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

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