|
|
//+----------------------------------------------------------------------------//+-------------------------------------------------------------------------
//
// Copyright (C) 1992-1995, Microsoft Corporation
//
// File: service.cxx
//
// Contents: A Class for abstracting the concept of a Service/Replica on
// each volume in the namespace.
//
// Classes:
//
// Functions:
//
// History: 26-Jan-93 SudK Created
// 12-May-93 SudK Modified
// 28-Mar-95 Milans Updated to handle server
// knowledge inconsistencies
// 27-Dec-95 Milans Updated for NT/SUR
//
//--------------------------------------------------------------------------
//#include <ntos.h>
//#include <ntrtl.h>
//#include <nturtl.h>
//#include <dfsfsctl.h>
//#include <windows.h>
#include "headers.hxx"
#pragma hdrstop
extern "C" { #include <dfserr.h>
#include <dfspriv.h> // For I_NetDfsXXX calls
#include "dfsmsrv.h"
}
#include "service.hxx"
#include "cdfsvol.hxx"
#include "jnpt.hxx"
#include "dfsmwml.h"
INIT_DFS_REPLICA_INFO_MARSHAL_INFO()
DWORD RelationInfoToNetInfo( PDFS_PKT_RELATION_INFO RelationInfo, LPNET_DFS_ENTRY_ID_CONTAINER pNetInfo);
NTSTATUS DfspCreateExitPoint ( IN HANDLE DriverHandle, IN LPGUID Uid, IN LPWSTR Prefix, IN ULONG Type, IN ULONG ShortPrefixLen, OUT LPWSTR ShortPrefix);
NTSTATUS DfspDeleteExitPoint ( IN HANDLE DriverHandle, IN LPGUID Uid, IN LPWSTR Prefix, IN ULONG Type);
//+------------------------------------------------------------------------
//
// Member: CDfsService::CDfsService, private
//
// Synopsis: This is private constructor with no arguments.
//
// Arguments: None.
//
// Returns: Nothing.
//
// Notes: This constructor should be followed up by some kind of
// deserialization to setup the instance appropriately.
//
//-------------------------------------------------------------------------
CDfsService::CDfsService( void ) {
IDfsVolInlineDebOut(( DEB_TRACE, "CDfsService::+CDfsService(1)(0x%x)\n", this));
//
// Initialise all the private section appropriately.
//
memset(&_DfsReplicaInfo, 0, sizeof(DFS_REPLICA_INFO)); memset(&_DfsPktService, 0, sizeof(DFS_SERVICE)); memset(&_ftModification, 0, sizeof(FILETIME));
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::CDfsService(1)() exit\n")); }
//+------------------------------------------------------------------------
//
// Member: CDfsService::CDfsService
//
// Synopsis: This is the primary way of constructing a CDfsService instance
// using a DFS_REPLICA_INFO structure. The DFS_REPLICA_INFO struct
// passed in has to be freed by the caller. This constructor does
// not eat up that memory.
//
// Arguments: [pReplicaInfo] -- The ReplicaInfo struct that defines this Svc.
// [bCreatePktSvc] -- Whether to create PKT Service struct in
// private section.
// [pdwErr] -- On return, indicates result of construction.
//
// Returns: *pdwErr will be set to ERROR_OUTOFMEMORY if memory allocation fails.
//
// Notes: This constructor allocates required memory and then copies.
//
//-------------------------------------------------------------------------
CDfsService::CDfsService( PDFS_REPLICA_INFO pReplicaInfo, BOOLEAN bCreatePktSvc, DWORD *pdwErr ) { DWORD dwErr = ERROR_SUCCESS; ULONG size; LPBYTE buffer;
IDfsVolInlineDebOut(( DEB_TRACE, "CDfsService::+CDfsService(2)(0x%x)\n", this));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsService::CDfsService(%ws,%ws,%ws)\n", pReplicaInfo->pwszServerName, pReplicaInfo->pwszShareName, bCreatePktSvc == TRUE ? L"TRUE" : L"FALSE"); #endif
//
// First initialise the ServiceEntry structure.
//
ZeroMemory(&_DfsReplicaInfo, sizeof(DFS_REPLICA_INFO)); ZeroMemory(&_DfsPktService, sizeof(DFS_SERVICE)); ZeroMemory(&_ftModification, sizeof(FILETIME));
//
// We first need to initialise the ReplicaInfo structure in the private
// section. The simplest way to do this is to serialize what we got and
// then Deserialize the same thing.
//
_DfsReplicaInfo = *pReplicaInfo; // Temporarily
size = GetMarshalSize();
buffer = new BYTE[size];
if (buffer != NULL) {
Serialize(buffer, size);
//
// Now we unmarshall this buffer again to get a new ReplicaInfo
// structure.
//
DeSerialize(buffer, size);
delete [] buffer;
} else {
ZeroMemory( &_DfsReplicaInfo, sizeof(DFS_REPLICA_INFO));
dwErr = ERROR_OUTOFMEMORY;
}
//
// Now that we have initialised the DfsReplicaInfo structure in the
// private section, we need to initialize the DFS_SERVICE structure
// as well.
//
if (dwErr == ERROR_SUCCESS && bCreatePktSvc) dwErr = InitializePktSvc();
*pdwErr = dwErr;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::CDfsService(2)() exit\n"));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsService::CDfsService exit %d\n", dwErr); #endif
}
//+------------------------------------------------------------------------
//
// Member: CDfsService::~CDfsService
//
// Synopsis: The Destructor. Gets rid of all the memory.
//
// Arguments: None
//
// Returns: Nothing.
//
// Notes: This assumes that the constructor used "new" to allocate
// memory for the strings in the private structure.
//
//-------------------------------------------------------------------------
CDfsService::~CDfsService(void) { ULONG i; PDS_MACHINE pMachine;
IDfsVolInlineDebOut(( DEB_TRACE, "CDfsService::~CDfsService(0x%x)\n", this));
//
// Need to get rid of memory in DFS_SERVICE and DfsReplicaInfo structs.
//
if (_DfsReplicaInfo.pwszServerName != pwszComputerName) { MarshalBufferFree( _DfsReplicaInfo.pwszServerName ); }
MarshalBufferFree( _DfsReplicaInfo.pwszShareName );
if (_DfsPktService.pMachEntry != NULL) { pMachine = _DfsPktService.pMachEntry->pMachine;
if (pMachine != NULL) DfsMachineFree(pMachine); // Free using appropriate mechanism
delete _DfsPktService.pMachEntry;
}
if (_DfsPktService.Name.Buffer != NULL) { delete [] _DfsPktService.Name.Buffer; }
if (_DfsPktService.Address.Buffer != NULL) { delete [] _DfsPktService.Address.Buffer; }
if (_DfsPktService.StgId.Buffer != NULL) { delete [] _DfsPktService.StgId.Buffer; }
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::~CDfsService() exit\n"));
}
//+------------------------------------------------------------------------
//
// Member: CDfsService::InitializePktSvc
//
// Synopsis: This is the method that initialises the DFS_SERVICE structure
// in the private section of Class. The DFS_REPLICA_INFO
// structure should have been setup by the time this routine is
// called.
//
// Arguments: None
//
// Returns: [ERROR_SUCCESS] -- If everything went ok.
//
// [ERROR_OUTOFMEMORY] -- If unable to allocate requisite memory.
//
// History: 26-Jan-1993 Sudk Created.
// 13-May-93 Sudk Modified for new interface.
//
//-------------------------------------------------------------------------
DWORD CDfsService::InitializePktSvc() { DWORD dwErr = ERROR_SUCCESS; UNICODE_STRING ustr;
//
// We just put in a switch for Each ReplicaType that we will handle.
//
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::InitializePktSvc()\n"));
switch(_DfsReplicaInfo.ulReplicaType) {
case DFS_STORAGE_TYPE_DFS:
_DfsPktService.ProviderId = PROV_ID_DFS_RDR; _DfsPktService.Capability = PROV_DFS_RDR; _DfsPktService.Type = DFS_SERVICE_TYPE_MASTER; _DfsPktService.Cost = (ULONG) ~0L; break;
case DFS_STORAGE_TYPE_NONDFS: _DfsPktService.ProviderId = PROV_ID_LM_RDR; _DfsPktService.Capability = PROV_STRIP_PREFIX; _DfsPktService.Type = DFS_SERVICE_TYPE_DOWN_LEVEL | DFS_SERVICE_TYPE_MASTER; _DfsPktService.Cost = (ULONG) ~0L; break;
default: ASSERT( FALSE && "Invalid Replica Type"); break;
}
if (_DfsReplicaInfo.ulReplicaState & DFS_STORAGE_STATE_OFFLINE) _DfsPktService.Type |= DFS_SERVICE_TYPE_OFFLINE;
//
// Now, we construct the DS_MACHINE
//
_DfsPktService.pMachEntry = (PDFS_MACHINE_ENTRY) new DFS_MACHINE_ENTRY; if (_DfsPktService.pMachEntry == NULL) { return( ERROR_OUTOFMEMORY ); } else { ZeroMemory( (PVOID) _DfsPktService.pMachEntry, sizeof( DFS_MACHINE_ENTRY ) ); }
dwErr = DfsGetDSMachine( _DfsReplicaInfo.pwszServerName, &_DfsPktService.pMachEntry->pMachine);
if (dwErr != ERROR_SUCCESS) {
delete _DfsPktService.pMachEntry; _DfsPktService.pMachEntry = NULL;
IDfsVolInlineDebOut((DEB_ERROR, "Unable to get to %ws machine \n", _DfsReplicaInfo.pwszServerName));
return( ERROR_OUTOFMEMORY );
}
ustr.Length = (USHORT)wcslen(_DfsReplicaInfo.pwszServerName); ustr.Buffer = new WCHAR [ustr.Length + 1]; ustr.Length *= sizeof(WCHAR); ustr.MaximumLength = ustr.Length + sizeof(WCHAR);
if (ustr.Buffer != NULL) { wcscpy(ustr.Buffer, _DfsReplicaInfo.pwszServerName); _DfsPktService.Name = ustr; } else { delete _DfsPktService.pMachEntry; _DfsPktService.pMachEntry = NULL; return( ERROR_OUTOFMEMORY ); }
ustr.Length = (1 + wcslen(_DfsReplicaInfo.pwszServerName) + 1 + wcslen(_DfsReplicaInfo.pwszShareName)); ustr.Buffer = new WCHAR [ustr.Length + 1]; ustr.Length *= sizeof(WCHAR); ustr.MaximumLength = ustr.Length + sizeof(WCHAR);
if (ustr.Buffer != NULL) { wcscpy(ustr.Buffer, UNICODE_PATH_SEP_STR); wcscat(ustr.Buffer, _DfsReplicaInfo.pwszServerName); wcscat(ustr.Buffer, UNICODE_PATH_SEP_STR); wcscat(ustr.Buffer, _DfsReplicaInfo.pwszShareName); _DfsPktService.Address = ustr; } else { delete [] _DfsPktService.Name.Buffer; _DfsPktService.Name.Buffer = NULL; _DfsPktService.Name.Length = _DfsPktService.Name.MaximumLength = 0; delete _DfsPktService.pMachEntry; _DfsPktService.pMachEntry = NULL; return( ERROR_OUTOFMEMORY ); }
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::InitializePktSvc() exit\n"));
return( ERROR_SUCCESS );
}
//+------------------------------------------------------------------------
//
// Member: CDfsService::DeSerialize, private
//
// Synopsis: This function takes a buffer as an argument and deserializes
// its contents into the private DfsReplicaInfo structure.
//
// Arguments: [buffer] -- The buffer which has to be deserialized.
// [size] -- The size of the buffer.
//
// Returns: Nothing.
//
//
//
// History: 13-May-93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::DeSerialize(BYTE *buffer, ULONG size) {
ULONG ulReplicaType; MARSHAL_BUFFER marshalBuffer; NTSTATUS status;
MarshalBufferInitialize(&marshalBuffer, size, buffer);
status = DfsRtlGet(&marshalBuffer, &MiFileTime, &_ftModification);
if (!NT_SUCCESS(status)) return( ERROR_INVALID_PARAMETER );
//
// Now that we know which Minfo Struct to use and we also have the
// buffer at hand. We can just do a simple Unmarshall to get the stuff
// out of the buffer.
//
status = DfsRtlGet(&marshalBuffer, &MiDfsReplicaInfo, &_DfsReplicaInfo);
if (ulDfsManagerType == DFS_MANAGER_SERVER) {
//
// To handle machine renames, we store the local computer name as a
// L"." Replace this with the current computer name, if necessary.
//
if (NT_SUCCESS(status) && pwszComputerName != NULL) {
if (wcscmp(_DfsReplicaInfo.pwszServerName, L".") == 0) {
MarshalBufferFree(_DfsReplicaInfo.pwszServerName);
_DfsReplicaInfo.pwszServerName = pwszComputerName;
} }
}
if (status == STATUS_INSUFFICIENT_RESOURCES) { return( ERROR_OUTOFMEMORY ); } else if (!NT_SUCCESS(status)) { return( ERROR_INVALID_PARAMETER ); }
//
// Now that we have deserialized we are done.
//
return ERROR_SUCCESS;
}
//+------------------------------------------------------------------------
//
// Member: CDfsService::DeSerialize, public
//
// Synopsis: This function takes a buffer as an argument and deserializes
// its contents and creates an instance of this class and
// returns a pointer to it.
//
// Arguments: [buffer] -- The buffer which has to be deserialized.
// [size] -- The size of the buffer.
// [ppService] - The new instance is returned here.
//
// Returns: ERROR_SUCCESS -- If all went well.
//
// Notes: This method will not throw any exceptions.
//
// History: 13-May-93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::DeSerialize( PBYTE buffer, ULONG size, CDfsService **ppService) {
DWORD dwErr = ERROR_SUCCESS;
*ppService = NULL;
//
// Construct a NULL CDfsService first and then unmarshall the stuff.
//
*ppService = new CDfsService;
if (*ppService == NULL) { return(ERROR_OUTOFMEMORY); }
dwErr = (*ppService)->DeSerialize(buffer, size);
//
// Now the ReplicaInfo struct in the private section has been setup
// appropriately. What is left is to setup the DFS_SERVICE struct
// as well and then we have a properly constructed CDfsService.
//
if (dwErr == ERROR_SUCCESS) { dwErr = (*ppService)->InitializePktSvc(); }
if (dwErr != ERROR_SUCCESS) { delete *ppService; *ppService = NULL; }
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Member: CDfsService::Serialize, public
//
// Synopsis: This function takes a buffer as an argument and serializes
// the private DfsReplicaInfo structure into that buffer.
//
// Arguments: [buffer] -- ReplInfo struct to be serialised into this.
// [size] -- The size of the buffer.
//
// Returns: Nothing.
//
// Notes: Will ASSERT if the buffer is not big enough. The
// size of the buffer should have been calculated using
// the function GetMarshalSize() in this class.
//
// The ServiceInfo MUST BE MARSHALLED FIRST!. This is because
// the Deserialize routine does a _GetUlong to figure out what
// kind of ServiceInfo was marshalled.
//
// History: 13-May-93 SudK Created.
//
//-------------------------------------------------------------------------
VOID CDfsService::Serialize(PBYTE buffer, ULONG size) {
MARSHAL_BUFFER marshalBuffer; NTSTATUS status; DFS_REPLICA_INFO dfsReplicaInfo;
ASSERT( size >= GetMarshalSize() );
//
// Now that we have a proper buffer lets go marshall the stuff in.
//
MarshalBufferInitialize(&marshalBuffer, size, buffer); status = DfsRtlPut(&marshalBuffer, &MiFileTime, &_ftModification); ASSERT(NT_SUCCESS(status));
dfsReplicaInfo = _DfsReplicaInfo;
if (ulDfsManagerType == DFS_MANAGER_SERVER && pwszComputerName != NULL) {
if (_wcsicmp(dfsReplicaInfo.pwszServerName, pwszComputerName) == 0) dfsReplicaInfo.pwszServerName = L".";
}
status = DfsRtlPut(&marshalBuffer, &MiDfsReplicaInfo, &dfsReplicaInfo); ASSERT(NT_SUCCESS(status));
}
//+----------------------------------------------------------------------------
//
// Function: CDfsService::GetNetStorageInfo, public
//
// Synopsis: Returns the service info in a DFS_STORAGE_INFO struct.
// Useful for NetDfsXXX APIs.
//
// Arguments: [pInfo] -- Pointer to DFS_STORAGE_INFO to fill. Pointer
// members will be allocated using MIDL_user_allocate.
//
// [pcbInfo] -- On successful return, set to size in bytes of
// returned info. The size does not include the size
// of the DFS_STORAGE_INFO struct itself.
//
// Returns:
//
//-----------------------------------------------------------------------------
DWORD CDfsService::GetNetStorageInfo( LPDFS_STORAGE_INFO pInfo, LPDWORD pcbInfo) { DWORD dwErr = ERROR_SUCCESS; LPWSTR wszShare; DWORD cbInfo = 0, cbItem;
pInfo->State = _DfsReplicaInfo.ulReplicaState;
cbItem = (wcslen(_DfsReplicaInfo.pwszServerName) + 1) * sizeof(WCHAR); pInfo->ServerName = (LPWSTR) MIDL_user_allocate(cbItem); if (pInfo->ServerName != NULL) { wcscpy(pInfo->ServerName, _DfsReplicaInfo.pwszServerName); cbInfo += cbItem; } else { dwErr = ERROR_OUTOFMEMORY; }
if (dwErr == ERROR_SUCCESS) { cbItem = (wcslen(_DfsReplicaInfo.pwszShareName) + 1) * sizeof(WCHAR); pInfo->ShareName = (LPWSTR) MIDL_user_allocate(cbItem); if (pInfo->ShareName != NULL) { wcscpy( pInfo->ShareName, _DfsReplicaInfo.pwszShareName ); cbInfo += cbItem; } else { MIDL_user_free( pInfo->ServerName ); pInfo->ServerName = NULL; dwErr = ERROR_OUTOFMEMORY; } }
*pcbInfo = cbInfo;
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Member: CDfsService::IsEqual, public
//
// Synopsis: This function takes a replicaInfo structure and compares it
// for equality with itself. After all a ReplicaInfo structure
// uniquely identifies a service.
//
// Arguments: [pReplicaInfo] -- A replicaInfo struct.
//
// Returns: TRUE if it is equal else FALSE.
//
// Notes: Can throw an exception due to bad structures etc.
//
// History: 13-May-93 SudK Created.
//
//-------------------------------------------------------------------------
BOOLEAN CDfsService::IsEqual(PDFS_REPLICA_INFO pReplicaInfo) {
if (_wcsicmp(pReplicaInfo->pwszServerName, _DfsReplicaInfo.pwszServerName)) { return(FALSE); }
if (_wcsicmp(pReplicaInfo->pwszShareName, _DfsReplicaInfo.pwszShareName)) { return(FALSE); }
return(TRUE);
}
//+------------------------------------------------------------------------
//
// Method: CDfsService::CreateExitPoint, public
//
// Synopsis: This method creates an exit point at the remote machine.
//
// Arguments: [peid] -- The Pkt Entry ID of the exit point.
//
// [Type] -- The type of volume where we are.
//
// Returns: [ERROR_SUCCESS] -- If all went well.
//
// [NERR_DfsServerUpgraded] -- A non-dfs replica has since been
// made Dfs aware.
//
// [NERR_DfsServerNotDfsAware] -- Server is non-dfs or
// replica is unavailable at this time.
//
// History: 01 Feb 93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::CreateExitPoint( PDFS_PKT_ENTRY_ID peid, ULONG Type) { DWORD dwErr = ERROR_SUCCESS; NET_API_STATUS netStatus; ULONG dwVersion; BOOL fRetry; HANDLE pktHandle = NULL; NTSTATUS status = STATUS_SUCCESS;
//
// If this is marked as a non-dfs aware replica, try and see if the
// replica has been made Dfs aware. If so, we return a distinguished
// error code so the caller can turn around, do a create local partition
// and retry the CreateExitPoint.
//
if (_DfsReplicaInfo.ulReplicaType == DFS_STORAGE_TYPE_NONDFS) {
//
// At the time this server was added as a replica for this volume,
// this server was was either unavailable or not dfs aware. So,
// try and see if the server is now Dfs Aware or not.
//
netStatus = I_NetDfsGetVersion( _DfsReplicaInfo.pwszServerName, &dwVersion);
DFSM_TRACE_ERROR_HIGH(netStatus, ALL_ERROR, CDfsServiceCreateExitPoint_Error_I_NetDfsGetVersion, LOGSTATUS(netStatus)); if (netStatus == NERR_Success) {
return( NERR_DfsServerUpgraded );
} else {
return( NERR_DfsServerNotDfsAware );
}
}
ASSERT (_DfsReplicaInfo.ulReplicaType != DFS_STORAGE_TYPE_NONDFS);
status = PktOpen(&pktHandle, 0, 0, NULL);
if (!NT_SUCCESS(status)) { dwErr = RtlNtStatusToDosError(status); return dwErr; }
fRetry = FALSE;
do {
netStatus = (NET_API_STATUS)DfspCreateExitPoint( pktHandle, &peid->Uid, peid->Prefix.Buffer, Type, peid->ShortPrefix.MaximumLength/sizeof(WCHAR), peid->ShortPrefix.Buffer);
if (netStatus == STATUS_SUCCESS) peid->ShortPrefix.Length = wcslen(peid->ShortPrefix.Buffer) * sizeof(WCHAR);
if (fRetry) {
//
// We have already tried once to sync up the server. Time to quit
//
fRetry = FALSE;
} else if (netStatus == DFS_STATUS_NOSUCH_LOCAL_VOLUME || netStatus == DFS_STATUS_LOCAL_ENTRY || netStatus == DFS_STATUS_BAD_EXIT_POINT) {
fRetry = SyncKnowledge();
}
} while ( fRetry );
if (pktHandle != NULL) PktClose(pktHandle);
if (netStatus != NERR_Success) dwErr = RtlNtStatusToDosError(netStatus);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_TRACE, "Failed to do CreateExitPt %ws at %ws. Error: %x\n", peid->Prefix.Buffer, _DfsReplicaInfo.pwszServerName, dwErr)); }
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Method: CDfsService::DeleteExitPoint()
//
// Synopsis: This method deletes an exit point at the remote machine.
//
// Arguments: [peid] -- ExitPath to be deleted along with GUID in the
// EntryId struct.
// [Type] -- The type of volume where we are.
//
// Returns: [ERROR_SUCCESS] -- If successfully deleted exit point, or exit point
// did not exist to begin with.
//
// Rpc error from I_NetDfsDeleteExitPoint
//
// Notes:
//
// History: 01 Feb 93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::DeleteExitPoint( PDFS_PKT_ENTRY_ID peid, ULONG Type) { DWORD dwErr = ERROR_SUCCESS; NTSTATUS status = STATUS_SUCCESS; BOOL fRetry; HANDLE pktHandle = NULL;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService:DeleteExitPoint()\n"));
// ASSERT (_DfsReplicaInfo.ulReplicaType != DFS_STORAGE_TYPE_NONDFS);
status = PktOpen(&pktHandle, 0, 0, NULL);
fRetry = FALSE;
do {
status = DfspDeleteExitPoint( pktHandle, &peid->Uid, peid->Prefix.Buffer, Type);
if (fRetry) {
//
// We have already tried once to sync up the server. Time to quit
//
fRetry = FALSE;
} else if (status == DFS_STATUS_BAD_EXIT_POINT || status == DFS_STATUS_NOSUCH_LOCAL_VOLUME) {
//
// The server is out of sync with the DC. Lets try to force it
// into a valid state
//
fRetry = SyncKnowledge();
}
} while ( fRetry );
if (pktHandle != NULL) PktClose(pktHandle);
if (!NT_SUCCESS(status)) dwErr = RtlNtStatusToDosError(status);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_TRACE, "Failed to do DeleteExitPt %ws at %ws. Error: %x\n", peid->Prefix.Buffer, _DfsReplicaInfo.pwszServerName, status )); }
if (status == DFS_E_BAD_EXIT_POINT) dwErr = ERROR_SUCCESS;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService:DeleteExitPoint() exit\n"));
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Method: CDfsService::CreateLocalVolume()
//
// Synopsis: This method creates knowledge regarding a new volume at the
// remote server.
//
// Arguments: [peid] -- The EntryId. This class does not know this.
// [EntryType] -- Type of Entry. This class doesn't know this.
//
// Returns: [ERROR_SUCCESS] -- Successfully created local volume knowledge on
// server.
//
// History: 01 Feb 93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::CreateLocalVolume( PDFS_PKT_ENTRY_ID peid, ULONG EntryType) { DFS_PKT_RELATION_INFO RelationInfo; NET_DFS_ENTRY_ID_CONTAINER NetRelationInfo; DWORD dwErr = ERROR_SUCCESS; NTSTATUS status;
//
// First to check whether this is necessary since this could be a down
// level scenario.
//
if (_DfsReplicaInfo.ulReplicaType == DFS_STORAGE_TYPE_NONDFS) {
return(ERROR_SUCCESS);
}
//
// Now we need to create a config info structure. We will have to go to
// the PKT for this since this is not available in the Private section
// above.
//
dwErr = GetPktCacheRelationInfo(peid, &RelationInfo);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR,"Failed to do GetPktCacheRelationInfo on %ws %08lx\n", peid->Prefix.Buffer, dwErr));
return( dwErr );
}
//
// Convert the ConfigInfo into an LPNET_DFS_ENTRY_ID_CONTAINER suitable
// for calling I_NetDfsCreateLocalPartition.
//
dwErr = RelationInfoToNetInfo( &RelationInfo, &NetRelationInfo );
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR, "Failed to allocate memory for NET_ENTRY_ID_CONTAINER"));
return( dwErr );
}
BOOL fRetry;
fRetry = FALSE;
//
// Note that I_NetDfsCreateLocalPartition returns an NT_STATUS cast to a
// NET_API_STATUS
//
do {
status = I_NetDfsCreateLocalPartition( _DfsReplicaInfo.pwszServerName, _DfsReplicaInfo.pwszShareName, &peid->Uid, peid->Prefix.Buffer, peid->ShortPrefix.Buffer, &NetRelationInfo, FALSE);
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, CDfsServiceCreateLocalVolume_I_NetDfsCreateLocalPartition, LOGSTATUS(status)); //
// If this operation fails, it could reflect a knowledge inconsistency at
// the server. So, handle it now.
//
IDfsVolInlineDebOut(( DEB_TRACE, "I_NetDfsCreateLocalPartition returned %08lx\n", status));
if (fRetry) {
//
// We have already tried once to sync up the server. Time to quit
//
fRetry = FALSE;
} else if (status == DFS_STATUS_LOCAL_ENTRY) {
//
// The server thinks that the volume we are trying to create
// already exists. This is bogus, so lets try to bring the server
// up to sync with us.
//
fRetry = SyncKnowledge();
}
} while ( fRetry );
if (!NT_SUCCESS(status)) { dwErr = RtlNtStatusToDosError(status); }
DeallocateCacheRelationInfo(RelationInfo);
delete [] NetRelationInfo.Buffer;
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_TRACE, "Failed to CreateLocalVol at %ws for %ws. Error: %x\n", _DfsReplicaInfo.pwszServerName, peid->Prefix.Buffer, dwErr)); }
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Method: CDfsService::DeleteLocalVolume()
//
// Synopsis: This method deletes knowledge regarding a volume at remote
// machine.
//
// Arguments: [peid] -- EntryId information.
//
// Returns: [ERROR_SUCCESS] -- If successfully deleted the knowledge at the remote
// server, or the server didn't know about the volume
// to begin with.
//
// History: 01 Feb 93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::DeleteLocalVolume( PDFS_PKT_ENTRY_ID peid) { NTSTATUS status; DWORD dwErr = ERROR_SUCCESS; BOOL fRetry;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::DeleteLocalVolume()\n"));
//
// First to check whether this is necessary since this could be a down
// level scenario.
//
if (_DfsReplicaInfo.ulReplicaType == DFS_STORAGE_TYPE_NONDFS) { return(ERROR_SUCCESS); }
fRetry = FALSE;
//
// Note that I_NetDfsCreateLocalPartition returns an NT_STATUS cast to a
// NET_API_STATUS
//
do {
status = I_NetDfsDeleteLocalPartition( _DfsReplicaInfo.pwszServerName, &peid->Uid, peid->Prefix.Buffer);
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, CDfsServiceDeleteLocalVolume_Error_I_NetDfsDeleteLocalPartition, LOGSTATUS(status)); IDfsVolInlineDebOut(( DEB_TRACE, "NT Status %08lx from DfsDeleteLocalPartition\n", status));
if (fRetry) {
//
// We have already tried once to sync up the server. Time to quit
//
fRetry = FALSE;
} else if (status == DFS_STATUS_NOSUCH_LOCAL_VOLUME) {
//
// This could happen because the server's knowledge is
// inconsistent with that of this DC. Try to bring it in sync.
//
fRetry = SyncKnowledge();
}
} while ( fRetry );
if (!NT_SUCCESS(status)) { IDfsVolInlineDebOut(( DEB_TRACE, "Failed to Delete Local Volume at %ws for %ws Error: %x\n", _DfsReplicaInfo.pwszServerName, peid->Prefix.Buffer, status)); }
if (status == DFS_STATUS_NOSUCH_LOCAL_VOLUME) dwErr = ERROR_SUCCESS; else if (!NT_SUCCESS(status)) dwErr = RtlNtStatusToDosError(status); else dwErr = ERROR_SUCCESS;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::DeleteLocalVolume() exit\n"));
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: CDfsService::SetVolumeState
//
// Synopsis: This method sets the Online/Offline state of the volume at
// the remote machine.
//
// Arguments: [peid] -- The entry id of the volume.
//
// [fState] -- The state to set it at.
//
// [fRemoteOpMustSucceed] -- If TRUE, then the whole operation
// fails if the remote server cannot be forced offline.
// If FALSE, then the operation succeeds as long as the
// local DC's PKT is updated.
//
// Returns: ERROR_SUCCESS -- The state of the volume was set as specified.
//
// Converted NTSTATUS from call to remote dfs.
//
//-----------------------------------------------------------------------------
DWORD CDfsService::SetVolumeState( const PDFS_PKT_ENTRY_ID peid, const ULONG fState, const BOOL fRemoteOpMustSucceed) { NTSTATUS Status; DWORD dwErr = ERROR_SUCCESS; SYSTEMTIME st;
//
// We first inform the DC's Dfs driver to set the replica state.
//
Status = DfsSetServiceState( peid, GetServiceName(), fState );
//
// Save the changed state
//
if (NT_SUCCESS(Status)) {
GetSystemTime( &st ); SystemTimeToFileTime( &st, &_ftModification );
if (fState == DFS_SERVICE_TYPE_OFFLINE) {
_DfsReplicaInfo.ulReplicaState = DFS_STORAGE_STATE_OFFLINE;
} else {
_DfsReplicaInfo.ulReplicaState = DFS_STORAGE_STATE_ONLINE;
}
}
//
// Only in the case that this succeeded and the service in question is
// a dfs aware replica do we tell the server to take the volume offline
//
if (NT_SUCCESS(Status)) {
if (_DfsReplicaInfo.ulReplicaType == DFS_STORAGE_TYPE_DFS) {
Status = I_NetDfsSetLocalVolumeState( _DfsReplicaInfo.pwszServerName, &peid->Uid, peid->Prefix.Buffer, fState);
DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, CDfsServiceSetVolumeState_Error_I_NetDfsSetLocalVolumeState, LOGSTATUS(Status));
if (!fRemoteOpMustSucceed) {
Status = STATUS_SUCCESS;
}
if (!NT_SUCCESS(Status)) {
//
// Try to undo the DC's PKT change
//
NTSTATUS statusRecover;
statusRecover = DfsSetServiceState( peid, GetServiceName(), (_DfsReplicaInfo.ulReplicaState == DFS_STORAGE_STATE_OFFLINE) ? DFS_STORAGE_STATE_ONLINE : 0);
dwErr = RtlNtStatusToDosError(Status);
}
} else {
//
// Replica is not dfs-aware
//
NOTHING;
}
} else {
dwErr = RtlNtStatusToDosError(Status);
}
return( dwErr ); }
//+------------------------------------------------------------------------
//
// Method: CDfsService::FixLocalVolume()
//
// Synopsis: This method creates knowledge regarding a new volume at remote
// machine. This method merely packages the info from private
// section of the class into a buffer and makes an FSCTRL to the
// remote service. The rest happens at the remote service. This
// method does not affect the local PKT at all. It updates the
// remote service's PKT and the DFS.CFG file on disk and updates
// the registry at the other end.This is a kind of FORCE operation.
// At the remote server every attempt will be made to create this
// local volume knowledge.
//
// Arguments: [peid] -- The EntryId. This class does not know this.
// [EntryType] -- Type of Entry. This class doesn't know this.
//
// Returns: [ERROR_SUCCESS] -- If operation successfully completed.
//
// History: 18-June-93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::FixLocalVolume( PDFS_PKT_ENTRY_ID peid, ULONG EntryType) { DFS_PKT_RELATION_INFO RelationInfo; NET_DFS_ENTRY_ID_CONTAINER NetRelationInfo; DWORD dwErr = ERROR_SUCCESS; NTSTATUS status;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::FixLocalVolume()\n"));
//
// First to check whether this is necessary since this could be a down
// level scenario.
//
if (_DfsReplicaInfo.ulReplicaType == DFS_STORAGE_TYPE_NONDFS) { return(ERROR_SUCCESS); }
//
// Now we need to create a relation info structure. We will have to go to
// the PKT for this since this is not available in the private section
//
dwErr = GetPktCacheRelationInfo(peid, &RelationInfo);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR, "Failed to do GetPktCacheRelationInfo on %ws %08lx\n", peid->Prefix.Buffer, dwErr));
return( dwErr ); }
//
// Now that we have the relationInfo. We know how to construct ConfigInfo.
//
RelationInfoToNetInfo( &RelationInfo, &NetRelationInfo );
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR, "Failed to allocate memory for NET_ENTRY_ID_CONTAINER"));
return( dwErr );
}
//
// Now we are all setup to make the FSCTRL.
//
status = I_NetDfsFixLocalVolume( _DfsReplicaInfo.pwszServerName, _DfsReplicaInfo.pwszShareName, EntryType, _DfsPktService.Type, NULL, &peid->Uid, peid->Prefix.Buffer, &NetRelationInfo, PKT_ENTRY_SUPERSEDE);
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, CDfsServiceFixLocalVolume_Error_I_NetDfsFixLocalVolume, LOGSTATUS(status));
if (!NT_SUCCESS(status)) dwErr = RtlNtStatusToDosError(status);
DeallocateCacheRelationInfo(RelationInfo);
delete [] NetRelationInfo.Buffer;
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_TRACE, "Failed to FixLocalVolume at %ws for %ws. Error: %x\n", _DfsReplicaInfo.pwszServerName, peid->Prefix.Buffer, dwErr)); }
IDfsVolInlineDebOut((DEB_TRACE, "CDfsService::FixLocalVolume() exit\n"));
return( dwErr );
}
//+------------------------------------------------------------------------
//
// Method: CDfsService::ModifyPrefix()
//
// Synopsis: This method takes the PKT_ENTRY_ID that it gets and advises
// the remote server of the new prefix for the volume ID.
//
// Arguments: [peid] -- NewEntry ID for this service.
//
// Returns: [ERROR_SUCCESS] -- If operation completed successfully.
//
// History: 31 April 93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsService::ModifyPrefix( PDFS_PKT_ENTRY_ID peid) { DWORD dwErr = ERROR_SUCCESS; NTSTATUS status; BOOL fRetry;
//
// First to check whether this is necessary since this could be a down
// level scenario.
//
if (_DfsReplicaInfo.ulReplicaType == DFS_STORAGE_TYPE_NONDFS) { return(ERROR_SUCCESS); }
fRetry = FALSE;
do {
status = I_NetDfsModifyPrefix( _DfsReplicaInfo.pwszServerName, &peid->Uid, peid->Prefix.Buffer);
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, CDfsServiceModifyPrefix_Error_I_NetDfsModifyPrefix, LOGSTATUS(status));
if (fRetry) {
//
// We have already tried once to sync up the server. Time to quit
//
fRetry = FALSE;
} else if (status == DFS_STATUS_NOSUCH_LOCAL_VOLUME || status == DFS_STATUS_BAD_EXIT_POINT) {
//
// The server seems to be out of sync with this DC. Try to
// force it to sync up
//
fRetry = SyncKnowledge();
}
} while ( fRetry );
if (!NT_SUCCESS(status)) dwErr = RtlNtStatusToDosError(status);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_TRACE, "Failed to do ModifyPrefix at [%ws] to [%ws]. Error: %x\n", _DfsReplicaInfo.pwszServerName, peid->Prefix.Buffer, dwErr)); }
return( dwErr );
}
//+----------------------------------------------------------------------------
//
// Function: CDfsService::SyncKnowledge()
//
// Synopsis: Tries to force the server's knowledge to correspond with that
// on this DC.
//
// Arguments: None.
//
// Returns: TRUE if the server had to change any knowledge and was able
// to do so. FALSE if either nothing changed or the server was
// unable to comply.
//
//-----------------------------------------------------------------------------
BOOL CDfsService::SyncKnowledge() { NTSTATUS Status = STATUS_SUCCESS; DFS_PKT_ENTRY_ID EntryId;
EntryId.Uid = _DfsPktService.pMachEntry->pMachine->guidMachine;
RtlInitUnicodeString( &EntryId.Prefix, _DfsReplicaInfo.pwszServerName );
// Status = DfsSetServerInfo( &EntryId, NULL );
if (!NT_SUCCESS(Status)) {
LogMessage( DEB_ERROR, &EntryId.Prefix.Buffer, 1, DFS_CANT_SYNC_SERVER_MSG );
} return( (BOOL) (Status == STATUS_REGISTRY_RECOVERED) );
}
//+----------------------------------------------------------------------------
//
// Function: CDfsService::VerifyStgIdInUse
//
// Synopsis: Given a storage id, verifies using knowledge on the DC whether
// that storage id or some parent/child thereof is already shared.
// This routine simply fsctls to the driver, which does the
// verification.
//
// Arguments: [pustrStgId] -- The storage id to check.
//
// Returns: TRUE if this storage id or some parent/child thereof is already
// shared, FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL CDfsService::VerifyStgIdInUse( PUNICODE_STRING pustrStgId) {
NTSTATUS Status = STATUS_SUCCESS; DFS_PKT_ENTRY_ID EntryId; BOOL fStgIdInUse;
//
// Marshal the machine's Guid and the storage id into a DFS_PKT_ENTRY_ID
// structure, and fsctl to the driver to verify the storage id.
//
memcpy( (PVOID) &EntryId.Uid, (PVOID) &_DfsPktService.pMachEntry->pMachine->guidMachine, sizeof(GUID) );
EntryId.Prefix = *pustrStgId;
// Status = DfsCheckStgIdInUse( &EntryId );
fStgIdInUse = (Status == STATUS_DEVICE_BUSY);
if (Status != STATUS_DEVICE_BUSY && Status != STATUS_SUCCESS) {
LogMessage( DEB_TRACE, &pustrStgId->Buffer, 1, DFS_CANT_VERIFY_SERVER_KNOWLEDGE_MSG );
}
return( fStgIdInUse );
}
//+----------------------------------------------------------------------------
//
// Function: CDfsService::SetCreateTime, public
//
// Synopsis: Initializes the Modification Time of this service to the
// current time.
//
// Arguments: None
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID CDfsService::SetCreateTime() { SYSTEMTIME st; FILETIME ft;
GetSystemTime( &st ); SystemTimeToFileTime( &st, &_ftModification );
}
//+----------------------------------------------------------------------------
//
// Function: RelationInfoToNetInfo, private
//
// Synopsis: Converts a DFS_PKT_RELATION_INFO struct into a
// NET_DFS_ENTRY_ID_CONTAINER struct for use with I_NetDfs calls.
//
// Arguments: [RelationInfo] -- Reference to source DFS_PKT_RELATION_INFO
//
// [pNetInfo] -- On successful return, contains a valid
// NET_DFS_ENTRY_ID_CONTAINER. pNetInfo->Buffer is
// allocated using new - caller responsible for freeing
// it using delete.
//
// Returns: [ERROR_SUCCESS] -- Successfully created *ppNetInfo.
//
// [ERROR_OUTOFMEMORY] -- Unable to allocate room for the info.
//
//-----------------------------------------------------------------------------
DWORD RelationInfoToNetInfo( PDFS_PKT_RELATION_INFO RelationInfo, LPNET_DFS_ENTRY_ID_CONTAINER pNetInfo) { DWORD dwErr; ULONG i;
//
// The +1 is so we don't try to do a 0 length allocation. This simplifies
// cleanup in the caller's code.
//
pNetInfo->Buffer = new NET_DFS_ENTRY_ID [RelationInfo->SubordinateIdCount + 1];
if (pNetInfo->Buffer != NULL) {
pNetInfo->Count = RelationInfo->SubordinateIdCount;
for (i = 0; i < pNetInfo->Count; i++) {
pNetInfo->Buffer[i].Uid = RelationInfo->SubordinateIdList[i].Uid; pNetInfo->Buffer[i].Prefix = RelationInfo->SubordinateIdList[i].Prefix.Buffer;
}
dwErr = ERROR_SUCCESS;
} else {
pNetInfo->Count = 0;
dwErr = ERROR_OUTOFMEMORY;
}
return( dwErr ); }
|