mingw: emulate `stat()` a little more faithfully

When creating directories via `safe_create_leading_directories()`, we might encounter an already-existing directory which is not readable by the current user. To handle that situation, Git's code calls `stat()` to determine whether we're looking at a directory. In such a case, `CreateFile()` will fail, though, no matter what, and consequently `mingw_stat()` will fail, too. But POSIX semantics seem to still allow `stat()` to go forward. So let's call `mingw_lstat()` to the rescue if we fail to get a file handle due to denied permission in `mingw_stat()`, and fill the stat info that way. We need to be careful to not allow this to go forward in case that we're looking at a symbolic link: to resolve the link, we would still have to create a file handle, and we just found out that we cannot. Therefore, `stat()` still needs to fail with `EACCES` in that case. This fixes https://github.com/git-for-windows/git/issues/2531. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Jan 9, 2026 at 20:05 UTC 2cba5746c03f85fedd45a08b4f91921c5960bb36
1 file changed +13 -1
compat/mingw.c
+13 -1
@@ -1273,7 +1273,19 @@ int mingw_stat(const char *file_name, struct stat *buf)
1273 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
1274 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1275 if (hnd == INVALID_HANDLE_VALUE) {
1276 - errno = err_win_to_posix(GetLastError());
1276 + DWORD err = GetLastError();
1277 +
1278 + if (err == ERROR_ACCESS_DENIED &&
1279 + !mingw_lstat(file_name, buf) &&
1280 + !S_ISLNK(buf->st_mode))
1281 + /*
1282 + * POSIX semantics state to still try to fill
1283 + * information, even if permission is denied to create
1284 + * a file handle.
1285 + */
1286 + return 0;
1287 +
1288 + errno = err_win_to_posix(err);
1289 return -1;
1290 }
1291 result = get_file_info_by_handle(hnd, buf);