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.

1018 lines
28 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. cpinit.c
  5. Abstract:
  6. Initialization and shutdown code for the Checkpoint Manager (CP)
  7. Author:
  8. John Vert (jvert) 1/14/1997
  9. Revision History:
  10. --*/
  11. #include "cpp.h"
  12. extern PFM_RESOURCE gpQuoResource;
  13. BOOL
  14. CppCopyCheckpointCallback(
  15. IN LPWSTR ValueName,
  16. IN LPVOID ValueData,
  17. IN DWORD ValueType,
  18. IN DWORD ValueSize,
  19. IN PCP_CALLBACK_CONTEXT Context
  20. );
  21. BOOL
  22. CpckCopyCheckpointCallback(
  23. IN LPWSTR ValueName,
  24. IN LPVOID ValueData,
  25. IN DWORD ValueType,
  26. IN DWORD ValueSize,
  27. IN PCP_CALLBACK_CONTEXT Context
  28. );
  29. BOOL
  30. CppEnumResourceCallback(
  31. IN PCP_CALLBACK_CONTEXT pCbContext,
  32. IN PVOID Context2,
  33. IN PFM_RESOURCE Resource,
  34. IN LPCWSTR Name
  35. );
  36. BOOL
  37. CpckEnumResourceCallback(
  38. IN PCP_CALLBACK_CONTEXT pCbContext,
  39. IN PVOID Context2,
  40. IN PFM_RESOURCE Resource,
  41. IN LPCWSTR Name
  42. );
  43. VOID
  44. CppResourceNotify(
  45. IN PVOID Context,
  46. IN PFM_RESOURCE Resource,
  47. IN DWORD NotifyCode
  48. )
  49. /*++
  50. Routine Description:
  51. Resource notification callback for hooking resource state
  52. changes. This allows to to register/deregister our registry
  53. notifications for that resource.
  54. Arguments:
  55. Context - Supplies the context. Not used
  56. Resource - Supplies the resource that is going online or
  57. has been taken offline.
  58. NotifyCode - Supplies the type of notification, either
  59. NOTIFY_RESOURCE_PREONLINE or NOTIFY_RESOURCE_POSTOFFLINE
  60. /NOTIFY_RESOURCE_FAILED.
  61. Return Value:
  62. ERROR_SUCCESS if successful
  63. Win32 error code otherwise
  64. --*/
  65. {
  66. DWORD Status;
  67. ClRtlLogPrint(LOG_NOISE,
  68. "[CP] CppResourceNotify for resource %1!ws!\n",
  69. OmObjectName(Resource));
  70. if ( Resource->QuorumResource ) {
  71. return;
  72. }
  73. if (NotifyCode == NOTIFY_RESOURCE_PREONLINE) {
  74. //
  75. // If you are running in fix quorum mode and the quorum resource is offline, then there
  76. // is really no point attempting to restore the checkpoints since you are doomed to
  77. // fail accessing the quorum.
  78. //
  79. if ( ( CsNoQuorum ) && ( gpQuoResource->State == ClusterResourceOffline ) ) return;
  80. //
  81. // Restore any checkpointed registry state for this resource
  82. // This will also start the registry notification thread.
  83. //
  84. Resource->CheckpointState = 0;
  85. Status = CppWatchRegistry(Resource);
  86. if (Status != ERROR_SUCCESS) {
  87. ClRtlLogPrint(LOG_CRITICAL,
  88. "[CP] CppWatchRegistry for resource %1!ws! failed %2!d!\n",
  89. OmObjectName(Resource),
  90. Status);
  91. }
  92. Status = CpckReplicateCryptoKeys(Resource);
  93. if (Status != ERROR_SUCCESS) {
  94. ClRtlLogPrint(LOG_CRITICAL,
  95. "[CP] CpckReplicateCryptoKeys for resource %1!ws! failed %2!d!\n",
  96. OmObjectName(Resource),
  97. Status);
  98. }
  99. } else {
  100. CL_ASSERT(NotifyCode == NOTIFY_RESOURCE_POSTOFFLINE ||
  101. NotifyCode == NOTIFY_RESOURCE_FAILED);
  102. //
  103. // Remove any posted registry notification for this resource
  104. //
  105. Status = CppRundownCheckpoints(Resource);
  106. if (Status != ERROR_SUCCESS) {
  107. ClRtlLogPrint(LOG_CRITICAL,
  108. "[CP] CppUnWatchRegistry for resource %1!ws! failed %2!d!\n",
  109. OmObjectName(Resource),
  110. Status);
  111. }
  112. }
  113. }
  114. DWORD
  115. CpInitialize(
  116. VOID
  117. )
  118. /*++
  119. Routine Description:
  120. Initializes the checkpoint manager
  121. Arguments:
  122. None
  123. Return Value:
  124. ERROR_SUCCESS if successful
  125. Win32 error code otherwise
  126. --*/
  127. {
  128. DWORD Status;
  129. InitializeCriticalSection(&CppNotifyLock);
  130. InitializeListHead(&CpNotifyListHead);
  131. //
  132. // Register for resource online/offline notifications
  133. //
  134. Status = OmRegisterTypeNotify(ObjectTypeResource,
  135. NULL,
  136. NOTIFY_RESOURCE_PREONLINE |
  137. NOTIFY_RESOURCE_POSTOFFLINE|
  138. NOTIFY_RESOURCE_FAILED,
  139. CppResourceNotify);
  140. return(ERROR_SUCCESS);
  141. }
  142. DWORD
  143. CpShutdown(
  144. VOID
  145. )
  146. /*++
  147. Routine Description:
  148. Shuts down the Checkpoint Manager
  149. Arguments:
  150. None
  151. Return Value:
  152. ERROR_SUCCESS if successful
  153. Win32 error code otherwise
  154. --*/
  155. {
  156. DeleteCriticalSection(&CppNotifyLock);
  157. return(ERROR_SUCCESS);
  158. }
  159. DWORD
  160. CpCompleteQuorumChange(
  161. IN LPCWSTR lpszOldQuorumPath
  162. )
  163. /*++
  164. Routine Description:
  165. Completes a change of the quorum disk. This involves deleting
  166. all the checkpoint files on the old quorum disk.
  167. Simple algorithm used here is to enumerate all the resources.
  168. For each resource, enumerate all its checkpoints and delete the
  169. checkpoint files.
  170. Arguments:
  171. lpszNewQuorumPath - Supplies the new quorum path.
  172. Return Value:
  173. ERROR_SUCCESS if successful
  174. Win32 error code otherwise
  175. --*/
  176. {
  177. CP_CALLBACK_CONTEXT CbContext;
  178. CbContext.lpszPathName = lpszOldQuorumPath;
  179. OmEnumObjects(ObjectTypeResource,
  180. CppEnumResourceCallback,
  181. (PVOID)&CbContext,
  182. CppRemoveCheckpointFileCallback);
  183. OmEnumObjects(ObjectTypeResource,
  184. CpckEnumResourceCallback,
  185. (PVOID)&CbContext,
  186. CpckRemoveCheckpointFileCallback);
  187. return(ERROR_SUCCESS);
  188. }
  189. DWORD
  190. CpCopyCheckpointFiles(
  191. IN LPCWSTR lpszPathName,
  192. IN BOOL IsChangeFileAttribute
  193. )
  194. /*++
  195. Routine Description:
  196. Copies all the checkpoint files from the quorum disk to the supplied
  197. directory path. This function is invoked whenever the quorum disk
  198. changes or when the user wants to make a backup of the cluster DB
  199. on the quorum disk.
  200. Simple algorithm used here is to enumerate all the resources.
  201. For each resource, enumerate all its checkpoints and copy the
  202. checkpoint files from the quorum disk to the supplied path.
  203. Arguments:
  204. lpszPathName - Supplies the destination path name.
  205. Return Value:
  206. ERROR_SUCCESS if successful
  207. Win32 error code otherwise
  208. --*/
  209. {
  210. CP_CALLBACK_CONTEXT CbContext;
  211. CbContext.lpszPathName = lpszPathName;
  212. CbContext.IsChangeFileAttribute = IsChangeFileAttribute;
  213. OmEnumObjects(ObjectTypeResource,
  214. CppEnumResourceCallback,
  215. (PVOID)&CbContext,
  216. CppCopyCheckpointCallback);
  217. OmEnumObjects(ObjectTypeResource,
  218. CpckEnumResourceCallback,
  219. (PVOID)&CbContext,
  220. CpckCopyCheckpointCallback);
  221. return(ERROR_SUCCESS);
  222. }
  223. BOOL
  224. CppEnumResourceCallback(
  225. IN PCP_CALLBACK_CONTEXT pCbContext,
  226. IN PENUM_VALUE_CALLBACK lpValueEnumRoutine,
  227. IN PFM_RESOURCE Resource,
  228. IN LPCWSTR Name
  229. )
  230. /*++
  231. Routine Description:
  232. Resource enumeration callback for copying or deleting checkpoints
  233. when the quorum resource changes or when the user is making
  234. a backup of the cluster DB on the quorum disk.
  235. Arguments:
  236. lpszPathName - Supplies the new quorum path to be passed to lpValueEnumRoutine.
  237. lpValueEnumRoutine - Supplies the value enumeration callback to
  238. be called if checkpoints exist.
  239. Resource - Supplies the resource object.
  240. Name - Supplies the resource name
  241. Return Value:
  242. TRUE to continue enumeration
  243. --*/
  244. {
  245. DWORD Status;
  246. HDMKEY ResourceKey;
  247. HDMKEY RegSyncKey;
  248. CP_CALLBACK_CONTEXT Context;
  249. //
  250. // Open up the resource's key
  251. //
  252. ResourceKey = DmOpenKey(DmResourcesKey,
  253. OmObjectId(Resource),
  254. KEY_READ);
  255. if (ResourceKey != NULL) {
  256. //
  257. // Open up the RegSync key
  258. //
  259. RegSyncKey = DmOpenKey(ResourceKey,
  260. L"RegSync",
  261. KEY_READ);
  262. DmCloseKey(ResourceKey);
  263. if (RegSyncKey != NULL) {
  264. Context.lpszPathName = pCbContext->lpszPathName;
  265. Context.Resource = Resource;
  266. Context.IsChangeFileAttribute = pCbContext->IsChangeFileAttribute;
  267. DmEnumValues(RegSyncKey,
  268. lpValueEnumRoutine,
  269. &Context);
  270. DmCloseKey(RegSyncKey);
  271. }
  272. }
  273. return(TRUE);
  274. }
  275. BOOL
  276. CppCopyCheckpointCallback(
  277. IN LPWSTR ValueName,
  278. IN LPVOID ValueData,
  279. IN DWORD ValueType,
  280. IN DWORD ValueSize,
  281. IN PCP_CALLBACK_CONTEXT Context
  282. )
  283. /*++
  284. Routine Description:
  285. Registry value enumeration callback used when the quorum resource
  286. is changing or when the user is making a backup of the cluster DB
  287. on the quorum disk. Copies the specified checkpoint file from the
  288. current quorum directory to the supplied path (in the Context parameter).
  289. Arguments:
  290. ValueName - Supplies the name of the value (this is the checkpoint ID)
  291. ValueData - Supplies the value data (this is the registry subtree)
  292. ValueType - Supplies the value type (must be REG_SZ)
  293. ValueSize - Supplies the size of ValueData
  294. Context - Supplies the quorum change context (new path and resource)
  295. Return Value:
  296. TRUE to continue enumeration
  297. --*/
  298. {
  299. WCHAR OldCheckpointFile[MAX_PATH+1];
  300. LPWSTR NewCheckpointDir;
  301. LPWSTR NewCheckpointFile;
  302. DWORD Status;
  303. DWORD Id;
  304. Id = wcstol(ValueName, NULL, 16);
  305. if (Id == 0) {
  306. ClRtlLogPrint(LOG_UNUSUAL,
  307. "[CP] CppCopyCheckpointCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  308. ValueName,
  309. OmObjectName(Context->Resource));
  310. return(TRUE);
  311. }
  312. //
  313. // Get a temporary file name for saving the old checkpoint file
  314. //
  315. Status = DmCreateTempFileName(OldCheckpointFile);
  316. if (Status != ERROR_SUCCESS) {
  317. ClRtlLogPrint(LOG_CRITICAL,
  318. "[CP] CppCopyCheckpointCallback - DmCreateTempFileName for old file failed with status %1!d! for resource %2!ws!...\n",
  319. Status,
  320. OmObjectName(Context->Resource));
  321. return(TRUE);
  322. }
  323. //
  324. // Get the old checkpoint file from the node hosting the quorum resource
  325. //
  326. Status = CpGetDataFile(Context->Resource,
  327. Id,
  328. OldCheckpointFile,
  329. FALSE);
  330. if (Status != ERROR_SUCCESS) {
  331. ClRtlLogPrint(LOG_CRITICAL,
  332. "[CP] CppCopyCheckpointCallback - CpGetDataFile for checkpoint ID %2!d! failed with status %1!d! for resource %3!ws!...\n",
  333. Status,
  334. Id,
  335. OmObjectName(Context->Resource));
  336. return(TRUE);
  337. }
  338. //
  339. // Get the new checkpoint file and directory
  340. //
  341. Status = CppGetCheckpointFile(Context->Resource,
  342. Id,
  343. &NewCheckpointDir,
  344. &NewCheckpointFile,
  345. Context->lpszPathName,
  346. FALSE);
  347. if (Status != ERROR_SUCCESS) {
  348. ClRtlLogPrint(LOG_CRITICAL,
  349. "[CP] CppCopyCheckpointCallback - CppGetCheckpointFile for new file failed %1!d!\n",
  350. Status);
  351. return(TRUE);
  352. }
  353. //
  354. // If necessary, try to change the file attributes to NORMAL
  355. //
  356. if (Context->IsChangeFileAttribute == TRUE) {
  357. QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_NORMAL);
  358. QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_NORMAL);
  359. }
  360. //
  361. // Create the new directory.
  362. //
  363. if (!QfsCreateDirectory(NewCheckpointDir, NULL)) {
  364. Status = GetLastError();
  365. if (Status != ERROR_ALREADY_EXISTS) {
  366. ClRtlLogPrint(LOG_CRITICAL,
  367. "[CP] CppCopyCheckpointCallback unable to create directory %1!ws!, error %2!d!\n",
  368. NewCheckpointDir,
  369. Status);
  370. LocalFree(NewCheckpointFile);
  371. LocalFree(NewCheckpointDir);
  372. return(TRUE);
  373. }
  374. Status = ERROR_SUCCESS;
  375. }
  376. //
  377. // Copy the old file to the new file
  378. //
  379. if (!QfsClRtlCopyFileAndFlushBuffers(OldCheckpointFile, NewCheckpointFile)) {
  380. Status = GetLastError();
  381. ClRtlLogPrint(LOG_CRITICAL,
  382. "[CP] CppCopyCheckpointCallback unable to copy file %1!ws! to %2!ws!, error %3!d!\n",
  383. OldCheckpointFile,
  384. NewCheckpointFile,
  385. Status);
  386. }
  387. //
  388. // If necessary, change the file attributes to READONLY
  389. //
  390. if ((Status == ERROR_SUCCESS) && (Context->IsChangeFileAttribute == TRUE)) {
  391. if (!QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_READONLY)
  392. ||
  393. !QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_READONLY)) {
  394. Status = GetLastError();
  395. ClRtlLogPrint(LOG_CRITICAL,
  396. "[CP] CppCopyCheckpointCallback unable to change file attributes in %1!ws!, error %2!d!\n",
  397. NewCheckpointDir,
  398. Status);
  399. }
  400. }
  401. LocalFree(NewCheckpointFile);
  402. LocalFree(NewCheckpointDir);
  403. return(TRUE);
  404. }
  405. BOOL
  406. CppRemoveCheckpointFileCallback(
  407. IN LPWSTR ValueName,
  408. IN LPVOID ValueData,
  409. IN DWORD ValueType,
  410. IN DWORD ValueSize,
  411. IN PCP_CALLBACK_CONTEXT Context
  412. )
  413. /*++
  414. Routine Description:
  415. Registry value enumeration callback used when the quorum resource
  416. is changing. Deletes the specified checkpoint file from the old
  417. quorum directory.
  418. Arguments:
  419. ValueName - Supplies the name of the value (this is the checkpoint ID)
  420. ValueData - Supplies the value data (this is the registry subtree)
  421. ValueType - Supplies the value type (must be REG_SZ)
  422. ValueSize - Supplies the size of ValueData
  423. Context - Supplies the quorum change context (old path and resource)
  424. Return Value:
  425. TRUE to continue enumeration
  426. --*/
  427. {
  428. DWORD Status;
  429. DWORD Id;
  430. Id = wcstol(ValueName, NULL, 16);
  431. if (Id == 0) {
  432. ClRtlLogPrint(LOG_UNUSUAL,
  433. "[CP] CppRemoveCheckpointFileCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  434. ValueName,
  435. OmObjectName(Context->Resource));
  436. return(TRUE);
  437. }
  438. Status = CppDeleteFile(Context->Resource, Id, Context->lpszPathName);
  439. return(TRUE);
  440. }
  441. BOOL
  442. CpckEnumResourceCallback(
  443. IN PCP_CALLBACK_CONTEXT pCbContext,
  444. IN PENUM_VALUE_CALLBACK lpValueEnumRoutine,
  445. IN PFM_RESOURCE Resource,
  446. IN LPCWSTR Name
  447. )
  448. /*++
  449. Routine Description:
  450. Resource enumeration callback for copying or deleting crypto checkpoints
  451. when the quorum resource changes or when the user is making
  452. a backup of the cluster DB on the quorum disk.
  453. Arguments:
  454. lpszPathName - Supplies the new quorum path to be passed to lpValueEnumRoutine.
  455. lpValueEnumRoutine - Supplies the value enumeration callback to
  456. be called if checkpoints exist.
  457. Resource - Supplies the resource object.
  458. Name - Supplies the resource name
  459. Return Value:
  460. TRUE to continue enumeration
  461. --*/
  462. {
  463. DWORD Status;
  464. HDMKEY ResourceKey;
  465. HDMKEY CryptoSyncKey;
  466. CP_CALLBACK_CONTEXT Context;
  467. //
  468. // Open up the resource's key
  469. //
  470. ResourceKey = DmOpenKey(DmResourcesKey,
  471. OmObjectId(Resource),
  472. KEY_READ);
  473. if (ResourceKey != NULL) {
  474. //
  475. // Open up the CryptoSyncKey key
  476. //
  477. CryptoSyncKey = DmOpenKey(ResourceKey,
  478. L"CryptoSync",
  479. KEY_READ);
  480. DmCloseKey(ResourceKey);
  481. if (CryptoSyncKey != NULL) {
  482. Context.lpszPathName = pCbContext->lpszPathName;
  483. Context.Resource = Resource;
  484. Context.IsChangeFileAttribute = pCbContext->IsChangeFileAttribute;
  485. DmEnumValues(CryptoSyncKey,
  486. lpValueEnumRoutine,
  487. &Context);
  488. DmCloseKey(CryptoSyncKey);
  489. }
  490. }
  491. return(TRUE);
  492. }
  493. BOOL
  494. CpckCopyCheckpointCallback(
  495. IN LPWSTR ValueName,
  496. IN LPVOID ValueData,
  497. IN DWORD ValueType,
  498. IN DWORD ValueSize,
  499. IN PCP_CALLBACK_CONTEXT Context
  500. )
  501. /*++
  502. Routine Description:
  503. Crypto key enumeration callback used when the quorum resource
  504. is changing or when the user is making a backup of the cluster DB
  505. on the quorum disk. Copies the specified checkpoint file from the
  506. current quorum directory to the supplied path (in the Context parameter).
  507. Arguments:
  508. ValueName - Supplies the name of the value (this is the checkpoint ID)
  509. ValueData - Supplies the value data (this is the crypto info)
  510. ValueType - Supplies the value type (must be REG_BINARY)
  511. ValueSize - Supplies the size of ValueData
  512. Context - Supplies the quorum change context (new path and resource)
  513. Return Value:
  514. TRUE to continue enumeration
  515. --*/
  516. {
  517. WCHAR OldCheckpointFile[MAX_PATH+1];
  518. LPWSTR NewCheckpointDir;
  519. LPWSTR NewCheckpointFile;
  520. DWORD Status;
  521. DWORD Id;
  522. Id = wcstol(ValueName, NULL, 16);
  523. if (Id == 0) {
  524. ClRtlLogPrint(LOG_UNUSUAL,
  525. "[CPCK] CpckCopyCheckpointCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  526. ValueName,
  527. OmObjectName(Context->Resource));
  528. return(TRUE);
  529. }
  530. //
  531. // Get a temporary file name for saving the old checkpoint file
  532. //
  533. Status = DmCreateTempFileName(OldCheckpointFile);
  534. if (Status != ERROR_SUCCESS) {
  535. ClRtlLogPrint(LOG_CRITICAL,
  536. "[CP] CpckCopyCheckpointCallback - DmCreateTempFileName for old file failed with status %1!d! for resource %2!ws!...\n",
  537. Status,
  538. OmObjectName(Context->Resource));
  539. return(TRUE);
  540. }
  541. //
  542. // Get the old checkpoint file from the node hosting the quorum resource
  543. //
  544. Status = CpGetDataFile(Context->Resource,
  545. Id,
  546. OldCheckpointFile,
  547. TRUE);
  548. if (Status != ERROR_SUCCESS) {
  549. ClRtlLogPrint(LOG_CRITICAL,
  550. "[CP] CpckCopyCheckpointCallback - CpGetDataFile for checkpoint ID %2!d! failed with status %1!d! for resource %3!ws!...\n",
  551. Status,
  552. Id,
  553. OmObjectName(Context->Resource));
  554. return(TRUE);
  555. }
  556. //
  557. // Get the new checkpoint file and directory
  558. //
  559. Status = CppGetCheckpointFile(Context->Resource,
  560. Id,
  561. &NewCheckpointDir,
  562. &NewCheckpointFile,
  563. Context->lpszPathName,
  564. TRUE);
  565. if (Status != ERROR_SUCCESS) {
  566. ClRtlLogPrint(LOG_CRITICAL,
  567. "[CPCK] CpckCopyCheckpointCallback - CppGetCheckpointFile for new file failed %1!d!\n",
  568. Status);
  569. return(TRUE);
  570. }
  571. //
  572. // If necessary, try to change the file attributes to NORMAL
  573. //
  574. if (Context->IsChangeFileAttribute == TRUE) {
  575. QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_NORMAL);
  576. QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_NORMAL);
  577. }
  578. //
  579. // Create the new directory.
  580. //
  581. if (!QfsCreateDirectory(NewCheckpointDir, NULL)) {
  582. Status = GetLastError();
  583. if (Status != ERROR_ALREADY_EXISTS) {
  584. ClRtlLogPrint(LOG_CRITICAL,
  585. "[CPCK] CpckCopyCheckpointCallback unable to create directory %1!ws!, error %2!d!\n",
  586. NewCheckpointDir,
  587. Status);
  588. LocalFree(NewCheckpointFile);
  589. LocalFree(NewCheckpointDir);
  590. return(TRUE);
  591. }
  592. Status = ERROR_SUCCESS;
  593. }
  594. //
  595. // Copy the old file to the new file
  596. //
  597. if (!QfsClRtlCopyFileAndFlushBuffers(OldCheckpointFile, NewCheckpointFile)) {
  598. Status = GetLastError();
  599. ClRtlLogPrint(LOG_CRITICAL,
  600. "[CPCK] CpckCopyCheckpointCallback unable to copy file %1!ws! to %2!ws!, error %3!d!\n",
  601. OldCheckpointFile,
  602. NewCheckpointFile,
  603. Status);
  604. }
  605. //
  606. // If necessary, change the file attributes to READONLY
  607. //
  608. if ((Status == ERROR_SUCCESS) && (Context->IsChangeFileAttribute == TRUE)) {
  609. if (!QfsSetFileAttributes(NewCheckpointFile, FILE_ATTRIBUTE_READONLY)
  610. ||
  611. !QfsSetFileAttributes(NewCheckpointDir, FILE_ATTRIBUTE_READONLY)) {
  612. Status = GetLastError();
  613. ClRtlLogPrint(LOG_CRITICAL,
  614. "[CPCK] CpckCopyCheckpointCallback unable to change file attributes in %1!ws!, error %2!d!\n",
  615. NewCheckpointDir,
  616. Status);
  617. }
  618. }
  619. LocalFree(NewCheckpointFile);
  620. LocalFree(NewCheckpointDir);
  621. return(TRUE);
  622. }
  623. /****
  624. @func DWORD | CpRestoreCheckpointFiles | Create a directory if necessary
  625. and copy all the resource checkpoint files from the backup
  626. directory to the quorum disk
  627. @parm IN LPWSTR | lpszSourcePathName | The name of the source path
  628. where the files are backed up.
  629. @parm IN LPWSTR | lpszSubDirName | The name of the sub-directory under
  630. the source path which can be a possible candidate for
  631. containing the resource checkpoint files.
  632. @parm IN LPCWSTR | lpszQuoLogPathName | The name of the quorum disk
  633. path where the files will be restored.
  634. @rdesc Returns a Win32 error code on failure. ERROR_SUCCESS on success.
  635. @xref <f DmpRestoreClusterDatabase>
  636. ****/
  637. DWORD CpRestoreCheckpointFiles(
  638. IN LPWSTR lpszSourcePathName,
  639. IN LPWSTR lpszSubDirName,
  640. IN LPCWSTR lpszQuoLogPathName )
  641. {
  642. LPWSTR szSourcePathName = NULL;
  643. LPWSTR szSourceFileName = NULL;
  644. WCHAR szDestPathName[MAX_PATH];
  645. WCHAR szDestFileName[MAX_PATH];
  646. DWORD dwLen;
  647. QfsHANDLE hFindFile = QfsINVALID_HANDLE_VALUE;
  648. WIN32_FIND_DATA FindData;
  649. WCHAR szTempCpFileNameExtn[10];
  650. DWORD status;
  651. //
  652. // Chittur Subbaraman (chitturs) - 10/20/98
  653. //
  654. dwLen = lstrlenW( lpszSourcePathName );
  655. dwLen += lstrlenW( lpszSubDirName );
  656. //
  657. // It is safer to use dynamic memory allocation for user-supplied
  658. // path since we don't want to put restrictions on the user
  659. // on the length of the path that can be supplied. However, as
  660. // far as our own quorum disk path is concerned, it is system-dependent
  661. // and static memory allocation for that would suffice.
  662. //
  663. szSourcePathName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
  664. ( dwLen + 15 ) *
  665. sizeof ( WCHAR ) );
  666. if ( szSourcePathName == NULL )
  667. {
  668. status = GetLastError();
  669. ClRtlLogPrint(LOG_NOISE,
  670. "[CP] CpRestoreCheckpointFiles: Error %1!d! in allocating memory for %2!ws! !!!\n",
  671. status,
  672. lpszSourcePathName);
  673. CL_LOGFAILURE( status );
  674. goto FnExit;
  675. }
  676. lstrcpyW( szSourcePathName, lpszSourcePathName );
  677. lstrcatW( szSourcePathName, lpszSubDirName );
  678. if ( szSourcePathName[dwLen-1] != L'\\' )
  679. {
  680. szSourcePathName[dwLen++] = L'\\';
  681. szSourcePathName[dwLen] = L'\0';
  682. }
  683. mbstowcs ( szTempCpFileNameExtn, "*.CP*", 6 );
  684. lstrcatW ( szSourcePathName, szTempCpFileNameExtn );
  685. //
  686. // Try to find the first file in the directory
  687. //
  688. hFindFile = QfsFindFirstFile( szSourcePathName, &FindData );
  689. //
  690. // Reuse the source path name variable
  691. //
  692. szSourcePathName[dwLen] = L'\0';
  693. if ( !QfsIsHandleValid( hFindFile ) )
  694. {
  695. status = GetLastError();
  696. if ( status != ERROR_FILE_NOT_FOUND )
  697. {
  698. ClRtlLogPrint(LOG_NOISE,
  699. "[CP] CpRestoreCheckpointFiles: No file can be found in the supplied path %1!ws! Error = %2!%d! !!!\n",
  700. szSourcePathName,
  701. status);
  702. CL_LOGFAILURE( status );
  703. } else
  704. {
  705. status = ERROR_SUCCESS;
  706. }
  707. goto FnExit;
  708. }
  709. dwLen = lstrlenW( szSourcePathName );
  710. szSourceFileName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
  711. ( dwLen + 1 + LOG_MAX_FILENAME_LENGTH ) *
  712. sizeof ( WCHAR ) );
  713. if ( szSourceFileName == NULL )
  714. {
  715. status = GetLastError();
  716. ClRtlLogPrint(LOG_NOISE,
  717. "[CP] CpRestoreCheckpointFiles: Error %1!d! in allocating memory for %2!ws! !!!\n",
  718. status,
  719. szSourcePathName);
  720. CL_LOGFAILURE( status );
  721. goto FnExit;
  722. }
  723. lstrcpyW( szDestPathName, lpszQuoLogPathName );
  724. lstrcatW( szDestPathName, lpszSubDirName );
  725. dwLen = lstrlenW( szDestPathName );
  726. if ( szDestPathName[dwLen-1] != L'\\' )
  727. {
  728. szDestPathName[dwLen++] = L'\\';
  729. szDestPathName[dwLen] = L'\0';
  730. }
  731. //
  732. // Create the new directory, if necessary
  733. //
  734. if ( !QfsCreateDirectory ( szDestPathName, NULL ) )
  735. {
  736. status = GetLastError();
  737. if ( status != ERROR_ALREADY_EXISTS )
  738. {
  739. ClRtlLogPrint(LOG_CRITICAL,
  740. "[CP] CpRestoreCheckpointFiles: Unable to create directory %1!ws!, error %2!d!\n",
  741. szDestPathName,
  742. status);
  743. CL_LOGFAILURE( status );
  744. goto FnExit;
  745. }
  746. }
  747. status = ERROR_SUCCESS;
  748. while ( status == ERROR_SUCCESS )
  749. {
  750. //
  751. // Copy the checkpoint file to the destination
  752. //
  753. lstrcpyW( szSourceFileName, szSourcePathName );
  754. lstrcatW( szSourceFileName, FindData.cFileName );
  755. lstrcpyW( szDestFileName, szDestPathName );
  756. lstrcatW( szDestFileName, FindData.cFileName );
  757. status = QfsCopyFile( szSourceFileName, szDestFileName, FALSE );
  758. if ( !status )
  759. {
  760. status = GetLastError();
  761. ClRtlLogPrint(LOG_UNUSUAL,
  762. "[CP] CpRestoreCheckpointFiles: Unable to copy file %1!ws! to %2!ws!, Error = %3!d!\n",
  763. szSourceFileName,
  764. szDestFileName,
  765. status);
  766. CL_LOGFAILURE( status );
  767. goto FnExit;
  768. }
  769. //
  770. // Set the file attribute to normal. Continue even if you
  771. // fail in this step but log an error.
  772. //
  773. if ( !QfsSetFileAttributes( szDestFileName, FILE_ATTRIBUTE_NORMAL ) )
  774. {
  775. ClRtlLogPrint(LOG_UNUSUAL,
  776. "[CP] CpRestoreCheckpointFiles::Error in changing %1!ws! attribute to NORMAL\n",
  777. szDestFileName);
  778. }
  779. if ( QfsFindNextFile( hFindFile, &FindData ) )
  780. {
  781. status = ERROR_SUCCESS;
  782. } else
  783. {
  784. status = GetLastError();
  785. }
  786. }
  787. if ( status == ERROR_NO_MORE_FILES )
  788. {
  789. status = ERROR_SUCCESS;
  790. } else
  791. {
  792. ClRtlLogPrint(LOG_UNUSUAL,
  793. "[CP] CpRestoreCheckpointFiles: FindNextFile failed !!!\n");
  794. }
  795. FnExit:
  796. LocalFree( szSourcePathName );
  797. LocalFree( szSourceFileName );
  798. QfsFindCloseIfValid( hFindFile );
  799. return(status);
  800. }