crt: Fix fstat() to signal overflow and return correct type for directories msvcrt _fstat function is broken and for directory fd it returns S_ISREG type. 32-bit pre-msvcr110 _fstat does not properly signal size overflow. UCRT seems to work correctly. Add mingw-w64 fstat wrappers around msvcrt _fstat functions which change S_IFMT to S_IFDIR if winapi filehandle has FILE_ATTRIBUTE_DIRECTORY attribute set. Provide wrapper for all 4 fstat size_t/time_t variants. For 32-bit pre-msvcr110 builds, adds similar workaround like for existing mingw-w64 stat functions. Currently our mingw-w64 header files defines non-underscore fstat and fstat64 functions as __MINGW_ASM_CALL redirects to underscore _fstat32, _fstat32i64, _fstat64i32, _fstat64 functions based on _FILE_OFFSET_BITS and _TIME_BITS macros. So every one of these 4 functions needs its own fixup wrapper. This change introduce 4 new non-underscore symbols fstat32, fstat32i64, fstat64i32, fstat64 which provides necessary fixup and to which mingw-w64 sys/stat.h header file redirects existing fstat and fstat64 functions. UCRT does not need any fixup, so new symbols are added as aliases in def files. Co-authored-by: LIU Hao <lh_mouse@126.com> Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index e10cfe1..c266b33 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am
@@ -190,6 +190,8 @@ stdio/_strtof_l.c \ stdio/_wcstof_l.c \ stdio/acrt_iob_func.c \ + stdio/fstat32i64.c \ + stdio/fstat64.c \ stdio/strtof.c \ stdio/snprintf_alias.c \ stdio/snwprintf_alias.c \ @@ -374,6 +376,8 @@ stdio/_getc_nolock.c \ stdio/mingw_lock.c \ stdio/msvcrtos_ftruncate64.c \ + stdio/msvcr110pre_fstat32.c \ + stdio/msvcr110pre_fstat64i32.c \ stdio/msvcr110pre_stat32.c \ stdio/msvcr110pre_stat64i32.c \ stdio/msvcr110pre_wstat32.c \ @@ -1028,6 +1032,8 @@ misc/imaxdiv.c src_pre_msvcr110=\ + stdio/msvcr110pre_fstat32.c \ + stdio/msvcr110pre_fstat64i32.c \ stdio/msvcr110pre_stat32.c \ stdio/msvcr110pre_stat64i32.c \ stdio/msvcr110pre_wstat32.c \ @@ -1060,6 +1066,8 @@ misc/__p__osver_emul.c src_post_msvcr100=\ + stdio/msvcr110plus_fstat32.c \ + stdio/msvcr110plus_fstat64i32.c \ stdio/msvcr110plus_stat32.c \ stdio/msvcr110plus_stat64i32.c \ stdio/msvcr110plus_wstat32.c \ @@ -1294,7 +1302,7 @@ stdio/_Exit.c \ stdio/asprintf.c \ stdio/mingw_ftruncate64.c stdio/lltoa.c stdio/lltow.c \ - stdio/__mingw_fix_stat.h stdio/__mingw_fix_stat_finish.c \ + stdio/__mingw_fix_stat.h stdio/__mingw_fix_stat_finish.c stdio/__mingw_fix_fstat_finish.c \ stdio/__mingw_fix_stat_path.c stdio/__mingw_fix_wstat_path.c \ \ stdio/mingw_pformat.h stdio/mingw_sformat.h stdio/mingw_swformat.h \
diff --git a/mingw-w64-crt/def-include/crt-aliases.def.in b/mingw-w64-crt/def-include/crt-aliases.def.in index 8f9ee2e..2b88b69 100644 --- a/mingw-w64-crt/def-include/crt-aliases.def.in +++ b/mingw-w64-crt/def-include/crt-aliases.def.in
@@ -64,13 +64,11 @@ ADD_UNDERSCORE(fileno) ; ADD_UNDERSCORE(flushall) ADD_UNDERSCORE(fputchar) -#ifdef FIXED_SIZE_SYMBOLS -#ifndef CRTDLL -ADD_UNDERSCORE(fstat) -#endif -#else +#if defined(UCRTBASE) F32(fstat == _fstat32) F64(fstat == _fstat64i32) +#else +; fstat for non-UCRT is provided by mingw to workaround S_IFDIR issue in _fstat #endif ; ftime is provided in misc/ftime32.c or misc/ftime64.c as MS _ftime is not ABI compatible with POSIX ftime #if defined(UCRTBASE) @@ -305,23 +303,23 @@ lseek64 == _lseeki64 #endif #ifdef UCRTBASE +fstat32 == _fstat32 +fstat32i64 == _fstat32i64 +fstat64 == _fstat64 +fstat64i32 == _fstat64i32 stat32 == _stat32 stat32i64 == _stat32i64 stat64 == _stat64 stat64i32 == _stat64i32 #else +; fstat for non-UCRT is provided by mingw to workaround S_IFDIR issue in _fstat ; stat for non-UCRT is provided by mingw to workaround trailing slash issue in _stat #endif #ifdef FIXED_SIZE_SYMBOLS -// NO_FIXED_SIZE_64_ALIAS means that DLL provides the native _fstat64 symbol -#if defined(NO_FIXED_SIZE_64_ALIAS) && !defined(NO_FSTAT64_ALIAS) -fstat64 == _fstat64 -#endif #ifdef WITH_FSEEKO64_ALIAS fseeko64 == _fseeki64 #endif #else -fstat64 == _fstat64 fseeko64 == _fseeki64 ftello64 == _ftelli64 #endif
diff --git a/mingw-w64-crt/lib-common/api-ms-win-crt-filesystem-l1-1-0.def.in b/mingw-w64-crt/lib-common/api-ms-win-crt-filesystem-l1-1-0.def.in index a0665a3..bdaa9bc 100644 --- a/mingw-w64-crt/lib-common/api-ms-win-crt-filesystem-l1-1-0.def.in +++ b/mingw-w64-crt/lib-common/api-ms-win-crt-filesystem-l1-1-0.def.in
@@ -37,10 +37,13 @@ F32(_fstati64 == _fstat32i64) F64(_fstati64 == _fstat64) _fstat32 +fstat32 == _fstat32 _fstat32i64 +fstat32i64 == _fstat32i64 _fstat64 fstat64 == _fstat64 _fstat64i32 +fstat64i32 == _fstat64i32 _fullpath _getdiskfree _getdrive
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index 500d076..0a76606 100644 --- a/mingw-w64-crt/lib-common/msvcrt.def.in +++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -1907,10 +1907,6 @@ ; This includes list of some symbol alises for compatibility with C99 and POSIX functions and symbols from other msvcr* libraries #define FIXED_SIZE_SYMBOLS #define NO_FIXED_SIZE_64_ALIAS -#ifdef __i386__ -; i386 fstat64 alias provided by emu -#define NO_FSTAT64_ALIAS -#endif #define NO_TIME_ALIAS #define NO_TMPFILE_ALIAS #define NO_STRCMPI_ALIAS
diff --git a/mingw-w64-crt/misc/crtdll_fstat.c b/mingw-w64-crt/misc/crtdll_fstat.c index 2fe5b1e..5441e32 100644 --- a/mingw-w64-crt/misc/crtdll_fstat.c +++ b/mingw-w64-crt/misc/crtdll_fstat.c
@@ -22,8 +22,3 @@ #undef _fstat int __attribute__ ((alias ("_fstat32"))) __cdecl _fstat(int fd, struct _stat32 *stat); extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_fstat32))))) (__cdecl *__MINGW_IMP_SYMBOL(_fstat))(int fd, struct _stat32 *stat); - -#undef fstat -struct stat; -int __attribute__ ((alias ("_fstat32"))) __cdecl fstat(int fd, struct stat *stat); -extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_fstat32))))) (__cdecl *__MINGW_IMP_SYMBOL(fstat))(int fd, struct stat *stat);
diff --git a/mingw-w64-crt/stdio/__mingw_fix_fstat_finish.c b/mingw-w64-crt/stdio/__mingw_fix_fstat_finish.c new file mode 100644 index 0000000..724b960 --- /dev/null +++ b/mingw-w64-crt/stdio/__mingw_fix_fstat_finish.c
@@ -0,0 +1,18 @@ +/** + * 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 <windows.h> +#include "__mingw_fix_stat.h" + +int __mingw_fix_fstat_finish(int ret, int fd, unsigned short *mode) +{ + /* msvcrt's _fstat fills S_IFREG for directories. Fix it to S_IFDIR. */ + BY_HANDLE_FILE_INFORMATION fi; + if (ret == 0 && S_ISREG(*mode) && GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &fi) && (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + *mode = (*mode & ~S_IFMT) | S_IFDIR; + return ret; +}
diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat.h b/mingw-w64-crt/stdio/__mingw_fix_stat.h index 9096062..1317dbf 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_stat.h +++ b/mingw-w64-crt/stdio/__mingw_fix_stat.h
@@ -11,5 +11,12 @@ 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); +int __mingw_fix_fstat_finish(int ret, int fd, unsigned short *mode); + +#define __MINGW_FIXED_FSTAT(fstat_func, fd, obj) ({ \ + int _fstat_ret = fstat_func(fd, obj); \ + _fstat_ret = __mingw_fix_fstat_finish(_fstat_ret, fd, &(obj)->st_mode); \ + _fstat_ret; \ +}) #endif
diff --git a/mingw-w64-crt/stdio/_fstat64.c b/mingw-w64-crt/stdio/_fstat64.c index 28c5d73..9386dd9 100644 --- a/mingw-w64-crt/stdio/_fstat64.c +++ b/mingw-w64-crt/stdio/_fstat64.c
@@ -43,6 +43,3 @@ #define ARGS int fd, struct _stat64 *stat #define CALL fd, stat #include "msvcrt_or_emu_glue.h" - -int __attribute__ ((alias ("_fstat64"))) __cdecl fstat64(int, struct stat64 *); -extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_fstat64))))) (__cdecl *__MINGW_IMP_SYMBOL(fstat64))(int, struct stat64 *);
diff --git a/mingw-w64-crt/stdio/fstat32i64.c b/mingw-w64-crt/stdio/fstat32i64.c new file mode 100644 index 0000000..8ba257d --- /dev/null +++ b/mingw-w64-crt/stdio/fstat32i64.c
@@ -0,0 +1,16 @@ +/** + * 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 "__mingw_fix_stat.h" + +int __cdecl fstat32i64(int fd, struct _stat32i64 *stat); +int __cdecl fstat32i64(int fd, struct _stat32i64 *stat) +{ + return __MINGW_FIXED_FSTAT(_fstat32i64, fd, stat); +} +int (__cdecl *__MINGW_IMP_SYMBOL(fstat32i64))(int, struct _stat32i64 *) = fstat32i64;
diff --git a/mingw-w64-crt/stdio/fstat64.c b/mingw-w64-crt/stdio/fstat64.c new file mode 100644 index 0000000..442409c --- /dev/null +++ b/mingw-w64-crt/stdio/fstat64.c
@@ -0,0 +1,15 @@ +/** + * 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 "__mingw_fix_stat.h" + +int __cdecl fstat64(int fd, struct stat64 *stat) +{ + return __MINGW_FIXED_FSTAT(_fstat64, fd, (struct _stat64 *)stat); +} +int (__cdecl *__MINGW_IMP_SYMBOL(fstat64))(int, struct stat64 *) = fstat64;
diff --git a/mingw-w64-crt/stdio/msvcr110plus_fstat32.c b/mingw-w64-crt/stdio/msvcr110plus_fstat32.c new file mode 100644 index 0000000..dfc57b2 --- /dev/null +++ b/mingw-w64-crt/stdio/msvcr110plus_fstat32.c
@@ -0,0 +1,24 @@ +/** + * 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 "__mingw_fix_stat.h" + +int __cdecl fstat32(int fd, struct _stat32 *stat); +int __cdecl fstat32(int fd, struct _stat32 *stat) +{ + return __MINGW_FIXED_FSTAT(_fstat32, fd, stat); +} +int (__cdecl *__MINGW_IMP_SYMBOL(fstat32))(int, struct _stat32 *) = fstat32; + +/* On 32-bit systems fstat() is ABI-compatible with fstat32() */ +#ifndef _WIN64 +#undef stat +struct stat; +int __attribute__ ((alias ("fstat32"))) __cdecl fstat(int fd, struct stat *stat); +extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(fstat32))))) (__cdecl *__MINGW_IMP_SYMBOL(fstat))(int fd, struct stat *stat); +#endif
diff --git a/mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c b/mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c new file mode 100644 index 0000000..7b14828 --- /dev/null +++ b/mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c
@@ -0,0 +1,24 @@ +/** + * 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 "__mingw_fix_stat.h" + +int __cdecl fstat64i32(int fd, struct _stat64i32 *stat); +int __cdecl fstat64i32(int fd, struct _stat64i32 *stat) +{ + return __MINGW_FIXED_FSTAT(_fstat64i32, fd, stat); +} +int (__cdecl *__MINGW_IMP_SYMBOL(fstat64i32))(int fd, struct _stat64i32 *) = fstat64i32; + +/* On 64-bit systems fstat() is ABI-compatible with fstat64i32() */ +#ifdef _WIN64 +#undef stat +struct stat; +int __attribute__ ((alias ("fstat64i32"))) __cdecl fstat(int fd, struct stat *stat); +extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(fstat64i32))))) (__cdecl *__MINGW_IMP_SYMBOL(fstat))(int fd, struct stat *stat); +#endif
diff --git a/mingw-w64-crt/stdio/msvcr110plus_stat32.c b/mingw-w64-crt/stdio/msvcr110plus_stat32.c index c31527f..f936ef9 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_stat32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_stat32.c
@@ -19,7 +19,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(stat32))(const char *, struct _stat32 *) = stat32; -/* On 32-bit systems is stat() function ABI compatible with stat32() function */ +/* On 32-bit systems stat() is ABI-compatible with stat32() */ #ifndef _WIN64 #undef stat struct stat;
diff --git a/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c b/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c index 7df90a0..89c3e05 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_stat64i32.c
@@ -19,7 +19,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(stat64i32))(const char *, struct _stat64i32 *) = stat64i32; -/* On 64-bit systems is stat() function ABI compatible with stat64i32() function */ +/* On 64-bit systems stat() is ABI-compatible with stat64i32() */ #ifdef _WIN64 #undef stat struct stat;
diff --git a/mingw-w64-crt/stdio/msvcr110plus_wstat32.c b/mingw-w64-crt/stdio/msvcr110plus_wstat32.c index 15f55cd..50e183c 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_wstat32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_wstat32.c
@@ -19,7 +19,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(wstat32))(const wchar_t *, struct _stat32 *) = wstat32; -/* On 32-bit systems is wstat() function ABI compatible with wstat32() function */ +/* On 32-bit systems wstat() is ABI-compatible with wstat32() */ #ifndef _WIN64 #undef stat #undef wstat
diff --git a/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c b/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c index c2f1e32..caf5ca7 100644 --- a/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110plus_wstat64i32.c
@@ -19,7 +19,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(wstat64i32))(const wchar_t *, struct _stat64i32 *) = wstat64i32; -/* On 64-bit systems is wstat() function ABI compatible with wstat64i32() function */ +/* On 64-bit systems wstat() is ABI-compatible with wstat64i32() */ #ifdef _WIN64 #undef stat #undef wstat
diff --git a/mingw-w64-crt/stdio/msvcr110pre_fstat32.c b/mingw-w64-crt/stdio/msvcr110pre_fstat32.c new file mode 100644 index 0000000..cbc6dbb --- /dev/null +++ b/mingw-w64-crt/stdio/msvcr110pre_fstat32.c
@@ -0,0 +1,50 @@ +/** + * 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 <stdint.h> +#include <errno.h> +#include "__mingw_fix_stat.h" + +/* For pre-msvcr110 builds, we cannot use _fstat32() as it does + * not signal EOVERFLOW when file size does not fit into the st_size field, + * as it is required by POSIX fstat(). + * This file is used only for pre-msvcr110 builds. + */ +int __cdecl fstat32(int fd, struct _stat32 *stat); +int __cdecl fstat32(int fd, struct _stat32 *stat) +{ + struct _stat32i64 st; + int ret = __MINGW_FIXED_FSTAT(_fstat32i64, fd, &st); + if (ret != 0) + return ret; + if (st.st_size > INT32_MAX) { + errno = EOVERFLOW; + return -1; + } + stat->st_dev=st.st_dev; + stat->st_ino=st.st_ino; + stat->st_mode=st.st_mode; + stat->st_nlink=st.st_nlink; + stat->st_uid=st.st_uid; + stat->st_gid=st.st_gid; + stat->st_rdev=st.st_rdev; + stat->st_size=(_off_t) st.st_size; + stat->st_atime=st.st_atime; + stat->st_mtime=st.st_mtime; + stat->st_ctime=st.st_ctime; + return 0; +} +int (__cdecl *__MINGW_IMP_SYMBOL(fstat32))(int, struct _stat32 *) = fstat32; + +/* On 32-bit systems fstat() is ABI-compatible with fstat32() */ +#ifndef _WIN64 +#undef stat +struct stat; +int __attribute__ ((alias ("fstat32"))) __cdecl fstat(int fd, struct stat *stat); +extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(fstat32))))) (__cdecl *__MINGW_IMP_SYMBOL(fstat))(int fd, struct stat *stat); +#endif
diff --git a/mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c b/mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c new file mode 100644 index 0000000..6ca74be --- /dev/null +++ b/mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c
@@ -0,0 +1,50 @@ +/** + * 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 <stdint.h> +#include <errno.h> +#include "__mingw_fix_stat.h" + +/* For pre-msvcr110 builds, we cannot use _fstat64i32() as it does + * not signal EOVERFLOW when file size does not fit into the st_size field, + * as it is required by POSIX fstat(). + * This file is used only for pre-msvcr110 builds. + */ +int __cdecl fstat64i32(int fd, struct _stat64i32 *stat); +int __cdecl fstat64i32(int fd, struct _stat64i32 *stat) +{ + struct _stat64 st; + int ret = __MINGW_FIXED_FSTAT(_fstat64, fd, &st); + if (ret != 0) + return ret; + if (st.st_size > INT32_MAX) { + errno = EOVERFLOW; + return -1; + } + stat->st_dev=st.st_dev; + stat->st_ino=st.st_ino; + stat->st_mode=st.st_mode; + stat->st_nlink=st.st_nlink; + stat->st_uid=st.st_uid; + stat->st_gid=st.st_gid; + stat->st_rdev=st.st_rdev; + stat->st_size=(_off_t) st.st_size; + stat->st_atime=st.st_atime; + stat->st_mtime=st.st_mtime; + stat->st_ctime=st.st_ctime; + return 0; +} +int (__cdecl *__MINGW_IMP_SYMBOL(fstat64i32))(int, struct _stat64i32 *) = fstat64i32; + +/* On 64-bit systems stat() is ABI-compatible with stat64i32() */ +#ifdef _WIN64 +#undef stat +struct stat; +int __attribute__ ((alias ("fstat64i32"))) __cdecl fstat(int fd, struct stat *stat); +extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(fstat64i32))))) (__cdecl *__MINGW_IMP_SYMBOL(fstat))(int fd, struct stat *stat); +#endif
diff --git a/mingw-w64-crt/stdio/msvcr110pre_stat32.c b/mingw-w64-crt/stdio/msvcr110pre_stat32.c index 0d58f7b..196c2de 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_stat32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_stat32.c
@@ -10,9 +10,9 @@ #include <errno.h> #include "__mingw_fix_stat.h" -/* For pre-msvcr110 builds, we cannot use _stat32() function as it does +/* For pre-msvcr110 builds, we cannot use _stat32() as it does * not signal EOVERFLOW when file size does not fit into the st_size field, - * as it is required by POSIX stat() function. + * as it is required by POSIX stat(). * This file is used only for pre-msvcr110 builds. */ int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat); @@ -26,7 +26,7 @@ ret = __mingw_fix_stat_finish(ret, _Filename, _path, st.st_mode); if (ret != 0) return ret; - if (st.st_size > UINT32_MAX) { + if (st.st_size > INT32_MAX) { errno = EOVERFLOW; return -1; } @@ -45,7 +45,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(stat32))(const char *, struct _stat32 *) = stat32; -/* On 32-bit systems is stat() function ABI compatible with stat32() function */ +/* On 32-bit systems stat() is ABI-compatible with stat32() */ #ifndef _WIN64 #undef stat struct stat;
diff --git a/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c b/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c index b2b037a..2a6cc9a 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_stat64i32.c
@@ -10,9 +10,9 @@ #include <errno.h> #include "__mingw_fix_stat.h" -/* For pre-msvcr110 builds, we cannot use _stat64i32() function as it does +/* For pre-msvcr110 builds, we cannot use _stat64i32() as it does * not signal EOVERFLOW when file size does not fit into the st_size field, - * as it is required by POSIX stat() function. + * as it is required by POSIX stat(). * This file is used only for pre-msvcr110 builds. */ int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat); @@ -26,7 +26,7 @@ ret = __mingw_fix_stat_finish(ret, _Filename, _path, st.st_mode); if (ret != 0) return ret; - if (st.st_size > UINT32_MAX) { + if (st.st_size > INT32_MAX) { errno = EOVERFLOW; return -1; } @@ -45,7 +45,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(stat64i32))(const char *, struct _stat64i32 *) = stat64i32; -/* On 64-bit systems is stat() function ABI compatible with stat64i32() function */ +/* On 64-bit systems stat() is ABI-compatible with stat64i32() */ #ifdef _WIN64 #undef stat struct stat;
diff --git a/mingw-w64-crt/stdio/msvcr110pre_wstat32.c b/mingw-w64-crt/stdio/msvcr110pre_wstat32.c index b4af68e..b9848ff 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_wstat32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_wstat32.c
@@ -10,9 +10,9 @@ #include <errno.h> #include "__mingw_fix_stat.h" -/* For pre-msvcr110 builds, we cannot use _wstat32() function as it does +/* For pre-msvcr110 builds, we cannot use _wstat32() as it does * not signal EOVERFLOW when file size does not fit into the st_size field, - * as it is required by POSIX stat() function. + * as it is required by POSIX stat(). * This file is used only for pre-msvcr110 builds. */ int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat); @@ -26,7 +26,7 @@ ret = __mingw_fix_stat_finish(ret, _Filename, _path, st.st_mode); if (ret != 0) return ret; - if (st.st_size > UINT32_MAX) { + if (st.st_size > INT32_MAX) { errno = EOVERFLOW; return -1; } @@ -45,7 +45,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(wstat32))(const wchar_t *, struct _stat32 *) = wstat32; -/* On 32-bit systems is wstat() function ABI compatible with wstat32() function */ +/* On 32-bit systems wstat() is ABI-compatible with wstat32() */ #ifndef _WIN64 #undef stat #undef wstat
diff --git a/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c b/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c index 9a55612..a7611bf 100644 --- a/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c +++ b/mingw-w64-crt/stdio/msvcr110pre_wstat64i32.c
@@ -10,9 +10,9 @@ #include <errno.h> #include "__mingw_fix_stat.h" -/* For pre-msvcr110 builds, we cannot use _wstat64i32() function as it does +/* For pre-msvcr110 builds, we cannot use _wstat64i32() as it does * not signal EOVERFLOW when file size does not fit into the st_size field, - * as it is required by POSIX stat() function. + * as it is required by POSIX stat(). * This file is used only for pre-msvcr110 builds. */ int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat); @@ -26,7 +26,7 @@ ret = __mingw_fix_stat_finish(ret, _Filename, _path, st.st_mode); if (ret != 0) return ret; - if (st.st_size > UINT32_MAX) { + if (st.st_size > INT32_MAX) { errno = EOVERFLOW; return -1; } @@ -45,7 +45,7 @@ } int (__cdecl *__MINGW_IMP_SYMBOL(wstat64i32))(const wchar_t *, struct _stat64i32 *) = wstat64i32; -/* On 64-bit systems is wstat() function ABI compatible with wstat64i32() function */ +/* On 64-bit systems wstat() is ABI-compatible with wstat64i32() */ #ifdef _WIN64 #undef stat #undef wstat
diff --git a/mingw-w64-crt/testcases/t_fstat.c b/mingw-w64-crt/testcases/t_fstat.c index 0e85bd5..0622b9e 100644 --- a/mingw-w64-crt/testcases/t_fstat.c +++ b/mingw-w64-crt/testcases/t_fstat.c
@@ -1,15 +1,53 @@ #include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <windows.h> -int main(int argc, char *argv[]) +#define TMPTMPL "mingw-w64-fstat-XXXXXX" +static char dirpath[MAX_PATH + sizeof(TMPTMPL)]; + +static void remove_dirpath(void) { rmdir(dirpath); } + +int main() { struct stat st; struct stat64 st64; - if (0 == fstat(0, &st)) - printf("mode = %x\n", st.st_mode); - if (0 == fstat64(0, &st64)) - printf("mode = %x\n", st64.st_mode); + HANDLE handle; + int dirfd; + + assert(fstat(0, &st) == 0); + printf("fstat(0): mode = %08o\n", st.st_mode); + assert(!S_ISDIR(st.st_mode)); + + assert(fstat64(0, &st64) == 0); + printf("fstat64(0): mode = %08o\n", st64.st_mode); + assert(!S_ISDIR(st64.st_mode)); + + assert(GetTempPathA(MAX_PATH, dirpath)); + printf("GetTempPathA(): path=%s\n", dirpath); + + strcat(dirpath, TMPTMPL); + assert(mkdtemp(dirpath)); + atexit(remove_dirpath); + printf("mkdtemp(): path=%s\n", dirpath); + + handle = CreateFileA(dirpath, FILE_READ_ATTRIBUTES | DELETE, FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_DELETE_ON_CLOSE, NULL); + assert(handle != INVALID_HANDLE_VALUE); + + dirfd = _open_osfhandle((intptr_t)handle, O_RDONLY); + assert(dirfd >= 0); + + assert(fstat(dirfd, &st) == 0); + printf("fstat(dirfd): mode = %08o\n", st.st_mode); + assert(S_ISDIR(st.st_mode)); + + assert(fstat64(dirfd, &st64) == 0); + printf("fstat64(dirfd): mode = %08o\n", st64.st_mode); + assert(S_ISDIR(st64.st_mode)); + return 0; }
diff --git a/mingw-w64-headers/crt/sys/stat.h b/mingw-w64-headers/crt/sys/stat.h index 5d2e6df..347f66e 100644 --- a/mingw-w64-headers/crt/sys/stat.h +++ b/mingw-w64-headers/crt/sys/stat.h
@@ -149,21 +149,21 @@ }; #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) #ifdef _USE_32BIT_TIME_T -int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(_fstat32i64); +int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(fstat32i64); int __cdecl stat(const char *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(stat32i64); int __cdecl wstat(const wchar_t *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(wstat32i64); #else -int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(_fstat64); +int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(fstat64); int __cdecl stat(const char *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(stat64); int __cdecl wstat(const wchar_t *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(wstat64); #endif #else #ifdef _USE_32BIT_TIME_T -int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(_fstat32); +int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(fstat32); int __cdecl stat(const char *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(stat32); int __cdecl wstat(const wchar_t *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(wstat32); #else -int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(_fstat64i32); +int __cdecl fstat(int _Desc, struct stat *_Stat) __MINGW_ASM_CALL(fstat64i32); int __cdecl stat(const char *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(stat64i32); int __cdecl wstat(const wchar_t *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(wstat64i32); #endif