reactos/drivers/storage/partmgr/partmgr.c
Hermès Bélusca-Maïto 3d26d76a4c
[PARTMGR] Detect and flag partitionless ("super-floppy") disks (#6926)
CORE-15575

Detect whether the disk is a "super-floppy", which is the name given
to partitionless disk having no MBR, with the unique partition volume
starting at sector offset zero and spanning the whole disk.
The name comes from the fact that at the partitioning level, the disk
"looks like" a large-capacity floppy disk.

This is typically how external removable (USB, ...) drives are
partitioned by default by Windows.

https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-and-gpt-faq?view=windows-11#superfloppy

The kernel-mode functions IoReadPartitionTable() / IoWritePartitionTable()
report the drive layout of a "super-floppy" disk as follows:
an MBR-style disk containing only one single partition starting at the
beginning of the disk (StartingOffset == 0) without hidden sectors, and
its type being FAT16 non-bootable.
The disk NTFT signature is set to 0x00000001.

----

Additional bug fixes to make the feature work reliably:

- Make PartMgrGetDriveLayout() also update the FDO DiskData's
  PartitionStyle and Signature/GPT DiskId for consistency (code moved
  from PartMgrRefreshDiskData()).

- In FdoIoctlDiskSetDriveLayout[Ex](), if the disk is "super-floppy",
  but the user wants to create more than one partition, fail the call.
  (In the Ex call, fail also if the partition style changes.)
2024-06-12 12:15:22 +02:00

1504 lines
45 KiB
C

/*
* PROJECT: Partition manager driver
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Main file
* COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
*/
/* The Partition Manager Driver in ReactOS complements disk.sys/classpnp.sys drivers
* (which are derived from Windows 10 drivers) so does not do exactly what Windows 2003 partmgr.sys
* does. Here is acts like both partition and volume manager, because volmgr.sys does not (yet)
* exist in ReactOS. Thus handles some IOCTL_VOLUME_*, and IOCTL_MOUNTMGR_* IOCTLs.
*/
#include "partmgr.h"
static
CODE_SEG("PAGE")
PDRIVE_LAYOUT_INFORMATION
PartMgrConvertExtendedToLayout(
_In_ CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)
{
PDRIVE_LAYOUT_INFORMATION Layout;
PPARTITION_INFORMATION Partition;
PPARTITION_INFORMATION_EX PartitionEx;
PAGED_CODE();
ASSERT(LayoutEx);
if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR)
{
ASSERT(FALSE);
return NULL;
}
size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
Layout = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR);
if (Layout == NULL)
{
return NULL;
}
Layout->Signature = LayoutEx->Mbr.Signature;
Layout->PartitionCount = LayoutEx->PartitionCount;
for (UINT32 i = 0; i < LayoutEx->PartitionCount; i++)
{
Partition = &Layout->PartitionEntry[i];
PartitionEx = &LayoutEx->PartitionEntry[i];
Partition->StartingOffset = PartitionEx->StartingOffset;
Partition->PartitionLength = PartitionEx->PartitionLength;
Partition->RewritePartition = PartitionEx->RewritePartition;
Partition->PartitionNumber = PartitionEx->PartitionNumber;
Partition->PartitionType = PartitionEx->Mbr.PartitionType;
Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
}
return Layout;
}
static
CODE_SEG("PAGE")
PDRIVE_LAYOUT_INFORMATION_EX
PartMgrConvertLayoutToExtended(
_In_ CONST PDRIVE_LAYOUT_INFORMATION Layout)
{
PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
PAGED_CODE();
ASSERT(Layout != NULL);
size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
Layout->PartitionCount * sizeof (PARTITION_INFORMATION_EX);
layoutEx = ExAllocatePoolUninitialized(PagedPool, layoutSize, TAG_PARTMGR);
if (layoutEx == NULL)
{
return NULL;
}
layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
layoutEx->PartitionCount = Layout->PartitionCount;
layoutEx->Mbr.Signature = Layout->Signature;
for (UINT32 i = 0; i < Layout->PartitionCount; i++)
{
PPARTITION_INFORMATION part = &Layout->PartitionEntry[i];
layoutEx->PartitionEntry[i] = (PARTITION_INFORMATION_EX) {
.PartitionStyle = PARTITION_STYLE_MBR,
.StartingOffset = part->StartingOffset,
.PartitionLength = part->PartitionLength,
.RewritePartition = part->RewritePartition,
.PartitionNumber = part->PartitionNumber,
.Mbr = {
.PartitionType = part->PartitionType,
.BootIndicator = part->BootIndicator,
.RecognizedPartition = part->RecognizedPartition,
.HiddenSectors = part->HiddenSectors,
}
};
}
return layoutEx;
}
/**
* @brief
* Detects whether a disk is a "super-floppy", i.e. an unpartitioned
* disk with only a valid VBR, as reported by IoReadPartitionTable()
* and IoWritePartitionTable():
* only one single partition starting at offset zero and spanning the
* whole disk, without hidden sectors, whose type is FAT16 non-bootable.
*
* Accessing \Device\HarddiskN\Partition0 or Partition1 on such disks
* returns the same data.
*
* @note
* - Requires partitioning lock held.
* - Uses the cached disk partition layout.
**/
static
CODE_SEG("PAGE")
BOOLEAN
PartMgrIsDiskSuperFloppy(
_In_ PFDO_EXTENSION FdoExtension)
{
PPARTITION_INFORMATION_EX PartitionInfo;
PAGED_CODE();
ASSERT(FdoExtension->LayoutValid && FdoExtension->LayoutCache);
/* We must be MBR and have only one partition */
ASSERT(FdoExtension->DiskData.PartitionStyle == FdoExtension->LayoutCache->PartitionStyle);
if (FdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_MBR)
return FALSE;
if (FdoExtension->LayoutCache->PartitionCount != 1)
return FALSE;
/* Get the single partition entry */
PartitionInfo = FdoExtension->LayoutCache->PartitionEntry;
ASSERT(FdoExtension->DiskData.PartitionStyle == PartitionInfo->PartitionStyle);
/* The single partition must start at the beginning of the disk */
if (!(PartitionInfo->StartingOffset.QuadPart == 0 &&
PartitionInfo->Mbr.HiddenSectors == 0))
{
return FALSE;
}
/* The disk signature is usually set to 1; warn in case it's not */
ASSERT(FdoExtension->DiskData.Mbr.Signature == FdoExtension->LayoutCache->Mbr.Signature);
if (FdoExtension->DiskData.Mbr.Signature != 1)
{
WARN("Super-Floppy disk %lu signature %08x != 1!\n",
FdoExtension->DiskData.DeviceNumber, FdoExtension->DiskData.Mbr.Signature);
}
/* The partition must be recognized and report as FAT16 non-bootable */
if ((PartitionInfo->Mbr.RecognizedPartition != TRUE) ||
(PartitionInfo->Mbr.PartitionType != PARTITION_FAT_16) ||
(PartitionInfo->Mbr.BootIndicator != FALSE))
{
WARN("Super-Floppy disk %lu does not return default settings!\n"
" RecognizedPartition = %s, expected TRUE\n"
" PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n"
" BootIndicator = %s, expected FALSE\n",
FdoExtension->DiskData.DeviceNumber,
PartitionInfo->Mbr.RecognizedPartition ? "TRUE" : "FALSE",
PartitionInfo->Mbr.PartitionType,
PartitionInfo->Mbr.BootIndicator ? "TRUE" : "FALSE");
}
/* The partition and disk sizes should agree */
if (PartitionInfo->PartitionLength.QuadPart != FdoExtension->DiskData.DiskSize)
{
WARN("PartitionLength = %I64u is different from DiskSize = %I64u\n",
PartitionInfo->PartitionLength.QuadPart, FdoExtension->DiskData.DiskSize);
}
return TRUE;
}
static
CODE_SEG("PAGE")
VOID
PartMgrUpdatePartitionDevices(
_In_ PFDO_EXTENSION FdoExtension,
_Inout_ PDRIVE_LAYOUT_INFORMATION_EX NewLayout)
{
NTSTATUS status;
PSINGLE_LIST_ENTRY curEntry, prevEntry;
UINT32 totalPartitions = 0;
// Clear the partition numbers from the list entries
for (UINT32 i = 0; i < NewLayout->PartitionCount; i++)
{
NewLayout->PartitionEntry[i].PartitionNumber = 0;
}
// iterate over old partition list
prevEntry = &FdoExtension->PartitionList;
curEntry = FdoExtension->PartitionList.Next;
while (curEntry != NULL)
{
PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry, PARTITION_EXTENSION, ListEntry);
UINT32 partNumber = 0; // count detected partitions for device symlinks
BOOLEAN found = FALSE;
PPARTITION_INFORMATION_EX partEntry;
// trying to find this partition in returned layout
for (UINT32 i = 0; i < NewLayout->PartitionCount; i++)
{
partEntry = &NewLayout->PartitionEntry[i];
// skip unused and container partitions
if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR &&
(partEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
IsContainerPartition(partEntry->Mbr.PartitionType)))
{
continue;
}
partNumber++;
// skip already found partitions
if (partEntry->PartitionNumber)
{
continue;
}
// skip if partitions are not equal
if (partEntry->StartingOffset.QuadPart != partExt->StartingOffset ||
partEntry->PartitionLength.QuadPart != partExt->PartitionLength)
{
continue;
}
// found matching partition - processing it
found = TRUE;
break;
}
if (found)
{
// update (possibly changed) partition metadata
if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR)
{
partExt->Mbr.PartitionType = partEntry->Mbr.PartitionType;
partExt->Mbr.BootIndicator = partEntry->Mbr.BootIndicator;
}
else
{
partExt->Gpt.PartitionType = partEntry->Gpt.PartitionType;
partExt->Gpt.PartitionId = partEntry->Gpt.PartitionId;
partExt->Gpt.Attributes = partEntry->Gpt.Attributes;
RtlCopyMemory(partExt->Gpt.Name, partEntry->Gpt.Name, sizeof(partExt->Gpt.Name));
}
partExt->OnDiskNumber = partNumber;
partEntry->PartitionNumber = partNumber; // mark it as a found one
totalPartitions++;
}
else
{
// detach the device from the list
prevEntry->Next = curEntry->Next;
curEntry = prevEntry;
partExt->Attached = FALSE;
// enumerated PDOs will receive IRP_MN_REMOVE_DEVICE
if (!partExt->IsEnumerated)
{
PartitionHandleRemove(partExt, TRUE);
}
}
prevEntry = curEntry;
curEntry = curEntry->Next;
}
UINT32 partNumber = 0;
UINT32 pdoNumber = 1;
// now looking through remaining "new" partitions
for (UINT32 i = 0; i < NewLayout->PartitionCount; i++)
{
PPARTITION_INFORMATION_EX partEntry = &NewLayout->PartitionEntry[i];
// again, skip unused and container partitions
if (NewLayout->PartitionStyle == PARTITION_STYLE_MBR &&
(partEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
IsContainerPartition(partEntry->Mbr.PartitionType)))
{
continue;
}
partNumber++;
// and skip processed partitions
if (partEntry->PartitionNumber != 0)
{
continue;
}
// find the first free PDO index
for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
curEntry != NULL;
curEntry = curEntry->Next)
{
PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
PARTITION_EXTENSION,
ListEntry);
if (partExt->DetectedNumber == pdoNumber)
{
// found a matching pdo number - restart the search
curEntry = FdoExtension->PartitionList.Next;
pdoNumber++;
}
}
partEntry->PartitionNumber = partNumber;
PDEVICE_OBJECT partitionDevice;
status = PartitionCreateDevice(FdoExtension->DeviceObject,
partEntry,
pdoNumber,
NewLayout->PartitionStyle,
&partitionDevice);
if (!NT_SUCCESS(status))
{
partEntry->PartitionNumber = 0;
continue;
}
// mark partition as removable if parent device is removable
if (FdoExtension->LowerDevice->Characteristics & FILE_REMOVABLE_MEDIA)
partitionDevice->Characteristics |= FILE_REMOVABLE_MEDIA;
totalPartitions++;
// insert the structure to the partition list
curEntry = FdoExtension->PartitionList.Next;
prevEntry = NULL;
while (curEntry != NULL)
{
PPARTITION_EXTENSION curPart = CONTAINING_RECORD(curEntry,
PARTITION_EXTENSION,
ListEntry);
if (curPart->OnDiskNumber < partNumber)
{
prevEntry = curEntry;
curEntry = curPart->ListEntry.Next;
}
else
{ // we found where to put the partition
break;
}
}
PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension;
if (prevEntry)
{
// insert after prevEntry
partExt->ListEntry.Next = prevEntry->Next;
prevEntry->Next = &partExt->ListEntry;
}
else
{
// insert at the beginning
partExt->ListEntry.Next = FdoExtension->PartitionList.Next;
FdoExtension->PartitionList.Next = &partExt->ListEntry;
}
partExt->Attached = TRUE;
}
FdoExtension->EnumeratedPartitionsTotal = totalPartitions;
}
/**
* @brief
* Retrieves the disk partition layout from the given disk FDO.
*
* If the disk layout cache is valid, just return it; otherwise,
* read the partition table layout from disk and update the cache.
*
* @note Requires partitioning lock held.
**/
static
CODE_SEG("PAGE")
NTSTATUS
PartMgrGetDriveLayout(
_In_ PFDO_EXTENSION FdoExtension,
_Out_ PDRIVE_LAYOUT_INFORMATION_EX *DriveLayout)
{
PAGED_CODE();
if (FdoExtension->LayoutValid)
{
*DriveLayout = FdoExtension->LayoutCache;
return STATUS_SUCCESS;
}
PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL;
NTSTATUS status = IoReadPartitionTableEx(FdoExtension->LowerDevice, &layoutEx);
if (!NT_SUCCESS(status))
return status;
if (FdoExtension->LayoutCache)
ExFreePool(FdoExtension->LayoutCache);
FdoExtension->LayoutCache = layoutEx;
FdoExtension->LayoutValid = TRUE;
FdoExtension->DiskData.PartitionStyle = layoutEx->PartitionStyle;
if (FdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
{
FdoExtension->DiskData.Mbr.Signature = layoutEx->Mbr.Signature;
// FdoExtension->DiskData.Mbr.Checksum = geometryEx.Partition.Mbr.CheckSum;
}
else
{
FdoExtension->DiskData.Gpt.DiskId = layoutEx->Gpt.DiskId;
}
FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension);
*DriveLayout = layoutEx;
return status;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskGetDriveGeometryEx(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
PAGED_CODE();
// We're patching the DISK_PARTITION_INFO part of the returned structure
// as disk.sys doesn't really know about the partition table on a disk
PDISK_GEOMETRY_EX_INTERNAL geometryEx = Irp->AssociatedIrp.SystemBuffer;
ULONG outBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength;
NTSTATUS status;
status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
FdoExtension->LowerDevice,
NULL,
0,
geometryEx,
outBufferLength,
FALSE);
if (!NT_SUCCESS(status))
{
return status;
}
// if DISK_PARTITION_INFO fits the output size
if (outBufferLength >= FIELD_OFFSET(DISK_GEOMETRY_EX_INTERNAL, Detection))
{
PartMgrAcquireLayoutLock(FdoExtension);
geometryEx->Partition.SizeOfPartitionInfo = sizeof(geometryEx->Partition);
geometryEx->Partition.PartitionStyle = FdoExtension->DiskData.PartitionStyle;
switch (geometryEx->Partition.PartitionStyle)
{
case PARTITION_STYLE_MBR:
geometryEx->Partition.Mbr.Signature = FdoExtension->DiskData.Mbr.Signature;
// checksum?
break;
case PARTITION_STYLE_GPT:
geometryEx->Partition.Gpt.DiskId = FdoExtension->DiskData.Gpt.DiskId;
break;
default:
RtlZeroMemory(&geometryEx->Partition, sizeof(geometryEx->Partition));
}
PartMgrReleaseLayoutLock(FdoExtension);
}
// the logic is copied from disk.sys
Irp->IoStatus.Information = min(outBufferLength, sizeof(DISK_GEOMETRY_EX_INTERNAL));
return status;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskGetPartitionInfo(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer;
PAGED_CODE();
if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfo)))
{
return STATUS_BUFFER_TOO_SMALL;
}
PartMgrAcquireLayoutLock(FdoExtension);
*partInfo = (PARTITION_INFORMATION){
.PartitionType = PARTITION_ENTRY_UNUSED,
.StartingOffset.QuadPart = 0,
.PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize,
.HiddenSectors = 0,
.PartitionNumber = 0,
.BootIndicator = FALSE,
.RewritePartition = FALSE,
.RecognizedPartition = FALSE,
};
PartMgrReleaseLayoutLock(FdoExtension);
Irp->IoStatus.Information = sizeof(*partInfo);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskGetPartitionInfoEx(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer;
PAGED_CODE();
if (!VerifyIrpOutBufferSize(Irp, sizeof(*partInfoEx)))
{
return STATUS_BUFFER_TOO_SMALL;
}
PartMgrAcquireLayoutLock(FdoExtension);
// most of the fields a zeroed for Partition0
*partInfoEx = (PARTITION_INFORMATION_EX){
.PartitionLength.QuadPart = FdoExtension->DiskData.DiskSize,
.PartitionStyle = FdoExtension->DiskData.PartitionStyle,
};
PartMgrReleaseLayoutLock(FdoExtension);
Irp->IoStatus.Information = sizeof(*partInfoEx);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskGetDriveLayout(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
PartMgrAcquireLayoutLock(FdoExtension);
PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx);
if (!NT_SUCCESS(status))
{
PartMgrReleaseLayoutLock(FdoExtension);
return status;
}
// checking this value from layoutEx in case it has been changed
if (layoutEx->PartitionStyle != PARTITION_STYLE_MBR)
{
PartMgrReleaseLayoutLock(FdoExtension);
return STATUS_INVALID_DEVICE_REQUEST;
}
size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]);
size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION);
if (!VerifyIrpOutBufferSize(Irp, size))
{
PartMgrReleaseLayoutLock(FdoExtension);
return STATUS_BUFFER_TOO_SMALL;
}
PDRIVE_LAYOUT_INFORMATION partitionList = PartMgrConvertExtendedToLayout(layoutEx);
PartMgrReleaseLayoutLock(FdoExtension);
if (partitionList == NULL)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, partitionList, size);
ExFreePoolWithTag(partitionList, TAG_PARTMGR);
Irp->IoStatus.Information = size;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskGetDriveLayoutEx(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
PartMgrAcquireLayoutLock(FdoExtension);
PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
NTSTATUS status = PartMgrGetDriveLayout(FdoExtension, &layoutEx);
if (!NT_SUCCESS(status))
{
PartMgrReleaseLayoutLock(FdoExtension);
return status;
}
size_t size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]);
size += layoutEx->PartitionCount * sizeof(PARTITION_INFORMATION_EX);
if (!VerifyIrpOutBufferSize(Irp, size))
{
PartMgrReleaseLayoutLock(FdoExtension);
return STATUS_BUFFER_TOO_SMALL;
}
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, layoutEx, size);
PartMgrReleaseLayoutLock(FdoExtension);
Irp->IoStatus.Information = size;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskSetDriveLayout(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PDRIVE_LAYOUT_INFORMATION layoutInfo = Irp->AssociatedIrp.SystemBuffer;
PAGED_CODE();
if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutInfo)))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]);
layoutSize += layoutInfo->PartitionCount * sizeof(PARTITION_INFORMATION);
if (!VerifyIrpInBufferSize(Irp, layoutSize))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
PDRIVE_LAYOUT_INFORMATION_EX layoutEx = PartMgrConvertLayoutToExtended(layoutInfo);
if (layoutEx == NULL)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
PartMgrAcquireLayoutLock(FdoExtension);
// If the current disk is super-floppy but the user changes
// the number of partitions to > 1, fail the call.
if (FdoExtension->IsSuperFloppy && (layoutEx->PartitionCount > 1))
{
PartMgrReleaseLayoutLock(FdoExtension);
return STATUS_INVALID_DEVICE_REQUEST;
}
// this in fact updates the bus relations
PartMgrUpdatePartitionDevices(FdoExtension, layoutEx);
// write the partition table to the disk
NTSTATUS status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx);
if (NT_SUCCESS(status))
{
// save the layout cache
if (FdoExtension->LayoutCache)
{
ExFreePool(FdoExtension->LayoutCache);
}
FdoExtension->LayoutCache = layoutEx;
FdoExtension->LayoutValid = TRUE;
// set updated partition numbers
for (UINT32 i = 0; i < layoutInfo->PartitionCount; i++)
{
PPARTITION_INFORMATION part = &layoutInfo->PartitionEntry[i];
part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber;
}
FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension);
}
else
{
FdoExtension->LayoutValid = FALSE;
}
PartMgrReleaseLayoutLock(FdoExtension);
IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
// notify everyone that the disk layout has changed
TARGET_DEVICE_CUSTOM_NOTIFICATION notification;
notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
notification.Version = 1;
notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
notification.FileObject = NULL;
notification.NameBufferOffset = -1;
IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO,
&notification,
NULL,
NULL);
Irp->IoStatus.Information = layoutSize;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskSetDriveLayoutEx(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PDRIVE_LAYOUT_INFORMATION_EX layoutEx, layoutUser = Irp->AssociatedIrp.SystemBuffer;
NTSTATUS status;
PAGED_CODE();
if (!VerifyIrpInBufferSize(Irp, sizeof(*layoutUser)))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
size_t layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]);
layoutSize += layoutUser->PartitionCount * sizeof(PARTITION_INFORMATION_EX);
if (!VerifyIrpInBufferSize(Irp, layoutSize))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
// we need to copy the structure from the IRP input buffer
layoutEx = ExAllocatePoolWithTag(PagedPool, layoutSize, TAG_PARTMGR);
if (!layoutEx)
{
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(layoutEx, layoutUser, layoutSize);
PartMgrAcquireLayoutLock(FdoExtension);
// If the current disk is super-floppy but the user changes either
// the disk type or the number of partitions to > 1, fail the call.
if (FdoExtension->IsSuperFloppy &&
((layoutEx->PartitionStyle != PARTITION_STYLE_MBR) ||
(layoutEx->PartitionCount > 1)))
{
PartMgrReleaseLayoutLock(FdoExtension);
return STATUS_INVALID_DEVICE_REQUEST;
}
// if partition count is 0, it's the same as IOCTL_DISK_CREATE_DISK
if (layoutEx->PartitionCount == 0)
{
CREATE_DISK createDisk = {0};
createDisk.PartitionStyle = layoutEx->PartitionStyle;
if (createDisk.PartitionStyle == PARTITION_STYLE_MBR)
{
createDisk.Mbr.Signature = layoutEx->Mbr.Signature;
}
else if (createDisk.PartitionStyle == PARTITION_STYLE_GPT)
{
createDisk.Gpt.DiskId = layoutEx->Gpt.DiskId;
}
status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk);
}
else
{
// this in fact updates the bus relations
PartMgrUpdatePartitionDevices(FdoExtension, layoutEx);
// write the partition table to the disk
status = IoWritePartitionTableEx(FdoExtension->LowerDevice, layoutEx);
if (NT_SUCCESS(status))
{
// set updated partition numbers
for (UINT32 i = 0; i < layoutEx->PartitionCount; i++)
{
PPARTITION_INFORMATION_EX part = &layoutEx->PartitionEntry[i];
part->PartitionNumber = layoutEx->PartitionEntry[i].PartitionNumber;
}
}
}
// update the layout cache
if (NT_SUCCESS(status))
{
if (FdoExtension->LayoutCache)
{
ExFreePool(FdoExtension->LayoutCache);
}
FdoExtension->LayoutCache = layoutEx;
FdoExtension->LayoutValid = TRUE;
FdoExtension->IsSuperFloppy = PartMgrIsDiskSuperFloppy(FdoExtension);
}
else
{
FdoExtension->LayoutValid = FALSE;
}
PartMgrReleaseLayoutLock(FdoExtension);
IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
// notify everyone that the disk layout has changed
TARGET_DEVICE_CUSTOM_NOTIFICATION notification;
notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
notification.Version = 1;
notification.Size = FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
notification.FileObject = NULL;
notification.NameBufferOffset = -1;
IoReportTargetDeviceChangeAsynchronous(FdoExtension->PhysicalDiskDO,
&notification,
NULL,
NULL);
Irp->IoStatus.Information = layoutSize;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskUpdateProperties(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
PartMgrAcquireLayoutLock(FdoExtension);
FdoExtension->LayoutValid = FALSE;
PartMgrReleaseLayoutLock(FdoExtension);
IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskCreateDisk(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
PCREATE_DISK createDisk = Irp->AssociatedIrp.SystemBuffer;
if (!VerifyIrpInBufferSize(Irp, sizeof(*createDisk)))
{
return STATUS_INFO_LENGTH_MISMATCH;
}
PartMgrAcquireLayoutLock(FdoExtension);
NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, createDisk);
FdoExtension->LayoutValid = FALSE;
PartMgrReleaseLayoutLock(FdoExtension);
IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
return status;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoIoctlDiskDeleteDriveLayout(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
CREATE_DISK createDisk = { .PartitionStyle = PARTITION_STYLE_RAW };
PAGED_CODE();
PartMgrAcquireLayoutLock(FdoExtension);
NTSTATUS status = IoCreateDisk(FdoExtension->LowerDevice, &createDisk);
FdoExtension->LayoutValid = FALSE;
PartMgrReleaseLayoutLock(FdoExtension);
IoInvalidateDeviceRelations(FdoExtension->PhysicalDiskDO, BusRelations);
return status;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoHandleStartDevice(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
// obtain the disk device number
// this is not expected to change thus not in PartMgrRefreshDiskData
STORAGE_DEVICE_NUMBER deviceNumber;
NTSTATUS status = IssueSyncIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
FdoExtension->LowerDevice,
NULL,
0,
&deviceNumber,
sizeof(deviceNumber),
FALSE);
if (!NT_SUCCESS(status))
{
return status;
}
FdoExtension->DiskData.DeviceNumber = deviceNumber.DeviceNumber;
// register the disk interface
// partmgr.sys from Windows 8.1 also registers a mysterious GUID_DEVINTERFACE_HIDDEN_DISK here
UNICODE_STRING interfaceName;
status = IoRegisterDeviceInterface(FdoExtension->PhysicalDiskDO,
&GUID_DEVINTERFACE_DISK,
NULL,
&interfaceName);
if(!NT_SUCCESS(status))
{
ERR("Failed to register GUID_DEVINTERFACE_DISK, status %x\n", status);
return status;
}
FdoExtension->DiskInterfaceName = interfaceName;
status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
INFO("Disk interface %wZ\n", &interfaceName);
if (!NT_SUCCESS(status))
{
RtlFreeUnicodeString(&interfaceName);
RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL);
}
return status;
}
/**
* @brief
* Refreshes all the cached disk FDO data.
* The geometry of the disk and its partition layout cache is updated.
*
* @note Requires partitioning lock held.
**/
static
CODE_SEG("PAGE")
NTSTATUS
PartMgrRefreshDiskData(
_In_ PFDO_EXTENSION FdoExtension)
{
NTSTATUS status;
PAGED_CODE();
// get the DiskSize and BytesPerSector
DISK_GEOMETRY_EX geometryEx;
status = IssueSyncIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
FdoExtension->LowerDevice,
NULL,
0,
&geometryEx,
sizeof(geometryEx),
FALSE);
if (!NT_SUCCESS(status))
return status;
FdoExtension->DiskData.DiskSize = geometryEx.DiskSize.QuadPart;
FdoExtension->DiskData.BytesPerSector = geometryEx.Geometry.BytesPerSector;
// get the partition style-related info
PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL;
status = PartMgrGetDriveLayout(FdoExtension, &layoutEx);
if (!NT_SUCCESS(status))
return status;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoHandleDeviceRelations(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type;
PAGED_CODE();
if (type == BusRelations)
{
PartMgrAcquireLayoutLock(FdoExtension);
NTSTATUS status = PartMgrRefreshDiskData(FdoExtension);
if (!NT_SUCCESS(status))
{
PartMgrReleaseLayoutLock(FdoExtension);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
INFO("Partition style %u\n", FdoExtension->DiskData.PartitionStyle);
// PartMgrRefreshDiskData() calls PartMgrGetDriveLayout() inside
// so we're sure here that it returns only the cached layout.
PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
PartMgrGetDriveLayout(FdoExtension, &layoutEx);
PartMgrUpdatePartitionDevices(FdoExtension, layoutEx);
// now fill the DeviceRelations structure
TRACE("Reporting %u partitions\n", FdoExtension->EnumeratedPartitionsTotal);
PDEVICE_RELATIONS deviceRelations =
ExAllocatePoolWithTag(PagedPool,
sizeof(DEVICE_RELATIONS)
+ sizeof(PDEVICE_OBJECT)
* (FdoExtension->EnumeratedPartitionsTotal - 1),
TAG_PARTMGR);
if (!deviceRelations)
{
PartMgrReleaseLayoutLock(FdoExtension);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
deviceRelations->Count = 0;
PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
while (curEntry != NULL)
{
PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
PARTITION_EXTENSION,
ListEntry);
// mark the PDO to know that we don't need to manually delete it
partExt->IsEnumerated = TRUE;
deviceRelations->Objects[deviceRelations->Count++] = partExt->DeviceObject;
ObReferenceObject(partExt->DeviceObject);
curEntry = partExt->ListEntry.Next;
}
ASSERT(deviceRelations->Count == FdoExtension->EnumeratedPartitionsTotal);
PartMgrReleaseLayoutLock(FdoExtension);
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(FdoExtension->LowerDevice, Irp);
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoHandleRemoveDevice(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
if (FdoExtension->DiskInterfaceName.Buffer)
{
IoSetDeviceInterfaceState(&FdoExtension->DiskInterfaceName, FALSE);
RtlFreeUnicodeString(&FdoExtension->DiskInterfaceName);
RtlInitUnicodeString(&FdoExtension->DiskInterfaceName, NULL);
}
// Send the IRP down the stack
IoSkipCurrentIrpStackLocation(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = IoCallDriver(FdoExtension->LowerDevice, Irp);
IoDetachDevice(FdoExtension->LowerDevice);
IoDeleteDevice(FdoExtension->DeviceObject);
return status;
}
static
CODE_SEG("PAGE")
NTSTATUS
FdoHandleSurpriseRemoval(
_In_ PFDO_EXTENSION FdoExtension,
_In_ PIRP Irp)
{
PAGED_CODE();
// all enumerated child devices should receive IRP_MN_REMOVE_DEVICE
// removing only non-enumerated ones here
for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
curEntry != NULL;
curEntry = curEntry->Next)
{
PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
PARTITION_EXTENSION,
ListEntry);
if (partExt->IsEnumerated)
{
PartitionHandleRemove(partExt, TRUE);
}
}
// Send the IRP down the stack
IoSkipCurrentIrpStackLocation(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
return IoCallDriver(FdoExtension->LowerDevice, Irp);
}
static
CODE_SEG("PAGE")
NTSTATUS
NTAPI
PartMgrAddDevice(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PDEVICE_OBJECT PhysicalDeviceObject)
{
PDEVICE_OBJECT deviceObject;
PAGED_CODE();
NTSTATUS status = IoCreateDevice(DriverObject,
sizeof(FDO_EXTENSION),
0,
FILE_DEVICE_BUS_EXTENDER,
FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
FALSE,
&deviceObject);
if (!NT_SUCCESS(status))
{
ERR("Failed to create FDO 0x%x\n", status);
return status;
}
PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, sizeof(*deviceExtension));
deviceExtension->IsFDO = TRUE;
deviceExtension->DeviceObject = deviceObject;
deviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
deviceExtension->PhysicalDiskDO = PhysicalDeviceObject;
KeInitializeEvent(&deviceExtension->SyncEvent, SynchronizationEvent, TRUE);
// the the attaching failed
if (!deviceExtension->LowerDevice)
{
IoDeleteDevice(deviceObject);
return STATUS_DEVICE_REMOVED;
}
deviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
// device is initialized
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
static
NTSTATUS
NTAPI
PartMgrDeviceControl(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
NTSTATUS status;
// Note: IRP_MJ_DEVICE_CONTROL handler in the storage stack must be able to pass IOCTLs
// at an IRQL higher than PASSIVE_LEVEL
INFO("IRP_MJ_DEVICE_CONTROL %p Irp %p IOCTL %x isFdo: %u\n",
DeviceObject, Irp, ioStack->Parameters.DeviceIoControl.IoControlCode, fdoExtension->IsFDO);
if (!fdoExtension->IsFDO)
{
return PartitionHandleDeviceControl(DeviceObject, Irp);
}
switch (ioStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
status = FdoIoctlDiskGetDriveGeometryEx(fdoExtension, Irp);
break;
case IOCTL_DISK_GET_PARTITION_INFO:
status = FdoIoctlDiskGetPartitionInfo(fdoExtension, Irp);
break;
case IOCTL_DISK_GET_PARTITION_INFO_EX:
status = FdoIoctlDiskGetPartitionInfoEx(fdoExtension, Irp);
break;
case IOCTL_DISK_GET_DRIVE_LAYOUT:
status = FdoIoctlDiskGetDriveLayout(fdoExtension, Irp);
break;
case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
status = FdoIoctlDiskGetDriveLayoutEx(fdoExtension, Irp);
break;
case IOCTL_DISK_SET_DRIVE_LAYOUT:
status = FdoIoctlDiskSetDriveLayout(fdoExtension, Irp);
break;
case IOCTL_DISK_SET_DRIVE_LAYOUT_EX:
status = FdoIoctlDiskSetDriveLayoutEx(fdoExtension, Irp);
break;
case IOCTL_DISK_UPDATE_PROPERTIES:
status = FdoIoctlDiskUpdateProperties(fdoExtension, Irp);
break;
case IOCTL_DISK_CREATE_DISK:
status = FdoIoctlDiskCreateDisk(fdoExtension, Irp);
break;
case IOCTL_DISK_DELETE_DRIVE_LAYOUT:
status = FdoIoctlDiskDeleteDriveLayout(fdoExtension, Irp);
break;
// case IOCTL_DISK_GROW_PARTITION: // todo
default:
return ForwardIrpAndForget(DeviceObject, Irp);
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
static
CODE_SEG("PAGE")
NTSTATUS
NTAPI
PartMgrPnp(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
PAGED_CODE();
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
INFO("IRP_MJ_PNP %p Irp %p %s isFDO: %u\n",
DeviceObject, Irp, GetIRPMinorFunctionString(ioStack->MinorFunction), fdoExtension->IsFDO);
if (!fdoExtension->IsFDO)
{
return PartitionHandlePnp(DeviceObject, Irp);
}
switch (ioStack->MinorFunction) {
case IRP_MN_START_DEVICE:
{
NTSTATUS status;
// if this is sent to the FDO so we should forward it down the
// attachment chain before we can start the FDO
if (!IoForwardIrpSynchronously(fdoExtension->LowerDevice, Irp))
{
status = STATUS_UNSUCCESSFUL;
}
else
{
status = FdoHandleStartDevice(fdoExtension, Irp);
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
return FdoHandleDeviceRelations(fdoExtension, Irp);
}
case IRP_MN_SURPRISE_REMOVAL:
{
return FdoHandleSurpriseRemoval(fdoExtension, Irp);
}
case IRP_MN_REMOVE_DEVICE:
{
return FdoHandleRemoveDevice(fdoExtension, Irp);
}
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
{
Irp->IoStatus.Status = STATUS_SUCCESS;
// fallthrough
}
default:
{
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(fdoExtension->LowerDevice, Irp);
}
}
}
static
NTSTATUS
NTAPI
PartMgrReadWrite(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
if (!partExt->IsFDO)
{
if (!partExt->IsEnumerated)
{
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
{
ioStack->Parameters.Read.ByteOffset.QuadPart += partExt->StartingOffset;
}
}
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(partExt->LowerDevice, Irp);
}
DRIVER_DISPATCH PartMgrPower;
NTSTATUS
NTAPI
PartMgrPower(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
PoStartNextPowerIrp(Irp);
if (!partExt->IsFDO)
{
NTSTATUS status;
if (!partExt->IsEnumerated)
{
status = STATUS_DEVICE_DOES_NOT_EXIST;
}
else if (ioStack->MinorFunction == IRP_MN_SET_POWER ||
ioStack->MinorFunction == IRP_MN_QUERY_POWER)
{
status = STATUS_SUCCESS;
}
else
{
status = Irp->IoStatus.Status;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
else
{
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(partExt->LowerDevice, Irp);
}
}
DRIVER_DISPATCH PartMgrShutdownFlush;
NTSTATUS
NTAPI
PartMgrShutdownFlush(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp)
{
PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
PDEVICE_OBJECT lowerDevice;
// forward to the partition0 device in both cases
if (!partExt->IsFDO)
{
if (!partExt->IsEnumerated)
{
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
{
PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension;
lowerDevice = fdoExtension->LowerDevice;
}
}
else
{
lowerDevice = partExt->LowerDevice;
}
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(lowerDevice, Irp);
}
CODE_SEG("PAGE")
VOID
NTAPI
PartMgrUnload(
_In_ PDRIVER_OBJECT DriverObject)
{
}
CODE_SEG("INIT")
NTSTATUS
NTAPI
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload = PartMgrUnload;
DriverObject->DriverExtension->AddDevice = PartMgrAddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = ForwardIrpAndForget;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = ForwardIrpAndForget;
DriverObject->MajorFunction[IRP_MJ_READ] = PartMgrReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = PartMgrReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PartMgrDeviceControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = PartMgrPnp;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = PartMgrShutdownFlush;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = PartMgrShutdownFlush;
DriverObject->MajorFunction[IRP_MJ_POWER] = PartMgrPower;
return STATUS_SUCCESS;
}