-1

我在用着:

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) 
        {
            ...
        }
    }
}

枚举计算机的所有 NTFS 分区。

它适用于我的 Windows 7、我尝试过的 Windows 8.1 以及 Windows 10 计算机。

但它在另一台 Windows 10 计算机上失败:在这台计算机上,卷C:diskInfo.PartitionType值等于0x00,而不是0x07( PARTITION_IFS)。

该值是(请参阅此处的文档):

PARTITION_ENTRY_UNUSED:0x00:未使用的条目分区。

这很奇怪,因为我可以确认,分区确实是 NTFS。

问题:

  • 众所周知,IOCTL_DISK_GET_PARTITION_INFO获取分区类型不是 100% 可靠吗?

  • 枚举所有 NTFS 卷的更可靠方法是什么?


注意:我还查看了 usingIOCTL_DISK_GET_PARTITION_INFO_EX而不是,IOCTL_DISK_GET_PARTITION_INFO但是结构PARTITION_INFORMATION_EX似乎没有提供有关的信息PartitionType,而结构PARTITION_INFORMATION确实提供了对PartitionType.

4

2 回答 2

1

感谢@RemyLebeau 的评论,我做了进一步的调查:

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

在失败的计算机(装有 Windows 10 的计算机)上。我发现它CreateFile成功了,但后来因为ieDeviceIoControl失败了(参见系统错误代码 (0-499))。GetLastError1ERROR_INVALID_FUNCTION

结论(我引用雷米的评论):

这意味着您传递给 DeviceIoControl() 的设备不支持 IOCTL_DISK_GET_PARTITION_INFO。

然后我尝试了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);

然后它起作用了。我可以看到那diskInfo.PartitionStylePARTITION_STYLE_GPT(=1),这就是IOCTL_DISK_GET_PARTITION_INFO失败的原因。我再次引用雷米的评论:

GPT 分区驱动器不支持 IOCTL_DISK_GET_PARTITION_INFO。

所以这是结论:

  • 使用IOCTL_DISK_GET_PARTITION_INFO_EX而不是IOCTL_DISK_GET_PARTITION_INFO

    • 如果diskInfo.PartitionStyle为 0 (PARTITION_STYLE_MBR),则可以测试 diskInfo.Mbr.PartitionType。如果是 0x07,则为 NTFS

    • 如果diskInfo.PartitionStyle为 1 (PARTITION_STYLE_GPT),则可以测试 diskInfo.Gpt.PartitionType,请参见此处:https ://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_partition_information_gpt 。即使NTFS 维基百科页面在 GPT 案例中提到了EBD0A0A2-B9E5-4433-87C0-68B6B72699C7NTFS 的 GUID,该 GUID 实际上与文件系统无关(请参阅下面的评论)。

  • 相反,它可能更容易使用GetVolumeInformation(),只需比较结果是否为"NTFS"字符串,就像在另一个答案中一样

  • 在我的特殊情况下,我最初想在尝试建立索引之前DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, ...)测试一个卷是否为 NTFS,因为我认为这种 MFT 查询将仅限于 NTFS 卷。事实上,一个更简单的解决方案是 NOT TEST 是否是 NTFS,然后只做FSCTL_ENUM_USN_DATA. 根据文档,可能发生的最坏情况是FSCTL_ENUM_USN_DATA失败并ERROR_INVALID_FUNCTION出现错误:

    “ERROR_INVALID_FUNCTION 指定卷上的文件系统不支持此控制代码。”

于 2019-03-20T22:20:42.467 回答
1

正如@RemyLebeau 所说,您没有检查每个调用的返回值。

PARTITION_ENTRY_UNUSED通常意味着DeviceIoControl()调用失败。这取决于您的用户的权限。您应该检查您的用户的访问权限,以查看它是否具有对 volume的FILE_READ_DATA权限(包含在 中) 。在我的测试环境中,如果您无法访问带有 的打开卷,则返回,然后也会失败。GENERIC_READC:C:GENERIC_READCreateFile()INVALID_HANDLE_VALUEDeviceIoControl()

编辑:

我建议使用GetVolumeInformation(),例如:

wchar_t fs[MAX_PATH + 1] = { 0 };
GetVolumeInformationW(L"C:\\", NULL, 0, NULL, NULL, NULL, fs, MAX_PATH + 1);

fs您将在缓冲区中看到类型信息。

于 2019-03-20T07:04:02.413 回答