/* * @implemented */ PRTL_SPLAY_LINKS NTAPI RtlRealSuccessor(PRTL_SPLAY_LINKS Links) { PRTL_SPLAY_LINKS Child; /* Get the right child */ Child = RtlRightChild(Links); if (Child) { /* Get left-most child */ while (RtlLeftChild(Child)) Child = RtlLeftChild(Child); return Child; } /* We don't have a right child, keep looping until we find our parent */ Child = Links; while (RtlIsRightChild(Child)) Child = RtlParent(Child); /* The parent should be a left child, return the real successor */ if (RtlIsLeftChild(Child)) return RtlParent(Child); /* The parent isn't a right child, so no real successor for us */ return NULL; }
static VOID FixupChildLinks(PRTL_SPLAY_LINKS Links, BOOLEAN Root, BOOLEAN LeftChild) { if (RtlLeftChild(Links)) { RtlInsertAsLeftChild(Links, RtlLeftChild(Links)); } if (RtlRightChild(Links)) { RtlInsertAsRightChild(Links, RtlRightChild(Links)); } if (!Root) { if (LeftChild) { RtlInsertAsLeftChild(RtlParent(Links), Links); } else { RtlInsertAsRightChild(RtlParent(Links), Links); } } }
VOID DumpNode ( PTUNNEL_NODE Node, ULONG Indent ) { ULONG i; CHAR SpaceBuf[MAXINDENT*INDENTSTEP + 1]; Indent--; if (Indent > MAXINDENT) { Indent = MAXINDENT; } // // DbgPrint is really expensive to iteratively call to do the indenting, // so just build up the indentation all at once on the stack. // RtlFillMemory(SpaceBuf, Indent*INDENTSTEP, ' '); SpaceBuf[Indent*INDENTSTEP] = '\0'; DbgPrint("%sNode 0x%x CreateTime = %08x%08x, DirKey = %08x%08x, Flags = %d\n", SpaceBuf, Node, DblHex64(Node->CreateTime.QuadPart), DblHex64(Node->DirKey), Node->Flags ); DbgPrint("%sShort = %wZ, Long = %wZ\n", SpaceBuf, &Node->ShortName, &Node->LongName ); DbgPrint("%sP = %x, R = %x, L = %x\n", SpaceBuf, RtlParent(&Node->CacheLinks), RtlRightChild(&Node->CacheLinks), RtlLeftChild(&Node->CacheLinks) ); }
VOID SwapSplayLinks ( IN PRTL_SPLAY_LINKS Link1, IN PRTL_SPLAY_LINKS Link2 ) { PRTL_SPLAY_LINKS *Parent1ChildPtr; PRTL_SPLAY_LINKS *Parent2ChildPtr; /* We have the following situation Parent1 Parent2 | | | | Link1 Link2 / \ / \ / \ / \ LC1 RC1 LC2 RC2 where one of the links can possibly be the root and one of the links can possibly be a direct child of the other. Without loss of generality we'll make link2 be the possible and root and link1 be the possible child. */ if ((RtlIsRoot(Link1)) || (RtlParent(Link2) == Link1)) { SwapPointers(Link1, Link2); } // // The four cases we need to handle are // // 1. Link1 is not a child of link2 and link2 is not the root // 2. Link1 is not a child of link2 and link2 is the root // 3. Link1 is a child of link2 and link2 is not the root // 4. Link1 is a child of link2 and link2 is the root // // // Each case will be handled separately // if (RtlParent(Link1) != Link2) { if (!RtlIsRoot(Link2)) { // // Case 1 the initial steps are: // // 1. get both parent child pointers // 2. swap the parent child pointers // 3. swap the parent pointers // Parent1ChildPtr = ParentsChildPointerAddress(Link1); Parent2ChildPtr = ParentsChildPointerAddress(Link2); SwapPointers(*Parent1ChildPtr, *Parent2ChildPtr); SwapPointers(Link1->Parent, Link2->Parent); } else { // // Case 2 the initial steps are: // // 1. Set link1's parent child pointer to link2 // 2. Set parent pointer of link2 to link1's parent // 3. Set parent pointer of link1 to be itself // Parent1ChildPtr = ParentsChildPointerAddress(Link1); *Parent1ChildPtr = Link2; Link2->Parent = Link1->Parent; Link1->Parent = Link1; } // // Case 1 and 2 common steps are: // // 1. swap the child pointers // SwapPointers(Link1->LeftChild, Link2->LeftChild); SwapPointers(Link1->RightChild, Link2->RightChild); } else { // RtlParent(Link1) == Link2 if (!RtlIsRoot(Link2)) { // // Case 3 the initial steps are: // // 1. Set Link2's parent child pointer to link1 // 2. Set Link1's parent pointer to parent of link2 // Parent2ChildPtr = ParentsChildPointerAddress(Link2); *Parent2ChildPtr = Link1; Link1->Parent = Link2->Parent; } else { // // Case 4 the initial steps are: // // 1. Set Link1's parent pointer to be link1 // Link1->Parent = Link1; } // // Case 3 and 4 common steps are: // // 1. Swap the child pointers // 2. if link1 was a left child (i.e., RtlLeftChild(Link1) == Link1) // then set left child of link1 to link2 // else set right child of link1 to link2 // SwapPointers(Link1->LeftChild, Link2->LeftChild); SwapPointers(Link1->RightChild, Link2->RightChild); if (Link1->LeftChild == Link1) { Link1->LeftChild = Link2; } else { Link1->RightChild = Link2; } } // // Case 1, 2, 3, 4 common (and final) steps are: // // 1. Fix the parent pointers of the left and right children // if (Link1->LeftChild != NULL) {Link1->LeftChild->Parent = Link1;} if (Link1->RightChild != NULL) {Link1->RightChild->Parent = Link1;} if (Link2->LeftChild != NULL) {Link2->LeftChild->Parent = Link2;} if (Link2->RightChild != NULL) {Link2->RightChild->Parent = Link2;} }
PRTL_SPLAY_LINKS RtlRealPredecessor ( IN PRTL_SPLAY_LINKS Links ) /*++ Routine Description: The RealPredecessor function takes as input a pointer to a splay link in a tree and returns a pointer to the predecessor of the input node within the entire tree. If there is not a predecessor, the return value is NULL. Arguments: Links - Supplies a pointer to a splay link in a tree. Return Value: PRTL_SPLAY_LINKS - returns a pointer to the predecessor in the entire tree --*/ { PRTL_SPLAY_LINKS Ptr; /* first check to see if there is a left subtree to the input link if there is then the real predecessor is the right most node in the left subtree. That is find and return P in the following diagram Links / . . . P / */ if ((Ptr = RtlLeftChild(Links)) != NULL) { while (RtlRightChild(Ptr) != NULL) { Ptr = RtlRightChild(Ptr); } return Ptr; } /* we do not have a left child so check to see if have a parent and if so find the first ancestor that we are a right descendent of. That is find and return P in the following diagram P \ . . . Links */ Ptr = Links; while (RtlIsLeftChild(Ptr)) { Ptr = RtlParent(Ptr); } if (RtlIsRightChild(Ptr)) { return RtlParent(Ptr); } // // otherwise we are do not have a real predecessor so we simply return // NULL // return NULL; }
PRTL_SPLAY_LINKS RtlSplay ( IN PRTL_SPLAY_LINKS Links ) /*++ Routine Description: The Splay function takes as input a pointer to a splay link in a tree and splays the tree. Its function return value is a pointer to the root of the splayed tree. Arguments: Links - Supplies a pointer to a splay link in a tree. Return Value: PRTL_SPLAY_LINKS - returns a pointer to the root of the splayed tree. --*/ { PRTL_SPLAY_LINKS L; PRTL_SPLAY_LINKS P; PRTL_SPLAY_LINKS G; // // while links is not the root we need to keep rotating it toward // the root // L = Links; while (!RtlIsRoot(L)) { P = RtlParent(L); G = RtlParent(P); if (RtlIsLeftChild(L)) { if (RtlIsRoot(P)) { /* we have the following case P L / \ / \ L c ==> a P / \ / \ a b b c */ // // Connect P & b // P->LeftChild = L->RightChild; if (P->LeftChild != NULL) {P->LeftChild->Parent = P;} // // Connect L & P // L->RightChild = P; P->Parent = L; // // Make L the root // L->Parent = L; } else if (RtlIsLeftChild(P)) { /* we have the following case | | G L / \ / \ P d ==> a P / \ / \ L c b G / \ / \ a b c d */ // // Connect P & b // P->LeftChild = L->RightChild; if (P->LeftChild != NULL) {P->LeftChild->Parent = P;} // // Connect G & c // G->LeftChild = P->RightChild; if (G->LeftChild != NULL) {G->LeftChild->Parent = G;} // // Connect L & Great GrandParent // if (RtlIsRoot(G)) { L->Parent = L; } else { L->Parent = G->Parent; *(ParentsChildPointerAddress(G)) = L; } // // Connect L & P // L->RightChild = P; P->Parent = L; // // Connect P & G // P->RightChild = G; G->Parent = P; } else { // RtlIsRightChild(Parent) /* we have the following case | | G L / \ / \ a P G P / \ / \ / \ L d ==> a b c d / \ b c */ // // Connect G & b // G->RightChild = L->LeftChild; if (G->RightChild != NULL) {G->RightChild->Parent = G;} // // Connect P & c // P->LeftChild = L->RightChild; if (P->LeftChild != NULL) {P->LeftChild->Parent = P;} // // Connect L & Great GrandParent // if (RtlIsRoot(G)) { L->Parent = L; } else { L->Parent = G->Parent; *(ParentsChildPointerAddress(G)) = L; } // // Connect L & G // L->LeftChild = G; G->Parent = L; // // Connect L & P // L->RightChild = P; P->Parent = L; } } else { // RtlIsRightChild(L) if (RtlIsRoot(P)) { /* we have the following case P L / \ / \ a L P c / \ / \ b c ==> a b */ // // Connect P & b // P->RightChild = L->LeftChild; if (P->RightChild != NULL) {P->RightChild->Parent = P;} // // Connect P & L // L->LeftChild = P; P->Parent = L; // // Make L the root // L->Parent = L; } else if (RtlIsRightChild(P)) { /* we have the following case | | G L / \ / \ a P P d / \ / \ b L G c / \ / \ c d ==> a b */ // // Connect G & b // G->RightChild = P->LeftChild; if (G->RightChild != NULL) {G->RightChild->Parent = G;} // // Connect P & c // P->RightChild = L->LeftChild; if (P->RightChild != NULL) {P->RightChild->Parent = P;} // // Connect L & Great GrandParent // if (RtlIsRoot(G)) { L->Parent = L; } else { L->Parent = G->Parent; *(ParentsChildPointerAddress(G)) = L; } // // Connect L & P // L->LeftChild = P; P->Parent = L; // // Connect P & G // P->LeftChild = G; G->Parent = P; } else { // RtlIsLeftChild(P) /* we have the following case | | G L / \ / \ P d P G / \ / \ / \ a L ==> a b c d / \ b c */ // // Connect P & b // P->RightChild = L->LeftChild; if (P->RightChild != NULL) {P->RightChild->Parent = P;} // // Connect G & c // G->LeftChild = L->RightChild; if (G->LeftChild != NULL) {G->LeftChild->Parent = G;} // // Connect L & Great GrandParent // if (RtlIsRoot(G)) { L->Parent = L; } else { L->Parent = G->Parent; *(ParentsChildPointerAddress(G)) = L; } // // Connect L & P // L->LeftChild = P; P->Parent = L; // // Connect L & G // L->RightChild = G; G->Parent = L; } } } return L; }
PRTL_SPLAY_LINKS RtlDelete ( IN PRTL_SPLAY_LINKS Links ) /*++ Routine Description: The Delete function takes as input a pointer to a splay link in a tree and deletes that node from the tree. Its function return value is a pointer to the root of the tree. If the tree is now empty, the return value is NULL. Arguments: Links - Supplies a pointer to a splay link in a tree. Return Value: PRTL_SPLAY_LINKS - returns a pointer to the root of the tree. --*/ { PRTL_SPLAY_LINKS Predecessor; PRTL_SPLAY_LINKS Parent; PRTL_SPLAY_LINKS Child; PRTL_SPLAY_LINKS *ParentChildPtr; // // First check to see if Links as two children. If it does then swap // Links with its subtree predecessor. Now we are guaranteed that Links // has at most one child. // if ((RtlLeftChild(Links) != NULL) && (RtlRightChild(Links) != NULL)) { // // get the predecessor, and swap their position in the tree // Predecessor = RtlSubtreePredecessor(Links); SwapSplayLinks(Predecessor, Links); } // // If Links has no children then delete links by checking if it is // already the root or has a parent. If it is the root then the // tree is now empty, otherwise it set the appropriate parent's child // pointer (i.e., the one to links) to NULL, and splay the parent. // if ((RtlLeftChild(Links) == NULL) && (RtlRightChild(Links) == NULL)) { // // Links has no children, if it is the root then return NULL // if (RtlIsRoot(Links)) { return NULL; } // // Links as not children and is not the root, so to the parent's // child pointer to NULL and splay the parent. // Parent = RtlParent(Links); ParentChildPtr = ParentsChildPointerAddress(Links); *ParentChildPtr = NULL; return RtlSplay(Parent); } // // otherwise Links has one child. If it is the root then make the child // the new root, otherwise link together the child and parent, and splay // the parent. But first remember who our child is. // if (RtlLeftChild(Links) != NULL) { Child = RtlLeftChild(Links); } else { Child = RtlRightChild(Links); } // // If links is the root then we make the child the root and return the // child. // if (RtlIsRoot(Links)) { Child->Parent = Child; return Child; } // // Links is not the root, so set link's parent child pointer to be // the child and the set child's parent to be link's parent, and splay // the parent. // ParentChildPtr = ParentsChildPointerAddress(Links); *ParentChildPtr = Child; Child->Parent = Links->Parent; return RtlSplay(RtlParent(Child)); }
/* * @implemented */ VOID NTAPI RtlRemoveUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable, PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry) { PUNICODE_PREFIX_TABLE_ENTRY Entry, RefEntry, NewEntry; PRTL_SPLAY_LINKS SplayLinks; DPRINT("RtlRemoveUnicodePrefix(): Table %p, TableEntry %p\n", PrefixTable, PrefixTableEntry); /* Erase the last entry */ PrefixTable->LastNextEntry = NULL; /* Check if this was a Case Match Entry */ if (PrefixTableEntry->NodeTypeCode == PFX_NTC_CASE_MATCH) { /* Get the case match entry */ Entry = PrefixTableEntry->CaseMatch; /* Now loop until we find one referencing what the caller sent */ while (Entry->CaseMatch != PrefixTableEntry) Entry = Entry->CaseMatch; /* We found the entry that was sent, link them to delete this entry */ Entry->CaseMatch = PrefixTableEntry->CaseMatch; } else if ((PrefixTableEntry->NodeTypeCode == PFX_NTC_ROOT) || (PrefixTableEntry->NodeTypeCode == PFX_NTC_CHILD)) { /* Check if this entry is a case match */ if (PrefixTableEntry->CaseMatch != PrefixTableEntry) { /* Get the case match entry */ Entry = PrefixTableEntry->CaseMatch; /* Now loop until we find one referencing what the caller sent */ while (Entry->CaseMatch != PrefixTableEntry) Entry = Entry->CaseMatch; /* We found the entry that was sent, link them to delete this entry */ Entry->CaseMatch = PrefixTableEntry->CaseMatch; /* Copy the data */ Entry->NodeTypeCode = PrefixTableEntry->NodeTypeCode; Entry->NextPrefixTree = PrefixTableEntry->NextPrefixTree; Entry->Links = PrefixTableEntry->Links; /* Now check if we are a root entry */ if (RtlIsRoot(&PrefixTableEntry->Links)) { /* We are, so make this entry root as well */ Entry->Links.Parent = &Entry->Links; /* Find the entry referencing us */ RefEntry = Entry->NextPrefixTree; while (RefEntry->NextPrefixTree != Entry) { /* Not this one, move to the next entry */ RefEntry = RefEntry->NextPrefixTree; } /* Link them to us now */ RefEntry->NextPrefixTree = Entry; } else if (RtlIsLeftChild(&PrefixTableEntry->Links)) { /* We were the left child, so make us as well */ RtlParent(&PrefixTableEntry->Links)->LeftChild = &Entry->Links; } else { /* We were the right child, so make us as well */ RtlParent(&PrefixTableEntry->Links)->RightChild = &Entry->Links; } /* Check if we have a left child */ if (RtlLeftChild(&Entry->Links)) { /* Update its parent link */ RtlLeftChild(&Entry->Links)->Parent = &Entry->Links; } /* Check if we have a right child */ if (RtlRightChild(&Entry->Links)) { /* Update its parent link */ RtlRightChild(&Entry->Links)->Parent = &Entry->Links; } } else { /* It's not a case match, so we'll delete the actual entry */ SplayLinks = &PrefixTableEntry->Links; /* Find the root entry */ while (!RtlIsRoot(SplayLinks)) SplayLinks = RtlParent(SplayLinks); Entry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links); /* Delete the entry and check if the whole tree is gone */ SplayLinks = RtlDelete(&PrefixTableEntry->Links); if (!SplayLinks) { /* The tree is also gone now, find the entry referencing us */ RefEntry = Entry->NextPrefixTree; while (RefEntry->NextPrefixTree != Entry) { /* Not this one, move to the next entry */ RefEntry = RefEntry->NextPrefixTree; } /* Link them so this entry stops being referenced */ RefEntry->NextPrefixTree = Entry->NextPrefixTree; } else if (&Entry->Links != SplayLinks) { /* The tree is still here, but we got moved to a new one */ NewEntry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links); /* Find the entry referencing us */ RefEntry = Entry->NextPrefixTree; while (RefEntry->NextPrefixTree != Entry) { /* Not this one, move to the next entry */ RefEntry = RefEntry->NextPrefixTree; } /* Since we got moved, make us the new root entry */ NewEntry->NodeTypeCode = PFX_NTC_ROOT; /* Link us with the entry referencing the old root */ RefEntry->NextPrefixTree = NewEntry; /* And link us with the old tree */ NewEntry->NextPrefixTree = Entry->NextPrefixTree; /* Set the old tree as a child */ Entry->NodeTypeCode = PFX_NTC_CHILD; Entry->NextPrefixTree = NULL; } } } }
/* * @implemented */ PUNICODE_PREFIX_TABLE_ENTRY NTAPI RtlNextUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable, BOOLEAN Restart) { PRTL_SPLAY_LINKS SplayLinks; PUNICODE_PREFIX_TABLE_ENTRY Entry, CaseMatchEntry = NULL; DPRINT("RtlNextUnicodePrefix(): Table %p Restart %u\n", PrefixTable, Restart); /* We might need this entry 2/3rd of the time, so cache it now */ if (PrefixTable->LastNextEntry) CaseMatchEntry = PrefixTable->LastNextEntry->CaseMatch; /* Check if this is a restart or if we don't have a last entry */ if ((Restart) || !(PrefixTable->LastNextEntry)) { /* Get the next entry and validate it */ Entry = PrefixTable->NextPrefixTree; if (Entry->NodeTypeCode == PFX_NTC_TABLE) return NULL; /* Now get the Splay Tree Links */ SplayLinks = &Entry->Links; /* Loop until we get the first node in the tree */ while (RtlLeftChild(SplayLinks)) SplayLinks = RtlLeftChild(SplayLinks); /* Get the entry from it */ Entry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links); } else if (CaseMatchEntry->NodeTypeCode == PFX_NTC_CASE_MATCH) { /* If the last entry was a Case Match, then return it */ Entry = CaseMatchEntry; } else { /* Find the successor */ SplayLinks = RtlRealSuccessor(&CaseMatchEntry->Links); if (!SplayLinks) { /* Didn't find one, we'll have to search the tree */ SplayLinks = &PrefixTable->LastNextEntry->Links; /* Get the topmost node (root) */ while (!RtlIsRoot(SplayLinks)) SplayLinks = RtlParent(SplayLinks); Entry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links); /* Get its tree and make sure somethign is in it */ Entry = Entry->NextPrefixTree; if (Entry->NameLength <= 0) return NULL; /* Select these new links and find the first node */ while (RtlLeftChild(SplayLinks)) SplayLinks = RtlLeftChild(SplayLinks); } /* Get the entry from it */ Entry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links); } /* Save this entry as the last one returned, and return it */ PrefixTable->LastNextEntry = Entry; return Entry; }
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 ) /*++ Routine Description: Adds an entry to the tunnel cache keyed by DirectoryKey ## (KeyByShortName ? ShortName : LongName) ShortName, LongName, and Data are copied and stored in the tunnel. As a side effect, if there are too many entries in the tunnel cache, this routine will initiate expiration in the tunnel cache. Arguments: Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache() DirKey - the key value of the directory the name appeared in ShortName - (optional if !KeyByShortName) the 8.3 name of the file LongName - (optional if KeyByShortName) the long name of the file KeyByShortName - specifies which name is keyed in the tunnel cache DataLength - specifies the length of the opaque data segment (file system specific) which contains the tunnelling information for this file Data - pointer to the opaque tunneling data segment Return Value: None --*/ { LONG Compare; ULONG NodeSize; PUNICODE_STRING NameKey; PRTL_SPLAY_LINKS *Links; LIST_ENTRY FreePoolList; PTUNNEL_NODE Node = NULL; PTUNNEL_NODE NewNode = NULL; BOOLEAN FreeOldNode = FALSE; BOOLEAN AllocatedFromPool = FALSE; PAGED_CODE(); // // If MaxEntries is 0 then tunneling is disabled. // if (TunnelMaxEntries == 0) return; InitializeListHead(&FreePoolList); // // Grab a new node for this data // NodeSize = sizeof(TUNNEL_NODE) + ShortName->Length + LongName->Length + DataLength; if (LOOKASIDE_NODE_SIZE >= NodeSize) { NewNode = ExAllocateFromPagedLookasideList(&TunnelLookasideList); } if (NewNode == NULL) { // // Data doesn't fit in lookaside nodes // NewNode = ExAllocatePoolWithTag(PagedPool, NodeSize, 'PnuT'); if (NewNode == NULL) { // // Give up tunneling this entry // return; } AllocatedFromPool = TRUE; } // // Traverse the cache to find our insertion point // NameKey = (KeyByShortName ? ShortName : LongName); ExAcquireFastMutex(&Cache->Mutex); Links = &Cache->Cache; while (*Links) { Node = CONTAINING_RECORD(*Links, TUNNEL_NODE, CacheLinks); Compare = FsRtlCompareNodeAndKey(Node, DirKey, NameKey); if (Compare > 0) { Links = &RtlLeftChild(&Node->CacheLinks); } else { if (Compare < 0) { Links = &RtlRightChild(&Node->CacheLinks); } else { break; } } } // // Thread new data into the splay tree // RtlInitializeSplayLinks(&NewNode->CacheLinks); if (Node) { // // Not inserting first node in tree // if (*Links) { // // Entry exists in the cache, so replace by swapping all splay links // RtlRightChild(&NewNode->CacheLinks) = RtlRightChild(*Links); RtlLeftChild(&NewNode->CacheLinks) = RtlLeftChild(*Links); if (RtlRightChild(*Links)) RtlParent(RtlRightChild(*Links)) = &NewNode->CacheLinks; if (RtlLeftChild(*Links)) RtlParent(RtlLeftChild(*Links)) = &NewNode->CacheLinks; if (!RtlIsRoot(*Links)) { // // Change over the parent links. Note that we've messed with *Links now // since it is pointing at the parent member. // RtlParent(&NewNode->CacheLinks) = RtlParent(*Links); if (RtlIsLeftChild(*Links)) { RtlLeftChild(RtlParent(*Links)) = &NewNode->CacheLinks; } else { RtlRightChild(RtlParent(*Links)) = &NewNode->CacheLinks; } } else { // // Set root of the cache // Cache->Cache = &NewNode->CacheLinks; } // // Free old node // RemoveEntryList(&Node->ListLinks); FsRtlFreeTunnelNode(Node, &FreePoolList); Cache->NumEntries--; } else { // // Simple insertion as a leaf // NewNode->CacheLinks.Parent = &Node->CacheLinks; *Links = &NewNode->CacheLinks; } } else { Cache->Cache = &NewNode->CacheLinks; } // // Thread onto the timer list // FsRtlQueryNormalizedSystemTime(&NewNode->CreateTime); InsertTailList(&Cache->TimerQueue, &NewNode->ListLinks); Cache->NumEntries++; // // Stash tunneling information // NewNode->DirKey = DirKey; if (KeyByShortName) { NewNode->Flags = TUNNEL_FLAG_KEY_SHORT; } else { NewNode->Flags = 0; } // // Initialize the internal UNICODE_STRINGS to point at the buffer segments. For various // reasons (UNICODE APIs are incomplete, we're avoiding calling any allocate routine more // than once, UNICODE strings are not guaranteed to be null terminated) we have to do a lot // of this by hand. // // The data is layed out like this in the allocated block: // // ----------------------------------------------------------------------------------- // | TUNNEL_NODE | Node->ShortName.Buffer | Node->LongName.Buffer | Node->TunnelData | // ----------------------------------------------------------------------------------- // NewNode->ShortName.Buffer = (PWCHAR)((PCHAR)NewNode + sizeof(TUNNEL_NODE)); NewNode->LongName.Buffer = (PWCHAR)((PCHAR)NewNode + sizeof(TUNNEL_NODE) + ShortName->Length); NewNode->ShortName.Length = NewNode->ShortName.MaximumLength = ShortName->Length; NewNode->LongName.Length = NewNode->LongName.MaximumLength = LongName->Length; if (ShortName->Length) { RtlCopyMemory(NewNode->ShortName.Buffer, ShortName->Buffer, ShortName->Length); } if (LongName->Length) { RtlCopyMemory(NewNode->LongName.Buffer, LongName->Buffer, LongName->Length); } NewNode->TunnelData = (PVOID)((PCHAR)NewNode + sizeof(TUNNEL_NODE) + ShortName->Length + LongName->Length); NewNode->TunnelDataLength = DataLength; RtlCopyMemory(NewNode->TunnelData, Data, DataLength); if (AllocatedFromPool) { SetFlag(NewNode->Flags, TUNNEL_FLAG_NON_LOOKASIDE); } #if defined(TUNNELTEST) || defined (KEYVIEW) DbgPrint("FsRtlAddToTunnelCache:\n"); DumpNode(NewNode, 1); #ifndef KEYVIEW DumpTunnel(Cache); #endif #endif // TUNNELTEST // // Clean out the cache, release, and then drop any pool memory we need to // FsRtlPruneTunnelCache(Cache, &FreePoolList); ExReleaseFastMutex(&Cache->Mutex); FsRtlEmptyFreePoolList(&FreePoolList); return; }
VOID DumpTunnel ( PTUNNEL Tunnel ) { PRTL_SPLAY_LINKS SplayLinks, Ptr; PTUNNEL_NODE Node; PLIST_ENTRY Link; ULONG Indent = 1, i; ULONG EntryCount = 0; BOOLEAN CountOff = FALSE; DbgPrint("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); DbgPrint("NumEntries = %d\n", Tunnel->NumEntries); DbgPrint("****** Cache Tree\n"); SplayLinks = Tunnel->Cache; if (SplayLinks == NULL) { goto end; } while (RtlLeftChild(SplayLinks) != NULL) { SplayLinks = RtlLeftChild(SplayLinks); Indent++; } while (SplayLinks) { Node = CONTAINING_RECORD( SplayLinks, TUNNEL_NODE, CacheLinks ); EntryCount++; DumpNode(Node, Indent); Ptr = SplayLinks; /* first check to see if there is a right subtree to the input link if there is then the real successor is the left most node in the right subtree. That is find and return P in the following diagram Links \ . . . / P \ */ if ((Ptr = RtlRightChild(SplayLinks)) != NULL) { Indent++; while (RtlLeftChild(Ptr) != NULL) { Indent++; Ptr = RtlLeftChild(Ptr); } SplayLinks = Ptr; } else { /* we do not have a right child so check to see if have a parent and if so find the first ancestor that we are a left decendent of. That is find and return P in the following diagram P / . . . Links */ Ptr = SplayLinks; while (RtlIsRightChild(Ptr)) { Indent--; Ptr = RtlParent(Ptr); } if (!RtlIsLeftChild(Ptr)) { // // we do not have a real successor so we simply return // NULL // SplayLinks = NULL; } else { Indent--; SplayLinks = RtlParent(Ptr); } } } end: if (CountOff = (EntryCount != Tunnel->NumEntries)) { DbgPrint("!!!!!!!!!! Splay Tree Count Mismatch (%d != %d)\n", EntryCount, Tunnel->NumEntries); } EntryCount = 0; DbgPrint("****** Timer Queue\n"); for (Link = Tunnel->TimerQueue.Flink; Link != &Tunnel->TimerQueue; Link = Link->Flink) { Node = CONTAINING_RECORD( Link, TUNNEL_NODE, ListLinks ); EntryCount++; DumpNode(Node, 1); } if (CountOff |= (EntryCount != Tunnel->NumEntries)) { DbgPrint("!!!!!!!!!! Timer Queue Count Mismatch (%d != %d)\n", EntryCount, Tunnel->NumEntries); } ASSERT(!CountOff); DbgPrint("------------------------------------------------------------------\n"); }
static VOID SwapSplayLinks(PRTL_SPLAY_LINKS LinkA, PRTL_SPLAY_LINKS LinkB) { if (RtlParent(LinkA) == LinkB || RtlIsRoot(LinkB)) { PRTL_SPLAY_LINKS Tmp = LinkA; LinkA = LinkB; LinkB = Tmp; } { RTL_SPLAY_LINKS Ta = *LinkA, Tb = *LinkB; BOOLEAN RootA = RtlIsRoot(LinkA), LeftA = RtlIsLeftChild(LinkA), LeftB = RtlIsLeftChild(LinkB); *LinkB = Ta; *LinkA = Tb; // A was parent of B is a special case: A->Parent is now B if (RtlParent(&Tb) == LinkA) { if (!RootA) { if (LeftA) { RtlInsertAsLeftChild(RtlParent(&Ta), LinkB); } else { RtlInsertAsRightChild(RtlParent(&Ta), LinkB); } } if (LeftB) { RtlInsertAsLeftChild(LinkB, LinkA); } else { RtlInsertAsRightChild(LinkB, LinkA); } } FixupChildLinks(LinkA, FALSE, LeftB); FixupChildLinks(LinkB, RootA, LeftA); // A was root is a special case: B->Parent is now B if (RootA) RtlParent(LinkB) = LinkB; #ifdef VERIFY_SWAP_SPLAY_LINKS // Verify the distinct cases of node swap if (RootA) { if (RtlParent(&Tb) == LinkA) { // LinkA = D, LinkB = B // D B S S.L S.R S Q Q.R ASSERT(RtlParent(LinkA) == LinkB); ASSERT(RtlLeftChild(LinkA) == RtlLeftChild(&Tb)); ASSERT(RtlRightChild(LinkA) == RtlRightChild(&Tb)); ASSERT(RtlParent(LinkB) == LinkB); ASSERT(RtlLeftChild(LinkB) == (LeftB ? LinkA : RtlLeftChild(&Ta))); ASSERT(RtlRightChild(LinkB) == (LeftB ? RtlRightChild(&Ta) : LinkA)); } else { // LinkA = D, LinkB = A // D A S.P S.L S.R S Q.L Q.R ASSERT(RtlParent(LinkA) == RtlParent(&Tb)); ASSERT(RtlLeftChild(LinkA) == RtlLeftChild(&Tb)); ASSERT(RtlRightChild(LinkA) == RtlRightChild(&Tb)); ASSERT(RtlParent(LinkB) == LinkB); ASSERT(RtlLeftChild(LinkB) == RtlLeftChild(&Ta)); ASSERT(RtlRightChild(LinkB) == RtlRightChild(&Ta)); } } else { if (RtlParent(&Tb) == LinkA) { // LinkA = B, LinkB = A // B A S S.L S.R Q.P Q Q.R ASSERT(RtlParent(LinkA) == LinkB); ASSERT(RtlLeftChild(LinkA) == RtlLeftChild(&Tb)); ASSERT(RtlRightChild(LinkA) == RtlRightChild(&Tb)); ASSERT(RtlParent(LinkB) == RtlParent(&Ta)); ASSERT(RtlLeftChild(LinkB) == (LeftB ? LinkA : RtlLeftChild(&Ta))); ASSERT(RtlRightChild(LinkB) == (LeftB ? RtlRightChild(&Ta) : LinkA)); } else { // LinkA = A, LinkB = C // A C S.P S.L S.R Q.P Q.L Q.R ASSERT(!memcmp(LinkA, &Tb, sizeof(Tb))); ASSERT(!memcmp(LinkB, &Ta, sizeof(Ta))); } } #endif } }
/* * @implemented */ PRTL_SPLAY_LINKS NTAPI RtlSplay(PRTL_SPLAY_LINKS Links) { /* * Implementation Notes (http://en.wikipedia.org/wiki/Splay_tree): * * To do a splay, we carry out a sequence of rotations, * each of which moves the target node N closer to the root. * * Each particular step depends on only two factors: * - Whether N is the left or right child of its parent node, P, * - Whether P is the left or right child of its parent, G (for grandparent node). * * Thus, there are four cases: * - Case 1: N is the left child of P and P is the left child of G. * In this case we perform a double right rotation, so that * P becomes N's right child, and G becomes P's right child. * * - Case 2: N is the right child of P and P is the right child of G. * In this case we perform a double left rotation, so that * P becomes N's left child, and G becomes P's left child. * * - Case 3: N is the left child of P and P is the right child of G. * In this case we perform a rotation so that * G becomes N's left child, and P becomes N's right child. * * - Case 4: N is the right child of P and P is the left child of G. * In this case we perform a rotation so that * P becomes N's left child, and G becomes N's right child. * * Finally, if N doesn't have a grandparent node, we simply perform a * left or right rotation to move it to the root. * * By performing a splay on the node of interest after every operation, * we keep recently accessed nodes near the root and keep the tree * roughly balanced, so that we achieve the desired amortized time bounds. */ PRTL_SPLAY_LINKS N, P, G; /* N is the item we'll be playing with */ N = Links; /* Let the algorithm run until N becomes the root entry */ while (!RtlIsRoot(N)) { /* Now get the parent and grand-parent */ P = RtlParent(N); G = RtlParent(P); /* Case 1 & 3: N is left child of P */ if (RtlIsLeftChild(N)) { /* Case 1: P is the left child of G */ if (RtlIsLeftChild(P)) { /* * N's right-child becomes P's left child and * P's right-child becomes G's left child. */ RtlLeftChild(P) = RtlRightChild(N); RtlLeftChild(G) = RtlRightChild(P); /* * If they exist, update their parent pointers too, * since they've changed trees. */ if (RtlLeftChild(P)) RtlParent(RtlLeftChild(P)) = P; if (RtlLeftChild(G)) RtlParent(RtlLeftChild(G)) = G; /* * Now we'll shove N all the way to the top. * Check if G is the root first. */ if (RtlIsRoot(G)) { /* G doesn't have a parent, so N will become the root! */ RtlParent(N) = N; } else { /* G has a parent, so inherit it since we take G's place */ RtlParent(N) = RtlParent(G); /* * Now find out who was referencing G and have it reference * N instead, since we're taking G's place. */ if (RtlIsLeftChild(G)) { /* * G was a left child, so change its parent's left * child link to point to N now. */ RtlLeftChild(RtlParent(G)) = N; } else { /* * G was a right child, so change its parent's right * child link to point to N now. */ RtlRightChild(RtlParent(G)) = N; } } /* Now N is on top, so P has become its child. */ RtlRightChild(N) = P; RtlParent(P) = N; /* N is on top, P is its child, so G is grandchild. */ RtlRightChild(P) = G; RtlParent(G) = P; } /* Case 3: P is the right child of G */ else if (RtlIsRightChild(P)) { /* * N's left-child becomes G's right child and * N's right-child becomes P's left child. */ RtlRightChild(G) = RtlLeftChild(N); RtlLeftChild(P) = RtlRightChild(N); /* * If they exist, update their parent pointers too, * since they've changed trees. */ if (RtlRightChild(G)) RtlParent(RtlRightChild(G)) = G; if (RtlLeftChild(P)) RtlParent(RtlLeftChild(P)) = P; /* * Now we'll shove N all the way to the top. * Check if G is the root first. */ if (RtlIsRoot(G)) { /* G doesn't have a parent, so N will become the root! */ RtlParent(N) = N; } else { /* G has a parent, so inherit it since we take G's place */ RtlParent(N) = RtlParent(G); /* * Now find out who was referencing G and have it reference * N instead, since we're taking G's place. */ if (RtlIsLeftChild(G)) { /* * G was a left child, so change its parent's left * child link to point to N now. */ RtlLeftChild(RtlParent(G)) = N; } else { /* * G was a right child, so change its parent's right * child link to point to N now. */ RtlRightChild(RtlParent(G)) = N; } } /* Now N is on top, so G has become its left child. */ RtlLeftChild(N) = G; RtlParent(G) = N; /* N is on top, G is its left child, so P is right child. */ RtlRightChild(N) = P; RtlParent(P) = N; } /* "Finally" case: N doesn't have a grandparent => P is root */ else { /* P's left-child becomes N's right child */ RtlLeftChild(P) = RtlRightChild(N); /* If it exists, update its parent pointer too */ if (RtlLeftChild(P)) RtlParent(RtlLeftChild(P)) = P; /* Now make N the root, no need to worry about references */ N->Parent = N; /* And make P its right child */ N->RightChild = P; P->Parent = N; } } /* Case 2 & 4: N is right child of P */ else { /* Case 2: P is the right child of G */ if (RtlIsRightChild(P)) { /* * P's left-child becomes G's right child and * N's left-child becomes P's right child. */ RtlRightChild(G) = RtlLeftChild(P); RtlRightChild(P) = RtlLeftChild(N); /* * If they exist, update their parent pointers too, * since they've changed trees. */ if (RtlRightChild(G)) RtlParent(RtlRightChild(G)) = G; if (RtlRightChild(P)) RtlParent(RtlRightChild(P)) = P; /* * Now we'll shove N all the way to the top. * Check if G is the root first. */ if (RtlIsRoot(G)) { /* G doesn't have a parent, so N will become the root! */ RtlParent(N) = N; } else { /* G has a parent, so inherit it since we take G's place */ RtlParent(N) = RtlParent(G); /* * Now find out who was referencing G and have it reference * N instead, since we're taking G's place. */ if (RtlIsLeftChild(G)) { /* * G was a left child, so change its parent's left * child link to point to N now. */ RtlLeftChild(RtlParent(G)) = N; } else { /* * G was a right child, so change its parent's right * child link to point to N now. */ RtlRightChild(RtlParent(G)) = N; } } /* Now N is on top, so P has become its child. */ RtlLeftChild(N) = P; RtlParent(P) = N; /* N is on top, P is its child, so G is grandchild. */ RtlLeftChild(P) = G; RtlParent(G) = P; } /* Case 4: P is the left child of G */ else if (RtlIsLeftChild(P)) { /* * N's left-child becomes G's right child and * N's right-child becomes P's left child. */ RtlRightChild(P) = RtlLeftChild(N); RtlLeftChild(G) = RtlRightChild(N); /* * If they exist, update their parent pointers too, * since they've changed trees. */ if (RtlRightChild(P)) RtlParent(RtlRightChild(P)) = P; if (RtlLeftChild(G)) RtlParent(RtlLeftChild(G)) = G; /* * Now we'll shove N all the way to the top. * Check if G is the root first. */ if (RtlIsRoot(G)) { /* G doesn't have a parent, so N will become the root! */ RtlParent(N) = N; } else { /* G has a parent, so inherit it since we take G's place */ RtlParent(N) = RtlParent(G); /* * Now find out who was referencing G and have it reference * N instead, since we're taking G's place. */ if (RtlIsLeftChild(G)) { /* * G was a left child, so change its parent's left * child link to point to N now. */ RtlLeftChild(RtlParent(G)) = N; } else { /* * G was a right child, so change its parent's right * child link to point to N now. */ RtlRightChild(RtlParent(G)) = N; } } /* Now N is on top, so P has become its left child. */ RtlLeftChild(N) = P; RtlParent(G) = N; /* N is on top, P is its left child, so G is right child. */ RtlRightChild(N) = G; RtlParent(P) = N; } /* "Finally" case: N doesn't have a grandparent => P is root */ else { /* P's right-child becomes N's left child */ RtlRightChild(P) = RtlLeftChild(N); /* If it exists, update its parent pointer too */ if (RtlRightChild(P)) RtlParent(RtlRightChild(P)) = P; /* Now make N the root, no need to worry about references */ N->Parent = N; /* And make P its left child */ N->LeftChild = P; P->Parent = N; } } } /* Return the root entry */ ASSERT(RtlIsRoot(N)); return N; }
/* * @implemented */ PRTL_SPLAY_LINKS NTAPI RtlDelete(PRTL_SPLAY_LINKS Links) { PRTL_SPLAY_LINKS N, P, C, SP; N = Links; /* Check if we have two children */ if ((RtlLeftChild(N)) && (RtlRightChild(N))) { /* Get the predecessor */ SP = RtlSubtreePredecessor(N); /* Swap it with N, this will guarantee that N will have only a child */ SwapSplayLinks(SP, N); } /* Check if we have no children */ if (!(RtlLeftChild(N)) && !(RtlRightChild(N))) { /* If we are also the root, then the tree is gone */ if (RtlIsRoot(N)) return NULL; /* Get our parent */ P = RtlParent(N); /* Find out who is referencing us and delete the reference */ if (RtlIsLeftChild(N)) { /* N was a left child, so erase its parent's left child link */ RtlLeftChild(RtlParent(N)) = NULL; } else { /* N was a right child, so erase its parent's right child link */ RtlRightChild(RtlParent(N)) = NULL; } /* And finally splay the parent */ return RtlSplay(P); } /* If we got here, we have a child (not two: we swapped above!) */ if (RtlLeftChild(N)) { /* We have a left child, so get it */ C = RtlLeftChild(N); } else { /* We have a right child, get him instead */ C = RtlRightChild(N); } /* Check if we are the root entry */ if (RtlIsRoot(N)) { /* Our child is now root, return him */ C->Parent = C; return C; } /* Find out who is referencing us and link to our child instead */ if (RtlIsLeftChild(N)) { /* N was a left child, so set its parent's left child as our child */ RtlLeftChild(RtlParent(N)) = C; } else { /* N was a right child, so set its parent's right child as our child */ RtlRightChild(RtlParent(N)) = C; } /* Finally, inherit our parent and splay the parent */ C->Parent = N->Parent; return RtlSplay(RtlParent(C)); }