Introduction
In this article, I will show how to determine boot partition of Windows OS with C# by using Win API (pinvoke).
Background
Windows OS has different types of partition on the disk. And there must be a system partition generally (C:\), other than this, there may be user partitions such as D: \, E:\. There may also be another type of partition such as Boot partition which is what constitutes the subject of our writing. Sometimes, developers want to identify boot partition in order not to damage the system because this partition is very important for boot operation of Windows OS.
Thanks to Richard, I realized boot indicator property is not valid on GPT disk. So I updated source code and article as compatible with GPT disk.
Using the Code
I used C# (Pinvoke). I have to define classic MS definitions which are structs, constants, etc. So I won't mention these definitions below.
The Native class contains definitions of structs, constants of Win API.
The NativeApi
the class contains functions of Win API like,CreateFile
DeviceIoControl
etc.
Firstly; We need to obtain handles of all hard drives which are mounted on the system. So we enumerate these drives. And then we can get partition list for all physical drives. Then we can enumerate all partitions.
This is full of body code:
public const uint MAX_NUMBER_OF_DRIVES = 64;
for (uint i = 0; i < MAX_NUMBER_OF_DRIVES; i++)
{
string volume = string.Format("\\\\.\\PhysicalDrive{0}", i);
SafeFileHandle hndl = CreateFile(volume, Native.GENERIC_READ | Native.GENERIC_WRITE,
Native.FILE_SHARE_READ | Native.FILE_SHARE_WRITE,
IntPtr.Zero,
Native.OPEN_EXISTING,
Native.FILE_ATTRIBUTE_READONLY,
IntPtr.Zero);
IntPtr driveLayoutPtr = IntPtr.Zero;
int DRIVE_LAYOUT_BUFFER_SIZE = 1024;
int error;
uint dummy = 0;
do
{
error = 0;
driveLayoutPtr = Marshal.AllocHGlobal(DRIVE_LAYOUT_BUFFER_SIZE);
if (DeviceIoControl
(hndl, Native.IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IntPtr.Zero, 0, driveLayoutPtr,
(uint)DRIVE_LAYOUT_BUFFER_SIZE, ref dummy, IntPtr.Zero))
{
DRIVE_LAYOUT_INFORMATION_EX driveLayout = (DRIVE_LAYOUT_INFORMATION_EX)
Marshal.PtrToStructure(driveLayoutPtr, typeof(DRIVE_LAYOUT_INFORMATION_EX));
for (uint p = 0; p < driveLayout.PartitionCount; p++)
{
IntPtr ptr = new IntPtr(driveLayoutPtr.ToInt64() +
Marshal.OffsetOf(typeof(DRIVE_LAYOUT_INFORMATION_EX), "PartitionEntry").ToInt64()
+ (p * Marshal.SizeOf(typeof(PARTITION_INFORMATION_EX))));
PARTITION_INFORMATION_EX partInfo = (PARTITION_INFORMATION_EX)
Marshal.PtrToStructure(ptr, typeof(PARTITION_INFORMATION_EX));
if (partInfo.PartitionStyle != PARTITION_STYLE.PARTITION_STYLE_GPT)
{
if ((partInfo.PartitionStyle != PARTITION_STYLE.PARTITION_STYLE_MBR) ||
(partInfo.Mbr.RecognizedPartition))
{
if (partInfo.Mbr.BootIndicator == true)
{
Console.WriteLine("Drive No: " + i + " Partition Number :" +
partInfo.PartitionNumber + " is boot partition");
}
}
}
else if (partInfo.PartitionStyle == PARTITION_STYLE.PARTITION_STYLE_GPT) {
if (partInfo.Gpt.PartitionType== new Guid("e3c9e316-0b5c-4db8-817d-f92df00215ae"))
{
Console.WriteLine("Drive No: " + i + " Partition Number :"
+ partInfo.PartitionNumber + " is boot partition");
}
}
}
}
else
{
error = Marshal.GetLastWin32Error();
DRIVE_LAYOUT_BUFFER_SIZE *= 2;
}
Marshal.FreeHGlobal(driveLayoutPtr);
driveLayoutPtr = IntPtr.Zero;
} while (error == Native.ERROR_INSUFFICIENT_BUFFER);
}
As seen above, we get all partitions and check each one is BootIndicator
or not.
The important thing is at first, filling DRIVE_LAYOUT_INFORMATION_EX structure by using the DeviceIoControl function. And then there is pointer arithmetic to extract buffer. Finally, We need to convert byte buffer to the PARTITION_INFORMATION_EX structure. That's all!
Don't forget that boot partition doesn't have to be separated on all Windows installed machines. Consider that boot OS files may be on OS installed partition which is generally " Local Disk (C:) ".
Finally, if you want to test sample application, the application requires administrator credentials to run correctly.
Points of Interest
I wrote this article for developers which are interested in Win API programming. And I think low-level programming is very hard and interesting. So I like learning new things when I develop a program. I think if you are interested in learning fundamentals of something, then this topic will help you to identify boot partition programmatically. I hope you enjoyed reading this article.