xref: /freebsd-src/contrib/llvm-project/libcxx/src/filesystem/error.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===////
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===////
8*06c3fb27SDimitry Andric 
9*06c3fb27SDimitry Andric #ifndef FILESYSTEM_ERROR_H
10*06c3fb27SDimitry Andric #define FILESYSTEM_ERROR_H
11*06c3fb27SDimitry Andric 
12*06c3fb27SDimitry Andric #include <__assert>
13*06c3fb27SDimitry Andric #include <__config>
14*06c3fb27SDimitry Andric #include <cerrno>
15*06c3fb27SDimitry Andric #include <cstdarg>
16*06c3fb27SDimitry Andric #include <cstddef>
17*06c3fb27SDimitry Andric #include <cstdint>
18*06c3fb27SDimitry Andric #include <filesystem>
19*06c3fb27SDimitry Andric #include <string>
20*06c3fb27SDimitry Andric #include <system_error>
21*06c3fb27SDimitry Andric #include <utility> // __libcpp_unreachable
22*06c3fb27SDimitry Andric 
23*06c3fb27SDimitry Andric #include "format_string.h"
24*06c3fb27SDimitry Andric 
25*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
26*06c3fb27SDimitry Andric # define WIN32_LEAN_AND_MEAN
27*06c3fb27SDimitry Andric # define NOMINMAX
28*06c3fb27SDimitry Andric # include <windows.h> // ERROR_* macros
29*06c3fb27SDimitry Andric #endif
30*06c3fb27SDimitry Andric 
31*06c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
32*06c3fb27SDimitry Andric 
33*06c3fb27SDimitry Andric namespace detail {
34*06c3fb27SDimitry Andric 
35*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
36*06c3fb27SDimitry Andric 
37*06c3fb27SDimitry Andric inline errc __win_err_to_errc(int err) {
38*06c3fb27SDimitry Andric   constexpr struct {
39*06c3fb27SDimitry Andric     DWORD win;
40*06c3fb27SDimitry Andric     errc errc;
41*06c3fb27SDimitry Andric   } win_error_mapping[] = {
42*06c3fb27SDimitry Andric       {ERROR_ACCESS_DENIED, errc::permission_denied},
43*06c3fb27SDimitry Andric       {ERROR_ALREADY_EXISTS, errc::file_exists},
44*06c3fb27SDimitry Andric       {ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
45*06c3fb27SDimitry Andric       {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
46*06c3fb27SDimitry Andric       {ERROR_BAD_UNIT, errc::no_such_device},
47*06c3fb27SDimitry Andric       {ERROR_BROKEN_PIPE, errc::broken_pipe},
48*06c3fb27SDimitry Andric       {ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
49*06c3fb27SDimitry Andric       {ERROR_BUSY, errc::device_or_resource_busy},
50*06c3fb27SDimitry Andric       {ERROR_BUSY_DRIVE, errc::device_or_resource_busy},
51*06c3fb27SDimitry Andric       {ERROR_CANNOT_MAKE, errc::permission_denied},
52*06c3fb27SDimitry Andric       {ERROR_CANTOPEN, errc::io_error},
53*06c3fb27SDimitry Andric       {ERROR_CANTREAD, errc::io_error},
54*06c3fb27SDimitry Andric       {ERROR_CANTWRITE, errc::io_error},
55*06c3fb27SDimitry Andric       {ERROR_CURRENT_DIRECTORY, errc::permission_denied},
56*06c3fb27SDimitry Andric       {ERROR_DEV_NOT_EXIST, errc::no_such_device},
57*06c3fb27SDimitry Andric       {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy},
58*06c3fb27SDimitry Andric       {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty},
59*06c3fb27SDimitry Andric       {ERROR_DIRECTORY, errc::invalid_argument},
60*06c3fb27SDimitry Andric       {ERROR_DISK_FULL, errc::no_space_on_device},
61*06c3fb27SDimitry Andric       {ERROR_FILE_EXISTS, errc::file_exists},
62*06c3fb27SDimitry Andric       {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory},
63*06c3fb27SDimitry Andric       {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device},
64*06c3fb27SDimitry Andric       {ERROR_INVALID_ACCESS, errc::permission_denied},
65*06c3fb27SDimitry Andric       {ERROR_INVALID_DRIVE, errc::no_such_device},
66*06c3fb27SDimitry Andric       {ERROR_INVALID_FUNCTION, errc::function_not_supported},
67*06c3fb27SDimitry Andric       {ERROR_INVALID_HANDLE, errc::invalid_argument},
68*06c3fb27SDimitry Andric       {ERROR_INVALID_NAME, errc::no_such_file_or_directory},
69*06c3fb27SDimitry Andric       {ERROR_INVALID_PARAMETER, errc::invalid_argument},
70*06c3fb27SDimitry Andric       {ERROR_LOCK_VIOLATION, errc::no_lock_available},
71*06c3fb27SDimitry Andric       {ERROR_LOCKED, errc::no_lock_available},
72*06c3fb27SDimitry Andric       {ERROR_NEGATIVE_SEEK, errc::invalid_argument},
73*06c3fb27SDimitry Andric       {ERROR_NOACCESS, errc::permission_denied},
74*06c3fb27SDimitry Andric       {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory},
75*06c3fb27SDimitry Andric       {ERROR_NOT_READY, errc::resource_unavailable_try_again},
76*06c3fb27SDimitry Andric       {ERROR_NOT_SAME_DEVICE, errc::cross_device_link},
77*06c3fb27SDimitry Andric       {ERROR_NOT_SUPPORTED, errc::not_supported},
78*06c3fb27SDimitry Andric       {ERROR_OPEN_FAILED, errc::io_error},
79*06c3fb27SDimitry Andric       {ERROR_OPEN_FILES, errc::device_or_resource_busy},
80*06c3fb27SDimitry Andric       {ERROR_OPERATION_ABORTED, errc::operation_canceled},
81*06c3fb27SDimitry Andric       {ERROR_OUTOFMEMORY, errc::not_enough_memory},
82*06c3fb27SDimitry Andric       {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory},
83*06c3fb27SDimitry Andric       {ERROR_READ_FAULT, errc::io_error},
84*06c3fb27SDimitry Andric       {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument},
85*06c3fb27SDimitry Andric       {ERROR_RETRY, errc::resource_unavailable_try_again},
86*06c3fb27SDimitry Andric       {ERROR_SEEK, errc::io_error},
87*06c3fb27SDimitry Andric       {ERROR_SHARING_VIOLATION, errc::permission_denied},
88*06c3fb27SDimitry Andric       {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open},
89*06c3fb27SDimitry Andric       {ERROR_WRITE_FAULT, errc::io_error},
90*06c3fb27SDimitry Andric       {ERROR_WRITE_PROTECT, errc::permission_denied},
91*06c3fb27SDimitry Andric   };
92*06c3fb27SDimitry Andric 
93*06c3fb27SDimitry Andric   for (const auto &pair : win_error_mapping)
94*06c3fb27SDimitry Andric     if (pair.win == static_cast<DWORD>(err))
95*06c3fb27SDimitry Andric       return pair.errc;
96*06c3fb27SDimitry Andric   return errc::invalid_argument;
97*06c3fb27SDimitry Andric }
98*06c3fb27SDimitry Andric 
99*06c3fb27SDimitry Andric #endif // _LIBCPP_WIN32API
100*06c3fb27SDimitry Andric 
101*06c3fb27SDimitry Andric inline error_code capture_errno() {
102*06c3fb27SDimitry Andric   _LIBCPP_ASSERT_UNCATEGORIZED(errno != 0, "Expected errno to be non-zero");
103*06c3fb27SDimitry Andric   return error_code(errno, generic_category());
104*06c3fb27SDimitry Andric }
105*06c3fb27SDimitry Andric 
106*06c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
107*06c3fb27SDimitry Andric inline error_code make_windows_error(int err) {
108*06c3fb27SDimitry Andric   return make_error_code(__win_err_to_errc(err));
109*06c3fb27SDimitry Andric }
110*06c3fb27SDimitry Andric #endif
111*06c3fb27SDimitry Andric 
112*06c3fb27SDimitry Andric template <class T>
113*06c3fb27SDimitry Andric T error_value();
114*06c3fb27SDimitry Andric template <>
115*06c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX14 void error_value<void>() {}
116*06c3fb27SDimitry Andric template <>
117*06c3fb27SDimitry Andric inline bool error_value<bool>() {
118*06c3fb27SDimitry Andric   return false;
119*06c3fb27SDimitry Andric }
120*06c3fb27SDimitry Andric #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__
121*06c3fb27SDimitry Andric template <>
122*06c3fb27SDimitry Andric inline size_t error_value<size_t>() {
123*06c3fb27SDimitry Andric   return size_t(-1);
124*06c3fb27SDimitry Andric }
125*06c3fb27SDimitry Andric #endif
126*06c3fb27SDimitry Andric template <>
127*06c3fb27SDimitry Andric inline uintmax_t error_value<uintmax_t>() {
128*06c3fb27SDimitry Andric   return uintmax_t(-1);
129*06c3fb27SDimitry Andric }
130*06c3fb27SDimitry Andric template <>
131*06c3fb27SDimitry Andric inline _LIBCPP_CONSTEXPR_SINCE_CXX14 file_time_type error_value<file_time_type>() {
132*06c3fb27SDimitry Andric   return file_time_type::min();
133*06c3fb27SDimitry Andric }
134*06c3fb27SDimitry Andric template <>
135*06c3fb27SDimitry Andric inline path error_value<path>() {
136*06c3fb27SDimitry Andric   return {};
137*06c3fb27SDimitry Andric }
138*06c3fb27SDimitry Andric 
139*06c3fb27SDimitry Andric template <class T>
140*06c3fb27SDimitry Andric struct ErrorHandler {
141*06c3fb27SDimitry Andric   const char* func_name_;
142*06c3fb27SDimitry Andric   error_code* ec_ = nullptr;
143*06c3fb27SDimitry Andric   const path* p1_ = nullptr;
144*06c3fb27SDimitry Andric   const path* p2_ = nullptr;
145*06c3fb27SDimitry Andric 
146*06c3fb27SDimitry Andric   ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
147*06c3fb27SDimitry Andric                const path* p2 = nullptr)
148*06c3fb27SDimitry Andric       : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
149*06c3fb27SDimitry Andric     if (ec_)
150*06c3fb27SDimitry Andric       ec_->clear();
151*06c3fb27SDimitry Andric   }
152*06c3fb27SDimitry Andric 
153*06c3fb27SDimitry Andric   T report(const error_code& ec) const {
154*06c3fb27SDimitry Andric     if (ec_) {
155*06c3fb27SDimitry Andric       *ec_ = ec;
156*06c3fb27SDimitry Andric       return error_value<T>();
157*06c3fb27SDimitry Andric     }
158*06c3fb27SDimitry Andric     string what = string("in ") + func_name_;
159*06c3fb27SDimitry Andric     switch (bool(p1_) + bool(p2_)) {
160*06c3fb27SDimitry Andric     case 0:
161*06c3fb27SDimitry Andric       __throw_filesystem_error(what, ec);
162*06c3fb27SDimitry Andric     case 1:
163*06c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, ec);
164*06c3fb27SDimitry Andric     case 2:
165*06c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, *p2_, ec);
166*06c3fb27SDimitry Andric     }
167*06c3fb27SDimitry Andric     __libcpp_unreachable();
168*06c3fb27SDimitry Andric   }
169*06c3fb27SDimitry Andric 
170*06c3fb27SDimitry Andric   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0)
171*06c3fb27SDimitry Andric   void report_impl(const error_code& ec, const char* msg, va_list ap) const {
172*06c3fb27SDimitry Andric     if (ec_) {
173*06c3fb27SDimitry Andric       *ec_ = ec;
174*06c3fb27SDimitry Andric       return;
175*06c3fb27SDimitry Andric     }
176*06c3fb27SDimitry Andric     string what =
177*06c3fb27SDimitry Andric         string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap);
178*06c3fb27SDimitry Andric     switch (bool(p1_) + bool(p2_)) {
179*06c3fb27SDimitry Andric     case 0:
180*06c3fb27SDimitry Andric       __throw_filesystem_error(what, ec);
181*06c3fb27SDimitry Andric     case 1:
182*06c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, ec);
183*06c3fb27SDimitry Andric     case 2:
184*06c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, *p2_, ec);
185*06c3fb27SDimitry Andric     }
186*06c3fb27SDimitry Andric     __libcpp_unreachable();
187*06c3fb27SDimitry Andric   }
188*06c3fb27SDimitry Andric 
189*06c3fb27SDimitry Andric   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
190*06c3fb27SDimitry Andric   T report(const error_code& ec, const char* msg, ...) const {
191*06c3fb27SDimitry Andric     va_list ap;
192*06c3fb27SDimitry Andric     va_start(ap, msg);
193*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
194*06c3fb27SDimitry Andric     try {
195*06c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
196*06c3fb27SDimitry Andric       report_impl(ec, msg, ap);
197*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
198*06c3fb27SDimitry Andric     } catch (...) {
199*06c3fb27SDimitry Andric       va_end(ap);
200*06c3fb27SDimitry Andric       throw;
201*06c3fb27SDimitry Andric     }
202*06c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
203*06c3fb27SDimitry Andric     va_end(ap);
204*06c3fb27SDimitry Andric     return error_value<T>();
205*06c3fb27SDimitry Andric   }
206*06c3fb27SDimitry Andric 
207*06c3fb27SDimitry Andric   T report(errc const& err) const {
208*06c3fb27SDimitry Andric     return report(make_error_code(err));
209*06c3fb27SDimitry Andric   }
210*06c3fb27SDimitry Andric 
211*06c3fb27SDimitry Andric   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
212*06c3fb27SDimitry Andric   T report(errc const& err, const char* msg, ...) const {
213*06c3fb27SDimitry Andric     va_list ap;
214*06c3fb27SDimitry Andric     va_start(ap, msg);
215*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
216*06c3fb27SDimitry Andric     try {
217*06c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
218*06c3fb27SDimitry Andric       report_impl(make_error_code(err), msg, ap);
219*06c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
220*06c3fb27SDimitry Andric     } catch (...) {
221*06c3fb27SDimitry Andric       va_end(ap);
222*06c3fb27SDimitry Andric       throw;
223*06c3fb27SDimitry Andric     }
224*06c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
225*06c3fb27SDimitry Andric     va_end(ap);
226*06c3fb27SDimitry Andric     return error_value<T>();
227*06c3fb27SDimitry Andric   }
228*06c3fb27SDimitry Andric 
229*06c3fb27SDimitry Andric private:
230*06c3fb27SDimitry Andric   ErrorHandler(ErrorHandler const&) = delete;
231*06c3fb27SDimitry Andric   ErrorHandler& operator=(ErrorHandler const&) = delete;
232*06c3fb27SDimitry Andric };
233*06c3fb27SDimitry Andric 
234*06c3fb27SDimitry Andric } // end namespace detail
235*06c3fb27SDimitry Andric 
236*06c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM
237*06c3fb27SDimitry Andric 
238*06c3fb27SDimitry Andric #endif // FILESYSTEM_ERROR_H
239