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
);
399 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
400 IN PSTRING NtDeviceName
,
401 OUT PUCHAR NtSystemPath
,
402 OUT PSTRING NtSystemPathString
)
404 PDRIVE_LAYOUT_INFORMATION
*LayoutArray
;
405 PCONFIGURATION_INFORMATION ConfigInfo
;
406 OBJECT_ATTRIBUTES ObjectAttributes
;
407 IO_STATUS_BLOCK StatusBlock
;
408 UNICODE_STRING UnicodeString1
;
409 UNICODE_STRING UnicodeString2
;
419 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation
;
420 PREG_DISK_MOUNT_INFO DiskMountInfo
;
423 DPRINT("xHalIoAssignDriveLetters()\n");
425 ConfigInfo
= IoGetConfigurationInformation();
427 RDiskCount
= xHalpGetRDiskCount();
429 DPRINT("RDiskCount %d\n", RDiskCount
);
431 Buffer1
= (PWSTR
)ExAllocatePool(PagedPool
,
433 Buffer2
= (PWSTR
)ExAllocatePool(PagedPool
,
436 PartialInformation
= (PKEY_VALUE_PARTIAL_INFORMATION
)ExAllocatePool(PagedPool
,
437 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(REG_DISK_MOUNT_INFO
));
439 DiskMountInfo
= (PREG_DISK_MOUNT_INFO
) PartialInformation
->Data
;
441 /* Open or Create the 'MountedDevices' key */
442 RtlInitUnicodeString(&UnicodeString1
, L
"\\Registry\\Machine\\SYSTEM\\MountedDevices");
443 InitializeObjectAttributes(&ObjectAttributes
,
445 OBJ_CASE_INSENSITIVE
,
448 Status
= ZwOpenKey(&hKey
,
451 if (!NT_SUCCESS(Status
))
453 Status
= ZwCreateKey(&hKey
,
458 REG_OPTION_NON_VOLATILE
,
461 if (!NT_SUCCESS(Status
))
464 DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1
, Status
);
467 /* Create PhysicalDrive links */
468 DPRINT("Physical disk drives: %d\n", ConfigInfo
->DiskCount
);
469 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
472 L
"\\Device\\Harddisk%d\\Partition0",
474 RtlInitUnicodeString(&UnicodeString1
,
477 InitializeObjectAttributes(&ObjectAttributes
,
483 Status
= ZwOpenFile(&FileHandle
,
484 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
488 FILE_SYNCHRONOUS_IO_NONALERT
);
489 if (NT_SUCCESS(Status
))
494 L
"\\??\\PhysicalDrive%d",
496 RtlInitUnicodeString(&UnicodeString2
,
499 DPRINT("Creating link: %S ==> %S\n",
503 IoCreateSymbolicLink(&UnicodeString2
,
508 /* Initialize layout array */
509 LayoutArray
= ExAllocatePool(NonPagedPool
,
510 ConfigInfo
->DiskCount
* sizeof(PDRIVE_LAYOUT_INFORMATION
));
511 RtlZeroMemory(LayoutArray
,
512 ConfigInfo
->DiskCount
* sizeof(PDRIVE_LAYOUT_INFORMATION
));
513 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
516 L
"\\Device\\Harddisk%d\\Partition0",
518 RtlInitUnicodeString(&UnicodeString1
,
521 Status
= xHalQueryDriveLayout(&UnicodeString1
,
523 if (!NT_SUCCESS(Status
))
525 DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
527 LayoutArray
[i
] = NULL
;
530 /* We don't use the RewritePartition value while mounting the disks.
531 * We use this value for marking pre-assigned (registry) partitions.
533 for (j
= 0; j
< LayoutArray
[i
]->PartitionCount
; j
++)
535 LayoutArray
[i
]->PartitionEntry
[j
].RewritePartition
= FALSE
;
540 /* Dump layout array */
541 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
543 DPRINT("Harddisk %d:\n",
546 if (LayoutArray
[i
] == NULL
)
549 DPRINT("Logical partitions: %d\n",
550 LayoutArray
[i
]->PartitionCount
);
552 for (j
= 0; j
< LayoutArray
[i
]->PartitionCount
; j
++)
554 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
556 LayoutArray
[i
]->PartitionEntry
[j
].PartitionNumber
,
557 LayoutArray
[i
]->PartitionEntry
[j
].BootIndicator
,
558 LayoutArray
[i
]->PartitionEntry
[j
].PartitionType
,
559 LayoutArray
[i
]->PartitionEntry
[j
].StartingOffset
.QuadPart
,
560 LayoutArray
[i
]->PartitionEntry
[j
].PartitionLength
.QuadPart
);
565 /* Assign pre-assigned (registry) partitions */
568 for (k
= 2; k
< 26; k
++)
570 swprintf(Buffer1
, DiskMountString
, L
'A' + k
);
571 RtlInitUnicodeString(&UnicodeString1
, Buffer1
);
572 Status
= ZwQueryValueKey(hKey
,
574 KeyValuePartialInformation
,
576 sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + sizeof(REG_DISK_MOUNT_INFO
),
578 if (NT_SUCCESS(Status
) &&
579 PartialInformation
->Type
== REG_BINARY
&&
580 PartialInformation
->DataLength
== sizeof(REG_DISK_MOUNT_INFO
))
582 DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1
, DiskMountInfo
->Signature
,
583 DiskMountInfo
->StartingOffset
.u
.HighPart
, DiskMountInfo
->StartingOffset
.u
.LowPart
);
585 BOOLEAN Found
= FALSE
;
586 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
588 DPRINT("%x\n", LayoutArray
[i
]->Signature
);
589 if (LayoutArray
[i
] &&
590 LayoutArray
[i
]->Signature
&&
591 LayoutArray
[i
]->Signature
== DiskMountInfo
->Signature
)
593 for (j
= 0; j
< LayoutArray
[i
]->PartitionCount
; j
++)
595 if (LayoutArray
[i
]->PartitionEntry
[j
].StartingOffset
.QuadPart
== DiskMountInfo
->StartingOffset
.QuadPart
)
597 if (IsRecognizedPartition(LayoutArray
[i
]->PartitionEntry
[j
].PartitionType
) &&
598 LayoutArray
[i
]->PartitionEntry
[j
].RewritePartition
== FALSE
)
601 L
"\\Device\\Harddisk%d\\Partition%d",
603 LayoutArray
[i
]->PartitionEntry
[j
].PartitionNumber
);
604 RtlInitUnicodeString(&UnicodeString2
,
608 DPRINT(" %wZ\n", &UnicodeString2
);
609 Found
= HalpAssignDrive(&UnicodeString2
,
611 DOSDEVICE_DRIVE_FIXED
,
612 DiskMountInfo
->Signature
,
613 DiskMountInfo
->StartingOffset
,
615 /* Mark the partition as assigned */
616 LayoutArray
[i
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
625 /* We didn't find a partition for this entry, remove them. */
626 Status
= ZwDeleteValueKey(hKey
, &UnicodeString1
);
633 /* Assign bootable partition on first harddisk */
634 DPRINT("Assigning bootable primary partition on first harddisk:\n");
637 Status
= xHalpGetDiskNumberFromRDisk(0, &DiskNumber
);
638 if (NT_SUCCESS(Status
) &&
639 DiskNumber
< ConfigInfo
->DiskCount
&&
640 LayoutArray
[DiskNumber
])
642 /* Search for bootable partition */
643 for (j
= 0; j
< NUM_PARTITION_TABLE_ENTRIES
&& j
< LayoutArray
[DiskNumber
]->PartitionCount
; j
++)
645 if ((LayoutArray
[DiskNumber
]->PartitionEntry
[j
].BootIndicator
== TRUE
) &&
646 IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
))
648 if (LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
)
651 L
"\\Device\\Harddisk%lu\\Partition%d",
653 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
654 RtlInitUnicodeString(&UnicodeString2
,
658 DPRINT(" %wZ\n", &UnicodeString2
);
659 HalpAssignDrive(&UnicodeString2
,
661 DOSDEVICE_DRIVE_FIXED
,
662 LayoutArray
[DiskNumber
]->Signature
,
663 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
665 /* Mark the partition as assigned */
666 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
674 /* Assign remaining primary partitions */
675 DPRINT("Assigning remaining primary partitions:\n");
676 for (RDisk
= 0; RDisk
< RDiskCount
; RDisk
++)
678 Status
= xHalpGetDiskNumberFromRDisk(RDisk
, &DiskNumber
);
679 if (NT_SUCCESS(Status
) &&
680 DiskNumber
< ConfigInfo
->DiskCount
&&
681 LayoutArray
[DiskNumber
])
683 /* Search for primary partitions */
684 for (j
= 0; (j
< NUM_PARTITION_TABLE_ENTRIES
) && (j
< LayoutArray
[DiskNumber
]->PartitionCount
); j
++)
686 if (LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
687 IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
))
690 L
"\\Device\\Harddisk%d\\Partition%d",
692 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
693 RtlInitUnicodeString(&UnicodeString2
,
699 HalpAssignDrive(&UnicodeString2
,
701 DOSDEVICE_DRIVE_FIXED
,
702 LayoutArray
[DiskNumber
]->Signature
,
703 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
705 /* Mark the partition as assigned */
706 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
712 /* Assign extended (logical) partitions */
713 DPRINT("Assigning extended (logical) partitions:\n");
714 for (RDisk
= 0; RDisk
< RDiskCount
; RDisk
++)
716 Status
= xHalpGetDiskNumberFromRDisk(RDisk
, &DiskNumber
);
717 if (NT_SUCCESS(Status
) &&
718 DiskNumber
< ConfigInfo
->DiskCount
&&
719 LayoutArray
[DiskNumber
])
721 /* Search for extended partitions */
722 for (j
= NUM_PARTITION_TABLE_ENTRIES
; j
< LayoutArray
[DiskNumber
]->PartitionCount
; j
++)
724 if (IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
) &&
725 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
726 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
!= 0)
729 L
"\\Device\\Harddisk%d\\Partition%d",
731 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
732 RtlInitUnicodeString(&UnicodeString2
,
738 HalpAssignDrive(&UnicodeString2
,
740 DOSDEVICE_DRIVE_FIXED
,
741 LayoutArray
[DiskNumber
]->Signature
,
742 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
744 /* Mark the partition as assigned */
745 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
751 /* Assign remaining primary partitions without an arc-name */
752 DPRINT("Assigning remaining primary partitions:\n");
753 for (DiskNumber
= 0; DiskNumber
< ConfigInfo
->DiskCount
; DiskNumber
++)
755 if (LayoutArray
[DiskNumber
])
757 /* Search for primary partitions */
758 for (j
= 0; (j
< NUM_PARTITION_TABLE_ENTRIES
) && (j
< LayoutArray
[DiskNumber
]->PartitionCount
); j
++)
760 if (LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
761 IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
))
764 L
"\\Device\\Harddisk%d\\Partition%d",
766 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
767 RtlInitUnicodeString(&UnicodeString2
,
773 HalpAssignDrive(&UnicodeString2
,
775 DOSDEVICE_DRIVE_FIXED
,
776 LayoutArray
[DiskNumber
]->Signature
,
777 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
779 /* Mark the partition as assigned */
780 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
786 /* Assign extended (logical) partitions without an arc-name */
787 DPRINT("Assigning extended (logical) partitions:\n");
788 for (DiskNumber
= 0; DiskNumber
< ConfigInfo
->DiskCount
; DiskNumber
++)
790 if (LayoutArray
[DiskNumber
])
792 /* Search for extended partitions */
793 for (j
= NUM_PARTITION_TABLE_ENTRIES
; j
< LayoutArray
[DiskNumber
]->PartitionCount
; j
++)
795 if (IsRecognizedPartition(LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionType
) &&
796 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
== FALSE
&&
797 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
!= 0)
800 L
"\\Device\\Harddisk%d\\Partition%d",
802 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].PartitionNumber
);
803 RtlInitUnicodeString(&UnicodeString2
,
809 HalpAssignDrive(&UnicodeString2
,
811 DOSDEVICE_DRIVE_FIXED
,
812 LayoutArray
[DiskNumber
]->Signature
,
813 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].StartingOffset
,
815 /* Mark the partition as assigned */
816 LayoutArray
[DiskNumber
]->PartitionEntry
[j
].RewritePartition
= TRUE
;
822 /* Assign removable disk drives */
823 DPRINT("Assigning removable disk drives:\n");
824 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
828 /* Search for virtual partitions */
829 if (LayoutArray
[i
]->PartitionCount
== 1 &&
830 LayoutArray
[i
]->PartitionEntry
[0].PartitionType
== 0)
833 L
"\\Device\\Harddisk%d\\Partition1",
835 RtlInitUnicodeString(&UnicodeString2
,
841 HalpAssignDrive(&UnicodeString2
,
843 DOSDEVICE_DRIVE_REMOVABLE
,
845 RtlConvertLongToLargeInteger(0),
851 /* Free layout array */
852 for (i
= 0; i
< ConfigInfo
->DiskCount
; i
++)
854 if (LayoutArray
[i
] != NULL
)
855 ExFreePool(LayoutArray
[i
]);
857 ExFreePool(LayoutArray
);
859 /* Assign floppy drives */
860 DPRINT("Floppy drives: %d\n", ConfigInfo
->FloppyCount
);
861 for (i
= 0; i
< ConfigInfo
->FloppyCount
; i
++)
864 L
"\\Device\\Floppy%d",
866 RtlInitUnicodeString(&UnicodeString1
,
869 /* Assign drive letters A: or B: or first free drive letter */
872 HalpAssignDrive(&UnicodeString1
,
873 (i
< 2) ? i
: AUTO_DRIVE
,
874 DOSDEVICE_DRIVE_REMOVABLE
,
876 RtlConvertLongToLargeInteger(0),
880 /* Assign cdrom drives */
881 DPRINT("CD-Rom drives: %d\n", ConfigInfo
->CdRomCount
);
882 for (i
= 0; i
< ConfigInfo
->CdRomCount
; i
++)
885 L
"\\Device\\CdRom%d",
887 RtlInitUnicodeString(&UnicodeString1
,
890 /* Assign first free drive letter */
891 DPRINT(" %wZ\n", &UnicodeString1
);
892 HalpAssignDrive(&UnicodeString1
,
894 DOSDEVICE_DRIVE_CDROM
,
896 RtlConvertLongToLargeInteger(0),
900 /* Anything else to do? */
902 ExFreePool(PartialInformation
);
913 /* PRIVATE FUNCTIONS *********************************************************/
917 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject
,
918 IN PDISK_GEOMETRY Geometry
,
919 OUT PULONGLONG RealSectorCount
)
922 IO_STATUS_BLOCK IoStatusBlock
;
925 PARTITION_INFORMATION PartitionInfo
;
928 /* Allocate a non-paged event */
929 Event
= ExAllocatePoolWithTag(NonPagedPool
,
932 if (!Event
) return STATUS_INSUFFICIENT_RESOURCES
;
935 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
938 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
943 sizeof(DISK_GEOMETRY
),
949 /* Fail, free the event */
951 return STATUS_INSUFFICIENT_RESOURCES
;
954 /* Call the driver and check if it's pending */
955 Status
= IoCallDriver(DeviceObject
, Irp
);
956 if (Status
== STATUS_PENDING
)
958 /* Wait on the driver */
959 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
960 Status
= IoStatusBlock
.Status
;
963 /* Check if the driver returned success */
964 if(NT_SUCCESS(Status
))
966 /* Build another IRP */
967 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO
,
972 sizeof(PARTITION_INFORMATION
),
978 /* Fail, free the event */
980 return STATUS_INSUFFICIENT_RESOURCES
;
983 /* Call the driver and check if it's pending */
984 Status
= IoCallDriver(DeviceObject
, Irp
);
985 if (Status
== STATUS_PENDING
)
987 /* Wait on the driver */
988 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
989 Status
= IoStatusBlock
.Status
;
992 /* Check if the driver returned success */
993 if(NT_SUCCESS(Status
))
995 /* Get the number of sectors */
996 *RealSectorCount
= (PartitionInfo
.PartitionLength
.QuadPart
/
997 Geometry
->BytesPerSector
);
1001 /* Free the event and return the Status */
1008 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry
,
1009 IN ULONGLONG MaxOffset
,
1010 IN ULONGLONG MaxSector
)
1012 ULONGLONG EndingSector
;
1015 /* Unused partitions are considered valid */
1016 if (Entry
->PartitionType
== PARTITION_ENTRY_UNUSED
) return TRUE
;
1018 /* Get the last sector of the partition */
1019 EndingSector
= GET_STARTING_SECTOR(Entry
) + GET_PARTITION_LENGTH(Entry
);
1021 /* Check if it's more then the maximum sector */
1022 if (EndingSector
> MaxSector
)
1024 /* Invalid partition */
1025 DPRINT1("FSTUB: entry is invalid\n");
1026 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry
));
1027 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry
));
1028 DPRINT1("FSTUB: end %#I64x\n", EndingSector
);
1029 DPRINT1("FSTUB: max %#I64x\n", MaxSector
);
1032 else if(GET_STARTING_SECTOR(Entry
) > MaxOffset
)
1034 /* Invalid partition */
1035 DPRINT1("FSTUB: entry is invalid\n");
1036 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry
));
1037 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry
));
1038 DPRINT1("FSTUB: end %#I64x\n", EndingSector
);
1039 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset
);
1043 /* It's fine, return success */
1049 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset
,
1050 IN PLARGE_INTEGER PartitionLength
,
1051 IN CCHAR ShiftCount
,
1052 IN ULONG SectorsPerTrack
,
1053 IN ULONG NumberOfTracks
,
1054 IN ULONG ConventionalCylinders
,
1055 OUT PPARTITION_DESCRIPTOR PartitionDescriptor
)
1057 LARGE_INTEGER FirstSector
, SectorCount
;
1058 ULONG LastSector
, Remainder
, SectorsPerCylinder
;
1059 ULONG StartingCylinder
, EndingCylinder
;
1060 ULONG StartingTrack
, EndingTrack
;
1061 ULONG StartingSector
, EndingSector
;
1064 /* Calculate the number of sectors for each cylinder */
1065 SectorsPerCylinder
= SectorsPerTrack
* NumberOfTracks
;
1067 /* Calculate the first sector, and the sector count */
1068 FirstSector
.QuadPart
= PartitionOffset
->QuadPart
>> ShiftCount
;
1069 SectorCount
.QuadPart
= PartitionLength
->QuadPart
>> ShiftCount
;
1071 /* Now calculate the last sector */
1072 LastSector
= FirstSector
.LowPart
+ SectorCount
.LowPart
- 1;
1074 /* Calculate the first and last cylinders */
1075 StartingCylinder
= FirstSector
.LowPart
/ SectorsPerCylinder
;
1076 EndingCylinder
= LastSector
/ SectorsPerCylinder
;
1078 /* Set the default number of cylinders */
1079 if (!ConventionalCylinders
) ConventionalCylinders
= 1024;
1081 /* Normalize the values */
1082 if (StartingCylinder
>= ConventionalCylinders
)
1084 /* Set the maximum to 1023 */
1085 StartingCylinder
= ConventionalCylinders
- 1;
1087 if (EndingCylinder
>= ConventionalCylinders
)
1089 /* Set the maximum to 1023 */
1090 EndingCylinder
= ConventionalCylinders
- 1;
1093 /* Calculate the starting head and sector that still remain */
1094 Remainder
= FirstSector
.LowPart
% SectorsPerCylinder
;
1095 StartingTrack
= Remainder
/ SectorsPerTrack
;
1096 StartingSector
= Remainder
% SectorsPerTrack
;
1098 /* Calculate the ending head and sector that still remain */
1099 Remainder
= LastSector
% SectorsPerCylinder
;
1100 EndingTrack
= Remainder
/ SectorsPerTrack
;
1101 EndingSector
= Remainder
% SectorsPerTrack
;
1103 /* Set cylinder data for the MSB */
1104 PartitionDescriptor
->StartingCylinderMsb
= (UCHAR
)StartingCylinder
;
1105 PartitionDescriptor
->EndingCylinderMsb
= (UCHAR
)EndingCylinder
;
1107 /* Set the track data */
1108 PartitionDescriptor
->StartingTrack
= (UCHAR
)StartingTrack
;
1109 PartitionDescriptor
->EndingTrack
= (UCHAR
)EndingTrack
;
1111 /* Update cylinder data for the LSB */
1112 StartingCylinder
= ((StartingSector
+ 1) & 0x3F) |
1113 ((StartingCylinder
>> 2) & 0xC0);
1114 EndingCylinder
= ((EndingSector
+ 1) & 0x3F) |
1115 ((EndingCylinder
>> 2) & 0xC0);
1117 /* Set the cylinder data for the LSB */
1118 PartitionDescriptor
->StartingCylinderLsb
= (UCHAR
)StartingCylinder
;
1119 PartitionDescriptor
->EndingCylinderLsb
= (UCHAR
)EndingCylinder
;
1124 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject
,
1125 IN PULONG ConventionalCylinders
,
1126 IN PLONGLONG DiskSize
)
1128 PDISK_GEOMETRY DiskGeometry
= NULL
;
1129 PIO_STATUS_BLOCK IoStatusBlock
= NULL
;
1130 PKEVENT Event
= NULL
;
1135 *ConventionalCylinders
= 0;
1138 /* Allocate the structure in nonpaged pool */
1139 DiskGeometry
= ExAllocatePoolWithTag(NonPagedPool
,
1140 sizeof(DISK_GEOMETRY
),
1142 if (!DiskGeometry
) goto Cleanup
;
1144 /* Allocate the status block in nonpaged pool */
1145 IoStatusBlock
= ExAllocatePoolWithTag(NonPagedPool
,
1146 sizeof(IO_STATUS_BLOCK
),
1148 if (!IoStatusBlock
) goto Cleanup
;
1150 /* Allocate the event in nonpaged pool too */
1151 Event
= ExAllocatePoolWithTag(NonPagedPool
,
1154 if (!Event
) goto Cleanup
;
1156 /* Initialize the event */
1157 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
1160 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY
,
1165 sizeof(DISK_GEOMETRY
),
1169 if (!Irp
) goto Cleanup
;
1171 /* Now call the driver */
1172 Status
= IoCallDriver(DeviceObject
, Irp
);
1173 if (Status
== STATUS_PENDING
)
1175 /* Wait for it to complete */
1176 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
1177 Status
= IoStatusBlock
->Status
;
1180 /* Check driver status */
1181 if (NT_SUCCESS(Status
))
1183 /* Return the cylinder count */
1184 *ConventionalCylinders
= DiskGeometry
->Cylinders
.LowPart
;
1186 /* Make sure it's not larger then 1024 */
1187 if (DiskGeometry
->Cylinders
.LowPart
>= 1024)
1189 /* Otherwise, normalize the value */
1190 *ConventionalCylinders
= 1024;
1193 /* Calculate the disk size */
1194 *DiskSize
= DiskGeometry
->Cylinders
.QuadPart
*
1195 DiskGeometry
->TracksPerCylinder
*
1196 DiskGeometry
->SectorsPerTrack
*
1197 DiskGeometry
->BytesPerSector
;
1201 /* Free all the pointers */
1202 if (Event
) ExFreePool(Event
);
1203 if (IoStatusBlock
) ExFreePool(IoStatusBlock
);
1204 if (DiskGeometry
) ExFreePool(DiskGeometry
);
1208 /* PUBLIC FUNCTIONS **********************************************************/
1215 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject
,
1216 IN ULONG SectorSize
,
1217 IN ULONG MbrTypeIdentifier
,
1218 OUT PVOID
*MbrBuffer
)
1220 LARGE_INTEGER Offset
;
1224 IO_STATUS_BLOCK IoStatusBlock
;
1226 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1228 PIO_STACK_LOCATION IoStackLocation
;
1229 Offset
.QuadPart
= 0;
1231 /* Assume failure */
1234 /* Normalize the buffer size */
1235 BufferSize
= max(SectorSize
, 512);
1237 /* Allocate the buffer */
1238 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
1239 PAGE_SIZE
> BufferSize
?
1240 PAGE_SIZE
: BufferSize
,
1242 if (!Buffer
) return;
1244 /* Initialize the Event */
1245 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1248 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1262 /* Make sure to override volume verification */
1263 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1264 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1266 /* Call the driver */
1267 Status
= IoCallDriver(DeviceObject
, Irp
);
1268 if (Status
== STATUS_PENDING
)
1270 /* Wait for completion */
1271 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1272 Status
= IoStatusBlock
.Status
;
1275 /* Check driver Status */
1276 if (NT_SUCCESS(Status
))
1278 /* Validate the MBR Signature */
1279 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1286 /* Get the partition entry */
1287 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1288 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1290 /* Make sure it's what the caller wanted */
1291 if (PartitionDescriptor
->PartitionType
!= MbrTypeIdentifier
)
1293 /* It's not, free our buffer */
1298 /* Check if this is a secondary entry */
1299 if (PartitionDescriptor
->PartitionType
== 0x54)
1301 /* Return our buffer, but at sector 63 */
1302 *(PULONG
)Buffer
= 63;
1303 *MbrBuffer
= Buffer
;
1305 else if (PartitionDescriptor
->PartitionType
== 0x55)
1307 /* EZ Drive, return the buffer directly */
1308 *MbrBuffer
= Buffer
;
1312 /* Otherwise crash on debug builds */
1313 ASSERT(PartitionDescriptor
->PartitionType
== 0x55);
1324 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
1325 IN ULONG SectorSize
,
1326 IN BOOLEAN ReturnRecognizedPartitions
,
1327 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
1330 IO_STATUS_BLOCK IoStatusBlock
;
1332 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1335 PPARTITION_INFORMATION PartitionInfo
;
1336 PUCHAR Buffer
= NULL
;
1337 ULONG BufferSize
= 2048, InputSize
;
1338 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo
= NULL
;
1339 LONG j
= -1, i
= -1, k
;
1340 DISK_GEOMETRY DiskGeometry
;
1341 LONGLONG EndSector
, MaxSector
, StartOffset
;
1342 ULONGLONG MaxOffset
;
1343 LARGE_INTEGER Offset
, VolumeOffset
;
1344 BOOLEAN IsPrimary
= TRUE
, IsEzDrive
= FALSE
, MbrFound
= FALSE
;
1345 BOOLEAN IsValid
, IsEmpty
= TRUE
;
1347 PIO_STACK_LOCATION IoStackLocation
;
1348 PBOOT_SECTOR_INFO BootSectorInfo
= (PBOOT_SECTOR_INFO
)Buffer
;
1349 UCHAR PartitionType
;
1350 LARGE_INTEGER HiddenSectors64
;
1351 VolumeOffset
.QuadPart
= Offset
.QuadPart
= 0;
1354 /* Allocate the buffer */
1355 *PartitionBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1358 if (!(*PartitionBuffer
)) return STATUS_INSUFFICIENT_RESOURCES
;
1360 /* Normalize the buffer size */
1361 InputSize
= max(512, SectorSize
);
1363 /* Check for EZ Drive */
1364 HalExamineMBR(DeviceObject
, InputSize
, 0x55, &MbrBuffer
);
1367 /* EZ Drive found, bias the offset */
1369 ExFreePool(MbrBuffer
);
1370 Offset
.QuadPart
= 512;
1373 /* Get drive geometry */
1374 Status
= HalpGetFullGeometry(DeviceObject
, &DiskGeometry
, &MaxOffset
);
1375 if (!NT_SUCCESS(Status
))
1377 ExFreePool(*PartitionBuffer
);
1378 *PartitionBuffer
= NULL
;
1382 /* Get the end and maximum sector */
1383 EndSector
= MaxOffset
;
1384 MaxSector
= MaxOffset
<< 1;
1385 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
1386 MaxOffset
, MaxSector
);
1388 /* Allocate our buffer */
1389 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
1392 /* Fail, free the input buffer */
1393 ExFreePool(*PartitionBuffer
);
1394 return STATUS_INSUFFICIENT_RESOURCES
;
1397 /* Start partition loop */
1400 /* Assume the partition is valid */
1403 /* Initialize the event */
1404 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1406 /* Clear the buffer and build the IRP */
1407 RtlZeroMemory(Buffer
, InputSize
);
1408 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1418 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1422 /* Make sure to disable volume verification */
1423 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1424 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1426 /* Call the driver */
1427 Status
= IoCallDriver(DeviceObject
, Irp
);
1428 if (Status
== STATUS_PENDING
)
1430 /* Wait for completion */
1431 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1432 Status
= IoStatusBlock
.Status
;
1435 /* Normalize status code and check for failure */
1436 if (Status
== STATUS_NO_DATA_DETECTED
) Status
= STATUS_SUCCESS
;
1437 if (!NT_SUCCESS(Status
)) break;
1439 /* If we biased for EZ-Drive, unbias now */
1440 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
1442 /* Make sure this is a valid MBR */
1443 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1445 /* It's not, fail */
1446 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1447 "partition table %d\n", j
+ 1);
1451 /* At this point we have a valid MBR */
1454 /* Check if we weren't given an offset */
1455 if (!Offset
.QuadPart
)
1457 /* Then read the signature off the disk */
1458 (*PartitionBuffer
)->Signature
= ((PULONG
)Buffer
)
1459 [PARTITION_TABLE_OFFSET
/ 2 - 1];
1462 /* Get the partition descriptor array */
1463 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1464 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1466 /* Get the partition type */
1467 PartitionType
= PartitionDescriptor
->PartitionType
;
1469 /* Start looping partitions */
1471 DPRINT("FSTUB: Partition Table %d:\n", j
);
1472 for (Entry
= 1, k
= 0; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1474 /* Get the partition type */
1475 PartitionType
= PartitionDescriptor
->PartitionType
;
1477 /* Print debug messages */
1478 DPRINT("Partition Entry %d,%d: type %#x %s\n",
1482 (PartitionDescriptor
->ActiveFlag
) ? "Active" : "");
1483 DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
1484 GET_STARTING_SECTOR(PartitionDescriptor
),
1485 GET_PARTITION_LENGTH(PartitionDescriptor
));
1487 /* Make sure that the partition is valid, unless it's the first */
1488 if (!(HalpIsValidPartitionEntry(PartitionDescriptor
,
1490 MaxSector
)) && !(j
))
1492 /* It's invalid, so fail */
1497 /* Check if it's a container */
1498 if (IsContainerPartition(PartitionType
))
1500 /* Increase the count of containers */
1503 /* More then one table is invalid */
1504 DPRINT1("FSTUB: Multiple container partitions found in "
1505 "partition table %d\n - table is invalid\n",
1512 /* Check if the partition is supposedly empty */
1515 /* But check if it actually has a start and/or length */
1516 if ((GET_STARTING_SECTOR(PartitionDescriptor
)) ||
1517 (GET_PARTITION_LENGTH(PartitionDescriptor
)))
1519 /* So then it's not really empty */
1524 /* Check if the caller wanted only recognized partitions */
1525 if (ReturnRecognizedPartitions
)
1527 /* Then check if this one is unused, or a container */
1528 if ((PartitionType
== PARTITION_ENTRY_UNUSED
) ||
1529 IsContainerPartition(PartitionType
))
1531 /* Skip it, since the caller doesn't want it */
1536 /* Increase the structure count and check if they can fit */
1537 if ((sizeof(DRIVE_LAYOUT_INFORMATION
) +
1538 (++i
* sizeof(PARTITION_INFORMATION
))) >
1541 /* Allocate a new buffer that's twice as big */
1542 DriveLayoutInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1545 if (!DriveLayoutInfo
)
1547 /* Out of memory, unto this extra structure */
1549 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1553 /* Copy the contents of the old buffer */
1554 RtlMoveMemory(DriveLayoutInfo
,
1558 /* Free the old buffer and set this one as the new one */
1559 ExFreePool(*PartitionBuffer
);
1560 *PartitionBuffer
= DriveLayoutInfo
;
1562 /* Double the size */
1566 /* Now get the current structure being filled and initialize it */
1567 PartitionInfo
= &(*PartitionBuffer
)->PartitionEntry
[i
];
1568 PartitionInfo
->PartitionType
= PartitionType
;
1569 PartitionInfo
->RewritePartition
= FALSE
;
1571 /* Check if we're dealing with a partition that's in use */
1572 if (PartitionType
!= PARTITION_ENTRY_UNUSED
)
1574 /* Check if it's bootable */
1575 PartitionInfo
->BootIndicator
= PartitionDescriptor
->
1579 /* Check if its' a container */
1580 if (IsContainerPartition(PartitionType
))
1582 /* Then don't recognize it and use the volume offset */
1583 PartitionInfo
->RecognizedPartition
= FALSE
;
1584 StartOffset
= VolumeOffset
.QuadPart
;
1588 /* Then recognize it and use the partition offset */
1589 PartitionInfo
->RecognizedPartition
= TRUE
;
1590 StartOffset
= Offset
.QuadPart
;
1593 /* Get the starting offset */
1594 PartitionInfo
->StartingOffset
.QuadPart
=
1596 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor
),
1599 /* Calculate the number of hidden sectors */
1600 HiddenSectors64
.QuadPart
= (PartitionInfo
->
1601 StartingOffset
.QuadPart
-
1604 PartitionInfo
->HiddenSectors
= HiddenSectors64
.LowPart
;
1606 /* Get the partition length */
1607 PartitionInfo
->PartitionLength
.QuadPart
=
1608 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor
),
1611 /* FIXME: REACTOS HACK */
1612 PartitionInfo
->PartitionNumber
= i
+ 1;
1616 /* Otherwise, clear all the relevant fields */
1617 PartitionInfo
->BootIndicator
= FALSE
;
1618 PartitionInfo
->RecognizedPartition
= FALSE
;
1619 PartitionInfo
->StartingOffset
.QuadPart
= 0;
1620 PartitionInfo
->PartitionLength
.QuadPart
= 0;
1621 PartitionInfo
->HiddenSectors
= 0;
1623 /* FIXME: REACTOS HACK */
1624 PartitionInfo
->PartitionNumber
= 0;
1628 /* Finish debug log, and check for failure */
1630 if (!NT_SUCCESS(Status
)) break;
1632 /* Also check if we hit an invalid entry here */
1635 /* We did, so break out of the loop minus one entry */
1640 /* Reset the offset */
1641 Offset
.QuadPart
= 0;
1643 /* Go back to the descriptor array and loop it */
1644 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1645 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1646 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1648 /* Check if this is a container partition, since we skipped them */
1649 if (IsContainerPartition(PartitionType
))
1651 /* Get its offset */
1652 Offset
.QuadPart
= VolumeOffset
.QuadPart
+
1654 GET_STARTING_SECTOR(PartitionDescriptor
),
1657 /* If this is a primary partition, this is the volume offset */
1658 if (IsPrimary
) VolumeOffset
= Offset
;
1660 /* Also update the maximum sector */
1661 MaxSector
= GET_PARTITION_LENGTH(PartitionDescriptor
);
1662 DPRINT1("FSTUB: MaxSector now = %#08lx\n", MaxSector
);
1667 /* Loop the next partitions, which are not primary anymore */
1669 } while (Offset
.HighPart
| Offset
.LowPart
);
1671 /* Check if this is a removable device that's probably a super-floppy */
1672 if ((DiskGeometry
.MediaType
== RemovableMedia
) &&
1677 /* Read the jump bytes to detect super-floppy */
1678 if ((BootSectorInfo
->JumpByte
[0] == 0xeb) ||
1679 (BootSectorInfo
->JumpByte
[0] == 0xe9))
1681 /* Super floppes don't have typical MBRs, so skip them */
1682 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
1683 "table - disk is a super floppy and has no valid MBR\n",
1684 BootSectorInfo
->JumpByte
);
1689 /* Check if we're still at partition -1 */
1692 /* The likely cause is the super floppy detection above */
1693 if ((MbrFound
) || (DiskGeometry
.MediaType
== RemovableMedia
))
1695 /* Print out debugging information */
1696 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
1699 DPRINT1("FSTUB: Drive has %#08lx sectors and is %#016I64x "
1701 EndSector
, EndSector
* DiskGeometry
.BytesPerSector
);
1703 /* We should at least have some sectors */
1706 /* Get the entry we'll use */
1707 PartitionInfo
= &(*PartitionBuffer
)->PartitionEntry
[0];
1709 /* Fill it out with data for a super-floppy */
1710 PartitionInfo
->RewritePartition
= FALSE
;
1711 PartitionInfo
->RecognizedPartition
= TRUE
;
1712 PartitionInfo
->PartitionType
= PARTITION_FAT_16
;
1713 PartitionInfo
->BootIndicator
= FALSE
;
1714 PartitionInfo
->HiddenSectors
= 0;
1715 PartitionInfo
->StartingOffset
.QuadPart
= 0;
1716 PartitionInfo
->PartitionLength
.QuadPart
= (EndSector
*
1720 /* FIXME: REACTOS HACK */
1721 PartitionInfo
->PartitionNumber
= 0;
1723 /* Set the signature and set the count back to 0 */
1724 (*PartitionBuffer
)->Signature
= 1;
1730 /* Otherwise, this isn't a super floppy, so set an invalid count */
1735 /* Set the partition count */
1736 (*PartitionBuffer
)->PartitionCount
= ++i
;
1738 /* If we have no count, delete the signature */
1739 if (!i
) (*PartitionBuffer
)->Signature
= 0;
1741 /* Free the buffer and check for success */
1742 if (Buffer
) ExFreePool(Buffer
);
1743 if (!NT_SUCCESS(Status
)) ExFreePool(*PartitionBuffer
);
1754 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
1755 IN ULONG SectorSize
,
1756 IN ULONG PartitionNumber
,
1757 IN ULONG PartitionType
)
1761 IO_STATUS_BLOCK IoStatusBlock
;
1763 LARGE_INTEGER Offset
, VolumeOffset
;
1764 PUCHAR Buffer
= NULL
;
1768 PPARTITION_DESCRIPTOR PartitionDescriptor
;
1769 BOOLEAN IsPrimary
= TRUE
, IsEzDrive
= FALSE
;
1771 PIO_STACK_LOCATION IoStackLocation
;
1772 VolumeOffset
.QuadPart
= Offset
.QuadPart
= 0;
1775 /* Normalize the buffer size */
1776 BufferSize
= max(512, SectorSize
);
1778 /* Check for EZ Drive */
1779 HalExamineMBR(DeviceObject
, BufferSize
, 0x55, &MbrBuffer
);
1782 /* EZ Drive found, bias the offset */
1784 ExFreePool(MbrBuffer
);
1785 Offset
.QuadPart
= 512;
1788 /* Allocate our partition buffer */
1789 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
1790 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1792 /* Initialize the event we'll use and loop partitions */
1793 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1796 /* Reset the event since we reuse it */
1797 KeResetEvent(&Event
);
1799 /* Build the read IRP */
1800 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
1810 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1814 /* Make sure to disable volume verification */
1815 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1816 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1818 /* Call the driver */
1819 Status
= IoCallDriver(DeviceObject
, Irp
);
1820 if (Status
== STATUS_PENDING
)
1822 /* Wait for completion */
1823 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1824 Status
= IoStatusBlock
.Status
;
1827 /* Check for failure */
1828 if (!NT_SUCCESS(Status
)) break;
1830 /* If we biased for EZ-Drive, unbias now */
1831 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
1833 /* Make sure this is a valid MBR */
1834 if (((PUSHORT
)Buffer
)[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
1836 /* It's not, fail */
1837 Status
= STATUS_BAD_MASTER_BOOT_RECORD
;
1841 /* Get the partition descriptors and loop them */
1842 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1843 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1844 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1846 /* Check if it's unused or a container partition */
1847 if ((PartitionDescriptor
->PartitionType
==
1848 PARTITION_ENTRY_UNUSED
) ||
1849 (IsContainerPartition(PartitionDescriptor
->PartitionType
)))
1851 /* Go to the next one */
1855 /* It's a valid partition, so increase the partition count */
1856 if (++i
== PartitionNumber
)
1858 /* We found a match, set the type */
1859 PartitionDescriptor
->PartitionType
= (UCHAR
)PartitionType
;
1861 /* Reset the reusable event */
1862 KeResetEvent(&Event
);
1864 /* Build the write IRP */
1865 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
1875 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1879 /* Disable volume verification */
1880 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
1881 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
1883 /* Call the driver */
1884 Status
= IoCallDriver(DeviceObject
, Irp
);
1885 if (Status
== STATUS_PENDING
)
1887 /* Wait for completion */
1888 KeWaitForSingleObject(&Event
,
1893 Status
= IoStatusBlock
.Status
;
1896 /* We're done, break out of the loop */
1901 /* If we looped all the partitions, break out */
1902 if (Entry
<= NUM_PARTITION_TABLE_ENTRIES
) break;
1904 /* Nothing found yet, get the partition array again */
1905 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
1906 &(((PUSHORT
)Buffer
)[PARTITION_TABLE_OFFSET
]);
1907 for (Entry
= 1; Entry
<= 4; Entry
++, PartitionDescriptor
++)
1909 /* Check if this was a container partition (we skipped these) */
1910 if (IsContainerPartition(PartitionDescriptor
->PartitionType
))
1912 /* Update the partition offset */
1913 Offset
.QuadPart
= VolumeOffset
.QuadPart
+
1914 GET_STARTING_SECTOR(PartitionDescriptor
) *
1917 /* If this was the primary partition, update the volume too */
1918 if (IsPrimary
) VolumeOffset
= Offset
;
1923 /* Check if we already searched all the partitions */
1924 if (Entry
> NUM_PARTITION_TABLE_ENTRIES
)
1926 /* Then we failed to find a good MBR */
1927 Status
= STATUS_BAD_MASTER_BOOT_RECORD
;
1931 /* Loop the next partitions, which are not primary anymore */
1933 } while (i
< PartitionNumber
);
1935 /* Everything done, cleanup */
1936 if (Buffer
) ExFreePool(Buffer
);
1945 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
1946 IN ULONG SectorSize
,
1947 IN ULONG SectorsPerTrack
,
1948 IN ULONG NumberOfHeads
,
1949 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
1952 IO_STATUS_BLOCK IoStatusBlock
;
1954 NTSTATUS Status
= STATUS_SUCCESS
;
1958 PPARTITION_TABLE PartitionTable
;
1959 LARGE_INTEGER Offset
, NextOffset
, ExtendedOffset
, SectorOffset
;
1960 LARGE_INTEGER StartOffset
, PartitionLength
;
1963 BOOLEAN IsEzDrive
= FALSE
, IsSuperFloppy
= FALSE
, DoRewrite
= FALSE
, IsMbr
;
1964 ULONG ConventionalCylinders
;
1966 PDISK_LAYOUT DiskLayout
= (PDISK_LAYOUT
)PartitionBuffer
;
1968 UCHAR PartitionType
;
1969 PIO_STACK_LOCATION IoStackLocation
;
1970 PPARTITION_INFORMATION PartitionInfo
= PartitionBuffer
->PartitionEntry
;
1971 PPARTITION_INFORMATION TableEntry
;
1972 ExtendedOffset
.QuadPart
= NextOffset
.QuadPart
= Offset
.QuadPart
= 0;
1975 /* Normalize the buffer size */
1976 BufferSize
= max(512, SectorSize
);
1978 /* Get the partial drive geometry */
1979 xHalGetPartialGeometry(DeviceObject
, &ConventionalCylinders
, &DiskSize
);
1981 /* Check for EZ Drive */
1982 HalExamineMBR(DeviceObject
, BufferSize
, 0x55, &MbrBuffer
);
1985 /* EZ Drive found, bias the offset */
1987 ExFreePool(MbrBuffer
);
1988 Offset
.QuadPart
= 512;
1991 /* Get the number of bits to shift to multiply by the sector size */
1992 for (k
= 0; k
< 32; k
++) if ((SectorSize
>> k
) == 1) break;
1994 /* Check if there's only one partition */
1995 if (PartitionBuffer
->PartitionCount
== 1)
1997 /* Check if it has no starting offset or hidden sectors */
1998 if (!(PartitionInfo
->StartingOffset
.QuadPart
) &&
1999 !(PartitionInfo
->HiddenSectors
))
2001 /* Then it's a super floppy */
2002 IsSuperFloppy
= TRUE
;
2004 /* Which also means it must be non-bootable FAT-16 */
2005 if ((PartitionInfo
->PartitionNumber
) ||
2006 (PartitionInfo
->PartitionType
!= PARTITION_FAT_16
) ||
2007 (PartitionInfo
->BootIndicator
))
2009 /* It's not, so we fail */
2010 return STATUS_INVALID_PARAMETER
;
2013 /* Check if it needs a rewrite, and disable EZ drive for sure */
2014 if (PartitionInfo
->RewritePartition
) DoRewrite
= TRUE
;
2019 /* Count the number of partition tables */
2020 DiskLayout
->TableCount
= (PartitionBuffer
->PartitionCount
+ 4 - 1) / 4;
2022 /* Allocate our partition buffer */
2023 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_FILE_SYSTEM
);
2024 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
2026 /* Loop the entries */
2027 Entry
= (PPTE
)&Buffer
[PARTITION_TABLE_OFFSET
];
2028 for (i
= 0; i
< DiskLayout
->TableCount
; i
++)
2030 /* Set if this is the MBR partition */
2033 /* Initialize th event */
2034 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2036 /* Build the read IRP */
2037 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
2047 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2051 /* Make sure to disable volume verification */
2052 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2053 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2055 /* Call the driver */
2056 Status
= IoCallDriver(DeviceObject
, Irp
);
2057 if (Status
== STATUS_PENDING
)
2059 /* Wait for completion */
2060 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
2061 Status
= IoStatusBlock
.Status
;
2064 /* Check for failure */
2065 if (!NT_SUCCESS(Status
)) break;
2067 /* If we biased for EZ-Drive, unbias now */
2068 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2070 /* Check if this is a normal disk */
2073 /* Set the boot record signature */
2074 Buffer
[BOOT_SIGNATURE_OFFSET
] = BOOT_RECORD_SIGNATURE
;
2076 /* By default, don't require a rewrite */
2079 /* Check if we don't have an offset */
2080 if (!Offset
.QuadPart
)
2082 /* Check if the signature doesn't match */
2083 if (((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1] !=
2084 PartitionBuffer
->Signature
)
2086 /* Then write the signature and now w need a rewrite */
2087 ((PULONG
)Buffer
)[PARTITION_TABLE_OFFSET
/ 2 - 1] =
2088 PartitionBuffer
->Signature
;
2093 /* Loop the partition table entries */
2094 PartitionTable
= &DiskLayout
->PartitionTable
[i
];
2095 for (j
= 0; j
< 4; j
++)
2097 /* Get the current entry and type */
2098 TableEntry
= &PartitionTable
->PartitionEntry
[j
];
2099 PartitionType
= TableEntry
->PartitionType
;
2101 /* Check if the entry needs a rewrite */
2102 if (TableEntry
->RewritePartition
)
2104 /* Then we need one too */
2107 /* Save the type and if it's a bootable partition */
2108 Entry
[j
].PartitionType
= TableEntry
->PartitionType
;
2109 Entry
[j
].ActiveFlag
= TableEntry
->BootIndicator
? 0x80 : 0;
2111 /* Make sure it's used */
2112 if (PartitionType
!= PARTITION_ENTRY_UNUSED
)
2114 /* Make sure it's not a container (unless primary) */
2115 if ((IsMbr
) || !(IsContainerPartition(PartitionType
)))
2117 /* Use the partition offset */
2118 StartOffset
.QuadPart
= Offset
.QuadPart
;
2122 /* Use the extended logical partition offset */
2123 StartOffset
.QuadPart
= ExtendedOffset
.QuadPart
;
2126 /* Set the sector offset */
2127 SectorOffset
.QuadPart
= TableEntry
->
2128 StartingOffset
.QuadPart
-
2129 StartOffset
.QuadPart
;
2131 /* Now calculate the starting sector */
2132 StartOffset
.QuadPart
= SectorOffset
.QuadPart
>> k
;
2133 Entry
[j
].StartingSector
= StartOffset
.LowPart
;
2135 /* As well as the length */
2136 PartitionLength
.QuadPart
= TableEntry
->PartitionLength
.
2138 Entry
[j
].PartitionLength
= PartitionLength
.LowPart
;
2140 /* Calculate the CHS values */
2141 HalpCalculateChsValues(&TableEntry
->StartingOffset
,
2142 &TableEntry
->PartitionLength
,
2146 ConventionalCylinders
,
2147 (PPARTITION_DESCRIPTOR
)
2152 /* Otherwise set up an empty entry */
2153 Entry
[j
].StartingSector
= 0;
2154 Entry
[j
].PartitionLength
= 0;
2155 Entry
[j
].StartingTrack
= 0;
2156 Entry
[j
].EndingTrack
= 0;
2157 Entry
[j
].StartingCylinder
= 0;
2158 Entry
[j
].EndingCylinder
= 0;
2162 /* Check if this is a container partition */
2163 if (IsContainerPartition(PartitionType
))
2165 /* Then update the offset to use */
2166 NextOffset
= TableEntry
->StartingOffset
;
2171 /* Check if we need to write back the buffer */
2174 /* We don't need to do this again */
2177 /* Initialize the event */
2178 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2180 /* If we unbiased for EZ-Drive, rebias now */
2181 if ((IsEzDrive
) && !(Offset
.QuadPart
)) Offset
.QuadPart
= 512;
2183 /* Build the write IRP */
2184 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
2194 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2198 /* Make sure to disable volume verification */
2199 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
2200 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2202 /* Call the driver */
2203 Status
= IoCallDriver(DeviceObject
, Irp
);
2204 if (Status
== STATUS_PENDING
)
2206 /* Wait for completion */
2207 KeWaitForSingleObject(&Event
,
2212 Status
= IoStatusBlock
.Status
;
2215 /* Check for failure */
2216 if (!NT_SUCCESS(Status
)) break;
2218 /* If we biased for EZ-Drive, unbias now */
2219 if (IsEzDrive
&& (Offset
.QuadPart
== 512)) Offset
.QuadPart
= 0;
2222 /* Update the partition offset and set the extended offset if needed */
2223 Offset
= NextOffset
;
2224 if (IsMbr
) ExtendedOffset
= NextOffset
;
2227 /* If we had a buffer, free it, then return status */
2228 if (Buffer
) ExFreePool(Buffer
);
2237 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
2238 IN PSTRING NtDeviceName
,
2239 OUT PUCHAR NtSystemPath
,
2240 OUT PSTRING NtSystemPathString
)
2242 /* Call our deprecated function for now */
2243 xHalIoAssignDriveLetters(LoaderBlock
,
2246 NtSystemPathString
);