Subject: Re: [PATCH 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`

From: Junio C Hamano <[email-masked]>
Date: Sat, 29 Nov 2025 22:49:22 -0800

"Johannes Schindelin via GitGitGadget" <[email-masked]>
writes:

> From: Johannes Schindelin <[email-masked]>
>
> 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 like Linux.

"like Linux" -> "as POSIX expects"?

cf. 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 <[email-masked]>
> ---
>  compat/mingw.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
>
> diff --git a/compat/mingw.c b/compat/mingw.c
> index 736a07a028..9fbf12a3d3 100644
> --- a/compat/mingw.c
> +++ b/compat/mingw.c
> @@ -627,6 +627,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);
>  
> @@ -651,6 +652,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.
> +	 */

"Linux" -> "open() on POSIX-compliant systems".

IOW, _wopen() does not have to behave like POSIX open() and the compat/
layer is how the emulation goes.

FWIW, this is not limited to symbolic links but anything that exists
at the path specified should cause the same EEXIST failure.  The
O_CREAT|O_EXCL combination asks the system to atomically create the
thing anew (or fail).

    O_EXCL
        If O_CREAT and O_EXCL are set, open() shall fail if the file
        exists. The check for the existence of the file and the creation of
        the file if it does not exist shall be atomic with respect to other
        threads executing open() naming the same filename in the same
        directory with O_EXCL and O_CREAT set. If O_EXCL and O_CREAT are
        set, and path names a symbolic link, open() shall fail and set errno
        to [EEXIST], regardless of the contents of the symbolic link. If
        O_EXCL is set and O_CREAT is not set, the result is undefined.

> +	if (create &&
> +	    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&
> +	    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
> +		errno = EEXIST;
> +		return -1;
> +	}
> +
>  	fd = open_fn(wfilename, oflags, mode);
>  
>  	/*