Code example - how to find holes in sparse files with Win32 API?

110 Views Asked by At

How can a Win32 application find all holes in sparse files? UNIX/POSIX/Linux/FreeBSD have lseek(..., SEEK_HOLE, ...) and lseek(..., SEEK_DATA, ...), but how can I do that with pure Win32 API?

We are looking for a code example in ISO C which demonstrates how to get a listing of all data sections and all holes in file, e.g.

file xyz.data
data from pos0...pos16383
hole from pos16384...pos65535
data from pos 65546...pos100020
1

There are 1 best solutions below

0
On
ULONG GetSparseRanges(HANDLE hFile)
{
    FILE_ALLOCATED_RANGE_BUFFER queryRange {{},{0, MAXLONG}}, allocRanges[16];

    DWORD dwAllocRangeCount, i = 0;
    BOOL fFinished = FALSE;
    do
    {
        switch (DWORD dwError = DeviceIoControl(hFile,
            FSCTL_QUERY_ALLOCATED_RANGES,
            &queryRange,
            sizeof(queryRange),
            allocRanges,
            sizeof(allocRanges),
            &dwAllocRangeCount,
            NULL) ? NOERROR : GetLastError())
        {
        case NOERROR:
            fFinished = TRUE;
        case ERROR_MORE_DATA:
            if (dwAllocRangeCount /= sizeof(FILE_ALLOCATED_RANGE_BUFFER))
            {
                PFILE_ALLOCATED_RANGE_BUFFER range = allocRanges;
                do 
                {
                    queryRange.FileOffset.QuadPart = range->FileOffset.QuadPart + range->Length.QuadPart;
                    
                    DbgPrint("[%08x] range: [%016I64x, %016I64x) [%016I64x]\n", i++,
                        range->FileOffset.QuadPart, 
                        queryRange.FileOffset.QuadPart,
                        range->Length.QuadPart);

                } while (range++, --dwAllocRangeCount);
                
                break;
            }
            return ERROR_INTERNAL_ERROR;

        default:
            return dwError;
        }

    } while (!fFinished);

    return NOERROR;
}

ULONG GetSparseRanges(PCWSTR lpFileName)
{
    HANDLE hFile = CreateFileW(lpFileName, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    if (INVALID_HANDLE_VALUE == hFile) return GetLastError();

    ULONG dwError = GetSparseRanges(hFile);
    CloseHandle(hFile);
    return dwError;
}