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

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