aboutsummaryrefslogtreecommitdiffstats
path: root/compat
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2022-07-29 10:05:52 +0000
committerJunio C Hamano <gitster@pobox.com>2022-07-29 11:24:04 -0700
commit82ba1191ffeaf1482fce9fd9e72334c8dbc3bbbe (patch)
treefe42215098703f62d2131f212ce32afb424ceeea /compat
parentfd59c5bdeeb50f18e86f36cbf7a0b82554621690 (diff)
downloadgit-82ba1191ffeaf1482fce9fd9e72334c8dbc3bbbe.tar.gz
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 4b0abd5c695 (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 https://github.com/git-for-windows/git/issues/3727 Reported-by: Pierre Garnier <pgarnier@mega.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'compat')
-rw-r--r--compat/mingw.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/compat/mingw.c b/compat/mingw.c
index 6fe80fdf01..77471d9a22 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -768,8 +768,8 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
wfilename[n] = L'\0';
attributes = GetFileAttributesW(wfilename);
wfilename[n] = c;
- if (attributes == FILE_ATTRIBUTE_DIRECTORY ||
- attributes == FILE_ATTRIBUTE_DEVICE)
+ if (attributes &
+ (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))
return 1;
if (attributes == INVALID_FILE_ATTRIBUTES)
switch (GetLastError()) {