Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

tunnel.c File Reference

#include "FsRtlP.h"

Go to the source code of this file.

Classes

struct  TUNNEL_NODE

Defines

#define INLINE   __inline
#define TUNNEL_KEY_NAME   L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem"
#define TUNNEL_AGE_VALUE_NAME   L"MaximumTunnelEntryAgeInSeconds"
#define TUNNEL_SIZE_VALUE_NAME   L"MaximumTunnelEntries"
#define KEY_WORK_AREA   ((sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(ULONG)) + 64)
#define MAX_LOOKASIDE_DEPTH   256
#define LOOKASIDE_NODE_SIZE
#define TUNNEL_FLAG_NON_LOOKASIDE   0x1
#define TUNNEL_FLAG_KEY_SHORT   0x2

Typedefs

typedef * PTUNNEL_NODE

Functions

NTSTATUS FsRtlGetTunnelParameterValue (IN PUNICODE_STRING ValueName, IN OUT PULONG Value)
VOID FsRtlPruneTunnelCache (IN PTUNNEL Cache, IN OUT PLIST_ENTRY FreePoolList)
INLINE LONG FsRtlCompareNodeAndKey (TUNNEL_NODE *Node, ULONGLONG DirectoryKey, PUNICODE_STRING Name)
INLINE VOID FsRtlFreeTunnelNode (PTUNNEL_NODE Node, PLIST_ENTRY FreePoolList OPTIONAL)
INLINE VOID FsRtlEmptyFreePoolList (PLIST_ENTRY FreePoolList)
INLINE VOID FsRtlRemoveNodeFromTunnel (IN PTUNNEL Cache, IN PTUNNEL_NODE Node, IN PLIST_ENTRY FreePoolList, IN PBOOLEAN Splay OPTIONAL)
VOID FsRtlInitializeTunnels (VOID)
VOID FsRtlInitializeTunnelCache (IN PTUNNEL Cache)
VOID FsRtlAddToTunnelCache (IN PTUNNEL Cache, IN ULONGLONG DirKey, IN PUNICODE_STRING ShortName, IN PUNICODE_STRING LongName, IN BOOLEAN KeyByShortName, IN ULONG DataLength, IN PVOID Data)
BOOLEAN FsRtlFindInTunnelCache (IN PTUNNEL Cache, IN ULONGLONG DirKey, IN PUNICODE_STRING Name, OUT PUNICODE_STRING ShortName, OUT PUNICODE_STRING LongName, IN OUT PULONG DataLength, OUT PVOID Data)
VOID FsRtlDeleteKeyFromTunnelCache (IN PTUNNEL Cache, IN ULONGLONG DirKey)
VOID FsRtlDeleteTunnelCache (IN PTUNNEL Cache)

Variables

ULONG TunnelMaxEntries
ULONG TunnelMaxAge
PAGED_LOOKASIDE_LIST TunnelLookasideList


Define Documentation

#define INLINE   __inline
 

Definition at line 63 of file tunnel.c.

#define KEY_WORK_AREA   ((sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(ULONG)) + 64)
 

Definition at line 73 of file tunnel.c.

#define LOOKASIDE_NODE_SIZE
 

Value:

( sizeof(TUNNEL_NODE) + \ sizeof(WCHAR)*(8+1+3) + \ sizeof(WCHAR)*(16) + \ sizeof(ULONGLONG) )

Definition at line 93 of file tunnel.c.

Referenced by FsRtlAddToTunnelCache(), and FsRtlInitializeTunnels().

#define MAX_LOOKASIDE_DEPTH   256
 

Definition at line 91 of file tunnel.c.

Referenced by FsRtlInitializeTunnels().

#define TUNNEL_AGE_VALUE_NAME   L"MaximumTunnelEntryAgeInSeconds"
 

Definition at line 71 of file tunnel.c.

Referenced by FsRtlInitializeTunnels().

#define TUNNEL_FLAG_KEY_SHORT   0x2
 

Definition at line 103 of file tunnel.c.

Referenced by FsRtlAddToTunnelCache(), and FsRtlCompareNodeAndKey().

#define TUNNEL_FLAG_NON_LOOKASIDE   0x1
 

Definition at line 102 of file tunnel.c.

Referenced by FsRtlAddToTunnelCache(), and FsRtlFreeTunnelNode().

#define TUNNEL_KEY_NAME   L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem"
 

Definition at line 70 of file tunnel.c.

Referenced by FsRtlGetTunnelParameterValue().

#define TUNNEL_SIZE_VALUE_NAME   L"MaximumTunnelEntries"
 

Definition at line 72 of file tunnel.c.

Referenced by FsRtlInitializeTunnels().


Typedef Documentation

typedef * PTUNNEL_NODE
 

Referenced by FsRtlAddToTunnelCache(), FsRtlDeleteKeyFromTunnelCache(), FsRtlDeleteTunnelCache(), FsRtlEmptyFreePoolList(), FsRtlFindInTunnelCache(), and FsRtlPruneTunnelCache().


Function Documentation

VOID FsRtlAddToTunnelCache IN PTUNNEL  Cache,
IN ULONGLONG  DirKey,
IN PUNICODE_STRING  ShortName,
IN PUNICODE_STRING  LongName,
IN BOOLEAN  KeyByShortName,
IN ULONG  DataLength,
IN PVOID  Data
 

Definition at line 584 of file tunnel.c.

References Compare(), DbgPrint, ExAllocateFromPagedLookasideList(), ExAllocatePoolWithTag, FALSE, FsRtlCompareNodeAndKey(), FsRtlEmptyFreePoolList(), FsRtlFreeTunnelNode(), FsRtlPruneTunnelCache(), KeQuerySystemTime(), LOOKASIDE_NODE_SIZE, NULL, PAGED_CODE, PagedPool, PTUNNEL_NODE, SetFlag, TRUE, TUNNEL_FLAG_KEY_SHORT, TUNNEL_FLAG_NON_LOOKASIDE, TunnelLookasideList, and TunnelMaxEntries.

00595 : 00596 00597 Adds an entry to the tunnel cache keyed by 00598 00599 DirectoryKey ## (KeyByShortName ? ShortName : LongName) 00600 00601 ShortName, LongName, and Data are copied and stored in the tunnel. As a side 00602 effect, if there are too many entries in the tunnel cache, this routine will 00603 initiate expiration in the tunnel cache. 00604 00605 Arguments: 00606 00607 Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache() 00608 00609 DirKey - the key value of the directory the name appeared in 00610 00611 ShortName - (optional if !KeyByShortName) the 8.3 name of the file 00612 00613 LongName - (optional if KeyByShortName) the long name of the file 00614 00615 KeyByShortName - specifies which name is keyed in the tunnel cache 00616 00617 DataLength - specifies the length of the opaque data segment (file 00618 system specific) which contains the tunnelling information for this 00619 file 00620 00621 Data - pointer to the opaque tunneling data segment 00622 00623 Return Value: 00624 00625 None 00626 00627 --*/ 00628 { 00629 LONG Compare; 00630 ULONG NodeSize; 00631 PUNICODE_STRING NameKey; 00632 PRTL_SPLAY_LINKS *Links; 00633 LIST_ENTRY FreePoolList; 00634 00635 PTUNNEL_NODE Node = NULL; 00636 PTUNNEL_NODE NewNode = NULL; 00637 BOOLEAN FreeOldNode = FALSE; 00638 BOOLEAN AllocatedFromPool = FALSE; 00639 00640 PAGED_CODE(); 00641 00642 // 00643 // If MaxEntries is 0 then tunneling is disabled. 00644 // 00645 00646 if (TunnelMaxEntries == 0) return; 00647 00648 InitializeListHead(&FreePoolList); 00649 00650 // 00651 // Grab a new node for this data 00652 // 00653 00654 NodeSize = sizeof(TUNNEL_NODE) + ShortName->Length + LongName->Length + DataLength; 00655 00656 if (LOOKASIDE_NODE_SIZE >= NodeSize) { 00657 00658 NewNode = ExAllocateFromPagedLookasideList(&TunnelLookasideList); 00659 } 00660 00661 if (NewNode == NULL) { 00662 00663 // 00664 // Data doesn't fit in lookaside nodes 00665 // 00666 00667 NewNode = ExAllocatePoolWithTag(PagedPool, NodeSize, 'PnuT'); 00668 00669 if (NewNode == NULL) { 00670 00671 // 00672 // Give up tunneling this entry 00673 // 00674 00675 return; 00676 } 00677 00678 AllocatedFromPool = TRUE; 00679 } 00680 00681 // 00682 // Traverse the cache to find our insertion point 00683 // 00684 00685 NameKey = (KeyByShortName ? ShortName : LongName); 00686 00687 ExAcquireFastMutex(&Cache->Mutex); 00688 00689 Links = &Cache->Cache; 00690 00691 while (*Links) { 00692 00693 Node = CONTAINING_RECORD(*Links, TUNNEL_NODE, CacheLinks); 00694 00695 Compare = FsRtlCompareNodeAndKey(Node, DirKey, NameKey); 00696 00697 if (Compare > 0) { 00698 00699 Links = &RtlLeftChild(&Node->CacheLinks); 00700 00701 } else { 00702 00703 if (Compare < 0) { 00704 00705 Links = &RtlRightChild(&Node->CacheLinks); 00706 00707 } else { 00708 00709 break; 00710 } 00711 } 00712 } 00713 00714 // 00715 // Thread new data into the splay tree 00716 // 00717 00718 RtlInitializeSplayLinks(&NewNode->CacheLinks); 00719 00720 if (Node) { 00721 00722 // 00723 // Not inserting first node in tree 00724 // 00725 00726 if (*Links) { 00727 00728 // 00729 // Entry exists in the cache, so replace by swapping all splay links 00730 // 00731 00732 RtlRightChild(&NewNode->CacheLinks) = RtlRightChild(*Links); 00733 RtlLeftChild(&NewNode->CacheLinks) = RtlLeftChild(*Links); 00734 00735 if (RtlRightChild(*Links)) RtlParent(RtlRightChild(*Links)) = &NewNode->CacheLinks; 00736 if (RtlLeftChild(*Links)) RtlParent(RtlLeftChild(*Links)) = &NewNode->CacheLinks; 00737 00738 if (!RtlIsRoot(*Links)) { 00739 00740 // 00741 // Change over the parent links. Note that we've messed with *Links now 00742 // since it is pointing at the parent member. 00743 // 00744 00745 RtlParent(&NewNode->CacheLinks) = RtlParent(*Links); 00746 00747 if (RtlIsLeftChild(*Links)) { 00748 00749 RtlLeftChild(RtlParent(*Links)) = &NewNode->CacheLinks; 00750 00751 } else { 00752 00753 RtlRightChild(RtlParent(*Links)) = &NewNode->CacheLinks; 00754 } 00755 00756 } else { 00757 00758 // 00759 // Set root of the cache 00760 // 00761 00762 Cache->Cache = &NewNode->CacheLinks; 00763 } 00764 00765 // 00766 // Free old node 00767 // 00768 00769 RemoveEntryList(&Node->ListLinks); 00770 00771 FsRtlFreeTunnelNode(Node, &FreePoolList); 00772 00773 Cache->NumEntries--; 00774 00775 } else { 00776 00777 // 00778 // Simple insertion as a leaf 00779 // 00780 00781 NewNode->CacheLinks.Parent = &Node->CacheLinks; 00782 *Links = &NewNode->CacheLinks; 00783 } 00784 00785 } else { 00786 00787 Cache->Cache = &NewNode->CacheLinks; 00788 } 00789 00790 // 00791 // Thread onto the timer list 00792 // 00793 00794 KeQuerySystemTime(&NewNode->CreateTime); 00795 InsertTailList(&Cache->TimerQueue, &NewNode->ListLinks); 00796 00797 Cache->NumEntries++; 00798 00799 // 00800 // Stash tunneling information 00801 // 00802 00803 NewNode->DirKey = DirKey; 00804 00805 if (KeyByShortName) { 00806 00807 NewNode->Flags = TUNNEL_FLAG_KEY_SHORT; 00808 00809 } else { 00810 00811 NewNode->Flags = 0; 00812 } 00813 00814 // 00815 // Initialize the internal UNICODE_STRINGS to point at the buffer segments. For various 00816 // reasons (UNICODE APIs are incomplete, we're avoiding calling any allocate routine more 00817 // than once, UNICODE strings are not guaranteed to be null terminated) we have to do a lot 00818 // of this by hand. 00819 // 00820 // The data is layed out like this in the allocated block: 00821 // 00822 // ----------------------------------------------------------------------------------- 00823 // | TUNNEL_NODE | Node->ShortName.Buffer | Node->LongName.Buffer | Node->TunnelData | 00824 // ----------------------------------------------------------------------------------- 00825 // 00826 00827 NewNode->ShortName.Buffer = (PWCHAR)((PCHAR)NewNode + sizeof(TUNNEL_NODE)); 00828 NewNode->LongName.Buffer = (PWCHAR)((PCHAR)NewNode + sizeof(TUNNEL_NODE) + ShortName->Length); 00829 00830 NewNode->ShortName.Length = NewNode->ShortName.MaximumLength = ShortName->Length; 00831 NewNode->LongName.Length = NewNode->LongName.MaximumLength = LongName->Length; 00832 00833 if (ShortName->Length) { 00834 00835 RtlCopyMemory(NewNode->ShortName.Buffer, ShortName->Buffer, ShortName->Length); 00836 } 00837 00838 if (LongName->Length) { 00839 00840 RtlCopyMemory(NewNode->LongName.Buffer, LongName->Buffer, LongName->Length); 00841 } 00842 00843 NewNode->TunnelData = (PVOID)((PCHAR)NewNode + sizeof(TUNNEL_NODE) + ShortName->Length + LongName->Length); 00844 00845 NewNode->TunnelDataLength = DataLength; 00846 00847 RtlCopyMemory(NewNode->TunnelData, Data, DataLength); 00848 00849 if (AllocatedFromPool) { 00850 00851 SetFlag(NewNode->Flags, TUNNEL_FLAG_NON_LOOKASIDE); 00852 } 00853 00854 #if defined(TUNNELTEST) || defined (KEYVIEW) 00855 DbgPrint("FsRtlAddToTunnelCache:\n"); 00856 DumpNode(NewNode, 1); 00857 #ifndef KEYVIEW 00858 DumpTunnel(Cache); 00859 #endif 00860 #endif // TUNNELTEST 00861 00862 // 00863 // Clean out the cache, release, and then drop any pool memory we need to 00864 // 00865 00866 FsRtlPruneTunnelCache(Cache, &FreePoolList); 00867 00868 ExReleaseFastMutex(&Cache->Mutex); 00869 00870 FsRtlEmptyFreePoolList(&FreePoolList); 00871 00872 return; 00873 }

INLINE LONG FsRtlCompareNodeAndKey TUNNEL_NODE Node,
ULONGLONG  DirectoryKey,
PUNICODE_STRING  Name
 

Definition at line 218 of file tunnel.c.

References TUNNEL_NODE::DirKey, FlagOn, TUNNEL_NODE::Flags, TUNNEL_NODE::LongName, Name, RtlCompareUnicodeString(), TUNNEL_NODE::ShortName, TRUE, and TUNNEL_FLAG_KEY_SHORT.

Referenced by FsRtlAddToTunnelCache(), and FsRtlFindInTunnelCache().

00225 : 00226 00227 Compare a tunnel node with a key/name pair 00228 00229 Arguments: 00230 00231 Node - a tunnel node 00232 00233 DirectoryKey - a key value 00234 00235 Name - a filename 00236 00237 Return Value: 00238 00239 Signed comparison result 00240 00241 --*/ 00242 00243 { 00244 return (Node->DirKey > DirectoryKey ? 1 : 00245 (Node->DirKey < DirectoryKey ? -1 : 00246 RtlCompareUnicodeString((FlagOn(Node->Flags, TUNNEL_FLAG_KEY_SHORT) ? 00247 &Node->ShortName : &Node->LongName), 00248 Name, 00249 TRUE))); 00250 }

VOID FsRtlDeleteKeyFromTunnelCache IN PTUNNEL  Cache,
IN ULONGLONG  DirKey
 

Definition at line 1086 of file tunnel.c.

References DbgPrint, FsRtlEmptyFreePoolList(), FsRtlRemoveNodeFromTunnel(), NULL, PAGED_CODE, PTUNNEL_NODE, RtlRealSuccessor(), TRUE, and TunnelMaxEntries.

01092 : 01093 01094 Deletes all entries in the cache associated with a specific directory 01095 01096 Arguments: 01097 01098 Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache() 01099 01100 DirKey - the key value of the directory (presumeably being removed) 01101 01102 Return Value: 01103 01104 None 01105 01106 --*/ 01107 { 01108 PRTL_SPLAY_LINKS Links; 01109 PRTL_SPLAY_LINKS SuccessorLinks; 01110 PTUNNEL_NODE Node; 01111 LIST_ENTRY FreePoolList; 01112 01113 PRTL_SPLAY_LINKS LastLinks = NULL; 01114 BOOLEAN Splay = TRUE; 01115 01116 PAGED_CODE(); 01117 01118 // 01119 // If MaxEntries is 0 then tunneling is disabled. 01120 // 01121 01122 if (TunnelMaxEntries == 0) return; 01123 01124 InitializeListHead(&FreePoolList); 01125 01126 #ifdef KEYVIEW 01127 DbgPrint("++\nDeleting key %08x%08x\n--\n", DblHex64(DirKey)); 01128 #endif 01129 01130 ExAcquireFastMutex(&Cache->Mutex); 01131 01132 Links = Cache->Cache; 01133 01134 while (Links) { 01135 01136 Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks); 01137 01138 if (Node->DirKey > DirKey) { 01139 01140 // 01141 // All nodes to the right are bigger, go left 01142 // 01143 01144 Links = RtlLeftChild(&Node->CacheLinks); 01145 01146 } else { 01147 01148 if (Node->DirKey < DirKey) { 01149 01150 if (LastLinks) { 01151 01152 // 01153 // If we have previously seen a candidate node to delete 01154 // and we have now gone too far left - we know where to start. 01155 // 01156 01157 break; 01158 } 01159 01160 Links = RtlRightChild(&Node->CacheLinks); 01161 01162 } else { 01163 01164 // 01165 // Node is a candidate to be deleted, but we might have more nodes 01166 // to the left in the tree. Note this location and go on. 01167 // 01168 01169 LastLinks = Links; 01170 Links = RtlLeftChild(&Node->CacheLinks); 01171 } 01172 } 01173 } 01174 01175 for (Links = LastLinks; 01176 Links; 01177 Links = SuccessorLinks) { 01178 01179 SuccessorLinks = RtlRealSuccessor(Links); 01180 Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks); 01181 01182 if (Node->DirKey != DirKey) { 01183 01184 // 01185 // Reached nodes which have a different key, so we're done 01186 // 01187 01188 break; 01189 } 01190 01191 FsRtlRemoveNodeFromTunnel(Cache, Node, &FreePoolList, &Splay); 01192 } 01193 01194 #ifdef TUNNELTEST 01195 DbgPrint("FsRtlDeleteKeyFromTunnelCache:\n"); 01196 #ifndef KEYVIEW 01197 DumpTunnel(Cache); 01198 #endif 01199 #endif // TUNNELTEST 01200 01201 ExReleaseFastMutex(&Cache->Mutex); 01202 01203 // 01204 // Free delayed pool 01205 // 01206 01207 FsRtlEmptyFreePoolList(&FreePoolList); 01208 01209 return; 01210 }

VOID FsRtlDeleteTunnelCache IN PTUNNEL  Cache  ) 
 

Definition at line 1226 of file tunnel.c.

References FsRtlFreeTunnelNode(), NULL, PAGED_CODE, PTUNNEL_NODE, and TunnelMaxEntries.

01231 : 01232 01233 Deletes a tunnel cache 01234 01235 Arguments: 01236 01237 Cache - the cache to delete, initialized by FsRtlInitializeTunnelCache() 01238 01239 Return Value: 01240 01241 None 01242 01243 --*/ 01244 { 01245 PTUNNEL_NODE Node; 01246 PLIST_ENTRY Link, Next; 01247 01248 PAGED_CODE(); 01249 01250 // 01251 // If MaxEntries is 0 then tunneling is disabled. 01252 // 01253 01254 if (TunnelMaxEntries == 0) return; 01255 01256 // 01257 // Zero out the cache and delete everything on the timer list 01258 // 01259 01260 Cache->Cache = NULL; 01261 Cache->NumEntries = 0; 01262 01263 for (Link = Cache->TimerQueue.Flink; 01264 Link != &Cache->TimerQueue; 01265 Link = Next) { 01266 01267 Next = Link->Flink; 01268 01269 Node = CONTAINING_RECORD(Link, TUNNEL_NODE, ListLinks); 01270 01271 FsRtlFreeTunnelNode(Node, NULL); 01272 } 01273 01274 InitializeListHead(&Cache->TimerQueue); 01275 01276 return; 01277 }

INLINE VOID FsRtlEmptyFreePoolList PLIST_ENTRY  FreePoolList  ) 
 

Definition at line 297 of file tunnel.c.

References FsRtlFreeTunnelNode(), NULL, and PTUNNEL_NODE.

Referenced by FsRtlAddToTunnelCache(), FsRtlDeleteKeyFromTunnelCache(), and FsRtlFindInTunnelCache().

00302 : 00303 00304 Free all pool memory that has been delayed onto a free list. 00305 00306 Arguments: 00307 00308 FreePoolList - a list of freeable pool memory 00309 00310 Return Value: 00311 00312 None 00313 00314 -*/ 00315 { 00316 PTUNNEL_NODE FreeNode; 00317 00318 while (!IsListEmpty(FreePoolList)) { 00319 00320 FreeNode = CONTAINING_RECORD(FreePoolList->Flink, TUNNEL_NODE, ListLinks); 00321 RemoveEntryList(FreePoolList->Flink); 00322 00323 FsRtlFreeTunnelNode(FreeNode, NULL); 00324 } 00325 }

BOOLEAN FsRtlFindInTunnelCache IN PTUNNEL  Cache,
IN ULONGLONG  DirKey,
IN PUNICODE_STRING  Name,
OUT PUNICODE_STRING  ShortName,
OUT PUNICODE_STRING  LongName,
IN OUT PULONG  DataLength,
OUT PVOID  Data
 

Definition at line 913 of file tunnel.c.

References ASSERT, Compare(), DbgPrint, FALSE, FsRtlAllocatePoolWithTag, FsRtlCompareNodeAndKey(), FsRtlEmptyFreePoolList(), FsRtlPruneTunnelCache(), Name, PAGED_CODE, PagedPool, PTUNNEL_NODE, RtlCopyUnicodeString(), Status, TRUE, and TunnelMaxEntries.

00924 : 00925 00926 Looks up the key 00927 00928 DirKey ## Name 00929 00930 in the tunnel cache and removes it. As a side effect, this routine will initiate 00931 expiration of the aged entries in the tunnel cache. 00932 00933 Arguments: 00934 00935 Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache() 00936 00937 DirKey - the key value of the directory the name will appear in 00938 00939 Name - the name of the entry 00940 00941 ShortName - return string to hold the short name of the tunneled file. Must 00942 already be allocated and large enough for max 8.3 name 00943 00944 LongName - return string to hold the long name of the tunneled file. If 00945 already allocated, may be grown if not large enough. Caller is 00946 responsible for noticing this and freeing data regardless of return value. 00947 00948 DataLength - provides the length of the buffer avaliable to hold the 00949 tunneling information, returns the size of the tunneled information 00950 read out 00951 00952 Return Value: 00953 00954 Boolean true if found, false otherwise 00955 00956 --*/ 00957 { 00958 PRTL_SPLAY_LINKS Links; 00959 PTUNNEL_NODE Node; 00960 LONG Compare; 00961 LIST_ENTRY FreePoolList; 00962 00963 BOOLEAN Status = FALSE; 00964 00965 PAGED_CODE(); 00966 00967 // 00968 // If MaxEntries is 0 then tunneling is disabled. 00969 // 00970 00971 if (TunnelMaxEntries == 0) return FALSE; 00972 00973 InitializeListHead(&FreePoolList); 00974 00975 #ifdef KEYVIEW 00976 DbgPrint("++\nSearching for %wZ , %08x%08x\n--\n", Name, DblHex64(DirKey)); 00977 #endif 00978 00979 ExAcquireFastMutex(&Cache->Mutex); 00980 00981 // 00982 // Expire aged entries first so we don't grab old data 00983 // 00984 00985 FsRtlPruneTunnelCache(Cache, &FreePoolList); 00986 00987 Links = Cache->Cache; 00988 00989 while (Links) { 00990 00991 Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks); 00992 00993 Compare = FsRtlCompareNodeAndKey(Node, DirKey, Name); 00994 00995 if (Compare > 0) { 00996 00997 Links = RtlLeftChild(&Node->CacheLinks); 00998 00999 } else { 01000 01001 if (Compare < 0) { 01002 01003 Links = RtlRightChild(&Node->CacheLinks); 01004 01005 } else { 01006 01007 // 01008 // Found tunneling information 01009 // 01010 01011 #if defined(TUNNELTEST) || defined(KEYVIEW) 01012 DbgPrint("FsRtlFindInTunnelCache:\n"); 01013 DumpNode(Node, 1); 01014 #ifndef KEYVIEW 01015 DumpTunnel(Cache); 01016 #endif 01017 #endif // TUNNELTEST 01018 01019 break; 01020 } 01021 } 01022 } 01023 01024 try { 01025 01026 if (Links) { 01027 01028 // 01029 // Copy node data into caller's area 01030 // 01031 01032 ASSERT(ShortName->MaximumLength >= (8+1+3)*sizeof(WCHAR)); 01033 RtlCopyUnicodeString(ShortName, &Node->ShortName); 01034 01035 if (LongName->MaximumLength >= Node->LongName.Length) { 01036 01037 RtlCopyUnicodeString(LongName, &Node->LongName); 01038 01039 } else { 01040 01041 // 01042 // Need to allocate more memory for the long name 01043 // 01044 01045 LongName->Buffer = FsRtlAllocatePoolWithTag(PagedPool, Node->LongName.Length, '4nuT'); 01046 LongName->Length = LongName->MaximumLength = Node->LongName.Length; 01047 01048 RtlCopyMemory(LongName->Buffer, Node->LongName.Buffer, Node->LongName.Length); 01049 } 01050 01051 ASSERT(*DataLength >= Node->TunnelDataLength); 01052 RtlCopyMemory(Data, Node->TunnelData, Node->TunnelDataLength); 01053 *DataLength = Node->TunnelDataLength; 01054 01055 Status = TRUE; 01056 } 01057 01058 } finally { 01059 01060 ExReleaseFastMutex(&Cache->Mutex); 01061 01062 FsRtlEmptyFreePoolList(&FreePoolList); 01063 } 01064 01065 return Status; 01066 }

INLINE VOID FsRtlFreeTunnelNode PTUNNEL_NODE  Node,
PLIST_ENTRY FreePoolList  OPTIONAL
 

Definition at line 255 of file tunnel.c.

References ExFreePool(), ExFreeToPagedLookasideList(), FlagOn, TUNNEL_FLAG_NON_LOOKASIDE, and TunnelLookasideList.

Referenced by FsRtlAddToTunnelCache(), FsRtlDeleteTunnelCache(), FsRtlEmptyFreePoolList(), and FsRtlRemoveNodeFromTunnel().

00261 : 00262 00263 Free a node 00264 00265 Arguments: 00266 00267 Node - a tunnel node to free 00268 00269 FreePoolList - optional list to hold freeable pool memory 00270 00271 Return Value: 00272 00273 None 00274 00275 -*/ 00276 { 00277 if (FreePoolList) { 00278 00279 InsertHeadList(FreePoolList, &Node->ListLinks); 00280 00281 } else { 00282 00283 if (FlagOn(Node->Flags, TUNNEL_FLAG_NON_LOOKASIDE)) { 00284 00285 ExFreePool(Node); 00286 00287 } else { 00288 00289 ExFreeToPagedLookasideList(&TunnelLookasideList, Node); 00290 } 00291 } 00292 }

NTSTATUS FsRtlGetTunnelParameterValue IN PUNICODE_STRING  ValueName,
IN OUT PULONG  Value
 

Definition at line 1371 of file tunnel.c.

References ASSERT, Buffer, ExAllocatePoolWithTag, ExFreePool(), Handle, KEY_WORK_AREA, KeyName, NT_SUCCESS, NTSTATUS(), NULL, ObjectAttributes, PagedPool, Status, TUNNEL_KEY_NAME, and ValueName.

Referenced by FsRtlInitializeTunnels().

01378 : 01379 01380 Given a unicode value name this routine will go into the registry 01381 location for the Tunnel parameter information and get the 01382 value. 01383 01384 Arguments: 01385 01386 ValueName - the unicode name for the registry value located in the 01387 double space configuration location of the registry. 01388 Value - a pointer to the ULONG for the result. 01389 01390 Return Value: 01391 01392 NTSTATUS 01393 01394 If STATUS_SUCCESSFUL is returned, the location *Value will be 01395 updated with the DWORD value from the registry. If any failing 01396 status is returned, this value is untouched. 01397 01398 --*/ 01399 01400 { 01401 HANDLE Handle; 01402 NTSTATUS Status; 01403 ULONG RequestLength; 01404 ULONG ResultLength; 01405 UCHAR Buffer[KEY_WORK_AREA]; 01406 UNICODE_STRING KeyName; 01407 OBJECT_ATTRIBUTES ObjectAttributes; 01408 PKEY_VALUE_FULL_INFORMATION KeyValueInformation; 01409 01410 KeyName.Buffer = TUNNEL_KEY_NAME; 01411 KeyName.Length = sizeof(TUNNEL_KEY_NAME) - sizeof(WCHAR); 01412 KeyName.MaximumLength = sizeof(TUNNEL_KEY_NAME); 01413 01414 InitializeObjectAttributes(&ObjectAttributes, 01415 &KeyName, 01416 OBJ_CASE_INSENSITIVE, 01417 NULL, 01418 NULL); 01419 01420 Status = ZwOpenKey(&Handle, 01421 KEY_READ, 01422 &ObjectAttributes); 01423 01424 if (!NT_SUCCESS(Status)) { 01425 01426 return Status; 01427 } 01428 01429 RequestLength = KEY_WORK_AREA; 01430 01431 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer; 01432 01433 while (1) { 01434 01435 Status = ZwQueryValueKey(Handle, 01436 ValueName, 01437 KeyValueFullInformation, 01438 KeyValueInformation, 01439 RequestLength, 01440 &ResultLength); 01441 01442 ASSERT( Status != STATUS_BUFFER_OVERFLOW ); 01443 01444 if (Status == STATUS_BUFFER_OVERFLOW) { 01445 01446 // 01447 // Try to get a buffer big enough. 01448 // 01449 01450 if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) { 01451 01452 ExFreePool(KeyValueInformation); 01453 } 01454 01455 RequestLength += 256; 01456 01457 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) 01458 ExAllocatePoolWithTag(PagedPool, 01459 RequestLength, 01460 'KnuT'); 01461 01462 if (!KeyValueInformation) { 01463 return STATUS_NO_MEMORY; 01464 } 01465 01466 } else { 01467 01468 break; 01469 } 01470 } 01471 01472 ZwClose(Handle); 01473 01474 if (NT_SUCCESS(Status)) { 01475 01476 if (KeyValueInformation->DataLength != 0) { 01477 01478 PULONG DataPtr; 01479 01480 // 01481 // Return contents to the caller. 01482 // 01483 01484 DataPtr = (PULONG) 01485 ((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset); 01486 *Value = *DataPtr; 01487 01488 } else { 01489 01490 // 01491 // Treat as if no value was found 01492 // 01493 01494 Status = STATUS_OBJECT_NAME_NOT_FOUND; 01495 } 01496 } 01497 01498 if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) { 01499 01500 ExFreePool(KeyValueInformation); 01501 } 01502 01503 return Status; 01504 }

VOID FsRtlInitializeTunnelCache IN PTUNNEL  Cache  ) 
 

Definition at line 517 of file tunnel.c.

References ExInitializeFastMutex, NULL, and PAGED_CODE.

00522 : 00523 00524 Initialize a new tunnel cache. 00525 00526 Arguments: 00527 00528 None 00529 00530 Return Value: 00531 00532 None 00533 00534 --*/ 00535 { 00536 PAGED_CODE(); 00537 00538 ExInitializeFastMutex(&Cache->Mutex); 00539 00540 Cache->Cache = NULL; 00541 InitializeListHead(&Cache->TimerQueue); 00542 Cache->NumEntries = 0; 00543 00544 return; 00545 }

VOID FsRtlInitializeTunnels VOID   ) 
 

Definition at line 382 of file tunnel.c.

References ExInitializePagedLookasideList(), FsRtlGetTunnelParameterValue(), LOOKASIDE_NODE_SIZE, MAX_LOOKASIDE_DEPTH, MmIsThisAnNtAsSystem(), NULL, PAGED_CODE, TUNNEL_AGE_VALUE_NAME, TUNNEL_SIZE_VALUE_NAME, TunnelLookasideList, TunnelMaxAge, TunnelMaxEntries, USHORT, ValueName, and VOID().

Referenced by FsRtlInitSystem().

00387 : 00388 00389 Initializes the global part of the tunneling package. 00390 00391 Arguments: 00392 00393 None 00394 00395 Return Value: 00396 00397 None 00398 00399 --*/ 00400 { 00401 UNICODE_STRING ValueName; 00402 USHORT LookasideDepth; 00403 00404 PAGED_CODE(); 00405 00406 if (MmIsThisAnNtAsSystem()) { 00407 00408 TunnelMaxEntries = 1024; 00409 00410 } else { 00411 00412 TunnelMaxEntries = 256; 00413 } 00414 00415 TunnelMaxAge = 15; 00416 00417 // 00418 // Query our configurable parameters 00419 // 00420 // Don't worry about failure in retrieving from the registry. We've gotten 00421 // this far so fall back on defaults even if there was a problem with resources. 00422 // 00423 00424 ValueName.Buffer = TUNNEL_SIZE_VALUE_NAME; 00425 ValueName.Length = sizeof(TUNNEL_SIZE_VALUE_NAME) - sizeof(WCHAR); 00426 ValueName.MaximumLength = sizeof(TUNNEL_SIZE_VALUE_NAME); 00427 (VOID) FsRtlGetTunnelParameterValue(&ValueName, &TunnelMaxEntries); 00428 00429 ValueName.Buffer = TUNNEL_AGE_VALUE_NAME; 00430 ValueName.Length = sizeof(TUNNEL_AGE_VALUE_NAME) - sizeof(WCHAR); 00431 ValueName.MaximumLength = sizeof(TUNNEL_AGE_VALUE_NAME); 00432 (VOID) FsRtlGetTunnelParameterValue(&ValueName, &TunnelMaxAge); 00433 00434 if (TunnelMaxAge == 0) { 00435 00436 // 00437 // If the registry has been set so the timeout is zero, we should force 00438 // the number of entries to zero also. This preserves expectations and lets 00439 // us key off of max entries alone in performing the hard disabling of the 00440 // caching code. 00441 // 00442 00443 TunnelMaxEntries = 0; 00444 } 00445 00446 // 00447 // Convert from seconds to 10ths of msecs, the internal resolution 00448 // 00449 00450 TunnelMaxAge *= 10000000; 00451 00452 // 00453 // Build the lookaside list for common node allocation 00454 // 00455 00456 if (TunnelMaxEntries > MAXUSHORT) { 00457 00458 // 00459 // User is hinting a big need to us 00460 // 00461 00462 LookasideDepth = MAX_LOOKASIDE_DEPTH; 00463 00464 } else { 00465 00466 LookasideDepth = ((USHORT)TunnelMaxEntries)/16; 00467 } 00468 00469 if (LookasideDepth == 0 && TunnelMaxEntries) { 00470 00471 // 00472 // Miniscule number of entries allowed. Lookaside 'em all. 00473 // 00474 00475 LookasideDepth = (USHORT)TunnelMaxEntries + 1; 00476 } 00477 00478 if (LookasideDepth > MAX_LOOKASIDE_DEPTH) { 00479 00480 // 00481 // Finally, restrict the depth to something reasonable. 00482 // 00483 00484 LookasideDepth = MAX_LOOKASIDE_DEPTH; 00485 } 00486 00487 ExInitializePagedLookasideList( &TunnelLookasideList, 00488 NULL, 00489 NULL, 00490 0, 00491 LOOKASIDE_NODE_SIZE, 00492 'LnuT', 00493 LookasideDepth ); 00494 00495 return; 00496 }

VOID FsRtlPruneTunnelCache IN PTUNNEL  Cache,
IN OUT PLIST_ENTRY  FreePoolList
 

Definition at line 1281 of file tunnel.c.

References DbgPrint, FsRtlRemoveNodeFromTunnel(), KeQuerySystemTime(), PAGED_CODE, PTUNNEL_NODE, TRUE, TunnelMaxAge, and TunnelMaxEntries.

Referenced by FsRtlAddToTunnelCache(), and FsRtlFindInTunnelCache().

01287 : 01288 01289 Removes deadwood entries from the tunnel cache as defined by TunnelMaxAge and TunnelMaxEntries. 01290 Pool memory is returned on a list for deletion by the calling routine at a time of 01291 its choosing. 01292 01293 For performance reasons we don't want to force freeing of memory inside a mutex. 01294 01295 Arguments: 01296 01297 Cache - the tunnel cache to prune 01298 01299 FreePoolList - a list to queue pool memory on to 01300 01301 Return Value: 01302 01303 None 01304 --*/ 01305 { 01306 PTUNNEL_NODE Node; 01307 LARGE_INTEGER ExpireTime; 01308 LARGE_INTEGER CurrentTime; 01309 BOOLEAN Splay = TRUE; 01310 01311 PAGED_CODE(); 01312 01313 // 01314 // Calculate the age of the oldest entry we want to keep 01315 // 01316 01317 KeQuerySystemTime(&CurrentTime); 01318 ExpireTime.QuadPart = CurrentTime.QuadPart - TunnelMaxAge; 01319 01320 // 01321 // Expire old entries off of the timer queue. We have to check 01322 // for future time because the clock may jump as a result of 01323 // hard clock change. If we did not do this, a rogue entry 01324 // with a future time could sit at the top of the queue and 01325 // prevent entries from going away. 01326 // 01327 01328 while (!IsListEmpty(&Cache->TimerQueue)) { 01329 01330 Node = CONTAINING_RECORD(Cache->TimerQueue.Flink, TUNNEL_NODE, ListLinks); 01331 01332 if (Node->CreateTime.QuadPart < ExpireTime.QuadPart || 01333 Node->CreateTime.QuadPart > CurrentTime.QuadPart) { 01334 01335 #if defined(TUNNELTEST) || defined(KEYVIEW) 01336 DbgPrint("Expiring node %x (%ud%ud 1/10 msec too old)\n", Node, DblHex64(ExpireTime.QuadPart - Node->CreateTime.QuadPart)); 01337 #endif // TUNNELTEST 01338 01339 FsRtlRemoveNodeFromTunnel(Cache, Node, FreePoolList, &Splay); 01340 01341 } else { 01342 01343 // 01344 // No more nodes to be expired 01345 // 01346 01347 break; 01348 } 01349 } 01350 01351 // 01352 // Remove entries until we're under the TunnelMaxEntries limit 01353 // 01354 01355 while (Cache->NumEntries > TunnelMaxEntries) { 01356 01357 Node = CONTAINING_RECORD(Cache->TimerQueue.Flink, TUNNEL_NODE, ListLinks); 01358 01359 #if defined(TUNNELTEST) || defined(KEYVIEW) 01360 DbgPrint("Dumping node %x (%d > %d)\n", Node, Cache->NumEntries, TunnelMaxEntries); 01361 #endif // TUNNELTEST 01362 01363 FsRtlRemoveNodeFromTunnel(Cache, Node, FreePoolList, &Splay); 01364 } 01365 01366 return; 01367 }

INLINE VOID FsRtlRemoveNodeFromTunnel IN PTUNNEL  Cache,
IN PTUNNEL_NODE  Node,
IN PLIST_ENTRY  FreePoolList,
IN PBOOLEAN Splay  OPTIONAL
 

Definition at line 330 of file tunnel.c.

References FALSE, FsRtlFreeTunnelNode(), RtlDelete(), and RtlDeleteNoSplay().

Referenced by FsRtlDeleteKeyFromTunnelCache(), and FsRtlPruneTunnelCache().

00338 : 00339 00340 Performs the common work of deleting a node from a tunnel cache. Pool memory 00341 is not deleted immediately but is saved aside on a list for deletion later 00342 by the calling routine. 00343 00344 Arguments: 00345 00346 Cache - the tunnel cache the node is in 00347 00348 Node - the node being removed 00349 00350 FreePoolList - an initialized list to take the node if it was allocated from 00351 pool 00352 00353 Splay - an optional flag to indicate whether the tree should be splayed on 00354 the delete. Set to FALSE if splaying was performed. 00355 00356 Return Value: 00357 00358 None. 00359 00360 --*/ 00361 { 00362 if (Splay && *Splay) { 00363 00364 Cache->Cache = RtlDelete(&Node->CacheLinks); 00365 00366 *Splay = FALSE; 00367 00368 } else { 00369 00370 RtlDeleteNoSplay(&Node->CacheLinks, &Cache->Cache); 00371 } 00372 00373 RemoveEntryList(&Node->ListLinks); 00374 00375 Cache->NumEntries--; 00376 00377 FsRtlFreeTunnelNode(Node, FreePoolList); 00378 }


Variable Documentation

PAGED_LOOKASIDE_LIST TunnelLookasideList
 

Definition at line 90 of file tunnel.c.

Referenced by FsRtlAddToTunnelCache(), FsRtlFreeTunnelNode(), and FsRtlInitializeTunnels().

ULONG TunnelMaxAge
 

Definition at line 80 of file tunnel.c.

Referenced by FsRtlInitializeTunnels(), and FsRtlPruneTunnelCache().

ULONG TunnelMaxEntries
 

Definition at line 79 of file tunnel.c.

Referenced by FsRtlAddToTunnelCache(), FsRtlDeleteKeyFromTunnelCache(), FsRtlDeleteTunnelCache(), FsRtlFindInTunnelCache(), FsRtlInitializeTunnels(), and FsRtlPruneTunnelCache().


Generated on Sat May 15 19:45:50 2004 for test by doxygen 1.3.7