diff options
author | Ron Yorston <rmy@pobox.com> | 2019-03-04 09:59:27 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-03-04 10:18:07 +0000 |
commit | 325fee1f922150460547d1317b3abd443a657385 (patch) | |
tree | 59bc016c110036b5d3dfe49a767af9eb7e1c2672 /win32 | |
parent | 7c9be982c7758c477cd2735ed3784f3eee67a78e (diff) | |
download | busybox-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.c | 51 |
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 | ||
288 | static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata) | 288 | static 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 | */ |
483 | static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf) | 486 | 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) | |||
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 | */ | ||
573 | static 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 | |||
600 | int mingw_lstat(const char *file_name, struct mingw_stat *buf) | 570 | int 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 | |||
604 | int mingw_stat(const char *file_name, struct mingw_stat *buf) | 575 | int 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 | ||
609 | int mingw_fstat(int fd, struct mingw_stat *buf) | 580 | int mingw_fstat(int fd, struct mingw_stat *buf) |