mirror of
https://github.com/reactos/reactos.git
synced 2024-09-18 16:52:54 +00:00
691 lines
19 KiB
C
691 lines
19 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: drivers/ksfilter/ks/allocators.c
|
|
* PURPOSE: KS Allocator functions
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
typedef enum
|
|
{
|
|
ALLOCATOR_NPAGED_LOOKASIDE,
|
|
ALLOCATOR_PAGED_LOOKASIDE,
|
|
ALLOCATOR_CUSTOM
|
|
}ALLOCATOR_TYPE;
|
|
|
|
typedef enum
|
|
{
|
|
ALLOCATOR_DEVICE_CONTROL,
|
|
ALLOCATOR_DEVICE_CLOSE,
|
|
ALLOCATOR_ALLOCATE,
|
|
ALLOCATOR_FREE
|
|
|
|
}ALLOC_REQUEST;
|
|
|
|
typedef PVOID (*PFNKSPAGEDPOOLALLOCATE)(IN PPAGED_LOOKASIDE_LIST Lookaside);
|
|
typedef PVOID (*PFNKSNPAGEDPOOLALLOCATE)(IN PNPAGED_LOOKASIDE_LIST Lookaside);
|
|
|
|
typedef VOID (*PFNKSPAGEDPOOLFREE)(IN PPAGED_LOOKASIDE_LIST Lookaside, IN PVOID Entry);
|
|
typedef VOID (*PFNKSNPAGEDPOOLFREE)(IN PNPAGED_LOOKASIDE_LIST Lookaside, IN PVOID Entry);
|
|
|
|
typedef VOID (NTAPI *PFNKSNPAGEDPOOLDELETE)(IN PNPAGED_LOOKASIDE_LIST Lookaside);
|
|
typedef VOID (NTAPI *PFNKSPAGEDPOOLDELETE)(IN PPAGED_LOOKASIDE_LIST Lookaside);
|
|
|
|
typedef struct
|
|
{
|
|
IKsAllocatorVtbl *lpVtbl;
|
|
LONG ref;
|
|
PKSIOBJECT_HEADER Header;
|
|
ALLOCATOR_TYPE Type;
|
|
|
|
KSSTREAMALLOCATOR_STATUS Status;
|
|
|
|
union
|
|
{
|
|
NPAGED_LOOKASIDE_LIST NPagedList;
|
|
PAGED_LOOKASIDE_LIST PagedList;
|
|
PVOID CustomList;
|
|
}u;
|
|
|
|
union
|
|
{
|
|
PFNKSDEFAULTALLOCATE DefaultAllocate;
|
|
PFNKSPAGEDPOOLALLOCATE PagedPool;
|
|
PFNKSNPAGEDPOOLALLOCATE NPagedPool;
|
|
}Allocate;
|
|
|
|
union
|
|
{
|
|
PFNKSDEFAULTFREE DefaultFree;
|
|
PFNKSPAGEDPOOLFREE PagedPool;
|
|
PFNKSNPAGEDPOOLFREE NPagedPool;
|
|
}Free;
|
|
|
|
union
|
|
{
|
|
PFNKSDELETEALLOCATOR DefaultDelete;
|
|
PFNKSNPAGEDPOOLDELETE NPagedPool;
|
|
PFNKSPAGEDPOOLDELETE PagedPool;
|
|
}Delete;
|
|
|
|
}ALLOCATOR, *PALLOCATOR;
|
|
|
|
/* use KSNAME_Allocator for IID_IKsAllocator */
|
|
const GUID IID_IKsAllocator = {0x642F5D00L, 0x4791, 0x11D0, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
|
const GUID KSPROPSETID_StreamAllocator = {0x0cf6e4342, 0xec87, 0x11cf, {0xa1, 0x30, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}};
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_Allocate(
|
|
IN PFILE_OBJECT FileObject,
|
|
PVOID *Frame);
|
|
|
|
VOID
|
|
NTAPI
|
|
IKsAllocator_FreeFrame(
|
|
IN PFILE_OBJECT FileObject,
|
|
PVOID Frame);
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_fnQueryInterface(
|
|
IKsAllocator * iface,
|
|
IN REFIID refiid,
|
|
OUT PVOID* Output)
|
|
{
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
|
|
if (IsEqualGUIDAligned(refiid, &IID_IUnknown) ||
|
|
IsEqualGUIDAligned(refiid, &IID_IKsAllocator))
|
|
{
|
|
*Output = &This->lpVtbl;
|
|
_InterlockedIncrement(&This->ref);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
IKsAllocator_fnAddRef(
|
|
IKsAllocator * iface)
|
|
{
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
IKsAllocator_fnRelease(
|
|
IKsAllocator * iface)
|
|
{
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
|
|
InterlockedDecrement(&This->ref);
|
|
|
|
if (This->ref == 0)
|
|
{
|
|
FreeItem(This);
|
|
return 0;
|
|
}
|
|
/* Return new reference count */
|
|
return This->ref;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_fnDeviceIoControl(
|
|
IKsAllocator *iface,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
PIO_STACK_LOCATION IoStack;
|
|
PKSSTREAMALLOCATOR_FUNCTIONTABLE FunctionTable;
|
|
PKSSTREAMALLOCATOR_STATUS State;
|
|
PKSPROPERTY Property;
|
|
|
|
/* FIXME locks */
|
|
|
|
/* get current irp stack */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IoStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_KS_PROPERTY)
|
|
{
|
|
/* only KSPROPERTY requests are supported */
|
|
UNIMPLEMENTED;
|
|
|
|
/* complete and forget irps */
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
|
|
{
|
|
/* invalid request */
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
/* check the request */
|
|
Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
if (IsEqualGUIDAligned(&Property->Set, &KSPROPSETID_StreamAllocator))
|
|
{
|
|
if (Property->Id == KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE)
|
|
{
|
|
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE))
|
|
{
|
|
/* buffer too small */
|
|
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
|
|
Irp->IoStatus.Information = sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE);
|
|
/* complete and forget irp */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
if (!(Property->Flags & KSPROPERTY_TYPE_GET))
|
|
{
|
|
/* only support retrieving the property */
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
/* complete and forget irp */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* get output buffer */
|
|
FunctionTable = (PKSSTREAMALLOCATOR_FUNCTIONTABLE)Irp->UserBuffer;
|
|
|
|
FunctionTable->AllocateFrame = IKsAllocator_Allocate;
|
|
FunctionTable->FreeFrame = IKsAllocator_FreeFrame;
|
|
|
|
/* save result */
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE);
|
|
/* complete request */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (Property->Id == KSPROPERTY_STREAMALLOCATOR_STATUS)
|
|
{
|
|
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KSPROPERTY_STREAMALLOCATOR_STATUS))
|
|
{
|
|
/* buffer too small */
|
|
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
|
|
Irp->IoStatus.Information = sizeof(KSPROPERTY_STREAMALLOCATOR_STATUS);
|
|
/* complete and forget irp */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
if (!(Property->Flags & KSPROPERTY_TYPE_GET))
|
|
{
|
|
/* only support retrieving the property */
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
/* complete and forget irp */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* get output buffer */
|
|
State = (PKSSTREAMALLOCATOR_STATUS)Irp->UserBuffer;
|
|
|
|
/* copy allocator status */
|
|
RtlMoveMemory(State, &This->Status, sizeof(KSSTREAMALLOCATOR_STATUS));
|
|
|
|
/* save result */
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(KSSTREAMALLOCATOR_STATUS);
|
|
|
|
/* complete request */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* unhandled request */
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_fnClose(
|
|
IKsAllocator *iface)
|
|
{
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
|
|
/* FIXME locks */
|
|
|
|
/* now close allocator */
|
|
if (This->Type == ALLOCATOR_CUSTOM)
|
|
{
|
|
This->Delete.DefaultDelete(This->u.CustomList);
|
|
}
|
|
else if (This->Type == ALLOCATOR_NPAGED_LOOKASIDE)
|
|
{
|
|
This->Delete.NPagedPool(&This->u.NPagedList);
|
|
}
|
|
else if (This->Type == ALLOCATOR_PAGED_LOOKASIDE)
|
|
{
|
|
This->Delete.PagedPool(&This->u.PagedList);
|
|
}
|
|
|
|
/* free object header */
|
|
KsFreeObjectHeader(&This->Header);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_fnAllocateFrame(
|
|
IKsAllocator *iface,
|
|
IN PVOID * OutFrame)
|
|
{
|
|
PVOID Frame = NULL;
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
|
|
/* FIXME locks */
|
|
|
|
/* now allocate frame */
|
|
if (This->Type == ALLOCATOR_CUSTOM)
|
|
{
|
|
Frame = This->Allocate.DefaultAllocate(This->u.CustomList);
|
|
}
|
|
else if (This->Type == ALLOCATOR_NPAGED_LOOKASIDE)
|
|
{
|
|
Frame = This->Allocate.NPagedPool(&This->u.NPagedList);
|
|
}
|
|
else if (This->Type == ALLOCATOR_PAGED_LOOKASIDE)
|
|
{
|
|
Frame = This->Allocate.PagedPool(&This->u.PagedList);
|
|
}
|
|
|
|
if (Frame)
|
|
{
|
|
*OutFrame = Frame;
|
|
InterlockedIncrement((PLONG)&This->Status.AllocatedFrames);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IKsAllocator_fnFreeFrame(
|
|
IKsAllocator *iface,
|
|
IN PVOID Frame)
|
|
{
|
|
PALLOCATOR This = (PALLOCATOR)CONTAINING_RECORD(iface, ALLOCATOR, lpVtbl);
|
|
|
|
/* now allocate frame */
|
|
if (This->Type == ALLOCATOR_CUSTOM)
|
|
{
|
|
This->Free.DefaultFree(This->u.CustomList, Frame);
|
|
}
|
|
else if (This->Type == ALLOCATOR_NPAGED_LOOKASIDE)
|
|
{
|
|
This->Free.NPagedPool(&This->u.NPagedList, Frame);
|
|
}
|
|
else if (This->Type == ALLOCATOR_PAGED_LOOKASIDE)
|
|
{
|
|
This->Free.PagedPool(&This->u.PagedList, Frame);
|
|
}
|
|
}
|
|
|
|
|
|
static IKsAllocatorVtbl vt_IKsAllocator =
|
|
{
|
|
IKsAllocator_fnQueryInterface,
|
|
IKsAllocator_fnAddRef,
|
|
IKsAllocator_fnRelease,
|
|
IKsAllocator_fnDeviceIoControl,
|
|
IKsAllocator_fnClose,
|
|
IKsAllocator_fnAllocateFrame,
|
|
IKsAllocator_fnFreeFrame
|
|
};
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI NTSTATUS NTAPI
|
|
KsCreateAllocator(
|
|
IN HANDLE ConnectionHandle,
|
|
IN PKSALLOCATOR_FRAMING AllocatorFraming,
|
|
OUT PHANDLE AllocatorHandle)
|
|
{
|
|
return KspCreateObjectType(ConnectionHandle,
|
|
KSSTRING_Allocator,
|
|
(PVOID)AllocatorFraming,
|
|
sizeof(KSALLOCATOR_FRAMING),
|
|
GENERIC_READ,
|
|
AllocatorHandle);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI NTSTATUS NTAPI
|
|
KsCreateDefaultAllocator(
|
|
IN PIRP Irp)
|
|
{
|
|
return KsCreateDefaultAllocatorEx(Irp, NULL, NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsValidateAllocatorCreateRequest(
|
|
IN PIRP Irp,
|
|
OUT PKSALLOCATOR_FRAMING* OutAllocatorFraming)
|
|
{
|
|
PKSALLOCATOR_FRAMING AllocatorFraming;
|
|
ULONG Size;
|
|
NTSTATUS Status;
|
|
ULONG SupportedFlags;
|
|
|
|
/* set minimum request size */
|
|
Size = sizeof(KSALLOCATOR_FRAMING);
|
|
|
|
Status = KspCopyCreateRequest(Irp,
|
|
KSSTRING_Allocator,
|
|
&Size,
|
|
(PVOID*)&AllocatorFraming);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* allowed supported flags */
|
|
SupportedFlags = (KSALLOCATOR_OPTIONF_COMPATIBLE | KSALLOCATOR_OPTIONF_SYSTEM_MEMORY |
|
|
KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER | KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | KSALLOCATOR_REQUIREMENTF_FRAME_INTEGRITY |
|
|
KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE);
|
|
|
|
|
|
if (!AllocatorFraming->FrameSize || (AllocatorFraming->OptionsFlags & (~SupportedFlags)))
|
|
{
|
|
FreeItem(AllocatorFraming);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* store result */
|
|
*OutAllocatorFraming = AllocatorFraming;
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
IKsAllocator_DispatchRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Frame,
|
|
IN ALLOC_REQUEST Request)
|
|
{
|
|
PKSIOBJECT_HEADER Header;
|
|
NTSTATUS Status;
|
|
IKsAllocator * Allocator;
|
|
|
|
/* sanity check */
|
|
ASSERT(FileObject);
|
|
|
|
/* get object header */
|
|
Header = (PKSIOBJECT_HEADER)FileObject->FsContext2;
|
|
|
|
/* get real allocator */
|
|
Status = Header->Unknown->lpVtbl->QueryInterface(Header->Unknown, &IID_IKsAllocator, (PVOID*)&Allocator);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* misbehaving object */
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (Request == ALLOCATOR_DEVICE_CONTROL)
|
|
{
|
|
/* dispatch request allocator */
|
|
Status = Allocator->lpVtbl->DispatchDeviceIoControl(Allocator, DeviceObject, Irp);
|
|
}
|
|
else if (Request == ALLOCATOR_DEVICE_CLOSE)
|
|
{
|
|
/* delete allocator */
|
|
Status = Allocator->lpVtbl->Close(Allocator);
|
|
}
|
|
else if (Request == ALLOCATOR_ALLOCATE)
|
|
{
|
|
/* allocate frame */
|
|
Status = Allocator->lpVtbl->AllocateFrame(Allocator, (PVOID*)Frame);
|
|
|
|
}else if (Request == ALLOCATOR_FREE)
|
|
{
|
|
/* allocate frame */
|
|
Allocator->lpVtbl->FreeFrame(Allocator, Frame);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
/* release interface */
|
|
Allocator->lpVtbl->Release(Allocator);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_DispatchDeviceIoControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
/* get current irp stack */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* dispatch request */
|
|
Status = IKsAllocator_DispatchRequest(DeviceObject, IoStack->FileObject, Irp, NULL, ALLOCATOR_DEVICE_CONTROL);
|
|
|
|
/* complete request */
|
|
Irp->IoStatus.Status = Status;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_DispatchClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
/* get current irp stack */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* dispatch request */
|
|
Status = IKsAllocator_DispatchRequest(DeviceObject, IoStack->FileObject, Irp, NULL, ALLOCATOR_DEVICE_CLOSE);
|
|
|
|
/* complete request */
|
|
Irp->IoStatus.Status = Status;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IKsAllocator_Allocate(
|
|
IN PFILE_OBJECT FileObject,
|
|
PVOID *Frame)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
/* dispatch request */
|
|
Status = IKsAllocator_DispatchRequest(NULL, FileObject, NULL, (PVOID)Frame, ALLOCATOR_ALLOCATE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IKsAllocator_FreeFrame(
|
|
IN PFILE_OBJECT FileObject,
|
|
PVOID Frame)
|
|
{
|
|
/* dispatch request */
|
|
IKsAllocator_DispatchRequest(NULL, FileObject, NULL, Frame, ALLOCATOR_FREE);
|
|
}
|
|
|
|
|
|
static KSDISPATCH_TABLE DispatchTable =
|
|
{
|
|
IKsAllocator_DispatchDeviceIoControl,
|
|
KsDispatchInvalidDeviceRequest,
|
|
KsDispatchInvalidDeviceRequest,
|
|
KsDispatchInvalidDeviceRequest,
|
|
IKsAllocator_DispatchClose,
|
|
KsDispatchQuerySecurity,
|
|
KsDispatchSetSecurity,
|
|
KsDispatchFastIoDeviceControlFailure,
|
|
KsDispatchFastReadFailure,
|
|
KsDispatchFastReadFailure,
|
|
};
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI NTSTATUS NTAPI
|
|
KsCreateDefaultAllocatorEx(
|
|
IN PIRP Irp,
|
|
IN PVOID InitializeContext OPTIONAL,
|
|
IN PFNKSDEFAULTALLOCATE DefaultAllocate OPTIONAL,
|
|
IN PFNKSDEFAULTFREE DefaultFree OPTIONAL,
|
|
IN PFNKSINITIALIZEALLOCATOR InitializeAllocator OPTIONAL,
|
|
IN PFNKSDELETEALLOCATOR DeleteAllocator OPTIONAL)
|
|
{
|
|
NTSTATUS Status;
|
|
PKSALLOCATOR_FRAMING AllocatorFraming;
|
|
PALLOCATOR Allocator;
|
|
PVOID Ctx;
|
|
|
|
/* first validate connect request */
|
|
Status = KsValidateAllocatorCreateRequest(Irp, &AllocatorFraming);
|
|
if (!NT_SUCCESS(Status))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* check the valid file alignment */
|
|
if (AllocatorFraming->FileAlignment > (PAGE_SIZE-1))
|
|
{
|
|
FreeItem(AllocatorFraming);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* allocate allocator struct */
|
|
Allocator = AllocateItem(NonPagedPool, sizeof(ALLOCATOR));
|
|
if (!Allocator)
|
|
{
|
|
FreeItem(AllocatorFraming);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* allocate object header */
|
|
|
|
Status = KsAllocateObjectHeader((KSOBJECT_HEADER*)&Allocator->Header, 0, NULL, Irp, &DispatchTable);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
FreeItem(AllocatorFraming);
|
|
FreeItem(Allocator);
|
|
return Status;
|
|
}
|
|
|
|
/* set allocator type in object header */
|
|
Allocator->lpVtbl = &vt_IKsAllocator;
|
|
Allocator->Header->Unknown = (PUNKNOWN)&Allocator->lpVtbl;
|
|
Allocator->ref = 1;
|
|
|
|
if (DefaultAllocate)
|
|
{
|
|
/* use external allocator */
|
|
Allocator->Type = ALLOCATOR_CUSTOM;
|
|
Allocator->Allocate.DefaultAllocate = DefaultAllocate;
|
|
Allocator->Free.DefaultFree = DefaultFree;
|
|
Allocator->Delete.DefaultDelete = DeleteAllocator;
|
|
Ctx = InitializeAllocator(InitializeContext, AllocatorFraming, &Allocator->u.CustomList);
|
|
/* check for success */
|
|
if (!Ctx)
|
|
{
|
|
KsFreeObjectHeader(Allocator->Header);
|
|
FreeItem(Allocator);
|
|
return Status;
|
|
}
|
|
}
|
|
else if (AllocatorFraming->PoolType == NonPagedPool)
|
|
{
|
|
/* use non-paged pool allocator */
|
|
Allocator->Type = ALLOCATOR_NPAGED_LOOKASIDE;
|
|
Allocator->Allocate.NPagedPool = ExAllocateFromNPagedLookasideList;
|
|
Allocator->Free.NPagedPool = ExFreeToNPagedLookasideList;
|
|
Allocator->Delete.NPagedPool = ExDeleteNPagedLookasideList;
|
|
ExInitializeNPagedLookasideList(&Allocator->u.NPagedList, NULL, NULL, 0, AllocatorFraming->FrameSize, 0, 0);
|
|
}
|
|
else if (AllocatorFraming->PoolType == PagedPool)
|
|
{
|
|
/* use paged pool allocator */
|
|
Allocator->Allocate.PagedPool = ExAllocateFromPagedLookasideList;
|
|
Allocator->Free.PagedPool = ExFreeToPagedLookasideList;
|
|
Allocator->Delete.PagedPool = ExDeletePagedLookasideList;
|
|
Allocator->Type = ALLOCATOR_PAGED_LOOKASIDE;
|
|
ExInitializePagedLookasideList(&Allocator->u.PagedList, NULL, NULL, 0, AllocatorFraming->FrameSize, 0, 0);
|
|
|
|
}
|
|
|
|
/* backup allocator framing */
|
|
RtlMoveMemory(&Allocator->Status.Framing, AllocatorFraming, sizeof(KSALLOCATOR_FRAMING));
|
|
FreeItem(AllocatorFraming);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI NTSTATUS NTAPI
|
|
KsValidateAllocatorFramingEx(
|
|
IN PKSALLOCATOR_FRAMING_EX Framing,
|
|
IN ULONG BufferSize,
|
|
IN const KSALLOCATOR_FRAMING_EX* PinFraming)
|
|
{
|
|
if (BufferSize < sizeof(KSALLOCATOR_FRAMING_EX))
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
/* verify framing */
|
|
if ((Framing->FramingItem[0].Flags & KSALLOCATOR_FLAG_PARTIAL_READ_SUPPORT) &&
|
|
Framing->OutputCompression.RatioNumerator != MAXULONG &&
|
|
Framing->OutputCompression.RatioDenominator != 0 &&
|
|
Framing->OutputCompression.RatioDenominator < Framing->OutputCompression.RatioNumerator)
|
|
{
|
|
/* framing request is ok */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|