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