You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
8.0 KiB
361 lines
8.0 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fcbtable.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the data structures that facilitate management of the
|
|
collection of FCB's associated with a NET_ROOT
|
|
|
|
Author:
|
|
|
|
Balan Sethu Raman (SethuR) 10/17/96
|
|
|
|
Revision History:
|
|
|
|
This was derived from the original implementation of prefix tables done
|
|
by Joe Linn.
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RxTableComputePathHashValue)
|
|
#pragma alloc_text(PAGE, RxInitializeFcbTable)
|
|
#pragma alloc_text(PAGE, RxFinalizeFcbTable)
|
|
#pragma alloc_text(PAGE, RxFcbTableLookupFcb)
|
|
#pragma alloc_text(PAGE, RxFcbTableInsertFcb)
|
|
#pragma alloc_text(PAGE, RxFcbTableRemoveFcb)
|
|
#endif
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_PREFIX)
|
|
|
|
ULONG
|
|
RxTableComputePathHashValue (
|
|
IN PUNICODE_STRING Name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
here, we compute a caseinsensitive hashvalue. we want to avoid a call/char to
|
|
the unicodeupcase routine but we want to still have some reasonable spread on
|
|
the hashvalues. many rules just dont work for known important cases. for
|
|
example, the (use the first k and the last n) rule that old c compilers used
|
|
doesn't pickup the difference among \nt\private\......\slm.ini and that would be
|
|
nice. note that the underlying comparison used already takes cognizance of the
|
|
length before comparing.
|
|
|
|
the rule we have selected is to use the 2nd, the last 4, and three selected
|
|
at 1/4 points
|
|
|
|
Arguments:
|
|
|
|
Name - the name to be hashed
|
|
|
|
Return Value:
|
|
|
|
ULONG which is a hashvalue for the name given.
|
|
|
|
--*/
|
|
{
|
|
ULONG HashValue;
|
|
LONG i,j;
|
|
LONG Length = Name->Length / sizeof( WCHAR );
|
|
PWCHAR Buffer = Name->Buffer;
|
|
LONG Probe[8];
|
|
|
|
PAGED_CODE();
|
|
|
|
HashValue = 0;
|
|
|
|
Probe[0] = 1;
|
|
Probe[1] = Length - 1;
|
|
Probe[2] = Length - 2;
|
|
Probe[3] = Length - 3;
|
|
Probe[4] = Length - 4;
|
|
Probe[5] = Length >> 2;
|
|
Probe[6] = (2 * Length) >> 2;
|
|
Probe[7] = (3 * Length) >> 2;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
j = Probe[i];
|
|
if ((j < 0) || (j >= Length)) {
|
|
continue;
|
|
}
|
|
HashValue = (HashValue << 3) + RtlUpcaseUnicodeChar( Buffer[j] );
|
|
}
|
|
|
|
RxDbgTrace( 0, Dbg, ("RxTableComputeHashValue Hashv=%ld Name=%wZ\n", HashValue, Name ));
|
|
return HashValue;
|
|
}
|
|
|
|
|
|
#define HASH_BUCKET(TABLE,HASHVALUE) &((TABLE)->HashBuckets[(HASHVALUE) % (TABLE)->NumberOfBuckets])
|
|
|
|
VOID
|
|
RxInitializeFcbTable (
|
|
IN OUT PRX_FCB_TABLE FcbTable,
|
|
IN BOOLEAN CaseInsensitiveMatch
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine initializes the RX_FCB_TABLE data structure
|
|
|
|
Arguments:
|
|
|
|
pFcbTable - the table instance to be initialized.
|
|
|
|
CaseInsensitiveMatch - indicates if all the lookups will be case
|
|
insensitive
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// this is not zero'd so you have to be careful to init everything
|
|
//
|
|
|
|
FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
|
|
FcbTable->NodeByteSize = sizeof( RX_PREFIX_TABLE );
|
|
|
|
ExInitializeResourceLite( &FcbTable->TableLock );
|
|
|
|
FcbTable->Version = 0;
|
|
FcbTable->TableEntryForNull = NULL;
|
|
|
|
FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
|
|
|
|
FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
|
|
for (i=0; i < FcbTable->NumberOfBuckets; i++) {
|
|
InitializeListHead( &FcbTable->HashBuckets[i] );
|
|
}
|
|
|
|
FcbTable->Lookups = 0;
|
|
FcbTable->FailedLookups = 0;
|
|
FcbTable->Compares = 0;
|
|
}
|
|
|
|
VOID
|
|
RxFinalizeFcbTable (
|
|
IN OUT PRX_FCB_TABLE FcbTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine deinitializes a prefix table.
|
|
|
|
Arguments:
|
|
|
|
FcbTable - the table to be finalized.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
ExDeleteResourceLite( &FcbTable->TableLock );
|
|
|
|
#if DBG
|
|
for (i=0; i < FcbTable->NumberOfBuckets; i++) {
|
|
ASSERT( IsListEmpty( &FcbTable->HashBuckets[i] ) );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
PFCB
|
|
RxFcbTableLookupFcb (
|
|
IN PRX_FCB_TABLE FcbTable,
|
|
IN PUNICODE_STRING Path
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine looks up a path in the RX_FCB_TABLE instance.
|
|
|
|
Arguments:
|
|
|
|
FcbTable - the table to be looked in.
|
|
|
|
Path - the name to be looked up
|
|
|
|
Return Value:
|
|
|
|
a pointer to an FCB instance if successful, otherwise NULL
|
|
|
|
--*/
|
|
{
|
|
ULONG HashValue;
|
|
PLIST_ENTRY HashBucket, ListEntry;
|
|
PRX_FCB_TABLE_ENTRY FcbTableEntry;
|
|
PFCB Fcb = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxDbgTrace(+1, Dbg, ("RxFcbTableLookupName %lx %\n",FcbTable));
|
|
|
|
if (Path->Length == 0) {
|
|
FcbTableEntry = FcbTable->TableEntryForNull;
|
|
} else {
|
|
|
|
HashValue = RxTableComputePathHashValue( Path );
|
|
HashBucket = HASH_BUCKET( FcbTable, HashValue );
|
|
|
|
for (ListEntry = HashBucket->Flink;
|
|
ListEntry != HashBucket;
|
|
ListEntry = ListEntry->Flink) {
|
|
|
|
|
|
FcbTableEntry = (PRX_FCB_TABLE_ENTRY)CONTAINING_RECORD( ListEntry, RX_FCB_TABLE_ENTRY, HashLinks );
|
|
|
|
InterlockedIncrement( &FcbTable->Compares );
|
|
|
|
if ((FcbTableEntry->HashValue == HashValue) &&
|
|
(FcbTableEntry->Path.Length == Path->Length) &&
|
|
(RtlEqualUnicodeString( Path, &FcbTableEntry->Path, FcbTable->CaseInsensitiveMatch ))) {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ListEntry == HashBucket) {
|
|
FcbTableEntry = NULL;
|
|
}
|
|
}
|
|
|
|
InterlockedIncrement( &FcbTable->Lookups );
|
|
|
|
if (FcbTableEntry == NULL) {
|
|
InterlockedIncrement( &FcbTable->FailedLookups );
|
|
} else {
|
|
Fcb = (PFCB)CONTAINING_RECORD( FcbTableEntry, FCB, FcbTableEntry );
|
|
|
|
RxReferenceNetFcb( Fcb );
|
|
}
|
|
|
|
RxDbgTraceUnIndent( -1,Dbg );
|
|
|
|
return Fcb;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxFcbTableInsertFcb (
|
|
IN OUT PRX_FCB_TABLE FcbTable,
|
|
IN OUT PFCB Fcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine inserts a FCB in the RX_FCB_TABLE instance.
|
|
|
|
Arguments:
|
|
|
|
FcbTable - the table to be looked in.
|
|
|
|
Fcb - the FCB instance to be inserted
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
Notes:
|
|
|
|
The insertion routine combines the semantics of an insertion followed by
|
|
lookup. This is the reason for the additional reference. Otherwise an
|
|
additional call to reference the FCB inserted in the table needs to
|
|
be made
|
|
|
|
--*/
|
|
{
|
|
PRX_FCB_TABLE_ENTRY FcbTableEntry;
|
|
ULONG HashValue;
|
|
PLIST_ENTRY ListEntry, HashBucket;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( RxIsFcbTableLockExclusive( FcbTable ) );
|
|
|
|
FcbTableEntry = &Fcb->FcbTableEntry;
|
|
FcbTableEntry->HashValue = RxTableComputePathHashValue( &FcbTableEntry->Path );
|
|
HashBucket = HASH_BUCKET( FcbTable, FcbTableEntry->HashValue );
|
|
|
|
RxReferenceNetFcb( Fcb );
|
|
|
|
if (FcbTableEntry->Path.Length){
|
|
InsertHeadList( HashBucket, &FcbTableEntry->HashLinks );
|
|
} else {
|
|
FcbTable->TableEntryForNull = FcbTableEntry;
|
|
}
|
|
|
|
InterlockedIncrement( &FcbTable->Version );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxFcbTableRemoveFcb (
|
|
IN OUT PRX_FCB_TABLE FcbTable,
|
|
IN OUT PFCB Fcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deletes an instance from the table
|
|
|
|
Arguments:
|
|
|
|
FcbTable - the table to be looked in.
|
|
|
|
Fcb - the FCB instance to be inserted
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
PRX_FCB_TABLE_ENTRY FcbTableEntry;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( RxIsPrefixTableLockExclusive( FcbTable ) );
|
|
|
|
FcbTableEntry = &Fcb->FcbTableEntry;
|
|
|
|
if (FcbTableEntry->Path.Length) {
|
|
RemoveEntryList( &FcbTableEntry->HashLinks );
|
|
} else {
|
|
FcbTable->TableEntryForNull = NULL;
|
|
}
|
|
|
|
InitializeListHead( &FcbTableEntry->HashLinks );
|
|
InterlockedIncrement( &FcbTable->Version );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|