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.

3705 lines
86 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. bintree.c
  5. Abstract:
  6. Routines that manage the memdb binary tree structures.
  7. Author:
  8. Jim Schmidt (jimschm) 8-Aug-1996
  9. Revision History:
  10. jimschm 30-Dec-1998 Hacked in AVL balancing
  11. jimschm 23-Sep-1998 Proxy nodes, so MemDbMoveTree can replace end nodes too
  12. jimschm 29-May-1998 Ability to replace center nodes in key strings
  13. jimschm 21-Oct-1997 Split from memdb.c
  14. --*/
  15. #include "pch.h"
  16. #include "memdbp.h"
  17. #ifndef UNICODE
  18. #error UNICODE required
  19. #endif
  20. #define MAX_MEMDB_SIZE 0x08000000 //128 MB
  21. #define KSF_FLAGS_TO_COPY (KSF_USERFLAG_MASK|KSF_ENDPOINT|KSF_BINARY|KSF_PROXY_NODE)
  22. DWORD
  23. pNewKey (
  24. IN PCWSTR KeyStr,
  25. IN PCWSTR KeyStrWithHive,
  26. IN BOOL Endpoint
  27. );
  28. DWORD
  29. pAllocKeyToken (
  30. IN PCWSTR KeyName,
  31. OUT PINT AdjustFactor
  32. );
  33. VOID
  34. pDeallocToken (
  35. IN DWORD Token
  36. );
  37. DWORD
  38. pFindPatternKeyWorker (
  39. IN PCWSTR SubKey,
  40. IN PCWSTR End,
  41. IN DWORD RootOffset,
  42. IN BOOL EndPatternAllowed
  43. );
  44. #ifdef DEBUG
  45. VOID
  46. pDumpTree (
  47. IN DWORD Root,
  48. IN PCSTR Title OPTIONAL
  49. );
  50. VOID
  51. pCheckBalanceFactors (
  52. IN DWORD Root
  53. );
  54. DWORD g_SingleRotations = 0;
  55. DWORD g_DoubleRotations = 0;
  56. DWORD g_Deletions = 0;
  57. DWORD g_Insertions = 0;
  58. #define INCSTAT(x) (x++)
  59. #else
  60. #define pDumpTree(arg1,arg2)
  61. #define INCSTAT(x)
  62. #endif
  63. #define ANTIDIRECTION(x) ((x)^KSF_BALANCE_MASK)
  64. #define FLAGS_TO_INT(x) ((INT) ((x)==KSF_LEFT_HEAVY ? -1 : (x)==KSF_RIGHT_HEAVY ? 1 : 0))
  65. #define INT_TO_FLAGS(x) ((DWORD) ((x)==-1 ? KSF_LEFT_HEAVY : (x)==1 ? KSF_RIGHT_HEAVY : 0))
  66. //
  67. // Implementation
  68. //
  69. DWORD
  70. pRotateOnce (
  71. OUT PDWORD RootPtr,
  72. IN DWORD ParentOffset,
  73. IN DWORD PivotOffset,
  74. IN DWORD Direction
  75. )
  76. {
  77. PKEYSTRUCT GrandParent;
  78. PKEYSTRUCT Parent;
  79. PKEYSTRUCT Pivot;
  80. PKEYSTRUCT TempKey;
  81. DWORD Temp;
  82. INT OldRootBalance;
  83. INT NewRootBalance;
  84. DWORD OldDir, NewDir;
  85. INCSTAT(g_SingleRotations);
  86. MYASSERT (ParentOffset != INVALID_OFFSET);
  87. MYASSERT (PivotOffset != INVALID_OFFSET);
  88. Parent = GetKeyStruct (ParentOffset);
  89. Pivot = GetKeyStruct (PivotOffset);
  90. if (Direction == KSF_LEFT_HEAVY) {
  91. //
  92. // Perform LL rotation
  93. //
  94. Temp = Pivot->Right;
  95. Pivot->Right = ParentOffset;
  96. Pivot->Parent = Parent->Parent;
  97. Parent->Parent = PivotOffset;
  98. Parent->Left = Temp;
  99. } else {
  100. //
  101. // Preform RR rotation
  102. //
  103. Temp = Pivot->Left;
  104. Pivot->Left = ParentOffset;
  105. Pivot->Parent = Parent->Parent;
  106. Parent->Parent = PivotOffset;
  107. Parent->Right = Temp;
  108. }
  109. if (Temp != INVALID_OFFSET) {
  110. TempKey = GetKeyStruct (Temp);
  111. TempKey->Parent = ParentOffset;
  112. }
  113. OldDir = Parent->Flags & KSF_BALANCE_MASK;
  114. NewDir = Pivot->Flags & KSF_BALANCE_MASK;
  115. OldRootBalance = FLAGS_TO_INT (OldDir);
  116. NewRootBalance = FLAGS_TO_INT (NewDir);
  117. if (Direction == KSF_LEFT_HEAVY) {
  118. OldRootBalance = -(++NewRootBalance);
  119. } else {
  120. OldRootBalance = -(--NewRootBalance);
  121. }
  122. Pivot->Flags = (Pivot->Flags & (~KSF_BALANCE_MASK)) | INT_TO_FLAGS(NewRootBalance);
  123. Parent->Flags = (Parent->Flags & (~KSF_BALANCE_MASK)) | INT_TO_FLAGS(OldRootBalance);
  124. //
  125. // Fix grandparent/root to parent linkage
  126. //
  127. if (Pivot->Parent != INVALID_OFFSET) {
  128. GrandParent = GetKeyStruct (Pivot->Parent);
  129. if (GrandParent->Left == ParentOffset) {
  130. GrandParent->Left = PivotOffset;
  131. } else {
  132. GrandParent->Right = PivotOffset;
  133. }
  134. } else {
  135. *RootPtr = PivotOffset;
  136. }
  137. return PivotOffset;
  138. }
  139. DWORD
  140. pRotateTwice (
  141. OUT PDWORD RootPtr,
  142. IN DWORD ParentOffset,
  143. IN DWORD PivotOffset,
  144. IN DWORD Direction
  145. )
  146. {
  147. PKEYSTRUCT GrandParent;
  148. PKEYSTRUCT Parent;
  149. PKEYSTRUCT Pivot;
  150. PKEYSTRUCT Child;
  151. DWORD ChildOffset;
  152. PKEYSTRUCT GrandChildLeft;
  153. PKEYSTRUCT GrandChildRight;
  154. DWORD AntiDirection;
  155. DWORD Flag;
  156. INT ParentDir;
  157. INT PivotDir;
  158. INT ChildDir;
  159. INCSTAT(g_DoubleRotations);
  160. //
  161. // Initialize pointers
  162. //
  163. MYASSERT (ParentOffset != INVALID_OFFSET);
  164. MYASSERT (PivotOffset != INVALID_OFFSET);
  165. Parent = GetKeyStruct (ParentOffset);
  166. Pivot = GetKeyStruct (PivotOffset);
  167. if (Direction == KSF_LEFT_HEAVY) {
  168. AntiDirection = KSF_RIGHT_HEAVY;
  169. ChildOffset = Pivot->Right;
  170. } else {
  171. AntiDirection = KSF_LEFT_HEAVY;
  172. ChildOffset = Pivot->Left;
  173. }
  174. MYASSERT (ChildOffset != INVALID_OFFSET);
  175. Child = GetKeyStruct (ChildOffset);
  176. if (Child->Left != INVALID_OFFSET) {
  177. GrandChildLeft = GetKeyStruct (Child->Left);
  178. } else {
  179. GrandChildLeft = NULL;
  180. }
  181. if (Child->Right != INVALID_OFFSET) {
  182. GrandChildRight = GetKeyStruct (Child->Right);
  183. } else {
  184. GrandChildRight = NULL;
  185. }
  186. //
  187. // Perform the rotation
  188. //
  189. if (Direction == KSF_LEFT_HEAVY) {
  190. //
  191. // Perform LR rotation
  192. //
  193. Child->Parent = Parent->Parent;
  194. Parent->Left = Child->Right;
  195. if (GrandChildRight) {
  196. GrandChildRight->Parent = ParentOffset;
  197. }
  198. Pivot->Right = Child->Left;
  199. if (GrandChildLeft) {
  200. GrandChildLeft->Parent = PivotOffset;
  201. }
  202. Child->Left = PivotOffset;
  203. Pivot->Parent = ChildOffset;
  204. Child->Right = ParentOffset;
  205. Parent->Parent = ChildOffset;
  206. } else {
  207. //
  208. // Preform RL rotation
  209. //
  210. Child->Parent = Parent->Parent;
  211. Parent->Right = Child->Left;
  212. if (GrandChildLeft) {
  213. GrandChildLeft->Parent = ParentOffset;
  214. }
  215. Pivot->Left = Child->Right;
  216. if (GrandChildRight) {
  217. GrandChildRight->Parent = PivotOffset;
  218. }
  219. Child->Right = PivotOffset;
  220. Pivot->Parent = ChildOffset;
  221. Child->Left = ParentOffset;
  222. Parent->Parent = ChildOffset;
  223. }
  224. //
  225. // Fix balance factors
  226. //
  227. Flag = Child->Flags & KSF_BALANCE_MASK;
  228. ChildDir = FLAGS_TO_INT (Flag);
  229. if (Direction == KSF_RIGHT_HEAVY) {
  230. ParentDir = -max (ChildDir, 0);
  231. PivotDir = -min (ChildDir, 0);
  232. } else {
  233. ParentDir = -min (ChildDir, 0);
  234. PivotDir = -max (ChildDir, 0);
  235. }
  236. Parent->Flags = Parent->Flags & (~KSF_BALANCE_MASK) | INT_TO_FLAGS(ParentDir);
  237. Pivot->Flags = Pivot->Flags & (~KSF_BALANCE_MASK) | INT_TO_FLAGS(PivotDir);
  238. Child->Flags = Child->Flags & (~KSF_BALANCE_MASK);
  239. //
  240. // Fix grandparent/root to parent linkage
  241. //
  242. if (Child->Parent != INVALID_OFFSET) {
  243. GrandParent = GetKeyStruct (Child->Parent);
  244. if (GrandParent->Left == ParentOffset) {
  245. GrandParent->Left = ChildOffset;
  246. } else {
  247. GrandParent->Right = ChildOffset;
  248. }
  249. } else {
  250. *RootPtr = ChildOffset;
  251. }
  252. return ChildOffset;
  253. }
  254. VOID
  255. pBalanceInsertion (
  256. OUT PDWORD RootPtr,
  257. IN DWORD ChangedNode,
  258. IN DWORD PivotEnd
  259. )
  260. {
  261. DWORD PrevPivot;
  262. DWORD PivotNode;
  263. PKEYSTRUCT KeyStruct;
  264. PKEYSTRUCT KeyParent;
  265. DWORD BalanceFlags;
  266. PivotNode = ChangedNode;
  267. MYASSERT (PivotNode != INVALID_OFFSET);
  268. //
  269. // Initialize previous pivot to be the changed node,
  270. // and begin balancing at its parent
  271. //
  272. PrevPivot = PivotNode;
  273. KeyStruct = GetKeyStruct (PivotNode);
  274. PivotNode = KeyStruct->Parent;
  275. //
  276. // Balance the tree starting at the changed node and going
  277. // up until PivotEnd is reached. PivotEnd is the offset to
  278. // the deepest node with a balance of non-zero.
  279. //
  280. MYASSERT (PivotNode != INVALID_OFFSET || PivotNode == PivotEnd);
  281. while (PivotNode != INVALID_OFFSET) {
  282. KeyParent = GetKeyStruct (PivotNode);
  283. BalanceFlags = KeyParent->Flags & KSF_BALANCE_MASK;
  284. if (BalanceFlags == KSF_LEFT_HEAVY) {
  285. if (KeyParent->Left == PrevPivot) {
  286. MYASSERT (KeyStruct == GetKeyStruct (PrevPivot));
  287. if (KeyStruct->Flags & KSF_LEFT_HEAVY) {
  288. //
  289. // LL rotation
  290. //
  291. pRotateOnce (RootPtr, PivotNode, PrevPivot, KSF_LEFT_HEAVY);
  292. } else if (KeyStruct->Flags & KSF_RIGHT_HEAVY) {
  293. //
  294. // LR rotation
  295. //
  296. pRotateTwice (RootPtr, PivotNode, PrevPivot, KSF_LEFT_HEAVY);
  297. }
  298. } else {
  299. KeyParent->Flags = KeyParent->Flags & (~KSF_BALANCE_MASK);
  300. }
  301. } else if (BalanceFlags == KSF_RIGHT_HEAVY) {
  302. if (KeyParent->Right == PrevPivot) {
  303. MYASSERT (KeyStruct == GetKeyStruct (PrevPivot));
  304. if (KeyStruct->Flags & KSF_RIGHT_HEAVY) {
  305. //
  306. // RR rotation
  307. //
  308. pRotateOnce (RootPtr, PivotNode, PrevPivot, KSF_RIGHT_HEAVY);
  309. } else if (KeyStruct->Flags & KSF_LEFT_HEAVY) {
  310. //
  311. // RL rotation
  312. //
  313. pRotateTwice (RootPtr, PivotNode, PrevPivot, KSF_RIGHT_HEAVY);
  314. }
  315. } else {
  316. KeyParent->Flags = KeyParent->Flags & (~KSF_BALANCE_MASK);
  317. }
  318. } else {
  319. if (KeyParent->Right == PrevPivot) {
  320. KeyParent->Flags = (KeyParent->Flags & (~KSF_BALANCE_MASK)) | KSF_RIGHT_HEAVY;
  321. } else {
  322. KeyParent->Flags = (KeyParent->Flags & (~KSF_BALANCE_MASK)) | KSF_LEFT_HEAVY;
  323. }
  324. }
  325. if (PivotNode == PivotEnd) {
  326. break;
  327. }
  328. PrevPivot = PivotNode;
  329. PivotNode = KeyParent->Parent;
  330. KeyStruct = KeyParent;
  331. }
  332. }
  333. VOID
  334. pBalanceDeletion (
  335. OUT PDWORD RootPtr,
  336. IN DWORD NodeNeedingAdjustment,
  337. IN DWORD Direction
  338. )
  339. {
  340. PKEYSTRUCT KeyStruct;
  341. PKEYSTRUCT ChildStruct;
  342. DWORD ChildOffset;
  343. DWORD Node;
  344. DWORD AntiDirection;
  345. DWORD OldNode;
  346. DWORD OrgParent;
  347. Node = NodeNeedingAdjustment;
  348. MYASSERT (Node != INVALID_OFFSET);
  349. KeyStruct = GetKeyStruct (Node);
  350. for (;;) {
  351. MYASSERT (KeyStruct == GetKeyStruct (Node));
  352. AntiDirection = ANTIDIRECTION (Direction);
  353. OrgParent = KeyStruct->Parent;
  354. //
  355. // Case 1 - parent was initially balanced (terminates balancing)
  356. //
  357. if (!(KeyStruct->Flags & KSF_BALANCE_MASK)) {
  358. KeyStruct->Flags |= AntiDirection;
  359. break;
  360. }
  361. //
  362. // Case 2 - parent was heavy on side that was deleted
  363. //
  364. if (KeyStruct->Flags & Direction) {
  365. KeyStruct->Flags = KeyStruct->Flags & (~KSF_BALANCE_MASK);
  366. }
  367. //
  368. // Cases 3, 4 and 5 - deletion caused imbalance in parent
  369. //
  370. else {
  371. MYASSERT (KeyStruct->Flags & AntiDirection);
  372. ChildOffset = Direction == KSF_LEFT_HEAVY ?
  373. KeyStruct->Right :
  374. KeyStruct->Left;
  375. MYASSERT (ChildOffset != INVALID_OFFSET);
  376. ChildStruct = GetKeyStruct (ChildOffset);
  377. if (!(ChildStruct->Flags & KSF_BALANCE_MASK)) {
  378. //
  379. // Case 3 - single rotation needed (terminates balancing). We
  380. // don't care that Node changes during rotation.
  381. //
  382. pRotateOnce (RootPtr, Node, ChildOffset, AntiDirection);
  383. break;
  384. } else if (ChildStruct->Flags & Direction) {
  385. //
  386. // Case 4 - double rotation needed, Node is changed during rotation
  387. //
  388. Node = pRotateTwice (RootPtr, Node, ChildOffset, AntiDirection);
  389. } else {
  390. //
  391. // Case 5 - single rotation needed, Node is changed during rotation
  392. //
  393. Node = pRotateOnce (RootPtr, Node, ChildOffset, AntiDirection);
  394. }
  395. }
  396. //
  397. // Continue climbing the tree
  398. //
  399. OldNode = Node;
  400. Node = OrgParent;
  401. if (Node != INVALID_OFFSET) {
  402. KeyStruct = GetKeyStruct (Node);
  403. if (KeyStruct->Left == OldNode) {
  404. Direction = KSF_LEFT_HEAVY;
  405. } else {
  406. Direction = KSF_RIGHT_HEAVY;
  407. }
  408. } else {
  409. break;
  410. }
  411. }
  412. }
  413. #ifdef DEBUG
  414. VOID
  415. DumpBinTreeStats (
  416. VOID
  417. )
  418. {
  419. DEBUGMSG ((
  420. DBG_STATS,
  421. "MemDb Binary Tree Stats:\n\n"
  422. " Insertions: %u\n"
  423. " Deletions: %u\n"
  424. " Single Rotations: %u\n"
  425. " Double Rotations: %u\n",
  426. g_Insertions,
  427. g_Deletions,
  428. g_SingleRotations,
  429. g_DoubleRotations
  430. ));
  431. }
  432. INT
  433. pComputeHeight (
  434. IN DWORD Offset
  435. )
  436. {
  437. PKEYSTRUCT KeyStruct;
  438. INT Left, Right;
  439. if (Offset == INVALID_OFFSET) {
  440. return 0;
  441. }
  442. KeyStruct = GetKeyStruct (Offset);
  443. Left = pComputeHeight (KeyStruct->Left);
  444. Right = pComputeHeight (KeyStruct->Right);
  445. return 1 + max (Left, Right);
  446. }
  447. VOID
  448. pMakeNum (
  449. OUT PTSTR Msg,
  450. IN DWORD Offset,
  451. IN TCHAR LeftChar,
  452. IN TCHAR RightChar
  453. )
  454. {
  455. TCHAR Num[32];
  456. INT Len;
  457. PTSTR OrgMsg;
  458. INT i;
  459. _stprintf (Num, TEXT("%u"), Offset);
  460. Len = (6 - TcharCount (Num)) / 2;
  461. OrgMsg = Msg;
  462. for (i = 0 ; i < Len ; i++) {
  463. *Msg++ = LeftChar;
  464. }
  465. for (i = 0 ; Num[i] ; i++) {
  466. *Msg++ = Num[i];
  467. }
  468. OrgMsg += 6;
  469. while (Msg < OrgMsg) {
  470. *Msg++ = RightChar;
  471. }
  472. *Msg = 0;
  473. }
  474. VOID
  475. pDumpTree (
  476. IN DWORD Root,
  477. IN PCSTR Title OPTIONAL
  478. )
  479. {
  480. DWORD Offset;
  481. PKEYSTRUCT KeyStruct;
  482. PKEYSTRUCT KeyParent;
  483. DWORD MaxLevel;
  484. DWORD Spaces;
  485. UINT u;
  486. TCHAR Msg[16384];
  487. UINT Pos;
  488. INT Pass;
  489. GROWBUFFER NodesA = GROWBUF_INIT;
  490. GROWBUFFER NodesB = GROWBUF_INIT;
  491. PGROWBUFFER Nodes;
  492. PGROWBUFFER NextNodes;
  493. PDWORD OffsetPtr;
  494. PDWORD EndOfList;
  495. INT HalfWidth;
  496. TCHAR LeftChar, RightChar;
  497. if (Root == INVALID_OFFSET) {
  498. return;
  499. }
  500. if (Title) {
  501. LOGDIRECTA (DBG_VERBOSE, "\r\n");
  502. LOGDIRECTA (DBG_VERBOSE, Title);
  503. LOGDIRECTA (DBG_VERBOSE, "\r\n\r\n");
  504. }
  505. for (Pass = 0 ; Pass < 2 ; Pass++) {
  506. MaxLevel = (DWORD) pComputeHeight (Root);
  507. MaxLevel = min (MaxLevel, 10);
  508. if (Pass == 0) {
  509. HalfWidth = 3;
  510. Spaces = 6;
  511. } else {
  512. HalfWidth = 1;
  513. Spaces = 2;
  514. }
  515. for (u = 1 ; u < MaxLevel ; u++) {
  516. Spaces *= 2;
  517. }
  518. NodesB.End = 0;
  519. Nodes = &NodesA;
  520. NextNodes = &NodesB;
  521. GrowBufAppendDword (NextNodes, Root);
  522. for (u = 0 ; u < MaxLevel ; u++) {
  523. //
  524. // Swap growbufs
  525. //
  526. if (Nodes == &NodesA) {
  527. Nodes = &NodesB;
  528. NextNodes = &NodesA;
  529. } else {
  530. Nodes = &NodesA;
  531. NextNodes = &NodesB;
  532. }
  533. NextNodes->End = 0;
  534. //
  535. // Process all nodes
  536. //
  537. EndOfList = (PDWORD) (Nodes->Buf + Nodes->End);
  538. for (OffsetPtr = (PDWORD) (Nodes->Buf) ; OffsetPtr < EndOfList ; OffsetPtr++) {
  539. //
  540. // Add all children as next nodes
  541. //
  542. Offset = *OffsetPtr;
  543. if (Offset == INVALID_OFFSET) {
  544. GrowBufAppendDword (NextNodes, INVALID_OFFSET);
  545. GrowBufAppendDword (NextNodes, INVALID_OFFSET);
  546. } else {
  547. KeyStruct = GetKeyStruct (Offset);
  548. GrowBufAppendDword (NextNodes, KeyStruct->Left);
  549. GrowBufAppendDword (NextNodes, KeyStruct->Right);
  550. }
  551. //
  552. // Print current node
  553. //
  554. Pos = 0;
  555. LeftChar = TEXT(' ');
  556. RightChar = TEXT(' ');
  557. if (Offset != INVALID_OFFSET) {
  558. KeyStruct = GetKeyStruct (Offset);
  559. if (KeyStruct->Parent != INVALID_OFFSET) {
  560. KeyParent = GetKeyStruct (KeyStruct->Parent);
  561. if (KeyParent->Right == Offset) {
  562. LeftChar = TEXT('\'');
  563. } else if (KeyParent->Left == Offset) {
  564. RightChar = TEXT('\'');
  565. }
  566. }
  567. for ( ; Pos < (Spaces - HalfWidth) ; Pos++) {
  568. Msg[Pos] = LeftChar;
  569. }
  570. if (Pass == 0) {
  571. pMakeNum (Msg + Pos, Offset, LeftChar, RightChar);
  572. } else {
  573. _stprintf (Msg + Pos, TEXT("%2i"), FLAGS_TO_INT (KeyStruct->Flags & KSF_BALANCE_MASK));
  574. }
  575. Pos += TcharCount (Msg + Pos);
  576. }
  577. while (Pos < Spaces * 2) {
  578. Msg[Pos] = RightChar;
  579. Pos++;
  580. }
  581. Msg[Pos] = 0;
  582. LOGDIRECT (DBG_VERBOSE, Msg);
  583. }
  584. LOGDIRECT (DBG_VERBOSE, TEXT("\r\n"));
  585. for (OffsetPtr = (PDWORD) (Nodes->Buf) ; OffsetPtr < EndOfList ; OffsetPtr++) {
  586. Offset = *OffsetPtr;
  587. for (Pos = 0 ; Pos < Spaces ; Pos++) {
  588. Msg[Pos] = TEXT(' ');
  589. }
  590. if (Offset != INVALID_OFFSET) {
  591. KeyStruct = GetKeyStruct (*OffsetPtr);
  592. if (KeyStruct->Left != INVALID_OFFSET ||
  593. KeyStruct->Right != INVALID_OFFSET
  594. ) {
  595. Msg[Pos] = '|';
  596. Pos++;
  597. }
  598. }
  599. while (Pos < Spaces * 2) {
  600. Msg[Pos] = TEXT(' ');
  601. Pos++;
  602. }
  603. Msg[Pos] = 0;
  604. LOGDIRECT (DBG_VERBOSE, Msg);
  605. }
  606. Spaces /= 2;
  607. LOGDIRECT (DBG_VERBOSE, TEXT("\r\n"));
  608. Spaces = max (Spaces, 1);
  609. }
  610. LOGDIRECT (DBG_VERBOSE, TEXT("\r\n"));
  611. }
  612. FreeGrowBuffer (&NodesA);
  613. FreeGrowBuffer (&NodesB);
  614. }
  615. BOOL
  616. pCheckTreeBalance (
  617. IN DWORD Root,
  618. IN BOOL Force
  619. )
  620. {
  621. DWORD NextOffset;
  622. DWORD PrevOffset;
  623. DWORD Offset;
  624. PKEYSTRUCT KeyStruct;
  625. DWORD MinLevel = 0xFFFFFFFF;
  626. DWORD MaxLevel = 0;
  627. DWORD Level = 0;
  628. DWORD Nodes = 0;
  629. static DWORD SpotCheck = 0;
  630. //
  631. // Don't perform this check every single time
  632. //
  633. if (!Force) {
  634. SpotCheck++;
  635. if (SpotCheck == 10000) {
  636. SpotCheck = 0;
  637. } else {
  638. return FALSE;
  639. }
  640. }
  641. if (Root == INVALID_OFFSET) {
  642. return FALSE;
  643. }
  644. pCheckBalanceFactors (Root);
  645. NextOffset = Root;
  646. //
  647. // Get leftmost node
  648. //
  649. do {
  650. Offset = NextOffset;
  651. Level++;
  652. KeyStruct = GetKeyStruct (Offset);
  653. NextOffset = KeyStruct->Left;
  654. } while (NextOffset != INVALID_OFFSET);
  655. //
  656. // Recurse through entire tree
  657. //
  658. PrevOffset = INVALID_OFFSET;
  659. do {
  660. //
  661. // Visit node at Offset
  662. //
  663. Nodes++;
  664. KeyStruct = GetKeyStruct (Offset);
  665. if (KeyStruct->Left == INVALID_OFFSET ||
  666. KeyStruct->Right == INVALID_OFFSET
  667. ) {
  668. MinLevel = min (MinLevel, Level);
  669. MaxLevel = max (MaxLevel, Level);
  670. }
  671. //
  672. // Go to the next node
  673. //
  674. if (KeyStruct->Right != INVALID_OFFSET) {
  675. //
  676. // Go to left-most node of right
  677. //
  678. KeyStruct = GetKeyStruct (Offset);
  679. NextOffset = KeyStruct->Right;
  680. while (NextOffset != INVALID_OFFSET) {
  681. Offset = NextOffset;
  682. Level++;
  683. KeyStruct = GetKeyStruct (Offset);
  684. NextOffset = KeyStruct->Left;
  685. }
  686. }
  687. else {
  688. //
  689. // Go to parent, looping if its right child is the
  690. // previous node.
  691. //
  692. do {
  693. PrevOffset = Offset;
  694. Offset = KeyStruct->Parent;
  695. Level--;
  696. if (Offset == INVALID_OFFSET) {
  697. break;
  698. }
  699. KeyStruct = GetKeyStruct (Offset);
  700. } while (KeyStruct->Right == PrevOffset);
  701. }
  702. } while (Offset != INVALID_OFFSET);
  703. DEBUGMSG_IF ((
  704. (MaxLevel - MinLevel) > 3,
  705. DBG_NAUSEA,
  706. "Binary tree imbalance detected: MinLevel=%u, MaxLevel=%u, Nodes=%u",
  707. MinLevel,
  708. MaxLevel,
  709. Nodes
  710. ));
  711. return TRUE;
  712. }
  713. INT
  714. pComputeBalanceFactor (
  715. IN DWORD Offset
  716. )
  717. {
  718. PKEYSTRUCT KeyStruct;
  719. KeyStruct = GetKeyStruct (Offset);
  720. return pComputeHeight (KeyStruct->Right) - pComputeHeight (KeyStruct->Left);
  721. }
  722. VOID
  723. pCheckBalanceFactors (
  724. IN DWORD Root
  725. )
  726. {
  727. DWORD Offset;
  728. INT Factor;
  729. PKEYSTRUCT KeyStruct;
  730. Offset = GetFirstOffset (Root);
  731. while (Offset != INVALID_OFFSET) {
  732. KeyStruct = GetKeyStruct (Offset);
  733. Factor = pComputeBalanceFactor (Offset);
  734. if ((Factor == -1 && !(KeyStruct->Flags & KSF_LEFT_HEAVY)) ||
  735. (Factor == 1 && !(KeyStruct->Flags & KSF_RIGHT_HEAVY)) ||
  736. (!Factor && (KeyStruct->Flags & KSF_BALANCE_MASK))
  737. ) {
  738. pDumpTree (Root, "Tree Balance Factor Error");
  739. DEBUGMSG ((DBG_WHOOPS, "Tree balance factors are wrong!"));
  740. break;
  741. }
  742. if (Factor < -1 || Factor > 1) {
  743. pDumpTree (Root, "Balance Factor Out of Bounds.");
  744. DEBUGMSG ((DBG_WHOOPS, "Balance factors out of bounds!"));
  745. break;
  746. }
  747. Offset = GetNextOffset (Offset);
  748. }
  749. }
  750. #endif
  751. PBYTE
  752. pAllocMemoryFromDb (
  753. IN UINT RequestSize,
  754. OUT PDWORD Offset,
  755. OUT PINT AdjustFactor
  756. )
  757. {
  758. PBYTE result;
  759. PBYTE newBuf;
  760. //
  761. // Grow heap if necessary
  762. //
  763. *AdjustFactor = 0;
  764. if (RequestSize + g_db->End > g_db->AllocSize) {
  765. if (g_db->AllocSize < 0x100000) {
  766. g_db->AllocSize += BLOCK_SIZE;
  767. } else {
  768. g_db->AllocSize *= 2;
  769. }
  770. if (g_db->AllocSize >= MAX_MEMDB_SIZE) {
  771. OutOfMemory_Terminate ();
  772. }
  773. if (g_db->Buf) {
  774. newBuf = (PBYTE) MemReAlloc (g_hHeap, 0, g_db->Buf, g_db->AllocSize);
  775. } else {
  776. newBuf = (PBYTE) MemAlloc (g_hHeap, 0, g_db->AllocSize);
  777. }
  778. if (!newBuf) {
  779. // g_db->AllocSize must be bigger than 2G
  780. OutOfMemory_Terminate();
  781. }
  782. //
  783. // provide relocation difference to caller
  784. //
  785. if (g_db->Buf) {
  786. *AdjustFactor = (INT) ((PBYTE) newBuf - (PBYTE) g_db->Buf);
  787. }
  788. g_db->Buf = newBuf;
  789. }
  790. result = g_db->Buf + g_db->End;
  791. *Offset = g_db->End;
  792. g_db->End += RequestSize;
  793. return result;
  794. }
  795. PKEYSTRUCT
  796. pAllocKeyStructBlock (
  797. OUT PDWORD Offset,
  798. OUT PINT AdjustFactor
  799. )
  800. {
  801. DWORD delOffset;
  802. DWORD prevDel;
  803. PKEYSTRUCT keyStruct = NULL;
  804. //
  805. // Look for free block
  806. //
  807. *AdjustFactor = 0;
  808. prevDel = INVALID_OFFSET;
  809. delOffset = g_db->FirstDeleted;
  810. while (delOffset != INVALID_OFFSET) {
  811. keyStruct = GetKeyStruct (delOffset);
  812. prevDel = delOffset;
  813. delOffset = keyStruct->NextDeleted;
  814. }
  815. //
  816. // Alloc new block if no free space
  817. //
  818. if (delOffset == INVALID_OFFSET) {
  819. //
  820. // Calc position in block
  821. //
  822. keyStruct = (PKEYSTRUCT) pAllocMemoryFromDb (sizeof (KEYSTRUCT), Offset, AdjustFactor);
  823. } else {
  824. //
  825. // Delink free block if recovering free space
  826. //
  827. *Offset = delOffset;
  828. if (prevDel != INVALID_OFFSET) {
  829. GetKeyStruct (prevDel)->NextDeleted = keyStruct->NextDeleted;
  830. } else {
  831. g_db->FirstDeleted = keyStruct->NextDeleted;
  832. }
  833. }
  834. return keyStruct;
  835. }
  836. DWORD
  837. pAllocKeyStruct (
  838. IN OUT PDWORD ParentOffsetPtr,
  839. IN PCWSTR KeyName,
  840. IN DWORD PrevLevelNode
  841. )
  842. /*++
  843. Routine Description:
  844. pAllocKeyStruct allocates a block of memory in the single
  845. heap, expanding it if necessary.
  846. The KeyName must not already be in the tree, and
  847. ParentOffsetPtr must point to a valid DWORD offset
  848. variable. ParentOffsetPtr, or one of the children
  849. of ParentOffsetPtr, will be linked to the new struct.
  850. Arguments:
  851. ParentOffsetPtr - Address of a DWORD that holds the offset to
  852. the root. Within the function, the variable
  853. will change to point to the parent of the
  854. new struct.
  855. KeyName - The string identifying the key. It cannot
  856. contain backslashes. The new struct will
  857. be initialized and this name will be copied
  858. into the struct.
  859. PrevLevelNode - Specifies the previous level root offset
  860. Return Value:
  861. An offset to the new structure.
  862. --*/
  863. {
  864. PKEYSTRUCT KeyStruct;
  865. PKEYSTRUCT KeyParent;
  866. DWORD Offset;
  867. DWORD NodeOffsetParent;
  868. INT cmp;
  869. DWORD PivotEnd;
  870. PDWORD RootPtr;
  871. INT adjustFactor;
  872. DWORD newToken;
  873. INCSTAT(g_Insertions);
  874. #ifdef DEBUG
  875. pCheckTreeBalance (*ParentOffsetPtr, FALSE);
  876. #endif
  877. KeyStruct = pAllocKeyStructBlock (
  878. &Offset,
  879. &adjustFactor
  880. );
  881. //
  882. // Database might have moved. Relocate any pointers within the database now.
  883. //
  884. if (ParentOffsetPtr != &g_db->FirstLevelRoot) {
  885. ParentOffsetPtr = (PDWORD) ((PBYTE) ParentOffsetPtr + adjustFactor);
  886. }
  887. //
  888. // Init new block
  889. //
  890. KeyStruct->NextLevelRoot = INVALID_OFFSET;
  891. KeyStruct->PrevLevelNode = PrevLevelNode;
  892. KeyStruct->Left = INVALID_OFFSET;
  893. KeyStruct->Right = INVALID_OFFSET;
  894. KeyStruct->dwValue = 0;
  895. KeyStruct->Flags = 0;
  896. #ifdef DEBUG
  897. KeyStruct->Signature = SIGNATURE;
  898. #endif
  899. newToken = pAllocKeyToken (KeyName, &adjustFactor);
  900. //
  901. // Again the database might have moved
  902. //
  903. KeyStruct = (PKEYSTRUCT) ((PBYTE) KeyStruct + adjustFactor);
  904. if (ParentOffsetPtr != &g_db->FirstLevelRoot) {
  905. ParentOffsetPtr = (PDWORD) ((PBYTE) ParentOffsetPtr + adjustFactor);
  906. }
  907. //
  908. // finish updating keystruct
  909. //
  910. KeyStruct->KeyToken = newToken;
  911. //
  912. // Put it in the tree
  913. //
  914. NodeOffsetParent = INVALID_OFFSET;
  915. PivotEnd = INVALID_OFFSET;
  916. RootPtr = ParentOffsetPtr;
  917. while (*ParentOffsetPtr != INVALID_OFFSET) {
  918. NodeOffsetParent = *ParentOffsetPtr;
  919. KeyParent = GetKeyStruct (*ParentOffsetPtr);
  920. if (KeyParent->Flags & KSF_BALANCE_MASK) {
  921. PivotEnd = *ParentOffsetPtr;
  922. }
  923. cmp = StringICompareW (KeyName, GetKeyToken (KeyParent->KeyToken));
  924. if (cmp < 0) {
  925. ParentOffsetPtr = &KeyParent->Left;
  926. } else if (cmp > 0) {
  927. ParentOffsetPtr = &KeyParent->Right;
  928. } else {
  929. MYASSERT (FALSE);
  930. }
  931. }
  932. KeyStruct->Parent = NodeOffsetParent;
  933. *ParentOffsetPtr = Offset;
  934. #ifdef DEBUG
  935. // If using retail structs, delete Signature from BlockPtr
  936. if (!g_UseDebugStructs) {
  937. MoveMemory (
  938. KeyStruct,
  939. (PCBYTE) KeyStruct + (sizeof (KEYSTRUCT_DEBUG) - sizeof (KEYSTRUCT_RETAIL)),
  940. sizeof (KEYSTRUCT_RETAIL)
  941. );
  942. }
  943. #endif
  944. //
  945. // Balance the tree
  946. //
  947. pBalanceInsertion (RootPtr, Offset, PivotEnd);
  948. #ifdef DEBUG
  949. pCheckTreeBalance (*RootPtr, FALSE);
  950. #endif
  951. return Offset;
  952. }
  953. VOID
  954. pDeallocKeyStruct (
  955. IN DWORD Offset,
  956. IN OUT PDWORD RootPtr,
  957. IN BOOL DelinkFlag,
  958. IN BOOL ClearFlag
  959. )
  960. /*++
  961. Routine Description:
  962. pDeallocKeyStruct first deletes all structures pointed to by
  963. NextLevelRoot. After all items are deleted from the next
  964. level, pDeallocKeyStruct optionally delinks the struct from
  965. the binary tree. Before exiting, the struct is given to the
  966. deleted block chain.
  967. Arguments:
  968. Offset - An offset to the item as provided by pAllocKeyStruct
  969. or any of the Find functions.
  970. RootPtr - A pointer to the level tree root variable. This value
  971. will be updated if delinking is involved.
  972. DelinkFlag - A flag indicating TRUE to delink the struct from
  973. the binary tree it is in, or FALSE if the struct is
  974. only to be added to the deleted block chain.
  975. ClearFlag - Specifies FALSE if the key struct's children are to
  976. be deleted, or TRUE if the current key struct should
  977. simply be cleaned up but left allocated.
  978. Return Value:
  979. none
  980. --*/
  981. {
  982. PKEYSTRUCT KeyStruct;
  983. PKEYSTRUCT KeyParent;
  984. PKEYSTRUCT KeyChild;
  985. PKEYSTRUCT KeyLeftmost;
  986. PKEYSTRUCT KeyLeftChild;
  987. PKEYSTRUCT KeyRightChild;
  988. DWORD Leftmost;
  989. DWORD NodeOffset;
  990. PDWORD ParentOffsetPtr;
  991. WCHAR TempStr[MEMDB_MAX];
  992. DWORD Direction = 0;
  993. DWORD RebalanceOffset;
  994. KeyStruct = GetKeyStruct (Offset);
  995. //
  996. // Remove endpoints from hash table
  997. //
  998. if (KeyStruct->Flags & KSF_ENDPOINT) {
  999. PrivateBuildKeyFromOffset (0, Offset, TempStr, NULL, NULL, NULL);
  1000. RemoveHashTableEntry (TempStr);
  1001. //
  1002. // Free binary value on key
  1003. //
  1004. FreeKeyStructBinaryBlock (KeyStruct);
  1005. KeyStruct->Flags &= ~KSF_ENDPOINT;
  1006. }
  1007. //
  1008. // Call recursively if there are sublevels to this key
  1009. //
  1010. if (!ClearFlag) {
  1011. if (KeyStruct->NextLevelRoot != INVALID_OFFSET) {
  1012. NodeOffset = GetFirstOffset (KeyStruct->NextLevelRoot);
  1013. while (NodeOffset != INVALID_OFFSET) {
  1014. pDeallocKeyStruct (NodeOffset, &KeyStruct->NextLevelRoot, FALSE, FALSE);
  1015. NodeOffset = GetNextOffset (NodeOffset);
  1016. }
  1017. }
  1018. //
  1019. // Remove the item from its binary tree
  1020. //
  1021. if (DelinkFlag) {
  1022. //
  1023. // Find parent-to-child pointer
  1024. //
  1025. if (KeyStruct->Parent != INVALID_OFFSET) {
  1026. KeyParent = GetKeyStruct (KeyStruct->Parent);
  1027. if (KeyParent->Left == Offset) {
  1028. ParentOffsetPtr = &KeyParent->Left;
  1029. Direction = KSF_LEFT_HEAVY;
  1030. } else {
  1031. ParentOffsetPtr = &KeyParent->Right;
  1032. Direction = KSF_RIGHT_HEAVY;
  1033. }
  1034. } else {
  1035. ParentOffsetPtr = RootPtr;
  1036. }
  1037. if (KeyStruct->Left == INVALID_OFFSET &&
  1038. KeyStruct->Right == INVALID_OFFSET
  1039. ) {
  1040. //
  1041. // No children; reset parent, then rebalance tree
  1042. //
  1043. *ParentOffsetPtr = INVALID_OFFSET;
  1044. RebalanceOffset = KeyStruct->Parent;
  1045. } else if (KeyStruct->Left == INVALID_OFFSET) {
  1046. //
  1047. // Only a right child; bring it up a level and rebalance
  1048. //
  1049. *ParentOffsetPtr = KeyStruct->Right;
  1050. KeyChild = GetKeyStruct (*ParentOffsetPtr);
  1051. KeyChild->Parent = KeyStruct->Parent;
  1052. //
  1053. // The moved node's balance factor must be set the same as the
  1054. // node we are deleting. The rebalancing will correct it.
  1055. //
  1056. KeyChild->Flags = (KeyChild->Flags & (~KSF_BALANCE_MASK)) |
  1057. (KeyStruct->Flags & KSF_BALANCE_MASK);
  1058. Direction = KSF_RIGHT_HEAVY;
  1059. RebalanceOffset = KeyStruct->Right;
  1060. } else if (KeyStruct->Right == INVALID_OFFSET) {
  1061. //
  1062. // Only a left child; bring it up a level and rebalance
  1063. //
  1064. *ParentOffsetPtr = KeyStruct->Left;
  1065. KeyChild = GetKeyStruct (*ParentOffsetPtr);
  1066. KeyChild->Parent = KeyStruct->Parent;
  1067. //
  1068. // The moved node's balance factor must be set the same as the
  1069. // node we are deleting. The rebalancing will correct it.
  1070. //
  1071. KeyChild->Flags = (KeyChild->Flags & (~KSF_BALANCE_MASK)) |
  1072. (KeyStruct->Flags & KSF_BALANCE_MASK);
  1073. Direction = KSF_LEFT_HEAVY;
  1074. RebalanceOffset = KeyStruct->Left;
  1075. } else {
  1076. //
  1077. // Two children - find min val of right subtree (the leftmost node
  1078. // of the right child).
  1079. //
  1080. Leftmost = KeyStruct->Right;
  1081. KeyLeftmost = GetKeyStruct (Leftmost);
  1082. while (KeyLeftmost->Left != INVALID_OFFSET) {
  1083. Leftmost = KeyLeftmost->Left;
  1084. KeyLeftmost = GetKeyStruct (Leftmost);
  1085. }
  1086. //
  1087. // If Leftmost has right children, and it is not the
  1088. // right child of the node we are deleting, then
  1089. // hook right subtree to parent.
  1090. //
  1091. // If Leftmost does not have right children, then
  1092. // remove its parent's linkage
  1093. //
  1094. if (Leftmost != KeyStruct->Right) {
  1095. KeyParent = GetKeyStruct (KeyLeftmost->Parent);
  1096. if (KeyLeftmost->Right != INVALID_OFFSET) {
  1097. //
  1098. // Because of the balance properties, we know that
  1099. // we have a single leaf node to the right. Its
  1100. // balance factor is zero, and we move it to a
  1101. // position where it remains zero.
  1102. //
  1103. KeyRightChild = GetKeyStruct (KeyLeftmost->Right);
  1104. MYASSERT (KeyRightChild->Left == INVALID_OFFSET);
  1105. MYASSERT (KeyRightChild->Right == INVALID_OFFSET);
  1106. KeyParent->Left = KeyLeftmost->Right;
  1107. KeyRightChild->Parent = KeyLeftmost->Parent;
  1108. } else {
  1109. KeyParent->Left = INVALID_OFFSET;
  1110. }
  1111. //
  1112. // We are affecting the balance factor of the
  1113. // parent. Rebalancing must start at the leftmost
  1114. // node's parent.
  1115. //
  1116. RebalanceOffset = KeyLeftmost->Parent;
  1117. Direction = KSF_LEFT_HEAVY; // we deleted from the left side
  1118. } else {
  1119. //
  1120. // In this case there is no leftmost node of the right child.
  1121. // Therefore, we reduced the height of the right side.
  1122. //
  1123. RebalanceOffset = Leftmost;
  1124. Direction = KSF_RIGHT_HEAVY;
  1125. }
  1126. //
  1127. // Now leftmost is available to replace the deleted
  1128. // node
  1129. //
  1130. KeyLeftmost->Parent = KeyStruct->Parent;
  1131. *ParentOffsetPtr = Leftmost;
  1132. KeyLeftmost->Left = KeyStruct->Left;
  1133. KeyLeftChild = GetKeyStruct (KeyStruct->Left);
  1134. KeyLeftChild->Parent = Leftmost;
  1135. if (Leftmost != KeyStruct->Right) {
  1136. KeyLeftmost->Right = KeyStruct->Right;
  1137. MYASSERT (KeyStruct->Right != INVALID_OFFSET);
  1138. KeyRightChild = GetKeyStruct (KeyStruct->Right);
  1139. KeyRightChild->Parent = Leftmost;
  1140. }
  1141. //
  1142. // We need to copy the balance factor of what we are deleting to the
  1143. // replacement node.
  1144. //
  1145. KeyLeftmost->Flags = (KeyLeftmost->Flags & (~KSF_BALANCE_MASK)) |
  1146. (KeyStruct->Flags & KSF_BALANCE_MASK);
  1147. }
  1148. //
  1149. // Rebalance the tree
  1150. //
  1151. if (RebalanceOffset != INVALID_OFFSET) {
  1152. MYASSERT (Direction);
  1153. if (Direction) {
  1154. //pDumpTree (*RootPtr, "Before rebalance");
  1155. pBalanceDeletion (RootPtr, RebalanceOffset, Direction);
  1156. //pDumpTree (*RootPtr, "Final tree");
  1157. }
  1158. }
  1159. #ifdef DEBUG
  1160. pCheckTreeBalance (*RootPtr, FALSE);
  1161. #endif
  1162. }
  1163. //
  1164. // Donate block to free space unless caller does not
  1165. // want child structs freed.
  1166. //
  1167. pDeallocToken (KeyStruct->KeyToken);
  1168. KeyStruct->NextDeleted = g_db->FirstDeleted;
  1169. g_db->FirstDeleted = Offset;
  1170. }
  1171. }
  1172. VOID
  1173. pRemoveHashEntriesForNode (
  1174. IN PCWSTR Root,
  1175. IN DWORD Offset
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. pRemoveHashEntriesFromNode removes all hash table entries from all children
  1180. of the specified node. This function is called recursively.
  1181. Arguments:
  1182. Root - Specifies the root string that corresponds with Offset. This must
  1183. also contain the temporary hive root.
  1184. Offset - Specifies the offset of the node to process. The node and all of
  1185. its children will be removed from the hash table.
  1186. Return Value:
  1187. None.
  1188. --*/
  1189. {
  1190. DWORD ChildOffset;
  1191. PKEYSTRUCT KeyStruct;
  1192. WCHAR ChildRoot[MEMDB_MAX];
  1193. PWSTR End;
  1194. //
  1195. // Remove hash entry if this root is an endpoint
  1196. //
  1197. KeyStruct = GetKeyStruct (Offset);
  1198. if (KeyStruct->Flags & KSF_ENDPOINT) {
  1199. RemoveHashTableEntry (Root);
  1200. #ifdef DEBUG
  1201. {
  1202. DWORD HashOffset;
  1203. HashOffset = FindStringInHashTable (Root, NULL);
  1204. if (HashOffset != INVALID_OFFSET) {
  1205. DEBUGMSG ((DBG_WARNING, "Memdb move duplicate: %s", Root));
  1206. }
  1207. }
  1208. #endif
  1209. }
  1210. //
  1211. // Recurse for all children, removing hash entries for all endpoints found
  1212. //
  1213. StringCopyW (ChildRoot, Root);
  1214. End = GetEndOfStringW (ChildRoot);
  1215. *End = L'\\';
  1216. End++;
  1217. *End = 0;
  1218. ChildOffset = GetFirstOffset (KeyStruct->NextLevelRoot);
  1219. while (ChildOffset != INVALID_OFFSET) {
  1220. KeyStruct = GetKeyStruct (ChildOffset);
  1221. StringCopyW (End, GetKeyToken (KeyStruct->KeyToken));
  1222. pRemoveHashEntriesForNode (ChildRoot, ChildOffset);
  1223. ChildOffset = GetNextOffset (ChildOffset);
  1224. }
  1225. }
  1226. VOID
  1227. pAddHashEntriesForNode (
  1228. IN PCWSTR Root,
  1229. IN DWORD Offset,
  1230. IN BOOL AddRoot
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. pAddHashEntriesForNode adds hash table entries for the specified root and
  1235. all of its children.
  1236. Arguments:
  1237. Root - Specifies the root string that corresponds to Offset. This string
  1238. must also include the temporary hive root.
  1239. Offset - Specifies the node offset to begin processing. The node and all
  1240. of its children are added to the hash table.
  1241. AddRoot - Specifies TRUE if the root should be added to the hash table,
  1242. FALSE otherwise.
  1243. Return Value:
  1244. None.
  1245. --*/
  1246. {
  1247. DWORD ChildOffset;
  1248. PKEYSTRUCT KeyStruct;
  1249. WCHAR ChildRoot[MEMDB_MAX];
  1250. PWSTR End;
  1251. DWORD HashOffset;
  1252. //
  1253. // Add hash entry if this root is an endpoint
  1254. //
  1255. KeyStruct = GetKeyStruct (Offset);
  1256. if (AddRoot && KeyStruct->Flags & KSF_ENDPOINT) {
  1257. HashOffset = FindStringInHashTable (Root, NULL);
  1258. if (HashOffset != Offset) {
  1259. #ifdef DEBUG
  1260. if (HashOffset != INVALID_OFFSET) {
  1261. DEBUGMSG ((DBG_WARNING, "Memdb duplicate: %s", Root));
  1262. }
  1263. #endif
  1264. AddHashTableEntry (Root, Offset);
  1265. }
  1266. }
  1267. //
  1268. // Recurse for all children, adding hash entries for all endpoints found
  1269. //
  1270. StringCopyW (ChildRoot, Root);
  1271. End = GetEndOfStringW (ChildRoot);
  1272. *End = L'\\';
  1273. End++;
  1274. *End = 0;
  1275. ChildOffset = GetFirstOffset (KeyStruct->NextLevelRoot);
  1276. while (ChildOffset != INVALID_OFFSET) {
  1277. KeyStruct = GetKeyStruct (ChildOffset);
  1278. StringCopyW (End, GetKeyToken (KeyStruct->KeyToken));
  1279. pAddHashEntriesForNode (ChildRoot, ChildOffset, TRUE);
  1280. ChildOffset = GetNextOffset (ChildOffset);
  1281. }
  1282. }
  1283. BOOL
  1284. pFindPlaceForNewNode (
  1285. IN PKEYSTRUCT InsertNode,
  1286. IN PDWORD TreeRootPtr,
  1287. OUT PDWORD ParentOffsetPtr,
  1288. OUT PDWORD *ParentToChildOffsetPtr,
  1289. OUT PDWORD PivotEnd
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. pFindPlaceForNewNode searches a level for the position within the tree.
  1294. This is used to insert new unique keys in the tree.
  1295. Arguments:
  1296. InsertNode - Specifies the allocated but unlinked node. Its
  1297. Key member must be valid.
  1298. TreeRootPtr - Specifies a pointer to the memory that holds the
  1299. root offset. This is used to walk the tree. It
  1300. can be INVALID_OFFSET.
  1301. ParentOffsetPtr - Receives the offset to the parent node
  1302. ParentToChildOffsetPtr - Recieves the address of the left or right child
  1303. pointer within the parent struct
  1304. PivotEnd - Receives the offset of the tree node that should
  1305. stop balancing
  1306. Return Value:
  1307. TRUE if a spot was found in the tree for InsertNode, or FALSE if a spot was
  1308. not found (because the key name is already in the tree).
  1309. --*/
  1310. {
  1311. PDWORD ParentPtr;
  1312. PKEYSTRUCT Parent;
  1313. INT cmp;
  1314. ParentPtr = TreeRootPtr;
  1315. *ParentOffsetPtr = INVALID_OFFSET;
  1316. *PivotEnd = INVALID_OFFSET;
  1317. while (*ParentPtr != INVALID_OFFSET) {
  1318. *ParentOffsetPtr = *ParentPtr;
  1319. Parent = GetKeyStruct (*ParentPtr);
  1320. if (Parent->Flags & KSF_BALANCE_MASK) {
  1321. *PivotEnd = *ParentPtr;
  1322. }
  1323. cmp = StringICompareW (GetKeyToken (InsertNode->KeyToken), GetKeyToken (Parent->KeyToken));
  1324. if (cmp < 0) {
  1325. ParentPtr = &Parent->Left;
  1326. } else if (cmp > 0) {
  1327. ParentPtr = &Parent->Right;
  1328. } else {
  1329. return FALSE;
  1330. }
  1331. }
  1332. *ParentToChildOffsetPtr = ParentPtr;
  1333. return TRUE;
  1334. }
  1335. VOID
  1336. pMergeFamilies (
  1337. IN PDWORD DestTreeRootPtr,
  1338. IN DWORD MergeSrcOffset,
  1339. IN DWORD MergeDestPrevLevelOffset
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. pMergeFamilies takes two tree families and merges them together. When
  1344. duplicates are found, their linkage is abandoned, but they are not
  1345. deallocated. This allows MemDbBuildKeyFromOffset to continue to work.
  1346. Arguments:
  1347. DestTreeRootPtr - Specifies the address of the destination level's
  1348. root variable. This is potentially altered with
  1349. insertion and balancing.
  1350. MergeSrcOffset - Specifies the offset to the source tree family
  1351. (STF). The STF is merged into the destination
  1352. tree indicated by DestTreeRootPtr.
  1353. MergeDestPrevLevelOffset - Specifies the offset to the previous level node.
  1354. This value cannot be INVALID_OFFSET.
  1355. Return Value:
  1356. None.
  1357. --*/
  1358. {
  1359. PKEYSTRUCT MergeSrc;
  1360. PKEYSTRUCT MergeDest;
  1361. PDWORD ParentToChildOffsetPtr;
  1362. DWORD ParentOffset;
  1363. DWORD DestCollisionOffset;
  1364. DWORD PivotEnd;
  1365. GROWBUFFER NextLevelMerge = GROWBUF_INIT;
  1366. DWORD NodeOffset;
  1367. PDWORD NextLevelOffsetPtr;
  1368. UINT Pos;
  1369. BOOL FoundPlaceForNode;
  1370. //
  1371. // Look for a place within the tree indicated by the offset
  1372. // stored in DestTreeRootPtr. If one is found, we can simply
  1373. // relink the node at MergeSrcOffset. Otherwise, we have to
  1374. // recursively merge the next level of MergeSrcOffset, and
  1375. // we have to abandon MergeSrcOffset.
  1376. //
  1377. MergeSrc = GetKeyStruct (MergeSrcOffset);
  1378. MYASSERT (MergeSrc);
  1379. FoundPlaceForNode = pFindPlaceForNewNode (
  1380. MergeSrc,
  1381. DestTreeRootPtr,
  1382. &ParentOffset,
  1383. &ParentToChildOffsetPtr,
  1384. &PivotEnd
  1385. );
  1386. if (FoundPlaceForNode) {
  1387. //
  1388. // Since we found a place to put the src family, it is
  1389. // easy to hook it and its next level into the dest
  1390. // family.
  1391. //
  1392. MergeSrc->Parent = ParentOffset;
  1393. *ParentToChildOffsetPtr = MergeSrcOffset;
  1394. MergeSrc->Flags = MergeSrc->Flags & (~KSF_BALANCE_MASK);
  1395. MergeSrc->Left = INVALID_OFFSET;
  1396. MergeSrc->Right = INVALID_OFFSET;
  1397. MergeSrc->PrevLevelNode = MergeDestPrevLevelOffset;
  1398. pBalanceInsertion (DestTreeRootPtr, MergeSrcOffset, PivotEnd);
  1399. #ifdef DEBUG
  1400. pCheckTreeBalance (*DestTreeRootPtr, FALSE);
  1401. #endif
  1402. } else {
  1403. //
  1404. // We found a collision, then we have to abandon MergeSrc,
  1405. // removing linkage to the parent and children -- but preserving
  1406. // the linkage to the previous level. Finally, we have to call
  1407. // this function recursively to hook up all the next level nodes.
  1408. //
  1409. DestCollisionOffset = ParentOffset; // renamed to be more accurate
  1410. MergeDest = GetKeyStruct (DestCollisionOffset);
  1411. MYASSERT (MergeDest);
  1412. MergeSrc->Parent = INVALID_OFFSET;
  1413. MergeSrc->Left = INVALID_OFFSET;
  1414. MergeSrc->Right = INVALID_OFFSET;
  1415. MergeSrc->PrevLevelNode = MergeDestPrevLevelOffset;
  1416. //
  1417. // If this is an end point, then try to preserve value and flags
  1418. //
  1419. if (MergeSrc->Flags & KSF_ENDPOINT) {
  1420. if (MergeDest->Flags & KSF_ENDPOINT) {
  1421. DEBUGMSG ((
  1422. DBG_WARNING,
  1423. "MemDb: Loss of value and flags in %s",
  1424. GetKeyToken (MergeSrc->KeyToken)
  1425. ));
  1426. } else {
  1427. MergeDest->Flags = MergeDest->Flags & ~KSF_FLAGS_TO_COPY;
  1428. MergeDest->Flags |= MergeSrc->Flags & KSF_FLAGS_TO_COPY;
  1429. MergeDest->dwValue = MergeSrc->dwValue;
  1430. }
  1431. }
  1432. //
  1433. // Save away all entries in the next src level into a grow buffer,
  1434. // then call pMergeFamilies recursively.
  1435. //
  1436. NodeOffset = GetFirstOffset (MergeSrc->NextLevelRoot);
  1437. while (NodeOffset != INVALID_OFFSET) {
  1438. NextLevelOffsetPtr = (PDWORD) GrowBuffer (&NextLevelMerge, sizeof (DWORD));
  1439. MYASSERT (NextLevelOffsetPtr);
  1440. *NextLevelOffsetPtr = NodeOffset;
  1441. NodeOffset = GetNextOffset (NodeOffset);
  1442. }
  1443. NextLevelOffsetPtr = (PDWORD) NextLevelMerge.Buf;
  1444. for (Pos = 0 ; Pos < NextLevelMerge.End ; Pos += sizeof (DWORD)) {
  1445. pMergeFamilies (
  1446. &MergeDest->NextLevelRoot,
  1447. *NextLevelOffsetPtr,
  1448. DestCollisionOffset
  1449. );
  1450. NextLevelOffsetPtr++;
  1451. }
  1452. FreeGrowBuffer (&NextLevelMerge);
  1453. }
  1454. }
  1455. DWORD
  1456. pMoveKey (
  1457. IN DWORD OriginalKey,
  1458. IN PCWSTR NewKeyRoot,
  1459. IN PCWSTR NewKeyRootWithHive
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. pMoveKey moves a key (and all of its children) to a new root. If the
  1464. caller specifies a source key that has no children, a proxy node is created
  1465. to maintain offsets. The proxy node is not listed in the hash table.
  1466. Arguments:
  1467. OriginalKey - Specifies the offset to the original key that needs to
  1468. be moved. It does not need to be an endpoint, and may
  1469. have children.
  1470. NewKeyRoot - Specifies the new root for OriginalKey. It may have
  1471. multiple levels (separated by backslashes).
  1472. NewKeyRootWithHive - Different from NewKeyRoot only when the node is in a
  1473. temporary hive. This is used for the hash table only.
  1474. Return Value:
  1475. TRUE if successful, FALSE otherwise.
  1476. --*/
  1477. {
  1478. DWORD ReplacementKey;
  1479. PKEYSTRUCT SrcKey, DestKey, ChildKey;
  1480. PKEYSTRUCT KeyParent;
  1481. DWORD NodeOffset;
  1482. GROWBUFFER Children = GROWBUF_INIT;
  1483. PDWORD ChildOffsetPtr;
  1484. DWORD Pos;
  1485. WCHAR OriginalRoot[MEMDB_MAX];
  1486. BOOL Endpoint;
  1487. //
  1488. // Check requirements
  1489. //
  1490. SrcKey = GetKeyStruct (OriginalKey);
  1491. if (!SrcKey) {
  1492. DEBUGMSG ((DBG_WHOOPS, "MemDb: pMoveKey can't find original key %s", OriginalKey));
  1493. return INVALID_OFFSET;
  1494. }
  1495. if (SrcKey->Flags & KSF_PROXY_NODE) {
  1496. DEBUGMSG ((DBG_WHOOPS, "MemDb: pMoveKey can't move proxy node %s", OriginalKey));
  1497. return INVALID_OFFSET;
  1498. }
  1499. Endpoint = SrcKey->Flags & KSF_ENDPOINT;
  1500. if (!PrivateBuildKeyFromOffset (0, OriginalKey, OriginalRoot, NULL, NULL, NULL)) {
  1501. return INVALID_OFFSET;
  1502. }
  1503. //
  1504. // Allocate new key
  1505. //
  1506. ReplacementKey = pNewKey (NewKeyRoot, NewKeyRootWithHive, FALSE);
  1507. if (ReplacementKey == INVALID_OFFSET) {
  1508. return INVALID_OFFSET;
  1509. }
  1510. SrcKey = GetKeyStruct (OriginalKey);
  1511. DestKey = GetKeyStruct (ReplacementKey);
  1512. if (!SrcKey || !DestKey) {
  1513. return INVALID_OFFSET;
  1514. }
  1515. DEBUGMSG ((DBG_NAUSEA, "Moving %s to %s", OriginalRoot, NewKeyRootWithHive));
  1516. //
  1517. // Remove all hash entries for all children
  1518. //
  1519. pRemoveHashEntriesForNode (OriginalRoot, OriginalKey);
  1520. //
  1521. // Record all children in an array
  1522. //
  1523. NodeOffset = GetFirstOffset (SrcKey->NextLevelRoot);
  1524. while (NodeOffset != INVALID_OFFSET) {
  1525. ChildOffsetPtr = (PDWORD) GrowBuffer (&Children, sizeof (DWORD));
  1526. if (!ChildOffsetPtr) {
  1527. return INVALID_OFFSET;
  1528. }
  1529. *ChildOffsetPtr = NodeOffset;
  1530. NodeOffset = GetNextOffset (NodeOffset);
  1531. }
  1532. //
  1533. // Move next level pointer to new node. There are two cases
  1534. // to handle:
  1535. //
  1536. // 1. Destination exists and has children. Here the source
  1537. // needs to be merged into the destination.
  1538. //
  1539. // 2. Destination is brand new and has no children. Here we
  1540. // simply move the source children to the destination.
  1541. //
  1542. // During this process, the hash table is updated accordingly.
  1543. //
  1544. if (DestKey->NextLevelRoot != INVALID_OFFSET) {
  1545. //
  1546. // Hard case, merge children to new parent's family
  1547. //
  1548. ChildOffsetPtr = (PDWORD) Children.Buf;
  1549. for (Pos = 0 ; Pos < Children.End ; Pos += sizeof (DWORD)) {
  1550. pMergeFamilies (
  1551. &DestKey->NextLevelRoot,
  1552. *ChildOffsetPtr,
  1553. ReplacementKey
  1554. );
  1555. ChildOffsetPtr++;
  1556. }
  1557. } else {
  1558. //
  1559. // Easy case, link children to new parent
  1560. //
  1561. DestKey->NextLevelRoot = SrcKey->NextLevelRoot;
  1562. SrcKey->NextLevelRoot = INVALID_OFFSET;
  1563. if (DestKey->Flags & KSF_ENDPOINT) {
  1564. DEBUGMSG ((
  1565. DBG_WARNING,
  1566. "MemDb: Loss of value and flags in %s",
  1567. GetKeyToken (SrcKey->KeyToken)
  1568. ));
  1569. } else {
  1570. DestKey->Flags = DestKey->Flags & ~KSF_FLAGS_TO_COPY;
  1571. DestKey->Flags |= SrcKey->Flags & KSF_FLAGS_TO_COPY;
  1572. DestKey->dwValue = SrcKey->dwValue;
  1573. }
  1574. ChildOffsetPtr = (PDWORD) Children.Buf;
  1575. for (Pos = 0 ; Pos < Children.End ; Pos += sizeof (DWORD)) {
  1576. NodeOffset = *ChildOffsetPtr;
  1577. ChildOffsetPtr++;
  1578. ChildKey = GetKeyStruct (NodeOffset);
  1579. ChildKey->PrevLevelNode = ReplacementKey;
  1580. }
  1581. }
  1582. //
  1583. // Add all new entries to hash table
  1584. //
  1585. pAddHashEntriesForNode (NewKeyRootWithHive, ReplacementKey, FALSE);
  1586. //
  1587. // Free the original key node, or if an endpoint, make the
  1588. // node a proxy to the new node (to maintain offsets).
  1589. //
  1590. if (!Endpoint) {
  1591. SrcKey->NextLevelRoot = INVALID_OFFSET;
  1592. KeyParent = GetKeyStruct (SrcKey->PrevLevelNode);
  1593. pDeallocKeyStruct (OriginalKey, &KeyParent->NextLevelRoot, TRUE, FALSE);
  1594. } else {
  1595. DestKey->Flags = (DestKey->Flags & KSF_BALANCE_MASK) | (SrcKey->Flags & (~KSF_BALANCE_MASK));
  1596. DestKey->dwValue = SrcKey->dwValue;
  1597. SrcKey->Flags = KSF_PROXY_NODE | (SrcKey->Flags & KSF_BALANCE_MASK);
  1598. SrcKey->dwValue = ReplacementKey;
  1599. SrcKey->NextLevelRoot = INVALID_OFFSET;
  1600. }
  1601. FreeGrowBuffer (&Children);
  1602. return ReplacementKey;
  1603. }
  1604. BOOL
  1605. MemDbMoveTreeA (
  1606. IN PCSTR RootNode,
  1607. IN PCSTR NewRoot
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. MemDbMoveTree is the external interface to pMoveKey. See description in
  1612. pMoveKey for details.
  1613. Arguments:
  1614. RootNode - Specifies the node to move.
  1615. NewRoot - Specifies the new root for RootNode.
  1616. Return Value:
  1617. TRUE if successful, FALSE otherwise.
  1618. --*/
  1619. {
  1620. PCWSTR UnicodeRootNode;
  1621. PCWSTR UnicodeNewRoot;
  1622. BOOL b = FALSE;
  1623. UnicodeRootNode = ConvertAtoW (RootNode);
  1624. UnicodeNewRoot = ConvertAtoW (NewRoot);
  1625. if (UnicodeRootNode && UnicodeNewRoot) {
  1626. b = MemDbMoveTreeW (UnicodeRootNode, UnicodeNewRoot);
  1627. }
  1628. FreeConvertedStr (UnicodeRootNode);
  1629. FreeConvertedStr (UnicodeNewRoot);
  1630. return b;
  1631. }
  1632. BOOL
  1633. MemDbMoveTreeW (
  1634. IN PCWSTR RootNode,
  1635. IN PCWSTR NewRoot
  1636. )
  1637. {
  1638. DWORD Offset;
  1639. WCHAR Temp[MEMDB_MAX];
  1640. WCHAR NewRootWithHive[MEMDB_MAX];
  1641. PWSTR p, q;
  1642. PCWSTR SubKey;
  1643. BOOL b = FALSE;
  1644. INT HiveLen;
  1645. if (StringIMatch (RootNode, NewRoot)) {
  1646. DEBUGMSG ((DBG_WHOOPS, "Cannot move tree because source and dest are the same"));
  1647. return FALSE;
  1648. }
  1649. EnterCriticalSection (&g_MemDbCs);
  1650. __try {
  1651. SubKey = SelectHive (RootNode);
  1652. //
  1653. // Copy key to temp buffer
  1654. //
  1655. StringCopyW (Temp, SubKey);
  1656. if (*Temp == 0) {
  1657. DEBUGMSG ((DBG_WHOOPS, "MemDbMoveTree requires a root"));
  1658. __leave;
  1659. }
  1660. //
  1661. // Compute the new root with the original hive
  1662. //
  1663. if (StringIMatchW (Temp, RootNode)) {
  1664. // no hive case
  1665. StringCopyW (NewRootWithHive, NewRoot);
  1666. } else {
  1667. HiveLen = wcslen (RootNode) - wcslen (SubKey);
  1668. StringCopyTcharCountW (NewRootWithHive, RootNode, HiveLen);
  1669. StringCopyW (AppendWackW (NewRootWithHive), NewRoot);
  1670. }
  1671. //
  1672. // Find the last offset of the root key
  1673. //
  1674. q = Temp;
  1675. Offset = INVALID_OFFSET;
  1676. do {
  1677. if (Offset == INVALID_OFFSET) {
  1678. Offset = g_db->FirstLevelRoot;
  1679. } else {
  1680. Offset = GetKeyStruct (Offset)->NextLevelRoot;
  1681. }
  1682. if (Offset == INVALID_OFFSET) {
  1683. DEBUGMSGW ((DBG_VERBOSE, "MemDbMoveTree root %s not found", RootNode));
  1684. __leave;
  1685. }
  1686. p = wcschr (q, L'\\');
  1687. if (p) {
  1688. *p = 0;
  1689. }
  1690. Offset = FindKeyStruct (Offset, q);
  1691. if (Offset == INVALID_OFFSET) {
  1692. DEBUGMSGW ((DBG_VERBOSE, "MemDbMoveTree root %s not found", RootNode));
  1693. __leave;
  1694. }
  1695. q = p + 1;
  1696. } while (p);
  1697. //
  1698. // Now move the key
  1699. //
  1700. Offset = pMoveKey (Offset, NewRoot, NewRootWithHive);
  1701. if (Offset != INVALID_OFFSET) {
  1702. b = TRUE;
  1703. } else {
  1704. DEBUGMSGW ((DBG_WHOOPS, "Can't move %s to %s", RootNode, NewRoot));
  1705. }
  1706. }
  1707. __finally {
  1708. LeaveCriticalSection (&g_MemDbCs);
  1709. }
  1710. return b;
  1711. }
  1712. PKEYSTRUCT
  1713. pGetKeyStructWithProxy (
  1714. IN DWORD Offset
  1715. )
  1716. /*++
  1717. Routine Description:
  1718. pGetKeyStructWithProxy returns a pointer given an offset. It also implements proxy
  1719. nodes, transparent to the rest of memdb. The debug version checks the
  1720. signature and validity of each offset. It is assumed that Offset is always
  1721. valid.
  1722. Arguments:
  1723. Offset - Specifies the offset to the node
  1724. Return Value:
  1725. The pointer to the node.
  1726. --*/
  1727. {
  1728. PKEYSTRUCT KeyStruct;
  1729. #ifdef DEBUG
  1730. if (Offset == INVALID_OFFSET) {
  1731. DEBUGMSG ((DBG_ERROR, "Invalid root accessed in pGetKeyStructWithProxy at offset %u", Offset));
  1732. return NULL;
  1733. }
  1734. if (!g_db->Buf) {
  1735. DEBUGMSG ((DBG_ERROR, "Attempt to access non-existent buffer at %u", Offset));
  1736. return NULL;
  1737. }
  1738. if (Offset > g_db->End) {
  1739. DEBUGMSG ((DBG_ERROR, "Access beyond length of buffer in pGetKeyStructWithProxy (offset %u)", Offset));
  1740. return NULL;
  1741. }
  1742. #endif
  1743. KeyStruct = (PKEYSTRUCT) (g_db->Buf + Offset);
  1744. #ifdef DEBUG
  1745. if (!g_UseDebugStructs) {
  1746. KeyStruct = (PKEYSTRUCT) (g_db->Buf + Offset - sizeof (DWORD));
  1747. } else if (KeyStruct->Signature != SIGNATURE) {
  1748. DEBUGMSG ((DBG_ERROR, "Signature does not match in pGetKeyStructWithProxy at offset %u!", Offset));
  1749. return NULL;
  1750. }
  1751. #endif
  1752. if (KeyStruct->Flags & KSF_PROXY_NODE) {
  1753. return pGetKeyStructWithProxy (KeyStruct->dwValue);
  1754. }
  1755. return KeyStruct;
  1756. }
  1757. PKEYSTRUCT
  1758. GetKeyStruct (
  1759. IN DWORD Offset
  1760. )
  1761. /*++
  1762. Routine Description:
  1763. GetKeyStruct returns a pointer given an offset. It does not support proxy
  1764. nodes, so the rest of memdb accesses the unaltered tree. The debug version
  1765. checks the signature and validity of each offset. It is assumed that Offset
  1766. is always valid.
  1767. Arguments:
  1768. Offset - Specifies the offset to the node
  1769. Return Value:
  1770. The pointer to the node.
  1771. --*/
  1772. {
  1773. PKEYSTRUCT KeyStruct;
  1774. #ifdef DEBUG
  1775. if (Offset == INVALID_OFFSET) {
  1776. DEBUGMSG ((DBG_ERROR, "Invalid root accessed in GetKeyStruct at offset %u", Offset));
  1777. return NULL;
  1778. }
  1779. if (!g_db->Buf) {
  1780. DEBUGMSG ((DBG_ERROR, "Attempt to access non-existent buffer at %u", Offset));
  1781. return NULL;
  1782. }
  1783. if (Offset > g_db->End) {
  1784. DEBUGMSG ((DBG_ERROR, "Access beyond length of buffer in GetKeyStruct (offset %u)", Offset));
  1785. return NULL;
  1786. }
  1787. #endif
  1788. KeyStruct = (PKEYSTRUCT) (g_db->Buf + Offset);
  1789. #ifdef DEBUG
  1790. if (!g_UseDebugStructs) {
  1791. KeyStruct = (PKEYSTRUCT) (g_db->Buf + Offset - sizeof (DWORD));
  1792. } else if (KeyStruct->Signature != SIGNATURE) {
  1793. DEBUGMSG ((DBG_ERROR, "Signature does not match in GetKeyStruct at offset %u!", Offset));
  1794. return NULL;
  1795. }
  1796. #endif
  1797. return KeyStruct;
  1798. }
  1799. DWORD
  1800. FindKeyStruct (
  1801. IN DWORD RootOffset,
  1802. IN PCWSTR KeyName
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. FindKeyStruct takes a key name and looks for the
  1807. offset in the tree specified by RootOffset. The key
  1808. name must not contain backslashes.
  1809. Arguments:
  1810. RootOffset - An offset to the root of the level
  1811. KeyName - The name of the key to find in the binary tree
  1812. Return Value:
  1813. An offset to the structure, or INVALID_OFFSET if the key
  1814. was not found.
  1815. --*/
  1816. {
  1817. PKEYSTRUCT KeyStruct;
  1818. int cmp;
  1819. //
  1820. // Walk the binary tree looking for KeyName
  1821. //
  1822. while (RootOffset != INVALID_OFFSET) {
  1823. KeyStruct = GetKeyStruct (RootOffset);
  1824. cmp = StringICompareW (KeyName, GetKeyToken (KeyStruct->KeyToken));
  1825. if (!cmp) {
  1826. break;
  1827. }
  1828. if (cmp < 0) {
  1829. RootOffset = KeyStruct->Left;
  1830. } else {
  1831. RootOffset = KeyStruct->Right;
  1832. }
  1833. }
  1834. return RootOffset;
  1835. }
  1836. DWORD
  1837. GetFirstOffset (
  1838. IN DWORD RootOffset
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. GetFirstOffset walks down the left side of the binary tree
  1843. pointed to by RootOffset, and returns the left-most node.
  1844. Arguments:
  1845. RootOffset - An offset to the root of the level
  1846. Return Value:
  1847. An offset to the leftmost structure, or INVALID_OFFSET if the
  1848. root was invalid.
  1849. --*/
  1850. {
  1851. PKEYSTRUCT KeyStruct;
  1852. if (RootOffset == INVALID_OFFSET) {
  1853. return INVALID_OFFSET;
  1854. }
  1855. //
  1856. // Go to leftmost node of root
  1857. //
  1858. KeyStruct = GetKeyStruct (RootOffset);
  1859. while (KeyStruct->Left != INVALID_OFFSET) {
  1860. RootOffset = KeyStruct->Left;
  1861. KeyStruct = GetKeyStruct (RootOffset);
  1862. }
  1863. return RootOffset;
  1864. }
  1865. DWORD
  1866. GetNextOffset (
  1867. IN DWORD NodeOffset
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. GetNextOffset traverses the binary tree in order. This
  1872. technique relies on parent links to traverse without a
  1873. stack or recursion.
  1874. Arguments:
  1875. NodeOffset - Offset to a node in the tree, usually the
  1876. return value from GetFirstOffset or GetNextOffset.
  1877. Return Value:
  1878. An offset to the next structure, or INVALID_OFFSET if the
  1879. end is reached.
  1880. --*/
  1881. {
  1882. PKEYSTRUCT KeyStruct;
  1883. DWORD Last;
  1884. KeyStruct = GetKeyStruct (NodeOffset);
  1885. //
  1886. // If right child exist, go to leftmost node of right child
  1887. //
  1888. if (KeyStruct->Right != INVALID_OFFSET) {
  1889. //
  1890. // Go to right child
  1891. //
  1892. NodeOffset = KeyStruct->Right;
  1893. //
  1894. // Go to left-most of right child
  1895. //
  1896. KeyStruct = GetKeyStruct (NodeOffset);
  1897. while (KeyStruct->Left != INVALID_OFFSET) {
  1898. NodeOffset = KeyStruct->Left;
  1899. KeyStruct = GetKeyStruct (NodeOffset);
  1900. }
  1901. }
  1902. //
  1903. // Else move up to parent
  1904. //
  1905. else {
  1906. //
  1907. // Climb to top of processed nodes
  1908. //
  1909. do {
  1910. Last = NodeOffset;
  1911. NodeOffset = KeyStruct->Parent;
  1912. if (NodeOffset != INVALID_OFFSET) {
  1913. KeyStruct = GetKeyStruct (NodeOffset);
  1914. } else {
  1915. break; // reached the root of tree
  1916. }
  1917. } while (Last == KeyStruct->Right);
  1918. }
  1919. return NodeOffset;
  1920. }
  1921. DWORD
  1922. pFindPatternKeyStruct (
  1923. IN DWORD RootOffset,
  1924. IN DWORD NodeOffset,
  1925. IN PCWSTR KeyName
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. pFindPatternKeyStruct takes a key name and looks for the
  1930. offset in the tree specified by RootOffset. The key name must
  1931. not contain backslashes, and the stored key name is
  1932. treated as a pattern.
  1933. Arguments:
  1934. RootOffset - An offset to the root of the level
  1935. NodeOffset - The previous return value from pFindPatternKeyStruct
  1936. (for enumeration) or INVALID_OFFSET for the first
  1937. call.
  1938. KeyName - The name of the key to find in the binary tree
  1939. Return Value:
  1940. An offset to the structure, or INVALID_OFFSET if the key
  1941. was not found.
  1942. --*/
  1943. {
  1944. PKEYSTRUCT KeyStruct;
  1945. //
  1946. // if NodeOffset is invalid, this is the first search item
  1947. //
  1948. if (NodeOffset == INVALID_OFFSET) {
  1949. NodeOffset = GetFirstOffset (RootOffset);
  1950. }
  1951. //
  1952. // otherwise advance NodeOffset
  1953. //
  1954. else {
  1955. NodeOffset = GetNextOffset (NodeOffset);
  1956. }
  1957. //
  1958. // Examine key as a pattern, then go to next node
  1959. //
  1960. while (NodeOffset != INVALID_OFFSET) {
  1961. KeyStruct = GetKeyStruct (NodeOffset);
  1962. // Compare key (string in KeyStruct->KeyToken is the pattern)
  1963. if (IsPatternMatchW (GetKeyToken (KeyStruct->KeyToken), KeyName)) {
  1964. return NodeOffset;
  1965. }
  1966. // No match yet - go to next node
  1967. NodeOffset = GetNextOffset (NodeOffset);
  1968. }
  1969. return INVALID_OFFSET;
  1970. }
  1971. DWORD
  1972. pFindKeyStructUsingPattern (
  1973. IN DWORD RootOffset,
  1974. IN DWORD NodeOffset,
  1975. IN PCWSTR PatternStr
  1976. )
  1977. /*++
  1978. Routine Description:
  1979. pFindKeyStructUsingPattern takes a key pattern and looks
  1980. for the offset in the tree specified by RootOffset. The key
  1981. name must not contain backslashes, but can contain wildcards.
  1982. Arguments:
  1983. RootOffset - An offset to the root of the level
  1984. NodeOffset - The previous return value from pFindPatternKeyStruct
  1985. (for enumeration) or INVALID_OFFSET for the first
  1986. call.
  1987. KeyName - The name of the key to find in the binary tree
  1988. Return Value:
  1989. An offset to the structure, or INVALID_OFFSET if the key
  1990. was not found.
  1991. --*/
  1992. {
  1993. PKEYSTRUCT KeyStruct;
  1994. // if NodeOffset is invalid, this is the first search item
  1995. if (NodeOffset == INVALID_OFFSET) {
  1996. NodeOffset = GetFirstOffset (RootOffset);
  1997. }
  1998. // otherwise advance NodeOffset
  1999. else {
  2000. NodeOffset = GetNextOffset (NodeOffset);
  2001. }
  2002. //
  2003. // Examine key as a pattern, then go to next node
  2004. //
  2005. while (NodeOffset != INVALID_OFFSET) {
  2006. KeyStruct = GetKeyStruct (NodeOffset);
  2007. // Compare key
  2008. if (IsPatternMatchW (PatternStr, GetKeyToken (KeyStruct->KeyToken))) {
  2009. return NodeOffset;
  2010. }
  2011. // No match yet - go to next node
  2012. NodeOffset = GetNextOffset (NodeOffset);
  2013. }
  2014. return INVALID_OFFSET;
  2015. }
  2016. DWORD
  2017. pFindPatternKeyStructUsingPattern (
  2018. IN DWORD RootOffset,
  2019. IN DWORD NodeOffset,
  2020. IN PCWSTR PatternStr
  2021. )
  2022. /*++
  2023. Routine Description:
  2024. pFindPatternKeyStructUsingPattern takes a key pattern and looks
  2025. for the offset in the tree specified by RootOffset. The key name
  2026. must not contain backslashes, but can contain wildcards. The
  2027. wildcards in the stored key are processed as well.
  2028. Arguments:
  2029. RootOffset - An offset to the root of the level
  2030. NodeOffset - The previous return value from pFindPatternKeyStruct
  2031. (for enumeration) or INVALID_OFFSET for the first
  2032. call.
  2033. KeyName - The name of the key to find in the binary tree
  2034. Return Value:
  2035. An offset to the structure, or INVALID_OFFSET if the key
  2036. was not found.
  2037. --*/
  2038. {
  2039. PKEYSTRUCT KeyStruct;
  2040. // if NodeOffset is invalid, this is the first search item
  2041. if (NodeOffset == INVALID_OFFSET) {
  2042. NodeOffset = GetFirstOffset (RootOffset);
  2043. }
  2044. // otherwise advance NodeOffset
  2045. else {
  2046. NodeOffset = GetNextOffset (NodeOffset);
  2047. }
  2048. //
  2049. // Examine key as a pattern, then go to next node
  2050. //
  2051. while (NodeOffset != INVALID_OFFSET) {
  2052. KeyStruct = GetKeyStruct (NodeOffset);
  2053. // Compare key (PatternStr is the pattern)
  2054. if (IsPatternMatchW (PatternStr, GetKeyToken (KeyStruct->KeyToken))) {
  2055. return NodeOffset;
  2056. }
  2057. // Compare key (string in KeyStruct->KeyToken is the pattern)
  2058. if (IsPatternMatchW (GetKeyToken (KeyStruct->KeyToken), PatternStr)) {
  2059. return NodeOffset;
  2060. }
  2061. // No match yet - go to next node
  2062. NodeOffset = GetNextOffset (NodeOffset);
  2063. }
  2064. return INVALID_OFFSET;
  2065. }
  2066. DWORD
  2067. FindKey (
  2068. IN PCWSTR FullKeyPath
  2069. )
  2070. /*++
  2071. Routine Description:
  2072. FindKey locates a complete key string and returns
  2073. the offset to the KEYSTRUCT, or INVALID_OFFSET if
  2074. the key path does not exist. The FullKeyPath
  2075. must supply the complete path to the KEYSTRUCT.
  2076. Arguments:
  2077. FullKeyPath - A backslash-delimited key path to a value
  2078. Return Value:
  2079. An offset to the structure, or INVALID_OFFSET if the key
  2080. was not found.
  2081. --*/
  2082. {
  2083. return FindStringInHashTable (FullKeyPath, NULL);
  2084. }
  2085. DWORD
  2086. FindPatternKey (
  2087. IN DWORD RootOffset,
  2088. IN PCWSTR FullKeyPath,
  2089. IN BOOL EndPatternAllowed
  2090. )
  2091. /*++
  2092. Routine Description:
  2093. FindPatternKey locates a complete key string and returns
  2094. the offset to the KEYSTRUCT, or INVALID_OFFSET if the
  2095. key path does not exist. Each stored part of the key is
  2096. treated as a pattern, and FullKeyPath must supply the
  2097. complete path to the KEYSTRUCT without wildcards.
  2098. Arguments:
  2099. RootOffset - An offset to the level's binary tree root
  2100. FullKeyPath - A backslash-delimited key path to a value
  2101. without wildcards.
  2102. EndPatternAllowed - Specifies TRUE if the stored pattern can
  2103. have an asterisk at the end, to indicate
  2104. any subkeys, or FALSE if the pattern matches
  2105. on the same level only.
  2106. Return Value:
  2107. An offset to the structure, or INVALID_OFFSET if the key
  2108. was not found.
  2109. --*/
  2110. {
  2111. WCHAR Path[MEMDB_MAX + 1];
  2112. PWSTR p;
  2113. PCWSTR End;
  2114. //
  2115. // Divide the string into a multi-sz
  2116. //
  2117. StringCopyW (Path, FullKeyPath);
  2118. for (p = Path ; *p ; p++) {
  2119. if (*p == L'\\') {
  2120. *p = 0;
  2121. }
  2122. }
  2123. End = p;
  2124. if (End > Path && *(End - 1) == 0) {
  2125. //
  2126. // Special case: the wack was at the end of the string.
  2127. // Therefore, inc End so we test that final empty value.
  2128. //
  2129. End++;
  2130. }
  2131. if (End == Path) {
  2132. DEBUGMSG ((DBG_ERROR, "FindPatternKey: Empty key not allowed"));
  2133. return INVALID_OFFSET;
  2134. }
  2135. //
  2136. // Now test the key against all stored patterns
  2137. //
  2138. return pFindPatternKeyWorker (Path, End, RootOffset, EndPatternAllowed);
  2139. }
  2140. DWORD
  2141. pFindPatternKeyWorker (
  2142. IN PCWSTR SubKey,
  2143. IN PCWSTR End,
  2144. IN DWORD RootOffset,
  2145. IN BOOL EndPatternAllowed
  2146. )
  2147. {
  2148. DWORD Offset;
  2149. PCWSTR NextSubKey;
  2150. DWORD MatchOffset;
  2151. PKEYSTRUCT KeyStruct;
  2152. NextSubKey = GetEndOfString (SubKey) + 1;
  2153. // Begin an enumeration of the matches
  2154. Offset = pFindPatternKeyStruct (RootOffset, INVALID_OFFSET, SubKey);
  2155. while (Offset != INVALID_OFFSET) {
  2156. //
  2157. // Is there more in the caller's key string to test?
  2158. //
  2159. if (NextSubKey < End) {
  2160. //
  2161. // Yes, call pFindPatternKeyWorker recursively
  2162. //
  2163. MatchOffset = pFindPatternKeyWorker (
  2164. NextSubKey,
  2165. End,
  2166. GetKeyStruct (Offset)->NextLevelRoot,
  2167. EndPatternAllowed
  2168. );
  2169. if (MatchOffset != INVALID_OFFSET) {
  2170. //
  2171. // We found one match. There may be others, but
  2172. // we return this one.
  2173. //
  2174. return MatchOffset;
  2175. }
  2176. } else {
  2177. //
  2178. // No, if this is an endpoint, return the match.
  2179. //
  2180. KeyStruct = GetKeyStruct (Offset);
  2181. if (KeyStruct->Flags & KSF_ENDPOINT) {
  2182. return Offset;
  2183. }
  2184. }
  2185. // Continue enumeration
  2186. Offset = pFindPatternKeyStruct (RootOffset, Offset, SubKey);
  2187. }
  2188. //
  2189. // The normal search failed. Now we test for an endpoint that has
  2190. // just an asterisk. If we find one, we return it as our match.
  2191. // This only applies when we have more subkeys, and EndPatternAllowed
  2192. // is TRUE.
  2193. //
  2194. if (NextSubKey < End && EndPatternAllowed) {
  2195. // Begin another enumeration of the matches
  2196. Offset = pFindPatternKeyStruct (RootOffset, INVALID_OFFSET, SubKey);
  2197. while (Offset != INVALID_OFFSET) {
  2198. //
  2199. // If EndPatternAllowed is TRUE, then test this offset
  2200. // for an exact match with an asterisk.
  2201. //
  2202. KeyStruct = GetKeyStruct (Offset);
  2203. if (KeyStruct->Flags & KSF_ENDPOINT) {
  2204. if (StringMatchW (GetKeyToken (KeyStruct->KeyToken), L"*")) {
  2205. return Offset;
  2206. }
  2207. }
  2208. // Continue enumeration
  2209. Offset = pFindPatternKeyStruct (RootOffset, Offset, SubKey);
  2210. }
  2211. }
  2212. //
  2213. // No match was found
  2214. //
  2215. return INVALID_OFFSET;
  2216. }
  2217. DWORD
  2218. FindKeyUsingPattern (
  2219. IN DWORD RootOffset,
  2220. IN PCWSTR FullKeyPath
  2221. )
  2222. /*++
  2223. Routine Description:
  2224. FindKeyUsingPattern locates a key string using a pattern
  2225. and returns the offset to the KEYSTRUCT, or INVALID_OFFSET
  2226. if the key path does not exist. Each part of the stored key
  2227. is treated as a literal string.
  2228. Arguments:
  2229. RootOffset - An offset to the level's binary tree root
  2230. FullKeyPath - A backslash-delimited key path to a value
  2231. with optional wildcards.
  2232. Return Value:
  2233. An offset to the structure, or INVALID_OFFSET if the key
  2234. was not found.
  2235. --*/
  2236. {
  2237. WCHAR Path[MEMDB_MAX];
  2238. PWSTR p;
  2239. PWSTR Start, End;
  2240. DWORD Offset, NextLevelOffset;
  2241. StringCopyW (Path, FullKeyPath);
  2242. End = Path;
  2243. //
  2244. // Split string at backslash
  2245. //
  2246. Start = End;
  2247. p = wcschr (End, '\\');
  2248. if (p) {
  2249. End = _wcsinc (p);
  2250. *p = 0;
  2251. } else {
  2252. End = NULL;
  2253. }
  2254. //
  2255. // Look at this level for the very first key
  2256. //
  2257. Offset = pFindKeyStructUsingPattern (RootOffset, INVALID_OFFSET, Start);
  2258. //
  2259. // If this is the last level, we may have found the key!
  2260. //
  2261. if (!End) {
  2262. while (Offset != INVALID_OFFSET) {
  2263. if (GetKeyStruct (Offset)->Flags & KSF_ENDPOINT) {
  2264. return Offset;
  2265. }
  2266. Offset = pFindKeyStructUsingPattern (RootOffset, Offset, Start);
  2267. }
  2268. }
  2269. //
  2270. // Otherwise recursively examine next level
  2271. //
  2272. while (Offset != INVALID_OFFSET) {
  2273. //
  2274. // Look at all subkeys for a match
  2275. //
  2276. NextLevelOffset = GetKeyStruct (Offset)->NextLevelRoot;
  2277. NextLevelOffset = FindKeyUsingPattern (NextLevelOffset, End);
  2278. //
  2279. // When the recursive search succeeded, propagate the return value
  2280. //
  2281. if (NextLevelOffset != INVALID_OFFSET) {
  2282. return NextLevelOffset;
  2283. }
  2284. //
  2285. // No match, continue looking in this level for another match
  2286. //
  2287. Offset = pFindKeyStructUsingPattern (RootOffset, Offset, Start);
  2288. }
  2289. return INVALID_OFFSET;
  2290. }
  2291. DWORD
  2292. FindPatternKeyUsingPattern (
  2293. IN DWORD RootOffset,
  2294. IN PCWSTR FullKeyPath
  2295. )
  2296. /*++
  2297. Routine Description:
  2298. pFindPatternKeyUsingPattern locates a patterned key string
  2299. using a pattern and returns the offset to the KEYSTRUCT,
  2300. or INVALID_OFFSET if the key path does not exist. Each
  2301. part of the key is treated as a pattern.
  2302. Arguments:
  2303. RootOffset - An offset to the level's binary tree root
  2304. FullKeyPath - A backslash-delimited key path to a value
  2305. with optional wildcards.
  2306. Return Value:
  2307. An offset to the structure, or INVALID_OFFSET if the key
  2308. was not found.
  2309. --*/
  2310. {
  2311. WCHAR Path[MEMDB_MAX];
  2312. PWSTR p;
  2313. PWSTR Start, End;
  2314. DWORD Offset, NextLevelOffset;
  2315. StringCopyW (Path, FullKeyPath);
  2316. End = Path;
  2317. // Split string at backslash
  2318. Start = End;
  2319. p = wcschr (End, L'\\');
  2320. if (p) {
  2321. End = p + 1;
  2322. *p = 0;
  2323. }
  2324. else
  2325. End = NULL;
  2326. // Look at this level for the very first key
  2327. Offset = pFindPatternKeyStructUsingPattern (RootOffset, INVALID_OFFSET, Start);
  2328. // If this is the last level, we may have found the key!
  2329. if (!End) {
  2330. while (Offset != INVALID_OFFSET) {
  2331. if (GetKeyStruct (Offset)->Flags & KSF_ENDPOINT)
  2332. return Offset;
  2333. Offset = pFindPatternKeyStructUsingPattern (RootOffset, Offset, Start);
  2334. }
  2335. }
  2336. // Otherwise recursively examine next level
  2337. while (Offset != INVALID_OFFSET) {
  2338. // Look at all subkeys for a match
  2339. NextLevelOffset = GetKeyStruct (Offset)->NextLevelRoot;
  2340. NextLevelOffset = FindPatternKeyUsingPattern (NextLevelOffset, End);
  2341. // When the recursive search succeeded, propagate the return value
  2342. if (NextLevelOffset != INVALID_OFFSET)
  2343. return NextLevelOffset;
  2344. // No match, continue looking in this level for another match
  2345. Offset = pFindPatternKeyStructUsingPattern (RootOffset, Offset, Start);
  2346. }
  2347. return INVALID_OFFSET;
  2348. }
  2349. DWORD
  2350. pNewKey (
  2351. IN PCWSTR KeyStr,
  2352. IN PCWSTR KeyStrWithHive,
  2353. IN BOOL Endpoint
  2354. )
  2355. /*++
  2356. Routine Description:
  2357. NewKey allocates a key struct off our heap, and links it into the binary
  2358. tree. KeyStr must be a full key path, and any part of the path that does
  2359. not exist will be created. KeyStr must not already exist (though parts
  2360. of it can exist).
  2361. Arguments:
  2362. KeyStr - The full path to the value, separated by backslashes.
  2363. Each string between backslashes will cause a key
  2364. struct to be allocated and linked. Some of the
  2365. structs may already have been allocated.
  2366. KeyStrWithHive - The full path to the value, plus the hive
  2367. prefix (if any). Can be the same as KeyStr
  2368. if there is no hive prefix.
  2369. Endpoint - Specifies TRUE if new node is an endpoint, or FALSE if
  2370. it is not.
  2371. Return Value:
  2372. An offset to the last node of the new structure, or
  2373. INVALID_OFFSET if the key could not be allocated.
  2374. --*/
  2375. {
  2376. WCHAR Path[MEMDB_MAX];
  2377. PWSTR p;
  2378. PWSTR Start, End;
  2379. DWORD Offset, ThisLevelRoot;
  2380. PDWORD ParentOffsetPtr;
  2381. PKEYSTRUCT KeyStruct;
  2382. DWORD LastLevel;
  2383. BOOL NewNodeCreated = FALSE;
  2384. StringCopyW (Path, KeyStr);
  2385. End = Path;
  2386. ThisLevelRoot = g_db->FirstLevelRoot;
  2387. ParentOffsetPtr = &g_db->FirstLevelRoot;
  2388. LastLevel = INVALID_OFFSET;
  2389. do {
  2390. // Split string at backslash
  2391. Start = End;
  2392. p = wcschr (End, L'\\');
  2393. if (p) {
  2394. End = p + 1;
  2395. *p = 0;
  2396. }
  2397. else
  2398. End = NULL;
  2399. // Look in tree for key
  2400. if (!NewNodeCreated) {
  2401. Offset = FindKeyStruct (ThisLevelRoot, Start);
  2402. } else {
  2403. Offset = INVALID_OFFSET;
  2404. }
  2405. if (Offset == INVALID_OFFSET) {
  2406. // Add a new key if it was not found
  2407. Offset = pAllocKeyStruct (ParentOffsetPtr, Start, LastLevel);
  2408. if (Offset == INVALID_OFFSET) {
  2409. return Offset;
  2410. }
  2411. NewNodeCreated = TRUE;
  2412. }
  2413. // Continue to next level
  2414. KeyStruct = GetKeyStruct (Offset);
  2415. LastLevel = Offset;
  2416. ThisLevelRoot = KeyStruct->NextLevelRoot;
  2417. ParentOffsetPtr = &KeyStruct->NextLevelRoot;
  2418. } while (End);
  2419. if (Endpoint) {
  2420. if (!(KeyStruct->Flags & KSF_ENDPOINT)) {
  2421. NewNodeCreated = TRUE;
  2422. }
  2423. KeyStruct->Flags |= KSF_ENDPOINT;
  2424. if (NewNodeCreated) {
  2425. AddHashTableEntry (KeyStr, Offset);
  2426. }
  2427. }
  2428. return Offset;
  2429. }
  2430. DWORD
  2431. NewKey (
  2432. IN PCWSTR KeyStr,
  2433. IN PCWSTR KeyStrWithHive
  2434. )
  2435. {
  2436. return pNewKey (KeyStr, KeyStrWithHive, TRUE);
  2437. }
  2438. VOID
  2439. DeleteKey (
  2440. IN PCWSTR KeyStr,
  2441. IN OUT PDWORD RootPtr,
  2442. IN BOOL MustMatch
  2443. )
  2444. /*++
  2445. Routine Description:
  2446. DeleteKey takes a key path and puts the key struct in the deleted
  2447. block chain. Any sub-levels are deleted as well. Optionally,
  2448. the binary tree in which the key participates in may be updated.
  2449. Arguments:
  2450. KeyStr - The full path to the value, separated by backslashes.
  2451. RootPtr - A pointer to the level's binary tree root variable.
  2452. If necessary, the variable is updated.
  2453. MustMatch - A flag indicating if the delete only applies to
  2454. end points or if any matching struct is to be deleted.
  2455. TRUE indicates only endpoints can be deleted.
  2456. Return Value:
  2457. none
  2458. --*/
  2459. {
  2460. WCHAR Path[MEMDB_MAX];
  2461. PWSTR p;
  2462. PWSTR Start, End;
  2463. DWORD Offset;
  2464. DWORD NextOffset;
  2465. PKEYSTRUCT KeyStruct;
  2466. INCSTAT(g_Deletions);
  2467. StringCopyW (Path, KeyStr);
  2468. End = Path;
  2469. //
  2470. // Split string at backslash
  2471. //
  2472. Start = End;
  2473. p = wcschr (End, L'\\');
  2474. if (p) {
  2475. End = _wcsinc (p);
  2476. *p = 0;
  2477. } else {
  2478. End = NULL;
  2479. }
  2480. //
  2481. // Look at this level for the very first key
  2482. //
  2483. Offset = pFindKeyStructUsingPattern (*RootPtr, INVALID_OFFSET, Start);
  2484. //
  2485. // If this is the last level, delete the matching keys
  2486. // (may need to be endpoints if MustMatch is TRUE)
  2487. //
  2488. if (!End) {
  2489. while (Offset != INVALID_OFFSET) {
  2490. KeyStruct = GetKeyStruct (Offset);
  2491. NextOffset = pFindKeyStructUsingPattern (*RootPtr, Offset, Start);
  2492. //
  2493. // If must match and lower levels exist, don't delete, just turn
  2494. // off the endpoint flag
  2495. //
  2496. if (MustMatch && KeyStruct->NextLevelRoot != INVALID_OFFSET) {
  2497. // Call to clean up, not to delink or recurse
  2498. pDeallocKeyStruct (Offset, RootPtr, FALSE, TRUE);
  2499. }
  2500. //
  2501. // Else delete the struct if an endpoint or don't care about
  2502. // endpoints
  2503. //
  2504. else if (!MustMatch || (KeyStruct->Flags & KSF_ENDPOINT)) {
  2505. // Call to free the entire key struct and all children
  2506. pDeallocKeyStruct (Offset, RootPtr, TRUE, FALSE);
  2507. }
  2508. Offset = NextOffset;
  2509. }
  2510. }
  2511. //
  2512. // Otherwise recursively examine next level for each match
  2513. //
  2514. else {
  2515. while (Offset != INVALID_OFFSET) {
  2516. //
  2517. // Delete all matching subkeys
  2518. //
  2519. NextOffset = pFindKeyStructUsingPattern (*RootPtr, Offset, Start);
  2520. DeleteKey (End, &GetKeyStruct (Offset)->NextLevelRoot, MustMatch);
  2521. //
  2522. // If this is not an endpoint and has no children, delete it
  2523. //
  2524. KeyStruct = GetKeyStruct (Offset);
  2525. if (KeyStruct->NextLevelRoot == INVALID_OFFSET &&
  2526. !(KeyStruct->Flags & KSF_ENDPOINT)
  2527. ) {
  2528. // Call to free the entire key struct
  2529. pDeallocKeyStruct (Offset, RootPtr, TRUE, FALSE);
  2530. }
  2531. //
  2532. // Continue looking in this level for another match
  2533. //
  2534. Offset = NextOffset;
  2535. }
  2536. }
  2537. }
  2538. VOID
  2539. CopyValToPtr (
  2540. PKEYSTRUCT KeyStruct,
  2541. PDWORD ValPtr
  2542. )
  2543. {
  2544. if (ValPtr) {
  2545. if (!(KeyStruct->Flags & KSF_BINARY)) {
  2546. *ValPtr = KeyStruct->dwValue;
  2547. } else {
  2548. *ValPtr = 0;
  2549. }
  2550. }
  2551. }
  2552. VOID
  2553. CopyFlagsToPtr (
  2554. PKEYSTRUCT KeyStruct,
  2555. PDWORD ValPtr
  2556. )
  2557. {
  2558. if (ValPtr) {
  2559. *ValPtr = KeyStruct->Flags & KSF_USERFLAG_MASK;
  2560. }
  2561. }
  2562. BOOL
  2563. PrivateBuildKeyFromOffset (
  2564. IN DWORD StartLevel, // zero-based
  2565. IN DWORD TailOffset,
  2566. OUT PWSTR Buffer, OPTIONAL
  2567. OUT PDWORD ValPtr, OPTIONAL
  2568. OUT PDWORD UserFlagsPtr, OPTIONAL
  2569. OUT PDWORD Chars OPTIONAL
  2570. )
  2571. /*++
  2572. Routine Description:
  2573. PrivateBuildKeyFromOffset generates the key string given an offset. The
  2574. caller can specify the start level to skip root nodes. It is assumed that
  2575. TailOffset is always valid.
  2576. Arguments:
  2577. StartLevel - Specifies the zero-based level to begin building the key
  2578. string. This is used to skip the root portion of the key
  2579. string.
  2580. TailOffset - Specifies the offset to the last level of the key string.
  2581. Buffer - Receives the key string, must be able to hold MEMDB_MAX
  2582. characters.
  2583. ValPtr - Receives the key's value
  2584. UserFlagsPtr - Receives the user flags
  2585. Chars - Receives the number of characters in Buffer
  2586. Return Value:
  2587. TRUE if the key was build properly, FALSE otherwise.
  2588. --*/
  2589. {
  2590. static DWORD Offsets[MEMDB_MAX];
  2591. PKEYSTRUCT KeyStruct;
  2592. DWORD CurrentOffset;
  2593. DWORD OffsetEnd;
  2594. DWORD OffsetStart;
  2595. register PWSTR p;
  2596. register PCWSTR s;
  2597. //
  2598. // Build string
  2599. //
  2600. OffsetEnd = MEMDB_MAX;
  2601. OffsetStart = OffsetEnd;
  2602. CurrentOffset = TailOffset;
  2603. while (CurrentOffset != INVALID_OFFSET) {
  2604. //
  2605. // Record offset
  2606. //
  2607. OffsetStart--;
  2608. Offsets[OffsetStart] = CurrentOffset;
  2609. //
  2610. // Dec for start level and go to parent
  2611. //
  2612. CurrentOffset = pGetKeyStructWithProxy (CurrentOffset)->PrevLevelNode;
  2613. }
  2614. //
  2615. // Filter for "string is not long enough"
  2616. //
  2617. OffsetStart += StartLevel;
  2618. if (OffsetStart >= OffsetEnd) {
  2619. return FALSE;
  2620. }
  2621. //
  2622. // Transfer node's value and flags to caller's variables
  2623. //
  2624. CopyValToPtr (pGetKeyStructWithProxy (TailOffset), ValPtr);
  2625. CopyFlagsToPtr (pGetKeyStructWithProxy (TailOffset), UserFlagsPtr);
  2626. //
  2627. // Copy each piece of the string to Buffer and calculate character count
  2628. //
  2629. if (Buffer) {
  2630. p = Buffer;
  2631. for (CurrentOffset = OffsetStart ; CurrentOffset < OffsetEnd ; CurrentOffset++) {
  2632. KeyStruct = pGetKeyStructWithProxy (Offsets[CurrentOffset]);
  2633. s = GetKeyToken (KeyStruct->KeyToken);
  2634. while (*s) {
  2635. *p++ = *s++;
  2636. }
  2637. *p++ = L'\\';
  2638. }
  2639. p--;
  2640. *p = 0;
  2641. if (Chars) {
  2642. *Chars = (p - Buffer) / sizeof (WCHAR);
  2643. }
  2644. } else if (Chars) {
  2645. *Chars = 0;
  2646. for (CurrentOffset = OffsetStart ; CurrentOffset < OffsetEnd ; CurrentOffset++) {
  2647. KeyStruct = pGetKeyStructWithProxy (Offsets[CurrentOffset]);
  2648. *Chars += wcslen(GetKeyToken (KeyStruct->KeyToken)) + 1;
  2649. }
  2650. *Chars -= 1;
  2651. }
  2652. return TRUE;
  2653. }
  2654. UINT
  2655. pComputeTokenHash (
  2656. IN PCWSTR KeyName
  2657. )
  2658. {
  2659. UINT hash;
  2660. hash = 0;
  2661. while (*KeyName) {
  2662. hash = (hash << 1) ^ (*KeyName++);
  2663. }
  2664. return hash % TOKENBUCKETS;
  2665. }
  2666. DWORD
  2667. pFindKeyToken (
  2668. IN PCWSTR KeyName,
  2669. OUT PUINT Hash
  2670. )
  2671. {
  2672. DWORD offset;
  2673. PTOKENSTRUCT tokenStruct;
  2674. INT cmp;
  2675. *Hash = pComputeTokenHash (KeyName);
  2676. offset = g_db->TokenBuckets[*Hash];
  2677. while (offset != INVALID_OFFSET) {
  2678. tokenStruct = (PTOKENSTRUCT) (g_db->Buf + offset);
  2679. if (StringMatchW (tokenStruct->String, KeyName)) {
  2680. break;
  2681. }
  2682. offset = tokenStruct->Right;
  2683. }
  2684. return offset;
  2685. }
  2686. DWORD
  2687. pAllocKeyToken (
  2688. IN PCWSTR KeyName,
  2689. OUT PINT AdjustFactor
  2690. )
  2691. {
  2692. PTOKENSTRUCT tokenStruct;
  2693. PTOKENSTRUCT tokenParent;
  2694. DWORD tokenOffset;
  2695. UINT size;
  2696. PDWORD parentToChildLink;
  2697. DWORD newNodeParentOffset;
  2698. DWORD pivotPoint;
  2699. INT cmp;
  2700. UINT hash;
  2701. //
  2702. // Use existing token first
  2703. //
  2704. tokenOffset = pFindKeyToken (KeyName, &hash);
  2705. if (tokenOffset != INVALID_OFFSET) {
  2706. *AdjustFactor = 0;
  2707. return tokenOffset;
  2708. }
  2709. //
  2710. // Existing token does not exist -- allocate a new one
  2711. //
  2712. size = sizeof (TOKENSTRUCT) + SizeOfStringW (KeyName);
  2713. tokenStruct = (PTOKENSTRUCT) pAllocMemoryFromDb (
  2714. size,
  2715. &tokenOffset,
  2716. AdjustFactor
  2717. );
  2718. tokenStruct->Right = g_db->TokenBuckets[hash];
  2719. StringCopyW (tokenStruct->String, KeyName);
  2720. g_db->TokenBuckets[hash] = tokenOffset;
  2721. return tokenOffset;
  2722. }
  2723. VOID
  2724. pDeallocToken (
  2725. IN DWORD Token
  2726. )
  2727. {
  2728. return;
  2729. }
  2730. PCWSTR
  2731. GetKeyToken (
  2732. IN DWORD Token
  2733. )
  2734. {
  2735. PTOKENSTRUCT tokenStruct;
  2736. tokenStruct = (PTOKENSTRUCT) (g_db->Buf + Token);
  2737. return tokenStruct->String;
  2738. }