Skip to content

Commit f09d78a

Browse files
committed
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 <[email protected]>
1 parent d2736e7 commit f09d78a

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

compat/mingw.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,39 @@ int mingw_chmod(const char *filename, int mode)
486486
return _wchmod(wfilename, mode);
487487
}
488488

489+
/**
490+
* Verifies that safe_create_leading_directories() would succeed.
491+
*/
492+
static int has_valid_directory_prefix(wchar_t *wfilename)
493+
{
494+
int n = wcslen(wfilename);
495+
496+
while (n > 0) {
497+
wchar_t c = wfilename[--n];
498+
DWORD attributes;
499+
500+
if (!is_dir_sep(c))
501+
continue;
502+
503+
wfilename[n] = L'\0';
504+
attributes = GetFileAttributesW(wfilename);
505+
wfilename[n] = c;
506+
if (attributes == FILE_ATTRIBUTE_DIRECTORY ||
507+
attributes == FILE_ATTRIBUTE_DEVICE)
508+
return 1;
509+
if (attributes == INVALID_FILE_ATTRIBUTES)
510+
switch (GetLastError()) {
511+
case ERROR_PATH_NOT_FOUND:
512+
continue;
513+
case ERROR_FILE_NOT_FOUND:
514+
/* This implies parent directory exists. */
515+
return 1;
516+
}
517+
return 0;
518+
}
519+
return 1;
520+
}
521+
489522
/* We keep the do_lstat code in a separate function to avoid recursion.
490523
* When a path ends with a slash, the stat will fail with ENOENT. In
491524
* this case, we strip the trailing slashes and stat again.
@@ -546,6 +579,12 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
546579
case ERROR_NOT_ENOUGH_MEMORY:
547580
errno = ENOMEM;
548581
break;
582+
case ERROR_PATH_NOT_FOUND:
583+
if (!has_valid_directory_prefix(wfilename)) {
584+
errno = ENOTDIR;
585+
break;
586+
}
587+
/* fallthru */
549588
default:
550589
errno = ENOENT;
551590
break;

0 commit comments

Comments
 (0)