xref: /reactos/drivers/ksfilter/ks/api.c (revision e4930be4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/api.c
5  * PURPOSE:         KS API functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 const GUID GUID_NULL              = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
15 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
16 
17 /*
18     @implemented
19 */
20 KSDDKAPI
21 NTSTATUS
22 NTAPI
KsAcquireResetValue(IN PIRP Irp,OUT KSRESET * ResetValue)23 KsAcquireResetValue(
24     IN  PIRP Irp,
25     OUT KSRESET* ResetValue)
26 {
27     PIO_STACK_LOCATION IoStack;
28     KSRESET* Value;
29     NTSTATUS Status = STATUS_SUCCESS;
30 
31     /* get current irp stack */
32     IoStack = IoGetCurrentIrpStackLocation(Irp);
33 
34     /* check if there is reset value provided */
35     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSRESET))
36         return STATUS_INVALID_PARAMETER;
37 
38     if (Irp->RequestorMode == UserMode)
39     {
40         /* need to probe the buffer */
41         _SEH2_TRY
42         {
43             ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSRESET), sizeof(UCHAR));
44             Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
45             *ResetValue = *Value;
46         }
47         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
48         {
49             /* Exception, get the error code */
50             Status = _SEH2_GetExceptionCode();
51         }
52         _SEH2_END;
53     }
54     else
55     {
56         Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
57         *ResetValue = *Value;
58     }
59 
60     return Status;
61 }
62 
63 /*
64     @implemented
65 */
66 KSDDKAPI
67 VOID
68 NTAPI
KsAcquireDeviceSecurityLock(IN KSDEVICE_HEADER DevHeader,IN BOOLEAN Exclusive)69 KsAcquireDeviceSecurityLock(
70     IN KSDEVICE_HEADER DevHeader,
71     IN BOOLEAN Exclusive)
72 {
73     PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
74 
75     KeEnterCriticalRegion();
76 
77     if (Exclusive)
78     {
79         ExAcquireResourceExclusiveLite(&Header->SecurityLock, TRUE);
80     }
81     else
82     {
83         ExAcquireResourceSharedLite(&Header->SecurityLock, TRUE);
84     }
85 }
86 
87 /*
88     @implemented
89 */
90 KSDDKAPI
91 VOID
92 NTAPI
KsReleaseDeviceSecurityLock(IN KSDEVICE_HEADER DevHeader)93 KsReleaseDeviceSecurityLock(
94     IN KSDEVICE_HEADER DevHeader)
95 {
96     PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
97 
98     DPRINT("KsReleaseDevice\n");
99 
100     ExReleaseResourceLite(&Header->SecurityLock);
101     KeLeaveCriticalRegion();
102 }
103 
104 /*
105     @implemented
106 */
107 KSDDKAPI
108 NTSTATUS
109 NTAPI
KsDefaultDispatchPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)110 KsDefaultDispatchPnp(
111     IN  PDEVICE_OBJECT DeviceObject,
112     IN  PIRP Irp)
113 {
114     PDEVICE_EXTENSION DeviceExtension;
115     PKSIDEVICE_HEADER DeviceHeader;
116     PIO_STACK_LOCATION IoStack;
117     PDEVICE_OBJECT PnpDeviceObject;
118     NTSTATUS Status;
119     ULONG MinorFunction;
120 
121     /* get current irp stack */
122     IoStack = IoGetCurrentIrpStackLocation(Irp);
123 
124     /* caller wants to add the target device */
125     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
126 
127     /* get device header */
128     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
129 
130     /* backup PnpBaseObject */
131     PnpDeviceObject = DeviceHeader->PnpDeviceObject;
132 
133 
134     /* backup minor function code */
135     MinorFunction = IoStack->MinorFunction;
136 
137     if(MinorFunction == IRP_MN_REMOVE_DEVICE)
138     {
139         /* remove the device */
140         KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
141     }
142 
143     /* skip current irp stack */
144     IoSkipCurrentIrpStackLocation(Irp);
145 
146     /* call attached pnp device object */
147     Status = IoCallDriver(PnpDeviceObject, Irp);
148 
149     if (MinorFunction == IRP_MN_REMOVE_DEVICE)
150     {
151         /* time is over */
152         IoDetachDevice(PnpDeviceObject);
153         /* delete device */
154         IoDeleteDevice(DeviceObject);
155     }
156     /* done */
157     return Status;
158 }
159 
160 /*
161     @implemented
162 */
163 KSDDKAPI
164 NTSTATUS
165 NTAPI
KsDefaultDispatchPower(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)166 KsDefaultDispatchPower(
167     IN  PDEVICE_OBJECT DeviceObject,
168     IN  PIRP Irp)
169 {
170     PDEVICE_EXTENSION DeviceExtension;
171     PKSIDEVICE_HEADER DeviceHeader;
172     PKSIOBJECT_HEADER ObjectHeader;
173     //PIO_STACK_LOCATION IoStack;
174     PLIST_ENTRY ListEntry;
175     NTSTATUS Status;
176 
177     /* get current irp stack */
178     //IoStack = IoGetCurrentIrpStackLocation(Irp);
179 
180     /* caller wants to add the target device */
181     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
182 
183     /* get device header */
184     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
185 
186     /* FIXME locks */
187 
188     /* loop our power dispatch list and call registered notification functions */
189     ListEntry = DeviceHeader->PowerDispatchList.Flink;
190     /* let's go */
191     while(ListEntry != &DeviceHeader->PowerDispatchList)
192     {
193         /* get object header */
194         ObjectHeader = (PKSIOBJECT_HEADER)CONTAINING_RECORD(ListEntry, KSIOBJECT_HEADER, PowerDispatchEntry);
195 
196         /* does it have still a cb */
197         if (ObjectHeader->PowerDispatch)
198         {
199             /* call the power cb */
200             Status = ObjectHeader->PowerDispatch(ObjectHeader->PowerContext, Irp);
201             ASSERT(NT_SUCCESS(Status));
202         }
203 
204         /* iterate to next entry */
205         ListEntry = ListEntry->Flink;
206     }
207 
208     /* start next power irp */
209     PoStartNextPowerIrp(Irp);
210 
211     /* skip current irp stack location */
212     IoSkipCurrentIrpStackLocation(Irp);
213 
214     /* let's roll */
215     Status = PoCallDriver(DeviceHeader->PnpDeviceObject, Irp);
216 
217     /* done */
218     return Status;
219 }
220 
221 /*
222     @implemented
223 */
224 KSDDKAPI
225 NTSTATUS
226 NTAPI
KsDefaultForwardIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)227 KsDefaultForwardIrp(
228     IN PDEVICE_OBJECT DeviceObject,
229     IN PIRP Irp)
230 {
231     PDEVICE_EXTENSION DeviceExtension;
232     PKSIDEVICE_HEADER DeviceHeader;
233     //PIO_STACK_LOCATION IoStack;
234     NTSTATUS Status;
235 
236     /* get current irp stack */
237     //IoStack = IoGetCurrentIrpStackLocation(Irp);
238 
239     /* caller wants to add the target device */
240     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
241 
242     /* get device header */
243     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
244 
245     /* forward the request to the PDO */
246     Status = IoCallDriver(DeviceHeader->PnpDeviceObject, Irp);
247 
248     return Status;
249 }
250 
251 /*
252     @implemented
253 */
254 KSDDKAPI
255 VOID
256 NTAPI
KsSetDevicePnpAndBaseObject(IN KSDEVICE_HEADER Header,IN PDEVICE_OBJECT PnpDeviceObject,IN PDEVICE_OBJECT BaseDevice)257 KsSetDevicePnpAndBaseObject(
258     IN  KSDEVICE_HEADER Header,
259     IN  PDEVICE_OBJECT PnpDeviceObject,
260     IN  PDEVICE_OBJECT BaseDevice)
261 {
262     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
263 
264     DeviceHeader->PnpDeviceObject = PnpDeviceObject;
265     DeviceHeader->BaseDevice = BaseDevice;
266 }
267 
268 /*
269     @implemented
270 */
271 KSDDKAPI
272 PDEVICE_OBJECT
273 NTAPI
KsQueryDevicePnpObject(IN KSDEVICE_HEADER Header)274 KsQueryDevicePnpObject(
275     IN  KSDEVICE_HEADER Header)
276 {
277     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
278 
279     /* return PnpDeviceObject */
280     return DeviceHeader->PnpDeviceObject;
281 
282 }
283 
284 /*
285     @implemented
286 */
287 KSDDKAPI
288 ACCESS_MASK
289 NTAPI
KsQueryObjectAccessMask(IN KSOBJECT_HEADER Header)290 KsQueryObjectAccessMask(
291     IN KSOBJECT_HEADER Header)
292 {
293     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
294 
295     /* return access mask */
296     return ObjectHeader->AccessMask;
297 
298 }
299 
300 /*
301     @unimplemented
302 */
303 KSDDKAPI
304 VOID
305 NTAPI
KsRecalculateStackDepth(IN KSDEVICE_HEADER Header,IN BOOLEAN ReuseStackLocation)306 KsRecalculateStackDepth(
307     IN  KSDEVICE_HEADER Header,
308     IN  BOOLEAN ReuseStackLocation)
309 {
310     UNIMPLEMENTED;
311 }
312 
313 
314 /*
315     @implemented
316 */
317 KSDDKAPI
318 VOID
319 NTAPI
KsSetTargetState(IN KSOBJECT_HEADER Header,IN KSTARGET_STATE TargetState)320 KsSetTargetState(
321     IN  KSOBJECT_HEADER Header,
322     IN  KSTARGET_STATE TargetState)
323 {
324     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
325 
326     /* set target state */
327     DeviceHeader->TargetState = TargetState;
328 }
329 
330 /*
331     @implemented
332 */
333 KSDDKAPI
334 VOID
335 NTAPI
KsSetTargetDeviceObject(IN KSOBJECT_HEADER Header,IN PDEVICE_OBJECT TargetDevice OPTIONAL)336 KsSetTargetDeviceObject(
337     IN  KSOBJECT_HEADER Header,
338     IN  PDEVICE_OBJECT TargetDevice OPTIONAL)
339 {
340     PDEVICE_EXTENSION DeviceExtension;
341     PKSIDEVICE_HEADER DeviceHeader;
342     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
343 
344     if(ObjectHeader->TargetDevice)
345     {
346         /* there is already a target device set */
347         if (!TargetDevice)
348         {
349             /* caller wants to remove the target device */
350             DeviceExtension = (PDEVICE_EXTENSION)ObjectHeader->TargetDevice->DeviceExtension;
351 
352             /* get device header */
353             DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
354 
355             /* acquire lock */
356             KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
357 
358             /* remove entry */
359             RemoveEntryList(&ObjectHeader->TargetDeviceListEntry);
360 
361             /* remove device pointer */
362             ObjectHeader->TargetDevice = NULL;
363 
364             /* release lock */
365             KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
366         }
367     }
368     else
369     {
370         /* no target device yet set */
371         if (TargetDevice)
372         {
373             /* caller wants to add the target device */
374             DeviceExtension = (PDEVICE_EXTENSION)TargetDevice->DeviceExtension;
375 
376             /* get device header */
377             DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
378 
379             /* acquire lock */
380             KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
381 
382             /* insert list entry */
383             InsertTailList(&DeviceHeader->TargetDeviceList, &ObjectHeader->TargetDeviceListEntry);
384 
385             /* store target device */
386             ObjectHeader->TargetDevice = TargetDevice;
387 
388             /* release lock */
389             KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
390         }
391     }
392 
393 }
394 
395 /*
396     @implemented
397 */
398 KSDDKAPI
399 VOID
400 NTAPI
KsSetPowerDispatch(IN KSOBJECT_HEADER Header,IN PFNKSCONTEXT_DISPATCH PowerDispatch OPTIONAL,IN PVOID PowerContext OPTIONAL)401 KsSetPowerDispatch(
402     IN  KSOBJECT_HEADER Header,
403     IN  PFNKSCONTEXT_DISPATCH PowerDispatch OPTIONAL,
404     IN  PVOID PowerContext OPTIONAL)
405 {
406     PDEVICE_EXTENSION DeviceExtension;
407     PKSIDEVICE_HEADER DeviceHeader;
408     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
409 
410     /* caller wants to add the target device */
411     DeviceExtension = (PDEVICE_EXTENSION)ObjectHeader->ParentDeviceObject->DeviceExtension;
412 
413     /* get device header */
414     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
415 
416     /* acquire lock */
417     KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
418 
419     if (PowerDispatch)
420     {
421         /* add power dispatch entry */
422         InsertTailList(&DeviceHeader->PowerDispatchList, &ObjectHeader->PowerDispatchEntry);
423 
424        /* store function and context */
425        ObjectHeader->PowerDispatch = PowerDispatch;
426        ObjectHeader->PowerContext = PowerContext;
427     }
428     else
429     {
430         /* remove power dispatch entry */
431         RemoveEntryList(&ObjectHeader->PowerDispatchEntry);
432 
433        /* store function and context */
434        ObjectHeader->PowerDispatch = NULL;
435        ObjectHeader->PowerContext = NULL;
436 
437     }
438 
439     /* release lock */
440     KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
441 }
442 
443 
444 /*
445     @implemented
446 */
447 KSDDKAPI
448 PKSOBJECT_CREATE_ITEM
449 NTAPI
KsQueryObjectCreateItem(IN KSOBJECT_HEADER Header)450 KsQueryObjectCreateItem(
451     IN KSOBJECT_HEADER Header)
452 {
453     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
454     return ObjectHeader->OriginalCreateItem;
455 }
456 
457 NTSTATUS
KspAddCreateItemToList(OUT PLIST_ENTRY ListHead,IN ULONG ItemsCount,IN PKSOBJECT_CREATE_ITEM ItemsList)458 KspAddCreateItemToList(
459     OUT PLIST_ENTRY ListHead,
460     IN ULONG ItemsCount,
461     IN  PKSOBJECT_CREATE_ITEM ItemsList)
462 {
463     ULONG Index;
464     PCREATE_ITEM_ENTRY Entry;
465 
466     /* add the items */
467     for(Index = 0; Index < ItemsCount; Index++)
468     {
469         /* allocate item */
470         Entry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
471         if (!Entry)
472         {
473             /* no memory */
474             return STATUS_INSUFFICIENT_RESOURCES;
475         }
476 
477         /* initialize entry */
478         InitializeListHead(&Entry->ObjectItemList);
479         Entry->CreateItem = &ItemsList[Index];
480         Entry->ReferenceCount = 0;
481         Entry->ItemFreeCallback = NULL;
482 
483         InsertTailList(ListHead, &Entry->Entry);
484     }
485     return STATUS_SUCCESS;
486 }
487 
488 VOID
KspFreeCreateItems(PLIST_ENTRY ListHead)489 KspFreeCreateItems(
490     PLIST_ENTRY ListHead)
491 {
492     PCREATE_ITEM_ENTRY Entry;
493 
494     while(!IsListEmpty(ListHead))
495     {
496         /* remove create item from list */
497         Entry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(RemoveHeadList(ListHead), CREATE_ITEM_ENTRY, Entry);
498 
499         /* caller shouldnt have any references */
500         //ASSERT(Entry->ReferenceCount == 0);
501         //ASSERT(IsListEmpty(&Entry->ObjectItemList));
502 
503         /* does the creator wish notification */
504         if (Entry->ItemFreeCallback)
505         {
506             /* notify creator */
507             Entry->ItemFreeCallback(Entry->CreateItem);
508         }
509 
510         /* free create item entry */
511          FreeItem(Entry);
512     }
513 
514 }
515 
516 /*
517     @implemented
518 */
519 KSDDKAPI
520 NTSTATUS
521 NTAPI
KsAllocateDeviceHeader(OUT KSDEVICE_HEADER * OutHeader,IN ULONG ItemsCount,IN PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL)522 KsAllocateDeviceHeader(
523     OUT KSDEVICE_HEADER* OutHeader,
524     IN  ULONG ItemsCount,
525     IN  PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL)
526 {
527     NTSTATUS Status = STATUS_SUCCESS;
528     PKSIDEVICE_HEADER Header;
529 
530     if (!OutHeader)
531         return STATUS_INVALID_PARAMETER;
532 
533     /* allocate a device header */
534     Header = AllocateItem(PagedPool, sizeof(KSIDEVICE_HEADER));
535 
536     /* check for success */
537     if (!Header)
538         return STATUS_INSUFFICIENT_RESOURCES;
539 
540     /* clear all memory */
541     RtlZeroMemory(Header, sizeof(KSIDEVICE_HEADER));
542 
543     /* initialize device mutex */
544     KeInitializeMutex(&Header->DeviceMutex, 0);
545 
546     /* initialize target device list */
547     InitializeListHead(&Header->TargetDeviceList);
548     /* initialize power dispatch list */
549     InitializeListHead(&Header->PowerDispatchList);
550     /* initialize object bag lists */
551     InitializeListHead(&Header->ObjectBags);
552 
553     /* initialize create item list */
554     InitializeListHead(&Header->ItemList);
555 
556     /* initialize basic header */
557     Header->BasicHeader.Type = KsObjectTypeDevice;
558     Header->BasicHeader.KsDevice = &Header->KsDevice;
559     Header->BasicHeader.Parent.KsDevice = &Header->KsDevice;
560 
561     /* are there any create items provided */
562     if (ItemsCount && ItemsList)
563     {
564         Status = KspAddCreateItemToList(&Header->ItemList, ItemsCount, ItemsList);
565 
566         if (NT_SUCCESS(Status))
567         {
568             /* store item count */
569             Header->ItemListCount = ItemsCount;
570         }
571         else
572         {
573             /* release create items */
574             KspFreeCreateItems(&Header->ItemList);
575         }
576     }
577 
578     /* store result */
579     *OutHeader = Header;
580 
581     return Status;
582 }
583 
584 /*
585     @implemented
586 */
587 KSDDKAPI
588 VOID
589 NTAPI
KsFreeDeviceHeader(IN KSDEVICE_HEADER DevHeader)590 KsFreeDeviceHeader(
591     IN  KSDEVICE_HEADER DevHeader)
592 {
593     PKSIDEVICE_HEADER Header;
594 
595     Header = (PKSIDEVICE_HEADER)DevHeader;
596 
597     if (!DevHeader)
598         return;
599 
600     KspFreeCreateItems(&Header->ItemList);
601     FreeItem(Header);
602 }
603 
604 /*
605     @implemented
606 */
607 KSDDKAPI
608 NTSTATUS
609 NTAPI
KsAllocateObjectHeader(OUT KSOBJECT_HEADER * Header,IN ULONG ItemsCount,IN PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL,IN PIRP Irp,IN KSDISPATCH_TABLE * Table)610 KsAllocateObjectHeader(
611     OUT KSOBJECT_HEADER *Header,
612     IN  ULONG ItemsCount,
613     IN  PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL,
614     IN  PIRP Irp,
615     IN  KSDISPATCH_TABLE* Table)
616 {
617     PIO_STACK_LOCATION IoStack;
618     //PDEVICE_EXTENSION DeviceExtension;
619     //PKSIDEVICE_HEADER DeviceHeader;
620     PKSIOBJECT_HEADER ObjectHeader;
621     //PKSOBJECT_CREATE_ITEM CreateItem;
622     NTSTATUS Status;
623 
624     if (!Header)
625         return STATUS_INVALID_PARAMETER_1;
626 
627     if (!Irp)
628         return STATUS_INVALID_PARAMETER_4;
629 
630     if (!Table)
631         return STATUS_INVALID_PARAMETER_5;
632 
633     /* get current stack location */
634     IoStack = IoGetCurrentIrpStackLocation(Irp);
635     /* get device extension */
636     //DeviceExtension = (PDEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
637     /* get device header */
638     //DeviceHeader = DeviceExtension->DeviceHeader;
639 
640     /* sanity check */
641     ASSERT(IoStack->FileObject);
642     /* check for an file object */
643 
644     /* allocate the object header */
645     ObjectHeader = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_HEADER));
646     if (!ObjectHeader)
647         return STATUS_INSUFFICIENT_RESOURCES;
648 
649     /* initialize object header */
650     RtlZeroMemory(ObjectHeader, sizeof(KSIOBJECT_HEADER));
651 
652     /* initialize create item list */
653     InitializeListHead(&ObjectHeader->ItemList);
654 
655     /* get create item */
656     //CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
657 
658     /* do we have a name */
659     if (IoStack->FileObject->FileName.Buffer)
660     {
661         /* copy object class */
662         ObjectHeader->ObjectClass.MaximumLength = IoStack->FileObject->FileName.MaximumLength;
663         ObjectHeader->ObjectClass.Buffer = AllocateItem(NonPagedPool, ObjectHeader->ObjectClass.MaximumLength);
664         if (!ObjectHeader->ObjectClass.Buffer)
665         {
666             FreeItem(ObjectHeader);
667             return STATUS_INSUFFICIENT_RESOURCES;
668         }
669         RtlCopyUnicodeString(&ObjectHeader->ObjectClass, &IoStack->FileObject->FileName);
670     }
671 
672     /* copy dispatch table */
673     RtlCopyMemory(&ObjectHeader->DispatchTable, Table, sizeof(KSDISPATCH_TABLE));
674 
675     /* store create items */
676     if (ItemsCount && ItemsList)
677     {
678         Status = KspAddCreateItemToList(&ObjectHeader->ItemList, ItemsCount, ItemsList);
679 
680         if (NT_SUCCESS(Status))
681         {
682             /* store item count */
683             ObjectHeader->ItemListCount = ItemsCount;
684         }
685         else
686         {
687             /* destroy header*/
688             KsFreeObjectHeader(ObjectHeader);
689             return Status;
690         }
691     }
692     /* store the object in the file object */
693     IoStack->FileObject->FsContext2 = ObjectHeader;
694 
695     /* store parent device */
696     ObjectHeader->ParentDeviceObject = IoGetRelatedDeviceObject(IoStack->FileObject);
697 
698     /* store originating create item */
699     ObjectHeader->OriginalCreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
700 
701     /* FIXME store access mask see KsQueryObjectAccessMask */
702     ObjectHeader->AccessMask = IoStack->Parameters.Create.SecurityContext->DesiredAccess;
703 
704 
705     /* store result */
706     *Header = ObjectHeader;
707 
708     DPRINT("KsAllocateObjectHeader ObjectClass %S FileObject %p, ObjectHeader %p\n", ObjectHeader->ObjectClass.Buffer, IoStack->FileObject, ObjectHeader);
709 
710     return STATUS_SUCCESS;
711 
712 }
713 
714 /*
715     @implemented
716 */
717 KSDDKAPI
718 VOID
719 NTAPI
KsFreeObjectHeader(IN PVOID Header)720 KsFreeObjectHeader(
721     IN  PVOID Header)
722 {
723     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER) Header;
724 
725     DPRINT("KsFreeObjectHeader Header %p Class %wZ\n", Header, &ObjectHeader->ObjectClass);
726 
727     if (ObjectHeader->ObjectClass.Buffer)
728     {
729         /* release object class buffer */
730         FreeItem(ObjectHeader->ObjectClass.Buffer);
731     }
732 
733     if (ObjectHeader->Unknown)
734     {
735         /* release associated object */
736         ObjectHeader->Unknown->lpVtbl->Release(ObjectHeader->Unknown);
737     }
738 
739     /* free create items */
740     KspFreeCreateItems(&ObjectHeader->ItemList);
741 
742     /* free object header */
743     FreeItem(ObjectHeader);
744 
745 }
746 
747 NTSTATUS
KspAddObjectCreateItemToList(PLIST_ENTRY ListHead,IN PDRIVER_DISPATCH Create,IN PVOID Context,IN PWCHAR ObjectClass,IN PSECURITY_DESCRIPTOR SecurityDescriptor)748 KspAddObjectCreateItemToList(
749     PLIST_ENTRY ListHead,
750     IN  PDRIVER_DISPATCH Create,
751     IN  PVOID Context,
752     IN  PWCHAR ObjectClass,
753     IN  PSECURITY_DESCRIPTOR SecurityDescriptor)
754 {
755    PLIST_ENTRY Entry;
756    PCREATE_ITEM_ENTRY CreateEntry;
757 
758     /* point to first entry */
759     Entry = ListHead->Flink;
760 
761     while(Entry != ListHead)
762     {
763         /* get create entry */
764         CreateEntry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(Entry, CREATE_ITEM_ENTRY, Entry);
765         /* if the create item has no create routine, then it is free to use */
766         if (CreateEntry->CreateItem->Create == NULL)
767         {
768             /* sanity check */
769             ASSERT(IsListEmpty(&CreateEntry->ObjectItemList));
770             ASSERT(CreateEntry->ReferenceCount == 0);
771             /* use free entry */
772             CreateEntry->CreateItem->Context = Context;
773             CreateEntry->CreateItem->Create = Create;
774             RtlInitUnicodeString(&CreateEntry->CreateItem->ObjectClass, ObjectClass);
775             CreateEntry->CreateItem->SecurityDescriptor = SecurityDescriptor;
776 
777             return STATUS_SUCCESS;
778         }
779 
780         if (!_wcsicmp(ObjectClass, CreateEntry->CreateItem->ObjectClass.Buffer))
781         {
782             /* the same object class already exists */
783             return STATUS_OBJECT_NAME_COLLISION;
784         }
785 
786         /* iterate to next entry */
787         Entry = Entry->Flink;
788     }
789     return STATUS_ALLOTTED_SPACE_EXCEEDED;
790 }
791 
792 /*
793     @implemented
794 */
795 KSDDKAPI
796 NTSTATUS
797 NTAPI
KsAddObjectCreateItemToDeviceHeader(IN KSDEVICE_HEADER DevHeader,IN PDRIVER_DISPATCH Create,IN PVOID Context,IN PWCHAR ObjectClass,IN PSECURITY_DESCRIPTOR SecurityDescriptor)798 KsAddObjectCreateItemToDeviceHeader(
799     IN  KSDEVICE_HEADER DevHeader,
800     IN  PDRIVER_DISPATCH Create,
801     IN  PVOID Context,
802     IN  PWCHAR ObjectClass,
803     IN  PSECURITY_DESCRIPTOR SecurityDescriptor)
804 {
805     PKSIDEVICE_HEADER Header;
806     NTSTATUS Status;
807 
808     Header = (PKSIDEVICE_HEADER)DevHeader;
809 
810     DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
811 
812      /* check if a device header has been provided */
813     if (!DevHeader)
814         return STATUS_INVALID_PARAMETER_1;
815 
816     /* check if a create item has been provided */
817     if (!Create)
818         return STATUS_INVALID_PARAMETER_2;
819 
820     /* check if a object class has been provided */
821     if (!ObjectClass)
822         return STATUS_INVALID_PARAMETER_4;
823 
824     /* let others do the work */
825     Status = KspAddObjectCreateItemToList(&Header->ItemList, Create, Context, ObjectClass, SecurityDescriptor);
826 
827     if (NT_SUCCESS(Status))
828     {
829         /* increment create item count */
830         InterlockedIncrement(&Header->ItemListCount);
831     }
832     DPRINT("KsAddObjectCreateItemToDeviceHeader Status %x\n", Status);
833     return Status;
834 }
835 
836 /*
837     @implemented
838 */
839 KSDDKAPI
840 NTSTATUS
841 NTAPI
KsAddObjectCreateItemToObjectHeader(IN KSOBJECT_HEADER ObjectHeader,IN PDRIVER_DISPATCH Create,IN PVOID Context,IN PWCHAR ObjectClass,IN PSECURITY_DESCRIPTOR SecurityDescriptor)842 KsAddObjectCreateItemToObjectHeader(
843     IN  KSOBJECT_HEADER ObjectHeader,
844     IN  PDRIVER_DISPATCH Create,
845     IN  PVOID Context,
846     IN  PWCHAR ObjectClass,
847     IN  PSECURITY_DESCRIPTOR SecurityDescriptor)
848 {
849     PKSIOBJECT_HEADER Header;
850     NTSTATUS Status;
851 
852     Header = (PKSIOBJECT_HEADER)ObjectHeader;
853 
854     DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
855 
856      /* check if a device header has been provided */
857     if (!Header)
858         return STATUS_INVALID_PARAMETER_1;
859 
860     /* check if a create item has been provided */
861     if (!Create)
862         return STATUS_INVALID_PARAMETER_2;
863 
864     /* check if a object class has been provided */
865     if (!ObjectClass)
866         return STATUS_INVALID_PARAMETER_4;
867 
868     /* let's work */
869     Status = KspAddObjectCreateItemToList(&Header->ItemList, Create, Context, ObjectClass, SecurityDescriptor);
870 
871     if (NT_SUCCESS(Status))
872     {
873         /* increment create item count */
874         InterlockedIncrement(&Header->ItemListCount);
875     }
876 
877     return Status;
878 }
879 
880 /*
881     @implemented
882 */
883 KSDDKAPI
884 NTSTATUS
885 NTAPI
KsAllocateObjectCreateItem(IN KSDEVICE_HEADER DevHeader,IN PKSOBJECT_CREATE_ITEM CreateItem,IN BOOLEAN AllocateEntry,IN PFNKSITEMFREECALLBACK ItemFreeCallback OPTIONAL)886 KsAllocateObjectCreateItem(
887     IN  KSDEVICE_HEADER DevHeader,
888     IN  PKSOBJECT_CREATE_ITEM CreateItem,
889     IN  BOOLEAN AllocateEntry,
890     IN  PFNKSITEMFREECALLBACK ItemFreeCallback OPTIONAL)
891 {
892     PCREATE_ITEM_ENTRY CreateEntry;
893     PKSIDEVICE_HEADER Header;
894     PKSOBJECT_CREATE_ITEM Item;
895 
896     Header = (PKSIDEVICE_HEADER)DevHeader;
897 
898     if (!DevHeader)
899         return STATUS_INVALID_PARAMETER_1;
900 
901     if (!CreateItem)
902         return STATUS_INVALID_PARAMETER_2;
903 
904     /* first allocate a create entry */
905     CreateEntry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
906 
907     /* check for allocation success */
908     if (!CreateEntry)
909     {
910         /* not enough resources */
911         return STATUS_INSUFFICIENT_RESOURCES;
912     }
913 
914 
915     if (AllocateEntry)
916     {
917         /* allocate create item */
918         Item = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
919         if (!Item)
920         {
921             /* no memory */
922             FreeItem(CreateEntry);
923             return STATUS_INSUFFICIENT_RESOURCES;
924         }
925 
926         /* initialize descriptor */
927         Item->Context = CreateItem->Context;
928         Item->Create = CreateItem->Create;
929         Item->Flags = CreateItem->Flags;
930         Item->SecurityDescriptor = CreateItem->SecurityDescriptor;
931         Item->ObjectClass.Length = 0;
932         Item->ObjectClass.MaximumLength = CreateItem->ObjectClass.MaximumLength;
933 
934         /* copy object class */
935         Item->ObjectClass.Buffer = AllocateItem(NonPagedPool, Item->ObjectClass.MaximumLength);
936         if (!Item->ObjectClass.Buffer)
937         {
938             /* release resources */
939             FreeItem(Item);
940             FreeItem(CreateEntry);
941 
942             return STATUS_INSUFFICIENT_RESOURCES;
943         }
944         RtlCopyUnicodeString(&Item->ObjectClass, &CreateItem->ObjectClass);
945     }
946     else
947     {
948         if (ItemFreeCallback)
949         {
950             /* callback is only accepted when the create item is copied */
951             ItemFreeCallback = NULL;
952         }
953         /* use passed create item */
954         Item = CreateItem;
955     }
956 
957     /* initialize create item entry */
958     InitializeListHead(&CreateEntry->ObjectItemList);
959     CreateEntry->ItemFreeCallback = ItemFreeCallback;
960     CreateEntry->CreateItem = Item;
961     CreateEntry->ReferenceCount = 0;
962 
963     /* now insert the create item entry */
964     InsertTailList(&Header->ItemList, &CreateEntry->Entry);
965 
966     /* increment item count */
967     InterlockedIncrement(&Header->ItemListCount);
968 
969     return STATUS_SUCCESS;
970 }
971 
972 NTSTATUS
KspObjectFreeCreateItems(IN KSDEVICE_HEADER Header,IN PKSOBJECT_CREATE_ITEM CreateItem)973 KspObjectFreeCreateItems(
974     IN  KSDEVICE_HEADER Header,
975     IN  PKSOBJECT_CREATE_ITEM CreateItem)
976 {
977     UNIMPLEMENTED;
978     return STATUS_NOT_IMPLEMENTED;
979 }
980 
981 /*
982     @implemented
983 */
984 KSDDKAPI
985 NTSTATUS
986 NTAPI
KsFreeObjectCreateItem(IN KSDEVICE_HEADER Header,IN PUNICODE_STRING CreateItem)987 KsFreeObjectCreateItem(
988     IN  KSDEVICE_HEADER Header,
989     IN  PUNICODE_STRING CreateItem)
990 {
991     KSOBJECT_CREATE_ITEM Item;
992 
993     RtlZeroMemory(&Item, sizeof(KSOBJECT_CREATE_ITEM));
994     RtlInitUnicodeString(&Item.ObjectClass, CreateItem->Buffer);
995 
996     return KspObjectFreeCreateItems(Header, &Item);
997 }
998 
999 
1000 /*
1001     @implemented
1002 */
1003 KSDDKAPI
1004 NTSTATUS
1005 NTAPI
KsFreeObjectCreateItemsByContext(IN KSDEVICE_HEADER Header,IN PVOID Context)1006 KsFreeObjectCreateItemsByContext(
1007     IN  KSDEVICE_HEADER Header,
1008     IN  PVOID Context)
1009 {
1010     KSOBJECT_CREATE_ITEM Item;
1011 
1012     RtlZeroMemory(&Item, sizeof(KSOBJECT_CREATE_ITEM));
1013 
1014     Item.Context = Context;
1015 
1016     return KspObjectFreeCreateItems(Header, &Item);
1017 }
1018 
1019 /*
1020     @implemented
1021 */
1022 KSDDKAPI
1023 NTSTATUS
1024 NTAPI
KsCreateDefaultSecurity(IN PSECURITY_DESCRIPTOR ParentSecurity OPTIONAL,OUT PSECURITY_DESCRIPTOR * DefaultSecurity)1025 KsCreateDefaultSecurity(
1026     IN PSECURITY_DESCRIPTOR ParentSecurity OPTIONAL,
1027     OUT PSECURITY_DESCRIPTOR* DefaultSecurity)
1028 {
1029     PGENERIC_MAPPING Mapping;
1030     SECURITY_SUBJECT_CONTEXT SubjectContext;
1031     NTSTATUS Status;
1032 
1033     /* start capturing security context of calling thread */
1034     SeCaptureSubjectContext(&SubjectContext);
1035     /* get generic mapping */
1036     Mapping = IoGetFileObjectGenericMapping();
1037     /* build new descriptor */
1038     Status = SeAssignSecurity(ParentSecurity, NULL, DefaultSecurity, FALSE, &SubjectContext, Mapping, NonPagedPool);
1039     /* release security descriptor */
1040     SeReleaseSubjectContext(&SubjectContext);
1041     /* done */
1042     return Status;
1043 }
1044 
1045 /*
1046     @unimplemented
1047 */
1048 KSDDKAPI
1049 NTSTATUS
1050 NTAPI
KsForwardIrp(IN PIRP Irp,IN PFILE_OBJECT FileObject,IN BOOLEAN ReuseStackLocation)1051 KsForwardIrp(
1052     IN  PIRP Irp,
1053     IN  PFILE_OBJECT FileObject,
1054     IN  BOOLEAN ReuseStackLocation)
1055 {
1056     UNIMPLEMENTED;
1057     return STATUS_UNSUCCESSFUL;
1058 }
1059 
1060 
1061 /*
1062     @unimplemented
1063 */
1064 KSDDKAPI
1065 NTSTATUS
1066 NTAPI
KsForwardAndCatchIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PFILE_OBJECT FileObject,IN KSSTACK_USE StackUse)1067 KsForwardAndCatchIrp(
1068     IN  PDEVICE_OBJECT DeviceObject,
1069     IN  PIRP Irp,
1070     IN  PFILE_OBJECT FileObject,
1071     IN  KSSTACK_USE StackUse)
1072 {
1073     UNIMPLEMENTED;
1074     return STATUS_UNSUCCESSFUL;
1075 }
1076 
1077 
1078 NTSTATUS
1079 NTAPI
KspSynchronousIoControlDeviceCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)1080 KspSynchronousIoControlDeviceCompletion(
1081     IN PDEVICE_OBJECT  DeviceObject,
1082     IN PIRP  Irp,
1083     IN PVOID  Context)
1084 {
1085     PIO_STATUS_BLOCK IoStatusBlock = (PIO_STATUS_BLOCK)Context;
1086 
1087     IoStatusBlock->Information = Irp->IoStatus.Information;
1088     IoStatusBlock->Status = Irp->IoStatus.Status;
1089 
1090     return STATUS_SUCCESS;
1091 }
1092 
1093 /*
1094     @implemented
1095 */
1096 KSDDKAPI
1097 NTSTATUS
1098 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)1099 KsSynchronousIoControlDevice(
1100     IN  PFILE_OBJECT FileObject,
1101     IN  KPROCESSOR_MODE RequestorMode,
1102     IN  ULONG IoControl,
1103     IN  PVOID InBuffer,
1104     IN  ULONG InSize,
1105     OUT PVOID OutBuffer,
1106     IN  ULONG OutSize,
1107     OUT PULONG BytesReturned)
1108 {
1109     PKSIOBJECT_HEADER ObjectHeader;
1110     PDEVICE_OBJECT DeviceObject;
1111     KEVENT Event;
1112     PIRP Irp;
1113     IO_STATUS_BLOCK IoStatusBlock;
1114     PIO_STACK_LOCATION IoStack;
1115     NTSTATUS Status;
1116 
1117     /* check for valid file object */
1118     if (!FileObject)
1119         return STATUS_INVALID_PARAMETER;
1120 
1121     /* get device object to send the request to */
1122     DeviceObject = IoGetRelatedDeviceObject(FileObject);
1123     if (!DeviceObject)
1124         return STATUS_UNSUCCESSFUL;
1125 
1126 
1127     /* get object header */
1128     ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
1129 
1130     /* check if there is fast device io function */
1131     if (ObjectHeader && ObjectHeader->DispatchTable.FastDeviceIoControl)
1132     {
1133         IoStatusBlock.Status = STATUS_UNSUCCESSFUL;
1134         IoStatusBlock.Information = 0;
1135 
1136         /* send the request */
1137         Status = ObjectHeader->DispatchTable.FastDeviceIoControl(FileObject, TRUE, InBuffer, InSize, OutBuffer, OutSize, IoControl, &IoStatusBlock, DeviceObject);
1138         /* check if the request was handled */
1139         //DPRINT("Handled %u Status %x Length %u\n", Status, IoStatusBlock.Status, IoStatusBlock.Information);
1140         if (Status)
1141         {
1142             /* store bytes returned */
1143             *BytesReturned = (ULONG)IoStatusBlock.Information;
1144             /* return status */
1145             return IoStatusBlock.Status;
1146         }
1147     }
1148 
1149     /* initialize the event */
1150     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1151 
1152     /* create the irp */
1153     Irp =  IoBuildDeviceIoControlRequest(IoControl, DeviceObject, InBuffer, InSize, OutBuffer, OutSize, FALSE, &Event, &IoStatusBlock);
1154 
1155     if (!Irp)
1156     {
1157         /* no memory to allocate the irp */
1158         return STATUS_INSUFFICIENT_RESOURCES;
1159     }
1160 
1161 
1162     /* Store Fileobject */
1163     IoStack = IoGetNextIrpStackLocation(Irp);
1164     IoStack->FileObject = FileObject;
1165 
1166     if (IoControl == IOCTL_KS_WRITE_STREAM)
1167     {
1168         Irp->AssociatedIrp.SystemBuffer = OutBuffer;
1169     }
1170     else if (IoControl == IOCTL_KS_READ_STREAM)
1171     {
1172         Irp->AssociatedIrp.SystemBuffer = InBuffer;
1173     }
1174 
1175     IoSetCompletionRoutine(Irp, KspSynchronousIoControlDeviceCompletion, (PVOID)&IoStatusBlock, TRUE, TRUE, TRUE);
1176 
1177     Status = IoCallDriver(DeviceObject, Irp);
1178     if (Status == STATUS_PENDING)
1179     {
1180         KeWaitForSingleObject(&Event, Executive, RequestorMode, FALSE, NULL);
1181         Status = IoStatusBlock.Status;
1182     }
1183 
1184     *BytesReturned = (ULONG)IoStatusBlock.Information;
1185     return Status;
1186 }
1187 
1188 /*
1189     @unimplemented
1190 */
1191 KSDDKAPI
1192 NTSTATUS
1193 NTAPI
KsUnserializeObjectPropertiesFromRegistry(IN PFILE_OBJECT FileObject,IN HANDLE ParentKey OPTIONAL,IN PUNICODE_STRING RegistryPath OPTIONAL)1194 KsUnserializeObjectPropertiesFromRegistry(
1195     IN PFILE_OBJECT FileObject,
1196     IN HANDLE ParentKey OPTIONAL,
1197     IN PUNICODE_STRING RegistryPath OPTIONAL)
1198 {
1199     UNIMPLEMENTED;
1200     return STATUS_NOT_IMPLEMENTED;
1201 }
1202 
1203 
1204 /*
1205     @implemented
1206 */
1207 KSDDKAPI
1208 NTSTATUS
1209 NTAPI
KsCacheMedium(IN PUNICODE_STRING SymbolicLink,IN PKSPIN_MEDIUM Medium,IN ULONG PinDirection)1210 KsCacheMedium(
1211     IN  PUNICODE_STRING SymbolicLink,
1212     IN  PKSPIN_MEDIUM Medium,
1213     IN  ULONG PinDirection)
1214 {
1215     HANDLE hKey;
1216     UNICODE_STRING Path;
1217     UNICODE_STRING BasePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediumCache\\");
1218     UNICODE_STRING GuidString;
1219     NTSTATUS Status;
1220     OBJECT_ATTRIBUTES ObjectAttributes;
1221     BOOLEAN PathAdjusted = FALSE;
1222     ULONG Value = 0;
1223 
1224     /* first check if the medium is standard */
1225     if (IsEqualGUIDAligned(&KSMEDIUMSETID_Standard, &Medium->Set) ||
1226         IsEqualGUIDAligned(&GUID_NULL, &Medium->Set))
1227     {
1228         /* no need to cache that */
1229         return STATUS_SUCCESS;
1230     }
1231 
1232     /* convert guid to string */
1233     Status = RtlStringFromGUID(&Medium->Set, &GuidString);
1234     if (!NT_SUCCESS(Status))
1235         return Status;
1236 
1237     /* allocate path buffer */
1238     Path.Length = 0;
1239     Path.MaximumLength = BasePath.MaximumLength + GuidString.MaximumLength + 10 * sizeof(WCHAR);
1240     Path.Buffer = AllocateItem(PagedPool, Path.MaximumLength);
1241     if (!Path.Buffer)
1242     {
1243         /* not enough resources */
1244         RtlFreeUnicodeString(&GuidString);
1245         return STATUS_INSUFFICIENT_RESOURCES;
1246     }
1247 
1248     RtlAppendUnicodeStringToString(&Path, &BasePath);
1249     RtlAppendUnicodeStringToString(&Path, &GuidString);
1250     RtlAppendUnicodeToString(&Path, L"-");
1251     /* FIXME append real instance id */
1252     RtlAppendUnicodeToString(&Path, L"0");
1253     RtlAppendUnicodeToString(&Path, L"-");
1254     /* FIXME append real instance id */
1255     RtlAppendUnicodeToString(&Path, L"0");
1256 
1257     /* free guid string */
1258     RtlFreeUnicodeString(&GuidString);
1259 
1260     /* initialize object attributes */
1261     InitializeObjectAttributes(&ObjectAttributes, &Path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
1262     /* create the key */
1263     Status = ZwCreateKey(&hKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1264 
1265     /* free path buffer */
1266     FreeItem(Path.Buffer);
1267 
1268     if (NT_SUCCESS(Status))
1269     {
1270         /* store symbolic link */
1271         if (SymbolicLink->Buffer[1] == L'?' && SymbolicLink->Buffer[2] == L'?')
1272         {
1273             /* replace kernel path with user mode path */
1274             SymbolicLink->Buffer[1] = L'\\';
1275             PathAdjusted = TRUE;
1276         }
1277 
1278         /* store the key */
1279         Status = ZwSetValueKey(hKey, SymbolicLink, 0, REG_DWORD, &Value, sizeof(ULONG));
1280 
1281         if (PathAdjusted)
1282         {
1283             /* restore kernel path */
1284             SymbolicLink->Buffer[1] = L'?';
1285         }
1286 
1287         ZwClose(hKey);
1288     }
1289 
1290     /* done */
1291     return Status;
1292 }
1293 
1294 /*
1295     @implemented
1296 */
1297 NTSTATUS
1298 NTAPI
DllInitialize(PUNICODE_STRING RegistryPath)1299 DllInitialize(
1300     PUNICODE_STRING  RegistryPath)
1301 {
1302     return STATUS_SUCCESS;
1303 }
1304 
1305 
1306 NTSTATUS
1307 NTAPI
KopDispatchClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1308 KopDispatchClose(
1309     IN PDEVICE_OBJECT DeviceObject,
1310     IN PIRP Irp)
1311 {
1312     PKO_OBJECT_HEADER Header;
1313     PIO_STACK_LOCATION IoStack;
1314     PDEVICE_EXTENSION DeviceExtension;
1315 
1316     /* get current irp stack location */
1317     IoStack = IoGetCurrentIrpStackLocation(Irp);
1318 
1319     /* get ko object header */
1320     Header = (PKO_OBJECT_HEADER)IoStack->FileObject->FsContext2;
1321 
1322     /* free ks object header */
1323     KsFreeObjectHeader(Header->ObjectHeader);
1324 
1325     /* free ko object header */
1326     FreeItem(Header);
1327 
1328     /* get device extension */
1329     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1330 
1331     /* release bus object */
1332     KsDereferenceBusObject((KSDEVICE_HEADER)DeviceExtension->DeviceHeader);
1333 
1334     /* complete request */
1335     Irp->IoStatus.Status = STATUS_SUCCESS;
1336     CompleteRequest(Irp, IO_NO_INCREMENT);
1337 
1338     return STATUS_SUCCESS;
1339 }
1340 
1341 
1342 
1343 static KSDISPATCH_TABLE KoDispatchTable =
1344 {
1345     KsDispatchInvalidDeviceRequest,
1346     KsDispatchInvalidDeviceRequest,
1347     KsDispatchInvalidDeviceRequest,
1348     KsDispatchInvalidDeviceRequest,
1349     KopDispatchClose,
1350     KsDispatchQuerySecurity,
1351     KsDispatchSetSecurity,
1352     KsDispatchFastIoDeviceControlFailure,
1353     KsDispatchFastReadFailure,
1354     KsDispatchFastReadFailure,
1355 };
1356 
1357 
1358 NTSTATUS
1359 NTAPI
KopDispatchCreate(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1360 KopDispatchCreate(
1361     IN PDEVICE_OBJECT DeviceObject,
1362     IN PIRP Irp)
1363 {
1364     PKO_OBJECT_HEADER Header = NULL;
1365     PIO_STACK_LOCATION IoStack;
1366     PKO_DRIVER_EXTENSION DriverObjectExtension;
1367     NTSTATUS Status;
1368 
1369     /* get current irp stack location */
1370     IoStack = IoGetCurrentIrpStackLocation(Irp);
1371 
1372     if (!IoStack->FileObject)
1373     {
1374         DPRINT1("FileObject not attached!\n");
1375         Status = STATUS_UNSUCCESSFUL;
1376         goto cleanup;
1377     }
1378 
1379     /* get driver object extension */
1380     DriverObjectExtension = (PKO_DRIVER_EXTENSION)IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)KoDriverInitialize);
1381     if (!DriverObjectExtension)
1382     {
1383         DPRINT1("No DriverObjectExtension!\n");
1384         Status = STATUS_UNSUCCESSFUL;
1385         goto cleanup;
1386     }
1387 
1388     /* allocate ko object header */
1389     Header = (PKO_OBJECT_HEADER)AllocateItem(NonPagedPool, sizeof(KO_OBJECT_HEADER));
1390     if (!Header)
1391     {
1392         DPRINT1("failed to allocate KO_OBJECT_HEADER\n");
1393         Status = STATUS_INSUFFICIENT_RESOURCES;
1394         goto cleanup;
1395     }
1396 
1397     /* initialize create item */
1398     Header->CreateItem.Create = KopDispatchCreate;
1399     RtlInitUnicodeString(&Header->CreateItem.ObjectClass, KOSTRING_CreateObject);
1400 
1401 
1402     /* now allocate the object header */
1403     Status = KsAllocateObjectHeader(&Header->ObjectHeader, 1, &Header->CreateItem, Irp, &KoDispatchTable);
1404     if (!NT_SUCCESS(Status))
1405     {
1406         /* failed */
1407         goto cleanup;
1408     }
1409 
1410     /* FIXME
1411      * extract clsid and interface id from irp
1412      * call the standard create handler
1413      */
1414 
1415     UNIMPLEMENTED;
1416 
1417     IoStack->FileObject->FsContext2 = (PVOID)Header;
1418 
1419     Irp->IoStatus.Status = Status;
1420     CompleteRequest(Irp, IO_NO_INCREMENT);
1421 
1422     return Status;
1423 
1424 cleanup:
1425 
1426     if (Header && Header->ObjectHeader)
1427         KsFreeObjectHeader(Header->ObjectHeader);
1428 
1429     if (Header)
1430         FreeItem(Header);
1431 
1432     Irp->IoStatus.Status = Status;
1433     CompleteRequest(Irp, IO_NO_INCREMENT);
1434     return Status;
1435 }
1436 
1437 
1438 
1439 NTSTATUS
1440 NTAPI
KopAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)1441 KopAddDevice(
1442     IN PDRIVER_OBJECT DriverObject,
1443     IN PDEVICE_OBJECT PhysicalDeviceObject)
1444 {
1445     NTSTATUS Status = STATUS_DEVICE_REMOVED;
1446     PDEVICE_OBJECT FunctionalDeviceObject= NULL;
1447     PDEVICE_OBJECT NextDeviceObject;
1448     PDEVICE_EXTENSION DeviceExtension;
1449     PKSOBJECT_CREATE_ITEM CreateItem;
1450 
1451     /* create the device object */
1452     Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KS, FILE_DEVICE_SECURE_OPEN, FALSE, &FunctionalDeviceObject);
1453     if (!NT_SUCCESS(Status))
1454         return Status;
1455 
1456     /* allocate the create item */
1457     CreateItem = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
1458 
1459     if (!CreateItem)
1460     {
1461         /* not enough memory */
1462         IoDeleteDevice(FunctionalDeviceObject);
1463         return STATUS_INSUFFICIENT_RESOURCES;
1464     }
1465 
1466     /* initialize create item */
1467     CreateItem->Create = KopDispatchCreate;
1468     RtlInitUnicodeString(&CreateItem->ObjectClass, KOSTRING_CreateObject);
1469 
1470     /* get device extension */
1471     DeviceExtension = (PDEVICE_EXTENSION)FunctionalDeviceObject->DeviceExtension;
1472 
1473     /* now allocate the device header */
1474     Status = KsAllocateDeviceHeader((KSDEVICE_HEADER*)&DeviceExtension->DeviceHeader, 1, CreateItem);
1475     if (!NT_SUCCESS(Status))
1476     {
1477         /* failed */
1478         IoDeleteDevice(FunctionalDeviceObject);
1479         FreeItem(CreateItem);
1480         return Status;
1481     }
1482 
1483     /* now attach to device stack */
1484     NextDeviceObject = IoAttachDeviceToDeviceStack(FunctionalDeviceObject, PhysicalDeviceObject);
1485     if (NextDeviceObject)
1486     {
1487         /* store pnp base object */
1488          KsSetDevicePnpAndBaseObject((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, NextDeviceObject, FunctionalDeviceObject);
1489         /* set device flags */
1490         FunctionalDeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
1491         FunctionalDeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
1492     }
1493     else
1494     {
1495         /* failed */
1496         KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceExtension->DeviceHeader);
1497         FreeItem(CreateItem);
1498         IoDeleteDevice(FunctionalDeviceObject);
1499         Status =  STATUS_DEVICE_REMOVED;
1500     }
1501 
1502     /* return result */
1503     return Status;
1504 }
1505 
1506 
1507 /*
1508     @implemented
1509 */
1510 COMDDKAPI
1511 NTSTATUS
1512 NTAPI
KoDeviceInitialize(IN PDEVICE_OBJECT DeviceObject)1513 KoDeviceInitialize(
1514     IN PDEVICE_OBJECT DeviceObject)
1515 {
1516     PDEVICE_EXTENSION DeviceExtension;
1517 
1518     /* get device extension */
1519     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1520 
1521     return KsAddObjectCreateItemToDeviceHeader((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, KopDispatchCreate, NULL, KOSTRING_CreateObject, NULL);
1522 }
1523 
1524 /*
1525     @implemented
1526 */
1527 COMDDKAPI
1528 NTSTATUS
1529 NTAPI
KoDriverInitialize(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPathName,IN KoCreateObjectHandler CreateObjectHandler)1530 KoDriverInitialize(
1531     IN PDRIVER_OBJECT DriverObject,
1532     IN PUNICODE_STRING RegistryPathName,
1533     IN KoCreateObjectHandler CreateObjectHandler)
1534 {
1535     PKO_DRIVER_EXTENSION DriverObjectExtension;
1536     NTSTATUS Status;
1537 
1538     /* allocate driver object extension */
1539     Status = IoAllocateDriverObjectExtension(DriverObject, (PVOID)KoDriverInitialize, sizeof(KO_DRIVER_EXTENSION), (PVOID*)&DriverObjectExtension);
1540 
1541     /* did it work */
1542     if (NT_SUCCESS(Status))
1543     {
1544         /* store create handler */
1545         DriverObjectExtension->CreateObjectHandler = CreateObjectHandler;
1546 
1547          /* Setting our IRP handlers */
1548         DriverObject->MajorFunction[IRP_MJ_PNP] = KsDefaultDispatchPnp;
1549         DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
1550         DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
1551 
1552         /* The driver unload routine */
1553         DriverObject->DriverUnload = KsNullDriverUnload;
1554 
1555         /* The driver-supplied AddDevice */
1556         DriverObject->DriverExtension->AddDevice = KopAddDevice;
1557 
1558         /* KS handles these */
1559         DPRINT1("Setting KS function handlers\n");
1560         KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
1561         KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
1562         KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
1563 
1564     }
1565 
1566     return Status;
1567 }
1568 
1569 /*
1570     @unimplemented
1571 */
1572 COMDDKAPI
1573 VOID
1574 NTAPI
KoRelease(IN REFCLSID ClassId)1575 KoRelease(
1576     IN REFCLSID ClassId)
1577 {
1578 
1579 }
1580 
1581 /*
1582     @implemented
1583 */
1584 KSDDKAPI
1585 VOID
1586 NTAPI
KsAcquireControl(IN PVOID Object)1587 KsAcquireControl(
1588     IN PVOID Object)
1589 {
1590     PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1591 
1592     /* sanity check */
1593     ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
1594 
1595     KeWaitForSingleObject(BasicHeader->ControlMutex, Executive, KernelMode, FALSE, NULL);
1596 
1597 }
1598 
1599 /*
1600     @implemented
1601 */
1602 VOID
1603 NTAPI
KsReleaseControl(IN PVOID Object)1604 KsReleaseControl(
1605     IN PVOID  Object)
1606 {
1607     PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1608 
1609     /* sanity check */
1610     ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
1611 
1612     KeReleaseMutex(BasicHeader->ControlMutex, FALSE);
1613 }
1614 
1615 
1616 
1617 /*
1618     @implemented
1619 */
1620 KSDDKAPI
1621 VOID
1622 NTAPI
KsAcquireDevice(IN PKSDEVICE Device)1623 KsAcquireDevice(
1624     IN PKSDEVICE Device)
1625 {
1626     IKsDevice *KsDevice;
1627     PKSIDEVICE_HEADER DeviceHeader;
1628 
1629     DPRINT("KsAcquireDevice\n");
1630     DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
1631 
1632     /* get device interface*/
1633     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
1634 
1635     /* acquire device mutex */
1636     KsDevice->lpVtbl->AcquireDevice(KsDevice);
1637 }
1638 
1639 /*
1640     @implemented
1641 */
1642 VOID
1643 NTAPI
KsReleaseDevice(IN PKSDEVICE Device)1644 KsReleaseDevice(
1645     IN PKSDEVICE  Device)
1646 {
1647     IKsDevice *KsDevice;
1648     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
1649 
1650     /* get device interface*/
1651     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
1652 
1653     /* release device mutex */
1654     KsDevice->lpVtbl->ReleaseDevice(KsDevice);
1655 }
1656 
1657 /*
1658     @implemented
1659 */
1660 KSDDKAPI
1661 VOID
1662 NTAPI
KsTerminateDevice(IN PDEVICE_OBJECT DeviceObject)1663 KsTerminateDevice(
1664     IN PDEVICE_OBJECT DeviceObject)
1665 {
1666     IKsDevice *KsDevice;
1667     PKSIDEVICE_HEADER DeviceHeader;
1668     PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1669 
1670     /* get device header */
1671     DeviceHeader = DeviceExtension->DeviceHeader;
1672 
1673     /* get device interface*/
1674     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
1675 
1676     /* now free device header */
1677     KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
1678 
1679     /* release interface when available */
1680     if (KsDevice)
1681     {
1682         /* delete IKsDevice interface */
1683         KsDevice->lpVtbl->Release(KsDevice);
1684     }
1685 }
1686 
1687 /*
1688     @implemented
1689 */
1690 KSDDKAPI
1691 VOID
1692 NTAPI
KsCompletePendingRequest(IN PIRP Irp)1693 KsCompletePendingRequest(
1694     IN PIRP Irp)
1695 {
1696     PIO_STACK_LOCATION IoStack;
1697 
1698     /* get current irp stack location */
1699     IoStack = IoGetCurrentIrpStackLocation(Irp);
1700 
1701     /* sanity check */
1702     ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1703 
1704     if (IoStack->MajorFunction != IRP_MJ_CLOSE)
1705     {
1706         /* can be completed immediately */
1707         CompleteRequest(Irp, IO_NO_INCREMENT);
1708         return;
1709     }
1710 
1711     /* did close operation fail */
1712     if (!NT_SUCCESS(Irp->IoStatus.Status))
1713     {
1714         /* closing failed, complete irp */
1715         CompleteRequest(Irp, IO_NO_INCREMENT);
1716         return;
1717     }
1718 
1719     /* FIXME
1720      * delete object / device header
1721      * remove dead pin / filter instance
1722      */
1723     UNIMPLEMENTED;
1724 
1725 }
1726 
1727 NTSTATUS
1728 NTAPI
KspSetGetBusDataCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)1729 KspSetGetBusDataCompletion(
1730     IN PDEVICE_OBJECT  DeviceObject,
1731     IN PIRP  Irp,
1732     IN PVOID  Context)
1733 {
1734     /* signal completion */
1735     KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
1736 
1737     /* more work needs be done, so dont free the irp */
1738     return STATUS_MORE_PROCESSING_REQUIRED;
1739 
1740 }
1741 
1742 NTSTATUS
KspDeviceSetGetBusData(IN PDEVICE_OBJECT DeviceObject,IN ULONG DataType,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length,IN BOOL bGet)1743 KspDeviceSetGetBusData(
1744     IN PDEVICE_OBJECT DeviceObject,
1745     IN ULONG DataType,
1746     IN PVOID Buffer,
1747     IN ULONG Offset,
1748     IN ULONG Length,
1749     IN BOOL bGet)
1750 {
1751     PIO_STACK_LOCATION IoStack;
1752     PIRP Irp;
1753     NTSTATUS Status;
1754     KEVENT Event;
1755 
1756     /* allocate the irp */
1757     Irp = IoAllocateIrp(1, /*FIXME */
1758                         FALSE);
1759 
1760     if (!Irp)
1761         return STATUS_INSUFFICIENT_RESOURCES;
1762 
1763     /* initialize the event */
1764     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1765 
1766     /* get next stack location */
1767     IoStack = IoGetNextIrpStackLocation(Irp);
1768 
1769     /* setup a completion routine */
1770     IoSetCompletionRoutine(Irp, KspSetGetBusDataCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
1771 
1772     /* setup parameters */
1773     IoStack->Parameters.ReadWriteConfig.Buffer = Buffer;
1774     IoStack->Parameters.ReadWriteConfig.Length = Length;
1775     IoStack->Parameters.ReadWriteConfig.Offset = Offset;
1776     IoStack->Parameters.ReadWriteConfig.WhichSpace = DataType;
1777     /* setup function code */
1778     IoStack->MajorFunction = IRP_MJ_PNP;
1779     IoStack->MinorFunction = (bGet ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG);
1780 
1781     /* lets call the driver */
1782     Status = IoCallDriver(DeviceObject, Irp);
1783 
1784     /* is the request still pending */
1785     if (Status == STATUS_PENDING)
1786     {
1787         /* have a nap */
1788         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1789         /* update status */
1790         Status = Irp->IoStatus.Status;
1791     }
1792 
1793     /* free the irp */
1794     IoFreeIrp(Irp);
1795     /* done */
1796     return Status;
1797 }
1798 
1799 /*
1800     @implemented
1801 */
1802 KSDDKAPI
1803 ULONG
1804 NTAPI
KsDeviceSetBusData(IN PKSDEVICE Device,IN ULONG DataType,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)1805 KsDeviceSetBusData(
1806     IN PKSDEVICE Device,
1807     IN ULONG DataType,
1808     IN PVOID Buffer,
1809     IN ULONG Offset,
1810     IN ULONG Length)
1811 {
1812     return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
1813                                   DataType, Buffer, Offset, Length, FALSE);
1814 }
1815 
1816 
1817 /*
1818     @implemented
1819 */
1820 KSDDKAPI
1821 ULONG
1822 NTAPI
KsDeviceGetBusData(IN PKSDEVICE Device,IN ULONG DataType,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)1823 KsDeviceGetBusData(
1824     IN PKSDEVICE Device,
1825     IN ULONG DataType,
1826     IN PVOID Buffer,
1827     IN ULONG Offset,
1828     IN ULONG Length)
1829 {
1830     return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
1831                                   DataType, Buffer, Offset, Length, TRUE);
1832 
1833 }
1834 
1835 /*
1836     @implemented
1837 */
1838 KSDDKAPI
1839 void
1840 NTAPI
KsDeviceRegisterAdapterObject(IN PKSDEVICE Device,IN PADAPTER_OBJECT AdapterObject,IN ULONG MaxMappingsByteCount,IN ULONG MappingTableStride)1841 KsDeviceRegisterAdapterObject(
1842     IN PKSDEVICE Device,
1843     IN PADAPTER_OBJECT AdapterObject,
1844     IN ULONG MaxMappingsByteCount,
1845     IN ULONG MappingTableStride)
1846 {
1847     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
1848 
1849     DeviceHeader->AdapterObject = AdapterObject;
1850     DeviceHeader->MaxMappingsByteCount = MaxMappingsByteCount;
1851     DeviceHeader->MappingTableStride = MappingTableStride;
1852 
1853 }
1854 
1855 
1856 /*
1857     @implemented
1858 */
1859 KSDDKAPI
1860 PVOID
1861 NTAPI
KsGetFirstChild(IN PVOID Object)1862 KsGetFirstChild(
1863     IN PVOID Object)
1864 {
1865     PKSBASIC_HEADER BasicHeader;
1866 
1867     /* get the basic header */
1868     BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1869 
1870     /* type has to be either a device or a filter factory */
1871     ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory);
1872 
1873     return (PVOID)BasicHeader->FirstChild.Filter;
1874 }
1875 
1876 /*
1877     @implemented
1878 */
1879 KSDDKAPI
1880 PVOID
1881 NTAPI
KsGetNextSibling(IN PVOID Object)1882 KsGetNextSibling(
1883     IN PVOID Object)
1884 {
1885     PKSBASIC_HEADER BasicHeader;
1886 
1887     /* get the basic header */
1888     BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1889 
1890     ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
1891            BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
1892 
1893     return (PVOID)BasicHeader->Next.Pin;
1894 }
1895 
1896 ULONG
KspCountMethodSets(IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)1897 KspCountMethodSets(
1898     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
1899     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
1900 {
1901     ULONG Index, SubIndex, Count;
1902     BOOL bFound;
1903 
1904     if (!AutomationTableA)
1905         return AutomationTableB->MethodSetsCount;
1906 
1907     if (!AutomationTableB)
1908         return AutomationTableA->MethodSetsCount;
1909 
1910 
1911     DPRINT("AutomationTableA MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableA->MethodItemSize, AutomationTableA->MethodSetsCount);
1912     DPRINT("AutomationTableB MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableB->MethodItemSize, AutomationTableB->MethodSetsCount);
1913 
1914     if (AutomationTableA->MethodItemSize && AutomationTableB->MethodItemSize)
1915     {
1916         /* sanity check */
1917         ASSERT(AutomationTableA->MethodItemSize  == AutomationTableB->MethodItemSize);
1918     }
1919 
1920     /* now iterate all property sets and compare their guids */
1921     Count = AutomationTableA->MethodSetsCount;
1922 
1923     for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
1924     {
1925         /* set found to false */
1926         bFound = FALSE;
1927 
1928         for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
1929         {
1930             if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
1931             {
1932                 /* same property set found */
1933                 bFound = TRUE;
1934                 break;
1935             }
1936         }
1937 
1938         if (!bFound)
1939             Count++;
1940     }
1941 
1942     return Count;
1943 }
1944 
1945 ULONG
KspCountEventSets(IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)1946 KspCountEventSets(
1947     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
1948     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
1949 {
1950     ULONG Index, SubIndex, Count;
1951     BOOL bFound;
1952 
1953     if (!AutomationTableA)
1954         return AutomationTableB->EventSetsCount;
1955 
1956     if (!AutomationTableB)
1957         return AutomationTableA->EventSetsCount;
1958 
1959     DPRINT("AutomationTableA EventItemSize %lu EventSetsCount %lu\n", AutomationTableA->EventItemSize, AutomationTableA->EventSetsCount);
1960     DPRINT("AutomationTableB EventItemSize %lu EventSetsCount %lu\n", AutomationTableB->EventItemSize, AutomationTableB->EventSetsCount);
1961 
1962     if (AutomationTableA->EventItemSize && AutomationTableB->EventItemSize)
1963     {
1964         /* sanity check */
1965         ASSERT(AutomationTableA->EventItemSize == AutomationTableB->EventItemSize);
1966     }
1967 
1968     /* now iterate all Event sets and compare their guids */
1969     Count = AutomationTableA->EventSetsCount;
1970 
1971     for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
1972     {
1973         /* set found to false */
1974         bFound = FALSE;
1975 
1976         for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
1977         {
1978             if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
1979             {
1980                 /* same Event set found */
1981                 bFound = TRUE;
1982                 break;
1983             }
1984         }
1985 
1986         if (!bFound)
1987             Count++;
1988     }
1989 
1990     return Count;
1991 }
1992 
1993 
1994 ULONG
KspCountPropertySets(IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)1995 KspCountPropertySets(
1996     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
1997     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
1998 {
1999     ULONG Index, SubIndex, Count;
2000     BOOL bFound;
2001 
2002     if (!AutomationTableA)
2003         return AutomationTableB->PropertySetsCount;
2004 
2005     if (!AutomationTableB)
2006         return AutomationTableA->PropertySetsCount;
2007 
2008     /* sanity check */
2009     DPRINT("AutomationTableA PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableA->PropertyItemSize, AutomationTableA->PropertySetsCount);
2010     DPRINT("AutomationTableB PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableB->PropertyItemSize, AutomationTableB->PropertySetsCount);
2011     ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
2012 
2013     /* now iterate all property sets and compare their guids */
2014     Count = AutomationTableA->PropertySetsCount;
2015 
2016     for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
2017     {
2018         /* set found to false */
2019         bFound = FALSE;
2020 
2021         for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
2022         {
2023             if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
2024             {
2025                 /* same property set found */
2026                 bFound = TRUE;
2027                 break;
2028             }
2029         }
2030 
2031         if (!bFound)
2032             Count++;
2033     }
2034 
2035     return Count;
2036 }
2037 
2038 NTSTATUS
KspCopyMethodSets(OUT PKSAUTOMATION_TABLE Table,IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)2039 KspCopyMethodSets(
2040     OUT PKSAUTOMATION_TABLE  Table,
2041     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2042     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
2043 {
2044     ULONG Index, SubIndex, Count;
2045     BOOL bFound;
2046 
2047     if (!AutomationTableA)
2048     {
2049         /* copy of property set */
2050         RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableB->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableB->MethodSetsCount);
2051         return STATUS_SUCCESS;
2052     }
2053     else if (!AutomationTableB)
2054     {
2055         /* copy of property set */
2056         RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
2057         return STATUS_SUCCESS;
2058     }
2059 
2060     /* first copy all property items from dominant table */
2061     RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
2062     /* set counter */
2063     Count = AutomationTableA->MethodSetsCount;
2064 
2065     /* now copy entries which aren't available in the dominant table */
2066     for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
2067     {
2068         /* set found to false */
2069         bFound = FALSE;
2070 
2071         for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
2072         {
2073             if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
2074             {
2075                 /* same property set found */
2076                 bFound = TRUE;
2077                 break;
2078             }
2079         }
2080 
2081         if (!bFound)
2082         {
2083             /* copy new property item set */
2084             RtlMoveMemory((PVOID)&Table->MethodSets[Count], &AutomationTableB->MethodSets[Index], sizeof(KSMETHOD_SET));
2085             Count++;
2086         }
2087     }
2088 
2089     return STATUS_SUCCESS;
2090 }
2091 
2092 VOID
KspAddPropertyItem(OUT PKSPROPERTY_SET OutPropertySet,IN PKSPROPERTY_ITEM PropertyItem,IN ULONG PropertyItemSize)2093 KspAddPropertyItem(
2094     OUT PKSPROPERTY_SET OutPropertySet,
2095     IN PKSPROPERTY_ITEM PropertyItem,
2096     IN ULONG PropertyItemSize)
2097 {
2098     PKSPROPERTY_ITEM CurrentPropertyItem;
2099     ULONG Index;
2100 
2101     // check if the property item is already present
2102     CurrentPropertyItem = (PKSPROPERTY_ITEM)OutPropertySet->PropertyItem;
2103     for(Index = 0; Index < OutPropertySet->PropertiesCount; Index++)
2104     {
2105         if (CurrentPropertyItem->PropertyId == PropertyItem->PropertyId)
2106         {
2107             // item already present
2108             return;
2109         }
2110 
2111         // next item
2112         CurrentPropertyItem = (PKSPROPERTY_ITEM)((ULONG_PTR)CurrentPropertyItem + PropertyItemSize);
2113     }
2114     // add item
2115     RtlCopyMemory(CurrentPropertyItem, PropertyItem, PropertyItemSize);
2116     OutPropertySet->PropertiesCount++;
2117 }
2118 
2119 NTSTATUS
KspMergePropertySet(OUT PKSAUTOMATION_TABLE Table,OUT PKSPROPERTY_SET OutPropertySet,IN PKSPROPERTY_SET PropertySetA,IN PKSPROPERTY_SET PropertySetB,IN KSOBJECT_BAG Bag OPTIONAL)2120 KspMergePropertySet(
2121     OUT PKSAUTOMATION_TABLE  Table,
2122     OUT PKSPROPERTY_SET OutPropertySet,
2123     IN PKSPROPERTY_SET PropertySetA,
2124     IN PKSPROPERTY_SET PropertySetB,
2125     IN KSOBJECT_BAG  Bag OPTIONAL)
2126 {
2127     ULONG PropertyCount, Index;
2128     PKSPROPERTY_ITEM PropertyItem, CurrentPropertyItem;
2129     NTSTATUS Status;
2130 
2131     // max properties
2132     PropertyCount = PropertySetA->PropertiesCount + PropertySetB->PropertiesCount;
2133 
2134     // allocate items
2135     PropertyItem = AllocateItem(NonPagedPool, Table->PropertyItemSize * PropertyCount);
2136     if (!PropertyItem)
2137         return STATUS_INSUFFICIENT_RESOURCES;
2138 
2139     if (Bag)
2140     {
2141         /* add table to object bag */
2142         Status = KsAddItemToObjectBag(Bag, PropertyItem, NULL);
2143         /* check for success */
2144         if (!NT_SUCCESS(Status))
2145         {
2146             /* free table */
2147             FreeItem(Table);
2148             return Status;
2149         }
2150     }
2151 
2152     // copy entries from dominant table
2153     RtlCopyMemory(PropertyItem, PropertySetA->PropertyItem, Table->PropertyItemSize * PropertySetA->PropertiesCount);
2154 
2155     // init property set
2156     OutPropertySet->PropertiesCount = PropertySetA->PropertiesCount;
2157     OutPropertySet->PropertyItem = PropertyItem;
2158 
2159     // copy other entries
2160     CurrentPropertyItem = (PKSPROPERTY_ITEM)PropertySetB->PropertyItem;
2161     for(Index = 0; Index < PropertySetB->PropertiesCount; Index++)
2162     {
2163 
2164         // add entries
2165         KspAddPropertyItem(OutPropertySet, CurrentPropertyItem, Table->PropertyItemSize);
2166 
2167         // next entry
2168         CurrentPropertyItem = (PKSPROPERTY_ITEM)((ULONG_PTR)CurrentPropertyItem + Table->PropertyItemSize);
2169     }
2170 
2171     // done
2172     return STATUS_SUCCESS;
2173 }
2174 
2175 
2176 NTSTATUS
KspCopyPropertySets(OUT PKSAUTOMATION_TABLE Table,IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL,IN KSOBJECT_BAG Bag OPTIONAL)2177 KspCopyPropertySets(
2178     OUT PKSAUTOMATION_TABLE  Table,
2179     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2180     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL,
2181     IN KSOBJECT_BAG  Bag OPTIONAL)
2182 {
2183     ULONG Index, SubIndex, Count;
2184     BOOL bFound;
2185     NTSTATUS Status;
2186 
2187     if (!AutomationTableA)
2188     {
2189         /* copy of property set */
2190         RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableB->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableB->PropertySetsCount);
2191         return STATUS_SUCCESS;
2192     }
2193     else if (!AutomationTableB)
2194     {
2195         /* copy of property set */
2196         RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
2197         return STATUS_SUCCESS;
2198     }
2199 
2200     /* first copy all property items from dominant table */
2201     RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
2202     /* set counter */
2203     Count = AutomationTableA->PropertySetsCount;
2204 
2205     /* now copy entries which aren't available in the dominant table */
2206     for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
2207     {
2208         /* set found to false */
2209         bFound = FALSE;
2210 
2211         for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
2212         {
2213             if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
2214             {
2215                 /* same property set found */
2216                 bFound = TRUE;
2217                 break;
2218             }
2219         }
2220 
2221         if (!bFound)
2222         {
2223             /* copy new property item set */
2224             RtlMoveMemory((PVOID)&Table->PropertySets[Count], &AutomationTableB->PropertySets[Index], sizeof(KSPROPERTY_SET));
2225             Count++;
2226         }
2227         else
2228         {
2229             // merge property sets
2230             Status = KspMergePropertySet(Table, (PKSPROPERTY_SET)&Table->PropertySets[SubIndex], (PKSPROPERTY_SET)&AutomationTableA->PropertySets[SubIndex], (PKSPROPERTY_SET)&AutomationTableB->PropertySets[Index], Bag);
2231             if (!NT_SUCCESS(Status))
2232             {
2233                 // failed to merge
2234                 DPRINT1("[KS] Failed to merge %x\n", Status);
2235                 return Status;
2236             }
2237         }
2238     }
2239 
2240     return STATUS_SUCCESS;
2241 }
2242 
2243 NTSTATUS
KspCopyEventSets(OUT PKSAUTOMATION_TABLE Table,IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL)2244 KspCopyEventSets(
2245     OUT PKSAUTOMATION_TABLE  Table,
2246     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2247     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
2248 {
2249     ULONG Index, SubIndex, Count;
2250     BOOL bFound;
2251 
2252     if (!AutomationTableA)
2253     {
2254         /* copy of Event set */
2255         RtlMoveMemory((PVOID)Table->EventSets, AutomationTableB->EventSets, sizeof(KSEVENT_SET) * AutomationTableB->EventSetsCount);
2256         return STATUS_SUCCESS;
2257     }
2258     else if (!AutomationTableB)
2259     {
2260         /* copy of Event set */
2261         RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
2262         return STATUS_SUCCESS;
2263     }
2264 
2265     /* first copy all Event items from dominant table */
2266     RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
2267     /* set counter */
2268     Count = AutomationTableA->EventSetsCount;
2269 
2270     /* now copy entries which aren't available in the dominant table */
2271     for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
2272     {
2273         /* set found to false */
2274         bFound = FALSE;
2275 
2276         for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
2277         {
2278             if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
2279             {
2280                 /* same Event set found */
2281                 bFound = TRUE;
2282                 break;
2283             }
2284         }
2285 
2286         if (!bFound)
2287         {
2288             /* copy new Event item set */
2289             RtlMoveMemory((PVOID)&Table->EventSets[Count], &AutomationTableB->EventSets[Index], sizeof(KSEVENT_SET));
2290             Count++;
2291         }
2292     }
2293 
2294     return STATUS_SUCCESS;
2295 }
2296 
2297 
2298 /*
2299     @implemented
2300 */
2301 NTSTATUS
2302 NTAPI
KsMergeAutomationTables(OUT PKSAUTOMATION_TABLE * AutomationTableAB,IN PKSAUTOMATION_TABLE AutomationTableA OPTIONAL,IN PKSAUTOMATION_TABLE AutomationTableB OPTIONAL,IN KSOBJECT_BAG Bag OPTIONAL)2303 KsMergeAutomationTables(
2304     OUT PKSAUTOMATION_TABLE  *AutomationTableAB,
2305     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2306     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL,
2307     IN KSOBJECT_BAG  Bag OPTIONAL)
2308 {
2309     PKSAUTOMATION_TABLE Table;
2310     NTSTATUS Status = STATUS_SUCCESS;
2311 
2312     if (!AutomationTableA && !AutomationTableB)
2313     {
2314         /* nothing to merge */
2315         return STATUS_SUCCESS;
2316     }
2317 
2318     /* allocate an automation table */
2319     Table = AllocateItem(NonPagedPool, sizeof(KSAUTOMATION_TABLE));
2320     if (!Table)
2321         return STATUS_INSUFFICIENT_RESOURCES;
2322 
2323     if (Bag)
2324     {
2325         /* add table to object bag */
2326         Status = KsAddItemToObjectBag(Bag, Table, NULL);
2327         /* check for success */
2328         if (!NT_SUCCESS(Status))
2329         {
2330             /* free table */
2331             FreeItem(Table);
2332             return Status;
2333         }
2334     }
2335 
2336     /* count property sets */
2337     Table->PropertySetsCount = KspCountPropertySets(AutomationTableA, AutomationTableB);
2338 
2339     if (Table->PropertySetsCount)
2340     {
2341         if (AutomationTableA)
2342         {
2343             /* use item size from dominant automation table */
2344             Table->PropertyItemSize = AutomationTableA->PropertyItemSize;
2345         }
2346         else
2347         {
2348             /* use item size from 2nd automation table */
2349             Table->PropertyItemSize = AutomationTableB->PropertyItemSize;
2350         }
2351 
2352         if (AutomationTableA && AutomationTableB)
2353         {
2354             // FIXME handle different property item sizes
2355             ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
2356         }
2357 
2358         /* now allocate the property sets */
2359         Table->PropertySets = AllocateItem(NonPagedPool, sizeof(KSPROPERTY_SET) * Table->PropertySetsCount);
2360 
2361         if (!Table->PropertySets)
2362         {
2363             /* not enough memory */
2364             goto cleanup;
2365         }
2366 
2367         if (Bag)
2368         {
2369             /* add set to property bag */
2370             Status = KsAddItemToObjectBag(Bag, (PVOID)Table->PropertySets, NULL);
2371             /* check for success */
2372             if (!NT_SUCCESS(Status))
2373             {
2374                 /* cleanup table */
2375                 goto cleanup;
2376             }
2377         }
2378         /* now copy the property sets */
2379         Status = KspCopyPropertySets(Table, AutomationTableA, AutomationTableB, Bag);
2380         if(!NT_SUCCESS(Status))
2381             goto cleanup;
2382 
2383     }
2384 
2385     /* now count the method sets */
2386     Table->MethodSetsCount = KspCountMethodSets(AutomationTableA, AutomationTableB);
2387 
2388     if (Table->MethodSetsCount)
2389     {
2390         if (AutomationTableA)
2391         {
2392             /* use item size from dominant automation table */
2393             Table->MethodItemSize  = AutomationTableA->MethodItemSize;
2394         }
2395         else
2396         {
2397             /* use item size from 2nd automation table */
2398             Table->MethodItemSize = AutomationTableB->MethodItemSize;
2399         }
2400 
2401         /* now allocate the property sets */
2402         Table->MethodSets = AllocateItem(NonPagedPool, sizeof(KSMETHOD_SET) * Table->MethodSetsCount);
2403 
2404         if (!Table->MethodSets)
2405         {
2406             /* not enough memory */
2407             goto cleanup;
2408         }
2409 
2410         if (Bag)
2411         {
2412             /* add set to property bag */
2413             Status = KsAddItemToObjectBag(Bag, (PVOID)Table->MethodSets, NULL);
2414             /* check for success */
2415             if (!NT_SUCCESS(Status))
2416             {
2417                 /* cleanup table */
2418                 goto cleanup;
2419             }
2420         }
2421         /* now copy the property sets */
2422         Status = KspCopyMethodSets(Table, AutomationTableA, AutomationTableB);
2423         if(!NT_SUCCESS(Status))
2424             goto cleanup;
2425     }
2426 
2427 
2428     /* now count the event sets */
2429     Table->EventSetsCount = KspCountEventSets(AutomationTableA, AutomationTableB);
2430 
2431     if (Table->EventSetsCount)
2432     {
2433         if (AutomationTableA)
2434         {
2435             /* use item size from dominant automation table */
2436             Table->EventItemSize  = AutomationTableA->EventItemSize;
2437         }
2438         else
2439         {
2440             /* use item size from 2nd automation table */
2441             Table->EventItemSize = AutomationTableB->EventItemSize;
2442         }
2443 
2444         /* now allocate the property sets */
2445         Table->EventSets = AllocateItem(NonPagedPool, sizeof(KSEVENT_SET) * Table->EventSetsCount);
2446 
2447         if (!Table->EventSets)
2448         {
2449             /* not enough memory */
2450             goto cleanup;
2451         }
2452 
2453         if (Bag)
2454         {
2455             /* add set to property bag */
2456             Status = KsAddItemToObjectBag(Bag, (PVOID)Table->EventSets, NULL);
2457             /* check for success */
2458             if (!NT_SUCCESS(Status))
2459             {
2460                 /* cleanup table */
2461                 goto cleanup;
2462             }
2463         }
2464         /* now copy the property sets */
2465         Status = KspCopyEventSets(Table, AutomationTableA, AutomationTableB);
2466         if(!NT_SUCCESS(Status))
2467             goto cleanup;
2468     }
2469 
2470     /* store result */
2471     *AutomationTableAB = Table;
2472 
2473     return Status;
2474 
2475 
2476 cleanup:
2477 
2478     if (Table)
2479     {
2480         if (Table->PropertySets)
2481         {
2482             /* clean property sets */
2483             if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->PropertySets, TRUE)))
2484                 FreeItem((PVOID)Table->PropertySets);
2485         }
2486 
2487         if (Table->MethodSets)
2488         {
2489             /* clean property sets */
2490             if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->MethodSets, TRUE)))
2491                 FreeItem((PVOID)Table->MethodSets);
2492         }
2493 
2494         if (Table->EventSets)
2495         {
2496             /* clean property sets */
2497             if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->EventSets, TRUE)))
2498                 FreeItem((PVOID)Table->EventSets);
2499         }
2500 
2501         if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, Table, TRUE)))
2502                 FreeItem(Table);
2503     }
2504 
2505     return STATUS_INSUFFICIENT_RESOURCES;
2506 }
2507 
2508 /*
2509     @unimplemented
2510 */
2511 KSDDKAPI
2512 PUNKNOWN
2513 NTAPI
KsRegisterAggregatedClientUnknown(IN PVOID Object,IN PUNKNOWN ClientUnknown)2514 KsRegisterAggregatedClientUnknown(
2515     IN PVOID  Object,
2516     IN PUNKNOWN  ClientUnknown)
2517 {
2518     PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
2519 
2520     /* sanity check */
2521     ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
2522            BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
2523 
2524     if (BasicHeader->ClientAggregate)
2525     {
2526         /* release existing aggregate */
2527         BasicHeader->ClientAggregate->lpVtbl->Release(BasicHeader->ClientAggregate);
2528     }
2529 
2530     /* increment reference count */
2531     ClientUnknown->lpVtbl->AddRef(ClientUnknown);
2532 
2533     /* store client aggregate */
2534     BasicHeader->ClientAggregate = ClientUnknown;
2535 
2536     /* return objects outer unknown */
2537     return BasicHeader->OuterUnknown;
2538 }
2539 
2540 /*
2541     @unimplemented
2542 */
2543 NTSTATUS
2544 NTAPI
KsRegisterFilterWithNoKSPins(IN PDEVICE_OBJECT DeviceObject,IN const GUID * InterfaceClassGUID,IN ULONG PinCount,IN BOOL * PinDirection,IN KSPIN_MEDIUM * MediumList,IN GUID * CategoryList OPTIONAL)2545 KsRegisterFilterWithNoKSPins(
2546     IN PDEVICE_OBJECT  DeviceObject,
2547     IN const GUID*  InterfaceClassGUID,
2548     IN ULONG  PinCount,
2549     IN BOOL*  PinDirection,
2550     IN KSPIN_MEDIUM*  MediumList,
2551     IN GUID*  CategoryList OPTIONAL)
2552 {
2553     ULONG Size, Index;
2554     NTSTATUS Status;
2555     PWSTR SymbolicLinkList;
2556     //PUCHAR Buffer;
2557     HANDLE hKey;
2558     UNICODE_STRING InterfaceString;
2559     //UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
2560 
2561     if (!InterfaceClassGUID || !PinCount || !PinDirection || !MediumList)
2562     {
2563         /* all these parameters are required */
2564         return STATUS_INVALID_PARAMETER;
2565     }
2566 
2567     /* calculate filter data value size */
2568     Size = PinCount * sizeof(KSPIN_MEDIUM);
2569     if (CategoryList)
2570     {
2571         /* add category list */
2572         Size += PinCount * sizeof(GUID);
2573     }
2574 
2575     /* FIXME generate filter data blob */
2576     UNIMPLEMENTED;
2577 
2578     /* get symbolic link list */
2579     Status = IoGetDeviceInterfaces(InterfaceClassGUID, DeviceObject, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &SymbolicLinkList);
2580     if (NT_SUCCESS(Status))
2581     {
2582         /* initialize first symbolic link */
2583         RtlInitUnicodeString(&InterfaceString, SymbolicLinkList);
2584 
2585         /* open first device interface registry key */
2586         Status = IoOpenDeviceInterfaceRegistryKey(&InterfaceString, GENERIC_WRITE, &hKey);
2587 
2588         if (NT_SUCCESS(Status))
2589         {
2590             /* write filter data */
2591             //Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Buffer, Size);
2592 
2593             /* close the key */
2594             ZwClose(hKey);
2595         }
2596 
2597         if (PinCount)
2598         {
2599             /* update medium cache */
2600             for(Index = 0; Index < PinCount; Index++)
2601             {
2602                 KsCacheMedium(&InterfaceString, &MediumList[Index], PinDirection[Index]);
2603             }
2604         }
2605 
2606         /* free the symbolic link list */
2607         FreeItem(SymbolicLinkList);
2608     }
2609 
2610     return Status;
2611 }
2612