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.

4086 lines
120 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. spptwrt.c
  5. Abstract:
  6. Creates, Deletes and Commits the partitions
  7. to the disk.
  8. Author:
  9. Vijay Jayaseelan (vijayj)
  10. Revision History:
  11. None
  12. --*/
  13. #include "spprecmp.h"
  14. #pragma hdrstop
  15. #include "sppart3.h"
  16. #include <oemtypes.h>
  17. //
  18. // If we are testing commit then we don't commit on
  19. // disk zero (i.e. primary disk) where we have our
  20. // NT and recovery console installation
  21. //
  22. //#define TESTING_COMMIT 1
  23. #if 0
  24. //
  25. // To test GPT partitions using existing loader
  26. //
  27. //#define STAMP_MBR_ON_GPT_DISK 1
  28. #endif
  29. //
  30. // Variable to selectively trun on/off commits to
  31. // the disk
  32. //
  33. BOOLEAN DoActualCommit = TRUE;
  34. ULONG
  35. SpPtnGetContainerPartitionCount(
  36. IN ULONG DiskId
  37. )
  38. /*++
  39. Routine Description:
  40. Counts the number of container partitions in the region
  41. list for the given disk
  42. Arguments:
  43. DiskId : Disk ID
  44. Return Value:
  45. Count of the container partitions for the disk
  46. --*/
  47. {
  48. ULONG Count = 0;
  49. if (SPPT_IS_MBR_DISK(DiskId)) {
  50. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  51. while (Region) {
  52. if (SPPT_IS_REGION_CONTAINER_PARTITION(Region))
  53. Count++;
  54. Region = Region->Next;
  55. }
  56. }
  57. return Count;
  58. }
  59. ULONG
  60. SpPtnGetLogicalDriveCount(
  61. IN ULONG DiskId
  62. )
  63. /*++
  64. Routine Description:
  65. Counts the number of logical drives in the regions list
  66. for the given disk
  67. Arguments:
  68. DiskId : Disk ID
  69. Return Value:
  70. Count of the logical drives for the disk
  71. --*/
  72. {
  73. ULONG Count = 0;
  74. if (SPPT_IS_MBR_DISK(DiskId)) {
  75. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  76. while (Region) {
  77. if (SPPT_IS_REGION_LOGICAL_DRIVE(Region))
  78. Count++;
  79. Region = Region->Next;
  80. }
  81. }
  82. return Count;
  83. }
  84. ULONG
  85. SpPtnGetPartitionCountDisk(
  86. IN ULONG DiskId
  87. )
  88. /*++
  89. Routine Description:
  90. Counts the number of partitions for the given
  91. disk.
  92. Arguments:
  93. DiskId : Disk ID
  94. Return Value:
  95. Count of number of partitions for the disk
  96. --*/
  97. {
  98. ULONG PartCount = 0;
  99. if (DiskId < HardDiskCount) {
  100. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  101. while (Region) {
  102. if (SPPT_IS_REGION_PARTITIONED(Region))
  103. PartCount++;
  104. Region = Region->Next;
  105. }
  106. Region = SPPT_GET_EXTENDED_DISK_REGION(DiskId);
  107. while (Region) {
  108. if (SPPT_IS_REGION_PARTITIONED(Region))
  109. PartCount++;
  110. Region = Region->Next;
  111. }
  112. }
  113. return PartCount;
  114. }
  115. ULONG
  116. SpPtnGetDirtyPartitionCountDisk(
  117. IN ULONG DiskId
  118. )
  119. /*++
  120. Routine Description:
  121. Counts the number of dirty partitions for the given
  122. disk.
  123. NB: A partition is dirty if it needs to be commit
  124. to the disk with some new information
  125. Arguments:
  126. DiskId : Disk ID
  127. Return Value:
  128. Count of the number of dirty partitions for the given
  129. disk
  130. --*/
  131. {
  132. ULONG PartCount = 0;
  133. if (DiskId < HardDiskCount) {
  134. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  135. while (Region) {
  136. if (SPPT_IS_REGION_DIRTY(Region))
  137. PartCount++;
  138. Region = Region->Next;
  139. }
  140. Region = SPPT_GET_EXTENDED_DISK_REGION(DiskId);
  141. while (Region) {
  142. if (SPPT_IS_REGION_DIRTY(Region))
  143. PartCount++;
  144. Region = Region->Next;
  145. }
  146. }
  147. return PartCount;
  148. }
  149. VOID
  150. SpPtnGetPartitionTypeCounts(
  151. IN ULONG DiskId,
  152. IN BOOLEAN SkipDeleted,
  153. IN PULONG PrimaryPartitions, OPTIONAL
  154. IN PULONG ContainerPartitions, OPTIONAL
  155. IN PULONG LogicalDrives, OPTIONAL
  156. IN PULONG KnownPrimaryCount, OPTIONAL
  157. IN PULONG KnownLogicalCount OPTIONAL
  158. )
  159. /*++
  160. Routine Description:
  161. Counts various partition types for the given disk.
  162. Arguments:
  163. DiskId : Disk ID
  164. SkipDeleted : Whether to skip the partitions marked
  165. deleted or not
  166. PrimaryPartitions : Place holder for primary partition count
  167. ContainerPartitions : Place holder for container partition count
  168. LogicalDrives : Place holder for logical drives count
  169. Return Value:
  170. None
  171. --*/
  172. {
  173. if (SPPT_IS_MBR_DISK(DiskId) &&
  174. (ARGUMENT_PRESENT(PrimaryPartitions) ||
  175. ARGUMENT_PRESENT(ContainerPartitions) ||
  176. ARGUMENT_PRESENT(LogicalDrives))) {
  177. ULONG Primary = 0, Container = 0, Logical = 0;
  178. ULONG ValidPrimary = 0, ValidLogical = 0;
  179. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  180. while (Region) {
  181. if (!(SkipDeleted && SPPT_IS_REGION_MARKED_DELETE(Region))) {
  182. if (SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
  183. Container++;
  184. ASSERT(SPPT_IS_REGION_LOGICAL_DRIVE(Region) == FALSE);
  185. ASSERT(SPPT_IS_REGION_PRIMARY_PARTITION(Region) == FALSE);
  186. } else if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
  187. UCHAR SystemId = SPPT_GET_PARTITION_TYPE(Region);
  188. Logical++;
  189. if(SPPT_IS_VALID_PRIMARY_PARTITION_TYPE(SystemId)) {
  190. ValidLogical++;
  191. }
  192. ASSERT(SPPT_IS_REGION_CONTAINER_PARTITION(Region) == FALSE);
  193. ASSERT(SPPT_IS_REGION_PRIMARY_PARTITION(Region) == FALSE);
  194. } else if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  195. UCHAR SystemId = SPPT_GET_PARTITION_TYPE(Region);
  196. Primary++;
  197. if(SPPT_IS_VALID_PRIMARY_PARTITION_TYPE(SystemId)) {
  198. ValidPrimary++;
  199. }
  200. ASSERT(SPPT_IS_REGION_CONTAINER_PARTITION(Region) == FALSE);
  201. ASSERT(SPPT_IS_REGION_LOGICAL_DRIVE(Region) == FALSE);
  202. }
  203. }
  204. Region = Region->Next;
  205. }
  206. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  207. "SETUP:SpPtnGetPartitionTypeCounts(%d):P:%d,C:%d,L:%d,VP:%d,VL:%d\n",
  208. DiskId,
  209. Primary,
  210. Container,
  211. Logical,
  212. ValidPrimary,
  213. ValidLogical));
  214. ASSERT((Logical <= Container) && (Primary < PTABLE_DIMENSION));
  215. if (ARGUMENT_PRESENT(PrimaryPartitions))
  216. *PrimaryPartitions = Primary;
  217. if (ARGUMENT_PRESENT(ContainerPartitions))
  218. *ContainerPartitions = Container;
  219. if (ARGUMENT_PRESENT(LogicalDrives))
  220. *LogicalDrives = Logical;
  221. if (ARGUMENT_PRESENT(KnownPrimaryCount))
  222. *KnownPrimaryCount = ValidPrimary;
  223. if (ARGUMENT_PRESENT(KnownLogicalCount))
  224. *KnownLogicalCount = ValidLogical;
  225. }
  226. }
  227. VOID
  228. SpPtnFreeDiskRegions(
  229. IN ULONG DiskId
  230. )
  231. /*++
  232. Routine Description:
  233. Free the disk region linked list. Its assumed that
  234. this list has all the regions allocated in heap
  235. Arguments:
  236. DiskId : Disk ID
  237. Return Value:
  238. None
  239. --*/
  240. {
  241. NTSTATUS Status;
  242. PPARTITIONED_DISK Disk = SPPT_GET_PARTITIONED_DISK(DiskId);
  243. PDISK_REGION Region = Disk->PrimaryDiskRegions;
  244. PDISK_REGION Temp;
  245. while (Region) {
  246. Temp = Region;
  247. Region = Region->Next;
  248. SpMemFree(Temp);
  249. }
  250. Disk->PrimaryDiskRegions = NULL;
  251. //
  252. // Mark the disk blank since we don't have any regions
  253. // for the disk currently
  254. //
  255. SPPT_SET_DISK_BLANK(DiskId, TRUE);
  256. }
  257. NTSTATUS
  258. SpPtnZapSectors(
  259. IN HANDLE DiskHandle,
  260. IN ULONG BytesPerSector,
  261. IN ULONGLONG StartSector,
  262. IN ULONG SectorCount
  263. )
  264. /*++
  265. Routine Description:
  266. Zaps (zeros) the requested sector(s).
  267. Arguments:
  268. DiskHandle : Open Handle to disk with R/W permissions
  269. StartSector : Starting sector to Zap
  270. Sector Count: Number of sectors to Zap
  271. (includes starting sector also)
  272. Return Value:
  273. Appropriate status code.
  274. --*/
  275. {
  276. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  277. if (SectorCount) {
  278. ULONG BufferSize = (BytesPerSector * 2);
  279. PVOID UBuffer = SpMemAlloc(BufferSize);
  280. ULONGLONG SectorIdx = StartSector;
  281. if (UBuffer) {
  282. PVOID Buffer = UBuffer;
  283. RtlZeroMemory(UBuffer, BufferSize);
  284. Buffer = ALIGN(Buffer, BytesPerSector);
  285. Status = STATUS_SUCCESS;
  286. while (NT_SUCCESS(Status) && SectorCount) {
  287. Status = SpReadWriteDiskSectors(DiskHandle,
  288. SectorIdx,
  289. 1,
  290. BytesPerSector,
  291. Buffer,
  292. TRUE);
  293. SectorIdx++;
  294. SectorCount--;
  295. }
  296. SpMemFree(UBuffer);
  297. } else {
  298. Status = STATUS_NO_MEMORY;
  299. }
  300. }
  301. return Status;
  302. }
  303. NTSTATUS
  304. SpPtnZapRegionBootSector(
  305. IN HANDLE DiskHandle,
  306. IN PDISK_REGION Region
  307. )
  308. /*++
  309. Routine Description:
  310. Zaps (zeros) the starting sector for the given
  311. region. Generally used to zap the boot sector after
  312. creating a new partition
  313. Currently skips the zapping for Container partitions
  314. Arguments:
  315. DiskHandle : Open Handle to disk with R/W permissions
  316. Region : The region, whose boot sector (starting sector)
  317. needs to be zapped
  318. Return Value:
  319. Appropriate status code.
  320. --*/
  321. {
  322. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  323. if (Region) {
  324. if (!SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
  325. Status = SpPtnZapSectors(DiskHandle,
  326. SPPT_DISK_SECTOR_SIZE(Region->DiskNumber),
  327. Region->StartSector,
  328. 1);
  329. } else {
  330. Status = STATUS_SUCCESS;
  331. }
  332. }
  333. return Status;
  334. }
  335. #if 0
  336. NTSTATUS
  337. SpPtnStampMBROnGptDisk(
  338. IN HANDLE DiskHandle,
  339. IN ULONG DiskId,
  340. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
  341. )
  342. /*++
  343. Routine Description:
  344. Stamps the first 3 partitions as primary partitions in the
  345. MBR of the GPT disk (for testing)
  346. Arguments:
  347. DiskHandle : Open Handle to disk with R/W permissions
  348. DiskId : The disk which we are operating on.
  349. LayoutInfo : The partition information for the disk
  350. Return Value:
  351. Appropriate status code.
  352. --*/
  353. {
  354. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  355. if ((DiskId < HardDiskCount) && LayoutInfo && SPPT_IS_GPT_DISK(DiskId)) {
  356. PPARTITION_INFORMATION_EX PartInfo;
  357. ON_DISK_PTE PartEntries[4];
  358. BOOLEAN WriteMBR = FALSE;
  359. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskId);
  360. ULONG BytesPerSector = Disk->Geometry.BytesPerSector;
  361. ULONG Index;
  362. RtlZeroMemory(PartEntries, sizeof(ON_DISK_PTE) * 4);
  363. //
  364. // Go through the partitions and pick up the partitions
  365. // whose number are less than 4 (and not zero)
  366. //
  367. for (Index = 0; Index < LayoutInfo->PartitionCount; Index++) {
  368. ULONG PartIndex = 0;
  369. PartInfo = LayoutInfo->PartitionEntry + Index;
  370. PartIndex = PartInfo->PartitionNumber;
  371. if ((PartIndex > 0) && (PartIndex < 4)) {
  372. ULONGLONG SectorStart = (PartInfo->StartingOffset.QuadPart /
  373. BytesPerSector);
  374. ULONGLONG SectorCount = (PartInfo->PartitionLength.QuadPart /
  375. BytesPerSector);
  376. ULONGLONG SectorEnd = SectorStart + SectorCount;
  377. WriteMBR = TRUE; // need to write MBR
  378. SpPtInitializeCHSFields(Disk,
  379. SectorStart,
  380. SectorEnd,
  381. PartEntries + PartIndex);
  382. U_ULONG(&(PartEntries[PartIndex].RelativeSectors)) = (ULONG)SectorStart;
  383. U_ULONG(&(PartEntries[PartIndex].SectorCount)) = (ULONG)SectorCount;
  384. PartEntries[PartIndex].SystemId = PARTITION_HUGE;
  385. }
  386. }
  387. if (WriteMBR) {
  388. PUCHAR UBuffer;
  389. PUCHAR Buffer;
  390. PON_DISK_MBR DummyMbr;
  391. UBuffer = SpMemAlloc(BytesPerSector * 2);
  392. if (UBuffer) {
  393. RtlZeroMemory(UBuffer, BytesPerSector * 2);
  394. //
  395. // align the buffer on sector boundary
  396. //
  397. Buffer = ALIGN(UBuffer, BytesPerSector);
  398. //
  399. // Read sector 0 (for existing boot code)
  400. //
  401. Status = SpReadWriteDiskSectors(
  402. DiskHandle,
  403. (Disk->Int13Hooker == HookerEZDrive) ? 1 : 0,
  404. 1,
  405. BytesPerSector,
  406. Buffer,
  407. FALSE
  408. );
  409. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  410. "SETUP:SpPtnStampMBROnGptDisk():Read MBR on an GPT Disk for testing (%lx)\n",
  411. Status));
  412. if (NT_SUCCESS(Status)) {
  413. ASSERT(512 == BytesPerSector);
  414. DummyMbr = (PON_DISK_MBR)Buffer;
  415. //
  416. // copy the 3 entries in partition table (which we created eariler)
  417. //
  418. RtlCopyMemory(DummyMbr->PartitionTable + 1, PartEntries + 1,
  419. sizeof(PartEntries) - sizeof(ON_DISK_PTE));
  420. //
  421. // Write the sector(s).
  422. //
  423. Status = SpReadWriteDiskSectors(
  424. DiskHandle,
  425. (Disk->Int13Hooker == HookerEZDrive) ? 1 : 0,
  426. 1,
  427. BytesPerSector,
  428. Buffer,
  429. TRUE
  430. );
  431. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  432. "SETUP:SpPtnStampMBROnGtpDisk():Wrote MBR on an GPT Disk for testing (%lx)\n",
  433. Status));
  434. }
  435. SpMemFree(UBuffer);
  436. } else {
  437. Status = STATUS_NO_MEMORY;
  438. }
  439. } else {
  440. Status = STATUS_SUCCESS;
  441. }
  442. }
  443. return Status;
  444. }
  445. #endif // 0, comment out
  446. NTSTATUS
  447. SpPtnAssignPartitionNumbers(
  448. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
  449. )
  450. /*++
  451. Routine Description:
  452. Given a drive layout structure with number of partitions,
  453. walks through each partitions assigning a partition number
  454. if one is not already assigned.
  455. Does not assign partition number to container partitions
  456. Arguments:
  457. LayoutEx - Contains all the partitions some of which needs
  458. partition numbers
  459. Return Value:
  460. Appropriate error code.
  461. --*/
  462. {
  463. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  464. if (LayoutEx && LayoutEx->PartitionCount) {
  465. ULONG Index;
  466. PBOOLEAN UsedArray;
  467. ULONG PartCount = LayoutEx->PartitionCount;
  468. ULONG Size = PartCount;
  469. ULONG MaxPartAssigned;
  470. PPARTITION_INFORMATION_EX PartInfo = LayoutEx->PartitionEntry;
  471. //
  472. // Find out the space needed for boolean array
  473. //
  474. for (Index = 0, MaxPartAssigned = 0; Index < PartCount; Index++) {
  475. if (PartInfo[Index].PartitionNumber > MaxPartAssigned)
  476. MaxPartAssigned = PartInfo[Index].PartitionNumber;
  477. }
  478. Size = max(MaxPartAssigned, PartCount);
  479. Size++;
  480. UsedArray = (PBOOLEAN)SpMemAlloc(sizeof(BOOLEAN) * Size);
  481. if (UsedArray) {
  482. BOOLEAN Assign = FALSE;
  483. RtlZeroMemory(UsedArray, (sizeof(BOOLEAN) * Size));
  484. UsedArray[0] = TRUE; // don't assign '0' to any partition
  485. //
  486. // Mark the already assigned partition numbers
  487. //
  488. for (Index = 0; Index < PartCount; Index++) {
  489. if (PartInfo[Index].PartitionNumber != 0)
  490. UsedArray[PartInfo[Index].PartitionNumber] = TRUE;
  491. else
  492. Assign = TRUE;
  493. }
  494. if (Assign) {
  495. ULONG NextFreeEntry;
  496. //
  497. // Find the next available partition number for assignment
  498. //
  499. for (Index = 1, NextFreeEntry = 0; Index < Size; Index++) {
  500. if (!UsedArray[Index]) {
  501. NextFreeEntry = Index;
  502. break;
  503. }
  504. }
  505. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  506. "SETUP: SpPtnAssignPartitionNumber : NextFreeEntry = %d\n",
  507. NextFreeEntry));
  508. //
  509. // Assign the partition numbers for the needed partitions
  510. //
  511. for (Index = 0; (Index < PartCount); Index++) {
  512. if (SPPT_PARTITION_NEEDS_NUMBER(PartInfo + Index)) {
  513. PartInfo[Index].PartitionNumber = NextFreeEntry;
  514. UsedArray[NextFreeEntry] = TRUE;
  515. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  516. "SETUP: SpPtnAssignPartitionNumber : Assigning = %d to %d\n",
  517. NextFreeEntry, Index));
  518. while ((NextFreeEntry < Size) && UsedArray[NextFreeEntry])
  519. NextFreeEntry++;
  520. }
  521. }
  522. }
  523. Status = STATUS_SUCCESS;
  524. SpMemFree(UsedArray);
  525. } else {
  526. Status = STATUS_NO_MEMORY;
  527. }
  528. }
  529. return Status;
  530. }
  531. NTSTATUS
  532. SpPtnInitializeDiskStyle(
  533. IN ULONG DiskId,
  534. IN PARTITION_STYLE Style,
  535. IN PCREATE_DISK DiskInfo OPTIONAL
  536. )
  537. /*++
  538. Routine Description:
  539. Given the disk, changes the disk style (MBR/GPT) as
  540. requested.
  541. For RAW disks, uses the default partition type style
  542. which can differ from platform to platform.
  543. Arguments:
  544. DiskId : Disk ID
  545. Style : Partition Style
  546. DiskInfo : Disk information which needs to be used,
  547. while initializing the disk
  548. Return Value:
  549. Appropriate error code
  550. --*/
  551. {
  552. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  553. #ifdef COMMIT_TESTING
  554. if (!DiskId)
  555. return STATUS_SUCCESS;
  556. #endif
  557. if (SPPT_IS_BLANK_DISK(DiskId) &&
  558. ((Style == PARTITION_STYLE_GPT) || (Style == PARTITION_STYLE_MBR))) {
  559. WCHAR DiskPath[MAX_PATH];
  560. HANDLE DiskHandle;
  561. //
  562. // form the name
  563. //
  564. swprintf(DiskPath, L"\\Device\\Harddisk%u", DiskId);
  565. //
  566. // Open partition 0 on this disk..
  567. //
  568. Status = SpOpenPartition0(DiskPath, &DiskHandle, TRUE);
  569. if (NT_SUCCESS(Status)) {
  570. IO_STATUS_BLOCK IoStatusBlock;
  571. NTSTATUS InitStatus;
  572. if (Style == PARTITION_STYLE_GPT) {
  573. CREATE_DISK CreateInfo;
  574. RtlZeroMemory(&CreateInfo, sizeof(CREATE_DISK));
  575. if (DiskInfo) {
  576. CreateInfo = *DiskInfo;
  577. CreateInfo.PartitionStyle = Style;
  578. } else {
  579. CreateInfo.PartitionStyle = Style;
  580. SpCreateNewGuid(&(CreateInfo.Gpt.DiskId));
  581. CreateInfo.Gpt.MaxPartitionCount = 0; // will be 128 actually
  582. }
  583. Status = ZwDeviceIoControlFile( DiskHandle,
  584. NULL,
  585. NULL,
  586. NULL,
  587. &IoStatusBlock,
  588. IOCTL_DISK_CREATE_DISK,
  589. &CreateInfo,
  590. sizeof(CREATE_DISK),
  591. NULL,
  592. 0);
  593. } else {
  594. //
  595. // Note : This is needed since CREATE_DISK doesn't work for
  596. // MBR disks :(
  597. //
  598. ULONG LayoutSize;
  599. PDRIVE_LAYOUT_INFORMATION_EX DriveLayout;
  600. PHARD_DISK Disk;
  601. Disk = SPPT_GET_HARDDISK(DiskId);
  602. LayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  603. (3 * sizeof(PARTITION_INFORMATION_EX));
  604. DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)SpMemAlloc(LayoutSize);
  605. if (DriveLayout) {
  606. RtlZeroMemory(DriveLayout, LayoutSize);
  607. DriveLayout->PartitionStyle = PARTITION_STYLE_MBR;
  608. DriveLayout->PartitionCount = 4;
  609. if (DiskInfo) {
  610. Disk->Signature = DriveLayout->Mbr.Signature =
  611. DiskInfo->Mbr.Signature;
  612. } else {
  613. Disk->Signature = DriveLayout->Mbr.Signature =
  614. SPPT_GET_NEW_DISK_SIGNATURE();
  615. }
  616. DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
  617. DriveLayout->PartitionEntry[1].RewritePartition = TRUE;
  618. DriveLayout->PartitionEntry[2].RewritePartition = TRUE;
  619. DriveLayout->PartitionEntry[3].RewritePartition = TRUE;
  620. Status = ZwDeviceIoControlFile( DiskHandle,
  621. NULL,
  622. NULL,
  623. NULL,
  624. &IoStatusBlock,
  625. IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
  626. DriveLayout,
  627. LayoutSize,
  628. NULL,
  629. 0);
  630. if (NT_SUCCESS(Status)) {
  631. ULONG Signature = 0;
  632. //
  633. // Zero out sector 1 & 2 also since it might contain
  634. // stale GPT information
  635. //
  636. if (!SPPT_IS_REMOVABLE_DISK(DiskId)) {
  637. SpPtnZapSectors(DiskHandle,
  638. SPPT_DISK_SECTOR_SIZE(DiskId),
  639. 1,
  640. 2);
  641. }
  642. Status = SpMasterBootCode(DiskId, DiskHandle, &Signature);
  643. }
  644. SpMemFree(DriveLayout);
  645. } else {
  646. Status = STATUS_NO_MEMORY;
  647. }
  648. }
  649. ZwClose(DiskHandle);
  650. }
  651. }
  652. if (!NT_SUCCESS(Status)) {
  653. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  654. "SETUP: SpPtnInitializeDiskStyle (%d, %d) failed with (%lx)\n",
  655. DiskId, Style, Status));
  656. }
  657. SpAppendDiskTag(SPPT_GET_HARDDISK(DiskId));
  658. return Status;
  659. }
  660. BOOLEAN
  661. SpPtnRegionToPartitionInfoEx(
  662. IN PDISK_REGION Region,
  663. OUT PPARTITION_INFORMATION_EX PartInfo
  664. )
  665. /*++
  666. Routine Description:
  667. Fills in the PartInfo structure from the given region.
  668. NB. If the region is not dirty uses the cached partition
  669. information to fill the structure.
  670. Arguments:
  671. Region - Which has the details to be filled
  672. into PartInfo
  673. PartInfo - The structure which needs to filled
  674. Return Value:
  675. TRUE if successful, otherwise FALSE
  676. --*/
  677. {
  678. BOOLEAN Result = FALSE;
  679. if (Region && PartInfo &&
  680. (SPPT_IS_REGION_CONTAINER_PARTITION(Region) || SPPT_IS_REGION_PARTITIONED(Region))) {
  681. if (SPPT_IS_REGION_DIRTY(Region)) {
  682. PHARD_DISK Disk = SPPT_GET_HARDDISK(Region->DiskNumber);
  683. PartInfo->StartingOffset.QuadPart = Region->StartSector *
  684. Disk->Geometry.BytesPerSector;
  685. PartInfo->PartitionLength.QuadPart = Region->SectorCount *
  686. Disk->Geometry.BytesPerSector;
  687. PartInfo->PartitionNumber = Region->PartitionNumber;
  688. PartInfo->RewritePartition = TRUE;
  689. if (SPPT_IS_GPT_DISK(Region->DiskNumber)) {
  690. PPARTITION_INFORMATION_GPT GptInfo;
  691. PartInfo->PartitionStyle = PARTITION_STYLE_GPT;
  692. GptInfo = &(PartInfo->Gpt);
  693. if (Region->PartInfoDirty) {
  694. //
  695. // User specified partition attributes
  696. //
  697. *GptInfo = Region->PartInfo.Gpt;
  698. } else {
  699. GptInfo->Attributes = 0;
  700. if (SPPT_IS_REGION_SYSTEMPARTITION(Region)) {
  701. GptInfo->PartitionType = PARTITION_SYSTEM_GUID;
  702. } else {
  703. GptInfo->PartitionType = PARTITION_BASIC_DATA_GUID;
  704. }
  705. SpCreateNewGuid(&(GptInfo->PartitionId));
  706. }
  707. SpPtnGetPartitionNameFromGUID(&(GptInfo->PartitionType),
  708. GptInfo->Name);
  709. } else {
  710. PPARTITION_INFORMATION_MBR MbrInfo;
  711. PartInfo->PartitionStyle = PARTITION_STYLE_MBR;
  712. MbrInfo = &(PartInfo->Mbr);
  713. MbrInfo->PartitionType = SPPT_GET_PARTITION_TYPE(Region);
  714. if (!MbrInfo->PartitionType)
  715. MbrInfo->PartitionType = PARTITION_IFS;
  716. MbrInfo->BootIndicator = SPPT_IS_REGION_ACTIVE_PARTITION(Region);
  717. //
  718. // System partition must be active partition for MBR disks
  719. // on Non-ARC machines
  720. //
  721. if (SPPT_IS_REGION_SYSTEMPARTITION(Region) && !SpIsArc() ) {
  722. ASSERT(MbrInfo->BootIndicator);
  723. }
  724. MbrInfo->RecognizedPartition =
  725. IsRecognizedPartition(MbrInfo->PartitionType);
  726. MbrInfo->HiddenSectors = 0;
  727. }
  728. } else {
  729. *PartInfo = Region->PartInfo;
  730. }
  731. Result = TRUE;
  732. }
  733. return Result;
  734. }
  735. BOOLEAN
  736. SpPtnInitDiskInfo(
  737. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
  738. OUT PCREATE_DISK CreateInfo
  739. )
  740. /*++
  741. Routine Description:
  742. Fills the information needed for creating a disk,
  743. form the given drive layout structure
  744. NB. If the LayoutInfo is marked as RAW disk style
  745. then used the default partition style for the disk.
  746. This default style can vary from platform to platform
  747. Arguments:
  748. LayoutInfo - The drive layout information to use
  749. CreateInfo - The disk information to be filled in
  750. Return Value:
  751. TRUE if successful otherwise FALSE.1
  752. --*/
  753. {
  754. BOOLEAN Result = FALSE;
  755. if (LayoutInfo && CreateInfo) {
  756. RtlZeroMemory(CreateInfo, sizeof(CREATE_DISK));
  757. CreateInfo->PartitionStyle = LayoutInfo->PartitionStyle;
  758. switch (CreateInfo->PartitionStyle) {
  759. case PARTITION_STYLE_MBR:
  760. CreateInfo->Mbr.Signature = LayoutInfo->Mbr.Signature;
  761. Result = TRUE;
  762. break;
  763. case PARTITION_STYLE_GPT:
  764. CreateInfo->Gpt.DiskId = LayoutInfo->Gpt.DiskId;
  765. CreateInfo->Gpt.MaxPartitionCount =
  766. LayoutInfo->Gpt.MaxPartitionCount;
  767. Result = TRUE;
  768. break;
  769. case PARTITION_STYLE_RAW:
  770. CreateInfo->PartitionStyle = SPPT_DEFAULT_PARTITION_STYLE;
  771. if (CreateInfo->PartitionStyle == PARTITION_STYLE_GPT) {
  772. SpCreateNewGuid(&(CreateInfo->Gpt.DiskId));
  773. } else {
  774. CreateInfo->Mbr.Signature = SPPT_GET_NEW_DISK_SIGNATURE();
  775. }
  776. Result = TRUE;
  777. break;
  778. default:
  779. break;
  780. }
  781. }
  782. return Result;
  783. }
  784. NTSTATUS
  785. SpPtnCommitChanges(
  786. IN ULONG DiskNumber,
  787. OUT PBOOLEAN AnyChanges
  788. )
  789. /*++
  790. Routine Description:
  791. Given the disk, commits the in memory disk region structures
  792. to the disk as partitions.
  793. The commit happens only if atlease a single disk region for the
  794. given disk is dirty.
  795. Arguments:
  796. DiskNumber : Disk to commit for.
  797. AnyChanges : Place holder, indicating if any thing was committed
  798. or not.
  799. Return Value:
  800. Appropriate error code.
  801. --*/
  802. {
  803. NTSTATUS Status;
  804. ULONG LayoutSize;
  805. HANDLE Handle = NULL;
  806. ULONG Index;
  807. ULONG PartitionCount;
  808. ULONG DirtyCount;
  809. WCHAR DevicePath[MAX_PATH];
  810. BOOLEAN ProcessExtended;
  811. PHARD_DISK Disk;
  812. PDISK_REGION Region;
  813. IO_STATUS_BLOCK IoStatusBlock;
  814. PPARTITION_INFORMATION_EX PartInfo;
  815. PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx;
  816. //
  817. // For the time being lets not commit the primary disk
  818. // where we have our OS/RC installed
  819. //
  820. #ifdef TESTING_COMMIT
  821. if (!DiskNumber)
  822. return STATUS_SUCCESS;
  823. #endif
  824. if (DiskNumber >= HardDiskCount)
  825. return STATUS_INVALID_PARAMETER;
  826. *AnyChanges = FALSE;
  827. SpPtDumpDiskRegionInformation(DiskNumber, TRUE);
  828. //
  829. // Check to see if we need to commit
  830. //
  831. DirtyCount = SpPtnGetDirtyPartitionCountDisk(DiskNumber);
  832. if (DoActualCommit && !DirtyCount)
  833. return STATUS_SUCCESS;
  834. *AnyChanges = TRUE;
  835. if (!SpPtnGetContainerPartitionCount(DiskNumber)) {
  836. //
  837. // Recreate the DRIVE_LAYOUT_INFORMATION_EX structure
  838. //
  839. PartitionCount = SpPtnGetPartitionCountDisk(DiskNumber);
  840. LayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
  841. if (PartitionCount == 0) {
  842. CREATE_DISK DiskInfo;
  843. SpPtnInitDiskInfo(&(SPPT_GET_HARDDISK(DiskNumber)->DriveLayout),
  844. &DiskInfo);
  845. SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
  846. Status = SpPtnInitializeDiskStyle(DiskNumber,
  847. DiskInfo.PartitionStyle, &DiskInfo);
  848. SpPtnFreeDiskRegions(DiskNumber);
  849. //
  850. // Update the boot entries to point to null regions
  851. // (if any)
  852. //
  853. SpUpdateRegionForBootEntries();
  854. return Status;
  855. }
  856. if (PartitionCount > 1) {
  857. LayoutSize += ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX));
  858. }
  859. if (PartitionCount < 4) {
  860. LayoutSize += ((4 - PartitionCount) * sizeof(PARTITION_INFORMATION_EX));
  861. }
  862. DriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)SpMemAlloc(LayoutSize);
  863. if (!DriveLayoutEx)
  864. return STATUS_NO_MEMORY;
  865. RtlZeroMemory(DriveLayoutEx, LayoutSize);
  866. RtlCopyMemory(DriveLayoutEx, &(HardDisks[DiskNumber].DriveLayout),
  867. FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry));
  868. DriveLayoutEx->PartitionCount = PartitionCount;
  869. PartInfo = DriveLayoutEx->PartitionEntry;
  870. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  871. ProcessExtended = TRUE;
  872. //
  873. // Initialize stray partitions
  874. //
  875. if (SPPT_IS_MBR_DISK(DiskNumber) && (PartitionCount < 4)) {
  876. ULONG Index = PartitionCount;
  877. DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  878. DriveLayoutEx->PartitionCount = 4;
  879. while (Index < 4) {
  880. DriveLayoutEx->PartitionEntry[Index].PartitionStyle = PARTITION_STYLE_MBR;
  881. DriveLayoutEx->PartitionEntry[Index].RewritePartition = TRUE;
  882. Index++;
  883. }
  884. }
  885. //
  886. // Make PARTITION_INFORMATION_EXs from DISK_REGIONs for all non deleted
  887. // partitions
  888. //
  889. for (Index=0; (Region && (Index < PartitionCount));) {
  890. if (SPPT_IS_REGION_PARTITIONED(Region) &&
  891. (!SPPT_IS_REGION_MARKED_DELETE(Region))) {
  892. Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
  893. ASSERT(NT_SUCCESS(Status));
  894. Index++;
  895. }
  896. Region = Region->Next;
  897. }
  898. } else {
  899. //
  900. // The disk has container partitions and possibly logical
  901. // drives
  902. //
  903. ULONG PrimaryCount = 0, ContainerCount = 0, LogicalCount = 0;
  904. ULONG TotalPartitions;
  905. //SpPtDumpDiskRegionInformation(DiskNumber, TRUE);
  906. SpPtnGetPartitionTypeCounts(DiskNumber,
  907. TRUE,
  908. &PrimaryCount,
  909. &ContainerCount,
  910. &LogicalCount,
  911. NULL,
  912. NULL);
  913. TotalPartitions = PrimaryCount + ContainerCount + LogicalCount;
  914. if (TotalPartitions == 0) {
  915. CREATE_DISK DiskInfo;
  916. SpPtnInitDiskInfo(&(SPPT_GET_HARDDISK(DiskNumber)->DriveLayout),
  917. &DiskInfo);
  918. SPPT_SET_DISK_BLANK(DiskNumber, TRUE);
  919. Status = SpPtnInitializeDiskStyle(DiskNumber,
  920. DiskInfo.PartitionStyle, &DiskInfo);
  921. SpPtnFreeDiskRegions(DiskNumber);
  922. //
  923. // Update the boot entries to point to null regions
  924. // (if any)
  925. //
  926. SpUpdateRegionForBootEntries();
  927. return Status;
  928. } else {
  929. BOOLEAN FirstContainer = FALSE;
  930. //
  931. // allocate adequate space for the drive layout information
  932. //
  933. PartitionCount = (4 * (ContainerCount + 1));
  934. LayoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
  935. (PartitionCount * sizeof(PARTITION_INFORMATION_EX));
  936. DriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)SpMemAlloc(LayoutSize);
  937. if (!DriveLayoutEx)
  938. return STATUS_NO_MEMORY;
  939. //
  940. // initialize the drive layout information
  941. //
  942. RtlZeroMemory(DriveLayoutEx, LayoutSize);
  943. RtlCopyMemory(DriveLayoutEx, &(HardDisks[DiskNumber].DriveLayout),
  944. FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry));
  945. DriveLayoutEx->PartitionCount = PartitionCount;
  946. PartInfo = DriveLayoutEx->PartitionEntry;
  947. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  948. //SpPtDumpDiskRegionInformation(DiskNumber, TRUE);
  949. //
  950. // first pickup the primary partitions and the first
  951. // container partition and put them in the drive layout
  952. // information
  953. //
  954. for (Index=0; (Region && (Index < 4)); ) {
  955. if (!SPPT_IS_REGION_MARKED_DELETE(Region)){
  956. if (!FirstContainer &&
  957. SPPT_IS_REGION_CONTAINER_PARTITION(Region)) {
  958. FirstContainer = TRUE;
  959. Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
  960. ASSERT(NT_SUCCESS(Status));
  961. Index++;
  962. } else if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  963. Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
  964. ASSERT(NT_SUCCESS(Status));
  965. Index++;
  966. }
  967. }
  968. Region = Region->Next;
  969. }
  970. //SpPtDumpDriveLayoutInformation(NULL, DriveLayoutEx);
  971. //
  972. // further container and logical drives need to start at
  973. // multiple of 4 index, in drive layout
  974. //
  975. if (Index)
  976. Index = 4;
  977. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  978. //
  979. // pickup the remaining valid container and logical drives
  980. // and put them in the drive layout information except
  981. // for the first container partition, which we have
  982. // already processed
  983. //
  984. while (Region && (Index < PartitionCount)) {
  985. if ((!SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(Region)) &&
  986. (!SPPT_IS_REGION_MARKED_DELETE(Region)) &&
  987. (!SPPT_IS_REGION_PRIMARY_PARTITION(Region)) &&
  988. (SPPT_IS_REGION_PARTITIONED(Region) ||
  989. SPPT_IS_REGION_CONTAINER_PARTITION(Region))) {
  990. Status = SpPtnRegionToPartitionInfoEx(Region, PartInfo + Index);
  991. ASSERT(NT_SUCCESS(Status));
  992. if (SPPT_IS_REGION_CONTAINER_PARTITION(Region) &&
  993. (Region->Next) &&
  994. SPPT_IS_REGION_LOGICAL_DRIVE(Region->Next)) {
  995. //
  996. // think about this ;)
  997. //
  998. if (Index % 4)
  999. Index += 3;
  1000. else
  1001. Index += 4;
  1002. } else {
  1003. Index++;
  1004. }
  1005. }
  1006. Region = Region->Next;
  1007. }
  1008. }
  1009. }
  1010. //
  1011. // Assign proper partition numbers
  1012. //
  1013. // TBD : Needed ?
  1014. // Status = SpPtnAssignPartitionNumbers(DriveLayoutEx);
  1015. //
  1016. Status = STATUS_SUCCESS;
  1017. if (NT_SUCCESS(Status)) {
  1018. //
  1019. // Need to rewrite all the partitions
  1020. //
  1021. for (Index = 0; Index < DriveLayoutEx->PartitionCount; Index++)
  1022. PartInfo[Index].RewritePartition = TRUE;
  1023. //
  1024. // Commit the Partition changes
  1025. //
  1026. //
  1027. // Create a device path (NT style!) that will describe this disk. This
  1028. // will be of the form: \Device\Harddisk0
  1029. //
  1030. swprintf(DevicePath, L"\\Device\\Harddisk%u", DiskNumber);
  1031. //SpPtDumpDriveLayoutInformation(DevicePath, DriveLayoutEx);
  1032. //
  1033. // Open partition 0 on this disk..
  1034. //
  1035. Status = SpOpenPartition0(DevicePath, &Handle, TRUE);
  1036. if(NT_SUCCESS(Status)){
  1037. if (DoActualCommit) {
  1038. // write the drive layout information
  1039. Status = ZwDeviceIoControlFile( Handle,
  1040. NULL,
  1041. NULL,
  1042. NULL,
  1043. &IoStatusBlock,
  1044. IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
  1045. DriveLayoutEx,
  1046. LayoutSize,
  1047. NULL,
  1048. 0);
  1049. if(NT_SUCCESS(Status)) {
  1050. Region = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  1051. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1052. "SETUP: SpPtnCommitChanges : Commited partitions "
  1053. "successfully on %ws (%lx)\n",
  1054. DevicePath));
  1055. if (NT_SUCCESS(Status)) {
  1056. ULONG Signature = 0;
  1057. ULONG Count = 0;
  1058. if (SPPT_IS_MBR_DISK(DiskNumber)) {
  1059. Status = SpMasterBootCode(DiskNumber,
  1060. Handle,
  1061. &Signature);
  1062. if (!NT_SUCCESS(Status)) {
  1063. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1064. "SETUP: SpPtnCommitChanges : Unable to write "
  1065. "master boot code (%lx)\n",
  1066. Status));
  1067. }
  1068. }
  1069. while (Region && NT_SUCCESS(Status)) {
  1070. if (Region->Filesystem == FilesystemNewlyCreated) {
  1071. Status = SpPtnZapRegionBootSector(Handle, Region);
  1072. Count++;
  1073. }
  1074. Region = Region->Next;
  1075. }
  1076. if (!NT_SUCCESS(Status)) {
  1077. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1078. "SETUP: SpPtnCommitChanges : Error in Zapping\n"));
  1079. //SpPtDumpDiskRegion(Region);
  1080. } else {
  1081. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1082. "SETUP: SpPtnCommitChanges : Zapped %d sectors :)\n",
  1083. Count));
  1084. #ifdef STAMP_MBR_ON_GPT_DISK
  1085. Status = ZwDeviceIoControlFile( Handle,
  1086. NULL,
  1087. NULL,
  1088. NULL,
  1089. &IoStatusBlock,
  1090. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  1091. NULL,
  1092. 0,
  1093. DriveLayoutEx,
  1094. LayoutSize);
  1095. if (NT_SUCCESS(Status)) {
  1096. Status = SpPtnStampMBROnGptDisk(Handle,
  1097. DiskNumber,
  1098. DriveLayoutEx);
  1099. }
  1100. #endif
  1101. }
  1102. }
  1103. } else {
  1104. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1105. "SETUP: SpPtnCommitChanges : unable to do "
  1106. "IOCTL_DISK_SET_DRIVE_LAYOUT_EX on device %ws (%lx)\n",
  1107. DevicePath,
  1108. Status));
  1109. }
  1110. } else {
  1111. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1112. "SETUP: SpPtnCommitChanges : Skipping acutal commit to disk "
  1113. "for %ws\n",
  1114. DevicePath));
  1115. }
  1116. ZwClose(Handle);
  1117. } else {
  1118. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1119. "SETUP: SpPtnCommitChanges : unable to open "
  1120. "partition0 on device %ws (%lx)\n",
  1121. DevicePath,
  1122. Status ));
  1123. }
  1124. } else {
  1125. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1126. "SETUP: SpPtnCommitChanges : unable to assign "
  1127. "partition numbers for %ws (%lx)\n",
  1128. DevicePath,
  1129. Status ));
  1130. }
  1131. SpMemFree(DriveLayoutEx);
  1132. return Status;
  1133. }
  1134. NTSTATUS
  1135. SpPtnRemoveLogicalDrive(
  1136. IN PDISK_REGION LogicalDrive
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Manipulates the in memory region data structure
  1141. so as to mark the logical drive as deleted.
  1142. NB. When a logical drive gets deleted, the container
  1143. partition needs to be deleted based on some
  1144. conditions.
  1145. Arguments:
  1146. LogicalDrive : The region representing the logical
  1147. drive which needs to be deleted.
  1148. Return Value:
  1149. Approprate error code
  1150. --*/
  1151. {
  1152. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1153. if (SPPT_IS_REGION_LOGICAL_DRIVE(LogicalDrive) &&
  1154. (LogicalDrive->Container)){
  1155. PDISK_REGION ContainerRegion = LogicalDrive->Container;
  1156. BOOLEAN LastLogicalDrive =
  1157. (SpPtnGetLogicalDriveCount(LogicalDrive->DiskNumber) == 1);
  1158. SPPT_SET_REGION_DELETED(LogicalDrive, TRUE);
  1159. SPPT_SET_REGION_DIRTY(LogicalDrive, TRUE);
  1160. SPPT_SET_REGION_PARTITIONED(LogicalDrive, FALSE);
  1161. if (LastLogicalDrive) {
  1162. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1163. "SETUP:SpPtnRemoveLogicalDrive(%p) is the last"
  1164. " logical drive\n", LogicalDrive));
  1165. }
  1166. if (ContainerRegion->Container) {
  1167. PDISK_REGION Region = NULL;
  1168. SPPT_SET_REGION_DELETED(ContainerRegion, TRUE);
  1169. SPPT_SET_REGION_DIRTY(ContainerRegion, TRUE);
  1170. SPPT_SET_REGION_PARTITIONED(ContainerRegion, FALSE);
  1171. //
  1172. // if this was the last logical drive then delete the
  1173. // first container region also
  1174. //
  1175. if (LastLogicalDrive) {
  1176. ASSERT(SPPT_IS_REGION_CONTAINER_PARTITION(
  1177. ContainerRegion->Container));
  1178. SPPT_SET_REGION_DELETED(ContainerRegion->Container, TRUE);
  1179. SPPT_SET_REGION_DIRTY(ContainerRegion->Container, TRUE);
  1180. SPPT_SET_REGION_PARTITIONED(ContainerRegion->Container, FALSE);
  1181. }
  1182. } else {
  1183. if (LastLogicalDrive) {
  1184. //
  1185. // No trailing region, so delete the first container region
  1186. //
  1187. SPPT_SET_REGION_DELETED(ContainerRegion, TRUE);
  1188. SPPT_SET_REGION_DIRTY(ContainerRegion, TRUE);
  1189. SPPT_SET_REGION_PARTITIONED(ContainerRegion, FALSE);
  1190. }
  1191. }
  1192. Status = STATUS_SUCCESS;
  1193. }
  1194. return Status;
  1195. }
  1196. BOOLEAN
  1197. SpPtnDelete(
  1198. IN ULONG DiskNumber,
  1199. IN ULONGLONG StartSector
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. Removes the requested partition for the given disk.
  1204. Also updates the region structure when returns.
  1205. Arguments:
  1206. DiskNumber : Disk where the partition needs to be
  1207. deleted.
  1208. StartSector : Start sector of the partition/region
  1209. which needs to be deleted.
  1210. Return Value:
  1211. TRUE if successful otherwise FALSE.
  1212. --*/
  1213. {
  1214. BOOLEAN Result = FALSE;
  1215. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1216. PDISK_REGION Region;
  1217. PPARTITIONED_DISK PartDisk;
  1218. NTSTATUS InitStatus;
  1219. #ifdef TESTING_COMMIT
  1220. if (DiskNumber == 0)
  1221. return TRUE;
  1222. #endif
  1223. PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  1224. Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
  1225. if (Region) {
  1226. if (SPPT_IS_REGION_DYNAMIC_VOLUME(Region) || SPPT_IS_REGION_LDM_METADATA(Region)) {
  1227. //
  1228. // delete all the regions on this disk
  1229. //
  1230. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  1231. if (SPPT_IS_MBR_DISK(DiskNumber)) {
  1232. //
  1233. // Skip OEM partitions on MBR disk since they will always be
  1234. // hard partitions
  1235. //
  1236. // NOTE : Assumes that all the OEM partitions are primary
  1237. // partitions (which also indicates they are hard partitions)
  1238. //
  1239. while (CurrRegion) {
  1240. if (!IsOEMPartition(SPPT_GET_PARTITION_TYPE(CurrRegion))) {
  1241. SPPT_SET_REGION_PARTITIONED(CurrRegion, FALSE);
  1242. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  1243. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  1244. }
  1245. CurrRegion = CurrRegion->Next;
  1246. }
  1247. } else {
  1248. while (CurrRegion) {
  1249. //
  1250. // Skip ESP & MSR partitions since they will always be
  1251. // hard partitions
  1252. //
  1253. if (!SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion) &&
  1254. !SPPT_IS_REGION_MSFT_RESERVED(CurrRegion)) {
  1255. SPPT_SET_REGION_PARTITIONED(CurrRegion, FALSE);
  1256. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  1257. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  1258. }
  1259. CurrRegion = CurrRegion->Next;
  1260. }
  1261. }
  1262. Status = STATUS_SUCCESS;
  1263. } else if (SPPT_IS_REGION_LOGICAL_DRIVE(Region)) {
  1264. Status = SpPtnRemoveLogicalDrive(Region);
  1265. } else {
  1266. SPPT_SET_REGION_PARTITIONED(Region, FALSE);
  1267. SPPT_SET_REGION_DELETED(Region, TRUE);
  1268. SPPT_SET_REGION_DIRTY(Region, TRUE);
  1269. Status = STATUS_SUCCESS;
  1270. }
  1271. if (NT_SUCCESS(Status)) {
  1272. Status = SpPtnCommitChanges(DiskNumber, &Result);
  1273. if (!(Result && NT_SUCCESS(Status))) {
  1274. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1275. "SETUP: SpPtnDelete(%u, %I64u) failed to commit changes (%lx)\n",
  1276. DiskNumber, StartSector, Status));
  1277. }
  1278. } else {
  1279. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1280. "SETUP: SpPtnDelete(%u, %I64u) failed to delete logical drive (%lx)\n",
  1281. DiskNumber, StartSector, Status));
  1282. }
  1283. }
  1284. Result = Result && NT_SUCCESS(Status);
  1285. //
  1286. // Reinitialize regions irrespective of commit's status
  1287. //
  1288. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  1289. if (!NT_SUCCESS(InitStatus)) {
  1290. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1291. "SETUP: SpPtnDelete(%u, %I64u) failed to reinit regions\n",
  1292. DiskNumber,
  1293. StartSector));
  1294. Result = FALSE;
  1295. }
  1296. return Result;
  1297. }
  1298. ValidationValue
  1299. SpPtnGetSizeCB(
  1300. IN ULONG Key
  1301. )
  1302. /*++
  1303. Routine Description:
  1304. Key stroke filter for getting the partition size
  1305. from the user
  1306. Arguments:
  1307. Key - The key stroke
  1308. Return Value:
  1309. One of the enumerated types of ValidationValue, indicating
  1310. whether to accept / reject / terminate / ignore the key
  1311. stroke.
  1312. --*/
  1313. {
  1314. if(Key == ASCI_ESC) {
  1315. //
  1316. // User wants to bail.
  1317. //
  1318. return(ValidateTerminate);
  1319. }
  1320. if(Key & KEY_NON_CHARACTER) {
  1321. return(ValidateIgnore);
  1322. }
  1323. //
  1324. // Allow only digits.
  1325. //
  1326. return(((Key >= L'0') && (Key <= L'9')) ? ValidateAccept : ValidateReject);
  1327. }
  1328. BOOLEAN
  1329. SpPtnGetSizeFromUser(
  1330. IN PHARD_DISK Disk,
  1331. IN ULONGLONG MinMB,
  1332. IN ULONGLONG MaxMB,
  1333. OUT PULONGLONG SizeMB
  1334. )
  1335. /*++
  1336. Routine Description:
  1337. Gets the size from user, after showing him the minimum
  1338. and maximum values
  1339. Arguments:
  1340. Disk - Disk for which the partition size is being
  1341. requested
  1342. MinMB - Minimum partition size
  1343. MaxMB - Maximim patitions size
  1344. SizeMB - Place holder for user entered size
  1345. Return Value:
  1346. TRUE if the input was valid or FALSE if the user
  1347. cancelled the input dialog using ESC.
  1348. --*/
  1349. {
  1350. BOOLEAN Result;
  1351. WCHAR Buffer[200];
  1352. WCHAR SizeBuffer[32] = {0};
  1353. *SizeMB = 0;
  1354. //
  1355. // Put up a screen displaying min/max size info.
  1356. //
  1357. SpStartScreen(
  1358. SP_SCRN_CONFIRM_CREATE_PARTITION,
  1359. 3,
  1360. CLIENT_TOP + 1,
  1361. FALSE,
  1362. FALSE,
  1363. DEFAULT_ATTRIBUTE,
  1364. Disk->Description,
  1365. (ULONG)MinMB,
  1366. (ULONG)MaxMB
  1367. );
  1368. //
  1369. // Display the staus text.
  1370. //
  1371. SpDisplayStatusOptions(
  1372. DEFAULT_STATUS_ATTRIBUTE,
  1373. SP_STAT_ENTER_EQUALS_CREATE,
  1374. SP_STAT_ESC_EQUALS_CANCEL,
  1375. 0
  1376. );
  1377. //
  1378. // Get and display the size prompt.
  1379. //
  1380. SpFormatMessage(Buffer, sizeof(Buffer), SP_TEXT_SIZE_PROMPT);
  1381. SpvidDisplayString(Buffer, DEFAULT_ATTRIBUTE, 3, NextMessageTopLine);
  1382. Result = TRUE;
  1383. //
  1384. // Get the size from the user.
  1385. //
  1386. do {
  1387. swprintf(SizeBuffer,L"%u", (ULONG)MaxMB);
  1388. if(!SpGetInput(SpPtnGetSizeCB,
  1389. SplangGetColumnCount(Buffer) + 5,
  1390. NextMessageTopLine,
  1391. 8, // at the max 99999999
  1392. SizeBuffer,
  1393. TRUE)) {
  1394. //
  1395. // User pressed escape and bailed.
  1396. //
  1397. Result = FALSE;
  1398. break;
  1399. }
  1400. *SizeMB = SpStringToLong(SizeBuffer, NULL, 10);
  1401. }
  1402. while(((*SizeMB) < MinMB) || ((*SizeMB) > MaxMB));
  1403. return Result;
  1404. }
  1405. VOID
  1406. SpPtnAlignPartitionStartAndEnd(
  1407. IN PHARD_DISK Disk,
  1408. IN ULONGLONG SizeMB,
  1409. IN ULONGLONG StartSector,
  1410. IN PDISK_REGION Region,
  1411. IN BOOLEAN ForExtended,
  1412. OUT PULONGLONG AlignedStartSector,
  1413. OUT PULONGLONG AlignedEndSector
  1414. )
  1415. /*++
  1416. Routine Description:
  1417. Aligns the partition start and end sector
  1418. Arguments:
  1419. Disk - Partition's disk for which alignment needs to be
  1420. done.
  1421. SizeMB - The partition's size
  1422. StartSector - The start sector of the partition
  1423. Region - The region representing the partition
  1424. ForExtended - Whether this partition needs to be aligned
  1425. for creating a container partition.
  1426. AlignedStartSector - Place holder for the aligned start sector
  1427. AlignedEndSector - Place holder fot the aligned end sector
  1428. Return Value:
  1429. None
  1430. --*/
  1431. {
  1432. ULONGLONG SectorCount;
  1433. ULONGLONG LeftOverSectors;
  1434. //
  1435. // Determine the number of sectors in the size passed in.
  1436. //
  1437. SectorCount = SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector);
  1438. //
  1439. // If this is the first free space inside the extended partition
  1440. // we need to decrement the StartSector so that while creating
  1441. // first logical inside the extended we don't create the
  1442. // logical at one cylinder offset
  1443. //
  1444. if (SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(Region) && StartSector) {
  1445. StartSector--;
  1446. }
  1447. //
  1448. // Align the start sector.
  1449. //
  1450. (*AlignedStartSector) = SpPtAlignStart(Disk, StartSector, ForExtended);
  1451. //
  1452. // Determine the end sector based on the size passed in.
  1453. //
  1454. (*AlignedEndSector) = (*AlignedStartSector) + SectorCount;
  1455. //
  1456. // Align the ending sector to a cylinder boundary. If it is not already
  1457. // aligned and is more than half way into the final cylinder, align it up,
  1458. // otherwise align it down.
  1459. //
  1460. LeftOverSectors = (*AlignedEndSector) % Disk->SectorsPerCylinder;
  1461. if (LeftOverSectors) {
  1462. (*AlignedEndSector) -= LeftOverSectors;
  1463. if (LeftOverSectors > (Disk->SectorsPerCylinder / 2)) {
  1464. (*AlignedEndSector) += Disk->SectorsPerCylinder;
  1465. }
  1466. }
  1467. //
  1468. // If the ending sector is past the end of the free space, shrink it
  1469. // so it fits.
  1470. //
  1471. while((*AlignedEndSector) > StartSector + Region->SectorCount) {
  1472. (*AlignedEndSector) -= Disk->SectorsPerCylinder;
  1473. }
  1474. //
  1475. // Find out if last sector is in the last cylinder. If it is then align it down.
  1476. // This is necessary so that we reserve a cylinder at the end of the disk, so that users
  1477. // can convert the disk to dynamic after the system is installed.
  1478. //
  1479. // (guhans) Don't align down if this is ASR. ASR already takes this into account.
  1480. //
  1481. if( !DockableMachine && !SpDrEnabled() &&
  1482. ((*AlignedEndSector) > ((Disk->CylinderCount - 1) * Disk->SectorsPerCylinder))) {
  1483. (*AlignedEndSector) -= Disk->SectorsPerCylinder;
  1484. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1485. "SETUP: End of partition was aligned down 1 cylinder \n"));
  1486. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1487. "SETUP: AlignedStartSector = %I64x \n", AlignedStartSector));
  1488. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1489. "SETUP: AlignedEndSector = %I64x \n", AlignedEndSector));
  1490. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1491. "SETUP: SectorsPerCylinder = %lx \n", Disk->SectorsPerCylinder));
  1492. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1493. "SETUP: CylinderCount = %lx \n", Disk->CylinderCount));
  1494. }
  1495. ASSERT((*AlignedEndSector) > 0);
  1496. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1497. "SETUP:SpPtnAlignPartitionStartAndEnd:S/C:%d,Size:%I64d,"
  1498. "StartSector:%I64d,RSS:%I64d,FE:%d,AS:%I64d,AE:%I64d\n"
  1499. "LeftOverSectors:%I64d\n",
  1500. Disk->SectorsPerCylinder,
  1501. SizeMB,
  1502. StartSector,
  1503. Region->StartSector,
  1504. ForExtended,
  1505. *AlignedStartSector,
  1506. *AlignedEndSector,
  1507. LeftOverSectors));
  1508. }
  1509. BOOLEAN
  1510. SpPtnCreateLogicalDrive(
  1511. IN ULONG DiskNumber,
  1512. IN ULONGLONG StartSector,
  1513. IN ULONGLONG SizeInSectors, // Used ONLY in the ASR case
  1514. IN BOOLEAN ForNT,
  1515. IN BOOLEAN AlignToCylinder,
  1516. IN ULONGLONG DesiredMB OPTIONAL,
  1517. IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
  1518. OUT PDISK_REGION *ActualDiskRegion OPTIONAL
  1519. )
  1520. /*++
  1521. Routine Description:
  1522. Creates logical drive.
  1523. To create a logical drive we need to create the
  1524. logical drive's container partition also first.
  1525. Algorithm:
  1526. if (first logical drive) {
  1527. 1. create an extended partition encompassing the
  1528. whole free space in region
  1529. 2. create a logical drive at one track offset
  1530. from the extened partition of the required size
  1531. } else {
  1532. 1. create an extended partition encompassing the
  1533. given space
  1534. 2. create a logical drive of the maximim size
  1535. inside the created extended partition
  1536. }
  1537. Arguments:
  1538. DiskNumber - Disk on which logical drive nedds to be
  1539. created.
  1540. StartSector - The starting sector for the region, which
  1541. will contain the container & logical drive
  1542. ForNT - Indicating whether to use the given
  1543. Desired Size or not
  1544. AlignToCylinder - Indicating whether the partition should
  1545. be aligned on a cylinder boundary (Usually set
  1546. to TRUE, except in a few specific ASR cases).
  1547. PartInfo - Partition Information which needs to be
  1548. used while creating the partition (like
  1549. Partition Type on MBR disks and GUID
  1550. for Partition Id on GPT disks)
  1551. ActualDiskRegion - Place holder for returning, the
  1552. region which indicates the new
  1553. partition in memory
  1554. Return Value:
  1555. TRUE is successful otherwise FALSE.
  1556. --*/
  1557. {
  1558. BOOLEAN Result = FALSE;
  1559. NTSTATUS Status;
  1560. NTSTATUS InitStatus;
  1561. UCHAR PartitionType = 0;
  1562. ULONG Primary = 0, Container = 0, Logical = 0;
  1563. BOOLEAN FirstLogical = FALSE;
  1564. BOOLEAN ReservedRegion = FALSE;
  1565. BOOLEAN CreateContainer = TRUE;
  1566. BOOLEAN Beyond1024;
  1567. BOOLEAN FreeRegions = FALSE;
  1568. ULONGLONG MinMB = 0, MaxMB = 0, SizeMB = 0;
  1569. ULONGLONG LogicalSize = 0;
  1570. ULONGLONG CylinderMB = 0;
  1571. PDISK_REGION Region;
  1572. ULONGLONG SectorCount, LeftOverSectors;
  1573. ULONGLONG AlignedStartSector, AlignedEndSector;
  1574. ULONGLONG LogicalStartSector, LogicalEndSector;
  1575. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  1576. PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  1577. PDISK_REGION NewContainer = NULL, NewLogical = NULL;
  1578. //
  1579. // get hold of the region
  1580. //
  1581. Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
  1582. if (!Region)
  1583. return Result;
  1584. //
  1585. // should be free
  1586. //
  1587. ASSERT(SPPT_IS_REGION_PARTITIONED(Region) == FALSE);
  1588. //
  1589. // get the various partition type count on the disk
  1590. //
  1591. SpPtnGetPartitionTypeCounts(DiskNumber,
  1592. TRUE,
  1593. &Primary,
  1594. &Container,
  1595. &Logical,
  1596. NULL,
  1597. NULL);
  1598. //
  1599. // first logical indicates, what we will be creating the first
  1600. // container partition which will consume the whole free space
  1601. // available
  1602. //
  1603. FirstLogical = !(Logical || Container);
  1604. //
  1605. // Some times there might be just an extended partition and we
  1606. // might be creating the partition in the starting free space inside
  1607. // this extended partition. For this case we want to make sure that
  1608. // we don't create another container partition
  1609. //
  1610. if (!FirstLogical && SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(Region)) {
  1611. CreateContainer = FALSE;
  1612. }
  1613. //
  1614. // Create an extened partition
  1615. //
  1616. SpPtQueryMinMaxCreationSizeMB(DiskNumber,
  1617. Region->StartSector,
  1618. CreateContainer,
  1619. !CreateContainer,
  1620. &MinMB,
  1621. &MaxMB,
  1622. &ReservedRegion
  1623. );
  1624. if (ReservedRegion) {
  1625. ULONG ValidKeys[2] = {ASCI_CR , 0};
  1626. SpStartScreen(
  1627. SP_SCRN_REGION_RESERVED,
  1628. 3,
  1629. HEADER_HEIGHT+1,
  1630. FALSE,
  1631. FALSE,
  1632. DEFAULT_ATTRIBUTE
  1633. );
  1634. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1635. SP_STAT_ENTER_EQUALS_CONTINUE,
  1636. 0);
  1637. SpWaitValidKey(ValidKeys, NULL, NULL);
  1638. return FALSE;
  1639. }
  1640. if (ForNT) {
  1641. //
  1642. // If a size was requested then try to use that, otherwise use
  1643. // the maximum.
  1644. //
  1645. if (DesiredMB) {
  1646. if (DesiredMB <= MaxMB) {
  1647. SizeMB = DesiredMB;
  1648. } else {
  1649. return FALSE; // don't have the space user requested
  1650. }
  1651. } else {
  1652. SizeMB = MaxMB;
  1653. }
  1654. } else {
  1655. if (SpPtnGetSizeFromUser(Disk, MinMB, MaxMB, &SizeMB)) {
  1656. DesiredMB = SizeMB;
  1657. } else {
  1658. return FALSE; // user didn't want to proceed
  1659. }
  1660. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1661. SP_STAT_PLEASE_WAIT,
  1662. 0);
  1663. }
  1664. //
  1665. // get the aligned start and end sector for exteneded/logical partition
  1666. //
  1667. if (AlignToCylinder) {
  1668. SpPtnAlignPartitionStartAndEnd(Disk,
  1669. FirstLogical ? MaxMB : SizeMB,
  1670. StartSector,
  1671. Region,
  1672. CreateContainer,
  1673. &AlignedStartSector,
  1674. &AlignedEndSector);
  1675. }
  1676. else {
  1677. AlignedStartSector = StartSector;
  1678. if (SpDrEnabled()) {
  1679. AlignedEndSector = StartSector + SizeInSectors;
  1680. }
  1681. else {
  1682. AlignedEndSector = StartSector +
  1683. (SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector));
  1684. }
  1685. }
  1686. if (CreateContainer) {
  1687. //
  1688. // Logical drive start is always at 1 track offset from extended start
  1689. //
  1690. LogicalStartSector = AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber);
  1691. if (FirstLogical) {
  1692. ULONGLONG SectorCount = (SizeMB * 1024 * 1024) / SPPT_DISK_SECTOR_SIZE(DiskNumber);
  1693. ULONGLONG Remainder = 0;
  1694. if (SpDrEnabled()) {
  1695. SectorCount = SizeInSectors;
  1696. }
  1697. LogicalEndSector = LogicalStartSector + SectorCount;
  1698. if (AlignToCylinder) {
  1699. Remainder = LogicalEndSector % SPPT_DISK_CYLINDER_SIZE(DiskNumber);
  1700. LogicalEndSector -= Remainder;
  1701. if (Remainder > (SPPT_DISK_CYLINDER_SIZE(DiskNumber) / 2))
  1702. LogicalEndSector += SPPT_DISK_CYLINDER_SIZE(DiskNumber);
  1703. }
  1704. if (LogicalEndSector > AlignedEndSector)
  1705. LogicalEndSector = AlignedEndSector;
  1706. } else {
  1707. LogicalEndSector = AlignedEndSector;
  1708. }
  1709. } else {
  1710. //
  1711. // The first free region (inside first extended) is at the offset
  1712. // of 1 sector from the previous exteneded region. Since we are not
  1713. // using the aligned start sector some times this first logical
  1714. // will be greater than the requested size i.e.
  1715. // end is aligned but start may not be aligned
  1716. //
  1717. LogicalStartSector = StartSector - 1 + SPPT_DISK_TRACK_SIZE(DiskNumber);
  1718. LogicalEndSector = AlignedEndSector;
  1719. }
  1720. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1721. "SETUP:SpPtnCreateLogicalDrive():"
  1722. "CMB:%I64d,CS:%I64d,CE:%I64d,LS:%I64d,LE:%I64d\n",
  1723. CylinderMB,
  1724. AlignedStartSector,
  1725. AlignedEndSector,
  1726. LogicalStartSector,
  1727. LogicalEndSector));
  1728. //
  1729. // allocate the new regions
  1730. //
  1731. if (CreateContainer) {
  1732. //
  1733. // allocate the container region
  1734. //
  1735. NewContainer = (PDISK_REGION)SpMemAlloc(sizeof(DISK_REGION));
  1736. if (!NewContainer)
  1737. return FALSE;
  1738. RtlZeroMemory(NewContainer, sizeof(DISK_REGION));
  1739. }
  1740. //
  1741. // allocate the logical drive region
  1742. //
  1743. NewLogical = (PDISK_REGION)SpMemAlloc(sizeof(DISK_REGION));
  1744. if (!NewLogical) {
  1745. SpMemFree(NewContainer);
  1746. return FALSE;
  1747. }
  1748. RtlZeroMemory(NewLogical, sizeof(DISK_REGION));
  1749. //
  1750. // put the new regions in the list
  1751. //
  1752. if (CreateContainer) {
  1753. NewContainer->Next = NewLogical;
  1754. NewLogical->Next = Region->Next;
  1755. Region->Next = NewContainer;
  1756. } else {
  1757. //
  1758. // This is the first logical inside the
  1759. // already existing extended partition
  1760. //
  1761. ASSERT(Region->Container->Next == Region);
  1762. NewLogical->Next = Region->Next;
  1763. Region->Container->Next = NewLogical;
  1764. }
  1765. //
  1766. // fill the container disk region.
  1767. //
  1768. if (CreateContainer) {
  1769. ASSERT(AlignedStartSector < AlignedEndSector);
  1770. NewContainer->DiskNumber = DiskNumber;
  1771. NewContainer->StartSector = AlignedStartSector;
  1772. NewContainer->SectorCount = AlignedEndSector - AlignedStartSector;
  1773. if (!FirstLogical) {
  1774. PDISK_REGION FirstContainer = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  1775. while (FirstContainer && !SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(FirstContainer))
  1776. FirstContainer = FirstContainer->Next;
  1777. ASSERT(FirstContainer);
  1778. NewContainer->Container = FirstContainer;
  1779. }
  1780. SPPT_SET_REGION_PARTITIONED(NewContainer, FALSE);
  1781. SPPT_SET_REGION_DIRTY(NewContainer, TRUE);
  1782. SPPT_SET_REGION_EPT(NewContainer, EPTContainerPartition);
  1783. NewContainer->FreeSpaceKB = (ULONG)(-1);
  1784. NewContainer->AdjustedFreeSpaceKB = (ULONG)(-1);
  1785. Beyond1024 = SpIsRegionBeyondCylinder1024(NewContainer);
  1786. //
  1787. // Only mark the first extended (container) partition as XINT13_EXTENDED
  1788. // if beyond 1024 cylinders, for backward compatability with Win9x
  1789. //
  1790. PartitionType = (Beyond1024 && FirstLogical) ? PARTITION_XINT13_EXTENDED : PARTITION_EXTENDED;
  1791. SPPT_SET_PARTITION_TYPE(NewContainer, PartitionType);
  1792. }
  1793. //
  1794. // fill in the logical disk region
  1795. //
  1796. ASSERT(LogicalStartSector < LogicalEndSector);
  1797. if (CreateContainer) {
  1798. ASSERT((AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber)) == LogicalStartSector);
  1799. if (LogicalStartSector != (AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber))) {
  1800. LogicalStartSector = AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber);
  1801. }
  1802. }
  1803. ASSERT(LogicalEndSector <= AlignedEndSector);
  1804. if (LogicalEndSector > AlignedEndSector) {
  1805. LogicalEndSector = AlignedEndSector;
  1806. }
  1807. NewLogical->DiskNumber = DiskNumber;
  1808. NewLogical->StartSector = LogicalStartSector;
  1809. NewLogical->SectorCount = LogicalEndSector - LogicalStartSector;
  1810. if (CreateContainer) {
  1811. NewLogical->Container = NewContainer; // the new logical drive's container !!!
  1812. } else {
  1813. ASSERT(Region->Container);
  1814. NewLogical->Container = Region->Container;
  1815. }
  1816. SPPT_SET_REGION_PARTITIONED(NewLogical, TRUE);
  1817. SPPT_SET_REGION_DIRTY(NewLogical, TRUE);
  1818. SPPT_SET_REGION_EPT(NewLogical, EPTLogicalDrive);
  1819. NewLogical->FreeSpaceKB = (ULONG)(-1);
  1820. NewLogical->AdjustedFreeSpaceKB = (ULONG)(-1);
  1821. Beyond1024 = SpIsRegionBeyondCylinder1024(NewLogical);
  1822. PartitionType = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE;
  1823. //
  1824. // If the argument is specified and is valid partition type
  1825. // then use that making the assumption the caller knows exactly
  1826. // what he wants
  1827. //
  1828. if (ARGUMENT_PRESENT(PartInfo) && !IsContainerPartition(PartInfo->Mbr.PartitionType)) {
  1829. PartitionType = PartInfo->Mbr.PartitionType;
  1830. }
  1831. SPPT_SET_PARTITION_TYPE(NewLogical, PartitionType);
  1832. NewLogical->Filesystem = FilesystemNewlyCreated; // to zap boot sector
  1833. SpFormatMessage(Region->TypeName,
  1834. sizeof(Region->TypeName),
  1835. SP_TEXT_FS_NAME_BASE + Region->Filesystem);
  1836. //
  1837. // commit to the disk
  1838. //
  1839. Status = SpPtnCommitChanges(DiskNumber, &Result);
  1840. if (!(NT_SUCCESS(Status) && Result)) {
  1841. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1842. "SETUP: SpPtnDelete(%u, %I64u) failed to commit changes (%lx)\n",
  1843. DiskNumber,
  1844. StartSector,
  1845. Status));
  1846. }
  1847. Result = Result && NT_SUCCESS(Status);
  1848. //
  1849. // Reinitialize irrespective of commit's status
  1850. //
  1851. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  1852. if (!NT_SUCCESS(InitStatus)) {
  1853. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1854. "SETUP: SpPtnCreateLogicalDrive(%u, %I64u) failed to reinit regions\n",
  1855. DiskNumber,
  1856. StartSector));
  1857. Result = FALSE;
  1858. }
  1859. if (Result && ARGUMENT_PRESENT(ActualDiskRegion)) {
  1860. *ActualDiskRegion = SpPtLookupRegionByStart(PartDisk,
  1861. FALSE,
  1862. LogicalStartSector);
  1863. //SpPtDumpDiskRegion(*ActualDiskRegion);
  1864. }
  1865. //
  1866. // We don't need to free the regions which we allocated above
  1867. // as the above commit and init would have done that already
  1868. //
  1869. return Result;
  1870. }
  1871. BOOLEAN
  1872. SpPtnCreate(
  1873. IN ULONG DiskNumber,
  1874. IN ULONGLONG StartSector,
  1875. IN ULONGLONG SizeInSectors, // Used ONLY in the ASR case
  1876. IN ULONGLONG SizeMB,
  1877. IN BOOLEAN InExtended,
  1878. IN BOOLEAN AlignToCylinder,
  1879. IN PPARTITION_INFORMATION_EX PartInfo,
  1880. OUT PDISK_REGION *ActualDiskRegion OPTIONAL
  1881. )
  1882. /*++
  1883. Routine Description:
  1884. Creates a primary partition of the requested size on the
  1885. given disk (either MBR/GPT).
  1886. Arguments:
  1887. DiskNumber : Disk on which the partition needs to be
  1888. created
  1889. StartSector : Start sector of the region, which represents
  1890. the free space in which the partition needs
  1891. to be created
  1892. SizeMB : The size of the partition
  1893. InExtended : Whether to create an logical drive
  1894. or not (currently NOT USED except in the ASR case)
  1895. AlignToCylinder : Indicating whether the partition should
  1896. be aligned on a cylinder boundary (Usually set
  1897. to TRUE, except in a few specific ASR cases).
  1898. PartInfo : Partition attributes to use
  1899. ActualDiskRegion : Place holder for the actual disk
  1900. region which will represent the created
  1901. partition
  1902. Return Value:
  1903. TRUE if successful, otherwise FALSE
  1904. --*/
  1905. {
  1906. BOOLEAN Result = FALSE;
  1907. PDISK_REGION Region;
  1908. ULONGLONG SectorCount, AlignedStartSector;
  1909. ULONGLONG AlignedEndSector, LeftOverSectors;
  1910. PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  1911. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  1912. PDISK_REGION PrevRegion;
  1913. PDISK_REGION NewRegion = NULL;
  1914. NTSTATUS Status;
  1915. NTSTATUS InitStatus;
  1916. BOOLEAN FirstLogical = TRUE;
  1917. //
  1918. // Verify that the optional attributes specified
  1919. // are correct
  1920. //
  1921. if (PartInfo) {
  1922. if ((SPPT_IS_MBR_DISK(DiskNumber) &&
  1923. (PartInfo->PartitionStyle != PARTITION_STYLE_MBR)) ||
  1924. (SPPT_IS_GPT_DISK(DiskNumber) &&
  1925. (PartInfo->PartitionStyle != PARTITION_STYLE_GPT))) {
  1926. return FALSE;
  1927. }
  1928. }
  1929. Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
  1930. if (!Region)
  1931. return Result;
  1932. ASSERT(SPPT_IS_REGION_PARTITIONED(Region) == FALSE);
  1933. SpPtDumpDiskRegion(Region);
  1934. //
  1935. // Determine the number of sectors in the size passed in.
  1936. //
  1937. if (SpDrEnabled()) {
  1938. SectorCount = SizeInSectors;
  1939. }
  1940. else {
  1941. SectorCount = SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector);
  1942. }
  1943. //
  1944. // Align the start sector.
  1945. //
  1946. if (AlignToCylinder) {
  1947. if (!SpDrEnabled()) {
  1948. AlignedStartSector = SpPtAlignStart(Disk, StartSector, FALSE);
  1949. }
  1950. else {
  1951. AlignedStartSector = SpPtAlignStart(Disk, StartSector, InExtended);
  1952. }
  1953. }
  1954. else {
  1955. AlignedStartSector = StartSector;
  1956. }
  1957. //
  1958. // Determine the end sector based on the size passed in.
  1959. //
  1960. AlignedEndSector = AlignedStartSector + SectorCount;
  1961. //
  1962. // Align the ending sector to a cylinder boundary. If it is not already
  1963. // aligned and is more than half way into the final cylinder, align it up,
  1964. // otherwise align it down.
  1965. //
  1966. if (AlignToCylinder) {
  1967. LeftOverSectors = AlignedEndSector % Disk->SectorsPerCylinder;
  1968. if (LeftOverSectors) {
  1969. AlignedEndSector -= LeftOverSectors;
  1970. if (LeftOverSectors > (Disk->SectorsPerCylinder / 2)) {
  1971. AlignedEndSector += Disk->SectorsPerCylinder;
  1972. }
  1973. }
  1974. }
  1975. //
  1976. // If the ending sector is past the end of the free space, shrink it
  1977. // so it fits.
  1978. //
  1979. while(AlignedEndSector > Region->StartSector + Region->SectorCount) {
  1980. AlignedEndSector -= Disk->SectorsPerCylinder;
  1981. }
  1982. //
  1983. // Find out if last sector is in the last cylinder. If it is then align it down.
  1984. // This is necessary so that we reserve a cylinder at the end of the disk, so that users
  1985. // can convert the disk to dynamic after the system is installed.
  1986. //
  1987. // (guhans) Don't align down if this is ASR. ASR already takes this into account.
  1988. //
  1989. if( !DockableMachine && !SpDrEnabled() && SPPT_IS_MBR_DISK(DiskNumber) &&
  1990. (AlignedEndSector > ((Disk->CylinderCount - 1) * Disk->SectorsPerCylinder))) {
  1991. AlignedEndSector -= Disk->SectorsPerCylinder;
  1992. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1993. "SETUP: End of partition was aligned down 1 cylinder \n"));
  1994. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1995. "SETUP: AlignedStartSector = %I64x \n", AlignedStartSector));
  1996. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1997. "SETUP: AlignedEndSector = %I64x \n", AlignedEndSector));
  1998. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1999. "SETUP: SectorsPerCylinder = %lx \n", Disk->SectorsPerCylinder));
  2000. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2001. "SETUP: CylinderCount = %lx \n", Disk->CylinderCount));
  2002. }
  2003. ASSERT(AlignedEndSector > 0);
  2004. //
  2005. // Find the previous region
  2006. //
  2007. PrevRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2008. if(PrevRegion == Region) {
  2009. PrevRegion = NULL;
  2010. } else {
  2011. while (PrevRegion) {
  2012. if(PrevRegion->Next == Region) {
  2013. break;
  2014. }
  2015. PrevRegion = PrevRegion->Next;
  2016. }
  2017. }
  2018. //
  2019. // Create a new disk region for the new free space at the
  2020. // beginning and end of the free space, if any.
  2021. //
  2022. if(AlignedStartSector - Region->StartSector) {
  2023. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2024. "SETUP:SpPtnCreate():Previous:OS:%I64d,AS:%I64d,DIFF:%I64d,S/P:%d\n",
  2025. Region->StartSector,
  2026. AlignedStartSector,
  2027. (ULONGLONG)(AlignedStartSector - Region->StartSector),
  2028. Disk->SectorsPerCylinder));
  2029. NewRegion = SpPtAllocateDiskRegionStructure(
  2030. DiskNumber,
  2031. Region->StartSector,
  2032. AlignedStartSector - Region->StartSector,
  2033. FALSE,
  2034. NULL,
  2035. 0
  2036. );
  2037. ASSERT(NewRegion);
  2038. if(PrevRegion) {
  2039. PrevRegion->Next = NewRegion;
  2040. } else {
  2041. ASSERT(Region == SPPT_GET_PRIMARY_DISK_REGION(DiskNumber));
  2042. PartDisk->PrimaryDiskRegions = NewRegion;
  2043. }
  2044. NewRegion->Next = Region;
  2045. }
  2046. if(Region->StartSector + Region->SectorCount - AlignedEndSector) {
  2047. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2048. "SETUP:SpPtnCreate():Next:OE:%I64d,AE:%I64d,DIFF:%I64d,S/P:%d\n",
  2049. (ULONGLONG)(Region->StartSector + Region->SectorCount),
  2050. AlignedEndSector,
  2051. (ULONGLONG)(Region->StartSector + Region->SectorCount - AlignedEndSector),
  2052. Disk->SectorsPerCylinder));
  2053. NewRegion = SpPtAllocateDiskRegionStructure(
  2054. DiskNumber,
  2055. AlignedEndSector,
  2056. Region->StartSector + Region->SectorCount -
  2057. AlignedEndSector,
  2058. FALSE,
  2059. NULL,
  2060. 0
  2061. );
  2062. NewRegion->Next = Region->Next;
  2063. Region->Next = NewRegion;
  2064. }
  2065. //
  2066. // fill the current disk region.
  2067. //
  2068. Region->DiskNumber = DiskNumber;
  2069. Region->StartSector = AlignedStartSector;
  2070. Region->SectorCount = AlignedEndSector - AlignedStartSector;
  2071. SPPT_SET_REGION_PARTITIONED(Region, TRUE);
  2072. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2073. Region->VolumeLabel[0] = 0;
  2074. Region->Filesystem = FilesystemNewlyCreated;
  2075. Region->FreeSpaceKB = (ULONG)(-1);
  2076. Region->AdjustedFreeSpaceKB = (ULONG)(-1);
  2077. //
  2078. // Set the passed in partition information
  2079. //
  2080. if (PartInfo) {
  2081. SpPtnSetRegionPartitionInfo(Region, PartInfo);
  2082. }
  2083. SpFormatMessage(Region->TypeName,
  2084. sizeof(Region->TypeName),
  2085. SP_TEXT_FS_NAME_BASE + Region->Filesystem);
  2086. //
  2087. // commit to the disk
  2088. //
  2089. Status = SpPtnCommitChanges(DiskNumber, &Result);
  2090. if (!(Result && NT_SUCCESS(Status))) {
  2091. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2092. "SETUP: SpPtnCreate(%u, %I64u) failed to commit changes to"
  2093. "the drive (%lx)\n",
  2094. DiskNumber,
  2095. StartSector,
  2096. Status));
  2097. }
  2098. Result = Result && NT_SUCCESS(Status);
  2099. //
  2100. // Reinitialize irrespective of commit's status
  2101. //
  2102. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  2103. if (!NT_SUCCESS(InitStatus)){
  2104. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2105. "SETUP: SpPtnCreate(%u, %I64u) failed to reinitialize regions\n",
  2106. DiskNumber,
  2107. StartSector));
  2108. Result = FALSE;
  2109. }
  2110. if (Result && ARGUMENT_PRESENT(ActualDiskRegion)) {
  2111. *ActualDiskRegion = SpPtLookupRegionByStart(PartDisk,
  2112. FALSE,
  2113. AlignedStartSector);
  2114. }
  2115. return Result;
  2116. }
  2117. BOOLEAN
  2118. SpPtnDoCreate(
  2119. IN PDISK_REGION Region,
  2120. OUT PDISK_REGION *ActualRegion, OPTIONAL
  2121. IN BOOLEAN ForNT,
  2122. IN ULONGLONG DesiredMB OPTIONAL,
  2123. IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
  2124. IN BOOLEAN ConfirmIt
  2125. )
  2126. /*++
  2127. Routine Description:
  2128. Given the region which was selected by the user,
  2129. this routine creates the appropriate partition in
  2130. it.
  2131. This routine decides whether to create a primary or
  2132. container partition on MBR disks.
  2133. Algorithm:
  2134. if (RemoveableMedia && already partition exists) {
  2135. 1. put up a warning for the user
  2136. 2. return with error
  2137. }
  2138. if ((MBR disk) && ((there is no space for primary partition) ||
  2139. (region is in a container space)){
  2140. 1. create a logical drive using SpPtnCreateLogicalDrive()
  2141. } else {
  2142. 1. align the start sector.
  2143. 2. create the required GPT/MBR partition.
  2144. }
  2145. Arguments:
  2146. Region - The region representing the free space on disk
  2147. where the partition needs to be created.
  2148. ActualRegion - Place holder, for the region which will
  2149. represent the actual partition after
  2150. creating it.
  2151. ForNT - Indicates whether to use the given desired size
  2152. argument or not.
  2153. DesiredSize - The size of the partition to created
  2154. PartInfo - The partition attributes to use while creating
  2155. the new partition
  2156. ConfirmIt - Whether to pop up error dialogs, if something
  2157. goes wrong while creating the partition
  2158. Return Value:
  2159. TRUE if successful otherwise FALSE
  2160. --*/
  2161. {
  2162. BOOLEAN Result = FALSE;
  2163. ULONG DiskNumber = Region->DiskNumber;
  2164. ULONGLONG MinMB = 0, MaxMB = 0;
  2165. ULONGLONG SizeMB = 0;
  2166. BOOLEAN ReservedRegion = FALSE;
  2167. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  2168. if (SPPT_IS_MBR_DISK(DiskNumber)) {
  2169. ULONG PrimaryCount = 0;
  2170. ULONG ContainerCount = 0;
  2171. ULONG LogicalCount = 0;
  2172. ULONG ValidPrimaryCount = 0;
  2173. BOOLEAN InContainer = FALSE;
  2174. BOOLEAN FirstContainer = FALSE;
  2175. SpPtnGetPartitionTypeCounts(DiskNumber,
  2176. TRUE,
  2177. &PrimaryCount,
  2178. &ContainerCount,
  2179. &LogicalCount,
  2180. &ValidPrimaryCount,
  2181. NULL);
  2182. //
  2183. // Create a logical drive if we have a valid primary
  2184. // or there is no more space for another primary
  2185. //
  2186. FirstContainer = (ContainerCount == 0) && (ValidPrimaryCount > 0);
  2187. InContainer = (Region->Container != NULL);
  2188. //
  2189. // We allow only one partition on the removable media (?)
  2190. //
  2191. if (SPPT_IS_REMOVABLE_DISK(DiskNumber)) {
  2192. if (PrimaryCount || ContainerCount || LogicalCount) {
  2193. ULONG ValidKeys[2] = { ASCI_CR ,0 };
  2194. //
  2195. // Disk is already partitioned
  2196. //
  2197. SpDisplayScreen(SP_SCRN_REMOVABLE_ALREADY_PARTITIONED,
  2198. 3,
  2199. HEADER_HEIGHT + 1);
  2200. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2201. SP_STAT_ENTER_EQUALS_CONTINUE,
  2202. 0);
  2203. SpWaitValidKey(ValidKeys, NULL, NULL);
  2204. return FALSE;
  2205. }
  2206. } else {
  2207. if (FirstContainer || InContainer) {
  2208. //
  2209. // create the logical drive
  2210. //
  2211. Result = SpPtnCreateLogicalDrive(DiskNumber,
  2212. Region->StartSector,
  2213. 0, // SizeInSectors: used only in the ASR case
  2214. ForNT,
  2215. TRUE, // AlignToCylinder
  2216. DesiredMB,
  2217. PartInfo,
  2218. ActualRegion);
  2219. if (!Result) {
  2220. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2221. "SETUP: SpPtnCreateLogicalDrive() failed\n"));
  2222. }
  2223. return Result;
  2224. }
  2225. //
  2226. // check to see if there is no space in the partition table
  2227. //
  2228. if (PrimaryCount >= (PTABLE_DIMENSION - 1)) {
  2229. //
  2230. // Let the user know that the partition table is full
  2231. //
  2232. if (ConfirmIt) {
  2233. while (TRUE) {
  2234. ULONG Keys[2] = {ASCI_CR, 0};
  2235. SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,
  2236. 3,
  2237. CLIENT_TOP + 1);
  2238. SpDisplayStatusOptions(
  2239. DEFAULT_STATUS_ATTRIBUTE,
  2240. SP_STAT_ENTER_EQUALS_CONTINUE,
  2241. 0
  2242. );
  2243. if (SpWaitValidKey(Keys, NULL, NULL) == ASCI_CR)
  2244. return FALSE;
  2245. }
  2246. } else {
  2247. return TRUE;
  2248. }
  2249. }
  2250. }
  2251. }
  2252. //
  2253. // need to create the primary / GPT partition
  2254. //
  2255. SpPtQueryMinMaxCreationSizeMB(DiskNumber,
  2256. Region->StartSector,
  2257. FALSE,
  2258. TRUE,
  2259. &MinMB,
  2260. &MaxMB,
  2261. &ReservedRegion
  2262. );
  2263. if (ReservedRegion) {
  2264. ULONG ValidKeys[2] = {ASCI_CR , 0};
  2265. SpStartScreen(
  2266. SP_SCRN_REGION_RESERVED,
  2267. 3,
  2268. HEADER_HEIGHT+1,
  2269. FALSE,
  2270. FALSE,
  2271. DEFAULT_ATTRIBUTE
  2272. );
  2273. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2274. SP_STAT_ENTER_EQUALS_CONTINUE,
  2275. 0);
  2276. SpWaitValidKey(ValidKeys, NULL, NULL);
  2277. return FALSE;
  2278. }
  2279. if (ForNT) {
  2280. //
  2281. // If a size was requested then try to use that, otherwise use
  2282. // the maximum.
  2283. //
  2284. if (DesiredMB) {
  2285. if (DesiredMB <= MaxMB) {
  2286. SizeMB = DesiredMB;
  2287. } else {
  2288. return FALSE; // don't have the space user requested
  2289. }
  2290. } else {
  2291. SizeMB = MaxMB;
  2292. }
  2293. } else {
  2294. if (!SpPtnGetSizeFromUser(Disk, MinMB, MaxMB, &SizeMB))
  2295. return FALSE; // user didn't want to proceed
  2296. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2297. SP_STAT_PLEASE_WAIT,
  2298. 0);
  2299. }
  2300. //SpPtDumpDiskRegionInformation(DiskNumber, FALSE);
  2301. //
  2302. // Create the partition.
  2303. //
  2304. Result = SpPtnCreate(
  2305. Region->DiskNumber,
  2306. Region->StartSector,
  2307. 0, // SizeInSectors: used only in the ASR case
  2308. SizeMB,
  2309. FALSE,
  2310. TRUE, // AlignToCylinder
  2311. PartInfo,
  2312. ActualRegion
  2313. );
  2314. //SpPtDumpDiskRegionInformation(DiskNumber, FALSE);
  2315. if (!Result) {
  2316. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2317. "SETUP: SpPtnCreate() failed \n"));
  2318. }
  2319. return Result;
  2320. }
  2321. BOOLEAN
  2322. SpPtnDoDelete(
  2323. IN PDISK_REGION pRegion,
  2324. IN PWSTR RegionDescription,
  2325. IN BOOLEAN ConfirmIt
  2326. )
  2327. /*++
  2328. Routine Description:
  2329. Given the region which was selected by the user,
  2330. this routine prompts the user then calls the
  2331. actual deletion routine
  2332. Argument:
  2333. pRegion - Region selected by the user which
  2334. needs to be deleted
  2335. RegionDescription - Description of the
  2336. region
  2337. ConfirmIt - Whether the deletion needs to be
  2338. confirmed
  2339. Return Value:
  2340. TRUE if deletion was carried out and was successful.
  2341. FALSE if deletion was cancelled or could not be carried
  2342. out because of some other error.
  2343. ++*/
  2344. {
  2345. ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; // do not change order
  2346. ULONG Mnemonics[2] = { MnemonicDeletePartition2, 0 };
  2347. PHARD_DISK Disk;
  2348. ULONG Key;
  2349. BOOLEAN Result = FALSE;
  2350. //
  2351. // Prompt for MSR deletion
  2352. //
  2353. if (SPPT_IS_GPT_DISK(pRegion->DiskNumber) &&
  2354. SPPT_IS_REGION_MSFT_RESERVED(pRegion) && ConfirmIt) {
  2355. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_MSRPART, 3, HEADER_HEIGHT+1);
  2356. SpDisplayStatusOptions(
  2357. DEFAULT_STATUS_ATTRIBUTE,
  2358. SP_STAT_ENTER_EQUALS_CONTINUE,
  2359. SP_STAT_ESC_EQUALS_CANCEL,
  2360. 0
  2361. );
  2362. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  2363. return Result;
  2364. }
  2365. }
  2366. //
  2367. // Special warning if this is a system partition.
  2368. //
  2369. // Do not check system partition on NEC98.
  2370. //
  2371. if (!IsNEC_98) { //NEC98
  2372. if(ConfirmIt && pRegion->IsSystemPartition) {
  2373. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_SYSPART,3,HEADER_HEIGHT+1);
  2374. SpDisplayStatusOptions(
  2375. DEFAULT_STATUS_ATTRIBUTE,
  2376. SP_STAT_ENTER_EQUALS_CONTINUE,
  2377. SP_STAT_ESC_EQUALS_CANCEL,
  2378. 0
  2379. );
  2380. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  2381. return Result;
  2382. }
  2383. }
  2384. } //NEC98
  2385. if(ConfirmIt && (pRegion->DynamicVolume || SPPT_IS_REGION_LDM_METADATA(pRegion))) {
  2386. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_DYNVOL,3,HEADER_HEIGHT+1);
  2387. SpDisplayStatusOptions(
  2388. DEFAULT_STATUS_ATTRIBUTE,
  2389. SP_STAT_ENTER_EQUALS_CONTINUE,
  2390. SP_STAT_ESC_EQUALS_CANCEL,
  2391. 0
  2392. );
  2393. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  2394. return Result;
  2395. }
  2396. }
  2397. //
  2398. // CR is no longer a valid key.
  2399. //
  2400. ValidKeys[1] = 0;
  2401. //
  2402. // Display the staus text.
  2403. //
  2404. if (ConfirmIt) {
  2405. Disk = SPPT_GET_HARDDISK(pRegion->DiskNumber);
  2406. SpStartScreen(
  2407. SP_SCRN_CONFIRM_REMOVE_PARTITION,
  2408. 3,
  2409. CLIENT_TOP+1,
  2410. FALSE,
  2411. FALSE,
  2412. DEFAULT_ATTRIBUTE,
  2413. RegionDescription,
  2414. Disk->Description
  2415. );
  2416. SpDisplayStatusOptions(
  2417. DEFAULT_STATUS_ATTRIBUTE,
  2418. SP_STAT_L_EQUALS_DELETE,
  2419. SP_STAT_ESC_EQUALS_CANCEL,
  2420. 0
  2421. );
  2422. Key = SpWaitValidKey(ValidKeys,NULL,Mnemonics);
  2423. if(Key == ASCI_ESC) {
  2424. return Result;
  2425. }
  2426. SpDisplayStatusOptions(
  2427. DEFAULT_STATUS_ATTRIBUTE,
  2428. SP_STAT_PLEASE_WAIT,
  2429. 0);
  2430. }
  2431. //
  2432. // Delete the bootset, if any, for the region
  2433. //
  2434. SpPtDeleteBootSetsForRegion(pRegion);
  2435. //
  2436. // Now go ahead and delete it.
  2437. //
  2438. Result = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
  2439. if (!Result) {
  2440. if (ConfirmIt) {
  2441. SpDisplayScreen(SP_SCRN_PARTITION_DELETE_FAILED,3,HEADER_HEIGHT+1);
  2442. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
  2443. SpInputDrain();
  2444. while(SpInputGetKeypress() != ASCI_CR) ;
  2445. }
  2446. return Result;
  2447. }
  2448. //
  2449. // Delete the drive letters if the necessary. This is to ensure that
  2450. // the drive letters assigned to CD-ROM drives will go away,
  2451. // when the the disks have no partitioned space.
  2452. //
  2453. SpPtDeleteDriveLetters();
  2454. return Result;
  2455. }
  2456. VOID
  2457. SpPtnMakeRegionActive(
  2458. IN PDISK_REGION Region
  2459. )
  2460. /*++
  2461. Routine Description:
  2462. Makes the given region active (i.e. converts into system partition).
  2463. Is valid only for MBR disks. Makes all the other regions
  2464. inactive on the disk
  2465. Arguments:
  2466. Region - The region (primary partition) which needs to made
  2467. active.
  2468. Return Value:
  2469. None.
  2470. --*/
  2471. {
  2472. static BOOLEAN WarnedOtherOS = FALSE;
  2473. if (Region && SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  2474. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(Region->DiskNumber);
  2475. while (CurrRegion) {
  2476. if ((Region != CurrRegion) &&
  2477. SPPT_IS_REGION_ACTIVE_PARTITION(CurrRegion)) {
  2478. //
  2479. // Give the warning for the first time
  2480. //
  2481. if (!WarnedOtherOS && !UnattendedOperation) {
  2482. SpDisplayScreen((SPPT_GET_PARTITION_TYPE(CurrRegion) == 10) ?
  2483. SP_SCRN_BOOT_MANAGER : SP_SCRN_OTHER_OS_ACTIVE,
  2484. 3,
  2485. HEADER_HEIGHT + 1);
  2486. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,
  2487. DEFAULT_STATUS_ATTRIBUTE);
  2488. SpInputDrain();
  2489. while (SpInputGetKeypress() != ASCI_CR) ;
  2490. WarnedOtherOS = TRUE;
  2491. }
  2492. SPPT_MARK_REGION_AS_ACTIVE(CurrRegion, FALSE);
  2493. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2494. }
  2495. CurrRegion = CurrRegion->Next;
  2496. }
  2497. SPPT_MARK_REGION_AS_ACTIVE(Region, TRUE);
  2498. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2499. }
  2500. }
  2501. BOOLEAN
  2502. SpPtMakeDiskRaw(
  2503. IN ULONG DiskNumber
  2504. )
  2505. /*++
  2506. Routine Description:
  2507. Converts the given disk to RAW i.e. Zaps couple of first
  2508. sectors which have information about the disk format
  2509. Arguments:
  2510. DiskNumber : Disk Index, to converted into RAW
  2511. Return Value:
  2512. TRUE, if successful, otherwise FALSE
  2513. --*/
  2514. {
  2515. BOOLEAN Result = FALSE;
  2516. if (DiskNumber < HardDiskCount) {
  2517. HANDLE DiskHandle;
  2518. NTSTATUS Status;
  2519. WCHAR DiskName[256];
  2520. swprintf(DiskName, L"\\Device\\Harddisk%u", DiskNumber);
  2521. //
  2522. // Open partition 0 on this disk..
  2523. //
  2524. Status = SpOpenPartition0(DiskName, &DiskHandle, TRUE);
  2525. if(NT_SUCCESS(Status)){
  2526. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  2527. ULONG BytesPerSector = Disk->Geometry.BytesPerSector;
  2528. ULONG BufferSize = (BytesPerSector * 2);
  2529. PVOID UBuffer = SpMemAlloc(BufferSize);
  2530. if (UBuffer) {
  2531. PVOID Buffer = UBuffer;
  2532. RtlZeroMemory(UBuffer, BufferSize);
  2533. Buffer = ALIGN(Buffer, BytesPerSector);
  2534. //
  2535. // Wipe out 0'th sector
  2536. //
  2537. Status = SpReadWriteDiskSectors(DiskHandle,
  2538. 0,
  2539. 1,
  2540. BytesPerSector,
  2541. Buffer,
  2542. TRUE);
  2543. if (NT_SUCCESS(Status)) {
  2544. //
  2545. // Wipe out 1st sector
  2546. //
  2547. Status = SpReadWriteDiskSectors(DiskHandle,
  2548. 1,
  2549. 1,
  2550. BytesPerSector,
  2551. Buffer,
  2552. TRUE);
  2553. if (NT_SUCCESS(Status)) {
  2554. //
  2555. // Wipe out 2nd sector
  2556. //
  2557. Status = SpReadWriteDiskSectors(DiskHandle,
  2558. 2,
  2559. 1,
  2560. BytesPerSector,
  2561. Buffer,
  2562. TRUE);
  2563. }
  2564. }
  2565. } else {
  2566. Status = STATUS_NO_MEMORY;
  2567. }
  2568. ZwClose(DiskHandle);
  2569. }
  2570. Result = NT_SUCCESS(Status);
  2571. }
  2572. if (Result) {
  2573. SpPtnFreeDiskRegions(DiskNumber);
  2574. }
  2575. return Result;
  2576. }
  2577. VOID
  2578. SpPtnDeletePartitionsForRemoteBoot(
  2579. PPARTITIONED_DISK PartDisk,
  2580. PDISK_REGION StartRegion,
  2581. PDISK_REGION EndRegion,
  2582. BOOLEAN Extended
  2583. )
  2584. /*++
  2585. Routine Description:
  2586. Deletes the specified start region and end region partitions
  2587. and all the partitions in between them.
  2588. Arguments:
  2589. PartDisk : The partitioned disk
  2590. StartRegion : The starting region for deletion
  2591. EndRegion : The Ending region for deletion
  2592. Extended : Not used (for backward compatability)
  2593. Return Value:
  2594. None
  2595. --*/
  2596. {
  2597. PDISK_REGION CurrRegion = StartRegion;
  2598. BOOLEAN FirstContainerDeleted = FALSE;
  2599. ULONG DiskNumber = StartRegion ?
  2600. StartRegion->DiskNumber : EndRegion->DiskNumber;
  2601. BOOLEAN Changes = FALSE;
  2602. NTSTATUS Status;
  2603. NTSTATUS InitStatus;
  2604. //
  2605. // Mark all the regions which need to be deleted
  2606. //
  2607. while (CurrRegion && (CurrRegion != EndRegion)) {
  2608. if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
  2609. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  2610. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2611. if (SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(CurrRegion))
  2612. FirstContainerDeleted = TRUE;
  2613. //
  2614. // Remove any boot sets pointing to this region.
  2615. //
  2616. SpPtDeleteBootSetsForRegion(CurrRegion);
  2617. //
  2618. // Get rid of the compressed drives, if any
  2619. //
  2620. if( CurrRegion->NextCompressed != NULL ) {
  2621. SpDisposeCompressedDrives( CurrRegion->NextCompressed );
  2622. CurrRegion->NextCompressed = NULL;
  2623. CurrRegion->MountDrive = 0;
  2624. CurrRegion->HostDrive = 0;
  2625. }
  2626. }
  2627. CurrRegion = CurrRegion->Next;
  2628. }
  2629. if (EndRegion && CurrRegion && (CurrRegion == EndRegion)){
  2630. if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
  2631. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  2632. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2633. if (SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(CurrRegion))
  2634. FirstContainerDeleted = TRUE;
  2635. //
  2636. // Remove any boot sets pointing to this region.
  2637. //
  2638. SpPtDeleteBootSetsForRegion(CurrRegion);
  2639. //
  2640. // Get rid of the compressed drives, if any
  2641. //
  2642. if( CurrRegion->NextCompressed != NULL ) {
  2643. SpDisposeCompressedDrives( CurrRegion->NextCompressed );
  2644. CurrRegion->NextCompressed = NULL;
  2645. CurrRegion->MountDrive = 0;
  2646. CurrRegion->HostDrive = 0;
  2647. }
  2648. }
  2649. }
  2650. //
  2651. // If the first container partition was deleted then delete
  2652. // all the container and logical partitions,
  2653. //
  2654. if (FirstContainerDeleted) {
  2655. CurrRegion = PartDisk->PrimaryDiskRegions;
  2656. while (CurrRegion) {
  2657. if (SPPT_IS_REGION_CONTAINER_PARTITION(CurrRegion) ||
  2658. SPPT_IS_REGION_LOGICAL_DRIVE(CurrRegion)) {
  2659. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  2660. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2661. //
  2662. // Remove any boot sets pointing to this region.
  2663. //
  2664. SpPtDeleteBootSetsForRegion(CurrRegion);
  2665. //
  2666. // Get rid of the compressed drives, if any
  2667. //
  2668. if( CurrRegion->NextCompressed != NULL ) {
  2669. SpDisposeCompressedDrives( CurrRegion->NextCompressed );
  2670. CurrRegion->NextCompressed = NULL;
  2671. CurrRegion->MountDrive = 0;
  2672. CurrRegion->HostDrive = 0;
  2673. }
  2674. }
  2675. CurrRegion = CurrRegion->Next;
  2676. }
  2677. }
  2678. //
  2679. // Commit the changes
  2680. //
  2681. Status = SpPtnCommitChanges(DiskNumber, &Changes);
  2682. //
  2683. // Initialize region structure for the disk again
  2684. //
  2685. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  2686. if (!NT_SUCCESS(Status) || !Changes || !NT_SUCCESS(InitStatus)) {
  2687. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2688. "SETUP:SpPtnDeletePartitionsForRemoteBoot(%p, %p, %p, %d) failed "
  2689. "with %lx status\n",
  2690. PartDisk,
  2691. StartRegion,
  2692. EndRegion,
  2693. Extended,
  2694. Status));
  2695. }
  2696. }
  2697. NTSTATUS
  2698. SpPtnMakeRegionArcSysPart(
  2699. IN PDISK_REGION Region
  2700. )
  2701. /*++
  2702. Routine Description:
  2703. Makes the given region a system partition on ARC machines
  2704. Arguments:
  2705. Region - The region which needs to be convered to system
  2706. partition
  2707. Return Value:
  2708. STATUS_SUCCESS if successful, otherwise appropriate error
  2709. code.
  2710. --*/
  2711. {
  2712. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2713. if (Region && SpIsArc() && !ValidArcSystemPartition) {
  2714. if (SPPT_IS_MBR_DISK(Region->DiskNumber)) {
  2715. if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  2716. SpPtnMakeRegionActive(Region);
  2717. SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
  2718. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2719. Status = STATUS_SUCCESS;
  2720. }
  2721. } else {
  2722. WCHAR RegionName[MAX_PATH];
  2723. SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
  2724. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2725. //
  2726. // Remove the drive letter also
  2727. //
  2728. swprintf(RegionName,
  2729. L"\\Device\\Harddisk%u\\Partition%u",
  2730. Region->DiskNumber,
  2731. Region->PartitionNumber);
  2732. SpDeleteDriveLetter(RegionName);
  2733. Region->DriveLetter = 0;
  2734. Status = STATUS_SUCCESS;
  2735. }
  2736. }
  2737. return Status;
  2738. }
  2739. ULONG
  2740. SpPtnCountPartitionsByFSType(
  2741. IN ULONG DiskId,
  2742. IN FilesystemType FsType
  2743. )
  2744. /*++
  2745. Routine Description:
  2746. Counts the partition based on the file system type.
  2747. Note : The partitions which are marked
  2748. deleted are skipped.
  2749. Arguments:
  2750. DiskId : The disk on which the partitions need to be
  2751. counted
  2752. FsType : File system type which needs to present on
  2753. the partitions
  2754. Return Value:
  2755. Number of partitions containing the requested file system
  2756. --*/
  2757. {
  2758. ULONG Count = 0;
  2759. if ((FsType < FilesystemMax) && (DiskId < HardDiskCount)) {
  2760. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  2761. while (Region) {
  2762. if (SPPT_IS_REGION_PARTITIONED(Region) &&
  2763. !SPPT_IS_REGION_MARKED_DELETE(Region) &&
  2764. (Region->Filesystem == FsType)) {
  2765. Count++;
  2766. }
  2767. Region = Region->Next;
  2768. }
  2769. }
  2770. return Count;
  2771. }
  2772. PDISK_REGION
  2773. SpPtnLocateESP(
  2774. VOID
  2775. )
  2776. {
  2777. PDISK_REGION EspRegion = NULL;
  2778. ULONG Index;
  2779. for (Index=0; (Index < HardDiskCount) && (!EspRegion); Index++) {
  2780. if (SPPT_IS_GPT_DISK(Index)) {
  2781. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(Index);
  2782. while (CurrRegion) {
  2783. if (SPPT_IS_REGION_PARTITIONED(CurrRegion) &&
  2784. SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
  2785. EspRegion = CurrRegion;
  2786. break; // found the first ESP
  2787. }
  2788. CurrRegion = CurrRegion->Next;
  2789. }
  2790. }
  2791. }
  2792. return EspRegion;
  2793. }
  2794. NTSTATUS
  2795. SpPtnCreateESPForDisk(
  2796. IN ULONG DiskId
  2797. )
  2798. {
  2799. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2800. PDISK_REGION EspCandidateRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  2801. if (EspCandidateRegion && SpPtnIsValidESPRegion(EspCandidateRegion)) {
  2802. ULONG DiskId = EspCandidateRegion->DiskNumber;
  2803. ULONGLONG SizeMB = SpPtnGetDiskESPSizeMB(DiskId);
  2804. PARTITION_INFORMATION_EX PartInfo;
  2805. PDISK_REGION EspRegion = NULL;
  2806. BOOLEAN CreateResult;
  2807. RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
  2808. PartInfo.PartitionStyle = PARTITION_STYLE_GPT;
  2809. PartInfo.Gpt.Attributes = 1; // required ???
  2810. PartInfo.Gpt.PartitionType = PARTITION_SYSTEM_GUID;
  2811. SpCreateNewGuid(&(PartInfo.Gpt.PartitionId));
  2812. CreateResult = SpPtnCreate(DiskId,
  2813. EspCandidateRegion->StartSector,
  2814. 0, // SizeInSectors: used only in the ASR case
  2815. SizeMB,
  2816. FALSE,
  2817. TRUE,
  2818. &PartInfo,
  2819. &EspRegion);
  2820. if (CreateResult) {
  2821. //
  2822. // format this region
  2823. //
  2824. WCHAR RegionDescr[128];
  2825. //
  2826. // Mark this region as ESP
  2827. //
  2828. SPPT_MARK_REGION_AS_SYSTEMPARTITION(EspRegion, TRUE);
  2829. SPPT_SET_REGION_DIRTY(EspRegion, TRUE);
  2830. ValidArcSystemPartition = TRUE;
  2831. SpPtRegionDescription(
  2832. SPPT_GET_PARTITIONED_DISK(EspRegion->DiskNumber),
  2833. EspRegion,
  2834. RegionDescr,
  2835. sizeof(RegionDescr));
  2836. if (!SetupSourceDevicePath || !DirectoryOnSetupSource) {
  2837. SpGetWinntParams(&SetupSourceDevicePath, &DirectoryOnSetupSource);
  2838. }
  2839. Status = SpDoFormat(RegionDescr,
  2840. EspRegion,
  2841. FilesystemFat,
  2842. TRUE,
  2843. TRUE,
  2844. FALSE,
  2845. SifHandle,
  2846. 0, // default cluster size
  2847. SetupSourceDevicePath,
  2848. DirectoryOnSetupSource);
  2849. if (!NT_SUCCESS(Status)) {
  2850. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2851. "SETUP:SpPtnCreateESP() failed to"
  2852. " format ESP partition for %p region (%lx)\n",
  2853. EspRegion,
  2854. Status));
  2855. } else {
  2856. BOOLEAN AnyChanges = FALSE;
  2857. Status = SpPtnCommitChanges(EspRegion->DiskNumber,
  2858. &AnyChanges);
  2859. if (!NT_SUCCESS(Status)) {
  2860. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2861. "SETUP:SpPtnCreateESP() failed to"
  2862. " commit changes to disk (%lx)\n",
  2863. Status));
  2864. }
  2865. Status = SpPtnInitializeDiskDrive(EspRegion->DiskNumber);
  2866. if (!NT_SUCCESS(Status)) {
  2867. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2868. "SETUP:SpPtnCreateESP() failed to"
  2869. " reinitialize disk regions (%lx)\n",
  2870. Status));
  2871. }
  2872. }
  2873. } else {
  2874. Status = STATUS_UNSUCCESSFUL;
  2875. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2876. "SETUP:SpPtnCreateESP() failed to"
  2877. " create ESP partition for %p region (%lx)\n",
  2878. EspRegion,
  2879. Status));
  2880. }
  2881. }
  2882. return Status;
  2883. }
  2884. NTSTATUS
  2885. SpPtnCreateESP(
  2886. IN BOOLEAN PromptUser
  2887. )
  2888. {
  2889. NTSTATUS Status = STATUS_CANCELLED;
  2890. BOOLEAN Confirmed = FALSE;
  2891. if (ValidArcSystemPartition) {
  2892. Status = STATUS_SUCCESS;
  2893. return Status;
  2894. }
  2895. if (UnattendedOperation) {
  2896. Confirmed = TRUE;
  2897. } else {
  2898. if (PromptUser) {
  2899. //
  2900. // Prompt the user for confirmation
  2901. //
  2902. ULONG ValidKeys[] = { ASCI_CR, ASCI_ESC, 0 };
  2903. ULONG UserOption = ASCI_CR;
  2904. SpDisplayScreen(SP_AUTOCREATE_ESP, 3, HEADER_HEIGHT+1);
  2905. SpDisplayStatusOptions(
  2906. DEFAULT_STATUS_ATTRIBUTE,
  2907. SP_STAT_ENTER_EQUALS_CONTINUE,
  2908. SP_STAT_ESC_EQUALS_CANCEL,
  2909. 0);
  2910. //
  2911. // Wait for user input
  2912. //
  2913. SpInputDrain();
  2914. UserOption = SpWaitValidKey(ValidKeys, NULL, NULL);
  2915. if (UserOption == ASCI_CR) {
  2916. Confirmed = TRUE;
  2917. }
  2918. } else {
  2919. Confirmed = TRUE;
  2920. }
  2921. }
  2922. if (Confirmed) {
  2923. WCHAR ArcDiskName[MAX_PATH];
  2924. ULONG DiskNumber;
  2925. ULONG ArcDiskNumber;
  2926. PDISK_REGION EspCandidateRegion = NULL;
  2927. //
  2928. // Find the first harddisk (non-removable) media that the
  2929. // BIOS enumerated to be used for system partition
  2930. //
  2931. for (DiskNumber = 0, Status = STATUS_UNSUCCESSFUL;
  2932. (!NT_SUCCESS(Status) && (DiskNumber < HardDiskCount));
  2933. DiskNumber++) {
  2934. swprintf(ArcDiskName, L"multi(0)disk(0)rdisk(%d)", DiskNumber);
  2935. ArcDiskNumber = SpArcDevicePathToDiskNumber(ArcDiskName);
  2936. //
  2937. // Make sure its not removable disk and its reachable by firmware
  2938. //
  2939. if ((ArcDiskNumber == (ULONG)-1) || SPPT_IS_REMOVABLE_DISK(ArcDiskNumber)) {
  2940. continue; // get to the next disk
  2941. }
  2942. Status = SpPtnCreateESPForDisk(ArcDiskNumber);
  2943. }
  2944. if (PromptUser && !NT_SUCCESS(Status)) {
  2945. ULONG ValidKeys[] = { ASCI_CR, 0 };
  2946. ValidArcSystemPartition = FALSE;
  2947. SpDisplayScreen(SP_AUTOCREATE_ESP_FAILED, 3, HEADER_HEIGHT+1);
  2948. SpDisplayStatusOptions(
  2949. DEFAULT_STATUS_ATTRIBUTE,
  2950. SP_STAT_ENTER_EQUALS_CONTINUE,
  2951. 0);
  2952. //
  2953. // Wait for user input
  2954. //
  2955. SpInputDrain();
  2956. SpWaitValidKey(ValidKeys, NULL, NULL);
  2957. }
  2958. } else {
  2959. Status = STATUS_CANCELLED;
  2960. }
  2961. return Status;
  2962. }
  2963. NTSTATUS
  2964. SpPtnInitializeGPTDisk(
  2965. IN ULONG DiskNumber
  2966. )
  2967. {
  2968. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2969. if ((DiskNumber < HardDiskCount) && (SPPT_IS_GPT_DISK(DiskNumber))) {
  2970. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2971. PDISK_REGION EspRegion = NULL;
  2972. PDISK_REGION MsrRegion = NULL;
  2973. while (CurrRegion && !EspRegion && !MsrRegion) {
  2974. if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
  2975. EspRegion = CurrRegion;
  2976. } else if (SPPT_IS_REGION_MSFT_RESERVED(CurrRegion)) {
  2977. MsrRegion = CurrRegion;
  2978. }
  2979. CurrRegion = CurrRegion->Next;
  2980. }
  2981. if (!MsrRegion) {
  2982. PDISK_REGION MsrCandidate = NULL;
  2983. if (EspRegion) {
  2984. MsrCandidate = EspRegion->Next;
  2985. } else {
  2986. MsrCandidate = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2987. }
  2988. if (MsrCandidate && SpPtnIsValidMSRRegion(MsrCandidate)) {
  2989. PARTITION_INFORMATION_EX PartInfo;
  2990. PDISK_REGION MsrRegion = NULL;
  2991. ULONGLONG SizeMB = SpPtnGetDiskMSRSizeMB(DiskNumber);
  2992. BOOLEAN CreateResult;
  2993. RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
  2994. PartInfo.PartitionStyle = PARTITION_STYLE_GPT;
  2995. PartInfo.Gpt.Attributes = 0; // required ???
  2996. PartInfo.Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID;
  2997. SpCreateNewGuid(&(PartInfo.Gpt.PartitionId));
  2998. CreateResult = SpPtnCreate(DiskNumber,
  2999. MsrCandidate->StartSector,
  3000. 0, // SizeInSectors: used only in the ASR case
  3001. SizeMB,
  3002. FALSE,
  3003. TRUE,
  3004. &PartInfo,
  3005. &MsrRegion);
  3006. Status = CreateResult ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  3007. if (!NT_SUCCESS(Status)) {
  3008. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  3009. "SETUP:SpPtnInitializeGPTDisk() failed with "
  3010. " (%lx)\n",
  3011. Status));
  3012. }
  3013. } else {
  3014. Status = STATUS_SUCCESS;
  3015. }
  3016. } else {
  3017. Status = STATUS_SUCCESS;
  3018. }
  3019. }
  3020. return Status;
  3021. }
  3022. NTSTATUS
  3023. SpPtnInitializeGPTDisks(
  3024. VOID
  3025. )
  3026. {
  3027. NTSTATUS LastError = STATUS_SUCCESS;
  3028. NTSTATUS Status = STATUS_SUCCESS;
  3029. ULONG DiskNumber;
  3030. for (DiskNumber = 0; (DiskNumber < HardDiskCount); DiskNumber++) {
  3031. if (SPPT_IS_GPT_DISK(DiskNumber)) {
  3032. Status = SpPtnInitializeGPTDisk(DiskNumber);
  3033. if (!NT_SUCCESS(Status)) {
  3034. LastError = Status;
  3035. }
  3036. }
  3037. }
  3038. return LastError;
  3039. }
  3040. NTSTATUS
  3041. SpPtnRepartitionGPTDisk(
  3042. IN ULONG DiskId,
  3043. IN ULONG MinimumFreeSpaceKB,
  3044. OUT PDISK_REGION *RegionToInstall
  3045. )
  3046. /*++
  3047. Routine Description:
  3048. Repartitions a given disk for unattended and remote
  3049. boot install case
  3050. Arguments:
  3051. DiskId : The disk which needs to be repartitioned
  3052. MinimumFreeSpace : Minimum space required in KB
  3053. RegionToInstall : Place holder for the region which
  3054. will be selected for installation.
  3055. Return Value:
  3056. Appropriate status code.
  3057. --*/
  3058. {
  3059. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3060. if ((DiskId < HardDiskCount) && !SPPT_IS_REMOVABLE_DISK(DiskId)) {
  3061. PDISK_REGION CurrentRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  3062. BOOLEAN Changes = FALSE;
  3063. //
  3064. // Mark all the existing partitioned space on the disk
  3065. // for deletion
  3066. //
  3067. while (CurrentRegion) {
  3068. if (SPPT_IS_REGION_PARTITIONED(CurrentRegion)) {
  3069. SPPT_SET_REGION_DELETED(CurrentRegion, TRUE);
  3070. SPPT_SET_REGION_DIRTY(CurrentRegion, TRUE);
  3071. Changes = TRUE;
  3072. }
  3073. CurrentRegion = CurrentRegion->Next;
  3074. }
  3075. //
  3076. // Delete all the partitioned space on the disk
  3077. //
  3078. if (Changes) {
  3079. Status = SpPtnCommitChanges(DiskId, &Changes);
  3080. } else {
  3081. Status = STATUS_SUCCESS;
  3082. }
  3083. if (!NT_SUCCESS(Status)) {
  3084. return Status;
  3085. }
  3086. //
  3087. // Update the in memory region structure for the disk
  3088. //
  3089. Status = SpPtnInitializeDiskDrive(DiskId);
  3090. if (!NT_SUCCESS(Status)) {
  3091. return Status;
  3092. }
  3093. //
  3094. // Reinitialize the disk style to GPT to be sure its
  3095. // GPT disk
  3096. //
  3097. SPPT_SET_DISK_BLANK(DiskId, TRUE);
  3098. Status = SpPtnInitializeDiskStyle(DiskId,
  3099. PARTITION_STYLE_GPT,
  3100. NULL);
  3101. if (!NT_SUCCESS(Status)) {
  3102. return Status;
  3103. }
  3104. //
  3105. // Update the in memory region structure for the disk
  3106. //
  3107. Status = SpPtnInitializeDiskDrive(DiskId);
  3108. if (!NT_SUCCESS(Status)) {
  3109. return Status;
  3110. }
  3111. //
  3112. // First create the ESP on the disk
  3113. //
  3114. Status = SpPtnCreateESPForDisk(DiskId);
  3115. if (!NT_SUCCESS(Status)) {
  3116. return Status;
  3117. }
  3118. //
  3119. // Create the MSR partition
  3120. //
  3121. Status = SpPtnInitializeGPTDisk(DiskId);
  3122. if (!NT_SUCCESS(Status)) {
  3123. return Status;
  3124. }
  3125. //
  3126. // Find the first free space region with adequate space
  3127. //
  3128. CurrentRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  3129. while (CurrentRegion) {
  3130. if (SPPT_IS_REGION_FREESPACE(CurrentRegion) &&
  3131. (SPPT_REGION_FREESPACE_KB(CurrentRegion) >= MinimumFreeSpaceKB)) {
  3132. break;
  3133. }
  3134. CurrentRegion = CurrentRegion->Next;
  3135. }
  3136. if (CurrentRegion) {
  3137. *RegionToInstall = CurrentRegion;
  3138. } else {
  3139. Status = STATUS_UNSUCCESSFUL;
  3140. }
  3141. }
  3142. return Status;
  3143. }