crt: Provide emulation of _fstat32i64, _stat32i64 and _wstat32i64 functions

Functions _fstat32i64 (alias of _fstati64), _stat32i64 (alias of _stati64)
and _wstat32i64 (alias of _wstati64) are available since msvcrt40.dll.
These functions returns 64-bit st_size and 32-bit file timestamps.

For pre-msvcrt40 CRT import libraries provides mingw-w64 emulation of those
functions via the _fstat64, _stat64 and _stat64 functions, which returns
both st_size and file timestamps in 64-bit precision.

When timestamp does not fit into the 32-bit field then sets field to invalid
value -1. This is behavior of msvcrt functions with 32-bit time_t fields.

Note that _fstat64, _stat64 and _stat64 functions are available in all CRT
import libraries, in pre-msvcr70 CRT import libraries they are emulated.

Signed-off-by: Martin Storsjö <martin@martin.st>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 02a857d..8a41cbb 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -799,6 +799,9 @@
   misc/_dstbias.c \
   misc/dummy__setusermatherr.c \
   stdio/_filelengthi64.c \
+  stdio/_fstat32i64.c \
+  stdio/_stat32i64.c \
+  stdio/_wstat32i64.c \
   stdio/fgetpos.c \
   stdio/fsetpos.c
 
diff --git a/mingw-w64-crt/stdio/_fstat32i64.c b/mingw-w64-crt/stdio/_fstat32i64.c
new file mode 100644
index 0000000..1bd63cd
--- /dev/null
+++ b/mingw-w64-crt/stdio/_fstat32i64.c
@@ -0,0 +1,42 @@
+/**
+ * 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 <stdint.h>
+
+/* When the file time does not fit into the st_Xtime field:
+ *           crtdll-msvcr71   msvcr80+
+ * st_Xtime       -1             -1
+ * errno       no change       EINVAL
+ * returns         0              0
+ *
+ * This file is used only for pre-msvcrt40 builds,
+ * So use the pre-msvcrt40 behavior - fills -1 without errno change.
+ */
+int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat)
+{
+  struct _stat64 st;
+  int ret=_fstat64(_FileDes,&st);
+  if (ret != 0)
+    return ret;
+  _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=st.st_size;
+  _Stat->st_atime=((st.st_atime > INT32_MAX) ? -1 : st.st_atime);
+  _Stat->st_mtime=((st.st_mtime > INT32_MAX) ? -1 : st.st_mtime);
+  _Stat->st_ctime=((st.st_ctime > INT32_MAX) ? -1 : st.st_ctime);
+  return 0;
+}
+int (__cdecl *__MINGW_IMP_SYMBOL(_fstat32i64))(int, struct _stat32i64 *) = _fstat32i64;
+
+#undef _fstati64
+int __attribute__ ((alias ("_fstat32i64"))) __cdecl _fstati64(int, struct _stat32i64 *);
+extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_fstat32i64))))) (__cdecl *__MINGW_IMP_SYMBOL(_fstati64))(int, struct _stat32i64 *);
diff --git a/mingw-w64-crt/stdio/_stat32i64.c b/mingw-w64-crt/stdio/_stat32i64.c
new file mode 100644
index 0000000..641f2f5
--- /dev/null
+++ b/mingw-w64-crt/stdio/_stat32i64.c
@@ -0,0 +1,42 @@
+/**
+ * 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 <stdint.h>
+
+/* When the file time does not fit into the st_Xtime field:
+ *           crtdll-msvcr71   msvcr80+
+ * st_Xtime       -1             -1
+ * errno       no change       EINVAL
+ * returns         0              0
+ *
+ * This file is used only for pre-msvcrt40 builds,
+ * So use the pre-msvcrt40 behavior - fills -1 without errno change.
+ */
+int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat)
+{
+  struct _stat64 st;
+  int ret=_stat64(_Name,&st);
+  if (ret != 0)
+    return ret;
+  _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=st.st_size;
+  _Stat->st_atime=((st.st_atime > INT32_MAX) ? -1 : st.st_atime);
+  _Stat->st_mtime=((st.st_mtime > INT32_MAX) ? -1 : st.st_mtime);
+  _Stat->st_ctime=((st.st_ctime > INT32_MAX) ? -1 : st.st_ctime);
+  return 0;
+}
+int (__cdecl *__MINGW_IMP_SYMBOL(_stat32i64))(const char *, struct _stat32i64 *) = _stat32i64;
+
+#undef _stati64
+int __attribute__ ((alias ("_stat32i64"))) __cdecl _stati64(const char *, struct _stat32i64 *);
+extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_stat32i64))))) (__cdecl *__MINGW_IMP_SYMBOL(_stati64))(const char *, struct _stat32i64 *);
diff --git a/mingw-w64-crt/stdio/_wstat32i64.c b/mingw-w64-crt/stdio/_wstat32i64.c
new file mode 100644
index 0000000..dab7600
--- /dev/null
+++ b/mingw-w64-crt/stdio/_wstat32i64.c
@@ -0,0 +1,42 @@
+/**
+ * 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 <stdint.h>
+
+/* When the file time does not fit into the st_Xtime field:
+ *           crtdll-msvcr71   msvcr80+
+ * st_Xtime       -1             -1
+ * errno       no change       EINVAL
+ * returns         0              0
+ *
+ * This file is used only for pre-msvcrt40 builds,
+ * So use the pre-msvcrt40 behavior - fills -1 without errno change.
+ */
+int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat)
+{
+  struct _stat64 st;
+  int ret=_wstat64(_Name,&st);
+  if (ret != 0)
+    return ret;
+  _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=st.st_size;
+  _Stat->st_atime=((st.st_atime > INT32_MAX) ? -1 : st.st_atime);
+  _Stat->st_mtime=((st.st_mtime > INT32_MAX) ? -1 : st.st_mtime);
+  _Stat->st_ctime=((st.st_ctime > INT32_MAX) ? -1 : st.st_ctime);
+  return 0;
+}
+int (__cdecl *__MINGW_IMP_SYMBOL(_wstat32i64))(const wchar_t *, struct _stat32i64 *) = _wstat32i64;
+
+#undef _wstati64
+int __attribute__ ((alias ("_wstat32i64"))) __cdecl _wstati64(const wchar_t *, struct _stat32i64 *);
+extern int __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_wstat32i64))))) (__cdecl *__MINGW_IMP_SYMBOL(_wstati64))(const wchar_t *, struct _stat32i64 *);