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
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;
|
|
}
|