1257 lines
34 KiB
C++
1257 lines
34 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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 IO_REPARSE_TAG_DFS 0x8000000A
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Class: DfsRootFolder
|
|
//
|
|
// Synopsis: This class implements The Dfs ROOT folder.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define NUMBER_OF_SHARED_LINK_LOCKS 0x80
|
|
#define DFS_MAX_ROOT_ERRORS 10
|
|
|
|
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 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
|
|
|
|
|
|
class DfsRootFolder: public DfsFolder
|
|
{
|
|
private:
|
|
|
|
CRITICAL_SECTION *_pRootLock;
|
|
|
|
CRITICAL_SECTION *_pChildLocks; // All the children locks.
|
|
LONG _ChildLockIndex; // Currently allocated lock index.
|
|
ULONG _RootFlags;
|
|
|
|
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;
|
|
|
|
|
|
|
|
NTSTATUS _DirectoryCreateError;
|
|
|
|
ULONG _ChildCount;
|
|
|
|
LONG _CurrentErrors;
|
|
|
|
struct _DFS_NAME_TABLE *_pMetadataNameTable; // the Metadata NameTable.
|
|
struct _DFS_PREFIX_TABLE *_pLogicalPrefixTable; // The logical namespace prefix table.
|
|
|
|
|
|
protected:
|
|
BOOLEAN _LocalCreate;
|
|
UNICODE_STRING _DfsVisibleContext; // this is the context that should
|
|
// be seen during api calls, etc.
|
|
|
|
public:
|
|
DfsRootFolder *pPrevRoot, *pNextRoot; // pointers to previos and
|
|
// next recognized roots.
|
|
|
|
DfsStatistics *pStatistics;
|
|
|
|
private:
|
|
|
|
virtual
|
|
DfsStore *
|
|
GetMetadataStore() = 0;
|
|
|
|
|
|
NTSTATUS
|
|
OpenLinkDirectory(
|
|
LPWSTR DirectoryName,
|
|
ULONG ShareMode,
|
|
PHANDLE pDirHandle,
|
|
PBOOLEAN pIsNewlyCreated );
|
|
|
|
NTSTATUS
|
|
SetDfsReparsePoint(
|
|
HANDLE DirHandle );
|
|
|
|
NTSTATUS
|
|
ClearDfsReparsePoint(
|
|
HANDLE DirHandle );
|
|
|
|
|
|
NTSTATUS
|
|
CreateLinkDirectories(
|
|
PUNICODE_STRING pLinkName,
|
|
HANDLE RelativeHandle,
|
|
PHANDLE pDirectoryHandle,
|
|
PBOOLEAN pIsNewlyCreated );
|
|
|
|
NTSTATUS
|
|
DeleteLinkDirectories(
|
|
PUNICODE_STRING pLinkName,
|
|
HANDLE RelativeHandle );
|
|
|
|
|
|
NTSTATUS
|
|
CreateLinkReparsePoint(
|
|
PUNICODE_STRING pLinkName,
|
|
HANDLE RelativeHandle );
|
|
|
|
NTSTATUS
|
|
DeleteLinkReparsePoint(
|
|
PUNICODE_STRING pLinkName,
|
|
HANDLE RelativeHandle );
|
|
|
|
|
|
NTSTATUS
|
|
MorphLinkCollision(
|
|
LPWSTR DirectoryName );
|
|
|
|
NTSTATUS
|
|
IsDirectoryReparsePoint(
|
|
HANDLE DirHandle,
|
|
PBOOLEAN pReparsePoint,
|
|
PBOOLEAN pDfsReparsePoint );
|
|
|
|
|
|
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()
|
|
{
|
|
_RootFlags |= ROOT_FOLDER_STANDBY;
|
|
}
|
|
|
|
VOID
|
|
SetLastCreateDirectoryError( NTSTATUS NtStatus)
|
|
{
|
|
_DirectoryCreateError = NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetLastCreateDirectoryError()
|
|
{
|
|
return _DirectoryCreateError;
|
|
}
|
|
|
|
VOID
|
|
ClearLastCreateDirectoryError()
|
|
{
|
|
_DirectoryCreateError = STATUS_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
_CreateDirectories = TRUE;
|
|
}
|
|
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() {_ChildCount++; }
|
|
VOID DecrementChildCount() { _ChildCount--; }
|
|
|
|
public:
|
|
|
|
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
|
|
IsRootFolderAvailableForApi()
|
|
{
|
|
return ((_RootFlags & ROOT_API_AVAILABILITY_FLAGS) == ROOT_API_AVAILABILITY_FLAGS);
|
|
}
|
|
|
|
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(_pLock)
|
|
{
|
|
DeleteCriticalSection( _pLock );
|
|
delete _pLock;
|
|
_pLock = NULL;
|
|
}
|
|
|
|
if(_pChildLocks)
|
|
{
|
|
for ( i = 0; i < NUMBER_OF_SHARED_LINK_LOCKS; i++ )
|
|
{
|
|
DeleteCriticalSection( &_pChildLocks[i] );
|
|
}
|
|
|
|
delete [] _pChildLocks;
|
|
_pChildLocks = NULL;
|
|
}
|
|
|
|
if (pStatistics != NULL)
|
|
{
|
|
pStatistics->ReleaseReference();
|
|
pStatistics = NULL;
|
|
}
|
|
|
|
DfsFreeUnicodeString(&_PhysicalShareName);
|
|
DfsFreeUnicodeString(&_RootRegKeyName);
|
|
DfsFreeUnicodeString(&_LogicalShareName );
|
|
DfsFreeUnicodeString(&_DfsNameContext );
|
|
|
|
}
|
|
|
|
//
|
|
// 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
|
|
GetVisibleContext()
|
|
{
|
|
return &_DfsVisibleContext;
|
|
}
|
|
|
|
//
|
|
// 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()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
DFSSTATUS
|
|
UpdateLinkInformation(
|
|
DFS_METADATA_HANDLE RootHandle,
|
|
LPWSTR ChildName );
|
|
|
|
|
|
|
|
NTSTATUS
|
|
OpenDirectory(
|
|
PUNICODE_STRING pDirectoryName,
|
|
ULONG ShareMode,
|
|
HANDLE RelativeHandle,
|
|
PHANDLE pOpenedHandle,
|
|
PBOOLEAN pIsNewlyCreated );
|
|
|
|
VOID
|
|
CloseDirectory( HANDLE DirHandle);
|
|
|
|
|
|
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 )
|
|
{
|
|
Status = ERROR_SUCCESS;
|
|
*ppFolder = (DfsFolder *)pData;
|
|
(*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;
|
|
DFSSTATUS Status;
|
|
UNICODE_STRING MetadataName;
|
|
PVOID pData;
|
|
|
|
RtlInitUnicodeString( &MetadataName, pChildMetadataNameString);
|
|
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 );
|
|
}
|
|
|
|
if ( NtStatus != STATUS_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;
|
|
DFSSTATUS Status;
|
|
|
|
NtStatus = DfsPrefixTableAcquireWriteLock( _pLogicalPrefixTable );
|
|
if ( NtStatus == STATUS_SUCCESS )
|
|
{
|
|
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 )
|
|
{
|
|
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 )
|
|
{
|
|
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 );
|
|
|
|
|
|
//
|
|
// 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;
|
|
DfsFolder *pFolder = NULL;
|
|
UNICODE_STRING Remaining;
|
|
BOOLEAN IsSubStringMatch;
|
|
|
|
if (pLinkName->Length == 0)
|
|
{
|
|
return ERROR_SUCCESS; // Root name.
|
|
}
|
|
|
|
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
|
|
GetVisibleNameContext(
|
|
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 = GetVisibleContext();
|
|
*pContextName = *pName;
|
|
}
|
|
}
|
|
|
|
|
|
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
|
|
SetApiInformation(
|
|
PUNICODE_STRING pLinkName,
|
|
LPWSTR Server,
|
|
LPWSTR Share,
|
|
DWORD Level,
|
|
LPBYTE pBuffer );
|
|
|
|
VOID
|
|
SetRootFolderSynchronized()
|
|
{
|
|
_RootFlags |= ROOT_FOLDER_SYNCHRONIZED;
|
|
if (IsRootFolderShareAcquired() &&
|
|
GetLastCreateDirectoryError() == STATUS_SUCCESS)
|
|
{
|
|
SetRootDirectoriesCreated();
|
|
}
|
|
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 )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
// Check if the root folder is available for api calls. If not,
|
|
// we return an error back to the caller:
|
|
// dfsdev: check if this error is a valid one to return.
|
|
//
|
|
if (IsRootFolderAvailableForApi() == FALSE)
|
|
{
|
|
Status = ERROR_DEVICE_NOT_AVAILABLE;
|
|
}
|
|
|
|
if ((Status == ERROR_SUCCESS) &&
|
|
(WriteRequest == TRUE))
|
|
{
|
|
Status = ReSynchronize();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
virtual
|
|
DFSSTATUS
|
|
RootApiRequestPrologue( BOOLEAN WriteRequest )
|
|
{
|
|
DFSSTATUS Status;
|
|
|
|
Status = CommonRootApiPrologue( WriteRequest );
|
|
|
|
return Status;
|
|
}
|
|
|
|
virtual
|
|
VOID
|
|
RootApiRequestEpilogue(
|
|
BOOLEAN WriteRequest,
|
|
DFSSTATUS CompletionStatus )
|
|
{
|
|
UNREFERENCED_PARAMETER(CompletionStatus);
|
|
UNREFERENCED_PARAMETER(WriteRequest);
|
|
return NOTHING;
|
|
}
|
|
|
|
virtual
|
|
DFSSTATUS
|
|
ReSynchronize()
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsEmptyDirectory(
|
|
HANDLE DirectoryHandle,
|
|
PVOID pDirectoryBuffer,
|
|
ULONG DirectoryBufferSize );
|
|
|
|
void
|
|
GenerateEventLog(DWORD EventMsg,
|
|
WORD SubStrings,
|
|
const TCHAR * apszSubStrings[],
|
|
DWORD Errorcode);
|
|
};
|
|
|
|
|
|
#endif // __DFS_ROOT_FOLDER__
|