[NTOSKRNL]
authorPierre Schweitzer <pierre@reactos.org>
Tue, 12 Oct 2010 20:22:29 +0000 (20:22 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Tue, 12 Oct 2010 20:22:29 +0000 (20:22 +0000)
Implemented FstubAllocateDiskInformation(), FstubDbgGuidToString(), FstubDbgPrintDriveLayoutEx(), FstubDbgPrintPartitionEx(), FstubDetectPartitionStyle(), FstubFreeDiskInformation(), FstubGetDiskGeometry(), FstubReadPartitionTableMBR(), FstubReadSector()

Stubbed FstubReadPartitionTableEFI()

This leads to a correct & working implementation of IoReadPartitionTableEx(). As this state, it only handles MBR partition tables as EFI/GPT as been stubbed out.

EFI/GPT support will come later.

svn path=/trunk/; revision=49130

reactos/ntoskrnl/fstub/fstubex.c

index bd41993..d04c299 100644 (file)
@@ -3,7 +3,7 @@
 * LICENSE:         GPL - See COPYING in the top level directory
 * FILE:            ntoskrnl/fstub/fstubex.c
 * PURPOSE:         Extended FSTUB Routines (not linked to HAL)
-* PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+* PROGRAMMERS:     Pierre Schweitzer (pierre.schweitzer@reactos.org)
 */
 
 /* INCLUDES ******************************************************************/
 #define NDEBUG
 #include <debug.h>
 
+/* PRIVATE FUNCTIONS *********************************************************/
+
+#define PARTITION_ENTRY_SIZE 128
+#define TAG_FSTUB 'BtsF'
+
+typedef struct _DISK_INFORMATION
+{
+    PDEVICE_OBJECT DeviceObject;
+    ULONG SectorSize;
+    DISK_GEOMETRY_EX DiskGeometry;
+    PUSHORT Buffer;
+    ULONGLONG SectorCount;
+} DISK_INFORMATION, *PDISK_INFORMATION;
+
+/* Defines system type for MBR showing that a GPT is following */ 
+#define EFI_PMBR_OSTYPE_EFI 0xEE
+
+#define IS_VALID_DISK_INFO(Disk) \
+  (Disk)               &&        \
+  (Disk->DeviceObject) &&        \
+  (Disk->SectorSize)   &&        \
+  (Disk->Buffer)       &&        \
+  (Disk->SectorCount)
+
+VOID
+NTAPI
+FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry,
+                         IN ULONG PartitionNumber
+);
+
+NTSTATUS
+NTAPI
+FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject,
+                     OUT PDISK_GEOMETRY_EX Geometry
+);
+
+NTSTATUS
+NTAPI
+FstubReadSector(IN PDEVICE_OBJECT DeviceObject,
+                IN ULONG SectorSize,
+                IN ULONGLONG StartingSector OPTIONAL,
+                OUT PUSHORT Buffer
+);
+
+NTSTATUS
+NTAPI
+FstubAllocateDiskInformation(IN PDEVICE_OBJECT DeviceObject,
+                             OUT PDISK_INFORMATION * DiskBuffer,
+                             PDISK_GEOMETRY_EX DiskGeometry OPTIONAL)
+{
+    NTSTATUS Status;
+    PDISK_INFORMATION DiskInformation;
+    PAGED_CODE();
+
+    ASSERT(DeviceObject);
+    ASSERT(DiskBuffer);
+
+    /* Allocate internal structure */
+    DiskInformation = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_INFORMATION), TAG_FSTUB);
+    if (!DiskInformation)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* If caller don't pass needed information, let's get them */
+    if (!DiskGeometry)
+    {
+        Status = FstubGetDiskGeometry(DeviceObject, &(DiskInformation->DiskGeometry));
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
+            return Status;
+        }
+    }
+    else
+    {
+        DiskInformation->DiskGeometry = *DiskGeometry;
+    }
+
+    /* Ensure read/received information are correct */
+    if (DiskInformation->DiskGeometry.Geometry.BytesPerSector == 0 ||
+        DiskInformation->DiskGeometry.DiskSize.QuadPart == 0)
+    {
+        ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
+        return STATUS_DEVICE_NOT_READY;
+    }
+
+    /* Store vital information as well */
+    DiskInformation->DeviceObject = DeviceObject;
+    DiskInformation->SectorSize = DiskInformation->DiskGeometry.Geometry.BytesPerSector;
+    DiskInformation->SectorCount = DiskInformation->DiskGeometry.DiskSize.QuadPart / DiskInformation->SectorSize;
+
+    /* Finally, allocate the buffer that will be used for different read */
+    DiskInformation->Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskInformation->SectorSize, TAG_FSTUB);
+    if (!DiskInformation->Buffer)
+    {
+        ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Return allocated internal structure */
+    *DiskBuffer = DiskInformation;
+
+    return STATUS_SUCCESS;
+}
+
+PCHAR
+NTAPI
+FstubDbgGuidToString(IN PGUID Guid,
+                     OUT PCHAR String)
+{
+    sprintf(String,
+            "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+            Guid->Data1,
+            Guid->Data2,
+            Guid->Data3,
+            Guid->Data4[0],
+            Guid->Data4[1],
+            Guid->Data4[2],
+            Guid->Data4[3],
+            Guid->Data4[4],
+            Guid->Data4[5],
+            Guid->Data4[6],
+            Guid->Data4[7]);
+
+    return String;
+}
+
+VOID
+NTAPI
+FstubDbgPrintDriveLayoutEx(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout)
+{
+    ULONG i;
+    CHAR Guid[38];
+    PAGED_CODE();
+
+    DPRINT1("FSTUB: DRIVE_LAYOUT_INFORMATION_EX: %p\n", DriveLayout);
+    switch (DriveLayout->PartitionStyle)
+    {
+        case PARTITION_STYLE_MBR:
+            if (DriveLayout->PartitionCount % 4 != 0)
+            {
+                DPRINT1("Warning: Partition count isn't a 4-factor: %ld!\n", DriveLayout->PartitionCount);
+            }
+
+            DPRINT1("Signature: %8.8x\n", DriveLayout->Mbr.Signature);
+            for (i = 0; i < DriveLayout->PartitionCount; i++)
+            {
+                FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i);
+            }
+
+            break;
+        case PARTITION_STYLE_GPT:
+            FstubDbgGuidToString(&(DriveLayout->Gpt.DiskId), Guid);
+            DPRINT1("DiskId: %s\n", Guid);
+            DPRINT1("StartingUsableOffset: %I64x\n", DriveLayout->Gpt.StartingUsableOffset.QuadPart);
+            DPRINT1("UsableLength: %I64x\n", DriveLayout->Gpt.UsableLength.QuadPart);
+            DPRINT1("MaxPartitionCount: %ld\n", DriveLayout->Gpt.MaxPartitionCount);
+            for (i = 0; i < DriveLayout->PartitionCount; i++)
+            {
+                FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i);
+            }
+
+            break;
+        default:
+            DPRINT1("Unsupported partition style: %ld\n", DriveLayout->PartitionStyle);
+    }
+}
+
+VOID
+NTAPI
+FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry,
+                         IN ULONG PartitionNumber)
+{
+    CHAR Guid[38];
+    PAGED_CODE();
+
+    DPRINT1("Printing partition %ld\n", PartitionNumber);
+
+    switch (PartitionEntry[PartitionNumber].PartitionStyle)
+    {
+        case PARTITION_STYLE_MBR:
+            DPRINT1("  StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart);
+            DPRINT1("  PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart);
+            DPRINT1("  RewritePartition: %d\n", PartitionEntry[PartitionNumber].RewritePartition);
+            DPRINT1("  PartitionType: %02x\n", PartitionEntry[PartitionNumber].Mbr.PartitionType);
+            DPRINT1("  BootIndicator: %d\n", PartitionEntry[PartitionNumber].Mbr.BootIndicator);
+            DPRINT1("  RecognizedPartition: %d\n", PartitionEntry[PartitionNumber].Mbr.RecognizedPartition);
+            DPRINT1("  HiddenSectors: %ld\n", PartitionEntry[PartitionNumber].Mbr.HiddenSectors);
+
+            break;
+        case PARTITION_STYLE_GPT:
+            DPRINT1("  StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart);
+            DPRINT1("  PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart);
+            DPRINT1("  RewritePartition: %d\n", PartitionEntry[PartitionNumber].RewritePartition);
+            FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionType), Guid);
+            DPRINT1("  PartitionType: %s\n", Guid);
+            FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionId), Guid);
+            DPRINT1("  PartitionId: %s\n", Guid);
+            DPRINT1("  Attributes: %16x\n", PartitionEntry[PartitionNumber].Gpt.Attributes);
+            DPRINT1("  Name: %ws\n", PartitionEntry[PartitionNumber].Gpt.Name);
+
+            break;
+        default:
+            DPRINT1("  Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle);
+    }
+}
+
+NTSTATUS
+NTAPI
+FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk,
+                          IN PARTITION_STYLE * PartitionStyle)
+{
+    NTSTATUS Status;
+    PPARTITION_DESCRIPTOR PartitionDescriptor;
+    PAGED_CODE();
+
+    ASSERT(IS_VALID_DISK_INFO(Disk));
+    ASSERT(PartitionStyle);
+
+    /* Read disk first sector */
+    Status = FstubReadSector(Disk->DeviceObject,
+                             Disk->SectorSize,
+                             0,
+                             Disk->Buffer);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Get the partition descriptor array */
+    PartitionDescriptor = (PPARTITION_DESCRIPTOR)
+                          &(Disk->Buffer[PARTITION_TABLE_OFFSET]);
+    /* If we have not the 0xAA55 then it's raw partition */
+    if (Disk->Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
+    {
+        *PartitionStyle = PARTITION_STYLE_RAW;
+    }
+    /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
+    else if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
+             PartitionDescriptor[1].PartitionType == 0 &&
+             PartitionDescriptor[2].PartitionType == 0 &&
+             PartitionDescriptor[3].PartitionType == 0)
+    {
+        *PartitionStyle = PARTITION_STYLE_GPT;
+    }
+    /* Otherwise, partition table is in MBR */
+    else
+    {
+        *PartitionStyle = PARTITION_STYLE_MBR;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer)
+{
+    if (DiskBuffer)
+    {
+        if (DiskBuffer->Buffer)
+        {
+            ExFreePoolWithTag(DiskBuffer->Buffer, TAG_FSTUB);
+        }
+        ExFreePoolWithTag(DiskBuffer, TAG_FSTUB);
+    }
+}
+
+NTSTATUS
+NTAPI
+FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject,
+                     OUT PDISK_GEOMETRY_EX Geometry)
+{
+    PIRP Irp;
+    NTSTATUS Status;
+    PKEVENT Event = NULL;
+    PDISK_GEOMETRY_EX DiskGeometry = NULL;
+    PIO_STATUS_BLOCK IoStatusBlock = NULL;
+    PAGED_CODE();
+
+    ASSERT(DeviceObject);
+    ASSERT(Geometry);
+
+    /* Allocate needed components */
+    DiskGeometry = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_GEOMETRY_EX), TAG_FSTUB);
+    if (!DiskGeometry)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+
+    IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool, sizeof(IO_STATUS_BLOCK), TAG_FSTUB);
+    if (!IoStatusBlock)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+
+    Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_FSTUB);
+    if (!Event)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+    /* Initialize the waiting event */
+    KeInitializeEvent(Event, NotificationEvent, FALSE);
+
+    /* Build the request to get disk geometry */
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
+                                        DeviceObject,
+                                        0,
+                                        0,
+                                        DiskGeometry,
+                                        sizeof(DISK_GEOMETRY_EX),
+                                        FALSE,
+                                        Event,
+                                        IoStatusBlock);
+    if (!Irp)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto Cleanup;
+    }
+
+    /* Call the driver and wait for completion if needed */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock->Status;
+    }
+
+    /* In case of a success, return read data */
+    if (NT_SUCCESS(Status))
+    {
+        *Geometry = *DiskGeometry;
+    }
+
+Cleanup:
+    if (DiskGeometry)
+    {
+        ExFreePoolWithTag(DiskGeometry, TAG_FSTUB);
+
+        if (NT_SUCCESS(Status))
+        {
+            ASSERT(Geometry->Geometry.BytesPerSector % PARTITION_ENTRY_SIZE == 0);
+        }
+    }
+
+    if (IoStatusBlock)
+    {
+        ExFreePoolWithTag(IoStatusBlock, TAG_FSTUB);
+    }
+
+    if (Event)
+    {
+        ExFreePoolWithTag(Event, TAG_FSTUB);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+FstubReadPartitionTableEFI(IN PDISK_INFORMATION Disk,
+                           IN BOOLEAN ReadBackupTable,
+                           OUT struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+FstubReadPartitionTableMBR(IN PDISK_INFORMATION Disk,
+                           IN BOOLEAN ReturnRecognizedPartitions,
+                           OUT struct _DRIVE_LAYOUT_INFORMATION_EX** ReturnedDriveLayout)
+{
+    ULONG i;
+    NTSTATUS Status;
+    PDRIVE_LAYOUT_INFORMATION DriveLayout = NULL;
+    PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL;
+    PAGED_CODE();
+
+    ASSERT(IS_VALID_DISK_INFO(Disk));
+    ASSERT(ReturnedDriveLayout);
+
+    /* Zero output */
+    *ReturnedDriveLayout = NULL;
+
+    /* Read partition table the old way */
+    Status = IoReadPartitionTable(Disk->DeviceObject,
+                                  Disk->SectorSize,
+                                  ReturnRecognizedPartitions,
+                                  &DriveLayout);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */
+    DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool,
+                                          FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
+                                          DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX),
+                                          TAG_FSTUB);
+    if (!DriveLayoutEx)
+    {
+        /* Let's not leak memory as in Windows 2003 */
+        ExFreePool(DriveLayout);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Start converting the DRIVE_LAYOUT_INFORMATION structure */
+    DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
+    DriveLayoutEx->PartitionCount = DriveLayout->PartitionCount;
+    DriveLayoutEx->Mbr.Signature = DriveLayout->Signature;
+
+    /* Convert each found partition */
+    for (i = 0; i < DriveLayout->PartitionCount; i++)
+    {
+        DriveLayoutEx->PartitionEntry[i].PartitionStyle = PARTITION_STYLE_MBR;
+        DriveLayoutEx->PartitionEntry[i].StartingOffset = DriveLayout->PartitionEntry[i].StartingOffset;
+        DriveLayoutEx->PartitionEntry[i].PartitionLength = DriveLayout->PartitionEntry[i].PartitionLength;
+        DriveLayoutEx->PartitionEntry[i].PartitionNumber = DriveLayout->PartitionEntry[i].PartitionNumber;
+        DriveLayoutEx->PartitionEntry[i].RewritePartition = DriveLayout->PartitionEntry[i].RewritePartition;
+        DriveLayoutEx->PartitionEntry[i].Mbr.PartitionType = DriveLayout->PartitionEntry[i].PartitionType;
+        DriveLayoutEx->PartitionEntry[i].Mbr.BootIndicator = DriveLayout->PartitionEntry[i].BootIndicator;
+        DriveLayoutEx->PartitionEntry[i].Mbr.RecognizedPartition = DriveLayout->PartitionEntry[i].RecognizedPartition;
+        DriveLayoutEx->PartitionEntry[i].Mbr.HiddenSectors = DriveLayout->PartitionEntry[i].HiddenSectors;
+    }
+
+    /* Finally, return data and free old structure */
+    *ReturnedDriveLayout = DriveLayoutEx;
+    ExFreePool(DriveLayout);
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+FstubReadSector(IN PDEVICE_OBJECT DeviceObject,
+                IN ULONG SectorSize,
+                IN ULONGLONG StartingSector OPTIONAL,
+                OUT PUSHORT Buffer)
+{
+    PIRP Irp;
+    KEVENT Event;
+    NTSTATUS Status;
+    LARGE_INTEGER StartingOffset;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIO_STACK_LOCATION IoStackLocation;
+    PAGED_CODE();
+
+    ASSERT(DeviceObject);
+    ASSERT(Buffer);
+    ASSERT(SectorSize);
+
+    /* Compute starting offset */
+    StartingOffset.QuadPart = StartingSector * SectorSize;
+
+    /* Initialize waiting event */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    /* Prepare IRP */
+    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
+                                       DeviceObject,
+                                       Buffer,
+                                       SectorSize,
+                                       &StartingOffset,
+                                       &Event,
+                                       &IoStatusBlock);
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Override volume verify */
+    IoStackLocation = IoGetNextIrpStackLocation(Irp);
+    IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
+
+    /* Then call driver, and wait for completion if needed */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
+    }
+
+    return Status;
+}
+
 /* FUNCTIONS *****************************************************************/
 
 /*
@@ -52,15 +543,70 @@ IoReadDiskSignature(IN PDEVICE_OBJECT DeviceObject,
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
 IoReadPartitionTableEx(IN PDEVICE_OBJECT DeviceObject,
                        IN struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PDISK_INFORMATION Disk;
+    PARTITION_STYLE PartitionStyle;
+    PAGED_CODE();
+
+    ASSERT(DeviceObject);
+    ASSERT(DriveLayout);
+
+    /* First of all, allocate internal structure */
+    Status = FstubAllocateDiskInformation(DeviceObject, &Disk, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+    ASSERT(Disk);
+
+    /* Then, detect partition style (MBR? GTP/EFI? RAW?) */
+    Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
+    if (!NT_SUCCESS(Status))
+    {
+        FstubFreeDiskInformation(Disk);
+        return Status;
+    }
+
+    /* Here partition table is really read, depending on its style */
+    switch (PartitionStyle)
+    {
+        case PARTITION_STYLE_MBR:
+        case PARTITION_STYLE_RAW:
+            Status = FstubReadPartitionTableMBR(Disk, FALSE, DriveLayout);
+            break;
+
+        case PARTITION_STYLE_GPT:
+             /* Read primary table */
+             Status = FstubReadPartitionTableEFI(Disk, FALSE, DriveLayout);
+             /* If it failed, try reading backup table */
+             if (!NT_SUCCESS(Status))
+             {
+                 Status = FstubReadPartitionTableEFI(Disk, TRUE, DriveLayout);
+             }
+             break;
+
+        default:
+             DPRINT("Unknown partition type\n");
+             Status = STATUS_UNSUCCESSFUL;
+    }
+
+    /* It's over, internal structure not needed anymore */
+    FstubFreeDiskInformation(Disk);
+
+    /* In case of success, print data */
+    if (NT_SUCCESS(Status))
+    {
+        FstubDbgPrintDriveLayoutEx(*DriveLayout);
+    }
+
+    return Status;
 }
 
 /*