c++windowswinapintfsntfs-mft

Enumerate all partitions and test if they are NTFS


I'm using:

DWORD d = GetLogicalDrives();
for (int i = 0; i < 26; i++)
{
    if ((1 << i) & d) // drive letter 'A' + i present on computer
    {
        wstring s = std::wstring(L"\\\\.\\") + wchar_t('A' + i) + L":";

        PARTITION_INFORMATION diskInfo;
        DWORD dwResult;
        HANDLE dev = CreateFile(LPWSTR(s.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
        DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &diskInfo, sizeof(diskInfo), &dwResult, NULL);
        CloseHandle(dev);
        if (diskInfo.PartitionType == PARTITION_IFS) 
        {
            ...
        }
    }
}

to enumerate all NTFS partitions of a computer.

It works on my Windows 7, on a Windows 8.1 I tried it on, and on a Windows 10 computer.

But it fails on another Windows 10 computer: on this one, the volume C: has a diskInfo.PartitionType value equal to 0x00, instead of 0x07 (PARTITION_IFS).

This value is (see the doc here):

PARTITION_ENTRY_UNUSED : 0x00 : An unused entry partition.

This is strange, since, I can confirm, the partition is really NTFS.

Questions:


Note: I also looked at using IOCTL_DISK_GET_PARTITION_INFO_EX instead of IOCTL_DISK_GET_PARTITION_INFO but then the structure PARTITION_INFORMATION_EX does not seem to give informations about PartitionType, whereas the structure PARTITION_INFORMATION does give access to PartitionType.


Solution

  • I did further investigation thanks to @RemyLebeau's comments with:

    HANDLE dev = CreateFile(..., GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
    
    if (dev == INVALID_HANDLE_VALUE) 
    { 
        DWORD err = GetLastError();  // then MessageBox       
    } 
    else
    { 
        BOOL ret = DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &diskInfo, sizeof(diskInfo), &dwResult, NULL);
    
        if (ret == FALSE) 
        { 
            DWORD err = GetLastError();  // then MessageBox
        } 
        CloseHandle(dev); 
    } 
    

    on the computer where it failed (computer with Windows 10). I found that CreateFile succeeded but then DeviceIoControl failed with GetLastError being 1 i.e. ERROR_INVALID_FUNCTION (see System Error Codes (0-499)).

    Conclusion (I quote Remy's comment):

    That means IOCTL_DISK_GET_PARTITION_INFO is not supported by the device you passed to DeviceIoControl().

    I then tried with IOCTL_DISK_GET_PARTITION_INFO_EX:

    PARTITION_INFORMATION_EX diskInfo;
    BOOL ret = DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &diskInfo, sizeof(diskInfo), &lpBytesReturned, NULL);
    

    and then it worked. I could see that diskInfo.PartitionStyle was PARTITION_STYLE_GPT (=1), and this was the reason why IOCTL_DISK_GET_PARTITION_INFO failed. I quote Remy's comment again:

    IOCTL_DISK_GET_PARTITION_INFO is not supported on GPT partitioned drives.

    So here's the conclusion: