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.

2699 lines
76 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. cmsavres.c
  5. Abstract:
  6. This file contains code for SaveKey and RestoreKey.
  7. Author:
  8. Bryan M. Willman (bryanwi) 15-Jan-92
  9. Revision History:
  10. --*/
  11. #include "cmp.h"
  12. //
  13. // defines how big the buffer we use for doing a savekey by copying the
  14. // hive file should be.
  15. //
  16. #define CM_SAVEKEYBUFSIZE 0x10000
  17. extern PCMHIVE CmpMasterHive;
  18. extern BOOLEAN CmpProfileLoaded;
  19. extern PUCHAR CmpStashBuffer;
  20. extern ULONG CmpGlobalQuotaAllowed;
  21. extern ULONG CmpGlobalQuotaWarning;
  22. extern ULONG CmpGlobalQuotaUsed;
  23. extern BOOLEAN HvShutdownComplete; // Set to true after shutdown
  24. // to disable any further I/O
  25. PCMHIVE
  26. CmpCreateTemporaryHive(
  27. IN HANDLE FileHandle
  28. );
  29. VOID
  30. CmpDestroyTemporaryHive(
  31. PCMHIVE CmHive
  32. );
  33. NTSTATUS
  34. CmpLoadHiveVolatile(
  35. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  36. IN HANDLE FileHandle
  37. );
  38. NTSTATUS
  39. CmpRefreshHive(
  40. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock
  41. );
  42. NTSTATUS
  43. CmpSaveKeyByFileCopy(
  44. PCMHIVE Hive,
  45. HANDLE FileHandle
  46. );
  47. ULONG
  48. CmpRefreshWorkerRoutine(
  49. PCM_KEY_CONTROL_BLOCK Current,
  50. PVOID Context1,
  51. PVOID Context2
  52. );
  53. BOOLEAN
  54. CmpMergeKeyValues(
  55. PHHIVE SourceHive,
  56. HCELL_INDEX SourceKeyCell,
  57. PCM_KEY_NODE SourceKeyNode,
  58. PHHIVE TargetHive,
  59. HCELL_INDEX TargetKeyCell,
  60. PCM_KEY_NODE TargetKeyNode
  61. );
  62. VOID
  63. CmpShiftSecurityCells(PHHIVE Hive);
  64. VOID
  65. CmpShiftValueList(PHHIVE Hive,
  66. HCELL_INDEX ValueList,
  67. ULONG Count
  68. );
  69. VOID
  70. CmpShiftKey(PHHIVE Hive,
  71. PCMHIVE OldHive,
  72. HCELL_INDEX Cell,
  73. HCELL_INDEX ParentCell
  74. );
  75. VOID
  76. CmpShiftIndex(PHHIVE Hive,
  77. PCM_KEY_INDEX Index
  78. );
  79. BOOLEAN
  80. CmpShiftAllCells2( PHHIVE Hive,
  81. PCMHIVE OldHive,
  82. HCELL_INDEX Cell,
  83. HCELL_INDEX ParentCell
  84. );
  85. BOOLEAN
  86. CmpShiftAllCells(PHHIVE NewHive,
  87. PCMHIVE OldHive
  88. );
  89. #ifdef ALLOC_PRAGMA
  90. #pragma alloc_text(PAGE,CmRestoreKey)
  91. #pragma alloc_text(PAGE,CmpLoadHiveVolatile)
  92. #pragma alloc_text(PAGE,CmpRefreshHive)
  93. #pragma alloc_text(PAGE,CmSaveKey)
  94. #pragma alloc_text(PAGE,CmDumpKey)
  95. #pragma alloc_text(PAGE,CmSaveMergedKeys)
  96. #pragma alloc_text(PAGE,CmpCreateTemporaryHive)
  97. #pragma alloc_text(PAGE,CmpDestroyTemporaryHive)
  98. #pragma alloc_text(PAGE,CmpRefreshWorkerRoutine)
  99. #pragma alloc_text(PAGE,CmpSaveKeyByFileCopy)
  100. #pragma alloc_text(PAGE,CmpOverwriteHive)
  101. #pragma alloc_text(PAGE,CmpShiftHiveFreeBins)
  102. #pragma alloc_text(PAGE,CmpSwitchStorageAndRebuildMappings)
  103. #pragma alloc_text(PAGE,CmpShiftSecurityCells)
  104. #pragma alloc_text(PAGE,CmpShiftValueList)
  105. #pragma alloc_text(PAGE,CmpShiftKey)
  106. #pragma alloc_text(PAGE,CmpShiftIndex)
  107. #pragma alloc_text(PAGE,CmpShiftAllCells2)
  108. #pragma alloc_text(PAGE,CmpShiftAllCells)
  109. #endif
  110. NTSTATUS
  111. CmRestoreKey(
  112. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  113. IN HANDLE FileHandle,
  114. IN ULONG Flags
  115. )
  116. /*++
  117. Routine Description:
  118. This copies the data from an on-disk hive into the registry. The file
  119. is not loaded into the registry, and the system will NOT be using
  120. the source file after the call returns.
  121. If the flag REG_WHOLE_HIVE_VOLATILE is not set, the given key is replaced
  122. by the root of the hive file. The root's name is changed to the name
  123. of the given key.
  124. If the flag REG_WHOLE_HIVE_VOLATILE is set, a volatile hive is created,
  125. the hive file is copied into it, and the resulting hive is linked to
  126. the master hive. The given key must be in the master hive. (Usually
  127. will be \Registry\User)
  128. If the flag REG_REFRESH_HIVE is set (must be only flag) then the
  129. the Hive will be restored to its state as of the last flush.
  130. (The hive must be marked NOLAZY_FLUSH, and the caller must have
  131. TCB privilege, and the handle must point to the root of the hive.
  132. If the refresh fails, the hive will be corrupt, and the system
  133. will bugcheck.)
  134. If the flag REG_FORCE_RESTORE is set, the restore operation is done even
  135. if there areopen handles underneath the key we are restoring to.
  136. Arguments:
  137. Hive - supplies a pointer to the hive control structure for the hive
  138. Cell - supplies index of node at root of tree to restore into
  139. FileHandle - handle of the file to read from.
  140. Return Value:
  141. NTSTATUS - Result code from call, among the following:
  142. <TBS>
  143. --*/
  144. {
  145. NTSTATUS status;
  146. PCELL_DATA ptar;
  147. PCELL_DATA psrc;
  148. PCMHIVE TmpCmHive;
  149. HCELL_INDEX newroot;
  150. HCELL_INDEX newcell;
  151. HCELL_INDEX parent;
  152. HCELL_INDEX list;
  153. ULONG count;
  154. ULONG i;
  155. ULONG j;
  156. LONG size;
  157. PHHIVE Hive;
  158. HCELL_INDEX Cell;
  159. HSTORAGE_TYPE Type;
  160. ULONG NumberLeaves;
  161. PHCELL_INDEX LeafArray;
  162. PCM_KEY_INDEX Leaf;
  163. PCM_KEY_FAST_INDEX FastLeaf;
  164. PRELEASE_CELL_ROUTINE SourceReleaseCellRoutine;
  165. PRELEASE_CELL_ROUTINE TargetReleaseCellRoutine;
  166. PAGED_CODE();
  167. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"CmRestoreKey:\n"));
  168. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tKCB=%p\n",KeyControlBlock));
  169. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tFileHandle=%08lx\n",FileHandle));
  170. if (Flags & REG_REFRESH_HIVE) {
  171. if ((Flags & ~REG_REFRESH_HIVE) != 0) {
  172. //
  173. // Refresh must be alone
  174. //
  175. return STATUS_INVALID_PARAMETER;
  176. }
  177. }
  178. //
  179. // If they want to do WHOLE_HIVE_VOLATILE, it's a completely different API.
  180. //
  181. if (Flags & REG_WHOLE_HIVE_VOLATILE) {
  182. return(CmpLoadHiveVolatile(KeyControlBlock, FileHandle));
  183. }
  184. //
  185. // If they want to do REFRESH_HIVE, that's a completely different api too.
  186. //
  187. if (Flags & REG_REFRESH_HIVE) {
  188. CmpLockRegistryExclusive();
  189. status = CmpRefreshHive(KeyControlBlock);
  190. CmpUnlockRegistry();
  191. return status;
  192. }
  193. Hive = KeyControlBlock->KeyHive;
  194. Cell = KeyControlBlock->KeyCell;
  195. //
  196. // Disallow attempts to "restore" the master hive
  197. //
  198. if (Hive == &CmpMasterHive->Hive) {
  199. return STATUS_ACCESS_DENIED;
  200. }
  201. CmpLockRegistryExclusive();
  202. #ifdef CHECK_REGISTRY_USECOUNT
  203. CmpCheckRegistryUseCount();
  204. #endif //CHECK_REGISTRY_USECOUNT
  205. //
  206. // Make sure this key has not been deleted
  207. //
  208. if (KeyControlBlock->Delete) {
  209. CmpUnlockRegistry();
  210. return(STATUS_CANNOT_DELETE);
  211. }
  212. #ifdef NT_UNLOAD_KEY_EX
  213. if( IsHiveFrozen(((PCMHIVE)Hive)) ) {
  214. //
  215. // deny attempts to clobber with a frozen hive
  216. //
  217. CmpUnlockRegistry();
  218. return STATUS_TOO_LATE;
  219. }
  220. #endif //NT_UNLOAD_KEY_EX
  221. DCmCheckRegistry(CONTAINING_RECORD(Hive, CMHIVE, Hive));
  222. //
  223. // Check for any open handles underneath the key we are restoring to.
  224. //
  225. if (CmpSearchForOpenSubKeys(KeyControlBlock,(Flags&REG_FORCE_RESTORE)?SearchAndDeref:SearchIfExist) != 0) {
  226. //
  227. // Cannot restore over a subtree with open handles in it, or the open handles to subkeys
  228. // successfully marked as closed.
  229. //
  230. CmpUnlockRegistry();
  231. return(STATUS_CANNOT_DELETE);
  232. }
  233. //
  234. // Make sure this is the only handle open for this key
  235. //
  236. if (KeyControlBlock->RefCount != 1 && !(Flags&REG_FORCE_RESTORE)) {
  237. CmpUnlockRegistry();
  238. return(STATUS_CANNOT_DELETE);
  239. }
  240. ptar = HvGetCell(Hive, Cell);
  241. if( ptar == NULL ) {
  242. //
  243. // we couldn't map the bin containing this cell
  244. //
  245. CmpUnlockRegistry();
  246. return STATUS_INSUFFICIENT_RESOURCES;
  247. }
  248. // release the cell right here as we are holding the reglock exclusive
  249. HvReleaseCell(Hive,Cell);
  250. //
  251. // The subtree the caller wants does not exactly match a
  252. // subtree. Make a temporary hive, load the file into it,
  253. // tree copy the temporary to the active, and free the temporary.
  254. //
  255. //
  256. // Create the temporary hive
  257. //
  258. status = CmpInitializeHive(&TmpCmHive,
  259. HINIT_FILE,
  260. 0,
  261. HFILE_TYPE_PRIMARY,
  262. NULL,
  263. FileHandle,
  264. NULL,
  265. NULL,
  266. NULL,
  267. CM_CHECK_REGISTRY_CHECK_CLEAN
  268. );
  269. if (!NT_SUCCESS(status)) {
  270. goto ErrorExit1;
  271. }
  272. //
  273. // Create a new target root, under which we will copy the new tree
  274. //
  275. if (ptar->u.KeyNode.Flags & KEY_HIVE_ENTRY) {
  276. parent = HCELL_NIL; // root of hive, so parent is NIL
  277. } else {
  278. parent = ptar->u.KeyNode.Parent;
  279. }
  280. SourceReleaseCellRoutine = TmpCmHive->Hive.ReleaseCellRoutine;
  281. TargetReleaseCellRoutine = Hive->ReleaseCellRoutine;
  282. TmpCmHive->Hive.ReleaseCellRoutine = NULL;
  283. Hive->ReleaseCellRoutine = NULL;
  284. newroot = CmpCopyKeyPartial(&(TmpCmHive->Hive),
  285. TmpCmHive->Hive.BaseBlock->RootCell,
  286. Hive,
  287. parent,
  288. TRUE);
  289. TmpCmHive->Hive.ReleaseCellRoutine = SourceReleaseCellRoutine;
  290. Hive->ReleaseCellRoutine = TargetReleaseCellRoutine;
  291. if (newroot == HCELL_NIL) {
  292. status = STATUS_INSUFFICIENT_RESOURCES;
  293. goto ErrorExit2;
  294. }
  295. //
  296. // newroot has all the correct stuff, except that it has the
  297. // source root's name, when it needs to have the target root's.
  298. // So edit its name.
  299. //
  300. psrc = HvGetCell(Hive, Cell);
  301. if( psrc == NULL ) {
  302. //
  303. // we couldn't map the bin containing this cell
  304. //
  305. status = STATUS_INSUFFICIENT_RESOURCES;
  306. goto ErrorExit2;
  307. }
  308. // release the cell right here as we are holding the reglock exclusive
  309. HvReleaseCell(Hive,Cell);
  310. ptar = HvGetCell(Hive, newroot);
  311. if( ptar == NULL ) {
  312. //
  313. // we couldn't map the bin containing this cell
  314. //
  315. status = STATUS_INSUFFICIENT_RESOURCES;
  316. goto ErrorExit2;
  317. }
  318. size = FIELD_OFFSET(CM_KEY_NODE, Name) + psrc->u.KeyNode.NameLength;
  319. // release the cell right here as we are holding the reglock exclusive
  320. HvReleaseCell(Hive,newroot);
  321. //
  322. // make sure that new root has correct amount of space
  323. // to hold name from old root
  324. //
  325. newcell = HvReallocateCell(Hive, newroot, size);
  326. if (newcell == HCELL_NIL) {
  327. status = STATUS_INSUFFICIENT_RESOURCES;
  328. goto ErrorExit2;
  329. }
  330. newroot = newcell;
  331. ptar = HvGetCell(Hive, newroot);
  332. if( ptar == NULL ) {
  333. //
  334. // we couldn't map the bin containing this cell
  335. // this shouldn't happen, as we just allocated this cell
  336. // (i.e. it should be PINNED in memory at this point)
  337. //
  338. ASSERT( FALSE );
  339. status = STATUS_INSUFFICIENT_RESOURCES;
  340. goto ErrorExit2;
  341. }
  342. // release the cell right here as we are holding the reglock exclusive
  343. HvReleaseCell(Hive,newroot);
  344. status = STATUS_SUCCESS;
  345. RtlCopyMemory((PVOID)&(ptar->u.KeyNode.Name[0]),
  346. (PVOID)&(psrc->u.KeyNode.Name[0]),
  347. psrc->u.KeyNode.NameLength);
  348. ptar->u.KeyNode.NameLength = psrc->u.KeyNode.NameLength;
  349. if (psrc->u.KeyNode.Flags & KEY_COMP_NAME) {
  350. ptar->u.KeyNode.Flags |= KEY_COMP_NAME;
  351. } else {
  352. ptar->u.KeyNode.Flags &= ~KEY_COMP_NAME;
  353. }
  354. //
  355. // newroot is now ready to have subtree copied under it, do tree copy
  356. //
  357. if (CmpCopyTree(&(TmpCmHive->Hive),
  358. TmpCmHive->Hive.BaseBlock->RootCell,
  359. Hive,
  360. newroot) == FALSE)
  361. {
  362. status = STATUS_INSUFFICIENT_RESOURCES;
  363. goto ErrorExit2;
  364. }
  365. //
  366. // The new root and the tree under it now look the way we want.
  367. //
  368. //
  369. // Swap the new tree in for the old one.
  370. //
  371. ptar = HvGetCell(Hive, Cell);
  372. if( ptar == NULL ) {
  373. //
  374. // we couldn't map the bin containing this cell
  375. //
  376. status = STATUS_INSUFFICIENT_RESOURCES;
  377. goto ErrorExit2;
  378. }
  379. parent = ptar->u.KeyNode.Parent;
  380. // release the cell right here as we are holding the reglock exclusive
  381. HvReleaseCell(Hive,Cell);
  382. if (ptar->u.KeyNode.Flags & KEY_HIVE_ENTRY) {
  383. //
  384. // root is actually the root of the hive. parent doesn't
  385. // refer to it via a child list, but rather with an inter hive
  386. // pointer. also, must update base block
  387. //
  388. ptar = HvGetCell( (&(CmpMasterHive->Hive)), parent);
  389. if( ptar == NULL ) {
  390. //
  391. // we couldn't map the bin containing this cell
  392. //
  393. status = STATUS_INSUFFICIENT_RESOURCES;
  394. goto ErrorExit2;
  395. }
  396. // release the cell right here as we are holding the reglock exclusive
  397. HvReleaseCell((&(CmpMasterHive->Hive)), parent);
  398. ptar->u.KeyNode.ChildHiveReference.KeyCell = newroot;
  399. ptar = HvGetCell(Hive, newroot);
  400. if( ptar == NULL ) {
  401. //
  402. // we couldn't map the bin containing this cell
  403. // this shouldn't happen, as we just allocated this cell
  404. // (i.e. it should be PINNED in memory at this point)
  405. //
  406. ASSERT( FALSE );
  407. status = STATUS_INSUFFICIENT_RESOURCES;
  408. goto ErrorExit2;
  409. }
  410. // release the cell right here as we are holding the reglock exclusive
  411. HvReleaseCell(Hive, newroot);
  412. ptar->u.KeyNode.Parent = parent;
  413. Hive->BaseBlock->RootCell = newroot;
  414. } else {
  415. //
  416. // Notice that new root is *always* name of existing target,
  417. // therefore, even in b-tree, old and new cell can share
  418. // the same reference slot in the parent. So simply edit
  419. // the new cell_index on the top of the old.
  420. //
  421. ptar = HvGetCell(Hive, parent);
  422. if( ptar == NULL ) {
  423. //
  424. // we couldn't map the bin containing this cell
  425. //
  426. status = STATUS_INSUFFICIENT_RESOURCES;
  427. goto ErrorExit2;
  428. }
  429. // release the cell right here as we are holding the reglock exclusive
  430. HvReleaseCell(Hive, parent);
  431. Type = HvGetCellType(Cell);
  432. list = ptar->u.KeyNode.SubKeyLists[Type];
  433. count = ptar->u.KeyNode.SubKeyCounts[Type];
  434. ptar = HvGetCell(Hive, list);
  435. if( ptar == NULL ) {
  436. //
  437. // we couldn't map the bin containing this cell
  438. //
  439. status = STATUS_INSUFFICIENT_RESOURCES;
  440. goto ErrorExit2;
  441. }
  442. // release the cell right here as we are holding the reglock exclusive
  443. HvReleaseCell(Hive, list);
  444. if (ptar->u.KeyIndex.Signature == CM_KEY_INDEX_ROOT) {
  445. NumberLeaves = ptar->u.KeyIndex.Count;
  446. LeafArray = &ptar->u.KeyIndex.List[0];
  447. } else {
  448. NumberLeaves = 1;
  449. LeafArray = &list;
  450. }
  451. //
  452. // Look in each leaf for the HCELL_INDEX we need to replace
  453. //
  454. for (i = 0; i < NumberLeaves; i++) {
  455. Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafArray[i]);
  456. if( Leaf == NULL ) {
  457. //
  458. // we couldn't map the bin containing this cell
  459. //
  460. status = STATUS_INSUFFICIENT_RESOURCES;
  461. goto ErrorExit2;
  462. }
  463. // release the cell right here as we are holding the reglock exclusive
  464. HvReleaseCell(Hive, LeafArray[i]);
  465. if( !HvMarkCellDirty(Hive, LeafArray[i]) ) {
  466. status = STATUS_NO_LOG_SPACE;
  467. goto ErrorExit2;
  468. }
  469. if ( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
  470. (Leaf->Signature == CM_KEY_HASH_LEAF) ) {
  471. FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
  472. for (j=0; j < FastLeaf->Count; j++) {
  473. if (FastLeaf->List[j].Cell == Cell) {
  474. FastLeaf->List[j].Cell = newroot;
  475. goto FoundCell;
  476. }
  477. }
  478. } else {
  479. for (j=0; j < Leaf->Count; j++) {
  480. if (Leaf->List[j] == Cell) {
  481. Leaf->List[j] = newroot;
  482. goto FoundCell;
  483. }
  484. }
  485. }
  486. }
  487. ASSERT(FALSE); // implies we didn't find it
  488. // we should never get here
  489. }
  490. FoundCell:
  491. //
  492. // Fix up the key control block to point to the new root
  493. //
  494. KeyControlBlock->KeyCell = newroot;
  495. //
  496. // Kcb has changed, update the cache information.
  497. // Registry locked exclusively, no need for KCB lock.
  498. //
  499. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  500. CmpCleanUpKcbValueCache(KeyControlBlock);
  501. {
  502. PCM_KEY_NODE Node = (PCM_KEY_NODE)HvGetCell(KeyControlBlock->KeyHive,KeyControlBlock->KeyCell);
  503. if( Node == NULL ) {
  504. //
  505. // we couldn't map the bin containing this cell
  506. //
  507. status = STATUS_INSUFFICIENT_RESOURCES;
  508. goto ErrorExit2;
  509. }
  510. // release the cell right here as we are holding the reglock exclusive
  511. HvReleaseCell(KeyControlBlock->KeyHive,KeyControlBlock->KeyCell);
  512. CmpSetUpKcbValueCache(KeyControlBlock,Node->ValueList.Count,Node->ValueList.List);
  513. KeyControlBlock->Flags = Node->Flags;
  514. CmpAssignSecurityToKcb(KeyControlBlock,Node->Security);
  515. //
  516. // we need to update the other kcb cache members too!!!
  517. //
  518. CmpCleanUpSubKeyInfo (KeyControlBlock);
  519. KeyControlBlock->KcbLastWriteTime = Node->LastWriteTime;
  520. KeyControlBlock->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
  521. KeyControlBlock->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
  522. KeyControlBlock->KcbMaxValueDataLen = Node->MaxValueDataLen;
  523. }
  524. KeyControlBlock->ExtFlags = 0;
  525. // mark the cached info as not valid
  526. KeyControlBlock->ExtFlags |= CM_KCB_INVALID_CACHED_INFO;
  527. //
  528. // Delete the old subtree and it's root cell
  529. //
  530. CmpDeleteTree(Hive, Cell);
  531. CmpFreeKeyByCell(Hive, Cell, FALSE);
  532. //
  533. // Report the notify event
  534. //
  535. CmpReportNotify(KeyControlBlock,
  536. KeyControlBlock->KeyHive,
  537. KeyControlBlock->KeyCell,
  538. REG_NOTIFY_CHANGE_NAME);
  539. //
  540. // Free the temporary hive
  541. //
  542. CmpDestroyTemporaryHive(TmpCmHive);
  543. //
  544. // We've given user chance to log on, so turn on quota
  545. //
  546. if (CmpProfileLoaded == FALSE) {
  547. CmpProfileLoaded = TRUE;
  548. CmpSetGlobalQuotaAllowed();
  549. }
  550. DCmCheckRegistry(CONTAINING_RECORD(Hive, CMHIVE, Hive));
  551. CmpUnlockRegistry();
  552. return status;
  553. //
  554. // Error exits
  555. //
  556. ErrorExit2:
  557. CmpDestroyTemporaryHive(TmpCmHive);
  558. ErrorExit1:
  559. DCmCheckRegistry(CONTAINING_RECORD(Hive, CMHIVE, Hive));
  560. CmpUnlockRegistry();
  561. return status;
  562. }
  563. NTSTATUS
  564. CmpLoadHiveVolatile(
  565. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  566. IN HANDLE FileHandle
  567. )
  568. /*++
  569. Routine Description:
  570. Creates a VOLATILE hive and loads it underneath the given Hive and Cell.
  571. The data for the volatile hive is copied out of the given file. The
  572. file is *NOT* in use by the registry when this returns.
  573. Arguments:
  574. Hive - Supplies the hive that the new hive is to be created under.
  575. Currently this must be the Master Hive.
  576. Cell - Supplies the HCELL_INDEX of the new hive's parent. (Usually
  577. will by \Registry\User)
  578. FileHandle - Supplies a handle to the hive file that will be copied
  579. into the volatile hive.
  580. Return Value:
  581. NTSTATUS
  582. --*/
  583. {
  584. NTSTATUS status;
  585. PHHIVE Hive;
  586. PCELL_DATA RootData;
  587. PCMHIVE NewHive;
  588. PCMHIVE TempHive;
  589. HCELL_INDEX Cell;
  590. HCELL_INDEX Root;
  591. NTSTATUS Status;
  592. UNICODE_STRING RootName;
  593. UNICODE_STRING NewName;
  594. USHORT NewNameLength;
  595. PUNICODE_STRING ConstructedName;
  596. PRELEASE_CELL_ROUTINE SourceReleaseCellRoutine;
  597. PRELEASE_CELL_ROUTINE TargetReleaseCellRoutine;
  598. PAGED_CODE();
  599. CmpLockRegistryExclusive();
  600. if (KeyControlBlock->Delete) {
  601. CmpUnlockRegistry();
  602. return(STATUS_KEY_DELETED);
  603. }
  604. Hive = KeyControlBlock->KeyHive;
  605. Cell = KeyControlBlock->KeyCell;
  606. #ifdef NT_UNLOAD_KEY_EX
  607. if( IsHiveFrozen(((PCMHIVE)Hive)) ) {
  608. //
  609. // deny attempts to clobber with a frozen hive
  610. //
  611. CmpUnlockRegistry();
  612. return STATUS_TOO_LATE;
  613. }
  614. #endif //NT_UNLOAD_KEY_EX
  615. //
  616. // New hives can be created only under the master hive.
  617. //
  618. if (Hive != &CmpMasterHive->Hive) {
  619. CmpUnlockRegistry();
  620. return(STATUS_INVALID_PARAMETER);
  621. }
  622. //
  623. // Create a temporary hive and load the file into it
  624. //
  625. status = CmpInitializeHive(&TempHive,
  626. HINIT_FILE,
  627. 0,
  628. HFILE_TYPE_PRIMARY,
  629. NULL,
  630. FileHandle,
  631. NULL,
  632. NULL,
  633. NULL,
  634. CM_CHECK_REGISTRY_CHECK_CLEAN);
  635. if (!NT_SUCCESS(status)) {
  636. CmpUnlockRegistry();
  637. return(status);
  638. }
  639. //
  640. // Create the volatile hive.
  641. //
  642. status = CmpInitializeHive(&NewHive,
  643. HINIT_CREATE,
  644. HIVE_VOLATILE,
  645. 0,
  646. NULL,
  647. NULL,
  648. NULL,
  649. NULL,
  650. NULL,
  651. 0);
  652. if (!NT_SUCCESS(status)) {
  653. CmpDestroyTemporaryHive(TempHive);
  654. CmpUnlockRegistry();
  655. return(status);
  656. }
  657. //
  658. // Create the target root
  659. //
  660. SourceReleaseCellRoutine = TempHive->Hive.ReleaseCellRoutine;
  661. TargetReleaseCellRoutine = NewHive->Hive.ReleaseCellRoutine;
  662. TempHive->Hive.ReleaseCellRoutine = NULL;
  663. NewHive->Hive.ReleaseCellRoutine = NULL;
  664. Root = CmpCopyKeyPartial(&TempHive->Hive,
  665. TempHive->Hive.BaseBlock->RootCell,
  666. &NewHive->Hive,
  667. HCELL_NIL,
  668. FALSE);
  669. TempHive->Hive.ReleaseCellRoutine = SourceReleaseCellRoutine;
  670. NewHive->Hive.ReleaseCellRoutine = TargetReleaseCellRoutine;
  671. if (Root == HCELL_NIL) {
  672. CmpDestroyTemporaryHive(TempHive);
  673. CmpDestroyTemporaryHive(NewHive);
  674. CmpUnlockRegistry();
  675. return(STATUS_INSUFFICIENT_RESOURCES);
  676. }
  677. NewHive->Hive.BaseBlock->RootCell = Root;
  678. //
  679. // Copy the temporary hive into the volatile hive
  680. //
  681. if (!CmpCopyTree(&TempHive->Hive,
  682. TempHive->Hive.BaseBlock->RootCell,
  683. &NewHive->Hive,
  684. Root))
  685. {
  686. CmpDestroyTemporaryHive(TempHive);
  687. CmpDestroyTemporaryHive(NewHive);
  688. CmpUnlockRegistry();
  689. return(STATUS_INSUFFICIENT_RESOURCES);
  690. }
  691. //
  692. // The volatile hive now has all the right stuff in all the right places,
  693. // we just need to link it into the master hive.
  694. //
  695. RootData = HvGetCell(&NewHive->Hive,Root);
  696. if( RootData == NULL ) {
  697. //
  698. // we couldn't map the bin containing this cell
  699. // this shouldn't happen, as we just allocated this cell
  700. // (i.e. it should be PINNED in memory at this point)
  701. //
  702. ASSERT( FALSE );
  703. CmpDestroyTemporaryHive(TempHive);
  704. CmpDestroyTemporaryHive(NewHive);
  705. CmpUnlockRegistry();
  706. return(STATUS_INSUFFICIENT_RESOURCES);
  707. }
  708. // release the cell right here as we are holding the reglock exclusive
  709. HvReleaseCell(&NewHive->Hive,Root);
  710. ConstructedName = CmpConstructName(KeyControlBlock);
  711. NewNameLength = ConstructedName->Length +
  712. CmpHKeyNameLen(&RootData->u.KeyNode) +
  713. sizeof(WCHAR);
  714. NewName.Buffer = ExAllocatePool(PagedPool, NewNameLength);
  715. if (NewName.Buffer == NULL) {
  716. CmpDestroyTemporaryHive(TempHive);
  717. CmpDestroyTemporaryHive(NewHive);
  718. CmpUnlockRegistry();
  719. ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
  720. return(STATUS_INSUFFICIENT_RESOURCES);
  721. }
  722. NewName.Length = NewName.MaximumLength = NewNameLength;
  723. RtlCopyUnicodeString(&NewName, ConstructedName);
  724. ExFreePoolWithTag(ConstructedName, CM_NAME_TAG | PROTECTED_POOL);
  725. RtlAppendUnicodeToString(&NewName, L"\\");
  726. if (RootData->u.KeyNode.Flags & KEY_COMP_NAME) {
  727. CmpCopyCompressedName(NewName.Buffer + (NewName.Length / sizeof(WCHAR)),
  728. NewName.MaximumLength - NewName.Length,
  729. RootData->u.KeyNode.Name,
  730. CmpHKeyNameLen(&RootData->u.KeyNode));
  731. NewName.Length += CmpHKeyNameLen(&RootData->u.KeyNode);
  732. } else {
  733. RootName.Buffer = RootData->u.KeyNode.Name;
  734. RootName.Length = RootName.MaximumLength = RootData->u.KeyNode.NameLength;
  735. RtlAppendUnicodeStringToString(&NewName,&RootName);
  736. }
  737. Status = CmpLinkHiveToMaster(&NewName,
  738. NULL,
  739. NewHive,
  740. FALSE,
  741. NULL);
  742. if (NT_SUCCESS(Status)) {
  743. // call the worker to add the hive to the list
  744. CmpAddToHiveFileList(NewHive);
  745. } else {
  746. CmpDestroyTemporaryHive(NewHive);
  747. }
  748. CmpDestroyTemporaryHive(TempHive);
  749. ExFreePool(NewName.Buffer);
  750. if (NT_SUCCESS(Status)) {
  751. //
  752. // We've given user chance to log on, so turn on quota
  753. //
  754. if (CmpProfileLoaded == FALSE) {
  755. CmpProfileLoaded = TRUE;
  756. CmpSetGlobalQuotaAllowed();
  757. }
  758. }
  759. CmpUnlockRegistry();
  760. return(Status);
  761. }
  762. ULONG
  763. CmpRefreshWorkerRoutine(
  764. PCM_KEY_CONTROL_BLOCK Current,
  765. PVOID Context1,
  766. PVOID Context2
  767. )
  768. /*++
  769. Routine Description:
  770. Helper used by CmpRefreshHive when calling
  771. CmpSearchKeyControlBlockTree.
  772. If a match is found, the KCB is deleted and restart is returned.
  773. Else, continue is returned.
  774. Arguments:
  775. Current - the kcb to examine
  776. Context1 - the hive to match against
  777. Context2 - nothing
  778. Return Value:
  779. if no match, return continue.
  780. if match, return restart.
  781. --*/
  782. {
  783. PAGED_CODE();
  784. if (Current->KeyHive == (PHHIVE)Context1) {
  785. //
  786. // match. set deleted flag. continue search.
  787. //
  788. Current->Delete = TRUE;
  789. Current->KeyHive = NULL;
  790. Current->KeyCell = 0;
  791. return(KCB_WORKER_DELETE);
  792. }
  793. return KCB_WORKER_CONTINUE;
  794. }
  795. NTSTATUS
  796. CmpRefreshHive(
  797. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock
  798. )
  799. /*++
  800. Routine Description:
  801. Backs out all changes to a hives since it was last flushed.
  802. Used as a transaction abort by the security system.
  803. Caller must have SeTcbPrivilege.
  804. The target hive must have HIVE_NOLAZYFLUSH set.
  805. KeyControlBlock must refer to the root of the hive (HIVE_ENTRY must
  806. be set in the key.)
  807. Any kcbs that point into this hive (and thus any handles open
  808. against it) will be force to DELETED state. (If we do any work.)
  809. All notifies pending against the hive will be flushed.
  810. When we're done, only the tombstone kcbs, handles, and attached
  811. notify blocks will be left.
  812. WARNNOTE: Once reads have begun, if the operation fails, the hive
  813. will be corrupt, so we will bugcheck.
  814. Arguments:
  815. KeyControlBlock - provides a reference to the root of the hive
  816. we wish to refresh.
  817. Return Value:
  818. NTSTATUS
  819. --*/
  820. {
  821. PHHIVE Hive;
  822. PLIST_ENTRY ptr;
  823. PCM_NOTIFY_BLOCK node;
  824. #ifdef CMP_KCB_CACHE_VALIDATION
  825. PCELL_DATA pcell;
  826. HCELL_INDEX Cell;
  827. #endif //CMP_KCB_CACHE_VALIDATION
  828. PAGED_CODE();
  829. //
  830. // Check to see if the caller has the privilege to make this call.
  831. //
  832. if (!SeSinglePrivilegeCheck(SeTcbPrivilege, KeGetPreviousMode())) {
  833. return STATUS_PRIVILEGE_NOT_HELD;
  834. }
  835. if (KeyControlBlock->Delete) {
  836. return(STATUS_KEY_DELETED);
  837. }
  838. CmpLockRegistryExclusive();
  839. Hive = KeyControlBlock->KeyHive;
  840. #ifdef CMP_KCB_CACHE_VALIDATION
  841. Cell = KeyControlBlock->KeyCell;
  842. #endif //CMP_KCB_CACHE_VALIDATION
  843. #ifdef NT_UNLOAD_KEY_EX
  844. if( IsHiveFrozen(((PCMHIVE)Hive)) ) {
  845. //
  846. // deny attempts to clobber with a frozen hive
  847. //
  848. CmpUnlockRegistry();
  849. return STATUS_TOO_LATE;
  850. }
  851. #endif //NT_UNLOAD_KEY_EX
  852. //
  853. // check to see if hive is of proper type
  854. //
  855. if ( ! (Hive->HiveFlags & HIVE_NOLAZYFLUSH)) {
  856. CmpUnlockRegistry();
  857. return STATUS_INVALID_PARAMETER;
  858. }
  859. //
  860. // punt if any volatile storage has been allocated
  861. //
  862. if (Hive->Storage[Volatile].Length != 0) {
  863. CmpUnlockRegistry();
  864. return STATUS_UNSUCCESSFUL;
  865. }
  866. #ifdef CMP_KCB_CACHE_VALIDATION
  867. //
  868. // check to see if call was applied to the root of the hive
  869. //
  870. pcell = HvGetCell(Hive, Cell);
  871. if( pcell == NULL ) {
  872. //
  873. // we couldn't map the bin containing this cell
  874. //
  875. CmpUnlockRegistry();
  876. return STATUS_INSUFFICIENT_RESOURCES;
  877. }
  878. // release the cell right here as we are holding the reglock exclusive
  879. HvReleaseCell(Hive,Cell);
  880. ASSERT( pcell->u.KeyNode.Flags == KeyControlBlock->Flags );
  881. #endif //CMP_KCB_CACHE_VALIDATION
  882. if ( ! (KeyControlBlock->Flags & KEY_HIVE_ENTRY)) {
  883. CmpUnlockRegistry();
  884. return STATUS_INVALID_PARAMETER;
  885. }
  886. //
  887. // Flush all NotifyBlocks attached to this hive
  888. //
  889. while (TRUE) {
  890. //
  891. // flush below will edit list, so restart at beginning each time
  892. //
  893. ptr = &(((PCMHIVE)Hive)->NotifyList);
  894. if (ptr->Flink == NULL) {
  895. break;
  896. }
  897. ptr = ptr->Flink;
  898. node = CONTAINING_RECORD(ptr, CM_NOTIFY_BLOCK, HiveList);
  899. ASSERT((node->KeyBody)->NotifyBlock == node);
  900. CmpFlushNotify(node->KeyBody);
  901. }
  902. //
  903. // Force all kcbs that refer to this hive to the deleted state.
  904. //
  905. CmpSearchKeyControlBlockTree(
  906. CmpRefreshWorkerRoutine,
  907. (PVOID)Hive,
  908. NULL
  909. );
  910. //
  911. // Call the worker to do the refresh
  912. //
  913. HvRefreshHive(Hive);
  914. CmpUnlockRegistry();
  915. //
  916. // we're back (rather than bugchecked) so it worked
  917. //
  918. return STATUS_SUCCESS;
  919. }
  920. NTSTATUS
  921. CmDumpKey(
  922. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  923. IN HANDLE FileHandle
  924. )
  925. /*++
  926. Routine Description:
  927. Dumps the key into the specified File - no tree copy.
  928. It is supposed to work fast, Works only when KeyControlBlock is
  929. the root of the hive
  930. Arguments:
  931. KeyControlBlock - pointer to the KCB that describes the key
  932. FileHandle - handle of the file to dump to.
  933. Return Value:
  934. NTSTATUS - Result code from call, among the following:
  935. <TBS>
  936. --*/
  937. {
  938. NTSTATUS status;
  939. PHHIVE Hive;
  940. HCELL_INDEX Cell;
  941. PCMHIVE CmHive;
  942. PAGED_CODE();
  943. //
  944. // Disallow attempts to "save" the master hive
  945. //
  946. Hive = KeyControlBlock->KeyHive;
  947. Cell = KeyControlBlock->KeyCell;
  948. if (Hive == &CmpMasterHive->Hive) {
  949. return STATUS_ACCESS_DENIED;
  950. }
  951. //
  952. // Make sure the cell passed in is the root cell of the hive.
  953. //
  954. if (Cell != Hive->BaseBlock->RootCell) {
  955. return STATUS_INVALID_PARAMETER;
  956. }
  957. CmpLockRegistry();
  958. //
  959. // Punt if post shutdown
  960. //
  961. if (HvShutdownComplete) {
  962. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmDumpKey: Attempt to write hive AFTER SHUTDOWN\n"));
  963. CmpUnlockRegistry();
  964. return STATUS_REGISTRY_IO_FAILED;
  965. }
  966. if (KeyControlBlock->Delete) {
  967. CmpUnlockRegistry();
  968. return STATUS_KEY_DELETED;
  969. }
  970. CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive);
  971. //
  972. // protect against lazy flusher
  973. //
  974. CmLockHive (CmHive);
  975. // sanity
  976. ASSERT( CmHive->FileHandles[HFILE_TYPE_EXTERNAL] == NULL );
  977. CmHive->FileHandles[HFILE_TYPE_EXTERNAL] = FileHandle;
  978. status = HvWriteHive(Hive,FALSE,FALSE,FALSE);
  979. CmHive->FileHandles[HFILE_TYPE_EXTERNAL] = NULL;
  980. CmUnlockHive (CmHive);
  981. CmpUnlockRegistry();
  982. return status;
  983. }
  984. NTSTATUS
  985. CmSaveKey(
  986. IN PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  987. IN HANDLE FileHandle,
  988. IN ULONG HiveVersion
  989. )
  990. /*++
  991. Routine Description:
  992. Arguments:
  993. KeyControlBlock - pointer to the KCB that describes the key
  994. FileHandle - handle of the file to dump to.
  995. Return Value:
  996. NTSTATUS - Result code from call, among the following:
  997. <TBS>
  998. --*/
  999. {
  1000. NTSTATUS status;
  1001. PCMHIVE TmpCmHive;
  1002. PCMHIVE CmHive;
  1003. HCELL_INDEX newroot;
  1004. PHHIVE Hive;
  1005. HCELL_INDEX Cell;
  1006. ULONG OldQuotaAllowed;
  1007. ULONG OldQuotaWarning;
  1008. PAGED_CODE();
  1009. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"CmSaveKey:\n"));
  1010. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tKCB=%p",KeyControlBlock));
  1011. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tFileHandle=%08lx\n",FileHandle));
  1012. //
  1013. // Disallow attempts to "save" the master hive
  1014. //
  1015. Hive = KeyControlBlock->KeyHive;
  1016. Cell = KeyControlBlock->KeyCell;
  1017. if (Hive == &CmpMasterHive->Hive) {
  1018. return STATUS_ACCESS_DENIED;
  1019. }
  1020. CmpLockRegistry();
  1021. if (KeyControlBlock->Delete) {
  1022. CmpUnlockRegistry();
  1023. return STATUS_KEY_DELETED;
  1024. }
  1025. CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive);
  1026. DCmCheckRegistry(CmHive);
  1027. if ( (Hive->HiveFlags & HIVE_NOLAZYFLUSH) &&
  1028. (Hive->DirtyCount != 0) &&
  1029. (CmHive->FileHandles[HFILE_TYPE_PRIMARY] != NULL)
  1030. )
  1031. {
  1032. //
  1033. // we really need the lock exclusive in this case as we can't afford somebody else
  1034. // to alter the file
  1035. //
  1036. CmpUnlockRegistry();
  1037. CmpLockRegistryExclusive();
  1038. if (KeyControlBlock->Delete) {
  1039. CmpUnlockRegistry();
  1040. return STATUS_KEY_DELETED;
  1041. }
  1042. #ifdef CHECK_REGISTRY_USECOUNT
  1043. CmpCheckRegistryUseCount();
  1044. #endif //CHECK_REGISTRY_USECOUNT
  1045. //
  1046. // It's a NOLAZY hive, and there's some dirty data, so writing
  1047. // out a snapshot of what's in memory will not give the caller
  1048. // consistent user data. Therefore, copy the on disk image
  1049. // instead of the memory image
  1050. //
  1051. //
  1052. // Note that this will generate weird results if the key
  1053. // being saved is not the root of the hive, since the
  1054. // resulting file will always be a copy of the entire hive, not
  1055. // just the subtree they asked for.
  1056. //
  1057. status = CmpSaveKeyByFileCopy((PCMHIVE)Hive, FileHandle);
  1058. #ifdef CHECK_REGISTRY_USECOUNT
  1059. CmpCheckRegistryUseCount();
  1060. #endif //CHECK_REGISTRY_USECOUNT
  1061. CmpUnlockRegistry();
  1062. return status;
  1063. }
  1064. //
  1065. // Always try to copy the hive and write it out. This has the
  1066. // effect of compressing out unused free storage.
  1067. // If there isn't space, and the savekey is of the root of the
  1068. // hive, then just write it out directly. (i.e. don't fail on
  1069. // a whole hive restore just because we're out of memory.)
  1070. //
  1071. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tSave of partial hive\n"));
  1072. //
  1073. // The subtree the caller wants does not exactly match a
  1074. // subtree. Make a temporary hive, tree copy the source
  1075. // to temp, write out the temporary, free the temporary.
  1076. //
  1077. //
  1078. // temporarily disable registry quota as we will be giving this memory back immediately!
  1079. //
  1080. OldQuotaAllowed = CmpGlobalQuotaAllowed;
  1081. OldQuotaWarning = CmpGlobalQuotaWarning;
  1082. CmpGlobalQuotaAllowed = CM_WRAP_LIMIT;
  1083. CmpGlobalQuotaWarning = CM_WRAP_LIMIT;
  1084. //
  1085. // Create the temporary hive
  1086. //
  1087. TmpCmHive = CmpCreateTemporaryHive(FileHandle);
  1088. if (TmpCmHive == NULL) {
  1089. status = STATUS_INSUFFICIENT_RESOURCES;
  1090. goto ErrorInsufficientResources;
  1091. }
  1092. //
  1093. // Create a root cell, mark it as such
  1094. //
  1095. //
  1096. // overwrite the hive's minor version in order to implement NtSaveKeyEx
  1097. //
  1098. TmpCmHive->Hive.BaseBlock->Minor = HiveVersion;
  1099. TmpCmHive->Hive.Version = HiveVersion;
  1100. newroot = CmpCopyKeyPartial(
  1101. Hive,
  1102. Cell,
  1103. &(TmpCmHive->Hive),
  1104. HCELL_NIL, // will force KEY_HIVE_ENTRY set
  1105. TRUE);
  1106. if (newroot == HCELL_NIL) {
  1107. status = STATUS_INSUFFICIENT_RESOURCES;
  1108. goto ErrorInsufficientResources;
  1109. }
  1110. TmpCmHive->Hive.BaseBlock->RootCell = newroot;
  1111. //
  1112. // Do a tree copy
  1113. //
  1114. if (CmpCopyTree(Hive, Cell, &(TmpCmHive->Hive), newroot) == FALSE) {
  1115. status = STATUS_INSUFFICIENT_RESOURCES;
  1116. goto ErrorInsufficientResources;
  1117. }
  1118. //
  1119. // Write the file
  1120. //
  1121. CmLockHive (TmpCmHive);
  1122. ASSERT( TmpCmHive->FileHandles[HFILE_TYPE_EXTERNAL] == NULL );
  1123. TmpCmHive->FileHandles[HFILE_TYPE_EXTERNAL] = FileHandle;
  1124. status = HvWriteHive(&(TmpCmHive->Hive),FALSE,FALSE,FALSE);
  1125. TmpCmHive->FileHandles[HFILE_TYPE_EXTERNAL] = NULL;
  1126. CmUnlockHive (TmpCmHive);
  1127. //
  1128. // Error exits
  1129. //
  1130. ErrorInsufficientResources:
  1131. //
  1132. // Free the temporary hive
  1133. //
  1134. if (TmpCmHive != NULL) {
  1135. CmpDestroyTemporaryHive(TmpCmHive);
  1136. }
  1137. //
  1138. // Set global quota back to what it was.
  1139. //
  1140. CmpGlobalQuotaAllowed = OldQuotaAllowed;
  1141. CmpGlobalQuotaWarning = OldQuotaWarning;
  1142. DCmCheckRegistry(CONTAINING_RECORD(Hive, CMHIVE, Hive));
  1143. CmpUnlockRegistry();
  1144. return status;
  1145. }
  1146. NTSTATUS
  1147. CmSaveMergedKeys(
  1148. IN PCM_KEY_CONTROL_BLOCK HighPrecedenceKcb,
  1149. IN PCM_KEY_CONTROL_BLOCK LowPrecedenceKcb,
  1150. IN HANDLE FileHandle
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Arguments:
  1155. HighPrecedenceKcb - pointer to the KCB that describes the High precedence key
  1156. (the one that wins in a duplicate key case)
  1157. LowPrecedenceKcb - pointer to the KCB that describes the Low precedence key
  1158. (the one that gets overwritten in a duplicate key case)
  1159. FileHandle - handle of the file to dump to.
  1160. Return Value:
  1161. NTSTATUS - Result code from call, among the following:
  1162. <TBS>
  1163. --*/
  1164. {
  1165. NTSTATUS status;
  1166. PCMHIVE TmpCmHive;
  1167. HCELL_INDEX newroot;
  1168. PHHIVE HighHive;
  1169. PHHIVE LowHive;
  1170. HCELL_INDEX HighCell;
  1171. HCELL_INDEX LowCell;
  1172. ULONG OldQuotaAllowed;
  1173. ULONG OldQuotaWarning;
  1174. PCM_KEY_NODE HighNode,LowNode;
  1175. PRELEASE_CELL_ROUTINE SourceReleaseCellRoutine;
  1176. PRELEASE_CELL_ROUTINE TargetReleaseCellRoutine;
  1177. #if DBG
  1178. ULONG OldQuotaUsed;
  1179. #endif
  1180. PAGED_CODE();
  1181. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"CmSaveMergedKeys:\n"));
  1182. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tHighKCB=%p",HighPrecedenceKcb));
  1183. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tLowKCB=%p",LowPrecedenceKcb));
  1184. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tFileHandle=%08lx\n",FileHandle));
  1185. //
  1186. // Disallow attempts to "merge" keys located in the same hive
  1187. // A brutal way to avoid recursivity
  1188. //
  1189. HighHive = HighPrecedenceKcb->KeyHive;
  1190. HighCell = HighPrecedenceKcb->KeyCell;
  1191. LowHive = LowPrecedenceKcb->KeyHive;
  1192. LowCell = LowPrecedenceKcb->KeyCell;
  1193. if (LowHive == HighHive ) {
  1194. return STATUS_INVALID_PARAMETER;
  1195. }
  1196. CmpLockRegistryExclusive();
  1197. #ifdef CHECK_REGISTRY_USECOUNT
  1198. CmpCheckRegistryUseCount();
  1199. #endif //CHECK_REGISTRY_USECOUNT
  1200. if (HighPrecedenceKcb->Delete || LowPrecedenceKcb->Delete) {
  1201. //
  1202. // Unlock the registry and fail if one of the keys are marked as deleted
  1203. //
  1204. CmpUnlockRegistry();
  1205. return STATUS_KEY_DELETED;
  1206. }
  1207. DCmCheckRegistry(CONTAINING_RECORD(HighHive, CMHIVE, Hive));
  1208. DCmCheckRegistry(CONTAINING_RECORD(LowHive, CMHIVE, Hive));
  1209. if( ((HighHive->HiveFlags & HIVE_NOLAZYFLUSH) && (HighHive->DirtyCount != 0)) ||
  1210. ((LowHive->HiveFlags & HIVE_NOLAZYFLUSH) && (LowHive->DirtyCount != 0)) ) {
  1211. //
  1212. // Reject the call when one of the hives is a NOLAZY hive and there's
  1213. // some dirty data. Another alternative will be to save only one of the
  1214. // trees (if a valid one exists) or an entire hive (see CmSaveKey)
  1215. //
  1216. status = STATUS_INVALID_PARAMETER;
  1217. #ifdef CHECK_REGISTRY_USECOUNT
  1218. CmpCheckRegistryUseCount();
  1219. #endif //CHECK_REGISTRY_USECOUNT
  1220. CmpUnlockRegistry();
  1221. return status;
  1222. }
  1223. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tCopy of partial HighHive\n"));
  1224. //
  1225. // Make a temporary hive, tree copy the key subtree from
  1226. // HighHive hive to temp, tree-merge with the key subtree from
  1227. // LowHive hive, write out the temporary, free the temporary.
  1228. // Always write the HighHive subtree first, so its afterwise
  1229. // only add new keys/values
  1230. //
  1231. //
  1232. // temporarily disable registry quota as we will be giving this memory back immediately!
  1233. //
  1234. OldQuotaAllowed = CmpGlobalQuotaAllowed;
  1235. OldQuotaWarning = CmpGlobalQuotaWarning;
  1236. CmpGlobalQuotaAllowed = CM_WRAP_LIMIT;
  1237. CmpGlobalQuotaWarning = CM_WRAP_LIMIT;
  1238. #if DBG
  1239. OldQuotaUsed = CmpGlobalQuotaUsed;
  1240. #endif
  1241. //
  1242. // Create the temporary hive
  1243. //
  1244. TmpCmHive = CmpCreateTemporaryHive(FileHandle);
  1245. if (TmpCmHive == NULL) {
  1246. status = STATUS_INSUFFICIENT_RESOURCES;
  1247. goto ErrorInsufficientResources;
  1248. }
  1249. //
  1250. // Create a root cell, mark it as such
  1251. //
  1252. //
  1253. // since the registry is locked exclusively here, we don't need to lock/release cells
  1254. // while copying the trees; So, we just set the release routines to NULL and restore after
  1255. // the copy is complete; this saves some pain
  1256. //
  1257. SourceReleaseCellRoutine = HighHive->ReleaseCellRoutine;
  1258. TargetReleaseCellRoutine = TmpCmHive->Hive.ReleaseCellRoutine;
  1259. HighHive->ReleaseCellRoutine = NULL;
  1260. TmpCmHive->Hive.ReleaseCellRoutine = NULL;
  1261. newroot = CmpCopyKeyPartial(
  1262. HighHive,
  1263. HighCell,
  1264. &(TmpCmHive->Hive),
  1265. HCELL_NIL, // will force KEY_HIVE_ENTRY set
  1266. TRUE);
  1267. HighHive->ReleaseCellRoutine = SourceReleaseCellRoutine;
  1268. TmpCmHive->Hive.ReleaseCellRoutine = TargetReleaseCellRoutine;
  1269. if (newroot == HCELL_NIL) {
  1270. status = STATUS_INSUFFICIENT_RESOURCES;
  1271. goto ErrorInsufficientResources;
  1272. }
  1273. TmpCmHive->Hive.BaseBlock->RootCell = newroot;
  1274. //
  1275. // Do a tree copy. Copy the HighCell tree from HighHive first.
  1276. //
  1277. if (CmpCopyTree(HighHive, HighCell, &(TmpCmHive->Hive), newroot) == FALSE) {
  1278. status = STATUS_INSUFFICIENT_RESOURCES;
  1279. goto ErrorInsufficientResources;
  1280. }
  1281. //
  1282. // Merge the values in the root node of the merged subtrees
  1283. //
  1284. LowNode = (PCM_KEY_NODE)HvGetCell(LowHive, LowCell);
  1285. if( LowNode == NULL ) {
  1286. //
  1287. // we couldn't map the bin containing this cell
  1288. //
  1289. status = STATUS_INSUFFICIENT_RESOURCES;
  1290. goto ErrorInsufficientResources;
  1291. }
  1292. // release the cell right here as we are holding the reglock exclusive
  1293. HvReleaseCell(LowHive, LowCell);
  1294. HighNode = (PCM_KEY_NODE)HvGetCell(&(TmpCmHive->Hive),newroot);
  1295. if( HighNode == NULL ) {
  1296. //
  1297. // we couldn't map the bin containing this cell
  1298. //
  1299. status = STATUS_INSUFFICIENT_RESOURCES;
  1300. goto ErrorInsufficientResources;
  1301. }
  1302. // release the cell right here as we are holding the reglock exclusive
  1303. HvReleaseCell(&(TmpCmHive->Hive),newroot);
  1304. //
  1305. // since the registry is locked exclusively here, we don't need to lock/release cells
  1306. // while copying the trees; So, we just set the release routines to NULL and restore after
  1307. // the copy is complete; this saves some pain
  1308. //
  1309. SourceReleaseCellRoutine = LowHive->ReleaseCellRoutine;
  1310. TargetReleaseCellRoutine = TmpCmHive->Hive.ReleaseCellRoutine;
  1311. LowHive->ReleaseCellRoutine = NULL;
  1312. TmpCmHive->Hive.ReleaseCellRoutine = NULL;
  1313. if (CmpMergeKeyValues(LowHive, LowCell, LowNode, &(TmpCmHive->Hive), newroot, HighNode) == FALSE ){
  1314. LowHive->ReleaseCellRoutine = SourceReleaseCellRoutine;
  1315. TmpCmHive->Hive.ReleaseCellRoutine = TargetReleaseCellRoutine;
  1316. status = STATUS_INSUFFICIENT_RESOURCES;
  1317. goto ErrorInsufficientResources;
  1318. }
  1319. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tMerge partial LowHive over the HighHive\n"));
  1320. //
  1321. // Merge the two trees. A Merge operation is a sync that obeys
  1322. // the following aditional rules:
  1323. // 1. keys the exist in the taget tree and does not exist
  1324. // in the source tree remain as they are (don't get deleted)
  1325. // 2. keys the doesn't exist both in the target tree are added
  1326. // "as they are" from the source tree (always the target tree
  1327. // has a higher precedence)
  1328. //
  1329. if (CmpMergeTrees(LowHive, LowCell, &(TmpCmHive->Hive), newroot) == FALSE) {
  1330. LowHive->ReleaseCellRoutine = SourceReleaseCellRoutine;
  1331. TmpCmHive->Hive.ReleaseCellRoutine = TargetReleaseCellRoutine;
  1332. status = STATUS_INSUFFICIENT_RESOURCES;
  1333. goto ErrorInsufficientResources;
  1334. }
  1335. LowHive->ReleaseCellRoutine = SourceReleaseCellRoutine;
  1336. TmpCmHive->Hive.ReleaseCellRoutine = TargetReleaseCellRoutine;
  1337. //
  1338. // Write the file
  1339. //
  1340. TmpCmHive->FileHandles[HFILE_TYPE_EXTERNAL] = FileHandle;
  1341. status = HvWriteHive(&(TmpCmHive->Hive),FALSE,FALSE,FALSE);
  1342. TmpCmHive->FileHandles[HFILE_TYPE_EXTERNAL] = NULL;
  1343. //
  1344. // Error exits
  1345. //
  1346. ErrorInsufficientResources:
  1347. //
  1348. // Free the temporary hive
  1349. //
  1350. if (TmpCmHive != NULL) {
  1351. CmpDestroyTemporaryHive(TmpCmHive);
  1352. }
  1353. #if DBG
  1354. //
  1355. // Sanity check: when this assert fires, we have leaks in the merge routine.
  1356. //
  1357. ASSERT( OldQuotaUsed == CmpGlobalQuotaUsed );
  1358. #endif
  1359. //
  1360. // Set global quota back to what it was.
  1361. //
  1362. CmpGlobalQuotaAllowed = OldQuotaAllowed;
  1363. CmpGlobalQuotaWarning = OldQuotaWarning;
  1364. DCmCheckRegistry(CONTAINING_RECORD(HighHive, CMHIVE, Hive));
  1365. DCmCheckRegistry(CONTAINING_RECORD(LowHive, CMHIVE, Hive));
  1366. #ifdef CHECK_REGISTRY_USECOUNT
  1367. CmpCheckRegistryUseCount();
  1368. #endif //CHECK_REGISTRY_USECOUNT
  1369. CmpUnlockRegistry();
  1370. return status;
  1371. }
  1372. NTSTATUS
  1373. CmpSaveKeyByFileCopy(
  1374. PCMHIVE CmHive,
  1375. HANDLE FileHandle
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. Do special case of SaveKey by copying the hive file
  1380. Arguments:
  1381. CmHive - supplies a pointer to an HHive
  1382. FileHandle - open handle to target file
  1383. Return Value:
  1384. NTSTATUS - Result code from call, among the following:
  1385. --*/
  1386. {
  1387. PHBASE_BLOCK BaseBlock;
  1388. NTSTATUS status;
  1389. ULONG Offset;
  1390. ULONG Length;
  1391. ULONG Position;
  1392. PUCHAR CopyBuffer;
  1393. ULONG BufferLength;
  1394. ULONG BytesToCopy;
  1395. CMP_OFFSET_ARRAY offsetElement;
  1396. PAGED_CODE();
  1397. //
  1398. // Attempt to allocate large buffer for copying stuff around. If
  1399. // we can't get one, just use the stash buffer.
  1400. //
  1401. BufferLength = CM_SAVEKEYBUFSIZE;
  1402. try {
  1403. CopyBuffer = ExAllocatePoolWithQuota(PagedPoolCacheAligned,
  1404. BufferLength);
  1405. } except(EXCEPTION_EXECUTE_HANDLER) {
  1406. CopyBuffer = NULL;
  1407. }
  1408. CmpLockRegistryExclusive();
  1409. #ifdef CHECK_REGISTRY_USECOUNT
  1410. CmpCheckRegistryUseCount();
  1411. #endif //CHECK_REGISTRY_USECOUNT
  1412. if (CopyBuffer == NULL) {
  1413. LOCK_STASH_BUFFER();
  1414. CopyBuffer = CmpStashBuffer;
  1415. BufferLength = HBLOCK_SIZE;
  1416. }
  1417. //
  1418. // Read the base block, step the sequence number, and write it out
  1419. //
  1420. status = STATUS_REGISTRY_IO_FAILED;
  1421. CmHive->FileHandles[HFILE_TYPE_EXTERNAL] = FileHandle;
  1422. Offset = 0;
  1423. if( !CmpFileRead((PHHIVE)CmHive,HFILE_TYPE_PRIMARY,&Offset,CopyBuffer,HBLOCK_SIZE) ) {
  1424. goto ErrorExit;
  1425. }
  1426. BaseBlock = (PHBASE_BLOCK)CopyBuffer;
  1427. Length = BaseBlock->Length;
  1428. BaseBlock->Sequence1++;
  1429. Offset = 0;
  1430. offsetElement.FileOffset = Offset;
  1431. offsetElement.DataBuffer = CopyBuffer;
  1432. offsetElement.DataLength = HBLOCK_SIZE;
  1433. if ( ! CmpFileWrite((PHHIVE)CmHive, HFILE_TYPE_EXTERNAL, &offsetElement,
  1434. 1, &Offset))
  1435. {
  1436. goto ErrorExit;
  1437. }
  1438. //
  1439. // Flush the external, so header will show corrupt until we're done
  1440. //
  1441. if (CmpFileFlush((PHHIVE)CmHive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  1442. status = STATUS_SUCCESS;
  1443. }
  1444. //
  1445. // For span of data, read from master and write to external
  1446. //
  1447. for (Position = 0; Position < Length; Position += BytesToCopy) {
  1448. Offset = Position + HBLOCK_SIZE;
  1449. BytesToCopy = Length-Position;
  1450. if (BytesToCopy > BufferLength) {
  1451. BytesToCopy = BufferLength;
  1452. }
  1453. if( !CmpFileRead((PHHIVE)CmHive,HFILE_TYPE_PRIMARY,&Offset,CopyBuffer,BytesToCopy) ) {
  1454. goto ErrorExit;
  1455. }
  1456. Offset = Position + HBLOCK_SIZE;
  1457. offsetElement.FileOffset = Offset;
  1458. offsetElement.DataBuffer = CopyBuffer;
  1459. offsetElement.DataLength = BytesToCopy;
  1460. if ( ! CmpFileWrite((PHHIVE)CmHive, HFILE_TYPE_EXTERNAL, &offsetElement,
  1461. 1, &Offset))
  1462. {
  1463. goto ErrorExit;
  1464. }
  1465. }
  1466. //
  1467. // Flush the external, so data is there before we update the header
  1468. //
  1469. if (CmpFileFlush((PHHIVE)CmHive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  1470. status = STATUS_SUCCESS;
  1471. }
  1472. //
  1473. // Reread the base block, sync the seq #, rewrite it.
  1474. // (Brute force, but means no memory alloc - always works)
  1475. //
  1476. Offset = 0;
  1477. if( !CmpFileRead((PHHIVE)CmHive,HFILE_TYPE_PRIMARY,&Offset,CopyBuffer,HBLOCK_SIZE) ) {
  1478. goto ErrorExit;
  1479. }
  1480. BaseBlock->Sequence1++; // it got trampled when we reread it
  1481. BaseBlock->Sequence2++;
  1482. Offset = 0;
  1483. offsetElement.FileOffset = Offset;
  1484. offsetElement.DataBuffer = CopyBuffer;
  1485. offsetElement.DataLength = HBLOCK_SIZE;
  1486. if ( ! CmpFileWrite((PHHIVE)CmHive, HFILE_TYPE_EXTERNAL, &offsetElement,
  1487. 1, &Offset))
  1488. {
  1489. goto ErrorExit;
  1490. }
  1491. //
  1492. // Flush the external, and we are done
  1493. //
  1494. if (CmpFileFlush((PHHIVE)CmHive, HFILE_TYPE_EXTERNAL,NULL,0)) {
  1495. status = STATUS_SUCCESS;
  1496. }
  1497. ErrorExit:
  1498. if (CopyBuffer != CmpStashBuffer) {
  1499. ExFreePool(CopyBuffer);
  1500. } else {
  1501. UNLOCK_STASH_BUFFER();
  1502. }
  1503. CmHive->FileHandles[HFILE_TYPE_EXTERNAL] = NULL;
  1504. CmpUnlockRegistry();
  1505. return status;
  1506. }
  1507. PCMHIVE
  1508. CmpCreateTemporaryHive(
  1509. IN HANDLE FileHandle
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Allocates and inits a temporary hive.
  1514. Arguments:
  1515. FileHandle - Supplies the handle of the file to back the hive.
  1516. Return Value:
  1517. Pointer to CmHive.
  1518. If NULL the operation failed.
  1519. --*/
  1520. {
  1521. PCMHIVE TempHive;
  1522. NTSTATUS Status;
  1523. PAGED_CODE();
  1524. //
  1525. // NOTE: Hive will get put on CmpHiveListHead list.
  1526. // Make sure CmpDestroyTemporaryHive gets called to remove it.
  1527. //
  1528. Status = CmpInitializeHive(&TempHive,
  1529. HINIT_CREATE,
  1530. HIVE_VOLATILE,
  1531. 0,
  1532. NULL,
  1533. NULL,
  1534. NULL,
  1535. NULL,
  1536. NULL,
  1537. 0);
  1538. if (NT_SUCCESS(Status)) {
  1539. return(TempHive);
  1540. } else {
  1541. return(NULL);
  1542. }
  1543. }
  1544. VOID
  1545. CmpDestroyTemporaryHive(
  1546. PCMHIVE CmHive
  1547. )
  1548. /*++
  1549. Routine Description:
  1550. Frees all the pieces of a hive.
  1551. Arguments:
  1552. CmHive - CM level hive structure to free
  1553. Return Value:
  1554. None.
  1555. --*/
  1556. {
  1557. PAGED_CODE();
  1558. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"CmpDestroyTemporaryHive:\n"));
  1559. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tCmHive=%p\n", CmHive));
  1560. if (CmHive == NULL) {
  1561. return;
  1562. }
  1563. //
  1564. // NOTE: Hive is on CmpHiveListHead list.
  1565. // Remove it.
  1566. //
  1567. CmpDestroyHiveViewList(CmHive);
  1568. CmpDestroySecurityCache(CmHive);
  1569. CmpDropFileObjectForHive(CmHive);
  1570. LOCK_HIVE_LIST();
  1571. CmpRemoveEntryList(&CmHive->HiveList);
  1572. UNLOCK_HIVE_LIST();
  1573. HvFreeHive(&(CmHive->Hive));
  1574. ASSERT( CmHive->HiveLock );
  1575. ExFreePool(CmHive->HiveLock);
  1576. ASSERT( CmHive->ViewLock );
  1577. ExFreePool(CmHive->ViewLock);
  1578. CmpFree(CmHive, sizeof(CMHIVE));
  1579. return;
  1580. }
  1581. NTSTATUS
  1582. CmpOverwriteHive(
  1583. PCMHIVE CmHive,
  1584. PCMHIVE NewHive,
  1585. HCELL_INDEX LinkCell
  1586. )
  1587. {
  1588. HCELL_INDEX RootCell;
  1589. BOOLEAN Result;
  1590. PCM_KEY_NODE RootNode;
  1591. PULONG Vector;
  1592. ULONG Length;
  1593. PAGED_CODE();
  1594. // get rid of the views.
  1595. CmpDestroyHiveViewList (CmHive);
  1596. RootCell = NewHive->Hive.BaseBlock->RootCell;
  1597. RootNode = (PCM_KEY_NODE)HvGetCell(&(NewHive->Hive),RootCell);
  1598. if( RootNode == NULL ) {
  1599. return STATUS_INSUFFICIENT_RESOURCES;
  1600. }
  1601. if( !HvMarkCellDirty(&(NewHive->Hive),RootCell) ) {
  1602. HvReleaseCell(&(NewHive->Hive),RootCell);
  1603. return STATUS_NO_LOG_SPACE;
  1604. }
  1605. RootNode->Parent = LinkCell;
  1606. RootNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;
  1607. HvReleaseCell(&(NewHive->Hive),RootCell);
  1608. //
  1609. // dump data over to the log and primary
  1610. //
  1611. ASSERT( NewHive->Hive.DirtyVector.Buffer == NULL );
  1612. ASSERT( NewHive->Hive.DirtyAlloc == 0 );
  1613. Length = NewHive->Hive.Storage[Stable].Length;
  1614. Vector = (PULONG)((NewHive->Hive.Allocate)(ROUND_UP(Length /HSECTOR_SIZE/8,sizeof(ULONG)),TRUE,CM_FIND_LEAK_TAG22));
  1615. if (Vector == NULL) {
  1616. return STATUS_NO_MEMORY;
  1617. }
  1618. RtlZeroMemory(Vector, Length / HSECTOR_SIZE / 8);
  1619. RtlInitializeBitMap(&(NewHive->Hive.DirtyVector), Vector, Length / HSECTOR_SIZE);
  1620. NewHive->Hive.DirtyAlloc = ROUND_UP(Length /HSECTOR_SIZE/8,sizeof(ULONG));
  1621. RtlSetAllBits(&(NewHive->Hive.DirtyVector));
  1622. NewHive->Hive.DirtyCount = NewHive->Hive.DirtyVector.SizeOfBitMap;
  1623. NewHive->Hive.Log = TRUE;
  1624. NewHive->FileHandles[HFILE_TYPE_LOG] = CmHive->FileHandles[HFILE_TYPE_LOG];
  1625. Result = HvpGrowLog2(&(NewHive->Hive), Length);
  1626. if( Result) {
  1627. Result = HvpWriteLog(&(NewHive->Hive));
  1628. }
  1629. NewHive->FileHandles[HFILE_TYPE_LOG] = NULL;
  1630. NewHive->Hive.Free(Vector,NewHive->Hive.DirtyAlloc);
  1631. NewHive->Hive.DirtyAlloc = 0;
  1632. NewHive->Hive.DirtyCount = 0;
  1633. RtlZeroMemory(&(NewHive->Hive.DirtyVector),sizeof(RTL_BITMAP));
  1634. NewHive->Hive.Log = FALSE;
  1635. if( !Result ) {
  1636. return STATUS_REGISTRY_IO_FAILED;
  1637. }
  1638. NewHive->FileHandles[HFILE_TYPE_EXTERNAL] = CmHive->FileHandles[HFILE_TYPE_PRIMARY];
  1639. //
  1640. // all data in the new hive is marked as dirty !!!
  1641. // even if this fails; we are going to keep the hive in memory, so no problem, we have the log !
  1642. //
  1643. NewHive->FileObject = CmHive->FileObject;
  1644. NewHive->Hive.BaseBlock->Type = HFILE_TYPE_PRIMARY;
  1645. HvWriteHive(&(NewHive->Hive),Length <= CmHive->Hive.Storage[Stable].Length,CmHive->FileObject != NULL,TRUE);
  1646. NewHive->FileHandles[HFILE_TYPE_EXTERNAL] = NULL;
  1647. NewHive->FileObject = NULL;
  1648. RtlClearAllBits(&(NewHive->Hive.DirtyVector));
  1649. NewHive->Hive.DirtyCount = 0;
  1650. return STATUS_SUCCESS;
  1651. }
  1652. VOID
  1653. CmpSwitchStorageAndRebuildMappings(PCMHIVE OldCmHive,
  1654. PCMHIVE NewCmHive
  1655. )
  1656. /*++
  1657. Routine Description:
  1658. Switches relevant storage between the hives. Then, rebuilds
  1659. the kcb mapping according with the mapping stored inside OldHive
  1660. Arguments:
  1661. OldHive - Hive to be updated; the one that is currently linked in
  1662. the registry tree
  1663. NewHive - the compressed hive; it'll be freed after this operation.
  1664. Return Value:
  1665. None.
  1666. --*/
  1667. {
  1668. HHIVE TmpHive;
  1669. RTL_BITMAP Bitmap;
  1670. ULONG i;
  1671. LONG j;
  1672. PCM_KCB_REMAP_BLOCK RemapBlock;
  1673. PLIST_ENTRY AnchorAddr;
  1674. BOOLEAN OldSmallDir;
  1675. BOOLEAN NewSmallDir;
  1676. PFREE_HBIN FreeBin;
  1677. PCM_KNODE_REMAP_BLOCK KnodeRemapBlock;
  1678. PAGED_CODE();
  1679. //
  1680. // The baseblock
  1681. //
  1682. OldCmHive->Hive.BaseBlock->Sequence1 = NewCmHive->Hive.BaseBlock->Sequence1;
  1683. OldCmHive->Hive.BaseBlock->Sequence2 = NewCmHive->Hive.BaseBlock->Sequence2;
  1684. OldCmHive->Hive.BaseBlock->RootCell = NewCmHive->Hive.BaseBlock->RootCell;
  1685. //
  1686. // rest of the hive
  1687. //
  1688. ASSERT( (NewCmHive->Hive.DirtyVector.Buffer == NULL) &&
  1689. (NewCmHive->Hive.DirtyCount == 0) &&
  1690. (NewCmHive->Hive.DirtyAlloc == 0) &&
  1691. (OldCmHive->Hive.Storage[Stable].Length >= NewCmHive->Hive.Storage[Stable].Length) );
  1692. OldCmHive->Hive.LogSize = NewCmHive->Hive.LogSize;
  1693. NewCmHive->Hive.LogSize = 0;
  1694. //
  1695. // switch hive stable storage; preserving the volatile info
  1696. //
  1697. OldSmallDir = (OldCmHive->Hive.Storage[Stable].Map == (PHMAP_DIRECTORY)&(OldCmHive->Hive.Storage[Stable].SmallDir));
  1698. NewSmallDir = (NewCmHive->Hive.Storage[Stable].Map == (PHMAP_DIRECTORY)&(NewCmHive->Hive.Storage[Stable].SmallDir));
  1699. RtlCopyMemory(&(TmpHive.Storage[Stable]),&(OldCmHive->Hive.Storage[Stable]),sizeof(TmpHive.Storage[Stable]) - sizeof(LIST_ENTRY) );
  1700. RtlCopyMemory(&(OldCmHive->Hive.Storage[Stable]),&(NewCmHive->Hive.Storage[Stable]),sizeof(TmpHive.Storage[Stable]) - sizeof(LIST_ENTRY) );
  1701. RtlCopyMemory(&(NewCmHive->Hive.Storage[Stable]),&(TmpHive.Storage[Stable]),sizeof(TmpHive.Storage[Stable]) - sizeof(LIST_ENTRY) );
  1702. if( OldSmallDir ) {
  1703. NewCmHive->Hive.Storage[Stable].Map = (PHMAP_DIRECTORY)&(NewCmHive->Hive.Storage[Stable].SmallDir);
  1704. }
  1705. if( NewSmallDir ) {
  1706. OldCmHive->Hive.Storage[Stable].Map = (PHMAP_DIRECTORY)&(OldCmHive->Hive.Storage[Stable].SmallDir);
  1707. }
  1708. //
  1709. // For FreeBins we have to take special precaution and move them manually from one list to another
  1710. //
  1711. // new hive should not have free bins.
  1712. ASSERT( IsListEmpty(&(NewCmHive->Hive.Storage[Stable].FreeBins)) );
  1713. while( !IsListEmpty(&(OldCmHive->Hive.Storage[Stable].FreeBins)) ) {
  1714. FreeBin = (PFREE_HBIN)RemoveHeadList(&(OldCmHive->Hive.Storage[Stable].FreeBins));
  1715. FreeBin = CONTAINING_RECORD(FreeBin,
  1716. FREE_HBIN,
  1717. ListEntry);
  1718. InsertTailList(
  1719. &(NewCmHive->Hive.Storage[Stable].FreeBins),
  1720. &(FreeBin->ListEntry)
  1721. );
  1722. }
  1723. ASSERT( IsListEmpty(&(OldCmHive->Hive.Storage[Stable].FreeBins)) );
  1724. ASSERT( IsListEmpty(&(OldCmHive->LRUViewListHead)) && (OldCmHive->MappedViews == 0) && (OldCmHive->UseCount == 0) );
  1725. ASSERT( IsListEmpty(&(NewCmHive->LRUViewListHead)) && (NewCmHive->MappedViews == 0) && (OldCmHive->UseCount == 0) );
  1726. ASSERT( IsListEmpty(&(OldCmHive->PinViewListHead)) && (OldCmHive->PinnedViews == 0) );
  1727. ASSERT( IsListEmpty(&(NewCmHive->PinViewListHead)) && (NewCmHive->PinnedViews == 0) );
  1728. //
  1729. // now the security cache; we preserve the security cache; only that we go through it and
  1730. // shift cells accordingly
  1731. //
  1732. for( i=0;i<OldCmHive->SecurityCount;i++) {
  1733. if( HvGetCellType(OldCmHive->SecurityCache[i].Cell) == (ULONG)Stable ) {
  1734. ASSERT( OldCmHive->SecurityCache[i].Cell == OldCmHive->CellRemapArray[i].OldCell );
  1735. ASSERT( OldCmHive->SecurityCache[i].Cell == OldCmHive->SecurityCache[i].CachedSecurity->Cell);
  1736. OldCmHive->SecurityCache[i].Cell = OldCmHive->CellRemapArray[i].NewCell;
  1737. OldCmHive->SecurityCache[i].CachedSecurity->Cell = OldCmHive->CellRemapArray[i].NewCell;
  1738. }
  1739. }
  1740. //
  1741. // now restore mappings for kcbs KeyCells
  1742. //
  1743. AnchorAddr = &(OldCmHive->KcbConvertListHead);
  1744. RemapBlock = (PCM_KCB_REMAP_BLOCK)(OldCmHive->KcbConvertListHead.Flink);
  1745. while ( RemapBlock != (PCM_KCB_REMAP_BLOCK)AnchorAddr ) {
  1746. RemapBlock = CONTAINING_RECORD(
  1747. RemapBlock,
  1748. CM_KCB_REMAP_BLOCK,
  1749. RemapList
  1750. );
  1751. ASSERT( RemapBlock->OldCellIndex != HCELL_NIL );
  1752. if( (HvGetCellType(RemapBlock->KeyControlBlock->KeyCell) == (ULONG)Stable) && // we are preserving volatile storage
  1753. (!(RemapBlock->KeyControlBlock->ExtFlags & CM_KCB_KEY_NON_EXIST)) // don't mess with fake kcbs
  1754. ) {
  1755. ASSERT( RemapBlock->NewCellIndex != HCELL_NIL );
  1756. RemapBlock->KeyControlBlock->KeyCell = RemapBlock->NewCellIndex;
  1757. }
  1758. //
  1759. // invalidate the cache
  1760. //
  1761. if( (!(RemapBlock->KeyControlBlock->Flags & KEY_PREDEF_HANDLE) ) && // don't mess with predefined handles
  1762. (!(RemapBlock->KeyControlBlock->ExtFlags & (CM_KCB_KEY_NON_EXIST|CM_KCB_SYM_LINK_FOUND))) && // don't mess with fake kcbs or symlinks
  1763. (HvGetCellType(RemapBlock->KeyControlBlock->KeyCell) == (ULONG)Stable) // we are preserving volatile storage
  1764. ) {
  1765. CmpCleanUpKcbValueCache(RemapBlock->KeyControlBlock);
  1766. CmpSetUpKcbValueCache(RemapBlock->KeyControlBlock,RemapBlock->ValueCount,RemapBlock->ValueList);
  1767. }
  1768. //
  1769. // skip to the next element
  1770. //
  1771. RemapBlock = (PCM_KCB_REMAP_BLOCK)(RemapBlock->RemapList.Flink);
  1772. }
  1773. //
  1774. // now restore mappings for volatile Knodes
  1775. //
  1776. AnchorAddr = &(OldCmHive->KnodeConvertListHead);
  1777. KnodeRemapBlock = (PCM_KNODE_REMAP_BLOCK)(OldCmHive->KnodeConvertListHead.Flink);
  1778. while ( KnodeRemapBlock != (PCM_KNODE_REMAP_BLOCK)AnchorAddr ) {
  1779. KnodeRemapBlock = CONTAINING_RECORD(
  1780. KnodeRemapBlock,
  1781. CM_KNODE_REMAP_BLOCK,
  1782. RemapList
  1783. );
  1784. KnodeRemapBlock->KeyNode->Parent = KnodeRemapBlock->NewParent;
  1785. //
  1786. // skip to the next element
  1787. //
  1788. KnodeRemapBlock = (PCM_KNODE_REMAP_BLOCK)(KnodeRemapBlock->RemapList.Flink);
  1789. }
  1790. }
  1791. NTSTATUS
  1792. CmpShiftHiveFreeBins(
  1793. PCMHIVE CmHive,
  1794. PCMHIVE *NewHive
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. Arguments:
  1799. CmHive - the hive to compress
  1800. NewHive - hive with the free bins shifted to the end.
  1801. Return Value:
  1802. NTSTATUS - Result code from call, among the following:
  1803. <TBS>
  1804. --*/
  1805. {
  1806. NTSTATUS status;
  1807. HCELL_INDEX newroot;
  1808. PHHIVE Hive;
  1809. HCELL_INDEX RootCell;
  1810. ULONG NewLength;
  1811. PAGED_CODE();
  1812. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  1813. ASSERT( !IsListEmpty(&(CmHive->Hive.Storage[Stable].FreeBins)) );
  1814. *NewHive = NULL;
  1815. //
  1816. // Disallow attempts to "save" a hive which cannot be saved.
  1817. //
  1818. Hive = &(CmHive->Hive);
  1819. RootCell = Hive->BaseBlock->RootCell;
  1820. if ( (Hive == &CmpMasterHive->Hive) ||
  1821. ( (Hive->HiveFlags & HIVE_NOLAZYFLUSH) && (Hive->DirtyCount != 0) ) ||
  1822. (CmHive->FileHandles[HFILE_TYPE_PRIMARY] == NULL)
  1823. ) {
  1824. return STATUS_ACCESS_DENIED;
  1825. }
  1826. if(Hive->DirtyCount != 0) {
  1827. //
  1828. // need to flush the hive as we will replace it with the compressed one.
  1829. //
  1830. if( !HvSyncHive(Hive) ) {
  1831. return STATUS_ACCESS_DENIED;
  1832. }
  1833. }
  1834. //
  1835. // The subtree the caller wants does not exactly match a
  1836. // subtree. Make a temporary hive, tree copy the source
  1837. // to temp, write out the temporary, free the temporary.
  1838. //
  1839. //
  1840. // Create the temporary hive
  1841. //
  1842. (*NewHive) = CmpCreateTemporaryHive(NULL);
  1843. if (*NewHive == NULL) {
  1844. status = STATUS_INSUFFICIENT_RESOURCES;
  1845. goto ErrorInsufficientResources;
  1846. }
  1847. //
  1848. // Create a root cell, mark it as such
  1849. //
  1850. //
  1851. // preserve the hive version and signal to copy tree to build mappings and preserve volatile.
  1852. //
  1853. (*NewHive)->Hive.BaseBlock->Minor = Hive->BaseBlock->Minor;
  1854. (*NewHive)->Hive.Version = Hive->Version;
  1855. (*NewHive)->Hive.BaseBlock->RootCell = CmHive->Hive.BaseBlock->RootCell;
  1856. //
  1857. // this will create a clone hive (in paged pool) and will compute the shift index for each bin
  1858. //
  1859. status = HvCloneHive(&(CmHive->Hive),&((*NewHive)->Hive),&NewLength);
  1860. if( !NT_SUCCESS(status) ) {
  1861. goto ErrorInsufficientResources;
  1862. }
  1863. //
  1864. // iterate through the hive and shift each cell; this will take care of the mappings too.
  1865. //
  1866. if( !CmpShiftAllCells(&((*NewHive)->Hive),CmHive) ) {
  1867. status = STATUS_INSUFFICIENT_RESOURCES;
  1868. goto ErrorInsufficientResources;
  1869. }
  1870. (*NewHive)->Hive.BaseBlock->RootCell = HvShiftCell(&((*NewHive)->Hive),(*NewHive)->Hive.BaseBlock->RootCell);
  1871. //
  1872. // moves free bins at the end and updates the maps.
  1873. //
  1874. status = HvShrinkHive(&((*NewHive)->Hive),NewLength);
  1875. if( !NT_SUCCESS(status) ) {
  1876. goto ErrorInsufficientResources;
  1877. }
  1878. return STATUS_SUCCESS;
  1879. //
  1880. // Error exits
  1881. //
  1882. ErrorInsufficientResources:
  1883. //
  1884. // Free the temporary hive
  1885. //
  1886. if ((*NewHive) != NULL) {
  1887. CmpDestroyTemporaryHive((*NewHive));
  1888. (*NewHive) = NULL;
  1889. }
  1890. return status;
  1891. }
  1892. BOOLEAN
  1893. CmpShiftAllCells(PHHIVE NewHive,
  1894. PCMHIVE OldHive
  1895. )
  1896. /*++
  1897. Routine Description:
  1898. Parsess the logical structure of the registry tree and remaps all
  1899. cells inside, according to the Spare filed in each bin. Updates
  1900. kcb and security mapping also.
  1901. Arguments:
  1902. NewHive - hive to remap
  1903. OldHive - the old hive - will use volatile from it (temporary)
  1904. Return Value:
  1905. NTSTATUS - Result code from call, among the following:
  1906. <TBS>
  1907. --*/
  1908. {
  1909. PRELEASE_CELL_ROUTINE ReleaseCellRoutine;
  1910. BOOLEAN Result = TRUE;
  1911. ULONG i;
  1912. PAGED_CODE();
  1913. ReleaseCellRoutine = NewHive->ReleaseCellRoutine;
  1914. NewHive->ReleaseCellRoutine = NULL;
  1915. //
  1916. // setup volatile to the newhive; just temporary, so we can access it
  1917. //
  1918. ASSERT( NewHive->Storage[Volatile].Length == 0 );
  1919. ASSERT( NewHive->Storage[Volatile].Map == NULL );
  1920. ASSERT( NewHive->Storage[Volatile].SmallDir == NULL );
  1921. NewHive->Storage[Volatile].Length = OldHive->Hive.Storage[Volatile].Length;
  1922. NewHive->Storage[Volatile].Map = OldHive->Hive.Storage[Volatile].Map;
  1923. NewHive->Storage[Volatile].SmallDir = OldHive->Hive.Storage[Volatile].SmallDir;
  1924. CmpShiftSecurityCells(NewHive);
  1925. //
  1926. // update the security mapping array
  1927. //
  1928. for( i=0;i<OldHive->SecurityCount;i++) {
  1929. if( HvGetCellType(OldHive->SecurityCache[i].Cell) == (ULONG)Stable ) {
  1930. OldHive->CellRemapArray[i].NewCell = HvShiftCell(NewHive,OldHive->CellRemapArray[i].OldCell);
  1931. }
  1932. }
  1933. Result = CmpShiftAllCells2(NewHive,OldHive,NewHive->BaseBlock->RootCell, HCELL_NIL);
  1934. NewHive->Storage[Volatile].Length = 0;
  1935. NewHive->Storage[Volatile].Map = NULL;
  1936. NewHive->Storage[Volatile].SmallDir = NULL;
  1937. NewHive->ReleaseCellRoutine = ReleaseCellRoutine;
  1938. return Result;
  1939. }
  1940. BOOLEAN
  1941. CmpShiftAllCells2( PHHIVE Hive,
  1942. PCMHIVE OldHive,
  1943. HCELL_INDEX Cell,
  1944. HCELL_INDEX ParentCell
  1945. )
  1946. /*++
  1947. Routine Description:
  1948. In this routine, HvGetCell cannot fail because the hive is in paged pool!
  1949. Arguments:
  1950. CmHive - hive to remap
  1951. Return Value:
  1952. TRUE/FALSE
  1953. --*/
  1954. {
  1955. PCMP_CHECK_REGISTRY_STACK_ENTRY CheckStack;
  1956. LONG StackIndex;
  1957. PCM_KEY_NODE Node;
  1958. HCELL_INDEX SubKey;
  1959. BOOLEAN Result = TRUE;
  1960. PCM_KEY_INDEX Index;
  1961. ULONG i;
  1962. ASSERT( Hive->ReleaseCellRoutine == NULL );
  1963. //
  1964. // Initialize the stack to simulate recursion here
  1965. //
  1966. CheckStack = ExAllocatePool(PagedPool,sizeof(CMP_CHECK_REGISTRY_STACK_ENTRY)*CMP_MAX_REGISTRY_DEPTH);
  1967. if (CheckStack == NULL) {
  1968. return FALSE;
  1969. }
  1970. CheckStack[0].Cell = Cell;
  1971. CheckStack[0].ParentCell = ParentCell;
  1972. CheckStack[0].ChildIndex = 0;
  1973. CheckStack[0].CellChecked = FALSE;
  1974. StackIndex = 0;
  1975. while(StackIndex >=0) {
  1976. //
  1977. // first check the current cell
  1978. //
  1979. if( CheckStack[StackIndex].CellChecked == FALSE ) {
  1980. CheckStack[StackIndex].CellChecked = TRUE;
  1981. CmpShiftKey(Hive,OldHive,CheckStack[StackIndex].Cell,CheckStack[StackIndex].ParentCell);
  1982. }
  1983. Node = (PCM_KEY_NODE)HvGetCell(Hive, CheckStack[StackIndex].Cell);
  1984. ASSERT( Node != NULL );
  1985. if( CheckStack[StackIndex].ChildIndex < Node->SubKeyCounts[Stable] ) {
  1986. //
  1987. // we still have childs to check; add another entry for them and advance the
  1988. // StackIndex
  1989. //
  1990. SubKey = CmpFindSubKeyByNumber(Hive,
  1991. Node,
  1992. CheckStack[StackIndex].ChildIndex);
  1993. ASSERT( SubKey != HCELL_NIL );
  1994. //
  1995. // next iteration will check the next child
  1996. //
  1997. CheckStack[StackIndex].ChildIndex++;
  1998. StackIndex++;
  1999. if( StackIndex == CMP_MAX_REGISTRY_DEPTH ) {
  2000. //
  2001. // we've run out of stack; registry tree has too many levels
  2002. //
  2003. Result = FALSE;
  2004. // bail out
  2005. break;
  2006. }
  2007. CheckStack[StackIndex].Cell = SubKey;
  2008. CheckStack[StackIndex].ParentCell = CheckStack[StackIndex-1].Cell;
  2009. CheckStack[StackIndex].ChildIndex = 0;
  2010. CheckStack[StackIndex].CellChecked = FALSE;
  2011. } else {
  2012. //
  2013. // add all volatile nodes to the volatile list
  2014. //
  2015. PCM_KNODE_REMAP_BLOCK knodeRemapBlock;
  2016. for(i = 0; i<Node->SubKeyCounts[Volatile];i++) {
  2017. SubKey = CmpFindSubKeyByNumber(Hive,
  2018. Node,
  2019. Node->SubKeyCounts[Stable] + i);
  2020. ASSERT( SubKey != HCELL_NIL );
  2021. knodeRemapBlock = (PCM_KNODE_REMAP_BLOCK)ExAllocatePool(PagedPool, sizeof(CM_KNODE_REMAP_BLOCK));
  2022. if( knodeRemapBlock == NULL ) {
  2023. Result = FALSE;
  2024. break;
  2025. }
  2026. ASSERT( HvGetCellType(SubKey) == (ULONG)Volatile );
  2027. knodeRemapBlock->KeyNode = (PCM_KEY_NODE)HvGetCell(Hive,SubKey);;
  2028. knodeRemapBlock->NewParent = HvShiftCell(Hive,CheckStack[StackIndex].Cell);
  2029. InsertTailList(&(OldHive->KnodeConvertListHead),&(knodeRemapBlock->RemapList));
  2030. }
  2031. //
  2032. // we have checked all childs for this node; time to take care of the index.
  2033. //
  2034. if( Node->SubKeyLists[Stable] != HCELL_NIL ) {
  2035. Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]);
  2036. CmpShiftIndex(Hive,Index);
  2037. Node->SubKeyLists[Stable] = HvShiftCell(Hive,Node->SubKeyLists[Stable]);
  2038. }
  2039. //
  2040. // ; go back
  2041. //
  2042. StackIndex--;
  2043. }
  2044. }
  2045. ExFreePool(CheckStack);
  2046. return Result;
  2047. }
  2048. VOID
  2049. CmpShiftIndex(PHHIVE Hive,
  2050. PCM_KEY_INDEX Index
  2051. )
  2052. {
  2053. ULONG i,j;
  2054. HCELL_INDEX LeafCell;
  2055. PCM_KEY_INDEX Leaf;
  2056. PCM_KEY_FAST_INDEX FastIndex;
  2057. if (Index->Signature == CM_KEY_INDEX_ROOT) {
  2058. //
  2059. // step through root, update the leafs
  2060. //
  2061. for (i = 0; i < Index->Count; i++) {
  2062. LeafCell = Index->List[i];
  2063. Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
  2064. ASSERT( Leaf != NULL );
  2065. for(j=0;j<Leaf->Count;j++) {
  2066. if( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
  2067. (Leaf->Signature == CM_KEY_HASH_LEAF) ) {
  2068. FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
  2069. FastIndex->List[j].Cell = HvShiftCell(Hive,FastIndex->List[j].Cell);
  2070. } else {
  2071. Leaf->List[j] = HvShiftCell(Hive,Leaf->List[j]);
  2072. }
  2073. }
  2074. }
  2075. }
  2076. //
  2077. // now update the root
  2078. //
  2079. for (i = 0; i < Index->Count; i++) {
  2080. if( (Index->Signature == CM_KEY_FAST_LEAF) ||
  2081. (Index->Signature == CM_KEY_HASH_LEAF) ) {
  2082. FastIndex = (PCM_KEY_FAST_INDEX)Index;
  2083. FastIndex->List[i].Cell = HvShiftCell(Hive,FastIndex->List[i].Cell);
  2084. } else {
  2085. Index->List[i] = HvShiftCell(Hive,Index->List[i]);
  2086. }
  2087. }
  2088. }
  2089. VOID
  2090. CmpShiftKey(PHHIVE Hive,
  2091. PCMHIVE OldHive,
  2092. HCELL_INDEX Cell,
  2093. HCELL_INDEX ParentCell
  2094. )
  2095. {
  2096. PCM_KEY_NODE Node;
  2097. PCM_KCB_REMAP_BLOCK RemapBlock;
  2098. PLIST_ENTRY AnchorAddr;
  2099. Node = (PCM_KEY_NODE)HvGetCell(Hive,Cell);
  2100. ASSERT( Node != NULL );
  2101. //
  2102. // key node related cells
  2103. //
  2104. if( ParentCell != HCELL_NIL ) {
  2105. ASSERT( ParentCell == Node->Parent );
  2106. Node->Parent = HvShiftCell(Hive,Node->Parent);
  2107. }
  2108. ASSERT( Node->Security != HCELL_NIL );
  2109. Node->Security = HvShiftCell(Hive,Node->Security);
  2110. if( Node->Class != HCELL_NIL ) {
  2111. Node->Class = HvShiftCell(Hive,Node->Class);
  2112. }
  2113. //
  2114. // now the valuelist
  2115. //
  2116. if( Node->ValueList.Count > 0 ) {
  2117. CmpShiftValueList(Hive,Node->ValueList.List,Node->ValueList.Count);
  2118. Node->ValueList.List = HvShiftCell(Hive,Node->ValueList.List);
  2119. }
  2120. //
  2121. // walk the KcbConvertListHead and store the mappings
  2122. //
  2123. AnchorAddr = &(OldHive->KcbConvertListHead);
  2124. RemapBlock = (PCM_KCB_REMAP_BLOCK)(OldHive->KcbConvertListHead.Flink);
  2125. while ( RemapBlock != (PCM_KCB_REMAP_BLOCK)AnchorAddr ) {
  2126. RemapBlock = CONTAINING_RECORD(
  2127. RemapBlock,
  2128. CM_KCB_REMAP_BLOCK,
  2129. RemapList
  2130. );
  2131. ASSERT( RemapBlock->OldCellIndex != HCELL_NIL );
  2132. if( RemapBlock->OldCellIndex == Cell ) {
  2133. //
  2134. // found it !
  2135. //
  2136. // can only be set once
  2137. ASSERT( RemapBlock->NewCellIndex == HCELL_NIL );
  2138. RemapBlock->NewCellIndex = HvShiftCell(Hive,Cell);;
  2139. RemapBlock->ValueCount = Node->ValueList.Count;
  2140. RemapBlock->ValueList = Node->ValueList.List;
  2141. break;
  2142. }
  2143. //
  2144. // skip to the next element
  2145. //
  2146. RemapBlock = (PCM_KCB_REMAP_BLOCK)(RemapBlock->RemapList.Flink);
  2147. }
  2148. }
  2149. VOID
  2150. CmpShiftValueList(PHHIVE Hive,
  2151. HCELL_INDEX ValueList,
  2152. ULONG Count
  2153. )
  2154. {
  2155. PCELL_DATA List,pcell;
  2156. ULONG i,j;
  2157. HCELL_INDEX Cell;
  2158. ULONG DataLength;
  2159. HCELL_INDEX Data;
  2160. PCM_BIG_DATA BigData;
  2161. PHCELL_INDEX Plist;
  2162. List = HvGetCell(Hive,ValueList);
  2163. ASSERT( List != NULL );
  2164. for (i = 0; i < Count; i++) {
  2165. Cell = List->u.KeyList[i];
  2166. pcell = HvGetCell(Hive, Cell);
  2167. ASSERT( pcell != NULL );
  2168. DataLength = pcell->u.KeyValue.DataLength;
  2169. if (DataLength < CM_KEY_VALUE_SPECIAL_SIZE) {
  2170. //
  2171. // regular value.
  2172. //
  2173. if( CmpIsHKeyValueBig(Hive,DataLength) == TRUE ) {
  2174. BigData = (PCM_BIG_DATA)HvGetCell(Hive, pcell->u.KeyValue.Data);
  2175. ASSERT( BigData != NULL );
  2176. if( BigData->Count ) {
  2177. Plist = (PHCELL_INDEX)HvGetCell(Hive,BigData->List);
  2178. ASSERT( Plist != NULL );
  2179. for(j=0;j<BigData->Count;j++) {
  2180. Plist[j] = HvShiftCell(Hive,Plist[j]);
  2181. }
  2182. BigData->List = HvShiftCell(Hive,BigData->List);
  2183. }
  2184. }
  2185. if( pcell->u.KeyValue.Data != HCELL_NIL ) {
  2186. pcell->u.KeyValue.Data = HvShiftCell(Hive,pcell->u.KeyValue.Data);
  2187. }
  2188. }
  2189. List->u.KeyList[i] = HvShiftCell(Hive,List->u.KeyList[i]);
  2190. }
  2191. }
  2192. VOID
  2193. CmpShiftSecurityCells(PHHIVE Hive)
  2194. {
  2195. PCM_KEY_NODE RootNode;
  2196. PCM_KEY_SECURITY SecurityCell;
  2197. HCELL_INDEX ListAnchor;
  2198. HCELL_INDEX NextCell;
  2199. ASSERT( Hive->ReleaseCellRoutine == NULL );
  2200. RootNode = (PCM_KEY_NODE) HvGetCell(Hive, Hive->BaseBlock->RootCell);
  2201. ASSERT( RootNode != NULL );
  2202. ListAnchor = NextCell = RootNode->Security;
  2203. do {
  2204. SecurityCell = (PCM_KEY_SECURITY) HvGetCell(Hive, NextCell);
  2205. ASSERT( SecurityCell != NULL );
  2206. NextCell = SecurityCell->Flink;
  2207. SecurityCell->Flink = HvShiftCell(Hive,SecurityCell->Flink);
  2208. SecurityCell->Blink = HvShiftCell(Hive,SecurityCell->Blink);
  2209. } while ( NextCell != ListAnchor );
  2210. }