On 2025-03-09 Pali Rohár wrote: > On Friday 07 March 2025 20:31:09 Lasse Collin wrote: > > The commit 45bf2cca702b from 2009 added memset calls to zero the > > stat buffer on failure. That seems unncessary, but the commit > > message says it fixed something with binutils/bfd. I see you > > removed the memset, so I hope it isn't needed anymore. > > I have tested various CRT DLL import libraries and various _stat* > functions from them, and all of them do not touch stat buffer on > error. > > Hence I removed those memset calls, to have mingw-w64 emulation > functions to behave in the same way as the native crtdll/msvcrt/ucrt > underscore _stat* functions. > > For me it looks strange if the _fstat64i32() emulation for libmsvcrt.a > zero fill the stat buffer and the native _fstat64i32() from > libmsvcr80.a or libucrt.a, or native _fstat() from libmsvcrt.a does > not do it. > > Now I'm looking at 45bf2cca702b and I do not think it fixed something > for UCRT or msvcr80+, as those changes are only for pre-msvcr80 for > which is needed mingw-w64 emulation (which the commit changed). > > What could it fix is probably non-underscored stat function? But that > it also suspicious. Because now I have tested that Linux stat() > function from glibc does not touch struct stat buffer too. > > So for me it looks like that the change in 45bf2cca702b is very > suspicious as it change behavior in a way which is different from > _both_ Linux glibc and also MS crtdll/msvcrt/ucrt.
Thanks for testing! I agree that the change in the commit is weird. If it really fixed something, it merely worked around a bug somewhere outside mingw-w64. It's should be fine to remove the memset calls. > > > Ok. I'm sending 10 patches in the attachment. > > > > Thanks! Makefile.am changes didn't apply to master, but the rest did > > cleanly. I think I can test the .c/.h file changes easily still. > > Maybe you need 3 other changes which I have sent to list? Anyway, I > these changes on top of 99518b7fd9d0 ("Add missing comparison > operators for Microsoft::WRL::ComPtr") with those other 3 small > changes. Thanks! Your earlier patches were merged to master and then these stat patches applied cleanly. I don't have knowledge to review the .def files, but I have looked at the C files. In many ways the code is better now. :-) I did some very basic testing with MSVCRT including the tweaks I made. Even though things worked for me, I'm worried about a few details. (1) Does the __MINGW_ASM_CALL usage work with control flow integrity (CFI) on Windows? Consider this: // <sys/stat.h> int __cdecl stat(const char *_Filename, struct stat *_Stat) __MINGW_ASM_CALL(stat64i32); // stat64i32.c int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) stat.h has "struct stat *" and stat64i32.c has "struct _stat64i32 *". On Linux and "clang -fsanitize=function", this kind of argument type mismatch doesn't work if the function is called indirectly using a function pointer. It might not be common to take the address of stat, but it should still work. (I didn't test how this works on Windows, sorry.) If needed, this alone should be easy to fix. stat*.c files could define _TIME_BITS and _FILE_OFFSET_BITS to get the correct "struct stat" variant. The pointer could be cast to "struct _stat64i32 *" when calling _stat64i32. But the C standard and compilers might not like that: (2) Casting a pointer to/from two structs breaks strict aliasing rules even if the structs have identical members. Because the casts are done at translation unit boundaries, it might work in practice as long as -flto isn't used. Casting likely is OK also if calling a CRT function (not a libmingwex wrapper) because -flto shouldn't be able to see what the CRT DLLs do. Otherwise I suspect that extra code is needed. For example, stat32.c could use memcpy to convert struct _stat32 to struct stat like mingw-w64-crt/stdio/_stat.c does in the current mingw-w64 code. These wrappers could set _TIME_BITS and _FILE_OFFSET_BITS to get the correct copy of struct stat. Strict aliasing issues often feel silly (a simple thing becomes more complex and slower), but it seems to have been a concern in the past. For example, see the commits ae36a4bbc0e6 and b38f5085b758. (3) fstat, stat, and wstat aren't declared in <sys/stat.h> when __CRT__NO_INLINE is defined, thus those declarations are missing if compiling without optimizations. I changed those to _CRTBLD, but this broke ftw.c (not ftw64.c). <ftw.h> uses "struct stat" and "struct stat64". I almost fixed the ftw issue, but I didn't finish because figuring out the stat redirects should be finished first (*if* they need to be changed). If both (1) and (2) are a concern, there might be a need for five ftw variants: four due to time_t/off_t combinations, and the fifth due to ftw64 using struct stat64. ftw/ftw64 take a function pointer argument, and that function takes a pointer to a struct stat/stat64 as an argument. The typename may need to match for CFI. Maybe using macros to redirect stat, wstat, and fstat could be simpler after all. Then the four ftw variants would be built with distinct struct stat32/64/32i64/64i32 types, and a fifth variant for ftw64-with-stat64 wouldn't be needed. Using macros means that four statxxx structs (instead of two) would be needed in <sys/stat.h>. They would be identical to the four in <_mingw_stat64.h> except that the leading underscore would be omitted. The current <sys/stat.h> in mingw-w64 uses macros to redirect stat and fstat for _FILE_OFFSET_BITS == 64, so such macros should be OK in terms of application compatibility. (4) Always using 64-bit time in struct stat64 doesn't sound correct because it should still use time_t. But it has been this way for a very long time and matches _stat64, thus I agree it's best to not change it. In 2025, few POSIX apps should be using the LFS functions with the "64" suffix anyway. (5) This isn't about your patches, but I looked for other broken uses of __CRT__NO_INLINE. The macro comes from 4a0f06032b17 (2009). <sys/utime.h> uses the macro to avoid declaring the inline functions that redirect _utime/_futime/_wutime to 32/64-bit versions. See the commits cad9b5a68bdc and e217baf22f0a (both from 2009). Thus, _USE_32BIT_TIME_T is ignored if an application is built with optimizations disabled. Seems that a wrong function might be called in that case. I didn't try to fix this now. I attached my edits. They apply on top of your patches. I included even the S_IFBLK change because if API/ABI is touched anyway, it's good to do all changes at once, but I understand that it's out of scope of these stat changes. Feel free to adapt/edit/squash as you prefer, and skip those that you don't like. Remember that my _CRTBLD change broke ftw.c, but let's figure out the stat function redirects first. Unfortunately I don't have time to look at this further this week, but I should have time some day next week. -- Lasse Collin
From 9498df7b33681963b4079829f7953d86d9118430 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 01/10] crt: __mingw_fix_wstat_path: Fix function name and const correctness --- mingw-w64-crt/stdio/__mingw_fix_wstat_path.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c index a121911fa..aa0c2e1a5 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c @@ -18,8 +18,8 @@ * to free it. */ -wchar_t* __mingw_fix_stat_path (wchar_t* _path); -wchar_t* __mingw_fix_stat_path (wchar_t* _path) +wchar_t* __mingw_fix_wstat_path (const wchar_t* _path); +wchar_t* __mingw_fix_wstat_path (const wchar_t* _path) { int len; wchar_t *p; -- 2.48.1 From 3eead65f9b3b14027485e05fa23e5428ee554729 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 02/10] crt: __mingw_fix_stat_path: Use size_t instead of int --- mingw-w64-crt/stdio/__mingw_fix_stat_path.c | 2 +- mingw-w64-crt/stdio/__mingw_fix_wstat_path.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c index 1efb3fea3..91382ee6b 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c @@ -21,7 +21,7 @@ char* __mingw_fix_stat_path (const char* _path); char* __mingw_fix_stat_path (const char* _path) { - int len; + size_t len; char *p; p = (char*)_path; diff --git a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c index aa0c2e1a5..76f12074f 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c @@ -21,7 +21,7 @@ wchar_t* __mingw_fix_wstat_path (const wchar_t* _path); wchar_t* __mingw_fix_wstat_path (const wchar_t* _path) { - int len; + size_t len; wchar_t *p; p = (wchar_t*)_path; -- 2.48.1 From b74a7c491e3d509455a42eb751688e3750617151 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 03/10] headers: Use _CRTBLD instead of __CRT__NO_INLINE in <sys/stat.h> __CRT__NO_INLINE is defined when building programs with optimizations disabled, thus fstat, stat, and wstat declarations were missing in that case. --- mingw-w64-headers/crt/sys/stat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mingw-w64-headers/crt/sys/stat.h b/mingw-w64-headers/crt/sys/stat.h index b7884d89f..edbdbc11f 100644 --- a/mingw-w64-headers/crt/sys/stat.h +++ b/mingw-w64-headers/crt/sys/stat.h @@ -140,7 +140,7 @@ struct stat { time_t st_ctime; }; -#ifndef __CRT__NO_INLINE +#ifndef _CRTBLD #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); -- 2.48.1 From 3fd0d84a529ca20c4216d98b38ffb5260adcddf9 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 04/10] crt: stat: Remove unneeded __CRT__NO_INLINE definitions --- mingw-w64-crt/stdio/__mingw_fix_stat_path.c | 1 - mingw-w64-crt/stdio/__mingw_fix_wstat_path.c | 1 - mingw-w64-crt/stdio/_fstat32i64.c | 1 - mingw-w64-crt/stdio/_fstat64.c | 1 - mingw-w64-crt/stdio/_fstat64i32.c | 1 - mingw-w64-crt/stdio/_stat32i64.c | 1 - mingw-w64-crt/stdio/_stat64.c | 1 - mingw-w64-crt/stdio/_stat64i32.c | 1 - mingw-w64-crt/stdio/_wstat32i64.c | 1 - mingw-w64-crt/stdio/_wstat64.c | 1 - mingw-w64-crt/stdio/_wstat64i32.c | 1 - mingw-w64-crt/stdio/stat32.c | 1 - mingw-w64-crt/stdio/stat32i64.c | 1 - mingw-w64-crt/stdio/stat64.c | 1 - mingw-w64-crt/stdio/stat64i32.c | 1 - mingw-w64-crt/stdio/wstat32.c | 1 - mingw-w64-crt/stdio/wstat32i64.c | 1 - mingw-w64-crt/stdio/wstat64.c | 1 - mingw-w64-crt/stdio/wstat64i32.c | 1 - 19 files changed, 19 deletions(-) diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c index 91382ee6b..109abf243 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c index 76f12074f..a409dde71 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/_fstat32i64.c b/mingw-w64-crt/stdio/_fstat32i64.c index a30dee49d..bf7311265 100644 --- a/mingw-w64-crt/stdio/_fstat32i64.c +++ b/mingw-w64-crt/stdio/_fstat32i64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> int __cdecl _fstat32i64(int _FileDes,struct _stat32i64 *_Stat) diff --git a/mingw-w64-crt/stdio/_fstat64.c b/mingw-w64-crt/stdio/_fstat64.c index b8032ef7a..a053c8f9d 100644 --- a/mingw-w64-crt/stdio/_fstat64.c +++ b/mingw-w64-crt/stdio/_fstat64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <io.h> #include <windows.h> diff --git a/mingw-w64-crt/stdio/_fstat64i32.c b/mingw-w64-crt/stdio/_fstat64i32.c index 93871c2f4..8a10dd44f 100644 --- a/mingw-w64-crt/stdio/_fstat64i32.c +++ b/mingw-w64-crt/stdio/_fstat64i32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> int __cdecl _fstat64i32(int _FileDes,struct _stat64i32 *_Stat) diff --git a/mingw-w64-crt/stdio/_stat32i64.c b/mingw-w64-crt/stdio/_stat32i64.c index b83142f2a..61d2fb8ee 100644 --- a/mingw-w64-crt/stdio/_stat32i64.c +++ b/mingw-w64-crt/stdio/_stat32i64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> int __cdecl _stat32i64(const char *_Name,struct _stat32i64 *_Stat) diff --git a/mingw-w64-crt/stdio/_stat64.c b/mingw-w64-crt/stdio/_stat64.c index 71247f0e4..18e48af14 100644 --- a/mingw-w64-crt/stdio/_stat64.c +++ b/mingw-w64-crt/stdio/_stat64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <windows.h> diff --git a/mingw-w64-crt/stdio/_stat64i32.c b/mingw-w64-crt/stdio/_stat64i32.c index 90e5ee6a6..5ff60cb47 100644 --- a/mingw-w64-crt/stdio/_stat64i32.c +++ b/mingw-w64-crt/stdio/_stat64i32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> int __cdecl _stat64i32(const char *_Name,struct _stat64i32 *_Stat) diff --git a/mingw-w64-crt/stdio/_wstat32i64.c b/mingw-w64-crt/stdio/_wstat32i64.c index a584363f0..11e544bc1 100644 --- a/mingw-w64-crt/stdio/_wstat32i64.c +++ b/mingw-w64-crt/stdio/_wstat32i64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> int __cdecl _wstat32i64(const wchar_t *_Name,struct _stat32i64 *_Stat) diff --git a/mingw-w64-crt/stdio/_wstat64.c b/mingw-w64-crt/stdio/_wstat64.c index 9d5a39ebc..2f5bd2242 100644 --- a/mingw-w64-crt/stdio/_wstat64.c +++ b/mingw-w64-crt/stdio/_wstat64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <windows.h> diff --git a/mingw-w64-crt/stdio/_wstat64i32.c b/mingw-w64-crt/stdio/_wstat64i32.c index 846ed576b..d2dd2b195 100644 --- a/mingw-w64-crt/stdio/_wstat64i32.c +++ b/mingw-w64-crt/stdio/_wstat64i32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> int __cdecl _wstat64i32(const wchar_t *_Name,struct _stat64i32 *_Stat) diff --git a/mingw-w64-crt/stdio/stat32.c b/mingw-w64-crt/stdio/stat32.c index be3e4694b..fa189133b 100644 --- a/mingw-w64-crt/stdio/stat32.c +++ b/mingw-w64-crt/stdio/stat32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/stat32i64.c b/mingw-w64-crt/stdio/stat32i64.c index f853d7a3f..3291ef6b8 100644 --- a/mingw-w64-crt/stdio/stat32i64.c +++ b/mingw-w64-crt/stdio/stat32i64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/stat64.c b/mingw-w64-crt/stdio/stat64.c index 096bae132..930696fae 100644 --- a/mingw-w64-crt/stdio/stat64.c +++ b/mingw-w64-crt/stdio/stat64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/stat64i32.c b/mingw-w64-crt/stdio/stat64i32.c index 66f069722..298212019 100644 --- a/mingw-w64-crt/stdio/stat64i32.c +++ b/mingw-w64-crt/stdio/stat64i32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/wstat32.c b/mingw-w64-crt/stdio/wstat32.c index 41e3b1c85..278a2a7bd 100644 --- a/mingw-w64-crt/stdio/wstat32.c +++ b/mingw-w64-crt/stdio/wstat32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/wstat32i64.c b/mingw-w64-crt/stdio/wstat32i64.c index 15acacb53..ea190f573 100644 --- a/mingw-w64-crt/stdio/wstat32i64.c +++ b/mingw-w64-crt/stdio/wstat32i64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/wstat64.c b/mingw-w64-crt/stdio/wstat64.c index 399efcf72..a496a54eb 100644 --- a/mingw-w64-crt/stdio/wstat64.c +++ b/mingw-w64-crt/stdio/wstat64.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> diff --git a/mingw-w64-crt/stdio/wstat64i32.c b/mingw-w64-crt/stdio/wstat64i32.c index 5821cc464..f79f4fcdd 100644 --- a/mingw-w64-crt/stdio/wstat64i32.c +++ b/mingw-w64-crt/stdio/wstat64i32.c @@ -4,7 +4,6 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ -#define __CRT__NO_INLINE #include <sys/stat.h> #include <stdlib.h> -- 2.48.1 From e9e77e033606a4d67cd7f4b0a01e35915d278fa1 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 05/10] crt: stat: Check for malloc failure --- mingw-w64-crt/stdio/__mingw_fix_stat_path.c | 2 ++ mingw-w64-crt/stdio/__mingw_fix_wstat_path.c | 2 ++ mingw-w64-crt/stdio/stat32.c | 2 ++ mingw-w64-crt/stdio/stat32i64.c | 2 ++ mingw-w64-crt/stdio/stat64.c | 2 ++ mingw-w64-crt/stdio/stat64i32.c | 2 ++ mingw-w64-crt/stdio/wstat32.c | 2 ++ mingw-w64-crt/stdio/wstat32i64.c | 2 ++ mingw-w64-crt/stdio/wstat64.c | 2 ++ mingw-w64-crt/stdio/wstat64i32.c | 2 ++ 10 files changed, 20 insertions(+) diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c index 109abf243..66d57950b 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c @@ -55,6 +55,8 @@ char* __mingw_fix_stat_path (const char* _path) if (_path[len - 1] == '/' || _path[len - 1] == '\\') { p = (char*)malloc (len); + if (p == NULL) + return NULL; /* malloc has set errno. */ memcpy (p, _path, len - 1); p[len - 1] = '\0'; } diff --git a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c index a409dde71..7dc03e308 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_wstat_path.c @@ -55,6 +55,8 @@ wchar_t* __mingw_fix_wstat_path (const wchar_t* _path) if (_path[len - 1] == L'/' || _path[len - 1] == L'\\') { p = (wchar_t*)malloc (len * sizeof(wchar_t)); + if (p == NULL) + return NULL; /* malloc has set errno. */ memcpy (p, _path, (len - 1) * sizeof(wchar_t)); p[len - 1] = L'\0'; } diff --git a/mingw-w64-crt/stdio/stat32.c b/mingw-w64-crt/stdio/stat32.c index fa189133b..0ea2ce589 100644 --- a/mingw-w64-crt/stdio/stat32.c +++ b/mingw-w64-crt/stdio/stat32.c @@ -13,6 +13,8 @@ int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat); int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat) { char *_path = __mingw_fix_stat_path(_Filename); + if (_path == NULL) + return -1; int ret = _stat32(_path, _Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/stat32i64.c b/mingw-w64-crt/stdio/stat32i64.c index 3291ef6b8..131003577 100644 --- a/mingw-w64-crt/stdio/stat32i64.c +++ b/mingw-w64-crt/stdio/stat32i64.c @@ -13,6 +13,8 @@ int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat); int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat) { char *_path = __mingw_fix_stat_path(_Filename); + if (_path == NULL) + return -1; int ret = _stat32i64(_path, _Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/stat64.c b/mingw-w64-crt/stdio/stat64.c index 930696fae..7651aa06d 100644 --- a/mingw-w64-crt/stdio/stat64.c +++ b/mingw-w64-crt/stdio/stat64.c @@ -12,6 +12,8 @@ char *__mingw_fix_stat_path(const char *_path); int __cdecl stat64(const char *_Filename, struct stat64 *_Stat) { char *_path = __mingw_fix_stat_path(_Filename); + if (_path == NULL) + return -1; int ret = _stat64(_path, (struct _stat64 *)_Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/stat64i32.c b/mingw-w64-crt/stdio/stat64i32.c index 298212019..49026ad4d 100644 --- a/mingw-w64-crt/stdio/stat64i32.c +++ b/mingw-w64-crt/stdio/stat64i32.c @@ -13,6 +13,8 @@ int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat); int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) { char *_path = __mingw_fix_stat_path(_Filename); + if (_path == NULL) + return -1; int ret = _stat64i32(_path, _Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/wstat32.c b/mingw-w64-crt/stdio/wstat32.c index 278a2a7bd..af9ede4e6 100644 --- a/mingw-w64-crt/stdio/wstat32.c +++ b/mingw-w64-crt/stdio/wstat32.c @@ -13,6 +13,8 @@ int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat); int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat) { wchar_t *_path = __mingw_fix_wstat_path(_Filename); + if (_path == NULL) + return -1; int ret = _wstat32(_path, _Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/wstat32i64.c b/mingw-w64-crt/stdio/wstat32i64.c index ea190f573..b9a9470f7 100644 --- a/mingw-w64-crt/stdio/wstat32i64.c +++ b/mingw-w64-crt/stdio/wstat32i64.c @@ -13,6 +13,8 @@ int __cdecl wstat32i64(const wchar_t *_Filename, struct _stat32i64 *_Stat); int __cdecl wstat32i64(const wchar_t *_Filename, struct _stat32i64 *_Stat) { wchar_t *_path = __mingw_fix_wstat_path(_Filename); + if (_path == NULL) + return -1; int ret = _wstat32i64(_path, _Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/wstat64.c b/mingw-w64-crt/stdio/wstat64.c index a496a54eb..d66606f01 100644 --- a/mingw-w64-crt/stdio/wstat64.c +++ b/mingw-w64-crt/stdio/wstat64.c @@ -12,6 +12,8 @@ wchar_t *__mingw_fix_wstat_path(const wchar_t *_path); int __cdecl wstat64(const wchar_t *_Filename, struct stat64 *_Stat) { wchar_t *_path = __mingw_fix_wstat_path(_Filename); + if (_path == NULL) + return -1; int ret = _wstat64(_path, (struct _stat64 *)_Stat); if (_path != _Filename) free(_path); diff --git a/mingw-w64-crt/stdio/wstat64i32.c b/mingw-w64-crt/stdio/wstat64i32.c index f79f4fcdd..9853d80dc 100644 --- a/mingw-w64-crt/stdio/wstat64i32.c +++ b/mingw-w64-crt/stdio/wstat64i32.c @@ -13,6 +13,8 @@ int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat); int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat) { wchar_t *_path = __mingw_fix_wstat_path(_Filename); + if (_path == NULL) + return -1; int ret = _wstat64i32(_path, _Stat); if (_path != _Filename) free(_path); -- 2.48.1 From 485b56c1b48fb2da0e6582a458f67164dcd63c55 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 06/10] crt: stat: Fail if the pathname ends with a slash and isn't a directory POSIX requires stat("foo/", &st) to fail if foo isn't a directory or a symbolic link to a directory. Preserve errno when calling free(). --- mingw-w64-crt/Makefile.am | 2 +- mingw-w64-crt/stdio/__mingw_fix_stat_common.c | 35 +++++++++++++++++++ mingw-w64-crt/stdio/stat32.c | 6 ++-- mingw-w64-crt/stdio/stat32i64.c | 6 ++-- mingw-w64-crt/stdio/stat64.c | 6 ++-- mingw-w64-crt/stdio/stat64i32.c | 6 ++-- mingw-w64-crt/stdio/wstat32.c | 6 ++-- mingw-w64-crt/stdio/wstat32i64.c | 6 ++-- mingw-w64-crt/stdio/wstat64.c | 6 ++-- mingw-w64-crt/stdio/wstat64i32.c | 6 ++-- 10 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 mingw-w64-crt/stdio/__mingw_fix_stat_common.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index ead376082..1e3fb851c 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -1029,7 +1029,7 @@ src_libmingwex=\ 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 \ - stdio/__mingw_fix_stat_path.c stdio/__mingw_fix_wstat_path.c \ + stdio/__mingw_fix_stat_common.c stdio/__mingw_fix_stat_path.c stdio/__mingw_fix_wstat_path.c \ \ stdio/mingw_pformat.h mingw_sformat.h mingw_swformat.h \ stdio/mingw_fprintf.c stdio/mingw_fwprintf.c stdio/mingw_fscanf.c stdio/mingw_fwscanf.c stdio/mingw_pformat.c \ diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat_common.c b/mingw-w64-crt/stdio/__mingw_fix_stat_common.c new file mode 100644 index 000000000..642db9add --- /dev/null +++ b/mingw-w64-crt/stdio/__mingw_fix_stat_common.c @@ -0,0 +1,35 @@ +/** + * 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 <errno.h> + +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode) +{ + // If the original pathname and used pathname differ, it means that + // __mingw_fix_stat_path or __mingw_fix_wstat_path had to allocate + // a temporary buffer and remove a trailing directory separator. + // In this case the temporary allocation has to be freed, and the + // stat function succeeds only if the pathname was a directory. + if (orig_path != used_path) { + // Save errno because we call free. + int saved_errno = errno; + free(used_path); + + if (ret == 0 && !S_ISDIR(mode)) { + ret = -1; + saved_errno = ENOTDIR; + } + + errno = saved_errno; + } + + return ret; +} diff --git a/mingw-w64-crt/stdio/stat32.c b/mingw-w64-crt/stdio/stat32.c index 0ea2ce589..2793ded54 100644 --- a/mingw-w64-crt/stdio/stat32.c +++ b/mingw-w64-crt/stdio/stat32.c @@ -8,6 +8,8 @@ #include <stdlib.h> char *__mingw_fix_stat_path(const char *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat); int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat) @@ -16,9 +18,7 @@ int __cdecl stat32(const char *_Filename, struct _stat32 *_Stat) if (_path == NULL) return -1; int ret = _stat32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat32))(const char *, struct _stat32 *) = stat32; diff --git a/mingw-w64-crt/stdio/stat32i64.c b/mingw-w64-crt/stdio/stat32i64.c index 131003577..8b8a5db28 100644 --- a/mingw-w64-crt/stdio/stat32i64.c +++ b/mingw-w64-crt/stdio/stat32i64.c @@ -8,6 +8,8 @@ #include <stdlib.h> char *__mingw_fix_stat_path(const char *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat); int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat) @@ -16,8 +18,6 @@ int __cdecl stat32i64(const char *_Filename, struct _stat32i64 *_Stat) if (_path == NULL) return -1; int ret = _stat32i64(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat32i64))(const char *, struct _stat32i64 *) = stat32i64; diff --git a/mingw-w64-crt/stdio/stat64.c b/mingw-w64-crt/stdio/stat64.c index 7651aa06d..964dc52b0 100644 --- a/mingw-w64-crt/stdio/stat64.c +++ b/mingw-w64-crt/stdio/stat64.c @@ -8,6 +8,8 @@ #include <stdlib.h> char *__mingw_fix_stat_path(const char *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl stat64(const char *_Filename, struct stat64 *_Stat) { @@ -15,8 +17,6 @@ int __cdecl stat64(const char *_Filename, struct stat64 *_Stat) if (_path == NULL) return -1; int ret = _stat64(_path, (struct _stat64 *)_Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat64))(const char *, struct stat64 *) = stat64; diff --git a/mingw-w64-crt/stdio/stat64i32.c b/mingw-w64-crt/stdio/stat64i32.c index 49026ad4d..22b0490e9 100644 --- a/mingw-w64-crt/stdio/stat64i32.c +++ b/mingw-w64-crt/stdio/stat64i32.c @@ -8,6 +8,8 @@ #include <stdlib.h> char *__mingw_fix_stat_path(const char *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat); int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) @@ -16,9 +18,7 @@ int __cdecl stat64i32(const char *_Filename, struct _stat64i32 *_Stat) if (_path == NULL) return -1; int ret = _stat64i32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(stat64i32))(const char *, struct _stat64i32 *) = stat64i32; diff --git a/mingw-w64-crt/stdio/wstat32.c b/mingw-w64-crt/stdio/wstat32.c index af9ede4e6..6640ec2f8 100644 --- a/mingw-w64-crt/stdio/wstat32.c +++ b/mingw-w64-crt/stdio/wstat32.c @@ -8,6 +8,8 @@ #include <stdlib.h> wchar_t *__mingw_fix_wstat_path(const wchar_t *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat); int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat) @@ -16,9 +18,7 @@ int __cdecl wstat32(const wchar_t *_Filename, struct _stat32 *_Stat) if (_path == NULL) return -1; int ret = _wstat32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat32))(const wchar_t *, struct _stat32 *) = wstat32; diff --git a/mingw-w64-crt/stdio/wstat32i64.c b/mingw-w64-crt/stdio/wstat32i64.c index b9a9470f7..6dfa3b2fc 100644 --- a/mingw-w64-crt/stdio/wstat32i64.c +++ b/mingw-w64-crt/stdio/wstat32i64.c @@ -8,6 +8,8 @@ #include <stdlib.h> wchar_t *__mingw_fix_wstat_path(const wchar_t *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl wstat32i64(const wchar_t *_Filename, struct _stat32i64 *_Stat); int __cdecl wstat32i64(const wchar_t *_Filename, struct _stat32i64 *_Stat) @@ -16,8 +18,6 @@ int __cdecl wstat32i64(const wchar_t *_Filename, struct _stat32i64 *_Stat) if (_path == NULL) return -1; int ret = _wstat32i64(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat32i64))(const wchar_t *, struct _stat32i64 *) = wstat32i64; diff --git a/mingw-w64-crt/stdio/wstat64.c b/mingw-w64-crt/stdio/wstat64.c index d66606f01..7185413c4 100644 --- a/mingw-w64-crt/stdio/wstat64.c +++ b/mingw-w64-crt/stdio/wstat64.c @@ -8,6 +8,8 @@ #include <stdlib.h> wchar_t *__mingw_fix_wstat_path(const wchar_t *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl wstat64(const wchar_t *_Filename, struct stat64 *_Stat) { @@ -15,8 +17,6 @@ int __cdecl wstat64(const wchar_t *_Filename, struct stat64 *_Stat) if (_path == NULL) return -1; int ret = _wstat64(_path, (struct _stat64 *)_Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat64))(const wchar_t *, struct stat64 *) = wstat64; diff --git a/mingw-w64-crt/stdio/wstat64i32.c b/mingw-w64-crt/stdio/wstat64i32.c index 9853d80dc..ae7a78463 100644 --- a/mingw-w64-crt/stdio/wstat64i32.c +++ b/mingw-w64-crt/stdio/wstat64i32.c @@ -8,6 +8,8 @@ #include <stdlib.h> wchar_t *__mingw_fix_wstat_path(const wchar_t *_path); +int __mingw_fix_stat_common(int ret, const void *orig_path, void *used_path, + unsigned short mode); int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat); int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat) @@ -16,9 +18,7 @@ int __cdecl wstat64i32(const wchar_t *_Filename, struct _stat64i32 *_Stat) if (_path == NULL) return -1; int ret = _wstat64i32(_path, _Stat); - if (_path != _Filename) - free(_path); - return ret; + return __mingw_fix_stat_common(ret, _Filename, _path, _Stat->st_mode); } int (__cdecl *__MINGW_IMP_SYMBOL(wstat64i32))(const wchar_t *, struct _stat64i32 *) = wstat64i32; -- 2.48.1 From e5945fe195d6ea66827c12cd3defab4dae1b1a86 Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:20:06 +0200 Subject: [PATCH 07/10] crt: Add __mingw_filename_cp() It returns the code page that the CRT currently uses for filenames. With UCRT, setlocale(LC_ALL, ".UTF-8") makes the CRT use UTF-8 for filenames, ignoring CP_ACP and CP_OEMCP. Such a setlocale() call can make the WinAPI filename code page differ from the code page used by the CRT. Otherwise the CRT and WinAPI use the same code page which is either CP_ACP or CP_OEMCP. The latter is used if SetFileApisToOEM has been called. --- mingw-w64-crt/Makefile.am | 1 + mingw-w64-crt/misc/__mingw_filename_cp.c | 18 ++++++++++++++++++ mingw-w64-headers/crt/locale.h | 3 +++ 3 files changed, 22 insertions(+) create mode 100644 mingw-w64-crt/misc/__mingw_filename_cp.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index 1e3fb851c..9293cb564 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -1018,6 +1018,7 @@ src_libmingwex=\ misc/wdirent.c misc/winbs_uint64.c misc/winbs_ulong.c misc/winbs_ushort.c \ misc/wmemchr.c misc/wmemcmp.c misc/wmemcpy.c misc/wmemmove.c misc/wmempcpy.c \ misc/wmemset.c misc/ftw.c misc/ftw64.c misc/mingw-access.c \ + misc/__mingw_filename_cp.c \ \ ssp/chk_fail.c ssp/gets_chk.c ssp/memcpy_chk.c ssp/memmove_chk.c \ ssp/mempcpy_chk.c \ diff --git a/mingw-w64-crt/misc/__mingw_filename_cp.c b/mingw-w64-crt/misc/__mingw_filename_cp.c new file mode 100644 index 000000000..2be1a4c31 --- /dev/null +++ b/mingw-w64-crt/misc/__mingw_filename_cp.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. + */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <locale.h> + +unsigned int __cdecl __mingw_filename_cp(void) +{ + return (___lc_codepage_func() == CP_UTF8) + ? CP_UTF8 + : AreFileApisANSI() ? CP_ACP : CP_OEMCP; +} diff --git a/mingw-w64-headers/crt/locale.h b/mingw-w64-headers/crt/locale.h index 9b695e333..66a1cd9ac 100644 --- a/mingw-w64-headers/crt/locale.h +++ b/mingw-w64-headers/crt/locale.h @@ -98,6 +98,9 @@ extern "C" { _CRTIMP unsigned int __cdecl ___lc_codepage_func(void); + /* Get the code page that the CRT currently uses for filenames. */ + unsigned int __cdecl __mingw_filename_cp(void); + #ifndef _WLOCALE_DEFINED #define _WLOCALE_DEFINED _CRTIMP wchar_t *__cdecl _wsetlocale(int _Category,const wchar_t *_Locale); -- 2.48.1 From b89bd7e1c081d2bcf61ce92d00cdcf2e98b98eea Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:21:06 +0200 Subject: [PATCH 08/10] crt: stat: Don't remove a trailing '\' if it is a DBCS trail byte In double-byte character sets, the trail byte of a two-byte character can be a backslash. If such a two-byte character was at the end of the pathname, the trailing backslash was incorrectly removed. The code still removes only one trailing directory separator and thus stat("directory//", &st) still incorrectly fails with MSVCRT. This commit only fixes the DBCS issue. --- mingw-w64-crt/stdio/__mingw_fix_stat_path.c | 36 ++++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c index 66d57950b..b23fc1f4c 100644 --- a/mingw-w64-crt/stdio/__mingw_fix_stat_path.c +++ b/mingw-w64-crt/stdio/__mingw_fix_stat_path.c @@ -4,8 +4,21 @@ * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif #include <sys/stat.h> #include <stdlib.h> +#include <locale.h> +#include <windows.h> + +static const char * +next_char(unsigned int cp, const char *p) +{ + /* If it is a lead byte, skip the next byte except if it is \0. + * If it is \0, it's not a valid DBCS string. */ + return (IsDBCSLeadByteEx(cp, *p) && p[1] != '\0') ? p + 2 : p + 1; +} /** * Returns _path without trailing slash if any @@ -20,6 +33,7 @@ char* __mingw_fix_stat_path (const char* _path); char* __mingw_fix_stat_path (const char* _path) { + const unsigned int cp = __mingw_filename_cp(); size_t len; char *p; @@ -28,30 +42,42 @@ char* __mingw_fix_stat_path (const char* _path) if (_path && *_path) { len = strlen (_path); - /* Ignore X:\ */ - + /* Ignore X:\ + * No ANSI or OEM code page uses ':' as a trail byte. (The code page 1361 + * cannot be used as ANSI or OEM code page.) */ if (len <= 1 || ((len == 2 || len == 3) && _path[1] == ':')) return p; + const char *r = _path; + /* Check UNC \\abc\<name>\ */ if ((_path[0] == '\\' || _path[0] == '/') && (_path[1] == '\\' || _path[1] == '/')) { - const char *r = &_path[2]; + r = &_path[2]; while (*r != 0 && *r != '\\' && *r != '/') - ++r; + r = next_char(cp, r); if (*r != 0) ++r; if (*r == 0) return p; while (*r != 0 && *r != '\\' && *r != '/') - ++r; + r = next_char(cp, r); if (*r != 0) ++r; if (*r == 0) return p; } + /* Return if the last character is a double-byte character. + * Its trail byte could be a '\' which must not be interpret + * as a directory separator. */ + while (r[1] != '\0') { + r = next_char(cp, r); + if (*r == '\0') + return p; + } + if (_path[len - 1] == '/' || _path[len - 1] == '\\') { p = (char*)malloc (len); -- 2.48.1 From 1c30043a3bc99d3ee52bfdcd10ee7933f086530f Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:21:06 +0200 Subject: [PATCH 09/10] crt: dirname: Use __mingw_filename_cp This way it works even if setlocale(LC_ALL, ".UTF8") has been used with UCRT. IsDBCSLeadByteEx(CP_UTF8, x) always returns FALSE, so nothing else in dirname.c needs to be modified. --- mingw-w64-crt/misc/dirname.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mingw-w64-crt/misc/dirname.c b/mingw-w64-crt/misc/dirname.c index 7e6c8d58a..239d5db8d 100644 --- a/mingw-w64-crt/misc/dirname.c +++ b/mingw-w64-crt/misc/dirname.c @@ -7,6 +7,7 @@ #define WIN32_LEAN_AND_MEAN #endif #include <stdlib.h> +#include <locale.h> #include <libgen.h> #include <windows.h> @@ -91,7 +92,7 @@ do_get_path_info(struct path_info* info, char* path) int dbcs_tb, prev_dir_sep, dir_sep; /* Get the code page for paths in the same way as `fopen()`. */ - cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + cp = __mingw_filename_cp(); /* Set the structure to 'no data'. */ info->prefix_end = NULL; -- 2.48.1 From 063f1368fbddd1c3fc9350ed87fd2433bc18b8cf Mon Sep 17 00:00:00 2001 From: Lasse Collin <lasse.col...@tukaani.org> Date: Wed, 12 Mar 2025 16:21:06 +0200 Subject: [PATCH 10/10] headers: Change _S_IFBLK and S_IFBLK from 0x3000 to 0x6000 (ABI break) Windows doesn't have the non-standard _S_IFBLK or the POSIX S_IFBLK, but these macros have been provided by mingw-w64 as an extension. The value 0x3000 was inherited to mingw-w64 from MinGW. In MinGW in 2016, the value of S_IFBLK was changed to an intentionally broken value 0x3001 to make S_ISBLK(S_IFBLK) return false. At the same time, the underscore version _S_IFBLK was poisoned by default. Thus, there's no need to preserve 0x3000 for MinGW compatibility. The value of S_IFBLK isn't specified in POSIX, but every POSIX-like operating system seems to use 0x6000. When S_IFBLK isn't defined, 0x6000 is used as a fallback value in many packages (e.g. Gnulib, libarchive, and Python), thus MSVC builds of such packages use 0x6000. Changing S_IFBLK to 0x6000 is an ABI break, but in the long term it should avoid bugs where apps assume that the value is 0x6000.[1] The underscore version _S_IFBLK perhaps could be removed, but this commit preserves it just in case something relies on it. [1] https://sourceforge.net/p/mingw-w64/mailman/message/59131760/ --- mingw-w64-headers/crt/sys/stat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mingw-w64-headers/crt/sys/stat.h b/mingw-w64-headers/crt/sys/stat.h index edbdbc11f..5b1cf4871 100644 --- a/mingw-w64-headers/crt/sys/stat.h +++ b/mingw-w64-headers/crt/sys/stat.h @@ -84,7 +84,7 @@ extern "C" { #endif #ifndef NO_OLDNAMES -#define _S_IFBLK 0x3000 /* Block: Is this ever set under w32? */ +#define _S_IFBLK 0x6000 /* mingw-w64 extension */ #define S_IFMT _S_IFMT #define S_IFDIR _S_IFDIR -- 2.48.1
_______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public