You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1040 lines
27 KiB
1040 lines
27 KiB
/*++
|
|
Module Name:
|
|
|
|
DfsJP.cpp
|
|
|
|
Abstract:
|
|
|
|
This COM Class provides method to get information of Dfs
|
|
Junction Points and to enumerate replica of a junction point.
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "DfsCore.h"
|
|
#include "DfsJP.h"
|
|
#include "DfsRep.h"
|
|
#include "JPEnum.h"
|
|
#include "RepEnum.h"
|
|
#include "netutils.h"
|
|
#include "ldaputils.h"
|
|
#include <dsgetdc.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// CDfsJuntionPoint
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
CDfsJunctionPoint :: CDfsJunctionPoint ()
|
|
{
|
|
dfsDebugOut((_T("CDfsJunctionPoint::CDfsJunctionPoint this=%p\n"), this));
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
CDfsJunctionPoint :: ~CDfsJunctionPoint ()
|
|
{
|
|
_FreeMemberVariables();
|
|
dfsDebugOut((_T("CDfsJunctionPoint::~CDfsJunctionPoint this=%p\n"), this));
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_State
|
|
(
|
|
long* pVal
|
|
)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_EntryPath
|
|
(
|
|
BSTR* pVal
|
|
)
|
|
{
|
|
if (!pVal)
|
|
return E_INVALIDARG;
|
|
|
|
*pVal = m_bstrEntryPath.Copy ();
|
|
if (!*pVal)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_JunctionName
|
|
(
|
|
BOOL i_bDfsNameIncluded,
|
|
BSTR* pVal
|
|
)
|
|
{
|
|
if (!pVal)
|
|
return E_INVALIDARG;
|
|
|
|
if (i_bDfsNameIncluded)
|
|
*pVal = m_bstrJunctionNameEx.Copy ();
|
|
else
|
|
*pVal = m_bstrJunctionName.Copy ();
|
|
|
|
if (!*pVal)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_Comment
|
|
(
|
|
BSTR* pVal
|
|
)
|
|
{
|
|
if (!pVal)
|
|
return E_INVALIDARG;
|
|
|
|
DFS_INFO_100* pInfoBuffer = NULL;
|
|
NET_API_STATUS nRet = NetDfsGetInfo(
|
|
m_bstrEntryPath,
|
|
NULL,
|
|
NULL,
|
|
100,
|
|
(LPBYTE*)&pInfoBuffer
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsGetInfo entry=%s, level 100 for comment, nRet=%d\n"),
|
|
m_bstrEntryPath, nRet));
|
|
|
|
if (NERR_Success == nRet)
|
|
{
|
|
*pVal = SysAllocString(pInfoBuffer->Comment);
|
|
|
|
NetApiBufferFree(pInfoBuffer);
|
|
|
|
if (!*pVal)
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(nRet);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: put_Comment
|
|
(
|
|
BSTR newVal
|
|
)
|
|
{
|
|
DFS_INFO_100 InfoBuffer = {(newVal ? newVal : _T(""))};
|
|
NET_API_STATUS nRet = NetDfsSetInfo (
|
|
m_bstrEntryPath,
|
|
NULL,
|
|
NULL,
|
|
100,
|
|
(LPBYTE) &InfoBuffer
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsSetInfo entry=%s, level 100 for comment, nRet=%d\n"),
|
|
m_bstrEntryPath, nRet));
|
|
|
|
return HRESULT_FROM_WIN32(nRet);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// get_Timeout
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_Timeout
|
|
(
|
|
long* pVal
|
|
)
|
|
{
|
|
if (!pVal || !m_bstrEntryPath)
|
|
return E_INVALIDARG;
|
|
|
|
DFS_INFO_4* pInfoBuffer = NULL;
|
|
NET_API_STATUS nRet = NetDfsGetInfo(
|
|
m_bstrEntryPath,
|
|
NULL,
|
|
NULL,
|
|
4,
|
|
(LPBYTE*)&pInfoBuffer
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsGetInfo entry=%s, level 4 for Timeout, nRet=%d\n"),
|
|
m_bstrEntryPath, nRet));
|
|
|
|
if (NERR_Success == nRet)
|
|
{
|
|
*pVal = pInfoBuffer->Timeout;
|
|
|
|
NetApiBufferFree(pInfoBuffer);
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(nRet);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// put_Timeout
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: put_Timeout
|
|
(
|
|
long newVal
|
|
)
|
|
{
|
|
if (!m_bstrEntryPath)
|
|
return E_INVALIDARG;
|
|
|
|
DFS_INFO_102 DfsInfoLevel102 = {newVal};
|
|
NET_API_STATUS nRet = NetDfsSetInfo (
|
|
m_bstrEntryPath,
|
|
NULL,
|
|
NULL,
|
|
102,
|
|
(LPBYTE) &DfsInfoLevel102
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsSetInfo entry=%s, level 102 for Timeout, nRet=%d\n"),
|
|
m_bstrEntryPath, nRet));
|
|
|
|
return HRESULT_FROM_WIN32(nRet);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_ReplicaSetDN
|
|
(
|
|
BSTR* pVal
|
|
)
|
|
{
|
|
if (!pVal)
|
|
return E_INVALIDARG;
|
|
|
|
if (!m_bstrEntryPath)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
if (!m_bstrReplicaSetDN)
|
|
{
|
|
hr = _GetReplicaSetDN(m_bstrEntryPath);
|
|
RETURN_IF_FAILED(hr);
|
|
}
|
|
|
|
*pVal = m_bstrReplicaSetDN.Copy ();
|
|
if (!*pVal)
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_ReplicaSetExist
|
|
(
|
|
BOOL* pVal
|
|
)
|
|
{
|
|
if (!pVal)
|
|
return E_INVALIDARG;
|
|
|
|
if (!m_bstrEntryPath)
|
|
return E_INVALIDARG;
|
|
|
|
*pVal = m_bReplicaSetExist;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_ReplicaSetExistEx
|
|
(
|
|
BSTR* o_pbstrDC,
|
|
BOOL* pVal
|
|
)
|
|
{
|
|
if (!pVal || !o_pbstrDC)
|
|
return E_INVALIDARG;
|
|
|
|
if (!m_bstrEntryPath)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
if (!m_bstrReplicaSetDN)
|
|
{
|
|
hr = _GetReplicaSetDN(m_bstrEntryPath);
|
|
RETURN_IF_FAILED(hr);
|
|
}
|
|
|
|
DFS_TYPE dwDfsType = DFS_TYPE_UNASSIGNED;
|
|
CComBSTR bstrDomainName;
|
|
CComBSTR bstrDomainDN;
|
|
hr = _GetDfsType(&dwDfsType, &bstrDomainName, &bstrDomainDN);
|
|
RETURN_IF_FAILED(hr);
|
|
|
|
m_bReplicaSetExist = FALSE;
|
|
if (dwDfsType == DFS_TYPE_FTDFS)
|
|
{
|
|
CComBSTR bstrDN = m_bstrReplicaSetDN;
|
|
if ((BSTR)bstrDN) bstrDN += _T(",");
|
|
if ((BSTR)bstrDN) bstrDN += bstrDomainDN;
|
|
RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrDN);
|
|
|
|
PLDAP pldap = NULL;
|
|
CComBSTR bstrDC;
|
|
hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_bReplicaSetExist = (S_OK == IsValidObject(pldap, bstrDN));
|
|
|
|
CloseConnectionToDS(pldap);
|
|
|
|
*o_pbstrDC = bstrDC.Copy();
|
|
if (!*o_pbstrDC)
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
}
|
|
|
|
*pVal = m_bReplicaSetExist;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CDfsJunctionPoint :: _GetDfsType(
|
|
OUT DFS_TYPE* o_pdwDfsType,
|
|
OUT BSTR* o_pbstrDomainName,
|
|
OUT BSTR* o_pbstrDomainDN
|
|
)
|
|
{
|
|
if (!o_pdwDfsType)
|
|
return E_INVALIDARG;
|
|
|
|
if (!m_spiDfsRoot)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
m_spiDfsRoot->get_DfsType((long *)o_pdwDfsType);
|
|
if (*o_pdwDfsType == DFS_TYPE_FTDFS)
|
|
{
|
|
if (o_pbstrDomainName)
|
|
hr = m_spiDfsRoot->get_DomainName(o_pbstrDomainName);
|
|
|
|
if (SUCCEEDED(hr) && o_pbstrDomainDN)
|
|
hr = m_spiDfsRoot->get_DomainDN(o_pbstrDomainDN);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: put_ReplicaSetExist
|
|
(
|
|
BOOL newVal
|
|
)
|
|
{
|
|
if (!m_bstrEntryPath)
|
|
return E_INVALIDARG;
|
|
|
|
m_bReplicaSetExist = newVal;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
HRESULT CDfsJunctionPoint::_Init(
|
|
PDFS_INFO_3 pDfsInfo,
|
|
BOOL bReplicaSetExist,
|
|
BSTR bstrReplicaSetDN
|
|
)
|
|
{
|
|
_FreeMemberVariables();
|
|
|
|
if (bReplicaSetExist && (!bstrReplicaSetDN || !*bstrReplicaSetDN))
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do {
|
|
m_bstrEntryPath = pDfsInfo->EntryPath;
|
|
BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrEntryPath, &hr);
|
|
|
|
hr = GetUNCPathComponent(m_bstrEntryPath, &m_bstrJunctionName, 4, 0);
|
|
BREAK_IF_FAILED(hr);
|
|
|
|
hr = GetUNCPathComponent(m_bstrEntryPath, &m_bstrJunctionNameEx, 3, 0);
|
|
BREAK_IF_FAILED(hr);
|
|
|
|
PDFS_STORAGE_INFO pStorage = pDfsInfo->Storage;
|
|
|
|
for (DWORD i = 0; i < pDfsInfo->NumberOfStorages && pStorage; i++, pStorage++)
|
|
{
|
|
hr = _AddToReplicaList(pStorage->ServerName, pStorage->ShareName, pStorage->State);
|
|
BREAK_IF_FAILED(hr);
|
|
}
|
|
|
|
m_bReplicaSetExist = bReplicaSetExist;
|
|
|
|
if (m_bReplicaSetExist)
|
|
{
|
|
m_bstrReplicaSetDN = bstrReplicaSetDN;
|
|
BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrReplicaSetDN, &hr);
|
|
}
|
|
} while (0);
|
|
|
|
if (FAILED(hr))
|
|
_FreeMemberVariables();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: Initialize
|
|
(
|
|
IUnknown *i_piDfsRoot,
|
|
BSTR i_szEntryPath,
|
|
BOOL i_bReplicaSetExist,
|
|
BSTR i_bstrReplicaSetDN
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This initializes the junction point. Before this method is called the
|
|
data stored by DfsJunctionPoint is NULL. If initialization fails the
|
|
properties will be NULL.
|
|
|
|
Arguments:
|
|
|
|
i_szEntryPath - The the Entry Path to the Junction Point.
|
|
--*/
|
|
|
|
RETURN_INVALIDARG_IF_NULL(i_piDfsRoot);
|
|
RETURN_INVALIDARG_IF_NULL(i_szEntryPath);
|
|
|
|
if ((IDfsRoot *)m_spiDfsRoot)
|
|
m_spiDfsRoot.Release();
|
|
i_piDfsRoot->QueryInterface(IID_IDfsRoot, (void **)&m_spiDfsRoot);
|
|
|
|
PDFS_INFO_3 pDfsInfo = NULL;
|
|
NET_API_STATUS nRet = NetDfsGetInfo(
|
|
i_szEntryPath,
|
|
NULL,
|
|
NULL,
|
|
3,
|
|
(LPBYTE*) &pDfsInfo
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsGetInfo entry=%s, level 3 for Link Initialization, nRet=%d\n"),
|
|
i_szEntryPath, nRet));
|
|
|
|
if (NERR_Success != nRet)
|
|
{
|
|
if (NERR_DfsNoSuchVolume == nRet)
|
|
return S_FALSE; // no such link
|
|
else
|
|
return HRESULT_FROM_WIN32(nRet);
|
|
}
|
|
|
|
HRESULT hr = _Init(pDfsInfo, i_bReplicaSetExist, i_bstrReplicaSetDN);
|
|
|
|
NetApiBufferFree(pDfsInfo);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Note: not all fields of pDfsInfo is filled in, e.g., comment/timeout are not filled in
|
|
HRESULT VariantToDfsInfoLevel3(VARIANT *pVar, OUT PDFS_INFO_3 *ppDfsInfo)
|
|
{
|
|
*ppDfsInfo = NULL;
|
|
|
|
if (V_VT(pVar) != (VT_ARRAY | VT_VARIANT))
|
|
return E_INVALIDARG;
|
|
|
|
SAFEARRAY *psa_2 = V_ARRAY(pVar);
|
|
long lLowerBound = 0;
|
|
long lUpperBound = 0;
|
|
long lCount = 0;
|
|
|
|
if (!psa_2)
|
|
return E_INVALIDARG;
|
|
|
|
SafeArrayGetLBound(psa_2, 1, &lLowerBound );
|
|
SafeArrayGetUBound(psa_2, 1, &lUpperBound );
|
|
lCount = lUpperBound - lLowerBound + 1;
|
|
if (lCount != ARRAY_COUNT_FOR_DFS_INFO_3)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
VARIANT HUGEP *pArray_2;
|
|
SafeArrayAccessData(psa_2, (void HUGEP **) &pArray_2);
|
|
do {
|
|
if (V_VT(&(pArray_2[0])) != VT_BSTR ||
|
|
V_VT(&(pArray_2[1])) != (VT_ARRAY | VT_VARIANT))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
SAFEARRAY *psa_1 = V_ARRAY(&(pArray_2[1]));
|
|
if (!psa_1)
|
|
{
|
|
lCount = 0; // empty root/link container
|
|
} else
|
|
{
|
|
SafeArrayGetLBound(psa_1, 1, &lLowerBound );
|
|
SafeArrayGetUBound(psa_1, 1, &lUpperBound );
|
|
lCount = lUpperBound - lLowerBound + 1;
|
|
}
|
|
|
|
*ppDfsInfo = (PDFS_INFO_3)calloc(
|
|
sizeof(DFS_INFO_3) + lCount * sizeof(DFS_STORAGE_INFO),
|
|
1);
|
|
BREAK_OUTOFMEMORY_IF_NULL(*ppDfsInfo, &hr);
|
|
|
|
LPDFS_STORAGE_INFO pStorage = (LPDFS_STORAGE_INFO)((BYTE*)*ppDfsInfo + sizeof(DFS_INFO_3));
|
|
|
|
(*ppDfsInfo)->EntryPath = pArray_2[0].bstrVal;
|
|
(*ppDfsInfo)->NumberOfStorages = lCount;
|
|
(*ppDfsInfo)->Storage = pStorage;
|
|
|
|
VARIANT HUGEP *pArray_1;
|
|
SafeArrayAccessData(psa_1, (void HUGEP **)&pArray_1);
|
|
for (long i = 0; i < lCount; i++, pStorage++)
|
|
{
|
|
if (V_VT(&(pArray_1[i])) != (VT_ARRAY | VT_VARIANT))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
SAFEARRAY *psa_0 = V_ARRAY(&(pArray_1[i]));
|
|
SafeArrayGetLBound(psa_0, 1, &lLowerBound );
|
|
SafeArrayGetUBound(psa_0, 1, &lUpperBound );
|
|
if (ARRAY_COUNT_FOR_DFS_STORAGE_INFO != (lUpperBound - lLowerBound + 1))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
VARIANT HUGEP *pArray_0;
|
|
SafeArrayAccessData(psa_0, (void HUGEP **)&pArray_0);
|
|
if (V_VT(&(pArray_0[0])) != VT_BSTR ||
|
|
V_VT(&(pArray_0[1])) != VT_BSTR ||
|
|
V_VT(&(pArray_0[2])) != VT_I4)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
} else
|
|
{
|
|
pStorage->ServerName = pArray_0[0].bstrVal;
|
|
pStorage->ShareName = pArray_0[1].bstrVal;
|
|
pStorage->State = pArray_0[2].lVal;
|
|
}
|
|
SafeArrayUnaccessData(psa_0);
|
|
}
|
|
SafeArrayUnaccessData(psa_1);
|
|
|
|
} while (0);
|
|
|
|
SafeArrayUnaccessData(psa_2);
|
|
|
|
if (FAILED(hr) && *ppDfsInfo)
|
|
free((void *)*ppDfsInfo);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: InitializeEx
|
|
(
|
|
IUnknown *piDfsRoot,
|
|
VARIANT *pVar,
|
|
BOOL bReplicaSetExist,
|
|
BSTR bstrReplicaSetDN
|
|
)
|
|
{
|
|
RETURN_INVALIDARG_IF_NULL(piDfsRoot);
|
|
RETURN_INVALIDARG_IF_NULL(pVar);
|
|
|
|
if ((IDfsRoot *)m_spiDfsRoot)
|
|
m_spiDfsRoot.Release();
|
|
piDfsRoot->QueryInterface(IID_IDfsRoot, (void **)&m_spiDfsRoot);
|
|
|
|
PDFS_INFO_3 pDfsInfo = NULL;
|
|
HRESULT hr = VariantToDfsInfoLevel3(pVar, &pDfsInfo);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _Init(pDfsInfo, bReplicaSetExist, bstrReplicaSetDN);
|
|
|
|
free((void *)pDfsInfo);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get_CountOfDfsReplicas
|
|
(
|
|
long* pVal
|
|
)
|
|
{
|
|
if (!pVal)
|
|
return(E_INVALIDARG);
|
|
|
|
*pVal = m_Replicas.size();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void CDfsJunctionPoint :: _FreeMemberVariables
|
|
(
|
|
)
|
|
{
|
|
m_bstrEntryPath.Empty();
|
|
m_bstrJunctionName.Empty();
|
|
m_bstrJunctionNameEx.Empty();
|
|
m_bstrReplicaSetDN.Empty();
|
|
|
|
m_bReplicaSetExist = FALSE;
|
|
|
|
FreeReplicas(&m_Replicas);
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
HRESULT CDfsJunctionPoint :: _GetReplicaSetDN
|
|
(
|
|
BSTR i_szEntryPath
|
|
)
|
|
{
|
|
// as an example, given an entry path \\dom\public\dir1\dir2
|
|
|
|
// set m_bstrReplicaSetDN to be:
|
|
// "CN=public|dir1|dir2,CN=public,CN=DFS Volumes,
|
|
// CN=File Replication Service,CN=System"
|
|
|
|
CComBSTR bstrDfsName; // e.g., "public"
|
|
HRESULT hr = GetUNCPathComponent(i_szEntryPath, &bstrDfsName, 3, 4);
|
|
RETURN_IF_FAILED(hr);
|
|
|
|
CComBSTR bstrDfsRootDN = _T("CN=");
|
|
RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrDfsRootDN);
|
|
bstrDfsRootDN += bstrDfsName;
|
|
RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrDfsRootDN);
|
|
bstrDfsRootDN += CN_DFSVOLUMES_PREFIX;
|
|
RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrDfsRootDN);
|
|
|
|
hr = ExtendDNIfLongJunctionName(m_bstrJunctionNameEx, bstrDfsRootDN, &m_bstrReplicaSetDN);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: get__NewEnum
|
|
(
|
|
LPUNKNOWN* pVal
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This property gets a new replica enumerator pointer.
|
|
|
|
Arguments:
|
|
|
|
pVal - Pointer in which the pointer to IEnumVARIANT pointer will be returned.
|
|
|
|
--*/
|
|
|
|
if (!pVal)
|
|
return E_INVALIDARG;
|
|
|
|
*pVal = NULL;
|
|
|
|
// Create a new ReplicaEnum object which implements IEnumVARIANT
|
|
// and return the pointer to IEnumVARIANT.
|
|
CComObject<CReplicaEnum> *pReplicaEnum = new CComObject<CReplicaEnum>();
|
|
if (!pReplicaEnum)
|
|
return E_OUTOFMEMORY;
|
|
|
|
// Initialize the enumerator with the list of replicas and the entrypath.
|
|
HRESULT hr = pReplicaEnum->Initialize(&m_Replicas, m_bstrEntryPath);
|
|
|
|
// Get the enumerator pointer.
|
|
if (SUCCEEDED(hr))
|
|
hr = pReplicaEnum->QueryInterface(IID_IEnumVARIANT, (void **)pVal);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete pReplicaEnum;
|
|
return hr;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// AddReplica
|
|
|
|
HRESULT CDfsJunctionPoint::_AddToReplicaList(BSTR bstrServerName, BSTR bstrShareName, long lDfsStorageState)
|
|
{
|
|
REPLICAINFO* pDfsReplica = new REPLICAINFO;
|
|
RETURN_OUTOFMEMORY_IF_NULL(pDfsReplica);
|
|
|
|
HRESULT hr = pDfsReplica->Init(bstrServerName, bstrShareName, lDfsStorageState);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pDfsReplica;
|
|
return hr;
|
|
}
|
|
|
|
m_Replicas.push_back(pDfsReplica);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CDfsJunctionPoint::_DeleteFromReplicaList(BSTR bstrServerName, BSTR bstrShareName)
|
|
{
|
|
for (REPLICAINFOLIST::iterator i = m_Replicas.begin(); i != m_Replicas.end(); i++)
|
|
{
|
|
if (0 == lstrcmpi(bstrServerName, (*i)->m_bstrServerName) &&
|
|
0 == lstrcmpi(bstrShareName, (*i)->m_bstrShareName))
|
|
{
|
|
delete (*i);
|
|
m_Replicas.erase(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CDfsJunctionPoint::_GetDfsStorageState
|
|
(
|
|
BSTR i_szServerName,
|
|
BSTR i_szShareName,
|
|
long* o_pVal
|
|
)
|
|
{
|
|
if (!i_szServerName || !i_szShareName || !o_pVal)
|
|
return E_INVALIDARG;
|
|
|
|
*o_pVal = DFS_STORAGE_STATE_OFFLINE;
|
|
|
|
PDFS_INFO_3 pDfsInfo = NULL;
|
|
NET_API_STATUS nstatRetVal = NetDfsGetInfo (
|
|
m_bstrEntryPath,
|
|
i_szServerName,
|
|
i_szShareName,
|
|
3,
|
|
(LPBYTE*)&pDfsInfo
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsGetInfo entry=%s, server=%s, share=%s, level 3 for State, nRet=%d\n"),
|
|
m_bstrEntryPath, i_szServerName, i_szShareName, nstatRetVal));
|
|
|
|
if (nstatRetVal != NERR_Success)
|
|
{
|
|
if (nstatRetVal == NERR_DfsNoSuchVolume)
|
|
return S_FALSE;
|
|
else
|
|
return HRESULT_FROM_WIN32 (nstatRetVal);
|
|
}
|
|
|
|
BOOL bFound = FALSE;
|
|
LPDFS_STORAGE_INFO pStorageInfo = pDfsInfo->Storage;
|
|
for (UINT i=0; i < pDfsInfo->NumberOfStorages; i++, pStorageInfo++)
|
|
{
|
|
if ( !lstrcmpi(pStorageInfo->ServerName, i_szServerName) &&
|
|
!lstrcmpi(pStorageInfo->ShareName, i_szShareName) )
|
|
{
|
|
bFound = TRUE;
|
|
*o_pVal = pStorageInfo->State;
|
|
break;
|
|
}
|
|
}
|
|
|
|
NetApiBufferFree(pDfsInfo);
|
|
|
|
return (bFound ? S_OK : S_FALSE);
|
|
}
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: AddReplica
|
|
(
|
|
BSTR i_szServerName,
|
|
BSTR i_szShareName,
|
|
VARIANT* o_pvarReplicaObject
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method adds a Replica to an existing Junction Point.
|
|
|
|
Arguments:
|
|
|
|
i_szServerName - The name of the server which hosts the share that the junction point should point to.
|
|
i_szShareName - The name of the share that the junction point should point to.
|
|
o_pvarReplicaObject - The Newly Created Replica's Object is returned here.
|
|
--*/
|
|
|
|
if (!i_szServerName || !i_szShareName || !o_pvarReplicaObject)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
long lDfsStorageState = DFS_STORAGE_STATE_OFFLINE;
|
|
NET_API_STATUS nstatRetVal = NetDfsAdd (
|
|
m_bstrEntryPath,
|
|
i_szServerName,
|
|
i_szShareName,
|
|
NULL,
|
|
DFS_RESTORE_VOLUME
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsAdd entry=%s, server=%s, share=%s, DFS_RESTORE_VOLUME, nRet=%d\n"),
|
|
m_bstrEntryPath, i_szServerName, i_szShareName, nstatRetVal));
|
|
|
|
if (NERR_Success != nstatRetVal)
|
|
{
|
|
return HRESULT_FROM_WIN32 (nstatRetVal);
|
|
} else
|
|
{
|
|
hr = _GetDfsStorageState(i_szServerName, i_szShareName, &lDfsStorageState);
|
|
if (S_OK != hr)
|
|
{
|
|
// something is wrong, we failed to find the target we just added
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
// Gets the IReplica interface pointer.
|
|
IDfsReplica* pIReplicaPtr = NULL;
|
|
hr = CoCreateInstance(CLSID_DfsReplica, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IDfsReplica, (void **)&pIReplicaPtr);
|
|
RETURN_IF_FAILED(hr);
|
|
|
|
// Initialize the replica object.
|
|
hr = pIReplicaPtr->Initialize(
|
|
m_bstrEntryPath,
|
|
i_szServerName,
|
|
i_szShareName,
|
|
lDfsStorageState
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = _AddToReplicaList(i_szServerName, i_szShareName, lDfsStorageState);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
o_pvarReplicaObject->vt = VT_DISPATCH;
|
|
o_pvarReplicaObject->pdispVal = (IDispatch*)pIReplicaPtr;
|
|
} else
|
|
{
|
|
pIReplicaPtr->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// RemoveReplica
|
|
|
|
|
|
STDMETHODIMP CDfsJunctionPoint :: RemoveReplica
|
|
(
|
|
BSTR i_szServerName,
|
|
BSTR i_szShareName
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method removes a replica for the Junction point.
|
|
|
|
Arguments:
|
|
|
|
i_szServerName - The name of the server hosting the share that the replica is representing.
|
|
i_szShareName - The name of the share that the replica is representing
|
|
--*/
|
|
if (!i_szServerName || !i_szShareName)
|
|
return E_INVALIDARG;
|
|
|
|
NET_API_STATUS nstatRetVal = NetDfsRemove(
|
|
m_bstrEntryPath,
|
|
i_szServerName,
|
|
i_szShareName
|
|
);
|
|
|
|
dfsDebugOut((_T("NetDfsRemove entrypath=%s, server=%s, share=%s, nRet=%d\n"),
|
|
m_bstrEntryPath, i_szServerName, i_szShareName, nstatRetVal));
|
|
|
|
if (ERROR_NOT_FOUND == nstatRetVal)
|
|
nstatRetVal = NERR_Success;
|
|
|
|
if (NERR_Success == nstatRetVal)
|
|
_DeleteFromReplicaList(i_szServerName, i_szShareName);
|
|
|
|
return HRESULT_FROM_WIN32 (nstatRetVal);
|
|
}
|
|
|
|
STDMETHODIMP CDfsJunctionPoint::RemoveAllReplicas()
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This method deletes the Junction point.
|
|
|
|
--*/
|
|
|
|
if (m_Replicas.empty())
|
|
return S_OK;
|
|
|
|
//
|
|
// DFS DCR: allow link deletion happen at once
|
|
//
|
|
NET_API_STATUS nstatRetVal = NetDfsRemove(
|
|
m_bstrEntryPath,
|
|
NULL,
|
|
NULL
|
|
);
|
|
dfsDebugOut((_T("NetDfsRemove at once entrypath=%s, nRet=%d\n"), m_bstrEntryPath, nstatRetVal));
|
|
|
|
if (ERROR_NOT_FOUND == nstatRetVal)
|
|
nstatRetVal = NERR_Success;
|
|
|
|
if (NERR_Success == nstatRetVal)
|
|
FreeReplicas(&m_Replicas);
|
|
|
|
return HRESULT_FROM_WIN32 (nstatRetVal);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// DeleteRootReplica
|
|
|
|
STDMETHODIMP CDfsJunctionPoint::DeleteRootReplica
|
|
(
|
|
BSTR i_bstrDomainName,
|
|
BSTR i_bstrDfsName,
|
|
BSTR i_bstrServerName,
|
|
BSTR i_bstrShareName,
|
|
BOOL i_bForce
|
|
)
|
|
{
|
|
RETURN_INVALIDARG_IF_TRUE(!i_bstrServerName || !*i_bstrServerName);
|
|
RETURN_INVALIDARG_IF_TRUE(!i_bstrShareName || !*i_bstrShareName);
|
|
|
|
NET_API_STATUS nStatus = NERR_Success;
|
|
|
|
if (!i_bstrDfsName || !*i_bstrDfsName) // standalone Dfs
|
|
{
|
|
nStatus = NetDfsRemoveStdRoot(
|
|
i_bstrServerName,
|
|
i_bstrShareName,
|
|
0 // No Flags.
|
|
);
|
|
dfsDebugOut((_T("NetDfsRemoveStdRoot server=%s, share=%s, nRet=%d\n"),
|
|
i_bstrServerName, i_bstrShareName, nStatus));
|
|
} else
|
|
{
|
|
if (!i_bForce)
|
|
{
|
|
nStatus = NetDfsRemoveFtRoot(
|
|
i_bstrServerName,
|
|
i_bstrShareName,
|
|
i_bstrDfsName,
|
|
0 // No Flags.
|
|
);
|
|
dfsDebugOut((_T("NetDfsRemoveFtRoot server=%s, share=%s, DfsName=%s, nRet=%d\n"),
|
|
i_bstrServerName, i_bstrShareName, i_bstrDfsName, nStatus));
|
|
} else
|
|
{
|
|
nStatus = NetDfsRemoveFtRootForced(
|
|
i_bstrDomainName,
|
|
i_bstrServerName,
|
|
i_bstrShareName,
|
|
i_bstrDfsName,
|
|
0 // No Flags.
|
|
);
|
|
dfsDebugOut((_T("NetDfsRemoveFtRootForced domain=%s, server=%s, share=%s, DfsName=%s, nRet=%d\n"),
|
|
i_bstrDomainName, i_bstrServerName, i_bstrShareName, i_bstrDfsName, nStatus));
|
|
}
|
|
}
|
|
|
|
if (NERR_Success == nStatus)
|
|
_DeleteFromReplicaList(i_bstrServerName, i_bstrShareName);
|
|
|
|
return HRESULT_FROM_WIN32(nStatus);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// GetOneRootReplica
|
|
|
|
// always return the first entry in the m_Replicas list.
|
|
STDMETHODIMP CDfsJunctionPoint::GetOneRootReplica
|
|
(
|
|
OUT BSTR* o_pbstrServerName,
|
|
OUT BSTR* o_pbstrShareName
|
|
)
|
|
{
|
|
RETURN_INVALIDARG_IF_NULL(o_pbstrServerName);
|
|
RETURN_INVALIDARG_IF_NULL(o_pbstrShareName);
|
|
|
|
*o_pbstrServerName = NULL;
|
|
*o_pbstrShareName = NULL;
|
|
|
|
if (m_Replicas.empty())
|
|
return E_INVALIDARG;
|
|
|
|
REPLICAINFOLIST::iterator i = m_Replicas.begin();
|
|
*o_pbstrServerName = SysAllocString((*i)->m_bstrServerName);
|
|
RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrServerName);
|
|
|
|
*o_pbstrShareName = SysAllocString((*i)->m_bstrShareName);
|
|
if (!*o_pbstrShareName)
|
|
{
|
|
SysFreeString(*o_pbstrServerName);
|
|
*o_pbstrServerName = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|