master
  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(what, ec);
101    case 1:
102      filesystem::__throw_filesystem_error(what, *p1_, ec);
103    case 2:
104      filesystem::__throw_filesystem_error(what, *p1_, *p2_, 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(what, ec);
119    case 1:
120      filesystem::__throw_filesystem_error(what, *p1_, ec);
121    case 2:
122      filesystem::__throw_filesystem_error(what, *p1_, *p2_, 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(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(make_error_code(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