[NTOSKRNL] In FsRtlAddToTunnelCache() allocate memory from PagedPool when required.
[reactos.git] / ntoskrnl / fsrtl / tunnel.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/tunnel.c
5 * PURPOSE: Provides the Tunnel Cache implementation for file system drivers.
6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
7 * Pierre Schweitzer (pierre@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 typedef struct {
17 RTL_SPLAY_LINKS SplayInfo;
18 LIST_ENTRY TimerQueueEntry;
19 LARGE_INTEGER Time;
20 ULONGLONG DirectoryKey;
21 ULONG Flags;
22 UNICODE_STRING LongName;
23 UNICODE_STRING ShortName;
24 PVOID Data;
25 ULONG DataLength;
26 } TUNNEL_NODE_ENTRY, *PTUNNEL_NODE_ENTRY;
27
28 ULONG TunnelMaxEntries = 256;
29 ULONG TunnelMaxAge = 15;
30 PAGED_LOOKASIDE_LIST TunnelLookasideList;
31
32 #define DEFAULT_EXTRA_SIZE (72)
33 #define DEFAULT_ENTRY_SIZE (sizeof(TUNNEL_NODE_ENTRY) + DEFAULT_EXTRA_SIZE)
34
35 #define TUNNEL_FLAG_POOL 0x2
36 #define TUNNEL_FLAG_KEY_SHORT_NAME 0x1
37
38 VOID
39 FsRtlFreeTunnelNode(
40 IN PTUNNEL_NODE_ENTRY CurEntry,
41 IN PLIST_ENTRY PoolList OPTIONAL)
42 {
43 if (PoolList)
44 {
45 /* divert the linked list entry, it's not required anymore, but we need it */
46 InsertHeadList(PoolList, &CurEntry->TimerQueueEntry);
47 return;
48 }
49
50 if (CurEntry->Flags & TUNNEL_FLAG_POOL)
51 ExFreePool(CurEntry);
52 else
53 ExFreeToPagedLookasideList(&TunnelLookasideList, CurEntry);
54 }
55
56 VOID
57 FsRtlRemoveNodeFromTunnel(
58 IN PTUNNEL Cache,
59 IN PTUNNEL_NODE_ENTRY CurEntry,
60 IN PLIST_ENTRY PoolList,
61 OUT PBOOLEAN Rebalance)
62 {
63 /* delete entry and rebalance if required */
64 if (Rebalance && *Rebalance)
65 {
66 Cache->Cache = RtlDelete(&CurEntry->SplayInfo);
67 /* reset */
68 *Rebalance = FALSE;
69 }
70 else
71 {
72 RtlDeleteNoSplay(&CurEntry->SplayInfo, &Cache->Cache);
73 }
74
75 /* remove entry */
76 RemoveEntryList(&CurEntry->TimerQueueEntry);
77
78 /* free node entry */
79 FsRtlFreeTunnelNode(CurEntry, PoolList);
80
81 /* decrement node count */
82 Cache->NumEntries--;
83 }
84
85 VOID
86 FsRtlPruneTunnelCache(
87 IN PTUNNEL Cache,
88 IN PLIST_ENTRY PoolList)
89 {
90 PLIST_ENTRY Entry, NextEntry;
91 PTUNNEL_NODE_ENTRY CurEntry;
92 LARGE_INTEGER CurTime, OldTime;
93 BOOLEAN Rebalance = TRUE;
94 PAGED_CODE();
95
96 /* query time */
97 KeQuerySystemTime(&CurTime);
98
99 /* subtract maximum node age */
100 OldTime.QuadPart = CurTime.QuadPart - TunnelMaxAge;
101
102 /* free all entries */
103 Entry = Cache->TimerQueue.Flink;
104
105 while(Entry != &Cache->TimerQueue)
106 {
107 /* get node entry */
108 CurEntry = CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
109
110 /* get next entry */
111 NextEntry = Entry->Flink;
112
113 /* prune if expired OR if in advance in time */
114 if (CurEntry->Time.QuadPart < OldTime.QuadPart ||
115 CurEntry->Time.QuadPart > CurTime.QuadPart)
116 {
117 FsRtlRemoveNodeFromTunnel(Cache, CurEntry, PoolList, &Rebalance);
118 }
119
120 /* move to next entry */
121 Entry = NextEntry;
122 }
123
124 /* If we have too many entries */
125 while (Cache->NumEntries > TunnelMaxEntries)
126 {
127 CurEntry = CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
128 FsRtlRemoveNodeFromTunnel(Cache, CurEntry, PoolList, &Rebalance);
129 }
130 }
131
132 INIT_FUNCTION
133 VOID
134 FsRtlGetTunnelParameterValue(
135 IN PUNICODE_STRING ParameterName,
136 OUT PULONG Value)
137 {
138 UNICODE_STRING Root = RTL_CONSTANT_STRING(L"Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem");
139 OBJECT_ATTRIBUTES ObjectAttributes;
140 HANDLE hKey;
141 NTSTATUS Status;
142 ULONG Length;
143 PKEY_VALUE_FULL_INFORMATION Info;
144
145 /* initialize object attributes */
146 InitializeObjectAttributes(&ObjectAttributes, &Root, OBJ_CASE_INSENSITIVE, NULL, NULL);
147
148 /* open registry key */
149 Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes);
150
151 if (!NT_SUCCESS(Status))
152 {
153 /* failed to open key */
154 return;
155 }
156
157 /* query value size */
158 Status = ZwQueryValueKey(hKey, ParameterName, KeyValueFullInformation, NULL, 0, &Length);
159
160 if (Status != STATUS_BUFFER_TOO_SMALL)
161 {
162 /* failed to query size */
163 ZwClose(hKey);
164 return;
165 }
166
167 /* allocate buffer */
168 Info = ExAllocatePool(PagedPool, Length);
169
170 if (!Info)
171 {
172 /* out of memory */
173 ZwClose(hKey);
174 return;
175 }
176
177 /* query value */
178 Status = ZwQueryValueKey(hKey, ParameterName, KeyValueFullInformation, NULL, 0, &Length);
179
180 if (NT_SUCCESS(Status))
181 {
182 if (Info->DataLength)
183 {
184 /* store result */
185 *Value = (ULONG)((ULONG_PTR)Info + Info->DataOffset);
186 }
187 }
188
189 /* free buffer */
190 ExFreePool(Info);
191
192 /* close key */
193 ZwClose(hKey);
194 }
195
196 INIT_FUNCTION
197 VOID
198 NTAPI
199 FsRtlInitializeTunnels(VOID)
200 {
201 ULONG TunnelEntries;
202 UNICODE_STRING MaximumTunnelEntryAgeInSeconds = RTL_CONSTANT_STRING(L"MaximumTunnelEntryAgeInSeconds");
203 UNICODE_STRING MaximumTunnelEntries = RTL_CONSTANT_STRING( L"MaximumTunnelEntries");
204
205 /* check for nt */
206 if (MmIsThisAnNtAsSystem())
207 {
208 /* default */
209 TunnelMaxEntries = 1024;
210 }
211
212 /* check for custom override of max entries*/
213 FsRtlGetTunnelParameterValue(&MaximumTunnelEntries, &TunnelMaxEntries);
214
215 /* check for custom override of age*/
216 FsRtlGetTunnelParameterValue(&MaximumTunnelEntryAgeInSeconds, &TunnelMaxAge);
217
218 if (!TunnelMaxAge)
219 {
220 /* no age means no entries */
221 TunnelMaxEntries = 0;
222 }
223
224 /* get max entries */
225 TunnelEntries = TunnelMaxEntries;
226
227 /* convert to ticks */
228 TunnelMaxAge *= 10000000;
229
230 if(TunnelMaxEntries <= 65535)
231 {
232 /* use max 256 entries */
233 TunnelEntries = TunnelMaxEntries / 16;
234 }
235
236 if(!TunnelEntries && TunnelMaxEntries )
237 {
238 /* max tunnel entries was too small */
239 TunnelEntries = TunnelMaxEntries + 1;
240 }
241
242 if (TunnelEntries > 0xFFFF)
243 {
244 /* max entries is 256 */
245 TunnelEntries = 256;
246 }
247
248 /* initialize look aside list */
249 ExInitializePagedLookasideList(&TunnelLookasideList, NULL, NULL, 0, DEFAULT_ENTRY_SIZE, 'TunL', TunnelEntries);
250 }
251
252 LONG
253 FsRtlCompareNodeAndKey(
254 IN PTUNNEL_NODE_ENTRY CurEntry,
255 IN ULONGLONG DirectoryKey,
256 IN PUNICODE_STRING KeyString)
257 {
258 PUNICODE_STRING String;
259 LONG Ret;
260
261 if (DirectoryKey > CurEntry->DirectoryKey)
262 {
263 Ret = 1;
264 }
265 else if (DirectoryKey < CurEntry->DirectoryKey)
266 {
267 Ret = -1;
268 }
269 else
270 {
271 if (CurEntry->Flags & TUNNEL_FLAG_KEY_SHORT_NAME)
272 {
273 /* use short name as key */
274 String = &CurEntry->ShortName;
275 }
276 else
277 {
278 /* use long name as key */
279 String = &CurEntry->LongName;
280 }
281
282 Ret = RtlCompareUnicodeString(KeyString, String, TRUE);
283 }
284
285 return Ret;
286 }
287
288 VOID
289 FsRtlEmptyFreePoolList(
290 IN PLIST_ENTRY PoolList)
291 {
292 PLIST_ENTRY CurEntry;
293 PTUNNEL_NODE_ENTRY CurNode;
294
295 /* loop over all the entry */
296 while (!IsListEmpty(PoolList))
297 {
298 /* and free them, one by one */
299 CurEntry = RemoveHeadList(PoolList);
300 CurNode = CONTAINING_RECORD(CurEntry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
301 FsRtlFreeTunnelNode(CurNode, 0);
302 }
303 }
304
305 /* PUBLIC FUNCTIONS **********************************************************/
306
307 /*++
308 * @name FsRtlAddToTunnelCache
309 * @implemented
310 *
311 * FILLME
312 *
313 * @param Cache
314 * FILLME
315 *
316 * @param DirectoryKey
317 * FILLME
318 *
319 * @param ShortName
320 * FILLME
321 *
322 * @param LongName
323 * FILLME
324 *
325 * @param KeyByShortName
326 * FILLME
327 *
328 * @param DataLength
329 * FILLME
330 *
331 * @param Data
332 * FILLME
333 *
334 * @return None
335 *
336 * @remarks None
337 *
338 *--*/
339 VOID
340 NTAPI
341 FsRtlAddToTunnelCache(IN PTUNNEL Cache,
342 IN ULONGLONG DirectoryKey,
343 IN PUNICODE_STRING ShortName,
344 IN PUNICODE_STRING LongName,
345 IN BOOLEAN KeyByShortName,
346 IN ULONG DataLength,
347 IN PVOID Data)
348 {
349 PTUNNEL_NODE_ENTRY NodeEntry = NULL;
350 PRTL_SPLAY_LINKS CurEntry, LastEntry;
351 ULONG Length;
352 LONG Result = 0;
353 BOOLEAN AllocatedFromPool = FALSE;
354 PUNICODE_STRING KeyString;
355 LIST_ENTRY PoolList;
356
357 PAGED_CODE();
358
359 /* check if tunnel cache is enabled */
360 if (!TunnelMaxEntries)
361 {
362 /* entries are disabled */
363 return;
364 }
365
366 /* initialize free pool list */
367 InitializeListHead(&PoolList);
368
369 /* calculate node length */
370 Length = sizeof(TUNNEL_NODE_ENTRY);
371
372 /* add data size */
373 Length += DataLength;
374
375 if (ShortName)
376 {
377 /* add short name length */
378 Length += ShortName->Length;
379 }
380
381 if (LongName)
382 {
383 /* add short name length */
384 Length += LongName->Length;
385 }
386
387 if (Length <= DEFAULT_ENTRY_SIZE)
388 {
389 /* get standard entry */
390 NodeEntry = ExAllocateFromPagedLookasideList(&TunnelLookasideList);
391 }
392
393 if (NodeEntry == NULL)
394 {
395 /* bigger than default entry or allocation failed */
396 NodeEntry = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, Length);
397 /* check for success */
398 if (NodeEntry == NULL)
399 {
400 /* out of memory */
401 return;
402 }
403
404 AllocatedFromPool = TRUE;
405 }
406
407 /* acquire lock */
408 ExAcquireFastMutex(&Cache->Mutex);
409
410 /* now search cache for existing entries */
411 CurEntry = Cache->Cache;
412
413 /* check which key should be used for search */
414 KeyString = (KeyByShortName ? ShortName : LongName);
415
416 /* initialize last entry */
417 LastEntry = NULL;
418
419 while(CurEntry)
420 {
421 /* compare current node */
422 Result = FsRtlCompareNodeAndKey((PTUNNEL_NODE_ENTRY)CurEntry, DirectoryKey, KeyString);
423
424 /* backup last entry */
425 LastEntry = CurEntry;
426
427 if (Result > 0)
428 {
429 /* current directory key is bigger */
430 CurEntry = CurEntry->LeftChild;
431 }
432 else
433 {
434 if (Result == 0)
435 {
436 /* found equal entry */
437 break;
438 }
439
440 /* current directory key is smaller */
441 CurEntry = CurEntry->RightChild;
442 }
443 }
444
445 /* initialize node entry */
446 RtlInitializeSplayLinks(&NodeEntry->SplayInfo);
447
448 if (CurEntry != NULL)
449 {
450 /* found existing item */
451 if (CurEntry->LeftChild)
452 {
453 /* update parent */
454 RtlInsertAsLeftChild(NodeEntry, CurEntry->LeftChild);
455 }
456
457 if (CurEntry->RightChild)
458 {
459 /* update parent */
460 RtlInsertAsRightChild(NodeEntry, CurEntry->RightChild);
461 }
462
463 if (CurEntry->Parent == CurEntry)
464 {
465 /* cur entry was root */
466 Cache->Cache = (struct _RTL_SPLAY_LINKS*)NodeEntry;
467 }
468 else
469 {
470 /* update parent node */
471 if (RtlIsLeftChild(CurEntry))
472 {
473 RtlInsertAsLeftChild(RtlParent(CurEntry), NodeEntry);
474 }
475 else
476 {
477 RtlInsertAsRightChild(RtlParent(CurEntry), NodeEntry);
478 }
479 }
480
481 /* remove entry */
482 RemoveEntryList(&((PTUNNEL_NODE_ENTRY)CurEntry)->TimerQueueEntry);
483
484 /* free node entry */
485 FsRtlFreeTunnelNode((PTUNNEL_NODE_ENTRY)CurEntry, &PoolList);
486
487 /* decrement node count */
488 Cache->NumEntries--;
489 }
490 else
491 {
492 if (LastEntry == NULL)
493 {
494 /* first entry in tunnel cache */
495 Cache->Cache = (struct _RTL_SPLAY_LINKS*)NodeEntry;
496 }
497 else
498 {
499 if (Result > 0)
500 {
501 /* new left node */
502 RtlInsertAsLeftChild(LastEntry, NodeEntry);
503 }
504 else
505 {
506 /* new right node */
507 RtlInsertAsRightChild(LastEntry, NodeEntry);
508 }
509 }
510 }
511
512 /* initialize entry */
513 KeQuerySystemTime(&NodeEntry->Time);
514
515 NodeEntry->DirectoryKey = DirectoryKey;
516 NodeEntry->Flags = (AllocatedFromPool ? TUNNEL_FLAG_POOL : 0x0);
517 NodeEntry->Flags |= (KeyByShortName ? TUNNEL_FLAG_KEY_SHORT_NAME : 0x0);
518
519 if (ShortName)
520 {
521 /* copy short name */
522 NodeEntry->ShortName.Length = ShortName->Length;
523 NodeEntry->ShortName.MaximumLength = ShortName->Length;
524 NodeEntry->ShortName.Buffer = (LPWSTR)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY));
525
526 RtlMoveMemory(NodeEntry->ShortName.Buffer, ShortName->Buffer, ShortName->Length);
527 }
528 else
529 {
530 NodeEntry->ShortName.Length = NodeEntry->ShortName.MaximumLength = 0;
531 NodeEntry->ShortName.Buffer = NULL;
532 }
533
534 if (LongName)
535 {
536 /* copy long name */
537 NodeEntry->LongName.Length = LongName->Length;
538 NodeEntry->LongName.MaximumLength = LongName->Length;
539 NodeEntry->LongName.Buffer = (LPWSTR)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY) + NodeEntry->ShortName.Length);
540
541 RtlMoveMemory(NodeEntry->LongName.Buffer, LongName->Buffer, LongName->Length);
542 }
543 else
544 {
545 NodeEntry->LongName.Length = NodeEntry->LongName.MaximumLength = 0;
546 NodeEntry->LongName.Buffer = NULL;
547 }
548
549 NodeEntry->DataLength = DataLength;
550 NodeEntry->Data = (PVOID)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY) + NodeEntry->ShortName.Length + NodeEntry->LongName.Length);
551 RtlMoveMemory(NodeEntry->Data, Data, DataLength);
552
553 /* increment node count */
554 Cache->NumEntries++;
555
556 /* insert into list */
557 InsertTailList(&Cache->TimerQueue, &NodeEntry->TimerQueueEntry);
558
559 /* prune cache */
560 FsRtlPruneTunnelCache(Cache, &PoolList);
561
562 /* release lock */
563 ExReleaseFastMutex(&Cache->Mutex);
564
565 /* free pool list */
566 FsRtlEmptyFreePoolList(&PoolList);
567 }
568
569 /*++
570 * @name FsRtlDeleteKeyFromTunnelCache
571 * @implemented
572 *
573 * FILLME
574 *
575 * @param Cache
576 * FILLME
577 *
578 * @param DirectoryKey
579 * FILLME
580 *
581 * @return None
582 *
583 * @remarks None
584 *
585 *--*/
586 VOID
587 NTAPI
588 FsRtlDeleteKeyFromTunnelCache(IN PTUNNEL Cache,
589 IN ULONGLONG DirectoryKey)
590 {
591 BOOLEAN Rebalance = TRUE;
592 LIST_ENTRY PoolList;
593 PTUNNEL_NODE_ENTRY CurNode;
594 PRTL_SPLAY_LINKS CurEntry, LastEntry = NULL, Successors;
595
596 PAGED_CODE();
597
598 /* check if tunnel cache is enabled */
599 if (!TunnelMaxEntries)
600 {
601 /* entries are disabled */
602 return;
603 }
604
605 /* initialize free pool list */
606 InitializeListHead(&PoolList);
607
608 /* acquire lock */
609 ExAcquireFastMutex(&Cache->Mutex);
610
611 /* Look for the entry */
612 CurEntry = Cache->Cache;
613 while (CurEntry)
614 {
615 CurNode = CONTAINING_RECORD(CurEntry, TUNNEL_NODE_ENTRY, SplayInfo);
616
617 if (CurNode->DirectoryKey > DirectoryKey)
618 {
619 /* current directory key is bigger */
620 CurEntry = CurEntry->LeftChild;
621 }
622 else if (CurNode->DirectoryKey < DirectoryKey)
623 {
624 /* if we have already found one suitable, break */
625 if (LastEntry != NULL)
626 {
627 break;
628 }
629
630 /* current directory key is smaller */
631 CurEntry = CurEntry->RightChild;
632 }
633 else
634 {
635 /* save and look for another */
636 LastEntry = CurEntry;
637 CurEntry = CurEntry->LeftChild;
638 }
639 }
640
641 /* was it found? */
642 if (LastEntry == NULL)
643 {
644 /* release tunnel lock */
645 ExReleaseFastMutex(&Cache->Mutex);
646
647 return;
648 }
649
650 /* delete any matching key */
651 do
652 {
653 CurNode = CONTAINING_RECORD(LastEntry, TUNNEL_NODE_ENTRY, SplayInfo);
654
655 Successors = RtlRealSuccessor(LastEntry);
656 if (CurNode->DirectoryKey != DirectoryKey)
657 {
658 break;
659 }
660
661 /* remove from tunnel */
662 FsRtlRemoveNodeFromTunnel(Cache, CurNode, &PoolList, &Rebalance);
663 LastEntry = Successors;
664 }
665 while (LastEntry != NULL);
666
667 /* release tunnel lock */
668 ExReleaseFastMutex(&Cache->Mutex);
669
670 /* free pool */
671 FsRtlEmptyFreePoolList(&PoolList);
672 }
673
674 /*++
675 * @name FsRtlDeleteTunnelCache
676 * @implemented
677 *
678 * FILLME
679 *
680 * @param Cache
681 * FILLME
682 *
683 * @return None
684 *
685 * @remarks None
686 *
687 *--*/
688 VOID
689 NTAPI
690 FsRtlDeleteTunnelCache(IN PTUNNEL Cache)
691 {
692 PLIST_ENTRY Entry, NextEntry;
693 PTUNNEL_NODE_ENTRY CurEntry;
694
695 PAGED_CODE();
696
697 /* check if tunnel cache is enabled */
698 if (!TunnelMaxEntries)
699 {
700 /* entries are disabled */
701 return;
702 }
703
704 /* free all entries */
705 Entry = Cache->TimerQueue.Flink;
706
707 while(Entry != &Cache->TimerQueue)
708 {
709 /* get node entry */
710 CurEntry = CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
711
712 /* get next entry */
713 NextEntry = Entry->Flink;
714
715 /* remove entry from list */
716 RemoveEntryList(&CurEntry->TimerQueueEntry);
717
718 /* free entry */
719 FsRtlFreeTunnelNode(CurEntry, NULL);
720
721 /* move to next entry */
722 Entry = NextEntry;
723 }
724
725 /* reset object */
726 Cache->Cache = NULL;
727 Cache->NumEntries = 0;
728 InitializeListHead(&Cache->TimerQueue);
729 }
730
731 /*++
732 * @name FsRtlFindInTunnelCache
733 * @implemented
734 *
735 * FILLME
736 *
737 * @param Cache
738 * FILLME
739 *
740 * @param DirectoryKey
741 * FILLME
742 *
743 * @param ShortName
744 * FILLME
745 *
746 * @param LongName
747 * FILLME
748 *
749 * @param KeyByShortName
750 * FILLME
751 *
752 * @param DataLength
753 * FILLME
754 *
755 * @param Data
756 * FILLME
757 *
758 * @return None
759 *
760 * @remarks None
761 *
762 *--*/
763 BOOLEAN
764 NTAPI
765 FsRtlFindInTunnelCache(IN PTUNNEL Cache,
766 IN ULONGLONG DirectoryKey,
767 IN PUNICODE_STRING Name,
768 OUT PUNICODE_STRING ShortName,
769 OUT PUNICODE_STRING LongName,
770 IN OUT PULONG DataLength,
771 OUT PVOID Data)
772 {
773 BOOLEAN Ret = FALSE;
774 PTUNNEL_NODE_ENTRY CurEntry;
775 LIST_ENTRY PoolList;
776 //NTSTATUS Status;
777 LONG Result;
778
779 PAGED_CODE();
780
781 /* check if tunnel cache is enabled */
782 if (!TunnelMaxEntries)
783 {
784 /* entries are disabled */
785 return FALSE;
786 }
787
788 /* initialize free pool list */
789 InitializeListHead(&PoolList);
790
791 /* acquire tunnel lock */
792 ExAcquireFastMutex(&Cache->Mutex);
793
794 /* prune old entries */
795 FsRtlPruneTunnelCache(Cache, &PoolList);
796
797 /* now search cache for existing entries */
798 CurEntry = (PTUNNEL_NODE_ENTRY)Cache->Cache;
799
800 while(CurEntry)
801 {
802 /* compare current node */
803 Result = FsRtlCompareNodeAndKey(CurEntry, DirectoryKey, Name);
804
805 if (Result > 0)
806 {
807 /* current directory key is bigger */
808 CurEntry = (PTUNNEL_NODE_ENTRY)CurEntry->SplayInfo.LeftChild;
809 }
810 else
811 {
812 if (Result == 0)
813 {
814 /* found equal entry */
815 break;
816 }
817
818 /* current directory key is smaller */
819 CurEntry = (PTUNNEL_NODE_ENTRY)CurEntry->SplayInfo.RightChild;
820 }
821 }
822
823 if (CurEntry != NULL)
824 {
825 _SEH2_TRY
826 {
827 /* copy short name */
828 RtlCopyUnicodeString(ShortName, &CurEntry->ShortName);
829
830 /* check size */
831 if (LongName->MaximumLength < CurEntry->LongName.Length)
832 {
833 /* buffer is too small */
834 LongName->Buffer = ExAllocatePool(PagedPool, CurEntry->LongName.Length);
835 if (LongName->Buffer)
836 {
837 LongName->Length = CurEntry->LongName.Length;
838 LongName->MaximumLength = CurEntry->LongName.MaximumLength;
839 RtlMoveMemory(LongName->Buffer, CurEntry->LongName.Buffer, CurEntry->LongName.Length);
840 }
841 }
842 else
843 {
844 /* buffer is big enough */
845 RtlCopyUnicodeString(LongName, &CurEntry->LongName);
846 }
847
848 /* copy data */
849 RtlMoveMemory(Data, CurEntry->Data, CurEntry->DataLength);
850
851 /* store size */
852 *DataLength = CurEntry->DataLength;
853
854 /* done */
855 Ret = TRUE;
856 }
857 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
858 {
859 /* Get the status */
860 //Status = _SEH2_GetExceptionCode();
861 }
862 _SEH2_END;
863
864 }
865
866 /* release tunnel lock */
867 ExReleaseFastMutex(&Cache->Mutex);
868
869 /* free pool */
870 FsRtlEmptyFreePoolList(&PoolList);
871
872 return Ret;
873 }
874
875 /*++
876 * @name FsRtlInitializeTunnelCache
877 * @implemented
878 *
879 * FILLME
880 *
881 * @param Cache
882 * FILLME
883 *
884 * @return None
885 *
886 * @remarks None
887 *
888 *--*/
889 VOID
890 NTAPI
891 FsRtlInitializeTunnelCache(IN PTUNNEL Cache)
892 {
893 PAGED_CODE();
894
895 /* initialize mutex */
896 ExInitializeFastMutex(&Cache->Mutex);
897
898 /* initialize node tree */
899 Cache->Cache = NULL;
900
901 /* initialize timer list */
902 InitializeListHead(&Cache->TimerQueue);
903
904 /* initialize node count */
905 Cache->NumEntries = 0;
906 }
907
908 /* EOF */