Что именно вы хотите получить?
1) Емкость физического диска
OR
2) емкость раздела на диске
OR
3) емкость файловой системы на разделе
Для физического диска есть PDO, для него disk.sys создает и прикрепляет FDO (\Device\Harddisk<I>\DR0
- имя или \Device\Harddisk<I>\Partition0
- символическая ссылка, где I номер диска в 0,1,2..)
для каждого раздела на физическом диске disk.sys создает PDO (\Device\Harddisk<I>\Partition<J>
- (J в {1,2,3..}) - символическая ссылка на некоторые \Device\HarddiskVolume<X>
)
1) есть несколько способов получить емкость Физического диска:
откройте любое из \Device\Harddisk<I>\Partition<J>
устройств (J в {0,1,..} - таким образом, FDO диска или PDO любого раздела) с помощью (FILE_READ_ACCESS | FILE_WRITE_ACCESS)
и отправьте IOCTL_SCSI_PASS_THROUGH_DIRECT с SCSIOP_READ_CAPACITY
и/или SCSIOP_READ_CAPACITY16
- и мы получили SCSIOP_READ_CAPACITY
или SCSIOP_READ_CAPACITY16
структуру.
READ_CAPACITY_DATA_EX rcd;
SCSI_PASS_THROUGH_DIRECT sptd = {
sizeof(sptd), 0, 0, 0, 0, CDB12GENERIC_LENGTH, 0, SCSI_IOCTL_DATA_IN,
sizeof(rcd), 1, &rcd, 0, {SCSIOP_READ_CAPACITY16}
};
if (0 <= NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptd, sizeof(sptd), &sptd, sizeof(sptd)))
{
DbgPrint("---- SCSIOP_READ_CAPACITY16 ----\n");
rcd.BytesPerBlock = _byteswap_ulong(rcd.BytesPerBlock);
rcd.LogicalBlockAddress.QuadPart = _byteswap_uint64(rcd.LogicalBlockAddress.QuadPart) + 1;
DbgPrint("%I64x %x\n", rcd.LogicalBlockAddress, rcd.BytesPerBlock);
rcd.LogicalBlockAddress.QuadPart *= rcd.BytesPerBlock;
DbgPrint("%I64x %I64u\n", rcd.LogicalBlockAddress.QuadPart, rcd.LogicalBlockAddress.QuadPart);
}
or
READ_CAPACITY_DATA rcd;
SCSI_PASS_THROUGH_DIRECT sptd = {
sizeof(sptd), 0, 0, 0, 0, CDB10GENERIC_LENGTH, 0, SCSI_IOCTL_DATA_IN,
sizeof(rcd), 1, &rcd, 0, {SCSIOP_READ_CAPACITY}
};
if (0 <= NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptd, sizeof(sptd), &sptd, sizeof(sptd)))
{
DbgPrint("---- SCSIOP_READ_CAPACITY ----\n");
rcd.BytesPerBlock = _byteswap_ulong(rcd.BytesPerBlock);
rcd.LogicalBlockAddress = _byteswap_ulong(rcd.LogicalBlockAddress) + 1;
DbgPrint("%x %x\n", rcd.LogicalBlockAddress, rcd.BytesPerBlock);
ULARGE_INTEGER u = {rcd.LogicalBlockAddress};
u.QuadPart *= rcd.BytesPerBlock;
DbgPrint("%I64x %I64u\n", u.QuadPart, u.QuadPart);
}
откройте любое из \Device\Harddisk<I>\Partition<J>
устройств с помощью FILE_READ_ACCESS
и отправьте IOCTL_STORAGE_READ_CAPACITY — должен быть тот же результат, что и a) — этот дескриптор запроса ClassReadDriveCapacity
в classpnp.sys, который отправляет внутренний запрос SCSI (SCSIOP_READ_CAPACITY
) на PDO диска. этот способ не работал на XP.
STORAGE_READ_CAPACITY sc;
if (0 <= NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_STORAGE_READ_CAPACITY, 0, 0, &sc, sizeof(sc)))
{
DbgPrint("---- IOCTL_STORAGE_READ_CAPACITY ----\n");
DbgPrint("%I64x %I64x %x \n", sc.DiskLength.QuadPart, sc.NumberOfBlocks.QuadPart, sc.BlockLength);
sc.NumberOfBlocks.QuadPart *= sc.BlockLength;
DbgPrint("%I64x %I64u\n", sc.NumberOfBlocks.QuadPart, sc.NumberOfBlocks.QuadPart);
}
откройте любой из \Device\Harddisk<I>\Partition<J>
с любым доступом и отправьте IOCTL_DISK_GET_DRIVE_GEOMETRY_EX и используйте DISK_GEOMETRY_EX.DiskSize
. это думаю лучший способ. не нужны никакие права и работа на XP
DISK_GEOMETRY_EX GeometryEx;
if (0 <= NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 0, 0, &GeometryEx, sizeof(GeometryEx)))
{
DbgPrint("---- IOCTL_DISK_GET_DRIVE_GEOMETRY ----\n");
ULONG BytesPerCylinder = GeometryEx.Geometry.TracksPerCylinder * GeometryEx.Geometry.SectorsPerTrack * GeometryEx.Geometry.BytesPerSector;
DbgPrint("%I64x == %I64x\n", GeometryEx.Geometry.Cylinders.QuadPart, GeometryEx.DiskSize.QuadPart / BytesPerCylinder);
DbgPrint("%I64x <= %I64x\n", GeometryEx.Geometry.Cylinders.QuadPart * BytesPerCylinder, GeometryEx.DiskSize.QuadPart);
}
откройте \Device\Harddisk<I>\Partition0
или \Device\Harddisk<I>\Dr0
с помощью FILE_READ_ACCESS
и используйте IOCTL_DISK_GET_LENGTH_INFO
чтобы получить емкость раздела на диске - откройте \Device\Harddisk<I>\Partition<J>
(где J в {1,2..} ) или, если буква X присвоена разделу - \GLOBAL??\X:
и используйте IOCTL_DISK_GET_LENGTH_INFO. опять нужен FILE_READ_ACCESS
GET_LENGTH_INFORMATION gli;
if (0 <= NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb, IOCTL_DISK_GET_LENGTH_INFO, 0, 0, &gli, sizeof(gli)))
{
DbgPrint("---- IOCTL_DISK_GET_LENGTH_INFO ----\n");
DbgPrint("%I64x %I64u\n", gli.Length.QuadPart, gli.Length.QuadPart);
}
чтобы получить емкость файловой системы на разделе - откройте любой файл (например, \GLOBAL??\X:\
) и используйте NtQueryVolumeInformationFile(FileFsSizeInformation)
FILE_FS_SIZE_INFORMATION fsi;
if (0 <= NtOpenFile(&hFile, SYNCHRONIZE, &oa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_FREE_SPACE_QUERY|FILE_SYNCHRONOUS_IO_NONALERT))
{
if (0 <= NtQueryVolumeInformationFile(hFile, &iosb, &fsi, sizeof(fsi), FileFsSizeInformation))
{
DbgPrint("%I64x %x %x\n", fsi.TotalAllocationUnits.QuadPart, fsi.SectorsPerAllocationUnit, fsi.BytesPerSector);
fsi.TotalAllocationUnits.QuadPart *= fsi.SectorsPerAllocationUnit * fsi.BytesPerSector;
DbgPrint("%I64x %I64u\n", fsi.TotalAllocationUnits.QuadPart, fsi.TotalAllocationUnits.QuadPart);
}
NtClose(hFile);
}
или используйте GetDiskFreeSpaceEx - внутри он также вызывает NtQueryVolumeInformationFile( FileFsSizeInformation)
, но использует флаг FILE_DIRECTORY_FILE
, поэтому в качестве входного параметра вы можете использовать только каталоги
person
RbMm
schedule
09.08.2016
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
прекрасно работает для обычного пользователя. Так что, похоже, должен быть способ. - person Ben Voigt   schedule 07.11.2013get-WmiObject win32_logicaldisk
кажется правильной командой. Теперь, как я узнаю, с квотой эти числа или без? - person Ben Voigt   schedule 07.11.2013FindFirstVolume
... загрузочные тома, у которых нет буквы диска, пропускаются. - person Ben Voigt   schedule 07.11.2013GENERIC_READ
требуется доступ администратора? Я понимаю, что это нужно дляGENERIC_WRITE
, ноGENERIC_READ
?? - person Remy Lebeau   schedule 07.11.2013Win32_Volume
/CIM_StorageVolume
совпадают со списком томов, который я получил через Win32 API. И емкость у них доступная без повышения прав (хотя она как ни странно на 4096 байт меньше, чем значение изIOCTL_DISK_GET_LENGTH_INFO
) - person Ben Voigt   schedule 07.11.2013