aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarsten Blees <karsten.blees@gmail.com>2026-01-09 20:05:09 +0000
committerJunio C Hamano <gitster@pobox.com>2026-01-09 18:32:55 -0800
commit43745a7d55daa1aa0937a3c6e8b521bd026a31f1 (patch)
tree7fa87f23d96dec5a0e4038a71ccaf620632c7491
parent5e88e98c04267b44e4f822f297c60e1e8c852411 (diff)
downloadgit-43745a7d55daa1aa0937a3c6e8b521bd026a31f1.tar.xz
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>
-rw-r--r--compat/mingw.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/compat/mingw.c b/compat/mingw.c
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)