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 | |
33 | namespace detail { |
34 | |
35 | #if defined(_LIBCPP_WIN32API) |
36 | |
37 | inline 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 | |
101 | inline 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) |
107 | inline error_code make_windows_error(int err) { return make_error_code(__win_err_to_errc(err)); } |
108 | #endif |
109 | |
110 | template <class T> |
111 | T error_value(); |
112 | template <> |
113 | inline constexpr void error_value<void>() {} |
114 | template <> |
115 | inline bool error_value<bool>() { |
116 | return false; |
117 | } |
118 | #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ |
119 | template <> |
120 | inline size_t error_value<size_t>() { |
121 | return size_t(-1); |
122 | } |
123 | #endif |
124 | template <> |
125 | inline uintmax_t error_value<uintmax_t>() { |
126 | return uintmax_t(-1); |
127 | } |
128 | template <> |
129 | inline constexpr file_time_type error_value<file_time_type>() { |
130 | return file_time_type::min(); |
131 | } |
132 | template <> |
133 | inline path error_value<path>() { |
134 | return {}; |
135 | } |
136 | |
137 | template <class T> |
138 | struct 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 | |
223 | private: |
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 | |