reactos/drivers/storage/partmgr/partition.c
Hermès Bélusca-Maïto 0a8b421d53
[PARTMGR] Implement IOCTL_VOLUME_QUERY_VOLUME_NUMBER and IOCTL_VOLUME_IS_PARTITION (#6911)
- Implement IOCTL_VOLUME_QUERY_VOLUME_NUMBER:
  See usage example in:
  7241cebfa2/mayfield/branches/spr/src/umapps/ndassvc/service/drivematch.cpp (L627)

- Stubplement 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.
2024-06-10 21:32:47 +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;
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 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;
}