crt: Fix mingw-w64 emulation of _fstat64i32, _stat64i32 and _wstat64i32 functions

All 64-bit CRT import libraries already provides _fstat64i32, _stat64i32
and _wstat64i32 function symbols. These symbols are either directly
exported from 64-bit CRT DLL library or def file contains alias to other
ABI compatible symbols (_fstat, _stat and _wstat).

Also all these functions _fstat64i32, _stat64i32 and _wstat64i32 are
provided by msvcr80+ and UCRT, so ensure that mingw-w64 does not provide
any replacement for msvcr80+ import libraries. And ensure that libmingwex.a
library does not provide duplication of these symbols.

For 32-bit pre-msvcr80 CRT import libraries provides mingw-w64 emulation
via _fstat64, _stat64 and _wstat64, which just truncates 64-bit st_size
(returned by _*stat64 function) to 32-bit st_size (which is ABI of
_*stat64i32). Do not use any _mingw_no_trailing_slash workaround as for all
these functions with underscore prefix, it is expected that behavior is
same as for other stat functions with underscore prefix.

These _fstat64i32, _stat64i32 and _wstat64i32 functions in msvcr80+ and
UCRT DLL libraries do not touch output struct stat buffer on error. So do
same thing in mingw-w64 emulation and remove memset(stat, 0, sizeof(stat))
call in failure path.

And add missing __MINGW_IMP_SYMBOL import symbols into mingw-w64 emulation
code for these functions as msvcr80+ import libraries already have them.

Signed-off-by: Martin Storsjö <martin@martin.st>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 32187b8..02a857d 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -554,9 +554,11 @@
   stdio/_scprintf.c \
   stdio/_scwprintf.c \
   stdio/_stat64.c \
+  stdio/_stat64i32.c \
   stdio/_vscprintf.c \
   stdio/_vscwprintf.c \
   stdio/_wstat64.c \
+  stdio/_wstat64i32.c \
   string/wcstok.c
 
 # Files included in libmsvcrt-os.a (for msvcrt.dll) on x86_64
@@ -757,6 +759,8 @@
   misc/__initenv.c \
   misc/__winitenv.c \
   stdio/_setmaxstdio.c \
+  stdio/_stat64i32.c \
+  stdio/_wstat64i32.c \
   stdio/gets.c
 
 if ARM64EC
@@ -855,6 +859,8 @@
   stdio/_fseeki64.c \
   stdio/_fstat64i32.c \
   stdio/_ftelli64.c \
+  stdio/_stat64i32.c \
+  stdio/_wstat64i32.c \
   stdio/mingw_lock.c \
   string/wcstok.c
 
@@ -1055,8 +1061,8 @@
   \
   stdio/strtok_r.c \
   stdio/_Exit.c            stdio/_findfirst64i32.c   stdio/_findnext64i32.c \
-  stdio/_stat.c            stdio/_stat64i32.c        stdio/_wfindfirst64i32.c stdio/_wfindnext64i32.c \
-  stdio/_wstat.c           stdio/_wstat64i32.c       stdio/asprintf.c \
+  stdio/_stat.c            stdio/_wfindfirst64i32.c  stdio/_wfindnext64i32.c \
+  stdio/_wstat.c           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         \
   \
diff --git a/mingw-w64-crt/stdio/_fstat64i32.c b/mingw-w64-crt/stdio/_fstat64i32.c
index 7e71f2e..cc72b38 100644
--- a/mingw-w64-crt/stdio/_fstat64i32.c
+++ b/mingw-w64-crt/stdio/_fstat64i32.c
@@ -1,14 +1,27 @@
+/**
+ * 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.
+ */
+
 #define __CRT__NO_INLINE
 #include <sys/stat.h>
 
+/* When the file size does not fit into the st_size field:
+ *           crtdll-msvcr90   msvcr100   msvcr110+
+ * st_size      truncate         0           0
+ * errno       no change     no change   EOVERFLOW
+ * returns         0            -1          -1
+ *
+ * This file is used only for pre-msvcr80 builds,
+ * So use the pre-msvcr80 behavior - truncate without error.
+ */
 int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat)
 {
   struct _stat64 st;
   int ret=_fstat64(_FileDes,&st);
-  if (ret == -1) {
-    *_Stat = (struct _stat64i32){0};
-    return -1;
-  }
+  if (ret != 0)
+    return ret;
   _Stat->st_dev=st.st_dev;
   _Stat->st_ino=st.st_ino;
   _Stat->st_mode=st.st_mode;
@@ -16,10 +29,10 @@
   _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; /* 32bit size */
+  _Stat->st_size=(_off_t) st.st_size; /* truncate 64-bit st_size to 32-bit */
   _Stat->st_atime=st.st_atime;
   _Stat->st_mtime=st.st_mtime;
   _Stat->st_ctime=st.st_ctime;
-  return ret;
+  return 0;
 }
-
+int (__cdecl *__MINGW_IMP_SYMBOL(_fstat64i32))(int, struct _stat64i32 *) = _fstat64i32;
diff --git a/mingw-w64-crt/stdio/_stat64i32.c b/mingw-w64-crt/stdio/_stat64i32.c
index e288470..47aa080 100644
--- a/mingw-w64-crt/stdio/_stat64i32.c
+++ b/mingw-w64-crt/stdio/_stat64i32.c
@@ -1,77 +1,27 @@
-#define __CRT__NO_INLINE
-#include <sys/stat.h>
-#include <stdlib.h>
-
 /**
- * Returns _path without trailing slash if any
- *
- * - if _path has no trailing slash, the function returns it
- * - if _path has a trailing slash, but is of the form C:/, then it returns it
- * - otherwise, the function creates a new string, which is a copy of _path
- *   without the trailing slash. It is then the responsibility of the caller
- *   to free it.
+ * 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.
  */
 
-static char*
-_mingw_no_trailing_slash (const char* _path)
-{
-  int len;
-  char *p;
+#define __CRT__NO_INLINE
+#include <sys/stat.h>
 
-  p = (char*)_path;
-
-  if (_path && *_path) {
-    len = strlen (_path);
-
-    /* Ignore X:\ */
-
-    if (len <= 1 || ((len == 2 || len == 3) && _path[1] == ':'))
-      return p;
-
-    /* Check UNC \\abc\<name>\ */
-    if ((_path[0] == '\\' || _path[0] == '/')
-	&& (_path[1] == '\\' || _path[1] == '/'))
-      {
-	const char *r = &_path[2];
-	while (*r != 0 && *r != '\\' && *r != '/')
-	  ++r;
-	if (*r != 0)
-	  ++r;
-	if (*r == 0)
-	  return p;
-	while (*r != 0 && *r != '\\' && *r != '/')
-	  ++r;
-	if (*r != 0)
-	  ++r;
-	if (*r == 0)
-	  return p;
-      }
-
-    if (_path[len - 1] == '/' || _path[len - 1] == '\\')
-      {
-	p = (char*)malloc (len);
-	memcpy (p, _path, len - 1);
-	p[len - 1] = '\0';
-      }
-  }
-
-  return p;
-}
-
+/* When the file size does not fit into the st_size field:
+ *           crtdll-msvcr90   msvcr100   msvcr110+
+ * st_size      truncate         0           0
+ * errno       no change     no change   EOVERFLOW
+ * returns         0            -1          -1
+ *
+ * This file is used only for pre-msvcr80 builds,
+ * So use the pre-msvcr80 behavior - truncate without error.
+ */
 int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat)
 {
   struct _stat64 st;
-  char *_path = _mingw_no_trailing_slash(_Name);
-  
-  int ret=_stat64(_path,&st);
-
-  if (_path != _Name)
-    free(_path);
-
-  if (ret == -1) {
-    *_Stat = (struct _stat64i32){0};
-    return -1;
-  }
+  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;
@@ -79,10 +29,10 @@
   _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_size=(_off_t) st.st_size; /* truncate 64-bit st_size to 32-bit */
   _Stat->st_atime=st.st_atime;
   _Stat->st_mtime=st.st_mtime;
   _Stat->st_ctime=st.st_ctime;
-  return ret;
+  return 0;
 }
-
+int (__cdecl *__MINGW_IMP_SYMBOL(_stat64i32))(const char *, struct _stat64i32 *) = _stat64i32;
diff --git a/mingw-w64-crt/stdio/_wstat64i32.c b/mingw-w64-crt/stdio/_wstat64i32.c
index b17c505..a48a510 100644
--- a/mingw-w64-crt/stdio/_wstat64i32.c
+++ b/mingw-w64-crt/stdio/_wstat64i32.c
@@ -1,77 +1,27 @@
-#define __CRT__NO_INLINE
-#include <sys/stat.h>
-#include <stdlib.h>
-
 /**
- * Returns _path without trailing slash if any
- *
- * - if _path has no trailing slash, the function returns it
- * - if _path has a trailing slash, but is of the form C:/, then it returns it
- * - otherwise, the function creates a new string, which is a copy of _path
- *   without the trailing slash. It is then the responsibility of the caller
- *   to free it.
+ * 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.
  */
 
-static wchar_t*
-_mingw_no_trailing_slash (const wchar_t* _path)
-{
-  int len;
-  wchar_t *p;
+#define __CRT__NO_INLINE
+#include <sys/stat.h>
 
-  p = (wchar_t*)_path;
-
-  if (_path && *_path) {
-    len = wcslen (_path);
-
-    /* Ignore X:\ */
-
-    if (len <= 1 || ((len == 2 || len == 3) && _path[1] == L':'))
-      return p;
-
-    /* Check UNC \\abc\<name>\ */
-    if ((_path[0] == L'\\' || _path[0] == L'/')
-	&& (_path[1] == L'\\' || _path[1] == L'/'))
-      {
-	const wchar_t *r = &_path[2];
-	while (*r != 0 && *r != L'\\' && *r != L'/')
-	  ++r;
-	if (*r != 0)
-	  ++r;
-	if (*r == 0)
-	  return p;
-	while (*r != 0 && *r != L'\\' && *r != L'/')
-	  ++r;
-	if (*r != 0)
-	  ++r;
-	if (*r == 0)
-	  return p;
-      }
-
-    if (_path[len - 1] == L'/' || _path[len - 1] == L'\\')
-      {
-	p = (wchar_t*)malloc (len * sizeof(wchar_t));
-	memcpy (p, _path, (len - 1) * sizeof(wchar_t));
-	p[len - 1] = L'\0';
-      }
-  }
-
-  return p;
-}
-
+/* When the file size does not fit into the st_size field:
+ *           crtdll-msvcr90   msvcr100   msvcr110+
+ * st_size      truncate         0           0
+ * errno       no change     no change   EOVERFLOW
+ * returns         0            -1          -1
+ *
+ * This file is used only for pre-msvcr80 builds,
+ * So use the pre-msvcr80 behavior - truncate without error.
+ */
 int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat)
 {
   struct _stat64 st;
-  wchar_t *_path = _mingw_no_trailing_slash(_Name);
-  
-  int ret=_wstat64(_path,&st);
-
-  if (_path != _Name)
-    free(_path);
-
-  if (ret == -1) {
-    *_Stat = (struct _stat64i32){0};
-    return -1;
-  }
+  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;
@@ -79,10 +29,10 @@
   _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_size=(_off_t) st.st_size; /* truncate 64-bit st_size to 32-bit */
   _Stat->st_atime=st.st_atime;
   _Stat->st_mtime=st.st_mtime;
   _Stat->st_ctime=st.st_ctime;
-  return ret;
+  return 0;
 }
-
+int (__cdecl *__MINGW_IMP_SYMBOL(_wstat64i32))(const wchar_t *, struct _stat64i32 *) = _wstat64i32;