mirror of
https://github.com/reactos/reactos.git
synced 2024-08-29 22:58:34 +00:00
793 lines
25 KiB
C
793 lines
25 KiB
C
/*
|
|
* 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@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();
|
|
|
|
// 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)
|
|
{
|
|
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();
|
|
|
|
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:
|
|
{
|
|
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 = FALSE;
|
|
|
|
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;
|
|
}
|