test: tunnel.c File Reference

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().