397 lines
11 KiB
C
397 lines
11 KiB
C
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (C) 1992, Microsoft Corporation.
|
||
|
//
|
||
|
// File: fcbsup.c
|
||
|
//
|
||
|
// Contents: Support routines for associating DFS_FCB records with
|
||
|
// file objects, and looking them up again.
|
||
|
//
|
||
|
// Functions: DfsInitFcbs - Initialize the hash table for DFS_FCB lookup
|
||
|
// DfsLookupFcb - Lookup an DFS_FCB associated with a file object
|
||
|
// DfsAttachFcb - Associate an DFS_FCB with a file object
|
||
|
// DfsDetachFcb - Remove the Association between an DFS_FCB and
|
||
|
// a file object
|
||
|
// DfsAllocateFcb - Allocate an FCB
|
||
|
// DfsDestroyFcb - Deallocate an FCB
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include "dfsprocs.h"
|
||
|
#include "attach.h"
|
||
|
#include "fcbsup.h"
|
||
|
|
||
|
#define Dbg 0x1000
|
||
|
|
||
|
#define HASH(k,m) (((ULONG_PTR)(k)>>12^(ULONG_PTR)(k)>>2) & m)
|
||
|
|
||
|
#define DEFAULT_HASH_SIZE 16 // default size of hash table
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsInitFcbHashTable(
|
||
|
IN ULONG cHash,
|
||
|
OUT PFCB_HASH_TABLE *ppHashTable);
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(INIT, DfsInitFcbs)
|
||
|
#pragma alloc_text(PAGE, DfsUninitFcbs)
|
||
|
#pragma alloc_text(PAGE, DfsInitFcbHashTable)
|
||
|
|
||
|
//
|
||
|
// The following routines are not pageable because they acquire spinlocks.
|
||
|
//
|
||
|
// DfsLookupFcb
|
||
|
// DfsAttachFcb
|
||
|
// DfsDetachFcb
|
||
|
//
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsInitFcbs - Initialize the DFS_FCB lookup hash table
|
||
|
//
|
||
|
// Synopsis: This function initializes data structures which are
|
||
|
// used for looking up an DFS_FCB associated with some open
|
||
|
// file object.
|
||
|
//
|
||
|
// Arguments: [cHash] -- Size of the hash table to be allocated. Must be
|
||
|
// a power of two. If zero, a default size is used.
|
||
|
//
|
||
|
// Returns: NTSTATUS -- STATUS_SUCCESS, unless memory allocation
|
||
|
// fails.
|
||
|
//
|
||
|
// Note: The hash buckets are initialized to zero, then later
|
||
|
// initialized to a list head when used. This is a debugging
|
||
|
// aid to determine if some hash buckets are never used.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsInitFcbHashTable(
|
||
|
IN ULONG cHash,
|
||
|
OUT PFCB_HASH_TABLE *ppHashTable)
|
||
|
{
|
||
|
PFCB_HASH_TABLE pHashTable;
|
||
|
ULONG cbHashTable;
|
||
|
|
||
|
if (cHash == 0) {
|
||
|
cHash = DEFAULT_HASH_SIZE;
|
||
|
}
|
||
|
ASSERT ((cHash & (cHash-1)) == 0); // Assure cHash is a power of two
|
||
|
|
||
|
cbHashTable = sizeof (FCB_HASH_TABLE) + (cHash-1)*sizeof (LIST_ENTRY);
|
||
|
pHashTable = ExAllocatePoolWithTag(NonPagedPool, cbHashTable, ' sfD');
|
||
|
if (pHashTable == NULL) {
|
||
|
return STATUS_NO_MEMORY;
|
||
|
}
|
||
|
pHashTable->NodeTypeCode = DFS_NTC_FCB_HASH;
|
||
|
pHashTable->NodeByteSize = (NODE_BYTE_SIZE) cbHashTable;
|
||
|
|
||
|
pHashTable->HashMask = (cHash-1);
|
||
|
KeInitializeSpinLock( &pHashTable->HashListSpinLock );
|
||
|
RtlZeroMemory(&pHashTable->HashBuckets[0], cHash * sizeof (LIST_ENTRY));
|
||
|
|
||
|
*ppHashTable = pHashTable;
|
||
|
|
||
|
return(STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsInitFcbs(
|
||
|
IN ULONG cHash
|
||
|
) {
|
||
|
NTSTATUS status;
|
||
|
|
||
|
status = DfsInitFcbHashTable( cHash, &DfsData.FcbHashTable );
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DfsUninitFcbs(
|
||
|
VOID
|
||
|
) {
|
||
|
ExFreePool (DfsData.FcbHashTable);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsLookupFcb - Lookup an DFS_FCB in the hash table
|
||
|
//
|
||
|
// Synopsis: This function will lookup the DFS_FCB associated with
|
||
|
// a particular file object.
|
||
|
//
|
||
|
// Arguments: [pFile] -- Pointer to file object for which the DFS_FCB is
|
||
|
// being looked up.
|
||
|
//
|
||
|
// Returns: PVOID -- pointer to the DFS_FCB found, or NULL if none
|
||
|
//
|
||
|
// Algorithm: Knuth would call it hashing with conflict resoulution
|
||
|
// by chaining.
|
||
|
//
|
||
|
// History: 20 Feb 1993 Alanw Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
PDFS_FCB
|
||
|
DfsLookupFcb(
|
||
|
IN PFILE_OBJECT pFile
|
||
|
) {
|
||
|
PLIST_ENTRY pListHead, pLink;
|
||
|
PDFS_FCB pFCB;
|
||
|
KIRQL SavedIrql;
|
||
|
PFCB_HASH_TABLE pHashTable = DfsData.FcbHashTable;
|
||
|
|
||
|
KeAcquireSpinLock( &pHashTable->HashListSpinLock, &SavedIrql );
|
||
|
pListHead = &pHashTable->HashBuckets[ HASH(pFile, pHashTable->HashMask) ];
|
||
|
|
||
|
if ((pListHead->Flink == NULL) || // list not initialized
|
||
|
(pListHead->Flink == pListHead)) { // list empty
|
||
|
KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
|
||
|
pFCB = CONTAINING_RECORD(pLink, DFS_FCB, HashChain);
|
||
|
if (pFCB->FileObject == pFile) {
|
||
|
KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
|
||
|
return pFCB;
|
||
|
}
|
||
|
}
|
||
|
KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsAttachFcb - Inserts an DFS_FCB into the hash table
|
||
|
//
|
||
|
// Synopsis: This function associates an DFS_FCB to a file object. This
|
||
|
// involves inserting it into the hash table.
|
||
|
//
|
||
|
// Arguments: [pFCB] -- Pointer to the DFS_FCB to be inserted.
|
||
|
// [pFileObj] -- Pointer to the corresponding file object, used
|
||
|
// as the hash key.
|
||
|
//
|
||
|
// Returns: -nothing-
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
DfsAttachFcb(
|
||
|
IN PFILE_OBJECT pFileObj,
|
||
|
IN PDFS_FCB pFCB
|
||
|
) {
|
||
|
PFCB_HASH_TABLE pHashTable = (PFCB_HASH_TABLE) DfsData.FcbHashTable;
|
||
|
PLIST_ENTRY pListHead;
|
||
|
KIRQL SavedIrql;
|
||
|
|
||
|
KeAcquireSpinLock( &pHashTable->HashListSpinLock, &SavedIrql );
|
||
|
|
||
|
pListHead = &pHashTable->HashBuckets[ HASH(pFileObj, pHashTable->HashMask) ];
|
||
|
|
||
|
if (pListHead->Flink == NULL) {
|
||
|
InitializeListHead(pListHead);
|
||
|
}
|
||
|
InsertHeadList(pListHead, &pFCB->HashChain);
|
||
|
KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
|
||
|
|
||
|
DebugTrace(0, Dbg, "Attached Fcb %08lx ", pFCB);
|
||
|
DebugTrace(0, Dbg, "For Fileobject %08lx ", pFileObj);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsDetachFcb - Detach an DFS_FCB from the lookup hash table
|
||
|
//
|
||
|
// Synopsis: This function detaches an DFS_FCB from the hash table. This
|
||
|
// involves just deleting it from the hash bucket chain.
|
||
|
//
|
||
|
// Arguments: [pFCB] -- Pointer to the DFS_FCB to be detached.
|
||
|
// [pFileObj] -- Pointer to the corresponding file object, used
|
||
|
// for debugging only.
|
||
|
//
|
||
|
// Returns: -nothing-
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DfsDetachFcb(
|
||
|
IN PFILE_OBJECT pFileObj,
|
||
|
IN PDFS_FCB pFCB
|
||
|
) {
|
||
|
PFCB_HASH_TABLE pHashTable = (PFCB_HASH_TABLE) DfsData.FcbHashTable;
|
||
|
KIRQL SavedIrql;
|
||
|
|
||
|
ASSERT(pFCB->FileObject == pFileObj);
|
||
|
ASSERT(DfsLookupFcb(pFCB->FileObject) == pFCB);
|
||
|
|
||
|
KeAcquireSpinLock( &pHashTable->HashListSpinLock, &SavedIrql );
|
||
|
RemoveEntryList(&pFCB->HashChain);
|
||
|
pFCB->FileObject = NULL;
|
||
|
KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
|
||
|
|
||
|
DebugTrace(0, Dbg, "Detached Fcb %08lx ", pFCB);
|
||
|
DebugTrace(0, Dbg, "For Fileobject %08lx ", pFileObj);
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsAllocateFcb - Allocate an FCB
|
||
|
//
|
||
|
// Synopsis: This function allocates an FCB for a fileObject that is the
|
||
|
// argument of a Create IRP. The most important thing this
|
||
|
// Fcb contains is the full file name of the fileObject,
|
||
|
// normalized for relative opens etc.
|
||
|
//
|
||
|
// Arguments: [DeviceObject] -- The Device on which the file is being
|
||
|
// opened.
|
||
|
// [FileObject] -- The file object for which the FCB is to be
|
||
|
// allocated.
|
||
|
// [Fcb] -- On successful return, has pointer to newly allocated
|
||
|
// Fcb.
|
||
|
//
|
||
|
// Returns: [STATUS_SUCCESS] -- Successfully allocated FCB
|
||
|
//
|
||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
DfsAllocateFcb(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PFILE_OBJECT FileObject,
|
||
|
OUT PDFS_FCB *Fcb)
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
PDFS_VOLUME_OBJECT deviceObject = (PDFS_VOLUME_OBJECT) DeviceObject;
|
||
|
PDFS_FCB relatedFcb = NULL;
|
||
|
PDFS_FCB fcb;
|
||
|
PUNICODE_STRING relatedName;
|
||
|
ULONG length;
|
||
|
|
||
|
length = sizeof(DFS_FCB) +
|
||
|
deviceObject->Provider.DeviceName.Length +
|
||
|
sizeof(UNICODE_PATH_SEP) +
|
||
|
FileObject->FileName.Length +
|
||
|
sizeof(UNICODE_NULL);
|
||
|
|
||
|
if (FileObject->RelatedFileObject != NULL) {
|
||
|
|
||
|
relatedFcb = DfsLookupFcb( FileObject->RelatedFileObject );
|
||
|
|
||
|
if (relatedFcb != NULL) {
|
||
|
|
||
|
length += relatedFcb->FullFileName.Length +
|
||
|
sizeof(UNICODE_PATH_SEP);
|
||
|
|
||
|
relatedName = &relatedFcb->FullFileName;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
length += FileObject->RelatedFileObject->FileName.Length;
|
||
|
|
||
|
relatedName = &FileObject->RelatedFileObject->FileName;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
relatedName = NULL;
|
||
|
}
|
||
|
|
||
|
if (length <= MAXUSHORT) {
|
||
|
|
||
|
fcb = (PDFS_FCB) ExAllocatePoolWithTag( NonPagedPool, length, ' sfD' );
|
||
|
|
||
|
if (fcb != NULL) {
|
||
|
|
||
|
RtlZeroMemory( fcb, length );
|
||
|
|
||
|
fcb->NodeTypeCode = DFS_NTC_FCB;
|
||
|
fcb->NodeByteSize = (USHORT)length;
|
||
|
|
||
|
fcb->FullFileName.Length = 0;
|
||
|
fcb->FullFileName.MaximumLength = (USHORT) (length - sizeof(DFS_FCB));
|
||
|
fcb->FullFileName.Buffer = (PWCHAR) (fcb + 1);
|
||
|
|
||
|
if (relatedName == NULL) {
|
||
|
|
||
|
RtlCopyUnicodeString(
|
||
|
&fcb->FullFileName,
|
||
|
&deviceObject->Provider.DeviceName);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
RtlCopyUnicodeString(
|
||
|
&fcb->FullFileName,
|
||
|
relatedName);
|
||
|
|
||
|
}
|
||
|
|
||
|
DfsConcatenateFilePath(
|
||
|
&fcb->FullFileName,
|
||
|
FileObject->FileName.Buffer,
|
||
|
FileObject->FileName.Length);
|
||
|
|
||
|
fcb->FileObject = FileObject;
|
||
|
|
||
|
*Fcb = fcb;
|
||
|
|
||
|
status = STATUS_SUCCESS;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
|
||
|
}
|
||
|
|
||
|
return( status );
|
||
|
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfsDestroyFcb
|
||
|
//
|
||
|
// Synopsis: Destroys an FCB allocated by DfsAllocateFcb
|
||
|
//
|
||
|
// Arguments: [Fcb] -- The Fcb to destroy.
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
DfsDestroyFcb(
|
||
|
IN PDFS_FCB Fcb)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Make sure its gone from our Fcb tables
|
||
|
//
|
||
|
|
||
|
ASSERT( DfsLookupFcb( Fcb->FileObject ) != Fcb );
|
||
|
|
||
|
//
|
||
|
// Now, free it up.
|
||
|
//
|
||
|
|
||
|
ExFreePool( Fcb );
|
||
|
|
||
|
}
|