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.

3131 lines
90 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Spntfix.c
  5. Abstract:
  6. This module contains code to repair winnt installations.
  7. Author:
  8. Shie-Lin Tzong (shielint) 27-Jan-1994
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. //
  14. // Path to the ntuser.dat hive
  15. //
  16. #define DEFAULT_USER_PATH L"Users\\Default User"
  17. //
  18. // Global variables control which repair options should be performed.
  19. // Initialized to ALL options. We explicitly use 1 and 0 for true and false.
  20. //
  21. #ifdef _X86_
  22. ULONG RepairItems[RepairItemMax] = { 0, 0, 0}; // BCL - Seagate - removed one.
  23. #else
  24. ULONG RepairItems[RepairItemMax] = { 0, 0}; // BCL
  25. #endif
  26. PVOID RepairGauge = NULL;
  27. //
  28. // global variables for delayed driver CAB opening during
  29. // repair
  30. //
  31. extern PWSTR gszDrvInfDeviceName;
  32. extern PWSTR gszDrvInfDirName;
  33. extern HANDLE ghSif;
  34. #define ATTR_RHS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
  35. //**************************************************************
  36. // S E L E C T I N G N T T O REPAIR S T U F F
  37. //**************************************************************
  38. #define MENU_LEFT_X 3
  39. #define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
  40. #define LIST_BOX_WIDTH 50
  41. #define LIST_BOX_HEIGHT RepairItemMax+1
  42. #define HIVE_LIST_BOX_WIDTH 45
  43. #define HIVE_LIST_BOX_HEIGHT RepairHiveMax+1
  44. #define MENU_INDENT 4
  45. VOID
  46. SppGetRepairPathInformation(
  47. IN PVOID LogFileHandle,
  48. OUT PWSTR *SystemPartition,
  49. OUT PWSTR *SystemPartitionDirectory,
  50. OUT PWSTR *WinntPartition,
  51. OUT PWSTR *WinntPartitionDirectory
  52. )
  53. /*++
  54. Routine Description:
  55. This goes through the list of NTs on the system and finds out which are
  56. repairable. Presents the information to the user.
  57. Arguments:
  58. SifHandle - Handle the txtsetup.sif
  59. SystemPartition - Supplies a variable to receive the name of System
  60. partition.
  61. SystemPartitionDirectory - Supplies a variable to receive the name of
  62. the osloader directory on the system partition.
  63. WinntPartition - Supplies a variable to receive the name of winnt
  64. partition.
  65. WinntPartitionDirectory - Supplies a variable to receive the winnt
  66. directory.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. PWSTR KeyName = NULL;
  72. *SystemPartition = SpGetSectionKeyIndex (LogFileHandle,
  73. SIF_NEW_REPAIR_PATHS,
  74. SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE,
  75. 0);
  76. if (*SystemPartition == NULL) {
  77. KeyName = SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE;
  78. goto ReportError;
  79. }
  80. *SystemPartitionDirectory = SpGetSectionKeyIndex (LogFileHandle,
  81. SIF_NEW_REPAIR_PATHS,
  82. SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DIRECTORY,
  83. 0);
  84. if (*SystemPartitionDirectory == NULL) {
  85. KeyName = SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DIRECTORY;
  86. goto ReportError;
  87. }
  88. *WinntPartition = SpGetSectionKeyIndex ( LogFileHandle,
  89. SIF_NEW_REPAIR_PATHS,
  90. SIF_NEW_REPAIR_PATHS_TARGET_DEVICE,
  91. 0);
  92. if (*WinntPartition == NULL) {
  93. KeyName = SIF_NEW_REPAIR_PATHS_TARGET_DEVICE;
  94. goto ReportError;
  95. }
  96. *WinntPartitionDirectory = SpGetSectionKeyIndex (LogFileHandle,
  97. SIF_NEW_REPAIR_PATHS,
  98. SIF_NEW_REPAIR_PATHS_TARGET_DIRECTORY,
  99. 0);
  100. if (*WinntPartitionDirectory == NULL) {
  101. KeyName = SIF_NEW_REPAIR_PATHS_TARGET_DIRECTORY;
  102. goto ReportError;
  103. }
  104. ReportError:
  105. if (KeyName) {
  106. //
  107. // Unable to find path information. This indicates the setup.log
  108. // is bad. Inform user and exit.
  109. //
  110. SpFatalSifError(LogFileHandle,SIF_NEW_REPAIR_PATHS,KeyName,0,0);
  111. }
  112. }
  113. BOOLEAN
  114. SpFindNtToRepair(
  115. IN PVOID SifHandle,
  116. OUT PDISK_REGION *TargetRegion,
  117. OUT PWSTR *TargetPath,
  118. OUT PDISK_REGION *SystemPartitionRegion,
  119. OUT PWSTR *SystemPartitionDirectory,
  120. OUT PBOOLEAN RepairableBootSetsFound
  121. )
  122. /*++
  123. Routine Description:
  124. This goes through the list of NTs on the system and finds out which are
  125. repairable. Presents the information to the user.
  126. Arguments:
  127. SifHandle: Handle the txtsetup.sif
  128. TargetRegion: Variable to receive the partition of the Windows NT to install
  129. NULL if not chosen.
  130. TargetPath: Variable to receive the target path of Windows NT. NULL if
  131. not decided.
  132. SystemPartitionRegion:
  133. Variable to receive the system partition of the Windows NT
  134. SystemPartitionDirectory:
  135. Variable to receive the osloader directory of the system
  136. partition.
  137. RepairableBootSetsFound:
  138. Indicates whether a repairable boot set was found. This
  139. information can be used by the caller when the function
  140. returns FALSE, so that the caller can determine if no
  141. repairable disk was found, or if the user didn't select
  142. any of the repairable systems found.
  143. Return Value:
  144. A boolean value to indicate if selection has been made.
  145. --*/
  146. {
  147. NT_PRODUCT_TYPE ProductType;
  148. BOOLEAN GoRepair = FALSE;
  149. NTSTATUS NtStatus;
  150. ULONG j, RepairBootSets = 0, MajorVersion, MinorVersion, BuildNumber, ProductSuiteMask;
  151. PSP_BOOT_ENTRY BootEntry;
  152. PSP_BOOT_ENTRY ChosenBootEntry;
  153. LCID LangId;
  154. UPG_PROGRESS_TYPE UpgradeProgressValue;
  155. //
  156. // Find all upgradeable boot entries. These are entries that are unique in
  157. // the boot entry list and are present on disk.
  158. //
  159. SpDetermineUniqueAndPresentBootEntries();
  160. for ( BootEntry = SpBootEntries; BootEntry != NULL ; BootEntry = BootEntry->Next ) {
  161. if (!BootEntry->Processable) {
  162. continue;
  163. }
  164. //
  165. // Reinitialize
  166. //
  167. BootEntry->Processable = FALSE;
  168. LangId = -1;
  169. //
  170. // try loading the registry and getting the following information
  171. // out of it:
  172. //
  173. // 1) Product type: WINNT | LANMANNT
  174. // 2) Major and Minor Version Number
  175. //
  176. // Based on the information, we will update the RepairableList.
  177. //
  178. NtStatus = SpDetermineProduct(
  179. BootEntry->OsPartitionDiskRegion,
  180. BootEntry->OsDirectory,
  181. &ProductType,
  182. &MajorVersion,
  183. &MinorVersion,
  184. &BuildNumber,
  185. &ProductSuiteMask,
  186. &UpgradeProgressValue,
  187. NULL,
  188. NULL, // Pid is not needed
  189. NULL, // ignore eval variation flag
  190. &LangId, // Language Id
  191. NULL // service pack not needed?
  192. );
  193. if(NT_SUCCESS(NtStatus)) {
  194. //
  195. // make sure we only try to repair a build that matches the CD we have inserted
  196. //
  197. BootEntry->Processable = SpDoBuildsMatch(
  198. SifHandle,
  199. BuildNumber,
  200. ProductType,
  201. ProductSuiteMask,
  202. AdvancedServer,
  203. SuiteType,
  204. LangId
  205. );
  206. if( BootEntry->Processable ) {
  207. RepairBootSets++;
  208. ChosenBootEntry = BootEntry;
  209. }
  210. }
  211. }
  212. //
  213. // Find out how many valid boot sets there are which we can repair
  214. //
  215. *RepairableBootSetsFound = (RepairBootSets != 0);
  216. if ( RepairBootSets == 1 ) {
  217. //
  218. // If it is a fresh attempt at upgrade ask the user if he
  219. // wants to upgrade or not
  220. //
  221. GoRepair = SppSelectNTSingleRepair(
  222. ChosenBootEntry->OsPartitionDiskRegion,
  223. ChosenBootEntry->OsDirectory,
  224. ChosenBootEntry->FriendlyName
  225. );
  226. } else if (RepairBootSets > 1) {
  227. //
  228. // Find out if the user wants to upgrade one of the Windows
  229. // NT found
  230. //
  231. GoRepair = SppSelectNTMultiRepair(
  232. &ChosenBootEntry
  233. );
  234. }
  235. //
  236. // Depending on upgrade selection made do the setup needed before
  237. // we do the upgrade
  238. //
  239. if (GoRepair) {
  240. PWSTR p1,p2,p3;
  241. ULONG u;
  242. //
  243. // Return the region we are goint to repair
  244. //
  245. *TargetRegion = ChosenBootEntry->OsPartitionDiskRegion;
  246. *TargetPath = SpDupStringW(ChosenBootEntry->OsDirectory);
  247. *SystemPartitionRegion = ChosenBootEntry->LoaderPartitionDiskRegion;
  248. //
  249. // Process the osloader variable to extract the system partition path.
  250. // The var vould be of the form ...partition(1)\os\nt\... or
  251. // ...partition(1)os\nt\...
  252. // So we search forward for the first \ and then backwards for
  253. // the closest ) to find the start of the directory. We then
  254. // search backwards in the resulting string for the last \ to find
  255. // the end of the directory.
  256. //
  257. p1 = ChosenBootEntry->LoaderFile;
  258. p2 = wcsrchr(p1, L'\\');
  259. if (p2 == NULL) {
  260. p2 = p1;
  261. }
  262. u = (ULONG)(p2 - p1);
  263. if(u == 0) {
  264. *SystemPartitionDirectory = SpDupStringW(L"");
  265. } else {
  266. p2 = p3 = SpMemAlloc((u+2)*sizeof(WCHAR));
  267. ASSERT(p3);
  268. if(*p1 != L'\\') {
  269. *p3++ = L'\\';
  270. }
  271. wcsncpy(p3, p1, u);
  272. p3[u] = 0;
  273. *SystemPartitionDirectory = p2;
  274. }
  275. }
  276. //
  277. // Do cleanup
  278. //
  279. CLEAR_CLIENT_SCREEN();
  280. return (GoRepair);
  281. }
  282. BOOLEAN
  283. SppSelectNTSingleRepair(
  284. IN PDISK_REGION Region,
  285. IN PWSTR OsLoadFileName,
  286. IN PWSTR LoadIdentifier
  287. )
  288. /*++
  289. Routine Description:
  290. Inform a user that Setup has found a previous Windows NT installation.
  291. The user has the option to repair this or cancel.
  292. Arguments:
  293. Region - Region descriptor for the NT found
  294. OsLoadFileName - Directory for the NT found
  295. LoadIdentifier - Multi boot load identifier used for this NT.
  296. Return Value:
  297. --*/
  298. {
  299. ULONG ValidKeys[] = { KEY_F3,ASCI_CR, ASCI_ESC, 0 };
  300. ULONG c;
  301. PWSTR TmpString = NULL;
  302. ASSERT(Region->PartitionedSpace);
  303. ASSERT(wcslen(OsLoadFileName) >= 2);
  304. if( Region->DriveLetter ) {
  305. swprintf( TemporaryBuffer,
  306. L"%wc:%ws",
  307. Region->DriveLetter,
  308. OsLoadFileName );
  309. TmpString = SpDupStringW( TemporaryBuffer );
  310. }
  311. while(1) {
  312. SpStartScreen(
  313. SP_SCRN_WINNT_REPAIR,
  314. 3,
  315. HEADER_HEIGHT+1,
  316. FALSE,
  317. FALSE,
  318. DEFAULT_ATTRIBUTE,
  319. (Region->DriveLetter)? TmpString : OsLoadFileName,
  320. LoadIdentifier
  321. );
  322. SpDisplayStatusOptions(
  323. DEFAULT_STATUS_ATTRIBUTE,
  324. SP_STAT_F3_EQUALS_EXIT,
  325. SP_STAT_ESC_EQUALS_CANCEL,
  326. SP_STAT_ENTER_EQUALS_REPAIR,
  327. 0
  328. );
  329. if( TmpString != NULL ) {
  330. SpMemFree( TmpString );
  331. }
  332. switch(c=SpWaitValidKey(ValidKeys,NULL,NULL)) {
  333. case KEY_F3:
  334. SpConfirmExit();
  335. break;
  336. case ASCI_CR:
  337. return(TRUE);
  338. default:
  339. //
  340. // must have entered ESC
  341. //
  342. return(FALSE);
  343. }
  344. }
  345. }
  346. BOOLEAN
  347. SppSelectNTMultiRepair(
  348. OUT PSP_BOOT_ENTRY *BootEntryChosen
  349. )
  350. {
  351. PVOID Menu;
  352. ULONG MenuTopY;
  353. ULONG ValidKeys[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
  354. ULONG Keypress;
  355. PSP_BOOT_ENTRY BootEntry,FirstRepairSet;
  356. while(1) {
  357. //
  358. // Display the text that goes above the menu on the partitioning screen.
  359. //
  360. SpDisplayScreen(SP_SCRN_WINNT_REPAIR_LIST,3,CLIENT_TOP+1);
  361. //
  362. // Calculate menu placement. Leave one blank line
  363. // and one line for a frame.
  364. //
  365. MenuTopY = NextMessageTopLine + (SplangQueryMinimizeExtraSpacing() ? 2 : 5);
  366. //
  367. // Create a menu.
  368. //
  369. Menu = SpMnCreate(
  370. MENU_LEFT_X,
  371. MenuTopY,
  372. MENU_WIDTH,
  373. VideoVars.ScreenHeight-MenuTopY-2-STATUS_HEIGHT
  374. );
  375. ASSERT(Menu);
  376. //
  377. // Build up a menu of partitions and free spaces.
  378. //
  379. FirstRepairSet = NULL;
  380. for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next ) {
  381. if( BootEntry->Processable ) {
  382. if( BootEntry->OsPartitionDiskRegion->DriveLetter ) {
  383. swprintf(
  384. TemporaryBuffer,
  385. L"%wc:%ws %ws",
  386. BootEntry->OsPartitionDiskRegion->DriveLetter,
  387. BootEntry->OsDirectory,
  388. BootEntry->FriendlyName
  389. );
  390. } else {
  391. swprintf(
  392. TemporaryBuffer,
  393. L"%ws %ws",
  394. BootEntry->OsDirectory,
  395. BootEntry->FriendlyName
  396. );
  397. }
  398. SpMnAddItem(Menu,
  399. TemporaryBuffer,
  400. MENU_LEFT_X+MENU_INDENT,
  401. MENU_WIDTH-(2*MENU_INDENT),
  402. TRUE,
  403. (ULONG_PTR)BootEntry
  404. );
  405. if(FirstRepairSet == NULL) {
  406. FirstRepairSet = BootEntry;
  407. }
  408. }
  409. }
  410. //
  411. // Initialize the status line.
  412. //
  413. SpDisplayStatusOptions(
  414. DEFAULT_STATUS_ATTRIBUTE,
  415. SP_STAT_F3_EQUALS_EXIT,
  416. SP_STAT_ESC_EQUALS_CANCEL,
  417. SP_STAT_ENTER_EQUALS_REPAIR,
  418. 0
  419. );
  420. //
  421. // Display the menu
  422. //
  423. SpMnDisplay(
  424. Menu,
  425. (ULONG_PTR)FirstRepairSet,
  426. TRUE,
  427. ValidKeys,
  428. NULL,
  429. NULL,
  430. &Keypress,
  431. (PULONG_PTR)BootEntryChosen
  432. );
  433. //
  434. // Now act on the user's selection.
  435. //
  436. switch(Keypress) {
  437. case KEY_F3:
  438. SpConfirmExit();
  439. break;
  440. case ASCI_CR:
  441. SpMnDestroy(Menu);
  442. return( TRUE );
  443. default:
  444. SpMnDestroy(Menu);
  445. return(FALSE);
  446. }
  447. SpMnDestroy(Menu);
  448. }
  449. }
  450. VOID
  451. SppRepairScreenRepaint(
  452. IN PWSTR FullSourcename, OPTIONAL
  453. IN PWSTR FullTargetname, OPTIONAL
  454. IN BOOLEAN RepaintEntireScreen
  455. )
  456. {
  457. UNREFERENCED_PARAMETER(FullTargetname);
  458. UNREFERENCED_PARAMETER(FullSourcename);
  459. //
  460. // Repaint the entire screen if necessary.
  461. //
  462. if(RepaintEntireScreen) {
  463. if( SpDrEnabled() ) {
  464. SpStartScreen( SP_SCRN_ASR_IS_EXAMINING, 0, 6, TRUE, FALSE, DEFAULT_ATTRIBUTE );
  465. }
  466. else {
  467. SpStartScreen( SP_SCRN_SETUP_IS_EXAMINING,0, 6, TRUE, FALSE, DEFAULT_ATTRIBUTE );
  468. }
  469. if(RepairGauge) {
  470. SpDrawGauge(RepairGauge);
  471. }
  472. }
  473. }
  474. BOOLEAN
  475. SpErDiskScreen(
  476. BOOLEAN *HasErDisk
  477. )
  478. /*++
  479. Routine Description:
  480. Ask user if user has emergency repair disk.
  481. Arguments:
  482. *HasErDisk - Indicates whether diskette will be used.
  483. Return Value:
  484. TRUE - User chose disk or diskless.
  485. FALSE - User wants to return to previous screen.
  486. --*/
  487. {
  488. ULONG ValidKeys[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
  489. ULONG MnemonicKeys[] = { MnemonicLocate, 0 };
  490. BOOLEAN Choosing;
  491. ULONG c;
  492. for (Choosing = TRUE; Choosing; ) {
  493. SpDisplayScreen(SP_SCRN_REPAIR_ASK_REPAIR_DISK,3,4);
  494. SpDisplayStatusOptions(
  495. DEFAULT_STATUS_ATTRIBUTE,
  496. SP_STAT_ENTER_EQUALS_CONTINUE,
  497. SP_STAT_L_EQUALS_LOCATE,
  498. SP_STAT_ESC_EQUALS_CANCEL,
  499. SP_STAT_F3_EQUALS_EXIT,
  500. 0
  501. );
  502. //
  503. // Wait for keypress. Valid keys:
  504. //
  505. // L = Do not use ER diskette, locate on hard disk
  506. // F3 = exit
  507. // ENTER = Use ER diskette
  508. // ESC = cancel, return to previous screen
  509. //
  510. SpInputDrain();
  511. switch(c=SpWaitValidKey(ValidKeys,NULL,MnemonicKeys)) {
  512. case ASCI_CR:
  513. //
  514. // User wants express setup.
  515. //
  516. *HasErDisk = TRUE;
  517. Choosing = FALSE;
  518. break;
  519. case (MnemonicLocate | KEY_MNEMONIC):
  520. //
  521. // User wants repair without diskette.
  522. //
  523. *HasErDisk = FALSE;
  524. Choosing = FALSE;
  525. break;
  526. case KEY_F3:
  527. //
  528. // User wants to exit.
  529. //
  530. SpConfirmExit();
  531. break;
  532. default:
  533. //
  534. // must be ESC
  535. //
  536. *HasErDisk = FALSE;
  537. Choosing = FALSE;
  538. return( FALSE );
  539. }
  540. }
  541. return( TRUE );
  542. }
  543. BOOLEAN
  544. SppRepairReportError(
  545. IN BOOLEAN AllowEsc,
  546. IN ULONG ErrorScreenId,
  547. IN ULONG SubErrorId,
  548. IN PWSTR SectionName,
  549. IN ULONG LineNumber,
  550. IN PBOOLEAN DoNotPromptAgain
  551. )
  552. /*++
  553. Routine Description:
  554. Inform a user that repair has encountered some kind of error.
  555. The user has the option to continue or exit.
  556. Arguments:
  557. AllowEsc - Supplies a BOOLEAN to indicate if ESC is allowed.
  558. ErrorScreenId - The SCREEN error message number.
  559. SubErrorId - the sub error number
  560. SectionName - the name of the section which error occured.
  561. LineNumber - the error line number within the specified section.
  562. Return Value:
  563. FALSE if ESC was pressed.
  564. --*/
  565. {
  566. ULONG ValidKeys0[] = { KEY_F3, ASCI_CR, 0 };
  567. ULONG ValidKeys1[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
  568. ULONG MnemonicKeys[] = { MnemonicRepairAll, 0 };
  569. PULONG ValidKeys;
  570. PULONG Mnemonics;
  571. ULONG c;
  572. PWSTR SubError;
  573. BOOLEAN rc;
  574. SubError = SpMemAlloc(512);
  575. //
  576. // Line numbers are 0-based. Want to display to user as 1-based.
  577. //
  578. LineNumber++;
  579. //
  580. // Fetch/format the suberror.
  581. //
  582. SpFormatMessage(SubError, 512, SubErrorId, SectionName, LineNumber);
  583. //
  584. // Display the error screen.
  585. //
  586. SpStartScreen(
  587. ErrorScreenId,
  588. 3,
  589. HEADER_HEIGHT+1,
  590. FALSE,
  591. FALSE,
  592. DEFAULT_ATTRIBUTE,
  593. SubError
  594. );
  595. SpMemFree(SubError);
  596. //
  597. // Display status options: enter to continue.
  598. //
  599. if (AllowEsc) {
  600. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  601. SP_STAT_ENTER_EQUALS_CONTINUE,
  602. SP_STAT_A_EQUALS_REPAIR_ALL,
  603. SP_STAT_ESC_EQUALS_SKIP_FILE,
  604. SP_STAT_F3_EQUALS_EXIT,
  605. 0);
  606. ValidKeys = ValidKeys1;
  607. Mnemonics = MnemonicKeys;
  608. if( DoNotPromptAgain != NULL ) {
  609. *DoNotPromptAgain = FALSE;
  610. }
  611. } else {
  612. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  613. SP_STAT_ENTER_EQUALS_CONTINUE,
  614. SP_STAT_F3_EQUALS_EXIT,
  615. 0);
  616. ValidKeys = ValidKeys0;
  617. Mnemonics = NULL;
  618. }
  619. //
  620. // Wait for the user to press enter.
  621. //
  622. switch(c=SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
  623. case KEY_F3:
  624. SpConfirmExit();
  625. break;
  626. case ASCI_CR:
  627. rc = TRUE;
  628. break;
  629. case ASCI_ESC:
  630. rc = FALSE;
  631. break;
  632. default:
  633. //
  634. // must be repair all mnemonic
  635. //
  636. ASSERT(c == (MnemonicRepairAll | KEY_MNEMONIC));
  637. if( DoNotPromptAgain != NULL ) {
  638. *DoNotPromptAgain = TRUE;
  639. }
  640. rc = TRUE;
  641. break;
  642. }
  643. CLEAR_CLIENT_SCREEN();
  644. return(rc);
  645. }
  646. BOOLEAN
  647. SpLoadRepairLogFile(
  648. IN PWCHAR Filename,
  649. OUT PVOID *Handle
  650. )
  651. /*++
  652. Routine Description:
  653. Load repair text file (setup.log) into memory.
  654. Arguments:
  655. Filename - Supplies full filename (in NT namespace) of the file to
  656. be loaded.
  657. Handle - receives handle to loaded file, which can be
  658. used in subsequent calls to other text file services.
  659. Return Value:
  660. BOOLEAN value to indicate if the setup.log is processed.
  661. --*/
  662. {
  663. NTSTATUS Status;
  664. PWSTR Version;
  665. ULONG ErrorSubId;
  666. ULONG ErrorLine;
  667. //
  668. // Load setup.log
  669. //
  670. Status = SpLoadSetupTextFile(
  671. Filename,
  672. NULL, // No image already in memory
  673. 0, // Image size is empty
  674. Handle,
  675. &ErrorLine,
  676. TRUE,
  677. FALSE
  678. );
  679. if(!NT_SUCCESS(Status)) {
  680. if(Status == STATUS_UNSUCCESSFUL) {
  681. //
  682. // Syntax error in setup.log file
  683. //
  684. ErrorSubId = SP_TEXT_REPAIR_INF_ERROR_1;
  685. } else {
  686. //
  687. // Unable to load setup.log file
  688. //
  689. ErrorLine = 0;
  690. ErrorSubId = SP_TEXT_REPAIR_INF_ERROR_0;
  691. }
  692. SppRepairReportError(FALSE,
  693. SP_SCRN_REPAIR_INF_ERROR,
  694. ErrorSubId,
  695. NULL,
  696. ErrorLine,
  697. NULL );
  698. *Handle = NULL;
  699. return (FALSE);
  700. }
  701. //
  702. // Check if this setup.log file is for Winnt 3.5
  703. //
  704. Version = SpGetSectionKeyIndex(*Handle,
  705. SIF_NEW_REPAIR_SIGNATURE,
  706. SIF_NEW_REPAIR_VERSION_KEY,
  707. 0); // should be moved to spsif.c
  708. if(Version == NULL) {
  709. SppRepairReportError(FALSE,
  710. SP_SCRN_REPAIR_INF_ERROR,
  711. SP_TEXT_REPAIR_INF_ERROR_2,
  712. NULL,
  713. 0,
  714. NULL);
  715. } else {
  716. if(!_wcsicmp(Version,SIF_NEW_REPAIR_NT_VERSION)) {
  717. return(TRUE);
  718. } else {
  719. SppRepairReportError(FALSE,
  720. SP_SCRN_REPAIR_INF_ERROR,
  721. SP_TEXT_REPAIR_INF_ERROR_5,
  722. NULL,
  723. 0,
  724. NULL);
  725. }
  726. }
  727. //
  728. // Control comes here only when error occurs ...
  729. //
  730. SpFreeTextFile(*Handle);
  731. *Handle = NULL;
  732. return(FALSE);
  733. }
  734. VOID
  735. SpRepairDiskette(
  736. OUT PVOID *SifHandle,
  737. OUT PDISK_REGION *TargetRegion,
  738. OUT PWSTR *TargetPath,
  739. OUT PDISK_REGION *SystemPartitionRegion,
  740. OUT PWSTR *SystemPartitionDirectory
  741. )
  742. /*++
  743. Routine Description:
  744. This routine checks if there is a floppy drive. If no, it returns
  745. silently. Otherwise, it prompts user for Emergency Repair Disk.
  746. Arguments:
  747. SifHandle - Supplies a variable to receive the setup.log file handle.
  748. TargetRegion - Supplies a variable to receive the pointer to the target
  749. installation region.
  750. TargetPath - Supplies a variable to receive the nt name of target path.
  751. SystemPartitionRegion - Supplies a variable to receive the pointer of the
  752. system partition region.
  753. SystemPartitionDirectory - Supplies a variable to receive the osloader
  754. directory name on the system partition.
  755. Return Value:
  756. None.
  757. --*/
  758. {
  759. PWSTR szDiskName;
  760. BOOLEAN b, rc = FALSE;
  761. PWSTR FullLogFilename, p, FloppyDevicePath = L"\\device\\floppy0";
  762. PWSTR SystemPartition, WinntPartition;
  763. //
  764. // Assume failure.
  765. //
  766. *SifHandle = NULL;
  767. //
  768. // Always want to prompt for the disk in A:.
  769. // First, check if there is an A:. If no floppy drive,
  770. // simply skip the request for ER diskette.
  771. //
  772. if(SpGetFloppyDriveType(0) == FloppyTypeNone) {
  773. return;
  774. }
  775. //
  776. // Fetch the generic repair disk name.
  777. //
  778. SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_REPAIR_DISK_NAME);
  779. szDiskName = SpDupStringW(TemporaryBuffer);
  780. p = TemporaryBuffer;
  781. *p = 0;
  782. SpConcatenatePaths(p, FloppyDevicePath);
  783. SpConcatenatePaths(p, SETUP_LOG_FILENAME);
  784. FullLogFilename = SpDupStringW(p);
  785. while (rc == FALSE) {
  786. //
  787. // Prompt for the disk -- ignore what may be in the drive already,
  788. // and allow escape.
  789. //
  790. b = SpPromptForDisk(
  791. szDiskName,
  792. FloppyDevicePath,
  793. SETUP_LOG_FILENAME,
  794. TRUE, // Always prompt for at least once
  795. TRUE, // Allow user to cancel
  796. FALSE, // No multiple prompts
  797. NULL // don't care about redraw flag
  798. );
  799. //
  800. // If the user pressed escape at the disk prompt, bail out now.
  801. //
  802. if(!b) {
  803. rc = TRUE; // User canceled. Skip repair floppy
  804. } else {
  805. rc = SpLoadRepairLogFile(FullLogFilename, SifHandle);
  806. if (rc) {
  807. //
  808. // Now we need to figure out the partition, path information
  809. // to update boot.ini.
  810. //
  811. SppGetRepairPathInformation(*SifHandle,
  812. &SystemPartition,
  813. SystemPartitionDirectory,
  814. &WinntPartition,
  815. TargetPath
  816. );
  817. *SystemPartitionRegion = SpRegionFromNtName(
  818. SystemPartition,
  819. PartitionOrdinalCurrent);
  820. if (*SystemPartitionRegion == NULL) {
  821. SpFatalSifError(*SifHandle,
  822. SIF_NEW_REPAIR_PATHS,
  823. SIF_NEW_REPAIR_PATHS_SYSTEM_PARTITION_DEVICE,0,0);
  824. }
  825. *TargetRegion = SpRegionFromNtName(WinntPartition, PartitionOrdinalCurrent);
  826. if (*TargetRegion == NULL) {
  827. SpFatalSifError(*SifHandle,
  828. SIF_NEW_REPAIR_PATHS,
  829. SIF_NEW_REPAIR_PATHS_TARGET_DEVICE,0,0);
  830. }
  831. }
  832. }
  833. }
  834. SpMemFree(szDiskName);
  835. SpMemFree(FullLogFilename);
  836. return;
  837. }
  838. VOID
  839. SppRepairWinntFiles(
  840. IN PVOID LogFileHandle,
  841. IN PVOID MasterSifHandle,
  842. IN PWSTR SourceDevicePath,
  843. IN PWSTR DirectoryOnSourceDevice,
  844. IN PWSTR SystemPartition,
  845. IN PWSTR SystemPartitionDirectory,
  846. IN PWSTR WinntPartition,
  847. IN PWSTR WinntPartitionDirectory
  848. )
  849. /*++
  850. Routine Description:
  851. This routine goes through the system partition files and winnt files
  852. listed in the setup.log file and checks their validity.
  853. Arguments:
  854. LogFileHandle - Handle of the setup.log
  855. MasterSifHandle - Handle of the txtsetup.sif
  856. SourceDevicePath - supplies the NT name of the source device
  857. DirectoryOnSourceDevice - supplies the directory on the source device
  858. which contains source file.
  859. Return Value:
  860. None.
  861. --*/
  862. {
  863. PWSTR SystemPartitionFiles = L"system partition files";
  864. PWSTR WinntFiles = L"WinNt files";
  865. ULONG TotalFileCount;
  866. BOOLEAN RepairWithoutConfirming;
  867. //
  868. // Create file repair gauge
  869. //
  870. TotalFileCount = SpCountLinesInSection(LogFileHandle,SIF_NEW_REPAIR_SYSPARTFILES);
  871. TotalFileCount += SpCountLinesInSection(LogFileHandle,SIF_NEW_REPAIR_WINNTFILES);
  872. TotalFileCount += SpCountLinesInSection(LogFileHandle,SIF_NEW_REPAIR_FILES_IN_REPAIR_DIR);
  873. CLEAR_CLIENT_SCREEN();
  874. SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_SETUP_IS_EXAMINING);
  875. RepairGauge = SpCreateAndDisplayGauge(TotalFileCount,0,15,TemporaryBuffer,NULL,GF_PERCENTAGE,0);
  876. ASSERT(RepairGauge);
  877. //
  878. // delay opening of driver inf and cab file till required
  879. //
  880. ghSif = MasterSifHandle;
  881. gszDrvInfDeviceName = SourceDevicePath;
  882. gszDrvInfDirName = DirectoryOnSourceDevice;
  883. SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
  884. SppRepairScreenRepaint(NULL, NULL, TRUE);
  885. //
  886. // first recreate all of the directories we copy into
  887. //
  888. if (SystemPartition != NULL) {
  889. SpCreateDirectory(SystemPartition,NULL,SystemPartitionDirectory,0,0);
  890. }
  891. //
  892. // Create the nt tree.
  893. //
  894. SpCreateDirectoryStructureFromSif(MasterSifHandle,
  895. SIF_NTDIRECTORIES,
  896. WinntPartition,
  897. WinntPartitionDirectory);
  898. //
  899. // Verify and repair the files in [Files.InRepairDirectory]. If textmode
  900. // setup is executing a disaster recovery, do not prompt the user for the
  901. // files to repair. Just go ahead and repair 'em.
  902. //
  903. RepairWithoutConfirming = SpDrEnabled() && SpDrIsRepairFast();
  904. SppVerifyAndRepairVdmFiles(LogFileHandle,
  905. WinntPartition,
  906. NULL,
  907. &RepairWithoutConfirming);
  908. //
  909. // Verify and repair the files in [FIles.SystemPartition]
  910. //
  911. SppVerifyAndRepairFiles(LogFileHandle,
  912. MasterSifHandle,
  913. SIF_NEW_REPAIR_SYSPARTFILES,
  914. SourceDevicePath,
  915. DirectoryOnSourceDevice,
  916. SystemPartition,
  917. SystemPartitionDirectory,
  918. TRUE,
  919. &RepairWithoutConfirming);
  920. //
  921. // Verify and repair the files in [Files.WinNt]
  922. //
  923. SppVerifyAndRepairFiles(LogFileHandle,
  924. MasterSifHandle,
  925. SIF_NEW_REPAIR_WINNTFILES,
  926. SourceDevicePath,
  927. DirectoryOnSourceDevice,
  928. WinntPartition,
  929. NULL,
  930. FALSE,
  931. &RepairWithoutConfirming);
  932. SpDestroyGauge(RepairGauge);
  933. RepairGauge = NULL;
  934. }
  935. VOID
  936. SppVerifyAndRepairFiles(
  937. IN PVOID LogFileHandle,
  938. IN PVOID MasterSifHandle,
  939. IN PWSTR SectionName,
  940. IN PWSTR SourceDevicePath,
  941. IN PWSTR DirectoryOnSourceDevice,
  942. IN PWSTR TargetDevicePath,
  943. IN PWSTR DirectoryOnTargetDevice,
  944. IN BOOLEAN SystemPartitionFiles,
  945. IN OUT PBOOLEAN RepairWithoutConfirming
  946. )
  947. /*++
  948. Routine Description:
  949. This routine goes through the files listed in the specified section of
  950. setup.log file and checks their validity. If a file's checksum does
  951. not match the checksum listed in the setup.log file, we will prompt
  952. the user and recopy the file from original installation sources.
  953. Arguments:
  954. LogFileHandle - Handle of the setup.log
  955. MasterSifHandle - Handle of the txtsetup.sif
  956. SectionName - Section in setup.log to be examined
  957. SourceDevicePath - supplies the NT name of the source device
  958. DirectoryOnSourceDevice - supplies the directory on the source device
  959. which contains source file.
  960. TargetDevicePath - supplies the nt name of the target device
  961. DirectoryOnTargetDevice - the name of the winnt directory on target
  962. device
  963. SystemPartitionFile - supplies a boolean value to indicate if the target
  964. file is on system partition
  965. RepairWithoutConfirming - Pointer to a flag that indicates whether or not
  966. setup should repair a damaged file without
  967. asking the user to confirm.
  968. Return Value:
  969. None.
  970. --*/
  971. {
  972. PWSTR FullTargetName, ChecksumString;
  973. PWSTR TargetDirectory, TargetFileName;
  974. PWSTR SourceFileName;
  975. ULONG Checksum, FileChecksum, PrefixLength, Length, Count, i;
  976. BOOLEAN IsNtImage, IsValid, RepairFile, SysPartNTFS = FALSE;
  977. BOOLEAN RedrawGauge = TRUE, ForceNoComp;
  978. FILE_TO_COPY FileToCopy;
  979. PWSTR OemDiskDescription, OemDiskTag, OemSourceDirectory;
  980. PWSTR DevicePath, Directory, q;
  981. PWSTR MediaShortName, PreviousMediaName = L"";
  982. PWSTR MediaDir;
  983. NTSTATUS Status;
  984. //
  985. // Allocate a SMALL buffer for local use and init FileToCopy struct
  986. //
  987. TargetDirectory = NULL;
  988. FullTargetName = SpMemAlloc(1024);
  989. *FullTargetName = 0;
  990. FileToCopy.Next = NULL;
  991. FileToCopy.AbsoluteTargetDirectory = TRUE;
  992. FileToCopy.TargetDevicePath = TargetDevicePath;
  993. SpConcatenatePaths(FullTargetName,TargetDevicePath);
  994. if(SystemPartitionFiles) {
  995. PDISK_REGION SystemPartitionRegion;
  996. //
  997. // We must find out whether the system partition is NTFS, because
  998. // if it is, then we might want to make sure it's not compressed.
  999. //
  1000. if(SystemPartitionRegion = SpRegionFromNtName(TargetDevicePath,
  1001. PartitionOrdinalCurrent)) {
  1002. SysPartNTFS = (SystemPartitionRegion->Filesystem == FilesystemNtfs);
  1003. }
  1004. //
  1005. // For system partition files, we need to concatenate target
  1006. // directory to FullTargetName. Because the target filename
  1007. // of system partition files do not have target directory.
  1008. //
  1009. FileToCopy.TargetDirectory = DirectoryOnTargetDevice;
  1010. SpConcatenatePaths(FullTargetName,FileToCopy.TargetDirectory);
  1011. }
  1012. PrefixLength = wcslen(FullTargetName);
  1013. Count = SpCountLinesInSection(LogFileHandle,SectionName);
  1014. for (i = 0; i < Count; i++) {
  1015. if (RedrawGauge) {
  1016. SppRepairScreenRepaint(NULL, NULL, TRUE);
  1017. RedrawGauge = FALSE;
  1018. }
  1019. SpTickGauge(RepairGauge);
  1020. //
  1021. // Initialize the 'ForceNoComp' flag to FALSE, thus allowing the
  1022. // file to use NTFS compression.
  1023. //
  1024. ForceNoComp = FALSE;
  1025. //
  1026. // Initialize target fullname to be DevicePath+Directory for
  1027. // system partition file or DevicePath for Winnt files
  1028. //
  1029. FullTargetName[PrefixLength] = (WCHAR)NULL;
  1030. //
  1031. // If we allocate space for TargetDirectory we must free it.
  1032. //
  1033. if (TargetDirectory) {
  1034. SpMemFree(TargetDirectory);
  1035. TargetDirectory = NULL;
  1036. }
  1037. TargetFileName = SpGetKeyName(LogFileHandle,SectionName,i);
  1038. if(!TargetFileName) {
  1039. SppRepairReportError(FALSE,
  1040. SP_SCRN_REPAIR_INF_ERROR_0,
  1041. SP_TEXT_REPAIR_INF_ERROR_1,
  1042. SectionName,
  1043. i,
  1044. NULL);
  1045. RedrawGauge = TRUE;
  1046. continue;
  1047. }
  1048. //
  1049. // If the target file name contains \system32\config\, it is
  1050. // hive related file. We simply ignore it.
  1051. //
  1052. q = SpDupStringW(TargetFileName);
  1053. SpStringToUpper(q);
  1054. if (wcsstr(q,L"\\SYSTEM32\\CONFIG\\")) {
  1055. SpMemFree(q);
  1056. continue;
  1057. }
  1058. SpMemFree(q);
  1059. SpConcatenatePaths(FullTargetName,TargetFileName);
  1060. SpDisplayStatusText(SP_STAT_EXAMINING_WINNT,
  1061. DEFAULT_STATUS_ATTRIBUTE,
  1062. TargetFileName);
  1063. ChecksumString = SpGetSectionLineIndex(LogFileHandle,SectionName,i,1);
  1064. if(!ChecksumString) {
  1065. SppRepairReportError(FALSE,
  1066. SP_SCRN_REPAIR_INF_ERROR_0,
  1067. SP_TEXT_REPAIR_INF_ERROR_1,
  1068. SectionName,
  1069. i,
  1070. NULL);
  1071. RedrawGauge = TRUE;
  1072. continue;
  1073. }
  1074. Checksum = (ULONG)SpStringToLong(ChecksumString, NULL, 16);
  1075. //
  1076. // Validate the security set on the file.
  1077. // Note that we do not check the files in the system partition
  1078. // on non-x86 systems since it is always FAT
  1079. //
  1080. #ifndef _X86_
  1081. if(!SystemPartitionFiles) {
  1082. #endif
  1083. Status = SpVerifyFileAccess( FullTargetName,
  1084. STANDARD_RIGHTS_READ |
  1085. FILE_READ_ATTRIBUTES |
  1086. FILE_WRITE_ATTRIBUTES |
  1087. DELETE |
  1088. WRITE_DAC |
  1089. SYNCHRONIZE );
  1090. if( !NT_SUCCESS( Status ) &&
  1091. ((Status == STATUS_ACCESS_DENIED)||(Status == STATUS_PRIVILEGE_NOT_HELD)) ) {
  1092. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Security of %ls, must be fixed. Status = %x\n", FullTargetName, Status ));
  1093. Status = SpSetDefaultFileSecurity( FullTargetName );
  1094. if( !NT_SUCCESS( Status ) ) {
  1095. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to change security of %ls. Status = %x\n", FullTargetName, Status ));
  1096. }
  1097. }
  1098. #ifndef _X86_ // end of block started by "if(!SystemPartitionFiles) {" above
  1099. }
  1100. #endif
  1101. //
  1102. // If this is a system partition file and the system partition is NTFS,
  1103. // then check to see whether this file can use NTFS compression, and
  1104. // if not, force it to be uncompressed.
  1105. //
  1106. if((SysPartNTFS) &&
  1107. IsFileFlagSet(MasterSifHandle,TargetFileName,FILEFLG_FORCENOCOMP))
  1108. {
  1109. ForceNoComp = TRUE;
  1110. SpVerifyNoCompression(FullTargetName);
  1111. }
  1112. SpValidateAndChecksumFile(NULL,FullTargetName,&IsNtImage,&FileChecksum,&IsValid);
  1113. //
  1114. // If the image is invalid or the file on the target is not the
  1115. // original file copied by setup, we will recopy it.
  1116. //
  1117. if (!IsValid || FileChecksum != Checksum) {
  1118. //
  1119. // Ask user if he wants to repair the file
  1120. //
  1121. if(*RepairWithoutConfirming) {
  1122. RepairFile = TRUE;
  1123. } else {
  1124. RepairFile = SppRepairReportError(
  1125. TRUE,
  1126. SP_SCRN_REPAIR_FILE_MISMATCH,
  1127. SP_TEXT_REPAIR_INF_ERROR_4,
  1128. TargetFileName,
  1129. i,
  1130. RepairWithoutConfirming);
  1131. RedrawGauge = TRUE;
  1132. }
  1133. if (!RepairFile) {
  1134. continue;
  1135. }
  1136. SpDisplayStatusText(SP_STAT_REPAIR_WINNT,
  1137. DEFAULT_STATUS_ATTRIBUTE,
  1138. TargetFileName);
  1139. if (SystemPartitionFiles) {
  1140. FileToCopy.TargetFilename = TargetFileName;
  1141. } else {
  1142. //
  1143. // For Winnt files, the TargetName contains path and filename.
  1144. // We need to seperate them.
  1145. //
  1146. TargetDirectory = SpDupStringW(TargetFileName);
  1147. Length = wcslen(TargetDirectory);
  1148. while (Length) {
  1149. if (TargetDirectory[Length] == L'\\') {
  1150. TargetDirectory[Length] = 0;
  1151. TargetFileName = &TargetDirectory[Length + 1];
  1152. break;
  1153. } else {
  1154. Length--;
  1155. }
  1156. }
  1157. if (Length == 0) {
  1158. SppRepairReportError(FALSE,
  1159. SP_SCRN_REPAIR_INF_ERROR_0,
  1160. SP_TEXT_REPAIR_INF_ERROR_1,
  1161. SectionName,
  1162. i,
  1163. NULL);
  1164. RedrawGauge = TRUE;
  1165. continue;
  1166. }
  1167. FileToCopy.TargetFilename = TargetFileName;
  1168. FileToCopy.TargetDirectory = TargetDirectory;
  1169. }
  1170. SourceFileName = SpGetSectionLineIndex(LogFileHandle,SectionName,i,0);
  1171. if (!SourceFileName) {
  1172. SppRepairReportError(FALSE,
  1173. SP_SCRN_REPAIR_INF_ERROR_0,
  1174. SP_TEXT_REPAIR_INF_ERROR_1,
  1175. SectionName,
  1176. i,
  1177. NULL);
  1178. RedrawGauge = TRUE;
  1179. continue;
  1180. }
  1181. FileToCopy.SourceFilename = NULL;
  1182. q = SpDupStringW(SourceFileName);
  1183. SpStringToUpper(q);
  1184. if (wcsstr(q,L"DRIVER.CAB")) {
  1185. SpMemFree(q);
  1186. q = SpDupStringW(TargetFileName);
  1187. SpStringToUpper(q);
  1188. if (!wcsstr(q,L"DRIVER.CAB")) {
  1189. FileToCopy.SourceFilename = TargetFileName;
  1190. }
  1191. }
  1192. SpMemFree(q);
  1193. FileToCopy.SourceFilename = FileToCopy.SourceFilename
  1194. ? FileToCopy.SourceFilename
  1195. : SourceFileName;
  1196. FileToCopy.Flags = COPY_ALWAYS | COPY_NOVERSIONCHECK | (ForceNoComp ? COPY_FORCENOCOMP : 0);
  1197. //
  1198. // The file may come from OEM diskette. We need to check if the
  1199. // sources device is listed in log file. If not, it must be
  1200. // from MS setup sources.
  1201. //
  1202. OemSourceDirectory = SpGetSectionLineIndex(LogFileHandle,SectionName,i,2);
  1203. OemDiskTag = NULL;
  1204. if (OemSourceDirectory) {
  1205. OemDiskDescription = SpGetSectionLineIndex(LogFileHandle,SectionName,i,3);
  1206. if (OemDiskDescription) {
  1207. OemDiskTag = SpGetSectionLineIndex(LogFileHandle,SectionName,i,4);
  1208. if((OemDiskTag != NULL) &&
  1209. (wcslen(OemDiskTag) == 0)){
  1210. OemDiskTag = SourceFileName;
  1211. }
  1212. }
  1213. }
  1214. if (OemDiskTag) {
  1215. BOOLEAN rs;
  1216. PWSTR szDevicePath = SpDupStringW(L"\\device\\floppy0");
  1217. //
  1218. // Prompt for the disk, based on the setup media type.
  1219. //
  1220. rs = SpPromptForDisk(
  1221. OemDiskDescription,
  1222. szDevicePath,
  1223. OemDiskTag,
  1224. FALSE, // don't ignore disk in drive
  1225. TRUE, // allow escape
  1226. TRUE, // warn about multiple prompts for same disk
  1227. NULL // don't care redraw flag
  1228. );
  1229. SpMemFree(szDevicePath);
  1230. RedrawGauge = TRUE;
  1231. if (rs == FALSE) {
  1232. continue;
  1233. }
  1234. DevicePath = L"\\device\\floppy0";
  1235. Directory = OemSourceDirectory;
  1236. MediaDir = NULL;
  1237. } else {
  1238. PWSTR szDescription = 0, szTagFileName = 0;
  1239. BOOLEAN bDiskFound = FALSE;
  1240. //
  1241. // Search SourceFileName against txtsetup.sif to figure out its
  1242. // media name.
  1243. //
  1244. MediaShortName = SpLookUpValueForFile(
  1245. MasterSifHandle,
  1246. SourceFileName,
  1247. INDEX_WHICHMEDIA,
  1248. FALSE
  1249. );
  1250. if(MediaShortName) {
  1251. SpGetSourceMediaInfo(MasterSifHandle,MediaShortName,NULL,NULL,&MediaDir);
  1252. } else {
  1253. SpNonFatalSifError(
  1254. MasterSifHandle,
  1255. SIF_FILESONSETUPMEDIA,
  1256. SourceFileName,
  1257. 0,
  1258. INDEX_WHICHMEDIA,
  1259. SourceFileName
  1260. );
  1261. //
  1262. // If we returned from SpNonFatalSifError, then the user wants to
  1263. // skip the file.
  1264. //
  1265. RedrawGauge = TRUE;
  1266. continue;
  1267. }
  1268. //
  1269. // Prompt user to insert the source media, if changed.
  1270. //
  1271. SpGetSourceMediaInfo(MasterSifHandle, MediaShortName,
  1272. &szDescription, &szTagFileName, NULL);
  1273. //
  1274. // Prompt for the disk, based on the setup media type.
  1275. //
  1276. bDiskFound = SpPromptForDisk(
  1277. szDescription,
  1278. SourceDevicePath,
  1279. szTagFileName,
  1280. FALSE, // don't ignore disk in drive
  1281. TRUE, // don't allow escape
  1282. TRUE, // warn about multiple prompts for same disk
  1283. NULL // don't care redraw flag
  1284. );
  1285. RedrawGauge = TRUE;
  1286. //
  1287. // user might have wanted to skip the file
  1288. //
  1289. if (!bDiskFound)
  1290. continue;
  1291. DevicePath = SourceDevicePath;
  1292. Directory = DirectoryOnSourceDevice;
  1293. }
  1294. //
  1295. // Copy the file.
  1296. //
  1297. // If the file is listed for lock smashing then we need to smash it
  1298. // if installing UP on x86 (we don't bother with the latter
  1299. // qualifications here).
  1300. //
  1301. SpCopyFileWithRetry(
  1302. &FileToCopy,
  1303. DevicePath,
  1304. Directory,
  1305. MediaDir,
  1306. NULL, // TargetRoot -> NULL
  1307. SystemPartitionFiles ? ATTR_RHS : 0,
  1308. SppRepairScreenRepaint,
  1309. NULL, // Do not want checksum
  1310. NULL, // Do not want to know if file was skipped
  1311. IsFileFlagSet(
  1312. MasterSifHandle,
  1313. FileToCopy.TargetFilename,
  1314. FILEFLG_SMASHLOCKS) ? COPY_SMASHLOCKS : 0
  1315. );
  1316. }
  1317. }
  1318. SpMemFree(FullTargetName);
  1319. if (RedrawGauge) {
  1320. SppRepairScreenRepaint(NULL, NULL, TRUE);
  1321. }
  1322. }
  1323. BOOLEAN
  1324. SpDisplayRepairMenu(
  1325. VOID
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. This routine presents a list of repairable items to user and
  1330. let user choose the items to be fixed among the list.
  1331. Arguments:
  1332. None.
  1333. Return Value:
  1334. None. Some global repare variables are set or cleared.
  1335. --*/
  1336. {
  1337. PVOID Menu;
  1338. ULONG MenuTopY;
  1339. ULONG ValidKeys[] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
  1340. ULONG Keypress, MessageIds[RepairItemMax];
  1341. ULONG i;
  1342. ULONG_PTR OptionChosen, InitialHighlight;
  1343. PWSTR MenuItem;
  1344. ULONG ListBoxWidth, curLBEntryWidth;
  1345. //
  1346. // Initialize repair options to repair ALL.
  1347. // Initialize repair menu item message id.
  1348. //
  1349. for (i = 0; i < RepairItemMax; i++) {
  1350. RepairItems[i] = 1;
  1351. if (i == 0) {
  1352. MessageIds[i] = SP_REPAIR_MENU_ITEM_1;
  1353. } else {
  1354. MessageIds[i] = MessageIds[i - 1] + 1;
  1355. }
  1356. }
  1357. while(1) {
  1358. //
  1359. // Display the text that goes above the menu on the partitioning screen.
  1360. //
  1361. SpDisplayScreen(SP_SCRN_REPAIR_MENU,3,CLIENT_TOP+1);
  1362. //
  1363. // Calculate menu placement. Leave one blank line
  1364. // and one line for a frame.
  1365. //
  1366. MenuTopY = NextMessageTopLine + (SplangQueryMinimizeExtraSpacing() ? 2 : 5);
  1367. //
  1368. // Create a menu.
  1369. // First, find the longest string, so we can size the listbox accordingly
  1370. //
  1371. ListBoxWidth = LIST_BOX_WIDTH; // It will be at least this wide
  1372. for (i = 0; i <= RepairItemMax; i++ ) {
  1373. if (i == RepairItemMax) {
  1374. SpFormatMessage(TemporaryBuffer,
  1375. sizeof(TemporaryBuffer),
  1376. SP_REPAIR_MENU_ITEM_CONTINUE);
  1377. } else {
  1378. SpFormatMessage(TemporaryBuffer,
  1379. sizeof(TemporaryBuffer),
  1380. MessageIds[i]);
  1381. }
  1382. if((curLBEntryWidth = SplangGetColumnCount(TemporaryBuffer)+(2*MENU_INDENT)) > ListBoxWidth) {
  1383. ListBoxWidth = min(curLBEntryWidth, MENU_WIDTH);
  1384. }
  1385. }
  1386. Menu = SpMnCreate(
  1387. MENU_LEFT_X,
  1388. MenuTopY,
  1389. ListBoxWidth,
  1390. LIST_BOX_HEIGHT
  1391. );
  1392. if( !Menu )
  1393. return FALSE;
  1394. ASSERT(Menu);
  1395. for (i = 0; i <= RepairItemMax; i++ ) {
  1396. if (i == RepairItemMax) {
  1397. SpFormatMessage(TemporaryBuffer,
  1398. sizeof(TemporaryBuffer),
  1399. SP_REPAIR_MENU_ITEM_CONTINUE);
  1400. } else {
  1401. SpFormatMessage(TemporaryBuffer,
  1402. sizeof(TemporaryBuffer),
  1403. MessageIds[i]);
  1404. (TemporaryBuffer)[1] = RepairItems[i] ? L'X' : L' ';
  1405. }
  1406. SpMnAddItem(Menu,
  1407. TemporaryBuffer,
  1408. MENU_LEFT_X+MENU_INDENT,
  1409. ListBoxWidth-(2*MENU_INDENT),
  1410. TRUE,
  1411. i
  1412. );
  1413. }
  1414. InitialHighlight = RepairItemMax;
  1415. //
  1416. // Initialize the status line.
  1417. //
  1418. SpDisplayStatusOptions(
  1419. DEFAULT_STATUS_ATTRIBUTE,
  1420. SP_STAT_F3_EQUALS_EXIT,
  1421. SP_STAT_ESC_EQUALS_CANCEL,
  1422. SP_STAT_ENTER_EQUALS_CHANGE,
  1423. 0
  1424. );
  1425. DisplayMenu:
  1426. //
  1427. // Display the menu
  1428. //
  1429. SpMnDisplay(
  1430. Menu,
  1431. InitialHighlight,
  1432. TRUE,
  1433. ValidKeys,
  1434. NULL,
  1435. NULL,
  1436. &Keypress,
  1437. &OptionChosen
  1438. );
  1439. //
  1440. // Now act on the user's selection.
  1441. //
  1442. switch(Keypress) {
  1443. case KEY_F3:
  1444. SpConfirmExit();
  1445. break;
  1446. case ASCI_CR:
  1447. if (OptionChosen == RepairItemMax) {
  1448. SpMnDestroy(Menu);
  1449. return( TRUE );
  1450. } else {
  1451. MenuItem = SpMnGetText(Menu, OptionChosen);
  1452. if( !MenuItem )
  1453. goto DisplayMenu;
  1454. RepairItems[OptionChosen] ^= 1;
  1455. if (RepairItems[OptionChosen]) {
  1456. MenuItem[1] = L'X';
  1457. } else {
  1458. MenuItem[1] = L' ';
  1459. }
  1460. InitialHighlight = OptionChosen;
  1461. goto DisplayMenu;
  1462. }
  1463. break;
  1464. default:
  1465. SpMnDestroy(Menu);
  1466. return(FALSE);
  1467. }
  1468. SpMnDestroy(Menu);
  1469. }
  1470. }
  1471. NTSTATUS
  1472. SppRepairFile(
  1473. IN PVOID MasterSifHandle,
  1474. IN PWSTR TargetPath,
  1475. IN PWSTR TargetFilename,
  1476. IN PWSTR SourceDevicePath,
  1477. IN PWSTR DirectoryOnSourceDevice,
  1478. IN PWSTR SourceFilename,
  1479. IN BOOLEAN SystemPartitionFile
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. This routine repairs ONE file and the source of the file MUST be on
  1484. emergency repair diskette or on the repair directory of the winnt
  1485. being repaired.
  1486. Arguments:
  1487. MasterSifHandle - Hanle of the txtsetup.sif
  1488. TargetPath - Supplies the target file path
  1489. TargetFilename - supplies the name of the target file
  1490. SourceDevicePath - supplies the NT name of the source device
  1491. DirectoryOnSourceDevice - supplies the directory on the source device
  1492. which contains source file.
  1493. SourceFilename - supplies the name of the source file
  1494. SystemPartitionFile - supplies a boolean value to indicate if the target
  1495. file is on system partition
  1496. Return Value:
  1497. NTSTATUS of the file copy.
  1498. --*/
  1499. {
  1500. PWSTR szDiskName;
  1501. PWSTR FullSourceFilename, FullTargetFilename;
  1502. NTSTATUS Status;
  1503. if (RepairFromErDisk) {
  1504. //
  1505. // Fetch the generic repair disk name.
  1506. //
  1507. SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),
  1508. SP_TEXT_REPAIR_DISK_NAME);
  1509. szDiskName = SpDupStringW(TemporaryBuffer);
  1510. //
  1511. // Prompt for the disk -- do not ignore what may be in the drive
  1512. // already, and dont allow escape.
  1513. //
  1514. SpPromptForDisk(
  1515. szDiskName,
  1516. SourceDevicePath,
  1517. SETUP_LOG_FILENAME,
  1518. FALSE, // if disk is in already dont prompt
  1519. FALSE, // Do not allow user to cancel
  1520. TRUE, // warn for multiple prompts
  1521. NULL // don't care about redraw flag
  1522. );
  1523. SpMemFree(szDiskName);
  1524. }
  1525. //
  1526. // Form the name of the source and target fullname.
  1527. //
  1528. wcscpy(TemporaryBuffer, TargetPath);
  1529. SpConcatenatePaths(TemporaryBuffer, TargetFilename);
  1530. FullTargetFilename = SpDupStringW(TemporaryBuffer);
  1531. wcscpy(TemporaryBuffer, SourceDevicePath);
  1532. SpConcatenatePaths(TemporaryBuffer, DirectoryOnSourceDevice);
  1533. SpConcatenatePaths(TemporaryBuffer, SourceFilename);
  1534. FullSourceFilename = SpDupStringW(TemporaryBuffer);
  1535. //
  1536. // Copy the file.
  1537. //
  1538. // If the file is listed for lock smashing then we need to smash it
  1539. // if installing UP on x86 (we don't bother with the latter
  1540. // qualifications here).
  1541. //
  1542. Status = SpCopyFileUsingNames(
  1543. FullSourceFilename,
  1544. FullTargetFilename,
  1545. SystemPartitionFile ? ATTR_RHS : 0,
  1546. IsFileFlagSet(MasterSifHandle,TargetFilename,FILEFLG_SMASHLOCKS) ? COPY_SMASHLOCKS : 0
  1547. );
  1548. SpMemFree(FullSourceFilename);
  1549. SpMemFree(FullTargetFilename);
  1550. return(Status);
  1551. }
  1552. VOID
  1553. SppRepairStartMenuGroupsAndItems(
  1554. IN PWSTR WinntPartition,
  1555. IN PWSTR WinntDirectory
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. This routine loads the software hive, and set a value on Winlogon key
  1560. to indicate to Winlogon that it should recreate the Start Menu groups
  1561. and items for the Default User.
  1562. Arguments:
  1563. WinntPartition - supplies the NT name of the Winnt partition.
  1564. WinntDirectory - Supplies the name of the Winnt directory.
  1565. Return Value:
  1566. None.
  1567. --*/
  1568. {
  1569. NTSTATUS Status;
  1570. PWSTR p,q;
  1571. PWSTR LOCAL_MACHINE_KEY_NAME = L"\\registry\\machine";
  1572. ULONG Repair = 1;
  1573. PWSTR WINLOGON_KEY_NAME = L"Microsoft\\Windows NT\\CurrentVersion\\Winlogon";
  1574. PWSTR REPAIR_VALUE_NAME = L"Repair";
  1575. OBJECT_ATTRIBUTES Obja;
  1576. UNICODE_STRING UnicodeString;
  1577. HANDLE SoftwareKey;
  1578. //
  1579. // Put up a screen telling the user what we are doing.
  1580. //
  1581. // SpStartScreen(SP_SCRN_REPAIR_CHECK_HIVES,
  1582. // 0,
  1583. // 8,
  1584. // TRUE,
  1585. // FALSE,
  1586. // DEFAULT_ATTRIBUTE
  1587. // );
  1588. //
  1589. // SpDisplayStatusText(SP_STAT_REG_LOADING_HIVES,DEFAULT_STATUS_ATTRIBUTE);
  1590. //
  1591. // Load the software hive
  1592. //
  1593. //
  1594. // Form the name of the hive file.
  1595. // This is WinntPartition + WinntDirectory + system32\config + the hive name.
  1596. //
  1597. p = NULL;
  1598. q = NULL;
  1599. wcscpy(TemporaryBuffer,WinntPartition);
  1600. SpConcatenatePaths(TemporaryBuffer,WinntDirectory);
  1601. SpConcatenatePaths(TemporaryBuffer,L"system32\\config\\software");
  1602. p = SpDupStringW( TemporaryBuffer );
  1603. //
  1604. // Form the path of the key into which we will
  1605. // load the hive. We'll use the convention that
  1606. // a hive will be loaded into \registry\machine\x<hivename>.
  1607. //
  1608. wcscpy(TemporaryBuffer,LOCAL_MACHINE_KEY_NAME);
  1609. SpConcatenatePaths(TemporaryBuffer,L"x");
  1610. wcscat(TemporaryBuffer,L"software");
  1611. q = SpDupStringW( TemporaryBuffer );
  1612. if( (p == NULL) || (q == NULL) ) {
  1613. goto fix_strtmenu_cleanup_1;
  1614. }
  1615. //
  1616. // Attempt to load the hive.
  1617. //
  1618. Status = SpLoadUnloadKey(NULL,NULL,q,p);
  1619. if(!NT_SUCCESS(Status)) {
  1620. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to load hive %ws to key %ws (%lx)\n",p,q,Status));
  1621. goto fix_strtmenu_cleanup_1;
  1622. }
  1623. INIT_OBJA(&Obja,&UnicodeString,q);
  1624. Status = ZwOpenKey(&SoftwareKey,KEY_ALL_ACCESS,&Obja);
  1625. if(!NT_SUCCESS(Status)) {
  1626. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws (%lx)\n",q,Status));
  1627. goto fix_strtmenu_cleanup_2;
  1628. }
  1629. Status = SpOpenSetValueAndClose(
  1630. SoftwareKey,
  1631. WINLOGON_KEY_NAME,
  1632. REPAIR_VALUE_NAME,
  1633. REG_DWORD,
  1634. &Repair,
  1635. sizeof(ULONG)
  1636. );
  1637. if(!NT_SUCCESS(Status)) {
  1638. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set value %ws on key %ws. Status = %lx\n",REPAIR_VALUE_NAME,REPAIR_VALUE_NAME,Status));
  1639. goto fix_strtmenu_cleanup_3;
  1640. }
  1641. Status = ZwFlushKey(SoftwareKey );
  1642. fix_strtmenu_cleanup_3:
  1643. Status = ZwClose( SoftwareKey );
  1644. fix_strtmenu_cleanup_2:
  1645. Status = SpLoadUnloadKey(NULL,NULL,q,NULL);
  1646. fix_strtmenu_cleanup_1:
  1647. if( p != NULL ) {
  1648. SpMemFree( p );
  1649. }
  1650. if( q != NULL ) {
  1651. SpMemFree( q );
  1652. }
  1653. }
  1654. VOID
  1655. SppInspectHives(
  1656. IN PWSTR PartitionPath,
  1657. IN PWSTR SystemRoot,
  1658. OUT PULONG HiveLoaded,
  1659. IN PWSTR *HiveNames
  1660. )
  1661. /*++
  1662. Routine Description:
  1663. This routine inspects setup hives by loading and unloading them and
  1664. returns the loadable information in HiveLoaded[].
  1665. Arguments:
  1666. PartitionPath - supplies the NT name of the Winnt partition.
  1667. SystemRoot - Supplies the name of the Winnt System root.
  1668. HiveLoaded - Supplies a pointer to a ULONG array to receive the
  1669. loadable information for each hive inspected.
  1670. HIveNames - Supplies a pointer to a PWSTR array to receive the
  1671. name of hives to inspect.
  1672. Return Value:
  1673. None. HiveLoaded array initialized.
  1674. --*/
  1675. {
  1676. NTSTATUS Status;
  1677. PWSTR pwstrTemp1,pwstrTemp2;
  1678. int h;
  1679. PWSTR LOCAL_MACHINE_KEY_NAME = L"\\registry\\machine";
  1680. //
  1681. // Put up a screen telling the user what we are doing.
  1682. //
  1683. SpStartScreen(SP_SCRN_REPAIR_CHECK_HIVES,
  1684. 0,
  1685. 8,
  1686. TRUE,
  1687. FALSE,
  1688. DEFAULT_ATTRIBUTE
  1689. );
  1690. SpDisplayStatusText(SP_STAT_REG_LOADING_HIVES,DEFAULT_STATUS_ATTRIBUTE);
  1691. //
  1692. // Load each template hive we care about from the target tree.
  1693. //
  1694. for (h = 0; h < RepairHiveMax; h++) {
  1695. pwstrTemp1 = TemporaryBuffer;
  1696. pwstrTemp2 = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  1697. if( h != RepairHiveUser ) {
  1698. //
  1699. // Form the name of the hive file.
  1700. // This is partitionpath + sysroot + system32\config + the hive name.
  1701. //
  1702. wcscpy(pwstrTemp1,PartitionPath);
  1703. SpConcatenatePaths(pwstrTemp1,SystemRoot);
  1704. SpConcatenatePaths(pwstrTemp1,L"system32\\config");
  1705. SpConcatenatePaths(pwstrTemp1,HiveNames[h]);
  1706. } else {
  1707. wcscpy(pwstrTemp1,PartitionPath);
  1708. SpConcatenatePaths(pwstrTemp1,DEFAULT_USER_PATH);
  1709. SpConcatenatePaths(pwstrTemp1,HiveNames[h]);
  1710. }
  1711. //
  1712. // First we must verify that the hive file exists. We have to do
  1713. // this because loading a hive will create one if it didn't already
  1714. // exist!
  1715. //
  1716. if(!SpFileExists(pwstrTemp1, FALSE)) {
  1717. HiveLoaded[h] = 0;
  1718. continue;
  1719. }
  1720. //
  1721. // Form the path of the key into which we will
  1722. // load the hive. We'll use the convention that
  1723. // a hive will be loaded into \registry\machine\x<hivename>.
  1724. //
  1725. wcscpy(pwstrTemp2,LOCAL_MACHINE_KEY_NAME);
  1726. SpConcatenatePaths(pwstrTemp2,L"x");
  1727. wcscat(pwstrTemp2,HiveNames[h]);
  1728. //
  1729. // Attempt to load the hive.
  1730. //
  1731. HiveLoaded[h] = 0;
  1732. Status = SpLoadUnloadKey(NULL,NULL,pwstrTemp2,pwstrTemp1);
  1733. if (NT_SUCCESS(Status) || Status == STATUS_NO_MEMORY) {
  1734. //
  1735. // If the reason the hive did not load is because of not
  1736. // enough memory. We assume the hive is OK.
  1737. //
  1738. HiveLoaded[h] = 1;
  1739. //
  1740. // Unload the hive.
  1741. //
  1742. SpLoadUnloadKey(NULL,NULL,pwstrTemp2,NULL);
  1743. }
  1744. }
  1745. //
  1746. // Sam and security hives must be updated together. If any one of
  1747. // them failed to load, we must update both.
  1748. //
  1749. if ((HiveLoaded[RepairHiveSecurity] == 0) ||
  1750. (HiveLoaded[RepairHiveSam] == 0)) {
  1751. HiveLoaded[RepairHiveSam] = 0;
  1752. HiveLoaded[RepairHiveSecurity] = 0;
  1753. }
  1754. }
  1755. VOID
  1756. SppRepairHives(
  1757. PVOID MasterSifHandle,
  1758. PWSTR WinntPartition,
  1759. PWSTR WinntPartitionDirectory,
  1760. PWSTR SourceDevicePath,
  1761. PWSTR DirectoryOnSourceDevice
  1762. )
  1763. /*++
  1764. Routine Description:
  1765. This routine inspects hives and let user choose the hives which he
  1766. wants to repair.
  1767. Arguments:
  1768. MasterSifHandle - The handle of textsetup.sif
  1769. WinntPartition - The nt name of Winnt partition
  1770. WinntPartitionDirectory - The directory name of winnt installation
  1771. SourceDevicePath - The NT name of source device which contains hives
  1772. DirectoryOnSourceDevice - The directory name of source device
  1773. Return Value:
  1774. None.
  1775. --*/
  1776. {
  1777. //
  1778. // Do not change the order of the files in 'HiveNames' array.
  1779. // If you do that, you also need to change the order of the
  1780. // enum 'RepairHive' in spntfix.h
  1781. //
  1782. PWSTR HiveNames[RepairHiveMax] = { L"system",L"software",L"default",L"ntuser.dat",L"security",L"sam"};
  1783. ULONG HiveLoaded[RepairHiveMax];
  1784. PVOID Menu;
  1785. ULONG MenuTopY;
  1786. ULONG ValidKeys[] = { KEY_F3, ASCI_CR, 0 };
  1787. ULONG ValidKeys1[] = { KEY_F3, ASCI_CR, 0 };
  1788. ULONG i;
  1789. ULONG_PTR InitialHighlight, OptionChosen;
  1790. PWSTR MenuItem, TargetPath, p;
  1791. ULONG Keypress, MessageIds[RepairHiveMax];
  1792. BOOLEAN Selectable;
  1793. NTSTATUS Status;
  1794. ULONG ListBoxWidth, curLBEntryWidth;
  1795. BOOLEAN DetermineHivesToRepair;
  1796. //
  1797. // Inspect hives by loading hives to determine which hives need to be
  1798. // fixed.
  1799. //
  1800. SppInspectHives(WinntPartition,
  1801. WinntPartitionDirectory,
  1802. HiveLoaded,
  1803. HiveNames);
  1804. // BCL - Seagate: If doing ASR, don't do the menu.
  1805. if ( SpDrEnabled() ) {
  1806. goto UpdateTheHives;
  1807. }
  1808. //
  1809. // Initialize hive menu item message id.
  1810. //
  1811. for (i = 0; i < RepairHiveMax; i++) {
  1812. if (i == 0) {
  1813. MessageIds[i] = SP_REPAIR_HIVE_ITEM_1;
  1814. } else {
  1815. MessageIds[i] = MessageIds[i - 1] + 1;
  1816. }
  1817. }
  1818. DetermineHivesToRepair = TRUE;
  1819. while(DetermineHivesToRepair) {
  1820. //
  1821. // Display the text that goes above the menu on the partitioning screen.
  1822. //
  1823. SpDisplayScreen(SP_SCRN_REPAIR_HIVE_MENU,3,CLIENT_TOP+1);
  1824. //
  1825. // Calculate menu placement. Leave one blank line
  1826. // and one line for a frame.
  1827. //
  1828. MenuTopY = NextMessageTopLine + (SplangQueryMinimizeExtraSpacing() ? 2 : 5);
  1829. //
  1830. // Create a menu.
  1831. // First, find the longest string, so we can size the listbox accordingly
  1832. //
  1833. ListBoxWidth = HIVE_LIST_BOX_WIDTH; // It will be at least this wide
  1834. for (i = 0; i <= RepairHiveMax; i++ ) {
  1835. if (i == RepairHiveMax) {
  1836. SpFormatMessage(TemporaryBuffer,
  1837. sizeof(TemporaryBuffer),
  1838. SP_REPAIR_MENU_ITEM_CONTINUE);
  1839. } else {
  1840. SpFormatMessage(TemporaryBuffer,
  1841. sizeof(TemporaryBuffer),
  1842. MessageIds[i]);
  1843. }
  1844. if((curLBEntryWidth = SplangGetColumnCount(TemporaryBuffer)+(2*MENU_INDENT)) > ListBoxWidth) {
  1845. ListBoxWidth = min(curLBEntryWidth, MENU_WIDTH);
  1846. }
  1847. }
  1848. Menu = SpMnCreate(
  1849. MENU_LEFT_X,
  1850. MenuTopY,
  1851. ListBoxWidth,
  1852. HIVE_LIST_BOX_HEIGHT
  1853. );
  1854. ASSERT(Menu);
  1855. //
  1856. // Build up a menu of hives
  1857. //
  1858. for (i = 0; i <= RepairHiveMax; i++ ) {
  1859. if (i == RepairHiveSam) {
  1860. Selectable = FALSE;
  1861. } else {
  1862. Selectable = TRUE;
  1863. }
  1864. if (i == RepairHiveMax) {
  1865. SpFormatMessage(TemporaryBuffer,
  1866. sizeof(TemporaryBuffer),
  1867. SP_REPAIR_MENU_ITEM_CONTINUE);
  1868. } else {
  1869. SpFormatMessage(TemporaryBuffer,
  1870. sizeof(TemporaryBuffer),
  1871. MessageIds[i]);
  1872. p = TemporaryBuffer;
  1873. if (HiveLoaded[i] || ( i == RepairHiveSam )) {
  1874. p[1] = L' ';
  1875. } else {
  1876. p[1] = L'X';
  1877. }
  1878. }
  1879. SpMnAddItem(Menu,
  1880. TemporaryBuffer,
  1881. MENU_LEFT_X+MENU_INDENT,
  1882. ListBoxWidth-(2*MENU_INDENT),
  1883. Selectable,
  1884. i
  1885. );
  1886. }
  1887. InitialHighlight = RepairHiveMax;
  1888. //
  1889. // Initialize the status line.
  1890. //
  1891. SpDisplayStatusOptions(
  1892. DEFAULT_STATUS_ATTRIBUTE,
  1893. SP_STAT_ENTER_EQUALS_CHANGE,
  1894. SP_STAT_F3_EQUALS_EXIT,
  1895. 0
  1896. );
  1897. DisplayMenu:
  1898. //
  1899. // Display the menu
  1900. //
  1901. SpMnDisplay(
  1902. Menu,
  1903. InitialHighlight,
  1904. TRUE,
  1905. ValidKeys,
  1906. NULL,
  1907. NULL,
  1908. &Keypress,
  1909. &OptionChosen
  1910. );
  1911. //
  1912. // Now act on the user's selection.
  1913. //
  1914. switch(Keypress) {
  1915. case KEY_F3:
  1916. SpConfirmExit();
  1917. break;
  1918. case ASCI_CR:
  1919. if (OptionChosen == RepairHiveMax) {
  1920. SpMnDestroy(Menu);
  1921. DetermineHivesToRepair = FALSE;
  1922. } else {
  1923. HiveLoaded[OptionChosen] ^= 1;
  1924. MenuItem = SpMnGetText(Menu, OptionChosen);
  1925. if ((HiveLoaded[OptionChosen] != 0) ||
  1926. (OptionChosen == RepairHiveSam)){
  1927. MenuItem[1] = L' ';
  1928. } else {
  1929. MenuItem[1] = L'X';
  1930. }
  1931. //
  1932. // Security and sam must go together.
  1933. //
  1934. HiveLoaded[RepairHiveSam] = HiveLoaded[RepairHiveSecurity];
  1935. InitialHighlight = OptionChosen;
  1936. goto DisplayMenu;
  1937. }
  1938. break;
  1939. }
  1940. }
  1941. UpdateTheHives:
  1942. //
  1943. // At this point user has decided which hives to repair.
  1944. // We will copy the hives from repair disk to
  1945. // Winnt\system32\config directory.
  1946. //
  1947. for (i = 0; i < RepairHiveMax; i++ ) {
  1948. // BCL - Seagate: Don't do ntuser.dat. As of 4/17/98, there is no
  1949. // copy of this file to copy from.
  1950. if ( SpDrEnabled() && i == RepairHiveUser ) {
  1951. continue;
  1952. }
  1953. if (HiveLoaded[i] == 0) {
  1954. //
  1955. // Form Target path
  1956. //
  1957. if( i != RepairHiveUser ) {
  1958. wcscpy(TemporaryBuffer, WinntPartition);
  1959. SpConcatenatePaths(TemporaryBuffer, WinntPartitionDirectory);
  1960. SpConcatenatePaths(TemporaryBuffer, L"\\SYSTEM32\\CONFIG");
  1961. TargetPath = SpDupStringW(TemporaryBuffer);
  1962. } else {
  1963. wcscpy(TemporaryBuffer, WinntPartition);
  1964. SpConcatenatePaths(TemporaryBuffer, WinntPartitionDirectory);
  1965. SpConcatenatePaths(TemporaryBuffer, DEFAULT_USER_PATH);
  1966. TargetPath = SpDupStringW(TemporaryBuffer);
  1967. }
  1968. Status = SppRepairFile(MasterSifHandle,
  1969. TargetPath,
  1970. HiveNames[i],
  1971. SourceDevicePath,
  1972. DirectoryOnSourceDevice,
  1973. HiveNames[i],
  1974. FALSE
  1975. );
  1976. if (!NT_SUCCESS(Status)) {
  1977. //
  1978. // Tell user we couldn't do it. Options are to continue or exit.
  1979. //
  1980. SpStartScreen(
  1981. SP_SCRN_REPAIR_HIVE_FAIL,
  1982. 3,
  1983. HEADER_HEIGHT+1,
  1984. FALSE,
  1985. FALSE,
  1986. DEFAULT_ATTRIBUTE
  1987. );
  1988. SpDisplayStatusOptions(
  1989. DEFAULT_STATUS_ATTRIBUTE,
  1990. SP_STAT_ENTER_EQUALS_CONTINUE,
  1991. SP_STAT_F3_EQUALS_EXIT,
  1992. 0
  1993. );
  1994. switch(SpWaitValidKey(ValidKeys1,NULL,NULL)) {
  1995. case ASCI_CR:
  1996. return;
  1997. break;
  1998. case KEY_F3:
  1999. SpConfirmExit();
  2000. break;
  2001. }
  2002. }
  2003. SpMemFree(TargetPath);
  2004. }
  2005. }
  2006. }
  2007. VOID
  2008. SpRepairWinnt(
  2009. IN PVOID LogFileHandle,
  2010. IN PVOID MasterSifHandle,
  2011. IN PWSTR SourceDevicePath,
  2012. IN PWSTR DirectoryOnSourceDevice
  2013. )
  2014. /*++
  2015. Routine Description:
  2016. This is a the top level repair rutine. It calls worker routines
  2017. for each repair options that user selected.
  2018. Arguments:
  2019. LogFileHandle - Handle of the setup.log
  2020. MasterSifHandle - Handle of the txtsetup.sif
  2021. SourceDevicePath - The NT name for the repair source device.
  2022. DirectoryOnSourceDevice - The directory name on the repair source
  2023. device which contains the source files.
  2024. Return Value:
  2025. None.
  2026. --*/
  2027. {
  2028. PWSTR SystemPartition, SystemPartitionDirectory;
  2029. PWSTR WinntPartition, WinntPartitionDirectory;
  2030. PWSTR HiveRepairSourceDevice, DirectoryOnHiveRepairSource;
  2031. //
  2032. // Initialize the diamond decompression engine.
  2033. //
  2034. SpdInitialize();
  2035. //
  2036. // Determine SystemPartition, SystemPartitionDirectory.
  2037. // WinntParition and WinntPartitionDirectory of the WINNT
  2038. // installation to be repaired.
  2039. //
  2040. SppGetRepairPathInformation(LogFileHandle,
  2041. &SystemPartition,
  2042. &SystemPartitionDirectory,
  2043. &WinntPartition,
  2044. &WinntPartitionDirectory
  2045. );
  2046. //
  2047. // If repair involves disk access, then run autochk on Nt and system
  2048. // partitions.
  2049. //
  2050. if( RepairItems[RepairFiles]
  2051. #ifdef _X86_
  2052. ||
  2053. RepairItems[RepairNvram]
  2054. #endif
  2055. ) {
  2056. PDISK_REGION SystemPartitionRegion;
  2057. PDISK_REGION WinntPartitionRegion;
  2058. WinntPartitionRegion = SpRegionFromNtName( WinntPartition,
  2059. PartitionOrdinalCurrent);
  2060. SystemPartitionRegion = SpRegionFromNtName( SystemPartition,
  2061. PartitionOrdinalCurrent);
  2062. if( !RepairNoCDROMDrive ) {
  2063. //
  2064. // If we know that the system doesn't have a CD-ROM drive,
  2065. // then don't even attempt to run autochk.
  2066. //
  2067. SpRunAutochkOnNtAndSystemPartitions( MasterSifHandle,
  2068. WinntPartitionRegion,
  2069. SystemPartitionRegion,
  2070. SourceDevicePath,
  2071. DirectoryOnSourceDevice,
  2072. NULL
  2073. );
  2074. }
  2075. }
  2076. //
  2077. // Verify and repair security of the directories that form the NT tree
  2078. // This needs to be done before repairing the hives because the
  2079. // system32\config directory might not be there anymore!
  2080. //
  2081. SppVerifyAndRepairNtTreeAccess(MasterSifHandle,
  2082. WinntPartition,
  2083. WinntPartitionDirectory,
  2084. SystemPartition,
  2085. SystemPartitionDirectory
  2086. );
  2087. #if 0
  2088. // BCL - Seagate - the RepairHives member has been removed from the
  2089. // struct
  2090. if (RepairItems[RepairHives]) {
  2091. //
  2092. // User has selected to repair hives. If user has provided the
  2093. // ER disk, we will copy the hive from ER disk to repair damaged
  2094. // hives. Otherwise we copy the hive from the directory where
  2095. // setup.log was loaded.
  2096. //
  2097. if (RepairFromErDisk) {
  2098. HiveRepairSourceDevice = L"\\device\\floppy0";
  2099. DirectoryOnHiveRepairSource = L"";
  2100. } else {
  2101. HiveRepairSourceDevice = WinntPartition;
  2102. wcscpy(TemporaryBuffer, WinntPartitionDirectory);
  2103. SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
  2104. DirectoryOnHiveRepairSource = SpDupStringW(TemporaryBuffer);
  2105. }
  2106. SppRepairHives(MasterSifHandle,
  2107. WinntPartition,
  2108. WinntPartitionDirectory,
  2109. HiveRepairSourceDevice,
  2110. DirectoryOnHiveRepairSource
  2111. );
  2112. if (!RepairFromErDisk) {
  2113. SpMemFree(DirectoryOnHiveRepairSource);
  2114. }
  2115. }
  2116. if (RepairItems[RepairFiles]) {
  2117. SppRepairWinntFiles(LogFileHandle,
  2118. MasterSifHandle,
  2119. SourceDevicePath,
  2120. DirectoryOnSourceDevice,
  2121. SystemPartition,
  2122. SystemPartitionDirectory,
  2123. WinntPartition,
  2124. WinntPartitionDirectory
  2125. );
  2126. }
  2127. #endif
  2128. //
  2129. // The code to repair nvram variables and boot sector is
  2130. // incorporated into SpStartSetup.
  2131. //
  2132. //
  2133. // Load the software hive, and and set the repair flag under Winlogon,
  2134. // so that winlogon can recreate the start menu groups and items for
  2135. // the default user.
  2136. //
  2137. SppRepairStartMenuGroupsAndItems( WinntPartition,
  2138. WinntPartitionDirectory );
  2139. //
  2140. // Terminate diamond.
  2141. //
  2142. SpdTerminate();
  2143. }
  2144. VOID
  2145. SppVerifyAndRepairNtTreeAccess(
  2146. IN PVOID MasterSifHandle,
  2147. IN PWSTR TargetDevicePath,
  2148. IN PWSTR DirectoryOnTargetDevice,
  2149. IN PWSTR SystemPartition,
  2150. IN PWSTR SystemPartitionDirectory
  2151. )
  2152. /*++
  2153. Routine Description:
  2154. This routine examines whether or not the directories that form the
  2155. NT tree are accessible, and set the appropriate security descriptor
  2156. in each directory, when necessary.
  2157. Arguments:
  2158. MasterSifHandle - Hanle of the txtsetup.sif
  2159. TargetDevicePath - supplies the nt name of the target device
  2160. DirectoryOnTargetDevice - the name of the winnt directory on target
  2161. device
  2162. SystemPartition - supplies the nt name of the target device (non-x86 platforms)
  2163. SystemPartitionDirectory - the name of the winnt directory on target
  2164. device (non-x86 platforms)
  2165. Return Value:
  2166. None.
  2167. --*/
  2168. {
  2169. ULONG Count, i;
  2170. PWSTR SectionName = L"WinntDirectories";
  2171. PWSTR DirectoryName;
  2172. PWSTR TargetPath;
  2173. PWSTR WinNtDirectory;
  2174. NTSTATUS Status;
  2175. SpDisplayStatusText(SP_STAT_SETUP_IS_EXAMINING_DIRS, DEFAULT_STATUS_ATTRIBUTE);
  2176. if(SpIsArc()){
  2177. //
  2178. // Make sure that on ARC platforms, the system partition directory
  2179. // exists (re-create it if it doesn't exist)
  2180. //
  2181. SpCreateDirectory(SystemPartition,NULL,SystemPartitionDirectory,0,0);
  2182. }
  2183. WinNtDirectory = ( PWSTR )SpMemAlloc( ( wcslen( TargetDevicePath ) + 1 +
  2184. wcslen( DirectoryOnTargetDevice ) + 1 +
  2185. 1 )*sizeof( WCHAR ) );
  2186. TargetPath = ( PWSTR )SpMemAlloc( 1024 );
  2187. if( ( WinNtDirectory == NULL ) ||
  2188. ( TargetPath == NULL ) ) {
  2189. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to allocate memory for WinNtDirectory \n"));
  2190. if( WinNtDirectory != NULL ) {
  2191. SpMemFree( WinNtDirectory );
  2192. }
  2193. if( TargetPath != NULL ) {
  2194. SpMemFree( TargetPath );
  2195. }
  2196. return;
  2197. }
  2198. wcscpy( WinNtDirectory, TargetDevicePath );
  2199. SpConcatenatePaths( WinNtDirectory, DirectoryOnTargetDevice );
  2200. Count = SpCountLinesInSection(MasterSifHandle, SectionName);
  2201. //
  2202. // Note that in the loop below, the maximum value for 'i' is 'Count'
  2203. // instead of 'Count-1'. This is because we need to create the directory
  2204. // 'Profiles\\Default User' which cannot be listed in txtsetup.sif.
  2205. // This is due to pre-install requirements, and DOS limitation regarding
  2206. // long file names.
  2207. //
  2208. for (i = 0; i <= Count; i++) {
  2209. if( i != Count ) {
  2210. DirectoryName = SpGetSectionLineIndex(MasterSifHandle,SectionName,i,0);
  2211. } else {
  2212. //
  2213. // Due to pre-installation requirements, and DOS limitation
  2214. // regarding long file names, the "Default User" directory
  2215. // is not specified on txtsetup.sif, as the other directories.
  2216. // This directory is treated as a special case in the
  2217. // repair process.
  2218. //
  2219. DirectoryName = DEFAULT_USER_PATH;
  2220. }
  2221. if(!DirectoryName) {
  2222. SppRepairReportError(FALSE,
  2223. SP_SCRN_REPAIR_INF_ERROR_0,
  2224. SP_TEXT_REPAIR_INF_ERROR_1,
  2225. SectionName,
  2226. i,
  2227. NULL);
  2228. continue;
  2229. }
  2230. wcscpy( TargetPath, WinNtDirectory );
  2231. //
  2232. // Make sure that TargetPath doesn't contain '\' as the last character
  2233. //
  2234. if(!((DirectoryName[0] == L'\\') && (DirectoryName[1] == 0))) {
  2235. SpConcatenatePaths( TargetPath, DirectoryName );
  2236. }
  2237. Status = SpVerifyFileAccess( TargetPath,
  2238. STANDARD_RIGHTS_READ |
  2239. FILE_READ_ATTRIBUTES |
  2240. FILE_LIST_DIRECTORY |
  2241. FILE_ADD_FILE |
  2242. FILE_ADD_SUBDIRECTORY |
  2243. FILE_TRAVERSE |
  2244. WRITE_DAC |
  2245. SYNCHRONIZE );
  2246. //
  2247. // If unable to access the directory, try to determine why.
  2248. // If it is because of access denied, change the directory security.
  2249. // If it is because the directory doesn't exist, then create it.
  2250. //
  2251. if( !NT_SUCCESS( Status ) ) {
  2252. if ((Status == STATUS_ACCESS_DENIED)||(Status == STATUS_PRIVILEGE_NOT_HELD) ) {
  2253. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Security of %ls, must be fixed. Status = %x\n", TargetPath, Status ));
  2254. Status = SpSetDefaultFileSecurity( TargetPath );
  2255. if( !NT_SUCCESS( Status ) ) {
  2256. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to change security of %ls. Status = %x\n", TargetPath, Status ));
  2257. }
  2258. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  2259. if(((DirectoryName[0] == L'\\') && (DirectoryName[1] == 0))) {
  2260. //
  2261. // Create the target directory
  2262. //
  2263. SpCreateDirectory( TargetDevicePath,
  2264. NULL,
  2265. DirectoryOnTargetDevice,
  2266. 0,
  2267. 0);
  2268. } else {
  2269. SpCreateDirectory( TargetDevicePath,
  2270. DirectoryOnTargetDevice,
  2271. DirectoryName,
  2272. 0,
  2273. 0);
  2274. }
  2275. } else {
  2276. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to access directory %ls. Status = %x\n", TargetPath, Status ));
  2277. }
  2278. }
  2279. }
  2280. if( WinNtDirectory != NULL ) {
  2281. SpMemFree( WinNtDirectory );
  2282. }
  2283. if( TargetPath != NULL ) {
  2284. SpMemFree( TargetPath );
  2285. }
  2286. return;
  2287. }
  2288. VOID
  2289. SppVerifyAndRepairVdmFiles(
  2290. IN PVOID LogFileHandle,
  2291. IN PWSTR TargetDevicePath,
  2292. IN PWSTR DirectoryOnTargetDevice,
  2293. IN PBOOLEAN RepairWithoutConfirming
  2294. )
  2295. /*++
  2296. Routine Description:
  2297. This routine repairs the Vdm configuration files listed on
  2298. 'Files.InRepairDirectory' of setup.log. Currently, such files are:
  2299. autoexec.nt and config.nt. It is assumed that files in this section
  2300. will be copied from the emergency repair disk, or from the repair
  2301. directory.
  2302. Arguments:
  2303. LogFileHandle - Handle of the setup.log
  2304. TargetDevicePath - supplies the nt name of the target device
  2305. DirectoryOnTargetDevice - the name of the winnt directory on target
  2306. device
  2307. RepairWithoutConfirming - Pointer to a flag that indicates whether or not
  2308. setup should repair files without confirming
  2309. with the user.
  2310. Return Value:
  2311. None.
  2312. --*/
  2313. {
  2314. PWSTR FullTargetName, ChecksumString;
  2315. PWSTR TargetDirectory, TargetFileName;
  2316. PWSTR SourceFileName;
  2317. ULONG Checksum, FileChecksum, PrefixLength, Length, Count, i;
  2318. BOOLEAN IsNtImage, IsValid, RepairFile;
  2319. BOOLEAN RedrawGauge = TRUE;
  2320. FILE_TO_COPY FileToCopy;
  2321. PWSTR DevicePath, Directory;
  2322. PWSTR SectionName = SIF_NEW_REPAIR_FILES_IN_REPAIR_DIR;
  2323. //
  2324. // Allocate a SMALL buffer for local use and init FileToCopy struct
  2325. //
  2326. TargetDirectory = NULL;
  2327. FullTargetName = SpMemAlloc(1024);
  2328. *FullTargetName = 0;
  2329. FileToCopy.Next = NULL;
  2330. FileToCopy.Flags = COPY_ALWAYS;
  2331. FileToCopy.AbsoluteTargetDirectory = TRUE;
  2332. FileToCopy.TargetDevicePath = TargetDevicePath;
  2333. SpConcatenatePaths(FullTargetName,TargetDevicePath);
  2334. PrefixLength = wcslen(FullTargetName);
  2335. Count = SpCountLinesInSection(LogFileHandle,SectionName);
  2336. for (i = 0; i < Count; i++) {
  2337. if (RedrawGauge) {
  2338. SppRepairScreenRepaint(NULL, NULL, TRUE);
  2339. RedrawGauge = FALSE;
  2340. }
  2341. SpTickGauge(RepairGauge);
  2342. //
  2343. // Initialize target fullname to be DevicePath+Directory for
  2344. // system partition file or DevicePath for Winnt files
  2345. //
  2346. FullTargetName[PrefixLength] = (WCHAR)NULL;
  2347. //
  2348. // If we allocate space for TargetDirectory we must free it.
  2349. //
  2350. if (TargetDirectory) {
  2351. SpMemFree(TargetDirectory);
  2352. TargetDirectory = NULL;
  2353. }
  2354. TargetFileName = SpGetKeyName(LogFileHandle,SectionName,i);
  2355. if(!TargetFileName) {
  2356. SppRepairReportError(FALSE,
  2357. SP_SCRN_REPAIR_INF_ERROR_0,
  2358. SP_TEXT_REPAIR_INF_ERROR_1,
  2359. SectionName,
  2360. i,
  2361. NULL);
  2362. RedrawGauge = TRUE;
  2363. continue;
  2364. }
  2365. SpConcatenatePaths(FullTargetName,TargetFileName);
  2366. SpDisplayStatusText(SP_STAT_EXAMINING_WINNT,
  2367. DEFAULT_STATUS_ATTRIBUTE,
  2368. TargetFileName);
  2369. ChecksumString = SpGetSectionLineIndex(LogFileHandle,SectionName,i,1);
  2370. if(!ChecksumString) {
  2371. SppRepairReportError(FALSE,
  2372. SP_SCRN_REPAIR_INF_ERROR_0,
  2373. SP_TEXT_REPAIR_INF_ERROR_1,
  2374. SectionName,
  2375. i,
  2376. NULL);
  2377. RedrawGauge = TRUE;
  2378. continue;
  2379. }
  2380. Checksum = (ULONG)SpStringToLong(ChecksumString, NULL, 16);
  2381. SpValidateAndChecksumFile(NULL,FullTargetName,&IsNtImage,&FileChecksum,&IsValid);
  2382. //
  2383. // If the image is invalid or the file on the target is not the
  2384. // original file copied by setup, we will recopy it.
  2385. //
  2386. if (!IsValid || FileChecksum != Checksum) {
  2387. //
  2388. // Ask user if he wants to repair the file
  2389. //
  2390. RepairFile = ( *RepairWithoutConfirming )?
  2391. TRUE :
  2392. SppRepairReportError(
  2393. TRUE,
  2394. SP_SCRN_REPAIR_FILE_MISMATCH,
  2395. SP_TEXT_REPAIR_INF_ERROR_4,
  2396. TargetFileName,
  2397. i,
  2398. RepairWithoutConfirming);
  2399. RedrawGauge = TRUE;
  2400. if (!RepairFile) {
  2401. continue;
  2402. }
  2403. SpDisplayStatusText(SP_STAT_REPAIR_WINNT,
  2404. DEFAULT_STATUS_ATTRIBUTE,
  2405. TargetFileName);
  2406. //
  2407. // TargetName contains path and filename.
  2408. // We need to seperate them.
  2409. //
  2410. TargetDirectory = SpDupStringW(TargetFileName);
  2411. Length = wcslen(TargetDirectory);
  2412. while (Length) {
  2413. if (TargetDirectory[Length] == L'\\') {
  2414. TargetDirectory[Length] = 0;
  2415. TargetFileName = &TargetDirectory[Length + 1];
  2416. break;
  2417. } else {
  2418. Length--;
  2419. }
  2420. }
  2421. if (Length == 0) {
  2422. SppRepairReportError(FALSE,
  2423. SP_SCRN_REPAIR_INF_ERROR_0,
  2424. SP_TEXT_REPAIR_INF_ERROR_1,
  2425. SectionName,
  2426. i,
  2427. NULL);
  2428. RedrawGauge = TRUE;
  2429. continue;
  2430. }
  2431. FileToCopy.TargetFilename = TargetFileName;
  2432. FileToCopy.TargetDirectory = TargetDirectory;
  2433. SourceFileName = SpGetSectionLineIndex(LogFileHandle,SectionName,i,0);
  2434. if (!SourceFileName) {
  2435. SppRepairReportError(FALSE,
  2436. SP_SCRN_REPAIR_INF_ERROR_0,
  2437. SP_TEXT_REPAIR_INF_ERROR_1,
  2438. SectionName,
  2439. i,
  2440. NULL);
  2441. RedrawGauge = TRUE;
  2442. continue;
  2443. }
  2444. FileToCopy.SourceFilename = SourceFileName;
  2445. //
  2446. // Find out whether the source file should come from the
  2447. // Emergency Repair Disk or the Repair directory
  2448. //
  2449. if (RepairFromErDisk) {
  2450. BOOLEAN rs;
  2451. PWSTR szDiskName;
  2452. PWSTR szDevicePath = SpDupStringW(L"\\device\\floppy0");
  2453. //
  2454. // Fetch the generic repair disk name.
  2455. //
  2456. SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),
  2457. SP_TEXT_REPAIR_DISK_NAME);
  2458. szDiskName = SpDupStringW(TemporaryBuffer);
  2459. //
  2460. // Prompt for the disk, based on the setup media type.
  2461. //
  2462. rs = SpPromptForDisk(
  2463. szDiskName,
  2464. szDevicePath,
  2465. SETUP_LOG_FILENAME,
  2466. FALSE, // if disk is in already dont prompt
  2467. FALSE, // allow escape
  2468. TRUE, // warn for multiple prompts
  2469. NULL // don't care about redraw flag
  2470. );
  2471. SpMemFree(szDiskName);
  2472. SpMemFree(szDevicePath);
  2473. RedrawGauge = TRUE;
  2474. if (rs == FALSE) {
  2475. continue;
  2476. }
  2477. DevicePath = L"\\device\\floppy0";
  2478. wcscpy( TemporaryBuffer, L"\\" );
  2479. Directory = SpDupStringW(TemporaryBuffer); // OemSourceDirectory;
  2480. } else {
  2481. RedrawGauge = TRUE;
  2482. DevicePath = TargetDevicePath;
  2483. wcscpy( TemporaryBuffer, DirectoryOnTargetDevice );
  2484. SpConcatenatePaths( TemporaryBuffer, SETUP_REPAIR_DIRECTORY );
  2485. Directory = SpDupStringW(TemporaryBuffer);
  2486. }
  2487. //
  2488. // Copy the file.
  2489. //
  2490. SpCopyFileWithRetry(
  2491. &FileToCopy,
  2492. DevicePath,
  2493. Directory,
  2494. NULL,
  2495. NULL, // TargetRoot -> NULL
  2496. 0, // SystemPartitionFiles ? ATTR_RHS : 0,
  2497. SppRepairScreenRepaint,
  2498. NULL, // Do not want checksum
  2499. NULL, // Do not want to know if file was skipped
  2500. 0
  2501. );
  2502. SpMemFree( Directory );
  2503. }
  2504. }
  2505. SpMemFree(FullTargetName);
  2506. if (RedrawGauge) {
  2507. SppRepairScreenRepaint(NULL, NULL, TRUE);
  2508. }
  2509. }