1629 lines
45 KiB
C++
1629 lines
45 KiB
C++
//+----------------------------------------------------------------------------//+-------------------------------------------------------------------------
|
||
//
|
||
// 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 );
|
||
}
|