reactos/drivers/filesystems/fastfat_new/splaysup.c
Pierre Schweitzer aeadcaf515
[FASTFAT] Import the MS FastFAT sample from WXP.
Modified it so that it builds in trunk (with GCC, though).
Not to be switched for now, as it doesn't work in ReactOS (yet?).
2017-11-23 12:35:51 +01:00

505 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
PrefxSup.c
Abstract:
This module implements the Fat Name lookup Suport routines
--*/
#include "fatprocs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (FAT_BUG_CHECK_SPLAYSUP)
//
// The debug trace level for this module
//
#define Dbg (DEBUG_TRACE_SPLAYSUP)
//
// Local procedures and types used only in this package
//
typedef enum _COMPARISON {
IsLessThan,
IsGreaterThan,
IsEqual
} COMPARISON;
COMPARISON
FatCompareNames (
IN PSTRING NameA,
IN PSTRING NameB
);
//
// Do a macro here to check for a common case.
//
#define CompareNames(NAMEA,NAMEB) ( \
*(PUCHAR)(NAMEA)->Buffer != *(PUCHAR)(NAMEB)->Buffer ? \
*(PUCHAR)(NAMEA)->Buffer < *(PUCHAR)(NAMEB)->Buffer ? \
IsLessThan : IsGreaterThan : \
FatCompareNames((PSTRING)(NAMEA), (PSTRING)(NAMEB)) \
)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatInsertName)
#pragma alloc_text(PAGE, FatRemoveNames)
#pragma alloc_text(PAGE, FatFindFcb)
#pragma alloc_text(PAGE, FatCompareNames)
#endif
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;
}
Restart:
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;
}
VOID
FatRemoveNames (
IN PIRP_CONTEXT IrpContext,
IN PFCB Fcb
)
/*++
Routine Description:
This routine will remove the short name and any long names associated
with the files from their repsective splay tree.
Arguments:
Name - Supplies the Fcb to process.
Return Value:
None.
--*/
{
PDCB Parent;
PRTL_SPLAY_LINKS NewRoot;
Parent = Fcb->ParentDcb;
//
// We used to assert this condition, but it really isn't good. If
// someone rapidly renames a directory multiple times and we can't
// flush the lower fcbs fast enough (that didn't go away synch.)
// well, well hit some of them again.
//
// ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE ));
//
if (FlagOn( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE )) {
//
// Delete the node short name.
//
NewRoot = RtlDelete(&Fcb->ShortName.Links);
Parent->Specific.Dcb.RootOemNode = NewRoot;
//
// Now check for the presence of long name and delete it.
//
if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME )) {
NewRoot = RtlDelete(&Fcb->LongName.Oem.Links);
Parent->Specific.Dcb.RootOemNode = NewRoot;
RtlFreeOemString( &Fcb->LongName.Oem.Name.Oem );
ClearFlag( Fcb->FcbState, FCB_STATE_HAS_OEM_LONG_NAME );
}
if (FlagOn( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME )) {
NewRoot = RtlDelete(&Fcb->LongName.Unicode.Links);
Parent->Specific.Dcb.RootUnicodeNode = NewRoot;
RtlFreeUnicodeString( &Fcb->LongName.Unicode.Name.Unicode );
ClearFlag( Fcb->FcbState, FCB_STATE_HAS_UNICODE_LONG_NAME );
}
ClearFlag( Fcb->FcbState, FCB_STATE_NAMES_IN_SPLAY_TREE );
}
return;
}
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;
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;
}
//
// Local support routine
//
COMPARISON
FatCompareNames (
IN PSTRING NameA,
IN PSTRING NameB
)
/*++
Routine Description:
This function compares two names as fast as possible. Note that since
this comparison is case sensitive, I neither know nor case if the names
are UNICODE or OEM. All that is important is that the result is
deterministic.
Arguments:
NameA & NameB - The names to compare.
Return Value:
COMPARISON - returns
IsLessThan if NameA < NameB lexicalgraphically,
IsGreaterThan if NameA > NameB lexicalgraphically,
IsEqual if NameA is equal to NameB
--*/
{
ULONG i;
ULONG MinLength;
PAGED_CODE();
//
// Figure out the minimum of the two lengths
//
MinLength = NameA->Length < NameB->Length ? NameA->Length :
NameB->Length;
//
// Loop through looking at all of the characters in both strings
// testing for equalilty, less than, and greater than
//
i = (ULONG)RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinLength );
if (i < MinLength) {
return NameA->Buffer[i] < NameB->Buffer[i] ? IsLessThan :
IsGreaterThan;
}
if (NameA->Length < NameB->Length) {
return IsLessThan;
}
if (NameA->Length > NameB->Length) {
return IsGreaterThan;
}
return IsEqual;
}