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