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 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 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 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 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 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 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 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 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 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 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