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.

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