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