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.

1293 lines
32 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. Interfaces for registering and deregistering registry checkpoint
  7. handlers.
  8. Author:
  9. John Vert (jvert) 1/16/1997
  10. Revision History:
  11. --*/
  12. #include "cpp.h"
  13. //
  14. // Local type and structure definitions
  15. //
  16. typedef struct _CPP_ADD_CONTEXT {
  17. BOOL Found;
  18. LPCWSTR KeyName;
  19. } CPP_ADD_CONTEXT, *PCPP_ADD_CONTEXT;
  20. typedef struct _CPP_DEL_CONTEXT {
  21. DWORD dwId;
  22. LPCWSTR KeyName;
  23. } CPP_DEL_CONTEXT, *PCPP_DEL_CONTEXT;
  24. typedef struct _CPP_GET_CONTEXT {
  25. DWORD Available;
  26. DWORD Required;
  27. LPWSTR lpOutput;
  28. } CPP_GET_CONTEXT, *PCPP_GET_CONTEXT;
  29. //
  30. // Local function prototypes
  31. //
  32. BOOL
  33. CppWatchCallback(
  34. IN LPWSTR ValueName,
  35. IN LPVOID ValueData,
  36. IN DWORD ValueType,
  37. IN DWORD ValueSize,
  38. IN PFM_RESOURCE Resource
  39. );
  40. BOOL
  41. CppAddCheckpointCallback(
  42. IN LPWSTR ValueName,
  43. IN LPVOID ValueData,
  44. IN DWORD ValueType,
  45. IN DWORD ValueSize,
  46. IN PCPP_ADD_CONTEXT Context
  47. );
  48. BOOL
  49. CppDeleteCheckpointCallback(
  50. IN LPWSTR ValueName,
  51. IN LPVOID ValueData,
  52. IN DWORD ValueType,
  53. IN DWORD ValueSize,
  54. IN PCPP_DEL_CONTEXT Context
  55. );
  56. BOOL
  57. CppGetCheckpointsCallback(
  58. IN LPWSTR ValueName,
  59. IN LPVOID ValueData,
  60. IN DWORD ValueType,
  61. IN DWORD ValueSize,
  62. IN PCPP_GET_CONTEXT Context
  63. );
  64. DWORD
  65. CppWatchRegistry(
  66. IN PFM_RESOURCE Resource
  67. )
  68. /*++
  69. Routine Description:
  70. Restores any registry checkpoints for this resource and begins
  71. watching the registry for any further modifications.
  72. Arguments:
  73. Resource - Supplies the resource.
  74. Return Value:
  75. ERROR_SUCCESS if successful
  76. Win32 error code otherwise
  77. --*/
  78. {
  79. DWORD Status;
  80. HDMKEY ResourceKey;
  81. HDMKEY RegSyncKey;
  82. //
  83. // Open up the resource's key
  84. //
  85. ResourceKey = DmOpenKey(DmResourcesKey,
  86. OmObjectId(Resource),
  87. KEY_READ);
  88. CL_ASSERT(ResourceKey != NULL);
  89. //
  90. // Open up the RegSync key
  91. //
  92. RegSyncKey = DmOpenKey(ResourceKey,
  93. L"RegSync",
  94. KEY_READ);
  95. DmCloseKey(ResourceKey);
  96. if (RegSyncKey != NULL) {
  97. DmEnumValues(RegSyncKey,
  98. CppWatchCallback,
  99. Resource);
  100. DmCloseKey(RegSyncKey);
  101. }
  102. return(ERROR_SUCCESS);
  103. }
  104. BOOL
  105. CppWatchCallback(
  106. IN LPWSTR ValueName,
  107. IN LPVOID ValueData,
  108. IN DWORD ValueType,
  109. IN DWORD ValueSize,
  110. IN PFM_RESOURCE Resource
  111. )
  112. /*++
  113. Routine Description:
  114. Value enumeration callback for watching a resource's registry
  115. checkpoint subtrees.
  116. Arguments:
  117. ValueName - Supplies the name of the value (this is the checkpoint ID)
  118. ValueData - Supplies the value data (this is the registry subtree)
  119. ValueType - Supplies the value type (must be REG_SZ)
  120. ValueSize - Supplies the size of ValueData
  121. Resource - Supplies the resource this value is a registry checkpoint for
  122. Return Value:
  123. TRUE to continue enumeration
  124. --*/
  125. {
  126. HKEY hKey;
  127. DWORD Id;
  128. DWORD Status;
  129. DWORD Disposition;
  130. WCHAR TempFile[MAX_PATH];
  131. BOOLEAN WasEnabled;
  132. Id = wcstol(ValueName, NULL, 16);
  133. if (Id == 0) {
  134. ClRtlLogPrint(LOG_UNUSUAL,
  135. "[CP] CppWatchCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  136. ValueName,
  137. OmObjectName(Resource));
  138. return(TRUE);
  139. }
  140. //
  141. // Attempt to create the specified registry key.
  142. //
  143. Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  144. ValueData,
  145. 0,
  146. NULL,
  147. 0,
  148. KEY_WRITE,
  149. NULL,
  150. &hKey,
  151. &Disposition);
  152. if (Status != ERROR_SUCCESS) {
  153. //
  154. // For some reason we could not open the key. Try again with restore
  155. // privilege. Note that this will not work if the key does not exist.
  156. // Not much we can do in that case.
  157. //
  158. ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  159. &WasEnabled);
  160. Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  161. ValueData,
  162. REG_OPTION_BACKUP_RESTORE,
  163. KEY_WRITE,
  164. &hKey);
  165. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  166. WasEnabled);
  167. }
  168. if (Status != ERROR_SUCCESS) {
  169. ClRtlLogPrint(LOG_CRITICAL,
  170. "[CP] CppWatchCallback: could not create key %1!ws! error %2!d!\n",
  171. ValueData,
  172. Status);
  173. return(TRUE);
  174. }
  175. ClRtlLogPrint(LOG_NOISE,
  176. "[CP] CppWatchCallback retrieving checkpoint id %1!lx! for resource %2!ws\n",
  177. Id,
  178. OmObjectName(Resource));
  179. //
  180. // See if there is any checkpoint data for this ID.
  181. //
  182. Status = DmCreateTempFileName(TempFile);
  183. if (Status != ERROR_SUCCESS) {
  184. CL_UNEXPECTED_ERROR( Status );
  185. }
  186. Status = CpGetDataFile(Resource,
  187. Id,
  188. TempFile,
  189. FALSE);
  190. if (Status != ERROR_SUCCESS) {
  191. ClRtlLogPrint(LOG_UNUSUAL,
  192. "[CP] CppWatchCallback - CpGetDataFile for id %1!lx! resource %2!ws! failed %3!d!\n",
  193. Id,
  194. OmObjectName(Resource),
  195. Status);
  196. } else {
  197. //
  198. // Finally install the checkpointed file into the registry.
  199. //
  200. Status = CppInstallDatabase(hKey,
  201. TempFile);
  202. if (Status != ERROR_SUCCESS) {
  203. ClRtlLogPrint(LOG_CRITICAL,
  204. "[CP] CppWatchCallback: could not restore temp file %1!ws! to key %2!ws! error %3!d!\n",
  205. TempFile,
  206. ValueData,
  207. Status);
  208. CsLogEventData2(LOG_CRITICAL,
  209. CP_REG_CKPT_RESTORE_FAILED,
  210. sizeof(Status),
  211. &Status,
  212. OmObjectName(Resource),
  213. ValueData);
  214. }
  215. }
  216. DeleteFile(TempFile);
  217. RegCloseKey(hKey);
  218. //
  219. // Install the registry watcher for this checkpoint
  220. //
  221. Status = CppRegisterNotify(Resource,
  222. ValueData,
  223. Id);
  224. if (Status != ERROR_SUCCESS) {
  225. ClRtlLogPrint(LOG_CRITICAL,
  226. "[CP] CppWatchRegistry - CppRegisterNotify failed for key %1!ws! %1!d!\n",
  227. ValueData,
  228. Status);
  229. }
  230. return(TRUE);
  231. }
  232. DWORD
  233. CpAddRegistryCheckpoint(
  234. IN PFM_RESOURCE Resource,
  235. IN LPCWSTR KeyName
  236. )
  237. /*++
  238. Routine Description:
  239. Adds a new registry checkpoint to a resource's list.
  240. Arguments:
  241. Resource - supplies the resource the registry checkpoint should be added to.
  242. KeyName - Supplies the name of the registry key (relative to HKEY_LOCAL_MACHINE);
  243. Return Value:
  244. ERROR_SUCCESS if successful
  245. Win32 error code otherwise
  246. --*/
  247. {
  248. CPP_ADD_CONTEXT Context;
  249. HDMKEY ResourceKey = NULL;
  250. HDMKEY RegSyncKey = NULL;
  251. DWORD Disposition;
  252. DWORD Id;
  253. WCHAR IdName[9];
  254. DWORD Status;
  255. HKEY hKey = NULL;
  256. CLUSTER_RESOURCE_STATE State;
  257. BOOLEAN WasEnabled;
  258. DWORD Count=60;
  259. HKEY hKeyOpen = NULL;
  260. //
  261. // Make sure the specified key is valid.
  262. // - First we try and open the key while using backup privilege.
  263. // If the key exists, this will get us a handle even if our account
  264. // does not have permission.
  265. // - If you are using REG_OPTION_BACKUP_RESTORE and the key does not
  266. // exist, a new key will not be created. So if the first create fails,
  267. // we try again without REG_OPTION_BACKUP_RESTORE. This will create
  268. // the key if it does not exist (and we have permission to create such
  269. // a key) If the key does not exist and we cannot create they key,
  270. // the checkpoint add fails.
  271. //
  272. Status = ClRtlEnableThreadPrivilege(SE_BACKUP_PRIVILEGE,
  273. &WasEnabled);
  274. if (Status != ERROR_SUCCESS)
  275. {
  276. ClRtlLogPrint(LOG_CRITICAL,
  277. "[CP] CpAddRegistryCheckpoint - ClRtlEnableThreadPrivilege failed with Status %1!u!\n",
  278. Status);
  279. goto FnExit;
  280. }
  281. Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  282. KeyName,
  283. 0,
  284. NULL,
  285. REG_OPTION_BACKUP_RESTORE,
  286. KEY_READ,
  287. NULL,
  288. &hKey,
  289. &Disposition);
  290. ClRtlRestoreThreadPrivilege(SE_BACKUP_PRIVILEGE,
  291. WasEnabled);
  292. if (Status != ERROR_SUCCESS) {
  293. //
  294. // Try again without REG_OPTION_BACKUP_RESTORE.
  295. //
  296. Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  297. KeyName,
  298. 0,
  299. NULL,
  300. 0,
  301. KEY_READ,
  302. NULL,
  303. &hKey,
  304. &Disposition);
  305. if (Status != ERROR_SUCCESS) {
  306. ClRtlLogPrint(LOG_CRITICAL,
  307. "[CP] CpAddRegistryCheckpoint Could not create key %1!ws! error %2!d!\n",
  308. KeyName,
  309. Status);
  310. goto FnExit;
  311. } else {
  312. ClRtlLogPrint(LOG_UNUSUAL,
  313. "[CP] CpAddRegistryCheckpoint created new key %1!ws! for checkpointing.\n",
  314. KeyName);
  315. }
  316. }
  317. //
  318. // Chittur Subbaraman (chitturs) - 2/26/99
  319. //
  320. // Make sure the key can be opened. Else, bail out.
  321. //
  322. Status = RegOpenKeyW(HKEY_LOCAL_MACHINE,
  323. KeyName,
  324. &hKeyOpen);
  325. if ( Status != ERROR_SUCCESS ) {
  326. ClRtlLogPrint(LOG_CRITICAL,
  327. "[CP] CpAddRegistryCheckpoint Could not open key %1!ws! error %2!d!\n",
  328. KeyName,
  329. Status);
  330. goto FnExit;
  331. }
  332. if ( hKeyOpen != NULL ) {
  333. RegCloseKey( hKeyOpen );
  334. }
  335. //
  336. // Open up the resource's key
  337. //
  338. ResourceKey = DmOpenKey(DmResourcesKey,
  339. OmObjectId(Resource),
  340. KEY_READ);
  341. if( ResourceKey == NULL ) {
  342. Status = GetLastError();
  343. ClRtlLogPrint(LOG_CRITICAL,
  344. "[CP] CpAddRegistryCheckpoint couldn't open Resource key for %1!ws! error %2!d!\n",
  345. OmObjectName(Resource),
  346. Status);
  347. goto FnExit;
  348. }
  349. //
  350. // Open up the RegSync key
  351. //
  352. RegSyncKey = DmCreateKey(ResourceKey,
  353. L"RegSync",
  354. 0,
  355. KEY_READ | KEY_WRITE,
  356. NULL,
  357. &Disposition);
  358. DmCloseKey(ResourceKey);
  359. if (RegSyncKey == NULL) {
  360. Status = GetLastError();
  361. ClRtlLogPrint(LOG_CRITICAL,
  362. "[CP] CpAddRegistryCheckpoint couldn't create RegSync key for %1!ws! error %2!d!\n",
  363. OmObjectName(Resource),
  364. Status);
  365. goto FnExit;
  366. }
  367. if (Disposition == REG_OPENED_EXISTING_KEY) {
  368. //
  369. // Enumerate all the other values to make sure this key is
  370. // not already registered.
  371. //
  372. Context.Found = FALSE;
  373. Context.KeyName = KeyName;
  374. DmEnumValues(RegSyncKey,
  375. CppAddCheckpointCallback,
  376. &Context);
  377. if (Context.Found) {
  378. //
  379. // This checkpoint already exists.
  380. //
  381. ClRtlLogPrint(LOG_UNUSUAL,
  382. "[CP] CpAddRegistryCheckpoint failing attempt to add duplicate checkpoint for %1!ws!\n",
  383. KeyName);
  384. Status = ERROR_ALREADY_EXISTS;
  385. goto FnExit;
  386. }
  387. //
  388. // Now we need to find a unique checkpoint ID for this registry subtree.
  389. // Start at 1 and keep trying value names until we get to one that does
  390. // not already exist.
  391. //
  392. for (Id=1; ; Id++) {
  393. DWORD dwType;
  394. DWORD cbData;
  395. wsprintfW(IdName,L"%08lx",Id);
  396. cbData = 0;
  397. Status = DmQueryValue(RegSyncKey,
  398. IdName,
  399. &dwType,
  400. NULL,
  401. &cbData);
  402. if (Status == ERROR_FILE_NOT_FOUND) {
  403. //
  404. // Found a free ID.
  405. //
  406. break;
  407. }
  408. }
  409. } else {
  410. //
  411. // The key was just created, so this must be the only checkpoint
  412. // that exists.
  413. //
  414. Id = 1;
  415. wsprintfW(IdName, L"%08lx",Id);
  416. }
  417. ClRtlLogPrint(LOG_NOISE,
  418. "[CP] CpAddRegistryCheckpoint creating new checkpoint id %1!d! for subtree %2!ws!\n",
  419. Id,
  420. KeyName);
  421. Status = DmSetValue(RegSyncKey,
  422. IdName,
  423. REG_SZ,
  424. (CONST BYTE *)KeyName,
  425. (lstrlenW(KeyName)+1)*sizeof(WCHAR));
  426. if (Status != ERROR_SUCCESS) {
  427. ClRtlLogPrint(LOG_CRITICAL,
  428. "[CP] CpAddRegistryCheckpoint failed to create new checkpoint id %1!d! error %2!d!\n",
  429. Id,
  430. KeyName);
  431. goto FnExit;
  432. }
  433. RetryCheckpoint:
  434. //
  435. // Take the initial checkpoint
  436. //
  437. Status = CppCheckpoint(Resource,
  438. hKey,
  439. Id,
  440. KeyName);
  441. //this may fail due to quorum resource being offline
  442. // we could do one of two things here, wait for quorum resource to
  443. // come online or retry
  444. // we retry as this may be called from the online routines of a
  445. //resource and we dont want to add any circular waits
  446. if ((Status == ERROR_ACCESS_DENIED) ||
  447. (Status == ERROR_INVALID_FUNCTION) ||
  448. (Status == ERROR_NOT_READY) ||
  449. (Status == RPC_X_INVALID_PIPE_OPERATION) ||
  450. (Status == ERROR_BUSY) ||
  451. (Status == ERROR_SWAPERROR))
  452. {
  453. if (Count--)
  454. {
  455. Sleep(1000);
  456. goto RetryCheckpoint;
  457. }
  458. #if DBG
  459. else
  460. {
  461. if (IsDebuggerPresent())
  462. DebugBreak();
  463. }
  464. #endif
  465. }
  466. if (Status != ERROR_SUCCESS) {
  467. ClRtlLogPrint(LOG_CRITICAL,
  468. "[CP] CpAddRegistryCheckpoint failed to take initial checkpoint for %1!ws! error %2!d!\n",
  469. KeyName,
  470. Status);
  471. goto FnExit;
  472. }
  473. //
  474. // If the resource is currently online, add this to the list of subtree notifications
  475. //
  476. State = FmGetResourceState(Resource, NULL, NULL);
  477. if ((State == ClusterResourceOnline) ||
  478. (State == ClusterResourceOnlinePending)) {
  479. Status = CppRegisterNotify(Resource,
  480. KeyName,
  481. Id);
  482. if (Status != ERROR_SUCCESS) {
  483. ClRtlLogPrint(LOG_CRITICAL,
  484. "[CP] CpAddRegistryCheckpoint - CppRegisterNotify failed for key %1!ws! %1!d!\n",
  485. KeyName,
  486. Status);
  487. }
  488. }
  489. FnExit:
  490. if (RegSyncKey) DmCloseKey(RegSyncKey);
  491. if (hKey) RegCloseKey(hKey);
  492. return(Status);
  493. }
  494. BOOL
  495. CppAddCheckpointCallback(
  496. IN LPWSTR ValueName,
  497. IN LPVOID ValueData,
  498. IN DWORD ValueType,
  499. IN DWORD ValueSize,
  500. IN PCPP_ADD_CONTEXT Context
  501. )
  502. /*++
  503. Routine Description:
  504. Value enumeration callback for adding a new registry
  505. checkpoint subtrees. This is only used to see if the specified
  506. registry subtree is already being watched.
  507. Arguments:
  508. ValueName - Supplies the name of the value (this is the checkpoint ID)
  509. ValueData - Supplies the value data (this is the registry subtree)
  510. ValueType - Supplies the value type (must be REG_SZ)
  511. ValueSize - Supplies the size of ValueData
  512. Context - Supplies the callback context
  513. Return Value:
  514. TRUE to continue enumeration
  515. FALSE if a match is found and enumeration should be stopped
  516. --*/
  517. {
  518. if (lstrcmpiW(ValueData, Context->KeyName) == 0) {
  519. //
  520. // Found a match
  521. //
  522. Context->Found = TRUE;
  523. return(FALSE);
  524. }
  525. return(TRUE);
  526. }
  527. DWORD
  528. CpDeleteRegistryCheckpoint(
  529. IN PFM_RESOURCE Resource,
  530. IN LPCWSTR KeyName
  531. )
  532. /*++
  533. Routine Description:
  534. Removes a registry checkpoint from a resource's list.
  535. Arguments:
  536. Resource - supplies the resource the registry checkpoint should be added to.
  537. KeyName - Supplies the name of the registry key (relative to HKEY_LOCAL_MACHINE);
  538. Return Value:
  539. ERROR_SUCCESS if successful
  540. Win32 error code otherwise
  541. --*/
  542. {
  543. CPP_DEL_CONTEXT Context;
  544. HDMKEY ResourceKey;
  545. HDMKEY RegSyncKey;
  546. DWORD Status;
  547. WCHAR ValueId[9];
  548. LPWSTR pszFileName=NULL;
  549. LPWSTR pszDirectoryName=NULL;
  550. CLUSTER_RESOURCE_STATE State;
  551. //
  552. // Open up the resource's key
  553. //
  554. ResourceKey = DmOpenKey(DmResourcesKey,
  555. OmObjectId(Resource),
  556. KEY_READ);
  557. CL_ASSERT(ResourceKey != NULL);
  558. //
  559. // Open up the RegSync key
  560. //
  561. RegSyncKey = DmOpenKey(ResourceKey,
  562. L"RegSync",
  563. KEY_READ | KEY_WRITE);
  564. DmCloseKey(ResourceKey);
  565. if (RegSyncKey == NULL) {
  566. Status = GetLastError();
  567. ClRtlLogPrint(LOG_NOISE,
  568. "[CP] CpDeleteRegistryCheckpoint - couldn't open RegSync key error %1!d!\n",
  569. Status);
  570. return(Status);
  571. }
  572. //
  573. // Enumerate all the values to find this one
  574. //
  575. Context.dwId = 0;
  576. Context.KeyName = KeyName;
  577. DmEnumValues(RegSyncKey,
  578. CppDeleteCheckpointCallback,
  579. &Context);
  580. if (Context.dwId == 0) {
  581. //
  582. // The specified tree was not found.
  583. //
  584. DmCloseKey(RegSyncKey);
  585. return(ERROR_FILE_NOT_FOUND);
  586. }
  587. wsprintfW(ValueId,L"%08lx",Context.dwId);
  588. Status = DmDeleteValue(RegSyncKey, ValueId);
  589. DmCloseKey(RegSyncKey);
  590. if (Status != ERROR_SUCCESS) {
  591. ClRtlLogPrint(LOG_CRITICAL,
  592. "[CP] CpDeleteRegistryCheckpoint - couldn't delete value %1!ws! error %2!d!\n",
  593. ValueId,
  594. Status);
  595. return(Status);
  596. }
  597. //delete the file corresponding to this checkpoint
  598. Status = CpDeleteCheckpointFile(Resource, Context.dwId, NULL);
  599. if (Status != ERROR_SUCCESS) {
  600. ClRtlLogPrint(LOG_CRITICAL,
  601. "[CP] CpDeleteRegistryCheckpoint - couldn't delete checkpoint file , error %1!d!\n",
  602. Status);
  603. return(Status);
  604. }
  605. //
  606. // Now remove the checkpoint from our watcher list
  607. //
  608. State = FmGetResourceState(Resource, NULL, NULL);
  609. if ((State == ClusterResourceOnline) ||
  610. (State == ClusterResourceOnlinePending)) {
  611. Status = CppRundownCheckpointById(Resource, Context.dwId);
  612. }
  613. return(Status);
  614. }
  615. DWORD
  616. CpRemoveResourceCheckpoints(
  617. IN PFM_RESOURCE Resource
  618. )
  619. /*++
  620. Routine Description:
  621. This is called when a resource is deleted to remove all the checkpoints
  622. and the related stuff in the registry.
  623. Arguments:
  624. Resource - supplies the resource the registry checkpoint should be added to.
  625. KeyName - Supplies the name of the registry key (relative to HKEY_LOCAL_MACHINE);
  626. Return Value:
  627. ERROR_SUCCESS if successful
  628. Win32 error code otherwise
  629. --*/
  630. {
  631. DWORD Status;
  632. //delete all the checkpoints corresponding to this resource
  633. Status = CpDeleteCheckpointFile(Resource, 0, NULL);
  634. if (Status != ERROR_SUCCESS)
  635. {
  636. ClRtlLogPrint(LOG_CRITICAL,
  637. "[CP] CpRemoveResourceCheckpoints, CppDeleteCheckpointFile failed %1!d!\n",
  638. Status);
  639. goto FnExit;
  640. }
  641. FnExit:
  642. return(Status);
  643. }
  644. BOOL
  645. CppDeleteCheckpointCallback(
  646. IN LPWSTR ValueName,
  647. IN LPVOID ValueData,
  648. IN DWORD ValueType,
  649. IN DWORD ValueSize,
  650. IN PCPP_DEL_CONTEXT Context
  651. )
  652. /*++
  653. Routine Description:
  654. Value enumeration callback for deleting an old registry
  655. checkpoint subtrees.
  656. Arguments:
  657. ValueName - Supplies the name of the value (this is the checkpoint ID)
  658. ValueData - Supplies the value data (this is the registry subtree)
  659. ValueType - Supplies the value type (must be REG_SZ)
  660. ValueSize - Supplies the size of ValueData
  661. Context - Supplies the callback context
  662. Return Value:
  663. TRUE to continue enumeration
  664. FALSE if a match is found and enumeration should be stopped
  665. --*/
  666. {
  667. if (lstrcmpiW(ValueData, Context->KeyName) == 0) {
  668. //
  669. // Found a match
  670. //
  671. Context->dwId = wcstol(ValueName, NULL, 16);
  672. return(FALSE);
  673. }
  674. return(TRUE);
  675. }
  676. DWORD
  677. CpGetRegistryCheckpoints(
  678. IN PFM_RESOURCE Resource,
  679. OUT PUCHAR OutBuffer,
  680. IN DWORD OutBufferSize,
  681. OUT LPDWORD BytesReturned,
  682. OUT LPDWORD Required
  683. )
  684. /*++
  685. Routine Description:
  686. Retrieves a list of the resource's registry checkpoints
  687. Arguments:
  688. Resource - Supplies the resource whose registry checkpoints should be retrieved.
  689. OutBuffer - Supplies a pointer to the output buffer.
  690. OutBufferSize - Supplies the size (in bytes) of the output buffer.
  691. BytesReturned - Returns the number of bytes written to the output buffer.
  692. Required - Returns the number of bytes required. (if the output buffer was insufficient)
  693. Return Value:
  694. ERROR_SUCCESS if successful
  695. Win32 error code otherwise
  696. --*/
  697. {
  698. CPP_GET_CONTEXT Context;
  699. HDMKEY ResourceKey;
  700. HDMKEY RegSyncKey;
  701. DWORD Status;
  702. *BytesReturned = 0;
  703. *Required = 0;
  704. //
  705. // Open up the resource's key
  706. //
  707. ResourceKey = DmOpenKey(DmResourcesKey,
  708. OmObjectId(Resource),
  709. KEY_READ);
  710. CL_ASSERT(ResourceKey != NULL);
  711. //
  712. // Open up the RegSync key
  713. //
  714. RegSyncKey = DmOpenKey(ResourceKey,
  715. L"RegSync",
  716. KEY_READ | KEY_WRITE);
  717. DmCloseKey(ResourceKey);
  718. if (RegSyncKey == NULL) {
  719. //
  720. // No reg sync key, therefore there are no subtrees
  721. //
  722. return(ERROR_SUCCESS);
  723. }
  724. Context.Available = OutBufferSize;
  725. Context.Required = 0;
  726. Context.lpOutput = (LPWSTR)OutBuffer;
  727. DmEnumValues(RegSyncKey,
  728. CppGetCheckpointsCallback,
  729. &Context);
  730. DmCloseKey(RegSyncKey);
  731. if (Context.Available < sizeof(WCHAR)) {
  732. Status = ERROR_MORE_DATA;
  733. } else {
  734. if ( (PCHAR)(Context.lpOutput) - OutBuffer ) {
  735. *Context.lpOutput++ = L'\0';
  736. }
  737. Status = ERROR_SUCCESS;
  738. }
  739. if ( Context.Required ) {
  740. *Required = Context.Required + sizeof(WCHAR);
  741. }
  742. //
  743. // If the buffer was large enough for all the data, indicate the
  744. // number of bytes we are returning in the output buffer.
  745. //
  746. if ( OutBufferSize >= *Required ) {
  747. *BytesReturned = (DWORD)((PCHAR)(Context.lpOutput) - OutBuffer);
  748. }
  749. return(Status);
  750. }
  751. BOOL
  752. CppGetCheckpointsCallback(
  753. IN LPWSTR ValueName,
  754. IN LPVOID ValueData,
  755. IN DWORD ValueType,
  756. IN DWORD ValueSize,
  757. IN PCPP_GET_CONTEXT Context
  758. )
  759. /*++
  760. Routine Description:
  761. Value enumeration callback for retrieving all of a resource's
  762. checkpoint subtrees.
  763. Arguments:
  764. ValueName - Supplies the name of the value (this is the checkpoint ID)
  765. ValueData - Supplies the value data (this is the registry subtree)
  766. ValueType - Supplies the value type (must be REG_SZ)
  767. ValueSize - Supplies the size of ValueData
  768. Context - Supplies the callback context
  769. Return Value:
  770. TRUE to continue enumeration
  771. --*/
  772. {
  773. Context->Required += ValueSize;
  774. if (Context->Available >= ValueSize) {
  775. CopyMemory(Context->lpOutput, ValueData, ValueSize);
  776. Context->lpOutput += ValueSize/sizeof(WCHAR);
  777. Context->Available -= ValueSize;
  778. } else {
  779. Context->Available = 0;
  780. }
  781. return(TRUE);
  782. }
  783. DWORD CppSaveCheckpointToFile(
  784. IN HKEY hKey,
  785. IN LPCWSTR KeyName,
  786. IN LPWSTR TempFile)
  787. {
  788. DWORD Status;
  789. Status = DmCreateTempFileName(TempFile);
  790. if (Status != ERROR_SUCCESS) {
  791. CL_UNEXPECTED_ERROR( Status );
  792. TempFile[0] = L'\0';
  793. return(Status);
  794. }
  795. Status = DmGetDatabase(hKey, TempFile);
  796. if (Status != ERROR_SUCCESS)
  797. {
  798. ClRtlLogPrint(LOG_UNUSUAL,
  799. "[CP] CppCheckpoint failed to get registry database %1!ws! to file %2!ws! error %3!d!\n",
  800. KeyName,
  801. TempFile,
  802. Status);
  803. CL_LOGFAILURE(Status);
  804. DeleteFile(TempFile);
  805. TempFile[0] = L'\0';
  806. }
  807. return(Status);
  808. }
  809. DWORD
  810. CppCheckpoint(
  811. IN PFM_RESOURCE Resource,
  812. IN HKEY hKey,
  813. IN DWORD dwId,
  814. IN LPCWSTR KeyName
  815. )
  816. /*++
  817. Routine Description:
  818. Takes a checkpoint of the specified registry key.
  819. Arguments:
  820. Resource - Supplies the resource this is a checkpoint for.
  821. hKey - Supplies the registry subtree to checkpoint
  822. dwId - Supplies the checkpoint ID.
  823. KeyName - Supplies the name of the registry key.
  824. Return Value:
  825. ERROR_SUCCESS if successful
  826. Win32 error code otherwise
  827. --*/
  828. {
  829. DWORD Status;
  830. WCHAR TempFile[MAX_PATH];
  831. Status = CppSaveCheckpointToFile(hKey, KeyName, TempFile);
  832. if (Status == ERROR_SUCCESS)
  833. {
  834. //
  835. // Got a file with the right bits in it. Checkpoint the
  836. // file.
  837. //
  838. Status = CpSaveDataFile(Resource,
  839. dwId,
  840. TempFile,
  841. FALSE);
  842. if (Status != ERROR_SUCCESS) {
  843. ClRtlLogPrint(LOG_CRITICAL,
  844. "[CP] CppCheckpoint - CpSaveData failed %1!d!\n",
  845. Status);
  846. }
  847. }
  848. //if the file was created, delete it
  849. if (TempFile[0] != L'\0')
  850. DeleteFile(TempFile);
  851. return(Status);
  852. }
  853. DWORD
  854. CppInstallDatabase(
  855. IN HKEY hKey,
  856. IN LPWSTR FileName
  857. )
  858. /*++
  859. Routine Description:
  860. Installs a new registry database from a specified file.
  861. Arguments:
  862. hKey - Supplies the registry key where FileName will be installed to.
  863. FileName - The name of the file from which to read the registry database
  864. to install.
  865. Return Value:
  866. ERROR_SUCCESS if the installation completed successfully
  867. Win32 error code otherwise.
  868. --*/
  869. {
  870. DWORD Status;
  871. BOOLEAN WasEnabled;
  872. //
  873. // Install the new registry from the file
  874. //
  875. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  876. &WasEnabled);
  877. if (Status != ERROR_SUCCESS) {
  878. if (Status == STATUS_PRIVILEGE_NOT_HELD) {
  879. ClRtlLogPrint(LOG_CRITICAL,
  880. "[CP] Restore privilege not held by cluster service\n");
  881. } else {
  882. ClRtlLogPrint(LOG_CRITICAL,
  883. "[CP] Attempt to enable restore privilege failed %1!lx!\n",Status);
  884. }
  885. return(Status);
  886. }
  887. Status = RegRestoreKeyW(hKey,
  888. FileName,
  889. REG_FORCE_RESTORE);
  890. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  891. WasEnabled);
  892. if (Status != ERROR_SUCCESS) {
  893. ClRtlLogPrint(LOG_CRITICAL,
  894. "[CP] Error installing registry database from %1!ws!, error %2!u!.\n",
  895. FileName,
  896. Status);
  897. }
  898. return(Status);
  899. }
  900. DWORD
  901. CppDeleteCheckpointFile(
  902. IN PFM_RESOURCE Resource,
  903. IN DWORD dwCheckpointId,
  904. IN OPTIONAL LPCWSTR lpszQuorumPath
  905. )
  906. /*++
  907. Routine Description:
  908. Deletes the checkpoint file corresponding the resource.
  909. This node must be the owner of the quorum resource
  910. Arguments:
  911. PFM_RESOURCE - Supplies the pointer to the resource.
  912. dwCheckpointId - The checkpoint id to be deleted. If 0, all
  913. checkpoints are deleted.
  914. lpszQuorumPath - If specified, the checkpoint file relative
  915. to this path is deleted.
  916. Return Value:
  917. ERROR_SUCCESS if completed successfully
  918. Win32 error code otherwise.
  919. --*/
  920. {
  921. DWORD Status;
  922. HDMKEY ResourceKey;
  923. HDMKEY RegSyncKey;
  924. CP_CALLBACK_CONTEXT Context;
  925. if (dwCheckpointId)
  926. {
  927. Status = CppDeleteFile(Resource, dwCheckpointId, lpszQuorumPath);
  928. }
  929. else
  930. {
  931. HDMKEY ResourceKey;
  932. HDMKEY RegSyncKey;
  933. CP_CALLBACK_CONTEXT Context;
  934. //delete all checkpoints corresponding to this resource
  935. //
  936. // Open up the resource's key
  937. //
  938. ResourceKey = DmOpenKey(DmResourcesKey,
  939. OmObjectId(Resource),
  940. KEY_READ);
  941. CL_ASSERT(ResourceKey != NULL);
  942. //
  943. // Open up the RegSync key
  944. //
  945. RegSyncKey = DmOpenKey(ResourceKey,
  946. L"RegSync",
  947. KEY_READ | KEY_WRITE);
  948. DmCloseKey(ResourceKey);
  949. if (RegSyncKey == NULL)
  950. {
  951. Status = GetLastError();
  952. ClRtlLogPrint(LOG_NOISE,
  953. "[CP] CppDeleteCheckpointFile- couldn't open RegSync key error %1!d!\n",
  954. Status);
  955. goto FnExit;
  956. }
  957. Context.lpszPathName = lpszQuorumPath;
  958. Context.Resource = Resource;
  959. //
  960. // Enumerate all the values and delete them one by one.
  961. //
  962. DmEnumValues(RegSyncKey,
  963. CppRemoveCheckpointFileCallback,
  964. &Context);
  965. }
  966. FnExit:
  967. return(Status);
  968. }
  969. DWORD CppDeleteFile(
  970. IN PFM_RESOURCE Resource,
  971. IN DWORD dwCheckpointId,
  972. IN OPTIONAL LPCWSTR lpszQuorumPath
  973. )
  974. /*++
  975. Routine Description:
  976. Gets the file corresponding to the checkpoint id relative
  977. to the supplied path and deletes it.
  978. Arguments:
  979. PFM_RESOURCE - Supplies the pointer to the resource.
  980. dwCheckpointId - The checkpoint id to be deleted. If 0, all
  981. checkpoints are deleted.
  982. lpszQuorumPath - If specified, the checkpoint file relative
  983. to this path is deleted.
  984. Return Value:
  985. ERROR_SUCCESS if the completed successfully
  986. Win32 error code otherwise.
  987. --*/
  988. {
  989. DWORD Status;
  990. LPWSTR pszFileName=NULL;
  991. LPWSTR pszDirectoryName=NULL;
  992. Status = CppGetCheckpointFile(Resource, dwCheckpointId,
  993. &pszDirectoryName, &pszFileName, lpszQuorumPath, FALSE);
  994. if (Status != ERROR_SUCCESS) {
  995. ClRtlLogPrint(LOG_CRITICAL,
  996. "[CP] CppDeleteFile- couldnt get checkpoint file name, error %1!d!\n",
  997. Status);
  998. goto FnExit;
  999. }
  1000. if (!DeleteFileW(pszFileName))
  1001. {
  1002. Status = GetLastError();
  1003. ClRtlLogPrint(LOG_CRITICAL,
  1004. "[CP] CppDeleteFile - couldn't delete the file %2!ws!, error %1!d!\n",
  1005. Status,
  1006. pszFileName);
  1007. goto FnExit;
  1008. }
  1009. //
  1010. // Now try and delete the directory.
  1011. //
  1012. if (!RemoveDirectoryW(pszDirectoryName))
  1013. {
  1014. //if there is a failure, we still return success
  1015. //because it may not be possible to delete a directory
  1016. //when it is not empty
  1017. ClRtlLogPrint(LOG_UNUSUAL,
  1018. "[CP] CppDeleteFile- unable to remove directory %1!ws!, error %2!d!\n",
  1019. pszDirectoryName,
  1020. GetLastError());
  1021. }
  1022. FnExit:
  1023. if (pszFileName) LocalFree(pszFileName);
  1024. if (pszDirectoryName) LocalFree(pszDirectoryName);
  1025. return(Status);
  1026. }