Skip to content
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

[filesystem] Don't error on weird system files #2715

Merged
merged 8 commits into from
May 17, 2022

Conversation

strega-nil-ms
Copy link
Contributor

@strega-nil-ms strega-nil-ms commented 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 #2370

This will require serious testing to make sure the behavior is the same.

Related issue in Rust: rust-lang/rust#96980

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 requested a review from a team as a code owner May 12, 2022 01:26
@StephanTLavavej StephanTLavavej added bug Something isn't working filesystem C++17 filesystem labels May 12, 2022
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
given the following program:

```cxx
#include <filesystem>
#include <stdio.h>

namespace fs = std::filesystem;

int wmain(int argc, wchar_t **argv)
{
    std::error_code ec;
    for (int i = 1; i < argc; ++i)
    {
        wprintf(L"exists(%ls): %ls\n", argv[i], fs::exists(argv[i], ec) ? L"true" : L"false");
        if (ec)
        {
            wprintf(L"  error: 0x%lX\n", ec.value());
        }
    }
}
```

before this change, the result of this program would be:

```
PS C:\..\nimazzuc\projects\stl-tests> .\exists.exe \\?\C:\hiberfil.sys
exists(\??\C:\hiberfil.sys): false
```

after this change,

```
PS C:\..\nimazzuc\projects\stl-tests> .\exists.exe \\?\C:\hiberfil.sys
exists(\\?\C:\hiberfil.sys): true
```
@StephanTLavavej StephanTLavavej self-assigned this May 12, 2022
Copy link
Member

@StephanTLavavej StephanTLavavej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just one more round of comments and I think this will be ready to go!

stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/inc/xfilesystem_abi.h Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
@fsb4000
Copy link
Contributor

fsb4000 commented May 13, 2022

I didn't test anything but I just had read a comment from the Rust issue:

Ok I tested with two users. For the sake of this example, I'll call them "Admin" and "User".

As Admin I created a directory and denied User all access. Within the directory I then created a "test.txt" file and granted User access to just that file.

As User, I tried using FindFirstFile to test if the file exists. This failed with ERROR_ACCESS_DENIED. I then tried using GetFileAttributes which succeeded. As does opening the file with CreateFile,

Thus FindFirstFile can fail in situations where directly accessing the file would succeed.

rust-lang/rust#96980 (comment)

so I decided to copy the comment for those who didn't follow the link

@ChrisDenton
Copy link

While I think the two user scenario is more realistic, you can get the same outcome by simply denying yourself list folder permissions on the file's parent directory. This is simpler to test.

this fixes the obvious bug of
`FindFirstFileW(directory-we-dont-have-access-to/file-we-do)`
that I didn't notice when implementing.
This instead GetFileAttributesExW, followed by FindFirstFileW if that
fails with ERROR_SHARING_VIOLATION.

The change:

Let testdir be a directory where the current user doesn't have list
permissions; let testdir/testfile.txt be a file which the current user
_does_ have permissions on.

Then, FindFirstFileW(L"testdir/testfile.txt") will result in
ERROR_ACCESS_DENIED, but GetFileAttributesExW(L"testdir/testfile.txt")
will succeed.
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
stl/src/filesystem.cpp Outdated Show resolved Hide resolved
@StephanTLavavej
Copy link
Member

@strega-nil-ms I pushed a conflict-free merge with main (as filesystem.cpp had changed), followed by minor changes for @miscco's feedback (detaching comments) and mine (limiting variable scope), followed by a correctness fix. I then verified that your branch fixes the originally reported bug:

hiberfil.sys size

This remained unchanged throughout testing:

C:\Temp>dir /ah C:\hiberfil.sys
[...]
05/11/2022  03:32 AM    13,648,355,328 hiberfil.sys

Test code

C:\Temp>type meow.cpp
#include <filesystem>
#include <iostream>
using namespace std;
using namespace std::filesystem;

int main() {
    try {
        const auto bytes = file_size(LR"(C:\hiberfil.sys)");
        cout << "hiberfil.sys size: " << bytes << endl;
    } catch (const filesystem_error& e) {
        cout << "filesystem_error: " << e.what() << endl;
    }
}

Current behavior of main

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 meow.cpp && meow
meow.cpp
filesystem_error: file_size: The process cannot access the file because it is being used by another process.: "C:\hiberfil.sys"

Before final correctness fix

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 meow.cpp && meow
meow.cpp
hiberfil.sys size: 12884901891
  • 13648355328 is 0x3'2D81'6000
  • 12884901891 is 0x3'0000'0003

After final correctness fix

C:\Temp>cl /EHsc /nologo /W4 /std:c++17 meow.cpp && meow
meow.cpp
hiberfil.sys size: 13648355328

With this manual testing, and your new "fallback" approach that's activated only when the original codepath fails, I think this is ready to ship. (Entirely replacing the original codepath would be much riskier and require more extensive testing.)

@StephanTLavavej StephanTLavavej self-assigned this May 16, 2022
@StephanTLavavej
Copy link
Member

I'm mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed.

StephanTLavavej added a commit to StephanTLavavej/STL that referenced this pull request May 16, 2022
@StephanTLavavej StephanTLavavej merged commit 1134982 into microsoft:main May 17, 2022
@StephanTLavavej
Copy link
Member

Thanks for investigating and fixing this bug affecting hiberfil.sys and more!

🐞 🔍 🐻

@strega-nil strega-nil deleted the fix-2370 branch August 10, 2022 20:35
fsb4000 pushed a commit to fsb4000/STL that referenced this pull request Aug 13, 2022
Co-authored-by: nicole mazzuca <mazzucan@outlook.com>
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

<filesystem>: filesystem::exists returns false for c:\hiberfil.sys
9 participants