2

Unfortunately this link was closed, but it does have my actual question: Get size of volume on Windows

When I use WMI to get the capacity of a volume in Windows, via Win32_Volume and the Capacity property for my c:\ drive, I get this value: 499513290752

However, when I use

bool Success = DeviceIoControl(
            Handle,
            IoControl.IOCTL_DISK_GET_LENGTH_INFO,
            IntPtr.Zero, //InBuffer
            0,  //InBuffer Size
            OutputBuffer,
            (uint)Marshal.SizeOf(OutputLengthInfo),
            out BytesReturned,
            IntPtr.Zero
        );

I get: 499513294848 which is exactly 4096 larger than what WMI reports. I find this is the same for every volume on the hard drive. (This Handle is a SafeFileHandle that is obtained from a call to CreateFile() with a file name of "\\?\Volume{93b1858d-033d-4719-a42a-870d8eb3fe0d}\").

Also, using the following to query the c:\ drive

uint SectorsPerCluster = 0;
uint BytesPerSector = 0;
uint NumberOfFreeClusters = 0;
uint TotalNumberOfClusters = 0;

GetDiskFreeSpace(
    Drive, 
    out SectorsPerCluster, 
    out BytesPerSector, 
    out NumberOfFreeClusters, 
    out TotalNumberOfClusters
);

Reports that there are 121951487 total clusters, 8 sectors per cluster, and 512 bytes per sector, which gives 499513290752 bytes, the same as WMI.

When I use Win32_DiskPartition, it does report the same value as DeviceIoControl for capacity, which is weird (the filename here is "\\?\GLOBALROOT\Device\Harddisk0\Partition1" as one example).

I also get a wildly different number when comparing the value obtained from Win32_DiskDrive and DeviceIoControl function for a physical disk given by "\\.\PhysicalDrive0":

Win32_DiskDrive: 500105249280

IoControl: 500107862016 (a difference of around 2.5 MiB I think)

The Win32_DiskDrive size matches the math of Bytes Per Sector * TotalSectors as reported in the WMI class: 512 bytes per sector * 976768065 total sectors = 500105249280. If the IoControl value is correct, this would mean there are actually 976773168 total sectors. The value from Disk Geometry also supports the 500105249280 disk size.

So, which value/source should I trust, and why are they always 4096 bytes different for volumes? Is the IOCTL_DISK_GET_LENGTH_INFO only valid for partitions and not for physical disks or volumes?

UPDATE: Some more information/clarification. I have also tried to read the physical sectors, and can read beyond the disk size reported by DiskGeometry and Win32_DiskDrive. In this case the IOCTL_DISK_GET_LENGTH_INFO value is actually correct, I can read up to the number of sectors reported by this function, and only get an error when I try to read beyond it. So why would the other functions not report the actual total number of sectors/correct size? Is the physical disk hiding certain areas that some functions can't access?

Community
  • 1
  • 1
mhaken
  • 1,075
  • 4
  • 14
  • 28
  • Don't have an answer, but I just voted to reopen @BenVoigt's question you linked. It sounds perfectly on topic for the `winapi` tag, and it has all the relevant information. No idea why it was closed to begin with. – dxiv Aug 09 '16 at 01:26
  • People who do not actually read the question and close it either because it does not seem to fit the expectations of some other tag applied to it or doesn't have *a* code sample. I swear this happens way too often around here, but not often enough for me to bring it up on Meta (like I was about to several months ago when several questions asking about how to use IWebBrowser2 and/or WebKitGTK+ were closed by web programmers for not actually being about writing HTML). What makes this one even more absurd is that it was closed **2 years after it was asked**. Also voted to reopen, if pointlessly. – andlabs Aug 09 '16 at 01:36
  • As for the question, if I were to guess, the WMI method is only telling you about the C: partition and the `DeviceIoControl()` call is telling you about the entire physical drive? Just a guess, assuming the C: partition is the only partition on the drive and takes up the entire space of the drive. – andlabs Aug 09 '16 at 01:44
  • 1
    My guess would be that the WMI method is telling you about the usable space on the file system, i.e., excluding the first cluster which is reserved for the boot code. I'm less sure about the physical drive, but I think the entire first track contains nothing but the MBR. – Harry Johnston Aug 09 '16 at 04:33
  • Great. Now we've got two identical questions. – David Heffernan Aug 09 '16 at 07:51
  • i write answer here - http://stackoverflow.com/questions/19825910/get-size-of-volume-on-windows/38855953#38855953 – RbMm Aug 09 '16 at 16:25
  • @HarryJohnston: Right -- the boot record itself is only one sector (typically 512 bytes), but generally 8 sectors (4096 bytes) is reserved to help ensure the file system is properly aligned, since many disks report a smaller sector size than the actual physically optimal alignment. – Ben Voigt Aug 09 '16 at 17:24
  • @BenVoigt, I thought the MBR was one the first sector of the physical disk, not each volume, since it's job it to find the partition that's marked active. This also doesn't explain why the physical disk in WMI reports it's about 2.5 MiB smaller than the GetLengthInfo DeviceIoControl method. Is this maybe that WMI is reporting the sum of usable space across the partitions or volumes? I haven't found a number that adds up yet. – mhaken Aug 10 '16 at 01:47
  • @hakenmt: The "master" boot record is for the whole disk, but each volume may have one as well. That's what allows a boot menu to chainload to different OSes, each on its own partition, without having to be aware of the kernel format and rules for launching each and every one. – Ben Voigt Aug 10 '16 at 06:31
  • @HarryJohnston it appears that for the disk, it's more than just the first track. The difference in sectors reported by WMI vs DiskLength is 5103. Given that the disk is reporting 63 sectors per track, it's exactly 81 tracks short. Don't know if there's anything special about 81, maybe it's a legacy holdover of how many tracks could be read at once on older systems? – mhaken Aug 11 '16 at 17:58
  • At least it makes sense now why the volumes are all 4096 bytes short and the partitions are not. Interesting to note, that the Win32_LogicalDiskToPartition WMI class reports starting address and ending address which accounts for the whole size of the volume and is not 4096 bytes short in case anyone is looking for another method to get the correct info. – mhaken Aug 11 '16 at 17:58
  • I'd hazard a guess that the 1 is the first track, but I don't know about the 80. It isn't the number of heads by any chance? – Harry Johnston Aug 11 '16 at 22:13
  • there's a line of remark for [IOCTL_DISK_GET_LENGTH_INFO](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365178(v=vs.85).aspx) > Volume handles do not have access to the full volume. To read or write to the last few sectors of a volume, you must call FSCTL_ALLOW_EXTENDED_DASD_IO, which instructs the file system to not perform any boundary checks. I try to call FSCTL_ALLOW_EXTENDED_DASD_IO with DeviceIoControl,I **can** read other 4KB in the end of volume,but I still get a different size of the volume. – Stone Jan 21 '17 at 03:32

1 Answers1

0

GetDiskFreeSpace reports the file system volume size, which in the case of NTFS does not include the cluster containing the backup sector at the end of the volume (partition).

IOCTL_DISK_GET_LENGTH_INFO reports the actual volume (partition) size (it does not refer to the filesystem volume).

Tal Aloni
  • 1,429
  • 14
  • 14