Improved performance.
This commit is contained in:
parent
0d5fe58361
commit
454ed9f0ba
|
@ -59,31 +59,32 @@ struct MappedPage
|
|||
LPVOID lpBytes;
|
||||
};
|
||||
|
||||
#define BLOCKS_PER_PAGE 128
|
||||
#define PAGE_SIZE 65536
|
||||
#define PAGE_SIZE 131072
|
||||
#define BLOCKS_PER_PAGE 256
|
||||
|
||||
#define NUMBER_OF_MAPPED_PAGES 100
|
||||
|
||||
/***********************************************************
|
||||
* Prototypes for private methods
|
||||
*/
|
||||
static void* BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This,
|
||||
DWORD pagenum,
|
||||
DWORD desired_access);
|
||||
DWORD desired_access);
|
||||
static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This,
|
||||
DWORD pagenum,
|
||||
DWORD access);
|
||||
DWORD access);
|
||||
static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This);
|
||||
static void* BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This,
|
||||
ULONG index,
|
||||
DWORD desired_access);
|
||||
ULONG index,
|
||||
DWORD desired_access);
|
||||
static BigBlock* BIGBLOCKFILE_GetBigBlockFromPointer(LPBIGBLOCKFILE This,
|
||||
void* pBlock);
|
||||
void* pBlock);
|
||||
static void BIGBLOCKFILE_RemoveBlock(LPBIGBLOCKFILE This,
|
||||
ULONG index);
|
||||
ULONG index);
|
||||
static BigBlock* BIGBLOCKFILE_AddBigBlock(LPBIGBLOCKFILE This,
|
||||
ULONG index);
|
||||
ULONG index);
|
||||
static BigBlock* BIGBLOCKFILE_CreateBlock(ULONG index);
|
||||
|
||||
static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
|
||||
static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
|
||||
|
||||
/******************************************************************************
|
||||
* BIGBLOCKFILE_Construct
|
||||
|
@ -94,7 +95,7 @@ static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
|
|||
*/
|
||||
BigBlockFile * BIGBLOCKFILE_Construct(
|
||||
HANDLE hFile,
|
||||
DWORD openFlags,
|
||||
DWORD openFlags,
|
||||
ULONG blocksize)
|
||||
{
|
||||
LPBIGBLOCKFILE This;
|
||||
|
@ -134,11 +135,11 @@ BigBlockFile * BIGBLOCKFILE_Construct(
|
|||
This->filesize.LowPart = GetFileSize(This->hfile, NULL);
|
||||
This->blocksize = blocksize;
|
||||
|
||||
/* create the read only mapped pages list
|
||||
/* create the mapped pages list
|
||||
*/
|
||||
This->headmap_ro = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
|
||||
This->maplisthead = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
|
||||
|
||||
if (This->headmap_ro == NULL)
|
||||
if (This->maplisthead == NULL)
|
||||
{
|
||||
CloseHandle(This->hfilemap);
|
||||
CloseHandle(This->hfile);
|
||||
|
@ -146,22 +147,7 @@ BigBlockFile * BIGBLOCKFILE_Construct(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
This->headmap_ro->next = NULL;
|
||||
|
||||
/* create the writeable mapped pages list
|
||||
*/
|
||||
This->headmap_w = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
|
||||
|
||||
if (This->headmap_w == NULL)
|
||||
{
|
||||
CloseHandle(This->hfilemap);
|
||||
CloseHandle(This->hfile);
|
||||
HeapFree(GetProcessHeap(), 0, This->headmap_ro);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
This->headmap_w->next = NULL;
|
||||
This->maplisthead->next = NULL;
|
||||
|
||||
/* initialize the block list
|
||||
*/
|
||||
|
@ -178,11 +164,10 @@ BigBlockFile * BIGBLOCKFILE_Construct(
|
|||
void BIGBLOCKFILE_Destructor(
|
||||
LPBIGBLOCKFILE This)
|
||||
{
|
||||
/* unmap all views and destroy the mapped page lists
|
||||
/* unmap all views and destroy the mapped page list
|
||||
*/
|
||||
BIGBLOCKFILE_FreeAllMappedPages(This);
|
||||
HeapFree(GetProcessHeap(), 0, This->headmap_ro);
|
||||
HeapFree(GetProcessHeap(), 0, This->headmap_w);
|
||||
HeapFree(GetProcessHeap(), 0, This->maplisthead);
|
||||
|
||||
/* close all open handles
|
||||
*/
|
||||
|
@ -262,7 +247,6 @@ void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index)
|
|||
* BIGBLOCKFILE_ReleaseBigBlock
|
||||
*
|
||||
* Releases the specified block.
|
||||
*
|
||||
*/
|
||||
void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock)
|
||||
{
|
||||
|
@ -615,126 +599,120 @@ static void * BIGBLOCKFILE_GetMappedView(
|
|||
DWORD pagenum,
|
||||
DWORD desired_access)
|
||||
{
|
||||
MappedPage * current;
|
||||
MappedPage * newMappedPage;
|
||||
DWORD hioffset, lowoffset;
|
||||
DWORD numBytesToMap;
|
||||
MappedPage* current = This->maplisthead;
|
||||
ULONG count = 1;
|
||||
BOOL found = FALSE;
|
||||
|
||||
/* use correct list
|
||||
assert(This->maplisthead != NULL);
|
||||
|
||||
/*
|
||||
* Search for the page in the list.
|
||||
*/
|
||||
if (desired_access == FILE_MAP_READ)
|
||||
current = This->headmap_ro;
|
||||
else if (desired_access == FILE_MAP_WRITE)
|
||||
current = This->headmap_w;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
hioffset = 0;
|
||||
lowoffset = PAGE_SIZE * pagenum;
|
||||
|
||||
while (current->next != NULL)
|
||||
while ((found == FALSE) && (current->next != NULL))
|
||||
{
|
||||
if (current->next->number == pagenum) /* page already mapped */
|
||||
if (current->next->number == pagenum)
|
||||
{
|
||||
current->next->ref++;
|
||||
return current->next->lpBytes;
|
||||
found = TRUE;
|
||||
|
||||
/*
|
||||
* If it's not already at the head of the list
|
||||
* move it there.
|
||||
*/
|
||||
if (current != This->maplisthead)
|
||||
{
|
||||
MappedPage* temp = current->next;
|
||||
|
||||
current->next = current->next->next;
|
||||
|
||||
temp->next = This->maplisthead->next;
|
||||
This->maplisthead->next = temp;
|
||||
}
|
||||
}
|
||||
else if (current->next->number > pagenum) /* this page is not mapped yet */
|
||||
|
||||
/*
|
||||
* The list is full and we haven't found it.
|
||||
* Free the last element of the list because we'll add a new
|
||||
* one at the head.
|
||||
*/
|
||||
if ((found == FALSE) &&
|
||||
(count >= NUMBER_OF_MAPPED_PAGES) &&
|
||||
(current->next != NULL))
|
||||
{
|
||||
/* allocate new MappedPage
|
||||
*/
|
||||
newMappedPage = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
|
||||
UnmapViewOfFile(current->next->lpBytes);
|
||||
|
||||
if (newMappedPage == NULL)
|
||||
return NULL;
|
||||
|
||||
/* initialize the new MappedPage
|
||||
*/
|
||||
newMappedPage->number = pagenum;
|
||||
newMappedPage->ref = 1;
|
||||
|
||||
newMappedPage->next = current->next;
|
||||
current->next = newMappedPage;
|
||||
|
||||
/* actually map the page
|
||||
*/
|
||||
if (((pagenum + 1) * PAGE_SIZE) > This->filesize.LowPart)
|
||||
numBytesToMap = This->filesize.LowPart - (pagenum * PAGE_SIZE);
|
||||
else
|
||||
numBytesToMap = PAGE_SIZE;
|
||||
|
||||
newMappedPage->lpBytes = MapViewOfFile(This->hfilemap,
|
||||
desired_access,
|
||||
hioffset,
|
||||
lowoffset,
|
||||
numBytesToMap);
|
||||
|
||||
return newMappedPage->lpBytes;
|
||||
HeapFree(GetProcessHeap(), 0, current->next);
|
||||
current->next = NULL;
|
||||
}
|
||||
else
|
||||
|
||||
if (current->next != NULL)
|
||||
current = current->next;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/* reached end of the list, this view is not mapped yet
|
||||
/*
|
||||
* Add the page at the head of the list.
|
||||
*/
|
||||
if (current->next == NULL)
|
||||
if (found == FALSE)
|
||||
{
|
||||
/* allocate new MappedPage
|
||||
*/
|
||||
MappedPage* newMappedPage;
|
||||
DWORD numBytesToMap;
|
||||
DWORD hioffset = 0;
|
||||
DWORD lowoffset = PAGE_SIZE * pagenum;
|
||||
|
||||
newMappedPage = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
|
||||
|
||||
if (newMappedPage == NULL)
|
||||
return NULL;
|
||||
|
||||
/* initialize the new MappedPage
|
||||
*/
|
||||
newMappedPage->number = pagenum;
|
||||
newMappedPage->ref = 1;
|
||||
newMappedPage->ref = 0;
|
||||
|
||||
newMappedPage->next = NULL;
|
||||
current->next = newMappedPage;
|
||||
newMappedPage->next = This->maplisthead->next;
|
||||
This->maplisthead->next = newMappedPage;
|
||||
|
||||
/* actually map the page
|
||||
*/
|
||||
if (((pagenum + 1) * PAGE_SIZE) > This->filesize.LowPart)
|
||||
numBytesToMap = This->filesize.LowPart - (pagenum * PAGE_SIZE);
|
||||
else
|
||||
numBytesToMap = PAGE_SIZE;
|
||||
|
||||
if (This->flProtect == PAGE_READONLY)
|
||||
desired_access = FILE_MAP_READ;
|
||||
else
|
||||
desired_access = FILE_MAP_WRITE;
|
||||
|
||||
newMappedPage->lpBytes = MapViewOfFile(This->hfilemap,
|
||||
desired_access,
|
||||
hioffset,
|
||||
lowoffset,
|
||||
numBytesToMap);
|
||||
|
||||
return newMappedPage->lpBytes;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
/*
|
||||
* The page we want should now be at the head of the list.
|
||||
*/
|
||||
assert(This->maplisthead->next != NULL);
|
||||
|
||||
current = This->maplisthead->next;
|
||||
current->ref++;
|
||||
|
||||
return current->lpBytes;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* BIGBLOCKFILE_ReleaseMappedPage [PRIVATE]
|
||||
*
|
||||
* Decrements the reference count of the mapped page.
|
||||
* If the page is not used anymore it will be unmapped.
|
||||
*/
|
||||
static void BIGBLOCKFILE_ReleaseMappedPage(
|
||||
LPBIGBLOCKFILE This,
|
||||
DWORD pagenum,
|
||||
DWORD access)
|
||||
{
|
||||
MappedPage * previous;
|
||||
MappedPage * current;
|
||||
MappedPage* previous = This->maplisthead;
|
||||
MappedPage* current;
|
||||
|
||||
/* use the list corresponding to the desired access mode
|
||||
*/
|
||||
if (access == FILE_MAP_READ)
|
||||
previous = This->headmap_ro;
|
||||
else if (access == FILE_MAP_WRITE)
|
||||
previous = This->headmap_w;
|
||||
else
|
||||
return;
|
||||
assert(This->maplisthead->next != NULL);
|
||||
|
||||
current = previous->next;
|
||||
|
||||
|
@ -747,17 +725,6 @@ static void BIGBLOCKFILE_ReleaseMappedPage(
|
|||
/* decrement the reference count
|
||||
*/
|
||||
current->ref--;
|
||||
|
||||
if (current->ref == 0)
|
||||
{
|
||||
/* this page is not used anymore, we can unmap it
|
||||
*/
|
||||
UnmapViewOfFile(current->lpBytes);
|
||||
|
||||
previous->next = current->next;
|
||||
HeapFree(GetProcessHeap(), 0, current);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -772,47 +739,25 @@ static void BIGBLOCKFILE_ReleaseMappedPage(
|
|||
* BIGBLOCKFILE_FreeAllMappedPages [PRIVATE]
|
||||
*
|
||||
* Unmap all currently mapped pages.
|
||||
* Empty both mapped pages lists.
|
||||
* Empty mapped pages list.
|
||||
*/
|
||||
static void BIGBLOCKFILE_FreeAllMappedPages(
|
||||
LPBIGBLOCKFILE This)
|
||||
{
|
||||
/*
|
||||
* start with the read only list
|
||||
*/
|
||||
MappedPage * current = This->headmap_ro->next;
|
||||
MappedPage * current = This->maplisthead->next;
|
||||
|
||||
while (current != NULL)
|
||||
{
|
||||
/* unmap views
|
||||
/* Unmap views.
|
||||
*/
|
||||
UnmapViewOfFile(current->lpBytes);
|
||||
|
||||
/* free the nodes
|
||||
/* Free the nodes.
|
||||
*/
|
||||
This->headmap_ro->next = current->next;
|
||||
This->maplisthead->next = current->next;
|
||||
HeapFree(GetProcessHeap(), 0, current);
|
||||
|
||||
current = This->headmap_ro->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* then do the write list
|
||||
*/
|
||||
current = This->headmap_w->next;
|
||||
|
||||
while (current != NULL)
|
||||
{
|
||||
/* unmap views
|
||||
*/
|
||||
UnmapViewOfFile(current->lpBytes);
|
||||
|
||||
/* free the nodes
|
||||
*/
|
||||
This->headmap_w->next = current->next;
|
||||
HeapFree(GetProcessHeap(), 0, current);
|
||||
|
||||
current = This->headmap_w->next;
|
||||
current = This->maplisthead->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
105
ole/storage32.c
105
ole/storage32.c
|
@ -2461,6 +2461,7 @@ void StorageImpl_SetNextBlockInChain(
|
|||
void* depotBuffer;
|
||||
|
||||
assert(depotBlockCount < This->bigBlockDepotCount);
|
||||
assert(blockIndex != nextBlock);
|
||||
|
||||
if (depotBlockCount < COUNT_BBDEPOTINHEADER)
|
||||
{
|
||||
|
@ -3740,12 +3741,28 @@ BlockChainStream* BlockChainStream_Construct(
|
|||
ULONG propertyIndex)
|
||||
{
|
||||
BlockChainStream* newStream;
|
||||
ULONG blockIndex;
|
||||
|
||||
newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
|
||||
|
||||
newStream->parentStorage = parentStorage;
|
||||
newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
|
||||
newStream->ownerPropertyIndex = propertyIndex;
|
||||
newStream->lastBlockNoInSequence = 0xFFFFFFFF;
|
||||
newStream->tailIndex = BLOCK_END_OF_CHAIN;
|
||||
newStream->numBlocks = 0;
|
||||
|
||||
blockIndex = BlockChainStream_GetHeadOfChain(newStream);
|
||||
|
||||
while (blockIndex != BLOCK_END_OF_CHAIN)
|
||||
{
|
||||
newStream->numBlocks++;
|
||||
newStream->tailIndex = blockIndex;
|
||||
|
||||
blockIndex = StorageImpl_GetNextBlockInChain(
|
||||
parentStorage,
|
||||
blockIndex);
|
||||
}
|
||||
|
||||
return newStream;
|
||||
}
|
||||
|
@ -3833,10 +3850,24 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This,
|
|||
BYTE* bufferWalker;
|
||||
BYTE* bigBlockBuffer;
|
||||
|
||||
if (This->lastBlockNoInSequence == 0xFFFFFFFF)
|
||||
This->lastBlockNoInSequence = blockNoInSequence;
|
||||
/*
|
||||
* Find the first block in the stream that contains part of the buffer.
|
||||
*/
|
||||
blockIndex = BlockChainStream_GetHeadOfChain(This);
|
||||
if (blockNoInSequence > This->lastBlockNoInSequence)
|
||||
{
|
||||
ULONG temp = blockNoInSequence;
|
||||
|
||||
blockIndex = This->lastBlockNoInSequenceIndex;
|
||||
blockNoInSequence -= This->lastBlockNoInSequence;
|
||||
This->lastBlockNoInSequence = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockIndex = BlockChainStream_GetHeadOfChain(This);
|
||||
This->lastBlockNoInSequence = blockNoInSequence;
|
||||
}
|
||||
|
||||
while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
|
||||
{
|
||||
|
@ -3846,6 +3877,8 @@ BOOL BlockChainStream_ReadAt(BlockChainStream* This,
|
|||
blockNoInSequence--;
|
||||
}
|
||||
|
||||
This->lastBlockNoInSequenceIndex = blockIndex;
|
||||
|
||||
/*
|
||||
* Start reading the buffer.
|
||||
*/
|
||||
|
@ -3906,10 +3939,25 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This,
|
|||
BYTE* bufferWalker;
|
||||
BYTE* bigBlockBuffer;
|
||||
|
||||
if (This->lastBlockNoInSequence == 0xFFFFFFFF)
|
||||
This->lastBlockNoInSequence = blockNoInSequence;
|
||||
|
||||
/*
|
||||
* Find the first block in the stream that contains part of the buffer.
|
||||
*/
|
||||
blockIndex = BlockChainStream_GetHeadOfChain(This);
|
||||
if (blockNoInSequence > This->lastBlockNoInSequence)
|
||||
{
|
||||
ULONG temp = blockNoInSequence;
|
||||
|
||||
blockIndex = This->lastBlockNoInSequenceIndex;
|
||||
blockNoInSequence -= This->lastBlockNoInSequence;
|
||||
This->lastBlockNoInSequence = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockIndex = BlockChainStream_GetHeadOfChain(This);
|
||||
This->lastBlockNoInSequence = blockNoInSequence;
|
||||
}
|
||||
|
||||
while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN))
|
||||
{
|
||||
|
@ -3919,6 +3967,8 @@ BOOL BlockChainStream_WriteAt(BlockChainStream* This,
|
|||
blockNoInSequence--;
|
||||
}
|
||||
|
||||
This->lastBlockNoInSequenceIndex = blockIndex;
|
||||
|
||||
/*
|
||||
* Here, I'm casting away the constness on the buffer variable
|
||||
* This is OK since we don't intend to modify that buffer.
|
||||
|
@ -4001,6 +4051,9 @@ BOOL BlockChainStream_Shrink(BlockChainStream* This,
|
|||
blockIndex,
|
||||
BLOCK_END_OF_CHAIN);
|
||||
|
||||
This->tailIndex = blockIndex;
|
||||
This->numBlocks = numBlocks;
|
||||
|
||||
/*
|
||||
* Mark the extra blocks as free
|
||||
*/
|
||||
|
@ -4046,24 +4099,25 @@ BOOL BlockChainStream_Enlarge(BlockChainStream* This,
|
|||
}
|
||||
else
|
||||
{
|
||||
StgProperty chainProp;
|
||||
assert(This->ownerPropertyIndex != PROPERTY_NULL);
|
||||
StgProperty chainProp;
|
||||
assert(This->ownerPropertyIndex != PROPERTY_NULL);
|
||||
|
||||
StorageImpl_ReadProperty(
|
||||
This->parentStorage,
|
||||
This->ownerPropertyIndex,
|
||||
&chainProp);
|
||||
StorageImpl_ReadProperty(
|
||||
This->parentStorage,
|
||||
This->ownerPropertyIndex,
|
||||
&chainProp);
|
||||
|
||||
chainProp.startingBlock = blockIndex;
|
||||
|
||||
StorageImpl_WriteProperty(
|
||||
This->parentStorage,
|
||||
This->ownerPropertyIndex,
|
||||
&chainProp);
|
||||
}
|
||||
}
|
||||
StorageImpl_WriteProperty(
|
||||
This->parentStorage,
|
||||
This->ownerPropertyIndex,
|
||||
&chainProp);
|
||||
}
|
||||
|
||||
currentBlock = blockIndex;
|
||||
This->tailIndex = blockIndex;
|
||||
This->numBlocks = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out how many blocks are needed to contain this stream
|
||||
|
@ -4076,15 +4130,25 @@ BOOL BlockChainStream_Enlarge(BlockChainStream* This,
|
|||
/*
|
||||
* Go to the current end of chain
|
||||
*/
|
||||
while (blockIndex != BLOCK_END_OF_CHAIN)
|
||||
if (This->tailIndex == BLOCK_END_OF_CHAIN)
|
||||
{
|
||||
oldNumBlocks++;
|
||||
currentBlock = blockIndex;
|
||||
|
||||
blockIndex =
|
||||
StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
|
||||
while (blockIndex != BLOCK_END_OF_CHAIN)
|
||||
{
|
||||
This->numBlocks++;
|
||||
currentBlock = blockIndex;
|
||||
|
||||
blockIndex =
|
||||
StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock);
|
||||
}
|
||||
|
||||
This->tailIndex = currentBlock;
|
||||
}
|
||||
|
||||
currentBlock = This->tailIndex;
|
||||
oldNumBlocks = This->numBlocks;
|
||||
|
||||
/*
|
||||
* Add new blocks to the chain
|
||||
*/
|
||||
|
@ -4106,6 +4170,9 @@ BOOL BlockChainStream_Enlarge(BlockChainStream* This,
|
|||
oldNumBlocks++;
|
||||
}
|
||||
|
||||
This->tailIndex = blockIndex;
|
||||
This->numBlocks = newNumBlocks;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -140,8 +140,7 @@ struct BigBlockFile
|
|||
HANDLE hfile;
|
||||
HANDLE hfilemap;
|
||||
DWORD flProtect;
|
||||
MappedPage *headmap_ro;
|
||||
MappedPage *headmap_w;
|
||||
MappedPage *maplisthead;
|
||||
BigBlock *headblock;
|
||||
};
|
||||
|
||||
|
@ -724,8 +723,12 @@ void StorageUtl_CopyPropertyToSTATSTG(STATSTG* destination,
|
|||
struct BlockChainStream
|
||||
{
|
||||
StorageImpl* parentStorage;
|
||||
ULONG* headOfStreamPlaceHolder;
|
||||
ULONG ownerPropertyIndex;
|
||||
ULONG* headOfStreamPlaceHolder;
|
||||
ULONG ownerPropertyIndex;
|
||||
ULONG lastBlockNoInSequence;
|
||||
ULONG lastBlockNoInSequenceIndex;
|
||||
ULONG tailIndex;
|
||||
ULONG numBlocks;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue