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.

4213 lines
122 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spdr.c
  5. Abstract:
  6. Source file for Automated System Recovery (ASR) functions for text-mode
  7. setup. The services defined in this module recreate the boot and system
  8. partitions based on information obtained by reading records from a
  9. configuration file, the asr.sif file (aka SIF).
  10. Terminology
  11. The following terms are used:
  12. 1. The "system" partition is the partition that contains the OS loader
  13. programs (i.e., On x86 platforms these are the boot.ini. ntldr, and
  14. ntdetect.com files, among others).
  15. 2. The "boot" (aka NT) partition is the partition that contains the %SystemRoot%
  16. directory, i.e., the directory containing the NT system files. In the
  17. text-mode setup sources, this directory is also called the
  18. "TargetDirectory" since, when running normal textmode setup, this is the
  19. directory into which NT gets installed.
  20. 3. Extended partition and Logical Disk Terminology
  21. In the SIF file two kinds of extended partition records can be found. The
  22. first kind, of which there may be zero, one, or more, are called Logical
  23. Disk Descriptor records, or LDDs. LDDs describe a partition within an
  24. extended partition. The second kind are called Container Partition
  25. Descriptor records, or CPDs, because they describe extended partitions.
  26. For any disk, at most one extended partition may exist and, therefore, only
  27. one CPD per disk record may exist in the SIF file.
  28. Extended partitions and logical disk support in Windows NT 5.0:
  29. 1) Windows NT 5.0 supports 0 or 1 extended partition per disk.
  30. 2) Logical disks only exist within extended partitions.
  31. 3) An extended partition may contain zero (0) or more logical disk
  32. partitions.
  33. Algorithm for Recovering the System and NT Partitions (see
  34. SpDrPtPrepareDisks()):
  35. For each disk
  36. {
  37. Check whether its capacity is sufficient to contain all the partitions
  38. specified in the asr.sif file for that disk (ie the partition set).
  39. if (Existing Physical Disk Partitions != asr.sif configuration)
  40. {
  41. - Remove disk's existing partitions;
  42. - Recreate disk's partitions according to the asr.sif
  43. specifications.
  44. }
  45. else
  46. {
  47. - Replace all corrupt boot and NT system files, excluding
  48. registry files.
  49. - Set Repaired Flag.
  50. }
  51. }
  52. - Reinstall NT from CDROM into NT directory specified by asr.sif.
  53. - If specified, copy 3rd-party files per asr.sif file.
  54. - Reboot and execute gui-mode disaster recover.
  55. ASR Restrictions:
  56. For the boot and system volumes ASR requires that the restored (new)
  57. system have:
  58. Same number of drives as the old system.
  59. Capacity of each new drive >= capacity of corresponding old drive.
  60. Revision History:
  61. Initial Code Michael Peterson (v-michpe) 13.May.1997
  62. Code cleanup and changes Guhan Suriyanarayanan (guhans) 21.Aug.1999
  63. --*/
  64. #include "spprecmp.h"
  65. #pragma hdrstop
  66. #include <oemtypes.h>
  67. //
  68. // Defaults used for textmode ASR. The static ones aren't accessed from outside
  69. // this file, and are grouped here so that it's easy to change them if need be.
  70. //
  71. static PWSTR ASR_CONTEXT_KEY = L"\\CurrentControlSet\\Control\\Session Manager\\Environment";
  72. static PWSTR ASR_CONTEXT_VALUE = L"ASR_C_CONTEXT";
  73. static PWSTR ASR_CONTEXT_DATA = L"AsrInProgress";
  74. static PWSTR ASR_BOOT_PARTITION_VALUE = L"ASR_C_WINNT_PARTITION_DEVICE";
  75. static PWSTR ASR_SYSTEM_PARTITION_VALUE = L"ASR_C_SYSTEM_PARTITION_DEVICE";
  76. static PWSTR ASR_SIF_NAME = L"asr.sif";
  77. static PWSTR ASR_SIF_PATH = L"\\Device\\Floppy0\\asr.sif";
  78. static PWSTR ASR_SIF_TARGET_PATH = L"\\repair\\asr.sif";
  79. static PWSTR ASR_SETUP_LOG_NAME = L"setup.log";
  80. static PWSTR ASR_DEFAULT_SETUP_LOG_PATH = L"\\Device\\Floppy0\\Setup.log";
  81. extern const PWSTR SIF_ASR_PARTITIONS_SECTION;
  82. extern const PWSTR SIF_ASR_SYSTEMS_SECTION;
  83. PWSTR ASR_FLOPPY0_DEVICE_PATH = L"\\Device\\Floppy0";
  84. PWSTR ASR_CDROM0_DEVICE_PATH = L"\\Device\\CdRom0";
  85. PWSTR ASR_TEMP_DIRECTORY_PATH = L"\\TEMP";
  86. PWSTR ASR_SIF_SYSTEM_KEY = L"1"; // we only handle one system per sif
  87. static PWSTR Gbl_SourceSetupLogFileName = NULL;
  88. PWSTR Gbl_SystemPartitionName = NULL;
  89. PWSTR Gbl_SystemPartitionDirectory = NULL;
  90. PWSTR Gbl_BootPartitionName = NULL;
  91. PWSTR Gbl_BootPartitionDirectory = NULL;
  92. ULONG Gbl_FixedDiskCount = 0;
  93. WCHAR Gbl_BootPartitionDriveLetter;
  94. PVOID Gbl_HandleToSetupLog = NULL;
  95. PVOID Gbl_SifHandle = NULL;
  96. BOOLEAN Gbl_RepairWinntFast = FALSE; // Put in spdrfix.c
  97. BOOLEAN Gbl_NtPartitionIntact = TRUE;
  98. BOOLEAN Gbl_RepairFromErDisk = FALSE;
  99. BOOLEAN Gbl_AsrSifOnInstallationMedia = FALSE;
  100. ASRMODE Gbl_AsrMode = ASRMODE_NONE;
  101. PDISK_REGION Gbl_BootPartitionRegion = NULL;
  102. PDISK_REGION Gbl_SystemPartitionRegion = NULL;
  103. PSIF_PARTITION_RECORD Gbl_SystemPartitionRecord = NULL;
  104. DWORD Gbl_SystemDiskIndex = 0;
  105. PSIF_PARTITION_RECORD Gbl_BootPartitionRecord = NULL;
  106. DWORD Gbl_BootDiskIndex = 0;
  107. PSIF_INSTALLFILE_LIST Gbl_3rdPartyFileList = NULL;
  108. PCONFIGURATION_INFORMATION Gbl_IoDevices = NULL;
  109. PWSTR RemoteBootAsrSifName = NULL;
  110. //
  111. // delay the driver cab opening until required
  112. // (while repair is being performed)
  113. //
  114. PWSTR gszDrvInfDeviceName = 0;
  115. PWSTR gszDrvInfDirName = 0;
  116. HANDLE ghSif = 0;
  117. //
  118. // To Enable/Disable Emergency repair
  119. //
  120. BOOLEAN DisableER = TRUE;
  121. // Module identification for debug traces
  122. #define THIS_MODULE L" spdr.c"
  123. #define THIS_MODULE_CODE L"A"
  124. // Keys valid on various menu screens
  125. #define ASCI_C 67
  126. #define ASCI_c 99
  127. #define ASCI_F 70
  128. #define ASCI_f 102
  129. #define ASCI_M 77
  130. #define ASCI_m 109
  131. #define ASCI_R 82
  132. #define ASCI_r 114
  133. // Useful macros
  134. #define FilesystemNotApplicable ((FilesystemType) FilesystemMax)
  135. // External functions and variables
  136. extern BOOLEAN ForceConsole;
  137. extern const PWSTR SIF_ASR_GPT_PARTITIONS_SECTION;
  138. extern const PWSTR SIF_ASR_MBR_PARTITIONS_SECTION;
  139. extern PWSTR NtBootDevicePath;
  140. extern PWSTR DirectoryOnBootDevice;
  141. extern VOID SpInitializePidString(
  142. IN HANDLE MasterSifHandle,
  143. IN PWSTR SetupSourceDevicePath,
  144. IN PWSTR DirectoryOnSourceDevice
  145. );
  146. extern NTSTATUS SpOpenSetValueAndClose(
  147. IN HANDLE hKeyRoot,
  148. IN PWSTR SubKeyName, OPTIONAL
  149. IN PWSTR ValueName,
  150. IN ULONG ValueType,
  151. IN PVOID Value,
  152. IN ULONG ValueSize
  153. );
  154. extern BOOLEAN
  155. SpPtnCreateLogicalDrive(
  156. IN ULONG DiskNumber,
  157. IN ULONGLONG StartSector,
  158. IN ULONGLONG SizeInSectors,
  159. IN BOOLEAN ForNT,
  160. IN BOOLEAN AlignToCylinder,
  161. IN ULONGLONG DesiredMB OPTIONAL,
  162. IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
  163. OUT PDISK_REGION *ActualDiskRegion OPTIONAL
  164. );
  165. extern ULONG
  166. SpPtnGetPartitionCountDisk(
  167. IN ULONG DiskId
  168. );
  169. extern ULONG
  170. SpPtnGetContainerPartitionCount(
  171. IN ULONG DiskId
  172. );
  173. extern NTSTATUS
  174. SpPtnZapSectors(
  175. IN HANDLE DiskHandle,
  176. IN ULONG BytesPerSector,
  177. IN ULONGLONG StartSector,
  178. IN ULONG SectorCount
  179. );
  180. extern PDISK_REGION
  181. SpPtnLocateESP(
  182. VOID
  183. );
  184. VOID
  185. SpAsrInitIoDeviceCount(VOID)
  186. /*++
  187. Routine Description:
  188. Gets the IO Devices counts and updates Gbl_IoDevices. Prints out
  189. debug information with the deves counts.
  190. Arguments:
  191. None
  192. Return Value:
  193. void
  194. Side Effect:
  195. Updates Gbl_IoDevices with configuration information
  196. --*/
  197. {
  198. ULONG diskIndex;
  199. Gbl_IoDevices = IoGetConfigurationInformation();
  200. //!!review null?
  201. DbgStatusMesg((_asrinfo, "----- I/O Device Configurations: -----\n"));
  202. DbgMesg((_asrinfo, " SCSI ports: %lu\n", Gbl_IoDevices->ScsiPortCount));
  203. DbgMesg((_asrinfo, " Floppy disk drives: %lu\n", Gbl_IoDevices->FloppyCount));
  204. DbgMesg((_asrinfo, " CDROM disk drives: %lu\n", Gbl_IoDevices->CdRomCount));
  205. if (Gbl_IoDevices->TapeCount) {
  206. DbgMesg((_asrinfo, " Tape drives: %lu\n", Gbl_IoDevices->TapeCount));
  207. }
  208. if (Gbl_IoDevices->MediumChangerCount) {
  209. DbgMesg((_asrinfo, " Media changers: %lu\n", Gbl_IoDevices->MediumChangerCount));
  210. }
  211. DbgMesg((_asrinfo, " Hard disk drives: %lu\n", Gbl_IoDevices->DiskCount));
  212. for (diskIndex = 0; diskIndex < Gbl_IoDevices->DiskCount; diskIndex++) {
  213. DbgMesg((_asrinfo, " %ws %s %ws\n",
  214. (PWSTR) HardDisks[diskIndex].DevicePath,
  215. DISK_IS_REMOVABLE(diskIndex) ? "(rmvable):" : "(fixed): ",
  216. (PWSTR) HardDisks[diskIndex].Description));
  217. }
  218. DbgStatusMesg((_asrinfo, "----- End of I/O Device Configurations: -----\n\n"));
  219. }
  220. VOID
  221. SpAsrDbgDumpRegion(
  222. IN PDISK_REGION pRegion
  223. )
  224. {
  225. UCHAR partitionType = 0;
  226. PWSTR partitionPath = NULL;
  227. if (!pRegion) {
  228. KdPrintEx((_asrinfo, "pRegion is NULL. Cannot be examined.\n"));
  229. return;
  230. }
  231. if (!SPPT_IS_REGION_PARTITIONED(pRegion)) {
  232. KdPrintEx((_asrinfo, "[/]: non-partitioned region.\n"));
  233. return;
  234. }
  235. else {
  236. SpNtNameFromRegion(
  237. pRegion,
  238. TemporaryBuffer,
  239. sizeof(TemporaryBuffer),
  240. PartitionOrdinalCurrent
  241. );
  242. partitionPath = SpDupStringW(TemporaryBuffer);
  243. partitionType = SPPT_GET_PARTITION_TYPE(pRegion);
  244. KdPrintEx((_asrinfo, "[%ws]: partitioned. type:0x%x dynamicVol:%s\n",
  245. partitionPath,
  246. partitionType,
  247. pRegion->DynamicVolume ? "Yes" : "No"));
  248. SpMemFree(partitionPath);
  249. }
  250. }
  251. VOID
  252. SpAsrDbgDumpDisk(IN ULONG Disk)
  253. {
  254. PDISK_REGION primaryRegion = NULL,
  255. extRegion = NULL;
  256. DbgMesg((_asrinfo,
  257. "\n SpAsrDbgDumpDisk. Existing regions on disk %lu (sig:0x%x):\n",
  258. Disk,
  259. SpAsrGetActualDiskSignature(Disk)
  260. ));
  261. primaryRegion = SPPT_GET_PRIMARY_DISK_REGION(Disk);
  262. extRegion = SPPT_GET_EXTENDED_DISK_REGION(Disk);
  263. if (!primaryRegion && !extRegion) {
  264. DbgMesg((_asrinfo, "*** No Partitions ***\n"));
  265. return;
  266. }
  267. while (primaryRegion) {
  268. DbgMesg((_asrinfo, "(pri) "));
  269. SpAsrDbgDumpRegion(primaryRegion);
  270. primaryRegion = primaryRegion->Next;
  271. }
  272. while (extRegion) {
  273. DbgMesg((_asrinfo, "(ext) "));
  274. SpAsrDbgDumpRegion(extRegion);
  275. extRegion = extRegion->Next;
  276. }
  277. }
  278. VOID
  279. SpAsrDeletePartitions(
  280. IN ULONG DiskNumber,
  281. IN BOOLEAN PreserveInterestingPartitions, // ESP for GPT, InterestingPartitionType for MBR
  282. IN UCHAR InterestingMbrPartitionType, // see above
  283. OUT BOOLEAN *IsBlank // this is set FALSE if disk contains partitions that weren't deleted
  284. )
  285. {
  286. PPARTITIONED_DISK pDisk = NULL;
  287. PDISK_REGION CurrRegion = NULL;
  288. BOOLEAN Changes = FALSE;
  289. NTSTATUS Status, InitStatus;
  290. BOOLEAN preserveThisPartition = FALSE;
  291. *IsBlank = TRUE;
  292. DbgStatusMesg((_asrinfo,
  293. "Deleting partitions on DiskNumber %lu "
  294. "(partition count: %lu + %lu)\n",
  295. DiskNumber,
  296. SpPtnGetPartitionCountDisk(DiskNumber),
  297. SpPtnGetContainerPartitionCount(DiskNumber)
  298. ));
  299. //
  300. // Check if disk has any partitions
  301. //
  302. pDisk = &PartitionedDisks[DiskNumber];
  303. if (!pDisk) {
  304. return;
  305. }
  306. //
  307. // Mark partitions for deletion
  308. //
  309. CurrRegion = pDisk->PrimaryDiskRegions;
  310. while (CurrRegion) {
  311. if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
  312. preserveThisPartition = FALSE;
  313. if (PreserveInterestingPartitions) {
  314. if (SPPT_IS_GPT_DISK(DiskNumber)) {
  315. if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
  316. preserveThisPartition = TRUE;
  317. }
  318. //
  319. // TODO: OEM partitions on GPT, do we preserve them?
  320. //
  321. }
  322. else {
  323. //
  324. // Preserve the MBR partition, if it matches the OEM partition type
  325. //
  326. if ((PARTITION_ENTRY_UNUSED != InterestingMbrPartitionType) &&
  327. (InterestingMbrPartitionType == SPPT_GET_PARTITION_TYPE(CurrRegion))) {
  328. preserveThisPartition = TRUE;
  329. }
  330. }
  331. }
  332. if (preserveThisPartition) {
  333. DbgStatusMesg((_asrinfo, "Preserving partition with start sector: %I64u\n",
  334. CurrRegion->StartSector));
  335. *IsBlank = FALSE;
  336. SPPT_SET_REGION_DELETED(CurrRegion, FALSE);
  337. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  338. }
  339. else {
  340. DbgStatusMesg((_asrinfo, "Deleting partition with start sector: %I64u\n",
  341. CurrRegion->StartSector));
  342. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  343. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  344. //
  345. // If this is a container partition, make sure we zero it
  346. //
  347. if (SPPT_IS_REGION_CONTAINER_PARTITION(CurrRegion)) {
  348. WCHAR DiskPath[MAX_PATH];
  349. HANDLE DiskHandle;
  350. //
  351. // form the name
  352. //
  353. DbgStatusMesg((_asrinfo,
  354. "Zapping first sector for container partition with start sector: %I64u\n",
  355. CurrRegion->StartSector
  356. ));
  357. swprintf(DiskPath, L"\\Device\\Harddisk%u", DiskNumber);
  358. Status = SpOpenPartition0(DiskPath, &DiskHandle, TRUE);
  359. if (NT_SUCCESS(Status)) {
  360. SpPtnZapSectors(DiskHandle, SPPT_DISK_SECTOR_SIZE(DiskNumber), CurrRegion->StartSector, 2);
  361. ZwClose(DiskHandle);
  362. }
  363. else {
  364. DbgStatusMesg((_asrinfo,
  365. "Could not open handle to disk %lu to zap sector: %I64u (0x%x)\n",
  366. DiskNumber,
  367. CurrRegion->StartSector,
  368. Status
  369. ));
  370. }
  371. }
  372. //
  373. // Remove any boot sets pointing to this region.
  374. //
  375. SpPtDeleteBootSetsForRegion(CurrRegion);
  376. //
  377. // Get rid of the compressed drives, if any
  378. //
  379. if (CurrRegion->NextCompressed != NULL) {
  380. SpDisposeCompressedDrives(CurrRegion->NextCompressed);
  381. CurrRegion->NextCompressed = NULL;
  382. CurrRegion->MountDrive = 0;
  383. CurrRegion->HostDrive = 0;
  384. }
  385. }
  386. }
  387. CurrRegion = CurrRegion->Next;
  388. }
  389. //
  390. // Commit the changes
  391. //
  392. Status = SpPtnCommitChanges(DiskNumber, &Changes);
  393. //
  394. // Initialize region structure for the disk again
  395. //
  396. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  397. if (!NT_SUCCESS(Status) || !Changes || !NT_SUCCESS(InitStatus)) {
  398. DbgFatalMesg((_asrerr,
  399. "Could not successfully delete partitions on disk %lu (0x%x)",
  400. DiskNumber,
  401. Status
  402. ));
  403. //
  404. // If this is going to be a serious problem, we will hit a fatal error
  405. // when we try to create partitions on this disk. Let's defer
  406. // any UI error messages till then.
  407. //
  408. }
  409. else {
  410. DbgStatusMesg((_asrinfo, "Deleted all partitions on disk %lu.\n", DiskNumber));
  411. }
  412. }
  413. BOOLEAN
  414. SpAsrProcessSetupLogFile(
  415. PWSTR FullLogFileName,
  416. BOOLEAN AllowRetry
  417. )
  418. {
  419. PDISK_REGION region = NULL;
  420. BOOLEAN result = FALSE;
  421. DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. (ER) Loading setup log file [%ws]\n", FullLogFileName));
  422. result = SpLoadRepairLogFile(FullLogFileName, &Gbl_HandleToSetupLog);
  423. if (!result) {
  424. if (AllowRetry) {
  425. DbgErrorMesg((_asrwarn,
  426. "ProcessSetupLogFile. Error loading setup log file [%ws]. AllowRetry:TRUE. continuing.\n",
  427. FullLogFileName));
  428. return FALSE;
  429. }
  430. else {
  431. DbgFatalMesg((_asrerr, "ProcessSetupLogFile. Error loading setup log file [%ws]. AllowRetry:FALSE. Terminating.\n",
  432. FullLogFileName));
  433. SpAsrRaiseFatalError(SP_TEXT_DR_NO_SETUPLOG, L"Setup.log file not loaded successfully");
  434. }
  435. }
  436. //
  437. // Determine the system partition, system partition directory, NT partition,
  438. // and the NT partition directory from the setup.log file.
  439. //
  440. SppGetRepairPathInformation(Gbl_HandleToSetupLog,
  441. &Gbl_SystemPartitionName,
  442. &Gbl_SystemPartitionDirectory,
  443. &Gbl_BootPartitionName,
  444. &Gbl_BootPartitionDirectory);
  445. if (!(Gbl_SystemPartitionName && Gbl_SystemPartitionDirectory
  446. && Gbl_BootPartitionName && Gbl_BootPartitionDirectory)) {
  447. DbgFatalMesg((_asrerr,
  448. "ProcessSetupLogFile. Invalid NULL value in one of the following: \n"
  449. ));
  450. DbgMesg((_asrinfo,
  451. "\tGbl_SystemPartitionName: %p Gbl_SystemPartitionDirectory: %p\n",
  452. Gbl_SystemPartitionName,
  453. Gbl_SystemPartitionDirectory
  454. ));
  455. DbgMesg((_asrinfo,
  456. "\tGbl_BootPartitionName: %p Gbl_BootPartitionDirectory: %p\n",
  457. Gbl_BootPartitionName,
  458. Gbl_BootPartitionDirectory
  459. ));
  460. SpAsrRaiseFatalError(SP_TEXT_DR_BAD_SETUPLOG, L"One or more directory and partition names from setup.log were NULL.");
  461. }
  462. //
  463. // Check whether the system and nt partition regions exist on this machine
  464. //
  465. Gbl_SystemPartitionRegion = SpRegionFromNtName(Gbl_SystemPartitionName, PartitionOrdinalCurrent);
  466. if (!Gbl_SystemPartitionRegion) {
  467. DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. System partition [%ws] does not yet exist\n", Gbl_SystemPartitionName));
  468. }
  469. Gbl_BootPartitionRegion = SpRegionFromNtName(Gbl_BootPartitionName, PartitionOrdinalCurrent);
  470. if (!Gbl_BootPartitionRegion) {
  471. DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. Boot partition [%ws] does not yet exist\n", Gbl_BootPartitionName));
  472. }
  473. DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. (ER) DONE loading setup log file [%ws]\n",
  474. FullLogFileName));
  475. return TRUE;
  476. }
  477. BOOLEAN
  478. SpAsrRegionCanBeFormatted(IN PDISK_REGION pRegion)
  479. {
  480. UCHAR partitionType = 0x0;
  481. BOOLEAN canBeFormatted = FALSE;
  482. partitionType = SPPT_GET_PARTITION_TYPE(pRegion);
  483. switch (partitionType) {
  484. case PARTITION_HUGE:
  485. case PARTITION_FAT32:
  486. case PARTITION_IFS:
  487. canBeFormatted = TRUE;
  488. break;
  489. }
  490. return canBeFormatted;
  491. }
  492. FilesystemType
  493. SpAsrGetFsTypeFromPartitionType(
  494. IN UCHAR PartitionType
  495. )
  496. {
  497. FilesystemType fileSystemType = FilesystemUnknown;
  498. // if this is an extended partition, or logical disk, skip it.
  499. if (IsContainerPartition(PartitionType)) {
  500. return FilesystemNotApplicable;
  501. }
  502. if (IsRecognizedFatPartition(PartitionType)) {
  503. fileSystemType = FilesystemFat;
  504. }
  505. else if (IsRecognizedFat32Partition(PartitionType)) {
  506. fileSystemType = FilesystemFat32;
  507. }
  508. else if (IsRecognizedNtfsPartition(PartitionType)) {
  509. fileSystemType = FilesystemNtfs;
  510. }
  511. else {
  512. fileSystemType = FilesystemUnknown;
  513. }
  514. return fileSystemType;
  515. }
  516. BOOLEAN
  517. SpAsrPartitionNeedsFormatting(
  518. IN PDISK_REGION pRegion,
  519. IN UCHAR NewFileSystemType
  520. )
  521. /*++
  522. Description:
  523. This routine is only called when checking whether an existing partition
  524. needs to be [re]formatted.
  525. --*/
  526. {
  527. BOOLEAN needsFormatting = FALSE;
  528. FilesystemType fsType;
  529. ASSERT(pRegion);
  530. // if (!SpAsrRegionCanBeFormatted(pRegion)) {
  531. // return FALSE;
  532. // }
  533. // *NewFilesystemType = SpAsrGetFsTypeFromPartitionType(RequiredSysId);
  534. fsType = SpIdentifyFileSystem(HardDisks[pRegion->DiskNumber].DevicePath,
  535. HardDisks[pRegion->DiskNumber].Geometry.BytesPerSector,
  536. SpPtGetOrdinal(pRegion,PartitionOrdinalCurrent));
  537. switch (fsType) {
  538. case FilesystemFat:
  539. if (!IsRecognizedFatPartition(NewFileSystemType)) {
  540. needsFormatting = TRUE;
  541. }
  542. break;
  543. case FilesystemNtfs:
  544. if (!IsRecognizedNtfsPartition(NewFileSystemType)) {
  545. needsFormatting = TRUE;
  546. }
  547. break;
  548. case FilesystemFat32:
  549. if (!IsRecognizedFat32Partition(NewFileSystemType)) {
  550. needsFormatting = TRUE;
  551. }
  552. break;
  553. case FilesystemDoubleSpace:
  554. needsFormatting = FALSE;
  555. break;
  556. case FilesystemUnknown:
  557. case FilesystemNewlyCreated:
  558. default:
  559. needsFormatting = TRUE;
  560. break;
  561. }
  562. DbgStatusMesg((_asrinfo, "SpAsrPartitionNeedsFormatting. DiskRegion %p Disk:%lu SS:%I64u SC:%I64u fsType:0x%x NewFsType:0x%x NeedsFmt:%s\n",
  563. pRegion,
  564. pRegion->DiskNumber,
  565. pRegion->StartSector,
  566. pRegion->SectorCount,
  567. fsType,
  568. NewFileSystemType,
  569. needsFormatting ? "TRUE" : "FALSE"));
  570. return needsFormatting;
  571. }
  572. //
  573. // Called only for boot and system partitions.
  574. //
  575. BOOLEAN
  576. SpAsrReformatPartition(
  577. IN PDISK_REGION pRegion,
  578. IN UCHAR PartitionType,
  579. IN PVOID SifHandle,
  580. IN DWORD ClusterSize,
  581. IN PWSTR Local_SetupSourceDevicePath,
  582. IN PWSTR Local_DirectoryOnSetupSource,
  583. IN BOOL IsBootPartition // TRUE=>Boot, FALSE=>System
  584. )
  585. {
  586. NTSTATUS status = STATUS_SUCCESS;
  587. PWSTR partitionDeviceName = NULL;
  588. FilesystemType Filesystem;
  589. UNICODE_STRING UnicodeString;
  590. IO_STATUS_BLOCK IoStatusBlock;
  591. OBJECT_ATTRIBUTES Obja;
  592. HANDLE Handle = NULL;
  593. WCHAR formatStr[6]; // okay to hardcode "6".
  594. //
  595. // For the recognised partitions, ensure that the partition type matches the
  596. // filesystem type. For other partitions, we cannot perform this check.
  597. //
  598. switch (PartitionType) {
  599. case PARTITION_FAT32: {
  600. wcscpy(formatStr, L"FAT32");
  601. Filesystem = FilesystemFat32;
  602. break;
  603. }
  604. case PARTITION_HUGE: {
  605. wcscpy(formatStr, L"FAT");
  606. Filesystem = FilesystemFat;
  607. break;
  608. }
  609. case PARTITION_IFS: {
  610. wcscpy(formatStr, L"NTFS");
  611. Filesystem = FilesystemNtfs;
  612. break;
  613. }
  614. default: {
  615. //
  616. // This is fatal, we need to format the boot and system drive.
  617. //
  618. DbgErrorMesg((_asrerr,
  619. "Region %p, Partition Type 0x%x, SifHandle %p, SetupSrc [%ws], Dir [%ws], IsBoot %d\n",
  620. pRegion, PartitionType, SifHandle, Local_SetupSourceDevicePath,
  621. Local_DirectoryOnSetupSource, IsBootPartition
  622. ));
  623. ASSERT(0 && "Cannot format boot or system partition");
  624. swprintf(TemporaryBuffer, L"Partition type 0x%x for %s partition is not recognised\n",
  625. PartitionType,
  626. (IsBootPartition ? "boot" : "system")
  627. );
  628. SpAsrRaiseFatalError(
  629. (IsBootPartition ? SP_TEXT_DR_UNKNOWN_NT_FILESYSTEM : SP_TEXT_DR_UNKNOWN_LOADER_FILESYSTEM),
  630. TemporaryBuffer
  631. );
  632. }
  633. }
  634. if (SPPT_IS_MBR_DISK(pRegion->DiskNumber)) {
  635. //
  636. // This should only be set for MBR disks
  637. //
  638. SPPT_SET_PARTITION_TYPE(pRegion, PartitionType);
  639. }
  640. partitionDeviceName = SpAsrGetRegionName(pRegion);
  641. DbgStatusMesg((_asrinfo, "About to format [%ws] for [%ws].\n", partitionDeviceName, formatStr));
  642. //
  643. // If automated ASR tests are in progress, we won't actually format the drives
  644. //
  645. if (ASRMODE_NORMAL != SpAsrGetAsrMode()) {
  646. DbgStatusMesg((_asrerr, "ASR Quick Tests in Progress, skipping format\n"));
  647. status = STATUS_SUCCESS;
  648. }
  649. else {
  650. status = SpDoFormat(partitionDeviceName,
  651. pRegion,
  652. Filesystem,
  653. TRUE, // IsFailureFatal
  654. FALSE, // Check FAT Size, FALSE since we automatically convert if needed
  655. #ifdef PRERELEASE
  656. TRUE, // To reduce testing time, we can quick format in pre-release
  657. #else
  658. FALSE, // Quick Format
  659. #endif
  660. SifHandle,
  661. ClusterSize,
  662. Local_SetupSourceDevicePath,
  663. Local_DirectoryOnSetupSource
  664. );
  665. }
  666. //
  667. // Won't get here if SpDoFormat failed, we set IsFailureFatal = TRUE.
  668. //
  669. ASSERT(NT_SUCCESS(status) && L"SpDoFormat returned on failure");
  670. //
  671. // To make sure the file system mounts, we'll open a handle to the
  672. // partition and close it right back.
  673. //
  674. INIT_OBJA(&Obja, &UnicodeString, partitionDeviceName);
  675. status = ZwCreateFile(
  676. &Handle,
  677. FILE_GENERIC_READ,
  678. &Obja,
  679. &IoStatusBlock,
  680. NULL,
  681. FILE_ATTRIBUTE_NORMAL,
  682. FILE_SHARE_READ|FILE_SHARE_WRITE,
  683. FILE_OPEN,
  684. FILE_SYNCHRONOUS_IO_NONALERT,
  685. NULL,
  686. 0
  687. );
  688. ZwClose(Handle);
  689. ASSERT(NT_SUCCESS(status) && L"Couldn't open the partition after formatting it");
  690. DbgStatusMesg((_asrinfo, "ReformatPartition. Done [%ws] for [%ws].\n", partitionDeviceName, formatStr));
  691. SpMemFree(partitionDeviceName);
  692. return TRUE;
  693. }
  694. VOID
  695. SpAsrRemoveDiskMountPoints(IN ULONG Disk)
  696. /*++
  697. Description:
  698. For each partition on the specified disk, its drive letter (if
  699. present) is removed.
  700. Arguments:
  701. Disk Specifies the disk containing the partitions whose drive letters
  702. are to be removed.
  703. Returns:
  704. None
  705. --*/
  706. {
  707. PPARTITIONED_DISK pDisk = NULL;
  708. PDISK_REGION pDiskRegion = NULL;
  709. PWSTR partitionPath = NULL;
  710. UCHAR partitionType = 0;
  711. pDisk = &PartitionedDisks[Disk];
  712. DbgStatusMesg((_asrinfo, "SpAsrRemoveDiskMountPoints. Removing mount points for Disk %lu.\n", Disk));
  713. //
  714. // We first delete the primary partitions (other than the container partition)
  715. //
  716. pDiskRegion = pDisk->PrimaryDiskRegions;
  717. while (pDiskRegion) {
  718. if (SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
  719. //
  720. // We don't want to delete the container partition yet
  721. //
  722. partitionType = SPPT_GET_PARTITION_TYPE(pDiskRegion);
  723. if (!IsContainerPartition(partitionType)) {
  724. partitionPath = SpAsrGetRegionName(pDiskRegion);
  725. SpAsrDeleteMountPoint(partitionPath);
  726. SpMemFree(partitionPath);
  727. }
  728. }
  729. pDiskRegion = pDiskRegion->Next;
  730. }
  731. //
  732. // Next, delete the extended region mount points
  733. //
  734. pDiskRegion = pDisk->ExtendedDiskRegions;
  735. while (pDiskRegion) {
  736. if (SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
  737. partitionPath = SpAsrGetRegionName(pDiskRegion);
  738. SpAsrDeleteMountPoint(partitionPath);
  739. SpMemFree(partitionPath);
  740. }
  741. pDiskRegion = pDiskRegion->Next;
  742. }
  743. }
  744. VOID
  745. SpAsrRemoveMountPoints(VOID)
  746. {
  747. ULONG driveCount;
  748. // remove the mount points associated with all removable disk drives (Jaz, Zip, etc.,)
  749. for (driveCount = 0; driveCount < Gbl_IoDevices->DiskCount; driveCount++) {
  750. if (DISK_IS_REMOVABLE(driveCount)) {
  751. swprintf(TemporaryBuffer, L"%ws\\Partition1", (PWSTR) HardDisks[driveCount].DevicePath);
  752. SpAsrDeleteMountPoint(TemporaryBuffer);
  753. }
  754. }
  755. // next, unlink CD-ROM drive letters.
  756. // NB: the device name is case sensitive - Must be CdRom.
  757. for (driveCount = 0; driveCount < Gbl_IoDevices->CdRomCount; driveCount++) {
  758. swprintf(TemporaryBuffer, L"\\Device\\CdRom%u", driveCount);
  759. SpAsrDeleteMountPoint(TemporaryBuffer);
  760. }
  761. // finally, remove the mount points for all partitions on all fixed
  762. // disks attached to the system.
  763. for (driveCount = 0; driveCount < HardDiskCount; driveCount++) {
  764. if (Gbl_PartitionSetTable2[driveCount]) {
  765. SpAsrRemoveDiskMountPoints(driveCount);
  766. }
  767. }
  768. }
  769. VOID
  770. SpAsrSetRegionMountPoint(
  771. IN PDISK_REGION pRegion,
  772. IN PSIF_PARTITION_RECORD pRec
  773. )
  774. {
  775. NTSTATUS status = STATUS_UNSUCCESSFUL;
  776. PWSTR partitionDeviceName = NULL;
  777. BOOLEAN isBoot = FALSE;
  778. //
  779. // Make sure that the input's okay ...
  780. //
  781. if (!pRec) {
  782. DbgErrorMesg((_asrwarn,
  783. "SpAsrSetRegionMountPoint. Rec %p is NULL!\n",
  784. pRec
  785. ));
  786. return;
  787. }
  788. if (!pRegion || !(SPPT_IS_REGION_PARTITIONED(pRegion))) {
  789. DbgErrorMesg((_asrwarn,
  790. "SpAsrSetRegionMountPoint. Region %p is NULL/unpartitioned for ptn-rec:[%ws].\n",
  791. pRegion, pRec->CurrPartKey
  792. ));
  793. return;
  794. }
  795. partitionDeviceName = SpAsrGetRegionName(pRegion);
  796. //
  797. // If this is the boot volume, set the drive letter
  798. //
  799. isBoot = SpAsrIsBootPartitionRecord(pRec->PartitionFlag);
  800. if (isBoot) {
  801. DbgStatusMesg((_asrinfo, "Setting [%ws] boot drive-letter to [%wc]\n",
  802. partitionDeviceName,
  803. Gbl_BootPartitionDriveLetter
  804. ));
  805. status = SpAsrSetPartitionDriveLetter(pRegion, Gbl_BootPartitionDriveLetter);
  806. if (!NT_SUCCESS(status)) {
  807. DbgErrorMesg((_asrwarn, "SpAsrSetRegionMountPoint. SpAsrSetPartitionDriveLetter failed for boot-drive. boot-ptn:[%ws], ptn-rec:[%ws]. (0x%x)\n",
  808. partitionDeviceName,
  809. pRec->CurrPartKey,
  810. status
  811. ));
  812. }
  813. }
  814. //
  815. // And if the volume guid is present, set the volume guid
  816. //
  817. if ((pRec->VolumeGuid) && (wcslen(pRec->VolumeGuid) > 0)) {
  818. DbgStatusMesg((_asrinfo,
  819. "SpAsrSetRegionMountPoint. Setting [%ws] guid to [%ws]\n",
  820. partitionDeviceName, pRec->VolumeGuid
  821. ));
  822. status = SpAsrSetVolumeGuid(pRegion, pRec->VolumeGuid);
  823. if (!NT_SUCCESS(status)) {
  824. DbgErrorMesg((_asrwarn,
  825. "SpAsrSetRegionMountPoint. SpAsrSetVolumeGuid failed. device:[%ws], ptn-rec:[%ws]. (0x%x)\n",
  826. partitionDeviceName, pRec->CurrPartKey, status
  827. ));
  828. }
  829. }
  830. SpMemFree(partitionDeviceName);
  831. }
  832. VOID
  833. SpAsrRestoreDiskMountPoints(IN ULONG DiskIndex)
  834. {
  835. PSIF_PARTITION_RECORD pRec = NULL;
  836. PDISK_REGION pRegion = NULL;
  837. //
  838. // Make sure there is a partition list for the disk
  839. //
  840. if (Gbl_PartitionSetTable2[DiskIndex] == NULL ||
  841. Gbl_PartitionSetTable2[DiskIndex]->pDiskRecord == NULL ||
  842. Gbl_PartitionSetTable2[DiskIndex]->pDiskRecord->PartitionList == NULL) {
  843. return;
  844. }
  845. //
  846. // Go through the paritions and set their mount points. This will also
  847. // set the drive letter for the boot volume. (We have to set it now
  848. // since we can't change it in GUI-mode Setup)
  849. //
  850. pRec = Gbl_PartitionSetTable2[DiskIndex]->pDiskRecord->PartitionList->First;
  851. while (pRec) {
  852. pRegion = SpAsrDiskPartitionExists(DiskIndex, pRec);
  853. if (!pRegion) {
  854. //
  855. // We don't expect to find the regions for the non-critical disks.
  856. //
  857. DbgErrorMesg((_asrwarn,
  858. "RestoreDiskMountPoints: Disk region not found, physical-disk %lu, ptn-rec-key %ws.\n",
  859. DiskIndex,
  860. pRec->CurrPartKey
  861. ));
  862. }
  863. else {
  864. SpAsrSetRegionMountPoint(pRegion, pRec);
  865. }
  866. pRec = pRec->Next;
  867. }
  868. }
  869. VOID
  870. SpAsrUpdatePartitionRecord(
  871. IN ULONG Disk,
  872. IN ULONGLONG NewStartSector,
  873. IN ULONGLONG PrevStartSector,
  874. IN ULONGLONG NewSectorCount
  875. )
  876. {
  877. PSIF_PARTITION_RECORD pRecNew = NULL;
  878. //
  879. // Update the partition record whose disk and partition start sector
  880. // match that of the Disk and PrevStartSector parameters.
  881. //
  882. pRecNew = Gbl_PartitionSetTable2[Disk]->pDiskRecord->PartitionList->First;
  883. while (pRecNew) {
  884. if (pRecNew->StartSector == PrevStartSector) {
  885. pRecNew->StartSector = NewStartSector;
  886. pRecNew->SectorCount = NewSectorCount;
  887. break;
  888. }
  889. pRecNew = pRecNew->Next;
  890. }
  891. }
  892. VOID
  893. SpAsrGetFirstFreespace(
  894. IN ULONG DiskNumber,
  895. IN BOOLEAN IsAPrimaryPartition,
  896. OUT ULONGLONG *StartSector,
  897. OUT ULONGLONG *FreeSectors,
  898. OUT ULONGLONG *SizeMbFree,
  899. IN CONST ULONGLONG MinimumSectorCount
  900. )
  901. {
  902. PDISK_REGION pRegion = NULL;
  903. ULONG NumPartitions = 0;
  904. BOOLEAN extendedExists;
  905. *StartSector = 0;
  906. *FreeSectors = 0;
  907. *SizeMbFree = 0;
  908. NumPartitions = SpPtnGetPartitionCountDisk(DiskNumber)
  909. + SpPtnGetContainerPartitionCount(DiskNumber);
  910. DbgStatusMesg((_asrinfo,
  911. "SpAsrGetFirstFreespace. Dsk %lu. PartitionCount= %lu\n",
  912. DiskNumber,
  913. NumPartitions
  914. ));
  915. pRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  916. if (0 == NumPartitions) {
  917. if (pRegion) {
  918. *StartSector = pRegion->StartSector;
  919. *FreeSectors = pRegion->SectorCount;
  920. if ((*FreeSectors) < MinimumSectorCount) {
  921. *FreeSectors = 0;
  922. }
  923. *SizeMbFree = SpAsrConvertSectorsToMB(*FreeSectors, SPPT_DISK_SECTOR_SIZE(DiskNumber));
  924. return;
  925. }
  926. else {
  927. //
  928. // We have the whole disk at our disposal.
  929. //
  930. *FreeSectors = SpAsrGetTrueDiskSectorCount(DiskNumber);
  931. if ((*FreeSectors) < MinimumSectorCount) {
  932. *FreeSectors = 0;
  933. }
  934. *SizeMbFree = SpAsrConvertSectorsToMB(*FreeSectors, SPPT_DISK_SECTOR_SIZE(DiskNumber));
  935. *StartSector = 0;
  936. return;
  937. }
  938. }
  939. while (pRegion) {
  940. DbgStatusMesg((_asrinfo,
  941. "SpAsrGetFirstFreespace: MinSC: %I64u. Dsk %lu. Region: %p SS %I64u, SC %I64u, %spartitioned, %sfree-space \n",
  942. MinimumSectorCount,
  943. DiskNumber,
  944. pRegion,
  945. pRegion->StartSector,
  946. pRegion->SectorCount,
  947. (SPPT_IS_REGION_PARTITIONED(pRegion) ? "" : "non-"),
  948. (SPPT_IS_REGION_FREESPACE(pRegion) ? "IS " : "not ")
  949. ));
  950. if (SPPT_IS_REGION_FREESPACE(pRegion)) {
  951. ULONGLONG AvailableSectors = 0;
  952. BOOLEAN Found = (IsAPrimaryPartition ?
  953. (!SPPT_IS_REGION_CONTAINER_PARTITION(pRegion) && !SPPT_IS_REGION_INSIDE_CONTAINER(pRegion)) :
  954. (SPPT_IS_REGION_INSIDE_CONTAINER(pRegion))
  955. );
  956. AvailableSectors = pRegion->SectorCount;
  957. //
  958. // If we're trying to create a logical drive, we need to take into account that
  959. // the size of the Free region is not fully available to us for use--the first
  960. // track will be used for the EBR. So we must subtract out the first track
  961. // from the AvailableSectors.
  962. //
  963. if (!IsAPrimaryPartition) {
  964. AvailableSectors -= SPPT_DISK_TRACK_SIZE(DiskNumber);
  965. }
  966. DbgStatusMesg((_asrinfo,
  967. "SpAsrGetFirstFreespace: For this region %p, AvailableSectors:%I64u, Found is %s kind of free space)\n",
  968. pRegion,
  969. AvailableSectors,
  970. (Found ? "TRUE. (right" : "FALSE (wrong")
  971. ));
  972. if ((Found) && (pRegion->StartSector > 0) && (AvailableSectors >= MinimumSectorCount)) {
  973. *StartSector = pRegion->StartSector;
  974. *FreeSectors = AvailableSectors;
  975. *SizeMbFree = SpAsrConvertSectorsToMB(AvailableSectors, SPPT_DISK_SECTOR_SIZE(DiskNumber));
  976. return;
  977. }
  978. }
  979. pRegion = pRegion->Next;
  980. }
  981. }
  982. VOID
  983. SpAsrRecreatePartition(
  984. IN PSIF_PARTITION_RECORD pRec,
  985. IN ULONG DiskNumber,
  986. IN CONST BOOLEAN IsAligned
  987. )
  988. {
  989. NTSTATUS status = STATUS_SUCCESS;
  990. BOOLEAN diskChanged = FALSE,
  991. result = FALSE;
  992. ULONGLONG sizeMbFree = 0,
  993. freeSectors = 0,
  994. oldStartSector = 0,
  995. oldSectorCount = 0,
  996. alignedSector = 0;
  997. WCHAR DiskPath[MAX_PATH];
  998. HANDLE DiskHandle = NULL;
  999. PDISK_REGION pRegion = NULL;
  1000. PARTITION_INFORMATION_EX PartInfo;
  1001. DbgStatusMesg((_asrinfo,
  1002. "Recreating Ptn %p [%ws] (%s, SS %I64u, SC %I64u type 0x%x)\n",
  1003. pRec,
  1004. pRec->CurrPartKey,
  1005. pRec->IsPrimaryRecord ? "Pri" :
  1006. pRec->IsContainerRecord ? "Con" :
  1007. pRec->IsLogicalDiskRecord ? "Log" :
  1008. pRec->IsDescriptorRecord ? "Des" :"ERR",
  1009. pRec->StartSector,
  1010. pRec->SectorCount,
  1011. pRec->PartitionType
  1012. ));
  1013. //
  1014. // Get needed parameters (start sector and remaining free space) from the
  1015. // first unpartitioned region on the disk.
  1016. //
  1017. SpAsrGetFirstFreespace(DiskNumber,
  1018. (pRec->IsPrimaryRecord || pRec->IsContainerRecord),
  1019. &pRec->StartSector,
  1020. &freeSectors, // Sector count of this free space
  1021. &sizeMbFree,
  1022. pRec->SectorCount
  1023. );
  1024. //
  1025. // We fail if the number of free sectors are less than the number
  1026. // of sectors required to create the partition.
  1027. //
  1028. if (!freeSectors) {
  1029. DbgFatalMesg((_asrerr,
  1030. "Ptn-record [%ws]: Disk %lu. reqSec %I64u > available sectors\n",
  1031. pRec->CurrPartKey,
  1032. DiskNumber,
  1033. pRec->SectorCount
  1034. ));
  1035. SpAsrRaiseFatalError(
  1036. SP_TEXT_DR_INSUFFICIENT_CAPACITY,
  1037. L"Not enough free space left to create partition"
  1038. );
  1039. }
  1040. pRec->SizeMB = SpAsrConvertSectorsToMB(pRec->SectorCount, BYTES_PER_SECTOR(DiskNumber));
  1041. //
  1042. // Check if this is an LDM partition on the boot/sys disk. If so,
  1043. // all the 0x42 partitions on that disk need to be retyped to a basic
  1044. // type (6, 7 or B). This is to prevent LDM from getting confused on
  1045. // reboot. At the end of GUI-Setup, asr_ldm will do the needful to
  1046. // reset the partition types as needed.
  1047. //
  1048. if (pRec->NeedsLdmRetype) {
  1049. if (PARTITION_STYLE_MBR == pRec->PartitionStyle) {
  1050. if (!IsRecognizedPartition(pRec->FileSystemType)) {
  1051. //
  1052. // This is an 0x42 partition on the boot/sys disk, but it is
  1053. // not the boot or system partition. The FileSystemType is not
  1054. // recognised since it is set to be 0x42 as well. (The
  1055. // FileSystemType is only valid for the boot and system
  1056. // partitions--for all other partitions,
  1057. // it is set to be the same as the PartitionType)
  1058. //
  1059. // We set it to 0x7 for the time being. The actual file-system type
  1060. // will be set later in GUI-Setup by asr_ldm and asr_fmt.
  1061. //
  1062. DbgStatusMesg((_asrinfo,
  1063. "MBR ptn-rec %ws re-typed (0x%x->0x7) \n",
  1064. pRec->CurrPartKey, pRec->FileSystemType));
  1065. pRec->FileSystemType = PARTITION_IFS;
  1066. pRec->PartitionType = PARTITION_IFS;
  1067. }
  1068. else {
  1069. DbgStatusMesg((_asrinfo,
  1070. "MBR ptn-rec %ws re-typed (0x%x->0x%x).\n",
  1071. pRec->CurrPartKey, pRec->PartitionType,
  1072. pRec->FileSystemType));
  1073. pRec->PartitionType = pRec->FileSystemType;
  1074. }
  1075. }
  1076. else if (PARTITION_STYLE_GPT == pRec->PartitionStyle) {
  1077. DbgStatusMesg((_asrinfo,
  1078. "GPT ptn-rec %ws re-typed (%ws to basic).\n",
  1079. pRec->CurrPartKey, pRec->PartitionTypeGuid));
  1080. CopyMemory(&(pRec->PartitionTypeGuid),
  1081. &PARTITION_BASIC_DATA_GUID, sizeof(GUID));
  1082. }
  1083. else {
  1084. ASSERT(0 && L"Unrecognised partition style");
  1085. }
  1086. }
  1087. RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
  1088. //
  1089. // Fill out the PARTITION_INFORMATION_EX structure that SpPtnCreate uses
  1090. //
  1091. PartInfo.PartitionStyle = pRec->PartitionStyle;
  1092. if (PARTITION_STYLE_MBR == pRec->PartitionStyle) {
  1093. PartInfo.Mbr.PartitionType = pRec->PartitionType;
  1094. PartInfo.Mbr.BootIndicator =
  1095. SpAsrIsSystemPartitionRecord(pRec->PartitionFlag);
  1096. }
  1097. else if (PARTITION_STYLE_GPT == pRec->PartitionStyle) {
  1098. CopyMemory(&(PartInfo.Gpt.PartitionType), &(pRec->PartitionTypeGuid),
  1099. sizeof(GUID));
  1100. CopyMemory(&(PartInfo.Gpt.PartitionId), &(pRec->PartitionIdGuid),
  1101. sizeof(GUID));
  1102. PartInfo.Gpt.Attributes = pRec->GptAttributes;
  1103. wcscpy(PartInfo.Gpt.Name, pRec->PartitionName);
  1104. }
  1105. else {
  1106. //
  1107. // Unrecognised disk layout?
  1108. //
  1109. return;
  1110. }
  1111. DbgStatusMesg((_asrinfo,
  1112. "Recreating Ptn [%ws] (%s, Adjusted SS %I64u, type 0x%x)\n",
  1113. pRec->CurrPartKey, pRec->IsPrimaryRecord ? "Pri" :
  1114. pRec->IsContainerRecord ? "Con" :
  1115. pRec->IsLogicalDiskRecord ? "Log" :
  1116. pRec->IsDescriptorRecord ? "Des" :"ERR",
  1117. pRec->StartSector, pRec->PartitionType));
  1118. //
  1119. // Before creating the partition, let's zero out the first few
  1120. // sectors in that partition, so that we forcibly nuke any
  1121. // stale file-system or other information present
  1122. //
  1123. DbgStatusMesg((_asrinfo,
  1124. "Zeroing 2 sectors starting with sector: %I64u\n",pRec->StartSector));
  1125. swprintf(DiskPath, L"\\Device\\Harddisk%u", DiskNumber);
  1126. status = SpOpenPartition0(DiskPath, &DiskHandle, TRUE);
  1127. if (NT_SUCCESS(status)) {
  1128. status = SpPtnZapSectors(DiskHandle,
  1129. SPPT_DISK_SECTOR_SIZE(DiskNumber),
  1130. pRec->StartSector,
  1131. 2);
  1132. if (!NT_SUCCESS(status)) {
  1133. DbgStatusMesg((_asrwarn,
  1134. "Could not zero sector %I64u on disk %lu (0x%x)\n",
  1135. pRec->StartSector, DiskNumber, status));
  1136. }
  1137. //
  1138. // If the first partition we're creating is a container partition,
  1139. // SpPtnCreate will align it to a cylinder boundary. The problem
  1140. // is that since we haven't zero'ed that sector (at the first
  1141. // cylinder boundary), it may contain some stale EBR info, and we will
  1142. // end up thinking that that EBR is valid.
  1143. //
  1144. // So if this is a container partition, let's do one additional
  1145. // thing--check what the cylinder aligned boundary will be, and
  1146. // zero that out if needed.
  1147. //
  1148. if (IsAligned && pRec->IsContainerRecord) {
  1149. alignedSector = SpPtAlignStart(SPPT_GET_HARDDISK(DiskNumber), pRec->StartSector, TRUE);
  1150. if (alignedSector != pRec->StartSector) {
  1151. status = SpPtnZapSectors(DiskHandle,
  1152. SPPT_DISK_SECTOR_SIZE(DiskNumber),
  1153. alignedSector,
  1154. 2);
  1155. if (!NT_SUCCESS(status)) {
  1156. DbgStatusMesg((_asrwarn,
  1157. "Could not zero aligned-sector %I64u on disk %lu (0x%x)\n",
  1158. alignedSector, DiskNumber, status));
  1159. }
  1160. }
  1161. }
  1162. ZwClose(DiskHandle);
  1163. }
  1164. else {
  1165. DbgStatusMesg((_asrwarn,
  1166. "Could not open handle to disk %lu to zap sector: %I64u (0x%x)\n",
  1167. DiskNumber,
  1168. pRec->StartSector,
  1169. status
  1170. ));
  1171. }
  1172. //
  1173. // Create this partition on disk. If we aren't successful, we treat it as a fatal error.
  1174. //
  1175. if (pRec->IsLogicalDiskRecord) {
  1176. //
  1177. // For logical disks, we need to call SpPtnCreateLogicalDrive, which
  1178. // will take care of creating the descriptor records as needed.
  1179. //
  1180. result = SpPtnCreateLogicalDrive(
  1181. DiskNumber,
  1182. pRec->StartSector,
  1183. pRec->SectorCount,
  1184. TRUE,
  1185. IsAligned,
  1186. pRec->SizeMB,
  1187. &PartInfo,
  1188. &pRegion
  1189. );
  1190. }
  1191. else {
  1192. //
  1193. // If this is a container partition, make sure we zero the
  1194. // first sector of the partition before creating it
  1195. //
  1196. result = SpPtnCreate(
  1197. DiskNumber,
  1198. pRec->StartSector,
  1199. pRec->SectorCount,
  1200. pRec->SizeMB,
  1201. IsContainerPartition(pRec->PartitionType),
  1202. IsAligned,
  1203. &PartInfo,
  1204. &pRegion
  1205. );
  1206. }
  1207. if (!result) {
  1208. DbgFatalMesg((_asrerr, "SpPtnCreate failed for ptn-rec %ws at %p (Disk %lu, SS %I64u, Size %I64u)\n",
  1209. pRec->CurrPartKey,
  1210. pRec,
  1211. DiskNumber,
  1212. pRec->StartSector,
  1213. pRec->SizeMB
  1214. ));
  1215. SpAsrRaiseFatalError(
  1216. SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  1217. TemporaryBuffer
  1218. );
  1219. // does not return
  1220. }
  1221. if (pRec->NeedsLdmRetype) {
  1222. pRec->NeedsLdmRetype = FALSE;
  1223. pRegion->DynamicVolume = TRUE;
  1224. pRegion->DynamicVolumeSuitableForOS = TRUE;
  1225. }
  1226. SpUpdateDoubleSpaceIni();
  1227. //
  1228. // If the new disk geometry is different, the start sector and sector count
  1229. // of the newly created region wil be different from the old values.
  1230. //
  1231. if ((pRec->StartSector != pRegion->StartSector) ||
  1232. (pRec->SectorCount != pRegion->SectorCount)) {
  1233. pRec->StartSector = pRegion->StartSector;
  1234. pRec->SectorCount = pRegion->SectorCount;
  1235. }
  1236. DbgStatusMesg((_asrinfo, "Created %ws at sector %I64u for key [%ws], type 0x%x, region %p.\n",
  1237. pRec->IsPrimaryRecord ? L"primary partition" :
  1238. pRec->IsContainerRecord ? L"container partition" :
  1239. pRec->IsLogicalDiskRecord ? L"logical disk partition" : L"LDM Partition",
  1240. pRegion->StartSector,
  1241. pRec->CurrPartKey,
  1242. pRec->PartitionType,
  1243. pRegion
  1244. ));
  1245. }
  1246. ULONGLONG
  1247. RoundUp(
  1248. IN ULONGLONG Number,
  1249. IN ULONG MultipleOf
  1250. )
  1251. {
  1252. if (Number % MultipleOf) {
  1253. return (Number + (ULONGLONG) MultipleOf - (Number % (ULONGLONG) MultipleOf));
  1254. }
  1255. else {
  1256. return Number;
  1257. }
  1258. }
  1259. BOOLEAN
  1260. SpAsrRecreateDiskPartitions(
  1261. IN ULONG Disk,
  1262. IN BOOLEAN SkipSpecialPartitions, // OEM partitions for x86, ESP for ia64
  1263. IN UCHAR MbrOemPartitionType
  1264. )
  1265. {
  1266. ULONGLONG oldStartSector = 0,
  1267. oldSectorCount = 0;
  1268. PSIF_PARTITION_RECORD pRec = NULL;
  1269. PSIF_PARTITION_RECORD_LIST pList = NULL;
  1270. SIF_PARTITION_RECORD_LIST logicalDiskList;
  1271. SIF_PARTITION_RECORD_LIST primaryPartList;
  1272. ULONG count = 0,
  1273. SectorsPerCylinder = 0;
  1274. BOOLEAN isAligned = TRUE;
  1275. BOOLEAN moveToNext = TRUE;
  1276. ZeroMemory(&logicalDiskList, sizeof(SIF_PARTITION_RECORD_LIST));
  1277. ZeroMemory(&primaryPartList, sizeof(SIF_PARTITION_RECORD_LIST));
  1278. SectorsPerCylinder = HardDisks[Disk].SectorsPerCylinder;
  1279. if (!Gbl_PartitionSetTable1[Disk]->pDiskRecord->PartitionList) {
  1280. //
  1281. // No partitions to recreate
  1282. //
  1283. return TRUE;
  1284. }
  1285. //
  1286. // Split the partitions into two lists, one containing
  1287. // just the primary partitions, and the second containing
  1288. // the logical drives. The primary partition list will
  1289. // also include the container record if any.
  1290. //
  1291. // pList = SpAsrCopyPartitionRecordList(Gbl_PartitionSetTable1[Disk]->pDiskRecord->PartitionList);
  1292. pList = Gbl_PartitionSetTable1[Disk]->pDiskRecord->PartitionList;
  1293. ASSERT(pList);
  1294. isAligned = Gbl_PartitionSetTable1[Disk]->IsAligned;
  1295. pRec = SpAsrPopNextPartitionRecord(pList);
  1296. while (pRec) {
  1297. if (pRec->IsPrimaryRecord || pRec->IsContainerRecord) {
  1298. //
  1299. // Primary records go into the primaryPartList
  1300. //
  1301. if (SkipSpecialPartitions) {
  1302. if ((PARTITION_STYLE_MBR == pRec->PartitionStyle) &&
  1303. (MbrOemPartitionType == pRec->PartitionType)) {
  1304. //
  1305. // This is an OEM partition that already exists on the
  1306. // target machine. Discard this record.
  1307. //
  1308. SpMemFree(pRec);
  1309. pRec = NULL;
  1310. }
  1311. else if ((PARTITION_STYLE_GPT == pRec->PartitionStyle) &&
  1312. (RtlEqualMemory(&(pRec->PartitionTypeGuid), &PARTITION_SYSTEM_GUID, sizeof(GUID)))
  1313. ) {
  1314. //
  1315. // This is the EFI System Partition, and it already
  1316. // exists on the taget machine. Discard this
  1317. // record.
  1318. //
  1319. SpMemFree(pRec);
  1320. pRec = NULL;
  1321. }
  1322. }
  1323. if (pRec) {
  1324. SpAsrInsertPartitionRecord(&primaryPartList, pRec);
  1325. }
  1326. }
  1327. else if (pRec->IsLogicalDiskRecord) {
  1328. //
  1329. // LogicalDiskRecords go into the logicalDisklist
  1330. //
  1331. SpAsrInsertPartitionRecord(&logicalDiskList, pRec);
  1332. }
  1333. else if (pRec->IsDescriptorRecord) {
  1334. //
  1335. // Discard the descriptor records
  1336. //
  1337. SpMemFree(pRec);
  1338. }
  1339. else {
  1340. ASSERT(0 && L"Partition record has incorrect flags set");
  1341. SpMemFree(pRec);
  1342. }
  1343. pRec = SpAsrPopNextPartitionRecord(pList);
  1344. }
  1345. //
  1346. // Recreate the primary partitions first.
  1347. //
  1348. pRec = SpAsrPopNextPartitionRecord(&primaryPartList);
  1349. while (pRec) {
  1350. //
  1351. // If it's the container partition, we need to make sure it's big
  1352. // enough to hold all the logical drives
  1353. //
  1354. if (pRec->IsContainerRecord) {
  1355. ULONGLONG sectorCount = 0;
  1356. PSIF_PARTITION_RECORD pLogicalDiskRec = NULL;
  1357. pLogicalDiskRec = logicalDiskList.First;
  1358. while (pLogicalDiskRec) {
  1359. sectorCount += RoundUp(pLogicalDiskRec->SectorCount, SectorsPerCylinder);
  1360. pLogicalDiskRec = pLogicalDiskRec->Next;
  1361. }
  1362. if (pRec->SectorCount < sectorCount) {
  1363. pRec->SectorCount = sectorCount;
  1364. }
  1365. }
  1366. oldStartSector = pRec->StartSector;
  1367. oldSectorCount = pRec->SectorCount;
  1368. count = SpPtnGetPartitionCountDisk(Disk) + SpPtnGetContainerPartitionCount(Disk);
  1369. SpAsrRecreatePartition(pRec, Disk, isAligned);
  1370. if ((pRec->StartSector != oldStartSector) ||
  1371. (pRec->SectorCount != oldSectorCount)) {
  1372. SpAsrUpdatePartitionRecord(
  1373. Disk,
  1374. pRec->StartSector,
  1375. oldStartSector,
  1376. pRec->SectorCount
  1377. );
  1378. }
  1379. SpMemFree(pRec);
  1380. if (SpPtnGetPartitionCountDisk(Disk) + SpPtnGetContainerPartitionCount(Disk) > (count + 1)) {
  1381. // moveToNext = FALSE;
  1382. // pRec = NULL;
  1383. ASSERT(0 && L"Partition count differs from expected value (stale data?)");
  1384. }
  1385. // else {
  1386. pRec = SpAsrPopNextPartitionRecord(&primaryPartList);
  1387. // }
  1388. }
  1389. if (moveToNext) {
  1390. //
  1391. // Recreate the logical drives next
  1392. //
  1393. pRec = SpAsrPopNextPartitionRecord(&logicalDiskList);
  1394. while (pRec) {
  1395. oldStartSector = pRec->StartSector;
  1396. oldSectorCount = pRec->SectorCount;
  1397. count = SpPtnGetPartitionCountDisk(Disk);
  1398. SpAsrRecreatePartition(pRec, Disk, isAligned);
  1399. if ((pRec->StartSector != oldStartSector) ||
  1400. (pRec->SectorCount != oldSectorCount)) {
  1401. SpAsrUpdatePartitionRecord(
  1402. Disk,
  1403. pRec->StartSector,
  1404. oldStartSector,
  1405. pRec->SectorCount
  1406. );
  1407. }
  1408. SpMemFree(pRec);
  1409. if (SpPtnGetPartitionCountDisk(Disk) > (count + 1)) {
  1410. // moveToNext = FALSE;
  1411. // pRec = NULL;
  1412. ASSERT(0 && L".. Partition count differs from expected value .. (stale data?)");
  1413. }
  1414. // else {
  1415. pRec = SpAsrPopNextPartitionRecord(&logicalDiskList);
  1416. // }
  1417. }
  1418. }
  1419. return moveToNext;
  1420. }
  1421. BOOLEAN
  1422. SpAsrAttemptRepair(
  1423. IN PVOID SifHandle,
  1424. IN PWSTR Local_SetupSourceDevicePath,
  1425. IN PWSTR Local_DirectoryOnSetupSource,
  1426. IN PWSTR AutoSourceDevicePath,
  1427. IN PWSTR AutoDirectoryOnSetupSource
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This routine attempts to replace any missing or corrupted system files with
  1432. their counterparts from an installation source (CDROM, Harddisk, etc). If
  1433. successful, a full-scale installation is not required and the recovery can
  1434. proceed much faster.
  1435. To accomplish this, AsrAttemptRepair() employs the following logic:
  1436. * If \Device\floppy0\setup.log cannot be opened, then repair can
  1437. not proceed and a full-scale install must be performed. Otherwise, the
  1438. repair is begun.
  1439. * The first step in the repair is to verify that the directories
  1440. forming the NT tree are present and accessible. If any of these
  1441. directories are missing or inaccessible, they are recreated and made
  1442. accessible.
  1443. * The second step is to copy any missing or corrupted files from
  1444. installation source. To accomplish this, SppRepairWinntFiles() is
  1445. called. This function checks whether each file enumerated in the
  1446. setup.log file is present on the disk AND that its checksum matches
  1447. that specified in setup.log. If either of these two conditions are
  1448. not met, a new version of the file is copied from the installation
  1449. source (e.g., the CDROM) to the disk.
  1450. Arguments:
  1451. SifHandle Handle to txtsetup.inf
  1452. SetupSourceDevicePath The physical device path of the media containing the
  1453. installation files.
  1454. DirectoryOnSetupSource The name of the directory on the source media (see
  1455. previous parameter) containing the installation files.
  1456. Returns:
  1457. TRUE if the attempted repair operation is successful.
  1458. FALSE if the setup.log file was not opened (ie it wasn't present
  1459. on the ASR/ER floppy), or the system or boot partitions were NULL
  1460. --*/
  1461. {
  1462. if (!(Gbl_HandleToSetupLog &&
  1463. Gbl_SystemPartitionRegion &&
  1464. Gbl_BootPartitionRegion)) {
  1465. return FALSE;
  1466. }
  1467. // run autochk on boot and system partitions
  1468. DbgStatusMesg((_asrinfo,
  1469. "AttemptRepair. Running AutoChk on boot and sys ptns\n"
  1470. ));
  1471. SpRunAutochkOnNtAndSystemPartitions(
  1472. SifHandle,
  1473. Gbl_BootPartitionRegion,
  1474. Gbl_SystemPartitionRegion,
  1475. Local_SetupSourceDevicePath,
  1476. Local_DirectoryOnSetupSource,
  1477. NULL
  1478. );
  1479. //
  1480. // Verify and repair security of the directories that form the NT tree
  1481. // using the information obtained from the setup.log file.
  1482. //
  1483. DbgStatusMesg((_asrinfo,
  1484. "AttemptRepair. Verifying and repairing directory structure\n"
  1485. ));
  1486. SppVerifyAndRepairNtTreeAccess(SifHandle,
  1487. Gbl_BootPartitionName,
  1488. Gbl_BootPartitionDirectory,
  1489. Gbl_SystemPartitionName,
  1490. Gbl_SystemPartitionDirectory
  1491. );
  1492. // initialize the diamond compression engine.
  1493. SpdInitialize();
  1494. //
  1495. // At this point, we are safe in assuming that the partition and directory
  1496. // structures required to recover the system are still intact. That being
  1497. // the case, replace the files whose state is preventing the system from
  1498. // booting.
  1499. //
  1500. if (RepairItems[RepairFiles]) {
  1501. //
  1502. // initialize PID only in case of normal ASR
  1503. //
  1504. if ((ASRMODE_NORMAL == SpAsrGetAsrMode()) && !RepairWinnt) {
  1505. SpInitializePidString(SifHandle,
  1506. Local_SetupSourceDevicePath,
  1507. Local_DirectoryOnSetupSource
  1508. );
  1509. }
  1510. SppRepairWinntFiles(Gbl_HandleToSetupLog,
  1511. SifHandle,
  1512. Local_SetupSourceDevicePath,
  1513. Local_DirectoryOnSetupSource,
  1514. Gbl_SystemPartitionName,
  1515. Gbl_SystemPartitionDirectory,
  1516. Gbl_BootPartitionName,
  1517. Gbl_BootPartitionDirectory
  1518. );
  1519. SppRepairStartMenuGroupsAndItems(Gbl_BootPartitionName, Gbl_BootPartitionDirectory);
  1520. }
  1521. //
  1522. // Repair the hives. This action is only available if the Fast Repair
  1523. // option was chosen.
  1524. //
  1525. if (Gbl_RepairWinntFast) {
  1526. PWSTR directoryOnHiveRepairSource = NULL;
  1527. BOOLEAN tmpRepairFromErDisk = Gbl_RepairFromErDisk;
  1528. //
  1529. // Create the complete hive repair path
  1530. //
  1531. wcscpy(TemporaryBuffer, Gbl_BootPartitionDirectory);
  1532. SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
  1533. directoryOnHiveRepairSource = SpDupStringW(TemporaryBuffer);
  1534. Gbl_RepairFromErDisk = FALSE;
  1535. SppRepairHives(SifHandle,
  1536. Gbl_BootPartitionName,
  1537. Gbl_BootPartitionDirectory,
  1538. Gbl_BootPartitionName,
  1539. directoryOnHiveRepairSource
  1540. );
  1541. SpMemFree(directoryOnHiveRepairSource);
  1542. Gbl_RepairFromErDisk = tmpRepairFromErDisk;
  1543. }
  1544. SpdTerminate();
  1545. return TRUE;
  1546. }
  1547. BOOLEAN
  1548. SpDoRepair(
  1549. IN PVOID SifHandle,
  1550. IN PWSTR SetupSourceDevicePath,
  1551. IN PWSTR DirectoryOnSetupSource,
  1552. IN PWSTR AutoSourceDevicePath,
  1553. IN PWSTR AutoDirectoryOnSetupSource,
  1554. IN PWSTR RepairPath,
  1555. IN PULONG RepairOptions
  1556. )
  1557. {
  1558. ULONG count = 0;
  1559. ASRMODE prevMode = ASRMODE_NONE;
  1560. BOOLEAN returnValue = FALSE;
  1561. for (count = 0; count < RepairItemMax; count++) {
  1562. RepairItems[count] = RepairOptions[count];
  1563. }
  1564. prevMode = SpAsrSetAsrMode(TRUE);
  1565. Gbl_SourceSetupLogFileName = RepairPath;
  1566. SpAsrProcessSetupLogFile(Gbl_SourceSetupLogFileName, FALSE);
  1567. returnValue = SpAsrAttemptRepair(SifHandle,
  1568. SetupSourceDevicePath,
  1569. DirectoryOnSetupSource,
  1570. AutoSourceDevicePath,
  1571. AutoDirectoryOnSetupSource
  1572. );
  1573. SpAsrSetAsrMode(prevMode);
  1574. return returnValue;
  1575. }
  1576. VOID
  1577. SpAsrRepairOrDRMenu(VOID)
  1578. /*++
  1579. Routine Description:
  1580. Display a screen allowing the user to choose among the repair
  1581. options: Recovery Console, Conventional Repair, ASR or Exit.
  1582. Arguments:
  1583. None.
  1584. Return Value:
  1585. None.
  1586. Side Effects:
  1587. Sets the following global flags to indicate user's selection:
  1588. ForceConsole set to TRUE if user wants Recovery Console
  1589. RepairWinnt set to TRUE if user wants Conventional Repair
  1590. SpAsrSetAsrMode(ASRMODE_NORMAL) if user wants Conventional Repair or ASR
  1591. --*/
  1592. {
  1593. ULONG repairKeys[] = {KEY_F3, KEY_F10, 0};
  1594. ULONG mnemonicKeys[] = {MnemonicConsole, MnemonicRepair, 0};
  1595. BOOLEAN done = TRUE;
  1596. ULONG UserOption;
  1597. do {
  1598. done = TRUE;
  1599. if (SpIsERDisabled()) {
  1600. UserOption = (MnemonicConsole | KEY_MNEMONIC); // only Command console
  1601. } else {
  1602. // display the choice screen for the user.
  1603. SpDisplayScreen(SP_SCRN_DR_OR_REPAIR,3,4);
  1604. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1605. SP_STAT_C_EQUALS_CMDCONS,
  1606. SP_STAT_R_EQUALS_REPAIR,
  1607. SP_STAT_F3_EQUALS_EXIT,
  1608. 0
  1609. );
  1610. // wait for keypress. Valid keys:
  1611. // F3 = exit
  1612. // F10,C = Recovery Console
  1613. // R = Repair Winnt
  1614. // A = Automated System Recovery (ASR)
  1615. SpInputDrain();
  1616. UserOption = SpWaitValidKey(repairKeys,NULL,mnemonicKeys);
  1617. }
  1618. switch(UserOption) {
  1619. case KEY_F3:
  1620. // User wants to exit.
  1621. SpConfirmExit();
  1622. done = FALSE;
  1623. break;
  1624. case KEY_F10:
  1625. case (MnemonicConsole | KEY_MNEMONIC):
  1626. // User wants the recovery console.
  1627. ForceConsole = TRUE;
  1628. SpAsrSetAsrMode(ASRMODE_NONE);
  1629. RepairWinnt = FALSE;
  1630. break;
  1631. case (MnemonicRepair | KEY_MNEMONIC):
  1632. // User wants conventional repair.
  1633. SpAsrSetAsrMode(ASRMODE_NORMAL);
  1634. RepairWinnt = TRUE;
  1635. break;
  1636. default:
  1637. // User doesn't want any of our choices. Show him the same screen again.
  1638. done = FALSE;
  1639. break;
  1640. }
  1641. } while (!done);
  1642. }
  1643. BOOLEAN
  1644. SpAsrRepairManualOrFastMenu(VOID)
  1645. /*++
  1646. Routine Description:
  1647. Display a screen allowing the user to choose between Manual and Fast
  1648. Repair modes. Manual--user will select options on next screen,
  1649. Fast--defaults are used
  1650. Arguments:
  1651. None.
  1652. Return Value:
  1653. TRUE if the user selected a repair mode
  1654. FALSE if the user hit <ESC> to cancel
  1655. Side Effect:
  1656. Gbl_RepairWinntFast is set to TRUE if user selects Fast Repair, FALSE otherwise
  1657. --*/
  1658. {
  1659. ULONG repairKeys[] = {KEY_F3, ASCI_ESC, 0};
  1660. ULONG mnemonicKeys[] = {MnemonicFastRepair, MnemonicManualRepair, 0};
  1661. BOOLEAN done;
  1662. do {
  1663. done = TRUE;
  1664. //
  1665. // Display the choice screen for the user.
  1666. //
  1667. SpDisplayScreen(SP_SCRN_REPAIR_MANUAL_OR_FAST,3,4);
  1668. SpDisplayStatusOptions(
  1669. DEFAULT_STATUS_ATTRIBUTE,
  1670. SP_STAT_M_EQUALS_REPAIR_MANUAL,
  1671. SP_STAT_F_EQUALS_REPAIR_FAST,
  1672. SP_STAT_ESC_EQUALS_CANCEL,
  1673. SP_STAT_F3_EQUALS_EXIT,
  1674. 0
  1675. );
  1676. //
  1677. // wait for keypress. Valid keys:
  1678. // F3 = exit
  1679. // ESC = cancel
  1680. // M = Manual Repair
  1681. // F = Fast Repair
  1682. //
  1683. SpInputDrain();
  1684. switch(SpWaitValidKey(repairKeys,NULL,mnemonicKeys)) {
  1685. case KEY_F3:
  1686. // User wants to exit.
  1687. SpConfirmExit();
  1688. break;
  1689. case (MnemonicManualRepair | KEY_MNEMONIC):
  1690. // User wants manual repair, i.e., choose from the list.
  1691. Gbl_RepairWinntFast = FALSE;
  1692. break;
  1693. case (MnemonicFastRepair | KEY_MNEMONIC):
  1694. // User wants fast repair, i.e., don't show the list.
  1695. Gbl_RepairWinntFast = TRUE;
  1696. break;
  1697. case ASCI_ESC:
  1698. // User wants to cancel
  1699. return FALSE;
  1700. default:
  1701. // User doesn't want any of our choices
  1702. done = FALSE;
  1703. break;
  1704. }
  1705. } while (!done);
  1706. return TRUE;
  1707. }
  1708. //
  1709. // Returns true if this physical disk is to be skipped while
  1710. // repartitioning all the disks. (i.e., this disk is intact,
  1711. // or is removable, etc)
  1712. //
  1713. BOOLEAN
  1714. SpAsrpSkipDiskRepartition(
  1715. IN DWORD DiskIndex,
  1716. IN BOOLEAN SkipNonCritical // should we skip non-critical disks?
  1717. )
  1718. {
  1719. //
  1720. // Skip removable disks. They are not counted in the
  1721. // partition set table, hence their entry is NULL.
  1722. //
  1723. if (NULL == Gbl_PartitionSetTable1[DiskIndex]) {
  1724. return TRUE;
  1725. }
  1726. //
  1727. // Skip disks for which no disk record exists in asr.sif
  1728. //
  1729. if (NULL == Gbl_PartitionSetTable1[DiskIndex]->pDiskRecord) {
  1730. return TRUE;
  1731. }
  1732. //
  1733. // Skip disks for which a disk record may exist but no
  1734. // partition records reference that disk record.
  1735. //
  1736. if (NULL == Gbl_PartitionSetTable1[DiskIndex]->pDiskRecord->PartitionList) {
  1737. return TRUE;
  1738. }
  1739. //
  1740. // Skip non-critical disks if told to.
  1741. //
  1742. if ((SkipNonCritical) && (FALSE == Gbl_PartitionSetTable1[DiskIndex]->pDiskRecord->IsCritical)) {
  1743. return TRUE;
  1744. }
  1745. //
  1746. // Skip disks that are intact
  1747. //
  1748. if (Gbl_PartitionSetTable1[DiskIndex]->PartitionsIntact) {
  1749. return TRUE;
  1750. }
  1751. return FALSE;
  1752. }
  1753. VOID
  1754. SpAsrClobberDiskWarning(VOID)
  1755. /*++
  1756. Routine Description:
  1757. Display a screen warning the user that when a partition on a disk is
  1758. to be recreated, *all* partitions on that disk are clobbered, and
  1759. allowing the user to abort.
  1760. Arguments:
  1761. None.
  1762. Return Value:
  1763. None.
  1764. --*/
  1765. {
  1766. ULONG validKeys[] = {KEY_F3, 0};
  1767. ULONG mnemonicKeys[] = {MnemonicContinueSetup, 0};
  1768. BOOLEAN done = FALSE,
  1769. skip = FALSE;
  1770. DWORD diskIndex = 0;
  1771. ULONG Keypress = 0;
  1772. PVOID Menu;
  1773. ULONG MenuTopY;
  1774. //
  1775. // Dummy variables for user selection data, we don't use these
  1776. //
  1777. ULONG_PTR FirstData = 0,
  1778. ReturnedData = 0;
  1779. if ((ASRMODE_NORMAL != SpAsrGetAsrMode()) || SpAsrGetSilentRepartitionFlag(ASR_SIF_SYSTEM_KEY)) {
  1780. //
  1781. // Automated tests; don't display warning menu
  1782. //
  1783. return;
  1784. }
  1785. //
  1786. // Display the "your disks will be repartitioned" warning message
  1787. //
  1788. SpDisplayScreen(SP_SCRN_DR_DISK_REFORMAT_WARNING,3,CLIENT_TOP+1);
  1789. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1790. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  1791. SP_STAT_F3_EQUALS_EXIT,
  1792. 0
  1793. );
  1794. //
  1795. // And generate the list of disks that will be repartitioned.
  1796. // Calculate menu placement. Leave one blank line and one
  1797. // line for a frame.
  1798. //
  1799. MenuTopY = NextMessageTopLine + 2;
  1800. //
  1801. // Create a menu.
  1802. //
  1803. Menu = SpMnCreate(3, MenuTopY, (VideoVars.ScreenWidth-6),
  1804. (VideoVars.ScreenHeight - MenuTopY -
  1805. (SplangQueryMinimizeExtraSpacing() ? 1 : 2) - STATUS_HEIGHT)
  1806. );
  1807. if (!Menu) {
  1808. SpAsrRaiseFatalError(SP_SCRN_OUT_OF_MEMORY, L"SpMnCreate failed");
  1809. }
  1810. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  1811. skip = SpAsrpSkipDiskRepartition(diskIndex, FALSE);
  1812. if (!skip) {
  1813. PHARD_DISK Disk = SPPT_GET_HARDDISK(diskIndex);
  1814. if (!FirstData) {
  1815. FirstData = (ULONG_PTR)Disk;
  1816. }
  1817. if (!SpMnAddItem(Menu, Disk->Description, 3, (VideoVars.ScreenWidth-6), TRUE, (ULONG_PTR)Disk)) {
  1818. SpAsrRaiseFatalError(SP_SCRN_OUT_OF_MEMORY, L"SpMnAddItem failed");
  1819. }
  1820. }
  1821. }
  1822. SpInputDrain();
  1823. do {
  1824. //
  1825. // wait for keypress. Valid keys:
  1826. // C = continue
  1827. // F3 = exit
  1828. //
  1829. SpMnDisplay(Menu,
  1830. FirstData,
  1831. TRUE,
  1832. validKeys,
  1833. mnemonicKeys,
  1834. NULL, // no new highlight callback
  1835. &Keypress,
  1836. &ReturnedData
  1837. );
  1838. switch(Keypress) {
  1839. case KEY_F3:
  1840. //
  1841. // User wants to exit--confirm.
  1842. //
  1843. SpConfirmExit();
  1844. break;
  1845. case (MnemonicContinueSetup | KEY_MNEMONIC):
  1846. //
  1847. // User wants to continue with Setup
  1848. //
  1849. done = TRUE;
  1850. break;
  1851. }
  1852. } while (!done);
  1853. SpMnDestroy(Menu);
  1854. }
  1855. VOID
  1856. SpAsrCannotDoER(VOID)
  1857. /*++
  1858. Routine Description:
  1859. Display a screen informing the user that ER canot be performed on
  1860. the system because the boot partition in not intact, i.e., ASR
  1861. recreated/reformatted that partition.
  1862. Arguments:
  1863. None.
  1864. Return Value:
  1865. None.
  1866. --*/
  1867. {
  1868. ULONG warningKeys[] = { KEY_F3, 0 };
  1869. ULONG mnemonicKeys[] = { 0 };
  1870. // display the message screen
  1871. SpDisplayScreen(SP_SCRN_DR_CANNOT_DO_ER,3,4);
  1872. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1873. SP_STAT_F3_EQUALS_EXIT,
  1874. 0
  1875. );
  1876. // wait for keypress. Valid key:
  1877. // F3 = exit
  1878. SpInputDrain();
  1879. do {
  1880. switch(SpWaitValidKey(warningKeys,NULL,mnemonicKeys)) {
  1881. case KEY_F3:
  1882. // User wants to exit.
  1883. return;
  1884. }
  1885. } while (TRUE);
  1886. }
  1887. VOID
  1888. SpAsrQueryRepairOrDr()
  1889. /*++
  1890. -pending code description
  1891. --*/
  1892. {
  1893. BOOLEAN done = TRUE;
  1894. do {
  1895. done = TRUE;
  1896. // ask the user if he wants repair or ASR
  1897. SpAsrRepairOrDRMenu();
  1898. if (RepairWinnt) {
  1899. // User wants to repair, check Manual or Fast
  1900. if (done = SpAsrRepairManualOrFastMenu()) {
  1901. if (Gbl_RepairWinntFast) { // Fast Repair
  1902. RepairItems[RepairNvram] = 1;
  1903. RepairItems[RepairFiles] = 1;
  1904. #ifdef _X86_
  1905. RepairItems[RepairBootSect] = 1;
  1906. #endif
  1907. }
  1908. else { // Manual Repair
  1909. done = SpDisplayRepairMenu();
  1910. }
  1911. }
  1912. }
  1913. } while (!done);
  1914. }
  1915. BOOLEAN
  1916. SpAsrOpenAsrStateFile(ULONG *ErrorLine, PWSTR AsrSifPath)
  1917. {
  1918. NTSTATUS status;
  1919. ASSERT(ErrorLine);
  1920. *ErrorLine = 0;
  1921. // load asr.sif
  1922. status = SpLoadSetupTextFile(
  1923. AsrSifPath,
  1924. NULL,
  1925. 0,
  1926. &Gbl_HandleToDrStateFile,
  1927. ErrorLine,
  1928. TRUE,
  1929. FALSE
  1930. );
  1931. if (!NT_SUCCESS(status)) {
  1932. DbgErrorMesg((_asrerr, "SpAsrOpenAsrStateFile. Unable to open %ws. status:0x%x ErrorLine:%lu\n",
  1933. AsrSifPath,
  1934. status,
  1935. *ErrorLine));
  1936. Gbl_HandleToDrStateFile = NULL;
  1937. return FALSE;
  1938. }
  1939. return TRUE;
  1940. }
  1941. BOOLEAN
  1942. SpAsrLoadAsrDiskette(VOID)
  1943. /*++
  1944. Routine Description:
  1945. This routine checks for a floppy drive. If one is not found, this routine
  1946. never returns, Setup terminates with an error. If a floppy drive is found,
  1947. this routine prompts for the ASR disk. If the disk is loaded, it reads and
  1948. parses the asr.sif file.
  1949. Arguments:
  1950. None.
  1951. Return Values:
  1952. TRUE if disk was loaded successfully
  1953. DOES NOT RETURN if no floppy drive was found, or if asr.sif is corrupt.
  1954. --*/
  1955. {
  1956. ULONG errorAtLine = 0,
  1957. diskIndex = 0;
  1958. PWSTR diskName = NULL;
  1959. PWSTR diskDeviceName = NULL;
  1960. PWSTR localAsrSifPath = NULL;
  1961. BOOLEAN result = FALSE;
  1962. if (!RemoteBootSetup) {
  1963. //
  1964. // Look for the asr.sif in the boot directory. If it isn't present
  1965. // in the boot directory, we'll look for it on the floppy drive.
  1966. //
  1967. localAsrSifPath = SpMemAlloc((wcslen(NtBootDevicePath)+wcslen(ASR_SIF_NAME)+2) * sizeof(WCHAR));
  1968. if (localAsrSifPath) {
  1969. localAsrSifPath[0] = UNICODE_NULL;
  1970. wcscpy(localAsrSifPath,NtBootDevicePath);
  1971. SpConcatenatePaths(localAsrSifPath,ASR_SIF_NAME);
  1972. result = SpAsrOpenAsrStateFile(&errorAtLine, localAsrSifPath);
  1973. Gbl_AsrSifOnInstallationMedia = result;
  1974. SpMemFree(localAsrSifPath);
  1975. localAsrSifPath = NULL;
  1976. }
  1977. if (!result) {
  1978. //
  1979. // Check if the machine has a floppy drive. This is kind of redundant,
  1980. // since he couldn't have got this far if there isn't a floppy drive.
  1981. // However, we've had cases where setupldr recognises the floppy drive,
  1982. // but we then loose the floppy by the time we get here.
  1983. //
  1984. if (SpGetFloppyDriveType(0) == FloppyTypeNone) {
  1985. SpAsrRaiseFatalError(
  1986. SP_TEXT_DR_NO_FLOPPY_DRIVE,
  1987. L"Floppy drive does not exist"
  1988. );
  1989. // does not return
  1990. }
  1991. SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_DR_DISK_NAME);
  1992. diskName = SpDupStringW(TemporaryBuffer);
  1993. diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
  1994. //
  1995. // Prompt for the disk. We don't allow him to hit ESC to cancel,
  1996. // since he can't quit out of ASR at this point.
  1997. //
  1998. SpPromptForDisk(
  1999. diskName,
  2000. diskDeviceName,
  2001. ASR_SIF_NAME,
  2002. FALSE, // no ignore disk in drive
  2003. FALSE, // no allow escape
  2004. FALSE, // no warn multiple prompts
  2005. NULL // don't care about redraw flag
  2006. );
  2007. DbgStatusMesg((_asrinfo,
  2008. "SpAsrLoadAsrDiskette. Disk [%ws] loaded successfully on %ws\n",
  2009. diskName, diskDeviceName
  2010. ));
  2011. SpMemFree(diskName);
  2012. SpMemFree(diskDeviceName);
  2013. //
  2014. // Open asr.sif from the floppy. If we can't read it, it's a fatal
  2015. // error.
  2016. //
  2017. result = SpAsrOpenAsrStateFile(&errorAtLine, ASR_SIF_PATH);
  2018. }
  2019. } else {
  2020. //
  2021. // open the file from the remote location
  2022. //
  2023. RemoteBootAsrSifName = SpGetSectionKeyIndex(
  2024. WinntSifHandle,
  2025. L"OSChooser",
  2026. L"ASRINFFile",
  2027. 0);
  2028. if (!RemoteBootAsrSifName) {
  2029. SpAsrRaiseFatalError(
  2030. SP_TEXT_DR_NO_ASRSIF_RIS,
  2031. L"Couldn't get ASRINFFile from winnt.sif in RIS case"
  2032. );
  2033. // does not return
  2034. }
  2035. result = SpAsrOpenAsrStateFile(&errorAtLine, RemoteBootAsrSifName);
  2036. }
  2037. if (!result) {
  2038. swprintf(TemporaryBuffer, L"Failed to load/parse asr.sif at line %lu\n",
  2039. errorAtLine);
  2040. if (errorAtLine > 0) {
  2041. SpAsrRaiseFatalErrorLu(SP_TEXT_DR_STATEFILE_BAD_LINE,
  2042. TemporaryBuffer,
  2043. errorAtLine
  2044. );
  2045. }
  2046. else {
  2047. SpAsrRaiseFatalError(SP_TEXT_DR_STATEFILE_ERROR, TemporaryBuffer);
  2048. }
  2049. // does not return
  2050. }
  2051. //
  2052. // Set Gbl_FixedDiskCount
  2053. //
  2054. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  2055. Gbl_FixedDiskCount += DISK_IS_REMOVABLE(diskIndex) ? 0 : 1;
  2056. }
  2057. AutoPartitionPicker = FALSE;
  2058. return TRUE;
  2059. }
  2060. BOOLEAN
  2061. SpAsrLoadErDiskette(VOID)
  2062. /*++
  2063. Routine Description:
  2064. This routine checks for a floppy drive, and prompts for the ER
  2065. Diskette if a drive is found. If a floppy drive is not found,
  2066. this routine never returns, Setup terminates with an error.
  2067. Arguments:
  2068. None.
  2069. Return Values:
  2070. TRUE if disk was loaded successfully
  2071. FALSE otherwise (user hit cancel, or there was no floppy drive present)
  2072. --*/
  2073. {
  2074. BOOLEAN diskLoaded = FALSE;
  2075. PWSTR diskName = NULL,
  2076. diskDeviceName = NULL;
  2077. // check if an A: drive exists.
  2078. if (SpGetFloppyDriveType(0) == FloppyTypeNone) {
  2079. SpAsrRaiseFatalError(
  2080. SP_TEXT_DR_NO_FLOPPY_DRIVE,
  2081. L"Floppy drive does not exist"
  2082. );
  2083. // does not return
  2084. }
  2085. SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer),
  2086. SP_TEXT_REPAIR_OR_DR_DISK_NAME);
  2087. diskName = SpDupStringW(TemporaryBuffer);
  2088. diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
  2089. // prompt for the disk.
  2090. diskLoaded = SpPromptForDisk(
  2091. diskName,
  2092. diskDeviceName,
  2093. ASR_SETUP_LOG_NAME,
  2094. TRUE,
  2095. TRUE,
  2096. FALSE,
  2097. NULL
  2098. );
  2099. DbgStatusMesg((_asrinfo, "SpAsrLoadErDiskette. ER disk [%ws] %s loaded successfully on %s\n",
  2100. diskName, diskLoaded?"":"NOT", diskDeviceName));
  2101. SpMemFree(diskName);
  2102. SpMemFree(diskDeviceName);
  2103. return diskLoaded;
  2104. }
  2105. BOOLEAN
  2106. SpAsrGetErFromHardDrive(
  2107. IN PVOID MasterSifHandle,
  2108. OUT PVOID *RepairSifHandle,
  2109. OUT PWSTR *FullLogFileName
  2110. )
  2111. /*++
  2112. -pending code description
  2113. --*/
  2114. {
  2115. BOOLEAN foundRepairableSystem = FALSE,
  2116. result = FALSE;
  2117. DbgStatusMesg((_asrinfo, "SpAsrGetErFromHardDrive. ER: Attempting to load ER data from Hard drive"));
  2118. //
  2119. // If user has no emergency repair diskette, we need to find out
  2120. // if there is any NT to repair and which one to repair.
  2121. //
  2122. result = SpFindNtToRepair(MasterSifHandle,
  2123. &Gbl_BootPartitionRegion,
  2124. &Gbl_BootPartitionDirectory,
  2125. &Gbl_SystemPartitionRegion,
  2126. &Gbl_SystemPartitionDirectory,
  2127. &foundRepairableSystem
  2128. );
  2129. if (result) {
  2130. //
  2131. // Repairable systems were found, and the user selected one to repair
  2132. //
  2133. //
  2134. // Get the device path of the system and boot partitions.
  2135. //
  2136. SpNtNameFromRegion(Gbl_SystemPartitionRegion,
  2137. TemporaryBuffer,
  2138. sizeof(TemporaryBuffer),
  2139. PartitionOrdinalCurrent
  2140. );
  2141. Gbl_SystemPartitionName = SpDupStringW(TemporaryBuffer);
  2142. SpNtNameFromRegion(Gbl_BootPartitionRegion,
  2143. TemporaryBuffer,
  2144. sizeof(TemporaryBuffer),
  2145. PartitionOrdinalCurrent
  2146. );
  2147. Gbl_BootPartitionName = SpDupStringW(TemporaryBuffer);
  2148. //
  2149. // Form the full NT path of the setup.log file in the chosen
  2150. // system on the hard drive.
  2151. //
  2152. SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
  2153. SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
  2154. SpConcatenatePaths(TemporaryBuffer, SETUP_LOG_FILENAME);
  2155. *FullLogFileName = SpDupStringW(TemporaryBuffer);
  2156. DbgStatusMesg((_asrinfo,
  2157. "ER: User picked system to repair. boot-ptn:[%ws] sys-ptn:[%ws] log-file:[%ws]\n",
  2158. Gbl_BootPartitionName,
  2159. Gbl_SystemPartitionName,
  2160. *FullLogFileName
  2161. ));
  2162. //
  2163. // Read and process the setup.log file.
  2164. //
  2165. result = SpLoadRepairLogFile(*FullLogFileName, RepairSifHandle);
  2166. if (!result) {
  2167. //
  2168. // Load setup.log failed. Ask user to insert a ER diskette again.
  2169. //
  2170. DbgErrorMesg((_asrwarn,
  2171. "ER: Attempt to load log file [%ws] FAILED\n",
  2172. *FullLogFileName
  2173. ));
  2174. return FALSE;
  2175. }
  2176. //
  2177. // Setup file was read. Will return TRUE
  2178. //
  2179. Gbl_RepairFromErDisk = FALSE;
  2180. }
  2181. else {
  2182. //
  2183. // User did not select a system to repair
  2184. //
  2185. if (foundRepairableSystem) {
  2186. //
  2187. // Setup found a WINNT installation, but no installation was
  2188. // chosen by the user. We will go back to ask for the ER
  2189. // diskette again.
  2190. //
  2191. DbgErrorMesg((_asrwarn, "ER: Repairable systems were found, but user did not select any\n"));
  2192. return FALSE;
  2193. }
  2194. else {
  2195. //
  2196. // Couldn't find any NT to repair
  2197. //
  2198. ULONG validKeys[] = {KEY_F3, ASCI_CR, 0};
  2199. ULONG mnemonicKeys[] = {MnemonicCustom, 0};
  2200. DbgErrorMesg((_asrwarn, "ER: No repairable systems were found\n"));
  2201. SpStartScreen(SP_SCRN_REPAIR_NT_NOT_FOUND,
  2202. 3,
  2203. HEADER_HEIGHT+1,
  2204. FALSE,
  2205. FALSE,
  2206. DEFAULT_ATTRIBUTE
  2207. );
  2208. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2209. SP_STAT_ENTER_EQUALS_REPAIR,
  2210. SP_STAT_F3_EQUALS_EXIT,
  2211. 0
  2212. );
  2213. SpInputDrain();
  2214. switch (SpWaitValidKey(validKeys,NULL,NULL)) {
  2215. case KEY_F3:
  2216. //
  2217. // User wants to exit Setup
  2218. //
  2219. SpDone(0,TRUE,TRUE);
  2220. break;
  2221. default:
  2222. return FALSE;
  2223. }
  2224. }
  2225. }
  2226. return TRUE;
  2227. }
  2228. BOOLEAN
  2229. SpAsrGetErDiskette(IN PVOID SifHandle)
  2230. /*++
  2231. -pending code description
  2232. --*/
  2233. {
  2234. PWSTR fullLogFileName = NULL;
  2235. BOOLEAN done = FALSE,
  2236. hasErDisk = FALSE;
  2237. while (!done) {
  2238. //
  2239. // display message to let user know he can either provide his
  2240. // own ER disk or let setup search for him.
  2241. //
  2242. if (!SpErDiskScreen(&hasErDisk)) {
  2243. return FALSE;
  2244. }
  2245. Gbl_HandleToSetupLog = NULL;
  2246. fullLogFileName = NULL;
  2247. if (hasErDisk) {
  2248. //
  2249. // Ask for emergency repair diskette until either we get it or
  2250. // user cancels the request.
  2251. //
  2252. done = SpAsrLoadErDiskette();
  2253. if (done) {
  2254. Gbl_SourceSetupLogFileName = ASR_DEFAULT_SETUP_LOG_PATH;
  2255. done = SpAsrProcessSetupLogFile(Gbl_SourceSetupLogFileName, TRUE);
  2256. }
  2257. }
  2258. else {
  2259. done = SpAsrGetErFromHardDrive(SifHandle, &Gbl_HandleToSetupLog, &fullLogFileName);
  2260. if (fullLogFileName) {
  2261. Gbl_SourceSetupLogFileName = SpDupStringW(fullLogFileName);
  2262. SpMemFree(fullLogFileName);
  2263. }
  2264. }
  2265. }
  2266. DbgStatusMesg((_asrinfo, "SpAsrGetErDiskette. ER: %s Floppy. Using setup log file [%ws]\n",
  2267. hasErDisk?"Using":"NO", (Gbl_SourceSetupLogFileName ? Gbl_SourceSetupLogFileName : L"")));
  2268. return TRUE;
  2269. }
  2270. PSIF_PARTITION_RECORD
  2271. SpAsrGetBootPartitionRecord(VOID)
  2272. {
  2273. ULONG diskIndex = 0;
  2274. PSIF_PARTITION_RECORD pRecord = NULL;
  2275. if (Gbl_BootPartitionRecord) {
  2276. return Gbl_BootPartitionRecord;
  2277. }
  2278. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  2279. //
  2280. // Find NT partition record from the partition set table.
  2281. //
  2282. if (Gbl_PartitionSetTable2[diskIndex] == NULL ||
  2283. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord == NULL ||
  2284. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList == NULL) {
  2285. continue;
  2286. }
  2287. DbgStatusMesg((_asrinfo, "Disk %lu ptn records: ", diskIndex));
  2288. pRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
  2289. while (pRecord) {
  2290. DbgMesg((_asrinfo, "[%ws]", pRecord->CurrPartKey));
  2291. if (SpAsrIsBootPartitionRecord(pRecord->PartitionFlag)) {
  2292. ASSERT((pRecord->NtDirectoryName) && L"Boot partition is missing NT directory name.");
  2293. return pRecord;
  2294. }
  2295. pRecord = pRecord->Next;
  2296. }
  2297. DbgMesg((_asrinfo, "\n"));
  2298. }
  2299. DbgFatalMesg((_asrerr, "SpAsrGetBootPartitionRecord. No boot partition record was found.\n"));
  2300. SpAsrRaiseFatalErrorWs(
  2301. SP_SCRN_DR_SIF_BAD_RECORD,
  2302. L"No boot partition found in asr.sif",
  2303. SIF_ASR_PARTITIONS_SECTION
  2304. );
  2305. //
  2306. // Never gets here
  2307. //
  2308. return NULL;
  2309. }
  2310. PWSTR
  2311. SpDrGetNtDirectory(VOID)
  2312. /*++
  2313. Routine Description:
  2314. Returns the target path according to the value found in the asr.sif
  2315. file, but without the leading drive letter and colon.
  2316. Arguments:
  2317. None
  2318. Return Value:
  2319. A pointer to a string containing the NT directory path. This will be of
  2320. the form:
  2321. \WINDOWS
  2322. and not:
  2323. C:\WINDOWS
  2324. --*/
  2325. {
  2326. PSIF_PARTITION_RECORD pRecord = SpAsrGetBootPartitionRecord();
  2327. return (pRecord ? pRecord->NtDirectoryName : NULL);
  2328. }
  2329. ASRMODE
  2330. SpAsrGetAsrMode(VOID)
  2331. /*++
  2332. Routine Description:
  2333. Returns whether ASR is in progress
  2334. Return Value:
  2335. The Asr type currently in progress.
  2336. --*/
  2337. {
  2338. return Gbl_AsrMode;
  2339. }
  2340. ASRMODE
  2341. SpAsrSetAsrMode(
  2342. IN CONST ASRMODE NewAsrMode
  2343. )
  2344. /*++
  2345. Routine Description:
  2346. Sets the Gbl_AsrMode state variable to the value of NewAsrMode.
  2347. Arguments:
  2348. NewAsrMode - new Asr mode
  2349. Return Value:
  2350. Returns the previous Asr mode
  2351. --*/
  2352. {
  2353. ASRMODE oldMode = Gbl_AsrMode;
  2354. Gbl_AsrMode = NewAsrMode;
  2355. return oldMode;
  2356. }
  2357. BOOLEAN
  2358. SpDrEnabled(VOID) {
  2359. //
  2360. // Asr is enabled if Gbl_AsrMode is set to anything other than
  2361. // ASRMODE_NONE
  2362. //
  2363. return (ASRMODE_NONE != Gbl_AsrMode);
  2364. }
  2365. BOOLEAN
  2366. SpAsrIsQuickTest(VOID) {
  2367. return (
  2368. (ASRMODE_QUICKTEST_TEXT == Gbl_AsrMode) ||
  2369. (ASRMODE_QUICKTEST_FULL == Gbl_AsrMode)
  2370. );
  2371. }
  2372. BOOLEAN
  2373. SpDrIsRepairFast(VOID)
  2374. /*++
  2375. Routine Description:
  2376. Tests whether the "Fast" Emergency Repair flag is set.
  2377. Return Value:
  2378. TRUE if "Fast" ER flag is set
  2379. FALSE otherwise
  2380. --*/
  2381. {
  2382. return Gbl_RepairWinntFast;
  2383. }
  2384. BOOLEAN
  2385. SpDrSetRepairFast(BOOLEAN NewValue)
  2386. /*++
  2387. Routine Description:
  2388. Sets the "Fast" Emergency Repair flag.
  2389. Arguments:
  2390. Value New Value (TRUE or FALSE) to which to set the
  2391. Gbl_RepairWinntFast flag
  2392. Return Value:
  2393. Previous value of Gbl_RepairWinntFast;
  2394. --*/
  2395. {
  2396. BOOLEAN oldValue = Gbl_RepairWinntFast;
  2397. Gbl_RepairWinntFast = NewValue;
  2398. return oldValue;
  2399. }
  2400. extern VOID
  2401. SpAsrDbgDumpSystemMountPoints(VOID);
  2402. VOID
  2403. SpDrCleanup(VOID)
  2404. /*++
  2405. -pending code description
  2406. --*/
  2407. {
  2408. ULONG diskIndex = 0;
  2409. //
  2410. // Remove all the mountpoints in the system, we shall recreate them.
  2411. //
  2412. SpAsrRemoveMountPoints();
  2413. DbgStatusMesg((_asrinfo, "Restoring volume mount points.\n"));
  2414. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  2415. if (!(DISK_IS_REMOVABLE(diskIndex))) {
  2416. SpAsrRestoreDiskMountPoints(diskIndex);
  2417. SpAsrDbgDumpDisk(diskIndex);
  2418. }
  2419. }
  2420. // DbgStatusMesg((_asrinfo, "Dumping mount points AFTER text-mode ASR:\n"));
  2421. // SpAsrDbgDumpSystemMountPoints();
  2422. }
  2423. VOID
  2424. SpAsrCopyStateFile(VOID)
  2425. {
  2426. NTSTATUS status = STATUS_SUCCESS;
  2427. PWSTR diskName = NULL,
  2428. targetFilePath = NULL,
  2429. sourceFilePath = NULL,
  2430. bootPartition = NULL,
  2431. diskDeviceName = NULL;
  2432. SpdInitialize();
  2433. SpFormatMessage(
  2434. TemporaryBuffer,
  2435. sizeof(TemporaryBuffer),
  2436. SP_TEXT_DR_DISK_NAME
  2437. );
  2438. diskName = SpDupStringW(TemporaryBuffer);
  2439. if (RemoteBootAsrSifName == NULL) {
  2440. if (Gbl_AsrSifOnInstallationMedia) {
  2441. wcscpy(TemporaryBuffer,NtBootDevicePath);
  2442. SpConcatenatePaths(TemporaryBuffer,ASR_SIF_NAME);
  2443. sourceFilePath = SpDupStringW(TemporaryBuffer);
  2444. }
  2445. else {
  2446. //
  2447. // Prompt the user to insert the ASR disk, if it isn't
  2448. // already in the drive
  2449. //
  2450. diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
  2451. sourceFilePath = SpDupStringW(ASR_SIF_PATH);
  2452. SpPromptForDisk(
  2453. diskName,
  2454. diskDeviceName,
  2455. ASR_SIF_NAME,
  2456. FALSE, // no ignore disk in drive
  2457. FALSE, // no allow escape
  2458. TRUE, // warn multiple prompts
  2459. NULL // don't care about redraw flag
  2460. );
  2461. SpMemFree(diskDeviceName);
  2462. }
  2463. } else {
  2464. sourceFilePath = SpDupStringW(RemoteBootAsrSifName);
  2465. }
  2466. //
  2467. // Build the full path to the directory into which the file will be
  2468. // written.
  2469. //
  2470. bootPartition = SpAsrGetRegionName(Gbl_BootPartitionRegion);
  2471. if (!Gbl_BootPartitionDirectory) {
  2472. Gbl_BootPartitionDirectory = SpDrGetNtDirectory();
  2473. }
  2474. wcscpy(TemporaryBuffer, bootPartition);
  2475. SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
  2476. SpConcatenatePaths(TemporaryBuffer, ASR_SIF_TARGET_PATH);
  2477. targetFilePath = SpDupStringW(TemporaryBuffer);
  2478. SpMemFree(bootPartition);
  2479. //
  2480. // Copy the file. In case of errors, user will have the option
  2481. // to retry, or quit Setup. We cannot skip this file.
  2482. //
  2483. do {
  2484. if (SpFileExists(targetFilePath, FALSE)) {
  2485. SpDeleteFile(targetFilePath, NULL, NULL);
  2486. }
  2487. status = SpCopyFileUsingNames(
  2488. sourceFilePath,
  2489. targetFilePath,
  2490. 0,
  2491. 0
  2492. );
  2493. if (!NT_SUCCESS(status)) {
  2494. DbgErrorMesg((_asrwarn, "SpAsrCopyFiles. Could not copy asr.sif. src:[%ws] dest:[%ws]. (0x%x)\n",
  2495. ASR_SIF_PATH,
  2496. targetFilePath,
  2497. status
  2498. ));
  2499. SpAsrFileErrorRetrySkipAbort(
  2500. SP_SCRN_DR_SIF_NOT_FOUND,
  2501. ASR_SIF_PATH,
  2502. diskName,
  2503. NULL,
  2504. FALSE // no allow skip
  2505. );
  2506. }
  2507. } while (!NT_SUCCESS(status));
  2508. SpdTerminate();
  2509. SpMemFree(diskName);
  2510. SpMemFree(targetFilePath);
  2511. SpMemFree(sourceFilePath);
  2512. }
  2513. NTSTATUS
  2514. SpAsrCopy3rdPartyFiles(
  2515. VOID
  2516. )
  2517. {
  2518. PWSTR bootPartition = NULL,
  2519. fullTargetPath = NULL,
  2520. fullSourcePath = NULL,
  2521. windirPathPrefix = NULL,
  2522. tempPathPrefix = NULL;
  2523. BOOL moveToNext = FALSE,
  2524. diskLoaded = FALSE;
  2525. NTSTATUS status = STATUS_SUCCESS;
  2526. PSIF_INSTALLFILE_RECORD pRec = NULL;
  2527. if (!Gbl_3rdPartyFileList) {
  2528. //
  2529. // No files to copy, we're done
  2530. //
  2531. return STATUS_SUCCESS;
  2532. }
  2533. //
  2534. // Build the expansion strings for
  2535. // %TEMP%, %TMP%, and %SYSTEMROOT%
  2536. //
  2537. bootPartition = SpAsrGetRegionName(Gbl_BootPartitionRegion);
  2538. if (!Gbl_BootPartitionDirectory) {
  2539. Gbl_BootPartitionDirectory = SpDrGetNtDirectory();
  2540. }
  2541. wcscpy(TemporaryBuffer, bootPartition);
  2542. SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
  2543. windirPathPrefix = SpDupStringW(TemporaryBuffer);
  2544. wcscpy(TemporaryBuffer, bootPartition);
  2545. SpConcatenatePaths(TemporaryBuffer, ASR_TEMP_DIRECTORY_PATH);
  2546. tempPathPrefix = SpDupStringW(TemporaryBuffer);
  2547. //
  2548. // Create the TEMP directory
  2549. //
  2550. SpCreateDirectory(
  2551. bootPartition,
  2552. NULL,
  2553. ASR_TEMP_DIRECTORY_PATH,
  2554. 0,
  2555. 0
  2556. );
  2557. SpMemFree(bootPartition);
  2558. //
  2559. // Initialize the compression engine. We may have to uncompress files
  2560. //
  2561. SpdInitialize();
  2562. //
  2563. // Begin copying the files over
  2564. //
  2565. //! display status setup is copying ...
  2566. while (pRec = SpAsrRemoveInstallFileRecord(Gbl_3rdPartyFileList)) {
  2567. if ((!pRec->DestinationFilePath) ||
  2568. (!pRec->SourceFilePath) ||
  2569. (!pRec->DiskDeviceName) ||
  2570. (!pRec->SourceMediaExternalLabel)
  2571. ) {
  2572. ASSERT(0 && L"InstallFiles: Invalid record, one or more attributes are NULL");
  2573. continue;
  2574. }
  2575. diskLoaded = TRUE;
  2576. //
  2577. // Prompt the user for the media if needed
  2578. //
  2579. if ((pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA) ||
  2580. (pRec->Flags & ASR_PROMPT_USER_ON_MEDIA_ERROR)
  2581. ) {
  2582. do {
  2583. moveToNext = TRUE;
  2584. //
  2585. // Prompt the user to insert the appropriate disk
  2586. //
  2587. diskLoaded = SpPromptForDisk(
  2588. pRec->SourceMediaExternalLabel,
  2589. pRec->DiskDeviceName, // if this isn't CD or floppy, SpPromptForDisk will always return true
  2590. pRec->SourceFilePath,
  2591. (BOOLEAN)(pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA), // IgnoreDiskInDrive if PromptAlways
  2592. ! (BOOLEAN)(pRec->Flags & ASR_FILE_IS_REQUIRED), // AllowEscape if the File is not Required
  2593. TRUE, // WarnMultiplePrompts
  2594. NULL
  2595. );
  2596. //
  2597. // If the user hit <ESC> to cancel, we put up a prompt allowing
  2598. // him to retry, skip this file and continue, or exit from Setup.
  2599. //
  2600. if (!diskLoaded) {
  2601. moveToNext = SpAsrFileErrorRetrySkipAbort(
  2602. SP_SCRN_DR_SIF_INSTALL_FILE_NOT_FOUND,
  2603. pRec->SourceFilePath,
  2604. pRec->SourceMediaExternalLabel,
  2605. pRec->VendorString,
  2606. !(pRec->Flags & ASR_FILE_IS_REQUIRED) // allow skip
  2607. );
  2608. }
  2609. } while (!moveToNext);
  2610. }
  2611. if (!diskLoaded) {
  2612. //
  2613. // Disk was not loaded and the user wants to skip this file
  2614. //
  2615. DbgErrorMesg((_asrwarn,
  2616. "SpDrCopy3rdPartyFiles: User skipped file (disk not loaded), src:[%ws] dest[%ws]\n",
  2617. pRec->SourceFilePath,
  2618. pRec->DestinationFilePath
  2619. ));
  2620. continue;
  2621. }
  2622. //
  2623. // The correct disk was loaded. Build the full target path. pRec->CopyToDirectory
  2624. // indicates which prefix we should use.
  2625. //
  2626. switch (pRec->CopyToDirectory) {
  2627. case _SystemRoot:
  2628. wcscpy(TemporaryBuffer, windirPathPrefix);
  2629. break;
  2630. case _Temp:
  2631. case _Tmp:
  2632. case _Default:
  2633. default:
  2634. wcscpy(TemporaryBuffer, tempPathPrefix);
  2635. break;
  2636. }
  2637. SpConcatenatePaths(TemporaryBuffer, pRec->DestinationFilePath);
  2638. fullTargetPath = SpDupStringW(TemporaryBuffer);
  2639. //
  2640. // If the file already exists, prompt the user if needed. We allow him
  2641. // to over-write (delete the existing file), preserve existing
  2642. // (skip copying this file), or exit from Setup.
  2643. //
  2644. if (SpFileExists(fullTargetPath, FALSE)) {
  2645. BOOL deleteFile = FALSE;
  2646. if (pRec->Flags & ASR_PROMPT_USER_ON_COLLISION) {
  2647. if (SpAsrFileErrorDeleteSkipAbort(SP_SCRN_DR_OVERWRITE_EXISTING_FILE, fullTargetPath)) {
  2648. deleteFile = TRUE;
  2649. }
  2650. }
  2651. else if (pRec->Flags & ASR_OVERWRITE_ON_COLLISION) {
  2652. deleteFile = TRUE;
  2653. }
  2654. if (deleteFile) {
  2655. //
  2656. // User chose to overwrite (or OVERWRITE_ON_COLLISION flag was set)
  2657. //
  2658. SpDeleteFile(fullTargetPath, NULL, NULL);
  2659. DbgErrorMesg((_asrwarn,
  2660. "SpDrCopy3rdPartyFiles: Over-writing file, src:[%ws] dest[%ws]\n",
  2661. pRec->SourceFilePath,
  2662. fullTargetPath
  2663. ));
  2664. }
  2665. else {
  2666. //
  2667. // User chose to preserve existing file
  2668. //
  2669. DbgErrorMesg((_asrwarn,
  2670. "SpDrCopy3rdPartyFiles: File exists, existing file was preserved. src:[%ws] dest[%ws]\n",
  2671. pRec->SourceFilePath,
  2672. fullTargetPath
  2673. ));
  2674. continue;
  2675. }
  2676. }
  2677. //
  2678. // Combine the devicepath ("\device\cdrom0") and the sourcefilepath
  2679. // ("i386\driver.sys") to get the full path ("\device\cdrom0\i386\driver.sys")
  2680. // SpConcatenatePaths takes care of adding in the \ between the two if needed
  2681. //
  2682. wcscpy(TemporaryBuffer, pRec->DiskDeviceName);
  2683. SpConcatenatePaths(TemporaryBuffer, pRec->SourceFilePath);
  2684. fullSourcePath = SpDupStringW(TemporaryBuffer);
  2685. moveToNext = FALSE;
  2686. while (!moveToNext) {
  2687. moveToNext = TRUE;
  2688. status = SpCopyFileUsingNames(
  2689. fullSourcePath,
  2690. fullTargetPath,
  2691. 0, // no attributes
  2692. 0 // no flags
  2693. );
  2694. if (!NT_SUCCESS(status)) {
  2695. DbgErrorMesg((_asrwarn, "SpDrCopy3rdPartyFiles. SpCopyFileUsingNames failed. src:[%ws] dest:[%ws]. (0x%x)\n",
  2696. pRec->SourceFilePath,
  2697. fullTargetPath,
  2698. status
  2699. ));
  2700. //
  2701. // File copy was unsuccessful, we put up a prompt allowing
  2702. // the user to retry, skip this file and continue, or exit
  2703. // from Setup.
  2704. //
  2705. if ((pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA) ||
  2706. (pRec->Flags & ASR_PROMPT_USER_ON_MEDIA_ERROR)) {
  2707. moveToNext = SpAsrFileErrorRetrySkipAbort(
  2708. SP_SCRN_DR_SIF_INSTALL_FILE_NOT_FOUND,
  2709. pRec->SourceFilePath,
  2710. pRec->SourceMediaExternalLabel,
  2711. pRec->VendorString,
  2712. TRUE // allow skip
  2713. );
  2714. }
  2715. else {
  2716. moveToNext = TRUE;
  2717. }
  2718. }
  2719. }
  2720. if (!NT_SUCCESS(status)) {
  2721. DbgErrorMesg((_asrwarn, "SpDrCopy3rdPartyFiles: Unable to copy file (copy error), src:[%ws] dest[%ws]\n",
  2722. pRec->SourceFilePath,
  2723. fullTargetPath
  2724. ));
  2725. }
  2726. else {
  2727. DbgStatusMesg((_asrinfo, "SpDrCopy3rdPartyFiles. Copied [%ws] to [%ws]\n",
  2728. pRec->SourceFilePath,
  2729. fullTargetPath
  2730. ));
  2731. }
  2732. SpMemFree(fullSourcePath);
  2733. SpMemFree(fullTargetPath);
  2734. SpAsrDeleteInstallFileRecord(pRec);
  2735. }
  2736. //
  2737. // Done. Shut down the compression engine.
  2738. //
  2739. SpdTerminate();
  2740. SpMemFree(Gbl_3rdPartyFileList);
  2741. SpMemFree(tempPathPrefix);
  2742. SpMemFree(windirPathPrefix);
  2743. return STATUS_SUCCESS;
  2744. }
  2745. NTSTATUS
  2746. SpDrCopyFiles(VOID)
  2747. {
  2748. SpAsrCopyStateFile();
  2749. return SpAsrCopy3rdPartyFiles();
  2750. }
  2751. #define STRING_VALUE(s) REG_SZ,(s),(wcslen((s))+1)*sizeof(WCHAR)
  2752. NTSTATUS
  2753. SpDrSetEnvironmentVariables(HANDLE *HiveRootKeys)
  2754. {
  2755. NTSTATUS status;
  2756. status = SpOpenSetValueAndClose(
  2757. HiveRootKeys[SetupHiveSystem],
  2758. ASR_CONTEXT_KEY,
  2759. ASR_CONTEXT_VALUE,
  2760. STRING_VALUE(ASR_CONTEXT_DATA));
  2761. DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
  2762. ASR_CONTEXT_KEY,
  2763. ASR_CONTEXT_VALUE,
  2764. ASR_CONTEXT_DATA,
  2765. status));
  2766. if (!NT_SUCCESS(status)) {
  2767. return status;
  2768. }
  2769. Gbl_SystemPartitionName = SpAsrGetRegionName(Gbl_SystemPartitionRegion);
  2770. status = SpOpenSetValueAndClose(
  2771. HiveRootKeys[SetupHiveSystem],
  2772. ASR_CONTEXT_KEY,
  2773. ASR_SYSTEM_PARTITION_VALUE,
  2774. STRING_VALUE(Gbl_SystemPartitionName));
  2775. DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
  2776. ASR_CONTEXT_KEY,
  2777. ASR_SYSTEM_PARTITION_VALUE,
  2778. Gbl_SystemPartitionName,
  2779. status));
  2780. if (!NT_SUCCESS(status)) {
  2781. return status;
  2782. }
  2783. Gbl_BootPartitionName = SpAsrGetRegionName(Gbl_BootPartitionRegion);
  2784. status = SpOpenSetValueAndClose(
  2785. HiveRootKeys[SetupHiveSystem],
  2786. ASR_CONTEXT_KEY,
  2787. ASR_BOOT_PARTITION_VALUE,
  2788. STRING_VALUE(Gbl_BootPartitionName));
  2789. DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
  2790. ASR_CONTEXT_KEY,
  2791. ASR_BOOT_PARTITION_VALUE,
  2792. Gbl_BootPartitionName,
  2793. status));
  2794. return status;
  2795. }
  2796. PDISK_REGION
  2797. SpAsrPrepareBootRegion(
  2798. IN PVOID SifHandle,
  2799. IN PWSTR Local_SetupSourceDevicePath,
  2800. IN PWSTR Local_DirectoryOnSetupSource
  2801. )
  2802. /*++
  2803. -pending code description
  2804. --*/
  2805. {
  2806. PWSTR systemKey = ASR_SIF_SYSTEM_KEY;
  2807. PWSTR ntDir = NULL;
  2808. ULONG diskIndex = 0;
  2809. PSIF_PARTITION_RECORD ppartitionRecord = NULL;
  2810. FilesystemType regionFsType = FilesystemUnknown;
  2811. BOOLEAN isBoot = FALSE;
  2812. //
  2813. // Initialize Gbl_BootPartitionDriveLetter.
  2814. //
  2815. ntDir = SpAsrGetNtDirectoryPathBySystemKey(systemKey);
  2816. if (!SpAsrIsValidBootDrive(ntDir)) {
  2817. SpAsrRaiseFatalErrorWs(
  2818. SP_SCRN_DR_SIF_BAD_RECORD,
  2819. L"Windows directory specified in asr.sif is invalid",
  2820. SIF_ASR_SYSTEMS_SECTION
  2821. );
  2822. // Does not return
  2823. }
  2824. Gbl_BootPartitionDriveLetter = ntDir[0];
  2825. //
  2826. // Find boot partition region from the partition set table.
  2827. // from the records in the global partition set.
  2828. //
  2829. Gbl_BootPartitionRegion = NULL;
  2830. for (diskIndex = 0; (diskIndex < HardDiskCount); diskIndex++) {
  2831. if (!(Gbl_PartitionSetTable2[diskIndex] &&
  2832. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord &&
  2833. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList)) {
  2834. continue;
  2835. }
  2836. ppartitionRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
  2837. while (ppartitionRecord) {
  2838. isBoot = SpAsrIsBootPartitionRecord(ppartitionRecord->PartitionFlag);
  2839. if (isBoot) {
  2840. Gbl_BootPartitionRegion = SpAsrDiskPartitionExists(diskIndex, ppartitionRecord);
  2841. if (!Gbl_BootPartitionRegion) {
  2842. DbgFatalMesg((_asrerr,
  2843. "Partition record with boot region found, but boot (winnt) region is NULL\n"
  2844. ));
  2845. SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  2846. L"Boot pRegion is NULL"
  2847. );
  2848. }
  2849. Gbl_BootPartitionRecord = SpAsrCopyPartitionRecord(ppartitionRecord);
  2850. break;
  2851. }
  2852. ppartitionRecord = ppartitionRecord->Next;
  2853. }
  2854. }
  2855. if (!Gbl_BootPartitionRegion) {
  2856. DbgFatalMesg((_asrerr, "No partition record with boot region found, boot (winnt) region is NULL\n"));
  2857. SpAsrRaiseFatalErrorWs(
  2858. SP_SCRN_DR_SIF_BAD_RECORD,
  2859. L"No boot partition found in asr.sif",
  2860. SIF_ASR_PARTITIONS_SECTION
  2861. );
  2862. }
  2863. SpAsrReformatPartition(Gbl_BootPartitionRegion,
  2864. Gbl_BootPartitionRecord->FileSystemType,
  2865. SifHandle,
  2866. Gbl_BootPartitionRecord->ClusterSize,
  2867. Local_SetupSourceDevicePath,
  2868. Local_DirectoryOnSetupSource,
  2869. TRUE
  2870. );
  2871. return Gbl_BootPartitionRegion;
  2872. }
  2873. PDISK_REGION
  2874. SpAsrPrepareSystemRegion(
  2875. IN PVOID SifHandle,
  2876. IN PWSTR Local_SetupSourceDevicePath,
  2877. IN PWSTR Local_DirectoryOnSetupSource
  2878. )
  2879. /*++
  2880. -pending code description
  2881. --*/
  2882. {
  2883. ULONG diskIndex = 0;
  2884. BOOLEAN found = FALSE;
  2885. BOOLEAN diskChanged = FALSE;
  2886. PWSTR partitionDeviceName = NULL;
  2887. PDISK_REGION pRegion = NULL;
  2888. PSIF_PARTITION_RECORD ppartitionRecord = NULL;
  2889. ULONGLONG startSector = 0;
  2890. DWORD diskNumber = 0;
  2891. if (IsNEC_98) {
  2892. // This is a NEC x86 machine
  2893. pRegion = Gbl_BootPartitionRegion;
  2894. ASSERT(pRegion);
  2895. } else {
  2896. // This is not a NEC x86 machine
  2897. #ifdef _IA64_
  2898. WCHAR RegionName[MAX_PATH];
  2899. if (!(pRegion = SpPtnLocateESP())) {
  2900. SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  2901. L"System Region is NULL"
  2902. );
  2903. }
  2904. SPPT_MARK_REGION_AS_SYSTEMPARTITION(pRegion, TRUE);
  2905. SPPT_SET_REGION_DIRTY(pRegion, TRUE);
  2906. ValidArcSystemPartition = TRUE;
  2907. //
  2908. // Remove the drive letter also
  2909. //
  2910. swprintf(RegionName,
  2911. L"\\Device\\Harddisk%u\\Partition%u",
  2912. pRegion->DiskNumber,
  2913. pRegion->PartitionNumber);
  2914. SpDeleteDriveLetter(RegionName);
  2915. pRegion->DriveLetter = 0;
  2916. #else
  2917. if (!(pRegion = SpPtValidSystemPartition())) {
  2918. SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  2919. L"System Region is NULL"
  2920. );
  2921. }
  2922. #endif
  2923. }
  2924. partitionDeviceName = SpAsrGetRegionName(pRegion);
  2925. DbgStatusMesg((_asrinfo, "PrepareSystemRegion. sys-ptn:[%ws]. Making Active\n",
  2926. partitionDeviceName));
  2927. startSector = pRegion->StartSector;
  2928. diskNumber = pRegion->DiskNumber;
  2929. #ifndef _IA64_
  2930. SpPtnMakeRegionActive(pRegion);
  2931. #endif
  2932. SpPtnCommitChanges(pRegion->DiskNumber, &diskChanged);
  2933. DbgStatusMesg((
  2934. _asrinfo,
  2935. "PrepareSystemRegion. sys-region made active. Disk %lu. %s.\n",
  2936. pRegion->DiskNumber,
  2937. diskChanged ? "Disk not changed.":"Disk changed"
  2938. ));
  2939. pRegion = SpPtLookupRegionByStart(SPPT_GET_PARTITIONED_DISK(diskNumber), FALSE, startSector);
  2940. //
  2941. // Consistency checks. These can eventually be removed
  2942. //
  2943. ASSERT(pRegion);
  2944. diskIndex = pRegion->DiskNumber;
  2945. ASSERT(Gbl_PartitionSetTable2[diskIndex]);
  2946. ASSERT(Gbl_PartitionSetTable2[diskIndex]->pDiskRecord);
  2947. ASSERT(Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList);
  2948. //
  2949. // Ensure that the partition is correctly formatted. To accomplish this,
  2950. // we need to find the record corresponding to this pRegion. We use the
  2951. // record to check for the correct file format.
  2952. //
  2953. ppartitionRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
  2954. while (ppartitionRecord) {
  2955. if ((ULONGLONG)ppartitionRecord->StartSector == pRegion->StartSector) {
  2956. found = TRUE;
  2957. break;
  2958. }
  2959. ppartitionRecord = ppartitionRecord->Next;
  2960. }
  2961. if (!found) {
  2962. DbgFatalMesg((_asrerr,
  2963. "Did not find system partition, start sector: %I64u\n",
  2964. pRegion->StartSector
  2965. ));
  2966. SpAsrRaiseFatalErrorWs(
  2967. SP_SCRN_DR_SIF_BAD_RECORD,
  2968. L"No system partition found in asr.sif",
  2969. SIF_ASR_PARTITIONS_SECTION
  2970. );
  2971. }
  2972. //
  2973. // Format the system partition if needed. We don't re-format the system
  2974. // partition if it's intact.
  2975. //
  2976. if (SpAsrPartitionNeedsFormatting(pRegion, ppartitionRecord->FileSystemType)) {
  2977. SpAsrReformatPartition(
  2978. pRegion,
  2979. ppartitionRecord->FileSystemType,
  2980. SifHandle,
  2981. ppartitionRecord->ClusterSize,
  2982. Local_SetupSourceDevicePath,
  2983. Local_DirectoryOnSetupSource,
  2984. FALSE
  2985. );
  2986. }
  2987. SpMemFree(partitionDeviceName);
  2988. Gbl_SystemPartitionRegion = pRegion;
  2989. return Gbl_SystemPartitionRegion;
  2990. }
  2991. #if 0
  2992. //
  2993. // We don't convert the partition types any more--it is okay to leave
  2994. // them as type 0x42 if the partitions are intact.
  2995. //
  2996. BOOLEAN
  2997. SpAsrChangeLdmPartitionTypes(VOID)
  2998. /*++
  2999. Routine Description
  3000. Changes disk types from 0x42 to 0x7 if needed
  3001. (If the disk is intact, it would not have been re-created
  3002. and hence re-typed above)
  3003. --*/
  3004. {
  3005. ULONG setIndex;
  3006. ULONG ptnIndex;
  3007. PDISK_PARTITION_SET ppartitionSet;
  3008. PSIF_DISK_RECORD pdiskRecord;
  3009. PSIF_PARTITION_RECORD ppartitionRecord;
  3010. BOOLEAN madeAChange = FALSE;
  3011. // Look for any disks which were marked to change from type 0x42 to
  3012. // type 0x7.
  3013. for (setIndex = 0; setIndex < HardDiskCount; setIndex++) {
  3014. ppartitionSet = Gbl_PartitionSetTable2[setIndex];
  3015. if (ppartitionSet && ppartitionSet->pDiskRecord) {
  3016. pdiskRecord = ppartitionSet->pDiskRecord;
  3017. if (pdiskRecord->ContainsNtPartition ||
  3018. pdiskRecord->ContainsSystemPartition) {
  3019. ppartitionRecord = pdiskRecord->PartitionList->First;
  3020. while (ppartitionRecord) {
  3021. if (ppartitionRecord->NeedsLdmRetype) {
  3022. // Disk type needs to be changed
  3023. PPARTITIONED_DISK pDisk;
  3024. PDISK_REGION pRegion = NULL;
  3025. pDisk = &PartitionedDisks[setIndex];
  3026. // try finding the disk region in the main list
  3027. pRegion = SpPtLookupRegionByStart(pDisk, FALSE, ppartitionRecord->StartSector);
  3028. if (!pRegion) {
  3029. // that failed, try finding disk region using the
  3030. // extended partitions list
  3031. pRegion = SpPtLookupRegionByStart(pDisk, TRUE, ppartitionRecord->StartSector);
  3032. }
  3033. if (!pRegion) {
  3034. // the disk region couldn't be found
  3035. DbgErrorMesg((_asrwarn, "SpAsrChangeLdmPartitionTypes. Unable to reset LDM partition record %ws at SS %I64u\n",
  3036. ppartitionRecord->CurrPartKey,
  3037. ppartitionRecord->StartSector));
  3038. ppartitionRecord = ppartitionRecord->Next;
  3039. continue;
  3040. }
  3041. // The disk region was found, now change the disk type
  3042. if (!IsRecognizedPartition(ppartitionRecord->FileSystemType)) {
  3043. //
  3044. // This is an 0x42 partition on the boot/sys disk, but it is
  3045. // not the boot or system partition. The FileSystemType is not
  3046. // recognised since it is set to be 0x42 as well. (The
  3047. // FileSystemType is only valid for the boot and system
  3048. // partitions--for all other partitions,
  3049. // it is set to be the same as the PartitionType)
  3050. //
  3051. // We set it to 0x7 for the time being. The actual file-system type
  3052. // will be set later in GUI-Setup by asr_ldm and asr_fmt.
  3053. //
  3054. DbgStatusMesg((_asrinfo,
  3055. "MBR ptn-rec %ws re-typed (0x%x->0x7) \n",
  3056. ppartitionRecord->CurrPartKey,
  3057. ppartitionRecord->FileSystemType
  3058. ));
  3059. ppartitionRecord->FileSystemType = PARTITION_IFS;
  3060. ppartitionRecord->PartitionType = PARTITION_IFS;
  3061. }
  3062. else {
  3063. DbgStatusMesg((_asrinfo,
  3064. "MBR ptn-rec %ws re-typed (0x%x->0x%x).\n",
  3065. ppartitionRecord->CurrPartKey,
  3066. ppartitionRecord->PartitionType,
  3067. ppartitionRecord->FileSystemType
  3068. ));
  3069. ppartitionRecord->PartitionType = ppartitionRecord->FileSystemType;
  3070. }
  3071. ppartitionRecord->NeedsLdmRetype = FALSE;
  3072. SPPT_SET_PARTITION_TYPE(pRegion, ppartitionRecord->FileSystemType);
  3073. SPPT_SET_REGION_DIRTY(pRegion, TRUE);
  3074. pRegion->DynamicVolume = TRUE;
  3075. pRegion->DynamicVolumeSuitableForOS = TRUE;
  3076. madeAChange = TRUE;
  3077. DbgStatusMesg((_asrinfo, "SpAsrChangeLdmPartitionTypes. Changed disk [%ws] ptn [%ws] type to 0x%x\n",
  3078. pdiskRecord->CurrDiskKey, ppartitionRecord->CurrPartKey, ppartitionRecord->PartitionType));
  3079. }
  3080. ppartitionRecord = ppartitionRecord->Next;
  3081. }
  3082. }
  3083. }
  3084. }
  3085. return madeAChange;
  3086. }
  3087. #endif // 0
  3088. extern VOID
  3089. SpAsrDbgDumpInstallFileList(IN PSIF_INSTALLFILE_LIST pList);
  3090. VOID
  3091. SpAsrSetNewDiskID(
  3092. IN ULONG DiskNumber,
  3093. IN GUID *NewGuid, // valid only for GPT disks
  3094. IN ULONG NewSignature // valid only for MBR disks
  3095. )
  3096. {
  3097. PPARTITIONED_DISK pDisk = &PartitionedDisks[DiskNumber];
  3098. PDISK_REGION pFirstRegion = NULL;
  3099. BOOLEAN Changes = FALSE;
  3100. NTSTATUS Status = STATUS_SUCCESS;
  3101. if (PARTITION_STYLE_GPT == (PARTITION_STYLE) (pDisk->HardDisk->DriveLayout.PartitionStyle)) {
  3102. //
  3103. // Set the new disk GUID
  3104. //
  3105. CopyMemory(&(pDisk->HardDisk->DriveLayout.Gpt.DiskId), NewGuid, sizeof(GUID));
  3106. }
  3107. else if (PARTITION_STYLE_MBR == (PARTITION_STYLE) (pDisk->HardDisk->DriveLayout.PartitionStyle)) {
  3108. //
  3109. // Set the new disk signature
  3110. //
  3111. pDisk->HardDisk->DriveLayout.Mbr.Signature = NewSignature;
  3112. }
  3113. else {
  3114. return;
  3115. }
  3116. //
  3117. // For Commit to pick up the new Guid, at least one region on the
  3118. // disk must be marked dirty.
  3119. //
  3120. pFirstRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3121. SPPT_SET_REGION_DIRTY(pFirstRegion, TRUE);
  3122. Status = SpPtnCommitChanges(DiskNumber, &Changes);
  3123. //
  3124. // Reset the dirty flag on the first region
  3125. //
  3126. pFirstRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3127. SPPT_SET_REGION_DIRTY(pFirstRegion, FALSE);
  3128. }
  3129. NTSTATUS
  3130. SpDrPtPrepareDisks(
  3131. IN PVOID SifHandle,
  3132. OUT PDISK_REGION *BootPartitionRegion,
  3133. OUT PDISK_REGION *SystemPartitionRegion,
  3134. IN PWSTR SetupSourceDevicePath,
  3135. IN PWSTR DirectoryOnSetupSource,
  3136. OUT BOOLEAN *RepairedNt
  3137. )
  3138. /*++
  3139. Description:
  3140. If necessary, SpDrPtPrepareDisks() restores (recreates and formats) the
  3141. system and boot partitions based on information obtained from the
  3142. asr.sif file.
  3143. Arguments:
  3144. SifHandle - Handle to txtsetup.sif
  3145. BootPartitionRegion - Receives a pointer to the partition into
  3146. which NT will be installed (e.g., \WINNT).
  3147. SystemPartitionRegion - Receives a pointer to the partition into
  3148. which the boot loader will be installed.
  3149. SetupSourceDevicePath - Path to the CDROM
  3150. DirectoryOnSetupSource - The directory on the installation CDROM.
  3151. (usually "\I386" for x86 installations)
  3152. RepairedNt - Receives a pointer to a boolean value that is set to:
  3153. TRUE: Indicates the partition structure on the loader
  3154. disk and he partition structure on the NT disk were
  3155. intact and that ASR attempted to perform a repair
  3156. operation.
  3157. FALSE: Indicates the partition structure on either the
  3158. loader disk or the NT disk (or both) were removed
  3159. and recreated. When SpStartSetup() sees this value,
  3160. it will proceed with a normal installation.
  3161. Return Value:
  3162. STATUS_SUCCESS, always! (as of now, anyway)
  3163. --*/
  3164. {
  3165. BOOL done = TRUE,
  3166. next = TRUE,
  3167. warningScreenDone = FALSE;
  3168. NTSTATUS status;
  3169. ULONG diskIndex = 0;
  3170. PWSTR setupSourceDevicePath = NULL,
  3171. directoryOnSetupSource = NULL;
  3172. DbgStatusMesg((_asrinfo, "Entering SpDrPtPrepareDisks. Beginning ASR/ER/RC Processing\n"));
  3173. DbgStatusMesg((_asrinfo, "SetupSourceDevicePath:[%ws], DirectoryOnSetupSource:[%ws]\n",
  3174. SetupSourceDevicePath, DirectoryOnSetupSource));
  3175. *RepairedNt = FALSE;
  3176. //
  3177. // find out if the user wants Recovery Console, traditional Emergency
  3178. // Repair (ER), or full scale Automated System Recovery (ASR)
  3179. //
  3180. Gbl_SifHandle = SifHandle;
  3181. setupSourceDevicePath = SpDupStringW(SetupSourceDevicePath);
  3182. directoryOnSetupSource = SpDupStringW(DirectoryOnSetupSource);
  3183. do {
  3184. if (!done) {
  3185. DbgStatusMesg((_asrinfo, "User hit <ESC> to cancel. Prompting for ASR/ER/RC again\n"));
  3186. }
  3187. if (!SpDrEnabled() || RepairWinnt) {
  3188. SpAsrQueryRepairOrDr();
  3189. }
  3190. if(ForceConsole) { // Recovery Console
  3191. DbgStatusMesg((_asrinfo, "User chose Recovery Console. Exiting SpDrPtPrepareDisks.\n"));
  3192. return STATUS_SUCCESS;
  3193. }
  3194. DbgStatusMesg((_asrinfo, "User chose %s, sys-drive:[%wc], nt/boot-drive:[%wc]\n",
  3195. RepairWinnt ? Gbl_RepairWinntFast ? "Fast ER" : "Manual ER" : "ASR",
  3196. (Gbl_SystemPartitionRegion ? Gbl_SystemPartitionRegion->DriveLetter : L'\\'),
  3197. (Gbl_BootPartitionRegion ? Gbl_BootPartitionRegion->DriveLetter : L'\\') ));
  3198. //
  3199. // Prompt for ER/ASR floppy
  3200. //
  3201. if (RepairWinnt) { // ER
  3202. done = SpAsrGetErDiskette(SifHandle);
  3203. }
  3204. else { // ASR
  3205. if (ASRMODE_NORMAL == SpAsrGetAsrMode()) {
  3206. SpInitializePidString(SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource);
  3207. }
  3208. done = SpAsrLoadAsrDiskette();
  3209. }
  3210. } while (!done);
  3211. //
  3212. // At this point, if RepairWinnt is TRUE, user wants ER, else user
  3213. // wants ASR. (If he wanted Recovery Console we would've returned
  3214. // STATUS_SUCCESS above.) In either case, the appropriate disk is
  3215. // already in the drive
  3216. //
  3217. if (RepairWinnt) { // ER
  3218. //
  3219. // if the boot partition was not repaired (deleted, recreated, and
  3220. // reformatted), then attempt an emergency repair of the system.
  3221. //
  3222. if (Gbl_NtPartitionIntact == TRUE) {
  3223. *RepairedNt = SpAsrAttemptRepair(
  3224. SifHandle,
  3225. SetupSourceDevicePath,
  3226. DirectoryOnSetupSource,
  3227. SetupSourceDevicePath,
  3228. DirectoryOnSetupSource
  3229. );
  3230. if (*RepairedNt) {
  3231. WinntSetup = FALSE;
  3232. }
  3233. *SystemPartitionRegion = Gbl_SystemPartitionRegion;
  3234. *BootPartitionRegion = Gbl_BootPartitionRegion;
  3235. }
  3236. else {
  3237. //
  3238. // If the NT partition is not intact, we cannot do an ER.
  3239. //
  3240. SpAsrCannotDoER();
  3241. SpDone(0, FALSE, TRUE);
  3242. }
  3243. }
  3244. else { // ASR
  3245. SpAsrInitIoDeviceCount();
  3246. SpAsrCheckAsrStateFileVersion();
  3247. SpAsrCreatePartitionSets(setupSourceDevicePath, directoryOnSetupSource);
  3248. Gbl_3rdPartyFileList = SpAsrInit3rdPartyFileList(SetupSourceDevicePath);
  3249. SpAsrDbgDumpPartitionSets();
  3250. SpAsrDeleteMountedDevicesKey();
  3251. SpAsrRemoveMountPoints(); // restored by asr_fmt.exe etc
  3252. //
  3253. // Check hard disks and repartition as needed
  3254. //
  3255. next = TRUE;
  3256. for (diskIndex = 0; diskIndex < HardDiskCount; (diskIndex += (next ? 1 : 0))) {
  3257. BOOLEAN skip = FALSE;
  3258. next = TRUE;
  3259. SpAsrDbgDumpDisk(diskIndex);
  3260. if (!warningScreenDone) {
  3261. skip = SpAsrpSkipDiskRepartition(diskIndex, FALSE);
  3262. if (!skip) {
  3263. //
  3264. // If we are going to repartition a disk, put up the
  3265. // warning screen to make sure the user knows all
  3266. // partitions on the disk are going to get clobbered,
  3267. // but only once - after the first disk with a problem,
  3268. // don't display the screen again.
  3269. //
  3270. SpAsrClobberDiskWarning();
  3271. warningScreenDone = TRUE;
  3272. }
  3273. }
  3274. skip = SpAsrpSkipDiskRepartition(diskIndex, TRUE);
  3275. if (!skip) {
  3276. CREATE_DISK CreateDisk;
  3277. PSIF_DISK_RECORD pCurrentDisk = Gbl_PartitionSetTable1[diskIndex]->pDiskRecord;
  3278. PHARD_DISK HardDisk = SPPT_GET_HARDDISK(diskIndex);
  3279. BOOLEAN IsBlank = TRUE;
  3280. BOOLEAN preservePartitions = FALSE;
  3281. UCHAR MbrPartitionType = PARTITION_ENTRY_UNUSED;
  3282. //
  3283. // We're here because the partition structure of the disk does not
  3284. // match with that specified by the SIF file. As a consequence
  3285. // all of the partitions on this disk will be removed and recreated.
  3286. //
  3287. if (SpPtnGetPartitionCountDisk(diskIndex) ||
  3288. SpPtnGetContainerPartitionCount(diskIndex)) {
  3289. //
  3290. // The physical disk has partitions, clear them
  3291. //
  3292. // On GPT disks, we erase all the partitions with the
  3293. // exception of the EFI System Partition. Note that we
  3294. // delete all foreign/unrecognised partitions as
  3295. // well.
  3296. //
  3297. // For MBR disks, we erase all the partitions with the
  3298. // exception of any OEM partitions. Note that as in the
  3299. // case of GPT disks, we delete unrecognised/foriegn
  3300. // partitions.
  3301. //
  3302. //
  3303. // Get the partition type of the first partition on the
  3304. // sifDisk. If this is an OEM partition, and the
  3305. // current disk has a partition with the same exact
  3306. // partition type, we should preserve it.
  3307. //
  3308. if (PARTITION_STYLE_MBR == pCurrentDisk->PartitionStyle) {
  3309. if (((pCurrentDisk->ContainsNtPartition)
  3310. || (pCurrentDisk->ContainsSystemPartition)) &&
  3311. (pCurrentDisk->PartitionList) &&
  3312. (pCurrentDisk->PartitionList->First)) {
  3313. MbrPartitionType = pCurrentDisk->PartitionList->First->PartitionType;
  3314. }
  3315. if (IsOEMPartition(MbrPartitionType)) {
  3316. preservePartitions = TRUE;
  3317. }
  3318. }
  3319. else if (PARTITION_STYLE_GPT == pCurrentDisk->PartitionStyle) {
  3320. preservePartitions = TRUE;
  3321. }
  3322. SpAsrDeletePartitions(diskIndex, preservePartitions, MbrPartitionType, &IsBlank);
  3323. }
  3324. if (IsBlank) {
  3325. //
  3326. // The disk is blank, set the appropriate signature/ID
  3327. //
  3328. ZeroMemory(&CreateDisk, sizeof(CREATE_DISK));
  3329. CreateDisk.PartitionStyle = pCurrentDisk->PartitionStyle;
  3330. if (PARTITION_STYLE_MBR == pCurrentDisk->PartitionStyle) {
  3331. CreateDisk.Mbr.Signature = pCurrentDisk->SifDiskMbrSignature;
  3332. }
  3333. else if (PARTITION_STYLE_GPT == pCurrentDisk->PartitionStyle) {
  3334. CopyMemory(&(CreateDisk.Gpt.DiskId),
  3335. &(pCurrentDisk->SifDiskGptId),
  3336. sizeof(GUID));
  3337. CreateDisk.Gpt.MaxPartitionCount = pCurrentDisk->MaxGptPartitionCount;
  3338. }
  3339. else {
  3340. ASSERT(0 && L"Unrecognised partition style");
  3341. continue;
  3342. }
  3343. SPPT_SET_DISK_BLANK(diskIndex, TRUE);
  3344. //
  3345. // Intialise the disk to the appropriate style
  3346. //
  3347. status = SpPtnInitializeDiskStyle(diskIndex, pCurrentDisk->PartitionStyle, &CreateDisk);
  3348. if (NT_SUCCESS(status)) {
  3349. status = SpPtnInitializeDiskDrive(diskIndex);
  3350. }
  3351. }
  3352. else {
  3353. //
  3354. // Special case: the EFI system partition, or some OEM
  3355. // partition, was preserved. We should just update
  3356. // the disk GUID or signature.
  3357. //
  3358. SpAsrSetNewDiskID(diskIndex, &(pCurrentDisk->SifDiskGptId), pCurrentDisk->SifDiskMbrSignature);
  3359. }
  3360. //
  3361. // Create the new paritions
  3362. //
  3363. SpAsrRecreateDiskPartitions(diskIndex, (preservePartitions && (!IsBlank)), MbrPartitionType);
  3364. }
  3365. }
  3366. SpAsrDbgDumpPartitionLists(2, L"After partition recreation.");
  3367. //
  3368. // Format the Boot partition. (Always, EXCEPT in automated tests)
  3369. // This won't return if the boot partition region doesn't exist
  3370. //
  3371. *BootPartitionRegion = SpAsrPrepareBootRegion(
  3372. SifHandle,
  3373. setupSourceDevicePath,
  3374. directoryOnSetupSource
  3375. );
  3376. //
  3377. // Format the system partition only if necessary.
  3378. // This won't return if the system partition region doesn't exist
  3379. //
  3380. *SystemPartitionRegion = SpAsrPrepareSystemRegion(
  3381. SifHandle,
  3382. setupSourceDevicePath,
  3383. directoryOnSetupSource
  3384. );
  3385. } // RepairWinnt
  3386. SpMemFree(setupSourceDevicePath);
  3387. SpMemFree(directoryOnSetupSource);
  3388. DbgStatusMesg((_asrinfo, "Exiting SpDrPtPrepareDisks\n"));
  3389. return STATUS_SUCCESS;
  3390. }