Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compat/mingw: rename the symlink, not the target #1864

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dscho
Copy link
Member

@dscho dscho commented Feb 21, 2025

This contribution just came in as a Git for Windows Pull Request.

Granted, I have not yet managed to find time to upstream support for symbolic links (it is in the pipeline: https://github.com/dscho/git/tree/support-symlinks-on-windows), but this patch still should be in upstream Git because there are other ways to create symbolic links than by using Git.

Cc: Patrick Steinhardt [email protected]

Since 183ea3e [1], a new technique is used on Windows to rename files,
where supported. The first step of this technique is to open the file
with `CreateFileW`. At that time, `FILE_ATTRIBUTE_NORMAL` was passed as
the value of the `dwFlagsAndAttributes` argument. In b30404d [2], this
was improved by passing `FILE_FLAG_BACKUP_SEMANTICS`, to support
directories as well as regular files.

However, neither value of `dwFlagsAndAttributes` is sufficient to open
a symbolic link with the correct semantics to rename it. Symlinks on
Windows are reparse points. Attempting to open a reparse point with
`CreateFileW` dereferences the reparse point and opens the target
instead, unless `FILE_FLAG_OPEN_REPARSE_POINT` is included in
`dwFlagsAndAttributes`. This is documented for that flag and in the
"Symbolic Link Behavior" section of the `CreateFileW` docs [3].

This produces a regression where attempting to rename a symlink on
Windows renames its target to the intended new name and location of the
symlink. For example, if `symlink` points to `file`, then running

    git mv symlink symlink-renamed

leaves `symlink` in place and unchanged, but renames `file` to
`symlink-renamed` [4].

This regression is detectable by existing tests in `t7001-mv.sh`, but
the tests must be run by a Windows user with the ability to create
symlinks, and the `ln -s` command used to create the initial symlink
must also be able to create a real symlink (such as by setting the
`MSYS` environment variable to `winsymlinks:nativestrict`). Then
these two tests fail if the regression is present, and pass otherwise:

    38 - git mv should overwrite file with a symlink
    39 - check moved symlink

Let's fix this, so that renaming a symlink again renames the symlink
itself and leaves the target unchanged, by passing

    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT

as the `dwFlagsAndAttributes` argument. This is sufficient (and safe)
because including `FILE_FLAG_OPEN_REPARSE_POINT` causes no harm even
when used to open a file or directory that is not a reparse point. In
that case, as noted in [3], this flag is simply ignored.

[1]: git-for-windows@183ea3e
[2]: git-for-windows@b30404d
[3]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
[4]: git-for-windows#5436

Signed-off-by: Eliah Kagan <[email protected]>
Signed-off-by: Johannes Schindelin <[email protected]>
@dscho dscho self-assigned this Feb 21, 2025
@dscho
Copy link
Member Author

dscho commented Feb 21, 2025

/submit

Copy link

gitgitgadget bot commented Feb 21, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-1864/dscho/fix-renaming-symlinks-on-windows-v1

To fetch this version to local tag pr-1864/dscho/fix-renaming-symlinks-on-windows-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-1864/dscho/fix-renaming-symlinks-on-windows-v1

Copy link

gitgitgadget bot commented Feb 21, 2025

On the Git mailing list, Junio C Hamano wrote (reply to this):

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

>     This contribution just came in as a Git for Windows Pull Request.
>     
>     Granted, I have not yet managed to find time to upstream support for
>     symbolic links (it is in the pipeline:
>     https://github.com/dscho/git/tree/support-symlinks-on-windows), but this
>     patch still should be in upstream Git because there are other ways to
>     create symbolic links than by using Git.

Thanks, let me mark it for 'next' immediately.

Copy link

gitgitgadget bot commented Feb 22, 2025

This patch series was integrated into seen via git@3c0f5d2.

@gitgitgadget gitgitgadget bot added the seen label Feb 22, 2025
Copy link

gitgitgadget bot commented Feb 24, 2025

On the Git mailing list, Patrick Steinhardt wrote (reply to this):

On Fri, Feb 21, 2025 at 10:26:15AM -0800, Junio C Hamano wrote:
> "Johannes Schindelin via GitGitGadget" <[email protected]>
> writes:
> 
> >     This contribution just came in as a Git for Windows Pull Request.
> >     
> >     Granted, I have not yet managed to find time to upstream support for
> >     symbolic links (it is in the pipeline:
> >     https://github.com/dscho/git/tree/support-symlinks-on-windows), but this
> >     patch still should be in upstream Git because there are other ways to
> >     create symbolic links than by using Git.
> 
> Thanks, let me mark it for 'next' immediately.

The Windows API continues to be quite esoteric to me, so thanks for
plugging the gaps in my knowledge and fixing this edge case.

Patrick

Copy link

gitgitgadget bot commented Feb 24, 2025

This patch series was integrated into seen via git@e205ecd.

Copy link

gitgitgadget bot commented Feb 24, 2025

This patch series was integrated into next via git@8a9f3a5.

@gitgitgadget gitgitgadget bot added the next label Feb 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants