john_e
john_e

Reputation: 456

Win32: Accessing a partition beyond the end of a volume?

It's possible to open a disk volume as a file by using a function call like

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

However, that only allows access to the area of the partition occupied by the volume - which may not be all of it.

Is it possible, given the drive letter of the volume, to open a handle to the entire partition? The true size of the partition can be calculated by calling DeviceIoControl(...IOCTL_GET_DRIVE_GEOMETRY...) on the volume handle, but reads/writes beyond the end of the volume do not work.

Upvotes: 1

Views: 439

Answers (2)

john_e
john_e

Reputation: 456

I found what appears to be a simpler solution for my use case: the FSCTL_ALLOW_EXTENDED_DASD_IO control code removes the restriction on the volume handle, allowing access to sectors on the partition outside the filesystem. So apart from error checking, it's a one-line addition to my code:

DeviceIoControl(hDisk, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwBytesRead, NULL);

Upvotes: 0

RbMm
RbMm

Reputation: 33744

exist different device objects for whole disk (fdo) and for partitions (pdo) on it. the first created device for whole disk. it have canonical name format

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

also well known symbolic links created for it

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

then already, if disk formated and exist partitions on it - created additional volume devices (pdo). the native name of this devices have form

"\\Device\\HarddiskVolume%d"

and well known symbolic links format for partitions -

"\\Device\\HarddiskX\\PartitionY" 

where X the same as for whole disk and Y always not 0. so disk device is \Device\HarddiskX\DRX or \Device\HarddiskX\Partition0 or \DosDevices\PhysicalDriveX and partitions for on this disk have names \Device\HarddiskX\PartitionY (symbolic link to \Device\HarddiskVolume%d). when volume is mounted - mount manager can assign letter to device, like \\\?\c: but this is only symbolic link to some volume device.

Is it possible, given the drive letter of the volume, to open a handle to the entire partition?

yes. more correct say handle to entire disk (or partition 0). we can do by send IOCTL_STORAGE_GET_DEVICE_NUMBER to volume device and use DeviceNumber from STORAGE_DEVICE_NUMBER to construct the name of the disk ("\\\\?\\PhysicalDrive%d") on which this partition live. so code can look like

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

here i read the last sector of disk. usual i view here EFI PART as first 8 in buffer. on some (removable) flash i view ...NTFS label

Upvotes: 1

Related Questions