summaryrefslogtreecommitdiff
path: root/compat/mingw.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/mingw.c')
-rw-r--r--compat/mingw.c39
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;