[STORPORT] Fix x64 build
[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;
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 /* bigger than default entry */
390 NodeEntry = ExAllocatePool(NonPagedPool, Length);
391 AllocatedFromPool = TRUE;
392 }
393 else
394 {
395 /* get standard entry */
396 NodeEntry = ExAllocateFromPagedLookasideList(&TunnelLookasideList);
397 }
398
399 /* check for success */
400 if (!NodeEntry)
401 {
402 /* out of memory */
403 return;
404 }
405
406 /* acquire lock */
407 ExAcquireFastMutex(&Cache->Mutex);
408
409 /* now search cache for existing entries */
410 CurEntry = Cache->Cache;
411
412 /* check which key should be used for search */
413 KeyString = (KeyByShortName ? ShortName : LongName);
414
415 /* initialize last entry */
416 LastEntry = NULL;
417
418 while(CurEntry)
419 {
420 /* compare current node */
421 Result = FsRtlCompareNodeAndKey((PTUNNEL_NODE_ENTRY)CurEntry, DirectoryKey, KeyString);
422
423 /* backup last entry */
424 LastEntry = CurEntry;
425
426 if (Result > 0)
427 {
428 /* current directory key is bigger */
429 CurEntry = CurEntry->LeftChild;
430 }
431 else
432 {
433 if (Result == 0)
434 {
435 /* found equal entry */
436 break;
437 }
438
439 /* current directory key is smaller */
440 CurEntry = CurEntry->RightChild;
441 }
442 }
443
444 /* initialize node entry */
445 RtlInitializeSplayLinks(&NodeEntry->SplayInfo);
446
447 if (CurEntry != NULL)
448 {
449 /* found existing item */
450 if (CurEntry->LeftChild)
451 {
452 /* update parent */
453 RtlInsertAsLeftChild(NodeEntry, CurEntry->LeftChild);
454 }
455
456 if (CurEntry->RightChild)
457 {
458 /* update parent */
459 RtlInsertAsRightChild(NodeEntry, CurEntry->RightChild);
460 }
461
462 if (CurEntry->Parent == CurEntry)
463 {
464 /* cur entry was root */
465 Cache->Cache = (struct _RTL_SPLAY_LINKS*)NodeEntry;
466 }
467 else
468 {
469 /* update parent node */
470 if (RtlIsLeftChild(CurEntry))
471 {
472 RtlInsertAsLeftChild(RtlParent(CurEntry), NodeEntry);
473 }
474 else
475 {
476 RtlInsertAsRightChild(RtlParent(CurEntry), NodeEntry);
477 }
478 }
479
480 /* remove entry */
481 RemoveEntryList(&((PTUNNEL_NODE_ENTRY)CurEntry)->TimerQueueEntry);
482
483 /* free node entry */
484 FsRtlFreeTunnelNode((PTUNNEL_NODE_ENTRY)CurEntry, &PoolList);
485
486 /* decrement node count */
487 Cache->NumEntries--;
488 }
489 else
490 {
491 if (LastEntry == NULL)
492 {
493 /* first entry in tunnel cache */
494 Cache->Cache = (struct _RTL_SPLAY_LINKS*)NodeEntry;
495 }
496 else
497 {
498 if (Result > 0)
499 {
500 /* new left node */
501 RtlInsertAsLeftChild(LastEntry, NodeEntry);
502 }
503 else
504 {
505 /* new right node */
506 RtlInsertAsRightChild(LastEntry, NodeEntry);
507 }
508 }
509 }
510
511 /* initialize entry */
512 KeQuerySystemTime(&NodeEntry->Time);
513
514 NodeEntry->DirectoryKey = DirectoryKey;
515 NodeEntry->Flags = (AllocatedFromPool ? TUNNEL_FLAG_POOL : 0x0);
516 NodeEntry->Flags |= (KeyByShortName ? TUNNEL_FLAG_KEY_SHORT_NAME : 0x0);
517
518 if (ShortName)
519 {
520 /* copy short name */
521 NodeEntry->ShortName.Length = ShortName->Length;
522 NodeEntry->ShortName.MaximumLength = ShortName->Length;
523 NodeEntry->ShortName.Buffer = (LPWSTR)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY));
524
525 RtlMoveMemory(NodeEntry->ShortName.Buffer, ShortName->Buffer, ShortName->Length);
526 }
527 else
528 {
529 NodeEntry->ShortName.Length = NodeEntry->ShortName.MaximumLength = 0;
530 NodeEntry->ShortName.Buffer = NULL;
531 }
532
533 if (LongName)
534 {
535 /* copy long name */
536 NodeEntry->LongName.Length = LongName->Length;
537 NodeEntry->LongName.MaximumLength = LongName->Length;
538 NodeEntry->LongName.Buffer = (LPWSTR)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY) + NodeEntry->ShortName.Length);
539
540 RtlMoveMemory(NodeEntry->LongName.Buffer, LongName->Buffer, LongName->Length);
541 }
542 else
543 {
544 NodeEntry->LongName.Length = NodeEntry->LongName.MaximumLength = 0;
545 NodeEntry->LongName.Buffer = NULL;
546 }
547
548 NodeEntry->DataLength = DataLength;
549 NodeEntry->Data = (PVOID)((ULONG_PTR)NodeEntry + sizeof(TUNNEL_NODE_ENTRY) + NodeEntry->ShortName.Length + NodeEntry->LongName.Length);
550 RtlMoveMemory(NodeEntry->Data, Data, DataLength);
551
552 /* increment node count */
553 Cache->NumEntries++;
554
555 /* insert into list */
556 InsertTailList(&Cache->TimerQueue, &NodeEntry->TimerQueueEntry);
557
558 /* prune cache */
559 FsRtlPruneTunnelCache(Cache, &PoolList);
560
561 /* release lock */
562 ExReleaseFastMutex(&Cache->Mutex);
563
564 /* free pool list */
565 FsRtlEmptyFreePoolList(&PoolList);
566 }
567
568 /*++
569 * @name FsRtlDeleteKeyFromTunnelCache
570 * @implemented
571 *
572 * FILLME
573 *
574 * @param Cache
575 * FILLME
576 *
577 * @param DirectoryKey
578 * FILLME
579 *
580 * @return None
581 *
582 * @remarks None
583 *
584 *--*/
585 VOID
586 NTAPI
587 FsRtlDeleteKeyFromTunnelCache(IN PTUNNEL Cache,
588 IN ULONGLONG DirectoryKey)
589 {
590 BOOLEAN Rebalance = TRUE;
591 LIST_ENTRY PoolList;
592 PTUNNEL_NODE_ENTRY CurNode;
593 PRTL_SPLAY_LINKS CurEntry, LastEntry = NULL, Successors;
594
595 PAGED_CODE();
596
597 /* check if tunnel cache is enabled */
598 if (!TunnelMaxEntries)
599 {
600 /* entries are disabled */
601 return;
602 }
603
604 /* initialize free pool list */
605 InitializeListHead(&PoolList);
606
607 /* acquire lock */
608 ExAcquireFastMutex(&Cache->Mutex);
609
610 /* Look for the entry */
611 CurEntry = Cache->Cache;
612 while (CurEntry)
613 {
614 CurNode = CONTAINING_RECORD(CurEntry, TUNNEL_NODE_ENTRY, SplayInfo);
615
616 if (CurNode->DirectoryKey > DirectoryKey)
617 {
618 /* current directory key is bigger */
619 CurEntry = CurEntry->LeftChild;
620 }
621 else if (CurNode->DirectoryKey < DirectoryKey)
622 {
623 /* if we have already found one suitable, break */
624 if (LastEntry != NULL)
625 {
626 break;
627 }
628
629 /* current directory key is smaller */
630 CurEntry = CurEntry->RightChild;
631 }
632 else
633 {
634 /* save and look for another */
635 LastEntry = CurEntry;
636 CurEntry = CurEntry->LeftChild;
637 }
638 }
639
640 /* was it found? */
641 if (LastEntry == NULL)
642 {
643 /* release tunnel lock */
644 ExReleaseFastMutex(&Cache->Mutex);
645
646 return;
647 }
648
649 /* delete any matching key */
650 do
651 {
652 CurNode = CONTAINING_RECORD(LastEntry, TUNNEL_NODE_ENTRY, SplayInfo);
653
654 Successors = RtlRealSuccessor(LastEntry);
655 if (CurNode->DirectoryKey != DirectoryKey)
656 {
657 break;
658 }
659
660 /* remove from tunnel */
661 FsRtlRemoveNodeFromTunnel(Cache, CurNode, &PoolList, &Rebalance);
662 LastEntry = Successors;
663 }
664 while (LastEntry != NULL);
665
666 /* release tunnel lock */
667 ExReleaseFastMutex(&Cache->Mutex);
668
669 /* free pool */
670 FsRtlEmptyFreePoolList(&PoolList);
671 }
672
673 /*++
674 * @name FsRtlDeleteTunnelCache
675 * @implemented
676 *
677 * FILLME
678 *
679 * @param Cache
680 * FILLME
681 *
682 * @return None
683 *
684 * @remarks None
685 *
686 *--*/
687 VOID
688 NTAPI
689 FsRtlDeleteTunnelCache(IN PTUNNEL Cache)
690 {
691 PLIST_ENTRY Entry, NextEntry;
692 PTUNNEL_NODE_ENTRY CurEntry;
693
694 PAGED_CODE();
695
696 /* check if tunnel cache is enabled */
697 if (!TunnelMaxEntries)
698 {
699 /* entries are disabled */
700 return;
701 }
702
703 /* free all entries */
704 Entry = Cache->TimerQueue.Flink;
705
706 while(Entry != &Cache->TimerQueue)
707 {
708 /* get node entry */
709 CurEntry = CONTAINING_RECORD(Entry, TUNNEL_NODE_ENTRY, TimerQueueEntry);
710
711 /* get next entry */
712 NextEntry = Entry->Flink;
713
714 /* remove entry from list */
715 RemoveEntryList(&CurEntry->TimerQueueEntry);
716
717 /* free entry */
718 FsRtlFreeTunnelNode(CurEntry, NULL);
719
720 /* move to next entry */
721 Entry = NextEntry;
722 }
723
724 /* reset object */
725 Cache->Cache = NULL;
726 Cache->NumEntries = 0;
727 InitializeListHead(&Cache->TimerQueue);
728 }
729
730 /*++
731 * @name FsRtlFindInTunnelCache
732 * @implemented
733 *
734 * FILLME
735 *
736 * @param Cache
737 * FILLME
738 *
739 * @param DirectoryKey
740 * FILLME
741 *
742 * @param ShortName
743 * FILLME
744 *
745 * @param LongName
746 * FILLME
747 *
748 * @param KeyByShortName
749 * FILLME
750 *
751 * @param DataLength
752 * FILLME
753 *
754 * @param Data
755 * FILLME
756 *
757 * @return None
758 *
759 * @remarks None
760 *
761 *--*/
762 BOOLEAN
763 NTAPI
764 FsRtlFindInTunnelCache(IN PTUNNEL Cache,
765 IN ULONGLONG DirectoryKey,
766 IN PUNICODE_STRING Name,
767 OUT PUNICODE_STRING ShortName,
768 OUT PUNICODE_STRING LongName,
769 IN OUT PULONG DataLength,
770 OUT PVOID Data)
771 {
772 BOOLEAN Ret = FALSE;
773 PTUNNEL_NODE_ENTRY CurEntry;
774 LIST_ENTRY PoolList;
775 //NTSTATUS Status;
776 LONG Result;
777
778 PAGED_CODE();
779
780 /* check if tunnel cache is enabled */
781 if (!TunnelMaxEntries)
782 {
783 /* entries are disabled */
784 return FALSE;
785 }
786
787 /* initialize free pool list */
788 InitializeListHead(&PoolList);
789
790 /* acquire tunnel lock */
791 ExAcquireFastMutex(&Cache->Mutex);
792
793 /* prune old entries */
794 FsRtlPruneTunnelCache(Cache, &PoolList);
795
796 /* now search cache for existing entries */
797 CurEntry = (PTUNNEL_NODE_ENTRY)Cache->Cache;
798
799 while(CurEntry)
800 {
801 /* compare current node */
802 Result = FsRtlCompareNodeAndKey(CurEntry, DirectoryKey, Name);
803
804 if (Result > 0)
805 {
806 /* current directory key is bigger */
807 CurEntry = (PTUNNEL_NODE_ENTRY)CurEntry->SplayInfo.LeftChild;
808 }
809 else
810 {
811 if (Result == 0)
812 {
813 /* found equal entry */
814 break;
815 }
816
817 /* current directory key is smaller */
818 CurEntry = (PTUNNEL_NODE_ENTRY)CurEntry->SplayInfo.RightChild;
819 }
820 }
821
822 if (CurEntry != NULL)
823 {
824 _SEH2_TRY
825 {
826 /* copy short name */
827 RtlCopyUnicodeString(ShortName, &CurEntry->ShortName);
828
829 /* check size */
830 if (LongName->MaximumLength < CurEntry->LongName.Length)
831 {
832 /* buffer is too small */
833 LongName->Buffer = ExAllocatePool(PagedPool, CurEntry->LongName.Length);
834 if (LongName->Buffer)
835 {
836 LongName->Length = CurEntry->LongName.Length;
837 LongName->MaximumLength = CurEntry->LongName.MaximumLength;
838 RtlMoveMemory(LongName->Buffer, CurEntry->LongName.Buffer, CurEntry->LongName.Length);
839 }
840 }
841 else
842 {
843 /* buffer is big enough */
844 RtlCopyUnicodeString(LongName, &CurEntry->LongName);
845 }
846
847 /* copy data */
848 RtlMoveMemory(Data, CurEntry->Data, CurEntry->DataLength);
849
850 /* store size */
851 *DataLength = CurEntry->DataLength;
852
853 /* done */
854 Ret = TRUE;
855 }
856 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
857 {
858 /* Get the status */
859 //Status = _SEH2_GetExceptionCode();
860 }
861 _SEH2_END;
862
863 }
864
865 /* release tunnel lock */
866 ExReleaseFastMutex(&Cache->Mutex);
867
868 /* free pool */
869 FsRtlEmptyFreePoolList(&PoolList);
870
871 return Ret;
872 }
873
874 /*++
875 * @name FsRtlInitializeTunnelCache
876 * @implemented
877 *
878 * FILLME
879 *
880 * @param Cache
881 * FILLME
882 *
883 * @return None
884 *
885 * @remarks None
886 *
887 *--*/
888 VOID
889 NTAPI
890 FsRtlInitializeTunnelCache(IN PTUNNEL Cache)
891 {
892 PAGED_CODE();
893
894 /* initialize mutex */
895 ExInitializeFastMutex(&Cache->Mutex);
896
897 /* initialize node tree */
898 Cache->Cache = NULL;
899
900 /* initialize timer list */
901 InitializeListHead(&Cache->TimerQueue);
902
903 /* initialize node count */
904 Cache->NumEntries = 0;
905 }
906
907 /* EOF */