Use of FSCTL_GET_VOLUME_BITMAP to read $bitmap file from NTFS / ReFS volume

Q. How to read $bitmap file from NTFS / ReFS volume?

Ans:

FSCTL_GET_VOLUME_BITMAP IOCTL is provided to read the $bitmap file. To use this IOCT you should know the size of $bitmap in advance, If you do not know this then you’ll have to read $bitmap file in chunks and store it in file to refer it later. The sample pseudo code for reading $bitmap file looks like below:

Additional things to look for structures: STARTING_LCN_INPUT_BUFFER and VOLUME_BITMAP_BUFFER

 

#define BITMAP_CHUNK_SIZE 32*1024	// 32 KB is our chunk size to read $bitmap file

int
readVolumeBitmap(
    std::wstring volumeName
    )
{
	HANDLE hVolume;
    STARTING_LCN_INPUT_BUFFER startingLcn;
	VOLUME_BITMAP_BUFFER *volBitmap;
    UINT32 bitmapSize;
    DWORD bytesReturned, bytesWritten;
    BOOL ret, retFile;
    HANDLE hFile;
    std::wstring bitmapFile;
    int result;
	
	/* Open the volume for reading */
	hVolume = CreateFile(
                           volumeName.c_str(),
                           GENERIC_READ,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL,
                           OPEN_EXISTING,
                           0,
                           NULL);

    startingLcn.StartingLcn.QuadPart = 0;
    bitmapSize = BITMAP_CHUNK_SIZE + sizeof(LARGE_INTEGER)*2;
    volBitmap = (VOLUME_BITMAP_BUFFER *) malloc (bitmapSize);

	bitmapFile = L"dummy_bitmap.bin";

    hFile = CreateFile(
                       bitmapFile.c_str(),
                       GENERIC_WRITE,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL,
                       CREATE_ALWAYS,
                       0,
                       NULL);


	/* Read $bitmap file in loop */
    while (TRUE) {
        ret = DeviceIoControl (
                               hVolume,
                               FSCTL_GET_VOLUME_BITMAP,
                               &startingLcn,
                               sizeof(STARTING_LCN_INPUT_BUFFER),
                               volBitmap,
                               bitmapSize,
                               &bytesReturned,
                               NULL);

        if (startingLcn.StartingLcn.QuadPart != m_volBitmap->StartingLcn.QuadPart) {
                /* some ioctl error */
				return -1;
        }
        if (FALSE==ret){
			/* only error we expect is to read more data */
            if (GetLastError() != ERROR_MORE_DATA) {
                /* some ioctl error */
				return -1;
            }
        }

		/* find out the exact bytes read from $bitmap */
        bytesReturned -= sizeof(LARGE_INTEGER)*2;
        retFile = WriteFile (
                             hFile,
                             volBitmap->Buffer,
                             bytesReturned,
                             &bytesWritten,
                             NULL);
		/* If eof occured for reading $bitmap break the loop */
        if (TRUE==ret) {
            break;
        }
        /* Update the read offset for next request */
        startingLcn.StartingLcn.QuadPart += bytesReturned*8;
    }

    CloseHandle(hFile);
	CloseHandle(hVolume);
    free (volBitmap);

    return 0;
}