Source code of Windows XP (NT5)
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.

1596 lines
54 KiB

  1. /*++
  2. Copyright (C) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. VarObjHeap.CPP
  5. Abstract:
  6. Implements the storage of variable length objects over the top of of a fixed
  7. length page system. It keeps a set of admin pages for holding the pages active
  8. by this subsystem, along with how much space is used on each. When a page becomes
  9. empty it frees up the page to the page system. It also deals with blocks that span
  10. multiple pages
  11. History:
  12. paulall 02-Feb-2001 Created
  13. --*/
  14. #include <windows.h>
  15. #include "VarObjHeap.h"
  16. #include "pagemgr.h"
  17. #ifdef DBG
  18. #include <tchar.h>
  19. #endif
  20. #include <wbemutil.h>
  21. //**************************************************************************************
  22. //CVarObjHeap will do little other than initialize variables. The Initialize method
  23. //deals with starting everything up.
  24. //**************************************************************************************
  25. CVarObjHeap::CVarObjHeap()
  26. : m_pObjectFile(NULL), m_dwPageSize(0), m_dwStatus(AdminPagesNeedReading)
  27. {
  28. }
  29. //**************************************************************************************
  30. //~CVarObjHeap will break the connection with the transacted object file layer
  31. //**************************************************************************************
  32. CVarObjHeap::~CVarObjHeap()
  33. {
  34. Shutdown(0);
  35. }
  36. //**************************************************************************************
  37. //Initialize will create the link with the transacted object file layer
  38. //**************************************************************************************
  39. DWORD CVarObjHeap::Initialize(CPageSource *pPageManager)
  40. {
  41. //Initialize the object file layer...
  42. DWORD dwRes = pPageManager->GetObjectHeapPageFile(&m_pObjectFile);
  43. if (dwRes == ERROR_SUCCESS)
  44. m_dwPageSize = m_pObjectFile->GetPageSize();
  45. if (dwRes == ERROR_SUCCESS)
  46. {
  47. m_dwStatus = AdminPagesNeedReading;
  48. dwRes = ReadAdminPages(pPageManager, true);
  49. }
  50. return dwRes;
  51. }
  52. //**************************************************************************************
  53. //Shutdown will close the transactioned object file layer and tidy up anything else
  54. //that is needed.
  55. //**************************************************************************************
  56. DWORD CVarObjHeap::Shutdown(DWORD dwShutdownType)
  57. {
  58. DWORD dwRes = ERROR_SUCCESS;
  59. //Flush the admin pages... remember the error though!
  60. dwRes = FlushAdminPages();
  61. if (m_pObjectFile)
  62. {
  63. m_pObjectFile->Release();
  64. m_pObjectFile = NULL;
  65. }
  66. //Delete the admin pages structures
  67. m_aAdminPages.Lock();
  68. while (m_aAdminPages.Size())
  69. {
  70. VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[0];
  71. delete [] pEntry->pbPage;
  72. delete pEntry;
  73. m_aAdminPages.RemoveAt(0);
  74. }
  75. m_aAdminPages.Unlock();
  76. return dwRes;
  77. }
  78. //**************************************************************************************
  79. //InvalidateCache - called when a transaction is aborted and we need to re-read cached
  80. //data. Data we cache is mainlyh the admin pages, therefore we should just re-read
  81. //them.
  82. //**************************************************************************************
  83. DWORD CVarObjHeap::InvalidateCache()
  84. {
  85. m_dwStatus = AdminPagesNeedReading;
  86. return ReadAdminPages(0, true);
  87. }
  88. DWORD CVarObjHeap::FlushCaches()
  89. {
  90. m_dwStatus = AdminPagesNeedReading;
  91. return ReadAdminPages(0, false);
  92. }
  93. //**************************************************************************************
  94. //ReadBuffer retrieves the appropriate page(s) from the virtual page store and copies
  95. //off the actual block from those page(s). It may reside on the main page if it is small,
  96. //it may reside on main page and some of the next page, or it may reside on main page,
  97. //one or more whole pages following that, followed by a partial (or full) page.
  98. //**************************************************************************************
  99. DWORD CVarObjHeap::ReadBuffer(/* in */ ULONG ulPageId,
  100. /* in */ ULONG ulOffsetId,
  101. /* out */ BYTE **ppReturnedBlock,
  102. /* out */ DWORD *pdwBlockSize)
  103. {
  104. if ((ulPageId == 0) || (ulOffsetId == 0))
  105. DebugBreak();
  106. DWORD dwRes = ERROR_SUCCESS;
  107. if (m_dwStatus == NoError)
  108. {
  109. //Nothing to do... help with compiler prediction logic
  110. }
  111. else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
  112. {
  113. dwRes = ReadAdminPages(0, true);
  114. if (dwRes != ERROR_SUCCESS)
  115. return dwRes;
  116. }
  117. else if (m_dwStatus == RootAdminPageCreationFailure)
  118. {
  119. OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
  120. DebugBreak();
  121. return ERROR_INTERNAL_ERROR;
  122. }
  123. //We need to retrieve the page from the file store, and then we need to retrieve the
  124. //block from the the page. We need to allocate the appropriate memory and copy it
  125. //into that memory.
  126. BYTE *pbPage = new BYTE[m_dwPageSize];
  127. if (pbPage == NULL)
  128. dwRes = ERROR_OUTOFMEMORY;
  129. CVectorDeleteMe<BYTE> vdm1(pbPage);
  130. //So, first we need to retrieve the page...
  131. if (dwRes == ERROR_SUCCESS)
  132. dwRes = m_pObjectFile->GetPage(ulPageId, 0, pbPage);
  133. //Retrieve the REAL offset and size to the block based on offsetId
  134. BYTE *pOffsetPointer = NULL;
  135. DWORD dwBlockSize = 0;
  136. DWORD dwCRC32 = 0;
  137. if (dwRes == ERROR_SUCCESS)
  138. dwRes = OffsetToPointer(ulOffsetId, pbPage, &pOffsetPointer, &dwBlockSize, &dwCRC32);
  139. //We can now allocate the real block now as we know how big it is. We may not have all
  140. //the pages in memory yet though!
  141. BYTE *pBlock = NULL;
  142. if (dwRes == ERROR_SUCCESS)
  143. pBlock = new BYTE[dwBlockSize];
  144. if ((dwRes == ERROR_SUCCESS) && (pBlock == NULL))
  145. dwRes = ERROR_OUTOFMEMORY;
  146. DWORD dwBlockNumber = 0;
  147. DWORD dwAmountCopiedSoFar = 0;
  148. //Copy off the first block
  149. if (dwRes == ERROR_SUCCESS)
  150. {
  151. DWORD dwSizeOfFirstPageBlock = min(dwBlockSize, DWORD((pbPage + m_dwPageSize) - pOffsetPointer));
  152. dwAmountCopiedSoFar = dwSizeOfFirstPageBlock;
  153. memcpy(pBlock, pOffsetPointer, dwSizeOfFirstPageBlock);
  154. }
  155. //We should now loop through the pages (retrieving them if necessary) and copying
  156. //the data into our buffer
  157. while ((dwRes == ERROR_SUCCESS) && (dwAmountCopiedSoFar < dwBlockSize))
  158. {
  159. dwBlockNumber++;
  160. //Read the next page...
  161. dwRes = m_pObjectFile->GetPage(ulPageId + dwBlockNumber, 0, pbPage);
  162. if (dwRes == ERROR_SUCCESS)
  163. {
  164. //Distinguish if this is a full page or not...
  165. if ((dwAmountCopiedSoFar + m_dwPageSize) > dwBlockSize)
  166. {
  167. //This is a partial block, so copy as much as is needed
  168. DWORD dwPartialSize = dwBlockSize - dwAmountCopiedSoFar;
  169. memcpy((pBlock + dwAmountCopiedSoFar), pbPage, dwPartialSize);
  170. dwAmountCopiedSoFar += dwPartialSize;
  171. }
  172. else
  173. {
  174. //This is a full block, so grab it all...
  175. memcpy((pBlock + dwAmountCopiedSoFar), pbPage, m_dwPageSize);
  176. dwAmountCopiedSoFar += m_dwPageSize;
  177. }
  178. }
  179. }
  180. #ifdef DBG
  181. if (dwRes == ERROR_SUCCESS)
  182. {
  183. //Can only check for single-page blocks!
  184. if (ulOffsetId != 1)
  185. {
  186. dwRes = ValidatePageCRCWithAdminPage(pbPage, ulPageId);
  187. }
  188. }
  189. #endif
  190. //If we are successful, lets do a CRC check on the object
  191. if (dwRes == ERROR_SUCCESS)
  192. {
  193. try
  194. {
  195. DWORD dwNewCRC32 = CreateCRC32(pBlock, dwBlockSize);
  196. FINALIZE_CRC32(dwNewCRC32);
  197. if (dwNewCRC32 != dwCRC32)
  198. {
  199. #ifdef DBG
  200. OutputDebugString(L"WinMgmt: CRC check on an object retrieved from repository is invalid\n");
  201. DebugBreak();
  202. #endif
  203. dwRes = ERROR_INTERNAL_ERROR;
  204. }
  205. }
  206. catch (...)
  207. {
  208. #ifdef DBG
  209. OutputDebugString(L"WinMgmt: CRC check on an object retrieved from repository is invalid\n");
  210. DebugBreak();
  211. #endif
  212. dwRes = ERROR_INTERNAL_ERROR;
  213. }
  214. }
  215. //If successful we need to return the pointer to the object
  216. if (dwRes == ERROR_SUCCESS)
  217. {
  218. *ppReturnedBlock = pBlock;
  219. *pdwBlockSize = dwBlockSize;
  220. }
  221. else
  222. {
  223. delete [] pBlock;
  224. }
  225. return dwRes;
  226. }
  227. //**************************************************************************************
  228. //WriteNewBuffer will write a new page based on size of BYTE *, and return the
  229. //new virtual pageId and offsetId of the block. Although we may use multiple pages
  230. //we only need to return the details of the first page.
  231. //**************************************************************************************
  232. DWORD CVarObjHeap::WriteNewBuffer(/* in */ ULONG ulBlockSize,
  233. /* in */ const BYTE *pBlock,
  234. /* out */ ULONG *pulPageId,
  235. /* out */ ULONG *pulOffsetId)
  236. {
  237. DWORD dwRes = ERROR_SUCCESS;
  238. if (m_dwStatus == NoError)
  239. {
  240. //Nothing to do... help with compiler prediction logic
  241. }
  242. else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
  243. {
  244. dwRes = ReadAdminPages(0, true);
  245. if (dwRes != ERROR_SUCCESS)
  246. return dwRes;
  247. }
  248. else if (m_dwStatus == RootAdminPageCreationFailure)
  249. {
  250. OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
  251. DebugBreak();
  252. return ERROR_INTERNAL_ERROR;
  253. }
  254. //If this block will not fit on a single page we call the dedicated method!
  255. if (ulBlockSize > (m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2)))
  256. return AllocateMultiPageBuffer(ulBlockSize, pBlock, pulPageId, pulOffsetId);
  257. BYTE *pbPage = new BYTE[m_dwPageSize];
  258. if (pbPage == NULL)
  259. dwRes = ERROR_OUTOFMEMORY;
  260. CVectorDeleteMe<BYTE> vdm(pbPage);
  261. DWORD dwPageId = 0;
  262. //Find a page that has enough space for this
  263. if (dwRes == ERROR_SUCCESS)
  264. dwRes = FindPageWithSpace(ulBlockSize, &dwPageId);
  265. if (dwRes == ERROR_SUCCESS)
  266. {
  267. //There is a page with space in it!
  268. //Read the page from the file
  269. dwRes = m_pObjectFile->GetPage(dwPageId, 0, pbPage);
  270. #ifdef DBG
  271. if (dwRes == ERROR_SUCCESS)
  272. dwRes = ValidatePageCRCWithAdminPage(pbPage, dwPageId);
  273. if (dwRes == ERROR_SUCCESS)
  274. dwRes = ValidatePageFreeSpaceWithAdminPage(pbPage, dwPageId);
  275. if (dwRes == ERROR_SUCCESS)
  276. dwRes = ValidatePageFreeSpace(pbPage, ulBlockSize);
  277. #endif /* DBG */
  278. }
  279. else if (dwRes == ERROR_FILE_NOT_FOUND)
  280. {
  281. //We didn't find space so we allocate a new page
  282. dwRes = AllocateNewPage(ulBlockSize, &dwPageId, pbPage);
  283. }
  284. //We now have a page, albeit a new page or an existing one, so now we need
  285. //to allocate space from it
  286. if (dwRes == ERROR_SUCCESS)
  287. {
  288. dwRes = AllocateFromPage(dwPageId, pbPage, ulBlockSize, pBlock, pulOffsetId);
  289. }
  290. //Write the page to the object file
  291. if (dwRes == ERROR_SUCCESS)
  292. dwRes = m_pObjectFile->PutPage(dwPageId, 0, pbPage);
  293. DWORD dwCRC32 = 0;
  294. if (dwRes == ERROR_SUCCESS)
  295. {
  296. dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
  297. FINALIZE_CRC32(dwCRC32);
  298. }
  299. if (dwRes == ERROR_SUCCESS)
  300. dwRes = UpdateAdminPageForAllocate(dwPageId, ulBlockSize, dwCRC32);
  301. if (dwRes == ERROR_SUCCESS)
  302. dwRes = FlushAdminPages();
  303. //Update the pageId for the client caller
  304. if (dwRes == ERROR_SUCCESS)
  305. {
  306. *pulPageId = dwPageId;
  307. if ((*pulPageId == 0) || (*pulOffsetId == 0))
  308. DebugBreak();
  309. }
  310. #ifdef DBG
  311. if (dwRes == ERROR_SUCCESS)
  312. dwRes = ValidatePageFreeSpaceWithAdminPage(pbPage, dwPageId);
  313. if (dwRes == ERROR_SUCCESS)
  314. dwRes = ValidateAllCRC32OnPage(pbPage);
  315. #endif
  316. return dwRes;
  317. }
  318. //**************************************************************************************
  319. //WriteExistingBuffer will update an existing block with new data. The old virtual page
  320. //and offset are passed in, and new ones are returned. They may or may not be the same
  321. //depending on if it still fits in the page or not.
  322. //**************************************************************************************
  323. DWORD CVarObjHeap::WriteExistingBuffer(/* in */ ULONG ulBlockSize,
  324. /* in */ const BYTE *pBlock,
  325. /* in */ ULONG ulOldPageId,
  326. /* in */ ULONG ulOldOffsetId,
  327. /* out */ ULONG *pulNewPageId,
  328. /* out */ ULONG *pulNewOffsetId)
  329. {
  330. //Validate the in parameters!
  331. if ((ulOldPageId == 0) || (ulOldOffsetId == 0))
  332. {
  333. DebugBreak();
  334. return ERROR_INTERNAL_ERROR;
  335. }
  336. DWORD dwRes = ERROR_SUCCESS;
  337. if (m_dwStatus == NoError)
  338. {
  339. //Nothing to do... help with compiler prediction logic
  340. }
  341. else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
  342. {
  343. dwRes = ReadAdminPages(0, true);
  344. if (dwRes != ERROR_SUCCESS)
  345. return dwRes;
  346. }
  347. else if (m_dwStatus == RootAdminPageCreationFailure)
  348. {
  349. OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
  350. DebugBreak();
  351. return ERROR_INTERNAL_ERROR;
  352. }
  353. //We need to retrieve the page that is being updated, then we need to overwrite the
  354. //original stuff in the page. We may need to shuffle all the existing blocks around
  355. //within the page to make sure everything is fully packed. We may need to adjust
  356. //the free-page list with the amount of space we have available on this page.
  357. //TODO! Do this properly!!!
  358. dwRes = DeleteBuffer(ulOldPageId, ulOldOffsetId);
  359. if (dwRes == ERROR_SUCCESS)
  360. dwRes = WriteNewBuffer(ulBlockSize, pBlock, pulNewPageId, pulNewOffsetId);
  361. //Validate the out parameters!
  362. if ((*pulNewPageId == 0) || (*pulNewOffsetId == 0))
  363. {
  364. DebugBreak();
  365. dwRes = ERROR_INTERNAL_ERROR;
  366. }
  367. return dwRes;
  368. }
  369. //**************************************************************************************
  370. //DeleteBuffer is called to delete the item in the store given the virtual pageId and
  371. //offsetId.
  372. //**************************************************************************************
  373. DWORD CVarObjHeap::DeleteBuffer(/* in */ ULONG ulPageId,
  374. /* in */ ULONG ulOffsetId)
  375. {
  376. DWORD dwRes = ERROR_SUCCESS;
  377. if (m_dwStatus == NoError)
  378. {
  379. //Nothing to do... help with compiler prediction logic
  380. }
  381. else if ((m_dwStatus == AdminPageReadFailure) || (m_dwStatus == AdminPagesNeedReading))
  382. {
  383. dwRes = ReadAdminPages(0, true);
  384. if (dwRes != ERROR_SUCCESS)
  385. return dwRes;
  386. }
  387. else if (m_dwStatus == RootAdminPageCreationFailure)
  388. {
  389. OutputDebugString(L"WinMgmt: Repository initialization failed and we were still called to retrieve stuff! Yeah, right!\n");
  390. DebugBreak();
  391. return ERROR_INTERNAL_ERROR;
  392. }
  393. //Allocate space for the page we are going to manipulate
  394. BYTE *pbPage = new BYTE[m_dwPageSize];
  395. if (pbPage == NULL)
  396. dwRes = ERROR_OUTOFMEMORY;
  397. CVectorDeleteMe<BYTE> vdm(pbPage);
  398. //Retrieve the page that contains this object
  399. if (dwRes == ERROR_SUCCESS)
  400. dwRes = m_pObjectFile->GetPage(ulPageId, 0, pbPage);
  401. //If this object is a multi-page object we have a different algorithm
  402. if (dwRes == ERROR_SUCCESS)
  403. {
  404. if (MultiPageObject(pbPage))
  405. return DeleteMultiPageBuffer(ulPageId, ulOffsetId, pbPage);
  406. }
  407. //Remove the object from this page
  408. DWORD dwSize = 0;
  409. if (dwRes == ERROR_SUCCESS)
  410. dwRes = RemoveFromPage(ulPageId, ulOffsetId, pbPage, &dwSize);
  411. DWORD dwCRC32 = 0;
  412. if (dwRes == ERROR_SUCCESS)
  413. {
  414. dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
  415. FINALIZE_CRC32(dwCRC32);
  416. }
  417. //Update the admin page, possibly even deleting the page!
  418. bool bPageDeleted = false;
  419. if (dwRes == ERROR_SUCCESS)
  420. dwRes = UpdateAdminPageForDelete(ulPageId, dwSize, dwCRC32, &bPageDeleted);
  421. //Flush the page back to the object file and update admin page
  422. if ((dwRes == ERROR_SUCCESS) && !bPageDeleted)
  423. {
  424. dwRes = m_pObjectFile->PutPage(ulPageId, 0, pbPage);
  425. }
  426. //Flush the admin pages
  427. if (dwRes == ERROR_SUCCESS)
  428. dwRes = FlushAdminPages();
  429. return dwRes;
  430. }
  431. //**************************************************************************************
  432. //AllocateFromPage - adds an allocation to the end of the existing allocations
  433. //**************************************************************************************
  434. DWORD CVarObjHeap::AllocateFromPage(/* in */ DWORD dwPageId,
  435. /* in */ BYTE *pbPage,
  436. /* in */ ULONG ulBlockSize,
  437. /* in */ const BYTE *pBlock,
  438. /* out*/ ULONG *pdwNewOffset)
  439. {
  440. #ifdef XFILES_DEBUG
  441. if (dwPageId == 0x125)
  442. {
  443. OutputDebugString(L"===============================\n");
  444. OutputDebugString(L"Start of AllocateFromPage\n");
  445. DumpPageOffsetTable(dwPageId, pbPage);
  446. }
  447. #endif
  448. DWORD dwRes = ERROR_SUCCESS;
  449. //Get a pointer to the start of the offset table
  450. VarObjObjOffsetEntry *pOffsetEntry = (VarObjObjOffsetEntry *) pbPage;
  451. //This is the location where the last block resided and size so we can calculate
  452. //where the new block goes
  453. DWORD dwLastOffset = pOffsetEntry[0].dwPhysicalStartOffset;
  454. DWORD dwLastSize = 0;
  455. DWORD dwNewOffsetId = GetTickCount() + (DWORD)rand();
  456. bool bNewOffsetIdClash = false;
  457. //Loop through the table until we get to the end... adjusting the offset within the
  458. //entries along the way to account for the fact we will be shifting them by the size
  459. //of an offset entry.
  460. for (DWORD dwOffsetIndex = 0; pOffsetEntry[dwOffsetIndex].dwOffsetId != 0; dwOffsetIndex++)
  461. {
  462. //Shuffle the size of this offset by one entry because we will be doing a memcpy
  463. //when this is done so we have room for our new entry.
  464. pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset += sizeof VarObjObjOffsetEntry;
  465. dwLastOffset = pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset;
  466. dwLastSize = pOffsetEntry[dwOffsetIndex].dwBlockLength;
  467. if (pOffsetEntry[dwOffsetIndex].dwOffsetId == dwNewOffsetId)
  468. {
  469. bNewOffsetIdClash = true;
  470. }
  471. }
  472. //While we have an offset class we need to keep re-calculating
  473. while (bNewOffsetIdClash)
  474. {
  475. bNewOffsetIdClash = false;
  476. dwNewOffsetId = GetTickCount() + (DWORD)rand();
  477. for (DWORD dwIndex = 0; pOffsetEntry[dwIndex].dwOffsetId != 0; dwIndex++)
  478. {
  479. if (pOffsetEntry[dwIndex].dwOffsetId == dwNewOffsetId)
  480. {
  481. bNewOffsetIdClash = true;
  482. break;
  483. }
  484. }
  485. }
  486. //Now dwOffsetIndex is where we are going to insert this new offset entry, and dwLastOffset + dwLastSize
  487. //is the new location where we need to copy this data...
  488. //Only problem now though is that we need to shuffle all data along by the size of an offset entry!
  489. MoveMemory(&pOffsetEntry[dwOffsetIndex+1], &pOffsetEntry[dwOffsetIndex], ((dwLastOffset + dwLastSize) - pOffsetEntry[0].dwPhysicalStartOffset) + sizeof(VarObjObjOffsetEntry));
  490. //Write the new entry in the offset table
  491. pOffsetEntry[dwOffsetIndex].dwOffsetId = dwNewOffsetId;
  492. if (dwLastOffset == 0)
  493. {
  494. //First block of the page!
  495. pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset = (sizeof(VarObjObjOffsetEntry) * 2);
  496. }
  497. else
  498. {
  499. pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset = dwLastOffset + dwLastSize;
  500. }
  501. pOffsetEntry[dwOffsetIndex].dwBlockLength = ulBlockSize;
  502. #if XFILES_DEBUG
  503. if (dwPageId == 0x125)
  504. {
  505. OutputDebugString(L"===============================\n");
  506. OutputDebugString(L"Start of AllocateFromPage\n");
  507. DumpPageOffsetTable(dwPageId, pbPage);
  508. }
  509. #endif
  510. //Write the block to the page
  511. #ifdef DBG
  512. if (pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset + ulBlockSize > m_dwPageSize)
  513. {
  514. 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");
  515. DebugBreak();
  516. dwRes = ERROR_INTERNAL_ERROR;
  517. }
  518. #endif
  519. if (dwRes == ERROR_SUCCESS)
  520. {
  521. //Generate the CRC
  522. DWORD dwCRC32 = CreateCRC32(pBlock, ulBlockSize);
  523. FINALIZE_CRC32(dwCRC32);
  524. pOffsetEntry[dwOffsetIndex].dwCRC = dwCRC32;
  525. //Copy the blob into the block
  526. CopyMemory(pbPage + pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset, pBlock, ulBlockSize);
  527. //Return the offset ID
  528. *pdwNewOffset = dwNewOffsetId;
  529. }
  530. return dwRes;
  531. }
  532. //**************************************************************************************
  533. //OffsetToPointer - Given and offsetId and a page, calculate the physical pointer to the
  534. //object and also return the size of the block.
  535. //**************************************************************************************
  536. DWORD CVarObjHeap::OffsetToPointer(/* in */ ULONG ulOffsetId,
  537. /* in */ BYTE *pbPage,
  538. /* out*/ BYTE **pOffsetPointer,
  539. /* out*/ ULONG *pdwBlockSize,
  540. /* out*/ DWORD *pdwCRC32)
  541. {
  542. DWORD dwRes = ERROR_FILE_NOT_FOUND;
  543. //Get a pointer to the start of the offset table
  544. VarObjObjOffsetEntry *pOffsetEntry = (VarObjObjOffsetEntry *) pbPage;
  545. //Loop through the table until we find the one we are interested in
  546. for (DWORD dwOffsetIndex = 0; pOffsetEntry[dwOffsetIndex].dwOffsetId != 0; dwOffsetIndex++)
  547. {
  548. if (pOffsetEntry[dwOffsetIndex].dwOffsetId == ulOffsetId)
  549. {
  550. dwRes = ERROR_SUCCESS;
  551. *pdwBlockSize = pOffsetEntry[dwOffsetIndex].dwBlockLength;
  552. *pOffsetPointer = pbPage + pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset;
  553. *pdwCRC32 = pOffsetEntry[dwOffsetIndex].dwCRC;
  554. break;
  555. }
  556. }
  557. return dwRes;
  558. }
  559. //**************************************************************************************
  560. //ReadAdminPages - Reads the admin pages into memory and marks them as clean (no changes)
  561. //**************************************************************************************
  562. DWORD CVarObjHeap::ReadAdminPages(CPageSource *pTransactionManager, bool bReReadPages)
  563. {
  564. m_aAdminPages.Lock();
  565. //Check it wasn't lock contention that meant we had multiple
  566. //threads trying to re-read the admin pages.
  567. if (m_dwStatus == NoError)
  568. {
  569. m_aAdminPages.Unlock();
  570. return ERROR_SUCCESS;
  571. }
  572. //Delete anything we may already have in the list in case we need to re-read it in
  573. //case of an aborted transaction.
  574. while (m_aAdminPages.Size())
  575. {
  576. VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[0];
  577. delete [] pEntry->pbPage;
  578. delete pEntry;
  579. m_aAdminPages.RemoveAt(0);
  580. }
  581. DWORD dwRes = ERROR_SUCCESS;
  582. if (bReReadPages)
  583. {
  584. m_dwStatus = AdminPagesNeedReading;
  585. DWORD dwAdminPageId = 0; //First admin page always resides on page 0
  586. do
  587. {
  588. bool bDirty = false;
  589. BYTE *pbAdminPage = new BYTE[m_dwPageSize];
  590. VarObjAdminPageEntry *pEntry = new VarObjAdminPageEntry;
  591. if ((pbAdminPage == NULL) || (pEntry == NULL))
  592. {
  593. dwRes = ERROR_OUTOFMEMORY;
  594. m_dwStatus = AdminPageReadFailure;
  595. }
  596. if (dwRes == ERROR_SUCCESS)
  597. {
  598. dwRes = m_pObjectFile->GetPage(dwAdminPageId, 0, pbAdminPage);
  599. if ((dwRes == ERROR_FILE_NOT_FOUND) && (dwAdminPageId == 0))
  600. {
  601. //This is the first attempt, so we need to create the admin page!
  602. dwRes = m_pObjectFile->NewPage(1, 1, &dwAdminPageId);
  603. if (dwRes == ERROR_SUCCESS)
  604. {
  605. //Write the default data to the admin page
  606. bDirty = true;
  607. VarObjHeapAdminPage* pAdminPage = (VarObjHeapAdminPage*)pbAdminPage;
  608. pAdminPage->dwNextAdminPage = 0;
  609. pAdminPage->dwNumberEntriesOnPage = 0;
  610. pAdminPage->dwVersion = VAROBJ_VERSION;
  611. dwRes = m_pObjectFile->PutPage(dwAdminPageId, 0, pbAdminPage);
  612. if (dwRes != ERROR_SUCCESS)
  613. {
  614. m_dwStatus = RootAdminPageCreationFailure;
  615. }
  616. }
  617. else
  618. {
  619. m_dwStatus = RootAdminPageCreationFailure;
  620. }
  621. }
  622. else if ((dwAdminPageId == 0) && (dwRes != ERROR_SUCCESS))
  623. {
  624. m_dwStatus = AdminPageReadFailure;
  625. }
  626. }
  627. if (dwRes == ERROR_SUCCESS)
  628. {
  629. pEntry->dwPageId = dwAdminPageId;
  630. pEntry->pbPage = pbAdminPage;
  631. pEntry->bDirty = bDirty;
  632. }
  633. if ((dwRes == ERROR_SUCCESS) && (m_aAdminPages.Add(pEntry) != CFlexArray::no_error))
  634. {
  635. dwRes = ERROR_OUTOFMEMORY;
  636. m_dwStatus = AdminPageReadFailure;
  637. }
  638. if (dwRes == ERROR_SUCCESS)
  639. dwAdminPageId = ((VarObjHeapAdminPage*)pbAdminPage)->dwNextAdminPage;
  640. else
  641. {
  642. //Tidy up!
  643. delete [] pbAdminPage;
  644. delete pEntry;
  645. }
  646. }
  647. while ((dwRes == ERROR_SUCCESS) && (dwAdminPageId != 0));
  648. //If we had a problem we need to delete everything in the admin list
  649. if (dwRes != ERROR_SUCCESS)
  650. {
  651. while (m_aAdminPages.Size())
  652. {
  653. VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[0];
  654. delete [] pEntry->pbPage;
  655. delete pEntry;
  656. m_aAdminPages.RemoveAt(0);
  657. }
  658. }
  659. if (dwRes == ERROR_SUCCESS)
  660. {
  661. m_dwStatus = NoError;
  662. }
  663. }
  664. m_aAdminPages.Unlock();
  665. return dwRes;
  666. }
  667. //**************************************************************************************
  668. //FlushAdminPages - Writes each of the changed admin pages back to the object file
  669. //**************************************************************************************
  670. DWORD CVarObjHeap::FlushAdminPages()
  671. {
  672. DWORD dwRes = ERROR_SUCCESS;
  673. m_aAdminPages.Lock();
  674. for (DWORD dwIndex = 0; dwIndex != m_aAdminPages.Size(); dwIndex++)
  675. {
  676. VarObjAdminPageEntry * pEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwIndex];
  677. #if DBG
  678. if ((dwIndex == 0) && (pEntry->dwPageId != 0))
  679. {
  680. OutputDebugString(L"WinMgmt: Repository corrupt! First admin page should always be page 0!\n");
  681. DebugBreak();
  682. }
  683. VarObjHeapAdminPage *pAdminPage = (VarObjHeapAdminPage*) pEntry->pbPage;
  684. if ((dwIndex != 0) && (pAdminPage->dwVersion != 0))
  685. {
  686. OutputDebugString(L"WinMmgt: Repository corrupt! Trailing admin pages should have version stamp of 0!\n");
  687. DebugBreak();
  688. }
  689. #endif
  690. if (pEntry->bDirty)
  691. dwRes = m_pObjectFile->PutPage(pEntry->dwPageId, 0, pEntry->pbPage);
  692. if (dwRes == ERROR_SUCCESS)
  693. pEntry->bDirty = false;
  694. else
  695. break;
  696. }
  697. m_aAdminPages.Unlock();
  698. return dwRes;
  699. }
  700. //**************************************************************************************
  701. //Find a page form the admin pages that can accomodate a particular buffer size
  702. //**************************************************************************************
  703. DWORD CVarObjHeap::FindPageWithSpace(/* in */ DWORD dwRequiredSize,
  704. /* out*/ DWORD *pdwPageId)
  705. {
  706. DWORD dwRes = ERROR_FILE_NOT_FOUND;
  707. m_aAdminPages.Lock();
  708. for (DWORD dwPageIndex = 0; (*pdwPageId == 0) && (dwPageIndex != m_aAdminPages.Size()); dwPageIndex++)
  709. {
  710. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
  711. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  712. #if DBG
  713. if ((dwPageIndex != 0) && (pAdminPage->dwVersion != 0))
  714. {
  715. OutputDebugString(L"WinMgmt: Repository admin page is corrupt as version is invalid!\n");
  716. DebugBreak();
  717. }
  718. if (pAdminPage->dwNumberEntriesOnPage > ((m_dwPageSize - sizeof(VarObjHeapAdminPage)) / sizeof(VarObjHeapFreeList)))
  719. {
  720. OutputDebugString(L"WinMgmt: Repository admin page is corrupt because it thinks there are more entries than fit on the page!\n");
  721. DebugBreak();
  722. }
  723. #endif
  724. for (DWORD dwFreeIndex = 0; (*pdwPageId == 0) && (dwFreeIndex != pAdminPage->dwNumberEntriesOnPage); dwFreeIndex++)
  725. {
  726. if (pFreeListEntry[dwFreeIndex].dwFreeSpace >= (dwRequiredSize + sizeof(VarObjObjOffsetEntry)))
  727. {
  728. *pdwPageId = pFreeListEntry[dwFreeIndex].dwPageId;
  729. dwRes = ERROR_SUCCESS;
  730. }
  731. }
  732. }
  733. m_aAdminPages.Unlock();
  734. return dwRes;
  735. }
  736. //**************************************************************************************
  737. //Allocate a new page for use with objects.
  738. //**************************************************************************************
  739. DWORD CVarObjHeap::AllocateNewPage(/* in */ DWORD ulBlockSize,
  740. /* out*/ DWORD *pdwPageId,
  741. /* in */ BYTE *pbNewObjectPage)
  742. {
  743. DWORD dwRes = ERROR_SUCCESS;
  744. //Allocate a new page from the object file
  745. if (dwRes == ERROR_SUCCESS)
  746. dwRes = m_pObjectFile->NewPage(0, 1, pdwPageId);
  747. if (dwRes != ERROR_SUCCESS)
  748. return dwRes;
  749. //We need to know if we get to the end without finding space because at that point
  750. //we need to allocate a new admin page!
  751. dwRes = ERROR_FILE_NOT_FOUND;
  752. //Find an admin page that has space for this new entry
  753. m_aAdminPages.Lock();
  754. for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
  755. {
  756. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
  757. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  758. if ((sizeof(VarObjHeapAdminPage) + ((pAdminPage->dwNumberEntriesOnPage + 1) * sizeof(VarObjHeapFreeList))) <= m_dwPageSize)
  759. {
  760. dwRes = ERROR_SUCCESS;
  761. break;
  762. }
  763. }
  764. m_aAdminPages.Unlock();
  765. if (dwRes == ERROR_FILE_NOT_FOUND)
  766. {
  767. //TODO! REMOVE DEBUG CODE!
  768. if (m_aAdminPages.Size() == 0)
  769. {
  770. OutputDebugString(L"Winmgmt: Repository admin page list is empty (1)\n");
  771. DebugBreak();
  772. }
  773. //We did not find an admin page with any additional slots available. We need to allocate
  774. //a new admin page
  775. dwRes = ERROR_SUCCESS;
  776. DWORD dwNewAdminPageId = 0;
  777. //We need to allocate a new page in the object file
  778. dwRes = m_pObjectFile->NewPage(0, 1, &dwNewAdminPageId);
  779. if (m_aAdminPages.Size() == 0)
  780. {
  781. OutputDebugString(L"Winmgmt: Repository admin page list is empty (2)\n");
  782. DebugBreak();
  783. }
  784. //we need to allocate all the memory for the admin page cache
  785. BYTE *pbNewAdminPage = NULL;
  786. VarObjAdminPageEntry *pAdminPageEntry = NULL;
  787. if (dwRes == ERROR_SUCCESS)
  788. {
  789. pbNewAdminPage = new BYTE[m_dwPageSize];
  790. pAdminPageEntry = new VarObjAdminPageEntry;
  791. if ((pbNewAdminPage == NULL) || (pAdminPageEntry == NULL))
  792. dwRes = ERROR_OUTOFMEMORY;
  793. }
  794. if (dwRes == ERROR_SUCCESS)
  795. {
  796. if (m_aAdminPages.Add(pAdminPageEntry) != CFlexArray::no_error)
  797. {
  798. dwRes = ERROR_OUTOFMEMORY;
  799. }
  800. }
  801. if (m_aAdminPages.Size() == 0)
  802. {
  803. OutputDebugString(L"Winmgmt: Repository admin page list is empty (3)\n");
  804. DebugBreak();
  805. }
  806. if (dwRes != ERROR_SUCCESS)
  807. {
  808. delete [] pbNewAdminPage;
  809. delete pAdminPageEntry;
  810. }
  811. if (dwRes == ERROR_SUCCESS)
  812. {
  813. //Write the admin page entry detail
  814. pAdminPageEntry->dwPageId = dwNewAdminPageId;
  815. pAdminPageEntry->pbPage = pbNewAdminPage;
  816. pAdminPageEntry->bDirty = true; //new page needs to be written!
  817. //Hook the previous admin page to this one (we have already added the new one remember!
  818. if (m_aAdminPages.Size() == 0)
  819. {
  820. OutputDebugString(L"Winmgmt: Repository admin page list is empty (4)\n");
  821. DebugBreak();
  822. }
  823. VarObjAdminPageEntry *pPreviousAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[m_aAdminPages.Size() - 2];
  824. VarObjHeapAdminPage *pPreviousAdminPage = (VarObjHeapAdminPage *)(pPreviousAdminPageEntry->pbPage);
  825. pPreviousAdminPage->dwNextAdminPage = dwNewAdminPageId;
  826. pPreviousAdminPageEntry->bDirty = true; //We just changed the page so it needs to be marked for flushing
  827. //Initialize this new admin page with everything necessary
  828. VarObjHeapAdminPage *pNewAdminPage = (VarObjHeapAdminPage *)pbNewAdminPage;
  829. pNewAdminPage->dwNextAdminPage = 0;
  830. pNewAdminPage->dwNumberEntriesOnPage = 0;
  831. pNewAdminPage->dwVersion = 0; //not used on anything but the first page!
  832. //Now we have all the details in there, we can set the index to this page so we can allocate
  833. //add the new object page to it!
  834. dwPageIndex = m_aAdminPages.Size() - 1;
  835. }
  836. }
  837. //By here we now have the admin page we have space to put this new page entry!
  838. if (dwRes == ERROR_SUCCESS)
  839. {
  840. //cached admin page entry, update the dirty bit as we are changing it
  841. VarObjAdminPageEntry *pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
  842. pAdminPageEntry->bDirty = true;
  843. //Admin page header, update the number of entries
  844. VarObjHeapAdminPage *pAdminPage = (VarObjHeapAdminPage *)pAdminPageEntry->pbPage;
  845. pAdminPage->dwNumberEntriesOnPage++;
  846. //Add the entry to the end!
  847. VarObjHeapFreeList *pFreeList = (VarObjHeapFreeList *)(pAdminPageEntry->pbPage + sizeof(VarObjHeapAdminPage) + (sizeof(VarObjHeapFreeList) * (pAdminPage->dwNumberEntriesOnPage - 1)));
  848. pFreeList->dwPageId = *pdwPageId;
  849. pFreeList->dwFreeSpace = m_dwPageSize - sizeof(VarObjObjOffsetEntry);
  850. pFreeList->dwCRC32 = 0;
  851. pFreeList->dwReserved = 0;
  852. //Now we need to need to initialize the new object page to look like an empty page
  853. ZeroMemory(pbNewObjectPage, sizeof(VarObjObjOffsetEntry));
  854. }
  855. return dwRes;
  856. }
  857. //**************************************************************************************
  858. //Allocates a multi-page entry in the object file. This requires
  859. //different algorithms to work things out so is a special case
  860. //**************************************************************************************
  861. DWORD CVarObjHeap::AllocateMultiPageBuffer(/* in */ ULONG ulBlockSize,
  862. /* in */ const BYTE *pBlock,
  863. /* out */ ULONG *pulPageId,
  864. /* out */ ULONG *pulOffsetId)
  865. {
  866. DWORD dwRes = ERROR_SUCCESS;
  867. //Whole pages calculation
  868. DWORD dwNumberPagesNeeded = (ulBlockSize + (sizeof(VarObjObjOffsetEntry) * 2)) / m_dwPageSize;
  869. //Partial page calculation
  870. if ((ulBlockSize + (sizeof(VarObjObjOffsetEntry) * 2) % m_dwPageSize) != 0)
  871. dwNumberPagesNeeded++;
  872. DWORD dwFirstPageId = 0;
  873. dwRes = m_pObjectFile->NewPage(0, dwNumberPagesNeeded, &dwFirstPageId);
  874. for (DWORD dwCurrentOffset = 0, dwPageIndex = 0; dwPageIndex != dwNumberPagesNeeded; dwPageIndex++)
  875. {
  876. BYTE *pPage = new BYTE[m_dwPageSize];
  877. if (pPage == NULL)
  878. dwRes = ERROR_OUTOFMEMORY;
  879. CVectorDeleteMe<BYTE> vdm(pPage);
  880. if (dwRes == ERROR_SUCCESS)
  881. {
  882. if (dwCurrentOffset == 0)
  883. {
  884. //We have to write the header for the offset page
  885. ZeroMemory(pPage, sizeof(VarObjObjOffsetEntry) * 2);
  886. VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pPage;
  887. pEntry->dwBlockLength = ulBlockSize;
  888. pEntry->dwOffsetId = 1;
  889. pEntry->dwPhysicalStartOffset = sizeof(VarObjObjOffsetEntry) * 2;
  890. DWORD dwCRC32 = CreateCRC32(pBlock, ulBlockSize);
  891. FINALIZE_CRC32(dwCRC32);
  892. pEntry->dwCRC = dwCRC32;
  893. //Fill the rest of this page
  894. CopyMemory(pPage + (sizeof(VarObjObjOffsetEntry) * 2), pBlock, m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2));
  895. dwCurrentOffset = m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2);
  896. }
  897. else
  898. {
  899. if (ulBlockSize - dwCurrentOffset > m_dwPageSize)
  900. {
  901. CopyMemory(pPage, pBlock + dwCurrentOffset, m_dwPageSize);
  902. dwCurrentOffset += m_dwPageSize;
  903. }
  904. else
  905. {
  906. CopyMemory(pPage, pBlock + dwCurrentOffset, ulBlockSize - dwCurrentOffset);
  907. dwCurrentOffset += (ulBlockSize - dwCurrentOffset);
  908. //NOTE!!! dwCurrentOffset should equal ulBlockSize now!!!!!
  909. }
  910. }
  911. dwRes = m_pObjectFile->PutPage(dwFirstPageId + dwPageIndex, 0, pPage);
  912. }
  913. if (FAILED(dwRes))
  914. break;
  915. }
  916. if (dwRes == ERROR_SUCCESS)
  917. {
  918. //Set up the pageId and offset details the client requested
  919. *pulPageId = dwFirstPageId;
  920. *pulOffsetId = 1;
  921. }
  922. return dwRes;
  923. }
  924. //**************************************************************************************
  925. //DeleteMultiPageBuffer - handles the deletion of an object when it spans
  926. //multiple pages
  927. //******************4********************************************************************
  928. DWORD CVarObjHeap::DeleteMultiPageBuffer(/* in */ ULONG ulPageId,
  929. /* in */ ULONG ulOffsetId,
  930. /* in */ BYTE *pbPage)
  931. {
  932. DWORD dwRes = ERROR_SUCCESS;
  933. //Calculate how many pages are used:
  934. VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*)pbPage;
  935. //Whole pages calculation
  936. DWORD dwNumberPagesNeeded = (pEntry->dwBlockLength + (sizeof(VarObjObjOffsetEntry) * 2)) / m_dwPageSize;
  937. //Partial page calculation
  938. if ((pEntry->dwBlockLength + (sizeof(VarObjObjOffsetEntry) * 2) % m_dwPageSize) != 0)
  939. dwNumberPagesNeeded++;
  940. for (DWORD dwPageIndex = 0; dwPageIndex != dwNumberPagesNeeded; dwPageIndex ++)
  941. {
  942. dwRes = m_pObjectFile->FreePage(0, ulPageId + dwPageIndex);
  943. if (FAILED(dwRes))
  944. break;
  945. }
  946. return dwRes;
  947. }
  948. //**************************************************************************************
  949. //DeleteFromPage - removes an object from a specific object page
  950. //**************************************************************************************
  951. DWORD CVarObjHeap::RemoveFromPage(/* in */ ULONG ulPageId,
  952. /* in */ ULONG ulOffsetId,
  953. /* in */ BYTE *pbPage,
  954. /* out*/ DWORD *pdwSize)
  955. {
  956. DWORD dwRes = ERROR_FILE_NOT_FOUND;
  957. //Need to remove the entry from the offset table, subtracting the deleted object size
  958. //from the offset of all items following it
  959. VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*)pbPage;
  960. DWORD dwFoundOffset = 0;
  961. DWORD dwFoundSize = 0;
  962. DWORD dwFoundIndex = 0;
  963. for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex ++)
  964. {
  965. if (pEntry[dwIndex].dwOffsetId == ulOffsetId)
  966. {
  967. //This is ours, so record the details
  968. dwFoundOffset = pEntry[dwIndex].dwPhysicalStartOffset;
  969. dwFoundSize = pEntry[dwIndex].dwBlockLength;
  970. *pdwSize = dwFoundSize;
  971. dwRes = ERROR_SUCCESS;
  972. dwFoundIndex = dwIndex;
  973. }
  974. else if (dwRes == ERROR_SUCCESS)
  975. {
  976. //We have already found it so we need to adjust this entry
  977. //to account for the removed space
  978. pEntry[dwIndex - 1].dwPhysicalStartOffset = pEntry[dwIndex].dwPhysicalStartOffset - dwFoundSize - sizeof(VarObjObjOffsetEntry);
  979. pEntry[dwIndex - 1].dwBlockLength = pEntry[dwIndex].dwBlockLength;
  980. pEntry[dwIndex - 1].dwOffsetId = pEntry[dwIndex].dwOffsetId;
  981. pEntry[dwIndex - 1].dwCRC = pEntry[dwIndex].dwCRC;
  982. }
  983. else
  984. {
  985. //Adjust for the fact that we are removing an entry for the offset table
  986. pEntry[dwIndex].dwPhysicalStartOffset -= sizeof(VarObjObjOffsetEntry);
  987. }
  988. }
  989. if (dwRes == ERROR_SUCCESS)
  990. {
  991. //We need to adjust the end-of-list by one place also
  992. pEntry[dwIndex - 1].dwPhysicalStartOffset = 0;
  993. pEntry[dwIndex - 1].dwBlockLength = 0;
  994. pEntry[dwIndex - 1].dwOffsetId = 0;
  995. pEntry[dwIndex - 1].dwCRC = 0;
  996. //Now we need to adjust all entries up to the deleted one by the size of
  997. //the offset table entry... although if this was the first item in the list then there
  998. //is nothing to do
  999. if (dwFoundIndex != 0)
  1000. {
  1001. MoveMemory(pbPage + pEntry[0].dwPhysicalStartOffset,
  1002. pbPage + pEntry[0].dwPhysicalStartOffset + sizeof(VarObjObjOffsetEntry),
  1003. dwFoundOffset - (pEntry[0].dwPhysicalStartOffset + sizeof(VarObjObjOffsetEntry)));
  1004. }
  1005. //Now we need to shuffle all entries that appeared after this entry back one... if this
  1006. //was the last entry then we don't have anything to do.
  1007. if (pEntry[dwFoundIndex].dwOffsetId != 0)
  1008. {
  1009. MoveMemory(pbPage + pEntry[dwFoundIndex].dwPhysicalStartOffset,
  1010. pbPage + dwFoundOffset + dwFoundSize,
  1011. (pEntry[dwIndex - 2].dwPhysicalStartOffset + pEntry[dwIndex - 2].dwBlockLength) - (pEntry[dwFoundIndex].dwPhysicalStartOffset));
  1012. }
  1013. }
  1014. return dwRes;
  1015. }
  1016. //**************************************************************************************
  1017. //UpdateAdminPageForAllocate - Updates the admin page to decrement the amount
  1018. //of free space on a page by this amount ( + sizeof(VarObjObjOffsetEntry))
  1019. //**************************************************************************************
  1020. DWORD CVarObjHeap::UpdateAdminPageForAllocate(/* in */ ULONG ulPageId,
  1021. /* in */ ULONG ulBlockSize,
  1022. /* in */ DWORD dwNewCRC)
  1023. {
  1024. DWORD dwRes = ERROR_FILE_NOT_FOUND;
  1025. //Find an admin page that has this page
  1026. for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
  1027. {
  1028. VarObjAdminPageEntry* pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
  1029. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(pAdminPageEntry->pbPage);
  1030. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  1031. for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
  1032. {
  1033. if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
  1034. {
  1035. pFreeListEntry[dwEntry].dwFreeSpace -= (ulBlockSize + sizeof(VarObjObjOffsetEntry));
  1036. pFreeListEntry[dwEntry].dwCRC32 = dwNewCRC;
  1037. pAdminPageEntry->bDirty = true;
  1038. #if XFILES_DEBUG
  1039. wchar_t buf[100];
  1040. swprintf(buf, L"Page 0x%08X has allocated 0x%08X bytes. Space left 0x%08X\n", ulPageId, ulBlockSize + sizeof(VarObjObjOffsetEntry), pFreeListEntry[dwEntry].dwFreeSpace);
  1041. OutputDebugString(buf);
  1042. #endif
  1043. dwRes = ERROR_SUCCESS;
  1044. break;
  1045. }
  1046. }
  1047. if (dwRes == ERROR_SUCCESS)
  1048. break;
  1049. }
  1050. return dwRes;
  1051. }
  1052. //**************************************************************************************
  1053. //UpdateAdminPageForDelete - Updates the admin page for giving space back. If the page
  1054. //is totally empty we should delete the page altogether. Note that the space taken
  1055. //up is sizeof(VarObjObjOffsetEntry) more than specified because of the offset entry!
  1056. //**************************************************************************************
  1057. DWORD CVarObjHeap::UpdateAdminPageForDelete(/* in */ ULONG ulPageId,
  1058. /* in */ ULONG ulBlockSize,
  1059. /* in */ DWORD dwNewCRC,
  1060. /* out */ bool *pbPageDeleted)
  1061. {
  1062. DWORD dwRes = ERROR_FILE_NOT_FOUND;
  1063. bool bFinished = false;
  1064. //Find an admin page that has this page
  1065. for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
  1066. {
  1067. VarObjAdminPageEntry* pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex];
  1068. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(pAdminPageEntry->pbPage);
  1069. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  1070. for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
  1071. {
  1072. if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
  1073. {
  1074. pFreeListEntry[dwEntry].dwFreeSpace += (ulBlockSize + sizeof(VarObjObjOffsetEntry));
  1075. pFreeListEntry[dwEntry].dwCRC32 = dwNewCRC;
  1076. dwRes = ERROR_SUCCESS;
  1077. bFinished = true;
  1078. pAdminPageEntry->bDirty = true;
  1079. #if XFILES_DEBUG
  1080. wchar_t buf[100];
  1081. swprintf(buf, L"Page 0x%08X has deallocated 0x%08X bytes. Space left 0x%08X\n", ulPageId, ulBlockSize + sizeof(VarObjObjOffsetEntry), pFreeListEntry[dwEntry].dwFreeSpace);
  1082. OutputDebugString(buf);
  1083. #endif
  1084. if (pFreeListEntry[dwEntry].dwFreeSpace == (m_dwPageSize - sizeof(VarObjObjOffsetEntry)))
  1085. {
  1086. dwRes = RemoveEntryFromAdminPage(dwPageIndex, dwEntry);
  1087. if (dwRes == ERROR_SUCCESS)
  1088. {
  1089. dwRes = m_pObjectFile->FreePage(0, ulPageId);
  1090. *pbPageDeleted = true;
  1091. }
  1092. }
  1093. break;
  1094. }
  1095. }
  1096. if (bFinished)
  1097. break;
  1098. }
  1099. return dwRes;
  1100. }
  1101. //**************************************************************************************
  1102. //Deletes a page, and updates the admin pages as appropriage. If the admin page
  1103. //is now enpty we delete this admin page and update the next pointer of the previous
  1104. //page. We do not delete the first admin page however as it has a special pageId
  1105. //that is reserved.
  1106. //**************************************************************************************
  1107. DWORD CVarObjHeap::DeletePage(/* in */ DWORD ulPageId)
  1108. {
  1109. DWORD dwRes = m_pObjectFile->FreePage(0, ulPageId);
  1110. bool bFinished = false;
  1111. if (dwRes == ERROR_SUCCESS)
  1112. {
  1113. dwRes = ERROR_FILE_NOT_FOUND;
  1114. for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
  1115. {
  1116. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
  1117. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  1118. for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
  1119. {
  1120. if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
  1121. {
  1122. dwRes = RemoveEntryFromAdminPage(dwPageIndex, dwEntry);
  1123. bFinished = true;
  1124. break;
  1125. }
  1126. }
  1127. if (bFinished)
  1128. break;
  1129. }
  1130. }
  1131. return dwRes;
  1132. }
  1133. //**************************************************************************************
  1134. //Removes an object page entry from an admin page, removing the
  1135. //admin page if it is no longer needed
  1136. //**************************************************************************************
  1137. DWORD CVarObjHeap::RemoveEntryFromAdminPage(/* in */ DWORD dwAdminPageIndex,
  1138. /* in */ DWORD dwAdminPageEntry)
  1139. {
  1140. DWORD dwRes = ERROR_SUCCESS;
  1141. VarObjAdminPageEntry *pAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwAdminPageIndex];
  1142. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)pAdminPageEntry->pbPage;
  1143. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  1144. pAdminPage->dwNumberEntriesOnPage--;
  1145. if ((pAdminPage->dwNumberEntriesOnPage == 0) && (dwAdminPageIndex != 0))
  1146. {
  1147. //Need to delete this admin page... update the previous pages next admin page entry
  1148. VarObjAdminPageEntry *pPreviousAdminPageEntry = (VarObjAdminPageEntry*)m_aAdminPages[dwAdminPageIndex - 1];
  1149. VarObjHeapAdminPage * pPreviousAdminPage = (VarObjHeapAdminPage *)pPreviousAdminPageEntry->pbPage;
  1150. pPreviousAdminPage->dwNextAdminPage = pAdminPage->dwNextAdminPage;
  1151. //Set the dirty bit on that page so it gets flushed!
  1152. pPreviousAdminPageEntry->bDirty = true;
  1153. //Do the actual free page of this admin page
  1154. dwRes = m_pObjectFile->FreePage(0, pAdminPageEntry->dwPageId);
  1155. if (dwRes == ERROR_SUCCESS)
  1156. {
  1157. m_aAdminPages.RemoveAt(dwAdminPageIndex);
  1158. delete pAdminPageEntry;
  1159. }
  1160. }
  1161. else if ((pAdminPage->dwNumberEntriesOnPage == 0) && (dwAdminPageIndex == 0))
  1162. {
  1163. //The first admin page cannot be deleted so we just ignore this
  1164. }
  1165. else if (pAdminPage->dwNumberEntriesOnPage != 0)
  1166. {
  1167. //We just need to delete the entry, so shuffle the entries about
  1168. //in the page
  1169. MoveMemory(&pFreeListEntry[dwAdminPageEntry], &pFreeListEntry[dwAdminPageEntry+1], sizeof(VarObjHeapFreeList) * (pAdminPage->dwNumberEntriesOnPage - dwAdminPageEntry));
  1170. }
  1171. return dwRes;
  1172. }
  1173. #ifdef DBG
  1174. //Given a page we validate that there is in fact enough space
  1175. //for this block. If there is not it asserts. This implies
  1176. //that the admin page is not in sync with the actual pages.
  1177. DWORD CVarObjHeap::ValidatePageFreeSpace(/* in */ const BYTE *pbPage,
  1178. /* in */ DWORD ulBlockSize)
  1179. {
  1180. DWORD dwRes = ERROR_SUCCESS;
  1181. VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pbPage;
  1182. DWORD dwNextAvailableOffset = pEntry[0].dwPhysicalStartOffset + pEntry[0].dwBlockLength;
  1183. //Search through the offset table until we find the last entry
  1184. for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex++)
  1185. {
  1186. dwNextAvailableOffset = pEntry[dwIndex].dwPhysicalStartOffset + pEntry[dwIndex].dwBlockLength;
  1187. }
  1188. if ((dwNextAvailableOffset + ulBlockSize + sizeof(VarObjObjOffsetEntry))> m_dwPageSize)
  1189. {
  1190. dwRes = ERROR_INTERNAL_ERROR;
  1191. OutputDebugString(L"WinMgmt Repository Corruption: Object heap admin page free space information is out of sync with actual pages!\n");
  1192. DebugBreak();
  1193. }
  1194. return dwRes;
  1195. }
  1196. //Given a page and a page ID, it validates the amount of free space
  1197. //on the page is equal to the amount the admin page thinks is on
  1198. //there.
  1199. DWORD CVarObjHeap::ValidatePageFreeSpaceWithAdminPage(/* in */ const BYTE *pbPage,
  1200. /* in */ DWORD ulPageId)
  1201. {
  1202. DWORD dwRes = ERROR_SUCCESS;
  1203. VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pbPage;
  1204. DWORD dwNextAvailableOffset = pEntry[0].dwPhysicalStartOffset + pEntry[0].dwBlockLength;
  1205. //Search through the offset table until we find the last entry
  1206. for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex++)
  1207. {
  1208. dwNextAvailableOffset = pEntry[dwIndex].dwPhysicalStartOffset + pEntry[dwIndex].dwBlockLength;
  1209. }
  1210. DWORD dwFreeSpace = m_dwPageSize - dwNextAvailableOffset;
  1211. //Find the page in the admin page table
  1212. for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
  1213. {
  1214. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
  1215. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  1216. for (DWORD dwEntry = 0; dwEntry != pAdminPage->dwNumberEntriesOnPage; dwEntry ++)
  1217. {
  1218. //If this is the page we are interested in...
  1219. if (ulPageId == pFreeListEntry[dwEntry].dwPageId)
  1220. {
  1221. //check the free space matches...
  1222. if (pFreeListEntry[dwEntry].dwFreeSpace != dwFreeSpace)
  1223. {
  1224. //Oops, it doesn't! We have a problem!
  1225. OutputDebugString(L"WinMgmt Repository Corruption: Free space in page is out of sink with the free space listed in admin page!\n");
  1226. DebugBreak();
  1227. return ERROR_INTERNAL_ERROR;
  1228. }
  1229. return ERROR_SUCCESS;
  1230. }
  1231. }
  1232. }
  1233. return dwRes;
  1234. }
  1235. //Dumps the offset table of a page to the debugger
  1236. DWORD CVarObjHeap::DumpPageOffsetTable(/* in */ DWORD dwPageId,
  1237. /* in */ const BYTE *pbPage)
  1238. {
  1239. wchar_t buf[100];
  1240. OutputDebugString(L"================================\n");
  1241. _stprintf(buf, L"Dumping offset table for pageId <0x%X>\n", dwPageId);
  1242. OutputDebugString(buf);
  1243. OutputDebugString(L"================================\n");
  1244. DWORD dwRes = ERROR_SUCCESS;
  1245. VarObjObjOffsetEntry *pEntry = (VarObjObjOffsetEntry*) pbPage;
  1246. for (DWORD dwIndex = 0; pEntry[dwIndex].dwOffsetId != 0; dwIndex++)
  1247. {
  1248. _stprintf(buf, L"0x%08X, 0x%08X, 0x%08X, 0x%08X\n", dwIndex, pEntry[dwIndex].dwOffsetId, pEntry[dwIndex].dwBlockLength, pEntry[dwIndex].dwPhysicalStartOffset);
  1249. OutputDebugString(buf);
  1250. }
  1251. _stprintf(buf, L"0x%08X, 0x%08X, 0x%08X, 0x%08X\n", dwIndex, pEntry[dwIndex].dwOffsetId, pEntry[dwIndex].dwBlockLength, pEntry[dwIndex].dwPhysicalStartOffset);
  1252. OutputDebugString(buf);
  1253. OutputDebugString(L"================================\n");
  1254. return ERROR_SUCCESS;
  1255. }
  1256. #endif /* DBG */
  1257. static DWORD g_CRCTable[] =
  1258. {
  1259. 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
  1260. 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
  1261. 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
  1262. 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
  1263. 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
  1264. 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  1265. 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
  1266. 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
  1267. 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  1268. 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
  1269. 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
  1270. 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  1271. 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
  1272. 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
  1273. 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  1274. 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
  1275. 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
  1276. 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  1277. 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
  1278. 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
  1279. 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
  1280. 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
  1281. 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
  1282. 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  1283. 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
  1284. 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
  1285. 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  1286. 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
  1287. 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
  1288. 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  1289. 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
  1290. 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
  1291. };
  1292. //Creates a CRC for a block
  1293. DWORD CVarObjHeap::CreateCRC32(/* in */ const BYTE *pBlock,
  1294. /* in */ DWORD dwSize,
  1295. /* in */ DWORD dwPreviousCRC)
  1296. {
  1297. if(dwSize == 0)
  1298. return dwPreviousCRC;
  1299. DWORD dwNewCRC = 0;
  1300. for (int n = 0; n < dwSize; n++)
  1301. {
  1302. dwNewCRC = g_CRCTable[ BYTE(dwPreviousCRC ^ DWORD(pBlock[n]))]
  1303. ^ ((dwPreviousCRC >> 8) & 0x00FFFFFF);
  1304. dwPreviousCRC = dwNewCRC;
  1305. }
  1306. return dwNewCRC;
  1307. }
  1308. #ifdef DBG
  1309. //Checks the CRCs of all objects on a page (cannot do this
  1310. //for a multi-page object though as we only have the first
  1311. //page!)
  1312. DWORD CVarObjHeap::ValidateAllCRC32OnPage(/* in */ const BYTE *pbPage)
  1313. {
  1314. DWORD dwRes = ERROR_SUCCESS;
  1315. //Get a pointer to the start of the offset table
  1316. VarObjObjOffsetEntry *pOffsetEntry = (VarObjObjOffsetEntry *) pbPage;
  1317. //Loop through the table until we find the one we are interested in
  1318. for (DWORD dwOffsetIndex = 0; pOffsetEntry[dwOffsetIndex].dwOffsetId != 0; dwOffsetIndex++)
  1319. {
  1320. if (pOffsetEntry[dwOffsetIndex].dwBlockLength > (m_dwPageSize - (sizeof(VarObjObjOffsetEntry) * 2)))
  1321. {
  1322. break;
  1323. }
  1324. else
  1325. {
  1326. try
  1327. {
  1328. DWORD dwNewCRC32 = CreateCRC32(pbPage + pOffsetEntry[dwOffsetIndex].dwPhysicalStartOffset, pOffsetEntry[dwOffsetIndex].dwBlockLength);
  1329. FINALIZE_CRC32(dwNewCRC32);
  1330. if (dwNewCRC32 != pOffsetEntry[dwOffsetIndex].dwCRC)
  1331. {
  1332. OutputDebugString(L"WinMgmt: Page Check: CRC check on an object retrieved from repository is invalid\n");
  1333. DebugBreak();
  1334. dwRes = ERROR_INTERNAL_ERROR;
  1335. }
  1336. }
  1337. catch (...)
  1338. {
  1339. OutputDebugString(L"WinMgmt: Page Check: CRC check on an object retrieved from repository is invalid\n");
  1340. DebugBreak();
  1341. dwRes = ERROR_INTERNAL_ERROR;
  1342. }
  1343. }
  1344. }
  1345. return dwRes;
  1346. }
  1347. //Validates the page check-sum with the admin page
  1348. DWORD CVarObjHeap::ValidatePageCRCWithAdminPage(/* in */ const BYTE *pbPage,
  1349. /* in */ DWORD dwPageId)
  1350. {
  1351. DWORD dwCRC32 = 0;
  1352. dwCRC32 = CreateCRC32(pbPage, m_dwPageSize);
  1353. FINALIZE_CRC32(dwCRC32);
  1354. for (DWORD dwPageIndex = 0; dwPageIndex != m_aAdminPages.Size(); dwPageIndex++)
  1355. {
  1356. VarObjHeapAdminPage * pAdminPage = (VarObjHeapAdminPage *)(((VarObjAdminPageEntry*)m_aAdminPages[dwPageIndex])->pbPage);
  1357. VarObjHeapFreeList *pFreeListEntry = (VarObjHeapFreeList *)(((BYTE*)pAdminPage) + sizeof (VarObjHeapAdminPage));
  1358. if ((dwPageIndex != 0) && (pAdminPage->dwVersion != 0))
  1359. {
  1360. OutputDebugString(L"WinMgmt: Repository admin page is corrupt as version is invalid!\n");
  1361. DebugBreak();
  1362. return ERROR_INTERNAL_ERROR;
  1363. }
  1364. if (pAdminPage->dwNumberEntriesOnPage > ((m_dwPageSize - sizeof(VarObjHeapAdminPage)) / sizeof(VarObjHeapFreeList)))
  1365. {
  1366. OutputDebugString(L"WinMgmt: Repository admin page is corrupt because it thinks there are more entries than fit on the page!\n");
  1367. DebugBreak();
  1368. return ERROR_INTERNAL_ERROR;
  1369. }
  1370. for (DWORD dwFreeIndex = 0; dwFreeIndex != pAdminPage->dwNumberEntriesOnPage; dwFreeIndex++)
  1371. {
  1372. if (pFreeListEntry[dwFreeIndex].dwPageId == dwPageId)
  1373. {
  1374. if (pFreeListEntry[dwFreeIndex].dwCRC32 == 0)
  1375. return ERROR_SUCCESS;
  1376. else if (pFreeListEntry[dwFreeIndex].dwCRC32 == dwCRC32)
  1377. return ERROR_SUCCESS;
  1378. else
  1379. {
  1380. OutputDebugString(L"WinMgmt: Repository admin page has an invalid CRC for the object page!\n");
  1381. DebugBreak();
  1382. return ERROR_INTERNAL_ERROR;
  1383. }
  1384. }
  1385. }
  1386. }
  1387. OutputDebugString(L"WinMgmt: Requested page was not found in the admin page list!\n");
  1388. DebugBreak();
  1389. return ERROR_INTERNAL_ERROR;
  1390. }
  1391. #endif