Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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