Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4214 lines
127 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 amd64/x86 platforms these are the boot.ini. ntldr,
  14. and 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 amd64/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. NULL, // no selection callback
  1836. &Keypress,
  1837. &ReturnedData
  1838. );
  1839. switch(Keypress) {
  1840. case KEY_F3:
  1841. //
  1842. // User wants to exit--confirm.
  1843. //
  1844. SpConfirmExit();
  1845. break;
  1846. case (MnemonicContinueSetup | KEY_MNEMONIC):
  1847. //
  1848. // User wants to continue with Setup
  1849. //
  1850. done = TRUE;
  1851. break;
  1852. }
  1853. } while (!done);
  1854. SpMnDestroy(Menu);
  1855. }
  1856. VOID
  1857. SpAsrCannotDoER(VOID)
  1858. /*++
  1859. Routine Description:
  1860. Display a screen informing the user that ER canot be performed on
  1861. the system because the boot partition in not intact, i.e., ASR
  1862. recreated/reformatted that partition.
  1863. Arguments:
  1864. None.
  1865. Return Value:
  1866. None.
  1867. --*/
  1868. {
  1869. ULONG warningKeys[] = { KEY_F3, 0 };
  1870. ULONG mnemonicKeys[] = { 0 };
  1871. // display the message screen
  1872. SpDisplayScreen(SP_SCRN_DR_CANNOT_DO_ER,3,4);
  1873. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1874. SP_STAT_F3_EQUALS_EXIT,
  1875. 0
  1876. );
  1877. // wait for keypress. Valid key:
  1878. // F3 = exit
  1879. SpInputDrain();
  1880. do {
  1881. switch(SpWaitValidKey(warningKeys,NULL,mnemonicKeys)) {
  1882. case KEY_F3:
  1883. // User wants to exit.
  1884. return;
  1885. }
  1886. } while (TRUE);
  1887. }
  1888. VOID
  1889. SpAsrQueryRepairOrDr()
  1890. /*++
  1891. -pending code description
  1892. --*/
  1893. {
  1894. BOOLEAN done = TRUE;
  1895. do {
  1896. done = TRUE;
  1897. // ask the user if he wants repair or ASR
  1898. SpAsrRepairOrDRMenu();
  1899. if (RepairWinnt) {
  1900. // User wants to repair, check Manual or Fast
  1901. if (done = SpAsrRepairManualOrFastMenu()) {
  1902. if (Gbl_RepairWinntFast) { // Fast Repair
  1903. RepairItems[RepairNvram] = 1;
  1904. RepairItems[RepairFiles] = 1;
  1905. #if defined(_AMD64_) || defined(_X86_)
  1906. RepairItems[RepairBootSect] = 1;
  1907. #endif // defined(_AMD64_) || defined(_X86_)
  1908. }
  1909. else { // Manual Repair
  1910. done = SpDisplayRepairMenu();
  1911. }
  1912. }
  1913. }
  1914. } while (!done);
  1915. }
  1916. BOOLEAN
  1917. SpAsrOpenAsrStateFile(ULONG *ErrorLine, PWSTR AsrSifPath)
  1918. {
  1919. NTSTATUS status;
  1920. ASSERT(ErrorLine);
  1921. *ErrorLine = 0;
  1922. // load asr.sif
  1923. status = SpLoadSetupTextFile(
  1924. AsrSifPath,
  1925. NULL,
  1926. 0,
  1927. &Gbl_HandleToDrStateFile,
  1928. ErrorLine,
  1929. TRUE,
  1930. FALSE
  1931. );
  1932. if (!NT_SUCCESS(status)) {
  1933. DbgErrorMesg((_asrerr, "SpAsrOpenAsrStateFile. Unable to open %ws. status:0x%x ErrorLine:%lu\n",
  1934. AsrSifPath,
  1935. status,
  1936. *ErrorLine));
  1937. Gbl_HandleToDrStateFile = NULL;
  1938. return FALSE;
  1939. }
  1940. return TRUE;
  1941. }
  1942. BOOLEAN
  1943. SpAsrLoadAsrDiskette(VOID)
  1944. /*++
  1945. Routine Description:
  1946. This routine checks for a floppy drive. If one is not found, this routine
  1947. never returns, Setup terminates with an error. If a floppy drive is found,
  1948. this routine prompts for the ASR disk. If the disk is loaded, it reads and
  1949. parses the asr.sif file.
  1950. Arguments:
  1951. None.
  1952. Return Values:
  1953. TRUE if disk was loaded successfully
  1954. DOES NOT RETURN if no floppy drive was found, or if asr.sif is corrupt.
  1955. --*/
  1956. {
  1957. ULONG errorAtLine = 0,
  1958. diskIndex = 0;
  1959. PWSTR diskName = NULL;
  1960. PWSTR diskDeviceName = NULL;
  1961. PWSTR localAsrSifPath = NULL;
  1962. BOOLEAN result = FALSE;
  1963. if (!RemoteBootSetup) {
  1964. //
  1965. // Look for the asr.sif in the boot directory. If it isn't present
  1966. // in the boot directory, we'll look for it on the floppy drive.
  1967. //
  1968. localAsrSifPath = SpMemAlloc((wcslen(NtBootDevicePath)+wcslen(ASR_SIF_NAME)+2) * sizeof(WCHAR));
  1969. if (localAsrSifPath) {
  1970. localAsrSifPath[0] = UNICODE_NULL;
  1971. wcscpy(localAsrSifPath,NtBootDevicePath);
  1972. SpConcatenatePaths(localAsrSifPath,ASR_SIF_NAME);
  1973. result = SpAsrOpenAsrStateFile(&errorAtLine, localAsrSifPath);
  1974. Gbl_AsrSifOnInstallationMedia = result;
  1975. SpMemFree(localAsrSifPath);
  1976. localAsrSifPath = NULL;
  1977. }
  1978. if (!result) {
  1979. //
  1980. // Check if the machine has a floppy drive. This is kind of redundant,
  1981. // since he couldn't have got this far if there isn't a floppy drive.
  1982. // However, we've had cases where setupldr recognises the floppy drive,
  1983. // but we then loose the floppy by the time we get here.
  1984. //
  1985. if (SpGetFloppyDriveType(0) == FloppyTypeNone) {
  1986. SpAsrRaiseFatalError(
  1987. SP_TEXT_DR_NO_FLOPPY_DRIVE,
  1988. L"Floppy drive does not exist"
  1989. );
  1990. // does not return
  1991. }
  1992. SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_DR_DISK_NAME);
  1993. diskName = SpDupStringW(TemporaryBuffer);
  1994. diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
  1995. //
  1996. // Prompt for the disk. We don't allow him to hit ESC to cancel,
  1997. // since he can't quit out of ASR at this point.
  1998. //
  1999. SpPromptForDisk(
  2000. diskName,
  2001. diskDeviceName,
  2002. ASR_SIF_NAME,
  2003. FALSE, // no ignore disk in drive
  2004. FALSE, // no allow escape
  2005. FALSE, // no warn multiple prompts
  2006. NULL // don't care about redraw flag
  2007. );
  2008. DbgStatusMesg((_asrinfo,
  2009. "SpAsrLoadAsrDiskette. Disk [%ws] loaded successfully on %ws\n",
  2010. diskName, diskDeviceName
  2011. ));
  2012. SpMemFree(diskName);
  2013. SpMemFree(diskDeviceName);
  2014. //
  2015. // Open asr.sif from the floppy. If we can't read it, it's a fatal
  2016. // error.
  2017. //
  2018. result = SpAsrOpenAsrStateFile(&errorAtLine, ASR_SIF_PATH);
  2019. }
  2020. } else {
  2021. //
  2022. // open the file from the remote location
  2023. //
  2024. RemoteBootAsrSifName = SpGetSectionKeyIndex(
  2025. WinntSifHandle,
  2026. L"OSChooser",
  2027. L"ASRINFFile",
  2028. 0);
  2029. if (!RemoteBootAsrSifName) {
  2030. SpAsrRaiseFatalError(
  2031. SP_TEXT_DR_NO_ASRSIF_RIS,
  2032. L"Couldn't get ASRINFFile from winnt.sif in RIS case"
  2033. );
  2034. // does not return
  2035. }
  2036. result = SpAsrOpenAsrStateFile(&errorAtLine, RemoteBootAsrSifName);
  2037. }
  2038. if (!result) {
  2039. swprintf(TemporaryBuffer, L"Failed to load/parse asr.sif at line %lu\n",
  2040. errorAtLine);
  2041. if (errorAtLine > 0) {
  2042. SpAsrRaiseFatalErrorLu(SP_TEXT_DR_STATEFILE_BAD_LINE,
  2043. TemporaryBuffer,
  2044. errorAtLine
  2045. );
  2046. }
  2047. else {
  2048. SpAsrRaiseFatalError(SP_TEXT_DR_STATEFILE_ERROR, TemporaryBuffer);
  2049. }
  2050. // does not return
  2051. }
  2052. //
  2053. // Set Gbl_FixedDiskCount
  2054. //
  2055. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  2056. Gbl_FixedDiskCount += DISK_IS_REMOVABLE(diskIndex) ? 0 : 1;
  2057. }
  2058. AutoPartitionPicker = FALSE;
  2059. return TRUE;
  2060. }
  2061. BOOLEAN
  2062. SpAsrLoadErDiskette(VOID)
  2063. /*++
  2064. Routine Description:
  2065. This routine checks for a floppy drive, and prompts for the ER
  2066. Diskette if a drive is found. If a floppy drive is not found,
  2067. this routine never returns, Setup terminates with an error.
  2068. Arguments:
  2069. None.
  2070. Return Values:
  2071. TRUE if disk was loaded successfully
  2072. FALSE otherwise (user hit cancel, or there was no floppy drive present)
  2073. --*/
  2074. {
  2075. BOOLEAN diskLoaded = FALSE;
  2076. PWSTR diskName = NULL,
  2077. diskDeviceName = NULL;
  2078. // check if an A: drive exists.
  2079. if (SpGetFloppyDriveType(0) == FloppyTypeNone) {
  2080. SpAsrRaiseFatalError(
  2081. SP_TEXT_DR_NO_FLOPPY_DRIVE,
  2082. L"Floppy drive does not exist"
  2083. );
  2084. // does not return
  2085. }
  2086. SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer),
  2087. SP_TEXT_REPAIR_OR_DR_DISK_NAME);
  2088. diskName = SpDupStringW(TemporaryBuffer);
  2089. diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
  2090. // prompt for the disk.
  2091. diskLoaded = SpPromptForDisk(
  2092. diskName,
  2093. diskDeviceName,
  2094. ASR_SETUP_LOG_NAME,
  2095. TRUE,
  2096. TRUE,
  2097. FALSE,
  2098. NULL
  2099. );
  2100. DbgStatusMesg((_asrinfo, "SpAsrLoadErDiskette. ER disk [%ws] %s loaded successfully on %s\n",
  2101. diskName, diskLoaded?"":"NOT", diskDeviceName));
  2102. SpMemFree(diskName);
  2103. SpMemFree(diskDeviceName);
  2104. return diskLoaded;
  2105. }
  2106. BOOLEAN
  2107. SpAsrGetErFromHardDrive(
  2108. IN PVOID MasterSifHandle,
  2109. OUT PVOID *RepairSifHandle,
  2110. OUT PWSTR *FullLogFileName
  2111. )
  2112. /*++
  2113. -pending code description
  2114. --*/
  2115. {
  2116. BOOLEAN foundRepairableSystem = FALSE,
  2117. result = FALSE;
  2118. DbgStatusMesg((_asrinfo, "SpAsrGetErFromHardDrive. ER: Attempting to load ER data from Hard drive"));
  2119. //
  2120. // If user has no emergency repair diskette, we need to find out
  2121. // if there is any NT to repair and which one to repair.
  2122. //
  2123. result = SpFindNtToRepair(MasterSifHandle,
  2124. &Gbl_BootPartitionRegion,
  2125. &Gbl_BootPartitionDirectory,
  2126. &Gbl_SystemPartitionRegion,
  2127. &Gbl_SystemPartitionDirectory,
  2128. &foundRepairableSystem
  2129. );
  2130. if (result) {
  2131. //
  2132. // Repairable systems were found, and the user selected one to repair
  2133. //
  2134. //
  2135. // Get the device path of the system and boot partitions.
  2136. //
  2137. SpNtNameFromRegion(Gbl_SystemPartitionRegion,
  2138. TemporaryBuffer,
  2139. sizeof(TemporaryBuffer),
  2140. PartitionOrdinalCurrent
  2141. );
  2142. Gbl_SystemPartitionName = SpDupStringW(TemporaryBuffer);
  2143. SpNtNameFromRegion(Gbl_BootPartitionRegion,
  2144. TemporaryBuffer,
  2145. sizeof(TemporaryBuffer),
  2146. PartitionOrdinalCurrent
  2147. );
  2148. Gbl_BootPartitionName = SpDupStringW(TemporaryBuffer);
  2149. //
  2150. // Form the full NT path of the setup.log file in the chosen
  2151. // system on the hard drive.
  2152. //
  2153. SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
  2154. SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
  2155. SpConcatenatePaths(TemporaryBuffer, SETUP_LOG_FILENAME);
  2156. *FullLogFileName = SpDupStringW(TemporaryBuffer);
  2157. DbgStatusMesg((_asrinfo,
  2158. "ER: User picked system to repair. boot-ptn:[%ws] sys-ptn:[%ws] log-file:[%ws]\n",
  2159. Gbl_BootPartitionName,
  2160. Gbl_SystemPartitionName,
  2161. *FullLogFileName
  2162. ));
  2163. //
  2164. // Read and process the setup.log file.
  2165. //
  2166. result = SpLoadRepairLogFile(*FullLogFileName, RepairSifHandle);
  2167. if (!result) {
  2168. //
  2169. // Load setup.log failed. Ask user to insert a ER diskette again.
  2170. //
  2171. DbgErrorMesg((_asrwarn,
  2172. "ER: Attempt to load log file [%ws] FAILED\n",
  2173. *FullLogFileName
  2174. ));
  2175. return FALSE;
  2176. }
  2177. //
  2178. // Setup file was read. Will return TRUE
  2179. //
  2180. Gbl_RepairFromErDisk = FALSE;
  2181. }
  2182. else {
  2183. //
  2184. // User did not select a system to repair
  2185. //
  2186. if (foundRepairableSystem) {
  2187. //
  2188. // Setup found a WINNT installation, but no installation was
  2189. // chosen by the user. We will go back to ask for the ER
  2190. // diskette again.
  2191. //
  2192. DbgErrorMesg((_asrwarn, "ER: Repairable systems were found, but user did not select any\n"));
  2193. return FALSE;
  2194. }
  2195. else {
  2196. //
  2197. // Couldn't find any NT to repair
  2198. //
  2199. ULONG validKeys[] = {KEY_F3, ASCI_CR, 0};
  2200. ULONG mnemonicKeys[] = {MnemonicCustom, 0};
  2201. DbgErrorMesg((_asrwarn, "ER: No repairable systems were found\n"));
  2202. SpStartScreen(SP_SCRN_REPAIR_NT_NOT_FOUND,
  2203. 3,
  2204. HEADER_HEIGHT+1,
  2205. FALSE,
  2206. FALSE,
  2207. DEFAULT_ATTRIBUTE
  2208. );
  2209. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2210. SP_STAT_ENTER_EQUALS_REPAIR,
  2211. SP_STAT_F3_EQUALS_EXIT,
  2212. 0
  2213. );
  2214. SpInputDrain();
  2215. switch (SpWaitValidKey(validKeys,NULL,NULL)) {
  2216. case KEY_F3:
  2217. //
  2218. // User wants to exit Setup
  2219. //
  2220. SpDone(0,TRUE,TRUE);
  2221. break;
  2222. default:
  2223. return FALSE;
  2224. }
  2225. }
  2226. }
  2227. return TRUE;
  2228. }
  2229. BOOLEAN
  2230. SpAsrGetErDiskette(IN PVOID SifHandle)
  2231. /*++
  2232. -pending code description
  2233. --*/
  2234. {
  2235. PWSTR fullLogFileName = NULL;
  2236. BOOLEAN done = FALSE,
  2237. hasErDisk = FALSE;
  2238. while (!done) {
  2239. //
  2240. // display message to let user know he can either provide his
  2241. // own ER disk or let setup search for him.
  2242. //
  2243. if (!SpErDiskScreen(&hasErDisk)) {
  2244. return FALSE;
  2245. }
  2246. Gbl_HandleToSetupLog = NULL;
  2247. fullLogFileName = NULL;
  2248. if (hasErDisk) {
  2249. //
  2250. // Ask for emergency repair diskette until either we get it or
  2251. // user cancels the request.
  2252. //
  2253. done = SpAsrLoadErDiskette();
  2254. if (done) {
  2255. Gbl_SourceSetupLogFileName = ASR_DEFAULT_SETUP_LOG_PATH;
  2256. done = SpAsrProcessSetupLogFile(Gbl_SourceSetupLogFileName, TRUE);
  2257. }
  2258. }
  2259. else {
  2260. done = SpAsrGetErFromHardDrive(SifHandle, &Gbl_HandleToSetupLog, &fullLogFileName);
  2261. if (fullLogFileName) {
  2262. Gbl_SourceSetupLogFileName = SpDupStringW(fullLogFileName);
  2263. SpMemFree(fullLogFileName);
  2264. }
  2265. }
  2266. }
  2267. DbgStatusMesg((_asrinfo, "SpAsrGetErDiskette. ER: %s Floppy. Using setup log file [%ws]\n",
  2268. hasErDisk?"Using":"NO", (Gbl_SourceSetupLogFileName ? Gbl_SourceSetupLogFileName : L"")));
  2269. return TRUE;
  2270. }
  2271. PSIF_PARTITION_RECORD
  2272. SpAsrGetBootPartitionRecord(VOID)
  2273. {
  2274. ULONG diskIndex = 0;
  2275. PSIF_PARTITION_RECORD pRecord = NULL;
  2276. if (Gbl_BootPartitionRecord) {
  2277. return Gbl_BootPartitionRecord;
  2278. }
  2279. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  2280. //
  2281. // Find NT partition record from the partition set table.
  2282. //
  2283. if (Gbl_PartitionSetTable2[diskIndex] == NULL ||
  2284. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord == NULL ||
  2285. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList == NULL) {
  2286. continue;
  2287. }
  2288. DbgStatusMesg((_asrinfo, "Disk %lu ptn records: ", diskIndex));
  2289. pRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
  2290. while (pRecord) {
  2291. DbgMesg((_asrinfo, "[%ws]", pRecord->CurrPartKey));
  2292. if (SpAsrIsBootPartitionRecord(pRecord->PartitionFlag)) {
  2293. ASSERT((pRecord->NtDirectoryName) && L"Boot partition is missing NT directory name.");
  2294. return pRecord;
  2295. }
  2296. pRecord = pRecord->Next;
  2297. }
  2298. DbgMesg((_asrinfo, "\n"));
  2299. }
  2300. DbgFatalMesg((_asrerr, "SpAsrGetBootPartitionRecord. No boot partition record was found.\n"));
  2301. SpAsrRaiseFatalErrorWs(
  2302. SP_SCRN_DR_SIF_BAD_RECORD,
  2303. L"No boot partition found in asr.sif",
  2304. SIF_ASR_PARTITIONS_SECTION
  2305. );
  2306. //
  2307. // Never gets here
  2308. //
  2309. return NULL;
  2310. }
  2311. PWSTR
  2312. SpDrGetNtDirectory(VOID)
  2313. /*++
  2314. Routine Description:
  2315. Returns the target path according to the value found in the asr.sif
  2316. file, but without the leading drive letter and colon.
  2317. Arguments:
  2318. None
  2319. Return Value:
  2320. A pointer to a string containing the NT directory path. This will be of
  2321. the form:
  2322. \WINDOWS
  2323. and not:
  2324. C:\WINDOWS
  2325. --*/
  2326. {
  2327. PSIF_PARTITION_RECORD pRecord = SpAsrGetBootPartitionRecord();
  2328. return (pRecord ? pRecord->NtDirectoryName : NULL);
  2329. }
  2330. ASRMODE
  2331. SpAsrGetAsrMode(VOID)
  2332. /*++
  2333. Routine Description:
  2334. Returns whether ASR is in progress
  2335. Return Value:
  2336. The Asr type currently in progress.
  2337. --*/
  2338. {
  2339. return Gbl_AsrMode;
  2340. }
  2341. ASRMODE
  2342. SpAsrSetAsrMode(
  2343. IN CONST ASRMODE NewAsrMode
  2344. )
  2345. /*++
  2346. Routine Description:
  2347. Sets the Gbl_AsrMode state variable to the value of NewAsrMode.
  2348. Arguments:
  2349. NewAsrMode - new Asr mode
  2350. Return Value:
  2351. Returns the previous Asr mode
  2352. --*/
  2353. {
  2354. ASRMODE oldMode = Gbl_AsrMode;
  2355. Gbl_AsrMode = NewAsrMode;
  2356. return oldMode;
  2357. }
  2358. BOOLEAN
  2359. SpDrEnabled(VOID) {
  2360. //
  2361. // Asr is enabled if Gbl_AsrMode is set to anything other than
  2362. // ASRMODE_NONE
  2363. //
  2364. return (ASRMODE_NONE != Gbl_AsrMode);
  2365. }
  2366. BOOLEAN
  2367. SpAsrIsQuickTest(VOID) {
  2368. return (
  2369. (ASRMODE_QUICKTEST_TEXT == Gbl_AsrMode) ||
  2370. (ASRMODE_QUICKTEST_FULL == Gbl_AsrMode)
  2371. );
  2372. }
  2373. BOOLEAN
  2374. SpDrIsRepairFast(VOID)
  2375. /*++
  2376. Routine Description:
  2377. Tests whether the "Fast" Emergency Repair flag is set.
  2378. Return Value:
  2379. TRUE if "Fast" ER flag is set
  2380. FALSE otherwise
  2381. --*/
  2382. {
  2383. return Gbl_RepairWinntFast;
  2384. }
  2385. BOOLEAN
  2386. SpDrSetRepairFast(BOOLEAN NewValue)
  2387. /*++
  2388. Routine Description:
  2389. Sets the "Fast" Emergency Repair flag.
  2390. Arguments:
  2391. Value New Value (TRUE or FALSE) to which to set the
  2392. Gbl_RepairWinntFast flag
  2393. Return Value:
  2394. Previous value of Gbl_RepairWinntFast;
  2395. --*/
  2396. {
  2397. BOOLEAN oldValue = Gbl_RepairWinntFast;
  2398. Gbl_RepairWinntFast = NewValue;
  2399. return oldValue;
  2400. }
  2401. extern VOID
  2402. SpAsrDbgDumpSystemMountPoints(VOID);
  2403. VOID
  2404. SpDrCleanup(VOID)
  2405. /*++
  2406. -pending code description
  2407. --*/
  2408. {
  2409. ULONG diskIndex = 0;
  2410. //
  2411. // Remove all the mountpoints in the system, we shall recreate them.
  2412. //
  2413. SpAsrRemoveMountPoints();
  2414. DbgStatusMesg((_asrinfo, "Restoring volume mount points.\n"));
  2415. for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
  2416. if (!(DISK_IS_REMOVABLE(diskIndex))) {
  2417. SpAsrRestoreDiskMountPoints(diskIndex);
  2418. SpAsrDbgDumpDisk(diskIndex);
  2419. }
  2420. }
  2421. // DbgStatusMesg((_asrinfo, "Dumping mount points AFTER text-mode ASR:\n"));
  2422. // SpAsrDbgDumpSystemMountPoints();
  2423. }
  2424. VOID
  2425. SpAsrCopyStateFile(VOID)
  2426. {
  2427. NTSTATUS status = STATUS_SUCCESS;
  2428. PWSTR diskName = NULL,
  2429. targetFilePath = NULL,
  2430. sourceFilePath = NULL,
  2431. bootPartition = NULL,
  2432. diskDeviceName = NULL;
  2433. SpdInitialize();
  2434. SpFormatMessage(
  2435. TemporaryBuffer,
  2436. sizeof(TemporaryBuffer),
  2437. SP_TEXT_DR_DISK_NAME
  2438. );
  2439. diskName = SpDupStringW(TemporaryBuffer);
  2440. if (RemoteBootAsrSifName == NULL) {
  2441. if (Gbl_AsrSifOnInstallationMedia) {
  2442. wcscpy(TemporaryBuffer,NtBootDevicePath);
  2443. SpConcatenatePaths(TemporaryBuffer,ASR_SIF_NAME);
  2444. sourceFilePath = SpDupStringW(TemporaryBuffer);
  2445. }
  2446. else {
  2447. //
  2448. // Prompt the user to insert the ASR disk, if it isn't
  2449. // already in the drive
  2450. //
  2451. diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
  2452. sourceFilePath = SpDupStringW(ASR_SIF_PATH);
  2453. SpPromptForDisk(
  2454. diskName,
  2455. diskDeviceName,
  2456. ASR_SIF_NAME,
  2457. FALSE, // no ignore disk in drive
  2458. FALSE, // no allow escape
  2459. TRUE, // warn multiple prompts
  2460. NULL // don't care about redraw flag
  2461. );
  2462. SpMemFree(diskDeviceName);
  2463. }
  2464. } else {
  2465. sourceFilePath = SpDupStringW(RemoteBootAsrSifName);
  2466. }
  2467. //
  2468. // Build the full path to the directory into which the file will be
  2469. // written.
  2470. //
  2471. bootPartition = SpAsrGetRegionName(Gbl_BootPartitionRegion);
  2472. if (!Gbl_BootPartitionDirectory) {
  2473. Gbl_BootPartitionDirectory = SpDrGetNtDirectory();
  2474. }
  2475. wcscpy(TemporaryBuffer, bootPartition);
  2476. SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
  2477. SpConcatenatePaths(TemporaryBuffer, ASR_SIF_TARGET_PATH);
  2478. targetFilePath = SpDupStringW(TemporaryBuffer);
  2479. SpMemFree(bootPartition);
  2480. //
  2481. // Copy the file. In case of errors, user will have the option
  2482. // to retry, or quit Setup. We cannot skip this file.
  2483. //
  2484. do {
  2485. if (SpFileExists(targetFilePath, FALSE)) {
  2486. SpDeleteFile(targetFilePath, NULL, NULL);
  2487. }
  2488. status = SpCopyFileUsingNames(
  2489. sourceFilePath,
  2490. targetFilePath,
  2491. 0,
  2492. 0
  2493. );
  2494. if (!NT_SUCCESS(status)) {
  2495. DbgErrorMesg((_asrwarn, "SpAsrCopyFiles. Could not copy asr.sif. src:[%ws] dest:[%ws]. (0x%x)\n",
  2496. ASR_SIF_PATH,
  2497. targetFilePath,
  2498. status
  2499. ));
  2500. SpAsrFileErrorRetrySkipAbort(
  2501. SP_SCRN_DR_SIF_NOT_FOUND,
  2502. ASR_SIF_PATH,
  2503. diskName,
  2504. NULL,
  2505. FALSE // no allow skip
  2506. );
  2507. }
  2508. } while (!NT_SUCCESS(status));
  2509. SpdTerminate();
  2510. SpMemFree(diskName);
  2511. SpMemFree(targetFilePath);
  2512. SpMemFree(sourceFilePath);
  2513. }
  2514. NTSTATUS
  2515. SpAsrCopy3rdPartyFiles(
  2516. VOID
  2517. )
  2518. {
  2519. PWSTR bootPartition = NULL,
  2520. fullTargetPath = NULL,
  2521. fullSourcePath = NULL,
  2522. windirPathPrefix = NULL,
  2523. tempPathPrefix = NULL;
  2524. BOOL moveToNext = FALSE,
  2525. diskLoaded = FALSE;
  2526. NTSTATUS status = STATUS_SUCCESS;
  2527. PSIF_INSTALLFILE_RECORD pRec = NULL;
  2528. if (!Gbl_3rdPartyFileList) {
  2529. //
  2530. // No files to copy, we're done
  2531. //
  2532. return STATUS_SUCCESS;
  2533. }
  2534. //
  2535. // Build the expansion strings for
  2536. // %TEMP%, %TMP%, and %SYSTEMROOT%
  2537. //
  2538. bootPartition = SpAsrGetRegionName(Gbl_BootPartitionRegion);
  2539. if (!Gbl_BootPartitionDirectory) {
  2540. Gbl_BootPartitionDirectory = SpDrGetNtDirectory();
  2541. }
  2542. wcscpy(TemporaryBuffer, bootPartition);
  2543. SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
  2544. windirPathPrefix = SpDupStringW(TemporaryBuffer);
  2545. wcscpy(TemporaryBuffer, bootPartition);
  2546. SpConcatenatePaths(TemporaryBuffer, ASR_TEMP_DIRECTORY_PATH);
  2547. tempPathPrefix = SpDupStringW(TemporaryBuffer);
  2548. //
  2549. // Create the TEMP directory
  2550. //
  2551. SpCreateDirectory(
  2552. bootPartition,
  2553. NULL,
  2554. ASR_TEMP_DIRECTORY_PATH,
  2555. 0,
  2556. 0
  2557. );
  2558. SpMemFree(bootPartition);
  2559. //
  2560. // Initialize the compression engine. We may have to uncompress files
  2561. //
  2562. SpdInitialize();
  2563. //
  2564. // Begin copying the files over
  2565. //
  2566. //! display status setup is copying ...
  2567. while (pRec = SpAsrRemoveInstallFileRecord(Gbl_3rdPartyFileList)) {
  2568. if ((!pRec->DestinationFilePath) ||
  2569. (!pRec->SourceFilePath) ||
  2570. (!pRec->DiskDeviceName) ||
  2571. (!pRec->SourceMediaExternalLabel)
  2572. ) {
  2573. ASSERT(0 && L"InstallFiles: Invalid record, one or more attributes are NULL");
  2574. continue;
  2575. }
  2576. diskLoaded = TRUE;
  2577. //
  2578. // Prompt the user for the media if needed
  2579. //
  2580. if ((pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA) ||
  2581. (pRec->Flags & ASR_PROMPT_USER_ON_MEDIA_ERROR)
  2582. ) {
  2583. do {
  2584. moveToNext = TRUE;
  2585. //
  2586. // Prompt the user to insert the appropriate disk
  2587. //
  2588. diskLoaded = SpPromptForDisk(
  2589. pRec->SourceMediaExternalLabel,
  2590. pRec->DiskDeviceName, // if this isn't CD or floppy, SpPromptForDisk will always return true
  2591. pRec->SourceFilePath,
  2592. (BOOLEAN)(pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA), // IgnoreDiskInDrive if PromptAlways
  2593. ! (BOOLEAN)(pRec->Flags & ASR_FILE_IS_REQUIRED), // AllowEscape if the File is not Required
  2594. TRUE, // WarnMultiplePrompts
  2595. NULL
  2596. );
  2597. //
  2598. // If the user hit <ESC> to cancel, we put up a prompt allowing
  2599. // him to retry, skip this file and continue, or exit from Setup.
  2600. //
  2601. if (!diskLoaded) {
  2602. moveToNext = SpAsrFileErrorRetrySkipAbort(
  2603. SP_SCRN_DR_SIF_INSTALL_FILE_NOT_FOUND,
  2604. pRec->SourceFilePath,
  2605. pRec->SourceMediaExternalLabel,
  2606. pRec->VendorString,
  2607. !(pRec->Flags & ASR_FILE_IS_REQUIRED) // allow skip
  2608. );
  2609. }
  2610. } while (!moveToNext);
  2611. }
  2612. if (!diskLoaded) {
  2613. //
  2614. // Disk was not loaded and the user wants to skip this file
  2615. //
  2616. DbgErrorMesg((_asrwarn,
  2617. "SpDrCopy3rdPartyFiles: User skipped file (disk not loaded), src:[%ws] dest[%ws]\n",
  2618. pRec->SourceFilePath,
  2619. pRec->DestinationFilePath
  2620. ));
  2621. continue;
  2622. }
  2623. //
  2624. // The correct disk was loaded. Build the full target path. pRec->CopyToDirectory
  2625. // indicates which prefix we should use.
  2626. //
  2627. switch (pRec->CopyToDirectory) {
  2628. case _SystemRoot:
  2629. wcscpy(TemporaryBuffer, windirPathPrefix);
  2630. break;
  2631. case _Temp:
  2632. case _Tmp:
  2633. case _Default:
  2634. default:
  2635. wcscpy(TemporaryBuffer, tempPathPrefix);
  2636. break;
  2637. }
  2638. SpConcatenatePaths(TemporaryBuffer, pRec->DestinationFilePath);
  2639. fullTargetPath = SpDupStringW(TemporaryBuffer);
  2640. //
  2641. // If the file already exists, prompt the user if needed. We allow him
  2642. // to over-write (delete the existing file), preserve existing
  2643. // (skip copying this file), or exit from Setup.
  2644. //
  2645. if (SpFileExists(fullTargetPath, FALSE)) {
  2646. BOOL deleteFile = FALSE;
  2647. if (pRec->Flags & ASR_PROMPT_USER_ON_COLLISION) {
  2648. if (SpAsrFileErrorDeleteSkipAbort(SP_SCRN_DR_OVERWRITE_EXISTING_FILE, fullTargetPath)) {
  2649. deleteFile = TRUE;
  2650. }
  2651. }
  2652. else if (pRec->Flags & ASR_OVERWRITE_ON_COLLISION) {
  2653. deleteFile = TRUE;
  2654. }
  2655. if (deleteFile) {
  2656. //
  2657. // User chose to overwrite (or OVERWRITE_ON_COLLISION flag was set)
  2658. //
  2659. SpDeleteFile(fullTargetPath, NULL, NULL);
  2660. DbgErrorMesg((_asrwarn,
  2661. "SpDrCopy3rdPartyFiles: Over-writing file, src:[%ws] dest[%ws]\n",
  2662. pRec->SourceFilePath,
  2663. fullTargetPath
  2664. ));
  2665. }
  2666. else {
  2667. //
  2668. // User chose to preserve existing file
  2669. //
  2670. DbgErrorMesg((_asrwarn,
  2671. "SpDrCopy3rdPartyFiles: File exists, existing file was preserved. src:[%ws] dest[%ws]\n",
  2672. pRec->SourceFilePath,
  2673. fullTargetPath
  2674. ));
  2675. continue;
  2676. }
  2677. }
  2678. //
  2679. // Combine the devicepath ("\device\cdrom0") and the sourcefilepath
  2680. // ("i386\driver.sys") to get the full path ("\device\cdrom0\i386\driver.sys")
  2681. // SpConcatenatePaths takes care of adding in the \ between the two if needed
  2682. //
  2683. wcscpy(TemporaryBuffer, pRec->DiskDeviceName);
  2684. SpConcatenatePaths(TemporaryBuffer, pRec->SourceFilePath);
  2685. fullSourcePath = SpDupStringW(TemporaryBuffer);
  2686. moveToNext = FALSE;
  2687. while (!moveToNext) {
  2688. moveToNext = TRUE;
  2689. status = SpCopyFileUsingNames(
  2690. fullSourcePath,
  2691. fullTargetPath,
  2692. 0, // no attributes
  2693. 0 // no flags
  2694. );
  2695. if (!NT_SUCCESS(status)) {
  2696. DbgErrorMesg((_asrwarn, "SpDrCopy3rdPartyFiles. SpCopyFileUsingNames failed. src:[%ws] dest:[%ws]. (0x%x)\n",
  2697. pRec->SourceFilePath,
  2698. fullTargetPath,
  2699. status
  2700. ));
  2701. //
  2702. // File copy was unsuccessful, we put up a prompt allowing
  2703. // the user to retry, skip this file and continue, or exit
  2704. // from Setup.
  2705. //
  2706. if ((pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA) ||
  2707. (pRec->Flags & ASR_PROMPT_USER_ON_MEDIA_ERROR)) {
  2708. moveToNext = SpAsrFileErrorRetrySkipAbort(
  2709. SP_SCRN_DR_SIF_INSTALL_FILE_NOT_FOUND,
  2710. pRec->SourceFilePath,
  2711. pRec->SourceMediaExternalLabel,
  2712. pRec->VendorString,
  2713. TRUE // allow skip
  2714. );
  2715. }
  2716. else {
  2717. moveToNext = TRUE;
  2718. }
  2719. }
  2720. }
  2721. if (!NT_SUCCESS(status)) {
  2722. DbgErrorMesg((_asrwarn, "SpDrCopy3rdPartyFiles: Unable to copy file (copy error), src:[%ws] dest[%ws]\n",
  2723. pRec->SourceFilePath,
  2724. fullTargetPath
  2725. ));
  2726. }
  2727. else {
  2728. DbgStatusMesg((_asrinfo, "SpDrCopy3rdPartyFiles. Copied [%ws] to [%ws]\n",
  2729. pRec->SourceFilePath,
  2730. fullTargetPath
  2731. ));
  2732. }
  2733. SpMemFree(fullSourcePath);
  2734. SpMemFree(fullTargetPath);
  2735. SpAsrDeleteInstallFileRecord(pRec);
  2736. }
  2737. //
  2738. // Done. Shut down the compression engine.
  2739. //
  2740. SpdTerminate();
  2741. SpMemFree(Gbl_3rdPartyFileList);
  2742. SpMemFree(tempPathPrefix);
  2743. SpMemFree(windirPathPrefix);
  2744. return STATUS_SUCCESS;
  2745. }
  2746. NTSTATUS
  2747. SpDrCopyFiles(VOID)
  2748. {
  2749. SpAsrCopyStateFile();
  2750. return SpAsrCopy3rdPartyFiles();
  2751. }
  2752. #define STRING_VALUE(s) REG_SZ,(s),(wcslen((s))+1)*sizeof(WCHAR)
  2753. NTSTATUS
  2754. SpDrSetEnvironmentVariables(HANDLE *HiveRootKeys)
  2755. {
  2756. NTSTATUS status;
  2757. status = SpOpenSetValueAndClose(
  2758. HiveRootKeys[SetupHiveSystem],
  2759. ASR_CONTEXT_KEY,
  2760. ASR_CONTEXT_VALUE,
  2761. STRING_VALUE(ASR_CONTEXT_DATA));
  2762. DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
  2763. ASR_CONTEXT_KEY,
  2764. ASR_CONTEXT_VALUE,
  2765. ASR_CONTEXT_DATA,
  2766. status));
  2767. if (!NT_SUCCESS(status)) {
  2768. return status;
  2769. }
  2770. Gbl_SystemPartitionName = SpAsrGetRegionName(Gbl_SystemPartitionRegion);
  2771. status = SpOpenSetValueAndClose(
  2772. HiveRootKeys[SetupHiveSystem],
  2773. ASR_CONTEXT_KEY,
  2774. ASR_SYSTEM_PARTITION_VALUE,
  2775. STRING_VALUE(Gbl_SystemPartitionName));
  2776. DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
  2777. ASR_CONTEXT_KEY,
  2778. ASR_SYSTEM_PARTITION_VALUE,
  2779. Gbl_SystemPartitionName,
  2780. status));
  2781. if (!NT_SUCCESS(status)) {
  2782. return status;
  2783. }
  2784. Gbl_BootPartitionName = SpAsrGetRegionName(Gbl_BootPartitionRegion);
  2785. status = SpOpenSetValueAndClose(
  2786. HiveRootKeys[SetupHiveSystem],
  2787. ASR_CONTEXT_KEY,
  2788. ASR_BOOT_PARTITION_VALUE,
  2789. STRING_VALUE(Gbl_BootPartitionName));
  2790. DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
  2791. ASR_CONTEXT_KEY,
  2792. ASR_BOOT_PARTITION_VALUE,
  2793. Gbl_BootPartitionName,
  2794. status));
  2795. return status;
  2796. }
  2797. PDISK_REGION
  2798. SpAsrPrepareBootRegion(
  2799. IN PVOID SifHandle,
  2800. IN PWSTR Local_SetupSourceDevicePath,
  2801. IN PWSTR Local_DirectoryOnSetupSource
  2802. )
  2803. /*++
  2804. -pending code description
  2805. --*/
  2806. {
  2807. PWSTR systemKey = ASR_SIF_SYSTEM_KEY;
  2808. PWSTR ntDir = NULL;
  2809. ULONG diskIndex = 0;
  2810. PSIF_PARTITION_RECORD ppartitionRecord = NULL;
  2811. FilesystemType regionFsType = FilesystemUnknown;
  2812. BOOLEAN isBoot = FALSE;
  2813. //
  2814. // Initialize Gbl_BootPartitionDriveLetter.
  2815. //
  2816. ntDir = SpAsrGetNtDirectoryPathBySystemKey(systemKey);
  2817. if (!SpAsrIsValidBootDrive(ntDir)) {
  2818. SpAsrRaiseFatalErrorWs(
  2819. SP_SCRN_DR_SIF_BAD_RECORD,
  2820. L"Windows directory specified in asr.sif is invalid",
  2821. SIF_ASR_SYSTEMS_SECTION
  2822. );
  2823. // Does not return
  2824. }
  2825. Gbl_BootPartitionDriveLetter = ntDir[0];
  2826. //
  2827. // Find boot partition region from the partition set table.
  2828. // from the records in the global partition set.
  2829. //
  2830. Gbl_BootPartitionRegion = NULL;
  2831. for (diskIndex = 0; (diskIndex < HardDiskCount); diskIndex++) {
  2832. if (!(Gbl_PartitionSetTable2[diskIndex] &&
  2833. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord &&
  2834. Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList)) {
  2835. continue;
  2836. }
  2837. ppartitionRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
  2838. while (ppartitionRecord) {
  2839. isBoot = SpAsrIsBootPartitionRecord(ppartitionRecord->PartitionFlag);
  2840. if (isBoot) {
  2841. Gbl_BootPartitionRegion = SpAsrDiskPartitionExists(diskIndex, ppartitionRecord);
  2842. if (!Gbl_BootPartitionRegion) {
  2843. DbgFatalMesg((_asrerr,
  2844. "Partition record with boot region found, but boot (winnt) region is NULL\n"
  2845. ));
  2846. SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  2847. L"Boot pRegion is NULL"
  2848. );
  2849. }
  2850. Gbl_BootPartitionRecord = SpAsrCopyPartitionRecord(ppartitionRecord);
  2851. break;
  2852. }
  2853. ppartitionRecord = ppartitionRecord->Next;
  2854. }
  2855. }
  2856. if (!Gbl_BootPartitionRegion) {
  2857. DbgFatalMesg((_asrerr, "No partition record with boot region found, boot (winnt) region is NULL\n"));
  2858. SpAsrRaiseFatalErrorWs(
  2859. SP_SCRN_DR_SIF_BAD_RECORD,
  2860. L"No boot partition found in asr.sif",
  2861. SIF_ASR_PARTITIONS_SECTION
  2862. );
  2863. }
  2864. SpAsrReformatPartition(Gbl_BootPartitionRegion,
  2865. Gbl_BootPartitionRecord->FileSystemType,
  2866. SifHandle,
  2867. Gbl_BootPartitionRecord->ClusterSize,
  2868. Local_SetupSourceDevicePath,
  2869. Local_DirectoryOnSetupSource,
  2870. TRUE
  2871. );
  2872. return Gbl_BootPartitionRegion;
  2873. }
  2874. PDISK_REGION
  2875. SpAsrPrepareSystemRegion(
  2876. IN PVOID SifHandle,
  2877. IN PWSTR Local_SetupSourceDevicePath,
  2878. IN PWSTR Local_DirectoryOnSetupSource
  2879. )
  2880. /*++
  2881. -pending code description
  2882. --*/
  2883. {
  2884. ULONG diskIndex = 0;
  2885. BOOLEAN found = FALSE;
  2886. BOOLEAN diskChanged = FALSE;
  2887. PWSTR partitionDeviceName = NULL;
  2888. PDISK_REGION pRegion = NULL;
  2889. PSIF_PARTITION_RECORD ppartitionRecord = NULL;
  2890. ULONGLONG startSector = 0;
  2891. DWORD diskNumber = 0;
  2892. if (IsNEC_98) {
  2893. // This is a NEC x86 machine
  2894. pRegion = Gbl_BootPartitionRegion;
  2895. ASSERT(pRegion);
  2896. } else {
  2897. // This is not a NEC x86 machine
  2898. #ifdef _IA64_
  2899. WCHAR RegionName[MAX_PATH];
  2900. if (!(pRegion = SpPtnLocateESP())) {
  2901. SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  2902. L"System Region is NULL"
  2903. );
  2904. }
  2905. SPPT_MARK_REGION_AS_SYSTEMPARTITION(pRegion, TRUE);
  2906. SPPT_SET_REGION_DIRTY(pRegion, TRUE);
  2907. ValidArcSystemPartition = TRUE;
  2908. //
  2909. // Remove the drive letter also
  2910. //
  2911. swprintf(RegionName,
  2912. L"\\Device\\Harddisk%u\\Partition%u",
  2913. pRegion->DiskNumber,
  2914. pRegion->PartitionNumber);
  2915. SpDeleteDriveLetter(RegionName);
  2916. pRegion->DriveLetter = 0;
  2917. #else
  2918. if (!(pRegion = SpPtValidSystemPartition())) {
  2919. SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
  2920. L"System Region is NULL"
  2921. );
  2922. }
  2923. #endif
  2924. }
  2925. partitionDeviceName = SpAsrGetRegionName(pRegion);
  2926. DbgStatusMesg((_asrinfo, "PrepareSystemRegion. sys-ptn:[%ws]. Making Active\n",
  2927. partitionDeviceName));
  2928. startSector = pRegion->StartSector;
  2929. diskNumber = pRegion->DiskNumber;
  2930. #ifndef _IA64_
  2931. SpPtnMakeRegionActive(pRegion);
  2932. #endif
  2933. SpPtnCommitChanges(pRegion->DiskNumber, &diskChanged);
  2934. DbgStatusMesg((
  2935. _asrinfo,
  2936. "PrepareSystemRegion. sys-region made active. Disk %lu. %s.\n",
  2937. pRegion->DiskNumber,
  2938. diskChanged ? "Disk not changed.":"Disk changed"
  2939. ));
  2940. pRegion = SpPtLookupRegionByStart(SPPT_GET_PARTITIONED_DISK(diskNumber), FALSE, startSector);
  2941. //
  2942. // Consistency checks. These can eventually be removed
  2943. //
  2944. ASSERT(pRegion);
  2945. diskIndex = pRegion->DiskNumber;
  2946. ASSERT(Gbl_PartitionSetTable2[diskIndex]);
  2947. ASSERT(Gbl_PartitionSetTable2[diskIndex]->pDiskRecord);
  2948. ASSERT(Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList);
  2949. //
  2950. // Ensure that the partition is correctly formatted. To accomplish this,
  2951. // we need to find the record corresponding to this pRegion. We use the
  2952. // record to check for the correct file format.
  2953. //
  2954. ppartitionRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
  2955. while (ppartitionRecord) {
  2956. if ((ULONGLONG)ppartitionRecord->StartSector == pRegion->StartSector) {
  2957. found = TRUE;
  2958. break;
  2959. }
  2960. ppartitionRecord = ppartitionRecord->Next;
  2961. }
  2962. if (!found) {
  2963. DbgFatalMesg((_asrerr,
  2964. "Did not find system partition, start sector: %I64u\n",
  2965. pRegion->StartSector
  2966. ));
  2967. SpAsrRaiseFatalErrorWs(
  2968. SP_SCRN_DR_SIF_BAD_RECORD,
  2969. L"No system partition found in asr.sif",
  2970. SIF_ASR_PARTITIONS_SECTION
  2971. );
  2972. }
  2973. //
  2974. // Format the system partition if needed. We don't re-format the system
  2975. // partition if it's intact.
  2976. //
  2977. if (SpAsrPartitionNeedsFormatting(pRegion, ppartitionRecord->FileSystemType)) {
  2978. SpAsrReformatPartition(
  2979. pRegion,
  2980. ppartitionRecord->FileSystemType,
  2981. SifHandle,
  2982. ppartitionRecord->ClusterSize,
  2983. Local_SetupSourceDevicePath,
  2984. Local_DirectoryOnSetupSource,
  2985. FALSE
  2986. );
  2987. }
  2988. SpMemFree(partitionDeviceName);
  2989. Gbl_SystemPartitionRegion = pRegion;
  2990. return Gbl_SystemPartitionRegion;
  2991. }
  2992. #if 0
  2993. //
  2994. // We don't convert the partition types any more--it is okay to leave
  2995. // them as type 0x42 if the partitions are intact.
  2996. //
  2997. BOOLEAN
  2998. SpAsrChangeLdmPartitionTypes(VOID)
  2999. /*++
  3000. Routine Description
  3001. Changes disk types from 0x42 to 0x7 if needed
  3002. (If the disk is intact, it would not have been re-created
  3003. and hence re-typed above)
  3004. --*/
  3005. {
  3006. ULONG setIndex;
  3007. ULONG ptnIndex;
  3008. PDISK_PARTITION_SET ppartitionSet;
  3009. PSIF_DISK_RECORD pdiskRecord;
  3010. PSIF_PARTITION_RECORD ppartitionRecord;
  3011. BOOLEAN madeAChange = FALSE;
  3012. // Look for any disks which were marked to change from type 0x42 to
  3013. // type 0x7.
  3014. for (setIndex = 0; setIndex < HardDiskCount; setIndex++) {
  3015. ppartitionSet = Gbl_PartitionSetTable2[setIndex];
  3016. if (ppartitionSet && ppartitionSet->pDiskRecord) {
  3017. pdiskRecord = ppartitionSet->pDiskRecord;
  3018. if (pdiskRecord->ContainsNtPartition ||
  3019. pdiskRecord->ContainsSystemPartition) {
  3020. ppartitionRecord = pdiskRecord->PartitionList->First;
  3021. while (ppartitionRecord) {
  3022. if (ppartitionRecord->NeedsLdmRetype) {
  3023. // Disk type needs to be changed
  3024. PPARTITIONED_DISK pDisk;
  3025. PDISK_REGION pRegion = NULL;
  3026. pDisk = &PartitionedDisks[setIndex];
  3027. // try finding the disk region in the main list
  3028. pRegion = SpPtLookupRegionByStart(pDisk, FALSE, ppartitionRecord->StartSector);
  3029. if (!pRegion) {
  3030. // that failed, try finding disk region using the
  3031. // extended partitions list
  3032. pRegion = SpPtLookupRegionByStart(pDisk, TRUE, ppartitionRecord->StartSector);
  3033. }
  3034. if (!pRegion) {
  3035. // the disk region couldn't be found
  3036. DbgErrorMesg((_asrwarn, "SpAsrChangeLdmPartitionTypes. Unable to reset LDM partition record %ws at SS %I64u\n",
  3037. ppartitionRecord->CurrPartKey,
  3038. ppartitionRecord->StartSector));
  3039. ppartitionRecord = ppartitionRecord->Next;
  3040. continue;
  3041. }
  3042. // The disk region was found, now change the disk type
  3043. if (!IsRecognizedPartition(ppartitionRecord->FileSystemType)) {
  3044. //
  3045. // This is an 0x42 partition on the boot/sys disk, but it is
  3046. // not the boot or system partition. The FileSystemType is not
  3047. // recognised since it is set to be 0x42 as well. (The
  3048. // FileSystemType is only valid for the boot and system
  3049. // partitions--for all other partitions,
  3050. // it is set to be the same as the PartitionType)
  3051. //
  3052. // We set it to 0x7 for the time being. The actual file-system type
  3053. // will be set later in GUI-Setup by asr_ldm and asr_fmt.
  3054. //
  3055. DbgStatusMesg((_asrinfo,
  3056. "MBR ptn-rec %ws re-typed (0x%x->0x7) \n",
  3057. ppartitionRecord->CurrPartKey,
  3058. ppartitionRecord->FileSystemType
  3059. ));
  3060. ppartitionRecord->FileSystemType = PARTITION_IFS;
  3061. ppartitionRecord->PartitionType = PARTITION_IFS;
  3062. }
  3063. else {
  3064. DbgStatusMesg((_asrinfo,
  3065. "MBR ptn-rec %ws re-typed (0x%x->0x%x).\n",
  3066. ppartitionRecord->CurrPartKey,
  3067. ppartitionRecord->PartitionType,
  3068. ppartitionRecord->FileSystemType
  3069. ));
  3070. ppartitionRecord->PartitionType = ppartitionRecord->FileSystemType;
  3071. }
  3072. ppartitionRecord->NeedsLdmRetype = FALSE;
  3073. SPPT_SET_PARTITION_TYPE(pRegion, ppartitionRecord->FileSystemType);
  3074. SPPT_SET_REGION_DIRTY(pRegion, TRUE);
  3075. pRegion->DynamicVolume = TRUE;
  3076. pRegion->DynamicVolumeSuitableForOS = TRUE;
  3077. madeAChange = TRUE;
  3078. DbgStatusMesg((_asrinfo, "SpAsrChangeLdmPartitionTypes. Changed disk [%ws] ptn [%ws] type to 0x%x\n",
  3079. pdiskRecord->CurrDiskKey, ppartitionRecord->CurrPartKey, ppartitionRecord->PartitionType));
  3080. }
  3081. ppartitionRecord = ppartitionRecord->Next;
  3082. }
  3083. }
  3084. }
  3085. }
  3086. return madeAChange;
  3087. }
  3088. #endif // 0
  3089. extern VOID
  3090. SpAsrDbgDumpInstallFileList(IN PSIF_INSTALLFILE_LIST pList);
  3091. VOID
  3092. SpAsrSetNewDiskID(
  3093. IN ULONG DiskNumber,
  3094. IN GUID *NewGuid, // valid only for GPT disks
  3095. IN ULONG NewSignature // valid only for MBR disks
  3096. )
  3097. {
  3098. PPARTITIONED_DISK pDisk = &PartitionedDisks[DiskNumber];
  3099. PDISK_REGION pFirstRegion = NULL;
  3100. BOOLEAN Changes = FALSE;
  3101. NTSTATUS Status = STATUS_SUCCESS;
  3102. if (PARTITION_STYLE_GPT == (PARTITION_STYLE) (pDisk->HardDisk->DriveLayout.PartitionStyle)) {
  3103. //
  3104. // Set the new disk GUID
  3105. //
  3106. CopyMemory(&(pDisk->HardDisk->DriveLayout.Gpt.DiskId), NewGuid, sizeof(GUID));
  3107. }
  3108. else if (PARTITION_STYLE_MBR == (PARTITION_STYLE) (pDisk->HardDisk->DriveLayout.PartitionStyle)) {
  3109. //
  3110. // Set the new disk signature
  3111. //
  3112. pDisk->HardDisk->DriveLayout.Mbr.Signature = NewSignature;
  3113. }
  3114. else {
  3115. return;
  3116. }
  3117. //
  3118. // For Commit to pick up the new Guid, at least one region on the
  3119. // disk must be marked dirty.
  3120. //
  3121. pFirstRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3122. SPPT_SET_REGION_DIRTY(pFirstRegion, TRUE);
  3123. Status = SpPtnCommitChanges(DiskNumber, &Changes);
  3124. //
  3125. // Reset the dirty flag on the first region
  3126. //
  3127. pFirstRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3128. SPPT_SET_REGION_DIRTY(pFirstRegion, FALSE);
  3129. }
  3130. NTSTATUS
  3131. SpDrPtPrepareDisks(
  3132. IN PVOID SifHandle,
  3133. OUT PDISK_REGION *BootPartitionRegion,
  3134. OUT PDISK_REGION *SystemPartitionRegion,
  3135. IN PWSTR SetupSourceDevicePath,
  3136. IN PWSTR DirectoryOnSetupSource,
  3137. OUT BOOLEAN *RepairedNt
  3138. )
  3139. /*++
  3140. Description:
  3141. If necessary, SpDrPtPrepareDisks() restores (recreates and formats) the
  3142. system and boot partitions based on information obtained from the
  3143. asr.sif file.
  3144. Arguments:
  3145. SifHandle - Handle to txtsetup.sif
  3146. BootPartitionRegion - Receives a pointer to the partition into
  3147. which NT will be installed (e.g., \WINNT).
  3148. SystemPartitionRegion - Receives a pointer to the partition into
  3149. which the boot loader will be installed.
  3150. SetupSourceDevicePath - Path to the CDROM
  3151. DirectoryOnSetupSource - The directory on the installation CDROM.
  3152. (usually "\I386" for x86 installations)
  3153. RepairedNt - Receives a pointer to a boolean value that is set to:
  3154. TRUE: Indicates the partition structure on the loader
  3155. disk and he partition structure on the NT disk were
  3156. intact and that ASR attempted to perform a repair
  3157. operation.
  3158. FALSE: Indicates the partition structure on either the
  3159. loader disk or the NT disk (or both) were removed
  3160. and recreated. When SpStartSetup() sees this value,
  3161. it will proceed with a normal installation.
  3162. Return Value:
  3163. STATUS_SUCCESS, always! (as of now, anyway)
  3164. --*/
  3165. {
  3166. BOOL done = TRUE,
  3167. next = TRUE,
  3168. warningScreenDone = FALSE;
  3169. NTSTATUS status;
  3170. ULONG diskIndex = 0;
  3171. PWSTR setupSourceDevicePath = NULL,
  3172. directoryOnSetupSource = NULL;
  3173. DbgStatusMesg((_asrinfo, "Entering SpDrPtPrepareDisks. Beginning ASR/ER/RC Processing\n"));
  3174. DbgStatusMesg((_asrinfo, "SetupSourceDevicePath:[%ws], DirectoryOnSetupSource:[%ws]\n",
  3175. SetupSourceDevicePath, DirectoryOnSetupSource));
  3176. *RepairedNt = FALSE;
  3177. //
  3178. // find out if the user wants Recovery Console, traditional Emergency
  3179. // Repair (ER), or full scale Automated System Recovery (ASR)
  3180. //
  3181. Gbl_SifHandle = SifHandle;
  3182. setupSourceDevicePath = SpDupStringW(SetupSourceDevicePath);
  3183. directoryOnSetupSource = SpDupStringW(DirectoryOnSetupSource);
  3184. do {
  3185. if (!done) {
  3186. DbgStatusMesg((_asrinfo, "User hit <ESC> to cancel. Prompting for ASR/ER/RC again\n"));
  3187. }
  3188. if (!SpDrEnabled() || RepairWinnt) {
  3189. SpAsrQueryRepairOrDr();
  3190. }
  3191. if(ForceConsole) { // Recovery Console
  3192. DbgStatusMesg((_asrinfo, "User chose Recovery Console. Exiting SpDrPtPrepareDisks.\n"));
  3193. return STATUS_SUCCESS;
  3194. }
  3195. DbgStatusMesg((_asrinfo, "User chose %s, sys-drive:[%wc], nt/boot-drive:[%wc]\n",
  3196. RepairWinnt ? Gbl_RepairWinntFast ? "Fast ER" : "Manual ER" : "ASR",
  3197. (Gbl_SystemPartitionRegion ? Gbl_SystemPartitionRegion->DriveLetter : L'\\'),
  3198. (Gbl_BootPartitionRegion ? Gbl_BootPartitionRegion->DriveLetter : L'\\') ));
  3199. //
  3200. // Prompt for ER/ASR floppy
  3201. //
  3202. if (RepairWinnt) { // ER
  3203. done = SpAsrGetErDiskette(SifHandle);
  3204. }
  3205. else { // ASR
  3206. if (ASRMODE_NORMAL == SpAsrGetAsrMode()) {
  3207. SpInitializePidString(SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource);
  3208. }
  3209. done = SpAsrLoadAsrDiskette();
  3210. }
  3211. } while (!done);
  3212. //
  3213. // At this point, if RepairWinnt is TRUE, user wants ER, else user
  3214. // wants ASR. (If he wanted Recovery Console we would've returned
  3215. // STATUS_SUCCESS above.) In either case, the appropriate disk is
  3216. // already in the drive
  3217. //
  3218. if (RepairWinnt) { // ER
  3219. //
  3220. // if the boot partition was not repaired (deleted, recreated, and
  3221. // reformatted), then attempt an emergency repair of the system.
  3222. //
  3223. if (Gbl_NtPartitionIntact == TRUE) {
  3224. *RepairedNt = SpAsrAttemptRepair(
  3225. SifHandle,
  3226. SetupSourceDevicePath,
  3227. DirectoryOnSetupSource,
  3228. SetupSourceDevicePath,
  3229. DirectoryOnSetupSource
  3230. );
  3231. if (*RepairedNt) {
  3232. WinntSetup = FALSE;
  3233. }
  3234. *SystemPartitionRegion = Gbl_SystemPartitionRegion;
  3235. *BootPartitionRegion = Gbl_BootPartitionRegion;
  3236. }
  3237. else {
  3238. //
  3239. // If the NT partition is not intact, we cannot do an ER.
  3240. //
  3241. SpAsrCannotDoER();
  3242. SpDone(0, FALSE, TRUE);
  3243. }
  3244. }
  3245. else { // ASR
  3246. SpAsrInitIoDeviceCount();
  3247. SpAsrCheckAsrStateFileVersion();
  3248. SpAsrCreatePartitionSets(setupSourceDevicePath, directoryOnSetupSource);
  3249. Gbl_3rdPartyFileList = SpAsrInit3rdPartyFileList(SetupSourceDevicePath);
  3250. SpAsrDbgDumpPartitionSets();
  3251. SpAsrDeleteMountedDevicesKey();
  3252. SpAsrRemoveMountPoints(); // restored by asr_fmt.exe etc
  3253. //
  3254. // Check hard disks and repartition as needed
  3255. //
  3256. next = TRUE;
  3257. for (diskIndex = 0; diskIndex < HardDiskCount; (diskIndex += (next ? 1 : 0))) {
  3258. BOOLEAN skip = FALSE;
  3259. next = TRUE;
  3260. SpAsrDbgDumpDisk(diskIndex);
  3261. if (!warningScreenDone) {
  3262. skip = SpAsrpSkipDiskRepartition(diskIndex, FALSE);
  3263. if (!skip) {
  3264. //
  3265. // If we are going to repartition a disk, put up the
  3266. // warning screen to make sure the user knows all
  3267. // partitions on the disk are going to get clobbered,
  3268. // but only once - after the first disk with a problem,
  3269. // don't display the screen again.
  3270. //
  3271. SpAsrClobberDiskWarning();
  3272. warningScreenDone = TRUE;
  3273. }
  3274. }
  3275. skip = SpAsrpSkipDiskRepartition(diskIndex, TRUE);
  3276. if (!skip) {
  3277. CREATE_DISK CreateDisk;
  3278. PSIF_DISK_RECORD pCurrentDisk = Gbl_PartitionSetTable1[diskIndex]->pDiskRecord;
  3279. PHARD_DISK HardDisk = SPPT_GET_HARDDISK(diskIndex);
  3280. BOOLEAN IsBlank = TRUE;
  3281. BOOLEAN preservePartitions = FALSE;
  3282. UCHAR MbrPartitionType = PARTITION_ENTRY_UNUSED;
  3283. //
  3284. // We're here because the partition structure of the disk does not
  3285. // match with that specified by the SIF file. As a consequence
  3286. // all of the partitions on this disk will be removed and recreated.
  3287. //
  3288. if (SpPtnGetPartitionCountDisk(diskIndex) ||
  3289. SpPtnGetContainerPartitionCount(diskIndex)) {
  3290. //
  3291. // The physical disk has partitions, clear them
  3292. //
  3293. // On GPT disks, we erase all the partitions with the
  3294. // exception of the EFI System Partition. Note that we
  3295. // delete all foreign/unrecognised partitions as
  3296. // well.
  3297. //
  3298. // For MBR disks, we erase all the partitions with the
  3299. // exception of any OEM partitions. Note that as in the
  3300. // case of GPT disks, we delete unrecognised/foriegn
  3301. // partitions.
  3302. //
  3303. //
  3304. // Get the partition type of the first partition on the
  3305. // sifDisk. If this is an OEM partition, and the
  3306. // current disk has a partition with the same exact
  3307. // partition type, we should preserve it.
  3308. //
  3309. if (PARTITION_STYLE_MBR == pCurrentDisk->PartitionStyle) {
  3310. if (((pCurrentDisk->ContainsNtPartition)
  3311. || (pCurrentDisk->ContainsSystemPartition)) &&
  3312. (pCurrentDisk->PartitionList) &&
  3313. (pCurrentDisk->PartitionList->First)) {
  3314. MbrPartitionType = pCurrentDisk->PartitionList->First->PartitionType;
  3315. }
  3316. if (IsOEMPartition(MbrPartitionType)) {
  3317. preservePartitions = TRUE;
  3318. }
  3319. }
  3320. else if (PARTITION_STYLE_GPT == pCurrentDisk->PartitionStyle) {
  3321. preservePartitions = TRUE;
  3322. }
  3323. SpAsrDeletePartitions(diskIndex, preservePartitions, MbrPartitionType, &IsBlank);
  3324. }
  3325. if (IsBlank) {
  3326. //
  3327. // The disk is blank, set the appropriate signature/ID
  3328. //
  3329. ZeroMemory(&CreateDisk, sizeof(CREATE_DISK));
  3330. CreateDisk.PartitionStyle = pCurrentDisk->PartitionStyle;
  3331. if (PARTITION_STYLE_MBR == pCurrentDisk->PartitionStyle) {
  3332. CreateDisk.Mbr.Signature = pCurrentDisk->SifDiskMbrSignature;
  3333. }
  3334. else if (PARTITION_STYLE_GPT == pCurrentDisk->PartitionStyle) {
  3335. CopyMemory(&(CreateDisk.Gpt.DiskId),
  3336. &(pCurrentDisk->SifDiskGptId),
  3337. sizeof(GUID));
  3338. CreateDisk.Gpt.MaxPartitionCount = pCurrentDisk->MaxGptPartitionCount;
  3339. }
  3340. else {
  3341. ASSERT(0 && L"Unrecognised partition style");
  3342. continue;
  3343. }
  3344. SPPT_SET_DISK_BLANK(diskIndex, TRUE);
  3345. //
  3346. // Intialise the disk to the appropriate style
  3347. //
  3348. status = SpPtnInitializeDiskStyle(diskIndex, pCurrentDisk->PartitionStyle, &CreateDisk);
  3349. if (NT_SUCCESS(status)) {
  3350. status = SpPtnInitializeDiskDrive(diskIndex);
  3351. }
  3352. }
  3353. else {
  3354. //
  3355. // Special case: the EFI system partition, or some OEM
  3356. // partition, was preserved. We should just update
  3357. // the disk GUID or signature.
  3358. //
  3359. SpAsrSetNewDiskID(diskIndex, &(pCurrentDisk->SifDiskGptId), pCurrentDisk->SifDiskMbrSignature);
  3360. }
  3361. //
  3362. // Create the new paritions
  3363. //
  3364. SpAsrRecreateDiskPartitions(diskIndex, (preservePartitions && (!IsBlank)), MbrPartitionType);
  3365. }
  3366. }
  3367. SpAsrDbgDumpPartitionLists(2, L"After partition recreation.");
  3368. //
  3369. // Format the Boot partition. (Always, EXCEPT in automated tests)
  3370. // This won't return if the boot partition region doesn't exist
  3371. //
  3372. *BootPartitionRegion = SpAsrPrepareBootRegion(
  3373. SifHandle,
  3374. setupSourceDevicePath,
  3375. directoryOnSetupSource
  3376. );
  3377. //
  3378. // Format the system partition only if necessary.
  3379. // This won't return if the system partition region doesn't exist
  3380. //
  3381. *SystemPartitionRegion = SpAsrPrepareSystemRegion(
  3382. SifHandle,
  3383. setupSourceDevicePath,
  3384. directoryOnSetupSource
  3385. );
  3386. } // RepairWinnt
  3387. SpMemFree(setupSourceDevicePath);
  3388. SpMemFree(directoryOnSetupSource);
  3389. DbgStatusMesg((_asrinfo, "Exiting SpDrPtPrepareDisks\n"));
  3390. return STATUS_SUCCESS;
  3391. }