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