mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 13:54:41 +00:00
2612 lines
67 KiB
C
2612 lines
67 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: drivers/ksfilter/ks/api.c
|
|
* PURPOSE: KS API functions
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
const GUID GUID_NULL = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsAcquireResetValue(
|
|
IN PIRP Irp,
|
|
OUT KSRESET* ResetValue)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
KSRESET* Value;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
/* get current irp stack */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* check if there is reset value provided */
|
|
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSRESET))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
if (Irp->RequestorMode == UserMode)
|
|
{
|
|
/* need to probe the buffer */
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSRESET), sizeof(UCHAR));
|
|
Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
*ResetValue = *Value;
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Exception, get the error code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
else
|
|
{
|
|
Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
*ResetValue = *Value;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsAcquireDeviceSecurityLock(
|
|
IN KSDEVICE_HEADER DevHeader,
|
|
IN BOOLEAN Exclusive)
|
|
{
|
|
PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
|
|
|
|
KeEnterCriticalRegion();
|
|
|
|
if (Exclusive)
|
|
{
|
|
ExAcquireResourceExclusiveLite(&Header->SecurityLock, TRUE);
|
|
}
|
|
else
|
|
{
|
|
ExAcquireResourceSharedLite(&Header->SecurityLock, TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsReleaseDeviceSecurityLock(
|
|
IN KSDEVICE_HEADER DevHeader)
|
|
{
|
|
PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
|
|
|
|
DPRINT("KsReleaseDevice\n");
|
|
|
|
ExReleaseResourceLite(&Header->SecurityLock);
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsDefaultDispatchPnp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PDEVICE_OBJECT PnpDeviceObject;
|
|
NTSTATUS Status;
|
|
ULONG MinorFunction;
|
|
|
|
/* get current irp stack */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* caller wants to add the target device */
|
|
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
|
|
|
|
/* backup PnpBaseObject */
|
|
PnpDeviceObject = DeviceHeader->PnpDeviceObject;
|
|
|
|
|
|
/* backup minor function code */
|
|
MinorFunction = IoStack->MinorFunction;
|
|
|
|
if(MinorFunction == IRP_MN_REMOVE_DEVICE)
|
|
{
|
|
/* remove the device */
|
|
KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
|
|
}
|
|
|
|
/* skip current irp stack */
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
/* call attached pnp device object */
|
|
Status = IoCallDriver(PnpDeviceObject, Irp);
|
|
|
|
if (MinorFunction == IRP_MN_REMOVE_DEVICE)
|
|
{
|
|
/* time is over */
|
|
IoDetachDevice(PnpDeviceObject);
|
|
/* delete device */
|
|
IoDeleteDevice(DeviceObject);
|
|
}
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsDefaultDispatchPower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
PKSIOBJECT_HEADER ObjectHeader;
|
|
//PIO_STACK_LOCATION IoStack;
|
|
PLIST_ENTRY ListEntry;
|
|
NTSTATUS Status;
|
|
|
|
/* get current irp stack */
|
|
//IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* caller wants to add the target device */
|
|
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
|
|
|
|
/* FIXME locks */
|
|
|
|
/* loop our power dispatch list and call registered notification functions */
|
|
ListEntry = DeviceHeader->PowerDispatchList.Flink;
|
|
/* let's go */
|
|
while(ListEntry != &DeviceHeader->PowerDispatchList)
|
|
{
|
|
/* get object header */
|
|
ObjectHeader = (PKSIOBJECT_HEADER)CONTAINING_RECORD(ListEntry, KSIOBJECT_HEADER, PowerDispatchEntry);
|
|
|
|
/* does it have still a cb */
|
|
if (ObjectHeader->PowerDispatch)
|
|
{
|
|
/* call the power cb */
|
|
Status = ObjectHeader->PowerDispatch(ObjectHeader->PowerContext, Irp);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
|
|
/* iterate to next entry */
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
/* start next power irp */
|
|
PoStartNextPowerIrp(Irp);
|
|
|
|
/* skip current irp stack location */
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
/* let's roll */
|
|
Status = PoCallDriver(DeviceHeader->PnpDeviceObject, Irp);
|
|
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsDefaultForwardIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
//PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
/* get current irp stack */
|
|
//IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* caller wants to add the target device */
|
|
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
|
|
|
|
/* forward the request to the PDO */
|
|
Status = IoCallDriver(DeviceHeader->PnpDeviceObject, Irp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsSetDevicePnpAndBaseObject(
|
|
IN KSDEVICE_HEADER Header,
|
|
IN PDEVICE_OBJECT PnpDeviceObject,
|
|
IN PDEVICE_OBJECT BaseDevice)
|
|
{
|
|
PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
|
|
|
|
DeviceHeader->PnpDeviceObject = PnpDeviceObject;
|
|
DeviceHeader->BaseDevice = BaseDevice;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
PDEVICE_OBJECT
|
|
NTAPI
|
|
KsQueryDevicePnpObject(
|
|
IN KSDEVICE_HEADER Header)
|
|
{
|
|
PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
|
|
|
|
/* return PnpDeviceObject */
|
|
return DeviceHeader->PnpDeviceObject;
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
ACCESS_MASK
|
|
NTAPI
|
|
KsQueryObjectAccessMask(
|
|
IN KSOBJECT_HEADER Header)
|
|
{
|
|
PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
|
|
|
|
/* return access mask */
|
|
return ObjectHeader->AccessMask;
|
|
|
|
}
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsRecalculateStackDepth(
|
|
IN KSDEVICE_HEADER Header,
|
|
IN BOOLEAN ReuseStackLocation)
|
|
{
|
|
UNIMPLEMENTED;
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsSetTargetState(
|
|
IN KSOBJECT_HEADER Header,
|
|
IN KSTARGET_STATE TargetState)
|
|
{
|
|
PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
|
|
|
|
/* set target state */
|
|
DeviceHeader->TargetState = TargetState;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsSetTargetDeviceObject(
|
|
IN KSOBJECT_HEADER Header,
|
|
IN PDEVICE_OBJECT TargetDevice OPTIONAL)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
|
|
|
|
if(ObjectHeader->TargetDevice)
|
|
{
|
|
/* there is already a target device set */
|
|
if (!TargetDevice)
|
|
{
|
|
/* caller wants to remove the target device */
|
|
DeviceExtension = (PDEVICE_EXTENSION)ObjectHeader->TargetDevice->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
|
|
|
|
/* acquire lock */
|
|
KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
|
|
|
|
/* remove entry */
|
|
RemoveEntryList(&ObjectHeader->TargetDeviceListEntry);
|
|
|
|
/* remove device pointer */
|
|
ObjectHeader->TargetDevice = NULL;
|
|
|
|
/* release lock */
|
|
KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* no target device yet set */
|
|
if (TargetDevice)
|
|
{
|
|
/* caller wants to add the target device */
|
|
DeviceExtension = (PDEVICE_EXTENSION)TargetDevice->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
|
|
|
|
/* acquire lock */
|
|
KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
|
|
|
|
/* insert list entry */
|
|
InsertTailList(&DeviceHeader->TargetDeviceList, &ObjectHeader->TargetDeviceListEntry);
|
|
|
|
/* store target device */
|
|
ObjectHeader->TargetDevice = TargetDevice;
|
|
|
|
/* release lock */
|
|
KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsSetPowerDispatch(
|
|
IN KSOBJECT_HEADER Header,
|
|
IN PFNKSCONTEXT_DISPATCH PowerDispatch OPTIONAL,
|
|
IN PVOID PowerContext OPTIONAL)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
|
|
|
|
/* caller wants to add the target device */
|
|
DeviceExtension = (PDEVICE_EXTENSION)ObjectHeader->ParentDeviceObject->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
|
|
|
|
/* acquire lock */
|
|
KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
|
|
|
|
if (PowerDispatch)
|
|
{
|
|
/* add power dispatch entry */
|
|
InsertTailList(&DeviceHeader->PowerDispatchList, &ObjectHeader->PowerDispatchEntry);
|
|
|
|
/* store function and context */
|
|
ObjectHeader->PowerDispatch = PowerDispatch;
|
|
ObjectHeader->PowerContext = PowerContext;
|
|
}
|
|
else
|
|
{
|
|
/* remove power dispatch entry */
|
|
RemoveEntryList(&ObjectHeader->PowerDispatchEntry);
|
|
|
|
/* store function and context */
|
|
ObjectHeader->PowerDispatch = NULL;
|
|
ObjectHeader->PowerContext = NULL;
|
|
|
|
}
|
|
|
|
/* release lock */
|
|
KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
PKSOBJECT_CREATE_ITEM
|
|
NTAPI
|
|
KsQueryObjectCreateItem(
|
|
IN KSOBJECT_HEADER Header)
|
|
{
|
|
PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
|
|
return ObjectHeader->OriginalCreateItem;
|
|
}
|
|
|
|
NTSTATUS
|
|
KspAddCreateItemToList(
|
|
OUT PLIST_ENTRY ListHead,
|
|
IN ULONG ItemsCount,
|
|
IN PKSOBJECT_CREATE_ITEM ItemsList)
|
|
{
|
|
ULONG Index;
|
|
PCREATE_ITEM_ENTRY Entry;
|
|
|
|
/* add the items */
|
|
for(Index = 0; Index < ItemsCount; Index++)
|
|
{
|
|
/* allocate item */
|
|
Entry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
|
|
if (!Entry)
|
|
{
|
|
/* no memory */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* initialize entry */
|
|
InitializeListHead(&Entry->ObjectItemList);
|
|
Entry->CreateItem = &ItemsList[Index];
|
|
Entry->ReferenceCount = 0;
|
|
Entry->ItemFreeCallback = NULL;
|
|
|
|
InsertTailList(ListHead, &Entry->Entry);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
KspFreeCreateItems(
|
|
PLIST_ENTRY ListHead)
|
|
{
|
|
PCREATE_ITEM_ENTRY Entry;
|
|
|
|
while(!IsListEmpty(ListHead))
|
|
{
|
|
/* remove create item from list */
|
|
Entry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(RemoveHeadList(ListHead), CREATE_ITEM_ENTRY, Entry);
|
|
|
|
/* caller shouldnt have any references */
|
|
//ASSERT(Entry->ReferenceCount == 0);
|
|
//ASSERT(IsListEmpty(&Entry->ObjectItemList));
|
|
|
|
/* does the creator wish notification */
|
|
if (Entry->ItemFreeCallback)
|
|
{
|
|
/* notify creator */
|
|
Entry->ItemFreeCallback(Entry->CreateItem);
|
|
}
|
|
|
|
/* free create item entry */
|
|
FreeItem(Entry);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsAllocateDeviceHeader(
|
|
OUT KSDEVICE_HEADER* OutHeader,
|
|
IN ULONG ItemsCount,
|
|
IN PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PKSIDEVICE_HEADER Header;
|
|
|
|
if (!OutHeader)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* allocate a device header */
|
|
Header = AllocateItem(PagedPool, sizeof(KSIDEVICE_HEADER));
|
|
|
|
/* check for success */
|
|
if (!Header)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* clear all memory */
|
|
RtlZeroMemory(Header, sizeof(KSIDEVICE_HEADER));
|
|
|
|
/* initialize device mutex */
|
|
KeInitializeMutex(&Header->DeviceMutex, 0);
|
|
|
|
/* initialize target device list */
|
|
InitializeListHead(&Header->TargetDeviceList);
|
|
/* initialize power dispatch list */
|
|
InitializeListHead(&Header->PowerDispatchList);
|
|
/* initialize object bag lists */
|
|
InitializeListHead(&Header->ObjectBags);
|
|
|
|
/* initialize create item list */
|
|
InitializeListHead(&Header->ItemList);
|
|
|
|
/* initialize basic header */
|
|
Header->BasicHeader.Type = KsObjectTypeDevice;
|
|
Header->BasicHeader.KsDevice = &Header->KsDevice;
|
|
Header->BasicHeader.Parent.KsDevice = &Header->KsDevice;
|
|
|
|
/* are there any create items provided */
|
|
if (ItemsCount && ItemsList)
|
|
{
|
|
Status = KspAddCreateItemToList(&Header->ItemList, ItemsCount, ItemsList);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* store item count */
|
|
Header->ItemListCount = ItemsCount;
|
|
}
|
|
else
|
|
{
|
|
/* release create items */
|
|
KspFreeCreateItems(&Header->ItemList);
|
|
}
|
|
}
|
|
|
|
/* store result */
|
|
*OutHeader = Header;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsFreeDeviceHeader(
|
|
IN KSDEVICE_HEADER DevHeader)
|
|
{
|
|
PKSIDEVICE_HEADER Header;
|
|
|
|
Header = (PKSIDEVICE_HEADER)DevHeader;
|
|
|
|
if (!DevHeader)
|
|
return;
|
|
|
|
KspFreeCreateItems(&Header->ItemList);
|
|
FreeItem(Header);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsAllocateObjectHeader(
|
|
OUT KSOBJECT_HEADER *Header,
|
|
IN ULONG ItemsCount,
|
|
IN PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL,
|
|
IN PIRP Irp,
|
|
IN KSDISPATCH_TABLE* Table)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
//PDEVICE_EXTENSION DeviceExtension;
|
|
//PKSIDEVICE_HEADER DeviceHeader;
|
|
PKSIOBJECT_HEADER ObjectHeader;
|
|
//PKSOBJECT_CREATE_ITEM CreateItem;
|
|
NTSTATUS Status;
|
|
|
|
if (!Header)
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
if (!Irp)
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
if (!Table)
|
|
return STATUS_INVALID_PARAMETER_5;
|
|
|
|
/* get current stack location */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
/* get device extension */
|
|
//DeviceExtension = (PDEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
|
|
/* get device header */
|
|
//DeviceHeader = DeviceExtension->DeviceHeader;
|
|
|
|
/* sanity check */
|
|
ASSERT(IoStack->FileObject);
|
|
/* check for an file object */
|
|
|
|
/* allocate the object header */
|
|
ObjectHeader = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_HEADER));
|
|
if (!ObjectHeader)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* initialize object header */
|
|
RtlZeroMemory(ObjectHeader, sizeof(KSIOBJECT_HEADER));
|
|
|
|
/* initialize create item list */
|
|
InitializeListHead(&ObjectHeader->ItemList);
|
|
|
|
/* get create item */
|
|
//CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
|
|
|
/* do we have a name */
|
|
if (IoStack->FileObject->FileName.Buffer)
|
|
{
|
|
/* copy object class */
|
|
ObjectHeader->ObjectClass.MaximumLength = IoStack->FileObject->FileName.MaximumLength;
|
|
ObjectHeader->ObjectClass.Buffer = AllocateItem(NonPagedPool, ObjectHeader->ObjectClass.MaximumLength);
|
|
if (!ObjectHeader->ObjectClass.Buffer)
|
|
{
|
|
FreeItem(ObjectHeader);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyUnicodeString(&ObjectHeader->ObjectClass, &IoStack->FileObject->FileName);
|
|
}
|
|
|
|
/* copy dispatch table */
|
|
RtlCopyMemory(&ObjectHeader->DispatchTable, Table, sizeof(KSDISPATCH_TABLE));
|
|
|
|
/* store create items */
|
|
if (ItemsCount && ItemsList)
|
|
{
|
|
Status = KspAddCreateItemToList(&ObjectHeader->ItemList, ItemsCount, ItemsList);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* store item count */
|
|
ObjectHeader->ItemListCount = ItemsCount;
|
|
}
|
|
else
|
|
{
|
|
/* destroy header*/
|
|
KsFreeObjectHeader(ObjectHeader);
|
|
return Status;
|
|
}
|
|
}
|
|
/* store the object in the file object */
|
|
IoStack->FileObject->FsContext2 = ObjectHeader;
|
|
|
|
/* store parent device */
|
|
ObjectHeader->ParentDeviceObject = IoGetRelatedDeviceObject(IoStack->FileObject);
|
|
|
|
/* store originating create item */
|
|
ObjectHeader->OriginalCreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
|
|
|
|
/* FIXME store access mask see KsQueryObjectAccessMask */
|
|
ObjectHeader->AccessMask = IoStack->Parameters.Create.SecurityContext->DesiredAccess;
|
|
|
|
|
|
/* store result */
|
|
*Header = ObjectHeader;
|
|
|
|
DPRINT("KsAllocateObjectHeader ObjectClass %S FileObject %p, ObjectHeader %p\n", ObjectHeader->ObjectClass.Buffer, IoStack->FileObject, ObjectHeader);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsFreeObjectHeader(
|
|
IN PVOID Header)
|
|
{
|
|
PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER) Header;
|
|
|
|
DPRINT("KsFreeObjectHeader Header %p Class %wZ\n", Header, &ObjectHeader->ObjectClass);
|
|
|
|
if (ObjectHeader->ObjectClass.Buffer)
|
|
{
|
|
/* release object class buffer */
|
|
FreeItem(ObjectHeader->ObjectClass.Buffer);
|
|
}
|
|
|
|
if (ObjectHeader->Unknown)
|
|
{
|
|
/* release associated object */
|
|
ObjectHeader->Unknown->lpVtbl->Release(ObjectHeader->Unknown);
|
|
}
|
|
|
|
/* free create items */
|
|
KspFreeCreateItems(&ObjectHeader->ItemList);
|
|
|
|
/* free object header */
|
|
FreeItem(ObjectHeader);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
KspAddObjectCreateItemToList(
|
|
PLIST_ENTRY ListHead,
|
|
IN PDRIVER_DISPATCH Create,
|
|
IN PVOID Context,
|
|
IN PWCHAR ObjectClass,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PCREATE_ITEM_ENTRY CreateEntry;
|
|
|
|
/* point to first entry */
|
|
Entry = ListHead->Flink;
|
|
|
|
while(Entry != ListHead)
|
|
{
|
|
/* get create entry */
|
|
CreateEntry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(Entry, CREATE_ITEM_ENTRY, Entry);
|
|
/* if the create item has no create routine, then it is free to use */
|
|
if (CreateEntry->CreateItem->Create == NULL)
|
|
{
|
|
/* sanity check */
|
|
ASSERT(IsListEmpty(&CreateEntry->ObjectItemList));
|
|
ASSERT(CreateEntry->ReferenceCount == 0);
|
|
/* use free entry */
|
|
CreateEntry->CreateItem->Context = Context;
|
|
CreateEntry->CreateItem->Create = Create;
|
|
RtlInitUnicodeString(&CreateEntry->CreateItem->ObjectClass, ObjectClass);
|
|
CreateEntry->CreateItem->SecurityDescriptor = SecurityDescriptor;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!wcsicmp(ObjectClass, CreateEntry->CreateItem->ObjectClass.Buffer))
|
|
{
|
|
/* the same object class already exists */
|
|
return STATUS_OBJECT_NAME_COLLISION;
|
|
}
|
|
|
|
/* iterate to next entry */
|
|
Entry = Entry->Flink;
|
|
}
|
|
return STATUS_ALLOTTED_SPACE_EXCEEDED;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsAddObjectCreateItemToDeviceHeader(
|
|
IN KSDEVICE_HEADER DevHeader,
|
|
IN PDRIVER_DISPATCH Create,
|
|
IN PVOID Context,
|
|
IN PWCHAR ObjectClass,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
|
|
{
|
|
PKSIDEVICE_HEADER Header;
|
|
NTSTATUS Status;
|
|
|
|
Header = (PKSIDEVICE_HEADER)DevHeader;
|
|
|
|
DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
|
|
|
|
/* check if a device header has been provided */
|
|
if (!DevHeader)
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
/* check if a create item has been provided */
|
|
if (!Create)
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
/* check if a object class has been provided */
|
|
if (!ObjectClass)
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
/* let others do the work */
|
|
Status = KspAddObjectCreateItemToList(&Header->ItemList, Create, Context, ObjectClass, SecurityDescriptor);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* increment create item count */
|
|
InterlockedIncrement(&Header->ItemListCount);
|
|
}
|
|
DPRINT("KsAddObjectCreateItemToDeviceHeader Status %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsAddObjectCreateItemToObjectHeader(
|
|
IN KSOBJECT_HEADER ObjectHeader,
|
|
IN PDRIVER_DISPATCH Create,
|
|
IN PVOID Context,
|
|
IN PWCHAR ObjectClass,
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptor)
|
|
{
|
|
PKSIOBJECT_HEADER Header;
|
|
NTSTATUS Status;
|
|
|
|
Header = (PKSIOBJECT_HEADER)ObjectHeader;
|
|
|
|
DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
|
|
|
|
/* check if a device header has been provided */
|
|
if (!Header)
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
/* check if a create item has been provided */
|
|
if (!Create)
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
/* check if a object class has been provided */
|
|
if (!ObjectClass)
|
|
return STATUS_INVALID_PARAMETER_4;
|
|
|
|
/* let's work */
|
|
Status = KspAddObjectCreateItemToList(&Header->ItemList, Create, Context, ObjectClass, SecurityDescriptor);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* increment create item count */
|
|
InterlockedIncrement(&Header->ItemListCount);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsAllocateObjectCreateItem(
|
|
IN KSDEVICE_HEADER DevHeader,
|
|
IN PKSOBJECT_CREATE_ITEM CreateItem,
|
|
IN BOOLEAN AllocateEntry,
|
|
IN PFNKSITEMFREECALLBACK ItemFreeCallback OPTIONAL)
|
|
{
|
|
PCREATE_ITEM_ENTRY CreateEntry;
|
|
PKSIDEVICE_HEADER Header;
|
|
PKSOBJECT_CREATE_ITEM Item;
|
|
|
|
Header = (PKSIDEVICE_HEADER)DevHeader;
|
|
|
|
if (!DevHeader)
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
if (!CreateItem)
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
|
|
/* first allocate a create entry */
|
|
CreateEntry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
|
|
|
|
/* check for allocation success */
|
|
if (!CreateEntry)
|
|
{
|
|
/* not enough resources */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
if (AllocateEntry)
|
|
{
|
|
/* allocate create item */
|
|
Item = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
|
|
if (!Item)
|
|
{
|
|
/* no memory */
|
|
FreeItem(CreateEntry);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* initialize descriptor */
|
|
Item->Context = CreateItem->Context;
|
|
Item->Create = CreateItem->Create;
|
|
Item->Flags = CreateItem->Flags;
|
|
Item->SecurityDescriptor = CreateItem->SecurityDescriptor;
|
|
Item->ObjectClass.Length = 0;
|
|
Item->ObjectClass.MaximumLength = CreateItem->ObjectClass.MaximumLength;
|
|
|
|
/* copy object class */
|
|
Item->ObjectClass.Buffer = AllocateItem(NonPagedPool, Item->ObjectClass.MaximumLength);
|
|
if (!Item->ObjectClass.Buffer)
|
|
{
|
|
/* release resources */
|
|
FreeItem(Item);
|
|
FreeItem(CreateEntry);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyUnicodeString(&Item->ObjectClass, &CreateItem->ObjectClass);
|
|
}
|
|
else
|
|
{
|
|
if (ItemFreeCallback)
|
|
{
|
|
/* callback is only accepted when the create item is copied */
|
|
ItemFreeCallback = NULL;
|
|
}
|
|
/* use passed create item */
|
|
Item = CreateItem;
|
|
}
|
|
|
|
/* initialize create item entry */
|
|
InitializeListHead(&CreateEntry->ObjectItemList);
|
|
CreateEntry->ItemFreeCallback = ItemFreeCallback;
|
|
CreateEntry->CreateItem = Item;
|
|
CreateEntry->ReferenceCount = 0;
|
|
|
|
/* now insert the create item entry */
|
|
InsertTailList(&Header->ItemList, &CreateEntry->Entry);
|
|
|
|
/* increment item count */
|
|
InterlockedIncrement(&Header->ItemListCount);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
KspObjectFreeCreateItems(
|
|
IN KSDEVICE_HEADER Header,
|
|
IN PKSOBJECT_CREATE_ITEM CreateItem)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsFreeObjectCreateItem(
|
|
IN KSDEVICE_HEADER Header,
|
|
IN PUNICODE_STRING CreateItem)
|
|
{
|
|
KSOBJECT_CREATE_ITEM Item;
|
|
|
|
RtlZeroMemory(&Item, sizeof(KSOBJECT_CREATE_ITEM));
|
|
RtlInitUnicodeString(&Item.ObjectClass, CreateItem->Buffer);
|
|
|
|
return KspObjectFreeCreateItems(Header, &Item);
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsFreeObjectCreateItemsByContext(
|
|
IN KSDEVICE_HEADER Header,
|
|
IN PVOID Context)
|
|
{
|
|
KSOBJECT_CREATE_ITEM Item;
|
|
|
|
RtlZeroMemory(&Item, sizeof(KSOBJECT_CREATE_ITEM));
|
|
|
|
Item.Context = Context;
|
|
|
|
return KspObjectFreeCreateItems(Header, &Item);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsCreateDefaultSecurity(
|
|
IN PSECURITY_DESCRIPTOR ParentSecurity OPTIONAL,
|
|
OUT PSECURITY_DESCRIPTOR* DefaultSecurity)
|
|
{
|
|
PGENERIC_MAPPING Mapping;
|
|
SECURITY_SUBJECT_CONTEXT SubjectContext;
|
|
NTSTATUS Status;
|
|
|
|
/* start capturing security context of calling thread */
|
|
SeCaptureSubjectContext(&SubjectContext);
|
|
/* get generic mapping */
|
|
Mapping = IoGetFileObjectGenericMapping();
|
|
/* build new descriptor */
|
|
Status = SeAssignSecurity(ParentSecurity, NULL, DefaultSecurity, FALSE, &SubjectContext, Mapping, NonPagedPool);
|
|
/* release security descriptor */
|
|
SeReleaseSubjectContext(&SubjectContext);
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsForwardIrp(
|
|
IN PIRP Irp,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN BOOLEAN ReuseStackLocation)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsForwardAndCatchIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PFILE_OBJECT FileObject,
|
|
IN KSSTACK_USE StackUse)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KspSynchronousIoControlDeviceCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
PIO_STATUS_BLOCK IoStatusBlock = (PIO_STATUS_BLOCK)Context;
|
|
|
|
IoStatusBlock->Information = Irp->IoStatus.Information;
|
|
IoStatusBlock->Status = Irp->IoStatus.Status;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsSynchronousIoControlDevice(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN ULONG IoControl,
|
|
IN PVOID InBuffer,
|
|
IN ULONG InSize,
|
|
OUT PVOID OutBuffer,
|
|
IN ULONG OutSize,
|
|
OUT PULONG BytesReturned)
|
|
{
|
|
PKSIOBJECT_HEADER ObjectHeader;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
KEVENT Event;
|
|
PIRP Irp;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
/* check for valid file object */
|
|
if (!FileObject)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
/* get device object to send the request to */
|
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
|
if (!DeviceObject)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
/* get object header */
|
|
ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
|
|
|
|
/* check if there is fast device io function */
|
|
if (ObjectHeader && ObjectHeader->DispatchTable.FastDeviceIoControl)
|
|
{
|
|
IoStatusBlock.Status = STATUS_UNSUCCESSFUL;
|
|
IoStatusBlock.Information = 0;
|
|
|
|
/* send the request */
|
|
Status = ObjectHeader->DispatchTable.FastDeviceIoControl(FileObject, TRUE, InBuffer, InSize, OutBuffer, OutSize, IoControl, &IoStatusBlock, DeviceObject);
|
|
/* check if the request was handled */
|
|
//DPRINT("Handled %u Status %x Length %u\n", Status, IoStatusBlock.Status, IoStatusBlock.Information);
|
|
if (Status)
|
|
{
|
|
/* store bytes returned */
|
|
*BytesReturned = (ULONG)IoStatusBlock.Information;
|
|
/* return status */
|
|
return IoStatusBlock.Status;
|
|
}
|
|
}
|
|
|
|
/* initialize the event */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
/* create the irp */
|
|
Irp = IoBuildDeviceIoControlRequest(IoControl, DeviceObject, InBuffer, InSize, OutBuffer, OutSize, FALSE, &Event, &IoStatusBlock);
|
|
|
|
if (!Irp)
|
|
{
|
|
/* no memory to allocate the irp */
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
/* Store Fileobject */
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
IoStack->FileObject = FileObject;
|
|
|
|
if (IoControl == IOCTL_KS_WRITE_STREAM)
|
|
{
|
|
Irp->AssociatedIrp.SystemBuffer = OutBuffer;
|
|
}
|
|
else if (IoControl == IOCTL_KS_READ_STREAM)
|
|
{
|
|
Irp->AssociatedIrp.SystemBuffer = InBuffer;
|
|
}
|
|
|
|
IoSetCompletionRoutine(Irp, KspSynchronousIoControlDeviceCompletion, (PVOID)&IoStatusBlock, TRUE, TRUE, TRUE);
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, RequestorMode, FALSE, NULL);
|
|
Status = IoStatusBlock.Status;
|
|
}
|
|
|
|
*BytesReturned = (ULONG)IoStatusBlock.Information;
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsUnserializeObjectPropertiesFromRegistry(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN HANDLE ParentKey OPTIONAL,
|
|
IN PUNICODE_STRING RegistryPath OPTIONAL)
|
|
{
|
|
UNIMPLEMENTED;
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KsCacheMedium(
|
|
IN PUNICODE_STRING SymbolicLink,
|
|
IN PKSPIN_MEDIUM Medium,
|
|
IN ULONG PinDirection)
|
|
{
|
|
HANDLE hKey;
|
|
UNICODE_STRING Path;
|
|
UNICODE_STRING BasePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediumCache\\");
|
|
UNICODE_STRING GuidString;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
BOOLEAN PathAdjusted = FALSE;
|
|
ULONG Value = 0;
|
|
|
|
/* first check if the medium is standard */
|
|
if (IsEqualGUIDAligned(&KSMEDIUMSETID_Standard, &Medium->Set) ||
|
|
IsEqualGUIDAligned(&GUID_NULL, &Medium->Set))
|
|
{
|
|
/* no need to cache that */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* convert guid to string */
|
|
Status = RtlStringFromGUID(&Medium->Set, &GuidString);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* allocate path buffer */
|
|
Path.Length = 0;
|
|
Path.MaximumLength = BasePath.MaximumLength + GuidString.MaximumLength + 10 * sizeof(WCHAR);
|
|
Path.Buffer = AllocateItem(PagedPool, Path.MaximumLength);
|
|
if (!Path.Buffer)
|
|
{
|
|
/* not enough resources */
|
|
RtlFreeUnicodeString(&GuidString);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlAppendUnicodeStringToString(&Path, &BasePath);
|
|
RtlAppendUnicodeStringToString(&Path, &GuidString);
|
|
RtlAppendUnicodeToString(&Path, L"-");
|
|
/* FIXME append real instance id */
|
|
RtlAppendUnicodeToString(&Path, L"0");
|
|
RtlAppendUnicodeToString(&Path, L"-");
|
|
/* FIXME append real instance id */
|
|
RtlAppendUnicodeToString(&Path, L"0");
|
|
|
|
/* free guid string */
|
|
RtlFreeUnicodeString(&GuidString);
|
|
|
|
/* initialize object attributes */
|
|
InitializeObjectAttributes(&ObjectAttributes, &Path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
/* create the key */
|
|
Status = ZwCreateKey(&hKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
|
|
|
|
/* free path buffer */
|
|
FreeItem(Path.Buffer);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* store symbolic link */
|
|
if (SymbolicLink->Buffer[1] == L'?' && SymbolicLink->Buffer[2] == L'?')
|
|
{
|
|
/* replace kernel path with user mode path */
|
|
SymbolicLink->Buffer[1] = L'\\';
|
|
PathAdjusted = TRUE;
|
|
}
|
|
|
|
/* store the key */
|
|
Status = ZwSetValueKey(hKey, SymbolicLink, 0, REG_DWORD, &Value, sizeof(ULONG));
|
|
|
|
if (PathAdjusted)
|
|
{
|
|
/* restore kernel path */
|
|
SymbolicLink->Buffer[1] = L'?';
|
|
}
|
|
|
|
ZwClose(hKey);
|
|
}
|
|
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
DllInitialize(
|
|
PUNICODE_STRING RegistryPath)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KopDispatchClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PKO_OBJECT_HEADER Header;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
/* get current irp stack location */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* get ko object header */
|
|
Header = (PKO_OBJECT_HEADER)IoStack->FileObject->FsContext2;
|
|
|
|
/* free ks object header */
|
|
KsFreeObjectHeader(Header->ObjectHeader);
|
|
|
|
/* free ko object header */
|
|
FreeItem(Header);
|
|
|
|
/* get device extension */
|
|
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
/* release bus object */
|
|
KsDereferenceBusObject((KSDEVICE_HEADER)DeviceExtension->DeviceHeader);
|
|
|
|
/* complete request */
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
static KSDISPATCH_TABLE KoDispatchTable =
|
|
{
|
|
KsDispatchInvalidDeviceRequest,
|
|
KsDispatchInvalidDeviceRequest,
|
|
KsDispatchInvalidDeviceRequest,
|
|
KsDispatchInvalidDeviceRequest,
|
|
KopDispatchClose,
|
|
KsDispatchQuerySecurity,
|
|
KsDispatchSetSecurity,
|
|
KsDispatchFastIoDeviceControlFailure,
|
|
KsDispatchFastReadFailure,
|
|
KsDispatchFastReadFailure,
|
|
};
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KopDispatchCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PKO_OBJECT_HEADER Header = NULL;
|
|
PIO_STACK_LOCATION IoStack;
|
|
PKO_DRIVER_EXTENSION DriverObjectExtension;
|
|
NTSTATUS Status;
|
|
|
|
/* get current irp stack location */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (!IoStack->FileObject)
|
|
{
|
|
DPRINT1("FileObject not attached!\n");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* get driver object extension */
|
|
DriverObjectExtension = (PKO_DRIVER_EXTENSION)IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)KoDriverInitialize);
|
|
if (!DriverObjectExtension)
|
|
{
|
|
DPRINT1("No DriverObjectExtension!\n");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* allocate ko object header */
|
|
Header = (PKO_OBJECT_HEADER)AllocateItem(NonPagedPool, sizeof(KO_OBJECT_HEADER));
|
|
if (!Header)
|
|
{
|
|
DPRINT1("failed to allocate KO_OBJECT_HEADER\n");
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* initialize create item */
|
|
Header->CreateItem.Create = KopDispatchCreate;
|
|
RtlInitUnicodeString(&Header->CreateItem.ObjectClass, KOSTRING_CreateObject);
|
|
|
|
|
|
/* now allocate the object header */
|
|
Status = KsAllocateObjectHeader(&Header->ObjectHeader, 1, &Header->CreateItem, Irp, &KoDispatchTable);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* failed */
|
|
goto cleanup;
|
|
}
|
|
|
|
/* FIXME
|
|
* extract clsid and interface id from irp
|
|
* call the standard create handler
|
|
*/
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
IoStack->FileObject->FsContext2 = (PVOID)Header;
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
|
|
cleanup:
|
|
|
|
if (Header && Header->ObjectHeader)
|
|
KsFreeObjectHeader(Header->ObjectHeader);
|
|
|
|
if (Header)
|
|
FreeItem(Header);
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KopAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject)
|
|
{
|
|
NTSTATUS Status = STATUS_DEVICE_REMOVED;
|
|
PDEVICE_OBJECT FunctionalDeviceObject= NULL;
|
|
PDEVICE_OBJECT NextDeviceObject;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
PKSOBJECT_CREATE_ITEM CreateItem;
|
|
|
|
/* create the device object */
|
|
Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KS, FILE_DEVICE_SECURE_OPEN, FALSE, &FunctionalDeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* allocate the create item */
|
|
CreateItem = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
|
|
|
|
if (!CreateItem)
|
|
{
|
|
/* not enough memory */
|
|
IoDeleteDevice(FunctionalDeviceObject);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* initialize create item */
|
|
CreateItem->Create = KopDispatchCreate;
|
|
RtlInitUnicodeString(&CreateItem->ObjectClass, KOSTRING_CreateObject);
|
|
|
|
/* get device extension */
|
|
DeviceExtension = (PDEVICE_EXTENSION)FunctionalDeviceObject->DeviceExtension;
|
|
|
|
/* now allocate the device header */
|
|
Status = KsAllocateDeviceHeader((KSDEVICE_HEADER*)&DeviceExtension->DeviceHeader, 1, CreateItem);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* failed */
|
|
IoDeleteDevice(FunctionalDeviceObject);
|
|
FreeItem(CreateItem);
|
|
return Status;
|
|
}
|
|
|
|
/* now attach to device stack */
|
|
NextDeviceObject = IoAttachDeviceToDeviceStack(FunctionalDeviceObject, PhysicalDeviceObject);
|
|
if (NextDeviceObject)
|
|
{
|
|
/* store pnp base object */
|
|
KsSetDevicePnpAndBaseObject((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, NextDeviceObject, FunctionalDeviceObject);
|
|
/* set device flags */
|
|
FunctionalDeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
|
|
FunctionalDeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
|
|
}
|
|
else
|
|
{
|
|
/* failed */
|
|
KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceExtension->DeviceHeader);
|
|
FreeItem(CreateItem);
|
|
IoDeleteDevice(FunctionalDeviceObject);
|
|
Status = STATUS_DEVICE_REMOVED;
|
|
}
|
|
|
|
/* return result */
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
COMDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KoDeviceInitialize(
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
/* get device extension */
|
|
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
return KsAddObjectCreateItemToDeviceHeader((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, KopDispatchCreate, NULL, KOSTRING_CreateObject, NULL);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
COMDDKAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
KoDriverInitialize(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPathName,
|
|
IN KoCreateObjectHandler CreateObjectHandler)
|
|
{
|
|
PKO_DRIVER_EXTENSION DriverObjectExtension;
|
|
NTSTATUS Status;
|
|
|
|
/* allocate driver object extension */
|
|
Status = IoAllocateDriverObjectExtension(DriverObject, (PVOID)KoDriverInitialize, sizeof(KO_DRIVER_EXTENSION), (PVOID*)&DriverObjectExtension);
|
|
|
|
/* did it work */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* store create handler */
|
|
DriverObjectExtension->CreateObjectHandler = CreateObjectHandler;
|
|
|
|
/* Setting our IRP handlers */
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = KsDefaultDispatchPnp;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
|
|
|
|
/* The driver unload routine */
|
|
DriverObject->DriverUnload = KsNullDriverUnload;
|
|
|
|
/* The driver-supplied AddDevice */
|
|
DriverObject->DriverExtension->AddDevice = KopAddDevice;
|
|
|
|
/* KS handles these */
|
|
DPRINT1("Setting KS function handlers\n");
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
|
|
KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
COMDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KoRelease(
|
|
IN REFCLSID ClassId)
|
|
{
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsAcquireControl(
|
|
IN PVOID Object)
|
|
{
|
|
PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
|
|
|
|
/* sanity check */
|
|
ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
|
|
|
|
KeWaitForSingleObject(BasicHeader->ControlMutex, Executive, KernelMode, FALSE, NULL);
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KsReleaseControl(
|
|
IN PVOID Object)
|
|
{
|
|
PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
|
|
|
|
/* sanity check */
|
|
ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
|
|
|
|
KeReleaseMutex(BasicHeader->ControlMutex, FALSE);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsAcquireDevice(
|
|
IN PKSDEVICE Device)
|
|
{
|
|
IKsDevice *KsDevice;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
|
|
DPRINT("KsAcquireDevice\n");
|
|
DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
|
|
|
|
/* get device interface*/
|
|
KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
|
|
|
|
/* acquire device mutex */
|
|
KsDevice->lpVtbl->AcquireDevice(KsDevice);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KsReleaseDevice(
|
|
IN PKSDEVICE Device)
|
|
{
|
|
IKsDevice *KsDevice;
|
|
PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
|
|
|
|
/* get device interface*/
|
|
KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
|
|
|
|
/* release device mutex */
|
|
KsDevice->lpVtbl->ReleaseDevice(KsDevice);
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsTerminateDevice(
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
IKsDevice *KsDevice;
|
|
PKSIDEVICE_HEADER DeviceHeader;
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
/* get device header */
|
|
DeviceHeader = DeviceExtension->DeviceHeader;
|
|
|
|
/* get device interface*/
|
|
KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
|
|
|
|
/* now free device header */
|
|
KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
|
|
|
|
/* release interface when available */
|
|
if (KsDevice)
|
|
{
|
|
/* delete IKsDevice interface */
|
|
KsDevice->lpVtbl->Release(KsDevice);
|
|
}
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
VOID
|
|
NTAPI
|
|
KsCompletePendingRequest(
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
/* get current irp stack location */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* sanity check */
|
|
ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
|
|
|
|
if (IoStack->MajorFunction != IRP_MJ_CLOSE)
|
|
{
|
|
/* can be completed immediately */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return;
|
|
}
|
|
|
|
/* did close operation fail */
|
|
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
|
{
|
|
/* closing failed, complete irp */
|
|
CompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return;
|
|
}
|
|
|
|
/* FIXME
|
|
* delete object / device header
|
|
* remove dead pin / filter instance
|
|
*/
|
|
UNIMPLEMENTED;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KspSetGetBusDataCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
/* signal completion */
|
|
KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
|
|
|
/* more work needs be done, so dont free the irp */
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
KspDeviceSetGetBusData(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG DataType,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length,
|
|
IN BOOL bGet)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PIRP Irp;
|
|
NTSTATUS Status;
|
|
KEVENT Event;
|
|
|
|
/* allocate the irp */
|
|
Irp = IoAllocateIrp(1, /*FIXME */
|
|
FALSE);
|
|
|
|
if (!Irp)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* initialize the event */
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
/* get next stack location */
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
/* setup a completion routine */
|
|
IoSetCompletionRoutine(Irp, KspSetGetBusDataCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
|
|
|
|
/* setup parameters */
|
|
IoStack->Parameters.ReadWriteConfig.Buffer = Buffer;
|
|
IoStack->Parameters.ReadWriteConfig.Length = Length;
|
|
IoStack->Parameters.ReadWriteConfig.Offset = Offset;
|
|
IoStack->Parameters.ReadWriteConfig.WhichSpace = DataType;
|
|
/* setup function code */
|
|
IoStack->MajorFunction = IRP_MJ_PNP;
|
|
IoStack->MinorFunction = (bGet ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG);
|
|
|
|
/* lets call the driver */
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
|
|
/* is the request still pending */
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
/* have a nap */
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
/* update status */
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
/* free the irp */
|
|
IoFreeIrp(Irp);
|
|
/* done */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
ULONG
|
|
NTAPI
|
|
KsDeviceSetBusData(
|
|
IN PKSDEVICE Device,
|
|
IN ULONG DataType,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length)
|
|
{
|
|
return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
|
|
DataType, Buffer, Offset, Length, FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
ULONG
|
|
NTAPI
|
|
KsDeviceGetBusData(
|
|
IN PKSDEVICE Device,
|
|
IN ULONG DataType,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length)
|
|
{
|
|
return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
|
|
DataType, Buffer, Offset, Length, TRUE);
|
|
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
void
|
|
NTAPI
|
|
KsDeviceRegisterAdapterObject(
|
|
IN PKSDEVICE Device,
|
|
IN PADAPTER_OBJECT AdapterObject,
|
|
IN ULONG MaxMappingsByteCount,
|
|
IN ULONG MappingTableStride)
|
|
{
|
|
PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
|
|
|
|
DeviceHeader->AdapterObject = AdapterObject;
|
|
DeviceHeader->MaxMappingsByteCount = MaxMappingsByteCount;
|
|
DeviceHeader->MappingTableStride = MappingTableStride;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
PVOID
|
|
NTAPI
|
|
KsGetFirstChild(
|
|
IN PVOID Object)
|
|
{
|
|
PKSBASIC_HEADER BasicHeader;
|
|
|
|
/* get the basic header */
|
|
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
|
|
|
|
/* type has to be either a device or a filter factory */
|
|
ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory);
|
|
|
|
return (PVOID)BasicHeader->FirstChild.Filter;
|
|
}
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
KSDDKAPI
|
|
PVOID
|
|
NTAPI
|
|
KsGetNextSibling(
|
|
IN PVOID Object)
|
|
{
|
|
PKSBASIC_HEADER BasicHeader;
|
|
|
|
/* get the basic header */
|
|
BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
|
|
|
|
ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
|
|
BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
|
|
|
|
return (PVOID)BasicHeader->Next.Pin;
|
|
}
|
|
|
|
ULONG
|
|
KspCountMethodSets(
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
|
|
{
|
|
ULONG Index, SubIndex, Count;
|
|
BOOL bFound;
|
|
|
|
if (!AutomationTableA)
|
|
return AutomationTableB->MethodSetsCount;
|
|
|
|
if (!AutomationTableB)
|
|
return AutomationTableA->MethodSetsCount;
|
|
|
|
|
|
DPRINT("AutomationTableA MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableA->MethodItemSize, AutomationTableA->MethodSetsCount);
|
|
DPRINT("AutomationTableB MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableB->MethodItemSize, AutomationTableB->MethodSetsCount);
|
|
|
|
if (AutomationTableA->MethodItemSize && AutomationTableB->MethodItemSize)
|
|
{
|
|
/* sanity check */
|
|
ASSERT(AutomationTableA->MethodItemSize == AutomationTableB->MethodItemSize);
|
|
}
|
|
|
|
/* now iterate all property sets and compare their guids */
|
|
Count = AutomationTableA->MethodSetsCount;
|
|
|
|
for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
|
|
{
|
|
/* set found to false */
|
|
bFound = FALSE;
|
|
|
|
for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
|
|
{
|
|
if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
|
|
{
|
|
/* same property set found */
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
Count++;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
ULONG
|
|
KspCountEventSets(
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
|
|
{
|
|
ULONG Index, SubIndex, Count;
|
|
BOOL bFound;
|
|
|
|
if (!AutomationTableA)
|
|
return AutomationTableB->EventSetsCount;
|
|
|
|
if (!AutomationTableB)
|
|
return AutomationTableA->EventSetsCount;
|
|
|
|
DPRINT("AutomationTableA EventItemSize %lu EventSetsCount %lu\n", AutomationTableA->EventItemSize, AutomationTableA->EventSetsCount);
|
|
DPRINT("AutomationTableB EventItemSize %lu EventSetsCount %lu\n", AutomationTableB->EventItemSize, AutomationTableB->EventSetsCount);
|
|
|
|
if (AutomationTableA->EventItemSize && AutomationTableB->EventItemSize)
|
|
{
|
|
/* sanity check */
|
|
ASSERT(AutomationTableA->EventItemSize == AutomationTableB->EventItemSize);
|
|
}
|
|
|
|
/* now iterate all Event sets and compare their guids */
|
|
Count = AutomationTableA->EventSetsCount;
|
|
|
|
for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
|
|
{
|
|
/* set found to false */
|
|
bFound = FALSE;
|
|
|
|
for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
|
|
{
|
|
if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
|
|
{
|
|
/* same Event set found */
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
Count++;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
ULONG
|
|
KspCountPropertySets(
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
|
|
{
|
|
ULONG Index, SubIndex, Count;
|
|
BOOL bFound;
|
|
|
|
if (!AutomationTableA)
|
|
return AutomationTableB->PropertySetsCount;
|
|
|
|
if (!AutomationTableB)
|
|
return AutomationTableA->PropertySetsCount;
|
|
|
|
/* sanity check */
|
|
DPRINT("AutomationTableA PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableA->PropertyItemSize, AutomationTableA->PropertySetsCount);
|
|
DPRINT("AutomationTableB PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableB->PropertyItemSize, AutomationTableB->PropertySetsCount);
|
|
ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
|
|
|
|
/* now iterate all property sets and compare their guids */
|
|
Count = AutomationTableA->PropertySetsCount;
|
|
|
|
for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
|
|
{
|
|
/* set found to false */
|
|
bFound = FALSE;
|
|
|
|
for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
|
|
{
|
|
if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
|
|
{
|
|
/* same property set found */
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
Count++;
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
NTSTATUS
|
|
KspCopyMethodSets(
|
|
OUT PKSAUTOMATION_TABLE Table,
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
|
|
{
|
|
ULONG Index, SubIndex, Count;
|
|
BOOL bFound;
|
|
|
|
if (!AutomationTableA)
|
|
{
|
|
/* copy of property set */
|
|
RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableB->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableB->MethodSetsCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (!AutomationTableB)
|
|
{
|
|
/* copy of property set */
|
|
RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* first copy all property items from dominant table */
|
|
RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
|
|
/* set counter */
|
|
Count = AutomationTableA->MethodSetsCount;
|
|
|
|
/* now copy entries which aren't available in the dominant table */
|
|
for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
|
|
{
|
|
/* set found to false */
|
|
bFound = FALSE;
|
|
|
|
for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
|
|
{
|
|
if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
|
|
{
|
|
/* same property set found */
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
/* copy new property item set */
|
|
RtlMoveMemory((PVOID)&Table->MethodSets[Count], &AutomationTableB->MethodSets[Index], sizeof(KSMETHOD_SET));
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
KspAddPropertyItem(
|
|
OUT PKSPROPERTY_SET OutPropertySet,
|
|
IN PKSPROPERTY_ITEM PropertyItem,
|
|
IN ULONG PropertyItemSize)
|
|
{
|
|
PKSPROPERTY_ITEM CurrentPropertyItem;
|
|
ULONG Index;
|
|
|
|
// check if the property item is already present
|
|
CurrentPropertyItem = (PKSPROPERTY_ITEM)OutPropertySet->PropertyItem;
|
|
for(Index = 0; Index < OutPropertySet->PropertiesCount; Index++)
|
|
{
|
|
if (CurrentPropertyItem->PropertyId == PropertyItem->PropertyId)
|
|
{
|
|
// item already present
|
|
return;
|
|
}
|
|
|
|
// next item
|
|
CurrentPropertyItem = (PKSPROPERTY_ITEM)((ULONG_PTR)CurrentPropertyItem + PropertyItemSize);
|
|
}
|
|
// add item
|
|
RtlCopyMemory(CurrentPropertyItem, PropertyItem, PropertyItemSize);
|
|
OutPropertySet->PropertiesCount++;
|
|
}
|
|
|
|
NTSTATUS
|
|
KspMergePropertySet(
|
|
OUT PKSAUTOMATION_TABLE Table,
|
|
OUT PKSPROPERTY_SET OutPropertySet,
|
|
IN PKSPROPERTY_SET PropertySetA,
|
|
IN PKSPROPERTY_SET PropertySetB,
|
|
IN KSOBJECT_BAG Bag OPTIONAL)
|
|
{
|
|
ULONG PropertyCount, Index;
|
|
PKSPROPERTY_ITEM PropertyItem, CurrentPropertyItem;
|
|
NTSTATUS Status;
|
|
|
|
// max properties
|
|
PropertyCount = PropertySetA->PropertiesCount + PropertySetB->PropertiesCount;
|
|
|
|
// allocate items
|
|
PropertyItem = AllocateItem(NonPagedPool, Table->PropertyItemSize * PropertyCount);
|
|
if (!PropertyItem)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (Bag)
|
|
{
|
|
/* add table to object bag */
|
|
Status = KsAddItemToObjectBag(Bag, PropertyItem, NULL);
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* free table */
|
|
FreeItem(Table);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
// copy entries from dominant table
|
|
RtlCopyMemory(PropertyItem, PropertySetA->PropertyItem, Table->PropertyItemSize * PropertySetA->PropertiesCount);
|
|
|
|
// init property set
|
|
OutPropertySet->PropertiesCount = PropertySetA->PropertiesCount;
|
|
OutPropertySet->PropertyItem = PropertyItem;
|
|
|
|
// copy other entries
|
|
CurrentPropertyItem = (PKSPROPERTY_ITEM)PropertySetB->PropertyItem;
|
|
for(Index = 0; Index < PropertySetB->PropertiesCount; Index++)
|
|
{
|
|
|
|
// add entries
|
|
KspAddPropertyItem(OutPropertySet, CurrentPropertyItem, Table->PropertyItemSize);
|
|
|
|
// next entry
|
|
CurrentPropertyItem = (PKSPROPERTY_ITEM)((ULONG_PTR)CurrentPropertyItem + Table->PropertyItemSize);
|
|
}
|
|
|
|
// done
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
KspCopyPropertySets(
|
|
OUT PKSAUTOMATION_TABLE Table,
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL,
|
|
IN KSOBJECT_BAG Bag OPTIONAL)
|
|
{
|
|
ULONG Index, SubIndex, Count;
|
|
BOOL bFound;
|
|
NTSTATUS Status;
|
|
|
|
if (!AutomationTableA)
|
|
{
|
|
/* copy of property set */
|
|
RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableB->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableB->PropertySetsCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (!AutomationTableB)
|
|
{
|
|
/* copy of property set */
|
|
RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* first copy all property items from dominant table */
|
|
RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
|
|
/* set counter */
|
|
Count = AutomationTableA->PropertySetsCount;
|
|
|
|
/* now copy entries which aren't available in the dominant table */
|
|
for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
|
|
{
|
|
/* set found to false */
|
|
bFound = FALSE;
|
|
|
|
for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
|
|
{
|
|
if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
|
|
{
|
|
/* same property set found */
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
/* copy new property item set */
|
|
RtlMoveMemory((PVOID)&Table->PropertySets[Count], &AutomationTableB->PropertySets[Index], sizeof(KSPROPERTY_SET));
|
|
Count++;
|
|
}
|
|
else
|
|
{
|
|
// merge property sets
|
|
Status = KspMergePropertySet(Table, (PKSPROPERTY_SET)&Table->PropertySets[SubIndex], (PKSPROPERTY_SET)&AutomationTableA->PropertySets[SubIndex], (PKSPROPERTY_SET)&AutomationTableB->PropertySets[Index], Bag);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
// failed to merge
|
|
DPRINT1("[KS] Failed to merge %x\n", Status);
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
KspCopyEventSets(
|
|
OUT PKSAUTOMATION_TABLE Table,
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)
|
|
{
|
|
ULONG Index, SubIndex, Count;
|
|
BOOL bFound;
|
|
|
|
if (!AutomationTableA)
|
|
{
|
|
/* copy of Event set */
|
|
RtlMoveMemory((PVOID)Table->EventSets, AutomationTableB->EventSets, sizeof(KSEVENT_SET) * AutomationTableB->EventSetsCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (!AutomationTableB)
|
|
{
|
|
/* copy of Event set */
|
|
RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* first copy all Event items from dominant table */
|
|
RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
|
|
/* set counter */
|
|
Count = AutomationTableA->EventSetsCount;
|
|
|
|
/* now copy entries which aren't available in the dominant table */
|
|
for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
|
|
{
|
|
/* set found to false */
|
|
bFound = FALSE;
|
|
|
|
for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
|
|
{
|
|
if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
|
|
{
|
|
/* same Event set found */
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
/* copy new Event item set */
|
|
RtlMoveMemory((PVOID)&Table->EventSets[Count], &AutomationTableB->EventSets[Index], sizeof(KSEVENT_SET));
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
@implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KsMergeAutomationTables(
|
|
OUT PKSAUTOMATION_TABLE *AutomationTableAB,
|
|
IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,
|
|
IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL,
|
|
IN KSOBJECT_BAG Bag OPTIONAL)
|
|
{
|
|
PKSAUTOMATION_TABLE Table;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (!AutomationTableA && !AutomationTableB)
|
|
{
|
|
/* nothing to merge */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* allocate an automation table */
|
|
Table = AllocateItem(NonPagedPool, sizeof(KSAUTOMATION_TABLE));
|
|
if (!Table)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (Bag)
|
|
{
|
|
/* add table to object bag */
|
|
Status = KsAddItemToObjectBag(Bag, Table, NULL);
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* free table */
|
|
FreeItem(Table);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/* count property sets */
|
|
Table->PropertySetsCount = KspCountPropertySets(AutomationTableA, AutomationTableB);
|
|
|
|
if (Table->PropertySetsCount)
|
|
{
|
|
if (AutomationTableA)
|
|
{
|
|
/* use item size from dominant automation table */
|
|
Table->PropertyItemSize = AutomationTableA->PropertyItemSize;
|
|
}
|
|
else
|
|
{
|
|
/* use item size from 2nd automation table */
|
|
Table->PropertyItemSize = AutomationTableB->PropertyItemSize;
|
|
}
|
|
|
|
if (AutomationTableA && AutomationTableB)
|
|
{
|
|
// FIXME handle different property item sizes
|
|
ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
|
|
}
|
|
|
|
/* now allocate the property sets */
|
|
Table->PropertySets = AllocateItem(NonPagedPool, sizeof(KSPROPERTY_SET) * Table->PropertySetsCount);
|
|
|
|
if (!Table->PropertySets)
|
|
{
|
|
/* not enough memory */
|
|
goto cleanup;
|
|
}
|
|
|
|
if (Bag)
|
|
{
|
|
/* add set to property bag */
|
|
Status = KsAddItemToObjectBag(Bag, (PVOID)Table->PropertySets, NULL);
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* cleanup table */
|
|
goto cleanup;
|
|
}
|
|
}
|
|
/* now copy the property sets */
|
|
Status = KspCopyPropertySets(Table, AutomationTableA, AutomationTableB, Bag);
|
|
if(!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* now count the method sets */
|
|
Table->MethodSetsCount = KspCountMethodSets(AutomationTableA, AutomationTableB);
|
|
|
|
if (Table->MethodSetsCount)
|
|
{
|
|
if (AutomationTableA)
|
|
{
|
|
/* use item size from dominant automation table */
|
|
Table->MethodItemSize = AutomationTableA->MethodItemSize;
|
|
}
|
|
else
|
|
{
|
|
/* use item size from 2nd automation table */
|
|
Table->MethodItemSize = AutomationTableB->MethodItemSize;
|
|
}
|
|
|
|
/* now allocate the property sets */
|
|
Table->MethodSets = AllocateItem(NonPagedPool, sizeof(KSMETHOD_SET) * Table->MethodSetsCount);
|
|
|
|
if (!Table->MethodSets)
|
|
{
|
|
/* not enough memory */
|
|
goto cleanup;
|
|
}
|
|
|
|
if (Bag)
|
|
{
|
|
/* add set to property bag */
|
|
Status = KsAddItemToObjectBag(Bag, (PVOID)Table->MethodSets, NULL);
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* cleanup table */
|
|
goto cleanup;
|
|
}
|
|
}
|
|
/* now copy the property sets */
|
|
Status = KspCopyMethodSets(Table, AutomationTableA, AutomationTableB);
|
|
if(!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
/* now count the event sets */
|
|
Table->EventSetsCount = KspCountEventSets(AutomationTableA, AutomationTableB);
|
|
|
|
if (Table->EventSetsCount)
|
|
{
|
|
if (AutomationTableA)
|
|
{
|
|
/* use item size from dominant automation table */
|
|
Table->EventItemSize = AutomationTableA->EventItemSize;
|
|
}
|
|
else
|
|
{
|
|
/* use item size from 2nd automation table */
|
|
Table->EventItemSize = AutomationTableB->EventItemSize;
|
|
}
|
|
|
|
/* now allocate the property sets */
|
|
Table->EventSets = AllocateItem(NonPagedPool, sizeof(KSEVENT_SET) * Table->EventSetsCount);
|
|
|
|
if (!Table->EventSets)
|
|
{
|
|
/* not enough memory */
|
|
goto cleanup;
|
|
}
|
|
|
|
if (Bag)
|
|
{
|
|
/* add set to property bag */
|
|
Status = KsAddItemToObjectBag(Bag, (PVOID)Table->EventSets, NULL);
|
|
/* check for success */
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* cleanup table */
|
|
goto cleanup;
|
|
}
|
|
}
|
|
/* now copy the property sets */
|
|
Status = KspCopyEventSets(Table, AutomationTableA, AutomationTableB);
|
|
if(!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
}
|
|
|
|
/* store result */
|
|
*AutomationTableAB = Table;
|
|
|
|
return Status;
|
|
|
|
|
|
cleanup:
|
|
|
|
if (Table)
|
|
{
|
|
if (Table->PropertySets)
|
|
{
|
|
/* clean property sets */
|
|
if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->PropertySets, TRUE)))
|
|
FreeItem((PVOID)Table->PropertySets);
|
|
}
|
|
|
|
if (Table->MethodSets)
|
|
{
|
|
/* clean property sets */
|
|
if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->MethodSets, TRUE)))
|
|
FreeItem((PVOID)Table->MethodSets);
|
|
}
|
|
|
|
if (Table->EventSets)
|
|
{
|
|
/* clean property sets */
|
|
if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->EventSets, TRUE)))
|
|
FreeItem((PVOID)Table->EventSets);
|
|
}
|
|
|
|
if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, Table, TRUE)))
|
|
FreeItem(Table);
|
|
}
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
KSDDKAPI
|
|
PUNKNOWN
|
|
NTAPI
|
|
KsRegisterAggregatedClientUnknown(
|
|
IN PVOID Object,
|
|
IN PUNKNOWN ClientUnknown)
|
|
{
|
|
PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
|
|
|
|
/* sanity check */
|
|
ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
|
|
BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
|
|
|
|
if (BasicHeader->ClientAggregate)
|
|
{
|
|
/* release existing aggregate */
|
|
BasicHeader->ClientAggregate->lpVtbl->Release(BasicHeader->ClientAggregate);
|
|
}
|
|
|
|
/* increment reference count */
|
|
ClientUnknown->lpVtbl->AddRef(ClientUnknown);
|
|
|
|
/* store client aggregate */
|
|
BasicHeader->ClientAggregate = ClientUnknown;
|
|
|
|
/* return objects outer unknown */
|
|
return BasicHeader->OuterUnknown;
|
|
}
|
|
|
|
/*
|
|
@unimplemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
KsRegisterFilterWithNoKSPins(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN const GUID* InterfaceClassGUID,
|
|
IN ULONG PinCount,
|
|
IN BOOL* PinDirection,
|
|
IN KSPIN_MEDIUM* MediumList,
|
|
IN GUID* CategoryList OPTIONAL)
|
|
{
|
|
ULONG Size, Index;
|
|
NTSTATUS Status;
|
|
PWSTR SymbolicLinkList;
|
|
//PUCHAR Buffer;
|
|
HANDLE hKey;
|
|
UNICODE_STRING InterfaceString;
|
|
//UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
|
|
|
|
if (!InterfaceClassGUID || !PinCount || !PinDirection || !MediumList)
|
|
{
|
|
/* all these parameters are required */
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* calculate filter data value size */
|
|
Size = PinCount * sizeof(KSPIN_MEDIUM);
|
|
if (CategoryList)
|
|
{
|
|
/* add category list */
|
|
Size += PinCount * sizeof(GUID);
|
|
}
|
|
|
|
/* FIXME generate filter data blob */
|
|
UNIMPLEMENTED;
|
|
|
|
/* get symbolic link list */
|
|
Status = IoGetDeviceInterfaces(InterfaceClassGUID, DeviceObject, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &SymbolicLinkList);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* initialize first symbolic link */
|
|
RtlInitUnicodeString(&InterfaceString, SymbolicLinkList);
|
|
|
|
/* open first device interface registry key */
|
|
Status = IoOpenDeviceInterfaceRegistryKey(&InterfaceString, GENERIC_WRITE, &hKey);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* write filter data */
|
|
//Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Buffer, Size);
|
|
|
|
/* close the key */
|
|
ZwClose(hKey);
|
|
}
|
|
|
|
if (PinCount)
|
|
{
|
|
/* update medium cache */
|
|
for(Index = 0; Index < PinCount; Index++)
|
|
{
|
|
KsCacheMedium(&InterfaceString, &MediumList[Index], PinDirection[Index]);
|
|
}
|
|
}
|
|
|
|
/* free the symbolic link list */
|
|
FreeItem(SymbolicLinkList);
|
|
}
|
|
|
|
return Status;
|
|
}
|