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
@@ -866,9 +866,27 @@ int mingw_access(const char *filename, int mode)
866 int mingw_chdir(const char *dirname)
867 {
868 wchar_t wdirname[MAX_PATH];
869 +
870 if (xutftowcs_path(wdirname, dirname) < 0)
871 return -1;
871 - return _wchdir(wdirname);
872 +
873 + if (has_symlinks) {
874 + HANDLE hnd = CreateFileW(wdirname, 0,
875 + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
876 + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
877 + if (hnd == INVALID_HANDLE_VALUE) {
878 + errno = err_win_to_posix(GetLastError());
879 + return -1;
880 + }
881 + if (!GetFinalPathNameByHandleW(hnd, wdirname, ARRAY_SIZE(wdirname), 0)) {
882 + errno = err_win_to_posix(GetLastError());
883 + CloseHandle(hnd);
884 + return -1;
885 + }
886 + CloseHandle(hnd);
887 + }
888 +
889 + return _wchdir(normalize_ntpath(wdirname));
890 }
891
892 int mingw_chmod(const char *filename, int mode)