Yevhenii Nadtochii
Yevhenii Nadtochii

Reputation: 704

Adding new bytes to memory mapped file

How i can add new info to memory mapped file ? Using a pointer I can work with existing data, but only within their current size. Is it so ? For example:

void  DemoFileMapping()
{
    HANDLE hFile = CreateFile("1.txt", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    DWORD d;
    char * str = "ABCDEFG";
    WriteFile(hFile, str, strlen(str), &d, 0);

    HANDLE mapping = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, 0, 0);
    if (mapping)
    {
        unsigned char * buf = (unsigned char *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (buf)
        {
            buf[2] = 'Z'; // it works!
            UnmapViewOfFile(buf); 
        }
        CloseHandle(mapping);
    }
    CloseHandle(hFile);
}

But how can I add new information to the current one? For example, extend the string to "ABCDEFGHIJK"? I would like to have solutions without a banal backup of a larger area than the file size.

Upvotes: 1

Views: 1357

Answers (1)

RbMm
RbMm

Reputation: 33706

if I correct understand your question - you ask - are possible extend section (memory mapped file) after it was created. Yes. but for this need use ntdll api.

CreateFileMapping this is restricted shell over ZwCreateSection. if you look for it second parameter - DesiredAccess [in] - you can note next access flag:

SECTION_EXTEND_SIZE - Dynamically extend the size of the section.

Speaks for itself. but however MSDN not explain how extend the size of the section. for this exist next api - ZwExtendSection but on current time it not documented at all (but it present and worked how minimum from win2000 up to latest win 10). what sense document flag SECTION_EXTEND_SIZE without document ZwExtendSection I don't understand. also in documentation from ZwCreateSection - MaximumSize [in, optional] - the name of parameter is not correct. this is faster Initial section size, but not Maximum - because we can extend section.

also about ZwExtendSection - it extend section to NewSectionSize (if it more then current section size - otherwise call will be have no effect) rounds this value up to the nearest multiple of PAGE_SIZE and if section based on file - it extend file too, and NewSectionSize will be new file size - exactly byte to byte. file size will be not rounded to PAGE_SIZE

but if section already mapped at some BaseAddress - are view of section will be also automatically extended ? this depended from how map view of section. if by call MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); no. so you will be need unmap and then map section again after extend.

but is you will be use ZwMapViewOfSection with AllocationType [in] == MEM_RESERVE in this and only in this case ViewSize can be bigger than current section size (without MEM_RESERVE flag you got error if ViewSize bigger than current section size) - in this case system reserves ViewSize of the process's virtual address space but commit only current section size (may be little more pages). and when you call NtExtendSection - the committed view size will be extended up to NewSectionSize. this is similar when we first call VirtualAlloc with big ViewSize and MEM_RESERVE for reserve process's virtual address space without allocating any actual physical storage in memory and than again call VirtualAlloc with NewSectionSize and MEM_COMMIT flag. even not similar but exactly, only indirect.

before win8.1 no alternative for call ZwMapViewOfSection if we want use MEM_RESERVE flag, but from 8.1 we can use for this MapViewOfFile too with flag FILE_MAP_RESERVE. it declared in memoryapi.h from SDK as

#define FILE_MAP_RESERVE    0x80000000

but by unknown reason not documented in MSDN. I check this flag - it worked (how I say from win 8.1 only)

demo/test program can be next:

void DemoFileMapping()
{
    HANDLE hFile = CreateFile(L"1.txt", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    if (hFile != INVALID_HANDLE_VALUE)
    {
        HANDLE hSection;

        // set for demo intial size of section to 2 byte
        // NtCreateSection rounds this value up to the nearest multiple of PAGE_SIZE. 
        // however this will be have effect for file size exactly, if current file size less than this value
        LARGE_INTEGER InitialSize = { 2 };
        NTSTATUS status = NtCreateSection(&hSection, 
            SECTION_MAP_WRITE|SECTION_MAP_READ|SECTION_EXTEND_SIZE, 0, &InitialSize, 
            PAGE_READWRITE, SEC_COMMIT, hFile);

        //we can close file handle now
        CloseHandle(hFile);

        if (0 <= status)
        {
            PVOID BaseAddress = 0;
            SIZE_T ViewSize = 0x1000000;//reserve 16 Mb memory for example

            // BaseAddress = MapViewOfFile(hSection, FILE_MAP_RESERVE|FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, ViewSize);
            // note MEM_RESERVE
            if (0 <= ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, 
                &ViewSize, ViewUnmap, MEM_RESERVE, PAGE_READWRITE))
            {
                LARGE_INTEGER NewSize = { 0x20001 };// some random new size (128k+1 byte)

                // this call extend file, section and view size
                if (0 <= ZwExtendSection(hSection, &NewSize))
                {
                    memset(BaseAddress, '*', NewSize.LowPart);
                }

                UnmapViewOfFile(BaseAddress);
            }

            CloseHandle(hSection);
        }
    }
}

Upvotes: 6

Related Questions