Search code examples
c++windowsdeviceiocontrol

How to initialize disk on Windows server 2008/2012 through a C++ program


We are trying to initialize disk with the properties of some existing disk on Windows server 2008/2012 through a C++ program.

We are using DeviceIoControl() method and IOCTL_DISK_CREATE_DISK, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_PARTITION_INFO_EX codes from Disk management control codes to make the disk available for use.

Got the following code snippet by searching a bit

//To open the drive
hDevice = CreateFile( TEXT("\\\\.\\PhysicalDrive7"), 
                      GENERIC_READ | GENERIC_WRITE,       // no access to the drive 
                      FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode 
                      NULL,                               // default security attributes 
                      OPEN_EXISTING,                      // disposition 
                      0,                                  // file attributes 
                      NULL);                              // do not copy file attributes 


CREATE_DISK dsk; 
dsk.PartitionStyle = PARTITION_STYLE_MBR; //It can also be PARTITION_STYLE_GPT
dsk.Mbr.Signature = 1;

// Initialize disk
bResult = DeviceIoControl( hDevice,                 // device to be queried 
                           IOCTL_DISK_CREATE_DISK,  // operation to perform 
                           &dsk, sizeof(dsk),         
                           NULL, 0,                // no output buffer 
                           &junk,                  // # bytes returned 
                           NULL
                         ); 

LARGE_INTEGER lgPartitionSize;
lgPartitionSize.QuadPart = (1024 * 1024 * 1024);
DWORD dwDriverLayoutInfoExLen = sizeof (DRIVE_LAYOUT_INFORMATION_EX) + 3 * sizeof(PARTITION_INFORMATION_EX);
DRIVE_LAYOUT_INFORMATION_EX *pdg = (DRIVE_LAYOUT_INFORMATION_EX *)new BYTE[dwDriverLayoutInfoExLen];

SecureZeroMemory(pdg, dwDriverLayoutInfoExLen);

pdg->PartitionStyle = PARTITION_STYLE_MBR; 
pdg->PartitionCount = 1;
pdg->Mbr.Signature = 1;

pdg->PartitionEntry[0].PartitionStyle = PARTITION_STYLE_MBR;   
pdg->PartitionEntry[0].StartingOffset.QuadPart = 1048576;  
pdg->PartitionEntry[0].PartitionLength.QuadPart = lgPartitionSize.QuadPart * 200;   
pdg->PartitionEntry[0].PartitionNumber = 1;   
pdg->PartitionEntry[0].RewritePartition = TRUE;

pdg->PartitionEntry[0].Mbr.PartitionType = PARTITION_NTFT; // PARTITION_IFS (NTFS partition or logical drive)   
pdg->PartitionEntry[0].Mbr.BootIndicator = TRUE;
pdg->PartitionEntry[0].Mbr.RecognizedPartition = 1;   
pdg->PartitionEntry[0].Mbr.HiddenSectors = 32256 / 512;   

// Partition a disk
bResult = DeviceIoControl( hDevice,        // device to be queried 
                           IOCTL_DISK_SET_DRIVE_LAYOUT_EX,  // operation to perform 
                           pdg, sizeof DRIVE_LAYOUT_INFORMATION_EX, //output buffer
                           NULL, 0,                // no output buffer 
                           &junk,                    // # bytes returned 
                           NULL
                         ); 

bResult = DeviceIoControl(  hDevice, 
                            IOCTL_DISK_UPDATE_PROPERTIES, 
                            NULL, 0, NULL, 0, &junk, NULL);

PARTITION_INFORMATION_EX dskinfo; 
PARTITION_INFORMATION_MBR mbrinfo; 
mbrinfo.PartitionType = PARTITION_NTFT; 
mbrinfo.HiddenSectors = (32256 / 512);
mbrinfo.BootIndicator = 1;
mbrinfo.RecognizedPartition = 1;

dskinfo.PartitionStyle = PARTITION_STYLE_MBR; 
dskinfo.StartingOffset.QuadPart = 1048576;//0; 
dskinfo.PartitionLength.QuadPart = lgPartitionSize.QuadPart * 200; 
dskinfo.PartitionNumber = 1; 
dskinfo.RewritePartition = TRUE; 
dskinfo.Mbr = mbrinfo;


bResult = DeviceIoControl( hDevice,        // device to be queried 
                           IOCTL_DISK_SET_PARTITION_INFO_EX,  // operation to perform 
                           &dskinfo, sizeof(dskinfo),        // output buffer 
                           NULL, 0,                // no output buffer 
                           &junk,                    // # bytes returned   
                           NULL
                         ); 

All the calls to DeviceIoControl() are getting succeeded except the last one with IOCTL_DISK_SET_PARTITION_INFO_EX code with error 1 (i.e Incorrect function). What could be the reason for this?

If we comment out the last call, the disk is being initialized as raw disk, But this won't meet our requirements.

The above sample is for MBR partition style only. We could not find any sample for GPT,... styles. Please give a link if someone is aware of one.


Solution

  • You're using the wrong structure type with IOCTL_DISK_SET_PARTITION_INFO_EX. It takes a SET_PARTITION_INFORMATION_EX structure, not a PARTITION_INFORMATION_EX structure.

    You probably don't need to use IOCTL_DISK_SET_PARTITION_INFO_EX, since it just sets the partition type, which should have already been set with IOCTL_DISK_SET_DRIVE_LAYOUT_EX. Unfortunately you've used it to set the wrong partition type. NTFS partitions have the partition type PARTITION_IFS.

    Multiplying lgPartitionSize by 200 is almost certainly wrong. If lgPartitionSize is supposed the size in sectors then you need to multiply this by the sector size of the disk. The sector size of hard drives used to be always 512 bytes (0x200 bytes), but modern drives use a 4096 byte sector size.

    Correctly creating partition tables is not easy, and mindlessly copying other people's code like you've done isn't going to work. Even after you fix the problems I've mentioned above you're still likely to encounter other issues. You really need to understand the all the restrictions placed on how partitions should be laid out.

    You might want to consider using the diskpart command to programically initialize disks instead of C++ code.