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;
}