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

3892 lines
110 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation
  3. Module Name:
  4. hanfnc.c
  5. Abstract:
  6. default handlers for hal functions which don't get handlers
  7. installed by the hal
  8. Author:
  9. Ken Reneris (kenr) 19-July-1994
  10. Revision History:
  11. G.Chrysanthakopoulos (georgioc)
  12. Added support for removable disk with a BPB,instead of a partition table.
  13. All changes in HalIoReadParitionTable. Started 01-June-1996
  14. --*/
  15. #include "ntos.h"
  16. #include "zwapi.h"
  17. #include "hal.h"
  18. #include "ntdddisk.h"
  19. #include "haldisp.h"
  20. #include "ntddft.h"
  21. #include "mountmgr.h"
  22. #include "stdio.h"
  23. #include <setupblk.h>
  24. #include "drivesup.h"
  25. #include "fstub.h"
  26. //
  27. // Macro definitions
  28. //
  29. #define GET_STARTING_SECTOR( p ) ( \
  30. (ULONG) (p->StartingSectorLsb0) + \
  31. (ULONG) (p->StartingSectorLsb1 << 8) + \
  32. (ULONG) (p->StartingSectorMsb0 << 16) + \
  33. (ULONG) (p->StartingSectorMsb1 << 24) )
  34. #define GET_PARTITION_LENGTH( p ) ( \
  35. (ULONG) (p->PartitionLengthLsb0) + \
  36. (ULONG) (p->PartitionLengthLsb1 << 8) + \
  37. (ULONG) (p->PartitionLengthMsb0 << 16) + \
  38. (ULONG) (p->PartitionLengthMsb1 << 24) )
  39. //
  40. // Structure for determing if an 0xaa55 marked sector has a BPB in it.
  41. //
  42. typedef struct _BOOT_SECTOR_INFO {
  43. UCHAR JumpByte[1];
  44. UCHAR Ignore1[2];
  45. UCHAR OemData[8];
  46. UCHAR BytesPerSector[2];
  47. UCHAR Ignore2[6];
  48. UCHAR NumberOfSectors[2];
  49. UCHAR MediaByte[1];
  50. UCHAR Ignore3[2];
  51. UCHAR SectorsPerTrack[2];
  52. UCHAR NumberOfHeads[2];
  53. } BOOT_SECTOR_INFO, *PBOOT_SECTOR_INFO;
  54. typedef struct _PARTITION_TABLE {
  55. PARTITION_INFORMATION PartitionEntry[4];
  56. } PARTITION_TABLE, *PPARTITION_TABLE;
  57. typedef struct _DISK_LAYOUT {
  58. ULONG TableCount;
  59. ULONG Signature;
  60. PARTITION_TABLE PartitionTable[1];
  61. } DISK_LAYOUT, *PDISK_LAYOUT;
  62. typedef struct _PTE {
  63. UCHAR ActiveFlag; // Bootable or not
  64. UCHAR StartingTrack; // Not used
  65. USHORT StartingCylinder; // Not used
  66. UCHAR PartitionType; // 12 bit FAT, 16 bit FAT etc.
  67. UCHAR EndingTrack; // Not used
  68. USHORT EndingCylinder; // Not used
  69. ULONG StartingSector; // Hidden sectors
  70. ULONG PartitionLength; // Sectors in this partition
  71. } PTE;
  72. typedef PTE UNALIGNED *PPTE;
  73. //
  74. // Strings definitions
  75. //
  76. static PUCHAR DiskPartitionName = "\\Device\\Harddisk%d\\Partition%d";
  77. static PUCHAR RegistryKeyName = DISK_REGISTRY_KEY;
  78. VOID
  79. HalpCalculateChsValues(
  80. IN PLARGE_INTEGER PartitionOffset,
  81. IN PLARGE_INTEGER PartitionLength,
  82. IN CCHAR ShiftCount,
  83. IN ULONG SectorsPerTrack,
  84. IN ULONG NumberOfTracks,
  85. IN ULONG ConventionalCylinders,
  86. OUT PPARTITION_DESCRIPTOR PartitionDescriptor
  87. );
  88. NTSTATUS
  89. HalpQueryPartitionType(
  90. IN PUNICODE_STRING DeviceName,
  91. IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
  92. OUT PULONG PartitionType
  93. );
  94. NTSTATUS
  95. HalpQueryDriveLayout(
  96. IN PUNICODE_STRING DeviceName,
  97. OUT PDRIVE_LAYOUT_INFORMATION* DriveLayout
  98. );
  99. VOID
  100. FASTCALL
  101. xHalGetPartialGeometry(
  102. IN PDEVICE_OBJECT DeviceObject,
  103. IN PULONG ConventionalCylinders,
  104. IN PLONGLONG DiskSize
  105. );
  106. NTSTATUS
  107. HalpGetFullGeometry(
  108. IN PDEVICE_OBJECT DeviceObject,
  109. IN PDISK_GEOMETRY Geometry,
  110. OUT PULONGLONG RealSectorCount
  111. );
  112. BOOLEAN
  113. HalpIsValidPartitionEntry(
  114. PPARTITION_DESCRIPTOR Entry,
  115. ULONGLONG MaxOffset,
  116. ULONGLONG MaxSector
  117. );
  118. NTSTATUS
  119. HalpNextMountLetter(
  120. IN PUNICODE_STRING DeviceName,
  121. OUT PUCHAR DriveLetter
  122. );
  123. UCHAR
  124. HalpNextDriveLetter(
  125. IN PUNICODE_STRING DeviceName,
  126. IN PSTRING NtDeviceName,
  127. OUT PUCHAR NtSystemPath,
  128. IN BOOLEAN UseHardLinksIfNecessary
  129. );
  130. VOID
  131. HalpEnableAutomaticDriveLetterAssignment(
  132. );
  133. NTSTATUS
  134. HalpSetMountLetter(
  135. IN PUNICODE_STRING DeviceName,
  136. IN UCHAR DriveLetter
  137. );
  138. BOOLEAN
  139. HalpIsOldStyleFloppy(
  140. IN PUNICODE_STRING DeviceName
  141. );
  142. PULONG
  143. IopComputeHarddiskDerangements(
  144. IN ULONG DiskCount
  145. );
  146. VOID
  147. FstubFixupEfiPartition(
  148. IN PPARTITION_DESCRIPTOR Entry,
  149. IN ULONGLONG MaxSector
  150. );
  151. #ifdef ALLOC_PRAGMA
  152. #pragma alloc_text(PAGE, HalpCalculateChsValues)
  153. #pragma alloc_text(PAGE, HalpQueryPartitionType)
  154. #pragma alloc_text(PAGE, HalpQueryDriveLayout)
  155. #pragma alloc_text(PAGE, HalpNextMountLetter)
  156. #pragma alloc_text(PAGE, HalpNextDriveLetter)
  157. #pragma alloc_text(PAGE, HalpEnableAutomaticDriveLetterAssignment)
  158. #pragma alloc_text(PAGE, HalpSetMountLetter)
  159. #pragma alloc_text(PAGE, IoAssignDriveLetters)
  160. #pragma alloc_text(PAGE, IoReadPartitionTable)
  161. #pragma alloc_text(PAGE, IoSetPartitionInformation)
  162. #pragma alloc_text(PAGE, IoWritePartitionTable)
  163. #pragma alloc_text(PAGE, HalpIsValidPartitionEntry)
  164. #pragma alloc_text(PAGE, HalpGetFullGeometry)
  165. #pragma alloc_text(PAGE, HalpIsOldStyleFloppy)
  166. #pragma alloc_text(PAGE, IopComputeHarddiskDerangements)
  167. #pragma alloc_text(PAGE, FstubFixupEfiPartition)
  168. #endif
  169. VOID
  170. FASTCALL
  171. HalExamineMBR(
  172. IN PDEVICE_OBJECT DeviceObject,
  173. IN ULONG SectorSize,
  174. IN ULONG MBRTypeIdentifier,
  175. OUT PVOID *Buffer
  176. )
  177. /*++
  178. Routine Description:
  179. Given a master boot record type (MBR - the zero'th sector on the disk),
  180. read the master boot record of a disk. If the MBR is found to be of that
  181. type, allocate a structure whose layout is dependant upon that partition
  182. type, fill with the appropriate values, and return a pointer to that buffer
  183. in the output parameter.
  184. The best example for a use of this routine is to support Ontrack
  185. systems DiskManager software. Ontrack software lays down a special
  186. partition describing the entire drive. The special partition type
  187. (0x54) will be recognized and a couple of longwords of data will
  188. be passed back in a buffer for a disk driver to act upon.
  189. Arguments:
  190. DeviceObject - The device object describing the entire drive.
  191. SectorSize - The minimum number of bytes that an IO operation can
  192. fetch.
  193. MBRIndentifier - A value that will be searched for in the
  194. in the MBR. This routine will understand
  195. the semantics implied by this value.
  196. Buffer - Pointer to a buffer that returns data according to the
  197. type of MBR searched for. If the MBR is not of the
  198. type asked for, the buffer will not be allocated and this
  199. pointer will be NULL. It is the responsibility of the
  200. caller of HalExamineMBR to deallocate the buffer. The
  201. caller should deallocate the memory ASAP.
  202. Return Value:
  203. None.
  204. --*/
  205. {
  206. LARGE_INTEGER partitionTableOffset;
  207. PUCHAR readBuffer = (PUCHAR) NULL;
  208. KEVENT event;
  209. IO_STATUS_BLOCK ioStatus;
  210. PIRP irp;
  211. PPARTITION_DESCRIPTOR partitionTableEntry;
  212. NTSTATUS status = STATUS_SUCCESS;
  213. ULONG readSize;
  214. *Buffer = NULL;
  215. //
  216. // Determine the size of a read operation to ensure that at least 512
  217. // bytes are read. This will guarantee that enough data is read to
  218. // include an entire partition table. Note that this code assumes that
  219. // the actual sector size of the disk (if less than 512 bytes) is a
  220. // multiple of 2, a fairly reasonable assumption.
  221. //
  222. if (SectorSize >= 512) {
  223. readSize = SectorSize;
  224. } else {
  225. readSize = 512;
  226. }
  227. //
  228. // Start at sector 0 of the device.
  229. //
  230. partitionTableOffset = RtlConvertUlongToLargeInteger( 0 );
  231. //
  232. // Allocate a buffer that will hold the reads.
  233. //
  234. readBuffer = ExAllocatePoolWithTag(
  235. NonPagedPoolCacheAligned,
  236. PAGE_SIZE>readSize?PAGE_SIZE:readSize,
  237. 'btsF'
  238. );
  239. if (readBuffer == NULL) {
  240. return;
  241. }
  242. //
  243. // Read record containing partition table.
  244. //
  245. // Create a notification event object to be used while waiting for
  246. // the read request to complete.
  247. //
  248. KeInitializeEvent( &event, NotificationEvent, FALSE );
  249. irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  250. DeviceObject,
  251. readBuffer,
  252. readSize,
  253. &partitionTableOffset,
  254. &event,
  255. &ioStatus );
  256. if (!irp) {
  257. ExFreePool(readBuffer);
  258. return;
  259. } else {
  260. PIO_STACK_LOCATION irpStack;
  261. irpStack = IoGetNextIrpStackLocation(irp);
  262. irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  263. }
  264. status = IoCallDriver( DeviceObject, irp );
  265. if (status == STATUS_PENDING) {
  266. (VOID) KeWaitForSingleObject( &event,
  267. Executive,
  268. KernelMode,
  269. FALSE,
  270. (PLARGE_INTEGER) NULL);
  271. status = ioStatus.Status;
  272. }
  273. if (!NT_SUCCESS( status )) {
  274. ExFreePool(readBuffer);
  275. return;
  276. }
  277. //
  278. // Check for Boot Record signature.
  279. //
  280. if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  281. ExFreePool(readBuffer);
  282. return;
  283. }
  284. //
  285. // Check for DM type partition.
  286. //
  287. partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]);
  288. if (partitionTableEntry->PartitionType != MBRTypeIdentifier) {
  289. //
  290. // The partition type isn't what the caller cares about.
  291. //
  292. ExFreePool(readBuffer);
  293. } else {
  294. if (partitionTableEntry->PartitionType == 0x54) {
  295. //
  296. // Rather than allocate a new piece of memory to return
  297. // the data - just use the memory allocated for the buffer.
  298. // We can assume the caller will delete this shortly.
  299. //
  300. ((PULONG)readBuffer)[0] = 63;
  301. *Buffer = readBuffer;
  302. } else if (partitionTableEntry->PartitionType == 0x55) {
  303. //
  304. // EzDrive Parititon. Simply return the pointer to non-null
  305. // There is no skewing here.
  306. //
  307. *Buffer = readBuffer;
  308. } else {
  309. ASSERT(partitionTableEntry->PartitionType == 0x55);
  310. }
  311. }
  312. }
  313. VOID
  314. FASTCALL
  315. xHalGetPartialGeometry(
  316. IN PDEVICE_OBJECT DeviceObject,
  317. IN PULONG ConventionalCylinders,
  318. IN PLONGLONG DiskSize
  319. )
  320. /*++
  321. Routine Description:
  322. We need this routine to get the number of cylinders that the disk driver
  323. thinks is on the drive. We will need this to calculate CHS values
  324. when we fill in the partition table entries.
  325. Arguments:
  326. DeviceObject - The device object describing the entire drive.
  327. ConventionalCylinders - Number of cylinders on the drive.
  328. Return Value:
  329. None.
  330. --*/
  331. {
  332. PIRP localIrp;
  333. PDISK_GEOMETRY diskGeometry;
  334. PIO_STATUS_BLOCK iosb;
  335. PKEVENT eventPtr;
  336. NTSTATUS status;
  337. *ConventionalCylinders = 0UL;
  338. *DiskSize = 0UL;
  339. diskGeometry = ExAllocatePoolWithTag(
  340. NonPagedPool,
  341. sizeof(DISK_GEOMETRY),
  342. 'btsF'
  343. );
  344. if (!diskGeometry) {
  345. return;
  346. }
  347. iosb = ExAllocatePoolWithTag(
  348. NonPagedPool,
  349. sizeof(IO_STATUS_BLOCK),
  350. 'btsF'
  351. );
  352. if (!iosb) {
  353. ExFreePool(diskGeometry);
  354. return;
  355. }
  356. eventPtr = ExAllocatePoolWithTag(
  357. NonPagedPool,
  358. sizeof(KEVENT),
  359. 'btsF'
  360. );
  361. if (!eventPtr) {
  362. ExFreePool(iosb);
  363. ExFreePool(diskGeometry);
  364. return;
  365. }
  366. KeInitializeEvent(
  367. eventPtr,
  368. NotificationEvent,
  369. FALSE
  370. );
  371. localIrp = IoBuildDeviceIoControlRequest(
  372. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  373. DeviceObject,
  374. NULL,
  375. 0UL,
  376. diskGeometry,
  377. sizeof(DISK_GEOMETRY),
  378. FALSE,
  379. eventPtr,
  380. iosb
  381. );
  382. if (!localIrp) {
  383. ExFreePool(eventPtr);
  384. ExFreePool(iosb);
  385. ExFreePool(diskGeometry);
  386. return;
  387. }
  388. //
  389. // Call the lower level driver, wait for the opertion
  390. // to finish.
  391. //
  392. status = IoCallDriver(
  393. DeviceObject,
  394. localIrp
  395. );
  396. if (status == STATUS_PENDING) {
  397. (VOID) KeWaitForSingleObject(
  398. eventPtr,
  399. Executive,
  400. KernelMode,
  401. FALSE,
  402. (PLARGE_INTEGER) NULL
  403. );
  404. status = iosb->Status;
  405. }
  406. if (NT_SUCCESS(status)) {
  407. //
  408. // The operation completed successfully. Get the cylinder
  409. // count of the drive.
  410. //
  411. *ConventionalCylinders = diskGeometry->Cylinders.LowPart;
  412. //
  413. // If the count is less than 1024 we can pass that back. Otherwise
  414. // send back the 1024
  415. //
  416. if (diskGeometry->Cylinders.QuadPart >= (LONGLONG)1024) {
  417. *ConventionalCylinders = 1024;
  418. }
  419. //
  420. // Calculate disk size from gemotry information
  421. //
  422. *DiskSize = diskGeometry->Cylinders.QuadPart *
  423. diskGeometry->TracksPerCylinder *
  424. diskGeometry->SectorsPerTrack *
  425. diskGeometry->BytesPerSector;
  426. }
  427. ExFreePool(eventPtr);
  428. ExFreePool(iosb);
  429. ExFreePool(diskGeometry);
  430. return;
  431. }
  432. VOID
  433. HalpCalculateChsValues(
  434. IN PLARGE_INTEGER PartitionOffset,
  435. IN PLARGE_INTEGER PartitionLength,
  436. IN CCHAR ShiftCount,
  437. IN ULONG SectorsPerTrack,
  438. IN ULONG NumberOfTracks,
  439. IN ULONG ConventionalCylinders,
  440. OUT PPARTITION_DESCRIPTOR PartitionDescriptor
  441. )
  442. /*++
  443. Routine Description:
  444. This routine will determine the cylinder, head, and sector (CHS) values
  445. that should be placed in a partition table entry, given the partition's
  446. location on the disk and its size. The values calculated are packed into
  447. int13 format -- the high two bits of the sector byte contain bits 8 and 9
  448. of the 10 bit cylinder value, the low 6 bits of the sector byte contain
  449. the 6 bit sector value; the cylinder byte contains the low 8 bits
  450. of the cylinder value; and the head byte contains the 8-bit head value.
  451. Both the start and end CHS values are calculated.
  452. Arguments:
  453. PartitionOffset - Byte offset of the partition, relative to the entire
  454. physical disk.
  455. PartitionLength - Size in bytes of the partition.
  456. ShiftCount - Shift count to convert from byte counts to sector counts.
  457. SectorsPerTrack - Number of sectors in a track on the media on which
  458. the partition resides.
  459. NumberOfTracks - Number of tracks in a cylinder on the media on which
  460. the partition resides.
  461. ConventionalCylinders - The "normalized" disk cylinders. We will never
  462. set the cylinders greater than this.
  463. PartitionDescriptor - Structure to be filled in with the start and
  464. end CHS values. Other fields in the structure are not referenced
  465. or modified.
  466. Return Value:
  467. None.
  468. Note:
  469. The Cylinder and Head values are 0-based but the Sector value is 1-based.
  470. If the start or end cylinder overflows 10 bits (ie, > 1023), CHS values
  471. will be set to all 1's.
  472. No checking is done on the SectorsPerTrack and NumberOfTrack values.
  473. --*/
  474. {
  475. ULONG startSector, sectorCount, endSector;
  476. ULONG sectorsPerCylinder;
  477. ULONG remainder;
  478. ULONG startC, startH, startS, endC, endH, endS;
  479. LARGE_INTEGER tempInt;
  480. PAGED_CODE();
  481. //
  482. // Calculate the number of sectors in a cylinder. This is the
  483. // number of heads multiplied by the number of sectors per track.
  484. //
  485. sectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
  486. //
  487. // Convert byte offset/count to sector offset/count.
  488. //
  489. tempInt.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
  490. startSector = tempInt.LowPart;
  491. tempInt.QuadPart = PartitionLength->QuadPart >> ShiftCount;
  492. sectorCount = tempInt.LowPart;
  493. endSector = startSector + sectorCount - 1;
  494. startC = startSector / sectorsPerCylinder;
  495. endC = endSector / sectorsPerCylinder;
  496. if (!ConventionalCylinders) {
  497. ConventionalCylinders = 1024;
  498. }
  499. //
  500. // Set these values so that win95 is happy.
  501. //
  502. if (startC >= ConventionalCylinders) {
  503. startC = ConventionalCylinders - 1;
  504. }
  505. if (endC >= ConventionalCylinders) {
  506. endC = ConventionalCylinders - 1;
  507. }
  508. //
  509. // Calculate the starting track and sector.
  510. //
  511. remainder = startSector % sectorsPerCylinder;
  512. startH = remainder / SectorsPerTrack;
  513. startS = remainder % SectorsPerTrack;
  514. //
  515. // Calculate the ending track and sector.
  516. //
  517. remainder = endSector % sectorsPerCylinder;
  518. endH = remainder / SectorsPerTrack;
  519. endS = remainder % SectorsPerTrack;
  520. //
  521. // Pack the result into the caller's structure.
  522. //
  523. // low 8 bits of the cylinder => C value
  524. PartitionDescriptor->StartingCylinderMsb = (UCHAR) startC;
  525. PartitionDescriptor->EndingCylinderMsb = (UCHAR) endC;
  526. // 8 bits of head value => H value
  527. PartitionDescriptor->StartingTrack = (UCHAR) startH;
  528. PartitionDescriptor->EndingTrack = (UCHAR) endH;
  529. // bits 8-9 of cylinder and 6 bits of the sector => S value
  530. PartitionDescriptor->StartingCylinderLsb = (UCHAR) (((startS + 1) & 0x3f)
  531. | ((startC >> 2) & 0xc0));
  532. PartitionDescriptor->EndingCylinderLsb = (UCHAR) (((endS + 1) & 0x3f)
  533. | ((endC >> 2) & 0xc0));
  534. }
  535. #define BOOTABLE_PARTITION 0
  536. #define PRIMARY_PARTITION 1
  537. #define LOGICAL_PARTITION 2
  538. #define FT_PARTITION 3
  539. #define OTHER_PARTITION 4
  540. #define GPT_PARTITION 5
  541. NTSTATUS
  542. HalpQueryPartitionType(
  543. IN PUNICODE_STRING DeviceName,
  544. IN PDRIVE_LAYOUT_INFORMATION DriveLayout,
  545. OUT PULONG PartitionType
  546. )
  547. {
  548. NTSTATUS status;
  549. PFILE_OBJECT fileObject;
  550. PDEVICE_OBJECT deviceObject;
  551. KEVENT event;
  552. PIRP irp;
  553. PARTITION_INFORMATION_EX partInfo;
  554. IO_STATUS_BLOCK ioStatus;
  555. ULONG i;
  556. status = IoGetDeviceObjectPointer(DeviceName,
  557. FILE_READ_ATTRIBUTES,
  558. &fileObject, &deviceObject);
  559. if (!NT_SUCCESS(status)) {
  560. return status;
  561. }
  562. deviceObject = IoGetAttachedDeviceReference(fileObject->DeviceObject);
  563. ObDereferenceObject(fileObject);
  564. if (deviceObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  565. ObDereferenceObject(deviceObject);
  566. *PartitionType = LOGICAL_PARTITION;
  567. return STATUS_SUCCESS;
  568. }
  569. KeInitializeEvent(&event, NotificationEvent, FALSE);
  570. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
  571. deviceObject, NULL, 0, &partInfo,
  572. sizeof(partInfo), FALSE, &event,
  573. &ioStatus);
  574. if (!irp) {
  575. ObDereferenceObject(deviceObject);
  576. return STATUS_INSUFFICIENT_RESOURCES;
  577. }
  578. status = IoCallDriver(deviceObject, irp);
  579. if (status == STATUS_PENDING) {
  580. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  581. status = ioStatus.Status;
  582. }
  583. ObDereferenceObject(deviceObject);
  584. if (!NT_SUCCESS(status)) {
  585. if (!DriveLayout) {
  586. *PartitionType = LOGICAL_PARTITION;
  587. return STATUS_SUCCESS;
  588. }
  589. return status;
  590. }
  591. if (partInfo.PartitionStyle != PARTITION_STYLE_MBR) {
  592. if (partInfo.PartitionStyle != PARTITION_STYLE_GPT) {
  593. *PartitionType = OTHER_PARTITION;
  594. return STATUS_SUCCESS;
  595. }
  596. if (IsEqualGUID(&partInfo.Gpt.PartitionType,
  597. &PARTITION_BASIC_DATA_GUID)) {
  598. *PartitionType = GPT_PARTITION;
  599. return STATUS_SUCCESS;
  600. }
  601. *PartitionType = OTHER_PARTITION;
  602. return STATUS_SUCCESS;
  603. }
  604. if (!IsRecognizedPartition(partInfo.Mbr.PartitionType)) {
  605. *PartitionType = OTHER_PARTITION;
  606. return STATUS_SUCCESS;
  607. }
  608. if (partInfo.Mbr.PartitionType&0x80) {
  609. *PartitionType = FT_PARTITION;
  610. return STATUS_SUCCESS;
  611. }
  612. if (!DriveLayout) {
  613. *PartitionType = LOGICAL_PARTITION;
  614. return STATUS_SUCCESS;
  615. }
  616. for (i = 0; i < 4; i++) {
  617. if (partInfo.StartingOffset.QuadPart ==
  618. DriveLayout->PartitionEntry[i].StartingOffset.QuadPart) {
  619. if (partInfo.Mbr.BootIndicator) {
  620. *PartitionType = BOOTABLE_PARTITION;
  621. } else {
  622. *PartitionType = PRIMARY_PARTITION;
  623. }
  624. return STATUS_SUCCESS;
  625. }
  626. }
  627. *PartitionType = LOGICAL_PARTITION;
  628. return STATUS_SUCCESS;
  629. }
  630. NTSTATUS
  631. HalpQueryDriveLayout(
  632. IN PUNICODE_STRING DeviceName,
  633. OUT PDRIVE_LAYOUT_INFORMATION* DriveLayout
  634. )
  635. {
  636. NTSTATUS status;
  637. PFILE_OBJECT fileObject;
  638. PDEVICE_OBJECT deviceObject;
  639. KEVENT event;
  640. PIRP irp;
  641. DISK_GEOMETRY geometry;
  642. IO_STATUS_BLOCK ioStatus;
  643. status = IoGetDeviceObjectPointer(DeviceName, FILE_READ_ATTRIBUTES,
  644. &fileObject, &deviceObject);
  645. if (!NT_SUCCESS(status)) {
  646. return status;
  647. }
  648. deviceObject = IoGetAttachedDeviceReference(fileObject->DeviceObject);
  649. ObDereferenceObject(fileObject);
  650. if (deviceObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  651. ObDereferenceObject(deviceObject);
  652. return STATUS_NO_MEDIA;
  653. }
  654. KeInitializeEvent(&event, NotificationEvent, FALSE);
  655. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  656. deviceObject, NULL, 0, &geometry,
  657. sizeof(geometry), FALSE, &event,
  658. &ioStatus);
  659. if (!irp) {
  660. ObDereferenceObject(deviceObject);
  661. return STATUS_INSUFFICIENT_RESOURCES;
  662. }
  663. status = IoCallDriver(deviceObject, irp);
  664. if (status == STATUS_PENDING) {
  665. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  666. status = ioStatus.Status;
  667. }
  668. if (!NT_SUCCESS(status)) {
  669. ObDereferenceObject(deviceObject);
  670. return status;
  671. }
  672. status = IoReadPartitionTable(deviceObject, geometry.BytesPerSector,
  673. FALSE, DriveLayout);
  674. ObDereferenceObject(deviceObject);
  675. return status;
  676. }
  677. NTSTATUS
  678. HalpNextMountLetter(
  679. IN PUNICODE_STRING DeviceName,
  680. OUT PUCHAR DriveLetter
  681. )
  682. /*++
  683. Routine Description:
  684. This routine gives the device the next available drive letter.
  685. Arguments:
  686. DeviceName - Supplies the device name.
  687. DriveLetter - Returns the drive letter assigned or 0.
  688. Return Value:
  689. NTSTATUS
  690. --*/
  691. {
  692. UNICODE_STRING name;
  693. PFILE_OBJECT fileObject;
  694. PDEVICE_OBJECT deviceObject;
  695. PMOUNTMGR_DRIVE_LETTER_TARGET input;
  696. KEVENT event;
  697. PIRP irp;
  698. MOUNTMGR_DRIVE_LETTER_INFORMATION output;
  699. IO_STATUS_BLOCK ioStatus;
  700. NTSTATUS status;
  701. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  702. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  703. &deviceObject);
  704. if (!NT_SUCCESS(status)) {
  705. return status;
  706. }
  707. input = ExAllocatePoolWithTag(PagedPool,
  708. (sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) +
  709. DeviceName->Length),
  710. 'btsF'
  711. );
  712. if (!input) {
  713. ObDereferenceObject(fileObject);
  714. return STATUS_INSUFFICIENT_RESOURCES;
  715. }
  716. input->DeviceNameLength = DeviceName->Length;
  717. RtlCopyMemory(input->DeviceName, DeviceName->Buffer, DeviceName->Length);
  718. KeInitializeEvent(&event, NotificationEvent, FALSE);
  719. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
  720. deviceObject, input,
  721. sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) +
  722. DeviceName->Length, &output,
  723. sizeof(output), FALSE, &event,
  724. &ioStatus);
  725. if (!irp) {
  726. ExFreePool(input);
  727. ObDereferenceObject(fileObject);
  728. return STATUS_INSUFFICIENT_RESOURCES;
  729. }
  730. status = IoCallDriver(deviceObject, irp);
  731. if (status == STATUS_PENDING) {
  732. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  733. status = ioStatus.Status;
  734. }
  735. ExFreePool(input);
  736. ObDereferenceObject(fileObject);
  737. *DriveLetter = output.CurrentDriveLetter;
  738. return status;
  739. }
  740. UCHAR
  741. HalpNextDriveLetter(
  742. IN PUNICODE_STRING DeviceName,
  743. IN PSTRING NtDeviceName,
  744. OUT PUCHAR NtSystemPath,
  745. IN BOOLEAN UseHardLinksIfNecessary
  746. )
  747. /*++
  748. Routine Description:
  749. This routine gives the device the next available drive letter.
  750. Arguments:
  751. DeviceName - Supplies the device name.
  752. NtDeviceName - Supplies the NT device name.
  753. NtSystemPath - Supplies the NT system path.
  754. Return Value:
  755. The drive letter assigned or 0.
  756. --*/
  757. {
  758. NTSTATUS status;
  759. UCHAR firstDriveLetter, driveLetter;
  760. WCHAR name[40];
  761. UNICODE_STRING symName;
  762. UNICODE_STRING unicodeString, floppyPrefix, cdromPrefix;
  763. status = HalpNextMountLetter(DeviceName, &driveLetter);
  764. if (NT_SUCCESS(status)) {
  765. return driveLetter;
  766. }
  767. if (!NtDeviceName || !NtSystemPath) {
  768. return 0xFF;
  769. }
  770. if (!UseHardLinksIfNecessary) {
  771. return 0;
  772. }
  773. RtlInitUnicodeString(&floppyPrefix, L"\\Device\\Floppy");
  774. RtlInitUnicodeString(&cdromPrefix, L"\\Device\\CdRom");
  775. if (RtlPrefixUnicodeString(&floppyPrefix, DeviceName, TRUE)) {
  776. firstDriveLetter = 'A';
  777. } else if (RtlPrefixUnicodeString(&cdromPrefix, DeviceName, TRUE)) {
  778. firstDriveLetter = 'D';
  779. } else {
  780. firstDriveLetter = 'C';
  781. }
  782. for (driveLetter = firstDriveLetter; driveLetter <= 'Z'; driveLetter++) {
  783. status = HalpSetMountLetter(DeviceName, driveLetter);
  784. if (NT_SUCCESS(status)) {
  785. RtlAnsiStringToUnicodeString(&unicodeString, NtDeviceName, TRUE);
  786. if (RtlEqualUnicodeString(&unicodeString, DeviceName, TRUE)) {
  787. NtSystemPath[0] = driveLetter;
  788. }
  789. RtlFreeUnicodeString(&unicodeString);
  790. return driveLetter;
  791. }
  792. }
  793. for (driveLetter = firstDriveLetter; driveLetter <= 'Z'; driveLetter++) {
  794. swprintf(name, L"\\DosDevices\\%c:", driveLetter);
  795. RtlInitUnicodeString(&symName, name);
  796. status = IoCreateSymbolicLink(&symName, DeviceName);
  797. if (NT_SUCCESS(status)) {
  798. RtlAnsiStringToUnicodeString(&unicodeString, NtDeviceName, TRUE);
  799. if (RtlEqualUnicodeString(&unicodeString, DeviceName, TRUE)) {
  800. NtSystemPath[0] = driveLetter;
  801. }
  802. RtlFreeUnicodeString(&unicodeString);
  803. return driveLetter;
  804. }
  805. }
  806. return 0;
  807. }
  808. VOID
  809. HalpEnableAutomaticDriveLetterAssignment(
  810. )
  811. /*++
  812. Routine Description:
  813. This routine enables automatic drive letter assignment by the mount
  814. point manager.
  815. Arguments:
  816. None.
  817. Return Value:
  818. None.
  819. --*/
  820. {
  821. UNICODE_STRING name;
  822. PFILE_OBJECT fileObject;
  823. PDEVICE_OBJECT deviceObject;
  824. KEVENT event;
  825. PIRP irp;
  826. IO_STATUS_BLOCK ioStatus;
  827. NTSTATUS status;
  828. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  829. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  830. &deviceObject);
  831. if (!NT_SUCCESS(status)) {
  832. return;
  833. }
  834. KeInitializeEvent(&event, NotificationEvent, FALSE);
  835. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS,
  836. deviceObject, NULL, 0, NULL, 0, FALSE,
  837. &event, &ioStatus);
  838. if (!irp) {
  839. ObDereferenceObject(fileObject);
  840. return;
  841. }
  842. status = IoCallDriver(deviceObject, irp);
  843. if (status == STATUS_PENDING) {
  844. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  845. status = ioStatus.Status;
  846. }
  847. ObDereferenceObject(fileObject);
  848. }
  849. NTSTATUS
  850. HalpSetMountLetter(
  851. IN PUNICODE_STRING DeviceName,
  852. IN UCHAR DriveLetter
  853. )
  854. /*++
  855. Routine Description:
  856. This routine sets the drive letter for the given device.
  857. Arguments:
  858. DeviceName - Supplies the device name.
  859. DriveLetter - Supplies the drive letter.
  860. Return Value:
  861. NTSTATUS
  862. --*/
  863. {
  864. WCHAR dosBuffer[30];
  865. UNICODE_STRING dosName;
  866. ULONG createPointSize;
  867. PMOUNTMGR_CREATE_POINT_INPUT createPoint;
  868. UNICODE_STRING name;
  869. NTSTATUS status;
  870. PFILE_OBJECT fileObject;
  871. PDEVICE_OBJECT deviceObject;
  872. KEVENT event;
  873. PIRP irp;
  874. IO_STATUS_BLOCK ioStatus;
  875. swprintf(dosBuffer, L"\\DosDevices\\%c:", DriveLetter);
  876. RtlInitUnicodeString(&dosName, dosBuffer);
  877. createPointSize = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
  878. dosName.Length + DeviceName->Length;
  879. createPoint = (PMOUNTMGR_CREATE_POINT_INPUT)
  880. ExAllocatePoolWithTag(PagedPool, createPointSize, 'btsF');
  881. if (!createPoint) {
  882. return STATUS_INSUFFICIENT_RESOURCES;
  883. }
  884. createPoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  885. createPoint->SymbolicLinkNameLength = dosName.Length;
  886. createPoint->DeviceNameOffset = createPoint->SymbolicLinkNameOffset +
  887. createPoint->SymbolicLinkNameLength;
  888. createPoint->DeviceNameLength = DeviceName->Length;
  889. RtlCopyMemory((PCHAR) createPoint + createPoint->SymbolicLinkNameOffset,
  890. dosName.Buffer, dosName.Length);
  891. RtlCopyMemory((PCHAR) createPoint + createPoint->DeviceNameOffset,
  892. DeviceName->Buffer, DeviceName->Length);
  893. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  894. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  895. &deviceObject);
  896. if (!NT_SUCCESS(status)) {
  897. ExFreePool(createPoint);
  898. return status;
  899. }
  900. KeInitializeEvent(&event, NotificationEvent, FALSE);
  901. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CREATE_POINT,
  902. deviceObject, createPoint,
  903. createPointSize, NULL, 0, FALSE,
  904. &event, &ioStatus);
  905. if (!irp) {
  906. ObDereferenceObject(fileObject);
  907. ExFreePool(createPoint);
  908. return STATUS_INSUFFICIENT_RESOURCES;
  909. }
  910. status = IoCallDriver(deviceObject, irp);
  911. if (status == STATUS_PENDING) {
  912. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  913. status = ioStatus.Status;
  914. }
  915. ObDereferenceObject(fileObject);
  916. ExFreePool(createPoint);
  917. return status;
  918. }
  919. BOOLEAN
  920. HalpIsOldStyleFloppy(
  921. IN PUNICODE_STRING DeviceName
  922. )
  923. /*++
  924. Routine Description:
  925. This routine determines whether or not the given device is an old style
  926. floppy. That is, a floppy controlled by a traditional floppy controller.
  927. These floppies have precedent in the drive letter ordering.
  928. Arguments:
  929. DeviceName - Supplies the device name.
  930. Return Value:
  931. FALSE - The given device is not an old style floppy.
  932. TRUE - The given device is an old style floppy.
  933. --*/
  934. {
  935. PFILE_OBJECT fileObject;
  936. PDEVICE_OBJECT deviceObject;
  937. KEVENT event;
  938. PIRP irp;
  939. MOUNTDEV_NAME name;
  940. IO_STATUS_BLOCK ioStatus;
  941. NTSTATUS status;
  942. PAGED_CODE();
  943. status = IoGetDeviceObjectPointer(DeviceName, FILE_READ_ATTRIBUTES,
  944. &fileObject, &deviceObject);
  945. if (!NT_SUCCESS(status)) {
  946. return FALSE;
  947. }
  948. deviceObject = IoGetAttachedDeviceReference(fileObject->DeviceObject);
  949. ObDereferenceObject(fileObject);
  950. KeInitializeEvent(&event, NotificationEvent, FALSE);
  951. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
  952. deviceObject, NULL, 0, &name,
  953. sizeof(name), FALSE, &event,
  954. &ioStatus);
  955. if (!irp) {
  956. ObDereferenceObject(deviceObject);
  957. return FALSE;
  958. }
  959. status = IoCallDriver(deviceObject, irp);
  960. if (status == STATUS_PENDING) {
  961. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  962. status = ioStatus.Status;
  963. }
  964. ObDereferenceObject(deviceObject);
  965. if (status == STATUS_BUFFER_OVERFLOW) {
  966. return FALSE;
  967. }
  968. return TRUE;
  969. }
  970. PULONG
  971. IopComputeHarddiskDerangements(
  972. IN ULONG DiskCount
  973. )
  974. /*++
  975. Routine Description:
  976. This routine returns an array of hard disk numbers in the correct firmware
  977. (BIOS) order. It does this by using the \ArcName\multi() names.
  978. Arguments:
  979. DiskCount - Supplies the number of disks in the system.
  980. Return Value:
  981. An array of hard disk numbers. The caller must free this list with
  982. ExFreePool.
  983. --*/
  984. {
  985. PULONG r;
  986. ULONG i, j;
  987. WCHAR deviceNameBuffer[50];
  988. UNICODE_STRING deviceName;
  989. NTSTATUS status;
  990. PFILE_OBJECT fileObject;
  991. PDEVICE_OBJECT deviceObject;
  992. KEVENT event;
  993. PIRP irp;
  994. STORAGE_DEVICE_NUMBER number;
  995. IO_STATUS_BLOCK ioStatus;
  996. if (DiskCount == 0) {
  997. return NULL;
  998. }
  999. r = ExAllocatePool(PagedPool|POOL_COLD_ALLOCATION, DiskCount*sizeof(ULONG));
  1000. if (!r) {
  1001. return NULL;
  1002. }
  1003. for (i = 0; i < DiskCount; i++) {
  1004. swprintf(deviceNameBuffer, L"\\ArcName\\multi(0)disk(0)rdisk(%d)", i);
  1005. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1006. status = IoGetDeviceObjectPointer(&deviceName, FILE_READ_ATTRIBUTES,
  1007. &fileObject, &deviceObject);
  1008. if (!NT_SUCCESS(status)) {
  1009. r[i] = (ULONG) -1;
  1010. continue;
  1011. }
  1012. deviceObject = IoGetAttachedDeviceReference(fileObject->DeviceObject);
  1013. ObDereferenceObject(fileObject);
  1014. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1015. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
  1016. deviceObject, NULL, 0, &number,
  1017. sizeof(number), FALSE, &event,
  1018. &ioStatus);
  1019. if (!irp) {
  1020. ObDereferenceObject(deviceObject);
  1021. r[i] = (ULONG) -1;
  1022. continue;
  1023. }
  1024. status = IoCallDriver(deviceObject, irp);
  1025. if (status == STATUS_PENDING) {
  1026. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1027. status = ioStatus.Status;
  1028. }
  1029. ObDereferenceObject(deviceObject);
  1030. if (!NT_SUCCESS(status)) {
  1031. r[i] = (ULONG) -1;
  1032. continue;
  1033. }
  1034. r[i] = number.DeviceNumber;
  1035. }
  1036. for (i = 0; i < DiskCount; i++) {
  1037. for (j = 0; j < DiskCount; j++) {
  1038. if (r[j] == i) {
  1039. break;
  1040. }
  1041. }
  1042. if (j < DiskCount) {
  1043. continue;
  1044. }
  1045. for (j = 0; j < DiskCount; j++) {
  1046. if (r[j] == (ULONG) -1) {
  1047. r[j] = i;
  1048. break;
  1049. }
  1050. }
  1051. }
  1052. return r;
  1053. }
  1054. VOID
  1055. FASTCALL
  1056. IoAssignDriveLetters(
  1057. IN struct _LOADER_PARAMETER_BLOCK *LoaderBlock,
  1058. IN PSTRING NtDeviceName,
  1059. OUT PUCHAR NtSystemPath,
  1060. OUT PSTRING NtSystemPathString
  1061. )
  1062. /*++
  1063. Routine Description:
  1064. This routine assigns DOS drive letters to eligible disk partitions
  1065. and CDROM drives. It also maps the partition containing the NT
  1066. boot path to \SystemRoot. In NT, objects are built for all partition
  1067. types except 0 (unused) and 5 (extended). But drive letters are assigned
  1068. only to recognized partition types (1, 4, 6, 7, e).
  1069. Drive letter assignment is done in several stages:
  1070. 1) For each CdRom:
  1071. Determine if sticky letters are assigned and reserve the letter.
  1072. 2) For each disk:
  1073. Determine how many primary partitions and which is bootable.
  1074. Determine which partitions already have 'sticky letters'
  1075. and create their symbolic links.
  1076. Create a bit map for each disk that idicates which partitions
  1077. require default drive letter assignments.
  1078. 3) For each disk:
  1079. Assign default drive letters for the bootable
  1080. primary partition or the first nonbootable primary partition.
  1081. 4) For each disk:
  1082. Assign default drive letters for the partitions in
  1083. extended volumes.
  1084. 5) For each disk:
  1085. Assign default drive letters for the remaining (ENHANCED)
  1086. primary partitions.
  1087. 6) Assign A: and B: to the first two floppies in the system if they
  1088. exist. Then assign remaining floppies next available drive letters.
  1089. 7) Assign drive letters to CdRoms (either sticky or default).
  1090. Arguments:
  1091. LoaderBlock - pointer to a loader parameter block.
  1092. NtDeviceName - pointer to the boot device name string used
  1093. to resolve NtSystemPath.
  1094. Return Value:
  1095. None.
  1096. --*/
  1097. {
  1098. PUCHAR ntName;
  1099. STRING ansiString;
  1100. UNICODE_STRING unicodeString;
  1101. PUCHAR ntPhysicalName;
  1102. STRING ansiPhysicalString;
  1103. UNICODE_STRING unicodePhysicalString;
  1104. NTSTATUS status;
  1105. OBJECT_ATTRIBUTES objectAttributes;
  1106. PCONFIGURATION_INFORMATION configurationInformation;
  1107. ULONG diskCount;
  1108. ULONG floppyCount;
  1109. HANDLE deviceHandle;
  1110. IO_STATUS_BLOCK ioStatusBlock;
  1111. ULONG diskNumber;
  1112. ULONG i, j, k;
  1113. UCHAR driveLetter;
  1114. WCHAR deviceNameBuffer[50];
  1115. UNICODE_STRING deviceName, floppyPrefix, cdromPrefix;
  1116. PDRIVE_LAYOUT_INFORMATION layout;
  1117. BOOLEAN bootable;
  1118. ULONG partitionType;
  1119. ULONG skip;
  1120. ULONG diskCountIncrement;
  1121. ULONG actualDiskCount = 0;
  1122. PULONG harddiskDerangementArray;
  1123. PAGED_CODE();
  1124. //
  1125. // Get the count of devices from the registry.
  1126. //
  1127. configurationInformation = IoGetConfigurationInformation();
  1128. diskCount = configurationInformation->DiskCount;
  1129. floppyCount = configurationInformation->FloppyCount;
  1130. //
  1131. // Allocate general NT name buffer.
  1132. //
  1133. ntName = ExAllocatePoolWithTag( NonPagedPool, 128, 'btsF');
  1134. ntPhysicalName = ExAllocatePoolWithTag( NonPagedPool, 64, 'btsF');
  1135. if (ntName == NULL || ntPhysicalName == NULL) {
  1136. KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
  1137. }
  1138. //
  1139. // If we're doing a remote boot, set NtSystemPath appropriately.
  1140. //
  1141. if (IoRemoteBootClient) {
  1142. PUCHAR p;
  1143. PUCHAR q;
  1144. //
  1145. // If this is a remote boot setup boot, NtBootPathName is of the
  1146. // form \<server>\<share>\setup\<install-directory>\<platform>.
  1147. // We want the root of the X: drive to be the root of the install
  1148. // directory.
  1149. //
  1150. // If this is a normal remote boot, NtBootPathName is of the form
  1151. // \<server>\<share>\images\<machine>\winnt. We want the root of
  1152. // the X: drive to be the root of the machine directory.
  1153. //
  1154. // Thus in either case, we need to remove all but the last element
  1155. // of the path.
  1156. //
  1157. // Find the beginning of the last element of the path (including
  1158. // the leading backslash).
  1159. //
  1160. p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator
  1161. q = NULL;
  1162. if ( (p != NULL) && (*(p+1) == 0) ) {
  1163. //
  1164. // NtBootPathName ends with a backslash, so we need to back up
  1165. // to the previous backslash.
  1166. //
  1167. q = p;
  1168. *q = 0;
  1169. p = strrchr( LoaderBlock->NtBootPathName, '\\' ); // find last separator
  1170. *q = '\\';
  1171. }
  1172. if ( p == NULL ) {
  1173. KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
  1174. }
  1175. //
  1176. // Set NtSystemPath to X:\<last element of path>. Note that the symbolic
  1177. // link for X: is created in io\ioinit.c\IopInitializeBootDrivers.
  1178. //
  1179. // Note that we use X: for the textmode setup phase of a remote
  1180. // installation. But for a true remote boot, we use C:.
  1181. //
  1182. #if defined(REMOTE_BOOT)
  1183. if ((LoaderBlock->SetupLoaderBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL |
  1184. SETUPBLK_FLAGS_SYSPREP_INSTALL)) == 0) {
  1185. NtSystemPath[0] = 'C';
  1186. } else
  1187. #endif
  1188. {
  1189. NtSystemPath[0] = 'X';
  1190. }
  1191. NtSystemPath[1] = ':';
  1192. strcpy(&NtSystemPath[2], p );
  1193. if ( q != NULL ) {
  1194. NtSystemPath[strlen(NtSystemPath)-1] = '\0'; // remove trailing backslash
  1195. }
  1196. RtlInitString(NtSystemPathString, NtSystemPath);
  1197. }
  1198. //
  1199. // For each disk ...
  1200. //
  1201. diskCountIncrement = 0;
  1202. for (diskNumber = 0; diskNumber < diskCount; diskNumber++) {
  1203. //
  1204. // Create ANSI name string for physical disk.
  1205. //
  1206. sprintf( ntName, DiskPartitionName, diskNumber, 0 );
  1207. //
  1208. // Convert to unicode string.
  1209. //
  1210. RtlInitAnsiString( &ansiString, ntName );
  1211. RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
  1212. InitializeObjectAttributes( &objectAttributes,
  1213. &unicodeString,
  1214. OBJ_CASE_INSENSITIVE,
  1215. NULL,
  1216. NULL );
  1217. //
  1218. // Open device by name.
  1219. //
  1220. status = ZwOpenFile( &deviceHandle,
  1221. FILE_READ_DATA | SYNCHRONIZE,
  1222. &objectAttributes,
  1223. &ioStatusBlock,
  1224. FILE_SHARE_READ,
  1225. FILE_SYNCHRONOUS_IO_NONALERT );
  1226. if (NT_SUCCESS( status )) {
  1227. //
  1228. // The device was successfully opened. Generate a DOS device name
  1229. // for the drive itself.
  1230. //
  1231. sprintf( ntPhysicalName, "\\DosDevices\\PhysicalDrive%d", diskNumber );
  1232. RtlInitAnsiString( &ansiPhysicalString, ntPhysicalName );
  1233. RtlAnsiStringToUnicodeString( &unicodePhysicalString, &ansiPhysicalString, TRUE );
  1234. IoCreateSymbolicLink( &unicodePhysicalString, &unicodeString );
  1235. RtlFreeUnicodeString( &unicodePhysicalString );
  1236. ZwClose(deviceHandle);
  1237. actualDiskCount = diskNumber + 1;
  1238. }
  1239. RtlFreeUnicodeString( &unicodeString );
  1240. if (!NT_SUCCESS( status )) {
  1241. #if DBG
  1242. DbgPrint( "IoAssignDriveLetters: Failed to open %s\n", ntName );
  1243. #endif // DBG
  1244. //
  1245. // This may be a sparse name space. Try going farther but
  1246. // not forever.
  1247. //
  1248. if (diskCountIncrement < 50) {
  1249. diskCountIncrement++;
  1250. diskCount++;
  1251. }
  1252. }
  1253. } // end for diskNumber ...
  1254. ExFreePool( ntName );
  1255. ExFreePool( ntPhysicalName );
  1256. diskCount -= diskCountIncrement;
  1257. if (actualDiskCount > diskCount) {
  1258. diskCount = actualDiskCount;
  1259. }
  1260. harddiskDerangementArray = IopComputeHarddiskDerangements(diskCount);
  1261. for (k = 0; k < diskCount; k++) {
  1262. if (harddiskDerangementArray) {
  1263. i = harddiskDerangementArray[k];
  1264. } else {
  1265. i = k;
  1266. }
  1267. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition0", i);
  1268. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1269. status = HalpQueryDriveLayout(&deviceName, &layout);
  1270. if (!NT_SUCCESS(status)) {
  1271. layout = NULL;
  1272. }
  1273. bootable = FALSE;
  1274. for (j = 1; ; j++) {
  1275. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d",
  1276. i, j);
  1277. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1278. status = HalpQueryPartitionType(&deviceName, layout,
  1279. &partitionType);
  1280. if (!NT_SUCCESS(status)) {
  1281. break;
  1282. }
  1283. if (partitionType != BOOTABLE_PARTITION &&
  1284. partitionType != GPT_PARTITION) {
  1285. continue;
  1286. }
  1287. bootable = TRUE;
  1288. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE);
  1289. if (partitionType == BOOTABLE_PARTITION) {
  1290. break;
  1291. }
  1292. }
  1293. if (bootable) {
  1294. if (layout) {
  1295. ExFreePool(layout);
  1296. }
  1297. continue;
  1298. }
  1299. for (j = 1; ; j++) {
  1300. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d",
  1301. i, j);
  1302. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1303. status = HalpQueryPartitionType(&deviceName, layout,
  1304. &partitionType);
  1305. if (!NT_SUCCESS(status)) {
  1306. break;
  1307. }
  1308. if (partitionType != PRIMARY_PARTITION) {
  1309. continue;
  1310. }
  1311. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE);
  1312. break;
  1313. }
  1314. if (layout) {
  1315. ExFreePool(layout);
  1316. }
  1317. }
  1318. for (k = 0; k < diskCount; k++) {
  1319. if (harddiskDerangementArray) {
  1320. i = harddiskDerangementArray[k];
  1321. } else {
  1322. i = k;
  1323. }
  1324. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition0", i);
  1325. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1326. status = HalpQueryDriveLayout(&deviceName, &layout);
  1327. if (!NT_SUCCESS(status)) {
  1328. layout = NULL;
  1329. }
  1330. for (j = 1; ; j++) {
  1331. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d",
  1332. i, j);
  1333. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1334. status = HalpQueryPartitionType(&deviceName, layout,
  1335. &partitionType);
  1336. if (!NT_SUCCESS(status)) {
  1337. break;
  1338. }
  1339. if (partitionType != LOGICAL_PARTITION) {
  1340. continue;
  1341. }
  1342. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE);
  1343. }
  1344. if (layout) {
  1345. ExFreePool(layout);
  1346. }
  1347. }
  1348. for (k = 0; k < diskCount; k++) {
  1349. if (harddiskDerangementArray) {
  1350. i = harddiskDerangementArray[k];
  1351. } else {
  1352. i = k;
  1353. }
  1354. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition0", i);
  1355. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1356. status = HalpQueryDriveLayout(&deviceName, &layout);
  1357. if (!NT_SUCCESS(status)) {
  1358. layout = NULL;
  1359. }
  1360. skip = 0;
  1361. for (j = 1; ; j++) {
  1362. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d",
  1363. i, j);
  1364. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1365. status = HalpQueryPartitionType(&deviceName, layout,
  1366. &partitionType);
  1367. if (!NT_SUCCESS(status)) {
  1368. break;
  1369. }
  1370. if (partitionType == BOOTABLE_PARTITION) {
  1371. skip = j;
  1372. } else if (partitionType == PRIMARY_PARTITION) {
  1373. if (!skip) {
  1374. skip = j;
  1375. }
  1376. }
  1377. }
  1378. for (j = 1; ; j++) {
  1379. if (j == skip) {
  1380. continue;
  1381. }
  1382. swprintf(deviceNameBuffer, L"\\Device\\Harddisk%d\\Partition%d",
  1383. i, j);
  1384. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1385. status = HalpQueryPartitionType(&deviceName, layout,
  1386. &partitionType);
  1387. if (!NT_SUCCESS(status)) {
  1388. break;
  1389. }
  1390. if (partitionType != PRIMARY_PARTITION &&
  1391. partitionType != FT_PARTITION) {
  1392. continue;
  1393. }
  1394. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, FALSE);
  1395. }
  1396. if (layout) {
  1397. ExFreePool(layout);
  1398. }
  1399. }
  1400. if (harddiskDerangementArray) {
  1401. ExFreePool(harddiskDerangementArray);
  1402. }
  1403. for (i = 0; i < floppyCount; i++) {
  1404. swprintf(deviceNameBuffer, L"\\Device\\Floppy%d", i);
  1405. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1406. if (!HalpIsOldStyleFloppy(&deviceName)) {
  1407. continue;
  1408. }
  1409. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, TRUE);
  1410. }
  1411. for (i = 0; i < floppyCount; i++) {
  1412. swprintf(deviceNameBuffer, L"\\Device\\Floppy%d", i);
  1413. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1414. if (HalpIsOldStyleFloppy(&deviceName)) {
  1415. continue;
  1416. }
  1417. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, TRUE);
  1418. }
  1419. for (i = 0; i < configurationInformation->CdRomCount; i++) {
  1420. swprintf(deviceNameBuffer, L"\\Device\\CdRom%d", i);
  1421. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1422. HalpNextDriveLetter(&deviceName, NtDeviceName, NtSystemPath, TRUE);
  1423. }
  1424. if (!IoRemoteBootClient) {
  1425. RtlAnsiStringToUnicodeString(&unicodeString, NtDeviceName, TRUE);
  1426. driveLetter = HalpNextDriveLetter(&unicodeString, NULL, NULL, TRUE);
  1427. if (driveLetter) {
  1428. if (driveLetter != 0xFF) {
  1429. NtSystemPath[0] = driveLetter;
  1430. }
  1431. } else {
  1432. RtlInitUnicodeString(&floppyPrefix, L"\\Device\\Floppy");
  1433. RtlInitUnicodeString(&cdromPrefix, L"\\Device\\CdRom");
  1434. if (RtlPrefixUnicodeString(&floppyPrefix, &unicodeString, TRUE)) {
  1435. driveLetter = 'A';
  1436. } else if (RtlPrefixUnicodeString(&cdromPrefix, &unicodeString, TRUE)) {
  1437. driveLetter = 'D';
  1438. } else {
  1439. driveLetter = 'C';
  1440. }
  1441. for (; driveLetter <= 'Z'; driveLetter++) {
  1442. status = HalpSetMountLetter(&unicodeString, driveLetter);
  1443. if (NT_SUCCESS(status)) {
  1444. NtSystemPath[0] = driveLetter;
  1445. }
  1446. }
  1447. }
  1448. RtlFreeUnicodeString(&unicodeString);
  1449. }
  1450. HalpEnableAutomaticDriveLetterAssignment();
  1451. } // end IoAssignDriveLetters()
  1452. NTSTATUS
  1453. FASTCALL
  1454. IoReadPartitionTable(
  1455. IN PDEVICE_OBJECT DeviceObject,
  1456. IN ULONG SectorSize,
  1457. IN BOOLEAN ReturnRecognizedPartitions,
  1458. OUT struct _DRIVE_LAYOUT_INFORMATION **PartitionBuffer
  1459. )
  1460. /*++
  1461. Routine Description:
  1462. This routine walks the disk reading the partition tables and creates
  1463. an entry in the partition list buffer for each partition.
  1464. The algorithm used by this routine is two-fold:
  1465. 1) Read each partition table and for each valid, recognized
  1466. partition found, to build a descriptor in a partition list.
  1467. Extended partitions are located in order to find other
  1468. partition tables, but no descriptors are built for these.
  1469. The partition list is built in nonpaged pool that is allocated
  1470. by this routine. It is the caller's responsibility to free
  1471. this pool after it has gathered the appropriate information
  1472. from the list.
  1473. 2) Read each partition table and for each and every entry, build
  1474. a descriptor in the partition list. Extended partitions are
  1475. located to find each partition table on the disk, and entries
  1476. are built for these as well. The partition list is build in
  1477. nonpaged pool that is allocated by this routine. It is the
  1478. caller's responsibility to free this pool after it has copied
  1479. the information back to its caller.
  1480. The first algorithm is used when the ReturnRecognizedPartitions flag
  1481. is set. This is used to determine how many partition device objects
  1482. the device driver is to create, and where each lives on the drive.
  1483. The second algorithm is used when the ReturnRecognizedPartitions flag
  1484. is clear. This is used to find all of the partition tables and their
  1485. entries for a utility such as fdisk, that would like to revamp where
  1486. the partitions live.
  1487. Arguments:
  1488. DeviceObject - Pointer to device object for this disk.
  1489. SectorSize - Sector size on the device.
  1490. ReturnRecognizedPartitions - A flag indicated whether only recognized
  1491. partition descriptors are to be returned, or whether all partition
  1492. entries are to be returned.
  1493. PartitionBuffer - Pointer to the pointer of the buffer in which the list
  1494. of partition will be stored.
  1495. Return Value:
  1496. The functional value is STATUS_SUCCESS if at least one sector table was
  1497. read.
  1498. Notes:
  1499. It is the responsibility of the caller to deallocate the partition list
  1500. buffer allocated by this routine.
  1501. --*/
  1502. {
  1503. ULONG partitionBufferSize = PARTITION_BUFFER_SIZE;
  1504. PDRIVE_LAYOUT_INFORMATION newPartitionBuffer = NULL;
  1505. LONG partitionTableCounter = -1;
  1506. DISK_GEOMETRY diskGeometry;
  1507. ULONGLONG endSector;
  1508. ULONGLONG maxSector;
  1509. ULONGLONG maxOffset;
  1510. LARGE_INTEGER partitionTableOffset;
  1511. LARGE_INTEGER volumeStartOffset;
  1512. LARGE_INTEGER tempInt;
  1513. BOOLEAN primaryPartitionTable;
  1514. LONG partitionNumber;
  1515. PUCHAR readBuffer = (PUCHAR) NULL;
  1516. KEVENT event;
  1517. IO_STATUS_BLOCK ioStatus;
  1518. PIRP irp;
  1519. PPARTITION_DESCRIPTOR partitionTableEntry;
  1520. CCHAR partitionEntry;
  1521. NTSTATUS status = STATUS_SUCCESS;
  1522. ULONG readSize;
  1523. PPARTITION_INFORMATION partitionInfo;
  1524. BOOLEAN foundEZHooker = FALSE;
  1525. BOOLEAN mbrSignatureFound = FALSE;
  1526. BOOLEAN emptyPartitionTable = TRUE;
  1527. PAGED_CODE();
  1528. //
  1529. // Create the buffer that will be passed back to the driver containing
  1530. // the list of partitions on the disk.
  1531. //
  1532. *PartitionBuffer = ExAllocatePoolWithTag( NonPagedPool,
  1533. partitionBufferSize,
  1534. 'btsF' );
  1535. if (*PartitionBuffer == NULL) {
  1536. return STATUS_INSUFFICIENT_RESOURCES;
  1537. }
  1538. //
  1539. // Determine the size of a read operation to ensure that at least 512
  1540. // bytes are read. This will guarantee that enough data is read to
  1541. // include an entire partition table. Note that this code assumes that
  1542. // the actual sector size of the disk (if less than 512 bytes) is a
  1543. // multiple of 2, a fairly reasonable assumption.
  1544. //
  1545. if (SectorSize >= 512) {
  1546. readSize = SectorSize;
  1547. } else {
  1548. readSize = 512;
  1549. }
  1550. //
  1551. // Look to see if this is an EZDrive Disk. If it is then get the
  1552. // real parititon table at 1.
  1553. //
  1554. {
  1555. PVOID buff;
  1556. HalExamineMBR(
  1557. DeviceObject,
  1558. readSize,
  1559. (ULONG)0x55,
  1560. &buff
  1561. );
  1562. if (buff) {
  1563. foundEZHooker = TRUE;
  1564. ExFreePool(buff);
  1565. partitionTableOffset.QuadPart = 512;
  1566. } else {
  1567. partitionTableOffset.QuadPart = 0;
  1568. }
  1569. }
  1570. //
  1571. // Get the drive size so we can verify that the partition table is
  1572. // correct.
  1573. //
  1574. status = HalpGetFullGeometry(DeviceObject,
  1575. &diskGeometry,
  1576. &maxOffset);
  1577. if(!NT_SUCCESS(status)) {
  1578. ExFreePool(*PartitionBuffer);
  1579. *PartitionBuffer = NULL;
  1580. return status;
  1581. }
  1582. //
  1583. // Partition offsets need to fit on the disk or we're not going to
  1584. // expose them. Partition ends are generally very very sloppy so we
  1585. // need to allow some slop. Adding in a cylinders worth isn't enough
  1586. // so now we'll assume that all partitions end within 2x of the real end
  1587. // of the disk.
  1588. //
  1589. endSector = maxOffset;
  1590. maxSector = maxOffset * 2;
  1591. KdPrintEx((DPFLTR_FSTUB_ID,
  1592. DPFLTR_TRACE_LEVEL,
  1593. "FSTUB: MaxOffset = %#I64x, maxSector = %#I64x\n",
  1594. maxOffset,
  1595. maxSector));
  1596. //
  1597. // Indicate that the primary partition table is being read and
  1598. // processed.
  1599. //
  1600. primaryPartitionTable = TRUE;
  1601. //
  1602. // The partitions in this volume have their start sector as 0.
  1603. //
  1604. volumeStartOffset.QuadPart = 0;
  1605. //
  1606. // Initialize the number of partitions in the list.
  1607. //
  1608. partitionNumber = -1;
  1609. //
  1610. // Allocate a buffer that will hold the reads.
  1611. //
  1612. readBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1613. PAGE_SIZE,
  1614. 'btsF' );
  1615. if (readBuffer == NULL) {
  1616. ExFreePool( *PartitionBuffer );
  1617. return STATUS_INSUFFICIENT_RESOURCES;
  1618. }
  1619. //
  1620. // Read each partition table, create an object for the partition(s)
  1621. // it represents, and then if there is a link entry to another
  1622. // partition table, repeat.
  1623. //
  1624. do {
  1625. BOOLEAN tableIsValid;
  1626. ULONG containerPartitionCount;
  1627. tableIsValid = TRUE;
  1628. //
  1629. // Read record containing partition table.
  1630. //
  1631. // Create a notification event object to be used while waiting for
  1632. // the read request to complete.
  1633. //
  1634. KeInitializeEvent( &event, NotificationEvent, FALSE );
  1635. //
  1636. // Zero out the buffer we're reading into. In case we get back
  1637. // STATUS_NO_DATA_DETECTED we'll be prepared.
  1638. //
  1639. RtlZeroMemory(readBuffer, readSize);
  1640. irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  1641. DeviceObject,
  1642. readBuffer,
  1643. readSize,
  1644. &partitionTableOffset,
  1645. &event,
  1646. &ioStatus );
  1647. if (!irp) {
  1648. status = STATUS_INSUFFICIENT_RESOURCES;
  1649. break;
  1650. } else {
  1651. PIO_STACK_LOCATION irpStack;
  1652. irpStack = IoGetNextIrpStackLocation(irp);
  1653. irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  1654. }
  1655. status = IoCallDriver( DeviceObject, irp );
  1656. if (status == STATUS_PENDING) {
  1657. (VOID) KeWaitForSingleObject( &event,
  1658. Executive,
  1659. KernelMode,
  1660. FALSE,
  1661. (PLARGE_INTEGER) NULL);
  1662. status = ioStatus.Status;
  1663. }
  1664. //
  1665. // Special case - if we got a blank-check reading the sector then
  1666. // pretend it was just successful so we can deal with superfloppies
  1667. // where noone bothered to write anything to the non-filesystem sectors
  1668. //
  1669. if(status == STATUS_NO_DATA_DETECTED) {
  1670. status = STATUS_SUCCESS;
  1671. }
  1672. if (!NT_SUCCESS( status )) {
  1673. break;
  1674. }
  1675. //
  1676. // If EZDrive is hooking the MBR then we found the first partition table
  1677. // in sector 1 rather than 0. However that partition table is relative
  1678. // to sector zero. So, Even though we got it from one, reset the partition
  1679. // offset to 0.
  1680. //
  1681. if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) {
  1682. partitionTableOffset.QuadPart = 0;
  1683. }
  1684. //
  1685. // Check for Boot Record signature.
  1686. //
  1687. if (((PUSHORT) readBuffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  1688. KdPrintEx((DPFLTR_FSTUB_ID,
  1689. DPFLTR_WARNING_LEVEL,
  1690. "FSTUB: (IoReadPartitionTable) No 0xaa55 found in partition table %d\n",
  1691. partitionTableCounter + 1));
  1692. break;
  1693. } else {
  1694. mbrSignatureFound = TRUE;
  1695. }
  1696. //
  1697. // Copy NTFT disk signature to buffer
  1698. //
  1699. if (partitionTableOffset.QuadPart == 0) {
  1700. (*PartitionBuffer)->Signature = ((PULONG) readBuffer)[PARTITION_TABLE_OFFSET/2-1];
  1701. }
  1702. partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]);
  1703. //
  1704. // Keep count of partition tables in case we have an extended partition;
  1705. //
  1706. partitionTableCounter++;
  1707. //
  1708. // First create the objects corresponding to the entries in this
  1709. // table that are not link entries or are unused.
  1710. //
  1711. KdPrintEx((DPFLTR_FSTUB_ID,
  1712. DPFLTR_TRACE_LEVEL,
  1713. "FSTUB: Partition Table %d:\n",
  1714. partitionTableCounter));
  1715. for (partitionEntry = 1, containerPartitionCount = 0;
  1716. partitionEntry <= NUM_PARTITION_TABLE_ENTRIES;
  1717. partitionEntry++, partitionTableEntry++) {
  1718. KdPrintEx((DPFLTR_FSTUB_ID,
  1719. DPFLTR_TRACE_LEVEL,
  1720. "Partition Entry %d,%d: type %#x %s\n",
  1721. partitionTableCounter,
  1722. partitionEntry,
  1723. partitionTableEntry->PartitionType,
  1724. (partitionTableEntry->ActiveFlag) ? "Active" : ""));
  1725. KdPrintEx((DPFLTR_FSTUB_ID,
  1726. DPFLTR_TRACE_LEVEL,
  1727. "\tOffset %#08lx for %#08lx Sectors\n",
  1728. GET_STARTING_SECTOR(partitionTableEntry),
  1729. GET_PARTITION_LENGTH(partitionTableEntry)));
  1730. if (partitionTableEntry->PartitionType == 0xEE) {
  1731. FstubFixupEfiPartition (partitionTableEntry,
  1732. maxOffset);
  1733. }
  1734. //
  1735. // Do a quick pass over the entry to see if this table is valid.
  1736. // It's only fatal if the master partition table is invalid.
  1737. //
  1738. if((HalpIsValidPartitionEntry(partitionTableEntry,
  1739. maxOffset,
  1740. maxSector) == FALSE) &&
  1741. (partitionTableCounter == 0)) {
  1742. tableIsValid = FALSE;
  1743. break;
  1744. }
  1745. //
  1746. // Only one container partition is allowed per table - any more
  1747. // and it's invalid.
  1748. //
  1749. if(IsContainerPartition(partitionTableEntry->PartitionType)) {
  1750. containerPartitionCount++;
  1751. if(containerPartitionCount != 1) {
  1752. KdPrintEx((DPFLTR_FSTUB_ID,
  1753. DPFLTR_ERROR_LEVEL,
  1754. "FSTUB: Multiple container partitions found in "
  1755. "partition table %d\n - table is invalid\n",
  1756. partitionTableCounter));
  1757. tableIsValid = FALSE;
  1758. break;
  1759. }
  1760. }
  1761. if(emptyPartitionTable) {
  1762. if((GET_STARTING_SECTOR(partitionTableEntry) != 0) ||
  1763. (GET_PARTITION_LENGTH(partitionTableEntry) != 0)) {
  1764. //
  1765. // There's a valid, non-empty partition here. The table
  1766. // is not empty.
  1767. //
  1768. emptyPartitionTable = FALSE;
  1769. }
  1770. }
  1771. //
  1772. // If the partition entry is not used or not recognized, skip
  1773. // it. Note that this is only done if the caller wanted only
  1774. // recognized partition descriptors returned.
  1775. //
  1776. if (ReturnRecognizedPartitions) {
  1777. //
  1778. // Check if partition type is 0 (unused) or 5/f (extended).
  1779. // The definition of recognized partitions has broadened
  1780. // to include any partition type other than 0 or 5/f.
  1781. //
  1782. if ((partitionTableEntry->PartitionType == PARTITION_ENTRY_UNUSED) ||
  1783. IsContainerPartition(partitionTableEntry->PartitionType)) {
  1784. continue;
  1785. }
  1786. }
  1787. //
  1788. // Bump up to the next partition entry.
  1789. //
  1790. partitionNumber++;
  1791. if (((partitionNumber * sizeof( PARTITION_INFORMATION )) +
  1792. sizeof( DRIVE_LAYOUT_INFORMATION )) >
  1793. (ULONG) partitionBufferSize) {
  1794. //
  1795. // The partition list is too small to contain all of the
  1796. // entries, so create a buffer that is twice as large to
  1797. // store the partition list and copy the old buffer into
  1798. // the new one.
  1799. //
  1800. newPartitionBuffer = ExAllocatePoolWithTag( NonPagedPool,
  1801. partitionBufferSize << 1,
  1802. 'btsF' );
  1803. if (newPartitionBuffer == NULL) {
  1804. --partitionNumber;
  1805. status = STATUS_INSUFFICIENT_RESOURCES;
  1806. break;
  1807. }
  1808. RtlCopyMemory( newPartitionBuffer,
  1809. *PartitionBuffer,
  1810. partitionBufferSize );
  1811. ExFreePool( *PartitionBuffer );
  1812. //
  1813. // Reassign the new buffer to the return parameter and
  1814. // reset the size of the buffer.
  1815. //
  1816. *PartitionBuffer = newPartitionBuffer;
  1817. partitionBufferSize <<= 1;
  1818. }
  1819. //
  1820. // Describe this partition table entry in the partition list
  1821. // entry being built for the driver. This includes writing
  1822. // the partition type, starting offset of the partition, and
  1823. // the length of the partition.
  1824. //
  1825. partitionInfo = &(*PartitionBuffer)->PartitionEntry[partitionNumber];
  1826. partitionInfo->PartitionType = partitionTableEntry->PartitionType;
  1827. partitionInfo->RewritePartition = FALSE;
  1828. if (partitionTableEntry->PartitionType != PARTITION_ENTRY_UNUSED) {
  1829. LONGLONG startOffset;
  1830. partitionInfo->BootIndicator =
  1831. partitionTableEntry->ActiveFlag & PARTITION_ACTIVE_FLAG ?
  1832. (BOOLEAN) TRUE : (BOOLEAN) FALSE;
  1833. if (IsContainerPartition(partitionTableEntry->PartitionType)) {
  1834. partitionInfo->RecognizedPartition = FALSE;
  1835. startOffset = volumeStartOffset.QuadPart;
  1836. } else {
  1837. partitionInfo->RecognizedPartition = TRUE;
  1838. startOffset = partitionTableOffset.QuadPart;
  1839. }
  1840. partitionInfo->StartingOffset.QuadPart = startOffset +
  1841. UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry),
  1842. SectorSize);
  1843. tempInt.QuadPart = (partitionInfo->StartingOffset.QuadPart -
  1844. startOffset) / SectorSize;
  1845. partitionInfo->HiddenSectors = tempInt.LowPart;
  1846. partitionInfo->PartitionLength.QuadPart =
  1847. UInt32x32To64(GET_PARTITION_LENGTH(partitionTableEntry),
  1848. SectorSize);
  1849. } else {
  1850. //
  1851. // Partitions that are not used do not describe any part
  1852. // of the disk. These types are recorded in the partition
  1853. // list buffer when the caller requested all of the entries
  1854. // be returned. Simply zero out the remaining fields in
  1855. // the entry.
  1856. //
  1857. partitionInfo->BootIndicator = FALSE;
  1858. partitionInfo->RecognizedPartition = FALSE;
  1859. partitionInfo->StartingOffset.QuadPart = 0;
  1860. partitionInfo->PartitionLength.QuadPart = 0;
  1861. partitionInfo->HiddenSectors = 0;
  1862. }
  1863. }
  1864. KdPrintEx((DPFLTR_FSTUB_ID, DPFLTR_TRACE_LEVEL, "\n"));
  1865. //
  1866. // If an error occurred, leave the routine now.
  1867. //
  1868. if (!NT_SUCCESS( status )) {
  1869. break;
  1870. }
  1871. if(tableIsValid == FALSE) {
  1872. //
  1873. // Invalidate this partition table and stop looking for new ones.
  1874. // we'll build the partition list based on the ones we found
  1875. // previously.
  1876. //
  1877. partitionTableCounter--;
  1878. break;
  1879. }
  1880. //
  1881. // Now check to see if there are any link entries in this table,
  1882. // and if so, set up the sector address of the next partition table.
  1883. // There can only be one link entry in each partition table, and it
  1884. // will point to the next table.
  1885. //
  1886. partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) readBuffer)[PARTITION_TABLE_OFFSET]);
  1887. //
  1888. // Assume that the link entry is empty.
  1889. //
  1890. partitionTableOffset.QuadPart = 0;
  1891. for (partitionEntry = 1;
  1892. partitionEntry <= NUM_PARTITION_TABLE_ENTRIES;
  1893. partitionEntry++, partitionTableEntry++) {
  1894. if (IsContainerPartition(partitionTableEntry->PartitionType)) {
  1895. //
  1896. // Obtain the address of the next partition table on the
  1897. // disk. This is the number of hidden sectors added to
  1898. // the beginning of the extended partition (in the case of
  1899. // logical drives), since all logical drives are relative
  1900. // to the extended partition. The VolumeStartSector will
  1901. // be zero if this is the primary parition table.
  1902. //
  1903. partitionTableOffset.QuadPart = volumeStartOffset.QuadPart +
  1904. UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry),
  1905. SectorSize);
  1906. //
  1907. // Set the VolumeStartSector to be the begining of the
  1908. // second partition (extended partition) because all of
  1909. // the offsets to the partition tables of the logical drives
  1910. // are relative to this extended partition.
  1911. //
  1912. if (primaryPartitionTable) {
  1913. volumeStartOffset = partitionTableOffset;
  1914. }
  1915. //
  1916. // Update the maximum sector to be the end of the container
  1917. // partition.
  1918. //
  1919. maxSector = GET_PARTITION_LENGTH(partitionTableEntry);
  1920. KdPrintEx((DPFLTR_FSTUB_ID,
  1921. DPFLTR_TRACE_LEVEL,
  1922. "FSTUB: MaxSector now = %#08lx\n",
  1923. maxSector));
  1924. //
  1925. // There is only ever one link entry per partition table,
  1926. // exit the loop once it has been found.
  1927. //
  1928. break;
  1929. }
  1930. }
  1931. //
  1932. // All the other partitions will be logical drives.
  1933. //
  1934. primaryPartitionTable = FALSE;
  1935. } while (partitionTableOffset.HighPart | partitionTableOffset.LowPart);
  1936. //
  1937. // Detect super-floppy media attempt #1.
  1938. // If the media is removable and has an 0xaa55 signature on it and
  1939. // is empty then check to see if we can recognize the BPB. If we recognize
  1940. // a jump-byte at the beginning of the media then it's a super floppy. If
  1941. // we don't then it's an unpartitioned disk.
  1942. //
  1943. if((diskGeometry.MediaType == RemovableMedia) &&
  1944. (partitionTableCounter == 0) &&
  1945. (mbrSignatureFound == TRUE) &&
  1946. (emptyPartitionTable == TRUE)) {
  1947. PBOOT_SECTOR_INFO bootSector = (PBOOT_SECTOR_INFO) readBuffer;
  1948. if((bootSector->JumpByte[0] == 0xeb) ||
  1949. (bootSector->JumpByte[0] == 0xe9)) {
  1950. //
  1951. // We've got a superfloppy of some sort.
  1952. //
  1953. KdPrintEx((DPFLTR_FSTUB_ID,
  1954. DPFLTR_TRACE_LEVEL,
  1955. "FSTUB: Jump byte %#x found "
  1956. "along with empty partition table - disk is a "
  1957. "super floppy and has no valid MBR\n",
  1958. bootSector->JumpByte));
  1959. partitionTableCounter = -1;
  1960. }
  1961. }
  1962. //
  1963. // If the partition table count is still -1 then we didn't find any
  1964. // valid partition records. In this case we'll build a partition list
  1965. // that contiains one partition spanning the entire disk.
  1966. //
  1967. if(partitionTableCounter == -1) {
  1968. if((mbrSignatureFound == TRUE) ||
  1969. (diskGeometry.MediaType == RemovableMedia)) {
  1970. //
  1971. // Either we found a signature but the partition layout was
  1972. // invalid (for all disks) or we didn't find a signature but this
  1973. // is a removable disk. Either of these two cases makes a
  1974. // superfloppy.
  1975. //
  1976. KdPrintEx((DPFLTR_FSTUB_ID,
  1977. DPFLTR_TRACE_LEVEL,
  1978. "FSTUB: Drive %#p has no valid MBR. "
  1979. "Make it into a super-floppy\n", DeviceObject));
  1980. KdPrintEx((DPFLTR_FSTUB_ID,
  1981. DPFLTR_TRACE_LEVEL,
  1982. "FSTUB: Drive has %#08lx sectors "
  1983. "and is %#016I64x bytes large\n",
  1984. endSector,
  1985. endSector * diskGeometry.BytesPerSector));
  1986. if (endSector > 0) {
  1987. partitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
  1988. partitionInfo->RewritePartition = FALSE;
  1989. partitionInfo->RecognizedPartition = TRUE;
  1990. partitionInfo->PartitionType = PARTITION_FAT_16;
  1991. partitionInfo->BootIndicator = FALSE;
  1992. partitionInfo->HiddenSectors = 0;
  1993. partitionInfo->StartingOffset.QuadPart = 0;
  1994. partitionInfo->PartitionLength.QuadPart =
  1995. (endSector * diskGeometry.BytesPerSector);
  1996. (*PartitionBuffer)->Signature = 1;
  1997. partitionNumber = 0;
  1998. }
  1999. } else {
  2000. //
  2001. // We found no partitions. Make sure the partition count is -1
  2002. // so that we setup a zeroed-out partition table below.
  2003. //
  2004. partitionNumber = -1;
  2005. }
  2006. }
  2007. //
  2008. // Fill in the first field in the PartitionBuffer. This field indicates how
  2009. // many partition entries there are in the PartitionBuffer.
  2010. //
  2011. (*PartitionBuffer)->PartitionCount = ++partitionNumber;
  2012. if (!partitionNumber) {
  2013. //
  2014. // Zero out disk signature.
  2015. //
  2016. (*PartitionBuffer)->Signature = 0;
  2017. }
  2018. //
  2019. // Deallocate read buffer if it was allocated it.
  2020. //
  2021. if (readBuffer != NULL) {
  2022. ExFreePool( readBuffer );
  2023. }
  2024. if (!NT_SUCCESS(status)) {
  2025. ExFreePool(*PartitionBuffer);
  2026. *PartitionBuffer = NULL;
  2027. }
  2028. #if DBG
  2029. if (NT_SUCCESS(status)) {
  2030. FstubDbgPrintDriveLayout(*PartitionBuffer);
  2031. }
  2032. #endif
  2033. return status;
  2034. }
  2035. NTSTATUS
  2036. FASTCALL
  2037. IoSetPartitionInformation(
  2038. IN PDEVICE_OBJECT DeviceObject,
  2039. IN ULONG SectorSize,
  2040. IN ULONG PartitionNumber,
  2041. IN ULONG PartitionType
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. This routine is invoked when a disk device driver is asked to set the
  2046. partition type in a partition table entry via an I/O control code. This
  2047. control code is generally issued by the format utility just after it
  2048. has formatted the partition. The format utility performs the I/O control
  2049. function on the partition and the driver passes the address of the base
  2050. physical device object and the number of the partition associated with
  2051. the device object that the format utility has open. If this routine
  2052. returns success, then the disk driver should updates its notion of the
  2053. partition type for this partition in its device extension.
  2054. Arguments:
  2055. DeviceObject - Pointer to the base physical device object for the device
  2056. on which the partition type is to be set.
  2057. SectorSize - Supplies the size of a sector on the disk in bytes.
  2058. PartitionNumber - Specifies the partition number on the device whose
  2059. partition type is to be changed.
  2060. PartitionType - Specifies the new type for the partition.
  2061. Return Value:
  2062. The function value is the final status of the operation.
  2063. Notes:
  2064. This routine is synchronous. Therefore, it MUST be invoked by the disk
  2065. driver's dispatch routine, or by a disk driver's thread. Likewise, all
  2066. users, FSP threads, etc., must be prepared to enter a wait state when
  2067. issuing the I/O control code to set the partition type for the device.
  2068. Note also that this routine assumes that the partition number passed
  2069. in by the disk driver actually exists since the driver itself supplies
  2070. this parameter.
  2071. Finally, note that this routine may NOT be invoked at APC_LEVEL. It
  2072. must be invoked at PASSIVE_LEVEL. This is due to the fact that this
  2073. routine uses a kernel event object to synchronize I/O completion on the
  2074. device. The event cannot be set to the signaled state without queueing
  2075. the I/O system's special kernel APC routine for I/O completion and
  2076. executing it. (This rules is a bit esoteric since it only holds true
  2077. if the device driver returns something other than STATUS_PENDING, which
  2078. it will probably never do.)
  2079. --*/
  2080. {
  2081. #define GET_STARTING_SECTOR( p ) ( \
  2082. (ULONG) (p->StartingSectorLsb0) + \
  2083. (ULONG) (p->StartingSectorLsb1 << 8) + \
  2084. (ULONG) (p->StartingSectorMsb0 << 16) + \
  2085. (ULONG) (p->StartingSectorMsb1 << 24) )
  2086. PIRP irp;
  2087. KEVENT event;
  2088. IO_STATUS_BLOCK ioStatus;
  2089. NTSTATUS status;
  2090. LARGE_INTEGER partitionTableOffset;
  2091. LARGE_INTEGER volumeStartOffset;
  2092. PUCHAR buffer = (PUCHAR) NULL;
  2093. ULONG transferSize;
  2094. ULONG partitionNumber;
  2095. ULONG partitionEntry;
  2096. PPARTITION_DESCRIPTOR partitionTableEntry;
  2097. BOOLEAN primaryPartitionTable;
  2098. BOOLEAN foundEZHooker = FALSE;
  2099. PAGED_CODE();
  2100. //
  2101. // Begin by determining the size of the buffer required to read and write
  2102. // the partition information to/from the disk. This is done to ensure
  2103. // that at least 512 bytes are read, thereby guaranteeing that enough data
  2104. // is read to include an entire partition table. Note that this code
  2105. // assumes that the actual sector size of the disk (if less than 512
  2106. // bytes) is a multiple of 2, a
  2107. // fairly reasonable assumption.
  2108. //
  2109. if (SectorSize >= 512) {
  2110. transferSize = SectorSize;
  2111. } else {
  2112. transferSize = 512;
  2113. }
  2114. //
  2115. // Look to see if this is an EZDrive Disk. If it is then get the
  2116. // real parititon table at 1.
  2117. //
  2118. {
  2119. PVOID buff;
  2120. HalExamineMBR(
  2121. DeviceObject,
  2122. transferSize,
  2123. (ULONG)0x55,
  2124. &buff
  2125. );
  2126. if (buff) {
  2127. foundEZHooker = TRUE;
  2128. ExFreePool(buff);
  2129. partitionTableOffset.QuadPart = 512;
  2130. } else {
  2131. partitionTableOffset.QuadPart = 0;
  2132. }
  2133. }
  2134. //
  2135. // The partitions in this primary partition have their start sector 0.
  2136. //
  2137. volumeStartOffset.QuadPart = 0;
  2138. //
  2139. // Indicate that the table being read and processed is the primary partition
  2140. // table.
  2141. //
  2142. primaryPartitionTable = TRUE;
  2143. //
  2144. // Initialize the number of partitions found thus far.
  2145. //
  2146. partitionNumber = 0;
  2147. //
  2148. // Allocate a buffer that will hold the read/write data.
  2149. //
  2150. buffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned, PAGE_SIZE, 'btsF');
  2151. if (buffer == NULL) {
  2152. return STATUS_INSUFFICIENT_RESOURCES;
  2153. }
  2154. //
  2155. // Initialize a kernel event to use in synchronizing device requests
  2156. // with I/O completion.
  2157. //
  2158. KeInitializeEvent( &event, NotificationEvent, FALSE );
  2159. //
  2160. // Read each partition table scanning for the partition table entry that
  2161. // the caller wishes to modify.
  2162. //
  2163. do {
  2164. //
  2165. // Read the record containing the partition table.
  2166. //
  2167. (VOID) KeResetEvent( &event );
  2168. irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  2169. DeviceObject,
  2170. buffer,
  2171. transferSize,
  2172. &partitionTableOffset,
  2173. &event,
  2174. &ioStatus );
  2175. if (!irp) {
  2176. status = STATUS_INSUFFICIENT_RESOURCES;
  2177. break;
  2178. } else {
  2179. PIO_STACK_LOCATION irpStack;
  2180. irpStack = IoGetNextIrpStackLocation(irp);
  2181. irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  2182. }
  2183. status = IoCallDriver( DeviceObject, irp );
  2184. if (status == STATUS_PENDING) {
  2185. (VOID) KeWaitForSingleObject( &event,
  2186. Executive,
  2187. KernelMode,
  2188. FALSE,
  2189. (PLARGE_INTEGER) NULL );
  2190. status = ioStatus.Status;
  2191. }
  2192. if (!NT_SUCCESS( status )) {
  2193. break;
  2194. }
  2195. //
  2196. // If EZDrive is hooking the MBR then we found the first partition table
  2197. // in sector 1 rather than 0. However that partition table is relative
  2198. // to sector zero. So, Even though we got it from one, reset the partition
  2199. // offset to 0.
  2200. //
  2201. if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) {
  2202. partitionTableOffset.QuadPart = 0;
  2203. }
  2204. //
  2205. // Check for a valid Boot Record signature in the partition table
  2206. // record.
  2207. //
  2208. if (((PUSHORT) buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  2209. status = STATUS_BAD_MASTER_BOOT_RECORD;
  2210. break;
  2211. }
  2212. partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) buffer)[PARTITION_TABLE_OFFSET]);
  2213. //
  2214. // Scan the partition entries in this partition table to determine if
  2215. // any of the entries are the desired entry. Each entry in each
  2216. // table must be scanned in the same order as in IoReadPartitionTable
  2217. // so that the partition table entry cooresponding to the driver's
  2218. // notion of the partition number can be located.
  2219. //
  2220. for (partitionEntry = 1;
  2221. partitionEntry <= NUM_PARTITION_TABLE_ENTRIES;
  2222. partitionEntry++, partitionTableEntry++) {
  2223. //
  2224. // If the partition entry is empty or for an extended, skip it.
  2225. //
  2226. if ((partitionTableEntry->PartitionType == PARTITION_ENTRY_UNUSED) ||
  2227. IsContainerPartition(partitionTableEntry->PartitionType)) {
  2228. continue;
  2229. }
  2230. //
  2231. // A valid partition entry that is recognized has been located.
  2232. // Bump the count and check to see if this entry is the desired
  2233. // entry.
  2234. //
  2235. partitionNumber++;
  2236. if (partitionNumber == PartitionNumber) {
  2237. //
  2238. // This is the desired partition that is to be changed. Simply
  2239. // overwrite the partition type and write the entire partition
  2240. // buffer back out to the disk.
  2241. //
  2242. partitionTableEntry->PartitionType = (UCHAR) PartitionType;
  2243. (VOID) KeResetEvent( &event );
  2244. irp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE,
  2245. DeviceObject,
  2246. buffer,
  2247. transferSize,
  2248. &partitionTableOffset,
  2249. &event,
  2250. &ioStatus );
  2251. if (!irp) {
  2252. status = STATUS_INSUFFICIENT_RESOURCES;
  2253. break;
  2254. } else {
  2255. PIO_STACK_LOCATION irpStack;
  2256. irpStack = IoGetNextIrpStackLocation(irp);
  2257. irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  2258. }
  2259. status = IoCallDriver( DeviceObject, irp );
  2260. if (status == STATUS_PENDING) {
  2261. (VOID) KeWaitForSingleObject( &event,
  2262. Executive,
  2263. KernelMode,
  2264. FALSE,
  2265. (PLARGE_INTEGER) NULL );
  2266. status = ioStatus.Status;
  2267. }
  2268. break;
  2269. }
  2270. }
  2271. //
  2272. // If all of the entries in the current buffer were scanned and the
  2273. // desired entry was not found, then continue. Otherwise, leave the
  2274. // routine.
  2275. //
  2276. if (partitionEntry <= NUM_PARTITION_TABLE_ENTRIES) {
  2277. break;
  2278. }
  2279. //
  2280. // Now scan the current buffer to locate an extended partition entry
  2281. // in the table so that its partition information can be read. There
  2282. // can only be one extended partition entry in each partition table,
  2283. // and it will point to the next table.
  2284. //
  2285. partitionTableEntry = (PPARTITION_DESCRIPTOR) &(((PUSHORT) buffer)[PARTITION_TABLE_OFFSET]);
  2286. for (partitionEntry = 1;
  2287. partitionEntry <= NUM_PARTITION_TABLE_ENTRIES;
  2288. partitionEntry++, partitionTableEntry++) {
  2289. if (IsContainerPartition(partitionTableEntry->PartitionType)) {
  2290. //
  2291. // Obtain the address of the next partition table on the disk.
  2292. // This is the number of hidden sectors added to the beginning
  2293. // of the extended partition (in the case of logical drives),
  2294. // since all logical drives are relative to the extended
  2295. // partition. The starting offset of the volume will be zero
  2296. // if this is the primary partition table.
  2297. //
  2298. partitionTableOffset.QuadPart = volumeStartOffset.QuadPart +
  2299. UInt32x32To64(GET_STARTING_SECTOR(partitionTableEntry),
  2300. SectorSize);
  2301. //
  2302. // Set the starting offset of the volume to be the beginning of
  2303. // the second partition (the extended partition) because all of
  2304. // the offsets to the partition tables of the logical drives
  2305. // are relative to this extended partition.
  2306. //
  2307. if (primaryPartitionTable) {
  2308. volumeStartOffset = partitionTableOffset;
  2309. }
  2310. break;
  2311. }
  2312. }
  2313. //
  2314. // Ensure that a partition entry was located that was an extended
  2315. // partition, otherwise the desired partition will never be found.
  2316. //
  2317. if (partitionEntry > NUM_PARTITION_TABLE_ENTRIES) {
  2318. status = STATUS_BAD_MASTER_BOOT_RECORD;
  2319. break;
  2320. }
  2321. //
  2322. // All the other partitions will be logical drives.
  2323. //
  2324. primaryPartitionTable = FALSE;
  2325. } while (partitionNumber < PartitionNumber);
  2326. //
  2327. // If a data buffer was successfully allocated, deallocate it now.
  2328. //
  2329. if (buffer != NULL) {
  2330. ExFreePool( buffer );
  2331. }
  2332. return status;
  2333. }
  2334. NTSTATUS
  2335. FASTCALL
  2336. IoWritePartitionTable(
  2337. IN PDEVICE_OBJECT DeviceObject,
  2338. IN ULONG SectorSize,
  2339. IN ULONG SectorsPerTrack,
  2340. IN ULONG NumberOfHeads,
  2341. IN struct _DRIVE_LAYOUT_INFORMATION *PartitionBuffer
  2342. )
  2343. /*++
  2344. Routine Description:
  2345. This routine walks the disk writing the partition tables from
  2346. the entries in the partition list buffer for each partition.
  2347. Applications that create and delete partitions should issue a
  2348. IoReadPartitionTable call with the 'return recognized partitions'
  2349. boolean set to false to get a full description of the system.
  2350. Then the drive layout structure can be modified by the application to
  2351. reflect the new configuration of the disk and then is written back
  2352. to the disk using this routine.
  2353. Arguments:
  2354. DeviceObject - Pointer to device object for this disk.
  2355. SectorSize - Sector size on the device.
  2356. SectorsPerTrack - Track size on the device.
  2357. NumberOfHeads - Same as tracks per cylinder.
  2358. PartitionBuffer - Pointer drive layout buffer.
  2359. Return Value:
  2360. The functional value is STATUS_SUCCESS if all writes are completed
  2361. without error.
  2362. --*/
  2363. {
  2364. //
  2365. // This macro has the effect of Bit = log2(Data)
  2366. //
  2367. #define WHICH_BIT(Data, Bit) { \
  2368. for (Bit = 0; Bit < 32; Bit++) { \
  2369. if ((Data >> Bit) == 1) { \
  2370. break; \
  2371. } \
  2372. } \
  2373. }
  2374. ULONG writeSize;
  2375. PUSHORT writeBuffer = NULL;
  2376. PPTE partitionEntry;
  2377. PPARTITION_TABLE partitionTable;
  2378. CCHAR shiftCount;
  2379. LARGE_INTEGER partitionTableOffset;
  2380. LARGE_INTEGER nextRecordOffset;
  2381. ULONG partitionTableCount;
  2382. ULONG partitionEntryCount;
  2383. KEVENT event;
  2384. IO_STATUS_BLOCK ioStatus;
  2385. PIRP irp;
  2386. BOOLEAN rewritePartition = FALSE;
  2387. NTSTATUS status = STATUS_SUCCESS;
  2388. LARGE_INTEGER tempInt;
  2389. BOOLEAN foundEZHooker = FALSE;
  2390. ULONG conventionalCylinders;
  2391. LONGLONG diskSize;
  2392. BOOLEAN isSuperFloppy = FALSE;
  2393. //
  2394. // Cast to a structure that is easier to use.
  2395. //
  2396. PDISK_LAYOUT diskLayout = (PDISK_LAYOUT) PartitionBuffer;
  2397. //
  2398. // Ensure that no one is calling this function illegally.
  2399. //
  2400. PAGED_CODE();
  2401. FstubDbgPrintDriveLayout ( PartitionBuffer );
  2402. //
  2403. // Determine the size of a write operation to ensure that at least 512
  2404. // bytes are written. This will guarantee that enough data is written to
  2405. // include an entire partition table. Note that this code assumes that
  2406. // the actual sector size of the disk (if less than 512 bytes) is a
  2407. // multiple of 2, a fairly reasonable assumption.
  2408. //
  2409. if (SectorSize >= 512) {
  2410. writeSize = SectorSize;
  2411. } else {
  2412. writeSize = 512;
  2413. }
  2414. xHalGetPartialGeometry( DeviceObject,
  2415. &conventionalCylinders,
  2416. &diskSize );
  2417. //
  2418. // Look to see if this is an EZDrive Disk. If it is then get the
  2419. // real partititon table at 1.
  2420. //
  2421. {
  2422. PVOID buff;
  2423. HalExamineMBR(
  2424. DeviceObject,
  2425. writeSize,
  2426. (ULONG)0x55,
  2427. &buff
  2428. );
  2429. if (buff) {
  2430. foundEZHooker = TRUE;
  2431. ExFreePool(buff);
  2432. partitionTableOffset.QuadPart = 512;
  2433. } else {
  2434. partitionTableOffset.QuadPart = 0;
  2435. }
  2436. }
  2437. //
  2438. // Initialize starting variables.
  2439. //
  2440. nextRecordOffset.QuadPart = 0;
  2441. //
  2442. // Calculate shift count for converting between byte and sector.
  2443. //
  2444. WHICH_BIT( SectorSize, shiftCount );
  2445. //
  2446. // Check to see if this device is partitioned (or is being partitioned)
  2447. // as a floppy. Floppys have a single partititon with hidden sector count
  2448. // and partition offset equal to zero. If the disk is being partitioned
  2449. // like this then we need to be sure not to write an MBR signature or
  2450. // an NTFT signature to the media.
  2451. //
  2452. // NOTE: this is only to catch ourself when someone tries to write the
  2453. // existing partition table back to disk. Any changes to the table will
  2454. // result in a real MBR being written out.
  2455. //
  2456. if(PartitionBuffer->PartitionCount == 1) {
  2457. PPARTITION_INFORMATION partitionEntry = PartitionBuffer->PartitionEntry;
  2458. if((partitionEntry->StartingOffset.QuadPart == 0) &&
  2459. (partitionEntry->HiddenSectors == 0)) {
  2460. isSuperFloppy = TRUE;
  2461. //
  2462. // This would indeed appear to be an attempt to format a floppy.
  2463. // Make sure the other parameters match the defaut values we
  2464. // provide in ReadParititonTable. If they don't then fail
  2465. // the write operation.
  2466. //
  2467. if((partitionEntry->PartitionNumber != 0) ||
  2468. (partitionEntry->PartitionType != PARTITION_FAT_16) ||
  2469. (partitionEntry->BootIndicator == TRUE)) {
  2470. return STATUS_INVALID_PARAMETER;
  2471. }
  2472. if(partitionEntry->RewritePartition == TRUE) {
  2473. rewritePartition = TRUE;
  2474. }
  2475. foundEZHooker = FALSE;
  2476. }
  2477. }
  2478. //
  2479. // Convert partition count to partition table or boot sector count.
  2480. //
  2481. diskLayout->TableCount =
  2482. (PartitionBuffer->PartitionCount +
  2483. NUM_PARTITION_TABLE_ENTRIES - 1) /
  2484. NUM_PARTITION_TABLE_ENTRIES;
  2485. //
  2486. // Allocate a buffer for the sector writes.
  2487. //
  2488. writeBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned, PAGE_SIZE, 'btsF');
  2489. if (writeBuffer == NULL) {
  2490. return STATUS_INSUFFICIENT_RESOURCES;
  2491. }
  2492. //
  2493. // Point to the partition table entries in write buffer.
  2494. //
  2495. partitionEntry = (PPTE) &writeBuffer[PARTITION_TABLE_OFFSET];
  2496. for (partitionTableCount = 0;
  2497. partitionTableCount < diskLayout->TableCount;
  2498. partitionTableCount++) {
  2499. UCHAR partitionType;
  2500. //
  2501. // the first partition table is in the mbr (physical sector 0).
  2502. // other partition tables are in ebr's within the extended partition.
  2503. //
  2504. BOOLEAN mbr = (BOOLEAN) (!partitionTableCount);
  2505. LARGE_INTEGER extendedPartitionOffset;
  2506. //
  2507. // Read the boot record that's already there into the write buffer
  2508. // and save its boot code area if the signature is valid. This way
  2509. // we don't clobber any boot code that might be there already.
  2510. //
  2511. KeInitializeEvent( &event, NotificationEvent, FALSE );
  2512. irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  2513. DeviceObject,
  2514. writeBuffer,
  2515. writeSize,
  2516. &partitionTableOffset,
  2517. &event,
  2518. &ioStatus );
  2519. if (!irp) {
  2520. status = STATUS_INSUFFICIENT_RESOURCES;
  2521. break;
  2522. } else {
  2523. PIO_STACK_LOCATION irpStack;
  2524. irpStack = IoGetNextIrpStackLocation(irp);
  2525. irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  2526. }
  2527. status = IoCallDriver( DeviceObject, irp );
  2528. if (status == STATUS_PENDING) {
  2529. (VOID) KeWaitForSingleObject( &event,
  2530. Executive,
  2531. KernelMode,
  2532. FALSE,
  2533. (PLARGE_INTEGER) NULL);
  2534. status = ioStatus.Status;
  2535. }
  2536. if (!NT_SUCCESS( status )) {
  2537. break;
  2538. }
  2539. //
  2540. // If EZDrive is hooking the MBR then we found the first partition table
  2541. // in sector 1 rather than 0. However that partition table is relative
  2542. // to sector zero. So, Even though we got it from one, reset the partition
  2543. // offset to 0.
  2544. //
  2545. if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) {
  2546. partitionTableOffset.QuadPart = 0;
  2547. }
  2548. if(isSuperFloppy == FALSE) {
  2549. //
  2550. // Write signature to last word of boot sector.
  2551. //
  2552. writeBuffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
  2553. //
  2554. // Write NTFT disk signature if it changed and this is the MBR.
  2555. //
  2556. rewritePartition = FALSE;
  2557. if (partitionTableOffset.QuadPart == 0) {
  2558. if (((PULONG)writeBuffer)[PARTITION_TABLE_OFFSET/2-1] !=
  2559. PartitionBuffer->Signature) {
  2560. ((PULONG) writeBuffer)[PARTITION_TABLE_OFFSET/2-1] =
  2561. PartitionBuffer->Signature;
  2562. rewritePartition = TRUE;
  2563. }
  2564. }
  2565. //
  2566. // Get pointer to first partition table.
  2567. //
  2568. partitionTable = &diskLayout->PartitionTable[partitionTableCount];
  2569. //
  2570. // Walk table to determine whether this boot record has changed
  2571. // and update partition table in write buffer in case it needs
  2572. // to be written out to disk.
  2573. //
  2574. for (partitionEntryCount = 0;
  2575. partitionEntryCount < NUM_PARTITION_TABLE_ENTRIES;
  2576. partitionEntryCount++) {
  2577. partitionType =
  2578. partitionTable->PartitionEntry[partitionEntryCount].PartitionType;
  2579. //
  2580. // If the rewrite ISN'T true then copy then just leave the data
  2581. // alone that is in the on-disk table.
  2582. //
  2583. if (partitionTable->PartitionEntry[partitionEntryCount].RewritePartition) {
  2584. //
  2585. // This boot record needs to be written back to disk.
  2586. //
  2587. rewritePartition = TRUE;
  2588. //
  2589. // Copy partition type from user buffer to write buffer.
  2590. //
  2591. partitionEntry[partitionEntryCount].PartitionType =
  2592. partitionTable->PartitionEntry[partitionEntryCount].PartitionType;
  2593. //
  2594. // Copy the partition active flag.
  2595. //
  2596. partitionEntry[partitionEntryCount].ActiveFlag =
  2597. partitionTable->PartitionEntry[partitionEntryCount].BootIndicator ?
  2598. (UCHAR) PARTITION_ACTIVE_FLAG : (UCHAR) 0;
  2599. if (partitionType != PARTITION_ENTRY_UNUSED) {
  2600. LARGE_INTEGER sectorOffset;
  2601. //
  2602. // Calculate partition offset.
  2603. // If in the mbr or the entry is not a link entry, partition offset
  2604. // is sectors past last boot record. Otherwise (not in the mbr and
  2605. // entry is a link entry), partition offset is sectors past start
  2606. // of extended partition.
  2607. //
  2608. if (mbr || !IsContainerPartition(partitionType)) {
  2609. tempInt.QuadPart = partitionTableOffset.QuadPart;
  2610. } else {
  2611. tempInt.QuadPart = extendedPartitionOffset.QuadPart;
  2612. }
  2613. sectorOffset.QuadPart =
  2614. partitionTable->PartitionEntry[partitionEntryCount].StartingOffset.QuadPart -
  2615. tempInt.QuadPart;
  2616. tempInt.QuadPart = sectorOffset.QuadPart >> shiftCount;
  2617. partitionEntry[partitionEntryCount].StartingSector = tempInt.LowPart;
  2618. //
  2619. // Calculate partition length.
  2620. //
  2621. tempInt.QuadPart = partitionTable->PartitionEntry[partitionEntryCount].PartitionLength.QuadPart >> shiftCount;
  2622. partitionEntry[partitionEntryCount].PartitionLength = tempInt.LowPart;
  2623. //
  2624. // Fill in CHS values
  2625. //
  2626. HalpCalculateChsValues(
  2627. &partitionTable->PartitionEntry[partitionEntryCount].StartingOffset,
  2628. &partitionTable->PartitionEntry[partitionEntryCount].PartitionLength,
  2629. shiftCount,
  2630. SectorsPerTrack,
  2631. NumberOfHeads,
  2632. conventionalCylinders,
  2633. (PPARTITION_DESCRIPTOR) &partitionEntry[partitionEntryCount]);
  2634. } else {
  2635. //
  2636. // Zero out partition entry fields in case an entry
  2637. // was deleted.
  2638. //
  2639. partitionEntry[partitionEntryCount].StartingSector = 0;
  2640. partitionEntry[partitionEntryCount].PartitionLength = 0;
  2641. partitionEntry[partitionEntryCount].StartingTrack = 0;
  2642. partitionEntry[partitionEntryCount].EndingTrack = 0;
  2643. partitionEntry[partitionEntryCount].StartingCylinder = 0;
  2644. partitionEntry[partitionEntryCount].EndingCylinder = 0;
  2645. }
  2646. }
  2647. if (IsContainerPartition(partitionType)) {
  2648. //
  2649. // Save next record offset.
  2650. //
  2651. nextRecordOffset =
  2652. partitionTable->PartitionEntry[partitionEntryCount].StartingOffset;
  2653. }
  2654. } // end for partitionEntryCount ...
  2655. }
  2656. if (rewritePartition == TRUE) {
  2657. rewritePartition = FALSE;
  2658. //
  2659. // Create a notification event object to be used while waiting for
  2660. // the write request to complete.
  2661. //
  2662. KeInitializeEvent( &event, NotificationEvent, FALSE );
  2663. if (foundEZHooker && (partitionTableOffset.QuadPart == 0)) {
  2664. partitionTableOffset.QuadPart = 512;
  2665. }
  2666. irp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE,
  2667. DeviceObject,
  2668. writeBuffer,
  2669. writeSize,
  2670. &partitionTableOffset,
  2671. &event,
  2672. &ioStatus );
  2673. if (!irp) {
  2674. status = STATUS_INSUFFICIENT_RESOURCES;
  2675. break;
  2676. } else {
  2677. PIO_STACK_LOCATION irpStack;
  2678. irpStack = IoGetNextIrpStackLocation(irp);
  2679. irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
  2680. }
  2681. status = IoCallDriver( DeviceObject, irp );
  2682. if (status == STATUS_PENDING) {
  2683. (VOID) KeWaitForSingleObject( &event,
  2684. Executive,
  2685. KernelMode,
  2686. FALSE,
  2687. (PLARGE_INTEGER) NULL);
  2688. status = ioStatus.Status;
  2689. }
  2690. if (!NT_SUCCESS( status )) {
  2691. break;
  2692. }
  2693. if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) {
  2694. partitionTableOffset.QuadPart = 0;
  2695. }
  2696. } // end if (reWrite ...
  2697. //
  2698. // Update partitionTableOffset to next boot record offset
  2699. //
  2700. partitionTableOffset = nextRecordOffset;
  2701. if(mbr) {
  2702. extendedPartitionOffset = nextRecordOffset;
  2703. }
  2704. } // end for partitionTableCount ...
  2705. //
  2706. // Deallocate write buffer if it was allocated it.
  2707. //
  2708. if (writeBuffer != NULL) {
  2709. ExFreePool( writeBuffer );
  2710. }
  2711. return status;
  2712. }
  2713. VOID
  2714. FstubFixupEfiPartition(
  2715. IN PPARTITION_DESCRIPTOR Entry,
  2716. IN ULONGLONG MaxSector
  2717. )
  2718. /*++
  2719. Routine Description:
  2720. Protective GPT partition entries can have invalid sizes. The EFI
  2721. standard explicitly allows this. For these partitions, fixup
  2722. the length so it doesn't go past the end of the disk.
  2723. Arguments:
  2724. Entry - Supplies the partition entry to modify.
  2725. MaxSector - Supplies the maximum valid sector.
  2726. Return Value:
  2727. NTSTATUS code
  2728. --*/
  2729. {
  2730. ULONGLONG endingSector;
  2731. PPTE partitionEntry;
  2732. PAGED_CODE();
  2733. partitionEntry = (PPTE) Entry;
  2734. endingSector = partitionEntry->StartingSector;
  2735. endingSector += partitionEntry->PartitionLength;
  2736. if (endingSector > MaxSector) {
  2737. partitionEntry->PartitionLength =
  2738. (ULONG)(MaxSector - partitionEntry->StartingSector);
  2739. }
  2740. }
  2741. BOOLEAN
  2742. HalpIsValidPartitionEntry(
  2743. PPARTITION_DESCRIPTOR Entry,
  2744. ULONGLONG MaxOffset,
  2745. ULONGLONG MaxSector
  2746. )
  2747. {
  2748. ULONGLONG endingSector;
  2749. PAGED_CODE();
  2750. if(Entry->PartitionType == PARTITION_ENTRY_UNUSED) {
  2751. //
  2752. // Unused partition entries are always valid.
  2753. //
  2754. return TRUE;
  2755. }
  2756. //
  2757. // Container partition entries and normal partition entries are valid iff
  2758. // the partition they describe can possibly fit on the disk. We add
  2759. // the base sector, the sector offset of the partition and the partition
  2760. // length. If they exceed the sector count then this partition entry
  2761. // is considered invalid.
  2762. //
  2763. //
  2764. // Do this in two steps to avoid 32-bit truncation.
  2765. //
  2766. endingSector = GET_STARTING_SECTOR(Entry);
  2767. endingSector += GET_PARTITION_LENGTH(Entry);
  2768. if(endingSector > MaxSector) {
  2769. KdPrintEx((DPFLTR_FSTUB_ID,
  2770. DPFLTR_TRACE_LEVEL,
  2771. "FSTUB: entry is invalid\n"));
  2772. KdPrintEx((DPFLTR_FSTUB_ID,
  2773. DPFLTR_TRACE_LEVEL,
  2774. "FSTUB: offset %#08lx\n",
  2775. GET_STARTING_SECTOR(Entry)));
  2776. KdPrintEx((DPFLTR_FSTUB_ID,
  2777. DPFLTR_TRACE_LEVEL,
  2778. "FSTUB: length %#08lx\n",
  2779. GET_PARTITION_LENGTH(Entry)));
  2780. KdPrintEx((DPFLTR_FSTUB_ID,
  2781. DPFLTR_TRACE_LEVEL,
  2782. "FSTUB: end %#I64x\n",
  2783. endingSector));
  2784. KdPrintEx((DPFLTR_FSTUB_ID,
  2785. DPFLTR_TRACE_LEVEL,
  2786. "FSTUB: max %#I64x\n",
  2787. MaxSector));
  2788. return FALSE;
  2789. } else if(GET_STARTING_SECTOR(Entry) > MaxOffset) {
  2790. KdPrintEx((DPFLTR_FSTUB_ID,
  2791. DPFLTR_TRACE_LEVEL,
  2792. "FSTUB: entry is invalid\n"));
  2793. KdPrintEx((DPFLTR_FSTUB_ID,
  2794. DPFLTR_TRACE_LEVEL,
  2795. "FSTUB: offset %#08lx\n",
  2796. GET_STARTING_SECTOR(Entry)));
  2797. KdPrintEx((DPFLTR_FSTUB_ID,
  2798. DPFLTR_TRACE_LEVEL,
  2799. "FSTUB: length %#08lx\n",
  2800. GET_PARTITION_LENGTH(Entry)));
  2801. KdPrintEx((DPFLTR_FSTUB_ID,
  2802. DPFLTR_TRACE_LEVEL,
  2803. "FSTUB: end %#I64x\n",
  2804. endingSector));
  2805. KdPrintEx((DPFLTR_FSTUB_ID,
  2806. DPFLTR_TRACE_LEVEL,
  2807. "FSTUB: maxOffset %#I64x\n",
  2808. MaxOffset));
  2809. return FALSE;
  2810. }
  2811. return TRUE;
  2812. }
  2813. NTSTATUS
  2814. HalpGetFullGeometry(
  2815. IN PDEVICE_OBJECT DeviceObject,
  2816. IN PDISK_GEOMETRY Geometry,
  2817. OUT PULONGLONG RealSectorCount
  2818. )
  2819. /*++
  2820. Routine Description:
  2821. We need this routine to get the number of cylinders that the disk driver
  2822. thinks is on the drive. We will need this to calculate CHS values
  2823. when we fill in the partition table entries.
  2824. Arguments:
  2825. DeviceObject - The device object describing the entire drive.
  2826. Geometry - The geometry of the drive
  2827. RealSectorCount - the actual number of sectors reported by the drive (
  2828. this may be less than the size computed by the geometry)
  2829. Return Value:
  2830. None.
  2831. --*/
  2832. {
  2833. PIRP localIrp;
  2834. IO_STATUS_BLOCK iosb;
  2835. PKEVENT eventPtr;
  2836. NTSTATUS status;
  2837. PAGED_CODE();
  2838. eventPtr = ExAllocatePoolWithTag(
  2839. NonPagedPool,
  2840. sizeof(KEVENT),
  2841. 'btsF'
  2842. );
  2843. if (!eventPtr) {
  2844. return STATUS_INSUFFICIENT_RESOURCES;
  2845. }
  2846. KeInitializeEvent(
  2847. eventPtr,
  2848. NotificationEvent,
  2849. FALSE
  2850. );
  2851. localIrp = IoBuildDeviceIoControlRequest(
  2852. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  2853. DeviceObject,
  2854. NULL,
  2855. 0UL,
  2856. Geometry,
  2857. sizeof(DISK_GEOMETRY),
  2858. FALSE,
  2859. eventPtr,
  2860. &iosb
  2861. );
  2862. if (!localIrp) {
  2863. ExFreePool(eventPtr);
  2864. return STATUS_INSUFFICIENT_RESOURCES;
  2865. }
  2866. //
  2867. // Call the lower level driver, wait for the opertion
  2868. // to finish.
  2869. //
  2870. status = IoCallDriver(
  2871. DeviceObject,
  2872. localIrp
  2873. );
  2874. if (status == STATUS_PENDING) {
  2875. (VOID) KeWaitForSingleObject(
  2876. eventPtr,
  2877. Executive,
  2878. KernelMode,
  2879. FALSE,
  2880. (PLARGE_INTEGER) NULL
  2881. );
  2882. status = iosb.Status;
  2883. }
  2884. KeClearEvent (eventPtr);
  2885. if(NT_SUCCESS(status)) {
  2886. PARTITION_INFORMATION partitionInfo;
  2887. localIrp = IoBuildDeviceIoControlRequest(
  2888. IOCTL_DISK_GET_PARTITION_INFO,
  2889. DeviceObject,
  2890. NULL,
  2891. 0UL,
  2892. &partitionInfo,
  2893. sizeof(PARTITION_INFORMATION),
  2894. FALSE,
  2895. eventPtr,
  2896. &iosb
  2897. );
  2898. if (!localIrp) {
  2899. ExFreePool(eventPtr);
  2900. return STATUS_INSUFFICIENT_RESOURCES;
  2901. }
  2902. //
  2903. // Call the lower level driver, wait for the opertion
  2904. // to finish.
  2905. //
  2906. status = IoCallDriver(
  2907. DeviceObject,
  2908. localIrp
  2909. );
  2910. if (status == STATUS_PENDING) {
  2911. (VOID) KeWaitForSingleObject(
  2912. eventPtr,
  2913. Executive,
  2914. KernelMode,
  2915. FALSE,
  2916. (PLARGE_INTEGER) NULL
  2917. );
  2918. status = iosb.Status;
  2919. }
  2920. if(NT_SUCCESS(status)) {
  2921. *RealSectorCount = (partitionInfo.PartitionLength.QuadPart /
  2922. Geometry->BytesPerSector);
  2923. }
  2924. }
  2925. ExFreePool(eventPtr);
  2926. return status;
  2927. }