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.

2934 lines
84 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. sppart2.c
  5. Abstract:
  6. Second file for disk preparation UI;
  7. supplies routines to handle a user's selection
  8. of the partition onto which he wants to install NT.
  9. Author:
  10. Ted Miller (tedm) 16-Sep-1993
  11. Revision History:
  12. --*/
  13. #include "spprecmp.h"
  14. #pragma hdrstop
  15. #ifdef _X86_
  16. BOOLEAN
  17. SpIsWin9xMsdosSys(
  18. IN PDISK_REGION Region,
  19. OUT PSTR* Win9xPath
  20. );
  21. #endif
  22. ULONG
  23. SpFormattingOptions(
  24. IN BOOLEAN AllowFatFormat,
  25. IN BOOLEAN AllowNtfsFormat,
  26. IN BOOLEAN AllowConvertNtfs,
  27. IN BOOLEAN AllowDoNothing,
  28. IN BOOLEAN AllowEscape
  29. );
  30. BOOLEAN
  31. SpPtRegionDescription(
  32. IN PPARTITIONED_DISK pDisk,
  33. IN PDISK_REGION pRegion,
  34. OUT PWCHAR Buffer,
  35. IN ULONG BufferSize
  36. );
  37. typedef enum {
  38. FormatOptionCancel = 0,
  39. FormatOptionFat,
  40. FormatOptionNtfs,
  41. FormatOptionFatQuick,
  42. FormatOptionNtfsQuick,
  43. FormatOptionConvertToNtfs,
  44. FormatOptionDoNothing
  45. } FormatOptions;
  46. extern PSETUP_COMMUNICATION CommunicationParams;
  47. //#ifdef TEST
  48. #if defined(_AMD64_) || defined(_X86_)
  49. BOOLEAN
  50. SpIsExistsOs(
  51. IN PDISK_REGION CColonRegion
  52. );
  53. extern NTSTATUS
  54. pSpBootCodeIo(
  55. IN PWSTR FilePath,
  56. IN PWSTR AdditionalFilePath, OPTIONAL
  57. IN ULONG BytesToRead,
  58. IN PUCHAR *Buffer,
  59. IN ULONG OpenDisposition,
  60. IN BOOLEAN Write,
  61. IN ULONGLONG Offset,
  62. IN ULONG BytesPerSector
  63. );
  64. extern VOID
  65. SpDetermineOsTypeFromBootSector(
  66. IN PWSTR CColonPath,
  67. IN PUCHAR BootSector,
  68. OUT PUCHAR *OsDescription,
  69. OUT PBOOLEAN IsNtBootcode,
  70. OUT PBOOLEAN IsOtherOsInstalled,
  71. IN WCHAR DriveLetter
  72. );
  73. extern BOOLEAN
  74. SpHasMZHeader(
  75. IN PWSTR FileName
  76. );
  77. #endif // defined(_AMD64_) || defined(_X86_)
  78. //#endif //TEST
  79. BOOLEAN
  80. SpPtIsForeignPartition(
  81. IN PDISK_REGION Region
  82. )
  83. {
  84. BOOLEAN ForeignPartition = TRUE; // for blank disks ?
  85. if (Region){
  86. UCHAR SystemId;
  87. if (SPPT_IS_MBR_DISK(Region->DiskNumber)) {
  88. SystemId = SpPtGetPartitionType(Region);
  89. ASSERT(SystemId != PARTITION_ENTRY_UNUSED);
  90. ASSERT(!IsContainerPartition(SystemId));
  91. ForeignPartition = ((PartitionNameIds[SystemId] != (UCHAR)(-1)) &&
  92. (!Region->DynamicVolume || !Region->DynamicVolumeSuitableForOS));
  93. }
  94. if (SPPT_IS_GPT_DISK(Region->DiskNumber)) {
  95. //
  96. // If problem occurs of unattend case trying to install to an OEM partition
  97. // Add this condition (||(Region->IsReserved)) to block selection of OEM
  98. // partition.
  99. //
  100. ForeignPartition = (Region->DynamicVolume && !Region->DynamicVolumeSuitableForOS);
  101. }
  102. }
  103. return ForeignPartition;
  104. }
  105. BOOLEAN
  106. SpPtDeterminePartitionGood(
  107. IN PDISK_REGION Region,
  108. IN ULONGLONG RequiredKB,
  109. IN BOOLEAN DisallowOtherInstalls
  110. )
  111. {
  112. UCHAR SystemId;
  113. BOOLEAN NewlyCreated;
  114. ULONG PreconfirmFormatId;
  115. ULONG ValidKeys1[2] = { ASCI_CR ,0 };
  116. ULONG ValidKeys2[2] = { ASCI_ESC,0 };
  117. ULONG Mnemonics1[2] = { MnemonicContinueSetup, 0 };
  118. ULONG Mnemonics2[2] = { 0,0 };
  119. ULONGLONG RegionSizeKB;
  120. ULONG r;
  121. #if defined(_AMD64_) || defined(_X86_)
  122. PDISK_REGION systemPartitionRegion;
  123. #endif // defined(_AMD64_) || defined(_X86_)
  124. ULONG selection;
  125. NTSTATUS Status;
  126. ULONG Count;
  127. PWSTR p;
  128. PWSTR RegionDescr;
  129. LARGE_INTEGER temp;
  130. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  131. "SETUP: SpPtDeterminePartitionGood(): Starting partition verification\n" ));
  132. //
  133. // Make sure we can see the disk from the firmware/bios.
  134. // If we can get an arc name for the disk, assume it's ok.
  135. // Otherwise, it ain't.
  136. //
  137. p = SpNtToArc( HardDisks[Region->DiskNumber].DevicePath,PrimaryArcPath );
  138. if (p == NULL) {
  139. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  140. "SETUP: SpPtDeterminePartitionGood(): Failed to create an arc name for this partition\n" ));
  141. return FALSE;
  142. }
  143. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  144. "SETUP: SpPtDeterminePartitionGood(): partition=[%ws]\n", p ));
  145. //
  146. // Make sure the partition is formatted.
  147. //
  148. if( Region->PartitionedSpace ) {
  149. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  150. "SETUP: SpPtDeterminePartitionGood(): This partition is formated.\n"));
  151. } else {
  152. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  153. "SETUP: SpPtDeterminePartitionGood(): This partition hasn't been formated.\n"));
  154. return FALSE;
  155. }
  156. //
  157. // I think he's formatted, but he better be of a format that I can read.
  158. // Make sure.
  159. //
  160. if( (Region->Filesystem == FilesystemFat) ||
  161. (Region->Filesystem == FilesystemFirstKnown) ||
  162. (Region->Filesystem == FilesystemNtfs) ||
  163. (Region->Filesystem == FilesystemFat32) ) {
  164. //
  165. // Life is grand. Let's tell the user and keep going.
  166. //
  167. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  168. "SETUP: SpPtDeterminePartitionGood(): This partition "
  169. "is formated with a known filesystem (%d).\n", Region->Filesystem ));
  170. } else {
  171. //
  172. // Darn! We don't know how to read this filesystem. Bail.
  173. //
  174. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  175. "SETUP: SpPtDeterminePartitionGood(): This partition is "
  176. "formated with an unknown (or invalid for holding an installation) "
  177. "filesystem (%d).\n", Region->Filesystem ));
  178. return FALSE;
  179. }
  180. #if defined(_AMD64_) || defined(_X86_)
  181. //
  182. // On amd64/x86 we don't allow disks that have LUN greater than 0
  183. //
  184. SpStringToLower( p );
  185. if( wcsstr( p, L"scsi(" ) &&
  186. wcsstr( p, L")rdisk(" ) ) {
  187. if( wcsstr( p, L")rdisk(0)" ) == NULL ) {
  188. SpMemFree(p);
  189. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  190. "SETUP: SpPtDeterminePartitionGood(): Disks with "
  191. "a LUN greater than zero are not allowed\n" ));
  192. return FALSE;
  193. }
  194. }
  195. #endif // defined(_AMD64_) || defined(_X86_)
  196. SpMemFree(p);
  197. //
  198. // Disallow installation to PCMCIA disks.
  199. //
  200. if(HardDisks[Region->DiskNumber].PCCard) {
  201. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  202. "SETUP: SpPtDeterminePartitionGood(): Cannot install to PCMCIA disk\n" ));
  203. return FALSE;
  204. }
  205. //
  206. // don't choose a removeable drive
  207. //
  208. #if 0
  209. //
  210. // Allow installs to removable media...
  211. //
  212. if(HardDisks[Region->DiskNumber].Characteristics & FILE_REMOVABLE_MEDIA) {
  213. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  214. "SETUP: SpPtDeterminePartitionGood(): Cannot install to a removable disk\n" ));
  215. return FALSE;
  216. }
  217. #endif
  218. //
  219. // Disallow installs to removable media or AT formatted drive, on NEC98.
  220. //
  221. if(IsNEC_98 &&
  222. ((HardDisks[Region->DiskNumber].Characteristics & FILE_REMOVABLE_MEDIA) ||
  223. (HardDisks[Region->DiskNumber].FormatType == DISK_FORMAT_TYPE_PCAT))) {
  224. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  225. "SETUP: SpPtDeterminePartitionGood(): Cannot install "
  226. "to a removable disk or AT formatted disk\n" ));
  227. return FALSE;
  228. }
  229. //
  230. // Calculate the size of the region in KB.
  231. //
  232. temp.QuadPart = UInt32x32To64(
  233. Region->SectorCount,
  234. HardDisks[Region->DiskNumber].Geometry.BytesPerSector
  235. );
  236. RegionSizeKB = RtlExtendedLargeIntegerDivide(temp,1024,&r).LowPart;
  237. //
  238. // If the region is not large enough, bail
  239. //
  240. if (RegionSizeKB < RequiredKB) {
  241. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  242. "SETUP: SpPtDeterminePartitionGood(): Partition does not "
  243. "have enough free space: required=%ld, available=%ld\n",
  244. RequiredKB,
  245. RegionSizeKB ));
  246. return FALSE;
  247. }
  248. if (!Region->PartitionedSpace) {
  249. //
  250. // can't use a partition with just free space
  251. //
  252. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  253. "SETUP: SpPtDeterminePartitionGood(): Partition does not "
  254. "have any partitioned space\n" ));
  255. return FALSE;
  256. }
  257. SystemId = SpPtGetPartitionType(Region);
  258. if (SystemId == PARTITION_ENTRY_UNUSED || IsContainerPartition(SystemId)) {
  259. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Invalid partition type(1)\n" ));
  260. return FALSE;
  261. }
  262. if(SpPtIsForeignPartition(Region)) {
  263. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  264. "SETUP: SpPtDeterminePartitionGood(): Invalid partition type(2)\n" ));
  265. return FALSE;
  266. }
  267. //
  268. // The region is a partition that we recognize.
  269. // See whether it has enough free space on it.
  270. //
  271. if(Region->AdjustedFreeSpaceKB == (ULONG)(-1)) {
  272. //
  273. // If the partition was newly created during setup
  274. // then it is acceptable (because the check to see
  275. // if it is large enough was done above).
  276. //
  277. if(Region->Filesystem != FilesystemNewlyCreated) {
  278. //
  279. // Otherwise, we don't know how much space is
  280. // on the drive so reformat will be necessary.
  281. //
  282. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  283. "SETUP: SpPtDeterminePartitionGood(): Format is necessary\n" ));
  284. return FALSE;
  285. }
  286. } else {
  287. if(Region->AdjustedFreeSpaceKB < RequiredKB) {
  288. //
  289. // If we get here, then the partition is large enough,
  290. // but there is definitely not enough free space on it.
  291. //
  292. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  293. "SETUP: SpPtDeterminePartitionGood(): Partition does not have "
  294. "enough free space: required=%ld, available=%ld\n",
  295. RequiredKB, Region->AdjustedFreeSpaceKB ));
  296. return FALSE;
  297. }
  298. }
  299. #if defined(_AMD64_) || defined(_X86_)
  300. if(!SpIsArc())
  301. {
  302. //
  303. // On an amd64/x86 machine, make sure that we have a valid primary partition
  304. // on drive 0 (C:), for booting.
  305. //
  306. if (!IsNEC_98) { // this is a standard PC/AT type machine
  307. if((systemPartitionRegion = SpPtValidSystemPartition()) == NULL) {
  308. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  309. "SETUP: SpPtDeterminePartitionGood(): Not a valid primary partition\n" ));
  310. return FALSE;
  311. }
  312. //
  313. // Make sure the system partition is active and all others are inactive.
  314. //
  315. SpPtMakeRegionActive(systemPartitionRegion);
  316. } else {
  317. //
  318. // Check existing system on target partition,
  319. // If it exists, don't choose it as target partition.
  320. //
  321. if (SpIsExistsOs(Region)) {
  322. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): OS already exists\n" ));
  323. return(FALSE);
  324. }
  325. //
  326. // All of partition is bootable on NEC98,
  327. // so we don't need to check system partition on C:.
  328. //
  329. systemPartitionRegion = Region;
  330. } //NEC98
  331. }
  332. #endif // defined(_AMD64_) || defined(_X86_)
  333. if (DisallowOtherInstalls) {
  334. PUCHAR Win9xPath;
  335. #ifdef _X86_
  336. if (SpIsWin9xMsdosSys( Region, &Win9xPath )) {
  337. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot use a partition with WIN9x installed on it\n" ));
  338. return FALSE;
  339. }
  340. #endif
  341. if (SpIsNtOnPartition(Region)) {
  342. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot use a partition with NT installed on it\n" ));
  343. return FALSE;
  344. }
  345. }
  346. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Parition is GOOD :)\n" ));
  347. return TRUE;
  348. }
  349. #if defined(_AMD64_) || defined(_X86_)
  350. BOOLEAN
  351. SpIsExistsOs(
  352. IN OUT PDISK_REGION CColonRegion
  353. )
  354. {
  355. PUCHAR NewBootCode;
  356. ULONG BootCodeSize;
  357. PUCHAR ExistingBootCode;
  358. NTSTATUS Status;
  359. PUCHAR ExistingBootCodeOs;
  360. PWSTR CColonPath;
  361. HANDLE PartitionHandle;
  362. BOOLEAN IsNtBootcode,OtherOsInstalled;
  363. UNICODE_STRING UnicodeString;
  364. OBJECT_ATTRIBUTES Obja;
  365. IO_STATUS_BLOCK IoStatusBlock;
  366. BOOLEAN BootSectorCorrupt = FALSE;
  367. ULONG BytesPerSector;
  368. ULONG ActualSectorCount, hidden_sectors, super_area_size;
  369. BOOLEAN IsExist = TRUE;
  370. ULONG MirrorSector;
  371. PWSTR *FilesToLookFor;
  372. ULONG FileCount;
  373. PWSTR NtFiles[1] = { L"NTLDR" };
  374. PWSTR ChicagoFiles[1] = { L"IO.SYS" };
  375. ExistingBootCode = NULL;
  376. BytesPerSector = HardDisks[CColonRegion->DiskNumber].Geometry.BytesPerSector;
  377. switch(CColonRegion->Filesystem) {
  378. case FilesystemNewlyCreated:
  379. //
  380. // If the filesystem is newly-created, then there is
  381. // nothing to do, because there can be no previous
  382. // operating system.
  383. //
  384. IsExist = TRUE;
  385. return( IsExist );
  386. case FilesystemNtfs:
  387. NewBootCode = PC98NtfsBootCode;
  388. BootCodeSize = sizeof(PC98NtfsBootCode);
  389. ASSERT(BootCodeSize == 8192);
  390. break;
  391. case FilesystemFat:
  392. NewBootCode = PC98FatBootCode;
  393. BootCodeSize = sizeof(PC98FatBootCode);
  394. ASSERT(BootCodeSize == 512);
  395. break;
  396. case FilesystemFat32:
  397. //
  398. // Special hackage required for Fat32 because its NT boot code
  399. // is discontiguous.
  400. //
  401. ASSERT(sizeof(Fat32BootCode) == 1536);
  402. NewBootCode = PC98Fat32BootCode;
  403. BootCodeSize = 512;
  404. break;
  405. default:
  406. ASSERT(0);
  407. IsExist = TRUE;
  408. return( IsExist );
  409. }
  410. //
  411. // Form the device path to C: and open the partition.
  412. //
  413. SpNtNameFromRegion(CColonRegion,TemporaryBuffer,sizeof(TemporaryBuffer),PartitionOrdinalCurrent);
  414. CColonPath = SpDupStringW(TemporaryBuffer);
  415. INIT_OBJA(&Obja,&UnicodeString,CColonPath);
  416. Status = ZwCreateFile(
  417. &PartitionHandle,
  418. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  419. &Obja,
  420. &IoStatusBlock,
  421. NULL,
  422. FILE_ATTRIBUTE_NORMAL,
  423. FILE_SHARE_READ | FILE_SHARE_WRITE,
  424. FILE_OPEN,
  425. FILE_SYNCHRONOUS_IO_NONALERT,
  426. NULL,
  427. 0
  428. );
  429. if (!NT_SUCCESS(Status)) {
  430. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to open the partition!\n"));
  431. ASSERT(0);
  432. IsExist = TRUE;
  433. return( IsExist );
  434. }
  435. //
  436. // Just use the existing boot code.
  437. //
  438. Status = pSpBootCodeIo(
  439. CColonPath,
  440. NULL,
  441. BootCodeSize,
  442. &ExistingBootCode,
  443. FILE_OPEN,
  444. FALSE,
  445. 0,
  446. BytesPerSector
  447. );
  448. if(CColonRegion->Filesystem == FilesystemNtfs) {
  449. MirrorSector = NtfsMirrorBootSector(PartitionHandle,BytesPerSector,NULL);
  450. }
  451. switch(CColonRegion->Filesystem) {
  452. case FilesystemFat:
  453. if(NT_SUCCESS(Status)) {
  454. //
  455. // Determine the type of operating system the existing boot sector(s) are for
  456. // and whether that os is actually installed.
  457. //
  458. SpDetermineOsTypeFromBootSector(
  459. CColonPath,
  460. ExistingBootCode,
  461. &ExistingBootCodeOs,
  462. &IsNtBootcode,
  463. &OtherOsInstalled,
  464. CColonRegion->DriveLetter
  465. );
  466. if (OtherOsInstalled == TRUE) {
  467. IsExist = TRUE;
  468. } else if (IsNtBootcode == TRUE) {
  469. wcscpy(TemporaryBuffer,CColonPath);
  470. FilesToLookFor = NtFiles;
  471. FileCount = ELEMENT_COUNT(NtFiles);
  472. if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) {
  473. IsExist = TRUE;
  474. } else {
  475. IsExist = FALSE;
  476. }
  477. } else {
  478. IsExist = FALSE;
  479. }
  480. } else {
  481. IsExist = TRUE;
  482. }
  483. break;
  484. case FilesystemFat32:
  485. wcscpy(TemporaryBuffer,CColonPath);
  486. FilesToLookFor = NtFiles;
  487. FileCount = ELEMENT_COUNT(NtFiles);
  488. if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) {
  489. IsExist = TRUE;
  490. }
  491. FilesToLookFor = ChicagoFiles;
  492. FileCount = ELEMENT_COUNT(ChicagoFiles);
  493. if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) {
  494. wcscpy(TemporaryBuffer, CColonPath);
  495. SpConcatenatePaths(TemporaryBuffer, L"IO.SYS");
  496. if(SpHasMZHeader(TemporaryBuffer)) {
  497. IsExist = TRUE;
  498. } else {
  499. IsExist = FALSE;
  500. }
  501. } else {
  502. IsExist = FALSE;
  503. }
  504. break;
  505. case FilesystemNtfs:
  506. wcscpy(TemporaryBuffer,CColonPath);
  507. FilesToLookFor = NtFiles;
  508. FileCount = ELEMENT_COUNT(NtFiles);
  509. if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) {
  510. IsExist = TRUE;
  511. } else {
  512. IsExist = FALSE;
  513. }
  514. break;
  515. default:
  516. ASSERT(0);
  517. IsExist = TRUE;
  518. }
  519. SpMemFree(CColonPath);
  520. ZwClose (PartitionHandle);
  521. return( IsExist );
  522. }
  523. #endif // defined(_AMD64_) || defined(_X86_)
  524. BOOLEAN
  525. SpPtDoPartitionSelection(
  526. IN OUT PDISK_REGION *Region,
  527. IN PWSTR RegionDescription,
  528. IN PVOID SifHandle,
  529. IN BOOLEAN Unattended,
  530. IN PWSTR SetupSourceDevicePath,
  531. IN PWSTR DirectoryOnSetupSource,
  532. IN BOOLEAN RemoteBootRepartition,
  533. OUT PBOOLEAN Win9xInstallationPresent
  534. )
  535. {
  536. ULONG RequiredKB;
  537. ULONG TempKB;
  538. UCHAR SystemId;
  539. BOOLEAN NewlyCreated;
  540. ULONG PreconfirmFormatId;
  541. ULONG ValidKeys1[2] = { ASCI_CR ,0 };
  542. ULONG ValidKeys2[2] = { ASCI_ESC,0 };
  543. ULONG Mnemonics1[2] = { MnemonicContinueSetup, 0 };
  544. ULONG Mnemonics2[2] = { 0,0 };
  545. ULONG RegionSizeKB;
  546. ULONG r;
  547. #if defined(_AMD64_) || defined(_X86_)
  548. PDISK_REGION systemPartitionRegion;
  549. #endif // defined(_AMD64_) || defined(_X86_)
  550. BOOLEAN AllowNtfsOptions;
  551. BOOLEAN AllowFatOptions;
  552. ULONG selection;
  553. NTSTATUS Status;
  554. ULONG Count;
  555. PWSTR p;
  556. PWSTR RegionDescr;
  557. PDISK_REGION region = *Region;
  558. LARGE_INTEGER temp;
  559. BOOLEAN AllowFormatting;
  560. BOOLEAN QuickFormat = FALSE, OtherOSOnPartition;
  561. PSTR Win9xPath = NULL;
  562. PWCHAR Win9xPathW = NULL;
  563. if (Win9xInstallationPresent) {
  564. *Win9xInstallationPresent = FALSE;
  565. }
  566. #if defined(REMOTE_BOOT)
  567. //
  568. // If this is a remote boot setup on a diskless machine, skip partition
  569. // selection (note that we check the RemoteBootSetup global flag, not
  570. // the passed-in RemoteBootRepartition flag).
  571. //
  572. if (RemoteBootSetup && (HardDiskCount == 0)) {
  573. return TRUE;
  574. }
  575. #endif // defined(REMOTE_BOOT)
  576. //
  577. // Assume that if we need to format the drive, that
  578. // the user needs to confirm.
  579. //
  580. PreconfirmFormatId = 0;
  581. NewlyCreated = FALSE;
  582. AllowNtfsOptions = TRUE;
  583. AllowFatOptions = TRUE;
  584. //
  585. // Disallow installation to PCMCIA disks.
  586. //
  587. if(HardDisks[region->DiskNumber].PCCard) {
  588. SpDisplayScreen(SP_SCRN_CANT_INSTALL_ON_PCMCIA,3,HEADER_HEIGHT+1);
  589. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  590. SpWaitValidKey(ValidKeys1,NULL,NULL);
  591. return(FALSE);
  592. }
  593. //
  594. // Disallow installation to non-platform disk
  595. // on clean installs
  596. //
  597. // AMD64/X86 - Installs only to MBR disks
  598. // IA64 - Installs only to GPT disks
  599. //
  600. if (SPPT_GET_DISK_TYPE(region->DiskNumber) != SPPT_DEFAULT_DISK_STYLE) {
  601. SpDisplayScreen(SP_SCRN_INVALID_INSTALLPART, 3, HEADER_HEIGHT+1);
  602. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  603. SpWaitValidKey(ValidKeys1,NULL,NULL);
  604. return FALSE;
  605. }
  606. //
  607. // Make sure we can see the disk from the firmware/bios.
  608. // If we can get an arc name for the disk, assume it's ok.
  609. // Otherwise, it ain't.
  610. //
  611. if(p = SpNtToArc(HardDisks[region->DiskNumber].DevicePath,PrimaryArcPath)) {
  612. #if defined(_AMD64_) || defined(_X86_)
  613. //
  614. // On amd64/x86 we don't allow disks that have LUN greater than 0
  615. //
  616. SpStringToLower( p );
  617. if( wcsstr( p, L"scsi(" ) &&
  618. wcsstr( p, L")rdisk(" ) ) {
  619. if( wcsstr( p, L")rdisk(0)" ) == NULL ) {
  620. //
  621. // Tell the user that we can't install to that disk.
  622. //
  623. SpDisplayScreen(SP_SCRN_DISK_NOT_INSTALLABLE_LUN_NOT_SUPPORTED,
  624. 3,
  625. HEADER_HEIGHT+1);
  626. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  627. SpWaitValidKey(ValidKeys1,NULL,NULL);
  628. SpMemFree(p);
  629. return(FALSE);
  630. }
  631. }
  632. #endif // defined(_AMD64_) || defined(_X86_)
  633. SpMemFree(p);
  634. } else {
  635. //
  636. // Tell the user that we can't install to that disk.
  637. //
  638. SpDisplayScreen(SP_SCRN_DISK_NOT_INSTALLABLE,3,HEADER_HEIGHT+1);
  639. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  640. SpWaitValidKey(ValidKeys1,NULL,NULL);
  641. return(FALSE);
  642. }
  643. //
  644. // Disallow installation of Personal onto dynamic disks
  645. // since dynamic disks feature is not available on Personal
  646. //
  647. if (SpIsProductSuite(VER_SUITE_PERSONAL) &&
  648. SpPtnIsDynamicDisk(region->DiskNumber)) {
  649. SpDisplayScreen(SP_NO_DYNAMIC_DISK_INSTALL,
  650. 3,
  651. HEADER_HEIGHT + 1);
  652. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  653. SP_STAT_ENTER_EQUALS_CONTINUE,
  654. 0);
  655. SpWaitValidKey(ValidKeys1, NULL, NULL);
  656. return FALSE;
  657. }
  658. //
  659. // Fetch the amount of free space required on the windows nt drive.
  660. //
  661. SpFetchDiskSpaceRequirements( SifHandle,
  662. region->BytesPerCluster,
  663. &RequiredKB,
  664. NULL);
  665. //
  666. // For remote install, we have not yet copied ~LS, so add that space
  667. // in also.
  668. //
  669. if (RemoteInstallSetup) {
  670. SpFetchTempDiskSpaceRequirements( SifHandle,
  671. region->BytesPerCluster,
  672. &TempKB,
  673. NULL);
  674. RequiredKB += TempKB;
  675. }
  676. //
  677. // Calculate the size of the region in KB.
  678. //
  679. temp.QuadPart = UInt32x32To64(
  680. region->SectorCount,
  681. HardDisks[region->DiskNumber].Geometry.BytesPerSector
  682. );
  683. RegionSizeKB = RtlExtendedLargeIntegerDivide(temp,1024,&r).LowPart;
  684. //
  685. // If the region is not large enough, tell the user.
  686. //
  687. if(RegionSizeKB < RequiredKB) {
  688. SpStartScreen(
  689. SP_SCRN_REGION_TOO_SMALL,
  690. 3,
  691. HEADER_HEIGHT+1,
  692. FALSE,
  693. FALSE,
  694. DEFAULT_ATTRIBUTE,
  695. (RequiredKB / 1024) + 1
  696. );
  697. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  698. SpWaitValidKey(ValidKeys1,NULL,NULL);
  699. return(FALSE);
  700. }
  701. if(region->PartitionedSpace) {
  702. if (SpPtIsForeignPartition(region)) {
  703. SpStartScreen(
  704. SP_SCRN_FOREIGN_PARTITION,
  705. 3,
  706. HEADER_HEIGHT+1,
  707. FALSE,
  708. FALSE,
  709. DEFAULT_ATTRIBUTE
  710. );
  711. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  712. SP_STAT_ENTER_EQUALS_CONTINUE,
  713. 0);
  714. SpWaitValidKey(ValidKeys1,
  715. NULL,
  716. NULL);
  717. return FALSE;
  718. }
  719. if (!RemoteBootRepartition) {
  720. //
  721. // The region is a partition that we recognize.
  722. // See whether it has enough free space on it.
  723. //
  724. if(region->AdjustedFreeSpaceKB == (ULONG)(-1)) {
  725. //
  726. // If the partition was newly created during setup
  727. // then it acceptable (because the check to see
  728. // if it is large enough was done above).
  729. //
  730. if(region->Filesystem != FilesystemNewlyCreated) {
  731. //
  732. // Otherwise, we don't know how much space is
  733. // on the drive so reformat will be necessary.
  734. //
  735. PreconfirmFormatId = SP_SCRN_UNKNOWN_FREESPACE;
  736. }
  737. } else {
  738. if(region->AdjustedFreeSpaceKB < RequiredKB) {
  739. //
  740. // If we get here, then the partition is large enough,
  741. // but there is definitely not enough free space on it.
  742. //
  743. CLEAR_CLIENT_SCREEN();
  744. SpDisplayStatusText(SP_STAT_EXAMINING_DISK_CONFIG,DEFAULT_STATUS_ATTRIBUTE);
  745. //
  746. // We check here to see if this partition is the partition we
  747. // booted from (in floppyless case on amd64/x86).
  748. //
  749. // Also make sure we aren't trying to format the drive w/
  750. // local source.
  751. //
  752. // If so, then the
  753. // user can't format, and we give a generic 'disk too full'
  754. // error.
  755. //
  756. if( ( region->IsLocalSource )
  757. #if defined(_AMD64_) || defined(_X86_)
  758. || ( (IsFloppylessBoot) &&
  759. (region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL))) )
  760. #endif // defined(_AMD64_) || defined(_X86_)
  761. ) {
  762. SpStartScreen(
  763. SP_SCRN_INSUFFICIENT_FREESPACE_NO_FMT,
  764. 3,
  765. HEADER_HEIGHT+1,
  766. FALSE,
  767. FALSE,
  768. DEFAULT_ATTRIBUTE,
  769. (RequiredKB / 1024) + 1
  770. );
  771. SpDisplayStatusOptions(
  772. DEFAULT_STATUS_ATTRIBUTE,
  773. SP_STAT_ENTER_EQUALS_CONTINUE,
  774. 0
  775. );
  776. SpWaitValidKey(ValidKeys1,NULL,NULL);
  777. return FALSE;
  778. }
  779. //
  780. // To use the selected partition, we will have to reformat.
  781. // Inform the user of that, and let him decide to bail
  782. // right here if this is not acceptable.
  783. //
  784. PreconfirmFormatId = SP_SCRN_INSUFFICIENT_FREESPACE;
  785. }
  786. }
  787. if(PreconfirmFormatId) {
  788. //
  789. // Do a 'preconfirmation' that the user really wants
  790. // to reformat this drive. We'll confirm again later
  791. // before actually reformatting anything.
  792. //
  793. SpStartScreen(
  794. PreconfirmFormatId,
  795. 3,
  796. HEADER_HEIGHT+1,
  797. FALSE,
  798. FALSE,
  799. DEFAULT_ATTRIBUTE,
  800. (RequiredKB / 1024) + 1
  801. );
  802. SpDisplayStatusOptions(
  803. DEFAULT_STATUS_ATTRIBUTE,
  804. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  805. SP_STAT_ESC_EQUALS_CANCEL,
  806. 0
  807. );
  808. if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics1) == ASCI_ESC) {
  809. //
  810. // User decided to select a different partition.
  811. //
  812. return(FALSE);
  813. } // otherwise user decided to use the partition anyway.
  814. }
  815. }
  816. } else {
  817. //
  818. // The region is a free space. Attempt to create a partition
  819. // in the space. The create routine will tell us whether this
  820. // was successful. If it was not successful, then the create routine
  821. // will have already informed the user of why.
  822. //
  823. PDISK_REGION p;
  824. if(!SpPtDoCreate(region,&p,TRUE,0,0,TRUE)) {
  825. return(FALSE);
  826. }
  827. //
  828. // If we just created an extended partition and a logical drive,
  829. // we'll need to switch regions -- Region points to the extended partition
  830. // region, but we want to point to the logical drive region.
  831. //
  832. ASSERT(p);
  833. region = p;
  834. *Region = p;
  835. NewlyCreated = TRUE;
  836. }
  837. if(NewlyCreated) {
  838. SpPtRegionDescription(
  839. &PartitionedDisks[region->DiskNumber],
  840. region,
  841. TemporaryBuffer,
  842. sizeof(TemporaryBuffer)
  843. );
  844. RegionDescr = SpDupStringW(TemporaryBuffer);
  845. } else {
  846. RegionDescr = SpDupStringW(RegionDescription);
  847. }
  848. OtherOSOnPartition = FALSE;
  849. if( SpIsNtOnPartition( region ) )
  850. OtherOSOnPartition = TRUE;
  851. #if defined(_AMD64_) || defined(_X86_)
  852. if(!SpIsArc())
  853. {
  854. //
  855. // On an amd64/x86 machine, make sure that we have a valid primary partition
  856. // on drive 0 (C:), for booting.
  857. //
  858. if (!IsNEC_98) { //NEC98
  859. if((systemPartitionRegion = SpPtValidSystemPartition()) == NULL) {
  860. SpStartScreen(
  861. SP_SCRN_NO_VALID_C_COLON,
  862. 3,
  863. HEADER_HEIGHT+1,
  864. FALSE,
  865. FALSE,
  866. DEFAULT_ATTRIBUTE,
  867. HardDisks[SpDetermineDisk0()].Description
  868. );
  869. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  870. SpWaitValidKey(ValidKeys1,NULL,NULL);
  871. SpMemFree(RegionDescr);
  872. return(FALSE);
  873. }
  874. //
  875. // Make sure the system partition is active and all others are inactive.
  876. //
  877. SpPtMakeRegionActive(systemPartitionRegion);
  878. //
  879. // Warn user about win9x installations on same partition
  880. //
  881. #if defined(_X86_)
  882. if( !OtherOSOnPartition && SpIsWin9xMsdosSys( systemPartitionRegion, &Win9xPath )){
  883. Win9xPathW = SpToUnicode(Win9xPath);
  884. if(SpIsWin4Dir(region, Win9xPathW)) {
  885. OtherOSOnPartition = TRUE;
  886. if (Win9xInstallationPresent) {
  887. *Win9xInstallationPresent = TRUE;
  888. }
  889. }
  890. SpMemFree(Win9xPathW);
  891. }
  892. if(Win9xPath) {
  893. SpMemFree(Win9xPath);
  894. }
  895. #endif // defined(_X86_)
  896. } else {
  897. //
  898. // All of partition is bootable on NEC98,
  899. // so we don't need to check system partition on C:.
  900. //
  901. systemPartitionRegion = *Region;
  902. } //NEC98
  903. }
  904. #endif // defined(_AMD64_) || defined(_X86_)
  905. //
  906. // Display common warning for other OS on partition
  907. //
  908. if( OtherOSOnPartition && !Unattended ){
  909. SpDisplayScreen(SP_SCRN_OTHEROS_ON_PARTITION,3,HEADER_HEIGHT+1);
  910. SpDisplayStatusOptions(
  911. DEFAULT_STATUS_ATTRIBUTE,
  912. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  913. SP_STAT_ESC_EQUALS_CANCEL,
  914. 0
  915. );
  916. if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics1) == ASCI_ESC) {
  917. return(FALSE);
  918. }
  919. //
  920. // Remove the boot sets which are already present for
  921. // this partition in boot.ini, if any. This aids in
  922. // disabling the other OSes installed on the same
  923. // partition
  924. //
  925. //
  926. // NOTE : We want to really think about enforcing
  927. // single installs on a partition, so for the time
  928. // being disable it
  929. //
  930. // SpPtDeleteBootSetsForRegion(region);
  931. }
  932. //
  933. // At this point, everything is fine, so commit any
  934. // partition changes the user may have made.
  935. // This won't return if an error occurs while updating the disk.
  936. //
  937. SpPtDoCommitChanges();
  938. //
  939. // Attempt to grow the partition the system will be on
  940. // if necessary.
  941. //
  942. if(PreInstall
  943. && Unattended
  944. && (p = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,SIF_EXTENDOEMPART,0))
  945. && (Count = SpStringToLong(p,NULL,10))) {
  946. //
  947. // 1 means size it maximally, any other non-0 number means
  948. // extend by that many MB
  949. //
  950. ExtendingOemPartition = SpPtExtend(region,(Count == 1) ? 0 : Count);
  951. }
  952. #if defined(_AMD64_) || defined(_X86_)
  953. if(!SpIsArc())
  954. {
  955. //
  956. // On an amd64/x86 machine, see whether we need to format C: and if so,
  957. // go ahead and do it. If the system is going on C:, then don't
  958. // bother with this here because it will be covered in the options
  959. // for the target NT partition.
  960. //
  961. if(systemPartitionRegion != region) {
  962. PWSTR SysPartRegionDescr;
  963. BOOLEAN bValidCColon;
  964. SpPtRegionDescription(
  965. &PartitionedDisks[systemPartitionRegion->DiskNumber],
  966. systemPartitionRegion,
  967. TemporaryBuffer,
  968. sizeof(TemporaryBuffer)
  969. );
  970. SysPartRegionDescr = SpDupStringW(TemporaryBuffer);
  971. bValidCColon = SpPtValidateCColonFormat(SifHandle,
  972. SysPartRegionDescr,
  973. systemPartitionRegion,
  974. FALSE,
  975. SetupSourceDevicePath,
  976. DirectoryOnSetupSource);
  977. SpMemFree(SysPartRegionDescr);
  978. if(!bValidCColon) {
  979. SpMemFree(RegionDescr);
  980. return(FALSE);
  981. }
  982. }
  983. }else
  984. #endif // defined(_AMD64_) || defined(_X86_)
  985. {
  986. //
  987. // If we are going to install on the system partition,
  988. // issue a special warning because it can't be converted to ntfs.
  989. //
  990. if((region->IsSystemPartition == 2) && !Unattended) {
  991. ULONG ValidKeys[3] = { ASCI_CR, ASCI_ESC, 0 };
  992. SpDisplayScreen(SP_SCRN_INSTALL_ON_SYSPART,3,HEADER_HEIGHT+1);
  993. SpDisplayStatusOptions(
  994. DEFAULT_STATUS_ATTRIBUTE,
  995. SP_STAT_ENTER_EQUALS_CONTINUE,
  996. SP_STAT_ESC_EQUALS_CANCEL,
  997. 0
  998. );
  999. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  1000. SpMemFree(RegionDescr);
  1001. return(FALSE);
  1002. }
  1003. AllowNtfsOptions = FALSE;
  1004. }
  1005. }
  1006. if( SpPtSectorCountToMB( &(HardDisks[region->DiskNumber]),
  1007. region->SectorCount ) > 32*1024 ) {
  1008. //
  1009. // If the partition size is greater than 32 GB, then we don't allow Fat formatting,
  1010. // because Fat32 does not support partitions that are that big.
  1011. //
  1012. AllowFatOptions = FALSE;
  1013. }
  1014. //
  1015. // Present formatting/conversion options to the user.
  1016. //
  1017. //
  1018. // If the partition was newly created, the only option is
  1019. // to format the partition. Ditto if the partition is
  1020. // a 'bad' partition -- damaged, can't tell free space, etc.
  1021. //
  1022. if(NewlyCreated
  1023. || (region->Filesystem < FilesystemFirstKnown)
  1024. || (region->FreeSpaceKB == (ULONG)(-1))
  1025. || (region->AdjustedFreeSpaceKB < RequiredKB)
  1026. || RemoteBootRepartition)
  1027. {
  1028. if (RemoteBootRepartition) {
  1029. //
  1030. // For remote boot we always quick format as NTFS without
  1031. // prompting the user.
  1032. //
  1033. selection = FormatOptionNtfs;
  1034. QuickFormat = TRUE;
  1035. } else {
  1036. if(NewlyCreated) {
  1037. SpStartScreen(
  1038. SP_SCRN_FORMAT_NEW_PART,
  1039. 3,
  1040. HEADER_HEIGHT+1,
  1041. FALSE,
  1042. FALSE,
  1043. DEFAULT_ATTRIBUTE,
  1044. HardDisks[region->DiskNumber].Description
  1045. );
  1046. } else if(region->Filesystem == FilesystemNewlyCreated) {
  1047. SpDisplayScreen(SP_SCRN_FORMAT_NEW_PART2,3,HEADER_HEIGHT+1);
  1048. } else {
  1049. SpStartScreen(
  1050. SP_SCRN_FORMAT_BAD_PART,
  1051. 3,
  1052. HEADER_HEIGHT+1,
  1053. FALSE,
  1054. FALSE,
  1055. DEFAULT_ATTRIBUTE,
  1056. RegionDescr,
  1057. HardDisks[region->DiskNumber].Description
  1058. );
  1059. }
  1060. selection = SpFormattingOptions(
  1061. AllowFatOptions,
  1062. AllowNtfsOptions,
  1063. FALSE,
  1064. FALSE,
  1065. TRUE
  1066. );
  1067. }
  1068. switch(selection) {
  1069. case FormatOptionCancel:
  1070. SpMemFree(RegionDescr);
  1071. return(FALSE);
  1072. default:
  1073. //
  1074. // Format the partition right here and now.
  1075. //
  1076. if ((selection == FormatOptionFatQuick) || (selection == FormatOptionNtfsQuick))
  1077. QuickFormat = TRUE;
  1078. Status = SpDoFormat(
  1079. RegionDescr,
  1080. region,
  1081. ((selection == FormatOptionNtfs) || (selection == FormatOptionNtfsQuick)) ?
  1082. FilesystemNtfs : FilesystemFat,
  1083. FALSE,
  1084. TRUE,
  1085. QuickFormat,
  1086. SifHandle,
  1087. 0, // default cluster size
  1088. SetupSourceDevicePath,
  1089. DirectoryOnSetupSource
  1090. );
  1091. SpMemFree(RegionDescr);
  1092. return(NT_SUCCESS(Status));
  1093. }
  1094. }
  1095. //
  1096. // The partition is acceptable as-is.
  1097. // Options are to reformat to fat or ntfs, or to leave as-is.
  1098. // If it's FAT, converting to ntfs is an option
  1099. // unless we're installing onto an ARC system partition.
  1100. //
  1101. SpStartScreen(
  1102. SP_SCRN_FS_OPTIONS,
  1103. 3,
  1104. HEADER_HEIGHT+1,
  1105. FALSE,
  1106. FALSE,
  1107. DEFAULT_ATTRIBUTE,
  1108. RegionDescr,
  1109. HardDisks[region->DiskNumber].Description
  1110. );
  1111. //
  1112. // If this is a winnt installation, don't want to let the user
  1113. // reformat the local source partition!
  1114. //
  1115. // Also, don't let them reformat if this is the partition we booted
  1116. // off of (in amd64/x86 floppyless boot case).
  1117. //
  1118. AllowFormatting = !region->IsLocalSource;
  1119. #if defined(_AMD64_) || defined(_X86_)
  1120. if(AllowFormatting) {
  1121. AllowFormatting = !(IsFloppylessBoot &&
  1122. (region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL))));
  1123. }
  1124. #endif // defined(_AMD64_) || defined(_X86_)
  1125. selection = SpFormattingOptions(
  1126. (BOOLEAN)(AllowFormatting ? AllowFatOptions : FALSE),
  1127. (BOOLEAN)(AllowFormatting ? AllowNtfsOptions : FALSE),
  1128. (BOOLEAN)(AllowNtfsOptions && (BOOLEAN)(region->Filesystem != FilesystemNtfs)),
  1129. TRUE,
  1130. TRUE
  1131. );
  1132. switch(selection) {
  1133. case FormatOptionDoNothing:
  1134. SpMemFree(RegionDescr);
  1135. return(TRUE);
  1136. case FormatOptionFat:
  1137. case FormatOptionFatQuick:
  1138. case FormatOptionNtfs:
  1139. case FormatOptionNtfsQuick:
  1140. //
  1141. // Confirm the format.
  1142. //
  1143. if( ( region->Filesystem != FilesystemFat ) ||
  1144. ( ( region->Filesystem == FilesystemFat ) &&
  1145. ( ( Count = SpGetNumberOfCompressedDrives( region ) ) == 0 ) )
  1146. ) {
  1147. SpStartScreen(
  1148. SP_SCRN_CONFIRM_FORMAT,
  1149. 3,
  1150. HEADER_HEIGHT+1,
  1151. FALSE,
  1152. FALSE,
  1153. DEFAULT_ATTRIBUTE,
  1154. RegionDescr,
  1155. HardDisks[region->DiskNumber].Description
  1156. );
  1157. } else {
  1158. SpStartScreen(
  1159. SP_SCRN_CONFIRM_FORMAT_COMPRESSED,
  1160. 3,
  1161. HEADER_HEIGHT+1,
  1162. FALSE,
  1163. FALSE,
  1164. DEFAULT_ATTRIBUTE,
  1165. RegionDescr,
  1166. HardDisks[region->DiskNumber].Description,
  1167. Count
  1168. );
  1169. }
  1170. SpDisplayStatusOptions(
  1171. DEFAULT_STATUS_ATTRIBUTE,
  1172. SP_STAT_F_EQUALS_FORMAT,
  1173. SP_STAT_ESC_EQUALS_CANCEL,
  1174. 0
  1175. );
  1176. Mnemonics2[0] = MnemonicFormat;
  1177. if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics2) == ASCI_ESC) {
  1178. SpMemFree(RegionDescr);
  1179. return(FALSE);
  1180. }
  1181. if ((selection == FormatOptionNtfsQuick) || (selection == FormatOptionFatQuick))
  1182. QuickFormat = TRUE;
  1183. //
  1184. // Format the partition right here and now.
  1185. //
  1186. Status = SpDoFormat(
  1187. RegionDescr,
  1188. region,
  1189. ((selection == FormatOptionNtfs) || (selection == FormatOptionNtfsQuick)) ?
  1190. FilesystemNtfs : FilesystemFat,
  1191. FALSE,
  1192. TRUE,
  1193. QuickFormat,
  1194. SifHandle,
  1195. 0, // default cluster size
  1196. SetupSourceDevicePath,
  1197. DirectoryOnSetupSource
  1198. );
  1199. SpMemFree(RegionDescr);
  1200. return(NT_SUCCESS(Status));
  1201. case FormatOptionCancel:
  1202. SpMemFree(RegionDescr);
  1203. return(FALSE);
  1204. case FormatOptionConvertToNtfs:
  1205. if(!UnattendedOperation) {
  1206. //
  1207. // Confirm that the user really wants to do this.
  1208. //
  1209. if( ( Count = SpGetNumberOfCompressedDrives( region ) ) == 0 ) {
  1210. SpStartScreen(
  1211. SP_SCRN_CONFIRM_CONVERT,
  1212. 3,
  1213. HEADER_HEIGHT+1,
  1214. FALSE,
  1215. FALSE,
  1216. DEFAULT_ATTRIBUTE,
  1217. RegionDescr,
  1218. HardDisks[region->DiskNumber].Description
  1219. );
  1220. } else {
  1221. SpStartScreen(
  1222. SP_SCRN_CONFIRM_CONVERT_COMPRESSED,
  1223. 3,
  1224. HEADER_HEIGHT+1,
  1225. FALSE,
  1226. FALSE,
  1227. DEFAULT_ATTRIBUTE,
  1228. RegionDescr,
  1229. HardDisks[region->DiskNumber].Description,
  1230. Count
  1231. );
  1232. }
  1233. SpDisplayStatusOptions(
  1234. DEFAULT_STATUS_ATTRIBUTE,
  1235. SP_STAT_C_EQUALS_CONVERT,
  1236. SP_STAT_ESC_EQUALS_CANCEL,
  1237. 0
  1238. );
  1239. Mnemonics2[0] = MnemonicConvert;
  1240. if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics2) == ASCI_ESC) {
  1241. SpMemFree(RegionDescr);
  1242. return(FALSE);
  1243. }
  1244. }
  1245. //
  1246. // Remember that we need to convert the NT drive to NTFS.
  1247. //
  1248. ConvertNtVolumeToNtfs = TRUE;
  1249. SpMemFree(RegionDescr);
  1250. return(TRUE);
  1251. }
  1252. //
  1253. // Should never get here.
  1254. //
  1255. SpMemFree(RegionDescr);
  1256. ASSERT(FALSE);
  1257. return(FALSE);
  1258. }
  1259. ULONG
  1260. SpFormattingOptions(
  1261. IN BOOLEAN AllowFatFormat,
  1262. IN BOOLEAN AllowNtfsFormat,
  1263. IN BOOLEAN AllowConvertNtfs,
  1264. IN BOOLEAN AllowDoNothing,
  1265. IN BOOLEAN AllowEscape
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. Present a menu of formatting options and allow the user to choose
  1270. among them. The text describing the menu must already be present
  1271. on-screen.
  1272. The user may also press escape to indicate that he wants to select
  1273. a different partition.
  1274. Arguments:
  1275. AllowFatFormat - TRUE if the option to format the partition to
  1276. FAT should be presented in the menu.
  1277. AllowNtfsFormat - TRUE if the option to format the partition to
  1278. NTFS should be presented in the menu.
  1279. AllowConvertNtfs - TRUE if the option to convert the partition to
  1280. NTFS should be presented in the menu.
  1281. AllowDoNothing - TRUE if the option to leave the partition as-is
  1282. should be presented in the menu.
  1283. Return Value:
  1284. Value from the FormatOptions enum indicating the outcome of the
  1285. user's interaction with the menu, which will be FormatOptionCancel
  1286. if the user pressed escape.
  1287. --*/
  1288. {
  1289. ULONG FatFormatOption = (ULONG)(-1);
  1290. ULONG NtfsFormatOption = (ULONG)(-1);
  1291. ULONG FatQFormatOption = (ULONG)(-1);
  1292. ULONG NtfsQFormatOption = (ULONG)(-1);
  1293. ULONG ConvertNtfsOption = (ULONG)(-1);
  1294. ULONG DoNothingOption = (ULONG)(-1);
  1295. ULONG OptionCount = 0;
  1296. PVOID Menu;
  1297. WCHAR FatQFormatText[128];
  1298. WCHAR NtfsQFormatText[128];
  1299. WCHAR FatFormatText[128];
  1300. WCHAR NtfsFormatText[128];
  1301. WCHAR ConvertNtfsText[128];
  1302. WCHAR DoNothingText[128];
  1303. WCHAR QuickText[128];
  1304. ULONG MaxLength;
  1305. ULONG Key;
  1306. ULONG_PTR Selection;
  1307. BOOLEAN Chosen;
  1308. ULONG ValidKeys[4] = { ASCI_CR, KEY_F3, 0, 0 };
  1309. if (AllowEscape) {
  1310. ValidKeys[2] = ASCI_ESC;
  1311. }
  1312. //
  1313. // If the only thing we're allowed to do is nothing, just return.
  1314. //
  1315. if(!AllowFatFormat
  1316. && !AllowNtfsFormat
  1317. && !AllowConvertNtfs
  1318. && AllowDoNothing) {
  1319. return(FormatOptionDoNothing);
  1320. }
  1321. //
  1322. // The FileSystem entry might be in the unattend section if we're
  1323. // in unattend mode. if we aren't in unattend mode, it may be in
  1324. // the data section.
  1325. //
  1326. // If we fail to find it in either place, then if we're unattended
  1327. // we return DoNothing. If we're attended, fall through to the attended
  1328. // case.
  1329. //
  1330. if( ( UnattendedSifHandle && (Menu = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,L"Filesystem",0)) ) ||
  1331. ( WinntSifHandle && (Menu = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,L"Filesystem",0)) ) ) {
  1332. if(!_wcsicmp(Menu,L"FormatFat") && AllowFatFormat) {
  1333. return(FormatOptionFat);
  1334. }
  1335. if(!_wcsicmp(Menu,L"FormatNtfs") && AllowNtfsFormat) {
  1336. return(FormatOptionNtfs);
  1337. }
  1338. if(!_wcsicmp(Menu,L"ConvertNtfs") && AllowConvertNtfs) {
  1339. return(FormatOptionConvertToNtfs);
  1340. }
  1341. if( (!_wcsicmp(Menu,L"ConvertNtfs")) &&
  1342. (!AllowConvertNtfs) &&
  1343. (AllowDoNothing) ) {
  1344. return(FormatOptionDoNothing);
  1345. }
  1346. if(!_wcsicmp(Menu,L"LeaveAlone") && AllowDoNothing) {
  1347. return(FormatOptionDoNothing);
  1348. }
  1349. } else {
  1350. if(UnattendedOperation && AllowDoNothing) {
  1351. return(FormatOptionDoNothing);
  1352. }
  1353. }
  1354. ASSERT(AllowFatFormat || AllowNtfsFormat || AllowConvertNtfs || AllowDoNothing);
  1355. SpFormatMessage(FatFormatText ,sizeof(FatFormatText),SP_TEXT_FAT_FORMAT);
  1356. SpFormatMessage(NtfsFormatText ,sizeof(FatFormatText),SP_TEXT_NTFS_FORMAT);
  1357. SpFormatMessage(ConvertNtfsText,sizeof(FatFormatText),SP_TEXT_NTFS_CONVERT);
  1358. SpFormatMessage(DoNothingText ,sizeof(FatFormatText),SP_TEXT_DO_NOTHING);
  1359. SpFormatMessage(QuickText, sizeof(QuickText), SP_TEXT_FORMAT_QUICK);
  1360. wcscpy(FatQFormatText, FatFormatText);
  1361. wcscat(FatQFormatText, QuickText);
  1362. wcscpy(NtfsQFormatText, NtfsFormatText);
  1363. wcscat(NtfsQFormatText, QuickText);
  1364. //
  1365. // Determine maximum length of the option strings.
  1366. //
  1367. MaxLength = wcslen(FatFormatText);
  1368. MaxLength = max(wcslen(NtfsFormatText), MaxLength);
  1369. MaxLength = max(wcslen(ConvertNtfsText), MaxLength);
  1370. MaxLength = max(wcslen(DoNothingText), MaxLength);
  1371. MaxLength = max(wcslen(FatQFormatText), MaxLength);
  1372. MaxLength = max(wcslen(NtfsQFormatText), MaxLength);
  1373. Menu = SpMnCreate(5,
  1374. NextMessageTopLine + 1,
  1375. VideoVars.ScreenWidth - 5,
  1376. 6);
  1377. //
  1378. // If we cannot create menu then cancel the formatting
  1379. // request itself
  1380. //
  1381. if (!Menu) {
  1382. return FormatOptionCancel;
  1383. }
  1384. #ifdef NEW_PARTITION_ENGINE
  1385. if(AllowNtfsFormat) {
  1386. NtfsQFormatOption = OptionCount++;
  1387. SpMnAddItem(Menu,
  1388. NtfsQFormatText,
  1389. 5,
  1390. MaxLength,
  1391. TRUE,
  1392. NtfsQFormatOption);
  1393. }
  1394. if(AllowFatFormat) {
  1395. FatQFormatOption = OptionCount++;
  1396. SpMnAddItem(Menu,
  1397. FatQFormatText,
  1398. 5,
  1399. MaxLength,
  1400. TRUE,
  1401. FatQFormatOption);
  1402. }
  1403. #endif
  1404. if(AllowNtfsFormat) {
  1405. NtfsFormatOption = OptionCount++;
  1406. SpMnAddItem(Menu,
  1407. NtfsFormatText,
  1408. 5,
  1409. MaxLength,
  1410. TRUE,
  1411. NtfsFormatOption);
  1412. }
  1413. if(AllowFatFormat) {
  1414. FatFormatOption = OptionCount++;
  1415. SpMnAddItem(Menu,
  1416. FatFormatText,
  1417. 5,
  1418. MaxLength,
  1419. TRUE,
  1420. FatFormatOption);
  1421. }
  1422. if(AllowConvertNtfs) {
  1423. ConvertNtfsOption = OptionCount++;
  1424. SpMnAddItem(Menu,
  1425. ConvertNtfsText,
  1426. 5,
  1427. MaxLength,
  1428. TRUE,
  1429. ConvertNtfsOption);
  1430. }
  1431. if(AllowDoNothing) {
  1432. DoNothingOption = OptionCount++;
  1433. SpMnAddItem(Menu,
  1434. DoNothingText,
  1435. 5,
  1436. MaxLength,
  1437. TRUE,
  1438. DoNothingOption);
  1439. }
  1440. //
  1441. // Determine the default.
  1442. // If do nothing if an option, then it is the default.
  1443. // Otherwise, if fat format is allowed, it is the default.
  1444. // Otherwise, the first item in the menu is the default.
  1445. //
  1446. if(AllowDoNothing) {
  1447. Selection = DoNothingOption;
  1448. } else {
  1449. if(AllowNtfsFormat) {
  1450. Selection = NtfsFormatOption;
  1451. } else {
  1452. Selection = 0;
  1453. }
  1454. }
  1455. //
  1456. // Display the menu.
  1457. //
  1458. Chosen = FALSE;
  1459. do {
  1460. SpDisplayStatusOptions(
  1461. DEFAULT_STATUS_ATTRIBUTE,
  1462. SP_STAT_ENTER_EQUALS_CONTINUE,
  1463. AllowEscape ? SP_STAT_ESC_EQUALS_CANCEL : 0,
  1464. 0
  1465. );
  1466. SpMnDisplay(Menu,
  1467. Selection,
  1468. FALSE,
  1469. ValidKeys,
  1470. NULL,
  1471. NULL,
  1472. NULL,
  1473. &Key,
  1474. &Selection);
  1475. switch(Key) {
  1476. case ASCI_CR:
  1477. Chosen = TRUE;
  1478. break;
  1479. case ASCI_ESC:
  1480. if (AllowEscape) {
  1481. SpMnDestroy(Menu);
  1482. return(FormatOptionCancel);
  1483. }
  1484. }
  1485. } while(!Chosen);
  1486. SpMnDestroy(Menu);
  1487. //
  1488. // Convert chosen option to a meaningful value.
  1489. //
  1490. if(Selection == FatQFormatOption) {
  1491. return(FormatOptionFatQuick);
  1492. }
  1493. if(Selection == NtfsQFormatOption) {
  1494. return(FormatOptionNtfsQuick);
  1495. }
  1496. if(Selection == FatFormatOption) {
  1497. return(FormatOptionFat);
  1498. }
  1499. if(Selection == NtfsFormatOption) {
  1500. return(FormatOptionNtfs);
  1501. }
  1502. if(Selection == ConvertNtfsOption) {
  1503. return(FormatOptionConvertToNtfs);
  1504. }
  1505. if(Selection == DoNothingOption) {
  1506. return(FormatOptionDoNothing);
  1507. }
  1508. ASSERT(FALSE);
  1509. return(FormatOptionCancel);
  1510. }
  1511. VOID
  1512. SpPtDoCommitChanges(
  1513. VOID
  1514. )
  1515. {
  1516. NTSTATUS Status;
  1517. ULONG i;
  1518. BOOLEAN Changes;
  1519. BOOLEAN AnyChanges = FALSE;
  1520. CLEAR_CLIENT_SCREEN();
  1521. //
  1522. // Update dblspace.ini, if necessary
  1523. //
  1524. SpUpdateDoubleSpaceIni();
  1525. //
  1526. // Iterate through the disks.
  1527. //
  1528. for(i=0; i<HardDiskCount; i++) {
  1529. //
  1530. // Tell the user what we're doing.
  1531. // This is useful because if it hangs, there will be an
  1532. // on-screen record of which disk we were updating.
  1533. //
  1534. SpDisplayStatusText(
  1535. SP_STAT_UPDATING_DISK,
  1536. DEFAULT_STATUS_ATTRIBUTE,
  1537. HardDisks[i].Description
  1538. );
  1539. //
  1540. // Commit any changes on this disk.
  1541. //
  1542. Status = SpPtCommitChanges(i,&Changes);
  1543. //
  1544. // If there were no changes, then we better have success.
  1545. //
  1546. ASSERT(NT_SUCCESS(Status) || Changes);
  1547. if(Changes) {
  1548. AnyChanges = TRUE;
  1549. }
  1550. //
  1551. // Fatal error if we can't update the disks with
  1552. // the new partitioning info.
  1553. //
  1554. if(!NT_SUCCESS(Status)) {
  1555. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtDoCommitChanges: status %lx updating disk %u\n",Status,i));
  1556. FatalPartitionUpdateError(HardDisks[i].Description);
  1557. }
  1558. }
  1559. }
  1560. VOID
  1561. FatalPartitionUpdateError(
  1562. IN PWSTR DiskDescription
  1563. )
  1564. {
  1565. ULONG ValidKeys[2] = { KEY_F3,0 };
  1566. while(1) {
  1567. SpStartScreen(
  1568. SP_SCRN_FATAL_FDISK_WRITE_ERROR,
  1569. 3,
  1570. HEADER_HEIGHT+3,
  1571. FALSE,
  1572. FALSE,
  1573. DEFAULT_ATTRIBUTE,
  1574. DiskDescription
  1575. );
  1576. SpDisplayStatusOptions(
  1577. DEFAULT_STATUS_ATTRIBUTE,
  1578. SP_STAT_F3_EQUALS_EXIT,
  1579. 0
  1580. );
  1581. if(SpWaitValidKey(ValidKeys,NULL,NULL) == KEY_F3) {
  1582. break;
  1583. }
  1584. }
  1585. SpDone(0,FALSE,TRUE);
  1586. }
  1587. NTSTATUS
  1588. SpDoFormat(
  1589. IN PWSTR RegionDescr,
  1590. IN PDISK_REGION Region,
  1591. IN ULONG FilesystemType,
  1592. IN BOOLEAN IsFailureFatal,
  1593. IN BOOLEAN CheckFatSize,
  1594. IN BOOLEAN QuickFormat,
  1595. IN PVOID SifHandle,
  1596. IN DWORD ClusterSize,
  1597. IN PWSTR SetupSourceDevicePath,
  1598. IN PWSTR DirectoryOnSetupSource
  1599. )
  1600. {
  1601. NTSTATUS Status;
  1602. ULONGLONG RegionSizeMB;
  1603. ULONG ValidKeys2[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  1604. LONG Key;
  1605. ASSERT( (FilesystemType == FilesystemFat) ||
  1606. (FilesystemType == FilesystemNtfs) ||
  1607. (FilesystemType == FilesystemFat32));
  1608. //
  1609. // Under normal conditions, setup switches to Fat32 if the partition is big
  1610. // enough (2GB as the cutoff). Before plowing ahead, though, we warn
  1611. // the user that the drive will not be compatible with MS-DOS/Win95, etc.
  1612. //
  1613. if(FilesystemType == FilesystemFat) {
  1614. RegionSizeMB = SpPtSectorCountToMB(
  1615. &(HardDisks[Region->DiskNumber]),
  1616. Region->SectorCount
  1617. );
  1618. if(RegionSizeMB > 2048) {
  1619. if(CheckFatSize) {
  1620. do {
  1621. SpStartScreen(
  1622. SP_SCRN_OSPART_LARGE,
  1623. 3,
  1624. HEADER_HEIGHT+1,
  1625. FALSE,
  1626. FALSE,
  1627. DEFAULT_ATTRIBUTE
  1628. );
  1629. SpDisplayStatusOptions(
  1630. DEFAULT_STATUS_ATTRIBUTE,
  1631. SP_STAT_ENTER_EQUALS_CONTINUE,
  1632. SP_STAT_ESC_EQUALS_CANCEL,
  1633. SP_STAT_F3_EQUALS_EXIT,
  1634. 0
  1635. );
  1636. switch(Key = SpWaitValidKey(ValidKeys2,NULL,NULL)) {
  1637. case KEY_F3:
  1638. SpConfirmExit();
  1639. break;
  1640. case ASCI_ESC:
  1641. return(STATUS_UNSUCCESSFUL);
  1642. }
  1643. } while(Key != ASCI_CR);
  1644. }
  1645. FilesystemType = FilesystemFat32;
  1646. }
  1647. }
  1648. AutofrmtRunning = TRUE;
  1649. Status = SpRunAutoFormat(
  1650. SifHandle,
  1651. RegionDescr,
  1652. Region,
  1653. FilesystemType,
  1654. QuickFormat,
  1655. ClusterSize,
  1656. SetupSourceDevicePath,
  1657. DirectoryOnSetupSource
  1658. );
  1659. AutofrmtRunning = FALSE;
  1660. if(!NT_SUCCESS(Status)) {
  1661. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to format (%lx)\n",Status));
  1662. if(IsFailureFatal) {
  1663. //
  1664. // Then we can't continue (this means that the system partition
  1665. // couldn't be formatted).
  1666. //
  1667. WCHAR DriveLetterString[2];
  1668. DriveLetterString[0] = Region->DriveLetter;
  1669. DriveLetterString[1] = L'\0';
  1670. SpStringToUpper(DriveLetterString);
  1671. SpStartScreen(SP_SCRN_SYSPART_FORMAT_ERROR,
  1672. 3,
  1673. HEADER_HEIGHT+1,
  1674. FALSE,
  1675. FALSE,
  1676. DEFAULT_ATTRIBUTE,
  1677. DriveLetterString
  1678. );
  1679. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  1680. SpInputDrain();
  1681. while(SpInputGetKeypress() != KEY_F3) ;
  1682. SpDone(0,FALSE,TRUE);
  1683. } else {
  1684. //
  1685. // Put up an error screen.
  1686. //
  1687. SpDisplayScreen(SP_SCRN_FORMAT_ERROR,3,HEADER_HEIGHT+1);
  1688. SpDisplayStatusOptions(
  1689. DEFAULT_STATUS_ATTRIBUTE,
  1690. SP_STAT_ENTER_EQUALS_CONTINUE,
  1691. 0
  1692. );
  1693. SpInputDrain();
  1694. while(SpInputGetKeypress() != ASCI_CR) ;
  1695. return(Status);
  1696. }
  1697. } else {
  1698. //
  1699. // Partition was successfuly formatted.
  1700. // Save the file system type on the region description.
  1701. //
  1702. Region->Filesystem = FilesystemType;
  1703. SpFormatMessage( Region->TypeName,
  1704. sizeof(Region->TypeName),
  1705. SP_TEXT_FS_NAME_BASE + Region->Filesystem );
  1706. //
  1707. // Reset the volume label
  1708. //
  1709. Region->VolumeLabel[0] = L'\0';
  1710. // Clean up boot.ini entries that referred to this partition
  1711. SpRemoveInstallationFromBootList(
  1712. NULL,
  1713. Region,
  1714. NULL,
  1715. NULL,
  1716. NULL,
  1717. PrimaryArcPath,
  1718. NULL
  1719. );
  1720. #if defined(_AMD64_) || defined(_X86_)
  1721. // call again to delete the secondary Arc name
  1722. SpRemoveInstallationFromBootList(
  1723. NULL,
  1724. Region,
  1725. NULL,
  1726. NULL,
  1727. NULL,
  1728. SecondaryArcPath,
  1729. NULL
  1730. );
  1731. #endif // defined(_AMD64_) || defined(_X86_)
  1732. }
  1733. return(STATUS_SUCCESS);
  1734. }
  1735. //
  1736. // dummy entry points for the cmd console
  1737. //
  1738. VOID
  1739. SpDetermineOsTypeFromBootSectorC(
  1740. IN PWSTR CColonPath,
  1741. IN PUCHAR BootSector,
  1742. OUT PUCHAR *OsDescription,
  1743. OUT PBOOLEAN IsNtBootcode,
  1744. OUT PBOOLEAN IsOtherOsInstalled,
  1745. IN WCHAR DriveLetter
  1746. )
  1747. {
  1748. #if defined(_AMD64_) || defined(_X86_)
  1749. SpDetermineOsTypeFromBootSector(
  1750. CColonPath,
  1751. BootSector,
  1752. OsDescription,
  1753. IsNtBootcode,
  1754. IsOtherOsInstalled,
  1755. DriveLetter
  1756. );
  1757. #else
  1758. *OsDescription = NULL;
  1759. *IsNtBootcode = FALSE;
  1760. *IsOtherOsInstalled = FALSE;
  1761. return;
  1762. #endif // defined(_AMD64_) || defined(_X86_)
  1763. }
  1764. NTSTATUS
  1765. pSpBootCodeIoC(
  1766. IN PWSTR FilePath,
  1767. IN PWSTR AdditionalFilePath, OPTIONAL
  1768. IN ULONG BytesToRead,
  1769. IN OUT PUCHAR *Buffer,
  1770. IN ULONG OpenDisposition,
  1771. IN BOOLEAN Write,
  1772. IN ULONGLONG Offset,
  1773. IN ULONG BytesPerSector
  1774. )
  1775. {
  1776. #if defined(_AMD64_) || defined(_X86_)
  1777. return pSpBootCodeIo(
  1778. FilePath,
  1779. AdditionalFilePath,
  1780. BytesToRead,
  1781. Buffer,
  1782. OpenDisposition,
  1783. Write,
  1784. Offset,
  1785. BytesPerSector
  1786. );
  1787. #else
  1788. return STATUS_NOT_IMPLEMENTED;
  1789. #endif // defined(_AMD64_) || defined(_X86_)
  1790. }
  1791. #ifdef OLD_PARTITION_ENGINE
  1792. VOID
  1793. SpPtMakeRegionActive(
  1794. IN PDISK_REGION Region
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. Make a partition active and make sure all other primary partitions
  1799. are inactive. The partition must be on disk 0.
  1800. If a region is found active that is not the region we want to be active,
  1801. tell the user that his other operating system will be disabled.
  1802. NOTE: Any changes made here are not committed automatically!
  1803. Arguments:
  1804. Region - supplies disk region descriptor for the partition to activate.
  1805. This region must be on disk 0.
  1806. Return Value:
  1807. None.
  1808. --*/
  1809. {
  1810. ULONG i;
  1811. static BOOLEAN WarnedOtherOs = FALSE;
  1812. ASSERT(Region->DiskNumber == SpDetermineDisk0());
  1813. if(Region->DiskNumber != SpDetermineDisk0()) {
  1814. return;
  1815. }
  1816. //
  1817. // Make sure the system partition is active and all others are inactive.
  1818. // If we find Boot Manager, present a warning that we are going to disable it.
  1819. // If we find some other operating system is active, present a generic warning.
  1820. //
  1821. for(i=0; i<PTABLE_DIMENSION; i++) {
  1822. PON_DISK_PTE pte = &PartitionedDisks[Region->DiskNumber].MbrInfo.OnDiskMbr.PartitionTable[i];
  1823. if(pte->ActiveFlag) {
  1824. //
  1825. // If this is not the region we want to be the system partition,
  1826. // then investigate its type.
  1827. //
  1828. if(i != Region->TablePosition) {
  1829. //
  1830. // If this is boot manager, give a specific warning.
  1831. // Otherwise, give a general warning.
  1832. //
  1833. if(!WarnedOtherOs && !UnattendedOperation) {
  1834. SpDisplayScreen(
  1835. (pte->SystemId == 10) ? SP_SCRN_BOOT_MANAGER : SP_SCRN_OTHER_OS_ACTIVE,
  1836. 3,
  1837. HEADER_HEIGHT+1
  1838. );
  1839. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
  1840. SpInputDrain();
  1841. while(SpInputGetKeypress() != ASCI_CR) ;
  1842. WarnedOtherOs = TRUE;
  1843. }
  1844. }
  1845. }
  1846. }
  1847. ASSERT(Region->PartitionedSpace);
  1848. ASSERT(Region->TablePosition < PTABLE_DIMENSION);
  1849. SpPtMarkActive(Region->TablePosition);
  1850. }
  1851. #endif
  1852. BOOLEAN
  1853. SpPtValidateCColonFormat(
  1854. IN PVOID SifHandle,
  1855. IN PWSTR RegionDescr,
  1856. IN PDISK_REGION Region,
  1857. IN BOOLEAN CheckOnly,
  1858. IN PWSTR SetupSourceDevicePath,
  1859. IN PWSTR DirectoryOnSetupSource
  1860. )
  1861. /*++
  1862. Routine Description:
  1863. Inspect C: to make sure it is formatted with a filesystem we
  1864. recognize, and has enough free space on it for the boot files.
  1865. If any of these tests fail, tell the user that we will have to
  1866. reformat C: to continue, and give the option of returning to the
  1867. partitioning screen or continuing anyway.
  1868. If the user opts to continue, then format the partition to FAT
  1869. before returning.
  1870. Arguments:
  1871. SifHandle - supplies handle to txtsetup.sif. This is used to fetch the
  1872. value indicating how much space is required on C:.
  1873. Region - supplies disk region descriptor for C:.
  1874. Return Value:
  1875. TRUE if, upon returning from this routine, C: is acceptable.
  1876. FALSE if not, which could mean that the user asked us not
  1877. to format his C:, or that the format failed.
  1878. --*/
  1879. {
  1880. ULONG MinFreeKB;
  1881. ULONG ValidKeys[3] = { ASCI_ESC, KEY_F3, 0 };
  1882. ULONG ValidKeys3[2] = { KEY_F3, 0 };
  1883. ULONG ValidKeys4[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  1884. ULONG Mnemonics[2] = { MnemonicFormat,0 };
  1885. ULONG Key;
  1886. BOOLEAN Confirm;
  1887. BOOLEAN Fat32;
  1888. NTSTATUS Status;
  1889. ULONGLONG RegionSizeMB;
  1890. WCHAR DriveLetterString[2];
  1891. BOOLEAN QuickFormat = TRUE;
  1892. ULONG FileSystem = FilesystemFat;
  1893. BOOLEAN AllowFat = FALSE;
  1894. //
  1895. // Initialize the drive letter string, to be used in the various error messages
  1896. //
  1897. DriveLetterString[0] = Region->DriveLetter;
  1898. DriveLetterString[1] = L'\0';
  1899. SpStringToUpper(DriveLetterString);
  1900. //
  1901. // Get the minimum free space required for C:.
  1902. //
  1903. SpFetchDiskSpaceRequirements( SifHandle,
  1904. Region->BytesPerCluster,
  1905. NULL,
  1906. &MinFreeKB );
  1907. d1:
  1908. //
  1909. // If the user newly created the C: drive, no confirmation is
  1910. // necessary.
  1911. //
  1912. if(Region->Filesystem == FilesystemNewlyCreated) {
  1913. //
  1914. // Shouldn't be newly created if we're checking
  1915. // to see whether we should do an upgrade, because we
  1916. // haven't gotten to the partitioning screen yet.
  1917. //
  1918. ASSERT(!CheckOnly);
  1919. Confirm = FALSE;
  1920. //
  1921. // If we don't know the filesystem on C: or we can't determine the
  1922. // free space, then we need to format the drive, and will confirm first.
  1923. //
  1924. } else if((Region->Filesystem == FilesystemUnknown) || (Region->FreeSpaceKB == (ULONG)(-1))) {
  1925. if(CheckOnly) {
  1926. return(FALSE);
  1927. }
  1928. SpStartScreen(SP_SCRN_C_UNKNOWN,
  1929. 3,
  1930. HEADER_HEIGHT+1,
  1931. FALSE,
  1932. FALSE,
  1933. DEFAULT_ATTRIBUTE,
  1934. DriveLetterString
  1935. );
  1936. Confirm = TRUE;
  1937. //
  1938. // If C: is too full, then we need to format over it.
  1939. // Confirm first.
  1940. //
  1941. } else if(Region->FreeSpaceKB < MinFreeKB) {
  1942. if(CheckOnly) {
  1943. return(FALSE);
  1944. }
  1945. //
  1946. // If this is a floppyless boot, then the user (probably) cannot
  1947. // format, and has no choice but to exit Setup and free some space.
  1948. //
  1949. if( IsFloppylessBoot &&
  1950. (Region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))) {
  1951. SpStartScreen(
  1952. SP_SCRN_C_FULL_NO_FMT,
  1953. 3,
  1954. HEADER_HEIGHT+1,
  1955. FALSE,
  1956. FALSE,
  1957. DEFAULT_ATTRIBUTE,
  1958. MinFreeKB,
  1959. DriveLetterString
  1960. );
  1961. SpDisplayStatusOptions(
  1962. DEFAULT_STATUS_ATTRIBUTE,
  1963. SP_STAT_F3_EQUALS_EXIT,
  1964. 0
  1965. );
  1966. SpWaitValidKey(ValidKeys3,NULL,NULL);
  1967. SpDone(0,FALSE,TRUE);
  1968. }
  1969. Confirm = TRUE;
  1970. SpStartScreen(
  1971. SP_SCRN_C_FULL,
  1972. 3,
  1973. HEADER_HEIGHT+1,
  1974. FALSE,
  1975. FALSE,
  1976. DEFAULT_ATTRIBUTE,
  1977. MinFreeKB,
  1978. DriveLetterString
  1979. );
  1980. //
  1981. // If all of the above tests fail, then the partition is acceptable as-is.
  1982. //
  1983. } else {
  1984. return(TRUE);
  1985. }
  1986. //
  1987. // If we are supposed to confirm, then do that here, forcing the
  1988. // user to press F if he really wants to format or esc to bail.
  1989. //
  1990. if(Confirm) {
  1991. SpDisplayStatusOptions(
  1992. DEFAULT_STATUS_ATTRIBUTE,
  1993. SP_STAT_ESC_EQUALS_CANCEL,
  1994. SP_STAT_F_EQUALS_FORMAT,
  1995. SP_STAT_F3_EQUALS_EXIT,
  1996. 0
  1997. );
  1998. switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
  1999. case KEY_F3:
  2000. SpConfirmExit();
  2001. goto d1;
  2002. case ASCI_ESC:
  2003. //
  2004. // User bailed.
  2005. //
  2006. return(FALSE);
  2007. default:
  2008. //
  2009. // Must be F.
  2010. //
  2011. break;
  2012. }
  2013. }
  2014. //
  2015. // Whistler formats only 32GB Fat32 partitions
  2016. //
  2017. AllowFat = (SPPT_REGION_FREESPACE_GB(Region) <= 32);
  2018. //
  2019. // Prompt the user for the formatting options
  2020. //
  2021. if (!UnattendedOperation) {
  2022. ULONG Selection;
  2023. SpDisplayScreen(SP_SCRN_FORMAT_NEW_PART3, 3, HEADER_HEIGHT+1);
  2024. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2025. SP_STAT_ENTER_EQUALS_SELECT,
  2026. 0);
  2027. Selection = SpFormattingOptions(
  2028. AllowFat,
  2029. TRUE,
  2030. FALSE,
  2031. FALSE,
  2032. TRUE);
  2033. if ((Selection != FormatOptionFatQuick) &&
  2034. (Selection != FormatOptionNtfsQuick)) {
  2035. QuickFormat = FALSE;
  2036. }
  2037. if ((Selection == FormatOptionNtfs) ||
  2038. (Selection == FormatOptionNtfsQuick)) {
  2039. FileSystem = FilesystemNtfs;
  2040. }
  2041. if (Selection == FormatOptionCancel) {
  2042. return FALSE; // user bailed out
  2043. }
  2044. }
  2045. if (!AllowFat && ((FileSystem == FilesystemFat) ||
  2046. (FileSystem == FilesystemFat32))) {
  2047. FileSystem = FilesystemNtfs;
  2048. }
  2049. if (FileSystem == FilesystemFat) {
  2050. //
  2051. // If the partition is larger than 2048MB then we want to make it
  2052. // Fat32. Ask the user first.
  2053. //
  2054. Fat32 = FALSE;
  2055. RegionSizeMB = SpPtSectorCountToMB(
  2056. &(HardDisks[Region->DiskNumber]),
  2057. Region->SectorCount
  2058. );
  2059. if(RegionSizeMB > 2048) {
  2060. do {
  2061. SpStartScreen(
  2062. SP_SCRN_C_LARGE,
  2063. 3,
  2064. HEADER_HEIGHT+1,
  2065. FALSE,
  2066. FALSE,
  2067. DEFAULT_ATTRIBUTE,
  2068. DriveLetterString
  2069. );
  2070. SpDisplayStatusOptions(
  2071. DEFAULT_STATUS_ATTRIBUTE,
  2072. SP_STAT_ENTER_EQUALS_CONTINUE,
  2073. SP_STAT_ESC_EQUALS_CANCEL,
  2074. SP_STAT_F3_EQUALS_EXIT,
  2075. 0
  2076. );
  2077. switch(Key = SpWaitValidKey(ValidKeys4,NULL,NULL)) {
  2078. case KEY_F3:
  2079. SpConfirmExit();
  2080. break;
  2081. case ASCI_ESC:
  2082. return(FALSE);
  2083. }
  2084. } while(Key != ASCI_CR);
  2085. Fat32 = TRUE;
  2086. }
  2087. FileSystem = Fat32 ? FilesystemFat32 : FilesystemFat;
  2088. }
  2089. if(!Confirm) {
  2090. //
  2091. // Just put up an information screen so the user doesn't
  2092. // go bonkers when we just start formatting his newly created C:.
  2093. //
  2094. SpStartScreen(SP_SCRN_ABOUT_TO_FORMAT_C,
  2095. 3,
  2096. HEADER_HEIGHT+1,
  2097. FALSE,
  2098. FALSE,
  2099. DEFAULT_ATTRIBUTE,
  2100. DriveLetterString
  2101. );
  2102. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  2103. SpInputDrain();
  2104. while(SpInputGetKeypress() != ASCI_CR) ;
  2105. }
  2106. //
  2107. // Do the format.
  2108. //
  2109. Status = SpDoFormat(
  2110. RegionDescr,
  2111. Region,
  2112. FileSystem,
  2113. TRUE,
  2114. FALSE,
  2115. QuickFormat,
  2116. SifHandle,
  2117. 0, // default cluster size
  2118. SetupSourceDevicePath,
  2119. DirectoryOnSetupSource
  2120. );
  2121. if(NT_SUCCESS(Status)) {
  2122. //
  2123. // At this point we must initialize the available free space on the partition. Otherwise,
  2124. // SpPtValidateCColonFormat() will not recognized this partition, if it is called again.
  2125. // This can happen if the user decides not format the partition (newly created or unformatted),
  2126. // that he initially selected as the target partition.
  2127. //
  2128. SpPtDetermineRegionSpace(Region);
  2129. }
  2130. return(NT_SUCCESS(Status));
  2131. }
  2132. #ifndef NEW_PARTITION_ENGINE
  2133. PDISK_REGION
  2134. SpPtValidSystemPartition(
  2135. VOID
  2136. )
  2137. /*++
  2138. Routine Description:
  2139. Determine whether there is a valid disk partition suitable for use
  2140. as the system partition on an x86 machine (ie, C:).
  2141. A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable.
  2142. If there is a partition that meets these criteria that is marked active,
  2143. then it is the system partition, regardless of whether there are other
  2144. partitions that also meet the criteria.
  2145. Arguments:
  2146. None.
  2147. Return Value:
  2148. Pointer to a disk region descriptor for a suitable system partition (C:)
  2149. for an x86 machine.
  2150. NULL if no such partition currently exists.
  2151. --*/
  2152. {
  2153. PON_DISK_PTE pte;
  2154. PDISK_REGION pRegion,pActiveRegion,pFirstRegion;
  2155. ULONG DiskNumber;
  2156. pActiveRegion = NULL;
  2157. pFirstRegion = NULL;
  2158. DiskNumber = SpDetermineDisk0();
  2159. #if defined(REMOTE_BOOT)
  2160. //
  2161. // If this is a diskless remote boot setup, there is no drive 0.
  2162. //
  2163. if ( DiskNumber == (ULONG)-1 ) {
  2164. return NULL;
  2165. }
  2166. #endif // defined(REMOTE_BOOT)
  2167. #ifdef GPT_PARTITION_ENGINE
  2168. if (SPPT_IS_GPT_DISK(DiskNumber)) {
  2169. return SpPtnValidSystemPartition();
  2170. }
  2171. #endif
  2172. //
  2173. // Look for the active partition on drive 0
  2174. // and for the first recognized primary partition on drive 0.
  2175. //
  2176. for(pRegion=PartitionedDisks[DiskNumber].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
  2177. if(pRegion->PartitionedSpace) {
  2178. UCHAR TmpSysId;
  2179. ASSERT(pRegion->TablePosition < PTABLE_DIMENSION);
  2180. pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
  2181. ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
  2182. //
  2183. // Skip if not recognized.
  2184. // In the repair case, we recognize FT partitions
  2185. //
  2186. TmpSysId = pte->SystemId;
  2187. if( !IsContainerPartition(TmpSysId)
  2188. && ( (PartitionNameIds[pte->SystemId] == (UCHAR)(-1)) ||
  2189. (pRegion->DynamicVolume && pRegion->DynamicVolumeSuitableForOS) ||
  2190. ((RepairWinnt || WinntSetup || SpDrEnabled() ) && pRegion->FtPartition )
  2191. )
  2192. )
  2193. {
  2194. //
  2195. // Remember it if it's active.
  2196. //
  2197. if((pte->ActiveFlag) && !pActiveRegion) {
  2198. pActiveRegion = pRegion;
  2199. }
  2200. //
  2201. // Remember it if it's the first one we've seen.
  2202. //
  2203. if(!pFirstRegion) {
  2204. pFirstRegion = pRegion;
  2205. }
  2206. }
  2207. }
  2208. }
  2209. //
  2210. // If there is an active, recognized region, use it as the
  2211. // system partition. Otherwise, use the first primary
  2212. // we encountered as the system partition. If there is
  2213. // no recognized primary, then there is no valid system partition.
  2214. //
  2215. return(pActiveRegion ? pActiveRegion : pFirstRegion);
  2216. }
  2217. #endif // ! NEW_PARTITION_ENGINE
  2218. ULONG
  2219. SpDetermineDisk0(
  2220. VOID
  2221. )
  2222. /*++
  2223. Routine Description:
  2224. Determine the real disk 0, which may not be the same as \device\harddisk0.
  2225. Consider the case where we have 2 scsi adapters and
  2226. the NT drivers load in an order such that the one with the BIOS
  2227. gets loaded *second* -- meaning that the system partition is actually
  2228. on disk 1, not disk 0.
  2229. Arguments:
  2230. None.
  2231. Return Value:
  2232. NT disk ordinal suitable for use in generating nt device paths
  2233. of the form \device\harddiskx.
  2234. --*/
  2235. {
  2236. ULONG DiskNumber = (ULONG)-1;
  2237. ULONG CurrentDisk = 0;
  2238. WCHAR ArcDiskName[MAX_PATH];
  2239. //
  2240. // Find the first harddisk (non-removable) media that the
  2241. // BIOS enumerated to be used for system partition
  2242. //
  2243. while (CurrentDisk < HardDiskCount) {
  2244. swprintf(ArcDiskName, L"multi(0)disk(0)rdisk(%d)", CurrentDisk);
  2245. DiskNumber = SpArcDevicePathToDiskNumber(ArcDiskName);
  2246. if (DiskNumber != (ULONG)-1) {
  2247. if (!SPPT_IS_REMOVABLE_DISK(DiskNumber)) {
  2248. break;
  2249. } else {
  2250. DiskNumber = (ULONG)-1;
  2251. }
  2252. }
  2253. CurrentDisk++;
  2254. }
  2255. #if defined(REMOTE_BOOT)
  2256. //
  2257. // If this is a diskless remote boot setup, there is no drive 0.
  2258. //
  2259. if ( RemoteBootSetup && (DiskNumber == (ULONG)-1) && (HardDiskCount == 0) ) {
  2260. return DiskNumber;
  2261. }
  2262. #endif // defined(REMOTE_BOOT)
  2263. return (DiskNumber == (ULONG)-1) ? 0 : DiskNumber;
  2264. }
  2265. #ifdef OLD_PARTITION_ENGINE
  2266. BOOL
  2267. SpPtIsSystemPartitionRecognizable(
  2268. VOID
  2269. )
  2270. /*++
  2271. Routine Description:
  2272. Determine whether the active partition is suitable for use
  2273. as the system partition on an x86 machine (ie, C:).
  2274. A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable.
  2275. Arguments:
  2276. None.
  2277. Return Value:
  2278. TRUE - We found a suitable partition
  2279. FALSE - We didn't find a suitable partition
  2280. --*/
  2281. {
  2282. PON_DISK_PTE pte;
  2283. PDISK_REGION pRegion;
  2284. ULONG DiskNumber;
  2285. //
  2286. // Any partitions on NEC98 are primary and active. So don't need to check on NEC98.
  2287. //
  2288. if( IsNEC_98 ) {
  2289. return TRUE;
  2290. }
  2291. DiskNumber = SpDetermineDisk0();
  2292. //
  2293. // Look for the active partition on drive 0
  2294. // and for the first recognized primary partition on drive 0.
  2295. //
  2296. for(pRegion=PartitionedDisks[DiskNumber].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
  2297. pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
  2298. if( (pRegion->PartitionedSpace) &&
  2299. (pte->ActiveFlag) ) {
  2300. //
  2301. // We've hit the active partition. Check its format.
  2302. //
  2303. if( (pRegion->Filesystem == FilesystemNtfs) ||
  2304. (pRegion->Filesystem == FilesystemFat) ||
  2305. (pRegion->Filesystem == FilesystemFat32) ) {
  2306. //
  2307. // We recognize him.
  2308. //
  2309. return TRUE;
  2310. }
  2311. }
  2312. }
  2313. //
  2314. // If we get here, we didn't find any active partitions
  2315. // we recognize.
  2316. //
  2317. return FALSE;
  2318. }
  2319. PDISK_REGION
  2320. SpPtValidSystemPartitionArc(
  2321. IN PVOID SifHandle,
  2322. IN PWSTR SetupSourceDevicePath,
  2323. IN PWSTR DirectoryOnSetupSource
  2324. )
  2325. /*++
  2326. Routine Description:
  2327. Determine whether there is a valid disk partition suitable for use
  2328. as the system partition on an ARC machine.
  2329. A partition is suitable if it is marked as a system partition in nvram,
  2330. has the required free space and is formatted with the FAT filesystem.
  2331. Arguments:
  2332. SifHandle - supplies handle to loaded setup information file.
  2333. Return Value:
  2334. Pointer to a disk region descriptor for a suitable system partition.
  2335. Does not return if no such partition exists.
  2336. --*/
  2337. {
  2338. ULONG RequiredSpaceKB = 0;
  2339. ULONG disk,pass;
  2340. PPARTITIONED_DISK pDisk;
  2341. PDISK_REGION pRegion;
  2342. //
  2343. // Go through all the regions. The first one that has enough free space
  2344. // and is of the required filesystem becomes *the* system partition.
  2345. //
  2346. for(disk=0; disk<HardDiskCount; disk++) {
  2347. pDisk = &PartitionedDisks[disk];
  2348. for(pass=0; pass<2; pass++) {
  2349. pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
  2350. for( ; pRegion; pRegion=pRegion->Next) {
  2351. if(pRegion->IsSystemPartition
  2352. && (pRegion->FreeSpaceKB != (ULONG)(-1))
  2353. && (pRegion->Filesystem == FilesystemFat))
  2354. {
  2355. ULONG TotalSizeOfFilesOnOsWinnt;
  2356. //
  2357. // On non-x86 platformrs, specially alpha machines that in general
  2358. // have small system partitions (~3 MB), we should compute the size
  2359. // of the files on \os\winnt (currently, osloader.exe and hall.dll),
  2360. // and consider this size as available disk space. We can do this
  2361. // since these files will be overwritten by the new ones.
  2362. // This fixes the problem that we see on Alpha, when the system
  2363. // partition is too full.
  2364. //
  2365. SpFindSizeOfFilesInOsWinnt( SifHandle,
  2366. pRegion,
  2367. &TotalSizeOfFilesOnOsWinnt );
  2368. //
  2369. // Transform the size into KB
  2370. //
  2371. TotalSizeOfFilesOnOsWinnt /= 1024;
  2372. //
  2373. // Determine the amount of free space required on a system partition.
  2374. //
  2375. SpFetchDiskSpaceRequirements( SifHandle,
  2376. pRegion->BytesPerCluster,
  2377. NULL,
  2378. &RequiredSpaceKB );
  2379. if ((pRegion->FreeSpaceKB + TotalSizeOfFilesOnOsWinnt) >= RequiredSpaceKB) {
  2380. return(pRegion);
  2381. }
  2382. }
  2383. }
  2384. }
  2385. }
  2386. //
  2387. // Make sure we don't look bad.
  2388. //
  2389. if( RequiredSpaceKB == 0 ) {
  2390. SpFetchDiskSpaceRequirements( SifHandle,
  2391. (32 * 1024),
  2392. NULL,
  2393. &RequiredSpaceKB );
  2394. }
  2395. //
  2396. // No valid system partition.
  2397. //
  2398. SpStartScreen(
  2399. SP_SCRN_NO_SYSPARTS,
  2400. 3,
  2401. HEADER_HEIGHT+1,
  2402. FALSE,
  2403. FALSE,
  2404. DEFAULT_ATTRIBUTE,
  2405. RequiredSpaceKB
  2406. );
  2407. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  2408. SpInputDrain();
  2409. while(SpInputGetKeypress() != KEY_F3) ;
  2410. SpDone(0,FALSE,TRUE);
  2411. //
  2412. // Should never get here, but it keeps the compiler happy
  2413. //
  2414. return NULL;
  2415. }
  2416. #endif // OLD_PARTITION_ENGINE