On 2025-02-23 Pali Rohár wrote: > This happens when people do not know difference and mix things > together. Then the result is even larger mess. WinAPI \\?\ has > meaning to not do any normalization, so consumer should not add or > remove some characters.
:-/ Quite possibly people just think about DOS paths and maybe \\server\share paths. At least I did. One has to append * or \* to list the directory contents, so it's quite natural to skip checking if the unmodified pathname really points to a directory. I wonder how many native apps do such a check. There are weird corner cases: \\?\C:\ \\?\C:/ <-- Old dirent doesn't accept this. //?/C:/ //?/C:\ In the new dirent, GetFullPathNameW converts mixed \/ usage to \, then * is appended and FindFirstFileW is called. The old code calls GetFileAttributes before constructing a full path, and GetFileAttributes fails with \\?\C:/ . I guess it's because \\?\ makes it do no normalization, or something like that. In any case, GetFullPathNameW can make a working pathname from a non-working one, which doesn't sound correct. > > The fact that something else does it wrong doesn't mean that it's > > necessarily fine to do so. Mixing these path types would be very > > bad in stat() or such function. To me it doesn't feel too bad when > > one is specifically trying to open a directory to list its contents > > (like opendir or Python's os.listdir). > > > > Having said that, I will try the GetFileAttributesW solution still. > > Maybe it has some other minor benefits in error detection (perhaps > > it allows shortening the checked error list of FindFirstFileW). > > This could improve error handling. It should catch currently unhandled error codes as ENOENT. Then the error cases of FindFirstFileW don't need to handle quite so many errors like those from \\.\nul (ERROR_INVALID_FUNCTION) and \\.\con (ERROR_NOT_FOUND). I suppose four error codes resulting in ENOENT can be omitted too since those shouldn't occur if GetFileAttributesW succeeds (unless the target changes due to a race condition). GetFileAttributesW docs has the following in "Remarks": If you call GetFileAttributes for a network share, the function fails, and GetLastError returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share. But it works still. Maybe it doesn't in some old Windows version? Calling GetFileAttributesW early in _wopendir (before GetFullPathNameW) made simple recursive directory scanning 20 % slower. The program only goes through the tree counting the entries, not even printing them. In real world apps the effect would be smaller. It's still dramatically faster than with the old dirent when taking advatange of d_type. > > > > An alternative would be to call GetLastError() == > > > > ERROR_INVALID_FLAGS if WideCharToMultiByte fails and retry with > > > > flags = 0. > > > > > > That is too complicated. > > > > It's not much more code. I have attached a patch to do that. On > > Win95, GetLastError returns ERROR_INVALID_FLAGS (1004), so I assume > > that this method works on NT4 too. > > Uff, that is questionable. Win9x was always different and not followed > the true NT based WinAPI. ERROR_INVALID_FLAGS is mentioned in WideCharToMultiByte docs, including the old ones. That error code is used on WinXP when trying CP_UTF8 with WC_ERR_INVALID_CHARS. To be very sure, someone would need to test it on NT4. Either method is equally fine to me, it just has to work correctly. > > I have no real clue about UWP apps, but it seems that GetVersion > > isn't supported in those. Thus, if UWP compatibility matters, the > > GetLastError method should be compatible. > > It is really not supported? For me it looks like very strict rules. I only know that the list I linked doesn't contain it. It has GetVersionExA and GetVersionExW though. Looking at GetVersion docs, they say "[desktop apps only]": https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversion GetVersionExA says "[desktop apps | UWP apps]": https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexa Reality might differ from the docs. > I think that GetVersion* functions are already used in mingw-w64. mingw-w64-crt/misc/__p__osver_emul.c seems to be the only match. It was added only a few months ago in 5f9f1d2e8c29. -- Lasse Collin _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public