From fd745dd04eb079626d36b252563b28aa25ece3a0 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Wed, 7 Apr 2010 09:54:51 -0500 Subject: [PATCH 1/5] ole32: Don't map storage files in memory. --- dlls/ole32/stg_bigblockfile.c | 495 +++-------------------------------------- 1 files changed, 37 insertions(+), 458 deletions(-) diff --git a/dlls/ole32/stg_bigblockfile.c b/dlls/ole32/stg_bigblockfile.c index 77abbf6..7a98c14 100644 --- a/dlls/ole32/stg_bigblockfile.c +++ b/dlls/ole32/stg_bigblockfile.c @@ -60,45 +60,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage); * class. */ -/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */ -#define PAGE_SIZE 131072 - -/* We keep a list of recently-discarded pages. This controls the - * size of that list. */ -#define MAX_VICTIM_PAGES 16 - -/*** - * This structure identifies the paged that are mapped - * from the file and their position in memory. It is - * also used to hold a reference count to those pages. - * - * page_index identifies which PAGE_SIZE chunk from the - * file this mapping represents. (The mappings are always - * PAGE_SIZE-aligned.) - */ - -typedef struct MappedPage MappedPage; -struct MappedPage -{ - MappedPage *next; - MappedPage *prev; - - DWORD page_index; - DWORD mapped_bytes; - LPVOID lpBytes; - LONG refcnt; -}; - struct BigBlockFile { BOOL fileBased; ULARGE_INTEGER filesize; HANDLE hfile; - HANDLE hfilemap; DWORD flProtect; - MappedPage *maplist; - MappedPage *victimhead, *victimtail; - ULONG num_victim_pages; ILockBytes *pLkbyt; }; @@ -126,27 +93,6 @@ static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile) This->filesize.u.LowPart = GetFileSize(This->hfile, &This->filesize.u.HighPart); - if( This->filesize.u.LowPart || This->filesize.u.HighPart ) - { - /* create the file mapping object - */ - This->hfilemap = CreateFileMappingA(This->hfile, - NULL, - This->flProtect, - 0, 0, - NULL); - - if (!This->hfilemap) - { - CloseHandle(This->hfile); - return FALSE; - } - } - else - This->hfilemap = NULL; - - This->maplist = NULL; - TRACE("file len %u\n", This->filesize.u.LowPart); return TRUE; @@ -160,7 +106,6 @@ static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile) static BOOL BIGBLOCKFILE_LockBytesInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt) { This->hfile = 0; - This->hfilemap = 0; This->pLkbyt = plkbyt; ILockBytes_AddRef(This->pLkbyt); @@ -171,283 +116,6 @@ static BOOL BIGBLOCKFILE_LockBytesInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt) return TRUE; } -/****************************************************************************** - * BIGBLOCKFILE_FindPageInList [PRIVATE] - * - */ -static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head, - ULONG page_index) -{ - for (; head != NULL; head = head->next) - { - if (head->page_index == page_index) - { - InterlockedIncrement(&head->refcnt); - break; - } - } - - return head; - -} - -static void BIGBLOCKFILE_UnlinkPage(MappedPage *page) -{ - if (page->next) page->next->prev = page->prev; - if (page->prev) page->prev->next = page->next; -} - -static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page) -{ - if (*head) (*head)->prev = page; - page->next = *head; - page->prev = NULL; - *head = page; -} - -static BOOL BIGBLOCKFILE_MapPage(BigBlockFile *This, MappedPage *page) -{ - DWORD lowoffset = PAGE_SIZE * page->page_index; - DWORD numBytesToMap; - DWORD desired_access; - - assert(This->fileBased); - - if( !This->hfilemap ) - return FALSE; - - if (lowoffset + PAGE_SIZE > This->filesize.u.LowPart) - numBytesToMap = This->filesize.u.LowPart - lowoffset; - else - numBytesToMap = PAGE_SIZE; - - if (This->flProtect == PAGE_READONLY) - desired_access = FILE_MAP_READ; - else - desired_access = FILE_MAP_WRITE; - - page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0, - lowoffset, numBytesToMap); - page->mapped_bytes = numBytesToMap; - - TRACE("mapped page %u to %p\n", page->page_index, page->lpBytes); - - return page->lpBytes != NULL; -} - - -static MappedPage *BIGBLOCKFILE_CreatePage(BigBlockFile *This, ULONG page_index) -{ - MappedPage *page; - - page = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage)); - if (page == NULL) - return NULL; - - page->page_index = page_index; - page->refcnt = 1; - - page->next = NULL; - page->prev = NULL; - - if (!BIGBLOCKFILE_MapPage(This, page)) - { - HeapFree(GetProcessHeap(),0,page); - return NULL; - } - - return page; -} - - -/****************************************************************************** - * BIGBLOCKFILE_GetMappedView [PRIVATE] - * - * Gets the page requested if it is already mapped. - * If it's not already mapped, this method will map it - */ -static void * BIGBLOCKFILE_GetMappedView( - LPBIGBLOCKFILE This, - DWORD page_index) -{ - MappedPage *page; - - page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index); - if (!page) - { - page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index); - if (page) - { - This->num_victim_pages--; - } - } - - if (page) - { - /* If the page is not already at the head of the list, move - * it there. (Also moves pages from victim to main list.) */ - if (This->maplist != page) - { - if (This->victimhead == page) This->victimhead = page->next; - if (This->victimtail == page) This->victimtail = page->prev; - - BIGBLOCKFILE_UnlinkPage(page); - - BIGBLOCKFILE_LinkHeadPage(&This->maplist, page); - } - - return page; - } - - page = BIGBLOCKFILE_CreatePage(This, page_index); - if (!page) return NULL; - - BIGBLOCKFILE_LinkHeadPage(&This->maplist, page); - - return page; -} - -static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page) -{ - TRACE("%d at %p\n", page->page_index, page->lpBytes); - - assert(This->fileBased); - - if (page->refcnt > 0) - ERR("unmapping inuse page %p\n", page->lpBytes); - - if (page->lpBytes) - UnmapViewOfFile(page->lpBytes); - - page->lpBytes = NULL; -} - -static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page) -{ - BIGBLOCKFILE_UnmapPage(This, page); - - HeapFree(GetProcessHeap(), 0, page); -} - -/****************************************************************************** - * BIGBLOCKFILE_ReleaseMappedPage [PRIVATE] - * - * Decrements the reference count of the mapped page. - */ -static void BIGBLOCKFILE_ReleaseMappedPage( - LPBIGBLOCKFILE This, - MappedPage *page) -{ - assert(This != NULL); - assert(page != NULL); - - /* If the page is no longer refenced, move it to the victim list. - * If the victim list is too long, kick somebody off. */ - if (!InterlockedDecrement(&page->refcnt)) - { - if (This->maplist == page) This->maplist = page->next; - - BIGBLOCKFILE_UnlinkPage(page); - - if (MAX_VICTIM_PAGES > 0) - { - if (This->num_victim_pages >= MAX_VICTIM_PAGES) - { - MappedPage *victim = This->victimtail; - if (victim) - { - This->victimtail = victim->prev; - if (This->victimhead == victim) - This->victimhead = victim->next; - - BIGBLOCKFILE_UnlinkPage(victim); - BIGBLOCKFILE_DeletePage(This, victim); - } - } - else This->num_victim_pages++; - - BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page); - if (This->victimtail == NULL) This->victimtail = page; - } - else - BIGBLOCKFILE_DeletePage(This, page); - } -} - -static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list) -{ - while (list != NULL) - { - MappedPage *next = list->next; - - BIGBLOCKFILE_DeletePage(This, list); - - list = next; - } -} - -/****************************************************************************** - * BIGBLOCKFILE_FreeAllMappedPages [PRIVATE] - * - * Unmap all currently mapped pages. - * Empty mapped pages list. - */ -static void BIGBLOCKFILE_FreeAllMappedPages( - LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_DeleteList(This, This->maplist); - BIGBLOCKFILE_DeleteList(This, This->victimhead); - - This->maplist = NULL; - This->victimhead = NULL; - This->victimtail = NULL; - This->num_victim_pages = 0; -} - -static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list) -{ - for (; list != NULL; list = list->next) - { - BIGBLOCKFILE_UnmapPage(This, list); - } -} - -static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_UnmapList(This, This->maplist); - BIGBLOCKFILE_UnmapList(This, This->victimhead); -} - -static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list) -{ - while (list != NULL) - { - MappedPage *next = list->next; - - if (list->page_index * PAGE_SIZE > This->filesize.u.LowPart) - { - TRACE("discarding %u\n", list->page_index); - - /* page is entirely outside of the file, delete it */ - BIGBLOCKFILE_UnlinkPage(list); - BIGBLOCKFILE_DeletePage(This, list); - } - else - { - /* otherwise, remap it */ - BIGBLOCKFILE_MapPage(This, list); - } - - list = next; - } -} - -static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_RemapList(This, This->maplist); - BIGBLOCKFILE_RemapList(This, This->victimhead); -} - /**************************************************************************** * BIGBLOCKFILE_GetProtectMode * @@ -483,76 +151,43 @@ static HRESULT ImplBIGBLOCKFILE_ReadAt( ULONG cb, /* [in] */ ULONG* pcbRead) /* [out] */ { - ULONG first_page = ulOffset.u.LowPart / PAGE_SIZE; - ULONG offset_in_page = ulOffset.u.LowPart % PAGE_SIZE; ULONG bytes_left = cb; - ULONG page_index = first_page; - ULONG bytes_from_page; - LPVOID writePtr = pv; - - HRESULT rc = S_OK; + LPBYTE readPtr = pv; + BOOL ret; + LARGE_INTEGER offset; + ULONG cbRead; TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead); /* verify a sane environment */ if (!This) return E_FAIL; - if (offset_in_page + bytes_left > PAGE_SIZE) - bytes_from_page = PAGE_SIZE - offset_in_page; - else - bytes_from_page = bytes_left; - if (pcbRead) *pcbRead = 0; - while (bytes_left) - { - LPBYTE readPtr; - BOOL eof = FALSE; - MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); + offset.QuadPart = ulOffset.QuadPart; - if (!page || !page->lpBytes) - { - rc = STG_E_READFAULT; - break; - } + ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN); - TRACE("page %i, offset %u, bytes_from_page %u, bytes_left %u\n", - page->page_index, offset_in_page, bytes_from_page, bytes_left); + if (!ret) + return STG_E_READFAULT; - if (page->mapped_bytes < bytes_from_page) - { - eof = TRUE; - bytes_from_page = page->mapped_bytes; - } + while (bytes_left) + { + ret = ReadFile(This->hfile, readPtr, bytes_left, &cbRead, NULL); - readPtr = (BYTE*)page->lpBytes + offset_in_page; - memcpy(writePtr,readPtr,bytes_from_page); - BIGBLOCKFILE_ReleaseMappedPage(This, page); + if (!ret || cbRead == 0) + return STG_E_READFAULT; if (pcbRead) - *pcbRead += bytes_from_page; - bytes_left -= bytes_from_page; + *pcbRead += cbRead; - if (bytes_left && !eof) - { - writePtr = (LPBYTE)writePtr + bytes_from_page; - page_index ++; - offset_in_page = 0; - if (bytes_left > PAGE_SIZE) - bytes_from_page = PAGE_SIZE; - else - bytes_from_page = bytes_left; - } - if (eof) - { - rc = STG_E_READFAULT; - break; - } + bytes_left -= cbRead; + readPtr += cbRead; } TRACE("finished\n"); - return rc; + return S_OK; } /****************************************************************************** @@ -571,14 +206,11 @@ static HRESULT ImplBIGBLOCKFILE_WriteAt( ULONG* pcbWritten) /* [out] */ { ULONG size_needed = ulOffset.u.LowPart + cb; - ULONG first_page = ulOffset.u.LowPart / PAGE_SIZE; - ULONG offset_in_page = ulOffset.u.LowPart % PAGE_SIZE; ULONG bytes_left = cb; - ULONG page_index = first_page; - ULONG bytes_to_page; - LPCVOID readPtr = pv; - - HRESULT rc = S_OK; + const BYTE *writePtr = pv; + BOOL ret; + LARGE_INTEGER offset; + ULONG cbWritten; TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten); @@ -588,6 +220,9 @@ static HRESULT ImplBIGBLOCKFILE_WriteAt( if (This->flProtect != PAGE_READWRITE) return STG_E_ACCESSDENIED; + if (pcbWritten) + *pcbWritten = 0; + if (size_needed > This->filesize.u.LowPart) { ULARGE_INTEGER newSize; @@ -596,57 +231,29 @@ static HRESULT ImplBIGBLOCKFILE_WriteAt( BIGBLOCKFILE_SetSize(This, newSize); } - if (offset_in_page + bytes_left > PAGE_SIZE) - bytes_to_page = PAGE_SIZE - offset_in_page; - else - bytes_to_page = bytes_left; + offset.QuadPart = ulOffset.QuadPart; - if (pcbWritten) - *pcbWritten = 0; + ret = SetFilePointerEx(This->hfile, offset, NULL, FILE_BEGIN); + + if (!ret) + return STG_E_READFAULT; while (bytes_left) { - LPBYTE writePtr; - MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); - - TRACE("page %i, offset %u, bytes_to_page %u, bytes_left %u\n", - page ? page->page_index : 0, offset_in_page, bytes_to_page, bytes_left); - - if (!page) - { - ERR("Unable to get a page to write. This should never happen\n"); - rc = E_FAIL; - break; - } - - if (page->mapped_bytes < bytes_to_page) - { - ERR("Not enough bytes mapped to the page. This should never happen\n"); - rc = E_FAIL; - break; - } + ret = WriteFile(This->hfile, writePtr, bytes_left, &cbWritten, NULL); - writePtr = (BYTE*)page->lpBytes + offset_in_page; - memcpy(writePtr,readPtr,bytes_to_page); - BIGBLOCKFILE_ReleaseMappedPage(This, page); + if (!ret) + return STG_E_READFAULT; if (pcbWritten) - *pcbWritten += bytes_to_page; - bytes_left -= bytes_to_page; + *pcbWritten += cbWritten; - if (bytes_left) - { - readPtr = (const BYTE *)readPtr + bytes_to_page; - page_index ++; - offset_in_page = 0; - if (bytes_left > PAGE_SIZE) - bytes_to_page = PAGE_SIZE; - else - bytes_to_page = bytes_left; - } + bytes_left -= cbWritten; + writePtr += cbWritten; } - return rc; + TRACE("finished\n"); + return S_OK; } /****************************************************************************** @@ -669,11 +276,6 @@ BigBlockFile *BIGBLOCKFILE_Construct(HANDLE hFile, ILockBytes* pLkByt, DWORD ope This->fileBased = fileBased; This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags); - This->maplist = NULL; - This->victimhead = NULL; - This->victimtail = NULL; - This->num_victim_pages = 0; - if (This->fileBased) { if (!BIGBLOCKFILE_FileInit(This, hFile)) @@ -701,11 +303,8 @@ BigBlockFile *BIGBLOCKFILE_Construct(HANDLE hFile, ILockBytes* pLkByt, DWORD ope */ void BIGBLOCKFILE_Destructor(BigBlockFile *This) { - BIGBLOCKFILE_FreeAllMappedPages(This); - if (This->fileBased) { - CloseHandle(This->hfilemap); CloseHandle(This->hfile); } else @@ -759,33 +358,13 @@ HRESULT BIGBLOCKFILE_SetSize(BigBlockFile *This, ULARGE_INTEGER newSize) TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart); - /* - * Unmap all views, must be done before call to SetEndFile. - * - * Just ditch the victim list because there is no guarantee we will need them - * and it is not worth the performance hit to unmap and remap them all. - */ - BIGBLOCKFILE_DeleteList(This, This->victimhead); - This->victimhead = NULL; - This->victimtail = NULL; - This->num_victim_pages = 0; - - BIGBLOCKFILE_UnmapAllMappedPages(This); - newpos.QuadPart = newSize.QuadPart; if (SetFilePointerEx(This->hfile, newpos, NULL, FILE_BEGIN)) { - if( This->hfilemap ) CloseHandle(This->hfilemap); - SetEndOfFile(This->hfile); - - /* re-create the file mapping object */ - This->hfilemap = CreateFileMappingA(This->hfile, NULL, This->flProtect, - 0, 0, NULL); } This->filesize = newSize; - BIGBLOCKFILE_RemapAllMappedPages(This); return hr; } -- 1.6.3.3