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
capture_errno()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
get_last_error()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)
func_name_ErrorHandler87 : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
88 if (ec_)
89 ec_->clear();
90 }
91
reportErrorHandler92 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)
report_implErrorHandler110 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)
reportErrorHandler128 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
reportErrorHandler145 T report(errc const& err) const { return report(make_error_code(err)); }
146
147 _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
reportErrorHandler148 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