Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1708 lines
46 KiB

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsRootFolder.hxx
//
// Contents: the Root DFS Folder class
//
// Classes: DfsRootFolder
//
// History: Dec. 8 2000, Author: udayh
//
//-----------------------------------------------------------------------------
#ifndef __DFS_ROOT_FOLDER__
#define __DFS_ROOT_FOLDER__
#include "DfsFolder.hxx"
#include "DfsFolderReferralData.hxx"
#include "dfsprefix.h"
#include "dfsnametable.h"
#include "DfsStatistics.hxx"
#define DFS_SHORTNAME_EXPANSION_SIZE 1024
//+----------------------------------------------------------------------------
//
// Class: DfsRootFolder
//
// Synopsis: This class implements The Dfs ROOT folder.
//
//-----------------------------------------------------------------------------
#define NUMBER_OF_SHARED_LINK_LOCKS 0x80
class DfsStore;
//
// The root flags that define the availability of roots for referrals
//
#define ROOT_AVAILABILITY_FLAGS ( ROOT_FOLDER_SHARE_ACQUIRED | \
ROOT_FOLDER_SYNCHRONIZED | \
ROOT_FOLDER_DIRECTORIES_CREATED )
//
// The root flags that define the availability of roots for referrals
//
#define ROOT_REFERRAL_AVAILABILITY_FLAGS ( ROOT_FOLDER_SHARE_ACQUIRED | \
ROOT_FOLDER_SYNCHRONIZED )
//
// The root flags that define the availability of roots for api
//
#define ROOT_API_AVAILABILITY_FLAGS ( ROOT_FOLDER_SYNCHRONIZED )
#define ROOT_SYNCHRONIZE_SKIP_FLAGS ( ROOT_FOLDER_STANDBY | \
ROOT_FOLDER_DELETE_IN_PROGRESS )
#define ROOT_FOLDER_DIRECTORIES_CREATED 0x0010
#define ROOT_FOLDER_SHARE_ACQUIRED 0x0020
#define ROOT_FOLDER_SYNCHRONIZED 0x0100
#define ROOT_FOLDER_STANDBY 0x1000
#define ROOT_FOLDER_DELETE_IN_PROGRESS 0x4000
#define FEWERRORS_ON_ROOT 0
#define TOOMANY_ERRORS_ON_ROOT 1
extern DFSSTATUS
DfsAddReparseVolumeToList (
IN PUNICODE_STRING pDirectoryName);
class DfsRootFolder: public DfsFolder
{
private:
CRITICAL_SECTION *_pRootLock;
CRITICAL_SECTION *_pChildLocks; // All the children locks.
LONG _ChildLockIndex; // Currently allocated lock index.
ULONG _RootFlags;
BOOLEAN _PrefetchNeeded; //load data on startup
BOOLEAN _LogicalShareAddedToTable;
LONG _TooManyEventLogErrors;
UNICODE_STRING _DfsNameContext; // the DfsNameContext for this root.
UNICODE_STRING _DfsNetbiosNameContext; // The netbios DfsNameContext for this root.
UNICODE_STRING _LogicalShareName; // the LogicalShareName of this root.
UNICODE_STRING _PhysicalShareName;
UNICODE_STRING _ShareFilePathName;
UNICODE_STRING _DirectoryCreateRootPathName;
UNICODE_STRING _RootRegKeyName; // the regkey name of the root where we
// store the root information.
// in cae of registry dfs, the metadata is
// also stored under this. IN AD case, this
// will have very little infor such as share info.
BOOLEAN _IgnoreNameContext;
BOOLEAN _CreateDirectories;
DFSSTATUS _DirectoryCreateError;
DFSSTATUS _ShareAcquireStatus;
LONG _ChildCount;
LONG _CurrentErrors;
BOOLEAN _fRootLockInit;
BOOLEAN _fpLockInit;
BOOLEAN _fChildLocksInit[NUMBER_OF_SHARED_LINK_LOCKS];
struct _DFS_PREFIX_TABLE *_pLogicalPrefixTable; // The logical namespace prefix table.
protected:
ULONG _RootFlavor;
BOOLEAN _LocalCreate;
BOOLEAN _RootScalability;
UNICODE_STRING _DfsVisibleContext; // this is the context that should
// be seen during api calls, etc
struct _DFS_NAME_TABLE *_pMetadataNameTable; // the Metadata NameTable.
public:
DfsRootFolder *pPrevRoot, *pNextRoot; // pointers to previos and
// next recognized roots.
DfsStatistics *pStatistics;
private:
virtual
DfsStore *
GetMetadataStore() = 0;
NTSTATUS
SetDfsReparsePoint(
HANDLE DirHandle );
NTSTATUS
CreateLinkDirectories(
PUNICODE_STRING pLinkName,
HANDLE RelativeHandle,
PHANDLE pDirectoryHandle,
PBOOLEAN pIsNewlyCreated,
ULONG ShareMode = 0 );
DFSSTATUS
CreateLinkReparsePoint(
PUNICODE_STRING pLinkName,
HANDLE RelativeHandle );
DFSSTATUS
MorphLinkCollision(
PUNICODE_STRING ParentDirectory,
PUNICODE_STRING DirectoryToRename );
protected:
DFSSTATUS
SetupLinkReparsePoint(
LPWSTR LinkName );
DFSSTATUS
TeardownLinkReparsePoint(
LPWSTR LinkName );
VOID
SetRootFolderShareAcquired()
{
_RootFlags |= ROOT_FOLDER_SHARE_ACQUIRED;
}
VOID
ClearRootFolderShareAcquired()
{
_RootFlags &= ~ROOT_FOLDER_SHARE_ACQUIRED;
}
BOOLEAN
IsRootFolderShareAcquired()
{
return ((_RootFlags & ROOT_FOLDER_SHARE_ACQUIRED) == ROOT_FOLDER_SHARE_ACQUIRED);
}
VOID
SetRootDirectoriesCreated()
{
_RootFlags |= ROOT_FOLDER_DIRECTORIES_CREATED;
}
VOID
ClearRootDirectoriesCreated()
{
_RootFlags &= ~ROOT_FOLDER_DIRECTORIES_CREATED;
}
BOOLEAN
IsRootDirectoriesCreated()
{
return ((_RootFlags & ROOT_FOLDER_DIRECTORIES_CREATED) ==
ROOT_FOLDER_DIRECTORIES_CREATED);
}
VOID
SetRootFolderStandby()
{
ClearRootFolderSynchronized();
_RootFlags |= ROOT_FOLDER_STANDBY;
}
VOID
SetLastCreateDirectoryError( DFSSTATUS Status)
{
_DirectoryCreateError = Status;
}
DFSSTATUS
GetLastCreateDirectoryError()
{
return _DirectoryCreateError;
}
VOID
ClearLastCreateDirectoryError()
{
_DirectoryCreateError = ERROR_SUCCESS;
InterlockedExchange(&_TooManyEventLogErrors, FEWERRORS_ON_ROOT);
_CurrentErrors = 0;
}
VOID
ClearRootFolderStandby()
{
_RootFlags &= ~ROOT_FOLDER_STANDBY;
}
BOOLEAN
IsRootFolderStandby()
{
return ((_RootFlags & ROOT_FOLDER_STANDBY) == ROOT_FOLDER_STANDBY);
}
//
// Function GetChildLock: Increments the ChildLockIndex and picks
// the next lock to allocate. We setup a fixed number of locks, and
// assign a lock to a link in a round-robin basis.
//
CRITICAL_SECTION *
GetChildLock()
{
USHORT LockNum;
LockNum = (USHORT)((ULONG)(InterlockedIncrement(&_ChildLockIndex)) &
(NUMBER_OF_SHARED_LINK_LOCKS - 1));
return &_pChildLocks[LockNum];
}
VOID
SetIgnoreNameContext()
{
_IgnoreNameContext = TRUE;
}
BOOLEAN
IsRootCreateDirectories()
{
return _CreateDirectories;
}
VOID
SetRootShareAcquireStatus( DFSSTATUS Status)
{
_ShareAcquireStatus = Status;
}
DFSSTATUS
GetRootShareAcquireStatus()
{
return _ShareAcquireStatus;
}
DFSSTATUS
InitializeDirectoryCreateInformation()
{
DFSSTATUS Status = ERROR_SUCCESS;
Status = DfsGetSharePath( _DfsNameContext.Buffer,
_PhysicalShareName.Buffer,
&_ShareFilePathName );
if (Status == ERROR_SUCCESS)
{
if (_LocalCreate == TRUE)
{
if (IsEmptyString(_ShareFilePathName.Buffer) )
{
Status = ERROR_INVALID_PARAMETER;
}
else {
Status = DfsCreateUnicodeString( &_DirectoryCreateRootPathName,
&_ShareFilePathName );
}
}
else {
if (IsEmptyString(_DfsNameContext.Buffer))
{
Status = ERROR_INVALID_PARAMETER;
}
else {
Status = DfsCreateUnicodePathString( &_DirectoryCreateRootPathName,
TRUE,
_DfsNameContext.Buffer,
_PhysicalShareName.Buffer );
}
}
}
return Status;
}
//
// Function LoadReplicaReferralData: Loads the replica specific
// data into the DfsFolderReferralData, for the specified child.
//
DFSSTATUS
LoadReplicaReferralData(
DFS_METADATA_HANDLE DfsMetadataHandle,
LPWSTR MetadataName,
DfsFolderReferralData *pReferralData );
//
// Function LoadPolicyReferralData: Loads the policy specific
// data into the DfsFolderReferralData, for the specified child.
// Currently not implemented.
//
DFSSTATUS
LoadPolicyReferralData(
DFS_METADATA_HANDLE DfsMetadataHandle )
{
UNREFERENCED_PARAMETER(DfsMetadataHandle);
return ERROR_SUCCESS;
}
//
// Function UnloadReplicaReferralData: Unloads the replica specific
// data from the DfsFolderReferralData
//
DFSSTATUS
UnloadReplicaReferralData(
DfsFolderReferralData *pReferralData );
//
// Function UnloadPolicyReferralData: Unloads the policy specific
// data from the DfsFolderReferralData.
// Currently not implemented.
//
DFSSTATUS
UnloadPolicyReferralData(
DfsFolderReferralData *pReferralData )
{
UNREFERENCED_PARAMETER(pReferralData);
return ERROR_SUCCESS;
}
VOID IncrementChildCount() {InterlockedIncrement(&_ChildCount); }
VOID DecrementChildCount() {InterlockedDecrement(&_ChildCount); }
public:
VOID
ResetCreateDirectories()
{
_CreateDirectories = FALSE;
}
VOID
SetRootFolderDeleteInProgress()
{
_RootFlags |= ROOT_FOLDER_DELETE_IN_PROGRESS;
}
VOID
ClearRootFolderDeleteInProgress()
{
_RootFlags &= ~ROOT_FOLDER_DELETE_IN_PROGRESS;
}
BOOLEAN
CheckRootFolderSkipSynchronize()
{
return ((_RootFlags & ROOT_SYNCHRONIZE_SKIP_FLAGS) ? TRUE : FALSE);
}
BOOLEAN
IsRootFolderAvailable()
{
return ((_RootFlags & ROOT_AVAILABILITY_FLAGS) == ROOT_AVAILABILITY_FLAGS);
}
BOOLEAN
IsRootSynchronized()
{
return ((_RootFlags & ROOT_FOLDER_SYNCHRONIZED) == ROOT_FOLDER_SYNCHRONIZED);
}
BOOLEAN
IsRootScalabilityMode()
{
return _RootScalability;
}
VOID
SetRootScalabilityMode()
{
_RootScalability = TRUE;
}
VOID
ResetRootScalabilityMode()
{
_RootScalability = FALSE;
}
BOOLEAN
IsRootFolderAvailableForApi()
{
BOOLEAN RetVal = TRUE;
if(_CurrentErrors > DfsServerGlobalData.AllowedErrors)
{
RetVal = FALSE;
}
else
{
RetVal = ((_RootFlags & ROOT_API_AVAILABILITY_FLAGS) == ROOT_API_AVAILABILITY_FLAGS);
}
return RetVal;
}
BOOLEAN
IsRootFolderAvailableForReferral()
{
BOOLEAN RetVal = TRUE;
if(_CurrentErrors > DfsServerGlobalData.AllowedErrors)
{
RetVal = FALSE;
}
else
{
RetVal = ((_RootFlags & ROOT_REFERRAL_AVAILABILITY_FLAGS) == ROOT_REFERRAL_AVAILABILITY_FLAGS);
}
return RetVal;
}
DFSSTATUS
AcquireRootShareDirectory(void);
DFSSTATUS
ReleaseRootShareDirectory(void);
//
// Function DfsRootFolder: Constructor.
//
DfsRootFolder(
LPWSTR NameContext,
LPWSTR RootRegKeyName,
PUNICODE_STRING pLogicalShare,
PUNICODE_STRING pPhysicalShare,
DfsObjectTypeEnumeration ObType,
DFSSTATUS *pStatus );
//
// Function ~DfsRootFolder: destructor.
// Delete all the locks we had allocated for the children links.
// Also delete the lock for this root folder.
//
virtual
~DfsRootFolder()
{
ULONG i = 0;
if (_pMetadataNameTable)
{
DfsDereferenceNameTable( _pMetadataNameTable);
_pMetadataNameTable = NULL;
}
if (_pLogicalPrefixTable)
{
DfsDereferencePrefixTable( _pLogicalPrefixTable);
_pLogicalPrefixTable = NULL;
}
if(_pRootLock)
{
if(_fRootLockInit)
{
DeleteCriticalSection( _pRootLock );
}
delete _pRootLock;
_pRootLock = NULL;
}
if(_pLock)
{
if(_fpLockInit)
{
DeleteCriticalSection( _pLock );
}
delete _pLock;
_pLock = NULL;
}
if(_pChildLocks)
{
for ( i = 0; i < NUMBER_OF_SHARED_LINK_LOCKS; i++ )
{
if(_fChildLocksInit[i])
{
DeleteCriticalSection( &_pChildLocks[i] );
}
}
delete [] _pChildLocks;
_pChildLocks = NULL;
}
if (pStatistics != NULL)
{
pStatistics->ReleaseReference();
pStatistics = NULL;
}
DfsFreeUnicodeString(&_PhysicalShareName);
DfsFreeUnicodeString(&_RootRegKeyName);
DfsFreeUnicodeString(&_LogicalShareName );
DfsFreeUnicodeString(&_DfsNameContext );
DfsFreeUnicodeString(&_ShareFilePathName );
DfsFreeUnicodeString(&_DirectoryCreateRootPathName);
}
//
// Function GetNetbiosNameContext: Returns the unicode string that
// is the netbios name context for this root
//
PUNICODE_STRING
GetNetbiosNameContext()
{
return &_DfsNetbiosNameContext;
}
//
// Function GetNameContext: Returns the unicode string that
// is the name context for this root
//
PUNICODE_STRING
GetNameContext()
{
return &_DfsNameContext;
}
//
// Function GetNameContextString: Returns the string that
// is the name context for this root
// Note: since we create the unicode string buffer with a null
// terminated wide string, we just return that buffer.
//
LPWSTR
GetNameContextString()
{
return _DfsNameContext.Buffer;
}
//
// Function GetVisibleNameContext: Returns the unicode string that
// is the name context for this root
//
PUNICODE_STRING
GetVisibleContextLocked()
{
return &_DfsVisibleContext;
}
DFSSTATUS
GetVisibleContext( PUNICODE_STRING pString)
{
DFSSTATUS Status;
Status = AcquireRootLock();
if (Status == ERROR_SUCCESS)
{
Status = DfsCreateUnicodeString( pString,
&_DfsVisibleContext);
ReleaseRootLock();
}
return Status;
}
VOID
ReleaseVisibleContext( PUNICODE_STRING pString)
{
DfsFreeUnicodeString( pString );
}
//
// MUST be called with root lock held (or at init)
//
DFSSTATUS
SetVisibleContext( PUNICODE_STRING pString,
BOOLEAN *pChanged)
{
DFSSTATUS Status = ERROR_SUCCESS;
if (pChanged)
{
*pChanged = FALSE;
}
if (RtlCompareUnicodeString(&_DfsVisibleContext, pString, TRUE) != 0)
{
UNICODE_STRING OldString = _DfsVisibleContext;
Status = DfsCreateUnicodeString( &_DfsVisibleContext,
pString );
//
// we use the new name if possible. If we fail due to any reason
// we reuse the old name.
//
if (Status == ERROR_SUCCESS)
{
if (pChanged)
{
*pChanged = TRUE;
}
if (OldString.Length != 0)
{
DfsFreeUnicodeString(&OldString);
}
}
else
{
_DfsVisibleContext = OldString;
}
}
return Status;
}
//
// Function GetLogicalShare: Returns the unicode string that
// is the logical share name for this root
//
PUNICODE_STRING
GetLogicalShare()
{
return &_LogicalShareName;
}
LPWSTR
GetRootRegKeyNameString()
{
return _RootRegKeyName.Buffer;
}
LPWSTR
GetDirectoryCreatePathNameString()
{
return _DirectoryCreateRootPathName.Buffer;
}
PUNICODE_STRING
GetDirectoryCreatePathName()
{
return &_DirectoryCreateRootPathName;
}
PUNICODE_STRING
GetRootPhysicalShareName()
{
return &_PhysicalShareName;
}
BOOLEAN
IsIgnoreNameContext()
{
return _IgnoreNameContext;
}
//
// Function Synchronize: This function should be overridden by
// each of the classes that are derived from this class.
// They implement the store specific synchronize functionality.
//
virtual
DFSSTATUS
Synchronize(BOOLEAN fForceSynch = FALSE, BOOLEAN CalledByApi = FALSE ) = 0;
//
// Function LoadReferralData
//
DFSSTATUS
LoadReferralData(
DfsFolderReferralData *pReferralData );
//
// Function UnloadReferralData
//
DFSSTATUS
UnloadReferralData(
DfsFolderReferralData *pReferralData );
virtual
DFSSTATUS
GetMetadataHandle( PDFS_METADATA_HANDLE pRootHandle) = 0;
virtual
VOID
ReleaseMetadataHandle( DFS_METADATA_HANDLE RootHandle) = 0;
virtual
ULONG
GetBlobSize()
{
return 0;
}
virtual
DFSSTATUS
SetSiteBlob(PVOID pBuffer, ULONG pSize)
{
UNREFERENCED_PARAMETER(pBuffer);
UNREFERENCED_PARAMETER(pSize);
return ERROR_NOT_SUPPORTED;
}
virtual
DFSSTATUS
GetSiteBlob(PVOID *pBuffer, PULONG pSize)
{
UNREFERENCED_PARAMETER(pBuffer);
UNREFERENCED_PARAMETER(pSize);
return ERROR_NOT_SUPPORTED;
}
DFSSTATUS
UpdateLinkInformation(
DFS_METADATA_HANDLE RootHandle,
LPWSTR ChildName,
BOOLEAN CalledByAPI = FALSE);
DFSSTATUS
UpdateFolderInformation(
IN DFS_METADATA_HANDLE DfsHandle,
LPWSTR ChildName,
DfsFolder *pChildFolder);
DFSSTATUS
RemoveAllLinkFolders(
BOOLEAN IsPermanent);
DFSSTATUS
LookupFolder( DfsFolder **ppFolder)
{
NTSTATUS NtStatus;
DFSSTATUS Status;
PVOID pData;
NtStatus = DfsNameTableAcquireReadLock( _pMetadataNameTable );
if (NtStatus == STATUS_SUCCESS)
{
NtStatus = DfsGetEntryNameTableLocked( _pMetadataNameTable,
&pData );
//
// If we were successful, pData is a pointer to the DfsFolder.
// Acquire a reference on the folder while we still have
// the table locked.
//
if ( NtStatus == STATUS_SUCCESS )
{
Status = ERROR_SUCCESS;
*ppFolder = (DfsFolder *)pData;
(*ppFolder)->AcquireReference();
}
DfsNameTableReleaseLock( _pMetadataNameTable );
}
if ( NtStatus != STATUS_SUCCESS )
{
Status = ERROR_NOT_FOUND;
}
return Status;
}
//
// Function LookupFolderByLogicalName: This function searches
// this roots logical namespace table to find a matching folder
// for any part of the passed in logical name.
// The logicalname that is passed in is relative to the Dfs Share
// name of this root.
// If any part of the logical name passed in has a match, the matching
// folder along with the rest of the logical name are returned.
// Otherwise, we return ERROR_NOT_FOUND.
//
DFSSTATUS
LookupFolderByLogicalName(
PUNICODE_STRING pChildLogicalName,
PUNICODE_STRING pRemainingName,
DfsFolder **ppFolder,
PBOOLEAN pSubStringMatch = NULL )
{
NTSTATUS NtStatus;
DFSSTATUS Status;
PVOID pData;
NtStatus = DfsPrefixTableAcquireReadLock( _pLogicalPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsFindUnicodePrefixLocked( _pLogicalPrefixTable,
pChildLogicalName,
pRemainingName,
&pData,
pSubStringMatch );
//
// If we were successful, pData is a pointer to a DfsFolder.
// Acquire a reference on the folder while we still have
// the table locked. This is very important: A valid reference
// to the folder exists in table, and this reference cannot
// go away while the table is locked. So we acquire a new
// reference on the folder while the table is locked, and then
// release the table lock.
//
if ( NtStatus == STATUS_SUCCESS )
{
DfsFolder *pFolder = (DfsFolder *)pData;
if (pFolder->IsFolderDeleteInProgress())
{
Status = ERROR_NOT_FOUND;
}
else
{
Status = ERROR_SUCCESS;
*ppFolder = pFolder;
(*ppFolder)->AcquireReference();
}
}
DfsPrefixTableReleaseLock( _pLogicalPrefixTable );
}
if ( NtStatus != STATUS_SUCCESS )
{
Status = ERROR_NOT_FOUND;
}
return Status;
}
//
// Function LookupFolderByMetadataName: This function searches
// this roots Metadata name table to find a matching folder
// for any part of the passed in Metadata Name.
// If a matching folder is found, a reference folder is returned
// to the caller.
// Else ERROR_NOT_FOUND is returned.
//
DFSSTATUS
LookupFolderByMetadataName(
LPWSTR pChildMetadataNameString,
DfsFolder **ppFolder )
{
NTSTATUS NtStatus = STATUS_SUCCESS;
DFSSTATUS Status = ERROR_SUCCESS;
PVOID pData = NULL;
UNICODE_STRING MetadataName;
Status = DfsRtlInitUnicodeStringEx( &MetadataName, pChildMetadataNameString);
if(Status == ERROR_SUCCESS)
{
NtStatus = DfsNameTableAcquireReadLock( _pMetadataNameTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsLookupNameTableLocked( _pMetadataNameTable,
&MetadataName,
&pData );
//
// If we were successful, pData is a pointer to the DfsFolder.
// Acquire a reference on the folder while we still have
// the table locked.
//
if ( NtStatus == STATUS_SUCCESS )
{
Status = ERROR_SUCCESS;
*ppFolder = (DfsFolder *)pData;
(*ppFolder)->AcquireReference();
}
DfsNameTableReleaseLock( _pMetadataNameTable );
}
Status = RtlNtStatusToDosError(NtStatus);
}
if (Status != ERROR_SUCCESS)
{
Status = ERROR_NOT_FOUND;
}
return Status;
}
//
// Function InsertLinkFolderInMetadataTable: This function attempts
// to insert the passed in folder into the metadata name table of
// the root.
// If the insert is successful, we bump up the reference count on
// the folder to reflect an active reference to it in the metadata
// table.
//
DFSSTATUS
InsertLinkFolderInMetadataTable(
DfsFolder *pLinkFolder )
{
NTSTATUS NtStatus;
DFSSTATUS Status;
NtStatus = DfsNameTableAcquireWriteLock( _pMetadataNameTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsInsertInNameTableLocked( _pMetadataNameTable,
pLinkFolder->GetFolderMetadataName(),
(PVOID)(pLinkFolder) );
if ( NtStatus == STATUS_SUCCESS )
{
pLinkFolder->AcquireReference();
//
// Set a flag in the folder to indicate that the folder
// is not in the metadata table.
//
pLinkFolder->SetFlag(DFS_FOLDER_IN_METADATA_TABLE);
}
DfsNameTableReleaseLock( _pMetadataNameTable );
}
Status = RtlNtStatusToDosError(NtStatus);
return Status;
}
//
// Function InsertLinkFolderInLogicalTable: This function attempts
// to insert the passed in folder into the logical namespace table of
// the root.
// If the insert is successful, we bump up the reference count on
// the folder to reflect an active reference to it in the logical
// table.
//
DFSSTATUS
InsertLinkFolderInLogicalTable(
DfsFolder *pLinkFolder )
{
NTSTATUS NtStatus = STATUS_SUCCESS;
DFSSTATUS Status = ERROR_SUCCESS;
UNICODE_STRING RemainingName;
PVOID pData;
NtStatus = DfsPrefixTableAcquireWriteLock( _pLogicalPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
//
// If another folder by this name is already in teh logical
// table, insert will cause memory to leak. Our InsertInPrefixTable
// should return an error on collision, but it currently doesn't.
// We should fix the insert in Prefix table to return error
// and fix all relevant code to handle this failure gracefully.
//
NtStatus = DfsFindUnicodePrefixLocked( _pLogicalPrefixTable,
pLinkFolder->GetFolderLogicalName(),
&RemainingName,
&pData,
NULL );
if ((NtStatus == STATUS_SUCCESS) &&
(RemainingName.Length == 0))
{
DfsFolder *pFolder = (DfsFolder *)pData;
NtStatus = DfsRemoveFromPrefixTableLocked( _pLogicalPrefixTable,
pLinkFolder->GetFolderLogicalName(),
pData );
if (NtStatus == STATUS_SUCCESS)
{
pFolder->ResetFlag(DFS_FOLDER_IN_LOGICAL_TABLE);
pFolder->ReleaseReference();
}
}
NtStatus = DfsInsertInPrefixTableLocked( _pLogicalPrefixTable,
pLinkFolder->GetFolderLogicalName(),
(PVOID)(pLinkFolder) );
if ( NtStatus == STATUS_SUCCESS )
{
pLinkFolder->AcquireReference();
pLinkFolder->SetFlag(DFS_FOLDER_IN_LOGICAL_TABLE);
}
DfsPrefixTableReleaseLock( _pLogicalPrefixTable );
}
Status = RtlNtStatusToDosError(NtStatus);
return Status;
}
//
// Function RemoveLinkFolderFromMetadataTable: This function attempts
// to remove the passed in folder from the metadata name table of
// the root.
// If the remove is successful, we release our reference on
// the folder.
//
DFSSTATUS
RemoveLinkFolderFromMetadataTable(
DfsFolder *pLinkFolder )
{
NTSTATUS NtStatus;
DFSSTATUS Status;
NtStatus = DfsNameTableAcquireWriteLock( _pMetadataNameTable );
if ( NtStatus == ERROR_SUCCESS )
{
if (pLinkFolder->IsFolderInMetadataTable())
{
NtStatus = DfsRemoveFromNameTableLocked( _pMetadataNameTable,
pLinkFolder->GetFolderMetadataName(),
(PVOID)(pLinkFolder) );
if ( NtStatus == STATUS_SUCCESS )
{
pLinkFolder->ResetFlag(DFS_FOLDER_IN_METADATA_TABLE);
pLinkFolder->ReleaseReference();
}
}
DfsNameTableReleaseLock( _pMetadataNameTable );
}
Status = RtlNtStatusToDosError(NtStatus);
return Status;
}
//
// Function RemoveLinkFolderFromLogicalTable: This function attempts
// to remove the passed in folder from the logical namespace table of
// the root.
// If the remove is successful, we release our reference on
// the folder.
//
DFSSTATUS
RemoveLinkFolderFromLogicalTable(
DfsFolder *pLinkFolder )
{
NTSTATUS NtStatus;
DFSSTATUS Status;
NtStatus = DfsPrefixTableAcquireWriteLock( _pLogicalPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
if (pLinkFolder->IsFolderInLogicalTable())
{
NtStatus = DfsRemoveFromPrefixTableLocked( _pLogicalPrefixTable,
pLinkFolder->GetFolderLogicalName(),
(PVOID)(pLinkFolder) );
if ( NtStatus == STATUS_SUCCESS )
{
pLinkFolder->ResetFlag(DFS_FOLDER_IN_LOGICAL_TABLE);
pLinkFolder->ReleaseReference();
}
}
DfsPrefixTableReleaseLock( _pLogicalPrefixTable );
}
Status = RtlNtStatusToDosError(NtStatus);
return Status;
}
//
// Function ReplaceLinkFolderInLogicalTable: This function attempts
// to replace the passed in folder in the logical namespace table of
// the root.
// If the replace is successful, we release our reference on
// replaced folder and acquire a reference on the folder that is
// now inserted into the logical namespace table.
//
DFSSTATUS
ReplaceLinkFolderInLogicalTable(
DfsFolder *pLinkFolder,
DfsFolder *pFolderToReplace )
{
NTSTATUS NtStatus;
DFSSTATUS Status;
NtStatus = DfsPrefixTableAcquireWriteLock( _pLogicalPrefixTable );
if ( NtStatus == STATUS_SUCCESS )
{
NtStatus = DfsReplaceInPrefixTableLocked( _pLogicalPrefixTable,
pLinkFolder->GetFolderLogicalName(),
(PVOID)(pFolderToReplace),
(PVOID)(pLinkFolder) );
if ( NtStatus == STATUS_SUCCESS )
{
pFolderToReplace->ResetFlag(DFS_FOLDER_IN_LOGICAL_TABLE);
pFolderToReplace->ReleaseReference();
pLinkFolder->AcquireReference();
pLinkFolder->SetFlag(DFS_FOLDER_IN_LOGICAL_TABLE);
}
DfsPrefixTableReleaseLock( _pLogicalPrefixTable );
}
Status = RtlNtStatusToDosError(NtStatus);
return Status;
}
//
// Function DfsCreateLinkFolder: Create a new DfsFolder and
// add it to the root's metadata and logical namespace tables.
//
DFSSTATUS
CreateLinkFolder(
IN LPWSTR ChildName,
IN PUNICODE_STRING pLinkName,
OUT DfsFolder **ppChildFolder,
IN BOOLEAN CalledByApi );
//
// Function DfsUpdateLinkFolder: When the DfsFolder needs
// to be updated, this function takes care of the update details.
//
DFSSTATUS
UpdateLinkFolder(
IN LPWSTR ChildName,
IN PUNICODE_STRING pLinkName,
OUT DfsFolder *pChildFolder);
DFSSTATUS
RemoveLinkFolder(
IN DfsFolder *pChildFolder,
BOOLEAN IsPermanent );
DFSSTATUS
RemoveLinkFolder(
IN LPWSTR MetadataName )
{
DfsFolder *pFolder = NULL;
DFSSTATUS Status;
Status =LookupFolderByMetadataName( MetadataName,
&pFolder );
if (Status == ERROR_SUCCESS)
{
Status = RemoveLinkFolder( pFolder,
TRUE ); // Permanent removal.
pFolder->ReleaseReference();
}
return Status;
}
DFSSTATUS
ValidateLinkName(
IN PUNICODE_STRING pLinkName )
{
DFSSTATUS Status = ERROR_SUCCESS;
DfsFolder *pFolder = NULL;
UNICODE_STRING Remaining;
BOOLEAN IsSubStringMatch = FALSE;
UNICODE_STRING CheckName = *pLinkName;
if (pLinkName->Length == 0)
{
return ERROR_SUCCESS; // Root name.
}
Status = ValidateAPiShortName(pLinkName);
if(Status != ERROR_SUCCESS)
{
return Status;
}
while ((Status == ERROR_SUCCESS) &&
(CheckName.Length > 0))
{
UNICODE_STRING NextComponent;
UNICODE_STRING CurrentName = CheckName;
Status = DfsGetNextComponent( &CurrentName,
&NextComponent,
&CheckName );
if (Status == ERROR_SUCCESS)
{
if (!IS_VALID_TOKEN(NextComponent.Buffer,
NextComponent.Length / sizeof(WCHAR)))
{
Status = ERROR_INVALID_NAME;
}
}
}
if (Status == ERROR_SUCCESS)
{
Status = LookupFolderByLogicalName( pLinkName,
&Remaining,
&pFolder,
&IsSubStringMatch );
if (Status == ERROR_SUCCESS)
{
pFolder->ReleaseReference();
if (Remaining.Length > 0) {
Status = ERROR_FILE_EXISTS;
}
}
else {
if (IsSubStringMatch)
{
Status = ERROR_FILE_EXISTS;
}
else {
Status = ERROR_NOT_FOUND;
}
}
}
return Status;
}
ULONG
GetChildCount() { return _ChildCount; }
ULONG
RootEnumerationCount() { return _ChildCount + 1; }
//
// Get the visible name context: This call
// ensures that the server component of the UNC
// names are setup correctly.
// GetVisibleNameContext first attempts to get the
// name context from the DFS path. If the path is
// empty, it uses the name context that was setup
// within the server for this root. If that is also
// empty (as is the case when the service is running local)
// it returns the computer name of this machine.
//
VOID
GetVisibleNameContextLocked(
PUNICODE_STRING pDfsName,
PUNICODE_STRING pContextName )
{
DFSSTATUS Status = ERROR_SUCCESS;
PUNICODE_STRING pName;
RtlInitUnicodeString( pContextName, NULL);
if (pDfsName != NULL)
{
Status = DfsGetPathComponents( pDfsName,
pContextName,
NULL,
NULL);
}
if (pContextName->Length == 0)
{
pName = GetNameContext();
*pContextName = *pName;
}
if (pContextName->Length == 0)
{
pName = GetVisibleContextLocked();
*pContextName = *pName;
}
}
DFSSTATUS
GetVisibleNameContext(
PUNICODE_STRING pDfsName,
PUNICODE_STRING pContextName )
{
DFSSTATUS Status = ERROR_SUCCESS;
UNICODE_STRING Name, *pName;
RtlInitUnicodeString( pContextName, NULL);
RtlInitUnicodeString( &Name, NULL);
if (pDfsName != NULL)
{
Status = DfsGetPathComponents( pDfsName,
&Name,
NULL,
NULL);
}
if (Name.Length == 0)
{
pName = GetNameContext();
Name = *pName;
}
if (Name.Length == 0)
{
Status = GetVisibleContext(pContextName);
}
else
{
Status = DfsCreateUnicodeString(pContextName, &Name);
}
return Status;
}
DWORD
GetRootFlavor()
{
return _RootFlavor;
}
DFSSTATUS
SetRootStandby();
DFSSTATUS
SetRootResynchronize();
DFSSTATUS
AddMetadataLink(
PUNICODE_STRING pLogicalName,
LPWSTR ReplicaServer,
LPWSTR ReplicaPath,
LPWSTR Comment );
DFSSTATUS
RemoveMetadataLink(
PUNICODE_STRING pLinkName );
DFSSTATUS
AddMetadataLinkReplica(
PUNICODE_STRING pLinkName,
LPWSTR ReplicaServer,
LPWSTR ReplicaPath );
DFSSTATUS
RemoveMetadataLinkReplica(
PUNICODE_STRING pLinkName,
LPWSTR ReplicaServer,
LPWSTR ReplicaPath,
PBOOLEAN pLastReplica );
DFSSTATUS
EnumerateApiLinks(
LPWSTR DfsPathName,
DWORD Level,
LPBYTE pBuffer,
LONG BufferSize,
LPDWORD pEntriesRead,
LPDWORD pResumeHandle,
PLONG pNextSizeRequired );
DFSSTATUS
GetApiInformation(
PUNICODE_STRING pDfsName,
PUNICODE_STRING pLinkName,
DWORD Level,
LPBYTE pBuffer,
LONG BufferSize,
PLONG pNextSizeRequired );
DFSSTATUS
ExtendedRootAttributes(
PULONG pAttr,
PUNICODE_STRING pRemaining,
BOOLEAN Set);
DFSSTATUS
SetApiInformation(
PUNICODE_STRING pLinkName,
LPWSTR Server,
LPWSTR Share,
DWORD Level,
LPBYTE pBuffer );
VOID
SetRootFolderSynchronized()
{
_RootFlags |= ROOT_FOLDER_SYNCHRONIZED;
if (IsRootFolderShareAcquired() &&
GetLastCreateDirectoryError() == ERROR_SUCCESS)
{
SetRootDirectoriesCreated();
}
else
{
ClearRootDirectoriesCreated();
}
ClearLastCreateDirectoryError();
}
VOID
ClearRootFolderSynchronized()
{
_RootFlags &= ~ROOT_FOLDER_SYNCHRONIZED;
ClearRootDirectoriesCreated();
ClearLastCreateDirectoryError();
}
virtual
DFSSTATUS
GetMetadataLogicalToLinkName( PUNICODE_STRING pIn,
PUNICODE_STRING pOut ) = 0;
virtual
VOID
ReleaseMetadataLogicalToLinkName( PUNICODE_STRING pIn ) = 0;
DFSSTATUS
AcquireRootLock()
{
return DfsAcquireWriteLock(_pRootLock);
}
VOID
ReleaseRootLock()
{
DfsReleaseLock(_pRootLock);
return NOTHING;
}
DFSSTATUS
CommonRootApiPrologue( BOOLEAN WriteRequest )
{
UNREFERENCED_PARAMETER(WriteRequest);
DFSSTATUS Status = ERROR_SUCCESS;
// Check if the root folder is available for api calls. If not,
// we return an error back to the caller:
// This appears to be the most appropriate error we return here.
//
if (IsRootFolderAvailableForApi() == FALSE)
{
Status = ERROR_DEVICE_NOT_AVAILABLE;
}
if (Status == ERROR_SUCCESS)
{
Status = ReSynchronize();
}
return Status;
}
virtual
DFSSTATUS
RootRequestPrologue( LPWSTR Name ) =0;
virtual
VOID
RootRequestEpilogue () = 0;
virtual
DFSSTATUS
RootApiRequestPrologue( BOOLEAN WriteRequest,
LPWSTR Name = NULL ) = 0;
virtual
VOID
RootApiRequestEpilogue(
BOOLEAN WriteRequest,
DFSSTATUS CompletionStatus ) = 0;
virtual
DFSSTATUS
ReSynchronize(BOOLEAN fForceSynch = FALSE) = 0;
//
// Derived classes that cache their metadata in memory
// (e.g. AdBlob) are expected to override this to flush
// its entire cache to disk.
//
virtual
DFSSTATUS
Flush() = 0;
BOOLEAN
IsEmptyDirectory(
HANDLE DirectoryHandle,
PVOID pDirectoryBuffer,
ULONG DirectoryBufferSize );
void
GenerateEventLog(DWORD EventMsg,
WORD SubStrings,
const TCHAR * apszSubStrings[],
DWORD Errorcode);
NTSTATUS
IsDirectoryMountPoint(
IN HANDLE DirHandle,
OUT PBOOLEAN pDfsMountPoint );
NTSTATUS
IsRootShareMountPoint(PUNICODE_STRING pDirectoryName);
DFSSTATUS
PrefetchReplicaData(DfsFolder *pChildFolder);
DFSSTATUS
LoadCachedServerSiteData(
IN DFS_METADATA_HANDLE RootMetadataHandle,
IN LPWSTR MetadataName);
DFSSTATUS
PreloadServerSiteData(void);
DFSSTATUS
LoadServerSiteData(DfsFolder *pChildFolder);
BOOLEAN GetPrefetchDataState(void)
{
return _PrefetchNeeded;
}
void SetPrefetchData(BOOLEAN Prefetch)
{
_PrefetchNeeded = Prefetch;
}
DFSSTATUS
ExpandShortName(PUNICODE_STRING pLinkName,
PUNICODE_STRING pNewPath,
PUNICODE_STRING pRemainingName);
NTSTATUS
ExpandLinkDirectories(
PUNICODE_STRING pLinkName,
PUNICODE_STRING pNewPath,
HANDLE RelativeHandle,
BOOLEAN FailOnExpand,
DWORD * NumComponentsExpanded);
NTSTATUS
GetAShortName(HANDLE ParentHandle,
BOOLEAN *Expanded,
PUNICODE_STRING pLinkName,
PUNICODE_STRING pNewPath);
BOOLEAN
IsAShortName(PUNICODE_STRING pLinkName);
NTSTATUS
CopyShortName(PUNICODE_STRING pNewName,
PUNICODE_STRING pNewPath);
NTSTATUS
FindRemaingName(PUNICODE_STRING pLinkName,
PUNICODE_STRING pRemainingName,
DWORD NumComponentsExpanded);
DFSSTATUS
ValidateAPiShortName(PUNICODE_STRING pLinkName);
void FreeShortNameData(PUNICODE_STRING pLinkName);
DFSSTATUS
CreateRenameName(PUNICODE_STRING pNewName);
DFSSTATUS
RenamePath(PUNICODE_STRING ParentDirectory,
PUNICODE_STRING DirectoryToRename);
virtual
DFSSTATUS
RenameLinks(
IN LPWSTR OldDomainName,
IN LPWSTR NewDomainName) = 0;
virtual
DFSSTATUS
CheckResynchronizeAccess( DFSSTATUS AccessCheckStatus) = 0;
DFSSTATUS
ClearRootFolderDeleteInProgressLocked(void)
{
DFSSTATUS LockStatus = ERROR_SUCCESS;
LockStatus = AcquireRootLock();
if (LockStatus == ERROR_SUCCESS)
{
ClearRootFolderDeleteInProgress();
ReleaseRootLock();
}
if (LockStatus != ERROR_SUCCESS)
{
ReleaseReference();
}
return LockStatus;
}
inline DFSSTATUS
AddReparseVolumeToList( VOID )
{
return DfsAddReparseVolumeToList( GetDirectoryCreatePathName() );
}
};
#endif // __DFS_ROOT_FOLDER__