2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fstub/fstubex.c
5 * PURPOSE: Extended FSTUB Routines (not linked to HAL)
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
17 #define PARTITION_ENTRY_SIZE 128
18 #define TAG_FSTUB 'BtsF'
20 typedef struct _DISK_INFORMATION
22 PDEVICE_OBJECT DeviceObject
;
24 DISK_GEOMETRY_EX DiskGeometry
;
26 ULONGLONG SectorCount
;
27 } DISK_INFORMATION
, *PDISK_INFORMATION
;
29 /* Defines system type for MBR showing that a GPT is following */
30 #define EFI_PMBR_OSTYPE_EFI 0xEE
32 #define IS_VALID_DISK_INFO(Disk) \
34 (Disk->DeviceObject) && \
35 (Disk->SectorSize) && \
41 FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry
,
42 IN ULONG PartitionNumber
47 FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject
,
48 OUT PDISK_GEOMETRY_EX Geometry
53 FstubReadSector(IN PDEVICE_OBJECT DeviceObject
,
55 IN ULONGLONG StartingSector OPTIONAL
,
61 FstubAllocateDiskInformation(IN PDEVICE_OBJECT DeviceObject
,
62 OUT PDISK_INFORMATION
* DiskBuffer
,
63 PDISK_GEOMETRY_EX DiskGeometry OPTIONAL
)
66 PDISK_INFORMATION DiskInformation
;
72 /* Allocate internal structure */
73 DiskInformation
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DISK_INFORMATION
), TAG_FSTUB
);
76 return STATUS_INSUFFICIENT_RESOURCES
;
79 /* If caller don't pass needed information, let's get them */
82 Status
= FstubGetDiskGeometry(DeviceObject
, &(DiskInformation
->DiskGeometry
));
83 if (!NT_SUCCESS(Status
))
85 ExFreePoolWithTag(DiskInformation
, TAG_FSTUB
);
91 DiskInformation
->DiskGeometry
= *DiskGeometry
;
94 /* Ensure read/received information are correct */
95 if (DiskInformation
->DiskGeometry
.Geometry
.BytesPerSector
== 0 ||
96 DiskInformation
->DiskGeometry
.DiskSize
.QuadPart
== 0)
98 ExFreePoolWithTag(DiskInformation
, TAG_FSTUB
);
99 return STATUS_DEVICE_NOT_READY
;
102 /* Store vital information as well */
103 DiskInformation
->DeviceObject
= DeviceObject
;
104 DiskInformation
->SectorSize
= DiskInformation
->DiskGeometry
.Geometry
.BytesPerSector
;
105 DiskInformation
->SectorCount
= DiskInformation
->DiskGeometry
.DiskSize
.QuadPart
/ DiskInformation
->SectorSize
;
107 /* Finally, allocate the buffer that will be used for different read */
108 DiskInformation
->Buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
, DiskInformation
->SectorSize
, TAG_FSTUB
);
109 if (!DiskInformation
->Buffer
)
111 ExFreePoolWithTag(DiskInformation
, TAG_FSTUB
);
112 return STATUS_INSUFFICIENT_RESOURCES
;
115 /* Return allocated internal structure */
116 *DiskBuffer
= DiskInformation
;
118 return STATUS_SUCCESS
;
123 FstubDbgGuidToString(IN PGUID Guid
,
127 "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
145 FstubDbgPrintDriveLayoutEx(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
)
151 DPRINT1("FSTUB: DRIVE_LAYOUT_INFORMATION_EX: %p\n", DriveLayout
);
152 switch (DriveLayout
->PartitionStyle
)
154 case PARTITION_STYLE_MBR
:
155 if (DriveLayout
->PartitionCount
% 4 != 0)
157 DPRINT1("Warning: Partition count isn't a 4-factor: %ld!\n", DriveLayout
->PartitionCount
);
160 DPRINT1("Signature: %8.8x\n", DriveLayout
->Mbr
.Signature
);
161 for (i
= 0; i
< DriveLayout
->PartitionCount
; i
++)
163 FstubDbgPrintPartitionEx(DriveLayout
->PartitionEntry
, i
);
167 case PARTITION_STYLE_GPT
:
168 FstubDbgGuidToString(&(DriveLayout
->Gpt
.DiskId
), Guid
);
169 DPRINT1("DiskId: %s\n", Guid
);
170 DPRINT1("StartingUsableOffset: %I64x\n", DriveLayout
->Gpt
.StartingUsableOffset
.QuadPart
);
171 DPRINT1("UsableLength: %I64x\n", DriveLayout
->Gpt
.UsableLength
.QuadPart
);
172 DPRINT1("MaxPartitionCount: %ld\n", DriveLayout
->Gpt
.MaxPartitionCount
);
173 for (i
= 0; i
< DriveLayout
->PartitionCount
; i
++)
175 FstubDbgPrintPartitionEx(DriveLayout
->PartitionEntry
, i
);
180 DPRINT1("Unsupported partition style: %ld\n", DriveLayout
->PartitionStyle
);
186 FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry
,
187 IN ULONG PartitionNumber
)
192 DPRINT1("Printing partition %ld\n", PartitionNumber
);
194 switch (PartitionEntry
[PartitionNumber
].PartitionStyle
)
196 case PARTITION_STYLE_MBR
:
197 DPRINT1(" StartingOffset: %I64x\n", PartitionEntry
[PartitionNumber
].StartingOffset
.QuadPart
);
198 DPRINT1(" PartitionLength: %I64x\n", PartitionEntry
[PartitionNumber
].PartitionLength
.QuadPart
);
199 DPRINT1(" RewritePartition: %d\n", PartitionEntry
[PartitionNumber
].RewritePartition
);
200 DPRINT1(" PartitionType: %02x\n", PartitionEntry
[PartitionNumber
].Mbr
.PartitionType
);
201 DPRINT1(" BootIndicator: %d\n", PartitionEntry
[PartitionNumber
].Mbr
.BootIndicator
);
202 DPRINT1(" RecognizedPartition: %d\n", PartitionEntry
[PartitionNumber
].Mbr
.RecognizedPartition
);
203 DPRINT1(" HiddenSectors: %ld\n", PartitionEntry
[PartitionNumber
].Mbr
.HiddenSectors
);
206 case PARTITION_STYLE_GPT
:
207 DPRINT1(" StartingOffset: %I64x\n", PartitionEntry
[PartitionNumber
].StartingOffset
.QuadPart
);
208 DPRINT1(" PartitionLength: %I64x\n", PartitionEntry
[PartitionNumber
].PartitionLength
.QuadPart
);
209 DPRINT1(" RewritePartition: %d\n", PartitionEntry
[PartitionNumber
].RewritePartition
);
210 FstubDbgGuidToString(&(PartitionEntry
[PartitionNumber
].Gpt
.PartitionType
), Guid
);
211 DPRINT1(" PartitionType: %s\n", Guid
);
212 FstubDbgGuidToString(&(PartitionEntry
[PartitionNumber
].Gpt
.PartitionId
), Guid
);
213 DPRINT1(" PartitionId: %s\n", Guid
);
214 DPRINT1(" Attributes: %16x\n", PartitionEntry
[PartitionNumber
].Gpt
.Attributes
);
215 DPRINT1(" Name: %ws\n", PartitionEntry
[PartitionNumber
].Gpt
.Name
);
219 DPRINT1(" Unsupported partition style: %ld\n", PartitionEntry
[PartitionNumber
].PartitionStyle
);
225 FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk
,
226 IN PARTITION_STYLE
* PartitionStyle
)
229 PPARTITION_DESCRIPTOR PartitionDescriptor
;
232 ASSERT(IS_VALID_DISK_INFO(Disk
));
233 ASSERT(PartitionStyle
);
235 /* Read disk first sector */
236 Status
= FstubReadSector(Disk
->DeviceObject
,
240 if (!NT_SUCCESS(Status
))
245 /* Get the partition descriptor array */
246 PartitionDescriptor
= (PPARTITION_DESCRIPTOR
)
247 &(Disk
->Buffer
[PARTITION_TABLE_OFFSET
]);
248 /* If we have not the 0xAA55 then it's raw partition */
249 if (Disk
->Buffer
[BOOT_SIGNATURE_OFFSET
] != BOOT_RECORD_SIGNATURE
)
251 *PartitionStyle
= PARTITION_STYLE_RAW
;
253 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
254 else if (PartitionDescriptor
[0].PartitionType
== EFI_PMBR_OSTYPE_EFI
&&
255 PartitionDescriptor
[1].PartitionType
== 0 &&
256 PartitionDescriptor
[2].PartitionType
== 0 &&
257 PartitionDescriptor
[3].PartitionType
== 0)
259 *PartitionStyle
= PARTITION_STYLE_GPT
;
261 /* Otherwise, partition table is in MBR */
264 *PartitionStyle
= PARTITION_STYLE_MBR
;
267 return STATUS_SUCCESS
;
272 FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer
)
276 if (DiskBuffer
->Buffer
)
278 ExFreePoolWithTag(DiskBuffer
->Buffer
, TAG_FSTUB
);
280 ExFreePoolWithTag(DiskBuffer
, TAG_FSTUB
);
286 FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject
,
287 OUT PDISK_GEOMETRY_EX Geometry
)
291 PKEVENT Event
= NULL
;
292 PDISK_GEOMETRY_EX DiskGeometry
= NULL
;
293 PIO_STATUS_BLOCK IoStatusBlock
= NULL
;
296 ASSERT(DeviceObject
);
299 /* Allocate needed components */
300 DiskGeometry
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DISK_GEOMETRY_EX
), TAG_FSTUB
);
303 Status
= STATUS_INSUFFICIENT_RESOURCES
;
307 IoStatusBlock
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IO_STATUS_BLOCK
), TAG_FSTUB
);
310 Status
= STATUS_INSUFFICIENT_RESOURCES
;
314 Event
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KEVENT
), TAG_FSTUB
);
317 Status
= STATUS_INSUFFICIENT_RESOURCES
;
320 /* Initialize the waiting event */
321 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
323 /* Build the request to get disk geometry */
324 Irp
= IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
,
329 sizeof(DISK_GEOMETRY_EX
),
335 Status
= STATUS_INSUFFICIENT_RESOURCES
;
339 /* Call the driver and wait for completion if needed */
340 Status
= IoCallDriver(DeviceObject
, Irp
);
341 if (Status
== STATUS_PENDING
)
343 KeWaitForSingleObject(Event
, Executive
, KernelMode
, FALSE
, NULL
);
344 Status
= IoStatusBlock
->Status
;
347 /* In case of a success, return read data */
348 if (NT_SUCCESS(Status
))
350 *Geometry
= *DiskGeometry
;
356 ExFreePoolWithTag(DiskGeometry
, TAG_FSTUB
);
358 if (NT_SUCCESS(Status
))
360 ASSERT(Geometry
->Geometry
.BytesPerSector
% PARTITION_ENTRY_SIZE
== 0);
366 ExFreePoolWithTag(IoStatusBlock
, TAG_FSTUB
);
371 ExFreePoolWithTag(Event
, TAG_FSTUB
);
379 FstubReadPartitionTableEFI(IN PDISK_INFORMATION Disk
,
380 IN BOOLEAN ReadBackupTable
,
381 OUT
struct _DRIVE_LAYOUT_INFORMATION_EX
** DriveLayout
)
384 return STATUS_NOT_IMPLEMENTED
;
389 FstubReadPartitionTableMBR(IN PDISK_INFORMATION Disk
,
390 IN BOOLEAN ReturnRecognizedPartitions
,
391 OUT
struct _DRIVE_LAYOUT_INFORMATION_EX
** ReturnedDriveLayout
)
395 PDRIVE_LAYOUT_INFORMATION DriveLayout
= NULL
;
396 PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx
= NULL
;
399 ASSERT(IS_VALID_DISK_INFO(Disk
));
400 ASSERT(ReturnedDriveLayout
);
403 *ReturnedDriveLayout
= NULL
;
405 /* Read partition table the old way */
406 Status
= IoReadPartitionTable(Disk
->DeviceObject
,
408 ReturnRecognizedPartitions
,
410 if (!NT_SUCCESS(Status
))
415 /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */
416 DriveLayoutEx
= ExAllocatePoolWithTag(NonPagedPool
,
417 FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
) +
418 DriveLayout
->PartitionCount
* sizeof(PARTITION_INFORMATION_EX
),
422 /* Let's not leak memory as in Windows 2003 */
423 ExFreePool(DriveLayout
);
424 return STATUS_INSUFFICIENT_RESOURCES
;
427 /* Start converting the DRIVE_LAYOUT_INFORMATION structure */
428 DriveLayoutEx
->PartitionStyle
= PARTITION_STYLE_MBR
;
429 DriveLayoutEx
->PartitionCount
= DriveLayout
->PartitionCount
;
430 DriveLayoutEx
->Mbr
.Signature
= DriveLayout
->Signature
;
432 /* Convert each found partition */
433 for (i
= 0; i
< DriveLayout
->PartitionCount
; i
++)
435 DriveLayoutEx
->PartitionEntry
[i
].PartitionStyle
= PARTITION_STYLE_MBR
;
436 DriveLayoutEx
->PartitionEntry
[i
].StartingOffset
= DriveLayout
->PartitionEntry
[i
].StartingOffset
;
437 DriveLayoutEx
->PartitionEntry
[i
].PartitionLength
= DriveLayout
->PartitionEntry
[i
].PartitionLength
;
438 DriveLayoutEx
->PartitionEntry
[i
].PartitionNumber
= DriveLayout
->PartitionEntry
[i
].PartitionNumber
;
439 DriveLayoutEx
->PartitionEntry
[i
].RewritePartition
= DriveLayout
->PartitionEntry
[i
].RewritePartition
;
440 DriveLayoutEx
->PartitionEntry
[i
].Mbr
.PartitionType
= DriveLayout
->PartitionEntry
[i
].PartitionType
;
441 DriveLayoutEx
->PartitionEntry
[i
].Mbr
.BootIndicator
= DriveLayout
->PartitionEntry
[i
].BootIndicator
;
442 DriveLayoutEx
->PartitionEntry
[i
].Mbr
.RecognizedPartition
= DriveLayout
->PartitionEntry
[i
].RecognizedPartition
;
443 DriveLayoutEx
->PartitionEntry
[i
].Mbr
.HiddenSectors
= DriveLayout
->PartitionEntry
[i
].HiddenSectors
;
446 /* Finally, return data and free old structure */
447 *ReturnedDriveLayout
= DriveLayoutEx
;
448 ExFreePool(DriveLayout
);
450 return STATUS_SUCCESS
;
455 FstubReadSector(IN PDEVICE_OBJECT DeviceObject
,
457 IN ULONGLONG StartingSector OPTIONAL
,
463 LARGE_INTEGER StartingOffset
;
464 IO_STATUS_BLOCK IoStatusBlock
;
465 PIO_STACK_LOCATION IoStackLocation
;
468 ASSERT(DeviceObject
);
472 /* Compute starting offset */
473 StartingOffset
.QuadPart
= StartingSector
* SectorSize
;
475 /* Initialize waiting event */
476 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
479 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
488 return STATUS_INSUFFICIENT_RESOURCES
;
491 /* Override volume verify */
492 IoStackLocation
= IoGetNextIrpStackLocation(Irp
);
493 IoStackLocation
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
495 /* Then call driver, and wait for completion if needed */
496 Status
= IoCallDriver(DeviceObject
, Irp
);
497 if (Status
== STATUS_PENDING
)
499 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
500 Status
= IoStatusBlock
.Status
;
506 /* FUNCTIONS *****************************************************************/
513 IoCreateDisk(IN PDEVICE_OBJECT DeviceObject
,
514 IN
struct _CREATE_DISK
* Disk
)
517 return STATUS_NOT_IMPLEMENTED
;
525 IoGetBootDiskInformation(IN OUT PBOOTDISK_INFORMATION BootDiskInformation
,
529 return STATUS_NOT_IMPLEMENTED
;
537 IoReadDiskSignature(IN PDEVICE_OBJECT DeviceObject
,
538 IN ULONG BytesPerSector
,
539 OUT PDISK_SIGNATURE Signature
)
542 return STATUS_NOT_IMPLEMENTED
;
550 IoReadPartitionTableEx(IN PDEVICE_OBJECT DeviceObject
,
551 IN
struct _DRIVE_LAYOUT_INFORMATION_EX
** DriveLayout
)
554 PDISK_INFORMATION Disk
;
555 PARTITION_STYLE PartitionStyle
;
558 ASSERT(DeviceObject
);
561 /* First of all, allocate internal structure */
562 Status
= FstubAllocateDiskInformation(DeviceObject
, &Disk
, 0);
563 if (!NT_SUCCESS(Status
))
569 /* Then, detect partition style (MBR? GTP/EFI? RAW?) */
570 Status
= FstubDetectPartitionStyle(Disk
, &PartitionStyle
);
571 if (!NT_SUCCESS(Status
))
573 FstubFreeDiskInformation(Disk
);
577 /* Here partition table is really read, depending on its style */
578 switch (PartitionStyle
)
580 case PARTITION_STYLE_MBR
:
581 case PARTITION_STYLE_RAW
:
582 Status
= FstubReadPartitionTableMBR(Disk
, FALSE
, DriveLayout
);
585 case PARTITION_STYLE_GPT
:
586 /* Read primary table */
587 Status
= FstubReadPartitionTableEFI(Disk
, FALSE
, DriveLayout
);
588 /* If it failed, try reading backup table */
589 if (!NT_SUCCESS(Status
))
591 Status
= FstubReadPartitionTableEFI(Disk
, TRUE
, DriveLayout
);
596 DPRINT("Unknown partition type\n");
597 Status
= STATUS_UNSUCCESSFUL
;
600 /* It's over, internal structure not needed anymore */
601 FstubFreeDiskInformation(Disk
);
603 /* In case of success, print data */
604 if (NT_SUCCESS(Status
))
606 FstubDbgPrintDriveLayoutEx(*DriveLayout
);
617 IoSetPartitionInformationEx(IN PDEVICE_OBJECT DeviceObject
,
618 IN ULONG PartitionNumber
,
619 IN
struct _SET_PARTITION_INFORMATION_EX
* PartitionInfo
)
622 return STATUS_NOT_IMPLEMENTED
;
630 IoVerifyPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
631 IN BOOLEAN FixErrors
)
634 return STATUS_NOT_IMPLEMENTED
;
642 IoWritePartitionTableEx(IN PDEVICE_OBJECT DeviceObject
,
643 IN
struct _DRIVE_LAYOUT_INFORMATION_EX
* DriveLayfout
)
646 return STATUS_NOT_IMPLEMENTED
;