mingw: allow `mingw_chdir()` to change to symlink-resolved directories
If symlinks are enabled, resolve all symlinks when changing directories, as required by POSIX. Note: Git's `real_path()` function bases its link resolution algorithm on this property of `chdir()`. Unfortunately, the current directory on Windows is limited to only MAX_PATH (260) characters. Therefore using symlinks and long paths in combination may be problematic. 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>
Karsten Blees committed
Jan 9, 2026 at 20:05 UTC
43745a7d55daa1aa0937a3c6e8b521bd026a31f1
1 file changed
+19
-1
compat/mingw.c
+19
-1
index 55f0bb478e..5d2a8c247c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -866,9 +866,27 @@ int mingw_access(const char *filename, int mode)
int mingw_chdir(const char *dirname)
{
wchar_t wdirname[MAX_PATH];
+
if (xutftowcs_path(wdirname, dirname) < 0)
return -1;
- return _wchdir(wdirname);
+
+ if (has_symlinks) {
+ HANDLE hnd = CreateFileW(wdirname, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (hnd == INVALID_HANDLE_VALUE) {
+ errno = err_win_to_posix(GetLastError());
+ return -1;
+ }
+ if (!GetFinalPathNameByHandleW(hnd, wdirname, ARRAY_SIZE(wdirname), 0)) {
+ errno = err_win_to_posix(GetLastError());
+ CloseHandle(hnd);
+ return -1;
+ }
+ CloseHandle(hnd);
+ }
+
+ return _wchdir(normalize_ntpath(wdirname));
}
int mingw_chmod(const char *filename, int mode)