From 325fee1f922150460547d1317b3abd443a657385 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 4 Mar 2019 09:59:27 +0000 Subject: win32: change handling of trailing slashes in stat(2) The code to implement stat(2) works around the fact that getting the attributes of a file fails if its name ends with a path separator. Directory names with a trailing path separator work fine. Why bother with this workaround? Linux doesn't. Instead try to return a meaningful error code. --- win32/mingw.c | 51 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) (limited to 'win32') diff --git a/win32/mingw.c b/win32/mingw.c index ea439a66d..9d9935f4b 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -287,6 +287,8 @@ static inline mode_t file_attr_to_st_mode(DWORD attr) static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) { + size_t len; + if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) return 0; @@ -316,6 +318,11 @@ static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fd return ENAMETOOLONG; case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; + case ERROR_INVALID_NAME: + len = strlen(fname); + if (len > 1 && (fname[len-1] == '/' || fname[len-1] == '\\')) + return ENOTDIR; + return EINVAL; default: return ENOENT; } @@ -473,11 +480,7 @@ static uid_t file_owner(HANDLE fh) } #endif -/* 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. - * - * If follow is true then act like stat() and report on the link +/* If follow is true then act like stat() and report on the link * target. Otherwise report on the link itself. */ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) @@ -564,46 +567,14 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) return -1; } -/* We provide our own lstat/fstat functions, since the provided - * lstat/fstat functions are so slow. These stat functions are - * tailored for Git's usage (read: fast), and are not meant to be - * complete. Note that Git stat()s are redirected to mingw_lstat() - * too, since Windows doesn't really handle symlinks that well. - */ -static int do_stat_internal(int follow, const char *file_name, struct mingw_stat *buf) -{ - int namelen; - char alt_name[PATH_MAX]; - - if (!do_lstat(follow, file_name, buf)) - return 0; - - /* if file_name ended in a '/', Windows returned ENOENT; - * try again without trailing slashes - */ - if (errno != ENOENT) - return -1; - - namelen = strlen(file_name); - if (namelen && file_name[namelen-1] != '/') - return -1; - while (namelen && file_name[namelen-1] == '/') - --namelen; - if (!namelen || namelen >= PATH_MAX) - return -1; - - memcpy(alt_name, file_name, namelen); - alt_name[namelen] = 0; - return do_lstat(follow, alt_name, buf); -} - int mingw_lstat(const char *file_name, struct mingw_stat *buf) { - return do_stat_internal(0, file_name, buf); + return do_lstat(0, file_name, buf); } + int mingw_stat(const char *file_name, struct mingw_stat *buf) { - return do_stat_internal(1, file_name, buf); + return do_lstat(1, file_name, buf); } int mingw_fstat(int fd, struct mingw_stat *buf) -- cgit v1.2.3-55-g6feb