1438 lines
31 KiB
C++
1438 lines
31 KiB
C++
/*++
|
|
|
|
Copyright (c) 1994-2001 Microsoft Corporation
|
|
|
|
Module Name :
|
|
iismbnode.cpp
|
|
|
|
Abstract:
|
|
CIISMBNode Object
|
|
|
|
Author:
|
|
Ronald Meijer (ronaldm)
|
|
Sergei Antonov (sergeia)
|
|
|
|
Project:
|
|
Internet Services Manager
|
|
|
|
Revision History:
|
|
10/28/2000 sergeia Split from iisobj.cpp
|
|
|
|
--*/
|
|
#include "stdafx.h"
|
|
#include "common.h"
|
|
#include "inetprop.h"
|
|
#include "InetMgrApp.h"
|
|
#include "supdlgs.h"
|
|
#include "iisobj.h"
|
|
#include "ftpsht.h"
|
|
#include "w3sht.h"
|
|
#include "fltdlg.h"
|
|
#include "pwiz.h"
|
|
#include <lm.h>
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
//
|
|
// CIISMBNode implementation
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
/* static */ LPOLESTR CIISMBNode::_cszSeparator = _T("/");
|
|
|
|
|
|
|
|
CIISMBNode::CIISMBNode(
|
|
IN CIISMachine * pOwner,
|
|
IN LPCTSTR szNode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
CIISMachine * pOwner : Owner machine object
|
|
LPCTSTR szNode : Node name
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_bstrNode(szNode),
|
|
m_bstrURL(NULL),
|
|
m_pOwner(pOwner)
|
|
{
|
|
ASSERT_READ_PTR(szNode);
|
|
ASSERT_READ_PTR(pOwner);
|
|
}
|
|
|
|
|
|
CIISMBNode::~CIISMBNode()
|
|
{
|
|
RemoveResultItems();
|
|
}
|
|
|
|
|
|
void
|
|
CIISMBNode::SetErrorOverrides(
|
|
IN OUT CError & err,
|
|
IN BOOL fShort
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set error message overrides
|
|
|
|
Arguments:
|
|
|
|
CError err : Error message object
|
|
BOOL fShort : TRUE to use only single-line errors
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Substitute friendly message for some ID codes.
|
|
//
|
|
// CODEWORK: Add global overrides as well.
|
|
//
|
|
err.AddOverride(EPT_S_NOT_REGISTERED,
|
|
fShort ? IDS_ERR_RPC_NA_SHORT : IDS_ERR_RPC_NA);
|
|
err.AddOverride(RPC_S_SERVER_UNAVAILABLE,
|
|
fShort ? IDS_ERR_RPC_NA_SHORT : IDS_ERR_RPC_NA);
|
|
|
|
err.AddOverride(RPC_S_UNKNOWN_IF, IDS_ERR_INTERFACE);
|
|
err.AddOverride(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
|
|
err.AddOverride(REGDB_E_CLASSNOTREG, IDS_ERR_NO_INTERFACE);
|
|
|
|
if (!fShort)
|
|
{
|
|
err.AddOverride(ERROR_ACCESS_DENIED, IDS_ERR_ACCESS_DENIED);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CIISMBNode::IsAdministrator() const
|
|
{
|
|
CIISMBNode * that = (CIISMBNode *)this;
|
|
return that->GetOwner()->HasAdministratorAccess();
|
|
}
|
|
|
|
void
|
|
CIISMBNode::DisplayError(
|
|
IN OUT CError & err
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display error message box. Substituting some friendly messages for
|
|
some specific error codes
|
|
|
|
Arguments:
|
|
|
|
CError & err : Error object contains code to be displayed
|
|
|
|
Return Value:
|
|
|
|
Noen
|
|
|
|
--*/
|
|
{
|
|
SetErrorOverrides(err);
|
|
err.MessageBox();
|
|
}
|
|
|
|
|
|
|
|
CIISMBNode *
|
|
CIISMBNode::GetParentNode() const
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to return the parent node in the scope tree
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Parent CIISMBNode or NULL.
|
|
|
|
--*/
|
|
{
|
|
LONG_PTR cookie = NULL;
|
|
HSCOPEITEM hParent;
|
|
CIISMBNode * pNode = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT_PTR(_lpConsoleNameSpace);
|
|
|
|
if (m_hResultItem != 0)
|
|
{
|
|
SCOPEDATAITEM si;
|
|
::ZeroMemory(&si, sizeof(SCOPEDATAITEM));
|
|
si.mask = SDI_PARAM;
|
|
si.ID = m_hScopeItem;
|
|
hr = _lpConsoleNameSpace->GetItem(&si);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
cookie = si.lParam;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = _lpConsoleNameSpace->GetParentItem(
|
|
m_hScopeItem,
|
|
&hParent,
|
|
&cookie
|
|
);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pNode = (CIISMBNode *)cookie;
|
|
ASSERT_PTR(pNode);
|
|
}
|
|
|
|
return pNode;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISMBNode::BuildMetaPath(
|
|
OUT CComBSTR & bstrPath
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Recursively build up the metabase path from the current node
|
|
and its parents
|
|
|
|
Arguments:
|
|
|
|
CComBSTR & bstrPath : Returns metabase path
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CIISMBNode * pNode = GetParentNode();
|
|
|
|
if (pNode)
|
|
{
|
|
hr = pNode->BuildMetaPath(bstrPath);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bstrPath.Append(_cszSeparator);
|
|
bstrPath.Append(QueryNodeName());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// No parent node
|
|
//
|
|
ASSERT_MSG("No parent node");
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CIISMBNode::FillCustomData(CLIPFORMAT cf, LPSTREAM pStream)
|
|
{
|
|
HRESULT hr = DV_E_CLIPFORMAT;
|
|
ULONG uWritten;
|
|
|
|
if (cf == m_CCF_MachineName)
|
|
{
|
|
hr = pStream->Write(
|
|
QueryMachineName(),
|
|
(ocslen((OLECHAR*)QueryMachineName()) + 1) * sizeof(OLECHAR),
|
|
&uWritten
|
|
);
|
|
|
|
ASSERT(SUCCEEDED(hr));
|
|
return hr;
|
|
}
|
|
//
|
|
// Generate complete metabase path for this node
|
|
//
|
|
CString strField;
|
|
CString strMetaPath;
|
|
CComBSTR bstr;
|
|
if (FAILED(hr = BuildMetaPath(bstr)))
|
|
{
|
|
ASSERT(FALSE);
|
|
return hr;
|
|
}
|
|
strMetaPath = bstr;
|
|
|
|
if (cf == m_CCF_MetaPath)
|
|
{
|
|
//
|
|
// Whole metabase path requested
|
|
//
|
|
strField = strMetaPath;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// A portion of the metabase is requested. Return the requested
|
|
// portion
|
|
//
|
|
LPCTSTR lpMetaPath = (LPCTSTR)strMetaPath;
|
|
LPCTSTR lpEndPath = lpMetaPath + strMetaPath.GetLength() + 1;
|
|
LPCTSTR lpSvc = NULL;
|
|
LPCTSTR lpInstance = NULL;
|
|
LPCTSTR lpParent = NULL;
|
|
LPCTSTR lpNode = NULL;
|
|
|
|
//
|
|
// Break up the metabase path in portions
|
|
//
|
|
if (lpSvc = _tcschr(lpMetaPath, _T('/')))
|
|
{
|
|
++lpSvc;
|
|
|
|
if (lpInstance = _tcschr(lpSvc, _T('/')))
|
|
{
|
|
++lpInstance;
|
|
|
|
if (lpParent = _tcschr(lpInstance, _T('/')))
|
|
{
|
|
++lpParent;
|
|
lpNode = _tcsrchr(lpParent, _T('/'));
|
|
|
|
if (lpNode)
|
|
{
|
|
++lpNode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int n1, n2;
|
|
if (cf == m_CCF_Service)
|
|
{
|
|
//
|
|
// Requested the service string
|
|
//
|
|
if (lpSvc)
|
|
{
|
|
n1 = DIFF(lpSvc - lpMetaPath);
|
|
n2 = lpInstance ? DIFF(lpInstance - lpSvc) : DIFF(lpEndPath - lpSvc);
|
|
strField = strMetaPath.Mid(n1, n2 - 1);
|
|
}
|
|
}
|
|
else if (cf == m_CCF_Instance)
|
|
{
|
|
//
|
|
// Requested the instance number
|
|
//
|
|
if (lpInstance)
|
|
{
|
|
n1 = DIFF(lpInstance - lpMetaPath);
|
|
n2 = lpParent ? DIFF(lpParent - lpInstance) : DIFF(lpEndPath - lpInstance);
|
|
strField = strMetaPath.Mid(n1, n2 - 1);
|
|
}
|
|
}
|
|
else if (cf == m_CCF_ParentPath)
|
|
{
|
|
//
|
|
// Requestd the parent path
|
|
//
|
|
if (lpParent)
|
|
{
|
|
n1 = DIFF(lpParent - lpMetaPath);
|
|
n2 = lpNode ? DIFF(lpNode - lpParent) : DIFF(lpEndPath - lpParent);
|
|
strField = strMetaPath.Mid(n1, n2 - 1);
|
|
}
|
|
}
|
|
else if (cf == m_CCF_Node)
|
|
{
|
|
//
|
|
// Requested the node name
|
|
//
|
|
if (lpNode)
|
|
{
|
|
n1 = DIFF(lpNode - lpMetaPath);
|
|
n2 = DIFF(lpEndPath - lpNode);
|
|
strField = strMetaPath.Mid(n1, n2 - 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
DV_E_CLIPFORMAT;
|
|
}
|
|
}
|
|
|
|
TRACEEOLID("Requested metabase path data: " << strField);
|
|
int len = strField.GetLength() + 1;
|
|
hr = pStream->Write(strField,
|
|
(ocslen(strField) + 1) * sizeof(OLECHAR), &uWritten);
|
|
ASSERT(SUCCEEDED(hr));
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::BuildURL(
|
|
OUT CComBSTR & bstrURL
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Recursively build up the URL from the current node
|
|
and its parents.
|
|
|
|
Arguments:
|
|
|
|
CComBSTR & bstrURL : Returns URL
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Prepend parent portion
|
|
//
|
|
CIISMBNode * pNode = GetParentNode();
|
|
|
|
if (pNode)
|
|
{
|
|
hr = pNode->BuildURL(bstrURL);
|
|
|
|
//
|
|
// And our portion
|
|
//
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bstrURL.Append(_cszSeparator);
|
|
bstrURL.Append(QueryNodeName());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// No parent node
|
|
//
|
|
ASSERT_MSG("No parent node");
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CIISMBNode::OnLostInterface(
|
|
IN OUT CError & err
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deal with lost interface. Ask the user to reconnect.
|
|
|
|
Arguments:
|
|
|
|
CError & err : Error object
|
|
|
|
Return Value:
|
|
|
|
TRUE if the interface was successfully recreated.
|
|
FALSE otherwise. If it tried and failed the error will
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
|
|
CString str;
|
|
str.Format(IDS_RECONNECT_WARNING, QueryMachineName());
|
|
|
|
if (YesNoMessageBox(str))
|
|
{
|
|
//
|
|
// Attempt to recreate the interface
|
|
//
|
|
err = CreateInterface(TRUE);
|
|
return err.Succeeded();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::DeleteNode(IResultData * pResult)
|
|
{
|
|
CError err;
|
|
|
|
if (!NoYesMessageBox(IDS_CONFIRM_DELETE))
|
|
return err;
|
|
|
|
do
|
|
{
|
|
CComBSTR path;
|
|
CMetaInterface * pInterface = QueryInterface();
|
|
ASSERT(pInterface != NULL);
|
|
err = BuildMetaPath(path);
|
|
if (err.Failed())
|
|
break;
|
|
CMetaKey mk(pInterface, METADATA_MASTER_ROOT_HANDLE, METADATA_PERMISSION_WRITE);
|
|
if (!mk.Succeeded())
|
|
break;
|
|
err = mk.DeleteKey(path);
|
|
if (err.Failed())
|
|
break;
|
|
|
|
err = RemoveScopeItem();
|
|
|
|
} while (FALSE);
|
|
|
|
if (err.Failed())
|
|
{
|
|
DisplayError(err);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::EnumerateVDirs(HSCOPEITEM hParent, CIISService * pService)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerate scope child items.
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent console handle
|
|
CIISService * pService : Service type
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(pService);
|
|
|
|
CError err;
|
|
CString strVRoot;
|
|
CMetaEnumerator * pme = NULL;
|
|
|
|
err = CreateEnumerator(pme);
|
|
|
|
while (err.Succeeded())
|
|
{
|
|
CIISDirectory * pDir;
|
|
|
|
err = pme->Next(strVRoot);
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
TRACEEOLID("Enumerating node: " << strVRoot);
|
|
|
|
CChildNodeProps child(pme, strVRoot, WITH_INHERITANCE, FALSE);
|
|
err = child.LoadData();
|
|
DWORD dwWin32Error = err.Win32Error();
|
|
|
|
if (err.Failed())
|
|
{
|
|
//
|
|
// Filter out the non-fatal errors
|
|
//
|
|
switch(err.Win32Error())
|
|
{
|
|
case ERROR_ACCESS_DENIED:
|
|
case ERROR_FILE_NOT_FOUND:
|
|
case ERROR_PATH_NOT_FOUND:
|
|
err.Reset();
|
|
break;
|
|
|
|
default:
|
|
TRACEEOLID("Fatal error occurred " << err);
|
|
}
|
|
}
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
//
|
|
// Skip non-virtual directories (that is, those with
|
|
// inherited vrpaths)
|
|
//
|
|
if (!child.IsPathInherited())
|
|
{
|
|
//
|
|
// Construct with full information.
|
|
//
|
|
pDir = new CIISDirectory(
|
|
m_pOwner,
|
|
pService,
|
|
strVRoot,
|
|
child.IsEnabledApplication(),
|
|
child.QueryWin32Error(),
|
|
child.GetRedirectedPath()
|
|
);
|
|
|
|
if (!pDir)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
err = pDir->AddToScopePane(hParent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SAFE_DELETE(pme);
|
|
|
|
if (err.Win32Error() == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
err.Reset();
|
|
}
|
|
|
|
if (err.Failed())
|
|
{
|
|
DisplayError(err);
|
|
}
|
|
|
|
// SetInterfaceError(err);
|
|
|
|
return err;
|
|
}
|
|
|
|
BOOL
|
|
CIISMBNode::GetPhysicalPath(
|
|
LPCTSTR metaPath,
|
|
CString & alias,
|
|
CString & physicalPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a physical path for the current node. Starting with the current
|
|
node, walk up the tree appending node names until a virtual directory
|
|
with a real physical path is found
|
|
|
|
Arguments:
|
|
|
|
CString & physicalPath : Returns file path
|
|
|
|
Return Value:
|
|
|
|
Pointer to path
|
|
|
|
--*/
|
|
{
|
|
if (CMetabasePath::IsMasterInstance(metaPath))
|
|
return FALSE;
|
|
|
|
BOOL fInherit = FALSE;
|
|
CMetaInterface * pInterface = QueryInterface();
|
|
ASSERT(pInterface != NULL);
|
|
CMetaKey mk(pInterface);
|
|
CError err(mk.QueryValue(
|
|
MD_VR_PATH,
|
|
physicalPath,
|
|
&fInherit,
|
|
metaPath
|
|
));
|
|
|
|
if (err.Failed())
|
|
{
|
|
CString lastNode;
|
|
CMetabasePath::GetLastNodeName(metaPath, lastNode);
|
|
PathAppend(lastNode.GetBuffer(MAX_PATH), alias);
|
|
lastNode.ReleaseBuffer();
|
|
CString buf(metaPath);
|
|
if (NULL == CMetabasePath::ConvertToParentPath(buf))
|
|
{
|
|
return FALSE;
|
|
}
|
|
else if (GetPhysicalPath(buf, lastNode, physicalPath))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
if (!alias.IsEmpty())
|
|
{
|
|
PathAppend(physicalPath.GetBuffer(MAX_PATH), alias);
|
|
physicalPath.ReleaseBuffer();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::CleanResult(IResultData * lpResultData)
|
|
{
|
|
CError err;
|
|
|
|
if (!m_ResultItems.IsEmpty())
|
|
{
|
|
POSITION pos = m_ResultItems.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CIISFileName * pNode = m_ResultItems.GetNext(pos);
|
|
err = lpResultData->DeleteItem(pNode->m_hResultItem, 0);
|
|
if (err.Failed())
|
|
{
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
delete pNode;
|
|
}
|
|
m_ResultItems.RemoveAll();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::EnumerateResultPane_(
|
|
BOOL fExpand,
|
|
IHeaderCtrl * lpHeader,
|
|
IResultData * lpResultData,
|
|
CIISService * pService
|
|
)
|
|
{
|
|
CError err;
|
|
if (HasFileSystemFiles())
|
|
{
|
|
if (fExpand)
|
|
{
|
|
do
|
|
{
|
|
CString dir;
|
|
CComBSTR root;
|
|
BuildMetaPath(root);
|
|
CString physPath, alias;
|
|
GetPhysicalPath(CString(root), alias, physPath);
|
|
|
|
if (pService->IsLocal() || PathIsUNC(physPath))
|
|
{
|
|
dir = physPath;
|
|
}
|
|
else
|
|
{
|
|
::MakeUNCPath(dir, pService->QueryMachineName(), physPath);
|
|
}
|
|
|
|
dir.TrimLeft();
|
|
dir.TrimRight();
|
|
|
|
if (dir.IsEmpty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (PathIsUNCServerShare(dir))
|
|
{
|
|
CString server, share;
|
|
int idx = dir.ReverseFind(_T('\\'));
|
|
ASSERT(idx != -1);
|
|
server = dir.Left(idx);
|
|
share = dir.Mid(++idx);
|
|
LPBYTE pbuf = NULL;
|
|
NET_API_STATUS rc = NetShareGetInfo((LPTSTR)(LPCTSTR)server, (LPTSTR)(LPCTSTR)share, 0, &pbuf);
|
|
if (NERR_Success == rc)
|
|
{
|
|
NetApiBufferFree(pbuf);
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_BAD_NETPATH;
|
|
break;
|
|
}
|
|
}
|
|
|
|
dir += _T("\\*");
|
|
WIN32_FIND_DATA w32data;
|
|
HANDLE hFind = ::FindFirstFile(dir, &w32data);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
err.GetLastWinError();
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
do
|
|
{
|
|
LPCTSTR name = w32data.cFileName;
|
|
if ((w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
|
{
|
|
CIISFileName * pNode = new CIISFileName(
|
|
GetOwner(),
|
|
pService,
|
|
w32data.dwFileAttributes,
|
|
name,
|
|
NULL);
|
|
if (!pNode)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
RESULTDATAITEM ri;
|
|
::ZeroMemory(&ri, sizeof(ri));
|
|
ri.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
|
|
ri.str = MMC_CALLBACK;
|
|
ri.nImage = pNode->QueryImage();
|
|
ri.lParam = (LPARAM)pNode;
|
|
err = lpResultData->InsertItem(&ri);
|
|
if (err.Succeeded())
|
|
{
|
|
pNode->SetScopeItem(m_hScopeItem);
|
|
pNode->SetResultItem(ri.itemID);
|
|
m_ResultItems.AddTail(pNode);
|
|
}
|
|
else
|
|
{
|
|
delete pNode;
|
|
}
|
|
}
|
|
|
|
} while (err.Succeeded() && FindNextFile(hFind, &w32data));
|
|
|
|
FindClose(hFind);
|
|
|
|
} while (FALSE);
|
|
}
|
|
else
|
|
{
|
|
RemoveResultItems();
|
|
}
|
|
}
|
|
ASSERT(err.Succeeded());
|
|
return err;
|
|
}
|
|
|
|
|
|
void
|
|
CIISMBNode::RemoveResultItems()
|
|
{
|
|
if (!m_ResultItems.IsEmpty())
|
|
{
|
|
POSITION pos = m_ResultItems.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
CIISFileName * pNode = m_ResultItems.GetNext(pos);
|
|
delete pNode;
|
|
}
|
|
m_ResultItems.RemoveAll();
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CIISMBNode::EnumerateWebDirs(HSCOPEITEM hParent, CIISService * pService)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumerate scope file system child items.
|
|
|
|
Arguments:
|
|
|
|
HSCOPEITEM hParent : Parent console handle
|
|
CIISService * pService : Service type
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(pService);
|
|
CError err;
|
|
do
|
|
{
|
|
CString dir;
|
|
CComBSTR root;
|
|
BuildMetaPath(root);
|
|
CString physPath, alias;
|
|
GetPhysicalPath(CString(root), alias, physPath);
|
|
|
|
if (pService->IsLocal() || PathIsUNC(physPath))
|
|
{
|
|
dir = physPath;
|
|
}
|
|
else
|
|
{
|
|
::MakeUNCPath(dir, pService->QueryMachineName(), physPath);
|
|
}
|
|
dir.TrimLeft();
|
|
dir.TrimRight();
|
|
if (dir.IsEmpty())
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Prepare for target machine metabase lookup
|
|
BOOL fCheckMetabase = TRUE;
|
|
CMetaKey mk(QueryInterface(), root, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE);
|
|
CError errMB(mk.QueryResult());
|
|
if (errMB.Win32Error() == ERROR_PATH_NOT_FOUND)
|
|
{
|
|
//
|
|
// Metabase path not found, not a problem.
|
|
//
|
|
fCheckMetabase = FALSE;
|
|
errMB.Reset();
|
|
}
|
|
|
|
// We could have vroot pointed to target machine, or to another remote machine.
|
|
// Check if this resource is available and we have access to this resource
|
|
if (PathIsUNC(dir))
|
|
{
|
|
CString server, user, password;
|
|
|
|
server = PathFindNextComponent(dir);
|
|
int n = server.Find(_T('\\'));
|
|
if (n != -1)
|
|
{
|
|
server = server.Left(n);
|
|
}
|
|
user = QueryInterface()->QueryAuthInfo()->QueryUserName();
|
|
password = QueryInterface()->QueryAuthInfo()->QueryPassword();
|
|
if (server.CompareNoCase(pService->QueryMachineName()) != 0)
|
|
{
|
|
// non-local resource, get connection credentials
|
|
if (fCheckMetabase)
|
|
{
|
|
err = mk.QueryValue(MD_VR_USERNAME, user);
|
|
if (err.Succeeded())
|
|
{
|
|
err = mk.QueryValue(MD_VR_PASSWORD, password);
|
|
}
|
|
// these credentials could be empty. try defaults
|
|
err.Reset();
|
|
}
|
|
}
|
|
// Add use for this resource
|
|
NETRESOURCE nr;
|
|
nr.dwType = RESOURCETYPE_DISK;
|
|
nr.lpLocalName = NULL;
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR)dir;
|
|
nr.lpProvider = NULL;
|
|
// Empty strings below mean no password, which is wrong. NULLs mean
|
|
// default user and default password -- this could work better for local case.
|
|
LPCTSTR p1 = password, p2 = user;
|
|
if (password.IsEmpty())
|
|
{
|
|
p1 = NULL;
|
|
}
|
|
if (user.IsEmpty())
|
|
{
|
|
p2 = NULL;
|
|
}
|
|
DWORD rc = WNetAddConnection2(&nr, p1, p2, 0);
|
|
if (NO_ERROR != rc)
|
|
{
|
|
err = rc;
|
|
break;
|
|
}
|
|
}
|
|
#if 0
|
|
// This is obsolete now
|
|
if (PathIsUNCServerShare(dir))
|
|
{
|
|
CString server, share;
|
|
int idx = dir.ReverseFind(_T('\\'));
|
|
ASSERT(idx != -1);
|
|
server = dir.Left(idx);
|
|
share = dir.Mid(++idx);
|
|
LPBYTE pbuf = NULL;
|
|
NET_API_STATUS rc = NetShareGetInfo((LPTSTR)(LPCTSTR)server, (LPTSTR)(LPCTSTR)share, 0, &pbuf);
|
|
if (NERR_Success == rc)
|
|
{
|
|
NetApiBufferFree(pbuf);
|
|
}
|
|
else
|
|
{
|
|
err = ERROR_BAD_NETPATH;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
dir += _T("\\*");
|
|
WIN32_FIND_DATA w32data;
|
|
HANDLE hFind = ::FindFirstFile(dir, &w32data);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
err.GetLastWinError();
|
|
break;
|
|
}
|
|
do
|
|
{
|
|
LPCTSTR name = w32data.cFileName;
|
|
if ( (w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
|
|
&& lstrcmp(name, _T(".")) != 0
|
|
&& lstrcmp(name, _T("..")) != 0
|
|
)
|
|
{
|
|
CIISFileName * pNode = new CIISFileName(m_pOwner,
|
|
pService, w32data.dwFileAttributes, name, NULL);
|
|
if (!pNode)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
if (fCheckMetabase)
|
|
{
|
|
errMB = mk.DoesPathExist(w32data.cFileName);
|
|
if (errMB.Succeeded())
|
|
{
|
|
//
|
|
// Match up with metabase properties. If the item
|
|
// is found in the metabase with a non-inherited vrpath,
|
|
// than a virtual root with this name exists, and this
|
|
// file/directory should not be shown.
|
|
//
|
|
CString vrpath;
|
|
BOOL f = FALSE;
|
|
DWORD attr = 0;
|
|
errMB = mk.QueryValue(MD_VR_PATH, vrpath, NULL, w32data.cFileName, &attr);
|
|
if (errMB.Succeeded() && (attr & METADATA_ISINHERITED) == 0)
|
|
{
|
|
TRACEEOLID("file/directory exists as vroot -- tossing" << w32data.cFileName);
|
|
delete pNode;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
err = pNode->AddToScopePane(hParent);
|
|
}
|
|
} while (err.Succeeded() && FindNextFile(hFind, &w32data));
|
|
|
|
FindClose(hFind);
|
|
|
|
} while (FALSE);
|
|
|
|
if (err.Failed())
|
|
{
|
|
DisplayError(err);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::CreateEnumerator(CMetaEnumerator *& pEnum)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create enumerator object for the current path. Requires interface
|
|
to already be initialized
|
|
|
|
Arguments:
|
|
|
|
CMetaEnumerator *& pEnum : Returns enumerator
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ASSERT(pEnum == NULL);
|
|
ASSERT(m_hScopeItem != NULL);
|
|
|
|
CComBSTR bstrPath;
|
|
|
|
CError err(BuildMetaPath(bstrPath));
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
TRACEEOLID("Build metabase path: " << bstrPath);
|
|
|
|
BOOL fContinue = TRUE;
|
|
|
|
while(fContinue)
|
|
{
|
|
fContinue = FALSE;
|
|
|
|
pEnum = new CMetaEnumerator(QueryInterface(), bstrPath);
|
|
|
|
err = pEnum ? pEnum->QueryResult() : ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
if (IsLostInterface(err))
|
|
{
|
|
SAFE_DELETE(pEnum);
|
|
|
|
fContinue = OnLostInterface(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISMBNode::Refresh(BOOL fReEnumerate)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Refresh current node, and optionally re-enumerate child objects
|
|
|
|
Arguments:
|
|
BOOL fReEnumerate : If true, kill child objects, and re-enumerate
|
|
|
|
--*/
|
|
{
|
|
CError err;
|
|
|
|
//
|
|
// Set MFC state for wait cursor
|
|
//
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
CWaitCursor wait;
|
|
|
|
if (fReEnumerate)
|
|
{
|
|
//
|
|
// Kill child objects
|
|
//
|
|
TRACEEOLID("Killing child objects");
|
|
|
|
ASSERT(m_hScopeItem != NULL);
|
|
err = RemoveChildren(m_hScopeItem);
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
err = EnumerateScopePane(m_hScopeItem);
|
|
}
|
|
}
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
//
|
|
// Refresh current node
|
|
//
|
|
err = RefreshData();
|
|
if (err.Succeeded())
|
|
{
|
|
err = RefreshDisplay();
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CIISMBNode::GetResultViewType(
|
|
OUT LPOLESTR * lplpViewType,
|
|
OUT long * lpViewOptions
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If we have an URL built up, display our result view as that URL,
|
|
and destroy it. This is done when 'browsing' a metabase node.
|
|
The derived class will build the URL, and reselect the node.
|
|
|
|
Arguments:
|
|
|
|
BSTR * lplpViewType : Return view type here
|
|
long * lpViewOptions : View options
|
|
|
|
Return Value:
|
|
|
|
S_FALSE to use default view type, S_OK indicates the
|
|
view type is returned in *ppViewType
|
|
|
|
--*/
|
|
{
|
|
if (m_bstrURL.Length())
|
|
{
|
|
*lpViewOptions = MMC_VIEW_OPTIONS_NONE;
|
|
*lplpViewType = (LPOLESTR)::CoTaskMemAlloc(
|
|
(m_bstrURL.Length() + 1) * sizeof(WCHAR)
|
|
);
|
|
|
|
if (*lplpViewType)
|
|
{
|
|
lstrcpy(*lplpViewType, m_bstrURL);
|
|
|
|
//
|
|
// Destroy URL so we get a normal result view next time
|
|
//
|
|
m_bstrURL.Empty();
|
|
m_fSkipEnumResult = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
//
|
|
// No URL waiting -- use standard result view
|
|
//
|
|
return CIISObject::GetResultViewType(lplpViewType, lpViewOptions);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ShellExecuteDirectory(
|
|
IN LPCTSTR lpszCommand,
|
|
IN LPCTSTR lpszOwner,
|
|
IN LPCTSTR lpszDirectory
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Shell Open or explore on a given directory path
|
|
|
|
Arguments:
|
|
|
|
LPCTSTR lpszCommand : "open" or "explore"
|
|
LPCTSTR lpszOwner : Owner server
|
|
LPCTSTR lpszDirectory : Directory path
|
|
|
|
Return Value:
|
|
|
|
Error return code.
|
|
|
|
--*/
|
|
{
|
|
CString strDir;
|
|
|
|
if (::IsServerLocal(lpszOwner) || ::IsUNCName(lpszDirectory))
|
|
{
|
|
//
|
|
// Local directory, or already a unc path
|
|
//
|
|
strDir = lpszDirectory;
|
|
}
|
|
else
|
|
{
|
|
::MakeUNCPath(strDir, lpszOwner, lpszDirectory);
|
|
}
|
|
|
|
TRACEEOLID("Attempting to " << lpszCommand << " Path: " << strDir);
|
|
|
|
CError err;
|
|
{
|
|
//
|
|
// AFX_MANAGE_STATE required for wait cursor
|
|
//
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState() );
|
|
CWaitCursor wait;
|
|
|
|
if (::ShellExecute(
|
|
NULL,
|
|
lpszCommand,
|
|
strDir,
|
|
NULL,
|
|
_T(""),
|
|
SW_SHOW
|
|
) <= (HINSTANCE)32)
|
|
{
|
|
err.GetLastWinError();
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CIISMBNode::Command(
|
|
IN long lCommandID,
|
|
IN CSnapInObjectRootBase * pObj,
|
|
IN DATA_OBJECT_TYPES type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle command from context menu.
|
|
|
|
Arguments:
|
|
|
|
long lCommandID : Command ID
|
|
CSnapInObjectRootBase * pObj : Base object
|
|
DATA_OBJECT_TYPES type : Data object type
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CError err = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
switch (lCommandID)
|
|
{
|
|
case IDM_BROWSE:
|
|
//
|
|
// Build URL for this node, and force a re-select so as to change
|
|
// the result view
|
|
//
|
|
BuildURL(m_bstrURL);
|
|
|
|
if (m_bstrURL.Length())
|
|
{
|
|
//
|
|
// After selection, the browsed URL will come up in the result view
|
|
//
|
|
SelectScopeItem();
|
|
}
|
|
break;
|
|
|
|
//
|
|
// CODEWORK: Build path, and, using the explorer URL, put this stuff
|
|
// in the result view.
|
|
//
|
|
case IDM_OPEN:
|
|
{
|
|
CComBSTR meta_path;
|
|
CString phys_path, alias;
|
|
BuildMetaPath(meta_path);
|
|
if (GetPhysicalPath(meta_path, alias, phys_path))
|
|
{
|
|
hr = ShellExecuteDirectory(_T("open"), QueryMachineName(), phys_path);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_EXPLORE:
|
|
{
|
|
CComBSTR meta_path;
|
|
CString phys_path, alias;
|
|
BuildMetaPath(meta_path);
|
|
if (GetPhysicalPath(meta_path, alias, phys_path))
|
|
{
|
|
TCHAR url[MAX_PATH];
|
|
DWORD len = MAX_PATH;
|
|
hr = UrlCreateFromPath(phys_path, url, &len, NULL);
|
|
m_bstrURL = url;
|
|
SelectScopeItem();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_TASK_SECURITY_WIZARD:
|
|
{
|
|
CComBSTR path;
|
|
VERIFY(SUCCEEDED(BuildMetaPath(path)));
|
|
hr = RunSecurityWizard(QueryAuthInfo(),
|
|
QueryInterface(), CString(path),
|
|
IDB_WIZ_FTP_LEFT_SEC, IDB_WIZ_FTP_HEAD_SEC);
|
|
}
|
|
break;
|
|
//
|
|
// Pass on to base class
|
|
//
|
|
default:
|
|
hr = CIISObject::Command(lCommandID, pObj, type);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::OnPropertyChange(BOOL fScope, IResultData * pResult)
|
|
{
|
|
CError err;
|
|
|
|
err = Refresh(fScope);
|
|
if (err.Succeeded())
|
|
{
|
|
if ( fScope
|
|
&& HasFileSystemFiles()
|
|
&& !m_ResultItems.IsEmpty()
|
|
)
|
|
{
|
|
err = CleanResult(pResult);
|
|
if (err.Succeeded())
|
|
{
|
|
err = EnumerateResultPane(fScope, NULL, pResult);
|
|
}
|
|
}
|
|
else if (!fScope)
|
|
{
|
|
pResult->UpdateItem(m_hResultItem);
|
|
}
|
|
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::RemoveResultNode(CIISMBNode * pNode, IResultData * pResult)
|
|
{
|
|
CError err;
|
|
ASSERT(HasFileSystemFiles());
|
|
err = pResult->DeleteItem(pNode->m_hResultItem, 0);
|
|
if (err.Succeeded())
|
|
{
|
|
BOOL found = FALSE;
|
|
POSITION pos = m_ResultItems.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
if (m_ResultItems.GetNext(pos) == pNode)
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
m_ResultItems.RemoveAt(pos);
|
|
delete pNode;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
// See FtpAddNew.cpp for the method CIISMBNode::AddFTPSite
|
|
// See WebAddNew.cpp for the method CIISMBNode::AddWebSite
|
|
// See add_app_pool.cpp for the method CIISMBNode::AddAppPool
|