aboutsummaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2019-03-04 09:59:27 +0000
committerRon Yorston <rmy@pobox.com>2019-03-04 10:18:07 +0000
commit325fee1f922150460547d1317b3abd443a657385 (patch)
tree59bc016c110036b5d3dfe49a767af9eb7e1c2672 /win32
parent7c9be982c7758c477cd2735ed3784f3eee67a78e (diff)
downloadbusybox-w32-325fee1f922150460547d1317b3abd443a657385.tar.gz
busybox-w32-325fee1f922150460547d1317b3abd443a657385.tar.bz2
busybox-w32-325fee1f922150460547d1317b3abd443a657385.zip
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.
Diffstat (limited to 'win32')
-rw-r--r--win32/mingw.c51
1 files changed, 11 insertions, 40 deletions
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)
287 287
288static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) 288static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
289{ 289{
290 size_t len;
291
290 if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata)) 292 if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
291 return 0; 293 return 0;
292 294
@@ -316,6 +318,11 @@ static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fd
316 return ENAMETOOLONG; 318 return ENAMETOOLONG;
317 case ERROR_NOT_ENOUGH_MEMORY: 319 case ERROR_NOT_ENOUGH_MEMORY:
318 return ENOMEM; 320 return ENOMEM;
321 case ERROR_INVALID_NAME:
322 len = strlen(fname);
323 if (len > 1 && (fname[len-1] == '/' || fname[len-1] == '\\'))
324 return ENOTDIR;
325 return EINVAL;
319 default: 326 default:
320 return ENOENT; 327 return ENOENT;
321 } 328 }
@@ -473,11 +480,7 @@ static uid_t file_owner(HANDLE fh)
473} 480}
474#endif 481#endif
475 482
476/* We keep the do_lstat code in a separate function to avoid recursion. 483/* If follow is true then act like stat() and report on the link
477 * When a path ends with a slash, the stat will fail with ENOENT. In
478 * this case, we strip the trailing slashes and stat again.
479 *
480 * If follow is true then act like stat() and report on the link
481 * target. Otherwise report on the link itself. 484 * target. Otherwise report on the link itself.
482 */ 485 */
483static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) 486static 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)
564 return -1; 567 return -1;
565} 568}
566 569
567/* We provide our own lstat/fstat functions, since the provided
568 * lstat/fstat functions are so slow. These stat functions are
569 * tailored for Git's usage (read: fast), and are not meant to be
570 * complete. Note that Git stat()s are redirected to mingw_lstat()
571 * too, since Windows doesn't really handle symlinks that well.
572 */
573static int do_stat_internal(int follow, const char *file_name, struct mingw_stat *buf)
574{
575 int namelen;
576 char alt_name[PATH_MAX];
577
578 if (!do_lstat(follow, file_name, buf))
579 return 0;
580
581 /* if file_name ended in a '/', Windows returned ENOENT;
582 * try again without trailing slashes
583 */
584 if (errno != ENOENT)
585 return -1;
586
587 namelen = strlen(file_name);
588 if (namelen && file_name[namelen-1] != '/')
589 return -1;
590 while (namelen && file_name[namelen-1] == '/')
591 --namelen;
592 if (!namelen || namelen >= PATH_MAX)
593 return -1;
594
595 memcpy(alt_name, file_name, namelen);
596 alt_name[namelen] = 0;
597 return do_lstat(follow, alt_name, buf);
598}
599
600int mingw_lstat(const char *file_name, struct mingw_stat *buf) 570int mingw_lstat(const char *file_name, struct mingw_stat *buf)
601{ 571{
602 return do_stat_internal(0, file_name, buf); 572 return do_lstat(0, file_name, buf);
603} 573}
574
604int mingw_stat(const char *file_name, struct mingw_stat *buf) 575int mingw_stat(const char *file_name, struct mingw_stat *buf)
605{ 576{
606 return do_stat_internal(1, file_name, buf); 577 return do_lstat(1, file_name, buf);
607} 578}
608 579
609int mingw_fstat(int fd, struct mingw_stat *buf) 580int mingw_fstat(int fd, struct mingw_stat *buf)