Skip to content

[libcxx] Handle windows system error code mapping in std::error_code. #93101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions libcxx/include/__filesystem/directory_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#include <__filesystem/path.h>
#include <__filesystem/perms.h>
#include <__system_error/errc.h>
#include <__system_error/error_category.h>
#include <__system_error/error_code.h>
#include <__system_error/error_condition.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
#include <cstdint>
Expand Down Expand Up @@ -249,15 +251,7 @@ class directory_entry {
_LIBCPP_EXPORTED_FROM_ABI error_code __do_refresh() noexcept;

_LIBCPP_HIDE_FROM_ABI static bool __is_dne_error(error_code const& __ec) {
if (!__ec)
return true;
switch (static_cast<errc>(__ec.value())) {
case errc::no_such_file_or_directory:
case errc::not_a_directory:
return true;
default:
return false;
}
return !__ec || __ec == errc::no_such_file_or_directory || __ec == errc::not_a_directory;
}

_LIBCPP_HIDE_FROM_ABI void
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/__system_error/system_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class _LIBCPP_EXPORTED_FROM_ABI system_error : public runtime_error {
_LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; }
};

// __ev is expected to be an error in the generic_category domain (e.g. from
// errno, or std::errc::*), not system_category (e.g. from windows syscalls).
_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_system_error(int __ev, const char* __what_arg);
_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void __throw_system_error(error_code __ec, const char* __what_arg) {
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
Expand Down
10 changes: 5 additions & 5 deletions libcxx/src/filesystem/directory_iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ class __dir_stream {
}
__stream_ = ::FindFirstFileW((root / "*").c_str(), &__data_);
if (__stream_ == INVALID_HANDLE_VALUE) {
ec = detail::make_windows_error(GetLastError());
ec = detail::get_last_error();
const bool ignore_permission_denied = bool(opts & directory_options::skip_permission_denied);
if (ignore_permission_denied && ec.value() == static_cast<int>(errc::permission_denied))
if (ignore_permission_denied && ec == errc::permission_denied)
ec.clear();
return;
}
Expand Down Expand Up @@ -91,7 +91,7 @@ class __dir_stream {
error_code close() noexcept {
error_code ec;
if (!::FindClose(__stream_))
ec = detail::make_windows_error(GetLastError());
ec = detail::get_last_error();
__stream_ = INVALID_HANDLE_VALUE;
return ec;
}
Expand All @@ -118,7 +118,7 @@ class __dir_stream {
if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
ec = detail::capture_errno();
const bool allow_eacces = bool(opts & directory_options::skip_permission_denied);
if (allow_eacces && ec.value() == EACCES)
if (allow_eacces && ec == errc::permission_denied)
ec.clear();
return;
}
Expand Down Expand Up @@ -307,7 +307,7 @@ bool recursive_directory_iterator::__try_recursion(error_code* ec) {
}
if (m_ec) {
const bool allow_eacess = bool(__imp_->__options_ & directory_options::skip_permission_denied);
if (m_ec.value() == EACCES && allow_eacess) {
if (m_ec == errc::permission_denied && allow_eacess) {
if (ec)
ec->clear();
} else {
Expand Down
73 changes: 7 additions & 66 deletions libcxx/src/filesystem/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,80 +32,21 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM

namespace detail {

#if defined(_LIBCPP_WIN32API)

inline errc __win_err_to_errc(int err) {
constexpr struct {
DWORD win;
errc errc;
} win_error_mapping[] = {
{ERROR_ACCESS_DENIED, errc::permission_denied},
{ERROR_ALREADY_EXISTS, errc::file_exists},
{ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
{ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
{ERROR_BAD_UNIT, errc::no_such_device},
{ERROR_BROKEN_PIPE, errc::broken_pipe},
{ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
{ERROR_BUSY, errc::device_or_resource_busy},
{ERROR_BUSY_DRIVE, errc::device_or_resource_busy},
{ERROR_CANNOT_MAKE, errc::permission_denied},
{ERROR_CANTOPEN, errc::io_error},
{ERROR_CANTREAD, errc::io_error},
{ERROR_CANTWRITE, errc::io_error},
{ERROR_CURRENT_DIRECTORY, errc::permission_denied},
{ERROR_DEV_NOT_EXIST, errc::no_such_device},
{ERROR_DEVICE_IN_USE, errc::device_or_resource_busy},
{ERROR_DIR_NOT_EMPTY, errc::directory_not_empty},
{ERROR_DIRECTORY, errc::invalid_argument},
{ERROR_DISK_FULL, errc::no_space_on_device},
{ERROR_FILE_EXISTS, errc::file_exists},
{ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory},
{ERROR_HANDLE_DISK_FULL, errc::no_space_on_device},
{ERROR_INVALID_ACCESS, errc::permission_denied},
{ERROR_INVALID_DRIVE, errc::no_such_device},
{ERROR_INVALID_FUNCTION, errc::function_not_supported},
{ERROR_INVALID_HANDLE, errc::invalid_argument},
{ERROR_INVALID_NAME, errc::no_such_file_or_directory},
{ERROR_INVALID_PARAMETER, errc::invalid_argument},
{ERROR_LOCK_VIOLATION, errc::no_lock_available},
{ERROR_LOCKED, errc::no_lock_available},
{ERROR_NEGATIVE_SEEK, errc::invalid_argument},
{ERROR_NOACCESS, errc::permission_denied},
{ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory},
{ERROR_NOT_READY, errc::resource_unavailable_try_again},
{ERROR_NOT_SAME_DEVICE, errc::cross_device_link},
{ERROR_NOT_SUPPORTED, errc::not_supported},
{ERROR_OPEN_FAILED, errc::io_error},
{ERROR_OPEN_FILES, errc::device_or_resource_busy},
{ERROR_OPERATION_ABORTED, errc::operation_canceled},
{ERROR_OUTOFMEMORY, errc::not_enough_memory},
{ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory},
{ERROR_READ_FAULT, errc::io_error},
{ERROR_REPARSE_TAG_INVALID, errc::invalid_argument},
{ERROR_RETRY, errc::resource_unavailable_try_again},
{ERROR_SEEK, errc::io_error},
{ERROR_SHARING_VIOLATION, errc::permission_denied},
{ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open},
{ERROR_WRITE_FAULT, errc::io_error},
{ERROR_WRITE_PROTECT, errc::permission_denied},
};

for (const auto& pair : win_error_mapping)
if (pair.win == static_cast<DWORD>(err))
return pair.errc;
return errc::invalid_argument;
}

#endif // _LIBCPP_WIN32API
// 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)
inline error_code make_windows_error(int err) { return make_error_code(__win_err_to_errc(err)); }
return std::error_code(GetLastError(), std::system_category());
#else
return capture_errno();
#endif
}

template <class T>
T error_value();
Expand Down
12 changes: 6 additions & 6 deletions libcxx/src/filesystem/file_descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ inline perms posix_get_perms(const StatT& st) noexcept { return static_cast<perm
inline file_status create_file_status(error_code& m_ec, path const& p, const StatT& path_stat, error_code* ec) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not attached to this line: Can you add a release note in libcxx/docs/ReleaseNotes/20.rst?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (ec)
*ec = m_ec;
if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
if (m_ec && (m_ec == errc::no_such_file_or_directory || m_ec == errc::not_a_directory)) {
return file_status(file_type::not_found);
} else if (m_ec) {
ErrorHandler<void> err("posix_stat", ec, &p);
Expand Down Expand Up @@ -229,7 +229,7 @@ inline file_status create_file_status(error_code& m_ec, path const& p, const Sta
inline file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
error_code m_ec;
if (detail::stat(p.c_str(), &path_stat) == -1)
m_ec = detail::capture_errno();
m_ec = detail::get_last_error();
return create_file_status(m_ec, p, path_stat, ec);
}

Expand All @@ -241,7 +241,7 @@ inline file_status posix_stat(path const& p, error_code* ec) {
inline file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
error_code m_ec;
if (detail::lstat(p.c_str(), &path_stat) == -1)
m_ec = detail::capture_errno();
m_ec = detail::get_last_error();
return create_file_status(m_ec, p, path_stat, ec);
}

Expand All @@ -253,7 +253,7 @@ inline file_status posix_lstat(path const& p, error_code* ec) {
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
inline bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
if (detail::ftruncate(fd.fd, to_size) == -1) {
ec = capture_errno();
ec = get_last_error();
return true;
}
ec.clear();
Expand All @@ -262,7 +262,7 @@ inline bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code&

inline bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
if (detail::fchmod(fd.fd, st.st_mode) == -1) {
ec = capture_errno();
ec = get_last_error();
return true;
}
ec.clear();
Expand All @@ -279,7 +279,7 @@ inline file_status FileDescriptor::refresh_status(error_code& ec) {
m_stat = {};
error_code m_ec;
if (detail::fstat(fd, &m_stat) == -1)
m_ec = capture_errno();
m_ec = get_last_error();
m_status = create_file_status(m_ec, name, m_stat, &ec);
return m_status;
}
Expand Down
49 changes: 25 additions & 24 deletions libcxx/src/filesystem/operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ path __canonical(path const& orig_p, error_code* ec) {
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free);
if (hold.get() == nullptr)
return err.report(capture_errno());
return err.report(detail::get_last_error());
return {hold.get()};
#else
# if defined(__MVS__) && !defined(PATH_MAX)
Expand All @@ -96,7 +96,7 @@ path __canonical(path const& orig_p, error_code* ec) {
# endif
path::value_type* ret;
if ((ret = detail::realpath(p.c_str(), buff)) == nullptr)
return err.report(capture_errno());
return err.report(detail::get_last_error());
return {ret};
#endif
}
Expand Down Expand Up @@ -396,9 +396,9 @@ bool __create_directory(const path& p, error_code* ec) {
if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
return true;

if (errno != EEXIST)
return err.report(capture_errno());
error_code mec = capture_errno();
error_code mec = detail::get_last_error();
if (mec != errc::file_exists)
return err.report(mec);
error_code ignored_ec;
const file_status st = status(p, ignored_ec);
if (!is_directory(st))
Expand All @@ -420,10 +420,10 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) {
if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0)
return true;

if (errno != EEXIST)
return err.report(capture_errno());
mec = detail::get_last_error();
if (mec != errc::file_exists)
return err.report(mec);

mec = capture_errno();
error_code ignored_ec;
st = status(p, ignored_ec);
if (!is_directory(st))
Expand All @@ -434,19 +434,19 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) {
void __create_directory_symlink(path const& from, path const& to, error_code* ec) {
ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
if (detail::symlink_dir(from.c_str(), to.c_str()) == -1)
return err.report(capture_errno());
return err.report(detail::get_last_error());
}

void __create_hard_link(const path& from, const path& to, error_code* ec) {
ErrorHandler<void> err("create_hard_link", ec, &from, &to);
if (detail::link(from.c_str(), to.c_str()) == -1)
return err.report(capture_errno());
return err.report(detail::get_last_error());
}

void __create_symlink(path const& from, path const& to, error_code* ec) {
ErrorHandler<void> err("create_symlink", ec, &from, &to);
if (detail::symlink_file(from.c_str(), to.c_str()) == -1)
return err.report(capture_errno());
return err.report(detail::get_last_error());
}

path __current_path(error_code* ec) {
Expand Down Expand Up @@ -489,15 +489,15 @@ path __current_path(error_code* ec) {

unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size), deleter);
if (hold.get() == nullptr)
return err.report(capture_errno(), "call to getcwd failed");
return err.report(detail::get_last_error(), "call to getcwd failed");

return {hold.get()};
}

void __current_path(const path& p, error_code* ec) {
ErrorHandler<void> err("current_path", ec, &p);
if (detail::chdir(p.c_str()) == -1)
err.report(capture_errno());
err.report(detail::get_last_error());
}

bool __equivalent(const path& p1, const path& p2, error_code* ec) {
Expand Down Expand Up @@ -585,10 +585,10 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
return err.report(errc::value_too_large);
detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0);
if (!h)
return err.report(detail::make_windows_error(GetLastError()));
return err.report(detail::get_last_error());
FILETIME last_write = timespec_to_filetime(ts);
if (!SetFileTime(h, nullptr, nullptr, &last_write))
return err.report(detail::make_windows_error(GetLastError()));
return err.report(detail::get_last_error());
#else
error_code m_ec;
array<TimeSpec, 2> tbuf;
Expand Down Expand Up @@ -646,7 +646,7 @@ void __permissions(const path& p, perms prms, perm_options opts, error_code* ec)
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
return err.report(capture_errno());
return err.report(detail::get_last_error());
}
#else
if (set_sym_perms)
Expand Down Expand Up @@ -674,14 +674,14 @@ path __read_symlink(const path& p, error_code* ec) {
#else
StatT sb;
if (detail::lstat(p.c_str(), &sb) == -1) {
return err.report(capture_errno());
return err.report(detail::get_last_error());
}
const size_t size = sb.st_size + 1;
auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]);
#endif
detail::SSizeT ret;
if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1)
return err.report(capture_errno());
return err.report(detail::get_last_error());
// Note that `ret` returning `0` would work, resulting in a valid empty string being returned.
if (static_cast<size_t>(ret) >= size)
return err.report(errc::value_too_large);
Expand All @@ -692,8 +692,9 @@ path __read_symlink(const path& p, error_code* ec) {
bool __remove(const path& p, error_code* ec) {
ErrorHandler<bool> err("remove", ec, &p);
if (detail::remove(p.c_str()) == -1) {
if (errno != ENOENT)
err.report(capture_errno());
error_code mec = detail::get_last_error();
if (mec != errc::no_such_file_or_directory)
err.report(mec);
return false;
}
return true;
Expand Down Expand Up @@ -846,21 +847,21 @@ uintmax_t __remove_all(const path& p, error_code* ec) {
void __rename(const path& from, const path& to, error_code* ec) {
ErrorHandler<void> err("rename", ec, &from, &to);
if (detail::rename(from.c_str(), to.c_str()) == -1)
err.report(capture_errno());
err.report(detail::get_last_error());
}

void __resize_file(const path& p, uintmax_t size, error_code* ec) {
ErrorHandler<void> err("resize_file", ec, &p);
if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
return err.report(capture_errno());
return err.report(detail::get_last_error());
}

space_info __space(const path& p, error_code* ec) {
ErrorHandler<void> err("space", ec, &p);
space_info si;
detail::StatVFS m_svfs = {};
if (detail::statvfs(p.c_str(), &m_svfs) == -1) {
err.report(capture_errno());
err.report(detail::get_last_error());
si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
return si;
}
Expand All @@ -887,7 +888,7 @@ path __temp_directory_path(error_code* ec) {
wchar_t buf[MAX_PATH];
DWORD retval = GetTempPathW(MAX_PATH, buf);
if (!retval)
return err.report(detail::make_windows_error(GetLastError()));
return err.report(detail::get_last_error());
if (retval > MAX_PATH)
return err.report(errc::filename_too_long);
// GetTempPathW returns a path with a trailing slash, which we
Expand Down
Loading