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.

1031 lines
26 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. hivemap.c
  5. Abstract:
  6. This module implements HvpBuildMap - used to build the initial map for a hive
  7. Author:
  8. Bryan M. Willman (bryanwi) 28-Mar-92
  9. Environment:
  10. Revision History:
  11. Dragos C. Sambotin (dragoss) 25-Jan-99
  12. Implementation of bin-size chunk loading of hives.
  13. --*/
  14. #include "cmp.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,HvpBuildMap)
  17. #pragma alloc_text(PAGE,HvpFreeMap)
  18. #pragma alloc_text(PAGE,HvpAllocateMap)
  19. #pragma alloc_text(PAGE,HvpBuildMapAndCopy)
  20. #pragma alloc_text(PAGE,HvpEnlistFreeCells)
  21. #pragma alloc_text(PAGE,HvpInitMap)
  22. #pragma alloc_text(PAGE,HvpCleanMap)
  23. #pragma alloc_text(PAGE,HvpEnlistBinInMap)
  24. #pragma alloc_text(PAGE,HvpGetBinMemAlloc)
  25. #endif
  26. extern struct {
  27. PHHIVE Hive;
  28. ULONG Status;
  29. ULONG Space;
  30. HCELL_INDEX MapPoint;
  31. PHBIN BinPoint;
  32. } HvCheckHiveDebug;
  33. //Dragos: Modified functions
  34. NTSTATUS
  35. HvpBuildMapAndCopy(
  36. PHHIVE Hive,
  37. PVOID Image
  38. )
  39. /*++
  40. Routine Description:
  41. Creates the map for the Stable storage of the hive, and inits
  42. the map for the volatile storage.
  43. Following fields in hive must already be filled in:
  44. Allocate, Free
  45. Will initialize Storage structure of HHIVE.
  46. This function is called for the HINIT_MEMORY case. The hive is guaranteed
  47. to be in paged-pool. More than that, the hive image is contiguous.
  48. It'll then copy from that image to the new paged-pool allocations.
  49. Arguments:
  50. Hive - Pointer to hive control structure to build map for.
  51. Image - pointer to flat memory image of original hive.
  52. Return Value:
  53. TRUE - it worked
  54. FALSE - either hive is corrupt or no memory for map
  55. --*/
  56. {
  57. PHBASE_BLOCK BaseBlock;
  58. ULONG Length;
  59. ULONG MapSlots;
  60. ULONG Tables;
  61. PHMAP_TABLE t = NULL;
  62. PHMAP_DIRECTORY d = NULL;
  63. PHBIN Bin;
  64. PHBIN CurrentBin;
  65. ULONG Offset;
  66. ULONG_PTR Address;
  67. PHMAP_ENTRY Me;
  68. NTSTATUS Status;
  69. PULONG Vector;
  70. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpBuildMap:\n"));
  71. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p",Hive));
  72. //
  73. // Compute size of data region to be mapped
  74. //
  75. BaseBlock = Hive->BaseBlock;
  76. Length = BaseBlock->Length;
  77. if ((Length % HBLOCK_SIZE) != 0 ) {
  78. Status = STATUS_REGISTRY_CORRUPT;
  79. goto ErrorExit1;
  80. }
  81. MapSlots = Length / HBLOCK_SIZE;
  82. if( MapSlots > 0 ) {
  83. Tables = (MapSlots-1) / HTABLE_SLOTS;
  84. } else {
  85. Tables = 0;
  86. }
  87. Hive->Storage[Stable].Length = Length;
  88. //
  89. // allocate dirty vector if one is not already present (from HvpRecoverData)
  90. //
  91. if (Hive->DirtyVector.Buffer == NULL) {
  92. Vector = (PULONG)((Hive->Allocate)(ROUND_UP(Length/HSECTOR_SIZE/8,sizeof(ULONG)), TRUE,CM_FIND_LEAK_TAG22));
  93. if (Vector == NULL) {
  94. Status = STATUS_NO_MEMORY;
  95. goto ErrorExit1;
  96. }
  97. RtlZeroMemory(Vector, Length / HSECTOR_SIZE / 8);
  98. RtlInitializeBitMap(&Hive->DirtyVector, Vector, Length / HSECTOR_SIZE);
  99. Hive->DirtyAlloc = ROUND_UP(Length/HSECTOR_SIZE/8,sizeof(ULONG));
  100. }
  101. //
  102. // allocate and build structure for map
  103. //
  104. if (Tables == 0) {
  105. //
  106. // Just 1 table, no need for directory
  107. //
  108. t = (Hive->Allocate)(sizeof(HMAP_TABLE), FALSE,CM_FIND_LEAK_TAG23);
  109. if (t == NULL) {
  110. Status = STATUS_INSUFFICIENT_RESOURCES;
  111. goto ErrorExit1;
  112. }
  113. RtlZeroMemory(t, sizeof(HMAP_TABLE));
  114. Hive->Storage[Stable].Map =
  115. (PHMAP_DIRECTORY)&(Hive->Storage[Stable].SmallDir);
  116. Hive->Storage[Stable].SmallDir = t;
  117. } else {
  118. //
  119. // Need directory and multiple tables
  120. //
  121. d = (PHMAP_DIRECTORY)(Hive->Allocate)(sizeof(HMAP_DIRECTORY), FALSE,CM_FIND_LEAK_TAG24);
  122. if (d == NULL) {
  123. Status = STATUS_INSUFFICIENT_RESOURCES;
  124. goto ErrorExit1;
  125. }
  126. RtlZeroMemory(d, sizeof(HMAP_DIRECTORY));
  127. //
  128. // Allocate tables and fill in dir
  129. //
  130. if (HvpAllocateMap(Hive, d, 0, Tables) == FALSE) {
  131. Status = STATUS_INSUFFICIENT_RESOURCES;
  132. goto ErrorExit2;
  133. }
  134. Hive->Storage[Stable].Map = d;
  135. Hive->Storage[Stable].SmallDir = 0;
  136. }
  137. //
  138. // Now we have to allocate the memory for the HBINs and fill in
  139. // the map appropriately. We are careful never to allocate less
  140. // than a page to avoid fragmenting pool. As long as the page
  141. // size is a multiple of HBLOCK_SIZE (a fairly good assumption as
  142. // long as HBLOCK_SIZE is 4k) this strategy will prevent pool
  143. // fragmentation.
  144. //
  145. // If we come across an HBIN that is entirely composed of a freed
  146. // HCELL, then we do not allocate memory, but mark its HBLOCKs in
  147. // the map as not present. HvAllocateCell will allocate memory for
  148. // the bin when it is needed.
  149. //
  150. Offset = 0;
  151. Bin = (PHBIN)Image;
  152. while (Bin < (PHBIN)((PUCHAR)(Image) + Length)) {
  153. if ( (Bin->Size > (Length-Offset)) ||
  154. (Bin->Signature != HBIN_SIGNATURE) ||
  155. (Bin->FileOffset != Offset)
  156. )
  157. {
  158. //
  159. // Bin is bogus
  160. //
  161. Status = STATUS_REGISTRY_CORRUPT;
  162. goto ErrorExit2;
  163. }
  164. CurrentBin = (PHBIN)(Hive->Allocate)(Bin->Size, FALSE,CM_FIND_LEAK_TAG25);
  165. if (CurrentBin==NULL) {
  166. Status = STATUS_INSUFFICIENT_RESOURCES;
  167. goto ErrorExit2; //fixfix
  168. }
  169. RtlCopyMemory(CurrentBin,
  170. (PUCHAR)Image+Offset,
  171. Bin->Size);
  172. //
  173. // create map entries for each block/page in bin
  174. //
  175. Address = (ULONG_PTR)CurrentBin;
  176. do {
  177. Me = HvpGetCellMap(Hive, Offset);
  178. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  179. Me->BlockAddress = Address;
  180. Me->BinAddress = (ULONG_PTR)CurrentBin;
  181. if (Address == (ULONG_PTR)CurrentBin) {
  182. Me->BinAddress |= HMAP_NEWALLOC;
  183. Me->MemAlloc = CurrentBin->Size;
  184. } else {
  185. Me->MemAlloc = 0;
  186. }
  187. Me->BinAddress |= HMAP_INPAGEDPOOL;
  188. // we don't need to set this - just for debug purposes
  189. ASSERT( (Me->CmView = NULL) == NULL );
  190. Address += HBLOCK_SIZE;
  191. Offset += HBLOCK_SIZE;
  192. } while ( Address < ((ULONG_PTR)CurrentBin + CurrentBin->Size ));
  193. if (Hive->ReadOnly == FALSE) {
  194. //
  195. // add free cells in the bin to the appropriate free lists
  196. //
  197. if ( ! HvpEnlistFreeCells(Hive,
  198. CurrentBin,
  199. CurrentBin->FileOffset
  200. )) {
  201. Status = STATUS_REGISTRY_CORRUPT;
  202. goto ErrorExit2;
  203. }
  204. }
  205. Bin = (PHBIN)((ULONG_PTR)Bin + Bin->Size);
  206. }
  207. return STATUS_SUCCESS;
  208. ErrorExit2:
  209. if (d != NULL) {
  210. //
  211. // directory was built and allocated, so clean it up
  212. //
  213. HvpFreeMap(Hive, d, 0, Tables);
  214. (Hive->Free)(d, sizeof(HMAP_DIRECTORY));
  215. }
  216. ErrorExit1:
  217. return Status;
  218. }
  219. NTSTATUS
  220. HvpInitMap(
  221. PHHIVE Hive
  222. )
  223. /*++
  224. Routine Description:
  225. Initialize the map for the Stable Volatile storage of the hive.
  226. Following fields in hive must already be filled in:
  227. Allocate, Free
  228. Will initialize Storage structure of HHIVE.
  229. Arguments:
  230. Hive - Pointer to hive control structure to build map for.
  231. Return Value:
  232. STATUS_SUCCESS - it worked
  233. STATUS_xxx - the errorneous status
  234. --*/
  235. {
  236. PHBASE_BLOCK BaseBlock;
  237. ULONG Length;
  238. ULONG MapSlots;
  239. ULONG Tables;
  240. PHMAP_TABLE t = NULL;
  241. PHMAP_DIRECTORY d = NULL;
  242. NTSTATUS Status;
  243. PULONG Vector = NULL;
  244. #ifndef _CM_LDR_
  245. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpInitMap:\n"));
  246. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p",Hive));
  247. #endif //_CM_LDR_
  248. //
  249. // Compute size of data region to be mapped
  250. //
  251. BaseBlock = Hive->BaseBlock;
  252. Length = BaseBlock->Length;
  253. if ((Length % HBLOCK_SIZE) != 0) {
  254. Status = STATUS_REGISTRY_CORRUPT;
  255. goto ErrorExit1;
  256. }
  257. MapSlots = Length / HBLOCK_SIZE;
  258. if( MapSlots > 0 ) {
  259. Tables = (MapSlots-1) / HTABLE_SLOTS;
  260. } else {
  261. Tables = 0;
  262. }
  263. Hive->Storage[Stable].Length = Length;
  264. //
  265. // allocate dirty vector if one is not already present (from HvpRecoverData)
  266. //
  267. if (Hive->DirtyVector.Buffer == NULL) {
  268. Vector = (PULONG)((Hive->Allocate)(ROUND_UP(Length/HSECTOR_SIZE/8,sizeof(ULONG)), TRUE,CM_FIND_LEAK_TAG27));
  269. if (Vector == NULL) {
  270. Status = STATUS_NO_MEMORY;
  271. goto ErrorExit1;
  272. }
  273. RtlZeroMemory(Vector, Length / HSECTOR_SIZE / 8);
  274. RtlInitializeBitMap(&Hive->DirtyVector, Vector, Length / HSECTOR_SIZE);
  275. Hive->DirtyAlloc = ROUND_UP(Length/HSECTOR_SIZE/8,sizeof(ULONG));
  276. }
  277. //
  278. // allocate and build structure for map
  279. //
  280. if (Tables == 0) {
  281. //
  282. // Just 1 table, no need for directory
  283. //
  284. t = (Hive->Allocate)(sizeof(HMAP_TABLE), FALSE,CM_FIND_LEAK_TAG26);
  285. if (t == NULL) {
  286. Status = STATUS_INSUFFICIENT_RESOURCES;
  287. goto ErrorExit1;
  288. }
  289. RtlZeroMemory(t, sizeof(HMAP_TABLE));
  290. Hive->Storage[Stable].Map =
  291. (PHMAP_DIRECTORY)&(Hive->Storage[Stable].SmallDir);
  292. Hive->Storage[Stable].SmallDir = t;
  293. } else {
  294. //
  295. // Need directory and multiple tables
  296. //
  297. d = (PHMAP_DIRECTORY)(Hive->Allocate)(sizeof(HMAP_DIRECTORY), FALSE,CM_FIND_LEAK_TAG28);
  298. if (d == NULL) {
  299. Status = STATUS_INSUFFICIENT_RESOURCES;
  300. goto ErrorExit1;
  301. }
  302. RtlZeroMemory(d, sizeof(HMAP_DIRECTORY));
  303. //
  304. // Allocate tables and fill in dir
  305. //
  306. if (HvpAllocateMap(Hive, d, 0, Tables) == FALSE) {
  307. Status = STATUS_INSUFFICIENT_RESOURCES;
  308. goto ErrorExit2;
  309. }
  310. Hive->Storage[Stable].Map = d;
  311. Hive->Storage[Stable].SmallDir = 0;
  312. }
  313. return STATUS_SUCCESS;
  314. ErrorExit2:
  315. if (d != NULL) {
  316. //
  317. // directory was built and allocated, so clean it up
  318. //
  319. HvpFreeMap(Hive, d, 0, Tables);
  320. (Hive->Free)(d, sizeof(HMAP_DIRECTORY));
  321. }
  322. ErrorExit1:
  323. if( Vector ) {
  324. (Hive->Free)(Vector, ROUND_UP(Length/HSECTOR_SIZE/8,sizeof(ULONG)));
  325. Hive->DirtyVector.Buffer = NULL;
  326. }
  327. return Status;
  328. }
  329. NTSTATUS
  330. HvpEnlistBinInMap(
  331. PHHIVE Hive,
  332. ULONG Length,
  333. PHBIN Bin,
  334. ULONG Offset,
  335. PVOID CmView OPTIONAL
  336. )
  337. /*++
  338. Routine Description:
  339. Creates map entries and enlist free cells for the specified bin
  340. Arguments:
  341. Hive - Pointer to hive control structure containing the target map
  342. Length - the Length of the hive image
  343. Bin - the bin to be enlisted
  344. Offset - the offset within the hive file
  345. CmView - pointer to the mapped view of the bin. If NULL, the bin resides in paged pool
  346. Return Value:
  347. STATUS_SUCCESS - it worked
  348. STATUS_REGISTRY_CORRUPT - the bin is inconsistent
  349. STATUS_REGISTRY_RECOVERED - if we have fixed the bin on-the-fly (self heal feature).
  350. --*/
  351. {
  352. NTSTATUS Status = STATUS_SUCCESS;
  353. ULONG BinOffset;
  354. ULONG_PTR Address;
  355. PHMAP_ENTRY Me;
  356. #ifndef _CM_LDR_
  357. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpEnlistBinInMap:\n"));
  358. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p\t Offset=%08lx",Hive,Offset));
  359. #endif //_CM_LDR_
  360. #ifndef _CM_LDR_
  361. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpEnlistBinInMap: BinAddress = 0x%p\t Size = 0x%lx\n", Bin, Bin->Size));
  362. #endif //_CM_LDR_
  363. //
  364. // create map entries for each block/page in bin
  365. //
  366. BinOffset = Offset;
  367. for (Address = (ULONG_PTR)Bin;
  368. Address < ((ULONG_PTR)Bin + Bin->Size);
  369. Address += HBLOCK_SIZE
  370. )
  371. {
  372. Me = HvpGetCellMap(Hive, Offset);
  373. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Offset);
  374. Me->BlockAddress = Address;
  375. Me->BinAddress = (ULONG_PTR)Bin;
  376. if (Offset == BinOffset) {
  377. Me->BinAddress |= HMAP_NEWALLOC;
  378. Me->MemAlloc = Bin->Size;
  379. } else {
  380. Me->MemAlloc = 0;
  381. }
  382. //
  383. // take care here !!!!!
  384. //
  385. if( CmView == NULL ) {
  386. Me->BinAddress |= HMAP_INPAGEDPOOL;
  387. // we don't need to set this - just for debug purposes
  388. ASSERT( (Me->CmView = NULL) == NULL );
  389. } else {
  390. Me->BinAddress |= HMAP_INVIEW;
  391. // this should be already set by now
  392. //ASSERT( Me->CmView == CmView );
  393. }
  394. Offset += HBLOCK_SIZE;
  395. }
  396. if (Hive->ReadOnly == FALSE) {
  397. //
  398. // add free cells in the bin to the apropriate free lists
  399. //
  400. if ( ! HvpEnlistFreeCells(Hive, Bin, BinOffset)) {
  401. HvCheckHiveDebug.Hive = Hive;
  402. HvCheckHiveDebug.Status = 0xA002;
  403. HvCheckHiveDebug.Space = Length;
  404. HvCheckHiveDebug.MapPoint = BinOffset;
  405. HvCheckHiveDebug.BinPoint = Bin;
  406. if( CmDoSelfHeal() ) {
  407. Status = STATUS_REGISTRY_RECOVERED;
  408. } else {
  409. Status = STATUS_REGISTRY_CORRUPT;
  410. goto ErrorExit;
  411. }
  412. }
  413. }
  414. //
  415. // logical consistency check
  416. //
  417. ASSERT(Offset == (BinOffset + Bin->Size));
  418. ErrorExit:
  419. return Status;
  420. }
  421. NTSTATUS
  422. HvpBuildMap(
  423. PHHIVE Hive,
  424. PVOID Image
  425. )
  426. /*++
  427. Routine Description:
  428. Creates the map for the Stable storage of the hive, and inits
  429. the map for the volatile storage.
  430. Following fields in hive must already be filled in:
  431. Allocate, Free
  432. Will initialize Storage structure of HHIVE.
  433. Arguments:
  434. Hive - Pointer to hive control structure to build map for.
  435. Image - pointer to in memory image of the hive
  436. Return Value:
  437. TRUE - it worked
  438. FALSE - either hive is corrupt or no memory for map
  439. --*/
  440. {
  441. PHBIN Bin;
  442. ULONG Offset;
  443. NTSTATUS Status;
  444. ULONG Length;
  445. #ifndef _CM_LDR_
  446. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpBuildMap:\n"));
  447. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p",Hive));
  448. #endif //_CM_LDR_
  449. //
  450. // Init the map
  451. //
  452. Status = HvpInitMap(Hive);
  453. if( !NT_SUCCESS(Status) ) {
  454. //
  455. // just return failure; HvpInitMap took care of cleanup
  456. //
  457. return Status;
  458. }
  459. //
  460. // Fill in the map
  461. //
  462. Offset = 0;
  463. Bin = (PHBIN)Image;
  464. Length = Hive->Storage[Stable].Length;
  465. while (Bin < (PHBIN)((PUCHAR)(Image) + Length)) {
  466. //
  467. // Check the validity of the bin header
  468. //
  469. if ( (Bin->Size > Length) ||
  470. (Bin->Size < HBLOCK_SIZE) ||
  471. (Bin->Signature != HBIN_SIGNATURE) ||
  472. (Bin->FileOffset != Offset)) {
  473. //
  474. // Bin is bogus
  475. //
  476. HvCheckHiveDebug.Hive = Hive;
  477. HvCheckHiveDebug.Status = 0xA001;
  478. HvCheckHiveDebug.Space = Length;
  479. HvCheckHiveDebug.MapPoint = Offset;
  480. HvCheckHiveDebug.BinPoint = Bin;
  481. //
  482. // for the loader.
  483. //
  484. if( CmDoSelfHeal() ) {
  485. //
  486. // put the correct signature, fileoffset and binsize in place;
  487. // HvEnlistBinInMap will take care of the cells consistency.
  488. //
  489. Bin->Signature = HBIN_SIGNATURE;
  490. Bin->FileOffset = Offset;
  491. if ( ((Offset + Bin->Size) > Length) ||
  492. (Bin->Size < HBLOCK_SIZE) ||
  493. (Bin->Size % HBLOCK_SIZE) ) {
  494. Bin->Size = HBLOCK_SIZE;
  495. }
  496. //
  497. // signal back to the caller that we have altered the hive.
  498. //
  499. CmMarkSelfHeal(Hive);
  500. } else {
  501. Status = STATUS_REGISTRY_CORRUPT;
  502. goto ErrorExit;
  503. }
  504. }
  505. //
  506. // enlist this bin
  507. //
  508. Status = HvpEnlistBinInMap(Hive, Length, Bin, Offset, NULL);
  509. //
  510. // for the loader.
  511. //
  512. if( CmDoSelfHeal() && (Status == STATUS_REGISTRY_RECOVERED) ) {
  513. CmMarkSelfHeal(Hive);
  514. Status = STATUS_SUCCESS;
  515. }
  516. if( !NT_SUCCESS(Status) ) {
  517. goto ErrorExit;
  518. }
  519. //
  520. // the next bin
  521. //
  522. Offset += Bin->Size;
  523. Bin = (PHBIN)((ULONG_PTR)Bin + Bin->Size);
  524. }
  525. return STATUS_SUCCESS;
  526. ErrorExit:
  527. //
  528. // Clean up the directory table
  529. //
  530. #ifndef _CM_LDR_
  531. HvpCleanMap( Hive );
  532. #endif //_CM_LDR_
  533. return Status;
  534. }
  535. BOOLEAN
  536. HvpEnlistFreeCells(
  537. PHHIVE Hive,
  538. PHBIN Bin,
  539. ULONG BinOffset
  540. )
  541. /*++
  542. Routine Description:
  543. Scan through the cells in the bin, locating the free ones.
  544. Enlist them in the hive's free list set.
  545. N.B. Bin MUST already be mapped when this is called.
  546. Arguments:
  547. Hive - pointer to hive control structure map is being built for
  548. Bin - pointer to bin to enlist cells from
  549. BinOffset - offset of Bin in image
  550. Return Value:
  551. FALSE - registry is corrupt
  552. TRUE - it worked
  553. --*/
  554. {
  555. PHCELL p;
  556. ULONG celloffset;
  557. ULONG size;
  558. HCELL_INDEX cellindex;
  559. BOOLEAN Result = TRUE;
  560. // PERFNOTE -- Keep this in mind as a possible optimization for NT6.
  561. // Since now the hive is loaded in chunks of bins, we can drop the
  562. // bins that are entirely free!!!!!!
  563. //
  564. //
  565. // Scan all the cells in the bin, total free and allocated, check
  566. // for impossible pointers.
  567. //
  568. celloffset = sizeof(HBIN);
  569. p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
  570. while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
  571. //
  572. // if free cell, check it out, add it to free list for hive
  573. //
  574. if (p->Size >= 0) {
  575. size = (ULONG)p->Size;
  576. if ( (size > Bin->Size) ||
  577. ( (PHCELL)(size + (PUCHAR)p) >
  578. (PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
  579. ((size % HCELL_PAD(Hive)) != 0) ||
  580. (size == 0) )
  581. {
  582. Result = FALSE;
  583. if( CmDoSelfHeal() ) {
  584. //
  585. // self heal mode; enlist the remaining of the bin as free
  586. // also zero it out so any references into the tampered area will be
  587. // detected and fixed by the logical check later on
  588. //
  589. p->Size = (LONG)((PUCHAR)((PUCHAR)Bin + Bin->Size) - (PUCHAR)p);
  590. RtlZeroMemory((PUCHAR)p + sizeof(ULONG),p->Size - sizeof(ULONG));
  591. size = (ULONG)p->Size;
  592. CmMarkSelfHeal(Hive);
  593. } else {
  594. goto Exit;
  595. }
  596. }
  597. //
  598. // cell is free, and is not obviously corrupt, add to free list
  599. //
  600. celloffset = (ULONG)((PUCHAR)p - (PUCHAR)Bin);
  601. cellindex = BinOffset + celloffset;
  602. //
  603. // Enlist this free cell, but do not coalesce with the next free cell
  604. // as we haven't gotten that far yet.
  605. //
  606. HvpEnlistFreeCell(Hive, cellindex, size, Stable, FALSE);
  607. } else {
  608. size = (ULONG)(p->Size * -1);
  609. if ( (size > Bin->Size) ||
  610. ( (PHCELL)(size + (PUCHAR)p) >
  611. (PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
  612. ((size % HCELL_PAD(Hive)) != 0) ||
  613. (size == 0) )
  614. {
  615. Result = FALSE;
  616. if( CmDoSelfHeal() ) {
  617. //
  618. // Self heal mode; we have no other way than to enlist this cell as a free cell
  619. //
  620. p->Size = (LONG)((PUCHAR)((PUCHAR)Bin + Bin->Size) - (PUCHAR)p);
  621. RtlZeroMemory((PUCHAR)p + sizeof(ULONG),p->Size - sizeof(ULONG));
  622. size = (ULONG)p->Size;
  623. celloffset = (ULONG)((PUCHAR)p - (PUCHAR)Bin);
  624. cellindex = BinOffset + celloffset;
  625. HvpEnlistFreeCell(Hive, cellindex, size, Stable, FALSE);
  626. CmMarkSelfHeal(Hive);
  627. } else {
  628. goto Exit;
  629. }
  630. }
  631. }
  632. ASSERT( ((LONG)size) >= 0);
  633. p = (PHCELL)((PUCHAR)p + size);
  634. }
  635. Exit:
  636. return Result;
  637. }
  638. VOID
  639. HvpCleanMap(
  640. PHHIVE Hive
  641. )
  642. /*++
  643. Routine Description:
  644. Cleans all the map allocations for the stable storage
  645. Arguments:
  646. Hive - Pointer to hive control structure to build map for.
  647. Return Value:
  648. None
  649. --*/
  650. {
  651. ULONG Length;
  652. ULONG MapSlots;
  653. ULONG Tables;
  654. PHMAP_DIRECTORY d = NULL;
  655. //
  656. // Compute MapSlots and Tables based on the Length
  657. //
  658. Length = Hive->Storage[Stable].Length;
  659. MapSlots = Length / HBLOCK_SIZE;
  660. if( MapSlots > 0 ) {
  661. Tables = (MapSlots-1) / HTABLE_SLOTS;
  662. } else {
  663. Tables = 0;
  664. }
  665. if( Hive->Storage[Stable].SmallDir == 0 ) {
  666. //
  667. // directory was built and allocated, so clean it up
  668. //
  669. d = Hive->Storage[Stable].Map;
  670. if( d != NULL ) {
  671. HvpFreeMap(Hive, d, 0, Tables);
  672. (Hive->Free)(d, sizeof(HMAP_DIRECTORY));
  673. }
  674. } else {
  675. //
  676. // no directory, just a smalldir
  677. //
  678. (Hive->Free)(Hive->Storage[Stable].SmallDir, sizeof(HMAP_TABLE));
  679. }
  680. Hive->Storage[Stable].SmallDir = NULL;
  681. Hive->Storage[Stable].Map = NULL;
  682. }
  683. VOID
  684. HvpFreeMap(
  685. PHHIVE Hive,
  686. PHMAP_DIRECTORY Dir,
  687. ULONG Start,
  688. ULONG End
  689. )
  690. /*++
  691. Routine Description:
  692. Sweeps through the directory Dir points to and frees Tables.
  693. Will free Start-th through End-th entries, INCLUSIVE.
  694. Arguments:
  695. Hive - supplies pointer to hive control block of interest
  696. Dir - supplies address of an HMAP_DIRECTORY structure
  697. Start - index of first map table pointer to clean up
  698. End - index of last map table pointer to clean up
  699. Return Value:
  700. NONE.
  701. --*/
  702. {
  703. ULONG i;
  704. if (End >= HDIRECTORY_SLOTS) {
  705. End = HDIRECTORY_SLOTS - 1;
  706. }
  707. for (i = Start; i <= End; i++) {
  708. if (Dir->Directory[i] != NULL) {
  709. (Hive->Free)(Dir->Directory[i], sizeof(HMAP_TABLE));
  710. Dir->Directory[i] = NULL;
  711. }
  712. }
  713. return;
  714. }
  715. BOOLEAN
  716. HvpAllocateMap(
  717. PHHIVE Hive,
  718. PHMAP_DIRECTORY Dir,
  719. ULONG Start,
  720. ULONG End
  721. )
  722. /*++
  723. Routine Description:
  724. Sweeps through the directory Dir points to and allocates Tables.
  725. Will allocate Start-th through End-th entries, INCLUSIVE.
  726. Does NOT clean up when out of memory, call HvpFreeMap to do that.
  727. Arguments:
  728. Hive - supplies pointer to hive control block of interest
  729. Dir - supplies address of an HMAP_DIRECTORY structure
  730. Start - index of first map table pointer to allocate for
  731. End - index of last map table pointer to allocate for
  732. Return Value:
  733. TRUE - it worked
  734. FALSE - insufficient memory
  735. --*/
  736. {
  737. ULONG i,j;
  738. PHMAP_TABLE t;
  739. for (i = Start; i <= End; i++) {
  740. ASSERT(Dir->Directory[i] == NULL);
  741. t = (PHMAP_TABLE)((Hive->Allocate)(sizeof(HMAP_TABLE), FALSE,CM_FIND_LEAK_TAG29));
  742. if (t == NULL) {
  743. return FALSE;
  744. }
  745. // the zero memory stuff can be removed
  746. RtlZeroMemory(t, sizeof(HMAP_TABLE));
  747. for(j=0;j<HTABLE_SLOTS;j++) {
  748. //
  749. // Invalidate the entry
  750. //
  751. //
  752. // ATTENTION : I don't really think we need this !!! <TBD>
  753. //
  754. t->Table[j].BinAddress = 0;
  755. // we don't need to set this - just for debug purposes
  756. ASSERT( (t->Table[j].CmView = NULL) == NULL );
  757. }
  758. Dir->Directory[i] = t;
  759. }
  760. return TRUE;
  761. }
  762. ULONG
  763. HvpGetBinMemAlloc(
  764. IN PHHIVE Hive,
  765. PHBIN Bin,
  766. IN HSTORAGE_TYPE Type
  767. )
  768. /*++
  769. Routine Description:
  770. Returns the bin MemAlloc (formelly kept right in the bin) by looking at
  771. the map. We need this to avoid touching the bins only to set their MemAlloc.
  772. Arguments:
  773. Hive - supplies a pointer to the hive control structure for the
  774. hive of interest
  775. Bin - The bin in question
  776. Type - Stable or Volatile
  777. Return Value:
  778. Pointer to the new BIN if we succeeded, NULL if we failed.
  779. --*/
  780. {
  781. PHMAP_ENTRY Map;
  782. HCELL_INDEX Cell;
  783. #if DBG
  784. ULONG i;
  785. PHMAP_ENTRY Me;
  786. #endif
  787. #ifndef _CM_LDR_
  788. PAGED_CODE();
  789. #endif //_CM_LDR_
  790. ASSERT( Bin->Signature == HBIN_SIGNATURE );
  791. Cell = Bin->FileOffset + (Type * HCELL_TYPE_MASK);
  792. Map = HvpGetCellMap(Hive, Cell);
  793. VALIDATE_CELL_MAP(__LINE__,Map,Hive,Cell);
  794. #if DBG
  795. //
  796. // some validation code
  797. //
  798. for( i=0;i<Bin->Size;i+=HBLOCK_SIZE) {
  799. Cell = Bin->FileOffset + i + (Type * HCELL_TYPE_MASK);
  800. Me = HvpGetCellMap(Hive, Cell);
  801. VALIDATE_CELL_MAP(__LINE__,Me,Hive,Cell);
  802. if( i == 0 ) {
  803. ASSERT( Me->MemAlloc != 0 );
  804. } else {
  805. ASSERT( Me->MemAlloc == 0 );
  806. }
  807. }
  808. #endif
  809. return Map->MemAlloc;
  810. }