Leaked source code of windows server 2003
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

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