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