xref: /llvm-project/libcxx/src/filesystem/error.h (revision 2b26ee6e790574e05c3c9a562bc37897daf0f384)
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