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