|
|
//+----------------------------------------------------------------------------
//
// 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__
|