2788 lines
86 KiB
C++
2788 lines
86 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 2000, Microsoft Corporation
|
|
//
|
|
// File: DfsStore.cxx
|
|
//
|
|
// Contents: the base DFS Store class, this contains the common
|
|
// store functionality.
|
|
//
|
|
// Classes: DfsStore.
|
|
//
|
|
// History: Dec. 8 2000, Author: udayh
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "DfsStore.hxx"
|
|
|
|
//
|
|
// logging stuff
|
|
//
|
|
|
|
#include "dfsstore.tmh"
|
|
|
|
|
|
// Initialize the common marshalling info for Registry and ADLegacy stores.
|
|
//
|
|
INIT_FILE_TIME_INFO();
|
|
INIT_DFS_REPLICA_INFO_MARSHAL_INFO();
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PackGetInfo - unpacks information based on MARSHAL_INFO struct
|
|
//
|
|
// Arguments: pInfo - pointer to the info to fill.
|
|
// ppBuffer - pointer to buffer that holds the binary stream.
|
|
// pSizeRemaining - pointer to size of above buffer
|
|
// pMarshalInfo - pointer to information that describes how to
|
|
// interpret the binary stream.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could unpack the name info
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine expects the binary stream to hold all the
|
|
// information that is necessary to return the information
|
|
// described by the MARSHAL_INFO structure.
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsStore::PackGetInformation(
|
|
ULONG_PTR Info,
|
|
PVOID *ppBuffer,
|
|
PULONG pSizeRemaining,
|
|
PMARSHAL_INFO pMarshalInfo )
|
|
{
|
|
PMARSHAL_TYPE_INFO typeInfo;
|
|
DFSSTATUS Status = ERROR_INVALID_DATA;
|
|
|
|
for ( typeInfo = &pMarshalInfo->_typeInfo[0];
|
|
typeInfo < &pMarshalInfo->_typeInfo[pMarshalInfo->_typecnt];
|
|
typeInfo++ )
|
|
{
|
|
|
|
switch ( typeInfo->_type & MTYPE_BASE_TYPE )
|
|
{
|
|
case MTYPE_COMPOUND:
|
|
Status = PackGetInformation(Info + typeInfo->_off,
|
|
ppBuffer,
|
|
pSizeRemaining,
|
|
typeInfo->_subinfo);
|
|
break;
|
|
|
|
case MTYPE_ULONG:
|
|
Status = PackGetULong( (PULONG)(Info + typeInfo->_off),
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
break;
|
|
|
|
case MTYPE_PWSTR:
|
|
Status = PackGetString( (PUNICODE_STRING)(Info + typeInfo->_off),
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
|
|
break;
|
|
|
|
case MTYPE_GUID:
|
|
|
|
Status = PackGetGuid( (GUID *)(Info + typeInfo->_off),
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PackSetInformation - packs information based on MARSHAL_INFO struct
|
|
//
|
|
// Arguments: pInfo - pointer to the info buffer to pack
|
|
// ppBuffer - pointer to buffer that holds the binary stream.
|
|
// pSizeRemaining - pointer to size of above buffer
|
|
// pMarshalInfo - pointer to information that describes how to
|
|
// pack the info into the binary stream.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could pack the info
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine expects the binary stream can hold all the
|
|
// information that is necessary to pack the information
|
|
// described by the MARSHAL_INFO structure.
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsStore::PackSetInformation(
|
|
ULONG_PTR Info,
|
|
PVOID *ppBuffer,
|
|
PULONG pSizeRemaining,
|
|
PMARSHAL_INFO pMarshalInfo )
|
|
{
|
|
PMARSHAL_TYPE_INFO typeInfo;
|
|
DFSSTATUS Status = ERROR_INVALID_DATA;
|
|
|
|
for ( typeInfo = &pMarshalInfo->_typeInfo[0];
|
|
typeInfo < &pMarshalInfo->_typeInfo[pMarshalInfo->_typecnt];
|
|
typeInfo++ )
|
|
{
|
|
|
|
switch ( typeInfo->_type & MTYPE_BASE_TYPE )
|
|
{
|
|
case MTYPE_COMPOUND:
|
|
Status = PackSetInformation( Info + typeInfo->_off,
|
|
ppBuffer,
|
|
pSizeRemaining,
|
|
typeInfo->_subinfo);
|
|
break;
|
|
|
|
case MTYPE_ULONG:
|
|
Status = PackSetULong( *(PULONG)(Info + typeInfo->_off),
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
break;
|
|
|
|
case MTYPE_PWSTR:
|
|
Status = PackSetString( (PUNICODE_STRING)(Info + typeInfo->_off),
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
|
|
break;
|
|
|
|
case MTYPE_GUID:
|
|
|
|
Status = PackSetGuid( (GUID *)(Info + typeInfo->_off),
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PackSizeInformation - packs information based on MARSHAL_INFO struct
|
|
//
|
|
// Arguments: pInfo - pointer to the info buffer to pack
|
|
// ppBuffer - pointer to buffer that holds the binary stream.
|
|
// pSizeRemaining - pointer to size of above buffer
|
|
// pMarshalInfo - pointer to information that describes how to
|
|
// pack the info into the binary stream.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could pack the info
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine expects the binary stream can hold all the
|
|
// information that is necessary to pack the information
|
|
// described by the MARSHAL_INFO structure.
|
|
//--------------------------------------------------------------------------
|
|
ULONG
|
|
DfsStore::PackSizeInformation(
|
|
ULONG_PTR Info,
|
|
PMARSHAL_INFO pMarshalInfo )
|
|
{
|
|
PMARSHAL_TYPE_INFO typeInfo;
|
|
ULONG Size = 0;
|
|
|
|
for ( typeInfo = &pMarshalInfo->_typeInfo[0];
|
|
typeInfo < &pMarshalInfo->_typeInfo[pMarshalInfo->_typecnt];
|
|
typeInfo++ )
|
|
{
|
|
|
|
switch ( typeInfo->_type & MTYPE_BASE_TYPE )
|
|
{
|
|
case MTYPE_COMPOUND:
|
|
Size += PackSizeInformation( Info + typeInfo->_off,
|
|
typeInfo->_subinfo);
|
|
break;
|
|
|
|
case MTYPE_ULONG:
|
|
Size += PackSizeULong();
|
|
|
|
break;
|
|
|
|
case MTYPE_PWSTR:
|
|
Size += PackSizeString( (PUNICODE_STRING)(Info + typeInfo->_off) );
|
|
|
|
break;
|
|
|
|
case MTYPE_GUID:
|
|
|
|
Size += PackSizeGuid();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PackGetReplicaInformation - Unpacks the replica info
|
|
//
|
|
// Arguments: pDfsReplicaInfo - pointer to the info to fill.
|
|
// ppBuffer - pointer to buffer that holds the binary stream.
|
|
// pSizeRemaining - pointer to size of above buffer
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could unpack the name info
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine expects the binary stream to hold all the
|
|
// information that is necessary to return a complete replica
|
|
// info structure (as defined by MiDfsReplicaInfo). If the stream
|
|
// does not have the sufficient info, ERROR_INVALID_DATA is
|
|
// returned back.
|
|
// This routine expects to find "replicaCount" number of individual
|
|
// binary streams in passed in buffer. Each stream starts with
|
|
// the size of the stream, followed by that size of data.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsStore::PackGetReplicaInformation(
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo,
|
|
PVOID *ppBuffer,
|
|
PULONG pSizeRemaining)
|
|
{
|
|
ULONG Count;
|
|
|
|
ULONG ReplicaSizeRemaining;
|
|
PVOID nextStream;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
for ( Count = 0; Count < pReplicaListInfo->ReplicaCount; Count++ )
|
|
{
|
|
PDFS_REPLICA_INFORMATION pReplicaInfo;
|
|
|
|
pReplicaInfo = &pReplicaListInfo->pReplicas[Count];
|
|
|
|
//
|
|
// We now have a binary stream in ppBuffer, the first word of which
|
|
// indicates the size of this stream.
|
|
//
|
|
Status = PackGetULong( &pReplicaInfo->DataSize,
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
|
|
|
|
//
|
|
// ppBuffer is now pointing past the size (to the binary stream)
|
|
// because UnpackUlong added size of ulong to it.
|
|
// Unravel that stream into the next array element.
|
|
// Note that when this unpack returns, the ppBuffer is not necessarily
|
|
// pointing to the next binary stream within this blob.
|
|
//
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
nextStream = *ppBuffer;
|
|
ReplicaSizeRemaining = pReplicaInfo->DataSize;
|
|
|
|
Status = PackGetInformation( (ULONG_PTR)pReplicaInfo,
|
|
ppBuffer,
|
|
&ReplicaSizeRemaining,
|
|
&MiDfsReplicaInfo );
|
|
//
|
|
// We now point the buffer to the next sub-stream, which is the previos
|
|
// stream + the size of the stream. We also set the remaining size
|
|
// appropriately.
|
|
//
|
|
*ppBuffer = (PVOID)((ULONG_PTR)nextStream + pReplicaInfo->DataSize);
|
|
*pSizeRemaining -= pReplicaInfo->DataSize;
|
|
|
|
}
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PackSetReplicaInformation - packs the replica info
|
|
//
|
|
// Arguments: pDfsReplicaInfo - pointer to the info to pack
|
|
// ppBuffer - pointer to buffer that holds the binary stream.
|
|
// pSizeRemaining - pointer to size of above buffer
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could pack the replica info
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine expects the binary stream to be able to
|
|
// hold the information that will be copied from the
|
|
// info structure (as defined by MiDfsReplicaInfo). If the stream
|
|
// does not have the sufficient info, ERROR_INVALID_DATA is
|
|
// returned back.
|
|
// This routine stores a "replicaCount" number of individual
|
|
// binary streams as the first ulong, and then it packs each
|
|
// stream.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsStore::PackSetReplicaInformation(
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo,
|
|
PVOID *ppBuffer,
|
|
PULONG pSizeRemaining)
|
|
{
|
|
ULONG Count;
|
|
|
|
ULONG ReplicaSizeRemaining;
|
|
PVOID nextStream;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
for ( Count = 0; Count < pReplicaListInfo->ReplicaCount; Count++ )
|
|
{
|
|
PDFS_REPLICA_INFORMATION pReplicaInfo;
|
|
|
|
pReplicaInfo = &pReplicaListInfo->pReplicas[Count];
|
|
|
|
//
|
|
// We now have a binary stream in ppBuffer, the first word of which
|
|
// indicates the size of this stream.
|
|
//
|
|
Status = PackSetULong( pReplicaInfo->DataSize,
|
|
ppBuffer,
|
|
pSizeRemaining );
|
|
|
|
//
|
|
// ppBuffer is now pointing past the size (to the binary stream)
|
|
// because packUlong added size of ulong to it.
|
|
// Unravel that stream into the next array element.
|
|
// Note that when this returns, the ppBuffer is not necessarily
|
|
// pointing to the next binary stream within this blob.
|
|
//
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
nextStream = *ppBuffer;
|
|
ReplicaSizeRemaining = pReplicaInfo->DataSize;
|
|
|
|
Status = PackSetInformation( (ULONG_PTR)pReplicaInfo,
|
|
ppBuffer,
|
|
&ReplicaSizeRemaining,
|
|
&MiDfsReplicaInfo );
|
|
|
|
//
|
|
// We now point the buffer to the next sub-stream, which is the previos
|
|
// stream + the size of the stream. We also set the remaining size
|
|
// appropriately.
|
|
//
|
|
*ppBuffer = (PVOID)((ULONG_PTR)nextStream + pReplicaInfo->DataSize);
|
|
*pSizeRemaining -= pReplicaInfo->DataSize;
|
|
}
|
|
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PackSizeReplicaInformation - packs the replica info
|
|
//
|
|
// Arguments: pDfsReplicaInfo - pointer to the info to pack
|
|
// ppBuffer - pointer to buffer that holds the binary stream.
|
|
// pSizeRemaining - pointer to size of above buffer
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could pack the replica info
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine expects the binary stream to be able to
|
|
// hold the information that will be copied from the
|
|
// info structure (as defined by MiDfsReplicaInfo). If the stream
|
|
// does not have the sufficient info, ERROR_INVALID_DATA is
|
|
// returned back.
|
|
// This routine stores a "replicaCount" number of individual
|
|
// binary streams as the first ulong, and then it packs each
|
|
// stream.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
ULONG
|
|
DfsStore::PackSizeReplicaInformation(
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo )
|
|
{
|
|
ULONG Count;
|
|
ULONG Size = 0;
|
|
|
|
for ( Count = 0; Count < pReplicaListInfo->ReplicaCount; Count++ )
|
|
{
|
|
PDFS_REPLICA_INFORMATION pReplicaInfo;
|
|
|
|
pReplicaInfo = &pReplicaListInfo->pReplicas[Count];
|
|
|
|
Size += PackSizeULong();
|
|
|
|
pReplicaInfo->DataSize = PackSizeInformation( (ULONG_PTR)pReplicaInfo,
|
|
&MiDfsReplicaInfo );
|
|
Size += pReplicaInfo->DataSize;
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: LookupRoot - Find a root
|
|
//
|
|
// Arguments: pContextName - the Dfs Name Context
|
|
// pLogicalShare - the Logical Share
|
|
// ppRoot - the DfsRootFolder that was found
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we found a matching root
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine takes a Dfs name context and logical share,
|
|
// and returns a Root that matches the passed in name
|
|
// context and logical share, if one exists.
|
|
// Note that the same DFS NC and logical share may exist
|
|
// in more than one store (though very unlikely). In this
|
|
// case, the first registered store wins.
|
|
// IF found, the reference root folder will be returned.
|
|
// It is the callers responsibility to release this referencce
|
|
// when the caller is done with this root.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsStore::LookupRoot(
|
|
PUNICODE_STRING pContextName,
|
|
PUNICODE_STRING pLogicalShare,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
DFSSTATUS Status;
|
|
DfsRootFolder *pRoot;
|
|
UNICODE_STRING DfsNetbiosNameContext;
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "Lookup root %wZ %wZ\n", pContextName, pLogicalShare);
|
|
//
|
|
// First, convert the context name to a netbios context name.
|
|
//
|
|
DfsGetNetbiosName( pContextName, &DfsNetbiosNameContext, NULL );
|
|
|
|
//
|
|
// Lock the store, so that we dont have new roots coming in while
|
|
// we are taking a look.
|
|
//
|
|
Status = AcquireReadLock();
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// The default return status is ERROR_NOT_FOUND;
|
|
//
|
|
Status = ERROR_NOT_FOUND;
|
|
|
|
//
|
|
// Run through our list of DFS roots, and see if any of them match
|
|
// the passed in name context and logical share.
|
|
//
|
|
|
|
pRoot = _DfsRootList;
|
|
|
|
if (pRoot != NULL)
|
|
{
|
|
do
|
|
{
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "Lookup root, checking root %wZ \n", pRoot->GetLogicalShare());
|
|
//
|
|
// If the Root indicates that the name context needs to be
|
|
// ignored, just check for logical share name match (aliasing
|
|
// support).
|
|
// Otherwise, compare the namecontext in the cases where
|
|
// the passed in name context is not empty.
|
|
//
|
|
if ( (pRoot->IsIgnoreNameContext() == TRUE) ||
|
|
(DfsNetbiosNameContext.Length != 0 &&
|
|
(RtlCompareUnicodeString(&DfsNetbiosNameContext,
|
|
pRoot->GetNetbiosNameContext(),
|
|
TRUE) == 0 )) )
|
|
{
|
|
if ( RtlCompareUnicodeString( pLogicalShare,
|
|
pRoot->GetLogicalShare(),
|
|
TRUE) == 0 )
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
pRoot = pRoot->pNextRoot;
|
|
} while ( pRoot != _DfsRootList );
|
|
}
|
|
|
|
//
|
|
// IF we found a matching root, bump up its reference count, and
|
|
// return the pointer to the root.
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
pRoot->AcquireReference();
|
|
*ppRootFolder = pRoot;
|
|
|
|
}
|
|
|
|
ReleaseLock();
|
|
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Done Lookup root for %wZ, root %p status %x\n",
|
|
pLogicalShare, pRoot, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetRootPhysicalShare(
|
|
HKEY RootKey,
|
|
PUNICODE_STRING pRootPhysicalShare )
|
|
{
|
|
DFSSTATUS Status;
|
|
ULONG DataSize, DataType;
|
|
LPWSTR DfsRootShare = NULL;
|
|
|
|
Status = RegQueryInfoKey( RootKey, // Key
|
|
NULL, // Class string
|
|
NULL, // Size of class string
|
|
NULL, // Reserved
|
|
NULL, // # of subkeys
|
|
NULL, // max size of subkey name
|
|
NULL, // max size of class name
|
|
NULL, // # of values
|
|
NULL, // max size of value name
|
|
&DataSize, // max size of value data,
|
|
NULL, // security descriptor
|
|
NULL ); // Last write time
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
DfsRootShare = (LPWSTR) new BYTE [DataSize];
|
|
if ( DfsRootShare == NULL )
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else
|
|
{
|
|
Status = RegQueryValueEx( RootKey,
|
|
DfsRootShareValueName,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)DfsRootShare,
|
|
&DataSize );
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (DataType == REG_SZ)
|
|
{
|
|
RtlInitUnicodeString( pRootPhysicalShare, DfsRootShare );
|
|
}
|
|
else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
if (DfsRootShare != NULL)
|
|
{
|
|
delete [] DfsRootShare;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
DfsStore::ReleaseRootPhysicalShare(
|
|
PUNICODE_STRING pRootPhysicalShare )
|
|
{
|
|
delete [] pRootPhysicalShare->Buffer;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetRootLogicalShare(
|
|
HKEY RootKey,
|
|
PUNICODE_STRING pRootLogicalShare )
|
|
{
|
|
DFSSTATUS Status;
|
|
ULONG DataSize, DataType;
|
|
LPWSTR DfsRootShare = NULL;
|
|
|
|
Status = RegQueryInfoKey( RootKey, // Key
|
|
NULL, // Class string
|
|
NULL, // Size of class string
|
|
NULL, // Reserved
|
|
NULL, // # of subkeys
|
|
NULL, // max size of subkey name
|
|
NULL, // max size of class name
|
|
NULL, // # of values
|
|
NULL, // max size of value name
|
|
&DataSize, // max size of value data,
|
|
NULL, // security descriptor
|
|
NULL ); // Last write time
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
DfsRootShare = (LPWSTR) new BYTE [DataSize];
|
|
if ( DfsRootShare == NULL )
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
} else
|
|
{
|
|
Status = RegQueryValueEx( RootKey,
|
|
DfsLogicalShareValueName,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)DfsRootShare,
|
|
&DataSize );
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (DataType == REG_SZ)
|
|
{
|
|
RtlInitUnicodeString( pRootLogicalShare, DfsRootShare );
|
|
}
|
|
else {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
if (DfsRootShare != NULL)
|
|
{
|
|
delete [] DfsRootShare;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
DfsStore::ReleaseRootLogicalShare(
|
|
PUNICODE_STRING pRootLogicalShare )
|
|
{
|
|
delete [] pRootLogicalShare->Buffer;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: StoreRecognizeNewDfs - the recognizer for new style dfs
|
|
//
|
|
// Arguments: Name - the namespace of interest.
|
|
// DfsKey - the key for the DFS registry space.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS on success
|
|
// ERROR status code otherwise
|
|
//
|
|
//
|
|
// Description: This routine looks up all the standalone roots
|
|
// hosted on this machine, and looks up the metadata for
|
|
// the roots and either creates new roots or updates existing
|
|
// ones to reflect the current children of the root.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsStore::StoreRecognizeNewDfs(
|
|
LPWSTR MachineName,
|
|
HKEY DfsKey )
|
|
{
|
|
DfsRootFolder *pRootFolder;
|
|
HKEY DfsRootKey;
|
|
DFSSTATUS Status;
|
|
ULONG ChildNum = 0;
|
|
|
|
DFS_TRACE_LOW(REFERRAL_SERVER, "Attempting to recognize new DFS\n");
|
|
do
|
|
{
|
|
//
|
|
// For each child, get the child name.
|
|
//
|
|
|
|
DWORD ChildNameLen = DFS_REGISTRY_CHILD_NAME_SIZE_MAX;
|
|
WCHAR ChildName[DFS_REGISTRY_CHILD_NAME_SIZE_MAX];
|
|
|
|
//
|
|
// Now enumerate the children, starting from the first child.
|
|
//
|
|
Status = RegEnumKeyEx( DfsKey,
|
|
ChildNum,
|
|
ChildName,
|
|
&ChildNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
ChildNum++;
|
|
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
DFS_TRACE_LOW(REFERRAL_SERVER, "Recognize New Dfs, found root (#%d) with metaname %ws\n", ChildNum, ChildName );
|
|
//
|
|
// We have the name of a child, so open the key to
|
|
// that root.
|
|
//
|
|
Status = RegOpenKeyEx( DfsKey,
|
|
ChildName,
|
|
0,
|
|
KEY_READ,
|
|
&DfsRootKey );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now get either an existing root by this name,
|
|
// or create a new one.
|
|
//
|
|
Status = GetRootFolder( MachineName,
|
|
ChildName,
|
|
DfsRootKey,
|
|
&pRootFolder );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
DFSSTATUS RootStatus;
|
|
|
|
//
|
|
// Call the synchronize method on the root to
|
|
// update it with the latest children.
|
|
// Again, ignore the error since we need to move
|
|
// on to the next root.
|
|
// dfsdev: need eventlog to signal this.
|
|
//
|
|
RootStatus = pRootFolder->Synchronize();
|
|
|
|
DFS_TRACE_ERROR_LOW(RootStatus, REFERRAL_SERVER, "Recognize DFS: Root folder for %ws, Synchronize status %x\n",
|
|
ChildName, RootStatus );
|
|
|
|
// Release our reference on the root folder.
|
|
|
|
pRootFolder->ReleaseReference();
|
|
}
|
|
|
|
//
|
|
// Close the root key, we are done with it.
|
|
//
|
|
RegCloseKey( DfsRootKey );
|
|
}
|
|
}
|
|
|
|
} while (Status == ERROR_SUCCESS);
|
|
|
|
//
|
|
// If we ran out of children, then return success code.
|
|
//
|
|
if (Status == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Done with recognize new dfs, Status %x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsGetRootFolder - Get a root folder if the machine
|
|
// hosts a registry based DFS.
|
|
//
|
|
// Arguments: Name - the namespace of interest.
|
|
// Key - the root key
|
|
// ppRootFolder - the created folder.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS on success
|
|
// ERROR status code otherwise
|
|
//
|
|
//
|
|
// Description: This routine reads in the information
|
|
// about the root and creates and adds it to our
|
|
// list of known roots, if this one does not already
|
|
// exist in our list.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetRootFolder (
|
|
LPWSTR DfsNameContextString,
|
|
LPWSTR RootRegKeyName,
|
|
HKEY DfsRootKey,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
DFSSTATUS Status;
|
|
UNICODE_STRING LogicalShare;
|
|
UNICODE_STRING PhysicalShare;
|
|
|
|
//
|
|
// Get the logical name information of this root.
|
|
//
|
|
|
|
Status = GetRootLogicalShare( DfsRootKey,
|
|
&LogicalShare );
|
|
|
|
|
|
//
|
|
// we successfully got the logical share, now get the physical share
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
Status = GetRootPhysicalShare( DfsRootKey,
|
|
&PhysicalShare );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
PhysicalShare = LogicalShare;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
Status = GetRootFolder ( DfsNameContextString,
|
|
RootRegKeyName,
|
|
&LogicalShare,
|
|
&PhysicalShare,
|
|
ppRootFolder );
|
|
|
|
//
|
|
// Normally, we get the physical share from the registry. If that failed,
|
|
// we dont treat it as fatal, and just use the logical share as the physical one.
|
|
// If we ever did that, detect the case and dont
|
|
// release the physical server.
|
|
//
|
|
// Otherwise, free up the buffer we allocated earlier on
|
|
// at this point.
|
|
//
|
|
|
|
if (PhysicalShare.Buffer != LogicalShare.Buffer)
|
|
{
|
|
ReleaseRootPhysicalShare( &PhysicalShare );
|
|
}
|
|
|
|
ReleaseRootLogicalShare( &LogicalShare );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetRootFolder (
|
|
LPWSTR DfsNameContextString,
|
|
LPWSTR RootRegKeyName,
|
|
PUNICODE_STRING pLogicalShare,
|
|
PUNICODE_STRING pPhysicalShare,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
UNICODE_STRING DfsNameContext;
|
|
|
|
DFS_TRACE_LOW(REFERRAL_SERVER, "Get Root Folder for %wZ\n", pLogicalShare);
|
|
//
|
|
// we have bot the logical DFS share name, as well as the local machine
|
|
// physical share that is backing the DFS logical share.
|
|
// now get a root folder for this dfs root.
|
|
//
|
|
|
|
RtlInitUnicodeString( &DfsNameContext, DfsNameContextString );
|
|
|
|
//
|
|
// Check if we already know about this root. If we do, this
|
|
// routine gives us a referenced root folder which we can return.
|
|
// If not, we create a brand new root folder.
|
|
//
|
|
|
|
Status = LookupRoot( &DfsNameContext,
|
|
pLogicalShare,
|
|
ppRootFolder );
|
|
|
|
//
|
|
// we did not find a root, so create a new one.
|
|
//
|
|
if ( Status != STATUS_SUCCESS )
|
|
{
|
|
Status = CreateNewRootFolder( DfsNameContextString,
|
|
RootRegKeyName,
|
|
pLogicalShare,
|
|
pPhysicalShare,
|
|
ppRootFolder );
|
|
|
|
DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Created New Dfs Root %p, Share %wZ, Status %x\n",
|
|
*ppRootFolder, pPhysicalShare, Status);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There is an existing root with this name.
|
|
// Validate that the root we looked up matches the
|
|
// metadata we are currently processing. If not, we
|
|
// have 2 roots with the same logical share name in the
|
|
// registry which is bogus.
|
|
|
|
//
|
|
// Dfs dev: rip out the following code.
|
|
// just check for equality of the 2 roots.
|
|
// they will not be null strings
|
|
//
|
|
if (RootRegKeyName != NULL)
|
|
{
|
|
if (_wcsicmp(RootRegKeyName,
|
|
(*ppRootFolder)->GetRootRegKeyNameString()) != 0)
|
|
{
|
|
(*ppRootFolder)->ReleaseReference();
|
|
*ppRootFolder = NULL;
|
|
Status = ERROR_DUP_NAME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsEmptyString((*ppRootFolder)->GetRootRegKeyNameString()) == FALSE)
|
|
{
|
|
(*ppRootFolder)->ReleaseReference();
|
|
*ppRootFolder = NULL;
|
|
Status = ERROR_DUP_NAME;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the above comparison matched, we found a root for the
|
|
// logical volume, make sure that the physical share names
|
|
// that is exported on the local machine to back the logical share
|
|
// matches.
|
|
//
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (RtlCompareUnicodeString( pPhysicalShare,
|
|
(*ppRootFolder)->GetRootPhysicalShareName(),
|
|
TRUE ) != 0)
|
|
{
|
|
//
|
|
// dfsdev: use appropriate status code.
|
|
//
|
|
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "GetRootFolder: Root %p, Status %x\n",
|
|
*ppRootFolder, Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::PackageEnumerationInfo(
|
|
DWORD Level,
|
|
DWORD EntryCount,
|
|
LPBYTE pLinkBuffer,
|
|
LPBYTE pBuffer,
|
|
LPBYTE *ppCurrentBuffer,
|
|
PLONG pSizeRemaining )
|
|
{
|
|
PDFS_API_INFO pInfo;
|
|
PDFS_API_INFO pCurrent = (PDFS_API_INFO)pLinkBuffer;
|
|
LONG HeaderSize;
|
|
ULONG_PTR NextFreeMemory;
|
|
PDFS_STORAGE_INFO pNewStorage, pOldStorage;
|
|
LONG TotalStores, i;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
LONG NeedLen;
|
|
|
|
NextFreeMemory = (ULONG_PTR)*ppCurrentBuffer;
|
|
|
|
HeaderSize = DfsApiSizeLevelHeader( Level );
|
|
pInfo = (PDFS_API_INFO)((ULONG_PTR)pBuffer + HeaderSize * EntryCount);
|
|
|
|
RtlCopyMemory( pInfo, pLinkBuffer, HeaderSize );
|
|
|
|
pNewStorage = NULL;
|
|
|
|
switch (Level)
|
|
{
|
|
case 4:
|
|
if (pNewStorage == NULL)
|
|
{
|
|
pNewStorage = pInfo->Info4.Storage = (PDFS_STORAGE_INFO)NextFreeMemory;
|
|
pOldStorage = pCurrent->Info4.Storage;
|
|
TotalStores = pInfo->Info4.NumberOfStorages;
|
|
}
|
|
|
|
case 3:
|
|
if (pNewStorage == NULL)
|
|
{
|
|
pNewStorage = pInfo->Info3.Storage = (PDFS_STORAGE_INFO)NextFreeMemory;
|
|
pOldStorage = pCurrent->Info3.Storage;
|
|
TotalStores = pInfo->Info3.NumberOfStorages;
|
|
}
|
|
|
|
NeedLen = sizeof(DFS_STORAGE_INFO) * TotalStores;
|
|
if (*pSizeRemaining >= NeedLen) {
|
|
*pSizeRemaining -= NeedLen;
|
|
NextFreeMemory += NeedLen;
|
|
}
|
|
else{
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
for (i = 0; i < TotalStores; i++)
|
|
{
|
|
pNewStorage[i] = pOldStorage[i];
|
|
|
|
pNewStorage[i].ServerName = (LPWSTR)NextFreeMemory;
|
|
NeedLen = (wcslen(pOldStorage[i].ServerName) + 1) * sizeof(WCHAR);
|
|
if (*pSizeRemaining >= NeedLen)
|
|
{
|
|
*pSizeRemaining -= NeedLen;
|
|
wcscpy(pNewStorage[i].ServerName,
|
|
pOldStorage[i].ServerName);
|
|
NextFreeMemory += NeedLen;
|
|
}
|
|
else {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
pNewStorage[i].ShareName = (LPWSTR)NextFreeMemory;
|
|
NeedLen = (wcslen(pOldStorage[i].ShareName) + 1) * sizeof(WCHAR);
|
|
if (*pSizeRemaining >= NeedLen)
|
|
{
|
|
*pSizeRemaining -= NeedLen;
|
|
wcscpy(pNewStorage[i].ShareName, pOldStorage[i].ShareName);
|
|
NextFreeMemory += NeedLen;
|
|
}
|
|
else {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
|
|
case 2:
|
|
pInfo->Info2.Comment = (LPWSTR)NextFreeMemory;
|
|
NeedLen = (wcslen(pCurrent->Info2.Comment) + 1) * sizeof(WCHAR);
|
|
if (*pSizeRemaining >= NeedLen)
|
|
{
|
|
*pSizeRemaining -= NeedLen;
|
|
wcscpy(pInfo->Info2.Comment, pCurrent->Info2.Comment);
|
|
NextFreeMemory += NeedLen;
|
|
}
|
|
else {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
case 1:
|
|
|
|
pInfo->Info1.EntryPath = (LPWSTR)NextFreeMemory;
|
|
|
|
NeedLen = (wcslen(pCurrent->Info1.EntryPath) + 1) * sizeof(WCHAR);
|
|
if (*pSizeRemaining >= NeedLen)
|
|
{
|
|
*pSizeRemaining -= NeedLen;
|
|
wcscpy(pInfo->Info1.EntryPath, pCurrent->Info1.EntryPath);
|
|
NextFreeMemory += NeedLen;
|
|
}
|
|
else {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
*ppCurrentBuffer = (LPBYTE)NextFreeMemory;
|
|
break;
|
|
|
|
default:
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if defined (OLD_ENUM_CODE)
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EnumerateRoots - enumerate all roots on the given machine
|
|
//
|
|
// Arguments:
|
|
// LPWSTR MachineName - name of the machine on which to enumerate.
|
|
// LPBYTE pBuffer, - the buffer to fill in
|
|
// ULONG BufferSize - the size of tghe buffer.
|
|
// PULONG pEntriesRead - the cumulative count of entries read.
|
|
// PULONG pSizeRequired - the total size required.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could pack the enumeartion info.
|
|
// ERROR_BUFFER_OVERFLOW if we ran out of space.
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine enumerates all the DFS roots on the
|
|
// specified machine.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DFSSTATUS
|
|
DfsStore::EnumerateRoots(
|
|
LPWSTR MachineName,
|
|
LPBYTE pBuffer,
|
|
ULONG BufferSize,
|
|
PULONG pEntriesRead,
|
|
PULONG pSizeRequired )
|
|
{
|
|
|
|
//
|
|
// Initialize the cumulative values we will be using.
|
|
//
|
|
ULONG TotalSize = 0;
|
|
ULONG EntriesRead = 0;
|
|
|
|
HKEY DfsKey, DfsFlavorKey;
|
|
ULONG_PTR CurrentBuffer = (ULONG_PTR)pBuffer;
|
|
ULONG CurrentSize = BufferSize;
|
|
BOOLEAN OverFlow = FALSE;
|
|
|
|
DFSSTATUS Status;
|
|
|
|
//
|
|
// open the old style key to the machine of interest.
|
|
//
|
|
Status = GetOldStandaloneRegistryKey( MachineName,
|
|
FALSE, // write permission not required
|
|
NULL,
|
|
&DfsKey );
|
|
|
|
//
|
|
// we now go to each flavor of dfs and enumerate that flavor.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = EnumerateOldFlavorRoot( DfsKey,
|
|
&CurrentBuffer,
|
|
&CurrentSize,
|
|
&EntriesRead,
|
|
&TotalSize );
|
|
RegCloseKey(DfsKey);
|
|
}
|
|
|
|
|
|
if (Status == ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
OverFlow = TRUE;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS ||
|
|
Status == ERROR_FILE_NOT_FOUND) {
|
|
|
|
Status = GetNewStandaloneRegistryKey( MachineName,
|
|
FALSE,
|
|
NULL,
|
|
&DfsFlavorKey );
|
|
|
|
//
|
|
// if we opened the standalone flavor key, enumerate it here.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = EnumerateFlavorRoot( DfsFlavorKey,
|
|
&CurrentBuffer,
|
|
&CurrentSize,
|
|
&EntriesRead,
|
|
&TotalSize );
|
|
//
|
|
// if we got buffer overflow, the TotalSize has been
|
|
// set to the size required. We will mark that we had
|
|
// an overflow, and change the status to error_Success
|
|
// so we can continue with enumeration of other flavors.
|
|
// we will use the overflow flag later on to return
|
|
// the appropriate error code.
|
|
//
|
|
|
|
if (Status == ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
OverFlow = TRUE;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
RegCloseKey( DfsFlavorKey );
|
|
}
|
|
}
|
|
//
|
|
// If we had no failures so far, move on to the ADBlob.
|
|
//
|
|
if (Status == ERROR_SUCCESS ||
|
|
Status == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
Status = GetNewADBlobRegistryKey( MachineName,
|
|
FALSE,
|
|
NULL,
|
|
&DfsFlavorKey );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = EnumerateFlavorRoot( DfsFlavorKey,
|
|
&CurrentBuffer,
|
|
&CurrentSize,
|
|
&EntriesRead,
|
|
&TotalSize );
|
|
//
|
|
// if we got buffer overflow, the TotalSize has been
|
|
// set to the size required. We will mark that we had
|
|
// an overflow, and change the status to error_Success
|
|
// so we can continue with enumeration of other flavors.
|
|
// we will use the overflow flag later on to return
|
|
// the appropriate error code.
|
|
//
|
|
|
|
if (Status == ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
OverFlow = TRUE;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
RegCloseKey( DfsFlavorKey );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// if we had no failures so far, we will return the cumulative values
|
|
// we have got so far. If we did run into an overflow case, we
|
|
// will also set the return code appropriately.
|
|
//
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (OverFlow == TRUE)
|
|
{
|
|
Status = ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
*pEntriesRead = EntriesRead;
|
|
*pSizeRequired = TotalSize;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EnumerateFlavorRoot - enumerate the roots for given flavor
|
|
//
|
|
// Arguments:
|
|
// HKEY DfsFlavorKey - the key to the flavor of interest
|
|
// PULONG_PTR pBuffer, - the buffer to fill in
|
|
// PULONG pBufferSize - the size of tghe buffer.
|
|
// PULONG pEntriesRead - the cumulative count of entries read.
|
|
// PULONG pSizeRequired - the total size required.
|
|
//
|
|
// Returns: Status
|
|
// ERROR_SUCCESS if we could pack the enumeartion info.
|
|
// ERROR_BUFFER_OVERFLOW if we ran out of space.
|
|
// error status otherwise.
|
|
//
|
|
//
|
|
// Description: This routine enumerates the keys under the passed in
|
|
// registry key, and reads the logical share info for each
|
|
// child. It packs this logical share info in the buffer
|
|
// passed in, if possible.
|
|
// On entry it expects the *pEntriesRead and *pSizeRequired
|
|
// to already hold previous enumeration values of other
|
|
// flavors, so these values are not initialized, but instead
|
|
// we use the values as starting point during this enumeartion.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::EnumerateFlavorRoot(
|
|
HKEY DfsFlavorKey,
|
|
PULONG_PTR pBuffer,
|
|
PULONG pBufferSize,
|
|
PULONG pEntriesRead,
|
|
PULONG pSizeRequired )
|
|
{
|
|
|
|
ULONG ChildNum = 0;
|
|
DFSSTATUS Status;
|
|
PDFS_INFO_200 pDfsInfo200;
|
|
|
|
ULONG TotalSize, EntriesRead;
|
|
HKEY DfsRootKey;
|
|
|
|
BOOLEAN OverFlow = FALSE;
|
|
|
|
//
|
|
// We start with total size and entries read with the passed in
|
|
// values, since we expect them to be initialized correctly, and
|
|
// possibly hold values from enumerations of other dfs flavors.
|
|
//
|
|
TotalSize = *pSizeRequired;
|
|
EntriesRead = *pEntriesRead;
|
|
|
|
//
|
|
// point the dfsinfo200 structure to the start of buffer passed in
|
|
// we will use this as an array of info200 buffers.
|
|
//
|
|
pDfsInfo200 = (PDFS_INFO_200)*pBuffer;
|
|
|
|
//
|
|
// now enumerate each child, and read its logical share name.
|
|
// update the total size required: if we have sufficient space
|
|
// in the passed in buffer, copy the information into the buffer.
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// For each child, get the child name.
|
|
//
|
|
|
|
DWORD ChildNameLen = DFS_REGISTRY_CHILD_NAME_SIZE_MAX;
|
|
WCHAR ChildName[DFS_REGISTRY_CHILD_NAME_SIZE_MAX];
|
|
//
|
|
// Now enumerate the children, starting from the first child.
|
|
//
|
|
Status = RegEnumKeyEx( DfsFlavorKey,
|
|
ChildNum,
|
|
ChildName,
|
|
&ChildNameLen,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
|
|
ChildNum++;
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "adding child %ws\n", ChildName);
|
|
// We have the name of a child, so open the key to
|
|
// that root.
|
|
//
|
|
Status = RegOpenKeyEx( DfsFlavorKey,
|
|
ChildName,
|
|
0,
|
|
KEY_READ,
|
|
&DfsRootKey );
|
|
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
Status = AddRootEnumerationInfo( DfsRootKey,
|
|
&pDfsInfo200,
|
|
pBufferSize,
|
|
&EntriesRead,
|
|
&TotalSize );
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
OverFlow = TRUE;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
RegCloseKey( DfsRootKey );
|
|
}
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "adding child %ws, Status %x\n", ChildName, Status);
|
|
}
|
|
} while (Status == ERROR_SUCCESS);
|
|
|
|
//
|
|
// if we broked out of the loop due to lack of children,
|
|
// update the return pointers correctly.
|
|
// if we had detected an overflow condition above, return overflow
|
|
// otherwise return success.
|
|
//
|
|
|
|
if (Status == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
*pEntriesRead = EntriesRead;
|
|
*pSizeRequired = TotalSize;
|
|
//
|
|
// the buffer is now pointing to the next unused pDfsInfo200 array
|
|
// entry: this lets the next enumerated flavor continue where
|
|
// we left off.
|
|
//
|
|
*pBuffer = (ULONG_PTR)pDfsInfo200;
|
|
if (OverFlow)
|
|
{
|
|
Status = ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "done with flavor read %x, Status %x\n",
|
|
*pEntriesRead, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::EnumerateOldFlavorRoot(
|
|
HKEY OldStandaloneDfsKey,
|
|
PULONG_PTR pBuffer,
|
|
PULONG pBufferSize,
|
|
PULONG pEntriesRead,
|
|
PULONG pSizeRequired )
|
|
{
|
|
DFSSTATUS Status;
|
|
PDFS_INFO_200 pDfsInfo200;
|
|
//
|
|
// point the dfsinfo200 structure to the start of buffer passed in
|
|
// we will use this as an array of info200 buffers.
|
|
//
|
|
pDfsInfo200 = (PDFS_INFO_200)*pBuffer;
|
|
|
|
Status = AddRootEnumerationInfo( OldStandaloneDfsKey,
|
|
&pDfsInfo200,
|
|
pBufferSize,
|
|
pEntriesRead,
|
|
pSizeRequired );
|
|
|
|
*pBuffer = (ULONG_PTR)pDfsInfo200;
|
|
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "enumeare old flavor: Read %d, Status %x\n", *pEntriesRead, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::AddRootEnumerationInfo(
|
|
HKEY RootKey,
|
|
PDFS_INFO_200 *ppDfsInfo200,
|
|
PULONG pBufferSize,
|
|
PULONG pEntriesRead,
|
|
PULONG pTotalSize )
|
|
{
|
|
ULONG NeedSize;
|
|
DWORD DataType;
|
|
DFSSTATUS Status;
|
|
WCHAR DataBuffer[MAX_PATH];
|
|
DWORD DataSize = MAX_PATH;
|
|
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "add root enum: Read %d\n", *pEntriesRead);
|
|
|
|
//
|
|
// The size of pDataBuffer is always fixed: so
|
|
// set the gotsize to the fixed size, and get the
|
|
// information reqarding the logical share value name.
|
|
//
|
|
Status = RegQueryValueEx( RootKey,
|
|
DfsLogicalShareValueName,
|
|
NULL,
|
|
&DataType,
|
|
(LPBYTE)DataBuffer,
|
|
&DataSize );
|
|
|
|
//
|
|
// if we got a valid buffer ( which is a string, type REG_SZ)
|
|
// we use that information.
|
|
//
|
|
|
|
if ((Status == ERROR_SUCCESS) && (DataType == REG_SZ))
|
|
{
|
|
//
|
|
// calculate size of string buffer space needed
|
|
//
|
|
DataSize = (wcslen(DataBuffer) + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// calculate amount of buffer space requirewd.
|
|
//
|
|
NeedSize = sizeof(DFS_INFO_200) + DataSize;
|
|
|
|
//
|
|
// if it fits in the amount of space we have, we
|
|
// can copy the info into the passed in buffer.
|
|
//
|
|
if (NeedSize <= *pBufferSize)
|
|
{
|
|
ULONG_PTR pStringBuffer;
|
|
//
|
|
// position the string buffer to the end of the buffer,
|
|
// leaving enough space to copy the string.
|
|
// This strategy allows us to treat the pDfsInfo200
|
|
// as an array, marching forward from the beginning
|
|
// of the buffer, while the strings are allocated
|
|
// starting from the end of the buffer, since we
|
|
// dont know how many pDfsInfo200 buffers we will
|
|
// be using.
|
|
//
|
|
pStringBuffer = (ULONG_PTR)(*ppDfsInfo200) + *pBufferSize - DataSize;
|
|
wcscpy( (LPWSTR)pStringBuffer, DataBuffer);
|
|
(*ppDfsInfo200)->FtDfsName = (LPWSTR)pStringBuffer;
|
|
*pBufferSize -= NeedSize;
|
|
(*pEntriesRead)++;
|
|
(*ppDfsInfo200)++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the size does not fit, we have overflowed.
|
|
//
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
//
|
|
// set the total size under all circumstances.
|
|
//
|
|
*pTotalSize += NeedSize;
|
|
}
|
|
//
|
|
// we may not find the logical share, if someone is in the process
|
|
// of writing registry:
|
|
//
|
|
if ((Status == ERROR_NOT_FOUND) ||
|
|
(Status == ERROR_FILE_NOT_FOUND))
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "add root enum: Read %d, Status %x\n", *pEntriesRead, Status);
|
|
return Status;
|
|
}
|
|
|
|
#else
|
|
|
|
DFSSTATUS
|
|
DfsStore::EnumerateRoots(
|
|
PULONG_PTR pBuffer,
|
|
PULONG pBufferSize,
|
|
PULONG pEntriesRead,
|
|
PULONG pSizeRequired )
|
|
{
|
|
|
|
ULONG RootNum = 0;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
DfsRootFolder *pRoot;
|
|
PDFS_INFO_200 pDfsInfo200;
|
|
|
|
ULONG TotalSize, EntriesRead;
|
|
BOOLEAN OverFlow = FALSE;
|
|
|
|
//
|
|
// We start with total size and entries read with the passed in
|
|
// values, since we expect them to be initialized correctly, and
|
|
// possibly hold values from enumerations of other dfs flavors.
|
|
//
|
|
TotalSize = *pSizeRequired;
|
|
EntriesRead = *pEntriesRead;
|
|
|
|
//
|
|
// point the dfsinfo200 structure to the start of buffer passed in
|
|
// we will use this as an array of info200 buffers.
|
|
//
|
|
pDfsInfo200 = (PDFS_INFO_200)*pBuffer;
|
|
|
|
//
|
|
// now enumerate each child, and read its logical share name.
|
|
// update the total size required: if we have sufficient space
|
|
// in the passed in buffer, copy the information into the buffer.
|
|
//
|
|
|
|
while (Status == ERROR_SUCCESS)
|
|
{
|
|
PUNICODE_STRING pRootName;
|
|
|
|
Status = FindNextRoot(RootNum++, &pRoot);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pRootName = pRoot->GetLogicalShare();
|
|
Status = AddRootEnumerationInfo( pRootName,
|
|
&pDfsInfo200,
|
|
pBufferSize,
|
|
&EntriesRead,
|
|
&TotalSize );
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
OverFlow = TRUE;
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "adding child %wZ, Status %x\n", pRootName, Status);
|
|
|
|
pRoot->ReleaseReference();
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// if we broked out of the loop due to lack of children,
|
|
// update the return pointers correctly.
|
|
// if we had detected an overflow condition above, return overflow
|
|
// otherwise return success.
|
|
//
|
|
|
|
if (Status == ERROR_NOT_FOUND)
|
|
{
|
|
*pEntriesRead = EntriesRead;
|
|
*pSizeRequired = TotalSize;
|
|
//
|
|
// the buffer is now pointing to the next unused pDfsInfo200 array
|
|
// entry: this lets the next enumerated flavor continue where
|
|
// we left off.
|
|
//
|
|
*pBuffer = (ULONG_PTR)pDfsInfo200;
|
|
if (OverFlow)
|
|
{
|
|
Status = ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "done with flavor read %x, Status %x\n",
|
|
*pEntriesRead, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::AddRootEnumerationInfo(
|
|
PUNICODE_STRING pRootName,
|
|
PDFS_INFO_200 *ppDfsInfo200,
|
|
PULONG pBufferSize,
|
|
PULONG pEntriesRead,
|
|
PULONG pTotalSize )
|
|
{
|
|
ULONG NeedSize;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "add root enum: Read %d\n", *pEntriesRead);
|
|
|
|
|
|
|
|
//
|
|
// calculate amount of buffer space requirewd.
|
|
//
|
|
NeedSize = sizeof(DFS_INFO_200) + pRootName->MaximumLength;
|
|
|
|
//
|
|
// if it fits in the amount of space we have, we
|
|
// can copy the info into the passed in buffer.
|
|
//
|
|
if (NeedSize <= *pBufferSize)
|
|
{
|
|
ULONG_PTR pStringBuffer;
|
|
//
|
|
// position the string buffer to the end of the buffer,
|
|
// leaving enough space to copy the string.
|
|
// This strategy allows us to treat the pDfsInfo200
|
|
// as an array, marching forward from the beginning
|
|
// of the buffer, while the strings are allocated
|
|
// starting from the end of the buffer, since we
|
|
// dont know how many pDfsInfo200 buffers we will
|
|
// be using.
|
|
//
|
|
pStringBuffer = (ULONG_PTR)(*ppDfsInfo200) + *pBufferSize - pRootName->MaximumLength;
|
|
wcscpy( (LPWSTR)pStringBuffer, pRootName->Buffer);
|
|
(*ppDfsInfo200)->FtDfsName = (LPWSTR)pStringBuffer;
|
|
*pBufferSize -= NeedSize;
|
|
(*pEntriesRead)++;
|
|
(*ppDfsInfo200)++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the size does not fit, we have overflowed.
|
|
//
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
//
|
|
// set the total size under all circumstances.
|
|
//
|
|
*pTotalSize += NeedSize;
|
|
|
|
|
|
DFS_TRACE_HIGH(REFERRAL_SERVER, "add root enum: Read %d, Status %x\n", *pEntriesRead, Status);
|
|
return Status;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::SetupADBlobRootKeyInformation(
|
|
HKEY DfsKey,
|
|
LPWSTR DfsLogicalShare,
|
|
LPWSTR DfsPhysicalShare )
|
|
{
|
|
|
|
DWORD Status;
|
|
HKEY FtDfsShareKey;
|
|
|
|
Status = RegCreateKeyEx( DfsKey,
|
|
DfsLogicalShare,
|
|
0,
|
|
L"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE,
|
|
NULL,
|
|
&FtDfsShareKey,
|
|
NULL );
|
|
|
|
//
|
|
// Now set the values for this root key, so that we know
|
|
// the DN for the root, and the physical share on the machine
|
|
// for the root, etc.
|
|
//
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = RegSetValueEx( FtDfsShareKey,
|
|
DfsRootShareValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)DfsPhysicalShare,
|
|
wcslen(DfsPhysicalShare) * sizeof(WCHAR) );
|
|
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
Status = RegSetValueEx( FtDfsShareKey,
|
|
DfsLogicalShareValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)DfsLogicalShare,
|
|
wcslen(DfsLogicalShare) * sizeof(WCHAR) );
|
|
|
|
}
|
|
|
|
RegCloseKey( FtDfsShareKey );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetMetadataNameInformation(
|
|
IN DFS_METADATA_HANDLE RootHandle,
|
|
IN LPWSTR MetadataName,
|
|
OUT PDFS_NAME_INFORMATION *ppInfo )
|
|
{
|
|
PVOID pBlob, pUseBlob;
|
|
ULONG BlobSize, UseBlobSize;
|
|
FILETIME BlobModifiedTime;
|
|
PDFS_NAME_INFORMATION pNewInfo = NULL;
|
|
DFSSTATUS Status;
|
|
|
|
Status = GetMetadataNameBlob( RootHandle,
|
|
MetadataName,
|
|
&pBlob,
|
|
&BlobSize,
|
|
&BlobModifiedTime );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pNewInfo = new DFS_NAME_INFORMATION;
|
|
if (pNewInfo != NULL)
|
|
{
|
|
RtlZeroMemory (pNewInfo, sizeof(DFS_NAME_INFORMATION));
|
|
|
|
pUseBlob = pBlob;
|
|
UseBlobSize = BlobSize;
|
|
Status = PackGetNameInformation( pNewInfo,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ReleaseMetadataNameBlob( pBlob, BlobSize );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pNewInfo->pData = pBlob;
|
|
pNewInfo->DataSize = BlobSize;
|
|
*ppInfo = pNewInfo;
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
DfsStore::ReleaseMetadataNameInformation(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
IN PDFS_NAME_INFORMATION pNameInfo )
|
|
{
|
|
UNREFERENCED_PARAMETER(DfsHandle);
|
|
|
|
ReleaseMetadataNameBlob( pNameInfo->pData,
|
|
pNameInfo->DataSize );
|
|
|
|
delete [] pNameInfo;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::SetMetadataNameInformation(
|
|
IN DFS_METADATA_HANDLE RootHandle,
|
|
IN LPWSTR MetadataName,
|
|
IN PDFS_NAME_INFORMATION pNameInfo )
|
|
{
|
|
PVOID pBlob;
|
|
ULONG BlobSize;
|
|
DFSSTATUS Status;
|
|
|
|
|
|
Status = CreateNameInformationBlob( pNameInfo,
|
|
&pBlob,
|
|
&BlobSize );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadataNameBlob( RootHandle,
|
|
MetadataName,
|
|
pBlob,
|
|
BlobSize );
|
|
|
|
ReleaseMetadataNameBlob( pBlob, BlobSize );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetMetadataReplicaInformation(
|
|
IN DFS_METADATA_HANDLE RootHandle,
|
|
IN LPWSTR MetadataName,
|
|
OUT PDFS_REPLICA_LIST_INFORMATION *ppInfo )
|
|
{
|
|
PVOID pBlob, pUseBlob;
|
|
ULONG BlobSize, UseBlobSize;
|
|
PDFS_REPLICA_LIST_INFORMATION pNewInfo;
|
|
DFSSTATUS Status;
|
|
|
|
|
|
Status = GetMetadataReplicaBlob( RootHandle,
|
|
MetadataName,
|
|
&pBlob,
|
|
&BlobSize,
|
|
NULL );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pNewInfo = new DFS_REPLICA_LIST_INFORMATION;
|
|
if (pNewInfo != NULL)
|
|
{
|
|
RtlZeroMemory (pNewInfo, sizeof(DFS_REPLICA_LIST_INFORMATION));
|
|
|
|
pUseBlob = pBlob;
|
|
UseBlobSize = BlobSize;
|
|
|
|
Status = PackGetULong( &pNewInfo->ReplicaCount,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pNewInfo->pReplicas = new DFS_REPLICA_INFORMATION[ pNewInfo->ReplicaCount];
|
|
if ( pNewInfo->pReplicas != NULL )
|
|
{
|
|
Status = PackGetReplicaInformation(pNewInfo,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
delete pNewInfo;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ReleaseMetadataReplicaBlob( pBlob, BlobSize );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pNewInfo->pData = pBlob;
|
|
pNewInfo->DataSize = BlobSize;
|
|
*ppInfo = pNewInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
DfsStore::ReleaseMetadataReplicaInformation(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo )
|
|
{
|
|
UNREFERENCED_PARAMETER(DfsHandle);
|
|
ReleaseMetadataReplicaBlob( pReplicaListInfo->pData,
|
|
pReplicaListInfo->DataSize );
|
|
|
|
delete [] pReplicaListInfo->pReplicas;
|
|
delete [] pReplicaListInfo;
|
|
|
|
}
|
|
|
|
DFSSTATUS
|
|
DfsStore::SetMetadataReplicaInformation(
|
|
IN DFS_METADATA_HANDLE RootHandle,
|
|
IN LPWSTR MetadataName,
|
|
IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo )
|
|
{
|
|
PVOID pBlob;
|
|
ULONG BlobSize;
|
|
DFSSTATUS Status;
|
|
|
|
Status = CreateReplicaListInformationBlob( pReplicaListInfo,
|
|
&pBlob,
|
|
&BlobSize );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadataReplicaBlob( RootHandle,
|
|
MetadataName,
|
|
pBlob,
|
|
BlobSize );
|
|
|
|
ReleaseMetadataReplicaBlob( pBlob, BlobSize );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::CreateNameInformationBlob(
|
|
IN PDFS_NAME_INFORMATION pDfsNameInfo,
|
|
OUT PVOID *ppBlob,
|
|
OUT PULONG pDataSize )
|
|
{
|
|
PVOID pBlob, pUseBlob;
|
|
ULONG BlobSize, UseBlobSize;
|
|
DFSSTATUS Status;
|
|
|
|
BlobSize = PackSizeNameInformation( pDfsNameInfo );
|
|
|
|
Status = AllocateMetadataNameBlob( &pBlob,
|
|
BlobSize );
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
pUseBlob = pBlob;
|
|
UseBlobSize = BlobSize;
|
|
|
|
// Pack the name information into the binary stream allocated.
|
|
//
|
|
Status = PackSetNameInformation( pDfsNameInfo,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ReleaseMetadataNameBlob( pBlob, BlobSize );
|
|
}
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
*ppBlob = pBlob;
|
|
*pDataSize = BlobSize - UseBlobSize;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::CreateReplicaListInformationBlob(
|
|
IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo,
|
|
OUT PVOID *ppBlob,
|
|
OUT PULONG pDataSize )
|
|
{
|
|
PVOID pBlob, pUseBlob;
|
|
ULONG BlobSize, UseBlobSize;
|
|
DFSSTATUS Status;
|
|
|
|
BlobSize = PackSizeULong();
|
|
BlobSize += PackSizeReplicaInformation( pReplicaListInfo );
|
|
|
|
BlobSize += PackSizeULong();
|
|
Status = AllocateMetadataReplicaBlob( &pBlob,
|
|
BlobSize );
|
|
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
pUseBlob = pBlob;
|
|
UseBlobSize = BlobSize;
|
|
|
|
|
|
//
|
|
// The first item in the stream is the number of replicas
|
|
//
|
|
Status = PackSetULong(pReplicaListInfo->ReplicaCount,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We than pack the array of replicas into the binary stream
|
|
//
|
|
Status = PackSetReplicaInformation( pReplicaListInfo,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We than pack the last word with a 0 so that all the
|
|
// old crap still works.
|
|
//
|
|
Status = PackSetULong( 0,
|
|
&pUseBlob,
|
|
&UseBlobSize );
|
|
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ReleaseMetadataReplicaBlob( pBlob, BlobSize );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
*ppBlob = pBlob;
|
|
*pDataSize = BlobSize - UseBlobSize;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::AddChildReplica (
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
LPWSTR LinkMetadataName,
|
|
LPWSTR ServerName,
|
|
LPWSTR SharePath )
|
|
{
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaList = NULL;
|
|
PDFS_REPLICA_INFORMATION pReplicaInfo;
|
|
DFS_REPLICA_LIST_INFORMATION NewList;
|
|
ULONG ReplicaIndex;
|
|
DFSSTATUS Status;
|
|
|
|
if ( (ServerName == NULL) || (SharePath == NULL) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetMetadataReplicaInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&pReplicaList );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
ReplicaIndex = FindReplicaInReplicaList( pReplicaList,
|
|
ServerName,
|
|
SharePath );
|
|
if (ReplicaIndex < pReplicaList->ReplicaCount)
|
|
{
|
|
Status = ERROR_FILE_EXISTS;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
RtlZeroMemory( &NewList, sizeof(DFS_REPLICA_LIST_INFORMATION));
|
|
NewList.ReplicaCount = pReplicaList->ReplicaCount + 1;
|
|
NewList.pReplicas = new DFS_REPLICA_INFORMATION [ NewList.ReplicaCount ];
|
|
if (NewList.pReplicas == NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
if (pReplicaList->ReplicaCount)
|
|
{
|
|
RtlCopyMemory( &NewList.pReplicas[0],
|
|
&pReplicaList->pReplicas[0],
|
|
pReplicaList->ReplicaCount * sizeof(DFS_REPLICA_INFORMATION) );
|
|
}
|
|
|
|
pReplicaInfo = &NewList.pReplicas[pReplicaList->ReplicaCount];
|
|
RtlZeroMemory( pReplicaInfo,
|
|
sizeof(DFS_REPLICA_INFORMATION) );
|
|
|
|
RtlInitUnicodeString(&pReplicaInfo->ServerName, ServerName);
|
|
RtlInitUnicodeString(&pReplicaInfo->ShareName, SharePath);
|
|
|
|
pReplicaInfo->ReplicaState = DFS_STORAGE_STATE_ONLINE;
|
|
pReplicaInfo->ReplicaType = 2; // hack fro backwards compat.
|
|
|
|
Status = SetMetadataReplicaInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&NewList );
|
|
delete [] NewList.pReplicas;
|
|
}
|
|
}
|
|
|
|
ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::RemoveChildReplica (
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
LPWSTR LinkMetadataName,
|
|
LPWSTR ServerName,
|
|
LPWSTR SharePath,
|
|
PBOOLEAN pLastReplica)
|
|
{
|
|
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaList;
|
|
DFS_REPLICA_LIST_INFORMATION NewList;
|
|
ULONG DeleteIndex;
|
|
ULONG NextIndex;
|
|
|
|
DFSSTATUS Status;
|
|
|
|
*pLastReplica = FALSE;
|
|
RtlZeroMemory( &NewList,
|
|
sizeof(DFS_REPLICA_LIST_INFORMATION));
|
|
|
|
|
|
if ( (ServerName == NULL) || (SharePath == NULL) )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetMetadataReplicaInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&pReplicaList );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
DeleteIndex = FindReplicaInReplicaList( pReplicaList,
|
|
ServerName,
|
|
SharePath );
|
|
if (DeleteIndex < pReplicaList->ReplicaCount)
|
|
{
|
|
NewList.ReplicaCount = pReplicaList->ReplicaCount - 1;
|
|
|
|
if (NewList.ReplicaCount)
|
|
{
|
|
NewList.pReplicas = new DFS_REPLICA_INFORMATION [NewList.ReplicaCount];
|
|
if (NewList.pReplicas != NULL)
|
|
{
|
|
if (DeleteIndex)
|
|
{
|
|
RtlCopyMemory( &NewList.pReplicas[0],
|
|
&pReplicaList->pReplicas[0],
|
|
DeleteIndex * sizeof(DFS_REPLICA_INFORMATION) );
|
|
}
|
|
|
|
NextIndex = DeleteIndex + 1;
|
|
|
|
if ( NextIndex < pReplicaList->ReplicaCount)
|
|
{
|
|
RtlCopyMemory( &NewList.pReplicas[DeleteIndex],
|
|
&pReplicaList->pReplicas[NextIndex],
|
|
(pReplicaList->ReplicaCount - NextIndex) * sizeof(DFS_REPLICA_INFORMATION) );
|
|
}
|
|
}
|
|
else {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = SetMetadataReplicaInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&NewList );
|
|
if (NewList.ReplicaCount == 0)
|
|
{
|
|
*pLastReplica = TRUE;
|
|
}
|
|
|
|
}
|
|
if (NewList.pReplicas != NULL)
|
|
{
|
|
delete [] NewList.pReplicas;
|
|
}
|
|
}
|
|
else {
|
|
Status = ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetStoreApiInformation(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
PUNICODE_STRING pRootName,
|
|
LPWSTR LinkMetadataName,
|
|
DWORD Level,
|
|
LPBYTE pBuffer,
|
|
LONG BufferSize,
|
|
PLONG pSizeRequired )
|
|
{
|
|
|
|
DFSSTATUS Status;
|
|
PDFS_NAME_INFORMATION pNameInformation = NULL;
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaList = NULL;
|
|
PDFS_REPLICA_INFORMATION pReplica;
|
|
|
|
PDFS_API_INFO pInfo = (PDFS_API_INFO)pBuffer;
|
|
DFS_API_INFO LocalInfo;
|
|
PDFS_STORAGE_INFO pStorage;
|
|
LONG HeaderSize = 0;
|
|
LONG AdditionalSize = 0;
|
|
UNICODE_STRING UsePrefixName;
|
|
|
|
ULONG i;
|
|
|
|
ULONG_PTR NextFreeMemory = NULL;
|
|
|
|
|
|
RtlZeroMemory(&LocalInfo, sizeof(DFS_API_INFO));
|
|
|
|
|
|
Status = GetMetadataNameInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&pNameInformation );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GenerateApiLogicalPath( pRootName,
|
|
&pNameInformation->Prefix,
|
|
&UsePrefixName );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = GetMetadataReplicaInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&pReplicaList );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
switch (Level)
|
|
{
|
|
case 100:
|
|
if (HeaderSize == 0)
|
|
{
|
|
HeaderSize = sizeof(DFS_INFO_100);
|
|
NextFreeMemory = (ULONG_PTR)(&pInfo->Info100 + 1);
|
|
}
|
|
AdditionalSize += pNameInformation->Comment.Length + sizeof(WCHAR);
|
|
break;
|
|
|
|
case 4:
|
|
if (HeaderSize == 0)
|
|
{
|
|
HeaderSize = sizeof(DFS_INFO_4);
|
|
LocalInfo.Info4.Timeout = pNameInformation->Timeout;
|
|
LocalInfo.Info4.State = pNameInformation->State;
|
|
LocalInfo.Info4.NumberOfStorages = pReplicaList->ReplicaCount;
|
|
pStorage = LocalInfo.Info4.Storage = (PDFS_STORAGE_INFO)(&pInfo->Info4 + 1);
|
|
NextFreeMemory = (ULONG_PTR)(LocalInfo.Info4.Storage + LocalInfo.Info4.NumberOfStorages);
|
|
}
|
|
|
|
case 3:
|
|
if (HeaderSize == 0)
|
|
{
|
|
HeaderSize = sizeof(DFS_INFO_3);
|
|
LocalInfo.Info3.State = pNameInformation->State;
|
|
LocalInfo.Info3.NumberOfStorages = pReplicaList->ReplicaCount;
|
|
pStorage = LocalInfo.Info3.Storage = (PDFS_STORAGE_INFO)(&pInfo->Info3 + 1);
|
|
NextFreeMemory = (ULONG_PTR)(LocalInfo.Info3.Storage + LocalInfo.Info3.NumberOfStorages);
|
|
}
|
|
|
|
for (i = 0; i < pReplicaList->ReplicaCount; i++)
|
|
{
|
|
|
|
UNICODE_STRING ServerName = pReplicaList->pReplicas[i].ServerName;
|
|
|
|
if (IsLocalName(&ServerName))
|
|
{
|
|
ServerName = *pRootName;
|
|
}
|
|
AdditionalSize += ( sizeof(DFS_STORAGE_INFO) +
|
|
ServerName.Length + sizeof(WCHAR) +
|
|
pReplicaList->pReplicas[i].ShareName.Length + sizeof(WCHAR) );
|
|
|
|
}
|
|
|
|
case 2:
|
|
if (HeaderSize == 0)
|
|
{
|
|
HeaderSize = sizeof(DFS_INFO_2);
|
|
LocalInfo.Info2.State = pNameInformation->State;
|
|
LocalInfo.Info2.NumberOfStorages = pReplicaList->ReplicaCount;
|
|
NextFreeMemory = (ULONG_PTR)(&pInfo->Info2 + 1);
|
|
}
|
|
|
|
AdditionalSize += pNameInformation->Comment.Length + sizeof(WCHAR);
|
|
|
|
case 1:
|
|
if (HeaderSize == 0)
|
|
{
|
|
HeaderSize = sizeof(DFS_INFO_1);
|
|
NextFreeMemory = (ULONG_PTR)(&pInfo->Info1 + 1);
|
|
}
|
|
AdditionalSize += UsePrefixName.Length + sizeof(WCHAR);
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
|
|
}
|
|
*pSizeRequired = HeaderSize + AdditionalSize;
|
|
if (*pSizeRequired > BufferSize)
|
|
{
|
|
Status = ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
RtlZeroMemory( pBuffer, *pSizeRequired);
|
|
RtlCopyMemory( &pInfo->Info4, &LocalInfo.Info4, HeaderSize );
|
|
|
|
switch (Level)
|
|
{
|
|
case 100:
|
|
|
|
pInfo->Info100.Comment = (LPWSTR)NextFreeMemory;
|
|
NextFreeMemory += pNameInformation->Comment.Length + sizeof(WCHAR);
|
|
RtlCopyMemory( pInfo->Info100.Comment,
|
|
pNameInformation->Comment.Buffer,
|
|
pNameInformation->Comment.Length );
|
|
break;
|
|
|
|
case 4:
|
|
case 3:
|
|
for (i = 0; i < pReplicaList->ReplicaCount; i++)
|
|
{
|
|
UNICODE_STRING ServerName = pReplicaList->pReplicas[i].ServerName;
|
|
|
|
if (IsLocalName(&ServerName))
|
|
{
|
|
ServerName = *pRootName;
|
|
}
|
|
|
|
pReplica = &pReplicaList->pReplicas[i];
|
|
pStorage[i].State = pReplica->ReplicaState;
|
|
pStorage[i].ServerName = (LPWSTR)NextFreeMemory;
|
|
NextFreeMemory += ServerName.Length + sizeof(WCHAR);
|
|
pStorage[i].ShareName = (LPWSTR)NextFreeMemory;
|
|
NextFreeMemory += pReplica->ShareName.Length + sizeof(WCHAR);
|
|
|
|
RtlCopyMemory( pStorage[i].ServerName,
|
|
ServerName.Buffer,
|
|
ServerName.Length );
|
|
|
|
RtlCopyMemory( pStorage[i].ShareName,
|
|
pReplica->ShareName.Buffer,
|
|
pReplica->ShareName.Length );
|
|
}
|
|
|
|
case 2:
|
|
|
|
pInfo->Info2.Comment = (LPWSTR)NextFreeMemory;
|
|
NextFreeMemory += pNameInformation->Comment.Length + sizeof(WCHAR);
|
|
RtlCopyMemory( pInfo->Info2.Comment,
|
|
pNameInformation->Comment.Buffer,
|
|
pNameInformation->Comment.Length );
|
|
|
|
case 1:
|
|
|
|
pInfo->Info1.EntryPath = (LPWSTR)NextFreeMemory;
|
|
|
|
RtlCopyMemory( pInfo->Info1.EntryPath,
|
|
UsePrefixName.Buffer,
|
|
UsePrefixName.Length );
|
|
pInfo->Info1.EntryPath[UsePrefixName.Length/sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
break;
|
|
}
|
|
}
|
|
ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
|
|
}
|
|
ReleaseApiLogicalPath( &UsePrefixName );
|
|
ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::SetStoreApiInformation(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
LPWSTR LinkMetadataName,
|
|
LPWSTR ServerName,
|
|
LPWSTR SharePath,
|
|
DWORD Level,
|
|
LPBYTE pBuffer )
|
|
{
|
|
DFSSTATUS Status;
|
|
PDFS_NAME_INFORMATION pNameInformation;
|
|
|
|
//
|
|
// The set is a little strange: the pBuffer is pointing to a pointer
|
|
// that we are interested in. Grab it directly.
|
|
// dfsdev: this is confusing, fix it or document in detail.
|
|
//
|
|
PDFS_API_INFO pApiInfo = (PDFS_API_INFO)(*(PULONG_PTR)pBuffer);
|
|
|
|
//
|
|
// dfsdev: need to do some api work before enabling code
|
|
// below.
|
|
//
|
|
#if 0
|
|
if ( (ServerName != NULL) || (SharePath != NULL) )
|
|
{
|
|
if (Level != 101)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
Status = GetMetadataNameInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
&pNameInformation );
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
|
|
switch (Level)
|
|
{
|
|
case 100:
|
|
RtlInitUnicodeString( &pNameInformation->Comment,
|
|
pApiInfo->Info100.Comment );
|
|
|
|
Status = SetMetadataNameInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
pNameInformation );
|
|
break;
|
|
|
|
case 102:
|
|
pNameInformation->Timeout = pApiInfo->Info102.Timeout;
|
|
|
|
Status = SetMetadataNameInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
pNameInformation );
|
|
|
|
break;
|
|
|
|
case 101:
|
|
|
|
if ((ServerName == NULL) && (SharePath == NULL))
|
|
{
|
|
pNameInformation->State = pApiInfo->Info101.State;
|
|
|
|
Status = SetMetadataNameInformation( DfsHandle,
|
|
LinkMetadataName,
|
|
pNameInformation );
|
|
}
|
|
else {
|
|
PDFS_REPLICA_LIST_INFORMATION pReplicaList;
|
|
ULONG ReplicaIndex;
|
|
|
|
Status = GetMetadataReplicaInformation (DfsHandle,
|
|
LinkMetadataName,
|
|
&pReplicaList );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
ReplicaIndex = FindReplicaInReplicaList( pReplicaList,
|
|
ServerName,
|
|
SharePath );
|
|
|
|
if (ReplicaIndex >= pReplicaList->ReplicaCount)
|
|
{
|
|
Status = ERROR_NOT_FOUND;
|
|
}
|
|
else {
|
|
DFS_REPLICA_LIST_INFORMATION NewList;
|
|
|
|
RtlZeroMemory( &NewList, sizeof( DFS_REPLICA_LIST_INFORMATION) );
|
|
NewList.ReplicaCount = pReplicaList->ReplicaCount;
|
|
NewList.pReplicas = new DFS_REPLICA_INFORMATION [ NewList.ReplicaCount ];
|
|
if (NewList.pReplicas != NULL)
|
|
{
|
|
RtlCopyMemory( &NewList.pReplicas[0],
|
|
&pReplicaList->pReplicas[0],
|
|
NewList.ReplicaCount * sizeof(DFS_REPLICA_INFORMATION) );
|
|
NewList.pReplicas[ReplicaIndex].ReplicaState = pApiInfo->Info101.State;
|
|
NewList.pReplicas[ReplicaIndex].ReplicaType = 2; // hack fro backwards compat.
|
|
Status = SetMetadataReplicaInformation (DfsHandle,
|
|
LinkMetadataName,
|
|
&NewList );
|
|
|
|
delete [] NewList.pReplicas;
|
|
}
|
|
else {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
|
|
ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::GetStoreApiInformationBuffer(
|
|
IN DFS_METADATA_HANDLE DfsHandle,
|
|
PUNICODE_STRING pRootName,
|
|
LPWSTR LinkMetadataName,
|
|
DWORD Level,
|
|
LPBYTE *ppBuffer,
|
|
PLONG pBufferSize )
|
|
{
|
|
DFSSTATUS Status;
|
|
LONG RequiredSize;
|
|
|
|
LONG BufferSize = 4096;
|
|
LPBYTE pBuffer = new BYTE [ BufferSize ];
|
|
|
|
if (pBuffer == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Status = GetStoreApiInformation( DfsHandle,
|
|
pRootName,
|
|
LinkMetadataName,
|
|
Level,
|
|
pBuffer,
|
|
BufferSize,
|
|
&RequiredSize );
|
|
|
|
if (Status == ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
delete [] pBuffer;
|
|
BufferSize = RequiredSize;
|
|
pBuffer = new BYTE[ BufferSize ];
|
|
if (pBuffer == NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else {
|
|
Status = GetStoreApiInformation( DfsHandle,
|
|
pRootName,
|
|
LinkMetadataName,
|
|
Level,
|
|
pBuffer,
|
|
BufferSize,
|
|
&RequiredSize );
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
*ppBuffer = pBuffer;
|
|
*pBufferSize = RequiredSize;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsStore::FindNextRoot(
|
|
ULONG RootNum,
|
|
DfsRootFolder **ppRootFolder )
|
|
{
|
|
DFSSTATUS Status;
|
|
DfsRootFolder *pRoot;
|
|
ULONG Start;
|
|
|
|
|
|
DFS_TRACE_LOW( REFERRAL_SERVER, "Store %p, Find next root %d\n",
|
|
this, RootNum );
|
|
//
|
|
// Lock the store, so that we dont have new roots coming in while
|
|
// we are taking a look.
|
|
//
|
|
Status = AcquireReadLock();
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// The default return status is ERROR_NOT_FOUND;
|
|
//
|
|
Status = ERROR_NOT_FOUND;
|
|
|
|
//
|
|
// Run through our list of DFS roots, and see if any of them match
|
|
// the passed in name context and logical share.
|
|
//
|
|
|
|
pRoot = _DfsRootList;
|
|
Start = 0;
|
|
|
|
if (pRoot != NULL)
|
|
{
|
|
do
|
|
{
|
|
if (Start++ == RootNum)
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
pRoot = pRoot->pNextRoot;
|
|
} while ( pRoot != _DfsRootList );
|
|
}
|
|
|
|
//
|
|
// IF we found a matching root, bump up its reference count, and
|
|
// return the pointer to the root.
|
|
//
|
|
if ( Status == ERROR_SUCCESS )
|
|
{
|
|
pRoot->AcquireReference();
|
|
*ppRootFolder = pRoot;
|
|
|
|
}
|
|
|
|
ReleaseLock();
|
|
|
|
DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Done find next %d, root %p status %x\n",
|
|
RootNum, pRoot, Status);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// the store syncrhonizer: syncrhonizes roots that we already know of.
|
|
// Note that we could be racing with a delete: in the worst case we will
|
|
// resync the same root more than once.
|
|
//
|
|
|
|
VOID
|
|
DfsStore::StoreSynchronizer()
|
|
{
|
|
ULONG RootNum = 0;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
DfsRootFolder *pRoot;
|
|
|
|
while (Status != ERROR_NOT_FOUND)
|
|
{
|
|
Status = FindNextRoot(RootNum++, &pRoot);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = pRoot->Synchronize();
|
|
|
|
DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Root %p Synchronize Status %x\n", this, Status);
|
|
|
|
pRoot->ReleaseReference();
|
|
}
|
|
}
|
|
return NOTHING;
|
|
}
|
|
|
|
|
|
|