cwinapimingwmsys2stat

_wstat for extended-length path prefixed with \\?\ in MINGW64


Description

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.

How to reproduce

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.

Running the code

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.

Solution

  • 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.