Leaked source code of windows server 2003
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.

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