1//===----------------------------------------------------------------------===////
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===////
8
9#ifndef FILESYSTEM_ERROR_H
10#define FILESYSTEM_ERROR_H
11
12#include <__assert>
13#include <__config>
14#include <cerrno>
15#include <cstdarg>
16#include <cstddef>
17#include <cstdint>
18#include <filesystem>
19#include <string>
20#include <system_error>
21#include <utility> // __libcpp_unreachable
22
23#include "format_string.h"
24
25#if defined(_LIBCPP_WIN32API)
26# define WIN32_LEAN_AND_MEAN
27# define NOMINMAX
28# include <windows.h> // ERROR_* macros
29#endif
30
31_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
32
33namespace detail {
34
35#if defined(_LIBCPP_WIN32API)
36
37inline errc __win_err_to_errc(int err) {
38 constexpr struct {
39 DWORD win;
40 errc errc;
41 } win_error_mapping[] = {
42 {ERROR_ACCESS_DENIED, errc::permission_denied},
43 {ERROR_ALREADY_EXISTS, errc::file_exists},
44 {ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
45 {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
46 {ERROR_BAD_UNIT, errc::no_such_device},
47 {ERROR_BROKEN_PIPE, errc::broken_pipe},
48 {ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
49 {ERROR_BUSY, errc::device_or_resource_busy},
50 {ERROR_BUSY_DRIVE, errc::device_or_resource_busy},
51 {ERROR_CANNOT_MAKE, errc::permission_denied},
52 {ERROR_CANTOPEN, errc::io_error},
53 {ERROR_CANTREAD, errc::io_error},
54 {ERROR_CANTWRITE, errc::io_error},
55 {ERROR_CURRENT_DIRECTORY, errc::permission_denied},
56 {ERROR_DEV_NOT_EXIST, errc::no_such_device},
57 {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy},
58 {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty},
59 {ERROR_DIRECTORY, errc::invalid_argument},
60 {ERROR_DISK_FULL, errc::no_space_on_device},
61 {ERROR_FILE_EXISTS, errc::file_exists},
62 {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory},
63 {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device},
64 {ERROR_INVALID_ACCESS, errc::permission_denied},
65 {ERROR_INVALID_DRIVE, errc::no_such_device},
66 {ERROR_INVALID_FUNCTION, errc::function_not_supported},
67 {ERROR_INVALID_HANDLE, errc::invalid_argument},
68 {ERROR_INVALID_NAME, errc::no_such_file_or_directory},
69 {ERROR_INVALID_PARAMETER, errc::invalid_argument},
70 {ERROR_LOCK_VIOLATION, errc::no_lock_available},
71 {ERROR_LOCKED, errc::no_lock_available},
72 {ERROR_NEGATIVE_SEEK, errc::invalid_argument},
73 {ERROR_NOACCESS, errc::permission_denied},
74 {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory},
75 {ERROR_NOT_READY, errc::resource_unavailable_try_again},
76 {ERROR_NOT_SAME_DEVICE, errc::cross_device_link},
77 {ERROR_NOT_SUPPORTED, errc::not_supported},
78 {ERROR_OPEN_FAILED, errc::io_error},
79 {ERROR_OPEN_FILES, errc::device_or_resource_busy},
80 {ERROR_OPERATION_ABORTED, errc::operation_canceled},
81 {ERROR_OUTOFMEMORY, errc::not_enough_memory},
82 {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory},
83 {ERROR_READ_FAULT, errc::io_error},
84 {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument},
85 {ERROR_RETRY, errc::resource_unavailable_try_again},
86 {ERROR_SEEK, errc::io_error},
87 {ERROR_SHARING_VIOLATION, errc::permission_denied},
88 {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open},
89 {ERROR_WRITE_FAULT, errc::io_error},
90 {ERROR_WRITE_PROTECT, errc::permission_denied},
91 };
92
93 for (const auto& pair : win_error_mapping)
94 if (pair.win == static_cast<DWORD>(err))
95 return pair.errc;
96 return errc::invalid_argument;
97}
98
99#endif // _LIBCPP_WIN32API
100
101inline error_code capture_errno() {
102 _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero");
103 return error_code(errno, generic_category());
104}
105
106#if defined(_LIBCPP_WIN32API)
107inline error_code make_windows_error(int err) { return make_error_code(__win_err_to_errc(err)); }
108#endif
109
110template <class T>
111T error_value();
112template <>
113inline constexpr void error_value<void>() {}
114template <>
115inline bool error_value<bool>() {
116 return false;
117}
118#if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__
119template <>
120inline size_t error_value<size_t>() {
121 return size_t(-1);
122}
123#endif
124template <>
125inline uintmax_t error_value<uintmax_t>() {
126 return uintmax_t(-1);
127}
128template <>
129inline constexpr file_time_type error_value<file_time_type>() {
130 return file_time_type::min();
131}
132template <>
133inline path error_value<path>() {
134 return {};
135}
136
137template <class T>
138struct ErrorHandler {
139 const char* func_name_;
140 error_code* ec_ = nullptr;
141 const path* p1_ = nullptr;
142 const path* p2_ = nullptr;
143
144 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, const path* p2 = nullptr)
145 : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
146 if (ec_)
147 ec_->clear();
148 }
149
150 T report(const error_code& ec) const {
151 if (ec_) {
152 *ec_ = ec;
153 return error_value<T>();
154 }
155 string what = string("in ") + func_name_;
156 switch (bool(p1_) + bool(p2_)) {
157 case 0:
158 __throw_filesystem_error(what, ec);
159 case 1:
160 __throw_filesystem_error(what, *p1_, ec);
161 case 2:
162 __throw_filesystem_error(what, *p1_, *p2_, ec);
163 }
164 __libcpp_unreachable();
165 }
166
167 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0)
168 void report_impl(const error_code& ec, const char* msg, va_list ap) const {
169 if (ec_) {
170 *ec_ = ec;
171 return;
172 }
173 string what = string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap);
174 switch (bool(p1_) + bool(p2_)) {
175 case 0:
176 __throw_filesystem_error(what, ec);
177 case 1:
178 __throw_filesystem_error(what, *p1_, ec);
179 case 2:
180 __throw_filesystem_error(what, *p1_, *p2_, ec);
181 }
182 __libcpp_unreachable();
183 }
184
185 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
186 T report(const error_code& ec, const char* msg, ...) const {
187 va_list ap;
188 va_start(ap, msg);
189#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
190 try {
191#endif // _LIBCPP_HAS_NO_EXCEPTIONS
192 report_impl(ec, msg, ap);
193#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
194 } catch (...) {
195 va_end(ap);
196 throw;
197 }
198#endif // _LIBCPP_HAS_NO_EXCEPTIONS
199 va_end(ap);
200 return error_value<T>();
201 }
202
203 T report(errc const& err) const { return report(make_error_code(err)); }
204
205 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
206 T report(errc const& err, const char* msg, ...) const {
207 va_list ap;
208 va_start(ap, msg);
209#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
210 try {
211#endif // _LIBCPP_HAS_NO_EXCEPTIONS
212 report_impl(make_error_code(err), msg, ap);
213#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
214 } catch (...) {
215 va_end(ap);
216 throw;
217 }
218#endif // _LIBCPP_HAS_NO_EXCEPTIONS
219 va_end(ap);
220 return error_value<T>();
221 }
222
223private:
224 ErrorHandler(ErrorHandler const&) = delete;
225 ErrorHandler& operator=(ErrorHandler const&) = delete;
226};
227
228} // end namespace detail
229
230_LIBCPP_END_NAMESPACE_FILESYSTEM
231
232#endif // FILESYSTEM_ERROR_H
233