/* $Id: mmapdup.cpp,v 1.3 2003-05-06 12:06:11 sandervl Exp $ */ /* * Win32 Memory mapped file & view classes * * Copyright 1999-2003 Sander van Leeuwen (sandervl@xs4all.nl) * * NOTE: Memory mapping DOES NOT work when kernel-mode code causes * a pagefault in the memory mapped object. (exceptions aren't * dispatched to our exception handler until after the kernel mode * call returns (too late)) * * NOTE: Are apps allowed to change the protection flags of memory mapped pages? * I'm assuming they aren't for now. * * TODO: Handles returned should be usable by all apis that accept file handles * TODO: Sharing memory mapped files between multiple processes * TODO: Memory mapped files with views that extend the file (not 100% correct now) * TODO: Suspend all threads when a page is committed (possible that another thread * accesses the same memory before the page is read from disk * TODO: File maps for new files (must select an initial size)! * * Project Odin Software License can be found in LICENSE.TXT * */ #include #include #include #include #include #include #include #include "mmap.h" #include "oslibdos.h" #include "oslibmem.h" #include "winimagepeldr.h" #include #define DBG_LOCALLOG DBG_mmapdup #include "dbglocal.h" //****************************************************************************** // Class Win32MemMapDup // // Duplicate memory mapping class (duplicate map with different protection flags // associated with an existing memory map) // //****************************************************************************** Win32MemMapDup::Win32MemMapDup(Win32MemMap *parent, HANDLE hFile, ULONG size, ULONG fdwProtect, LPSTR lpszName) : Win32MemMap(hFile, size, fdwProtect, lpszName) { this->parent = parent; hOrgMemFile = -1; //we're a duplicate parent->AddRef(); } //****************************************************************************** //****************************************************************************** Win32MemMapDup::~Win32MemMapDup() { parent->Release(); } //****************************************************************************** //****************************************************************************** BOOL Win32MemMapDup::Init(DWORD aMSize) { //copy values from original map mSize = parent->getMapSize(); //can't use hMemFile or else we'll close this file handle in the memmap dtor!! hDupMemFile = parent->getFileHandle(); //If the parent is a readonly map and we allow write access, then we must //override our parent's protection flags if((getProtFlags() & PAGE_READWRITE) && (parent->getProtFlags() == PAGE_READONLY)) { parent->setProtFlags(PAGE_READWRITE); } return TRUE; } //****************************************************************************** //****************************************************************************** BOOL Win32MemMapDup::flushView(ULONG viewaddr, ULONG offset, ULONG cbFlush) { return parent->flushView(viewaddr, offset, cbFlush); } //****************************************************************************** // Win32MemMapDup::mapViewOfFile // // Map the view identified by addr. Create a view with our parent as the parent // map and ourselves as the ower. // // View parent = memory map that contains the original memory map // View owner = duplicate memory map that created this view (can be NULL) // // Parameters: // // ULONG size - size of view // ULONG offset - offset in memory map // ULONG fdwAccess - access flags // FILE_MAP_WRITE, FILE_MAP_READ, FILE_MAP_COPY // FILE_MAP_ALL_ACCESS // // Returns: // <>NULL - success, view address // NULL - failure // //****************************************************************************** LPVOID Win32MemMapDup::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess) { DWORD processId = GetCurrentProcessId(); mapMutex.enter(); ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY)); Win32MemMapView *mapview; //@@@PH: if(fdwAccess & ~(FILE_MAP_WRITE|FILE_MAP_READ|FILE_MAP_COPY)) // Docs say FILE_MAP_ALL_ACCESS is same as FILE_MAP_WRITE. Doesn't match reality though. if(fdwAccess & ~FILE_MAP_ALL_ACCESS) goto parmfail; if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE)) goto parmfail; if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY))) goto parmfail; if (fdwAccess != FILE_MAP_ALL_ACCESS) if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY)) goto parmfail; if(offset+size > mSize && (!(fdwAccess & FILE_MAP_WRITE) || hDupMemFile == -1)) goto parmfail; //SvL: TODO: Doesn't work for multiple views if(offset+size > mSize) { mSize = offset+size; } if(parent->allocateMap() == FALSE) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto fail; } mapview = new Win32MemMapView(parent, offset, (size == 0) ? (mSize - offset) : size, fdwAccess, this); if(mapview == NULL) { goto fail; } if(mapview->everythingOk() == FALSE) { dprintf(("Win32MemMapDup::mapViewOfFile: !mapview->everythingOk")); delete mapview; goto fail; } mapMutex.leave(); SetLastError(ERROR_SUCCESS); return mapview->getViewAddr(); parmfail: dprintf(("Win32MemMapDup::mapViewOfFile: invalid parameter (ERROR_ACCESS_DENIED)")); //NT4 SP6 returns ERROR_ACCESS_DENIED for most invalid parameters SetLastError(ERROR_ACCESS_DENIED); fail: mapMutex.leave(); return 0; } //****************************************************************************** // Win32MemMapDup::unmapViewOfFile // // Unmap the view identified by addr by calling the parent and cleaning up // the duplicate object // // Parameters: // // LPVOID addr - view address; doesn't need to be the address // returned by MapViewOfFile(Ex) (as MSDN clearly says); // can be any address within the view range // // Returns: // TRUE - success // FALSE - failure // //****************************************************************************** BOOL Win32MemMapDup::unmapViewOfFile(LPVOID addr) { BOOL ret; dprintf(("Win32MemMapDup::unmapViewOfFile %x (nrmaps=%d)", addr, nrMappings)); mapMutex.enter(); if(nrMappings == 0) goto fail; ret = parent->unmapViewOfFile(addr); mapMutex.leave(); SetLastError(ERROR_SUCCESS); return TRUE; fail: mapMutex.leave(); SetLastError(ERROR_INVALID_ADDRESS); return FALSE; } //****************************************************************************** // Win32MemMapDup::commitPage // // Handle a pagefault for a duplicate view // // Parameters: // // ULONG ulFaultAddr - exception address // ULONG ulOffset - offset in memory map // BOOL fWriteAccess - TRUE -> write exception // FALSE -> read exception // // Returns: // TRUE - success // FALSE - failure // //****************************************************************************** BOOL Win32MemMapDup::commitPage(ULONG ulFaultAddr, ULONG offset, BOOL fWriteAccess, int nrpages) { if(mProtFlags & PAGE_WRITECOPY) {//this is a COW map, call commitGuardPage return commitGuardPage(ulFaultAddr, offset, fWriteAccess); } return parent->commitPage(ulFaultAddr, offset, fWriteAccess, nrpages); } //****************************************************************************** // Win32MemMapDup::commitGuardPage // // Handle a guard page exception for a copy-on-write view // // Parameters: // // ULONG ulFaultAddr - exception address // ULONG ulOffset - offset in memory map // BOOL fWriteAccess - TRUE -> write exception // FALSE -> read exception // // Returns: // TRUE - success // FALSE - failure // //****************************************************************************** BOOL Win32MemMapDup::commitGuardPage(ULONG ulFaultAddr, ULONG ulOffset, BOOL fWriteAccess) { return parent->commitGuardPage(ulFaultAddr, ulOffset, fWriteAccess); } //****************************************************************************** // Win32MemMapDup::invalidatePages // // Invalidate map pages. (called by WriteFile) // // Parameters: // // ULONG offset - offset in memory map // ULONG size - invalid range size // // Returns: // TRUE - success // FALSE - failure // //****************************************************************************** BOOL Win32MemMapDup::invalidatePages(ULONG offset, ULONG size) { return parent->invalidatePages(offset, size); } //****************************************************************************** //******************************************************************************