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.
---
This change depends on "crt: Implement POSIX mkdtemp() function".
---
 mingw-w64-crt/Makefile.am                     | 10 +++-
 mingw-w64-crt/def-include/crt-aliases.def.in  | 18 +++----
 .../api-ms-win-crt-filesystem-l1-1-0.def.in   |  3 ++
 mingw-w64-crt/lib-common/msvcrt.def.in        |  4 --
 mingw-w64-crt/misc/crtdll_fstat.c             |  5 --
 .../stdio/__mingw_fix_fstat_finish.c          | 18 +++++++
 mingw-w64-crt/stdio/__mingw_fix_stat.h        |  7 +++
 mingw-w64-crt/stdio/_fstat64.c                |  3 --
 mingw-w64-crt/stdio/fstat32i64.c              | 16 ++++++
 mingw-w64-crt/stdio/fstat64.c                 | 15 ++++++
 mingw-w64-crt/stdio/msvcr110plus_fstat32.c    | 24 +++++++++
 mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c | 24 +++++++++
 mingw-w64-crt/stdio/msvcr110pre_fstat32.c     | 50 +++++++++++++++++++
 mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c  | 50 +++++++++++++++++++
 mingw-w64-crt/testcases/t_fstat.c             | 48 ++++++++++++++++--
 mingw-w64-headers/crt/sys/stat.h              |  8 +--
 16 files changed, 271 insertions(+), 32 deletions(-)
 create mode 100644 mingw-w64-crt/stdio/__mingw_fix_fstat_finish.c
 create mode 100644 mingw-w64-crt/stdio/fstat32i64.c
 create mode 100644 mingw-w64-crt/stdio/fstat64.c
 create mode 100644 mingw-w64-crt/stdio/msvcr110plus_fstat32.c
 create mode 100644 mingw-w64-crt/stdio/msvcr110plus_fstat64i32.c
 create mode 100644 mingw-w64-crt/stdio/msvcr110pre_fstat32.c
 create mode 100644 mingw-w64-crt/stdio/msvcr110pre_fstat64i32.c

diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 7b025d213242..d6e049baaeed 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -190,6 +190,8 @@ src_msvcrt_common=\
   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 \
@@ -372,6 +374,8 @@ src_msvcrt=\
   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 \
@@ -1022,6 +1026,8 @@ src_pre_msvcr100=\
   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 \
@@ -1050,6 +1056,8 @@ src_post_msvcr80=\
   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 \
@@ -1268,7 +1276,7 @@ src_libmingwex=\
   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 8f9ee2e09c46..2b88b699c0fc 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(filelength)
 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 @@ fsetpos64 == fsetpos
 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 a0665a3a3d31..bdaa9bcd8dc5 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 @@ F64(_fstat == _fstat64i32)
 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 a4343bb765e0..979157d4e8bf 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -1907,10 +1907,6 @@ F_I386(_libm_sse2_tan_precise)
 ; 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 2fe5b1e9c342..5441e322f38c 100644
--- a/mingw-w64-crt/misc/crtdll_fstat.c
+++ b/mingw-w64-crt/misc/crtdll_fstat.c
@@ -22,8 +22,3 @@ int (__cdecl *__MINGW_IMP_SYMBOL(_fstat32))(int fd, struct 
_stat32 *stat) = _fst
 #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 000000000000..724b9607657d
--- /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 909606204b4d..1317dbffe2e8 100644
--- a/mingw-w64-crt/stdio/__mingw_fix_stat.h
+++ b/mingw-w64-crt/stdio/__mingw_fix_stat.h
@@ -11,5 +11,12 @@ 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);
+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 28c5d73c1f55..9386dd909c71 100644
--- a/mingw-w64-crt/stdio/_fstat64.c
+++ b/mingw-w64-crt/stdio/_fstat64.c
@@ -43,6 +43,3 @@ static int __cdecl emu__fstat64(int fd, struct _stat64 *stat)
 #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 000000000000..8ba257de481a
--- /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 000000000000..442409c34dd6
--- /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 000000000000..e33d0d5e302f
--- /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 is fstat() function ABI compatible with fstat32() 
function */
+#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 000000000000..971c3c820ed9
--- /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 is fstat() function ABI compatible with fstat64i32() 
function */
+#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_fstat32.c 
b/mingw-w64-crt/stdio/msvcr110pre_fstat32.c
new file mode 100644
index 000000000000..8fc841fa86d1
--- /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() function as it does
+ * not signal EOVERFLOW when file size does not fit into the st_size field,
+ * as it is required by POSIX fstat() function.
+ * 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 > UINT32_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 is fstat() function ABI compatible with fstat32() 
function */
+#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 000000000000..8068cf4746e7
--- /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() function as it does
+ * not signal EOVERFLOW when file size does not fit into the st_size field,
+ * as it is required by POSIX fstat() function.
+ * 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 > UINT32_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 is stat() function ABI compatible with stat64i32() 
function */
+#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/testcases/t_fstat.c 
b/mingw-w64-crt/testcases/t_fstat.c
index 0e85bd57d39f..0622b9e4ad5c 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 5d2e6dfaf031..347f66eef77b 100644
--- a/mingw-w64-headers/crt/sys/stat.h
+++ b/mingw-w64-headers/crt/sys/stat.h
@@ -149,21 +149,21 @@ struct stat {
 };
 #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
-- 
2.20.1



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to