xref: /llvm-project/libcxx/src/filesystem/error.h (revision 2b26ee6e790574e05c3c9a562bc37897daf0f384)
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