| //===----------------------------------------------------------------------===//// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===//// | |
| #ifndef FILESYSTEM_ERROR_H | |
| #define FILESYSTEM_ERROR_H | |
| #include <__assert> | |
| #include <__chrono/time_point.h> | |
| #include <__config> | |
| #include <cerrno> | |
| #include <cstdarg> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <filesystem> | |
| #include <string> | |
| #include <system_error> | |
| #include <utility> // __libcpp_unreachable | |
| #include "format_string.h" | |
| #ifdef _WIN32 | |
| # define WIN32_LEAN_AND_MEAN | |
| # define NOMINMAX | |
| # include <windows.h> // ERROR_* macros | |
| #endif | |
| _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM | |
| namespace detail { | |
| // On windows, libc functions use errno, but system functions use GetLastError. | |
| // So, callers need to be careful which of these next functions they call! | |
| inline error_code capture_errno() { | |
| _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero"); | |
| return error_code(errno, generic_category()); | |
| } | |
| inline error_code get_last_error() { | |
| #ifdef _WIN32 | |
| return std::error_code(GetLastError(), std::system_category()); | |
| #else | |
| return capture_errno(); | |
| #endif | |
| } | |
| template <class T> | |
| T error_value(); | |
| template <> | |
| inline constexpr void error_value<void>() {} | |
| template <> | |
| inline bool error_value<bool>() { | |
| return false; | |
| } | |
| #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ | |
| template <> | |
| inline size_t error_value<size_t>() { | |
| return size_t(-1); | |
| } | |
| #endif | |
| template <> | |
| inline uintmax_t error_value<uintmax_t>() { | |
| return uintmax_t(-1); | |
| } | |
| template <> | |
| inline constexpr file_time_type error_value<file_time_type>() { | |
| return file_time_type::min(); | |
| } | |
| template <> | |
| inline path error_value<path>() { | |
| return {}; | |
| } | |
| template <class T> | |
| struct ErrorHandler { | |
| const char* func_name_; | |
| error_code* ec_ = nullptr; | |
| const path* p1_ = nullptr; | |
| const path* p2_ = nullptr; | |
| ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, const path* p2 = nullptr) | |
| : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { | |
| if (ec_) | |
| ec_->clear(); | |
| } | |
| T report(const error_code& ec) const { | |
| if (ec_) { | |
| *ec_ = ec; | |
| return error_value<T>(); | |
| } | |
| string what = string("in ") + func_name_; | |
| switch (bool(p1_) + bool(p2_)) { | |
| case 0: | |
| filesystem::__throw_filesystem_error(what, ec); | |
| case 1: | |
| filesystem::__throw_filesystem_error(what, *p1_, ec); | |
| case 2: | |
| filesystem::__throw_filesystem_error(what, *p1_, *p2_, ec); | |
| } | |
| __libcpp_unreachable(); | |
| } | |
| _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) | |
| void report_impl(const error_code& ec, const char* msg, va_list ap) const { | |
| if (ec_) { | |
| *ec_ = ec; | |
| return; | |
| } | |
| string what = string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap); | |
| switch (bool(p1_) + bool(p2_)) { | |
| case 0: | |
| filesystem::__throw_filesystem_error(what, ec); | |
| case 1: | |
| filesystem::__throw_filesystem_error(what, *p1_, ec); | |
| case 2: | |
| filesystem::__throw_filesystem_error(what, *p1_, *p2_, ec); | |
| } | |
| __libcpp_unreachable(); | |
| } | |
| _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) | |
| T report(const error_code& ec, const char* msg, ...) const { | |
| va_list ap; | |
| va_start(ap, msg); | |
| __scope_guard guard([&] { va_end(ap); }); | |
| report_impl(ec, msg, ap); | |
| return error_value<T>(); | |
| } | |
| T report(errc const& err) const { return report(make_error_code(err)); } | |
| _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) | |
| T report(errc const& err, const char* msg, ...) const { | |
| va_list ap; | |
| va_start(ap, msg); | |
| __scope_guard guard([&] { va_end(ap); }); | |
| report_impl(make_error_code(err), msg, ap); | |
| return error_value<T>(); | |
| } | |
| private: | |
| ErrorHandler(ErrorHandler const&) = delete; | |
| ErrorHandler& operator=(ErrorHandler const&) = delete; | |
| }; | |
| } // namespace detail | |
| _LIBCPP_END_NAMESPACE_FILESYSTEM | |
| #endif // FILESYSTEM_ERROR_H |