[ISAPNP] Refactor string handling

- Don't allocate string buffers twice.
This commit is contained in:
Dmitry Borisov 2021-03-04 18:44:20 +06:00
parent 70ba96f164
commit c92bec609b
3 changed files with 182 additions and 193 deletions

View file

@ -11,132 +11,6 @@
#define NDEBUG
#include <debug.h>
NTSTATUS
NTAPI
IsaPnpDuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString)
{
if (SourceString == NULL ||
DestinationString == NULL ||
SourceString->Length > SourceString->MaximumLength ||
(SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING ||
Flags >= 4)
{
return STATUS_INVALID_PARAMETER;
}
if ((SourceString->Length == 0) &&
(Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
{
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
DestinationString->Buffer = NULL;
}
else
{
USHORT DestMaxLength = SourceString->Length;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestMaxLength += sizeof(UNICODE_NULL);
DestinationString->Buffer = ExAllocatePool(PagedPool, DestMaxLength);
if (DestinationString->Buffer == NULL)
return STATUS_NO_MEMORY;
RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
DestinationString->Length = SourceString->Length;
DestinationString->MaximumLength = DestMaxLength;
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
}
return STATUS_SUCCESS;
}
static
NTSTATUS
NTAPI
IsaFdoCreateDeviceIDs(
IN PISAPNP_PDO_EXTENSION PdoExt)
{
PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
UNICODE_STRING TempString;
WCHAR TempBuffer[256];
PWCHAR End;
NTSTATUS Status;
USHORT i;
TempString.Buffer = TempBuffer;
TempString.MaximumLength = sizeof(TempBuffer);
TempString.Length = 0;
/* Device ID */
Status = RtlStringCbPrintfExW(TempString.Buffer,
TempString.MaximumLength / sizeof(WCHAR),
&End,
NULL, 0,
L"ISAPNP\\%.3S%04x",
LogDev->VendorId,
LogDev->ProdId);
if (!NT_SUCCESS(Status))
return Status;
TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
Status = IsaPnpDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&TempString,
&PdoExt->DeviceID);
if (!NT_SUCCESS(Status))
return Status;
/* HardwareIDs */
Status = RtlStringCbPrintfExW(TempString.Buffer,
TempString.MaximumLength / sizeof(WCHAR),
&End,
NULL, 0,
L"ISAPNP\\%.3S%04x@"
L"*%.3S%04x@",
LogDev->VendorId,
LogDev->ProdId,
LogDev->VendorId,
LogDev->ProdId);
if (!NT_SUCCESS(Status))
return Status;
TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
Status = IsaPnpDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&TempString,
&PdoExt->HardwareIDs);
if (!NT_SUCCESS(Status))
return Status;
for (i = 0; i < PdoExt->HardwareIDs.Length / sizeof(WCHAR); i++)
if (PdoExt->HardwareIDs.Buffer[i] == '@')
PdoExt->HardwareIDs.Buffer[i] = UNICODE_NULL;
/* InstanceID */
Status = RtlStringCbPrintfExW(TempString.Buffer,
TempString.MaximumLength / sizeof(WCHAR),
&End,
NULL, 0,
L"%X",
LogDev->SerialNumber);
if (!NT_SUCCESS(Status))
return Status;
TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR));
Status = IsaPnpDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&TempString,
&PdoExt->InstanceID);
if (!NT_SUCCESS(Status))
return Status;
return STATUS_SUCCESS;
}
static
CODE_SEG("PAGE")
NTSTATUS
@ -487,10 +361,7 @@ IsaPnpFillDeviceRelations(
PdoExt->IsaPnpDevice = IsaDevice;
PdoExt->FdoExt = FdoExt;
Status = IsaFdoCreateDeviceIDs(PdoExt);
if (NT_SUCCESS(Status))
Status = IsaPnpCreateLogicalDeviceRequirements(PdoExt);
Status = IsaPnpCreateLogicalDeviceRequirements(PdoExt);
if (NT_SUCCESS(Status))
Status = IsaPnpCreateLogicalDeviceResources(PdoExt);
@ -728,10 +599,6 @@ NTSTATUS
IsaPnpCreateReadPortDO(
_In_ PISAPNP_FDO_EXTENSION FdoExt)
{
UNICODE_STRING DeviceID = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0");
UNICODE_STRING HardwareIDs = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0\0");
UNICODE_STRING CompatibleIDs = RTL_CONSTANT_STRING(L"\0\0");
UNICODE_STRING InstanceID = RTL_CONSTANT_STRING(L"0\0");
PISAPNP_PDO_EXTENSION PdoExt;
NTSTATUS Status;
@ -754,30 +621,6 @@ IsaPnpCreateReadPortDO(
PdoExt->Common.State = dsStopped;
PdoExt->FdoExt = FdoExt;
Status = IsaPnpDuplicateUnicodeString(0,
&DeviceID,
&PdoExt->DeviceID);
if (!NT_SUCCESS(Status))
return Status;
Status = IsaPnpDuplicateUnicodeString(0,
&HardwareIDs,
&PdoExt->HardwareIDs);
if (!NT_SUCCESS(Status))
return Status;
Status = IsaPnpDuplicateUnicodeString(0,
&CompatibleIDs,
&PdoExt->CompatibleIDs);
if (!NT_SUCCESS(Status))
return Status;
Status = IsaPnpDuplicateUnicodeString(0,
&InstanceID,
&PdoExt->InstanceID);
if (!NT_SUCCESS(Status))
return Status;
Status = IsaPnpCreateReadPortDORequirements(PdoExt);
if (!NT_SUCCESS(Status))
return Status;

View file

@ -85,10 +85,6 @@ typedef struct _ISAPNP_PDO_EXTENSION
ISAPNP_COMMON_EXTENSION Common;
PISAPNP_LOGICAL_DEVICE IsaPnpDevice;
PISAPNP_FDO_EXTENSION FdoExt;
UNICODE_STRING DeviceID;
UNICODE_STRING HardwareIDs;
UNICODE_STRING CompatibleIDs;
UNICODE_STRING InstanceID;
PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
PCM_RESOURCE_LIST ResourceList;
ULONG ResourceListSize;
@ -115,16 +111,6 @@ IsaPnpReleaseDeviceDataLock(
/* isapnp.c */
#define RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE 1
#define RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING 2
NTSTATUS
NTAPI
IsaPnpDuplicateUnicodeString(
IN ULONG Flags,
IN PCUNICODE_STRING SourceString,
OUT PUNICODE_STRING DestinationString);
CODE_SEG("PAGE")
NTSTATUS
IsaPnpFillDeviceRelations(

View file

@ -103,47 +103,204 @@ IsaPdoQueryId(
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
{
PUNICODE_STRING Source;
PWCHAR Buffer;
PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
NTSTATUS Status;
PWCHAR Buffer, End, IdStart;
size_t CharCount, Remaining;
PAGED_CODE();
switch (IrpSp->Parameters.QueryId.IdType)
{
case BusQueryDeviceID:
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
Source = &PdoExt->DeviceID;
{
CharCount = sizeof("ISAPNP\\XXXFFFF");
Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR),
TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
&End,
&Remaining,
0,
L"ISAPNP\\%.3S%04x",
LogDev->VendorId,
LogDev->ProdId);
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
DPRINT("Device ID: '%S'\n", Buffer);
break;
}
case BusQueryHardwareIDs:
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
Source = &PdoExt->HardwareIDs;
{
CharCount = sizeof("ISAPNP\\XXXFFFF") +
sizeof("*PNPxxxx") +
sizeof(ANSI_NULL); /* multi-string */
Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR),
TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
DPRINT("Hardware IDs:\n");
/* 1 */
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
&End,
&Remaining,
0,
L"ISAPNP\\%.3S%04x",
LogDev->VendorId,
LogDev->ProdId);
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
DPRINT(" '%S'\n", Buffer);
++End;
--Remaining;
/* 2 */
IdStart = End;
Status = RtlStringCchPrintfExW(End,
Remaining,
&End,
&Remaining,
0,
L"*%.3S%04x",
LogDev->VendorId,
LogDev->ProdId);
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
DPRINT(" '%S'\n", IdStart);
*++End = UNICODE_NULL;
--Remaining;
break;
}
case BusQueryCompatibleIDs:
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
Source = &PdoExt->CompatibleIDs;
break;
return STATUS_NOT_IMPLEMENTED;
case BusQueryInstanceID:
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
Source = &PdoExt->InstanceID;
{
CharCount = sizeof(LogDev->SerialNumber) * 2 + sizeof(ANSI_NULL);
Buffer = ExAllocatePoolWithTag(PagedPool,
CharCount * sizeof(WCHAR),
TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
Status = RtlStringCchPrintfExW(Buffer,
CharCount,
NULL,
NULL,
0,
L"%X",
LogDev->SerialNumber);
if (!NT_VERIFY(NT_SUCCESS(Status)))
goto Failure;
DPRINT("Instance ID: '%S'\n", Buffer);
break;
}
default:
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n",
IrpSp->Parameters.QueryId.IdType);
return Irp->IoStatus.Status;
return Irp->IoStatus.Status;
}
if (!Source->Buffer)
return Irp->IoStatus.Status;
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_ISAPNP);
if (!Buffer)
return STATUS_NO_MEMORY;
Failure:
ExFreePoolWithTag(Buffer, TAG_ISAPNP);
return Status;
}
static
CODE_SEG("PAGE")
NTSTATUS
IsaReadPortQueryId(
_Inout_ PIRP Irp,
_In_ PIO_STACK_LOCATION IrpSp)
{
PWCHAR Buffer;
static const WCHAR ReadPortId[] = L"ISAPNP\\ReadDataPort";
PAGED_CODE();
switch (IrpSp->Parameters.QueryId.IdType)
{
case BusQueryDeviceID:
{
Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(ReadPortId), TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId));
DPRINT("Device ID: '%S'\n", Buffer);
break;
}
case BusQueryHardwareIDs:
{
Buffer = ExAllocatePoolWithTag(PagedPool,
sizeof(ReadPortId) + sizeof(UNICODE_NULL),
TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(Buffer, ReadPortId, sizeof(ReadPortId));
Buffer[sizeof(ReadPortId) / sizeof(WCHAR)] = UNICODE_NULL; /* multi-string */
DPRINT("Hardware ID: '%S'\n", Buffer);
break;
}
case BusQueryCompatibleIDs:
{
/* Empty multi-string */
Buffer = ExAllocatePoolZero(PagedPool, sizeof(UNICODE_NULL) * 2, TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
DPRINT("Compatible ID: '%S'\n", Buffer);
break;
}
case BusQueryInstanceID:
{
/* Even if there are multiple ISA buses, the driver has only one Read Port */
static const WCHAR InstanceId[] = L"0";
Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(InstanceId), TAG_ISAPNP);
if (!Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(Buffer, InstanceId, sizeof(InstanceId));
DPRINT("Instance ID: '%S'\n", Buffer);
break;
}
default:
return Irp->IoStatus.Status;
}
RtlCopyMemory(Buffer, Source->Buffer, Source->MaximumLength);
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
return STATUS_SUCCESS;
}
@ -378,7 +535,10 @@ IsaPdoPnp(
break;
case IRP_MN_QUERY_ID:
Status = IsaPdoQueryId(PdoExt, Irp, IrpSp);
if (PdoExt->IsaPnpDevice)
Status = IsaPdoQueryId(PdoExt, Irp, IrpSp);
else
Status = IsaReadPortQueryId(Irp, IrpSp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE: