NT4/private/ntos/mup/prefixp.c
2020-09-30 17:12:29 +02:00

320 lines
8.8 KiB
C

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: prefixp.c
//
// Contents: PREFIX table implementation
//
// History: SethuR -- Implemented
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef KERNEL_MODE
#include "dfsprocs.h"
#define Dbg DEBUG_TRACE_RTL
#else
#define DfsDbgTrace(x,y,z,a)
#endif
#include <prefix.h>
#include <prefixp.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, _InitializePrefixTableEntryAllocation )
#pragma alloc_text( PAGE, _AllocateNamePageEntry )
#pragma alloc_text( PAGE, _AllocatePrefixTableEntry )
#pragma alloc_text( PAGE, _LookupPrefixTable )
#endif // ALLOC_PRAGMA
//
// This macro takes a pointer (or ulong) and returns its rounded up quadword
// value
//
#define QuadAlign(Ptr) ( \
((((ULONG)(Ptr)) + 7) & 0xfffffff8) \
)
//+---------------------------------------------------------------------------
//
// Function: _InitializePrefixTableEntryAllocation
//
// Synopsis: private fn. for initializing prefix table entry allocation
//
// Arguments: [pTable] -- table to be initialized
//
// Returns: one of the following NTSTATUS codes
// STATUS_SUCCESS -- call was successfull.
// STATUS_NO_MEMORY -- no resource available
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS _InitializePrefixTableEntryAllocation(PDFS_PREFIX_TABLE pTable)
{
NTSTATUS status = STATUS_SUCCESS;
#ifdef KERNEL_MODE
PVOID pSegment = NULL;
pSegment = ExAllocatePool(PagedPool,PREFIX_TABLE_ENTRY_SEGMENT_SIZE);
if (pSegment != NULL)
{
status = ExInitializeZone(&pTable->PrefixTableEntryZone,
QuadAlign(sizeof(DFS_PREFIX_TABLE_ENTRY)),
pSegment,
PREFIX_TABLE_ENTRY_SEGMENT_SIZE);
}
else
status = STATUS_NO_MEMORY;
#endif
return status;
}
//+---------------------------------------------------------------------------
//
// Function: _AllocateNamePageEntry
//
// Synopsis: private fn. for allocating a name page entry
//
// Arguments: [pNamePageList] -- name page list to allocate from
//
// [cLength] -- length of the buffer in WCHAR's
//
// Returns: NULL if unsuccessfull otherwise valid pointer
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
PWSTR _AllocateNamePageEntry(PNAME_PAGE_LIST pNamePageList,
ULONG cLength)
{
PNAME_PAGE pTempPage = pNamePageList->pFirstPage;
PWSTR pBuffer = NULL;
while (pTempPage != NULL)
{
if (pTempPage->cFreeSpace > (LONG)cLength)
break;
else
pTempPage = pTempPage->pNextPage;
}
if (pTempPage == NULL)
{
pTempPage = ALLOCATE_NAME_PAGE();
INITIALIZE_NAME_PAGE(pTempPage);
if (pTempPage != NULL)
{
pTempPage->pNextPage = pNamePageList->pFirstPage;
pNamePageList->pFirstPage = pTempPage;
pTempPage->cFreeSpace = FREESPACE_IN_NAME_PAGE;
}
}
if ((pTempPage != NULL) && (pTempPage->cFreeSpace >= (LONG)cLength))
{
pTempPage->cFreeSpace -= cLength;
pBuffer = &pTempPage->Names[pTempPage->cFreeSpace];
}
return pBuffer;
}
//+---------------------------------------------------------------------------
//
// Function: _AllocatePrefixTableEntry
//
// Synopsis: allocate prefic table entry
//
// Arguments: [pTable] -- the prefix table from which we need to allocate.
//
// Returns: returns a valid pointer if successfull otherwise NULL
//
// History: 04-18-94 SethuR Created
//
// Notes:
//
//----------------------------------------------------------------------------
PDFS_PREFIX_TABLE_ENTRY _AllocatePrefixTableEntry(PDFS_PREFIX_TABLE pTable)
{
PDFS_PREFIX_TABLE_ENTRY pEntry = NULL;
#ifdef KERNEL_MODE
NTSTATUS status;
PVOID pSegment = NULL;
pSegment = ExAllocatePool(PagedPool,PREFIX_TABLE_ENTRY_SEGMENT_SIZE);
if (pSegment != NULL)
{
status = ExExtendZone(&pTable->PrefixTableEntryZone,
pSegment,
PREFIX_TABLE_ENTRY_SEGMENT_SIZE);
if (NT_SUCCESS(status))
{
pEntry = ALLOCATE_DFS_PREFIX_TABLE_ENTRY(pTable);
}
else
{
DfsDbgTrace(0, Dbg, "ExExtendZone returned %lx\n", status);
}
}
#endif
return pEntry;
}
//+---------------------------------------------------------------------------
//
// 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)
{
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;
DfsDbgTrace(0, Dbg, "_LookupPrefixTable -- Entry\n", 0);
// 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 = ExAllocatePool( NonPagedPool, Path.Length + sizeof(WCHAR) );
if (NameBuffer == NULL) {
DfsDbgTrace(0, Dbg, "Unable to allocate %d non-paged bytes\n", (Path.Length + sizeof(WCHAR)) );
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->CaseSensitive)
{
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.
DfsDbgTrace(0, Dbg, "LOOKUP_BUCKET: Bucket(%ld)", BucketNo);
DfsDbgTrace(0, Dbg, "for Name(%wZ)\n", &Name);
LOOKUP_BUCKET(pTable->Buckets[BucketNo],Name,pParentEntry,pEntry,fNameFound);
DfsDbgTrace(0, Dbg, "Returned pEntry(%lx)", pEntry);
DfsDbgTrace(0, Dbg, " and fNameFound(%s)\n",fNameFound ? "TRUE" : "FALSE" );
if (pEntry != NULL)
{
// Cache the data available for this prefix if any.
if (pEntry->pData != NULL)
{
*pSuffix = Path;
*ppEntry = pEntry;
fPrefixFound = TRUE;
}
}
else
{
break;
}
// set the stage for processing the next name segment.
pParentEntry = pEntry;
}
}
if (!fPrefixFound)
{
status = STATUS_OBJECT_PATH_NOT_FOUND;
DfsDbgTrace(0, Dbg, "_LookupPrefixTable Error -- %lx\n", status);
}
if (NameBuffer != Buffer) {
ExFreePool( NameBuffer );
}
DfsDbgTrace(-1, Dbg, "_LookupPrefixTable -- Exit\n", 0);
return status;
}