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.
2515 lines
68 KiB
2515 lines
68 KiB
/*++
|
|
|
|
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 "aclpage.h"
|
|
#include "impexp.h"
|
|
#include "util.h"
|
|
#include "tracker.h"
|
|
#include <lm.h>
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
extern INT g_iDebugOutputLevel;
|
|
extern CPropertySheetTracker g_OpenPropertySheetTracker;
|
|
//
|
|
// CIISMBNode implementation
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
/* static */ LPOLESTR CIISMBNode::_cszSeparator = _T("/");
|
|
/* static */ CComBSTR CIISMBNode::_bstrRedirectPathBuf;
|
|
|
|
|
|
|
|
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);
|
|
if (this != m_pOwner)
|
|
{
|
|
m_pOwner->AddRef();
|
|
}
|
|
m_pMachineObject = m_pOwner;
|
|
|
|
if (g_iDebugOutputLevel & DEBUG_FLAG_CIISMBNODE)
|
|
{
|
|
TRACEEOL("AddRef to m_pOwner: node " << szNode << " count " << m_pOwner->UseCount())
|
|
}
|
|
}
|
|
|
|
|
|
CIISMBNode::~CIISMBNode()
|
|
{
|
|
if (this != m_pOwner)
|
|
{
|
|
m_pOwner->Release();
|
|
}
|
|
if (g_iDebugOutputLevel & DEBUG_FLAG_CIISMBNODE)
|
|
{
|
|
TRACEEOL("Released m_pOwner: node " << m_bstrNode << " count " << m_pOwner->UseCount())
|
|
}
|
|
}
|
|
|
|
CIISMBNode::CreateTag()
|
|
{
|
|
CIISMachine * pMachine = GetOwner();
|
|
if (pMachine)
|
|
{
|
|
CComBSTR bstrPath;
|
|
BuildMetaPath(bstrPath);
|
|
m_strTag = pMachine->QueryDisplayName();
|
|
m_strTag += bstrPath;
|
|
}
|
|
}
|
|
|
|
|
|
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);
|
|
err.AddOverride(ERROR_DUP_NAME, fShort ? IDS_ERR_BINDING_SHORT : IDS_ERR_BINDING_LONG);
|
|
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(CError& err, HWND hWnd) 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
|
|
|
|
--*/
|
|
{
|
|
if (err == E_POINTER)
|
|
{
|
|
err.Reset();
|
|
}
|
|
if (err.Failed())
|
|
{
|
|
SetErrorOverrides(err);
|
|
err.MessageBox(hWnd);
|
|
}
|
|
}
|
|
|
|
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;
|
|
SCOPEDATAITEM si;
|
|
::ZeroMemory(&si, sizeof(SCOPEDATAITEM));
|
|
|
|
CIISObject * ThisConst = (CIISObject *)this;
|
|
|
|
IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)ThisConst->GetConsoleNameSpace();
|
|
|
|
|
|
if (m_hResultItem != 0)
|
|
{
|
|
si.mask = SDI_PARAM;
|
|
si.ID = m_hScopeItem;
|
|
hr = pConsoleNameSpace->GetItem(&si);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
cookie = si.lParam;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Get our Item
|
|
si.mask = SDI_PARAM;
|
|
si.ID = m_hScopeItem;
|
|
// if we can get our item, then try to get our parents
|
|
// we need to do this because MMC will AV if we don't exist first...
|
|
if (SUCCEEDED(pConsoleNameSpace->GetItem(&si)))
|
|
{
|
|
hr = pConsoleNameSpace->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
|
|
//
|
|
//BUG:670171
|
|
// Path from BuildMetaPath() is returning something like
|
|
// /LM/W3SVC/1/ROOT
|
|
//
|
|
// however, it should be returned as LM/W3SVC/1/ROOT to be
|
|
// backwards compatible with how iis5 used to work...
|
|
if (_T("/") == strMetaPath.Left(1))
|
|
{
|
|
strField = strMetaPath.Right(strMetaPath.GetLength() - 1);
|
|
}
|
|
else
|
|
{
|
|
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 lpLM = NULL;
|
|
LPCTSTR lpSvc = NULL;
|
|
LPCTSTR lpInstance = NULL;
|
|
LPCTSTR lpParent = NULL;
|
|
LPCTSTR lpNode = NULL;
|
|
|
|
//
|
|
// Break up the metabase path in portions
|
|
//
|
|
if (lpLM = _tcschr(lpMetaPath, _T('/')))
|
|
{
|
|
++lpLM;
|
|
|
|
if (lpSvc = _tcschr(lpLM, _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;
|
|
|
|
// check if they have the property sheet open on it.
|
|
if (IsMyPropertySheetOpen())
|
|
{
|
|
::AfxMessageBox(IDS_CLOSE_PROPERTY_SHEET);
|
|
return S_OK;
|
|
}
|
|
|
|
// this could be an orphaned property sheet
|
|
// check if an orphaned property sheet is open on this item.
|
|
CIISObject * pAlreadyOpenProp = NULL;
|
|
if (TRUE == g_OpenPropertySheetTracker.FindAlreadyOpenPropertySheet(this,&pAlreadyOpenProp))
|
|
{
|
|
// Bring it to the foreground, and bail
|
|
HWND hHwnd = 0;
|
|
if (pAlreadyOpenProp)
|
|
{
|
|
if (hHwnd = pAlreadyOpenProp->IsMyPropertySheetOpen())
|
|
{
|
|
if (hHwnd && (hHwnd != (HWND) 1))
|
|
{
|
|
// Perhapse we should cancel the already
|
|
// opened property sheet...just a thought
|
|
if (!SetForegroundWindow(hHwnd))
|
|
{
|
|
// wasn't able to bring this property sheet to
|
|
// the foreground, the propertysheet must not
|
|
// exist anymore. let's just clean the hwnd
|
|
// so that the user will be able to open propertysheet
|
|
pAlreadyOpenProp->SetMyPropertySheetOpen(0);
|
|
}
|
|
else
|
|
{
|
|
::AfxMessageBox(IDS_CLOSE_PROPERTY_SHEET);
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CComBSTR path;
|
|
err = BuildMetaPath(path);
|
|
if (err.Succeeded())
|
|
{
|
|
err = CheckForMetabaseAccess(METADATA_PERMISSION_WRITE,this,TRUE,path);
|
|
if (!IsLostInterface(err))
|
|
{
|
|
// reset error if an other error other than No interface
|
|
err.Reset();
|
|
}
|
|
}
|
|
if (err.Succeeded())
|
|
{
|
|
if (!NoYesMessageBox(IDS_CONFIRM_DELETE))
|
|
return err;
|
|
|
|
do
|
|
{
|
|
CMetaInterface * pInterface = QueryInterface();
|
|
ASSERT(pInterface != NULL);
|
|
CMetaKey mk(pInterface, METADATA_MASTER_ROOT_HANDLE, METADATA_PERMISSION_WRITE);
|
|
if (!mk.Succeeded())
|
|
break;
|
|
err = mk.DeleteKey(path);
|
|
if (err.Failed())
|
|
break;
|
|
|
|
// don't hold the Metabasekey open
|
|
// (RemoveScopeItem may do a lot of things,and lock the metabase for other read requests)
|
|
mk.Close();
|
|
|
|
m_fFlaggedForDeletion = TRUE;
|
|
err = RemoveScopeItem();
|
|
|
|
} while (FALSE);
|
|
}
|
|
|
|
if (err.Failed())
|
|
{
|
|
DisplayError(err);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::EnumerateVDirs(
|
|
HSCOPEITEM hParent, CIISService * pService, BOOL bDisplayError)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Enumerate scope child items.
|
|
|
|
Arguments:
|
|
HSCOPEITEM hParent : Parent console handle
|
|
CIISService * pService : Service type
|
|
|
|
--*/
|
|
{
|
|
ASSERT_PTR(pService);
|
|
|
|
CError err;
|
|
CString strVRoot;
|
|
CIISDirectory * pDir;
|
|
|
|
if (pService->QueryMajorVersion() < 6)
|
|
{
|
|
CMetaEnumerator * pme = NULL;
|
|
err = CreateEnumerator(pme);
|
|
while (err.Succeeded())
|
|
{
|
|
err = pme->Next(strVRoot);
|
|
if (err.Succeeded())
|
|
{
|
|
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;
|
|
}
|
|
pDir->AddRef();
|
|
err = pDir->AddToScopePane(hParent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SAFE_DELETE(pme);
|
|
if (err.Win32Error() == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
err.Reset();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
CComBSTR bstrPath;
|
|
err = BuildMetaPath(bstrPath);
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
|
|
err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrPath);
|
|
if (!IsLostInterface(err))
|
|
{
|
|
// reset error if an other error other than No interface
|
|
err.Reset();
|
|
}
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
|
|
CMetaKey mk(QueryInterface(), bstrPath, METADATA_PERMISSION_READ);
|
|
err = mk.QueryResult();
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
|
|
CStringListEx list;
|
|
err = mk.GetChildPaths(list);
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
|
|
CString key_type;
|
|
BOOL bPossbileVDir = FALSE;
|
|
POSITION pos = list.GetHeadPosition();
|
|
while (err.Succeeded() && pos != NULL)
|
|
{
|
|
strVRoot = list.GetNext(pos);
|
|
err = mk.QueryValue(MD_KEY_TYPE, key_type, NULL, strVRoot);
|
|
|
|
bPossbileVDir = FALSE;
|
|
if (err.Succeeded())
|
|
{
|
|
if (key_type.CompareNoCase(_T(IIS_CLASS_WEB_VDIR)) == 0 || key_type.CompareNoCase(_T(IIS_CLASS_FTP_VDIR)) == 0)
|
|
{
|
|
bPossbileVDir = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (err == (HRESULT)MD_ERROR_DATA_NOT_FOUND)
|
|
{
|
|
// there is no KeyType
|
|
// for backward compatibility reasons -- this could be a VDir!
|
|
bPossbileVDir = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bPossbileVDir)
|
|
{
|
|
CChildNodeProps child(&mk, 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())
|
|
{
|
|
pDir = new CIISDirectory(
|
|
m_pOwner,
|
|
pService,
|
|
strVRoot,
|
|
child.IsEnabledApplication(),
|
|
child.QueryWin32Error(),
|
|
child.GetRedirectedPath()
|
|
);
|
|
|
|
if (!pDir)
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
pDir->AddRef();
|
|
err = pDir->AddToScopePane(hParent);
|
|
}
|
|
}
|
|
}
|
|
if (err == (HRESULT)MD_ERROR_DATA_NOT_FOUND)
|
|
{
|
|
err.Reset();
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
if (err.Failed() && bDisplayError)
|
|
{
|
|
DisplayError(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();
|
|
CError err;
|
|
|
|
ASSERT(pInterface != NULL);
|
|
if (pInterface)
|
|
{
|
|
CMetaKey mk(pInterface);
|
|
err = mk.QueryValue(
|
|
MD_VR_PATH,
|
|
physicalPath,
|
|
&fInherit,
|
|
metaPath
|
|
);
|
|
if (err.Succeeded())
|
|
{
|
|
physicalPath.TrimRight();
|
|
physicalPath.TrimLeft();
|
|
}
|
|
}
|
|
|
|
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())
|
|
{
|
|
// Check if physicalPath is \\.\ (device type)
|
|
// PathAppend will hose on this and get rid of the \\.\ part
|
|
// example: before \\.\c:\temp, after \\c:\temp
|
|
// obviously this is bad if there are Device path's in there
|
|
if (IsDevicePath(physicalPath))
|
|
{
|
|
CString csTemp;
|
|
csTemp = physicalPath;
|
|
physicalPath = AppendToDevicePath(csTemp, alias);
|
|
}
|
|
else
|
|
{
|
|
PathAppend(physicalPath.GetBuffer(MAX_PATH), alias);
|
|
physicalPath.ReleaseBuffer();
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::CleanResult(IResultData * lpResultData)
|
|
{
|
|
CError err;
|
|
|
|
POSITION pos = m_ResultViewList.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
POSITION pos_current = pos;
|
|
ResultViewEntry e = m_ResultViewList.GetNext(pos);
|
|
if (e._ResultData == (DWORD_PTR)lpResultData)
|
|
{
|
|
if (!e._ResultItems->IsEmpty())
|
|
{
|
|
// We should do this MMC cleaning before we delete our data
|
|
err = lpResultData->DeleteAllRsltItems();
|
|
POSITION p = e._ResultItems->GetHeadPosition();
|
|
while (p != NULL)
|
|
{
|
|
CIISFileName * pNode = e._ResultItems->GetNext(p);
|
|
// err = lpResultData->DeleteItem(pNode->m_hResultItem, 0);
|
|
if (err.Failed())
|
|
{
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
pNode->Release();
|
|
}
|
|
e._ResultItems->RemoveAll();
|
|
}
|
|
delete e._ResultItems;
|
|
// pos was updated above in GetNext
|
|
m_ResultViewList.RemoveAt(pos_current);
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::EnumerateResultPane_(
|
|
BOOL fExpand,
|
|
IHeaderCtrl * lpHeader,
|
|
IResultData * lpResultData,
|
|
CIISService * pService
|
|
)
|
|
{
|
|
CError err;
|
|
CIISMachine * pMachine = (CIISMachine *) GetMachineObject();
|
|
WIN32_FIND_DATA w32data;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
|
|
CString dir;
|
|
CComBSTR root;
|
|
CString physPath, alias, csPathMunged;
|
|
|
|
if (m_fFlaggedForDeletion)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if (!HasFileSystemFiles())
|
|
{
|
|
goto EnumerateResultPane__Exit;
|
|
|
|
}
|
|
|
|
if (!fExpand)
|
|
{
|
|
err = CleanResult(lpResultData);
|
|
goto EnumerateResultPane__Exit;
|
|
}
|
|
|
|
BuildMetaPath(root);
|
|
err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,root);
|
|
if (!IsLostInterface(err))
|
|
{
|
|
// reset error if an other error other than No interface
|
|
err.Reset();
|
|
}
|
|
if (err.Failed())
|
|
{
|
|
goto EnumerateResultPane__Exit;
|
|
}
|
|
|
|
GetPhysicalPath(CString(root), alias, physPath);
|
|
|
|
// -------------------------------------------------------------
|
|
// Before we do anything we need to see if it's a "special" path
|
|
//
|
|
// Everything after this function must validate against csPathMunged...
|
|
// this is because IsSpecialPath could have munged it...
|
|
// -------------------------------------------------------------
|
|
csPathMunged = physPath;
|
|
#ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS
|
|
GetSpecialPathRealPath(0,physPath,csPathMunged);
|
|
#endif
|
|
|
|
// Prepare for target machine metabase lookup
|
|
BOOL fCheckMetabase = FALSE;
|
|
if (PathIsUNC(csPathMunged))
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
|
|
if (IsDevicePath(csPathMunged))
|
|
{
|
|
// check if the device path
|
|
// points to an actual dir/file
|
|
// if it does then enumerate it.
|
|
if (IsSpecialPath(csPathMunged,TRUE,TRUE))
|
|
{
|
|
// Remunge this one more time!
|
|
CString csBefore;
|
|
csBefore = csPathMunged;
|
|
GetSpecialPathRealPath(1,csBefore,csPathMunged);
|
|
}
|
|
else
|
|
{
|
|
return err;
|
|
}
|
|
}
|
|
|
|
// WARNING:physPath could be empty!
|
|
csPathMunged.TrimLeft();
|
|
csPathMunged.TrimRight();
|
|
if (csPathMunged.IsEmpty()){goto EnumerateResultPane__Exit;}
|
|
|
|
if (pService->IsLocal() || PathIsUNC(csPathMunged))
|
|
{
|
|
dir = csPathMunged;
|
|
}
|
|
else
|
|
{
|
|
::MakeUNCPath(dir, pService->QueryMachineName(), csPathMunged);
|
|
}
|
|
|
|
dir.TrimLeft();
|
|
dir.TrimRight();
|
|
if (dir.IsEmpty()){goto EnumerateResultPane__Exit;}
|
|
|
|
if (PathIsUNC(dir))
|
|
{
|
|
CString server, user, password;
|
|
|
|
CString MyTestDir;
|
|
MyTestDir = dir;
|
|
MyTestDir += _T("\\*");
|
|
|
|
// we are trying to get the servername portion
|
|
// PathFindNextComponent should return something like "servername\mydir\myfile.txt"
|
|
// trim off everything after the 1st slash
|
|
server = PathFindNextComponent(dir);
|
|
int n = server.Find(_T('\\'));
|
|
if (n != -1)
|
|
{
|
|
server = server.Left(n);
|
|
}
|
|
user = QueryInterface()->QueryAuthInfo()->QueryUserName();
|
|
password = QueryInterface()->QueryAuthInfo()->QueryPassword();
|
|
|
|
// we need to compare the servername that we want to get to
|
|
// with the servername of the local computer.
|
|
// this way we know if we need to net use to the machine!
|
|
TCHAR szLocalMachineName[MAX_PATH + 1];
|
|
DWORD dwSize = MAX_PATH;
|
|
if (0 == ::GetComputerName(szLocalMachineName, &dwSize))
|
|
{
|
|
err.GetLastWinError();
|
|
goto EnumerateResultPane__Exit;
|
|
}
|
|
|
|
//
|
|
// As it turned out in some cases we cannot get access to file system
|
|
// even if we are connected to metabase. We will add connection in this
|
|
// case also.
|
|
//
|
|
if (!pService->IsLocal()
|
|
|| server.CompareNoCase(szLocalMachineName) != 0
|
|
)
|
|
{
|
|
BOOL bEmptyPassword = FALSE;
|
|
// non-local resource, get connection credentials
|
|
if (fCheckMetabase)
|
|
{
|
|
CMetaKey mk(QueryInterface(), root,
|
|
METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE);
|
|
err = mk.QueryResult();
|
|
if (err.Succeeded())
|
|
{
|
|
err = mk.QueryValue(MD_VR_USERNAME, user);
|
|
if (err.Succeeded())
|
|
{
|
|
err = mk.QueryValue(MD_VR_PASSWORD, password);
|
|
bEmptyPassword = (err.Failed() ? TRUE : err.Succeeded() && password.IsEmpty());
|
|
}
|
|
// these credentials could be empty. try defaults
|
|
err.Reset();
|
|
}
|
|
}
|
|
// Add net use for this resource
|
|
NETRESOURCE nr;
|
|
nr.dwType = RESOURCETYPE_DISK;
|
|
nr.lpLocalName = NULL;
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR)dir;
|
|
nr.lpProvider = NULL;
|
|
|
|
CString dir_ipc;
|
|
dir_ipc = _T("\\\\");
|
|
dir_ipc += server;
|
|
dir_ipc += _T("\\ipc$");
|
|
|
|
// Ensure we have a connection to this network file
|
|
// if it already exists, it won't create another one
|
|
// these Connections will be cleaned up in ~CIISMachine or when the machine is disconnected.
|
|
|
|
// 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;
|
|
// In case when password is really was set empty, passing NULL will fail.
|
|
if (password.IsEmpty() && !bEmptyPassword){p1 = NULL;}
|
|
if (user.IsEmpty()){p2 = NULL;}
|
|
|
|
// Check if we have access
|
|
// to the resource without netuse
|
|
BOOL bNeedToNetUse = FALSE;
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(MyTestDir, &w32data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// successfull access
|
|
FindClose(hFind);
|
|
}
|
|
else
|
|
{
|
|
// if we failed then we probably need to
|
|
// net use to this resource!
|
|
bNeedToNetUse = TRUE;
|
|
}
|
|
|
|
// --------------------
|
|
// Ensure we have a connection to this network file
|
|
// if it already exists, it won't create another one
|
|
// these Connections will be cleaned up in ~CIISMachine or when the machine is disconnected.
|
|
// --------------------
|
|
if (pMachine && bNeedToNetUse)
|
|
{
|
|
// try to setup a "net use \\computername\$ipc" connection
|
|
// that everyone can use
|
|
// set the share name to
|
|
// \\machine\IPC$
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir_ipc;
|
|
//ERROR_LOGON_FAILURE
|
|
DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
if (NO_ERROR == dwRet)
|
|
{
|
|
bNeedToNetUse = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet)
|
|
{
|
|
pMachine->m_MachineWNetConnections.Disconnect(dir_ipc);
|
|
dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if we have access after the 1st net use.
|
|
// We are connecting to a remote machine...
|
|
// Check if we have access
|
|
// to the resource without netuse
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(MyTestDir, &w32data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// successfull access
|
|
FindClose(hFind);
|
|
}
|
|
else
|
|
{
|
|
// if we failed then we probably need to
|
|
// net use to this resource!
|
|
bNeedToNetUse = TRUE;
|
|
}
|
|
|
|
if (bNeedToNetUse)
|
|
{
|
|
if (pMachine)
|
|
{
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir;
|
|
|
|
DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
if (NO_ERROR != dwRet)
|
|
{
|
|
if (ERROR_ALREADY_ASSIGNED != dwRet)
|
|
{
|
|
if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet)
|
|
{
|
|
// Errored with already assigned
|
|
// check if we have accesss...
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(MyTestDir, &w32data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// successfull access
|
|
FindClose(hFind);
|
|
}
|
|
else
|
|
{
|
|
// stil don't have access
|
|
// kill the current connection and the ipc$ resource
|
|
pMachine->m_MachineWNetConnections.Disconnect(dir);
|
|
pMachine->m_MachineWNetConnections.Disconnect(dir_ipc);
|
|
|
|
// try to reconnect with the new path...
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir;
|
|
|
|
dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet)
|
|
{
|
|
// Clean all connections to this machine and try again.
|
|
pMachine->m_MachineWNetConnections.Clear();
|
|
dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = dwRet;
|
|
goto EnumerateResultPane__Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (PathIsUNCServerShare(dir))
|
|
{
|
|
if (FALSE == DoesUNCShareExist(dir))
|
|
{
|
|
err = ERROR_BAD_NETPATH;
|
|
goto EnumerateResultPane__Exit;
|
|
}
|
|
}
|
|
|
|
dir += _T("\\*");
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(dir, &w32data);
|
|
// Bug:756402, revert previous change. we need to display if hidden or system.
|
|
const DWORD attr_skip = FILE_ATTRIBUTE_DIRECTORY; // | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
err.GetLastWinError();
|
|
goto EnumerateResultPane__Exit;
|
|
}
|
|
|
|
ResultItemsList * pResList = AddResultItems(lpResultData);
|
|
do
|
|
{
|
|
LPCTSTR name = w32data.cFileName;
|
|
if ((w32data.dwFileAttributes & attr_skip) == 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;
|
|
pNode->AddRef();
|
|
err = lpResultData->InsertItem(&ri);
|
|
if (err.Succeeded())
|
|
{
|
|
pNode->SetScopeItem(m_hScopeItem);
|
|
pNode->SetResultItem(ri.itemID);
|
|
pResList->AddTail(pNode);
|
|
}
|
|
else
|
|
{
|
|
pNode->Release();
|
|
}
|
|
|
|
// commenting out this refreshdata
|
|
// this is waaay too much of a performance hit
|
|
// and slows down everything drastically.
|
|
//pNode->RefreshData();
|
|
}
|
|
} while (err.Succeeded() && FindNextFile(hFind, &w32data));
|
|
FindClose(hFind);
|
|
|
|
EnumerateResultPane__Exit:
|
|
return err;
|
|
}
|
|
|
|
ResultItemsList *
|
|
CIISMBNode::AddResultItems(IResultData * pResultData)
|
|
{
|
|
ResultViewEntry e;
|
|
e._ResultData = (DWORD_PTR)pResultData;
|
|
e._ResultItems = new ResultItemsList;
|
|
m_ResultViewList.AddTail(e);
|
|
POSITION pos = m_ResultViewList.GetTailPosition();
|
|
return m_ResultViewList.GetAt(pos)._ResultItems;
|
|
}
|
|
|
|
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;
|
|
CIISMachine * pMachine = (CIISMachine *) GetMachineObject();
|
|
WIN32_FIND_DATA w32data;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
|
|
CString dir;
|
|
CComBSTR root;
|
|
BuildMetaPath(root);
|
|
CString physPath, alias, csPathMunged;
|
|
|
|
GetPhysicalPath(CString(root), alias, physPath);
|
|
|
|
// -------------------------------------------------------------
|
|
// Before we do anything we need to see if it's a "special" path
|
|
//
|
|
// Everything after this function must validate against csPathMunged...
|
|
// this is because IsSpecialPath could have munged it...
|
|
// -------------------------------------------------------------
|
|
csPathMunged = physPath;
|
|
#ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS
|
|
GetSpecialPathRealPath(0,physPath,csPathMunged);
|
|
#endif
|
|
|
|
// 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();
|
|
}
|
|
|
|
if (IsDevicePath(csPathMunged))
|
|
{
|
|
// check if the device path
|
|
// points to an actual dir/file
|
|
// if it does then enumerate it.
|
|
if (IsSpecialPath(csPathMunged,TRUE,TRUE))
|
|
{
|
|
// Remunge this one more time!
|
|
CString csBefore;
|
|
csBefore = csPathMunged;
|
|
GetSpecialPathRealPath(1,csBefore,csPathMunged);
|
|
}
|
|
else
|
|
{
|
|
goto EnumerateWebDirs_Exit;
|
|
}
|
|
}
|
|
|
|
// WARNING:physPath could be empty!
|
|
csPathMunged.TrimLeft();
|
|
csPathMunged.TrimRight();
|
|
if (csPathMunged.IsEmpty()){goto EnumerateWebDirs_Exit;}
|
|
|
|
if (pService->IsLocal() || PathIsUNC(csPathMunged))
|
|
{
|
|
dir = csPathMunged;
|
|
}
|
|
else
|
|
{
|
|
::MakeUNCPath(dir, pService->QueryMachineName(), csPathMunged);
|
|
}
|
|
|
|
dir.TrimLeft();
|
|
dir.TrimRight();
|
|
if (dir.IsEmpty()){goto EnumerateWebDirs_Exit;}
|
|
|
|
// ------------------------------
|
|
// Check if we need to "net use"
|
|
// to the file resource on a remote machine
|
|
// so we can enum it...
|
|
// ------------------------------
|
|
if (PathIsUNC(dir))
|
|
{
|
|
CString server, user, password;
|
|
|
|
CString MyTestDir;
|
|
MyTestDir = dir;
|
|
MyTestDir += _T("\\*");
|
|
|
|
// we are trying to get the servername portion
|
|
// PathFindNextComponent should return something like "servername\mydir\myfile.txt"
|
|
// trim off everything after the 1st slash
|
|
server = PathFindNextComponent(dir);
|
|
int n = server.Find(_T('\\'));
|
|
if (n != -1)
|
|
{server = server.Left(n);}
|
|
user = QueryInterface()->QueryAuthInfo()->QueryUserName();
|
|
password = QueryInterface()->QueryAuthInfo()->QueryPassword();
|
|
|
|
// we need to compare the servername that we want to get to
|
|
// with the servername of the local computer.
|
|
// this way we know if we need to net use to the machine!
|
|
TCHAR szLocalMachineName[MAX_PATH + 1];
|
|
DWORD dwSize = MAX_PATH;
|
|
if (0 == ::GetComputerName(szLocalMachineName, &dwSize))
|
|
{
|
|
err.GetLastWinError();
|
|
goto EnumerateWebDirs_Exit;
|
|
}
|
|
|
|
// Check to see if the localmachine is different that the
|
|
// machine we want to connect to to enum it's files upon...
|
|
if (!pService->IsLocal()
|
|
|| server.CompareNoCase(szLocalMachineName) != 0
|
|
)
|
|
{
|
|
// We are connecting to a path which is different from the computer name!
|
|
BOOL bEmptyPassword = FALSE;
|
|
|
|
// non-local resource, get connection credentials
|
|
if (fCheckMetabase && PathIsUNC(csPathMunged))
|
|
{
|
|
err = mk.QueryValue(MD_VR_USERNAME, user);
|
|
if (err.Succeeded())
|
|
{
|
|
err = mk.QueryValue(MD_VR_PASSWORD, password);
|
|
bEmptyPassword = (err.Failed() ? TRUE : err.Succeeded() && password.IsEmpty());
|
|
}
|
|
// 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;
|
|
|
|
CString dir_ipc;
|
|
dir_ipc = _T("\\\\");
|
|
dir_ipc += server;
|
|
dir_ipc += _T("\\ipc$");
|
|
|
|
// 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;
|
|
// In case when password is really was set empty, passing NULL will fail.
|
|
if (password.IsEmpty() && !bEmptyPassword){p1 = NULL;}
|
|
if (user.IsEmpty()){p2 = NULL;}
|
|
|
|
// Check if we have access
|
|
// to the resource without netuse
|
|
BOOL bNeedToNetUse = FALSE;
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(MyTestDir, &w32data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// successfull access
|
|
FindClose(hFind);
|
|
}
|
|
else
|
|
{
|
|
// if we failed then we probably need to
|
|
// net use to this resource!
|
|
bNeedToNetUse = TRUE;
|
|
}
|
|
|
|
// --------------------
|
|
// Ensure we have a connection to this network file
|
|
// if it already exists, it won't create another one
|
|
// these Connections will be cleaned up in ~CIISMachine or when the machine is disconnected.
|
|
// --------------------
|
|
if (pMachine && bNeedToNetUse)
|
|
{
|
|
// try to setup a "net use \\computername\$ipc" connection
|
|
// that everyone can use
|
|
// set the share name to
|
|
// \\machine\IPC$
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir_ipc;
|
|
DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
if (NO_ERROR == dwRet)
|
|
{
|
|
bNeedToNetUse = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet)
|
|
{
|
|
pMachine->m_MachineWNetConnections.Disconnect(dir_ipc);
|
|
dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if we have access after the 1st net use.
|
|
// We are connecting to a remote machine...
|
|
// Check if we have access
|
|
// to the resource without netuse
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(MyTestDir, &w32data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// successfull access
|
|
FindClose(hFind);
|
|
}
|
|
else
|
|
{
|
|
// if we failed then we probably need to
|
|
// net use to this resource!
|
|
bNeedToNetUse = TRUE;
|
|
}
|
|
|
|
if (bNeedToNetUse)
|
|
{
|
|
if (pMachine)
|
|
{
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir;
|
|
|
|
DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
if (NO_ERROR != dwRet)
|
|
{
|
|
if (ERROR_ALREADY_ASSIGNED != dwRet)
|
|
{
|
|
if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet)
|
|
{
|
|
// Errored with already assigned
|
|
// check if we have accesss...
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(MyTestDir, &w32data);
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// successfull access
|
|
FindClose(hFind);
|
|
}
|
|
else
|
|
{
|
|
// stil don't have access
|
|
// kill the current connection and the ipc$ resource
|
|
pMachine->m_MachineWNetConnections.Disconnect(dir);
|
|
pMachine->m_MachineWNetConnections.Disconnect(dir_ipc);
|
|
|
|
// try to reconnect with the new path...
|
|
nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir;
|
|
|
|
dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet)
|
|
{
|
|
// Clean all connections to this machine and try again.
|
|
pMachine->m_MachineWNetConnections.Clear();
|
|
dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0);
|
|
}
|
|
else
|
|
{
|
|
if (NO_ERROR != dwRet)
|
|
{
|
|
// Final failure, what now?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = dwRet;
|
|
goto EnumerateWebDirs_Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// -----------------------------------
|
|
// Enum thru the Physical file path...
|
|
// -----------------------------------
|
|
dir += _T("\\*");
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
hFind = ::FindFirstFile(dir, &w32data);
|
|
// Bug:756402, revert previous change. we need to display if hidden or system.
|
|
// const DWORD attr_skip = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
err.GetLastWinError();
|
|
goto EnumerateWebDirs_Exit;
|
|
}
|
|
do
|
|
{
|
|
LPCTSTR name = w32data.cFileName;
|
|
if ( (w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
|
|
// Bug:756402, revert previous change. we need to display if hidden or system.
|
|
// && (w32data.dwFileAttributes & attr_skip) == 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;
|
|
goto EnumerateWebDirs_Exit;
|
|
}
|
|
|
|
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);
|
|
pNode->Release();
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
pNode->AddRef();
|
|
err = pNode->AddToScopePane(hParent);
|
|
}
|
|
} while (err.Succeeded() && FindNextFile(hFind, &w32data));
|
|
FindClose(hFind);
|
|
|
|
EnumerateWebDirs_Exit:
|
|
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;
|
|
|
|
err = RefreshData();
|
|
if (err.Succeeded())
|
|
{
|
|
if (fReEnumerate)
|
|
{
|
|
//
|
|
// Kill child objects
|
|
//
|
|
TRACEEOLID("Killing child objects");
|
|
|
|
ASSERT(m_hScopeItem != NULL);
|
|
if (m_hScopeItem != NULL)
|
|
{
|
|
err = RemoveChildren(m_hScopeItem);
|
|
if (err.Succeeded())
|
|
{
|
|
err = EnumerateScopePane(m_hScopeItem);
|
|
}
|
|
}
|
|
}
|
|
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(
|
|
LPCTSTR lpszCommand,
|
|
LPCTSTR lpszOwner,
|
|
LPCTSTR lpszDirectory,
|
|
HWND hWnd
|
|
)
|
|
/*++
|
|
|
|
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();
|
|
if (err.Win32Error() == ERROR_NO_ASSOCIATION)
|
|
{
|
|
// Open shell OpenAs dialog
|
|
SHELLEXECUTEINFO ei = {0};
|
|
ei.cbSize = sizeof(ei);
|
|
ei.fMask = SEE_MASK_NOQUERYCLASSSTORE;
|
|
RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("Unknown"), 0, MAXIMUM_ALLOWED, &ei.hkeyClass);
|
|
if (ei.hkeyClass != NULL)
|
|
{
|
|
ei.fMask |= SEE_MASK_NOQUERYCLASSSTORE;
|
|
}
|
|
ei.lpFile = strDir;
|
|
ei.nShow = SW_SHOW;
|
|
ei.lpVerb = _T("openas");
|
|
ei.hwnd = hWnd;
|
|
|
|
err = ShellExecuteEx(&ei);
|
|
if (ei.hkeyClass != NULL)
|
|
{
|
|
RegCloseKey(ei.hkeyClass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
HRESULT
|
|
CIISMBNode::CreatePropertyPages(
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LONG_PTR handle,
|
|
IUnknown * pUnk,
|
|
DATA_OBJECT_TYPES type
|
|
)
|
|
{
|
|
CError err = CIISObject::CreatePropertyPages(lpProvider, handle, pUnk, type);
|
|
if (err == S_FALSE)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Set this objects Tag to compare with something already opened
|
|
CreateTag();
|
|
|
|
CIISObject * pAlreadyOpenProp = NULL;
|
|
if (TRUE == g_OpenPropertySheetTracker.FindAlreadyOpenPropertySheet(this,&pAlreadyOpenProp))
|
|
{
|
|
// Bring it to the foreground, and bail
|
|
HWND hHwnd = 0;
|
|
if (pAlreadyOpenProp)
|
|
{
|
|
if (hHwnd = pAlreadyOpenProp->IsMyPropertySheetOpen())
|
|
{
|
|
if (hHwnd && (hHwnd != (HWND) 1))
|
|
{
|
|
// Perhapse we should cancel the already
|
|
// opened property sheet...just a thought
|
|
if (!SetForegroundWindow(hHwnd))
|
|
{
|
|
// wasn't able to bring this property sheet to
|
|
// the foreground, the propertysheet must not
|
|
// exist anymore. let's just clean the hwnd
|
|
// so that the user will be able to open propertysheet
|
|
pAlreadyOpenProp->SetMyPropertySheetOpen(0);
|
|
}
|
|
else
|
|
{
|
|
return ERROR_ALREADY_EXISTS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if we are still connected
|
|
if (!GetOwner()->IsLocal())
|
|
{
|
|
|
|
// Problem here could be that lpszOwner is not a computername but rather
|
|
// an IP Address!!!!
|
|
LPCTSTR lpszServer = PURE_COMPUTER_NAME(GetOwner()->QueryServerName());
|
|
if (LooksLikeIPAddress(lpszServer))
|
|
{
|
|
//
|
|
// Get by ip address
|
|
//
|
|
CString strTemp;
|
|
CIPAddress ia(lpszServer);
|
|
if (NOERROR != MyGetHostName((DWORD)ia, strTemp))
|
|
{
|
|
// network is down!!!
|
|
err = ERROR_NO_NETWORK;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
// WARNING:QueryInterface() Can return NULL
|
|
// and if the CMetakey is created with a NULL
|
|
// pointer, it will AV.
|
|
if (!GetOwner()->QueryInterface())
|
|
{
|
|
return RPC_S_SERVER_UNAVAILABLE;
|
|
}
|
|
CMetaKey mk(GetOwner()->QueryInterface());
|
|
err = mk.QueryResult();
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
CComBSTR path;
|
|
err = BuildMetaPath(path);
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
CString buf = path;
|
|
while (FAILED(mk.DoesPathExist(buf)))
|
|
{
|
|
// Goto parent
|
|
if (NULL == CMetabasePath::ConvertToParentPath(buf))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
err = mk.Open(
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
|
|
buf
|
|
);
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
//
|
|
// Write some nonsense
|
|
//
|
|
DWORD dwDummy = 0x1234;
|
|
err = mk.SetValue(MD_ISM_ACCESS_CHECK, dwDummy);
|
|
BREAK_ON_ERR_FAILURE(err);
|
|
//
|
|
// And delete it again
|
|
//
|
|
err = mk.DeleteValue(MD_ISM_ACCESS_CHECK);
|
|
} while (FALSE);
|
|
}
|
|
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;
|
|
CComBSTR bstrMetaPath;
|
|
BOOL bNeedMetabase = FALSE;
|
|
BOOL bHaveMetabase = FALSE;
|
|
|
|
switch (lCommandID)
|
|
{
|
|
case IDM_BROWSE:
|
|
case IDM_OPEN:
|
|
case IDM_PERMISSION:
|
|
case IDM_EXPLORE:
|
|
case IDM_NEW_FTP_SITE_FROM_FILE:
|
|
case IDM_NEW_FTP_VDIR_FROM_FILE:
|
|
case IDM_NEW_WEB_SITE_FROM_FILE:
|
|
case IDM_NEW_WEB_VDIR_FROM_FILE:
|
|
case IDM_NEW_APP_POOL_FROM_FILE:
|
|
case IDM_TASK_EXPORT_CONFIG_WIZARD:
|
|
bNeedMetabase = TRUE;
|
|
break;
|
|
default:
|
|
bNeedMetabase = FALSE;
|
|
}
|
|
|
|
if (bNeedMetabase)
|
|
{
|
|
// WARNING:bstrMetaPath will be used by switch statement below
|
|
VERIFY(SUCCEEDED(BuildMetaPath(bstrMetaPath)));
|
|
err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath);
|
|
if (!IsLostInterface(err))
|
|
{
|
|
// reset error if an other error other than No interface
|
|
err.Reset();
|
|
}
|
|
if (err.Succeeded())
|
|
{
|
|
bHaveMetabase = TRUE;
|
|
}
|
|
}
|
|
|
|
switch (lCommandID)
|
|
{
|
|
|
|
case IDM_BROWSE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
//
|
|
// 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:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CString phys_path, alias;
|
|
if (GetPhysicalPath(bstrMetaPath, alias, phys_path))
|
|
{
|
|
hr = ShellExecuteDirectory(_T("open"), QueryMachineName(), phys_path, GetMainWindow(GetConsole())->m_hWnd);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_PERMISSION:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CString phys_path, alias, csPathMunged;
|
|
if (GetPhysicalPath(bstrMetaPath, alias, phys_path))
|
|
{
|
|
// -------------------------------------------------------------
|
|
// Before we do anything we need to see if it's a "special" path
|
|
//
|
|
// Everything after this function must validate against csPathMunged...
|
|
// this is because IsSpecialPath could have munged it...
|
|
// -------------------------------------------------------------
|
|
csPathMunged = phys_path;
|
|
#ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS
|
|
GetSpecialPathRealPath(0,phys_path,csPathMunged);
|
|
#endif
|
|
if (!IsDevicePath(csPathMunged))
|
|
{
|
|
INT_PTR iReturn = PopupPermissionDialog(
|
|
GetMainWindow(GetConsole())->m_hWnd,
|
|
QueryMachineName(),
|
|
csPathMunged);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_EXPLORE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CString phys_path, alias;
|
|
if (GetPhysicalPath(bstrMetaPath, 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_NEW_FTP_SITE_FROM_FILE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName());
|
|
CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName());
|
|
CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword());
|
|
|
|
if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_FTP_SERVER_W)))
|
|
{
|
|
// check if we need to just refresh this node or the node above us...
|
|
CIISMBNode * pNode = GetParentNode();
|
|
if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cServiceCollectorNode))
|
|
{
|
|
pNode->Refresh(TRUE);
|
|
}
|
|
else
|
|
{
|
|
BOOL bExpand = !IsLeafNode();Refresh(bExpand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_NEW_FTP_VDIR_FROM_FILE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName());
|
|
CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName());
|
|
CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword());
|
|
|
|
if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_FTP_VDIR_W)))
|
|
{
|
|
// check if we need to just refresh this node or the node above us...
|
|
CIISMBNode * pNode = GetParentNode();
|
|
if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cInstanceNode))
|
|
{
|
|
pNode->Refresh(TRUE);
|
|
}
|
|
else
|
|
{
|
|
BOOL bExpand = !IsLeafNode();Refresh(bExpand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_NEW_WEB_SITE_FROM_FILE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName());
|
|
CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName());
|
|
CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword());
|
|
|
|
if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_WEB_SERVER_W)))
|
|
{
|
|
// check if we need to just refresh this node or the node above us...
|
|
CIISMBNode * pNode = GetParentNode();
|
|
if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cServiceCollectorNode))
|
|
{
|
|
pNode->Refresh(TRUE);
|
|
}
|
|
else
|
|
{
|
|
BOOL bExpand = !IsLeafNode();Refresh(bExpand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_NEW_WEB_VDIR_FROM_FILE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName());
|
|
CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName());
|
|
CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword());
|
|
|
|
if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_WEB_VDIR_W)))
|
|
{
|
|
// check if we need to just refresh this node or the node above us...
|
|
CIISMBNode * pNode = GetParentNode();
|
|
if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cInstanceNode))
|
|
{
|
|
pNode->Refresh(TRUE);
|
|
}
|
|
else
|
|
{
|
|
BOOL bExpand = !IsLeafNode();Refresh(bExpand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_NEW_APP_POOL_FROM_FILE:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName());
|
|
CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName());
|
|
CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword());
|
|
|
|
if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,L"IIsApplicationPool")))
|
|
{
|
|
// check if we need to just refresh this node or the node above us...
|
|
CIISMBNode * pNode = GetParentNode();
|
|
if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cAppPoolsNode))
|
|
{
|
|
pNode->Refresh(TRUE);
|
|
}
|
|
else
|
|
{
|
|
BOOL bExpand = !IsLeafNode();Refresh(bExpand);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_TASK_EXPORT_CONFIG_WIZARD:
|
|
{
|
|
if (bHaveMetabase)
|
|
{
|
|
CString strNewPath, strRemainder;
|
|
CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName());
|
|
CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName());
|
|
CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword());
|
|
|
|
// Is this the root??
|
|
LPCTSTR lpPath = CMetabasePath::GetRootPath(bstrMetaPath, strNewPath, &strRemainder);
|
|
if (lpPath && (0 == _tcsicmp(lpPath,bstrMetaPath)))
|
|
{
|
|
CString strNewMetaPath;
|
|
//
|
|
// Get the instance properties
|
|
//
|
|
CMetabasePath::GetInstancePath(bstrMetaPath,strNewMetaPath);
|
|
CComBSTR bstrNewMetaPath((LPCTSTR) strNewMetaPath);
|
|
|
|
// if empty or if this is an app pool...
|
|
if (IsEqualGUID(* (GUID *) GetNodeType(),cAppPoolNode))
|
|
{
|
|
hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath);
|
|
}
|
|
else
|
|
{
|
|
if (strNewMetaPath.IsEmpty())
|
|
{
|
|
hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath);
|
|
}
|
|
else
|
|
{
|
|
hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrNewMetaPath);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Pass on to base class
|
|
//
|
|
default:
|
|
{
|
|
hr = CIISObject::Command(lCommandID, pObj, type);
|
|
}
|
|
|
|
} // end switch
|
|
|
|
return hr;
|
|
}
|
|
|
|
#if 0
|
|
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;
|
|
}
|
|
#endif
|
|
|
|
HRESULT
|
|
CIISMBNode::OnViewChange(BOOL fScope, IResultData * pResult, IHeaderCtrl * pHeader, DWORD hint)
|
|
{
|
|
CError err;
|
|
BOOL bReenumResult = 0 != (hint & PROP_CHANGE_REENUM_FILES);
|
|
BOOL bReenumScope =
|
|
0 != (hint & PROP_CHANGE_REENUM_VDIR) || 0 != (hint & PROP_CHANGE_REENUM_FILES);
|
|
|
|
if (QueryScopeItem() || QueryResultItem())
|
|
{
|
|
BOOL bExpand = fScope
|
|
&& !IsLeafNode()
|
|
&& bReenumScope
|
|
// && IsExpanded()
|
|
;
|
|
|
|
BOOL bHasResult = HasResultItems(pResult);
|
|
if (bHasResult && bReenumResult)
|
|
{
|
|
// Remove files that could be in result pane
|
|
err = CleanResult(pResult);
|
|
}
|
|
|
|
// after error this node could be not expanded, we should expand it anyway
|
|
err = Refresh(bExpand);
|
|
if (err.Succeeded())
|
|
{
|
|
if (fScope && HasFileSystemFiles() && bReenumResult && bHasResult)
|
|
{
|
|
err = EnumerateResultPane(TRUE, pHeader, pResult);
|
|
}
|
|
else if (!fScope && (bReenumResult || 0 != (hint & PROP_CHANGE_DISPLAY_ONLY)))
|
|
{
|
|
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())
|
|
{
|
|
POSITION pos = m_ResultViewList.GetHeadPosition();
|
|
while (pos != NULL)
|
|
{
|
|
ResultViewEntry e = m_ResultViewList.GetNext(pos);
|
|
if (e._ResultData == (DWORD_PTR)pResult)
|
|
{
|
|
BOOL found = FALSE;
|
|
POSITION p = e._ResultItems->GetHeadPosition();
|
|
POSITION pcur;
|
|
while (p != NULL)
|
|
{
|
|
pcur = p;
|
|
if (e._ResultItems->GetNext(p) == pNode)
|
|
{
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
e._ResultItems->RemoveAt(pcur);
|
|
pNode->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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
|