- Fixed a small block depot bug. - Implemented converting from small blocks to big blocks. - Validated file attributes and flags. - Fixed a bug for larger files.
diff --git a/ole/stg_bigblockfile.c b/ole/stg_bigblockfile.c index 587c0f5..13d52e7 100644 --- a/ole/stg_bigblockfile.c +++ b/ole/stg_bigblockfile.c
@@ -655,7 +655,7 @@ /* actually map the page */ - if (This->filesize.LowPart < PAGE_SIZE) + if (This->filesize.LowPart <= PAGE_SIZE) { newMappedPage->lpBytes = MapViewOfFile(This->hfilemap, desired_access, @@ -664,11 +664,12 @@ } else { + DWORD numBytesToMap = This->filesize.LowPart - (pagenum*PAGE_SIZE); newMappedPage->lpBytes = MapViewOfFile(This->hfilemap, desired_access, hioffset, lowoffset, - PAGE_SIZE); + numBytesToMap); } return newMappedPage->lpBytes; @@ -698,7 +699,7 @@ /* actually map the page */ - if (This->filesize.LowPart < PAGE_SIZE) + if (This->filesize.LowPart <= PAGE_SIZE) { newMappedPage->lpBytes = MapViewOfFile(This->hfilemap, desired_access, @@ -708,11 +709,12 @@ } else { + DWORD numBytesToMap = This->filesize.LowPart - (pagenum*PAGE_SIZE); newMappedPage->lpBytes = MapViewOfFile(This->hfilemap, desired_access, hioffset, lowoffset, - PAGE_SIZE); + numBytesToMap); } return newMappedPage->lpBytes;
diff --git a/ole/stg_stream.c b/ole/stg_stream.c index 606c9c2..cceb790 100644 --- a/ole/stg_stream.c +++ b/ole/stg_stream.c
@@ -281,7 +281,6 @@ This->smallBlockChain = SmallBlockChainStream_Construct( This->parentStorage->ancestorStorage, This->ownerProperty); - } else { @@ -574,19 +573,29 @@ This->ownerProperty, &curProperty); /* - * TODO - * determine if we have to switch from small to big blocks or vice versa + * Determine if we have to switch from small to big blocks or vice versa */ + if (curProperty.size.LowPart < LIMIT_TO_USE_SMALL_BLOCK) + { + if (libNewSize.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) + { + /* + * Transform the small block chain into a big block chain + */ + This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks( + This->parentStorage->ancestorStorage, + &This->smallBlockChain); + } + } + if (This->smallBlockChain!=0) { Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize); - curProperty.blockType = SMALL_BLOCK_TYPE; } else { Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize); - curProperty.blockType = BIG_BLOCK_TYPE; } /*
diff --git a/ole/storage32.c b/ole/storage32.c index db4e1a1..f7a2dab 100644 --- a/ole/storage32.c +++ b/ole/storage32.c
@@ -76,6 +76,16 @@ OLECHAR32 *newProperty, OLECHAR32 *currentProperty); + +/*********************************************************************** + * Declaration of miscellaneous functions... + */ +static HRESULT validateSTGM(DWORD stgmValue); + +static DWORD GetShareModeFromSTGM(DWORD stgm); +static DWORD GetAccessModeFromSTGM(DWORD stgm); +static DWORD GetCreationModeFromSTGM(DWORD stgm); + /* * Virtual function table for the IStorage32Impl class. */ @@ -147,6 +157,9 @@ }; + + + /************************************************************************ ** Storage32BaseImpl implementatiion */ @@ -284,6 +297,20 @@ *ppstm = 0; /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + /* + * As documented. + */ + if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || + (grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_TRANSACTED) ) + return STG_E_INVALIDFUNCTION; + + /* * Create a property enumeration to search the properties */ propertyEnumeration = IEnumSTATSTGImpl_Construct( @@ -358,6 +385,20 @@ return E_INVALIDARG; /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + /* + * As documented. + */ + if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || + (grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_PRIORITY) ) + return STG_E_INVALIDFUNCTION; + + /* * Initialize the out parameter */ *ppstg = 0; @@ -683,6 +724,20 @@ return STG_E_INVALIDNAME; /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + /* + * As documented. + */ + if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || + (grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_TRANSACTED) ) + return STG_E_INVALIDFUNCTION; + + /* * Initialize the out parameter */ *ppstm = 0; @@ -854,6 +909,13 @@ return STG_E_INVALIDNAME; /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) ) || + (grfMode & STGM_DELETEONRELEASE) ) + return STG_E_INVALIDFLAG; + + /* * Initialize the out parameter */ *ppstg = 0; @@ -1212,7 +1274,8 @@ Storage32Impl *This, DWORD grfCommitFlags)/* [in] */ { - return E_NOTIMPL; + FIXME(ole, "(%ld): stub!\n", grfCommitFlags); + return S_OK; } HRESULT WINAPI Storage32Impl_Revert( @@ -1441,7 +1504,7 @@ (Storage32BaseImpl*)parentStorage, (OLECHAR32*)propertyToDelete.name, NULL, - 0, + STGM_SHARE_EXCLUSIVE, 0, &pis); @@ -1750,6 +1813,9 @@ BOOL32 readSucessful; ULONG currentPropertyIndex; + if ( FAILED( validateSTGM(openFlags) )) + return STG_E_INVALIDFLAG; + memset(This, 0, sizeof(Storage32Impl)); /* @@ -1850,7 +1916,6 @@ lstrcpyAtoW(rootProp.name, rootPropertyName); rootProp.sizeOfNameString = (lstrlen32W(rootProp.name)+1) * sizeof(WCHAR); - rootProp.blockType = BIG_BLOCK_TYPE; rootProp.propertyType = PROPTYPE_ROOT; rootProp.previousProperty = PROPERTY_NULL; rootProp.nextProperty = PROPERTY_NULL; @@ -2345,7 +2410,6 @@ PROPERTY_NAME_BUFFER_LEN ); memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1); - memcpy(&buffer->blockType, currentProperty + OFFSET_PS_BLOCKTYPE, 1); StorageUtl_ReadWord( currentProperty, @@ -2432,7 +2496,6 @@ PROPERTY_NAME_BUFFER_LEN ); memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1); - memcpy(currentProperty + OFFSET_PS_BLOCKTYPE, &buffer->blockType, 1); /* * Reassign the size in case of mistake.... @@ -2566,6 +2629,99 @@ } /****************************************************************************** + * Storage32Impl_SmallBlocksToBigBlocks + * + * This method will convert a small block chain to a big block chain. + * The small block chain will be destroyed. + */ +BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( + Storage32Impl* This, + SmallBlockChainStream** ppsbChain) +{ + ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN; + ULARGE_INTEGER size, offset; + ULONG cbRead, cbWritten; + ULONG propertyIndex; + BOOL32 successRead, successWrite; + StgProperty chainProperty; + BYTE buffer[DEF_SMALL_BLOCK_SIZE]; + BlockChainStream *bbTempChain = NULL; + BlockChainStream *bigBlockChain = NULL; + + /* + * Create a temporary big block chain that doesn't have + * an associated property. This temporary chain will be + * used to copy data from small blocks to big blocks. + */ + bbTempChain = BlockChainStream_Construct(This, + &bbHeadOfChain, + PROPERTY_NULL); + + /* + * Grow the big block chain. + */ + size = SmallBlockChainStream_GetSize(*ppsbChain); + BlockChainStream_SetSize(bbTempChain, size); + + /* + * Copy the contents of the small block chain to the big block chain + * by small block size increments. + */ + offset.LowPart = 0; + offset.HighPart = 0; + + do + { + successRead = SmallBlockChainStream_ReadAt(*ppsbChain, + offset, + sizeof(buffer), + buffer, + &cbRead); + + successWrite = BlockChainStream_WriteAt(bbTempChain, + offset, + sizeof(buffer), + buffer, + &cbWritten); + offset.LowPart += This->smallBlockSize; + + } while (successRead && successWrite); + + assert(cbRead == cbWritten); + + /* + * Destroy the small block chain. + */ + propertyIndex = (*ppsbChain)->ownerPropertyIndex; + size.HighPart = 0; + size.LowPart = 0; + SmallBlockChainStream_SetSize(*ppsbChain, size); + SmallBlockChainStream_Destroy(*ppsbChain); + *ppsbChain = 0; + + /* + * Change the property information. This chain is now a big block chain + * and it doesn't reside in the small blocks chain anymore. + */ + Storage32Impl_ReadProperty(This, propertyIndex, &chainProperty); + + chainProperty.startingBlock = bbHeadOfChain; + + Storage32Impl_WriteProperty(This, propertyIndex, &chainProperty); + + /* + * Destroy the temporary propertyless big block chain. + * Create a new big block chain associated with this property. + */ + BlockChainStream_Destroy(bbTempChain); + bigBlockChain = BlockChainStream_Construct(This, + NULL, + propertyIndex); + + return bigBlockChain; +} + +/****************************************************************************** ** Storage32InternalImpl implementation */ @@ -3532,10 +3688,21 @@ blockIndex = BlockChainStream_GetHeadOfChain(This); /* - * Empty chain + * Empty chain. Create the head. */ if (blockIndex == BLOCK_END_OF_CHAIN) { + blockIndex = Storage32Impl_GetNextFreeBigBlock(This->parentStorage); + Storage32Impl_SetNextBlockInChain(This->parentStorage, + blockIndex, + BLOCK_END_OF_CHAIN); + + if (This->headOfStreamPlaceHolder != 0) + { + *(This->headOfStreamPlaceHolder) = blockIndex; + } + else + { StgProperty chainProp; assert(This->ownerPropertyIndex != PROPERTY_NULL); @@ -3544,21 +3711,14 @@ This->ownerPropertyIndex, &chainProp); - chainProp.startingBlock = Storage32Impl_GetNextFreeBigBlock( - This->parentStorage); - - blockIndex = chainProp.startingBlock; - - Storage32Impl_SetNextBlockInChain( - This->parentStorage, - blockIndex, - BLOCK_END_OF_CHAIN); + chainProp.startingBlock = blockIndex; Storage32Impl_WriteProperty( This->parentStorage, This->ownerPropertyIndex, &chainProp); } + } currentBlock = blockIndex; @@ -4343,21 +4503,6 @@ } else { - ULARGE_INTEGER fileSize = - BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile); - - ULONG diff = newSize.LowPart - size.LowPart; - - /* - * Make sure the file stays a multiple of blocksize - */ - if ((diff % This->parentStorage->bigBlockSize) != 0) - diff += (This->parentStorage->bigBlockSize - - (diff % This->parentStorage->bigBlockSize)); - - fileSize.LowPart += diff; - BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize); - SmallBlockChainStream_Enlarge(This, newSize); } @@ -4394,21 +4539,49 @@ Storage32Impl* newStorage = 0; HANDLE32 hFile = INVALID_HANDLE_VALUE32; HRESULT hr = S_OK; + DWORD shareMode; + DWORD accessMode; + DWORD creationMode; + DWORD fileAttributes; + /* + * Validate the parameters + */ if ((ppstgOpen == 0) || (pwcsName == 0)) return STG_E_INVALIDPOINTER; /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + /* + * Interpret the STGM value grfMode + */ + shareMode = GetShareModeFromSTGM(grfMode); + accessMode = GetAccessModeFromSTGM(grfMode); + creationMode = GetCreationModeFromSTGM(grfMode); + + if (grfMode & STGM_DELETEONRELEASE) + fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE; + else + fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; + + if (grfMode & STGM_TRANSACTED) + FIXME(ole, "Transacted mode not implemented.\n"); + + /* * Initialize the "out" parameter. */ *ppstgOpen = 0; hFile = CreateFile32W(pwcsName, - GENERIC_READ | GENERIC_WRITE, - 0, /*FILE_SHARE_READ,*/ + accessMode, + shareMode, NULL, - CREATE_NEW, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + creationMode, + fileAttributes, 0); if (hFile == INVALID_HANDLE_VALUE32) @@ -4437,7 +4610,7 @@ */ hr = Storage32BaseImpl_QueryInterface( (Storage32BaseImpl*)newStorage, - &IID_IStorage, + (REFIID)&IID_IStorage, (void**)ppstgOpen); return hr; @@ -4457,6 +4630,8 @@ Storage32Impl* newStorage = 0; HRESULT hr = S_OK; HANDLE32 hFile = 0; + DWORD shareMode; + DWORD accessMode; /* * Perform a sanity check @@ -4465,13 +4640,25 @@ return STG_E_INVALIDPOINTER; /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + /* + * Interpret the STGM value grfMode + */ + shareMode = GetShareModeFromSTGM(grfMode); + accessMode = GetAccessModeFromSTGM(grfMode); + + /* * Initialize the "out" parameter. */ *ppstgOpen = 0; hFile = CreateFile32W( pwcsName, - GENERIC_READ | GENERIC_WRITE, - 0, /*FILE_SHARE_READ,*/ + accessMode, + shareMode, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, @@ -4504,7 +4691,7 @@ */ hr = Storage32BaseImpl_QueryInterface( (Storage32BaseImpl*)newStorage, - &IID_IStorage, + (REFIID)&IID_IStorage, (void**)ppstgOpen); return hr; @@ -4527,3 +4714,192 @@ } +/**************************************************************************** + * This method validate a STGM parameter that can contain the values below + * + * STGM_DIRECT 0x00000000 + * STGM_TRANSACTED 0x00010000 + * STGM_SIMPLE 0x08000000 + * + * STGM_READ 0x00000000 + * STGM_WRITE 0x00000001 + * STGM_READWRITE 0x00000002 + * + * STGM_SHARE_DENY_NONE 0x00000040 + * STGM_SHARE_DENY_READ 0x00000030 + * STGM_SHARE_DENY_WRITE 0x00000020 + * STGM_SHARE_EXCLUSIVE 0x00000010 + * + * STGM_PRIORITY 0x00040000 + * STGM_DELETEONRELEASE 0x04000000 + * + * STGM_CREATE 0x00001000 + * STGM_CONVERT 0x00020000 + * STGM_FAILIFTHERE 0x00000000 + * + * STGM_NOSCRATCH 0x00100000 + * STGM_NOSNAPSHOT 0x00200000 + */ +static HRESULT validateSTGM(DWORD stgm) +{ + BOOL32 bSTGM_TRANSACTED = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED); + BOOL32 bSTGM_SIMPLE = ((stgm & STGM_SIMPLE) == STGM_SIMPLE); + BOOL32 bSTGM_DIRECT = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE); + + BOOL32 bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE); + BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE); + BOOL32 bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE); + + BOOL32 bSTGM_SHARE_DENY_NONE = + ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE); + + BOOL32 bSTGM_SHARE_DENY_READ = + ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ); + + BOOL32 bSTGM_SHARE_DENY_WRITE = + ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE); + + BOOL32 bSTGM_SHARE_EXCLUSIVE = + ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE); + + BOOL32 bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE); + BOOL32 bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT); + + BOOL32 bSTGM_NOSCRATCH = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH); + BOOL32 bSTGM_NOSNAPSHOT = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT); + + /* + * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE + */ + if ( ! bSTGM_DIRECT ) + if( bSTGM_TRANSACTED && bSTGM_SIMPLE ) + return E_FAIL; + + /* + * STGM_WRITE | STGM_READWRITE | STGM_READ + */ + if ( ! bSTGM_READ ) + if( bSTGM_WRITE && bSTGM_READWRITE ) + return E_FAIL; + + /* + * STGM_SHARE_DENY_NONE | others + * (I assume here that DENY_READ implies DENY_WRITE) + */ + if ( bSTGM_SHARE_DENY_NONE ) + if ( bSTGM_SHARE_DENY_READ || + bSTGM_SHARE_DENY_WRITE || + bSTGM_SHARE_EXCLUSIVE) + return E_FAIL; + + /* + * STGM_CREATE | STGM_CONVERT + * if both are false, STGM_FAILIFTHERE is set to TRUE + */ + if ( bSTGM_CREATE && bSTGM_CONVERT ) + return E_FAIL; + + /* + * STGM_NOSCRATCH requires STGM_TRANSACTED + */ + if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED ) + return E_FAIL; + + /* + * STGM_NOSNAPSHOT requires STGM_TRANSACTED and + * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE` + */ + if (bSTGM_NOSNAPSHOT) + { + if ( ! ( bSTGM_TRANSACTED && + !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) ) + return E_FAIL; + } + + return S_OK; +} + +/**************************************************************************** + * GetShareModeFromSTGM + * + * This method will return a share mode flag from a STGM value. + * The STGM value is assumed valid. + */ +static DWORD GetShareModeFromSTGM(DWORD stgm) +{ + DWORD dwShareMode = 0; + BOOL32 bSTGM_SHARE_DENY_NONE = + ((stgm & STGM_SHARE_DENY_NONE) == STGM_SHARE_DENY_NONE); + + BOOL32 bSTGM_SHARE_DENY_READ = + ((stgm & STGM_SHARE_DENY_READ) == STGM_SHARE_DENY_READ); + + BOOL32 bSTGM_SHARE_DENY_WRITE = + ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE); + + BOOL32 bSTGM_SHARE_EXCLUSIVE = + ((stgm & STGM_SHARE_EXCLUSIVE) == STGM_SHARE_EXCLUSIVE); + + if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ)) + dwShareMode = 0; + + if (bSTGM_SHARE_DENY_NONE) + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + + if (bSTGM_SHARE_DENY_WRITE) + dwShareMode = FILE_SHARE_READ; + + return dwShareMode; +} + +/**************************************************************************** + * GetAccessModeFromSTGM + * + * This method will return an access mode flag from a STGM value. + * The STGM value is assumed valid. + */ +static DWORD GetAccessModeFromSTGM(DWORD stgm) +{ + DWORD dwDesiredAccess = 0; + BOOL32 bSTGM_WRITE = ((stgm & STGM_WRITE) == STGM_WRITE); + BOOL32 bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE); + BOOL32 bSTGM_READ = ! (bSTGM_WRITE || bSTGM_READWRITE); + + if (bSTGM_READ) + dwDesiredAccess = GENERIC_READ; + + if (bSTGM_WRITE) + dwDesiredAccess |= GENERIC_WRITE; + + if (bSTGM_READWRITE) + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; + + return dwDesiredAccess; +} + +/**************************************************************************** + * GetCreationModeFromSTGM + * + * This method will return a creation mode flag from a STGM value. + * The STGM value is assumed valid. + */ +static DWORD GetCreationModeFromSTGM(DWORD stgm) +{ + DWORD dwCreationDistribution; + BOOL32 bSTGM_CREATE = ((stgm & STGM_CREATE) == STGM_CREATE); + BOOL32 bSTGM_CONVERT = ((stgm & STGM_CONVERT) == STGM_CONVERT); + BOOL32 bSTGM_FAILIFTHERE = ! (bSTGM_CREATE || bSTGM_CONVERT); + + if (bSTGM_CREATE) + dwCreationDistribution = CREATE_NEW; + else if (bSTGM_FAILIFTHERE) + dwCreationDistribution = CREATE_NEW; + else if (bSTGM_CONVERT) + { + FIXME(ole, "STGM_CONVERT not implemented!\n"); + dwCreationDistribution = CREATE_NEW; + } + + return dwCreationDistribution; +} +
diff --git a/ole/storage32.h b/ole/storage32.h index c8f1ef5..6d79120 100644 --- a/ole/storage32.h +++ b/ole/storage32.h
@@ -69,12 +69,6 @@ #define PROPTYPE_ROOT 0x05 /* - * Block type constants - */ -#define SMALL_BLOCK_TYPE 0x00 -#define BIG_BLOCK_TYPE 0x01 - -/* * This define allows me to assign a function to a vtable without having the * nasty warning about incompatible types. * @@ -121,7 +115,6 @@ WCHAR name[PROPERTY_NAME_MAX_LEN]; WORD sizeOfNameString; BYTE propertyType; - BYTE blockType; ULONG previousProperty; ULONG nextProperty; ULONG dirProperty; @@ -433,6 +426,9 @@ ULONG index, StgProperty* buffer); +BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( + Storage32Impl* This, + SmallBlockChainStream** ppsbChain); /**************************************************************************** * Storage32InternalImpl definitions.