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_UNCATEGORIZED(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) { 108 return make_error_code(__win_err_to_errc(err)); 109 } 110 #endif 111 112 template <class T> 113 T error_value(); 114 template <> 115 inline _LIBCPP_CONSTEXPR_SINCE_CXX14 void error_value<void>() {} 116 template <> 117 inline bool error_value<bool>() { 118 return false; 119 } 120 #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ 121 template <> 122 inline size_t error_value<size_t>() { 123 return size_t(-1); 124 } 125 #endif 126 template <> 127 inline uintmax_t error_value<uintmax_t>() { 128 return uintmax_t(-1); 129 } 130 template <> 131 inline _LIBCPP_CONSTEXPR_SINCE_CXX14 file_time_type error_value<file_time_type>() { 132 return file_time_type::min(); 133 } 134 template <> 135 inline path error_value<path>() { 136 return {}; 137 } 138 139 template <class T> 140 struct ErrorHandler { 141 const char* func_name_; 142 error_code* ec_ = nullptr; 143 const path* p1_ = nullptr; 144 const path* p2_ = nullptr; 145 146 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, 147 const path* p2 = nullptr) 148 : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { 149 if (ec_) 150 ec_->clear(); 151 } 152 153 T report(const error_code& ec) const { 154 if (ec_) { 155 *ec_ = ec; 156 return error_value<T>(); 157 } 158 string what = string("in ") + func_name_; 159 switch (bool(p1_) + bool(p2_)) { 160 case 0: 161 __throw_filesystem_error(what, ec); 162 case 1: 163 __throw_filesystem_error(what, *p1_, ec); 164 case 2: 165 __throw_filesystem_error(what, *p1_, *p2_, ec); 166 } 167 __libcpp_unreachable(); 168 } 169 170 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) 171 void report_impl(const error_code& ec, const char* msg, va_list ap) const { 172 if (ec_) { 173 *ec_ = ec; 174 return; 175 } 176 string what = 177 string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap); 178 switch (bool(p1_) + bool(p2_)) { 179 case 0: 180 __throw_filesystem_error(what, ec); 181 case 1: 182 __throw_filesystem_error(what, *p1_, ec); 183 case 2: 184 __throw_filesystem_error(what, *p1_, *p2_, ec); 185 } 186 __libcpp_unreachable(); 187 } 188 189 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 190 T report(const error_code& ec, const char* msg, ...) const { 191 va_list ap; 192 va_start(ap, msg); 193 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 194 try { 195 #endif // _LIBCPP_HAS_NO_EXCEPTIONS 196 report_impl(ec, msg, ap); 197 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 198 } catch (...) { 199 va_end(ap); 200 throw; 201 } 202 #endif // _LIBCPP_HAS_NO_EXCEPTIONS 203 va_end(ap); 204 return error_value<T>(); 205 } 206 207 T report(errc const& err) const { 208 return report(make_error_code(err)); 209 } 210 211 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 212 T report(errc const& err, const char* msg, ...) const { 213 va_list ap; 214 va_start(ap, msg); 215 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 216 try { 217 #endif // _LIBCPP_HAS_NO_EXCEPTIONS 218 report_impl(make_error_code(err), msg, ap); 219 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 220 } catch (...) { 221 va_end(ap); 222 throw; 223 } 224 #endif // _LIBCPP_HAS_NO_EXCEPTIONS 225 va_end(ap); 226 return error_value<T>(); 227 } 228 229 private: 230 ErrorHandler(ErrorHandler const&) = delete; 231 ErrorHandler& operator=(ErrorHandler const&) = delete; 232 }; 233 234 } // end namespace detail 235 236 _LIBCPP_END_NAMESPACE_FILESYSTEM 237 238 #endif // FILESYSTEM_ERROR_H 239