]> git.ipfire.org Git - thirdparty/git.git/commitdiff
mingw: special-case `open(symlink, O_CREAT | O_EXCL)`
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Wed, 17 Dec 2025 14:18:39 +0000 (14:18 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Dec 2025 23:18:12 +0000 (08:18 +0900)
The `_wopen()` function would gladly follow a symbolic link to a
non-existent file and create it when given above-mentioned flags.

Git expects the `open()` call to fail, though. So let's add yet another
work-around to pretend that Windows behaves according to POSIX, see:
https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.

This is required to let t4115.8(--reject removes .rej symlink if it
exists) pass on Windows when enabling the MSYS2 runtime's symbolic link
support.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
compat/mingw.c

index 90ba5cea9d3acee09138a54678460b95edf9ff4e..ba1b7b6dd1e6a75fcc190c5e4e72b372936879ef 100644 (file)
@@ -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);
 
        /*