1c7d3c844SLouis Dionne //===----------------------------------------------------------------------===//// 2c7d3c844SLouis Dionne // 3c7d3c844SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c7d3c844SLouis Dionne // See https://llvm.org/LICENSE.txt for license information. 5c7d3c844SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c7d3c844SLouis Dionne // 7c7d3c844SLouis Dionne //===----------------------------------------------------------------------===//// 8c7d3c844SLouis Dionne 9c7d3c844SLouis Dionne #ifndef FILESYSTEM_ERROR_H 10c7d3c844SLouis Dionne #define FILESYSTEM_ERROR_H 11c7d3c844SLouis Dionne 12c7d3c844SLouis Dionne #include <__assert> 13c7d3c844SLouis Dionne #include <__config> 14c7d3c844SLouis Dionne #include <cerrno> 15c7d3c844SLouis Dionne #include <cstdarg> 16c7d3c844SLouis Dionne #include <cstddef> 17c7d3c844SLouis Dionne #include <cstdint> 18c7d3c844SLouis Dionne #include <filesystem> 19c7d3c844SLouis Dionne #include <string> 20c7d3c844SLouis Dionne #include <system_error> 21c7d3c844SLouis Dionne #include <utility> // __libcpp_unreachable 22c7d3c844SLouis Dionne 23c7d3c844SLouis Dionne #include "format_string.h" 24c7d3c844SLouis Dionne 25c7d3c844SLouis Dionne #if defined(_LIBCPP_WIN32API) 26c7d3c844SLouis Dionne # define WIN32_LEAN_AND_MEAN 27c7d3c844SLouis Dionne # define NOMINMAX 28c7d3c844SLouis Dionne # include <windows.h> // ERROR_* macros 29c7d3c844SLouis Dionne #endif 30c7d3c844SLouis Dionne 31c7d3c844SLouis Dionne _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 32c7d3c844SLouis Dionne 33c7d3c844SLouis Dionne namespace detail { 34c7d3c844SLouis Dionne 35*2b26ee6eSJames Y Knight // On windows, libc functions use errno, but system functions use GetLastError. 36*2b26ee6eSJames Y Knight // So, callers need to be careful which of these next functions they call! 37c7d3c844SLouis Dionne 3821853b96SLouis Dionne inline error_code capture_errno() { 394f215fddSKonstantin Varlamov _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero"); 40c7d3c844SLouis Dionne return error_code(errno, generic_category()); 41c7d3c844SLouis Dionne } 42c7d3c844SLouis Dionne 43*2b26ee6eSJames Y Knight inline error_code get_last_error() { 44c7d3c844SLouis Dionne #if defined(_LIBCPP_WIN32API) 45*2b26ee6eSJames Y Knight return std::error_code(GetLastError(), std::system_category()); 46*2b26ee6eSJames Y Knight #else 47*2b26ee6eSJames Y Knight return capture_errno(); 48c7d3c844SLouis Dionne #endif 49*2b26ee6eSJames Y Knight } 50c7d3c844SLouis Dionne 51c7d3c844SLouis Dionne template <class T> 52c7d3c844SLouis Dionne T error_value(); 53c7d3c844SLouis Dionne template <> 545a6c1ce1SLouis Dionne inline constexpr void error_value<void>() {} 55c7d3c844SLouis Dionne template <> 5621853b96SLouis Dionne inline bool error_value<bool>() { 57c7d3c844SLouis Dionne return false; 58c7d3c844SLouis Dionne } 59c7d3c844SLouis Dionne #if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ 60c7d3c844SLouis Dionne template <> 6121853b96SLouis Dionne inline size_t error_value<size_t>() { 62c7d3c844SLouis Dionne return size_t(-1); 63c7d3c844SLouis Dionne } 64c7d3c844SLouis Dionne #endif 65c7d3c844SLouis Dionne template <> 6621853b96SLouis Dionne inline uintmax_t error_value<uintmax_t>() { 67c7d3c844SLouis Dionne return uintmax_t(-1); 68c7d3c844SLouis Dionne } 69c7d3c844SLouis Dionne template <> 705a6c1ce1SLouis Dionne inline constexpr file_time_type error_value<file_time_type>() { 71c7d3c844SLouis Dionne return file_time_type::min(); 72c7d3c844SLouis Dionne } 73c7d3c844SLouis Dionne template <> 7421853b96SLouis Dionne inline path error_value<path>() { 75c7d3c844SLouis Dionne return {}; 76c7d3c844SLouis Dionne } 77c7d3c844SLouis Dionne 78c7d3c844SLouis Dionne template <class T> 79c7d3c844SLouis Dionne struct ErrorHandler { 80c7d3c844SLouis Dionne const char* func_name_; 81c7d3c844SLouis Dionne error_code* ec_ = nullptr; 82c7d3c844SLouis Dionne const path* p1_ = nullptr; 83c7d3c844SLouis Dionne const path* p2_ = nullptr; 84c7d3c844SLouis Dionne 859783f28cSLouis Dionne ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, const path* p2 = nullptr) 86c7d3c844SLouis Dionne : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { 87c7d3c844SLouis Dionne if (ec_) 88c7d3c844SLouis Dionne ec_->clear(); 89c7d3c844SLouis Dionne } 90c7d3c844SLouis Dionne 91c7d3c844SLouis Dionne T report(const error_code& ec) const { 92c7d3c844SLouis Dionne if (ec_) { 93c7d3c844SLouis Dionne *ec_ = ec; 94c7d3c844SLouis Dionne return error_value<T>(); 95c7d3c844SLouis Dionne } 96c7d3c844SLouis Dionne string what = string("in ") + func_name_; 97c7d3c844SLouis Dionne switch (bool(p1_) + bool(p2_)) { 98c7d3c844SLouis Dionne case 0: 99c7d3c844SLouis Dionne __throw_filesystem_error(what, ec); 100c7d3c844SLouis Dionne case 1: 101c7d3c844SLouis Dionne __throw_filesystem_error(what, *p1_, ec); 102c7d3c844SLouis Dionne case 2: 103c7d3c844SLouis Dionne __throw_filesystem_error(what, *p1_, *p2_, ec); 104c7d3c844SLouis Dionne } 105c7d3c844SLouis Dionne __libcpp_unreachable(); 106c7d3c844SLouis Dionne } 107c7d3c844SLouis Dionne 108c7d3c844SLouis Dionne _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) 109c7d3c844SLouis Dionne void report_impl(const error_code& ec, const char* msg, va_list ap) const { 110c7d3c844SLouis Dionne if (ec_) { 111c7d3c844SLouis Dionne *ec_ = ec; 112c7d3c844SLouis Dionne return; 113c7d3c844SLouis Dionne } 1149783f28cSLouis Dionne string what = string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap); 115c7d3c844SLouis Dionne switch (bool(p1_) + bool(p2_)) { 116c7d3c844SLouis Dionne case 0: 117c7d3c844SLouis Dionne __throw_filesystem_error(what, ec); 118c7d3c844SLouis Dionne case 1: 119c7d3c844SLouis Dionne __throw_filesystem_error(what, *p1_, ec); 120c7d3c844SLouis Dionne case 2: 121c7d3c844SLouis Dionne __throw_filesystem_error(what, *p1_, *p2_, ec); 122c7d3c844SLouis Dionne } 123c7d3c844SLouis Dionne __libcpp_unreachable(); 124c7d3c844SLouis Dionne } 125c7d3c844SLouis Dionne 126c7d3c844SLouis Dionne _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 127c7d3c844SLouis Dionne T report(const error_code& ec, const char* msg, ...) const { 128c7d3c844SLouis Dionne va_list ap; 129c7d3c844SLouis Dionne va_start(ap, msg); 130ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS 131c7d3c844SLouis Dionne try { 132ba87515fSNikolas Klauser #endif // _LIBCPP_HAS_EXCEPTIONS 133c7d3c844SLouis Dionne report_impl(ec, msg, ap); 134ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS 135c7d3c844SLouis Dionne } catch (...) { 136c7d3c844SLouis Dionne va_end(ap); 137c7d3c844SLouis Dionne throw; 138c7d3c844SLouis Dionne } 139ba87515fSNikolas Klauser #endif // _LIBCPP_HAS_EXCEPTIONS 140c7d3c844SLouis Dionne va_end(ap); 141c7d3c844SLouis Dionne return error_value<T>(); 142c7d3c844SLouis Dionne } 143c7d3c844SLouis Dionne 1449783f28cSLouis Dionne T report(errc const& err) const { return report(make_error_code(err)); } 145c7d3c844SLouis Dionne 146c7d3c844SLouis Dionne _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) 147c7d3c844SLouis Dionne T report(errc const& err, const char* msg, ...) const { 148c7d3c844SLouis Dionne va_list ap; 149c7d3c844SLouis Dionne va_start(ap, msg); 150ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS 151c7d3c844SLouis Dionne try { 152ba87515fSNikolas Klauser #endif // _LIBCPP_HAS_EXCEPTIONS 153c7d3c844SLouis Dionne report_impl(make_error_code(err), msg, ap); 154ba87515fSNikolas Klauser #if _LIBCPP_HAS_EXCEPTIONS 155c7d3c844SLouis Dionne } catch (...) { 156c7d3c844SLouis Dionne va_end(ap); 157c7d3c844SLouis Dionne throw; 158c7d3c844SLouis Dionne } 159ba87515fSNikolas Klauser #endif // _LIBCPP_HAS_EXCEPTIONS 160c7d3c844SLouis Dionne va_end(ap); 161c7d3c844SLouis Dionne return error_value<T>(); 162c7d3c844SLouis Dionne } 163c7d3c844SLouis Dionne 164c7d3c844SLouis Dionne private: 165c7d3c844SLouis Dionne ErrorHandler(ErrorHandler const&) = delete; 166c7d3c844SLouis Dionne ErrorHandler& operator=(ErrorHandler const&) = delete; 167c7d3c844SLouis Dionne }; 168c7d3c844SLouis Dionne 169953af0e7SLouis Dionne } // namespace detail 170c7d3c844SLouis Dionne 171c7d3c844SLouis Dionne _LIBCPP_END_NAMESPACE_FILESYSTEM 172c7d3c844SLouis Dionne 173c7d3c844SLouis Dionne #endif // FILESYSTEM_ERROR_H 174