For a directory symlink, I think the type of the file depends on whether
you call stat or lstat. For stat, the type should be a directory. For
lstat, it should be a symlink. So I think your __check_handle_type should
work for stat, but I can't exactly tell what would happen when it gets
called from lstat.

Anyways, I am struggling to make the cross-compiler, but hopefully tomorrow
I'll follow this tutorial:
https://sourceforge.net/p/mingw-w64/wiki2/Build%20a%20native%20Windows%2064-bit%20gcc%20from%20Linux%20%28including%20cross-compiler%29/
up to the end of step 3, and then I will be able to run make check-compile.

On Thu, Jun 25, 2026 at 3:26 PM Jonathan Wakely <[email protected]> wrote:

> On Thu, 25 Jun 2026 at 18:34, Jonathan Wakely <[email protected]> wrote:
> >
> > 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;
>
> A directory symlink has both DIRECTORY and REPARSE_POINT set in
> FileAttributes, so to detect a symlinks we need to check for that
> first. So I've switched the order of the checks in my local build, and
> that fixes a few more of the failing tests.
>
> > #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