I use the code below to get the physical disk size, but the size returned is not correct. I've checked the size with other tools.
The code below reports
Total disk space: 8.249.955.840 bytes
and it should be
Total disk space: 8.254.390.272 bytes
How can I retrieve the actual/correct physical disk size? Tested on USB drives and normal hard drives. The code is long, here separate it in parts to show.
The structure:
[StructLayout(LayoutKind.Sequential)]
internal struct DiskGeometry {
public long Cylinders;
public int MediaType;
public int TracksPerCylinder;
public int SectorsPerTrack;
public int BytesPerSector;
}
Native methods:
internal static class NativeMethods {
[DllImport("Kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern SafeFileHandle CreateFile(
string fileName,
uint fileAccess,
uint fileShare,
IntPtr securityAttributes,
uint creationDisposition,
uint flags,
IntPtr template
);
[DllImport("Kernel32.dll", SetLastError=false, CharSet=CharSet.Auto)]
public static extern int DeviceIoControl(
SafeFileHandle device,
uint controlCode,
IntPtr inBuffer,
uint inBufferSize,
IntPtr outBuffer,
uint outBufferSize,
ref uint bytesReturned,
IntPtr overlapped
);
internal const uint FileAccessGenericRead=0x80000000;
internal const uint FileShareWrite=0x2;
internal const uint FileShareRead=0x1;
internal const uint CreationDispositionOpenExisting=0x3;
internal const uint IoCtlDiskGetDriveGeometry=0x70000;
}
Main entry:
internal const uint IoCtlDiskGetDriveGeometry=0x70000;
public static void Main() {
SafeFileHandle diskHandle=
NativeMethods.CreateFile(
@"\\.\PhysicalDrive0",
NativeMethods.FileAccessGenericRead,
NativeMethods.FileShareWrite|NativeMethods.FileShareRead,
IntPtr.Zero,
NativeMethods.CreationDispositionOpenExisting,
0,
IntPtr.Zero
);
if(diskHandle.IsInvalid) {
Console.WriteLine("CreateFile failed with error: {0}", Marshal.GetLastWin32Error());
return;
}
int geometrySize=Marshal.SizeOf(typeof(DiskGeometry));
Console.WriteLine("geometry size = {0}", geometrySize);
IntPtr geometryBlob=Marshal.AllocHGlobal(geometrySize);
uint numBytesRead=0;
if(
0==NativeMethods.DeviceIoControl(
diskHandle,
NativeMethods.IoCtlDiskGetDriveGeometry,
IntPtr.Zero,
0,
geometryBlob,
(uint)geometrySize,
ref numBytesRead,
IntPtr.Zero
)
) {
Console.WriteLine(
"DeviceIoControl failed with error: {0}",
Marshal.GetLastWin32Error()
);
return;
}
Console.WriteLine("Bytes read = {0}", numBytesRead);
DiskGeometry geometry=(DiskGeometry)Marshal.PtrToStructure(geometryBlob, typeof(DiskGeometry));
Marshal.FreeHGlobal(geometryBlob);
long bytesPerCylinder=(long)geometry.TracksPerCylinder*(long)geometry.SectorsPerTrack*(long)geometry.BytesPerSector;
long totalSize=geometry.Cylinders*bytesPerCylinder;
Console.WriteLine("Media Type: {0}", geometry.MediaType);
Console.WriteLine("Cylinders: {0}", geometry.Cylinders);
Console.WriteLine("Tracks per Cylinder: {0}", geometry.TracksPerCylinder);
Console.WriteLine("Sectors per Track: {0}", geometry.SectorsPerTrack);
Console.WriteLine("Bytes per Sector: {0}", geometry.BytesPerSector);
Console.WriteLine("Bytes per Cylinder: {0}", bytesPerCylinder);
Console.WriteLine("Total disk space: {0}", totalSize);
}
Your code calculates it in a wrong way. About the description of physical to logical sector number calculation, take a look of the artical on Wikipedia
and following is an online bidirectional conversion script
According to your post, the physical last sector would be at
chs(1003, 137, 30) = ((1003 * 255) + 137) * 63 + 30 - 1 = lba(16121855)
And the size would be
total sectors = 1+16121855 = 16121856 sectors
16121856 * 512 bytes per sector = 8254390272 bytes
Since you specify that it should be 8,254,390,272
, I calculate the last physical sector according to that size.
255*63 is only for alignment, it's called cylinder boundary. Usually, the physical last sector is NOT end at the boundary, but for the reason not to access nonexistence sectors, it should be larger than
[total cylinders] * [tracks per cylinder(also heads)] * [sectors per track]
For example, if your physical last sector was as the calculated value above, then simply ignore the cylinder next to 1002, and use the sectors max to chs(1002, 255, 63)
as your logical last sector would be safe.
To get the physical disk size, you can invoke DeviceIoControl
with the control code IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
. Here is the reference on MSDN
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With