From 731fe282e1c9d3721055bfcebcb80ac6a61b742f Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 11 Jun 2015 15:00:12 +0000 Subject: [PATCH] mingw: 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 --- compat/mingw.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/compat/mingw.c b/compat/mingw.c index 4582b5d450..8e1993f4af 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -634,6 +634,39 @@ int mingw_chmod(const char *filename, int mode) return _wchmod(wfilename, mode); } +/** + * 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; +} + int mingw_lstat(const char *file_name, struct stat *buf) { WIN32_FILE_ATTRIBUTE_DATA fdata; @@ -687,6 +720,12 @@ error: 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;