diff --git a/ChangeLog b/ChangeLog index 3d939e7281..8ef8464bd8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2026-09-05 Oleg Tolmatcev + + stat, fstat: Optimize on native Windows. + * lib/stat-w32.c: Include . + (GetFinalPathNameByHandleFuncType, GetFinalPathNameByHandleFunc): + Remove, along with the GetFinalPathNameByHandle and VOLUME_NAME_NONE + macros. + (GetFileInformationByHandleExFuncType, + GetFileInformationByHandleExFunc): Declare regardless of + _GL_WINDOWS_STAT_INODES, as the file name lookup needs them too. + (initialize): Do not resolve GetFinalPathNameByHandleA. + (_gl_fstat_by_handle): Get the name from GetFileInformationByHandleEx, + since it is faster than GetFinalPathNameByHandle and still operates + on the target of symbolic links. + 2026-09-05 Oleg Tolmatcev stat: Fix handling of symbolic links on native Windows. diff --git a/lib/stat-w32.c b/lib/stat-w32.c index b313f86db0..e5a9e28688 100644 --- a/lib/stat-w32.c +++ b/lib/stat-w32.c @@ -44,6 +44,7 @@ #include #include #include +#include #include /* Specification. */ @@ -54,13 +55,6 @@ /* Don't assume that UNICODE is not defined. */ #undef LoadLibrary #define LoadLibrary LoadLibraryA -#undef GetFinalPathNameByHandle -#define GetFinalPathNameByHandle GetFinalPathNameByHandleA - -/* Older mingw headers do not define VOLUME_NAME_NONE. */ -#ifndef VOLUME_NAME_NONE -# define VOLUME_NAME_NONE 4 -#endif #if !WIN32_ASSUME_VISTA @@ -68,20 +62,12 @@ # define GetProcAddress \ (void *) GetProcAddress -# if _GL_WINDOWS_STAT_INODES == 2 /* GetFileInformationByHandleEx was introduced only in Windows Vista. */ typedef DWORD (WINAPI * GetFileInformationByHandleExFuncType) (HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS fiClass, LPVOID lpBuffer, DWORD dwBufferSize); static GetFileInformationByHandleExFuncType GetFileInformationByHandleExFunc = NULL; -# endif -/* GetFinalPathNameByHandle was introduced only in Windows Vista. */ -typedef DWORD (WINAPI * GetFinalPathNameByHandleFuncType) (HANDLE hFile, - LPSTR lpFilePath, - DWORD lenFilePath, - DWORD dwFlags); -static GetFinalPathNameByHandleFuncType GetFinalPathNameByHandleFunc = NULL; static BOOL initialized = FALSE; static void @@ -89,21 +75,14 @@ initialize (void) { HMODULE kernel32 = LoadLibrary ("kernel32.dll"); if (kernel32 != NULL) - { -# if _GL_WINDOWS_STAT_INODES == 2 - GetFileInformationByHandleExFunc = - (GetFileInformationByHandleExFuncType) GetProcAddress (kernel32, "GetFileInformationByHandleEx"); -# endif - GetFinalPathNameByHandleFunc = - (GetFinalPathNameByHandleFuncType) GetProcAddress (kernel32, "GetFinalPathNameByHandleA"); - } + GetFileInformationByHandleExFunc = + (GetFileInformationByHandleExFuncType) GetProcAddress (kernel32, "GetFileInformationByHandleEx"); initialized = TRUE; } #else # define GetFileInformationByHandleExFunc GetFileInformationByHandleEx -# define GetFinalPathNameByHandleFunc GetFinalPathNameByHandle #endif @@ -272,28 +251,33 @@ _gl_fstat_by_handle (HANDLE h, const char *path, struct stat *buf) name suffix. If the file name is already known, use it. Otherwise, for non-empty files, it can be determined through - GetFinalPathNameByHandle - - or through GetFileInformationByHandleEx with argument FileNameInfo - Both require -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ + This requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher. */ if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0) { - char fpath[PATH_MAX]; - if (GetFinalPathNameByHandleFunc != NULL - && GetFinalPathNameByHandleFunc (h, fpath, sizeof (fpath), VOLUME_NAME_NONE) - < sizeof (fpath)) + /* Room for the header and for the file name. */ + union { - size_t length = strlen (fpath); - if (length >= 4 && fpath[length - 4] == '.') + FILE_NAME_INFO info; + char storage[sizeof (FILE_NAME_INFO) + + PATH_MAX * sizeof (WCHAR)]; + } fni; + if (GetFileInformationByHandleExFunc != NULL + && GetFileInformationByHandleExFunc (h, FileNameInfo, + &fni.info, + sizeof (fni))) + { + size_t length = fni.info.FileNameLength / sizeof (WCHAR); + const WCHAR *name = fni.info.FileName; + if (length >= 4 && name[length - 4] == L'.') { - const char *suffix = fpath + length - 3; - if (_stricmp (suffix, "exe", 3) == 0 - || _stricmp (suffix, "bat", 3) == 0 - || _stricmp (suffix, "cmd", 3) == 0 - || _stricmp (suffix, "com", 3) == 0) + const WCHAR *suffix = name + length - 3; + if (_wcsnicmp (suffix, L"exe", 3) == 0 + || _wcsnicmp (suffix, L"bat", 3) == 0 + || _wcsnicmp (suffix, L"cmd", 3) == 0 + || _wcsnicmp (suffix, L"com", 3) == 0) mode |= S_IEXEC_UGO; } }