reactos/drivers/storage/partmgr/partition.c
2024-06-12 12:14:53 +02:00

827 lines
26 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%lu\\Partition%lu";
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;
UINT32 volumeNum;
// create the device object
volumeNum = HarddiskVolumeNextId++;
swprintf(nameBuf, L"\\Device\\HarddiskVolume%lu", volumeNum);
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->VolumeNumber = volumeNum;
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%lu\\Partition%lu
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;
INFO("Symlink created %wZ -> %wZ\n", &partitionSymlink, &PartExt->DeviceName);
// 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", &partitionSymlink, &PartExt->DeviceName);
}
// 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 have one entry built into their 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 once 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_QUERY_VOLUME_NUMBER:
{
PVOLUME_NUMBER volNum = Irp->AssociatedIrp.SystemBuffer;
if (!VerifyIrpOutBufferSize(Irp, sizeof(*volNum)))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
PartMgrAcquireLayoutLock(fdoExtension);
volNum->VolumeNumber = partExt->VolumeNumber;
RtlCopyMemory(volNum->VolumeManagerName,
L"VOLMGR ", // Must be 8 space-padded characters
sizeof(volNum->VolumeManagerName));
PartMgrReleaseLayoutLock(fdoExtension);
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(*volNum);
break;
}
case IOCTL_VOLUME_IS_PARTITION:
{
// The only type of volume we support right now is disk partition
// so we just return success. A more robust algorithm would be
// to check whether the volume has only one single extent, that
// covers the whole partition on which it lies upon. If this is
// not the case, return STATUS_UNSUCCESSFUL instead.
status = STATUS_SUCCESS;
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;
}