将新字节添加到内存映射文件

Yev*_*hii 1 c winapi pointers

如何将新信息添加到内存映射文件?使用指针,我可以处理现有数据,但只能在其当前大小范围内。是这样吗 ?例如:

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);
}
Run Code Online (Sandbox Code Playgroud)

但是我怎样才能向当前信息添加新信息呢?例如,将字符串扩展为“ABCDEFGHIJK”?我希望有一种解决方案,无需对比文件大小更大的区域进行普通备份。

RbM*_*bMm 6

如果我正确理解你的问题 - 你问 - 可以在创建后扩展部分(内存映射文件)。是的。但为此需要使用ntdll api。

CreateFileMapping这是受限制的shell 过来的ZwCreateSection。如果您查找第二个参数 - DesiredAccess [in] - 您可以记下下一个访问标志:

SECTION_EXTEND_SIZE - 动态扩展该部分的大小。

不言而喻。但是MSDN并没有解释如何扩展该部分的大小。对于这个存在下一个API -ZwExtendSection但在当前时间它根本没有记录(但它呈现并工作如何最小从win2000到最新的win 10)。我不明白SECTION_EXTEND_SIZE没有文档的文档标志有什么意义。ZwExtendSection也在文档中ZwCreateSection- MaximumSize [in,可选] - 参数名称不正确。这是更快的初始部分大小,但不是最大 - 因为我们可以扩展部分。

还关于ZwExtendSection- 它将节扩展到NewSectionSize如果它大于当前节大小 - 否则调用将无效)将此值向上舍入到PAGE_SIZE最接近的倍数,并且如果节基于文件 - 它也会扩展文件,并且NewSectionSize将是新文件大小 - 精确到字节。文件大小不会四舍五入PAGE_SIZE

但如果部分已经映射到某个BaseAddress - 部分视图是否也会自动扩展?这取决于剖面图的视图方式。如果通过电话MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); 号码。因此,您将需要取消映射,然后在扩展后再次映射部分。

但是您将在这种情况下使用ZwMapViewOfSectionAllocationType [in] == MEM_RESERVE并且仅在这种情况下ViewSize可以大于当前部分大小(如果没有标志,如果ViewSize大于当前部分大小,MEM_RESERVE您会收到错误) - 在这种情况下系统保留ViewSize进程的虚拟地址空间,但仅提交当前节大小(可能多一点页)。当您调用时- 提交的视图大小将扩展到NewSectionSize。当我们第一次使用大ViewSize进行调用并保留进程的虚拟地址空间而不在内存中分配任何实际物理存储,然后再次使用NewSectionSize和标志进行调用时,情况类似。即使不相似,但完全相似,只是间接的。NtExtendSectionVirtualAllocMEM_RESERVEVirtualAllocMEM_COMMIT

ZwMapViewOfSection在 win8.1 之前,如果我们想要使用flag ,则没有其他调用方法MEM_RESERVE,但从 8.1 开始,我们MapViewOfFile也可以使用 flag 来实现此目的FILE_MAP_RESERVE。它在SDKmemoryapi.h中声明为

#define FILE_MAP_RESERVE    0x80000000
Run Code Online (Sandbox Code Playgroud)

但由于未知原因,MSDN 中未记录。我检查了这个标志 - 它有效(我只在 win 8.1 中这么说)

接下来是演示/测试程序:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)