POSIX requires stat("foo/", &st) to fail if "foo" isn't a directory or
a symbolic link to a directory. See ENOTDIR in [1].The statXX functions, that are used with MSVCRT, already have code to remove a trailing slash. Extend it to reject non-directories with ENOTDIR if a trailing slash was removed. These functions aren't used with UCRT because UCRT handles trailing slashes better than MSVCRT. One minor issue with UCRT is that "foo/" results in ENOENT instead of ENOTDIR. This commit doesn't fix it. Preserve errno when calling free(). [1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstatat.html --- mingw-w64-crt/Makefile.am | 2 +- mingw-w64-crt/stdio/__mingw_fix_stat.h | 2 ++ mingw-w64-crt/stdio/__mingw_fix_stat_finish.c | 36 +++++++++++++++++++ mingw-w64-crt/stdio/msvcr110plus_stat32.c | 4 +-- mingw-w64-crt/stdio/msvcr110plus_stat64i32.c | 4 +-- mingw-w64-crt/stdio/msvcr110plus_wstat32.c | 4 +-- mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c | 4 +-- mingw-w64-crt/stdio/msvcr110pre_stat32.c | 3 +- mingw-w64-crt/stdio/msvcr110pre_stat64i32.c | 3 +- mingw-w64-crt/stdio/msvcr110pre_wstat32.c | 3 +- mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c | 3 +- mingw-w64-crt/stdio/stat32i64.c | 4 +-- mingw-w64-crt/stdio/stat64.c | 4 +-- mingw-w64-crt/stdio/wstat32i64.c | 4 +-- mingw-w64-crt/stdio/wstat64.c | 4 +-- 15 files changed, 51 insertions(+), 33 deletions(-) create mode 100644 mingw-w64-crt/stdio/__mingw_fix_stat_finish.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index c8812f2d5..4adfbff3f 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -1103,7 +1103,7 @@ src_libmingwex=\ stdio/asprintf.c \ stdio/fopen64.c stdio/fseeko32.c stdio/fseeko64.c stdio/ftello.c \ stdio/ftello64.c stdio/ftruncate64.c stdio/lltoa.c stdio/lltow.c stdio/lseek64.c \ - stdio/__mingw_fix_stat.h \ + stdio/__mingw_fix_stat.h stdio/__mingw_fix_stat_finish.c \ stdio/__mingw_fix_stat_path.c stdio/__mingw_fix_wstat_path.c \ \ stdio/mingw_pformat.h mingw_sformat.h mingw_swformat.h \ diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat.h b/mingw-w64-crt/stdio/__mingw_fix_stat.h index 5aad9efb6..909606204 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_stat.h +++ b/mingw-w64-crt/stdio/__mingw_fix_stat.h @@ -9,5 +9,7 @@ char* __mingw_fix_stat_path (const char* _path); wchar_t* __mingw_fix_wstat_path (const wchar_t* _path); +int __mingw_fix_stat_finish(int ret, const void *orig_path, void *used_path, + unsigned short mode); #endif diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat_finish.c b/mingw-w64-crt/stdio/__mingw_fix_stat_finish.c new file mode 100644 index 000000000..8b7a128c2 --- /dev/null +++ b/mingw-w64-crt/stdio/__mingw_fix_stat_finish.c @@ -0,0 +1,36 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include <sys/stat.h> +#include <stdlib.h> +#include <errno.h> +#include "__mingw_fix_stat.h" + +int __mingw_fix_stat_finish(int ret, const void *orig_path, void *used_path, + unsigned short mode) +{ + /* + * If the original pathname and used pathname differ, it means that + * __mingw_fix_stat_path or __mingw_fix_wstat_path had to allocate + * a temporary buffer and remove a trailing directory separator. + * In this case the temporary allocation has to be freed, and the + * stat function succeeds only if the pathname was a directory. + */ + if (orig_path != used_path) { + /* Save errno because we call free. */ + int saved_errno = errno; + free(used_path); + + if (ret == 0 && !S_ISDIR(mode)) { + ret = -1; + saved_errno = ENOTDIR; + } + + errno = saved_errno; + } + + return ret; +} diff --git a/mingw-w64-crt/stdio/msvcr110plus_stat32.c b/mingw-w64-crt/stdio/msvcr110plus_stat32.c index f4cb9567a..c31527fb1 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_stat32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_stat32.c @@ -15,9 +15,7 @@ int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _stat32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat32))(const char *, struct _stat32 *) = stat32; diff --git a/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c b/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c index 7ccd23b34..7df90a001 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c @@ -15,9 +15,7 @@ int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _stat64i32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat64i32))(const char *, struct _stat64i32 *) = stat64i32; diff --git a/mingw-w64-crt/stdio/msvcr110plus_wstat32.c b/mingw-w64-crt/stdio/msvcr110plus_wstat32.c index 3c6576ae0..15f55cd8b 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_wstat32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_wstat32.c @@ -15,9 +15,7 @@ int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _wstat32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat32))(const wchar_t *, struct _stat32 *) = wstat32; diff --git a/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c b/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c index 7fc681b2a..c2f1e32cf 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c @@ -15,9 +15,7 @@ int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _wstat64i32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat64i32))(const wchar_t *, struct _stat64i32 *) = wstat64i32; diff --git a/mingw-w64-crt/stdio/msvcr110pre_stat32.c b/mingw-w64-crt/stdio/msvcr110pre_stat32.c index fe3cb20d6..63d753e61 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_stat32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_stat32.c @@ -23,8 +23,7 @@ int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _stat32i64(_path, &st); - if (_path != _Filename) - free(_path); + ret = __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); if (ret != 0) return ret; if (st.st_size > UINT32_MAX) { diff --git a/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c b/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c index d87a14f54..6741c9b65 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c @@ -23,8 +23,7 @@ int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _stat64(_path, &st); - if (_path != _Filename) - free(_path); + ret = __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); if (ret != 0) return ret; if (st.st_size > UINT32_MAX) { diff --git a/mingw-w64-crt/stdio/msvcr110pre_wstat32.c b/mingw-w64-crt/stdio/msvcr110pre_wstat32.c index 4fc02ee0f..4e6c92299 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_wstat32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_wstat32.c @@ -23,8 +23,7 @@ int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _wstat32i64(_path, &st); - if (_path != _Filename) - free(_path); + ret = __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); if (ret != 0) return ret; if (st.st_size > UINT32_MAX) { diff --git a/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c b/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c index 21c10b58b..a94703ea0 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c @@ -23,8 +23,7 @@ int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _wstat64(_path, &st); - if (_path != _Filename) - free(_path); + ret = __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); if (ret != 0) return ret; if (st.st_size > UINT32_MAX) { diff --git a/mingw-w64-crt/stdio/stat32i64.c b/mingw-w64-crt/stdio/stat32i64.c index b8d154605..0b0c5cde9 100644 --- a/mingw-w64-crt/stdio/stat32i64.c +++ b/mingw-w64-crt/stdio/stat32i64.c @@ -15,8 +15,6 @@ int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _stat32i64(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat32i64))(const char *, struct _stat32i64 *) = stat32i64; diff --git a/mingw-w64-crt/stdio/stat64.c b/mingw-w64-crt/stdio/stat64.c index 687135f3e..b1f5b4309 100644 --- a/mingw-w64-crt/stdio/stat64.c +++ b/mingw-w64-crt/stdio/stat64.c @@ -14,8 +14,6 @@ int __cdecl stat64(const char *_Filename, struct stat64 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _stat64(_path, (struct _stat64 *)_Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat64))(const char *, struct stat64 *) = stat64; diff --git a/mingw-w64-crt/stdio/wstat32i64.c b/mingw-w64-crt/stdio/wstat32i64.c index 2dc34b8f9..98dcaf11f 100644 --- a/mingw-w64-crt/stdio/wstat32i64.c +++ b/mingw-w64-crt/stdio/wstat32i64.c @@ -15,8 +15,6 @@ int __cdecl wstat32i64(const wchar_t *_Filename, struct _stat32i64 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _wstat32i64(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat32i64))(const wchar_t *, struct _stat32i64 *) = wstat32i64; diff --git a/mingw-w64-crt/stdio/wstat64.c b/mingw-w64-crt/stdio/wstat64.c index 8cc58521a..76d547435 100644 --- a/mingw-w64-crt/stdio/wstat64.c +++ b/mingw-w64-crt/stdio/wstat64.c @@ -14,8 +14,6 @@ int __cdecl wstat64(const wchar_t *_Filename, struct stat64 *_Stat) if (_path == NULL && _Filename != NULL) return -1; int ret = _wstat64(_path, (struct _stat64 *)_Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_finish(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat64))(const wchar_t *, struct stat64 *) = wstat64; -- 2.49.0 _______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
