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 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 10106c3fb27SDimitry Andric inline error_code capture_errno() { 10206c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(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) 107*cb14a3feSDimitry 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 144*cb14a3feSDimitry Andric ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, const path* p2 = nullptr) 14506c3fb27SDimitry Andric : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { 14606c3fb27SDimitry Andric if (ec_) 14706c3fb27SDimitry Andric ec_->clear(); 14806c3fb27SDimitry Andric } 14906c3fb27SDimitry Andric 15006c3fb27SDimitry 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) 16806c3fb27SDimitry 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 } 173*cb14a3feSDimitry 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) 18606c3fb27SDimitry 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 203*cb14a3feSDimitry Andric T report(errc const& err) const { return report(make_error_code(err)); } 20406c3fb27SDimitry Andric 20506c3fb27SDimitry Andric _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 20606c3fb27SDimitry 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