Search code examples
c++winapistorageioctlfileapi

Is there any way to determine on which disk does a particular logical offset of a spanned volume resides?


Some of my colleagues have worked on a mini-port driver that encrypts data when it is being written to a volume and decrypts it when it is being read. A possible issue that occurs in this for user is determine if the data is actually encrypted on the disk. To tackle this issue, I wrote a program that when given a complete file path, would print the data of the file present on the harddisk, thus displaying the encrypted version of the file data to the user. I have been successful for a volume when it belongs to a single disk, But have been facing issues when the volume is a spanned volume. After getting the logical address of the file, I convert it into physical offset and thus read data, but in case of spanned volumes, I can't deduce to which of the harddisks this physical offset belongs, since the volume now resides on multiple disks. Is there any way to deduce that or do i need to add this as a limitation of my program ?

My code till now is this.

void fetchData(string filenameWithPath) {
    string driveLetter = "\\\\.\\" + filenameWithPath.substr(0, 2);

    map<int, pair<unsigned long long, unsigned long long>> volStruct;

    wstring wdriveLetter = wstring(driveLetter.begin(), driveLetter.end());

    wstring wfilenameWithPath = wstring(filenameWithPath.begin(), filenameWithPath.end());
    HANDLE volHandle = CreateFile(wdriveLetter.c_str(),
        GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if (volHandle == INVALID_HANDLE_VALUE) {
        cerr << "Failed to open volume. Error code: " << GetLastError() << std::endl;
        return;
    }

    HANDLE handle = CreateFileW(wfilenameWithPath.c_str(), GENERIC_READ, 0, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |
        FILE_FLAG_NO_BUFFERING, NULL);

    if (handle == INVALID_HANDLE_VALUE) {
        cerr << "Failed to open file Handle. Error code: " << GetLastError() << endl;
        return;
    }

    VOLUME_DISK_EXTENTS* diskExtents = nullptr;
    DWORD buffersize = sizeof(diskExtents)*4;
    DWORD bytesReturned = 0;

    while (true) {
        diskExtents = (VOLUME_DISK_EXTENTS*)malloc(buffersize);
        if(DeviceIoControl(volHandle,
            IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
            NULL,
            0,
            diskExtents,
            buffersize,
            &bytesReturned,
            NULL)){

            break;
        }
        
        if (GetLastError() != ERROR_MORE_DATA) {
            cout << endl << "FAILED TO GET VOLUME DISK EXTENTS DATA. ERROR CODE [" << GetLastError() << "]";
            CloseHandle(handle);
            break;
        }

        buffersize = buffersize * 2;
        free(diskExtents);
    }

    
    CloseHandle(volHandle);
    CloseHandle(handle);

    
    for (DWORD i = 0; i < diskExtents->NumberOfDiskExtents; i++) {
        pair<unsigned long long, unsigned long long> temp;
        temp.first = diskExtents->Extents[i].StartingOffset.QuadPart;
        temp.second = diskExtents->Extents[i].ExtentLength.QuadPart;
        volStruct[diskExtents->Extents[i].DiskNumber] = temp;
    }

    
    cout << endl << "Exiting";
    free(diskExtents);
    return;


}

Solution

  • Okay so I found out how to determine on which disk does a particular logical offset of a spanned volume resides. All I had to do was create a VOLUME_LOGICAL_OFFSET buffer. Then pass this buffer to the IOCTL IOCTL_VOLUME_LOGICAL_TO_PHYSICAL. This gives an output buffer of type VOLUME_PHYSICAL_OFFSET. This buffer contains, the physical offset along with the disk number to which this physical offset relates.

    VOLUME_LOGICAL_OFFSET logicalOff;
    logicalOff.LogicalOffset = 16049504256;
    VOLUME_PHYSICAL_OFFSETS physicalOff;
    DWORD bytesReturned2;
    
    if (!DeviceIoControl(
        volHandle,
        IOCTL_VOLUME_LOGICAL_TO_PHYSICAL,
        &logicalOff,
        sizeof(VOLUME_LOGICAL_OFFSET),
        &physicalOff,
        sizeof(VOLUME_PHYSICAL_OFFSETS),
        &bytesReturned2,
        NULL)) {
    
        cout << endl << "Error converting Logical address to physical address...";
        cout << endl << "The last error is " << GetLastError();
      
        CloseHandle(volHandle);
        return;
    
    }
    CloseHandle(volHandle);
    
    cout << endl << "The logical offset " << logicalOff.LogicalOffset
        << " belongs to disk " << physicalOff.PhysicalOffset[0].DiskNumber
        << " and the physical offset is " << physicalOff.PhysicalOffset[0].Offset;