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.

1414 lines
40 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. Duinst.cpp
  5. Abstract:
  6. Contains the main installation code
  7. used by the app.
  8. Notes:
  9. Unicode only.
  10. History:
  11. 03/02/2001 rparsons Created
  12. --*/
  13. #include "precomp.h"
  14. extern SETUP_INFO g_si;
  15. /*++
  16. Routine Description:
  17. Determines if a newer version of our package
  18. exists on the target
  19. Arguments:
  20. None
  21. Return Value:
  22. TRUE if the installation should take place
  23. FALSE if the installation should not take place
  24. -1 on failure
  25. --*/
  26. int
  27. InstallCheckVersion()
  28. {
  29. BOOL fReturn = FALSE;
  30. CRegistry creg;
  31. DWORDLONG dwlPackageVersion = 0;
  32. DWORDLONG dwlInstalledVersion = 0;
  33. char szActiveSetupKey[MAX_PATH] = "";
  34. char szBuffer[MAX_PATH*3] = "";
  35. WCHAR wszActiveSetupKey[MAX_PATH] = L"";
  36. WCHAR wszPackageVersion[MAX_PATH] = L"";
  37. LPWSTR lpwInstalledVersion = NULL;
  38. //
  39. // Get the registry key path from the INF
  40. //
  41. fReturn = SetupGetLineTextA(NULL,
  42. g_si.hInf,
  43. "Strings",
  44. "ActiveSetupKey",
  45. szActiveSetupKey,
  46. sizeof(szActiveSetupKey),
  47. NULL);
  48. if (!fReturn) {
  49. return -1;
  50. }
  51. pAnsiToUnicode(szActiveSetupKey, wszActiveSetupKey, MAX_PATH);
  52. //
  53. // Determine if a package is already installed
  54. //
  55. fReturn = creg.IsRegistryKeyPresent(HKEY_LOCAL_MACHINE,
  56. wszActiveSetupKey);
  57. if (!fReturn) {
  58. return TRUE;
  59. }
  60. //
  61. // A package is installed - determine the version
  62. //
  63. lpwInstalledVersion = creg.GetString(HKEY_LOCAL_MACHINE,
  64. wszActiveSetupKey,
  65. L"Version",
  66. TRUE);
  67. if (NULL == lpwInstalledVersion) {
  68. return -1;
  69. }
  70. //
  71. // Convert the installed version string to a number
  72. //
  73. VersionStringToNumber(lpwInstalledVersion, &dwlInstalledVersion);
  74. creg.Free(lpwInstalledVersion);
  75. //
  76. // Now scan the INF AddReg data to determine if a newer version
  77. // is present with our package
  78. //
  79. if (0 != dwlInstalledVersion) {
  80. INFCONTEXT InfContext;
  81. BOOL fRetVal = FALSE;
  82. fRetVal = SetupFindFirstLineA(g_si.hInf,
  83. INF_VERSION_INFO,
  84. NULL,
  85. &InfContext);
  86. while (fRetVal) {
  87. if ((SetupGetStringFieldA(&InfContext,
  88. 1,
  89. szBuffer, sizeof(szBuffer),
  90. NULL) == FALSE) ||
  91. (_stricmp(szBuffer, "HKLM") != 0 )) {
  92. goto NextLine;
  93. }
  94. if ((SetupGetStringFieldA(&InfContext,
  95. 2,
  96. szBuffer,
  97. sizeof(szBuffer),
  98. NULL) == FALSE) ||
  99. (_stricmp(szBuffer, szActiveSetupKey) != 0 )) {
  100. goto NextLine;
  101. }
  102. if ((SetupGetStringFieldA(&InfContext,
  103. 3,
  104. szBuffer,
  105. sizeof(szBuffer),
  106. NULL) == TRUE) &&
  107. (_stricmp(szBuffer, "Version") == 0 )) {
  108. break;
  109. }
  110. NextLine:
  111. fRetVal = SetupFindNextLine(&InfContext, &InfContext);
  112. }
  113. if (fRetVal) {
  114. if (SetupGetStringFieldA(&InfContext,
  115. 5,
  116. szBuffer,
  117. sizeof(szBuffer),
  118. NULL) == TRUE) {
  119. pAnsiToUnicode(szBuffer, wszPackageVersion, MAX_PATH);
  120. VersionStringToNumber(wszPackageVersion, &dwlPackageVersion);
  121. g_si.dwlUpdateVersion = dwlPackageVersion;
  122. }
  123. }
  124. //
  125. // Compare the versions
  126. //
  127. if (dwlPackageVersion >= dwlInstalledVersion) {
  128. return TRUE; // Package has newer than what's installed
  129. }
  130. }
  131. return FALSE;
  132. }
  133. /*++
  134. Routine Description:
  135. Installs catalog files, if there are any to install
  136. Arguments:
  137. hInf - Handle to the INF containing catalog names
  138. lpwSourcePath - The path where the file is currently located
  139. Return Value:
  140. TRUE on success, FALSE otherwise
  141. --*/
  142. BOOL
  143. InstallCatalogFiles(
  144. IN HINF hInf,
  145. IN LPCWSTR lpwSourcePath
  146. )
  147. {
  148. DWORD dwTargetCatVersion = 0;
  149. DWORD dwSourceCatVersion = 0;
  150. DWORD dwError = 0;
  151. BOOL fReturn = FALSE;
  152. char szCatFileName[MAX_PATH] = "";
  153. WCHAR wszCatFileName[MAX_PATH] = L"";
  154. WCHAR wszTargetCat[MAX_PATH] = L"";
  155. char szSourceCat[MAX_PATH] = "";
  156. WCHAR wszSourceCat[MAX_PATH] = L"";
  157. char szTempCat[MAX_PATH] = "";
  158. WCHAR wszTempCat[MAX_PATH] = L"";
  159. INFCONTEXT InfContext;
  160. WCHAR wszCatRoot[] = L"CatRoot\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}";
  161. //
  162. // Loop through all the lines in the CatalogsToInstall section,
  163. // verifying and installing each one
  164. //
  165. fReturn = SetupFindFirstLineA(hInf, INF_CAT_SECTION_NAME, NULL, &InfContext) &&
  166. SetupGetLineTextA(&InfContext, NULL, NULL, NULL,
  167. szCatFileName, MAX_PATH, NULL);
  168. while (fReturn) {
  169. pAnsiToUnicode(szCatFileName, wszCatFileName, MAX_PATH);
  170. //
  171. // Get paths to src and dest, compare versions,
  172. // and do the copy if necessary
  173. //
  174. wsprintf(wszSourceCat, L"%s\\%s", g_si.lpwExtractPath, wszCatFileName);
  175. wsprintf(wszTargetCat, L"%s\\%s\\%s", g_si.lpwSystem32Directory,
  176. wszCatRoot, wszCatFileName);
  177. wsprintf(wszTempCat, L"%s\\%s", g_si.lpwWindowsDirectory,
  178. wszCatFileName);
  179. dwTargetCatVersion = GetCatVersion(wszTargetCat);
  180. dwSourceCatVersion = GetCatVersion(wszSourceCat);
  181. if (dwTargetCatVersion > dwSourceCatVersion) {
  182. // If the SP?.CAT on the target is greater than ours
  183. // don't install ours
  184. Print(TRACE, L"[InstallCatalogFiles] Not installing older catalog\n");
  185. return TRUE;
  186. }
  187. pUnicodeToAnsi(wszSourceCat, szSourceCat, MAX_PATH);
  188. pUnicodeToAnsi(wszTempCat, szTempCat, MAX_PATH);
  189. //
  190. // Put the CAT file in the Windows directory
  191. //
  192. dwError = SetupDecompressOrCopyFileA(szSourceCat,
  193. szTempCat,
  194. NULL);
  195. if (NO_ERROR == dwError) {
  196. //
  197. // Perform the installation using the approriate function
  198. //
  199. dwError = pInstallCatalogFile(wszTempCat, wszCatFileName);
  200. if (NO_ERROR != dwError) {
  201. Print(ERROR,
  202. L"[InstallCatalogFiles] Failed to install catalog %s\n",
  203. wszTempCat);
  204. return FALSE;
  205. }
  206. }
  207. DeleteFile(wszTempCat); // clean up copied-over file
  208. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  209. SetupGetLineTextA(&InfContext, NULL, NULL, NULL,
  210. szCatFileName, MAX_PATH, NULL);
  211. }
  212. return TRUE;
  213. }
  214. /*++
  215. Routine Description:
  216. Creates the uninstall key in the registry
  217. Arguments:
  218. None
  219. Return Value:
  220. TRUE on success, FALSE otherwise
  221. --*/
  222. BOOL
  223. InstallWriteUninstallKey()
  224. {
  225. BOOL fReturn = FALSE;
  226. CRegistry creg;
  227. char szUninstallKey[MAX_PATH] = "";
  228. WCHAR wszUninstallKey[MAX_PATH] = L"";
  229. WCHAR wszUninstallCommand[MAX_PATH] = L"";
  230. HKEY hKey = NULL;
  231. //
  232. // Get the path for the uninstall key from the INF
  233. //
  234. fReturn = SetupGetLineTextA(NULL,
  235. g_si.hInf,
  236. "Strings",
  237. "UninstallKey",
  238. szUninstallKey,
  239. sizeof(szUninstallKey),
  240. NULL);
  241. if (!fReturn) {
  242. return FALSE;
  243. }
  244. pAnsiToUnicode(szUninstallKey, wszUninstallKey, MAX_PATH);
  245. //
  246. // Attempt to create the key or open if it already exists
  247. //
  248. hKey = creg.CreateKey(HKEY_LOCAL_MACHINE,
  249. wszUninstallKey,
  250. KEY_SET_VALUE);
  251. if (NULL == hKey) {
  252. Print(ERROR, L"[InstallWriteUninstallKey] Failed to create key\n");
  253. return FALSE;
  254. }
  255. //
  256. // Set the DisplayName
  257. //
  258. fReturn = creg.SetString(hKey,
  259. NULL,
  260. REG_DISPLAY_NAME,
  261. g_si.lpwPrettyAppName,
  262. FALSE);
  263. if (!fReturn) {
  264. Print(ERROR, L"[InstallWriteUninstallKey] Failed to set DisplayName\n");
  265. return FALSE;
  266. }
  267. //
  268. // Build the uninstall string
  269. //
  270. wsprintf(wszUninstallCommand, L"%s\\%s.exe %s", g_si.lpwInstallDirectory,
  271. g_si.lpwEventLogSourceName, UNINSTALL_SWITCH);
  272. //
  273. // Set the Uninstall string
  274. //
  275. fReturn = creg.SetString(HKEY_LOCAL_MACHINE,
  276. wszUninstallKey,
  277. REG_UNINSTALL_STRING,
  278. wszUninstallCommand,
  279. TRUE);
  280. if (!fReturn) {
  281. Print(ERROR, L"[InstallWriteUninstallKey] Failed to set UninstallString\n");
  282. return FALSE;
  283. }
  284. return TRUE;
  285. }
  286. /*++
  287. Routine Description:
  288. Run any EXEs specified in the INF file
  289. Arguments:
  290. None
  291. Return Value:
  292. TRUE on success, FALSE otherwise
  293. --*/
  294. BOOL
  295. InstallRunINFProcesses()
  296. {
  297. char szFileName[MAX_PATH] = "";
  298. WCHAR wszExpFileName[MAX_PATH] = L"";
  299. WCHAR wszFileName[MAX_PATH] = L"";
  300. BOOL fReturn = FALSE;
  301. INFCONTEXT InfContext;
  302. //
  303. // Loop through all the lines in the ProcessesToRun section,
  304. // spawning off each one
  305. //
  306. fReturn = SetupFindFirstLineA(g_si.hInf, INF_PROCESSES_TO_RUN, NULL,
  307. &InfContext) &&
  308. SetupGetLineTextA(&InfContext,
  309. NULL, NULL, NULL,
  310. szFileName, MAX_PATH, NULL);
  311. while (fReturn) {
  312. pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
  313. //
  314. // Spawn the EXE and ignore any errors returned
  315. //
  316. ExpandEnvironmentStrings(wszFileName,
  317. wszExpFileName,
  318. MAX_PATH);
  319. LaunchProcessAndWait(wszExpFileName, NULL);
  320. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  321. SetupGetLineTextA(&InfContext,
  322. NULL, NULL, NULL,
  323. szFileName, MAX_PATH, NULL);
  324. }
  325. return TRUE;
  326. }
  327. /*++
  328. Routine Description:
  329. Sets up the specified directory for use
  330. Arguments:
  331. lpwDirectoryPath - Full path to the directory
  332. Return Value:
  333. TRUE on success, FALSE otherwise
  334. --*/
  335. BOOL
  336. InstallPrepareDirectory(
  337. IN LPWSTR lpwDirectoryPath,
  338. IN DWORD dwAttributes
  339. )
  340. {
  341. BOOL fReturn = FALSE;
  342. LPWSTR lpwParentPath = NULL, lpwEnd = NULL;
  343. //
  344. // See if the directory exists
  345. //
  346. if (GetFileAttributes(lpwDirectoryPath) == -1) {
  347. //
  348. // Didn't exist - attempt to create the directory
  349. //
  350. if (!CreateDirectory(lpwDirectoryPath, NULL)) {
  351. Print(ERROR, L"[InstallPrepareDirectory] Failed to create directory %s\n",
  352. lpwDirectoryPath);
  353. return FALSE;
  354. }
  355. }
  356. //
  357. // Build a path to the parent based on it's child
  358. //
  359. lpwParentPath = (LPWSTR) MALLOC((wcslen(lpwDirectoryPath)+1)*sizeof(WCHAR));
  360. if (NULL == lpwParentPath) {
  361. return FALSE;
  362. }
  363. wcscpy(lpwParentPath, lpwDirectoryPath);
  364. lpwEnd = wcsrchr(lpwParentPath, '\\');
  365. if (lpwEnd) {
  366. *lpwEnd = 0;
  367. }
  368. //
  369. // Adjust the permissions on the new directory
  370. // to match the parent
  371. //
  372. fReturn = MirrorDirectoryPerms(lpwParentPath,
  373. lpwDirectoryPath);
  374. if (!fReturn) {
  375. Print(ERROR,
  376. L"[InstallPrepareDirectory] Failed to mirror permissions from %s to %s\n",
  377. lpwParentPath, lpwDirectoryPath);
  378. return FALSE;
  379. }
  380. SetFileAttributes(lpwDirectoryPath, dwAttributes);
  381. return TRUE;
  382. }
  383. /*++
  384. Routine Description:
  385. Performs the backup of files that get
  386. replaced during install
  387. Arguments:
  388. None
  389. Return Value:
  390. TRUE on success, FALSE otherwise
  391. --*/
  392. BOOL
  393. InstallBackupFiles()
  394. {
  395. WCHAR wszBackupDir[MAX_PATH] = L"";
  396. WCHAR wszSourceFileName[MAX_PATH] = L"";
  397. WCHAR wszBackupFileName[MAX_PATH] = L"";
  398. char szEntry[MAX_PATH] = "";
  399. WCHAR wszEntry[MAX_PATH] = L"";
  400. char szFileName[MAX_PATH] = "";
  401. WCHAR wszFileName[MAX_PATH] = L"";
  402. WCHAR wszRestoreSection[MAX_PATH] = L"";
  403. WCHAR wszKey[10] = L"";
  404. BOOL fReturn = FALSE, fResult = FALSE;
  405. LPWSTR lpwDestDir = NULL;
  406. UINT uCount = 0;
  407. INFCONTEXT InfContext;
  408. //
  409. // Remove any previous backup directories
  410. // Don't check the return as it's not critical
  411. // that this happen successfully
  412. //
  413. wsprintf(wszBackupDir, L"%s\\Backup", g_si.lpwInstallDirectory);
  414. CommonRemoveDirectoryAndFiles(wszBackupDir, (PVOID) FALSE, FALSE, FALSE);
  415. wszBackupDir[0] = 0;
  416. wsprintf(wszBackupDir,
  417. L"%s\\%s",
  418. g_si.lpwInstallDirectory,
  419. g_si.lpwUninstallDirectory);
  420. CommonRemoveDirectoryAndFiles(wszBackupDir, (PVOID) FALSE, FALSE, FALSE);
  421. //
  422. // Prepare the new backup directory
  423. //
  424. fReturn = InstallPrepareDirectory(wszBackupDir,
  425. FILE_ATTRIBUTE_HIDDEN);
  426. if (!fReturn) {
  427. return FALSE;
  428. }
  429. //
  430. // Step through each entry in the queue
  431. //
  432. while (g_si.BackupFileQueue.GetSize()) {
  433. g_si.BackupFileQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
  434. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  435. //
  436. // Get the destination directory
  437. //
  438. GetNextToken(wszEntry, L".");
  439. GetNextToken(NULL, L".");
  440. lpwDestDir = GetNextToken(NULL, L".");
  441. if (NULL == lpwDestDir) {
  442. return FALSE;
  443. }
  444. //
  445. // Loop through all the lines in the backup files section(s),
  446. // and perform the backup
  447. //
  448. fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
  449. &InfContext) &&
  450. SetupGetLineTextA(&InfContext,
  451. NULL, NULL, NULL,
  452. szFileName, MAX_PATH, NULL);
  453. while (fReturn) {
  454. pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
  455. //
  456. // Build the path to the source file
  457. //
  458. wsprintf(wszSourceFileName,
  459. L"%s\\%s\\%s",
  460. g_si.lpwWindowsDirectory,
  461. lpwDestDir,
  462. wszFileName);
  463. //
  464. // Ensure that the source file exists
  465. //
  466. fResult = PathFileExists(wszSourceFileName);
  467. if (fResult) {
  468. //
  469. // Ensure that this file is not under WFP
  470. //
  471. fResult = IsFileProtected(wszSourceFileName);
  472. //
  473. // Build a path to the backup file
  474. //
  475. wsprintf(wszBackupFileName,
  476. L"%s\\%s",
  477. wszBackupDir,
  478. wszFileName);
  479. //
  480. // Backup the file - be sensitive to WFP
  481. //
  482. if (fResult) {
  483. fResult = ForceCopy(wszSourceFileName, wszBackupFileName);
  484. if (!fResult) {
  485. Print(ERROR, L"[InstallBackupFiles] Failed to copy %s to %s\n",
  486. wszSourceFileName, wszBackupFileName);
  487. return FALSE;
  488. }
  489. } else {
  490. fResult = ForceMove(wszSourceFileName, wszBackupFileName);
  491. if (!fResult) {
  492. Print(ERROR, L"[InstallBackupFiles] Failed to move %s to %s\n",
  493. wszSourceFileName, wszBackupFileName);
  494. return FALSE;
  495. }
  496. }
  497. //
  498. // Now save an entry to the INF
  499. //
  500. wsprintf(wszRestoreSection, L"Restore.Files.%s", lpwDestDir);
  501. wsprintf(wszKey, L"%u", ++uCount);
  502. SaveEntryToINF(wszRestoreSection,
  503. wszKey,
  504. wszFileName,
  505. g_si.lpwUninstallINFPath);
  506. }
  507. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  508. SetupGetLineTextA(&InfContext,
  509. NULL, NULL, NULL,
  510. szFileName, MAX_PATH, NULL);
  511. }
  512. }
  513. return TRUE;
  514. }
  515. /*++
  516. Routine Description:
  517. Performs a backup of the specified registry
  518. keys during install
  519. Arguments:
  520. None
  521. Return Value:
  522. TRUE on success, FALSE otherwise
  523. --*/
  524. BOOL
  525. InstallBackupRegistryKeys()
  526. {
  527. BOOL fReturn = FALSE, fResult = FALSE;
  528. HKEY hKeyRoot = NULL;
  529. char szEntry[MAX_PATH] = "";
  530. WCHAR wszEntry[MAX_PATH] = L"";
  531. char szKeyPath[MAX_PATH*3] = "";
  532. WCHAR wszKeyPath[MAX_PATH*3] = L"";
  533. WCHAR wszBackupFile[MAX_PATH] = L"";
  534. WCHAR wszKey[10] = L"";
  535. WCHAR wszEntryToSave[MAX_PATH*2] = L"";
  536. LPWSTR lpwKeyPart = NULL, lpwKeyRoot = NULL;
  537. UINT uCount = 0;
  538. CRegistry creg;
  539. INFCONTEXT InfContext;
  540. //
  541. // Step through each entry in the queue
  542. //
  543. while (g_si.BackupRegistryQueue.GetSize()) {
  544. g_si.BackupRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
  545. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  546. //
  547. // Loop through all the lines in the backup registry section(s),
  548. // and perform the backup
  549. //
  550. fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
  551. &InfContext) &&
  552. SetupGetLineTextA(&InfContext,
  553. NULL, NULL, NULL,
  554. szKeyPath, MAX_PATH, NULL);
  555. while (fReturn) {
  556. pAnsiToUnicode(szKeyPath, wszKeyPath, MAX_PATH*3);
  557. //
  558. // Split the key path into two separate parts
  559. //
  560. lpwKeyRoot = GetNextToken(wszKeyPath, L",");
  561. if (NULL == lpwKeyRoot) {
  562. break;
  563. }
  564. if (!_wcsicmp(lpwKeyRoot, L"HKLM")) {
  565. hKeyRoot = HKEY_LOCAL_MACHINE;
  566. } else if (!_wcsicmp(lpwKeyRoot, L"HKCR")) {
  567. hKeyRoot = HKEY_CLASSES_ROOT;
  568. } else if (!_wcsicmp(lpwKeyRoot, L"HKCU")) {
  569. hKeyRoot = HKEY_CURRENT_USER;
  570. } else if (!_wcsicmp(lpwKeyRoot, L"HKU")) {
  571. hKeyRoot = HKEY_USERS;
  572. } else {
  573. break;
  574. }
  575. lpwKeyPart = GetNextToken(NULL, L",");
  576. if (NULL == lpwKeyPart) {
  577. break;
  578. }
  579. //
  580. // Verify that the specified key exists
  581. //
  582. fResult = creg.IsRegistryKeyPresent(hKeyRoot, lpwKeyPart);
  583. if (fResult) {
  584. //
  585. // Build a path to the file for the backup
  586. // and backup the key
  587. //
  588. wsprintf(wszBackupFile,
  589. L"%s\\%s\\Regbkp%u",
  590. g_si.lpwInstallDirectory,
  591. g_si.lpwUninstallDirectory,
  592. ++uCount);
  593. fResult = creg.BackupRegistryKey(hKeyRoot, lpwKeyPart, wszBackupFile, TRUE);
  594. if (!fResult) {
  595. Print(ERROR,
  596. L"[InstallBackupRegistryKeys] Failed to backup key %s to %s\n",
  597. lpwKeyPart, wszBackupFile);
  598. return FALSE;
  599. }
  600. //
  601. // Now save an entry to the queue for the uninstall INF
  602. // We need one for deletion and restoration
  603. //
  604. wsprintf(wszEntryToSave, L"%s,%s", lpwKeyRoot, lpwKeyPart);
  605. wsprintf(wszKey, L"%u", ++uCount);
  606. SaveEntryToINF(INF_DELETE_REGISTRYW,
  607. wszKey,
  608. wszEntryToSave,
  609. g_si.lpwUninstallINFPath);
  610. wsprintf(wszEntryToSave, L"%s,%s,%s", lpwKeyRoot, lpwKeyPart, wszBackupFile);
  611. SaveEntryToINF(INF_RESTORE_REGISTRYW,
  612. wszKey,
  613. wszEntryToSave,
  614. g_si.lpwUninstallINFPath);
  615. }
  616. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  617. SetupGetLineTextA(&InfContext,
  618. NULL, NULL, NULL,
  619. szKeyPath, MAX_PATH, NULL);
  620. }
  621. }
  622. return TRUE;
  623. }
  624. /*++
  625. Routine Description:
  626. Performs the file copy operations
  627. Arguments:
  628. None
  629. Return Value:
  630. TRUE on success, FALSE otherwise
  631. --*/
  632. BOOL
  633. InstallCopyFiles()
  634. {
  635. WCHAR wszBackupDir[MAX_PATH] = L"";
  636. WCHAR wszDestFileName[MAX_PATH] = L"";
  637. WCHAR wszSourceFileName[MAX_PATH] = L"";
  638. char szEntry[MAX_PATH] = "";
  639. WCHAR wszEntry[MAX_PATH] = L"";
  640. char szFileName[MAX_PATH] = "";
  641. WCHAR wszFileName[MAX_PATH] = L"";
  642. BOOL fReturn = FALSE, fResult = FALSE;
  643. LPWSTR lpwDestDir = NULL;
  644. DWORDLONG dwlSourceVersion = 0, dwlDestVersion = 0;
  645. INFCONTEXT InfContext;
  646. //
  647. // Step through each entry in the queue
  648. //
  649. while (g_si.CopyFileQueue.GetSize()) {
  650. g_si.CopyFileQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
  651. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  652. //
  653. // Get the destination directory
  654. //
  655. GetNextToken(wszEntry, L".");
  656. GetNextToken(NULL, L".");
  657. lpwDestDir = GetNextToken(NULL, L".");
  658. if (NULL == lpwDestDir) {
  659. break;
  660. }
  661. //
  662. // Loop through all the lines in the copy files section(s),
  663. // and perform the copy
  664. //
  665. fReturn = SetupFindFirstLineA(g_si.hInf, szEntry, NULL,
  666. &InfContext) &&
  667. SetupGetLineTextA(&InfContext,
  668. NULL, NULL, NULL,
  669. szFileName, MAX_PATH, NULL);
  670. while (fReturn) {
  671. pAnsiToUnicode(szFileName, wszFileName, MAX_PATH);
  672. //
  673. // Build the path to the destination file
  674. //
  675. wsprintf(wszDestFileName,
  676. L"%s\\%s\\%s",
  677. g_si.lpwWindowsDirectory,
  678. lpwDestDir,
  679. wszFileName);
  680. //
  681. // Build the path to the source file
  682. //
  683. wsprintf(wszSourceFileName,
  684. L"%s\\%s",
  685. g_si.lpwExtractPath,
  686. wszFileName);
  687. //
  688. // Get version information from the source and destination
  689. //
  690. if (!GetVersionInfoFromImage(wszSourceFileName, &dwlSourceVersion)) {
  691. Print(TRACE, L"[InstallCopyFiles] Failed to get version info from %s\n",
  692. wszSourceFileName);
  693. dwlSourceVersion = 0;
  694. }
  695. if (!GetVersionInfoFromImage(wszDestFileName, &dwlDestVersion)) {
  696. Print(TRACE, L"[InstallCopyFiles] Failed to get version info from %s\n",
  697. wszDestFileName);
  698. dwlDestVersion = 0;
  699. }
  700. //
  701. // If neither file had version information, perform the copy.
  702. // If the target version is less than the source version,
  703. // perform the copy.
  704. // Otherwise, move to the next file
  705. //
  706. if ((dwlSourceVersion == 0 && dwlDestVersion == 0) ||
  707. (dwlDestVersion <= dwlSourceVersion)) {
  708. //
  709. // Ensure that this file is not under WFP
  710. //
  711. fResult = IsFileProtected(wszDestFileName);
  712. //
  713. // Copy the file - be sensitive to WFP
  714. //
  715. if (fResult) {
  716. Print(TRACE,
  717. L"[InstallCopyFiles] Preparing to install WFP file from %s to %s\n",
  718. wszSourceFileName, wszDestFileName);
  719. fResult = CommonEnableProtectedRenames();
  720. if (!fResult) {
  721. return FALSE;
  722. }
  723. fResult = InstallWFPFile(wszSourceFileName,
  724. wszFileName,
  725. wszDestFileName,
  726. g_si.fUpdateDllCache);
  727. if (!fResult) {
  728. return FALSE;
  729. }
  730. } else {
  731. Print(TRACE,
  732. L"[InstallCopyFiles] Preparing to install file from %s to %s\n",
  733. wszSourceFileName, wszDestFileName);
  734. fResult = ForceCopy(wszSourceFileName, wszDestFileName);
  735. if (!fResult) {
  736. Print(ERROR,
  737. L"[InstallCopyFiles] Failed to install file from %s to %s\n",
  738. wszSourceFileName, wszDestFileName);
  739. return FALSE;
  740. }
  741. }
  742. } else {
  743. break;
  744. }
  745. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  746. SetupGetLineTextA(&InfContext,
  747. NULL, NULL, NULL,
  748. szFileName, MAX_PATH, NULL);
  749. }
  750. }
  751. return TRUE;
  752. }
  753. /*++
  754. Routine Description:
  755. Installs a file that is protected
  756. by WFP
  757. Arguments:
  758. lpwSourceFileName - Path to the source file
  759. lpwDestFileName - Name of the destination file
  760. lpwDestFileNamePath - Name & path to the destination file
  761. fUpdateDllCache - A flag to indicate if the file
  762. should be placed in the DllCache directory
  763. Return Value:
  764. TRUE on success, FALSE otherwise
  765. --*/
  766. BOOL
  767. InstallWFPFile(
  768. IN LPCWSTR lpwSourceFileName,
  769. IN LPCWSTR lpwDestFileName,
  770. IN LPCWSTR lpwDestFileNamePath,
  771. IN BOOL fUpdateDllCache
  772. )
  773. {
  774. LPWSTR lpwCachePath = NULL;
  775. LPWSTR lpwExpandedCachePath = NULL;
  776. LPWSTR lpwTempFileName = NULL;
  777. DWORD cbSize = 0;
  778. WCHAR wszDllCachePath[MAX_PATH] = L"";
  779. WCHAR wszExtraFilePath[MAX_PATH] = L"";
  780. WCHAR wszExtraFileName[MAX_PATH] = L"";
  781. WCHAR wszOldSourcesPath[MAX_PATH] = L"";
  782. CRegistry creg;
  783. BOOL fAddedToReg = FALSE, fReturn = FALSE;
  784. if (fUpdateDllCache) {
  785. //
  786. // Try to get the dllcache directory path from
  787. // the registry
  788. //
  789. lpwCachePath = creg.GetString(HKEY_LOCAL_MACHINE,
  790. REG_WINFP_PATH,
  791. L"SfcDllCacheDir",
  792. TRUE);
  793. if (lpwCachePath) {
  794. if (cbSize = ExpandEnvironmentStrings(lpwCachePath,
  795. lpwExpandedCachePath,
  796. 0)) {
  797. lpwExpandedCachePath = (LPWSTR) MALLOC(cbSize*sizeof(WCHAR));
  798. if (lpwExpandedCachePath) {
  799. if (ExpandEnvironmentStrings(lpwCachePath,
  800. lpwExpandedCachePath,
  801. cbSize)) {
  802. //
  803. // Build a full path to \%windir%\system32\dllcache\filename.xxx
  804. //
  805. wsprintf(wszDllCachePath,
  806. L"%s\\%s",
  807. lpwExpandedCachePath,
  808. lpwDestFileName);
  809. }
  810. }
  811. }
  812. }
  813. //
  814. // If we couldn't get it from that key, try another
  815. //
  816. if (NULL == lpwExpandedCachePath) {
  817. lpwCachePath = creg.GetString(HKEY_LOCAL_MACHINE,
  818. REG_WINLOGON_PATH,
  819. L"SfcDllCacheDir",
  820. TRUE);
  821. if (lpwCachePath) {
  822. if (cbSize = ExpandEnvironmentStrings(lpwCachePath,
  823. lpwExpandedCachePath,
  824. 0)) {
  825. lpwExpandedCachePath = (LPWSTR) MALLOC(cbSize*sizeof(WCHAR));
  826. if (lpwExpandedCachePath) {
  827. if (ExpandEnvironmentStrings(lpwCachePath,
  828. lpwExpandedCachePath,
  829. cbSize)) {
  830. //
  831. // Build a full path to \%windir%\system32\dllcache\filename.xxx
  832. //
  833. wsprintf(wszDllCachePath,
  834. L"%s\\%s",
  835. lpwExpandedCachePath,
  836. lpwDestFileName);
  837. }
  838. }
  839. }
  840. }
  841. }
  842. //
  843. // If neither key worked, build the path manually
  844. //
  845. if (NULL == lpwExpandedCachePath) {
  846. wsprintf(wszDllCachePath,
  847. L"%s\\DllCache\\%s",
  848. g_si.lpwSystem32Directory,
  849. lpwDestFileName);
  850. }
  851. //
  852. // Replace the file in the DllCache directory
  853. //
  854. if (!CopyFile(lpwSourceFileName, wszDllCachePath, FALSE)) {
  855. Print(ERROR,
  856. L"[InstallWFPFile] Failed to copy %s to %s\n",
  857. lpwSourceFileName, wszDllCachePath);
  858. goto cleanup;
  859. return FALSE;
  860. }
  861. }
  862. //
  863. // Put an additional copy in 'Sources' under the install dir
  864. // The return is not critical for this operation
  865. //
  866. wsprintf(wszExtraFilePath, L"%s\\$Sources$", g_si.lpwInstallDirectory);
  867. wsprintf(wszOldSourcesPath, L"%s\\Sources", g_si.lpwInstallDirectory);
  868. CommonRemoveDirectoryAndFiles(wszExtraFilePath, (PVOID) FALSE, FALSE, FALSE);
  869. InstallPrepareDirectory(wszExtraFilePath,
  870. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
  871. wcscpy(wszExtraFileName, wszExtraFilePath);
  872. wcscat(wszExtraFileName, L"\\");
  873. wcscat(wszExtraFileName, lpwDestFileName);
  874. if (!CopyFile(lpwSourceFileName, wszExtraFileName, FALSE)) {
  875. Print(ERROR,
  876. L"[InstallWFPFile] Failed to copy %s to %s\n",
  877. lpwSourceFileName, wszExtraFileName);
  878. }
  879. if (!g_si.fSourceDirAdded) {
  880. //
  881. // Remove any old source path that may exist
  882. //
  883. creg.RemoveStringFromMultiSz(HKEY_LOCAL_MACHINE,
  884. REG_INSTALL_SOURCES,
  885. L"Installation Sources",
  886. wszOldSourcesPath,
  887. TRUE);
  888. creg.RemoveStringFromMultiSz(HKEY_LOCAL_MACHINE,
  889. REG_INSTALL_SOURCES,
  890. L"Installation Sources",
  891. wszExtraFilePath,
  892. TRUE);
  893. fReturn = creg.AddStringToMultiSz(HKEY_LOCAL_MACHINE,
  894. REG_INSTALL_SOURCES,
  895. L"Installation Sources",
  896. wszExtraFilePath,
  897. TRUE);
  898. if (!fReturn) {
  899. Print(ERROR,
  900. L"[InstallWFPFile] Failed to add %s to registry\n",
  901. wszExtraFilePath);
  902. }
  903. g_si.fSourceDirAdded = TRUE;
  904. }
  905. //
  906. // The catalog file won't vouch for WFP files until
  907. // the next reboot. Put the file down and let the
  908. // Session Manager rename them
  909. //
  910. lpwTempFileName = CopyTempFile(lpwSourceFileName,
  911. g_si.lpwSystem32Directory);
  912. if (NULL == lpwTempFileName) {
  913. Print(ERROR, L"[InstallWFPFile] Failed to get temp file\n");
  914. goto cleanup;
  915. return FALSE;
  916. }
  917. if (!MoveFileEx(lpwTempFileName,
  918. lpwDestFileNamePath,
  919. MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT)) {
  920. Print(ERROR, L"[InstallWFPFile] Failed to delay replace from %s to %s\n",
  921. lpwTempFileName, lpwDestFileNamePath);
  922. goto cleanup;
  923. return FALSE;
  924. }
  925. cleanup:
  926. if (lpwTempFileName) {
  927. FREE(lpwTempFileName);
  928. }
  929. if (lpwExpandedCachePath) {
  930. FREE(lpwExpandedCachePath);
  931. }
  932. return TRUE;
  933. }
  934. /*++
  935. Routine Description:
  936. Retrieves the section names from the installation
  937. INF file. This dictates what operations will be
  938. performed during install
  939. Arguments:
  940. None
  941. Return Value:
  942. TRUE on success, FALSE otherwise
  943. --*/
  944. BOOL
  945. InstallGetSectionsFromINF()
  946. {
  947. BOOL fReturn = FALSE;
  948. DWORD dwType = 0;
  949. char szSectionName[MAX_QUEUE_SIZE] = "";
  950. char *pSectionName;
  951. WCHAR wszDirective[MAX_PATH] = L"";
  952. INFCONTEXT InfContext;
  953. //
  954. // Loop through all the lines in the Sections section(s),
  955. //
  956. fReturn = SetupFindFirstLineA(g_si.hInf, INF_MASTER_SECTIONS, NULL,
  957. &InfContext) &&
  958. SetupGetLineTextA(&InfContext,
  959. NULL, NULL, NULL,
  960. szSectionName, MAX_QUEUE_SIZE, NULL);
  961. while (fReturn) {
  962. //
  963. // Determine which section we're working with
  964. //
  965. if (strstr(szSectionName, INF_BACKUP_FILES)) {
  966. dwType = dwBackupFiles;
  967. } else if (strstr(szSectionName, INF_BACKUP_REGISTRY)) {
  968. dwType = dwBackupRegistry;
  969. } else if (strstr(szSectionName, INF_DELETE_REGISTRY)) {
  970. dwType = dwDeleteRegistry;
  971. } else if (strstr(szSectionName, INF_COPY_FILES)) {
  972. dwType = dwCopyFiles;
  973. } else if (strstr(szSectionName, INF_REGISTRATIONS)) {
  974. dwType = dwRegistrations;
  975. } else if (strstr(szSectionName, INF_EXCLUDE)) {
  976. dwType = dwExclusionsInstall;
  977. } else if (strstr(szSectionName, INF_ADD_REGISTRY)) {
  978. dwType = dwAddRegistry;
  979. } else {
  980. Print(ERROR,
  981. L"[InstallGetSectionsFromINF] Illegal section name passed %s\n",
  982. szSectionName);
  983. return FALSE; // illegal section name
  984. }
  985. pSectionName = strtok(szSectionName, ",");
  986. do {
  987. pAnsiToUnicode(pSectionName, wszDirective, MAX_PATH);
  988. //
  989. // Loop through each section name and add it to the
  990. // appropriate queue
  991. //
  992. switch (dwType) {
  993. case dwBackupFiles:
  994. g_si.BackupFileQueue.Enqueue(wszDirective);
  995. break;
  996. case dwBackupRegistry:
  997. g_si.BackupRegistryQueue.Enqueue(wszDirective);
  998. break;
  999. case dwDeleteRegistry:
  1000. g_si.DeleteRegistryQueue.Enqueue(wszDirective);
  1001. break;
  1002. case dwCopyFiles:
  1003. g_si.CopyFileQueue.Enqueue(wszDirective);
  1004. break;
  1005. case dwRegistrations:
  1006. g_si.RegistrationQueue.Enqueue(wszDirective);
  1007. break;
  1008. case dwExclusionsInstall:
  1009. g_si.ExclusionQueue.Enqueue(wszDirective);
  1010. break;
  1011. case dwAddRegistry:
  1012. g_si.AddRegistryQueue.Enqueue(wszDirective);
  1013. break;
  1014. default:
  1015. return FALSE; // illegal section name
  1016. }
  1017. pSectionName = strtok(NULL, ",");
  1018. } while (NULL != pSectionName);
  1019. fReturn = SetupFindNextLine(&InfContext, &InfContext) &&
  1020. SetupGetLineTextA(&InfContext,
  1021. NULL, NULL, NULL,
  1022. szSectionName, MAX_QUEUE_SIZE, NULL);
  1023. }
  1024. return TRUE;
  1025. }
  1026. /*++
  1027. Routine Description:
  1028. Merges the registry data from the INF
  1029. into the registry
  1030. Arguments:
  1031. None
  1032. Return Value:
  1033. TRUE on success, FALSE otherwise
  1034. --*/
  1035. BOOL
  1036. InstallRegistryData()
  1037. {
  1038. BOOL fReturn = FALSE;
  1039. char szEntry[MAX_PATH] = "";
  1040. WCHAR wszEntry[MAX_PATH] = L"";
  1041. //
  1042. // Step through each entry in the queue
  1043. //
  1044. while (g_si.AddRegistryQueue.GetSize()) {
  1045. g_si.AddRegistryQueue.Dequeue(wszEntry, MAX_PATH - 1, FALSE);
  1046. pUnicodeToAnsi(wszEntry, szEntry, MAX_PATH);
  1047. //
  1048. // Merge all the registry data from the INF
  1049. //
  1050. fReturn = SetupInstallFromInfSectionA(NULL,
  1051. g_si.hInf,
  1052. szEntry,
  1053. SPINST_REGISTRY,
  1054. NULL,
  1055. NULL,
  1056. 0,
  1057. NULL,
  1058. NULL,
  1059. NULL,
  1060. NULL);
  1061. if (!fReturn) {
  1062. Print(ERROR, L"[InstallRegistryData] Failed to merge registry data\n");
  1063. return FALSE;
  1064. }
  1065. }
  1066. return TRUE;
  1067. }