Home > database >  How to check if a read-only file exists
How to check if a read-only file exists

Time:01-30

I'm looking for a way to check for a read-only file's existence without opening it. I've tried:

if (std::filesystem::exists("C:\\Windows\\System32\\hal.dll")) {
    std::cout << "Exists" << std::endl;
}
else {
    std::cout << "Does not exist" << std::endl;
}

But it returns "does not exist". I'm looking for a solution that can check the existence of files like these.

CodePudding user response:

std::filesystem::exists() works fine. But, you might not be querying the file you are expecting.

First, not everyone installs Windows at C:\Windows, so you should ask the OS where it is actually installed, by using GetWindowsDirectory(), SHGetFolderPath(CSIDL_WINDOWS), or SHGetKnownFolderPath(FOLDERID_Windows), eg:

namespace fs = std::filesystem;

fs::path getWindowsPath() {
    WCHAR szPath[MAX_PATH] = {};
    GetWindowsDirectoryW(szPath, MAX_PATH);
    return szPath;

    // or equivalent...
} 

Second, on 64-bit Windows systems, if a 32-bit app running inside the WOW64 emulator tries to access the 64-bit %WINDIR%\System32 folder, by default the access will get redirected to the 32-bit %WINDIR%\SysWOW64 folder instead, which could explain why your exists() check is not working.

To access the 64-bit System32 folder when running under WOW64, you have to either:

  • use the special SysNative alias, eg:
bool isWow64() {
    #ifdef _WIN64
    return false;
    #else
    BOOL bIsWow64 = FALSE;
    return IsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64;
    #endif
}

fs::path getSystemPath() {
    if (isWow64()) {
        return getWindowsPath() / "SysNative";
    }
    else {
        return getWindowsPath() / "System32";

        /* alternatively:

        WCHAR szPath[MAX_PATH] = {};
        GetSystemDirectoryW(szPath, MAX_PATH);
        return szPath;

        or equivalent...
        */
    }
}

...

if (std::filesystem::exists(getSystemPath() / "hal.dll")) {
    std::cout << "Exists" << std::endl;
}
else {
    std::cout << "Does not exist" << std::endl;
}
fs::path getSystemPath() {
    return getWindowsPath() / "System32";
    // or equivalent ...
}

...

PVOID oldValue = NULL;
if (isWow64()) {
    Wow64DisableWow64FsRedirection(&oldValue);
}

if (std::filesystem::exists(getSystemPath() / "hal.dll")) {
    std::cout << "Exists" << std::endl;
}
else {
    std::cout << "Does not exist" << std::endl;
}

if (isWow64()) {
    Wow64RevertWow64FsRedirection(oldValue);
}

See File System Redirector on MSDN for more details.

CodePudding user response:

If in Windows, function GetFileAttributes returns attributes if the file is there without opening. On error, it returns INVALID_FILE_ATTRIBUTES and then you can check with GetLastError().

If you are checking in order to open it later, this can lead to a race condition (TOCTOU bug as mentioned).

Besides that, there do exist reasons to check for the file existance without planning to open it, for example for an installer to see if the file to be replaced is there and warn the user.

  • Related