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.

1308 lines
29 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. keystruct.c
  5. Abstract:
  6. Routines that manage the memdb key structures.
  7. Author:
  8. Jim Schmidt (jimschm) 8-Aug-1996
  9. Revision History:
  10. mvander 13-Aug-1999 major restructuring
  11. jimschm 30-Dec-1998 Hacked in AVL balancing
  12. jimschm 23-Sep-1998 Proxy nodes, so MemDbMoveTree can replace end nodes too
  13. jimschm 29-May-1998 Ability to replace center nodes in key strings
  14. jimschm 21-Oct-1997 Split from memdb.c
  15. --*/
  16. #include "pch.h"
  17. #include "memdbp.h"
  18. #include "bintree.h"
  19. // LINT - in the next function keystruct is thought to be possibly NULL.
  20. // If we examine the code we'll see that this is not a possibility so...
  21. //lint -save -e794
  22. UINT g_TotalKeys = 0;
  23. UINT
  24. pAllocKeyStruct (
  25. IN PCWSTR KeyName,
  26. IN UINT PrevLevelIndex
  27. )
  28. /*++
  29. Routine Description:
  30. pAllocKeyStruct allocates a block of memory in the single
  31. heap, expanding it if necessary.
  32. The KeyName must not already be in the tree, and
  33. PrevLevelIndex must point to a valid UINT Index
  34. variable.
  35. This function may move the database buffer. Pointers
  36. into the database might not be valid afterwards.
  37. Arguments:
  38. KeyName - The string identifying the key. It cannot
  39. contain backslashes. The new struct will
  40. be initialized and this name will be copied
  41. into the struct.
  42. PrevLevelIndex - Specifies the previous level root Index
  43. Return Value:
  44. An Index to the new structure.
  45. --*/
  46. {
  47. UINT size;
  48. PKEYSTRUCT KeyStruct = NULL;
  49. UINT Offset;
  50. UINT PrevDel;
  51. UINT TreeOffset;
  52. UINT Index;
  53. MYASSERT (g_CurrentDatabase);
  54. size = SizeOfStringW (KeyName) + KEYSTRUCT_SIZE;
  55. //
  56. // Look for free block
  57. //
  58. PrevDel = INVALID_OFFSET;
  59. Offset = g_CurrentDatabase->FirstKeyDeleted;
  60. while (Offset != INVALID_OFFSET) {
  61. KeyStruct = GetKeyStructFromOffset(Offset);
  62. MYASSERT(KeyStruct);
  63. if (KeyStruct->Size >= size && KeyStruct->Size < (size + ALLOC_TOLERANCE)) {
  64. break;
  65. }
  66. PrevDel = Offset;
  67. Offset = KeyStruct->NextDeleted;
  68. }
  69. if (Offset == INVALID_OFFSET) {
  70. //
  71. // Alloc new block if no free space
  72. //
  73. g_TotalKeys ++;
  74. Offset = DatabaseAllocBlock (size);
  75. if (Offset == INVALID_OFFSET) {
  76. return INVALID_OFFSET;
  77. }
  78. #ifdef DEBUG
  79. //
  80. // if we are in debug mode, and we are using debug structs, set
  81. // pointer normally and set Signature DWORD. if we are not using
  82. // debug structs, then set pointer to 4 bytes below actual offset,
  83. // so all members are shifted down.
  84. //
  85. if (g_UseDebugStructs) {
  86. KeyStruct = (PKEYSTRUCT)OFFSET_TO_PTR(Offset);
  87. KeyStruct->Signature = KEYSTRUCT_SIGNATURE;
  88. } else {
  89. KeyStruct = (PKEYSTRUCT)OFFSET_TO_PTR(Offset - KEYSTRUCT_HEADER_SIZE);
  90. }
  91. #else
  92. KeyStruct = (PKEYSTRUCT)OFFSET_TO_PTR(Offset);
  93. #endif
  94. KeyStruct->Size = size;
  95. } else {
  96. //
  97. // Delink free block if recovering free space
  98. //
  99. if (PrevDel != INVALID_OFFSET) {
  100. GetKeyStructFromOffset(PrevDel)->NextDeleted = KeyStruct->NextDeleted;
  101. } else {
  102. g_CurrentDatabase->FirstKeyDeleted = KeyStruct->NextDeleted;
  103. }
  104. #ifdef DEBUG
  105. KeyStruct->KeyFlags &= ~KSF_DELETED;
  106. #endif
  107. }
  108. //
  109. // Init new block
  110. //
  111. KeyStruct->DataStructIndex = INVALID_OFFSET;
  112. KeyStruct->NextLevelTree = INVALID_OFFSET;
  113. KeyStruct->PrevLevelIndex = PrevLevelIndex;
  114. KeyStruct->Value = 0;
  115. KeyStruct->KeyFlags = 0;
  116. KeyStruct->DataFlags = 0;
  117. StringPasCopyConvertTo (KeyStruct->KeyName, KeyName);
  118. Index = AddKeyOffsetToBuffer(Offset);
  119. //
  120. // Put it in the tree
  121. //
  122. TreeOffset = (KeyStruct->PrevLevelIndex == INVALID_OFFSET) ?
  123. g_CurrentDatabase->FirstLevelTree :
  124. GetKeyStruct(KeyStruct->PrevLevelIndex)->NextLevelTree;
  125. if (TreeOffset == INVALID_OFFSET) {
  126. TreeOffset = BinTreeNew();
  127. if (TreeOffset == INVALID_OFFSET) {
  128. return INVALID_OFFSET;
  129. }
  130. if (PrevLevelIndex == INVALID_OFFSET) {
  131. g_CurrentDatabase->FirstLevelTree = TreeOffset;
  132. } else {
  133. GetKeyStruct(PrevLevelIndex)->NextLevelTree = TreeOffset;
  134. }
  135. }
  136. if (!BinTreeAddNode(TreeOffset, Index)) {
  137. return INVALID_OFFSET;
  138. }
  139. return Index;
  140. }
  141. //lint -restore
  142. UINT
  143. pNewKey (
  144. IN PCWSTR KeyStr,
  145. IN BOOL Endpoint
  146. )
  147. /*++
  148. Routine Description:
  149. NewKey allocates a key struct off our heap, and links it into the binary
  150. tree. KeyStr must be a full key path, and any part of the path that does
  151. not exist will be created. KeyStr must not already exist (though parts
  152. of it can exist).
  153. This function may move the database buffer. Pointers
  154. into the database might not be valid afterwards.
  155. Arguments:
  156. KeyStr - The full path to the value, separated by backslashes.
  157. Each string between backslashes will cause a key
  158. struct to be allocated and linked. Some of the
  159. structs may already have been allocated.
  160. Endpoint - Specifies TRUE if new node is an endpoint, or FALSE if
  161. it is not.
  162. Return Value:
  163. An Index to the last node of the new structure, or
  164. INVALID_OFFSET if the key could not be allocated.
  165. --*/
  166. {
  167. WCHAR Path[MEMDB_MAX];
  168. PWSTR p;
  169. PWSTR Start, End;
  170. UINT Index, ThisLevelTree;
  171. PKEYSTRUCT KeyStruct;
  172. UINT PrevLevelIndex;
  173. BOOL NewNodeCreated = FALSE;
  174. MYASSERT (g_CurrentDatabase);
  175. StringCopyW (Path, KeyStr);
  176. End = Path;
  177. ThisLevelTree = g_CurrentDatabase->FirstLevelTree;
  178. PrevLevelIndex = INVALID_OFFSET;
  179. do {
  180. // Split string at backslash
  181. Start = End;
  182. p = wcschr (End, L'\\');
  183. if (p) {
  184. End = p + 1;
  185. *p = 0;
  186. }
  187. else
  188. End = NULL;
  189. // Look in tree for key
  190. if (!NewNodeCreated) {
  191. Index = FindKeyStructInTree (ThisLevelTree, Start, FALSE);
  192. } else {
  193. Index = INVALID_OFFSET;
  194. }
  195. if (Index == INVALID_OFFSET) {
  196. // Add a new key if it was not found
  197. Index = pAllocKeyStruct (Start, PrevLevelIndex);
  198. if (Index == INVALID_OFFSET) {
  199. return INVALID_OFFSET;
  200. }
  201. NewNodeCreated = TRUE;
  202. }
  203. // Continue to next level
  204. KeyStruct = GetKeyStruct (Index);
  205. PrevLevelIndex = Index;
  206. ThisLevelTree = KeyStruct->NextLevelTree;
  207. } while (End);
  208. if (Endpoint) {
  209. if (!(KeyStruct->KeyFlags & KSF_ENDPOINT)) {
  210. NewNodeCreated = TRUE;
  211. }
  212. KeyStruct->KeyFlags |= KSF_ENDPOINT;
  213. if (NewNodeCreated) {
  214. (void)AddHashTableEntry (g_CurrentDatabase->HashTable, KeyStr, Index);
  215. }
  216. }
  217. return Index;
  218. }
  219. UINT
  220. NewKey (
  221. IN PCWSTR KeyStr
  222. )
  223. /*++
  224. Routine Description:
  225. creates a new key that is an endpoint.
  226. Arguments:
  227. KeyStr - The string identifying the key.
  228. Return Value:
  229. An Index to the new structure.
  230. --*/
  231. {
  232. return pNewKey (KeyStr, TRUE);
  233. }
  234. UINT
  235. NewEmptyKey (
  236. IN PCWSTR KeyStr
  237. )
  238. /*++
  239. Routine Description:
  240. creates an empty new key that is NOT an endpoint.
  241. This function may move the database buffer. Pointers
  242. into the database might not be valid afterwards.
  243. Arguments:
  244. KeyStr - The string identifying the key.
  245. Return Value:
  246. An Index to the new structure.
  247. --*/
  248. {
  249. return pNewKey (KeyStr, TRUE);
  250. }
  251. VOID
  252. pRemoveKeyFromTree (
  253. IN PKEYSTRUCT pKey
  254. )
  255. {
  256. BOOL LastNode;
  257. PUINT pTreeOffset;
  258. MYASSERT(pKey);
  259. MYASSERT (g_CurrentDatabase);
  260. if (pKey->PrevLevelIndex==INVALID_OFFSET) {
  261. pTreeOffset = &g_CurrentDatabase->FirstLevelTree;
  262. } else {
  263. pTreeOffset = &GetKeyStruct(pKey->PrevLevelIndex)->NextLevelTree;
  264. }
  265. MYASSERT(*pTreeOffset!=INVALID_OFFSET);
  266. BinTreeDeleteNode (*pTreeOffset, pKey->KeyName, &LastNode);
  267. if (LastNode) {
  268. BinTreeDestroy(*pTreeOffset);
  269. *pTreeOffset = INVALID_OFFSET;
  270. }
  271. }
  272. VOID
  273. pDeallocKeyStruct (
  274. IN UINT Index,
  275. IN BOOL ClearFlag,
  276. IN BOOL DelinkFlag,
  277. IN BOOL FreeIndexFlag
  278. )
  279. /*++
  280. Routine Description:
  281. pDeallocKeyStruct first deletes all structures pointed to by
  282. NextLevelTree. After all items are deleted from the next
  283. level, pDeallocKeyStruct optionally delinks the struct from
  284. the binary tree. Before exiting, the struct is given to the
  285. deleted block chain.
  286. Arguments:
  287. Index - An index in g_CurrentDatabase->OffsetBuffer
  288. ClearFlag - Specifies TRUE if the key struct's children are to
  289. be deleted, or FALSE if the current key struct should
  290. simply be cleaned up but left allocated.
  291. DelinkFlag - A flag indicating TRUE to delink the struct from
  292. the binary tree it is in, or FALSE if the struct is
  293. only to be added to the deleted block chain.
  294. FreeIndexFlag - This argument is only used if ClearFlag is true.
  295. It is FALSE if we do not want to free the index in
  296. g_CurrentDatabase->OffsetBuffer (i.e., we are moving the key and we do
  297. not want to deallocate the space in the buffer), or
  298. TRUE if we are just deleting the key, so we no longer
  299. need the g_CurrentDatabase->OffsetBuffer space at Index.
  300. Return Value:
  301. none
  302. --*/
  303. {
  304. PKEYSTRUCT KeyStruct;
  305. UINT KeyIndex, TreeEnum;
  306. WCHAR TempStr[MEMDB_MAX];
  307. PUINT linkageList;
  308. UINT linkageSize;
  309. BYTE instance;
  310. BYTE oldDbIndex;
  311. MYASSERT (g_CurrentDatabase);
  312. KeyStruct = GetKeyStruct (Index);
  313. if (FreeIndexFlag && (KeyStruct->DataFlags & DATAFLAG_DOUBLELINK)) {
  314. //
  315. // we have some double linkage here. Let's go to the other
  316. // key and remove the linkage that points to this one
  317. //
  318. for (instance = 0; instance <= DATAFLAG_INSTANCEMASK; instance ++) {
  319. // First, retrieve the linkage list
  320. linkageSize = 0;
  321. linkageList = (PUINT) KeyStructGetBinaryData (
  322. Index,
  323. DATAFLAG_DOUBLELINK,
  324. instance,
  325. &linkageSize,
  326. NULL
  327. );
  328. if (linkageList) {
  329. oldDbIndex = g_CurrentDatabaseIndex;
  330. while (linkageSize) {
  331. SelectDatabase (GET_DATABASE (*linkageList));
  332. KeyStructDeleteLinkage (
  333. GET_INDEX (*linkageList),
  334. DATAFLAG_DOUBLELINK,
  335. instance,
  336. GET_EXTERNAL_INDEX (Index),
  337. FALSE
  338. );
  339. linkageSize -= SIZEOF (UINT);
  340. linkageList ++;
  341. if (linkageSize < SIZEOF (UINT)) {
  342. break;
  343. }
  344. }
  345. SelectDatabase (oldDbIndex);
  346. }
  347. }
  348. }
  349. if (KeyStruct->KeyFlags & KSF_ENDPOINT) {
  350. //
  351. // Remove endpoints from hash table and free key data
  352. //
  353. if (PrivateBuildKeyFromIndex (0, Index, TempStr, NULL, NULL, NULL)) {
  354. RemoveHashTableEntry (g_CurrentDatabase->HashTable, TempStr);
  355. }
  356. KeyStructFreeAllData (KeyStruct);
  357. KeyStruct->KeyFlags &= ~KSF_ENDPOINT;
  358. }
  359. if (ClearFlag) {
  360. //
  361. // Call recursively if there are sublevels to this key
  362. //
  363. if (KeyStruct->NextLevelTree != INVALID_OFFSET) {
  364. KeyIndex = GetFirstIndex(KeyStruct->NextLevelTree, &TreeEnum);
  365. while (KeyIndex != INVALID_OFFSET) {
  366. pDeallocKeyStruct (KeyIndex, TRUE, FALSE, FreeIndexFlag);
  367. KeyIndex = GetNextIndex (&TreeEnum);
  368. }
  369. BinTreeDestroy(KeyStruct->NextLevelTree);
  370. }
  371. //
  372. // Remove the item from its binary tree
  373. //
  374. if (DelinkFlag) {
  375. pRemoveKeyFromTree(KeyStruct);
  376. }
  377. //
  378. // Donate block to free space unless caller does not
  379. // want child structs freed.
  380. //
  381. KeyStruct->NextDeleted = g_CurrentDatabase->FirstKeyDeleted;
  382. g_CurrentDatabase->FirstKeyDeleted = KeyIndexToOffset(Index);
  383. #ifdef DEBUG
  384. KeyStruct->KeyFlags |= KSF_DELETED;
  385. #endif
  386. // let's empty the keystruct (for better compression)
  387. ZeroMemory (KeyStruct->KeyName, KeyStruct->Size - KEYSTRUCT_SIZE);
  388. if (FreeIndexFlag) {
  389. RemoveKeyOffsetFromBuffer(Index);
  390. }
  391. }
  392. }
  393. BOOL
  394. PrivateDeleteKeyByIndex (
  395. IN UINT Index
  396. )
  397. /*++
  398. Routine Description:
  399. PrivateDeleteKeyByIndex will completely destroy the key struct
  400. that Index points to (along with all sub-levels. Furthermore,
  401. it goes back recursively and removes the parent structures as well
  402. if they no longer have a child (the current one was the only one).
  403. Arguments:
  404. Index - Index of the key structure.
  405. Return Value:
  406. TRUE if successfull, FALSE otherwise
  407. --*/
  408. {
  409. PKEYSTRUCT keyStruct;
  410. UINT prevLevelIndex;
  411. BOOL result = TRUE;
  412. keyStruct = GetKeyStruct (Index);
  413. prevLevelIndex = keyStruct->PrevLevelIndex;
  414. pDeallocKeyStruct (Index, TRUE, TRUE, TRUE);
  415. if (prevLevelIndex != INVALID_OFFSET) {
  416. keyStruct = GetKeyStruct (prevLevelIndex);
  417. if (keyStruct->NextLevelTree != INVALID_OFFSET) {
  418. result = PrivateDeleteKeyByIndex (prevLevelIndex);
  419. }
  420. }
  421. return result;
  422. }
  423. BOOL
  424. DeleteKey (
  425. IN PCWSTR KeyStr,
  426. IN UINT TreeOffset,
  427. IN BOOL MustMatch
  428. )
  429. /*++
  430. Routine Description:
  431. DeleteKey takes a key path and puts the key struct in the deleted
  432. block chain. Any sub-levels are deleted as well.
  433. Arguments:
  434. KeyStr - The full path to the value, separated by backslashes.
  435. TreeOffset - A pointer to the level's binary tree root variable.
  436. MustMatch - A flag indicating if the delete only applies to
  437. end points or if any matching struct is to be deleted.
  438. TRUE indicates only endpoints can be deleted.
  439. Return Value:
  440. none
  441. --*/
  442. {
  443. WCHAR Path[MEMDB_MAX];
  444. PWSTR p;
  445. PWSTR Start, End;
  446. UINT Index, NextIndex, TreeEnum=INVALID_OFFSET;
  447. PKEYSTRUCT KeyStruct;
  448. StringCopyW (Path, KeyStr);
  449. End = Path;
  450. //
  451. // Split string at backslash
  452. //
  453. Start = End;
  454. p = wcschr (End, L'\\');
  455. if (p) {
  456. End = p + 1;
  457. *p = 0;
  458. } else {
  459. End = NULL;
  460. }
  461. //
  462. // Look at this level for the very first key
  463. //
  464. Index = FindKeyStructUsingTreeOffset (TreeOffset, &TreeEnum, Start);
  465. //
  466. // If this is the last level, delete the matching keys
  467. // (may need to be endpoints if MustMatch is TRUE)
  468. //
  469. if (!End) {
  470. while (Index != INVALID_OFFSET) {
  471. KeyStruct = GetKeyStruct (Index);
  472. NextIndex = FindKeyStructUsingTreeOffset (TreeOffset, &TreeEnum, Start);
  473. //
  474. // If must match and lower levels exist, don't delete, just turn
  475. // off the endpoint flag
  476. //
  477. if (MustMatch && KeyStruct->NextLevelTree != INVALID_OFFSET) {
  478. // Call to clean up, not to delink or recurse
  479. pDeallocKeyStruct (Index, FALSE, FALSE, FALSE);
  480. }
  481. //
  482. // Else delete the struct if an endpoint or don't care about
  483. // endpoints
  484. //
  485. else if (!MustMatch || (KeyStruct->KeyFlags & KSF_ENDPOINT)) {
  486. // Call to free the entire key struct and all children
  487. pDeallocKeyStruct (Index, TRUE, TRUE, TRUE);
  488. }
  489. Index = NextIndex;
  490. }
  491. }
  492. //
  493. // Otherwise recursively examine next level for each match
  494. //
  495. else {
  496. while (Index != INVALID_OFFSET) {
  497. //
  498. // Delete all matching subkeys
  499. //
  500. NextIndex = FindKeyStructUsingTreeOffset (TreeOffset, &TreeEnum, Start);
  501. KeyStruct = GetKeyStruct (Index);
  502. DeleteKey (End, KeyStruct->NextLevelTree, MustMatch);
  503. //
  504. // If this is not an endpoint and has no children, delete it
  505. //
  506. if (KeyStruct->NextLevelTree == INVALID_OFFSET &&
  507. !(KeyStruct->KeyFlags & KSF_ENDPOINT)
  508. ) {
  509. // Call to free the entire key struct
  510. pDeallocKeyStruct (Index, TRUE, TRUE, TRUE);
  511. }
  512. //
  513. // Continue looking in this level for another match
  514. //
  515. Index = NextIndex;
  516. }
  517. }
  518. return TRUE;
  519. }
  520. VOID
  521. pRemoveHashEntriesForNode (
  522. IN PCWSTR Root,
  523. IN UINT Index
  524. )
  525. /*++
  526. Routine Description:
  527. pRemoveHashEntriesFromNode removes all hash table entries from all children
  528. of the specified node. This function is called recursively.
  529. Arguments:
  530. Root - Specifies the root string that corresponds with Index. This must
  531. also contain the temporary hive root.
  532. Index - Specifies the Index of the node to process. The node and all of
  533. its children will be removed from the hash table.
  534. Return Value:
  535. None.
  536. --*/
  537. {
  538. UINT ChildIndex, TreeEnum;
  539. PKEYSTRUCT KeyStruct;
  540. WCHAR ChildRoot[MEMDB_MAX];
  541. PWSTR End;
  542. MYASSERT (g_CurrentDatabase);
  543. //
  544. // Remove hash entry if this root is an endpoint
  545. //
  546. KeyStruct = GetKeyStruct (Index);
  547. if (KeyStruct->KeyFlags & KSF_ENDPOINT) {
  548. RemoveHashTableEntry (g_CurrentDatabase->HashTable, Root);
  549. #ifdef DEBUG
  550. {
  551. UINT HashIndex;
  552. HashIndex = FindStringInHashTable (g_CurrentDatabase->HashTable, Root);
  553. if (HashIndex != INVALID_OFFSET) {
  554. DEBUGMSG ((DBG_WARNING, "Memdb move duplicate: %s", Root));
  555. }
  556. }
  557. #endif
  558. }
  559. //
  560. // Recurse for all children, removing hash entries for all endpoints found
  561. //
  562. StringCopyW (ChildRoot, Root);
  563. End = GetEndOfStringW (ChildRoot);
  564. *End = L'\\';
  565. End++;
  566. *End = 0;
  567. ChildIndex = GetFirstIndex(KeyStruct->NextLevelTree, &TreeEnum);
  568. while (ChildIndex != INVALID_OFFSET) {
  569. KeyStruct = GetKeyStruct (ChildIndex);
  570. StringPasCopyConvertFrom (End, KeyStruct->KeyName);
  571. pRemoveHashEntriesForNode (ChildRoot, ChildIndex);
  572. ChildIndex = GetNextIndex(&TreeEnum);
  573. }
  574. }
  575. VOID
  576. pAddHashEntriesForNode (
  577. IN PCWSTR Root,
  578. IN UINT Index,
  579. IN BOOL AddRoot
  580. )
  581. /*++
  582. Routine Description:
  583. pAddHashEntriesForNode adds hash table entries for the specified root and
  584. all of its children.
  585. Arguments:
  586. Root - Specifies the root string that corresponds to Index. This string
  587. must also include the temporary hive root.
  588. Index - Specifies the node Index to begin processing. The node and all
  589. of its children are added to the hash table.
  590. AddRoot - Specifies TRUE if the root should be added to the hash table,
  591. FALSE otherwise.
  592. Return Value:
  593. None.
  594. --*/
  595. {
  596. UINT ChildIndex, TreeEnum;
  597. PKEYSTRUCT KeyStruct;
  598. WCHAR ChildRoot[MEMDB_MAX];
  599. PWSTR End;
  600. UINT HashIndex;
  601. MYASSERT (g_CurrentDatabase);
  602. //
  603. // Add hash entry if this root is an endpoint
  604. //
  605. KeyStruct = GetKeyStruct (Index);
  606. if (AddRoot && KeyStruct->KeyFlags & KSF_ENDPOINT) {
  607. HashIndex = FindStringInHashTable (g_CurrentDatabase->HashTable, Root);
  608. if (HashIndex != Index) {
  609. #ifdef DEBUG
  610. if (HashIndex != INVALID_OFFSET) {
  611. DEBUGMSG ((DBG_WARNING, "Memdb duplicate: %s", Root));
  612. }
  613. #endif
  614. AddHashTableEntry (g_CurrentDatabase->HashTable, Root, Index);
  615. }
  616. }
  617. //
  618. // Recurse for all children, adding hash entries for all endpoints found
  619. //
  620. StringCopyW (ChildRoot, Root);
  621. End = GetEndOfStringW (ChildRoot);
  622. *End = L'\\';
  623. End++;
  624. *End = 0;
  625. ChildIndex = GetFirstIndex(KeyStruct->NextLevelTree, &TreeEnum);
  626. while (ChildIndex != INVALID_OFFSET) {
  627. KeyStruct = GetKeyStruct(ChildIndex);
  628. StringPasCopyConvertFrom (End, KeyStruct->KeyName);
  629. pAddHashEntriesForNode(ChildRoot, ChildIndex, TRUE);
  630. ChildIndex = GetNextIndex(&TreeEnum);
  631. }
  632. }
  633. #ifdef DEBUG
  634. //
  635. // in non-DEBUG mode, GetKeyStructFromOffset
  636. // and GetKeyStruct are implemented as macros
  637. //
  638. PKEYSTRUCT
  639. GetKeyStructFromOffset (
  640. IN UINT Offset
  641. )
  642. /*++
  643. Routine Description:
  644. GetKeyStruct returns a pointer given an Offset. The debug version
  645. checks the signature and validity of each Index. It is assumed that
  646. Offset is always valid.
  647. Arguments:
  648. Offset - Specifies the Offset to the node
  649. Return Value:
  650. The pointer to the node.
  651. --*/
  652. {
  653. PKEYSTRUCT KeyStruct;
  654. MYASSERT (g_CurrentDatabase);
  655. if (Offset == INVALID_OFFSET) {
  656. DEBUGMSG ((DBG_ERROR, "Invalid root accessed in GetKeyStruct at offset %u", Offset));
  657. return NULL;
  658. }
  659. if (!g_CurrentDatabase) {
  660. DEBUGMSG ((DBG_ERROR, "Attempt to access non-existent buffer at %u", Offset));
  661. return NULL;
  662. }
  663. if (Offset > g_CurrentDatabase->End) {
  664. DEBUGMSG ((DBG_ERROR, "Access beyond length of buffer in GetKeyStruct (offset %u)", Offset));
  665. return NULL;
  666. }
  667. if (!g_UseDebugStructs) {
  668. KeyStruct = (PKEYSTRUCT) OFFSET_TO_PTR (Offset - KEYSTRUCT_HEADER_SIZE);
  669. return KeyStruct;
  670. }
  671. KeyStruct = (PKEYSTRUCT) OFFSET_TO_PTR (Offset);
  672. if (KeyStruct->Signature != KEYSTRUCT_SIGNATURE) {
  673. DEBUGMSG ((DBG_ERROR, "Signature does not match in GetKeyStruct at offset %u!", Offset));
  674. return NULL;
  675. }
  676. return KeyStruct;
  677. }
  678. PKEYSTRUCT
  679. GetKeyStruct (
  680. IN UINT Index
  681. )
  682. /*++
  683. Routine Description:
  684. GetKeyStruct returns a pointer given an Index. The debug version
  685. checks the signature and validity of each Index. It is assumed that Index
  686. is always valid.
  687. Arguments:
  688. Index - Specifies the Index to the node
  689. Return Value:
  690. The pointer to the node.
  691. --*/
  692. {
  693. UINT Offset;
  694. if (Index == INVALID_OFFSET) {
  695. DEBUGMSG ((DBG_ERROR, "Invalid root accessed in GetKeyStruct at index %u", Index));
  696. return NULL;
  697. }
  698. Offset = KeyIndexToOffset(Index);
  699. if (Offset == INVALID_OFFSET) {
  700. return NULL;
  701. }
  702. return GetKeyStructFromOffset(Offset);
  703. }
  704. #endif
  705. BOOL
  706. PrivateBuildKeyFromIndex (
  707. IN UINT StartLevel, // zero-based
  708. IN UINT TailIndex,
  709. OUT PWSTR Buffer, OPTIONAL
  710. OUT PUINT ValPtr, OPTIONAL
  711. OUT PUINT UserFlagsPtr, OPTIONAL
  712. OUT PUINT Chars OPTIONAL
  713. )
  714. /*++
  715. Routine Description:
  716. PrivateBuildKeyFromIndex generates the key string given an Index. The
  717. caller can specify the start level to skip root nodes. It is assumed that
  718. TailIndex is always valid.
  719. Arguments:
  720. StartLevel - Specifies the zero-based level to begin building the key
  721. string. This is used to skip the root portion of the key
  722. string.
  723. TailIndex - Specifies the Index to the last level of the key string.
  724. Buffer - Receives the key string, must be able to hold MEMDB_MAX
  725. characters.
  726. ValPtr - Receives the key's value
  727. UserFlagsPtr - Receives the user flags
  728. Chars - Receives the number of characters in Buffer
  729. Return Value:
  730. TRUE if the key was build properly, FALSE otherwise.
  731. --*/
  732. {
  733. static UINT Indices[MEMDB_MAX];
  734. PKEYSTRUCT KeyStruct;
  735. UINT CurrentIndex;
  736. UINT IndexEnd;
  737. UINT IndexStart;
  738. register PWSTR p;
  739. //
  740. // Build string
  741. //
  742. IndexEnd = MEMDB_MAX;
  743. IndexStart = MEMDB_MAX;
  744. CurrentIndex = TailIndex;
  745. while (CurrentIndex != INVALID_OFFSET) {
  746. //
  747. // Record offset
  748. //
  749. IndexStart--;
  750. Indices[IndexStart] = CurrentIndex;
  751. //
  752. // Dec for start level and go to parent
  753. //
  754. KeyStruct = GetKeyStruct (CurrentIndex);
  755. if (!KeyStruct) {
  756. return FALSE;
  757. }
  758. CurrentIndex = KeyStruct->PrevLevelIndex;
  759. }
  760. //
  761. // Filter for "string is not long enough"
  762. //
  763. IndexStart += StartLevel;
  764. if (IndexStart >= IndexEnd) {
  765. return FALSE;
  766. }
  767. //
  768. // Transfer node's value and flags to caller's variables
  769. //
  770. if (ValPtr) {
  771. KeyStructGetValue (GetKeyStruct(TailIndex), ValPtr);
  772. }
  773. if (UserFlagsPtr) {
  774. KeyStructGetFlags (GetKeyStruct(TailIndex), UserFlagsPtr);
  775. }
  776. //
  777. // Copy each piece of the string to Buffer and calculate character count
  778. //
  779. if (Buffer) {
  780. p = Buffer;
  781. for (CurrentIndex = IndexStart ; CurrentIndex < IndexEnd ; CurrentIndex++) {
  782. KeyStruct = GetKeyStruct (Indices[CurrentIndex]);
  783. CopyMemory(p, KeyStruct->KeyName + 1, *KeyStruct->KeyName * sizeof(WCHAR));
  784. p += *KeyStruct->KeyName;
  785. *p++ = L'\\';
  786. }
  787. p--;
  788. *p = 0;
  789. if (Chars) {
  790. *Chars = (UINT)(((UBINT)p - (UBINT)Buffer) / sizeof (WCHAR));
  791. }
  792. } else if (Chars) {
  793. *Chars = 0;
  794. for (CurrentIndex = IndexStart ; CurrentIndex < IndexEnd ; CurrentIndex++) {
  795. KeyStruct = GetKeyStruct (Indices[CurrentIndex]);
  796. *Chars += StringPasCharCount(KeyStruct->KeyName) + 1;
  797. }
  798. *Chars -= 1;
  799. }
  800. return TRUE;
  801. }
  802. BOOL
  803. KeyStructSetInsertionOrdered (
  804. IN PKEYSTRUCT pKey
  805. )
  806. /*++
  807. Routine Description:
  808. KeyStructSetInsertionOrdered sets the enumeration order of the children
  809. of Key to be in the order they were inserted.
  810. This function may move the database buffer. Pointers
  811. into the database might not be valid afterwards.
  812. Arguments:
  813. Key - key to make insertion ordered
  814. Return Value:
  815. TRUE if successful, FALSE otherwise.
  816. --*/
  817. {
  818. return BinTreeSetInsertionOrdered(pKey->NextLevelTree);
  819. }
  820. UINT
  821. GetFirstIndex (
  822. IN UINT TreeOffset,
  823. OUT PUINT pTreeEnum
  824. )
  825. /*++
  826. Routine Description:
  827. GetFirstIndex walks down the left side of the binary tree
  828. pointed to by TreeOffset, and returns the left-most node.
  829. Arguments:
  830. TreeOffset - An offset to the root of the tree
  831. TreeEnum - a pointer to a UINT which will hold enumeration
  832. information for future calls of GetNextIndex
  833. Return Value:
  834. An Index to the leftmost structure, or INVALID_OFFSET if the
  835. root was invalid.
  836. --*/
  837. {
  838. return BinTreeEnumFirst(TreeOffset, pTreeEnum);
  839. }
  840. UINT
  841. GetNextIndex (
  842. IN OUT PUINT pTreeEnum
  843. )
  844. /*++
  845. Routine Description:
  846. GetNextIndex traverses the binary tree in order.
  847. Arguments:
  848. TreeEnum - Enumerator filled by GetFirstIndex which
  849. will be changed by this function
  850. Return Value:
  851. An Index to the next structure, or INVALID_OFFSET if the
  852. end is reached.
  853. --*/
  854. {
  855. return BinTreeEnumNext(pTreeEnum);
  856. }
  857. UINT KeyStructGetChildCount (
  858. IN PKEYSTRUCT pKey
  859. )
  860. {
  861. if (!pKey) {
  862. return 0;
  863. }
  864. return BinTreeSize(pKey->NextLevelTree);
  865. }
  866. UINT
  867. FindKeyStructInTree (
  868. IN UINT TreeOffset,
  869. IN PWSTR KeyName,
  870. IN BOOL IsPascalString
  871. )
  872. /*++
  873. Routine Description:
  874. FindKeyStructInTree takes a key name and looks for the
  875. Index in the tree specified by TreeOffset. The key
  876. name must not contain backslashes.
  877. Arguments:
  878. TreeOffset - An offset to the root of the level
  879. KeyName - The name of the key to find in the binary tree
  880. (not the full key path; just the name of this level).
  881. IsPascalString - TRUE if string is in pascal format (char
  882. count is first WCHAR, no null terminator) otherwise FALSE
  883. Return Value:
  884. An Index to the structure, or INVALID_OFFSET if the key
  885. was not found.
  886. --*/
  887. {
  888. UINT Index;
  889. if (!IsPascalString) {
  890. StringPasConvertTo(KeyName);
  891. }
  892. Index = BinTreeFindNode(TreeOffset, KeyName);
  893. if (!IsPascalString) {
  894. StringPasConvertFrom(KeyName);
  895. }
  896. return Index;
  897. }
  898. #ifdef DEBUG
  899. BOOL
  900. CheckLevel(UINT TreeOffset,
  901. UINT PrevLevelIndex
  902. )
  903. {
  904. PKEYSTRUCT pKey;
  905. UINT KeyIndex, TreeEnum;
  906. WCHAR key[MEMDB_MAX];
  907. if (TreeOffset==INVALID_OFFSET) {
  908. return TRUE;
  909. }
  910. BinTreeCheck(TreeOffset);
  911. #if MEMDB_VERBOSE
  912. if (PrevLevelIndex!=INVALID_OFFSET) {
  913. wprintf(L"children of %.*s:\n",*GetKeyStruct(PrevLevelIndex)->KeyName,GetKeyStruct(PrevLevelIndex)->KeyName+1);
  914. } else {
  915. printf("top level children:\n");
  916. }
  917. BinTreePrint(TreeOffset);
  918. #endif
  919. if ((KeyIndex=BinTreeEnumFirst(TreeOffset,&TreeEnum))!=INVALID_OFFSET) {
  920. do {
  921. pKey=GetKeyStruct(KeyIndex);
  922. if (pKey->PrevLevelIndex!=PrevLevelIndex) {
  923. wprintf(L"MemDbCheckDatabase: PrevLevelIndex of Keystruct %s incorrect!", StringPasCopyConvertFrom (key, pKey->KeyName));
  924. }
  925. if (!CheckLevel(pKey->NextLevelTree, KeyIndex)) {
  926. wprintf(L"Child tree of %s bad!\n", StringPasCopyConvertFrom (key, pKey->KeyName));
  927. }
  928. } while ((KeyIndex=BinTreeEnumNext(&TreeEnum))!=INVALID_OFFSET);
  929. } else {
  930. printf("MemDbCheckDatabase: non-null binary tree has no children!");
  931. return FALSE;
  932. }
  933. return TRUE;
  934. }
  935. #endif