Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine whether a file or folder is on SSD or a hard drive?

How to programmatically determine in C or C++ whether a specified path is on a flash (SSD) drive or a magnetic hard drive? I'm only interested in fixed drives, not removable ones, although it will be nice to determine the type of a removable drive as well.

I'm looking for a solution that queries what Windows thinks of the specified path and the physical drive it's on. No benchmarking! Also note that looking for TRIM support is not a valid approach thanks to the SMR HDDs.

like image 914
Violet Giraffe Avatar asked Jun 20 '18 11:06

Violet Giraffe


1 Answers

From Old New Thing article: How can I tell whether a file is on an SSD?

This takes advantage of the trick we learned last time where you can make a storage query against a volume, and it will report the answer if the volume has a single extent.

We aren’t so much checking whether it’s on an SSD drive as we are checking whether seeks are free. That is true for SSDs, but it’s also true for RAM drives. But RAM drives are even faster than SSDs, so I think it’s okay to treat them as “super-awesome SSDs”...

This is a slightly modified version which doesn't need wil::unique_hfile class in the original article.

This implementation does not throw if path is invalid, it will report non-SSD for invalid path or network path.

#include <iostream>
#include <Windows.h>

HANDLE GetVolumeHandleForFile(const wchar_t* filePath)
{
    wchar_t volume_path[MAX_PATH];
    if (!GetVolumePathName(filePath, volume_path, ARRAYSIZE(volume_path)))
        return nullptr;

    wchar_t volume_name[MAX_PATH];
    if (!GetVolumeNameForVolumeMountPoint(volume_path,
        volume_name, ARRAYSIZE(volume_name)))
        return nullptr;

    auto length = wcslen(volume_name);
    if (length && volume_name[length - 1] == L'\\')
        volume_name[length - 1] = L'\0';

    return CreateFile(volume_name, 0,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
}

bool IsFileOnSsd(const wchar_t* file_path)
{
    bool is_ssd{ false };
    HANDLE volume = GetVolumeHandleForFile(file_path);
    if (volume == INVALID_HANDLE_VALUE)
    { return false; /*invalid path! throw?*/ }

    STORAGE_PROPERTY_QUERY query{};
    query.PropertyId = StorageDeviceSeekPenaltyProperty;
    query.QueryType = PropertyStandardQuery;
    DWORD count;
    DEVICE_SEEK_PENALTY_DESCRIPTOR result{};
    if (DeviceIoControl(volume, IOCTL_STORAGE_QUERY_PROPERTY,
        &query, sizeof(query), &result, sizeof(result), &count, nullptr))
    { is_ssd = !result.IncursSeekPenalty; }
    else { /*fails for network path, etc*/ }
    CloseHandle(volume);
    return is_ssd;
}

int main()
{
    std::wcout << IsFileOnSsd(L"C:\\") << "\n";
    std::wcout << IsFileOnSsd(L"D:\\") << "\n";
    return 0;
}
like image 54
Barmak Shemirani Avatar answered Sep 25 '22 15:09

Barmak Shemirani