Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1115 lines
31 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: prefix.c
//
// Contents: PREFIX table implementation
//
// History: SethuR -- Implemented
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef KERNEL_MODE
#include <ntifs.h>
#include <ntddser.h>
#include <windef.h>
#else
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#endif
#include <prefix.h>
#include <dfsprefix.h>
PDFS_PREFIX_TABLE_ENTRY
DfspNextUnicodeTableEntry(
IN PDFS_PREFIX_TABLE_ENTRY pEntry);
VOID
DfsDeletePrefixTable(
IN PDFS_PREFIX_TABLE pTable);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DfsFreePrefixTable )
#pragma alloc_text( PAGE, DfsInitializePrefixTable )
#pragma alloc_text( PAGE, DfsDeletePrefixTable )
#pragma alloc_text( PAGE, DfsInsertInPrefixTable )
#pragma alloc_text( PAGE, DfsFindUnicodePrefix )
#pragma alloc_text( PAGE, DfsRemoveFromPrefixTable )
#pragma alloc_text( PAGE, _LookupPrefixTable )
#pragma alloc_text( PAGE, DfsRemoveFromPrefixTableEx )
#pragma alloc_text( PAGE, DfsRemoveFromPrefixTableLockedEx )
#endif // ALLOC_PRAGMA
#if defined (PREFIX_TABLE_HEAP_MEMORY)
HANDLE PrefixTableHeapHandle = NULL;
#endif
NTSTATUS
DfsPrefixTableInit()
{
#if defined (PREFIX_TABLE_HEAP_MEMORY)
PrefixTableHeapHandle = HeapCreate(0, 0, 0);
if ( PrefixTableHeapHandle == NULL ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
/* printf("Prefix table using memory heap\n"); */
#endif
return STATUS_SUCCESS;
}
void
DfsPrefixTableShutdown(void)
{
#if defined (PREFIX_TABLE_HEAP_MEMORY)
if ( PrefixTableHeapHandle != NULL )
{
HeapDestroy(PrefixTableHeapHandle);
PrefixTableHeapHandle = NULL;
}
/* printf("Prefix table using memory heap\n"); */
#endif
}
//+---------------------------------------------------------------------------
//
// Function: DfsInitializePrefixTable
//
// Synopsis: API for initializing the prefix table
//
// Arguments: [pTable] -- the DFS prefix table instance
//
// Returns: one of the following NTSTATUS codes
// STATUS_SUCCESS -- call was successfull.
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
DfsInitializePrefixTable(
IN OUT PDFS_PREFIX_TABLE *ppTable,
IN BOOLEAN fCaseSensitive,
IN PVOID Lock)
{
PDFS_PREFIX_TABLE pTable = *ppTable;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Flags = fCaseSensitive ? PREFIX_TABLE_CASE_SENSITIVE : 0;
int i;
if ( pTable == NULL ) {
Flags |= PREFIX_TABLE_TABLE_ALLOCATED;
pTable = ALLOCATE_PREFIX_TABLE();
if ( pTable == NULL )
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if ( NT_SUCCESS(Status) ) {
RtlZeroMemory(pTable, sizeof(DFS_PREFIX_TABLE));
DfsInitializeHeader(&pTable->DfsHeader,
DFS_OT_PREFIX_TABLE,
sizeof(DFS_PREFIX_TABLE));
pTable->Flags = Flags;
pTable->LockCount = 0;
// Initialize the root entry
INITIALIZE_PREFIX_TABLE_ENTRY(&pTable->RootEntry);
// Initialize the various buckets.
for ( i = 0;i < NO_OF_HASH_BUCKETS;i++ ) {
INITIALIZE_BUCKET(pTable->Buckets[i]);
}
pTable->pPrefixTableLock = Lock;
if ( pTable->pPrefixTableLock == NULL ) {
pTable->pPrefixTableLock = ALLOCATE_PREFIX_TABLE_LOCK();
if ( pTable->pPrefixTableLock != NULL ) {
pTable->Flags |= PREFIX_TABLE_LOCK_ALLOCATED;
Status = INITIALIZE_PREFIX_TABLE_LOCK(pTable->pPrefixTableLock);
if (NT_SUCCESS( Status )) {
pTable->Flags |= PREFIX_TABLE_LOCK_INITIALIZED;
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
if (!NT_SUCCESS( Status )) {
if (pTable) {
DfsDeletePrefixTable( pTable );
pTable = NULL;
}
}
*ppTable = pTable;
return Status;
}
//+---------------------------------------------------------------------------
//
// Function: DfsInsertInPrefixTableLocked
//
// Synopsis: API for inserting a path in the prefix table
//
// Arguments: [pTable] -- the DFS prefix table instance
//
// [pPath] -- the path to be looked up.
//
// [pData] -- BLOB associated with the path
//
// Returns: one of the following NTSTATUS codes
// STATUS_SUCCESS -- call was successfull.
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS DfsInsertInPrefixTableLocked(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pData)
{
NTSTATUS status = STATUS_SUCCESS;
WCHAR Buffer[MAX_PATH_SEGMENT_SIZE];
PWCHAR NameBuffer = Buffer;
ULONG BucketNo = 0;
USHORT cbNameBuffer = sizeof(Buffer);
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
PDFS_PREFIX_TABLE_ENTRY pParentEntry = NULL;
PDFS_PREFIX_TABLE_ENTRY pLastInsertedEntry = NULL;
BOOLEAN fNameFound = FALSE;
UNICODE_STRING Path,Name;
BOOLEAN NewParent = FALSE;
if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
return STATUS_INVALID_PARAMETER;
}
// There is one special case, i.e., in which the prefix is '\'.
// Since this is the PATH_DELIMITER which is treated in a special
// way, we do the >processing upfront.
Path.Length = pPath->Length;
Path.MaximumLength = pPath->MaximumLength;
Path.Buffer = &pPath->Buffer[0];
pParentEntry = &pTable->RootEntry;
if ( pPath->Length == 0 ) {
return STATUS_SUCCESS;
} else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
if ( pPath->Length == sizeof(WCHAR) ) {
pTable->RootEntry.pData = pData;
return STATUS_SUCCESS;
} else {
Path.Length -= sizeof(WCHAR);
Path.Buffer++;
}
}
if ( Path.Length >= MAX_PATH_SEGMENT_SIZE * sizeof(WCHAR) ) {
NameBuffer = PREFIX_TABLE_ALLOCATE_MEMORY(Path.Length + sizeof(WCHAR));
if ( NameBuffer == NULL ) {
return( STATUS_INSUFFICIENT_RESOURCES );
} else {
cbNameBuffer = Path.Length + sizeof(WCHAR);
}
}
while ( Path.Length > 0 ) {
Name.Length = 0;
Name.Buffer = NameBuffer;
Name.MaximumLength = cbNameBuffer;
// Process the name segment
if ( pTable->Flags & PREFIX_TABLE_CASE_SENSITIVE ) {
SPLIT_CASE_SENSITIVE_PATH(&Path,&Name,BucketNo);
} else {
SPLIT_CASE_INSENSITIVE_PATH(&Path,&Name,BucketNo);
}
if ( Name.Length > 0 ) {
// Lookup the table to see if the name segment already exists.
LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
if ( pEntry == NULL ) {
// Initialize the new entry and initialize the name segment.
pEntry = ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable);
if ( pEntry != NULL ) {
INITIALIZE_PREFIX_TABLE_ENTRY(pEntry);
// Allocate the name space entry if there is no entry in the
// name page.
{
PWSTR pBuffer;
// Allocate the entry in the name page.
pBuffer = ALLOCATE_NAME_BUFFER((Name.Length/sizeof(WCHAR)));
if ( pBuffer != NULL ) {
RtlZeroMemory(pBuffer,Name.Length);
RtlCopyMemory(pBuffer,Name.Buffer,Name.Length);
pEntry->PathSegment = Name;
pEntry->PathSegment.Buffer = pBuffer;
} else {
FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pEntry);
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
// thread the entry to point to the parent.
// Increment the no. of children associated with this entry
if (NewParent == FALSE) {
pParentEntry->Reference++;
NewParent = TRUE;
}
pEntry->pParentEntry = pParentEntry;
pLastInsertedEntry = pEntry;
// Insert the entry in the bucket.
INSERT_IN_BUCKET(pTable->Buckets[BucketNo],pEntry);
// Insert the entry in the parent's children list.
INSERT_IN_CHILD_LIST(pEntry, pParentEntry);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
}
pParentEntry = pEntry;
} else {
status = STATUS_INVALID_PARAMETER;
break;
}
}
// If a new entry was not successfully inserted we need to walk up the chain
// of parent entries to undo the increment to the reference count and
// remove the entries from their parent links.
if (NT_SUCCESS(status) &&
pEntry != NULL /* to keep PREFAST happy */) {
// The entry was successfully inserted in the prefix table. Update
// the data (BLOB) associated with it.
// We do it outside the loop to prevent redundant comparisons within
// the loop.
pEntry->pData = pData;
pTable->TotalEntries += 1;
} else {
pParentEntry = pLastInsertedEntry;
while ( pParentEntry != NULL ) {
PDFS_PREFIX_TABLE_ENTRY pMaybeTempEntry;
pMaybeTempEntry = pParentEntry;
pParentEntry = pParentEntry->pParentEntry;
if ( --pMaybeTempEntry->Reference == 0 ) {
//
// If pParentEntry == NULL, pMaybeTempEntry is
// pTable->RootEntry. Do not try to remove it.
//
if ( pParentEntry != NULL ) {
REMOVE_FROM_CHILD_LIST(pMaybeTempEntry);
REMOVE_FROM_BUCKET(pMaybeTempEntry);
FREE_NAME_BUFFER( pMaybeTempEntry->PathSegment.Buffer );
FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pMaybeTempEntry);
}
}
else
{
break;
}
}
}
if ( NameBuffer != Buffer ) {
PREFIX_TABLE_FREE_MEMORY( NameBuffer );
}
return status;
}
//+---------------------------------------------------------------------------
//
// Function: DfsFindUnicodePrefixLocked
//
// Synopsis: fn. for looking up a name segment in a prefix table
//
// Arguments: [pTable] -- the DFS prefix table instance
//
// [pPath] -- the path to be looked up.
//
// [pSuffix] -- the suffix that could not be found.
//
// Returns: a valid ptr if successfull, NULL otherwise
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
DfsFindUnicodePrefixLocked(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PUNICODE_STRING pSuffix,
IN PVOID *ppData,
OUT PBOOLEAN pSubStringMatch)
{
NTSTATUS status = STATUS_SUCCESS;
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
return STATUS_INVALID_PARAMETER;
}
*ppData = NULL;
if ( pPath->Length == 0 ) {
status = STATUS_INVALID_PARAMETER;
} else {
status = _LookupPrefixTable(pTable,pPath,pSuffix,&pEntry, pSubStringMatch);
// Update the BLOB placeholder with the results of the lookup.
if ( status == STATUS_SUCCESS ) {
*ppData = pEntry->pData;
}
}
return status;
}
//+---------------------------------------------------------------------------
//
// Function: DfsRemoveFromPrefixTable
//
// Synopsis: private fn. for looking up a name segment in a prefix table
//
// Arguments: [pTable] -- the DFS prefix table instance
//
// [pPath] -- the path to be looked up.
//
// Returns: one of the following NTSTATUS codes
// STATUS_SUCCESS -- call was successfull.
// STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS DfsRemoveFromPrefixTableLocked(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pMatchingData)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING Path,Suffix;
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
return STATUS_INVALID_PARAMETER;
}
Suffix.Length = 0;
Suffix.Buffer = NULL;
Path.Length = pPath->Length;
Path.MaximumLength = pPath->MaximumLength;
Path.Buffer = &pPath->Buffer[0];
if ( pPath->Length == 0 ) {
return STATUS_SUCCESS;
} else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
if ( pPath->Length == sizeof(WCHAR) ) {
if ( pTable->RootEntry.pData == NULL ) {
status = STATUS_OBJECT_PATH_NOT_FOUND;
return status;
} else {
pTable->RootEntry.pData = NULL;
return STATUS_SUCCESS;
}
} else {
Path.Length -= sizeof(WCHAR);
Path.Buffer++;
}
}
status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry,NULL);
if ( NT_SUCCESS(status)&& (Suffix.Length == 0) ) {
if ( (pMatchingData == NULL) || (pMatchingData == pEntry->pData) )
{
DfsRemovePrefixTableEntry(pTable, pEntry);
pTable->TotalEntries -= 1;
}
else
{
status = STATUS_NOT_FOUND;
}
}
return status;
}
NTSTATUS DfsReplaceInPrefixTableLocked(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pReplaceData,
IN PVOID *ppMatchingData)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING Path,Suffix;
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
return STATUS_INVALID_PARAMETER;
}
Suffix.Length = 0;
Suffix.Buffer = NULL;
Path.Length = pPath->Length;
Path.MaximumLength = pPath->MaximumLength;
Path.Buffer = &pPath->Buffer[0];
if ( pPath->Length == 0 ) {
return STATUS_SUCCESS;
} else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
if ( pPath->Length == sizeof(WCHAR) ) {
if ( pTable->RootEntry.pData == NULL ) {
status = STATUS_OBJECT_PATH_NOT_FOUND;
return status;
} else {
pTable->RootEntry.pData = NULL;
return STATUS_SUCCESS;
}
} else {
Path.Length -= sizeof(WCHAR);
Path.Buffer++;
}
}
status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry,NULL);
if ( NT_SUCCESS(status)&& (Suffix.Length == 0) ) {
if ( (*ppMatchingData == NULL) || (*ppMatchingData == pEntry->pData) ) {
*ppMatchingData = pEntry->pData;
pEntry->pData = pReplaceData;
} else {
status = STATUS_NOT_FOUND;
}
}
if ( (status != STATUS_SUCCESS) && (*ppMatchingData == NULL) ) {
status = DfsInsertInPrefixTableLocked( pTable,
pPath,
pReplaceData );
}
return status;
}
VOID
DfsRemovePrefixTableEntry(
IN PDFS_PREFIX_TABLE pTable,
IN PDFS_PREFIX_TABLE_ENTRY pEntry )
{
UNREFERENCED_PARAMETER(pTable);
// Destroy the association between the data associated with
// this prefix.
pEntry->pData = NULL;
// found an exact match for the given path name in the table.
// traverse the list of parent pointers and delete them if
// required.
while ( pEntry != NULL ) {
if ( (--pEntry->Reference) == 0 ) {
PDFS_PREFIX_TABLE_ENTRY pTempEntry = pEntry;
pEntry = pEntry->pParentEntry;
//
// pEntry == NULL means pTempEntry is pTable->RootEntry.
// Do not try to remove it.
//
if ( pEntry != NULL ) {
REMOVE_FROM_CHILD_LIST(pTempEntry);
REMOVE_FROM_BUCKET(pTempEntry);
FREE_NAME_BUFFER( pTempEntry->PathSegment.Buffer );
FREE_DFS_PREFIX_TABLE_ENTRY(pTable,pTempEntry);
}
}
else
{
break;
}
}
return;
}
//+---------------------------------------------------------------------------
//
// Function: DfsFreePrefixTable
//
// Synopsis: API for freeing a prefix table
//
// Arguments: [pTable] -- the DFS prefix table instance
//
// Returns: one of the following NTSTATUS codes
// STATUS_SUCCESS -- call was successfull.
//
// History: 08-01-99 JHarper Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS
DfsDismantlePrefixTable(
IN PDFS_PREFIX_TABLE pTable,
IN VOID (*ProcessFunction)(PVOID pEntry))
{
NTSTATUS Status = STATUS_SUCCESS;
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
PDFS_PREFIX_TABLE_ENTRY pSentinelEntry = NULL;
ULONG i = 0;
WRITE_LOCK_PREFIX_TABLE(pTable, Status);
if ( Status != STATUS_SUCCESS )
goto done;
for ( i = 0; i < NO_OF_HASH_BUCKETS; i++ ) {
pSentinelEntry = &pTable->Buckets[i].SentinelEntry;
while ( pSentinelEntry->pNextEntry != pSentinelEntry ) {
pEntry = pSentinelEntry->pNextEntry;
REMOVE_FROM_BUCKET(pEntry);
if ( (ProcessFunction) && (pEntry->pData) ) {
ProcessFunction(pEntry->pData);
}
FREE_NAME_BUFFER( pEntry->PathSegment.Buffer );
FREE_DFS_PREFIX_TABLE_ENTRY(pTable, pEntry);
}
pTable->Buckets[i].NoOfEntries = 0;
}
if ( pTable->RootEntry.PathSegment.Buffer != NULL )
FREE_NAME_BUFFER(pTable->RootEntry.PathSegment.Buffer);
UNLOCK_PREFIX_TABLE(pTable);
done:
return Status;
}
NTSTATUS
DfsDereferencePrefixTable(
IN PDFS_PREFIX_TABLE pTable)
{
PDFS_OBJECT_HEADER pHeader = NULL;
USHORT headerType = 0;
LONG Ref = 0;
if(pTable == NULL)
{
return STATUS_INVALID_PARAMETER;
}
pHeader = &pTable->DfsHeader;
headerType = DfsGetHeaderType( pHeader );
if (headerType != DFS_OT_PREFIX_TABLE) {
return STATUS_UNSUCCESSFUL;
}
Ref = DfsDecrementReference( pHeader );
if (Ref == 0) {
DfsDeletePrefixTable( pTable );
pTable = NULL;
}
return STATUS_SUCCESS;
}
VOID
DfsDeletePrefixTable(
IN PDFS_PREFIX_TABLE pTable)
{
if (pTable != NULL) {
if (pTable->Flags & PREFIX_TABLE_LOCK_INITIALIZED) {
UNINITIALIZE_PREFIX_TABLE_LOCK( pTable->pPrefixTableLock );
pTable->Flags &= ~(PREFIX_TABLE_LOCK_INITIALIZED);
}
if (pTable->Flags & PREFIX_TABLE_LOCK_ALLOCATED) {
FREE_PREFIX_TABLE_LOCK( pTable->pPrefixTableLock );
pTable->pPrefixTableLock = NULL;
pTable->Flags &= ~(PREFIX_TABLE_LOCK_ALLOCATED);
}
if (pTable->Flags & PREFIX_TABLE_TABLE_ALLOCATED) {
FREE_PREFIX_TABLE( pTable );
}
}
return;
}
//+---------------------------------------------------------------------------
//
// Function: _LookupPrefixTable
//
// Synopsis: private fn. for looking up a name segment in a prefix table
//
// Arguments: [pTable] -- the DFS prefix table instance
//
// [pPath] -- the path to be looked up.
//
// [pSuffix] -- the suffix that could not be found.
//
// [ppEntry] -- placeholder for the matching entry for the prefix.
//
//
// Returns: one of the following NTSTATUS codes
// STATUS_SUCCESS -- call was successfull.
// STATUS_OBJECT_PATH_NOT_FOUND -- no entry for the path
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS _LookupPrefixTable(
PDFS_PREFIX_TABLE pTable,
UNICODE_STRING *pPath,
UNICODE_STRING *pSuffix,
PDFS_PREFIX_TABLE_ENTRY *ppEntry,
OUT PBOOLEAN pSubStringMatch )
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING Path = *pPath;
WCHAR Buffer[MAX_PATH_SEGMENT_SIZE];
PWCHAR NameBuffer = Buffer;
USHORT cbNameBuffer = sizeof(Buffer);
UNICODE_STRING Name;
ULONG BucketNo;
BOOLEAN fPrefixFound = FALSE;
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
PDFS_PREFIX_TABLE_ENTRY pParentEntry = &pTable->RootEntry;
BOOLEAN fNameFound = FALSE;
BOOLEAN SubStringMatch = TRUE;
// The \ is treated as a special case. The test for all names starting with
// a delimiter is done before we initiate the complete search process.
if ( Path.Buffer[0] == PATH_DELIMITER ) {
Path.Length = Path.Length - sizeof(WCHAR);
Path.Buffer += 1; // Skip the path delimiter at the beginning.
if ( pTable->RootEntry.pData != NULL ) {
fPrefixFound = TRUE;
*pSuffix = Path;
*ppEntry = &pTable->RootEntry;
}
}
if ( Path.Length >= MAX_PATH_SEGMENT_SIZE ) {
NameBuffer = PREFIX_TABLE_ALLOCATE_MEMORY(Path.Length + sizeof(WCHAR));
if ( NameBuffer == NULL ) {
return( STATUS_INSUFFICIENT_RESOURCES );
} else {
cbNameBuffer = Path.Length + sizeof(WCHAR);
}
}
while ( Path.Length > 0 ) {
Name.Length = 0;
Name.Buffer = NameBuffer;
Name.MaximumLength = cbNameBuffer;
if ( pTable->Flags & PREFIX_TABLE_CASE_SENSITIVE ) {
SPLIT_CASE_SENSITIVE_PATH(&Path,&Name,BucketNo);
} else {
SPLIT_CASE_INSENSITIVE_PATH(&Path,&Name,BucketNo);
}
if ( Name.Length > 0 ) {
// Process the name segment
// Lookup the bucket to see if the entry exists.
LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
if ( pEntry != NULL ) {
// Cache the data available for this prefix if any.
if ( pEntry->pData != NULL ) {
*pSuffix = Path;
*ppEntry = pEntry;
fPrefixFound = TRUE;
}
} else {
SubStringMatch = FALSE;
break;
}
// set the stage for processing the next name segment.
pParentEntry = pEntry;
}
}
if ( !fPrefixFound ) {
status = STATUS_OBJECT_PATH_NOT_FOUND;
}
if ( NameBuffer != Buffer ) {
PREFIX_TABLE_FREE_MEMORY( NameBuffer );
}
if (pSubStringMatch != NULL)
{
*pSubStringMatch = SubStringMatch;
}
return status;
}
NTSTATUS
DfsInsertInPrefixTable(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pData)
{
NTSTATUS status;
WRITE_LOCK_PREFIX_TABLE(pTable, status);
if ( status != STATUS_SUCCESS )
goto done;
status = DfsInsertInPrefixTableLocked(pTable, pPath, pData);
UNLOCK_PREFIX_TABLE(pTable);
done:
return status;
}
NTSTATUS
DfsFindUnicodePrefix(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PUNICODE_STRING pSuffix,
IN PVOID *ppData)
{
NTSTATUS Status;
READ_LOCK_PREFIX_TABLE(pTable, Status);
if ( Status != STATUS_SUCCESS )
goto done;
Status = DfsFindUnicodePrefixLocked(pTable, pPath, pSuffix, ppData,NULL);
UNLOCK_PREFIX_TABLE(pTable);
done:
return Status;
}
NTSTATUS
DfsRemoveFromPrefixTable(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pMatchingData)
{
NTSTATUS Status;
WRITE_LOCK_PREFIX_TABLE(pTable, Status);
if ( Status != STATUS_SUCCESS )
goto done;
Status = DfsRemoveFromPrefixTableLocked(pTable, pPath, pMatchingData);
UNLOCK_PREFIX_TABLE(pTable);
done:
return Status;
}
NTSTATUS
DfsRemoveFromPrefixTableLockedEx(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pMatchingData,
IN PVOID *pReturnedData)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING Path,Suffix;
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
UNREFERENCED_PARAMETER(pMatchingData);
if (IS_PREFIX_TABLE_LOCKED(pTable) == FALSE) {
return STATUS_INVALID_PARAMETER;
}
Suffix.Length = 0;
Suffix.Buffer = NULL;
Path.Length = pPath->Length;
Path.MaximumLength = pPath->MaximumLength;
Path.Buffer = &pPath->Buffer[0];
if ( pPath->Length == 0 ) {
return STATUS_SUCCESS;
} else if ( pPath->Buffer[0] == PATH_DELIMITER ) {
if ( pPath->Length == sizeof(WCHAR) ) {
if ( pTable->RootEntry.pData == NULL ) {
status = STATUS_OBJECT_PATH_NOT_FOUND;
return status;
} else {
pTable->RootEntry.pData = NULL;
return STATUS_SUCCESS;
}
} else {
Path.Length -= sizeof(WCHAR);
Path.Buffer++;
}
}
status = _LookupPrefixTable(pTable,&Path,&Suffix,&pEntry,NULL);
if ( NT_SUCCESS(status)&& (Suffix.Length == 0) )
{
*pReturnedData = pEntry->pData;
DfsRemovePrefixTableEntry(pTable, pEntry);
}
return status;
}
NTSTATUS
DfsRemoveFromPrefixTableEx(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pMatchingData,
IN PVOID *pReturnedData)
{
NTSTATUS Status;
WRITE_LOCK_PREFIX_TABLE(pTable, Status);
if ( Status != STATUS_SUCCESS )
goto done;
Status = DfsRemoveFromPrefixTableLockedEx(pTable, pPath, pMatchingData, pReturnedData);
UNLOCK_PREFIX_TABLE(pTable);
done:
return Status;
}
NTSTATUS
DfsReplaceInPrefixTable(
IN PDFS_PREFIX_TABLE pTable,
IN PUNICODE_STRING pPath,
IN PVOID pReplaceData,
IN PVOID pMatchingData)
{
NTSTATUS Status;
IN PVOID pGotData = pMatchingData;
WRITE_LOCK_PREFIX_TABLE(pTable, Status);
if ( Status != STATUS_SUCCESS )
goto done;
Status = DfsReplaceInPrefixTableLocked(pTable,
pPath,
pReplaceData,
&pGotData);
UNLOCK_PREFIX_TABLE(pTable);
done:
return Status;
}
#if !defined (KERNEL_MODE)
VOID
DumpParentName(
IN PDFS_PREFIX_TABLE_ENTRY pEntry)
{
if ( pEntry->pParentEntry != NULL ) {
DumpParentName(pEntry->pParentEntry);
if ( pEntry->pParentEntry->PathSegment.Buffer != NULL )
printf("\\%wZ", &pEntry->pParentEntry->PathSegment);
}
return;
}
VOID
DfsDumpPrefixTable(
PDFS_PREFIX_TABLE pPrefixTable,
IN VOID (*DumpFunction)(PVOID pEntry))
{
PPREFIX_TABLE_BUCKET pBucket;
PDFS_PREFIX_TABLE_ENTRY pCurEntry = NULL;
ULONG i, NumEntries;
NTSTATUS Status;
printf("Prefix table %p\n", pPrefixTable);
printf("Prefix table flags %x\n", pPrefixTable->Flags);
printf("Prefix table Lock %p\n", pPrefixTable->pPrefixTableLock);
READ_LOCK_PREFIX_TABLE(pPrefixTable, Status);
if (Status != STATUS_SUCCESS)
return NOTHING;
for ( i = 0; i < NO_OF_HASH_BUCKETS; i++ ) {
pBucket = &pPrefixTable->Buckets[i];
pCurEntry = pBucket->SentinelEntry.pNextEntry;
NumEntries = 0;
while ( pCurEntry != &pBucket->SentinelEntry ) {
NumEntries++;
if ( pCurEntry->pData != NULL ) {
printf("Found Prefix data %p in Bucket %d\n", pCurEntry->pData, i);
DumpParentName(pCurEntry);
printf("\\%wZ\n", &pCurEntry->PathSegment);
if ( DumpFunction ) {
DumpFunction(pCurEntry->pData);
}
}
pCurEntry = pCurEntry->pNextEntry;
}
printf("Number of entries in Bucket %d is %d\n", i, NumEntries);
}
UNLOCK_PREFIX_TABLE(pPrefixTable);
}
#endif
NTSTATUS
DfsPrefixTableAcquireWriteLock(
PDFS_PREFIX_TABLE pPrefixTable )
{
NTSTATUS Status;
WRITE_LOCK_PREFIX_TABLE(pPrefixTable, Status);
return Status;
}
NTSTATUS
DfsPrefixTableAcquireReadLock(
PDFS_PREFIX_TABLE pPrefixTable )
{
NTSTATUS Status;
READ_LOCK_PREFIX_TABLE(pPrefixTable, Status);
return Status;
}
NTSTATUS
DfsPrefixTableReleaseLock(
PDFS_PREFIX_TABLE pPrefixTable )
{
UNLOCK_PREFIX_TABLE(pPrefixTable);
return STATUS_SUCCESS;
}
NTSTATUS
DfsEnumeratePrefixTableLocked(
IN PDFS_PREFIX_TABLE pTable,
IN VOID (*ProcessFunction)(PVOID pEntry, PVOID pContext),
LPVOID lpvClientContext)
{
NTSTATUS Status = STATUS_SUCCESS;
PPREFIX_TABLE_BUCKET pBucket = NULL;
PDFS_PREFIX_TABLE_ENTRY pCurEntry = NULL;
ULONG i = 0;
if(pTable->TotalEntries == 0)
{
return Status;
}
for ( i = 0; i < NO_OF_HASH_BUCKETS; i++ )
{
pBucket = &pTable->Buckets[i];
pCurEntry = pBucket->SentinelEntry.pNextEntry;
while ( pCurEntry != &pBucket->SentinelEntry )
{
if ( pCurEntry->pData != NULL )
{
ProcessFunction(pCurEntry->pData, lpvClientContext);
}
pCurEntry = pCurEntry->pNextEntry;
}
}
return Status;
}