xref: /freebsd-src/contrib/llvm-project/libcxx/src/filesystem/error.h (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
106c3fb27SDimitry Andric //===----------------------------------------------------------------------===////
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===////
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #ifndef FILESYSTEM_ERROR_H
1006c3fb27SDimitry Andric #define FILESYSTEM_ERROR_H
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric #include <__assert>
1306c3fb27SDimitry Andric #include <__config>
1406c3fb27SDimitry Andric #include <cerrno>
1506c3fb27SDimitry Andric #include <cstdarg>
1606c3fb27SDimitry Andric #include <cstddef>
1706c3fb27SDimitry Andric #include <cstdint>
1806c3fb27SDimitry Andric #include <filesystem>
1906c3fb27SDimitry Andric #include <string>
2006c3fb27SDimitry Andric #include <system_error>
2106c3fb27SDimitry Andric #include <utility> // __libcpp_unreachable
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric #include "format_string.h"
2406c3fb27SDimitry Andric 
2506c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
2606c3fb27SDimitry Andric #  define WIN32_LEAN_AND_MEAN
2706c3fb27SDimitry Andric #  define NOMINMAX
2806c3fb27SDimitry Andric #  include <windows.h> // ERROR_* macros
2906c3fb27SDimitry Andric #endif
3006c3fb27SDimitry Andric 
3106c3fb27SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
3206c3fb27SDimitry Andric 
3306c3fb27SDimitry Andric namespace detail {
3406c3fb27SDimitry Andric 
3506c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
3606c3fb27SDimitry Andric 
__win_err_to_errc(int err)3706c3fb27SDimitry Andric inline errc __win_err_to_errc(int err) {
3806c3fb27SDimitry Andric   constexpr struct {
3906c3fb27SDimitry Andric     DWORD win;
4006c3fb27SDimitry Andric     errc errc;
4106c3fb27SDimitry Andric   } win_error_mapping[] = {
4206c3fb27SDimitry Andric       {ERROR_ACCESS_DENIED, errc::permission_denied},
4306c3fb27SDimitry Andric       {ERROR_ALREADY_EXISTS, errc::file_exists},
4406c3fb27SDimitry Andric       {ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
4506c3fb27SDimitry Andric       {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
4606c3fb27SDimitry Andric       {ERROR_BAD_UNIT, errc::no_such_device},
4706c3fb27SDimitry Andric       {ERROR_BROKEN_PIPE, errc::broken_pipe},
4806c3fb27SDimitry Andric       {ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
4906c3fb27SDimitry Andric       {ERROR_BUSY, errc::device_or_resource_busy},
5006c3fb27SDimitry Andric       {ERROR_BUSY_DRIVE, errc::device_or_resource_busy},
5106c3fb27SDimitry Andric       {ERROR_CANNOT_MAKE, errc::permission_denied},
5206c3fb27SDimitry Andric       {ERROR_CANTOPEN, errc::io_error},
5306c3fb27SDimitry Andric       {ERROR_CANTREAD, errc::io_error},
5406c3fb27SDimitry Andric       {ERROR_CANTWRITE, errc::io_error},
5506c3fb27SDimitry Andric       {ERROR_CURRENT_DIRECTORY, errc::permission_denied},
5606c3fb27SDimitry Andric       {ERROR_DEV_NOT_EXIST, errc::no_such_device},
5706c3fb27SDimitry Andric       {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy},
5806c3fb27SDimitry Andric       {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty},
5906c3fb27SDimitry Andric       {ERROR_DIRECTORY, errc::invalid_argument},
6006c3fb27SDimitry Andric       {ERROR_DISK_FULL, errc::no_space_on_device},
6106c3fb27SDimitry Andric       {ERROR_FILE_EXISTS, errc::file_exists},
6206c3fb27SDimitry Andric       {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory},
6306c3fb27SDimitry Andric       {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device},
6406c3fb27SDimitry Andric       {ERROR_INVALID_ACCESS, errc::permission_denied},
6506c3fb27SDimitry Andric       {ERROR_INVALID_DRIVE, errc::no_such_device},
6606c3fb27SDimitry Andric       {ERROR_INVALID_FUNCTION, errc::function_not_supported},
6706c3fb27SDimitry Andric       {ERROR_INVALID_HANDLE, errc::invalid_argument},
6806c3fb27SDimitry Andric       {ERROR_INVALID_NAME, errc::no_such_file_or_directory},
6906c3fb27SDimitry Andric       {ERROR_INVALID_PARAMETER, errc::invalid_argument},
7006c3fb27SDimitry Andric       {ERROR_LOCK_VIOLATION, errc::no_lock_available},
7106c3fb27SDimitry Andric       {ERROR_LOCKED, errc::no_lock_available},
7206c3fb27SDimitry Andric       {ERROR_NEGATIVE_SEEK, errc::invalid_argument},
7306c3fb27SDimitry Andric       {ERROR_NOACCESS, errc::permission_denied},
7406c3fb27SDimitry Andric       {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory},
7506c3fb27SDimitry Andric       {ERROR_NOT_READY, errc::resource_unavailable_try_again},
7606c3fb27SDimitry Andric       {ERROR_NOT_SAME_DEVICE, errc::cross_device_link},
7706c3fb27SDimitry Andric       {ERROR_NOT_SUPPORTED, errc::not_supported},
7806c3fb27SDimitry Andric       {ERROR_OPEN_FAILED, errc::io_error},
7906c3fb27SDimitry Andric       {ERROR_OPEN_FILES, errc::device_or_resource_busy},
8006c3fb27SDimitry Andric       {ERROR_OPERATION_ABORTED, errc::operation_canceled},
8106c3fb27SDimitry Andric       {ERROR_OUTOFMEMORY, errc::not_enough_memory},
8206c3fb27SDimitry Andric       {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory},
8306c3fb27SDimitry Andric       {ERROR_READ_FAULT, errc::io_error},
8406c3fb27SDimitry Andric       {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument},
8506c3fb27SDimitry Andric       {ERROR_RETRY, errc::resource_unavailable_try_again},
8606c3fb27SDimitry Andric       {ERROR_SEEK, errc::io_error},
8706c3fb27SDimitry Andric       {ERROR_SHARING_VIOLATION, errc::permission_denied},
8806c3fb27SDimitry Andric       {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open},
8906c3fb27SDimitry Andric       {ERROR_WRITE_FAULT, errc::io_error},
9006c3fb27SDimitry Andric       {ERROR_WRITE_PROTECT, errc::permission_denied},
9106c3fb27SDimitry Andric   };
9206c3fb27SDimitry Andric 
9306c3fb27SDimitry Andric   for (const auto& pair : win_error_mapping)
9406c3fb27SDimitry Andric     if (pair.win == static_cast<DWORD>(err))
9506c3fb27SDimitry Andric       return pair.errc;
9606c3fb27SDimitry Andric   return errc::invalid_argument;
9706c3fb27SDimitry Andric }
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric #endif // _LIBCPP_WIN32API
10006c3fb27SDimitry Andric 
capture_errno()10106c3fb27SDimitry Andric inline error_code capture_errno() {
102*1db9f3b2SDimitry Andric   _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero");
10306c3fb27SDimitry Andric   return error_code(errno, generic_category());
10406c3fb27SDimitry Andric }
10506c3fb27SDimitry Andric 
10606c3fb27SDimitry Andric #if defined(_LIBCPP_WIN32API)
make_windows_error(int err)107cb14a3feSDimitry Andric inline error_code make_windows_error(int err) { return make_error_code(__win_err_to_errc(err)); }
10806c3fb27SDimitry Andric #endif
10906c3fb27SDimitry Andric 
11006c3fb27SDimitry Andric template <class T>
11106c3fb27SDimitry Andric T error_value();
11206c3fb27SDimitry Andric template <>
1135f757f3fSDimitry Andric inline constexpr void error_value<void>() {}
11406c3fb27SDimitry Andric template <>
11506c3fb27SDimitry Andric inline bool error_value<bool>() {
11606c3fb27SDimitry Andric   return false;
11706c3fb27SDimitry Andric }
11806c3fb27SDimitry Andric #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__
11906c3fb27SDimitry Andric template <>
12006c3fb27SDimitry Andric inline size_t error_value<size_t>() {
12106c3fb27SDimitry Andric   return size_t(-1);
12206c3fb27SDimitry Andric }
12306c3fb27SDimitry Andric #endif
12406c3fb27SDimitry Andric template <>
12506c3fb27SDimitry Andric inline uintmax_t error_value<uintmax_t>() {
12606c3fb27SDimitry Andric   return uintmax_t(-1);
12706c3fb27SDimitry Andric }
12806c3fb27SDimitry Andric template <>
1295f757f3fSDimitry Andric inline constexpr file_time_type error_value<file_time_type>() {
13006c3fb27SDimitry Andric   return file_time_type::min();
13106c3fb27SDimitry Andric }
13206c3fb27SDimitry Andric template <>
13306c3fb27SDimitry Andric inline path error_value<path>() {
13406c3fb27SDimitry Andric   return {};
13506c3fb27SDimitry Andric }
13606c3fb27SDimitry Andric 
13706c3fb27SDimitry Andric template <class T>
13806c3fb27SDimitry Andric struct ErrorHandler {
13906c3fb27SDimitry Andric   const char* func_name_;
14006c3fb27SDimitry Andric   error_code* ec_ = nullptr;
14106c3fb27SDimitry Andric   const path* p1_ = nullptr;
14206c3fb27SDimitry Andric   const path* p2_ = nullptr;
14306c3fb27SDimitry Andric 
144cb14a3feSDimitry Andric   ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, const path* p2 = nullptr)
func_name_ErrorHandler14506c3fb27SDimitry Andric       : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) {
14606c3fb27SDimitry Andric     if (ec_)
14706c3fb27SDimitry Andric       ec_->clear();
14806c3fb27SDimitry Andric   }
14906c3fb27SDimitry Andric 
reportErrorHandler15006c3fb27SDimitry Andric   T report(const error_code& ec) const {
15106c3fb27SDimitry Andric     if (ec_) {
15206c3fb27SDimitry Andric       *ec_ = ec;
15306c3fb27SDimitry Andric       return error_value<T>();
15406c3fb27SDimitry Andric     }
15506c3fb27SDimitry Andric     string what = string("in ") + func_name_;
15606c3fb27SDimitry Andric     switch (bool(p1_) + bool(p2_)) {
15706c3fb27SDimitry Andric     case 0:
15806c3fb27SDimitry Andric       __throw_filesystem_error(what, ec);
15906c3fb27SDimitry Andric     case 1:
16006c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, ec);
16106c3fb27SDimitry Andric     case 2:
16206c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, *p2_, ec);
16306c3fb27SDimitry Andric     }
16406c3fb27SDimitry Andric     __libcpp_unreachable();
16506c3fb27SDimitry Andric   }
16606c3fb27SDimitry Andric 
16706c3fb27SDimitry Andric   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0)
report_implErrorHandler16806c3fb27SDimitry Andric   void report_impl(const error_code& ec, const char* msg, va_list ap) const {
16906c3fb27SDimitry Andric     if (ec_) {
17006c3fb27SDimitry Andric       *ec_ = ec;
17106c3fb27SDimitry Andric       return;
17206c3fb27SDimitry Andric     }
173cb14a3feSDimitry Andric     string what = string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap);
17406c3fb27SDimitry Andric     switch (bool(p1_) + bool(p2_)) {
17506c3fb27SDimitry Andric     case 0:
17606c3fb27SDimitry Andric       __throw_filesystem_error(what, ec);
17706c3fb27SDimitry Andric     case 1:
17806c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, ec);
17906c3fb27SDimitry Andric     case 2:
18006c3fb27SDimitry Andric       __throw_filesystem_error(what, *p1_, *p2_, ec);
18106c3fb27SDimitry Andric     }
18206c3fb27SDimitry Andric     __libcpp_unreachable();
18306c3fb27SDimitry Andric   }
18406c3fb27SDimitry Andric 
18506c3fb27SDimitry Andric   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
reportErrorHandler18606c3fb27SDimitry Andric   T report(const error_code& ec, const char* msg, ...) const {
18706c3fb27SDimitry Andric     va_list ap;
18806c3fb27SDimitry Andric     va_start(ap, msg);
18906c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
19006c3fb27SDimitry Andric     try {
19106c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
19206c3fb27SDimitry Andric       report_impl(ec, msg, ap);
19306c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
19406c3fb27SDimitry Andric     } catch (...) {
19506c3fb27SDimitry Andric       va_end(ap);
19606c3fb27SDimitry Andric       throw;
19706c3fb27SDimitry Andric     }
19806c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
19906c3fb27SDimitry Andric     va_end(ap);
20006c3fb27SDimitry Andric     return error_value<T>();
20106c3fb27SDimitry Andric   }
20206c3fb27SDimitry Andric 
reportErrorHandler203cb14a3feSDimitry Andric   T report(errc const& err) const { return report(make_error_code(err)); }
20406c3fb27SDimitry Andric 
20506c3fb27SDimitry Andric   _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4)
reportErrorHandler20606c3fb27SDimitry Andric   T report(errc const& err, const char* msg, ...) const {
20706c3fb27SDimitry Andric     va_list ap;
20806c3fb27SDimitry Andric     va_start(ap, msg);
20906c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
21006c3fb27SDimitry Andric     try {
21106c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
21206c3fb27SDimitry Andric       report_impl(make_error_code(err), msg, ap);
21306c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
21406c3fb27SDimitry Andric     } catch (...) {
21506c3fb27SDimitry Andric       va_end(ap);
21606c3fb27SDimitry Andric       throw;
21706c3fb27SDimitry Andric     }
21806c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
21906c3fb27SDimitry Andric     va_end(ap);
22006c3fb27SDimitry Andric     return error_value<T>();
22106c3fb27SDimitry Andric   }
22206c3fb27SDimitry Andric 
22306c3fb27SDimitry Andric private:
22406c3fb27SDimitry Andric   ErrorHandler(ErrorHandler const&)            = delete;
22506c3fb27SDimitry Andric   ErrorHandler& operator=(ErrorHandler const&) = delete;
22606c3fb27SDimitry Andric };
22706c3fb27SDimitry Andric 
22806c3fb27SDimitry Andric } // end namespace detail
22906c3fb27SDimitry Andric 
23006c3fb27SDimitry Andric _LIBCPP_END_NAMESPACE_FILESYSTEM
23106c3fb27SDimitry Andric 
23206c3fb27SDimitry Andric #endif // FILESYSTEM_ERROR_H
233