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.

842 lines
21 KiB

  1. //
  2. // REGHIVE.C
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995
  5. //
  6. // Implementation of RegLoadKey, RegUnLoadKey, RegSaveKey, RegReplaceKey and
  7. // supporting functions.
  8. //
  9. #include "pch.h"
  10. #ifdef WANT_HIVE_SUPPORT
  11. // Maximum number of times we'll allow RgCopyBranch to be reentered.
  12. #define MAXIMUM_COPY_RECURSION 32
  13. LPSTR g_RgNameBufferPtr; // Temporary buffer for RgCopyBranch
  14. LPBYTE g_RgDataBufferPtr; // Temporary buffer for RgCopyBranch
  15. UINT g_RgRecursionCount; // Tracks depth of RgCopyBranch
  16. #if MAXIMUM_VALUE_NAME_LENGTH > MAXIMUM_SUB_KEY_LENGTH
  17. #error Code assumes a value name can fit in a subkey buffer.
  18. #endif
  19. #ifdef VXD
  20. #pragma VxD_RARE_CODE_SEG
  21. #endif
  22. //
  23. // RgValidateHiveSubKey
  24. //
  25. // Note that unlike most parameter validation routines, this routine must be
  26. // called with the registry lock taken because we call RgGetNextSubSubKey.
  27. //
  28. // Pass back the length of the subkey to deal with the trailing backslash
  29. // problem.
  30. //
  31. // Returns TRUE if lpSubKey is a valid subkey string for hive functions.
  32. //
  33. BOOL
  34. INTERNAL
  35. RgValidateHiveSubKey(
  36. LPCSTR lpSubKey,
  37. UINT FAR* lpHiveKeyLength
  38. )
  39. {
  40. LPCSTR lpSubSubKey;
  41. UINT SubSubKeyLength;
  42. // Verify that we have a valid subkey that has one and only one sub-subkey.
  43. // Win95 messed this up and it was possible to load a hive with a keyname
  44. // containing a backslash!
  45. return !IsNullPtr(lpSubKey) && !RgIsBadSubKey(lpSubKey) &&
  46. (RgGetNextSubSubKey(lpSubKey, &lpSubSubKey, lpHiveKeyLength) > 0) &&
  47. (RgGetNextSubSubKey(NULL, &lpSubSubKey, &SubSubKeyLength) == 0);
  48. }
  49. //
  50. // VMMRegLoadKey
  51. //
  52. // See Win32 documentation of RegLoadKey.
  53. //
  54. LONG
  55. REGAPI
  56. VMMRegLoadKey(
  57. HKEY hKey,
  58. LPCSTR lpSubKey,
  59. LPCSTR lpFileName
  60. )
  61. {
  62. int ErrorCode;
  63. HKEY hSubKey;
  64. UINT SubKeyLength;
  65. LPHIVE_INFO lpHiveInfo;
  66. if (IsBadStringPtr(lpFileName, (UINT) -1))
  67. return ERROR_INVALID_PARAMETER;
  68. if ((hKey != HKEY_LOCAL_MACHINE) && (hKey != HKEY_USERS))
  69. return ERROR_BADKEY;
  70. if (!RgLockRegistry())
  71. return ERROR_LOCK_FAILED;
  72. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) != ERROR_SUCCESS)
  73. goto ReturnErrorCode;
  74. if (!RgValidateHiveSubKey(lpSubKey, &SubKeyLength)) {
  75. ErrorCode = ERROR_BADKEY;
  76. goto ReturnErrorCode;
  77. }
  78. // Check if a subkey with the specified name already exists.
  79. if (RgLookupKey(hKey, lpSubKey, &hSubKey, LK_OPEN) == ERROR_SUCCESS) {
  80. RgDestroyKeyHandle(hSubKey);
  81. ErrorCode = ERROR_BADKEY; // Win95 compatibility
  82. goto ReturnErrorCode;
  83. }
  84. if (IsNullPtr((lpHiveInfo = (LPHIVE_INFO)
  85. RgSmAllocMemory(sizeof(HIVE_INFO) + SubKeyLength)))) {
  86. ErrorCode = ERROR_OUTOFMEMORY;
  87. goto ReturnErrorCode;
  88. }
  89. // Fill in the HIVE_INFO.
  90. StrCpy(lpHiveInfo-> Name, lpSubKey);
  91. lpHiveInfo-> NameLength = SubKeyLength;
  92. lpHiveInfo-> Hash = (BYTE) RgHashString(lpSubKey, SubKeyLength);
  93. // Attempt to create a FILE_INFO for the specified file. If successful,
  94. // link this HIVE_INFO into the parent FILE_INFO's hive list.
  95. if ((ErrorCode = RgCreateFileInfoExisting(&lpHiveInfo-> lpFileInfo,
  96. lpFileName)) == ERROR_SUCCESS) {
  97. #ifdef WANT_NOTIFY_CHANGE_SUPPORT
  98. lpHiveInfo-> lpFileInfo-> lpParentFileInfo = hKey-> lpFileInfo;
  99. #endif
  100. lpHiveInfo-> lpNextHiveInfo = hKey-> lpFileInfo-> lpHiveInfoList;
  101. hKey-> lpFileInfo-> lpHiveInfoList = lpHiveInfo;
  102. // Signal any notifications waiting on this top-level key.
  103. RgSignalWaitingNotifies(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  104. REG_NOTIFY_CHANGE_NAME);
  105. }
  106. else
  107. RgFreeMemory(lpHiveInfo);
  108. ReturnErrorCode:
  109. RgUnlockRegistry();
  110. return ErrorCode;
  111. }
  112. //
  113. // VMMRegUnLoadKey
  114. //
  115. // See Win32 documentation of RegUnLoadKey.
  116. //
  117. LONG
  118. REGAPI
  119. VMMRegUnLoadKey(
  120. HKEY hKey,
  121. LPCSTR lpSubKey
  122. )
  123. {
  124. int ErrorCode;
  125. UINT SubKeyLength;
  126. LPFILE_INFO lpFileInfo;
  127. LPHIVE_INFO lpPrevHiveInfo;
  128. LPHIVE_INFO lpCurrHiveInfo;
  129. if ((hKey != HKEY_LOCAL_MACHINE) && (hKey != HKEY_USERS))
  130. return ERROR_BADKEY;
  131. if (!RgLockRegistry())
  132. return ERROR_LOCK_FAILED;
  133. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) != ERROR_SUCCESS)
  134. goto ReturnErrorCode;
  135. ErrorCode = ERROR_BADKEY; // Assume this error code
  136. if (!RgValidateHiveSubKey(lpSubKey, &SubKeyLength))
  137. goto ReturnErrorCode;
  138. lpPrevHiveInfo = NULL;
  139. lpCurrHiveInfo = hKey-> lpFileInfo-> lpHiveInfoList;
  140. while (!IsNullPtr(lpCurrHiveInfo)) {
  141. if (SubKeyLength == lpCurrHiveInfo-> NameLength && RgStrCmpNI(lpSubKey,
  142. lpCurrHiveInfo-> Name, SubKeyLength) == 0) {
  143. // Unlink this HIVE_INFO structure.
  144. if (IsNullPtr(lpPrevHiveInfo))
  145. hKey-> lpFileInfo-> lpHiveInfoList = lpCurrHiveInfo->
  146. lpNextHiveInfo;
  147. else
  148. lpPrevHiveInfo-> lpNextHiveInfo = lpCurrHiveInfo->
  149. lpNextHiveInfo;
  150. // Flush and destroy it's associated FILE_INFO structure. When we
  151. // destroy the FILE_INFO, all open keys in this hive will be
  152. // invalidated.
  153. lpFileInfo = lpCurrHiveInfo-> lpFileInfo;
  154. RgFlushFileInfo(lpFileInfo);
  155. RgDestroyFileInfo(lpFileInfo);
  156. // Free the HIVE_INFO itself.
  157. RgSmFreeMemory(lpCurrHiveInfo);
  158. // Signal any notifications waiting on this top-level key.
  159. RgSignalWaitingNotifies(hKey-> lpFileInfo, hKey-> KeynodeIndex,
  160. REG_NOTIFY_CHANGE_NAME);
  161. ErrorCode = ERROR_SUCCESS;
  162. break;
  163. }
  164. lpPrevHiveInfo = lpCurrHiveInfo;
  165. lpCurrHiveInfo = lpCurrHiveInfo-> lpNextHiveInfo;
  166. }
  167. ReturnErrorCode:
  168. RgUnlockRegistry();
  169. return ErrorCode;
  170. }
  171. //
  172. // RgCopyBranchHelper
  173. //
  174. // Copies all of the values and subkeys starting at the specified source key to
  175. // the specified destination key.
  176. //
  177. // For Win95 compatibility, we don't stop the copy process if we encounter an
  178. // error. (But unlike Win95, we do actually check more error codes)
  179. //
  180. // SHOULD ONLY BE CALLED BY RgCopyBranch.
  181. //
  182. VOID
  183. INTERNAL
  184. RgCopyBranchHelper(
  185. HKEY hSourceKey,
  186. HKEY hDestinationKey
  187. )
  188. {
  189. UINT Index;
  190. DWORD cbNameBuffer;
  191. LPVALUE_RECORD lpValueRecord;
  192. //
  193. // Copy all of the values from the source key to the destination key.
  194. //
  195. Index = 0;
  196. while (RgLookupValueByIndex(hSourceKey, Index++, &lpValueRecord) ==
  197. ERROR_SUCCESS) {
  198. DWORD cbDataBuffer;
  199. DWORD Type;
  200. cbNameBuffer = MAXIMUM_VALUE_NAME_LENGTH;
  201. cbDataBuffer = MAXIMUM_DATA_LENGTH + 1; // Terminating null
  202. if (RgCopyFromValueRecord(hSourceKey, lpValueRecord, g_RgNameBufferPtr,
  203. &cbNameBuffer, &Type, g_RgDataBufferPtr, &cbDataBuffer) ==
  204. ERROR_SUCCESS) {
  205. // Subtract the terminating null that RgCopyFromValueRecord added
  206. // to cbDataBuffer. We don't save that in the file.
  207. if (Type == REG_SZ) {
  208. ASSERT(cbDataBuffer > 0); // Must have the null!
  209. cbDataBuffer--;
  210. }
  211. RgSetValue(hDestinationKey, g_RgNameBufferPtr, Type,
  212. g_RgDataBufferPtr, cbDataBuffer);
  213. }
  214. RgUnlockDatablock(hSourceKey-> lpFileInfo, hSourceKey-> BlockIndex,
  215. FALSE);
  216. }
  217. // We can't recurse forever, so enforce a maximum depth like Win95.
  218. if (g_RgRecursionCount > MAXIMUM_COPY_RECURSION)
  219. return;
  220. g_RgRecursionCount++;
  221. //
  222. // Copy all of the subkeys from the source key to the destination key.
  223. //
  224. Index = 0;
  225. while (TRUE) {
  226. HKEY hSubSourceKey;
  227. HKEY hSubDestinationKey;
  228. cbNameBuffer = MAXIMUM_SUB_KEY_LENGTH;
  229. if (RgLookupKeyByIndex(hSourceKey, Index++, g_RgNameBufferPtr,
  230. &cbNameBuffer) != ERROR_SUCCESS)
  231. break;
  232. if (RgLookupKey(hSourceKey, g_RgNameBufferPtr, &hSubSourceKey,
  233. LK_OPEN) == ERROR_SUCCESS) {
  234. if (RgLookupKey(hDestinationKey, g_RgNameBufferPtr,
  235. &hSubDestinationKey, LK_CREATE) == ERROR_SUCCESS) {
  236. RgYield();
  237. RgCopyBranchHelper(hSubSourceKey, hSubDestinationKey);
  238. RgDestroyKeyHandle(hSubDestinationKey);
  239. }
  240. else
  241. TRAP();
  242. RgDestroyKeyHandle(hSubSourceKey);
  243. }
  244. else
  245. TRAP();
  246. }
  247. g_RgRecursionCount--;
  248. }
  249. //
  250. // RgCopyBranch
  251. //
  252. // Copies all of the values and subkeys starting at the specified source key to
  253. // the specified destination key.
  254. //
  255. // This function sets and cleans up for RgCopyBranchHelper who does all
  256. // the real copying.
  257. //
  258. // The backing store of the destination file is flushed if successful.
  259. //
  260. int
  261. INTERNAL
  262. RgCopyBranch(
  263. HKEY hSourceKey,
  264. HKEY hDestinationKey
  265. )
  266. {
  267. int ErrorCode;
  268. if (IsNullPtr(g_RgNameBufferPtr = RgSmAllocMemory(MAXIMUM_SUB_KEY_LENGTH)))
  269. ErrorCode = ERROR_OUTOFMEMORY;
  270. else {
  271. if (IsNullPtr(g_RgDataBufferPtr = RgSmAllocMemory(MAXIMUM_DATA_LENGTH +
  272. 1))) // + terminating null
  273. ErrorCode = ERROR_OUTOFMEMORY;
  274. else {
  275. g_RgRecursionCount = 0;
  276. RgCopyBranchHelper(hSourceKey, hDestinationKey);
  277. // Everything should be copied over, so flush the file now since
  278. // all callers will be immediately destroying this FILE_INFO
  279. // anyways.
  280. ErrorCode = RgFlushFileInfo(hDestinationKey-> lpFileInfo);
  281. }
  282. RgSmFreeMemory(g_RgNameBufferPtr);
  283. }
  284. RgSmFreeMemory(g_RgDataBufferPtr);
  285. return ErrorCode;
  286. }
  287. //
  288. // RgSaveKey
  289. //
  290. // Worker routine for VMMRegSaveKey and VMMRegReplaceKey. Saves all the keys
  291. // and values starting at hKey, which must point at a valid KEY structure, to
  292. // the location specified by lpFileName. The file must not currently exist.
  293. //
  294. int
  295. INTERNAL
  296. RgSaveKey(
  297. HKEY hKey,
  298. LPCSTR lpFileName
  299. )
  300. {
  301. int ErrorCode;
  302. HKEY hHiveKey;
  303. if (IsNullPtr(hHiveKey = RgCreateKeyHandle()))
  304. ErrorCode = ERROR_OUTOFMEMORY;
  305. else {
  306. // Artificially increment the count, so the below destroy will work.
  307. RgIncrementKeyReferenceCount(hHiveKey);
  308. if ((ErrorCode = RgCreateFileInfoNew(&hHiveKey-> lpFileInfo, lpFileName,
  309. CFIN_SECONDARY)) == ERROR_SUCCESS) {
  310. if (((ErrorCode = RgInitRootKeyFromFileInfo(hHiveKey)) != ERROR_SUCCESS) ||
  311. ((ErrorCode = RgCopyBranch(hKey, hHiveKey)) != ERROR_SUCCESS)) {
  312. RgSetFileAttributes(hHiveKey-> lpFileInfo-> FileName,
  313. FILE_ATTRIBUTE_NONE);
  314. RgDeleteFile(hHiveKey-> lpFileInfo-> FileName);
  315. }
  316. // If successful, then RgCopyBranch has already flushed the file.
  317. RgDestroyFileInfo(hHiveKey-> lpFileInfo);
  318. }
  319. RgDestroyKeyHandle(hHiveKey);
  320. }
  321. return ErrorCode;
  322. }
  323. //
  324. // VMMRegSaveKey
  325. //
  326. // See Win32 documentation of RegSaveKey.
  327. //
  328. LONG
  329. REGAPI
  330. VMMRegSaveKey(
  331. HKEY hKey,
  332. LPCSTR lpFileName,
  333. LPVOID lpSecurityAttributes
  334. )
  335. {
  336. int ErrorCode;
  337. if (IsBadStringPtr(lpFileName, (UINT) -1))
  338. return ERROR_INVALID_PARAMETER;
  339. if (!RgLockRegistry())
  340. return ERROR_LOCK_FAILED;
  341. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) == ERROR_SUCCESS)
  342. ErrorCode = RgSaveKey(hKey, lpFileName);
  343. RgUnlockRegistry();
  344. return ErrorCode;
  345. UNREFERENCED_PARAMETER(lpSecurityAttributes);
  346. }
  347. #ifdef WANT_REGREPLACEKEY
  348. //
  349. // RgGetKeyName
  350. //
  351. LPSTR
  352. INTERNAL
  353. RgGetKeyName(
  354. HKEY hKey
  355. )
  356. {
  357. LPSTR lpKeyName;
  358. LPKEY_RECORD lpKeyRecord;
  359. if (RgLockKeyRecord(hKey-> lpFileInfo, hKey-> BlockIndex, hKey->
  360. KeyRecordIndex, &lpKeyRecord) != ERROR_SUCCESS)
  361. lpKeyName = NULL;
  362. else {
  363. // A registry is corrupt if we ever hit this. We'll continue to
  364. // allocate a buffer and let downstream code fail when we try to use
  365. // the string.
  366. ASSERT(lpKeyRecord-> NameLength < MAXIMUM_SUB_KEY_LENGTH);
  367. if (!IsNullPtr(lpKeyName = (LPSTR) RgSmAllocMemory(lpKeyRecord->
  368. NameLength + 1))) { // + terminating null
  369. MoveMemory(lpKeyName, lpKeyRecord-> Name, lpKeyRecord->
  370. NameLength);
  371. lpKeyName[lpKeyRecord-> NameLength] = '\0';
  372. }
  373. RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BlockIndex, FALSE);
  374. }
  375. return lpKeyName;
  376. }
  377. //
  378. // RgCreateRootKeyForFile
  379. //
  380. // Creates a KEY and a FILE_INFO to access the specified file.
  381. //
  382. int
  383. INTERNAL
  384. RgCreateRootKeyForFile(
  385. LPHKEY lphKey,
  386. LPCSTR lpFileName
  387. )
  388. {
  389. int ErrorCode;
  390. HKEY hKey;
  391. if (IsNullPtr(hKey = RgCreateKeyHandle()))
  392. ErrorCode = ERROR_OUTOFMEMORY;
  393. else {
  394. // Artificially increment the count, so RgDestroyKeyHandle will work.
  395. RgIncrementKeyReferenceCount(hKey);
  396. if ((ErrorCode = RgCreateFileInfoExisting(&hKey-> lpFileInfo,
  397. lpFileName)) == ERROR_SUCCESS) {
  398. if ((ErrorCode = RgInitRootKeyFromFileInfo(hKey)) ==
  399. ERROR_SUCCESS) {
  400. *lphKey = hKey;
  401. return ERROR_SUCCESS;
  402. }
  403. RgDestroyFileInfo(hKey-> lpFileInfo);
  404. }
  405. RgDestroyKeyHandle(hKey);
  406. }
  407. return ErrorCode;
  408. }
  409. //
  410. // RgDestroyRootKeyForFile
  411. //
  412. // Destroys the resources allocated by RgCreateRootKeyForFile.
  413. //
  414. VOID
  415. INTERNAL
  416. RgDestroyRootKeyForFile(
  417. HKEY hKey
  418. )
  419. {
  420. RgDestroyFileInfo(hKey-> lpFileInfo);
  421. RgDestroyKeyHandle(hKey);
  422. }
  423. //
  424. // RgDeleteHiveFile
  425. //
  426. // Deletes the specified hive file after clearing its file attributes.
  427. //
  428. BOOL
  429. INTERNAL
  430. RgDeleteHiveFile(
  431. LPCSTR lpFileName
  432. )
  433. {
  434. RgSetFileAttributes(lpFileName, FILE_ATTRIBUTE_NONE);
  435. // RgSetFileAttributes may fail, but try to delete the file anyway.
  436. return RgDeleteFile(lpFileName);
  437. }
  438. //
  439. // VMMRegReplaceKey
  440. //
  441. // See Win32 documentation of RegReplaceKey.
  442. //
  443. LONG
  444. REGAPI
  445. VMMRegReplaceKey(
  446. HKEY hKey,
  447. LPCSTR lpSubKey,
  448. LPCSTR lpNewFileName,
  449. LPCSTR lpOldFileName
  450. )
  451. {
  452. int ErrorCode;
  453. HKEY hSubKey;
  454. LPKEYNODE lpKeynode;
  455. DWORD KeynodeIndex;
  456. HKEY hParentKey;
  457. char ReplaceFileName[MAX_PATH];
  458. BOOL fCreatedReplaceFile;
  459. HKEY hReplaceKey;
  460. HKEY hNewKey;
  461. HKEY hReplaceSubKey;
  462. LPSTR lpReplaceSubKey;
  463. if (IsBadOptionalStringPtr(lpSubKey, (UINT) -1) ||
  464. IsBadStringPtr(lpNewFileName, (UINT) -1) ||
  465. IsBadStringPtr(lpOldFileName, (UINT) -1))
  466. return ERROR_INVALID_PARAMETER;
  467. if (!RgLockRegistry())
  468. return ERROR_LOCK_FAILED;
  469. if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) != ERROR_SUCCESS)
  470. goto ErrorReturn;
  471. if ((ErrorCode = RgLookupKey(hKey, lpSubKey, &hSubKey, LK_OPEN)) !=
  472. ERROR_SUCCESS)
  473. goto ErrorReturn;
  474. //
  475. // The provided key handle must an immediate child from the same backing
  476. // store (not a hive) as either HKEY_LOCAL_MACHINE or HKEY_USERS.
  477. //
  478. if (RgLockInUseKeynode(hSubKey-> lpFileInfo, hSubKey-> KeynodeIndex,
  479. &lpKeynode) != ERROR_SUCCESS) {
  480. ErrorCode = ERROR_OUTOFMEMORY;
  481. goto ErrorDestroySubKey;
  482. }
  483. KeynodeIndex = lpKeynode-> ParentIndex;
  484. RgUnlockKeynode(hSubKey-> lpFileInfo, hSubKey-> KeynodeIndex, FALSE);
  485. // Find an open key on the parent check if it's HKEY_LOCAL_MACHINE or
  486. // HKEY_USERS. If not, bail out. KeynodeIndex may be REG_NULL, but
  487. // RgFindOpenKeyHandle handles that case.
  488. if (IsNullPtr(hParentKey = RgFindOpenKeyHandle(hSubKey-> lpFileInfo,
  489. KeynodeIndex)) || ((hParentKey != &g_RgLocalMachineKey) &&
  490. (hParentKey != &g_RgUsersKey))) {
  491. ErrorCode = ERROR_INVALID_PARAMETER;
  492. goto ErrorDestroySubKey;
  493. }
  494. //
  495. // All parameters have been validated, so begin the real work of the API.
  496. //
  497. // Because we'll be doing a file copy below, all changes must be flushed
  498. // now.
  499. if ((ErrorCode = RgFlushFileInfo(hSubKey-> lpFileInfo)) != ERROR_SUCCESS)
  500. goto ErrorDestroySubKey;
  501. // Make a backup of the current contents of the subkey.
  502. if ((ErrorCode = RgSaveKey(hSubKey, lpOldFileName)) != ERROR_SUCCESS)
  503. goto ErrorDestroySubKey;
  504. RgGenerateAltFileName(hSubKey-> lpFileInfo-> FileName, ReplaceFileName, 'R');
  505. // Check if the magic replacement file already exists and if not, create
  506. // it.
  507. if (RgGetFileAttributes(ReplaceFileName) == (DWORD) -1) {
  508. if ((ErrorCode = RgCopyFile(hSubKey-> lpFileInfo-> FileName,
  509. ReplaceFileName)) != ERROR_SUCCESS)
  510. goto ErrorDeleteOldFile;
  511. fCreatedReplaceFile = TRUE;
  512. }
  513. else
  514. fCreatedReplaceFile = FALSE;
  515. if ((ErrorCode = RgCreateRootKeyForFile(&hNewKey, lpNewFileName)) !=
  516. ERROR_SUCCESS)
  517. goto ErrorDeleteReplaceFile;
  518. if ((ErrorCode = RgCreateRootKeyForFile(&hReplaceKey, ReplaceFileName)) !=
  519. ERROR_SUCCESS)
  520. goto ErrorDestroyNewRootKey;
  521. // The original key that we were given may reference the subkey, so
  522. // lpSubKey would be a NULL or empty string. But we need the name that
  523. // this subkey refers to, so we have to go back to the file to pull out
  524. // the name.
  525. if (hKey != hSubKey)
  526. lpReplaceSubKey = (LPSTR) lpSubKey;
  527. else {
  528. // We allocate this from the heap to reduce the requirements of an
  529. // already strained stack. If this fails, we're likely out of memory.
  530. // Even if that's not why we failed, this is such an infrequent path
  531. // that it's a good enough error code.
  532. if (IsNullPtr(lpReplaceSubKey = RgGetKeyName(hSubKey))) {
  533. ErrorCode = ERROR_OUTOFMEMORY;
  534. goto ErrorDestroyReplaceRootKey;
  535. }
  536. }
  537. // Check if the specified subkey already exists and if it does, delete it.
  538. if (RgLookupKey(hReplaceKey, lpReplaceSubKey, &hReplaceSubKey, LK_OPEN) ==
  539. ERROR_SUCCESS) {
  540. RgDeleteKey(hReplaceSubKey);
  541. RgDestroyKeyHandle(hReplaceSubKey);
  542. }
  543. // Create the specified subkey in the replacement registry and copy the
  544. // new hive to that key.
  545. if ((ErrorCode = RgLookupKey(hReplaceKey, lpReplaceSubKey, &hReplaceSubKey,
  546. LK_CREATE)) == ERROR_SUCCESS) {
  547. // If successful, tag the FILE_INFO so that on system exit, we'll go
  548. // and rename the replacement file to actual filename.
  549. if ((ErrorCode = RgCopyBranch(hNewKey, hReplaceSubKey)) ==
  550. ERROR_SUCCESS)
  551. hKey-> lpFileInfo-> Flags |= FI_REPLACEMENTEXISTS;
  552. RgDestroyKeyHandle(hReplaceSubKey);
  553. }
  554. if (lpSubKey != lpReplaceSubKey)
  555. RgSmFreeMemory(lpReplaceSubKey);
  556. ErrorDestroyReplaceRootKey:
  557. RgDestroyRootKeyForFile(hReplaceKey);
  558. ErrorDestroyNewRootKey:
  559. RgDestroyRootKeyForFile(hNewKey);
  560. ErrorDeleteReplaceFile:
  561. if (ErrorCode != ERROR_SUCCESS && fCreatedReplaceFile)
  562. RgDeleteHiveFile(ReplaceFileName);
  563. ErrorDeleteOldFile:
  564. if (ErrorCode != ERROR_SUCCESS)
  565. RgDeleteHiveFile(lpOldFileName);
  566. ErrorDestroySubKey:
  567. RgDestroyKeyHandle(hSubKey);
  568. ErrorReturn:
  569. RgUnlockRegistry();
  570. return ErrorCode;
  571. }
  572. #ifdef VXD
  573. #pragma VxD_SYSEXIT_CODE_SEG
  574. #endif
  575. //
  576. // RgReplaceFileOnSysExit
  577. //
  578. // Essentially the same algorithm as rlReplaceFile from the Win95 registry
  579. // code with modifications for how file I/O is handled in this library.
  580. //
  581. int
  582. INTERNAL
  583. RgReplaceFileOnSysExit(
  584. LPCSTR lpFileName
  585. )
  586. {
  587. int ErrorCode;
  588. char ReplaceFileName[MAX_PATH];
  589. char SaveFileName[MAX_PATH];
  590. ErrorCode = ERROR_SUCCESS;
  591. if (RgGenerateAltFileName(lpFileName, ReplaceFileName, 'R') &&
  592. RgGetFileAttributes(ReplaceFileName) == (FILE_ATTRIBUTE_READONLY |
  593. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
  594. // If we were able to generate the replace file name, then we must be
  595. // able to generate the save file name, so ignore the result.
  596. RgGenerateAltFileName(lpFileName, SaveFileName, 'S');
  597. RgDeleteHiveFile(SaveFileName);
  598. // Preserve the current hive in case something fails below.
  599. if (!RgSetFileAttributes(lpFileName, FILE_ATTRIBUTE_NONE) ||
  600. !RgRenameFile(lpFileName, SaveFileName))
  601. ErrorCode = ERROR_REGISTRY_IO_FAILED;
  602. else {
  603. // Now try to move the replacement in.
  604. if (!RgSetFileAttributes(ReplaceFileName, FILE_ATTRIBUTE_NONE) ||
  605. !RgRenameFile(ReplaceFileName, lpFileName)) {
  606. ErrorCode = ERROR_REGISTRY_IO_FAILED;
  607. RgRenameFile(SaveFileName, lpFileName);
  608. }
  609. else
  610. RgDeleteFile(SaveFileName);
  611. }
  612. RgSetFileAttributes(lpFileName, FILE_ATTRIBUTE_READONLY |
  613. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  614. }
  615. return ErrorCode;
  616. }
  617. //
  618. // RgReplaceFileInfo
  619. //
  620. // Called during registry detach to do any necessary file replacements as a
  621. // result of calling RegReplaceKey.
  622. //
  623. int
  624. INTERNAL
  625. RgReplaceFileInfo(
  626. LPFILE_INFO lpFileInfo
  627. )
  628. {
  629. if (lpFileInfo-> Flags & FI_REPLACEMENTEXISTS)
  630. RgReplaceFileOnSysExit(lpFileInfo-> FileName);
  631. return ERROR_SUCCESS;
  632. }
  633. #endif // WANT_REGREPLACEKEY
  634. #endif // WANT_HIVE_SUPPORT