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)
7 * Eric Kohl (ekohl@rz-online.de)
8 * Casper S. Hornstrup (chorns@users.sourceforge.net)
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
16 #include <internal/hal.h>
18 /* DEPRECATED FUNCTIONS ******************************************************/
21 const WCHAR DiskMountString
[] = L
"\\DosDevices\\%C:";
23 #define AUTO_DRIVE ((ULONG)-1)
25 #define PARTITION_MAGIC 0xaa55
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
45 HalpAssignDrive(IN PUNICODE_STRING PartitionName
,
49 IN LARGE_INTEGER StartingOffset
,
52 WCHAR DriveNameBuffer
[16];
53 UNICODE_STRING DriveName
;
56 REG_DISK_MOUNT_INFO DiskMountInfo
;
58 DPRINT("HalpAssignDrive()\n");
60 if ((DriveNumber
!= AUTO_DRIVE
) && (DriveNumber
< 26))
62 /* Force assignment */
63 if ((ObSystemDeviceMap
->DriveMap
& (1 << DriveNumber
)) != 0)
65 DbgPrint("Drive letter already used!\n");
71 /* Automatic assignment */
72 DriveNumber
= AUTO_DRIVE
;
74 for (i
= 2; i
< 26; i
++)
76 if ((ObSystemDeviceMap
->DriveMap
& (1 << i
)) == 0)
83 if (DriveNumber
== AUTO_DRIVE
)
85 DbgPrint("No drive letter available!\n");
90 DPRINT("DriveNumber %d\n", DriveNumber
);
92 /* Update the System Device Map */
93 ObSystemDeviceMap
->DriveMap
|= (1 << DriveNumber
);
94 ObSystemDeviceMap
->DriveType
[DriveNumber
] = DriveType
;
96 /* Build drive name */
97 swprintf(DriveNameBuffer
,
100 RtlInitUnicodeString(&DriveName
,
103 DPRINT(" %wZ ==> %wZ\n",
107 /* Create symbolic link */
108 Status
= IoCreateSymbolicLink(&DriveName
,
112 DriveType
== DOSDEVICE_DRIVE_FIXED
&&
115 DiskMountInfo
.Signature
= Signature
;
116 DiskMountInfo
.StartingOffset
= StartingOffset
;
117 swprintf(DriveNameBuffer
, DiskMountString
, L
'A' + DriveNumber
);
118 RtlInitUnicodeString(&DriveName
, DriveNameBuffer
);
120 Status
= ZwSetValueKey(hKey
,
125 sizeof(DiskMountInfo
));
126 if (!NT_SUCCESS(Status
))
128 DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName
, Status
);
135 xHalpGetRDiskCount(VOID
)
138 UNICODE_STRING ArcName
;
139 PWCHAR ArcNameBuffer
;
140 OBJECT_ATTRIBUTES ObjectAttributes
;
141 HANDLE DirectoryHandle
;
142 POBJECT_DIRECTORY_INFORMATION DirectoryInfo
;
147 BOOLEAN First
= TRUE
;
150 DirectoryInfo
= ExAllocatePool(PagedPool
, 2 * PAGE_SIZE
);
151 if (DirectoryInfo
== NULL
)
156 RtlInitUnicodeString(&ArcName
, L
"\\ArcName");
157 InitializeObjectAttributes(&ObjectAttributes
,
163 Status
= ZwOpenDirectoryObject (&DirectoryHandle
,
164 SYMBOLIC_LINK_ALL_ACCESS
,
166 if (!NT_SUCCESS(Status
))
168 DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName
, Status
);
169 ExFreePool(DirectoryInfo
);
175 while (NT_SUCCESS(Status
))
177 Status
= NtQueryDirectoryObject (DirectoryHandle
,
185 if (NT_SUCCESS(Status
))
188 while (DirectoryInfo
[Count
].Name
.Buffer
)
190 DPRINT("Count %x\n", Count
);
191 DirectoryInfo
[Count
].Name
.Buffer
[DirectoryInfo
[Count
].Name
.Length
/ sizeof(WCHAR
)] = 0;
192 ArcNameBuffer
= DirectoryInfo
[Count
].Name
.Buffer
;
193 if (DirectoryInfo
[Count
].Name
.Length
>= sizeof(L
"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR
) &&
194 !_wcsnicmp(ArcNameBuffer
, L
"multi(0)disk(0)rdisk(", (sizeof(L
"multi(0)disk(0)rdisk(") - sizeof(WCHAR
)) / sizeof(WCHAR
)))
196 DPRINT("%S\n", ArcNameBuffer
);
197 ArcNameBuffer
+= (sizeof(L
"multi(0)disk(0)rdisk(") - sizeof(WCHAR
)) / sizeof(WCHAR
);
199 while (iswdigit(*ArcNameBuffer
))
201 CurrentRDisk
= CurrentRDisk
* 10 + *ArcNameBuffer
- L
'0';
204 if (!_wcsicmp(ArcNameBuffer
, L
")") &&
205 CurrentRDisk
>= RDiskCount
)
207 RDiskCount
= CurrentRDisk
+ 1;
214 ExFreePool(DirectoryInfo
);
219 xHalpGetDiskNumberFromRDisk(ULONG RDisk
, PULONG DiskNumber
)
221 WCHAR NameBuffer
[80];
222 UNICODE_STRING ArcName
;
223 UNICODE_STRING LinkName
;
224 OBJECT_ATTRIBUTES ObjectAttributes
;
229 L
"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
232 RtlInitUnicodeString(&ArcName
, NameBuffer
);
233 InitializeObjectAttributes(&ObjectAttributes
,
238 Status
= ZwOpenSymbolicLinkObject(&LinkHandle
,
239 SYMBOLIC_LINK_ALL_ACCESS
,
241 if (!NT_SUCCESS(Status
))
243 DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName
, Status
);
247 LinkName
.Buffer
= NameBuffer
;
249 LinkName
.MaximumLength
= sizeof(NameBuffer
);
250 Status
= ZwQuerySymbolicLinkObject(LinkHandle
,
254 if (!NT_SUCCESS(Status
))
256 DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status
);
259 if (LinkName
.Length
< sizeof(L
"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR
) ||
260 LinkName
.Length
>= sizeof(NameBuffer
))
262 return STATUS_UNSUCCESSFUL
;
265 NameBuffer
[LinkName
.Length
/ sizeof(WCHAR
)] = 0;
266 if (_wcsnicmp(NameBuffer
, L
"\\Device\\Harddisk", (sizeof(L
"\\Device\\Harddisk") - sizeof(WCHAR
)) / sizeof(WCHAR
)))
268 return STATUS_UNSUCCESSFUL
;
270 LinkName
.Buffer
+= (sizeof(L
"\\Device\\Harddisk") - sizeof(WCHAR
)) / sizeof(WCHAR
);
272 if (!iswdigit(*LinkName
.Buffer
))
274 return STATUS_UNSUCCESSFUL
;
277 while (iswdigit(*LinkName
.Buffer
))
279 *DiskNumber
= *DiskNumber
* 10 + *LinkName
.Buffer
- L
'0';
282 if (_wcsicmp(LinkName
.Buffer
, L
"\\Partition0"))
284 return STATUS_UNSUCCESSFUL
;
286 return STATUS_SUCCESS
;
291 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName
,
292 OUT PDRIVE_LAYOUT_INFORMATION
*LayoutInfo
)
294 IO_STATUS_BLOCK StatusBlock
;
295 DISK_GEOMETRY DiskGeometry
;
296 PDEVICE_OBJECT DeviceObject
= NULL
;
297 PFILE_OBJECT FileObject
;
302 DPRINT("xHalpQueryDriveLayout %wZ %p\n",
306 /* Get the drives sector size */
307 Status
= IoGetDeviceObjectPointer(DeviceName
,
308 FILE_READ_ATTRIBUTES
,
311 if (!NT_SUCCESS(Status
))
313 DPRINT("Status %x\n", Status
);
317 KeInitializeEvent(&Event
,
321 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
326 sizeof(DISK_GEOMETRY
),
332 ObDereferenceObject(FileObject
);
333 return(STATUS_INSUFFICIENT_RESOURCES
);
336 Status
= IoCallDriver(DeviceObject
,
338 if (Status
== STATUS_PENDING
)
340 KeWaitForSingleObject(&Event
,
345 Status
= StatusBlock
.Status
;
347 if (!NT_SUCCESS(Status
))
349 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
351 DiskGeometry
.BytesPerSector
= 512;
355 ObDereferenceObject(FileObject
);
360 DPRINT("DiskGeometry.BytesPerSector: %d\n",
361 DiskGeometry
.BytesPerSector
);
363 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
365 PDRIVE_LAYOUT_INFORMATION Buffer
;
367 /* Allocate a partition list for a single entry. */
368 Buffer
= ExAllocatePool(NonPagedPool
,
369 sizeof(DRIVE_LAYOUT_INFORMATION
));
372 RtlZeroMemory(Buffer
,
373 sizeof(DRIVE_LAYOUT_INFORMATION
));
374 Buffer
->PartitionCount
= 1;
375 *LayoutInfo
= Buffer
;
377 Status
= STATUS_SUCCESS
;
381 Status
= STATUS_UNSUCCESSFUL
;
386 /* Read the partition table */
387 Status
= IoReadPartitionTable(DeviceObject
,
388 DiskGeometry
.BytesPerSector
,
393 ObDereferenceObject(FileObject
);
400 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
401 IN PSTRING NtDeviceName
,
402 OUT PUCHAR NtSystemPath
,
403 OUT PSTRING NtSystemPathString
)
405 PDRIVE_LAYOUT_INFORMATION
*LayoutArray
;
406 PCONFIGURATION_INFORMATION ConfigInfo
;
407 OBJECT_ATTRIBUTES ObjectAttributes
;
408 IO_STATUS_BLOCK StatusBlock
;
409 UNICODE_STRING UnicodeString1
;
410 UNICODE_STRING UnicodeString2
;
420 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation
;
421 PREG_DISK_MOUNT_INFO DiskMountInfo
;
424 DPRINT("xHalIoAssignDriveLetters()\n");
426 ConfigInfo
= IoGetConfigurationInformation();
428 RDiskCount
= xHalpGetRDiskCount();
430 DPRINT("RDiskCount %d\n", RDiskCount
);
432 Buffer1
= (PWSTR
)ExAllocatePool(PagedPool
,
434 Buffer2
= (PWSTR
)ExAllocatePool(PagedPool
,
437 PartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)ExAllocatePool(PagedPool
,
438 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(REG_DISK_MOUNT_INFO
));
440 DiskMountInfo
= (PREG_DISK_MOUNT_INFO
) PartialInformation
->Data
;
442 /* Open or Create the 'MountedDevices' key */
443 RtlInitUnicodeString(&UnicodeString1
, L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
444 InitializeObjectAttributes(&ObjectAttributes
,
446 OBJ_CASE_INSENSITIVE
,
449 Status
= ZwOpenKey(&hKey
,
452 if (!NT_SUCCESS(Status
))
454 Status
= ZwCreateKey(&hKey
,
459 REG_OPTION_NON_VOLATILE
,
462 if (!NT_SUCCESS(Status
))
465 DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1
, Status
);
468 /* Create PhysicalDrive links */
469 DPRINT("Physical disk drives: %d\n", ConfigInfo
->DiskCount
);
470 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
473 L
"\\Device\\Harddisk%d\\Partition0",
475 RtlInitUnicodeString(&UnicodeString1
,
478 InitializeObjectAttributes(&ObjectAttributes
,
484 Status
= ZwOpenFile(&FileHandle
,
485 FILE_READ_DATA
| SYNCHRONIZE
,
489 FILE_SYNCHRONOUS_IO_NONALERT
);
490 if (NT_SUCCESS(Status
))
495 L
"\\??\\PhysicalDrive%d",
497 RtlInitUnicodeString(&UnicodeString2
,
500 DPRINT("Creating link: %S ==> %S\n",
504 IoCreateSymbolicLink(&UnicodeString2
,
509 /* Initialize layout array */
510 LayoutArray
= ExAllocatePool(NonPagedPool
,
511 ConfigInfo
->DiskCount
* sizeof(PDRIVE_LAYOUT_INFORMATION
));
512 RtlZeroMemory(LayoutArray
,
513 ConfigInfo
->DiskCount
* sizeof(PDRIVE_LAYOUT_INFORMATION
));
514 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
517 L
"\\Device\\Harddisk%d\\Partition0",
519 RtlInitUnicodeString(&UnicodeString1
,
522 Status
= xHalQueryDriveLayout(&UnicodeString1
,
524 if (!NT_SUCCESS(Status
))
526 DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
528 LayoutArray
[i
] = NULL
;
531 /* We don't use the RewritePartition value while mounting the disks.
532 * We use this value for marking pre-assigned (registry) partitions.
534 for (j
= 0; j
< LayoutArray
[i
]->PartitionCount
; j
++)
536 LayoutArray
[i
]->PartitionEntry
[j
].RewritePartition
= FALSE
;
541 /* Dump layout array */
542 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
544 DPRINT("Harddisk %d:\n",
547 if (LayoutArray
[i
] == NULL
)
550 DPRINT("Logical partitions: %d\n",
551 LayoutArray
[i
]->PartitionCount
);
553 for (j
= 0; j
< LayoutArray
[i
]->PartitionCount
; j
++)
555 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
557 LayoutArray
[i
]->PartitionEntry
[j
].PartitionNumber
,
558 LayoutArray
[i
]->PartitionEntry
[j
].BootIndicator
,
559 LayoutArray
[i
]->PartitionEntry
[j
].PartitionType
,
560 LayoutArray
[i
]->PartitionEntry
[j
].StartingOffset
.QuadPart
,
561 LayoutArray
[i
]->PartitionEntry
[j
].PartitionLength
.QuadPart
);
566 /* Assign pre-assigned (registry) partitions */
569 for (k
= 2; k
< 26; k
++)
571 swprintf(Buffer1
, DiskMountString
, L
'A' + k
);
572 RtlInitUnicodeString(&UnicodeString1
, Buffer1
);
573 Status
= ZwQueryValueKey(hKey
,
575 KeyValuePartialInformation
,
577 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(REG_DISK_MOUNT_INFO
),
579 if (NT_SUCCESS(Status
) &&
580 PartialInformation
->Type
== REG_BINARY
&&
581 PartialInformation
->DataLength
== sizeof(REG_DISK_MOUNT_INFO
))
583 DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1
, DiskMountInfo
->Signature
,
584 DiskMountInfo
->StartingOffset
.u
.HighPart
, DiskMountInfo
->StartingOffset
.u
.LowPart
);
586 BOOLEAN Found
= FALSE
;
587 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
589 DPRINT("%x\n", LayoutArray
[i
]->Signature
);
590 if (LayoutArray
[i
] &&
591 LayoutArray
[i
]->Signature
&&
592 LayoutArray
[i
]->Signature
== DiskMountInfo
->Signature
)
594 for (j
= 0; j
< LayoutArray
[i
]->PartitionCount
; j
++)
596 if (LayoutArray
[i
]->PartitionEntry
[j
].StartingOffset
.QuadPart
== DiskMountInfo
->StartingOffset
.QuadPart
)
598 if (IsRecognizedPartition(LayoutArray
[i
]->PartitionEntry
[j
].PartitionType
) &&
599 LayoutArray
[i
]->PartitionEntry
[j
].RewritePartition
== FALSE
)
602 L
"\\Device\\Harddisk%d\\Partition%d",
604 LayoutArray
[i
]->PartitionEntry
[j
].PartitionNumber
);
605 RtlInitUnicodeString(&UnicodeString2
,
609 DPRINT(" %wZ\n", &UnicodeString2
);
610 Found
= HalpAssignDrive(&UnicodeString2
,
612 DOSDEVICE_DRIVE_FIXED
,
613 DiskMountInfo
->Signature
,
614 DiskMountInfo
->StartingOffset
,
616 /* Mark the partition as assigned */
617 LayoutArray
[i
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
626 /* We didn't find a partition for this entry, remove them. */
627 Status
= ZwDeleteValueKey(hKey
, &UnicodeString1
);
634 /* Assign bootable partition on first harddisk */
635 DPRINT("Assigning bootable primary partition on first harddisk:\n");
638 Status
= xHalpGetDiskNumberFromRDisk(0, &DiskNumber
);
639 if (NT_SUCCESS(Status
) &&
640 DiskNumber
< ConfigInfo
->DiskCount
&&
641 LayoutArray
[DiskNumber
])
643 /* Search for bootable partition */
644 for (j
= 0; j
< NUM_PARTITION_TABLE_ENTRIES
&& j
< LayoutArray
[DiskNumber
]->PartitionCount
; j
++)
646 if ((LayoutArray
[DiskNumber
]->PartitionEntry
[j
].BootIndicator
== TRUE
) &&
647 IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
))
649 if (LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
)
652 L
"\\Device\\Harddisk%lu\\Partition%d",
654 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
655 RtlInitUnicodeString(&UnicodeString2
,
659 DPRINT(" %wZ\n", &UnicodeString2
);
660 HalpAssignDrive(&UnicodeString2
,
662 DOSDEVICE_DRIVE_FIXED
,
663 LayoutArray
[DiskNumber
]->Signature
,
664 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
666 /* Mark the partition as assigned */
667 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
675 /* Assign remaining primary partitions */
676 DPRINT("Assigning remaining primary partitions:\n");
677 for (RDisk
= 0; RDisk
< RDiskCount
; RDisk
++)
679 Status
= xHalpGetDiskNumberFromRDisk(RDisk
, &DiskNumber
);
680 if (NT_SUCCESS(Status
) &&
681 DiskNumber
< ConfigInfo
->DiskCount
&&
682 LayoutArray
[DiskNumber
])
684 /* Search for primary partitions */
685 for (j
= 0; (j
< NUM_PARTITION_TABLE_ENTRIES
) && (j
< LayoutArray
[DiskNumber
]->PartitionCount
); j
++)
687 if (LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
688 IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
))
691 L
"\\Device\\Harddisk%d\\Partition%d",
693 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
694 RtlInitUnicodeString(&UnicodeString2
,
700 HalpAssignDrive(&UnicodeString2
,
702 DOSDEVICE_DRIVE_FIXED
,
703 LayoutArray
[DiskNumber
]->Signature
,
704 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
706 /* Mark the partition as assigned */
707 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
713 /* Assign extended (logical) partitions */
714 DPRINT("Assigning extended (logical) partitions:\n");
715 for (RDisk
= 0; RDisk
< RDiskCount
; RDisk
++)
717 Status
= xHalpGetDiskNumberFromRDisk(RDisk
, &DiskNumber
);
718 if (NT_SUCCESS(Status
) &&
719 DiskNumber
< ConfigInfo
->DiskCount
&&
720 LayoutArray
[DiskNumber
])
722 /* Search for extended partitions */
723 for (j
= NUM_PARTITION_TABLE_ENTRIES
; j
< LayoutArray
[DiskNumber
]->PartitionCount
; j
++)
725 if (IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
) &&
726 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
727 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
!= 0)
730 L
"\\Device\\Harddisk%d\\Partition%d",
732 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
733 RtlInitUnicodeString(&UnicodeString2
,
739 HalpAssignDrive(&UnicodeString2
,
741 DOSDEVICE_DRIVE_FIXED
,
742 LayoutArray
[DiskNumber
]->Signature
,
743 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
745 /* Mark the partition as assigned */
746 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
752 /* Assign remaining primary partitions without an arc-name */
753 DPRINT("Assigning remaining primary partitions:\n");
754 for (DiskNumber
= 0; DiskNumber
< ConfigInfo
->DiskCount
; DiskNumber
++)
756 if (LayoutArray
[DiskNumber
])
758 /* Search for primary partitions */
759 for (j
= 0; (j
< NUM_PARTITION_TABLE_ENTRIES
) && (j
< LayoutArray
[DiskNumber
]->PartitionCount
); j
++)
761 if (LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
762 IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
))
765 L
"\\Device\\Harddisk%d\\Partition%d",
767 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
768 RtlInitUnicodeString(&UnicodeString2
,
774 HalpAssignDrive(&UnicodeString2
,
776 DOSDEVICE_DRIVE_FIXED
,
777 LayoutArray
[DiskNumber
]->Signature
,
778 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
780 /* Mark the partition as assigned */
781 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
787 /* Assign extended (logical) partitions without an arc-name */
788 DPRINT("Assigning extended (logical) partitions:\n");
789 for (DiskNumber
= 0; DiskNumber
< ConfigInfo
->DiskCount
; DiskNumber
++)
791 if (LayoutArray
[DiskNumber
])
793 /* Search for extended partitions */
794 for (j
= NUM_PARTITION_TABLE_ENTRIES
; j
< LayoutArray
[DiskNumber
]->PartitionCount
; j
++)
796 if (IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
) &&
797 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
798 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
!= 0)
801 L
"\\Device\\Harddisk%d\\Partition%d",
803 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
804 RtlInitUnicodeString(&UnicodeString2
,
810 HalpAssignDrive(&UnicodeString2
,
812 DOSDEVICE_DRIVE_FIXED
,
813 LayoutArray
[DiskNumber
]->Signature
,
814 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
816 /* Mark the partition as assigned */
817 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
823 /* Assign removable disk drives */
824 DPRINT("Assigning removable disk drives:\n");
825 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
829 /* Search for virtual partitions */
830 if (LayoutArray
[i
]->PartitionCount
== 1 &&
831 LayoutArray
[i
]->PartitionEntry
[0].PartitionType
== 0)
834 L
"\\Device\\Harddisk%d\\Partition1",
836 RtlInitUnicodeString(&UnicodeString2
,
842 HalpAssignDrive(&UnicodeString2
,
844 DOSDEVICE_DRIVE_REMOVABLE
,
846 RtlConvertLongToLargeInteger(0),
852 /* Free layout array */
853 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
855 if (LayoutArray
[i
] != NULL
)
856 ExFreePool(LayoutArray
[i
]);
858 ExFreePool(LayoutArray
);
860 /* Assign floppy drives */
861 DPRINT("Floppy drives: %d\n", ConfigInfo
->FloppyCount
);
862 for (i
= 0; i
< ConfigInfo
->FloppyCount
; i
++)
865 L
"\\Device\\Floppy%d",
867 RtlInitUnicodeString(&UnicodeString1
,
870 /* Assign drive letters A: or B: or first free drive letter */
873 HalpAssignDrive(&UnicodeString1
,
874 (i
< 2) ? i
: AUTO_DRIVE
,
875 DOSDEVICE_DRIVE_REMOVABLE
,
877 RtlConvertLongToLargeInteger(0),
881 /* Assign cdrom drives */
882 DPRINT("CD-Rom drives: %d\n", ConfigInfo
->CdRomCount
);
883 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
886 L
"\\Device\\CdRom%d",
888 RtlInitUnicodeString(&UnicodeString1
,
891 /* Assign first free drive letter */
892 DPRINT(" %wZ\n", &UnicodeString1
);
893 HalpAssignDrive(&UnicodeString1
,
895 DOSDEVICE_DRIVE_CDROM
,
897 RtlConvertLongToLargeInteger(0),
901 /* Anything else to do? */
903 ExFreePool(PartialInformation
);
914 /* PRIVATE FUNCTIONS *********************************************************/
918 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject
,
919 IN PDISK_GEOMETRY Geometry
,
920 OUT PULONGLONG RealSectorCount
)
923 IO_STATUS_BLOCK IoStatusBlock
;
926 PARTITION_INFORMATION PartitionInfo
;
929 /* Allocate a non-paged event */
930 Event
= ExAllocatePoolWithTag(NonPagedPool
,
933 if (!Event
) return STATUS_INSUFFICIENT_RESOURCES
;
936 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
939 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
944 sizeof(DISK_GEOMETRY
),
950 /* Fail, free the event */
952 return STATUS_INSUFFICIENT_RESOURCES
;
955 /* Call the driver and check if it's pending */
956 Status
= IoCallDriver(DeviceObject
, Irp
);
957 if (Status
== STATUS_PENDING
)
959 /* Wait on the driver */
960 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
961 Status
= IoStatusBlock
.Status
;
964 /* Check if the driver returned success */
965 if(NT_SUCCESS(Status
))
967 /* Build another IRP */
968 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO
,
973 sizeof(PARTITION_INFORMATION
),
979 /* Fail, free the event */
981 return STATUS_INSUFFICIENT_RESOURCES
;
984 /* Call the driver and check if it's pending */
985 Status
= IoCallDriver(DeviceObject
, Irp
);
986 if (Status
== STATUS_PENDING
)
988 /* Wait on the driver */
989 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
990 Status
= IoStatusBlock
.Status
;
993 /* Check if the driver returned success */
994 if(NT_SUCCESS(Status
))
996 /* Get the number of sectors */
997 *RealSectorCount
= (PartitionInfo
.PartitionLength
.QuadPart
/
998 Geometry
->BytesPerSector
);
1002 /* Free the event and return the Status */
1009 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry
,
1010 IN ULONGLONG MaxOffset
,
1011 IN ULONGLONG MaxSector
)
1013 ULONGLONG EndingSector
;
1016 /* Unused partitions are considered valid */
1017 if (Entry
->PartitionType
== PARTITION_ENTRY_UNUSED
) return TRUE
;
1019 /* Get the last sector of the partition */
1020 EndingSector
= GET_STARTING_SECTOR(Entry
) + GET_PARTITION_LENGTH(Entry
);
1022 /* Check if it's more then the maximum sector */
1023 if (EndingSector
> MaxSector
)
1025 /* Invalid partition */
1026 DPRINT1("FSTUB: entry is invalid\n");
1027 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry
));
1028 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry
));
1029 DPRINT1("FSTUB: end %#I64x\n", EndingSector
);
1030 DPRINT1("FSTUB: max %#I64x\n", MaxSector
);
1033 else if(GET_STARTING_SECTOR(Entry
) > MaxOffset
)
1035 /* Invalid partition */
1036 DPRINT1("FSTUB: entry is invalid\n");
1037 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry
));
1038 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry
));
1039 DPRINT1("FSTUB: end %#I64x\n", EndingSector
);
1040 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset
);
1044 /* It's fine, return success */
1050 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset
,
1051 IN PLARGE_INTEGER PartitionLength
,
1052 IN CCHAR ShiftCount
,
1053 IN ULONG SectorsPerTrack
,
1054 IN ULONG NumberOfTracks
,
1055 IN ULONG ConventionalCylinders
,
1056 OUT PPARTITION_DESCRIPTOR PartitionDescriptor
)
1058 LARGE_INTEGER FirstSector
, SectorCount
;
1059 ULONG LastSector
, Remainder
, SectorsPerCylinder
;
1060 ULONG StartingCylinder
, EndingCylinder
;
1061 ULONG StartingTrack
, EndingTrack
;
1062 ULONG StartingSector
, EndingSector
;
1065 /* Calculate the number of sectors for each cylinder */
1066 SectorsPerCylinder
= SectorsPerTrack
* NumberOfTracks
;
1068 /* Calculate the first sector, and the sector count */
1069 FirstSector
.QuadPart
= PartitionOffset
->QuadPart
>> ShiftCount
;
1070 SectorCount
.QuadPart
= PartitionLength
->QuadPart
>> ShiftCount
;
1072 /* Now calculate the last sector */
1073 LastSector
= FirstSector
.LowPart
+ SectorCount
.LowPart
- 1;
1075 /* Calculate the first and last cylinders */
1076 StartingCylinder
= FirstSector
.LowPart
/ SectorsPerCylinder
;
1077 EndingCylinder
= LastSector
/ SectorsPerCylinder
;
1079 /* Set the default number of cylinders */
1080 if (!ConventionalCylinders
) ConventionalCylinders
= 1024;
1082 /* Normalize the values */
1083 if (StartingCylinder
>= ConventionalCylinders
)
1085 /* Set the maximum to 1023 */
1086 StartingCylinder
= ConventionalCylinders
- 1;
1088 if (EndingCylinder
>= ConventionalCylinders
)
1090 /* Set the maximum to 1023 */
1091 EndingCylinder
= ConventionalCylinders
- 1;
1094 /* Calculate the starting head and sector that still remain */
1095 Remainder
= FirstSector
.LowPart
% SectorsPerCylinder
;
1096 StartingTrack
= Remainder
/ SectorsPerTrack
;
1097 StartingSector
= Remainder
% SectorsPerTrack
;
1099 /* Calculate the ending head and sector that still remain */
1100 Remainder
= LastSector
% SectorsPerCylinder
;
1101 EndingTrack
= Remainder
/ SectorsPerTrack
;
1102 EndingSector
= Remainder
% SectorsPerTrack
;
1104 /* Set cylinder data for the MSB */
1105 PartitionDescriptor
->StartingCylinderMsb
= (UCHAR
)StartingCylinder
;
1106 PartitionDescriptor
->EndingCylinderMsb
= (UCHAR
)EndingCylinder
;
1108 /* Set the track data */
1109 PartitionDescriptor
->StartingTrack
= (UCHAR
)StartingTrack
;
1110 PartitionDescriptor
->EndingTrack
= (UCHAR
)EndingTrack
;
1112 /* Update cylinder data for the LSB */
1113 StartingCylinder
= ((StartingSector
+ 1) & 0x3F) |
1114 ((StartingCylinder
>> 2) & 0xC0);
1115 EndingCylinder
= ((EndingSector
+ 1) & 0x3F) |
1116 ((EndingCylinder
>> 2) & 0xC0);
1118 /* Set the cylinder data for the LSB */
1119 PartitionDescriptor
->StartingCylinderLsb
= (UCHAR
)StartingCylinder
;
1120 PartitionDescriptor
->EndingCylinderLsb
= (UCHAR
)EndingCylinder
;
1125 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject
,
1126 IN PULONG ConventionalCylinders
,
1127 IN PLONGLONG DiskSize
)
1129 PDISK_GEOMETRY DiskGeometry
= NULL
;
1130 PIO_STATUS_BLOCK IoStatusBlock
= NULL
;
1131 PKEVENT Event
= NULL
;
1136 *ConventionalCylinders
= 0;
1139 /* Allocate the structure in nonpaged pool */
1140 DiskGeometry
= ExAllocatePoolWithTag(NonPagedPool
,
1141 sizeof(DISK_GEOMETRY
),
1143 if (!DiskGeometry
) goto Cleanup
;
1145 /* Allocate the status block in nonpaged pool */
1146 IoStatusBlock
= ExAllocatePoolWithTag(NonPagedPool
,
1147 sizeof(IO_STATUS_BLOCK
),
1149 if (!IoStatusBlock
) goto Cleanup
;
1151 /* Allocate the event in nonpaged pool too */
1152 Event
= ExAllocatePoolWithTag(NonPagedPool
,
1155 if (!Event
) goto Cleanup
;
1157 /* Initialize the event */
1158 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
1161 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1166 sizeof(DISK_GEOMETRY
),
1170 if (!Irp
) goto Cleanup
;
1172 /* Now call the driver */
1173 Status
= IoCallDriver(DeviceObject
, Irp
);
1174 if (Status
== STATUS_PENDING
)
1176 /* Wait for it to complete */
1177 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
1178 Status
= IoStatusBlock
->Status
;
1181 /* Check driver status */
1182 if (NT_SUCCESS(Status
))
1184 /* Return the cylinder count */
1185 *ConventionalCylinders
= DiskGeometry
->Cylinders
.LowPart
;
1187 /* Make sure it's not larger then 1024 */
1188 if (DiskGeometry
->Cylinders
.LowPart
>= 1024)
1190 /* Otherwise, normalize the value */
1191 *ConventionalCylinders
= 1024;
1194 /* Calculate the disk size */
1195 *DiskSize
= DiskGeometry
->Cylinders
.QuadPart
*
1196 DiskGeometry
->TracksPerCylinder
*
1197 DiskGeometry
->SectorsPerTrack
*
1198 DiskGeometry
->BytesPerSector
;
1202 /* Free all the pointers */
1203 if (Event
) ExFreePool(Event
);
1204 if (IoStatusBlock
) ExFreePool(IoStatusBlock
);
1205 if (DiskGeometry
) ExFreePool(DiskGeometry
);
1211 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject
,
1212 IN ULONG SectorSize
,
1213 IN ULONG MbrTypeIdentifier
,
1214 OUT PVOID
*MbrBuffer
)
1216 LARGE_INTEGER Offset
;
1220 IO_STATUS_BLOCK IoStatusBlock
;
1222 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1224 PIO_STACK_LOCATION IoStackLocation
;
1225 Offset
.QuadPart
= 0;
1227 /* Assume failure */
1230 /* Normalize the buffer size */
1231 BufferSize
= max(SectorSize
, 512);
1233 /* Allocate the buffer */
1234 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1235 PAGE_SIZE
> BufferSize
?
1236 PAGE_SIZE
: BufferSize
,
1238 if (!Buffer
) return;
1240 /* Initialize the Event */
1241 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1244 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1258 /* Make sure to override volume verification */
1259 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1260 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1262 /* Call the driver */
1263 Status
= IoCallDriver(DeviceObject
, Irp
);
1264 if (Status
== STATUS_PENDING
)
1266 /* Wait for completion */
1267 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1268 Status
= IoStatusBlock
.Status
;
1271 /* Check driver Status */
1272 if (NT_SUCCESS(Status
))
1274 /* Validate the MBR Signature */
1275 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1282 /* Get the partition entry */
1283 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1284 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1286 /* Make sure it's what the caller wanted */
1287 if (PartitionDescriptor
->PartitionType
!= MbrTypeIdentifier
)
1289 /* It's not, free our buffer */
1294 /* Check if this is a secondary entry */
1295 if (PartitionDescriptor
->PartitionType
== 0x54)
1297 /* Return our buffer, but at sector 63 */
1298 *(PULONG
)Buffer
= 63;
1299 *MbrBuffer
= Buffer
;
1301 else if (PartitionDescriptor
->PartitionType
== 0x55)
1303 /* EZ Drive, return the buffer directly */
1304 *MbrBuffer
= Buffer
;
1308 /* Otherwise crash on debug builds */
1309 ASSERT(PartitionDescriptor
->PartitionType
== 0x55);
1317 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
1318 IN ULONG SectorSize
,
1319 IN BOOLEAN ReturnRecognizedPartitions
,
1320 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
1323 IO_STATUS_BLOCK IoStatusBlock
;
1325 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1328 PPARTITION_INFORMATION PartitionInfo
;
1329 PUCHAR Buffer
= NULL
;
1330 ULONG BufferSize
= 2048, InputSize
;
1331 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo
= NULL
;
1332 LONG j
= -1, i
= -1, k
;
1333 DISK_GEOMETRY DiskGeometry
;
1334 LONGLONG EndSector
, MaxSector
, StartOffset
;
1335 ULONGLONG MaxOffset
;
1336 LARGE_INTEGER Offset
, VolumeOffset
;
1337 BOOLEAN IsPrimary
= TRUE
, IsEzDrive
= FALSE
, MbrFound
= FALSE
;
1338 BOOLEAN IsValid
, IsEmpty
= TRUE
;
1340 PIO_STACK_LOCATION IoStackLocation
;
1341 PBOOT_SECTOR_INFO BootSectorInfo
= (PBOOT_SECTOR_INFO
)Buffer
;
1342 UCHAR PartitionType
;
1343 LARGE_INTEGER HiddenSectors64
;
1344 VolumeOffset
.QuadPart
= Offset
.QuadPart
= 0;
1347 /* Allocate the buffer */
1348 *PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1351 if (!(*PartitionBuffer
)) return STATUS_INSUFFICIENT_RESOURCES
;
1353 /* Normalize the buffer size */
1354 InputSize
= max(512, SectorSize
);
1356 /* Check for EZ Drive */
1357 HalExamineMBR(DeviceObject
, InputSize
, 0x55, &MbrBuffer
);
1360 /* EZ Drive found, bias the offset */
1362 ExFreePool(MbrBuffer
);
1363 Offset
.QuadPart
= 512;
1366 /* Get drive geometry */
1367 Status
= HalpGetFullGeometry(DeviceObject
, &DiskGeometry
, &MaxOffset
);
1368 if (!NT_SUCCESS(Status
))
1370 ExFreePool(*PartitionBuffer
);
1371 *PartitionBuffer
= NULL
;
1375 /* Get the end and maximum sector */
1376 EndSector
= MaxOffset
;
1377 MaxSector
= MaxOffset
<< 1;
1378 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
1379 MaxOffset
, MaxSector
);
1381 /* Allocate our buffer */
1382 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
1385 /* Fail, free the input buffer */
1386 ExFreePool(*PartitionBuffer
);
1387 return STATUS_INSUFFICIENT_RESOURCES
;
1390 /* Start partition loop */
1393 /* Assume the partition is valid */
1396 /* Initialize the event */
1397 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1399 /* Clear the buffer and build the IRP */
1400 RtlZeroMemory(Buffer
, InputSize
);
1401 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1411 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1415 /* Make sure to disable volume verification */
1416 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1417 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1419 /* Call the driver */
1420 Status
= IoCallDriver(DeviceObject
, Irp
);
1421 if (Status
== STATUS_PENDING
)
1423 /* Wait for completion */
1424 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1425 Status
= IoStatusBlock
.Status
;
1428 /* Normalize status code and check for failure */
1429 if (Status
== STATUS_NO_DATA_DETECTED
) Status
= STATUS_SUCCESS
;
1430 if (!NT_SUCCESS(Status
)) break;
1432 /* If we biased for EZ-Drive, unbias now */
1433 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
1435 /* Make sure this is a valid MBR */
1436 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1438 /* It's not, fail */
1439 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1440 "partition table %d\n", j
+ 1);
1444 /* At this point we have a valid MBR */
1447 /* Check if we weren't given an offset */
1448 if (!Offset
.QuadPart
)
1450 /* Then read the signature off the disk */
1451 (*PartitionBuffer
)->Signature
= ((PULONG
)Buffer
)
1452 [PARTITION_TABLE_OFFSET
/ 2 - 1];
1455 /* Get the partition descriptor array */
1456 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1457 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1459 /* Get the partition type */
1460 PartitionType
= PartitionDescriptor
->PartitionType
;
1462 /* Start looping partitions */
1464 DPRINT("FSTUB: Partition Table %d:\n", j
);
1465 for (Entry
= 1, k
= 0; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1467 /* Get the partition type */
1468 PartitionType
= PartitionDescriptor
->PartitionType
;
1470 /* Print debug messages */
1471 DPRINT("Partition Entry %d,%d: type %#x %s\n",
1475 (PartitionDescriptor
->ActiveFlag
) ? "Active" : "");
1476 DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
1477 GET_STARTING_SECTOR(PartitionDescriptor
),
1478 GET_PARTITION_LENGTH(PartitionDescriptor
));
1480 /* Make sure that the partition is valid, unless it's the first */
1481 if (!(HalpIsValidPartitionEntry(PartitionDescriptor
,
1483 MaxSector
)) && !(j
))
1485 /* It's invalid, so fail */
1490 /* Check if it's a container */
1491 if (IsContainerPartition(PartitionType
))
1493 /* Increase the count of containers */
1496 /* More then one table is invalid */
1497 DPRINT1("FSTUB: Multiple container partitions found in "
1498 "partition table %d\n - table is invalid\n",
1505 /* Check if the partition is supposedly empty */
1508 /* But check if it actually has a start and/or length */
1509 if ((GET_STARTING_SECTOR(PartitionDescriptor
)) ||
1510 (GET_PARTITION_LENGTH(PartitionDescriptor
)))
1512 /* So then it's not really empty */
1517 /* Check if the caller wanted only recognized partitions */
1518 if (ReturnRecognizedPartitions
)
1520 /* Then check if this one is unused, or a container */
1521 if ((PartitionType
== PARTITION_ENTRY_UNUSED
) ||
1522 IsContainerPartition(PartitionType
))
1524 /* Skip it, since the caller doesn't want it */
1529 /* Increase the structure count and check if they can fit */
1530 if ((sizeof(DRIVE_LAYOUT_INFORMATION
) +
1531 (++i
* sizeof(PARTITION_INFORMATION
))) >
1534 /* Allocate a new buffer that's twice as big */
1535 DriveLayoutInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1538 if (!DriveLayoutInfo
)
1540 /* Out of memory, unto this extra structure */
1542 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1546 /* Copy the contents of the old buffer */
1547 RtlMoveMemory(DriveLayoutInfo
,
1551 /* Free the old buffer and set this one as the new one */
1552 ExFreePool(*PartitionBuffer
);
1553 *PartitionBuffer
= DriveLayoutInfo
;
1555 /* Double the size */
1559 /* Now get the current structure being filled and initialize it */
1560 PartitionInfo
= &(*PartitionBuffer
)->PartitionEntry
[i
];
1561 PartitionInfo
->PartitionType
= PartitionType
;
1562 PartitionInfo
->RewritePartition
= FALSE
;
1564 /* Check if we're dealing with a partition that's in use */
1565 if (PartitionType
!= PARTITION_ENTRY_UNUSED
)
1567 /* Check if it's bootable */
1568 PartitionInfo
->BootIndicator
= PartitionDescriptor
->
1572 /* Check if its' a container */
1573 if (IsContainerPartition(PartitionType
))
1575 /* Then don't recognize it and use the volume offset */
1576 PartitionInfo
->RecognizedPartition
= FALSE
;
1577 StartOffset
= VolumeOffset
.QuadPart
;
1581 /* Then recognize it and use the partition offset */
1582 PartitionInfo
->RecognizedPartition
= TRUE
;
1583 StartOffset
= Offset
.QuadPart
;
1586 /* Get the starting offset */
1587 PartitionInfo
->StartingOffset
.QuadPart
=
1589 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor
),
1592 /* Calculate the number of hidden sectors */
1593 HiddenSectors64
.QuadPart
= (PartitionInfo
->
1594 StartingOffset
.QuadPart
-
1597 PartitionInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
1599 /* Get the partition length */
1600 PartitionInfo
->PartitionLength
.QuadPart
=
1601 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor
),
1604 /* FIXME: REACTOS HACK */
1605 PartitionInfo
->PartitionNumber
= i
+ 1;
1609 /* Otherwise, clear all the relevant fields */
1610 PartitionInfo
->BootIndicator
= FALSE
;
1611 PartitionInfo
->RecognizedPartition
= FALSE
;
1612 PartitionInfo
->StartingOffset
.QuadPart
= 0;
1613 PartitionInfo
->PartitionLength
.QuadPart
= 0;
1614 PartitionInfo
->HiddenSectors
= 0;
1616 /* FIXME: REACTOS HACK */
1617 PartitionInfo
->PartitionNumber
= 0;
1621 /* Finish debug log, and check for failure */
1623 if (!NT_SUCCESS(Status
)) break;
1625 /* Also check if we hit an invalid entry here */
1628 /* We did, so break out of the loop minus one entry */
1633 /* Reset the offset */
1634 Offset
.QuadPart
= 0;
1636 /* Go back to the descriptor array and loop it */
1637 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1638 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1639 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1641 /* Check if this is a container partition, since we skipped them */
1642 if (IsContainerPartition(PartitionType
))
1644 /* Get its offset */
1645 Offset
.QuadPart
= VolumeOffset
.QuadPart
+
1647 GET_STARTING_SECTOR(PartitionDescriptor
),
1650 /* If this is a primary partition, this is the volume offset */
1651 if (IsPrimary
) VolumeOffset
= Offset
;
1653 /* Also update the maximum sector */
1654 MaxSector
= GET_PARTITION_LENGTH(PartitionDescriptor
);
1655 DPRINT1("FSTUB: MaxSector now = %#08lx\n", MaxSector
);
1660 /* Loop the next partitions, which are not primary anymore */
1662 } while (Offset
.HighPart
| Offset
.LowPart
);
1664 /* Check if this is a removable device that's probably a super-floppy */
1665 if ((DiskGeometry
.MediaType
== RemovableMedia
) &&
1670 /* Read the jump bytes to detect super-floppy */
1671 if ((BootSectorInfo
->JumpByte
[0] == 0xeb) ||
1672 (BootSectorInfo
->JumpByte
[0] == 0xe9))
1674 /* Super floppes don't have typical MBRs, so skip them */
1675 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
1676 "table - disk is a super floppy and has no valid MBR\n",
1677 BootSectorInfo
->JumpByte
);
1682 /* Check if we're still at partition -1 */
1685 /* The likely cause is the super floppy detection above */
1686 if ((MbrFound
) || (DiskGeometry
.MediaType
== RemovableMedia
))
1688 /* Print out debugging information */
1689 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
1692 DPRINT1("FSTUB: Drive has %#08lx sectors and is %#016I64x "
1694 EndSector
, EndSector
* DiskGeometry
.BytesPerSector
);
1696 /* We should at least have some sectors */
1699 /* Get the entry we'll use */
1700 PartitionInfo
= &(*PartitionBuffer
)->PartitionEntry
[0];
1702 /* Fill it out with data for a super-floppy */
1703 PartitionInfo
->RewritePartition
= FALSE
;
1704 PartitionInfo
->RecognizedPartition
= TRUE
;
1705 PartitionInfo
->PartitionType
= PARTITION_FAT_16
;
1706 PartitionInfo
->BootIndicator
= FALSE
;
1707 PartitionInfo
->HiddenSectors
= 0;
1708 PartitionInfo
->StartingOffset
.QuadPart
= 0;
1709 PartitionInfo
->PartitionLength
.QuadPart
= (EndSector
*
1713 /* FIXME: REACTOS HACK */
1714 PartitionInfo
->PartitionNumber
= 0;
1716 /* Set the signature and set the count back to 0 */
1717 (*PartitionBuffer
)->Signature
= 1;
1723 /* Otherwise, this isn't a super floppy, so set an invalid count */
1728 /* Set the partition count */
1729 (*PartitionBuffer
)->PartitionCount
= ++i
;
1731 /* If we have no count, delete the signature */
1732 if (!i
) (*PartitionBuffer
)->Signature
= 0;
1734 /* Free the buffer and check for success */
1735 if (Buffer
) ExFreePool(Buffer
);
1736 if (!NT_SUCCESS(Status
)) ExFreePool(*PartitionBuffer
);
1744 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
1745 IN ULONG SectorSize
,
1746 IN ULONG PartitionNumber
,
1747 IN ULONG PartitionType
)
1751 IO_STATUS_BLOCK IoStatusBlock
;
1753 LARGE_INTEGER Offset
, VolumeOffset
;
1754 PUCHAR Buffer
= NULL
;
1758 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1759 BOOLEAN IsPrimary
= TRUE
, IsEzDrive
= FALSE
;
1761 PIO_STACK_LOCATION IoStackLocation
;
1762 VolumeOffset
.QuadPart
= Offset
.QuadPart
= 0;
1765 /* Normalize the buffer size */
1766 BufferSize
= max(512, SectorSize
);
1768 /* Check for EZ Drive */
1769 HalExamineMBR(DeviceObject
, BufferSize
, 0x55, &MbrBuffer
);
1772 /* EZ Drive found, bias the offset */
1774 ExFreePool(MbrBuffer
);
1775 Offset
.QuadPart
= 512;
1778 /* Allocate our partition buffer */
1779 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
1780 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1782 /* Initialize the event we'll use and loop partitions */
1783 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1786 /* Reset the event since we reuse it */
1787 KeResetEvent(&Event
);
1789 /* Build the read IRP */
1790 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1800 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1804 /* Make sure to disable volume verification */
1805 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1806 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1808 /* Call the driver */
1809 Status
= IoCallDriver(DeviceObject
, Irp
);
1810 if (Status
== STATUS_PENDING
)
1812 /* Wait for completion */
1813 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1814 Status
= IoStatusBlock
.Status
;
1817 /* Check for failure */
1818 if (!NT_SUCCESS(Status
)) break;
1820 /* If we biased for EZ-Drive, unbias now */
1821 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
1823 /* Make sure this is a valid MBR */
1824 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1826 /* It's not, fail */
1827 Status
= STATUS_BAD_MASTER_BOOT_RECORD
;
1831 /* Get the partition descriptors and loop them */
1832 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1833 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1834 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1836 /* Check if it's unused or a container partition */
1837 if ((PartitionDescriptor
->PartitionType
==
1838 PARTITION_ENTRY_UNUSED
) ||
1839 (IsContainerPartition(PartitionDescriptor
->PartitionType
)))
1841 /* Go to the next one */
1845 /* It's a valid partition, so increase the partition count */
1846 if (++i
== PartitionNumber
)
1848 /* We found a match, set the type */
1849 PartitionDescriptor
->PartitionType
= (UCHAR
)PartitionType
;
1851 /* Reset the reusable event */
1852 KeResetEvent(&Event
);
1854 /* Build the write IRP */
1855 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
1865 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1869 /* Disable volume verification */
1870 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1871 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1873 /* Call the driver */
1874 Status
= IoCallDriver(DeviceObject
, Irp
);
1875 if (Status
== STATUS_PENDING
)
1877 /* Wait for completion */
1878 KeWaitForSingleObject(&Event
,
1883 Status
= IoStatusBlock
.Status
;
1886 /* We're done, break out of the loop */
1891 /* If we looped all the partitions, break out */
1892 if (Entry
<= NUM_PARTITION_TABLE_ENTRIES
) break;
1894 /* Nothing found yet, get the partition array again */
1895 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1896 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1897 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1899 /* Check if this was a container partition (we skipped these) */
1900 if (IsContainerPartition(PartitionDescriptor
->PartitionType
))
1902 /* Update the partition offset */
1903 Offset
.QuadPart
= VolumeOffset
.QuadPart
+
1904 GET_STARTING_SECTOR(PartitionDescriptor
) *
1907 /* If this was the primary partition, update the volume too */
1908 if (IsPrimary
) VolumeOffset
= Offset
;
1913 /* Check if we already searched all the partitions */
1914 if (Entry
> NUM_PARTITION_TABLE_ENTRIES
)
1916 /* Then we failed to find a good MBR */
1917 Status
= STATUS_BAD_MASTER_BOOT_RECORD
;
1921 /* Loop the next partitions, which are not primary anymore */
1923 } while (i
< PartitionNumber
);
1925 /* Everything done, cleanup */
1926 if (Buffer
) ExFreePool(Buffer
);
1932 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
1933 IN ULONG SectorSize
,
1934 IN ULONG SectorsPerTrack
,
1935 IN ULONG NumberOfHeads
,
1936 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
1939 IO_STATUS_BLOCK IoStatusBlock
;
1941 NTSTATUS Status
= STATUS_SUCCESS
;
1945 PPARTITION_TABLE PartitionTable
;
1946 LARGE_INTEGER Offset
, NextOffset
, ExtendedOffset
, SectorOffset
;
1947 LARGE_INTEGER StartOffset
, PartitionLength
;
1950 BOOLEAN IsEzDrive
= FALSE
, IsSuperFloppy
= FALSE
, DoRewrite
= FALSE
, IsMbr
;
1951 ULONG ConventionalCylinders
;
1953 PDISK_LAYOUT DiskLayout
= (PDISK_LAYOUT
)PartitionBuffer
;
1955 UCHAR PartitionType
;
1956 PIO_STACK_LOCATION IoStackLocation
;
1957 PPARTITION_INFORMATION PartitionInfo
= PartitionBuffer
->PartitionEntry
;
1958 PPARTITION_INFORMATION TableEntry
;
1959 ExtendedOffset
.QuadPart
= NextOffset
.QuadPart
= Offset
.QuadPart
= 0;
1962 /* Normalize the buffer size */
1963 BufferSize
= max(512, SectorSize
);
1965 /* Get the partial drive geometry */
1966 xHalGetPartialGeometry(DeviceObject
, &ConventionalCylinders
, &DiskSize
);
1968 /* Check for EZ Drive */
1969 HalExamineMBR(DeviceObject
, BufferSize
, 0x55, &MbrBuffer
);
1972 /* EZ Drive found, bias the offset */
1974 ExFreePool(MbrBuffer
);
1975 Offset
.QuadPart
= 512;
1978 /* Get the number of bits to shift to multiply by the sector size */
1979 for (k
= 0; k
< 32; k
++) if ((SectorSize
>> k
) == 1) break;
1981 /* Check if there's only one partition */
1982 if (PartitionBuffer
->PartitionCount
== 1)
1984 /* Check if it has no starting offset or hidden sectors */
1985 if (!(PartitionInfo
->StartingOffset
.QuadPart
) &&
1986 !(PartitionInfo
->HiddenSectors
))
1988 /* Then it's a super floppy */
1989 IsSuperFloppy
= TRUE
;
1991 /* Which also means it must be non-bootable FAT-16 */
1992 if ((PartitionInfo
->PartitionNumber
) ||
1993 (PartitionInfo
->PartitionType
!= PARTITION_FAT_16
) ||
1994 (PartitionInfo
->BootIndicator
))
1996 /* It's not, so we fail */
1997 return STATUS_INVALID_PARAMETER
;
2000 /* Check if it needs a rewrite, and disable EZ drive for sure */
2001 if (PartitionInfo
->RewritePartition
) DoRewrite
= TRUE
;
2006 /* Count the number of partition tables */
2007 DiskLayout
->TableCount
= (PartitionBuffer
->PartitionCount
+ 4 - 1) / 4;
2009 /* Allocate our partition buffer */
2010 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
2011 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2013 /* Loop the entries */
2014 Entry
= (PPTE
)&Buffer
[PARTITION_TABLE_OFFSET
];
2015 for (i
= 0; i
< DiskLayout
->TableCount
; i
++)
2017 /* Set if this is the MBR partition */
2020 /* Initialize th event */
2021 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2023 /* Build the read IRP */
2024 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2034 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2038 /* Make sure to disable volume verification */
2039 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2040 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2042 /* Call the driver */
2043 Status
= IoCallDriver(DeviceObject
, Irp
);
2044 if (Status
== STATUS_PENDING
)
2046 /* Wait for completion */
2047 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
2048 Status
= IoStatusBlock
.Status
;
2051 /* Check for failure */
2052 if (!NT_SUCCESS(Status
)) break;
2054 /* If we biased for EZ-Drive, unbias now */
2055 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2057 /* Check if this is a normal disk */
2060 /* Set the boot record signature */
2061 Buffer
[BOOT_SIGNATURE_OFFSET
] = BOOT_RECORD_SIGNATURE
;
2063 /* By default, don't require a rewrite */
2066 /* Check if we don't have an offset */
2067 if (!Offset
.QuadPart
)
2069 /* Check if the signature doesn't match */
2070 if (((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1] !=
2071 PartitionBuffer
->Signature
)
2073 /* Then write the signature and now w need a rewrite */
2074 ((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1] =
2075 PartitionBuffer
->Signature
;
2080 /* Loop the partition table entries */
2081 PartitionTable
= &DiskLayout
->PartitionTable
[i
];
2082 for (j
= 0; j
< 4; j
++)
2084 /* Get the current entry and type */
2085 TableEntry
= &PartitionTable
->PartitionEntry
[j
];
2086 PartitionType
= TableEntry
->PartitionType
;
2088 /* Check if the entry needs a rewrite */
2089 if (TableEntry
->RewritePartition
)
2091 /* Then we need one too */
2094 /* Save the type and if it's a bootable partition */
2095 Entry
[j
].PartitionType
= TableEntry
->PartitionType
;
2096 Entry
[j
].ActiveFlag
= TableEntry
->BootIndicator
? 0x80 : 0;
2098 /* Make sure it's used */
2099 if (PartitionType
!= PARTITION_ENTRY_UNUSED
)
2101 /* Make sure it's not a container (unless primary) */
2102 if ((IsMbr
) || !(IsContainerPartition(PartitionType
)))
2104 /* Use the partition offset */
2105 StartOffset
.QuadPart
= Offset
.QuadPart
;
2109 /* Use the extended logical partition offset */
2110 StartOffset
.QuadPart
= ExtendedOffset
.QuadPart
;
2113 /* Set the sector offset */
2114 SectorOffset
.QuadPart
= TableEntry
->
2115 StartingOffset
.QuadPart
-
2116 StartOffset
.QuadPart
;
2118 /* Now calculate the starting sector */
2119 StartOffset
.QuadPart
= SectorOffset
.QuadPart
>> k
;
2120 Entry
[j
].StartingSector
= StartOffset
.LowPart
;
2122 /* As well as the length */
2123 PartitionLength
.QuadPart
= TableEntry
->PartitionLength
.
2125 Entry
[j
].PartitionLength
= PartitionLength
.LowPart
;
2127 /* Calculate the CHS values */
2128 HalpCalculateChsValues(&TableEntry
->StartingOffset
,
2129 &TableEntry
->PartitionLength
,
2133 ConventionalCylinders
,
2134 (PPARTITION_DESCRIPTOR
)
2139 /* Otherwise set up an empty entry */
2140 Entry
[j
].StartingSector
= 0;
2141 Entry
[j
].PartitionLength
= 0;
2142 Entry
[j
].StartingTrack
= 0;
2143 Entry
[j
].EndingTrack
= 0;
2144 Entry
[j
].StartingCylinder
= 0;
2145 Entry
[j
].EndingCylinder
= 0;
2149 /* Check if this is a container partition */
2150 if (IsContainerPartition(PartitionType
))
2152 /* Then update the offset to use */
2153 NextOffset
= TableEntry
->StartingOffset
;
2158 /* Check if we need to write back the buffer */
2161 /* We don't need to do this again */
2164 /* Initialize the event */
2165 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2167 /* If we unbiased for EZ-Drive, rebias now */
2168 if ((IsEzDrive
) && !(Offset
.QuadPart
)) Offset
.QuadPart
= 512;
2170 /* Build the write IRP */
2171 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
2181 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2185 /* Make sure to disable volume verification */
2186 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2187 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2189 /* Call the driver */
2190 Status
= IoCallDriver(DeviceObject
, Irp
);
2191 if (Status
== STATUS_PENDING
)
2193 /* Wait for completion */
2194 KeWaitForSingleObject(&Event
,
2199 Status
= IoStatusBlock
.Status
;
2202 /* Check for failure */
2203 if (!NT_SUCCESS(Status
)) break;
2205 /* If we biased for EZ-Drive, unbias now */
2206 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2209 /* Update the partition offset and set the extended offset if needed */
2210 Offset
= NextOffset
;
2211 if (IsMbr
) ExtendedOffset
= NextOffset
;
2214 /* If we had a buffer, free it, then return status */
2215 if (Buffer
) ExFreePool(Buffer
);
2219 /* PUBLIC FUNCTIONS **********************************************************/
2226 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject
,
2227 IN ULONG SectorSize
,
2228 IN ULONG MbrTypeIdentifier
,
2229 OUT PVOID
*MbrBuffer
)
2231 HALDISPATCH
->HalExamineMBR(DeviceObject
,
2242 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
2243 IN ULONG SectorSize
,
2244 IN BOOLEAN ReturnRecognizedPartitions
,
2245 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
2247 return HALDISPATCH
->HalIoReadPartitionTable(DeviceObject
,
2249 ReturnRecognizedPartitions
,
2258 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
2259 IN ULONG SectorSize
,
2260 IN ULONG PartitionNumber
,
2261 IN ULONG PartitionType
)
2263 return HALDISPATCH
->HalIoSetPartitionInformation(DeviceObject
,
2274 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
2275 IN ULONG SectorSize
,
2276 IN ULONG SectorsPerTrack
,
2277 IN ULONG NumberOfHeads
,
2278 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
2280 return HALDISPATCH
->HalIoWritePartitionTable(DeviceObject
,
2292 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
2293 IN PSTRING NtDeviceName
,
2294 OUT PUCHAR NtSystemPath
,
2295 OUT PSTRING NtSystemPathString
)
2297 HALDISPATCH
->HalIoAssignDriveLetters(LoaderBlock
,
2300 NtSystemPathString
);