DWORD GetVolumeDiskExtents()

in host/AzureRecoveryLib/win32/WinUtils.cpp [261:422]


    DWORD GetVolumeDiskExtents(const std::string& volumeGuid, disk_extents_t& diskExtents)
    {
        TRACE_FUNC_BEGIN;
        DWORD dwRet = ERROR_SUCCESS;
        HANDLE hVolume = INVALID_HANDLE_VALUE;
        DWORD dwBytesReturned = 0;
        DWORD cbInBuff = 0;
        PVOLUME_DISK_EXTENTS pVolDiskExt = NULL;
        std::string volumeName = volumeGuid;

        if (volumeName.empty())
        {
            TRACE_ERROR("%s:Line %d: ERROR: Volume Name can not be empty.\n", __FUNCTION__, __LINE__);
            return ERROR_INVALID_PARAMETER;
        }

        do {

            //Remove trailing "\" if exist.
            if (volumeName[volumeName.length() - 1] == '\\')
                volumeName.erase(volumeName.length() - 1);

            //Get the volume handle
            HANDLE hVolume = INVALID_HANDLE_VALUE;
            hVolume = CreateFile(
                volumeName.c_str(),
                GENERIC_READ,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT,
                NULL
            );

            if (hVolume == INVALID_HANDLE_VALUE)
            {
                dwRet = GetLastError();
                TRACE_ERROR("%s:Line %d: Could not open the volume- %s. CreateFile failed with Error Code - %lu \n",
                    __FUNCTION__, __LINE__,
                    volumeName.c_str(),
                    dwRet);
                break;
            }

            //  Allocate default buffer sizes. 
            //  If the volume is created on basic disk then there will be only one disk extent for the volume, 
            //     and this default buffer will be enough to accomodate extent info.
            cbInBuff = sizeof(VOLUME_DISK_EXTENTS);
            pVolDiskExt = (PVOLUME_DISK_EXTENTS)malloc(cbInBuff);
            if (NULL == pVolDiskExt)
            {
                dwRet = ERROR_OUTOFMEMORY;
                TRACE_ERROR("%s:Line %d: Out of memory\n", __FUNCTION__, __LINE__);
                break;
            }

            if (!DeviceIoControl(
                hVolume,
                IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                NULL,
                0,
                pVolDiskExt,
                cbInBuff,
                &dwBytesReturned,
                NULL
            ))
            {
                dwRet = GetLastError();

                if (dwRet == ERROR_MORE_DATA)
                {
                    //  If the volume is created on dynamic disk then there will be 
                    //  posibility that more than one extent exist for the volume.
                    //  Calculate the size required to accomodate all extents.
                    cbInBuff = FIELD_OFFSET(VOLUME_DISK_EXTENTS, Extents) +
                        pVolDiskExt->NumberOfDiskExtents * sizeof(DISK_EXTENT);

                    //  Re-allocate the memory to new size
                    pVolDiskExt = (PVOLUME_DISK_EXTENTS)realloc(pVolDiskExt, cbInBuff);
                    if (NULL == pVolDiskExt)
                    {
                        dwRet = ERROR_OUTOFMEMORY;
                        TRACE_ERROR("%s:Line %d: Out of memory\n", __FUNCTION__, __LINE__);
                        break;
                    }

                    if (!DeviceIoControl(
                        hVolume,
                        IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
                        NULL,
                        0,
                        pVolDiskExt,
                        cbInBuff,
                        &dwBytesReturned,
                        NULL
                    ))
                    {
                        dwRet = GetLastError();
                        TRACE_ERROR("%s:Line %d: Could not get the volume disk extents. DeviceIoControl failed with Error %lu\n",
                            __FUNCTION__,
                            __LINE__,
                            dwRet);
                        break;
                    }
                    else
                    {
                        dwRet = ERROR_SUCCESS;
                    }
                }
                else
                {
                    TRACE_ERROR("%s:Line %d: Could not get the volume disk extents. DeviceIoControl failed with Error %lu\n",
                        __FUNCTION__,
                        __LINE__,
                        dwRet);
                    break;
                }
            }

            //Fill disk_extents_t structure with retrieved disk extents
            for (DWORD i_extent = 0; i_extent < pVolDiskExt->NumberOfDiskExtents; i_extent++)
            {
                //Here disk_id will be a signature if disk is MBR type, a GUID if GPT type.
                std::string disk_id;
                dwRet = GetDiskId(pVolDiskExt->Extents[i_extent].DiskNumber, disk_id);
                if (ERROR_SUCCESS != dwRet)
                {
                    TRACE_ERROR("%s:Line %d: Could not get the disk signature/guid of disk# %lu\n",
                        __FUNCTION__,
                        __LINE__,
                        pVolDiskExt->Extents[i_extent].DiskNumber
                    );
                    break;
                }

                disk_extent extent(
                    disk_id,
                    pVolDiskExt->Extents[i_extent].StartingOffset.QuadPart,
                    pVolDiskExt->Extents[i_extent].ExtentLength.QuadPart
                );

                std::stringstream extentOut;
                extentOut << "Disk-Id: " << extent.disk_id
                    << ", Offset: " << extent.offset
                    << ", Length: " << extent.length;

                TRACE_INFO("Extent Info: %s\n", extentOut.str().c_str());

                diskExtents.push_back(extent);
            }

        } while (false);

        if (NULL != pVolDiskExt)
            free(pVolDiskExt);

        if (INVALID_HANDLE_VALUE != hVolume)
            CloseHandle(hVolume);

        TRACE_FUNC_END;
        return dwRet;
    }