Search code examples
c++winapideviceiocontrol

Finding the last cluster of a file


I'm trying to find the last cluster of a target file and read the binary data off of it. I started off with CreateFile() and used that result in DeviceIoControl() with control code FSCTL_GET_RETRIEVAL_POINTERS.

hfile = CreateFile(result,                          
        GENERIC_READ | GENERIC_WRITE,   
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,                           
        OPEN_EXISTING,                  
        FILE_ATTRIBUTE_NORMAL,          
        NULL);

RETRIEVAL_POINTERS_BUFFER retrievalBuffer;  
const DWORD Clusters = 1000;
const DWORD rpBufferSize = sizeof(RETRIEVAL_POINTERS_BUFFER) + (2 * (Clusters - 1) *sizeof(LARGE_INTEGER));
BYTE output[rpBufferSize];
STARTING_VCN_INPUT_BUFFER startVcn;
startVcn.StartingVcn.QuadPart = 0;

returns = DeviceIoControl(hfile,
            FSCTL_GET_RETRIEVAL_POINTERS,
            &startVcn,
            sizeof(startVcn),
            &output,
            sizeof(output),
            &bytesReturned,
            NULL);

So I don't really know what to do next. If I display LARGE_INTEGER Lcn from the RETRIEVAL_POINTERS_BUFFER I get a huge number which represents the current extent. I also have a switch error case which comes up as NO_ERROR so I am assuming that all the cluster data was read successfully. What can I do which the Lcn number to help me find the last cluster of the file?


Solution

  • retrievalBuffer should be a pointer:

    RETRIEVAL_POINTERS_BUFFER *retrievalBuffer = (RETRIEVAL_POINTERS_BUFFER *) output;
    

    So the last extent starts at

    DWORD lastExtentN = retrievalBuffer->ExtentCount - 1;
    LARGE_INTEGER extentLcn = retrievalBuffer->Extents[ lastExtentN ].Lcn;
    

    The extent size is

    LARGE_INTEGER extentClusters = retrievalBuffer->Extents[ lastExtentN ].NextVcn
        - lastExtentN ? retrievalBuffer->Extents[ lastExtentN - 1 ].NextVcn
                      : retrievalBuffer->StartingVcn;
    

    Thus, last logical cluster number (LCN) of the file is:

    LARGE_INTEGER lastLcn = extentLcn + extentClusters - 1;
    

    Now you can open logical volume using CreateFile() and read this cluster using ReadFile()

    NOTE: you need to check extentLcn against -1 to support sparse files.