#include <sys/mman.h>
#include "mmap.h"
#include "util.h"
#include "out.h"
#include "win_mmap.h"
NTSTATUS
NtFreeVirtualMemory(_In_ HANDLE ProcessHandle, _Inout_ PVOID *BaseAddress,
_Inout_ PSIZE_T RegionSize, _In_ ULONG FreeType);
SRWLOCK FileMappingQLock = SRWLOCK_INIT;
struct FMLHead FileMappingQHead =
SORTEDQ_HEAD_INITIALIZER(FileMappingQHead);
static LONG_PTR
mmap_file_mapping_comparer(PFILE_MAPPING_TRACKER a, PFILE_MAPPING_TRACKER b)
{
return ((LONG_PTR)a->BaseAddress - (LONG_PTR)b->BaseAddress);
}
#ifdef MMAP_DEBUG_INFO
static void
mmap_info(void)
{
LOG(4, NULL);
AcquireSRWLockShared(&FileMappingQLock);
PFILE_MAPPING_TRACKER mt;
for (mt = SORTEDQ_FIRST(&FileMappingQHead);
mt != (void *)&FileMappingQHead;
mt = SORTEDQ_NEXT(mt, ListEntry)) {
LOG(4, "FH %08x FMH %08x AD %p-%p (%zu) "
"OF %08x FL %zu AC %d F %d",
mt->FileHandle,
mt->FileMappingHandle,
mt->BaseAddress,
mt->EndAddress,
(char *)mt->EndAddress - (char *)mt->BaseAddress,
mt->Offset,
mt->FileLen,
mt->Access,
mt->Flags);
}
ReleaseSRWLockShared(&FileMappingQLock);
}
#endif
static void *
mmap_reserve(void *addr, size_t len)
{
LOG(4, "addr %p len %zu", addr, len);
ASSERTeq((uintptr_t)addr % Mmap_align, 0);
ASSERTeq(len % Mmap_align, 0);
void *reserved_addr = VirtualAlloc(addr, len,
MEM_RESERVE, PAGE_NOACCESS);
if (reserved_addr == NULL) {
ERR("cannot find a contiguous region - "
"addr: %p, len: %lx, gle: 0x%08x",
addr, len, GetLastError());
errno = ENOMEM;
return MAP_FAILED;
}
return reserved_addr;
}
static int
mmap_unreserve(void *addr, size_t len)
{
LOG(4, "addr %p len %zu", addr, len);
ASSERTeq((uintptr_t)addr % Mmap_align, 0);
ASSERTeq(len % Mmap_align, 0);
size_t bytes_returned;
MEMORY_BASIC_INFORMATION basic_info;
bytes_returned = VirtualQuery(addr, &basic_info, sizeof(basic_info));
if (bytes_returned != sizeof(basic_info)) {
ERR("cannot query the virtual address properties of the range "
"- addr: %p, len: %d", addr, len);
errno = EINVAL;
return -1;
}
if (basic_info.State == MEM_RESERVE) {
DWORD nt_status;
void *release_addr = addr;
size_t release_size = len;
nt_status = NtFreeVirtualMemory(GetCurrentProcess(),
&release_addr, &release_size, MEM_RELEASE);
if (nt_status != 0) {
ERR("cannot release the reserved virtual space - "
"addr: %p, len: %d, nt_status: 0x%08x",
addr, len, nt_status);
errno = EINVAL;
return -1;
}
ASSERTeq(release_addr, addr);
ASSERTeq(release_size, len);
LOG(4, "freed reservation - addr: %p, size: %d", release_addr,
release_size);
} else {
LOG(4, "range not reserved - addr: %p, size: %d", addr, len);
}
return 0;
}
static void
mmap_init(void)
{
AcquireSRWLockExclusive(&FileMappingQLock);
SORTEDQ_INIT(&FileMappingQHead);
ReleaseSRWLockExclusive(&FileMappingQLock);
}
static void
mmap_fini(void)
{
AcquireSRWLockExclusive(&FileMappingQLock);
while (!SORTEDQ_EMPTY(&FileMappingQHead)) {
PFILE_MAPPING_TRACKER mt;
mt = (PFILE_MAPPING_TRACKER)SORTEDQ_FIRST(&FileMappingQHead);
SORTEDQ_REMOVE(&FileMappingQHead, mt, ListEntry);
if (mt->BaseAddress != NULL)
UnmapViewOfFile(mt->BaseAddress);
size_t release_size =
(char *)mt->EndAddress - (char *)mt->BaseAddress;
void *release_addr = (char *)mt->BaseAddress + release_size;
mmap_unreserve(release_addr, release_size);
if (mt->FileMappingHandle != NULL)
CloseHandle(mt->FileMappingHandle);
if (mt->FileHandle != NULL)
CloseHandle(mt->FileHandle);
free(mt);
}
ReleaseSRWLockExclusive(&FileMappingQLock);
}
#define PROT_ALL (PROT_READ|PROT_WRITE|PROT_EXEC)
void *
mmap(void *addr, size_t len, int prot, int flags, int fd, os_off_t offset)
{
LOG(4, "addr %p len %zu prot %d flags %d fd %d offset %ju",
addr, len, prot, flags, fd, offset);
if (len == 0) {
ERR("invalid length: %zu", len);
errno = EINVAL;
return MAP_FAILED;
}
if ((prot & ~PROT_ALL) != 0) {
ERR("invalid flags: 0x%08x", flags);
errno = EINVAL;
return MAP_FAILED;
}
if (((flags & MAP_PRIVATE) && (flags & MAP_SHARED)) ||
((flags & (MAP_PRIVATE | MAP_SHARED)) == 0)) {
ERR("neither MAP_PRIVATE or MAP_SHARED is set, or both: 0x%08x",
flags);
errno = EINVAL;
return MAP_FAILED;
}
DWORD protect = 0;
DWORD access = 0;
if (prot & PROT_WRITE) {
if (flags & MAP_PRIVATE) {
access = FILE_MAP_COPY;
if (prot & PROT_EXEC)
protect = PAGE_EXECUTE_WRITECOPY;
else
protect = PAGE_WRITECOPY;
} else {
access = FILE_MAP_ALL_ACCESS;
if (prot & PROT_EXEC)
protect = PAGE_EXECUTE_READWRITE;
else
protect = PAGE_READWRITE;
}
} else if (prot & PROT_READ) {
access = FILE_MAP_READ;
if (prot & PROT_EXEC)
protect = PAGE_EXECUTE_READ;
else
protect = PAGE_READONLY;
} else {
ERR("PAGE_NOACCESS is not supported");
errno = ENOTSUP;
return MAP_FAILED;
}
if (((uintptr_t)addr % Mmap_align) != 0) {
if ((flags & MAP_FIXED) == 0) {
addr = NULL;
} else {
ERR("hint address is not well-aligned: %p", addr);
errno = EINVAL;
return MAP_FAILED;
}
}
if ((offset % Mmap_align) != 0) {
ERR("offset is not well-aligned: %ju", offset);
errno = EINVAL;
return MAP_FAILED;
}
if ((flags & MAP_FIXED) != 0) {
int ret = munmap(addr, len);
if (ret != 0) {
ERR("!munmap: addr %p len %zu", addr, len);
return MAP_FAILED;
}
}
size_t len_align = roundup(len, Mmap_align);
size_t filelen;
size_t filelen_align;
HANDLE fh;
if (flags & MAP_ANON) {
fh = INVALID_HANDLE_VALUE;
offset = 0;
filelen = len;
filelen_align = len_align;
if ((flags & MAP_NORESERVE) != 0) {
protect |= SEC_RESERVE;
}
} else {
LARGE_INTEGER filesize;
if (fd == -1) {
ERR("invalid file descriptor: %d", fd);
errno = EBADF;
return MAP_FAILED;
}
if (!DuplicateHandle(GetCurrentProcess(),
(HANDLE)_get_osfhandle(fd),
GetCurrentProcess(), &fh,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
ERR("cannot duplicate handle - fd: %d, gle: 0x%08x",
fd, GetLastError());
errno = ENOMEM;
return MAP_FAILED;
}
if (!GetFileSizeEx(fh, &filesize)) {
ERR("cannot query the file size - fh: %d, gle: 0x%08x",
fd, GetLastError());
CloseHandle(fh);
return MAP_FAILED;
}
if (offset >= (os_off_t)filesize.QuadPart) {
errno = EINVAL;
ERR("offset is beyond the file size");
CloseHandle(fh);
return MAP_FAILED;
}
filelen = filesize.QuadPart - offset;
if (filelen > len)
filelen = len;
filelen_align = roundup(filelen, Mmap_align);
if ((offset + len) > (size_t)filesize.QuadPart) {
void *reserved_addr = mmap_reserve(addr, len_align);
if (reserved_addr == MAP_FAILED) {
ERR("cannot reserve region");
CloseHandle(fh);
return MAP_FAILED;
}
if (addr != reserved_addr && (flags & MAP_FIXED) != 0) {
ERR("cannot find a contiguous region - "
"addr: %p, len: %lx, gle: 0x%08x",
addr, len, GetLastError());
if (mmap_unreserve(reserved_addr,
len_align) != 0) {
ASSERT(FALSE);
ERR("cannot free reserved region");
}
errno = ENOMEM;
CloseHandle(fh);
return MAP_FAILED;
}
addr = reserved_addr;
if (mmap_unreserve(reserved_addr, filelen_align) != 0) {
ASSERT(FALSE);
ERR("cannot free reserved region");
CloseHandle(fh);
return MAP_FAILED;
}
}
}
HANDLE fmh = CreateFileMapping(fh,
NULL,
protect,
(DWORD) ((filelen + offset) >> 32),
(DWORD) ((filelen + offset) & 0xFFFFFFFF),
NULL);
if (fmh == NULL) {
DWORD gle = GetLastError();
ERR("CreateFileMapping, gle: 0x%08x", gle);
if (gle == ERROR_ACCESS_DENIED)
errno = EACCES;
else
errno = EINVAL;
CloseHandle(fh);
return MAP_FAILED;
}
void *base = MapViewOfFileEx(fmh,
access,
(DWORD) (offset >> 32),
(DWORD) (offset & 0xFFFFFFFF),
filelen,
addr);
if (base == NULL) {
if (addr == NULL || (flags & MAP_FIXED) != 0) {
ERR("MapViewOfFileEx, gle: 0x%08x", GetLastError());
errno = EINVAL;
CloseHandle(fh);
CloseHandle(fmh);
return MAP_FAILED;
}
base = MapViewOfFileEx(fmh,
access,
(DWORD) (offset >> 32),
(DWORD) (offset & 0xFFFFFFFF),
filelen,
NULL);
}
if (base == NULL) {
ERR("MapViewOfFileEx, gle: 0x%08x", GetLastError());
CloseHandle(fh);
CloseHandle(fmh);
return MAP_FAILED;
}
PFILE_MAPPING_TRACKER mt =
malloc(sizeof(struct FILE_MAPPING_TRACKER));
if (mt == NULL) {
ERR("!malloc");
CloseHandle(fh);
CloseHandle(fmh);
return MAP_FAILED;
}
mt->Flags = 0;
mt->FileHandle = fh;
mt->FileMappingHandle = fmh;
mt->BaseAddress = base;
mt->EndAddress = (void *)((char *)base + len_align);
mt->Access = access;
mt->Offset = offset;
mt->FileLen = filelen_align;
DWORD filesystemFlags;
if (fh == INVALID_HANDLE_VALUE) {
LOG(4, "anonymous mapping - not DAX mapped - handle: %p", fh);
} else if (GetVolumeInformationByHandleW(fh, NULL, 0, NULL, NULL,
&filesystemFlags, NULL, 0)) {
if (filesystemFlags & FILE_DAX_VOLUME) {
mt->Flags |= FILE_MAPPING_TRACKER_FLAG_DIRECT_MAPPED;
} else {
LOG(4, "file is not DAX mapped - handle: %p", fh);
}
} else {
ERR("failed to query volume information : %08x",
GetLastError());
}
AcquireSRWLockExclusive(&FileMappingQLock);
SORTEDQ_INSERT(&FileMappingQHead, mt, ListEntry,
FILE_MAPPING_TRACKER, mmap_file_mapping_comparer);
ReleaseSRWLockExclusive(&FileMappingQLock);
#ifdef MMAP_DEBUG_INFO
mmap_info();
#endif
return base;
}
static int
mmap_split(PFILE_MAPPING_TRACKER mt, void *begin, void *end)
{
LOG(4, "begin %p end %p", begin, end);
ASSERTeq((uintptr_t)begin % Mmap_align, 0);
ASSERTeq((uintptr_t)end % Mmap_align, 0);
PFILE_MAPPING_TRACKER mtb = NULL;
PFILE_MAPPING_TRACKER mte = NULL;
HANDLE fh = mt->FileHandle;
HANDLE fmh = mt->FileMappingHandle;
size_t len;
C_ASSERT(FILE_MAPPING_TRACKER_FLAGS_MASK == 1);
if (begin > mt->BaseAddress) {
mtb = malloc(sizeof(struct FILE_MAPPING_TRACKER));
if (mtb == NULL) {
ERR("!malloc");
goto err;
}
mtb->Flags = mt->Flags;
mtb->FileHandle = fh;
mtb->FileMappingHandle = fmh;
mtb->BaseAddress = mt->BaseAddress;
mtb->EndAddress = begin;
mtb->Access = mt->Access;
mtb->Offset = mt->Offset;
len = (char *)begin - (char *)mt->BaseAddress;
mtb->FileLen = len >= mt->FileLen ? mt->FileLen : len;
}
if (end < mt->EndAddress) {
mte = malloc(sizeof(struct FILE_MAPPING_TRACKER));
if (mte == NULL) {
ERR("!malloc");
goto err;
}
if (!mtb) {
mte->FileHandle = fh;
mte->FileMappingHandle = fmh;
} else {
mte->FileHandle = NULL;
mte->FileMappingHandle = NULL;
if (!DuplicateHandle(GetCurrentProcess(), fh,
GetCurrentProcess(),
&mte->FileHandle,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
ERR("DuplicateHandle, gle: 0x%08x",
GetLastError());
goto err;
}
if (!DuplicateHandle(GetCurrentProcess(), fmh,
GetCurrentProcess(),
&mte->FileMappingHandle,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
ERR("DuplicateHandle, gle: 0x%08x",
GetLastError());
goto err;
}
}
mte->Flags = mt->Flags;
mte->BaseAddress = end;
mte->EndAddress = mt->EndAddress;
mte->Access = mt->Access;
mte->Offset = mt->Offset +
((char *)mte->BaseAddress - (char *)mt->BaseAddress);
len = (char *)end - (char *)mt->BaseAddress;
mte->FileLen = len >= mt->FileLen ? 0 : mt->FileLen - len;
}
if (mt->FileLen > 0 && UnmapViewOfFile(mt->BaseAddress) == FALSE) {
ERR("UnmapViewOfFile, gle: 0x%08x", GetLastError());
goto err;
}
len = (char *)mt->EndAddress - (char *)mt->BaseAddress;
if (len > mt->FileLen) {
void *addr = (char *)mt->BaseAddress + mt->FileLen;
mmap_unreserve(addr, len - mt->FileLen);
}
if (!mtb && !mte) {
CloseHandle(fmh);
CloseHandle(fh);
}
SORTEDQ_REMOVE(&FileMappingQHead, mt, ListEntry);
free(mt);
if (mtb) {
len = (char *)mtb->EndAddress - (char *)mtb->BaseAddress;
if (len > mtb->FileLen) {
void *addr = (char *)mtb->BaseAddress + mtb->FileLen;
void *raddr = mmap_reserve(addr, len - mtb->FileLen);
if (raddr == MAP_FAILED) {
ERR("cannot find a contiguous region - "
"addr: %p, len: %lx, gle: 0x%08x",
addr, len, GetLastError());
goto err;
}
}
if (mtb->FileLen > 0) {
void *base = MapViewOfFileEx(mtb->FileMappingHandle,
mtb->Access,
(DWORD) (mtb->Offset >> 32),
(DWORD) (mtb->Offset & 0xFFFFFFFF),
mtb->FileLen,
mtb->BaseAddress);
if (base == NULL) {
ERR("MapViewOfFileEx, gle: 0x%08x",
GetLastError());
goto err;
}
}
SORTEDQ_INSERT(&FileMappingQHead, mtb, ListEntry,
FILE_MAPPING_TRACKER, mmap_file_mapping_comparer);
}
if (mte) {
len = (char *)mte->EndAddress - (char *)mte->BaseAddress;
if (len > mte->FileLen) {
void *addr = (char *)mte->BaseAddress + mte->FileLen;
void *raddr = mmap_reserve(addr, len - mte->FileLen);
if (raddr == MAP_FAILED) {
ERR("cannot find a contiguous region - "
"addr: %p, len: %lx, gle: 0x%08x",
addr, len, GetLastError());
goto err;
}
}
if (mte->FileLen > 0) {
void *base = MapViewOfFileEx(mte->FileMappingHandle,
mte->Access,
(DWORD) (mte->Offset >> 32),
(DWORD) (mte->Offset & 0xFFFFFFFF),
mte->FileLen,
mte->BaseAddress);
if (base == NULL) {
ERR("MapViewOfFileEx, gle: 0x%08x",
GetLastError());
goto err_mte;
}
}
SORTEDQ_INSERT(&FileMappingQHead, mte, ListEntry,
FILE_MAPPING_TRACKER, mmap_file_mapping_comparer);
}
return 0;
err:
if (mtb) {
ASSERTeq(mtb->FileMappingHandle, fmh);
ASSERTeq(mtb->FileHandle, fh);
CloseHandle(mtb->FileMappingHandle);
CloseHandle(mtb->FileHandle);
len = (char *)mtb->EndAddress - (char *)mtb->BaseAddress;
if (len > mtb->FileLen) {
void *addr = (char *)mtb->BaseAddress + mtb->FileLen;
mmap_unreserve(addr, len - mtb->FileLen);
}
}
err_mte:
if (mte) {
if (mte->FileMappingHandle)
CloseHandle(mte->FileMappingHandle);
if (mte->FileHandle)
CloseHandle(mte->FileHandle);
len = (char *)mte->EndAddress - (char *)mte->BaseAddress;
if (len > mte->FileLen) {
void *addr = (char *)mte->BaseAddress + mte->FileLen;
mmap_unreserve(addr, len - mte->FileLen);
}
}
free(mtb);
free(mte);
return -1;
}
int
munmap(void *addr, size_t len)
{
LOG(4, "addr %p len %zu", addr, len);
if (((uintptr_t)addr % Mmap_align) != 0) {
ERR("address is not well-aligned: %p", addr);
errno = EINVAL;
return -1;
}
if (len == 0) {
ERR("invalid length: %zu", len);
errno = EINVAL;
return -1;
}
int retval = -1;
if (len > UINTPTR_MAX - (uintptr_t)addr) {
len = UINTPTR_MAX - (uintptr_t)addr;
}
void *begin = addr;
void *end = (void *)((char *)addr + len);
AcquireSRWLockExclusive(&FileMappingQLock);
PFILE_MAPPING_TRACKER mt;
PFILE_MAPPING_TRACKER next;
for (mt = SORTEDQ_FIRST(&FileMappingQHead);
mt != (void *)&FileMappingQHead;
mt = next) {
next = SORTEDQ_NEXT(mt, ListEntry);
if (mt->BaseAddress >= end) {
LOG(4, "ignoring all mapped ranges beyond given range");
break;
}
if (mt->EndAddress <= begin) {
LOG(4, "skipping a mapped range before given range");
continue;
}
void *begin2 = begin > mt->BaseAddress ?
begin : mt->BaseAddress;
void *end2 = end < mt->EndAddress ?
end : mt->EndAddress;
size_t len2 = (char *)end2 - (char *)begin2;
void *align_end = (void *)roundup((uintptr_t)end2, Mmap_align);
if (mmap_split(mt, begin2, align_end) != 0) {
LOG(2, "mapping split failed");
goto err;
}
if (len > len2) {
len -= len2;
} else {
len = 0;
break;
}
}
if (len > 0)
mmap_unreserve(addr, roundup(len, Mmap_align));
retval = 0;
err:
ReleaseSRWLockExclusive(&FileMappingQLock);
if (retval == -1)
errno = EINVAL;
#ifdef MMAP_DEBUG_INFO
mmap_info();
#endif
return retval;
}
#define MS_ALL (MS_SYNC|MS_ASYNC|MS_INVALIDATE)
int
msync(void *addr, size_t len, int flags)
{
LOG(4, "addr %p len %zu flags %d", addr, len, flags);
if ((flags & ~MS_ALL) != 0) {
ERR("invalid flags: 0x%08x", flags);
errno = EINVAL;
return -1;
}
if (((flags & MS_SYNC) && (flags & MS_ASYNC)) ||
((flags & (MS_SYNC | MS_ASYNC)) == 0)) {
ERR("neither MS_SYNC or MS_ASYNC is set, or both: 0x%08x",
flags);
errno = EINVAL;
return -1;
}
if (((uintptr_t)addr % Pagesize) != 0) {
ERR("address is not page-aligned: %p", addr);
errno = EINVAL;
return -1;
}
if (len == 0) {
LOG(4, "zero-length region - do nothing");
return 0;
}
if (len > UINTPTR_MAX - (uintptr_t)addr) {
len = UINTPTR_MAX - (uintptr_t)addr;
}
int retval = -1;
void *begin = addr;
void *end = (void *)((char *)addr + len);
AcquireSRWLockShared(&FileMappingQLock);
PFILE_MAPPING_TRACKER mt;
SORTEDQ_FOREACH(mt, &FileMappingQHead, ListEntry) {
if (mt->BaseAddress >= end) {
LOG(4, "ignoring all mapped ranges beyond given range");
break;
}
if (mt->EndAddress <= begin) {
LOG(4, "skipping a mapped range before given range");
continue;
}
void *begin2 = begin > mt->BaseAddress ?
begin : mt->BaseAddress;
void *end2 = end < mt->EndAddress ?
end : mt->EndAddress;
size_t len2 = (char *)end2 - (char *)begin2;
if (mt->FileHandle != INVALID_HANDLE_VALUE) {
if (FlushViewOfFile(begin2, len2) == FALSE) {
ERR("FlushViewOfFile, gle: 0x%08x",
GetLastError());
errno = ENOMEM;
goto err;
}
if (FlushFileBuffers(mt->FileHandle) == FALSE) {
ERR("FlushFileBuffers, gle: 0x%08x",
GetLastError());
errno = EINVAL;
goto err;
}
}
if (len > len2) {
len -= len2;
} else {
len = 0;
break;
}
}
if (len > 0) {
ERR("indicated memory (or part of it) was not mapped");
errno = ENOMEM;
} else {
retval = 0;
}
err:
ReleaseSRWLockShared(&FileMappingQLock);
return retval;
}
#define PROT_ALL (PROT_READ|PROT_WRITE|PROT_EXEC)
int
mprotect(void *addr, size_t len, int prot)
{
LOG(4, "addr %p len %zu prot %d", addr, len, prot);
if (((uintptr_t)addr % Pagesize) != 0) {
ERR("address is not page-aligned: %p", addr);
errno = EINVAL;
return -1;
}
if (len == 0) {
LOG(4, "zero-length region - do nothing");
return 0;
}
if (len > UINTPTR_MAX - (uintptr_t)addr) {
len = UINTPTR_MAX - (uintptr_t)addr;
LOG(4, "limit len to %zu to not get beyond address space", len);
}
DWORD protect = 0;
if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
protect |= PAGE_READWRITE;
if (prot & PROT_EXEC)
protect |= PAGE_EXECUTE_READWRITE;
} else if (prot & PROT_READ) {
protect |= PAGE_READONLY;
if (prot & PROT_EXEC)
protect |= PAGE_EXECUTE_READ;
} else {
protect |= PAGE_NOACCESS;
}
int retval = -1;
void *begin = addr;
void *end = (void *)((char *)addr + len);
AcquireSRWLockShared(&FileMappingQLock);
PFILE_MAPPING_TRACKER mt;
SORTEDQ_FOREACH(mt, &FileMappingQHead, ListEntry) {
if (mt->BaseAddress >= end) {
LOG(4, "ignoring all mapped ranges beyond given range");
break;
}
if (mt->EndAddress <= begin) {
LOG(4, "skipping a mapped range before given range");
continue;
}
void *begin2 = begin > mt->BaseAddress ?
begin : mt->BaseAddress;
void *end2 = end < mt->EndAddress ?
end : mt->EndAddress;
if (mt->Access == FILE_MAP_COPY) {
if (protect & PAGE_READWRITE) {
protect &= ~PAGE_READWRITE;
protect |= PAGE_WRITECOPY;
} else if (protect & PAGE_EXECUTE_READWRITE) {
protect &= ~PAGE_EXECUTE_READWRITE;
protect |= PAGE_EXECUTE_WRITECOPY;
}
}
size_t len2 = (char *)end2 - (char *)begin2;
DWORD oldprot = 0;
BOOL ret;
ret = VirtualProtect(begin2, len2, protect, &oldprot);
if (ret == FALSE) {
DWORD gle = GetLastError();
ERR("VirtualProtect, gle: 0x%08x", gle);
switch (gle) {
case ERROR_INVALID_PARAMETER:
errno = EACCES;
break;
case ERROR_INVALID_ADDRESS:
errno = ENOMEM;
break;
default:
errno = EINVAL;
break;
}
goto err;
}
if (len > len2) {
len -= len2;
} else {
len = 0;
break;
}
}
if (len > 0) {
ERR("indicated memory (or part of it) was not mapped");
errno = ENOMEM;
} else {
retval = 0;
}
err:
ReleaseSRWLockShared(&FileMappingQLock);
return retval;
}
MSVC_CONSTR(mmap_init)
MSVC_DESTR(mmap_fini)