xref: /reactos/drivers/ksfilter/ks/bag.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/bag.c
5  * PURPOSE:         KS Object Bag functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 typedef struct
15 {
16     LIST_ENTRY Entry;
17     PVOID Item;
18     PFNKSFREE Free;
19     ULONG References;
20 }KSIOBJECT_BAG_ENTRY, *PKSIOBJECT_BAG_ENTRY;
21 
22 
23 /*
24     @implemented
25 */
26 KSDDKAPI
27 NTSTATUS
28 NTAPI
KsAllocateObjectBag(IN PKSDEVICE Device,OUT KSOBJECT_BAG * ObjectBag)29 KsAllocateObjectBag(
30     IN PKSDEVICE Device,
31     OUT KSOBJECT_BAG* ObjectBag)
32 {
33     PKSIDEVICE_HEADER DeviceHeader;
34     PKSIOBJECT_BAG Bag;
35     IKsDevice *KsDevice;
36 
37     /* get real device header */
38     DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
39 
40     /* allocate a object bag ctx */
41     Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
42     if (!Bag)
43         return STATUS_INSUFFICIENT_RESOURCES;
44 
45     /* get device interface */
46     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
47 
48     /* initialize object bag */
49     return KsDevice->lpVtbl->InitializeObjectBag(KsDevice, Bag, NULL);
50 }
51 
52 PKSIOBJECT_BAG_ENTRY
KspFindObjectBagItem(IN PLIST_ENTRY ObjectList,IN PVOID Item)53 KspFindObjectBagItem(
54     IN PLIST_ENTRY ObjectList,
55     IN PVOID Item)
56 {
57     PLIST_ENTRY Entry;
58     PKSIOBJECT_BAG_ENTRY BagEntry;
59 
60     /* point to first item */
61     Entry = ObjectList->Flink;
62     /* first scan the list if the item is already inserted */
63     while(Entry != ObjectList)
64     {
65         /* get bag entry */
66         BagEntry = (PKSIOBJECT_BAG_ENTRY)CONTAINING_RECORD(Entry, KSIOBJECT_BAG_ENTRY, Entry);
67 
68         if (BagEntry->Item == Item)
69         {
70             /* found entry */
71             return BagEntry;
72         }
73         /* move to next entry */
74         Entry = Entry->Flink;
75     }
76     /* item not in this object bag */
77     return NULL;
78 }
79 
80 
81 /*
82     @implemented
83 */
84 NTSTATUS
85 NTAPI
KsAddItemToObjectBag(IN KSOBJECT_BAG ObjectBag,IN PVOID Item,IN PFNKSFREE Free OPTIONAL)86 KsAddItemToObjectBag(
87     IN KSOBJECT_BAG  ObjectBag,
88     IN PVOID  Item,
89     IN PFNKSFREE  Free  OPTIONAL)
90 {
91     PKSIOBJECT_BAG Bag;
92     PKSIOBJECT_BAG_ENTRY BagEntry;
93 
94     DPRINT("KsAddItemToObjectBag\n");
95 
96     /* get real object bag */
97     Bag = (PKSIOBJECT_BAG)ObjectBag;
98 
99     /* acquire bag mutex */
100     KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
101 
102     /* is the item already present in this object bag */
103     BagEntry = KspFindObjectBagItem(&Bag->ObjectList, Item);
104 
105     if (BagEntry)
106     {
107         /* is is, update reference count */
108         InterlockedIncrement((PLONG)&BagEntry->References);
109         /* release mutex */
110         KeReleaseMutex(Bag->BagMutex, FALSE);
111         /* return result */
112         return STATUS_SUCCESS;
113     }
114 
115     /* item is new, allocate entry */
116     BagEntry = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG_ENTRY));
117     if (!BagEntry)
118     {
119         /* no memory */
120         KeReleaseMutex(Bag->BagMutex, FALSE);
121         /* return result */
122         return STATUS_INSUFFICIENT_RESOURCES;
123     }
124 
125     /* initialize bag entry */
126     BagEntry->References = 1;
127     BagEntry->Item = Item;
128     if (Free)
129         BagEntry->Free = Free;
130     else
131         BagEntry->Free = ExFreePool;
132 
133     /* insert item */
134     InsertTailList(&Bag->ObjectList, &BagEntry->Entry);
135 
136     /* release mutex */
137     KeReleaseMutex(Bag->BagMutex, FALSE);
138 
139     /* done */
140     return STATUS_SUCCESS;
141 }
142 
143 ULONG
KspGetObjectItemReferenceCount(IN PKSIDEVICE_HEADER DeviceHeader,IN PVOID Item)144 KspGetObjectItemReferenceCount(
145     IN PKSIDEVICE_HEADER DeviceHeader,
146     IN PVOID Item)
147 {
148     PLIST_ENTRY Entry;
149     PKSIOBJECT_BAG OtherBag;
150     PKSIOBJECT_BAG_ENTRY OtherBagEntry;
151     ULONG TotalRefs = 0;
152 
153     /* scan all object bags and see if item is present there */
154     Entry = DeviceHeader->ObjectBags.Flink;
155     while(Entry != &DeviceHeader->ObjectBags)
156     {
157         /* get other bag */
158         OtherBag = (PKSIOBJECT_BAG)CONTAINING_RECORD(Entry, KSIOBJECT_BAG, Entry);
159 
160         /* is the item present there */
161         OtherBagEntry = KspFindObjectBagItem(&OtherBag->ObjectList, Item);
162 
163         if (OtherBagEntry)
164             TotalRefs++;
165 
166         /* move to next item */
167         Entry = Entry->Flink;
168     }
169 
170     return TotalRefs;
171 }
172 
173 /*
174     @implemented
175 */
176 KSDDKAPI
177 ULONG
178 NTAPI
KsRemoveItemFromObjectBag(IN KSOBJECT_BAG ObjectBag,IN PVOID Item,IN BOOLEAN Free)179 KsRemoveItemFromObjectBag(
180     IN KSOBJECT_BAG ObjectBag,
181     IN PVOID Item,
182     IN BOOLEAN Free)
183 {
184     PKSIOBJECT_BAG Bag;
185     PKSIOBJECT_BAG_ENTRY BagEntry;
186     ULONG TotalRefs;
187 
188     /* get real object bag */
189     Bag = (PKSIOBJECT_BAG)ObjectBag;
190 
191     /* acquire bag mutex */
192     KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
193 
194     /* is the item already present in this object bag */
195     BagEntry = KspFindObjectBagItem(&Bag->ObjectList, Item);
196 
197     if (!BagEntry)
198     {
199         /* item was not in this object bag */
200         KeReleaseMutex(Bag->BagMutex, FALSE);
201         return 0;
202     }
203 
204     /* set current refs count */
205     TotalRefs = BagEntry->References;
206 
207     /* get total refs count */
208     TotalRefs += KspGetObjectItemReferenceCount((PKSIDEVICE_HEADER)Bag->DeviceHeader, Item);
209 
210     /* decrease reference count */
211     InterlockedDecrement((PLONG)&BagEntry->References);
212 
213     if (BagEntry->References == 0)
214     {
215         /* remove the entry */
216         RemoveEntryList(&BagEntry->Entry);
217     }
218 
219     if (TotalRefs == 1)
220     {
221         /* does the caller want to free the item */
222         if (Free)
223         {
224             /* free the item */
225             BagEntry->Free(BagEntry->Item);
226         }
227     }
228     if (BagEntry->References == 0)
229     {
230         /* free bag item entry */
231         FreeItem(BagEntry);
232     }
233 
234     /* release mutex */
235     KeReleaseMutex(Bag->BagMutex, FALSE);
236 
237 
238     return TotalRefs;
239 }
240 
241 /*
242     @implemented
243 */
244 KSDDKAPI
245 NTSTATUS
246 NTAPI
KsCopyObjectBagItems(IN KSOBJECT_BAG ObjectBagDestination,IN KSOBJECT_BAG ObjectBagSource)247 KsCopyObjectBagItems(
248     IN KSOBJECT_BAG ObjectBagDestination,
249     IN KSOBJECT_BAG ObjectBagSource)
250 {
251     PKSIOBJECT_BAG ObjectBagDest, ObjectBagSrc;
252     PLIST_ENTRY Entry;
253     PKSIOBJECT_BAG_ENTRY BagEntry;
254     NTSTATUS Status = STATUS_SUCCESS;
255 
256     /* get object bag src */
257     ObjectBagSrc = (PKSIOBJECT_BAG)ObjectBagSource;
258 
259     /* get object bag dst */
260     ObjectBagDest = (PKSIOBJECT_BAG)ObjectBagDestination;
261 
262     /* acquire source mutex */
263     KeWaitForSingleObject(ObjectBagSrc->BagMutex, Executive, KernelMode, FALSE, NULL);
264 
265     if (ObjectBagSrc->BagMutex != ObjectBagDest->BagMutex)
266     {
267         /* acquire destination mutex */
268         KeWaitForSingleObject(ObjectBagDest->BagMutex, Executive, KernelMode, FALSE, NULL);
269     }
270 
271     /* point to first item */
272     Entry = ObjectBagSrc->ObjectList.Flink;
273     /* first scan the list if the item is already inserted */
274     while(Entry != &ObjectBagSrc->ObjectList)
275     {
276         /* get bag entry */
277         BagEntry = (PKSIOBJECT_BAG_ENTRY)CONTAINING_RECORD(Entry, KSIOBJECT_BAG_ENTRY, Entry);
278 
279         /* add the item */
280         Status = KsAddItemToObjectBag(ObjectBagDestination, BagEntry->Item, BagEntry->Free);
281 
282         /* check for success */
283         if (!NT_SUCCESS(Status))
284             break;
285 
286         /* move to next entry */
287         Entry = Entry->Flink;
288     }
289 
290     if (ObjectBagSrc->BagMutex != ObjectBagDest->BagMutex)
291     {
292         /* release destination mutex */
293         KeReleaseMutex(ObjectBagDest->BagMutex, FALSE);
294     }
295 
296     /* release source mutex */
297      KeReleaseMutex(ObjectBagSrc->BagMutex, FALSE);
298 
299     return Status;
300 }
301 
302 /*
303     @implemented
304 */
305 KSDDKAPI
306 VOID
307 NTAPI
KsFreeObjectBag(IN KSOBJECT_BAG ObjectBag)308 KsFreeObjectBag(
309     IN KSOBJECT_BAG ObjectBag)
310 {
311     PLIST_ENTRY Entry;
312     PKSIOBJECT_BAG Bag;
313     PKSIOBJECT_BAG_ENTRY BagEntry;
314     ULONG TotalRefs;
315 
316     /* get real object bag */
317     Bag = (PKSIOBJECT_BAG)ObjectBag;
318 
319     /* acquire bag mutex */
320     KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
321 
322     while(!IsListEmpty(&Bag->ObjectList))
323     {
324         /* get an bag entry */
325         Entry = RemoveHeadList(&Bag->ObjectList);
326         /* access bag entry item */
327         BagEntry = (PKSIOBJECT_BAG_ENTRY)CONTAINING_RECORD(Entry, KSIOBJECT_BAG, Entry);
328 
329         /* check if the item is present in some other bag */
330         TotalRefs = KspGetObjectItemReferenceCount((PKSIDEVICE_HEADER)Bag->DeviceHeader, &BagEntry->Item);
331 
332         if (TotalRefs == 0)
333         {
334             /* item is ready to be freed */
335             BagEntry->Free(BagEntry->Item);
336         }
337 
338         /* free bag entry item */
339         FreeItem(BagEntry);
340     }
341 
342     /* remove bag entry from device object list */
343     RemoveEntryList(&Bag->Entry);
344 
345     /* release bag mutex */
346     KeReleaseMutex(Bag->BagMutex, FALSE);
347 
348     /* now free object bag */
349     FreeItem(Bag);
350 }
351 
352 /*
353     @implemented
354 */
355 KSDDKAPI
356 NTSTATUS
357 NTAPI
_KsEdit(IN KSOBJECT_BAG ObjectBag,IN OUT PVOID * PointerToPointerToItem,IN ULONG NewSize,IN ULONG OldSize,IN ULONG Tag)358 _KsEdit(
359     IN KSOBJECT_BAG ObjectBag,
360     IN OUT PVOID* PointerToPointerToItem,
361     IN ULONG NewSize,
362     IN ULONG OldSize,
363     IN ULONG Tag)
364 {
365     PKSIOBJECT_BAG Bag;
366     PKSIOBJECT_BAG_ENTRY BagEntry;
367     PVOID Item;
368     NTSTATUS Status;
369 
370     DPRINT("_KsEdit\n");
371 
372     /* get real object bag */
373     Bag = (PKSIOBJECT_BAG)ObjectBag;
374 
375     /* acquire bag mutex */
376     KeWaitForSingleObject(Bag->BagMutex, Executive, KernelMode, FALSE, NULL);
377 
378 
379     if (*PointerToPointerToItem)
380     {
381         /* search object bag for this entry */
382         BagEntry = KspFindObjectBagItem(&Bag->ObjectList, *PointerToPointerToItem);
383     }
384     else
385     {
386         /* pointer to null, allocate new entry */
387         BagEntry = NULL;
388     }
389 
390     if (!BagEntry || NewSize > OldSize)
391     {
392         /* entry does not exist or new entry must be allocated */
393         Item = AllocateItem(NonPagedPool, NewSize);
394 
395         if (!Item)
396         {
397             /* not enough resources */
398             KeReleaseMutex(Bag->BagMutex, FALSE);
399             return STATUS_INSUFFICIENT_RESOURCES;
400         }
401 
402         /* now add the item to the object bag */
403         Status = KsAddItemToObjectBag((KSOBJECT_BAG)Bag, Item, NULL);
404         /* check for success */
405         if (!NT_SUCCESS(Status))
406         {
407             /* failed to add item */
408             FreeItem(Item);
409             KeReleaseMutex(Bag->BagMutex, FALSE);
410             return Status;
411         }
412 
413         if (*PointerToPointerToItem)
414         {
415             /* object exists */
416             if (OldSize >= NewSize)
417             {
418                 /* copy old contents */
419                 RtlMoveMemory(Item, *PointerToPointerToItem, NewSize);
420             }
421             else
422             {
423                 /* copy new contents */
424                 RtlMoveMemory(Item, *PointerToPointerToItem, OldSize);
425             }
426         }
427 
428         if (BagEntry)
429         {
430             /* remove old entry */
431             KsRemoveItemFromObjectBag(ObjectBag, BagEntry->Item, TRUE);
432         }
433 
434         /* store item */
435        *PointerToPointerToItem = Item;
436     }
437 
438     /* release bag mutex */
439     KeReleaseMutex(Bag->BagMutex, FALSE);
440 
441     return STATUS_SUCCESS;
442 }
443 
444 
445