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