https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bd8226afe7f34c9135db1…
commit bd8226afe7f34c9135db1543638144177aab2081
Author: Victor Perevertkin <victor.perevertkin(a)reactos.org>
AuthorDate: Fri Nov 13 03:04:15 2020 +0300
Commit: Victor Perevertkin <victor.perevertkin(a)reactos.org>
CommitDate: Fri Nov 13 03:04:15 2020 +0300
[PARTMGR] Add the Partition Manager driver
This driver works as complement to disk.sys/classpnp.sys from Windows 10
Manages partition PDOs and exposes them as volumes to mountmgr.sys.
The driver is almost complete, just some minor IOCTLs missing (will be
added on demand)
---
drivers/storage/CMakeLists.txt | 1 +
drivers/storage/partmgr/CMakeLists.txt | 19 +
drivers/storage/partmgr/debug.h | 14 +
drivers/storage/partmgr/guid.c | 11 +
drivers/storage/partmgr/partition.c | 816 ++++++++++++++++++
drivers/storage/partmgr/partmgr.c | 1373 +++++++++++++++++++++++++++++++
drivers/storage/partmgr/partmgr.h | 192 +++++
drivers/storage/partmgr/partmgr.rc | 5 +
drivers/storage/partmgr/partmgr_reg.inf | 7 +
drivers/storage/partmgr/utils.c | 73 ++
10 files changed, 2511 insertions(+)
diff --git a/drivers/storage/CMakeLists.txt b/drivers/storage/CMakeLists.txt
index b3f0f02a4c4..44c5131d8f6 100644
--- a/drivers/storage/CMakeLists.txt
+++ b/drivers/storage/CMakeLists.txt
@@ -2,4 +2,5 @@ add_subdirectory(class)
add_subdirectory(floppy)
add_subdirectory(ide)
add_subdirectory(mountmgr)
+add_subdirectory(partmgr)
add_subdirectory(port)
diff --git a/drivers/storage/partmgr/CMakeLists.txt
b/drivers/storage/partmgr/CMakeLists.txt
new file mode 100644
index 00000000000..275fc305fb4
--- /dev/null
+++ b/drivers/storage/partmgr/CMakeLists.txt
@@ -0,0 +1,19 @@
+
+list(APPEND SOURCE
+ partition.c
+ partmgr.c
+ utils.c)
+
+list(APPEND PCH_SKIP_SOURCE
+ guid.c)
+
+add_library(partmgr MODULE
+ ${SOURCE}
+ ${PCH_SKIP_SOURCE}
+ partmgr.rc)
+
+add_pch(partmgr partmgr.h "${PCH_SKIP_SOURCE}")
+set_module_type(partmgr kernelmodedriver)
+add_importlibs(partmgr ntoskrnl hal)
+add_registry_inf(partmgr_reg.inf)
+add_cd_file(TARGET partmgr DESTINATION reactos/system32/drivers NO_CAB FOR all)
diff --git a/drivers/storage/partmgr/debug.h b/drivers/storage/partmgr/debug.h
new file mode 100644
index 00000000000..4ff75db66e3
--- /dev/null
+++ b/drivers/storage/partmgr/debug.h
@@ -0,0 +1,14 @@
+/*
+ * PROJECT: Partition manager driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Debug helpers
+ * COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin(a)reactos.org)
+ */
+
+#include <reactos/debug.h>
+
+#define ERR(fmt, ...) ERR__(DPFLTR_DISK_ID, fmt, ##__VA_ARGS__)
+#define WARN(fmt, ...) WARN__(DPFLTR_DISK_ID, fmt, ##__VA_ARGS__)
+#define TRACE(fmt, ...) TRACE__(DPFLTR_DISK_ID, fmt, ##__VA_ARGS__)
+#define INFO(fmt, ...) INFO__(DPFLTR_DISK_ID, fmt, ##__VA_ARGS__)
+// #define FDPRINT(lvl, fmt, ...) FDPRINT__(DPFLTR_DISK_ID, lvl, fmt, __VA_ARGS__)
diff --git a/drivers/storage/partmgr/guid.c b/drivers/storage/partmgr/guid.c
new file mode 100644
index 00000000000..9aa431750c7
--- /dev/null
+++ b/drivers/storage/partmgr/guid.c
@@ -0,0 +1,11 @@
+/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
+
+#include <ntdef.h>
+#include <initguid.h>
+#include <wdmguid.h>
+
+#define DEVICE_TYPE ULONG
+#include <ntdddisk.h>
+#include <ioevent.h>
+
+/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */
diff --git a/drivers/storage/partmgr/partition.c b/drivers/storage/partmgr/partition.c
new file mode 100644
index 00000000000..694836d3ae0
--- /dev/null
+++ b/drivers/storage/partmgr/partition.c
@@ -0,0 +1,816 @@
+/*
+ * PROJECT: Partition manager driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Partition device code
+ * COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin(a)reactos.org)
+ */
+
+#include "partmgr.h"
+
+static const WCHAR PartitionSymLinkFormat[] =
L"\\Device\\Harddisk%u\\Partition%u";
+
+
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionCreateDevice(
+ _In_ PDEVICE_OBJECT FDObject,
+ _In_ PPARTITION_INFORMATION_EX PartitionEntry,
+ _In_ UINT32 PdoNumber,
+ _In_ PARTITION_STYLE PartitionStyle,
+ _Out_ PDEVICE_OBJECT *PDO)
+{
+ PAGED_CODE();
+
+ static UINT32 HarddiskVolumeNextId = 1; // this is 1-based
+
+ WCHAR nameBuf[64];
+ UNICODE_STRING deviceName;
+
+ // create the device object
+
+ swprintf(nameBuf, L"\\Device\\HarddiskVolume%u", HarddiskVolumeNextId++);
+ RtlCreateUnicodeString(&deviceName, nameBuf);
+
+ PDEVICE_OBJECT partitionDevice;
+ NTSTATUS status = IoCreateDevice(FDObject->DriverObject,
+ sizeof(PARTITION_EXTENSION),
+ &deviceName,
+ FILE_DEVICE_DISK,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &partitionDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ ERR("Unable to create device object %wZ\n", &deviceName);
+ return status;
+ }
+
+ INFO("Created device object %p %wZ\n", partitionDevice, &deviceName);
+
+ PPARTITION_EXTENSION partExt = partitionDevice->DeviceExtension;
+ RtlZeroMemory(partExt, sizeof(*partExt));
+
+ partitionDevice->StackSize = FDObject->StackSize;
+ partitionDevice->Flags |= DO_DIRECT_IO;
+
+ if (PartitionStyle == PARTITION_STYLE_MBR)
+ {
+ partExt->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType;
+ partExt->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator;
+ partExt->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors;
+ }
+ else
+ {
+ partExt->Gpt.PartitionType = PartitionEntry->Gpt.PartitionType;
+ partExt->Gpt.PartitionId = PartitionEntry->Gpt.PartitionType;
+ partExt->Gpt.Attributes = PartitionEntry->Gpt.Attributes;
+
+ RtlCopyMemory(partExt->Gpt.Name, PartitionEntry->Gpt.Name,
sizeof(partExt->Gpt.Name));
+ }
+
+ partExt->DeviceName = deviceName;
+ partExt->StartingOffset = PartitionEntry->StartingOffset.QuadPart;
+ partExt->PartitionLength = PartitionEntry->PartitionLength.QuadPart;
+ partExt->OnDiskNumber = PartitionEntry->PartitionNumber; // the
"physical" partition number
+ partExt->DetectedNumber = PdoNumber; // counts only partitions with PDO created
+
+ partExt->DeviceObject = partitionDevice;
+ partExt->LowerDevice = FDObject;
+
+ partitionDevice->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ *PDO = partitionDevice;
+
+ return status;
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionHandleStartDevice(
+ _In_ PPARTITION_EXTENSION PartExt,
+ _In_ PIRP Irp)
+{
+ PAGED_CODE();
+
+ // fix the damn kernel!
+ if (PartExt->DeviceRemoved)
+ {
+ DPRINT1("IRP_MN_START_DEVICE after IRP_MN_REMOVE_DEVICE!\n");
+ return STATUS_SUCCESS;
+ }
+
+ // first, create a symbolic link for our device
+ WCHAR nameBuf[64];
+ UNICODE_STRING partitionSymlink, interfaceName;
+ PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension;
+
+ // \\Device\\Harddisk%u\\Partition%u
+ swprintf(nameBuf, PartitionSymLinkFormat,
+ fdoExtension->DiskData.DeviceNumber, PartExt->DetectedNumber);
+
+ if (!RtlCreateUnicodeString(&partitionSymlink, nameBuf))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NTSTATUS status = IoCreateSymbolicLink(&partitionSymlink,
&PartExt->DeviceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ PartExt->SymlinkCreated = TRUE;
+
+ TRACE("Symlink created %wZ -> %wZ\n", &PartExt->DeviceName,
&partitionSymlink);
+
+ // our partition device will have two interfaces:
+ // GUID_DEVINTERFACE_PARTITION and GUID_DEVINTERFACE_VOLUME
+ // the former one is used to notify mountmgr about new device
+
+ status = IoRegisterDeviceInterface(PartExt->DeviceObject,
+ &GUID_DEVINTERFACE_PARTITION,
+ NULL,
+ &interfaceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ PartExt->PartitionInterfaceName = interfaceName;
+ status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
+
+ INFO("Partition interface %wZ\n", &interfaceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ RtlFreeUnicodeString(&interfaceName);
+ RtlInitUnicodeString(&PartExt->PartitionInterfaceName, NULL);
+ return status;
+ }
+
+ status = IoRegisterDeviceInterface(PartExt->DeviceObject,
+ &GUID_DEVINTERFACE_VOLUME,
+ NULL,
+ &interfaceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ PartExt->VolumeInterfaceName = interfaceName;
+ status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
+
+ INFO("Volume interface %wZ\n", &interfaceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ RtlFreeUnicodeString(&interfaceName);
+ RtlInitUnicodeString(&PartExt->VolumeInterfaceName, NULL);
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionHandleRemove(
+ _In_ PPARTITION_EXTENSION PartExt,
+ _In_ BOOLEAN FinalRemove)
+{
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ // remove the symbolic link
+ if (PartExt->SymlinkCreated)
+ {
+ WCHAR nameBuf[64];
+ UNICODE_STRING partitionSymlink;
+ PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension;
+
+ swprintf(nameBuf, PartitionSymLinkFormat,
+ fdoExtension->DiskData.DeviceNumber, PartExt->DetectedNumber);
+
+ RtlInitUnicodeString(&partitionSymlink, nameBuf);
+
+ status = IoDeleteSymbolicLink(&partitionSymlink);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+ PartExt->SymlinkCreated = FALSE;
+
+ INFO("Symlink removed %wZ -> %wZ\n", &PartExt->DeviceName,
&partitionSymlink);
+ }
+
+ // release device interfaces
+ if (PartExt->PartitionInterfaceName.Buffer)
+ {
+ status = IoSetDeviceInterfaceState(&PartExt->PartitionInterfaceName,
FALSE);
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+ RtlFreeUnicodeString(&PartExt->PartitionInterfaceName);
+ RtlInitUnicodeString(&PartExt->PartitionInterfaceName, NULL);
+ }
+
+ if (PartExt->VolumeInterfaceName.Buffer)
+ {
+ status = IoSetDeviceInterfaceState(&PartExt->VolumeInterfaceName, FALSE);
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+ RtlFreeUnicodeString(&PartExt->VolumeInterfaceName);
+ RtlInitUnicodeString(&PartExt->VolumeInterfaceName, NULL);
+ }
+
+ if (FinalRemove)
+ {
+ // fix the damn kernel!
+ if (PartExt->DeviceRemoved)
+ {
+ DPRINT1("Double IRP_MN_REMOVE_DEVICE!\n");
+ return STATUS_SUCCESS;
+ }
+
+ PartExt->DeviceRemoved = TRUE;
+
+ ASSERT(PartExt->DeviceName.Buffer);
+ if (PartExt->DeviceName.Buffer)
+ {
+ INFO("Removed device %wZ\n", &PartExt->DeviceName);
+ RtlFreeUnicodeString(&PartExt->DeviceName);
+ }
+
+ IoDeleteDevice(PartExt->DeviceObject);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionHandleDeviceRelations(
+ _In_ PPARTITION_EXTENSION PartExt,
+ _In_ PIRP Irp)
+{
+ PAGED_CODE();
+
+ // fix the damn kernel!
+ if (PartExt->DeviceRemoved)
+ {
+ DPRINT1("QDR after device removal!\n");
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ DEVICE_RELATION_TYPE type = ioStack->Parameters.QueryDeviceRelations.Type;
+
+ if (type == TargetDeviceRelation)
+ {
+ // Device relations has one entry built in to it's size.
+ PDEVICE_RELATIONS deviceRelations =
+ ExAllocatePoolZero(PagedPool, sizeof(DEVICE_RELATIONS), TAG_PARTMGR);
+
+ if (deviceRelations != NULL)
+ {
+ deviceRelations->Count = 1;
+ deviceRelations->Objects[0] = PartExt->DeviceObject;
+ ObReferenceObject(deviceRelations->Objects[0]);
+
+ Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ Irp->IoStatus.Information = 0;
+ return Irp->IoStatus.Status;
+ }
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionHandleQueryId(
+ _In_ PPARTITION_EXTENSION PartExt,
+ _In_ PIRP Irp)
+{
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ BUS_QUERY_ID_TYPE idType = ioStack->Parameters.QueryId.IdType;
+ UNICODE_STRING idString;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ switch (idType)
+ {
+ case BusQueryDeviceID:
+ status = RtlCreateUnicodeString(&idString,
L"STORAGE\\Partition")
+ ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ case BusQueryHardwareIDs:
+ case BusQueryCompatibleIDs:
+ {
+ static WCHAR volumeID[] = L"STORAGE\\Volume\0";
+
+ idString.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(volumeID),
TAG_PARTMGR);
+ RtlCopyMemory(idString.Buffer, volumeID, sizeof(volumeID));
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+ case BusQueryInstanceID:
+ {
+ WCHAR string[64];
+ PFDO_EXTENSION fdoExtension = PartExt->LowerDevice->DeviceExtension;
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
+ {
+ swprintf(string, L"S%08lx_O%I64x_L%I64x",
+ fdoExtension->DiskData.Mbr.Signature,
+ PartExt->StartingOffset,
+ PartExt->PartitionLength);
+ }
+ else
+ {
+ swprintf(string,
+
L"S%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02xS_O%I64x_L%I64x",
+ fdoExtension->DiskData.Gpt.DiskId.Data1,
+ fdoExtension->DiskData.Gpt.DiskId.Data2,
+ fdoExtension->DiskData.Gpt.DiskId.Data3,
+ fdoExtension->DiskData.Gpt.DiskId.Data4[0],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[1],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[2],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[3],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[4],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[5],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[6],
+ fdoExtension->DiskData.Gpt.DiskId.Data4[7],
+ PartExt->StartingOffset,
+ PartExt->PartitionLength);
+ }
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ status = RtlCreateUnicodeString(&idString, string)
+ ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ Irp->IoStatus.Information = NT_SUCCESS(status) ? (ULONG_PTR) idString.Buffer : 0;
+ return status;
+}
+
+static
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionHandleQueryCapabilities(
+ _In_ PPARTITION_EXTENSION PartExt,
+ _In_ PIRP Irp)
+{
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ PDEVICE_CAPABILITIES devCaps =
ioStack->Parameters.DeviceCapabilities.Capabilities;
+
+ PAGED_CODE();
+ ASSERT(devCaps);
+
+ devCaps->SilentInstall = TRUE;
+ devCaps->RawDeviceOK = TRUE;
+ devCaps->NoDisplayInUI = TRUE;
+ devCaps->Address = PartExt->OnDiskNumber;
+ devCaps->UniqueID = 1;
+
+ return STATUS_SUCCESS;
+}
+
+CODE_SEG("PAGE")
+NTSTATUS
+PartitionHandlePnp(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp)
+{
+ PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ switch (ioStack->MinorFunction)
+ {
+ case IRP_MN_START_DEVICE:
+ {
+ status = PartitionHandleStartDevice(partExt, Irp);
+ break;
+ }
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ {
+ status = PartitionHandleDeviceRelations(partExt, Irp);
+ break;
+ }
+ 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:
+ {
+ status = STATUS_SUCCESS;
+ break;
+ }
+ case IRP_MN_SURPRISE_REMOVAL:
+ {
+ status = PartitionHandleRemove(partExt, FALSE);
+ break;
+ }
+ case IRP_MN_REMOVE_DEVICE:
+ {
+ status = PartitionHandleRemove(partExt, TRUE);
+ break;
+ }
+ case IRP_MN_QUERY_ID:
+ {
+ status = PartitionHandleQueryId(partExt, Irp);
+ break;
+ }
+ case IRP_MN_QUERY_CAPABILITIES:
+ {
+ status = PartitionHandleQueryCapabilities(partExt, Irp);
+ break;
+ }
+ default:
+ {
+ Irp->IoStatus.Information = 0;
+ status = STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return status;
+}
+
+NTSTATUS
+PartitionHandleDeviceControl(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp)
+{
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ PPARTITION_EXTENSION partExt = DeviceObject->DeviceExtension;
+ PFDO_EXTENSION fdoExtension = partExt->LowerDevice->DeviceExtension;
+ NTSTATUS status;
+
+ ASSERT(!partExt->IsFDO);
+
+ if (!partExt->IsEnumerated)
+ {
+ Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ switch (ioStack->Parameters.DeviceIoControl.IoControlCode)
+ {
+ // disk stuff
+ case IOCTL_DISK_GET_PARTITION_INFO:
+ {
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(PARTITION_INFORMATION)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ // not supported on anything other than MBR
+ if (fdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_MBR)
+ {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ PartMgrReleaseLayoutLock(fdoExtension);
+ break;
+ }
+
+ PPARTITION_INFORMATION partInfo = Irp->AssociatedIrp.SystemBuffer;
+
+ *partInfo = (PARTITION_INFORMATION){
+ .PartitionType = partExt->Mbr.PartitionType,
+ .StartingOffset.QuadPart = partExt->StartingOffset,
+ .PartitionLength.QuadPart = partExt->PartitionLength,
+ .HiddenSectors = partExt->Mbr.HiddenSectors,
+ .PartitionNumber = partExt->DetectedNumber,
+ .BootIndicator = partExt->Mbr.BootIndicator,
+ .RecognizedPartition = partExt->Mbr.RecognizedPartition,
+ .RewritePartition = FALSE,
+ };
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ Irp->IoStatus.Information = sizeof(*partInfo);
+ status = STATUS_SUCCESS;
+ break;
+ }
+ case IOCTL_DISK_GET_PARTITION_INFO_EX:
+ {
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(PARTITION_INFORMATION_EX)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ PPARTITION_INFORMATION_EX partInfoEx = Irp->AssociatedIrp.SystemBuffer;
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ *partInfoEx = (PARTITION_INFORMATION_EX){
+ .StartingOffset.QuadPart = partExt->StartingOffset,
+ .PartitionLength.QuadPart = partExt->PartitionLength,
+ .PartitionNumber = partExt->DetectedNumber,
+ .PartitionStyle = fdoExtension->DiskData.PartitionStyle,
+ .RewritePartition = FALSE,
+ };
+
+ if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
+ {
+ partInfoEx->Mbr = (PARTITION_INFORMATION_MBR){
+ .PartitionType = partExt->Mbr.PartitionType,
+ .HiddenSectors = partExt->Mbr.HiddenSectors,
+ .BootIndicator = partExt->Mbr.BootIndicator,
+ .RecognizedPartition = partExt->Mbr.RecognizedPartition,
+ };
+ }
+ else
+ {
+ partInfoEx->Gpt = (PARTITION_INFORMATION_GPT){
+ .PartitionType = partExt->Gpt.PartitionType,
+ .PartitionId = partExt->Gpt.PartitionId,
+ .Attributes = partExt->Gpt.Attributes,
+ };
+
+ RtlCopyMemory(partInfoEx->Gpt.Name,
+ partExt->Gpt.Name,
+ sizeof(partInfoEx->Gpt.Name));
+ }
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ Irp->IoStatus.Information = sizeof(*partInfoEx);
+ status = STATUS_SUCCESS;
+ break;
+ }
+ case IOCTL_DISK_SET_PARTITION_INFO:
+ {
+ PSET_PARTITION_INFORMATION inputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ if (!VerifyIrpInBufferSize(Irp, sizeof(*inputBuffer)))
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ // these functions use on disk numbers, not detected ones
+ status = IoSetPartitionInformation(fdoExtension->LowerDevice,
+ fdoExtension->DiskData.BytesPerSector,
+ partExt->OnDiskNumber,
+ inputBuffer->PartitionType);
+
+ if (NT_SUCCESS(status))
+ {
+ partExt->Mbr.PartitionType = inputBuffer->PartitionType;
+ }
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ Irp->IoStatus.Information = 0;
+ break;
+ }
+ case IOCTL_DISK_SET_PARTITION_INFO_EX:
+ {
+ PSET_PARTITION_INFORMATION_EX inputBuffer =
Irp->AssociatedIrp.SystemBuffer;
+ if (!VerifyIrpInBufferSize(Irp, sizeof(*inputBuffer)))
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ // these functions use on disk numbers, not detected ones
+ status = IoSetPartitionInformationEx(fdoExtension->LowerDevice,
+ partExt->OnDiskNumber,
+ inputBuffer);
+
+ if (NT_SUCCESS(status))
+ {
+ if (fdoExtension->DiskData.PartitionStyle == PARTITION_STYLE_MBR)
+ {
+ partExt->Mbr.PartitionType = inputBuffer->Mbr.PartitionType;
+ }
+ else
+ {
+ partExt->Gpt.PartitionType = inputBuffer->Gpt.PartitionType;
+ partExt->Gpt.PartitionId = inputBuffer->Gpt.PartitionId;
+ partExt->Gpt.Attributes = inputBuffer->Gpt.Attributes;
+
+ RtlMoveMemory(partExt->Gpt.Name,
+ inputBuffer->Gpt.Name,
+ sizeof(partExt->Gpt.Name));
+ }
+ }
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ Irp->IoStatus.Information = 0;
+ break;
+ }
+ case IOCTL_DISK_GET_LENGTH_INFO:
+ {
+ PGET_LENGTH_INFORMATION lengthInfo = Irp->AssociatedIrp.SystemBuffer;
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(*lengthInfo)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ lengthInfo->Length.QuadPart = partExt->PartitionLength;
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(*lengthInfo);
+ break;
+ }
+ case IOCTL_DISK_VERIFY:
+ {
+ PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
+ if (!VerifyIrpInBufferSize(Irp, sizeof(*verifyInfo)))
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ // Partition device should just adjust the starting offset
+ verifyInfo->StartingOffset.QuadPart += partExt->StartingOffset;
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ case IOCTL_DISK_UPDATE_PROPERTIES:
+ {
+ fdoExtension->LayoutValid = FALSE;
+ IoInvalidateDeviceRelations(fdoExtension->PhysicalDiskDO, BusRelations);
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+ case IOCTL_STORAGE_MEDIA_REMOVAL:
+ {
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+ // volume stuff (most of that should be in volmgr.sys one it is implemented)
+ case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
+ {
+ PVOLUME_DISK_EXTENTS volExts = Irp->AssociatedIrp.SystemBuffer;
+
+ // we fill only one extent entry so sizeof(*volExts) is enough
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(*volExts)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ PartMgrAcquireLayoutLock(fdoExtension);
+
+ // the only type of volume we support right now is disk partition
+ // so this structure is simple
+
+ *volExts = (VOLUME_DISK_EXTENTS) {
+ .NumberOfDiskExtents = 1,
+ .Extents = {{
+ .DiskNumber = fdoExtension->DiskData.DeviceNumber,
+ .StartingOffset.QuadPart = partExt->StartingOffset,
+ .ExtentLength.QuadPart = partExt->PartitionLength
+ }}
+ };
+
+ PartMgrReleaseLayoutLock(fdoExtension);
+
+ status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(*volExts);
+ break;
+ }
+ case IOCTL_VOLUME_ONLINE:
+ {
+ status = STATUS_SUCCESS;
+ break;
+ }
+ case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
+ {
+ PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION gptAttrs =
Irp->AssociatedIrp.SystemBuffer;
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(*gptAttrs)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ // not supported on anything other than GPT
+ if (fdoExtension->DiskData.PartitionStyle != PARTITION_STYLE_GPT)
+ {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ gptAttrs->GptAttributes = partExt->Gpt.Attributes;
+
+ status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(*gptAttrs);
+ break;
+ }
+ // mountmgr stuff
+ case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
+ {
+ PMOUNTDEV_NAME name = Irp->AssociatedIrp.SystemBuffer;
+
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ name->NameLength = partExt->DeviceName.Length;
+
+ // return NameLength back
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT) + name->NameLength))
+ {
+ Irp->IoStatus.Information = sizeof(USHORT);
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory(name->Name, partExt->DeviceName.Buffer,
name->NameLength);
+
+ status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength;
+ break;
+ }
+ case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
+ {
+ PMOUNTDEV_UNIQUE_ID uniqueId = Irp->AssociatedIrp.SystemBuffer;
+
+ if (!partExt->VolumeInterfaceName.Buffer)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT)))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ uniqueId->UniqueIdLength = partExt->VolumeInterfaceName.Length;
+
+ // return UniqueIdLength back
+ if (!VerifyIrpOutBufferSize(Irp, sizeof(USHORT) +
uniqueId->UniqueIdLength))
+ {
+ Irp->IoStatus.Information = sizeof(USHORT);
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory(uniqueId->UniqueId,
+ partExt->VolumeInterfaceName.Buffer,
+ uniqueId->UniqueIdLength);
+
+ status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = sizeof(USHORT) + uniqueId->UniqueIdLength;
+ break;
+ }
+ default:
+ return ForwardIrpAndForget(DeviceObject, Irp);
+ }
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return status;
+}
diff --git a/drivers/storage/partmgr/partmgr.c b/drivers/storage/partmgr/partmgr.c
new file mode 100644
index 00000000000..8abfdccedd6
--- /dev/null
+++ b/drivers/storage/partmgr/partmgr.c
@@ -0,0 +1,1373 @@
+/*
+ * 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(a)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;
+}
+
+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;
+ }
+
+ 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 in the beginning
+ partExt->ListEntry.Next = FdoExtension->PartitionList.Next;
+ FdoExtension->PartitionList.Next = &partExt->ListEntry;
+ }
+
+ partExt->Attached = TRUE;
+ }
+
+ FdoExtension->EnumeratedPartitionsTotal = totalPartitions;
+}
+
+// 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;
+
+ *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;
+ size_t 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);
+
+ // 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;
+ }
+ }
+ 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,
+ ¬ification,
+ 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 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;
+ }
+ 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,
+ ¬ification,
+ 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;
+ return status;
+}
+
+// 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;
+ }
+
+ 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;
+ }
+
+ 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);
+
+ // PartMgrAcquireLayoutLock calls PartMgrGetDriveLayout inside
+ // so we're sure here that it returns only 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();
+
+ for (PSINGLE_LIST_ENTRY curEntry = FdoExtension->PartitionList.Next;
+ curEntry != NULL;
+ curEntry = curEntry->Next)
+ {
+ PPARTITION_EXTENSION partExt = CONTAINING_RECORD(curEntry,
+ PARTITION_EXTENSION,
+ ListEntry);
+
+ ASSERT(partExt->DeviceRemoved);
+ }
+
+ // 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;
+}
diff --git a/drivers/storage/partmgr/partmgr.h b/drivers/storage/partmgr/partmgr.h
new file mode 100644
index 00000000000..05a0ee6bbbd
--- /dev/null
+++ b/drivers/storage/partmgr/partmgr.h
@@ -0,0 +1,192 @@
+/*
+ * PROJECT: Partition manager driver
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Main header
+ * COPYRIGHT: 2020 Victor Perevertkin (victor.perevertkin(a)reactos.org)
+ */
+
+#ifndef _PARTMGR_H_
+#define _PARTMGR_H_
+
+#include <ntifs.h>
+#include <mountdev.h>
+#include <ntddvol.h>
+#include <ntdddisk.h>
+#include <ndk/psfuncs.h>
+#include <ndk/section_attribs.h>
+#include <ioevent.h>
+#include <stdio.h>
+#include <debug/driverdbg.h>
+
+#include "debug.h"
+
+#define TAG_PARTMGR 'MtrP'
+
+// from disk.sys
+typedef struct _DISK_GEOMETRY_EX_INTERNAL
+{
+ DISK_GEOMETRY Geometry;
+ INT64 DiskSize;
+ DISK_PARTITION_INFO Partition;
+ DISK_DETECTION_INFO Detection;
+} DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
+
+typedef struct _FDO_EXTENSION
+{
+ BOOLEAN IsFDO;
+ PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT LowerDevice;
+ PDEVICE_OBJECT PhysicalDiskDO;
+ KEVENT SyncEvent;
+
+ BOOLEAN LayoutValid;
+ PDRIVE_LAYOUT_INFORMATION_EX LayoutCache;
+
+ SINGLE_LIST_ENTRY PartitionList;
+ UINT32 EnumeratedPartitionsTotal;
+
+ struct {
+ UINT64 DiskSize;
+ UINT32 DeviceNumber;
+ UINT32 BytesPerSector;
+ PARTITION_STYLE PartitionStyle;
+ union {
+ struct {
+ UINT32 Signature;
+ } Mbr;
+ struct {
+ GUID DiskId;
+ } Gpt;
+ };
+ } DiskData;
+} FDO_EXTENSION, *PFDO_EXTENSION;
+
+typedef struct _PARTITION_EXTENSION
+{
+ BOOLEAN IsFDO;
+ PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT LowerDevice;
+ PDEVICE_OBJECT Part0Device;
+
+ UINT64 StartingOffset;
+ UINT64 PartitionLength;
+ SINGLE_LIST_ENTRY ListEntry;
+
+ UINT32 DetectedNumber;
+ UINT32 OnDiskNumber; // partition number for issuing Io requests to the kernel
+ BOOLEAN IsEnumerated; // reported via IRP_MN_QUERY_DEVICE_RELATIONS
+ BOOLEAN SymlinkCreated;
+ BOOLEAN DeviceRemoved; // !!!
+ BOOLEAN Attached; // attached to PartitionList of the FDO
+ union
+ {
+ struct
+ {
+ GUID PartitionType;
+ GUID PartitionId;
+ UINT64 Attributes;
+ WCHAR Name[36];
+ } Gpt;
+ struct
+ {
+ UINT8 PartitionType;
+ BOOLEAN BootIndicator;
+ BOOLEAN RecognizedPartition;
+ UINT32 HiddenSectors;
+ } Mbr;
+ };
+ UNICODE_STRING PartitionInterfaceName;
+ UNICODE_STRING VolumeInterfaceName;
+ UNICODE_STRING DeviceName;
+} PARTITION_EXTENSION, *PPARTITION_EXTENSION;
+
+NTSTATUS
+PartitionCreateDevice(
+ _In_ PDEVICE_OBJECT FDObject,
+ _In_ PPARTITION_INFORMATION_EX PartitionEntry,
+ _In_ UINT32 OnDiskNumber,
+ _In_ PARTITION_STYLE PartitionStyle,
+ _Out_ PDEVICE_OBJECT *PDO);
+
+NTSTATUS
+PartitionHandleRemove(
+ _In_ PPARTITION_EXTENSION PartExt,
+ _In_ BOOLEAN FinalRemove);
+
+NTSTATUS
+PartitionHandlePnp(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp);
+
+NTSTATUS
+PartitionHandleDeviceControl(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp);
+
+NTSTATUS
+NTAPI
+ForwardIrpAndForget(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp);
+
+NTSTATUS
+IssueSyncIoControlRequest(
+ _In_ UINT32 IoControlCode,
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PVOID InputBuffer,
+ _In_ ULONG InputBufferLength,
+ _In_ PVOID OutputBuffer,
+ _In_ ULONG OutputBufferLength,
+ _In_ BOOLEAN InternalDeviceIoControl);
+
+inline
+BOOLEAN
+VerifyIrpOutBufferSize(
+ _In_ PIRP Irp,
+ _In_ SIZE_T Size)
+{
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ if (ioStack->Parameters.DeviceIoControl.OutputBufferLength < Size)
+ {
+ Irp->IoStatus.Information = Size;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+inline
+BOOLEAN
+VerifyIrpInBufferSize(
+ _In_ PIRP Irp,
+ _In_ SIZE_T Size)
+{
+ PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
+ if (ioStack->Parameters.DeviceIoControl.InputBufferLength < Size)
+ {
+ Irp->IoStatus.Information = Size;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+inline
+VOID
+PartMgrAcquireLayoutLock(
+ _In_ PFDO_EXTENSION FDOExtension)
+{
+ PAGED_CODE();
+
+ KeWaitForSingleObject(&FDOExtension->SyncEvent, Executive, KernelMode, FALSE,
NULL);
+}
+
+inline
+VOID
+PartMgrReleaseLayoutLock(
+ _In_ PFDO_EXTENSION FDOExtension)
+{
+ PAGED_CODE();
+
+ KeSetEvent(&FDOExtension->SyncEvent, IO_NO_INCREMENT, FALSE);
+}
+
+#endif // _PARTMGR_H_
diff --git a/drivers/storage/partmgr/partmgr.rc b/drivers/storage/partmgr/partmgr.rc
new file mode 100644
index 00000000000..29c32a5ad4e
--- /dev/null
+++ b/drivers/storage/partmgr/partmgr.rc
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "Partition Manager"
+#define REACTOS_STR_INTERNAL_NAME "partmgr"
+#define REACTOS_STR_ORIGINAL_FILENAME "partmgr.sys"
+#include <reactos/version.rc>
diff --git a/drivers/storage/partmgr/partmgr_reg.inf
b/drivers/storage/partmgr/partmgr_reg.inf
new file mode 100644
index 00000000000..de0e3c5178c
--- /dev/null
+++ b/drivers/storage/partmgr/partmgr_reg.inf
@@ -0,0 +1,7 @@
+[AddReg]
+HKLM,"SYSTEM\CurrentControlSet\Services\partmgr","ErrorControl",0x00010001,0x00000000
+HKLM,"SYSTEM\CurrentControlSet\Services\partmgr","DisplayName",0x00000000,"Partition
Manager"
+HKLM,"SYSTEM\CurrentControlSet\Services\partmgr","Group",0x00000000,"Boot
Bus Extender"
+HKLM,"SYSTEM\CurrentControlSet\Services\partmgr","ImagePath",0x00020000,"system32\drivers\partmgr.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\partmgr","Start",0x00010001,0x00000000
+HKLM,"SYSTEM\CurrentControlSet\Services\partmgr","Type",0x00010001,0x00000001
diff --git a/drivers/storage/partmgr/utils.c b/drivers/storage/partmgr/utils.c
new file mode 100644
index 00000000000..38751850dae
--- /dev/null
+++ b/drivers/storage/partmgr/utils.c
@@ -0,0 +1,73 @@
+#include "partmgr.h"
+
+NTSTATUS
+NTAPI
+ForwardIrpAndForget(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp)
+{
+ // this part of a structure is identical in both FDO and PDO
+ PDEVICE_OBJECT LowerDevice =
((PFDO_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
+
+ ASSERT(LowerDevice);
+
+ IoSkipCurrentIrpStackLocation(Irp);
+ return IoCallDriver(LowerDevice, Irp);
+}
+
+NTSTATUS
+IssueSyncIoControlRequest(
+ _In_ UINT32 IoControlCode,
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PVOID InputBuffer,
+ _In_ ULONG InputBufferLength,
+ _In_ PVOID OutputBuffer,
+ _In_ ULONG OutputBufferLength,
+ _In_ BOOLEAN InternalDeviceIoControl)
+{
+ PIRP Irp;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PKEVENT Event;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Allocate a non-paged event */
+ Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Event), TAG_PARTMGR);
+ if (!Event)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Initialize it */
+ KeInitializeEvent(Event, NotificationEvent, FALSE);
+
+ /* Build the IRP */
+ Irp = IoBuildDeviceIoControlRequest(IoControlCode,
+ DeviceObject,
+ InputBuffer,
+ InputBufferLength,
+ OutputBuffer,
+ OutputBufferLength,
+ InternalDeviceIoControl,
+ Event,
+ &IoStatusBlock);
+ if (!Irp)
+ {
+ /* Fail, free the event */
+ ExFreePoolWithTag(Event, TAG_PARTMGR);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Call the driver and check if it's pending */
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait on the driver */
+ KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
+ Status = IoStatusBlock.Status;
+ }
+
+ /* Free the event and return the Status */
+ ExFreePoolWithTag(Event, TAG_PARTMGR);
+ return Status;
+}