//+------------------------------------------------------------------------- // // 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 #include #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; }