696 lines
22 KiB
C
696 lines
22 KiB
C
/*
|
|
* Compound Storage (32 bit version)
|
|
*
|
|
* Implemented using the documentation of the LAOLA project at
|
|
* <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
|
|
* (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
|
|
*
|
|
* This include file contains definitions of types and function
|
|
* prototypes that are used in the many files implementing the
|
|
* storage functionality
|
|
*
|
|
* Copyright 1998,1999 Francis Beaudet
|
|
* Copyright 1998,1999 Thuy Nguyen
|
|
* Copyright 2010 Vincent Povirk for CodeWeavers
|
|
*
|
|
* 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
|
|
*/
|
|
#ifndef __STORAGE32_H__
|
|
#define __STORAGE32_H__
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winnt.h"
|
|
#include "objbase.h"
|
|
#include "winreg.h"
|
|
#include "winternl.h"
|
|
#include "wine/list.h"
|
|
|
|
/*
|
|
* Definitions for the file format offsets.
|
|
*/
|
|
static const ULONG OFFSET_MINORVERSION = 0x00000018;
|
|
static const ULONG OFFSET_MAJORVERSION = 0x0000001a;
|
|
static const ULONG OFFSET_BYTEORDERMARKER = 0x0000001c;
|
|
static const ULONG OFFSET_BIGBLOCKSIZEBITS = 0x0000001e;
|
|
static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020;
|
|
static const ULONG OFFSET_DIRSECTORCOUNT = 0x00000028;
|
|
static const ULONG OFFSET_BBDEPOTCOUNT = 0x0000002C;
|
|
static const ULONG OFFSET_ROOTSTARTBLOCK = 0x00000030;
|
|
static const ULONG OFFSET_TRANSACTIONSIG = 0x00000034;
|
|
static const ULONG OFFSET_SMALLBLOCKLIMIT = 0x00000038;
|
|
static const ULONG OFFSET_SBDEPOTSTART = 0x0000003C;
|
|
static const ULONG OFFSET_SBDEPOTCOUNT = 0x00000040;
|
|
static const ULONG OFFSET_EXTBBDEPOTSTART = 0x00000044;
|
|
static const ULONG OFFSET_EXTBBDEPOTCOUNT = 0x00000048;
|
|
static const ULONG OFFSET_BBDEPOTSTART = 0x0000004C;
|
|
static const ULONG OFFSET_PS_NAME = 0x00000000;
|
|
static const ULONG OFFSET_PS_NAMELENGTH = 0x00000040;
|
|
static const ULONG OFFSET_PS_STGTYPE = 0x00000042;
|
|
static const ULONG OFFSET_PS_LEFTCHILD = 0x00000044;
|
|
static const ULONG OFFSET_PS_RIGHTCHILD = 0x00000048;
|
|
static const ULONG OFFSET_PS_DIRROOT = 0x0000004C;
|
|
static const ULONG OFFSET_PS_GUID = 0x00000050;
|
|
static const ULONG OFFSET_PS_CTIMELOW = 0x00000064;
|
|
static const ULONG OFFSET_PS_CTIMEHIGH = 0x00000068;
|
|
static const ULONG OFFSET_PS_MTIMELOW = 0x0000006C;
|
|
static const ULONG OFFSET_PS_MTIMEHIGH = 0x00000070;
|
|
static const ULONG OFFSET_PS_STARTBLOCK = 0x00000074;
|
|
static const ULONG OFFSET_PS_SIZE = 0x00000078;
|
|
static const WORD DEF_BIG_BLOCK_SIZE_BITS = 0x0009;
|
|
static const WORD MIN_BIG_BLOCK_SIZE_BITS = 0x0009;
|
|
static const WORD MAX_BIG_BLOCK_SIZE_BITS = 0x000c;
|
|
static const WORD DEF_SMALL_BLOCK_SIZE_BITS = 0x0006;
|
|
static const WORD DEF_BIG_BLOCK_SIZE = 0x0200;
|
|
static const WORD DEF_SMALL_BLOCK_SIZE = 0x0040;
|
|
static const ULONG BLOCK_EXTBBDEPOT = 0xFFFFFFFC;
|
|
static const ULONG BLOCK_SPECIAL = 0xFFFFFFFD;
|
|
static const ULONG BLOCK_END_OF_CHAIN = 0xFFFFFFFE;
|
|
static const ULONG BLOCK_UNUSED = 0xFFFFFFFF;
|
|
static const ULONG DIRENTRY_NULL = 0xFFFFFFFF;
|
|
|
|
#define DIRENTRY_NAME_MAX_LEN 0x20
|
|
#define DIRENTRY_NAME_BUFFER_LEN 0x40
|
|
|
|
#define RAW_DIRENTRY_SIZE 0x00000080
|
|
|
|
#define HEADER_SIZE 512
|
|
|
|
#define MIN_BIG_BLOCK_SIZE 0x200
|
|
#define MAX_BIG_BLOCK_SIZE 0x1000
|
|
|
|
/*
|
|
* Type of child entry link
|
|
*/
|
|
#define DIRENTRY_RELATION_PREVIOUS 0
|
|
#define DIRENTRY_RELATION_NEXT 1
|
|
#define DIRENTRY_RELATION_DIR 2
|
|
|
|
/*
|
|
* type constant used in files for the root storage
|
|
*/
|
|
#define STGTY_ROOT 0x05
|
|
|
|
#define COUNT_BBDEPOTINHEADER 109
|
|
|
|
/* FIXME: This value is stored in the header, but we hard-code it to 0x1000. */
|
|
#define LIMIT_TO_USE_SMALL_BLOCK 0x1000
|
|
|
|
#define STGM_ACCESS_MODE(stgm) ((stgm)&0x0000f)
|
|
#define STGM_SHARE_MODE(stgm) ((stgm)&0x000f0)
|
|
#define STGM_CREATE_MODE(stgm) ((stgm)&0x0f000)
|
|
|
|
#define STGM_KNOWN_FLAGS (0xf0ff | \
|
|
STGM_TRANSACTED | STGM_CONVERT | STGM_PRIORITY | STGM_NOSCRATCH | \
|
|
STGM_NOSNAPSHOT | STGM_DIRECT_SWMR | STGM_DELETEONRELEASE | STGM_SIMPLE)
|
|
|
|
/*
|
|
* Forward declarations of all the structures used by the storage
|
|
* module.
|
|
*/
|
|
typedef struct StorageBaseImpl StorageBaseImpl;
|
|
typedef struct StorageBaseImplVtbl StorageBaseImplVtbl;
|
|
typedef struct StorageImpl StorageImpl;
|
|
typedef struct BlockChainStream BlockChainStream;
|
|
typedef struct SmallBlockChainStream SmallBlockChainStream;
|
|
typedef struct IEnumSTATSTGImpl IEnumSTATSTGImpl;
|
|
typedef struct DirEntry DirEntry;
|
|
typedef struct StgStreamImpl StgStreamImpl;
|
|
|
|
/*
|
|
* A reference to a directory entry in the file or a transacted cache.
|
|
*/
|
|
typedef ULONG DirRef;
|
|
|
|
/*
|
|
* This utility structure is used to read/write the information in a directory
|
|
* entry.
|
|
*/
|
|
struct DirEntry
|
|
{
|
|
WCHAR name[DIRENTRY_NAME_MAX_LEN];
|
|
WORD sizeOfNameString;
|
|
BYTE stgType;
|
|
DirRef leftChild;
|
|
DirRef rightChild;
|
|
DirRef dirRootEntry;
|
|
GUID clsid;
|
|
FILETIME ctime;
|
|
FILETIME mtime;
|
|
ULONG startingBlock;
|
|
ULARGE_INTEGER size;
|
|
};
|
|
|
|
HRESULT FileLockBytesImpl_Construct(HANDLE hFile, DWORD openFlags, LPCWSTR pwcsName, ILockBytes **pLockBytes) DECLSPEC_HIDDEN;
|
|
|
|
/*************************************************************************
|
|
* Ole Convert support
|
|
*/
|
|
|
|
HRESULT STORAGE_CreateOleStream(IStorage*, DWORD) DECLSPEC_HIDDEN;
|
|
HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName) DECLSPEC_HIDDEN;
|
|
|
|
enum swmr_mode
|
|
{
|
|
SWMR_None,
|
|
SWMR_Writer,
|
|
SWMR_Reader
|
|
};
|
|
|
|
/****************************************************************************
|
|
* StorageBaseImpl definitions.
|
|
*
|
|
* This structure defines the base information contained in all implementations
|
|
* of IStorage contained in this file storage implementation.
|
|
*
|
|
* In OOP terms, this is the base class for all the IStorage implementations
|
|
* contained in this file.
|
|
*/
|
|
struct StorageBaseImpl
|
|
{
|
|
IStorage IStorage_iface;
|
|
IPropertySetStorage IPropertySetStorage_iface; /* interface for adding a properties stream */
|
|
IDirectWriterLock IDirectWriterLock_iface;
|
|
LONG ref;
|
|
|
|
/*
|
|
* Stream tracking list
|
|
*/
|
|
|
|
struct list strmHead;
|
|
|
|
/*
|
|
* Storage tracking list
|
|
*/
|
|
struct list storageHead;
|
|
|
|
/*
|
|
* TRUE if this object has been invalidated
|
|
*/
|
|
BOOL reverted;
|
|
|
|
/*
|
|
* Index of the directory entry of this storage
|
|
*/
|
|
DirRef storageDirEntry;
|
|
|
|
/*
|
|
* virtual methods.
|
|
*/
|
|
const StorageBaseImplVtbl *baseVtbl;
|
|
|
|
/*
|
|
* flags that this storage was opened or created with
|
|
*/
|
|
DWORD openFlags;
|
|
|
|
/*
|
|
* State bits appear to only be preserved while running. No in the stream
|
|
*/
|
|
DWORD stateBits;
|
|
|
|
BOOL create; /* Was the storage created or opened.
|
|
The behaviour of STGM_SIMPLE depends on this */
|
|
/*
|
|
* If this storage was opened in transacted mode, the object that implements
|
|
* the transacted snapshot or cache.
|
|
*/
|
|
StorageBaseImpl *transactedChild;
|
|
enum swmr_mode lockingrole;
|
|
};
|
|
|
|
/* virtual methods for StorageBaseImpl objects */
|
|
struct StorageBaseImplVtbl {
|
|
void (*Destroy)(StorageBaseImpl*);
|
|
void (*Invalidate)(StorageBaseImpl*);
|
|
HRESULT (*Flush)(StorageBaseImpl*);
|
|
HRESULT (*GetFilename)(StorageBaseImpl*,LPWSTR*);
|
|
HRESULT (*CreateDirEntry)(StorageBaseImpl*,const DirEntry*,DirRef*);
|
|
HRESULT (*WriteDirEntry)(StorageBaseImpl*,DirRef,const DirEntry*);
|
|
HRESULT (*ReadDirEntry)(StorageBaseImpl*,DirRef,DirEntry*);
|
|
HRESULT (*DestroyDirEntry)(StorageBaseImpl*,DirRef);
|
|
HRESULT (*StreamReadAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,void*,ULONG*);
|
|
HRESULT (*StreamWriteAt)(StorageBaseImpl*,DirRef,ULARGE_INTEGER,ULONG,const void*,ULONG*);
|
|
HRESULT (*StreamSetSize)(StorageBaseImpl*,DirRef,ULARGE_INTEGER);
|
|
HRESULT (*StreamLink)(StorageBaseImpl*,DirRef,DirRef);
|
|
HRESULT (*GetTransactionSig)(StorageBaseImpl*,ULONG*,BOOL);
|
|
HRESULT (*SetTransactionSig)(StorageBaseImpl*,ULONG);
|
|
HRESULT (*LockTransaction)(StorageBaseImpl*);
|
|
HRESULT (*UnlockTransaction)(StorageBaseImpl*);
|
|
};
|
|
|
|
static inline void StorageBaseImpl_Destroy(StorageBaseImpl *This)
|
|
{
|
|
This->baseVtbl->Destroy(This);
|
|
}
|
|
|
|
static inline void StorageBaseImpl_Invalidate(StorageBaseImpl *This)
|
|
{
|
|
This->baseVtbl->Invalidate(This);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_Flush(StorageBaseImpl *This)
|
|
{
|
|
return This->baseVtbl->Flush(This);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_GetFilename(StorageBaseImpl *This, LPWSTR *result)
|
|
{
|
|
return This->baseVtbl->GetFilename(This, result);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_CreateDirEntry(StorageBaseImpl *This,
|
|
const DirEntry *newData, DirRef *index)
|
|
{
|
|
return This->baseVtbl->CreateDirEntry(This, newData, index);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_WriteDirEntry(StorageBaseImpl *This,
|
|
DirRef index, const DirEntry *data)
|
|
{
|
|
return This->baseVtbl->WriteDirEntry(This, index, data);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_ReadDirEntry(StorageBaseImpl *This,
|
|
DirRef index, DirEntry *data)
|
|
{
|
|
return This->baseVtbl->ReadDirEntry(This, index, data);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_DestroyDirEntry(StorageBaseImpl *This,
|
|
DirRef index)
|
|
{
|
|
return This->baseVtbl->DestroyDirEntry(This, index);
|
|
}
|
|
|
|
/* Read up to size bytes from this directory entry's stream at the given offset. */
|
|
static inline HRESULT StorageBaseImpl_StreamReadAt(StorageBaseImpl *This,
|
|
DirRef index, ULARGE_INTEGER offset, ULONG size, void *buffer, ULONG *bytesRead)
|
|
{
|
|
return This->baseVtbl->StreamReadAt(This, index, offset, size, buffer, bytesRead);
|
|
}
|
|
|
|
/* Write size bytes to this directory entry's stream at the given offset,
|
|
* growing the stream if necessary. */
|
|
static inline HRESULT StorageBaseImpl_StreamWriteAt(StorageBaseImpl *This,
|
|
DirRef index, ULARGE_INTEGER offset, ULONG size, const void *buffer, ULONG *bytesWritten)
|
|
{
|
|
return This->baseVtbl->StreamWriteAt(This, index, offset, size, buffer, bytesWritten);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_StreamSetSize(StorageBaseImpl *This,
|
|
DirRef index, ULARGE_INTEGER newsize)
|
|
{
|
|
return This->baseVtbl->StreamSetSize(This, index, newsize);
|
|
}
|
|
|
|
/* Make dst point to the same stream that src points to. Other stream operations
|
|
* will not work properly for entries that point to the same stream, so this
|
|
* must be a very temporary state, and only one entry pointing to a given stream
|
|
* may be reachable at any given time. */
|
|
static inline HRESULT StorageBaseImpl_StreamLink(StorageBaseImpl *This,
|
|
DirRef dst, DirRef src)
|
|
{
|
|
return This->baseVtbl->StreamLink(This, dst, src);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_GetTransactionSig(StorageBaseImpl *This,
|
|
ULONG* result, BOOL refresh)
|
|
{
|
|
return This->baseVtbl->GetTransactionSig(This, result, refresh);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_SetTransactionSig(StorageBaseImpl *This,
|
|
ULONG value)
|
|
{
|
|
return This->baseVtbl->SetTransactionSig(This, value);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_LockTransaction(StorageBaseImpl *This)
|
|
{
|
|
return This->baseVtbl->LockTransaction(This);
|
|
}
|
|
|
|
static inline HRESULT StorageBaseImpl_UnlockTransaction(StorageBaseImpl *This)
|
|
{
|
|
return This->baseVtbl->UnlockTransaction(This);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* StorageBaseImpl stream list handlers
|
|
*/
|
|
|
|
void StorageBaseImpl_AddStream(StorageBaseImpl * stg, StgStreamImpl * strm) DECLSPEC_HIDDEN;
|
|
void StorageBaseImpl_RemoveStream(StorageBaseImpl * stg, StgStreamImpl * strm) DECLSPEC_HIDDEN;
|
|
|
|
/* Number of BlockChainStream objects to cache in a StorageImpl */
|
|
#define BLOCKCHAIN_CACHE_SIZE 4
|
|
|
|
/****************************************************************************
|
|
* Storage32Impl definitions.
|
|
*
|
|
* This implementation of the IStorage32 interface represents a root
|
|
* storage. Basically, a document file.
|
|
*/
|
|
struct StorageImpl
|
|
{
|
|
struct StorageBaseImpl base;
|
|
|
|
/*
|
|
* File header
|
|
*/
|
|
WORD bigBlockSizeBits;
|
|
WORD smallBlockSizeBits;
|
|
ULONG bigBlockSize;
|
|
ULONG smallBlockSize;
|
|
ULONG bigBlockDepotCount;
|
|
ULONG rootStartBlock;
|
|
ULONG smallBlockLimit;
|
|
ULONG smallBlockDepotStart;
|
|
ULONG extBigBlockDepotStart;
|
|
ULONG *extBigBlockDepotLocations;
|
|
ULONG extBigBlockDepotLocationsSize;
|
|
ULONG extBigBlockDepotCount;
|
|
ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
|
|
ULONG transactionSig;
|
|
|
|
ULONG extBlockDepotCached[MAX_BIG_BLOCK_SIZE / 4];
|
|
ULONG indexExtBlockDepotCached;
|
|
|
|
ULONG blockDepotCached[MAX_BIG_BLOCK_SIZE / 4];
|
|
ULONG indexBlockDepotCached;
|
|
ULONG prevFreeBlock;
|
|
|
|
/* All small blocks before this one are known to be in use. */
|
|
ULONG firstFreeSmallBlock;
|
|
|
|
/*
|
|
* Abstraction of the big block chains for the chains of the header.
|
|
*/
|
|
BlockChainStream* rootBlockChain;
|
|
BlockChainStream* smallBlockDepotChain;
|
|
BlockChainStream* smallBlockRootChain;
|
|
|
|
/* Cache of block chain streams objects for directory entries */
|
|
BlockChainStream* blockChainCache[BLOCKCHAIN_CACHE_SIZE];
|
|
UINT blockChainToEvict;
|
|
|
|
ILockBytes* lockBytes;
|
|
|
|
ULONG locked_bytes[8];
|
|
};
|
|
|
|
HRESULT StorageImpl_ReadRawDirEntry(
|
|
StorageImpl *This,
|
|
ULONG index,
|
|
BYTE *buffer) DECLSPEC_HIDDEN;
|
|
|
|
void UpdateRawDirEntry(
|
|
BYTE *buffer,
|
|
const DirEntry *newData) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT StorageImpl_WriteRawDirEntry(
|
|
StorageImpl *This,
|
|
ULONG index,
|
|
const BYTE *buffer) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT StorageImpl_ReadDirEntry(
|
|
StorageImpl* This,
|
|
DirRef index,
|
|
DirEntry* buffer) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT StorageImpl_WriteDirEntry(
|
|
StorageImpl* This,
|
|
DirRef index,
|
|
const DirEntry* buffer) DECLSPEC_HIDDEN;
|
|
|
|
BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
|
|
StorageImpl* This,
|
|
SmallBlockChainStream** ppsbChain) DECLSPEC_HIDDEN;
|
|
|
|
SmallBlockChainStream* Storage32Impl_BigBlocksToSmallBlocks(
|
|
StorageImpl* This,
|
|
BlockChainStream** ppbbChain,
|
|
ULARGE_INTEGER newSize) DECLSPEC_HIDDEN;
|
|
|
|
/****************************************************************************
|
|
* StgStreamImpl definitions.
|
|
*
|
|
* This class implements the IStream interface and represents a stream
|
|
* located inside a storage object.
|
|
*/
|
|
struct StgStreamImpl
|
|
{
|
|
IStream IStream_iface;
|
|
LONG ref;
|
|
|
|
/*
|
|
* We are an entry in the storage object's stream handler list
|
|
*/
|
|
struct list StrmListEntry;
|
|
|
|
/*
|
|
* Storage that is the parent(owner) of the stream
|
|
*/
|
|
StorageBaseImpl* parentStorage;
|
|
|
|
/*
|
|
* Access mode of this stream.
|
|
*/
|
|
DWORD grfMode;
|
|
|
|
/*
|
|
* Index of the directory entry that owns (points to) this stream.
|
|
*/
|
|
DirRef dirEntry;
|
|
|
|
/*
|
|
* This is the current position of the cursor in the stream
|
|
*/
|
|
ULARGE_INTEGER currentPosition;
|
|
};
|
|
|
|
static inline StgStreamImpl *impl_from_IStream( IStream *iface )
|
|
{
|
|
return CONTAINING_RECORD(iface, StgStreamImpl, IStream_iface);
|
|
}
|
|
|
|
/*
|
|
* Method definition for the StgStreamImpl class.
|
|
*/
|
|
StgStreamImpl* StgStreamImpl_Construct(
|
|
StorageBaseImpl* parentStorage,
|
|
DWORD grfMode,
|
|
DirRef dirEntry) DECLSPEC_HIDDEN;
|
|
|
|
|
|
/* Range lock constants.
|
|
*
|
|
* The storage format reserves the region from 0x7fffff00-0x7fffffff for
|
|
* locking and synchronization. Unfortuantely, the spec doesn't say which bytes
|
|
* within that range are used, and for what. These are guesses based on testing.
|
|
* In particular, ends of ranges may be wrong.
|
|
|
|
0x0 through 0x57: Unknown. Causes read-only exclusive opens to fail.
|
|
0x58 through 0x7f: Priority mode.
|
|
0x80: Commit lock.
|
|
0x81 through 0x91: Priority mode, again. Not sure why it uses two regions.
|
|
0x92: Lock-checking lock. Held while opening so ranges can be tested without
|
|
causing spurious failures if others try to grab or test those ranges at the
|
|
same time.
|
|
0x93 through 0xa6: Read mode.
|
|
0xa7 through 0xba: Write mode.
|
|
0xbb through 0xce: Deny read.
|
|
0xcf through 0xe2: Deny write.
|
|
0xe2 through 0xff: Unknown. Causes read-only exclusive opens to fail.
|
|
*/
|
|
|
|
#define RANGELOCK_UNK1_FIRST 0x7fffff00
|
|
#define RANGELOCK_UNK1_LAST 0x7fffff57
|
|
#define RANGELOCK_PRIORITY1_FIRST 0x7fffff58
|
|
#define RANGELOCK_PRIORITY1_LAST 0x7fffff7f
|
|
#define RANGELOCK_COMMIT 0x7fffff80
|
|
#define RANGELOCK_PRIORITY2_FIRST 0x7fffff81
|
|
#define RANGELOCK_PRIORITY2_LAST 0x7fffff91
|
|
#define RANGELOCK_CHECKLOCKS 0x7fffff92
|
|
#define RANGELOCK_READ_FIRST 0x7fffff93
|
|
#define RANGELOCK_READ_LAST 0x7fffffa6
|
|
#define RANGELOCK_WRITE_FIRST 0x7fffffa7
|
|
#define RANGELOCK_WRITE_LAST 0x7fffffba
|
|
#define RANGELOCK_DENY_READ_FIRST 0x7fffffbb
|
|
#define RANGELOCK_DENY_READ_LAST 0x7fffffce
|
|
#define RANGELOCK_DENY_WRITE_FIRST 0x7fffffcf
|
|
#define RANGELOCK_DENY_WRITE_LAST 0x7fffffe2
|
|
#define RANGELOCK_UNK2_FIRST 0x7fffffe3
|
|
#define RANGELOCK_UNK2_LAST 0x7fffffff
|
|
#define RANGELOCK_TRANSACTION_FIRST RANGELOCK_PRIORITY1_FIRST
|
|
#define RANGELOCK_TRANSACTION_LAST RANGELOCK_CHECKLOCKS
|
|
#define RANGELOCK_FIRST RANGELOCK_UNK1_FIRST
|
|
#define RANGELOCK_LAST RANGELOCK_UNK2_LAST
|
|
|
|
|
|
/******************************************************************************
|
|
* Endian conversion macros
|
|
*/
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
#define htole32(x) RtlUlongByteSwap(x)
|
|
#define htole16(x) RtlUshortByteSwap(x)
|
|
#define lendian32toh(x) RtlUlongByteSwap(x)
|
|
#define lendian16toh(x) RtlUshortByteSwap(x)
|
|
|
|
#else
|
|
|
|
#define htole32(x) (x)
|
|
#define htole16(x) (x)
|
|
#define lendian32toh(x) (x)
|
|
#define lendian16toh(x) (x)
|
|
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* The StorageUtl_ functions are miscellaneous utility functions. Most of which
|
|
* are abstractions used to read values from file buffers without having to
|
|
* worry about bit order
|
|
*/
|
|
void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset,
|
|
ULARGE_INTEGER* value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset,
|
|
const ULARGE_INTEGER *value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value) DECLSPEC_HIDDEN;
|
|
void StorageUtl_CopyDirEntryToSTATSTG(StorageBaseImpl *storage,STATSTG* destination,
|
|
const DirEntry* source, int statFlags) DECLSPEC_HIDDEN;
|
|
|
|
/****************************************************************************
|
|
* BlockChainStream definitions.
|
|
*
|
|
* The BlockChainStream class is a utility class that is used to create an
|
|
* abstraction of the big block chains in the storage file.
|
|
*/
|
|
struct BlockChainRun
|
|
{
|
|
/* This represents a range of blocks that happen reside in consecutive sectors. */
|
|
ULONG firstSector;
|
|
ULONG firstOffset;
|
|
ULONG lastOffset;
|
|
};
|
|
|
|
typedef struct BlockChainBlock
|
|
{
|
|
ULONG index;
|
|
ULONG sector;
|
|
BOOL read;
|
|
BOOL dirty;
|
|
BYTE data[MAX_BIG_BLOCK_SIZE];
|
|
} BlockChainBlock;
|
|
|
|
struct BlockChainStream
|
|
{
|
|
StorageImpl* parentStorage;
|
|
ULONG* headOfStreamPlaceHolder;
|
|
DirRef ownerDirEntry;
|
|
struct BlockChainRun* indexCache;
|
|
ULONG indexCacheLen;
|
|
ULONG indexCacheSize;
|
|
BlockChainBlock cachedBlocks[2];
|
|
ULONG blockToEvict;
|
|
ULONG tailIndex;
|
|
ULONG numBlocks;
|
|
};
|
|
|
|
/*
|
|
* Methods for the BlockChainStream class.
|
|
*/
|
|
BlockChainStream* BlockChainStream_Construct(
|
|
StorageImpl* parentStorage,
|
|
ULONG* headOfStreamPlaceHolder,
|
|
DirRef dirEntry) DECLSPEC_HIDDEN;
|
|
|
|
void BlockChainStream_Destroy(
|
|
BlockChainStream* This) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT BlockChainStream_ReadAt(
|
|
BlockChainStream* This,
|
|
ULARGE_INTEGER offset,
|
|
ULONG size,
|
|
void* buffer,
|
|
ULONG* bytesRead) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT BlockChainStream_WriteAt(
|
|
BlockChainStream* This,
|
|
ULARGE_INTEGER offset,
|
|
ULONG size,
|
|
const void* buffer,
|
|
ULONG* bytesWritten) DECLSPEC_HIDDEN;
|
|
|
|
BOOL BlockChainStream_SetSize(
|
|
BlockChainStream* This,
|
|
ULARGE_INTEGER newSize) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT BlockChainStream_Flush(
|
|
BlockChainStream* This) DECLSPEC_HIDDEN;
|
|
|
|
/****************************************************************************
|
|
* SmallBlockChainStream definitions.
|
|
*
|
|
* The SmallBlockChainStream class is a utility class that is used to create an
|
|
* abstraction of the small block chains in the storage file.
|
|
*/
|
|
struct SmallBlockChainStream
|
|
{
|
|
StorageImpl* parentStorage;
|
|
DirRef ownerDirEntry;
|
|
ULONG* headOfStreamPlaceHolder;
|
|
};
|
|
|
|
/*
|
|
* Methods of the SmallBlockChainStream class.
|
|
*/
|
|
SmallBlockChainStream* SmallBlockChainStream_Construct(
|
|
StorageImpl* parentStorage,
|
|
ULONG* headOfStreamPlaceHolder,
|
|
DirRef dirEntry) DECLSPEC_HIDDEN;
|
|
|
|
void SmallBlockChainStream_Destroy(
|
|
SmallBlockChainStream* This) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT SmallBlockChainStream_ReadAt(
|
|
SmallBlockChainStream* This,
|
|
ULARGE_INTEGER offset,
|
|
ULONG size,
|
|
void* buffer,
|
|
ULONG* bytesRead) DECLSPEC_HIDDEN;
|
|
|
|
HRESULT SmallBlockChainStream_WriteAt(
|
|
SmallBlockChainStream* This,
|
|
ULARGE_INTEGER offset,
|
|
ULONG size,
|
|
const void* buffer,
|
|
ULONG* bytesWritten) DECLSPEC_HIDDEN;
|
|
|
|
BOOL SmallBlockChainStream_SetSize(
|
|
SmallBlockChainStream* This,
|
|
ULARGE_INTEGER newSize) DECLSPEC_HIDDEN;
|
|
|
|
|
|
#endif /* __STORAGE32_H__ */
|