xref: /reactos/ntoskrnl/ex/handle.c (revision e1f4d286)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ex/handle.c
5  * PURPOSE:         Generic Executive Handle Tables
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  *                  Thomas Weidenmueller <w3seek@reactos.com>
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 LIST_ENTRY HandleTableListHead;
19 EX_PUSH_LOCK HandleTableListLock;
20 #define SizeOfHandle(x) (sizeof(HANDLE) * (x))
21 #define INDEX_TO_HANDLE_VALUE(x) ((x) << HANDLE_TAG_BITS)
22 
23 /* PRIVATE FUNCTIONS *********************************************************/
24 
25 INIT_FUNCTION
26 VOID
27 NTAPI
28 ExpInitializeHandleTables(VOID)
29 {
30     /* Initialize the list of handle tables and the lock */
31     InitializeListHead(&HandleTableListHead);
32     ExInitializePushLock(&HandleTableListLock);
33 }
34 
35 PHANDLE_TABLE_ENTRY
36 NTAPI
37 ExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable,
38                           IN EXHANDLE Handle)
39 {
40     ULONG TableLevel;
41     ULONG_PTR TableBase;
42     PHANDLE_TABLE_ENTRY HandleArray, Entry;
43     PVOID *PointerArray;
44 
45     /* Clear the tag bits */
46     Handle.TagBits = 0;
47 
48     /* Check if the handle is in the allocated range */
49     if (Handle.Value >= HandleTable->NextHandleNeedingPool)
50     {
51         return NULL;
52     }
53 
54     /* Get the table code */
55     TableBase = HandleTable->TableCode;
56 
57     /* Extract the table level and actual table base */
58     TableLevel = (ULONG)(TableBase & 3);
59     TableBase &= ~3;
60 
61     PointerArray = (PVOID*)TableBase;
62     HandleArray = (PHANDLE_TABLE_ENTRY)TableBase;
63 
64     /* Check what level we're running at */
65     switch (TableLevel)
66     {
67         case 2:
68 
69             /* Get the mid level pointer array */
70             PointerArray = PointerArray[Handle.HighIndex];
71             ASSERT(PointerArray != NULL);
72 
73             /* Fall through */
74         case 1:
75 
76             /* Get the handle array */
77             HandleArray = PointerArray[Handle.MidIndex];
78             ASSERT(HandleArray != NULL);
79 
80             /* Fall through */
81         case 0:
82 
83             /* Get the entry using the low index */
84             Entry = &HandleArray[Handle.LowIndex];
85 
86             /* All done */
87             break;
88 
89         default:
90 
91             ASSERT(FALSE);
92             Entry = NULL;
93     }
94 
95     /* Return the handle entry */
96     return Entry;
97 }
98 
99 PVOID
100 NTAPI
101 ExpAllocateTablePagedPool(IN PEPROCESS Process OPTIONAL,
102                           IN SIZE_T Size)
103 {
104     PVOID Buffer;
105 
106     /* Do the allocation */
107     Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE);
108     if (Buffer)
109     {
110         /* Clear the memory */
111         RtlZeroMemory(Buffer, Size);
112 
113         /* Check if we have a process to charge quota */
114         if (Process)
115         {
116             /* FIXME: Charge quota */
117         }
118     }
119 
120     /* Return the allocated memory */
121     return Buffer;
122 }
123 
124 PVOID
125 NTAPI
126 ExpAllocateTablePagedPoolNoZero(IN PEPROCESS Process OPTIONAL,
127                                 IN SIZE_T Size)
128 {
129     PVOID Buffer;
130 
131     /* Do the allocation */
132     Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_OBJECT_TABLE);
133     if (Buffer)
134     {
135         /* Check if we have a process to charge quota */
136         if (Process)
137         {
138             /* FIXME: Charge quota */
139         }
140     }
141 
142     /* Return the allocated memory */
143     return Buffer;
144 }
145 
146 VOID
147 NTAPI
148 ExpFreeTablePagedPool(IN PEPROCESS Process OPTIONAL,
149                       IN PVOID Buffer,
150                       IN SIZE_T Size)
151 {
152     /* Free the buffer */
153     ExFreePoolWithTag(Buffer, TAG_OBJECT_TABLE);
154     if (Process)
155     {
156         /* FIXME: Release quota */
157     }
158 }
159 
160 VOID
161 NTAPI
162 ExpFreeLowLevelTable(IN PEPROCESS Process,
163                      IN PHANDLE_TABLE_ENTRY TableEntry)
164 {
165     /* Check if we have an entry */
166     if (TableEntry[0].Object)
167     {
168         /* Free the entry */
169         ExpFreeTablePagedPool(Process,
170                               TableEntry[0].Object,
171                               LOW_LEVEL_ENTRIES *
172                               sizeof(HANDLE_TABLE_ENTRY_INFO));
173     }
174 
175     /* Free the table */
176     ExpFreeTablePagedPool(Process, TableEntry, PAGE_SIZE);
177 }
178 
179 VOID
180 NTAPI
181 ExpFreeHandleTable(IN PHANDLE_TABLE HandleTable)
182 {
183     PEPROCESS Process = HandleTable->QuotaProcess;
184     ULONG i, j;
185     ULONG_PTR TableCode = HandleTable->TableCode;
186     ULONG_PTR TableBase = TableCode & ~3;
187     ULONG TableLevel = (ULONG)(TableCode & 3);
188     PHANDLE_TABLE_ENTRY Level1, *Level2, **Level3;
189     PAGED_CODE();
190 
191     /* Check which level we're at */
192     if (TableLevel == 0)
193     {
194         /* Select the first level table base and just free it */
195         Level1 = (PVOID)TableBase;
196         ExpFreeLowLevelTable(Process, Level1);
197     }
198     else if (TableLevel == 1)
199     {
200         /* Select the second level table base */
201         Level2 = (PVOID)TableBase;
202 
203         /* Loop each mid level entry */
204         for (i = 0; i < MID_LEVEL_ENTRIES; i++)
205         {
206             /* Leave if we've reached the last entry */
207             if (!Level2[i]) break;
208 
209             /* Free the second level table */
210             ExpFreeLowLevelTable(Process, Level2[i]);
211         }
212 
213         /* Free the second level table */
214         ExpFreeTablePagedPool(Process, Level2, PAGE_SIZE);
215     }
216     else
217     {
218         /* Select the third level table base */
219         Level3 = (PVOID)TableBase;
220 
221         /* Loop each high level entry */
222         for (i = 0; i < HIGH_LEVEL_ENTRIES; i++)
223         {
224             /* Leave if we've reached the last entry */
225             if (!Level3[i]) break;
226 
227             /* Loop each mid level entry */
228             for (j = 0; j < MID_LEVEL_ENTRIES; j++)
229             {
230                 /* Leave if we've reached the last entry */
231                 if (!Level3[i][j]) break;
232 
233                 /* Free the second level table */
234                 ExpFreeLowLevelTable(Process, Level3[i][j]);
235             }
236 
237             /* Free the third level table entry */
238             ExpFreeTablePagedPool(Process, Level3[i], PAGE_SIZE);
239         }
240 
241         /* Free the third level table */
242         ExpFreeTablePagedPool(Process,
243                               Level3,
244                               SizeOfHandle(HIGH_LEVEL_ENTRIES));
245     }
246 
247     /* Free the actual table and check if we need to release quota */
248     ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE);
249     if (Process)
250     {
251         /* FIXME: TODO */
252     }
253 }
254 
255 VOID
256 NTAPI
257 ExpFreeHandleTableEntry(IN PHANDLE_TABLE HandleTable,
258                         IN EXHANDLE Handle,
259                         IN PHANDLE_TABLE_ENTRY HandleTableEntry)
260 {
261     ULONG OldValue, *Free;
262     ULONG LockIndex;
263     PAGED_CODE();
264 
265     /* Sanity checks */
266     ASSERT(HandleTableEntry->Object == NULL);
267     ASSERT(HandleTableEntry == ExpLookupHandleTableEntry(HandleTable, Handle));
268 
269     /* Decrement the handle count */
270     InterlockedDecrement(&HandleTable->HandleCount);
271 
272     /* Mark the handle as free */
273     Handle.TagBits = 0;
274 
275     /* Check if we're FIFO */
276     if (!HandleTable->StrictFIFO)
277     {
278         /* Select a lock index */
279         LockIndex = Handle.Index % 4;
280 
281         /* Select which entry to use */
282         Free = (HandleTable->HandleTableLock[LockIndex].Locked) ?
283                 &HandleTable->FirstFree : &HandleTable->LastFree;
284     }
285     else
286     {
287         /* No need to worry about locking, take the last entry */
288         Free = &HandleTable->LastFree;
289     }
290 
291     /* Start value change loop */
292     for (;;)
293     {
294         /* Get the current value and write */
295         OldValue = *Free;
296         HandleTableEntry->NextFreeTableEntry = OldValue;
297         if (InterlockedCompareExchange((PLONG)Free, Handle.AsULONG, OldValue) == OldValue)
298         {
299             /* Break out, we're done. Make sure the handle value makes sense */
300             ASSERT((OldValue & FREE_HANDLE_MASK) <
301                    HandleTable->NextHandleNeedingPool);
302             break;
303         }
304     }
305 }
306 
307 PHANDLE_TABLE
308 NTAPI
309 ExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL,
310                        IN BOOLEAN NewTable)
311 {
312     PHANDLE_TABLE HandleTable;
313     PHANDLE_TABLE_ENTRY HandleTableTable, HandleEntry;
314     ULONG i;
315     PAGED_CODE();
316 
317     /* Allocate the table */
318     HandleTable = ExAllocatePoolWithTag(PagedPool,
319                                         sizeof(HANDLE_TABLE),
320                                         TAG_OBJECT_TABLE);
321     if (!HandleTable) return NULL;
322 
323     /* Check if we have a process */
324     if (Process)
325     {
326         /* FIXME: Charge quota */
327     }
328 
329     /* Clear the table */
330     RtlZeroMemory(HandleTable, sizeof(HANDLE_TABLE));
331 
332     /* Now allocate the first level structures */
333     HandleTableTable = ExpAllocateTablePagedPoolNoZero(Process, PAGE_SIZE);
334     if (!HandleTableTable)
335     {
336         /* Failed, free the table */
337         ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE);
338         return NULL;
339     }
340 
341     /* Write the pointer to our first level structures */
342     HandleTable->TableCode = (ULONG_PTR)HandleTableTable;
343 
344     /* Initialize the first entry */
345     HandleEntry = &HandleTableTable[0];
346     HandleEntry->NextFreeTableEntry = -2;
347     HandleEntry->Value = 0;
348 
349     /* Check if this is a new table */
350     if (NewTable)
351     {
352         /* Go past the root entry */
353         HandleEntry++;
354 
355         /* Loop every low level entry */
356         for (i = 1; i < (LOW_LEVEL_ENTRIES - 1); i++)
357         {
358             /* Set up the free data */
359             HandleEntry->Value = 0;
360             HandleEntry->NextFreeTableEntry = INDEX_TO_HANDLE_VALUE(i + 1);
361 
362             /* Move to the next entry */
363             HandleEntry++;
364         }
365 
366         /* Terminate the last entry */
367         HandleEntry->Value = 0;
368         HandleEntry->NextFreeTableEntry = 0;
369         HandleTable->FirstFree = INDEX_TO_HANDLE_VALUE(1);
370     }
371 
372     /* Set the next handle needing pool after our allocated page from above */
373     HandleTable->NextHandleNeedingPool = INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES);
374 
375     /* Setup the rest of the handle table data */
376     HandleTable->QuotaProcess = Process;
377     HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId;
378     HandleTable->Flags = 0;
379 
380     /* Loop all the handle table locks */
381     for (i = 0; i < 4; i++)
382     {
383         /* Initialize the handle table lock */
384         ExInitializePushLock(&HandleTable->HandleTableLock[i]);
385     }
386 
387     /* Initialize the contention event lock and return the lock */
388     ExInitializePushLock(&HandleTable->HandleContentionEvent);
389     return HandleTable;
390 }
391 
392 PHANDLE_TABLE_ENTRY
393 NTAPI
394 ExpAllocateLowLevelTable(IN PHANDLE_TABLE HandleTable,
395                          IN BOOLEAN DoInit)
396 {
397     ULONG i, Base;
398     PHANDLE_TABLE_ENTRY Low, HandleEntry;
399 
400     /* Allocate the low level table */
401     Low = ExpAllocateTablePagedPoolNoZero(HandleTable->QuotaProcess,
402                                           PAGE_SIZE);
403     if (!Low) return NULL;
404 
405     /* Setup the initial entry */
406     HandleEntry = &Low[0];
407     HandleEntry->NextFreeTableEntry = -2;
408     HandleEntry->Value = 0;
409 
410     /* Check if we're initializing */
411     if (DoInit)
412     {
413         /* Go to the next entry and the base entry */
414         HandleEntry++;
415         Base = HandleTable->NextHandleNeedingPool + INDEX_TO_HANDLE_VALUE(2);
416 
417         /* Loop each entry */
418         for (i = Base;
419              i < Base + INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES - 2);
420              i += INDEX_TO_HANDLE_VALUE(1))
421         {
422             /* Free this entry and move on to the next one */
423             HandleEntry->NextFreeTableEntry = i;
424             HandleEntry->Value = 0;
425             HandleEntry++;
426         }
427 
428         /* Terminate the last entry */
429         HandleEntry->NextFreeTableEntry = 0;
430         HandleEntry->Value = 0;
431     }
432 
433     /* Return the low level table */
434     return Low;
435 }
436 
437 PHANDLE_TABLE_ENTRY*
438 NTAPI
439 ExpAllocateMidLevelTable(IN PHANDLE_TABLE HandleTable,
440                          IN BOOLEAN DoInit,
441                          OUT PHANDLE_TABLE_ENTRY *LowTableEntry)
442 {
443     PHANDLE_TABLE_ENTRY *Mid, Low;
444 
445     /* Allocate the mid level table */
446     Mid = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, PAGE_SIZE);
447     if (!Mid) return NULL;
448 
449     /* Allocate a new low level for it */
450     Low = ExpAllocateLowLevelTable(HandleTable, DoInit);
451     if (!Low)
452     {
453         /* We failed, free the mid table */
454         ExpFreeTablePagedPool(HandleTable->QuotaProcess, Mid, PAGE_SIZE);
455         return NULL;
456     }
457 
458     /* Link the tables and return the pointer */
459     Mid[0] = Low;
460     *LowTableEntry = Low;
461     return Mid;
462 }
463 
464 BOOLEAN
465 NTAPI
466 ExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable,
467                                 IN BOOLEAN DoInit)
468 {
469     ULONG i, j, Index;
470     PHANDLE_TABLE_ENTRY Low = NULL, *Mid, **High, *SecondLevel, **ThirdLevel;
471     ULONG NewFree, FirstFree;
472     PVOID Value;
473     ULONG_PTR TableCode = HandleTable->TableCode;
474     ULONG_PTR TableBase = TableCode & ~3;
475     ULONG TableLevel = (ULONG)(TableCode & 3);
476     PAGED_CODE();
477 
478     /* Check how many levels we already have */
479     if (TableLevel == 0)
480     {
481         /* Allocate a mid level, since we only have a low level */
482         Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low);
483         if (!Mid) return FALSE;
484 
485         /* Link up the tables */
486         Mid[1] = Mid[0];
487         Mid[0] = (PVOID)TableBase;
488 
489         /* Write the new level and attempt to change the table code */
490         TableBase = ((ULONG_PTR)Mid) | 1;
491         Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, (PVOID)TableBase);
492     }
493     else if (TableLevel == 1)
494     {
495         /* Setup the 2nd level table */
496         SecondLevel = (PVOID)TableBase;
497 
498         /* Get if the next index can fit in the table */
499         i = HandleTable->NextHandleNeedingPool /
500             INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES);
501         if (i < MID_LEVEL_ENTRIES)
502         {
503             /* We need to allocate a new table */
504             Low = ExpAllocateLowLevelTable(HandleTable, DoInit);
505             if (!Low) return FALSE;
506 
507             /* Update the table */
508             Value = InterlockedExchangePointer((PVOID*)&SecondLevel[i], Low);
509             ASSERT(Value == NULL);
510         }
511         else
512         {
513             /* We need a new high level table */
514             High = ExpAllocateTablePagedPool(HandleTable->QuotaProcess,
515                                              SizeOfHandle(HIGH_LEVEL_ENTRIES));
516             if (!High) return FALSE;
517 
518             /* Allocate a new mid level table as well */
519             Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low);
520             if (!Mid)
521             {
522                 /* We failed, free the high level table as well */
523                 ExpFreeTablePagedPool(HandleTable->QuotaProcess,
524                                       High,
525                                       SizeOfHandle(HIGH_LEVEL_ENTRIES));
526                 return FALSE;
527             }
528 
529             /* Link up the tables */
530             High[0] = (PVOID)TableBase;
531             High[1] = Mid;
532 
533             /* Write the new table and change the table code */
534             TableBase = ((ULONG_PTR)High) | 2;
535             Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode,
536                                                (PVOID)TableBase);
537         }
538     }
539     else if (TableLevel == 2)
540     {
541         /* Setup the 3rd level table */
542         ThirdLevel = (PVOID)TableBase;
543 
544         /* Get the index and check if it can fit */
545         i = HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(MAX_MID_INDEX);
546         if (i >= HIGH_LEVEL_ENTRIES) return FALSE;
547 
548         /* Check if there's no mid-level table */
549         if (!ThirdLevel[i])
550         {
551             /* Allocate a new mid level table */
552             Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low);
553             if (!Mid) return FALSE;
554 
555             /* Update the table pointer */
556             Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i], Mid);
557             ASSERT(Value == NULL);
558         }
559         else
560         {
561             /* We have one, check at which index we should insert our entry */
562             Index = (HandleTable->NextHandleNeedingPool / INDEX_TO_HANDLE_VALUE(1)) -
563                      i * MAX_MID_INDEX;
564             j = Index / LOW_LEVEL_ENTRIES;
565 
566             /* Allocate a new low level */
567             Low = ExpAllocateLowLevelTable(HandleTable, DoInit);
568             if (!Low) return FALSE;
569 
570             /* Update the table pointer */
571             Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i][j], Low);
572             ASSERT(Value == NULL);
573         }
574     }
575     else
576     {
577         /* Something is really broken */
578         ASSERT(FALSE);
579     }
580 
581     /* Update the index of the next handle */
582     Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool,
583                                    INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
584 
585     /* Check if need to initialize the table */
586     if (DoInit)
587     {
588         /* Create a new index number */
589         Index += INDEX_TO_HANDLE_VALUE(1);
590 
591         /* Start free index change loop */
592         for (;;)
593         {
594             /* Setup the first free index */
595             FirstFree = HandleTable->FirstFree;
596             Low[LOW_LEVEL_ENTRIES - 1].NextFreeTableEntry = FirstFree;
597 
598             /* Change the index */
599             NewFree = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree,
600                                                  Index,
601                                                  FirstFree);
602             if (NewFree == FirstFree) break;
603         }
604     }
605 
606     /* All done */
607     return TRUE;
608 }
609 
610 ULONG
611 NTAPI
612 ExpMoveFreeHandles(IN PHANDLE_TABLE HandleTable)
613 {
614     ULONG LastFree, i;
615 
616     /* Clear the last free index */
617     LastFree = InterlockedExchange((PLONG) &HandleTable->LastFree, 0);
618 
619     /* Check if we had no index */
620     if (!LastFree) return LastFree;
621 
622     /* Acquire the locks we need */
623     for (i = 1; i < 4; i++)
624     {
625         /* Acquire this lock exclusively */
626         ExWaitOnPushLock(&HandleTable->HandleTableLock[i]);
627     }
628 
629     /* Check if we're not strict FIFO */
630     if (!HandleTable->StrictFIFO)
631     {
632         /* Update the first free index */
633         if (!InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, LastFree, 0))
634         {
635             /* We're done, exit */
636             return LastFree;
637         }
638     }
639 
640     /* We are strict FIFO, we need to reverse the entries */
641     ASSERT(FALSE);
642     return LastFree;
643 }
644 
645 PHANDLE_TABLE_ENTRY
646 NTAPI
647 ExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable,
648                             OUT PEXHANDLE NewHandle)
649 {
650     ULONG OldValue, NewValue, NewValue1;
651     PHANDLE_TABLE_ENTRY Entry;
652     EXHANDLE Handle, OldHandle;
653     BOOLEAN Result;
654     ULONG i;
655 
656     /* Start allocation loop */
657     for (;;)
658     {
659         /* Get the current link */
660         OldValue = HandleTable->FirstFree;
661         while (!OldValue)
662         {
663             /* No free entries remain, lock the handle table */
664             KeEnterCriticalRegion();
665             ExAcquirePushLockExclusive(&HandleTable->HandleTableLock[0]);
666 
667             /* Check the value again */
668             OldValue = HandleTable->FirstFree;
669             if (OldValue)
670             {
671                 /* Another thread has already created a new level, bail out */
672                 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]);
673                 KeLeaveCriticalRegion();
674                 break;
675             }
676 
677             /* Now move any free handles */
678             OldValue = ExpMoveFreeHandles(HandleTable);
679             if (OldValue)
680             {
681                 /* Another thread has already moved them, bail out */
682                 ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]);
683                 KeLeaveCriticalRegion();
684                 break;
685             }
686 
687             /* We're the first one through, so do the actual allocation */
688             Result = ExpAllocateHandleTableEntrySlow(HandleTable, TRUE);
689 
690             /* Unlock the table and get the value now */
691             ExReleasePushLockExclusive(&HandleTable->HandleTableLock[0]);
692             KeLeaveCriticalRegion();
693             OldValue = HandleTable->FirstFree;
694 
695             /* Check if allocation failed */
696             if (!Result)
697             {
698                 /* Check if nobody else went through here */
699                 if (!OldValue)
700                 {
701                     /* We're still the only thread around, so fail */
702                     NewHandle->GenericHandleOverlay = NULL;
703                     return NULL;
704                 }
705             }
706         }
707 
708         /* We made it, write the current value */
709         Handle.Value = (OldValue & FREE_HANDLE_MASK);
710 
711         /* Lookup the entry for this handle */
712         Entry = ExpLookupHandleTableEntry(HandleTable, Handle);
713 
714         /* Get an available lock and acquire it */
715         OldHandle.Value = OldValue;
716         i = OldHandle.Index % 4;
717         KeEnterCriticalRegion();
718         ExAcquirePushLockShared(&HandleTable->HandleTableLock[i]);
719 
720         /* Check if the value changed after acquiring the lock */
721         if (OldValue != *(volatile ULONG*)&HandleTable->FirstFree)
722         {
723             /* It did, so try again */
724             ExReleasePushLockShared(&HandleTable->HandleTableLock[i]);
725             KeLeaveCriticalRegion();
726             continue;
727         }
728 
729         /* Now get the next value and do the compare */
730         NewValue = *(volatile ULONG*)&Entry->NextFreeTableEntry;
731         NewValue1 = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree,
732                                                NewValue,
733                                                OldValue);
734 
735         /* The change was done, so release the lock */
736         ExReleasePushLockShared(&HandleTable->HandleTableLock[i]);
737         KeLeaveCriticalRegion();
738 
739         /* Check if the compare was successful */
740         if (NewValue1 == OldValue)
741         {
742             /* Make sure that the new handle is in range, and break out */
743             ASSERT((NewValue & FREE_HANDLE_MASK) <
744                    HandleTable->NextHandleNeedingPool);
745             break;
746         }
747         else
748         {
749             /* The compare failed, make sure we expected it */
750             ASSERT((NewValue1 & FREE_HANDLE_MASK) !=
751                    (OldValue & FREE_HANDLE_MASK));
752         }
753     }
754 
755     /* Increase the number of handles */
756     InterlockedIncrement(&HandleTable->HandleCount);
757 
758     /* Return the handle and the entry */
759     *NewHandle = Handle;
760     return Entry;
761 }
762 
763 PHANDLE_TABLE
764 NTAPI
765 ExCreateHandleTable(IN PEPROCESS Process OPTIONAL)
766 {
767     PHANDLE_TABLE HandleTable;
768     PAGED_CODE();
769 
770     /* Allocate the handle table */
771     HandleTable = ExpAllocateHandleTable(Process, TRUE);
772     if (!HandleTable) return NULL;
773 
774     /* Acquire the handle table lock */
775     KeEnterCriticalRegion();
776     ExAcquirePushLockExclusive(&HandleTableListLock);
777 
778     /* Insert it into the list */
779     InsertTailList(&HandleTableListHead, &HandleTable->HandleTableList);
780 
781     /* Release the lock */
782     ExReleasePushLockExclusive(&HandleTableListLock);
783     KeLeaveCriticalRegion();
784 
785     /* Return the handle table */
786     return HandleTable;
787 }
788 
789 HANDLE
790 NTAPI
791 ExCreateHandle(IN PHANDLE_TABLE HandleTable,
792                IN PHANDLE_TABLE_ENTRY HandleTableEntry)
793 {
794     EXHANDLE Handle;
795     PHANDLE_TABLE_ENTRY NewEntry;
796     PAGED_CODE();
797 
798     /* Start with a clean handle */
799     Handle.GenericHandleOverlay = NULL;
800 
801     /* Allocate a new entry */
802     NewEntry = ExpAllocateHandleTableEntry(HandleTable, &Handle);
803     if (NewEntry)
804     {
805         /* Enter a critical region */
806         KeEnterCriticalRegion();
807 
808         /* Write the entry */
809         *NewEntry = *HandleTableEntry;
810 
811         /* Unlock it and leave the critical region */
812         ExUnlockHandleTableEntry(HandleTable, NewEntry);
813         KeLeaveCriticalRegion();
814     }
815 
816     /* Return the handle value */
817     return Handle.GenericHandleOverlay;
818 }
819 
820 VOID
821 NTAPI
822 ExpBlockOnLockedHandleEntry(IN PHANDLE_TABLE HandleTable,
823                             IN PHANDLE_TABLE_ENTRY HandleTableEntry)
824 {
825     LONG_PTR OldValue;
826     EX_PUSH_LOCK_WAIT_BLOCK WaitBlock;
827 
828     /* Block on the pushlock */
829     ExBlockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock);
830 
831     /* Get the current value and check if it's been unlocked */
832     OldValue = HandleTableEntry->Value;
833     if (!(OldValue) || (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT))
834     {
835         /* Unblock the pushlock and return */
836         ExfUnblockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock);
837     }
838     else
839     {
840         /* Wait for it to be unblocked */
841         ExWaitForUnblockPushLock(&HandleTable->HandleContentionEvent,
842                                  &WaitBlock);
843     }
844 }
845 
846 BOOLEAN
847 NTAPI
848 ExpLockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
849                         IN PHANDLE_TABLE_ENTRY HandleTableEntry)
850 {
851     LONG_PTR NewValue, OldValue;
852 
853     /* Sanity check */
854     ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) ||
855            (KeGetCurrentIrql() == APC_LEVEL));
856 
857     /* Start lock loop */
858     for (;;)
859     {
860         /* Get the current value and check if it's locked */
861         OldValue = *(volatile LONG_PTR *)&HandleTableEntry->Object;
862         if (OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT)
863         {
864             /* It's not locked, remove the lock bit to lock it */
865             NewValue = OldValue & ~EXHANDLE_TABLE_ENTRY_LOCK_BIT;
866             if (InterlockedCompareExchangePointer(&HandleTableEntry->Object,
867                                                   (PVOID)NewValue,
868                                                   (PVOID)OldValue) == (PVOID)OldValue)
869             {
870                 /* We locked it, get out */
871                 return TRUE;
872             }
873         }
874         else
875         {
876             /* We couldn't lock it, bail out if it's been freed */
877             if (!OldValue) return FALSE;
878         }
879 
880         /* It's locked, wait for it to be unlocked */
881         ExpBlockOnLockedHandleEntry(HandleTable, HandleTableEntry);
882     }
883 }
884 
885 VOID
886 NTAPI
887 ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
888                          IN PHANDLE_TABLE_ENTRY HandleTableEntry)
889 {
890     LONG_PTR OldValue;
891     PAGED_CODE();
892 
893     /* Sanity check */
894     ASSERT((KeGetCurrentThread()->CombinedApcDisable != 0) ||
895            (KeGetCurrentIrql() == APC_LEVEL));
896 
897     /* Set the lock bit and make sure it wasn't earlier */
898     OldValue = InterlockedOr((PLONG) &HandleTableEntry->Value,
899                              EXHANDLE_TABLE_ENTRY_LOCK_BIT);
900     ASSERT((OldValue & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0);
901 
902     /* Unblock any waiters */
903     ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
904 }
905 
906 VOID
907 NTAPI
908 ExRemoveHandleTable(IN PHANDLE_TABLE HandleTable)
909 {
910     PAGED_CODE();
911 
912     /* Acquire the table lock */
913     KeEnterCriticalRegion();
914     ExAcquirePushLockExclusive(&HandleTableListLock);
915 
916     /* Remove the table and reset the list */
917     RemoveEntryList(&HandleTable->HandleTableList);
918     InitializeListHead(&HandleTable->HandleTableList);
919 
920     /* Release the lock */
921     ExReleasePushLockExclusive(&HandleTableListLock);
922     KeLeaveCriticalRegion();
923 }
924 
925 VOID
926 NTAPI
927 ExDestroyHandleTable(IN PHANDLE_TABLE HandleTable,
928                      IN PVOID DestroyHandleProcedure OPTIONAL)
929 {
930     PAGED_CODE();
931 
932     /* Remove the handle from the list */
933     ExRemoveHandleTable(HandleTable);
934 
935     /* Check if we have a destroy callback */
936     if (DestroyHandleProcedure)
937     {
938         /* FIXME: */
939         ASSERT(FALSE);
940     }
941 
942     /* Free the handle table */
943     ExpFreeHandleTable(HandleTable);
944 }
945 
946 BOOLEAN
947 NTAPI
948 ExDestroyHandle(IN PHANDLE_TABLE HandleTable,
949                 IN HANDLE Handle,
950                 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL)
951 {
952     EXHANDLE ExHandle;
953     PVOID Object;
954     PAGED_CODE();
955 
956     /* Setup the actual handle value */
957     ExHandle.GenericHandleOverlay = Handle;
958 
959     /* Enter a critical region and check if we have to lookup the handle */
960     KeEnterCriticalRegion();
961     if (!HandleTableEntry)
962     {
963         /* Lookup the entry */
964         HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle);
965 
966         /* Make sure that we found an entry, and that it's valid */
967         if (!(HandleTableEntry) ||
968             !(HandleTableEntry->Object) ||
969             (HandleTableEntry->NextFreeTableEntry == -2))
970         {
971             /* Invalid handle, fail */
972             KeLeaveCriticalRegion();
973             return FALSE;
974         }
975 
976         /* Lock the entry */
977         if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
978         {
979             /* Couldn't lock, fail */
980             KeLeaveCriticalRegion();
981             return FALSE;
982         }
983     }
984     else
985     {
986         /* Make sure the handle is locked */
987         ASSERT((HandleTableEntry->Value & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0);
988     }
989 
990     /* Clear the handle */
991     Object = InterlockedExchangePointer((PVOID*)&HandleTableEntry->Object, NULL);
992 
993     /* Sanity checks */
994     ASSERT(Object != NULL);
995     ASSERT((((ULONG_PTR)Object) & EXHANDLE_TABLE_ENTRY_LOCK_BIT) == 0);
996 
997     /* Unblock the pushlock */
998     ExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
999 
1000     /* Free the actual entry */
1001     ExpFreeHandleTableEntry(HandleTable, ExHandle, HandleTableEntry);
1002 
1003     /* If we got here, return success */
1004     KeLeaveCriticalRegion();
1005     return TRUE;
1006 }
1007 
1008 PHANDLE_TABLE_ENTRY
1009 NTAPI
1010 ExMapHandleToPointer(IN PHANDLE_TABLE HandleTable,
1011                      IN HANDLE Handle)
1012 {
1013     EXHANDLE ExHandle;
1014     PHANDLE_TABLE_ENTRY HandleTableEntry;
1015     PAGED_CODE();
1016 
1017     /* Set the handle value */
1018     ExHandle.GenericHandleOverlay = Handle;
1019 
1020     /* Fail if we got an invalid index */
1021     if (!(ExHandle.Index & (LOW_LEVEL_ENTRIES - 1))) return NULL;
1022 
1023     /* Do the lookup */
1024     HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle);
1025     if (!HandleTableEntry) return NULL;
1026 
1027     /* Lock it */
1028     if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry)) return NULL;
1029 
1030     /* Return the entry */
1031     return HandleTableEntry;
1032 }
1033 
1034 PHANDLE_TABLE
1035 NTAPI
1036 ExDupHandleTable(IN PEPROCESS Process,
1037                  IN PHANDLE_TABLE HandleTable,
1038                  IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,
1039                  IN ULONG_PTR Mask)
1040 {
1041     PHANDLE_TABLE NewTable;
1042     EXHANDLE Handle;
1043     PHANDLE_TABLE_ENTRY HandleTableEntry, NewEntry;
1044     BOOLEAN Failed = FALSE;
1045     PAGED_CODE();
1046 
1047     /* Allocate the duplicated copy */
1048     NewTable = ExpAllocateHandleTable(Process, FALSE);
1049     if (!NewTable) return NULL;
1050 
1051     /* Loop each entry */
1052     while (NewTable->NextHandleNeedingPool <
1053            HandleTable->NextHandleNeedingPool)
1054     {
1055         /* Insert it into the duplicated copy */
1056         if (!ExpAllocateHandleTableEntrySlow(NewTable, FALSE))
1057         {
1058             /* Insert failed, free the new copy and return */
1059             ExpFreeHandleTable(NewTable);
1060             return NULL;
1061         }
1062     }
1063 
1064     /* Setup the initial handle table data */
1065     NewTable->HandleCount = 0;
1066     NewTable->ExtraInfoPages = 0;
1067     NewTable->FirstFree = 0;
1068 
1069     /* Setup the first handle value  */
1070     Handle.Value = INDEX_TO_HANDLE_VALUE(1);
1071 
1072     /* Enter a critical region and lookup the new entry */
1073     KeEnterCriticalRegion();
1074     while ((NewEntry = ExpLookupHandleTableEntry(NewTable, Handle)))
1075     {
1076         /* Lookup the old entry */
1077         HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle);
1078 
1079         /* Loop each entry */
1080         do
1081         {
1082             /* Check if it doesn't match the audit mask */
1083             if (!(HandleTableEntry->Value & Mask))
1084             {
1085                 /* Free it since we won't use it */
1086                 Failed = TRUE;
1087             }
1088             else
1089             {
1090                 /* Lock the entry */
1091                 if (!ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1092                 {
1093                     /* Free it since we can't lock it, so we won't use it */
1094                     Failed = TRUE;
1095                 }
1096                 else
1097                 {
1098                     /* Copy the handle value */
1099                     *NewEntry = *HandleTableEntry;
1100 
1101                     /* Call the duplicate callback */
1102                     if (DupHandleProcedure(Process,
1103                                            HandleTable,
1104                                            HandleTableEntry,
1105                                            NewEntry))
1106                     {
1107                         /* Clear failure flag */
1108                         Failed = FALSE;
1109 
1110                         /* Lock the entry, increase the handle count */
1111                         NewEntry->Value |= EXHANDLE_TABLE_ENTRY_LOCK_BIT;
1112                         NewTable->HandleCount++;
1113                     }
1114                     else
1115                     {
1116                         /* Duplication callback refused, fail */
1117                         Failed = TRUE;
1118                     }
1119                 }
1120             }
1121 
1122             /* Check if we failed earlier and need to free */
1123             if (Failed)
1124             {
1125                 /* Free this entry */
1126                 NewEntry->Object = NULL;
1127                 NewEntry->NextFreeTableEntry = NewTable->FirstFree;
1128                 NewTable->FirstFree = (ULONG)Handle.Value;
1129             }
1130 
1131             /* Increase the handle value and move to the next entry */
1132             Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1133             NewEntry++;
1134             HandleTableEntry++;
1135         } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
1136 
1137         /* We're done, skip the last entry */
1138         Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1139     }
1140 
1141     /* Acquire the table lock and insert this new table into the list */
1142     ExAcquirePushLockExclusive(&HandleTableListLock);
1143     InsertTailList(&HandleTableListHead, &NewTable->HandleTableList);
1144     ExReleasePushLockExclusive(&HandleTableListLock);
1145 
1146     /* Leave the critical region we entered previously and return the table */
1147     KeLeaveCriticalRegion();
1148     return NewTable;
1149 }
1150 
1151 BOOLEAN
1152 NTAPI
1153 ExChangeHandle(IN PHANDLE_TABLE HandleTable,
1154                IN HANDLE Handle,
1155                IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,
1156                IN ULONG_PTR Context)
1157 {
1158     EXHANDLE ExHandle;
1159     PHANDLE_TABLE_ENTRY HandleTableEntry;
1160     BOOLEAN Result = FALSE;
1161     PAGED_CODE();
1162 
1163     /* Set the handle value */
1164     ExHandle.GenericHandleOverlay = Handle;
1165 
1166     /* Find the entry for this handle */
1167     HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle);
1168 
1169     /* Make sure that we found an entry, and that it's valid */
1170     if (!(HandleTableEntry) ||
1171         !(HandleTableEntry->Object) ||
1172         (HandleTableEntry->NextFreeTableEntry == -2))
1173     {
1174         /* It isn't, fail */
1175         return FALSE;
1176     }
1177 
1178     /* Enter a critical region */
1179     KeEnterCriticalRegion();
1180 
1181     /* Try locking the handle entry */
1182     if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1183     {
1184         /* Call the change routine and unlock the entry */
1185         Result = ChangeRoutine(HandleTableEntry, Context);
1186         ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1187     }
1188 
1189     /* Leave the critical region and return the callback result */
1190     KeLeaveCriticalRegion();
1191     return Result;
1192 }
1193 
1194 VOID
1195 NTAPI
1196 ExSweepHandleTable(IN PHANDLE_TABLE HandleTable,
1197                    IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,
1198                    IN PVOID Context)
1199 {
1200     EXHANDLE Handle;
1201     PHANDLE_TABLE_ENTRY HandleTableEntry;
1202     PAGED_CODE();
1203 
1204     /* Set the initial value and loop the entries */
1205     Handle.Value = INDEX_TO_HANDLE_VALUE(1);
1206     while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1207     {
1208         /* Loop each handle */
1209         do
1210         {
1211             /* Lock the entry */
1212             if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1213             {
1214                 /* Notify the callback routine */
1215                 EnumHandleProcedure(HandleTableEntry,
1216                                     Handle.GenericHandleOverlay,
1217                                     Context);
1218             }
1219 
1220             /* Go to the next handle and entry */
1221             Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1222             HandleTableEntry++;
1223         } while (Handle.Value % INDEX_TO_HANDLE_VALUE(LOW_LEVEL_ENTRIES));
1224 
1225         /* Skip past the last entry */
1226         Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1227     }
1228 }
1229 
1230 /*
1231  * @implemented
1232  */
1233 BOOLEAN
1234 NTAPI
1235 ExEnumHandleTable(IN PHANDLE_TABLE HandleTable,
1236                   IN PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
1237                   IN OUT PVOID Context,
1238                   OUT PHANDLE EnumHandle OPTIONAL)
1239 {
1240     EXHANDLE Handle;
1241     PHANDLE_TABLE_ENTRY HandleTableEntry;
1242     BOOLEAN Result = FALSE;
1243     PAGED_CODE();
1244 
1245     /* Enter a critical region */
1246     KeEnterCriticalRegion();
1247 
1248     /* Set the initial value and loop the entries */
1249     Handle.Value = 0;
1250     while ((HandleTableEntry = ExpLookupHandleTableEntry(HandleTable, Handle)))
1251     {
1252         /* Validate the entry */
1253         if ((HandleTableEntry->Object) &&
1254             (HandleTableEntry->NextFreeTableEntry != -2))
1255         {
1256             /* Lock the entry */
1257             if (ExpLockHandleTableEntry(HandleTable, HandleTableEntry))
1258             {
1259                 /* Notify the callback routine */
1260                 Result = EnumHandleProcedure(HandleTableEntry,
1261                                              Handle.GenericHandleOverlay,
1262                                              Context);
1263 
1264                 /* Unlock it */
1265                 ExUnlockHandleTableEntry(HandleTable, HandleTableEntry);
1266 
1267                 /* Was this the one looked for? */
1268                 if (Result)
1269                 {
1270                     /* If so, return it if requested */
1271                     if (EnumHandle) *EnumHandle = Handle.GenericHandleOverlay;
1272                     break;
1273                 }
1274             }
1275         }
1276 
1277         /* Go to the next entry */
1278         Handle.Value += INDEX_TO_HANDLE_VALUE(1);
1279     }
1280 
1281     /* Leave the critical region and return callback result */
1282     KeLeaveCriticalRegion();
1283     return Result;
1284 }
1285 
1286 #if DBG && defined(KDBG)
1287 BOOLEAN ExpKdbgExtHandle(ULONG Argc, PCHAR Argv[])
1288 {
1289     USHORT i;
1290     char *endptr;
1291     HANDLE ProcessId;
1292     EXHANDLE ExHandle;
1293     PLIST_ENTRY Entry;
1294     PEPROCESS Process;
1295     WCHAR KeyPath[MAX_PATH];
1296     PFILE_OBJECT FileObject;
1297     PHANDLE_TABLE HandleTable;
1298     POBJECT_HEADER ObjectHeader;
1299     PHANDLE_TABLE_ENTRY TableEntry;
1300     ULONG NeededLength, NameLength;
1301     PCM_KEY_CONTROL_BLOCK Kcb, CurrentKcb;
1302     POBJECT_HEADER_NAME_INFO ObjectNameInfo;
1303 
1304     if (Argc > 1)
1305     {
1306         /* Get EPROCESS address or PID */
1307         i = 0;
1308         while (Argv[1][i])
1309         {
1310             if (!isdigit(Argv[1][i]))
1311             {
1312                 i = 0;
1313                 break;
1314             }
1315 
1316             ++i;
1317         }
1318 
1319         if (i == 0)
1320         {
1321             if (!KdbpGetHexNumber(Argv[1], (PVOID)&Process))
1322             {
1323                 KdbpPrint("Invalid parameter: %s\n", Argv[1]);
1324                 return TRUE;
1325             }
1326 
1327             /* In the end, we always want a PID */
1328             ProcessId = PsGetProcessId(Process);
1329         }
1330         else
1331         {
1332             ProcessId = (HANDLE)strtoul(Argv[1], &endptr, 10);
1333             if (*endptr != '\0')
1334             {
1335                 KdbpPrint("Invalid parameter: %s\n", Argv[1]);
1336                 return TRUE;
1337             }
1338         }
1339     }
1340     else
1341     {
1342         ProcessId = PsGetCurrentProcessId();
1343     }
1344 
1345     for (Entry = HandleTableListHead.Flink;
1346          Entry != &HandleTableListHead;
1347          Entry = Entry->Flink)
1348     {
1349         /* Only return matching PID
1350          * 0 matches everything
1351          */
1352         HandleTable = CONTAINING_RECORD(Entry, HANDLE_TABLE, HandleTableList);
1353         if (ProcessId != 0 && HandleTable->UniqueProcessId != ProcessId)
1354         {
1355             continue;
1356         }
1357 
1358         KdbpPrint("\n");
1359 
1360         KdbpPrint("Handle table at %p with %d entries in use\n", HandleTable, HandleTable->HandleCount);
1361 
1362         ExHandle.Value = 0;
1363         while ((TableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle)))
1364         {
1365             if ((TableEntry->Object) &&
1366                 (TableEntry->NextFreeTableEntry != -2))
1367             {
1368                 ObjectHeader = ObpGetHandleObject(TableEntry);
1369 
1370                 KdbpPrint("%p: Object: %p GrantedAccess: %x Entry: %p\n", ExHandle.Value, &ObjectHeader->Body, TableEntry->GrantedAccess, TableEntry);
1371                 KdbpPrint("Object: %p Type: (%x) %wZ\n", &ObjectHeader->Body, ObjectHeader->Type, &ObjectHeader->Type->Name);
1372                 KdbpPrint("\tObjectHeader: %p\n", ObjectHeader);
1373                 KdbpPrint("\t\tHandleCount: %u PointerCount: %u\n", ObjectHeader->HandleCount, ObjectHeader->PointerCount);
1374 
1375                 /* Specific objects debug prints */
1376 
1377                 /* For file, display path */
1378                 if (ObjectHeader->Type == IoFileObjectType)
1379                 {
1380                     FileObject = (PFILE_OBJECT)&ObjectHeader->Body;
1381 
1382                     KdbpPrint("\t\t\tName: %wZ\n", &FileObject->FileName);
1383                 }
1384 
1385                 /* For directory, and win32k objects, display object name */
1386                 else if (ObjectHeader->Type == ObpDirectoryObjectType ||
1387                          ObjectHeader->Type == ExWindowStationObjectType ||
1388                          ObjectHeader->Type == ExDesktopObjectType ||
1389                          ObjectHeader->Type == MmSectionObjectType)
1390                 {
1391                     ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1392                     if (ObjectNameInfo != NULL && ObjectNameInfo->Name.Buffer != NULL)
1393                     {
1394                         KdbpPrint("\t\t\tName: %wZ\n", &ObjectNameInfo->Name);
1395                     }
1396                 }
1397 
1398                 /* For registry keys, display full path */
1399                 else if (ObjectHeader->Type == CmpKeyObjectType)
1400                 {
1401                     Kcb = ((PCM_KEY_BODY)&ObjectHeader->Body)->KeyControlBlock;
1402                     if (!Kcb->Delete)
1403                     {
1404                         CurrentKcb = Kcb;
1405 
1406                         /* See: CmpQueryNameInformation() */
1407 
1408                         while (CurrentKcb != NULL)
1409                         {
1410                             if (CurrentKcb->NameBlock->Compressed)
1411                                 NeededLength += CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
1412                             else
1413                                 NeededLength += CurrentKcb->NameBlock->NameLength;
1414 
1415                             NeededLength += sizeof(OBJ_NAME_PATH_SEPARATOR);
1416 
1417                             CurrentKcb = CurrentKcb->ParentKcb;
1418                         }
1419 
1420                         if (NeededLength < MAX_PATH * sizeof(WCHAR))
1421                         {
1422                             CurrentKcb = Kcb;
1423 
1424                             while (CurrentKcb != NULL)
1425                             {
1426                                 if (CurrentKcb->NameBlock->Compressed)
1427                                 {
1428                                     NameLength = CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
1429                                     CmpCopyCompressedName(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)],
1430                                                           NameLength,
1431                                                           CurrentKcb->NameBlock->Name,
1432                                                           CurrentKcb->NameBlock->NameLength);
1433                                 }
1434                                 else
1435                                 {
1436                                     NameLength = CurrentKcb->NameBlock->NameLength;
1437                                     RtlCopyMemory(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)],
1438                                                   CurrentKcb->NameBlock->Name,
1439                                                   NameLength);
1440                                 }
1441 
1442                                 NeededLength -= NameLength;
1443                                 NeededLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
1444                                 KeyPath[NeededLength/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
1445 
1446                                 CurrentKcb = CurrentKcb->ParentKcb;
1447                             }
1448                         }
1449 
1450                         KdbpPrint("\t\t\tName: %S\n", KeyPath);
1451                     }
1452                 }
1453             }
1454 
1455             ExHandle.Value += INDEX_TO_HANDLE_VALUE(1);
1456         }
1457     }
1458 
1459     return TRUE;
1460 }
1461 #endif
1462