Перечислите все разделы и проверьте, являются ли они NTFS - PullRequest
0 голосов
/ 20 марта 2019

Я использую:

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.

Ответы [ 2 ]

1 голос
/ 21 марта 2019

Я провел дополнительное расследование благодаря комментариям @ 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) ).

Заключение (цитирую комментарий Реми):

Это означает, что IOCTL_DISK_GET_PARTITION_INFO не поддерживается устройством, которое вы передали в DeviceIoControl ().

Я тогда попробовал с 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 потерпел неудачу. Я цитирую комментарий Реми снова:

IOCTL_DISK_GET_PARTITION_INFO не поддерживается на многораздельных дисках GPT.

Итак, вот вывод:

  • используйте IOCTL_DISK_GET_PARTITION_INFO_EX вместо IOCTL_DISK_GET_PARTITION_INFO

  • вероятно, вместо этого проще использовать GetVolumeInformation() и просто сравнить, если в результате получается строка "NTFS", как в другом ответе

  • в моем конкретном случае я изначально хотел проверить, является ли том NTFS или нет , прежде чем попытается выполнить индексацию с помощью DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, ...), потому что я думал, что такие запросы MFT будут ограничены томами NTFS. На самом деле, более простым решением было бы НЕ ИСПЫТАТЬ, если это NTFS или нет , и просто выполнить FSCTL_ENUM_USN_DATA. Худшее, что может случиться, это то, что FSCTL_ENUM_USN_DATA завершается с ошибкой ERROR_INVALID_FUNCTION, согласно документации:

    "ERROR_INVALID_FUNCTION Файловая система на указанном томе не поддерживает этот управляющий код."

1 голос
/ 20 марта 2019

Как говорит @RemyLebeau, вы не проверяете возвращаемое значение для каждого вызова.

PARTITION_ENTRY_UNUSED часто означает, что вызов DeviceIoControl() не выполнен. Это зависит от разрешений вашего пользователя. Вам следует проверить права доступа вашего пользователя, чтобы узнать, имеет ли он разрешение FILE_READ_DATA (включено в GENERIC_READ) на томе C:. В моей тестовой среде, если у вас нет доступа к открытому тому C: с GENERIC_READ, CreateFile() возвращает INVALID_HANDLE_VALUE, а затем DeviceIoControl() также дает сбой.

EDIT:

Я предлагаю использовать GetVolumeInformation(), например:

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

И вы увидите информацию о типе в буфере fs.

...