2015 10 14 22 14 [windows] Sparse file

今天寫個程式要在NTFS file system上產生 Sparse File.
參考MSDN #1 上面的說法, 要使用 FSCTL_SET_SPARSE 和 FSCTL_SET_ZERO_DATA 來產生 Sparse File.
不過照上面說的卻不work.

Google 了一下, 才找到#2這個網頁,
裡面明確說到, 如果你所填的zero bytes是在檔尾,
就需要用 SetFilePointer 和 SetEndOfFile 來讓資料真的寫入檔案.

後來發現事實上, 只需要用 FSCTL_SET_SPARSE,
然後再用SetFilePointer 和 SetEndOfFile 移到你想要的位置. 就可以產生Sparse File.
反之, 如果空洞是在檔案中間, 就不需要 SetEndOfFile.
但還是需要 SetFilePointer, 然後再 WriteFile 就可以了.


Sample code 如下:
/******************************************/
#include <windows.h>
#include <stdio.h>

int main()
{
    HANDLE  hFile;
    int rc;
    DWORD BytesReturned;
    BY_HANDLE_FILE_INFORMATION byHandleFile = { 0 };
    FILE_ZERO_DATA_INFORMATION fileZeroData = { 0 };
    LARGE_INTEGER sparse_size;
    sparse_size.QuadPart = 0xf0000000;

    hFile = CreateFile("t:\\test.log", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
        0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    printf("hFile = %p\n", hFile);

    rc = DeviceIoControl(hFile, FSCTL_SET_SPARSE,
        NULL, 0,
        NULL, 0, &BytesReturned, 0);
    printf(" DeviceIoControl(FSCTL_SET_SPARSE) rc = %d\n", rc);
    
    rc = WriteFile(hFile, "123", 3, &BytesReturned, 0);
    printf("WriteFile(123) rc = %d\n", rc);

    rc = GetFileInformationByHandle(hFile, &byHandleFile);
    printf("GetFileInformationByHandle rc = %d sparkse=%d\n", rc, byHandleFile.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE);

/* // 這部分可以不需要
    fileZeroData.FileOffset.QuadPart = byHandleFile.nFileSizeLow;
    fileZeroData.BeyondFinalZero.QuadPart = fileZeroData.FileOffset.QuadPart + sparse_size.QuadPart;
    rc = DeviceIoControl(hFile, FSCTL_SET_ZERO_DATA,
        &fileZeroData, sizeof(fileZeroData),
        NULL, 0, &BytesReturned, 0);
    printf("DeviceIoControl(FSCTL_SET_ZERO_DATA) rc = %d\n", rc);
    */
    
    //rc = SetFilePointer(hFile, 0x80000000, 1, FILE_END);  
    //printf("SetFilePointer() rc = %d\n", rc);
   { // 因為 sparse_size 太大, 所以要用 SetFilePointerEx
        LARGE_INTEGER offset;
        offset.QuadPart = sparse_size.QuadPart;
        rc = SetFilePointerEx(hFile, offset, NULL, FILE_END);
        printf("SetFilePointerEx() rc = %d\n", rc);
    }
    rc = SetEndOfFile(hFile);
    printf("SetEndOfFile() rc = %d\n", rc);
    CloseHandle(hFile);

    hFile = CreateFile("t:\\test.log", GENERIC_READ, FILE_SHARE_READ,
        0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    {
        LARGE_INTEGER size;
        rc = GetFileSizeEx(hFile, &size);
        printf("GetFileSize() rc = %d size=%I64x\n", rc, size.QuadPart);
    }
    CloseHandle(hFile);

    return 0;
}


 

Ref:
#1: Sparse File Operations (Windows) https://msdn.microsoft.com/zh-tw/library/windows/desktop/aa365566(v=vs.85).aspx

#2: NTFS Sparse Files For Programmers http://www.flexhex.com/docs/articles/sparse-files.phtml