xref: /freebsd/contrib/llvm-project/libcxx/src/filesystem/error.h (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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