How to extend the volume programmatically

My requirement is to increase the disk space through the program. When I used IOCTL_DISK_GROW_PARTITION in DeviceIO to expand it, Disk Management shows the new resized, while the disk size on that PC ("My Computer") remains unchanged.

   BOOL DeviceIoControl(
      (HANDLE) hDevice,            // handle to device
      IOCTL_DISK_GROW_PARTITION,   // dwIoControlCode
      (LPVOID) lpInBuffer,         // input buffer
      (DWORD) nInBufferSize,       // size of the input buffer
      NULL,                        // lpOutBuffer
      0,                           // nOutBufferSize 
      (LPDWORD) lpBytesReturned,   // number of bytes returned
      (LPOVERLAPPED) lpOverlapped  // OVERLAPPED structure
    );

      

After some analysis, I found that when using this API, the MBR of the disk changes, but the bitmap of the cluster disk does not change. I want to know the correct way to use this DeviceIO for volume expansion or other API to do the same process.

+3


source to share


1 answer


you need to understand the different disk drivers that maintain information about the location of the disk and its partitions (size, offset from the beginning of the disk, style (gpt or mbr)) and file system that mount this partition.

IOCTL_DISK_GROW_PARTITION

- this ioctl is handled by the disk driver and the partition extension, but it cannot have an effect on the file system not to handle this ioctl and not even know that the partition has been extended. so you need additional use of ioctl FSCTL_EXTEND_VOLUME

- this ioctl already dispatches and processes the filesystem.

so if we need to do the following steps



the complete code can be like the following

int __cdecl SortPartitions(PPARTITION_INFORMATION_EX PartitionEntry1, PPARTITION_INFORMATION_EX PartitionEntry2)
{
    if (!PartitionEntry1->PartitionNumber) return PartitionEntry2->PartitionNumber ? -1 : 0;
    if (!PartitionEntry2->PartitionNumber) return +1;
    if (PartitionEntry1->StartingOffset.QuadPart < PartitionEntry2->StartingOffset.QuadPart) return -1;
    if (PartitionEntry1->StartingOffset.QuadPart > PartitionEntry2->StartingOffset.QuadPart) return +1;
    return 0;
}

DWORD ExtendTest(HANDLE hDisk)
{
    STORAGE_DEVICE_NUMBER sdn;

    ULONG dwBytesRet;

    if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
    {
        return GetLastError();
    }

    if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
    {
        return ERROR_GEN_FAILURE;
    }

    GET_LENGTH_INFORMATION gli;

    if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), &dwBytesRet, NULL))
    {
        return GetLastError();
    }

    DbgPrint("Disk Length %I64x (%I64u)\n", gli.Length.QuadPart, gli.Length.QuadPart);

    PVOID stack = alloca(guz);

    union {
        PVOID buf;
        PDRIVE_LAYOUT_INFORMATION_EX pdli;
    };

    ULONG cb = 0, rcb, PartitionCount = 4;

    for (;;)
    {
        if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
        {
            if (PartitionCount = pdli->PartitionCount)
            {
                PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;

                qsort(PartitionEntry, PartitionCount, sizeof(PARTITION_INFORMATION_EX), 
                    (int (__cdecl *)(const void *, const void *))SortPartitions );

                do 
                {
                    if (!PartitionEntry->PartitionNumber)
                    {
                        continue;
                    }

                    LARGE_INTEGER EndOffset; 
                    LARGE_INTEGER MaximumOffset = PartitionCount != 1 ? (PartitionEntry + 1)->StartingOffset : gli.Length;

                    EndOffset.QuadPart = PartitionEntry->StartingOffset.QuadPart + PartitionEntry->PartitionLength.QuadPart;

                    if (EndOffset.QuadPart > MaximumOffset.QuadPart)
                    {
                        //??
                        __debugbreak();
                    }
                    else if (EndOffset.QuadPart < MaximumOffset.QuadPart)
                    {
                        DISK_GROW_PARTITION dgp;
                        dgp.PartitionNumber = PartitionEntry->PartitionNumber;
                        dgp.BytesToGrow.QuadPart = MaximumOffset.QuadPart - EndOffset.QuadPart;

                        WCHAR sz[128];

                        swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%u", sdn.DeviceNumber, dgp.PartitionNumber);

                        HANDLE hPartition = CreateFile(sz, FILE_READ_ACCESS|FILE_WRITE_ACCESS, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

                        if (hPartition != INVALID_HANDLE_VALUE)
                        {  
                            // +++ begin extend
                            BOOL fOk = FALSE;

                            DISK_GEOMETRY dg;
                            if (DeviceIoControl(hPartition, IOCTL_DISK_GROW_PARTITION, &dgp, sizeof(dgp), 0, 0, &dwBytesRet, 0) &&
                                DeviceIoControl(hPartition, IOCTL_DISK_UPDATE_DRIVE_SIZE, 0, 0, &dg, sizeof(dg), &dwBytesRet, 0) &&
                                DeviceIoControl(hPartition, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, PartitionEntry, sizeof(*PartitionEntry), &dwBytesRet, 0)
                                )
                            {
                                LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;

                                fOk = DeviceIoControl(hPartition, FSCTL_EXTEND_VOLUME, &SectorsPerPartition, 
                                    sizeof(SectorsPerPartition), 0, 0, &dwBytesRet, 0);

                            }

                            if (!fOk)
                            {
                                GetLastError();
                            }

                            //--- end extend
                            CloseHandle(hPartition);
                        }
                    }
                    // else EndOffset.QuadPart == MaximumOffset.QuadPart - partition can not be extended

                } while (PartitionEntry++, --PartitionCount);
            }

            return NOERROR;
        }

        switch (ULONG err = GetLastError())
        {
        case ERROR_MORE_DATA:
            PartitionCount = pdli->PartitionCount;
            continue;
        case ERROR_BAD_LENGTH:
        case ERROR_INSUFFICIENT_BUFFER:
            PartitionCount <<= 1;
            continue;
        default:
            return err;
        }
    }

}
DWORD ExtendTest()
{
    HANDLE hDisk = CreateFileW(L"\\\\?\\PhysicalDrive0", FILE_GENERIC_READ|FILE_GENERIC_WRITE, 
        FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

    if (hDisk != INVALID_HANDLE_VALUE)
    {
        DWORD err = ExtendTest(hDisk);
        CloseHandle(hDisk);

        return err;
    }

    return GetLastError();
}

      

+2


source







All Articles