/* * @implemented */ PVOID NTAPI RtlEnumerateGenericTableWithoutSplaying(IN PRTL_GENERIC_TABLE Table, IN OUT PVOID *RestartKey) { PRTL_SPLAY_LINKS FoundNode; /* Check if the table is empty */ if (RtlIsGenericTableEmpty(Table)) return NULL; /* Check if we have to restart */ if (!(*RestartKey)) { /* Then find the leftmost element */ FoundNode = Table->TableRoot; do { /* Get the left child */ FoundNode = RtlLeftChild(FoundNode); } while(RtlLeftChild(FoundNode)); /* Splay it */ *RestartKey = FoundNode; } else { /* Otherwise, try using the real successor */ FoundNode = RtlRealSuccessor(*RestartKey); if (FoundNode) *RestartKey = FoundNode; } /* Check if we found the node and return it */ return FoundNode ? &((PTABLE_ENTRY_HEADER)FoundNode)->UserData : NULL; }
VOID PrintTree ( IN PTREE_NODE Node ) { PRTL_SPLAY_LINKS Temp; ULONG LastValue; if (Node == NULL) { return; } // // find smallest value // while (RtlLeftChild(&Node->Links) != NULL) { Node = CONTAINING_RECORD(RtlLeftChild(&Node->Links), TREE_NODE, Links); } LastValue = Node->Data; //DbgPrint("%u\n", Node->Data); // // while the is a real successor we print the successor value // while ((Temp = RtlRealSuccessor(&Node->Links)) != NULL) { Node = CONTAINING_RECORD(Temp, TREE_NODE, Links); if (LastValue >= Node->Data) { DbgPrint("TestSplay Error\n"); } LastValue = Node->Data; //DbgPrint("%u\n", Node->Data); } }
PVOID RtlEnumerateGenericTableWithoutSplaying ( IN PRTL_GENERIC_TABLE Table, IN PVOID *RestartKey ) /*++ Routine Description: The function EnumerateGenericTableWithoutSplaying will return to the caller one-by-one the elements of of a table. The return value is a pointer to the user defined structure associated with the element. The input parameter RestartKey indicates if the enumeration should start from the beginning or should return the next element. If the are no more new elements to return the return value is NULL. As an example of its use, to enumerate all of the elements in a table the user would write: *RestartKey = NULL; for (ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey); ptr != NULL; ptr = EnumerateGenericTableWithoutSplaying(Table, &RestartKey)) { : } Arguments: Table - Pointer to the generic table to enumerate. RestartKey - Pointer that indicates if we should restart or return the next element. If the contents of RestartKey is NULL, the search will be started from the beginning. Return Value: PVOID - Pointer to the user data. --*/ { if (RtlIsGenericTableEmpty(Table)) { // // Nothing to do if the table is empty. // return NULL; } else { // // Will be used as the "iteration" through the tree. // PRTL_SPLAY_LINKS NodeToReturn; // // If the restart flag is true then go to the least element // in the tree. // if (*RestartKey == NULL) { // // We just loop until we find the leftmost child of the root. // for ( NodeToReturn = Table->TableRoot; RtlLeftChild(NodeToReturn); NodeToReturn = RtlLeftChild(NodeToReturn) ) { ; } *RestartKey = NodeToReturn; } else { // // The caller has passed in the previous entry found // in the table to enable us to continue the search. We call // RtlRealSuccessor to step to the next element in the tree. // NodeToReturn = RtlRealSuccessor(*RestartKey); if (NodeToReturn) { *RestartKey = NodeToReturn; } } // // If there actually is a next element in the enumeration // then the pointer to return is right after the list links. // return ((NodeToReturn)? ((PVOID)((PLIST_ENTRY)((PVOID)(NodeToReturn+1))+1)) :((PVOID)(NULL))); } }
PVOID RtlEnumerateGenericTable ( IN PRTL_GENERIC_TABLE Table, IN BOOLEAN Restart ) /*++ Routine Description: The function EnumerateGenericTable will return to the caller one-by-one the elements of of a table. The return value is a pointer to the user defined structure associated with the element. The input parameter Restart indicates if the enumeration should start from the beginning or should return the next element. If the are no more new elements to return the return value is NULL. As an example of its use, to enumerate all of the elements in a table the user would write: for (ptr = EnumerateGenericTable(Table,TRUE); ptr != NULL; ptr = EnumerateGenericTable(Table, FALSE)) { : } Arguments: Table - Pointer to the generic table to enumerate. Restart - Flag that if true we should start with the least element in the tree otherwise, return we return a pointer to the user data for the root and make the real successor to the root the new root. Return Value: PVOID - Pointer to the user data. --*/ { if (RtlIsGenericTableEmpty(Table)) { // // Nothing to do if the table is empty. // return NULL; } else { // // Will be used as the "iteration" through the tree. // PRTL_SPLAY_LINKS NodeToReturn; // // If the restart flag is true then go to the least element // in the tree. // if (Restart) { // // We just loop until we find the leftmost child of the root. // for ( NodeToReturn = Table->TableRoot; RtlLeftChild(NodeToReturn); NodeToReturn = RtlLeftChild(NodeToReturn) ) { ; } Table->TableRoot = RtlSplay(NodeToReturn); } else { // // The assumption here is that the root of the // tree is the last node that we returned. We // find the real successor to the root and return // it as next element of the enumeration. The // node that is to be returned is splayed (thereby // making it the root of the tree). Note that we // need to take care when there are no more elements. // NodeToReturn = RtlRealSuccessor(Table->TableRoot); if (NodeToReturn) { Table->TableRoot = RtlSplay(NodeToReturn); } } // // If there actually is a next element in the enumeration // then the pointer to return is right after the list links. // return ((NodeToReturn)? ((PVOID)((PLIST_ENTRY)((PVOID)(NodeToReturn+1))+1)) :((PVOID)(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 FsRtlDeleteKeyFromTunnelCache ( IN PTUNNEL Cache, IN ULONGLONG DirKey ) /*++ Routine Description: Deletes all entries in the cache associated with a specific directory Arguments: Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache() DirKey - the key value of the directory (presumeably being removed) Return Value: None --*/ { PRTL_SPLAY_LINKS Links; PRTL_SPLAY_LINKS SuccessorLinks; PTUNNEL_NODE Node; LIST_ENTRY FreePoolList; PRTL_SPLAY_LINKS LastLinks = NULL; BOOLEAN Splay = TRUE; PAGED_CODE(); // // If MaxEntries is 0 then tunneling is disabled. // if (TunnelMaxEntries == 0) return; InitializeListHead(&FreePoolList); #ifdef KEYVIEW DbgPrint("++\nDeleting key %08x%08x\n--\n", DblHex64(DirKey)); #endif ExAcquireFastMutex(&Cache->Mutex); Links = Cache->Cache; while (Links) { Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks); if (Node->DirKey > DirKey) { // // All nodes to the right are bigger, go left // Links = RtlLeftChild(&Node->CacheLinks); } else { if (Node->DirKey < DirKey) { if (LastLinks) { // // If we have previously seen a candidate node to delete // and we have now gone too far left - we know where to start. // break; } Links = RtlRightChild(&Node->CacheLinks); } else { // // Node is a candidate to be deleted, but we might have more nodes // to the left in the tree. Note this location and go on. // LastLinks = Links; Links = RtlLeftChild(&Node->CacheLinks); } } } for (Links = LastLinks; Links; Links = SuccessorLinks) { SuccessorLinks = RtlRealSuccessor(Links); Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks); if (Node->DirKey != DirKey) { // // Reached nodes which have a different key, so we're done // break; } FsRtlRemoveNodeFromTunnel(Cache, Node, &FreePoolList, &Splay); } #ifdef TUNNELTEST DbgPrint("FsRtlDeleteKeyFromTunnelCache:\n"); #ifndef KEYVIEW DumpTunnel(Cache); #endif #endif // TUNNELTEST ExReleaseFastMutex(&Cache->Mutex); // // Free delayed pool // FsRtlEmptyFreePoolList(&FreePoolList); return; }