diff options
author | Johannes Schindelin <johannes.schindelin@gmx.de> | 2016-01-26 15:34:52 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2016-01-26 13:42:59 -0800 |
commit | 4b0abd5c695c87bf600e57b6a5c7d6844707d34c (patch) | |
tree | fda17d83791e71a6b5b5b7d25d4676b58bd1c6b8 /compat | |
parent | mingw: try to delete target directory before renaming (diff) | |
download | tgif-4b0abd5c695c87bf600e57b6a5c7d6844707d34c.tar.xz |
mingw: let lstat() fail with errno == ENOTDIR when appropriate
POSIX semantics requires lstat() to fail with ENOTDIR when "[a]
component of the path prefix names an existing file that is neither a
directory nor a symbolic link to a directory".
See http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
This behavior is expected by t1404-update-ref-df-conflicts now.
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.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/compat/mingw.c b/compat/mingw.c index 9e64f76bde..545e952a58 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -454,6 +454,39 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)(filetime_to_hnsec(ft) / 10000000); } +/** + * Verifies that safe_create_leading_directories() would succeed. + */ +static int has_valid_directory_prefix(wchar_t *wfilename) +{ + int n = wcslen(wfilename); + + while (n > 0) { + wchar_t c = wfilename[--n]; + DWORD attributes; + + if (!is_dir_sep(c)) + continue; + + wfilename[n] = L'\0'; + attributes = GetFileAttributesW(wfilename); + wfilename[n] = c; + if (attributes == FILE_ATTRIBUTE_DIRECTORY || + attributes == FILE_ATTRIBUTE_DEVICE) + return 1; + if (attributes == INVALID_FILE_ATTRIBUTES) + switch (GetLastError()) { + case ERROR_PATH_NOT_FOUND: + continue; + case ERROR_FILE_NOT_FOUND: + /* This implies parent directory exists. */ + return 1; + } + return 0; + } + return 1; +} + /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. @@ -514,6 +547,12 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; + case ERROR_PATH_NOT_FOUND: + if (!has_valid_directory_prefix(wfilename)) { + errno = ENOTDIR; + break; + } + /* fallthru */ default: errno = ENOENT; break; |