Example #1
0
/*
* @implemented
*/
PRTL_SPLAY_LINKS
NTAPI
RtlRealPredecessor(PRTL_SPLAY_LINKS Links)
{
    PRTL_SPLAY_LINKS Child;

    /* Get the left child */
    Child = RtlLeftChild(Links);
    if (Child)
    {
        /* Get right-most child */
        while (RtlRightChild(Child)) Child = RtlRightChild(Child);
        return Child;
    }

    /* We don't have a left child, keep looping until we find our parent */
    Child = Links;
    while (RtlIsLeftChild(Child)) Child = RtlParent(Child);

    /* The parent should be a right child, return the real predecessor */
    if (RtlIsRightChild(Child)) return RtlParent(Child);

    /* The parent isn't a right child, so no real precessor for us */
    return NULL;
}
Example #2
0
PRTL_SPLAY_LINKS
RtlSubtreePredecessor (
    IN PRTL_SPLAY_LINKS Links
    )

/*++

Routine Description:

    The SubtreePredecessor function takes as input a pointer to a splay link
    in a tree and returns a pointer to the predecessor of the input node of
    the subtree rooted at the input node.  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 subtree

--*/

{
    PRTL_SPLAY_LINKS Ptr;

    //
    //  check to see if there is a left subtree to the input link
    //  if there is then the subtree 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;

    }

    //
    //  otherwise we are do not have a subtree predecessor so we simply return
    //  NULL
    //

    return NULL;

}
Example #3
0
/*
* @implemented
*/
PRTL_SPLAY_LINKS
NTAPI
RtlSubtreePredecessor(IN PRTL_SPLAY_LINKS Links)
{
    PRTL_SPLAY_LINKS Child;

    /* Get the left child */
    Child = RtlLeftChild(Links);
    if (!Child) return NULL;

    /* Get right-most child */
    while (RtlRightChild(Child)) Child = RtlRightChild(Child);

    /* Return it */
    return Child;
}
Example #4
0
PFCB
NTAPI
FatFindFcb(PFAT_IRP_CONTEXT IrpContext,
           PRTL_SPLAY_LINKS *RootNode,
           PSTRING AnsiName,
           PBOOLEAN IsDosName)
{
    PFCB_NAME_LINK Node;
    FSRTL_COMPARISON_RESULT Comparison;
    PRTL_SPLAY_LINKS Links;

    Links = *RootNode;

    while (Links)
    {
        Node = CONTAINING_RECORD(Links, FCB_NAME_LINK, Links);

        /* Compare the prefix */
        if (*(PUCHAR)Node->Name.Ansi.Buffer != *(PUCHAR)AnsiName->Buffer)
        {
            if (*(PUCHAR)Node->Name.Ansi.Buffer < *(PUCHAR)AnsiName->Buffer)
                Comparison = LessThan;
            else
                Comparison = GreaterThan;
        }
        else
        {
            /* Perform real comparison */
            Comparison = FatiCompareNames(&Node->Name.Ansi, AnsiName);
        }

        /* Do they match? */
        if (Comparison == GreaterThan)
        {
            /* No, it's greater, go to the left child */
            Links = RtlLeftChild(Links);
        }
        else if (Comparison == LessThan)
        {
            /* No, it's lesser, go to the right child */
            Links = RtlRightChild(Links);
        }
        else
        {
            /* Exact match, balance the tree */
            *RootNode = RtlSplay(Links);

            /* Save type of the name, if needed */
            if (IsDosName)
                *IsDosName = Node->IsDosName;

            /* Return the found fcb */
            return Node->Fcb;
        }
    }

    /* Nothing found */
    return NULL;
}
Example #5
0
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);
        }
    }
}
Example #6
0
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) );
}
Example #7
0
PFCB
FatFindFcb (
    IN PIRP_CONTEXT IrpContext,
    IN OUT PRTL_SPLAY_LINKS *RootNode,
    IN PSTRING Name,
    OUT PBOOLEAN FileNameDos OPTIONAL
    )

/*++

Routine Description:

    This routine searches either the Oem or Unicode splay tree looking
    for an Fcb with the specified name.  In the case the Fcb is found,
    rebalance the tree.

Arguments:

    RootNode - Supplies the parent to search.

    Name - If present, search the Oem tree.

    UnicodeName - If present, search the Unicode tree.

Return Value:

    PFCB - The Fcb, or NULL if none was found.

--*/

{
    COMPARISON Comparison;
    PFILE_NAME_NODE Node;
    PRTL_SPLAY_LINKS Links;

    PAGED_CODE();

    Links = *RootNode;

    while (Links != NULL) {

        Node = CONTAINING_RECORD(Links, FILE_NAME_NODE, Links);

        //
        //  Compare the prefix in the tree with the full name
        //

        Comparison = CompareNames(&Node->Name.Oem, Name);

        //
        //  See if they don't match
        //

        if (Comparison == IsGreaterThan) {

            //
            //  The prefix is greater than the full name
            //  so we go down the left child
            //

            Links = RtlLeftChild(Links);

            //
            //  And continue searching down this tree
            //

        } else if (Comparison == IsLessThan) {

            //
            //  The prefix is less than the full name
            //  so we go down the right child
            //

            Links = RtlRightChild(Links);

            //
            //  And continue searching down this tree
            //

        } else {

            //
            //  We found it.
            //
            //  Splay the tree and save the new root.
            //

            *RootNode = RtlSplay(Links);

            //
            //  Tell the caller what kind of name we hit
            //

            if (FileNameDos) {

                *FileNameDos = Node->FileNameDos;
            }

            return Node->Fcb;
        }
    }

    //
    //  We didn't find the Fcb.
    //

    return NULL;
}
Example #8
0
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));

}
BOOLEAN
xixfs_NLInsertNameLinkIgnoreCase (
	IN PXIXFS_IRPCONTEXT IrpContext,
	IN PRTL_SPLAY_LINKS *RootNode,
	IN PXIXFS_LCB NameLink
)
{
    FSRTL_COMPARISON_RESULT Comparison;
    PXIXFS_LCB Node;

    PAGED_CODE();
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO),
		("Enter xixfs_NLInsertNameLink \n"));
    //
    //  Check inputs.
    //

    ASSERT_IRPCONTEXT( IrpContext );

    RtlInitializeSplayLinks( &NameLink->IgnoreCaseLinks );

    //
    //  If we are the first entry in the tree, just become the root.
    //

    if (*RootNode == NULL) {

        *RootNode = &NameLink->IgnoreCaseLinks;

        return TRUE;
    }

    Node = CONTAINING_RECORD( *RootNode, XIXFS_LCB, IgnoreCaseLinks );

    while (TRUE) {

        //
        //  Compare the prefix in the tree with the prefix we want
        //  to insert.
        //

        Comparison = xixfs_FCBTLBFullCompareNames( IrpContext, &Node->IgnoreCaseFileName, &NameLink->IgnoreCaseFileName );

        //
        //  If we found the entry, return immediately.
        //

        if (Comparison == EqualTo) { return FALSE; }

        //
        //  If the tree prefix is greater than the new prefix then
        //  we go down the left subtree
        //

        if (Comparison == GreaterThan) {

            //
            //  We want to go down the left subtree, first check to see
            //  if we have a left subtree
            //

            if (RtlLeftChild( &Node->IgnoreCaseLinks ) == NULL) {

                //
                //  there isn't a left child so we insert ourselves as the
                //  new left child
                //

                RtlInsertAsLeftChild( &Node->IgnoreCaseLinks, &NameLink->IgnoreCaseLinks );

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a left child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlLeftChild( &Node->IgnoreCaseLinks ),
                                          XIXFS_LCB,
                                          IgnoreCaseLinks );
            }

        } else {

            //
            //  The tree prefix is either less than or a proper prefix
            //  of the new string.  We treat both cases as less than when
            //  we do insert.  So we want to go down the right subtree,
            //  first check to see if we have a right subtree
            //

            if (RtlRightChild( &Node->IgnoreCaseLinks ) == NULL) {

                //
                //  These isn't a right child so we insert ourselves as the
                //  new right child
                //

                RtlInsertAsRightChild( &Node->IgnoreCaseLinks, &NameLink->IgnoreCaseLinks );

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a right child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlRightChild( &Node->IgnoreCaseLinks ),
                                          XIXFS_LCB,
                                          IgnoreCaseLinks );
            }
        }
    }
	
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO),
		("Exit xixfs_NLInsertNameLink \n"));
    return TRUE;
}
Example #10
0
TABLE_SEARCH_RESULT
NTAPI
RtlpFindGenericTableNodeOrParent(IN PRTL_GENERIC_TABLE Table,
                                 IN PVOID Buffer,
                                 OUT PRTL_SPLAY_LINKS *NodeOrParent)
{
    PRTL_SPLAY_LINKS CurrentNode, ChildNode;
    RTL_GENERIC_COMPARE_RESULTS Result;

    /* Quick check to see if the table is empty */
    if (RtlIsGenericTableEmpty(Table))
    {
        *NodeOrParent = NULL;
        return TableEmptyTree;
    }

    /* Set the current node */
    CurrentNode = Table->TableRoot;

    /* Start compare loop */
    while (TRUE)
    {
        /* Do the compare */
        Result = Table->CompareRoutine(Table,
                                       Buffer,
                                       &((PTABLE_ENTRY_HEADER)CurrentNode)->
                                       UserData);
        if (Result == GenericLessThan)
        {
            /* We're less, check if this is the left child */
            if ((ChildNode = RtlLeftChild(CurrentNode)))
            {
                /* Continue searching from this node */
                CurrentNode = ChildNode;
            }
            else
            {
                /* Otherwise, the element isn't in this tree */
                *NodeOrParent = CurrentNode;
                return TableInsertAsLeft;
            }
        }
        else if (Result == GenericGreaterThan)
        {
            /* We're more, check if this is the right child */
            if ((ChildNode = RtlRightChild(CurrentNode)))
            {
                /* Continue searching from this node */
                CurrentNode = ChildNode;
            }
            else
            {
                /* Otherwise, the element isn't in this tree */
                *NodeOrParent = CurrentNode;
                return TableInsertAsRight;
            }
        }
        else
        {
            /* We should've found the node */
            ASSERT(Result == GenericEqual);

            /* Return node found */
            *NodeOrParent = CurrentNode;
            return TableFoundNode;
        }
    }
}
Example #11
0
BOOLEAN
CdInsertNameLink (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PRTL_SPLAY_LINKS *RootNode,
    _In_ PNAME_LINK NameLink
    )

/*++

Routine Description:

    This routine will insert a name in the splay tree pointed to
    by RootNode.

    The name could already exist in this tree for a case-insensitive tree.
    In that case we simply return FALSE and do nothing.

Arguments:

    RootNode - Supplies a pointer to the table.

    NameLink - Contains the new link to enter.

Return Value:

    BOOLEAN - TRUE if the name is inserted, FALSE otherwise.

--*/

{
    FSRTL_COMPARISON_RESULT Comparison;
    PNAME_LINK Node;

    PAGED_CODE();

    RtlInitializeSplayLinks( &NameLink->Links );

    //
    //  If we are the first entry in the tree, just become the root.
    //

    if (*RootNode == NULL) {

        *RootNode = &NameLink->Links;

        return TRUE;
    }

    Node = CONTAINING_RECORD( *RootNode, NAME_LINK, Links );

    while (TRUE) {

        //
        //  Compare the prefix in the tree with the prefix we want
        //  to insert.
        //

        Comparison = CdFullCompareNames( IrpContext, &Node->FileName, &NameLink->FileName );

        //
        //  If we found the entry, return immediately.
        //

        if (Comparison == EqualTo) { return FALSE; }

        //
        //  If the tree prefix is greater than the new prefix then
        //  we go down the left subtree
        //

        if (Comparison == GreaterThan) {

            //
            //  We want to go down the left subtree, first check to see
            //  if we have a left subtree
            //

            if (RtlLeftChild( &Node->Links ) == NULL) {

                //
                //  there isn't a left child so we insert ourselves as the
                //  new left child
                //

                RtlInsertAsLeftChild( &Node->Links, &NameLink->Links );

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a left child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlLeftChild( &Node->Links ),
                                          NAME_LINK,
                                          Links );
            }

        } else {

            //
            //  The tree prefix is either less than or a proper prefix
            //  of the new string.  We treat both cases as less than when
            //  we do insert.  So we want to go down the right subtree,
            //  first check to see if we have a right subtree
            //

            if (RtlRightChild( &Node->Links ) == NULL) {

                //
                //  These isn't a right child so we insert ourselves as the
                //  new right child
                //

                RtlInsertAsRightChild( &Node->Links, &NameLink->Links );

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a right child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlRightChild( &Node->Links ),
                                          NAME_LINK,
                                          Links );
            }
        }
    }

    return TRUE;
}
Example #12
0
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;
}
Example #13
0
VOID
NTAPI
FatInsertName(IN PFAT_IRP_CONTEXT IrpContext,
              IN PRTL_SPLAY_LINKS *RootNode,
              IN PFCB_NAME_LINK Name)
{
    PFCB_NAME_LINK NameLink;
    FSRTL_COMPARISON_RESULT Comparison;

    /* Initialize the splay links */
    RtlInitializeSplayLinks(&Name->Links);

    /* Is this the first entry? */
    if (*RootNode == NULL)
    {
        /* Yes, become root and return */
        *RootNode = &Name->Links;
        return;
    }

    /* Get the name link */
    NameLink = CONTAINING_RECORD(*RootNode, FCB_NAME_LINK, Links);
    while (TRUE)
    {
        /* Compare the prefix */
        if (*(PUCHAR)NameLink->Name.Ansi.Buffer != *(PUCHAR)&Name->Name.Ansi.Buffer)
        {
            if (*(PUCHAR)NameLink->Name.Ansi.Buffer < *(PUCHAR)&Name->Name.Ansi.Buffer)
                Comparison = LessThan;
            else
                Comparison = GreaterThan;
        }
        else
        {
            /* Perform real comparison */
            Comparison = FatiCompareNames(&NameLink->Name.Ansi, &Name->Name.Ansi);
        }

        /* Check the bad case first */
        if (Comparison == EqualTo)
        {
            /* Must not happen */
            ASSERT(FALSE);
        }

        /* Check comparison result */
        if (Comparison == GreaterThan)
        {
            /* Go to the left child */
            if (!RtlLeftChild(&NameLink->Links))
            {
                /* It's absent, insert here and break */
                RtlInsertAsLeftChild(&NameLink->Links, &Name->Links);
                break;
            }
            else
            {
                /* It's present, go inside it */
                NameLink = CONTAINING_RECORD(RtlLeftChild(&NameLink->Links),
                                             FCB_NAME_LINK,
                                             Links);
            }
        }
        else
        {
            /* Go to the right child */
            if (!RtlRightChild(&NameLink->Links))
            {
                /* It's absent, insert here and break */
                RtlInsertAsRightChild(&NameLink->Links, &Name->Links);
                break;
            }
            else
            {
                /* It's present, go inside it */
                NameLink = CONTAINING_RECORD(RtlRightChild(&NameLink->Links),
                                             FCB_NAME_LINK,
                                             Links);
            }
        }
    }
}
Example #14
0
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
    }
}
Example #15
0
/*
* @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;
}
Example #16
0
static
SEARCH_RESULT
FindNodeOrParent(
    IN PRTL_GENERIC_TABLE Table,
    IN PVOID Buffer,
    OUT PRTL_SPLAY_LINKS *NodeOrParent
    )

/*++

Routine Description:

    This routine is used by all of the routines of the generic
    table package to locate the a node in the tree.  It will
    find and return (via the NodeOrParent parameter) the node
    with the given key, or if that node is not in the tree it
    will return (via the NodeOrParent parameter) a pointer to
    the parent.

Arguments:

    Table - The generic table to search for the key.

    Buffer - Pointer to a buffer holding the key.  The table
             package doesn't examine the key itself.  It leaves
             this up to the user supplied compare routine.

    NodeOrParent - Will be set to point to the node containing the
                   the key or what should be the parent of the node
                   if it were in the tree.  Note that this will *NOT*
                   be set if the search result is EmptyTree.

Return Value:

    SEARCH_RESULT - EmptyTree: The tree was empty.  NodeOrParent
                               is *not* altered.

                    FoundNode: A node with the key is in the tree.
                               NodeOrParent points to that node.

                    InsertAsLeft: Node with key was not found.
                                  NodeOrParent points to what would be
                                  parent.  The node would be the left
                                  child.

                    InsertAsRight: Node with key was not found.
                                   NodeOrParent points to what would be
                                   parent.  The node would be the right
                                   child.

--*/



{

    if (RtlIsGenericTableEmpty(Table)) {

        return EmptyTree;

    } else {

        //
        // Used as the iteration variable while stepping through
        // the generic table.
        //
        PRTL_SPLAY_LINKS NodeToExamine = Table->TableRoot;

        //
        // Just a temporary.  Hopefully a good compiler will get
        // rid of it.
        //
        PRTL_SPLAY_LINKS Child;

        //
        // Holds the value of the comparasion.
        //
        RTL_GENERIC_COMPARE_RESULTS Result;

        while (TRUE) {

            //
            // Compare the buffer with the key in the tree element.
            //

            Result = Table->CompareRoutine(
                         Table,
                         Buffer,
                         ((PLIST_ENTRY)((PVOID)(NodeToExamine+1)))+1
                         );

            if (Result == GenericLessThan) {

                if (Child = RtlLeftChild(NodeToExamine)) {

                    NodeToExamine = Child;

                } else {

                    //
                    // Node is not in the tree.  Set the output
                    // parameter to point to what would be its
                    // parent and return which child it would be.
                    //

                    *NodeOrParent = NodeToExamine;
                    return InsertAsLeft;

                }

            } else if (Result == GenericGreaterThan) {

                if (Child = RtlRightChild(NodeToExamine)) {

                    NodeToExamine = Child;

                } else {

                    //
                    // Node is not in the tree.  Set the output
                    // parameter to point to what would be its
                    // parent and return which child it would be.
                    //

                    *NodeOrParent = NodeToExamine;
                    return InsertAsRight;

                }


            } else {

                //
                // Node is in the tree (or it better be because of the
                // assert).  Set the output parameter to point to
                // the node and tell the caller that we found the node.
                //

                ASSERT(Result == GenericEqual);
                *NodeOrParent = NodeToExamine;
                return FoundNode;

            }

        }

    }

}
Example #17
0
PNAME_LINK
CdFindNameLink (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PRTL_SPLAY_LINKS *RootNode,
    _In_ PUNICODE_STRING Name
    )

/*++

Routine Description:

    This routine searches through a splay link tree looking for a match for the
    input name.  If we find the corresponding name we will rebalance the
    tree.

Arguments:

    RootNode - Supplies the parent to search.

    Name - This is the name to search for.  Note if we are doing a case
        insensitive search the name would have been upcased already.

Return Value:

    PNAME_LINK - The name link found or NULL if there is no match.

--*/

{
    FSRTL_COMPARISON_RESULT Comparison;
    PNAME_LINK Node;
    PRTL_SPLAY_LINKS Links;

    PAGED_CODE();

    Links = *RootNode;

    while (Links != NULL) {

        Node = CONTAINING_RECORD( Links, NAME_LINK, Links );

        //
        //  Compare the prefix in the tree with the full name
        //

        Comparison = CdFullCompareNames( IrpContext, &Node->FileName, Name );

        //
        //  See if they don't match
        //

        if (Comparison == GreaterThan) {

            //
            //  The prefix is greater than the full name
            //  so we go down the left child
            //

            Links = RtlLeftChild( Links );

            //
            //  And continue searching down this tree
            //

        } else if (Comparison == LessThan) {

            //
            //  The prefix is less than the full name
            //  so we go down the right child
            //

            Links = RtlRightChild( Links );

            //
            //  And continue searching down this tree
            //

        } else {

            //
            //  We found it.
            //
            //  Splay the tree and save the new root.
            //

            *RootNode = RtlSplay( Links );

            return Node;
        }
    }

    //
    //  We didn't find the Link.
    //

    return NULL;
}
Example #18
0
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");
}
Example #19
0
PTREE_NODE
TreeInsert (
    IN PTREE_NODE Root,
    IN PTREE_NODE Node
    )

{
    PRTL_SPLAY_LINKS Temp;

    if (Root == NULL) {

        //DbgPrint("Add as root %u\n", Node->Data);
        return Node;

    }

    while (TRUE) {

        if (Root->Data == Node->Data) {

            //DbgPrint("Delete %u\n", Node->Data);

            Temp = RtlDelete(&Root->Links);
            if (Temp == NULL) {
                return NULL;
            } else {
                return CONTAINING_RECORD(Temp, TREE_NODE, Links);
            }

        }

        if (Root->Data < Node->Data) {

            //
            //  Go right
            //

            if (RtlRightChild(&Root->Links) == NULL) {

                //DbgPrint("Add as right child %u\n", Node->Data);
                RtlInsertAsRightChild(&Root->Links, &Node->Links);
                return CONTAINING_RECORD(RtlSplay(&Node->Links), TREE_NODE, Links);

            } else {

                Root = CONTAINING_RECORD(RtlRightChild(&Root->Links), TREE_NODE, Links);

            }

        } else {

            //
            //  Go Left
            //

            if (RtlLeftChild(&Root->Links) == NULL) {

                //DbgPrint("Add as left child %u\n", Node->Data);
                RtlInsertAsLeftChild(&Root->Links, &Node->Links);
                return CONTAINING_RECORD(RtlSplay(&Node->Links), TREE_NODE, Links);

            } else {

                Root = CONTAINING_RECORD(RtlLeftChild(&Root->Links), TREE_NODE, Links);

            }

        }
    }
}
Example #20
0
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;
}
Example #21
0
VOID
FatInsertName (
    IN PIRP_CONTEXT IrpContext,
    IN PRTL_SPLAY_LINKS *RootNode,
    IN PFILE_NAME_NODE Name
    )

/*++

Routine Description:

    This routine will insert a name in the splay tree pointed to
    by RootNode.

    The name must not already exist in the splay tree.

Arguments:

    RootNode - Supplies a pointer to the table.

    Name - Contains the New name to enter.

Return Value:

    None.

--*/

{
    COMPARISON Comparison;
    PFILE_NAME_NODE Node;

    RtlInitializeSplayLinks(&Name->Links);

    //
    //  If we are the first entry in the tree, just become the root.
    //

    if (*RootNode == NULL) {

        *RootNode = &Name->Links;

        return;
    }

    Node = CONTAINING_RECORD( *RootNode, FILE_NAME_NODE, Links );

    while (TRUE) {

        //
        //  Compare the prefix in the tree with the prefix we want
        //  to insert.  Note that Oem here doesn't mean anything.
        //

        Comparison = CompareNames(&Node->Name.Oem, &Name->Name.Oem);

        //
        //  We should never find the name in the table already.
        //

        if (Comparison == IsEqual) {

            FatBugCheck( (ULONG)*RootNode, (ULONG)Name, (ULONG)Node );
        }

        //
        //  If the tree prefix is greater than the new prefix then
        //  we go down the left subtree
        //

        if (Comparison == IsGreaterThan) {

            //
            //  We want to go down the left subtree, first check to see
            //  if we have a left subtree
            //

            if (RtlLeftChild(&Node->Links) == NULL) {

                //
                //  there isn't a left child so we insert ourselves as the
                //  new left child
                //

                RtlInsertAsLeftChild(&Node->Links, &Name->Links);

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a left child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlLeftChild(&Node->Links),
                                          FILE_NAME_NODE,
                                          Links );
            }

        } else {

            //
            //  The tree prefix is either less than or a proper prefix
            //  of the new string.  We treat both cases a less than when
            //  we do insert.  So we want to go down the right subtree,
            //  first check to see if we have a right subtree
            //

            if (RtlRightChild(&Node->Links) == NULL) {

                //
                //  These isn't a right child so we insert ourselves as the
                //  new right child
                //

                RtlInsertAsRightChild(&Node->Links, &Name->Links);

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a right child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlRightChild(&Node->Links),
                                          FILE_NAME_NODE,
                                          Links );
            }

        }
    }

    return;
}
Example #22
0
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
    )
/*++

Routine Description:

    Looks up the key

        DirKey ## Name

    in the tunnel cache and removes it. As a side effect, this routine will initiate
    expiration of the aged entries in the tunnel cache.

Arguments:

    Cache - a tunnel cache initialized by FsRtlInitializeTunnelCache()

    DirKey - the key value of the directory the name will appear in

    Name - the name of the entry

    ShortName - return string to hold the short name of the tunneled file. Must
        already be allocated and large enough for max 8.3 name

    LongName -  return string to hold the long name of the tunneled file. If
        already allocated, may be grown if not large enough. Caller is
        responsible for noticing this and freeing data regardless of return value.

    DataLength - provides the length of the buffer avaliable to hold the
        tunneling information, returns the size of the tunneled information
        read out

Return Value:

    Boolean true if found, false otherwise

--*/
{
    PRTL_SPLAY_LINKS Links;
    PTUNNEL_NODE Node;
    LONG Compare;
    LIST_ENTRY FreePoolList;

    BOOLEAN Status = FALSE;

    PAGED_CODE();

    //
    //  If MaxEntries is 0 then tunneling is disabled.
    //

    if (TunnelMaxEntries == 0) return FALSE;

    InitializeListHead(&FreePoolList);

#ifdef KEYVIEW
    DbgPrint("++\nSearching for %wZ , %08x%08x\n--\n", Name, DblHex64(DirKey));
#endif

    ExAcquireFastMutex(&Cache->Mutex);

    //
    //  Expire aged entries first so we don't grab old data
    //

    FsRtlPruneTunnelCache(Cache, &FreePoolList);

    Links = Cache->Cache;

    while (Links) {

        Node = CONTAINING_RECORD(Links, TUNNEL_NODE, CacheLinks);

        Compare = FsRtlCompareNodeAndKey(Node, DirKey, Name);

        if (Compare > 0) {

            Links = RtlLeftChild(&Node->CacheLinks);

        } else {

            if (Compare < 0) {

                Links = RtlRightChild(&Node->CacheLinks);

            } else {

                //
                //  Found tunneling information
                //

#if defined(TUNNELTEST) || defined(KEYVIEW)
                DbgPrint("FsRtlFindInTunnelCache:\n");
                DumpNode(Node, 1);
#ifndef KEYVIEW
                DumpTunnel(Cache);
#endif
#endif // TUNNELTEST

                break;
            }
        }
    }

    try {

        if (Links) {
    
            //
            //  Copy node data into caller's area
            //
    
            ASSERT(ShortName->MaximumLength >= (8+1+3)*sizeof(WCHAR));
            RtlCopyUnicodeString(ShortName, &Node->ShortName);
    
            if (LongName->MaximumLength >= Node->LongName.Length) {
    
                RtlCopyUnicodeString(LongName, &Node->LongName);
    
            } else {
    
                //
                //  Need to allocate more memory for the long name
                //
    
                LongName->Buffer = FsRtlAllocatePoolWithTag(PagedPool, Node->LongName.Length, '4nuT');
                LongName->Length = LongName->MaximumLength = Node->LongName.Length;
    
                RtlCopyMemory(LongName->Buffer, Node->LongName.Buffer, Node->LongName.Length);
            }
    
            ASSERT(*DataLength >= Node->TunnelDataLength);
            RtlCopyMemory(Data, Node->TunnelData, Node->TunnelDataLength);
            *DataLength = Node->TunnelDataLength;
    
            Status = TRUE;
        }

    } finally {

        ExReleaseFastMutex(&Cache->Mutex);
    
        FsRtlEmptyFreePoolList(&FreePoolList);
    }
    
    return Status;
}
PXIXFS_LCB
xixfs_NLFindNameLinkIgnoreCase (
    IN PXIXFS_IRPCONTEXT IrpContext,
    IN PRTL_SPLAY_LINKS *RootNode,
    IN PUNICODE_STRING Name
    )
{
	FSRTL_COMPARISON_RESULT Comparison;
	PXIXFS_LCB Node;
	PRTL_SPLAY_LINKS Links;

	PAGED_CODE();
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO),
		("Enter xixfs_NLFindNameLink \n"));

	Links = *RootNode;

	while (Links != NULL) {

		Node = CONTAINING_RECORD( Links, XIXFS_LCB, IgnoreCaseLinks );

		//
		//  Compare the prefix in the tree with the full name
		//

		Comparison = xixfs_FCBTLBFullCompareNames( IrpContext, &Node->IgnoreCaseFileName, Name );

		//
		//  See if they don't match
		//

		if (Comparison == GreaterThan) {

			//
			//  The prefix is greater than the full name
			//  so we go down the left child
			//

			Links = RtlLeftChild( Links );

			//
			//  And continue searching down this tree
			//

		} else if (Comparison == LessThan) {

			//
			//  The prefix is less than the full name
			//  so we go down the right child
			//

			Links = RtlRightChild( Links );

			//
			//  And continue searching down this tree
			//

		} else {

			//
			//  We found it.
			//
			//  Splay the tree and save the new root.
			//

			*RootNode = RtlSplay( Links );

			return Node;
		}
	}

	//
	//  We didn't find the Link.
	//
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO),
		("Exit xixfs_NLFindNameLink \n"));
	return NULL;
}
Example #24
0
/*
 * @implemented
 */
PUNICODE_PREFIX_TABLE_ENTRY
NTAPI
RtlFindUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable,
                     PUNICODE_STRING FullName,
                     ULONG CaseInsensitiveIndex)
{
    ULONG NameCount;
    PUNICODE_PREFIX_TABLE_ENTRY CurrentEntry, PreviousEntry, Entry, NextEntry;
    PRTL_SPLAY_LINKS SplayLinks;
    RTL_GENERIC_COMPARE_RESULTS Result;

    DPRINT("RtlFindUnicodePrefix(): Table %p, FullName %wZ, "
        "CaseInsensitive %lu\n", PrefixTable, FullName, CaseInsensitiveIndex);

    /* Find out how many names there are */
    NameCount = ComputeUnicodeNameLength(FullName);

    /* Find the right spot where to start looking for this entry */
    PreviousEntry = (PUNICODE_PREFIX_TABLE_ENTRY)PrefixTable;
    CurrentEntry = PreviousEntry->NextPrefixTree;
    while (CurrentEntry->NameLength > (CSHORT)NameCount)
    {
        /* Not a match, move to the next entry */
        PreviousEntry = CurrentEntry;
        CurrentEntry = CurrentEntry->NextPrefixTree;
    }

    /* Loop every entry which has valid entries */
    while (CurrentEntry->NameLength)
    {
        /* Get the splay links and loop */
        SplayLinks = &CurrentEntry->Links;
        while (SplayLinks)
        {
            /* Get the entry */
            Entry = CONTAINING_RECORD(SplayLinks,
                                      UNICODE_PREFIX_TABLE_ENTRY,
                                      Links);

            /* Do the comparison */
            Result = CompareUnicodeStrings(Entry->Prefix, FullName, 0);
            if (Result == GenericGreaterThan)
            {
                /* Prefix is greater, so restart on the left child */
                SplayLinks = RtlLeftChild(SplayLinks);
                continue;
            }
            else if (Result == GenericLessThan)
            {
                /* Prefix is smaller, so restart on the right child */
                SplayLinks = RtlRightChild(SplayLinks);
                continue;
            }

            /*
             * We have a match, check if this was a case-sensitive search
             * NOTE: An index of 0 means case-insensitive(ie, we'll be case
             * insensitive since index 0, ie, all the time)
             */
            if (!CaseInsensitiveIndex)
            {
                /*
                 * Check if this entry was a child. We need to return the root,
                 * so if this entry was a child, we'll splay the tree and get
                 * the root, and set the current entry as a child.
                 */
                if (Entry->NodeTypeCode == PFX_NTC_CHILD)
                {
                    /* Get the next entry */
                    NextEntry = CurrentEntry->NextPrefixTree;

                    /* Make the current entry become a child */
                    CurrentEntry->NodeTypeCode = PFX_NTC_CHILD;
                    CurrentEntry->NextPrefixTree = NULL;

                    /* Splay the tree */
                    SplayLinks = RtlSplay(&Entry->Links);

                    /* Get the new root entry */
                    Entry = CONTAINING_RECORD(SplayLinks,
                                              UNICODE_PREFIX_TABLE_ENTRY,
                                              Links);

                    /* Set it as a root entry */
                    Entry->NodeTypeCode = PFX_NTC_ROOT;

                    /* Add it to the root entries list */
                    PreviousEntry->NextPrefixTree = Entry;
                    Entry->NextPrefixTree = NextEntry;
                }

                /* Return the entry */
                return Entry;
            }

            /* We'll do a case-sensitive search if we've reached this point */
            NextEntry = Entry;
            do
            {
                /* Do the case-sensitive search */
                Result = CompareUnicodeStrings(NextEntry->Prefix,
                                               FullName,
                                               CaseInsensitiveIndex);
                if ((Result != GenericLessThan) &&
                    (Result != GenericGreaterThan))
                {
                    /* This is a positive match, return it */
                    return NextEntry;
                }

                /* No match yet, continue looping the circular list */
                NextEntry = NextEntry->CaseMatch;
            } while (NextEntry != Entry);

            /*
             * If we got here, then we found a non-case-sensitive match, but
             * we need to find a case-sensitive match, so we'll just keep
             * searching the next tree (NOTE: we need to break out for this).
             */
            break;
        }

        /* Splay links exhausted, move to next entry */
        PreviousEntry = CurrentEntry;
        CurrentEntry = CurrentEntry->NextPrefixTree;
    }

    /* If we got here, nothing was found */
    return NULL;
}
Example #25
0
VOID
RtlDeleteNoSplay (
    IN PRTL_SPLAY_LINKS Links,
    IN OUT PRTL_SPLAY_LINKS *Root
    )

/*++

Routine Description:

    The Delete function takes as input a pointer to a splay link in a tree,
    a pointer to the callers pointer to the tree and deletes that node from
    the tree.  The caller's pointer is updated upon return.  If the tree is
    now empty, the value is NULL.

    Unfortunately, the original RtlDelete() always splays and this is not
    always a desireable side-effect.

Arguments:

    Links - Supplies a pointer to a splay link in a tree.

    Root - Pointer to the callers pointer to the root 

Return Value:

    None

--*/

{
    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);

        if (RtlIsRoot(Links)) {

            //
            //  If we're switching with the root of the tree, fix the
            //  caller's root pointer
            //

            *Root = Predecessor;
        }

        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.
    //

    if ((RtlLeftChild(Links) == NULL) && (RtlRightChild(Links) == NULL)) {

        //
        //  Links has no children, if it is the root then set root to NULL
        //

        if (RtlIsRoot(Links)) {

            *Root = NULL;

            return;
        }

        //
        //  Links as not children and is not the root, so to the parent's
        //  child pointer to NULL.
        //

        ParentChildPtr = ParentsChildPointerAddress(Links);
        *ParentChildPtr = NULL;

        return;
    }

    //
    //  otherwise Links has one child.  If it is the root then make the child
    //  the new root, otherwise link together the child and 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;

        *Root = Child;

        return;
    }

    //
    //  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.
    //

    ParentChildPtr = ParentsChildPointerAddress(Links);
    *ParentChildPtr = Child;
    Child->Parent = Links->Parent;

    return;
}
Example #26
0
/*
 * @implemented
 */
BOOLEAN
NTAPI
RtlInsertUnicodePrefix(PUNICODE_PREFIX_TABLE PrefixTable,
                       PUNICODE_STRING Prefix,
                       PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry)
{
    PUNICODE_PREFIX_TABLE_ENTRY CurrentEntry, PreviousEntry, Entry, NextEntry;
    ULONG NameCount;
    RTL_GENERIC_COMPARE_RESULTS Result;
    PRTL_SPLAY_LINKS SplayLinks;

    DPRINT("RtlInsertUnicodePrefix(): Table %p, Prefix %wZ, "
        "TableEntry %p\n", PrefixTable, Prefix, PrefixTableEntry);

    /* Find out how many names there are */
    NameCount = ComputeUnicodeNameLength(Prefix);

    /* Set up the initial entry data */
    PrefixTableEntry->NameLength = (CSHORT)NameCount;
    PrefixTableEntry->Prefix = Prefix;
    RtlInitializeSplayLinks(&PrefixTableEntry->Links);

    /* Find the right spot where to insert this entry */
    PreviousEntry = (PUNICODE_PREFIX_TABLE_ENTRY)PrefixTable;
    CurrentEntry = PreviousEntry->NextPrefixTree;
    while (CurrentEntry->NameLength > (CSHORT)NameCount)
    {
        /* Not a match, move to the next entry */
        PreviousEntry = CurrentEntry;
        CurrentEntry = CurrentEntry->NextPrefixTree;
    }

    /* Check if we did find a tree by now */
    if (CurrentEntry->NameLength != (CSHORT)NameCount)
    {
        /* We didn't, so insert a new entry in the list */
        PreviousEntry->NextPrefixTree = PrefixTableEntry;
        PrefixTableEntry->NextPrefixTree = CurrentEntry;

        /* This is now a root entry with case match */
        PrefixTableEntry->NodeTypeCode = PFX_NTC_ROOT;
        PrefixTableEntry->CaseMatch = PrefixTableEntry;

        /* Quick return */
        return TRUE;
    }

    /* We found a tree, so start the search loop */
    Entry = CurrentEntry;
    while (TRUE)
    {
        /* Do a case-insensitive comparison to find out the match level */
        Result = CompareUnicodeStrings(Entry->Prefix, Prefix, 0);
        if (Result == GenericEqual)
        {
            /* We have a match, start doing a case-sensitive search */
            NextEntry = Entry;

            /* Search the circular case-match list */
            do
            {
                /* Check if we found a match */
                if (CompareUnicodeStrings(NextEntry->Prefix, Prefix, -1) ==
                    (GenericEqual))
                {
                    /* We must fail the insert: it already exists */
                    return FALSE;
                }

                /* Move to the next entry in the circular list */
                NextEntry = NextEntry->CaseMatch;
            }
            while (NextEntry != Entry);

            /*
             * No match found, so we can safely insert it. Remember that a
             * case insensitive match was found, so this is not a ROOT NTC
             * but a Case Match NTC instead.
             */
            PrefixTableEntry->NodeTypeCode = PFX_NTC_CASE_MATCH;
            PrefixTableEntry->NextPrefixTree = NULL;

            /* Insert it into the circular list */
            PrefixTableEntry->CaseMatch = Entry->CaseMatch;
            Entry->CaseMatch = PrefixTableEntry;
            break;
        }

        /* Check if the result was greater or lesser than */
        if (Result == GenericGreaterThan)
        {
            /* Check out if we have a left child */
            if (RtlLeftChild(&Entry->Links))
            {
                /* We do, enter it and restart the loop */
                SplayLinks = RtlLeftChild(&Entry->Links);
                Entry = CONTAINING_RECORD(SplayLinks,
                                          UNICODE_PREFIX_TABLE_ENTRY,
                                          Links);
            }
            else
            {
                /* We don't, set this entry as a child */
                PrefixTableEntry->NodeTypeCode = PFX_NTC_CHILD;
                PrefixTableEntry->NextPrefixTree = NULL;
                PrefixTableEntry->CaseMatch = PrefixTableEntry;

                /* Insert us into the tree */
                RtlInsertAsLeftChild(&Entry->Links, &PrefixTableEntry->Links);
                break;
            }
        }
        else
        {
            /* Check out if we have a right child */
            if (RtlRightChild(&Entry->Links))
            {
                /* We do, enter it and restart the loop */
                SplayLinks = RtlRightChild(&Entry->Links);
                Entry = CONTAINING_RECORD(SplayLinks,
                                          UNICODE_PREFIX_TABLE_ENTRY,
                                          Links);
            }
            else
            {
                /* We don't, set this entry as a child */
                PrefixTableEntry->NodeTypeCode = PFX_NTC_CHILD;
                PrefixTableEntry->NextPrefixTree = NULL;
                PrefixTableEntry->CaseMatch = PrefixTableEntry;

                /* Insert us into the tree */
                RtlInsertAsRightChild(&Entry->Links, &PrefixTableEntry->Links);
                break;
            }
        }
    }

    /* Get the next tree entry */
    NextEntry = CurrentEntry->NextPrefixTree;

    /* Set what was the current entry to a child entry */
    CurrentEntry->NodeTypeCode = PFX_NTC_CHILD;
    CurrentEntry->NextPrefixTree = NULL;

    /* Splay the tree */
    SplayLinks = RtlSplay(&Entry->Links);

    /* The link points to the root, get it */
    Entry = CONTAINING_RECORD(SplayLinks, UNICODE_PREFIX_TABLE_ENTRY, Links);

    /* Mark the root as a root entry */
    Entry->NodeTypeCode = PFX_NTC_ROOT;

    /* Add it to the tree list */
    PreviousEntry->NextPrefixTree = Entry;
    Entry->NextPrefixTree = NextEntry;

    /* Return success */
    return TRUE;
}
Example #27
0
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;

}
Example #28
0
/*
 * @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;
            }
        }
    }
}
Example #29
0
VOID
FatInsertName (
    IN PIRP_CONTEXT IrpContext,
    IN PRTL_SPLAY_LINKS *RootNode,
    IN PFILE_NAME_NODE Name
    )

/*++

Routine Description:

    This routine will insert a name in the splay tree pointed to
    by RootNode.

    The name must not already exist in the splay tree.

Arguments:

    RootNode - Supplies a pointer to the table.

    Name - Contains the New name to enter.

Return Value:

    None.

--*/

{
    COMPARISON Comparison;
    PFILE_NAME_NODE Node;

    PAGED_CODE();

    RtlInitializeSplayLinks(&Name->Links);

Restart:

    //
    //  If we are the first entry in the tree, just become the root.
    //

    if (*RootNode == NULL) {

        *RootNode = &Name->Links;

        return;
    }

    Node = CONTAINING_RECORD( *RootNode, FILE_NAME_NODE, Links );

    while (TRUE) {

        //
        //  Compare the prefix in the tree with the prefix we want
        //  to insert.  Note that Oem here doesn't mean anything.
        //

        Comparison = CompareNames(&Node->Name.Oem, &Name->Name.Oem);

        //
        //  We should never find the name in the table already.
        //

        if (Comparison == IsEqual) {

            //
            //  Almost. If the removable media was taken to another machine and
            //  back, and we have something like:
            //
            //  Old: foobar~1  /  foobarbaz
            //  New: foobar~1  /  foobarbazbaz
            //
            //  but a handle was kept open to foobarbaz so we couldn't purge
            //  away the Fcb in the verify path ... opening foobarbazbaz will
            //  try to insert a duplicate shortname. Bang!
            //
            //  Invalidate it and the horse it came in on.  This new one wins.
            //  The old one is gone.  Only if the old one is in normal state
            //  do we really have a problem.
            //
            
            if (Node->Fcb->FcbState == FcbGood) {
                
                FatBugCheck( (ULONG_PTR)*RootNode, (ULONG_PTR)Name, (ULONG_PTR)Node );
            }

            //
            //  Note, once we zap the prefix links we need to restart our walk
            //  of the tree.
            //
            
            FatMarkFcbCondition( IrpContext, Node->Fcb, FcbBad, TRUE );
            FatRemoveNames( IrpContext, Node->Fcb );

            goto Restart;
        }

        //
        //  If the tree prefix is greater than the new prefix then
        //  we go down the left subtree
        //

        if (Comparison == IsGreaterThan) {

            //
            //  We want to go down the left subtree, first check to see
            //  if we have a left subtree
            //

            if (RtlLeftChild(&Node->Links) == NULL) {

                //
                //  there isn't a left child so we insert ourselves as the
                //  new left child
                //

                RtlInsertAsLeftChild(&Node->Links, &Name->Links);

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a left child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlLeftChild(&Node->Links),
                                          FILE_NAME_NODE,
                                          Links );
            }

        } else {

            //
            //  The tree prefix is either less than or a proper prefix
            //  of the new string.  We treat both cases a less than when
            //  we do insert.  So we want to go down the right subtree,
            //  first check to see if we have a right subtree
            //

            if (RtlRightChild(&Node->Links) == NULL) {

                //
                //  These isn't a right child so we insert ourselves as the
                //  new right child
                //

                RtlInsertAsRightChild(&Node->Links, &Name->Links);

                //
                //  and exit the while loop
                //

                break;

            } else {

                //
                //  there is a right child so simply go down that path, and
                //  go back to the top of the loop
                //

                Node = CONTAINING_RECORD( RtlRightChild(&Node->Links),
                                          FILE_NAME_NODE,
                                          Links );
            }

        }
    }

    return;
}
Example #30
0
/*
 * @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));
}