No _stat or _stat64 return on System Volume Information file

Hey Folks, I'm getting a strange result. I've been using _stat and _stat64 (there are many variations on these functions, these are the only two I've tested) to get info on files. I can't get info on the file "C:\System Volume Information". _stat or _stat64 return -1, indicating an error. errno gets set to 2 in all cases, which corresponds to ENOENT, which is supposed to mean "No such file or directory." I beg to differ, lol. Here's the simplest demo code I could come up with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>


int main(int argc, char **argv)
{
	struct _stat stats;
	struct _stat64 stats2;

	printf_s("%d\n", _stat((char *)"C:\\System Volume Information", &stats));
	printf_s("%d\n", errno);

	printf_s("\n");

	printf_s("%d\n", _stat64((char *)"C:\\System Volume Information", &stats2));
	printf_s("%d\n", errno);

	return 0;
}


The output is always:

1
2
3
4
5
-1
2

-1
2


Among the things I've tried are: running the Command Prompt as Administrator, building for x64 rather than x86, building Release versions rather than Debug, and trying it on other Win10 computers (same results). I also checked it on the D: drive of my coding machine, since it has one. Same result. I tried to run it on my Win2008 server but the Win10 SDK appears not to allow this. I get "Application failed to start correctly".

Do any of you folks know what's going on?

TIA,

Lars
Whoops! Forgot to mention, I'm using Visual Studio Community 2017. My machine is running Win10 Pro x64.
Just for giggles, I ported the code to "ancient-spec" C++ and compiled it on Visual C/C++ 4.0. That code looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

//
// filetest.cpp
//

#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>


int main(int argc, char **argv)
{
	struct _stat stats;
    struct _stati64 stats2;

	printf("%d\n", _stat((char *)"C:\\System Volume Information", &stats));
	printf("%d\n", errno);

	printf("\n");

	printf("%d\n", _stati64((char *)"C:\\System Volume Information", &stats2));
	printf("%d\n", errno);

	return 0;
}



This code runs properly (that is, _stat and _stati64 return 0) and errno remains at 0. It runs on my Win2008 Server and all my Win10 boxes. Very curious.
That is odd.

I see that the working version has #include <stdlib.h>. You might try adding that. Also, usually symbols beginning with _ are reserved for the library. Do you have stat() and stat64() versions available?
dhayden: no, there are no stat or stat64 functions. Microsoft uses leading underscores (IMX) for non-standard features. I don't believe this is part of ANSI C or C++.

Thomas1965: I'm not trying to delete it or gain access to it. I'm wondering why my code fails to work. But thanks!
Last edited on
dhayden: forgot to mention that stdlib.h is necessary to define errno in VC/C++ 4. In VS2017 it's taken care of by other header files.
Last edited on
Epilogue: I've reported this to Microsoft, no word back yet.
forgot to mention that stdlib.h is necessary to define errno in VC/C++ 4.
If you want the most portable code, you should directly #include the header that the documentation says it's defined in, which is <cerrno> (or <errno.h> for C).

Well, while you wait for Microsoft...
What version of the Win10 SDK are you using, anyway?

And what happens when you run the same code but you use it with a different folder, such as a "normal" folder like C:\folder

Edit: I am able to reproduce the same issue in Visual Studio 2017.
Edit 2: "Normal" folders like the one above are handled successfully. So it is a special issue with "C:\System Volume Information", it appears.

I have found other GNU documents saying their version of stat also fails for special Windows folders like the one you're dealing with.
https://www.gnu.org/software/gnulib/manual/html_node/stat.html

_________________________________________________________

PS: What are you actually requiring these functions for?
If you are trying to get security attributes, you could use GetFileSecurity instead.
Last edited on
Ganado: VS2017 reports the SDK version as 10.0.17763.0. I haven't had problems except with Sytem Volume Information folders, but I haven't (for example) tried it on all the files on my C: drive.

That GNU doc is a good read, for example:

On MSVC 14, this function fails with error ENOENT on files such as ‘C:\pagefile.sys’ and on directories such as ‘C:\System Volume Information’.

Could very well be the same bug, not fixed as yet.

I had been using _findfirst and _findnext to get info on the files on a drive. Then I had a function called isdir(char *name) which called _stat to find if a given name was a folder. That started failing on the System Volume Information folders. That kinda stumped me, so I haven't done much more work on it.
I didn't look very deep, but if you can change it in isolation, a replacement for your stat call in isdir() would be to use GetFileAttributes.
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesa

You should be able to test the return value of the GetFileAttributes function, and bitwise-and it with FILE_ATTRIBUTE_DIRECTORY, but I didn't try this yet.
1
2
3
    if (fileAttributesResult & FILE_ATTRIBUTE_DIRECTORY) {
        printf("Directory ");
    } 
Ganado: Interesting notion, but I can't get it to work as a command-line program. The docs for GetFileAttributesA say you need both windows.h and fileapi.h, and when I include both I get a bunch of compiler errors, likely because it's not a proper windows program. But, I might try coding a minimal Windows program just to see if it works. Thanks!
Unlike the Win32 API/MS C Runtime C++17's <filesystem> doesn't at first glance appear to have problems with Windows protected system files/folders such as "System Volume Information" or "pagefile.sys." You might be able to duplicate what _stat() does using <filesystem>.

https://en.cppreference.com/w/cpp/filesystem

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <filesystem>

int main()
{
   for (auto& p : std::filesystem::directory_iterator("C:\\"))
   {
      std::cout << p.path() << '\n';
   }
}


I haven't used <filesystem> much so what it is a capable of doing I really can't say. Lack of experience.
Last edited on
Furry Guy: looking into this, thanks!
OK, I'm marking this as "solved" at this point as I don't think I'm likely to hear back from Microsoft. Thanks all!
Topic archived. No new replies allowed.