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(args&: what, args: ec); |
101 | case 1: |
102 | filesystem::__throw_filesystem_error(args&: what, args: *p1_, args: ec); |
103 | case 2: |
104 | filesystem::__throw_filesystem_error(args&: what, args: *p1_, args: *p2_, args: 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(args&: what, args: ec); |
119 | case 1: |
120 | filesystem::__throw_filesystem_error(args&: what, args: *p1_, args: ec); |
121 | case 2: |
122 | filesystem::__throw_filesystem_error(args&: what, args: *p1_, args: *p2_, args: 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(e: 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(ec: make_error_code(e: 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 | |