On Thu, 25 Jun 2026 at 17:52, Jonathan Wakely <[email protected]> wrote:
>
> On Wed, 24 Jun 2026 at 23:54, Adam Wood <[email protected]> wrote:
> >
> >
> >
> > On Wed, Jun 24, 2026 at 2:38 PM Jonathan Wakely <[email protected]> wrote:
> >>
> >> On Wed, 4 Mar 2026 at 23:17, Adam Wood <[email protected]> wrote:
> >> >
> >> >
> >> >
> >> > On Wed, Mar 4, 2026 at 9:14 AM Jonathan Wakely <[email protected]> 
> >> > wrote:
> >> >>
> >> >> On Mon, 16 Feb 2026 at 22:42, Adam Wood <[email protected]> 
> >> >> wrote:
> >> >> >
> >> >> > Tested on x86_64-w64-mingw32 on Windows 11.
> >> >> >
> >> >> > The changes in v4 make sure the new symlink functions are only 
> >> >> > defined/enabled
> >> >> > on versions of Windows with symlink support.
> >> >> >
> >> >> > Because path resolution may be different between Windows and POSIX 
> >> >> > when a
> >> >> > dotdot follows a symlink, I also made some edits to tests involving 
> >> >> > that
> >> >> > specific case. I removed my changes to fs::absolute and
> >> >> > fs::canonical because I was misplaced and was trying to force Windows 
> >> >> > to
> >> >> > act like POSIX in that specific case.
> >> >> >
> >> >> > Finally, I dealt with the issue that creating symlinks with the 
> >> >> > unprivileged
> >> >> > flag returns an error in earlier versions of Windows by just trying 
> >> >> > again
> >> >> > if ERROR_INVALID_PARAMETER occurs without the unpriviledged flag. This
> >> >> > is how MSVC STL does it as well.
> >> >> >
> >> >> > The patch does not support junctions or mount points.
> >> >>
> >> >> Hi Adam,
> >> >>
> >> >> Thanks for the new patch. I'm still reviewing it, but I see these
> >> >> tests failing using a mingw-w64 cross compiler and testing under Wine:
> >> >>
> >> >> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/1.cc:27:
> >> >> void test_successful_copy(const std::filesystem::__cxx11::path&, bool
> >> >> (*)(const std::filesystem::__cxx11::path&)): Assertion
> >> >> 'is_some_file_type(p2)' failed.
> >> >> FAIL: 
> >> >> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_symlink/1.cc
> >> >>
> >> >>  
> >> >> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc:36:
> >> >> void test01(): Assertion 'st1.type() == fs::file_type::directory'
> >> >> failed.
> >> >> FAIL: 
> >> >> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
> >> >>
> >> >> Do these PASS for you on real Windows?
> >> >>
> >> > Those tests all PASS on my Windows 11 VM.
> >>
> >> I've installed a Windows 11 VM. I built all the filesystem tests using
> >> a mingw-w64 cross compiler and ran the tests under Wine. For each test
> >> that PASSed before your changes and FAILed with your patch, I copied
> >> the .exe to the Windows VM and ran it there, and they also FAILed on
> >> the VM. So this doesn't seem to be a problem with Wine, the tests FAIL
> >> for Windows 11 too.
> >
> >
> > I've been compiling the tests entirely within the Windows VM and msys2 
> > terminal. I'll try this method and see if I can fix this.
>
> I've debugged it a bit and the problem is that
> symlink_status(".").type() is returning file_type::regular not
> file_type::directory.
>
> After the call to _fstat64 the stat buffer has st_mode = 33206, so
> S_ISREG(st_mode) is true.
>
> I don't think _ops_osfhandle works for directories, I think it can
> only handle regular files, pipes, and character devices. So I think
> your __stat_windows function needs to check for a directory before it
> opens the file descriptor to pass to _fstat64.

I think this fixes some of the failing tests:

 enum class FileType { Err = -1, Dir = S_IFDIR, Link = S_IFLNK, Other = 0 };

 // -1 error, 0 not a directory or symlink, otherwise S_IFDIR or S_IFLNK.
 inline FileType __check_handle_type(HANDLE handle)
 {
#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();
       return FileType::Err;
     }
   if (type_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
     return FileType::Dir;
   if (type_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT
          && type_info.ReparseTag == IO_REPARSE_TAG_SYMLINK)
     return FileType::Link;
#endif
   return FileType::Other;
 }

 // -1 error, 0 not a symlink, 1 a symlink
 inline int __is_handle_symlink(HANDLE handle)
 {
   if (FileType type = __check_handle_type(handle); type != FileType::Err)
     return type == FileType::Link;
   return -1;
 }

 inline int __stat_windows(const wchar_t* path, stat_type* buffer,
                           bool following_symlinks)
 {
   HANDLE handle = __open_for_stat(path, following_symlinks);
   if (handle == INVALID_HANDLE_VALUE)
     return -1;
   // Manually check for directory or symlink, because _fstat does not.
   FileType type = __check_handle_type(handle);
   if (type == FileType::Err)
     {
       CloseHandle(handle);
       return -1;
     }
   int fd = ::_open_osfhandle((intptr_t)handle, _O_RDONLY);
   if (fd == -1)
     {
       CloseHandle(handle);
       return -1;
     }
   int stat_result = ::_fstat64(fd, buffer);
   if (type != FileType::Other)
     {
       // Clear the previous file type.
       buffer->st_mode &= ~S_IFMT;
       buffer->st_mode |= (::mode_t)type;
     }
   ::_close(fd);
   return stat_result;
 }

i.e. replace __is_handle_symlink with __check_handle_type which checks
for directories and symlinks and returns either S_IFDIR or S_IFLNK.
Then define __is_handle_symlink in terms of that new function.

I'm still seeing other regressions though.

Reply via email to