Rework storage with blockfiles to properly use ILockBytes interfaces
Aric Stewart
aric at codeweavers.com
Wed Mar 14 11:43:54 CDT 2007
Implement ILockBytes on block files. Moving most of the code from
stg_bigblockfile.c to that implementation in stg_filelockbytes.
Rework storage to make all its interactions with the underlying data
through ILockBytes interfaces.
---
dlls/ole32/Makefile.in | 1 +
dlls/ole32/stg_bigblockfile.c | 759 ++--------------------------------
dlls/ole32/stg_filelockbytes.c | 894
++++++++++++++++++++++++++++++++++++++++
dlls/ole32/storage32.c | 293 +++++++-------
dlls/ole32/storage32.h | 25 +-
5 files changed, 1083 insertions(+), 889 deletions(-)
-------------- next part --------------
diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in
index 6779695..b3521f3 100644
--- a/dlls/ole32/Makefile.in
+++ b/dlls/ole32/Makefile.in
@@ -38,6 +38,7 @@ C_SRCS = \
regsvr.c \
rpc.c \
stg_bigblockfile.c \
+ stg_filelockbytes.c \
stg_prop.c \
stg_stream.c \
storage32.c \
diff --git a/dlls/ole32/stg_bigblockfile.c b/dlls/ole32/stg_bigblockfile.c
index df2cea1..be08041 100644
--- a/dlls/ole32/stg_bigblockfile.c
+++ b/dlls/ole32/stg_bigblockfile.c
@@ -2,6 +2,9 @@
*
* BigBlockFile
*
+ * Almost all of the functionallity that was here has been moved into
+ * stg_filelockbytes.c Please look there.
+ *
* This is the implementation of a file that consists of blocks of
* a predetermined size.
* This class is used in the Compound File implementation of the
@@ -55,113 +58,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(storage);
-/***********************************************************
- * Data structures used internally by the BigBlockFile
- * class.
- */
-
-/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
-#define PAGE_SIZE 131072
-
-#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE)
-
-/* We keep a list of recently-discarded pages. This controls the
- * size of that list. */
-#define MAX_VICTIM_PAGES 16
-
-/* This structure provides one bit for each block in a page.
- * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */
-typedef struct
-{
- unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))];
-} BlockBits;
-
-/***
- * 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.)
- */
-struct MappedPage
-{
- MappedPage *next;
- MappedPage *prev;
-
- DWORD page_index;
- LPVOID lpBytes;
- LONG refcnt;
-
- BlockBits readable_blocks;
- BlockBits writable_blocks;
-};
-
-/***********************************************************
- * Prototypes for private methods
- */
-static void* BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This,
- DWORD page_index);
-static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This,
- MappedPage *page);
-static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This);
-static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This);
-static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This);
-static void* BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This,
- ULONG index,
- DWORD desired_access);
-static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
- void* pBlock);
-static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
- ULONG page_index);
-static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
-static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile);
-static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt);
-
-/* Note that this evaluates a and b multiple times, so don't
- * pass expressions with side effects. */
-#define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
-
-/***********************************************************
- * Blockbits functions.
- */
-static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb,
- unsigned int index)
-{
- unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
- unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
-
- return bb->bits[array_index] & (1 << bit_index);
-}
-
-static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index)
-{
- unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
- unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
-
- bb->bits[array_index] |= (1 << bit_index);
-}
-
-static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index)
-{
- unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
- unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
-
- bb->bits[array_index] &= ~(1 << bit_index);
-}
-
-static inline void BIGBLOCKFILE_Zero(BlockBits *bb)
-{
- memset(bb->bits, 0, sizeof(bb->bits));
-}
-
/******************************************************************************
* BIGBLOCKFILE_Construct
*
- * Construct a big block file. Create the file mapping object.
- * Create the read only mapped pages list, the writable mapped page list
- * and the blocks in use list.
+ * Construct a big block file.
+ * Creates the ILockBytes for a file if needed.
*/
BigBlockFile * BIGBLOCKFILE_Construct(
HANDLE hFile,
@@ -177,117 +78,30 @@ BigBlockFile * BIGBLOCKFILE_Construct(
if (This == NULL)
return NULL;
- This->fileBased = fileBased;
-
- This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags);
-
This->blocksize = blocksize;
- This->maplist = NULL;
- This->victimhead = NULL;
- This->victimtail = NULL;
- This->num_victim_pages = 0;
-
- if (This->fileBased)
+ if (fileBased)
{
- if (!BIGBLOCKFILE_FileInit(This, hFile))
+ CreateILockBytesOnFile(hFile,openFlags,TRUE,&This->pLkbyt);
+ if (!This->pLkbyt)
{
- HeapFree(GetProcessHeap(), 0, This);
- return NULL;
+ ERR("Unable to create FileLockBytesImpl\n");
+ HeapFree(GetProcessHeap(), 0, This);
+ return NULL;
}
}
else
{
- if (!BIGBLOCKFILE_MemInit(This, pLkByt))
- {
- HeapFree(GetProcessHeap(), 0, This);
- return NULL;
- }
- }
+ This->pLkbyt = pLkByt;
- return This;
-}
-
-/******************************************************************************
- * BIGBLOCKFILE_FileInit
- *
- * Initialize a big block object supported by a file.
- */
-static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile)
-{
- This->pLkbyt = NULL;
- This->hbytearray = 0;
- This->pbytearray = NULL;
-
- This->hfile = hFile;
-
- if (This->hfile == INVALID_HANDLE_VALUE)
- return FALSE;
-
- 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
+ /*
+ * Increment the reference count of the ILockByte object since
+ * we're keeping a reference to it.
*/
- This->hfilemap = CreateFileMappingA(This->hfile,
- NULL,
- This->flProtect,
- 0, 0,
- NULL);
-
- if (!This->hfilemap)
- {
- CloseHandle(This->hfile);
- return FALSE;
- }
+ ILockBytes_AddRef(This->pLkbyt);
}
- else
- This->hfilemap = NULL;
-
- This->maplist = NULL;
-
- TRACE("file len %u\n", This->filesize.u.LowPart);
-
- return TRUE;
-}
-/******************************************************************************
- * BIGBLOCKFILE_MemInit
- *
- * Initialize a big block object supported by an ILockBytes on HGLOABL.
- */
-static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt)
-{
- This->hfile = 0;
- This->hfilemap = 0;
-
- /*
- * Retrieve the handle to the byte array from the LockByte object.
- */
- if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK)
- {
- FIXME("May not be an ILockBytes on HGLOBAL\n");
- return FALSE;
- }
-
- This->pLkbyt = plkbyt;
-
- /*
- * Increment the reference count of the ILockByte object since
- * we're keeping a reference to it.
- */
- ILockBytes_AddRef(This->pLkbyt);
-
- This->filesize.u.LowPart = GlobalSize(This->hbytearray);
- This->filesize.u.HighPart = 0;
-
- This->pbytearray = GlobalLock(This->hbytearray);
-
- TRACE("mem on %p len %u\n", This->pbytearray, This->filesize.u.LowPart);
-
- return TRUE;
+ return This;
}
/******************************************************************************
@@ -298,18 +112,7 @@ static BOOL BIGBLOCKFILE_MemInit(LPBIGBL
void BIGBLOCKFILE_Destructor(
LPBIGBLOCKFILE This)
{
- BIGBLOCKFILE_FreeAllMappedPages(This);
-
- if (This->fileBased)
- {
- CloseHandle(This->hfilemap);
- CloseHandle(This->hfile);
- }
- else
- {
- GlobalUnlock(This->hbytearray);
- ILockBytes_Release(This->pLkbyt);
- }
+ ILockBytes_Release(This->pLkbyt);
/* destroy this
*/
@@ -317,46 +120,13 @@ void BIGBLOCKFILE_Destructor(
}
/******************************************************************************
- * BIGBLOCKFILE_GetROBigBlock
- *
- * Returns the specified block in read only mode.
- * Will return NULL if the block doesn't exists.
- */
-void* BIGBLOCKFILE_GetROBigBlock(
- LPBIGBLOCKFILE This,
- ULONG index)
-{
- /*
- * block index starts at -1
- * translate to zero based index
- */
- if (index == 0xffffffff)
- index = 0;
- else
- index++;
-
- /*
- * validate the block index
- *
- */
- if (This->blocksize * (index + 1)
- > ROUND_UP(This->filesize.u.LowPart, This->blocksize))
- {
- TRACE("out of range %u vs %u\n", This->blocksize * (index + 1),
- This->filesize.u.LowPart);
- return NULL;
- }
-
- return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ);
-}
-
-/******************************************************************************
* BIGBLOCKFILE_EnsureExists
*
* Grows the file if necessary to make sure the block is valid.
*/
void BIGBLOCKFILE_EnsureExists(LPBIGBLOCKFILE This, ULONG index)
{
+ STATSTG lkbyt_stat;
/*
* block index starts at -1
* translate to zero based index
@@ -369,7 +139,9 @@ void BIGBLOCKFILE_EnsureExists(LPBIGBLOC
/*
* make sure that the block physically exists
*/
- if ((This->blocksize * (index + 1)) > This->filesize.u.LowPart)
+ ILockBytes_Stat(This->pLkbyt,&lkbyt_stat,STATFLAG_NONAME);
+
+ if ((This->blocksize * (index + 1)) > lkbyt_stat.cbSize.u.LowPart)
{
ULARGE_INTEGER newSize;
@@ -381,49 +153,6 @@ void BIGBLOCKFILE_EnsureExists(LPBIGBLOC
}
/******************************************************************************
- * BIGBLOCKFILE_GetBigBlock
- *
- * Returns the specified block.
- * Will grow the file if necessary.
- */
-void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index)
-{
- /* FIXME: is this necessary? */
- BIGBLOCKFILE_EnsureExists(This, index);
-
- /*
- * block index starts at -1
- * translate to zero based index
- */
- if (index == 0xffffffff)
- index = 0;
- else
- index++;
-
- return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE);
-}
-
-/******************************************************************************
- * BIGBLOCKFILE_ReleaseBigBlock
- *
- * Releases the specified block.
- */
-void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock)
-{
- MappedPage *page;
-
- if (pBlock == NULL)
- return;
-
- page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock);
-
- if (page == NULL)
- return;
-
- BIGBLOCKFILE_ReleaseMappedPage(This, page);
-}
-
-/******************************************************************************
* BIGBLOCKFILE_SetSize
*
* Sets the size of the file.
@@ -431,441 +160,23 @@ void BIGBLOCKFILE_ReleaseBigBlock(LPBIGB
*/
void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize)
{
- if (This->filesize.u.LowPart == newSize.u.LowPart)
- return;
-
- TRACE("from %u to %u\n", This->filesize.u.LowPart, newSize.u.LowPart);
- /*
- * unmap all views, must be done before call to SetEndFile
- */
- BIGBLOCKFILE_UnmapAllMappedPages(This);
-
- if (This->fileBased)
- {
- LARGE_INTEGER newpos;
-
- 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);
- }
- }
- else
- {
- GlobalUnlock(This->hbytearray);
-
- /*
- * Resize the byte array object.
- */
- ILockBytes_SetSize(This->pLkbyt, newSize);
-
- /*
- * Re-acquire the handle, it may have changed.
- */
- GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray);
- This->pbytearray = GlobalLock(This->hbytearray);
- }
-
- This->filesize.u.LowPart = newSize.u.LowPart;
- This->filesize.u.HighPart = newSize.u.HighPart;
-
- BIGBLOCKFILE_RemapAllMappedPages(This);
-}
-
-/******************************************************************************
- * BIGBLOCKFILE_GetSize
- *
- * Returns the size of the file.
- *
- */
-ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This)
-{
- return This->filesize;
-}
-
-/******************************************************************************
- * BIGBLOCKFILE_AccessCheck [PRIVATE]
- *
- * block_index is the index within the page.
- */
-static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index,
- DWORD desired_access)
-{
- assert(block_index < BLOCKS_PER_PAGE);
-
- if (desired_access == FILE_MAP_READ)
- {
- if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index))
- return FALSE;
-
- BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index);
- }
- else
- {
- assert(desired_access == FILE_MAP_WRITE);
-
- if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index))
- return FALSE;
-
- BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index);
- }
-
- return TRUE;
+ ILockBytes_SetSize(This->pLkbyt, newSize);
}
-/******************************************************************************
- * BIGBLOCKFILE_GetBigBlockPointer [PRIVATE]
- *
- * Returns a pointer to the specified block.
- */
-static void* BIGBLOCKFILE_GetBigBlockPointer(
- LPBIGBLOCKFILE This,
- ULONG block_index,
- DWORD desired_access)
+HRESULT BIGBLOCKFILE_ReadAt(BigBlockFile* This,
+ ULARGE_INTEGER offset,
+ void* buffer,
+ ULONG size,
+ ULONG* bytesRead)
{
- DWORD page_index = block_index / BLOCKS_PER_PAGE;
- DWORD block_on_page = block_index % BLOCKS_PER_PAGE;
-
- MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index);
- if (!page || !page->lpBytes) return NULL;
-
- if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access))
- {
- BIGBLOCKFILE_ReleaseMappedPage(This, page);
- return NULL;
- }
-
- return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize);
+ return ILockBytes_ReadAt(This->pLkbyt,offset,buffer,size,bytesRead);
}
-/******************************************************************************
- * BIGBLOCKFILE_GetMappedPageFromPointer [PRIVATE]
- *
- * pBlock is a pointer to a block on a page.
- * The page has to be on the in-use list. (As oppsed to the victim list.)
- *
- * Does not increment the usage count.
- */
-static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
- void *pBlock)
+HRESULT BIGBLOCKFILE_WriteAt(BigBlockFile* This,
+ ULARGE_INTEGER offset,
+ void* buffer,
+ const ULONG size,
+ ULONG* bytesWritten)
{
- MappedPage *page;
-
- for (page = This->maplist; page != NULL; page = page->next)
- {
- if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes
- && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE)
- break;
-
- }
-
- return page;
-}
-
-/******************************************************************************
- * 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;
-}
-
-/******************************************************************************
- * 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--;
-
- BIGBLOCKFILE_Zero(&page->readable_blocks);
- BIGBLOCKFILE_Zero(&page->writable_blocks);
- }
- }
-
- 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 BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page)
-{
- DWORD lowoffset = PAGE_SIZE * page->page_index;
-
- if (This->fileBased)
- {
- DWORD numBytesToMap;
- DWORD desired_access;
-
- 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);
- }
- else
- {
- page->lpBytes = (LPBYTE)This->pbytearray + lowoffset;
- }
-
- TRACE("mapped page %u to %p\n", page->page_index, page->lpBytes);
-
- return page->lpBytes != NULL;
-}
-
-static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE 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;
-
- BIGBLOCKFILE_MapPage(This, page);
-
- BIGBLOCKFILE_Zero(&page->readable_blocks);
- BIGBLOCKFILE_Zero(&page->writable_blocks);
-
- return page;
-}
-
-static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page)
-{
- TRACE("%d at %p\n", page->page_index, page->lpBytes);
- if (page->refcnt > 0)
- ERR("unmapping inuse page %p\n", page->lpBytes);
-
- if (This->fileBased && 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
- *
- * This function will return a protection mode flag for a file-mapping object
- * from the open flags of a file.
- */
-static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags)
-{
- switch(STGM_ACCESS_MODE(openFlags))
- {
- case STGM_WRITE:
- case STGM_READWRITE:
- return PAGE_READWRITE;
- }
- return PAGE_READONLY;
+ return ILockBytes_WriteAt(This->pLkbyt,offset,buffer,size,bytesWritten);
}
diff --git a/dlls/ole32/stg_filelockbytes.c b/dlls/ole32/stg_filelockbytes.c
new file mode 100644
index 0000000..4644561
--- /dev/null
+++ b/dlls/ole32/stg_filelockbytes.c
@@ -0,0 +1,894 @@
+/******************************************************************************
+ *
+ * File implementation of ILockBytes.
+ *
+ * Copyright 2007 CodeWeavers, Aric Stewart
+ *
+ * Much insiprition and code from memlockbytes.c and stg_bigblockfile.c
+ * both Copyright 1999 Thuy Nguyen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "objbase.h"
+#include "ole2.h"
+#include "winerror.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(storage);
+
+/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
+#define PAGE_SIZE 131072
+
+/***
+ * 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;
+ LPVOID lpBytes;
+ LONG refcnt;
+ ULONG mapped_bytes;
+};
+
+/******************************************************************************
+ * FileLockBytesImpl definition.
+ *
+ * This class implements the ILockBytes interface and represents a byte array
+ * object supported by an file on disk.
+ */
+struct FileLockBytesImpl
+{
+ /*
+ * ILockBytes
+ */
+ const ILockBytesVtbl *lpVtbl;
+
+ /*
+ * Reference count
+ */
+ LONG ref;
+
+ /*
+ * For compatibility with memLockBytes and GetHGlobalFromILockBytes
+ * This should always be NULL
+ */
+ HGLOBAL supportHandle;
+
+ /*
+ * Support for the LockBytes object
+ */
+ HANDLE fileHandle;
+ BOOL bCloseHandle;
+ ULARGE_INTEGER filesize;
+ HANDLE hfilemap;
+ DWORD flProtect;
+ MappedPage *maplist;
+ MappedPage *victimhead, *victimtail;
+ ULONG num_victim_pages;
+ ULONG max_victim_pages;
+};
+
+typedef struct FileLockBytesImpl FileLockBytesImpl;
+
+/*
+ * Method definition for the FileLockBytes class.
+ */
+static FileLockBytesImpl* FileLockBytesImpl_Construct(HANDLE hFile,
+ DWORD openFlags,
+ BOOL bCloseHandle,
+ UINT cached_pages);
+
+static void FileLockBytesImpl_Destroy(FileLockBytesImpl* This);
+
+static HRESULT WINAPI FileLockBytesImpl_SetSize( ILockBytes* iface, ULARGE_INTEGER libNewSize );
+
+
+static const ILockBytesVtbl FileLockBytesImpl_Vtbl;
+
+
+/* Private Prototypes */
+static void FileLockBytesImpl_FreeAllMappedPages(FileLockBytesImpl* This);
+static MappedPage* FileLockBytesImpl_GetMappedPage(
+ FileLockBytesImpl* This,
+ DWORD page_index);
+static void FileLockBytesImpl_ReleaseMappedPage( FileLockBytesImpl *This,
+ MappedPage *page);
+static void FileLockBytesImpl_RemapList( FileLockBytesImpl *This,
+ MappedPage *list);
+static void FileLockBytesImpl_UnmapPage( FileLockBytesImpl* This,
+ MappedPage *page);
+
+
+
+/******************************************************************************
+ *
+ * FileLockBytesImpl implementation
+ *
+ */
+
+/******************************************************************************
+ * This is the constructor for the FileLockBytesImpl class.
+ *
+ * PARAMS
+ * hFile [ I] Handle that will support the stream.
+ * openFlags [I] Storage open flags;
+ * bCloseHandle [I] set if the LockBytes implementation should close the
+ * file handle on release.
+ */
+static FileLockBytesImpl* FileLockBytesImpl_Construct(HANDLE hFile,
+ DWORD openFlags, BOOL bCloseHandle, UINT cached_pages)
+{
+ FileLockBytesImpl* newLockBytes;
+
+ /* some parameter checking */
+ if (hFile == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(FileLockBytesImpl));
+
+ if (newLockBytes != 0)
+ {
+ /*
+ * Set up the virtual function table and reference count.
+ */
+ newLockBytes->lpVtbl = &FileLockBytesImpl_Vtbl;
+ newLockBytes->ref = 0;
+
+ /*
+ * Initialize the support.
+ */
+ newLockBytes->supportHandle = NULL;
+ newLockBytes->fileHandle = hFile;
+ newLockBytes->bCloseHandle = bCloseHandle;
+ switch (openFlags&0x0000f)
+ {
+ case STGM_WRITE:
+ case STGM_READWRITE:
+ newLockBytes->flProtect = PAGE_READWRITE;
+ break;
+ default:
+ newLockBytes->flProtect = PAGE_READONLY;
+ }
+ newLockBytes->maplist = NULL;
+ newLockBytes->victimhead = NULL;
+ newLockBytes->victimtail = NULL;
+ newLockBytes->num_victim_pages = 0;
+ newLockBytes->max_victim_pages = cached_pages;
+ newLockBytes->filesize.u.LowPart = GetFileSize(hFile,
+ &newLockBytes->filesize.u.HighPart);
+ if (newLockBytes->filesize.u.LowPart ||
+ newLockBytes->filesize.u.HighPart)
+ {
+ newLockBytes->hfilemap = CreateFileMappingW(hFile, NULL,
+ newLockBytes->flProtect,
+ 0,0,NULL);
+ if (!newLockBytes->hfilemap)
+ {
+ TRACE("Unable to map file\n");
+ HeapFree(GetProcessHeap(),0,newLockBytes);
+ if (bCloseHandle)
+ CloseHandle(hFile);
+ return NULL;
+ }
+ }
+ else
+ newLockBytes->hfilemap = NULL;
+ }
+
+ return newLockBytes;
+}
+
+/******************************************************************************
+ * This is the destructor of the FileStreamImpl class.
+ *
+ * This method will clean-up all the resources used-up by the given
+ * FileLockBytesImpl class. The pointer passed-in to this function will be
+ * freed and will not be valid anymore.
+ */
+static void FileLockBytesImpl_Destroy(FileLockBytesImpl* This)
+{
+ FileLockBytesImpl_FreeAllMappedPages(This);
+
+ if (This->bCloseHandle)
+ CloseHandle(This->fileHandle);
+ CloseHandle(This->hfilemap);
+
+ /*
+ * Finally, free the memory used-up by the class.
+ */
+ HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ * This implements the IUnknown method QueryInterface for this
+ * class
+ */
+static HRESULT WINAPI FileLockBytesImpl_QueryInterface(
+ ILockBytes* iface,
+ REFIID riid, /* [in] */
+ void** ppvObject) /* [iid_is][out] */
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+
+ /*
+ * Perform a sanity check on the parameters.
+ */
+ if (ppvObject==0)
+ return E_INVALIDARG;
+
+ /*
+ * Initialize the return parameter.
+ */
+ *ppvObject = 0;
+
+ /*
+ * Compare the riid with the interface IDs implemented by this object.
+ */
+ if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
+ {
+ *ppvObject = (ILockBytes*)This;
+ }
+ else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0)
+ {
+ *ppvObject = (ILockBytes*)This;
+ }
+
+ /*
+ * Check that we obtained an interface.
+ */
+ if ((*ppvObject)==0)
+ return E_NOINTERFACE;
+
+ /*
+ * Query Interface always increases the reference count by one when it is
+ * successful
+ */
+ IUnknown_AddRef(iface);
+
+ return S_OK;
+}
+
+/******************************************************************************
+ * This implements the IUnknown method AddRef for this
+ * class
+ */
+static ULONG WINAPI FileLockBytesImpl_AddRef(ILockBytes* iface)
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+ return InterlockedIncrement(&This->ref);
+}
+
+/******************************************************************************
+ * This implements the IUnknown method Release for this
+ * class
+ */
+static ULONG WINAPI FileLockBytesImpl_Release(ILockBytes* iface)
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+ ULONG ref;
+
+ ref = InterlockedDecrement(&This->ref);
+
+ /*
+ * If the reference count goes down to 0, perform suicide.
+ */
+ if (ref==0)
+ {
+ FileLockBytesImpl_Destroy(This);
+ }
+
+ return ref;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * It reads a block of information from the byte array at the specified
+ * offset.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_ReadAt(
+ ILockBytes* iface,
+ ULARGE_INTEGER ulOffset, /* [in] */
+ void* pv, /* [length_is][size_is][out] */
+ ULONG cb, /* [in] */
+ ULONG* pcbRead) /* [out] */
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+ 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;
+
+ TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbRead);
+
+ /* verify a sane enviroment */
+ 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 = FileLockBytesImpl_GetMappedPage(This, page_index);
+
+ if (!page || !page->lpBytes)
+ {
+ rc = STG_E_READFAULT;
+ break;
+ }
+
+ 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 (page->mapped_bytes < bytes_from_page)
+ {
+ eof = TRUE;
+ bytes_from_page = page->mapped_bytes;
+ }
+
+ readPtr = (BYTE*)page->lpBytes + offset_in_page;
+ memcpy(writePtr,readPtr,bytes_from_page);
+ FileLockBytesImpl_ReleaseMappedPage(This, page);
+
+ if (pcbRead)
+ *pcbRead += bytes_from_page;
+ bytes_left -= bytes_from_page;
+
+ 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;
+ }
+ }
+
+ TRACE("finished\n");
+ return rc;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * It writes the specified bytes at the specified offset.
+ * position. If the file is too small, it will be resized.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_WriteAt(
+ ILockBytes* iface,
+ ULARGE_INTEGER ulOffset, /* [in] */
+ const void* pv, /* [size_is][in] */
+ ULONG cb, /* [in] */
+ ULONG* pcbWritten) /* [out] */
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+ 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;
+
+ TRACE("(%p)-> %i %p %i %p\n",This, ulOffset.u.LowPart, pv, cb, pcbWritten);
+
+ /* verify a sane enviroment */
+ if (!This) return E_FAIL;
+
+ if (This->flProtect != PAGE_READWRITE)
+ return STG_E_ACCESSDENIED;
+
+ if (size_needed > This->filesize.u.LowPart)
+ {
+ ULARGE_INTEGER newSize;
+ newSize.u.HighPart = 0;
+ newSize.u.LowPart = size_needed;
+ FileLockBytesImpl_SetSize(iface, newSize);
+ }
+
+ if (offset_in_page + bytes_left > PAGE_SIZE)
+ bytes_to_page = PAGE_SIZE - offset_in_page;
+ else
+ bytes_to_page = bytes_left;
+
+ if (pcbWritten)
+ *pcbWritten = 0;
+
+ while (bytes_left)
+ {
+ LPBYTE writePtr;
+ MappedPage *page = FileLockBytesImpl_GetMappedPage(This, page_index);
+
+ TRACE("page %i, offset %u, bytes_to_page %u, bytes_left %u\n",
+ page->page_index, offset_in_page, bytes_to_page, bytes_left);
+
+ if (page->mapped_bytes < bytes_to_page)
+ {
+ ERR("Not enough bytes mapped to the page. This should never happen\n");
+ rc = E_FAIL;
+ break;
+ }
+
+ if (!page)
+ {
+ ERR("Unable to get a page to write. This should never happen\n");
+ rc = E_FAIL;
+ break;
+ }
+
+ writePtr = (BYTE*)page->lpBytes + offset_in_page;
+ memcpy(writePtr,readPtr,bytes_to_page);
+ FileLockBytesImpl_ReleaseMappedPage(This, page);
+
+ if (pcbWritten)
+ *pcbWritten += bytes_to_page;
+ bytes_left -= bytes_to_page;
+
+ if (bytes_left)
+ {
+ readPtr = (LPBYTE)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;
+ }
+ }
+
+ return rc;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_Flush(ILockBytes* iface)
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+ FileLockBytesImpl_RemapList( This, This->maplist);
+ FileLockBytesImpl_RemapList( This, This->victimhead);
+
+ return S_OK;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * It will change the size of the byte array.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_SetSize(
+ ILockBytes* iface,
+ ULARGE_INTEGER libNewSize) /* [in] */
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+ MappedPage *list;
+ LARGE_INTEGER newpos;
+ HRESULT rc = S_OK;
+
+ if (This->filesize.u.LowPart == libNewSize.u.LowPart)
+ return S_OK;
+
+ TRACE("SetSize from %u to %u\n",This->filesize.u.LowPart,libNewSize.u.LowPart);
+
+ /* unmap all the pages */
+ list = This->maplist;
+ for (; list != NULL; list = list->next)
+ FileLockBytesImpl_UnmapPage(This,list);
+ list = This->victimhead;
+ for (; list != NULL; list = list->next)
+ FileLockBytesImpl_UnmapPage(This,list);
+
+ newpos.QuadPart = libNewSize.QuadPart;
+ if (SetFilePointerEx(This->fileHandle, newpos, NULL, FILE_BEGIN))
+ {
+ if (This->hfilemap)
+ CloseHandle(This->hfilemap);
+ SetEndOfFile(This->fileHandle);
+
+ This->hfilemap = CreateFileMappingW(This->fileHandle,
+ NULL,
+ This->flProtect,
+ 0, 0,
+ NULL);
+
+ This->filesize.u.LowPart = libNewSize.u.LowPart;
+ This->filesize.u.HighPart = libNewSize.u.HighPart;
+ }
+ else
+ rc = E_FAIL;
+
+ FileLockBytesImpl_RemapList(This,This->maplist);
+ FileLockBytesImpl_RemapList(This,This->victimhead);
+
+ return rc;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_LockRegion(
+ ILockBytes* iface,
+ ULARGE_INTEGER libOffset, /* [in] */
+ ULARGE_INTEGER cb, /* [in] */
+ DWORD dwLockType) /* [in] */
+{
+ return E_NOTIMPL;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_UnlockRegion(
+ ILockBytes* iface,
+ ULARGE_INTEGER libOffset, /* [in] */
+ ULARGE_INTEGER cb, /* [in] */
+ DWORD dwLockType) /* [in] */
+{
+ return E_NOTIMPL;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * This method returns information about the current
+ * byte array object.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+static HRESULT WINAPI FileLockBytesImpl_Stat(
+ ILockBytes* iface,
+ STATSTG* pstatstg, /* [out] */
+ DWORD grfStatFlag) /* [in] */
+{
+ FileLockBytesImpl* const This=(FileLockBytesImpl*)iface;
+
+ memset(pstatstg, 0, sizeof(STATSTG));
+
+ pstatstg->pwcsName = NULL;
+ pstatstg->type = STGTY_LOCKBYTES;
+ pstatstg->cbSize = This->filesize;
+
+ return S_OK;
+}
+
+
+/*************************************************************
+ * Private Functions
+ */
+static void FileLockBytesImpl_UnmapPage( FileLockBytesImpl* This,
+ MappedPage *page)
+{
+ BOOL rc = 1;
+
+ if (page->lpBytes || page->mapped_bytes)
+ rc = UnmapViewOfFile(page->lpBytes);
+ if (rc == 0)
+ ERR("Error unmaping page (%p)\n",page->lpBytes);
+
+ page->lpBytes = NULL;
+ page->mapped_bytes = 0;
+}
+
+static void FileLockBytesImpl_DeletePage( FileLockBytesImpl* This,
+ MappedPage *page)
+{
+ /* force the unmap */
+ FileLockBytesImpl_UnmapPage(This, page);
+
+ HeapFree(GetProcessHeap(),0,page);
+}
+
+static void FileLockBytesImpl_FreeAllMappedPages( FileLockBytesImpl* This)
+{
+ while (This->maplist != NULL)
+ {
+ MappedPage *next = This->maplist->next;
+ FileLockBytesImpl_DeletePage(This, This->maplist);
+ This->maplist = next;
+ }
+
+ while (This->victimhead != NULL)
+ {
+ MappedPage *next = This->victimhead->next;
+ FileLockBytesImpl_DeletePage(This, This->victimhead);
+ This->victimhead = next;
+ }
+
+ This->maplist = NULL;
+ This->victimhead = NULL;
+ This->victimtail = NULL;
+ This->num_victim_pages = 0;
+}
+
+static void FileLockBytesImpl_UnlinkPage(MappedPage *page)
+{
+ if (page->next) page->next->prev = page->prev;
+ if (page->prev) page->prev->next = page->next;
+}
+
+static void FileLockBytesImpl_LinkHeadPage(MappedPage **head, MappedPage *page)
+{
+ if (*head) (*head)->prev = page;
+ page->next = *head;
+ page->prev = NULL;
+ *head = page;
+}
+
+static BOOL FileLockBytesImpl_MapPage(FileLockBytesImpl *This, MappedPage *page)
+{
+ DWORD file_lowoffset = PAGE_SIZE * page->page_index;
+ DWORD numBytesToMap;
+ DWORD desired_access;
+
+ if (file_lowoffset + PAGE_SIZE > This->filesize.u.LowPart)
+ numBytesToMap = This->filesize.u.LowPart - file_lowoffset;
+ else
+ numBytesToMap = PAGE_SIZE;
+
+ if (page->lpBytes)
+ {
+ BOOL rc;
+ rc = FlushViewOfFile(page->lpBytes,page->mapped_bytes);
+ if (rc == 0)
+ ERR("Problems flushing page %u\n",page->page_index);
+ }
+
+ desired_access = (This->flProtect == PAGE_READONLY)?FILE_MAP_READ:FILE_MAP_WRITE;
+ page->mapped_bytes = numBytesToMap;
+
+ page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0,
+ file_lowoffset, numBytesToMap);
+
+ TRACE("mapped page %u to %p %i\n",page->page_index, page->lpBytes,
+ numBytesToMap);
+
+ return page->lpBytes != NULL;
+}
+
+static MappedPage* FileLockBytesImpl_CreatePage( FileLockBytesImpl * This,
+ ULONG page_index)
+{
+ MappedPage *page;
+
+ page = HeapAlloc(GetProcessHeap(),0, sizeof (MappedPage));
+ if (!page)
+ return NULL;
+
+ page->page_index = page_index;
+ page->refcnt = 1;
+
+ page->next = NULL;
+ page->prev = NULL;
+ page->lpBytes = NULL;
+
+ if (!FileLockBytesImpl_MapPage(This,page))
+ {
+ ERR("Unable to map page %i\n",page_index);
+ HeapFree(GetProcessHeap(),0,page);
+ return NULL;
+ }
+
+ return page;
+}
+
+static void FileLockBytesImpl_RemapList( FileLockBytesImpl *This,
+ MappedPage *list)
+{
+ MappedPage *ptr = list;
+ while (ptr != NULL)
+ {
+ MappedPage *next = ptr->next;
+ if (ptr->page_index * PAGE_SIZE > This->filesize.u.LowPart)
+ {
+ TRACE("discarding %u beyond EOF\n",ptr->page_index);
+ FileLockBytesImpl_UnlinkPage(ptr);
+ FileLockBytesImpl_DeletePage(This,ptr);
+ }
+ else
+ FileLockBytesImpl_MapPage(This,ptr);
+
+ ptr = next;
+ }
+}
+
+static MappedPage* FileLockBytesImpl_FindPageInList(MappedPage *head,
+ ULONG page_index)
+{
+ for (;head != NULL; head = head->next)
+ if (head->page_index == page_index)
+ break;
+
+ return head;
+}
+
+static MappedPage* FileLockBytesImpl_GetMappedPage(
+ FileLockBytesImpl* This,
+ DWORD page_index)
+{
+ MappedPage *page;
+
+ page = FileLockBytesImpl_FindPageInList(This->maplist, page_index);
+ if (!page)
+ {
+ page = FileLockBytesImpl_FindPageInList(This->victimhead, page_index);
+ if (page)
+ This->num_victim_pages --;
+ }
+ if (page)
+ {
+ InterlockedIncrement(&page->refcnt);
+ /* Move page to head to active list */
+ if (This->maplist != page)
+ {
+ if (This->victimhead == page) This->victimhead = page->next;
+ if (This->victimtail == page) This->victimtail = page->prev;
+
+ FileLockBytesImpl_UnlinkPage(page);
+
+ FileLockBytesImpl_LinkHeadPage(&This->maplist, page);
+ }
+ return page;
+ }
+
+ page = FileLockBytesImpl_CreatePage(This, page_index);
+ if (!page)
+ return NULL;
+
+ FileLockBytesImpl_LinkHeadPage(&This->maplist, page);
+
+ return page;
+}
+
+static void FileLockBytesImpl_ReleaseMappedPage(
+ FileLockBytesImpl *This, MappedPage *page)
+{
+ /*
+ * if refcount is reduced to 0 then it moves to the victim list
+ * and if the victim list is too long then someone gets freed
+ */
+
+ /*
+ * TODO: Do we need to flush anything?
+ */
+
+ if (!InterlockedDecrement(&page->refcnt))
+ {
+ if (This->maplist == page)
+ This->maplist = page->next;
+
+ FileLockBytesImpl_UnlinkPage(page);
+
+ if (This->max_victim_pages > 0)
+ {
+ if ( This->num_victim_pages >= This->max_victim_pages )
+ {
+ MappedPage *victim = This->victimtail;
+ if (victim)
+ {
+ This->victimtail = victim->prev;
+ if (This->victimhead == victim)
+ This->victimhead = victim->next;
+
+ FileLockBytesImpl_UnlinkPage(victim);
+ FileLockBytesImpl_DeletePage(This,victim);
+ }
+ }
+ else This->num_victim_pages ++;
+
+ FileLockBytesImpl_LinkHeadPage(&This->victimhead, page);
+ if (This->victimtail == NULL)
+ This->victimtail = page;
+ }
+ else
+ FileLockBytesImpl_DeletePage(This, page);
+ }
+}
+
+/*
+ * Virtual function table for the FileLockBytesImpl class.
+ */
+static const ILockBytesVtbl FileLockBytesImpl_Vtbl =
+{
+ FileLockBytesImpl_QueryInterface,
+ FileLockBytesImpl_AddRef,
+ FileLockBytesImpl_Release,
+ FileLockBytesImpl_ReadAt,
+ FileLockBytesImpl_WriteAt,
+ FileLockBytesImpl_Flush,
+ FileLockBytesImpl_SetSize,
+ FileLockBytesImpl_LockRegion,
+ FileLockBytesImpl_UnlockRegion,
+ FileLockBytesImpl_Stat,
+};
+
+
+
+HRESULT WINAPI CreateILockBytesOnFile(HANDLE hFile,
+ DWORD fFlags,
+ BOOL fDeleteOnRelease,
+ LPLOCKBYTES* ppLkbyt)
+{
+ FileLockBytesImpl* newLockBytes;
+
+ newLockBytes = FileLockBytesImpl_Construct(hFile, fFlags, fDeleteOnRelease,
+ 16);
+
+ if (newLockBytes != NULL)
+ {
+ return IUnknown_QueryInterface((IUnknown*)newLockBytes,
+ &IID_ILockBytes,
+ (void**)ppLkbyt);
+ }
+
+ return E_OUTOFMEMORY;
+}
diff --git a/dlls/ole32/storage32.c b/dlls/ole32/storage32.c
index dc2db11..2d10174 100644
--- a/dlls/ole32/storage32.c
+++ b/dlls/ole32/storage32.c
@@ -84,9 +84,6 @@ typedef struct StorageInternalImpl Stora
static StorageInternalImpl* StorageInternalImpl_Construct(StorageImpl* ancestorStorage,
DWORD openFlags, ULONG rootTropertyIndex);
static void StorageImpl_Destroy(StorageBaseImpl* iface);
-static void* StorageImpl_GetBigBlock(StorageImpl* This, ULONG blockIndex);
-static void* StorageImpl_GetROBigBlock(StorageImpl* This, ULONG blockIndex);
-static void StorageImpl_ReleaseBigBlock(StorageImpl* This, void* pBigBlock);
static BOOL StorageImpl_ReadBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
static BOOL StorageImpl_WriteBigBlock(StorageImpl* This, ULONG blockIndex, void* buffer);
static void StorageImpl_SetNextBlockInChain(StorageImpl* This, ULONG blockIndex, ULONG nextBlock);
@@ -104,7 +101,10 @@ static ULARGE_INTEGER BlockChainStream_G
static ULONG BlockChainStream_GetCount(BlockChainStream* This);
static ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This);
-
+static BOOL StorageImpl_WriteDWordToBigBlock( StorageImpl* This,
+ ULONG blockIndex, ULONG offset, DWORD value);
+static BOOL StorageImpl_ReadDWordFromBigBlock( StorageImpl* This,
+ ULONG blockIndex, ULONG offset, DWORD* value);
/* OLESTREAM memory structure to use for Get and Put Routines */
/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
@@ -245,10 +245,40 @@ static ULONG IEnumSTATSTGImpl_FindProper
static INT IEnumSTATSTGImpl_FindParentProperty(IEnumSTATSTGImpl *This, ULONG childProperty,
StgProperty *currentProperty, ULONG *propertyId);
+/************************************************************************
+** Block Functions
+*/
+
+static ULONG BLOCK_GetBigBlockOffset(ULONG index)
+{
+ if (index == 0xffffffff)
+ index = 0;
+ else
+ index ++;
+
+ return index * BIG_BLOCK_SIZE;
+}
/************************************************************************
** Storage32BaseImpl implementatiion
*/
+static HRESULT StorageImpl_ReadAt(StorageImpl* This,
+ ULARGE_INTEGER offset,
+ void* buffer,
+ ULONG size,
+ ULONG* bytesRead)
+{
+ return BIGBLOCKFILE_ReadAt(This->bigBlockFile,offset,buffer,size,bytesRead);
+}
+
+static HRESULT StorageImpl_WriteAt(StorageImpl* This,
+ ULARGE_INTEGER offset,
+ void* buffer,
+ const ULONG size,
+ ULONG* bytesWritten)
+{
+ return BIGBLOCKFILE_WriteAt(This->bigBlockFile,offset,buffer,size,bytesWritten);
+}
/************************************************************************
* Storage32BaseImpl_QueryInterface (IUnknown)
@@ -2417,7 +2447,7 @@ static HRESULT StorageImpl_Construct(
if (fileCreate)
{
ULARGE_INTEGER size;
- BYTE* bigBlockBuffer;
+ BYTE bigBlockBuffer[BIG_BLOCK_SIZE];
/*
* Initialize all header variables:
@@ -2450,11 +2480,10 @@ static HRESULT StorageImpl_Construct(
/*
* Initialize the big block depot
*/
- bigBlockBuffer = StorageImpl_GetBigBlock(This, 0);
memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
- StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+ StorageImpl_WriteBigBlock(This, 0, bigBlockBuffer);
}
else
{
@@ -2586,7 +2615,8 @@ static ULONG StorageImpl_GetNextFreeBigB
StorageImpl* This)
{
ULONG depotBlockIndexPos;
- void *depotBuffer;
+ BYTE depotBuffer[BIG_BLOCK_SIZE];
+ BOOL success;
ULONG depotBlockOffset;
ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG);
ULONG nextBlockIndex = BLOCK_SPECIAL;
@@ -2679,9 +2709,9 @@ static ULONG StorageImpl_GetNextFreeBigB
}
}
- depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+ success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
- if (depotBuffer != 0)
+ if (success)
{
while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
( nextBlockIndex != BLOCK_UNUSED))
@@ -2696,8 +2726,6 @@ static ULONG StorageImpl_GetNextFreeBigB
depotBlockOffset += sizeof(ULONG);
}
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
}
depotIndex++;
@@ -2722,16 +2750,13 @@ static ULONG StorageImpl_GetNextFreeBigB
*/
static void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
{
- BYTE* blockBuffer;
-
- blockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+ BYTE blockBuffer[BIG_BLOCK_SIZE];
/*
* Initialize blocks as free
*/
memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
-
- StorageImpl_ReleaseBigBlock(This, blockBuffer);
+ StorageImpl_WriteBigBlock(This, blockIndex, blockBuffer);
}
/******************************************************************************
@@ -2762,20 +2787,8 @@ static ULONG Storage32Impl_GetExtDepotBl
}
if (extBlockIndex != BLOCK_UNUSED)
- {
- BYTE* depotBuffer;
-
- depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex);
-
- if (depotBuffer != 0)
- {
- StorageUtl_ReadDWord(depotBuffer,
- extBlockOffset * sizeof(ULONG),
- &blockIndex);
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
- }
+ StorageImpl_ReadDWordFromBigBlock(This, extBlockIndex,
+ extBlockOffset * sizeof(ULONG), &blockIndex);
return blockIndex;
}
@@ -2805,18 +2818,9 @@ static void Storage32Impl_SetExtDepotBlo
if (extBlockIndex != BLOCK_UNUSED)
{
- BYTE* depotBuffer;
-
- depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex);
-
- if (depotBuffer != 0)
- {
- StorageUtl_WriteDWord(depotBuffer,
- extBlockOffset * sizeof(ULONG),
- blockIndex);
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
+ StorageImpl_WriteDWordToBigBlock(This, extBlockIndex,
+ extBlockOffset * sizeof(ULONG),
+ blockIndex);
}
}
@@ -2829,7 +2833,7 @@ static ULONG Storage32Impl_AddExtBlockDe
{
ULONG numExtBlocks = This->extBigBlockDepotCount;
ULONG nextExtBlock = This->extBigBlockDepotStart;
- BYTE* depotBuffer = NULL;
+ BYTE depotBuffer[BIG_BLOCK_SIZE];
ULONG index = BLOCK_UNUSED;
ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG);
ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG);
@@ -2859,17 +2863,15 @@ static ULONG Storage32Impl_AddExtBlockDe
/*
* Add the new extended block to the chain.
*/
- depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock);
- StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
+ StorageImpl_WriteDWordToBigBlock(This, nextExtBlock, nextBlockOffset,
+ index);
}
/*
* Initialize this block.
*/
- depotBuffer = StorageImpl_GetBigBlock(This, index);
memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
+ StorageImpl_WriteBigBlock(This, index, depotBuffer);
return index;
}
@@ -2921,7 +2923,8 @@ static HRESULT StorageImpl_GetNextBlockI
ULONG offsetInDepot = blockIndex * sizeof (ULONG);
ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
- void* depotBuffer;
+ BYTE depotBuffer[BIG_BLOCK_SIZE];
+ BOOL success;
ULONG depotBlockIndexPos;
int index;
@@ -2953,9 +2956,9 @@ static HRESULT StorageImpl_GetNextBlockI
depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
}
- depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+ success = StorageImpl_ReadBigBlock(This, depotBlockIndexPos, depotBuffer);
- if (!depotBuffer)
+ if (!success)
return STG_E_READFAULT;
for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++)
@@ -2963,7 +2966,6 @@ static HRESULT StorageImpl_GetNextBlockI
StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex);
This->blockDepotCached[index] = *nextBlockIndex;
}
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
}
*nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
@@ -2990,16 +2992,9 @@ static ULONG Storage32Impl_GetNextExtend
{
ULONG nextBlockIndex = BLOCK_SPECIAL;
ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
- void* depotBuffer;
- depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
-
- if (depotBuffer!=0)
- {
- StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
-
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
+ StorageImpl_ReadDWordFromBigBlock(This, blockIndex, depotBlockOffset,
+ &nextBlockIndex);
return nextBlockIndex;
}
@@ -3027,7 +3022,6 @@ static void StorageImpl_SetNextBlockInCh
ULONG depotBlockCount = offsetInDepot / This->bigBlockSize;
ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
ULONG depotBlockIndexPos;
- void* depotBuffer;
assert(depotBlockCount < This->bigBlockDepotCount);
assert(blockIndex != nextBlock);
@@ -3044,14 +3038,8 @@ static void StorageImpl_SetNextBlockInCh
depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
}
- depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
-
- if (depotBuffer!=0)
- {
- StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
- StorageImpl_ReleaseBigBlock(This, depotBuffer);
- }
-
+ StorageImpl_WriteDWordToBigBlock(This, depotBlockIndexPos, depotBlockOffset,
+ nextBlock);
/*
* Update the cached block depot, if necessary.
*/
@@ -3070,19 +3058,20 @@ static HRESULT StorageImpl_LoadFileHeade
StorageImpl* This)
{
HRESULT hr = STG_E_FILENOTFOUND;
- void* headerBigBlock = NULL;
+ BYTE headerBigBlock[BIG_BLOCK_SIZE];
+ BOOL success;
int index;
TRACE("\n");
/*
* Get a pointer to the big block of data containing the header.
*/
- headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
+ success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
/*
* Extract the information from the header.
*/
- if (headerBigBlock!=0)
+ if (success)
{
/*
* Check for the "magic number" signature and return an error if it is not
@@ -3090,13 +3079,11 @@ static HRESULT StorageImpl_LoadFileHeade
*/
if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
{
- StorageImpl_ReleaseBigBlock(This, headerBigBlock);
return STG_E_OLDFORMAT;
}
if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
{
- StorageImpl_ReleaseBigBlock(This, headerBigBlock);
return STG_E_INVALIDHEADER;
}
@@ -3169,11 +3156,6 @@ static HRESULT StorageImpl_LoadFileHeade
}
else
hr = S_OK;
-
- /*
- * Release the block.
- */
- StorageImpl_ReleaseBigBlock(This, headerBigBlock);
}
return hr;
@@ -3472,20 +3454,33 @@ static BOOL StorageImpl_ReadBigBlock(
ULONG blockIndex,
void* buffer)
{
- void* bigBlockBuffer;
+ ULARGE_INTEGER ulOffset;
+ DWORD read;
- bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
- if (bigBlockBuffer!=0)
- {
- memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
+ StorageImpl_ReadAt(This, ulOffset, buffer, This->bigBlockSize, &read);
+ return (read == This->bigBlockSize);
+}
- StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+static BOOL StorageImpl_ReadDWordFromBigBlock(
+ StorageImpl* This,
+ ULONG blockIndex,
+ ULONG offset,
+ DWORD* value)
+{
+ ULARGE_INTEGER ulOffset;
+ DWORD read;
+ DWORD tmp;
- return TRUE;
- }
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
+ ulOffset.u.LowPart += offset;
- return FALSE;
+ StorageImpl_ReadAt(This, ulOffset, &tmp, sizeof(DWORD), &read);
+ *value = le32toh(tmp);
+ return (read == sizeof(DWORD));
}
static BOOL StorageImpl_WriteBigBlock(
@@ -3493,41 +3488,32 @@ static BOOL StorageImpl_WriteBigBlock(
ULONG blockIndex,
void* buffer)
{
- void* bigBlockBuffer;
-
- bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+ ULARGE_INTEGER ulOffset;
+ DWORD wrote;
- if (bigBlockBuffer!=0)
- {
- memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
-
- StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
- return TRUE;
- }
-
- return FALSE;
+ StorageImpl_WriteAt(This, ulOffset, buffer, This->bigBlockSize, &wrote);
+ return (wrote == This->bigBlockSize);
}
-static void* StorageImpl_GetROBigBlock(
+static BOOL StorageImpl_WriteDWordToBigBlock(
StorageImpl* This,
- ULONG blockIndex)
+ ULONG blockIndex,
+ ULONG offset,
+ DWORD value)
{
- return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
-}
+ ULARGE_INTEGER ulOffset;
+ DWORD wrote;
-static void* StorageImpl_GetBigBlock(
- StorageImpl* This,
- ULONG blockIndex)
-{
- return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
-}
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex);
+ ulOffset.u.LowPart += offset;
-static void StorageImpl_ReleaseBigBlock(
- StorageImpl* This,
- void* pBigBlock)
-{
- BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
+ value = htole32(value);
+ StorageImpl_WriteAt(This, ulOffset, &value, sizeof(DWORD), &wrote);
+ return (wrote == sizeof(DWORD));
}
/******************************************************************************
@@ -4518,7 +4504,8 @@ HRESULT BlockChainStream_ReadAt(BlockCha
ULONG bytesToReadInBuffer;
ULONG blockIndex;
BYTE* bufferWalker;
- BYTE* bigBlockBuffer;
+
+ TRACE("(%p)-> %i %p %i %p\n",This, offset.u.LowPart, buffer, size, bytesRead);
/*
* Find the first block in the stream that contains part of the buffer.
@@ -4559,35 +4546,37 @@ HRESULT BlockChainStream_ReadAt(BlockCha
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
{
+ ULARGE_INTEGER ulOffset;
+ DWORD bytesReadAt;
/*
* Calculate how many bytes we can copy from this big block.
*/
bytesToReadInBuffer =
min(This->parentStorage->bigBlockSize - offsetInBlock, size);
- /*
- * Copy those bytes to the buffer
- */
- bigBlockBuffer =
- StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
- if (!bigBlockBuffer)
- return STG_E_READFAULT;
-
- memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
-
- StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+ TRACE("block %i\n",blockIndex);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
+ offsetInBlock;
+ StorageImpl_ReadAt(This->parentStorage,
+ ulOffset,
+ bufferWalker,
+ bytesToReadInBuffer,
+ &bytesReadAt);
/*
* Step to the next big block.
*/
- if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
+ if( size > bytesReadAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex)))
return STG_E_DOCFILECORRUPT;
- bufferWalker += bytesToReadInBuffer;
- size -= bytesToReadInBuffer;
- *bytesRead += bytesToReadInBuffer;
+ bufferWalker += bytesReadAt;
+ size -= bytesReadAt;
+ *bytesRead += bytesReadAt;
offsetInBlock = 0; /* There is no offset on the next block */
+ if (bytesToReadInBuffer != bytesReadAt)
+ break;
}
return (size == 0) ? S_OK : STG_E_READFAULT;
@@ -4611,7 +4600,6 @@ HRESULT BlockChainStream_WriteAt(BlockCh
ULONG bytesToWrite;
ULONG blockIndex;
const BYTE* bufferWalker;
- BYTE* bigBlockBuffer;
/*
* Find the first block in the stream that contains part of the buffer.
@@ -4659,31 +4647,39 @@ HRESULT BlockChainStream_WriteAt(BlockCh
while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
{
+ ULARGE_INTEGER ulOffset;
+ DWORD bytesWrittenAt;
/*
* Calculate how many bytes we can copy from this big block.
*/
bytesToWrite =
min(This->parentStorage->bigBlockSize - offsetInBlock, size);
- /*
- * Copy those bytes to the buffer
- */
- bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
-
- memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
+ TRACE("block %i\n",blockIndex);
+ ulOffset.u.HighPart = 0;
+ ulOffset.u.LowPart = BLOCK_GetBigBlockOffset(blockIndex) +
+ offsetInBlock;
- StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+ StorageImpl_WriteAt(This->parentStorage,
+ ulOffset,
+ (BYTE*)bufferWalker,
+ bytesToWrite,
+ &bytesWrittenAt);
/*
* Step to the next big block.
*/
- if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
+ if(size > bytesWrittenAt && FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex,
&blockIndex)))
return STG_E_DOCFILECORRUPT;
- bufferWalker += bytesToWrite;
- size -= bytesToWrite;
- *bytesWritten += bytesToWrite;
+
+ bufferWalker += bytesWrittenAt;
+ size -= bytesWrittenAt;
+ *bytesWritten += bytesWrittenAt;
offsetInBlock = 0; /* There is no offset on the next block */
+
+ if (bytesWrittenAt != bytesToWrite)
+ break;
}
return (size == 0) ? S_OK : STG_E_WRITEFAULT;
@@ -5131,7 +5127,7 @@ static ULONG SmallBlockChainStream_GetNe
ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
ULONG nextBlock, newsbdIndex;
- BYTE* smallBlockDepot;
+ BYTE smallBlockDepot[BIG_BLOCK_SIZE];
nextBlock = sbdIndex;
while (nextBlock != BLOCK_END_OF_CHAIN)
@@ -5155,11 +5151,8 @@ static ULONG SmallBlockChainStream_GetNe
/*
* Initialize all the small blocks to free
*/
- smallBlockDepot =
- StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
-
memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
- StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
+ StorageImpl_WriteBigBlock(This->parentStorage, newsbdIndex, smallBlockDepot);
if (count == 0)
{
diff --git a/dlls/ole32/storage32.h b/dlls/ole32/storage32.h
index 569cb36..52a5477 100644
--- a/dlls/ole32/storage32.h
+++ b/dlls/ole32/storage32.h
@@ -162,22 +162,11 @@ struct StgProperty
* Declaration of the data structures
*/
typedef struct BigBlockFile BigBlockFile,*LPBIGBLOCKFILE;
-typedef struct MappedPage MappedPage,*LPMAPPEDPAGE;
struct BigBlockFile
{
- BOOL fileBased;
- ULARGE_INTEGER filesize;
ULONG blocksize;
- HANDLE hfile;
- HANDLE hfilemap;
- DWORD flProtect;
- MappedPage *maplist;
- MappedPage *victimhead, *victimtail;
- ULONG num_victim_pages;
ILockBytes *pLkbyt;
- HGLOBAL hbytearray;
- LPVOID pbytearray;
};
/*
@@ -191,11 +180,17 @@ BigBlockFile* BIGBLOCKFILE_Construct(HA
BOOL fileBased);
void BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This);
void BIGBLOCKFILE_EnsureExists(LPBIGBLOCKFILE This, ULONG index);
-void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index);
-void* BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index);
-void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock);
void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize);
-ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This);
+HRESULT BIGBLOCKFILE_ReadAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset,
+ void* buffer, ULONG size, ULONG* bytesRead);
+HRESULT BIGBLOCKFILE_WriteAt(LPBIGBLOCKFILE This, ULARGE_INTEGER offset,
+ void* buffer, const ULONG size, ULONG* bytesRead);
+/*
+ * File base ILockBytes implementation
+ */
+HRESULT WINAPI CreateILockBytesOnFile (HANDLE hFile,
+ DWORD openFlags, BOOL bCloseHandle,
+ LPLOCKBYTES* ppLkByt);
/*************************************************************************
* Ole Convert support
More information about the wine-patches
mailing list