Win32: Доступ к разделу за пределами тома? - PullRequest
0 голосов
/ 12 января 2019

Можно открыть том диска в виде файла с помощью вызова функции, подобного

HANDLE hDisk = CreateFile("\\\\.\\G:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, 0, NULL);

Однако, это разрешает доступ только к области раздела, занятой томом - которая может быть не всей.

Можно ли, учитывая букву диска тома, открыть дескриптор всего раздела? Истинный размер раздела можно вычислить, вызвав DeviceIoControl(...IOCTL_GET_DRIVE_GEOMETRY...) на дескрипторе тома, но чтение / запись после конца тома не работают.

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Я нашел то, что представляется мне более простым решением для моего варианта использования: управляющий код FSCTL_ALLOW_EXTENDED_DASD_IO снимает ограничение на дескриптор тома, предоставляя доступ к секторам раздела вне файловой системы. Таким образом, помимо проверки ошибок, это дополнение к моему коду в одну строку:

DeviceIoControl(hDisk, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwBytesRead, NULL);
0 голосов
/ 12 января 2019

существуют различные объекты устройства для всего диска (fdo) и для разделов (pdo) на нем. первое созданное устройство для всего диска. имеет канонический формат имени

#define FDO_NAME_FORMAT "\\Device\\Harddisk%d\\DR%d"

для него созданы также известные символические ссылки

"\\Device\\Harddisk%d\\Partition0"
"\\DosDevices\\PhysicalDrive%d"

тогда уже, если диск отформатирован и на нем существуют разделы - создаются дополнительные тома устройства (pdo). родное название этого устройства имеет вид

"\\Device\\HarddiskVolume%d"

и хорошо известный формат символических ссылок для разделов -

"\\Device\\HarddiskX\\PartitionY" 

, где X то же самое, что и для всего диска, и Y всегда не 0. Таким образом, дисковое устройство имеет \Device\HarddiskX\DRX или \Device\HarddiskX\Partition0 или \DosDevices\PhysicalDriveX, а разделы для этого диска имеют имена \Device\HarddiskX\PartitionY (символическая ссылка до \Device\HarddiskVolume%d). когда том смонтирован - менеджер монтирования может назначить букву устройству, например \\\?\c:, но это только символическая ссылка на некоторое устройство тома.

Можно ли, учитывая букву диска тома, открыть ручку на весь раздел?

да. правильнее сказать дескриптор всего диска (или раздела 0). мы можем отправить IOCTL_STORAGE_GET_DEVICE_NUMBER на том устройства и использовать DeviceNumber из STORAGE_DEVICE_NUMBER, чтобы создать имя диска ("\\\\?\\PhysicalDrive%d"), на котором этот раздел находится. поэтому код может выглядеть как

ULONG dv(PCWSTR VolumeName)
{
    HANDLE hFile = CreateFile(VolumeName, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);

    if (hFile == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    union {
        STORAGE_DEVICE_NUMBER sdn;
        DISK_GEOMETRY_EX dg;
    };

    OVERLAPPED ov = {};

    ULONG dwError = DeviceIoControl(hFile, IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, &sdn, sizeof(sdn), 0, &ov)
        ? NOERROR : GetLastError();

    CloseHandle(hFile);

    if (dwError == NOERROR)
    {
        WCHAR name[32];
        swprintf(name, L"\\\\?\\PhysicalDrive%d", sdn.DeviceNumber);

        hFile = CreateFile(name, FILE_GENERIC_READ, 
            FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);

        if (hFile != INVALID_HANDLE_VALUE)
        {
            if (DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 0, 0, &dg, sizeof(dg), 0, &ov))
            {
                FILE_ALIGNMENT_INFO fai;
                if (GetFileInformationByHandleEx(hFile, FileAlignmentInfo, &fai, sizeof(fai)))
                {
                    if (fai.AlignmentRequirement < 2*sizeof(void*))
                    {
                        fai.AlignmentRequirement = 0;
                    }

                    ULONG_PTR a = fai.AlignmentRequirement;

                    if (PVOID buf = _malloca(dg.Geometry.BytesPerSector + a))
                    {
                        PVOID pv = (PVOID)(((ULONG_PTR)buf + a) & ~a);
                        LARGE_INTEGER ByteOffset;
                        ByteOffset.QuadPart = dg.DiskSize.QuadPart - dg.Geometry.BytesPerSector;
                        ov.Offset = ByteOffset.LowPart;
                        ov.OffsetHigh = ByteOffset.HighPart;
                        ReadFile(hFile, pv, dg.Geometry.BytesPerSector, 0, &ov);
                        _freea(buf);
                    }
                }
            }

            CloseHandle(hFile);
        }
    }

    return dwError;
}

здесь я прочитал последний сектор диска. обычно я рассматриваю здесь EFI PART как первые 8 в буфере. на некоторых (съемных) вспышках я вижу ...NTFS метку

...