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.

1604 lines
51 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. DllUpgd.c
  5. Abstract:
  6. Routines for supporting resource DLL upgrade.
  7. Author:
  8. Chittur Subbaraman (chitturs) 18-March-2001
  9. Revision History:
  10. 18-March-2001 Created
  11. --*/
  12. #include "fmp.h"
  13. //
  14. // Defines used locally within this module
  15. //
  16. #define CLUSTER_RESDLL_BACKUP_FILE_EXTENSION L".~WFPKDLLBKP$"
  17. #define CLUSTER_RESDLL_RENAMED_FILE_EXTENSION L".~WFPKDLLOLD$"
  18. #define CLUSTER_RESDLL_BACKUP_FILES L".~WFPKDLL*$"
  19. DWORD
  20. FmpUpgradeResourceDLL(
  21. IN PFM_RESOURCE pResource,
  22. IN LPWSTR lpszInstallationPath
  23. )
  24. /*++
  25. Routine Description:
  26. Upgrades a resource DLL currently loaded in one or more monitors.
  27. Arguments:
  28. pResource - A resource of the type implemented by the DLL.
  29. lpszInstallationPath - The full installation path of the DLL (including the full DLL name with
  30. extension)
  31. Return Value:
  32. ERROR_SUCCESS on success.
  33. Win32 error code otherwise.
  34. --*/
  35. {
  36. DWORD dwStatus = ERROR_SUCCESS;
  37. LPWSTR lpszNewDllName;
  38. WCHAR szCurrentDllPath[MAX_PATH];
  39. //
  40. // Get the DLL file name from the installation path. Also, get rid of any trailing '\' in
  41. // the supplied path.
  42. //
  43. // IMPORTANT: Note that lpszNewDLLName points into lpszInstallationPath buffer and so
  44. // we should not modify the lpszInstallation path buffer (there is really no reason to
  45. // do that) while we use lpszNewDllName.
  46. //
  47. dwStatus = FmpParsePathForFileName( lpszInstallationPath,
  48. TRUE, // Check for path existence
  49. &lpszNewDllName );
  50. //
  51. // If the parse fails or if the supplied "path" is a filename, bail.
  52. //
  53. if ( ( dwStatus != ERROR_SUCCESS ) || ( lpszNewDllName == NULL ) )
  54. {
  55. ClRtlLogPrint(LOG_CRITICAL,
  56. "[FM] FmpUpgradeResourceDLL: Unable to parse supplied path %1!ws! for file name, Status=%2!u!\n",
  57. (lpszInstallationPath == NULL) ? L"NULL":lpszInstallationPath,
  58. dwStatus);
  59. goto FnExit;
  60. }
  61. ClRtlLogPrint(LOG_NOISE,
  62. "[FM] FmpUpgradeResourceDLL: Installation path %1!ws!, resource [%2!ws!] %3!ws!\n",
  63. lpszInstallationPath,
  64. OmObjectName(pResource),
  65. OmObjectId(pResource));
  66. //
  67. // Validate the supplied parameters. If validation is successful, get the full path of the
  68. // currently loaded DLL.
  69. //
  70. dwStatus = FmpValidateResourceDLLReplacement( pResource,
  71. lpszNewDllName,
  72. szCurrentDllPath );
  73. if ( dwStatus != ERROR_SUCCESS )
  74. {
  75. ClRtlLogPrint(LOG_CRITICAL,
  76. "[FM] FmpUpgradeResourceDLL: Validation for resource DLL replacement failed, Status=%1!u!\n",
  77. dwStatus);
  78. goto FnExit;
  79. }
  80. //
  81. // Acquire the monitor lock so as to serialize one resource DLL upgrade process with
  82. // others as well as with monitor restarts.
  83. //
  84. FmpAcquireMonitorLock();
  85. //
  86. // Now, replace the DLL with the supplied DLL in a recoverable fashion.
  87. //
  88. dwStatus = FmpReplaceResourceDLL( lpszNewDllName,
  89. szCurrentDllPath,
  90. lpszInstallationPath );
  91. if ( dwStatus != ERROR_SUCCESS )
  92. {
  93. ClRtlLogPrint(LOG_CRITICAL,
  94. "[FM] FmpUpgradeResourceDLL: Replacement of resource DLL failed, Status=%1!u!\n",
  95. dwStatus);
  96. goto FnReleaseLockAndExit;
  97. }
  98. //
  99. // Shutdown and restart the monitors that have the resource DLL loaded.
  100. //
  101. dwStatus = FmpRecycleMonitors( lpszNewDllName );
  102. if ( dwStatus != ERROR_SUCCESS )
  103. {
  104. ClRtlLogPrint(LOG_CRITICAL,
  105. "[FM] FmpUpgradeResourceDLL: Recycling of resource DLL failed, Status=%1!u!\n",
  106. dwStatus);
  107. goto FnReleaseLockAndExit;
  108. }
  109. //
  110. // Attempt deletion of backup files in case all the steps are successful so far. Note that
  111. // this attempt is necessary here since it is not possible to delete the .old file
  112. // before we recycle the monitors since the monitors hold references to the DLL.
  113. //
  114. FmpDeleteBackupFiles ( szCurrentDllPath ); // Delete backup files
  115. FnReleaseLockAndExit:
  116. FmpReleaseMonitorLock();
  117. FnExit:
  118. ClRtlLogPrint(LOG_NOISE,
  119. "[FM] FmpUpgradeResourceDLL: Exit with status %1!u!...\n",
  120. dwStatus);
  121. return ( dwStatus );
  122. } // FmpUpgradeResourceDLL
  123. DWORD
  124. FmpParsePathForFileName(
  125. IN LPWSTR lpszPath,
  126. IN BOOL fCheckPathExists,
  127. OUT LPWSTR *ppszFileName
  128. )
  129. /*++
  130. Routine Description:
  131. Get the name of the file at the end of a supplied path.
  132. Arguments:
  133. lpszPath - A path including the file name.
  134. fCheckPathExists - Check if the path exists.
  135. ppszFileName - The name of the file parsed from the path.
  136. Return Value:
  137. ERROR_SUCCESS on success.
  138. Win32 error code otherwise.
  139. Note:
  140. This function will get rid of any trailing '\' in the supplied path. Also, this function
  141. will return a file name only if the input supplied is a valid path, else NULL file name
  142. will be returned.
  143. --*/
  144. {
  145. DWORD dwStatus = ERROR_SUCCESS;
  146. LPWSTR s;
  147. *ppszFileName = NULL;
  148. //
  149. // Check for invalid parameter.
  150. //
  151. if ( lpszPath == NULL )
  152. {
  153. dwStatus = ERROR_INVALID_PARAMETER;
  154. ClRtlLogPrint(LOG_CRITICAL,
  155. "[FM] FmpParsePathForFileName: Input param is NULL, Status=%1!u!\n",
  156. dwStatus);
  157. goto FnExit;
  158. }
  159. //
  160. // Make sure the last character is NULL if it is a '\'. This is to avoid getting confused
  161. // with paths such as C:\windows\cluster\clusres.dll\
  162. //
  163. if ( lpszPath[lstrlen ( lpszPath ) - 1] == L'\\' ) lpszPath[lstrlen ( lpszPath ) - 1] = L'\0';
  164. //
  165. // Parse the supplied path and look for the last occurrence of '\'. If there is no '\' at all,
  166. // may be the caller supplied a file name, bail with NULL out param but with success status.
  167. //
  168. s = wcsrchr( lpszPath, L'\\' );
  169. if ( s == NULL )
  170. {
  171. goto FnExit;
  172. }
  173. //
  174. // If the supplied parameter is a path (as opposed to a plain file name) and the caller
  175. // requested to check for validity, do so.
  176. //
  177. if ( fCheckPathExists && !ClRtlPathFileExists( lpszPath ) )
  178. {
  179. dwStatus = GetLastError();
  180. ClRtlLogPrint(LOG_CRITICAL,
  181. "[FM] FmpParsePathForFileName: Path %1!ws! does not exist, Status=%2!u!\n",
  182. lpszPath,
  183. dwStatus);
  184. goto FnExit;
  185. }
  186. //
  187. // Return the pointer to the char after the last '\'.
  188. //
  189. s++;
  190. *ppszFileName = s;
  191. FnExit:
  192. return ( dwStatus );
  193. }// FmpParsePathForFileName
  194. DWORD
  195. FmpValidateResourceDLLReplacement(
  196. IN PFM_RESOURCE pResource,
  197. IN LPWSTR lpszNewDllName,
  198. OUT LPWSTR lpszCurrentDllPath
  199. )
  200. /*++
  201. Routine Description:
  202. Validate the resource DLL replacement request.
  203. Arguments:
  204. pResource - The resource which is implemeted by the DLL.
  205. lpszNewDllName - The name of the DLL.
  206. lpszCurrentDllPath - The full path of the currently loaded DLL.
  207. Return Value:
  208. ERROR_SUCCESS on success.
  209. Win32 error code otherwise.
  210. --*/
  211. {
  212. DWORD dwStatus = ERROR_SUCCESS;
  213. LPWSTR lpszFileName;
  214. LPWSTR lpszDllName = NULL;
  215. WCHAR szDLLNameOfRes[MAX_PATH];
  216. BOOL fDllPathFound = TRUE;
  217. //
  218. // Get the plain file name from the DLL name stored in the restype structure. Since the
  219. // parse function can potentially get rid of the trailing '\', make a copy of the DLL
  220. // name.
  221. //
  222. //
  223. // IMPORTANT: Do not write stuff into szDllNameOfRes while lpszDllName is being used
  224. // since lpszDllName points inside szDllNameOfRes.
  225. //
  226. lstrcpy( szDLLNameOfRes, pResource->Type->DllName );
  227. dwStatus = FmpParsePathForFileName ( szDLLNameOfRes,
  228. TRUE, // Check for path existence
  229. &lpszDllName );
  230. if ( dwStatus != ERROR_SUCCESS )
  231. {
  232. ClRtlLogPrint(LOG_CRITICAL,
  233. "[FM] FmpValidateResourceDLLReplacement: Unable to parse path %1!ws! for filename, Status %2!u!\n",
  234. szDLLNameOfRes,
  235. dwStatus);
  236. goto FnExit;
  237. }
  238. //
  239. // If the dll information in the resource type structure is a file name, then you need to
  240. // search the path to find the full path of the DLL. Otherwise, you can merely copy the
  241. // information from the resource type structure and expand any environment strings in it.
  242. //
  243. if ( lpszDllName == NULL )
  244. {
  245. lpszDllName = pResource->Type->DllName;
  246. fDllPathFound = FALSE;
  247. } else
  248. {
  249. LPWSTR pszDllName;
  250. //
  251. // Expand any environment variables included in the DLL path name.
  252. //
  253. pszDllName = ClRtlExpandEnvironmentStrings( pResource->Type->DllName );
  254. if ( pszDllName == NULL )
  255. {
  256. dwStatus = GetLastError();
  257. ClRtlLogPrint(LOG_CRITICAL,
  258. "[FM] FmpValidateResourceDLLReplacement: Resource's DLL name %1!ws! cannot be expanded, Status=%2!u!\n",
  259. pResource->Type->DllName,
  260. dwStatus);
  261. goto FnExit;
  262. }
  263. lstrcpy( lpszCurrentDllPath, pszDllName );
  264. LocalFree( pszDllName );
  265. }
  266. if ( lstrcmp( lpszDllName, lpszNewDllName ) != 0 )
  267. {
  268. dwStatus = ERROR_INVALID_PARAMETER;
  269. ClRtlLogPrint(LOG_CRITICAL,
  270. "[FM] FmpValidateResourceDLLReplacement: Resource's DLL name %1!ws! does not match supplied name, Status=%2!u!\n",
  271. lpszDllName,
  272. dwStatus);
  273. goto FnExit;
  274. }
  275. //
  276. // Search all the paths specified in the environment variable and get the full current
  277. // path of the DLL that is loaded into the monitor.
  278. //
  279. if ( ( fDllPathFound == FALSE ) &&
  280. ( !SearchPath ( NULL, // Search all paths as LoadLibrary does
  281. lpszNewDllName, // File name to search for
  282. NULL, // No extension required
  283. MAX_PATH, // Size of out buffer
  284. lpszCurrentDllPath, // Buffer to receive full Dll path with file name
  285. &lpszFileName ) ) ) // Filename at the end of the path
  286. {
  287. dwStatus = GetLastError();
  288. ClRtlLogPrint(LOG_CRITICAL,
  289. "[FM] FmpValidateResourceDLLReplacement: SearchPath API for file %1!ws! failed, Status=%2!u!\n",
  290. lpszNewDllName,
  291. dwStatus);
  292. goto FnExit;
  293. }
  294. ClRtlLogPrint(LOG_NOISE,
  295. "[FM] FmpValidateResourceDLLReplacement: Current resource DLL full path %1!ws!\n",
  296. lpszCurrentDllPath);
  297. FnExit:
  298. return ( dwStatus );
  299. }// FmpValidateResourceDLLReplacement
  300. DWORD
  301. FmpReplaceResourceDLL(
  302. IN LPWSTR lpszNewDllName,
  303. IN LPWSTR lpszCurrentDllPath,
  304. IN LPWSTR lpszInstallationPath
  305. )
  306. /*++
  307. Routine Description:
  308. Replace the resource DLL with the one from the install path.
  309. Arguments:
  310. lpszNewDllName - The name of the DLL.
  311. lpszCurrentDllPath - The full path of the currently loaded DLL.
  312. lpszInstallationPath - The installation path of the DLL.
  313. Return Value:
  314. ERROR_SUCCESS on success.
  315. Win32 error code otherwise.
  316. --*/
  317. {
  318. DWORD dwStatus = ERROR_SUCCESS;
  319. HKEY hClussvcParamsKey = NULL;
  320. DWORD cbListSize = 0, cchLen = 0;
  321. LPWSTR lpmszUpgradeList = NULL;
  322. WCHAR szBakFile[MAX_PATH], szOldFile[MAX_PATH];
  323. WCHAR szClusterDirectory[MAX_PATH];
  324. DWORD dwType, dwLen;
  325. //
  326. //
  327. // This function works as follows. First we make a copy of the existing resource DLL file
  328. // to a file with CLUSTER_RESDLL_BACKUP_FILE_EXTENSION extension. Then we set the registry
  329. // value under the clussvc parameters key to indicate that an upgrade is starting. After
  330. // this, the existing DLL file is renamed. If all steps are successful so far, we copy
  331. // new DLL file from the supplied path. Once this is successful, the registry value set
  332. // above is deleted.
  333. //
  334. // This algorithm gives us the following guarantees:
  335. //
  336. // 1. If the registry value is set, then a good backup file with CLUSTER_RESDLL_BACKUP_FILE_EXTENSION
  337. // must exist.
  338. //
  339. // 2. If the registry value is not set, then the existing DLL file was not touched by
  340. // the upgrade process or the DLL upgrade was completely successful.
  341. //
  342. // Thus, only if the registry value is set at the time FmpCreateMonitor is invoked, it
  343. // will go through the elaborate recovery process implemented in FmpRecoverResourceDLLFiles.
  344. // At recovery time, we can be sure that the backup file with CLUSTER_RESDLL_BACKUP_FILE_EXTENSION
  345. // is a perfectly good backup. Also, at recovery time we cannot be sure of the state (good/bad)
  346. // of the existing DLL file (if it exists at all) or the renamed file with
  347. // CLUSTER_RESDLL_RENAMED_FILE_EXTENSION. So, the recovery process is pessimistic and just
  348. // copies the backup file wit CLUSTER_RESDLL_BACKUP_FILE_EXTENSION over any existing DLL
  349. // file.
  350. //
  351. // Sideeffect: Even if the registry value is not set, there could be a stale backup file
  352. // left. Thus wheneever FmpCreateMonitor is invoked, it has to cleanup those files.
  353. // This is done by invoking FmpDeleteBackupFiles(NULL) from FmpRecoverResourceDLLFiles.
  354. //
  355. //
  356. // Open key to SYSTEM\CurrentControlSet\Services\ClusSvc\Parameters
  357. //
  358. dwStatus = RegOpenKeyW( HKEY_LOCAL_MACHINE,
  359. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  360. &hClussvcParamsKey );
  361. if ( dwStatus != ERROR_SUCCESS )
  362. {
  363. ClRtlLogPrint(LOG_CRITICAL,
  364. "[FM] FmpReplaceResourceDLL: RegOpenKeyEx on %1!ws! failed, Status=%2!u!\n",
  365. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  366. dwStatus);
  367. goto FnExit;
  368. }
  369. //
  370. // See whether a past failed upgrade has left any values in the upgrade progress list
  371. //
  372. dwStatus = RegQueryValueExW( hClussvcParamsKey,
  373. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  374. 0,
  375. &dwType,
  376. NULL,
  377. &cbListSize );
  378. if ( ( dwStatus != ERROR_SUCCESS ) &&
  379. ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  380. {
  381. ClRtlLogPrint(LOG_CRITICAL,
  382. "[FM] FmpReplaceResourceDLL: RegQueryValueEx (1st time) on %1!ws! key, value %2!ws! failed, Status=%3!u!\n",
  383. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  384. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  385. dwStatus);
  386. goto FnExit;
  387. }
  388. if ( cbListSize != 0 )
  389. {
  390. //
  391. // Found some values left out from past upgrade. Read those values.
  392. //
  393. lpmszUpgradeList = LocalAlloc ( LPTR, cbListSize );
  394. if ( lpmszUpgradeList == NULL )
  395. {
  396. dwStatus = GetLastError();
  397. ClRtlLogPrint(LOG_CRITICAL,
  398. "[FM] FmpReplaceResourceDLL: Mem alloc failure, Status=%1!u!\n",
  399. dwStatus);
  400. goto FnExit;
  401. }
  402. dwStatus = RegQueryValueExW( hClussvcParamsKey,
  403. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  404. 0,
  405. &dwType,
  406. ( LPBYTE ) lpmszUpgradeList,
  407. &cbListSize );
  408. if ( dwStatus != ERROR_SUCCESS )
  409. {
  410. ClRtlLogPrint(LOG_CRITICAL,
  411. "[FM] FmpReplaceResourceDLL: RegQueryValueEx (2nd time) on %1!ws! key, value %2!ws! failed, Status=%3!u!\n",
  412. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  413. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  414. dwStatus);
  415. goto FnExit;
  416. }
  417. }
  418. //
  419. // Check whether a failed upgrade of the same DLL has occurred in the past.
  420. //
  421. if ( ClRtlMultiSzScan( lpmszUpgradeList,
  422. lpszCurrentDllPath ) != NULL )
  423. {
  424. ClRtlLogPrint(LOG_UNUSUAL,
  425. "[FM] FmpReplaceResourceDLL: ClRtlMultiSzScan detected %1!ws! in the multi-sz, skip append...\n",
  426. lpszCurrentDllPath);
  427. goto skip_multisz_append;
  428. }
  429. //
  430. // Append the current DLL path to the REG_MULTI_SZ
  431. //
  432. cchLen = cbListSize/sizeof( WCHAR );
  433. dwStatus = ClRtlMultiSzAppend( &lpmszUpgradeList,
  434. &cchLen,
  435. lpszCurrentDllPath );
  436. if ( dwStatus != ERROR_SUCCESS )
  437. {
  438. ClRtlLogPrint(LOG_CRITICAL,
  439. "[FM] FmpReplaceResourceDLL: ClRtlMultiSzAppend failed for %1!ws!, Status=%2!u!\n",
  440. lpszCurrentDllPath,
  441. dwStatus);
  442. goto FnExit;
  443. }
  444. //
  445. // Get the cluster bits installed directory
  446. //
  447. dwStatus = ClRtlGetClusterDirectory( szClusterDirectory, MAX_PATH );
  448. if ( dwStatus != ERROR_SUCCESS )
  449. {
  450. ClRtlLogPrint(LOG_CRITICAL,
  451. "[FM] FmpReplaceResourceDLL: Could not get cluster dir, Status=%1!u!\n",
  452. dwStatus);
  453. goto FnExit;
  454. }
  455. lstrcpy( szBakFile, szClusterDirectory );
  456. dwLen = lstrlenW( szBakFile );
  457. if ( szBakFile[dwLen-1] != L'\\' )
  458. {
  459. szBakFile[dwLen++] = L'\\';
  460. szBakFile[dwLen] = L'\0';
  461. }
  462. lstrcat( szBakFile, lpszNewDllName );
  463. lstrcat( szBakFile, CLUSTER_RESDLL_BACKUP_FILE_EXTENSION );
  464. //
  465. // Copy the current DLL to a bak file and save it into the cluster installation directory.
  466. // This needs to be done BEFORE the registry value is set so that you can be sure that once you
  467. // perform a recovery, the file that you use from the backup is good.
  468. //
  469. if ( !CopyFileEx( lpszCurrentDllPath, // Source file
  470. szBakFile, // Destination file
  471. NULL, // No progress routine
  472. NULL, // No data to progress routine
  473. NULL, // No cancel variable
  474. 0 ) ) // No flags
  475. {
  476. dwStatus = GetLastError();
  477. ClRtlLogPrint(LOG_CRITICAL,
  478. "[FM] FmpReplaceResourceDLL: CopyFileEx of %1!ws! to %2!ws! failed, Status=%3!u!\n",
  479. lpszCurrentDllPath,
  480. szBakFile,
  481. dwStatus);
  482. goto FnExit;
  483. }
  484. //
  485. // Set the file attributes to RO and hidden. Continue even if an error occurs since it is
  486. // not fatal.
  487. //
  488. if ( !SetFileAttributes( szBakFile, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN ) )
  489. {
  490. dwStatus = GetLastError();
  491. ClRtlLogPrint(LOG_NOISE,
  492. "[FM] FmpReplaceResourceDLL: Failed in SetFileAttributes for %1!ws!, Status=%2!u!\n",
  493. szBakFile,
  494. dwStatus);
  495. }
  496. //
  497. // Set the new upgrade list
  498. //
  499. dwStatus = RegSetValueExW( hClussvcParamsKey,
  500. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  501. 0,
  502. REG_MULTI_SZ,
  503. ( LPBYTE ) lpmszUpgradeList,
  504. cchLen * sizeof ( WCHAR ) );
  505. if ( dwStatus != ERROR_SUCCESS )
  506. {
  507. ClRtlLogPrint(LOG_CRITICAL,
  508. "[FM] FmpReplaceResourceDLL: RegSetValueExW (1st time) on %1!ws! key, value %2!ws! failed, Status=%3!u!\n",
  509. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  510. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  511. dwStatus);
  512. goto FnExit;
  513. }
  514. skip_multisz_append:
  515. lstrcpy( szOldFile, szClusterDirectory );
  516. dwLen = lstrlenW( szOldFile );
  517. if ( szOldFile[dwLen-1] != L'\\' )
  518. {
  519. szOldFile[dwLen++] = L'\\';
  520. szOldFile[dwLen] = L'\0';
  521. }
  522. lstrcat( szOldFile, lpszNewDllName );
  523. lstrcat( szOldFile, CLUSTER_RESDLL_RENAMED_FILE_EXTENSION );
  524. //
  525. // Rename the currently loaded DLL to the a .old file in the cluster installation directory
  526. //
  527. if ( !MoveFileEx( lpszCurrentDllPath, // Source file
  528. szOldFile, // Destination file
  529. MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH ) )
  530. {
  531. dwStatus = GetLastError();
  532. ClRtlLogPrint(LOG_CRITICAL,
  533. "[FM] FmpReplaceResourceDLL: MoveFileEx of %1!ws! to %2!ws! failed, Status=%3!u!\n",
  534. lpszCurrentDllPath,
  535. szOldFile,
  536. dwStatus);
  537. goto FnExit;
  538. }
  539. //
  540. // Set the file attributes to RO and hidden. Continue even if an error occurs since it is
  541. // not fatal.
  542. //
  543. if ( !SetFileAttributes( szOldFile, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN ) )
  544. {
  545. dwStatus = GetLastError();
  546. ClRtlLogPrint(LOG_NOISE,
  547. "[FM] FmpReplaceResourceDLL: Failed in SetFileAttributes for %1!ws!, Status=%2!u!\n",
  548. szOldFile,
  549. dwStatus);
  550. }
  551. //
  552. // Copy the new DLL from the installation path to the current DLL path. This should succeed
  553. // since the current DLL has been renamed.
  554. //
  555. if ( !CopyFileEx( lpszInstallationPath, // Source file
  556. lpszCurrentDllPath, // Destination file
  557. NULL, // No progress routine
  558. NULL, // No data to progress routine
  559. NULL, // No cancel variable
  560. 0 ) ) // No flags
  561. {
  562. dwStatus = GetLastError();
  563. ClRtlLogPrint(LOG_CRITICAL,
  564. "[FM] FmpReplaceResourceDLL: CopyFileEx of %1!ws! to %2!ws! failed, Status=%3!u!\n",
  565. lpszInstallationPath,
  566. lpszCurrentDllPath,
  567. dwStatus);
  568. goto FnExit;
  569. }
  570. //
  571. // Now get rid of the value we set in the registry. The BAK and OLD files are deleted later.
  572. //
  573. dwStatus = FmpResetMultiSzValue ( hClussvcParamsKey,
  574. lpmszUpgradeList,
  575. &cchLen,
  576. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  577. lpszCurrentDllPath );
  578. if ( dwStatus != ERROR_SUCCESS )
  579. {
  580. ClRtlLogPrint(LOG_CRITICAL,
  581. "[FM] FmpReplaceResourceDLL: Unable to remove %1!ws! from value %2!ws!, Status=%3!u!\n",
  582. lpszCurrentDllPath,
  583. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  584. dwStatus);
  585. goto FnExit;
  586. }
  587. FnExit:
  588. LocalFree( lpmszUpgradeList );
  589. if ( hClussvcParamsKey != NULL )
  590. {
  591. RegCloseKey( hClussvcParamsKey );
  592. }
  593. return ( dwStatus );
  594. }// FmpReplaceResourceDLL
  595. DWORD
  596. FmpRecycleMonitors(
  597. IN LPCWSTR lpszDllName
  598. )
  599. /*++
  600. Routine Description:
  601. Recycle all the monitors that have the specified resource DLL loaded.
  602. Arguments:
  603. lpszDllName - The name of the loaded resource DLL.
  604. Return Value:
  605. ERROR_SUCCESS on success.
  606. Win32 error code otherwise.
  607. --*/
  608. {
  609. DWORD i, dwStatus = ERROR_SUCCESS;
  610. FM_MONITOR_ENUM_HEADER MonitorEnumHeader;
  611. ClRtlLogPrint(LOG_NOISE,
  612. "[FM] FmpRecycleMonitors: Attempting to recycle all monitors that have loaded the DLL %1!ws!\n",
  613. lpszDllName);
  614. MonitorEnumHeader.ppMonitorList = NULL;
  615. MonitorEnumHeader.fDefaultMonitorAdded = FALSE;
  616. //
  617. // Create a list of monitors that have the resource DLL loaded.
  618. //
  619. dwStatus = FmpCreateMonitorList( lpszDllName, &MonitorEnumHeader );
  620. if ( dwStatus != ERROR_SUCCESS )
  621. {
  622. ClRtlLogPrint(LOG_CRITICAL,
  623. "[FM] FmpRecycleMonitors: FmpCreateMonitorList failed with status %1!u!\n",
  624. dwStatus);
  625. goto FnExit;
  626. }
  627. //
  628. // Now, shutdown and restart the monitors identified above. Shutdown and restart of each
  629. // monitor is done one by one so that the long shutdown time of some monitors will not affect
  630. // the restart of others. The FmpRestartMonitor function invokes a shutdown on the monitor,
  631. // waits until the monitor is fully shutdown and then restarts all the resources in the
  632. // old monitor in the new monitor.
  633. //
  634. for ( i=0; i<MonitorEnumHeader.cEntries; i++ )
  635. {
  636. //
  637. // Increment the ref count. It will be decremented by the restart function.
  638. //
  639. InterlockedIncrement( &MonitorEnumHeader.ppMonitorList[i]->RefCount );
  640. FmpRestartMonitor( MonitorEnumHeader.ppMonitorList[i] );
  641. } // for
  642. FnExit:
  643. LocalFree( MonitorEnumHeader.ppMonitorList );
  644. ClRtlLogPrint(LOG_NOISE,
  645. "[FM] FmpRecycleMonitors: Return with status %1!u!\n",
  646. dwStatus);
  647. return ( dwStatus );
  648. }// FmpRecycleMonitors
  649. DWORD
  650. FmpCreateMonitorList(
  651. IN LPCWSTR lpszDllName,
  652. OUT PFM_MONITOR_ENUM_HEADER pMonitorHeader
  653. )
  654. /*++
  655. Routine Description:
  656. Create a list of monitors that have the resource DLL implementing the resource loaded.
  657. Arguments:
  658. lpszDllName - The resource DLL that is being upgraded.
  659. pMonitorHeader - The enumeration list header which points to a list of monitors that have
  660. the DLL loaded.
  661. Return Value:
  662. ERROR_SUCCESS if successful.
  663. Win32 error code on error.
  664. --*/
  665. {
  666. DWORD dwStatus = ERROR_SUCCESS;
  667. pMonitorHeader->cEntries = 0;
  668. pMonitorHeader->cAllocated = ENUM_GROW_SIZE;
  669. pMonitorHeader->ppMonitorList = LocalAlloc( LPTR, ENUM_GROW_SIZE * sizeof ( PRESMON ) );
  670. if ( pMonitorHeader->ppMonitorList == NULL )
  671. {
  672. dwStatus = GetLastError();
  673. ClRtlLogPrint(LOG_CRITICAL,
  674. "[FM] FmpCreateMonitorList: Mem alloc failed with status %1!u!\n",
  675. dwStatus);
  676. goto FnExit;
  677. }
  678. //
  679. // Go through all the cluster resources to identify the monitors that have loaded the
  680. // specified DLL.
  681. //
  682. OmEnumObjects( ObjectTypeResource,
  683. FmpFindHostMonitors,
  684. ( PVOID ) lpszDllName,
  685. ( PVOID ) pMonitorHeader );
  686. FnExit:
  687. return ( dwStatus );
  688. }// FmpCreateMonitorList
  689. BOOL
  690. FmpFindHostMonitors(
  691. IN LPCWSTR lpszDllName,
  692. IN OUT PFM_MONITOR_ENUM_HEADER pMonitorEnumHeader,
  693. IN PFM_RESOURCE pResource,
  694. IN LPCWSTR lpszResourceId
  695. )
  696. /*++
  697. Routine Description:
  698. Callback routine for enumerating all resources in the cluster. This routine will build a list
  699. of monitors that have loaded the specified DLL.
  700. Arguments:
  701. lpszDllName - The DLL whose host processes have to be determined.
  702. pMonitorEnumHeader - The monitor list enumeration header
  703. pResource - The resource being enumerated.
  704. lpszResourceId - The Id of the resource object being enumerated.
  705. Returns:
  706. TRUE - The enumeration should continue.
  707. FALSE - The enumeration must stop
  708. --*/
  709. {
  710. BOOL fStatus = TRUE;
  711. PRESMON *ppMonitorList;
  712. DWORD i;
  713. LPWSTR lpszDllNameOfRes = NULL;
  714. WCHAR szDLLNameOfRes[MAX_PATH];
  715. DWORD dwStatus;
  716. //
  717. // Check whether the currently allocated monitor list has reached capacity. If so,
  718. // create a new bigger list, copy the contents of the old list to the new one and
  719. // free the old list.
  720. //
  721. if ( pMonitorEnumHeader->cEntries == pMonitorEnumHeader->cAllocated )
  722. {
  723. ppMonitorList = LocalAlloc( LPTR, pMonitorEnumHeader->cAllocated * 2 * sizeof ( PRESMON ) );
  724. if ( ppMonitorList == NULL )
  725. {
  726. fStatus = FALSE;
  727. ClRtlLogPrint(LOG_CRITICAL,
  728. "[FM] FmpFindHostMonitors: Mem alloc failed with status %1!u!\n",
  729. GetLastError());
  730. goto FnExit;
  731. }
  732. for ( i=0; i<pMonitorEnumHeader->cEntries; i++ )
  733. {
  734. ppMonitorList[i] = pMonitorEnumHeader->ppMonitorList[i];
  735. }
  736. pMonitorEnumHeader->cAllocated *= 2;
  737. LocalFree( pMonitorEnumHeader->ppMonitorList );
  738. pMonitorEnumHeader->ppMonitorList = ppMonitorList;
  739. }
  740. //
  741. // Get the plain file name from the DLL name stored in the restype structure. Since the
  742. // parse function can potentially get rid of the trailing '\', make a copy of the DLL
  743. // name.
  744. //
  745. //
  746. // IMPORTANT: Do not write stuff into szDllNameOfRes while lpszDllName is being used
  747. // since lpszDllName points inside szDllNameOfRes.
  748. //
  749. lstrcpy( szDLLNameOfRes, pResource->Type->DllName );
  750. dwStatus = FmpParsePathForFileName ( szDLLNameOfRes,
  751. TRUE, // Check for path existence
  752. &lpszDllNameOfRes );
  753. if ( dwStatus != ERROR_SUCCESS )
  754. {
  755. ClRtlLogPrint(LOG_CRITICAL,
  756. "[FM] FmpFindHostMonitors: Unable to parse path %1!ws! for filename, Status %2!u!\n",
  757. szDLLNameOfRes,
  758. dwStatus);
  759. fStatus = FALSE;
  760. goto FnExit;
  761. }
  762. if ( lpszDllNameOfRes == NULL ) lpszDllNameOfRes = pResource->Type->DllName;
  763. //
  764. // If this resource is not implemented in the specified DLL, you are done.
  765. //
  766. if ( lstrcmp( lpszDllNameOfRes, lpszDllName ) != 0 )
  767. {
  768. fStatus = TRUE;
  769. goto FnExit;
  770. }
  771. ClRtlLogPrint(LOG_NOISE,
  772. "[FM] FmpFindHostMonitors: Resource DLL %1!ws! for resource %2!ws! [%3!ws!] is loaded currently in %4!ws! monitor...\n",
  773. lpszDllName,
  774. OmObjectId(pResource),
  775. OmObjectName(pResource),
  776. (pResource->Monitor == FmpDefaultMonitor) ? L"default":L"separate");
  777. //
  778. // Since multiple resources can be loaded in the default monitor, you don't want to add
  779. // the default monitor multiple times in the list. Use a global static variable to indicate
  780. // that the default monitor has been added in the list. Also, note that only one resource can
  781. // be loaded in a separate monitor process and so there is no question of adding the separate
  782. // monitor multiple times in the list.
  783. //
  784. if ( pResource->Monitor == FmpDefaultMonitor )
  785. {
  786. if ( pMonitorEnumHeader->fDefaultMonitorAdded == TRUE )
  787. {
  788. fStatus = TRUE;
  789. goto FnExit;
  790. }
  791. pMonitorEnumHeader->fDefaultMonitorAdded = TRUE;
  792. }
  793. pMonitorEnumHeader->ppMonitorList[pMonitorEnumHeader->cEntries] = pResource->Monitor;
  794. pMonitorEnumHeader->cEntries ++;
  795. FnExit:
  796. return ( fStatus );
  797. } // FmpFindHostMonitors
  798. DWORD
  799. FmpRecoverResourceDLLFiles(
  800. VOID
  801. )
  802. /*++
  803. Routine Description:
  804. Check whether any resource DLLs need to be recovered due to a crash during an upgrade.
  805. Arguments:
  806. None.
  807. Returns:
  808. ERROR_SUCCESS on success
  809. Win32 error code otherwise
  810. --*/
  811. {
  812. DWORD dwStatus = ERROR_SUCCESS;
  813. LPWSTR lpszDllPath = NULL;
  814. LPCWSTR lpmszUpgradeList = NULL;
  815. LPWSTR lpmszBegin = NULL;
  816. DWORD cbListSize = 0, cchLen = 0;
  817. DWORD dwType, dwIndex;
  818. HKEY hClussvcParamsKey = NULL;
  819. //
  820. // Open key to SYSTEM\CurrentControlSet\Services\ClusSvc\Parameters
  821. //
  822. dwStatus = RegOpenKeyW( HKEY_LOCAL_MACHINE,
  823. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  824. &hClussvcParamsKey );
  825. if ( dwStatus != ERROR_SUCCESS )
  826. {
  827. ClRtlLogPrint(LOG_CRITICAL,
  828. "[FM] FmpRecoverResourceDLLFiles: RegOpenKeyEx on %1!ws! failed, Status=%2!u!\n",
  829. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  830. dwStatus);
  831. goto FnExit;
  832. }
  833. //
  834. // See whether a past failed upgrade has left any values in the upgrade progress list
  835. //
  836. dwStatus = RegQueryValueExW( hClussvcParamsKey,
  837. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  838. 0,
  839. &dwType,
  840. NULL,
  841. &cbListSize );
  842. if ( dwStatus != ERROR_SUCCESS )
  843. {
  844. if ( dwStatus == ERROR_FILE_NOT_FOUND )
  845. {
  846. dwStatus = ERROR_SUCCESS;
  847. //
  848. // Delete any backup files left over from past failed upgrades.
  849. //
  850. FmpDeleteBackupFiles( NULL );
  851. }
  852. else
  853. ClRtlLogPrint(LOG_CRITICAL,
  854. "[FM] FmpRecoverResourceDLLFiles: RegQueryValueEx (1st time) on %1!ws! key, value %2!ws! failed, Status=%3!u!\n",
  855. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  856. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  857. dwStatus);
  858. goto FnExit;
  859. }
  860. if ( cbListSize == 0 )
  861. {
  862. ClRtlLogPrint(LOG_NOISE,
  863. "[FM] FmpRecoverResourceDLLFiles: Value size is 0 for %1!ws! key, value %2!ws!\n",
  864. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  865. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST);
  866. goto FnExit;
  867. }
  868. //
  869. // Found some values left out from past upgrade. Read those values. Also, copy
  870. // those values into a temp buffer for allowing easy MULTI_SZ removal.
  871. //
  872. lpmszUpgradeList = LocalAlloc ( LPTR,
  873. 2 * cbListSize ); // Twice size needed for temp buffer below
  874. if ( lpmszUpgradeList == NULL )
  875. {
  876. dwStatus = GetLastError();
  877. ClRtlLogPrint(LOG_CRITICAL,
  878. "[FM] FmpRecoverResourceDLLFiles: Mem alloc failure, Status=%1!u!\n",
  879. dwStatus);
  880. goto FnExit;
  881. }
  882. lpmszBegin = ( LPWSTR ) lpmszUpgradeList;
  883. dwStatus = RegQueryValueExW( hClussvcParamsKey,
  884. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  885. 0,
  886. &dwType,
  887. ( LPBYTE ) lpmszUpgradeList,
  888. &cbListSize );
  889. if ( dwStatus != ERROR_SUCCESS )
  890. {
  891. ClRtlLogPrint(LOG_CRITICAL,
  892. "[FM] FmpRecoverResourceDLLFiles: RegQueryValueEx (2nd time) on %1!ws! key, value %2!ws! failed, Status=%3!u!\n",
  893. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  894. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  895. dwStatus);
  896. goto FnExit;
  897. }
  898. CopyMemory( lpmszBegin + cbListSize/sizeof(WCHAR), lpmszUpgradeList, cbListSize );
  899. cchLen = cbListSize/sizeof(WCHAR);
  900. //
  901. // This loop walks through the multi strings read from the registry and tries to
  902. // see if the file exists in the path. If not, it tries to copy the file from
  903. // a backup. Once it succeeds in copying a file from the backup, it tries to
  904. // delete the value from the MULTI_SZ and the appropriate backup files from the
  905. // cluster directory.
  906. //
  907. for ( dwIndex = 0; ; dwIndex++ )
  908. {
  909. lpszDllPath = ( LPWSTR ) ClRtlMultiSzEnum( lpmszUpgradeList,
  910. cbListSize/sizeof(WCHAR),
  911. dwIndex );
  912. //
  913. // If you reached the end of the multi-string, bail.
  914. //
  915. if ( lpszDllPath == NULL )
  916. {
  917. break;
  918. }
  919. //
  920. // Assume the worst and copy the DLL file from the good backup.
  921. //
  922. ClRtlLogPrint(LOG_NOISE,
  923. "[FM] FmpRecoverResourceDLLFiles: Resource DLL binary %1!ws! cannot be trusted due to a failure during upgrade...\n",
  924. lpszDllPath);
  925. ClRtlLogPrint(LOG_NOISE,
  926. "[FM] FmpRecoverResourceDLLFiles: Attempting to use a copy from backup...\n",
  927. lpszDllPath);
  928. dwStatus = FmpCopyBackupFile( lpszDllPath );
  929. if ( dwStatus == ERROR_SUCCESS )
  930. {
  931. //
  932. // The copy went fine. So, reset the registry value set during the upgrade.
  933. //
  934. dwStatus = FmpResetMultiSzValue ( hClussvcParamsKey,
  935. lpmszBegin + cbListSize/sizeof(WCHAR),
  936. &cchLen,
  937. CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST,
  938. lpszDllPath );
  939. if ( dwStatus == ERROR_SUCCESS )
  940. //
  941. // The registry value reset went fine, so get rid of the backup files
  942. //
  943. FmpDeleteBackupFiles( lpszDllPath );
  944. }
  945. } // for
  946. FnExit:
  947. LocalFree( lpmszBegin );
  948. if ( hClussvcParamsKey != NULL )
  949. {
  950. RegCloseKey( hClussvcParamsKey );
  951. }
  952. return ( dwStatus );
  953. }// FmpRecoverResourceDLLFiles
  954. DWORD
  955. FmpResetMultiSzValue(
  956. IN HKEY hKey,
  957. IN LPWSTR lpmszList,
  958. IN OUT LPDWORD pcchLen,
  959. IN LPCWSTR lpszValueName,
  960. IN LPCWSTR lpszString
  961. )
  962. /*++
  963. Routine Description:
  964. Gets rid of a specified string from a multi-string and sets the string to the given value name
  965. in the registry. The value is deleted if on the string removal the multi-string becomes
  966. empty.
  967. Arguments:
  968. hKey - An open registry handle.
  969. lpmszList - A multi-string.
  970. pcchLen - A pointer to the length of the multi string. On return, it will be set to the
  971. new length of the multi-string.
  972. lpszValueName - The value name to be modified.
  973. lpszString - The string to be removed from the multi-string.
  974. Returns:
  975. ERROR_SUCCESS on success
  976. Win32 error code otherwise
  977. --*/
  978. {
  979. DWORD dwStatus = ERROR_SUCCESS;
  980. //
  981. // Remove the supplied string from the multi-sz
  982. //
  983. dwStatus = ClRtlMultiSzRemove( lpmszList,
  984. pcchLen,
  985. lpszString );
  986. if ( dwStatus != ERROR_SUCCESS )
  987. {
  988. ClRtlLogPrint(LOG_CRITICAL,
  989. "[FM] FmpReplaceResourceDLL: ClRtlMultiSzRemove failed for %1!ws!, Status=%2!u!\n",
  990. lpszString,
  991. dwStatus);
  992. goto FnExit;
  993. }
  994. //
  995. // ClRtlMultiSzRemove will return a size of 1 character if the string is empty
  996. //
  997. if ( *pcchLen <= 2 )
  998. {
  999. //
  1000. // After removal from the multi-sz, there is nothing left, so delete the value
  1001. //
  1002. dwStatus = RegDeleteValue( hKey,
  1003. lpszValueName );
  1004. if ( dwStatus != ERROR_SUCCESS )
  1005. {
  1006. ClRtlLogPrint(LOG_CRITICAL,
  1007. "[FM] FmpResetMultiSzValue: RegDeleteValue on %1!ws! value failed, Status=%2!u!\n",
  1008. lpszValueName,
  1009. dwStatus);
  1010. goto FnExit;
  1011. }
  1012. } else
  1013. {
  1014. //
  1015. // Put the rest of the values back into the registry.
  1016. //
  1017. dwStatus = RegSetValueExW( hKey,
  1018. lpszValueName,
  1019. 0,
  1020. REG_MULTI_SZ,
  1021. ( LPBYTE ) lpmszList,
  1022. ( *pcchLen ) * sizeof ( WCHAR ) );
  1023. if ( dwStatus != ERROR_SUCCESS )
  1024. {
  1025. ClRtlLogPrint(LOG_CRITICAL,
  1026. "[FM] FmpResetMultiSzValue: RegSetValueEx on %1!ws! value failed, Status=%2!u!\n",
  1027. lpszValueName,
  1028. dwStatus);
  1029. goto FnExit;
  1030. }
  1031. }
  1032. FnExit:
  1033. return ( dwStatus );
  1034. }// FmpResetMultiSzValue
  1035. DWORD
  1036. FmpCopyBackupFile(
  1037. IN LPCWSTR lpszPath
  1038. )
  1039. /*++
  1040. Routine Description:
  1041. Parse the path for the DLL file name and copy the backup version of the file.
  1042. Arguments:
  1043. lpszPath - Path including the DLL file name.
  1044. Returns:
  1045. ERROR_SUCCESS on success
  1046. Win32 error code otherwise
  1047. Note:
  1048. We can only trust CLUSTER_RESDLL_BACKUP_FILE_EXTENSION file as the good backup since that
  1049. backup was made prior to setting the CLUSREG_NAME_SVC_PARAM_RESDLL_UPGD_PROGRESS_LIST value.
  1050. So, we don't look at the CLUSTER_RESDLL_RENAMED_FILE_EXTENSION file in this function.
  1051. --*/
  1052. {
  1053. WCHAR szSourceFile[MAX_PATH];
  1054. WCHAR szTempFile[MAX_PATH];
  1055. WCHAR szClusterDir[MAX_PATH];
  1056. LPWSTR lpszFileName;
  1057. DWORD dwStatus = ERROR_SUCCESS, i, dwLen;
  1058. //
  1059. // Get the plain file name from the DLL name stored in the restype structure. Since the
  1060. // parse function can potentially get rid of the trailing '\', make a copy of the DLL
  1061. // name.
  1062. //
  1063. // IMPORTANT: Dont write into szTempFile after you parse the file name since lpszFileName
  1064. // points into szTempFile.
  1065. //
  1066. lstrcpy( szTempFile, lpszPath );
  1067. dwStatus = FmpParsePathForFileName ( szTempFile,
  1068. FALSE, // Don't check for existence
  1069. &lpszFileName );
  1070. if ( ( dwStatus != ERROR_SUCCESS ) || ( lpszFileName == NULL ) )
  1071. {
  1072. ClRtlLogPrint(LOG_CRITICAL,
  1073. "[FM] FmpCopyBackupFile: Unable to parse path %1!ws! for filename, Status %2!u!\n",
  1074. szTempFile,
  1075. dwStatus);
  1076. goto FnExit;
  1077. }
  1078. //
  1079. // Get the cluster bits installed directory
  1080. //
  1081. dwStatus = ClRtlGetClusterDirectory( szClusterDir, MAX_PATH );
  1082. if ( dwStatus != ERROR_SUCCESS )
  1083. {
  1084. ClRtlLogPrint(LOG_CRITICAL,
  1085. "[FM] FmpCopyBackupFile: Could not get cluster dir, Status=%1!u!\n",
  1086. dwStatus);
  1087. goto FnExit;
  1088. }
  1089. lstrcpy( szSourceFile, szClusterDir );
  1090. dwLen = lstrlenW( szSourceFile );
  1091. if ( szSourceFile[dwLen-1] != L'\\' )
  1092. {
  1093. szSourceFile[dwLen++] = L'\\';
  1094. szSourceFile[dwLen] = L'\0';
  1095. }
  1096. lstrcat( szSourceFile, lpszFileName );
  1097. lstrcat( szSourceFile, CLUSTER_RESDLL_BACKUP_FILE_EXTENSION );
  1098. //
  1099. // Change the file attributes to normal
  1100. //
  1101. if ( !SetFileAttributes( szSourceFile, FILE_ATTRIBUTE_NORMAL ) )
  1102. {
  1103. dwStatus = GetLastError();
  1104. ClRtlLogPrint(LOG_NOISE,
  1105. "[FM] FmpCopyBackupFile: Failed in SetFileAttributes for %1!ws!, Status=%2!u!\n",
  1106. szSourceFile,
  1107. dwStatus);
  1108. }
  1109. //
  1110. // Copy the backup file to the DLL path.
  1111. //
  1112. if ( !CopyFileEx( szSourceFile, // Source file
  1113. lpszPath, // Destination file
  1114. NULL, // No progress routine
  1115. NULL, // No data to progress routine
  1116. NULL, // No cancel variable
  1117. 0 ) ) // No flags
  1118. {
  1119. dwStatus = GetLastError();
  1120. ClRtlLogPrint(LOG_CRITICAL,
  1121. "[FM] FmpCopyBackupFile: CopyFileEx of %1!ws! to %2!ws! failed, Status=%3!u!\n",
  1122. szSourceFile,
  1123. lpszPath,
  1124. dwStatus);
  1125. } else
  1126. {
  1127. dwStatus = ERROR_SUCCESS;
  1128. ClRtlLogPrint(LOG_NOISE,
  1129. "[FM] FmpCopyBackupFile: CopyFileEx of %1!ws! to %2!ws! successful...\n",
  1130. szSourceFile,
  1131. lpszPath,
  1132. dwStatus);
  1133. goto FnExit;
  1134. }
  1135. FnExit:
  1136. return ( dwStatus );
  1137. }// FmpCopyBackupFile
  1138. VOID
  1139. FmpDeleteBackupFiles(
  1140. IN LPCWSTR lpszPath OPTIONAL
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. Parse the path for the DLL file name and delete the backup files corresponding to it OR
  1145. delete all files with the known backup extension in the %windir%\cluster directory.
  1146. Arguments:
  1147. lpszPath - Path including the DLL file name. OPTIONAL
  1148. Returns:
  1149. ERROR_SUCCESS on success
  1150. Win32 error code otherwise
  1151. --*/
  1152. {
  1153. WCHAR szSourceFile[MAX_PATH];
  1154. WCHAR szTempFile[MAX_PATH];
  1155. WCHAR szClusterDir[MAX_PATH];
  1156. LPWSTR lpszFileName = L"*"; // Use in case IN param is NULL
  1157. DWORD dwStatus = ERROR_SUCCESS, i, dwLen;
  1158. HANDLE hFind = INVALID_HANDLE_VALUE;
  1159. WIN32_FIND_DATA FindData;
  1160. if ( lpszPath == NULL ) goto skip_path_parse;
  1161. //
  1162. // Get the plain file name from the DLL name stored in the restype structure. Since the
  1163. // parse function can potentially get rid of the trailing '\', make a copy of the DLL
  1164. // name.
  1165. //
  1166. // IMPORTANT: Dont write into szTempFile after you parse the file name since lpszFileName
  1167. // points into szTempFile.
  1168. //
  1169. lstrcpy( szTempFile, lpszPath );
  1170. dwStatus = FmpParsePathForFileName ( szTempFile,
  1171. FALSE, // Don't check for existence
  1172. &lpszFileName );
  1173. if ( ( dwStatus != ERROR_SUCCESS ) || ( lpszFileName == NULL ) )
  1174. {
  1175. ClRtlLogPrint(LOG_CRITICAL,
  1176. "[FM] FmpDeleteBackupFiles: Unable to parse path %1!ws! for filename, Status %2!u!\n",
  1177. szTempFile,
  1178. dwStatus);
  1179. goto FnExit;
  1180. }
  1181. skip_path_parse:
  1182. //
  1183. // Get the cluster bits installed directory
  1184. //
  1185. dwStatus = ClRtlGetClusterDirectory( szClusterDir, MAX_PATH );
  1186. if ( dwStatus != ERROR_SUCCESS )
  1187. {
  1188. ClRtlLogPrint(LOG_CRITICAL,
  1189. "[FM] FmpDeleteBackupFiles: Could not get cluster dir, Status=%1!u!\n",
  1190. dwStatus);
  1191. goto FnExit;
  1192. }
  1193. if ( lpszPath == NULL )
  1194. {
  1195. //
  1196. // Delete all files that match the backup file pattern.
  1197. //
  1198. lstrcpy( szSourceFile, szClusterDir );
  1199. dwLen = lstrlenW( szSourceFile );
  1200. if ( szSourceFile[dwLen-1] != L'\\' )
  1201. {
  1202. szSourceFile[dwLen++] = L'\\';
  1203. szSourceFile[dwLen] = L'\0';
  1204. }
  1205. lstrcat( szSourceFile, lpszFileName );
  1206. lstrcat( szSourceFile, CLUSTER_RESDLL_BACKUP_FILES );
  1207. if ( ( hFind = FindFirstFile( szSourceFile, &FindData ) ) == INVALID_HANDLE_VALUE )
  1208. {
  1209. dwStatus = GetLastError();
  1210. if ( dwStatus != ERROR_FILE_NOT_FOUND )
  1211. ClRtlLogPrint(LOG_NOISE,
  1212. "[FM] FmpDeleteBackupFiles: Failed in FindFirstFile for %1!ws!, Status=%2!u!\n",
  1213. szSourceFile,
  1214. dwStatus);
  1215. goto FnExit;
  1216. }
  1217. do
  1218. {
  1219. //
  1220. // Get the file name matching the pattern above and get the full path including
  1221. // the file name. Then change the file attributes to normal for allowing deletion.
  1222. //
  1223. lstrcpy( szSourceFile, szClusterDir );
  1224. dwLen = lstrlenW( szSourceFile );
  1225. if ( szSourceFile[dwLen-1] != L'\\' )
  1226. {
  1227. szSourceFile[dwLen++] = L'\\';
  1228. szSourceFile[dwLen] = L'\0';
  1229. }
  1230. lstrcat( szSourceFile, FindData.cFileName );
  1231. if ( !SetFileAttributes( szSourceFile, FILE_ATTRIBUTE_NORMAL ) )
  1232. {
  1233. dwStatus = GetLastError();
  1234. ClRtlLogPrint(LOG_NOISE,
  1235. "[FM] FmpDeleteBackupFiles: Failed in SetFileAttributes for %1!ws!, Status=%2!u!\n",
  1236. szSourceFile,
  1237. dwStatus);
  1238. }
  1239. if ( !DeleteFile( szSourceFile ) )
  1240. {
  1241. dwStatus = GetLastError();
  1242. ClRtlLogPrint(LOG_NOISE,
  1243. "[FM] FmpDeleteBackupFiles: Failed in DeleteFile for %1!ws!, Status=%2!u!\n",
  1244. szSourceFile,
  1245. dwStatus);
  1246. }
  1247. } while ( FindNextFile( hFind, &FindData ) );
  1248. FindClose ( hFind );
  1249. goto FnExit;
  1250. }
  1251. lstrcpy( szSourceFile, szClusterDir );
  1252. dwLen = lstrlenW( szSourceFile );
  1253. if ( szSourceFile[dwLen-1] != L'\\' )
  1254. {
  1255. szSourceFile[dwLen++] = L'\\';
  1256. szSourceFile[dwLen] = L'\0';
  1257. }
  1258. lstrcat( szSourceFile, lpszFileName );
  1259. lstrcat( szSourceFile, CLUSTER_RESDLL_BACKUP_FILE_EXTENSION );
  1260. if ( !SetFileAttributes( szSourceFile, FILE_ATTRIBUTE_NORMAL ) )
  1261. {
  1262. dwStatus = GetLastError();
  1263. ClRtlLogPrint(LOG_NOISE,
  1264. "[FM] FmpDeleteBackupFiles: Failed in SetFileAttributes for %1!ws!, Status=%2!u!\n",
  1265. szSourceFile,
  1266. dwStatus);
  1267. }
  1268. if ( !DeleteFile( szSourceFile ) )
  1269. {
  1270. dwStatus = GetLastError();
  1271. ClRtlLogPrint(LOG_NOISE,
  1272. "[FM] FmpDeleteBackupFiles: Failed in DeleteFile for %1!ws!, Status=%2!u!\n",
  1273. szSourceFile,
  1274. dwStatus);
  1275. }
  1276. lstrcpy( szSourceFile, szClusterDir );
  1277. dwLen = lstrlenW( szSourceFile );
  1278. if ( szSourceFile[dwLen-1] != L'\\' )
  1279. {
  1280. szSourceFile[dwLen++] = L'\\';
  1281. szSourceFile[dwLen] = L'\0';
  1282. }
  1283. lstrcat( szSourceFile, lpszFileName );
  1284. lstrcat( szSourceFile, CLUSTER_RESDLL_RENAMED_FILE_EXTENSION );
  1285. if ( !SetFileAttributes( szSourceFile, FILE_ATTRIBUTE_NORMAL ) )
  1286. {
  1287. dwStatus = GetLastError();
  1288. ClRtlLogPrint(LOG_NOISE,
  1289. "[FM] FmpDeleteBackupFiles: Failed in SetFileAttributes for %1!ws!, Status=%2!u!\n",
  1290. szSourceFile,
  1291. dwStatus);
  1292. }
  1293. if ( !DeleteFile( szSourceFile ) )
  1294. {
  1295. dwStatus = GetLastError();
  1296. ClRtlLogPrint(LOG_NOISE,
  1297. "[FM] FmpDeleteBackupFiles: Failed in DeleteFile for %1!ws!, Status=%2!u!\n",
  1298. szSourceFile,
  1299. dwStatus);
  1300. }
  1301. FnExit:
  1302. return;
  1303. }