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.

7775 lines
246 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. sppartit.c
  5. Abstract:
  6. Partitioning module in text setup.
  7. Author:
  8. Ted Miller (tedm) 7-September-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. #include <bootmbr.h>
  14. //
  15. // For NEC98 boot memu code.
  16. //
  17. #include <x86mboot.h> //NEC98
  18. extern BOOLEAN DriveAssignFromA; //NEC98
  19. extern BOOLEAN ConsoleRunning;
  20. extern BOOLEAN ForceConsole;
  21. extern BOOLEAN ValidArcSystemPartition;
  22. extern PSETUP_COMMUNICATION CommunicationParams;
  23. PPARTITIONED_DISK PartitionedDisks;
  24. //
  25. // Disk region containing the local source directory
  26. // in the winnt.exe setup case.
  27. //
  28. // If WinntSetup is TRUE and WinntFromCd is FALSE, then this
  29. // should be non-null. If it is not non-null, then we couldn't locate
  30. // the local source.
  31. //
  32. //
  33. PDISK_REGION LocalSourceRegion;
  34. #if defined(REMOTE_BOOT)
  35. //
  36. // For remote boot, we create a fake disk region for the net(0) device.
  37. //
  38. PDISK_REGION RemoteBootTargetRegion = NULL;
  39. #endif // defined(REMOTE_BOOT)
  40. //
  41. // RemoteBootSetup is true when Source and target paths are through the redirector
  42. // with possibly no system partition.
  43. //
  44. // RemoteInstallSetup is true when we are doing a remote install.
  45. //
  46. // RemoteSysPrepSetup is true when we are doing a remote install of a sys prep image.
  47. //
  48. // RemoteSysPrepVolumeIsNtfs is true when the sysprep image we're copying down
  49. // represents an ntfs volume.
  50. //
  51. BOOLEAN RemoteBootSetup = FALSE;
  52. BOOLEAN RemoteInstallSetup = FALSE;
  53. BOOLEAN RemoteSysPrepSetup = FALSE;
  54. BOOLEAN RemoteSysPrepVolumeIsNtfs = FALSE;
  55. VOID
  56. SpPtReadPartitionTables(
  57. IN PPARTITIONED_DISK pDisk
  58. );
  59. VOID
  60. SpPtInitializePartitionStructures(
  61. IN ULONG DiskNumber
  62. );
  63. VOID
  64. SpPtDeterminePartitionTypes(
  65. IN ULONG DiskNumber
  66. );
  67. VOID
  68. SpPtDetermineVolumeFreeSpace(
  69. IN ULONG DiskNumber
  70. );
  71. VOID
  72. SpPtLocateSystemPartitions(
  73. VOID
  74. );
  75. VOID
  76. SpPtDeleteDriveLetters(
  77. VOID
  78. );
  79. ValidationValue
  80. SpPtnGetSizeCB(
  81. IN ULONG Key
  82. );
  83. //begin NEC98
  84. NTSTATUS
  85. SpInitializeHardDisk_Nec98(
  86. PDISK_REGION
  87. );
  88. VOID
  89. SpReassignOnDiskOrdinals(
  90. IN PPARTITIONED_DISK pDisk
  91. );
  92. VOID
  93. ConvertPartitionTable(
  94. IN PPARTITIONED_DISK pDisk,
  95. IN PUCHAR Buffer,
  96. IN ULONG bps
  97. );
  98. //end NEC98
  99. NTSTATUS
  100. SpMasterBootCode(
  101. IN ULONG DiskNumber,
  102. IN HANDLE Partition0Handle,
  103. OUT PULONG NewNTFTSignature
  104. );
  105. VOID
  106. SpPtAssignDriveLetters(
  107. VOID
  108. );
  109. //begin NEC98
  110. VOID
  111. SpPtRemapDriveLetters(
  112. IN BOOLEAN DriveAssign_AT
  113. );
  114. VOID
  115. SpPtUnAssignDriveLetters(
  116. VOID
  117. );
  118. WCHAR
  119. SpDeleteDriveLetter(
  120. IN PWSTR DeviceName
  121. );
  122. VOID
  123. SpTranslatePteInfo(
  124. IN PON_DISK_PTE pPte,
  125. IN PREAL_DISK_PTE pRealPte,
  126. IN BOOLEAN Write // into real PTE
  127. );
  128. VOID
  129. SpTranslateMbrInfo(
  130. IN PON_DISK_MBR pMbr,
  131. IN PREAL_DISK_MBR pRealMbr,
  132. IN ULONG bps,
  133. IN BOOLEAN Write // into real MBR
  134. );
  135. VOID
  136. SpDetermineFormatTypeNec98(
  137. IN PPARTITIONED_DISK pDisk,
  138. IN PREAL_DISK_MBR_NEC98 pRealMbrNec98
  139. );
  140. //end NEC98
  141. PDISK_PARTITION
  142. SpGetPartitionDescriptionFromRegistry(
  143. IN PVOID Buffer,
  144. IN ULONG DiskSignature,
  145. IN PLARGE_INTEGER StartingOffset,
  146. IN PLARGE_INTEGER Length
  147. );
  148. VOID
  149. SpPtFindLocalSourceRegionOnDynamicVolumes(
  150. VOID
  151. );
  152. NTSTATUS
  153. SpPtCheckDynamicVolumeForOSInstallation(
  154. IN PDISK_REGION Region
  155. );
  156. #ifndef NEW_PARTITION_ENGINE
  157. NTSTATUS
  158. SpPtInitialize(
  159. VOID
  160. )
  161. {
  162. ULONG disk;
  163. PHARD_DISK harddisk;
  164. PPARTITIONED_DISK partdisk;
  165. ULONG Disk0Ordinal = 0;
  166. ASSERT(HardDisksDetermined);
  167. //
  168. // If there are no hard disks, bail now.
  169. //
  170. if(!HardDiskCount) {
  171. #if defined(REMOTE_BOOT)
  172. //
  173. // If this is a diskless remote boot setup, it's OK for there to be
  174. // no hard disks. Otherwise, this is a fatal error.
  175. //
  176. if (!RemoteBootSetup || RemoteInstallSetup)
  177. #endif // defined(REMOTE_BOOT)
  178. {
  179. SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,3,HEADER_HEIGHT+1);
  180. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  181. SpInputDrain();
  182. while(SpInputGetKeypress() != KEY_F3) ;
  183. SpDone(0,FALSE,TRUE);
  184. }
  185. return STATUS_SUCCESS;
  186. }
  187. CLEAR_CLIENT_SCREEN();
  188. #ifdef _X86_
  189. Disk0Ordinal = SpDetermineDisk0();
  190. //
  191. // If the user booted off of a high-density floppy (e.g. an ls-120), then
  192. // it's possible that we've locked the device in its bay. For this
  193. // reason, we're going to tell the drive to unlock floppy0.
  194. //
  195. {
  196. NTSTATUS Status;
  197. IO_STATUS_BLOCK IoStatusBlock;
  198. OBJECT_ATTRIBUTES ObjectAttributes;
  199. UNICODE_STRING UnicodeString;
  200. HANDLE Handle;
  201. WCHAR OpenPath[64];
  202. PREVENT_MEDIA_REMOVAL PMRemoval;
  203. wcscpy(OpenPath,L"\\device\\floppy0");
  204. INIT_OBJA(&ObjectAttributes,&UnicodeString,OpenPath);
  205. //
  206. // Open him.
  207. //
  208. Status = ZwCreateFile(
  209. &Handle,
  210. FILE_GENERIC_WRITE,
  211. &ObjectAttributes,
  212. &IoStatusBlock,
  213. NULL, // allocation size
  214. FILE_ATTRIBUTE_NORMAL,
  215. FILE_SHARE_VALID_FLAGS, // full sharing
  216. FILE_OPEN,
  217. FILE_SYNCHRONOUS_IO_NONALERT,
  218. NULL, // no EAs
  219. 0
  220. );
  221. if( NT_SUCCESS(Status) ) {
  222. //
  223. // Tell him to let go.
  224. //
  225. PMRemoval.PreventMediaRemoval = FALSE;
  226. Status = ZwDeviceIoControlFile(
  227. Handle,
  228. NULL,
  229. NULL,
  230. NULL,
  231. &IoStatusBlock,
  232. IOCTL_STORAGE_MEDIA_REMOVAL,
  233. &PMRemoval,
  234. sizeof(PMRemoval),
  235. NULL,
  236. 0
  237. );
  238. ZwClose(Handle);
  239. if( !NT_SUCCESS(Status) ) {
  240. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Setup: SpPtInitialize - Failed to tell the floppy to release its media.\n"));
  241. }
  242. } else {
  243. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Setup: SpPtInitialize - Failed to open the floppy.\n"));
  244. }
  245. }
  246. #endif
  247. //
  248. // Allocate an array for the partitioned disk descriptors.
  249. //
  250. PartitionedDisks = SpMemAlloc(HardDiskCount * sizeof(PARTITIONED_DISK));
  251. if(!PartitionedDisks) {
  252. return(STATUS_NO_MEMORY);
  253. }
  254. RtlZeroMemory(PartitionedDisks,HardDiskCount * sizeof(PARTITIONED_DISK));
  255. //
  256. // For each hard disk attached to the system, read its partition table.
  257. //
  258. for(disk=0; disk<HardDiskCount; disk++) {
  259. #ifdef GPT_PARTITION_ENGINE
  260. if (SPPT_IS_GPT_DISK(disk)) {
  261. SpPtnInitializeDiskDrive(disk);
  262. continue;
  263. }
  264. #endif
  265. harddisk = &HardDisks[disk];
  266. SpDisplayStatusText(
  267. SP_STAT_EXAMINING_DISK_N,
  268. DEFAULT_STATUS_ATTRIBUTE,
  269. harddisk->Description
  270. );
  271. partdisk = &PartitionedDisks[disk];
  272. partdisk->HardDisk = harddisk;
  273. //
  274. // Read the partition tables.
  275. //
  276. SpPtReadPartitionTables(partdisk);
  277. //
  278. // Initialize structures that are based on the partition tables.
  279. //
  280. SpPtInitializePartitionStructures(disk);
  281. //
  282. // Determine the type name for each partition on this disk.
  283. //
  284. SpPtDeterminePartitionTypes(disk);
  285. }
  286. //
  287. // Assign drive letters to the various partitions
  288. //
  289. SpPtAssignDriveLetters();
  290. //
  291. // DoubleSpace initialization.
  292. //
  293. //
  294. // Load dblspace.ini file
  295. //
  296. if( SpLoadDblspaceIni() ) {
  297. SpDisplayStatusText(
  298. SP_STAT_EXAMINING_DISK_N,
  299. DEFAULT_STATUS_ATTRIBUTE,
  300. HardDisks[Disk0Ordinal].Description
  301. );
  302. //
  303. // Build lists of compressed drives and add them to the DISK_REGION
  304. // structures
  305. //
  306. SpInitializeCompressedDrives();
  307. }
  308. for(disk=0; disk<HardDiskCount; disk++) {
  309. SpDisplayStatusText(
  310. SP_STAT_EXAMINING_DISK_N,
  311. DEFAULT_STATUS_ATTRIBUTE,
  312. HardDisks[disk].Description
  313. );
  314. //
  315. // Determine the amount of free space on recognized volumes.
  316. //
  317. SpPtDetermineVolumeFreeSpace(disk);
  318. }
  319. if(WinntSetup && !WinntFromCd && !LocalSourceRegion) {
  320. //
  321. // If we got that far and we still don't know where the local source files are,
  322. // then serch for them in the dynamic volumes that are not listed on the MBR or EBR.
  323. //
  324. SpPtFindLocalSourceRegionOnDynamicVolumes();
  325. }
  326. #ifdef _X86_
  327. //
  328. // If the mbr on disk 0 was not valid, inform the user that
  329. // continuing will mean the loss of whatever was on the disk.
  330. //
  331. // We won't actually write it out here. We know that in order to
  332. // continue, the user will HAVE to create a C: partition on this drive
  333. // so we'll end up writing the master boot code when that change is comitted.
  334. //
  335. // Bootable partition on NEC98 is not only C: so don't check it.
  336. //
  337. // If doing a remote install or remote sysprep setup, don't check it.
  338. //
  339. if((!IsNEC_98) && //NEC98
  340. (!ForceConsole) &&
  341. (!(RemoteInstallSetup || RemoteSysPrepSetup)) &&
  342. (!PartitionedDisks[Disk0Ordinal].MbrWasValid)) {
  343. ULONG ValidKeys[2] = { KEY_F3, 0 };
  344. ULONG Mnemonics[2] = { MnemonicContinueSetup,0 };
  345. while(1) {
  346. SpDisplayScreen(SP_SCRN_INVALID_MBR_0,3,HEADER_HEIGHT+1);
  347. SpDisplayStatusOptions(
  348. DEFAULT_STATUS_ATTRIBUTE,
  349. SP_STAT_C_EQUALS_CONTINUE_SETUP,
  350. SP_STAT_F3_EQUALS_EXIT,
  351. 0
  352. );
  353. switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
  354. case KEY_F3:
  355. SpConfirmExit();
  356. break;
  357. default:
  358. //
  359. // must be c=continue
  360. //
  361. goto x1;
  362. }
  363. }
  364. }
  365. x1:
  366. #endif
  367. //
  368. // Figure out which partitions are system partitions.
  369. //
  370. SpPtLocateSystemPartitions();
  371. return(STATUS_SUCCESS);
  372. }
  373. VOID
  374. SpPtDeterminePartitionTypes(
  375. IN ULONG DiskNumber
  376. )
  377. /*++
  378. Routine Description:
  379. Determine the partition types of each partition currently on a disk.
  380. The partition type is determined by the system id byte in the partition
  381. table entry. If the partition type is one we recognize as a Windows NT
  382. compatible filesystem (types 1,4,6,7) then we dig a little deeper and
  383. actually determine the filesystem on the volume and use the result as
  384. the type name.
  385. Unused spaces are not given type names.
  386. Arguments:
  387. DiskNumber - supplies the disk number of the disk whose partitions
  388. we want to inspect for determining their types.
  389. Return Value:
  390. None.
  391. --*/
  392. {
  393. PPARTITIONED_DISK pDisk;
  394. PDISK_REGION pRegion;
  395. ULONG NameId;
  396. UCHAR SysId;
  397. FilesystemType FsType;
  398. unsigned pass;
  399. ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
  400. pDisk = &PartitionedDisks[DiskNumber];
  401. for(pass=0; pass<2; pass++) {
  402. pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
  403. for( ; pRegion; pRegion=pRegion->Next) {
  404. pRegion->TypeName[0] = 0;
  405. pRegion->Filesystem = FilesystemUnknown;
  406. //
  407. // If this is a free space, skip it.
  408. //
  409. if(!pRegion->PartitionedSpace) {
  410. continue;
  411. }
  412. //
  413. // Fetch the system id.
  414. //
  415. // SysId = pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId;
  416. SysId = SpPtGetPartitionType(pRegion);
  417. //
  418. // If this is the extended partition, skip it.
  419. //
  420. if(IsContainerPartition(SysId)) {
  421. continue;
  422. }
  423. //
  424. // Initialize the FT related information
  425. //
  426. if( IsRecognizedPartition(SysId) &&
  427. (((SysId & VALID_NTFT) == VALID_NTFT) ||
  428. ((SysId & PARTITION_NTFT) == PARTITION_NTFT))
  429. ) {
  430. pRegion->FtPartition = TRUE;
  431. }
  432. //
  433. // Initialize the dynamic volume relatated information
  434. //
  435. if( (SysId == PARTITION_LDM)
  436. ) {
  437. pRegion->DynamicVolume = TRUE;
  438. //
  439. // Find out if the dynamic volume is suitable for OS installation
  440. //
  441. SpPtCheckDynamicVolumeForOSInstallation(pRegion);
  442. }
  443. //
  444. // If this is a 'recognized' partition type, then determine
  445. // the filesystem on it. Otherwise use a precanned name.
  446. // Note that we also determine the file system type if this is an
  447. // FT partition of type 'mirror', that is not the mirror shadow.
  448. // We don't care about the shadow since we cannot determine
  449. // its file system anyway (we can't access sector 0 of the shadow).
  450. //
  451. if((PartitionNameIds[SysId] == (UCHAR)(-1)) ||
  452. ( pRegion->FtPartition ) ||
  453. ( pRegion->DynamicVolume )
  454. ) {
  455. FsType = SpIdentifyFileSystem(
  456. HardDisks[DiskNumber].DevicePath,
  457. HardDisks[DiskNumber].Geometry.BytesPerSector,
  458. SpPtGetOrdinal(pRegion,PartitionOrdinalOnDisk)
  459. );
  460. NameId = SP_TEXT_FS_NAME_BASE + FsType;
  461. pRegion->Filesystem = FsType;
  462. } else {
  463. NameId = SP_TEXT_PARTITION_NAME_BASE + (ULONG)PartitionNameIds[SysId];
  464. }
  465. //
  466. // Get the final type name from the resources.
  467. //
  468. SpFormatMessage(
  469. pRegion->TypeName,
  470. sizeof(pRegion->TypeName),
  471. NameId
  472. );
  473. }
  474. }
  475. }
  476. #endif // ! NEW_PARTITION_ENGINE
  477. VOID
  478. SpPtDetermineRegionSpace(
  479. IN PDISK_REGION pRegion
  480. )
  481. {
  482. HANDLE Handle;
  483. OBJECT_ATTRIBUTES Obja;
  484. UNICODE_STRING UnicodeString;
  485. IO_STATUS_BLOCK IoStatusBlock;
  486. FILE_FS_SIZE_INFORMATION SizeInfo;
  487. ULONG r;
  488. NTSTATUS Status;
  489. WCHAR Buffer[512];
  490. struct LABEL_BUFFER {
  491. FILE_FS_VOLUME_INFORMATION VolumeInfo;
  492. WCHAR Label[256];
  493. } LabelBuffer;
  494. PFILE_FS_VOLUME_INFORMATION LabelInfo;
  495. #ifdef _X86_
  496. static BOOLEAN LookForUndelete = TRUE;
  497. PWSTR UndeleteFiles[1] = { L"SENTRY" };
  498. #endif
  499. PWSTR LocalSourceFiles[1] = { LocalSourceDirectory };
  500. ULONG ExtraSpace;
  501. //
  502. // Assume unknown.
  503. //
  504. pRegion->FreeSpaceKB = SPPT_REGION_FREESPACE_KB(pRegion);
  505. pRegion->AdjustedFreeSpaceKB = pRegion->FreeSpaceKB;
  506. pRegion->BytesPerCluster = (ULONG)(-1);
  507. //
  508. // If region is free space of an unknown type, skip it.
  509. //
  510. if(pRegion->Filesystem >= FilesystemFirstKnown) {
  511. //
  512. // Form the name of the root directory.
  513. //
  514. SpNtNameFromRegion(pRegion,Buffer,sizeof(Buffer),PartitionOrdinalCurrent);
  515. SpConcatenatePaths(Buffer,L"");
  516. //
  517. // Delete \pagefile.sys if it's there. This makes disk free space
  518. // calculations a little easier.
  519. //
  520. SpDeleteFile(Buffer,L"pagefile.sys",NULL);
  521. #ifdef _X86_
  522. //
  523. // Check to see if Undelete (dos 6) delete sentry or delete tracking
  524. // methods are in use. If so, give a warning because the free space
  525. // value we will display for this drive will be off.
  526. //
  527. if(LookForUndelete
  528. && (pRegion->Filesystem == FilesystemFat)
  529. && SpNFilesExist(Buffer,UndeleteFiles,ELEMENT_COUNT(UndeleteFiles),TRUE)) {
  530. SpDisplayScreen(SP_SCRN_FOUND_UNDELETE,3,HEADER_HEIGHT+1);
  531. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
  532. SpInputDrain();
  533. while(SpInputGetKeypress() != ASCI_CR) ;
  534. LookForUndelete = FALSE;
  535. }
  536. #endif
  537. //
  538. // If this is a winnt setup, then look for the local source
  539. // on this drive if we haven't found it already.
  540. //
  541. if(WinntSetup && !WinntFromCd && !LocalSourceRegion
  542. && SpNFilesExist(Buffer,LocalSourceFiles,ELEMENT_COUNT(LocalSourceFiles),TRUE)) {
  543. PWSTR SifName;
  544. PVOID SifHandle;
  545. ULONG ErrorLine;
  546. NTSTATUS Status;
  547. PWSTR p;
  548. LocalSourceRegion = pRegion;
  549. pRegion->IsLocalSource = TRUE;
  550. ExtraSpace = 0;
  551. //
  552. // Open the small ini file that text setup put there to tell us
  553. // how much space is taken up by the local source.
  554. //
  555. wcscpy(TemporaryBuffer,Buffer);
  556. SpConcatenatePaths(TemporaryBuffer,LocalSourceDirectory);
  557. SpConcatenatePaths(TemporaryBuffer,L"size.sif");
  558. SifName = SpDupStringW(TemporaryBuffer);
  559. Status = SpLoadSetupTextFile(SifName,NULL,0,&SifHandle,&ErrorLine,TRUE,FALSE);
  560. if(NT_SUCCESS(Status)) {
  561. p = SpGetSectionKeyIndex(SifHandle,L"Data",L"Size",0);
  562. if(p) {
  563. ExtraSpace = (ULONG)SpStringToLong(p,NULL,10);
  564. }
  565. SpFreeTextFile(SifHandle);
  566. }
  567. SpMemFree(SifName);
  568. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: %ws is the local source (occupying %lx bytes)\n",Buffer,ExtraSpace));
  569. }
  570. //
  571. // Open the root directory on the partition's filesystem.
  572. //
  573. INIT_OBJA(&Obja,&UnicodeString,Buffer);
  574. Status = ZwCreateFile(
  575. &Handle,
  576. FILE_GENERIC_READ,
  577. &Obja,
  578. &IoStatusBlock,
  579. NULL,
  580. FILE_ATTRIBUTE_NORMAL,
  581. FILE_SHARE_READ | FILE_SHARE_WRITE,
  582. FILE_OPEN,
  583. FILE_SYNCHRONOUS_IO_NONALERT,
  584. NULL,
  585. 0
  586. );
  587. if(!NT_SUCCESS(Status)) {
  588. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws (%lx)\n",Buffer,Status));
  589. //pRegion->Filesystem = FilesystemUnknown;
  590. return;
  591. }
  592. //
  593. // Fetch volume size info.
  594. //
  595. Status = ZwQueryVolumeInformationFile(
  596. Handle,
  597. &IoStatusBlock,
  598. &SizeInfo,
  599. sizeof(SizeInfo),
  600. FileFsSizeInformation
  601. );
  602. if(NT_SUCCESS(Status)) {
  603. LARGE_INTEGER FreeBytes;
  604. LARGE_INTEGER AdjustedFreeBytes;
  605. //
  606. // Calculate the amount of free space on the drive.
  607. // Use the Rtl multiply routine because there is a compiler
  608. // problem/chip errata on MIPS with 64-bit arithmetic
  609. // (tedm 2/28/96).
  610. //
  611. FreeBytes = RtlExtendedIntegerMultiply(
  612. SizeInfo.AvailableAllocationUnits,
  613. SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector
  614. );
  615. AdjustedFreeBytes = FreeBytes;
  616. if(pRegion->IsLocalSource) {
  617. //
  618. // Only about 1/4 of the total space is moved during textmode.
  619. // Remember too that gui-mode copies the files, so only 25%
  620. // of this space is reusable during setup...
  621. //
  622. AdjustedFreeBytes.QuadPart += (ExtraSpace >> 2);
  623. }
  624. //
  625. // convert this to a number of KB.
  626. //
  627. pRegion->FreeSpaceKB = RtlExtendedLargeIntegerDivide(FreeBytes,1024,&r).LowPart;
  628. if(r >= 512) {
  629. pRegion->FreeSpaceKB++;
  630. }
  631. pRegion->AdjustedFreeSpaceKB = RtlExtendedLargeIntegerDivide(AdjustedFreeBytes,1024,&r).LowPart;
  632. if(r >= 512) {
  633. pRegion->AdjustedFreeSpaceKB++;
  634. }
  635. pRegion->BytesPerCluster = SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector;
  636. if( pRegion->Filesystem == FilesystemDoubleSpace ) {
  637. //
  638. // If this the regison is a double space drive, then initialize
  639. // sector count correctly, so that the drive size can be calculated
  640. // correctly later on.
  641. //
  642. pRegion->SectorCount = (ULONG)( SizeInfo.TotalAllocationUnits.QuadPart
  643. * SizeInfo.SectorsPerAllocationUnit
  644. );
  645. }
  646. } else {
  647. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwQueryVolumeInformationFile for freespace failed (%lx)\n",Status));
  648. }
  649. //
  650. // Fetch volume label info.
  651. //
  652. Status = ZwQueryVolumeInformationFile(
  653. Handle,
  654. &IoStatusBlock,
  655. &LabelBuffer,
  656. sizeof(LabelBuffer),
  657. FileFsVolumeInformation
  658. );
  659. if(NT_SUCCESS(Status)) {
  660. ULONG SaveCharCount;
  661. LabelInfo = &LabelBuffer.VolumeInfo;
  662. //
  663. // We'll only save away the first <n> characters of
  664. // the volume label.
  665. //
  666. SaveCharCount = min(
  667. LabelInfo->VolumeLabelLength + sizeof(WCHAR),
  668. sizeof(pRegion->VolumeLabel)
  669. )
  670. / sizeof(WCHAR);
  671. if(SaveCharCount) {
  672. SaveCharCount--; // allow for terminating NUL.
  673. }
  674. wcsncpy(pRegion->VolumeLabel,LabelInfo->VolumeLabel,SaveCharCount);
  675. pRegion->VolumeLabel[SaveCharCount] = 0;
  676. } else {
  677. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwQueryVolumeInformationFile for label failed (%lx)\n",Status));
  678. }
  679. ZwClose(Handle);
  680. }
  681. }
  682. VOID
  683. SpPtDetermineVolumeFreeSpace(
  684. IN ULONG DiskNumber
  685. )
  686. {
  687. PPARTITIONED_DISK pDisk;
  688. PDISK_REGION pRegion;
  689. unsigned pass;
  690. #ifdef FULL_DOUBLE_SPACE_SUPPORT
  691. PDISK_REGION CompressedDrive;
  692. #endif // FULL_DOUBLE_SPACE_SUPPORT
  693. pDisk = &PartitionedDisks[DiskNumber];
  694. for(pass=0; pass<2; pass++) {
  695. pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
  696. for( ; pRegion; pRegion=pRegion->Next) {
  697. SpPtDetermineRegionSpace( pRegion );
  698. #ifdef FULL_DOUBLE_SPACE_SUPPORT
  699. if( ( pRegion->Filesystem == FilesystemFat ) &&
  700. ( pRegion->NextCompressed != NULL ) ) {
  701. //
  702. // If the region is a FAT partition that contains compressed
  703. // volumes, then determine the available space on each
  704. // compressed volume
  705. //
  706. for( CompressedDrive = pRegion->NextCompressed;
  707. CompressedDrive;
  708. CompressedDrive = CompressedDrive->NextCompressed ) {
  709. SpPtDetermineRegionSpace( CompressedDrive );
  710. }
  711. }
  712. #endif // FULL_DOUBLE_SPACE_SUPPORT
  713. }
  714. }
  715. }
  716. #ifdef OLD_PARTITION_ENGINE
  717. VOID
  718. SpPtLocateSystemPartitions(
  719. VOID
  720. )
  721. {
  722. if(!SpIsArc()) {
  723. //
  724. // NEC98 must not write boot.ini on C:
  725. //
  726. if (!IsNEC_98) { //NEC98
  727. PDISK_REGION pRegion;
  728. ULONG Disk0Ordinal = SpDetermineDisk0();
  729. //
  730. // Note: On X86 we currently don't allow system partitions to reside
  731. // on GPT disks
  732. //
  733. if (SPPT_IS_MBR_DISK(Disk0Ordinal)) {
  734. //
  735. // On x86 machines, we will mark any primary partitions on drive 0
  736. // as system partition, since such a partition is potentially bootable.
  737. //
  738. for(pRegion=PartitionedDisks[Disk0Ordinal].PrimaryDiskRegions;
  739. pRegion;
  740. pRegion=pRegion->Next) {
  741. //
  742. // Skip if free space or extended partition.
  743. //
  744. if(pRegion->PartitionedSpace &&
  745. !IsContainerPartition(SpPtGetPartitionType(pRegion)) &&
  746. (pRegion->ExtendedType == 0)) {
  747. //
  748. // It's a primary partition -- declare it a system partition.
  749. //
  750. pRegion->IsSystemPartition = TRUE;
  751. }
  752. }
  753. }
  754. }
  755. } else {
  756. PDISK_REGION pRegion;
  757. PPARTITIONED_DISK pDisk;
  758. unsigned pass;
  759. ULONG disk;
  760. PSP_BOOT_ENTRY BootEntry;
  761. //
  762. // On ARC machines, system partitions are specifically enumerated
  763. // in the NVRAM boot environment.
  764. //
  765. for(disk=0; disk<HardDiskCount; disk++) {
  766. if (SPPT_IS_GPT_DISK(disk)) {
  767. #ifndef OLD_PARTITION_ENGINE
  768. SpPtnLocateDiskSystemPartitions(disk);
  769. #endif
  770. } else {
  771. pDisk = &PartitionedDisks[disk];
  772. for(pass=0; pass<2; pass++) {
  773. pRegion = pass ?
  774. pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
  775. for( ; pRegion; pRegion=pRegion->Next) {
  776. UCHAR SystemId = SpPtGetPartitionType(pRegion);
  777. //
  778. // Skip if not a partition or extended partition.
  779. //
  780. if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) {
  781. //
  782. // Get the nt pathname for this region.
  783. //
  784. SpNtNameFromRegion(
  785. pRegion,
  786. TemporaryBuffer,
  787. sizeof(TemporaryBuffer),
  788. PartitionOrdinalOriginal
  789. );
  790. //
  791. // Determine if it is a system partition.
  792. //
  793. for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
  794. if((BootEntry->LoaderPartitionNtName != NULL) &&
  795. !_wcsicmp(BootEntry->LoaderPartitionNtName,TemporaryBuffer)) {
  796. pRegion->IsSystemPartition = TRUE;
  797. break;
  798. }
  799. }
  800. }
  801. }
  802. }
  803. }
  804. }
  805. }
  806. }
  807. #endif
  808. VOID
  809. SpPtReadPartitionTables(
  810. IN PPARTITIONED_DISK pDisk
  811. )
  812. /*++
  813. Routine Description:
  814. Read partition tables from a given disk.
  815. Arguments:
  816. pDisk - supplies pointer to disk descriptor to be filled in.
  817. Return Value:
  818. None.
  819. --*/
  820. {
  821. NTSTATUS Status;
  822. HANDLE Handle;
  823. PUCHAR Buffer;
  824. PUCHAR UnalignedBuffer;
  825. PON_DISK_MBR pBr;
  826. BOOLEAN InMbr;
  827. ULONG ExtendedStart;
  828. ULONG NextSector;
  829. PMBR_INFO pEbr,pLastEbr;
  830. BOOLEAN FoundLink;
  831. ULONG i,x;
  832. BOOLEAN Ignore;
  833. ULONG bps;
  834. ULONG SectorsInBootrec;
  835. //
  836. // If this disk is off-line, nothing to do.
  837. //
  838. if(pDisk->HardDisk->Status != DiskOnLine) {
  839. return;
  840. }
  841. //
  842. // Open partition 0 of this disk.
  843. //
  844. Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,FALSE);
  845. if(!NT_SUCCESS(Status)) {
  846. pDisk->HardDisk->Status = DiskOffLine;
  847. return;
  848. }
  849. bps = pDisk->HardDisk->Geometry.BytesPerSector;
  850. if (!IsNEC_98) { //NEC98
  851. SectorsInBootrec = (512/bps) ? (512/bps) : 1;
  852. } else {
  853. // we read two sectors because 0 sector include BootCode , 1 sector include
  854. // PatitionTables. (In AT Machine,0 sector include BootCode and PartitionTable.)
  855. SectorsInBootrec = 2;
  856. } //NEC98
  857. //
  858. // Allocate and align a buffer for sector i/o.
  859. //
  860. // MBR size is not 512 on NEC98.
  861. //
  862. if (!IsNEC_98) {
  863. ASSERT(sizeof(ON_DISK_MBR)==512);
  864. }
  865. UnalignedBuffer = SpMemAlloc(2 * SectorsInBootrec * bps);
  866. Buffer = ALIGN(UnalignedBuffer,bps);
  867. //
  868. // Read the MBR (sector 0).
  869. //
  870. NextSector = 0;
  871. #ifdef _X86_
  872. readmbr:
  873. #endif
  874. Status = SpReadWriteDiskSectors(Handle,NextSector,SectorsInBootrec,bps,Buffer,FALSE);
  875. if(!NT_SUCCESS(Status)) {
  876. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to read mbr for disk %ws (%lx)\n",pDisk->HardDisk->DevicePath,Status));
  877. pDisk->HardDisk->Status = DiskOffLine;
  878. ZwClose(Handle);
  879. SpMemFree(UnalignedBuffer);
  880. return;
  881. }
  882. //
  883. // Move the data we just read into the partitioned disk descriptor.
  884. //
  885. if (!IsNEC_98) { //NEC98
  886. RtlMoveMemory(&pDisk->MbrInfo.OnDiskMbr,Buffer,sizeof(ON_DISK_MBR));
  887. } else {
  888. SpDetermineFormatTypeNec98(pDisk,(PREAL_DISK_MBR_NEC98)Buffer);
  889. if(pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT) {
  890. //
  891. // Move the data we just read into the partitioned disk descriptor.
  892. //
  893. SpTranslateMbrInfo(&pDisk->MbrInfo.OnDiskMbr,(PREAL_DISK_MBR)Buffer,bps,FALSE);
  894. } else {
  895. //
  896. // Translate patririon table information from NEC98 format to PC/AT format.
  897. //
  898. ConvertPartitionTable(pDisk,Buffer,bps);
  899. //
  900. // Read NTFT Signature at 16th sector to check if hard disk is valid.
  901. //
  902. RtlZeroMemory(Buffer,bps);
  903. SpReadWriteDiskSectors(Handle,16,1,bps,Buffer,FALSE);
  904. //
  905. // check "AA55" at the end of 16th sector.
  906. //
  907. if(((PUSHORT)Buffer)[bps/2 - 1] == BOOT_RECORD_SIGNATURE){
  908. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = (((PULONG)Buffer)[0]);
  909. } else {
  910. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = 0x00000000;
  911. }
  912. }
  913. } //NEC98
  914. //
  915. // If this MBR is not valid, initialize it. Otherwise, fetch all logical drives
  916. // (EBR) info as well.
  917. //
  918. if(U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) == MBR_SIGNATURE) {
  919. #ifdef _X86_
  920. //
  921. // No NEC98 supports EZ Drive.
  922. //
  923. if (!IsNEC_98) { //NEC98
  924. //
  925. // EZDrive support: if the first entry in the partition table is
  926. // type 0x55, then the actual partition table is on sector 1.
  927. //
  928. // Only for x86 because on non-x86, the firmware can't see EZDrive
  929. // partitions, so we don't want to install on them!
  930. //
  931. if(!NextSector && (pDisk->MbrInfo.OnDiskMbr.PartitionTable[0].SystemId == 0x55)) {
  932. NextSector = 1;
  933. pDisk->HardDisk->Int13Hooker = HookerEZDrive;
  934. goto readmbr;
  935. }
  936. //
  937. // Also check for on-track.
  938. //
  939. if(!NextSector && (pDisk->MbrInfo.OnDiskMbr.PartitionTable[0].SystemId == 0x54)) {
  940. pDisk->HardDisk->Int13Hooker = HookerOnTrackDiskManager;
  941. }
  942. } //NEC98
  943. #endif
  944. #if defined(REMOTE_BOOT)
  945. if (RemoteBootSetup && !RemoteInstallSetup &&
  946. (U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) == 0)) {
  947. //
  948. // Uh, oh, we've got a case where the signature on the disk is 0, which is
  949. // bad for remote boot because we use 0 as flag for a diskless machine. Let's
  950. // write a new signature on the disk.
  951. //
  952. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = SpComputeSerialNumber();
  953. RtlMoveMemory(Buffer, &pDisk->MbrInfo.OnDiskMbr, sizeof(ON_DISK_MBR));
  954. Status = SpReadWriteDiskSectors(Handle,NextSector,SectorsInBootrec,bps,Buffer,TRUE);
  955. //
  956. // Ignore the status - if it failed, then it failed. The only thing that will
  957. // happen is that the user will get a warning that they need to reformat later.
  958. //
  959. }
  960. #endif // defined(REMOTE_BOOT)
  961. pDisk->MbrWasValid = TRUE;
  962. pBr = &pDisk->MbrInfo.OnDiskMbr;
  963. InMbr = TRUE;
  964. ExtendedStart = 0;
  965. pLastEbr = NULL;
  966. do {
  967. //
  968. // Look at all the entries in the current boot record to see if there
  969. // is a link entry.
  970. //
  971. FoundLink = FALSE;
  972. for(i=0; i<PTABLE_DIMENSION; i++) {
  973. if(IsContainerPartition(pBr->PartitionTable[i].SystemId)) {
  974. FoundLink = TRUE;
  975. NextSector = ExtendedStart + U_ULONG(pBr->PartitionTable[i].RelativeSectors);
  976. if(NextSector == 0) {
  977. //
  978. // Then we've got ourselves one seriously messed up boot record. We'll
  979. // just return, and present this mess as free space.
  980. //
  981. // NOTE: maybe we should warn the user that we are going to ignore
  982. // partitions past this point because the structures are damaged.
  983. //
  984. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Bad partition table for %ws\n",pDisk->HardDisk->DevicePath));
  985. ZwClose(Handle);
  986. SpMemFree(UnalignedBuffer);
  987. return;
  988. }
  989. pEbr = SpMemAlloc(sizeof(MBR_INFO));
  990. ASSERT(pEbr);
  991. RtlZeroMemory(pEbr,sizeof(MBR_INFO));
  992. //
  993. // Sector number on the disk where this boot sector is.
  994. //
  995. pEbr->OnDiskSector = NextSector;
  996. if(InMbr) {
  997. ExtendedStart = NextSector;
  998. InMbr = FALSE;
  999. }
  1000. //
  1001. // Read the next boot sector and break out of the loop through
  1002. // the current partition table.
  1003. //
  1004. Status = SpReadWriteDiskSectors(
  1005. Handle,
  1006. NextSector,
  1007. SectorsInBootrec,
  1008. bps,
  1009. Buffer,
  1010. FALSE
  1011. );
  1012. if(!IsNEC_98) {
  1013. RtlMoveMemory(&pEbr->OnDiskMbr,Buffer,sizeof(ON_DISK_MBR));
  1014. } else {
  1015. if(pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT) {
  1016. SpTranslateMbrInfo(&pEbr->OnDiskMbr,(PREAL_DISK_MBR)Buffer,bps,FALSE);
  1017. } else {
  1018. ConvertPartitionTable(pDisk,Buffer,bps);
  1019. }
  1020. }
  1021. if(!NT_SUCCESS(Status)
  1022. || (U_USHORT(pEbr->OnDiskMbr.AA55Signature) != MBR_SIGNATURE))
  1023. {
  1024. //
  1025. // NOTE: maybe we should warn the user that we are going to ignore
  1026. // partitions part this point because we could not read the disk
  1027. // or the structures are damaged.
  1028. //
  1029. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to read ebr on %ws at sector %lx (%lx)\n",pDisk->HardDisk->DevicePath,NextSector,Status));
  1030. ZwClose(Handle);
  1031. if(pLastEbr) {
  1032. SpMemFree(pEbr);
  1033. }
  1034. SpMemFree(UnalignedBuffer);
  1035. return;
  1036. }
  1037. pBr = &pEbr->OnDiskMbr;
  1038. //
  1039. // We just read the next boot sector. If all that boot sector contains
  1040. // is a link entry, the only thing we need the boot sector for is to find
  1041. // the next boot sector. This happens when there is free space at the start
  1042. // of the extended partition.
  1043. //
  1044. Ignore = TRUE;
  1045. for(x=0; x<PTABLE_DIMENSION; x++) {
  1046. if((pBr->PartitionTable[x].SystemId != PARTITION_ENTRY_UNUSED)
  1047. && !IsContainerPartition(pBr->PartitionTable[x].SystemId)) {
  1048. Ignore = FALSE;
  1049. break;
  1050. }
  1051. }
  1052. //
  1053. // Link the Ebr into the logical volume list if we're not ignoring it.
  1054. //
  1055. if(!Ignore) {
  1056. if(pLastEbr) {
  1057. pLastEbr->Next = pEbr;
  1058. } else {
  1059. ASSERT(pDisk->FirstEbrInfo.Next == NULL);
  1060. pDisk->FirstEbrInfo.Next = pEbr;
  1061. }
  1062. pLastEbr = pEbr;
  1063. }
  1064. break;
  1065. }
  1066. }
  1067. } while(FoundLink);
  1068. } else {
  1069. pDisk->MbrWasValid = FALSE;
  1070. if(!IsNEC_98) {
  1071. RtlZeroMemory(&pDisk->MbrInfo,sizeof(MBR_INFO));
  1072. } else {
  1073. RtlZeroMemory(Buffer,bps*SectorsInBootrec);
  1074. SpTranslateMbrInfo(&pDisk->MbrInfo.OnDiskMbr,(PREAL_DISK_MBR)Buffer,bps,FALSE);
  1075. }
  1076. U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = MBR_SIGNATURE;
  1077. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = SpComputeSerialNumber();
  1078. }
  1079. #if 0
  1080. if (IsNEC_98) { //NEC98
  1081. //
  1082. // Read NTFT Signature at 16th sector to check if hard disk is valid.
  1083. // (I wish to replace below codes by HAL function later.)
  1084. //
  1085. RtlZeroMemory(Buffer,bps);
  1086. SpReadWriteDiskSectors(Handle,
  1087. 16,
  1088. 1,
  1089. bps,
  1090. Buffer,
  1091. FALSE);
  1092. if(((PUSHORT)Buffer)[bps/2 - 1] == BOOT_RECORD_SIGNATURE){
  1093. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = (((PULONG)Buffer)[0]);
  1094. } else {
  1095. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = 0x00000000;
  1096. }
  1097. } //NEC98
  1098. #endif //0
  1099. //
  1100. // Close partition0.
  1101. //
  1102. ZwClose(Handle);
  1103. SpMemFree(UnalignedBuffer);
  1104. return;
  1105. }
  1106. PDISK_REGION
  1107. SpPtAllocateDiskRegionStructure(
  1108. IN ULONG DiskNumber,
  1109. IN ULONGLONG StartSector,
  1110. IN ULONGLONG SectorCount,
  1111. IN BOOLEAN PartitionedSpace,
  1112. IN PMBR_INFO MbrInfo,
  1113. IN ULONG TablePosition
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Allcoate and initialize a structure of type DISK_REGION.
  1118. Arguments:
  1119. Values to be filled into the fields of the newly allocated
  1120. disk region structure.
  1121. Return Value:
  1122. Pointer to new disk region structure.
  1123. --*/
  1124. {
  1125. PDISK_REGION p;
  1126. p = SpMemAlloc(sizeof(DISK_REGION));
  1127. ASSERT(p);
  1128. if(p) {
  1129. RtlZeroMemory(p,sizeof(DISK_REGION));
  1130. p->DiskNumber = DiskNumber;
  1131. p->StartSector = StartSector;
  1132. p->SectorCount = SectorCount;
  1133. p->PartitionedSpace = PartitionedSpace;
  1134. p->MbrInfo = MbrInfo;
  1135. p->TablePosition = TablePosition;
  1136. p->FtPartition = FALSE;
  1137. p->DynamicVolume = FALSE;
  1138. p->DynamicVolumeSuitableForOS = FALSE;
  1139. }
  1140. return(p);
  1141. }
  1142. VOID
  1143. SpPtInsertDiskRegionStructure(
  1144. IN PDISK_REGION Region,
  1145. IN OUT PDISK_REGION *ListHead
  1146. )
  1147. {
  1148. PDISK_REGION RegionCur,RegionPrev;
  1149. //
  1150. // Insert the region entry into the relevent list of region entries.
  1151. // Note that these lists are kept sorted by start sector.
  1152. //
  1153. if(RegionCur = *ListHead) {
  1154. if(Region->StartSector < RegionCur->StartSector) {
  1155. //
  1156. // Stick at head of list.
  1157. //
  1158. Region->Next = RegionCur;
  1159. *ListHead = Region;
  1160. } else {
  1161. while(1) {
  1162. RegionPrev = RegionCur;
  1163. RegionCur = RegionCur->Next;
  1164. if(RegionCur) {
  1165. if(RegionCur->StartSector > Region->StartSector) {
  1166. Region->Next = RegionCur;
  1167. RegionPrev->Next = Region;
  1168. break;
  1169. }
  1170. } else {
  1171. //
  1172. // Stick at end of list.
  1173. //
  1174. RegionPrev->Next = Region;
  1175. break;
  1176. }
  1177. }
  1178. }
  1179. } else {
  1180. *ListHead = Region;
  1181. }
  1182. }
  1183. VOID
  1184. SpPtAssignOrdinals(
  1185. IN PPARTITIONED_DISK pDisk,
  1186. IN BOOLEAN InitCurrentOrdinals,
  1187. IN BOOLEAN InitOnDiskOrdinals,
  1188. IN BOOLEAN InitOriginalOrdinals
  1189. )
  1190. {
  1191. PMBR_INFO pBrInfo;
  1192. ULONG i;
  1193. USHORT ordinal;
  1194. ordinal = 0;
  1195. for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
  1196. for(i=0; i<PTABLE_DIMENSION; i++) {
  1197. PON_DISK_PTE pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
  1198. if((pte->SystemId != PARTITION_ENTRY_UNUSED)
  1199. && !IsContainerPartition(pte->SystemId)) {
  1200. ordinal++;
  1201. if(InitCurrentOrdinals) {
  1202. pBrInfo->CurrentOrdinals[i] = ordinal;
  1203. }
  1204. if(InitOnDiskOrdinals) {
  1205. pBrInfo->OnDiskOrdinals[i] = ordinal;
  1206. }
  1207. if(InitOriginalOrdinals) {
  1208. pBrInfo->OriginalOrdinals[i] = ordinal;
  1209. }
  1210. } else {
  1211. if(InitCurrentOrdinals) {
  1212. pBrInfo->CurrentOrdinals[i] = 0;
  1213. }
  1214. if(InitOnDiskOrdinals) {
  1215. pBrInfo->OnDiskOrdinals[i] = 0;
  1216. }
  1217. if(InitOriginalOrdinals) {
  1218. pBrInfo->OriginalOrdinals[i] = 0;
  1219. }
  1220. }
  1221. }
  1222. }
  1223. }
  1224. VOID
  1225. SpPtInitializePartitionStructures(
  1226. IN ULONG DiskNumber
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. Perform additional initialization on the partition structures,
  1231. beyond what has been performed in SpPtReadPartitionTables.
  1232. Specifically, determine partition ordinals, offsets, and sizes.
  1233. Arguments:
  1234. DiskNumber - disk ordinal of disk descriptor to be filled in.
  1235. Return Value:
  1236. None.
  1237. --*/
  1238. {
  1239. ULONG i,pass;
  1240. PMBR_INFO pBrInfo;
  1241. BOOLEAN InMbr;
  1242. ULONGLONG ExtendedStart = 0;
  1243. ULONGLONG ExtendedEnd,ExtendedSize;
  1244. ULONGLONG offset,size;
  1245. ULONG bps;
  1246. PDISK_REGION pRegion,pRegionCur,pRegionPrev;
  1247. PPARTITIONED_DISK pDisk = &PartitionedDisks[DiskNumber];
  1248. //
  1249. // If this disk is off-line, nothing to do.
  1250. //
  1251. if(pDisk->HardDisk->Status != DiskOnLine) {
  1252. return;
  1253. }
  1254. InMbr = TRUE;
  1255. bps = pDisk->HardDisk->Geometry.BytesPerSector;
  1256. //
  1257. // Link the EBR chain to the MBR.
  1258. //
  1259. if(!IsNEC_98 || (pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) {
  1260. pDisk->MbrInfo.Next = &pDisk->FirstEbrInfo;
  1261. } else {
  1262. //
  1263. // There are no extended partition on NEC98.
  1264. //
  1265. pDisk->MbrInfo.Next = NULL;;
  1266. } //NEC98
  1267. for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
  1268. for(i=0; i<PTABLE_DIMENSION; i++) {
  1269. PON_DISK_PTE pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
  1270. if(pte->SystemId != PARTITION_ENTRY_UNUSED) {
  1271. if(IsContainerPartition(pte->SystemId)) {
  1272. //
  1273. // If we're in the MBR, ExtendedStart will be 0.
  1274. //
  1275. offset = ExtendedStart + U_ULONG(pte->RelativeSectors);
  1276. size = U_ULONG(pte->SectorCount);
  1277. //
  1278. // Track the start of the extended partition.
  1279. //
  1280. if(InMbr) {
  1281. ExtendedStart = U_ULONG(pte->RelativeSectors);
  1282. ExtendedEnd = ExtendedStart + U_ULONG(pte->SectorCount);
  1283. ExtendedSize = ExtendedEnd - ExtendedStart;
  1284. }
  1285. } else {
  1286. //
  1287. // In the MBR, the relative sectors field is the sector offset
  1288. // to the partition. In EBRs, the relative sectors field is the
  1289. // number of sectors between the start of the boot sector and
  1290. // the start of the filesystem data area. We will consider such
  1291. // partitions to start with their boot sectors.
  1292. //
  1293. offset = InMbr ? U_ULONG(pte->RelativeSectors) : pBrInfo->OnDiskSector;
  1294. size = U_ULONG(pte->SectorCount)
  1295. + (InMbr ? 0 : U_ULONG(pte->RelativeSectors));
  1296. }
  1297. if(InMbr || !IsContainerPartition(pte->SystemId)) {
  1298. //
  1299. // Create a region entry for this used space.
  1300. //
  1301. pRegion = SpPtAllocateDiskRegionStructure(
  1302. DiskNumber,
  1303. offset,
  1304. size,
  1305. TRUE,
  1306. pBrInfo,
  1307. i
  1308. );
  1309. ASSERT(pRegion);
  1310. //
  1311. // Insert the region entry into the relevent list of region entries.
  1312. // Note that these lists are kept sorted by start sector.
  1313. //
  1314. SpPtInsertDiskRegionStructure(
  1315. pRegion,
  1316. InMbr ? &pDisk->PrimaryDiskRegions : &pDisk->ExtendedDiskRegions
  1317. );
  1318. }
  1319. }
  1320. }
  1321. if(InMbr) {
  1322. InMbr = FALSE;
  1323. }
  1324. }
  1325. //
  1326. // Initialize partition ordinals.
  1327. //
  1328. SpPtAssignOrdinals(pDisk,TRUE,TRUE,TRUE);
  1329. //
  1330. // Now go through the regions for this disk and insert free space descriptors
  1331. // where necessary.
  1332. //
  1333. // Pass 0 for the MBR; pass 1 for logical drives.
  1334. //
  1335. for(pass=0; pass<(ULONG)(ExtendedStart ? 2 : 1); pass++) {
  1336. if(pRegionPrev = (pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions)) {
  1337. ULONGLONG EndSector,FreeSpaceSize;
  1338. ASSERT(pRegionPrev->PartitionedSpace);
  1339. //
  1340. // Handle any space occurring *before* the first partition.
  1341. //
  1342. if(pRegionPrev->StartSector != (pass ? ExtendedStart : 0)) {
  1343. ASSERT(pRegionPrev->StartSector > (pass ? ExtendedStart : 0));
  1344. pRegion = SpPtAllocateDiskRegionStructure(
  1345. DiskNumber,
  1346. pass ? ExtendedStart : 0,
  1347. pRegionPrev->StartSector - (pass ? ExtendedStart : 0),
  1348. FALSE,
  1349. NULL,
  1350. 0
  1351. );
  1352. ASSERT(pRegion);
  1353. pRegion->Next = pRegionPrev;
  1354. if(pass) {
  1355. // extended
  1356. pDisk->ExtendedDiskRegions = pRegion;
  1357. } else {
  1358. // mbr
  1359. pDisk->PrimaryDiskRegions = pRegion;
  1360. }
  1361. }
  1362. pRegionCur = pRegionPrev->Next;
  1363. while(pRegionCur) {
  1364. //
  1365. // If the start of this partition plus its size is less than the
  1366. // start of the next partition, then we need a new region.
  1367. //
  1368. EndSector = pRegionPrev->StartSector + pRegionPrev->SectorCount;
  1369. FreeSpaceSize = pRegionCur->StartSector - EndSector;
  1370. if((LONG)FreeSpaceSize > 0) {
  1371. pRegion = SpPtAllocateDiskRegionStructure(
  1372. DiskNumber,
  1373. EndSector,
  1374. FreeSpaceSize,
  1375. FALSE,
  1376. NULL,
  1377. 0
  1378. );
  1379. ASSERT(pRegion);
  1380. pRegionPrev->Next = pRegion;
  1381. pRegion->Next = pRegionCur;
  1382. }
  1383. pRegionPrev = pRegionCur;
  1384. pRegionCur = pRegionCur->Next;
  1385. }
  1386. //
  1387. // Space at end of disk/extended partition.
  1388. //
  1389. EndSector = pRegionPrev->StartSector + pRegionPrev->SectorCount;
  1390. FreeSpaceSize = (pass ? ExtendedEnd : pDisk->HardDisk->DiskSizeSectors) - EndSector;
  1391. if((LONG)FreeSpaceSize > 0) {
  1392. pRegionPrev->Next = SpPtAllocateDiskRegionStructure(
  1393. DiskNumber,
  1394. EndSector,
  1395. FreeSpaceSize,
  1396. FALSE,
  1397. NULL,
  1398. 0
  1399. );
  1400. ASSERT(pRegionPrev->Next);
  1401. }
  1402. } else {
  1403. //
  1404. // Show whole disk/extended partition as free.
  1405. //
  1406. if(pass) {
  1407. //
  1408. // Extended partition.
  1409. //
  1410. ASSERT(ExtendedStart);
  1411. pDisk->ExtendedDiskRegions = SpPtAllocateDiskRegionStructure(
  1412. DiskNumber,
  1413. ExtendedStart,
  1414. ExtendedSize,
  1415. FALSE,
  1416. NULL,
  1417. 0
  1418. );
  1419. ASSERT(pDisk->ExtendedDiskRegions);
  1420. } else {
  1421. //
  1422. // MBR.
  1423. //
  1424. pDisk->PrimaryDiskRegions = SpPtAllocateDiskRegionStructure(
  1425. DiskNumber,
  1426. 0,
  1427. pDisk->HardDisk->DiskSizeSectors,
  1428. FALSE,
  1429. NULL,
  1430. 0
  1431. );
  1432. ASSERT(pDisk->PrimaryDiskRegions);
  1433. }
  1434. }
  1435. }
  1436. }
  1437. VOID
  1438. SpPtCountPrimaryPartitions(
  1439. IN PPARTITIONED_DISK pDisk,
  1440. OUT PULONG TotalPrimaryPartitionCount,
  1441. OUT PULONG RecognizedPrimaryPartitionCount,
  1442. OUT PBOOLEAN ExtendedExists
  1443. )
  1444. {
  1445. ULONG TotalCount;
  1446. ULONG RecognizedCount;
  1447. ULONG u;
  1448. UCHAR SysId;
  1449. TotalCount = 0;
  1450. RecognizedCount = 0;
  1451. *ExtendedExists = FALSE;
  1452. for(u=0; u<PTABLE_DIMENSION; u++) {
  1453. SysId = pDisk->MbrInfo.OnDiskMbr.PartitionTable[u].SystemId;
  1454. if(SysId != PARTITION_ENTRY_UNUSED) {
  1455. TotalCount++;
  1456. if(IsRecognizedPartition(SysId)
  1457. && !(SysId & VALID_NTFT) && !(SysId & PARTITION_NTFT)) {
  1458. RecognizedCount++;
  1459. }
  1460. if(IsContainerPartition(SysId)) {
  1461. *ExtendedExists = TRUE;
  1462. }
  1463. }
  1464. }
  1465. *TotalPrimaryPartitionCount = TotalCount;
  1466. *RecognizedPrimaryPartitionCount = RecognizedCount;
  1467. }
  1468. PDISK_REGION
  1469. SpPtLookupRegionByStart(
  1470. IN PPARTITIONED_DISK pDisk,
  1471. IN BOOLEAN ExtendedPartition,
  1472. IN ULONGLONG StartSector
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. Locate a disk region, based on its starting sector.
  1477. The starting sector must match the starting sector of an existing
  1478. region EXACTLY for it to be considered a match.
  1479. Arguments:
  1480. pDisk - supplies disk on which to look for the region.
  1481. ExtendedPartition - if TRUE, then look in the extended partition to find
  1482. a match. Otherwise look in the main list.
  1483. StartSector - supplies the sector number of the first sector of the region.
  1484. Return Value:
  1485. NULL is region could not be found; otherwise a pointer to the matching
  1486. disk region structure.
  1487. --*/
  1488. {
  1489. PDISK_REGION Region = NULL;
  1490. #ifdef NEW_PARTITION_ENGINE
  1491. ExtendedPartition = FALSE;
  1492. #else
  1493. #ifdef GPT_PARTITION_ENGINE
  1494. if (pDisk->HardDisk->DiskFormatType == DISK_FORMAT_TYPE_GPT))
  1495. ExtendedPartition = FALSE;
  1496. #endif // GPT_PARTITION_ENGINE
  1497. #endif // NEW_PARTITION_ENGINE
  1498. Region = (ExtendedPartition) ?
  1499. pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions;
  1500. while (Region && (StartSector != Region->StartSector)) {
  1501. Region = Region->Next;
  1502. }
  1503. return Region;
  1504. }
  1505. ULONG
  1506. SpPtAlignStart(
  1507. IN PHARD_DISK pHardDisk,
  1508. IN ULONGLONG StartSector,
  1509. IN BOOLEAN ForExtended
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Snap a start sector to a cylinder boundary if it is not already
  1514. on a cylinder boundary. Any alignment that is necessary
  1515. is performed towards the end of the disk.
  1516. If the start sector is on cylinder 0, then alignment is to track 1
  1517. for primary partitions, or to track 0 on cylinder 1 for extended partitions.
  1518. Arguments:
  1519. pHardDisk - supplies disk descriptor for disk that the start sector is on.
  1520. StartSector - supplies the sector number of the first sector of the region.
  1521. ForExtended - if TRUE, then align the start sector as appropriate for creating
  1522. an extended partition. Otherwise align for a pimary partition or logical drive.
  1523. Return Value:
  1524. New (aligned) start sector. May or may not be different than StartSector.
  1525. --*/
  1526. {
  1527. PDISK_GEOMETRY pGeometry;
  1528. ULONGLONG r;
  1529. ULONGLONG C,H,S;
  1530. pGeometry = &pHardDisk->Geometry;
  1531. //
  1532. // Convert the start sector into cylinder, head, sector address.
  1533. //
  1534. C = StartSector / pHardDisk->SectorsPerCylinder;
  1535. r = StartSector % pHardDisk->SectorsPerCylinder;
  1536. H = r / pGeometry->SectorsPerTrack;
  1537. S = r % pGeometry->SectorsPerTrack;
  1538. //
  1539. // Align as necessary.
  1540. //
  1541. if(C) {
  1542. if(H || S) {
  1543. H = S = 0;
  1544. C++;
  1545. }
  1546. } else {
  1547. //
  1548. // Start cylinder is 0. If the caller wants to create an
  1549. // extended partition, bump the start cylinder up to 1.
  1550. //
  1551. if(ForExtended) {
  1552. C = 1;
  1553. H = S = 0;
  1554. } else {
  1555. if (!IsNEC_98 || (pHardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) { //NEC98
  1556. //
  1557. // Start cylinder is 0 and the caller does not want to
  1558. // create an extended partition. In this case, we want
  1559. // to start the partition on cylinder 0, track 1. If the
  1560. // start is beyond this already, start on cylinder 1.
  1561. //
  1562. if((H == 0) || ((H == 1) && !S)) {
  1563. H = 1;
  1564. S = 0;
  1565. } else {
  1566. H = S = 0;
  1567. C = 1;
  1568. }
  1569. } else {
  1570. //
  1571. // if Start cylinder is 0, force start Cylinder 1.
  1572. //
  1573. C = 1;
  1574. H = S = 0;
  1575. } //NEC98
  1576. }
  1577. }
  1578. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  1579. "SETUP:SpPtAlignStart():C:%I64d,H:%I64d,S:%I64d\n",
  1580. C, H, S));
  1581. //
  1582. // Now calculate and return the new start sector.
  1583. //
  1584. return (ULONG)((C * pHardDisk->SectorsPerCylinder) + (H * pGeometry->SectorsPerTrack) + S);
  1585. }
  1586. VOID
  1587. SpPtQueryMinMaxCreationSizeMB(
  1588. IN ULONG DiskNumber,
  1589. IN ULONGLONG StartSector,
  1590. IN BOOLEAN ForExtended,
  1591. IN BOOLEAN InExtended,
  1592. OUT PULONGLONG MinSize,
  1593. OUT PULONGLONG MaxSize,
  1594. OUT PBOOLEAN ReservedRegion
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. Given the starting sector of an unpartitioned space on a disk,
  1599. determine the minimum and maximum size in megabytes of the partition that can
  1600. be created in the space, taking all alignment and rounding
  1601. requirements into account.
  1602. Arguments:
  1603. DiskNumber - ordinal of disk on which partition will be created.
  1604. StartSector - starting sector of an unpartitioned space on the disk.
  1605. ForExtended - if TRUE, then the caller wants to know how large an
  1606. extended partition in that space could be. This may be smaller
  1607. than the general case, because an extended partition cannot start
  1608. on cylinder 0.
  1609. InExtended - if TRUE, then we want to create a logical drive. Otherwise
  1610. we want to create a primary (including extended) partition.
  1611. If TRUE, ForExtended must be FALSE.
  1612. MinSize - receives minimum size in megabytes for a partition in the space.
  1613. MaxSize - receives maximum size in megabytes for a partition in the space.
  1614. ReservedRegion - Receives a flag that indicates if the region is entirely
  1615. in the last cylinder. Because the last cylinder should be
  1616. reserved for dynamic volumes, this routine will return 0
  1617. as MaxSize, if the region is in such a cylinder
  1618. Return Value:
  1619. None.
  1620. --*/
  1621. {
  1622. PPARTITIONED_DISK pDisk;
  1623. ULONGLONG AlignedStartSector;
  1624. ULONGLONG AlignedEndSector;
  1625. ULONGLONG SectorCount;
  1626. PDISK_REGION pRegion;
  1627. ULONGLONG MB, ByteSize;
  1628. ULONGLONG Remainder;
  1629. ULONGLONG LeftOverSectors;
  1630. *MinSize = 0;
  1631. *MaxSize = 0;
  1632. *ReservedRegion = FALSE;
  1633. ASSERT(DiskNumber < HardDiskCount);
  1634. if(InExtended) {
  1635. ASSERT(!ForExtended);
  1636. }
  1637. pDisk = &PartitionedDisks[DiskNumber];
  1638. //
  1639. // Look up this region.
  1640. //
  1641. pRegion = SpPtLookupRegionByStart(pDisk, InExtended, StartSector);
  1642. ASSERT(pRegion);
  1643. if(!pRegion) {
  1644. return;
  1645. }
  1646. ASSERT(!pRegion->PartitionedSpace);
  1647. if(pRegion->PartitionedSpace) {
  1648. return;
  1649. }
  1650. //
  1651. // If this is the first free space inside the extended partition
  1652. // we need to decrement the StartSector so that while creating
  1653. // first logical inside the extended we don't create the
  1654. // logical at one cylinder offset
  1655. //
  1656. if (SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(pRegion) && StartSector) {
  1657. StartSector--;
  1658. }
  1659. //
  1660. // Align the start to a proper boundary.
  1661. //
  1662. AlignedStartSector = SpPtAlignStart(pDisk->HardDisk,StartSector,ForExtended);
  1663. //
  1664. // Determine the maximum aligned end sector.
  1665. //
  1666. AlignedEndSector = StartSector + pRegion->SectorCount;
  1667. if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) {
  1668. AlignedEndSector -= LeftOverSectors;
  1669. }
  1670. //
  1671. // Find out if last sector is in the last cylinder. If it is then align it down.
  1672. // This is because we should not allow the user to create a partition that contains the last cylinder.
  1673. // This is necessary so that we reserve a cylinder at the end of the disk, so that users
  1674. // can convert the disk to dynamic after the system is installed.
  1675. //
  1676. // (guhans) Don't align down if this is ASR. ASR already takes this into account.
  1677. //
  1678. if(!DockableMachine && !SpDrEnabled() && SPPT_IS_MBR_DISK(DiskNumber) && (!pRegion->Next) &&
  1679. (AlignedEndSector >= (pDisk->HardDisk->CylinderCount - 1) * pDisk->HardDisk->SectorsPerCylinder)) {
  1680. AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder;
  1681. if(AlignedEndSector == AlignedStartSector) {
  1682. //
  1683. // If after alignment, the partition size is zero, then the user was attempting to
  1684. // create a partition in the last cylinder of the disk. Since this cylinder is
  1685. // reserved for LDM (dynamic volume), just return 0 as maximum partition size, and
  1686. // also indicate to the caller that the region is reserved.
  1687. //
  1688. *ReservedRegion = TRUE;
  1689. *MinSize = 0;
  1690. *MaxSize = 0;
  1691. return;
  1692. }
  1693. }
  1694. //
  1695. // Calculate the number of sectors in the properly aligned space.
  1696. //
  1697. SectorCount = AlignedEndSector - AlignedStartSector;
  1698. //
  1699. // Convert sectors to MB.
  1700. //
  1701. ByteSize = SectorCount * pDisk->HardDisk->Geometry.BytesPerSector;
  1702. MB = ByteSize / (1024 * 1024);
  1703. Remainder = ByteSize % (1024 * 1024);
  1704. //
  1705. // If the remainder was greater than or equal to a half meg,
  1706. // bump up the number of megabytes.
  1707. //
  1708. *MaxSize = (MB + ((Remainder >= (512 * 1024)) ? 1 : 0));
  1709. //
  1710. // The mimimum size is one cylinder except that if a cylinder
  1711. // is smaller than 1 meg, the min size is 1 meg.
  1712. //
  1713. ByteSize = pDisk->HardDisk->SectorsPerCylinder *
  1714. pDisk->HardDisk->Geometry.BytesPerSector;
  1715. *MinSize = ByteSize / (1024 * 1024);
  1716. Remainder = ByteSize % (1024 * 1024);
  1717. if((*MinSize == 0) || (Remainder >= (512 * 1024))) {
  1718. (*MinSize)++;
  1719. }
  1720. }
  1721. ULONGLONG
  1722. SpPtSectorCountToMB(
  1723. IN PHARD_DISK pHardDisk,
  1724. IN ULONGLONG SectorCount
  1725. )
  1726. {
  1727. ULONGLONG ByteCount;
  1728. ULONGLONG MB,r;
  1729. //
  1730. // Calculate the number of bytes that this number of
  1731. // sectors represents.
  1732. //
  1733. ByteCount = (pHardDisk->Geometry.BytesPerSector * SectorCount);
  1734. //
  1735. // Calculate the number of megabytes this represents.
  1736. //
  1737. r = ByteCount % (1024 * 1204);
  1738. MB = ByteCount / (1024 * 1024);
  1739. //
  1740. // Round up if necessary.
  1741. //
  1742. if(r >= (512*1024)) {
  1743. MB++;
  1744. }
  1745. return (MB);
  1746. }
  1747. VOID
  1748. SpPtInitializeCHSFields(
  1749. IN PHARD_DISK HardDisk,
  1750. IN ULONGLONG AbsoluteStartSector,
  1751. IN ULONGLONG AbsoluteSectorCount,
  1752. OUT PON_DISK_PTE pte
  1753. )
  1754. {
  1755. ULONGLONG sC,sH,sS,r;
  1756. ULONGLONG eC,eH,eS;
  1757. ULONGLONG LastSector;
  1758. sC = AbsoluteStartSector / HardDisk->SectorsPerCylinder;
  1759. r = AbsoluteStartSector % HardDisk->SectorsPerCylinder;
  1760. sH = r / HardDisk->Geometry.SectorsPerTrack;
  1761. sS = r % HardDisk->Geometry.SectorsPerTrack;
  1762. LastSector = AbsoluteStartSector + AbsoluteSectorCount - 1;
  1763. eC = LastSector / HardDisk->SectorsPerCylinder;
  1764. r = LastSector % HardDisk->SectorsPerCylinder;
  1765. eH = r / HardDisk->Geometry.SectorsPerTrack;
  1766. eS = r % HardDisk->Geometry.SectorsPerTrack;
  1767. //
  1768. // If this partition extends past the 1024th cylinder,
  1769. // place reasonable values in the CHS fields.
  1770. //
  1771. #if defined(NEC_98) //NEC98
  1772. if (!IsNEC_98 || (HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) { //NEC98
  1773. #endif //NEC98
  1774. if(eC >= 1024) {
  1775. sC = 1023;
  1776. sH = HardDisk->Geometry.TracksPerCylinder - 1;
  1777. sS = HardDisk->Geometry.SectorsPerTrack - 1;
  1778. eC = sC;
  1779. eH = sH;
  1780. eS = sS;
  1781. }
  1782. //
  1783. // Pack the CHS values into int13 format.
  1784. //
  1785. pte->StartCylinder = (UCHAR)sC;
  1786. pte->StartHead = (UCHAR)sH;
  1787. pte->StartSector = (UCHAR)((sS & 0x3f) | ((sC >> 2) & 0xc0)) + 1;
  1788. pte->EndCylinder = (UCHAR)eC;
  1789. pte->EndHead = (UCHAR)eH;
  1790. pte->EndSector = (UCHAR)((eS & 0x3f) | ((eC >> 2) & 0xc0)) + 1;
  1791. #if defined(NEC_98) //NEC98
  1792. } else {
  1793. //
  1794. // No NEC98 have "1024th cylinder limit".
  1795. //
  1796. pte->StartCylinderLow = (UCHAR)sC;
  1797. pte->StartCylinderHigh = (UCHAR)(sC >> 4);
  1798. pte->StartHead = (UCHAR)sH;
  1799. pte->StartSector = (UCHAR)sS;
  1800. pte->EndCylinderLow = (UCHAR)eC;
  1801. pte->EndCylinderHigh = (UCHAR)(eC >> 4);
  1802. pte->EndHead = (UCHAR)eH;
  1803. pte->EndSector = (UCHAR)eS;
  1804. } //NEC98
  1805. #endif //NEC98
  1806. }
  1807. #ifndef NEW_PARTITION_ENGINE
  1808. BOOLEAN
  1809. SpPtCreate(
  1810. IN ULONG DiskNumber,
  1811. IN ULONGLONG StartSector,
  1812. IN ULONGLONG SizeMB,
  1813. IN BOOLEAN InExtended,
  1814. IN PPARTITION_INFORMATION_EX PartInfo,
  1815. OUT PDISK_REGION *ActualDiskRegion OPTIONAL
  1816. )
  1817. /*++
  1818. Routine Description:
  1819. Create a partition in a given free space.
  1820. Arguments:
  1821. DiskNumber - supplies the number of the disk on which we are
  1822. creating the partition.
  1823. StartSector - supplies the start sector of the free space in which
  1824. the parititon is to be created. This must exactly match the
  1825. start sector of the free space, and can be in either the primary
  1826. space list or the list of spaces in the extended partition.
  1827. SizeMB - supplies the size in megabytes of the partition.
  1828. InExtended - if TRUE, then the free space is within the extended partition,
  1829. and thus we are creating a logical drive. If FALSE, then the free
  1830. space is an ordinary unpartitioned space, and we are creating a
  1831. primary partition.
  1832. SysId - supplies the system id to give the partition. This may not
  1833. be 5/f (PARTITION_EXTENDED) if InExtended is TRUE or is an extended
  1834. partition already exists. No other checks are performed on this value.
  1835. ActualDiskRegion - if supplied, receives a pointer to the disk region in which
  1836. the partition was created.
  1837. Return Value:
  1838. TRUE if the partition was created successfully.
  1839. FALSE otherwise.
  1840. --*/
  1841. {
  1842. PPARTITIONED_DISK pDisk;
  1843. ULONGLONG SectorCount;
  1844. ULONGLONG AlignedStartSector;
  1845. ULONGLONG AlignedEndSector;
  1846. PDISK_REGION pRegion,pRegionPrev,pRegionNew,*pRegionHead;
  1847. ULONGLONG LeftOverSectors;
  1848. PMBR_INFO pBrInfo;
  1849. ULONG slot,i,spt;
  1850. PON_DISK_PTE pte;
  1851. ULONGLONG ExtendedStart;
  1852. UCHAR SysId;
  1853. #ifdef GPT_PARTITION_ENGINE
  1854. if (SPPT_IS_GPT_DISK(DiskNumber)) {
  1855. return SpPtnCreate(DiskNumber,
  1856. StartSector,
  1857. 0, // SizeInSectors: Not used except in ASR
  1858. SizeMB,
  1859. InExtended,
  1860. TRUE,
  1861. PartInfo,
  1862. ActualDiskRegion);
  1863. }
  1864. #endif
  1865. SysId = PartInfo->Mbr.PartitionType;
  1866. //
  1867. // Look up the disk region that describes this free space.
  1868. //
  1869. pDisk = &PartitionedDisks[DiskNumber];
  1870. pRegion = SpPtLookupRegionByStart(pDisk,InExtended,StartSector);
  1871. ASSERT(pRegion);
  1872. if(!pRegion) {
  1873. return(FALSE);
  1874. }
  1875. if(ActualDiskRegion) {
  1876. *ActualDiskRegion = pRegion;
  1877. }
  1878. ASSERT(!pRegion->PartitionedSpace);
  1879. if(pRegion->PartitionedSpace) {
  1880. return(FALSE);
  1881. }
  1882. if(InExtended) {
  1883. ASSERT(!IsContainerPartition(SysId));
  1884. //
  1885. // Locate the start sector of the extended partition.
  1886. //
  1887. for(i=0; i<PTABLE_DIMENSION; i++) {
  1888. if(IsContainerPartition(pDisk->MbrInfo.OnDiskMbr.PartitionTable[i].SystemId)) {
  1889. ExtendedStart = U_ULONG(pDisk->MbrInfo.OnDiskMbr.PartitionTable[i].RelativeSectors);
  1890. break;
  1891. }
  1892. }
  1893. ASSERT(ExtendedStart);
  1894. if(!ExtendedStart) {
  1895. return(FALSE);
  1896. }
  1897. }
  1898. //
  1899. // Determine the number of sectors in the size passed in.
  1900. // Note: the calculation is performed such that intermediate results
  1901. // won't overflow a ULONG.
  1902. //
  1903. SectorCount = SizeMB * ((1024*1024)/pDisk->HardDisk->Geometry.BytesPerSector);
  1904. //
  1905. // Align the start sector.
  1906. //
  1907. AlignedStartSector = SpPtAlignStart(
  1908. pDisk->HardDisk,
  1909. StartSector,
  1910. (BOOLEAN)IsContainerPartition(SysId)
  1911. );
  1912. //
  1913. // Determine the end sector based on the size passed in.
  1914. //
  1915. AlignedEndSector = AlignedStartSector + SectorCount;
  1916. //
  1917. // Align the ending sector to a cylinder boundary. If it is not already
  1918. // aligned and is more than half way into the final cylinder, align it up,
  1919. // otherwise align it down.
  1920. //
  1921. if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) {
  1922. AlignedEndSector -= LeftOverSectors;
  1923. if(LeftOverSectors > pDisk->HardDisk->SectorsPerCylinder/2) {
  1924. AlignedEndSector += pDisk->HardDisk->SectorsPerCylinder;
  1925. }
  1926. }
  1927. //
  1928. // If the ending sector is past the end of the free space, shrink it
  1929. // so it fits.
  1930. //
  1931. while(AlignedEndSector > pRegion->StartSector + pRegion->SectorCount) {
  1932. AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder;
  1933. }
  1934. //
  1935. // Find out if last sector is in the last cylinder. If it is then align it down.
  1936. // This is necessary so that we reserve a cylinder at the end of the disk, so that users
  1937. // can convert the disk to dynamic after the system is installed.
  1938. //
  1939. // (guhans) Don't align down if this is ASR. ASR already takes this into account.
  1940. //
  1941. if( !DockableMachine && !SpDrEnabled() &&
  1942. (AlignedEndSector > (pDisk->HardDisk->CylinderCount - 1) * pDisk->HardDisk->SectorsPerCylinder)
  1943. ) {
  1944. AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder;
  1945. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: End of partition was aligned down 1 cylinder \n"));
  1946. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: AlignedStartSector = %lx \n", AlignedStartSector));
  1947. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: AlignedEndSector = %lx \n", AlignedEndSector));
  1948. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SectorsPerCylinder = %lx \n", pDisk->HardDisk->SectorsPerCylinder));
  1949. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CylinderCount = %lx \n", pDisk->HardDisk->CylinderCount));
  1950. }
  1951. ASSERT((LONG)AlignedEndSector > 0);
  1952. if((LONG)AlignedEndSector < 0) {
  1953. return(FALSE);
  1954. }
  1955. //
  1956. // If we are creating a logical drive, create a new mbr structure
  1957. // for it.
  1958. //
  1959. if(InExtended) {
  1960. //
  1961. // Create a boot record for this new logical drive; use slot #0
  1962. // for the partition entry (and slot #1 for the extended record,
  1963. // if necessary).
  1964. //
  1965. pBrInfo = SpMemAlloc(sizeof(MBR_INFO));
  1966. ASSERT(pBrInfo);
  1967. RtlZeroMemory(pBrInfo,sizeof(MBR_INFO));
  1968. slot = 0;
  1969. } else {
  1970. //
  1971. // Look for a free slot in the MBR's partition table.
  1972. //
  1973. pBrInfo = &pDisk->MbrInfo;
  1974. for(slot=0; slot<PTABLE_DIMENSION; slot++) {
  1975. if(pBrInfo->OnDiskMbr.PartitionTable[slot].SystemId == PARTITION_ENTRY_UNUSED) {
  1976. break;
  1977. }
  1978. }
  1979. if(slot == PTABLE_DIMENSION) {
  1980. ASSERT(0);
  1981. return(FALSE);
  1982. }
  1983. }
  1984. //
  1985. // Initialize the partition table entry.
  1986. //
  1987. spt = pDisk->HardDisk->Geometry.SectorsPerTrack;
  1988. pte = &pBrInfo->OnDiskMbr.PartitionTable[slot];
  1989. pte->ActiveFlag = 0;
  1990. pte->SystemId = SysId;
  1991. U_ULONG(pte->RelativeSectors) = (ULONG)(InExtended ? spt : AlignedStartSector);
  1992. U_ULONG(pte->SectorCount) = (ULONG)(AlignedEndSector - AlignedStartSector - (InExtended ? spt : 0));
  1993. SpPtInitializeCHSFields(
  1994. pDisk->HardDisk,
  1995. AlignedStartSector + (InExtended ? spt : 0),
  1996. AlignedEndSector - AlignedStartSector - (InExtended ? spt : 0),
  1997. pte
  1998. );
  1999. //
  2000. // If we're in the extended partition we mark all entries in the
  2001. // boot record as dirty. Sometimes there is a turd boot record on
  2002. // the disk already, and by setting all entries to dirty we get
  2003. // the crud cleaned out if necessary. The only entries that should be
  2004. // in an EBR are the type 6 or whatever and a type 5 if there are
  2005. // additional logical drives in the extended partition.
  2006. //
  2007. if(InExtended) {
  2008. for(i=0; i<PTABLE_DIMENSION; i++) {
  2009. pBrInfo->Dirty[i] = TRUE;
  2010. }
  2011. } else {
  2012. pBrInfo->Dirty[slot] = TRUE;
  2013. }
  2014. //
  2015. // Don't zap the first sector of the extended partition,
  2016. // as this wipes out the first logical drive, and precludes
  2017. // access to all logical drives!
  2018. //
  2019. if(!IsContainerPartition(SysId)) {
  2020. pBrInfo->ZapBootSector[slot] = TRUE;
  2021. }
  2022. //
  2023. // Find the previous region (ie, the one that points to this one).
  2024. // This region (if it exists) will be partitioned space (otherwise
  2025. // it would have been part of the region we are trying to create
  2026. // a partition in!)
  2027. //
  2028. pRegionHead = InExtended ? &pDisk->ExtendedDiskRegions : &pDisk->PrimaryDiskRegions;
  2029. if(*pRegionHead == pRegion) {
  2030. pRegionPrev = NULL;
  2031. } else {
  2032. for(pRegionPrev = *pRegionHead; pRegionPrev; pRegionPrev = pRegionPrev->Next) {
  2033. if(pRegionPrev->Next == pRegion) {
  2034. ASSERT(pRegionPrev->PartitionedSpace);
  2035. break;
  2036. }
  2037. }
  2038. }
  2039. if(InExtended) {
  2040. PMBR_INFO PrevEbr;
  2041. //
  2042. // The new logical drive goes immediately after the
  2043. // previous logical drive (if any). Remember that if there is
  2044. // a previous region, it will be partitioned space (otherwise
  2045. // it would be a part of the region we are trying to create
  2046. // a partition in).
  2047. //
  2048. PrevEbr = pRegionPrev ? pRegionPrev->MbrInfo : NULL;
  2049. if(PrevEbr) {
  2050. pBrInfo->Next = PrevEbr->Next;
  2051. PrevEbr->Next = pBrInfo;
  2052. } else {
  2053. //
  2054. // No previous EBR or region. This means we are creating
  2055. // a logical drive at the beginning of the extended partition
  2056. // so set the First Ebr pointer to point to the new Ebr.
  2057. // Note that this does not mean that the extended partition
  2058. // is empty; the Next pointer in the new Ebr structure is
  2059. // set later.
  2060. //
  2061. pDisk->FirstEbrInfo.Next = pBrInfo;
  2062. if(pRegion->Next) {
  2063. //
  2064. // If there is a region following the one we're creating
  2065. // the partition in, it must be partitioned space, or else
  2066. // it would be part of the region we're creating the partition in.
  2067. //
  2068. ASSERT(pRegion->Next->PartitionedSpace);
  2069. ASSERT(pRegion->Next->MbrInfo);
  2070. pBrInfo->Next = pRegion->Next->MbrInfo;
  2071. } else {
  2072. //
  2073. // No more partitioned space in the extended partition;
  2074. // the logical drive we are creating is the only one.
  2075. //
  2076. pBrInfo->Next = NULL;
  2077. }
  2078. }
  2079. pBrInfo->OnDiskSector = AlignedStartSector;
  2080. //
  2081. // Create a link entry in the previous logical drive (if any).
  2082. //
  2083. if(PrevEbr) {
  2084. //
  2085. // If there is a link entry in there already, blow it away.
  2086. //
  2087. for(i=0; i<PTABLE_DIMENSION; i++) {
  2088. if(IsContainerPartition(PrevEbr->OnDiskMbr.PartitionTable[i].SystemId)) {
  2089. RtlZeroMemory(&PrevEbr->OnDiskMbr.PartitionTable[i],sizeof(ON_DISK_PTE));
  2090. PrevEbr->Dirty[i] = TRUE;
  2091. break;
  2092. }
  2093. }
  2094. //
  2095. // Find a free slot for the link entry.
  2096. //
  2097. for(i=0; i<PTABLE_DIMENSION; i++) {
  2098. pte = &PrevEbr->OnDiskMbr.PartitionTable[i];
  2099. if(pte->SystemId == PARTITION_ENTRY_UNUSED) {
  2100. pte->SystemId = PARTITION_EXTENDED;
  2101. pte->ActiveFlag = 0;
  2102. U_ULONG(pte->RelativeSectors) = (ULONG)(AlignedStartSector - ExtendedStart);
  2103. U_ULONG(pte->SectorCount) = (ULONG)(AlignedEndSector - AlignedStartSector);
  2104. SpPtInitializeCHSFields(
  2105. pDisk->HardDisk,
  2106. AlignedStartSector,
  2107. U_ULONG(pte->SectorCount),
  2108. pte
  2109. );
  2110. PrevEbr->Dirty[i] = TRUE;
  2111. break;
  2112. }
  2113. }
  2114. }
  2115. //
  2116. // Create a link entry in this new logical drive if necessary.
  2117. //
  2118. if(pBrInfo->Next) {
  2119. //
  2120. // Find the next entry's logical drive.
  2121. //
  2122. for(i=0; i<PTABLE_DIMENSION; i++) {
  2123. if((pBrInfo->Next->OnDiskMbr.PartitionTable[i].SystemId != PARTITION_ENTRY_UNUSED)
  2124. && !IsContainerPartition(pBrInfo->Next->OnDiskMbr.PartitionTable[i].SystemId))
  2125. {
  2126. pte = &pBrInfo->OnDiskMbr.PartitionTable[1];
  2127. pte->SystemId = PARTITION_EXTENDED;
  2128. pte->ActiveFlag = 0;
  2129. U_ULONG(pte->RelativeSectors) = (ULONG)(pBrInfo->Next->OnDiskSector - ExtendedStart);
  2130. U_ULONG(pte->SectorCount) = U_ULONG(pBrInfo->Next->OnDiskMbr.PartitionTable[i].RelativeSectors)
  2131. + U_ULONG(pBrInfo->Next->OnDiskMbr.PartitionTable[i].SectorCount);
  2132. SpPtInitializeCHSFields(
  2133. pDisk->HardDisk,
  2134. pBrInfo->Next->OnDiskSector,
  2135. U_ULONG(pte->SectorCount),
  2136. pte
  2137. );
  2138. break;
  2139. }
  2140. }
  2141. }
  2142. }
  2143. //
  2144. // If we just created a new extended partition, we need to
  2145. // create a blank region descriptor for it in the extended region list.
  2146. //
  2147. if(!InExtended && IsContainerPartition(SysId)) {
  2148. ASSERT(pDisk->ExtendedDiskRegions == NULL);
  2149. pDisk->ExtendedDiskRegions = SpPtAllocateDiskRegionStructure(
  2150. DiskNumber,
  2151. AlignedStartSector,
  2152. AlignedEndSector - AlignedStartSector,
  2153. FALSE,
  2154. NULL,
  2155. 0
  2156. );
  2157. ASSERT(pDisk->ExtendedDiskRegions);
  2158. }
  2159. //
  2160. // Create a new disk region for the new free space at the
  2161. // beginning and end of the free space, if any.
  2162. //
  2163. if(AlignedStartSector - pRegion->StartSector) {
  2164. pRegionNew = SpPtAllocateDiskRegionStructure(
  2165. DiskNumber,
  2166. pRegion->StartSector,
  2167. AlignedStartSector - pRegion->StartSector,
  2168. FALSE,
  2169. NULL,
  2170. 0
  2171. );
  2172. ASSERT(pRegionNew);
  2173. if(pRegionPrev) {
  2174. pRegionPrev->Next = pRegionNew;
  2175. } else {
  2176. *pRegionHead = pRegionNew;
  2177. }
  2178. pRegionNew->Next = pRegion;
  2179. }
  2180. if(pRegion->StartSector + pRegion->SectorCount - AlignedEndSector) {
  2181. pRegionNew = SpPtAllocateDiskRegionStructure(
  2182. DiskNumber,
  2183. AlignedEndSector,
  2184. pRegion->StartSector + pRegion->SectorCount - AlignedEndSector,
  2185. FALSE,
  2186. NULL,
  2187. 0
  2188. );
  2189. pRegionNew->Next = pRegion->Next;
  2190. pRegion->Next = pRegionNew;
  2191. }
  2192. //
  2193. // Adjust the current disk region.
  2194. //
  2195. pRegion->StartSector = AlignedStartSector;
  2196. pRegion->SectorCount = AlignedEndSector - AlignedStartSector;
  2197. pRegion->PartitionedSpace = TRUE;
  2198. pRegion->TablePosition = slot;
  2199. pRegion->MbrInfo = pBrInfo;
  2200. pRegion->VolumeLabel[0] = 0;
  2201. pRegion->Filesystem = FilesystemNewlyCreated;
  2202. pRegion->FreeSpaceKB = (ULONG)(-1);
  2203. pRegion->AdjustedFreeSpaceKB = (ULONG)(-1);
  2204. SpFormatMessage(
  2205. pRegion->TypeName,
  2206. sizeof(pRegion->TypeName),
  2207. SP_TEXT_FS_NAME_BASE + pRegion->Filesystem
  2208. );
  2209. SpPtCommitChanges(DiskNumber,(PUCHAR)&i);
  2210. //
  2211. // Adjust partition ordinals on this disk.
  2212. //
  2213. SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE);
  2214. //
  2215. // Get the nt pathname for this region.
  2216. //
  2217. if (!IsContainerPartition(SysId)) {
  2218. SpNtNameFromRegion(
  2219. pRegion,
  2220. TemporaryBuffer,
  2221. sizeof(TemporaryBuffer),
  2222. PartitionOrdinalCurrent
  2223. );
  2224. //
  2225. // Assign a drive letter for this region
  2226. //
  2227. if (!SpDrEnabled()) {
  2228. pRegion->DriveLetter = SpGetDriveLetter( TemporaryBuffer, NULL );
  2229. if (pRegion->DriveLetter == 0) {
  2230. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpGetDriveLetter failed on %ls\n", TemporaryBuffer));
  2231. } else {
  2232. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Partition = %ls (%ls), DriveLetter = %wc: \n", TemporaryBuffer, (InExtended)? L"Extended" : L"Primary", pRegion->DriveLetter));
  2233. }
  2234. }
  2235. }
  2236. return(TRUE);
  2237. }
  2238. BOOLEAN
  2239. SpPtDelete(
  2240. IN ULONG DiskNumber,
  2241. IN ULONGLONG StartSector
  2242. )
  2243. {
  2244. PPARTITIONED_DISK pDisk;
  2245. PDISK_REGION pRegion,pRegionPrev,*pRegionHead,pRegionNext;
  2246. BOOLEAN InExtended;
  2247. PON_DISK_PTE pte;
  2248. PMBR_INFO pEbrPrev,pEbr;
  2249. ULONG i,j;
  2250. PHARD_DISK pHardDisk;
  2251. ULONG PartitionOrdinal;
  2252. NTSTATUS Status;
  2253. HANDLE Handle;
  2254. #ifdef GPT_PARTITION_ENGINE
  2255. if (SPPT_IS_GPT_DISK(DiskNumber))
  2256. return SpPtnDelete(DiskNumber, StartSector);
  2257. #endif
  2258. //
  2259. // First try to look up this region in the extended partition.
  2260. // If we can find it, assume it's a logical drive.
  2261. //
  2262. pDisk = &PartitionedDisks[DiskNumber];
  2263. pRegion = SpPtLookupRegionByStart(pDisk,TRUE,StartSector);
  2264. if(pRegion && pRegion->PartitionedSpace) {
  2265. InExtended = TRUE;
  2266. } else {
  2267. InExtended = FALSE;
  2268. pRegion = SpPtLookupRegionByStart(pDisk,FALSE,StartSector);
  2269. }
  2270. ASSERT(pRegion);
  2271. if(!pRegion) {
  2272. return(FALSE);
  2273. }
  2274. ASSERT(pRegion->PartitionedSpace);
  2275. if(!pRegion->PartitionedSpace) {
  2276. return(FALSE);
  2277. }
  2278. //
  2279. // At this point, we dismount the volume (if it's not newly created),
  2280. // so we don't run into problems later on when we go to format
  2281. //
  2282. if(pRegion->Filesystem > FilesystemNewlyCreated) {
  2283. pHardDisk = &HardDisks[pRegion->DiskNumber];
  2284. PartitionOrdinal = SpPtGetOrdinal(pRegion, PartitionOrdinalOnDisk);
  2285. //
  2286. // Open the partition for read/write access.
  2287. // This shouldn't lock the volume so we need to lock it below.
  2288. //
  2289. Status = SpOpenPartition(
  2290. pHardDisk->DevicePath,
  2291. PartitionOrdinal,
  2292. &Handle,
  2293. TRUE
  2294. );
  2295. if(!NT_SUCCESS(Status)) {
  2296. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  2297. "SETUP: SpPtDelete: unable to open %ws partition %u (%lx)\n",
  2298. pHardDisk->DevicePath,
  2299. PartitionOrdinal,
  2300. Status
  2301. ));
  2302. goto AfterDismount;
  2303. }
  2304. //
  2305. // Lock the drive.
  2306. //
  2307. Status = SpLockUnlockVolume(Handle, TRUE);
  2308. //
  2309. // We shouldn't have any file opened that would cause this volume
  2310. // to already be locked, so if we get failure (ie, STATUS_ACCESS_DENIED)
  2311. // something is really wrong. This typically indicates something is
  2312. // wrong with the hard disk that won't allow us to access it.
  2313. //
  2314. if(!NT_SUCCESS(Status)) {
  2315. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtDelete: status %lx, unable to lock drive\n", Status));
  2316. ZwClose(Handle);
  2317. goto AfterDismount;
  2318. }
  2319. //
  2320. // Dismount the drive
  2321. //
  2322. Status = SpDismountVolume(Handle);
  2323. if(!NT_SUCCESS(Status)) {
  2324. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtDelete: status %lx, unable to dismount drive\n", Status));
  2325. SpLockUnlockVolume(Handle, FALSE);
  2326. ZwClose(Handle);
  2327. goto AfterDismount;
  2328. }
  2329. //
  2330. // Unlock the drive
  2331. //
  2332. Status = SpLockUnlockVolume(Handle, FALSE);
  2333. if(!NT_SUCCESS(Status)) {
  2334. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtDelete: status %lx, unable to unlock drive\n", Status));
  2335. }
  2336. ZwClose(Handle);
  2337. }
  2338. AfterDismount:
  2339. //
  2340. // Find the previous region (ie, the one that points to this one).
  2341. //
  2342. pRegionHead = InExtended ? &pDisk->ExtendedDiskRegions : &pDisk->PrimaryDiskRegions;
  2343. if(*pRegionHead == pRegion) {
  2344. pRegionPrev = NULL;
  2345. } else {
  2346. for(pRegionPrev = *pRegionHead; pRegionPrev; pRegionPrev = pRegionPrev->Next) {
  2347. if(pRegionPrev->Next == pRegion) {
  2348. break;
  2349. }
  2350. }
  2351. }
  2352. //
  2353. // Additional processing for logical drives.
  2354. //
  2355. if(InExtended) {
  2356. //
  2357. // Locate the previous and next logical drives (if any).
  2358. //
  2359. pEbr = pRegion->MbrInfo;
  2360. for(pEbrPrev=pDisk->FirstEbrInfo.Next; pEbrPrev; pEbrPrev=pEbrPrev->Next) {
  2361. if(pEbrPrev->Next == pEbr) {
  2362. break;
  2363. }
  2364. }
  2365. //
  2366. // If there is a previous logical drive, blow aways its link
  2367. // entry, because it points to the logical drive we're deleting.
  2368. //
  2369. if(pEbrPrev) {
  2370. for(i=0; i<PTABLE_DIMENSION; i++) {
  2371. pte = &pEbrPrev->OnDiskMbr.PartitionTable[i];
  2372. if(IsContainerPartition(pte->SystemId)) {
  2373. RtlZeroMemory(pte,sizeof(ON_DISK_PTE));
  2374. pEbrPrev->Dirty[i] = TRUE;
  2375. break;
  2376. }
  2377. }
  2378. }
  2379. //
  2380. // If there is a next logical drive and a previous logical drive,
  2381. // set a new link entry in previous logical drive to point to
  2382. // the next logical drive.
  2383. //
  2384. if(pEbrPrev && pEbr->Next) {
  2385. //
  2386. // Locate the link entry in the logical drive being deleted.
  2387. //
  2388. for(i=0; i<PTABLE_DIMENSION; i++) {
  2389. if(IsContainerPartition(pEbr->OnDiskMbr.PartitionTable[i].SystemId)) {
  2390. //
  2391. // Locate an empty slot in the previous logical drive's boot record
  2392. // and copy the link entry
  2393. //
  2394. for(j=0; j<PTABLE_DIMENSION; j++) {
  2395. if(pEbrPrev->OnDiskMbr.PartitionTable[j].SystemId == PARTITION_ENTRY_UNUSED) {
  2396. //
  2397. // Copy the link entry and mark the new link entry dirty
  2398. // so it gets updated on-disk. We do this even though on the
  2399. // typical disk it will have been marked dirty above. This one here
  2400. // handles the case of a wierd situation where the type 6/7/whatever
  2401. // is in slot 0 and the link entry was in slot 2 or 3. In that case,
  2402. // the RtlZeroMemory code above will have cleaned out a slot that is
  2403. // different than the one we're using here for the new link entry.
  2404. //
  2405. RtlMoveMemory(
  2406. &pEbrPrev->OnDiskMbr.PartitionTable[j],
  2407. &pEbr->OnDiskMbr.PartitionTable[i],
  2408. sizeof(ON_DISK_PTE)
  2409. );
  2410. pEbrPrev->Dirty[j] = TRUE;
  2411. break;
  2412. }
  2413. }
  2414. break;
  2415. }
  2416. }
  2417. }
  2418. //
  2419. // Remove the EBR for this logical drive.
  2420. //
  2421. if(pEbrPrev) {
  2422. pEbrPrev->Next = pEbr->Next;
  2423. } else {
  2424. ASSERT(pDisk->FirstEbrInfo.Next == pEbr);
  2425. pDisk->FirstEbrInfo.Next = pEbr->Next;
  2426. }
  2427. SpMemFree(pEbr);
  2428. } else {
  2429. ASSERT(pRegion->MbrInfo == &pDisk->MbrInfo);
  2430. pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition];
  2431. ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
  2432. //
  2433. // Mark the entry dirty in the MBR.
  2434. //
  2435. pDisk->MbrInfo.Dirty[pRegion->TablePosition] = TRUE;
  2436. //
  2437. // If this is the extended partition, verify that it is empty.
  2438. //
  2439. if(IsContainerPartition(pte->SystemId)) {
  2440. ASSERT(pDisk->ExtendedDiskRegions);
  2441. ASSERT(pDisk->ExtendedDiskRegions->PartitionedSpace == FALSE);
  2442. ASSERT(pDisk->ExtendedDiskRegions->Next == NULL);
  2443. ASSERT(pDisk->FirstEbrInfo.Next == NULL);
  2444. if(pDisk->ExtendedDiskRegions->Next || pDisk->FirstEbrInfo.Next) {
  2445. return(FALSE);
  2446. }
  2447. //
  2448. // Free the single disk region that covers the entire extended partition.
  2449. //
  2450. SpMemFree(pDisk->ExtendedDiskRegions);
  2451. pDisk->ExtendedDiskRegions = NULL;
  2452. }
  2453. //
  2454. // Adjust the PTE for this partition by zeroing it out.
  2455. //
  2456. RtlZeroMemory(pte,sizeof(ON_DISK_PTE));
  2457. }
  2458. //
  2459. // Adjust fields in the region to describe this space as free.
  2460. //
  2461. pRegion->MbrInfo->ZapBootSector[pRegion->TablePosition] = FALSE;
  2462. pRegion->PartitionedSpace = FALSE;
  2463. pRegion->MbrInfo = NULL;
  2464. pRegion->TablePosition = 0;
  2465. pRegion->DriveLetter = L'\0';
  2466. //
  2467. // If previous region is free space, coalesce it and the region
  2468. // we just made free.
  2469. //
  2470. if(pRegionPrev && !pRegionPrev->PartitionedSpace) {
  2471. PDISK_REGION p;
  2472. ASSERT(pRegionPrev->StartSector + pRegionPrev->SectorCount == pRegion->StartSector);
  2473. pRegion->SectorCount = pRegion->StartSector + pRegion->SectorCount - pRegionPrev->StartSector;
  2474. pRegion->StartSector = pRegionPrev->StartSector;
  2475. //
  2476. // Delete the previous region.
  2477. //
  2478. if(pRegionPrev == *pRegionHead) {
  2479. //
  2480. // The previous region was the first region.
  2481. //
  2482. *pRegionHead = pRegion;
  2483. } else {
  2484. for(p = *pRegionHead; p; p=p->Next) {
  2485. if(p->Next == pRegionPrev) {
  2486. ASSERT(p->PartitionedSpace);
  2487. p->Next = pRegion;
  2488. break;
  2489. }
  2490. }
  2491. }
  2492. SpMemFree(pRegionPrev);
  2493. }
  2494. //
  2495. // If the next region is free space, coalesce it and the region
  2496. // we just made free.
  2497. //
  2498. if((pRegionNext = pRegion->Next) && !pRegionNext->PartitionedSpace) {
  2499. ASSERT(pRegion->StartSector + pRegion->SectorCount == pRegionNext->StartSector);
  2500. pRegion->SectorCount = pRegionNext->StartSector + pRegionNext->SectorCount - pRegion->StartSector;
  2501. //
  2502. // Delete the next region.
  2503. //
  2504. pRegion->Next = pRegionNext->Next;
  2505. SpMemFree(pRegionNext);
  2506. }
  2507. SpPtCommitChanges(DiskNumber,(PUCHAR)&i);
  2508. //
  2509. // Adjust the partition ordinals on this disk.
  2510. //
  2511. SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE);
  2512. //
  2513. // No need to reassign drive letters
  2514. //
  2515. return(TRUE);
  2516. }
  2517. #endif // !NEW_PARTITION_ENGINE
  2518. BOOLEAN
  2519. SpPtExtend(
  2520. IN PDISK_REGION Region,
  2521. IN ULONGLONG SizeMB OPTIONAL
  2522. )
  2523. /*++
  2524. Routine Description:
  2525. Extends a partition by claiming any free space immedately following it
  2526. on the disk. The end boundary of the existing partition is adjusted
  2527. so that the partition encompasses the free space.
  2528. The partition may not be the extended partition and it may not be
  2529. a logical drive within the extended partition.
  2530. Note that no filesystem structures are manipulated or examined by
  2531. this routine. Essentially it deals only with the partition table entry.
  2532. Arguments:
  2533. Region - supplies the region descriptor for the partition to be
  2534. extended. That partition must not be the extended partition and
  2535. it cannot be a logical drive either.
  2536. SizeMB - if specified, indicates the size in MB by which the partition
  2537. will grow. If not specified, the partition grows to encompass all
  2538. the free space in the adjacent free space.
  2539. Return Value:
  2540. Boolean value indicating whether anything actually changed.
  2541. --*/
  2542. {
  2543. PDISK_REGION NextRegion;
  2544. PPARTITIONED_DISK pDisk;
  2545. PMBR_INFO pBrInfo;
  2546. PON_DISK_PTE pte;
  2547. ULONG BytesPerSector;
  2548. ULONGLONG NewEndSector;
  2549. ULONGLONG SectorCount;
  2550. PVOID UnalignedBuffer;
  2551. PON_DISK_MBR AlignedBuffer;
  2552. HANDLE Handle;
  2553. NTSTATUS Status;
  2554. //
  2555. // We aren't going to support this anymore on NT5. It's too messy.
  2556. //
  2557. return FALSE;
  2558. /*
  2559. pDisk = &PartitionedDisks[Region->DiskNumber];
  2560. BytesPerSector = pDisk->HardDisk->Geometry.BytesPerSector;
  2561. ASSERT(Region->PartitionedSpace);
  2562. if(!Region->PartitionedSpace) {
  2563. return(FALSE);
  2564. }
  2565. pBrInfo = Region->MbrInfo;
  2566. pte = &pBrInfo->OnDiskMbr.PartitionTable[Region->TablePosition];
  2567. //
  2568. // Make sure it's not the extended partition and is not
  2569. // in the extended partition.
  2570. //
  2571. if(pBrInfo->OnDiskSector || IsContainerPartition(pte->SystemId)) {
  2572. return(FALSE);
  2573. }
  2574. //
  2575. // If there's no next region then there's nothing to do.
  2576. // If there is a next region make sure it's empty.
  2577. //
  2578. NextRegion = Region->Next;
  2579. if(!NextRegion) {
  2580. return(FALSE);
  2581. }
  2582. if(NextRegion->PartitionedSpace) {
  2583. return(FALSE);
  2584. }
  2585. //
  2586. // Convert the passed in size to a sector count.
  2587. //
  2588. if(SizeMB) {
  2589. SectorCount = SizeMB * ((1024*1024)/BytesPerSector);
  2590. if(SectorCount > NextRegion->SectorCount) {
  2591. SectorCount = NextRegion->SectorCount;
  2592. }
  2593. } else {
  2594. SectorCount = NextRegion->SectorCount;
  2595. }
  2596. //
  2597. // Claim the part of the free region we need and align the ending sector
  2598. // to a cylinder boundary.
  2599. //
  2600. NewEndSector = NextRegion->StartSector + SectorCount;
  2601. NewEndSector -= NewEndSector % pDisk->HardDisk->SectorsPerCylinder;
  2602. //
  2603. // Fix up the size and end CHS fields in the partition table entry
  2604. // for the partition.
  2605. //
  2606. U_ULONG(pte->SectorCount) = NewEndSector - Region->StartSector;
  2607. SpPtInitializeCHSFields(
  2608. pDisk->HardDisk,
  2609. Region->StartSector,
  2610. NewEndSector - Region->StartSector,
  2611. pte
  2612. );
  2613. //pBrInfo->Dirty[Region->TablePosition] = TRUE;
  2614. //
  2615. // If there is space left over at the end of the free region
  2616. // we just stuck onto the end of the existing partition,
  2617. // adjust the free region's descriptor. Else get rid of it.
  2618. //
  2619. if(NextRegion->StartSector + NextRegion->SectorCount == NewEndSector) {
  2620. Region->Next = NextRegion->Next;
  2621. SpMemFree(NextRegion);
  2622. } else {
  2623. NextRegion->SectorCount = NextRegion->StartSector + NextRegion->SectorCount - NewEndSector;
  2624. NextRegion->StartSector = NewEndSector;
  2625. }
  2626. //
  2627. // Now we have to something tricky. We don't want to inform the disk driver
  2628. // about what we just did because he will delete the device object for
  2629. // the partition, which causes problems the next time we hit the disk, say to
  2630. // page in part of usetup.exe to get a message. We whack the partition table
  2631. // entry directly, knowing that a) we've been called after SpPtCommitChanges
  2632. // and b) no one cares about the new size until after we've rebooted.
  2633. //
  2634. UnalignedBuffer = SpMemAlloc(2*BytesPerSector);
  2635. AlignedBuffer = ALIGN(UnalignedBuffer,BytesPerSector);
  2636. Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,TRUE);
  2637. if(NT_SUCCESS(Status)) {
  2638. Status = SpReadWriteDiskSectors(Handle,0,1,BytesPerSector,AlignedBuffer,FALSE);
  2639. if(NT_SUCCESS(Status)) {
  2640. if(!IsNEC_98) {
  2641. RtlMoveMemory(
  2642. &AlignedBuffer->PartitionTable[Region->TablePosition],
  2643. &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition],
  2644. sizeof(ON_DISK_PTE)
  2645. );
  2646. } else {
  2647. PREAL_DISK_MBR pRealBuffer = (PREAL_DISK_MBR)AlignedBuffer;
  2648. ASSERT(pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT);
  2649. SpTranslatePteInfo(
  2650. &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition],
  2651. &pRealBuffer->PartitionTable[Region->TablePosition],
  2652. TRUE
  2653. );
  2654. }
  2655. Status = SpReadWriteDiskSectors(Handle,0,1,BytesPerSector,AlignedBuffer,TRUE);
  2656. if(!NT_SUCCESS(Status)) {
  2657. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtExtend: can't write sector 0, status %lx",Status));
  2658. }
  2659. } else {
  2660. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtExtend: can't read sector 0, status %lx",Status));
  2661. }
  2662. ZwClose(Handle);
  2663. } else {
  2664. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtExtend: can't open disk, status %lx",Status));
  2665. }
  2666. SpMemFree(UnalignedBuffer);
  2667. if(!NT_SUCCESS(Status)) {
  2668. FatalPartitionUpdateError(pDisk->HardDisk->Description);
  2669. }
  2670. return(TRUE);
  2671. */
  2672. }
  2673. VOID
  2674. SpPtMarkActive(
  2675. IN ULONG TablePosition
  2676. )
  2677. /*++
  2678. Routine Description:
  2679. Mark a partition on drive 0 active, and deactivate all others.
  2680. Arguments:
  2681. TablePosition - supplies offset within partition table (0-3)
  2682. of the partition entry to be activated.
  2683. Return Value:
  2684. None.
  2685. --*/
  2686. {
  2687. ULONG i;
  2688. PON_DISK_PTE pte;
  2689. ULONG Disk0Ordinal;
  2690. ASSERT(TablePosition < PTABLE_DIMENSION);
  2691. Disk0Ordinal = SpDetermineDisk0();
  2692. //
  2693. // Deactivate all others.
  2694. //
  2695. for(i=0; i<PTABLE_DIMENSION; i++) {
  2696. pte = &PartitionedDisks[Disk0Ordinal].MbrInfo.OnDiskMbr.PartitionTable[i];
  2697. if((pte->SystemId != PARTITION_ENTRY_UNUSED)
  2698. && pte->ActiveFlag
  2699. && (i != TablePosition))
  2700. {
  2701. pte->ActiveFlag = 0;
  2702. PartitionedDisks[0].MbrInfo.Dirty[i] = TRUE;
  2703. }
  2704. }
  2705. //
  2706. // Activate the one we want to activate.
  2707. //
  2708. pte = &PartitionedDisks[Disk0Ordinal].MbrInfo.OnDiskMbr.PartitionTable[TablePosition];
  2709. ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
  2710. ASSERT(!IsContainerPartition(pte->SystemId));
  2711. // @mtp - Original ASSERT(( PartitionNameIds[pte->SystemId] == (UCHAR)(-1)) || (pte->SystemId == PARTITION_LDM));
  2712. ASSERT((PartitionNameIds[pte->SystemId] == (UCHAR)(-1)) || (pte->SystemId == PARTITION_LDM) ||
  2713. ( SpDrEnabled() &&
  2714. IsRecognizedPartition(pte->SystemId) &&
  2715. ( ((pte->SystemId & VALID_NTFT) == VALID_NTFT ) ||
  2716. ((pte->SystemId & PARTITION_NTFT) == PARTITION_NTFT)
  2717. )
  2718. )
  2719. );
  2720. if(!pte->ActiveFlag) {
  2721. pte->ActiveFlag = 0x80;
  2722. PartitionedDisks[Disk0Ordinal].MbrInfo.Dirty[TablePosition] = TRUE;
  2723. }
  2724. }
  2725. #ifndef NEW_PARTITION_ENGINE
  2726. NTSTATUS
  2727. SpPtCommitChanges(
  2728. IN ULONG DiskNumber,
  2729. OUT PBOOLEAN AnyChanges
  2730. )
  2731. {
  2732. PPARTITIONED_DISK pDisk;
  2733. ULONG DiskLayoutSize;
  2734. PDISK_REGION pRegion;
  2735. PMBR_INFO pBrInfo;
  2736. ULONG BootRecordCount;
  2737. BOOLEAN NeedDummyEbr;
  2738. PDRIVE_LAYOUT_INFORMATION DriveLayout;
  2739. PPARTITION_INFORMATION PartitionInfo;
  2740. ULONG PartitionEntry;
  2741. ULONG bps;
  2742. PON_DISK_PTE pte;
  2743. ULONGLONG ExtendedStart;
  2744. ULONGLONG Offset;
  2745. NTSTATUS Status;
  2746. HANDLE Handle;
  2747. IO_STATUS_BLOCK IoStatusBlock;
  2748. ULONG i;
  2749. ULONGLONG ZapSector;
  2750. PUCHAR Buffer,UBuffer;
  2751. ULONG NewSig;
  2752. ULONGLONG RewriteSector[PTABLE_DIMENSION]; //NEC98
  2753. ULONG cnt,RewriteCnt=0; //NEC98
  2754. #ifdef GPT_PARTITION_ENGINE
  2755. if (SPPT_IS_GPT_DISK(DiskNumber))
  2756. return SpPtnCommitChanges(DiskNumber, AnyChanges);
  2757. #endif
  2758. ASSERT(DiskNumber < HardDiskCount);
  2759. pDisk = &PartitionedDisks[DiskNumber];
  2760. *AnyChanges = FALSE;
  2761. bps = pDisk->HardDisk->Geometry.BytesPerSector;
  2762. ExtendedStart = 0;
  2763. //
  2764. // Determine the number of boot records that will used on this disk.
  2765. // There is one for the MBR, and one for each logical drive.
  2766. //
  2767. BootRecordCount = 1;
  2768. for(pRegion=pDisk->ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) {
  2769. if(pRegion->PartitionedSpace) {
  2770. BootRecordCount++;
  2771. }
  2772. }
  2773. if (IsNEC_98) { //NEC98
  2774. ZapSector = 0;
  2775. #if defined(NEC_98) //NEC98
  2776. //
  2777. // Set RealDiskPosition. This value will be valid after changing partition.
  2778. //
  2779. for(i=0,pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
  2780. if(pRegion->PartitionedSpace) {
  2781. pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].RealDiskPosition = (UCHAR)i;
  2782. i++;
  2783. }
  2784. }
  2785. #endif //NEC98
  2786. } //NEC98
  2787. //
  2788. // Determine whether a dummy boot record is rquired at the start
  2789. // of the extended partition. This is the case when there is free
  2790. // space at its start.
  2791. //
  2792. if(pDisk->ExtendedDiskRegions
  2793. && !pDisk->ExtendedDiskRegions->PartitionedSpace
  2794. && pDisk->ExtendedDiskRegions->Next)
  2795. {
  2796. NeedDummyEbr = TRUE;
  2797. BootRecordCount++;
  2798. *AnyChanges = TRUE;
  2799. } else {
  2800. NeedDummyEbr = FALSE;
  2801. }
  2802. //
  2803. // Allocate a disk layout structure whose size is based on the
  2804. // number of boot records. This assumes that the structure contains
  2805. // one partition information structure in its definition.
  2806. //
  2807. DiskLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION)
  2808. + (BootRecordCount * PTABLE_DIMENSION * sizeof(PARTITION_INFORMATION))
  2809. - sizeof(PARTITION_INFORMATION);
  2810. DriveLayout = SpMemAlloc(DiskLayoutSize);
  2811. ASSERT(DriveLayout);
  2812. RtlZeroMemory(DriveLayout,DiskLayoutSize);
  2813. //
  2814. // Set up some of the fields of the drive layout structure.
  2815. //
  2816. DriveLayout->PartitionCount =
  2817. (!IsNEC_98) ? (BootRecordCount * sizeof(PTABLE_DIMENSION))
  2818. : (BootRecordCount * PTABLE_DIMENSION); //NEC98
  2819. //
  2820. // Go through each boot record and initialize the matching
  2821. // partition information structure in the drive layout structure.
  2822. //
  2823. for(PartitionEntry=0,pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
  2824. for(i=0; i<PTABLE_DIMENSION; i++) {
  2825. pBrInfo->UserData[i] = NULL;
  2826. }
  2827. //
  2828. // If we are going to need a dummy logical drive,
  2829. // leave space for it here.
  2830. //
  2831. if(pBrInfo == &pDisk->FirstEbrInfo) {
  2832. if(NeedDummyEbr) {
  2833. PartitionEntry += PTABLE_DIMENSION;
  2834. }
  2835. continue;
  2836. }
  2837. ASSERT(PartitionEntry < BootRecordCount*PTABLE_DIMENSION);
  2838. for(i=0; i<PTABLE_DIMENSION; i++) {
  2839. //
  2840. // Point to partition information structure within
  2841. // drive layout structure.
  2842. //
  2843. PartitionInfo = &DriveLayout->PartitionEntry[PartitionEntry+i];
  2844. //
  2845. // Transfer this partition table entry
  2846. // into the drive layout structure, field by field.
  2847. //
  2848. pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
  2849. //
  2850. // If this is the extended partition, remember where it starts.
  2851. //
  2852. if((pBrInfo == &pDisk->MbrInfo)
  2853. && IsContainerPartition(pte->SystemId)
  2854. && !ExtendedStart)
  2855. {
  2856. ExtendedStart = U_ULONG(pte->RelativeSectors);
  2857. }
  2858. if(pte->SystemId != PARTITION_ENTRY_UNUSED) {
  2859. if(!IsContainerPartition(pte->SystemId)) {
  2860. pBrInfo->UserData[i] = PartitionInfo;
  2861. }
  2862. //
  2863. // Calculate starting offset. If we are within
  2864. // the extended parttion and this is a type 5 entry,
  2865. // then the relative sector field counts the number of sectors
  2866. // between the main extended partition's first sector and
  2867. // the logical drive described by this entry.
  2868. // Otherwise, the relative sectors field describes the number
  2869. // of sectors between the boot record and the actual start
  2870. // of the partition.
  2871. //
  2872. if((pBrInfo != &pDisk->MbrInfo) && IsContainerPartition(pte->SystemId)) {
  2873. ASSERT(ExtendedStart);
  2874. Offset = ExtendedStart + U_ULONG(pte->RelativeSectors);
  2875. } else {
  2876. Offset = pBrInfo->OnDiskSector + U_ULONG(pte->RelativeSectors);
  2877. }
  2878. PartitionInfo->StartingOffset.QuadPart = UInt32x32To64(Offset,bps);
  2879. //
  2880. // Calculate size.
  2881. //
  2882. PartitionInfo->PartitionLength.QuadPart = UInt32x32To64(U_ULONG(pte->SectorCount),bps);
  2883. //
  2884. // Store start offset of newly created partition to clear sector later.
  2885. //
  2886. if(IsNEC_98 && pBrInfo->Dirty[i]) {
  2887. RewriteSector[RewriteCnt++] = Offset;
  2888. }
  2889. }
  2890. //
  2891. // Other fields.
  2892. //
  2893. PartitionInfo->PartitionType = pte->SystemId;
  2894. PartitionInfo->BootIndicator = pte->ActiveFlag;
  2895. PartitionInfo->RewritePartition = pBrInfo->Dirty[i];
  2896. if(pBrInfo->Dirty[i]) {
  2897. *AnyChanges = TRUE;
  2898. }
  2899. pBrInfo->Dirty[i] = FALSE;
  2900. }
  2901. PartitionEntry += PTABLE_DIMENSION;
  2902. }
  2903. //
  2904. // If there are no changes, just return success now.
  2905. //
  2906. if(!(*AnyChanges)) {
  2907. SpMemFree(DriveLayout);
  2908. return(STATUS_SUCCESS);
  2909. }
  2910. //
  2911. // If there is free space at the start of the extended partition,
  2912. // then we need to generate a dummy boot record.
  2913. //
  2914. if(NeedDummyEbr) {
  2915. pRegion = pDisk->ExtendedDiskRegions->Next;
  2916. ASSERT(pRegion->PartitionedSpace);
  2917. ASSERT(pRegion->StartSector == pRegion->MbrInfo->OnDiskSector);
  2918. ASSERT(ExtendedStart == pDisk->ExtendedDiskRegions->StartSector);
  2919. PartitionInfo = &DriveLayout->PartitionEntry[PTABLE_DIMENSION];
  2920. PartitionInfo->StartingOffset.QuadPart = UInt32x32To64(pRegion->StartSector,bps);
  2921. PartitionInfo->PartitionLength.QuadPart = UInt32x32To64(pRegion->SectorCount,bps);
  2922. PartitionInfo->PartitionType = PARTITION_EXTENDED;
  2923. PartitionInfo->RewritePartition = TRUE;
  2924. //
  2925. // Rewrite all other entries to ensure that if there was logica drive (first in the chain)
  2926. // that was deleted, it will really go away. There won't be any effect if we overwrite a
  2927. // logical drive that didn't exist
  2928. //
  2929. for( i = 1; i < PTABLE_DIMENSION; i ++ ) {
  2930. PartitionInfo = &DriveLayout->PartitionEntry[PTABLE_DIMENSION + i];
  2931. PartitionInfo->RewritePartition = TRUE;
  2932. }
  2933. }
  2934. //
  2935. // We now have everything set up. Open partition 0 on the disk.
  2936. //
  2937. Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,TRUE);
  2938. if(!NT_SUCCESS(Status)) {
  2939. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: committing changes, unable to open disk %u (%lx)\n",DiskNumber,Status));
  2940. SpMemFree(DriveLayout);
  2941. return(Status);
  2942. }
  2943. //
  2944. // Make sure the mbr is valid before writing the changes.
  2945. // Note that we slam in new boot code whenever any changes have been made.
  2946. // We do this to guaranteee proper support for xint13 booting, etc.
  2947. //
  2948. if (!IsNEC_98) { //NEC98
  2949. //
  2950. // If MBR of target hard disk is invalid, initialize it when select target partition.
  2951. // so don't rewrite MBR now.
  2952. //
  2953. Status = SpMasterBootCode(DiskNumber,Handle,&NewSig);
  2954. if(NT_SUCCESS(Status)) {
  2955. //
  2956. // If a new NTFT signature was generated, propagate it.
  2957. //
  2958. if(NewSig) {
  2959. U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = NewSig;
  2960. }
  2961. } else {
  2962. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: committing changes on disk %u, SpMasterBootCode returns %lx\n",DiskNumber,Status));
  2963. ZwClose(Handle);
  2964. SpMemFree(DriveLayout);
  2965. return(Status);
  2966. }
  2967. } //NEC98
  2968. DriveLayout->Signature = U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature);
  2969. #if 0
  2970. //
  2971. // We dump after the call to the IOCTL because it can change some of the data in the structure,
  2972. // such as PartitionNumber
  2973. //
  2974. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dumping DriveLayout before calling IOCTL_DISK_SET_DRIVE_LAYOUT: \n"));
  2975. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionCount = %lx\n", DriveLayout->PartitionCount));
  2976. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->Signature = %lx \n\n", DriveLayout->Signature));
  2977. for(i = 0; i < DriveLayout->PartitionCount; i++) {
  2978. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].StartingOffset = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].StartingOffset.u.HighPart, DriveLayout->PartitionEntry[i].StartingOffset.u.LowPart));
  2979. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionLength = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].PartitionLength.u.HighPart, DriveLayout->PartitionEntry[i].PartitionLength.u.LowPart));
  2980. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].HiddenSectors = 0x%08lx\n", i, DriveLayout->PartitionEntry[i].HiddenSectors));
  2981. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionNumber = %d\n", i, DriveLayout->PartitionEntry[i].PartitionNumber));
  2982. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionType = 0x%02x\n", i, DriveLayout->PartitionEntry[i].PartitionType));
  2983. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].BootIndicator = %ls\n", i, DriveLayout->PartitionEntry[i].BootIndicator? L"TRUE" : L"FALSE"));
  2984. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RecognizedPartition = %ls\n", i, DriveLayout->PartitionEntry[i].RecognizedPartition? L"TRUE" : L"FALSE"));
  2985. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RewritePartition = %ls\n\n", i, DriveLayout->PartitionEntry[i].RewritePartition? L"TRUE" : L"FALSE"));
  2986. }
  2987. #endif
  2988. //
  2989. // Write the changes.
  2990. //
  2991. Status = ZwDeviceIoControlFile(
  2992. Handle,
  2993. NULL,
  2994. NULL,
  2995. NULL,
  2996. &IoStatusBlock,
  2997. IOCTL_DISK_SET_DRIVE_LAYOUT,
  2998. DriveLayout,
  2999. DiskLayoutSize,
  3000. DriveLayout,
  3001. DiskLayoutSize
  3002. );
  3003. // Deferred freeing memory till later on because we still need info in this structure (lonnym)
  3004. // SpMemFree(DriveLayout);
  3005. if(!NT_SUCCESS(Status)) {
  3006. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: committing changes on disk %u, ioctl returns %lx\n",DiskNumber,Status));
  3007. SpMemFree(DriveLayout);
  3008. ZwClose(Handle);
  3009. return(Status);
  3010. }
  3011. #if 0
  3012. //
  3013. // We dump after the call to the IOCTL because it can change some of the data in the structure,
  3014. // such as PartitionNumber
  3015. //
  3016. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Dumping DriveLayout after IOCTL_DISK_SET_DRIVE_LAYOUT was called: \n"));
  3017. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionCount = %lx\n", DriveLayout->PartitionCount));
  3018. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->Signature = %lx \n\n", DriveLayout->Signature));
  3019. for(i = 0; i < DriveLayout->PartitionCount; i++) {
  3020. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].StartingOffset = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].StartingOffset.u.HighPart, DriveLayout->PartitionEntry[i].StartingOffset.u.LowPart));
  3021. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionLength = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].PartitionLength.u.HighPart, DriveLayout->PartitionEntry[i].PartitionLength.u.LowPart));
  3022. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].HiddenSectors = 0x%08lx\n", i, DriveLayout->PartitionEntry[i].HiddenSectors));
  3023. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionNumber = %d\n", i, DriveLayout->PartitionEntry[i].PartitionNumber));
  3024. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionType = 0x%02x\n", i, DriveLayout->PartitionEntry[i].PartitionType));
  3025. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].BootIndicator = %ls\n", i, DriveLayout->PartitionEntry[i].BootIndicator? L"TRUE" : L"FALSE"));
  3026. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RecognizedPartition = %ls\n", i, DriveLayout->PartitionEntry[i].RecognizedPartition? L"TRUE" : L"FALSE"));
  3027. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RewritePartition = %ls\n\n", i, DriveLayout->PartitionEntry[i].RewritePartition? L"TRUE" : L"FALSE"));
  3028. }
  3029. #endif
  3030. //
  3031. // Allocate a buffer for zapping.
  3032. //
  3033. UBuffer = SpMemAlloc(2*bps);
  3034. ASSERT(UBuffer);
  3035. Buffer = ALIGN(UBuffer,bps);
  3036. RtlZeroMemory(Buffer,bps);
  3037. if (IsNEC_98) { //NEC98
  3038. //
  3039. // Clear 1st sector of target partition.
  3040. //
  3041. for(cnt = 0; cnt < RewriteCnt; cnt++){
  3042. Status = SpReadWriteDiskSectors(Handle,
  3043. RewriteSector[cnt],
  3044. 1,
  3045. bps,
  3046. Buffer,
  3047. TRUE);
  3048. if(!NT_SUCCESS(Status)) {
  3049. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: clear sector %lx on disk %u returned %lx\n",ZapSector,DiskNumber,Status));
  3050. SpMemFree(DriveLayout);
  3051. SpMemFree(UBuffer);
  3052. ZwClose(Handle);
  3053. return(Status);
  3054. }
  3055. }
  3056. } //NEC98
  3057. for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
  3058. for(i=0; i<PTABLE_DIMENSION; i++) {
  3059. //
  3060. // Update current partition ordinals.
  3061. //
  3062. if (IsNEC_98) {
  3063. pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
  3064. }
  3065. if ((!IsNEC_98) ? (pBrInfo->UserData[i]) :
  3066. (PVOID)(pte->SystemId != PARTITION_ENTRY_UNUSED)) { //NEC98
  3067. #if defined(NEC_98) //NEC98
  3068. PartitionInfo = (!IsNEC_98) ? (PPARTITION_INFORMATION)pBrInfo->UserData[i] :
  3069. &DriveLayout->PartitionEntry[pte->RealDiskPosition]; //NEC98
  3070. #else
  3071. PartitionInfo = (PPARTITION_INFORMATION)pBrInfo->UserData[i];
  3072. #endif
  3073. //
  3074. // The partition ordinal better be non-0!
  3075. //
  3076. if(PartitionInfo->PartitionNumber) {
  3077. //
  3078. // Update current partition ordinal.
  3079. //
  3080. pBrInfo->CurrentOrdinals[i] = (USHORT)PartitionInfo->PartitionNumber;
  3081. } else {
  3082. SpBugCheck(
  3083. SETUP_BUGCHECK_PARTITION,
  3084. PARTITIONBUG_A,
  3085. DiskNumber,
  3086. pBrInfo->CurrentOrdinals[i]
  3087. );
  3088. }
  3089. }
  3090. if (!IsNEC_98) { //NEC98
  3091. //
  3092. // If there were any newly created partitions in this boot record,
  3093. // zap their filesystem boot sectors.
  3094. //
  3095. if(pBrInfo->ZapBootSector[i]) {
  3096. //
  3097. // We shouldn't be zapping any partitions that don't exist.
  3098. //
  3099. ASSERT(pBrInfo->OnDiskMbr.PartitionTable[i].SystemId != PARTITION_ENTRY_UNUSED);
  3100. //
  3101. // This calculation is correct for partitions and logical drives.
  3102. //
  3103. ZapSector = pBrInfo->OnDiskSector
  3104. + U_ULONG(pBrInfo->OnDiskMbr.PartitionTable[i].RelativeSectors);
  3105. //
  3106. // The consequences for messing up here are so huge that a special check
  3107. // is warranted to make sure we're not clobbering the MBR.
  3108. //
  3109. ASSERT(ZapSector);
  3110. if(ZapSector) {
  3111. Status = SpReadWriteDiskSectors(
  3112. Handle,
  3113. ZapSector,
  3114. 1,
  3115. bps,
  3116. Buffer,
  3117. TRUE
  3118. );
  3119. } else {
  3120. Status = STATUS_SUCCESS;
  3121. }
  3122. if(!NT_SUCCESS(Status)) {
  3123. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: zapping sector %lx on disk %u returned %lx\n",ZapSector,DiskNumber,Status));
  3124. SpMemFree(DriveLayout);
  3125. SpMemFree(UBuffer);
  3126. ZwClose(Handle);
  3127. return(Status);
  3128. }
  3129. pBrInfo->ZapBootSector[i] = FALSE;
  3130. }
  3131. } //NEC98
  3132. }
  3133. }
  3134. SpMemFree(UBuffer);
  3135. ZwClose(Handle);
  3136. //
  3137. // Reassign on-disk ordinals (but not original ones).
  3138. //
  3139. SpPtAssignOrdinals(pDisk,FALSE,TRUE,FALSE);
  3140. if (IsNEC_98) { //NEC98
  3141. //
  3142. // If newly created partition's position is before existing partition,
  3143. // OnDiskOrdinals is not equal number of volume infomation position on NEC98
  3144. //
  3145. SpReassignOnDiskOrdinals(pDisk);
  3146. } //NEC98
  3147. SpMemFree(DriveLayout);
  3148. return(STATUS_SUCCESS);
  3149. }
  3150. #endif // ! NEW_PARTITION_ENGINE
  3151. NTSTATUS
  3152. SpMasterBootCode(
  3153. IN ULONG DiskNumber,
  3154. IN HANDLE Partition0Handle,
  3155. OUT PULONG NewNTFTSignature
  3156. )
  3157. /*++
  3158. Routine Description:
  3159. Write new master boot code onto a drive.
  3160. If the mbr has a valid signature, the existing partition table
  3161. and NTFT signature are preserved. Otherwise the partition table
  3162. is zeroed out and a new ntft signature is generated.
  3163. Arguments:
  3164. DiskNumber - supplies 0-based system ordinal for the disk.
  3165. Partition0Handle - supplies an open handle for partition 0 on
  3166. the disk. The handle must have read and write access.
  3167. NewNTFTSignature - receives a value indicating the new NTFT signature,
  3168. if one was generated and written to the disk. If 0 is received,
  3169. then a new ntft signature was not generated and written.
  3170. Return Value:
  3171. NT Status code indicating outcome.
  3172. --*/
  3173. {
  3174. NTSTATUS Status;
  3175. ULONG BytesPerSector;
  3176. PUCHAR Buffer;
  3177. ULONG SectorCount;
  3178. PON_DISK_MBR Mbr;
  3179. BytesPerSector = HardDisks[DiskNumber].Geometry.BytesPerSector;
  3180. SectorCount = max(1,sizeof(ON_DISK_MBR)/BytesPerSector);
  3181. *NewNTFTSignature = 0;
  3182. //
  3183. // Allocate and align a buffer.
  3184. //
  3185. Buffer = SpMemAlloc(2 * SectorCount * BytesPerSector);
  3186. Mbr = ALIGN(Buffer,BytesPerSector);
  3187. //
  3188. // Read mbr
  3189. //
  3190. Status = SpReadWriteDiskSectors(
  3191. Partition0Handle,
  3192. (HardDisks[DiskNumber].Int13Hooker == HookerEZDrive) ? 1 : 0,
  3193. SectorCount,
  3194. BytesPerSector,
  3195. Mbr,
  3196. FALSE
  3197. );
  3198. if(NT_SUCCESS(Status)) {
  3199. if(U_USHORT(Mbr->AA55Signature) == MBR_SIGNATURE) {
  3200. //
  3201. // Valid. Slam in new boot code if there's no int13 hooker.
  3202. //
  3203. if(HardDisks[DiskNumber].Int13Hooker == NoHooker) {
  3204. ASSERT(&((PON_DISK_MBR)0)->BootCode == 0);
  3205. RtlMoveMemory(Mbr,x86BootCode,sizeof(Mbr->BootCode));
  3206. Status = SpReadWriteDiskSectors(
  3207. Partition0Handle,
  3208. 0,
  3209. SectorCount,
  3210. BytesPerSector,
  3211. Mbr,
  3212. TRUE
  3213. );
  3214. }
  3215. } else {
  3216. //
  3217. // Invalid. Construct a boot sector.
  3218. //
  3219. ASSERT(X86BOOTCODE_SIZE == sizeof(ON_DISK_MBR));
  3220. RtlMoveMemory(Mbr,x86BootCode,X86BOOTCODE_SIZE);
  3221. *NewNTFTSignature = SpComputeSerialNumber();
  3222. U_ULONG(Mbr->NTFTSignature) = *NewNTFTSignature;
  3223. U_USHORT(Mbr->AA55Signature) = MBR_SIGNATURE;
  3224. //
  3225. // Write the sector(s).
  3226. //
  3227. Status = SpReadWriteDiskSectors(
  3228. Partition0Handle,
  3229. (HardDisks[DiskNumber].Int13Hooker == HookerEZDrive) ? 1 : 0,
  3230. SectorCount,
  3231. BytesPerSector,
  3232. Mbr,
  3233. TRUE
  3234. );
  3235. if (NT_SUCCESS(Status)) {
  3236. PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber);
  3237. Disk->Signature = Disk->DriveLayout.Mbr.Signature = *NewNTFTSignature;
  3238. }
  3239. }
  3240. }
  3241. SpMemFree(Buffer);
  3242. return(Status);
  3243. }
  3244. #ifndef NEW_PARTITION_ENGINE
  3245. VOID
  3246. SpPtGetSectorLayoutInformation(
  3247. IN PDISK_REGION Region,
  3248. OUT PULONGLONG HiddenSectors,
  3249. OUT PULONGLONG VolumeSectorCount
  3250. )
  3251. /*++
  3252. Routine Description:
  3253. Given a region describing a partition or logical drive, return information
  3254. about its layout on disk appropriate for the BPB when the volume is
  3255. formatted.
  3256. Arguments:
  3257. Region - supplies a pointer to the disk region descriptor for the
  3258. partition or logical drive in question.
  3259. HiidenSectors - receives the value that should be placed in the
  3260. hidden sectors field of the BPB when the volume is formatted.
  3261. HiidenSectors - receives the value that should be placed in the
  3262. sector count field of the BPB when the volume is formatted.
  3263. Return Value:
  3264. None.
  3265. --*/
  3266. {
  3267. PON_DISK_PTE pte;
  3268. #ifdef GPT_PARTITION_ENGINE
  3269. if (SPPT_IS_GPT_DISK(Region->DiskNumber)) {
  3270. SpPtnGetSectorLayoutInformation(Region,
  3271. HiddenSectors,
  3272. VolumeSectorCount);
  3273. return;
  3274. }
  3275. #endif
  3276. ASSERT(Region->PartitionedSpace);
  3277. pte = &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition];
  3278. *HiddenSectors = U_ULONG(pte->RelativeSectors);
  3279. *VolumeSectorCount = U_ULONG(pte->SectorCount);
  3280. }
  3281. ULONG
  3282. SpPtGetOrdinal(
  3283. IN PDISK_REGION Region,
  3284. IN PartitionOrdinalType OrdinalType
  3285. )
  3286. {
  3287. ULONG ord;
  3288. #ifdef GPT_PARTITION_ENGINE
  3289. if (SPPT_IS_GPT_DISK(Region->DiskNumber))
  3290. return SpPtnGetOrdinal(Region, OrdinalType);
  3291. #endif
  3292. if(Region->PartitionedSpace && (!Region->DynamicVolume || Region->MbrInfo) ) {
  3293. //
  3294. // This is either a basic volume, or a dynamic volume that is listed on the MBR/EBR
  3295. //
  3296. switch(OrdinalType) {
  3297. case PartitionOrdinalOriginal:
  3298. ord = Region->MbrInfo->OriginalOrdinals[Region->TablePosition];
  3299. break;
  3300. case PartitionOrdinalOnDisk:
  3301. ord = Region->MbrInfo->OnDiskOrdinals[Region->TablePosition];
  3302. break;
  3303. case PartitionOrdinalCurrent:
  3304. ord = Region->MbrInfo->CurrentOrdinals[Region->TablePosition];
  3305. break;
  3306. }
  3307. } else {
  3308. //
  3309. // Dynamic volume that is not listed on MBR or EBR
  3310. //
  3311. ord = Region->TablePosition;
  3312. }
  3313. return(ord);
  3314. }
  3315. #endif // NEW_PARTITION_ENGINE
  3316. #define MENU_LEFT_X 3
  3317. #define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
  3318. #define MENU_INDENT 4
  3319. BOOLEAN
  3320. SpPtRegionDescription(
  3321. IN PPARTITIONED_DISK pDisk,
  3322. IN PDISK_REGION pRegion,
  3323. OUT PWCHAR Buffer,
  3324. IN ULONG BufferSize
  3325. )
  3326. {
  3327. WCHAR DriveLetter[3];
  3328. ULONGLONG RegionSizeMB;
  3329. ULONGLONG FreeSpace;
  3330. ULONG MessageId;
  3331. WCHAR TypeName[((sizeof(pRegion->TypeName)+sizeof(pRegion->VolumeLabel))/sizeof(WCHAR))+4];
  3332. BOOLEAN NewDescription = FALSE;
  3333. //
  3334. // Get the size of the region.
  3335. //
  3336. RegionSizeMB = SpPtSectorCountToMB(pDisk->HardDisk, pRegion->SectorCount);
  3337. //
  3338. // Don't show spaces smaller than 1 MB.
  3339. //
  3340. if(!RegionSizeMB) {
  3341. return(FALSE);
  3342. }
  3343. //
  3344. // Get the drive letter field, type of region, and amount of free space,
  3345. // if this is a used region.
  3346. //
  3347. if(pRegion->PartitionedSpace) {
  3348. if(pRegion->DriveLetter) {
  3349. if( pRegion->Filesystem != FilesystemFat ) {
  3350. DriveLetter[0] = pRegion->DriveLetter;
  3351. } else {
  3352. if( pRegion->NextCompressed == NULL ) {
  3353. DriveLetter[0] = pRegion->DriveLetter;
  3354. } else {
  3355. DriveLetter[0] = pRegion->HostDrive;
  3356. }
  3357. }
  3358. DriveLetter[1] = L':';
  3359. } else {
  3360. if( pRegion->Filesystem != FilesystemDoubleSpace ) {
  3361. DriveLetter[0] = L'-';
  3362. DriveLetter[1] = L'-';
  3363. } else {
  3364. DriveLetter[0] = pRegion->MountDrive;
  3365. DriveLetter[1] = L':';
  3366. }
  3367. }
  3368. DriveLetter[2] = 0;
  3369. #ifdef NEW_PARTITION_ENGINE
  3370. NewDescription = TRUE;
  3371. #endif
  3372. #ifdef GPT_PARTITION_ENGINE
  3373. if (SPPT_IS_GPT_DISK(pRegion->DiskNumber)) {
  3374. NewDescription = TRUE;
  3375. } else {
  3376. NewDescription = FALSE;
  3377. }
  3378. #endif
  3379. //
  3380. // Format the partition name
  3381. //
  3382. TypeName[0] = 0;
  3383. if (SPPT_IS_REGION_PARTITIONED(pRegion)) {
  3384. SpPtnGetPartitionName(pRegion,
  3385. TypeName,
  3386. sizeof(TypeName) / sizeof(TypeName[0]));
  3387. } else {
  3388. swprintf( TypeName,
  3389. L"\\Harddisk%u\\Partition%u",
  3390. pRegion->DiskNumber,
  3391. pRegion->PartitionNumber );
  3392. }
  3393. //
  3394. // Format the text based on whether we know the amount of free space.
  3395. //
  3396. if(pRegion->FreeSpaceKB == (ULONG)(-1)) {
  3397. SpFormatMessage(
  3398. Buffer,
  3399. BufferSize,
  3400. SP_TEXT_REGION_DESCR_2,
  3401. DriveLetter,
  3402. SplangPadString(-35,TypeName),
  3403. (ULONG)RegionSizeMB
  3404. );
  3405. } else {
  3406. ULONGLONG AuxFreeSpaceKB;
  3407. AuxFreeSpaceKB = (pRegion->IsLocalSource)? pRegion->AdjustedFreeSpaceKB :
  3408. pRegion->FreeSpaceKB;
  3409. //
  3410. // If there is less than 1 meg of free space,
  3411. // then use KB as the units for free space.
  3412. // Otherwise, use MB.
  3413. //
  3414. if(AuxFreeSpaceKB < 1024) {
  3415. MessageId = SP_TEXT_REGION_DESCR_1a;
  3416. FreeSpace = AuxFreeSpaceKB;
  3417. } else {
  3418. MessageId = SP_TEXT_REGION_DESCR_1;
  3419. FreeSpace = AuxFreeSpaceKB / 1024;
  3420. //
  3421. // Make sure we don't look bad...
  3422. //
  3423. if( FreeSpace > RegionSizeMB ) {
  3424. FreeSpace = RegionSizeMB;
  3425. }
  3426. }
  3427. SpFormatMessage(
  3428. Buffer,
  3429. BufferSize,
  3430. MessageId,
  3431. DriveLetter,
  3432. SplangPadString(-35,TypeName),
  3433. (ULONG)RegionSizeMB,
  3434. (ULONG)FreeSpace
  3435. );
  3436. }
  3437. } else {
  3438. //
  3439. // Not a used region, use a separate format string.
  3440. //
  3441. SpFormatMessage(Buffer,
  3442. BufferSize,
  3443. SP_TEXT_REGION_DESCR_3,
  3444. (ULONG)RegionSizeMB);
  3445. }
  3446. return(TRUE);
  3447. }
  3448. BOOLEAN
  3449. SpPtIterateRegionList(
  3450. IN PVOID Menu,
  3451. IN PPARTITIONED_DISK pDisk,
  3452. IN PDISK_REGION pRegion,
  3453. IN BOOLEAN InMbr,
  3454. OUT PDISK_REGION *FirstRegion
  3455. )
  3456. {
  3457. WCHAR Buffer[256];
  3458. #ifdef FULL_DOUBLE_SPACE_SUPPORT
  3459. PDISK_REGION Pointer;
  3460. #endif // FULL_DOUBLE_SPACE_SUPPORT
  3461. Buffer[0] = UNICODE_NULL;
  3462. for( ;pRegion; pRegion=pRegion->Next) {
  3463. PMBR_INFO pBrInfo = pRegion->MbrInfo;
  3464. //
  3465. // If this is the extended partition,
  3466. // iterate its contents now.
  3467. //
  3468. if(pRegion->PartitionedSpace
  3469. && IsContainerPartition(pBrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId))
  3470. {
  3471. //
  3472. // This better be in the MBR!
  3473. //
  3474. ASSERT(InMbr);
  3475. if(!SpPtIterateRegionList(Menu,pDisk,pDisk->ExtendedDiskRegions,FALSE,FirstRegion)) {
  3476. return(FALSE);
  3477. }
  3478. } else {
  3479. //
  3480. // Format a description of this region and add it to the menu.
  3481. //
  3482. if(SpPtRegionDescription(pDisk,pRegion,Buffer,sizeof(Buffer))) {
  3483. if(*FirstRegion == NULL) {
  3484. *FirstRegion = pRegion;
  3485. }
  3486. if(!SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),TRUE,(ULONG_PTR)pRegion)) {
  3487. return(FALSE);
  3488. }
  3489. #ifdef FULL_DOUBLE_SPACE_SUPPORT
  3490. if( ( pRegion->Filesystem == FilesystemFat ) &&
  3491. ( ( Pointer = pRegion->NextCompressed ) != NULL ) ) {
  3492. for( ; Pointer;
  3493. Pointer = Pointer->NextCompressed ) {
  3494. if(SpPtRegionDescription(pDisk,Pointer,Buffer,sizeof(Buffer))) {
  3495. if(!SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),TRUE,(ULONG)Pointer)) {
  3496. return(FALSE);
  3497. }
  3498. }
  3499. }
  3500. }
  3501. #endif // FULL_DOUBLE_SPACE_SUPPORT
  3502. }
  3503. }
  3504. }
  3505. return(TRUE);
  3506. }
  3507. BOOLEAN
  3508. SpPtGenerateMenu(
  3509. IN PVOID Menu,
  3510. IN PPARTITIONED_DISK pDisk,
  3511. OUT PDISK_REGION *FirstRegion
  3512. )
  3513. {
  3514. WCHAR Buffer[256];
  3515. //
  3516. // Add the disk name/description.
  3517. //
  3518. if(!SpMnAddItem(Menu,pDisk->HardDisk->Description,MENU_LEFT_X,MENU_WIDTH,FALSE,0)) {
  3519. return(FALSE);
  3520. }
  3521. //
  3522. // Only add a line between the disk anme and partitions if we have space on
  3523. // the screen. Not fatal if the space can't be added.
  3524. //
  3525. if(!SplangQueryMinimizeExtraSpacing()) {
  3526. SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0);
  3527. }
  3528. //
  3529. // If the disk is off-line, add a message indicating such.
  3530. //
  3531. // Also disallow installation or create/delete partition into
  3532. // removable meida on NEC98. Because NT cannot boot from it.
  3533. //
  3534. if(pDisk->HardDisk->Status == DiskOffLine) {
  3535. SpFormatMessage(
  3536. Buffer,
  3537. sizeof(Buffer),
  3538. (pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)
  3539. ? (!IsNEC_98 ? SP_TEXT_HARD_DISK_NO_MEDIA : SP_TEXT_DISK_OFF_LINE)
  3540. : SP_TEXT_DISK_OFF_LINE
  3541. );
  3542. return(SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),FALSE,0));
  3543. }
  3544. #if 0
  3545. else if(IsNEC_98 && (pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)) {
  3546. SpFormatMessage(Buffer,sizeof(Buffer),SP_TEXT_DISK_OFF_LINE);
  3547. return(SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),FALSE,0));
  3548. }
  3549. #endif //0
  3550. if(!SpPtIterateRegionList(Menu,pDisk,pDisk->PrimaryDiskRegions,TRUE,FirstRegion)) {
  3551. return(FALSE);
  3552. }
  3553. return(SplangQueryMinimizeExtraSpacing() ? TRUE : SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0));
  3554. }
  3555. //
  3556. // We will change item #0 in the array below as appropriate for
  3557. // the currently highlighted region.
  3558. //
  3559. ULONG PartitionMnemonics[4] = {0};
  3560. VOID
  3561. SpPtMenuCallback(
  3562. IN ULONG_PTR UserData
  3563. )
  3564. {
  3565. if (UserData){
  3566. PDISK_REGION pRegion = (PDISK_REGION)UserData;
  3567. //
  3568. // Don't allow deletion of the partition if the 'partition' is really
  3569. // a DoubleSpace drive.
  3570. //
  3571. if(pRegion->Filesystem == FilesystemDoubleSpace) {
  3572. PartitionMnemonics[0] = 0;
  3573. if (ConsoleRunning) {
  3574. SpDisplayStatusOptions(
  3575. DEFAULT_STATUS_ATTRIBUTE,
  3576. SP_STAT_ESC_EQUALS_CANCEL,
  3577. 0
  3578. );
  3579. } else {
  3580. SpDisplayStatusOptions(
  3581. DEFAULT_STATUS_ATTRIBUTE,
  3582. SP_STAT_ENTER_EQUALS_INSTALL,
  3583. SP_STAT_F3_EQUALS_EXIT,
  3584. 0
  3585. );
  3586. }
  3587. } else {
  3588. PHARD_DISK Disk = SPPT_GET_HARDDISK(pRegion->DiskNumber);
  3589. BOOLEAN FlipStyle = FALSE;
  3590. BOOLEAN MakeSysPart = FALSE;
  3591. FilesystemType FsType = pRegion->Filesystem;
  3592. #ifndef OLD_PARTITION_ENGINE
  3593. FlipStyle = SpPtnIsDiskStyleChangeAllowed(pRegion->DiskNumber);
  3594. #endif
  3595. //
  3596. // If it is a Reserved (MSR/OEM) partition on a GPT disk do not provide an option of deleting
  3597. // it unless we are in Recovery Console
  3598. //
  3599. // NOTE: Here we do not check for IA64 specifically as this change is with respect to
  3600. // GPT disks having reserved partitions and potentially even X86 machines can have
  3601. // GPT disks in the future and we need to block installation to their reserved partitions.
  3602. //
  3603. PartitionMnemonics[0] = pRegion->PartitionedSpace ?
  3604. ((SPPT_IS_REGION_RESERVED_GPT_PARTITION(pRegion) && !ForceConsole) ?
  3605. 0 : MnemonicDeletePartition) : MnemonicCreatePartition;
  3606. PartitionMnemonics[1] = FlipStyle ? MnemonicChangeDiskStyle : 0;
  3607. #ifdef NEW_PARTITION_ENGINE
  3608. if (SPPT_IS_REGION_SYSTEMPARTITION(pRegion)) {
  3609. ValidArcSystemPartition = TRUE;
  3610. }
  3611. if (!ValidArcSystemPartition && !FlipStyle && SpIsArc() &&
  3612. (FsType != FilesystemNtfs) && SpPtnIsValidESPPartition(pRegion)) {
  3613. //
  3614. // Need to allow conversion to system partition
  3615. //
  3616. MakeSysPart = TRUE;
  3617. PartitionMnemonics[1] = MnemonicMakeSystemPartition;
  3618. }
  3619. #endif
  3620. if (ConsoleRunning) {
  3621. if (MakeSysPart) {
  3622. SpDisplayStatusOptions(
  3623. DEFAULT_STATUS_ATTRIBUTE,
  3624. SP_STAT_ESC_EQUALS_CANCEL,
  3625. pRegion->PartitionedSpace ?
  3626. SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION,
  3627. SP_STAT_M_EQUALS_MAKE_SYSPART,
  3628. FlipStyle ? SP_STAT_S_EQUALS_CHANGE_DISK_STYLE : 0,
  3629. 0
  3630. );
  3631. } else {
  3632. SpDisplayStatusOptions(
  3633. DEFAULT_STATUS_ATTRIBUTE,
  3634. SP_STAT_ESC_EQUALS_CANCEL,
  3635. pRegion->PartitionedSpace ?
  3636. SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION,
  3637. FlipStyle ? SP_STAT_S_EQUALS_CHANGE_DISK_STYLE : 0,
  3638. 0
  3639. );
  3640. }
  3641. } else {
  3642. if (FlipStyle) {
  3643. SpDisplayStatusOptions(
  3644. DEFAULT_STATUS_ATTRIBUTE,
  3645. SP_STAT_ENTER_EQUALS_INSTALL,
  3646. pRegion->PartitionedSpace ?
  3647. SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION,
  3648. SP_STAT_S_EQUALS_CHANGE_DISK_STYLE,
  3649. SP_STAT_F3_EQUALS_EXIT,
  3650. 0
  3651. );
  3652. } else {
  3653. if (MakeSysPart) {
  3654. SpDisplayStatusOptions(
  3655. DEFAULT_STATUS_ATTRIBUTE,
  3656. SP_STAT_ENTER_EQUALS_INSTALL,
  3657. pRegion->PartitionedSpace ?
  3658. SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION,
  3659. SP_STAT_M_EQUALS_MAKE_SYSPART,
  3660. SP_STAT_F3_EQUALS_EXIT,
  3661. 0
  3662. );
  3663. } else {
  3664. //
  3665. // If it is a reserved partition (GPT (MSR/OEM)) partition do not display an option
  3666. // for deleting it unless we are in Recovery Console
  3667. //
  3668. SpDisplayStatusOptions(
  3669. DEFAULT_STATUS_ATTRIBUTE,
  3670. SP_STAT_ENTER_EQUALS_INSTALL,
  3671. pRegion->PartitionedSpace ?
  3672. ((SPPT_IS_REGION_RESERVED_GPT_PARTITION(pRegion) && !ForceConsole) ?
  3673. SP_EMPTY_OPTION : SP_STAT_D_EQUALS_DELETE_PARTITION) :
  3674. SP_STAT_C_EQUALS_CREATE_PARTITION,
  3675. SP_STAT_F3_EQUALS_EXIT,
  3676. 0
  3677. );
  3678. }
  3679. }
  3680. }
  3681. }
  3682. }
  3683. }
  3684. BOOLEAN
  3685. SpPtIsNotReservedPartition(
  3686. IN ULONG_PTR UserData,
  3687. IN ULONG Key
  3688. )
  3689. {
  3690. BOOLEAN Result = TRUE;
  3691. if ((ASCI_CR == Key) &&
  3692. (NULL != (PDISK_REGION)UserData) &&
  3693. (SPPT_IS_REGION_RESERVED_GPT_PARTITION((PDISK_REGION)UserData))) {
  3694. Result = FALSE;
  3695. }
  3696. return Result;
  3697. }
  3698. void
  3699. SpEnumerateDiskRegions(
  3700. IN PSPENUMERATEDISKREGIONS EnumRoutine,
  3701. IN ULONG_PTR Context
  3702. )
  3703. {
  3704. ULONG DiskNo;
  3705. PDISK_REGION pThisRegion;
  3706. for(DiskNo=0; (DiskNo<HardDiskCount); DiskNo++) {
  3707. for(pThisRegion=PartitionedDisks[DiskNo].PrimaryDiskRegions; pThisRegion; pThisRegion=pThisRegion->Next) {
  3708. if (!EnumRoutine( &PartitionedDisks[DiskNo], pThisRegion, Context )) {
  3709. return;
  3710. }
  3711. }
  3712. for(pThisRegion=PartitionedDisks[DiskNo].ExtendedDiskRegions; pThisRegion; pThisRegion=pThisRegion->Next) {
  3713. if (!EnumRoutine( &PartitionedDisks[DiskNo], pThisRegion, Context )) {
  3714. return;
  3715. }
  3716. }
  3717. }
  3718. }
  3719. #if DBG
  3720. void
  3721. SpPtDumpPartitionData(
  3722. void
  3723. )
  3724. {
  3725. ULONG DiskNo;
  3726. PDISK_REGION pThisRegion;
  3727. for(DiskNo=0; (DiskNo<HardDiskCount); DiskNo++) {
  3728. for(pThisRegion=PartitionedDisks[DiskNo].PrimaryDiskRegions; pThisRegion; pThisRegion=pThisRegion->Next) {
  3729. if (pThisRegion->FreeSpaceKB != -1) {
  3730. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: diskno=%d, sector-start=%d, sector-count=%d, free=%dKB\n",
  3731. pThisRegion->DiskNumber,
  3732. pThisRegion->StartSector,
  3733. pThisRegion->SectorCount,
  3734. pThisRegion->FreeSpaceKB
  3735. ));
  3736. }
  3737. }
  3738. }
  3739. }
  3740. #endif
  3741. #ifdef OLD_PARTITION_ENGINE
  3742. NTSTATUS
  3743. SpPtPrepareDisks(
  3744. IN PVOID SifHandle,
  3745. OUT PDISK_REGION *InstallRegion,
  3746. OUT PDISK_REGION *SystemPartitionRegion,
  3747. IN PWSTR SetupSourceDevicePath,
  3748. IN PWSTR DirectoryOnSetupSource,
  3749. IN BOOLEAN RemoteBootRepartition
  3750. )
  3751. {
  3752. PPARTITIONED_DISK pDisk;
  3753. WCHAR Buffer[256];
  3754. ULONG DiskNo;
  3755. PVOID Menu;
  3756. ULONG MenuTopY;
  3757. ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
  3758. ULONG ValidKeysCmdCons[2] = { ASCI_ESC, 0 };
  3759. ULONG Keypress;
  3760. PDISK_REGION pRegion;
  3761. PDISK_REGION FirstRegion,DefaultRegion;
  3762. BOOLEAN unattended;
  3763. BOOLEAN createdMenu;
  3764. //SpPtDumpPartitionData();
  3765. if (SpIsArc()) {
  3766. //
  3767. // Select a system partition from among those defined in NV-RAM.
  3768. //
  3769. *SystemPartitionRegion = SpPtValidSystemPartitionArc(SifHandle,
  3770. SetupSourceDevicePath,
  3771. DirectoryOnSetupSource);
  3772. (*SystemPartitionRegion)->IsSystemPartition = 2;
  3773. }
  3774. unattended = UnattendedOperation;
  3775. while(1) {
  3776. createdMenu = FALSE;
  3777. Keypress = 0;
  3778. #if defined(REMOTE_BOOT)
  3779. if (RemoteBootSetup && !RemoteInstallSetup && HardDiskCount == 0) {
  3780. //
  3781. // If there are no hard disks, allow diskless install
  3782. //
  3783. pRegion = NULL;
  3784. //
  3785. // Run through the rest of the code as if the user had just
  3786. // hit enter to select this partition.
  3787. //
  3788. Keypress = ASCI_CR;
  3789. } else
  3790. #endif // defined(REMOTE_BOOT)
  3791. if (unattended && RemoteBootRepartition) {
  3792. ULONG DiskNumber;
  3793. //
  3794. // Prepare the disk for remote boot installation. This involves
  3795. // converting disk 0 into as big a partition as possible.
  3796. //
  3797. if (*SystemPartitionRegion != NULL) {
  3798. DiskNumber = (*SystemPartitionRegion)->DiskNumber;
  3799. } else {
  3800. #ifdef _X86_
  3801. DiskNumber = SpDetermineDisk0();
  3802. #else
  3803. DiskNumber = 0;
  3804. #endif
  3805. }
  3806. if (NT_SUCCESS(SpPtPartitionDiskForRemoteBoot(DiskNumber, &pRegion))) {
  3807. SpPtRegionDescription(
  3808. &PartitionedDisks[pRegion->DiskNumber],
  3809. pRegion,
  3810. Buffer,
  3811. sizeof(Buffer)
  3812. );
  3813. //
  3814. // Run through the rest of the code as if the user had just
  3815. // hit enter to select this partition.
  3816. //
  3817. Keypress = ASCI_CR;
  3818. }
  3819. }
  3820. if (Keypress == 0) {
  3821. //
  3822. // Display the text that goes above the menu on the partitioning screen.
  3823. //
  3824. SpDisplayScreen(ConsoleRunning?SP_SCRN_PARTITION_CMDCONS:SP_SCRN_PARTITION,3,CLIENT_TOP+1);
  3825. //
  3826. // Calculate menu placement. Leave one blank line
  3827. // and one line for a frame.
  3828. //
  3829. MenuTopY = NextMessageTopLine+2;
  3830. //
  3831. // Create a menu.
  3832. //
  3833. Menu = SpMnCreate(
  3834. MENU_LEFT_X,
  3835. MenuTopY,
  3836. MENU_WIDTH,
  3837. VideoVars.ScreenHeight-MenuTopY-(SplangQueryMinimizeExtraSpacing() ? 1 : 2)-STATUS_HEIGHT
  3838. );
  3839. if(!Menu) {
  3840. return(STATUS_NO_MEMORY);
  3841. }
  3842. createdMenu = TRUE;
  3843. //
  3844. // Build up a menu of partitions and free spaces.
  3845. //
  3846. FirstRegion = NULL;
  3847. for(DiskNo=0; DiskNo<HardDiskCount; DiskNo++) {
  3848. pDisk = &PartitionedDisks[DiskNo];
  3849. if(!SpPtGenerateMenu(Menu,pDisk,&FirstRegion)) {
  3850. SpMnDestroy(Menu);
  3851. return(STATUS_NO_MEMORY);
  3852. }
  3853. }
  3854. ASSERT(FirstRegion);
  3855. //
  3856. // If this is unattended operation, try to use the local source
  3857. // region if there is one. If this fails, the user will have to
  3858. // intervene manually.
  3859. //
  3860. if(unattended &&
  3861. LocalSourceRegion &&
  3862. (!LocalSourceRegion->DynamicVolume || LocalSourceRegion->DynamicVolumeSuitableForOS)
  3863. ) {
  3864. pRegion = LocalSourceRegion;
  3865. Keypress = ASCI_CR;
  3866. } else {
  3867. pRegion = NULL;
  3868. if (AutoPartitionPicker && !ConsoleRunning
  3869. #if defined(REMOTE_BOOT)
  3870. && (!RemoteBootSetup || RemoteInstallSetup)
  3871. #endif // defined(REMOTE_BOOT)
  3872. ) {
  3873. PDISK_REGION pThisRegion;
  3874. ULONG RequiredKB = 0;
  3875. ULONG SectorNo;
  3876. ULONG pass;
  3877. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: -------------------------------------------------------------\n" ));
  3878. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Looking for an install partition\n\n" ));
  3879. for(DiskNo=0; (DiskNo<HardDiskCount); DiskNo++) {
  3880. for( pass = 0; ((pass < 2) && (pRegion == NULL)); pass ++ ) {
  3881. for(pThisRegion= (pass == 0) ? PartitionedDisks[DiskNo].PrimaryDiskRegions : PartitionedDisks[DiskNo].ExtendedDiskRegions,SectorNo=0; pThisRegion; pThisRegion=pThisRegion->Next,SectorNo++) {
  3882. //
  3883. // Fetch the amount of free space required on the windows nt drive.
  3884. //
  3885. SpFetchDiskSpaceRequirements( SifHandle,
  3886. pThisRegion->BytesPerCluster,
  3887. &RequiredKB,
  3888. NULL);
  3889. if (SpPtDeterminePartitionGood(pThisRegion,RequiredKB,TRUE))
  3890. {
  3891. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Selected install partition = (%d,%d),(%wc:),(%ws)\n",
  3892. DiskNo,SectorNo,pThisRegion->DriveLetter,pThisRegion->VolumeLabel));
  3893. pRegion = pThisRegion;
  3894. Keypress = ASCI_CR;
  3895. break;
  3896. }
  3897. }
  3898. }
  3899. }
  3900. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: -------------------------------------------------------------\n" ));
  3901. }
  3902. if( !pRegion ) {
  3903. //
  3904. // If there is a local source, make it the default partition.
  3905. //
  3906. DefaultRegion = (LocalSourceRegion &&
  3907. (!LocalSourceRegion->DynamicVolume || LocalSourceRegion->DynamicVolumeSuitableForOS))?
  3908. LocalSourceRegion : FirstRegion;
  3909. //
  3910. // Call the menu callback to initialize the status line.
  3911. //
  3912. SpPtMenuCallback((ULONG_PTR)DefaultRegion);
  3913. SpMnDisplay(
  3914. Menu,
  3915. (ULONG_PTR)DefaultRegion,
  3916. TRUE,
  3917. ConsoleRunning?ValidKeysCmdCons:ValidKeys,
  3918. PartitionMnemonics,
  3919. SpPtMenuCallback,
  3920. SpPtIsNotReservedPartition,
  3921. &Keypress,
  3922. (PULONG_PTR)(&pRegion)
  3923. );
  3924. }
  3925. }
  3926. }
  3927. //
  3928. // Now act on the user's selection.
  3929. //
  3930. if(Keypress & KEY_MNEMONIC) {
  3931. Keypress &= ~KEY_MNEMONIC;
  3932. }
  3933. if (IsNEC_98) { //NEC98
  3934. //
  3935. // If target hard drive has no/wrong MBR, force initialize it right now.
  3936. //
  3937. PPARTITIONED_DISK pDisk;
  3938. ULONG ValidKeysInit[] = {ASCI_ESC, 0 };
  3939. ULONG MnemonicKeysInit[] = { MnemonicInitializeDisk, 0 };
  3940. pDisk = &PartitionedDisks[pRegion->DiskNumber];
  3941. if(!(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) &&
  3942. ((U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) != MBR_SIGNATURE) ||
  3943. (pDisk->HardDisk->FormatType != DISK_FORMAT_TYPE_NEC98)) &&
  3944. ((Keypress == MnemonicCreatePartition) ||
  3945. (Keypress == MnemonicDeletePartition) || (Keypress == ASCI_CR))) {
  3946. //SpDisplayScreen(SP_SCRN_INIT_DISK_NEC98,3,HEADER_HEIGHT+1);
  3947. SpStartScreen(
  3948. SP_SCRN_INIT_DISK_NEC98,
  3949. 3,
  3950. CLIENT_TOP+1,
  3951. FALSE,
  3952. FALSE,
  3953. DEFAULT_ATTRIBUTE,
  3954. pDisk->HardDisk->Description
  3955. );
  3956. SpDisplayStatusOptions(
  3957. DEFAULT_STATUS_ATTRIBUTE,
  3958. SP_STAT_I_EQUALS_INIT_NEC98,
  3959. SP_STAT_ESC_EQUALS_CANCEL,
  3960. 0
  3961. );
  3962. if(SpWaitValidKey(ValidKeysInit,NULL,MnemonicKeysInit) == ASCI_ESC) {
  3963. SpMnDestroy(Menu);
  3964. continue;
  3965. }
  3966. //
  3967. // It will be not return, if successfully complete.
  3968. //
  3969. return( SpInitializeHardDisk_Nec98(pRegion) );
  3970. }
  3971. } //NEC98
  3972. switch(Keypress) {
  3973. case MnemonicCreatePartition:
  3974. SpPtDoCreate(pRegion,NULL,FALSE,0,0,TRUE);
  3975. break;
  3976. case MnemonicDeletePartition:
  3977. SpPtDoDelete(pRegion,SpMnGetText(Menu,(ULONG_PTR)pRegion),TRUE);
  3978. break;
  3979. case KEY_F3:
  3980. SpConfirmExit();
  3981. break;
  3982. case ASCI_ESC:
  3983. if (ConsoleRunning) {
  3984. SpPtDoCommitChanges();
  3985. }
  3986. if (createdMenu) {
  3987. SpMnDestroy(Menu);
  3988. return(STATUS_SUCCESS);
  3989. }
  3990. return(STATUS_SUCCESS);
  3991. case ASCI_CR:
  3992. if(SpPtDoPartitionSelection(&pRegion,
  3993. (!createdMenu) ? Buffer :
  3994. SpMnGetText(Menu,(ULONG_PTR)pRegion),
  3995. SifHandle,
  3996. unattended,
  3997. SetupSourceDevicePath,
  3998. DirectoryOnSetupSource,
  3999. RemoteBootRepartition)) {
  4000. //
  4001. // We're done here.
  4002. //
  4003. if (createdMenu) {
  4004. SpMnDestroy(Menu);
  4005. }
  4006. *InstallRegion = pRegion;
  4007. #if defined(REMOTE_BOOT)
  4008. //
  4009. // Set the install region differently if this is a remote
  4010. // boot -- in that case, the install region is always remote.
  4011. //
  4012. if (RemoteBootSetup && !RemoteInstallSetup) {
  4013. *InstallRegion = RemoteBootTargetRegion;
  4014. }
  4015. #endif // defined(REMOTE_BOOT)
  4016. if (!SpIsArc()) {
  4017. if (!IsNEC_98) { //NEC98
  4018. *SystemPartitionRegion = SpPtValidSystemPartition();
  4019. } else {
  4020. *SystemPartitionRegion = *InstallRegion;
  4021. } //NEC98
  4022. }else{
  4023. //
  4024. // Select a system partition from among those defined in NV-RAM.
  4025. // We have to do this again because the user may have deleted the
  4026. // system partition previously detected.
  4027. // Note that SpPtValidSystemPartitionArc(SifHandle) will not return if
  4028. // a valid system partition is not found.
  4029. //
  4030. *SystemPartitionRegion = SpPtValidSystemPartitionArc(SifHandle,
  4031. SetupSourceDevicePath,
  4032. DirectoryOnSetupSource);
  4033. }
  4034. #if defined(REMOTE_BOOT)
  4035. ASSERT(*SystemPartitionRegion ||
  4036. (RemoteBootSetup && !RemoteInstallSetup && (HardDiskCount == 0)));
  4037. #else
  4038. ASSERT(*SystemPartitionRegion);
  4039. #endif // defined(REMOTE_BOOT)
  4040. return(STATUS_SUCCESS);
  4041. } else {
  4042. //
  4043. // Something happened when we tried to select the
  4044. // partition. Make sure that autopartition-picker
  4045. // doesn't invoke next time through our while loop.
  4046. //
  4047. AutoPartitionPicker = FALSE;
  4048. }
  4049. break;
  4050. }
  4051. if (createdMenu) {
  4052. SpMnDestroy(Menu);
  4053. }
  4054. unattended = FALSE;
  4055. }
  4056. }
  4057. VOID
  4058. SpPtDoDelete(
  4059. IN PDISK_REGION pRegion,
  4060. IN PWSTR RegionDescription,
  4061. IN BOOLEAN ConfirmIt
  4062. )
  4063. {
  4064. ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; // do not change order
  4065. ULONG Mnemonics[2] = { MnemonicDeletePartition2, 0 };
  4066. ULONG k;
  4067. BOOLEAN b;
  4068. PPARTITIONED_DISK pDisk;
  4069. BOOLEAN LastLogical;
  4070. ULONG Count;
  4071. #ifdef GPT_PARTITION_ENGINE
  4072. if (SPPT_IS_GPT_DISK(pRegion->DiskNumber)) {
  4073. SpPtnDoDelete(pRegion,
  4074. RegionDescription,
  4075. ConfirmIt);
  4076. return;
  4077. }
  4078. #endif
  4079. //
  4080. // Special warning if this is a system partition.
  4081. //
  4082. // Do not check system partition on NEC98.
  4083. //
  4084. if (!IsNEC_98) { //NEC98
  4085. if(ConfirmIt && pRegion->IsSystemPartition) {
  4086. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_SYSPART,3,HEADER_HEIGHT+1);
  4087. SpDisplayStatusOptions(
  4088. DEFAULT_STATUS_ATTRIBUTE,
  4089. SP_STAT_ENTER_EQUALS_CONTINUE,
  4090. SP_STAT_ESC_EQUALS_CANCEL,
  4091. 0
  4092. );
  4093. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  4094. return;
  4095. }
  4096. }
  4097. } //NEC98
  4098. if(ConfirmIt && pRegion->DynamicVolume) {
  4099. SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_DYNVOL,3,HEADER_HEIGHT+1);
  4100. SpDisplayStatusOptions(
  4101. DEFAULT_STATUS_ATTRIBUTE,
  4102. SP_STAT_ENTER_EQUALS_CONTINUE,
  4103. SP_STAT_ESC_EQUALS_CANCEL,
  4104. 0
  4105. );
  4106. if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) {
  4107. return;
  4108. }
  4109. }
  4110. //
  4111. // CR is no longer a valid key.
  4112. //
  4113. ValidKeys[1] = 0;
  4114. pDisk = &PartitionedDisks[pRegion->DiskNumber];
  4115. //
  4116. // Put up the confirmation screen.
  4117. //
  4118. if (ConfirmIt) {
  4119. if( ( pRegion->Filesystem == FilesystemFat ) &&
  4120. ( pRegion->NextCompressed != NULL ) ) {
  4121. //
  4122. // Warn the user that the partition contains compressed volumes
  4123. //
  4124. Count = SpGetNumberOfCompressedDrives( pRegion );
  4125. SpStartScreen(
  4126. SP_SCRN_CONFIRM_REMOVE_PARTITION_COMPRESSED,
  4127. 3,
  4128. CLIENT_TOP+1,
  4129. FALSE,
  4130. FALSE,
  4131. DEFAULT_ATTRIBUTE,
  4132. RegionDescription,
  4133. pDisk->HardDisk->Description,
  4134. Count
  4135. );
  4136. } else {
  4137. SpStartScreen(
  4138. SP_SCRN_CONFIRM_REMOVE_PARTITION,
  4139. 3,
  4140. CLIENT_TOP+1,
  4141. FALSE,
  4142. FALSE,
  4143. DEFAULT_ATTRIBUTE,
  4144. RegionDescription,
  4145. pDisk->HardDisk->Description
  4146. );
  4147. }
  4148. }
  4149. //
  4150. // Display the staus text.
  4151. //
  4152. if (ConfirmIt) {
  4153. SpDisplayStatusOptions(
  4154. DEFAULT_STATUS_ATTRIBUTE,
  4155. SP_STAT_L_EQUALS_DELETE,
  4156. SP_STAT_ESC_EQUALS_CANCEL,
  4157. 0
  4158. );
  4159. k = SpWaitValidKey(ValidKeys,NULL,Mnemonics);
  4160. if(k == ASCI_ESC) {
  4161. return;
  4162. }
  4163. SpDisplayStatusOptions(
  4164. DEFAULT_STATUS_ATTRIBUTE,
  4165. SP_STAT_PLEASE_WAIT,
  4166. 0);
  4167. }
  4168. //
  4169. // User wants to go ahead.
  4170. // Determine whether this is the last logical drive in the
  4171. // extended partition.
  4172. //
  4173. if((pRegion->MbrInfo == pDisk->FirstEbrInfo.Next)
  4174. && (pDisk->FirstEbrInfo.Next->Next == NULL))
  4175. {
  4176. LastLogical = TRUE;
  4177. } else {
  4178. LastLogical = FALSE;
  4179. }
  4180. //
  4181. // Get rid of the compressed drives, if any
  4182. //
  4183. if( pRegion->NextCompressed != NULL ) {
  4184. SpDisposeCompressedDrives( pRegion->NextCompressed );
  4185. pRegion->NextCompressed = NULL;
  4186. pRegion->MountDrive = 0;
  4187. pRegion->HostDrive = 0;
  4188. }
  4189. b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
  4190. if (!b) {
  4191. if (ConfirmIt) {
  4192. SpDisplayScreen(SP_SCRN_PARTITION_DELETE_FAILED,3,HEADER_HEIGHT+1);
  4193. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
  4194. SpInputDrain();
  4195. while(SpInputGetKeypress() != ASCI_CR) ;
  4196. }
  4197. return;
  4198. }
  4199. //
  4200. // If we deleted the last logical drive in the extended partition,
  4201. // then remove the extended partition also.
  4202. //
  4203. // Do not check system partition on NEC98.
  4204. //
  4205. if (!IsNEC_98) { //NEC98
  4206. if(LastLogical) {
  4207. //
  4208. // Locate the extended partition.
  4209. //
  4210. for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) {
  4211. if(pRegion->PartitionedSpace
  4212. && IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId))
  4213. {
  4214. //
  4215. // Found it -- now delete it.
  4216. //
  4217. b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
  4218. ASSERT(b);
  4219. break;
  4220. }
  4221. }
  4222. }
  4223. } //NEC98
  4224. //
  4225. // Delete the drive letters if the necessary. This is to ensure that the drive letters assigned to CD-ROM
  4226. // drives will go away, when the the disks have no partitioned space.
  4227. //
  4228. SpPtDeleteDriveLetters();
  4229. }
  4230. BOOLEAN
  4231. SpPtDoCreate(
  4232. IN PDISK_REGION pRegion,
  4233. OUT PDISK_REGION *pActualRegion, OPTIONAL
  4234. IN BOOLEAN ForNT,
  4235. IN ULONGLONG DesiredMB OPTIONAL,
  4236. IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
  4237. IN BOOLEAN ConfirmIt
  4238. )
  4239. {
  4240. ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 };
  4241. BOOLEAN b;
  4242. PPARTITIONED_DISK pDisk;
  4243. ULONGLONG MinMB,MaxMB;
  4244. ULONG TotalPrimary,RecogPrimary;
  4245. BOOLEAN InExtended;
  4246. UCHAR CreateSysId;
  4247. UCHAR RealSysId;
  4248. BOOLEAN ExtendedExists;
  4249. ULONGLONG SizeMB,RealSizeMB;
  4250. WCHAR Buffer[200];
  4251. WCHAR SizeBuffer[10];
  4252. BOOLEAN Beyond1024;
  4253. BOOLEAN ReservedRegion;
  4254. UCHAR DesiredSysId = 0;
  4255. PARTITION_INFORMATION_EX NewPartInfo;
  4256. #ifdef GPT_PARTITION_ENGINE
  4257. if (SPPT_IS_GPT_DISK(pRegion->DiskNumber)) {
  4258. return SpPtnDoCreate(pRegion,
  4259. pActualRegion,
  4260. ForNT,
  4261. DesiredMB,
  4262. PartInfo,
  4263. ConfirmIt);
  4264. }
  4265. #endif
  4266. RtlZeroMemory(&NewPartInfo, sizeof(PARTITION_INFORMATION_EX));
  4267. DesiredSysId = PartInfo ? PartInfo->Mbr.PartitionType : 0;
  4268. ASSERT(!pRegion->PartitionedSpace);
  4269. pDisk = &PartitionedDisks[pRegion->DiskNumber];
  4270. //
  4271. // Determine whether this space is within the extended partition.
  4272. //
  4273. # if 0
  4274. //
  4275. // No NEC98 has Extended partition.
  4276. // All of partition on NEC98 are Primary.
  4277. //
  4278. InExtended = (!IsNEC_98) ? (BOOLEAN)(SpPtLookupRegionByStart(pDisk,TRUE,pRegion->StartSector) != NULL) : FALSE; //NEC98
  4279. # endif //0
  4280. InExtended = (BOOLEAN)(SpPtLookupRegionByStart(pDisk,TRUE,pRegion->StartSector) != NULL);
  4281. Beyond1024 = SpIsRegionBeyondCylinder1024(pRegion);
  4282. if( pDisk->HardDisk->Geometry.MediaType == RemovableMedia ) {
  4283. ULONG pass;
  4284. PDISK_REGION p;
  4285. //
  4286. // If the user is attempting to create a partition on a removable drive, then make sure that
  4287. // the drive doesn't already contain a primary partition or a logical drive.
  4288. //
  4289. for( pass = 0; pass < 2; pass++ ) {
  4290. for( p = (pass == 0)? pDisk->PrimaryDiskRegions : pDisk->ExtendedDiskRegions;
  4291. p;
  4292. p = p->Next ) {
  4293. if( p->PartitionedSpace ) {
  4294. PON_DISK_PTE pte;
  4295. UCHAR TmpSysId;
  4296. pte = &p->MbrInfo->OnDiskMbr.PartitionTable[p->TablePosition];
  4297. TmpSysId = pte->SystemId;
  4298. if( !IsContainerPartition(TmpSysId) ) {
  4299. ULONG ValidKeys1[2] = { ASCI_CR ,0 };
  4300. //
  4301. // Disk is already partitioned
  4302. //
  4303. SpDisplayScreen(SP_SCRN_REMOVABLE_ALREADY_PARTITIONED,3,HEADER_HEIGHT+1);
  4304. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  4305. SpWaitValidKey(ValidKeys1,NULL,NULL);
  4306. return( FALSE );
  4307. }
  4308. }
  4309. }
  4310. }
  4311. }
  4312. //
  4313. // Determine the type of partition to create for this space,
  4314. // excluding any issues with extended partitions.
  4315. //
  4316. if (DesiredSysId != 0) {
  4317. //
  4318. // If the caller specified a partition type, use it unless it
  4319. // won't work due to being beyond 1024 cylinders.
  4320. //
  4321. #if 0
  4322. RealSysId = DesiredSysId;
  4323. if (Beyond1024) {
  4324. if (RealSysId == PARTITION_FAT32) {
  4325. RealSysId = PARTITION_FAT32_XINT13;
  4326. } else {
  4327. RealSysId = PARTITION_XINT13;
  4328. }
  4329. }
  4330. #else
  4331. //
  4332. // Keep this code in until I determine if we will be explicitly
  4333. // creating extended partitions.
  4334. //
  4335. RealSysId = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE;
  4336. #endif
  4337. } else {
  4338. RealSysId = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE;
  4339. }
  4340. //
  4341. // Determine the type of partition to create in the space.
  4342. //
  4343. // If the free space is within the extended partition, create
  4344. // a logical drive.
  4345. //
  4346. // If there is no primary partition, create a primary partition.
  4347. //
  4348. // If there is a primary partition and no extended partition,
  4349. // create an extended partition spanning the entire space and
  4350. // then a logical drive within it of the size given by the user.
  4351. //
  4352. // If there is space in the partition table, create a primary partition.
  4353. //
  4354. if(InExtended) {
  4355. CreateSysId = RealSysId;
  4356. } else {
  4357. //
  4358. // Get statistics about primary partitions.
  4359. //
  4360. SpPtCountPrimaryPartitions(pDisk,&TotalPrimary,&RecogPrimary,&ExtendedExists);
  4361. //
  4362. // If there is no primary partition, create one.
  4363. //
  4364. if(!RecogPrimary) {
  4365. CreateSysId = RealSysId;
  4366. } else {
  4367. //
  4368. // Make sure we can create a new primary/extended partition.
  4369. //
  4370. if(TotalPrimary < PTABLE_DIMENSION) {
  4371. //
  4372. // If there is an extended partition, then we have no choice but
  4373. // to create another primary.
  4374. //
  4375. if(ExtendedExists) {
  4376. CreateSysId = RealSysId;
  4377. } else {
  4378. //
  4379. // Firmware doesn't understand type F link partitions.
  4380. // No great need to use on x86 either; assume that creating
  4381. // logical drives with the correct type is good enough.
  4382. //
  4383. //
  4384. // No NEC98 has PARTITION_EXTENDED, just PARTITION_HUGE only.
  4385. //
  4386. CreateSysId = (!IsNEC_98 ||
  4387. (pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT))
  4388. ? PARTITION_EXTENDED : PARTITION_HUGE; //NEC98
  4389. if((CreateSysId == PARTITION_EXTENDED) && Beyond1024) {
  4390. CreateSysId = PARTITION_XINT13_EXTENDED;
  4391. }
  4392. }
  4393. } else {
  4394. if (ConfirmIt) {
  4395. while (TRUE) {
  4396. ULONG ks[2] = { ASCI_CR,0 };
  4397. SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,3,CLIENT_HEIGHT+1);
  4398. SpDisplayStatusOptions(
  4399. DEFAULT_STATUS_ATTRIBUTE,
  4400. SP_STAT_ENTER_EQUALS_CONTINUE,
  4401. 0
  4402. );
  4403. switch(SpWaitValidKey(ks,NULL,NULL)) {
  4404. case ASCI_CR:
  4405. return(FALSE);
  4406. }
  4407. }
  4408. } else {
  4409. return TRUE;
  4410. }
  4411. }
  4412. }
  4413. }
  4414. //
  4415. // Get the mimimum and maximum sizes for the partition.
  4416. //
  4417. ReservedRegion = FALSE;
  4418. SpPtQueryMinMaxCreationSizeMB(
  4419. pRegion->DiskNumber,
  4420. pRegion->StartSector,
  4421. (BOOLEAN)IsContainerPartition(CreateSysId),
  4422. InExtended,
  4423. &MinMB,
  4424. &MaxMB,
  4425. &ReservedRegion
  4426. );
  4427. if( ReservedRegion ) {
  4428. ULONG ValidKeys1[2] = { ASCI_CR ,0 };
  4429. SpStartScreen(
  4430. SP_SCRN_REGION_RESERVED,
  4431. 3,
  4432. HEADER_HEIGHT+1,
  4433. FALSE,
  4434. FALSE,
  4435. DEFAULT_ATTRIBUTE
  4436. );
  4437. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
  4438. SpWaitValidKey(ValidKeys1,NULL,NULL);
  4439. return(FALSE);
  4440. }
  4441. if(ForNT) {
  4442. //
  4443. // If a size was requested then try to use that, otherwise use
  4444. // the maximum.
  4445. //
  4446. if (DesiredMB != 0) {
  4447. if (DesiredMB <= MaxMB) {
  4448. SizeMB = DesiredMB;
  4449. } else {
  4450. return FALSE;
  4451. }
  4452. } else {
  4453. SizeMB = MaxMB;
  4454. }
  4455. } else {
  4456. //
  4457. // Put up a screen displaying min/max size info.
  4458. //
  4459. SpStartScreen(
  4460. SP_SCRN_CONFIRM_CREATE_PARTITION,
  4461. 3,
  4462. CLIENT_TOP+1,
  4463. FALSE,
  4464. FALSE,
  4465. DEFAULT_ATTRIBUTE,
  4466. pDisk->HardDisk->Description,
  4467. MinMB,
  4468. MaxMB
  4469. );
  4470. //
  4471. // Display the staus text.
  4472. //
  4473. SpDisplayStatusOptions(
  4474. DEFAULT_STATUS_ATTRIBUTE,
  4475. SP_STAT_ENTER_EQUALS_CREATE,
  4476. SP_STAT_ESC_EQUALS_CANCEL,
  4477. 0
  4478. );
  4479. //
  4480. // Get and display the size prompt.
  4481. //
  4482. SpFormatMessage(Buffer,sizeof(Buffer),SP_TEXT_SIZE_PROMPT);
  4483. SpvidDisplayString(Buffer,DEFAULT_ATTRIBUTE,3,NextMessageTopLine);
  4484. //
  4485. // Get the size from the user.
  4486. //
  4487. do {
  4488. swprintf(SizeBuffer,L"%u",MaxMB);
  4489. if(!SpGetInput(SpPtnGetSizeCB,SplangGetColumnCount(Buffer)+5,NextMessageTopLine,5,SizeBuffer,TRUE, 0)) {
  4490. //
  4491. // User pressed escape and bailed.
  4492. //
  4493. return(FALSE);
  4494. }
  4495. SizeMB = (ULONG)SpStringToLong(SizeBuffer,NULL,10);
  4496. } while((SizeMB < MinMB) || (SizeMB > MaxMB));
  4497. }
  4498. if(IsContainerPartition(CreateSysId)) {
  4499. RealSizeMB = SizeMB;
  4500. SizeMB = MaxMB;
  4501. }
  4502. NewPartInfo.PartitionStyle = PARTITION_STYLE_MBR;
  4503. NewPartInfo.Mbr.PartitionType = CreateSysId;
  4504. //
  4505. // Create the partition.
  4506. //
  4507. b = SpPtCreate(
  4508. pRegion->DiskNumber,
  4509. pRegion->StartSector,
  4510. SizeMB,
  4511. InExtended,
  4512. &NewPartInfo,
  4513. pActualRegion
  4514. );
  4515. ASSERT(b);
  4516. //
  4517. // Create the logical drive if we just created the extended partition.
  4518. //
  4519. if(IsContainerPartition(CreateSysId)) {
  4520. ASSERT(!InExtended);
  4521. NewPartInfo.Mbr.PartitionType = RealSysId;
  4522. b = SpPtCreate(
  4523. pRegion->DiskNumber,
  4524. pRegion->StartSector,
  4525. RealSizeMB,
  4526. TRUE,
  4527. &NewPartInfo,
  4528. pActualRegion
  4529. );
  4530. ASSERT(b);
  4531. }
  4532. return(TRUE);
  4533. }
  4534. #endif // NEW_PARTITION_ENGINE
  4535. //
  4536. // The following table contains offsets from SP_TEXT_PARTITION_NAME_BASE
  4537. // to get the message id of the name of each type of partition.
  4538. // A -1 entry means there is no name in the message file for this type
  4539. // of partition or that the filesystem should be determined instead.
  4540. //
  4541. //
  4542. #define PT(id) ((UCHAR)((SP_TEXT_PARTITION_NAME_##id)-SP_TEXT_PARTITION_NAME_BASE))
  4543. #define UNKNOWN PT(UNK)
  4544. #define M1 ((UCHAR)(-1))
  4545. UCHAR PartitionNameIds[256] = {
  4546. M1,M1,PT(XENIX),PT(XENIX), // 00-03
  4547. M1,M1,M1,M1, // 04-07
  4548. UNKNOWN,UNKNOWN,PT(BOOTMANAGER),M1, // 08-0b
  4549. M1,UNKNOWN,M1,M1, // 0c-0f
  4550. UNKNOWN,UNKNOWN,PT(EISA),UNKNOWN, // 10-13
  4551. UNKNOWN,UNKNOWN,PT(BMHIDE),PT(BMHIDE), // 14-17
  4552. UNKNOWN,UNKNOWN,UNKNOWN,PT(BMHIDE), // 18-1b
  4553. PT(BMHIDE),UNKNOWN,UNKNOWN,UNKNOWN, // 1c-1f
  4554. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 20-23
  4555. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 24-27
  4556. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 28-2b
  4557. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 2c-2f
  4558. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 30-33
  4559. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 34-37
  4560. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 38-3b
  4561. PT(PWRQST),UNKNOWN,UNKNOWN,UNKNOWN, // 3c-3f
  4562. UNKNOWN,PT(PPCBOOT),PT(VERIT),PT(VERIT), // 40-43
  4563. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 44-47
  4564. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 48-4b
  4565. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 4c-4f
  4566. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 50-53
  4567. PT(ONTRACK),PT(EZDRIVE),UNKNOWN,UNKNOWN, // 54-57
  4568. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 58-5b
  4569. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 5c-5f
  4570. UNKNOWN,UNKNOWN,UNKNOWN,PT(UNIX), // 60-63
  4571. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 64-67
  4572. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 68-6b
  4573. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 6c-6f
  4574. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 70-73
  4575. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 74-77
  4576. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 78-7b
  4577. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 7c-7f
  4578. UNKNOWN,PT(NTFT),UNKNOWN,UNKNOWN, // 80-83
  4579. PT(NTFT),UNKNOWN,PT(NTFT),PT(NTFT), // 84-87
  4580. UNKNOWN,UNKNOWN,UNKNOWN,PT(NTFT), // 88-8b
  4581. PT(NTFT),UNKNOWN,PT(NTFT),UNKNOWN, // 8c-8f
  4582. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 90-93
  4583. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 94-97
  4584. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 98-9b
  4585. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 9c-9f
  4586. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a0-a3
  4587. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a4-a7
  4588. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a8-ab
  4589. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // ac-af
  4590. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b0-b3
  4591. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b4-b7
  4592. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b8-bb
  4593. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // bc-bf
  4594. UNKNOWN,PT(NTFT),UNKNOWN,UNKNOWN, // c0-c3
  4595. PT(NTFT),UNKNOWN,PT(NTFT),PT(NTFT), // c4-c7
  4596. UNKNOWN,UNKNOWN,UNKNOWN,PT(NTFT), // c8-cb
  4597. PT(NTFT),UNKNOWN,PT(NTFT),UNKNOWN, // cc-cf
  4598. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d0-d3
  4599. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d4-d7
  4600. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d8-db
  4601. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // dc-df
  4602. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e0-e3
  4603. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e4-e7
  4604. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e8-eb
  4605. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // ec-ef
  4606. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f0-f3
  4607. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f4-f7
  4608. UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f8-fb
  4609. UNKNOWN,UNKNOWN,UNKNOWN,PT(XENIXTABLE) // fc-ff
  4610. };
  4611. WCHAR
  4612. SpGetDriveLetter(
  4613. IN PWSTR DeviceName,
  4614. OUT PMOUNTMGR_MOUNT_POINT * MountPoint OPTIONAL
  4615. )
  4616. /*++
  4617. Routine Description:
  4618. This routine returns the drive letter associated to a given device.
  4619. Arguments:
  4620. DeviceName - Supplies the device name.
  4621. MountPoint - If specified, causes the function to allocate a mount
  4622. manager point and fills it in.
  4623. Return Value:
  4624. A drive letter, if one exists.
  4625. --*/
  4626. {
  4627. NTSTATUS Status;
  4628. OBJECT_ATTRIBUTES Obja;
  4629. UNICODE_STRING UnicodeString;
  4630. IO_STATUS_BLOCK IoStatusBlock;
  4631. HANDLE Handle;
  4632. DWORD nameLen;
  4633. DWORD mountPointSize;
  4634. PMOUNTMGR_MOUNT_POINT mountPoint;
  4635. PMOUNTMGR_MOUNT_POINTS mountPoints;
  4636. PMOUNTMGR_TARGET_NAME mountTarget;
  4637. DWORD bytes;
  4638. WCHAR driveLetter;
  4639. DWORD i;
  4640. PWSTR s;
  4641. LARGE_INTEGER DelayTime;
  4642. INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
  4643. Status = ZwOpenFile(
  4644. &Handle,
  4645. (ACCESS_MASK)(FILE_GENERIC_READ),
  4646. &Obja,
  4647. &IoStatusBlock,
  4648. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
  4649. FILE_NON_DIRECTORY_FILE
  4650. );
  4651. if( !NT_SUCCESS( Status ) ) {
  4652. return L'\0';
  4653. }
  4654. //
  4655. // setup a good device name
  4656. //
  4657. nameLen = wcslen(DeviceName);
  4658. mountPointSize = sizeof(MOUNTMGR_TARGET_NAME) + nameLen*sizeof(WCHAR) + 28;
  4659. mountTarget = SpMemAlloc(mountPointSize);
  4660. if (!mountTarget) {
  4661. ZwClose(Handle);
  4662. return L'\0';
  4663. }
  4664. RtlZeroMemory(mountTarget, mountPointSize);
  4665. mountTarget->DeviceNameLength = (USHORT) nameLen*sizeof(WCHAR);
  4666. RtlCopyMemory((PCHAR) &mountTarget->DeviceName, DeviceName, nameLen*sizeof(WCHAR));
  4667. //
  4668. // this loop is necessary as a synchronization
  4669. // method. we have previously committed changes, but
  4670. // the volume manager has not had a chance to
  4671. // do it's thing so here we wait......
  4672. //
  4673. for (i=0; i<20; i++) {
  4674. Status = ZwDeviceIoControlFile(
  4675. Handle,
  4676. NULL,
  4677. NULL,
  4678. NULL,
  4679. &IoStatusBlock,
  4680. IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
  4681. mountTarget,
  4682. mountPointSize,
  4683. NULL,
  4684. 0
  4685. );
  4686. if (!NT_SUCCESS( Status )) {
  4687. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION failed - %08x\n",Status));
  4688. DelayTime.HighPart = -1;
  4689. DelayTime.LowPart = (ULONG)(-5000000);
  4690. KeDelayExecutionThread(KernelMode,FALSE,&DelayTime);
  4691. } else {
  4692. //
  4693. // On removable disks, a drive letter may not have been assigned yet.
  4694. // So make sure one is assigned on this case.
  4695. //
  4696. MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
  4697. NTSTATUS Status1;
  4698. Status1 = ZwDeviceIoControlFile(
  4699. Handle,
  4700. NULL,
  4701. NULL,
  4702. NULL,
  4703. &IoStatusBlock,
  4704. IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
  4705. mountTarget,
  4706. mountPointSize,
  4707. &DriveLetterInformation,
  4708. sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION)
  4709. );
  4710. if (!NT_SUCCESS( Status1 )) {
  4711. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER failed. Status = %lx \n",Status1));
  4712. }
  4713. break;
  4714. }
  4715. }
  4716. if (!NT_SUCCESS( Status )) {
  4717. SpMemFree(mountTarget);
  4718. ZwClose(Handle);
  4719. return L'\0';
  4720. }
  4721. SpMemFree(mountTarget);
  4722. nameLen = wcslen(DeviceName);
  4723. mountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) + nameLen*sizeof(WCHAR) + 28;
  4724. mountPoint = SpMemAlloc(mountPointSize);
  4725. if (!mountPoint) {
  4726. ZwClose(Handle);
  4727. return L'\0';
  4728. }
  4729. RtlZeroMemory(mountPoint, mountPointSize);
  4730. mountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  4731. mountPoint->DeviceNameLength = (USHORT) nameLen*sizeof(WCHAR);
  4732. RtlCopyMemory((PCHAR) mountPoint + sizeof(MOUNTMGR_MOUNT_POINT),
  4733. DeviceName, nameLen*sizeof(WCHAR));
  4734. mountPoints = SpMemAlloc( 4096 );
  4735. if (!mountPoints) {
  4736. SpMemFree(mountPoint);
  4737. ZwClose(Handle);
  4738. return L'\0';
  4739. }
  4740. Status = ZwDeviceIoControlFile(
  4741. Handle,
  4742. NULL,
  4743. NULL,
  4744. NULL,
  4745. &IoStatusBlock,
  4746. IOCTL_MOUNTMGR_QUERY_POINTS,
  4747. mountPoint,
  4748. mountPointSize,
  4749. mountPoints,
  4750. 4096
  4751. );
  4752. if (!NT_SUCCESS( Status )) {
  4753. if (Status == STATUS_BUFFER_OVERFLOW) {
  4754. bytes = mountPoints->Size;
  4755. SpMemFree(mountPoints);
  4756. mountPoints = SpMemAlloc(bytes);
  4757. if (!mountPoints) {
  4758. SpMemFree(mountPoint);
  4759. ZwClose(Handle);
  4760. return L'\0';
  4761. }
  4762. Status = ZwDeviceIoControlFile(
  4763. Handle,
  4764. NULL,
  4765. NULL,
  4766. NULL,
  4767. &IoStatusBlock,
  4768. IOCTL_MOUNTMGR_QUERY_POINTS,
  4769. mountPoint,
  4770. mountPointSize,
  4771. mountPoints,
  4772. bytes
  4773. );
  4774. if (!NT_SUCCESS( Status )) {
  4775. SpMemFree(mountPoints);
  4776. SpMemFree(mountPoint);
  4777. ZwClose(Handle);
  4778. return L'\0';
  4779. }
  4780. } else {
  4781. mountPoints->NumberOfMountPoints = 0;
  4782. }
  4783. }
  4784. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  4785. "SETUP: IOCTL_MOUNTMGR_QUERY_POINTS : Number = %d \n",
  4786. mountPoints->NumberOfMountPoints));
  4787. driveLetter = 0;
  4788. for (i = 0; i < mountPoints->NumberOfMountPoints; i++) {
  4789. if (mountPoints->MountPoints[i].SymbolicLinkNameLength != 28) {
  4790. continue;
  4791. }
  4792. s = (PWSTR) ((PCHAR) mountPoints +
  4793. mountPoints->MountPoints[i].SymbolicLinkNameOffset);
  4794. if (s[0] != L'\\' ||
  4795. (s[1] != L'D' && s[1] != L'd') ||
  4796. (s[2] != L'O' && s[2] != L'o') ||
  4797. (s[3] != L'S' && s[3] != L's') ||
  4798. (s[4] != L'D' && s[4] != L'd') ||
  4799. (s[5] != L'E' && s[5] != L'e') ||
  4800. (s[6] != L'V' && s[6] != L'v') ||
  4801. (s[7] != L'I' && s[7] != L'i') ||
  4802. (s[8] != L'C' && s[8] != L'c') ||
  4803. (s[9] != L'E' && s[9] != L'e') ||
  4804. (s[10]!= L'S' && s[10]!= L's') ||
  4805. s[11] != L'\\' ||
  4806. s[13] != L':') {
  4807. continue;
  4808. }
  4809. if (s[12] < ((!IsNEC_98) ? L'C' : L'A') || s[12] > L'Z') { //NEC98
  4810. continue;
  4811. }
  4812. driveLetter = s[12];
  4813. if (ARGUMENT_PRESENT( MountPoint )) {
  4814. ULONG newMountPointSize;
  4815. PMOUNTMGR_MOUNT_POINT newMountPoint, oldMountPoint;
  4816. ULONG currentOffset;
  4817. //
  4818. // The caller wants us to return the actual mount point information.
  4819. //
  4820. oldMountPoint = &mountPoints->MountPoints[i];
  4821. newMountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) +
  4822. oldMountPoint->SymbolicLinkNameLength +
  4823. oldMountPoint->UniqueIdLength +
  4824. oldMountPoint->DeviceNameLength;
  4825. newMountPoint = SpMemAlloc(newMountPointSize);
  4826. if (newMountPoint) {
  4827. currentOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  4828. newMountPoint->SymbolicLinkNameLength = oldMountPoint->SymbolicLinkNameLength;
  4829. newMountPoint->SymbolicLinkNameOffset = currentOffset;
  4830. memcpy((PCHAR)newMountPoint + newMountPoint->SymbolicLinkNameOffset,
  4831. (PCHAR)mountPoints + oldMountPoint->SymbolicLinkNameOffset,
  4832. oldMountPoint->SymbolicLinkNameLength);
  4833. currentOffset += oldMountPoint->SymbolicLinkNameLength;
  4834. newMountPoint->UniqueIdLength = oldMountPoint->UniqueIdLength;
  4835. newMountPoint->UniqueIdOffset = currentOffset;
  4836. memcpy((PCHAR)newMountPoint + newMountPoint->UniqueIdOffset,
  4837. (PCHAR)mountPoints + oldMountPoint->UniqueIdOffset,
  4838. oldMountPoint->UniqueIdLength);
  4839. currentOffset += oldMountPoint->UniqueIdLength;
  4840. newMountPoint->DeviceNameLength = oldMountPoint->DeviceNameLength;
  4841. newMountPoint->DeviceNameOffset = currentOffset;
  4842. memcpy((PCHAR)newMountPoint + newMountPoint->DeviceNameOffset,
  4843. (PCHAR)mountPoints + oldMountPoint->DeviceNameOffset,
  4844. oldMountPoint->DeviceNameLength);
  4845. *MountPoint = newMountPoint;
  4846. }
  4847. }
  4848. break;
  4849. }
  4850. SpMemFree(mountPoints);
  4851. SpMemFree(mountPoint);
  4852. ZwClose(Handle);
  4853. return driveLetter;
  4854. }
  4855. WCHAR
  4856. SpDeleteDriveLetter(
  4857. IN PWSTR DeviceName
  4858. )
  4859. /*++
  4860. Routine Description:
  4861. This routine returns the drive letter associated to a given device.
  4862. Arguments:
  4863. DeviceName - Supplies the device name.
  4864. Return Value:
  4865. A drive letter, if one exists.
  4866. --*/
  4867. {
  4868. NTSTATUS Status;
  4869. OBJECT_ATTRIBUTES Obja;
  4870. UNICODE_STRING UnicodeString;
  4871. IO_STATUS_BLOCK IoStatusBlock;
  4872. HANDLE Handle;
  4873. DWORD nameLen;
  4874. DWORD mountPointSize;
  4875. PMOUNTMGR_MOUNT_POINT mountPoint;
  4876. PMOUNTMGR_MOUNT_POINTS mountPoints;
  4877. DWORD bytes;
  4878. WCHAR driveLetter;
  4879. INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
  4880. Status = ZwOpenFile(
  4881. &Handle,
  4882. (ACCESS_MASK)(FILE_GENERIC_READ),
  4883. &Obja,
  4884. &IoStatusBlock,
  4885. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
  4886. FILE_NON_DIRECTORY_FILE
  4887. );
  4888. if( !NT_SUCCESS( Status ) ) {
  4889. return L'\0';
  4890. }
  4891. nameLen = wcslen(DeviceName);
  4892. mountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) + nameLen*sizeof(WCHAR) + 28;
  4893. mountPoint = SpMemAlloc(mountPointSize);
  4894. if (!mountPoint) {
  4895. ZwClose(Handle);
  4896. return L'\0';
  4897. }
  4898. RtlZeroMemory(mountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
  4899. mountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  4900. mountPoint->DeviceNameLength = (USHORT) nameLen*sizeof(WCHAR);
  4901. RtlCopyMemory((PCHAR) mountPoint + sizeof(MOUNTMGR_MOUNT_POINT),
  4902. DeviceName, nameLen*sizeof(WCHAR));
  4903. mountPoints = SpMemAlloc( 4096 );
  4904. if (!mountPoints) {
  4905. SpMemFree(mountPoint);
  4906. ZwClose(Handle);
  4907. return L'\0';
  4908. }
  4909. Status = ZwDeviceIoControlFile(
  4910. Handle,
  4911. NULL,
  4912. NULL,
  4913. NULL,
  4914. &IoStatusBlock,
  4915. IOCTL_MOUNTMGR_DELETE_POINTS,
  4916. mountPoint,
  4917. mountPointSize,
  4918. mountPoints,
  4919. 4096
  4920. );
  4921. if (!NT_SUCCESS( Status )) {
  4922. if (Status == STATUS_BUFFER_OVERFLOW) {
  4923. bytes = mountPoints->Size;
  4924. SpMemFree(mountPoints);
  4925. mountPoints = SpMemAlloc(bytes);
  4926. if (!mountPoints) {
  4927. SpMemFree(mountPoint);
  4928. ZwClose(Handle);
  4929. return L'\0';
  4930. }
  4931. Status = ZwDeviceIoControlFile(
  4932. Handle,
  4933. NULL,
  4934. NULL,
  4935. NULL,
  4936. &IoStatusBlock,
  4937. IOCTL_MOUNTMGR_DELETE_POINTS,
  4938. mountPoint,
  4939. mountPointSize,
  4940. mountPoints,
  4941. bytes
  4942. );
  4943. if (!NT_SUCCESS( Status )) {
  4944. SpMemFree(mountPoints);
  4945. SpMemFree(mountPoint);
  4946. ZwClose(Handle);
  4947. return L'\0';
  4948. }
  4949. } else {
  4950. mountPoints->NumberOfMountPoints = 0;
  4951. }
  4952. }
  4953. driveLetter = 0;
  4954. SpMemFree(mountPoints);
  4955. SpMemFree(mountPoint);
  4956. ZwClose(Handle);
  4957. return driveLetter;
  4958. }
  4959. VOID
  4960. SpPtDeleteDriveLetters(
  4961. VOID
  4962. )
  4963. /*++
  4964. Routine Description:
  4965. This routine will delete all drive letters assigned to disks and CD-ROM drives. The deletion will
  4966. occur only if setup was started booting from the CD or boot floppies (in which case drive letter
  4967. migration does not take place), and only if the non-removable dissks have no partitioned spaces.
  4968. This ensures that on a clean install from the CD or boot floppies, the drive letters assigned to
  4969. partitions on removable disks and CD-ROM drives will always be greater than the drive letters assigned
  4970. to partitions on non-removable disks (unless the partitions on the removable disks were created before
  4971. the ones in the removable disks, during textmode setup).
  4972. Arguments:
  4973. None.
  4974. Return Value:
  4975. None.
  4976. --*/
  4977. {
  4978. ULONG disk;
  4979. PDISK_REGION pRegion;
  4980. unsigned pass;
  4981. BOOLEAN PartitionedSpaceFound = FALSE;
  4982. if( WinntSetup ) {
  4983. //
  4984. // If setup started from winnt32.exe then do not delete the drive letters since we want to preserve them
  4985. //
  4986. return;
  4987. }
  4988. //
  4989. // Setup started booting from a CD or from the boot floppies
  4990. // Find out if the disks contain at least one partition that is not a container.
  4991. // Note that we do not take into consideration partitions that are on removable media.
  4992. // This is to avoid the situation in which a newly created partition on a non-removable disk ends up with
  4993. // a drive letter that is greater than the one assigned to an existing partition on a removable disk.
  4994. //
  4995. for(disk = 0;
  4996. !PartitionedSpaceFound &&
  4997. (disk<HardDiskCount);
  4998. disk++) {
  4999. if((PartitionedDisks[disk].HardDisk)->Geometry.MediaType != RemovableMedia) {
  5000. for(pass=0; !PartitionedSpaceFound && (pass<2); pass++) {
  5001. pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions;
  5002. for( ; !PartitionedSpaceFound && pRegion; pRegion=pRegion->Next) {
  5003. UCHAR SystemId = PARTITION_ENTRY_UNUSED;
  5004. #ifdef OLD_PARTITION_TABLE
  5005. SystemId = pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId;
  5006. #else
  5007. if (SPPT_IS_MBR_DISK(disk) && SPPT_IS_REGION_PARTITIONED(pRegion)) {
  5008. SystemId = SPPT_GET_PARTITION_TYPE(pRegion);
  5009. }
  5010. #endif
  5011. if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) {
  5012. PartitionedSpaceFound = TRUE;
  5013. }
  5014. }
  5015. }
  5016. }
  5017. }
  5018. if( !PartitionedSpaceFound ) {
  5019. //
  5020. // If the disks have no partitioned regions that are not a container,
  5021. // then delete all drive letters, so that the drive letters for each CD-ROM drive
  5022. // also get deleted.
  5023. //
  5024. NTSTATUS Status;
  5025. OBJECT_ATTRIBUTES Obja;
  5026. IO_STATUS_BLOCK IoStatusBlock;
  5027. UNICODE_STRING UnicodeString;
  5028. HANDLE Handle;
  5029. INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME);
  5030. Status = ZwOpenFile( &Handle,
  5031. (ACCESS_MASK)(FILE_GENERIC_READ | FILE_GENERIC_WRITE),
  5032. &Obja,
  5033. &IoStatusBlock,
  5034. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  5035. FILE_NON_DIRECTORY_FILE );
  5036. if( NT_SUCCESS( Status ) ) {
  5037. MOUNTMGR_MOUNT_POINT MountMgrMountPoint;
  5038. MountMgrMountPoint.SymbolicLinkNameOffset = 0;
  5039. MountMgrMountPoint.SymbolicLinkNameLength = 0;
  5040. MountMgrMountPoint.UniqueIdOffset = 0;
  5041. MountMgrMountPoint.UniqueIdLength = 0;
  5042. MountMgrMountPoint.DeviceNameOffset = 0;
  5043. MountMgrMountPoint.DeviceNameLength = 0;
  5044. Status = ZwDeviceIoControlFile( Handle,
  5045. NULL,
  5046. NULL,
  5047. NULL,
  5048. &IoStatusBlock,
  5049. IOCTL_MOUNTMGR_DELETE_POINTS,
  5050. &MountMgrMountPoint,
  5051. sizeof( MOUNTMGR_MOUNT_POINT ),
  5052. TemporaryBuffer,
  5053. sizeof( TemporaryBuffer ) );
  5054. if( !NT_SUCCESS( Status ) ) {
  5055. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete drive letters. ZwDeviceIoControl( IOCTL_MOUNTMGR_DELETE_POINTS ) failed. Status = %lx \n", Status));
  5056. } else {
  5057. //
  5058. // If the drive letters got deleted then reset the drive letters assigned to all partitions.
  5059. // Note that we only really care about resetting the drive letters on the partitions on the
  5060. // removable disks, since, if we got that far, there won't be any partition on the non-removable
  5061. // disks
  5062. //
  5063. for(disk = 0; (disk<HardDiskCount); disk++) {
  5064. if ((PartitionedDisks[disk].HardDisk)->Geometry.MediaType == RemovableMedia) {
  5065. for(pass=0; pass<2; pass++) {
  5066. pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions;
  5067. for( ; pRegion; pRegion=pRegion->Next) {
  5068. UCHAR SystemId = SpPtGetPartitionType(pRegion);
  5069. if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) {
  5070. pRegion->DriveLetter = 0;
  5071. }
  5072. }
  5073. }
  5074. }
  5075. }
  5076. }
  5077. ZwClose( Handle );
  5078. } else {
  5079. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete drive letters. ZwOpenFile( %ls ) failed. Status = %lx \n", MOUNTMGR_DEVICE_NAME, Status));
  5080. }
  5081. }
  5082. }
  5083. VOID
  5084. SpPtAssignDriveLetters(
  5085. VOID
  5086. )
  5087. {
  5088. ULONG disk;
  5089. PDISK_REGION pRegion;
  5090. unsigned pass;
  5091. //
  5092. // Before initializing the drive letters, delete them if necessary.
  5093. // This is to get rid of the letters assigned to CD-ROM drives and removables, when the disks have no
  5094. // partitioned space.
  5095. //
  5096. SpPtDeleteDriveLetters();
  5097. //
  5098. // Initialize all drive letters to nothing.
  5099. // If it the region is a partitioned space, then assign a drive letter also.
  5100. //
  5101. for(disk=0; disk<HardDiskCount; disk++) {
  5102. // assign drive letters for removeable media also for command console
  5103. if(ForceConsole || ((PartitionedDisks[disk].HardDisk)->Geometry.MediaType != RemovableMedia)) {
  5104. for(pass=0; pass<2; pass++) {
  5105. pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions;
  5106. for( ; pRegion; pRegion=pRegion->Next) {
  5107. UCHAR SystemId = SpPtGetPartitionType(pRegion);
  5108. pRegion->DriveLetter = 0;
  5109. if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) {
  5110. //
  5111. // Get the nt pathname for this region.
  5112. //
  5113. SpNtNameFromRegion(
  5114. pRegion,
  5115. TemporaryBuffer,
  5116. sizeof(TemporaryBuffer),
  5117. PartitionOrdinalCurrent
  5118. );
  5119. //
  5120. // Assign a drive letter for this region
  5121. //
  5122. pRegion->DriveLetter = SpGetDriveLetter( TemporaryBuffer, NULL );
  5123. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Partition = %ls (%ls), DriveLetter = %wc: \n", TemporaryBuffer, (pass)? L"Extended" : L"Primary", pRegion->DriveLetter));
  5124. }
  5125. }
  5126. }
  5127. }
  5128. }
  5129. }
  5130. VOID
  5131. SpPtRemapDriveLetters(
  5132. IN BOOLEAN DriveAssign_AT
  5133. )
  5134. {
  5135. PWSTR p;
  5136. NTSTATUS Status;
  5137. UNICODE_STRING StartDriveLetterFrom;
  5138. UNICODE_STRING Dummy;
  5139. STRING ntDeviceName;
  5140. UCHAR deviceNameBuffer[256] = "\\Device\\Harddisk0\\Partition1";
  5141. UCHAR systemRootBuffer[256] = "C:\\$WIN_NT$.~BT";
  5142. ANSI_STRING ansiString;
  5143. BOOLEAN ForceUnmap = FALSE;
  5144. RTL_QUERY_REGISTRY_TABLE SetupTypeTable[]=
  5145. {
  5146. {NULL,
  5147. RTL_QUERY_REGISTRY_DIRECT,
  5148. L"DriveLetter",
  5149. &StartDriveLetterFrom,
  5150. REG_SZ,
  5151. &Dummy,
  5152. 0
  5153. },
  5154. {NULL,0,NULL,NULL,REG_NONE,NULL,0}
  5155. };
  5156. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveAssign_AT = %d.\n",(DriveAssign_AT ? 1 : 0)));
  5157. //
  5158. // Determin whether how to drive assign is 98 (HD start is A) or
  5159. // AT (HD start C).
  5160. //
  5161. RtlInitUnicodeString(&StartDriveLetterFrom, NULL);
  5162. RtlInitUnicodeString(&Dummy, NULL);
  5163. Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
  5164. L"\\Registry\\MACHINE\\SYSTEM\\Setup",
  5165. SetupTypeTable,
  5166. NULL,
  5167. NULL);
  5168. if (NT_SUCCESS(Status)) {
  5169. if ((StartDriveLetterFrom.Buffer[0] == L'C') ||
  5170. (StartDriveLetterFrom.Buffer[0] == L'c')) {
  5171. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLetter is in setupreg.hiv.\n"));
  5172. if (!DriveAssign_AT) {
  5173. //
  5174. // Delete hive value "DriveLetter".
  5175. //
  5176. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Re-assign as NEC assign.\n"));
  5177. Status = RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  5178. L"\\Registry\\MACHINE\\SYSTEM\\Setup",
  5179. L"DriveLetter");
  5180. if (!NT_SUCCESS(Status)) {
  5181. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Fail to delete KEY DriveLetter.\n"));
  5182. }
  5183. }
  5184. } else {
  5185. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: There is no DriveLetter.\n"));
  5186. if (DriveAssign_AT) {
  5187. //
  5188. // Add hive value "DriveLetter" as "C".
  5189. //
  5190. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Re-assign as AT assign.\n"));
  5191. Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  5192. L"\\Registry\\Machine\\System\\Setup",
  5193. L"DriveLetter",
  5194. REG_SZ,
  5195. L"C",
  5196. sizeof(L"C")+sizeof(WCHAR));
  5197. if (!NT_SUCCESS(Status)) {
  5198. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Fail to add KEY DriveLetter.\n"));
  5199. }
  5200. }
  5201. }
  5202. ForceUnmap = TRUE;
  5203. }
  5204. //
  5205. // Cancel all drive letters and Remap drive letters.
  5206. //
  5207. if (ForceUnmap) {
  5208. SpPtUnAssignDriveLetters();
  5209. ntDeviceName.Buffer = deviceNameBuffer;
  5210. ntDeviceName.MaximumLength = sizeof(deviceNameBuffer);
  5211. ntDeviceName.Length = 0;
  5212. ansiString.MaximumLength = sizeof(systemRootBuffer);
  5213. ansiString.Length = 0;
  5214. ansiString.Buffer = systemRootBuffer;
  5215. IoAssignDriveLetters( *(PLOADER_PARAMETER_BLOCK *)KeLoaderBlock,
  5216. &ntDeviceName,
  5217. ansiString.Buffer,
  5218. &ansiString );
  5219. }
  5220. RtlFreeUnicodeString(&StartDriveLetterFrom);
  5221. RtlFreeUnicodeString(&Dummy);
  5222. }
  5223. VOID
  5224. SpPtUnAssignDriveLetters(
  5225. VOID
  5226. )
  5227. {
  5228. ULONG disk;
  5229. PDISK_REGION pRegion;
  5230. unsigned pass;
  5231. ULONG CdCount, cdrom, dlet;
  5232. UNICODE_STRING linkString;
  5233. WCHAR tempBuffer[] = L"\\DosDevices\\A:";
  5234. //
  5235. // Release all drive letters of device.
  5236. // If it the region is a partitioned space, then assign a drive letter also.
  5237. //
  5238. for(disk=0; disk<HardDiskCount; disk++) {
  5239. for(pass=0; pass<2; pass++) {
  5240. pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions;
  5241. for( ; pRegion; pRegion=pRegion->Next) {
  5242. UCHAR SystemId = SpPtGetPartitionType(pRegion);
  5243. //pRegion->DriveLetter = 0;
  5244. if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) {
  5245. //
  5246. // Get the nt pathname for this region.
  5247. //
  5248. SpNtNameFromRegion(
  5249. pRegion,
  5250. TemporaryBuffer,
  5251. sizeof(TemporaryBuffer),
  5252. PartitionOrdinalOriginal
  5253. );
  5254. //
  5255. // Assign a drive letter for this region
  5256. //
  5257. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: delete Partition = %ls (%ls), DriveLetter = %wc: \n", TemporaryBuffer, (pass)? L"Extended" : L"Primary", pRegion->DriveLetter));
  5258. SpDeleteDriveLetter( TemporaryBuffer );
  5259. pRegion->DriveLetter = 0;
  5260. }
  5261. }
  5262. }
  5263. }
  5264. if(CdCount = IoGetConfigurationInformation()->CdRomCount) {
  5265. //
  5266. // Unlink CD-ROM drive letters.
  5267. //
  5268. for(cdrom=0; cdrom<CdCount; cdrom++) {
  5269. swprintf(TemporaryBuffer,L"\\Device\\Cdrom%u",cdrom);
  5270. SpDeleteDriveLetter( TemporaryBuffer );
  5271. }
  5272. }
  5273. //
  5274. // Delete all symbolic link related in drive letter.
  5275. //
  5276. for (dlet=0; dlet<26; dlet++) {
  5277. tempBuffer[12] = (WCHAR)(L'A' + dlet);
  5278. RtlInitUnicodeString( &linkString, tempBuffer);
  5279. IoDeleteSymbolicLink (&linkString);
  5280. }
  5281. }
  5282. #ifndef NEW_PARTITION_ENGINE
  5283. VOID
  5284. SpPtDeletePartitionsForRemoteBoot(
  5285. PPARTITIONED_DISK pDisk,
  5286. PDISK_REGION startRegion,
  5287. PDISK_REGION endRegion,
  5288. BOOLEAN Extended
  5289. )
  5290. {
  5291. PDISK_REGION pRegion;
  5292. PDISK_REGION pNextDeleteRegion;
  5293. BOOLEAN passedEndRegion = FALSE;
  5294. BOOLEAN b;
  5295. #ifdef GPT_PARTITION_ENGINE
  5296. if (pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_GPT) {
  5297. SpPtnDeletePartitionsForRemoteBoot(pDisk,
  5298. startRegion,
  5299. endRegion,
  5300. Extended);
  5301. return;
  5302. }
  5303. #endif
  5304. //
  5305. // Delete all disk regions from startRegion to endRegion.
  5306. //
  5307. pRegion = startRegion;
  5308. while (pRegion) {
  5309. //
  5310. // Before deleting this region, we need to save the next region
  5311. // to delete, since the list may get modified as a result of
  5312. // deleting this one (but a partitioned region won't get
  5313. // changed, only free ones). Note that endRegion might
  5314. // be unpartitioned so we need to be careful to check for
  5315. // the exit case.
  5316. //
  5317. pNextDeleteRegion = pRegion->Next;
  5318. while (pNextDeleteRegion) {
  5319. if (pNextDeleteRegion->PartitionedSpace) {
  5320. break;
  5321. } else {
  5322. if (pNextDeleteRegion == endRegion) {
  5323. passedEndRegion = TRUE;
  5324. }
  5325. pNextDeleteRegion = pNextDeleteRegion->Next;
  5326. }
  5327. }
  5328. //
  5329. // If this is the extended partition, first kill all the
  5330. // logical drives.
  5331. //
  5332. if (IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId)) {
  5333. ASSERT(!Extended);
  5334. SpPtDeletePartitionsForRemoteBoot(
  5335. pDisk,
  5336. pDisk->ExtendedDiskRegions,
  5337. NULL,
  5338. TRUE // used to check for another recursion
  5339. );
  5340. }
  5341. //
  5342. // Remove any boot entries pointing to this region.
  5343. //
  5344. SpPtDeleteBootSetsForRegion(pRegion);
  5345. //
  5346. // Get rid of the compressed drives, if any
  5347. //
  5348. if( pRegion->NextCompressed != NULL ) {
  5349. SpDisposeCompressedDrives( pRegion->NextCompressed );
  5350. pRegion->NextCompressed = NULL;
  5351. pRegion->MountDrive = 0;
  5352. pRegion->HostDrive = 0;
  5353. }
  5354. if (pRegion->PartitionedSpace) {
  5355. b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector);
  5356. }
  5357. ASSERT(b);
  5358. if ((pRegion == endRegion) ||
  5359. passedEndRegion) {
  5360. break;
  5361. }
  5362. pRegion = pNextDeleteRegion;
  5363. }
  5364. }
  5365. #endif // ! NEW_PARTITION_ENGINE
  5366. NTSTATUS
  5367. SpPtPartitionDiskForRemoteBoot(
  5368. IN ULONG DiskNumber,
  5369. OUT PDISK_REGION *RemainingRegion
  5370. )
  5371. {
  5372. PPARTITIONED_DISK pDisk;
  5373. PDISK_REGION pRegion;
  5374. ULONG PartitionCount = 0;
  5375. ULONGLONG firstRegionStartSector;
  5376. PDISK_REGION firstRegion = NULL, lastRegion = NULL;
  5377. BOOLEAN IsGPTDisk = FALSE;
  5378. pDisk = &PartitionedDisks[DiskNumber];
  5379. IsGPTDisk = SPPT_IS_GPT_DISK(DiskNumber);
  5380. //
  5381. // Scan through the disk and see how many contiguous recognized
  5382. // partitions there are.
  5383. //
  5384. if (pDisk->HardDisk->Status == DiskOffLine) {
  5385. return STATUS_DEVICE_OFF_LINE;
  5386. }
  5387. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5388. "SpPtPartitionDiskForRemoteBoot: cylinder size is %lx\n",
  5389. pDisk->HardDisk->SectorsPerCylinder));
  5390. pRegion = pDisk->PrimaryDiskRegions;
  5391. for( ; pRegion; pRegion=pRegion->Next) {
  5392. if (!pRegion->PartitionedSpace) {
  5393. //
  5394. // If the region is not partitioned, then add it to our list
  5395. // to merge if we have one.
  5396. //
  5397. if (firstRegion) {
  5398. //
  5399. // If this is a final free region covering the last
  5400. // partial cylinder on the disk, then don't add it.
  5401. //
  5402. if ((pRegion->Next == NULL) &&
  5403. (pRegion->SectorCount < pDisk->HardDisk->SectorsPerCylinder) &&
  5404. ((pRegion->StartSector % pDisk->HardDisk->SectorsPerCylinder) == 0)) {
  5405. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5406. "Skipping final partial cylinder free region %lx for %lx\n",
  5407. pRegion->StartSector, pRegion->SectorCount));
  5408. } else {
  5409. lastRegion = pRegion;
  5410. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5411. "Adding free region %lx for %lx\n",
  5412. pRegion->StartSector, pRegion->SectorCount));
  5413. }
  5414. } else {
  5415. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5416. "Skipping free region %lx for %lx\n",
  5417. pRegion->StartSector, pRegion->SectorCount));
  5418. }
  5419. } else {
  5420. PON_DISK_PTE pte;
  5421. UCHAR SystemId = 0;
  5422. if (IsGPTDisk) {
  5423. if (SPPT_IS_RECOGNIZED_FILESYSTEM(pRegion->Filesystem)) {
  5424. //
  5425. // TBD : Fix for cases where FT / Dynamic volumes can
  5426. // reside on the GPT disk
  5427. //
  5428. SystemId = PARTITION_FAT32;
  5429. } else {
  5430. SystemId = PARTITION_ENTRY_UNUSED;
  5431. }
  5432. } else {
  5433. SystemId = SpPtGetPartitionType(pRegion);
  5434. }
  5435. if (IsContainerPartition(SystemId)) {
  5436. //
  5437. // If this is the extended partition, we want to remove it.
  5438. //
  5439. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5440. "Adding extended region [type %d] %lx for %lx\n",
  5441. SystemId, pRegion->StartSector, pRegion->SectorCount));
  5442. if (!firstRegion) {
  5443. firstRegion = pRegion;
  5444. }
  5445. lastRegion = pRegion;
  5446. } else if ((PartitionNameIds[SystemId] == (UCHAR)(-1)) ||
  5447. (PartitionNameIds[SystemId] == PT(VERIT))) {
  5448. //
  5449. // For a recognized partition, remove it if we have already found
  5450. // a firstRegion; otherwise we will start our list with this
  5451. // region.
  5452. //
  5453. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5454. "Adding recognized region [type %d] %lx for %lx\n",
  5455. SystemId, pRegion->StartSector, pRegion->SectorCount));
  5456. if (!firstRegion) {
  5457. firstRegion = pRegion;
  5458. }
  5459. lastRegion = pRegion;
  5460. } else {
  5461. //
  5462. // If the partition is *not* recognized, and we have a list we
  5463. // have been keeping, then stop before this one, otherwise
  5464. // skip it.
  5465. //
  5466. if (firstRegion) {
  5467. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5468. "Stopping at unrecognized region [type %d] %lx for %lx\n",
  5469. SystemId, pRegion->StartSector, pRegion->SectorCount));
  5470. break;
  5471. } else {
  5472. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5473. "Skipping unrecognized region [type %d] %lx for %lx\n",
  5474. SystemId, pRegion->StartSector, pRegion->SectorCount));
  5475. }
  5476. }
  5477. }
  5478. }
  5479. //
  5480. // We should have found at least one region. If we didn't then the
  5481. // disk is alternating unpartitioned and unrecognized regions. In this
  5482. // case, use the largest unpartitioned region.
  5483. //
  5484. if (firstRegion == NULL) {
  5485. ULONGLONG BiggestUnpartitionedSectorCount = 0;
  5486. pRegion = pDisk->PrimaryDiskRegions;
  5487. for( ; pRegion; pRegion=pRegion->Next) {
  5488. if (!pRegion->PartitionedSpace) {
  5489. if (pRegion->SectorCount > BiggestUnpartitionedSectorCount) {
  5490. firstRegion = pRegion;
  5491. BiggestUnpartitionedSectorCount = pRegion->SectorCount;
  5492. }
  5493. }
  5494. }
  5495. if (firstRegion == NULL) {
  5496. return STATUS_DEVICE_OFF_LINE;
  5497. }
  5498. lastRegion = firstRegion;
  5499. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5500. "Adding single free region %lx for %lx\n",
  5501. firstRegion->StartSector, firstRegion->SectorCount));
  5502. }
  5503. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5504. "first is %lx, last is %lx\n", firstRegion, lastRegion));
  5505. //
  5506. // If we found exactly one region and it has a known filesystem on
  5507. // it, then we don't need to do any repartitioning. We still delete
  5508. // if the filesystem is unknown because later in setup there are
  5509. // some checks that the Filesystem is valid for this region, so by
  5510. // deleting it here we will ensure that Filesystem becomes
  5511. // NewlyCreated which is considered acceptable.
  5512. //
  5513. // We also don't need to repartition if we have just one region
  5514. // and it is already unpartitioned.
  5515. //
  5516. if (firstRegion == lastRegion) {
  5517. SpPtDeleteBootSetsForRegion(firstRegion);
  5518. if (!firstRegion->PartitionedSpace) {
  5519. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5520. "One region, unpartitioned, not repartitioning\n"));
  5521. *RemainingRegion = firstRegion;
  5522. return STATUS_SUCCESS;
  5523. } else if ((firstRegion->Filesystem == FilesystemNtfs) ||
  5524. (firstRegion->Filesystem == FilesystemFat) ||
  5525. (firstRegion->Filesystem == FilesystemFat32)) {
  5526. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
  5527. "One region, filesystem %d, not repartitioning\n",
  5528. firstRegion->Filesystem));
  5529. *RemainingRegion = firstRegion;
  5530. return STATUS_SUCCESS;
  5531. }
  5532. }
  5533. //
  5534. // We need to remove all the regions between firstRegion and
  5535. // lastRegion. Save the start sector of firstRegion for later,
  5536. // since after this call firstRegion may be invalid.
  5537. //
  5538. firstRegionStartSector = firstRegion->StartSector;
  5539. SpPtDeletePartitionsForRemoteBoot(
  5540. pDisk,
  5541. firstRegion,
  5542. lastRegion,
  5543. FALSE // these are not extended regions
  5544. );
  5545. //
  5546. // Now we need to find the region occupying the space we have
  5547. // freed. We scan for the region that includes firstRegionStartSector
  5548. // (the region we find may start before then if there was a small free
  5549. // region before it).
  5550. //
  5551. for (pRegion = pDisk->PrimaryDiskRegions;
  5552. pRegion;
  5553. pRegion=pRegion->Next) {
  5554. if (pRegion->StartSector <= firstRegionStartSector) {
  5555. firstRegion = pRegion;
  5556. } else {
  5557. break;
  5558. }
  5559. }
  5560. //
  5561. // Return this -- SpPtPrepareDisks handles the case where the
  5562. // selected region is free.
  5563. //
  5564. *RemainingRegion = firstRegion;
  5565. return STATUS_SUCCESS;
  5566. }
  5567. //
  5568. // Hard Disk Inialize data for NEC98
  5569. //
  5570. #define IPL_SIZE 0x8000 //NEC98
  5571. NTSTATUS
  5572. SpInitializeHardDisk_Nec98(
  5573. IN PDISK_REGION pRegionDisk
  5574. )
  5575. {
  5576. PHARD_DISK pHardDisk;
  5577. WCHAR DevicePath[(sizeof(DISK_DEVICE_NAME_BASE)+sizeof(L"000"))/sizeof(WCHAR)];
  5578. ULONG i,bps;
  5579. HANDLE Handle;
  5580. NTSTATUS Sts;
  5581. PUCHAR Buffer,UBuffer;
  5582. ULONG buffersize;
  5583. ULONG sectoraddress;
  5584. PUCHAR HdutlBuffer;
  5585. IO_STATUS_BLOCK IoStatusBlock;
  5586. pHardDisk = &HardDisks[pRegionDisk->DiskNumber];
  5587. bps = HardDisks[pRegionDisk->DiskNumber].Geometry.BytesPerSector;
  5588. Sts = SpOpenPartition0(pHardDisk->DevicePath,&Handle,TRUE);
  5589. if(!NT_SUCCESS(Sts)) {
  5590. return(Sts);
  5591. }
  5592. //
  5593. // Initialize Hard Disk
  5594. //
  5595. if(bps==256){
  5596. bps=512;
  5597. }
  5598. HdutlBuffer = SpMemAlloc(IPL_SIZE);
  5599. if(!HdutlBuffer) {
  5600. SpMemFree(HdutlBuffer);
  5601. ZwClose(Handle);
  5602. return(STATUS_NO_MEMORY);
  5603. }
  5604. RtlZeroMemory(HdutlBuffer,IPL_SIZE);
  5605. //
  5606. // Clear head of hard drive, instead of Physical Format.
  5607. //
  5608. Sts = SpReadWriteDiskSectors(Handle,0,(ULONG)(IPL_SIZE/bps),bps,HdutlBuffer,TRUE);
  5609. if(!NT_SUCCESS(Sts)) {
  5610. SpMemFree(HdutlBuffer);
  5611. ZwClose(Handle);
  5612. return(Sts);
  5613. }
  5614. //
  5615. // Set IPL Information
  5616. //
  5617. //
  5618. // Write Boot Code
  5619. //
  5620. sectoraddress=0;
  5621. switch(bps){
  5622. case 2048: buffersize=0x800; break;
  5623. case 1024: buffersize=0x400; break;
  5624. case 256: buffersize=0x100; break;
  5625. case 512: buffersize=0x200; break;
  5626. default : buffersize=0x800; //***max***
  5627. bps=0x800;
  5628. }
  5629. Sts = SpReadWriteDiskSectors(Handle,sectoraddress,(ULONG)(buffersize/bps),bps,x86PC98BootCode,TRUE);
  5630. if(!NT_SUCCESS(Sts)) {
  5631. SpMemFree(HdutlBuffer);
  5632. ZwClose(Handle);
  5633. return(Sts);
  5634. }
  5635. //
  5636. // Write Volume Info
  5637. //
  5638. sectoraddress=1;
  5639. switch(bps){
  5640. case 2048: buffersize=0x800; break; //***1sec***
  5641. case 1024: buffersize=0xc00; break; //***3sec***
  5642. case 256: buffersize=0x300; break; //***3sec***
  5643. case 512: buffersize=0x200; break; //***1sec***
  5644. default : buffersize=0x800; //***max****
  5645. }
  5646. Sts = SpReadWriteDiskSectors(Handle,sectoraddress,(ULONG)(buffersize/bps),bps,HdutlBuffer,TRUE);
  5647. if(!NT_SUCCESS(Sts)) {
  5648. SpMemFree(HdutlBuffer);
  5649. ZwClose(Handle);
  5650. return(Sts);
  5651. }
  5652. //
  5653. // Write Boot Menu
  5654. //
  5655. switch(bps){
  5656. case 2048: buffersize=0x2000; //***8KB***
  5657. sectoraddress=2;
  5658. break;
  5659. case 1024: buffersize=0x2000; //***8KB***
  5660. sectoraddress=4;
  5661. break;
  5662. case 256: buffersize=0x1c00; //***7KB***
  5663. sectoraddress=4;
  5664. break;
  5665. case 512: buffersize=0x1c00; //***7KB***
  5666. sectoraddress=2;
  5667. break;
  5668. default : buffersize=0x1c00; //***min***
  5669. }
  5670. Sts = SpReadWriteDiskSectors(Handle,sectoraddress,(ULONG)(buffersize/bps),bps,x86PC98BootMenu,TRUE);
  5671. if(!NT_SUCCESS(Sts)) {
  5672. SpMemFree(HdutlBuffer);
  5673. return(Sts);
  5674. }
  5675. //
  5676. // Write NTFT Signature.
  5677. //
  5678. RtlZeroMemory(HdutlBuffer,bps);
  5679. ((PULONG)HdutlBuffer)[0] = SpComputeSerialNumber();
  5680. ((PUSHORT)HdutlBuffer)[bps/2 - 1] = BOOT_RECORD_SIGNATURE;
  5681. Sts = SpReadWriteDiskSectors(Handle,16,1,bps,HdutlBuffer,TRUE);
  5682. if(!NT_SUCCESS(Sts)) {
  5683. SpMemFree(HdutlBuffer);
  5684. ZwClose(Handle);
  5685. return(Sts);
  5686. }
  5687. SpMemFree(HdutlBuffer);
  5688. ZwClose(Handle);
  5689. //
  5690. // Do ShutDown
  5691. //
  5692. SpDisplayScreen(SP_SCRN_INIT_REQUIRES_REBOOT_NEC98,3,4);
  5693. SpDisplayStatusOptions(
  5694. DEFAULT_STATUS_ATTRIBUTE,
  5695. SP_STAT_F3_EQUALS_REBOOT,
  5696. 0
  5697. );
  5698. SpInputDrain();
  5699. while(SpInputGetKeypress() != KEY_F3) ;
  5700. HalReturnToFirmware(HalRebootRoutine);
  5701. return(STATUS_SUCCESS);
  5702. }
  5703. VOID
  5704. SpReassignOnDiskOrdinals(
  5705. IN PPARTITIONED_DISK pDisk
  5706. )
  5707. {
  5708. #if defined(NEC_98) //NEC98
  5709. PMBR_INFO pBrInfo;
  5710. ULONG i;
  5711. for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) {
  5712. for(i=0; i<PTABLE_DIMENSION; i++) {
  5713. PON_DISK_PTE pte = &pBrInfo->OnDiskMbr.PartitionTable[i];
  5714. if((pte->SystemId != PARTITION_ENTRY_UNUSED)
  5715. && !IsContainerPartition(pte->SystemId)) {
  5716. //
  5717. // Reset real disk potition into OnDiskordinals.
  5718. // RealDiskPosition value is zero origin, but partition
  5719. // number start one.
  5720. //
  5721. pBrInfo->OnDiskOrdinals[i] = pte->RealDiskPosition + 1;
  5722. } else {
  5723. pBrInfo->OnDiskOrdinals[i] = 0;
  5724. }
  5725. }
  5726. }
  5727. #endif //NEC98
  5728. }
  5729. //
  5730. // Now, only for NEC98.
  5731. //
  5732. VOID
  5733. SpTranslatePteInfo(
  5734. IN PON_DISK_PTE pPte,
  5735. IN PREAL_DISK_PTE pRealPte,
  5736. IN BOOLEAN Write // into real PTE
  5737. )
  5738. {
  5739. ASSERT(pRealPte);
  5740. ASSERT(pPte);
  5741. if( Write ) {
  5742. //
  5743. // Initialize PTE
  5744. //
  5745. RtlZeroMemory(pRealPte, sizeof(REAL_DISK_PTE));
  5746. //
  5747. // Copy PTE entries from real on-disk PTE.
  5748. //
  5749. pRealPte->ActiveFlag = pPte->ActiveFlag;
  5750. pRealPte->StartHead = pPte->StartHead;
  5751. pRealPte->StartSector = pPte->StartSector;
  5752. pRealPte->StartCylinder = pPte->StartCylinder;
  5753. pRealPte->SystemId = pPte->SystemId;
  5754. pRealPte->EndHead = pPte->EndHead;
  5755. pRealPte->EndSector = pPte->EndSector;
  5756. pRealPte->EndCylinder = pPte->EndCylinder;
  5757. RtlMoveMemory(&pRealPte->RelativeSectors, &pPte->RelativeSectors,
  5758. sizeof(pPte->RelativeSectors)); //4
  5759. RtlMoveMemory(&pRealPte->SectorCount, &pPte->SectorCount,
  5760. sizeof(pPte->SectorCount)); //4
  5761. } else {
  5762. //
  5763. // Initialize PTE
  5764. //
  5765. RtlZeroMemory(pPte, sizeof(ON_DISK_PTE));
  5766. //
  5767. // Copy PTE entries from real on-disk PTE.
  5768. //
  5769. pPte->ActiveFlag = pRealPte->ActiveFlag;
  5770. pPte->StartHead = pRealPte->StartHead;
  5771. pPte->StartSector = pRealPte->StartSector;
  5772. pPte->StartCylinder = pRealPte->StartCylinder;
  5773. pPte->SystemId = pRealPte->SystemId;
  5774. pPte->EndHead = pRealPte->EndHead;
  5775. pPte->EndSector = pRealPte->EndSector;
  5776. pPte->EndCylinder = pRealPte->EndCylinder;
  5777. RtlMoveMemory(&pPte->RelativeSectors, &pRealPte->RelativeSectors,
  5778. sizeof(pRealPte->RelativeSectors)); //4
  5779. RtlMoveMemory(&pPte->SectorCount, &pRealPte->SectorCount,
  5780. sizeof(pPte->SectorCount)); //4
  5781. }
  5782. }
  5783. //
  5784. // Now, only for NEC98.
  5785. //
  5786. VOID
  5787. SpTranslateMbrInfo(
  5788. IN PON_DISK_MBR pMbr,
  5789. IN PREAL_DISK_MBR pRealMbr,
  5790. IN ULONG bps,
  5791. IN BOOLEAN Write // into real MBR
  5792. )
  5793. {
  5794. PREAL_DISK_PTE pRealPte;
  5795. PON_DISK_PTE pPte;
  5796. ULONG TmpData;
  5797. ULONG i;
  5798. pRealPte = pRealMbr->PartitionTable;
  5799. pPte = pMbr->PartitionTable;
  5800. ASSERT(pRealMbr);
  5801. ASSERT(pMbr);
  5802. if( Write ) {
  5803. //
  5804. // Initialize REAL_DISK_MBR
  5805. //
  5806. RtlZeroMemory(pRealMbr, sizeof(REAL_DISK_MBR));
  5807. //
  5808. // Copy MBR entries into real on-disk MBR.
  5809. //
  5810. RtlMoveMemory(&pRealMbr->BootCode, &pMbr->BootCode,
  5811. sizeof(pMbr->BootCode)); //440
  5812. RtlMoveMemory(&pRealMbr->NTFTSignature, &pMbr->NTFTSignature,
  5813. sizeof(pMbr->NTFTSignature)); //4
  5814. RtlMoveMemory(&pRealMbr->Filler, &pMbr->Filler,
  5815. sizeof(pMbr->Filler)); //2
  5816. RtlMoveMemory(&pRealMbr->AA55Signature, &pMbr->AA55Signature,
  5817. sizeof(pMbr->AA55Signature)); //2
  5818. } else {
  5819. //
  5820. // Initialize ON_DISK_MBR
  5821. //
  5822. RtlZeroMemory(pMbr, sizeof(ON_DISK_MBR));
  5823. //
  5824. // Copy MBR entries from real on-disk MBR.
  5825. //
  5826. RtlMoveMemory(&pMbr->BootCode, &pRealMbr->BootCode,
  5827. sizeof(pMbr->BootCode)); //440
  5828. RtlMoveMemory(&pMbr->NTFTSignature, &pRealMbr->NTFTSignature,
  5829. sizeof(pMbr->NTFTSignature)); //4
  5830. RtlMoveMemory(&pMbr->Filler, &pRealMbr->Filler,
  5831. sizeof(pMbr->Filler)); //2
  5832. RtlMoveMemory(&pMbr->AA55Signature, &pRealMbr->AA55Signature,
  5833. sizeof(pMbr->AA55Signature)); //2
  5834. }
  5835. //
  5836. // Translate PTEs from real on-disk PTEs.
  5837. //
  5838. for(i=0; i<NUM_PARTITION_TABLE_ENTRIES; i++) {
  5839. SpTranslatePteInfo(&pPte[i], &pRealPte[i], Write);
  5840. }
  5841. }
  5842. VOID
  5843. ConvertPartitionTable(
  5844. IN PPARTITIONED_DISK pDisk,
  5845. IN PUCHAR Buffer,
  5846. IN ULONG bps
  5847. )
  5848. {
  5849. #if defined(NEC_98) //NEC98
  5850. PREAL_DISK_PTE_NEC98 PteNec;
  5851. PON_DISK_PTE p;
  5852. ULONG TmpData;
  5853. ULONG i;
  5854. PteNec = (PREAL_DISK_PTE_NEC98)(Buffer + bps);
  5855. p = pDisk->MbrInfo.OnDiskMbr.PartitionTable;
  5856. for(i=0; i<PTABLE_DIMENSION; i++) {
  5857. switch (PteNec[i].SystemId){
  5858. case 0x00: // not use
  5859. p[i].SystemId = PARTITION_ENTRY_UNUSED;
  5860. break;
  5861. case 0x01: // FAT 12bit
  5862. case 0x81:
  5863. p[i].SystemId = PARTITION_FAT_12;
  5864. break;
  5865. case 0x11: // FAT 16bit
  5866. case 0x91:
  5867. p[i].SystemId = PARTITION_FAT_16;
  5868. break;
  5869. case 0x21: // FAT huge
  5870. case 0xa1:
  5871. p[i].SystemId = PARTITION_HUGE;
  5872. break;
  5873. case 0x31: // IFS
  5874. case 0xb1:
  5875. p[i].SystemId = PARTITION_IFS;
  5876. break;
  5877. case 0x41: // IFS 2nd,orphan
  5878. case 0xc1:
  5879. p[i].SystemId = (PARTITION_IFS | PARTITION_NTFT);
  5880. break;
  5881. case 0x51: // IFS deleted
  5882. case 0xd1:
  5883. p[i].SystemId = (PARTITION_IFS | VALID_NTFT);
  5884. break;
  5885. case 0x61: // FAT32
  5886. case 0xe1:
  5887. p[i].SystemId = PARTITION_FAT32;
  5888. break;
  5889. case 0x08: // FAT 12bit 2nd,orphan
  5890. case 0x88:
  5891. p[i].SystemId = (PARTITION_FAT_12 | PARTITION_NTFT);
  5892. break;
  5893. case 0x18: // FAT 12bit deleted
  5894. case 0x98:
  5895. p[i].SystemId = (PARTITION_FAT_12 | VALID_NTFT);
  5896. break;
  5897. case 0x28: // FAT 16bit 2nd,orphan
  5898. case 0xa8:
  5899. p[i].SystemId = (PARTITION_FAT_16 | PARTITION_NTFT);
  5900. break;
  5901. case 0x38: // FAT 16bit deleted
  5902. case 0xb8:
  5903. p[i].SystemId = (PARTITION_FAT_16 | VALID_NTFT);
  5904. break;
  5905. case 0x48: // FAT huge 2nd,orphan
  5906. case 0xc8:
  5907. p[i].SystemId = (PARTITION_HUGE | PARTITION_NTFT);
  5908. break;
  5909. case 0x58: // FAT huge deleted
  5910. case 0xd8:
  5911. p[i].SystemId = (PARTITION_HUGE | VALID_NTFT);
  5912. break;
  5913. case 0x68: // LDM partition
  5914. case 0xe8:
  5915. p[i].SystemId = PARTITION_LDM;
  5916. break;
  5917. default: // other
  5918. p[i].SystemId = PARTITION_XENIX_1;
  5919. }
  5920. if(p[i].SystemId == PARTITION_ENTRY_UNUSED) {
  5921. p[i].ActiveFlag = 0x00;
  5922. p[i].StartHead = 0x00;
  5923. p[i].StartSector = 0x00;
  5924. p[i].StartCylinderLow = 0x00;
  5925. p[i].StartCylinderHigh = 0x00;
  5926. p[i].EndHead = 0x00;
  5927. p[i].EndSector = 0x00;
  5928. p[i].EndCylinderLow = 0x00;
  5929. p[i].EndCylinderHigh = 0x00;
  5930. p[i].RelativeSectors[0] = 0x00;
  5931. p[i].RelativeSectors[1] = 0x00;
  5932. p[i].RelativeSectors[2] = 0x00;
  5933. p[i].RelativeSectors[3] = 0x00;
  5934. p[i].SectorCount[0] = 0x00;
  5935. p[i].SectorCount[1] = 0x00;
  5936. p[i].SectorCount[2] = 0x00;
  5937. p[i].SectorCount[3] = 0x00;
  5938. p[i].IPLSector = 0x00;
  5939. p[i].IPLHead = 0x00;
  5940. p[i].IPLCylinderLow = 0x00;
  5941. p[i].IPLCylinderHigh = 0x00;
  5942. //p[i].Reserved[2] = 0x00;
  5943. p[i].Reserved[0] = 0x00;
  5944. p[i].Reserved[1] = 0x00;
  5945. p[i].OldSystemId = 0x00;
  5946. memset(p[i].SystemName,0,16);
  5947. } else {
  5948. p[i].ActiveFlag = (PteNec[i].ActiveFlag & 0x80);
  5949. p[i].StartHead = PteNec[i].StartHead;
  5950. p[i].StartSector = PteNec[i].StartSector;
  5951. p[i].StartCylinderLow = PteNec[i].StartCylinderLow;
  5952. p[i].StartCylinderHigh = PteNec[i].StartCylinderHigh;
  5953. p[i].EndHead = PteNec[i].EndHead;
  5954. p[i].EndSector = PteNec[i].EndSector;
  5955. p[i].EndCylinderLow = PteNec[i].EndCylinderLow;
  5956. p[i].EndCylinderHigh = PteNec[i].EndCylinderHigh;
  5957. p[i].IPLSector = PteNec[i].IPLSector;
  5958. p[i].IPLHead = PteNec[i].IPLHead;
  5959. p[i].IPLCylinderLow = PteNec[i].IPLCylinderLow;
  5960. p[i].IPLCylinderHigh = PteNec[i].IPLCylinderHigh;
  5961. p[i].Reserved[0] = PteNec[i].Reserved[0];
  5962. p[i].Reserved[1] = PteNec[i].Reserved[1];
  5963. p[i].OldSystemId = PteNec[i].SystemId;
  5964. memcpy(p[i].SystemName , PteNec[i].SystemName , 16);
  5965. TmpData = (ULONG)PteNec[i].StartCylinderLow;
  5966. TmpData |= ((ULONG)PteNec[i].StartCylinderHigh << 8);
  5967. U_ULONG(p[i].RelativeSectors) = RtlEnlargedUnsignedMultiply(TmpData,
  5968. pDisk->HardDisk->SectorsPerCylinder).LowPart;
  5969. TmpData = (ULONG)(PteNec[i].EndCylinderLow + 1);
  5970. // In case of Low is 0xFF, Overflowed bit will be loss by OR.
  5971. TmpData += ((ULONG)PteNec[i].EndCylinderHigh << 8);
  5972. U_ULONG(p[i].SectorCount) = RtlEnlargedUnsignedMultiply(TmpData,
  5973. pDisk->HardDisk->SectorsPerCylinder).LowPart - U_ULONG(p[i].RelativeSectors);
  5974. //
  5975. // Set Ipl Address
  5976. //
  5977. TmpData = (ULONG)PteNec[i].IPLCylinderLow;
  5978. TmpData |= ((ULONG)PteNec[i].IPLCylinderHigh << 8);
  5979. TmpData = RtlEnlargedUnsignedMultiply(TmpData,pDisk->HardDisk->SectorsPerCylinder).LowPart;
  5980. TmpData += (ULONG)(PteNec[i].IPLHead * pDisk->HardDisk->Geometry.SectorsPerTrack);
  5981. TmpData += PteNec[i].IPLSector;
  5982. U_ULONG(p[i].IPLSectors) = TmpData;
  5983. }
  5984. }
  5985. U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = ((PUSHORT)Buffer)[bps/2 - 1];
  5986. if(bps == 256){
  5987. U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = 0x0000;
  5988. }
  5989. #endif //NEC98
  5990. }
  5991. #define IPL_SIGNATURE_NEC98 "IPL1"
  5992. VOID
  5993. SpDetermineFormatTypeNec98(
  5994. IN PPARTITIONED_DISK pDisk,
  5995. IN PREAL_DISK_MBR_NEC98 pRealMbrNec98
  5996. )
  5997. {
  5998. UCHAR FormatType;
  5999. if(!IsNEC_98) {
  6000. FormatType = DISK_FORMAT_TYPE_PCAT;
  6001. } else {
  6002. if(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) {
  6003. //
  6004. // All removable media are AT format.
  6005. //
  6006. FormatType = DISK_FORMAT_TYPE_PCAT;
  6007. } else {
  6008. if(U_USHORT(pRealMbrNec98->AA55Signature) == MBR_SIGNATURE) {
  6009. if(!_strnicmp(pRealMbrNec98->IPLSignature,IPL_SIGNATURE_NEC98,
  6010. sizeof(IPL_SIGNATURE_NEC98)-1)) {
  6011. //
  6012. // NEC98-format requires AA55Signature and "IPL1".
  6013. //
  6014. FormatType = DISK_FORMAT_TYPE_NEC98;
  6015. } else {
  6016. FormatType = DISK_FORMAT_TYPE_PCAT;
  6017. }
  6018. } else {
  6019. FormatType = DISK_FORMAT_TYPE_UNKNOWN;
  6020. }
  6021. }
  6022. }
  6023. pDisk->HardDisk->FormatType = FormatType;
  6024. #if 0
  6025. pDisk->HardDisk->MaxPartitionTables = ((FormatType == DISK_FORMAT_TYPE_PCAT) ?
  6026. NUM_PARTITION_TABLE_ENTRIES : NUM_PARTITION_TABLE_ENTRIES_NEC98);
  6027. #endif //0
  6028. return;
  6029. }
  6030. NTSTATUS
  6031. SpPtSearchLocalSourcesInDynamicDisk(
  6032. IN ULONG disk
  6033. )
  6034. {
  6035. NTSTATUS Status;
  6036. UNICODE_STRING UnicodeString;
  6037. OBJECT_ATTRIBUTES Obja;
  6038. HANDLE DirectoryHandle;
  6039. BOOLEAN RestartScan;
  6040. ULONG Context;
  6041. BOOLEAN MoreEntries;
  6042. POBJECT_DIRECTORY_INFORMATION DirInfo;
  6043. //
  6044. // Open the \ArcName directory.
  6045. //
  6046. INIT_OBJA(&Obja,&UnicodeString,HardDisks[disk].DevicePath);
  6047. Status = ZwOpenDirectoryObject(&DirectoryHandle,DIRECTORY_ALL_ACCESS,&Obja);
  6048. if(NT_SUCCESS(Status)) {
  6049. RestartScan = TRUE;
  6050. Context = 0;
  6051. MoreEntries = TRUE;
  6052. do {
  6053. Status = SpQueryDirectoryObject(
  6054. DirectoryHandle,
  6055. RestartScan,
  6056. &Context
  6057. );
  6058. if(NT_SUCCESS(Status)) {
  6059. PWSTR DirectoryName;
  6060. DirInfo = (POBJECT_DIRECTORY_INFORMATION)
  6061. ((PSERVICE_QUERY_DIRECTORY_OBJECT)&CommunicationParams->Buffer)->Buffer;
  6062. wcsncpy(TemporaryBuffer,DirInfo->Name.Buffer,DirInfo->Name.Length / sizeof(WCHAR));
  6063. (TemporaryBuffer)[DirInfo->Name.Length/sizeof(WCHAR)] = 0;
  6064. DirectoryName = SpDupStringW(TemporaryBuffer);
  6065. SpStringToLower(TemporaryBuffer);
  6066. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Checking directory object %ws\\%ws \n", HardDisks[disk].DevicePath, DirectoryName));
  6067. if( _wcsicmp(TemporaryBuffer,L"partition0") &&
  6068. wcsstr(TemporaryBuffer,L"partition") ) {
  6069. FilesystemType FsType;
  6070. WCHAR FsName[32];
  6071. ULONG NameId;
  6072. ULONG PartitionNumber;
  6073. PartitionNumber = SpStringToLong( DirectoryName + ((sizeof(L"partition") - sizeof(WCHAR)) / sizeof(WCHAR)),
  6074. NULL,
  6075. 10 );
  6076. FsType = SpIdentifyFileSystem( HardDisks[disk].DevicePath,
  6077. HardDisks[disk].Geometry.BytesPerSector,
  6078. PartitionNumber );
  6079. NameId = SP_TEXT_FS_NAME_BASE + FsType;
  6080. SpFormatMessage( FsName,
  6081. sizeof(FsName),
  6082. NameId );
  6083. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: File system in dynamic volume %ws\\%ws is %ws. \n", HardDisks[disk].DevicePath, DirectoryName, FsName));
  6084. if( FsType >= FilesystemFirstKnown ) {
  6085. PWSTR LocalSourceFiles[1] = { LocalSourceDirectory };
  6086. wcscpy( TemporaryBuffer,HardDisks[disk].DevicePath );
  6087. SpConcatenatePaths( TemporaryBuffer,DirectoryName );
  6088. if(SpNFilesExist(TemporaryBuffer,LocalSourceFiles,ELEMENT_COUNT(LocalSourceFiles),TRUE)) {
  6089. //
  6090. // Found local source directory
  6091. //
  6092. PDISK_REGION pRegion;
  6093. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Found %ws in dynamic volume %ws\\%ws. \n", LocalSourceDirectory, HardDisks[disk].DevicePath, DirectoryName));
  6094. pRegion = SpPtAllocateDiskRegionStructure( disk,
  6095. 0,
  6096. 0,
  6097. TRUE,
  6098. NULL,
  6099. PartitionNumber );
  6100. pRegion->DynamicVolume = TRUE;
  6101. pRegion->DynamicVolumeSuitableForOS = FALSE;
  6102. pRegion->IsLocalSource = TRUE;
  6103. pRegion->Filesystem = FsType;
  6104. LocalSourceRegion = pRegion;
  6105. MoreEntries = FALSE;
  6106. }
  6107. }
  6108. }
  6109. SpMemFree( DirectoryName );
  6110. } else {
  6111. MoreEntries = FALSE;
  6112. if(Status == STATUS_NO_MORE_ENTRIES) {
  6113. Status = STATUS_SUCCESS;
  6114. }
  6115. }
  6116. RestartScan = FALSE;
  6117. } while(MoreEntries);
  6118. ZwClose(DirectoryHandle);
  6119. } else {
  6120. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws directory. Status = %lx\n", HardDisks[disk].DevicePath, Status));
  6121. }
  6122. return( Status );
  6123. }
  6124. VOID
  6125. SpPtFindLocalSourceRegionOnDynamicVolumes(
  6126. VOID
  6127. )
  6128. {
  6129. ULONG disk;
  6130. PPARTITIONED_DISK partdisk;
  6131. PDISK_REGION pRegion;
  6132. BOOLEAN DiskIsDynamic;
  6133. ULONG pass;
  6134. ASSERT(HardDisksDetermined);
  6135. //
  6136. // For each hard disk attached to the system, read its partition table.
  6137. //
  6138. for(disk=0; disk<HardDiskCount && !LocalSourceRegion; disk++) {
  6139. partdisk = &PartitionedDisks[disk];
  6140. DiskIsDynamic = FALSE;
  6141. for( pass=0;
  6142. (pass < 2) && !DiskIsDynamic;
  6143. pass++ ) {
  6144. for( pRegion = ((pass == 0)? partdisk->PrimaryDiskRegions : partdisk->ExtendedDiskRegions);
  6145. pRegion && !DiskIsDynamic;
  6146. pRegion = pRegion->Next ) {
  6147. if( pRegion->DynamicVolume ) {
  6148. //
  6149. // This is a dynamic disk.
  6150. //
  6151. DiskIsDynamic = TRUE;
  6152. //
  6153. // Scan all dynamic volumes in the disk for the $win_nt$.~ls
  6154. //
  6155. SpPtSearchLocalSourcesInDynamicDisk( disk );
  6156. }
  6157. }
  6158. }
  6159. }
  6160. }
  6161. NTSTATUS
  6162. SpPtCheckDynamicVolumeForOSInstallation(
  6163. IN PDISK_REGION Region
  6164. )
  6165. {
  6166. NTSTATUS Status;
  6167. HANDLE Handle;
  6168. IO_STATUS_BLOCK IoStatusBlock;
  6169. PARTITION_INFORMATION PartitionInfo;
  6170. ULONG bps;
  6171. ULONG r;
  6172. ULONG StartSector;
  6173. ULONG SectorCount;
  6174. ULONG RelativeSectors;
  6175. ASSERT(Region->DynamicVolume);
  6176. Status = SpOpenPartition( HardDisks[Region->DiskNumber].DevicePath,
  6177. SpPtGetOrdinal(Region,PartitionOrdinalOnDisk),
  6178. &Handle,
  6179. FALSE );
  6180. #if DBG
  6181. SpNtNameFromRegion( Region,
  6182. TemporaryBuffer,
  6183. sizeof(TemporaryBuffer),
  6184. PartitionOrdinalOnDisk);
  6185. #endif
  6186. if( !NT_SUCCESS(Status) ) {
  6187. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open dynamic volume %ws. Status = %lx\n",TemporaryBuffer, Status));
  6188. return(Status);
  6189. }
  6190. Status = ZwDeviceIoControlFile(
  6191. Handle,
  6192. NULL,
  6193. NULL,
  6194. NULL,
  6195. &IoStatusBlock,
  6196. IOCTL_DISK_GET_PARTITION_INFO,
  6197. NULL,
  6198. 0,
  6199. &PartitionInfo,
  6200. sizeof(PartitionInfo)
  6201. );
  6202. if(NT_SUCCESS(Status)) {
  6203. bps = HardDisks[Region->DiskNumber].Geometry.BytesPerSector;
  6204. RelativeSectors = 0;
  6205. if( SpPtLookupRegionByStart(&PartitionedDisks[Region->DiskNumber],
  6206. TRUE,
  6207. Region->StartSector) == Region ) {
  6208. //
  6209. // The region is on an extended partition (logical drive)
  6210. //
  6211. PON_DISK_PTE pte;
  6212. //
  6213. // TBD : fix this
  6214. //
  6215. pte = &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition];
  6216. RelativeSectors = U_ULONG(pte->RelativeSectors);
  6217. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dynamic volume %ws is logical drive on extended partition. RelativeSectors = %lx \n",TemporaryBuffer, RelativeSectors));
  6218. }
  6219. StartSector = RtlExtendedLargeIntegerDivide(PartitionInfo.StartingOffset,bps,&r).LowPart;
  6220. SectorCount = RtlExtendedLargeIntegerDivide(PartitionInfo.PartitionLength,bps,&r).LowPart;
  6221. Region->DynamicVolumeSuitableForOS = ((Region->StartSector + RelativeSectors) == StartSector) &&
  6222. ((Region->SectorCount - RelativeSectors) == SectorCount);
  6223. if( Region->DynamicVolumeSuitableForOS ) {
  6224. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dynamic volume %ws is suitable for OS installation\n",TemporaryBuffer));
  6225. } else {
  6226. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dynamic volume %ws is not suitable for OS installation\n",TemporaryBuffer));
  6227. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: StartSector = %lx (from MBR)\n", Region->StartSector));
  6228. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SectorCount = %lx (from MBR)\n", Region->SectorCount));
  6229. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: StartSector = %lx (from IOCTL_DISK_GET_PARTITION_INFO)\n", StartSector));
  6230. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SectorCount = %lx (from IOCTL_DISK_GET_PARTITION_INFO)\n", SectorCount));
  6231. }
  6232. } else {
  6233. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get partition info for dynamic volume %ws. Status = %lx\n",TemporaryBuffer, Status));
  6234. }
  6235. ZwClose(Handle);
  6236. return(Status);
  6237. }
  6238. UCHAR
  6239. SpPtGetPartitionType(
  6240. IN PDISK_REGION Region
  6241. )
  6242. {
  6243. UCHAR SystemId = PARTITION_ENTRY_UNUSED;
  6244. if (!Region->PartitionedSpace)
  6245. return SystemId;
  6246. #ifdef OLD_PARTITION_ENGINE
  6247. SystemId = Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition].SystemId;
  6248. #endif
  6249. #ifdef NEW_PARTITION_ENGINE
  6250. SystemId = PARTITION_FAT32;
  6251. if (SPPT_IS_MBR_DISK(Region->DiskNumber)) {
  6252. SystemId = SPPT_GET_PARTITION_TYPE(Region);
  6253. }
  6254. #endif
  6255. #ifdef GPT_PARTITION_ENGINE
  6256. SystemId = PARTITION_FAT32;
  6257. if (SPPT_IS_MBR_DISK(Region->DiskNumber)) {
  6258. SystemId = Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition].SystemId;
  6259. }
  6260. #endif
  6261. return SystemId;
  6262. }
  6263. BOOLEAN
  6264. SpPtnIsRegionSpecialMBRPartition(
  6265. IN PDISK_REGION Region
  6266. )
  6267. {
  6268. BOOLEAN Result = FALSE;
  6269. if (Region && SPPT_IS_MBR_DISK(Region->DiskNumber) &&
  6270. SPPT_IS_REGION_PARTITIONED(Region)) {
  6271. UCHAR PartId = PartitionNameIds[SPPT_GET_PARTITION_TYPE(Region)];
  6272. Result = (PartId != (UCHAR)0xFF) &&
  6273. (SPPT_GET_PARTITION_TYPE(Region) != PARTITION_LDM) &&
  6274. ((PartId + SP_TEXT_PARTITION_NAME_BASE) !=
  6275. SP_TEXT_PARTITION_NAME_UNK);
  6276. }
  6277. return Result;
  6278. }
  6279. PWSTR
  6280. SpPtnGetPartitionName(
  6281. IN PDISK_REGION Region,
  6282. IN OUT PWSTR NameBuffer,
  6283. IN ULONG NameBufferSize
  6284. )
  6285. /*++
  6286. Routine Description:
  6287. Formats the name of the partition, with volume label
  6288. and file system type and returns it.
  6289. Note : Region is assumed to be of partitioned type
  6290. Arguments:
  6291. Region - The region whose name is to be formatted
  6292. NameBuffer - Buffer in which the name needs to be formatted
  6293. NameBuffer - The size of the NameBuffer (in characters)
  6294. Return Value:
  6295. Formatted partition name for the region, if any.
  6296. --*/
  6297. {
  6298. BOOLEAN SpecialPartition = FALSE;
  6299. if (NameBuffer) {
  6300. if (Region) {
  6301. if (SpPtnIsRegionSpecialMBRPartition(Region)) {
  6302. WCHAR Buffer[128];
  6303. SpFormatMessage(Buffer, sizeof(Buffer),
  6304. SP_TEXT_PARTITION_NAME_BASE +
  6305. PartitionNameIds[SPPT_GET_PARTITION_TYPE(Region)]);
  6306. SpFormatMessage(TemporaryBuffer,
  6307. sizeof(TemporaryBuffer),
  6308. SP_TEXT_PARTNAME_DESCR_3,
  6309. Region->PartitionNumber,
  6310. Buffer);
  6311. } else if (Region->VolumeLabel[0]) {
  6312. SpFormatMessage(TemporaryBuffer,
  6313. sizeof(TemporaryBuffer),
  6314. SP_TEXT_PARTNAME_DESCR_1,
  6315. Region->PartitionNumber,
  6316. Region->VolumeLabel,
  6317. Region->TypeName);
  6318. } else {
  6319. SpFormatMessage(TemporaryBuffer,
  6320. sizeof(TemporaryBuffer),
  6321. SP_TEXT_PARTNAME_DESCR_2,
  6322. Region->PartitionNumber,
  6323. Region->TypeName);
  6324. }
  6325. wcsncpy(NameBuffer, TemporaryBuffer, NameBufferSize - 1);
  6326. NameBuffer[NameBufferSize - 1] = 0; // Null terminate
  6327. } else {
  6328. *NameBuffer = 0; // Null terminate
  6329. }
  6330. }
  6331. return NameBuffer;
  6332. }