//===----------------------------------------------------------------------===//// // // 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 <__config> #include #include #include #include #include #include #include #include // __libcpp_unreachable #include "format_string.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include // 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() { #if defined(_LIBCPP_WIN32API) return std::error_code(GetLastError(), std::system_category()); #else return capture_errno(); #endif } template T error_value(); template <> inline constexpr void error_value() {} template <> inline bool error_value() { return false; } #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ template <> inline size_t error_value() { return size_t(-1); } #endif template <> inline uintmax_t error_value() { return uintmax_t(-1); } template <> inline constexpr file_time_type error_value() { return file_time_type::min(); } template <> inline path error_value() { return {}; } template 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(); } string what = string("in ") + func_name_; switch (bool(p1_) + bool(p2_)) { case 0: __throw_filesystem_error(what, ec); case 1: __throw_filesystem_error(what, *p1_, ec); case 2: __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: __throw_filesystem_error(what, ec); case 1: __throw_filesystem_error(what, *p1_, ec); case 2: __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); #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS report_impl(ec, msg, ap); #if _LIBCPP_HAS_EXCEPTIONS } catch (...) { va_end(ap); throw; } #endif // _LIBCPP_HAS_EXCEPTIONS va_end(ap); return error_value(); } 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); #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS report_impl(make_error_code(err), msg, ap); #if _LIBCPP_HAS_EXCEPTIONS } catch (...) { va_end(ap); throw; } #endif // _LIBCPP_HAS_EXCEPTIONS va_end(ap); return error_value(); } private: ErrorHandler(ErrorHandler const&) = delete; ErrorHandler& operator=(ErrorHandler const&) = delete; }; } // namespace detail _LIBCPP_END_NAMESPACE_FILESYSTEM #endif // FILESYSTEM_ERROR_H