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;