2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fstub/disksup.c
5 * PURPOSE: I/O HAL Routines for Disk Access
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
8 * Casper S. Hornstrup (chorns@users.sourceforge.net)
12 /* INCLUDES ******************************************************************/
17 #include <internal/hal.h>
19 const WCHAR DiskMountString
[] = L
"\\DosDevices\\%C:";
21 #define AUTO_DRIVE MAXULONG
23 #define PARTITION_MAGIC 0xaa55
25 #define EFI_PMBR_OSTYPE_EFI 0xEE
29 typedef struct _REG_DISK_MOUNT_INFO
32 LARGE_INTEGER StartingOffset
;
33 } REG_DISK_MOUNT_INFO
, *PREG_DISK_MOUNT_INFO
;
37 typedef enum _DISK_MANAGER
44 typedef enum _PARTITION_TYPE
52 } PARTITION_TYPE
, *PPARTITION_TYPE
;
56 HalpQueryDriveLayout(IN PUNICODE_STRING DeviceName
,
57 OUT PDRIVE_LAYOUT_INFORMATION
*LayoutInfo
)
59 IO_STATUS_BLOCK StatusBlock
;
60 PDEVICE_OBJECT DeviceObject
= NULL
;
61 PFILE_OBJECT FileObject
;
66 PDRIVE_LAYOUT_INFORMATION Buffer
;
69 /* Get device pointers */
70 Status
= IoGetDeviceObjectPointer(DeviceName
,
74 if (!NT_SUCCESS(Status
))
79 /* Get attached device object */
80 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
81 ObDereferenceObject(FileObject
);
83 /* Do not handle removable media */
84 if (BooleanFlagOn(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
))
86 ObDereferenceObject(DeviceObject
);
87 return STATUS_NO_MEDIA
;
90 /* We'll loop until our buffer is big enough */
93 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
96 /* If we already had a buffer, it means it's not big
97 * enough, so free and multiply size by two
101 ExFreePoolWithTag(Buffer
, TAG_FSTUB
);
105 /* Allocate buffer for output buffer */
106 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, BufferSize
, TAG_FSTUB
);
109 Status
= STATUS_NO_MEMORY
;
113 /* Build the IRP to query drive layout */
114 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT
,
125 Status
= STATUS_INSUFFICIENT_RESOURCES
;
129 /* Call the driver and wait if appropriate */
130 Status
= IoCallDriver(DeviceObject
, Irp
);
131 if (Status
== STATUS_PENDING
)
133 KeWaitForSingleObject(&Event
,
138 Status
= StatusBlock
.Status
;
140 /* If buffer is too small, keep looping */
141 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
143 /* We're done with the device */
144 ObDereferenceObject(DeviceObject
);
146 /* If querying worked, then return the buffer to the caller */
147 if (NT_SUCCESS(Status
))
149 ASSERT(Buffer
!= NULL
);
150 *LayoutInfo
= Buffer
;
152 /* Else, release the buffer if still allocated and fail */
157 ExFreePoolWithTag(Buffer
, TAG_FSTUB
);
165 HalpQueryPartitionType(IN PUNICODE_STRING DeviceName
,
166 IN PDRIVE_LAYOUT_INFORMATION LayoutInfo
,
167 OUT PPARTITION_TYPE PartitionType
)
173 PFILE_OBJECT FileObject
;
174 PDEVICE_OBJECT DeviceObject
;
175 IO_STATUS_BLOCK IoStatusBlock
;
176 PARTITION_INFORMATION_EX PartitionInfo
;
180 /* Get device pointers */
181 Status
= IoGetDeviceObjectPointer(DeviceName
,
182 FILE_READ_ATTRIBUTES
,
185 if (!NT_SUCCESS(Status
))
190 /* Get attached device object */
191 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
192 ObDereferenceObject(FileObject
);
194 /* Assume logical partition for removable devices */
195 if (BooleanFlagOn(DeviceObject
->Characteristics
, FILE_REMOVABLE_MEDIA
))
197 ObDereferenceObject(DeviceObject
);
198 *PartitionType
= LogicalPartition
;
199 return STATUS_SUCCESS
;
202 /* For the others, query partition info */
203 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
204 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX
,
209 sizeof(PartitionInfo
),
215 ObDereferenceObject(DeviceObject
);
216 return STATUS_INSUFFICIENT_RESOURCES
;
219 Status
= IoCallDriver(DeviceObject
, Irp
);
220 if (Status
== STATUS_PENDING
)
222 KeWaitForSingleObject(&Event
,
227 Status
= IoStatusBlock
.Status
;
230 /* We're done with the device */
231 ObDereferenceObject(DeviceObject
);
233 /* If we failed querying partition info, try to return something
234 * if caller didn't provide a precise layout, assume logical
235 * partition and fake success. Otherwise, just fail.
237 if (!NT_SUCCESS(Status
))
239 if (LayoutInfo
== NULL
)
241 *PartitionType
= LogicalPartition
;
242 return STATUS_SUCCESS
;
248 /* First, handle non MBR style (easy cases) */
249 if (PartitionInfo
.PartitionStyle
!= PARTITION_STYLE_MBR
)
251 /* If not GPT, we don't know what it is */
252 if (PartitionInfo
.PartitionStyle
!= PARTITION_STYLE_GPT
)
254 *PartitionType
= UnknownPartition
;
255 return STATUS_SUCCESS
;
258 /* Check whether that's data partition */
259 if (RtlCompareMemory(&PartitionInfo
.Gpt
.PartitionType
,
260 &PARTITION_BASIC_DATA_GUID
,
261 sizeof(GUID
)) == sizeof(GUID
))
263 *PartitionType
= DataPartition
;
264 return STATUS_SUCCESS
;
267 /* Otherwise, we don't know */
268 *PartitionType
= UnknownPartition
;
269 return STATUS_SUCCESS
;
272 /* If we don't recognize partition type, return unknown */
273 if (!IsRecognizedPartition(PartitionInfo
.Mbr
.PartitionType
))
275 *PartitionType
= UnknownPartition
;
276 return STATUS_SUCCESS
;
279 /* Check if that's a FT volume */
280 if (PartitionInfo
.Mbr
.PartitionType
& PARTITION_NTFT
)
282 *PartitionType
= FtPartition
;
283 return STATUS_SUCCESS
;
286 /* If the caller didn't provide the complete layout, just return */
287 if (LayoutInfo
== NULL
)
289 *PartitionType
= LogicalPartition
;
290 return STATUS_SUCCESS
;
293 /* Now, evaluate the partition to the 4 in the input layout */
294 for (i
= 0; i
< 4; ++i
)
296 /* If we find a partition matching */
297 if (LayoutInfo
->PartitionEntry
[i
].StartingOffset
.QuadPart
== PartitionInfo
.StartingOffset
.QuadPart
)
299 /* Return boot if boot flag is set */
300 if (PartitionInfo
.Mbr
.BootIndicator
)
302 *PartitionType
= BootablePartition
;
304 /* Primary otherwise */
307 *PartitionType
= PrimaryPartition
;
310 return STATUS_SUCCESS
;
314 /* Otherwise, assume logical */
315 *PartitionType
= LogicalPartition
;
316 return STATUS_SUCCESS
;
320 IopComputeHarddiskDerangements(IN ULONG DiskCount
)
328 UNICODE_STRING ArcName
;
329 PFILE_OBJECT FileObject
;
330 PDEVICE_OBJECT DeviceObject
;
331 IO_STATUS_BLOCK IoStatusBlock
;
332 STORAGE_DEVICE_NUMBER DeviceNumber
;
334 /* No disks, nothing to do */
340 /* Allocate a buffer big enough to hold all the disks */
341 Devices
= ExAllocatePoolWithTag(PagedPool
| POOL_COLD_ALLOCATION
,
342 sizeof(ULONG
) * DiskCount
,
349 /* Now, we'll query all the disks */
350 for (i
= 0; i
< DiskCount
; ++i
)
352 /* Using their ARC name */
353 swprintf(Buffer
, L
"\\ArcName\\multi(0)disk(0)rdisk(%d)", i
);
354 RtlInitUnicodeString(&ArcName
, Buffer
);
355 /* Get the attached DeviceObject */
356 if (NT_SUCCESS(IoGetDeviceObjectPointer(&ArcName
, FILE_READ_ATTRIBUTES
, &FileObject
, &DeviceObject
)))
358 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
359 ObDereferenceObject(FileObject
);
361 /* And query it for device number */
362 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
363 Irp
= IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER
,
368 sizeof(DeviceNumber
),
374 Status
= IoCallDriver(DeviceObject
, Irp
);
375 if (Status
== STATUS_PENDING
)
377 KeWaitForSingleObject(&Event
,
382 Status
= IoStatusBlock
.Status
;
385 ObDereferenceObject(DeviceObject
);
387 /* In case of a success remember device number */
388 if (NT_SUCCESS(Status
))
390 Devices
[i
] = DeviceNumber
.DeviceNumber
;
391 /* Move on, not to fall into our default case */
397 ObDereferenceObject(DeviceObject
);
400 /* Default case, for failures, set -1 */
405 /* Now, we'll check all device numbers */
406 for (i
= 0; i
< DiskCount
; ++i
)
408 /* First of all, check if we're at the right place */
409 for (j
= 0; j
< DiskCount
; ++j
)
417 /* If not, perform the change */
421 while (Devices
[k
] != -1)
423 if (++k
>= DiskCount
)
436 /* Return our device derangement map */
441 HalpNextMountLetter(IN PUNICODE_STRING DeviceName
,
442 OUT PUCHAR DriveLetter
)
447 UNICODE_STRING MountMgr
;
448 PFILE_OBJECT FileObject
;
449 PDEVICE_OBJECT DeviceObject
;
450 IO_STATUS_BLOCK IoStatusBlock
;
451 PMOUNTMGR_DRIVE_LETTER_TARGET Target
;
452 MOUNTMGR_DRIVE_LETTER_INFORMATION LetterInfo
;
454 /* To get next mount letter, we need the MountMgr */
455 RtlInitUnicodeString(&MountMgr
, L
"\\Device\\MountPointManager");
456 Status
= IoGetDeviceObjectPointer(&MountMgr
,
457 FILE_READ_ATTRIBUTES
,
460 if (!NT_SUCCESS(Status
))
465 /* Allocate our input buffer */
466 Target
= ExAllocatePoolWithTag(PagedPool
,
467 DeviceName
->Length
+ FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET
, DeviceName
),
471 ObDereferenceObject(FileObject
);
472 return STATUS_INSUFFICIENT_RESOURCES
;
475 /* And fill it with the device hat needs a drive letter */
476 Target
->DeviceNameLength
= DeviceName
->Length
;
477 RtlCopyMemory(&Target
->DeviceName
[0], DeviceName
->Buffer
, DeviceName
->Length
);
479 /* Call the mount manager */
480 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
481 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER
,
484 DeviceName
->Length
+ FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET
, DeviceName
),
492 ExFreePoolWithTag(Target
, TAG_FSTUB
);
493 ObDereferenceObject(FileObject
);
494 return STATUS_INSUFFICIENT_RESOURCES
;
497 Status
= IoCallDriver(DeviceObject
, Irp
);
498 if (Status
== STATUS_PENDING
)
500 KeWaitForSingleObject(&Event
,
505 Status
= IoStatusBlock
.Status
;
508 ExFreePoolWithTag(Target
, TAG_FSTUB
);
509 ObDereferenceObject(FileObject
);
511 DPRINT("Done: %d %c\n", LetterInfo
.DriveLetterWasAssigned
,
512 LetterInfo
.CurrentDriveLetter
);
514 /* Return the drive letter the MountMgr potentially assigned */
515 *DriveLetter
= LetterInfo
.CurrentDriveLetter
;
517 /* Also return the success */
522 HalpSetMountLetter(IN PUNICODE_STRING DeviceName
,
529 ULONG InputBufferLength
;
530 PFILE_OBJECT FileObject
;
531 PDEVICE_OBJECT DeviceObject
;
532 IO_STATUS_BLOCK IoStatusBlock
;
533 UNICODE_STRING DosDevice
, MountMgr
;
534 PMOUNTMGR_CREATE_POINT_INPUT InputBuffer
;
536 /* Setup the DosDevice name */
537 swprintf(Buffer
, L
"\\DosDevices\\%c:", DriveLetter
);
538 RtlInitUnicodeString(&DosDevice
, Buffer
);
540 /* Allocate the input buffer for the MountMgr */
541 InputBufferLength
= DosDevice
.Length
+ DeviceName
->Length
+ sizeof(MOUNTMGR_CREATE_POINT_INPUT
);
542 InputBuffer
= ExAllocatePoolWithTag(PagedPool
, InputBufferLength
, TAG_FSTUB
);
543 if (InputBuffer
== NULL
)
545 return STATUS_INSUFFICIENT_RESOURCES
;
548 /* Fill the input buffer */
549 InputBuffer
->SymbolicLinkNameOffset
= sizeof(MOUNTMGR_CREATE_POINT_INPUT
);
550 InputBuffer
->SymbolicLinkNameLength
= DosDevice
.Length
;
551 InputBuffer
->DeviceNameOffset
= DosDevice
.Length
+ sizeof(MOUNTMGR_CREATE_POINT_INPUT
);
552 InputBuffer
->DeviceNameLength
= DeviceName
->Length
;
553 RtlCopyMemory(&InputBuffer
[1], DosDevice
.Buffer
, DosDevice
.Length
);
554 RtlCopyMemory((PVOID
)((ULONG_PTR
)InputBuffer
+ InputBuffer
->DeviceNameOffset
),
558 /* Get the MountMgr device pointer, to send the IOCTL */
559 RtlInitUnicodeString(&MountMgr
, L
"\\Device\\MountPointManager");
560 Status
= IoGetDeviceObjectPointer(&MountMgr
,
561 FILE_READ_ATTRIBUTES
,
564 if (!NT_SUCCESS(Status
))
566 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
570 /* Call the MountMgr */
571 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
572 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CREATE_POINT
,
583 ObDereferenceObject(FileObject
);
584 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
585 return STATUS_INSUFFICIENT_RESOURCES
;
588 Status
= IoCallDriver(DeviceObject
, Irp
);
589 if (Status
== STATUS_PENDING
)
591 KeWaitForSingleObject(&Event
,
596 Status
= IoStatusBlock
.Status
;
599 ObDereferenceObject(FileObject
);
600 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
602 /* Return the MountMgr status */
607 HalpNextDriveLetter(IN PUNICODE_STRING DeviceName
,
608 IN PSTRING NtDeviceName
,
609 OUT PUCHAR NtSystemPath
,
615 UNICODE_STRING FloppyString
, CdString
, NtDeviceNameU
, DosDevice
;
617 /* Quick path, ask directly the mount manager to assign the next
620 if (NT_SUCCESS(HalpNextMountLetter(DeviceName
, &DriveLetter
)))
625 /* We'll allow MountMgr to fail only for non vital path */
626 if (NtDeviceName
== NULL
|| NtSystemPath
== NULL
)
631 /* And for removable devices */
637 /* Removable might be floppy or cdrom */
638 RtlInitUnicodeString(&FloppyString
, L
"\\Device\\Floppy");
639 RtlInitUnicodeString(&CdString
, L
"\\Device\\CdRom");
641 /* If floppy, start at A */
642 if (RtlPrefixUnicodeString(&FloppyString
, DeviceName
, TRUE
))
647 else if (RtlPrefixUnicodeString(&CdString
, DeviceName
, TRUE
))
651 /* For the rest start at C */
657 /* Now, try to assign a drive letter manually with the MountMgr */
658 for (i
= DriveLetter
; i
<= 'Z'; ++i
)
660 if (NT_SUCCESS(HalpSetMountLetter(DeviceName
, i
)))
662 /* If it worked, if we were managing system path, update manually */
663 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU
, NtDeviceName
, TRUE
)))
665 if (RtlEqualUnicodeString(&NtDeviceNameU
, DeviceName
, TRUE
))
670 RtlFreeUnicodeString(&NtDeviceNameU
);
677 /* Last fall back, we're not on a PnP device... */
678 for (i
= DriveLetter
; i
<= 'Z'; ++i
)
680 /* We'll link manually, without MountMgr knowing anything about the device */
681 swprintf(Buffer
, L
"\\DosDevices\\%c:", i
);
682 RtlInitUnicodeString(&DosDevice
, Buffer
);
684 /* If linking worked, then the letter was free ;-) */
685 if (NT_SUCCESS(IoCreateSymbolicLink(&DosDevice
, DeviceName
)))
687 /* If it worked, if we were managing system path, update manually */
688 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU
, NtDeviceName
, TRUE
)))
690 if (RtlEqualUnicodeString(&NtDeviceNameU
, DeviceName
, TRUE
))
695 RtlFreeUnicodeString(&NtDeviceNameU
);
702 /* We're done, nothing happened */
707 HalpIsOldStyleFloppy(PUNICODE_STRING DeviceName
)
712 MOUNTDEV_NAME DevName
;
713 PFILE_OBJECT FileObject
;
714 PDEVICE_OBJECT DeviceObject
;
715 IO_STATUS_BLOCK IoStatusBlock
;
718 /* Get the attached device object to our device */
719 if (!NT_SUCCESS(IoGetDeviceObjectPointer(DeviceName
,
720 FILE_READ_ATTRIBUTES
,
727 DeviceObject
= IoGetAttachedDeviceReference(FileObject
->DeviceObject
);
728 ObDereferenceObject(FileObject
);
730 /* Query its device name (ie, check floppy.sys implements MountMgr interface) */
731 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
732 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
743 ObDereferenceObject(DeviceObject
);
747 Status
= IoCallDriver(DeviceObject
, Irp
);
748 if (Status
== STATUS_PENDING
)
750 KeWaitForSingleObject(&Event
,
755 Status
= IoStatusBlock
.Status
;
758 /* If status is not STATUS_BUFFER_OVERFLOW, it means
759 * it's pre-mountmgr driver, aka "Old style".
761 ObDereferenceObject(DeviceObject
);
762 return (Status
!= STATUS_BUFFER_OVERFLOW
);
766 HalpDeleteMountLetter(UCHAR DriveLetter
)
772 ULONG InputBufferLength
;
773 PFILE_OBJECT FileObject
;
774 PDEVICE_OBJECT DeviceObject
;
775 IO_STATUS_BLOCK IoStatusBlock
;
776 PMOUNTMGR_MOUNT_POINT InputBuffer
;
777 UNICODE_STRING DosDevice
, MountMgr
;
778 PMOUNTMGR_MOUNT_POINTS OutputBuffer
;
780 /* Setup the device name of the letter to delete */
781 swprintf(Buffer
, L
"\\DosDevices\\%c:", DriveLetter
);
782 RtlInitUnicodeString(&DosDevice
, Buffer
);
784 /* Allocate the input buffer for MountMgr */
785 InputBufferLength
= DosDevice
.Length
+ sizeof(MOUNTMGR_MOUNT_POINT
);
786 InputBuffer
= ExAllocatePoolWithTag(PagedPool
, InputBufferLength
, TAG_FSTUB
);
787 if (InputBuffer
== NULL
)
789 return STATUS_INSUFFICIENT_RESOURCES
;
793 RtlZeroMemory(InputBuffer
, InputBufferLength
);
794 InputBuffer
->SymbolicLinkNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
795 InputBuffer
->SymbolicLinkNameLength
= DosDevice
.Length
;
796 RtlCopyMemory(&InputBuffer
[1], DosDevice
.Buffer
, DosDevice
.Length
);
798 /* Allocate big enough output buffer (we don't care about the output) */
799 OutputBuffer
= ExAllocatePoolWithTag(PagedPool
, 0x1000, TAG_FSTUB
);
800 if (OutputBuffer
== NULL
)
802 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
803 return STATUS_INSUFFICIENT_RESOURCES
;
806 /* Get the device pointer to the MountMgr */
807 RtlInitUnicodeString(&MountMgr
, L
"\\Device\\MountPointManager");
808 Status
= IoGetDeviceObjectPointer(&MountMgr
,
809 FILE_READ_ATTRIBUTES
,
812 if (!NT_SUCCESS(Status
))
814 ExFreePoolWithTag(OutputBuffer
, TAG_FSTUB
);
815 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
819 /* Call the mount manager to delete the drive letter */
820 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
821 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS
,
832 ObDereferenceObject(FileObject
);
833 ExFreePoolWithTag(OutputBuffer
, TAG_FSTUB
);
834 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
835 return STATUS_INSUFFICIENT_RESOURCES
;
838 Status
= IoCallDriver(DeviceObject
, Irp
);
839 if (Status
== STATUS_PENDING
)
841 KeWaitForSingleObject(&Event
,
846 Status
= IoStatusBlock
.Status
;
849 ObDereferenceObject(FileObject
);
850 ExFreePoolWithTag(OutputBuffer
, TAG_FSTUB
);
851 ExFreePoolWithTag(InputBuffer
, TAG_FSTUB
);
857 HalpEnableAutomaticDriveLetterAssignment(VOID
)
862 UNICODE_STRING MountMgr
;
863 PFILE_OBJECT FileObject
;
864 PDEVICE_OBJECT DeviceObject
;
865 IO_STATUS_BLOCK IoStatusBlock
;
867 /* Get the device pointer to the MountMgr */
868 RtlInitUnicodeString(&MountMgr
, L
"\\Device\\MountPointManager");
869 Status
= IoGetDeviceObjectPointer(&MountMgr
,
870 FILE_READ_ATTRIBUTES
,
873 if (!NT_SUCCESS(Status
))
878 /* Just send an IOCTL to enable the feature */
879 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
880 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS
,
894 Status
= IoCallDriver(DeviceObject
, Irp
);
895 if (Status
== STATUS_PENDING
)
897 KeWaitForSingleObject(&Event
,
902 Status
= IoStatusBlock
.Status
;
905 ObDereferenceObject(FileObject
);
912 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
913 IN PSTRING NtDeviceName
,
914 OUT PUCHAR NtSystemPath
,
915 OUT PSTRING NtSystemPathString
)
924 IO_STATUS_BLOCK StatusBlock
;
925 PARTITION_TYPE PartitionType
;
926 ANSI_STRING StringA1
, StringA2
;
927 PSTR Buffer1
, Buffer2
, LoadOptions
;
928 OBJECT_ATTRIBUTES ObjectAttributes
;
929 PDRIVE_LAYOUT_INFORMATION LayoutInfo
;
930 PCONFIGURATION_INFORMATION ConfigInfo
;
931 UNICODE_STRING StringU1
, StringU2
, StringU3
;
932 ULONG Increment
, DiskCount
, RealDiskCount
, HarddiskCount
, PartitionCount
, SystemPartition
;
936 /* Get our disk count */
937 ConfigInfo
= IoGetConfigurationInformation();
938 DiskCount
= ConfigInfo
->DiskCount
;
941 /* Allocate two generic string buffers we'll use and reuser later on */
942 Buffer1
= ExAllocatePoolWithTag(NonPagedPool
, 128, TAG_FSTUB
);
943 Buffer2
= ExAllocatePoolWithTag(NonPagedPool
, 64, TAG_FSTUB
);
944 if (Buffer1
== NULL
|| Buffer2
== NULL
)
946 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED
);
949 /* In case of a remote boot, setup system path */
950 if (IoRemoteBootClient
)
955 Last
= strrchr(LoaderBlock
->NtBootPathName
, '\\');
957 /* Misformed name, fail */
960 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED
);
963 /* In case the name was terminated by a \... */
964 if (Last
[1] == ANSI_NULL
)
966 /* Erase it, save position and find the previous \ */
969 Last
= strrchr(LoaderBlock
->NtBootPathName
, '\\');
973 /* Misformed name, fail */
976 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED
);
979 /* For a remote boot, assign X drive letter */
980 NtSystemPath
[0] = 'X';
981 NtSystemPath
[1] = ':';
982 /* And copy the end of the boot path */
983 strcpy((PSTR
)&NtSystemPath
[2], Last
);
985 /* If we had to remove the trailing \, remove it here too */
988 NtSystemPath
[strlen((PSTR
)NtSystemPath
) - 1] = ANSI_NULL
;
991 /* Setup output string */
992 RtlInitString(NtSystemPathString
, (PSTR
)NtSystemPath
);
995 /* For each of our disks, create the physical device DOS device */
999 for (i
= 0; i
< DiskCount
; ++i
)
1001 /* Setup the origin name */
1002 sprintf(Buffer1
, "\\Device\\Harddisk%d\\Partition%d", i
, 0);
1003 RtlInitAnsiString(&StringA1
, Buffer1
);
1004 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1
, &StringA1
, TRUE
)))
1006 /* We cannot fail */
1007 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED
);
1010 /* Open the device */
1011 InitializeObjectAttributes(&ObjectAttributes
,
1013 OBJ_CASE_INSENSITIVE
,
1016 Status
= ZwOpenFile(&FileHandle
,
1017 SYNCHRONIZE
| FILE_READ_DATA
,
1021 FILE_SYNCHRONOUS_IO_NONALERT
);
1022 if (NT_SUCCESS(Status
))
1024 /* If we managed, create the link */
1025 sprintf(Buffer2
, "\\DosDevices\\PhysicalDrive%d", i
);
1026 RtlInitAnsiString(&StringA2
, Buffer2
);
1027 Status
= RtlAnsiStringToUnicodeString(&StringU2
, &StringA2
, TRUE
);
1028 if (NT_SUCCESS(Status
))
1030 IoCreateSymbolicLink(&StringU2
, &StringU1
);
1031 RtlFreeUnicodeString(&StringU2
);
1034 ZwClose(FileHandle
);
1036 RealDiskCount
= i
+ 1;
1039 RtlFreeUnicodeString(&StringU1
);
1041 if (!NT_SUCCESS(Status
))
1052 /* We done for our buffers */
1053 ExFreePoolWithTag(Buffer1
, TAG_FSTUB
);
1054 ExFreePoolWithTag(Buffer2
, TAG_FSTUB
);
1056 /* Upcase our load options, if any */
1057 if (LoaderBlock
->LoadOptions
!= NULL
)
1059 LoadOptions
= _strupr(LoaderBlock
->LoadOptions
);
1066 /* If we boot with /MININT (system hive as volatile) option, assign X letter to boot device */
1067 if (LoadOptions
!= NULL
&&
1068 strstr(LoadOptions
, "MININT") != 0 &&
1069 NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1
, NtDeviceName
, TRUE
)))
1071 if (NT_SUCCESS(HalpSetMountLetter(&StringU1
, 'X')))
1073 *NtSystemPath
= 'X';
1076 RtlFreeUnicodeString(&StringU1
);
1079 /* Compute our disks derangements */
1080 DiskCount
-= Increment
;
1081 if (RealDiskCount
> DiskCount
)
1083 DiskCount
= RealDiskCount
;
1085 Devices
= IopComputeHarddiskDerangements(DiskCount
);
1087 /* Now, start browsing all our disks for assigning drive letters
1088 * Here, we'll only handle boot partition and primary partitions
1091 for (i
= 0; i
< DiskCount
; ++i
)
1093 /* Get device ID according to derangements map */
1094 if (Devices
!= NULL
)
1096 HarddiskCount
= Devices
[i
];
1099 /* Query disk layout */
1100 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition0", HarddiskCount
);
1101 RtlInitUnicodeString(&StringU1
, Buffer
);
1102 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1
, &LayoutInfo
)))
1107 /* Assume we didn't find system */
1108 SystemFound
= FALSE
;
1109 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, 1);
1110 RtlInitUnicodeString(&StringU1
, Buffer
);
1111 /* Query partition info for our disk */
1112 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1114 /* It failed, retry for all the partitions */
1115 for (PartitionCount
= 1; ; ++PartitionCount
)
1117 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, PartitionCount
);
1118 RtlInitUnicodeString(&StringU1
, Buffer
);
1119 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1124 /* We found a primary partition, assign a drive letter */
1125 if (PartitionType
== PrimaryPartition
)
1127 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, 0);
1135 for (PartitionCount
= 2; ; ++PartitionCount
)
1137 /* If our partition is bootable (MBR) or data (GPT), that's system partition */
1138 if (PartitionType
== BootablePartition
|| PartitionType
== DataPartition
)
1142 /* Assign a drive letter and stop here if MBR */
1143 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, 0);
1144 if (PartitionType
== BootablePartition
)
1150 /* Keep looping on all the partitions */
1151 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, PartitionCount
);
1152 RtlInitUnicodeString(&StringU1
, Buffer
);
1153 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1155 /* Mount every primary partition if we didn't find system */
1158 for (PartitionCount
= 1; ; ++PartitionCount
)
1160 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, PartitionCount
);
1161 RtlInitUnicodeString(&StringU1
, Buffer
);
1162 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1167 if (PartitionType
== PrimaryPartition
)
1169 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, 0);
1180 /* Free layout, we'll reallocate it for next device */
1181 if (LayoutInfo
!= NULL
)
1183 ExFreePoolWithTag(LayoutInfo
, TAG_FSTUB
);
1186 HarddiskCount
= i
+ 1;
1189 /* Now, assign logical partitions */
1190 for (i
= 0; i
< DiskCount
; ++i
)
1192 /* Get device ID according to derangements map */
1193 if (Devices
!= NULL
)
1195 HarddiskCount
= Devices
[i
];
1202 /* Query device layout */
1203 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition0", HarddiskCount
);
1204 RtlInitUnicodeString(&StringU1
, Buffer
);
1205 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1
, &LayoutInfo
)))
1210 /* And assign drive letter to logical partitions */
1211 for (PartitionCount
= 1; ; ++PartitionCount
)
1213 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, PartitionCount
);
1214 RtlInitUnicodeString(&StringU1
, Buffer
);
1215 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1220 if (PartitionType
== LogicalPartition
)
1222 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, 0);
1226 /* Free layout, we'll reallocate it for next device */
1227 if (LayoutInfo
!= NULL
)
1229 ExFreePoolWithTag(LayoutInfo
, 0);
1233 /* Now, assign drive letters to everything else */
1234 for (i
= 0; i
< DiskCount
; ++i
)
1236 /* Get device ID according to derangements map */
1237 if (Devices
!= NULL
)
1239 HarddiskCount
= Devices
[i
];
1246 /* Query device layout */
1247 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition0", HarddiskCount
);
1248 RtlInitUnicodeString(&StringU1
, Buffer
);
1249 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1
, &LayoutInfo
)))
1254 /* Save system partition if any */
1255 SystemPartition
= 0;
1256 for (PartitionCount
= 1; ; ++PartitionCount
)
1258 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, PartitionCount
);
1259 RtlInitUnicodeString(&StringU1
, Buffer
);
1260 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1265 if ((PartitionType
== BootablePartition
|| PartitionType
== PrimaryPartition
) && (SystemPartition
== 0))
1267 SystemPartition
= PartitionCount
;
1271 /* And assign drive letter to anything but system partition */
1272 for (PartitionCount
= 1; ; ++PartitionCount
)
1274 if (PartitionCount
!= SystemPartition
)
1276 swprintf(Buffer
, L
"\\Device\\Harddisk%d\\Partition%d", HarddiskCount
, PartitionCount
);
1277 RtlInitUnicodeString(&StringU1
, Buffer
);
1278 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1
, LayoutInfo
, &PartitionType
)))
1280 if (LayoutInfo
!= NULL
)
1282 ExFreePoolWithTag(LayoutInfo
, 0);
1288 if (PartitionType
== PrimaryPartition
|| PartitionType
== FtPartition
)
1290 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, 0);
1296 /* We're done with disks, if we have a device map, free it */
1297 if (Devices
!= NULL
)
1299 ExFreePoolWithTag(Devices
, TAG_FSTUB
);
1302 /* Now, assign drive letter to floppy drives */
1303 for (i
= 0; i
< ConfigInfo
->FloppyCount
; ++i
)
1305 swprintf(Buffer
, L
"\\Device\\Floppy%d", i
);
1306 RtlInitUnicodeString(&StringU1
, Buffer
);
1307 if (HalpIsOldStyleFloppy(&StringU1
))
1309 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, TRUE
);
1314 for (i
= 0; i
< ConfigInfo
->CdRomCount
; ++i
)
1316 swprintf(Buffer
, L
"\\Device\\CdRom%d", i
);
1317 RtlInitUnicodeString(&StringU1
, Buffer
);
1318 HalpNextDriveLetter(&StringU1
, NtDeviceName
, NtSystemPath
, TRUE
);
1321 /* If not remote boot, handle NtDeviceName */
1322 if (!IoRemoteBootClient
&& NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1
, NtDeviceName
, TRUE
)))
1324 /* Assign it a drive letter */
1325 DriveLetter
= HalpNextDriveLetter(&StringU1
, NULL
, NULL
, TRUE
);
1326 if (DriveLetter
!= 0)
1328 if (DriveLetter
!= 0xFF)
1330 *NtSystemPath
= DriveLetter
;
1333 /* If it fails through mount manager, retry manually */
1336 RtlInitUnicodeString(&StringU2
, L
"\\Device\\Floppy");
1337 RtlInitUnicodeString(&StringU3
, L
"\\Device\\CdRom");
1339 if (RtlPrefixUnicodeString(&StringU2
, &StringU1
, TRUE
))
1343 else if (RtlPrefixUnicodeString(&StringU3
, &StringU1
, TRUE
))
1352 /* Try any drive letter */
1353 while (HalpSetMountLetter(&StringU1
, DriveLetter
) != STATUS_SUCCESS
)
1357 if (DriveLetter
> 'Z')
1363 /* If we're beyond Z (ie, no slot left) */
1364 if (DriveLetter
> 'Z')
1366 /* Delete Z, and reuse it for system */
1367 HalpDeleteMountLetter('Z');
1368 HalpSetMountLetter(&StringU1
, 'Z');
1369 *NtSystemPath
= 'Z';
1373 /* Return matching drive letter */
1374 *NtSystemPath
= DriveLetter
;
1378 RtlFreeUnicodeString(&StringU1
);
1381 /* Enable auto assignement for mountmgr */
1382 HalpEnableAutomaticDriveLetterAssignment();
1385 /* PRIVATE FUNCTIONS *********************************************************/
1389 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject
,
1390 IN PDISK_GEOMETRY Geometry
,
1391 OUT PULONGLONG RealSectorCount
)
1394 IO_STATUS_BLOCK IoStatusBlock
;
1397 PARTITION_INFORMATION PartitionInfo
;
1400 /* Allocate a non-paged event */
1401 Event
= ExAllocatePoolWithTag(NonPagedPool
,
1404 if (!Event
) return STATUS_INSUFFICIENT_RESOURCES
;
1407 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
1410 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1415 sizeof(DISK_GEOMETRY
),
1421 /* Fail, free the event */
1422 ExFreePoolWithTag(Event
, TAG_FILE_SYSTEM
);
1423 return STATUS_INSUFFICIENT_RESOURCES
;
1426 /* Call the driver and check if it's pending */
1427 Status
= IoCallDriver(DeviceObject
, Irp
);
1428 if (Status
== STATUS_PENDING
)
1430 /* Wait on the driver */
1431 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
1432 Status
= IoStatusBlock
.Status
;
1435 /* Check if the driver returned success */
1436 if(NT_SUCCESS(Status
))
1438 /* Build another IRP */
1439 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO
,
1444 sizeof(PARTITION_INFORMATION
),
1450 /* Fail, free the event */
1451 ExFreePoolWithTag(Event
, TAG_FILE_SYSTEM
);
1452 return STATUS_INSUFFICIENT_RESOURCES
;
1456 KeClearEvent(Event
);
1458 /* Call the driver and check if it's pending */
1459 Status
= IoCallDriver(DeviceObject
, Irp
);
1460 if (Status
== STATUS_PENDING
)
1462 /* Wait on the driver */
1463 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
1464 Status
= IoStatusBlock
.Status
;
1467 /* Check if the driver returned success */
1468 if(NT_SUCCESS(Status
))
1470 /* Get the number of sectors */
1471 *RealSectorCount
= (PartitionInfo
.PartitionLength
.QuadPart
/
1472 Geometry
->BytesPerSector
);
1476 /* Free the event and return the Status */
1477 ExFreePoolWithTag(Event
, TAG_FILE_SYSTEM
);
1483 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry
,
1484 IN ULONGLONG MaxOffset
,
1485 IN ULONGLONG MaxSector
)
1487 ULONGLONG EndingSector
;
1490 /* Unused partitions are considered valid */
1491 if (Entry
->PartitionType
== PARTITION_ENTRY_UNUSED
) return TRUE
;
1493 /* Get the last sector of the partition */
1494 EndingSector
= GET_STARTING_SECTOR(Entry
) + GET_PARTITION_LENGTH(Entry
);
1496 /* Check if it's more then the maximum sector */
1497 if (EndingSector
> MaxSector
)
1499 /* Invalid partition */
1500 DPRINT1("FSTUB: entry is invalid\n");
1501 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry
));
1502 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry
));
1503 DPRINT1("FSTUB: end %#I64x\n", EndingSector
);
1504 DPRINT1("FSTUB: max %#I64x\n", MaxSector
);
1507 else if(GET_STARTING_SECTOR(Entry
) > MaxOffset
)
1509 /* Invalid partition */
1510 DPRINT1("FSTUB: entry is invalid\n");
1511 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry
));
1512 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry
));
1513 DPRINT1("FSTUB: end %#I64x\n", EndingSector
);
1514 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset
);
1518 /* It's fine, return success */
1524 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset
,
1525 IN PLARGE_INTEGER PartitionLength
,
1526 IN CCHAR ShiftCount
,
1527 IN ULONG SectorsPerTrack
,
1528 IN ULONG NumberOfTracks
,
1529 IN ULONG ConventionalCylinders
,
1530 OUT PPARTITION_DESCRIPTOR PartitionDescriptor
)
1532 LARGE_INTEGER FirstSector
, SectorCount
;
1533 ULONG LastSector
, Remainder
, SectorsPerCylinder
;
1534 ULONG StartingCylinder
, EndingCylinder
;
1535 ULONG StartingTrack
, EndingTrack
;
1536 ULONG StartingSector
, EndingSector
;
1539 /* Calculate the number of sectors for each cylinder */
1540 SectorsPerCylinder
= SectorsPerTrack
* NumberOfTracks
;
1542 /* Calculate the first sector, and the sector count */
1543 FirstSector
.QuadPart
= PartitionOffset
->QuadPart
>> ShiftCount
;
1544 SectorCount
.QuadPart
= PartitionLength
->QuadPart
>> ShiftCount
;
1546 /* Now calculate the last sector */
1547 LastSector
= FirstSector
.LowPart
+ SectorCount
.LowPart
- 1;
1549 /* Calculate the first and last cylinders */
1550 StartingCylinder
= FirstSector
.LowPart
/ SectorsPerCylinder
;
1551 EndingCylinder
= LastSector
/ SectorsPerCylinder
;
1553 /* Set the default number of cylinders */
1554 if (!ConventionalCylinders
) ConventionalCylinders
= 1024;
1556 /* Normalize the values */
1557 if (StartingCylinder
>= ConventionalCylinders
)
1559 /* Set the maximum to 1023 */
1560 StartingCylinder
= ConventionalCylinders
- 1;
1562 if (EndingCylinder
>= ConventionalCylinders
)
1564 /* Set the maximum to 1023 */
1565 EndingCylinder
= ConventionalCylinders
- 1;
1568 /* Calculate the starting head and sector that still remain */
1569 Remainder
= FirstSector
.LowPart
% SectorsPerCylinder
;
1570 StartingTrack
= Remainder
/ SectorsPerTrack
;
1571 StartingSector
= Remainder
% SectorsPerTrack
;
1573 /* Calculate the ending head and sector that still remain */
1574 Remainder
= LastSector
% SectorsPerCylinder
;
1575 EndingTrack
= Remainder
/ SectorsPerTrack
;
1576 EndingSector
= Remainder
% SectorsPerTrack
;
1578 /* Set cylinder data for the MSB */
1579 PartitionDescriptor
->StartingCylinderMsb
= (UCHAR
)StartingCylinder
;
1580 PartitionDescriptor
->EndingCylinderMsb
= (UCHAR
)EndingCylinder
;
1582 /* Set the track data */
1583 PartitionDescriptor
->StartingTrack
= (UCHAR
)StartingTrack
;
1584 PartitionDescriptor
->EndingTrack
= (UCHAR
)EndingTrack
;
1586 /* Update cylinder data for the LSB */
1587 StartingCylinder
= ((StartingSector
+ 1) & 0x3F) |
1588 ((StartingCylinder
>> 2) & 0xC0);
1589 EndingCylinder
= ((EndingSector
+ 1) & 0x3F) |
1590 ((EndingCylinder
>> 2) & 0xC0);
1592 /* Set the cylinder data for the LSB */
1593 PartitionDescriptor
->StartingCylinderLsb
= (UCHAR
)StartingCylinder
;
1594 PartitionDescriptor
->EndingCylinderLsb
= (UCHAR
)EndingCylinder
;
1599 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject
,
1600 IN PULONG ConventionalCylinders
,
1601 IN PLONGLONG DiskSize
)
1603 PDISK_GEOMETRY DiskGeometry
= NULL
;
1604 PIO_STATUS_BLOCK IoStatusBlock
= NULL
;
1605 PKEVENT Event
= NULL
;
1610 *ConventionalCylinders
= 0;
1613 /* Allocate the structure in nonpaged pool */
1614 DiskGeometry
= ExAllocatePoolWithTag(NonPagedPool
,
1615 sizeof(DISK_GEOMETRY
),
1617 if (!DiskGeometry
) goto Cleanup
;
1619 /* Allocate the status block in nonpaged pool */
1620 IoStatusBlock
= ExAllocatePoolWithTag(NonPagedPool
,
1621 sizeof(IO_STATUS_BLOCK
),
1623 if (!IoStatusBlock
) goto Cleanup
;
1625 /* Allocate the event in nonpaged pool too */
1626 Event
= ExAllocatePoolWithTag(NonPagedPool
,
1629 if (!Event
) goto Cleanup
;
1631 /* Initialize the event */
1632 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
1635 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1640 sizeof(DISK_GEOMETRY
),
1644 if (!Irp
) goto Cleanup
;
1646 /* Now call the driver */
1647 Status
= IoCallDriver(DeviceObject
, Irp
);
1648 if (Status
== STATUS_PENDING
)
1650 /* Wait for it to complete */
1651 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
1652 Status
= IoStatusBlock
->Status
;
1655 /* Check driver status */
1656 if (NT_SUCCESS(Status
))
1658 /* Return the cylinder count */
1659 *ConventionalCylinders
= DiskGeometry
->Cylinders
.LowPart
;
1661 /* Make sure it's not larger then 1024 */
1662 if (DiskGeometry
->Cylinders
.LowPart
>= 1024)
1664 /* Otherwise, normalize the value */
1665 *ConventionalCylinders
= 1024;
1668 /* Calculate the disk size */
1669 *DiskSize
= DiskGeometry
->Cylinders
.QuadPart
*
1670 DiskGeometry
->TracksPerCylinder
*
1671 DiskGeometry
->SectorsPerTrack
*
1672 DiskGeometry
->BytesPerSector
;
1676 /* Free all the pointers */
1677 if (Event
) ExFreePoolWithTag(Event
, TAG_FILE_SYSTEM
);
1678 if (IoStatusBlock
) ExFreePoolWithTag(IoStatusBlock
, TAG_FILE_SYSTEM
);
1679 if (DiskGeometry
) ExFreePoolWithTag(DiskGeometry
, TAG_FILE_SYSTEM
);
1685 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject
,
1686 IN ULONG SectorSize
,
1687 IN ULONG MbrTypeIdentifier
,
1688 OUT PVOID
*MbrBuffer
)
1690 LARGE_INTEGER Offset
;
1694 IO_STATUS_BLOCK IoStatusBlock
;
1696 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1698 PIO_STACK_LOCATION IoStackLocation
;
1699 Offset
.QuadPart
= 0;
1701 /* Assume failure */
1704 /* Normalize the buffer size */
1705 BufferSize
= max(SectorSize
, 512);
1707 /* Allocate the buffer */
1708 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1709 PAGE_SIZE
> BufferSize
?
1710 PAGE_SIZE
: BufferSize
,
1712 if (!Buffer
) return;
1714 /* Initialize the Event */
1715 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1718 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1728 ExFreePoolWithTag(Buffer
, TAG_FILE_SYSTEM
);
1732 /* Make sure to override volume verification */
1733 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1734 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1736 /* Call the driver */
1737 Status
= IoCallDriver(DeviceObject
, Irp
);
1738 if (Status
== STATUS_PENDING
)
1740 /* Wait for completion */
1741 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1742 Status
= IoStatusBlock
.Status
;
1745 /* Check driver Status */
1746 if (NT_SUCCESS(Status
))
1748 /* Validate the MBR Signature */
1749 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1752 ExFreePoolWithTag(Buffer
, TAG_FILE_SYSTEM
);
1756 /* Get the partition entry */
1757 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1758 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1760 /* Make sure it's what the caller wanted */
1761 if (PartitionDescriptor
->PartitionType
!= MbrTypeIdentifier
)
1763 /* It's not, free our buffer */
1764 ExFreePoolWithTag(Buffer
, TAG_FILE_SYSTEM
);
1768 /* Check if this is a secondary entry */
1769 if (PartitionDescriptor
->PartitionType
== 0x54)
1771 /* Return our buffer, but at sector 63 */
1772 *(PULONG
)Buffer
= 63;
1773 *MbrBuffer
= Buffer
;
1775 else if (PartitionDescriptor
->PartitionType
== 0x55)
1777 /* EZ Drive, return the buffer directly */
1778 *MbrBuffer
= Buffer
;
1782 /* Otherwise crash on debug builds */
1783 ASSERT(PartitionDescriptor
->PartitionType
== 0x55);
1791 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor
,
1792 IN ULONGLONG MaxOffset
)
1794 ULONG PartitionMaxOffset
, PartitionLength
;
1797 /* Compute partition length (according to MBR entry) */
1798 PartitionMaxOffset
= GET_STARTING_SECTOR(PartitionDescriptor
) + GET_PARTITION_LENGTH(PartitionDescriptor
);
1799 /* In case the partition length goes beyond disk size... */
1800 if (PartitionMaxOffset
> MaxOffset
)
1802 /* Resize partition to its maximum real length */
1803 PartitionLength
= (ULONG
)(PartitionMaxOffset
- GET_STARTING_SECTOR(PartitionDescriptor
));
1804 SET_PARTITION_LENGTH(PartitionDescriptor
, PartitionLength
);
1810 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
1811 IN ULONG SectorSize
,
1812 IN BOOLEAN ReturnRecognizedPartitions
,
1813 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
1816 IO_STATUS_BLOCK IoStatusBlock
;
1818 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1821 PPARTITION_INFORMATION PartitionInfo
;
1822 PUCHAR Buffer
= NULL
;
1823 ULONG BufferSize
= 2048, InputSize
;
1824 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo
= NULL
;
1825 LONG j
= -1, i
= -1, k
;
1826 DISK_GEOMETRY DiskGeometry
;
1827 LONGLONG EndSector
, MaxSector
, StartOffset
;
1828 ULONGLONG MaxOffset
;
1829 LARGE_INTEGER Offset
, VolumeOffset
;
1830 BOOLEAN IsPrimary
= TRUE
, IsEzDrive
= FALSE
, MbrFound
= FALSE
;
1831 BOOLEAN IsValid
, IsEmpty
= TRUE
;
1833 PIO_STACK_LOCATION IoStackLocation
;
1834 UCHAR PartitionType
;
1835 LARGE_INTEGER HiddenSectors64
;
1836 VolumeOffset
.QuadPart
= Offset
.QuadPart
= 0;
1839 /* Allocate the buffer */
1840 *PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1843 if (!(*PartitionBuffer
)) return STATUS_INSUFFICIENT_RESOURCES
;
1845 /* Normalize the buffer size */
1846 InputSize
= max(512, SectorSize
);
1848 /* Check for EZ Drive */
1849 HalExamineMBR(DeviceObject
, InputSize
, 0x55, &MbrBuffer
);
1852 /* EZ Drive found, bias the offset */
1854 ExFreePoolWithTag(MbrBuffer
, TAG_FILE_SYSTEM
);
1855 Offset
.QuadPart
= 512;
1858 /* Get drive geometry */
1859 Status
= HalpGetFullGeometry(DeviceObject
, &DiskGeometry
, &MaxOffset
);
1860 if (!NT_SUCCESS(Status
))
1862 ExFreePoolWithTag(*PartitionBuffer
, TAG_FILE_SYSTEM
);
1863 *PartitionBuffer
= NULL
;
1867 /* Get the end and maximum sector */
1868 EndSector
= MaxOffset
;
1869 MaxSector
= MaxOffset
<< 1;
1870 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
1871 MaxOffset
, MaxSector
);
1873 /* Allocate our buffer */
1874 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, InputSize
, TAG_FILE_SYSTEM
);
1877 /* Fail, free the input buffer */
1878 ExFreePoolWithTag(*PartitionBuffer
, TAG_FILE_SYSTEM
);
1879 *PartitionBuffer
= NULL
;
1880 return STATUS_INSUFFICIENT_RESOURCES
;
1883 /* Start partition loop */
1886 /* Assume the partition is valid */
1889 /* Initialize the event */
1890 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1892 /* Clear the buffer and build the IRP */
1893 RtlZeroMemory(Buffer
, InputSize
);
1894 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1904 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1908 /* Make sure to disable volume verification */
1909 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1910 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1912 /* Call the driver */
1913 Status
= IoCallDriver(DeviceObject
, Irp
);
1914 if (Status
== STATUS_PENDING
)
1916 /* Wait for completion */
1917 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1918 Status
= IoStatusBlock
.Status
;
1921 /* Normalize status code and check for failure */
1922 if (Status
== STATUS_NO_DATA_DETECTED
) Status
= STATUS_SUCCESS
;
1923 if (!NT_SUCCESS(Status
)) break;
1925 /* If we biased for EZ-Drive, unbias now */
1926 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
1928 /* Make sure this is a valid MBR */
1929 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1931 /* It's not, fail */
1932 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1933 "partition table %d\n", j
+ 1);
1937 /* At this point we have a valid MBR */
1940 /* Check if we weren't given an offset */
1941 if (!Offset
.QuadPart
)
1943 /* Then read the signature off the disk */
1944 (*PartitionBuffer
)->Signature
= ((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1];
1947 /* Get the partition descriptor array */
1948 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1949 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1951 /* Start looping partitions */
1953 DPRINT("FSTUB: Partition Table %d:\n", j
);
1954 for (Entry
= 1, k
= 0; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1956 /* Get the partition type */
1957 PartitionType
= PartitionDescriptor
->PartitionType
;
1959 /* Print debug messages */
1960 DPRINT("Partition Entry %d,%d: type %#x %s\n",
1964 (PartitionDescriptor
->ActiveFlag
) ? "Active" : "");
1965 DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
1966 GET_STARTING_SECTOR(PartitionDescriptor
),
1967 GET_PARTITION_LENGTH(PartitionDescriptor
));
1969 /* Check whether we're facing a protective MBR */
1970 if (PartitionType
== EFI_PMBR_OSTYPE_EFI
)
1972 /* Partition length might be bigger than disk size */
1973 FstubFixupEfiPartition(PartitionDescriptor
,
1977 /* Make sure that the partition is valid, unless it's the first */
1978 if (!(HalpIsValidPartitionEntry(PartitionDescriptor
,
1980 MaxSector
)) && (j
== 0))
1982 /* It's invalid, so fail */
1987 /* Check if it's a container */
1988 if (IsContainerPartition(PartitionType
))
1990 /* Increase the count of containers */
1993 /* More then one table is invalid */
1994 DPRINT1("FSTUB: Multiple container partitions found in "
1995 "partition table %d\n - table is invalid\n",
2002 /* Check if the partition is supposedly empty */
2005 /* But check if it actually has a start and/or length */
2006 if ((GET_STARTING_SECTOR(PartitionDescriptor
)) ||
2007 (GET_PARTITION_LENGTH(PartitionDescriptor
)))
2009 /* So then it's not really empty */
2014 /* Check if the caller wanted only recognized partitions */
2015 if (ReturnRecognizedPartitions
)
2017 /* Then check if this one is unused, or a container */
2018 if ((PartitionType
== PARTITION_ENTRY_UNUSED
) ||
2019 IsContainerPartition(PartitionType
))
2021 /* Skip it, since the caller doesn't want it */
2026 /* Increase the structure count and check if they can fit */
2027 if ((sizeof(DRIVE_LAYOUT_INFORMATION
) +
2028 (++i
* sizeof(PARTITION_INFORMATION
))) >
2031 /* Allocate a new buffer that's twice as big */
2032 DriveLayoutInfo
= ExAllocatePoolWithTag(NonPagedPool
,
2035 if (!DriveLayoutInfo
)
2037 /* Out of memory, unto this extra structure */
2039 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2043 /* Copy the contents of the old buffer */
2044 RtlMoveMemory(DriveLayoutInfo
,
2048 /* Free the old buffer and set this one as the new one */
2049 ExFreePoolWithTag(*PartitionBuffer
, TAG_FILE_SYSTEM
);
2050 *PartitionBuffer
= DriveLayoutInfo
;
2052 /* Double the size */
2056 /* Now get the current structure being filled and initialize it */
2057 PartitionInfo
= &(*PartitionBuffer
)->PartitionEntry
[i
];
2058 PartitionInfo
->PartitionType
= PartitionType
;
2059 PartitionInfo
->RewritePartition
= FALSE
;
2061 /* Check if we're dealing with a partition that's in use */
2062 if (PartitionType
!= PARTITION_ENTRY_UNUSED
)
2064 /* Check if it's bootable */
2065 PartitionInfo
->BootIndicator
= PartitionDescriptor
->
2069 /* Check if its' a container */
2070 if (IsContainerPartition(PartitionType
))
2072 /* Then don't recognize it and use the volume offset */
2073 PartitionInfo
->RecognizedPartition
= FALSE
;
2074 StartOffset
= VolumeOffset
.QuadPart
;
2078 /* Then recognize it and use the partition offset */
2079 PartitionInfo
->RecognizedPartition
= TRUE
;
2080 StartOffset
= Offset
.QuadPart
;
2083 /* Get the starting offset */
2084 PartitionInfo
->StartingOffset
.QuadPart
=
2086 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor
),
2089 /* Calculate the number of hidden sectors */
2090 HiddenSectors64
.QuadPart
= (PartitionInfo
->
2091 StartingOffset
.QuadPart
-
2094 PartitionInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
2096 /* Get the partition length */
2097 PartitionInfo
->PartitionLength
.QuadPart
=
2098 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor
),
2101 /* Get the partition number */
2102 PartitionInfo
->PartitionNumber
= (!IsContainerPartition(PartitionType
)) ? i
+ 1 : 0;
2106 /* Otherwise, clear all the relevant fields */
2107 PartitionInfo
->BootIndicator
= FALSE
;
2108 PartitionInfo
->RecognizedPartition
= FALSE
;
2109 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2110 PartitionInfo
->PartitionLength
.QuadPart
= 0;
2111 PartitionInfo
->HiddenSectors
= 0;
2113 PartitionInfo
->PartitionNumber
= 0;
2117 /* Finish debug log, and check for failure */
2119 if (!NT_SUCCESS(Status
)) break;
2121 /* Also check if we hit an invalid entry here */
2124 /* We did, so break out of the loop minus one entry */
2129 /* Reset the offset */
2130 Offset
.QuadPart
= 0;
2132 /* Go back to the descriptor array and loop it */
2133 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
2134 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
2135 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
2137 /* Check if this is a container partition, since we skipped them */
2138 if (IsContainerPartition(PartitionDescriptor
->PartitionType
))
2140 /* Get its offset */
2141 Offset
.QuadPart
= VolumeOffset
.QuadPart
+
2143 GET_STARTING_SECTOR(PartitionDescriptor
),
2146 /* If this is a primary partition, this is the volume offset */
2147 if (IsPrimary
) VolumeOffset
= Offset
;
2149 /* Also update the maximum sector */
2150 MaxSector
= GET_PARTITION_LENGTH(PartitionDescriptor
);
2151 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector
);
2156 /* Loop the next partitions, which are not primary anymore */
2158 } while (Offset
.HighPart
| Offset
.LowPart
);
2160 /* Check if this is a removable device that's probably a super-floppy */
2161 if ((DiskGeometry
.MediaType
== RemovableMedia
) &&
2162 (j
== 0) && (MbrFound
) && (IsEmpty
))
2164 PBOOT_SECTOR_INFO BootSectorInfo
= (PBOOT_SECTOR_INFO
)Buffer
;
2166 /* Read the jump bytes to detect super-floppy */
2167 if ((BootSectorInfo
->JumpByte
[0] == 0xeb) ||
2168 (BootSectorInfo
->JumpByte
[0] == 0xe9))
2170 /* Super floppes don't have typical MBRs, so skip them */
2171 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
2172 "table - disk is a super floppy and has no valid MBR\n",
2173 BootSectorInfo
->JumpByte
);
2178 /* Check if we're still at partition -1 */
2181 /* The likely cause is the super floppy detection above */
2182 if ((MbrFound
) || (DiskGeometry
.MediaType
== RemovableMedia
))
2184 /* Print out debugging information */
2185 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
2188 DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x "
2190 EndSector
, EndSector
* DiskGeometry
.BytesPerSector
);
2192 /* We should at least have some sectors */
2195 /* Get the entry we'll use */
2196 PartitionInfo
= &(*PartitionBuffer
)->PartitionEntry
[0];
2198 /* Fill it out with data for a super-floppy */
2199 PartitionInfo
->RewritePartition
= FALSE
;
2200 PartitionInfo
->RecognizedPartition
= TRUE
;
2201 PartitionInfo
->PartitionType
= PARTITION_FAT_16
;
2202 PartitionInfo
->BootIndicator
= FALSE
;
2203 PartitionInfo
->HiddenSectors
= 0;
2204 PartitionInfo
->StartingOffset
.QuadPart
= 0;
2205 PartitionInfo
->PartitionLength
.QuadPart
= (EndSector
*
2209 /* FIXME: REACTOS HACK */
2210 PartitionInfo
->PartitionNumber
= 0;
2212 /* Set the signature and set the count back to 0 */
2213 (*PartitionBuffer
)->Signature
= 1;
2219 /* Otherwise, this isn't a super floppy, so set an invalid count */
2224 /* Set the partition count */
2225 (*PartitionBuffer
)->PartitionCount
= ++i
;
2227 /* If we have no count, delete the signature */
2228 if (!i
) (*PartitionBuffer
)->Signature
= 0;
2230 /* Free the buffer and check for success */
2231 if (Buffer
) ExFreePoolWithTag(Buffer
, TAG_FILE_SYSTEM
);
2232 if (!NT_SUCCESS(Status
))
2234 ExFreePoolWithTag(*PartitionBuffer
, TAG_FILE_SYSTEM
);
2235 *PartitionBuffer
= NULL
;
2244 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
2245 IN ULONG SectorSize
,
2246 IN ULONG PartitionNumber
,
2247 IN ULONG PartitionType
)
2251 IO_STATUS_BLOCK IoStatusBlock
;
2253 LARGE_INTEGER Offset
, VolumeOffset
;
2254 PUCHAR Buffer
= NULL
;
2258 PPARTITION_DESCRIPTOR PartitionDescriptor
;
2259 BOOLEAN IsPrimary
= TRUE
, IsEzDrive
= FALSE
;
2261 PIO_STACK_LOCATION IoStackLocation
;
2262 VolumeOffset
.QuadPart
= Offset
.QuadPart
= 0;
2265 /* Normalize the buffer size */
2266 BufferSize
= max(512, SectorSize
);
2268 /* Check for EZ Drive */
2269 HalExamineMBR(DeviceObject
, BufferSize
, 0x55, &MbrBuffer
);
2272 /* EZ Drive found, bias the offset */
2274 ExFreePoolWithTag(MbrBuffer
, TAG_FILE_SYSTEM
);
2275 Offset
.QuadPart
= 512;
2278 /* Allocate our partition buffer */
2279 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
2280 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2282 /* Initialize the event we'll use and loop partitions */
2283 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2286 /* Reset the event since we reuse it */
2287 KeClearEvent(&Event
);
2289 /* Build the read IRP */
2290 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2300 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2304 /* Make sure to disable volume verification */
2305 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2306 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2308 /* Call the driver */
2309 Status
= IoCallDriver(DeviceObject
, Irp
);
2310 if (Status
== STATUS_PENDING
)
2312 /* Wait for completion */
2313 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
2314 Status
= IoStatusBlock
.Status
;
2317 /* Check for failure */
2318 if (!NT_SUCCESS(Status
)) break;
2320 /* If we biased for EZ-Drive, unbias now */
2321 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2323 /* Make sure this is a valid MBR */
2324 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
2326 /* It's not, fail */
2327 Status
= STATUS_BAD_MASTER_BOOT_RECORD
;
2331 /* Get the partition descriptors and loop them */
2332 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
2333 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
2334 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
2336 /* Check if it's unused or a container partition */
2337 if ((PartitionDescriptor
->PartitionType
==
2338 PARTITION_ENTRY_UNUSED
) ||
2339 (IsContainerPartition(PartitionDescriptor
->PartitionType
)))
2341 /* Go to the next one */
2345 /* It's a valid partition, so increase the partition count */
2346 if (++i
== PartitionNumber
)
2348 /* We found a match, set the type */
2349 PartitionDescriptor
->PartitionType
= (UCHAR
)PartitionType
;
2351 /* Reset the reusable event */
2352 KeClearEvent(&Event
);
2354 /* Build the write IRP */
2355 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
2365 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2369 /* Disable volume verification */
2370 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2371 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2373 /* Call the driver */
2374 Status
= IoCallDriver(DeviceObject
, Irp
);
2375 if (Status
== STATUS_PENDING
)
2377 /* Wait for completion */
2378 KeWaitForSingleObject(&Event
,
2383 Status
= IoStatusBlock
.Status
;
2386 /* We're done, break out of the loop */
2391 /* If we looped all the partitions, break out */
2392 if (Entry
<= NUM_PARTITION_TABLE_ENTRIES
) break;
2394 /* Nothing found yet, get the partition array again */
2395 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
2396 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
2397 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
2399 /* Check if this was a container partition (we skipped these) */
2400 if (IsContainerPartition(PartitionDescriptor
->PartitionType
))
2402 /* Update the partition offset */
2403 Offset
.QuadPart
= VolumeOffset
.QuadPart
+
2404 GET_STARTING_SECTOR(PartitionDescriptor
) *
2407 /* If this was the primary partition, update the volume too */
2408 if (IsPrimary
) VolumeOffset
= Offset
;
2413 /* Check if we already searched all the partitions */
2414 if (Entry
> NUM_PARTITION_TABLE_ENTRIES
)
2416 /* Then we failed to find a good MBR */
2417 Status
= STATUS_BAD_MASTER_BOOT_RECORD
;
2421 /* Loop the next partitions, which are not primary anymore */
2423 } while (i
< PartitionNumber
);
2425 /* Everything done, cleanup */
2426 if (Buffer
) ExFreePoolWithTag(Buffer
, TAG_FILE_SYSTEM
);
2432 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
2433 IN ULONG SectorSize
,
2434 IN ULONG SectorsPerTrack
,
2435 IN ULONG NumberOfHeads
,
2436 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
2439 IO_STATUS_BLOCK IoStatusBlock
;
2441 NTSTATUS Status
= STATUS_SUCCESS
;
2445 PPARTITION_TABLE PartitionTable
;
2446 LARGE_INTEGER Offset
, NextOffset
, ExtendedOffset
, SectorOffset
;
2447 LARGE_INTEGER StartOffset
, PartitionLength
;
2450 BOOLEAN IsEzDrive
= FALSE
, IsSuperFloppy
= FALSE
, DoRewrite
= FALSE
, IsMbr
;
2451 ULONG ConventionalCylinders
;
2453 PDISK_LAYOUT DiskLayout
= (PDISK_LAYOUT
)PartitionBuffer
;
2455 UCHAR PartitionType
;
2456 PIO_STACK_LOCATION IoStackLocation
;
2457 PPARTITION_INFORMATION PartitionInfo
= PartitionBuffer
->PartitionEntry
;
2458 PPARTITION_INFORMATION TableEntry
;
2459 ExtendedOffset
.QuadPart
= NextOffset
.QuadPart
= Offset
.QuadPart
= 0;
2462 /* Normalize the buffer size */
2463 BufferSize
= max(512, SectorSize
);
2465 /* Get the partial drive geometry */
2466 xHalGetPartialGeometry(DeviceObject
, &ConventionalCylinders
, &DiskSize
);
2468 /* Check for EZ Drive */
2469 HalExamineMBR(DeviceObject
, BufferSize
, 0x55, &MbrBuffer
);
2472 /* EZ Drive found, bias the offset */
2474 ExFreePoolWithTag(MbrBuffer
, TAG_FILE_SYSTEM
);
2475 Offset
.QuadPart
= 512;
2478 /* Get the number of bits to shift to multiply by the sector size */
2479 for (k
= 0; k
< 32; k
++) if ((SectorSize
>> k
) == 1) break;
2481 /* Check if there's only one partition */
2482 if (PartitionBuffer
->PartitionCount
== 1)
2484 /* Check if it has no starting offset or hidden sectors */
2485 if (!(PartitionInfo
->StartingOffset
.QuadPart
) &&
2486 !(PartitionInfo
->HiddenSectors
))
2488 /* Then it's a super floppy */
2489 IsSuperFloppy
= TRUE
;
2491 /* Which also means it must be non-bootable FAT-16 */
2492 if ((PartitionInfo
->PartitionNumber
) ||
2493 (PartitionInfo
->PartitionType
!= PARTITION_FAT_16
) ||
2494 (PartitionInfo
->BootIndicator
))
2496 /* It's not, so we fail */
2497 return STATUS_INVALID_PARAMETER
;
2500 /* Check if it needs a rewrite, and disable EZ drive for sure */
2501 if (PartitionInfo
->RewritePartition
) DoRewrite
= TRUE
;
2506 /* Count the number of partition tables */
2507 DiskLayout
->TableCount
= (PartitionBuffer
->PartitionCount
+ 4 - 1) / 4;
2509 /* Allocate our partition buffer */
2510 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
2511 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2513 /* Loop the entries */
2514 Entry
= (PPTE
)&Buffer
[PARTITION_TABLE_OFFSET
];
2515 for (i
= 0; i
< DiskLayout
->TableCount
; i
++)
2517 /* Set if this is the MBR partition */
2520 /* Initialize th event */
2521 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2523 /* Build the read IRP */
2524 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2534 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2538 /* Make sure to disable volume verification */
2539 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2540 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2542 /* Call the driver */
2543 Status
= IoCallDriver(DeviceObject
, Irp
);
2544 if (Status
== STATUS_PENDING
)
2546 /* Wait for completion */
2547 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
2548 Status
= IoStatusBlock
.Status
;
2551 /* Check for failure */
2552 if (!NT_SUCCESS(Status
)) break;
2554 /* If we biased for EZ-Drive, unbias now */
2555 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2557 /* Check if this is a normal disk */
2560 /* Set the boot record signature */
2561 Buffer
[BOOT_SIGNATURE_OFFSET
] = BOOT_RECORD_SIGNATURE
;
2563 /* By default, don't require a rewrite */
2566 /* Check if we don't have an offset */
2567 if (!Offset
.QuadPart
)
2569 /* Check if the signature doesn't match */
2570 if (((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1] !=
2571 PartitionBuffer
->Signature
)
2573 /* Then write the signature and now we need a rewrite */
2574 ((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1] =
2575 PartitionBuffer
->Signature
;
2580 /* Loop the partition table entries */
2581 PartitionTable
= &DiskLayout
->PartitionTable
[i
];
2582 for (j
= 0; j
< 4; j
++)
2584 /* Get the current entry and type */
2585 TableEntry
= &PartitionTable
->PartitionEntry
[j
];
2586 PartitionType
= TableEntry
->PartitionType
;
2588 /* Check if the entry needs a rewrite */
2589 if (TableEntry
->RewritePartition
)
2591 /* Then we need one too */
2594 /* Save the type and if it's a bootable partition */
2595 Entry
[j
].PartitionType
= TableEntry
->PartitionType
;
2596 Entry
[j
].ActiveFlag
= TableEntry
->BootIndicator
? 0x80 : 0;
2598 /* Make sure it's used */
2599 if (PartitionType
!= PARTITION_ENTRY_UNUSED
)
2601 /* Make sure it's not a container (unless primary) */
2602 if ((IsMbr
) || !(IsContainerPartition(PartitionType
)))
2604 /* Use the partition offset */
2605 StartOffset
.QuadPart
= Offset
.QuadPart
;
2609 /* Use the extended logical partition offset */
2610 StartOffset
.QuadPart
= ExtendedOffset
.QuadPart
;
2613 /* Set the sector offset */
2614 SectorOffset
.QuadPart
= TableEntry
->
2615 StartingOffset
.QuadPart
-
2616 StartOffset
.QuadPart
;
2618 /* Now calculate the starting sector */
2619 StartOffset
.QuadPart
= SectorOffset
.QuadPart
>> k
;
2620 Entry
[j
].StartingSector
= StartOffset
.LowPart
;
2622 /* As well as the length */
2623 PartitionLength
.QuadPart
= TableEntry
->PartitionLength
.
2625 Entry
[j
].PartitionLength
= PartitionLength
.LowPart
;
2627 /* Calculate the CHS values */
2628 HalpCalculateChsValues(&TableEntry
->StartingOffset
,
2629 &TableEntry
->PartitionLength
,
2633 ConventionalCylinders
,
2634 (PPARTITION_DESCRIPTOR
)
2639 /* Otherwise set up an empty entry */
2640 Entry
[j
].StartingSector
= 0;
2641 Entry
[j
].PartitionLength
= 0;
2642 Entry
[j
].StartingTrack
= 0;
2643 Entry
[j
].EndingTrack
= 0;
2644 Entry
[j
].StartingCylinder
= 0;
2645 Entry
[j
].EndingCylinder
= 0;
2649 /* Check if this is a container partition */
2650 if (IsContainerPartition(PartitionType
))
2652 /* Then update the offset to use */
2653 NextOffset
= TableEntry
->StartingOffset
;
2658 /* Check if we need to write back the buffer */
2661 /* We don't need to do this again */
2664 /* Initialize the event */
2665 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2667 /* If we unbiased for EZ-Drive, rebias now */
2668 if ((IsEzDrive
) && !(Offset
.QuadPart
)) Offset
.QuadPart
= 512;
2670 /* Build the write IRP */
2671 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
2681 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2685 /* Make sure to disable volume verification */
2686 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2687 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2689 /* Call the driver */
2690 Status
= IoCallDriver(DeviceObject
, Irp
);
2691 if (Status
== STATUS_PENDING
)
2693 /* Wait for completion */
2694 KeWaitForSingleObject(&Event
,
2699 Status
= IoStatusBlock
.Status
;
2702 /* Check for failure */
2703 if (!NT_SUCCESS(Status
)) break;
2705 /* If we biased for EZ-Drive, unbias now */
2706 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2709 /* Update the partition offset and set the extended offset if needed */
2710 Offset
= NextOffset
;
2711 if (IsMbr
) ExtendedOffset
= NextOffset
;
2714 /* If we had a buffer, free it, then return status */
2715 if (Buffer
) ExFreePoolWithTag(Buffer
, TAG_FILE_SYSTEM
);
2719 /* PUBLIC FUNCTIONS **********************************************************/
2726 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject
,
2727 IN ULONG SectorSize
,
2728 IN ULONG MbrTypeIdentifier
,
2729 OUT PVOID
*MbrBuffer
)
2731 HALDISPATCH
->HalExamineMBR(DeviceObject
,
2742 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
2743 IN ULONG SectorSize
,
2744 IN BOOLEAN ReturnRecognizedPartitions
,
2745 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
2747 return HALDISPATCH
->HalIoReadPartitionTable(DeviceObject
,
2749 ReturnRecognizedPartitions
,
2758 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
2759 IN ULONG SectorSize
,
2760 IN ULONG PartitionNumber
,
2761 IN ULONG PartitionType
)
2763 return HALDISPATCH
->HalIoSetPartitionInformation(DeviceObject
,
2774 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
2775 IN ULONG SectorSize
,
2776 IN ULONG SectorsPerTrack
,
2777 IN ULONG NumberOfHeads
,
2778 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
2780 return HALDISPATCH
->HalIoWritePartitionTable(DeviceObject
,
2792 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
2793 IN PSTRING NtDeviceName
,
2794 OUT PUCHAR NtSystemPath
,
2795 OUT PSTRING NtSystemPathString
)
2797 HALDISPATCH
->HalIoAssignDriveLetters(LoaderBlock
,
2800 NtSystemPathString
);