On Fri, Jul 10, 2026 at 1:34 PM Jonathan Wakely <[email protected]> wrote:

> Do not set errno in the helper functions __open_for_stat and
> __check_handle_type, because those are used from std::filesystem APIs
> which should set a std::error_code instead of changing errno. Move
> setting errno into the Windows-specific __stat_windows function and
> change the helper functions to use a std::error_code parameter instead.
>
This simplifies a lot. Thanks.

>
> Also simplify the Windows implementation of fs::read_symlink by moving
> the error handling for non-symlinks into windows_read_symlink_handle.
>
> libstdc++-v3/ChangeLog:
>
>         * src/c++17/fs_ops.cc (windows_read_symlink_handle): Use
>         __detail::__is_handle_symlink and report an error for
>         non-symlinks.
>         (filesystem::read_symlink): Remove error handling for
>         non-symlinks.
>         * src/filesystem/ops-common.h (__detail::__open_for_stat): Use
>         std::error_code parameter to report errors instead of setting
>         errno.
>         (__detail::__check_handle_type): Likewise.
>         (__detail::__is_handle_symlink): Likewise.
>         (__detail::__stat_windows): Pass std::error_code to helper
>         functions and set errno to report errors.
> ---
>
> Tested x86_64-linux and x86_64-w64-mingw32 cross with Wine testing.
>
>  libstdc++-v3/src/c++17/fs_ops.cc         | 26 ++++++---------
>  libstdc++-v3/src/filesystem/ops-common.h | 41 +++++++++++++-----------
>  2 files changed, 32 insertions(+), 35 deletions(-)
>
> diff --git a/libstdc++-v3/src/c++17/fs_ops.cc
> b/libstdc++-v3/src/c++17/fs_ops.cc
> index 81bffc7b1513..31f5abfa6fc7 100644
> --- a/libstdc++-v3/src/c++17/fs_ops.cc
> +++ b/libstdc++-v3/src/c++17/fs_ops.cc
> @@ -1257,6 +1257,13 @@ namespace
>                               std::error_code& ec,
>                               fs::path& result)
>    {
> +    if (!fs::__detail::__is_handle_symlink(link_handle.handle, ec))
> +      {
> +       if (!ec)
> +         ec.assign(EINVAL, std::generic_category()); // not a symlink
> +       return;
> +      }
> +
>      PREPARSE_DATA_BUFFER reparse_buffer = nullptr;
>      std::unique_ptr<char[]> big_buffer;
>
> @@ -1374,23 +1381,8 @@ fs::path fs::read_symlink(const path& p,
> error_code& ec)
>  #elif defined(_GLIBCXX_FILESYSTEM_IS_WINDOWS) \
>        && defined(SYMBOLIC_LINK_FLAG_DIRECTORY)
>    auto_win_file_handle link_handle(p.c_str(), ec, false);
> -  if (!link_handle)
> -    return result;
> -
> -  int is_symlink = __detail::__is_handle_symlink(link_handle.handle);
> -  if (is_symlink == -1)
> -    {
> -      ec = __last_system_error();
> -      return result;
> -    }
> -
> -  if (!is_symlink)
> -    {
> -      ec.assign(EINVAL, std::generic_category());
> -      return result;
> -    }
> -
> -  windows_read_symlink_handle(link_handle, ec, result);
> +  if (link_handle)
> +    windows_read_symlink_handle(link_handle, ec, result);
>  #else
>    ec = std::make_error_code(std::errc::function_not_supported);
>  #endif
> diff --git a/libstdc++-v3/src/filesystem/ops-common.h
> b/libstdc++-v3/src/filesystem/ops-common.h
> index cdb4a1ca0ca8..df610b74e402 100644
> --- a/libstdc++-v3/src/filesystem/ops-common.h
> +++ b/libstdc++-v3/src/filesystem/ops-common.h
> @@ -113,7 +113,9 @@ namespace __detail
>
>    using stat_type = struct ::__stat64;
>
> -  inline HANDLE __open_for_stat(const wchar_t* path, bool
> following_symlinks)
> +  inline HANDLE
> +  __open_for_stat(const wchar_t* path, bool following_symlinks,
> +                 std::error_code& ec)
>    {
>      constexpr auto share_flags
>        = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
> @@ -124,10 +126,7 @@ namespace __detail
>        = CreateFileW(path, 0, share_flags, 0, OPEN_EXISTING, file_flags,
> 0);
>
>      if (handle == INVALID_HANDLE_VALUE)
> -      {
> -       // CreateFileW does not set errno.
> -       errno =
> std::__last_system_error().default_error_condition().value();
> -      }
> +      ec = std::__last_system_error();
>
>      return handle;
>    }
> @@ -138,14 +137,15 @@ namespace __detail
>    // to a symlink or directory, then fix the result of _fstat64
> accordingly.
>    enum class FileType { Err = -1, Dir = S_IFDIR, Link = S_IFLNK, Other =
> 0 };
>
> -  inline FileType __check_handle_type(HANDLE handle, bool
> following_symlinks)
> +  inline FileType
> +  __check_handle_type(HANDLE handle, bool following_symlinks, error_code&
> ec)
>    {
>  #ifdef SYMBOLIC_LINK_FLAG_DIRECTORY
>      FILE_ATTRIBUTE_TAG_INFO type_info;
>      if (!GetFileInformationByHandleEx(handle, FileAttributeTagInfo,
>                                       &type_info, sizeof(type_info)))
>        {
> -       errno =
> std::__last_system_error().default_error_condition().value();
> +       ec = std::__last_system_error();
>         return FileType::Err;
>        }
>      // A directory symlink has both DIRECTORY and REPARSE_POINT set,
> @@ -160,32 +160,37 @@ namespace __detail
>      return FileType::Other;
>    }
>
> -  // -1 error, 0 not a symlink, 1 a symlink
> -  inline int __is_handle_symlink(HANDLE handle)
> +  // If no error occurs and `handle` represents a symlink, returns true.
> +  // Otherwise, returns false. Sets `ec` if an error occurred.
> +  inline bool __is_handle_symlink(HANDLE handle, std::error_code& ec)
>    {
> -    FileType type = __check_handle_type(handle, false);
> -    if (type == FileType::Err)
> -      return -1;
> -    return type == FileType::Link;
> +    return __check_handle_type(handle, false, ec) == FileType::Link;
>    }
>
> -  inline int __stat_windows(const wchar_t* path, stat_type* buffer,
> -                           bool following_symlinks)
> +  inline int
> +  __stat_windows(const wchar_t* path, stat_type* buffer,
> +                bool following_symlinks)
>    {
> -    HANDLE handle = __open_for_stat(path, following_symlinks);
> +    std::error_code ec;
> +    HANDLE handle = __open_for_stat(path, following_symlinks, ec);
>      if (handle == INVALID_HANDLE_VALUE)
> -      return -1;
> +      {
> +       errno = ec.default_error_condition().value();
> +       return -1;
> +      }
>      // Manually check for directory or symlink, because _fstat does not.
> -    FileType type = __check_handle_type(handle, following_symlinks);
> +    FileType type = __check_handle_type(handle, following_symlinks, ec);
>      if (type == FileType::Err)
>        {
>         CloseHandle(handle);
> +       errno = ec.default_error_condition().value();
>         return -1;
>        }
>      int fd = ::_open_osfhandle((intptr_t)handle, _O_RDONLY);
>      if (fd == -1)
>        {
>         CloseHandle(handle);
> +       errno = ec.default_error_condition().value();
>         return -1;
>        }
>      int stat_result = ::_fstat64(fd, buffer);
> --
> 2.55.0
>
>

Reply via email to