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.

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