I have a C program that needs to check if a file exists using stat. That file can have a path longer than MAX_PATH
(260 characters) and is therefore prefixed with \\?\
, see Windows documentation.
Also special characters are allowed, so it is using wide characters wchar_t*
instead of char*
.
When compiling the C program with MSVC 19 _wstat
can find the file \\?\D:\path\to\test.txt
(an empty text file).
But when compiling the same program with MING64 _wstat
is failing and the file can't be found.
main.c
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <wchar.h>
int main(void) {
//wchar_t* unicodeLongFileName = L"D:\\path\\to\\test.txt"; // Works fine
wchar_t* unicodeLongFileName = L"\\\\?\\D:\\path\\to\\test.txt"; // Broken in MSYS2
struct _stat statbuf;
int res = _wstat(unicodeLongFileName, &statbuf);
if (res != 0) {
perror( "Problem getting information" );
switch (errno)
{
case ENOENT:
wprintf(L"File \n%ls\n not found.\n", unicodeLongFileName);
break;
case EINVAL:
printf("Invalid parameter to _stat.\n");
break;
default:
/* Should never be reached. */
printf("Unexpected error in _stat.\n");
}
return -1;
}
wprintf(L"Found file \n%ls\n.\n", unicodeLongFileName);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(Test_wstat)
add_executable(Test_wstat main.c)
Compile the MSVC version with:
cmake -S . -B build_msvc
cmake --build build_msvc/ --config Release
and the MSYS2 version with:
$ cmake -S . -B build_mingw -G "MSYS Makefiles" -DCMAKE_C_COMPILER=gcc -Wno-dev
$ make -C build_mingw/ all -Oline
This is using gcc 12.2 from MINGW64 (MINGW64_NT-10.0-22621 version 3.3.4-341.x86_64) on Windows 11.
Create a new text file
$ touch /d/path/to/test.txt
and then run the programs
> ./build_msvc/Release/Test_wstat.exe
Found file
\\?\D:\workspace\Testitesttest\issue-10898\test_c_program\test.txt
$ ./build_mingw/Test_wstat.exe
Problem getting information: No such file or directory
File
\\?\D:\path\to\test.txt
not found.
The issue is that there are two variants of the C runtime on Windows. Both implement the_wstat
function, but they differ in functionality.
While Visual Studio links to the newer UCRT (Universal C Runtime) the MINGW64 environment links to MSVCRT (Microsoft Visual C++ Runtime) which is older and missing the needed features to handle \\?\
.
But I guess the answer to my original question is, that it's not possible to handle \\?\
using _wstat
in MINGW64.
One could use other functions to test if a file exists (@RbMm suggested GetFileAttributesW
and RtlDoesFileExists_U
).
The solution for my specific case is to switch to the UCRT64 environment of MSYS2 which links to the UCRT.