aboutsummaryrefslogtreecommitdiff
path: root/compat
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-01-09 18:32:29 -0800
committerJunio C Hamano <gitster@pobox.com>2026-01-09 18:32:29 -0800
commitec13dca8d0619dc1cfe4cee5801b32bc58792ae2 (patch)
tree4c84be76afefce235e96f2cf18b40262f46a65e8 /compat
parentc4a0c8845e2426375ad257b6c221a3a7d92ecfda (diff)
parentaa7b8864d841f16044b0d79fce5baaec1830b3e3 (diff)
downloadgit-ec13dca8d0619dc1cfe4cee5801b32bc58792ae2.tar.xz
Merge branch 'js/prep-symlink-windows' into js/symlink-windows
* js/prep-symlink-windows: trim_last_path_component(): avoid hard-coding the directory separator strbuf_readlink(): support link targets that exceed 2*PATH_MAX strbuf_readlink(): avoid calling `readlink()` twice in corner-cases init: do parse _all_ core.* settings early mingw: do resolve symlinks in `getcwd()` t7800: work around the MSYS path conversion on Windows t6423: introduce Windows-specific handling for symlinking to /dev/null t1305: skip symlink tests that do not apply to Windows t1006: accommodate for symlink support in MSYS2 t0600: fix incomplete prerequisite for a test case t0301: another fix for Windows compatibility t0001: handle `diff --no-index` gracefully mingw: special-case `open(symlink, O_CREAT | O_EXCL)` apply: symbolic links lack a "trustable executable bit" t9700: accommodate for Windows paths
Diffstat (limited to 'compat')
-rw-r--r--compat/mingw.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/compat/mingw.c b/compat/mingw.c
index 939f938fe2..cf4f3c92e7 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -629,6 +629,7 @@ int mingw_open (const char *filename, int oflags, ...)
int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
wchar_t wfilename[MAX_PATH];
open_fn_t open_fn;
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);
@@ -653,6 +654,19 @@ int mingw_open (const char *filename, int oflags, ...)
else if (xutftowcs_path(wfilename, filename) < 0)
return -1;
+ /*
+ * When `symlink` exists and is a symbolic link pointing to a
+ * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would
+ * create that file. Not what we want: Linux would say `EEXIST`
+ * in that instance, which is therefore what Git expects.
+ */
+ if (create &&
+ GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&
+ (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ errno = EEXIST;
+ return -1;
+ }
+
fd = open_fn(wfilename, oflags, mode);
/*
@@ -1225,18 +1239,16 @@ char *mingw_getcwd(char *pointer, int len)
{
wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
+ HANDLE hnd;
if (!ret || ret >= ARRAY_SIZE(cwd)) {
errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
return NULL;
}
- ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
- if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
- HANDLE hnd = CreateFileW(cwd, 0,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (hnd == INVALID_HANDLE_VALUE)
- return NULL;
+ hnd = CreateFileW(cwd, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (hnd != INVALID_HANDLE_VALUE) {
ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
CloseHandle(hnd);
if (!ret || ret >= ARRAY_SIZE(wpointer))
@@ -1245,13 +1257,11 @@ char *mingw_getcwd(char *pointer, int len)
return NULL;
return pointer;
}
- if (!ret || ret >= ARRAY_SIZE(wpointer))
- return NULL;
- if (GetFileAttributesW(wpointer) == INVALID_FILE_ATTRIBUTES) {
+ if (GetFileAttributesW(cwd) == INVALID_FILE_ATTRIBUTES) {
errno = ENOENT;
return NULL;
}
- if (xwcstoutf(pointer, wpointer, len) < 0)
+ if (xwcstoutf(pointer, cwd, len) < 0)
return NULL;
convert_slashes(pointer);
return pointer;