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