枚举所有分区并测试它们是否为NTFS

时间:2019-03-20 00:16:49

标签: c++ windows winapi ntfs ntfs-mft

我正在使用:

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:的{​​{1}}值等于diskInfo.PartitionType,而不是0x00({{1 }}。

此值为(请参见doc here):

  

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

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

问题:

  • 是否众所周知0x07并非100%可靠地获得分区类型?

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


注意:我还研究了使用IOCTL_DISK_GET_PARTITION_INFO_EX而不是PARTITION_IFS,但是结构PARTITION_INFORMATION_EX似乎没有提供有关IOCTL_DISK_GET_PARTITION_INFO的信息,而结构{{3 }}确实可以访问PARTITION_INFORMATION

2 个答案:

答案 0 :(得分:1)

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

<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery.bootstrapvalidator/0.5.0/css/bootstrapValidator.min.css" rel="stylesheet" /> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css" rel="stylesheet" /> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-validator/0.4.5/js/bootstrapvalidator.min.js"></script> <form class="well form-horizontal" action=" " method="post" id="contact_form"> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">First Name</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span> <input name="first_name" placeholder="First Name" class="form-control" type="text"> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">Last Name</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span> <input name="last_name" placeholder="Last Name" class="form-control" type="text"> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">E-Mail</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-envelope"></i></span> <input name="email" placeholder="E-Mail Address" class="form-control" type="text"> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">Phone #</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-earphone"></i></span> <input name="phone" placeholder="(845)555-1212" class="form-control" type="text"> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">Address</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-home"></i></span> <input name="address" placeholder="Address" class="form-control" type="text"> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">City</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-home"></i></span> <input name="city" placeholder="city" class="form-control" type="text"> </div> </div> </div> <!-- Select Basic --> <div class="form-group"> <label class="col-md-4 control-label">State</label> <div class="col-md-4 selectContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-list"></i></span> <select name="state" class="form-control selectpicker"> <option value=" ">Please select your state</option> <option>Alabama</option> <option>Alaska</option> </select> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">Zip Code</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-home"></i></span> <input name="zip" placeholder="Zip Code" class="form-control" type="text"> </div> </div> </div> <!-- Text input--> <div class="form-group"> <label class="col-md-4 control-label">Website or domain name</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-globe"></i></span> <input name="website" placeholder="Website or domain name" class="form-control" type="text"> </div> </div> </div> <!-- radio checks --> <div class="form-group"> <label class="col-md-4 control-label">Do you have hosting?</label> <div class="col-md-4"> <div class="radio"> <label> <input type="radio" name="hosting" value="yes" /> Yes </label> </div> <div class="radio"> <label> <input type="radio" name="hosting" value="no" /> No </label> </div> </div> </div> <!-- Text area --> <div class="form-group"> <label class="col-md-4 control-label">Project Description</label> <div class="col-md-4 inputGroupContainer"> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-pencil"></i></span> <textarea class="form-control" name="comment" placeholder="Project Description"></textarea> </div> </div> </div> <!-- Success message --> <div class="alert alert-success" role="alert" id="success_message">Success <i class="glyphicon glyphicon-thumbs-up"></i> Thanks for contacting us, we will get back to you shortly.</div> <!-- Button --> <div class="form-group"> <label class="col-md-4 control-label"></label> <div class="col-md-4"> <button type="submit" class="btn btn-warning">Send <span class="glyphicon glyphicon-send"></span></button> </div> </div> </fieldset> </form>通常意味着PARTITION_ENTRY_UNUSED调用失败。这取决于用户的权限。您应该检查用户的访问权限,以查看它是否具有卷DeviceIoControl()上的FILE_READ_DATA权限(包含在GENERIC_READ中)。在我的测试环境中,如果您无法使用C:访问打开卷C:,则GENERIC_READ返回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); 缓冲区中看到类型信息。

答案 1 :(得分: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成功了,但随后DeviceIoControl失败了,而GetLastError1,即ERROR_INVALID_FUNCTION(请参阅System Error Codes (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.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

  • 使用GetVolumeInformation()可能更容易,并且只比较结果是否为"NTFS"字符串,如other answer

  • 在我的特定情况下,我最初想在尝试使用DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, ...)进行索引之前 测试卷是否为NTFS,因为我认为这样的MFT查询仅限于NTFS卷。实际上,更简单的解决方案是不要测试是否为NTFS ,而只需执行FSCTL_ENUM_USN_DATA。根据文档,可能发生的最坏情况是FSCTL_ENUM_USN_DATA失败,并出现ERROR_INVALID_FUNCTION错误:

      

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