Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winapi 获取Windows上的卷大小_Winapi_Disk Partitioning_Raid - Fatal编程技术网

Winapi 获取Windows上的卷大小

Winapi 获取Windows上的卷大小,winapi,disk-partitioning,raid,Winapi,Disk Partitioning,Raid,我正在编写一个库来提取有关Windows系统(XP或更高版本)上的物理磁盘、分区和卷的信息 我想得到一个卷的容量。以下是我知道的方法以及每种方法失败的原因: --受用户配额的影响 --获取整个物理磁盘的大小,即使在使用卷句柄调用时也是如此 --不考虑RAID开销 --访问被拒绝时失败。(实际上,与所有其他查询不同,它需要GENERIC\u-READ访问权限,GENERIC\u-READ需要管理员访问权限。) --在XP上不可用,也有IOCTL\u DISK\u GET\u LENGTH\u I

我正在编写一个库来提取有关Windows系统(XP或更高版本)上的物理磁盘、分区和卷的信息

我想得到一个卷的容量。以下是我知道的方法以及每种方法失败的原因:

  • --受用户配额的影响
  • --获取整个物理磁盘的大小,即使在使用卷句柄调用时也是如此
  • --不考虑RAID开销
  • --访问被拒绝时失败。(实际上,与所有其他查询不同,它需要
    GENERIC\u-READ
    访问权限,
    GENERIC\u-READ
    需要管理员访问权限。)
  • --在XP上不可用,也有
    IOCTL\u DISK\u GET\u LENGTH\u INFO
    IOCTL\u DISK\u GET\u DRIVE\u GEOMETRY\u EX
  • +
    GetFreeDiskSpace
    用于集群大小——需要
    GENERIC\u READ
    (管理访问)并提供文件系统数据区域的大小,而不是整个卷的大小
  • --需要
    GENERIC\u READ
    (管理员访问),并且在USB连接的磁盘上也失败(可能使用Superflopy分区)
奇怪的是,来自
FSCTL\u GET\u VOLUME\u BITMAP
和WMI的
CIM\u LogicalDisk.Size
属性的集群数量一致,并且都比
IOCTL\u DISK\u GET\u LENGTH\u INFO
的值小4096字节


获取卷容量的正确方法是什么?由于所有其他查询都可以在没有管理员访问权限的情况下工作,因此我也在为此寻找一个最低权限的解决方案。

您希望得到什么

  • 1) 物理磁盘容量

  • 2) 磁盘上分区的容量

  • 3) 分区上文件系统的容量

物理磁盘有PDO,因为它是Disk.sys创建并连接FDO的(
\Device\Harddisk\DR0
-name或
\Device\Harddisk\Partition0
-symbolick链接,其中I磁盘号为0,1,2..)

对于物理磁盘上的每个分区,Disk.sys创建PDO(
\Device\Harddisk\Partition
-(J in{1,2,3..})-符号链接到某些
\Device\HarddiskVolume

1) 有几种方法可以获得物理磁盘容量:

  • (a)
打开任何
\Device\Harddisk\Partition
设备(J在{0,1,…}-so磁盘FDO或任何分区PDO中) 使用
(文件读取访问|文件写入访问)
并使用
SCSIOP\u读取容量
和/或
SCSIOP\u读取容量16
-我们得到了
SCSIOP\u读取容量
SCSIOP\u读取容量16
结构

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);
}
  • (c)
以任何访问权限打开任何
\Device\Harddisk\Partition
,并发送和使用
磁盘\u GEOMETRY\u 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);
}
  • (三)
要获取分区上文件系统的容量,请打开任何文件(
\GLOBAL???\X:\
),然后使用()

文件大小信息fsi;

如果(从表面上看,如果没有管理员访问权限,这似乎是不可能的。您是否尝试过使用WMI,特别是@JonathanPotter:我完全可以接受这样一个操作系统,它需要管理员访问才能在固定磁盘上获取信息,并且需要可移动媒体的交互式用户。但是Windows显然做出了不同的设计决策,因为
IOCTL\u VOLUME\u_VoMeMyDekkExpAs/Engult>对于正常用户来说是非常好的。所以看起来好像是一种方法。@我通常在远离WMI的地方,因为它是一个真正的熊从C++访问,因为输入很松散。正确的命令。现在,我如何知道这些数字是否有配额?卷是文件系统所在的块设备。对于简单卷,它与分区相同。对于RAID镜像、条带或跨卷,涉及多个分区。我非常感谢您的努力,但您显然由于(除了
IOCTL\u SCSI\u PASS\u THROUGH\u DIRECT
之外,由于
IOCTL\u DISK\u GET\u DRIVE\u GEOMETRY\u EX
的原因,这是不需要的)我尝试了所有这些方法,并解释了错误所在。例如,您建议的读取文件系统大小的方法没有,而是读取用户配额。@BenVoigt您希望从磁盘视图(原始字节大小)或文件系统视图(集群中的字节)获取卷容量?-第二个通常是smallerI我想要的是卷的大小,而不是文件系统的大小。(例如,如果扩展了一个跨卷,为了实际使用额外的空间,NTFS文件系统也必须调整大小)Windows卷管理工具(如磁盘管理MMC管理单元)倾向于同时发出卷和文件系统命令,但在例如Linux上,可以看到这些实际上是独立的操作,文件系统可能比卷(块设备)小得多。此外,卷也可能包含在(一组)中VHD文件,而不是分区中的文件——但我只是在寻找物理案例的解决方案,而不是虚拟案例的解决方案。@BenVoigt-在这种情况下,使用IOCTL\u VOLUME\u GET\u VOLUME\u DISK\u extensts-这是任何访问
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);
}
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);
}
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);
}
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);
}