Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4186 lines
126 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 && BytesPerSector) {
  278. ULONG BufferSize = (BytesPerSector * 2);
  279. PVOID UBuffer = SpMemAlloc(BufferSize);
  280. ULONGLONG SectorIdx = StartSector;
  281. if (UBuffer) {
  282. PVOID Buffer ;
  283. RtlZeroMemory(UBuffer, BufferSize);
  284. Buffer = ALIGN(UBuffer, 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. 0)) {
  1395. //
  1396. // User pressed escape and bailed.
  1397. //
  1398. Result = FALSE;
  1399. break;
  1400. }
  1401. *SizeMB = SpStringToLong(SizeBuffer, NULL, 10);
  1402. }
  1403. while(((*SizeMB) < MinMB) || ((*SizeMB) > MaxMB));
  1404. return Result;
  1405. }
  1406. VOID
  1407. SpPtnAlignPartitionStartAndEnd(
  1408. IN PHARD_DISK Disk,
  1409. IN ULONGLONG SizeMB,
  1410. IN ULONGLONG StartSector,
  1411. IN PDISK_REGION Region,
  1412. IN BOOLEAN ForExtended,
  1413. OUT PULONGLONG AlignedStartSector,
  1414. OUT PULONGLONG AlignedEndSector
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. Aligns the partition start and end sector
  1419. Arguments:
  1420. Disk - Partition's disk for which alignment needs to be
  1421. done.
  1422. SizeMB - The partition's size
  1423. StartSector - The start sector of the partition
  1424. Region - The region representing the partition
  1425. ForExtended - Whether this partition needs to be aligned
  1426. for creating a container partition.
  1427. AlignedStartSector - Place holder for the aligned start sector
  1428. AlignedEndSector - Place holder fot the aligned end sector
  1429. Return Value:
  1430. None
  1431. --*/
  1432. {
  1433. ULONGLONG SectorCount;
  1434. ULONGLONG LeftOverSectors;
  1435. //
  1436. // Determine the number of sectors in the size passed in.
  1437. //
  1438. SectorCount = SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector);
  1439. //
  1440. // If this is the first free space inside the extended partition
  1441. // we need to decrement the StartSector so that while creating
  1442. // first logical inside the extended we don't create the
  1443. // logical at one cylinder offset
  1444. //
  1445. if (SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(Region) && StartSector) {
  1446. StartSector--;
  1447. }
  1448. //
  1449. // Align the start sector.
  1450. //
  1451. (*AlignedStartSector) = SpPtAlignStart(Disk, StartSector, ForExtended);
  1452. //
  1453. // Determine the end sector based on the size passed in.
  1454. //
  1455. (*AlignedEndSector) = (*AlignedStartSector) + SectorCount;
  1456. //
  1457. // Align the ending sector to a cylinder boundary. If it is not already
  1458. // aligned and is more than half way into the final cylinder, align it up,
  1459. // otherwise align it down.
  1460. //
  1461. LeftOverSectors = (*AlignedEndSector) % Disk->SectorsPerCylinder;
  1462. if (LeftOverSectors) {
  1463. (*AlignedEndSector) -= LeftOverSectors;
  1464. if (LeftOverSectors > (Disk->SectorsPerCylinder / 2)) {
  1465. (*AlignedEndSector) += Disk->SectorsPerCylinder;
  1466. }
  1467. }
  1468. //
  1469. // If the ending sector is past the end of the free space, shrink it
  1470. // so it fits.
  1471. //
  1472. while((*AlignedEndSector) > StartSector + Region->SectorCount) {
  1473. (*AlignedEndSector) -= Disk->SectorsPerCylinder;
  1474. }
  1475. //
  1476. // Find out if last sector is in the last cylinder. If it is then align it down.
  1477. // This is necessary so that we reserve a cylinder at the end of the disk, so that users
  1478. // can convert the disk to dynamic after the system is installed.
  1479. //
  1480. // (guhans) Don't align down if this is ASR. ASR already takes this into account.
  1481. //
  1482. if( !DockableMachine && !SpDrEnabled() &&
  1483. ((*AlignedEndSector) > ((Disk->CylinderCount - 1) * Disk->SectorsPerCylinder))) {
  1484. (*AlignedEndSector) -= Disk->SectorsPerCylinder;
  1485. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1486. "SETUP: End of partition was aligned down 1 cylinder \n"));
  1487. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1488. "SETUP: AlignedStartSector = %I64x \n", AlignedStartSector));
  1489. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1490. "SETUP: AlignedEndSector = %I64x \n", AlignedEndSector));
  1491. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1492. "SETUP: SectorsPerCylinder = %lx \n", Disk->SectorsPerCylinder));
  1493. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1494. "SETUP: CylinderCount = %lx \n", Disk->CylinderCount));
  1495. }
  1496. ASSERT((*AlignedEndSector) > 0);
  1497. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1498. "SETUP:SpPtnAlignPartitionStartAndEnd:S/C:%d,Size:%I64d,"
  1499. "StartSector:%I64d,RSS:%I64d,FE:%d,AS:%I64d,AE:%I64d\n"
  1500. "LeftOverSectors:%I64d\n",
  1501. Disk->SectorsPerCylinder,
  1502. SizeMB,
  1503. StartSector,
  1504. Region->StartSector,
  1505. ForExtended,
  1506. *AlignedStartSector,
  1507. *AlignedEndSector,
  1508. LeftOverSectors));
  1509. }
  1510. BOOLEAN
  1511. SpPtnCreateLogicalDrive(
  1512. IN ULONG DiskNumber,
  1513. IN ULONGLONG StartSector,
  1514. IN ULONGLONG SizeInSectors, // Used ONLY in the ASR case
  1515. IN BOOLEAN ForNT,
  1516. IN BOOLEAN AlignToCylinder,
  1517. IN ULONGLONG DesiredMB OPTIONAL,
  1518. IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
  1519. OUT PDISK_REGION *ActualDiskRegion OPTIONAL
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. Creates logical drive.
  1524. To create a logical drive we need to create the
  1525. logical drive's container partition also first.
  1526. Algorithm:
  1527. if (first logical drive) {
  1528. 1. create an extended partition encompassing the
  1529. whole free space in region
  1530. 2. create a logical drive at one track offset
  1531. from the extened partition of the required size
  1532. } else {
  1533. 1. create an extended partition encompassing the
  1534. given space
  1535. 2. create a logical drive of the maximim size
  1536. inside the created extended partition
  1537. }
  1538. Arguments:
  1539. DiskNumber - Disk on which logical drive nedds to be
  1540. created.
  1541. StartSector - The starting sector for the region, which
  1542. will contain the container & logical drive
  1543. ForNT - Indicating whether to use the given
  1544. Desired Size or not
  1545. AlignToCylinder - Indicating whether the partition should
  1546. be aligned on a cylinder boundary (Usually set
  1547. to TRUE, except in a few specific ASR cases).
  1548. PartInfo - Partition Information which needs to be
  1549. used while creating the partition (like
  1550. Partition Type on MBR disks and GUID
  1551. for Partition Id on GPT disks)
  1552. ActualDiskRegion - Place holder for returning, the
  1553. region which indicates the new
  1554. partition in memory
  1555. Return Value:
  1556. TRUE is successful otherwise FALSE.
  1557. --*/
  1558. {
  1559. BOOLEAN Result = FALSE;
  1560. NTSTATUS Status;
  1561. NTSTATUS InitStatus;
  1562. UCHAR PartitionType = 0;
  1563. ULONG Primary = 0, Container = 0, Logical = 0;
  1564. BOOLEAN FirstLogical = FALSE;
  1565. BOOLEAN ReservedRegion = FALSE;
  1566. BOOLEAN CreateContainer = TRUE;
  1567. BOOLEAN Beyond1024;
  1568. BOOLEAN FreeRegions = FALSE;
  1569. ULONGLONG MinMB = 0, MaxMB = 0, SizeMB = 0;
  1570. ULONGLONG LogicalSize = 0;
  1571. ULONGLONG CylinderMB = 0;
  1572. PDISK_REGION Region;
  1573. ULONGLONG SectorCount, LeftOverSectors;
  1574. ULONGLONG AlignedStartSector, AlignedEndSector;
  1575. ULONGLONG LogicalStartSector, LogicalEndSector;
  1576. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  1577. PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  1578. PDISK_REGION NewContainer = NULL, NewLogical = NULL;
  1579. //
  1580. // get hold of the region
  1581. //
  1582. Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
  1583. if (!Region)
  1584. return Result;
  1585. //
  1586. // should be free
  1587. //
  1588. ASSERT(SPPT_IS_REGION_PARTITIONED(Region) == FALSE);
  1589. //
  1590. // get the various partition type count on the disk
  1591. //
  1592. SpPtnGetPartitionTypeCounts(DiskNumber,
  1593. TRUE,
  1594. &Primary,
  1595. &Container,
  1596. &Logical,
  1597. NULL,
  1598. NULL);
  1599. //
  1600. // first logical indicates, what we will be creating the first
  1601. // container partition which will consume the whole free space
  1602. // available
  1603. //
  1604. FirstLogical = !(Logical || Container);
  1605. //
  1606. // Some times there might be just an extended partition and we
  1607. // might be creating the partition in the starting free space inside
  1608. // this extended partition. For this case we want to make sure that
  1609. // we don't create another container partition
  1610. //
  1611. if (!FirstLogical && SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(Region)) {
  1612. CreateContainer = FALSE;
  1613. }
  1614. //
  1615. // Create an extened partition
  1616. //
  1617. SpPtQueryMinMaxCreationSizeMB(DiskNumber,
  1618. Region->StartSector,
  1619. CreateContainer,
  1620. !CreateContainer,
  1621. &MinMB,
  1622. &MaxMB,
  1623. &ReservedRegion
  1624. );
  1625. if (ReservedRegion) {
  1626. ULONG ValidKeys[2] = {ASCI_CR , 0};
  1627. SpStartScreen(
  1628. SP_SCRN_REGION_RESERVED,
  1629. 3,
  1630. HEADER_HEIGHT+1,
  1631. FALSE,
  1632. FALSE,
  1633. DEFAULT_ATTRIBUTE
  1634. );
  1635. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1636. SP_STAT_ENTER_EQUALS_CONTINUE,
  1637. 0);
  1638. SpWaitValidKey(ValidKeys, NULL, NULL);
  1639. return FALSE;
  1640. }
  1641. if (ForNT) {
  1642. //
  1643. // If a size was requested then try to use that, otherwise use
  1644. // the maximum.
  1645. //
  1646. if (DesiredMB) {
  1647. if (DesiredMB <= MaxMB) {
  1648. SizeMB = DesiredMB;
  1649. } else {
  1650. return FALSE; // don't have the space user requested
  1651. }
  1652. } else {
  1653. SizeMB = MaxMB;
  1654. }
  1655. } else {
  1656. if (SpPtnGetSizeFromUser(Disk, MinMB, MaxMB, &SizeMB)) {
  1657. DesiredMB = SizeMB;
  1658. } else {
  1659. return FALSE; // user didn't want to proceed
  1660. }
  1661. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  1662. SP_STAT_PLEASE_WAIT,
  1663. 0);
  1664. }
  1665. //
  1666. // get the aligned start and end sector for exteneded/logical partition
  1667. //
  1668. if (AlignToCylinder) {
  1669. SpPtnAlignPartitionStartAndEnd(Disk,
  1670. FirstLogical ? MaxMB : SizeMB,
  1671. StartSector,
  1672. Region,
  1673. CreateContainer,
  1674. &AlignedStartSector,
  1675. &AlignedEndSector);
  1676. }
  1677. else {
  1678. AlignedStartSector = StartSector;
  1679. if (SpDrEnabled()) {
  1680. AlignedEndSector = StartSector + SizeInSectors;
  1681. }
  1682. else {
  1683. AlignedEndSector = StartSector +
  1684. (SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector));
  1685. }
  1686. }
  1687. if (CreateContainer) {
  1688. //
  1689. // Logical drive start is always at 1 track offset from extended start
  1690. //
  1691. LogicalStartSector = AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber);
  1692. if (FirstLogical) {
  1693. ULONGLONG SectorCount = (SizeMB * 1024 * 1024) / SPPT_DISK_SECTOR_SIZE(DiskNumber);
  1694. ULONGLONG Remainder = 0;
  1695. if (SpDrEnabled()) {
  1696. SectorCount = SizeInSectors;
  1697. }
  1698. LogicalEndSector = LogicalStartSector + SectorCount;
  1699. if (AlignToCylinder) {
  1700. Remainder = LogicalEndSector % SPPT_DISK_CYLINDER_SIZE(DiskNumber);
  1701. LogicalEndSector -= Remainder;
  1702. if (Remainder > (SPPT_DISK_CYLINDER_SIZE(DiskNumber) / 2))
  1703. LogicalEndSector += SPPT_DISK_CYLINDER_SIZE(DiskNumber);
  1704. }
  1705. if (LogicalEndSector > AlignedEndSector)
  1706. LogicalEndSector = AlignedEndSector;
  1707. } else {
  1708. LogicalEndSector = AlignedEndSector;
  1709. }
  1710. } else {
  1711. //
  1712. // The first free region (inside first extended) is at the offset
  1713. // of 1 sector from the previous exteneded region. Since we are not
  1714. // using the aligned start sector some times this first logical
  1715. // will be greater than the requested size i.e.
  1716. // end is aligned but start may not be aligned
  1717. //
  1718. LogicalStartSector = StartSector - 1 + SPPT_DISK_TRACK_SIZE(DiskNumber);
  1719. LogicalEndSector = AlignedEndSector;
  1720. }
  1721. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1722. "SETUP:SpPtnCreateLogicalDrive():"
  1723. "CMB:%I64d,CS:%I64d,CE:%I64d,LS:%I64d,LE:%I64d\n",
  1724. CylinderMB,
  1725. AlignedStartSector,
  1726. AlignedEndSector,
  1727. LogicalStartSector,
  1728. LogicalEndSector));
  1729. //
  1730. // allocate the new regions
  1731. //
  1732. if (CreateContainer) {
  1733. //
  1734. // allocate the container region
  1735. //
  1736. NewContainer = (PDISK_REGION)SpMemAlloc(sizeof(DISK_REGION));
  1737. if (!NewContainer)
  1738. return FALSE;
  1739. RtlZeroMemory(NewContainer, sizeof(DISK_REGION));
  1740. }
  1741. //
  1742. // allocate the logical drive region
  1743. //
  1744. NewLogical = (PDISK_REGION)SpMemAlloc(sizeof(DISK_REGION));
  1745. if (!NewLogical) {
  1746. SpMemFree(NewContainer);
  1747. return FALSE;
  1748. }
  1749. RtlZeroMemory(NewLogical, sizeof(DISK_REGION));
  1750. //
  1751. // put the new regions in the list
  1752. //
  1753. if (CreateContainer) {
  1754. NewContainer->Next = NewLogical;
  1755. NewLogical->Next = Region->Next;
  1756. Region->Next = NewContainer;
  1757. } else {
  1758. //
  1759. // This is the first logical inside the
  1760. // already existing extended partition
  1761. //
  1762. ASSERT(Region->Container->Next == Region);
  1763. NewLogical->Next = Region->Next;
  1764. Region->Container->Next = NewLogical;
  1765. }
  1766. //
  1767. // fill the container disk region.
  1768. //
  1769. if (CreateContainer) {
  1770. ASSERT(AlignedStartSector < AlignedEndSector);
  1771. NewContainer->DiskNumber = DiskNumber;
  1772. NewContainer->StartSector = AlignedStartSector;
  1773. NewContainer->SectorCount = AlignedEndSector - AlignedStartSector;
  1774. if (!FirstLogical) {
  1775. PDISK_REGION FirstContainer = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  1776. while (FirstContainer && !SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(FirstContainer))
  1777. FirstContainer = FirstContainer->Next;
  1778. ASSERT(FirstContainer);
  1779. NewContainer->Container = FirstContainer;
  1780. }
  1781. SPPT_SET_REGION_PARTITIONED(NewContainer, FALSE);
  1782. SPPT_SET_REGION_DIRTY(NewContainer, TRUE);
  1783. SPPT_SET_REGION_EPT(NewContainer, EPTContainerPartition);
  1784. NewContainer->FreeSpaceKB = (ULONG)(-1);
  1785. NewContainer->AdjustedFreeSpaceKB = (ULONG)(-1);
  1786. Beyond1024 = SpIsRegionBeyondCylinder1024(NewContainer);
  1787. //
  1788. // Only mark the first extended (container) partition as XINT13_EXTENDED
  1789. // if beyond 1024 cylinders, for backward compatability with Win9x
  1790. //
  1791. PartitionType = (Beyond1024 && FirstLogical) ? PARTITION_XINT13_EXTENDED : PARTITION_EXTENDED;
  1792. SPPT_SET_PARTITION_TYPE(NewContainer, PartitionType);
  1793. }
  1794. //
  1795. // fill in the logical disk region
  1796. //
  1797. ASSERT(LogicalStartSector < LogicalEndSector);
  1798. if (CreateContainer) {
  1799. ASSERT((AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber)) == LogicalStartSector);
  1800. if (LogicalStartSector != (AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber))) {
  1801. LogicalStartSector = AlignedStartSector + SPPT_DISK_TRACK_SIZE(DiskNumber);
  1802. }
  1803. }
  1804. ASSERT(LogicalEndSector <= AlignedEndSector);
  1805. if (LogicalEndSector > AlignedEndSector) {
  1806. LogicalEndSector = AlignedEndSector;
  1807. }
  1808. NewLogical->DiskNumber = DiskNumber;
  1809. NewLogical->StartSector = LogicalStartSector;
  1810. NewLogical->SectorCount = LogicalEndSector - LogicalStartSector;
  1811. if (CreateContainer) {
  1812. NewLogical->Container = NewContainer; // the new logical drive's container !!!
  1813. } else {
  1814. ASSERT(Region->Container);
  1815. NewLogical->Container = Region->Container;
  1816. }
  1817. SPPT_SET_REGION_PARTITIONED(NewLogical, TRUE);
  1818. SPPT_SET_REGION_DIRTY(NewLogical, TRUE);
  1819. SPPT_SET_REGION_EPT(NewLogical, EPTLogicalDrive);
  1820. NewLogical->FreeSpaceKB = (ULONG)(-1);
  1821. NewLogical->AdjustedFreeSpaceKB = (ULONG)(-1);
  1822. Beyond1024 = SpIsRegionBeyondCylinder1024(NewLogical);
  1823. PartitionType = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE;
  1824. //
  1825. // If the argument is specified and is valid partition type
  1826. // then use that making the assumption the caller knows exactly
  1827. // what he wants
  1828. //
  1829. if (ARGUMENT_PRESENT(PartInfo) && !IsContainerPartition(PartInfo->Mbr.PartitionType)) {
  1830. PartitionType = PartInfo->Mbr.PartitionType;
  1831. }
  1832. SPPT_SET_PARTITION_TYPE(NewLogical, PartitionType);
  1833. NewLogical->Filesystem = FilesystemNewlyCreated; // to zap boot sector
  1834. SpFormatMessage(Region->TypeName,
  1835. sizeof(Region->TypeName),
  1836. SP_TEXT_FS_NAME_BASE + Region->Filesystem);
  1837. //
  1838. // commit to the disk
  1839. //
  1840. Status = SpPtnCommitChanges(DiskNumber, &Result);
  1841. if (!(NT_SUCCESS(Status) && Result)) {
  1842. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1843. "SETUP: SpPtnDelete(%u, %I64u) failed to commit changes (%lx)\n",
  1844. DiskNumber,
  1845. StartSector,
  1846. Status));
  1847. }
  1848. Result = Result && NT_SUCCESS(Status);
  1849. //
  1850. // Reinitialize irrespective of commit's status
  1851. //
  1852. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  1853. if (!NT_SUCCESS(InitStatus)) {
  1854. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1855. "SETUP: SpPtnCreateLogicalDrive(%u, %I64u) failed to reinit regions\n",
  1856. DiskNumber,
  1857. StartSector));
  1858. Result = FALSE;
  1859. }
  1860. if (Result && ARGUMENT_PRESENT(ActualDiskRegion)) {
  1861. *ActualDiskRegion = SpPtLookupRegionByStart(PartDisk,
  1862. FALSE,
  1863. LogicalStartSector);
  1864. //SpPtDumpDiskRegion(*ActualDiskRegion);
  1865. }
  1866. //
  1867. // We don't need to free the regions which we allocated above
  1868. // as the above commit and init would have done that already
  1869. //
  1870. return Result;
  1871. }
  1872. BOOLEAN
  1873. SpPtnCreate(
  1874. IN ULONG DiskNumber,
  1875. IN ULONGLONG StartSector,
  1876. IN ULONGLONG SizeInSectors, // Used ONLY in the ASR case
  1877. IN ULONGLONG SizeMB,
  1878. IN BOOLEAN InExtended,
  1879. IN BOOLEAN AlignToCylinder,
  1880. IN PPARTITION_INFORMATION_EX PartInfo,
  1881. OUT PDISK_REGION *ActualDiskRegion OPTIONAL
  1882. )
  1883. /*++
  1884. Routine Description:
  1885. Creates a primary partition of the requested size on the
  1886. given disk (either MBR/GPT).
  1887. Arguments:
  1888. DiskNumber : Disk on which the partition needs to be
  1889. created
  1890. StartSector : Start sector of the region, which represents
  1891. the free space in which the partition needs
  1892. to be created
  1893. SizeMB : The size of the partition
  1894. InExtended : Whether to create an logical drive
  1895. or not (currently NOT USED except in the ASR case)
  1896. AlignToCylinder : Indicating whether the partition should
  1897. be aligned on a cylinder boundary (Usually set
  1898. to TRUE, except in a few specific ASR cases).
  1899. PartInfo : Partition attributes to use
  1900. ActualDiskRegion : Place holder for the actual disk
  1901. region which will represent the created
  1902. partition
  1903. Return Value:
  1904. TRUE if successful, otherwise FALSE
  1905. --*/
  1906. {
  1907. BOOLEAN Result = FALSE;
  1908. PDISK_REGION Region;
  1909. ULONGLONG SectorCount, AlignedStartSector;
  1910. ULONGLONG AlignedEndSector, LeftOverSectors;
  1911. PPARTITIONED_DISK PartDisk = SPPT_GET_PARTITIONED_DISK(DiskNumber);
  1912. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  1913. PDISK_REGION PrevRegion;
  1914. PDISK_REGION NewRegion = NULL;
  1915. NTSTATUS Status;
  1916. NTSTATUS InitStatus;
  1917. BOOLEAN FirstLogical = TRUE;
  1918. //
  1919. // Verify that the optional attributes specified
  1920. // are correct
  1921. //
  1922. if (PartInfo) {
  1923. if ((SPPT_IS_MBR_DISK(DiskNumber) &&
  1924. (PartInfo->PartitionStyle != PARTITION_STYLE_MBR)) ||
  1925. (SPPT_IS_GPT_DISK(DiskNumber) &&
  1926. (PartInfo->PartitionStyle != PARTITION_STYLE_GPT))) {
  1927. return FALSE;
  1928. }
  1929. }
  1930. Region = SpPtLookupRegionByStart(PartDisk, FALSE, StartSector);
  1931. if (!Region)
  1932. return Result;
  1933. ASSERT(SPPT_IS_REGION_PARTITIONED(Region) == FALSE);
  1934. SpPtDumpDiskRegion(Region);
  1935. //
  1936. // Determine the number of sectors in the size passed in.
  1937. //
  1938. if (SpDrEnabled()) {
  1939. SectorCount = SizeInSectors;
  1940. }
  1941. else {
  1942. SectorCount = SizeMB * ((1024 * 1024) / Disk->Geometry.BytesPerSector);
  1943. }
  1944. //
  1945. // Align the start sector.
  1946. //
  1947. if (AlignToCylinder){
  1948. if (!SpDrEnabled()) {
  1949. AlignedStartSector = SpPtAlignStart(Disk, StartSector, FALSE);
  1950. }
  1951. else {
  1952. AlignedStartSector = SpPtAlignStart(Disk, StartSector, InExtended);
  1953. }
  1954. }
  1955. else {
  1956. AlignedStartSector = StartSector;
  1957. }
  1958. //
  1959. // Determine the end sector based on the size passed in.
  1960. //
  1961. AlignedEndSector = AlignedStartSector + SectorCount;
  1962. //
  1963. // Align the ending sector to a cylinder boundary. If it is not already
  1964. // aligned and is more than half way into the final cylinder, align it up,
  1965. // otherwise align it down.
  1966. //
  1967. if (AlignToCylinder) {
  1968. LeftOverSectors = AlignedEndSector % Disk->SectorsPerCylinder;
  1969. if (LeftOverSectors) {
  1970. AlignedEndSector -= LeftOverSectors;
  1971. if (LeftOverSectors > (Disk->SectorsPerCylinder / 2)) {
  1972. AlignedEndSector += Disk->SectorsPerCylinder;
  1973. }
  1974. }
  1975. }
  1976. //
  1977. // If the ending sector is past the end of the free space, shrink it
  1978. // so it fits.
  1979. //
  1980. while(AlignedEndSector > Region->StartSector + Region->SectorCount) {
  1981. AlignedEndSector -= Disk->SectorsPerCylinder;
  1982. }
  1983. //
  1984. // Find out if last sector is in the last cylinder. If it is then align it down.
  1985. // This is necessary so that we reserve a cylinder at the end of the disk, so that users
  1986. // can convert the disk to dynamic after the system is installed.
  1987. //
  1988. // (guhans) Don't align down if this is ASR. ASR already takes this into account.
  1989. //
  1990. if( !DockableMachine && !SpDrEnabled() && SPPT_IS_MBR_DISK(DiskNumber) &&
  1991. (AlignedEndSector > ((Disk->CylinderCount - 1) * Disk->SectorsPerCylinder))) {
  1992. AlignedEndSector -= Disk->SectorsPerCylinder;
  1993. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1994. "SETUP: End of partition was aligned down 1 cylinder \n"));
  1995. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1996. "SETUP: AlignedStartSector = %I64x \n", AlignedStartSector));
  1997. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1998. "SETUP: AlignedEndSector = %I64x \n", AlignedEndSector));
  1999. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2000. "SETUP: SectorsPerCylinder = %lx \n", Disk->SectorsPerCylinder));
  2001. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2002. "SETUP: CylinderCount = %lx \n", Disk->CylinderCount));
  2003. }
  2004. ASSERT(AlignedEndSector > 0);
  2005. //
  2006. // Find the previous region
  2007. //
  2008. PrevRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2009. if(PrevRegion == Region) {
  2010. PrevRegion = NULL;
  2011. } else {
  2012. while (PrevRegion) {
  2013. if(PrevRegion->Next == Region) {
  2014. break;
  2015. }
  2016. PrevRegion = PrevRegion->Next;
  2017. }
  2018. }
  2019. //
  2020. // Create a new disk region for the new free space at the
  2021. // beginning and end of the free space, if any.
  2022. //
  2023. if(AlignedStartSector - Region->StartSector) {
  2024. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2025. "SETUP:SpPtnCreate():Previous:OS:%I64d,AS:%I64d,DIFF:%I64d,S/P:%d\n",
  2026. Region->StartSector,
  2027. AlignedStartSector,
  2028. (ULONGLONG)(AlignedStartSector - Region->StartSector),
  2029. Disk->SectorsPerCylinder));
  2030. NewRegion = SpPtAllocateDiskRegionStructure(
  2031. DiskNumber,
  2032. Region->StartSector,
  2033. AlignedStartSector - Region->StartSector,
  2034. FALSE,
  2035. NULL,
  2036. 0
  2037. );
  2038. ASSERT(NewRegion);
  2039. if(PrevRegion) {
  2040. PrevRegion->Next = NewRegion;
  2041. } else {
  2042. ASSERT(Region == SPPT_GET_PRIMARY_DISK_REGION(DiskNumber));
  2043. PartDisk->PrimaryDiskRegions = NewRegion;
  2044. }
  2045. NewRegion->Next = Region;
  2046. }
  2047. if(Region->StartSector + Region->SectorCount - AlignedEndSector) {
  2048. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  2049. "SETUP:SpPtnCreate():Next:OE:%I64d,AE:%I64d,DIFF:%I64d,S/P:%d\n",
  2050. (ULONGLONG)(Region->StartSector + Region->SectorCount),
  2051. AlignedEndSector,
  2052. (ULONGLONG)(Region->StartSector + Region->SectorCount - AlignedEndSector),
  2053. Disk->SectorsPerCylinder));
  2054. NewRegion = SpPtAllocateDiskRegionStructure(
  2055. DiskNumber,
  2056. AlignedEndSector,
  2057. Region->StartSector + Region->SectorCount -
  2058. AlignedEndSector,
  2059. FALSE,
  2060. NULL,
  2061. 0
  2062. );
  2063. NewRegion->Next = Region->Next;
  2064. Region->Next = NewRegion;
  2065. }
  2066. //
  2067. // fill the current disk region.
  2068. //
  2069. Region->DiskNumber = DiskNumber;
  2070. Region->StartSector = AlignedStartSector;
  2071. Region->SectorCount = AlignedEndSector - AlignedStartSector;
  2072. SPPT_SET_REGION_PARTITIONED(Region, TRUE);
  2073. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2074. Region->VolumeLabel[0] = 0;
  2075. Region->Filesystem = FilesystemNewlyCreated;
  2076. Region->FreeSpaceKB = (ULONG)(-1);
  2077. Region->AdjustedFreeSpaceKB = (ULONG)(-1);
  2078. //
  2079. // Set the passed in partition information
  2080. //
  2081. if (PartInfo) {
  2082. SpPtnSetRegionPartitionInfo(Region, PartInfo);
  2083. }
  2084. SpFormatMessage(Region->TypeName,
  2085. sizeof(Region->TypeName),
  2086. SP_TEXT_FS_NAME_BASE + Region->Filesystem);
  2087. //
  2088. // commit to the disk
  2089. //
  2090. Status = SpPtnCommitChanges(DiskNumber, &Result);
  2091. if (!(Result && NT_SUCCESS(Status))) {
  2092. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2093. "SETUP: SpPtnCreate(%u, %I64u) failed to commit changes to"
  2094. "the drive (%lx)\n",
  2095. DiskNumber,
  2096. StartSector,
  2097. Status));
  2098. }
  2099. Result = Result && NT_SUCCESS(Status);
  2100. //
  2101. // Reinitialize irrespective of commit's status
  2102. //
  2103. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  2104. if (!NT_SUCCESS(InitStatus)){
  2105. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2106. "SETUP: SpPtnCreate(%u, %I64u) failed to reinitialize regions\n",
  2107. DiskNumber,
  2108. StartSector));
  2109. Result = FALSE;
  2110. }
  2111. if (Result && ARGUMENT_PRESENT(ActualDiskRegion)) {
  2112. *ActualDiskRegion = SpPtLookupRegionByStart(PartDisk,
  2113. FALSE,
  2114. AlignedStartSector);
  2115. }
  2116. return Result;
  2117. }
  2118. BOOLEAN
  2119. SpPtnDoCreate(
  2120. IN PDISK_REGION Region,
  2121. OUT PDISK_REGION *ActualRegion, OPTIONAL
  2122. IN BOOLEAN ForNT,
  2123. IN ULONGLONG DesiredMB OPTIONAL,
  2124. IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
  2125. IN BOOLEAN ConfirmIt
  2126. )
  2127. /*++
  2128. Routine Description:
  2129. Given the region which was selected by the user,
  2130. this routine creates the appropriate partition in
  2131. it.
  2132. This routine decides whether to create a primary or
  2133. container partition on MBR disks.
  2134. Algorithm:
  2135. if (RemoveableMedia && already partition exists) {
  2136. 1. put up a warning for the user
  2137. 2. return with error
  2138. }
  2139. if ((MBR disk) && ((there is no space for primary partition) ||
  2140. (region is in a container space)){
  2141. 1. create a logical drive using SpPtnCreateLogicalDrive()
  2142. } else {
  2143. 1. align the start sector.
  2144. 2. create the required GPT/MBR partition.
  2145. }
  2146. Arguments:
  2147. Region - The region representing the free space on disk
  2148. where the partition needs to be created.
  2149. ActualRegion - Place holder, for the region which will
  2150. represent the actual partition after
  2151. creating it.
  2152. ForNT - Indicates whether to use the given desired size
  2153. argument or not.
  2154. DesiredSize - The size of the partition to created
  2155. PartInfo - The partition attributes to use while creating
  2156. the new partition
  2157. ConfirmIt - Whether to pop up error dialogs, if something
  2158. goes wrong while creating the partition
  2159. Return Value:
  2160. TRUE if successful otherwise FALSE
  2161. --*/
  2162. {
  2163. BOOLEAN Result = FALSE;
  2164. ULONG DiskNumber = Region->DiskNumber;
  2165. ULONGLONG MinMB = 0, MaxMB = 0;
  2166. ULONGLONG SizeMB = 0;
  2167. BOOLEAN ReservedRegion = FALSE;
  2168. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  2169. if (SPPT_IS_MBR_DISK(DiskNumber)) {
  2170. ULONG PrimaryCount = 0;
  2171. ULONG ContainerCount = 0;
  2172. ULONG LogicalCount = 0;
  2173. ULONG ValidPrimaryCount = 0;
  2174. BOOLEAN InContainer = FALSE;
  2175. BOOLEAN FirstContainer = FALSE;
  2176. SpPtnGetPartitionTypeCounts(DiskNumber,
  2177. TRUE,
  2178. &PrimaryCount,
  2179. &ContainerCount,
  2180. &LogicalCount,
  2181. &ValidPrimaryCount,
  2182. NULL);
  2183. //
  2184. // Create a logical drive if we have a valid primary
  2185. // or there is no more space for another primary
  2186. // and the number of primary partitions do not exceed
  2187. // the partition table size (Partition Table not full)
  2188. //
  2189. FirstContainer =((ContainerCount == 0) &&
  2190. (ValidPrimaryCount > 0) &&
  2191. (PrimaryCount < PTABLE_DIMENSION));
  2192. InContainer = (Region->Container != NULL);
  2193. //
  2194. // We allow only one partition on the removable media (?)
  2195. //
  2196. if (SPPT_IS_REMOVABLE_DISK(DiskNumber)) {
  2197. if (PrimaryCount || ContainerCount || LogicalCount) {
  2198. ULONG ValidKeys[2] = { ASCI_CR ,0 };
  2199. //
  2200. // Disk is already partitioned
  2201. //
  2202. SpDisplayScreen(SP_SCRN_REMOVABLE_ALREADY_PARTITIONED,
  2203. 3,
  2204. HEADER_HEIGHT + 1);
  2205. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2206. SP_STAT_ENTER_EQUALS_CONTINUE,
  2207. 0);
  2208. SpWaitValidKey(ValidKeys, NULL, NULL);
  2209. return FALSE;
  2210. }
  2211. } else {
  2212. if (FirstContainer || InContainer) {
  2213. //
  2214. // create the logical drive
  2215. //
  2216. Result = SpPtnCreateLogicalDrive(DiskNumber,
  2217. Region->StartSector,
  2218. 0, // SizeInSectors: used only in the ASR case
  2219. ForNT,
  2220. TRUE, // AlignToCylinder
  2221. DesiredMB,
  2222. PartInfo,
  2223. ActualRegion);
  2224. if (!Result) {
  2225. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2226. "SETUP: SpPtnCreateLogicalDrive() failed\n"));
  2227. }
  2228. return Result;
  2229. }
  2230. //
  2231. // check to see if there is no space in the partition table
  2232. //
  2233. if (PrimaryCount >= (PTABLE_DIMENSION - 1)) {
  2234. //
  2235. // Let the user know that the partition table is full
  2236. //
  2237. if (ConfirmIt) {
  2238. while (TRUE) {
  2239. ULONG Keys[2] = {ASCI_CR, 0};
  2240. SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,
  2241. 3,
  2242. CLIENT_TOP + 1);
  2243. SpDisplayStatusOptions(
  2244. DEFAULT_STATUS_ATTRIBUTE,
  2245. SP_STAT_ENTER_EQUALS_CONTINUE,
  2246. 0
  2247. );
  2248. if (SpWaitValidKey(Keys, NULL, NULL) == ASCI_CR)
  2249. return FALSE;
  2250. }
  2251. } else {
  2252. return TRUE;
  2253. }
  2254. }
  2255. }
  2256. }
  2257. //
  2258. // need to create the primary / GPT partition
  2259. //
  2260. SpPtQueryMinMaxCreationSizeMB(DiskNumber,
  2261. Region->StartSector,
  2262. FALSE,
  2263. TRUE,
  2264. &MinMB,
  2265. &MaxMB,
  2266. &ReservedRegion
  2267. );
  2268. if (ReservedRegion) {
  2269. ULONG ValidKeys[2] = {ASCI_CR , 0};
  2270. SpStartScreen(
  2271. SP_SCRN_REGION_RESERVED,
  2272. 3,
  2273. HEADER_HEIGHT+1,
  2274. FALSE,
  2275. FALSE,
  2276. DEFAULT_ATTRIBUTE
  2277. );
  2278. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2279. SP_STAT_ENTER_EQUALS_CONTINUE,
  2280. 0);
  2281. SpWaitValidKey(ValidKeys, NULL, NULL);
  2282. return FALSE;
  2283. }
  2284. if (ForNT) {
  2285. //
  2286. // If a size was requested then try to use that, otherwise use
  2287. // the maximum.
  2288. //
  2289. if (DesiredMB) {
  2290. if (DesiredMB <= MaxMB) {
  2291. SizeMB = DesiredMB;
  2292. } else {
  2293. return FALSE; // don't have the space user requested
  2294. }
  2295. } else {
  2296. SizeMB = MaxMB;
  2297. }
  2298. } else {
  2299. if (!SpPtnGetSizeFromUser(Disk, MinMB, MaxMB, &SizeMB))
  2300. return FALSE; // user didn't want to proceed
  2301. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2302. SP_STAT_PLEASE_WAIT,
  2303. 0);
  2304. }
  2305. //SpPtDumpDiskRegionInformation(DiskNumber, FALSE);
  2306. //
  2307. // Create the partition.
  2308. //
  2309. Result = SpPtnCreate(
  2310. Region->DiskNumber,
  2311. Region->StartSector,
  2312. 0, // SizeInSectors: used only in the ASR case
  2313. SizeMB,
  2314. FALSE,
  2315. TRUE, // AlignToCylinder
  2316. PartInfo,
  2317. ActualRegion
  2318. );
  2319. //SpPtDumpDiskRegionInformation(DiskNumber, FALSE);
  2320. if (!Result) {
  2321. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2322. "SETUP: SpPtnCreate() failed \n"));
  2323. }
  2324. return Result;
  2325. }
  2326. BOOLEAN
  2327. SpPtnDoDelete(
  2328. IN PDISK_REGION pRegion,
  2329. IN PWSTR RegionDescription,
  2330. IN BOOLEAN ConfirmIt
  2331. )
  2332. /*++
  2333. Routine Description:
  2334. Given the region which was selected by the user,
  2335. this routine prompts the user then calls the
  2336. actual deletion routine
  2337. Argument:
  2338. pRegion - Region selected by the user which
  2339. needs to be deleted
  2340. RegionDescription - Description of the
  2341. region
  2342. ConfirmIt - Whether the deletion needs to be
  2343. confirmed
  2344. Return Value:
  2345. TRUE if deletion was carried out and was successful.
  2346. FALSE if deletion was cancelled or could not be carried
  2347. out because of some other error.
  2348. ++*/
  2349. {
  2350. ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; // do not change order
  2351. ULONG Mnemonics[2] = { MnemonicDeletePartition2, 0 };
  2352. PHARD_DISK Disk;
  2353. ULONG Key;
  2354. BOOLEAN Result = FALSE;
  2355. //
  2356. // Prompt for MSR deletion
  2357. //
  2358. if (SPPT_IS_GPT_DISK(pRegion->DiskNumber) &&
  2359. SPPT_IS_REGION_MSFT_RESERVED(pRegion) && ConfirmIt) {
  2360. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_MSRPART, 3, HEADER_HEIGHT+1);
  2361. SpDisplayStatusOptions(
  2362. DEFAULT_STATUS_ATTRIBUTE,
  2363. SP_STAT_ENTER_EQUALS_CONTINUE,
  2364. SP_STAT_ESC_EQUALS_CANCEL,
  2365. 0
  2366. );
  2367. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  2368. return Result;
  2369. }
  2370. }
  2371. //
  2372. // Special warning if this is a system partition.
  2373. //
  2374. // Do not check system partition on NEC98.
  2375. //
  2376. if (!IsNEC_98) { //NEC98
  2377. if(ConfirmIt && pRegion->IsSystemPartition) {
  2378. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_SYSPART,3,HEADER_HEIGHT+1);
  2379. SpDisplayStatusOptions(
  2380. DEFAULT_STATUS_ATTRIBUTE,
  2381. SP_STAT_ENTER_EQUALS_CONTINUE,
  2382. SP_STAT_ESC_EQUALS_CANCEL,
  2383. 0
  2384. );
  2385. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  2386. return Result;
  2387. }
  2388. }
  2389. } //NEC98
  2390. if(ConfirmIt && (pRegion->DynamicVolume || SPPT_IS_REGION_LDM_METADATA(pRegion))) {
  2391. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_DYNVOL,3,HEADER_HEIGHT+1);
  2392. SpDisplayStatusOptions(
  2393. DEFAULT_STATUS_ATTRIBUTE,
  2394. SP_STAT_ENTER_EQUALS_CONTINUE,
  2395. SP_STAT_ESC_EQUALS_CANCEL,
  2396. 0
  2397. );
  2398. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  2399. return Result;
  2400. }
  2401. }
  2402. //
  2403. // CR is no longer a valid key.
  2404. //
  2405. ValidKeys[1] = 0;
  2406. //
  2407. // Display the staus text.
  2408. //
  2409. if (ConfirmIt) {
  2410. Disk = SPPT_GET_HARDDISK(pRegion->DiskNumber);
  2411. SpStartScreen(
  2412. SP_SCRN_CONFIRM_REMOVE_PARTITION,
  2413. 3,
  2414. CLIENT_TOP+1,
  2415. FALSE,
  2416. FALSE,
  2417. DEFAULT_ATTRIBUTE,
  2418. RegionDescription,
  2419. Disk->Description
  2420. );
  2421. SpDisplayStatusOptions(
  2422. DEFAULT_STATUS_ATTRIBUTE,
  2423. SP_STAT_L_EQUALS_DELETE,
  2424. SP_STAT_ESC_EQUALS_CANCEL,
  2425. 0
  2426. );
  2427. Key = SpWaitValidKey(ValidKeys,NULL,Mnemonics);
  2428. if(Key == ASCI_ESC) {
  2429. return Result;
  2430. }
  2431. SpDisplayStatusOptions(
  2432. DEFAULT_STATUS_ATTRIBUTE,
  2433. SP_STAT_PLEASE_WAIT,
  2434. 0);
  2435. }
  2436. //
  2437. // Delete the bootset, if any, for the region
  2438. //
  2439. SpPtDeleteBootSetsForRegion(pRegion);
  2440. //
  2441. // Now go ahead and delete it.
  2442. //
  2443. Result = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
  2444. if (!Result) {
  2445. if (ConfirmIt) {
  2446. SpDisplayScreen(SP_SCRN_PARTITION_DELETE_FAILED,3,HEADER_HEIGHT+1);
  2447. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
  2448. SpInputDrain();
  2449. while(SpInputGetKeypress() != ASCI_CR) ;
  2450. }
  2451. return Result;
  2452. }
  2453. //
  2454. // Delete the drive letters if the necessary. This is to ensure that
  2455. // the drive letters assigned to CD-ROM drives will go away,
  2456. // when the the disks have no partitioned space.
  2457. //
  2458. SpPtDeleteDriveLetters();
  2459. return Result;
  2460. }
  2461. VOID
  2462. SpPtnMakeRegionActive(
  2463. IN PDISK_REGION Region
  2464. )
  2465. /*++
  2466. Routine Description:
  2467. Makes the given region active (i.e. converts into system partition).
  2468. Is valid only for MBR disks. Makes all the other regions
  2469. inactive on the disk
  2470. Arguments:
  2471. Region - The region (primary partition) which needs to made
  2472. active.
  2473. Return Value:
  2474. None.
  2475. --*/
  2476. {
  2477. static BOOLEAN WarnedOtherOS = FALSE;
  2478. if (Region && SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  2479. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(Region->DiskNumber);
  2480. while (CurrRegion) {
  2481. if ((Region != CurrRegion) &&
  2482. SPPT_IS_REGION_ACTIVE_PARTITION(CurrRegion)) {
  2483. //
  2484. // Give the warning for the first time
  2485. //
  2486. if (!WarnedOtherOS && !UnattendedOperation) {
  2487. SpDisplayScreen((SPPT_GET_PARTITION_TYPE(CurrRegion) == 10) ?
  2488. SP_SCRN_BOOT_MANAGER : SP_SCRN_OTHER_OS_ACTIVE,
  2489. 3,
  2490. HEADER_HEIGHT + 1);
  2491. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,
  2492. DEFAULT_STATUS_ATTRIBUTE);
  2493. SpInputDrain();
  2494. while (SpInputGetKeypress() != ASCI_CR) ;
  2495. WarnedOtherOS = TRUE;
  2496. }
  2497. SPPT_MARK_REGION_AS_ACTIVE(CurrRegion, FALSE);
  2498. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2499. }
  2500. CurrRegion = CurrRegion->Next;
  2501. }
  2502. SPPT_MARK_REGION_AS_ACTIVE(Region, TRUE);
  2503. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2504. }
  2505. }
  2506. BOOLEAN
  2507. SpPtMakeDiskRaw(
  2508. IN ULONG DiskNumber
  2509. )
  2510. /*++
  2511. Routine Description:
  2512. Converts the given disk to RAW i.e. Zaps couple of first
  2513. sectors which have information about the disk format
  2514. Arguments:
  2515. DiskNumber : Disk Index, to converted into RAW
  2516. Return Value:
  2517. TRUE, if successful, otherwise FALSE
  2518. --*/
  2519. {
  2520. BOOLEAN Result = FALSE;
  2521. if (DiskNumber < HardDiskCount) {
  2522. HANDLE DiskHandle;
  2523. NTSTATUS Status;
  2524. WCHAR DiskName[256];
  2525. swprintf(DiskName, L"\\Device\\Harddisk%u", DiskNumber);
  2526. //
  2527. // Open partition 0 on this disk..
  2528. //
  2529. Status = SpOpenPartition0(DiskName, &DiskHandle, TRUE);
  2530. if(NT_SUCCESS(Status)){
  2531. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  2532. ULONG BytesPerSector = Disk->Geometry.BytesPerSector;
  2533. ULONG BufferSize = (BytesPerSector * 2);
  2534. PVOID UBuffer = SpMemAlloc(BufferSize);
  2535. if (UBuffer) {
  2536. PVOID Buffer = UBuffer;
  2537. RtlZeroMemory(UBuffer, BufferSize);
  2538. Buffer = ALIGN(Buffer, BytesPerSector);
  2539. //
  2540. // Wipe out 0'th sector
  2541. //
  2542. Status = SpReadWriteDiskSectors(DiskHandle,
  2543. 0,
  2544. 1,
  2545. BytesPerSector,
  2546. Buffer,
  2547. TRUE);
  2548. if (NT_SUCCESS(Status)) {
  2549. //
  2550. // Wipe out 1st sector
  2551. //
  2552. Status = SpReadWriteDiskSectors(DiskHandle,
  2553. 1,
  2554. 1,
  2555. BytesPerSector,
  2556. Buffer,
  2557. TRUE);
  2558. if (NT_SUCCESS(Status)) {
  2559. //
  2560. // Wipe out 2nd sector
  2561. //
  2562. Status = SpReadWriteDiskSectors(DiskHandle,
  2563. 2,
  2564. 1,
  2565. BytesPerSector,
  2566. Buffer,
  2567. TRUE);
  2568. }
  2569. }
  2570. } else {
  2571. Status = STATUS_NO_MEMORY;
  2572. }
  2573. ZwClose(DiskHandle);
  2574. }
  2575. Result = NT_SUCCESS(Status);
  2576. }
  2577. if (Result) {
  2578. SpPtnFreeDiskRegions(DiskNumber);
  2579. }
  2580. return Result;
  2581. }
  2582. VOID
  2583. SpPtnDeletePartitionsForRemoteBoot(
  2584. PPARTITIONED_DISK PartDisk,
  2585. PDISK_REGION StartRegion,
  2586. PDISK_REGION EndRegion,
  2587. BOOLEAN Extended
  2588. )
  2589. /*++
  2590. Routine Description:
  2591. Deletes the specified start region and end region partitions
  2592. and all the partitions in between them.
  2593. Arguments:
  2594. PartDisk : The partitioned disk
  2595. StartRegion : The starting region for deletion
  2596. EndRegion : The Ending region for deletion
  2597. Extended : Not used (for backward compatability)
  2598. Return Value:
  2599. None
  2600. --*/
  2601. {
  2602. PDISK_REGION CurrRegion = StartRegion;
  2603. BOOLEAN FirstContainerDeleted = FALSE;
  2604. ULONG DiskNumber = StartRegion ?
  2605. StartRegion->DiskNumber : EndRegion->DiskNumber;
  2606. BOOLEAN Changes = FALSE;
  2607. NTSTATUS Status;
  2608. NTSTATUS InitStatus;
  2609. //
  2610. // Mark all the regions which need to be deleted
  2611. //
  2612. while (CurrRegion && (CurrRegion != EndRegion)) {
  2613. if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
  2614. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  2615. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2616. if (SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(CurrRegion))
  2617. FirstContainerDeleted = TRUE;
  2618. //
  2619. // Remove any boot sets pointing to this region.
  2620. //
  2621. SpPtDeleteBootSetsForRegion(CurrRegion);
  2622. //
  2623. // Get rid of the compressed drives, if any
  2624. //
  2625. if( CurrRegion->NextCompressed != NULL ) {
  2626. SpDisposeCompressedDrives( CurrRegion->NextCompressed );
  2627. CurrRegion->NextCompressed = NULL;
  2628. CurrRegion->MountDrive = 0;
  2629. CurrRegion->HostDrive = 0;
  2630. }
  2631. }
  2632. CurrRegion = CurrRegion->Next;
  2633. }
  2634. if (EndRegion && CurrRegion && (CurrRegion == EndRegion)){
  2635. if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
  2636. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  2637. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2638. if (SPPT_IS_REGION_FIRST_CONTAINER_PARTITION(CurrRegion))
  2639. FirstContainerDeleted = TRUE;
  2640. //
  2641. // Remove any boot sets pointing to this region.
  2642. //
  2643. SpPtDeleteBootSetsForRegion(CurrRegion);
  2644. //
  2645. // Get rid of the compressed drives, if any
  2646. //
  2647. if( CurrRegion->NextCompressed != NULL ) {
  2648. SpDisposeCompressedDrives( CurrRegion->NextCompressed );
  2649. CurrRegion->NextCompressed = NULL;
  2650. CurrRegion->MountDrive = 0;
  2651. CurrRegion->HostDrive = 0;
  2652. }
  2653. }
  2654. }
  2655. //
  2656. // If the first container partition was deleted then delete
  2657. // all the container and logical partitions,
  2658. //
  2659. if (FirstContainerDeleted) {
  2660. CurrRegion = PartDisk->PrimaryDiskRegions;
  2661. while (CurrRegion) {
  2662. if (SPPT_IS_REGION_CONTAINER_PARTITION(CurrRegion) ||
  2663. SPPT_IS_REGION_LOGICAL_DRIVE(CurrRegion)) {
  2664. SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
  2665. SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
  2666. //
  2667. // Remove any boot sets pointing to this region.
  2668. //
  2669. SpPtDeleteBootSetsForRegion(CurrRegion);
  2670. //
  2671. // Get rid of the compressed drives, if any
  2672. //
  2673. if( CurrRegion->NextCompressed != NULL ) {
  2674. SpDisposeCompressedDrives( CurrRegion->NextCompressed );
  2675. CurrRegion->NextCompressed = NULL;
  2676. CurrRegion->MountDrive = 0;
  2677. CurrRegion->HostDrive = 0;
  2678. }
  2679. }
  2680. CurrRegion = CurrRegion->Next;
  2681. }
  2682. }
  2683. //
  2684. // Commit the changes
  2685. //
  2686. Status = SpPtnCommitChanges(DiskNumber, &Changes);
  2687. //
  2688. // Initialize region structure for the disk again
  2689. //
  2690. InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
  2691. if (!NT_SUCCESS(Status) || !Changes || !NT_SUCCESS(InitStatus)) {
  2692. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2693. "SETUP:SpPtnDeletePartitionsForRemoteBoot(%p, %p, %p, %d) failed "
  2694. "with %lx status\n",
  2695. PartDisk,
  2696. StartRegion,
  2697. EndRegion,
  2698. Extended,
  2699. Status));
  2700. }
  2701. }
  2702. NTSTATUS
  2703. SpPtnMakeRegionArcSysPart(
  2704. IN PDISK_REGION Region
  2705. )
  2706. /*++
  2707. Routine Description:
  2708. Makes the given region a system partition on ARC machines
  2709. Arguments:
  2710. Region - The region which needs to be convered to system
  2711. partition
  2712. Return Value:
  2713. STATUS_SUCCESS if successful, otherwise appropriate error
  2714. code.
  2715. --*/
  2716. {
  2717. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2718. if (Region && SpIsArc() && !ValidArcSystemPartition) {
  2719. if (SPPT_IS_MBR_DISK(Region->DiskNumber)) {
  2720. if (SPPT_IS_REGION_PRIMARY_PARTITION(Region)) {
  2721. SpPtnMakeRegionActive(Region);
  2722. SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
  2723. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2724. Status = STATUS_SUCCESS;
  2725. }
  2726. } else {
  2727. WCHAR RegionName[MAX_PATH];
  2728. SPPT_MARK_REGION_AS_SYSTEMPARTITION(Region, TRUE);
  2729. SPPT_SET_REGION_DIRTY(Region, TRUE);
  2730. //
  2731. // Remove the drive letter also
  2732. //
  2733. swprintf(RegionName,
  2734. L"\\Device\\Harddisk%u\\Partition%u",
  2735. Region->DiskNumber,
  2736. Region->PartitionNumber);
  2737. SpDeleteDriveLetter(RegionName);
  2738. Region->DriveLetter = 0;
  2739. Status = STATUS_SUCCESS;
  2740. }
  2741. }
  2742. return Status;
  2743. }
  2744. ULONG
  2745. SpPtnCountPartitionsByFSType(
  2746. IN ULONG DiskId,
  2747. IN FilesystemType FsType
  2748. )
  2749. /*++
  2750. Routine Description:
  2751. Counts the partition based on the file system type.
  2752. Note : The partitions which are marked
  2753. deleted are skipped.
  2754. Arguments:
  2755. DiskId : The disk on which the partitions need to be
  2756. counted
  2757. FsType : File system type which needs to present on
  2758. the partitions
  2759. Return Value:
  2760. Number of partitions containing the requested file system
  2761. --*/
  2762. {
  2763. ULONG Count = 0;
  2764. if ((FsType < FilesystemMax) && (DiskId < HardDiskCount)) {
  2765. PDISK_REGION Region = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  2766. while (Region) {
  2767. if (SPPT_IS_REGION_PARTITIONED(Region) &&
  2768. !SPPT_IS_REGION_MARKED_DELETE(Region) &&
  2769. (Region->Filesystem == FsType)) {
  2770. Count++;
  2771. }
  2772. Region = Region->Next;
  2773. }
  2774. }
  2775. return Count;
  2776. }
  2777. PDISK_REGION
  2778. SpPtnLocateESP(
  2779. VOID
  2780. )
  2781. {
  2782. PDISK_REGION EspRegion = NULL;
  2783. ULONG Index;
  2784. for (Index=0; (Index < HardDiskCount) && (!EspRegion); Index++) {
  2785. if (SPPT_IS_GPT_DISK(Index)) {
  2786. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(Index);
  2787. while (CurrRegion) {
  2788. if (SPPT_IS_REGION_PARTITIONED(CurrRegion) &&
  2789. SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
  2790. EspRegion = CurrRegion;
  2791. break; // found the first ESP
  2792. }
  2793. CurrRegion = CurrRegion->Next;
  2794. }
  2795. }
  2796. }
  2797. return EspRegion;
  2798. }
  2799. NTSTATUS
  2800. SpPtnCreateESPForDisk(
  2801. IN ULONG DiskId
  2802. )
  2803. {
  2804. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2805. PDISK_REGION EspCandidateRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  2806. if (EspCandidateRegion && SpPtnIsValidESPRegion(EspCandidateRegion)) {
  2807. ULONG DiskId = EspCandidateRegion->DiskNumber;
  2808. ULONGLONG SizeMB = SpPtnGetDiskESPSizeMB(DiskId);
  2809. PARTITION_INFORMATION_EX PartInfo;
  2810. PDISK_REGION EspRegion = NULL;
  2811. BOOLEAN CreateResult;
  2812. RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
  2813. PartInfo.PartitionStyle = PARTITION_STYLE_GPT;
  2814. PartInfo.Gpt.Attributes = 1; // required ???
  2815. PartInfo.Gpt.PartitionType = PARTITION_SYSTEM_GUID;
  2816. SpCreateNewGuid(&(PartInfo.Gpt.PartitionId));
  2817. CreateResult = SpPtnCreate(DiskId,
  2818. EspCandidateRegion->StartSector,
  2819. 0, // SizeInSectors: used only in the ASR case
  2820. SizeMB,
  2821. FALSE,
  2822. TRUE,
  2823. &PartInfo,
  2824. &EspRegion);
  2825. if (CreateResult) {
  2826. //
  2827. // format this region
  2828. //
  2829. WCHAR RegionDescr[128];
  2830. //
  2831. // Mark this region as ESP
  2832. //
  2833. SPPT_MARK_REGION_AS_SYSTEMPARTITION(EspRegion, TRUE);
  2834. SPPT_SET_REGION_DIRTY(EspRegion, TRUE);
  2835. ValidArcSystemPartition = TRUE;
  2836. SpPtRegionDescription(
  2837. SPPT_GET_PARTITIONED_DISK(EspRegion->DiskNumber),
  2838. EspRegion,
  2839. RegionDescr,
  2840. sizeof(RegionDescr));
  2841. if (!SetupSourceDevicePath || !DirectoryOnSetupSource) {
  2842. SpGetWinntParams(&SetupSourceDevicePath, &DirectoryOnSetupSource);
  2843. }
  2844. Status = SpDoFormat(RegionDescr,
  2845. EspRegion,
  2846. FilesystemFat,
  2847. TRUE,
  2848. TRUE,
  2849. FALSE,
  2850. SifHandle,
  2851. 0, // default cluster size
  2852. SetupSourceDevicePath,
  2853. DirectoryOnSetupSource);
  2854. if (!NT_SUCCESS(Status)) {
  2855. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2856. "SETUP:SpPtnCreateESP() failed to"
  2857. " format ESP partition for %p region (%lx)\n",
  2858. EspRegion,
  2859. Status));
  2860. } else {
  2861. BOOLEAN AnyChanges = FALSE;
  2862. Status = SpPtnCommitChanges(EspRegion->DiskNumber,
  2863. &AnyChanges);
  2864. if (!NT_SUCCESS(Status)) {
  2865. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2866. "SETUP:SpPtnCreateESP() failed to"
  2867. " commit changes to disk (%lx)\n",
  2868. Status));
  2869. }
  2870. Status = SpPtnInitializeDiskDrive(EspRegion->DiskNumber);
  2871. if (!NT_SUCCESS(Status)) {
  2872. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2873. "SETUP:SpPtnCreateESP() failed to"
  2874. " reinitialize disk regions (%lx)\n",
  2875. Status));
  2876. }
  2877. }
  2878. } else {
  2879. Status = STATUS_UNSUCCESSFUL;
  2880. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2881. "SETUP:SpPtnCreateESP() failed to"
  2882. " create ESP partition for %p region (%lx)\n",
  2883. EspRegion,
  2884. Status));
  2885. }
  2886. }
  2887. return Status;
  2888. }
  2889. NTSTATUS
  2890. SpPtnCreateESP(
  2891. IN BOOLEAN PromptUser
  2892. )
  2893. {
  2894. NTSTATUS Status = STATUS_CANCELLED;
  2895. BOOLEAN Confirmed = FALSE;
  2896. if (ValidArcSystemPartition) {
  2897. Status = STATUS_SUCCESS;
  2898. return Status;
  2899. }
  2900. if (UnattendedOperation) {
  2901. Confirmed = TRUE;
  2902. } else {
  2903. if (PromptUser) {
  2904. //
  2905. // Prompt the user for confirmation
  2906. //
  2907. ULONG ValidKeys[] = { ASCI_CR, ASCI_ESC, 0 };
  2908. ULONG UserOption = ASCI_CR;
  2909. SpDisplayScreen(SP_AUTOCREATE_ESP, 3, HEADER_HEIGHT+1);
  2910. SpDisplayStatusOptions(
  2911. DEFAULT_STATUS_ATTRIBUTE,
  2912. SP_STAT_ENTER_EQUALS_CONTINUE,
  2913. SP_STAT_ESC_EQUALS_CANCEL,
  2914. 0);
  2915. //
  2916. // Wait for user input
  2917. //
  2918. SpInputDrain();
  2919. UserOption = SpWaitValidKey(ValidKeys, NULL, NULL);
  2920. if (UserOption == ASCI_CR) {
  2921. Confirmed = TRUE;
  2922. }
  2923. } else {
  2924. Confirmed = TRUE;
  2925. }
  2926. }
  2927. if (Confirmed) {
  2928. WCHAR ArcDiskName[MAX_PATH];
  2929. ULONG DiskNumber;
  2930. ULONG ArcDiskNumber;
  2931. PDISK_REGION EspCandidateRegion = NULL;
  2932. //
  2933. // Find the first harddisk (non-removable) media that the
  2934. // BIOS enumerated to be used for system partition
  2935. //
  2936. for (DiskNumber = 0, Status = STATUS_UNSUCCESSFUL;
  2937. (!NT_SUCCESS(Status) && (DiskNumber < HardDiskCount));
  2938. DiskNumber++) {
  2939. swprintf(ArcDiskName, L"multi(0)disk(0)rdisk(%d)", DiskNumber);
  2940. ArcDiskNumber = SpArcDevicePathToDiskNumber(ArcDiskName);
  2941. //
  2942. // Make sure its not removable disk and its reachable by firmware
  2943. //
  2944. if ((ArcDiskNumber == (ULONG)-1) || SPPT_IS_REMOVABLE_DISK(ArcDiskNumber)) {
  2945. continue; // get to the next disk
  2946. }
  2947. Status = SpPtnCreateESPForDisk(ArcDiskNumber);
  2948. }
  2949. if (PromptUser && !NT_SUCCESS(Status)) {
  2950. ULONG ValidKeys[] = { ASCI_CR, 0 };
  2951. ValidArcSystemPartition = FALSE;
  2952. SpDisplayScreen(SP_AUTOCREATE_ESP_FAILED, 3, HEADER_HEIGHT+1);
  2953. SpDisplayStatusOptions(
  2954. DEFAULT_STATUS_ATTRIBUTE,
  2955. SP_STAT_ENTER_EQUALS_CONTINUE,
  2956. 0);
  2957. //
  2958. // Wait for user input
  2959. //
  2960. SpInputDrain();
  2961. SpWaitValidKey(ValidKeys, NULL, NULL);
  2962. }
  2963. } else {
  2964. Status = STATUS_CANCELLED;
  2965. }
  2966. return Status;
  2967. }
  2968. NTSTATUS
  2969. SpPtnInitializeGPTDisk(
  2970. IN ULONG DiskNumber
  2971. )
  2972. {
  2973. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  2974. if ((DiskNumber < HardDiskCount) && (SPPT_IS_GPT_DISK(DiskNumber))) {
  2975. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2976. PDISK_REGION EspRegion = NULL;
  2977. PDISK_REGION MsrRegion = NULL;
  2978. while (CurrRegion && ((NULL == EspRegion) || (NULL == MsrRegion))) {
  2979. if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
  2980. EspRegion = CurrRegion;
  2981. } else if (SPPT_IS_REGION_MSFT_RESERVED(CurrRegion)) {
  2982. MsrRegion = CurrRegion;
  2983. }
  2984. CurrRegion = CurrRegion->Next;
  2985. }
  2986. if (!MsrRegion) {
  2987. PDISK_REGION MsrCandidate = NULL;
  2988. if (EspRegion) {
  2989. MsrCandidate = EspRegion->Next;
  2990. } else {
  2991. MsrCandidate = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  2992. }
  2993. if (MsrCandidate && SpPtnIsValidMSRRegion(MsrCandidate)) {
  2994. PARTITION_INFORMATION_EX PartInfo;
  2995. PDISK_REGION MsrRegion = NULL;
  2996. ULONGLONG SizeMB = SpPtnGetDiskMSRSizeMB(DiskNumber);
  2997. BOOLEAN CreateResult;
  2998. RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
  2999. PartInfo.PartitionStyle = PARTITION_STYLE_GPT;
  3000. PartInfo.Gpt.Attributes = 0; // required ???
  3001. PartInfo.Gpt.PartitionType = PARTITION_MSFT_RESERVED_GUID;
  3002. SpCreateNewGuid(&(PartInfo.Gpt.PartitionId));
  3003. CreateResult = SpPtnCreate(DiskNumber,
  3004. MsrCandidate->StartSector,
  3005. 0, // SizeInSectors: used only in the ASR case
  3006. SizeMB,
  3007. FALSE,
  3008. TRUE,
  3009. &PartInfo,
  3010. &MsrRegion);
  3011. Status = CreateResult ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  3012. if (!NT_SUCCESS(Status)) {
  3013. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  3014. "SETUP:SpPtnInitializeGPTDisk() failed with "
  3015. " (%lx)\n",
  3016. Status));
  3017. }
  3018. } else {
  3019. Status = STATUS_SUCCESS;
  3020. }
  3021. } else {
  3022. Status = STATUS_SUCCESS;
  3023. }
  3024. }
  3025. return Status;
  3026. }
  3027. BOOLEAN
  3028. SpIsMSRPresentOnDisk(
  3029. IN ULONG DiskNumber
  3030. )
  3031. /*++
  3032. Routine Description:
  3033. Determines if the Disk containing the ESP has a MSR.
  3034. Arguments:
  3035. DiskNumber - Disk Number of the Disk containing the ESP.
  3036. Return Value:
  3037. TRUE/FALSE depending on presence/absence of MSR.
  3038. --*/
  3039. {
  3040. BOOLEAN MsrPresent = FALSE;
  3041. if ((DiskNumber < HardDiskCount) && (SPPT_IS_GPT_DISK(DiskNumber))) {
  3042. PDISK_REGION CurrRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
  3043. while (CurrRegion) {
  3044. if (SPPT_IS_REGION_MSFT_RESERVED(CurrRegion)) {
  3045. MsrPresent = TRUE;
  3046. break;
  3047. }
  3048. CurrRegion = CurrRegion->Next;
  3049. }
  3050. }
  3051. return(MsrPresent);
  3052. }
  3053. ULONG
  3054. SpGetSystemDiskNumber(
  3055. VOID
  3056. )
  3057. /*++
  3058. Routine Description:
  3059. Finds the NT Disk number of the disk that was detected first and
  3060. is selected to contain the ESP.
  3061. Arguments:
  3062. None.
  3063. Return Value:
  3064. ULONG - NT Disk number of the disk containing the ESP.
  3065. --*/
  3066. {
  3067. WCHAR ArcDiskName[MAX_PATH];
  3068. ULONG NtDiskNumber;
  3069. NTSTATUS Status;
  3070. ULONG DiskNumber;
  3071. //
  3072. // Find the first harddisk (non-removable) media that the
  3073. // BIOS enumerated to be used for system partition
  3074. //
  3075. for (DiskNumber = 0; DiskNumber < HardDiskCount; DiskNumber++) {
  3076. swprintf(ArcDiskName, L"multi(0)disk(0)rdisk(%d)", DiskNumber);
  3077. NtDiskNumber = SpArcDevicePathToDiskNumber(ArcDiskName);
  3078. //
  3079. // Make sure its not removable disk and its reachable by firmware
  3080. //
  3081. if (((ULONG)-1 != NtDiskNumber) &&
  3082. (!SPPT_IS_REMOVABLE_DISK(NtDiskNumber))) {
  3083. break;
  3084. }
  3085. }
  3086. ASSERT((NtDiskNumber < HardDiskCount) &&
  3087. (-1 != NtDiskNumber));
  3088. return(NtDiskNumber);
  3089. }
  3090. NTSTATUS
  3091. SpPtnInitializeGPTDisks(
  3092. VOID
  3093. )
  3094. {
  3095. NTSTATUS LastError = STATUS_SUCCESS;
  3096. NTSTATUS Status = STATUS_SUCCESS;
  3097. ULONG DiskNumber;
  3098. ULONG SystemDiskNumber = SpGetSystemDiskNumber();
  3099. for (DiskNumber = 0; (DiskNumber < HardDiskCount); DiskNumber++) {
  3100. //
  3101. // Create an MSR on the System Partition Disk only if a ESP exists.
  3102. // If an ESP does not exist on the disk that the BIOS enumerated to be
  3103. // used for creating ESP, then do not create an MSR on that disk.
  3104. //
  3105. if (SPPT_IS_GPT_DISK(DiskNumber) &&
  3106. ((DiskNumber != SystemDiskNumber) || ValidArcSystemPartition)) {
  3107. Status = SpPtnInitializeGPTDisk(DiskNumber);
  3108. if (!NT_SUCCESS(Status)) {
  3109. LastError = Status;
  3110. }
  3111. }
  3112. }
  3113. return LastError;
  3114. }
  3115. NTSTATUS
  3116. SpPtnRepartitionGPTDisk(
  3117. IN ULONG DiskId,
  3118. IN ULONG MinimumFreeSpaceKB,
  3119. OUT PDISK_REGION *RegionToInstall
  3120. )
  3121. /*++
  3122. Routine Description:
  3123. Repartitions a given disk for unattended and remote
  3124. boot install case
  3125. Arguments:
  3126. DiskId : The disk which needs to be repartitioned
  3127. MinimumFreeSpace : Minimum space required in KB
  3128. RegionToInstall : Place holder for the region which
  3129. will be selected for installation.
  3130. Return Value:
  3131. Appropriate status code.
  3132. --*/
  3133. {
  3134. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3135. if ((DiskId < HardDiskCount) && !SPPT_IS_REMOVABLE_DISK(DiskId)) {
  3136. PDISK_REGION CurrentRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  3137. BOOLEAN Changes = FALSE;
  3138. //
  3139. // Mark all the existing partitioned space on the disk
  3140. // for deletion
  3141. //
  3142. while (CurrentRegion) {
  3143. if (SPPT_IS_REGION_PARTITIONED(CurrentRegion)) {
  3144. SPPT_SET_REGION_DELETED(CurrentRegion, TRUE);
  3145. SPPT_SET_REGION_DIRTY(CurrentRegion, TRUE);
  3146. Changes = TRUE;
  3147. }
  3148. CurrentRegion = CurrentRegion->Next;
  3149. }
  3150. //
  3151. // Delete all the partitioned space on the disk
  3152. //
  3153. if (Changes) {
  3154. Status = SpPtnCommitChanges(DiskId, &Changes);
  3155. } else {
  3156. Status = STATUS_SUCCESS;
  3157. }
  3158. if (!NT_SUCCESS(Status)) {
  3159. return Status;
  3160. }
  3161. //
  3162. // Update the in memory region structure for the disk
  3163. //
  3164. Status = SpPtnInitializeDiskDrive(DiskId);
  3165. if (!NT_SUCCESS(Status)) {
  3166. return Status;
  3167. }
  3168. //
  3169. // Reinitialize the disk style to GPT to be sure its
  3170. // GPT disk
  3171. //
  3172. SPPT_SET_DISK_BLANK(DiskId, TRUE);
  3173. Status = SpPtnInitializeDiskStyle(DiskId,
  3174. PARTITION_STYLE_GPT,
  3175. NULL);
  3176. if (!NT_SUCCESS(Status)) {
  3177. return Status;
  3178. }
  3179. //
  3180. // Update the in memory region structure for the disk
  3181. //
  3182. Status = SpPtnInitializeDiskDrive(DiskId);
  3183. if (!NT_SUCCESS(Status)) {
  3184. return Status;
  3185. }
  3186. //
  3187. // First create the ESP on the disk
  3188. //
  3189. Status = SpPtnCreateESPForDisk(DiskId);
  3190. if (!NT_SUCCESS(Status)) {
  3191. return Status;
  3192. }
  3193. //
  3194. // Create the MSR partition
  3195. //
  3196. Status = SpPtnInitializeGPTDisk(DiskId);
  3197. if (!NT_SUCCESS(Status)) {
  3198. return Status;
  3199. }
  3200. //
  3201. // Find the first free space region with adequate space
  3202. //
  3203. CurrentRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskId);
  3204. while (CurrentRegion) {
  3205. if (SPPT_IS_REGION_FREESPACE(CurrentRegion) &&
  3206. (SPPT_REGION_FREESPACE_KB(CurrentRegion) >= MinimumFreeSpaceKB)) {
  3207. break;
  3208. }
  3209. CurrentRegion = CurrentRegion->Next;
  3210. }
  3211. if (CurrentRegion) {
  3212. *RegionToInstall = CurrentRegion;
  3213. } else {
  3214. Status = STATUS_UNSUCCESSFUL;
  3215. }
  3216. }
  3217. return Status;
  3218. }