Skip to content

<filesystem>: filesystem::exists returns false for c:\hiberfil.sys #2370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
StephanTLavavej opened this issue Dec 1, 2021 Discussed in #2365 · 3 comments · Fixed by #2715
Closed

<filesystem>: filesystem::exists returns false for c:\hiberfil.sys #2370

StephanTLavavej opened this issue Dec 1, 2021 Discussed in #2365 · 3 comments · Fixed by #2715
Labels
bug Something isn't working filesystem C++17 filesystem fixed Something works now, yay!

Comments

@StephanTLavavej
Copy link
Member

Discussed in #2365

Originally posted by s-kipnis November 29, 2021
This behavior is at least strange. The file does exist, but has quite limited permissions.
Is it bug or side effect of Win32 API?


We need to look at all of the filesystem operation functions and determine what level of accurate answers we can provide for various questions.

@StephanTLavavej StephanTLavavej added the bug Something isn't working label Dec 1, 2021
@fsb4000
Copy link
Contributor

fsb4000 commented Dec 7, 2021

@MahmoudGSaleh MahmoudGSaleh added the filesystem C++17 filesystem label May 4, 2022
@strega-nil-ms
Copy link
Contributor

strega-nil-ms commented May 12, 2022

Results of investigation:

First, I created the following program for testing:

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int wmain(int argc, wchar_t** argv) {
    if (argc < 2) {
        std::wcerr << L"Not enough arguments\n";
        return 1;
    }
    std::error_code ec;

    for (int i = 1; i < argc; ++i) {
        std::wcout << L"on file: " << argv[i] << L'\n';
        (void) fs::exists(argv[i], ec);
        std::cout << "  exists: ";
        if (ec) {
            std::cout << "error: " << ec.message() << '\n';
        } else {
            std::cout << "no error\n";
        }

        (void) fs::symlink_status(argv[i], ec);
        std::cout << "  symlink_status: ";
        if (ec) {
            std::cout << "error: " << ec.message() << '\n';
        } else {
            std::cout << "no error\n";
        }

        (void) fs::status(argv[i], ec);
        std::cout << "  status: ";
        if (ec) {
            std::cout << "error: " << ec.message() << '\n';
        } else {
            std::cout << "no error\n";
        }
    }
}

For .\test.exe C:\hiberfil.sys C:\not-exists we get the following result:

on file: C:\hiberfil.sys
  exists: error: The process cannot access the file because it is being used by another process.
  symlink_status: error: The process cannot access the file because it is being used by another process.
  status: error: The process cannot access the file because it is being used by another process.
on file: C:\not-exists
  exists: no error
  symlink_status: error: The system cannot find the file specified.
  status: error: The system cannot find the file specified.

I will also note the following files act the same as C:\hiberfil.sys:

  • C:\DumpStack.log.tmp
  • C:\pagefile.sys
  • C:\swapfile.sys

Investigation

I had a few thoughts on why this would be; here are the results of my investigation:

  1. Is it because they're hidden?
    • no, attempting to do this with a local hidden file is fine
  2. Is it because they're files on the root of the drive?
    • no, doing this with a normal file that's at the root of the drive still works
  3. Is it because the permissions don't allow anything?
    • no, removing all access to a file that's at the root of the drive still works
  4. Is it because they're weird system files?
    • well, maybe, but status(C:\$Recycle.Bin) still works
  5. Is it because the file is opened by another process with dwShareMode = 0?
    • no, status(locked-file) succeeds

Given this, I'm not sure what's special about these four files.

How do other programs treat these files

Shells - PowerShell and CMD

PowerShell:

PS C:\..\projects\stl\testdir> Get-ChildItem C:\ -Hidden

    Directory: C:\

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d--hs           4/25/2022  9:23 PM                $Recycle.Bin
d--h-           4/25/2022 10:51 AM                $WinREAgent
l--hs           4/25/2022 10:36 AM                Documents and Settings -> C:\Users
d--h-           4/25/2022 11:32 AM                ProgramData
d--hs            5/2/2022  4:13 PM                Recovery
d--hs           4/25/2022 12:14 PM                System Volume Information
-a-hs           4/26/2022  9:34 AM          12288 DumpStack.log.tmp
-a-hs           5/11/2022  2:46 PM     2574749696 hiberfil.sys
-a-hs           5/11/2022  2:55 PM     2254000128 pagefile.sys
-a-hs           4/26/2022  9:34 AM       16777216 swapfile.sys

PS C:\..\projects\stl\testdir> Get-Item C:\hiberfil.sys -Force

    Directory: C:\

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a-hs           5/11/2022  2:46 PM     2574749696 hiberfil.sys

CMD:

C:\Users\nimazzuc\projects\stl\testdir>dir C:\ /AH
 Volume in drive C has no label.
 Volume Serial Number is 08E0-EC41

 Directory of C:\

04/25/2022  09:23 PM    <DIR>          $Recycle.Bin
04/25/2022  10:51 AM    <DIR>          $WinREAgent
04/25/2022  10:36 AM    <JUNCTION>     Documents and Settings [C:\Users]
04/26/2022  09:34 AM            12,288 DumpStack.log.tmp
05/11/2022  02:46 PM     2,574,749,696 hiberfil.sys
05/11/2022  02:55 PM     2,254,000,128 pagefile.sys
04/25/2022  11:32 AM    <DIR>          ProgramData
05/02/2022  04:13 PM    <DIR>          Recovery
04/26/2022  09:34 AM        16,777,216 swapfile.sys
04/25/2022  12:14 PM    <DIR>          System Volume Information
               4 File(s)  4,845,539,328 bytes
               6 Dir(s)  119,394,340,864 bytes free

C:\Users\nimazzuc\projects\stl\testdir>dir C:\hiberfil.sys /AH
 Volume in drive C has no label.
 Volume Serial Number is 08E0-EC41

 Directory of C:\

05/11/2022  02:46 PM     2,574,749,696 hiberfil.sys
               1 File(s)  2,574,749,696 bytes
               0 Dir(s)  119,393,341,440 bytes free

It seems like shells treat these as normal hidden files here.

Rust std::fs

Rust explicitly says that exists() calls metadata, and returns false for errors. metadata returns an error, thus Rust's std::fs has the same behavior as C++'s and exists() returns false.

Raw Win32 C++

  • GetFileAttributesExW on C:\hiberfil.sys gives error code 32 ("The process cannot access the file because it is being used by another process.")
  • GetFileAttributesW on C:\hiberfil.sys gives the same
  • FindFirstFileW on C:\hiberfil.sys gives no error, finds the file, and returns the correct attributes.
    • This means that we could use FindFirstFileW to get the attributes.

Results

For some reason, GetFileAttributesW and GetFileAttributesExW give errors, but FindFirstFileW does not, and gives us the information that we need. This is... at least a little concerning.

Given that FindFirstFileW additionally has the globbing behavior, I'm not sure what the correct choice is. Poking @BillyONeal for his feedback.

@BillyONeal
Copy link
Member

Given that the c++ spec says that exists must be implemented in terms of status, I think the correct behavior is unfortunately like rust's. :(

strega-nil-ms pushed a commit to strega-nil/stl that referenced this issue May 12, 2022
This changes from using GetFileAttributesExW to FindFirstFileW,
since FindFirstFileW gets the information from the directory
and thus doesn't error out.

Fixes microsoft#2370

This will require serious testing to make sure the behavior is the same.
strega-nil-ms pushed a commit to strega-nil/stl that referenced this issue May 12, 2022
This changes from using GetFileAttributesExW to FindFirstFileW,
since FindFirstFileW gets the information from the directory
and thus doesn't error out.

Fixes microsoft#2370

This will require serious testing to make sure the behavior is the same.
@strega-nil-ms strega-nil-ms self-assigned this May 12, 2022
@StephanTLavavej StephanTLavavej added the fixed Something works now, yay! label May 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working filesystem C++17 filesystem fixed Something works now, yay!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants