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

Fix the lstat() emulation on Windows #1291

Commits on Jul 29, 2022

  1. lstat(mingw): correctly detect ENOTDIR scenarios

    Files' attributes can indicate more than just whether they are files or
    directories. It was reported in Git for Windows that on certain network
    shares, this led to a nasty problem trying to create tags:
    
    	$ git tag -a -m "automatic tag creation"  test_dir/test_tag
    	fatal: cannot lock ref 'refs/tags/test_dir/test_tag': unable to resolve reference 'refs/tags/test_dir/test_tag': Not a directory
    
    Note: This does not necessarily happen with all types of network shares.
    One setup where it _did_ happen is a Windows Server 2019 VM, and as
    hinted in
    
    	http://woshub.com/slow-network-shared-folder-refresh-windows-server/
    
    in the indicated instance the following commands worked around the bug:
    
    	Set-SmbClientConfiguration -DirectoryCacheLifetime 0
    	Set-SmbClientConfiguration -FileInfoCacheLifetime 0
    	Set-SmbClientConfiguration -FileNotFoundCacheLifetime 0
    
    This would impact performance negatively, though, as it essentially
    turns off all caching, therefore we do not want to require users to do
    that just to be able to use Git on Windows.
    
    The underlying bug is in the code added in 4b0abd5 (mingw: let
    lstat() fail with errno == ENOTDIR when appropriate, 2016-01-26) that
    emulates the POSIX behavior where `lstat()` should return `ENOENT` if
    the file or directory simply does not exist but could be created, and
    `ENOTDIR` if there is no file or directory nor could there be because a
    leading path already exists and is not a directory.
    
    In that code, the return value of `GetFileAttributesW()` is interpreted
    as an enum value, not as a bit field, so that a perfectly fine leading
    directory can be misdetected as "not a directory".
    
    As a consequence, the `read_refs_internal()` function would return
    `ENOTDIR`, suggesting not only that the tag in the `git tag` invocation
    above does not exist, but that it cannot even be created.
    
    Let's fix the code so that it interprets the return value of the
    `GetFileAttributesW()` call correctly.
    
    This fixes git-for-windows#3727
    
    Reported-by: Pierre Garnier <pgarnier@mega.com>
    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
    dscho committed Jul 29, 2022
    Configuration menu
    Copy the full SHA
    b4f08ee View commit details
    Browse the repository at this point in the history