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 // On windows, libc functions use errno, but system functions use GetLastError. 36 // So, callers need to be careful which of these next functions they call! 37 38 inline error_code capture_errno() { 39 _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero"); 40 return error_code(errno, generic_category()); 41 } 42 43 inline error_code get_last_error() { 44 #if defined(_LIBCPP_WIN32API) 45 return std::error_code(GetLastError(), std::system_category()); 46 #else 47 return capture_errno(); 48 #endif 49 } 50 51 template <class T> 52 T error_value(); 53 template <> 54 inline constexpr void error_value<void>() {} 55 template <> 56 inline bool error_value<bool>() { 57 return false; 58 } 59 #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ 60 template <> 61 inline size_t error_value<size_t>() { 62 return size_t(-1); 63 } 64 #endif 65 template <> 66 inline uintmax_t error_value<uintmax_t>() { 67 return uintmax_t(-1); 68 } 69 template <> 70 inline constexpr file_time_type error_value<file_time_type>() { 71 return file_time_type::min(); 72 } 73 template <> 74 inline path error_value<path>() { 75 return {}; 76 } 77 78 template <class T> 79 struct ErrorHandler { 80 const char* func_name_; 81 error_code* ec_ = nullptr; 82 const path* p1_ = nullptr; 83 const path* p2_ = nullptr; 84 85 ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, const path* p2 = nullptr) 86 : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { 87 if (ec_) 88 ec_->clear(); 89 } 90 91 T report(const error_code& ec) const { 92 if (ec_) { 93 *ec_ = ec; 94 return error_value<T>(); 95 } 96 string what = string("in ") + func_name_; 97 switch (bool(p1_) + bool(p2_)) { 98 case 0: 99 __throw_filesystem_error(what, ec); 100 case 1: 101 __throw_filesystem_error(what, *p1_, ec); 102 case 2: 103 __throw_filesystem_error(what, *p1_, *p2_, ec); 104 } 105 __libcpp_unreachable(); 106 } 107 108 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) 109 void report_impl(const error_code& ec, const char* msg, va_list ap) const { 110 if (ec_) { 111 *ec_ = ec; 112 return; 113 } 114 string what = string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap); 115 switch (bool(p1_) + bool(p2_)) { 116 case 0: 117 __throw_filesystem_error(what, ec); 118 case 1: 119 __throw_filesystem_error(what, *p1_, ec); 120 case 2: 121 __throw_filesystem_error(what, *p1_, *p2_, ec); 122 } 123 __libcpp_unreachable(); 124 } 125 126 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 127 T report(const error_code& ec, const char* msg, ...) const { 128 va_list ap; 129 va_start(ap, msg); 130 #if _LIBCPP_HAS_EXCEPTIONS 131 try { 132 #endif // _LIBCPP_HAS_EXCEPTIONS 133 report_impl(ec, msg, ap); 134 #if _LIBCPP_HAS_EXCEPTIONS 135 } catch (...) { 136 va_end(ap); 137 throw; 138 } 139 #endif // _LIBCPP_HAS_EXCEPTIONS 140 va_end(ap); 141 return error_value<T>(); 142 } 143 144 T report(errc const& err) const { return report(make_error_code(err)); } 145 146 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 147 T report(errc const& err, const char* msg, ...) const { 148 va_list ap; 149 va_start(ap, msg); 150 #if _LIBCPP_HAS_EXCEPTIONS 151 try { 152 #endif // _LIBCPP_HAS_EXCEPTIONS 153 report_impl(make_error_code(err), msg, ap); 154 #if _LIBCPP_HAS_EXCEPTIONS 155 } catch (...) { 156 va_end(ap); 157 throw; 158 } 159 #endif // _LIBCPP_HAS_EXCEPTIONS 160 va_end(ap); 161 return error_value<T>(); 162 } 163 164 private: 165 ErrorHandler(ErrorHandler const&) = delete; 166 ErrorHandler& operator=(ErrorHandler const&) = delete; 167 }; 168 169 } // namespace detail 170 171 _LIBCPP_END_NAMESPACE_FILESYSTEM 172 173 #endif // FILESYSTEM_ERROR_H 174