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 */ 909