aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarsten Blees <karsten.blees@gmail.com>2026-01-09 20:05:01 +0000
committerJunio C Hamano <gitster@pobox.com>2026-01-09 18:32:55 -0800
commit2c37842ff97c28876e980f1829bc732c98dcde14 (patch)
treeed08718453a115ace6996e73881991dd1a2a0bc8
parent882e5e05282758c736bba4e719c5f6f626986fe7 (diff)
downloadgit-2c37842ff97c28876e980f1829bc732c98dcde14.tar.xz
mingw: let `mingw_lstat()` error early upon problems with reparse points
When obtaining lstat information for reparse points, we need to call `FindFirstFile()` in addition to `GetFileInformationEx()` to obtain the type of the reparse point (symlink, mount point etc.). However, currently there is no error handling whatsoever if `FindFirstFile()` fails. Call `FindFirstFile()` before modifying the `stat *buf` output parameter and error out if the call fails. Note: The `FindFirstFile()` return value includes all the data that we get from `GetFileAttributesEx()`, so we could replace `GetFileAttributesEx()` with `FindFirstFile()`. We don't do that because `GetFileAttributesEx()` is about twice as fast for single files. I.e. we only pay the extra cost of calling `FindFirstFile()` in the rare case that we encounter a reparse point. Please also note that the indentation the remaining reparse point code changed, and hence the best way to look at this diff is with `--color-moved -w`. That code was _not_ moved because a subsequent commit will move it to an altogether different function, anyway. Signed-off-by: Karsten Blees <karsten.blees@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--compat/mingw.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/compat/mingw.c b/compat/mingw.c
index ec6c2801d3..23a926c7d1 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -920,6 +920,7 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
int mingw_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
+ WIN32_FIND_DATAW findbuf = { 0 };
wchar_t wfilename[MAX_PATH];
int wlen = xutftowcs_path(wfilename, file_name);
if (wlen < 0)
@@ -934,6 +935,13 @@ int mingw_lstat(const char *file_name, struct stat *buf)
}
if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
+ /* for reparse points, use FindFirstFile to get the reparse tag */
+ if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ HANDLE handle = FindFirstFileW(wfilename, &findbuf);
+ if (handle == INVALID_HANDLE_VALUE)
+ goto error;
+ FindClose(handle);
+ }
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
@@ -946,20 +954,16 @@ int mingw_lstat(const char *file_name, struct stat *buf)
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- WIN32_FIND_DATAW findbuf;
- HANDLE handle = FindFirstFileW(wfilename, &findbuf);
- if (handle != INVALID_HANDLE_VALUE) {
- if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
- (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
- buf->st_mode = S_IFLNK | S_IREAD;
- if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
- buf->st_mode |= S_IWRITE;
- }
- FindClose(handle);
+ if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+ (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
+ buf->st_mode = S_IFLNK | S_IREAD;
+ if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+ buf->st_mode |= S_IWRITE;
}
}
return 0;
}
+error:
switch (GetLastError()) {
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION: