1851d56b09403f038e06b7acb27fed1f440a5d16
[reactos.git] / ntoskrnl / ex / handle.c
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 = 0;
1301 ULONG NameLength;
1302 PCM_KEY_CONTROL_BLOCK Kcb, CurrentKcb;
1303 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
1304
1305 if (Argc > 1)
1306 {
1307 /* Get EPROCESS address or PID */
1308 i = 0;
1309 while (Argv[1][i])
1310 {
1311 if (!isdigit(Argv[1][i]))
1312 {
1313 i = 0;
1314 break;
1315 }
1316
1317 ++i;
1318 }
1319
1320 if (i == 0)
1321 {
1322 if (!KdbpGetHexNumber(Argv[1], (PVOID)&Process))
1323 {
1324 KdbpPrint("Invalid parameter: %s\n", Argv[1]);
1325 return TRUE;
1326 }
1327
1328 /* In the end, we always want a PID */
1329 ProcessId = PsGetProcessId(Process);
1330 }
1331 else
1332 {
1333 ProcessId = (HANDLE)strtoul(Argv[1], &endptr, 10);
1334 if (*endptr != '\0')
1335 {
1336 KdbpPrint("Invalid parameter: %s\n", Argv[1]);
1337 return TRUE;
1338 }
1339 }
1340 }
1341 else
1342 {
1343 ProcessId = PsGetCurrentProcessId();
1344 }
1345
1346 for (Entry = HandleTableListHead.Flink;
1347 Entry != &HandleTableListHead;
1348 Entry = Entry->Flink)
1349 {
1350 /* Only return matching PID
1351 * 0 matches everything
1352 */
1353 HandleTable = CONTAINING_RECORD(Entry, HANDLE_TABLE, HandleTableList);
1354 if (ProcessId != 0 && HandleTable->UniqueProcessId != ProcessId)
1355 {
1356 continue;
1357 }
1358
1359 KdbpPrint("\n");
1360
1361 KdbpPrint("Handle table at %p with %d entries in use\n", HandleTable, HandleTable->HandleCount);
1362
1363 ExHandle.Value = 0;
1364 while ((TableEntry = ExpLookupHandleTableEntry(HandleTable, ExHandle)))
1365 {
1366 if ((TableEntry->Object) &&
1367 (TableEntry->NextFreeTableEntry != -2))
1368 {
1369 ObjectHeader = ObpGetHandleObject(TableEntry);
1370
1371 KdbpPrint("%p: Object: %p GrantedAccess: %x Entry: %p\n", ExHandle.Value, &ObjectHeader->Body, TableEntry->GrantedAccess, TableEntry);
1372 KdbpPrint("Object: %p Type: (%x) %wZ\n", &ObjectHeader->Body, ObjectHeader->Type, &ObjectHeader->Type->Name);
1373 KdbpPrint("\tObjectHeader: %p\n", ObjectHeader);
1374 KdbpPrint("\t\tHandleCount: %u PointerCount: %u\n", ObjectHeader->HandleCount, ObjectHeader->PointerCount);
1375
1376 /* Specific objects debug prints */
1377
1378 /* For file, display path */
1379 if (ObjectHeader->Type == IoFileObjectType)
1380 {
1381 FileObject = (PFILE_OBJECT)&ObjectHeader->Body;
1382
1383 KdbpPrint("\t\t\tName: %wZ\n", &FileObject->FileName);
1384 }
1385
1386 /* For directory, and win32k objects, display object name */
1387 else if (ObjectHeader->Type == ObpDirectoryObjectType ||
1388 ObjectHeader->Type == ExWindowStationObjectType ||
1389 ObjectHeader->Type == ExDesktopObjectType ||
1390 ObjectHeader->Type == MmSectionObjectType)
1391 {
1392 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
1393 if (ObjectNameInfo != NULL && ObjectNameInfo->Name.Buffer != NULL)
1394 {
1395 KdbpPrint("\t\t\tName: %wZ\n", &ObjectNameInfo->Name);
1396 }
1397 }
1398
1399 /* For registry keys, display full path */
1400 else if (ObjectHeader->Type == CmpKeyObjectType)
1401 {
1402 Kcb = ((PCM_KEY_BODY)&ObjectHeader->Body)->KeyControlBlock;
1403 if (!Kcb->Delete)
1404 {
1405 CurrentKcb = Kcb;
1406
1407 /* See: CmpQueryNameInformation() */
1408
1409 while (CurrentKcb != NULL)
1410 {
1411 if (CurrentKcb->NameBlock->Compressed)
1412 NeededLength += CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
1413 else
1414 NeededLength += CurrentKcb->NameBlock->NameLength;
1415
1416 NeededLength += sizeof(OBJ_NAME_PATH_SEPARATOR);
1417
1418 CurrentKcb = CurrentKcb->ParentKcb;
1419 }
1420
1421 if (NeededLength < MAX_PATH * sizeof(WCHAR))
1422 {
1423 CurrentKcb = Kcb;
1424
1425 while (CurrentKcb != NULL)
1426 {
1427 if (CurrentKcb->NameBlock->Compressed)
1428 {
1429 NameLength = CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
1430 CmpCopyCompressedName(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)],
1431 NameLength,
1432 CurrentKcb->NameBlock->Name,
1433 CurrentKcb->NameBlock->NameLength);
1434 }
1435 else
1436 {
1437 NameLength = CurrentKcb->NameBlock->NameLength;
1438 RtlCopyMemory(&KeyPath[(NeededLength - NameLength)/sizeof(WCHAR)],
1439 CurrentKcb->NameBlock->Name,
1440 NameLength);
1441 }
1442
1443 NeededLength -= NameLength;
1444 NeededLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
1445 KeyPath[NeededLength/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
1446
1447 CurrentKcb = CurrentKcb->ParentKcb;
1448 }
1449 }
1450
1451 KdbpPrint("\t\t\tName: %S\n", KeyPath);
1452 }
1453 }
1454 }
1455
1456 ExHandle.Value += INDEX_TO_HANDLE_VALUE(1);
1457 }
1458 }
1459
1460 return TRUE;
1461 }
1462 #endif