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.

2568 lines
69 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. object.c
  5. Abstract:
  6. Routines to manage an 'object' which currently can only be a registry
  7. key, value name, value, handle and root handle.
  8. Author:
  9. Jim Schmidt (jimschm) 14-Feb-1997
  10. Revision History:
  11. marcw 09-Mar-1999 Don't create empty keys that didn't exist in Win9x Registry.
  12. --*/
  13. #include "pch.h"
  14. #include "mergep.h"
  15. extern POOLHANDLE g_TempPool;
  16. extern DWORD g_ProgressBarCounter;
  17. BOOL AllocObjectVal (IN OUT PDATAOBJECT SrcObPtr, IN PBYTE Value, IN DWORD Size, IN DWORD AllocSize);
  18. VOID FreeObjectVal (IN OUT PDATAOBJECT SrcObPtr);
  19. #define NON_ROOT_KEY(Key) ((Key) && ((UINT)(Key) < 0x7fffff00))
  20. #ifdef DEBUG
  21. static TCHAR g_DebugEncoding[MAX_ENCODED_RULE];
  22. PCTSTR
  23. DebugEncoder (
  24. PVOID ObPtr
  25. )
  26. {
  27. CreateObjectString ((CPDATAOBJECT) ObPtr, g_DebugEncoding);
  28. return g_DebugEncoding;
  29. }
  30. #endif
  31. PKEYPROPS
  32. pCreateKeyPropsFromString (
  33. PCTSTR KeyString,
  34. BOOL Win95Flag
  35. )
  36. {
  37. PKEYPROPS RegKey;
  38. RegKey = (PKEYPROPS) PoolMemGetAlignedMemory (
  39. g_TempPool,
  40. sizeof (KEYPROPS) + SizeOfString (KeyString)
  41. );
  42. StringCopy (RegKey->KeyString, KeyString);
  43. RegKey->UseCount = 1;
  44. RegKey->OpenCount = 0;
  45. RegKey->OpenKey = NULL;
  46. RegKey->Win95 = Win95Flag;
  47. return RegKey;
  48. }
  49. VOID
  50. pFreeKeyProps (
  51. PKEYPROPS RegKey
  52. )
  53. {
  54. RegKey->UseCount--;
  55. if (!RegKey->UseCount) {
  56. // Close the key if it is open
  57. if (NON_ROOT_KEY (RegKey->OpenKey)) {
  58. if (RegKey->Win95) {
  59. CloseRegKey95 (RegKey->OpenKey);
  60. } else {
  61. CloseRegKey (RegKey->OpenKey);
  62. }
  63. }
  64. // Free the KEYPROPS memory
  65. PoolMemReleaseMemory (g_TempPool, RegKey);
  66. }
  67. }
  68. VOID
  69. pIncKeyPropUse (
  70. PKEYPROPS RegKey
  71. )
  72. {
  73. RegKey->UseCount++;
  74. if (RegKey->OpenKey) {
  75. RegKey->OpenCount++;
  76. }
  77. }
  78. PKEYPROPS
  79. pCreateDuplicateKeyProps (
  80. PKEYPROPS RegKey,
  81. BOOL Win95Flag
  82. )
  83. {
  84. PKEYPROPS NewRegKey;
  85. NewRegKey = pCreateKeyPropsFromString (RegKey->KeyString, Win95Flag);
  86. pFreeKeyProps (RegKey);
  87. return NewRegKey;
  88. }
  89. HKEY
  90. pGetWinNTKey (
  91. HKEY Key
  92. )
  93. {
  94. if (Key == HKEY_ROOT) {
  95. return g_hKeyRootNT;
  96. }
  97. return Key;
  98. }
  99. HKEY
  100. pGetWin95Key (
  101. HKEY Key
  102. )
  103. {
  104. if (Key == HKEY_ROOT) {
  105. return g_hKeyRoot95;
  106. }
  107. return Key;
  108. }
  109. VOID
  110. FixUpUserSpecifiedObject (
  111. PTSTR Object
  112. )
  113. {
  114. PTSTR p;
  115. // Look for a space-open bracket pair
  116. p = _tcsrchr (Object, TEXT('['));
  117. if (p) {
  118. p = _tcsdec2 (Object, p);
  119. if (p && _tcsnextc (p) == TEXT(' ')) {
  120. // Found: turn space into wack
  121. _settchar (p, TEXT('\\'));
  122. }
  123. }
  124. }
  125. VOID
  126. CreateObjectString (
  127. IN CPDATAOBJECT InObPtr,
  128. OUT PTSTR Object
  129. )
  130. {
  131. PTSTR p;
  132. *Object = 0;
  133. // Add HKR
  134. if (InObPtr->RootItem) {
  135. StringCopy (Object, GetRootStringFromOffset (InObPtr->RootItem));
  136. }
  137. // If no root, start with a wack when key is not relative
  138. else if (!(InObPtr->ObjectType & OT_REGISTRY_RELATIVE)) {
  139. if (InObPtr->KeyPtr) {
  140. StringCopy (Object, TEXT("\\"));
  141. }
  142. }
  143. // Add key
  144. if (InObPtr->KeyPtr) {
  145. if (*Object) {
  146. AppendWack (Object);
  147. }
  148. EncodeRuleChars (GetEndOfString (Object), InObPtr->KeyPtr->KeyString);
  149. }
  150. // Add tree
  151. if (InObPtr->ObjectType & OT_TREE) {
  152. if (*Object) {
  153. AppendWack (Object);
  154. StringCat (Object, TEXT("*"));
  155. }
  156. }
  157. // Add value name
  158. if (InObPtr->ValueName) {
  159. if (*Object) {
  160. AppendWack (Object);
  161. }
  162. p = _tcsappend (Object, TEXT("["));
  163. EncodeRuleChars (p, InObPtr->ValueName);
  164. StringCat (Object, TEXT("]"));
  165. }
  166. // Final product: HKR\Reg\Key\Path\*\[Root]
  167. }
  168. BOOL
  169. GetRegistryKeyStrFromObject (
  170. IN CPDATAOBJECT InObPtr,
  171. OUT PTSTR RegKey
  172. )
  173. {
  174. *RegKey = 0;
  175. // Add HKR
  176. if (InObPtr->RootItem) {
  177. StringCopy (RegKey, GetRootStringFromOffset (InObPtr->RootItem));
  178. } else {
  179. return FALSE;
  180. }
  181. // Add key
  182. if (InObPtr->KeyPtr) {
  183. EncodeRuleChars (AppendWack (RegKey), InObPtr->KeyPtr->KeyString);
  184. } else {
  185. return FALSE;
  186. }
  187. // Final product: HKR\Reg\Key\Path
  188. return TRUE;
  189. }
  190. BOOL
  191. TrackedCreateObjectStruct (
  192. IN PCTSTR Object,
  193. OUT PDATAOBJECT OutObPtr,
  194. IN BOOL Win95Flag /* , */
  195. ALLOCATION_TRACKING_DEF
  196. )
  197. {
  198. PCTSTR EndOfKey = NULL;
  199. PCTSTR EndOfSpace;
  200. PCTSTR ValueName;
  201. PCTSTR ObjectStart;
  202. TCHAR DecodeBuf[MAX_ENCODED_RULE];
  203. DWORD Length;
  204. DWORD RelativeFlag = 0;
  205. BOOL TreeFlag = FALSE;
  206. CHARTYPE ch = 0;
  207. //
  208. // Init
  209. //
  210. ObjectStart = SkipSpace (Object);
  211. ZeroMemory (OutObPtr, sizeof (DATAOBJECT));
  212. if (!(*ObjectStart)) {
  213. DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: Empty object"));
  214. return TRUE;
  215. }
  216. if (Win95Flag) {
  217. OutObPtr->ObjectType |= OT_WIN95;
  218. }
  219. //
  220. // Root
  221. //
  222. OutObPtr->RootItem = GetOffsetOfRootString (ObjectStart, &Length);
  223. if (OutObPtr->RootItem) {
  224. ObjectStart += Length;
  225. OutObPtr->ObjectType |= OT_REGISTRY;
  226. // If we have HKR\*, make ObjectStart point to \*
  227. if (_tcsnextc (ObjectStart) == TEXT('*')) {
  228. ObjectStart = _tcsdec2 (Object, ObjectStart);
  229. MYASSERT (ObjectStart);
  230. }
  231. }
  232. // If no root, starting with a wack means 'relative to the current root'
  233. else if (*ObjectStart == TEXT('\\')) {
  234. ObjectStart = _tcsinc (ObjectStart);
  235. }
  236. // If no root and key does not start with a wack, means 'relative to current key'
  237. else if (*ObjectStart != TEXT('[')) {
  238. RelativeFlag = OT_REGISTRY_RELATIVE;
  239. }
  240. //
  241. // Key
  242. //
  243. if (*ObjectStart) {
  244. // Extract key, but not tree or valuename syntax
  245. for (EndOfKey = ObjectStart ; *EndOfKey ; EndOfKey = _tcsinc (EndOfKey)) {
  246. ch = (CHARTYPE)_tcsnextc (EndOfKey);
  247. if (ch == TEXT('[') || ch == TEXT('*')) {
  248. //
  249. // EndOfKey points to start of value name or tree identifier
  250. //
  251. // Make it point to optional space before value, or
  252. // make it point to wack before asterisk of the tree identifier
  253. EndOfKey = _tcsdec2 (ObjectStart, EndOfKey);
  254. // Verify that tree identifier points to wack-asterisk, otherwise
  255. // return a syntax error
  256. if (ch == TEXT('*')) {
  257. if (!EndOfKey || _tcsnextc (EndOfKey) != TEXT('\\')) {
  258. DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: %s is not a valid object", Object));
  259. return FALSE;
  260. }
  261. // Put EndOfKey on last character of the key
  262. // (one char before \* tree identifer)
  263. EndOfKey = _tcsdec2 (ObjectStart, EndOfKey);
  264. }
  265. break;
  266. }
  267. }
  268. if (EndOfKey) {
  269. // EndOfKey points to the last character of the key, or the
  270. // nul terminating the key. We need to trim trailing space.
  271. EndOfSpace = SkipSpaceR (ObjectStart, EndOfKey);
  272. // If EndOfSpace points to a wack, back it up one char (a key
  273. // that does not have a tree identifier can end in a wack)
  274. if (ch != TEXT('*')) {
  275. if (_tcsnextc (EndOfSpace) == TEXT('\\')) {
  276. EndOfSpace = _tcsdec2 (ObjectStart, EndOfSpace);
  277. }
  278. }
  279. // Now make EndOfSpace point to the character after the end
  280. if (EndOfSpace) { // always the case when we have a valid key
  281. EndOfSpace = _tcsinc (EndOfSpace);
  282. }
  283. // Now make EndOfKey point to the first character after the key
  284. // (which is either a nul, \*, \[valuename] or [valuename])
  285. if (*EndOfKey) {
  286. EndOfKey = _tcsinc (EndOfKey);
  287. }
  288. } else {
  289. // no key found
  290. EndOfSpace = NULL;
  291. EndOfKey = ObjectStart;
  292. }
  293. // Decode key if it actually exists
  294. if (ObjectStart < EndOfSpace) {
  295. DecodeRuleCharsAB (DecodeBuf, ObjectStart, EndOfSpace);
  296. SetRegistryKey (OutObPtr, DecodeBuf);
  297. OutObPtr->ObjectType |= RelativeFlag;
  298. } else {
  299. // if HKR\*, set an empty key
  300. if (_tcsnextc (ObjectStart) != '[' && ch == TEXT('*')) {
  301. SetRegistryKey (OutObPtr, TEXT(""));
  302. }
  303. }
  304. //
  305. // Tree identifier exists
  306. //
  307. if (ch == TEXT('*')) {
  308. OutObPtr->ObjectType |= OT_TREE;
  309. // EndOfKey points to \*, so move it past the identifier
  310. EndOfKey = _tcsinc (EndOfKey);
  311. EndOfKey = _tcsinc (EndOfKey);
  312. // If we are at a wack, skip past it.
  313. if (_tcsnextc (EndOfKey) == TEXT('\\')) {
  314. EndOfKey = _tcsinc (EndOfKey);
  315. }
  316. }
  317. if (EndOfKey) {
  318. ObjectStart = EndOfKey;
  319. }
  320. }
  321. //
  322. // Value name
  323. //
  324. if (*ObjectStart) {
  325. //
  326. // ObjectStart may point to optional space
  327. //
  328. ObjectStart = SkipSpace (ObjectStart);
  329. //
  330. // ObjectStart now points to nul, [valuename] or syntax error
  331. //
  332. if (_tcsnextc (ObjectStart) == TEXT('[')) {
  333. // Skip past optional spaces following bracket
  334. ValueName = SkipSpace (_tcsinc (ObjectStart));
  335. // Locate end of [valuename]
  336. EndOfKey = ValueName;
  337. while (TRUE) {
  338. if (!(*EndOfKey)) {
  339. DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: Value name is incomplete in %s", Object));
  340. return FALSE;
  341. }
  342. ch = (CHARTYPE)_tcsnextc (EndOfKey);
  343. if (ch == TEXT(']')) {
  344. // move to first space character before closing bracket,
  345. // or leave it at the bracket if no space exists
  346. EndOfKey = _tcsdec2 (ValueName, EndOfKey);
  347. if (EndOfKey) {
  348. EndOfKey = SkipSpaceR (ValueName, EndOfKey);
  349. if (EndOfKey) {
  350. EndOfKey = _tcsinc (EndOfKey);
  351. }
  352. } else {
  353. EndOfKey = ValueName;
  354. }
  355. break;
  356. }
  357. EndOfKey = _tcsinc (EndOfKey);
  358. }
  359. // Now decode ValueName, which may be empty
  360. DecodeRuleCharsAB (DecodeBuf, ValueName, EndOfKey);
  361. SetRegistryValueName (OutObPtr, DecodeBuf);
  362. // Make ObjectStart point to nul
  363. ObjectStart = SkipSpace (_tcsinc (EndOfKey));
  364. }
  365. if (*ObjectStart) {
  366. DEBUGMSG ((DBG_WARNING, "CreateObjectStruct: %s does not have a valid value name", Object));
  367. return FALSE;
  368. }
  369. }
  370. //
  371. // The next line is normally disabled, and is enabled only when
  372. // tracking is needed.
  373. //
  374. //DebugRegisterAllocation (MERGE_OBJECT, OutObPtr, File, Line);
  375. return TRUE;
  376. }
  377. BOOL
  378. CombineObjectStructs (
  379. IN OUT PDATAOBJECT DestObPtr,
  380. IN CPDATAOBJECT SrcObPtr
  381. )
  382. {
  383. if (!SrcObPtr->ObjectType) {
  384. DEBUGMSG ((DBG_WARNING, "CombineObjectStructs: Source is empty"));
  385. return TRUE;
  386. }
  387. // The values and handles are no longer valid
  388. FreeObjectVal (DestObPtr);
  389. CloseObject (DestObPtr);
  390. // Registry object merging
  391. if (DestObPtr->ObjectType & OT_REGISTRY || !DestObPtr->ObjectType) {
  392. if (SrcObPtr->ObjectType & OT_REGISTRY) {
  393. //
  394. // Verify objects are compatible
  395. //
  396. if ((SrcObPtr->ObjectType & OT_TREE) &&
  397. (DestObPtr->ValueName)
  398. ) {
  399. DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry tree with valuename structs"));
  400. return FALSE;
  401. }
  402. if ((DestObPtr->ObjectType & OT_TREE) &&
  403. (SrcObPtr->ValueName)
  404. ) {
  405. DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry tree with valuename structs"));
  406. return FALSE;
  407. }
  408. //
  409. // Make dest ob the same platform as src ob
  410. //
  411. SetPlatformType (DestObPtr, IsWin95Object (SrcObPtr));
  412. //
  413. // Copy source's value name, key, type and root to dest
  414. // (if they exist)
  415. //
  416. if (SrcObPtr->ValueName) {
  417. SetRegistryValueName (DestObPtr, SrcObPtr->ValueName);
  418. }
  419. if (SrcObPtr->KeyPtr) {
  420. if ((SrcObPtr->ObjectType & OT_REGISTRY_RELATIVE) &&
  421. (DestObPtr->KeyPtr)
  422. ) {
  423. TCHAR CompleteKeyName[MAX_ENCODED_RULE];
  424. PTSTR p;
  425. // Src is only specifying a key name. Peel off
  426. // last key name of dest and replace it with
  427. // src.
  428. StringCopy (CompleteKeyName, DestObPtr->KeyPtr->KeyString);
  429. p = _tcsrchr (CompleteKeyName, TEXT('\\'));
  430. if (!p) {
  431. p = CompleteKeyName;
  432. } else {
  433. p = _tcsinc (p);
  434. }
  435. StringCopy (p, SrcObPtr->KeyPtr->KeyString);
  436. SetRegistryKey (DestObPtr, CompleteKeyName);
  437. } else {
  438. SetRegistryKey (DestObPtr, SrcObPtr->KeyPtr->KeyString);
  439. }
  440. }
  441. if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) {
  442. SetRegistryType (DestObPtr, SrcObPtr->Type);
  443. }
  444. if (SrcObPtr->RootItem) {
  445. DestObPtr->RootItem = SrcObPtr->RootItem;
  446. }
  447. return TRUE;
  448. }
  449. else {
  450. DEBUGMSG ((DBG_WHOOPS, "Cannot combine registry struct with other type of struct"));
  451. }
  452. }
  453. // Other type of object merging not supported
  454. DEBUGMSG ((DBG_WHOOPS, "Cannot combine unsupported or garbage objects"));
  455. return FALSE;
  456. }
  457. BOOL
  458. TrackedDuplicateObjectStruct (
  459. OUT PDATAOBJECT DestObPtr,
  460. IN CPDATAOBJECT SrcObPtr /* , */
  461. ALLOCATION_TRACKING_DEF
  462. )
  463. {
  464. ZeroMemory (DestObPtr, sizeof (DATAOBJECT));
  465. //
  466. // Create an object that has the same settings as the source,
  467. // but duplicate all strings.
  468. //
  469. if (SrcObPtr->ObjectType & OT_REGISTRY) {
  470. DestObPtr->ObjectType |= OT_REGISTRY;
  471. }
  472. if (SrcObPtr->KeyPtr) {
  473. DestObPtr->KeyPtr = SrcObPtr->KeyPtr;
  474. pIncKeyPropUse (DestObPtr->KeyPtr);
  475. }
  476. if (SrcObPtr->ValueName) {
  477. if (!SetRegistryValueName (DestObPtr, SrcObPtr->ValueName)) {
  478. LOG ((LOG_ERROR, "Error merging the registry (1)"));
  479. return FALSE;
  480. }
  481. }
  482. if (SrcObPtr->ObjectType & OT_VALUE) {
  483. if (!AllocObjectVal (
  484. DestObPtr,
  485. SrcObPtr->Value.Buffer,
  486. SrcObPtr->Value.Size,
  487. SrcObPtr->Value.AllocatedSize
  488. )) {
  489. LOG ((LOG_ERROR, "Error merging the registry (2)"));
  490. return FALSE;
  491. }
  492. }
  493. if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) {
  494. SetRegistryType (DestObPtr, SrcObPtr->Type);
  495. }
  496. DestObPtr->RootItem = SrcObPtr->RootItem;
  497. #define DUP_OBJECT_FLAGS (OT_TREE|OT_WIN95|OT_REGISTRY_RELATIVE)
  498. if (SrcObPtr->ObjectType & DUP_OBJECT_FLAGS) {
  499. DestObPtr->ObjectType |= (SrcObPtr->ObjectType & DUP_OBJECT_FLAGS);
  500. }
  501. if (SrcObPtr->ObjectType & OT_REGISTRY_ENUM_KEY) {
  502. DestObPtr->KeyEnum = SrcObPtr->KeyEnum;
  503. DestObPtr->ObjectType |= OT_REGISTRY_ENUM_KEY;
  504. }
  505. if (SrcObPtr->ObjectType & OT_REGISTRY_ENUM_VALUENAME) {
  506. DestObPtr->ValNameEnum = SrcObPtr->ValNameEnum;
  507. DestObPtr->ObjectType |= OT_REGISTRY_ENUM_VALUENAME;
  508. }
  509. if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) {
  510. if (!SetRegistryClass (DestObPtr, SrcObPtr->Class.Buffer, SrcObPtr->Class.Size)) {
  511. LOG ((LOG_ERROR, "Error merging the registry (3)"));
  512. return FALSE;
  513. }
  514. }
  515. //
  516. // The next line is normally disabled, and is enabled only when
  517. // tracking is needed.
  518. //
  519. //DebugRegisterAllocation (MERGE_OBJECT, DestObPtr, File, Line);
  520. return TRUE;
  521. }
  522. BOOL
  523. AllocObjectVal (
  524. IN OUT PDATAOBJECT SrcObPtr,
  525. IN PBYTE Value, OPTIONAL
  526. IN DWORD Size,
  527. IN DWORD AllocatedSize
  528. )
  529. {
  530. SrcObPtr->Value.Buffer = PoolMemGetAlignedMemory (g_TempPool, AllocatedSize);
  531. if (!SrcObPtr->Value.Buffer) {
  532. DEBUGMSG ((DBG_WARNING, "AllocObjectVal failed to alloc memory"));
  533. return FALSE;
  534. }
  535. SrcObPtr->Value.AllocatedSize = AllocatedSize;
  536. SrcObPtr->Value.Size = Size;
  537. if (Value) {
  538. CopyMemory (SrcObPtr->Value.Buffer, Value, AllocatedSize);
  539. }
  540. SrcObPtr->ObjectType |= OT_VALUE;
  541. return TRUE;
  542. }
  543. VOID
  544. FreeObjectVal (
  545. IN OUT PDATAOBJECT SrcObPtr
  546. )
  547. {
  548. if (SrcObPtr->ObjectType & OT_VALUE) {
  549. PoolMemReleaseMemory (g_TempPool, SrcObPtr->Value.Buffer);
  550. SrcObPtr->Value.Buffer = NULL;
  551. SrcObPtr->ObjectType &= ~OT_VALUE;
  552. }
  553. }
  554. VOID
  555. CloseObject (
  556. IN OUT PDATAOBJECT SrcObPtr
  557. )
  558. {
  559. if (!(SrcObPtr->ObjectType & OT_OPEN)) {
  560. return;
  561. }
  562. MYASSERT (IsRegistryKeyOpen (SrcObPtr));
  563. SrcObPtr->KeyPtr->OpenCount -= 1;
  564. if (!SrcObPtr->KeyPtr->OpenCount) {
  565. if (NON_ROOT_KEY (SrcObPtr->KeyPtr->OpenKey)) {
  566. if (IsWin95Object (SrcObPtr)) {
  567. CloseRegKey95 (SrcObPtr->KeyPtr->OpenKey);
  568. } else {
  569. CloseRegKey (SrcObPtr->KeyPtr->OpenKey);
  570. }
  571. }
  572. SrcObPtr->KeyPtr->OpenKey = NULL;
  573. }
  574. SrcObPtr->ObjectType &= ~OT_OPEN;
  575. }
  576. VOID
  577. FreeObjectStruct (
  578. IN OUT PDATAOBJECT SrcObPtr
  579. )
  580. {
  581. PushError();
  582. //
  583. // The next line is normally disabled, and is enabled only when
  584. // tracking is needed.
  585. //
  586. //DebugUnregisterAllocation (MERGE_OBJECT, SrcObPtr);
  587. FreeObjectVal (SrcObPtr);
  588. if (SrcObPtr->KeyPtr) {
  589. pFreeKeyProps (SrcObPtr->KeyPtr);
  590. }
  591. if (SrcObPtr->ParentKeyPtr) {
  592. pFreeKeyProps (SrcObPtr->ParentKeyPtr);
  593. }
  594. if (SrcObPtr->ValueName) {
  595. PoolMemReleaseMemory (g_TempPool, (PVOID) SrcObPtr->ValueName);
  596. }
  597. if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) {
  598. PoolMemReleaseMemory (g_TempPool, (PVOID) SrcObPtr->Class.Buffer);
  599. }
  600. ZeroMemory (SrcObPtr, sizeof (DATAOBJECT));
  601. PopError();
  602. }
  603. BOOL
  604. CreateObject (
  605. IN OUT PDATAOBJECT SrcObPtr
  606. )
  607. {
  608. DWORD rc;
  609. DWORD DontCare;
  610. PTSTR ClassPtr;
  611. if (SrcObPtr->ObjectType & OT_OPEN) {
  612. return TRUE;
  613. }
  614. if (SrcObPtr->KeyPtr) {
  615. if (SrcObPtr->KeyPtr->OpenKey) {
  616. SrcObPtr->ObjectType |= OT_OPEN;
  617. SrcObPtr->KeyPtr->OpenCount++;
  618. return TRUE;
  619. }
  620. if (IsWin95Object (SrcObPtr)) {
  621. DEBUGMSG ((DBG_WHOOPS, "Cannot create Win95 registry objects (%s)", SrcObPtr->KeyPtr->KeyString));
  622. return FALSE;
  623. }
  624. if (!SrcObPtr->KeyPtr->KeyString[0]) {
  625. // This is the root of a hive
  626. return OpenObject (SrcObPtr);
  627. }
  628. if (SrcObPtr->ObjectType & OT_REGISTRY_CLASS) {
  629. ClassPtr = (PTSTR) SrcObPtr->Class.Buffer;
  630. } else {
  631. ClassPtr = TEXT("");
  632. }
  633. if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) {
  634. rc = TrackedRegCreateKeyEx (
  635. SrcObPtr->ParentKeyPtr->OpenKey,
  636. SrcObPtr->ChildKey,
  637. 0, ClassPtr, 0,
  638. KEY_ALL_ACCESS, NULL,
  639. &SrcObPtr->KeyPtr->OpenKey,
  640. &DontCare
  641. );
  642. } else {
  643. rc = TrackedRegCreateKeyEx (
  644. pGetWinNTKey (GetRootKeyFromOffset (SrcObPtr->RootItem)),
  645. SrcObPtr->KeyPtr->KeyString,
  646. 0,
  647. ClassPtr,
  648. 0,
  649. KEY_ALL_ACCESS,
  650. NULL,
  651. &SrcObPtr->KeyPtr->OpenKey,
  652. &DontCare
  653. );
  654. }
  655. if (rc == ERROR_INVALID_PARAMETER) {
  656. //
  657. // Attempt was made to create a key directly under HKLM. There is no
  658. // backing storage, so the RegCreateKeyEx call failed with this error.
  659. // We handle it gracefully...
  660. //
  661. DEBUGMSG ((DBG_WARNING, "CreateObject: Not possible to create %s on NT", SrcObPtr->KeyPtr->KeyString));
  662. SetLastError (ERROR_SUCCESS);
  663. return FALSE;
  664. }
  665. if (rc == ERROR_ACCESS_DENIED) {
  666. //
  667. // Attempt was made to create a key that has a strong ACL. We'll
  668. // just assume success in this case.
  669. //
  670. LOG ((
  671. LOG_INFORMATION,
  672. "Can't create %s because access was denied",
  673. SrcObPtr->KeyPtr->KeyString
  674. ));
  675. SetLastError (ERROR_SUCCESS);
  676. return FALSE;
  677. }
  678. if (rc != ERROR_SUCCESS) {
  679. SetLastError (rc);
  680. LOG ((LOG_ERROR, "Failed to create a registry key (%s)", SrcObPtr->KeyPtr->KeyString));
  681. return FALSE;
  682. }
  683. SrcObPtr->KeyPtr->OpenCount = 1;
  684. SrcObPtr->ObjectType |= OT_OPEN;
  685. }
  686. return TRUE;
  687. }
  688. BOOL
  689. OpenObject (
  690. IN OUT PDATAOBJECT SrcObPtr
  691. )
  692. {
  693. DWORD rc = ERROR_SUCCESS;
  694. HKEY Parent;
  695. #if CLASS_FIELD_ENABLED
  696. TCHAR ClassBuf[MAX_CLASS_SIZE];
  697. DWORD ClassBufSize = MAX_CLASS_SIZE;
  698. #endif
  699. if (SrcObPtr->ObjectType & OT_OPEN) {
  700. return TRUE;
  701. }
  702. if (SrcObPtr->KeyPtr) {
  703. if (SrcObPtr->KeyPtr->OpenKey) {
  704. SrcObPtr->ObjectType |= OT_OPEN;
  705. SrcObPtr->KeyPtr->OpenCount++;
  706. return TRUE;
  707. }
  708. if (IsWin95Object (SrcObPtr)) {
  709. if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) {
  710. rc = TrackedRegOpenKeyEx95 (
  711. SrcObPtr->ParentKeyPtr->OpenKey,
  712. SrcObPtr->ChildKey,
  713. 0,
  714. KEY_READ,
  715. &SrcObPtr->KeyPtr->OpenKey
  716. );
  717. } else {
  718. Parent = pGetWin95Key (GetRootKeyFromOffset (SrcObPtr->RootItem));
  719. if (*SrcObPtr->KeyPtr->KeyString || NON_ROOT_KEY (Parent)) {
  720. rc = TrackedRegOpenKeyEx95 (
  721. Parent,
  722. SrcObPtr->KeyPtr->KeyString,
  723. 0,
  724. KEY_READ,
  725. &SrcObPtr->KeyPtr->OpenKey
  726. );
  727. } else {
  728. SrcObPtr->KeyPtr->OpenKey = Parent;
  729. }
  730. }
  731. }
  732. else {
  733. if (SrcObPtr->ParentKeyPtr && SrcObPtr->ParentKeyPtr->OpenKey && SrcObPtr->ChildKey) {
  734. rc = TrackedRegOpenKeyEx (
  735. SrcObPtr->ParentKeyPtr->OpenKey,
  736. SrcObPtr->ChildKey,
  737. 0,
  738. KEY_ALL_ACCESS,
  739. &SrcObPtr->KeyPtr->OpenKey
  740. );
  741. } else {
  742. Parent = pGetWinNTKey (GetRootKeyFromOffset (SrcObPtr->RootItem));
  743. if (*SrcObPtr->KeyPtr->KeyString || NON_ROOT_KEY (Parent)) {
  744. rc = TrackedRegOpenKeyEx (
  745. Parent,
  746. SrcObPtr->KeyPtr->KeyString,
  747. 0,
  748. KEY_ALL_ACCESS,
  749. &SrcObPtr->KeyPtr->OpenKey
  750. );
  751. } else {
  752. SrcObPtr->KeyPtr->OpenKey = Parent;
  753. }
  754. }
  755. }
  756. if (rc != ERROR_SUCCESS) {
  757. SetLastError (rc);
  758. return FALSE;
  759. }
  760. SrcObPtr->ObjectType |= OT_OPEN;
  761. SrcObPtr->KeyPtr->OpenCount = 1;
  762. #if CLASS_FIELD_ENABLED
  763. // Get the key's class
  764. if (IsWin95Object (SrcObPtr)) {
  765. rc = Win95RegQueryInfoKey (pGetWin95Key (SrcObPtr->RootKey),
  766. ClassBuf,
  767. &ClassBufSize,
  768. NULL, // reserved
  769. NULL, // sub key count
  770. NULL, // max sub key len
  771. NULL, // max class len
  772. NULL, // values
  773. NULL, // max value name len
  774. NULL, // max value len
  775. NULL, // security desc
  776. NULL // last write time
  777. );
  778. } else {
  779. rc = WinNTRegQueryInfoKey (pGetWin95Key (SrcObPtr->RootKey),
  780. ClassBuf,
  781. &ClassBufSize,
  782. NULL, // reserved
  783. NULL, // sub key count
  784. NULL, // max sub key len
  785. NULL, // max class len
  786. NULL, // values
  787. NULL, // max value name len
  788. NULL, // max value len
  789. NULL, // security desc
  790. NULL // last write time
  791. );
  792. }
  793. if (rc == ERROR_SUCCESS) {
  794. DEBUGMSG ((DBG_VERBOSE, "Class size is %u for %s\\%s", ClassBufSize,
  795. GetRootStringFromOffset (SrcObPtr->RootItem), SrcObPtr->KeyPtr->KeyString));
  796. SetRegistryClass (SrcObPtr, ClassBuf, ClassBufSize);
  797. }
  798. #endif
  799. }
  800. return TRUE;
  801. }
  802. VOID
  803. pFixRegSzTermination (
  804. IN OUT PDATAOBJECT SrcObPtr
  805. )
  806. {
  807. BOOL addNul = FALSE;
  808. PTSTR end;
  809. PBYTE oldBuf;
  810. UINT oldSize;
  811. if (SrcObPtr->Type == REG_SZ || SrcObPtr->Type == REG_EXPAND_SZ) {
  812. if (SrcObPtr->Value.Size & 1) {
  813. //
  814. // Force type to REG_NONE because we assume all REG_SZ
  815. // and REG_EXPAND_SZ values are truncated.
  816. //
  817. SrcObPtr->Type = REG_NONE;
  818. DEBUGMSG ((
  819. DBG_WARNING,
  820. "Truncation occurred because of odd string size for %s",
  821. DebugEncoder (SrcObPtr)
  822. ));
  823. } else {
  824. //
  825. // Check if we need to append a nul.
  826. //
  827. addNul = FALSE;
  828. oldBuf = SrcObPtr->Value.Buffer;
  829. oldSize = SrcObPtr->Value.Size;
  830. if (oldSize < sizeof (TCHAR)) {
  831. addNul = TRUE;
  832. } else {
  833. end = (PTSTR) (oldBuf + oldSize - sizeof (TCHAR));
  834. addNul = (*end != 0);
  835. }
  836. if (addNul) {
  837. if (AllocObjectVal (SrcObPtr, NULL, oldSize, oldSize + sizeof (TCHAR))) {
  838. CopyMemory (SrcObPtr->Value.Buffer, oldBuf, oldSize);
  839. end = (PTSTR) (SrcObPtr->Value.Buffer + oldSize);
  840. *end = 0;
  841. PoolMemReleaseMemory (g_TempPool, oldBuf);
  842. } else {
  843. SrcObPtr->Type = REG_NONE;
  844. }
  845. }
  846. }
  847. }
  848. }
  849. BOOL
  850. ReadObject (
  851. IN OUT PDATAOBJECT SrcObPtr
  852. )
  853. {
  854. return ReadObjectEx (SrcObPtr, FALSE);
  855. }
  856. BOOL
  857. ReadObjectEx (
  858. IN OUT PDATAOBJECT SrcObPtr,
  859. IN BOOL QueryOnly
  860. )
  861. {
  862. DWORD rc;
  863. DWORD ReqSize;
  864. // Skip if value has already been read
  865. if (SrcObPtr->ObjectType & OT_VALUE) {
  866. return TRUE;
  867. }
  868. // If registry key and valuename, query Win95 registry
  869. if (IsObjectRegistryKeyAndVal (SrcObPtr)) {
  870. // Open key if necessary
  871. if (!OpenObject (SrcObPtr)) {
  872. DEBUGMSG ((DBG_VERBOSE, "ReadObject failed because OpenObject failed"));
  873. return FALSE;
  874. }
  875. // Get the value size
  876. if (IsWin95Object (SrcObPtr)) {
  877. ReqSize = 0; // Temporary fix for win95reg
  878. rc = Win95RegQueryValueEx (SrcObPtr->KeyPtr->OpenKey,
  879. SrcObPtr->ValueName,
  880. NULL, &SrcObPtr->Type, NULL, &ReqSize);
  881. } else {
  882. rc = WinNTRegQueryValueEx (
  883. SrcObPtr->KeyPtr->OpenKey,
  884. SrcObPtr->ValueName,
  885. NULL,
  886. &SrcObPtr->Type,
  887. NULL,
  888. &ReqSize
  889. );
  890. if (rc == ERROR_ACCESS_DENIED) {
  891. LOG ((
  892. LOG_INFORMATION,
  893. "Access denied for query of %s in %s",
  894. SrcObPtr->ValueName,
  895. SrcObPtr->KeyPtr->KeyString
  896. ));
  897. ReqSize = 1;
  898. SrcObPtr->Type = REG_NONE;
  899. }
  900. }
  901. if (rc != ERROR_SUCCESS) {
  902. DEBUGMSG_IF ((rc != ERROR_FILE_NOT_FOUND, DBG_WARNING,
  903. "ReadObject failed for %s (type: %x)",
  904. DebugEncoder (SrcObPtr), SrcObPtr->ObjectType));
  905. DEBUGMSG_IF ((
  906. !QueryOnly && rc == ERROR_FILE_NOT_FOUND,
  907. DBG_WARNING,
  908. "Object %s not found",
  909. DebugEncoder (SrcObPtr)
  910. ));
  911. SetLastError (rc);
  912. return FALSE;
  913. }
  914. // Query only is used to see if the object exists
  915. if (QueryOnly) {
  916. return TRUE;
  917. }
  918. // Allocate a buffer for the value
  919. if (!AllocObjectVal (SrcObPtr, NULL, ReqSize, ReqSize)) {
  920. return FALSE;
  921. }
  922. // Get the the value
  923. if (IsWin95Object (SrcObPtr)) {
  924. rc = Win95RegQueryValueEx (SrcObPtr->KeyPtr->OpenKey,
  925. SrcObPtr->ValueName,
  926. NULL, &SrcObPtr->Type,
  927. SrcObPtr->Value.Buffer,
  928. &ReqSize);
  929. } else {
  930. rc = WinNTRegQueryValueEx (
  931. SrcObPtr->KeyPtr->OpenKey,
  932. SrcObPtr->ValueName,
  933. NULL,
  934. &SrcObPtr->Type,
  935. SrcObPtr->Value.Buffer,
  936. &ReqSize
  937. );
  938. if (rc == ERROR_ACCESS_DENIED) {
  939. SrcObPtr->Type = REG_NONE;
  940. SrcObPtr->Value.Size = 0;
  941. rc = ERROR_SUCCESS;
  942. }
  943. }
  944. if (rc != ERROR_SUCCESS) {
  945. FreeObjectVal (SrcObPtr);
  946. SetLastError (rc);
  947. LOG ((LOG_ERROR, "Failed to read from the registry"));
  948. return FALSE;
  949. }
  950. // The SrcObPtr->Type field is accurate
  951. SrcObPtr->ObjectType |= OT_REGISTRY_TYPE;
  952. // Fix REG_SZ or REG_EXPAND_SZ
  953. pFixRegSzTermination (SrcObPtr);
  954. //
  955. // If necessary, convert the data
  956. //
  957. return FilterObject (SrcObPtr);
  958. }
  959. DEBUGMSG ((DBG_WHOOPS, "Read Object: Object type (%Xh) is not supported", SrcObPtr->ObjectType));
  960. return FALSE;
  961. }
  962. BOOL
  963. WriteObject (
  964. IN CPDATAOBJECT DestObPtr
  965. )
  966. {
  967. DWORD rc;
  968. // If registry key, make sure it exists
  969. if ((DestObPtr->KeyPtr) &&
  970. !IsWin95Object (DestObPtr)
  971. ) {
  972. // Create or open key if necessary
  973. if (!CreateObject (DestObPtr)) {
  974. DEBUGMSG ((DBG_WARNING, "WriteObject: CreateObject failed for %s", DestObPtr->KeyPtr->KeyString));
  975. return FALSE;
  976. }
  977. // If no value name and no value, skip
  978. if (!(DestObPtr->ObjectType & OT_VALUE) && !(DestObPtr->ValueName)) {
  979. return TRUE;
  980. }
  981. // If no type, specify it as REG_NONE
  982. if (!IsRegistryTypeSpecified (DestObPtr)) {
  983. SetRegistryType (DestObPtr, REG_NONE);
  984. }
  985. // Write the value
  986. if (*DestObPtr->ValueName || NON_ROOT_KEY (DestObPtr->KeyPtr->OpenKey)) {
  987. rc = WinNTRegSetValueEx (
  988. DestObPtr->KeyPtr->OpenKey,
  989. DestObPtr->ValueName,
  990. 0,
  991. DestObPtr->Type,
  992. DestObPtr->Value.Buffer,
  993. DestObPtr->Value.Size
  994. );
  995. if (rc == ERROR_ACCESS_DENIED) {
  996. //
  997. // If access is denied, log & assume success
  998. //
  999. LOG ((
  1000. LOG_INFORMATION,
  1001. "Access denied; can't write registry value (%s [%s])",
  1002. DestObPtr->KeyPtr->KeyString,
  1003. DestObPtr->ValueName
  1004. ));
  1005. rc = ERROR_SUCCESS;
  1006. }
  1007. } else {
  1008. rc = ERROR_SUCCESS;
  1009. }
  1010. if (rc != ERROR_SUCCESS) {
  1011. SetLastError (rc);
  1012. LOG ((LOG_ERROR, "Failed to set a registry value (%s [%s])", DestObPtr->KeyPtr->KeyString, DestObPtr->ValueName));
  1013. return FALSE;
  1014. }
  1015. return TRUE;
  1016. }
  1017. DEBUGMSG ((DBG_WHOOPS, "Write Object: Object type (%Xh) is not supported", DestObPtr->ObjectType));
  1018. return FALSE;
  1019. }
  1020. FILTERRETURN
  1021. CopySingleObject (
  1022. IN OUT PDATAOBJECT SrcObPtr,
  1023. IN OUT PDATAOBJECT DestObPtr,
  1024. IN FILTERFUNCTION FilterFn, OPTIONAL
  1025. IN PVOID FilterArg OPTIONAL
  1026. )
  1027. {
  1028. FILTERRETURN fr = FILTER_RETURN_FAIL;
  1029. DATAOBJECT TempOb;
  1030. if (!ReadObject (SrcObPtr)) {
  1031. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  1032. fr = FILTER_RETURN_CONTINUE;
  1033. }
  1034. else {
  1035. DEBUGMSG ((DBG_ERROR, "CopySingleObject: Cannot read object %s", DebugEncoder (SrcObPtr)));
  1036. }
  1037. return fr;
  1038. }
  1039. if (FilterFn) {
  1040. fr = FilterFn (SrcObPtr, DestObPtr, FILTER_VALUE_COPY, FilterArg);
  1041. if (fr != FILTER_RETURN_CONTINUE) {
  1042. // handled means skip copy but don't stop enum
  1043. if (fr == FILTER_RETURN_HANDLED) {
  1044. fr = FILTER_RETURN_CONTINUE;
  1045. }
  1046. // Debug version tells us when a filter failed
  1047. DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopySingleObject failed because filter function FILTER_VALUE_COPY failed"));
  1048. return fr;
  1049. }
  1050. }
  1051. //
  1052. // Temporarily transfer SrcOb's value, value type and to DestOb
  1053. //
  1054. CopyMemory (&TempOb, DestObPtr, sizeof (DATAOBJECT));
  1055. DestObPtr->ObjectType |= SrcObPtr->ObjectType & (OT_VALUE|OT_REGISTRY_TYPE|OT_REGISTRY_CLASS);
  1056. DestObPtr->Value.Buffer = SrcObPtr->Value.Buffer;
  1057. DestObPtr->Value.Size = SrcObPtr->Value.Size;
  1058. DestObPtr->Class.Buffer = SrcObPtr->Class.Buffer;
  1059. DestObPtr->Class.Size = SrcObPtr->Class.Size;
  1060. DestObPtr->Type = SrcObPtr->Type;
  1061. //
  1062. // Write the dest ob
  1063. //
  1064. if (WriteObject (DestObPtr)) {
  1065. fr = FILTER_RETURN_CONTINUE;
  1066. } else {
  1067. DEBUGMSG ((DBG_ERROR, "CopySingleObject: Cannot write object %s", DebugEncoder (DestObPtr)));
  1068. }
  1069. //
  1070. // Restore the dest ob
  1071. //
  1072. CopyMemory (DestObPtr, &TempOb, sizeof (DATAOBJECT));
  1073. return fr;
  1074. }
  1075. FILTERRETURN
  1076. NextSubObjectEnum (
  1077. IN PDATAOBJECT RootSrcObPtr,
  1078. IN PDATAOBJECT RootDestObPtr, OPTIONAL
  1079. OUT PDATAOBJECT SubSrcObPtr,
  1080. OUT PDATAOBJECT SubDestObPtr,
  1081. IN FILTERFUNCTION FilterFn, OPTIONAL
  1082. IN PVOID FilterArg OPTIONAL
  1083. )
  1084. {
  1085. DWORD rc;
  1086. FILTERRETURN fr = FILTER_RETURN_FAIL;
  1087. PTSTR NewKey;
  1088. TCHAR KeyNameBuf[MAX_REGISTRY_KEY];
  1089. DWORD KeyNameBufSize;
  1090. TCHAR ClassBuf[MAX_CLASS_SIZE];
  1091. DWORD ClassBufSize;
  1092. FILETIME DontCare;
  1093. BOOL CreatedSubOb = FALSE;
  1094. if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
  1095. do {
  1096. MYASSERT (RootSrcObPtr->KeyPtr->OpenKey);
  1097. KeyNameBufSize = MAX_REGISTRY_KEY;
  1098. ClassBufSize = MAX_CLASS_SIZE;
  1099. fr = FILTER_RETURN_FAIL;
  1100. //
  1101. // Enumerate the next sub object
  1102. //
  1103. if (IsWin95Object (RootSrcObPtr)) {
  1104. rc = Win95RegEnumKey (
  1105. RootSrcObPtr->KeyPtr->OpenKey,
  1106. RootSrcObPtr->KeyEnum,
  1107. KeyNameBuf,
  1108. KeyNameBufSize
  1109. );
  1110. ClassBufSize = 0;
  1111. } else {
  1112. rc = WinNTRegEnumKeyEx (
  1113. RootSrcObPtr->KeyPtr->OpenKey,
  1114. RootSrcObPtr->KeyEnum,
  1115. KeyNameBuf,
  1116. &KeyNameBufSize,
  1117. NULL, // reserved
  1118. ClassBuf,
  1119. &ClassBufSize,
  1120. &DontCare // last write time
  1121. );
  1122. if (rc == ERROR_ACCESS_DENIED) {
  1123. LOG ((
  1124. LOG_INFORMATION,
  1125. "Access denied for enumeration of %s",
  1126. RootSrcObPtr->KeyPtr->KeyString
  1127. ));
  1128. rc = ERROR_NO_MORE_ITEMS;
  1129. }
  1130. }
  1131. if (rc != ERROR_SUCCESS) {
  1132. SetLastError (rc);
  1133. if (rc == ERROR_NO_MORE_ITEMS) {
  1134. fr = FILTER_RETURN_DONE;
  1135. }
  1136. return fr;
  1137. }
  1138. //
  1139. // Create sub source object
  1140. //
  1141. CreatedSubOb = TRUE;
  1142. ZeroMemory (SubSrcObPtr, sizeof (DATAOBJECT));
  1143. SubSrcObPtr->ObjectType = RootSrcObPtr->ObjectType & (OT_WIN95|OT_TREE);
  1144. SubSrcObPtr->RootItem = RootSrcObPtr->RootItem;
  1145. SubSrcObPtr->ParentKeyPtr = RootSrcObPtr->KeyPtr;
  1146. pIncKeyPropUse (SubSrcObPtr->ParentKeyPtr);
  1147. MYASSERT (KeyNameBuf && *KeyNameBuf);
  1148. NewKey = JoinPaths (RootSrcObPtr->KeyPtr->KeyString, KeyNameBuf);
  1149. SetRegistryKey (SubSrcObPtr, NewKey);
  1150. FreePathString (NewKey);
  1151. SubSrcObPtr->ChildKey = _tcsrchr (SubSrcObPtr->KeyPtr->KeyString, TEXT('\\'));
  1152. if (SubSrcObPtr->ChildKey) {
  1153. SubSrcObPtr->ChildKey = _tcsinc (SubSrcObPtr->ChildKey);
  1154. } else {
  1155. SubSrcObPtr->ChildKey = SubSrcObPtr->KeyPtr->KeyString;
  1156. }
  1157. #if CLASS_FIELD_ENABLED
  1158. SetRegistryClass (SubSrcObPtr, ClassBuf, ClassBufSize);
  1159. #endif
  1160. //
  1161. // Create sub dest object
  1162. //
  1163. ZeroMemory (SubDestObPtr, sizeof (DATAOBJECT));
  1164. if (RootDestObPtr) {
  1165. SubDestObPtr->ObjectType = RootDestObPtr->ObjectType & OT_TREE;
  1166. SubDestObPtr->RootItem = RootDestObPtr->RootItem;
  1167. SubDestObPtr->ParentKeyPtr = RootDestObPtr->KeyPtr;
  1168. pIncKeyPropUse (SubDestObPtr->ParentKeyPtr);
  1169. // let's convert KeyNameBuf if it's a path and the path changed
  1170. ConvertWin9xCmdLine (KeyNameBuf, DEBUGENCODER(SubDestObPtr), NULL);
  1171. NewKey = JoinPaths (RootDestObPtr->KeyPtr->KeyString, KeyNameBuf);
  1172. SetRegistryKey (SubDestObPtr, NewKey);
  1173. FreePathString (NewKey);
  1174. SubDestObPtr->ChildKey = _tcsrchr (SubDestObPtr->KeyPtr->KeyString, TEXT('\\'));
  1175. if (SubDestObPtr->ChildKey) {
  1176. SubDestObPtr->ChildKey = _tcsinc (SubDestObPtr->ChildKey);
  1177. } else {
  1178. SubDestObPtr->ChildKey = SubDestObPtr->KeyPtr->KeyString;
  1179. }
  1180. #if CLASS_FIELD_ENABLED
  1181. SetRegistryClass (SubDestObPtr, ClassBuf, ClassBufSize);
  1182. #endif
  1183. }
  1184. if (FilterFn) {
  1185. fr = FilterFn (
  1186. SubSrcObPtr,
  1187. RootDestObPtr ? SubDestObPtr : NULL,
  1188. FILTER_KEY_ENUM,
  1189. FilterArg
  1190. );
  1191. if (fr == FILTER_RETURN_DELETED) {
  1192. CreatedSubOb = FALSE;
  1193. FreeObjectStruct (SubSrcObPtr);
  1194. FreeObjectStruct (SubDestObPtr);
  1195. }
  1196. // Debug version tells us when a filter fails
  1197. DEBUGMSG_IF ((
  1198. fr == FILTER_RETURN_FAIL,
  1199. DBG_VERBOSE,
  1200. "NextSubObjectEnum failed because filter function FILTER_KEY_ENUM failed"
  1201. ));
  1202. } else {
  1203. fr = FILTER_RETURN_CONTINUE;
  1204. }
  1205. } while (fr == FILTER_RETURN_DELETED);
  1206. RootSrcObPtr->KeyEnum += 1;
  1207. }
  1208. if (fr != FILTER_RETURN_CONTINUE && fr != FILTER_RETURN_HANDLED) {
  1209. if (CreatedSubOb) {
  1210. FreeObjectStruct (SubSrcObPtr);
  1211. FreeObjectStruct (SubDestObPtr);
  1212. }
  1213. }
  1214. return fr;
  1215. }
  1216. BOOL
  1217. BeginSubObjectEnum (
  1218. IN PDATAOBJECT RootSrcObPtr,
  1219. IN PDATAOBJECT RootDestObPtr, OPTIONAL
  1220. OUT PDATAOBJECT SubSrcObPtr,
  1221. OUT PDATAOBJECT SubDestObPtr,
  1222. IN FILTERFUNCTION FilterFn, OPTIONAL
  1223. IN PVOID FilterArg OPTIONAL
  1224. )
  1225. {
  1226. if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
  1227. // Open key if necessary
  1228. if (!OpenObject (RootSrcObPtr)) {
  1229. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  1230. return FILTER_RETURN_DONE;
  1231. }
  1232. DEBUGMSG ((DBG_WARNING, "BeginSubObjectEnum: Can't open %s", DebugEncoder (RootSrcObPtr)));
  1233. return FILTER_RETURN_FAIL;
  1234. }
  1235. RootSrcObPtr->KeyEnum = 0;
  1236. return NextSubObjectEnum (RootSrcObPtr, RootDestObPtr, SubSrcObPtr, SubDestObPtr, FilterFn, FilterArg);
  1237. }
  1238. // Other object types do not have sub objects
  1239. DEBUGMSG ((DBG_WARNING, "BeginSubObjectEnum: Trying to enumerate unknown object"));
  1240. return FILTER_RETURN_FAIL;
  1241. }
  1242. FILTERRETURN
  1243. NextValueNameEnum (
  1244. IN PDATAOBJECT RootSrcObPtr,
  1245. IN PDATAOBJECT RootDestObPtr, OPTIONAL
  1246. OUT PDATAOBJECT ValSrcObPtr,
  1247. OUT PDATAOBJECT ValDestObPtr,
  1248. IN FILTERFUNCTION FilterFn, OPTIONAL
  1249. IN PVOID FilterArg OPTIONAL
  1250. )
  1251. {
  1252. DWORD rc;
  1253. FILTERRETURN fr = FILTER_RETURN_FAIL;
  1254. TCHAR ValNameBuf[MAX_REGISTRY_VALUE_NAME];
  1255. DWORD ValNameBufSize = MAX_REGISTRY_VALUE_NAME;
  1256. BOOL CreatedValOb = FALSE;
  1257. if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
  1258. MYASSERT (IsRegistryKeyOpen (RootSrcObPtr));
  1259. if (IsWin95Object (RootSrcObPtr)) {
  1260. rc = Win95RegEnumValue (
  1261. RootSrcObPtr->KeyPtr->OpenKey,
  1262. RootSrcObPtr->ValNameEnum,
  1263. ValNameBuf,
  1264. &ValNameBufSize,
  1265. NULL, // reserved
  1266. NULL, // type ptr
  1267. NULL, // value data ptr
  1268. NULL // value data size ptr
  1269. );
  1270. } else {
  1271. rc = WinNTRegEnumValue (
  1272. RootSrcObPtr->KeyPtr->OpenKey,
  1273. RootSrcObPtr->ValNameEnum,
  1274. ValNameBuf,
  1275. &ValNameBufSize,
  1276. NULL, // reserved
  1277. NULL, // type ptr
  1278. NULL, // value data ptr
  1279. NULL // value data size ptr
  1280. );
  1281. if (rc == ERROR_ACCESS_DENIED) {
  1282. LOG ((
  1283. LOG_INFORMATION,
  1284. "Access denied for enumeration of values in %s",
  1285. RootSrcObPtr->KeyPtr->KeyString
  1286. ));
  1287. rc = ERROR_NO_MORE_ITEMS;
  1288. }
  1289. }
  1290. if (rc != ERROR_SUCCESS) {
  1291. SetLastError (rc);
  1292. if (rc == ERROR_NO_MORE_ITEMS) {
  1293. fr = FILTER_RETURN_DONE;
  1294. } else {
  1295. LOG ((LOG_ERROR, "Failed to enumerate a registry value"));
  1296. }
  1297. return fr;
  1298. }
  1299. //
  1300. // Create src value object
  1301. //
  1302. CreatedValOb = TRUE;
  1303. ZeroMemory (ValSrcObPtr, sizeof (DATAOBJECT));
  1304. ValSrcObPtr->ObjectType = RootSrcObPtr->ObjectType & OT_WIN95; // (OT_WIN95|OT_TREE) removed
  1305. ValSrcObPtr->RootItem = RootSrcObPtr->RootItem;
  1306. ValSrcObPtr->ParentKeyPtr = RootSrcObPtr->KeyPtr;
  1307. pIncKeyPropUse (ValSrcObPtr->ParentKeyPtr);
  1308. ValSrcObPtr->KeyPtr = RootSrcObPtr->KeyPtr;
  1309. pIncKeyPropUse (ValSrcObPtr->KeyPtr);
  1310. if (rc == ERROR_SUCCESS) {
  1311. SetRegistryValueName (ValSrcObPtr, ValNameBuf);
  1312. } else {
  1313. SetRegistryValueName (ValSrcObPtr, TEXT(""));
  1314. }
  1315. //
  1316. // Create dest value object
  1317. //
  1318. CreatedValOb = TRUE;
  1319. ZeroMemory (ValDestObPtr, sizeof (DATAOBJECT));
  1320. if (RootDestObPtr) {
  1321. ValDestObPtr->RootItem = RootDestObPtr->RootItem;
  1322. ValDestObPtr->ParentKeyPtr = RootDestObPtr->KeyPtr;
  1323. pIncKeyPropUse (ValDestObPtr->ParentKeyPtr);
  1324. ValDestObPtr->KeyPtr = RootDestObPtr->KeyPtr;
  1325. pIncKeyPropUse (ValDestObPtr->KeyPtr);
  1326. // let's convert ValNameBuf if it's a path and the path changed
  1327. ConvertWin9xCmdLine (ValNameBuf, DEBUGENCODER(ValDestObPtr), NULL);
  1328. if (rc == ERROR_SUCCESS) {
  1329. SetRegistryValueName (ValDestObPtr, ValNameBuf);
  1330. } else {
  1331. SetRegistryValueName (ValDestObPtr, TEXT(""));
  1332. }
  1333. }
  1334. if (FilterFn) {
  1335. fr = FilterFn (
  1336. ValSrcObPtr,
  1337. RootDestObPtr ? ValDestObPtr : NULL,
  1338. FILTER_VALUENAME_ENUM,
  1339. FilterArg
  1340. );
  1341. // Debug version tells us when a filter fails
  1342. DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "NextValueNameEnum failed because filter function FILTER_VALUENAME_ENUM failed"));
  1343. } else {
  1344. fr = FILTER_RETURN_CONTINUE;
  1345. }
  1346. RootSrcObPtr->ValNameEnum += 1;
  1347. }
  1348. if (fr != FILTER_RETURN_CONTINUE && fr != FILTER_RETURN_HANDLED) {
  1349. if (CreatedValOb) {
  1350. FreeObjectStruct (ValSrcObPtr);
  1351. FreeObjectStruct (ValDestObPtr);
  1352. }
  1353. }
  1354. return fr;
  1355. }
  1356. FILTERRETURN
  1357. BeginValueNameEnum (
  1358. IN PDATAOBJECT RootSrcObPtr,
  1359. IN PDATAOBJECT RootDestObPtr, OPTIONAL
  1360. OUT PDATAOBJECT ValSrcObPtr,
  1361. OUT PDATAOBJECT ValDestObPtr,
  1362. IN FILTERFUNCTION FilterFn, OPTIONAL
  1363. IN PVOID FilterArg OPTIONAL
  1364. )
  1365. {
  1366. if (IsObjectRegistryKeyOnly (RootSrcObPtr)) {
  1367. // Open key if necessary
  1368. if (!OpenObject (RootSrcObPtr)) {
  1369. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  1370. return FILTER_RETURN_DONE;
  1371. }
  1372. DEBUGMSG ((DBG_WARNING, "BeginValueNameEnum: Can't open %s", DebugEncoder (RootSrcObPtr)));
  1373. return FILTER_RETURN_FAIL;
  1374. }
  1375. RootSrcObPtr->ValNameEnum = 0;
  1376. return NextValueNameEnum (RootSrcObPtr, RootDestObPtr, ValSrcObPtr, ValDestObPtr, FilterFn, FilterArg);
  1377. }
  1378. // Other object types do not have sub objects
  1379. DEBUGMSG ((DBG_WARNING, "BeginValueNameEnum: Trying to enumerate unknown object"));
  1380. return FILTER_RETURN_FAIL;
  1381. }
  1382. FILTERRETURN
  1383. CopyObject (
  1384. IN PDATAOBJECT SrcObPtr,
  1385. IN CPDATAOBJECT DestObPtr, OPTIONAL
  1386. IN FILTERFUNCTION FilterFn, OPTIONAL
  1387. IN PVOID FilterArg OPTIONAL
  1388. )
  1389. {
  1390. DATAOBJECT ChildOb, ChildDestOb;
  1391. FILTERRETURN fr = FILTER_RETURN_FAIL;
  1392. BOOL suppressKey = FALSE;
  1393. //
  1394. // Progress bar update
  1395. //
  1396. g_ProgressBarCounter++;
  1397. if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) {
  1398. g_ProgressBarCounter = 0;
  1399. TickProgressBar ();
  1400. }
  1401. //
  1402. // Tree copy
  1403. //
  1404. if (SrcObPtr->ObjectType & OT_TREE) {
  1405. if (DestObPtr) {
  1406. #ifdef DEBUG
  1407. //
  1408. // Verify destination does not specify value but does specify key
  1409. //
  1410. if (!IsObjectRegistryKeyOnly (DestObPtr)) {
  1411. DEBUGMSG ((
  1412. DBG_WHOOPS,
  1413. "CopyObject: Destination invalid for copy %s tree",
  1414. DebugEncoder (SrcObPtr)
  1415. ));
  1416. return FILTER_RETURN_FAIL;
  1417. }
  1418. #endif
  1419. // The source object cannot specify a registry value either
  1420. MYASSERT (!(SrcObPtr->ValueName));
  1421. #ifndef VAR_PROGRESS_BAR
  1422. //
  1423. // Progress bar update
  1424. //
  1425. g_ProgressBarCounter++;
  1426. if (g_ProgressBarCounter >= REGMERGE_TICK_THRESHOLD) {
  1427. g_ProgressBarCounter = 0;
  1428. TickProgressBarDelta (1);
  1429. }
  1430. #endif
  1431. //
  1432. // Ask the filter if it wants to create the key unconditionally
  1433. //
  1434. if (FilterFn) {
  1435. //
  1436. // suppressKey should never be set if filterFn exists.
  1437. //
  1438. MYASSERT (!suppressKey)
  1439. fr = FilterFn (SrcObPtr, DestObPtr, FILTER_CREATE_KEY, FilterArg);
  1440. if (fr == FILTER_RETURN_FAIL || fr == FILTER_RETURN_DONE) {
  1441. // The done at the key create does not really mean end the whole copy!
  1442. if (fr == FILTER_RETURN_DONE) {
  1443. fr = FILTER_RETURN_CONTINUE;
  1444. }
  1445. return fr;
  1446. }
  1447. } else {
  1448. //
  1449. // Check to see if the win9x object actually exists. If not,
  1450. // we'll pass on FILTER_RETURN_DONE. We don't want to get
  1451. // empty keys created on nt where no keys existed on win9x.
  1452. //
  1453. if (!OpenObject (SrcObPtr)) {
  1454. suppressKey = TRUE;
  1455. fr = FILTER_RETURN_HANDLED;
  1456. }
  1457. else {
  1458. fr = FILTER_RETURN_CONTINUE;
  1459. }
  1460. }
  1461. if (fr == FILTER_RETURN_CONTINUE) {
  1462. if (!CreateObject (DestObPtr)) {
  1463. if (GetLastError() == ERROR_SUCCESS) {
  1464. //
  1465. // CreateObject failed but because the last error was
  1466. // ERROR_SUCCESS, we skip this registry node and continue
  1467. // processing as if the error didn't occur.
  1468. //
  1469. return FILTER_RETURN_CONTINUE;
  1470. }
  1471. else {
  1472. DEBUGMSG ((DBG_WARNING,
  1473. "CopyObject: CreateObject failed to create %s",
  1474. DebugEncoder (DestObPtr)
  1475. ));
  1476. return FILTER_RETURN_FAIL;
  1477. }
  1478. }
  1479. }
  1480. }
  1481. //
  1482. // Copy all values (call CopyObject recursively)
  1483. //
  1484. SrcObPtr->ObjectType &= ~(OT_TREE);
  1485. if (FilterFn) {
  1486. //
  1487. // suppress key should never be set if there is a FilterFn.
  1488. //
  1489. MYASSERT (!suppressKey)
  1490. fr = FilterFn (SrcObPtr, DestObPtr, FILTER_PROCESS_VALUES, FilterArg);
  1491. // Debug version tells us that the filter failed
  1492. DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE, "CopyObject failed because filter function FILTER_PROCESS_VALUES failed"));
  1493. if (fr == FILTER_RETURN_FAIL || fr == FILTER_RETURN_DONE) {
  1494. DEBUGMSG ((DBG_VERBOSE, "CopyObject is exiting"));
  1495. SrcObPtr->ObjectType |= OT_TREE;
  1496. return fr;
  1497. }
  1498. } else {
  1499. fr = suppressKey ? FILTER_RETURN_HANDLED : FILTER_RETURN_CONTINUE;
  1500. }
  1501. //
  1502. // Skip copy of key's values if FilterFn returned FILTER_RETURN_HANDLED
  1503. //
  1504. if (fr == FILTER_RETURN_CONTINUE) {
  1505. fr = CopyObject (SrcObPtr, DestObPtr, FilterFn, FilterArg);
  1506. SrcObPtr->ObjectType |= OT_TREE;
  1507. if (fr != FILTER_RETURN_CONTINUE) {
  1508. return fr;
  1509. }
  1510. } else {
  1511. SrcObPtr->ObjectType |= OT_TREE;
  1512. }
  1513. //
  1514. // Enumerate all child objects and process them recursively
  1515. //
  1516. fr = BeginSubObjectEnum (
  1517. SrcObPtr,
  1518. DestObPtr,
  1519. &ChildOb,
  1520. &ChildDestOb,
  1521. FilterFn,
  1522. FilterArg
  1523. );
  1524. while (fr == FILTER_RETURN_CONTINUE || fr == FILTER_RETURN_HANDLED) {
  1525. if (fr == FILTER_RETURN_CONTINUE) {
  1526. fr = CopyObject (
  1527. &ChildOb,
  1528. DestObPtr ? &ChildDestOb : NULL,
  1529. FilterFn,
  1530. FilterArg
  1531. );
  1532. } else {
  1533. fr = FILTER_RETURN_CONTINUE;
  1534. }
  1535. FreeObjectStruct (&ChildOb);
  1536. FreeObjectStruct (&ChildDestOb);
  1537. if (fr != FILTER_RETURN_CONTINUE) {
  1538. return fr;
  1539. }
  1540. fr = NextSubObjectEnum (
  1541. SrcObPtr,
  1542. DestObPtr,
  1543. &ChildOb,
  1544. &ChildDestOb,
  1545. FilterFn,
  1546. FilterArg
  1547. );
  1548. }
  1549. // The end of enum does not really mean end the copy!
  1550. if (fr == FILTER_RETURN_DONE) {
  1551. fr = FILTER_RETURN_CONTINUE;
  1552. }
  1553. DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE,
  1554. "CopyObject: Filter in subob enum failed"));
  1555. }
  1556. //
  1557. // Copy all values of a key
  1558. //
  1559. else if (IsObjectRegistryKeyOnly (SrcObPtr)) {
  1560. #ifdef DEBUG
  1561. if (DestObPtr) {
  1562. //
  1563. // Verify destination does not specify value but does specify key
  1564. //
  1565. if (!IsObjectRegistryKeyOnly (DestObPtr)) {
  1566. DEBUGMSG ((
  1567. DBG_WHOOPS,
  1568. "CopyObject: Destination (%s) invalid for copy values in %s",
  1569. DebugEncoder (DestObPtr),
  1570. DebugEncoder (SrcObPtr)
  1571. ));
  1572. return fr;
  1573. }
  1574. }
  1575. #endif
  1576. //
  1577. // Enumerate all values in the key
  1578. //
  1579. fr = BeginValueNameEnum (
  1580. SrcObPtr,
  1581. DestObPtr,
  1582. &ChildOb,
  1583. &ChildDestOb,
  1584. FilterFn,
  1585. FilterArg
  1586. );
  1587. if (fr == FILTER_RETURN_DONE) {
  1588. //
  1589. // No values in this key. Make sure DestObPtr is created.
  1590. //
  1591. if (DestObPtr && !suppressKey) {
  1592. if (!CreateObject (DestObPtr)) {
  1593. DEBUGMSG ((DBG_WARNING, "CopyObject: Could not create %s (type %x)",
  1594. DebugEncoder (DestObPtr), DestObPtr->ObjectType));
  1595. }
  1596. }
  1597. } else {
  1598. //
  1599. // For each value, call CopySingleObject
  1600. //
  1601. while (fr == FILTER_RETURN_CONTINUE || fr == FILTER_RETURN_HANDLED) {
  1602. if (fr == FILTER_RETURN_CONTINUE && DestObPtr) {
  1603. fr = CopySingleObject (&ChildOb, &ChildDestOb, FilterFn, FilterArg);
  1604. } else {
  1605. fr = FILTER_RETURN_CONTINUE;
  1606. }
  1607. FreeObjectStruct (&ChildOb);
  1608. FreeObjectStruct (&ChildDestOb);
  1609. if (fr != FILTER_RETURN_CONTINUE) {
  1610. DEBUGMSG ((DBG_VERBOSE, "CopyObject failed because CopySingleObject failed"));
  1611. return fr;
  1612. }
  1613. fr = NextValueNameEnum (
  1614. SrcObPtr,
  1615. DestObPtr,
  1616. &ChildOb,
  1617. &ChildDestOb,
  1618. FilterFn,
  1619. FilterArg
  1620. );
  1621. }
  1622. }
  1623. // The end of enum does not really mean end the copy!
  1624. if (fr == FILTER_RETURN_DONE) {
  1625. fr = FILTER_RETURN_CONTINUE;
  1626. }
  1627. DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE,
  1628. "CopyObject: Filter in val enum failed"));
  1629. }
  1630. //
  1631. // One value copy
  1632. //
  1633. else if (IsObjectRegistryKeyAndVal (SrcObPtr)) {
  1634. #ifdef DEBUG
  1635. if (DestObPtr) {
  1636. //
  1637. // BUGBUG -- what is this used for?
  1638. //
  1639. if (!(DestObPtr->ValueName)) {
  1640. if (!SetRegistryValueName (DestObPtr, SrcObPtr->ValueName)) {
  1641. DEBUGMSG ((DBG_VERBOSE, "CopyObject failed because SetRegistryValueName failed"));
  1642. return fr;
  1643. }
  1644. }
  1645. }
  1646. #endif
  1647. if (DestObPtr) {
  1648. fr = CopySingleObject (SrcObPtr, DestObPtr, FilterFn, FilterArg);
  1649. }
  1650. DEBUGMSG_IF ((fr == FILTER_RETURN_FAIL, DBG_VERBOSE,
  1651. "CopyObject: Filter in CopySingleObject failed"));
  1652. }
  1653. //
  1654. // Other object coping not supported
  1655. //
  1656. else {
  1657. DEBUGMSG ((
  1658. DBG_WHOOPS,
  1659. "CopyObject: Don't know how to copy object %s",
  1660. DebugEncoder (SrcObPtr)
  1661. ));
  1662. }
  1663. return fr;
  1664. }
  1665. VOID
  1666. FreeRegistryKey (
  1667. PDATAOBJECT p
  1668. )
  1669. {
  1670. if (p->KeyPtr && (p->ObjectType & OT_REGISTRY)) {
  1671. pFreeKeyProps (p->KeyPtr);
  1672. p->KeyPtr = NULL;
  1673. }
  1674. }
  1675. VOID
  1676. FreeRegistryParentKey (
  1677. PDATAOBJECT p
  1678. )
  1679. {
  1680. if (p->ParentKeyPtr && (p->ObjectType & OT_REGISTRY)) {
  1681. pFreeKeyProps (p->ParentKeyPtr);
  1682. p->ParentKeyPtr = NULL;
  1683. }
  1684. }
  1685. BOOL
  1686. SetRegistryKey (
  1687. PDATAOBJECT p,
  1688. PCTSTR Key
  1689. )
  1690. {
  1691. FreeRegistryKey (p);
  1692. p->KeyPtr = pCreateKeyPropsFromString (Key, IsWin95Object (p));
  1693. if (!p->KeyPtr) {
  1694. DEBUGMSG ((DBG_WARNING, "SetRegistryKey failed to create KEYPROPS struct"));
  1695. return FALSE;
  1696. }
  1697. p->ObjectType |= OT_REGISTRY;
  1698. return TRUE;
  1699. }
  1700. VOID
  1701. FreeRegistryValueName (
  1702. PDATAOBJECT p
  1703. )
  1704. {
  1705. if (p->ValueName && p->ObjectType & OT_REGISTRY) {
  1706. PoolMemReleaseMemory (g_TempPool, (PVOID) p->ValueName);
  1707. p->ValueName = NULL;
  1708. }
  1709. }
  1710. BOOL
  1711. SetRegistryValueName (
  1712. PDATAOBJECT p,
  1713. PCTSTR ValueName
  1714. )
  1715. {
  1716. FreeRegistryValueName (p);
  1717. p->ValueName = PoolMemDuplicateString (g_TempPool, ValueName);
  1718. if (!p->ValueName) {
  1719. DEBUGMSG ((DBG_WARNING, "SetRegistryValueName failed to duplicate string"));
  1720. return FALSE;
  1721. }
  1722. p->ObjectType |= OT_REGISTRY;
  1723. return TRUE;
  1724. }
  1725. BOOL
  1726. SetRegistryClass (
  1727. PDATAOBJECT p,
  1728. PBYTE Class,
  1729. DWORD ClassSize
  1730. )
  1731. {
  1732. FreeRegistryClass (p);
  1733. p->Class.Buffer = PoolMemGetAlignedMemory (g_TempPool, ClassSize);
  1734. if (p->Class.Buffer) {
  1735. p->ObjectType |= OT_REGISTRY_CLASS|OT_REGISTRY;
  1736. p->Class.Size = ClassSize;
  1737. if (ClassSize) {
  1738. CopyMemory (p->Class.Buffer, Class, ClassSize);
  1739. }
  1740. } else {
  1741. p->ObjectType &= ~OT_REGISTRY_CLASS;
  1742. DEBUGMSG ((DBG_WARNING, "SetRegistryClass failed to duplicate string"));
  1743. return FALSE;
  1744. }
  1745. return TRUE;
  1746. }
  1747. VOID
  1748. FreeRegistryClass (
  1749. PDATAOBJECT p
  1750. )
  1751. {
  1752. if (p->ObjectType & OT_REGISTRY_CLASS) {
  1753. PoolMemReleaseMemory (g_TempPool, (PVOID) p->Class.Buffer);
  1754. p->ObjectType &= ~OT_REGISTRY_CLASS;
  1755. }
  1756. }
  1757. VOID
  1758. SetRegistryType (
  1759. PDATAOBJECT p,
  1760. DWORD Type
  1761. )
  1762. {
  1763. p->Type = Type;
  1764. p->ObjectType |= OT_REGISTRY_TYPE|OT_REGISTRY;
  1765. }
  1766. BOOL
  1767. SetPlatformType (
  1768. PDATAOBJECT p,
  1769. BOOL Win95Type
  1770. )
  1771. {
  1772. if (Win95Type != IsWin95Object (p)) {
  1773. //
  1774. // We need to close the other platform valid handle. Otherwise
  1775. // all subsequent operations will fail because we will try to
  1776. // use an valid handle for a wrong platform.
  1777. //
  1778. CloseObject (p);
  1779. // key type is changing to be the opposite platform,
  1780. // so we have to create a duplicate key struct
  1781. // (except for the platform being different)
  1782. if (p->KeyPtr) {
  1783. p->KeyPtr = pCreateDuplicateKeyProps (p->KeyPtr, Win95Type);
  1784. if (!p->KeyPtr) {
  1785. return FALSE;
  1786. }
  1787. }
  1788. if (Win95Type) {
  1789. p->ObjectType |= OT_WIN95;
  1790. } else {
  1791. p->ObjectType &= ~OT_WIN95;
  1792. }
  1793. FreeRegistryParentKey (p);
  1794. }
  1795. return TRUE;
  1796. }
  1797. BOOL
  1798. ReadWin95ObjectString (
  1799. PCTSTR ObjectStr,
  1800. PDATAOBJECT ObPtr
  1801. )
  1802. {
  1803. LONG rc = ERROR_INVALID_NAME;
  1804. BOOL b = FALSE;
  1805. if (!CreateObjectStruct (ObjectStr, ObPtr, WIN95OBJECT)) {
  1806. rc = GetLastError();
  1807. DEBUGMSG ((DBG_ERROR, "Read Win95 Object String: %s is invalid", ObjectStr));
  1808. goto c0;
  1809. }
  1810. if (!ReadObject (ObPtr)) {
  1811. rc = GetLastError();
  1812. if (rc == ERROR_FILE_NOT_FOUND || rc == ERROR_BADKEY) {
  1813. rc = ERROR_SUCCESS;
  1814. DEBUGMSG ((DBG_WARNING, "ReadWin95ObjectString: %s does not exist", ObjectStr));
  1815. }
  1816. FreeObjectStruct (ObPtr);
  1817. } else {
  1818. b = TRUE;
  1819. }
  1820. c0:
  1821. if (!b) {
  1822. SetLastError (rc);
  1823. }
  1824. return b;
  1825. }
  1826. BOOL
  1827. WriteWinNTObjectString (
  1828. PCTSTR ObjectStr,
  1829. CPDATAOBJECT SrcObPtr
  1830. )
  1831. {
  1832. DATAOBJECT DestOb, TempOb;
  1833. BOOL b = FALSE;
  1834. //
  1835. // 1. Create TempOb from destination object string
  1836. // 2. Copy SrcObPtr to DestOb
  1837. // 3. Override DestOb with any setting in TempOb
  1838. //
  1839. if (!CreateObjectStruct (ObjectStr, &TempOb, WINNTOBJECT)) {
  1840. DEBUGMSG ((DBG_ERROR, "WriteWinNTObjectString: %s struct cannot be created", ObjectStr));
  1841. goto c0;
  1842. }
  1843. if (!DuplicateObjectStruct (&DestOb, SrcObPtr)) {
  1844. goto c1;
  1845. }
  1846. if (!CombineObjectStructs (&DestOb, &TempOb)) {
  1847. goto c2;
  1848. }
  1849. MYASSERT (!(DestOb.ObjectType & OT_VALUE));
  1850. MYASSERT (SrcObPtr->ObjectType & OT_VALUE);
  1851. if (SrcObPtr->ObjectType & OT_REGISTRY_TYPE) {
  1852. DestOb.ObjectType |= OT_REGISTRY_TYPE;
  1853. DestOb.Type = SrcObPtr->Type;
  1854. }
  1855. ReplaceValue (&DestOb, SrcObPtr->Value.Buffer, SrcObPtr->Value.Size);
  1856. if (!WriteObject (&DestOb)) {
  1857. DEBUGMSG ((DBG_ERROR, "WriteWinNTObjectString: %s cannot be written", ObjectStr));
  1858. goto c2;
  1859. }
  1860. b = TRUE;
  1861. c2:
  1862. FreeObjectStruct (&DestOb);
  1863. c1:
  1864. FreeObjectStruct (&TempOb);
  1865. c0:
  1866. return b;
  1867. }
  1868. BOOL
  1869. ReplaceValue (
  1870. PDATAOBJECT ObPtr,
  1871. PBYTE NewValue,
  1872. DWORD Size
  1873. )
  1874. {
  1875. FreeObjectVal (ObPtr);
  1876. if (!AllocObjectVal (ObPtr, NewValue, Size, Size)) {
  1877. return FALSE;
  1878. }
  1879. // Fix REG_SZ or REG_EXPAND_SZ
  1880. pFixRegSzTermination (ObPtr);
  1881. return TRUE;
  1882. }
  1883. BOOL
  1884. GetDwordFromObject (
  1885. CPDATAOBJECT ObPtr,
  1886. PDWORD DwordPtr OPTIONAL
  1887. )
  1888. {
  1889. DWORD d;
  1890. if (DwordPtr) {
  1891. *DwordPtr = 0;
  1892. }
  1893. if (!(ObPtr->ObjectType & OT_VALUE)) {
  1894. if (!ReadObject (ObPtr)) {
  1895. return FALSE;
  1896. }
  1897. }
  1898. if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE)) {
  1899. return FALSE;
  1900. }
  1901. if (ObPtr->Type == REG_SZ) {
  1902. d = _tcstoul ((PCTSTR) ObPtr->Value.Buffer, NULL, 10);
  1903. } else if (
  1904. ObPtr->Type == REG_BINARY ||
  1905. ObPtr->Type == REG_NONE ||
  1906. ObPtr->Type == REG_DWORD
  1907. ) {
  1908. if (ObPtr->Value.Size != sizeof (DWORD)) {
  1909. DEBUGMSG ((DBG_NAUSEA, "GetDwordFromObject: Value size is %u", ObPtr->Value.Size));
  1910. return FALSE;
  1911. }
  1912. d = *((PDWORD) ObPtr->Value.Buffer);
  1913. } else {
  1914. return FALSE;
  1915. }
  1916. if (DwordPtr) {
  1917. *DwordPtr = d;
  1918. }
  1919. return TRUE;
  1920. }
  1921. PCTSTR
  1922. GetStringFromObject (
  1923. CPDATAOBJECT ObPtr
  1924. )
  1925. {
  1926. PTSTR result;
  1927. PTSTR resultPtr;
  1928. UINT i;
  1929. if (!(ObPtr->ObjectType & OT_VALUE)) {
  1930. if (!ReadObject (ObPtr)) {
  1931. return NULL;
  1932. }
  1933. }
  1934. if (!(ObPtr->ObjectType & OT_REGISTRY_TYPE)) {
  1935. return NULL;
  1936. }
  1937. if (ObPtr->Type == REG_SZ) {
  1938. result = AllocPathString (ObPtr->Value.Size);
  1939. _tcssafecpy (result, (PCTSTR) ObPtr->Value.Buffer, ObPtr->Value.Size / sizeof (TCHAR));
  1940. }
  1941. else if (ObPtr->Type == REG_DWORD) {
  1942. result = AllocPathString (11);
  1943. wsprintf (result, TEXT("%lu"), *((PDWORD) ObPtr->Value.Buffer));
  1944. }
  1945. else if (ObPtr->Type == REG_BINARY) {
  1946. result = AllocPathString (ObPtr->Value.Size?(ObPtr->Value.Size * 3):1);
  1947. resultPtr = result;
  1948. *resultPtr = 0;
  1949. for (i = 0; i < ObPtr->Value.Size; i++) {
  1950. wsprintf (resultPtr, TEXT("%02X"), ObPtr->Value.Buffer[i]);
  1951. resultPtr = GetEndOfString (resultPtr);
  1952. if (i < ObPtr->Value.Size - 1) {
  1953. _tcscat (resultPtr, TEXT(" "));
  1954. resultPtr = GetEndOfString (resultPtr);
  1955. }
  1956. }
  1957. } else {
  1958. return NULL;
  1959. }
  1960. return result;
  1961. }
  1962. FILTERRETURN
  1963. pDeleteDataObjectFilter (
  1964. IN CPDATAOBJECT SrcObjectPtr,
  1965. IN CPDATAOBJECT UnusedObPtr, OPTIONAL
  1966. IN FILTERTYPE FilterType,
  1967. IN PVOID UnusedArg OPTIONAL
  1968. )
  1969. {
  1970. if (FilterType == FILTER_KEY_ENUM) {
  1971. DeleteDataObject (SrcObjectPtr);
  1972. return FILTER_RETURN_DELETED;
  1973. }
  1974. return FILTER_RETURN_HANDLED;
  1975. }
  1976. BOOL
  1977. DeleteDataObject (
  1978. IN PDATAOBJECT ObjectPtr
  1979. )
  1980. {
  1981. FILTERRETURN fr;
  1982. DWORD rc;
  1983. ObjectPtr->ObjectType |= OT_TREE;
  1984. fr = CopyObject (ObjectPtr, NULL, pDeleteDataObjectFilter, NULL);
  1985. if (fr != FILTER_RETURN_FAIL) {
  1986. //
  1987. // Perform deletion
  1988. //
  1989. if (ObjectPtr->KeyPtr) {
  1990. CloseObject (ObjectPtr);
  1991. if (IsWin95Object (ObjectPtr)) {
  1992. DEBUGMSG ((DBG_WHOOPS, "CreateObject: Cannot delete a Win95 object (%s)", DebugEncoder (ObjectPtr)));
  1993. return FALSE;
  1994. }
  1995. if (ObjectPtr->ParentKeyPtr && ObjectPtr->ParentKeyPtr->OpenKey && ObjectPtr->ChildKey) {
  1996. rc = WinNTRegDeleteKey (
  1997. ObjectPtr->ParentKeyPtr->OpenKey,
  1998. ObjectPtr->ChildKey
  1999. );
  2000. if (rc == ERROR_ACCESS_DENIED) {
  2001. LOG ((
  2002. LOG_INFORMATION,
  2003. "Access denied trying to delete %s in %s",
  2004. ObjectPtr->ChildKey,
  2005. ObjectPtr->ParentKeyPtr->KeyString
  2006. ));
  2007. rc = ERROR_SUCCESS;
  2008. }
  2009. } else {
  2010. rc = WinNTRegDeleteKey (
  2011. pGetWinNTKey (GetRootKeyFromOffset (ObjectPtr->RootItem)),
  2012. ObjectPtr->KeyPtr->KeyString
  2013. );
  2014. if (rc == ERROR_ACCESS_DENIED) {
  2015. LOG ((
  2016. LOG_INFORMATION,
  2017. "Access denied trying to delete %s",
  2018. ObjectPtr->KeyPtr->KeyString
  2019. ));
  2020. rc = ERROR_SUCCESS;
  2021. }
  2022. }
  2023. if (rc != ERROR_SUCCESS) {
  2024. SetLastError (rc);
  2025. LOG ((LOG_ERROR, "Failed to delete registry key"));
  2026. return FALSE;
  2027. }
  2028. }
  2029. }
  2030. return fr != FILTER_RETURN_FAIL;
  2031. }
  2032. BOOL
  2033. RenameDataObject (
  2034. IN CPDATAOBJECT SrcObPtr,
  2035. IN CPDATAOBJECT DestObPtr
  2036. )
  2037. {
  2038. FILTERRETURN fr;
  2039. //
  2040. // Copy source to destination
  2041. //
  2042. fr = CopyObject (SrcObPtr, DestObPtr, NULL, NULL);
  2043. if (fr == FILTER_RETURN_FAIL) {
  2044. DEBUGMSG ((DBG_ERROR, "Rename Object: Could not copy source to destination"));
  2045. return FALSE;
  2046. }
  2047. //
  2048. // Delete source
  2049. //
  2050. if (!DeleteDataObject (SrcObPtr)) {
  2051. DEBUGMSG ((DBG_ERROR, "Rename Object: Could not delete destination"));
  2052. return FALSE;
  2053. }
  2054. return TRUE;
  2055. }
  2056. BOOL
  2057. DeleteDataObjectValue(
  2058. IN CPDATAOBJECT ObPtr
  2059. )
  2060. {
  2061. HKEY hKey;
  2062. BOOL bResult;
  2063. HKEY Parent;
  2064. LONG rc;
  2065. if(!ObPtr || !IsObjectRegistryKeyAndVal(ObPtr)){
  2066. MYASSERT(FALSE);
  2067. return FALSE;
  2068. }
  2069. Parent = pGetWinNTKey (GetRootKeyFromOffset (ObPtr->RootItem));
  2070. if(NON_ROOT_KEY (Parent)){
  2071. MYASSERT(FALSE);
  2072. return FALSE;
  2073. }
  2074. if(ERROR_SUCCESS != TrackedRegOpenKeyEx(Parent, ObPtr->KeyPtr->KeyString, 0, KEY_ALL_ACCESS, &hKey)){
  2075. MYASSERT(FALSE);
  2076. return FALSE;
  2077. }
  2078. rc = WinNTRegDeleteValue(hKey, ObPtr->ValueName);
  2079. bResult = (rc == ERROR_SUCCESS);
  2080. if (rc == ERROR_ACCESS_DENIED) {
  2081. LOG ((
  2082. LOG_INFORMATION,
  2083. "Access denied trying to delete %s in %s",
  2084. ObPtr->KeyPtr->KeyString,
  2085. ObPtr->ValueName
  2086. ));
  2087. bResult = TRUE;
  2088. }
  2089. CloseRegKey(hKey);
  2090. return bResult;
  2091. }