DWORD GetVolumeDiskExtents()

in host/common/win32/portablehelpersmajor.cpp [6616:6756]


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

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

    do {
        //Get the volume guid name of the volume/mountpoint. The \\?\Volume{guid} will be used to open the volume handle.
        if (!FormatVolumeNameToGuid(volumeName))
        {
            DebugPrintf(SV_LOG_ERROR, "%s:Line %d: Could not get volume guid name for the volume: %s.\n", __FUNCTION__, __LINE__, volumeName.c_str());
            dwRet = ERROR_INVALID_PARAMETER;
            break;
        }

        //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();
            DebugPrintf(SV_LOG_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;
            DebugPrintf(SV_LOG_FATAL, "%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;
                    DebugPrintf(SV_LOG_FATAL, "%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();
                    DebugPrintf(SV_LOG_ERROR, "%s:Line %d: Cloud not get the volume disk extents. DeviceIoControl failed with Error %lu\n", __FUNCTION__, __LINE__, dwRet);
                    break;
                }
                else
                {
                    dwRet = ERROR_SUCCESS;
                }
            }
            else
            {
                DebugPrintf(SV_LOG_ERROR, "%s:Line %d: Cloud 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 (int i_extent = 0; i_extent < pVolDiskExt->NumberOfDiskExtents; i_extent++)
        {
            std::stringstream diskName;
            diskName << "\\\\.\\PhysicalDrive" << pVolDiskExt->Extents[i_extent].DiskNumber;

            //Here disk_id will be a signature if disk is MBR type, a GUID if GPT type.
            std::string storage_type, vg_name, disk_id;
            VolumeSummary::FormatLabel lable;
            VolumeSummary::Vendor vendor;
            GetDiskAttributes(diskName.str(), storage_type, lable, vendor, vg_name, disk_id);

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

            extents.push_back(extent);
        }

    } while (false);

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

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

    return dwRet;
}