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.
767 lines
25 KiB
767 lines
25 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2000, Microsoft Corporation.
|
|
//
|
|
// File: name_table.c
|
|
//
|
|
// Contents: The DFS Name Table
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#define NAME_TABLE_C
|
|
#ifdef KERNEL_MODE
|
|
|
|
#include <ntifs.h>
|
|
#include <string.h>
|
|
#include <fsrtl.h>
|
|
#include <zwapi.h>
|
|
#include <wmlkm.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 "name_table.h"
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsInitNameTable - Creates and initializes the DFS Name table.
|
|
//
|
|
// Synopsis: DfsInitNameTable allocates space for the space table. It then
|
|
// initializes the lock and the hash buckets in the table and
|
|
// returns the allocated name table.
|
|
//
|
|
// Arguments: NumBuckets - Number of Buckets in the name table hash.
|
|
// ppNameTable - Pointer to name table pointer.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_SUCCESS if we could allocate the table.
|
|
// STATUS_INSUFFICIENT_RESOURCES otherwise.
|
|
//
|
|
//
|
|
// Description: The DFS NameTable is the starting point for all DFS namespace
|
|
// lookups. The NameTable hash buckets hold the root objects of
|
|
// all DFS's known to this server. The hash is based on the
|
|
// netbios DFS Naming context (which is the netbios
|
|
// domain/forest/machine name and the DFS Share name of the form
|
|
// \NetbiosName\\Sharename.)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
DfsInitializeNameTable(
|
|
IN ULONG NumBuckets,
|
|
OUT PDFS_NAME_TABLE *ppNameTable)
|
|
{
|
|
PDFS_NAME_TABLE pNameTable = NULL;
|
|
PDFS_NAME_TABLE_BUCKET pBucket = NULL;
|
|
ULONG HashTableSize;
|
|
PCRITICAL_SECTION pLock = NULL;
|
|
ULONG i;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
if ( NumBuckets == 0 ) {
|
|
NumBuckets = DEFAULT_NAME_TABLE_SIZE;
|
|
}
|
|
|
|
HashTableSize = sizeof(DFS_NAME_TABLE) +
|
|
NumBuckets * sizeof(DFS_NAME_TABLE_BUCKET);
|
|
|
|
do {
|
|
pNameTable = ALLOCATE_MEMORY(HashTableSize + sizeof(CRITICAL_SECTION));
|
|
|
|
if ( pNameTable == NULL ) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RtlZeroMemory(pNameTable, HashTableSize + sizeof(CRITICAL_SECTION));
|
|
|
|
DfsInitializeHeader( &(pNameTable->DfsHeader),
|
|
DFS_OT_NAME_TABLE,
|
|
HashTableSize + sizeof(CRITICAL_SECTION));
|
|
|
|
pLock = (PCRITICAL_SECTION)((ULONG_PTR)pNameTable + HashTableSize);
|
|
if (InitializeCriticalSectionAndSpinCount(pLock, DFS_NAMETABLE_CRIT_SPIN_COUNT) != TRUE)
|
|
{
|
|
Status = GetLastError();
|
|
break;
|
|
}
|
|
|
|
pNameTable->NumBuckets = NumBuckets;
|
|
pNameTable->pLock = (PVOID)pLock;
|
|
pNameTable->Flags = 0;
|
|
for ( i = 0; i < NumBuckets; i++ ) {
|
|
pBucket = &(pNameTable->HashBuckets[i]);
|
|
|
|
InitializeListHead(&pBucket->ListHead);
|
|
pBucket->Count = 0;
|
|
|
|
}
|
|
} while (FALSE);
|
|
|
|
if ( Status == STATUS_SUCCESS ) {
|
|
|
|
*ppNameTable = pNameTable;
|
|
|
|
} else {
|
|
|
|
if (pNameTable != NULL) {
|
|
FREE_MEMORY( pNameTable );
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsInsertInNameTable - Inserts the passed in Entry into table
|
|
//
|
|
// Synopsis: DfsInsertInNameTable checks and makes sure that another entry
|
|
// with matching name does not already exist in the table.
|
|
// It Inserts the passed in Entry in the appropriate hash bucket,
|
|
// The callers needs to take a reference on the object and this
|
|
// reference is passed on to the name table. The name table does
|
|
// not explicitly take a reference on the Entry object.
|
|
//
|
|
//
|
|
// Arguments: pEntry - The Entry to be inserted
|
|
//
|
|
// Returns: Status
|
|
// STATUS_OBJECT_NAME_COLLISION if name already exists in table
|
|
// STATUS_SUCCESS otherwise
|
|
//
|
|
//
|
|
// Description: The object representing the entry is assumed to be completely
|
|
// setup at the point it is
|
|
// inserted in the name table. Future lookup requests will
|
|
// find the entry.
|
|
// This call checks the name table to see if the Named Entry in
|
|
// specified Naming Context already exists. If it does, we cannot
|
|
// insert this entry, and return STATUS_OBJECT_NAME_COLLISION.
|
|
// In all other cases, the entry is inserted in the appro<priate
|
|
// bucket, and we are done.
|
|
// A reference is held on the Entry that is added to the name table.
|
|
// This reference needs to be taken by the caller of this function.
|
|
// The caller passes on that reference to the name table if this
|
|
// function returns STATUS_SUCCESS. (In all other cases, the
|
|
// caller needs to take appropriate action: either dereference the
|
|
// Entry or destro<y it.)
|
|
// This reference is released when the Entry is removed from the
|
|
// name table.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsInsertInNameTableLocked(
|
|
IN PDFS_NAME_TABLE pNameTable,
|
|
IN PUNICODE_STRING pName,
|
|
IN PVOID pData )
|
|
{
|
|
ULONG BucketNum;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PDFS_NAME_TABLE_ENTRY pEntry;
|
|
PDFS_NAME_TABLE_ENTRY pMatchingEntry;
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
|
|
GET_NAME_TABLE_BUCKET(pName, pNameTable, BucketNum);
|
|
|
|
// No lock necessary to get the list head. The nametable is static.
|
|
pBucket = &pNameTable->HashBuckets[BucketNum];
|
|
|
|
|
|
// Check Name table will check the specified name in the given bucket.
|
|
// and returns the status of the check. This call does not hold a reference
|
|
// on the matching entry, if one exists. So handle with care. (Dont access it
|
|
// after the bucket lock is released)
|
|
|
|
Status = DfsCheckNameTable( pName,
|
|
pBucket,
|
|
&pMatchingEntry);
|
|
|
|
// If the name already exists, then we fail the request. For all other
|
|
// error conditions except OBJECT_NOT_FOUND, return failure status intact.
|
|
// In case the object is not found, it is safe to insert this in the bucket,
|
|
// and return success.
|
|
if ( Status == STATUS_SUCCESS ) {
|
|
Status = STATUS_OBJECT_NAME_COLLISION;
|
|
} else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
|
|
|
|
pEntry = ALLOCATE_MEMORY(sizeof(DFS_NAME_TABLE_ENTRY));
|
|
if (pEntry != NULL) {
|
|
pEntry->pName = pName;
|
|
pEntry->pData = pData;
|
|
InsertHeadList(&pBucket->ListHead, &pEntry->NameTableLink);
|
|
pBucket->Count++;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsLookupNameTable - Looks for a name in the name table
|
|
//
|
|
// Arguments: lookupName - Unicode string of Entry
|
|
// lookupNC - The Naming Context of interest
|
|
// ppMatchEntry - The matching entry to return if found.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_OBJECT_NOT_FOUND if the matching name and NC is not
|
|
// found in the name table.
|
|
// STATUS_SUCCESS Otherwise.
|
|
//
|
|
//
|
|
// Description: The Entry is assumed to be completely setup at the point it is
|
|
// inserted in the name table. Future lookup requests will
|
|
// lookup the entry.
|
|
// This call checks the name table to see if the Named entry in the
|
|
// specified Naming Context already exists. If it does, we cannot
|
|
// insert this entry, and return STATUS_OBJECT_NAME_COLLISION.
|
|
// In all other cases, the entry is inserted in the appropriate
|
|
// bucket, and we are done.
|
|
// A reference is held on the entry that is added to the name table.
|
|
// This reference needs to be taken by the caller of this function.
|
|
// The caller passes on that reference to the name table if this
|
|
// function returns STATUS_SUCCESS. (In all other cases, the
|
|
// caller needs to take appropriate action: either dereference the
|
|
// entry or destroy it.)
|
|
// This reference is released when the entry is removed from the
|
|
// name table.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsLookupNameTableLocked(
|
|
IN PDFS_NAME_TABLE pNameTable,
|
|
IN PUNICODE_STRING pLookupName,
|
|
OUT PVOID *ppData )
|
|
{
|
|
|
|
ULONG BucketNum;
|
|
NTSTATUS Status;
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
PDFS_NAME_TABLE_ENTRY pMatchEntry;
|
|
|
|
GET_NAME_TABLE_BUCKET( pLookupName, pNameTable, BucketNum );
|
|
|
|
pBucket = &pNameTable->HashBuckets[BucketNum];
|
|
|
|
Status = DfsCheckNameTable( pLookupName,
|
|
pBucket,
|
|
&pMatchEntry );
|
|
if (Status == STATUS_SUCCESS) {
|
|
*ppData = pMatchEntry->pData;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsGetEntryNameTableLocked - Looks for a name in the name table
|
|
//
|
|
// Arguments: lookupName - Unicode string of Entry
|
|
// lookupNC - The Naming Context of interest
|
|
// ppMatchEntry - The matching entry to return if found.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_OBJECT_NOT_FOUND if the matching name and NC is not
|
|
// found in the name table.
|
|
// STATUS_SUCCESS Otherwise.
|
|
//
|
|
//
|
|
// Description: The Entry is assumed to be completely setup at the point it is
|
|
// inserted in the name table. Future lookup requests will
|
|
// lookup the entry.
|
|
// This call checks the name table to see if the Named entry in the
|
|
// specified Naming Context already exists. If it does, we cannot
|
|
// insert this entry, and return STATUS_OBJECT_NAME_COLLISION.
|
|
// In all other cases, the entry is inserted in the appropriate
|
|
// bucket, and we are done.
|
|
// A reference is held on the entry that is added to the name table.
|
|
// This reference needs to be taken by the caller of this function.
|
|
// The caller passes on that reference to the name table if this
|
|
// function returns STATUS_SUCCESS. (In all other cases, the
|
|
// caller needs to take appropriate action: either dereference the
|
|
// entry or destroy it.)
|
|
// This reference is released when the entry is removed from the
|
|
// name table.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsGetEntryNameTableLocked(
|
|
IN PDFS_NAME_TABLE pNameTable,
|
|
OUT PVOID *ppData )
|
|
{
|
|
|
|
ULONG BucketNum;
|
|
NTSTATUS Status = STATUS_NOT_FOUND;
|
|
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
PDFS_NAME_TABLE_ENTRY pEntry;
|
|
PLIST_ENTRY pListHead, pLink;
|
|
|
|
for (BucketNum = 0; BucketNum < pNameTable->NumBuckets; BucketNum++)
|
|
{
|
|
pBucket = &pNameTable->HashBuckets[BucketNum];
|
|
if (pBucket->Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
pListHead = &pBucket->ListHead;
|
|
pLink = pListHead->Flink;
|
|
if (pLink == pListHead)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
|
|
|
|
*ppData = pEntry->pData;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsCheckNameTable - Check for a name in the name table
|
|
//
|
|
// Arguments: lookupName - Unicode string of name
|
|
// lookupNC - The DFS Naming Context of interest
|
|
// pBucket - The bucket of interest.
|
|
// ppMatchEntry - The matching entry to return if found.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_OBJECT_NOT_FOUND if the matching name and NC is not
|
|
// found in the name table.
|
|
// STATUS_SUCCESS Otherwise.
|
|
//
|
|
//
|
|
// Description: It is assumed that appropriate locks are taken to traverse
|
|
// the links in the bucket.
|
|
// If an entry is found, it is returned without taking any
|
|
// references on the found object.
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS
|
|
DfsCheckNameTable(
|
|
IN PUNICODE_STRING pLookupName,
|
|
IN PDFS_NAME_TABLE_BUCKET pBucket,
|
|
OUT PDFS_NAME_TABLE_ENTRY *ppMatchEntry )
|
|
{
|
|
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|
PLIST_ENTRY pListHead, pLink;
|
|
PDFS_NAME_TABLE_ENTRY pEntry;
|
|
|
|
pListHead = &pBucket->ListHead;
|
|
|
|
for ( pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink ) {
|
|
|
|
pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
|
|
|
|
// If we find a matching Name, check if we are interested in a
|
|
// specific Naming context. If no naming context is specified, or the
|
|
// specified naming context matches, we have found our entry. Get a
|
|
// reference on the entry while the bucket is locked so the entry does
|
|
// not go away, and we can return avalid pointer to the caller.
|
|
// The caller is responsible for releasing this reference.
|
|
if (RtlCompareUnicodeString(pEntry->pName, pLookupName, TRUE) == 0) {
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// If we did find an entry, return it
|
|
if ( Status == STATUS_SUCCESS ) {
|
|
*ppMatchEntry = pEntry;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsRemoveFromNameTable - Removes the specified entry
|
|
// from the name table
|
|
//
|
|
// Arguments: pEntry - The entry to be removed.
|
|
//
|
|
// Returns: Status
|
|
// STATUS_SUCCESS if the specified entry was successfully removed.
|
|
// STATUS_NOT_FOUND if the specifed entry is not the entry in the
|
|
// table for that entry name.
|
|
// STATUS_OBJECT_NAME_NOT_FOUND if the entry name does not exist
|
|
// in the table
|
|
//
|
|
// Description: The passed in entry is expected to a valid pointer that will
|
|
// not be freed up while we are referencing it.
|
|
// We check for an object in the name table for a matching name.
|
|
// If the object in the name table matches the passed in object,
|
|
// we can safely remove it from the name table. When we do so,
|
|
// we also release the reference on the object that was held
|
|
// when the object was inserted into the table.
|
|
// If the object is not found or the object does not match the
|
|
// one in the table, error status is returned.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsRemoveFromNameTableLocked(
|
|
IN struct _DFS_NAME_TABLE *pNameTable,
|
|
IN PUNICODE_STRING pLookupName,
|
|
IN PVOID pData )
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PDFS_NAME_TABLE_ENTRY pMatchingEntry;
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
ULONG BucketNum;
|
|
|
|
|
|
GET_NAME_TABLE_BUCKET(pLookupName, pNameTable, BucketNum );
|
|
// No lock necessary to get the list head. The nametable is static.
|
|
pBucket = &pNameTable->HashBuckets[BucketNum];
|
|
|
|
// Check Name table will check the specified name in the given bucket.
|
|
// and returns the status of the check. This call does not hold a reference
|
|
// on the matching entry, if one exists. So handle with care. (Dont access
|
|
// it after the bucket lock is released)
|
|
|
|
Status = DfsCheckNameTable( pLookupName,
|
|
pBucket,
|
|
&pMatchingEntry);
|
|
|
|
|
|
// If we found an entry for the specified Name and NC, and the entry
|
|
// matches the pointer passed in, we remove the entry from the bucket.
|
|
// If the object does not match, we set the status to STATUS_NOT_FOUND,
|
|
// to indicate that the name of the object exists in the table, but
|
|
// the object in the table is different.
|
|
|
|
if ( Status == STATUS_SUCCESS ) {
|
|
if ( (pData == NULL) || (pMatchingEntry->pData == pData) ) {
|
|
RemoveEntryList(&pMatchingEntry->NameTableLink);
|
|
FREE_MEMORY( pMatchingEntry );
|
|
pBucket->Count--;
|
|
} else {
|
|
Status = STATUS_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsReplaceInNameTable - Removes an entry by the specified name,
|
|
// if one exists. The passed in entry is
|
|
// inserted into the table.
|
|
//
|
|
// Arguments: pNewEntry - The entry to be inserted in the table
|
|
//
|
|
// Returns: Status
|
|
// STATUS_SUCCESS if the passed in entry was inserted in the table
|
|
//
|
|
// Description: The caller needs to hold a reference to the passed in entry,
|
|
// and this reference is transferred to the name table.
|
|
// If the name exists in the name table, the object is removed
|
|
// from the nametable and its reference is discarded.
|
|
// The passed in object is inserted in the same bucket.
|
|
// This call allows an atomic replace of the entry object,
|
|
// avoiding a window during which a valid name may not be found
|
|
// in the name table.
|
|
//
|
|
// Note that the newentry being passed in may already be
|
|
// in the table (due to multiple threads doing this work) so
|
|
// that special situation should work.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsReplaceInNameTableLocked (
|
|
IN PDFS_NAME_TABLE pNameTable,
|
|
IN PUNICODE_STRING pLookupName,
|
|
IN OUT PVOID *ppData )
|
|
{
|
|
PDFS_NAME_TABLE_ENTRY pEntry;
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
ULONG BucketNum;
|
|
PVOID pOldData = NULL;
|
|
NTSTATUS Status;
|
|
|
|
GET_NAME_TABLE_BUCKET(pLookupName, pNameTable, BucketNum );
|
|
// No lock necessary to get the list head. The nametable is static.
|
|
pBucket = &pNameTable->HashBuckets[BucketNum];
|
|
|
|
// Check Name table will check the specified name in the given bucket.
|
|
// and returns the status of the check. This call does not hold a reference
|
|
// on the matching entry, if one exists. So handle with care. (Dont access
|
|
// it after the bucket lock is released)
|
|
|
|
Status = DfsCheckNameTable( pLookupName,
|
|
pBucket,
|
|
&pEntry );
|
|
|
|
// If we found a matching name, we remove it from the name table.
|
|
if ( Status == STATUS_SUCCESS ) {
|
|
pOldData = pEntry->pData;
|
|
pEntry->pName = pLookupName;
|
|
pEntry->pData = *ppData;
|
|
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
pEntry = ALLOCATE_MEMORY(sizeof(DFS_NAME_TABLE_ENTRY));
|
|
if (pEntry != NULL) {
|
|
pEntry->pName = pLookupName;
|
|
pEntry->pData = *ppData;
|
|
InsertHeadList(&pBucket->ListHead, &pEntry->NameTableLink);
|
|
pBucket->Count++;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if (Status == STATUS_SUCCESS) {
|
|
*ppData = pOldData;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DumpNameTable(
|
|
PDFS_NAME_TABLE pNameTable )
|
|
{
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
PLIST_ENTRY pListHead, pLink;
|
|
PDFS_NAME_TABLE_ENTRY pEntry;
|
|
ULONG i;
|
|
|
|
printf("Table %p type %x size %d RefCnt %d\n",
|
|
pNameTable,
|
|
DfsGetHeaderType(&pNameTable->DfsHeader),
|
|
DfsGetHeaderSize(&pNameTable->DfsHeader),
|
|
DfsGetHeaderCount(&pNameTable->DfsHeader));
|
|
|
|
printf("Number of buckets %d\n", pNameTable->NumBuckets);
|
|
|
|
for ( i = 0; i < pNameTable->NumBuckets; i++ ) {
|
|
pBucket = &pNameTable->HashBuckets[i];
|
|
if ( pBucket->Count == 0 )
|
|
continue;
|
|
|
|
printf("Bucket %d Count in bucket %d\n",
|
|
i,
|
|
pBucket->Count);
|
|
|
|
pListHead = &pBucket->ListHead;
|
|
for ( pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink ) {
|
|
pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
|
|
|
|
printf("Found entry %p Name %wZ\n",
|
|
pEntry, pEntry->pName);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DfsDismantleNameTable(
|
|
PDFS_NAME_TABLE pNameTable )
|
|
|
|
{
|
|
PDFS_NAME_TABLE_BUCKET pBucket;
|
|
PLIST_ENTRY pListHead, pLink, pCurrent;
|
|
PDFS_NAME_TABLE_ENTRY pEntry;
|
|
ULONG i;
|
|
|
|
for ( i = 0; i < pNameTable->NumBuckets; i++ ) {
|
|
pBucket = &pNameTable->HashBuckets[i];
|
|
|
|
pListHead = &pBucket->ListHead;
|
|
for ( pLink = pListHead->Flink; pLink != pListHead; ) {
|
|
pCurrent = pLink;
|
|
pLink = pLink->Flink;
|
|
pEntry = CONTAINING_RECORD(pCurrent, DFS_NAME_TABLE_ENTRY, NameTableLink);
|
|
RemoveEntryList( pCurrent );
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DfsReferenceNameTable(
|
|
IN PDFS_NAME_TABLE pNameTable)
|
|
{
|
|
|
|
PDFS_OBJECT_HEADER pHeader = &pNameTable->DfsHeader;
|
|
USHORT headerType = DfsGetHeaderType( pHeader );
|
|
|
|
if ( headerType != DFS_OT_NAME_TABLE ) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
DfsIncrementReference( pHeader );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
DfsDereferenceNameTable(
|
|
IN PDFS_NAME_TABLE pNameTable)
|
|
|
|
{
|
|
|
|
PDFS_OBJECT_HEADER pHeader = &pNameTable->DfsHeader;
|
|
USHORT headerType = DfsGetHeaderType( pHeader );
|
|
LONG Ref;
|
|
|
|
if ( headerType != DFS_OT_NAME_TABLE ) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
Ref = DfsDecrementReference( pHeader );
|
|
if (Ref == 0) {
|
|
DeleteCriticalSection(pNameTable->pLock);
|
|
|
|
FREE_MEMORY(pNameTable);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DfsNameTableAcquireWriteLock(
|
|
IN PDFS_NAME_TABLE pNameTable )
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DFS_LOCK_NAME_TABLE(pNameTable, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DfsNameTableAcquireReadLock(
|
|
IN PDFS_NAME_TABLE pNameTable )
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DFS_LOCK_NAME_TABLE(pNameTable, Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
DfsNameTableReleaseLock(
|
|
IN PDFS_NAME_TABLE pNameTable )
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DFS_UNLOCK_NAME_TABLE(pNameTable);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DfsEnumerateNameTableLocked(
|
|
IN PDFS_NAME_TABLE pNameTable,
|
|
IN OUT PVOID *ppEnumerator,
|
|
OUT PVOID *ppData )
|
|
{
|
|
PDFS_NAME_TABLE_ENTRY pEntry = (PDFS_NAME_TABLE_ENTRY)*ppEnumerator;
|
|
ULONG BucketNum = 0;
|
|
NTSTATUS NtStatus = STATUS_NO_MORE_MATCHES;
|
|
PDFS_NAME_TABLE_BUCKET pBucket = NULL;
|
|
PLIST_ENTRY pListHead, pLink;
|
|
|
|
*ppEnumerator = NULL;
|
|
*ppData = NULL;
|
|
|
|
|
|
if (pEntry != NULL)
|
|
{
|
|
GET_NAME_TABLE_BUCKET(pEntry->pName, pNameTable, BucketNum);
|
|
}
|
|
|
|
for ( ; BucketNum < pNameTable->NumBuckets; BucketNum++)
|
|
{
|
|
pBucket = &pNameTable->HashBuckets[BucketNum];
|
|
if (pBucket->Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
pListHead = &pBucket->ListHead;
|
|
if (pEntry != NULL)
|
|
{
|
|
pLink = pEntry->NameTableLink.Flink;
|
|
pEntry = NULL;
|
|
}
|
|
else
|
|
{
|
|
pLink = pListHead->Flink;
|
|
}
|
|
if (pLink == pListHead)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pEntry = CONTAINING_RECORD(pLink, DFS_NAME_TABLE_ENTRY, NameTableLink);
|
|
|
|
*ppEnumerator = (PVOID)pEntry;
|
|
*ppData = pEntry->pData;
|
|
NtStatus = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|