枚举所有分区并测试它们是否为 NTFS
Enumerate all partitions and test if they are NTFS
我正在使用:
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 卷的更可靠方法是什么?
注意:我也考虑了使用IOCTL_DISK_GET_PARTITION_INFO_EX
而不是IOCTL_DISK_GET_PARTITION_INFO
但是结构PARTITION_INFORMATION_EX
似乎没有提供有关PartitionType
的信息,而结构PARTITION_INFORMATION
确实可以访问PartitionType
。
由于@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
成功了,但后来DeviceIoControl
失败了,GetLastError
被1
即ERROR_INVALID_FUNCTION
(请参阅系统错误代码 (0-499))。
结论(我引用雷米的评论):
这意味着您传递给 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.PartitionStyle
是PARTITION_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://learn.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_partition_information_gpt。即使 NTFS 维基百科页面在 GPT 案例中提到了 NTFS 的 GUIDEBD0A0A2-B9E5-4433-87C0-68B6B72699C7
,此 GUID 实际上与文件系统无关(请参阅下面的评论)。
使用
GetVolumeInformation()
可能更容易,只需比较结果是否是"NTFS"
字符串,如另一个答案在我的特定情况下,我最初想在尝试使用
DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, ...)
进行索引之前测试卷是否为 NTFS,因为我认为此类 MFT 查询仅限于 NTFS 卷。实际上,更简单的解决方案是不测试它是否是NTFS,而只是执行FSCTL_ENUM_USN_DATA
。根据文档,可能发生的最糟糕的情况是FSCTL_ENUM_USN_DATA
失败并出现ERROR_INVALID_FUNCTION
错误:"ERROR_INVALID_FUNCTION指定卷上的文件系统不支持此控制代码。">
正如@RemyLebeau所说,您没有检查每个调用的返回值。
PARTITION_ENTRY_UNUSED
通常意味着DeviceIoControl()
调用失败。这取决于用户的权限。您应该检查用户的访问权限,以查看它是否具有卷C:
的FILE_READ_DATA
权限(包含在GENERIC_READ
中)。在我的测试环境中,如果您无法访问带有GENERIC_READ
的打开卷C:
,CreateFile()
返回INVALID_HANDLE_VALUE
,然后DeviceIoControl()
也会失败。
编辑:
我建议使用GetVolumeInformation()
,例如:
wchar_t fs[MAX_PATH + 1] = { 0 };
GetVolumeInformationW(L"C:\", NULL, 0, NULL, NULL, NULL, fs, MAX_PATH + 1);
您将在fs
缓冲区中看到类型信息。
- 在提升multi_index容器中,是否定义了"default index"?
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 检查输入是否不是整数或数字
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 此代码是否违反一个定义规则
- 是否需要删除包含对象的"pair"?
- 是否可以从int转换为enum类类型
- 无论条件是否为true,if总是在c++中执行
- 如何找到大小'x'数组是否完全填充,在C++?
- 检查值是否在集合p1和p2中,但不在p3中
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- C/C++预处理器是否可以检测一些编译器选项
- 枚举所有分区并测试它们是否为 NTFS