You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1724 lines
59 KiB
1724 lines
59 KiB
/*++
|
|
|
|
Copyright (C) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
VarObjHeap.CPP
|
|
|
|
Abstract:
|
|
|
|
Implements the storage of variable length objects over the top of of a fixed
|
|
length page system. It keeps a set of admin pages for holding the pages active
|
|
by this subsystem, along with how much space is used on each. When a page becomes
|
|
empty it frees up the page to the page system. It also deals with blocks that span
|
|
multiple pages
|
|
|
|
History:
|
|
paulall 02-Feb-2001 Created
|
|
|
|
--*/
|
|
#include "precomp.h"
|
|
#include "VarObjHeap.h"
|
|
#include "pagemgr.h"
|
|
#include <wbemutil.h>
|
|
|
|
|
|
//**************************************************************************************
|
|
//CVarObjHeap will do little other than initialize variables. The Initialize method
|
|
//deals with starting everything up.
|
|
//**************************************************************************************
|
|
CVarObjHeap::CVarObjHeap()
|
|
: m_pObjectFile(NULL), m_dwPageSize(0), m_dwStatus(AdminPagesNeedReading)
|
|
{
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//~CVarObjHeap will break the connection with the transacted object file layer
|
|
//**************************************************************************************
|
|
CVarObjHeap::~CVarObjHeap()
|
|
{
|
|
Shutdown(0);
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Initialize will create the link with the transacted object file layer
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::Initialize(CPageSource *pPageManager)
|
|
{
|
|
//Initialize the object file layer...
|
|
DWORD dwRes = pPageManager->GetObjectHeapPageFile(&m_pObjectFile);
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
m_dwPageSize = m_pObjectFile->GetPageSize();
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
m_dwStatus = AdminPagesNeedReading;
|
|
dwRes = ReadAdminPages(pPageManager, true);
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Shutdown will close the transactioned object file layer and tidy up anything else
|
|
//that is needed.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::Shutdown(DWORD dwShutdownType)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
//Flush the admin pages... remember the error though!
|
|
dwRes = FlushAdminPages();
|
|
|
|
if (m_pObjectFile)
|
|
{
|
|
m_pObjectFile->Release();
|
|
m_pObjectFile = NULL;
|
|
}
|
|
|
|
//Delete the admin pages structures
|
|
m_aAdminPages.Lock();
|
|
while (m_aAdminPages.Size())
|
|
{
|
|
VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[0];
|
|
delete [] pEntry->pbPage;
|
|
delete pEntry;
|
|
m_aAdminPages.RemoveAt(0);
|
|
}
|
|
m_aAdminPages.Unlock();
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//InvalidateCache - called when a transaction is aborted and we need to re-read cached
|
|
//data. Data we cache is mainlyh the admin pages, therefore we should just re-read
|
|
//them.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::InvalidateCache()
|
|
{
|
|
m_dwStatus = AdminPagesNeedReading;
|
|
return ReadAdminPages(0, true);
|
|
}
|
|
|
|
DWORD CVarObjHeap::FlushCaches()
|
|
{
|
|
m_dwStatus = AdminPagesNeedReading;
|
|
return ReadAdminPages(0, false);
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//ReadBuffer retrieves the appropriate page(s) from the virtual page store and copies
|
|
//off the actual block from those page(s). It may reside on the main page if it is small,
|
|
//it may reside on main page and some of the next page, or it may reside on main page,
|
|
//one or more whole pages following that, followed by a partial (or full) page.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::ReadBuffer(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulOffsetId,
|
|
/* out */ BYTE **ppReturnedBlock,
|
|
/* out */ DWORD *pdwBlockSize)
|
|
{
|
|
if ((ulPageId == 0) || (ulOffsetId == 0))
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
if (m_dwStatus == NoError)
|
|
{
|
|
//Nothing to do... help with compiler prediction logic
|
|
}
|
|
else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
|
|
{
|
|
dwRes = ReadAdminPages(0, true);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
return dwRes;
|
|
}
|
|
else if (m_dwStatus == RootAdminPageCreationFailure)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
//We need to retrieve the page from the file store, and then we need to retrieve the
|
|
//block from the the page. We need to allocate the appropriate memory and copy it
|
|
//into that memory.
|
|
|
|
|
|
BYTE *pbPage = new BYTE[m_dwPageSize];
|
|
if (pbPage == NULL)
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
CVectorDeleteMe<BYTE> vdm1(pbPage);
|
|
|
|
//So, first we need to retrieve the page...
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = m_pObjectFile->GetPage(ulPageId, 0, pbPage);
|
|
_ASSERT(dwRes != ERROR_FILE_NOT_FOUND, "WinMgmt: Page was requested that could not be found!");
|
|
}
|
|
|
|
//Retrieve the REAL offset and size to the block based on offsetId
|
|
BYTE *pOffsetPointer = NULL;
|
|
DWORD dwBlockSize = 0;
|
|
DWORD dwCRC32 = 0;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = OffsetToPointer(ulOffsetId, pbPage, &pOffsetPointer, &dwBlockSize, &dwCRC32);
|
|
_ASSERT(dwRes != ERROR_FILE_NOT_FOUND, "WinMgmt: Offset within page not found!\n");
|
|
}
|
|
|
|
//We can now allocate the real block now as we know how big it is. We may not have all
|
|
//the pages in memory yet though!
|
|
BYTE *pBlock = NULL;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
pBlock = new BYTE[dwBlockSize];
|
|
|
|
if ((dwRes == ERROR_SUCCESS) && (pBlock == NULL))
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
|
|
DWORD dwBlockNumber = 0;
|
|
DWORD dwAmountCopiedSoFar = 0;
|
|
|
|
//Copy off the first block
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwSizeOfFirstPageBlock = min(dwBlockSize, DWORD((pbPage + m_dwPageSize) - pOffsetPointer));
|
|
dwAmountCopiedSoFar = dwSizeOfFirstPageBlock;
|
|
memcpy(pBlock, pOffsetPointer, dwSizeOfFirstPageBlock);
|
|
}
|
|
//We should now loop through the pages (retrieving them if necessary) and copying
|
|
//the data into our buffer
|
|
while ((dwRes == ERROR_SUCCESS) && (dwAmountCopiedSoFar < dwBlockSize))
|
|
{
|
|
dwBlockNumber++;
|
|
|
|
//Read the next page...
|
|
dwRes = m_pObjectFile->GetPage(ulPageId + dwBlockNumber, 0, pbPage);
|
|
_ASSERT(dwRes != ERROR_FILE_NOT_FOUND, "WinMgmt: Page was requested that could not be found!");
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//Distinguish if this is a full page or not...
|
|
if ((dwAmountCopiedSoFar + m_dwPageSize) > dwBlockSize)
|
|
{
|
|
//This is a partial block, so copy as much as is needed
|
|
DWORD dwPartialSize = dwBlockSize - dwAmountCopiedSoFar;
|
|
memcpy((pBlock + dwAmountCopiedSoFar), pbPage, dwPartialSize);
|
|
dwAmountCopiedSoFar += dwPartialSize;
|
|
}
|
|
else
|
|
{
|
|
//This is a full block, so grab it all...
|
|
memcpy((pBlock + dwAmountCopiedSoFar), pbPage, m_dwPageSize);
|
|
dwAmountCopiedSoFar += m_dwPageSize;
|
|
}
|
|
}
|
|
}
|
|
#ifdef DBG
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//Can only check for single-page blocks!
|
|
if (ulOffsetId != 1)
|
|
{
|
|
dwRes = ValidatePageCRCWithAdminPage(pbPage, ulPageId);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//If we are successful, lets do a CRC check on the object
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
try
|
|
{
|
|
DWORD dwNewCRC32 = CreateCRC32(pBlock, dwBlockSize);
|
|
FINALIZE_CRC32(dwNewCRC32);
|
|
if (dwNewCRC32 != dwCRC32)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: CRC check on an object retrieved from repository is invalid\n");
|
|
DebugBreak();
|
|
#endif
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
}
|
|
catch (...)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: CRC check on an object retrieved from repository is invalid\n");
|
|
DebugBreak();
|
|
#endif
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
//If successful we need to return the pointer to the object
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
*ppReturnedBlock = pBlock;
|
|
*pdwBlockSize = dwBlockSize;
|
|
}
|
|
else
|
|
{
|
|
delete [] pBlock;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//WriteNewBuffer will write a new page based on size of BYTE *, and return the
|
|
//new virtual pageId and offsetId of the block. Although we may use multiple pages
|
|
//we only need to return the details of the first page.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::WriteNewBuffer(/* in */ ULONG ulBlockSize,
|
|
/* in */ const BYTE *pBlock,
|
|
/* out */ ULONG *pulPageId,
|
|
/* out */ ULONG *pulOffsetId)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
if (m_dwStatus == NoError)
|
|
{
|
|
//Nothing to do... help with compiler prediction logic
|
|
}
|
|
else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
|
|
{
|
|
dwRes = ReadAdminPages(0, true);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
return dwRes;
|
|
}
|
|
else if (m_dwStatus == RootAdminPageCreationFailure)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
//If this block will not fit on a single page we call the dedicated method!
|
|
if (ulBlockSize > (m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2)))
|
|
return AllocateMultiPageBuffer(ulBlockSize, pBlock, pulPageId, pulOffsetId);
|
|
|
|
BYTE *pbPage = new BYTE[m_dwPageSize];
|
|
if (pbPage == NULL)
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
CVectorDeleteMe<BYTE> vdm(pbPage);
|
|
|
|
DWORD dwPageId = 0;
|
|
|
|
//We are going to loop for a few times in case our admin pages for some reason
|
|
//are out of sink with the actual pages.
|
|
for (int i = 0; i != 10 ; i++)
|
|
{
|
|
//Find a page that has enough space for this
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = FindPageWithSpace(ulBlockSize, &dwPageId);
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//There is a page with space in it!
|
|
//Read the page from the file
|
|
dwRes = m_pObjectFile->GetPage(dwPageId, 0, pbPage);
|
|
|
|
#ifdef DBG
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = ValidatePageCRCWithAdminPage(pbPage, dwPageId);
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = ValidatePageFreeSpaceWithAdminPage(pbPage, dwPageId);
|
|
#endif /* DBG */
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
DWORD ulFreeSpaceLeft = 0;
|
|
dwRes = ValidatePageFreeSpace(pbPage, ulBlockSize, &ulFreeSpaceLeft);
|
|
|
|
if (dwRes == ERROR_INTERNAL_ERROR)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE,
|
|
"****REPOSITORY INCONSISTENCY DETECTED!****\n"
|
|
"****Admin page recorded page %ul had enough space available for %ul bytes****\n"
|
|
"****In reality it did not have enough space, and only has %ul left****\n"
|
|
"****Adjusting space in admin page to match actual space in page****\n",
|
|
dwPageId, ulBlockSize + sizeof(VarObjObjOffsetEntry), ulFreeSpaceLeft
|
|
));
|
|
//Something is screwed up on this page. Initiate recovery sequence.
|
|
DWORD dwCRC32 = 0;
|
|
dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
|
|
FINALIZE_CRC32(dwCRC32);
|
|
|
|
UpdateAdminPageForAllocate2(dwPageId, ulFreeSpaceLeft, dwCRC32);
|
|
|
|
|
|
if (i == 9)
|
|
{
|
|
ERRORTRACE((LOG_WBEMCORE,
|
|
"****TOO MANY REPOSITORY INCONSISTENCIES DETECTED!****\n"
|
|
"****ABORTING CURRENT OPERATION!****\n"
|
|
));
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
dwRes = ERROR_SUCCESS; //cancel error so we can try again
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
break; //something bad happened, lets bail
|
|
}
|
|
else if (dwRes == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
//We didn't find space so we allocate a new page
|
|
|
|
dwRes = AllocateNewPage(ulBlockSize, &dwPageId, pbPage);
|
|
break;
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
//We now have a page, albeit a new page or an existing one, so now we need
|
|
//to allocate space from it
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = AllocateFromPage(dwPageId, pbPage, ulBlockSize, pBlock, pulOffsetId);
|
|
}
|
|
|
|
//Write the page to the object file
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = m_pObjectFile->PutPage(dwPageId, 0, pbPage);
|
|
|
|
DWORD dwCRC32 = 0;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
|
|
FINALIZE_CRC32(dwCRC32);
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = UpdateAdminPageForAllocate(dwPageId, ulBlockSize, dwCRC32);
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = FlushAdminPages();
|
|
|
|
//Update the pageId for the client caller
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
*pulPageId = dwPageId;
|
|
if ((*pulPageId == 0) || (*pulOffsetId == 0))
|
|
{
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
#ifdef DBG
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef DBG
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = ValidatePageFreeSpaceWithAdminPage(pbPage, dwPageId);
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = ValidateAllCRC32OnPage(pbPage);
|
|
#endif
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//WriteExistingBuffer will update an existing block with new data. The old virtual page
|
|
//and offset are passed in, and new ones are returned. They may or may not be the same
|
|
//depending on if it still fits in the page or not.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::WriteExistingBuffer(/* in */ ULONG ulBlockSize,
|
|
/* in */ const BYTE *pBlock,
|
|
/* in */ ULONG ulOldPageId,
|
|
/* in */ ULONG ulOldOffsetId,
|
|
/* out */ ULONG *pulNewPageId,
|
|
/* out */ ULONG *pulNewOffsetId)
|
|
{
|
|
//Validate the in parameters!
|
|
if ((ulOldPageId == 0) || (ulOldOffsetId == 0))
|
|
{
|
|
#ifdef DBG
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
if (m_dwStatus == NoError)
|
|
{
|
|
//Nothing to do... help with compiler prediction logic
|
|
}
|
|
else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
|
|
{
|
|
dwRes = ReadAdminPages(0, true);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
return dwRes;
|
|
}
|
|
else if (m_dwStatus == RootAdminPageCreationFailure)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
//We need to retrieve the page that is being updated, then we need to overwrite the
|
|
//original stuff in the page. We may need to shuffle all the existing blocks around
|
|
//within the page to make sure everything is fully packed. We may need to adjust
|
|
//the free-page list with the amount of space we have available on this page.
|
|
//TODO! Do this properly!!!
|
|
dwRes = DeleteBuffer(ulOldPageId, ulOldOffsetId);
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = WriteNewBuffer(ulBlockSize, pBlock, pulNewPageId, pulNewOffsetId);
|
|
|
|
//Validate the out parameters!
|
|
if ((*pulNewPageId == 0) || (*pulNewOffsetId == 0))
|
|
{
|
|
#ifdef DBG
|
|
DebugBreak();
|
|
#endif
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//DeleteBuffer is called to delete the item in the store given the virtual pageId and
|
|
//offsetId.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::DeleteBuffer(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulOffsetId)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
if (m_dwStatus == NoError)
|
|
{
|
|
//Nothing to do... help with compiler prediction logic
|
|
}
|
|
else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
|
|
{
|
|
dwRes = ReadAdminPages(0, true);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
return dwRes;
|
|
}
|
|
else if (m_dwStatus == RootAdminPageCreationFailure)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
//Allocate space for the page we are going to manipulate
|
|
BYTE *pbPage = new BYTE[m_dwPageSize];
|
|
if (pbPage == NULL)
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
CVectorDeleteMe<BYTE> vdm(pbPage);
|
|
|
|
//Retrieve the page that contains this object
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = m_pObjectFile->GetPage(ulPageId, 0, pbPage);
|
|
_ASSERT(dwRes != ERROR_FILE_NOT_FOUND, "WinMgmt: Page not found!\n");
|
|
}
|
|
|
|
//If this object is a multi-page object we have a different algorithm
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
if (MultiPageObject(pbPage))
|
|
return DeleteMultiPageBuffer(ulPageId, ulOffsetId, pbPage);
|
|
}
|
|
|
|
//Remove the object from this page
|
|
DWORD dwSize = 0;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = RemoveFromPage(ulPageId, ulOffsetId, pbPage, &dwSize);
|
|
_ASSERT(dwRes != ERROR_FILE_NOT_FOUND, "WinMgmt: Offset within page not found!\n");
|
|
}
|
|
|
|
DWORD dwCRC32 = 0;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
|
|
FINALIZE_CRC32(dwCRC32);
|
|
}
|
|
|
|
//Update the admin page, possibly even deleting the page!
|
|
bool bPageDeleted = false;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = UpdateAdminPageForDelete(ulPageId, dwSize, dwCRC32, &bPageDeleted);
|
|
|
|
//Flush the page back to the object file and update admin page
|
|
if ((dwRes == ERROR_SUCCESS) && !bPageDeleted)
|
|
{
|
|
dwRes = m_pObjectFile->PutPage(ulPageId, 0, pbPage);
|
|
}
|
|
|
|
//Flush the admin pages
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = FlushAdminPages();
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
|
|
//**************************************************************************************
|
|
//AllocateFromPage - adds an allocation to the end of the existing allocations
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::AllocateFromPage(/* in */ DWORD dwPageId,
|
|
/* in */ BYTE *pbPage,
|
|
/* in */ ULONG ulBlockSize,
|
|
/* in */ const BYTE *pBlock,
|
|
/* out*/ ULONG *pdwNewOffset)
|
|
{
|
|
#ifdef XFILES_DEBUG
|
|
if (dwPageId == 0x125)
|
|
{
|
|
OutputDebugString(L"===============================\n");
|
|
OutputDebugString(L"Start of AllocateFromPage\n");
|
|
DumpPageOffsetTable(dwPageId, pbPage);
|
|
}
|
|
#endif
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
//Get a pointer to the start of the offset table
|
|
VarObjObjOffsetEntry *pOffsetEntry = (VarObjObjOffsetEntry *) pbPage;
|
|
|
|
//This is the location where the last block resided and size so we can calculate
|
|
//where the new block goes
|
|
DWORD dwLastOffset = pOffsetEntry[0].dwPhysicalStartOffset;
|
|
DWORD dwLastSize = 0;
|
|
DWORD dwNewOffsetId = 0;
|
|
bool bNewOffsetIdClash = false;
|
|
|
|
do
|
|
{
|
|
dwNewOffsetId = GetTickCount() + (DWORD)rand();
|
|
} while (dwNewOffsetId == 0);
|
|
|
|
|
|
//Loop through the table until we get to the end... adjusting the offset within the
|
|
//entries along the way to account for the fact we will be shifting them by the size
|
|
//of an offset entry.
|
|
for (DWORD dwOffsetIndex = 0; pOffsetEntry[dwOffsetIndex].dwOffsetId != 0; dwOffsetIndex++)
|
|
{
|
|
//Shuffle the size of this offset by one entry because we will be doing a memcpy
|
|
//when this is done so we have room for our new entry.
|
|
pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset += sizeof VarObjObjOffsetEntry;
|
|
dwLastOffset = pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset;
|
|
dwLastSize = pOffsetEntry[dwOffsetIndex].dwBlockLength;
|
|
|
|
if (pOffsetEntry[dwOffsetIndex].dwOffsetId == dwNewOffsetId)
|
|
{
|
|
bNewOffsetIdClash = true;
|
|
}
|
|
}
|
|
|
|
//While we have an offset clash we need to keep re-calculating
|
|
while (bNewOffsetIdClash)
|
|
{
|
|
bNewOffsetIdClash = false;
|
|
do
|
|
{
|
|
dwNewOffsetId = GetTickCount() + (DWORD)rand();
|
|
} while (dwNewOffsetId == 0);
|
|
|
|
for (DWORD dwIndex = 0; pOffsetEntry[dwIndex].dwOffsetId != 0; dwIndex++)
|
|
{
|
|
if (pOffsetEntry[dwIndex].dwOffsetId == dwNewOffsetId)
|
|
{
|
|
bNewOffsetIdClash = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Now dwOffsetIndex is where we are going to insert this new offset entry, and dwLastOffset + dwLastSize
|
|
//is the new location where we need to copy this data...
|
|
|
|
//Only problem now though is that we need to shuffle all data along by the size of an offset entry!
|
|
MoveMemory(&pOffsetEntry[dwOffsetIndex+1], &pOffsetEntry[dwOffsetIndex], ((dwLastOffset + dwLastSize) - pOffsetEntry[0].dwPhysicalStartOffset) + sizeof(VarObjObjOffsetEntry));
|
|
|
|
//Write the new entry in the offset table
|
|
pOffsetEntry[dwOffsetIndex].dwOffsetId = dwNewOffsetId;
|
|
|
|
if (dwLastOffset == 0)
|
|
{
|
|
//First block of the page!
|
|
pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset = (sizeof(VarObjObjOffsetEntry) * 2);
|
|
}
|
|
else
|
|
{
|
|
pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset = dwLastOffset + dwLastSize;
|
|
}
|
|
|
|
pOffsetEntry[dwOffsetIndex].dwBlockLength = ulBlockSize;
|
|
|
|
#if XFILES_DEBUG
|
|
if (dwPageId == 0x125)
|
|
{
|
|
OutputDebugString(L"===============================\n");
|
|
OutputDebugString(L"Start of AllocateFromPage\n");
|
|
DumpPageOffsetTable(dwPageId, pbPage);
|
|
}
|
|
#endif
|
|
|
|
//Write the block to the page
|
|
#ifdef DBG
|
|
if (pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset + ulBlockSize > m_dwPageSize)
|
|
{
|
|
OutputDebugString(L"WinMgmt: Object heap is about to write past the end of a page boundary and will cause heap corruption if we continue!\n");
|
|
DebugBreak();
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
}
|
|
#endif
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//Generate the CRC
|
|
DWORD dwCRC32 = CreateCRC32(pBlock, ulBlockSize);
|
|
FINALIZE_CRC32(dwCRC32);
|
|
pOffsetEntry[dwOffsetIndex].dwCRC = dwCRC32;
|
|
|
|
//Copy the blob into the block
|
|
CopyMemory(pbPage + pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset, pBlock, ulBlockSize);
|
|
|
|
//Return the offset ID
|
|
*pdwNewOffset = dwNewOffsetId;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//OffsetToPointer - Given and offsetId and a page, calculate the physical pointer to the
|
|
//object and also return the size of the block.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::OffsetToPointer(/* in */ ULONG ulOffsetId,
|
|
/* in */ BYTE *pbPage,
|
|
/* out*/ BYTE **pOffsetPointer,
|
|
/* out*/ ULONG *pdwBlockSize,
|
|
/* out*/ DWORD *pdwCRC32)
|
|
{
|
|
DWORD dwRes = ERROR_FILE_NOT_FOUND;
|
|
|
|
//Get a pointer to the start of the offset table
|
|
VarObjObjOffsetEntry *pOffsetEntry = (VarObjObjOffsetEntry *) pbPage;
|
|
|
|
//Loop through the table until we find the one we are interested in
|
|
for (DWORD dwOffsetIndex = 0; pOffsetEntry[dwOffsetIndex].dwOffsetId != 0; dwOffsetIndex++)
|
|
{
|
|
if (pOffsetEntry[dwOffsetIndex].dwOffsetId == ulOffsetId)
|
|
{
|
|
dwRes = ERROR_SUCCESS;
|
|
*pdwBlockSize = pOffsetEntry[dwOffsetIndex].dwBlockLength;
|
|
*pOffsetPointer = pbPage + pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset;
|
|
*pdwCRC32 = pOffsetEntry[dwOffsetIndex].dwCRC;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
|
|
//**************************************************************************************
|
|
//ReadAdminPages - Reads the admin pages into memory and marks them as clean (no changes)
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::ReadAdminPages(CPageSource *pTransactionManager, bool bReReadPages)
|
|
{
|
|
m_aAdminPages.Lock();
|
|
|
|
//Check it wasn't lock contention that meant we had multiple
|
|
//threads trying to re-read the admin pages.
|
|
if (m_dwStatus == NoError)
|
|
{
|
|
m_aAdminPages.Unlock();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//Delete anything we may already have in the list in case we need to re-read it in
|
|
//case of an aborted transaction.
|
|
while (m_aAdminPages.Size())
|
|
{
|
|
VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[0];
|
|
delete [] pEntry->pbPage;
|
|
delete pEntry;
|
|
m_aAdminPages.RemoveAt(0);
|
|
}
|
|
|
|
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
if (bReReadPages)
|
|
{
|
|
m_dwStatus = AdminPagesNeedReading;
|
|
|
|
DWORD dwAdminPageId = 0; //First admin page always resides on page 0
|
|
do
|
|
{
|
|
bool bDirty = false;
|
|
BYTE *pbAdminPage = new BYTE[m_dwPageSize];
|
|
VarObjAdminPageEntry *pEntry = new VarObjAdminPageEntry;
|
|
if ((pbAdminPage == NULL) || (pEntry == NULL))
|
|
{
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
m_dwStatus = AdminPageReadFailure;
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = m_pObjectFile->GetPage(dwAdminPageId, 0, pbAdminPage);
|
|
|
|
if ((dwRes == ERROR_FILE_NOT_FOUND) && (dwAdminPageId != 0))
|
|
{
|
|
_ASSERT(0, "WinMgmt: We lost the admin pages!\n");
|
|
}
|
|
|
|
if ((dwRes == ERROR_FILE_NOT_FOUND) && (dwAdminPageId == 0))
|
|
{
|
|
//This is the first attempt, so we need to create the admin page!
|
|
dwRes = m_pObjectFile->NewPage(1, 1, &dwAdminPageId);
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//Write the default data to the admin page
|
|
bDirty = true;
|
|
VarObjHeapAdminPage* pAdminPage = (VarObjHeapAdminPage*)pbAdminPage;
|
|
pAdminPage->dwNextAdminPage = 0;
|
|
pAdminPage->dwNumberEntriesOnPage = 0;
|
|
pAdminPage->dwVersion = VAROBJ_VERSION;
|
|
|
|
dwRes = m_pObjectFile->PutPage(dwAdminPageId, 0, pbAdminPage);
|
|
if (dwRes != ERROR_SUCCESS)
|
|
{
|
|
m_dwStatus = RootAdminPageCreationFailure;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwStatus = RootAdminPageCreationFailure;
|
|
}
|
|
}
|
|
else if ((dwAdminPageId == 0) && (dwRes != ERROR_SUCCESS))
|
|
{
|
|
m_dwStatus = AdminPageReadFailure;
|
|
}
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
pEntry->dwPageId = dwAdminPageId;
|
|
pEntry->pbPage = pbAdminPage;
|
|
pEntry->bDirty = bDirty;
|
|
}
|
|
|
|
if ((dwRes == ERROR_SUCCESS) && (m_aAdminPages.Add(pEntry) != CFlexArray::no_error))
|
|
{
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
m_dwStatus = AdminPageReadFailure;
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwAdminPageId = ((VarObjHeapAdminPage*)pbAdminPage)->dwNextAdminPage;
|
|
else
|
|
{
|
|
//Tidy up!
|
|
delete [] pbAdminPage;
|
|
delete pEntry;
|
|
}
|
|
}
|
|
while ((dwRes == ERROR_SUCCESS) && (dwAdminPageId != 0));
|
|
|
|
//If we had a problem we need to delete everything in the admin list
|
|
if (dwRes != ERROR_SUCCESS)
|
|
{
|
|
while (m_aAdminPages.Size())
|
|
{
|
|
VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[0];
|
|
delete [] pEntry->pbPage;
|
|
delete pEntry;
|
|
m_aAdminPages.RemoveAt(0);
|
|
}
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
m_dwStatus = NoError;
|
|
}
|
|
|
|
}
|
|
m_aAdminPages.Unlock();
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//FlushAdminPages - Writes each of the changed admin pages back to the object file
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::FlushAdminPages()
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
m_aAdminPages.Lock();
|
|
for (DWORD dwIndex = 0; dwIndex != m_aAdminPages.Size(); dwIndex++)
|
|
{
|
|
VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwIndex];
|
|
#if DBG
|
|
if ((dwIndex == 0) && (pEntry->dwPageId != 0))
|
|
{
|
|
OutputDebugString(L"WinMgmt: Repository corrupt! First admin page should always be page 0!\n");
|
|
DebugBreak();
|
|
}
|
|
VarObjHeapAdminPage *pAdminPage = (VarObjHeapAdminPage*) pEntry->pbPage;
|
|
if ((dwIndex != 0) && (pAdminPage->dwVersion != 0))
|
|
{
|
|
OutputDebugString(L"WinMmgt: Repository corrupt! Trailing admin pages should have version stamp of 0!\n");
|
|
DebugBreak();
|
|
}
|
|
#endif
|
|
if (pEntry->bDirty)
|
|
dwRes = m_pObjectFile->PutPage(pEntry->dwPageId, 0, pEntry->pbPage);
|
|
if (dwRes == ERROR_SUCCESS)
|
|
pEntry->bDirty = false;
|
|
else
|
|
break;
|
|
}
|
|
m_aAdminPages.Unlock();
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Find a page form the admin pages that can accomodate a particular buffer size
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::FindPageWithSpace(/* in */ DWORD dwRequiredSize,
|
|
/* out*/ DWORD *pdwPageId)
|
|
{
|
|
DWORD dwRes = ERROR_FILE_NOT_FOUND;
|
|
|
|
m_aAdminPages.Lock();
|
|
for (DWORD dwPageIndex = 0; (*pdwPageId == 0) && (dwPageIndex != m_aAdminPages.Size()); dwPageIndex++)
|
|
{
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
#if DBG
|
|
if ((dwPageIndex != 0) && (pAdminPage->dwVersion != 0))
|
|
{
|
|
OutputDebugString(L"WinMgmt: Repository admin page is corrupt as version is invalid!\n");
|
|
DebugBreak();
|
|
}
|
|
if (pAdminPage->dwNumberEntriesOnPage > ((m_dwPageSize - sizeof(VarObjHeapAdminPage)) / sizeof(VarObjHeapFreeList)))
|
|
{
|
|
OutputDebugString(L"WinMgmt: Repository admin page is corrupt because it thinks there are more entries than fit on the page!\n");
|
|
DebugBreak();
|
|
}
|
|
#endif
|
|
|
|
for (DWORD dwFreeIndex = 0; (*pdwPageId == 0) && (dwFreeIndex != pAdminPage->dwNumberEntriesOnPage); dwFreeIndex++)
|
|
{
|
|
if (pFreeListEntry[dwFreeIndex].dwFreeSpace >= (dwRequiredSize + sizeof(VarObjObjOffsetEntry)))
|
|
{
|
|
*pdwPageId = pFreeListEntry[dwFreeIndex].dwPageId;
|
|
dwRes = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
m_aAdminPages.Unlock();
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Allocate a new page for use with objects.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::AllocateNewPage(/* in */ DWORD ulBlockSize,
|
|
/* out*/ DWORD *pdwPageId,
|
|
/* in */ BYTE *pbNewObjectPage)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
//Allocate a new page from the object file
|
|
if (dwRes == ERROR_SUCCESS)
|
|
dwRes = m_pObjectFile->NewPage(0, 1, pdwPageId);
|
|
|
|
if (dwRes != ERROR_SUCCESS)
|
|
return dwRes;
|
|
|
|
//We need to know if we get to the end without finding space because at that point
|
|
//we need to allocate a new admin page!
|
|
dwRes = ERROR_FILE_NOT_FOUND;
|
|
|
|
//Find an admin page that has space for this new entry
|
|
m_aAdminPages.Lock();
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
if ((sizeof(VarObjHeapAdminPage) + ((pAdminPage->dwNumberEntriesOnPage + 1) * sizeof(VarObjHeapFreeList))) <= m_dwPageSize)
|
|
{
|
|
dwRes = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
m_aAdminPages.Unlock();
|
|
|
|
if (dwRes == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
//We did not find an admin page with any additional slots available. We need to allocate
|
|
//a new admin page
|
|
dwRes = ERROR_SUCCESS;
|
|
|
|
DWORD dwNewAdminPageId = 0;
|
|
|
|
//We need to allocate a new page in the object file
|
|
dwRes = m_pObjectFile->NewPage(0, 1, &dwNewAdminPageId);
|
|
|
|
//we need to allocate all the memory for the admin page cache
|
|
BYTE *pbNewAdminPage = NULL;
|
|
VarObjAdminPageEntry *pAdminPageEntry = NULL;
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
pbNewAdminPage = new BYTE[m_dwPageSize];
|
|
pAdminPageEntry = new VarObjAdminPageEntry;
|
|
|
|
if ((pbNewAdminPage == NULL) || (pAdminPageEntry == NULL))
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
}
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
if (m_aAdminPages.Add(pAdminPageEntry) != CFlexArray::no_error)
|
|
{
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
if (dwRes != ERROR_SUCCESS)
|
|
{
|
|
delete [] pbNewAdminPage;
|
|
delete pAdminPageEntry;
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//Write the admin page entry detail
|
|
pAdminPageEntry->dwPageId = dwNewAdminPageId;
|
|
pAdminPageEntry->pbPage = pbNewAdminPage;
|
|
pAdminPageEntry->bDirty = true; //new page needs to be written!
|
|
|
|
//Hook the previous admin page to this one (we have already added the new one remember!
|
|
VarObjAdminPageEntry *pPreviousAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[m_aAdminPages.Size() - 2];
|
|
VarObjHeapAdminPage *pPreviousAdminPage = (VarObjHeapAdminPage *)(pPreviousAdminPageEntry->pbPage);
|
|
pPreviousAdminPage->dwNextAdminPage = dwNewAdminPageId;
|
|
pPreviousAdminPageEntry->bDirty = true; //We just changed the page so it needs to be marked for flushing
|
|
|
|
//Initialize this new admin page with everything necessary
|
|
VarObjHeapAdminPage *pNewAdminPage = (VarObjHeapAdminPage *)pbNewAdminPage;
|
|
pNewAdminPage->dwNextAdminPage = 0;
|
|
pNewAdminPage->dwNumberEntriesOnPage = 0;
|
|
pNewAdminPage->dwVersion = 0; //not used on anything but the first page!
|
|
|
|
//Now we have all the details in there, we can set the index to this page so we can allocate
|
|
//add the new object page to it!
|
|
dwPageIndex = m_aAdminPages.Size() - 1;
|
|
}
|
|
}
|
|
|
|
//By here we now have the admin page we have space to put this new page entry!
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//cached admin page entry, update the dirty bit as we are changing it
|
|
VarObjAdminPageEntry *pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
|
|
pAdminPageEntry->bDirty = true;
|
|
|
|
//Admin page header, update the number of entries
|
|
VarObjHeapAdminPage *pAdminPage = (VarObjHeapAdminPage *)pAdminPageEntry->pbPage;
|
|
pAdminPage->dwNumberEntriesOnPage++;
|
|
|
|
//Add the entry to the end!
|
|
VarObjHeapFreeList *pFreeList = (VarObjHeapFreeList *)(pAdminPageEntry->pbPage + sizeof(VarObjHeapAdminPage) + (sizeof(VarObjHeapFreeList) * (pAdminPage->dwNumberEntriesOnPage - 1)));
|
|
pFreeList->dwPageId = *pdwPageId;
|
|
pFreeList->dwFreeSpace = m_dwPageSize - sizeof(VarObjObjOffsetEntry);
|
|
pFreeList->dwCRC32 = 0;
|
|
pFreeList->dwReserved = 0;
|
|
|
|
//Now we need to need to initialize the new object page to look like an empty page
|
|
ZeroMemory(pbNewObjectPage, sizeof(VarObjObjOffsetEntry));
|
|
|
|
}
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Allocates a multi-page entry in the object file. This requires
|
|
//different algorithms to work things out so is a special case
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::AllocateMultiPageBuffer(/* in */ ULONG ulBlockSize,
|
|
/* in */ const BYTE *pBlock,
|
|
/* out */ ULONG *pulPageId,
|
|
/* out */ ULONG *pulOffsetId)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
//Whole pages calculation
|
|
DWORD dwNumberPagesNeeded = (ulBlockSize + (sizeof(VarObjObjOffsetEntry) * 2)) / m_dwPageSize;
|
|
|
|
//Partial page calculation
|
|
if ((ulBlockSize + (sizeof(VarObjObjOffsetEntry) * 2) % m_dwPageSize) != 0)
|
|
dwNumberPagesNeeded++;
|
|
|
|
DWORD dwFirstPageId = 0;
|
|
dwRes = m_pObjectFile->NewPage(0, dwNumberPagesNeeded, &dwFirstPageId);
|
|
|
|
for (DWORD dwCurrentOffset = 0, dwPageIndex = 0; dwPageIndex != dwNumberPagesNeeded; dwPageIndex++)
|
|
{
|
|
BYTE *pPage = new BYTE[m_dwPageSize];
|
|
if (pPage == NULL)
|
|
dwRes = ERROR_OUTOFMEMORY;
|
|
CVectorDeleteMe<BYTE> vdm(pPage);
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
if (dwCurrentOffset == 0)
|
|
{
|
|
//We have to write the header for the offset page
|
|
ZeroMemory(pPage, sizeof(VarObjObjOffsetEntry) * 2);
|
|
VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pPage;
|
|
pEntry->dwBlockLength = ulBlockSize;
|
|
pEntry->dwOffsetId = 1;
|
|
pEntry->dwPhysicalStartOffset = sizeof(VarObjObjOffsetEntry) * 2;
|
|
|
|
DWORD dwCRC32 = CreateCRC32(pBlock, ulBlockSize);
|
|
FINALIZE_CRC32(dwCRC32);
|
|
pEntry->dwCRC = dwCRC32;
|
|
|
|
//Fill the rest of this page
|
|
CopyMemory(pPage + (sizeof(VarObjObjOffsetEntry) * 2), pBlock, m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2));
|
|
dwCurrentOffset = m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2);
|
|
}
|
|
else
|
|
{
|
|
if (ulBlockSize - dwCurrentOffset > m_dwPageSize)
|
|
{
|
|
CopyMemory(pPage, pBlock + dwCurrentOffset, m_dwPageSize);
|
|
dwCurrentOffset += m_dwPageSize;
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(pPage, pBlock + dwCurrentOffset, ulBlockSize - dwCurrentOffset);
|
|
dwCurrentOffset += (ulBlockSize - dwCurrentOffset);
|
|
|
|
//NOTE!!! dwCurrentOffset should equal ulBlockSize now!!!!!
|
|
}
|
|
}
|
|
|
|
dwRes = m_pObjectFile->PutPage(dwFirstPageId + dwPageIndex, 0, pPage);
|
|
}
|
|
if (FAILED(dwRes))
|
|
break;
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//Set up the pageId and offset details the client requested
|
|
*pulPageId = dwFirstPageId;
|
|
*pulOffsetId = 1;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//DeleteMultiPageBuffer - handles the deletion of an object when it spans
|
|
//multiple pages
|
|
//******************4********************************************************************
|
|
DWORD CVarObjHeap::DeleteMultiPageBuffer(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulOffsetId,
|
|
/* in */ BYTE *pbPage)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
//Calculate how many pages are used:
|
|
VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*)pbPage;
|
|
|
|
//Whole pages calculation
|
|
DWORD dwNumberPagesNeeded = (pEntry->dwBlockLength + (sizeof(VarObjObjOffsetEntry) * 2)) / m_dwPageSize;
|
|
|
|
//Partial page calculation
|
|
if ((pEntry->dwBlockLength + (sizeof(VarObjObjOffsetEntry) * 2) % m_dwPageSize) != 0)
|
|
dwNumberPagesNeeded++;
|
|
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != dwNumberPagesNeeded; dwPageIndex ++)
|
|
{
|
|
dwRes = m_pObjectFile->FreePage(0, ulPageId + dwPageIndex);
|
|
|
|
if (FAILED(dwRes))
|
|
break;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//DeleteFromPage - removes an object from a specific object page
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::RemoveFromPage(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulOffsetId,
|
|
/* in */ BYTE *pbPage,
|
|
/* out*/ DWORD *pdwSize)
|
|
{
|
|
DWORD dwRes = ERROR_FILE_NOT_FOUND;
|
|
|
|
//Need to remove the entry from the offset table, subtracting the deleted object size
|
|
//from the offset of all items following it
|
|
VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*)pbPage;
|
|
DWORD dwFoundOffset = 0;
|
|
DWORD dwFoundSize = 0;
|
|
DWORD dwFoundIndex = 0;
|
|
for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex ++)
|
|
{
|
|
|
|
if (pEntry[dwIndex].dwOffsetId == ulOffsetId)
|
|
{
|
|
//This is ours, so record the details
|
|
dwFoundOffset = pEntry[dwIndex].dwPhysicalStartOffset;
|
|
dwFoundSize = pEntry[dwIndex].dwBlockLength;
|
|
*pdwSize = dwFoundSize;
|
|
dwRes = ERROR_SUCCESS;
|
|
dwFoundIndex = dwIndex;
|
|
}
|
|
else if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//We have already found it so we need to adjust this entry
|
|
//to account for the removed space
|
|
pEntry[dwIndex - 1].dwPhysicalStartOffset = pEntry[dwIndex].dwPhysicalStartOffset - dwFoundSize - sizeof(VarObjObjOffsetEntry);
|
|
pEntry[dwIndex - 1].dwBlockLength = pEntry[dwIndex].dwBlockLength;
|
|
pEntry[dwIndex - 1].dwOffsetId = pEntry[dwIndex].dwOffsetId;
|
|
pEntry[dwIndex - 1].dwCRC = pEntry[dwIndex].dwCRC;
|
|
}
|
|
else
|
|
{
|
|
//Adjust for the fact that we are removing an entry for the offset table
|
|
pEntry[dwIndex].dwPhysicalStartOffset -= sizeof(VarObjObjOffsetEntry);
|
|
}
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
//We need to adjust the end-of-list by one place also
|
|
pEntry[dwIndex - 1].dwPhysicalStartOffset = 0;
|
|
pEntry[dwIndex - 1].dwBlockLength = 0;
|
|
pEntry[dwIndex - 1].dwOffsetId = 0;
|
|
pEntry[dwIndex - 1].dwCRC = 0;
|
|
|
|
//Now we need to adjust all entries up to the deleted one by the size of
|
|
//the offset table entry... although if this was the first item in the list then there
|
|
//is nothing to do
|
|
if (dwFoundIndex != 0)
|
|
{
|
|
MoveMemory(pbPage + pEntry[0].dwPhysicalStartOffset,
|
|
pbPage + pEntry[0].dwPhysicalStartOffset + sizeof(VarObjObjOffsetEntry),
|
|
dwFoundOffset - (pEntry[0].dwPhysicalStartOffset + sizeof(VarObjObjOffsetEntry)));
|
|
}
|
|
|
|
//Now we need to shuffle all entries that appeared after this entry back one... if this
|
|
//was the last entry then we don't have anything to do.
|
|
if (pEntry[dwFoundIndex].dwOffsetId != 0)
|
|
{
|
|
MoveMemory(pbPage + pEntry[dwFoundIndex].dwPhysicalStartOffset,
|
|
pbPage + dwFoundOffset + dwFoundSize,
|
|
(pEntry[dwIndex - 2].dwPhysicalStartOffset + pEntry[dwIndex - 2].dwBlockLength) - (pEntry[dwFoundIndex].dwPhysicalStartOffset));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
|
|
//**************************************************************************************
|
|
//UpdateAdminPageForAllocate - Updates the admin page to decrement the amount
|
|
//of free space on a page by this amount ( + sizeof(VarObjObjOffsetEntry))
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::UpdateAdminPageForAllocate(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulBlockSize,
|
|
/* in */ DWORD dwNewCRC)
|
|
{
|
|
DWORD dwRes = ERROR_FILE_NOT_FOUND;
|
|
|
|
//Find an admin page that has this page
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjAdminPageEntry* pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(pAdminPageEntry->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
|
|
{
|
|
if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
|
|
{
|
|
pFreeListEntry[dwEntry].dwFreeSpace -= (ulBlockSize + sizeof(VarObjObjOffsetEntry));
|
|
pFreeListEntry[dwEntry].dwCRC32 = dwNewCRC;
|
|
pAdminPageEntry->bDirty = true;
|
|
#if XFILES_DEBUG
|
|
wchar_t buf[100];
|
|
swprintf(buf, L"Page 0x%08X has allocated 0x%08X bytes. Space left 0x%08X\n", ulPageId, ulBlockSize + sizeof(VarObjObjOffsetEntry), pFreeListEntry[dwEntry].dwFreeSpace);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
dwRes = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
//**************************************************************************************
|
|
//UpdateAdminPageForAllocate2 - Updates the admin page to set the actual free
|
|
//space on page
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::UpdateAdminPageForAllocate2(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulPageFreeSpace,
|
|
/* in */ DWORD dwNewCRC)
|
|
{
|
|
DWORD dwRes = ERROR_FILE_NOT_FOUND;
|
|
|
|
//Find an admin page that has this page
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjAdminPageEntry* pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(pAdminPageEntry->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
|
|
{
|
|
if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
|
|
{
|
|
pFreeListEntry[dwEntry].dwFreeSpace = ulPageFreeSpace;
|
|
pFreeListEntry[dwEntry].dwCRC32 = dwNewCRC;
|
|
pAdminPageEntry->bDirty = true;
|
|
#if XFILES_DEBUG
|
|
wchar_t buf[100];
|
|
swprintf(buf, L"Page 0x%08X has allocated 0x%08X bytes. Space left 0x%08X\n", ulPageId, ulBlockSize + sizeof(VarObjObjOffsetEntry), pFreeListEntry[dwEntry].dwFreeSpace);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
dwRes = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
break;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//UpdateAdminPageForDelete - Updates the admin page for giving space back. If the page
|
|
//is totally empty we should delete the page altogether. Note that the space taken
|
|
//up is sizeof(VarObjObjOffsetEntry) more than specified because of the offset entry!
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::UpdateAdminPageForDelete(/* in */ ULONG ulPageId,
|
|
/* in */ ULONG ulBlockSize,
|
|
/* in */ DWORD dwNewCRC,
|
|
/* out */ bool *pbPageDeleted)
|
|
{
|
|
DWORD dwRes = ERROR_FILE_NOT_FOUND;
|
|
bool bFinished = false;
|
|
|
|
//Find an admin page that has this page
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjAdminPageEntry* pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(pAdminPageEntry->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
|
|
{
|
|
if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
|
|
{
|
|
pFreeListEntry[dwEntry].dwFreeSpace += (ulBlockSize + sizeof(VarObjObjOffsetEntry));
|
|
pFreeListEntry[dwEntry].dwCRC32 = dwNewCRC;
|
|
dwRes = ERROR_SUCCESS;
|
|
bFinished = true;
|
|
pAdminPageEntry->bDirty = true;
|
|
#if XFILES_DEBUG
|
|
wchar_t buf[100];
|
|
swprintf(buf, L"Page 0x%08X has deallocated 0x%08X bytes. Space left 0x%08X\n", ulPageId, ulBlockSize + sizeof(VarObjObjOffsetEntry), pFreeListEntry[dwEntry].dwFreeSpace);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
|
|
if (pFreeListEntry[dwEntry].dwFreeSpace == (m_dwPageSize - sizeof(VarObjObjOffsetEntry)))
|
|
{
|
|
dwRes = RemoveEntryFromAdminPage(dwPageIndex, dwEntry);
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = m_pObjectFile->FreePage(0, ulPageId);
|
|
*pbPageDeleted = true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (bFinished)
|
|
break;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Deletes a page, and updates the admin pages as appropriage. If the admin page
|
|
//is now enpty we delete this admin page and update the next pointer of the previous
|
|
//page. We do not delete the first admin page however as it has a special pageId
|
|
//that is reserved.
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::DeletePage(/* in */ DWORD ulPageId)
|
|
{
|
|
DWORD dwRes = m_pObjectFile->FreePage(0, ulPageId);
|
|
bool bFinished = false;
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
dwRes = ERROR_FILE_NOT_FOUND;
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
|
|
{
|
|
if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
|
|
{
|
|
dwRes = RemoveEntryFromAdminPage(dwPageIndex, dwEntry);
|
|
bFinished = true;
|
|
break;
|
|
}
|
|
}
|
|
if (bFinished)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//**************************************************************************************
|
|
//Removes an object page entry from an admin page, removing the
|
|
//admin page if it is no longer needed
|
|
//**************************************************************************************
|
|
DWORD CVarObjHeap::RemoveEntryFromAdminPage(/* in */ DWORD dwAdminPageIndex,
|
|
/* in */ DWORD dwAdminPageEntry)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
VarObjAdminPageEntry *pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwAdminPageIndex];
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)pAdminPageEntry->pbPage;
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
pAdminPage->dwNumberEntriesOnPage--;
|
|
if ((pAdminPage->dwNumberEntriesOnPage == 0) && (dwAdminPageIndex != 0))
|
|
{
|
|
//Need to delete this admin page... update the previous pages next admin page entry
|
|
VarObjAdminPageEntry *pPreviousAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwAdminPageIndex - 1];
|
|
VarObjHeapAdminPage * pPreviousAdminPage = (VarObjHeapAdminPage *)pPreviousAdminPageEntry->pbPage;
|
|
pPreviousAdminPage->dwNextAdminPage = pAdminPage->dwNextAdminPage;
|
|
//Set the dirty bit on that page so it gets flushed!
|
|
pPreviousAdminPageEntry->bDirty = true;
|
|
|
|
//Do the actual free page of this admin page
|
|
dwRes = m_pObjectFile->FreePage(0, pAdminPageEntry->dwPageId);
|
|
|
|
if (dwRes == ERROR_SUCCESS)
|
|
{
|
|
m_aAdminPages.RemoveAt(dwAdminPageIndex);
|
|
delete pAdminPageEntry;
|
|
}
|
|
|
|
}
|
|
else if ((pAdminPage->dwNumberEntriesOnPage == 0) && (dwAdminPageIndex == 0))
|
|
{
|
|
//The first admin page cannot be deleted so we just ignore this
|
|
}
|
|
else if (pAdminPage->dwNumberEntriesOnPage != 0)
|
|
{
|
|
//We just need to delete the entry, so shuffle the entries about
|
|
//in the page
|
|
MoveMemory(&pFreeListEntry[dwAdminPageEntry], &pFreeListEntry[dwAdminPageEntry+1], sizeof(VarObjHeapFreeList) * (pAdminPage->dwNumberEntriesOnPage - dwAdminPageEntry));
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
//Given a page we validate that there is in fact enough space
|
|
//for this block. If there is not it asserts. This implies
|
|
//that the admin page is not in sync with the actual pages.
|
|
DWORD CVarObjHeap::ValidatePageFreeSpace(/* in */ const BYTE *pbPage,
|
|
/* in */ DWORD ulBlockSize,
|
|
/* out */ DWORD *pulFreeSpaceLeft)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pbPage;
|
|
DWORD dwNextAvailableOffset = pEntry[0].dwPhysicalStartOffset + pEntry[0].dwBlockLength;
|
|
|
|
//Search through the offset table until we find the last entry
|
|
for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex++)
|
|
{
|
|
dwNextAvailableOffset = pEntry[dwIndex].dwPhysicalStartOffset + pEntry[dwIndex].dwBlockLength;
|
|
}
|
|
|
|
*pulFreeSpaceLeft = m_dwPageSize - dwNextAvailableOffset;
|
|
|
|
if ((dwNextAvailableOffset + ulBlockSize + sizeof(VarObjObjOffsetEntry))> m_dwPageSize)
|
|
{
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt Repository Corruption: Object heap admin page free space information is out of sync with actual pages!\n");
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
|
|
return dwRes;
|
|
}
|
|
|
|
#ifdef DBG
|
|
//Given a page and a page ID, it validates the amount of free space
|
|
//on the page is equal to the amount the admin page thinks is on
|
|
//there.
|
|
DWORD CVarObjHeap::ValidatePageFreeSpaceWithAdminPage(/* in */ const BYTE *pbPage,
|
|
/* in */ DWORD ulPageId)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pbPage;
|
|
DWORD dwNextAvailableOffset = pEntry[0].dwPhysicalStartOffset + pEntry[0].dwBlockLength;
|
|
|
|
//Search through the offset table until we find the last entry
|
|
for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex++)
|
|
{
|
|
dwNextAvailableOffset = pEntry[dwIndex].dwPhysicalStartOffset + pEntry[dwIndex].dwBlockLength;
|
|
}
|
|
|
|
DWORD dwFreeSpace = m_dwPageSize - dwNextAvailableOffset;
|
|
|
|
//Find the page in the admin page table
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
|
|
{
|
|
//If this is the page we are interested in...
|
|
if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
|
|
{
|
|
//check the free space matches...
|
|
if (pFreeListEntry[dwEntry].dwFreeSpace != dwFreeSpace)
|
|
{
|
|
#ifdef DBG
|
|
//Oops, it doesn't! We have a problem!
|
|
OutputDebugString(L"WinMgmt Repository Corruption: Free space in page is out of sink with the free space listed in admin page!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
return dwRes;
|
|
}
|
|
|
|
//Dumps the offset table of a page to the debugger
|
|
DWORD CVarObjHeap::DumpPageOffsetTable(/* in */ DWORD dwPageId,
|
|
/* in */ const BYTE *pbPage)
|
|
{
|
|
wchar_t buf[100];
|
|
OutputDebugString(L"================================\n");
|
|
StringCchPrintfW(buf, 100, L"Dumping offset table for pageId <0x%X>\n", dwPageId);
|
|
OutputDebugString(buf);
|
|
OutputDebugString(L"================================\n");
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pbPage;
|
|
for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex++)
|
|
{
|
|
StringCchPrintfW(buf, 100, L"0x%08X, 0x%08X, 0x%08X, 0x%08X\n", dwIndex, pEntry[dwIndex].dwOffsetId, pEntry[dwIndex].dwBlockLength, pEntry[dwIndex].dwPhysicalStartOffset);
|
|
OutputDebugString(buf);
|
|
}
|
|
StringCchPrintfW(buf, 100, L"0x%08X, 0x%08X, 0x%08X, 0x%08X\n", dwIndex, pEntry[dwIndex].dwOffsetId, pEntry[dwIndex].dwBlockLength, pEntry[dwIndex].dwPhysicalStartOffset);
|
|
OutputDebugString(buf);
|
|
OutputDebugString(L"================================\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
#endif /* DBG */
|
|
|
|
static DWORD g_CRCTable[] =
|
|
{
|
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
|
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
|
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
|
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
|
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
|
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
|
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
|
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
|
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
|
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
|
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
|
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
|
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
|
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
|
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
|
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
|
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
|
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
|
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
|
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
|
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
|
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
|
};
|
|
|
|
//Creates a CRC for a block
|
|
DWORD CVarObjHeap::CreateCRC32(/* in */ const BYTE *pBlock,
|
|
/* in */ DWORD dwSize,
|
|
/* in */ DWORD dwPreviousCRC)
|
|
{
|
|
if(dwSize == 0)
|
|
return dwPreviousCRC;
|
|
|
|
DWORD dwNewCRC = 0;
|
|
|
|
for (int n = 0; n < dwSize; n++)
|
|
{
|
|
dwNewCRC = g_CRCTable[ BYTE(dwPreviousCRC ^ DWORD(pBlock[n]))]
|
|
^ ((dwPreviousCRC >> 8) & 0x00FFFFFF);
|
|
dwPreviousCRC = dwNewCRC;
|
|
}
|
|
|
|
return dwNewCRC;
|
|
}
|
|
|
|
#ifdef DBG
|
|
//Checks the CRCs of all objects on a page (cannot do this
|
|
//for a multi-page object though as we only have the first
|
|
//page!)
|
|
DWORD CVarObjHeap::ValidateAllCRC32OnPage(/* in */ const BYTE *pbPage)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
|
|
//Get a pointer to the start of the offset table
|
|
VarObjObjOffsetEntry *pOffsetEntry = (VarObjObjOffsetEntry *) pbPage;
|
|
|
|
//Loop through the table until we find the one we are interested in
|
|
for (DWORD dwOffsetIndex = 0; pOffsetEntry[dwOffsetIndex].dwOffsetId != 0; dwOffsetIndex++)
|
|
{
|
|
if (pOffsetEntry[dwOffsetIndex].dwBlockLength > (m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2)))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
DWORD dwNewCRC32 = CreateCRC32(pbPage + pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset, pOffsetEntry[dwOffsetIndex].dwBlockLength);
|
|
FINALIZE_CRC32(dwNewCRC32);
|
|
if (dwNewCRC32 != pOffsetEntry[dwOffsetIndex].dwCRC)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Page Check: CRC check on an object retrieved from repository is invalid\n");
|
|
DebugBreak();
|
|
#endif
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
}
|
|
catch (...)
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Page Check: CRC check on an object retrieved from repository is invalid\n");
|
|
DebugBreak();
|
|
#endif
|
|
dwRes = ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return dwRes;
|
|
}
|
|
|
|
//Validates the page check-sum with the admin page
|
|
DWORD CVarObjHeap::ValidatePageCRCWithAdminPage(/* in */ const BYTE *pbPage,
|
|
/* in */ DWORD dwPageId)
|
|
{
|
|
DWORD dwCRC32 = 0;
|
|
dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
|
|
FINALIZE_CRC32(dwCRC32);
|
|
|
|
for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
|
|
{
|
|
VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
|
|
VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
|
|
|
|
if ((dwPageIndex != 0) && (pAdminPage->dwVersion != 0))
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository admin page is corrupt as version is invalid!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
if (pAdminPage->dwNumberEntriesOnPage > ((m_dwPageSize - sizeof(VarObjHeapAdminPage)) / sizeof(VarObjHeapFreeList)))
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository admin page is corrupt because it thinks there are more entries than fit on the page!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
|
|
for (DWORD dwFreeIndex = 0; dwFreeIndex != pAdminPage->dwNumberEntriesOnPage; dwFreeIndex++)
|
|
{
|
|
if (pFreeListEntry[dwFreeIndex].dwPageId == dwPageId)
|
|
{
|
|
if (pFreeListEntry[dwFreeIndex].dwCRC32 == 0)
|
|
return ERROR_SUCCESS;
|
|
else if (pFreeListEntry[dwFreeIndex].dwCRC32 == dwCRC32)
|
|
return ERROR_SUCCESS;
|
|
else
|
|
{
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Repository admin page has an invalid CRC for the object page!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef DBG
|
|
OutputDebugString(L"WinMgmt: Requested page was not found in the admin page list!\n");
|
|
DebugBreak();
|
|
#endif
|
|
return ERROR_INTERNAL_ERROR;
|
|
}
|
|
#endif
|
|
|