656 lines
16 KiB
C++
656 lines
16 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1995, Microsoft Corporation
|
|
//
|
|
// File: cdfsvol.cxx
|
|
//
|
|
// Contents: Class to abstract a Dfs Volume object and all the
|
|
// administration operations that can be performed on a
|
|
// volume object.
|
|
//
|
|
// Classes: CDfsVolume
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 05/10/93 Sudk Created.
|
|
// 12/19/95 Milans Ported to NT.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "headers.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include <cguid.h>
|
|
#include "cdfsvol.hxx"
|
|
#include "cldap.hxx"
|
|
|
|
extern "C" {
|
|
#include <winldap.h>
|
|
#include <dsgetdc.h>
|
|
}
|
|
#include "setup.hxx"
|
|
|
|
const GUID CLSID_CDfsVolume = {
|
|
0xd9918520, 0xb074, 0x11cd, { 0x47, 0x94, 0x26, 0x8a, 0x82, 0x6b, 0x00, 0x00 }
|
|
};
|
|
|
|
extern "C"
|
|
DWORD
|
|
DfsGetFtServersFromDs(
|
|
PLDAP pLDAP,
|
|
LPWSTR wszDomainName,
|
|
LPWSTR wszDfsName,
|
|
LPWSTR **List);
|
|
|
|
extern CLdap *pDfsmLdap;
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Class CDfsVolume Member Function Implementations
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::CDfsVolume
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDfsVolume::CDfsVolume()
|
|
{
|
|
IDfsVolInlineDebOut((
|
|
DEB_TRACE, "CDfsVolume::+CDfsVolume(0x%x)\n",
|
|
this));
|
|
|
|
_pStorage = NULL;
|
|
|
|
_pwzFileName = _FileNameBuffer;
|
|
_pwszParentName = _ParentNameBuffer;
|
|
_dwRotRegistration = NULL;
|
|
memset(&_peid, 0, sizeof(DFS_PKT_ENTRY_ID));
|
|
_peid.Prefix.Buffer = _EntryPathBuffer;
|
|
_peid.ShortPrefix.Buffer = _ShortPathBuffer;
|
|
_pRecoverySvc = NULL;
|
|
_Deleted = TRUE;
|
|
_State = DFS_VOLUME_STATE_OK;
|
|
_Timeout = GTimeout;
|
|
_pwszComment = NULL;
|
|
memset( &_ftEntryPath, 0, sizeof(FILETIME));
|
|
memset( &_ftState, 0, sizeof(FILETIME));
|
|
memset( &_ftComment, 0, sizeof(FILETIME));
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::~CDfsVolume
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDfsVolume::~CDfsVolume()
|
|
{
|
|
IDfsVolInlineDebOut((
|
|
DEB_TRACE, "CDfsVolume::~CDfsVolume(0x%x)\n",
|
|
this));
|
|
|
|
#if DBG
|
|
if (DfsSvcVerbose & 0x80000000) {
|
|
DbgPrint("CDfsVolume::~CDfsVolume @0x%x\n", this);
|
|
DbgPrint(" _DfsSvcList@0x%x\n", &_DfsSvcList);
|
|
}
|
|
#endif
|
|
|
|
if (_pStorage != NULL)
|
|
_pStorage->Release();
|
|
|
|
if (_pwzFileName != NULL && _pwzFileName != _FileNameBuffer)
|
|
delete [] _pwzFileName;
|
|
|
|
if (_pwszParentName != NULL && _pwszParentName != _ParentNameBuffer)
|
|
delete [] _pwszParentName;
|
|
|
|
if (_peid.Prefix.Buffer != NULL && _peid.Prefix.Buffer != _EntryPathBuffer)
|
|
delete [] _peid.Prefix.Buffer;
|
|
|
|
if (_peid.ShortPrefix.Buffer != NULL && _peid.ShortPrefix.Buffer != _ShortPathBuffer) {
|
|
delete [] _peid.ShortPrefix.Buffer;
|
|
}
|
|
|
|
if (_pwszComment != NULL)
|
|
delete [] _pwszComment;
|
|
|
|
if (_pRecoverySvc != NULL)
|
|
delete _pRecoverySvc;
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// IPersist Methods
|
|
//--------------------------------------------------------------------------
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::GetClassID
|
|
//
|
|
// Synopsis: Return classid - This is the implementation for both the
|
|
// IPersistStorage and IPersistFile Interfaces.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDfsVolume::GetClassID(LPCLSID lpClassID)
|
|
{
|
|
*lpClassID = CLSID_CDfsVolume;
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// IPersistStorage Methods
|
|
//--------------------------------------------------------------------------
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetNameFromStorage
|
|
//
|
|
// Synopsis: Given an IStorage, this routine computes the name of the
|
|
// object.
|
|
//
|
|
// Arguments: [pstg] -- The storage whose name is to be computed
|
|
// [ppwszName] -- Points to a buffer containing the name
|
|
// [wszBuffer] -- The buffer to use if name is <= MAX_PATH
|
|
//
|
|
// Returns: ERROR_SUCCESS if successful
|
|
// ERROR_OUTOFMEMORY if out of memory
|
|
// NERR_DfsInternalError if any other error
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
GetNameFromStorage(
|
|
CStorage *pstg,
|
|
LPWSTR *ppwszName,
|
|
WCHAR wszBuffer[])
|
|
{
|
|
DWORD dwErr;
|
|
ULONG cLen;
|
|
LPWSTR pwszName = NULL;
|
|
DFSMSTATSTG statstg;
|
|
|
|
ZeroMemory( &statstg, sizeof(statstg) );
|
|
|
|
dwErr = pstg->Stat( &statstg, STATFLAG_DEFAULT );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
cLen = 2 + wcslen( statstg.pwcsName ) + 1;
|
|
|
|
if (cLen > MAX_PATH) {
|
|
|
|
pwszName = new WCHAR[ cLen ];
|
|
|
|
if (pwszName == NULL) {
|
|
|
|
IDfsVolInlineDebOut((
|
|
DEB_ERROR, "Unable to allocate %d bytes\n",
|
|
cLen * sizeof(WCHAR)));
|
|
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
|
|
} else {
|
|
|
|
wcscpy( pwszName, statstg.pwcsName );
|
|
|
|
*ppwszName = pwszName;
|
|
|
|
}
|
|
|
|
} else { // Use given buffer
|
|
|
|
pwszName = wszBuffer;
|
|
|
|
wcscpy( pwszName, statstg.pwcsName );
|
|
|
|
*ppwszName = pwszName;
|
|
|
|
}
|
|
|
|
delete [] statstg.pwcsName;
|
|
|
|
} else {
|
|
|
|
IDfsVolInlineDebOut((
|
|
DEB_ERROR, "Error %08lx getting storage stats\n", dwErr ));
|
|
|
|
dwErr = NERR_DfsInternalError;
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::InitNew
|
|
//
|
|
// Synopsis: InitNew is only called by the reconciler when a new
|
|
// volume object is created as a result of a reconciliation.
|
|
// We simply create all the appropriate property sets so that
|
|
// the volume object reconciler can reconcile the property sets
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDfsVolume::InitNew(CStorage *pStg)
|
|
{
|
|
|
|
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::InitNew()\n"));
|
|
|
|
DWORD dwErr;
|
|
|
|
ASSERT( _pStorage == NULL );
|
|
|
|
//
|
|
// Save and AddRef the storage so it wont go away from us.
|
|
//
|
|
|
|
_pStorage = pStg;
|
|
|
|
_pStorage->AddRef();
|
|
|
|
//
|
|
// First thing we do now is to setup the Class ID.
|
|
//
|
|
|
|
dwErr = _pStorage->SetClass(CLSID_CDfsVolume);
|
|
|
|
//
|
|
// Next, we Initialize the property sets.
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = SetVersion( TRUE );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
_Recover.Initialize(_pStorage);
|
|
|
|
_Recover.SetDefaultProps();
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = _DfsSvcList.SetNullSvcList( _pStorage );
|
|
|
|
//
|
|
// Need to initialize our _pwzFileName member
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
ASSERT( _pwzFileName == _FileNameBuffer );
|
|
|
|
dwErr = GetNameFromStorage(
|
|
_pStorage,
|
|
&_pwzFileName,
|
|
_FileNameBuffer );
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
_Deleted = FALSE;
|
|
|
|
IDfsVolInlineDebOut((
|
|
DEB_TRACE, "Volume Object [%ws] successfully inited\n",
|
|
_pwzFileName));
|
|
|
|
}
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::Save
|
|
//
|
|
// Synopsis: Saves the persistent state of the object. We really don't need
|
|
// to support this. It really makes no sense to support this?
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDfsVolume::Save(
|
|
CStorage *pStgSave,
|
|
BOOL fSameAsLoad)
|
|
{
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::Load
|
|
//
|
|
// Synopsis: Loads a DfsVolume and the components it contains from
|
|
// storage.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDfsVolume::Load(
|
|
CStorage *pStg)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
|
|
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Load()\n"));
|
|
|
|
ASSERT(_pStorage == NULL);
|
|
_pStorage = pStg;
|
|
_pStorage->AddRef();
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = GetVersion( &_Version );
|
|
|
|
//
|
|
// Out here we are passing in the _pPSStorage. The called people will
|
|
// Addref and release this _pStorage on their own.
|
|
//
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
_Recover.Initialize(_pStorage);
|
|
|
|
dwErr = _DfsSvcList.InitializeServiceList(_pStorage);
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = GetIdProps( &_EntryType,
|
|
&_peid.Prefix.Buffer,
|
|
&_peid.ShortPrefix.Buffer,
|
|
&_pwszComment,
|
|
&_peid.Uid,
|
|
&_State,
|
|
&_Timeout,
|
|
&_ftEntryPath,
|
|
&_ftState,
|
|
&_ftComment);
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
_peid.Prefix.Length = wcslen(_peid.Prefix.Buffer) * sizeof(WCHAR);
|
|
_peid.Prefix.MaximumLength = _peid.Prefix.Length + sizeof(WCHAR);
|
|
|
|
_peid.ShortPrefix.Length = wcslen(_peid.ShortPrefix.Buffer) * sizeof(WCHAR);
|
|
_peid.ShortPrefix.MaximumLength = _peid.ShortPrefix.Length + sizeof(WCHAR);
|
|
|
|
dwErr = _Recover.GetRecoveryProps(&_RecoveryState, &_pRecoverySvc);
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
IDfsVolInlineDebOut((DEB_ERROR,
|
|
"CouldNot read RecoveryProps off Stg %08lx\n",
|
|
dwErr));
|
|
|
|
_RecoveryState = DFS_RECOVERY_STATE_NONE;
|
|
_pRecoverySvc = NULL;
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
_Deleted = FALSE;
|
|
}
|
|
|
|
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Load() exit\n"));
|
|
|
|
return( dwErr );
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// IPersistFile Methods
|
|
//--------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
CDfsVolume::Load(LPCWSTR pwszFileName, DWORD grfMode)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
dwErr = LoadNoRegister( pwszFileName, grfMode );
|
|
|
|
return( dwErr );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::LoadNoRegister
|
|
//
|
|
// Synopsis: Load the DfsVolume from a volume object. This is where all the
|
|
// initialization takes place.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDfsVolume::LoadNoRegister(
|
|
LPCWSTR pwszFileName,
|
|
DWORD grfMode)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
IDfsVolInlineDebOut((
|
|
DEB_TRACE, "CDfsVolume::LoadNoRegister(%ws)\n", pwszFileName));
|
|
|
|
dwErr = DfsmOpenStorage(
|
|
pwszFileName,
|
|
(CStorage FAR* FAR*)&_pStorage);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
ULONG uLen = wcslen(pwszFileName);
|
|
|
|
if (uLen > MAX_PATH)
|
|
_pwzFileName = new WCHAR[(uLen+1)];
|
|
else
|
|
_pwzFileName = _FileNameBuffer;
|
|
|
|
|
|
if (_pwzFileName == NULL)
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
else
|
|
wcscpy(_pwzFileName, pwszFileName);
|
|
|
|
} else {
|
|
|
|
IDfsVolInlineDebOut((
|
|
DEB_TRACE, "Unable to open %ws, %08lx\n", pwszFileName, dwErr));
|
|
|
|
}
|
|
|
|
//
|
|
// Before we do anything, lets see if the volume object is current.
|
|
//
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = UpgradeObject();
|
|
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
dwErr = GetVersion( &_Version );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
//
|
|
// Out here we are passing in the _pPSStorage. The called people
|
|
// will Addref and release this _pStorage on their own.
|
|
//
|
|
_Recover.Initialize(_pStorage);
|
|
|
|
dwErr = _DfsSvcList.InitializeServiceList(_pStorage);
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = GetIdProps( &_EntryType,
|
|
&(_peid.Prefix.Buffer),
|
|
&(_peid.ShortPrefix.Buffer),
|
|
&_pwszComment,
|
|
&(_peid.Uid),
|
|
&_State,
|
|
&_Timeout,
|
|
&_ftEntryPath,
|
|
&_ftState,
|
|
&_ftComment);
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
_peid.Prefix.Length = wcslen(_peid.Prefix.Buffer) * sizeof(WCHAR);
|
|
_peid.Prefix.MaximumLength = _peid.Prefix.Length + sizeof(WCHAR);
|
|
|
|
_peid.ShortPrefix.Length = wcslen(_peid.ShortPrefix.Buffer) * sizeof(WCHAR);
|
|
_peid.ShortPrefix.MaximumLength = _peid.ShortPrefix.Length + sizeof(WCHAR);
|
|
|
|
dwErr = _Recover.GetRecoveryProps(&_RecoveryState, &_pRecoverySvc);
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
IDfsVolInlineDebOut((DEB_ERROR,
|
|
"CouldNot read RecoveryProps off %ws\n",
|
|
_pwzFileName));
|
|
IDfsVolInlineDebOut((DEB_ERROR,"\tError = %08lx\n",dwErr));
|
|
|
|
_RecoveryState = DFS_RECOVERY_STATE_NONE;
|
|
_pRecoverySvc = NULL;
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
_Deleted = FALSE;
|
|
}
|
|
|
|
|
|
IDfsVolInlineDebOut((
|
|
DEB_TRACE, "CDfsVolume::LoadNoRegister() exit\n"));
|
|
return( dwErr );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CDfsVolume::Save
|
|
//
|
|
// Synopsis: Not Implemented
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
CDfsVolume::Save(LPCWSTR pwzFileName, BOOL fRemember)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
return( dwErr );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CDfsVolume::SyncWithRemoteServerNameInDs(void)
|
|
{
|
|
DWORD InfoSize = 0;
|
|
DWORD dwError = NO_ERROR;
|
|
DFS_INFO_3 DfsInfo;
|
|
BOOLEAN Found = FALSE;;
|
|
PDFSM_ROOT_LIST pRootList = NULL;
|
|
DFS_REPLICA_INFO *pReplicaInfo = NULL;
|
|
WCHAR* ServerShare = NULL;
|
|
DWORD Length = 0;
|
|
WCHAR* DcName = NULL;
|
|
DWORD i,j;
|
|
PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
|
|
LPWSTR *pList = NULL;
|
|
WCHAR wszFtDfsName[MAX_PATH+1];
|
|
ULONG start = 0;
|
|
ULONG end = 0;
|
|
CDfsService *pService;
|
|
LPWSTR DfsName = NULL;
|
|
|
|
|
|
RtlZeroMemory(wszFtDfsName, sizeof(wszFtDfsName));
|
|
RtlCopyMemory(wszFtDfsName, _peid.Prefix.Buffer, _peid.Prefix.Length);
|
|
|
|
//
|
|
// Extract the ftdfs name from the DfsInfo.EntryPath
|
|
//
|
|
|
|
for (DfsName = &wszFtDfsName[1];
|
|
*DfsName != UNICODE_PATH_SEP && *DfsName != UNICODE_NULL;
|
|
DfsName++) {
|
|
|
|
NOTHING;
|
|
|
|
}
|
|
|
|
if (*DfsName == UNICODE_PATH_SEP)
|
|
DfsName++;
|
|
|
|
|
|
if(dwError == ERROR_SUCCESS) {
|
|
dwError = DfsGetFtServersFromDs(
|
|
NULL,
|
|
NULL,
|
|
DfsName,
|
|
&pList
|
|
);
|
|
}
|
|
|
|
if(dwError == ERROR_SUCCESS) {
|
|
pService=_DfsSvcList.GetFirstService();
|
|
while(pService) {
|
|
Found = FALSE;
|
|
for(j=0;pList[j]!=NULL;j++) {
|
|
Length = sizeof(WCHAR) * 2; // whackwhack
|
|
Length += sizeof(WCHAR) * wcslen(pService->GetServiceName()); // server
|
|
Length += sizeof(WCHAR); // whack
|
|
Length += sizeof(WCHAR) * wcslen(pService->GetShareName()); // share
|
|
Length += sizeof(WCHAR); // terminating null
|
|
ServerShare = (WCHAR *)malloc(Length);
|
|
if(ServerShare == NULL) {
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
wcscpy(ServerShare, L"\\\\");
|
|
wcscat(ServerShare, pService->GetServiceName());
|
|
wcscat(ServerShare, L"\\");
|
|
wcscat(ServerShare, pService->GetShareName());
|
|
if(wcscmp(ServerShare, pList[j]) == 0) {
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
free(ServerShare);
|
|
ServerShare = NULL;
|
|
}
|
|
if(!Found) {
|
|
// after we delete the service we can no longer get the next in the list,
|
|
// so we grab it first.
|
|
CDfsService *NextService = _DfsSvcList.GetNextService(pService);
|
|
dwError = _DfsSvcList.DeleteService(pService, FALSE);
|
|
if(dwError != ERROR_SUCCESS) {
|
|
break;
|
|
}
|
|
pService = NextService;
|
|
} else {
|
|
pService=_DfsSvcList.GetNextService(pService);
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if(pList) {
|
|
NetApiBufferFree(pList);
|
|
}
|
|
|
|
|
|
return dwError;
|
|
}
|