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.

4731 lines
153 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sppart3.c
  5. Abstract:
  6. Partitioning module for disks in textmode setup.
  7. Contains functions that initialize the in memory data structures,
  8. representing the extents on the disk.
  9. Author:
  10. Matt Holle (matth) 1-December-1999
  11. Revision History:
  12. Vijay Jayaseelan (vijayj) 2-April-2000
  13. - Clean up
  14. - Added lookup and prompting for system partition on
  15. ARC systems
  16. - Added on disk ordinals for MBR disks
  17. --*/
  18. #include "spprecmp.h"
  19. #pragma hdrstop
  20. #include <initguid.h>
  21. #include <devguid.h>
  22. #include <diskguid.h>
  23. #include <oemtypes.h>
  24. #include "sppart3.h"
  25. #define MAX_NTPATH_LENGTH (2048)
  26. #define SUGGESTED_SYSTEMPARTIION_SIZE_MB (100)
  27. #define SUGGESTED_INSTALL_PARTITION_SIZE_MB (4*1024)
  28. extern BOOLEAN ConsoleRunning;
  29. extern BOOLEAN ForceConsole;
  30. //
  31. // Debugging Macros
  32. //
  33. //#define PERF_STATS 1
  34. //#define TESTING_SYSTEM_PARTITION 1
  35. NTSTATUS
  36. SpPtnInitializeDiskDrive(
  37. IN ULONG DiskId
  38. )
  39. /*++
  40. Routine Description:
  41. Initializes the in memory disk region structures for
  42. the given disk number.
  43. Arguments:
  44. DiskId : Disk ID
  45. Return Value:
  46. STATUS_SUCCESS if successful otherwise appropriate
  47. error code
  48. --*/
  49. {
  50. NTSTATUS Status;
  51. #ifdef PERF_STATS
  52. LARGE_INTEGER StartTime, EndTime;
  53. ULONGLONG Diff;
  54. KeQuerySystemTime(&StartTime);
  55. #endif
  56. //
  57. // Send the event
  58. //
  59. SendSetupProgressEvent(PartitioningEvent, ScanDiskEvent, &DiskId);
  60. //
  61. // It would have been better to just have a pointer to a list
  62. // of PDISK_REGIONs off of HARD_DISK, but for some reason, someone
  63. // long ago decided to also maintain a list of PARTITIONED_DISK, which
  64. // *does* contain a list of PDISK_REGIONs. I'm not sure of the use
  65. // of maintaining both HARD_DISKs and PARTITIONED_DISKs, but that's
  66. // the way the data structures are set, so we'll use those.
  67. //
  68. // But it doesn't end there. Rather than assuming that HardDisk[i]
  69. // is describing the same disk as PartitionedDisks[i], we'll
  70. // keep a pointer out of PartitionedDisks[i] that points to the
  71. // corresponding HardDisk entry. Oh well...
  72. //
  73. PartitionedDisks[DiskId].HardDisk = &HardDisks[DiskId];
  74. //
  75. // Initialize structures that are based on the partition tables.
  76. //
  77. Status = SpPtnInitializeDiskAreas(DiskId);
  78. //
  79. // Now we need to fill in additional Region structures
  80. // to represent empty space on the disk. For example, assume
  81. // we have 2 partitions on the disk, but there's empty space
  82. // in between:
  83. // partition1: 0 - 200 sectors
  84. // <empty space>
  85. // partition2: 500 - 1000 sectors
  86. //
  87. // I need to create another Region structure to represent
  88. // this empty space (ensuring that it's marked as unpartitioned.
  89. // This will allow me to present a nice UI to the user when it's
  90. // time to ask for input.
  91. //
  92. //
  93. // Sort the Partitions based on their location on the disk.
  94. //
  95. if( NT_SUCCESS(Status) ) {
  96. Status = SpPtnSortDiskAreas(DiskId);
  97. //
  98. // Create place holders for all empty spaces on the disk.
  99. //
  100. if( NT_SUCCESS(Status) ) {
  101. Status = SpPtnFillDiskFreeSpaceAreas(DiskId);
  102. if (NT_SUCCESS(Status)) {
  103. //
  104. // Mark logical drive's and its container, if any.
  105. //
  106. Status = SpPtnMarkLogicalDrives(DiskId);
  107. }
  108. }
  109. }
  110. #ifdef PERF_STATS
  111. KeQuerySystemTime(&EndTime);
  112. Diff = EndTime.QuadPart - StartTime.QuadPart;
  113. Diff /= 1000000;
  114. KdPrint(("SETUP:SpPtInitializeDiskDrive(%d) took %I64d Secs\n",
  115. DiskId,
  116. Diff));
  117. #endif
  118. SpPtDumpDiskDriveInformation(TRUE);
  119. return Status;
  120. }
  121. NTSTATUS
  122. SpPtnInitializeDiskDrives(
  123. VOID
  124. )
  125. /*++
  126. Routine Description:
  127. Initializes all the disk drive's in memory data structure
  128. representing the disk regions (extents)
  129. Arguments:
  130. None
  131. Return Value:
  132. STATUS_SUCCESS if successful other wise appropriate error
  133. code.
  134. --*/
  135. {
  136. ULONG disk;
  137. NTSTATUS Status = STATUS_SUCCESS;
  138. NTSTATUS ErrStatus = STATUS_SUCCESS;
  139. BOOLEAN ValidHardDiskPresent = FALSE;
  140. //
  141. // If there are no hard disks, bail now.
  142. //
  143. if(!HardDiskCount) {
  144. #if defined(REMOTE_BOOT)
  145. //
  146. // If this is a diskless remote boot setup, it's OK for there to be
  147. // no hard disks. Otherwise, this is a fatal error.
  148. //
  149. if (!RemoteBootSetup || RemoteInstallSetup)
  150. #endif // defined(REMOTE_BOOT)
  151. {
  152. SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,3,HEADER_HEIGHT+1);
  153. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  154. SpInputDrain();
  155. while(SpInputGetKeypress() != KEY_F3);
  156. SpDone(0,FALSE,TRUE);
  157. }
  158. return STATUS_SUCCESS;
  159. }
  160. CLEAR_CLIENT_SCREEN();
  161. //
  162. // Initialize all the RAW disks to platform specific
  163. // default disk styles
  164. //
  165. for(disk=0, Status = STATUS_SUCCESS;
  166. (disk < HardDiskCount);
  167. disk++) {
  168. if (SPPT_IS_RAW_DISK(disk) && SPPT_IS_BLANK_DISK(disk)) {
  169. PHARD_DISK HardDisk = SPPT_GET_HARDDISK(disk);
  170. PARTITION_STYLE Style = SPPT_DEFAULT_PARTITION_STYLE;
  171. //
  172. // Removable Media are always MBR (so don't bother)
  173. //
  174. if (HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) {
  175. continue;
  176. }
  177. Status = SpPtnInitializeDiskStyle(disk,
  178. Style,
  179. NULL);
  180. if (!NT_SUCCESS(Status)) {
  181. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  182. "SETUP:SpPtnInitializeDiskStyle(%d) failed with"
  183. " %lx \n",
  184. disk,
  185. Status));
  186. }
  187. }
  188. }
  189. //
  190. // Allocate an array for the partitioned disk descriptors.
  191. //
  192. PartitionedDisks = SpMemAlloc(HardDiskCount * sizeof(PARTITIONED_DISK));
  193. if(!PartitionedDisks) {
  194. return(STATUS_NO_MEMORY);
  195. }
  196. RtlZeroMemory( PartitionedDisks, HardDiskCount * sizeof(PARTITIONED_DISK) );
  197. //
  198. // Unlock the floppy if we booted off the ls-120 media
  199. //
  200. SpPtnUnlockDevice(L"\\device\\floppy0");
  201. //
  202. // Collect information about each partition.
  203. //
  204. for(disk=0, Status = ErrStatus = STATUS_SUCCESS;
  205. (disk < HardDiskCount);
  206. disk++) {
  207. //
  208. // Initialize the region structure for the given
  209. // disk
  210. //
  211. Status = SpPtnInitializeDiskDrive(disk);
  212. //
  213. // TBD - In remote boot case the disk needs to have
  214. // a valid signature. I am assuming that setupldr
  215. // would have stamped the signature when booting off
  216. // the harddisk
  217. //
  218. //
  219. // Save of the last error
  220. //
  221. if (!NT_SUCCESS(Status)){
  222. ErrStatus = Status;
  223. } else {
  224. ValidHardDiskPresent = TRUE;
  225. }
  226. }
  227. //
  228. // If no valid hard disk is present and this is not a remote boot setup
  229. // then we stop the setup.
  230. //
  231. if (!ValidHardDiskPresent &&
  232. (!RemoteBootSetup || RemoteInstallSetup)){
  233. SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,
  234. 3,
  235. HEADER_HEIGHT+1);
  236. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  237. SP_STAT_F3_EQUALS_EXIT,
  238. 0);
  239. SpInputDrain();
  240. while(SpInputGetKeypress() != KEY_F3);
  241. SpDone(0,FALSE,TRUE);
  242. return ErrStatus;
  243. }
  244. #if defined(_IA64_)
  245. //
  246. // Go and figure out the ESP partitions and
  247. // initialize the MSR partitions on valid GPT
  248. // disks
  249. //
  250. if (SpIsArc() && !SpDrEnabled()) {
  251. if (!ValidArcSystemPartition) {
  252. //
  253. // Create a system partition
  254. //
  255. Status = SpPtnCreateESP(TRUE);
  256. }
  257. //
  258. // Initialize the GPT disks, to have MSR
  259. // partition
  260. //
  261. Status = SpPtnInitializeGPTDisks();
  262. }
  263. #endif
  264. return ErrStatus;
  265. }
  266. NTSTATUS
  267. SpPtnInitializeDiskAreas(
  268. IN ULONG DiskNumber
  269. )
  270. /*++
  271. Routine Description:
  272. Examine the disk for partitioning information and fill in our
  273. partition descriptors.
  274. We'll ask the volume manager for a list of partitions and fill
  275. in our descriptors from the information he provided us.
  276. Arguments:
  277. DiskNumber - supplies the disk number of the disk whose partitions
  278. we want to inspect for determining their types.
  279. Return Value:
  280. NTSTATUS. If all goes well, we should be returing STATUS_SUCCESS.
  281. --*/
  282. {
  283. NTSTATUS Status = STATUS_SUCCESS;
  284. PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx;
  285. WCHAR DevicePath[(sizeof(DISK_DEVICE_NAME_BASE)+sizeof(L"000"))/sizeof(WCHAR)];
  286. HANDLE Handle;
  287. IO_STATUS_BLOCK IoStatusBlock;
  288. PDISK_REGION pDiskRegion = NULL;
  289. PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo = NULL;
  290. PFILE_FS_SIZE_INFORMATION pSizeInfo = NULL;
  291. PFILE_FS_VOLUME_INFORMATION pLabelInfo = NULL;
  292. PWCHAR MyTempBuffer = NULL;
  293. ULONG DriveLayoutSize,
  294. i,
  295. r;
  296. PWSTR LocalSourceFiles[1] = { LocalSourceDirectory };
  297. PHARD_DISK Disk = NULL;
  298. PPARTITIONED_DISK PartDisk = NULL;
  299. ULONGLONG *NewPartitions = NULL;
  300. ULONG NewPartitionCount;
  301. Disk = SPPT_GET_HARDDISK(DiskNumber);
  302. PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  303. //
  304. // Give the user some indication of what we're doing.
  305. //
  306. SpDisplayStatusText( SP_STAT_EXAMINING_DISK_N,
  307. DEFAULT_STATUS_ATTRIBUTE,
  308. Disk->Description);
  309. //
  310. // If we are updating the local source region disk then
  311. // make sure we invalidate LocalSourceRegion
  312. //
  313. if (LocalSourceRegion && (LocalSourceRegion->DiskNumber == DiskNumber)) {
  314. LocalSourceRegion = NULL;
  315. }
  316. //
  317. // Save off the new partitions created
  318. //
  319. NewPartitionCount = SpPtnCountPartitionsByFSType(DiskNumber,
  320. FilesystemNewlyCreated);
  321. if (NewPartitionCount) {
  322. PDISK_REGION NewRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  323. ULONG Index;
  324. NewPartitions = (PULONGLONG) SpMemAlloc(sizeof(ULONGLONG) * NewPartitionCount);
  325. if (!NewPartitions) {
  326. return STATUS_NO_MEMORY;
  327. }
  328. RtlZeroMemory(NewPartitions, sizeof(ULONGLONG) * NewPartitionCount);
  329. Index = 0;
  330. while (NewRegion && (Index < NewPartitionCount)) {
  331. if (SPPT_IS_REGION_PARTITIONED(NewRegion) &&
  332. !SPPT_IS_REGION_MARKED_DELETE(NewRegion) &&
  333. (NewRegion->Filesystem == FilesystemNewlyCreated)) {
  334. NewPartitions[Index] = NewRegion->StartSector;
  335. Index++;
  336. }
  337. NewRegion = NewRegion->Next;
  338. }
  339. }
  340. //
  341. // Free the old regions we allocated, if there are any
  342. //
  343. SpPtnFreeDiskRegions(DiskNumber);
  344. //
  345. // ============================
  346. //
  347. // Open a handle to this hard disk
  348. //
  349. // ============================
  350. //
  351. //
  352. // Create a device path (NT style!) that will describe this disk. This
  353. // will be of the form: \Device\Harddisk0
  354. //
  355. swprintf( DevicePath,
  356. L"\\Device\\Harddisk%u",
  357. DiskNumber );
  358. //
  359. // Open partition 0 on this disk..
  360. //
  361. Status = SpOpenPartition0( DevicePath,
  362. &Handle,
  363. FALSE );
  364. if(!NT_SUCCESS(Status)) {
  365. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  366. "SETUP: SpPtInitializeDiskAreas: unable to open partition0 on device %ws (%lx)\n",
  367. DevicePath,
  368. Status ));
  369. if (NewPartitions) {
  370. SpMemFree(NewPartitions);
  371. }
  372. return( Status );
  373. }
  374. //
  375. // ============================
  376. //
  377. // Load the drive layout information.
  378. //
  379. // ============================
  380. //
  381. //
  382. // Get the disk's layout information. We aren't
  383. // sure how big of a buffer we need, so brute-force it.
  384. //
  385. DriveLayoutSize = 0;
  386. DriveLayoutEx = NULL;
  387. Status = STATUS_BUFFER_TOO_SMALL;
  388. while ((Status == STATUS_BUFFER_TOO_SMALL) ||
  389. (Status == STATUS_BUFFER_OVERFLOW)) {
  390. if (DriveLayoutEx)
  391. SpMemFree(DriveLayoutEx);
  392. DriveLayoutSize += 1024;
  393. DriveLayoutEx = SpMemAlloc( DriveLayoutSize );
  394. if(!DriveLayoutEx) {
  395. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  396. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  397. if (NewPartitions) {
  398. SpMemFree(NewPartitions);
  399. }
  400. return (STATUS_NO_MEMORY);
  401. }
  402. RtlZeroMemory( DriveLayoutEx, DriveLayoutSize );
  403. //
  404. // Attempt to get the disk's partition information.
  405. //
  406. Status = ZwDeviceIoControlFile( Handle,
  407. NULL,
  408. NULL,
  409. NULL,
  410. &IoStatusBlock,
  411. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  412. NULL,
  413. 0,
  414. DriveLayoutEx,
  415. DriveLayoutSize );
  416. }
  417. if(!NT_SUCCESS(Status)) {
  418. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  419. "SETUP: SpPtInitializeDiskAreas: unable to query IOCTL_DISK_GET_DRIVE_LAYOUT_EX on device %ws (%lx)\n",
  420. DevicePath,
  421. Status ));
  422. if (NewPartitions) {
  423. SpMemFree(NewPartitions);
  424. }
  425. if (DriveLayoutEx)
  426. SpMemFree(DriveLayoutEx);
  427. if (Handle != INVALID_HANDLE_VALUE)
  428. ZwClose(Handle);
  429. return ( Status );
  430. }
  431. //
  432. // What kind of disk is this?
  433. //
  434. switch (DriveLayoutEx->PartitionStyle) {
  435. case PARTITION_STYLE_GPT:
  436. Disk->FormatType = DISK_FORMAT_TYPE_GPT;
  437. break;
  438. case PARTITION_STYLE_MBR:
  439. Disk->FormatType = DISK_FORMAT_TYPE_PCAT;
  440. Disk->Signature = DriveLayoutEx->Mbr.Signature;
  441. #if defined(_IA64_)
  442. //
  443. // Make sure that this is not a raw disk
  444. // which is being faked as MBR disk
  445. //
  446. if (SpPtnIsRawDiskDriveLayout(DriveLayoutEx)) {
  447. Disk->FormatType = DISK_FORMAT_TYPE_RAW;
  448. SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
  449. }
  450. #endif
  451. break;
  452. case PARTITION_STYLE_RAW:
  453. Disk->FormatType = DISK_FORMAT_TYPE_RAW;
  454. SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
  455. break;
  456. default:
  457. Disk->FormatType = DISK_FORMAT_TYPE_UNKNOWN;
  458. break;
  459. }
  460. SpAppendDiskTag(Disk);
  461. SpPtDumpDriveLayoutInformation(DevicePath, DriveLayoutEx);
  462. //
  463. // Don't need this guy anymore.
  464. //
  465. ZwClose( Handle );
  466. //
  467. // might need this while committing
  468. //
  469. Disk->DriveLayout = *DriveLayoutEx;
  470. Status = STATUS_SUCCESS;
  471. //
  472. // ============================
  473. //
  474. // Initialize partiton descriptors.
  475. //
  476. // ============================
  477. //
  478. if(DriveLayoutEx->PartitionCount) {
  479. BOOLEAN SysPartFound = FALSE;
  480. ULONG PartitionedSpaceCount = 1;
  481. //
  482. // Initialize an area entry for each partition
  483. // on the disk.
  484. //
  485. for( i = 0, pDiskRegion = NULL; i < DriveLayoutEx->PartitionCount; i++ ) {
  486. ULONG Count = 0;
  487. ULONG TypeNameId = SP_TEXT_UNKNOWN;
  488. LARGE_INTEGER DelayTime;
  489. BOOLEAN AssignDriveLetter = TRUE;
  490. PPARTITION_INFORMATION_EX PartInfo = DriveLayoutEx->PartitionEntry + i;
  491. //
  492. // IOCTL_DISK_GET_DRIVE_LAYOUT_EX may return us a list of entries that
  493. // are not used, so ignore these partitions.
  494. //
  495. if (// if its partition 0, which indicates whole disk
  496. (SPPT_IS_GPT_DISK(DiskNumber) && (PartInfo->PartitionNumber == 0)) ||
  497. (PartInfo->PartitionLength.QuadPart == 0) ||
  498. // if MBR entry not used or length is zero
  499. ((DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR) &&
  500. (PartInfo->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) &&
  501. (PartInfo->PartitionLength.QuadPart == 0)) ||
  502. // if unknown/unused GPT partition
  503. ((DriveLayoutEx->PartitionStyle == PARTITION_STYLE_GPT) &&
  504. (!memcmp(&PartInfo->Gpt.PartitionType,
  505. &PARTITION_ENTRY_UNUSED_GUID, sizeof(GUID))))){
  506. continue;
  507. }
  508. //
  509. // Allocate space for the next region.
  510. //
  511. if(pDiskRegion) {
  512. pDiskRegion->Next = SpMemAlloc( sizeof(DISK_REGION) );
  513. pDiskRegion = pDiskRegion->Next;
  514. } else {
  515. //
  516. // First region allocation for harddisk so initialize
  517. // the region list head for the hardisk
  518. //
  519. ASSERT(PartDisk->PrimaryDiskRegions == NULL);
  520. pDiskRegion = SpMemAlloc(sizeof(DISK_REGION));
  521. PartDisk->PrimaryDiskRegions = pDiskRegion;
  522. SPPT_SET_DISK_BLANK(DiskNumber, FALSE);
  523. }
  524. if(!pDiskRegion) {
  525. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  526. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  527. Status = STATUS_NO_MEMORY;
  528. break;
  529. }
  530. RtlZeroMemory(pDiskRegion, sizeof(DISK_REGION));
  531. //
  532. // Start filling out our Region descriptor...
  533. //
  534. //
  535. // DiskNumber
  536. //
  537. pDiskRegion->DiskNumber = DiskNumber;
  538. //
  539. // Partition information
  540. //
  541. pDiskRegion->PartInfo = *PartInfo;
  542. //
  543. // StartSector
  544. //
  545. pDiskRegion->StartSector = PartInfo->StartingOffset.QuadPart /
  546. Disk->Geometry.BytesPerSector;
  547. //
  548. // SectorCount
  549. //
  550. pDiskRegion->SectorCount = PartInfo->PartitionLength.QuadPart /
  551. Disk->Geometry.BytesPerSector;
  552. //
  553. // PartitionNumber
  554. //
  555. pDiskRegion->PartitionNumber = PartInfo->PartitionNumber;
  556. if (SPPT_IS_MBR_DISK(DiskNumber) && (PartInfo->PartitionNumber == 0)) {
  557. if (IsContainerPartition(PartInfo->Mbr.PartitionType)) {
  558. SPPT_SET_REGION_EPT(pDiskRegion, EPTContainerPartition);
  559. }
  560. //
  561. // nothing after this is really needed for container partition
  562. //
  563. continue;
  564. } else {
  565. //
  566. // PartitionedSpace
  567. //
  568. SPPT_SET_REGION_PARTITIONED(pDiskRegion, TRUE);
  569. }
  570. if (SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
  571. pDiskRegion->TablePosition = PartitionedSpaceCount++;
  572. }
  573. //
  574. // Partition Number should be valid
  575. //
  576. ASSERT(pDiskRegion->PartitionNumber);
  577. //
  578. // IsSystemPartition (is it active)
  579. //
  580. if( DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR ) {
  581. //
  582. // On IA64 systems don't use active MBR partitions as system
  583. // partitions
  584. //
  585. if (!SpIsArc()) {
  586. //
  587. // He's an MBR disk, so we can rely on the BootIndicator field.
  588. //
  589. pDiskRegion->IsSystemPartition = PartInfo->Mbr.BootIndicator;
  590. }
  591. //
  592. // Don't assign drive letters to OEM partitions
  593. //
  594. if (IsOEMPartition(SPPT_GET_PARTITION_TYPE(pDiskRegion))) {
  595. AssignDriveLetter = FALSE;
  596. }
  597. } else {
  598. //
  599. // He's not MBR, look at his PartitionType (which is a GUID).
  600. //
  601. pDiskRegion->IsSystemPartition = FALSE;
  602. if(IsEqualGUID(&(PartInfo->Gpt.PartitionType), &(PARTITION_SYSTEM_GUID))) {
  603. pDiskRegion->IsSystemPartition = TRUE;
  604. AssignDriveLetter = FALSE;
  605. #ifdef _IA64_
  606. //
  607. // We assign a Drive letter for ESP in the Recovery Console
  608. // for IA64
  609. //
  610. if (ForceConsole) {
  611. AssignDriveLetter = TRUE;
  612. }
  613. #endif
  614. }
  615. }
  616. if (SPPT_IS_REGION_SYSTEMPARTITION(pDiskRegion)) {
  617. SysPartFound = TRUE;
  618. }
  619. //
  620. // FtPartition
  621. //
  622. if( DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR ) {
  623. //
  624. // He's an MBR disk, so we can rely on the PartitionType field.
  625. //
  626. pDiskRegion->FtPartition = IsFTPartition(PartInfo->Mbr.PartitionType);
  627. } else {
  628. //
  629. // He's not MBR. Assume he's GPT and look at his PartitionType (which is a GUID).
  630. //
  631. pDiskRegion->FtPartition = FALSE;
  632. }
  633. //
  634. // DynamicVolume
  635. // DynamicVolumeSuitableForOS
  636. //
  637. if( DriveLayoutEx->PartitionStyle == PARTITION_STYLE_MBR ) {
  638. //
  639. // He's an MBR disk, so we can rely on the PartitionType field.
  640. //
  641. pDiskRegion->DynamicVolume = (PartInfo->Mbr.PartitionType == PARTITION_LDM);
  642. } else {
  643. //
  644. // He's not MBR. Assume he's GPT and look at his PartitionType (which is a GUID).
  645. //
  646. pDiskRegion->DynamicVolume = FALSE;
  647. if( !memcmp(&PartInfo->Gpt.PartitionType,
  648. &PARTITION_LDM_DATA_GUID, sizeof(GUID)) ) {
  649. //
  650. // The GUIDs match.
  651. pDiskRegion->DynamicVolume = TRUE;
  652. }
  653. }
  654. if (pDiskRegion->DynamicVolume) {
  655. TypeNameId = SP_TEXT_PARTITION_NAME_DYNVOL;
  656. }
  657. //
  658. // if MSFT reserved partition (we need to keep track of it but
  659. // not process it)
  660. //
  661. if((DriveLayoutEx->PartitionStyle == PARTITION_STYLE_GPT) &&
  662. (IsEqualGUID(&(PartInfo->Gpt.PartitionType), &PARTITION_MSFT_RESERVED_GUID) ||
  663. IsEqualGUID(&(PartInfo->Gpt.PartitionType), &PARTITION_LDM_METADATA_GUID) ||
  664. IS_OEM_PARTITION_GPT(PartInfo->Gpt.Attributes))) {
  665. pDiskRegion->IsReserved = TRUE;
  666. AssignDriveLetter = FALSE;
  667. //
  668. // Get the type name from the resources.
  669. //
  670. SpFormatMessage(pDiskRegion->TypeName,
  671. sizeof(pDiskRegion->TypeName),
  672. SP_TEXT_PARTNAME_RESERVED);
  673. continue;
  674. }
  675. //
  676. // Assume we can't install on this dynamic volume.
  677. //
  678. pDiskRegion->DynamicVolumeSuitableForOS = FALSE;
  679. //
  680. // For the following entries, we need an Open handle to this partition.
  681. //
  682. //
  683. // If the partition just got created, we may have to wait for
  684. // a few seconds before its actually available
  685. //
  686. // Note : We wait for 20 secs at the max for each partition
  687. //
  688. for (Count = 0; (Count < 10); Count++) {
  689. //
  690. // Open the handle to the required partition
  691. //
  692. Status = SpOpenPartition( DevicePath,
  693. PartInfo->PartitionNumber,
  694. &Handle,
  695. FALSE );
  696. if((Status == STATUS_NO_SUCH_DEVICE) ||
  697. (Status == STATUS_OBJECT_NAME_NOT_FOUND)) {
  698. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  699. "SETUP: SpPtInitializeDiskAreas: unable to open partition%d on device %ws (%lx)\n",
  700. PartInfo->PartitionNumber,
  701. DevicePath,
  702. Status ));
  703. DelayTime.HighPart = -1; // relative time
  704. DelayTime.LowPart = (ULONG)(-20000000); // 2 secs in 100ns interval
  705. KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
  706. } else {
  707. break;
  708. }
  709. }
  710. //
  711. // Need the partition handle to continue
  712. //
  713. if (!NT_SUCCESS(Status)) {
  714. //
  715. // ignore the error while trying to open dynamic disks
  716. //
  717. if (SPPT_IS_REGION_DYNAMIC_VOLUME(pDiskRegion)) {
  718. Status = STATUS_SUCCESS;
  719. }
  720. //
  721. // Get the type name from the resources.
  722. //
  723. SpFormatMessage(pDiskRegion->TypeName,
  724. sizeof(pDiskRegion->TypeName),
  725. TypeNameId);
  726. continue;
  727. }
  728. //
  729. // Check, if installtion can be done on the dynamic volume
  730. //
  731. if( pDiskRegion->DynamicVolume ) {
  732. //
  733. // Call disk manager to tell me if it's okay to
  734. // install on this dynamic volume. If I get back
  735. // anything but STATUS_SUCCESS, then assume we
  736. // can't install here.
  737. //
  738. Status = ZwDeviceIoControlFile(
  739. Handle,
  740. NULL,
  741. NULL,
  742. NULL,
  743. &IoStatusBlock,
  744. IOCTL_VOLUME_IS_PARTITION,
  745. NULL,
  746. 0,
  747. NULL,
  748. 0 );
  749. if( NT_SUCCESS(Status) ){
  750. pDiskRegion->DynamicVolumeSuitableForOS = TRUE;
  751. }
  752. }
  753. //
  754. // Filesystem
  755. //
  756. pFSInfo = SpMemAlloc( sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + (MAX_PATH*2) );
  757. if( !pFSInfo ) {
  758. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  759. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  760. ZwClose( Handle );
  761. Status = STATUS_NO_MEMORY;
  762. break;
  763. }
  764. RtlZeroMemory( pFSInfo, sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + (MAX_PATH*2) );
  765. Status = ZwQueryVolumeInformationFile(
  766. Handle,
  767. &IoStatusBlock,
  768. pFSInfo,
  769. sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + (MAX_PATH*2),
  770. FileFsAttributeInformation );
  771. if (!NT_SUCCESS(Status)) {
  772. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  773. "SETUP: SpPtInitializeDiskAreas: Failed to retrieve partition attribute information (%lx)\n",
  774. Status ));
  775. } else {
  776. if (!wcscmp(pFSInfo->FileSystemName, L"NTFS")) {
  777. pDiskRegion->Filesystem = FilesystemNtfs;
  778. TypeNameId = SP_TEXT_FS_NAME_3;
  779. } else if (!wcscmp(pFSInfo->FileSystemName, L"FAT")) {
  780. pDiskRegion->Filesystem = FilesystemFat;
  781. TypeNameId = SP_TEXT_FS_NAME_2;
  782. } else if (!wcscmp(pFSInfo->FileSystemName, L"FAT32")) {
  783. pDiskRegion->Filesystem = FilesystemFat32;
  784. TypeNameId = SP_TEXT_FS_NAME_4;
  785. } else if (TypeNameId == SP_TEXT_UNKNOWN){
  786. ULONG Index;
  787. pDiskRegion->Filesystem = FilesystemUnknown;
  788. //
  789. // Make sure it was not already created new partition
  790. //
  791. for (Index = 0; Index < NewPartitionCount; Index++) {
  792. if (pDiskRegion->StartSector == NewPartitions[Index]) {
  793. pDiskRegion->Filesystem = FilesystemNewlyCreated;
  794. TypeNameId = SP_TEXT_FS_NAME_1;
  795. break;
  796. }
  797. }
  798. }
  799. }
  800. //
  801. // if we cannot determine the partition type, then try
  802. // to use the known name from partition id.
  803. //
  804. if ((TypeNameId == SP_TEXT_UNKNOWN) && SPPT_IS_MBR_DISK(DiskNumber)) {
  805. ULONG PartitionType = SPPT_GET_PARTITION_TYPE(pDiskRegion);
  806. if (PartitionType < 256) {
  807. UCHAR NameId = PartitionNameIds[SPPT_GET_PARTITION_TYPE(pDiskRegion)];
  808. if (NameId != 0xFF) {
  809. TypeNameId = SP_TEXT_PARTITION_NAME_BASE + NameId;
  810. }
  811. }
  812. }
  813. //
  814. // Get the type name from the resources.
  815. //
  816. SpFormatMessage(pDiskRegion->TypeName,
  817. sizeof(pDiskRegion->TypeName),
  818. TypeNameId);
  819. SpMemFree( pFSInfo );
  820. //
  821. // FreeSpaceKB and BytesPerCluster (only if we know what FS it is)
  822. //
  823. if ((pDiskRegion->Filesystem != FilesystemUnknown) &&
  824. (pDiskRegion->Filesystem != FilesystemNewlyCreated)) {
  825. //
  826. // Delete \pagefile.sys if it's there. This makes disk free space
  827. // calculations a little easier.
  828. //
  829. MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
  830. if( !MyTempBuffer ) {
  831. //
  832. // No memory...
  833. //
  834. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  835. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  836. Status = STATUS_NO_MEMORY;
  837. break;
  838. }
  839. SpNtNameFromRegion( pDiskRegion,
  840. MyTempBuffer,
  841. MAX_NTPATH_LENGTH,
  842. PrimaryArcPath );
  843. SpConcatenatePaths( MyTempBuffer, L"" );
  844. SpDeleteFile( MyTempBuffer, L"pagefile.sys", NULL );
  845. SpMemFree( MyTempBuffer );
  846. MyTempBuffer = NULL;
  847. pSizeInfo = SpMemAlloc( sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2) );
  848. if( !pSizeInfo ) {
  849. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  850. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  851. ZwClose( Handle );
  852. Status = STATUS_NO_MEMORY;
  853. break;
  854. }
  855. RtlZeroMemory( pSizeInfo, sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2) );
  856. Status = ZwQueryVolumeInformationFile(
  857. Handle,
  858. &IoStatusBlock,
  859. pSizeInfo,
  860. sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2),
  861. FileFsSizeInformation );
  862. //
  863. // Waiting for another 2 secs for the volume to appear
  864. //
  865. if (Status == STATUS_NO_SUCH_DEVICE) {
  866. //
  867. // Wait for 2 seconds
  868. //
  869. DelayTime.HighPart = -1; // relative time
  870. DelayTime.LowPart = (ULONG)(-20000000); // 2 secs in 100ns interval
  871. KeDelayExecutionThread(KernelMode, FALSE, &DelayTime);
  872. RtlZeroMemory( pSizeInfo, sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2) );
  873. Status = ZwQueryVolumeInformationFile(
  874. Handle,
  875. &IoStatusBlock,
  876. pSizeInfo,
  877. sizeof(FILE_FS_SIZE_INFORMATION) + (MAX_PATH*2),
  878. FileFsSizeInformation );
  879. }
  880. if (!NT_SUCCESS(Status)) {
  881. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  882. "SETUP: SpPtInitializeDiskAreas: Failed to retrieve disk(%d)partition(%d) sizing information (%lx)\n",
  883. DiskNumber,
  884. pDiskRegion->PartitionNumber,
  885. Status ));
  886. } else {
  887. LARGE_INTEGER FreeBytes;
  888. FreeBytes = RtlExtendedIntegerMultiply(
  889. pSizeInfo->AvailableAllocationUnits,
  890. pSizeInfo->SectorsPerAllocationUnit * pSizeInfo->BytesPerSector );
  891. pDiskRegion->FreeSpaceKB = RtlExtendedLargeIntegerDivide( FreeBytes,
  892. 1024, &r ).LowPart;
  893. if(r >= 512) {
  894. pDiskRegion->FreeSpaceKB++;
  895. }
  896. //
  897. // Sigh... Legacy stuff. SpPtDeterminePartitionGood() will want this
  898. // field so that he knows what the free-space+space_from_local_source is.
  899. //
  900. pDiskRegion->AdjustedFreeSpaceKB = pDiskRegion->FreeSpaceKB;
  901. pDiskRegion->BytesPerCluster =
  902. pSizeInfo->SectorsPerAllocationUnit * pSizeInfo->BytesPerSector;
  903. }
  904. SpMemFree( pSizeInfo );
  905. //
  906. // VolumeLabel
  907. //
  908. pLabelInfo = SpMemAlloc( sizeof(FILE_FS_VOLUME_INFORMATION) + (MAX_PATH*2) );
  909. if( !pFSInfo ) {
  910. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  911. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  912. ZwClose( Handle );
  913. Status = STATUS_NO_MEMORY;
  914. break;
  915. }
  916. RtlZeroMemory( pLabelInfo, sizeof(FILE_FS_VOLUME_INFORMATION) + (MAX_PATH*2) );
  917. Status = ZwQueryVolumeInformationFile(
  918. Handle,
  919. &IoStatusBlock,
  920. pLabelInfo,
  921. sizeof(FILE_FS_VOLUME_INFORMATION) + (MAX_PATH*2),
  922. FileFsVolumeInformation );
  923. if (!NT_SUCCESS(Status)) {
  924. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  925. "SETUP: SpPtInitializeDiskAreas: Failed to retrieve volume information (%lx)\n", Status));
  926. } else {
  927. ULONG SaveCharCount;
  928. //
  929. // We'll only save away the first <n> characters of
  930. // the volume label.
  931. //
  932. SaveCharCount = min( pLabelInfo->VolumeLabelLength + sizeof(WCHAR),
  933. sizeof(pDiskRegion->VolumeLabel) ) / sizeof(WCHAR);
  934. if(SaveCharCount) {
  935. SaveCharCount--; // allow for terminating NUL.
  936. }
  937. wcsncpy( pDiskRegion->VolumeLabel,
  938. pLabelInfo->VolumeLabel,
  939. SaveCharCount );
  940. pDiskRegion->VolumeLabel[SaveCharCount] = 0;
  941. }
  942. SpMemFree( pLabelInfo );
  943. } else {
  944. //
  945. // Free space is what ever the partition size is
  946. //
  947. pDiskRegion->FreeSpaceKB = (pDiskRegion->SectorCount *
  948. Disk->Geometry.BytesPerSector) / 1024;
  949. pDiskRegion->AdjustedFreeSpaceKB = pDiskRegion->FreeSpaceKB;
  950. }
  951. //
  952. // Assign the drive letter if required
  953. //
  954. if (AssignDriveLetter) {
  955. //
  956. // Retrieve nt pathname for this region.
  957. //
  958. MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
  959. if( !MyTempBuffer ) {
  960. //
  961. // No memory...
  962. //
  963. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  964. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  965. Status = STATUS_NO_MEMORY;
  966. break;
  967. }
  968. SpNtNameFromRegion( pDiskRegion,
  969. MyTempBuffer,
  970. MAX_NTPATH_LENGTH,
  971. PrimaryArcPath );
  972. //
  973. // Assign the drive letter
  974. //
  975. pDiskRegion->DriveLetter = SpGetDriveLetter( MyTempBuffer, NULL );
  976. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  977. "SETUP: SpPtInitializeDiskAreas: Partition = %ls, DriveLetter = %wc: \n",
  978. MyTempBuffer, pDiskRegion->DriveLetter));
  979. SpMemFree( MyTempBuffer );
  980. MyTempBuffer = NULL;
  981. }
  982. //
  983. // See if this guy has the local source.
  984. //
  985. //
  986. MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
  987. if( !MyTempBuffer ) {
  988. //
  989. // No memory...
  990. //
  991. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  992. "SETUP: SpPtInitializeDiskAreas: SpMemAlloc failed!\n" ));
  993. Status = STATUS_NO_MEMORY;
  994. break;
  995. }
  996. SpNtNameFromRegion( pDiskRegion,
  997. MyTempBuffer,
  998. MAX_NTPATH_LENGTH,
  999. PrimaryArcPath );
  1000. SpConcatenatePaths( MyTempBuffer, L"" );
  1001. //
  1002. // Don't need this guy anymore.
  1003. //
  1004. ZwClose( Handle );
  1005. if( WinntSetup && !WinntFromCd && !LocalSourceRegion &&
  1006. SpNFilesExist(MyTempBuffer, LocalSourceFiles, ELEMENT_COUNT(LocalSourceFiles), TRUE) ) {
  1007. LocalSourceRegion = pDiskRegion;
  1008. pDiskRegion->IsLocalSource = TRUE;
  1009. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1010. "SETUP: %ws is the local source partition.\n", MyTempBuffer));
  1011. } else {
  1012. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1013. "SETUP: %ws is not the local source partition.\n", MyTempBuffer));
  1014. }
  1015. SpMemFree( MyTempBuffer );
  1016. MyTempBuffer = NULL;
  1017. Status = STATUS_SUCCESS;
  1018. }
  1019. //
  1020. // Go ahead and locate the system partitions on this disk
  1021. //
  1022. if (SpIsArc()) {
  1023. if (!SysPartFound) {
  1024. SpPtnLocateDiskSystemPartitions(DiskNumber);
  1025. } else {
  1026. ValidArcSystemPartition = TRUE;
  1027. }
  1028. }
  1029. }
  1030. //
  1031. // Update the boot entries to reflect the
  1032. // new region pointers
  1033. //
  1034. SpUpdateRegionForBootEntries();
  1035. if (NewPartitions) {
  1036. SpMemFree(NewPartitions);
  1037. }
  1038. SpMemFree( DriveLayoutEx );
  1039. return Status;
  1040. }
  1041. NTSTATUS
  1042. SpPtnSortDiskAreas(
  1043. IN ULONG DiskNumber
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. Examine the partitions defined on this disk and sort them
  1048. according to their location on the disk.
  1049. Arguments:
  1050. DiskNumber - supplies the disk number of the disk whose partitions
  1051. we want to inspect.
  1052. Return Value:
  1053. NTSTATUS. If all goes well, we should be returing STATUS_SUCCESS.
  1054. --*/
  1055. {
  1056. NTSTATUS Status = STATUS_SUCCESS;
  1057. PDISK_REGION pTempDiskRegion = NULL;
  1058. PDISK_REGION pCurrentDiskRegion = NULL;
  1059. PDISK_REGION pPreviousDiskRegion = NULL;
  1060. //
  1061. // Get a pointer to the list of regions.
  1062. //
  1063. pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  1064. if( !pCurrentDiskRegion ) {
  1065. //
  1066. // Odd. Either something is very wrong, or
  1067. // this disk simply has no partitions, which is
  1068. // certainly possible. Assume the best.
  1069. //
  1070. return STATUS_SUCCESS;
  1071. }
  1072. //
  1073. // We got something. Go sort the list. There
  1074. // can't be very many partitions, so just bubble-sort.
  1075. //
  1076. while( pCurrentDiskRegion->Next ) {
  1077. //
  1078. // There's another partition ahead of
  1079. // us. See if we need to switch places.
  1080. //
  1081. if( pCurrentDiskRegion->StartSector > pCurrentDiskRegion->Next->StartSector ) {
  1082. //
  1083. // Yes, we need to swap these 2 entries.
  1084. // Fixup the pointers.
  1085. //
  1086. if( pPreviousDiskRegion ) {
  1087. //
  1088. // 1. Set the previous disk region to point to
  1089. // the region after us.
  1090. //
  1091. pPreviousDiskRegion->Next = pCurrentDiskRegion->Next;
  1092. } else {
  1093. //
  1094. // We're at the very beginning of the linked
  1095. // list.
  1096. //
  1097. //
  1098. // 1. Set the disk's region pointer to point to
  1099. // the region after us.
  1100. //
  1101. PartitionedDisks[DiskNumber].PrimaryDiskRegions = pCurrentDiskRegion->Next;
  1102. }
  1103. //
  1104. // 2. Set our our next region's Next pointer to
  1105. // come back to us.
  1106. //
  1107. pTempDiskRegion = pCurrentDiskRegion->Next->Next;
  1108. pCurrentDiskRegion->Next->Next = pCurrentDiskRegion;
  1109. //
  1110. // 3. Set our own pointer to a couple of regions ahead.
  1111. //
  1112. pCurrentDiskRegion->Next = pTempDiskRegion;
  1113. //
  1114. // Now reset so we start the sort over again.
  1115. //
  1116. pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  1117. pPreviousDiskRegion = NULL;
  1118. } else {
  1119. //
  1120. // No need to swap these two regions in our list. Increment
  1121. // our pointers and continue.
  1122. //
  1123. pPreviousDiskRegion = pCurrentDiskRegion;
  1124. pCurrentDiskRegion = pCurrentDiskRegion->Next;
  1125. }
  1126. }
  1127. return Status;
  1128. }
  1129. NTSTATUS
  1130. SpPtnInitRegionFromDisk(
  1131. IN ULONG DiskNumber,
  1132. OUT PDISK_REGION Region
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. Given the disk id, creates a disk region representing
  1137. the whole disk
  1138. Arguments:
  1139. DiskNumber : Disk Id
  1140. Region : Region which gets initialized on return
  1141. Return Value:
  1142. STATUS_SUCCESS if successful, otherwise STATUS_INVALID_PARAMETER
  1143. --*/
  1144. {
  1145. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1146. if (Region) {
  1147. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  1148. RtlZeroMemory(Region, sizeof(DISK_REGION));
  1149. //
  1150. // Note : Most of the fields below don't need to be initialized
  1151. // because of the memset above, but its done for sake of
  1152. // clarity
  1153. //
  1154. Region->DiskNumber = DiskNumber;
  1155. Region->StartSector = Disk->Geometry.SectorsPerTrack;
  1156. Region->SectorCount = Disk->DiskSizeSectors - Region->StartSector;
  1157. SPPT_SET_REGION_PARTITIONED(Region, FALSE);
  1158. Region->PartitionNumber = 0;
  1159. Region->MbrInfo = NULL;
  1160. Region->TablePosition = 0;
  1161. Region->IsSystemPartition = FALSE;
  1162. Region->IsLocalSource = FALSE;
  1163. Region->Filesystem = FilesystemUnknown;
  1164. Region->FreeSpaceKB = Disk->DiskSizeMB * 1024;
  1165. Region->BytesPerCluster = -1;
  1166. Region->AdjustedFreeSpaceKB = Region->FreeSpaceKB;
  1167. Region->DriveLetter = 0;
  1168. Region->FtPartition = FALSE;
  1169. Region->DynamicVolume = FALSE;
  1170. Region->DynamicVolumeSuitableForOS = FALSE;
  1171. Status = STATUS_SUCCESS;
  1172. }
  1173. return Status;
  1174. }
  1175. NTSTATUS
  1176. SpPtnFillDiskFreeSpaceAreas(
  1177. IN ULONG DiskNumber
  1178. )
  1179. /*++
  1180. Routine Description:
  1181. This function will go peruse all partitions on the disk. If there are
  1182. any free regions on the disk, we'll create a region entry and
  1183. mark it as unformatted.
  1184. Arguments:
  1185. DiskNumber - supplies the disk number of the disk whose partitions
  1186. we want to inspect.
  1187. Return Value:
  1188. NTSTATUS. If all goes well, we should be returing STATUS_SUCCESS.
  1189. --*/
  1190. {
  1191. NTSTATUS Status = STATUS_SUCCESS;
  1192. PDISK_REGION pTempDiskRegion;
  1193. PDISK_REGION pCurrentDiskRegion = NULL;
  1194. ULONGLONG NextStart;
  1195. ULONGLONG NextSize;
  1196. PDISK_REGION FirstContainer = NULL;
  1197. //
  1198. // Get a pointer to the list of regions.
  1199. //
  1200. pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  1201. if( !pCurrentDiskRegion ) {
  1202. //
  1203. // Odd. Either something is very wrong, or
  1204. // this disk simply has no partitions, which is
  1205. // certainly possible. Assume the best and
  1206. // create one region entry that encompasses all
  1207. // space on the disk, but is unpartitioned.
  1208. //
  1209. pCurrentDiskRegion = SpMemAlloc(sizeof(DISK_REGION));
  1210. if (pCurrentDiskRegion) {
  1211. Status = SpPtnInitRegionFromDisk(DiskNumber, pCurrentDiskRegion);
  1212. } else {
  1213. Status = STATUS_NO_MEMORY;
  1214. }
  1215. if (NT_SUCCESS(Status)) {
  1216. ASSERT(!PartitionedDisks[DiskNumber].PrimaryDiskRegions);
  1217. PartitionedDisks[DiskNumber].PrimaryDiskRegions =
  1218. pCurrentDiskRegion;
  1219. SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
  1220. }
  1221. return Status;
  1222. }
  1223. //
  1224. // The regions are already sorted according to their relative
  1225. // position on the disk, so before we go through them, let's
  1226. // see if there's any empty space on the disk occurring *before*
  1227. // the first partition.
  1228. //
  1229. if( pCurrentDiskRegion->StartSector > SPPT_DISK_TRACK_SIZE(DiskNumber) ) {
  1230. //
  1231. // Yep. Make a region descriptor for this guy (if he is more than
  1232. // one cylinder in size)
  1233. //
  1234. NextStart = SPPT_DISK_TRACK_SIZE(DiskNumber);
  1235. NextSize = pCurrentDiskRegion->StartSector - NextStart;
  1236. //
  1237. // The first partition can start at first track offset. So this need not always
  1238. // be of minimum cylinder size
  1239. //
  1240. if (NextSize >= (SPPT_DISK_CYLINDER_SIZE(DiskNumber) - SPPT_DISK_TRACK_SIZE(DiskNumber))) {
  1241. pTempDiskRegion = SpMemAlloc( sizeof(DISK_REGION) );
  1242. if(!pTempDiskRegion) {
  1243. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1244. "SETUP: SpPtFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
  1245. return STATUS_NO_MEMORY;
  1246. }
  1247. RtlZeroMemory( pTempDiskRegion, sizeof(DISK_REGION) );
  1248. pTempDiskRegion->DiskNumber = DiskNumber;
  1249. pTempDiskRegion->StartSector = NextStart;
  1250. pTempDiskRegion->SectorCount = NextSize;
  1251. //
  1252. // Put this region before the current region
  1253. //
  1254. pTempDiskRegion->Next = pCurrentDiskRegion;
  1255. PartitionedDisks[DiskNumber].PrimaryDiskRegions = pTempDiskRegion;
  1256. }
  1257. }
  1258. //
  1259. // Now go through the regions, inserting regions to account for any
  1260. // empty space between the partitions.
  1261. //
  1262. while( pCurrentDiskRegion ) {
  1263. if( !pCurrentDiskRegion->Next ) {
  1264. NextStart = 0;
  1265. //
  1266. // if this is container partition then all the space in this
  1267. // container is free space
  1268. //
  1269. if (SPPT_IS_MBR_DISK(DiskNumber) &&
  1270. IsContainerPartition(SPPT_GET_PARTITION_TYPE(pCurrentDiskRegion))) {
  1271. PDISK_REGION ExtFree = NULL;
  1272. ASSERT(FirstContainer == NULL);
  1273. //
  1274. // We add one here because we should be able to differentiate the starting
  1275. // free region inside the extended partition from the extended partition
  1276. // itself.
  1277. //
  1278. NextStart = pCurrentDiskRegion->StartSector + 1;
  1279. NextSize = pCurrentDiskRegion->SectorCount;
  1280. if (NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) {
  1281. PDISK_REGION ExtFree = SpMemAlloc(sizeof(DISK_REGION));
  1282. if (!ExtFree) {
  1283. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1284. "SETUP: SpPtFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
  1285. return STATUS_NO_MEMORY;
  1286. }
  1287. RtlZeroMemory(ExtFree, sizeof(DISK_REGION));
  1288. ExtFree->DiskNumber = DiskNumber;
  1289. ExtFree->StartSector = NextStart;
  1290. ExtFree->SectorCount = NextSize;
  1291. pCurrentDiskRegion->Next = ExtFree;
  1292. //
  1293. // make the new region current region !!!
  1294. //
  1295. pCurrentDiskRegion = ExtFree;
  1296. NextStart = NextStart + NextSize - 1;
  1297. } else {
  1298. //
  1299. // Make sure that the free space after the extended
  1300. // partition is accounted for
  1301. //
  1302. NextStart = 0;
  1303. }
  1304. }
  1305. //
  1306. // There's nothing behind of us. See if there's any
  1307. // empty space back there that's unaccounted for.
  1308. //
  1309. if (!NextStart) {
  1310. NextStart = pCurrentDiskRegion->StartSector +
  1311. pCurrentDiskRegion->SectorCount;
  1312. }
  1313. if (PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors > NextStart) {
  1314. NextSize = PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors -
  1315. NextStart;
  1316. } else {
  1317. NextSize = 0;
  1318. }
  1319. //
  1320. // For ASR, allow partition size on GPT disks to be >= 1 sector.
  1321. // In all other cases, partition size must be >= 1 cylinder.
  1322. //
  1323. if ((NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) ||
  1324. (SpDrEnabled() && SPPT_IS_GPT_DISK(DiskNumber) && (NextSize >= 1))
  1325. ) {
  1326. //
  1327. // Yes there is. We need to make a region behind us that's
  1328. // marked as unpartitioned.
  1329. //
  1330. if (FirstContainer) {
  1331. //
  1332. // there could be free space at the end of the
  1333. // extended partition. Mark is separately from
  1334. // the free space after the extended partition
  1335. //
  1336. ULONGLONG ExtEnd = FirstContainer->StartSector +
  1337. FirstContainer->SectorCount;
  1338. ULONGLONG ExtFreeStart = NextStart;
  1339. ULONGLONG ExtFreeSize = (ExtEnd > ExtFreeStart) ?
  1340. ExtEnd - ExtFreeStart : 0;
  1341. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1342. "SETUP:SpPtnFillDiskFreeSpaces():EFS:%I64d,EFSize:%I64d,EE:%I64d\n",
  1343. ExtFreeStart,
  1344. ExtFreeSize,
  1345. ExtEnd));
  1346. if (ExtFreeSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) {
  1347. PDISK_REGION ExtFree = SpMemAlloc(sizeof(DISK_REGION));
  1348. if (!ExtFree) {
  1349. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1350. "SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
  1351. return STATUS_NO_MEMORY;
  1352. }
  1353. RtlZeroMemory(ExtFree, sizeof(DISK_REGION));
  1354. ExtFree->DiskNumber = DiskNumber;
  1355. ExtFree->StartSector = ExtFreeStart;
  1356. ExtFree->SectorCount = ExtFreeSize;
  1357. pCurrentDiskRegion->Next = ExtFree;
  1358. pCurrentDiskRegion = ExtFree;
  1359. NextStart = ExtEnd;
  1360. NextSize = 0;
  1361. if (PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors > NextStart) {
  1362. NextSize = PartitionedDisks[DiskNumber].HardDisk->DiskSizeSectors -
  1363. NextStart;
  1364. }
  1365. } else {
  1366. //
  1367. // Get rid of any free space at the end which is lesser than a
  1368. // cylinder partition inside the exteneded partition before
  1369. // we try to see if there is adequate space at the end of extended
  1370. // partition
  1371. //
  1372. NextStart += ExtFreeSize;
  1373. NextSize -= ExtFreeSize;
  1374. }
  1375. }
  1376. //
  1377. // For ASR, allow partition size on GPT disks to be >= 1 sector.
  1378. // In all other cases, partition size must be >= 1 cylinder.
  1379. //
  1380. if ((NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) ||
  1381. (SpDrEnabled() && SPPT_IS_GPT_DISK(DiskNumber) && (NextSize >= 1))
  1382. ) {
  1383. pTempDiskRegion = SpMemAlloc( sizeof(DISK_REGION) );
  1384. if(!pTempDiskRegion) {
  1385. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1386. "SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
  1387. return(STATUS_NO_MEMORY);
  1388. }
  1389. RtlZeroMemory( pTempDiskRegion, sizeof(DISK_REGION) );
  1390. pTempDiskRegion->DiskNumber = DiskNumber;
  1391. pTempDiskRegion->StartSector = NextStart;
  1392. pTempDiskRegion->SectorCount = NextSize;
  1393. pCurrentDiskRegion->Next = pTempDiskRegion;
  1394. }
  1395. }
  1396. //
  1397. // We just processed the last region. If there was any free space
  1398. // behind that partition, we just accounted for it, in which case
  1399. // we're done with this disk. If there wasn't any free space behind
  1400. // that partition, then we're also done.
  1401. //
  1402. return( Status );
  1403. } else {
  1404. //
  1405. // There's another partition ahead of us.
  1406. // See if there's free space between them.
  1407. //
  1408. NextStart = pCurrentDiskRegion->StartSector +
  1409. pCurrentDiskRegion->SectorCount;
  1410. if (pCurrentDiskRegion->Next->StartSector > NextStart) {
  1411. NextSize = pCurrentDiskRegion->Next->StartSector - NextStart;
  1412. //
  1413. // Check to see if its a container partition
  1414. //
  1415. if (!FirstContainer && SPPT_IS_MBR_DISK(DiskNumber) &&
  1416. IsContainerPartition(SPPT_GET_PARTITION_TYPE(pCurrentDiskRegion))) {
  1417. FirstContainer = pCurrentDiskRegion;
  1418. NextStart = pCurrentDiskRegion->StartSector + 1;
  1419. NextSize = pCurrentDiskRegion->Next->StartSector - NextStart;
  1420. }
  1421. if (FirstContainer) {
  1422. ULONGLONG ExtEnd = FirstContainer->StartSector +
  1423. FirstContainer->SectorCount;
  1424. ULONGLONG FreeEnd = pCurrentDiskRegion->Next->StartSector;
  1425. //
  1426. // Split the free region into extended free and normal free region
  1427. // if needed
  1428. //
  1429. if (!SPPT_IS_REGION_CONTAINED(FirstContainer, pCurrentDiskRegion->Next) &&
  1430. (ExtEnd < FreeEnd)) {
  1431. PDISK_REGION ExtFree = NULL;
  1432. //
  1433. // If the free space doesnt overlap the extended partition
  1434. // then do not subtract from extended end
  1435. //
  1436. if (NextStart < ExtEnd){
  1437. NextSize = ExtEnd - NextStart;
  1438. }
  1439. if (NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) {
  1440. ExtFree = SpMemAlloc(sizeof(DISK_REGION));
  1441. if (!ExtFree) {
  1442. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1443. "SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
  1444. return STATUS_NO_MEMORY;
  1445. }
  1446. RtlZeroMemory(ExtFree, sizeof(DISK_REGION));
  1447. ExtFree->DiskNumber = DiskNumber;
  1448. ExtFree->StartSector = NextStart;
  1449. ExtFree->SectorCount = NextSize;
  1450. //
  1451. // insert the region after the current one
  1452. //
  1453. ExtFree->Next = pCurrentDiskRegion->Next;
  1454. pCurrentDiskRegion->Next = ExtFree;
  1455. //
  1456. // make the new region current
  1457. //
  1458. pCurrentDiskRegion = ExtFree;
  1459. }
  1460. //
  1461. // Fix the next free region start
  1462. //
  1463. NextStart += NextSize;
  1464. if (FreeEnd > NextStart) {
  1465. NextSize = FreeEnd - NextStart;
  1466. } else {
  1467. NextSize = 0;
  1468. }
  1469. }
  1470. }
  1471. } else {
  1472. //
  1473. // skip container partitions (expect for starting free space
  1474. // inside the container partition)
  1475. //
  1476. NextSize = 0;
  1477. if (SPPT_IS_MBR_DISK(DiskNumber) &&
  1478. IsContainerPartition(SPPT_GET_PARTITION_TYPE(pCurrentDiskRegion)) &&
  1479. (pCurrentDiskRegion->Next->StartSector > pCurrentDiskRegion->StartSector)) {
  1480. if (!FirstContainer) {
  1481. FirstContainer = pCurrentDiskRegion;
  1482. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1483. "SETUP:SpPtnFillDiskFreeSpaces():%p is the first container\n",
  1484. FirstContainer));
  1485. }
  1486. //
  1487. // We add one here because we should be able to differentiate the starting
  1488. // free region inside the extended partition from the extended partition
  1489. // itself.
  1490. //
  1491. NextStart = pCurrentDiskRegion->StartSector + 1;
  1492. NextSize = pCurrentDiskRegion->Next->StartSector - NextStart + 1;
  1493. }
  1494. }
  1495. //
  1496. // For ASR, allow partition size on GPT disks to be >= 1 sector.
  1497. // In all other cases, partition size must be >= 1 cylinder.
  1498. //
  1499. if ((NextSize >= SPPT_DISK_CYLINDER_SIZE(DiskNumber)) ||
  1500. (SpDrEnabled() && SPPT_IS_GPT_DISK(DiskNumber) && (NextSize >= 1))
  1501. ) {
  1502. //
  1503. // Yes, there's free space and we need to insert
  1504. // a region here to represent it. Allocate a region
  1505. // and initialize it as unpartitioned space.
  1506. //
  1507. pTempDiskRegion = SpMemAlloc( sizeof(DISK_REGION) );
  1508. if(!pTempDiskRegion) {
  1509. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1510. "SETUP: SpPtnFillFreeSpaceAreas: SpMemAlloc failed!\n" ));
  1511. return(STATUS_NO_MEMORY);
  1512. }
  1513. RtlZeroMemory( pTempDiskRegion, sizeof(DISK_REGION) );
  1514. pTempDiskRegion->DiskNumber = DiskNumber;
  1515. pTempDiskRegion->StartSector = NextStart;
  1516. pTempDiskRegion->SectorCount = NextSize;
  1517. pTempDiskRegion->Next = pCurrentDiskRegion->Next;
  1518. pCurrentDiskRegion->Next = pTempDiskRegion;
  1519. pCurrentDiskRegion = pTempDiskRegion;
  1520. }
  1521. }
  1522. pCurrentDiskRegion = pCurrentDiskRegion->Next;
  1523. }
  1524. return Status;
  1525. }
  1526. #ifdef NOT_USED_CURRENTLY
  1527. VOID
  1528. SpDeleteDiskDriveLetters(
  1529. VOID
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. This routine will delete all drive letters assigned to disks and CD-ROM drives. The deletion will
  1534. occur only if setup was started booting from the CD or boot floppies (in which case drive letter
  1535. migration does not take place), and only if the non-removable dissks have no partitioned spaces.
  1536. This ensures that on a clean install from the CD or boot floppies, the drive letters assigned to
  1537. partitions on removable disks and CD-ROM drives will always be greater than the drive letters assigned
  1538. to partitions on non-removable disks (unless the partitions on the removable disks were created before
  1539. the ones in the removable disks, during textmode setup).
  1540. Arguments:
  1541. None.
  1542. Return Value:
  1543. None.
  1544. --*/
  1545. {
  1546. ULONG DiskNumber;
  1547. PDISK_REGION pDiskRegion;
  1548. PWCHAR MyTempBuffer = NULL;
  1549. unsigned pass;
  1550. BOOLEAN PartitionedSpaceFound = FALSE;
  1551. if( WinntSetup ) {
  1552. //
  1553. // If setup started from winnt32.exe then do not delete the drive letters since we want to preserve them
  1554. //
  1555. return;
  1556. }
  1557. //
  1558. // Setup started booting from a CD.
  1559. //
  1560. // Find out if the disks contain at least one partition that is not a container.
  1561. // Note that we do not take into consideration partitions that are on removable media.
  1562. // This is to avoid the situation in which a newly created partition on a non-removable disk ends up with
  1563. // a drive letter that is greater than the one assigned to an existing partition on a removable disk.
  1564. //
  1565. for(DiskNumber = 0; !PartitionedSpaceFound && (DiskNumber<HardDiskCount); DiskNumber++) {
  1566. if( PartitionedDisks[DiskNumber].HardDisk->Geometry.MediaType != RemovableMedia) {
  1567. //
  1568. // This disk isn't removable. Let's look at all the areas and see
  1569. // if there's anything that's partitioned.
  1570. //
  1571. pDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  1572. while( pDiskRegion ) {
  1573. if(SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
  1574. PartitionedSpaceFound = TRUE;
  1575. }
  1576. //
  1577. // Now get the next region on this disk.
  1578. //
  1579. pDiskRegion = pDiskRegion->Next;
  1580. }
  1581. }
  1582. }
  1583. if( !PartitionedSpaceFound ) {
  1584. //
  1585. // There are no partitions on this machine. Delete all drive letters
  1586. // so that the drive letters for each CD-ROM drive also get deleted.
  1587. //
  1588. // We'll do this by sending an IOCTL to the MountManager and ask him
  1589. // to whack all his knowledge of drive letters.
  1590. //
  1591. NTSTATUS Status;
  1592. OBJECT_ATTRIBUTES Obja;
  1593. IO_STATUS_BLOCK IoStatusBlock;
  1594. UNICODE_STRING UnicodeString;
  1595. HANDLE Handle;
  1596. INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
  1597. Status = ZwOpenFile( &Handle,
  1598. (ACCESS_MASK)(FILE_GENERIC_READ | FILE_GENERIC_WRITE),
  1599. &Obja,
  1600. &IoStatusBlock,
  1601. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1602. FILE_NON_DIRECTORY_FILE );
  1603. if( NT_SUCCESS( Status ) ) {
  1604. MOUNTMGR_MOUNT_POINT MountMgrMountPoint;
  1605. MountMgrMountPoint.SymbolicLinkNameOffset = 0;
  1606. MountMgrMountPoint.SymbolicLinkNameLength = 0;
  1607. MountMgrMountPoint.UniqueIdOffset = 0;
  1608. MountMgrMountPoint.UniqueIdLength = 0;
  1609. MountMgrMountPoint.DeviceNameOffset = 0;
  1610. MountMgrMountPoint.DeviceNameLength = 0;
  1611. Status = ZwDeviceIoControlFile( Handle,
  1612. NULL,
  1613. NULL,
  1614. NULL,
  1615. &IoStatusBlock,
  1616. IOCTL_MOUNTMGR_DELETE_POINTS,
  1617. &MountMgrMountPoint,
  1618. sizeof( MOUNTMGR_MOUNT_POINT ),
  1619. TemporaryBuffer,
  1620. sizeof( TemporaryBuffer ) );
  1621. if( !NT_SUCCESS( Status ) ) {
  1622. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1623. "SETUP: Unable to delete drive letters. "
  1624. "ZwDeviceIoControl( IOCTL_MOUNTMGR_DELETE_POINTS ) failed."
  1625. "Status = %lx \n", Status));
  1626. } else {
  1627. //
  1628. // If the drive letters got deleted then reset the drive letters assigned to all partitions.
  1629. // Note that we only really care about resetting the drive letters on the partitions on the
  1630. // removable disks, since, if we got that far, there won't be any partition on the non-removable
  1631. // disks
  1632. //
  1633. for(DiskNumber = 0; DiskNumber<HardDiskCount; DiskNumber++) {
  1634. //
  1635. // This disk isn't removable. Let's look at all the areas and see
  1636. // if there's anything that's partitioned.
  1637. //
  1638. pDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  1639. while( pDiskRegion ) {
  1640. pDiskRegion->DriveLetter = 0;
  1641. //
  1642. // Now get the next region on this disk.
  1643. //
  1644. pDiskRegion = pDiskRegion->Next;
  1645. }
  1646. }
  1647. }
  1648. ZwClose( Handle );
  1649. } else {
  1650. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1651. "SETUP: Unable to delete drive letters. "
  1652. "ZwOpenFile( %ls ) failed. Status = %lx \n",
  1653. MOUNTMGR_DEVICE_NAME,
  1654. Status));
  1655. }
  1656. }
  1657. }
  1658. NTSTATUS
  1659. SpAssignDiskDriveLetters(
  1660. VOID
  1661. )
  1662. /*++
  1663. Routine Description:
  1664. Arguments:
  1665. Return Value:
  1666. --*/
  1667. {
  1668. NTSTATUS Status = STATUS_SUCCESS;
  1669. ULONG DiskNumber;
  1670. PDISK_REGION pDiskRegion;
  1671. PWCHAR MyTempBuffer = NULL;
  1672. unsigned pass;
  1673. //
  1674. // Before initializing the drive letters, delete them if necessary.
  1675. // This is to get rid of the letters assigned to CD-ROM drives and removables, when the disks have no
  1676. // partitioned space.
  1677. //
  1678. SpDeleteDiskDriveLetters();
  1679. //
  1680. // Initialize all drive letters to nothing.
  1681. // If it the region is a partitioned space, then assign a drive letter also.
  1682. //
  1683. for( DiskNumber=0; DiskNumber<HardDiskCount; DiskNumber++ ) {
  1684. pDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  1685. while( pDiskRegion ) {
  1686. pDiskRegion->DriveLetter = 0;
  1687. if(SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
  1688. //
  1689. // Retrieve nt pathname for this region.
  1690. //
  1691. MyTempBuffer = (PWCHAR)SpMemAlloc( MAX_NTPATH_LENGTH );
  1692. if( !MyTempBuffer ) {
  1693. //
  1694. // No memory...
  1695. //
  1696. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1697. "SETUP: SpPtAssignDriveLetters: SpMemAlloc failed!\n" ));
  1698. return(STATUS_NO_MEMORY);
  1699. }
  1700. SpNtNameFromRegion( pDiskRegion,
  1701. MyTempBuffer,
  1702. MAX_NTPATH_LENGTH,
  1703. PrimaryArcPath );
  1704. //
  1705. // Assign the drive letter.
  1706. //
  1707. pDiskRegion->DriveLetter = SpGetDriveLetter( MyTempBuffer, NULL );
  1708. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1709. "SETUP: SpPtAssignDriveLetters: Partition = %ls, DriveLetter = %wc: \n",
  1710. MyTempBuffer, pDiskRegion->DriveLetter));
  1711. SpMemFree( MyTempBuffer );
  1712. MyTempBuffer = NULL;
  1713. }
  1714. //
  1715. // Now get the next region on this disk.
  1716. //
  1717. pDiskRegion = pDiskRegion->Next;
  1718. }
  1719. }
  1720. return( Status );
  1721. }
  1722. #endif // NOT_USED_CURRENTLY
  1723. //
  1724. // ============================================================================
  1725. // ============================================================================
  1726. //
  1727. // The following code provides support for disk/partition selection.
  1728. //
  1729. // ============================================================================
  1730. // ============================================================================
  1731. //
  1732. #define MENU_LEFT_X 3
  1733. #define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
  1734. #define MENU_INDENT 4
  1735. extern ULONG PartitionMnemonics[];
  1736. VOID
  1737. SpPtnAutoCreatePartitions(
  1738. IN PVOID SifHandle,
  1739. IN PWSTR SetupSourceDevicePath,
  1740. IN PWSTR DirectoryOnSetupSource
  1741. )
  1742. /*++
  1743. Routine Description:
  1744. If there are no partitions on any disks, create some.
  1745. Arguments:
  1746. SifHandle : Handle to txtsetup.sif
  1747. SetupSourceDevicePath : Device from which setup was launced
  1748. DirectoryOnSetupSource : Directory from where the kernel was loaded on
  1749. Setup device
  1750. Return Value:
  1751. None.
  1752. --*/
  1753. {
  1754. PDISK_REGION p = NULL;
  1755. PDISK_REGION Region = NULL;
  1756. ULONG Index;
  1757. BOOLEAN Found = FALSE;
  1758. WCHAR RegionStr[128] = {0};
  1759. NTSTATUS FormatStatus;
  1760. ULONG MyPartitionSizeMB = 0;
  1761. NTSTATUS Status;
  1762. KdPrintEx(( DPFLTR_SETUP_ID,
  1763. DPFLTR_INFO_LEVEL,
  1764. "SETUP: SpPtnAutoCreatePartitions - Checking for any existing partitions.\n" ));
  1765. Found = FALSE;
  1766. for(Index = 0; (Index < HardDiskCount) && (!Found); Index++) {
  1767. Region = SPPT_GET_PRIMARY_DISK_REGION( Index );
  1768. while( (Region) && (!Found) ) {
  1769. if( Region->PartitionedSpace &&
  1770. !SPPT_IS_REGION_RESERVED_PARTITION(Region)) {
  1771. //
  1772. // He's got something on the disk.
  1773. //
  1774. Found = TRUE;
  1775. }
  1776. Region = Region->Next;
  1777. }
  1778. }
  1779. if( !Found ) {
  1780. //
  1781. // The disks are all empty. We need to go
  1782. // create some partitions for the installation.
  1783. //
  1784. KdPrintEx(( DPFLTR_SETUP_ID,
  1785. DPFLTR_INFO_LEVEL,
  1786. "SETUP: SpPtnAutoCreatePartitions - No existing partitions were found.\n" ));
  1787. if (SpIsArc()) {
  1788. //
  1789. // If we're on an ARC machine, go create a system
  1790. // partition first.
  1791. //
  1792. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1793. "SETUP: SpPtnAutoCreatePartitions - About to "
  1794. "auto-generate a system partition.\n" ));
  1795. #if defined(_IA64_)
  1796. Status = SpPtnCreateESP(FALSE);
  1797. if (!NT_SUCCESS(Status)) {
  1798. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1799. "SETUP: SpPtnAutoCreatePartitions - Could not "
  1800. "autocreate ESP : %lx\n",
  1801. Status));
  1802. return;
  1803. }
  1804. #endif
  1805. }
  1806. //
  1807. // Now create a partition to install the operating system.
  1808. //
  1809. // To do this, we're going to take the following steps:
  1810. // 1. go find some free space on a disk that's big enough.
  1811. // 2. create a partitions that's half of this guy's free space, (make the
  1812. // partition at least 4Gig).
  1813. //
  1814. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1815. "SETUP: SpPtnAutoCreatePartitions - About to "
  1816. "auto-generate an installation partition.\n" ));
  1817. Found = FALSE;
  1818. for(Index = 0; (Index < HardDiskCount) && (!Found); Index++) {
  1819. Region = SPPT_GET_PRIMARY_DISK_REGION( Index );
  1820. while( (Region) && (!Found) ) {
  1821. if( (!Region->PartitionedSpace) &&
  1822. (SPPT_REGION_FREESPACE_KB(Region)/1024 >= (SUGGESTED_INSTALL_PARTITION_SIZE_MB)) ) {
  1823. KdPrintEx(( DPFLTR_SETUP_ID,
  1824. DPFLTR_INFO_LEVEL,
  1825. "SETUP: SpPtnAutoCreatePartitions - I found an area big enough for an installation.\n" ));
  1826. MyPartitionSizeMB = max( (ULONG)(SPPT_REGION_FREESPACE_KB(Region)/(2*1024)), SUGGESTED_INSTALL_PARTITION_SIZE_MB );
  1827. if( SpPtnDoCreate( Region,
  1828. &p,
  1829. TRUE,
  1830. MyPartitionSizeMB,
  1831. NULL,
  1832. FALSE ) ) {
  1833. KdPrintEx(( DPFLTR_SETUP_ID,
  1834. DPFLTR_INFO_LEVEL,
  1835. "SETUP: SpPtnAutoCreatePartitions - I just created an installation partition.\n" ));
  1836. //
  1837. // Got it.
  1838. //
  1839. Found = TRUE;
  1840. Region = p;
  1841. //
  1842. // Now format it.
  1843. //
  1844. swprintf( RegionStr,
  1845. L"\\Harddisk%u\\Partition%u",
  1846. Region->DiskNumber,
  1847. Region->PartitionNumber );
  1848. //
  1849. // Format the system region with NTFS file system
  1850. //
  1851. KdPrintEx(( DPFLTR_SETUP_ID,
  1852. DPFLTR_INFO_LEVEL,
  1853. "SETUP: SpPtnAutoCreatePartitions - I'm about to go format the installation partition.\n" ));
  1854. FormatStatus = SpDoFormat( RegionStr,
  1855. Region,
  1856. FilesystemNtfs,
  1857. TRUE,
  1858. TRUE,
  1859. FALSE,
  1860. SifHandle,
  1861. 0, // default cluster size
  1862. SetupSourceDevicePath,
  1863. DirectoryOnSetupSource );
  1864. KdPrintEx(( DPFLTR_SETUP_ID,
  1865. DPFLTR_INFO_LEVEL,
  1866. "SETUP: SpPtnAutoCreatePartitions - Format of an installation partition is complete.\n" ));
  1867. } else {
  1868. KdPrintEx(( DPFLTR_SETUP_ID,
  1869. DPFLTR_INFO_LEVEL,
  1870. "SETUP: SpPtnAutoCreatePartitions - I failed to create an installation partition.\n" ));
  1871. }
  1872. }
  1873. Region = Region->Next;
  1874. }
  1875. }
  1876. } else {
  1877. // let 'em know
  1878. KdPrintEx(( DPFLTR_SETUP_ID,
  1879. DPFLTR_INFO_LEVEL,
  1880. "SETUP: SpPtnAutoCreatePartitions - Existing partitions were found.\n" ));
  1881. }
  1882. }
  1883. NTSTATUS
  1884. SpPtnPrepareDisks(
  1885. IN PVOID SifHandle,
  1886. OUT PDISK_REGION *InstallArea,
  1887. OUT PDISK_REGION *SystemPartitionArea,
  1888. IN PWSTR SetupSourceDevicePath,
  1889. IN PWSTR DirectoryOnSetupSource,
  1890. IN BOOLEAN RemoteBootRepartition
  1891. )
  1892. /*++
  1893. Routine Description:
  1894. Shows the use the disk menu (with partitions) and locates
  1895. the system and boot partition
  1896. Arguments:
  1897. SifHandle : Handle to txtsetup.sif
  1898. InstallArea : Place holder for boot partition
  1899. SystemPartitionArea : Place holder for system partition
  1900. SetupSourceDevicePath : Device from which setup was launced
  1901. DirectoryOnSetupSource : Directory from where the kernel was loaded on
  1902. Setup device
  1903. RemoteBootRePartition : Whether to repartition the disk for remote boot
  1904. Return Value:
  1905. Appropriate status code
  1906. --*/
  1907. {
  1908. NTSTATUS Status = STATUS_SUCCESS;
  1909. WCHAR Buffer[256] = {0};
  1910. ULONG DiskNumber;
  1911. PVOID Menu;
  1912. ULONG MenuTopY;
  1913. ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
  1914. ULONG ValidKeysCmdCons[2] = { ASCI_ESC, 0 };
  1915. ULONG Keypress;
  1916. PDISK_REGION pDiskRegion;
  1917. PDISK_REGION FirstDiskRegion,DefaultDiskRegion;
  1918. BOOLEAN unattended = UnattendedOperation;
  1919. BOOLEAN OldUnattendedOperation;
  1920. BOOLEAN createdMenu;
  1921. ULONG LastUsedDisk = -1;
  1922. BOOLEAN Win9xPartition = FALSE;
  1923. //
  1924. // Do some special partitioning if there's nothing
  1925. // on the disk and the user has asked us to do an express
  1926. // installation.
  1927. //
  1928. if( (!CustomSetup) && (UnattendedOperation) && (HardDiskCount != 0)
  1929. #if defined(REMOTE_BOOT)
  1930. && (!RemoteBootSetup) && (!RemoteInstallSetup)
  1931. #endif
  1932. ) {
  1933. //
  1934. // See if we need to auto-generate some partitions for the
  1935. // installation.
  1936. //
  1937. SpPtnAutoCreatePartitions( SifHandle,
  1938. SetupSourceDevicePath,
  1939. DirectoryOnSetupSource );
  1940. }
  1941. if (SpIsArc()) {
  1942. //
  1943. // Select a system partition from among those defined in NV-RAM.
  1944. //
  1945. *SystemPartitionArea = SpPtnValidSystemPartitionArc(SifHandle,
  1946. SetupSourceDevicePath,
  1947. DirectoryOnSetupSource,
  1948. FALSE);
  1949. if (*SystemPartitionArea) {
  1950. (*SystemPartitionArea)->IsSystemPartition = TRUE;
  1951. }
  1952. }
  1953. //
  1954. // If the user selected any accessibility option and wanted to choose partition, show the partition screen
  1955. //
  1956. if(AccessibleSetup && !AutoPartitionPicker) {
  1957. unattended = FALSE;
  1958. }
  1959. //
  1960. // Save the current unattended mode and put the temp one
  1961. //
  1962. OldUnattendedOperation = UnattendedOperation;
  1963. UnattendedOperation = unattended;
  1964. while(1) {
  1965. createdMenu = FALSE;
  1966. Keypress = 0;
  1967. #if defined(REMOTE_BOOT)
  1968. if (RemoteBootSetup && !RemoteInstallSetup && HardDiskCount == 0) {
  1969. //
  1970. // If there are no hard disks, allow diskless install
  1971. //
  1972. pDiskRegion = NULL;
  1973. //
  1974. // Run through the rest of the code as if the user had just
  1975. // hit enter to select this partition.
  1976. //
  1977. Keypress = ASCI_CR;
  1978. } else
  1979. #endif // defined(REMOTE_BOOT)
  1980. if (unattended && RemoteBootRepartition) {
  1981. ULONG DiskNumber;
  1982. ULONG DiskSpaceRequiredKB = 2 * 1024 * 1024; // 2 GB
  1983. //
  1984. // What's the space we required for installation
  1985. //
  1986. SpFetchDiskSpaceRequirements(SifHandle,
  1987. 4 * 1024,
  1988. &DiskSpaceRequiredKB,
  1989. NULL);
  1990. //
  1991. // Prepare the disk for remote boot installation. This involves
  1992. // converting disk 0 into as big a partition as possible.
  1993. //
  1994. if (*SystemPartitionArea != NULL) {
  1995. DiskNumber = (*SystemPartitionArea)->DiskNumber;
  1996. } else {
  1997. DiskNumber = SpDetermineDisk0();
  1998. }
  1999. #ifdef _IA64_
  2000. Status = SpPtnRepartitionGPTDisk(DiskNumber,
  2001. DiskSpaceRequiredKB,
  2002. &pDiskRegion);
  2003. #else
  2004. Status = SpPtPartitionDiskForRemoteBoot(DiskNumber,
  2005. &pDiskRegion);
  2006. #endif
  2007. if (NT_SUCCESS(Status)) {
  2008. SpPtRegionDescription(
  2009. &PartitionedDisks[pDiskRegion->DiskNumber],
  2010. pDiskRegion,
  2011. Buffer,
  2012. sizeof(Buffer)
  2013. );
  2014. //
  2015. // Run through the rest of the code as if the user had just
  2016. // hit enter to select this partition.
  2017. //
  2018. Keypress = ASCI_CR;
  2019. }
  2020. }
  2021. if (Keypress == 0) {
  2022. //
  2023. // Display the text that goes above the menu on the partitioning screen.
  2024. //
  2025. SpDisplayScreen(ConsoleRunning ? SP_SCRN_PARTITION_CMDCONS:SP_SCRN_PARTITION,
  2026. 3,CLIENT_TOP+1);
  2027. //
  2028. // Calculate menu placement. Leave one blank line
  2029. // and one line for a frame.
  2030. //
  2031. MenuTopY = NextMessageTopLine + 2;
  2032. //
  2033. // Create a menu.
  2034. //
  2035. Menu = SpMnCreate(
  2036. MENU_LEFT_X,
  2037. MenuTopY,
  2038. MENU_WIDTH,
  2039. (VideoVars.ScreenHeight - MenuTopY -
  2040. (SplangQueryMinimizeExtraSpacing() ? 1 : 2) - STATUS_HEIGHT)
  2041. );
  2042. if(!Menu) {
  2043. UnattendedOperation = OldUnattendedOperation;
  2044. return(STATUS_NO_MEMORY);
  2045. }
  2046. createdMenu = TRUE;
  2047. //
  2048. // Build up a menu of partitions and free spaces.
  2049. //
  2050. FirstDiskRegion = NULL;
  2051. for(DiskNumber=0; DiskNumber<HardDiskCount; DiskNumber++) {
  2052. if( !SpPtnGenerateDiskMenu(Menu, DiskNumber, &FirstDiskRegion) ) {
  2053. SpMnDestroy(Menu);
  2054. UnattendedOperation = OldUnattendedOperation;
  2055. return(STATUS_NO_MEMORY);
  2056. }
  2057. }
  2058. ASSERT(FirstDiskRegion);
  2059. //
  2060. // If this is unattended operation, try to use the local source
  2061. // region if there is one. If this fails, the user will have to
  2062. // intervene manually.
  2063. //
  2064. if(!AutoPartitionPicker && unattended && LocalSourceRegion && CustomSetup &&
  2065. (!LocalSourceRegion->DynamicVolume || LocalSourceRegion->DynamicVolumeSuitableForOS)) {
  2066. pDiskRegion = LocalSourceRegion;
  2067. Keypress = ASCI_CR;
  2068. } else {
  2069. pDiskRegion = NULL;
  2070. //
  2071. // Unless we've been told not to, go look at each partition on each
  2072. // disk and see if we can find anything suitable for an OS installation.
  2073. //
  2074. if( AutoPartitionPicker && !ConsoleRunning
  2075. #if defined(REMOTE_BOOT)
  2076. && (!RemoteBootSetup || RemoteInstallSetup)
  2077. #endif // defined(REMOTE_BOOT)
  2078. ) {
  2079. PDISK_REGION pCurrentDiskRegion = NULL;
  2080. ULONG RequiredKB = 0;
  2081. ULONG SectorNo;
  2082. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2083. "SETUP: -------------------------------------------------------------\n" ));
  2084. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2085. "SETUP: Looking for an install partition\n\n" ));
  2086. for( DiskNumber=0;
  2087. ((DiskNumber < HardDiskCount) && (!pCurrentDiskRegion));
  2088. DiskNumber++ ) {
  2089. pCurrentDiskRegion = PartitionedDisks[DiskNumber].PrimaryDiskRegions;
  2090. while( pCurrentDiskRegion ) {
  2091. //
  2092. // Fetch the amount of free space required on the windows nt drive.
  2093. //
  2094. SpFetchDiskSpaceRequirements( SifHandle,
  2095. pCurrentDiskRegion->BytesPerCluster,
  2096. &RequiredKB,
  2097. NULL );
  2098. if( SpPtDeterminePartitionGood(pCurrentDiskRegion, RequiredKB, TRUE) ) {
  2099. //
  2100. // Got it. Remember the partition and pretend the user
  2101. // hit the <enter> key.
  2102. //
  2103. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2104. "SETUP: Selected install partition = "
  2105. "(DiskNumber:%d),(DriveLetter:%wc:),(%ws)\n",
  2106. DiskNumber,pCurrentDiskRegion->DriveLetter,
  2107. pCurrentDiskRegion->VolumeLabel));
  2108. pDiskRegion = pCurrentDiskRegion;
  2109. Keypress = ASCI_CR;
  2110. break;
  2111. }
  2112. pCurrentDiskRegion = pCurrentDiskRegion->Next;
  2113. }
  2114. }
  2115. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2116. "SETUP: -------------------------------------------------------------\n" ));
  2117. }
  2118. if( !pDiskRegion ) {
  2119. //
  2120. // We didn't find any suitable partitions, which means we'll be putting up a
  2121. // menu very quickly. Initialize the partition to highlight in the
  2122. // menu.
  2123. //
  2124. if (LastUsedDisk == -1) {
  2125. DefaultDiskRegion = FirstDiskRegion;
  2126. } else {
  2127. //
  2128. // Select the first region on the disk which the user last
  2129. // operated on
  2130. //
  2131. PDISK_REGION ValidRegion = SPPT_GET_PRIMARY_DISK_REGION(LastUsedDisk);
  2132. while (ValidRegion && SPPT_IS_REGION_CONTAINER_PARTITION(ValidRegion)) {
  2133. ValidRegion = ValidRegion->Next;
  2134. }
  2135. if (!ValidRegion)
  2136. ValidRegion = FirstDiskRegion;
  2137. DefaultDiskRegion = ValidRegion;
  2138. }
  2139. //
  2140. // Call the menu callback to initialize the status line.
  2141. //
  2142. SpPtMenuCallback( (ULONG_PTR)DefaultDiskRegion );
  2143. SpMnDisplay( Menu,
  2144. (ULONG_PTR)DefaultDiskRegion,
  2145. TRUE,
  2146. ConsoleRunning ? ValidKeysCmdCons : ValidKeys,
  2147. PartitionMnemonics,
  2148. SpPtMenuCallback,
  2149. SpPtIsNotReservedPartition,
  2150. &Keypress,
  2151. (PULONG_PTR)(&pDiskRegion) );
  2152. }
  2153. }
  2154. }
  2155. LastUsedDisk = pDiskRegion ? pDiskRegion->DiskNumber : -1;
  2156. //
  2157. // Now act on the user's selection.
  2158. //
  2159. if(Keypress & KEY_MNEMONIC) {
  2160. Keypress &= ~KEY_MNEMONIC;
  2161. }
  2162. //
  2163. // Disallow certain operations on partitions that contain local source
  2164. // or are the system partition (in the amd64/x86 floppiless case).
  2165. //
  2166. switch(Keypress) {
  2167. case MnemonicCreatePartition:
  2168. case MnemonicMakeSystemPartition:
  2169. case MnemonicDeletePartition:
  2170. case MnemonicChangeDiskStyle:
  2171. if( (pDiskRegion->IsLocalSource) ||
  2172. ((Keypress == MnemonicDeletePartition) &&
  2173. (SpPtnIsDeleteAllowedForRegion(pDiskRegion) == FALSE))
  2174. #if defined(_AMD64_) || defined(_X86_)
  2175. || (IsFloppylessBoot &&
  2176. pDiskRegion == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))
  2177. #endif // defined(_AMD64_) || defined(_X86_)
  2178. ) {
  2179. //
  2180. // Inform the user that we can't do this operation on this
  2181. // partition.
  2182. //
  2183. ULONG MyValidKeys[] = { ASCI_CR };
  2184. SpDisplayScreen(SP_SCRN_CONFIRM_INABILITY,3,HEADER_HEIGHT+1);
  2185. SpDisplayStatusOptions(
  2186. DEFAULT_STATUS_ATTRIBUTE,
  2187. SP_STAT_ENTER_EQUALS_CONTINUE,
  2188. 0
  2189. );
  2190. SpInputDrain();
  2191. SpWaitValidKey(MyValidKeys,NULL,NULL);
  2192. //
  2193. // Now change the keypress so we'll fall through the next switch.
  2194. //
  2195. Keypress = MnemonicUnused;
  2196. }
  2197. }
  2198. switch(Keypress) {
  2199. case MnemonicCreatePartition:
  2200. SpPtnDoCreate(pDiskRegion, NULL, FALSE, 0, 0, TRUE);
  2201. break;
  2202. case MnemonicMakeSystemPartition: {
  2203. //
  2204. // Make sure we don't have any other system partition
  2205. //
  2206. if (SPPT_IS_REGION_SYSTEMPARTITION(pDiskRegion)) {
  2207. ValidArcSystemPartition = TRUE;
  2208. }
  2209. if (!ValidArcSystemPartition && pDiskRegion->PartitionedSpace && SpIsArc() &&
  2210. (pDiskRegion->Filesystem != FilesystemNtfs)) {
  2211. if (NT_SUCCESS(SpPtnMakeRegionArcSysPart(pDiskRegion))) {
  2212. PDISK_REGION SysPartRegion = NULL;
  2213. //
  2214. // Ok format the partition if required
  2215. //
  2216. SysPartRegion = SpPtnValidSystemPartitionArc(SifHandle,
  2217. SetupSourceDevicePath,
  2218. DirectoryOnSetupSource,
  2219. FALSE);
  2220. if (SysPartRegion) {
  2221. ULONG SysPartDiskNumber = SysPartRegion->DiskNumber;
  2222. BOOLEAN Changes = FALSE;
  2223. if ((NT_SUCCESS(SpPtnCommitChanges(SysPartDiskNumber,
  2224. &Changes))) &&
  2225. (NT_SUCCESS(SpPtnInitializeDiskDrive(SysPartDiskNumber)))) {
  2226. //
  2227. // create MSR partition if needed
  2228. //
  2229. SpPtnInitializeGPTDisk(SysPartDiskNumber);
  2230. }
  2231. }
  2232. } else {
  2233. ValidArcSystemPartition = FALSE;
  2234. }
  2235. }
  2236. break;
  2237. }
  2238. case MnemonicDeletePartition: {
  2239. BOOLEAN SysPartDeleted = FALSE;
  2240. BOOLEAN DeletionResult;
  2241. SysPartDeleted = SPPT_IS_REGION_SYSTEMPARTITION(pDiskRegion);
  2242. DeletionResult = SpPtnDoDelete(pDiskRegion,
  2243. SpMnGetText(Menu,(ULONG_PTR)pDiskRegion),
  2244. TRUE);
  2245. if (DeletionResult && SysPartDeleted && SpIsArc()) {
  2246. //
  2247. // Find out if there are any other
  2248. // valid system partitions
  2249. //
  2250. SpPtnValidSystemPartitionArc(SifHandle,
  2251. SetupSourceDevicePath,
  2252. DirectoryOnSetupSource,
  2253. FALSE);
  2254. }
  2255. break;
  2256. }
  2257. case MnemonicChangeDiskStyle: {
  2258. //
  2259. // Before changing style make sure, its allowed
  2260. // on this platform for the selected disk
  2261. //
  2262. if (SpPtnIsDiskStyleChangeAllowed(pDiskRegion->DiskNumber)) {
  2263. PARTITION_STYLE Style = SPPT_DEFAULT_PARTITION_STYLE;
  2264. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2265. SP_STAT_PLEASE_WAIT,
  2266. 0);
  2267. //
  2268. // flip the style
  2269. //
  2270. if (!SPPT_IS_RAW_DISK(pDiskRegion->DiskNumber)) {
  2271. Style = SPPT_IS_GPT_DISK(pDiskRegion->DiskNumber) ?
  2272. PARTITION_STYLE_MBR : PARTITION_STYLE_GPT;
  2273. }
  2274. Status = SpPtnInitializeDiskStyle(pDiskRegion->DiskNumber,
  2275. Style, NULL);
  2276. if (NT_SUCCESS(Status)) {
  2277. Status = SpPtnInitializeDiskDrive(pDiskRegion->DiskNumber);
  2278. #if defined(_IA64_)
  2279. //
  2280. // Go and figure out the ESP partitions and
  2281. // initialize the MSR partitions on valid GPT
  2282. // disks, if none present
  2283. //
  2284. if (Style == PARTITION_STYLE_GPT) {
  2285. ULONG DiskNumber = pDiskRegion->DiskNumber;
  2286. if (SpIsArc() && !ValidArcSystemPartition && !SpDrEnabled()) {
  2287. //
  2288. // Create a system partition
  2289. //
  2290. Status = SpPtnCreateESP(TRUE);
  2291. }
  2292. //
  2293. // Initialize the GPT disks, to have MSR
  2294. // partition
  2295. //
  2296. Status = SpPtnInitializeGPTDisk(DiskNumber);
  2297. }
  2298. #endif
  2299. }
  2300. }
  2301. break;
  2302. }
  2303. case KEY_F3:
  2304. SpConfirmExit();
  2305. break;
  2306. case ASCI_ESC:
  2307. if( ConsoleRunning ) {
  2308. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2309. SP_STAT_PLEASE_WAIT,
  2310. 0);
  2311. SpPtDoCommitChanges();
  2312. }
  2313. if (createdMenu) {
  2314. SpMnDestroy(Menu);
  2315. }
  2316. UnattendedOperation = OldUnattendedOperation;
  2317. return(STATUS_SUCCESS);
  2318. case ASCI_CR:
  2319. Win9xPartition = FALSE;
  2320. if( SpPtDoPartitionSelection( &pDiskRegion,
  2321. ((Buffer[0]) ? Buffer : SpMnGetText(Menu,(ULONG_PTR)pDiskRegion)),
  2322. SifHandle,
  2323. unattended,
  2324. SetupSourceDevicePath,
  2325. DirectoryOnSetupSource,
  2326. RemoteBootRepartition,
  2327. &Win9xPartition) ) {
  2328. *InstallArea = pDiskRegion;
  2329. #if defined(REMOTE_BOOT)
  2330. //
  2331. // Set the install region differently if this is a remote
  2332. // boot -- in that case, the install region is always remote.
  2333. //
  2334. if (RemoteBootSetup && !RemoteInstallSetup) {
  2335. *InstallArea = RemoteBootTargetRegion;
  2336. }
  2337. #endif // defined(REMOTE_BOOT)
  2338. //
  2339. // We need to figure out where the system partition is.
  2340. //
  2341. if (!SpIsArc()) {
  2342. *SystemPartitionArea = SpPtnValidSystemPartition();
  2343. } else {
  2344. PWSTR p;
  2345. NTSTATUS TempStatus;
  2346. //
  2347. // Select a system partition from among those defined in NV-RAM.
  2348. // We have to do this again because the user may have deleted the
  2349. // system partition previously detected.
  2350. //
  2351. *SystemPartitionArea = SpPtnValidSystemPartitionArc(SifHandle,
  2352. SetupSourceDevicePath,
  2353. DirectoryOnSetupSource,
  2354. FALSE);
  2355. if (!(*SystemPartitionArea)) {
  2356. SpPtnPromptForSysPart(SifHandle);
  2357. break; // user pressed escape to mark the system partition
  2358. }
  2359. //
  2360. // Make sure we can see the disk from the firmware/BIOS.
  2361. // If not then we need to put up a message asking to enable the
  2362. // ROM BIOS for the disabled disk containing the system partition
  2363. //
  2364. p = SpNtToArc( HardDisks[(*SystemPartitionArea)->DiskNumber].DevicePath,
  2365. PrimaryArcPath );
  2366. if (p == NULL) {
  2367. ULONG ValidKeys[] = { KEY_F3, ASCI_ESC, 0 };
  2368. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2369. "SETUP: Enable the ROM BIOS for the Disk containing system partition\n" ));
  2370. SpDisplayScreen(SP_ENABLE_ESP_DISK_IN_FIRMWARE, 3, HEADER_HEIGHT+1);
  2371. SpDisplayStatusOptions(
  2372. DEFAULT_STATUS_ATTRIBUTE,
  2373. SP_STAT_F3_EQUALS_EXIT,
  2374. 0);
  2375. //
  2376. // Wait for user input
  2377. //
  2378. SpInputDrain();
  2379. switch (SpWaitValidKey(ValidKeys, NULL, NULL)){
  2380. case KEY_F3 :
  2381. // User has chosen to reboot
  2382. SpDone(0,FALSE,FALSE);
  2383. case ASCI_ESC:
  2384. // User wants to go to the partitioning screen
  2385. break;
  2386. }
  2387. break;
  2388. }
  2389. //
  2390. // Disallow installation onto ESP / MSR
  2391. //
  2392. if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(*InstallArea) ||
  2393. SPPT_IS_REGION_MSFT_RESERVED(*InstallArea)) {
  2394. ULONG ValidKeys[] = { ASCI_CR, 0 };
  2395. SpDisplayScreen(SP_ESP_INSTALL_PARTITION_SAME, 3, HEADER_HEIGHT+1);
  2396. SpDisplayStatusOptions(
  2397. DEFAULT_STATUS_ATTRIBUTE,
  2398. SP_STAT_ENTER_EQUALS_CONTINUE,
  2399. 0);
  2400. //
  2401. // Wait for user input
  2402. //
  2403. SpInputDrain();
  2404. SpWaitValidKey(ValidKeys, NULL, NULL);
  2405. break;
  2406. }
  2407. //
  2408. // Disallow non GPT ESPs
  2409. //
  2410. if (SpIsArc() && !SPPT_IS_GPT_DISK((*SystemPartitionArea)->DiskNumber)) {
  2411. ULONG ValidKeys[] = { ASCI_CR, 0 };
  2412. SpDisplayScreen(SP_NON_GPT_SYSTEM_PARTITION, 3, HEADER_HEIGHT+1);
  2413. SpDisplayStatusOptions(
  2414. DEFAULT_STATUS_ATTRIBUTE,
  2415. SP_STAT_ENTER_EQUALS_CONTINUE,
  2416. 0);
  2417. //
  2418. // Wait for user input
  2419. //
  2420. SpInputDrain();
  2421. SpWaitValidKey(ValidKeys, NULL, NULL);
  2422. break;
  2423. }
  2424. //
  2425. // Disallow installation if MSR does not exist on the disk containing the ESP.
  2426. //
  2427. TempStatus = SpPtnInitializeGPTDisk((*SystemPartitionArea)->DiskNumber);
  2428. if (NT_SUCCESS(TempStatus) &&
  2429. (!SpIsMSRPresentOnDisk((*SystemPartitionArea)->DiskNumber))){
  2430. ULONG ValidKeys[] = { ASCI_CR, 0 };
  2431. SpDisplayScreen(SP_MSR_NOT_PRESENT, 3, HEADER_HEIGHT+1);
  2432. SpDisplayStatusOptions(
  2433. DEFAULT_STATUS_ATTRIBUTE,
  2434. SP_STAT_ENTER_EQUALS_CONTINUE,
  2435. 0);
  2436. //
  2437. // Wait for user input
  2438. //
  2439. SpInputDrain();
  2440. SpWaitValidKey(ValidKeys, NULL, NULL);
  2441. break;
  2442. }
  2443. }
  2444. //
  2445. // We're done here.
  2446. //
  2447. if (createdMenu) {
  2448. SpMnDestroy(Menu);
  2449. }
  2450. #if defined(REMOTE_BOOT)
  2451. ASSERT(*SystemPartitionArea ||
  2452. (RemoteBootSetup && !RemoteInstallSetup && (HardDiskCount == 0)));
  2453. #else
  2454. ASSERT(*SystemPartitionArea);
  2455. ASSERT((*SystemPartitionArea)->Filesystem >= FilesystemFat);
  2456. #endif // defined(REMOTE_BOOT)
  2457. #ifdef _X86_
  2458. //
  2459. // If we are installing on to the same partition as Win9x then
  2460. // remove the boot entry for the old operating system
  2461. //
  2462. if (Win9xPartition) {
  2463. DiscardOldSystemLine = TRUE;
  2464. }
  2465. #endif
  2466. UnattendedOperation = OldUnattendedOperation;
  2467. return(STATUS_SUCCESS);
  2468. } else {
  2469. //
  2470. // Something happened when we tried to select the
  2471. // partition. Make sure that autopartition-picker
  2472. // doesn't invoke next time through our while loop.
  2473. //
  2474. AutoPartitionPicker = FALSE;
  2475. }
  2476. break;
  2477. }
  2478. if (createdMenu) {
  2479. SpMnDestroy(Menu);
  2480. }
  2481. unattended = FALSE;
  2482. }
  2483. }
  2484. BOOLEAN
  2485. SpPtnGenerateDiskMenu(
  2486. IN PVOID Menu,
  2487. IN ULONG DiskNumber,
  2488. OUT PDISK_REGION *FirstDiskRegion
  2489. )
  2490. /*++
  2491. Routine Description:
  2492. Examine the disk for partitioning information and fill in our
  2493. menu.
  2494. Arguments:
  2495. DiskNumber - supplies the disk number of the disk whose partitions
  2496. we want to inspect for determining their types.
  2497. Return Value:
  2498. TRUE Everything went okay.
  2499. FALSE Something horrible happened.
  2500. --*/
  2501. {
  2502. WCHAR Buffer[128];
  2503. ULONG MessageId;
  2504. PDISK_REGION Region = NULL;
  2505. WCHAR DriveLetter[3];
  2506. WCHAR PartitionName[128];
  2507. ULONGLONG FreeSpaceMB;
  2508. ULONGLONG AreaSizeMB;
  2509. ULONGLONG AreaSizeBytes;
  2510. ULONGLONG OneMB = 1024 * 1024;
  2511. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  2512. PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  2513. //
  2514. // Get a pointer to the list of regions.
  2515. //
  2516. Region = PartDisk->PrimaryDiskRegions;
  2517. //
  2518. // Add the disk name/description.
  2519. //
  2520. if(!SpMnAddItem(Menu, Disk->Description, MENU_LEFT_X, MENU_WIDTH, FALSE, 0)) {
  2521. return(FALSE);
  2522. }
  2523. //
  2524. // Only add a line between the disk name and partitions if we have space on
  2525. // the screen. Not fatal if the space can't be added.
  2526. //
  2527. if(!SplangQueryMinimizeExtraSpacing()) {
  2528. SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0);
  2529. }
  2530. //
  2531. // If the disk is off-line, add a message indicating such.
  2532. //
  2533. if((Disk->Status == DiskOffLine) || !Region) {
  2534. MessageId = SP_TEXT_DISK_OFF_LINE;
  2535. if( Disk->Characteristics & FILE_REMOVABLE_MEDIA ) {
  2536. //
  2537. // This is removable media, then just tell the user there's
  2538. // no media in the drive.
  2539. //
  2540. MessageId = SP_TEXT_HARD_DISK_NO_MEDIA;
  2541. }
  2542. SpFormatMessage( Buffer,
  2543. sizeof(Buffer),
  2544. MessageId );
  2545. return SpMnAddItem(Menu,
  2546. Buffer,
  2547. MENU_LEFT_X + MENU_INDENT,
  2548. MENU_WIDTH - (2 * MENU_INDENT),
  2549. FALSE,
  2550. 0);
  2551. }
  2552. //
  2553. // Now iterate through the areas on the disk and insert that info into the
  2554. // menu.
  2555. //
  2556. while( Region ) {
  2557. if (!SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
  2558. //
  2559. // remember the very first area that we examine.
  2560. //
  2561. if(*FirstDiskRegion == NULL) {
  2562. *FirstDiskRegion = Region;
  2563. }
  2564. //
  2565. // Figure out how big this disk area is and how much
  2566. // free space we've got.
  2567. //
  2568. if (Region->AdjustedFreeSpaceKB != -1) {
  2569. FreeSpaceMB = Region->AdjustedFreeSpaceKB / 1024;
  2570. } else {
  2571. FreeSpaceMB = 0;
  2572. }
  2573. AreaSizeBytes = Region->SectorCount * Disk->Geometry.BytesPerSector;
  2574. AreaSizeMB = AreaSizeBytes / OneMB;
  2575. if ((AreaSizeBytes % OneMB) > (OneMB / 2))
  2576. AreaSizeMB++;
  2577. /*
  2578. SpPtDumpDiskRegion(Region);
  2579. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2580. "SETUP: Menu Item Details Free:%I64d,%I64d,%I64d\n",
  2581. FreeSpaceMB, AreaSizeBytes, AreaSizeMB));
  2582. */
  2583. //
  2584. // See if this guy's partitioned.
  2585. //
  2586. if(SPPT_IS_REGION_PARTITIONED(Region)){
  2587. //
  2588. // Pickup the driveletter
  2589. //
  2590. if( Region->DriveLetter ) {
  2591. DriveLetter[0] = Region->DriveLetter;
  2592. } else {
  2593. DriveLetter[0] = L'-';
  2594. }
  2595. DriveLetter[1] = L':';
  2596. DriveLetter[2] = 0;
  2597. //
  2598. // Format the partition name
  2599. //
  2600. PartitionName[0] = 0;
  2601. SpPtnGetPartitionName(Region,
  2602. PartitionName,
  2603. sizeof(PartitionName)/sizeof(PartitionName[0]));
  2604. SpFormatMessage( Buffer,
  2605. sizeof( Buffer ),
  2606. SP_TEXT_REGION_DESCR_1,
  2607. DriveLetter,
  2608. SplangPadString(-35, PartitionName),
  2609. (ULONG)AreaSizeMB,
  2610. (ULONG)FreeSpaceMB );
  2611. } else {
  2612. //
  2613. // It's an unformatted area. Use a different message.
  2614. //
  2615. SpFormatMessage( Buffer,
  2616. sizeof( Buffer ),
  2617. SP_TEXT_REGION_DESCR_3,
  2618. (ULONG)AreaSizeMB );
  2619. }
  2620. //
  2621. // Add the formatted information into the menu.
  2622. //
  2623. if(!SpMnAddItem(Menu, Buffer, MENU_LEFT_X + MENU_INDENT,
  2624. MENU_WIDTH - (2 * MENU_INDENT), TRUE, (ULONG_PTR)Region)) {
  2625. return(FALSE);
  2626. }
  2627. }
  2628. Region = Region->Next;
  2629. }
  2630. return (SplangQueryMinimizeExtraSpacing() ?
  2631. TRUE : SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0));
  2632. }
  2633. PDISK_REGION
  2634. SpPtnValidSystemPartition(
  2635. VOID
  2636. )
  2637. /*++
  2638. Routine Description:
  2639. Determine whether there is a valid disk partition suitable for use
  2640. as the system partition on an amd64/x86 machine (ie, C:).
  2641. A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable.
  2642. If there is a partition that meets these criteria that is marked active,
  2643. then it is the system partition, regardless of whether there are other
  2644. partitions that also meet the criteria.
  2645. Arguments:
  2646. None.
  2647. Return Value:
  2648. Pointer to a disk region descriptor for a suitable system partition (C:)
  2649. for an amd64/x86 machine.
  2650. NULL if no such partition currently exists.
  2651. --*/
  2652. {
  2653. PDISK_REGION ActiveRegion , FirstRegion, CurrRegion;
  2654. PHARD_DISK Disk = NULL;
  2655. ULONG DiskNumber;
  2656. DiskNumber = SpDetermineDisk0();
  2657. #if defined(REMOTE_BOOT)
  2658. //
  2659. // If this is a diskless remote boot setup, there is no drive 0.
  2660. //
  2661. if ( DiskNumber == (ULONG)-1 ) {
  2662. return NULL;
  2663. }
  2664. #endif // defined(REMOTE_BOOT)
  2665. if (!PartitionedDisks) {
  2666. return NULL;
  2667. }
  2668. //
  2669. // Look for the active partition on drive 0
  2670. // and for the first recognized primary partition on drive 0.
  2671. //
  2672. CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2673. FirstRegion = NULL;
  2674. ActiveRegion = NULL;
  2675. while (CurrRegion) {
  2676. if (SPPT_IS_REGION_PRIMARY_PARTITION(CurrRegion)) {
  2677. UCHAR PartitionType = SPPT_GET_PARTITION_TYPE(CurrRegion);
  2678. if(!IsContainerPartition(PartitionType) &&
  2679. ((IsRecognizedPartition(PartitionType)) ||
  2680. (CurrRegion->DynamicVolume && CurrRegion->DynamicVolumeSuitableForOS) ||
  2681. ((RepairWinnt || WinntSetup || SpDrEnabled() ) && CurrRegion->FtPartition))) {
  2682. if (!FirstRegion)
  2683. FirstRegion = CurrRegion;
  2684. if (!ActiveRegion && SPPT_IS_REGION_ACTIVE_PARTITION(CurrRegion)) {
  2685. ActiveRegion = CurrRegion;
  2686. break;
  2687. }
  2688. }
  2689. }
  2690. CurrRegion = CurrRegion->Next;
  2691. }
  2692. #ifdef TESTING_SYSTEM_PARTITION
  2693. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2694. "%p Active, %p First\n",
  2695. ActiveRegion,
  2696. FirstRegion));
  2697. if (ActiveRegion)
  2698. FirstRegion = ActiveRegion;
  2699. ActiveRegion = NULL;
  2700. #endif
  2701. /*
  2702. //
  2703. // Don't do commit here as the multiple caller's are trying
  2704. // to reuse the old region from the existing linked list
  2705. // of regions for the disk after this
  2706. //
  2707. if (!ActiveRegion && FirstRegion) {
  2708. BOOLEAN Changes = FALSE;
  2709. ULONGLONG StartSector = FirstRegion->StartSector;
  2710. SpPtnMakeRegionActive(FirstRegion);
  2711. SPPT_MARK_REGION_AS_SYSTEMPARTITION(FirstRegion, TRUE);
  2712. if (NT_SUCCESS(SpPtnCommitChanges(DiskNumber, &Changes)) && Changes) {
  2713. SPPT_MARK_REGION_AS_ACTIVE(FirstRegion, TRUE);
  2714. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2715. "SETUP:SpPtnValidSystempartition():succeeded in marking\n"));
  2716. } else {
  2717. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2718. "SETUP:SpPtnValidSystempartition():Could not mark the first "
  2719. "partition on primary disk as active\n"));
  2720. }
  2721. }
  2722. */
  2723. //
  2724. // If there is an active, recognized region, use it as the
  2725. // system partition. Otherwise, use the first primary
  2726. // we encountered as the system partition. If there is
  2727. // no recognized primary, then there is no valid system partition.
  2728. //
  2729. return (ActiveRegion ? ActiveRegion : FirstRegion);
  2730. }
  2731. #if 0
  2732. ULONG
  2733. SpDetermineDisk0(
  2734. VOID
  2735. )
  2736. /*++
  2737. Routine Description:
  2738. Determine the real disk 0, which may not be the same as \device\harddisk0.
  2739. Consider the case where we have 2 scsi adapters and
  2740. the NT drivers load in an order such that the one with the BIOS
  2741. gets loaded *second* -- meaning that the system partition is actually
  2742. on disk 1, not disk 0.
  2743. Arguments:
  2744. None.
  2745. Return Value:
  2746. NT disk ordinal suitable for use in generating nt device paths
  2747. of the form \device\harddiskx.
  2748. --*/
  2749. {
  2750. ULONG DiskNumber = SpArcDevicePathToDiskNumber(L"multi(0)disk(0)rdisk(0)");
  2751. #if defined(REMOTE_BOOT)
  2752. //
  2753. // If this is a diskless remote boot setup, there is no drive 0.
  2754. //
  2755. if ( RemoteBootSetup && (DiskNumber == (ULONG)-1) && (HardDiskCount == 0) ) {
  2756. return DiskNumber;
  2757. }
  2758. #endif // defined(REMOTE_BOOT)
  2759. return((DiskNumber == (ULONG)(-1)) ? 0 : DiskNumber);
  2760. }
  2761. #endif
  2762. BOOL
  2763. SpPtnIsSystemPartitionRecognizable(
  2764. VOID
  2765. )
  2766. /*++
  2767. Routine Description:
  2768. Determine whether the active partition is suitable for use
  2769. as the system partition on an amd64/x86 machine (ie, C:).
  2770. A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable.
  2771. Arguments:
  2772. None.
  2773. Return Value:
  2774. TRUE - We found a suitable partition
  2775. FALSE - We didn't find a suitable partition
  2776. --*/
  2777. {
  2778. ULONG DiskNumber;
  2779. PDISK_REGION Region = NULL;
  2780. //
  2781. // Any partitions on NEC98 are primary and active. So don't need to check on NEC98.
  2782. //
  2783. if( IsNEC_98 ) {
  2784. return TRUE;
  2785. }
  2786. DiskNumber = SpDetermineDisk0();
  2787. //
  2788. // Look for the active partition on drive 0
  2789. // and for the first recognized primary partition on drive 0.
  2790. //
  2791. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2792. if (SPPT_IS_GPT_DISK(DiskNumber)) {
  2793. //
  2794. // On GPT we just need a valid formatted partition
  2795. //
  2796. while (Region) {
  2797. if (SPPT_IS_REGION_PARTITIONED(Region) &&
  2798. SPPT_IS_RECOGNIZED_FILESYSTEM(Region->Filesystem)) {
  2799. break;
  2800. }
  2801. Region = Region->Next;
  2802. }
  2803. } else {
  2804. //
  2805. // On MBR we need a valid active formatted partition
  2806. //
  2807. while (Region) {
  2808. if (SPPT_IS_REGION_ACTIVE_PARTITION(Region) &&
  2809. SPPT_IS_RECOGNIZED_FILESYSTEM(Region->Filesystem)) {
  2810. break;
  2811. }
  2812. Region = Region->Next;
  2813. }
  2814. }
  2815. return (Region) ? TRUE : FALSE;
  2816. }
  2817. BOOLEAN
  2818. SpPtnValidSystemPartitionArcRegion(
  2819. IN PVOID SifHandle,
  2820. IN PDISK_REGION Region
  2821. )
  2822. {
  2823. BOOLEAN Valid = FALSE;
  2824. if (SPPT_IS_REGION_SYSTEMPARTITION(Region) &&
  2825. (Region->FreeSpaceKB != -1) &&
  2826. (Region->Filesystem == FilesystemFat)) {
  2827. ULONG TotalSizeOfFilesOnOsWinnt = 0;
  2828. ULONG RequiredSpaceKB = 0;
  2829. //
  2830. // On non-x86 platformrs, specially alpha machines that in general
  2831. // have small system partitions (~3 MB), we should compute the size
  2832. // of the files on \os\winnt (currently, osloader.exe and hall.dll),
  2833. // and consider this size as available disk space. We can do this
  2834. // since these files will be overwritten by the new ones.
  2835. // This fixes the problem that we see on Alpha, when the system
  2836. // partition is too full.
  2837. //
  2838. SpFindSizeOfFilesInOsWinnt( SifHandle,
  2839. Region,
  2840. &TotalSizeOfFilesOnOsWinnt );
  2841. //
  2842. // Transform the size into KB
  2843. //
  2844. TotalSizeOfFilesOnOsWinnt /= 1024;
  2845. //
  2846. // Determine the amount of free space required on a system partition.
  2847. //
  2848. SpFetchDiskSpaceRequirements( SifHandle,
  2849. Region->BytesPerCluster,
  2850. NULL,
  2851. &RequiredSpaceKB );
  2852. if ((Region->FreeSpaceKB + TotalSizeOfFilesOnOsWinnt) >= RequiredSpaceKB) {
  2853. Valid = TRUE;
  2854. }
  2855. }
  2856. return Valid;
  2857. }
  2858. PDISK_REGION
  2859. SpPtnValidSystemPartitionArc(
  2860. IN PVOID SifHandle,
  2861. IN PWSTR SetupSourceDevicePath,
  2862. IN PWSTR DirectoryOnSetupSource,
  2863. IN BOOLEAN SysPartNeeded
  2864. )
  2865. /*++
  2866. Routine Description:
  2867. Determine whether there is a valid disk partition suitable for use
  2868. as the system partition on an ARC machine.
  2869. A partition is suitable if it is marked as a system partition in nvram,
  2870. has the required free space and is formatted with the FAT filesystem.
  2871. Arguments:
  2872. SifHandle - supplies handle to loaded setup information file.
  2873. Return Value:
  2874. Pointer to a disk region descriptor for a suitable system partition.
  2875. Does not return if no such partition exists.
  2876. --*/
  2877. {
  2878. ULONG RequiredSpaceKB = 0;
  2879. PDISK_REGION Region = NULL;
  2880. PPARTITIONED_DISK PartDisk;
  2881. ULONG Index;
  2882. //
  2883. // Go through all the regions. The one that's maked system partition
  2884. // or is valid system partition is used for further validation.
  2885. //
  2886. for(Index = 0; (Index < HardDiskCount) && (!Region); Index++) {
  2887. PartDisk = SPPT_GET_PARTITIONED_DISK(Index);
  2888. Region = SPPT_GET_PRIMARY_DISK_REGION(Index);
  2889. while (Region) {
  2890. if (SPPT_IS_REGION_PARTITIONED(Region) &&
  2891. SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
  2892. break; // found the required region
  2893. }
  2894. Region = Region->Next;
  2895. }
  2896. }
  2897. //
  2898. // If the region is there and not formatted format it as FAT
  2899. // file system
  2900. //
  2901. if (Region && (Region->Filesystem < FilesystemFat)) {
  2902. WCHAR DriveLetterString[4] = {0};
  2903. DriveLetterString[0] = Region->DriveLetter;
  2904. if (!UnattendedOperation) {
  2905. ULONG ValidKeys[] = { KEY_F3, 0 };
  2906. ULONG Mnemonics[] = { MnemonicFormat, 0 };
  2907. ULONG KeyPressed;
  2908. ULONG EscKey = SysPartNeeded ? KEY_F3 : ASCI_ESC;
  2909. ValidKeys[0] = SysPartNeeded ? KEY_F3 : ASCI_ESC;
  2910. SpStartScreen(SysPartNeeded ?
  2911. SP_SCRN_C_UNKNOWN_1 : SP_SCRN_C_UNKNOWN,
  2912. 3,
  2913. HEADER_HEIGHT+1,
  2914. FALSE,
  2915. FALSE,
  2916. DEFAULT_ATTRIBUTE,
  2917. DriveLetterString
  2918. );
  2919. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2920. SP_STAT_F_EQUALS_FORMAT,
  2921. SysPartNeeded ?
  2922. SP_STAT_F3_EQUALS_EXIT : SP_STAT_ESC_EQUALS_CANCEL,
  2923. 0);
  2924. SpInputDrain();
  2925. KeyPressed = SpWaitValidKey(ValidKeys, NULL, Mnemonics);
  2926. if (KeyPressed == EscKey) {
  2927. Region = NULL;
  2928. }
  2929. }
  2930. if (Region) {
  2931. WCHAR RegionStr[128];
  2932. NTSTATUS FormatStatus;
  2933. swprintf( RegionStr,
  2934. L"\\Harddisk%u\\Partition%u",
  2935. Region->DiskNumber,
  2936. Region->PartitionNumber );
  2937. //
  2938. // Format the system region with Fat file system
  2939. //
  2940. FormatStatus = SpDoFormat(RegionStr,
  2941. Region,
  2942. FilesystemFat,
  2943. TRUE,
  2944. TRUE,
  2945. FALSE,
  2946. SifHandle,
  2947. 0, // default cluster size
  2948. SetupSourceDevicePath,
  2949. DirectoryOnSetupSource);
  2950. if (!NT_SUCCESS(FormatStatus)) {
  2951. SpStartScreen(SP_SCRN_SYSPART_FORMAT_ERROR,
  2952. 3,
  2953. HEADER_HEIGHT+1,
  2954. FALSE,
  2955. FALSE,
  2956. DEFAULT_ATTRIBUTE,
  2957. DriveLetterString
  2958. );
  2959. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2960. SP_STAT_F3_EQUALS_EXIT,
  2961. 0);
  2962. SpInputDrain();
  2963. while(SpInputGetKeypress() != KEY_F3) ;
  2964. SpDone(0, FALSE, TRUE);
  2965. }
  2966. //
  2967. // Since we have formatted system partition, make sure
  2968. // it has adequate space to hold the startup files
  2969. //
  2970. if(!SpPtnValidSystemPartitionArcRegion(SifHandle, Region))
  2971. Region = NULL;
  2972. }
  2973. }
  2974. if (!Region && SysPartNeeded) {
  2975. //
  2976. // Make sure we don't look bad.
  2977. //
  2978. if( RequiredSpaceKB == 0 ) {
  2979. SpFetchDiskSpaceRequirements( SifHandle,
  2980. (32 * 1024),
  2981. NULL,
  2982. &RequiredSpaceKB );
  2983. }
  2984. //
  2985. // No valid system partition.
  2986. //
  2987. SpStartScreen(
  2988. SP_SCRN_NO_SYSPARTS,
  2989. 3,
  2990. HEADER_HEIGHT+1,
  2991. FALSE,
  2992. FALSE,
  2993. DEFAULT_ATTRIBUTE,
  2994. RequiredSpaceKB
  2995. );
  2996. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2997. SP_STAT_F3_EQUALS_EXIT,
  2998. 0);
  2999. SpInputDrain();
  3000. //
  3001. // wait for F3
  3002. //
  3003. while (SpInputGetKeypress() != KEY_F3) ;
  3004. SpDone(0, FALSE, TRUE);
  3005. }
  3006. ValidArcSystemPartition = (Region != NULL);
  3007. return Region;
  3008. }
  3009. NTSTATUS
  3010. SpPtnMarkLogicalDrives(
  3011. IN ULONG DiskId
  3012. )
  3013. /*++
  3014. Routine Description:
  3015. Walks through the region linked list and marks the container
  3016. partition and the logical drives. Also marks the free
  3017. space inside container partition as contained space
  3018. Arguments:
  3019. DiskId : Disk to process
  3020. Return Value:
  3021. STATUS_SUCCESS if successful, otherwise approprite error code
  3022. --*/
  3023. {
  3024. NTSTATUS Status = STATUS_SUCCESS;
  3025. if (SPPT_IS_MBR_DISK(DiskId)) {
  3026. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  3027. PDISK_REGION FirstContainer = NULL;
  3028. PDISK_REGION PrevContainer = NULL;
  3029. while (Region) {
  3030. if (SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
  3031. if (!FirstContainer) {
  3032. FirstContainer = Region;
  3033. Region->Container = NULL;
  3034. } else {
  3035. Region->Container = FirstContainer;
  3036. }
  3037. PrevContainer = Region;
  3038. } else {
  3039. if (PrevContainer) {
  3040. if (SPPT_IS_REGION_CONTAINED(PrevContainer, Region)) {
  3041. Region->Container = PrevContainer;
  3042. if (SPPT_IS_REGION_PARTITIONED(Region))
  3043. SPPT_SET_REGION_EPT(Region, EPTLogicalDrive);
  3044. } else {
  3045. if (SPPT_IS_REGION_CONTAINED(FirstContainer, Region))
  3046. Region->Container = FirstContainer;
  3047. }
  3048. }
  3049. }
  3050. Region = Region->Next;
  3051. }
  3052. }
  3053. return Status;
  3054. }
  3055. ULONG
  3056. SpPtnGetOrdinal(
  3057. IN PDISK_REGION Region,
  3058. IN PartitionOrdinalType OrdinalType
  3059. )
  3060. /*++
  3061. Routine Description:
  3062. Gets the Ordinal for the specified region of the specified
  3063. type.
  3064. Arguments:
  3065. Region - Region whose ordinal has to be found
  3066. OrdinalType - Type of ordinal for the region
  3067. Return Value:
  3068. -1 if invalid request, otherwise appropriate ordinal number
  3069. for the region.
  3070. --*/
  3071. {
  3072. ULONG Ordinal = -1;
  3073. if (Region && Region->PartitionNumber && SPPT_IS_REGION_PARTITIONED(Region)) {
  3074. switch (OrdinalType) {
  3075. case PartitionOrdinalOnDisk:
  3076. if (SPPT_IS_MBR_DISK(Region->DiskNumber) &&
  3077. !SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
  3078. Ordinal = Region->TablePosition;
  3079. } else if (SPPT_IS_GPT_DISK(Region->DiskNumber)) {
  3080. Ordinal = Region->TablePosition;
  3081. }
  3082. //
  3083. // Ordinal zero is not valid
  3084. //
  3085. if (Ordinal == 0) {
  3086. Ordinal = -1;
  3087. }
  3088. break;
  3089. default:
  3090. Ordinal = Region->PartitionNumber;
  3091. break;
  3092. }
  3093. }
  3094. if( Ordinal == -1 ) {
  3095. //
  3096. // This is really bad. We're about to
  3097. // fall over. Atleast try...
  3098. //
  3099. ASSERT(FALSE);
  3100. Ordinal = 1;
  3101. KdPrintEx(( DPFLTR_SETUP_ID,
  3102. DPFLTR_INFO_LEVEL,
  3103. "SETUP: SpPtnGetOrdinal: We didn't get an ordinal! Force it.\n" ));
  3104. }
  3105. return Ordinal;
  3106. }
  3107. VOID
  3108. SpPtnGetSectorLayoutInformation(
  3109. IN PDISK_REGION Region,
  3110. OUT PULONGLONG HiddenSectors,
  3111. OUT PULONGLONG VolumeSectorCount
  3112. )
  3113. /*++
  3114. Routine Description:
  3115. Gets the hidden sector and sector count for the formatted
  3116. partitions (volumes)
  3117. Arguments:
  3118. Region - The region for which the sector layout information
  3119. is needed
  3120. HiddenSectors - Place holder to return the # of hidden sectors
  3121. for the region
  3122. VolumeSectorCount- Place holder to return the # of valid sectors
  3123. for the volume
  3124. Return Value:
  3125. None
  3126. --*/
  3127. {
  3128. ULONGLONG Hidden = 0;
  3129. if (Region) {
  3130. if (ARGUMENT_PRESENT(HiddenSectors)) {
  3131. if (Region->PartInfo.PartitionStyle == PARTITION_STYLE_MBR)
  3132. Hidden = Region->PartInfo.Mbr.HiddenSectors;
  3133. else
  3134. Hidden = 0;
  3135. *HiddenSectors = Hidden;
  3136. }
  3137. if (ARGUMENT_PRESENT(VolumeSectorCount)) {
  3138. *VolumeSectorCount = Region->SectorCount - Hidden;
  3139. }
  3140. }
  3141. }
  3142. NTSTATUS
  3143. SpPtnUnlockDevice(
  3144. IN PWSTR DeviceName
  3145. )
  3146. /*++
  3147. Routine Description:
  3148. Attempts to unlock the media for the given device
  3149. name (NT device pathname)
  3150. Arguments:
  3151. DeviceName : The device for which the media needs to be
  3152. unlocked
  3153. Return Value:
  3154. STATUS_SUCCESS if successful, otherwise appropriate error
  3155. code
  3156. --*/
  3157. {
  3158. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3159. if (DeviceName) {
  3160. IO_STATUS_BLOCK IoStatusBlock;
  3161. OBJECT_ATTRIBUTES ObjectAttributes;
  3162. UNICODE_STRING UnicodeString;
  3163. HANDLE Handle;
  3164. PREVENT_MEDIA_REMOVAL PMRemoval;
  3165. INIT_OBJA(&ObjectAttributes,
  3166. &UnicodeString,
  3167. DeviceName);
  3168. //
  3169. // Open the device
  3170. //
  3171. Status = ZwCreateFile(
  3172. &Handle,
  3173. FILE_GENERIC_WRITE,
  3174. &ObjectAttributes,
  3175. &IoStatusBlock,
  3176. NULL, // allocation size
  3177. FILE_ATTRIBUTE_NORMAL,
  3178. FILE_SHARE_VALID_FLAGS, // full sharing
  3179. FILE_OPEN,
  3180. FILE_SYNCHRONOUS_IO_NONALERT,
  3181. NULL, // no EAs
  3182. 0
  3183. );
  3184. if( NT_SUCCESS(Status) ) {
  3185. //
  3186. // Allow media removal
  3187. //
  3188. PMRemoval.PreventMediaRemoval = FALSE;
  3189. Status = ZwDeviceIoControlFile(
  3190. Handle,
  3191. NULL,
  3192. NULL,
  3193. NULL,
  3194. &IoStatusBlock,
  3195. IOCTL_STORAGE_MEDIA_REMOVAL,
  3196. &PMRemoval,
  3197. sizeof(PMRemoval),
  3198. NULL,
  3199. 0
  3200. );
  3201. ZwClose(Handle);
  3202. if( !NT_SUCCESS(Status) ) {
  3203. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  3204. "Setup: SpPtnUnlockDevice(%ws) - "
  3205. "Failed to tell the floppy to release its media.\n",
  3206. DeviceName));
  3207. }
  3208. } else {
  3209. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  3210. "Setup: SpPtnUnlockDevice(%ws) - Failed to open the device.\n",
  3211. DeviceName));
  3212. }
  3213. }
  3214. return Status;
  3215. }
  3216. VOID
  3217. SpPtnAssignOrdinals(
  3218. IN ULONG DiskNumber
  3219. )
  3220. /*++
  3221. Routine Description:
  3222. Assigns the on disk ordinal for the partitions for
  3223. the requested disk. This on disk ordinal is used in
  3224. the boot.ini (or NVRAM) ARC names to identify the
  3225. boot and system partition devices.
  3226. Arguments:
  3227. DiskNumber : Disk Index for the disk which needs to
  3228. be assigned on disk ordinal for its
  3229. partitions
  3230. Return Value:
  3231. None.
  3232. --*/
  3233. {
  3234. if ((DiskNumber < HardDiskCount)) {
  3235. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3236. ULONG OnDiskOrdinal = 1;
  3237. if (SPPT_IS_MBR_DISK(DiskNumber)) {
  3238. //
  3239. // assign the ordinals to the primary partitions first
  3240. //
  3241. while (Region) {
  3242. if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  3243. Region->TablePosition = OnDiskOrdinal++;
  3244. }
  3245. Region = Region->Next;
  3246. }
  3247. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3248. //
  3249. // assign the ordinals to the logical drives next
  3250. //
  3251. while (Region) {
  3252. if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
  3253. Region->TablePosition = OnDiskOrdinal++;
  3254. }
  3255. Region = Region->Next;
  3256. }
  3257. } else {
  3258. //
  3259. // assign ordinals to the valid partition entries
  3260. //
  3261. while (Region) {
  3262. if (SPPT_IS_REGION_PARTITIONED(Region)) {
  3263. Region->TablePosition = OnDiskOrdinal++;
  3264. }
  3265. Region = Region->Next;
  3266. }
  3267. }
  3268. }
  3269. }
  3270. VOID
  3271. SpPtnLocateSystemPartitions(
  3272. VOID
  3273. )
  3274. /*++
  3275. Routine Description:
  3276. Locates and marks the system partition, by looking into all the
  3277. partitioned space on all the disks.
  3278. For non ARC machines, locates and marks the system partition
  3279. only on the primary disk
  3280. Arguments:
  3281. None
  3282. Return Value:
  3283. None
  3284. --*/
  3285. {
  3286. ULONG DiskNumber;
  3287. if (SpIsArc()) {
  3288. for (DiskNumber = 0; DiskNumber < HardDiskCount; DiskNumber++) {
  3289. SpPtnLocateDiskSystemPartitions(DiskNumber);
  3290. }
  3291. } else {
  3292. DiskNumber = SpDetermineDisk0();
  3293. if (DiskNumber != -1)
  3294. SpPtnLocateDiskSystemPartitions(DiskNumber);
  3295. }
  3296. }
  3297. VOID
  3298. SpPtnLocateDiskSystemPartitions(
  3299. IN ULONG DiskNumber
  3300. )
  3301. /*++
  3302. Routine Description:
  3303. Locates and marks the system partition for the requested
  3304. disk (if none exists)
  3305. For non ARC machine, only operates on primary disk
  3306. Arguments:
  3307. DiskNumber : Disk index, for which system partition
  3308. needs to be located and marked.
  3309. Return Value:
  3310. None.
  3311. --*/
  3312. {
  3313. PDISK_REGION Region = NULL;
  3314. if(!SpIsArc()) {
  3315. //
  3316. // Note: On amd64/X86 we currently don't allow system partitions to reside
  3317. // on GPT disks
  3318. //
  3319. if (SPPT_IS_MBR_DISK(DiskNumber) && (DiskNumber == SpDetermineDisk0())) {
  3320. //
  3321. // On x86 machines, we will mark any primary partitions on drive 0
  3322. // as system partition, since such a partition is potentially bootable.
  3323. //
  3324. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3325. while (Region && !SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
  3326. Region = Region->Next;
  3327. }
  3328. if (!Region) {
  3329. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3330. while (Region) {
  3331. if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  3332. SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
  3333. SPPT_SET_REGION_DIRTY(Region, TRUE);
  3334. break;
  3335. }
  3336. Region = Region->Next;
  3337. }
  3338. }
  3339. }
  3340. } else {
  3341. PSP_BOOT_ENTRY BootEntry;
  3342. //
  3343. // Don't look for system partitions on MBR disks
  3344. // on IA64
  3345. //
  3346. if (!SPPT_IS_GPT_DISK(DiskNumber)) {
  3347. return;
  3348. }
  3349. //
  3350. // On ARC machines, system partitions are specifically enumerated
  3351. // in the NVRAM boot environment.
  3352. //
  3353. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3354. while (Region) {
  3355. //
  3356. // Skip if not a partition or extended partition.
  3357. //
  3358. if(SPPT_IS_REGION_PARTITIONED(Region)) {
  3359. //
  3360. // Get the nt pathname for this region.
  3361. //
  3362. SpNtNameFromRegion(
  3363. Region,
  3364. TemporaryBuffer,
  3365. sizeof(TemporaryBuffer),
  3366. PartitionOrdinalOriginal
  3367. );
  3368. //
  3369. // Determine if it is a system partition.
  3370. //
  3371. for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
  3372. if(!IS_BOOT_ENTRY_DELETED(BootEntry) &&
  3373. IS_BOOT_ENTRY_WINDOWS(BootEntry) &&
  3374. (BootEntry->LoaderPartitionNtName != 0) &&
  3375. !_wcsicmp(BootEntry->LoaderPartitionNtName,TemporaryBuffer)) {
  3376. if (!SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
  3377. SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
  3378. SPPT_SET_REGION_DIRTY(Region, TRUE);
  3379. ValidArcSystemPartition = TRUE;
  3380. }
  3381. break;
  3382. }
  3383. }
  3384. }
  3385. Region = Region->Next;
  3386. }
  3387. }
  3388. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  3389. "SETUP:SpPtnLocateDiskSystemPartitions(%d):%p\n",
  3390. DiskNumber,
  3391. Region));
  3392. if (Region)
  3393. SpPtDumpDiskRegion(Region);
  3394. }
  3395. BOOLEAN
  3396. SpPtnIsDiskStyleChangeAllowed(
  3397. IN ULONG DiskNumber
  3398. )
  3399. /*++
  3400. Routine Description:
  3401. Finds out whether disk style change is allowed for the
  3402. given disk.
  3403. On AXP machines disk style change is not allowed. On
  3404. X-86 machines currently disk style change is disabled for
  3405. primary disks.
  3406. Arguments:
  3407. DiskNumber : Disk, whose style needs to be changed.
  3408. Return Value:
  3409. TRUE if disk style change is allowed, otherwise FALSE
  3410. --*/
  3411. {
  3412. BOOLEAN Result = FALSE;
  3413. if (DiskNumber < HardDiskCount) {
  3414. #if defined(_AMD64_) || defined(_X86_)
  3415. //
  3416. // On non ARC x86 machines, the disk should be a clean
  3417. // non-removable secondary disk
  3418. //
  3419. // Don't allow MBR to GPT disk conversion on X86
  3420. //
  3421. Result = (!SPPT_IS_REMOVABLE_DISK(DiskNumber) &&
  3422. SPPT_IS_BLANK_DISK(DiskNumber) &&
  3423. !SpIsArc() && SPPT_IS_GPT_DISK(DiskNumber));
  3424. #elif defined (_IA64_)
  3425. //
  3426. // Don't allow conversion from GPT to MBR on IA-64
  3427. //
  3428. Result = !SPPT_IS_REMOVABLE_DISK(DiskNumber) &&
  3429. SPPT_IS_BLANK_DISK(DiskNumber) &&
  3430. SPPT_IS_MBR_DISK(DiskNumber);
  3431. #endif // defined(_AMD64_) || defined(_X86_)
  3432. }
  3433. return Result;
  3434. }
  3435. VOID
  3436. SpPtnPromptForSysPart(
  3437. IN PVOID SifHandle
  3438. )
  3439. /*++
  3440. Routine Description:
  3441. Prompts the user about the absence of system partition
  3442. while installating to another valid non-system partition.
  3443. Allows the user to quit setup or continue (generally go
  3444. back to the partitioning engine)
  3445. Arguments:
  3446. SifHandle : Handle to txtsetup.sif (to do space calculation)
  3447. Return Value:
  3448. None
  3449. --*/
  3450. {
  3451. ULONG RequiredSpaceKB = 0;
  3452. ULONG KeyPressed = 0;
  3453. SpFetchDiskSpaceRequirements( SifHandle,
  3454. (32 * 1024),
  3455. NULL,
  3456. &RequiredSpaceKB );
  3457. //
  3458. // No valid system partition.
  3459. //
  3460. SpStartScreen(
  3461. SP_SCRN_MARK_SYSPART,
  3462. 3,
  3463. HEADER_HEIGHT+1,
  3464. FALSE,
  3465. FALSE,
  3466. DEFAULT_ATTRIBUTE,
  3467. RequiredSpaceKB
  3468. );
  3469. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  3470. SP_STAT_ESC_EQUALS_CANCEL,
  3471. SP_STAT_F3_EQUALS_EXIT,
  3472. 0);
  3473. SpInputDrain();
  3474. //
  3475. // wait for F3 or ESC key
  3476. //
  3477. while ((KeyPressed != KEY_F3) && (KeyPressed != ASCI_ESC)) {
  3478. KeyPressed = SpInputGetKeypress();
  3479. }
  3480. if (KeyPressed == KEY_F3) {
  3481. SpDone(0, FALSE, TRUE);
  3482. }
  3483. }
  3484. BOOLEAN
  3485. SpPtnIsDeleteAllowedForRegion(
  3486. IN PDISK_REGION Region
  3487. )
  3488. /*++
  3489. Routine Description:
  3490. Given a region this function tries to find out if the region
  3491. can be deleted.
  3492. Arguments:
  3493. Region : Pointer to region which is to be checked for
  3494. deletion
  3495. Return Value:
  3496. TRUE if the given region can be deleted otherwise FALSE
  3497. --*/
  3498. {
  3499. BOOLEAN Result = FALSE;
  3500. if (Region && SPPT_IS_REGION_PARTITIONED(Region)) {
  3501. PDISK_REGION BootRegion = SpRegionFromNtName(NtBootDevicePath,
  3502. PartitionOrdinalCurrent);
  3503. ULONG DiskNumber = Region->DiskNumber;
  3504. if (SPPT_IS_REGION_DYNAMIC_VOLUME(Region)) {
  3505. //
  3506. // Don't delete the dynamic volume if its on
  3507. // the same disk as local source or system partition
  3508. //
  3509. if (!(LocalSourceRegion &&
  3510. (LocalSourceRegion->DiskNumber == DiskNumber)) &&
  3511. !(BootRegion &&
  3512. (BootRegion->DiskNumber == DiskNumber))) {
  3513. Result = TRUE;
  3514. }
  3515. } else {
  3516. Result = ((BootRegion != Region) && (LocalSourceRegion != Region));
  3517. }
  3518. }
  3519. return Result;
  3520. }
  3521. BOOLEAN
  3522. SpPtnIsRawDiskDriveLayout(
  3523. IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
  3524. )
  3525. /*++
  3526. Routine Description:
  3527. Given a drive layout tests whether the given drive layout
  3528. could be for a raw disk
  3529. NOTE : If all the partition entries are empty entries or
  3530. if there are no partition entries then we assume the disk
  3531. to be RAW disk.
  3532. Arguments:
  3533. DriveLayout : Drive layout information that needs to
  3534. be tested
  3535. Return Value:
  3536. TRUE if the given disk is RAW otherwise FALSE
  3537. --*/
  3538. {
  3539. BOOLEAN Result = TRUE;
  3540. if (DriveLayout && DriveLayout->PartitionCount &&
  3541. (DriveLayout->PartitionStyle != PARTITION_STYLE_RAW)) {
  3542. ULONG Index;
  3543. for (Index=0; Index < DriveLayout->PartitionCount; Index++) {
  3544. PPARTITION_INFORMATION_EX PartInfo = DriveLayout->PartitionEntry + Index;
  3545. //
  3546. // Partition is invalid partition if
  3547. // - starting offset is 0 and
  3548. // - length is 0 and
  3549. // - partition number is 0
  3550. //
  3551. if ((PartInfo->StartingOffset.QuadPart) ||
  3552. (PartInfo->PartitionLength.QuadPart) ||
  3553. (PartInfo->PartitionNumber)) {
  3554. Result = FALSE;
  3555. break; // found an valid partition entry
  3556. }
  3557. }
  3558. }
  3559. return Result;
  3560. }
  3561. BOOLEAN
  3562. SpPtnIsDynamicDisk(
  3563. IN ULONG DiskIndex
  3564. )
  3565. /*++
  3566. Routine Description:
  3567. Determines whether the given disk is dynamic i.e. it has
  3568. atleast a single dynamic volume
  3569. Arguments:
  3570. DiskIndex - Zero based index of the disk to test
  3571. Return Value:
  3572. TRUE, if the disk has a dynamic volume otherwise FALSE
  3573. --*/
  3574. {
  3575. BOOLEAN Result = FALSE;
  3576. if ((DiskIndex < HardDiskCount) &&
  3577. !SPPT_IS_REMOVABLE_DISK(DiskIndex)) {
  3578. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskIndex);
  3579. while (Region && !SPPT_IS_REGION_DYNAMIC_VOLUME(Region)) {
  3580. Region = Region->Next;
  3581. }
  3582. if (Region) {
  3583. Result = TRUE;
  3584. }
  3585. }
  3586. return Result;
  3587. }
  3588. //
  3589. // Callback context structure for finding the Guid volume name
  3590. // for the specified NT partition name
  3591. //
  3592. typedef struct _NT_TO_GUID_VOLUME_NAME {
  3593. WCHAR NtName[MAX_PATH];
  3594. WCHAR GuidVolumeName[MAX_PATH];
  3595. } NT_TO_GUID_VOLUME_NAME, *PNT_TO_GUID_VOLUME_NAME;
  3596. static
  3597. BOOLEAN
  3598. SppPtnCompareGuidNameForPartition(
  3599. IN PVOID Context,
  3600. IN PMOUNTMGR_MOUNT_POINTS MountPoints,
  3601. IN PMOUNTMGR_MOUNT_POINT MountPoint
  3602. )
  3603. /*++
  3604. Routine Description:
  3605. Callback routine for searching the appropriate GUID
  3606. volume name for the specified NT partition.
  3607. Arguments:
  3608. Context : PNT_TO_GUID_VOLUME_NAME pointer disguised as PVOID
  3609. MountPoints : The MountPoints which were received from mountmgr.
  3610. NOTE : The only reason this is here is because
  3611. somebody created MOUNT_POINT structure abstraction
  3612. contained inside MOUNT_POINTS which has some fields
  3613. (like SymbolicNameOffset) which are relative to
  3614. the MOUNT_POINTS.
  3615. MountPoint : The current mountpoint (as part of MountPoints)
  3616. Return Value:
  3617. TRUE if we found a match and want to terminate the iteration else
  3618. FALSE.
  3619. --*/
  3620. {
  3621. BOOLEAN Result = FALSE;
  3622. if (Context && MountPoint && MountPoint->SymbolicLinkNameLength) {
  3623. WCHAR CanonicalName[MAX_PATH];
  3624. PWSTR GuidName = NULL;
  3625. UNICODE_STRING String;
  3626. PNT_TO_GUID_VOLUME_NAME Map = (PNT_TO_GUID_VOLUME_NAME)Context;
  3627. GuidName = SpMemAlloc(MountPoint->SymbolicLinkNameLength + 2);
  3628. if (GuidName) {
  3629. //
  3630. // Copy over the symbolic name and null terminate it
  3631. //
  3632. RtlCopyMemory(GuidName,
  3633. ((PCHAR)MountPoints) + MountPoint->SymbolicLinkNameOffset,
  3634. MountPoint->SymbolicLinkNameLength);
  3635. GuidName[MountPoint->SymbolicLinkNameLength/sizeof(WCHAR)] = UNICODE_NULL;
  3636. RtlInitUnicodeString(&String, GuidName);
  3637. //
  3638. // We are only bothered about volume names &
  3639. // resolve the actual object name
  3640. //
  3641. if (MOUNTMGR_IS_VOLUME_NAME(&String) &&
  3642. NT_SUCCESS(SpQueryCanonicalName(GuidName,
  3643. -1,
  3644. CanonicalName,
  3645. sizeof(CanonicalName)))) {
  3646. //
  3647. // Do the names compare correctly
  3648. //
  3649. Result = (_wcsicmp(CanonicalName, Map->NtName) == 0);
  3650. if (Result) {
  3651. //
  3652. // Copy the name to the result
  3653. //
  3654. RtlZeroMemory(Map->GuidVolumeName,
  3655. sizeof(Map->GuidVolumeName));
  3656. wcsncpy(Map->GuidVolumeName,
  3657. GuidName,
  3658. sizeof(Map->GuidVolumeName)/sizeof(WCHAR) - 1);
  3659. Map->GuidVolumeName[sizeof(Map->GuidVolumeName)/sizeof(WCHAR) - 1] = UNICODE_NULL;
  3660. }
  3661. }
  3662. SpMemFree(GuidName);
  3663. }
  3664. }
  3665. return Result;
  3666. }
  3667. NTSTATUS
  3668. SpPtnGetGuidNameForPartition(
  3669. IN PWSTR NtPartitionName,
  3670. IN OUT PWSTR VolumeName
  3671. )
  3672. /*++
  3673. Routine Description:
  3674. Gets the GUID volume name (in \\??\Volume{a-b-c-d} format) for
  3675. the given NT partition name (in \Device\harddiskX\PartitionY format).
  3676. Arguments:
  3677. NtPartitionName : NT partition name
  3678. VolumeName : Place holder buffer for receiving the GUID volume name.
  3679. Should be atlease MAX_PATH in length.
  3680. Return Value:
  3681. Approriate NTSTATUS code.
  3682. --*/
  3683. {
  3684. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3685. if (NtPartitionName && VolumeName) {
  3686. NT_TO_GUID_VOLUME_NAME Context = {0};
  3687. //
  3688. // Resolve the NT name to actual object name
  3689. //
  3690. Status = SpQueryCanonicalName(NtPartitionName,
  3691. -1,
  3692. Context.NtName,
  3693. sizeof(Context.NtName));
  3694. if (NT_SUCCESS(Status)) {
  3695. //
  3696. // Iterate through mountpoints and try to
  3697. // get the GUID volume name for the NT name
  3698. //
  3699. Status = SpIterateMountMgrMountPoints(&Context,
  3700. SppPtnCompareGuidNameForPartition);
  3701. if (NT_SUCCESS(Status)) {
  3702. if (Context.GuidVolumeName[0]) {
  3703. //
  3704. // Copy over the result
  3705. //
  3706. wcscpy(VolumeName, Context.GuidVolumeName);
  3707. } else {
  3708. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3709. }
  3710. }
  3711. }
  3712. }
  3713. return Status;
  3714. }