c++windowswritefile

UNBUFFERED READWRITE with Win32 API in C++


I'm trying to make 150 bytes write in UNBEFFERED MODE (for test) but i miss something... if some one can help ? the computed alignment sim to be right but still have a wrong data written data on the file... the requirement are: Size needed: 1024 Allocated pointer address at: DB6154D0 Allocated pointer address Aligned at: DB615600

#include <Windows.h>
#include <iostream>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <string>

void DisplayError(LPTSTR lpszFunction);

// Macro Given by Microsoft for computing the closest even interval from the progam need.
#define ROUND_UP_SIZE(Value,Pow2) ((SIZE_T) ((((ULONG)(Value)) + (Pow2) - 1) & (~(((LONG)(Pow2)) - 1))))
#define ROUND_UP_PTR(Ptr,Pow2)  ((void *) ((((ULONG_PTR)(Ptr)) + (Pow2) - 1) & (~(((LONG_PTR)(Pow2)) - 1))))

// Config structure for Unbeffered IO.
struct HandleConfig {
    DWORD SectorsPerCluster;
    DWORD BytesPerSector;
    DWORD NumberOfFreeClusters;
    DWORD TotalNumberOfClusters;
};

void MesureDisk(HandleConfig* config, BOOL debug) {
    DWORD lpSectorsPerCluster;
    DWORD lpBytesPerSector;
    DWORD lpNumberOfFreeClusters;
    DWORD lpTotalNumberOfClusters;

    if (GetDiskFreeSpaceA(
        NULL,
        &lpSectorsPerCluster,
        &lpBytesPerSector,
        &lpNumberOfFreeClusters,
        &lpTotalNumberOfClusters)) {
        if (!debug) {
            std::cout << "Disk measure Ok.\r\n";
        }
        else {
            std::cout << "Disk measure Ok.\r\n";
            std::cout << "Disk Structure: " << "\r\n" <<
                "SectorsPerCluster: " << lpSectorsPerCluster << "\r\n" <<
                "lpBytesPerSector: " << lpBytesPerSector << "\r\n" <<
                "lpNumberOfFreeClusters: " << lpNumberOfFreeClusters << "\r\n" <<
                "lpTotalNumberOfClusters: " << lpTotalNumberOfClusters << "\r\n";
        }
    }
    config->SectorsPerCluster = lpSectorsPerCluster;
    config->BytesPerSector = lpBytesPerSector;
    config->NumberOfFreeClusters = lpNumberOfFreeClusters;
    config->TotalNumberOfClusters = lpTotalNumberOfClusters;
}

void Windows_write_UNBEFFERED() {
    // Config the handle. 
    HANDLE hFile;
    char DataBuffer[] = "Some data for test !\r\n";
    DWORD dwBytesToWrite = 150;//(DWORD)strlen(DataBuffer);
    DWORD dwBytesWritten = 0;
    LPCSTR filePath = "File.txt";  // File PATH.

    hFile = CreateFileA(
        filePath,
        GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_ALWAYS,
        FILE_FLAG_NO_BUFFERING, //Set Flag
        NULL
    );

    // Measure the disc.
    HandleConfig fileConf;
    MesureDisk(&fileConf, TRUE);//Display the struct on Terminal.

    // Ensure you have one more sector than WRITE_SIZE would require.
    size_t sizeNeeded = fileConf.BytesPerSector + ROUND_UP_SIZE(dwBytesToWrite, fileConf.BytesPerSector);
    char* Buffer = new char[sizeNeeded];            //heap Allocation
    void* BufferAligned = ROUND_UP_PTR(Buffer, fileConf.BytesPerSector); //Offset the allocated Pointer from the disk Nomenclature.
    
    printf("sizeneeded: %d \r\n", sizeNeeded);
    printf("Allocated pointer address at: %X \r\n",Buffer );
    printf("Allocated pointer address Aligned at: %X \r\n", BufferAligned);
    
    // void* BU = VirtualAlloc(NULL, dwBytesToWrite, MEM_COMMIT,PAGE_READWRITE);
    if (!WriteFile(
        hFile,
        BufferAligned,
        sizeNeeded,                                 
        &dwBytesWritten,
        NULL)) {
        DWORD message = GetLastError();
        DisplayError((LPTSTR)&message);
        delete[] Buffer;
        CloseHandle(hFile);
        return;
    }
    CloseHandle(hFile);
    // VirtualFree(BU, 0, MEM_RELEASE);
    delete[] Buffer;
}

int main() {
    Windows_write_UNBEFFERED();
    return EXIT_SUCCESS;
}

void DisplayError(LPTSTR lpszFunction)
// Routine Description:
// Retrieve and output the system error message for the last-error code
{
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0,
        NULL);

    lpDisplayBuf =
        (LPVOID)LocalAlloc(LMEM_ZEROINIT,
            (lstrlen((LPCTSTR)lpMsgBuf)
                + lstrlen((LPCTSTR)lpszFunction)
                + 40) // account for format string
            * sizeof(TCHAR));

    if (FAILED(StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error code %d as follows:\n%s"),
        lpszFunction,
        dw,
        lpMsgBuf)))
    {
        printf("FATAL ERROR: Unable to output error code.\n");
    }

    _tprintf(TEXT("ERROR: %s\n"), (LPCTSTR)lpDisplayBuf);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

I'm trying to write 150 bytes in UNBEFFERED mode on windows with WriteFile() into a simple file but something is missing this code compile but produce a file with wrong content.


Solution

  • #include <Windows.h>
    #include <iostream>
    #include <tchar.h>
    #include <stdio.h>
    #include <strsafe.h>
    #include <string>
    #include <chrono>
    
    using namespace std::chrono;
    void DisplayError(LPTSTR lpszFunction);
    
    // Macro Given by Microsoft for computing the closest even interval from the progam need.
    #define ROUND_UP_SIZE(Value,Pow2) ((SIZE_T) ((((ULONG)(Value)) + (Pow2) - 1) & (~(((LONG)(Pow2)) - 1))))
    #define ROUND_UP_PTR(Ptr,Pow2)  ((void *) ((((ULONG_PTR)(Ptr)) + (Pow2) - 1) & (~(((LONG_PTR)(Pow2)) - 1))))
    
    // Config structure for Unbeffered IO.
    struct HandleConfig {
        DWORD SectorsPerCluster;
        DWORD BytesPerSector;
        DWORD NumberOfFreeClusters;
        DWORD TotalNumberOfClusters;
    };
    
    void MesureDisk(HandleConfig* config, BOOL debug) {
        DWORD lpSectorsPerCluster;
        DWORD lpBytesPerSector;
        DWORD lpNumberOfFreeClusters;
        DWORD lpTotalNumberOfClusters;
    
        if (GetDiskFreeSpaceA(
            NULL,
            &lpSectorsPerCluster,
            &lpBytesPerSector,
            &lpNumberOfFreeClusters,
            &lpTotalNumberOfClusters)) {
            if (!debug) {
                std::cout << "Disk measure Ok.\r\n";
            }
            else {
                std::cout << "Disk measure Ok.\r\n";
                std::cout << "Disk Structure: " << "\r\n" <<
                    "SectorsPerCluster: " << lpSectorsPerCluster << "\r\n" <<
                    "lpBytesPerSector: " << lpBytesPerSector << "\r\n" <<
                    "lpNumberOfFreeClusters: " << lpNumberOfFreeClusters << "\r\n" <<
                    "lpTotalNumberOfClusters: " << lpTotalNumberOfClusters << "\r\n";
            }
        }
        config->SectorsPerCluster = lpSectorsPerCluster;
        config->BytesPerSector = lpBytesPerSector;
        config->NumberOfFreeClusters = lpNumberOfFreeClusters;
        config->TotalNumberOfClusters = lpTotalNumberOfClusters;
    }
    
    void Windows_write_UNBEFFERED() {
        
        //Set the Data.
        std::string date = std::format("Date: {:%a %b %e %H:%M:%S %Z %Y}", zoned_time{ "Europe/Paris",floor<std::chrono::seconds>(system_clock::now()) });
        char DataBuffer[1024] = { "\0" };
        //Quick mem copy.
        size_t ct = 0;
        while (date[ct] != '\0') {
            DataBuffer[ct] = date.data()[ct];
            ct++;
        }
    
        // Config the handle. 
        HANDLE hFile;
        DWORD dwBytesToWrite = (DWORD)strlen(DataBuffer);
        DWORD dwBytesWritten = 0;
        LPCWSTR filePath = L"File.txt";  // File PATH.
        //Create File
        hFile = CreateFileW(
            filePath,
            GENERIC_WRITE,
            FILE_SHARE_READ,
            NULL,
            CREATE_ALWAYS,
            FILE_FLAG_NO_BUFFERING, //Set Flag
            NULL
        );
    
        if (hFile == INVALID_HANDLE_VALUE) {
            DWORD message = GetLastError();
            DisplayError((LPTSTR)&message);
            CloseHandle(hFile);
            return;
        }
    
        // Measure the disc.
        HandleConfig fileConf;
        MesureDisk(&fileConf, TRUE);//Display the struct on Terminal.
    
        // Ensure you have one more sector than WRITE_SIZE would require.
        const size_t sizeNeeded = fileConf.BytesPerSector + ROUND_UP_SIZE(dwBytesToWrite, fileConf.BytesPerSector);
    
    
        //Print Current Buffer Adress and offset Constraints for UNBEFFERED IO.
        printf("size needed: %d \r\n", sizeNeeded);
    
        // Move the current file pointer in Constreined offset (test for control ...neutral modification... or write in the midle of the block).
        printf("Current pointer position A: 0x%X \r\n", SetFilePointer(hFile, 0, 0, FILE_CURRENT));
        if (SetFilePointer(hFile, 0x200, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {//Move 512 bytes forward.
            DWORD message = GetLastError();
            DisplayError((LPTSTR)&message);
            printf("ERROR on Set file pointer...\r\n");
            CloseHandle(hFile);
            return;
        }
        printf("Current pointer position B: 0x%X \r\n", SetFilePointer(hFile, 0, 0, FILE_CURRENT));
    //  printf("Current pointer position C (reset at the begening of file): 0x%X \r\n", SetFilePointer(hFile, 0, 0, FILE_BEGIN));
    
        // Write the file.
        if (!WriteFile(
            hFile,
            DataBuffer,
            sizeNeeded,
            &dwBytesWritten,
            NULL)) {
            DWORD message = GetLastError();
            DisplayError((LPTSTR)&message);
            CloseHandle(hFile);
            return;
        }
        CloseHandle(hFile);
    }
    
    int main() {
        Windows_write_UNBEFFERED();
        return EXIT_SUCCESS;
    }
    
    void DisplayError(LPTSTR lpszFunction)
    // Routine Description:
    // Retrieve and output the system error message for the last-error code
    {
        LPVOID lpMsgBuf;
        LPVOID lpDisplayBuf;
        DWORD dw = GetLastError();
    
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            dw,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0,
            NULL);
    
        lpDisplayBuf =
            (LPVOID)LocalAlloc(LMEM_ZEROINIT,
                (lstrlen((LPCTSTR)lpMsgBuf)
                    + lstrlen((LPCTSTR)lpszFunction)
                    + 40) // account for format string
                * sizeof(TCHAR));
    
        if (FAILED(StringCchPrintf((LPTSTR)lpDisplayBuf,
            LocalSize(lpDisplayBuf) / sizeof(TCHAR),
            TEXT("%s failed with error code %d as follows:\n%s"),
            lpszFunction,
            dw,
            lpMsgBuf)))
        {
            printf("FATAL ERROR: Unable to output error code.\n");
        }
    
        _tprintf(TEXT("ERROR: %s\n"), (LPCTSTR)lpDisplayBuf);
    
        LocalFree(lpMsgBuf);
        LocalFree(lpDisplayBuf);
    }