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.
826 lines
21 KiB
826 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Importer.cpp
|
|
|
|
Abstract:
|
|
|
|
IIS MetaBase subroutines to support Import
|
|
|
|
Author:
|
|
|
|
Mohit Srivastava 04-April-01
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
const WCHAR CImporter::sm_wszInheritedPropertiesLocationPrefix[] = L"inherited:";
|
|
const ULONG CImporter::sm_cchInheritedPropertiesLocationPrefix =
|
|
sizeof(sm_wszInheritedPropertiesLocationPrefix)/sizeof(WCHAR) - 1;
|
|
|
|
//
|
|
// public
|
|
//
|
|
|
|
CImporter::CImporter(
|
|
LPCWSTR i_wszFileName,
|
|
LPCSTR i_pszPassword)
|
|
{
|
|
m_bInitCalled = false;
|
|
|
|
m_wszFileName = i_wszFileName;
|
|
m_pszPassword = i_pszPassword;
|
|
}
|
|
|
|
CImporter::~CImporter()
|
|
{
|
|
}
|
|
|
|
HRESULT CImporter::Init()
|
|
{
|
|
MD_ASSERT(m_bInitCalled == false);
|
|
m_bInitCalled = true;
|
|
return InitIST();
|
|
}
|
|
|
|
HRESULT CImporter::ShowPathsInFile(
|
|
LPCWSTR pszKeyType,
|
|
DWORD dwMDBufferSize,
|
|
LPWSTR pszBuffer,
|
|
DWORD* pdwMDRequiredBufferSize)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// All of the stuff is read into pISTProperty.
|
|
// Now loop through and populate in-memory cache.
|
|
// Properties are sorted by location.
|
|
//
|
|
ULONG acbMBPropertyRow[cMBProperty_NumberOfColumns];
|
|
tMBPropertyRow MBPropertyRow;
|
|
DWORD dwPreviousLocationID = (DWORD)-1;
|
|
DWORD bufLoc = 0;
|
|
DWORD dSize = 0;
|
|
|
|
for(ULONG i=0; ;i++)
|
|
{
|
|
hr = m_spISTProperty->GetColumnValues(
|
|
i,
|
|
cMBProperty_NumberOfColumns,
|
|
0,
|
|
acbMBPropertyRow,
|
|
(LPVOID*)&MBPropertyRow);
|
|
if(E_ST_NOMOREROWS == hr)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
else if(FAILED(hr))
|
|
{
|
|
DBGINFO((DBG_CONTEXT,
|
|
"[ReadSomeDataFromXML] GetColumnValues failed with hr = 0x%x. Table:%ws. Read row index:%d.\n", \
|
|
hr, wszTABLE_MBProperty, i));
|
|
return hr;
|
|
}
|
|
|
|
bool bNewLocation = false;
|
|
if(dwPreviousLocationID != *MBPropertyRow.pLocationID)
|
|
{
|
|
dwPreviousLocationID = *MBPropertyRow.pLocationID;
|
|
bNewLocation = true;
|
|
}
|
|
|
|
if(*MBPropertyRow.pID == MD_KEY_TYPE ||
|
|
*MBPropertyRow.pID == MD_SERVER_COMMENT)
|
|
{
|
|
if (!wcscmp((LPCWSTR)MBPropertyRow.pValue, pszKeyType))
|
|
{
|
|
// MBPropertyRow.pLocation
|
|
dSize = (DWORD)wcslen(MBPropertyRow.pLocation);
|
|
if (bufLoc + dSize < dwMDBufferSize - 1)
|
|
{
|
|
wcscpy(&(pszBuffer[bufLoc]), MBPropertyRow.pLocation);
|
|
pszBuffer[bufLoc + dSize] = 0;
|
|
}
|
|
bufLoc += dSize+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bufLoc < dwMDBufferSize)
|
|
{
|
|
pszBuffer[bufLoc] = 0;
|
|
}
|
|
else
|
|
{
|
|
pszBuffer[dwMDBufferSize-1] = 0;
|
|
pszBuffer[dwMDBufferSize-2] = 0;
|
|
}
|
|
|
|
*pdwMDRequiredBufferSize = bufLoc;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CImporter::DoIt(
|
|
LPWSTR i_wszSourcePath,
|
|
LPCWSTR i_wszKeyType,
|
|
DWORD i_dwMDFlags,
|
|
CMDBaseObject** o_ppboNew)
|
|
/*++
|
|
|
|
Synopsis:
|
|
|
|
Arguments: [i_wszSourcePath] -
|
|
[i_wszKeyType] -
|
|
[i_dwMDFlags] -
|
|
[o_ppboNew] -
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
MD_ASSERT(m_bInitCalled);
|
|
MD_ASSERT(i_wszKeyType);
|
|
MD_ASSERT(o_ppboNew);
|
|
MD_ASSERT(*o_ppboNew == NULL);
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL bSawSourcePath = false;
|
|
LPWSTR pLocation = NULL;
|
|
|
|
//
|
|
// This is a pointer to some node in *o_ppboNew
|
|
// It is the current node we are reading to.
|
|
//
|
|
CMDBaseObject* pboRead = NULL;
|
|
|
|
//
|
|
// Used for decryption
|
|
//
|
|
IIS_CRYPTO_STORAGE* pStorage = NULL;
|
|
|
|
|
|
g_LockMasterResource.ReadLock();
|
|
hr = InitSessionKey(m_spISTProperty, &pStorage, (LPSTR)m_pszPassword);
|
|
g_LockMasterResource.ReadUnlock();
|
|
if(FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Create the parent base object
|
|
//
|
|
*o_ppboNew = new CMDBaseObject(L"Thenamedoesntmatter", NULL);
|
|
if (*o_ppboNew == NULL || !((*o_ppboNew)->IsValid()) )
|
|
{
|
|
hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
delete *o_ppboNew;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// All of the stuff is read into pISTProperty.
|
|
// Now loop through and populate in-memory cache.
|
|
// Properties are sorted by location.
|
|
//
|
|
ULONG acbMBPropertyRow[cMBProperty_NumberOfColumns];
|
|
tMBPropertyRow MBPropertyRow;
|
|
BOOL bSkipLocation = FALSE;
|
|
DWORD dwPreviousLocationID = (DWORD)-1;
|
|
Relation eRelation = eREL_NONE;
|
|
for(ULONG i=0; ;i++)
|
|
{
|
|
BOOL bLocationWithProperty = TRUE;
|
|
BOOL bNewLocation = FALSE;
|
|
|
|
hr = m_spISTProperty->GetColumnValues(
|
|
i,
|
|
cMBProperty_NumberOfColumns,
|
|
0,
|
|
acbMBPropertyRow,
|
|
(LPVOID*)&MBPropertyRow);
|
|
if(E_ST_NOMOREROWS == hr)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
else if(FAILED(hr))
|
|
{
|
|
DBGINFOW((DBG_CONTEXT,
|
|
L"[ReadSomeDataFromXML] GetColumnValues failed with hr = 0x%x. Table:%s. Read row index:%d.\n", \
|
|
hr, wszTABLE_MBProperty, i));
|
|
|
|
goto exit;
|
|
}
|
|
|
|
if(0 == wcscmp(MD_GLOBAL_LOCATIONW, MBPropertyRow.pLocation))
|
|
{
|
|
//
|
|
// Ignore globals.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if((*MBPropertyRow.pID == MD_LOCATION) && (*MBPropertyRow.pName == MD_CH_LOC_NO_PROPERTYW))
|
|
{
|
|
bLocationWithProperty = FALSE;
|
|
}
|
|
if(dwPreviousLocationID != *MBPropertyRow.pLocationID)
|
|
{
|
|
bNewLocation = TRUE;
|
|
bSkipLocation = FALSE;
|
|
dwPreviousLocationID = *MBPropertyRow.pLocationID;
|
|
pboRead = *o_ppboNew;
|
|
pLocation = MBPropertyRow.pLocation;
|
|
|
|
if(*MBPropertyRow.pGroup == eMBProperty_IIsInheritedProperties)
|
|
{
|
|
if(_wcsnicmp(
|
|
pLocation,
|
|
sm_wszInheritedPropertiesLocationPrefix,
|
|
sm_cchInheritedPropertiesLocationPrefix) == 0)
|
|
{
|
|
pLocation += sm_cchInheritedPropertiesLocationPrefix;
|
|
}
|
|
}
|
|
}
|
|
if(bSkipLocation)
|
|
{
|
|
continue;
|
|
}
|
|
#if DBG
|
|
if(bLocationWithProperty == false)
|
|
{
|
|
MD_ASSERT(bNewLocation);
|
|
}
|
|
#endif
|
|
|
|
if(bNewLocation)
|
|
{
|
|
//
|
|
// See if we're at a (grand*)child or self
|
|
//
|
|
eRelation = GetRelation(i_wszSourcePath, pLocation);
|
|
|
|
switch(eRelation)
|
|
{
|
|
case eREL_SELF:
|
|
if(*MBPropertyRow.pGroup != eMBProperty_IIsInheritedProperties)
|
|
{
|
|
bSawSourcePath = true;
|
|
}
|
|
break;
|
|
case eREL_PARENT:
|
|
if(!(i_dwMDFlags & MD_IMPORT_INHERITED))
|
|
{
|
|
bSkipLocation = TRUE;
|
|
continue;
|
|
}
|
|
break;
|
|
case eREL_CHILD:
|
|
if(i_dwMDFlags & MD_IMPORT_NODE_ONLY)
|
|
{
|
|
bSkipLocation = TRUE;
|
|
continue;
|
|
}
|
|
break;
|
|
default: // eRelation == eREL_NONE
|
|
bSkipLocation = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if(*MBPropertyRow.pGroup == eMBProperty_IIsInheritedProperties)
|
|
{
|
|
if(!(i_dwMDFlags & MD_IMPORT_INHERITED))
|
|
{
|
|
bSkipLocation = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Some checks to see whether we skip just the current property, but not
|
|
// necessarily the entire location.
|
|
//
|
|
if(*MBPropertyRow.pGroup == eMBProperty_IIsInheritedProperties)
|
|
{
|
|
if( !(fMBProperty_INHERIT & *MBPropertyRow.pAttributes) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Check for keytype match
|
|
//
|
|
if( eRelation == eREL_SELF &&
|
|
*MBPropertyRow.pID == MD_KEY_TYPE &&
|
|
MBPropertyRow.pValue != NULL &&
|
|
i_wszKeyType[0] != L'\0' )
|
|
{
|
|
if(_wcsicmp((LPWSTR)MBPropertyRow.pValue, i_wszKeyType) != 0)
|
|
{
|
|
hr = RETURNCODETOHRESULT(ERROR_NO_MATCH);
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(eRelation == eREL_PARENT)
|
|
{
|
|
if( !(fMBProperty_INHERIT & *MBPropertyRow.pAttributes) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if(bNewLocation && (eRelation != eREL_PARENT))
|
|
{
|
|
//
|
|
// Create node in the metabase if it is not there yet.
|
|
// pboRead is pointer to this node.
|
|
//
|
|
hr = ReadMetaObject(i_wszSourcePath,
|
|
*o_ppboNew,
|
|
pLocation,
|
|
&pboRead);
|
|
if(FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if(bLocationWithProperty)
|
|
{
|
|
MD_ASSERT(pboRead != NULL);
|
|
hr = ReadDataObject(pboRead,
|
|
(LPVOID*)&MBPropertyRow,
|
|
acbMBPropertyRow,
|
|
pStorage,
|
|
TRUE);
|
|
if(FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(!bSawSourcePath)
|
|
{
|
|
hr = RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
if(FAILED(hr) && NULL != *o_ppboNew)
|
|
{
|
|
delete (*o_ppboNew);
|
|
*o_ppboNew = NULL;
|
|
}
|
|
|
|
delete pStorage;
|
|
pStorage = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CImporter::InitIST()
|
|
/*++
|
|
|
|
Synopsis:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
STQueryCell QueryCell[1];
|
|
|
|
//
|
|
// Get the property table.
|
|
//
|
|
QueryCell[0].pData = (LPVOID)m_wszFileName;
|
|
QueryCell[0].eOperator = eST_OP_EQUAL;
|
|
QueryCell[0].iCell = iST_CELL_FILE;
|
|
QueryCell[0].dbType = DBTYPE_WSTR;
|
|
QueryCell[0].cbSize = (lstrlenW(m_wszFileName)+1)*sizeof(WCHAR);
|
|
|
|
ULONG cCell = sizeof(QueryCell)/sizeof(STQueryCell);
|
|
|
|
//
|
|
// No need to initilize dispenser (InitializeSimpleTableDispenser()),
|
|
// because we now specify USE_CRT=1 in sources, which means that
|
|
// globals will be initialized.
|
|
//
|
|
|
|
hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&m_spISTDisp, WSZ_PRODUCT_IIS );
|
|
if(FAILED(hr))
|
|
{
|
|
DBGERROR((
|
|
DBG_CONTEXT,
|
|
"[%s] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",__FUNCTION__,hr));
|
|
return hr;
|
|
}
|
|
|
|
hr = m_spISTDisp->GetTable(
|
|
wszDATABASE_METABASE,
|
|
wszTABLE_MBProperty,
|
|
(LPVOID)QueryCell,
|
|
(LPVOID)&cCell,
|
|
eST_QUERYFORMAT_CELLS,
|
|
fST_LOS_DETAILED_ERROR_TABLE | fST_LOS_NO_LOGGING,
|
|
(LPVOID *)&m_spISTProperty);
|
|
|
|
//
|
|
// Log warnings/errors in getting the mb property table
|
|
// Do this BEFORE checking the return code of GetTable.
|
|
//
|
|
CComPtr<IErrorInfo> spErrorInfo;
|
|
HRESULT hrErrorTable = GetErrorInfo(0, &spErrorInfo);
|
|
if(hrErrorTable == S_OK) // GetErrorInfo returns S_FALSE when there is no error object
|
|
{
|
|
//
|
|
// Get the ICatalogErrorLogger interface to log the errors.
|
|
//
|
|
CComPtr<IAdvancedTableDispenser> spISTDispAdvanced;
|
|
hrErrorTable = m_spISTDisp->QueryInterface(
|
|
IID_IAdvancedTableDispenser,
|
|
(LPVOID*)&spISTDispAdvanced);
|
|
if(FAILED(hrErrorTable))
|
|
{
|
|
DBGWARN((
|
|
DBG_CONTEXT,
|
|
"[%s] Could not QI for Adv Dispenser, hr=0x%x\n", __FUNCTION__, hrErrorTable));
|
|
return hr;
|
|
}
|
|
|
|
hrErrorTable = spISTDispAdvanced->GetCatalogErrorLogger(&m_spILogger);
|
|
if(FAILED(hrErrorTable))
|
|
{
|
|
DBGWARN((
|
|
DBG_CONTEXT,
|
|
"[%s] Could not get ICatalogErrorLogger2, hr=0x%x\n", __FUNCTION__, hrErrorTable));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the ISimpleTableRead2 interface to read the errors.
|
|
//
|
|
hrErrorTable =
|
|
spErrorInfo->QueryInterface(IID_ISimpleTableRead2, (LPVOID*)&m_spISTError);
|
|
if(FAILED(hrErrorTable))
|
|
{
|
|
DBGWARN((DBG_CONTEXT, "[%s] Could not get ISTRead2 from IErrorInfo\n, __FUNCTION__"));
|
|
return hr;
|
|
}
|
|
|
|
for(ULONG iRow=0; ; iRow++)
|
|
{
|
|
tDETAILEDERRORSRow ErrorInfo;
|
|
hrErrorTable = m_spISTError->GetColumnValues(
|
|
iRow,
|
|
cDETAILEDERRORS_NumberOfColumns,
|
|
0,
|
|
0,
|
|
(LPVOID*)&ErrorInfo);
|
|
if(hrErrorTable == E_ST_NOMOREROWS)
|
|
{
|
|
break;
|
|
}
|
|
if(FAILED(hrErrorTable))
|
|
{
|
|
DBGWARN((DBG_CONTEXT, "[%s] Could not read an error row.\n", __FUNCTION__));
|
|
return hr;
|
|
}
|
|
|
|
hrErrorTable =
|
|
m_spILogger->ReportError(
|
|
BaseVersion_DETAILEDERRORS,
|
|
ExtendedVersion_DETAILEDERRORS,
|
|
cDETAILEDERRORS_NumberOfColumns,
|
|
0,
|
|
(LPVOID*)&ErrorInfo);
|
|
if(FAILED(hrErrorTable))
|
|
{
|
|
DBGWARN((DBG_CONTEXT, "[%s] Could not log error.\n", __FUNCTION__));
|
|
return hr;
|
|
}
|
|
hr = MD_ERROR_READ_METABASE_FILE;
|
|
} // for(ULONG iRow=0; ; iRow++)
|
|
} // if(hrErrorTable == S_OK)
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DBGERROR((DBG_CONTEXT, "[%s] GetTable failed with hr = 0x%x.\n",__FUNCTION__,hr));
|
|
return hr;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// private
|
|
//
|
|
|
|
CImporter::Relation CImporter::GetRelation(
|
|
LPCWSTR i_wszSourcePath,
|
|
LPCWSTR i_wszCheck)
|
|
/*++
|
|
|
|
Synopsis:
|
|
|
|
Arguments: [i_wszSourcePath] -
|
|
[i_wszCheck] -
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
Relation eRelation = eREL_NONE;
|
|
BOOL bIsSourcePath = false;
|
|
BOOL bIsChild = IsChild(i_wszSourcePath, i_wszCheck, &bIsSourcePath);
|
|
if(bIsChild)
|
|
{
|
|
eRelation = (bIsSourcePath) ? eREL_SELF : eREL_CHILD;
|
|
}
|
|
else
|
|
{
|
|
BOOL bIsParent = IsChild(i_wszCheck, i_wszSourcePath, &bIsSourcePath);
|
|
if(bIsParent)
|
|
{
|
|
MD_ASSERT(bIsSourcePath == false);
|
|
eRelation = eREL_PARENT;
|
|
}
|
|
else
|
|
{
|
|
eRelation = eREL_NONE;
|
|
}
|
|
}
|
|
|
|
return eRelation;
|
|
}
|
|
|
|
BOOL
|
|
CImporter::IsChild(
|
|
LPCWSTR i_wszParent,
|
|
LPCWSTR i_wszCheck,
|
|
BOOL *o_pbSamePerson)
|
|
/*++
|
|
|
|
Synopsis:
|
|
|
|
Arguments: [i_wszParent] - Ex. /LM/w3svc/1/root
|
|
[i_wszCheck] - Ex. /LM/w3svc/1
|
|
[o_pbSamePerson] - true if i_wszParent and i_wszCheck is same person
|
|
|
|
Return Value:
|
|
true if i_wszCheck is child or same person
|
|
|
|
--*/
|
|
{
|
|
MD_ASSERT(i_wszParent != NULL);
|
|
MD_ASSERT(i_wszCheck != NULL);
|
|
MD_ASSERT(o_pbSamePerson != NULL);
|
|
|
|
LPCWSTR pParent;
|
|
LPCWSTR pCheck;
|
|
|
|
pParent = i_wszParent;
|
|
pCheck = i_wszCheck;
|
|
|
|
SKIP_DELIMETER(pParent, MD_PATH_DELIMETERW);
|
|
SKIP_DELIMETER(pCheck, MD_PATH_DELIMETERW);
|
|
|
|
if(*pParent == L'\0')
|
|
{
|
|
switch(*pCheck)
|
|
{
|
|
case L'\0':
|
|
*o_pbSamePerson = TRUE;
|
|
break;
|
|
default:
|
|
*o_pbSamePerson = FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
while(*pParent != L'\0')
|
|
{
|
|
if(_wcsnicmp(pParent, pCheck, 1) == 0)
|
|
{
|
|
pParent++;
|
|
pCheck++;
|
|
}
|
|
else if(*pParent == MD_PATH_DELIMETERW && pParent[1] == L'\0' && *pCheck == L'\0')
|
|
{
|
|
*o_pbSamePerson = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
switch(*pCheck)
|
|
{
|
|
case L'\0':
|
|
*o_pbSamePerson = TRUE;
|
|
return TRUE;
|
|
case MD_PATH_DELIMETERW:
|
|
*o_pbSamePerson = (pCheck[1] == L'\0') ? TRUE : FALSE;
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
HRESULT CImporter::ReadMetaObject(
|
|
IN LPCWSTR i_wszAbsParentPath,
|
|
IN CMDBaseObject *i_pboParent,
|
|
IN LPCWSTR i_wszAbsChildPath,
|
|
OUT CMDBaseObject **o_ppboChild)
|
|
/*++
|
|
|
|
Synopsis:
|
|
Returns a pbo for the child. If it does not already exist, it is
|
|
created.
|
|
|
|
Arguments: [i_wszAbsParentPath] -
|
|
[i_pboParent] - pbo corresponding to i_wszAbsParentPath
|
|
[i_wszAbsChildPath] -
|
|
[o_ppboChild] - pbo corresponding to i_wszAbsChildPath
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
MD_ASSERT(i_pboParent != NULL);
|
|
MD_ASSERT(i_wszAbsParentPath != NULL);
|
|
MD_ASSERT(i_wszAbsChildPath != NULL);
|
|
MD_ASSERT(o_ppboChild != NULL);
|
|
|
|
HRESULT hr = ERROR_SUCCESS;
|
|
HRESULT hrWarn = ERROR_SUCCESS;
|
|
|
|
int iLenParent = (int)wcslen(i_wszAbsParentPath);
|
|
int iLenChild = (int)wcslen(i_wszAbsChildPath);
|
|
|
|
LPWSTR wszParent = NULL;
|
|
LPWSTR wszChild = NULL;
|
|
|
|
wszParent = new wchar_t[iLenParent+1];
|
|
if(wszParent == NULL)
|
|
{
|
|
hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
wszChild = new wchar_t[iLenChild+1];
|
|
if(wszChild == NULL)
|
|
{
|
|
hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
int idxParent = 0;
|
|
int idxChild = 0;
|
|
|
|
BOOL bRetParent = FALSE;
|
|
BOOL bRetChild = FALSE;
|
|
|
|
CMDBaseObject *pboNew = NULL;
|
|
CMDBaseObject *pboLastParent = i_pboParent;
|
|
|
|
while(1) {
|
|
bRetParent = EnumMDPath(i_wszAbsParentPath, wszParent, &idxParent);
|
|
bRetChild = EnumMDPath(i_wszAbsChildPath, wszChild, &idxChild);
|
|
|
|
if(bRetParent == FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
while(bRetChild == TRUE) {
|
|
//
|
|
// This is okay, since function that uses this takes an LPSTR
|
|
// and a bool saying whether or not the string is unicode.
|
|
//
|
|
LPSTR pszTemp = (LPSTR)wszChild;
|
|
|
|
pboNew = pboLastParent->GetChildObject(pszTemp, &hrWarn, TRUE);
|
|
if(pboNew == NULL) {
|
|
//
|
|
// Create it
|
|
//
|
|
pboNew = new CMDBaseObject(wszChild, NULL);
|
|
if (pboNew == NULL) {
|
|
hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
else if (!pboNew->IsValid()) {
|
|
hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
|
|
delete (pboNew);
|
|
goto exit;
|
|
}
|
|
hr = pboLastParent->InsertChildObject(pboNew);
|
|
if(FAILED(hr)) {
|
|
delete pboNew;
|
|
goto exit;
|
|
}
|
|
}
|
|
pboLastParent = pboNew;
|
|
|
|
bRetChild = EnumMDPath(i_wszAbsChildPath, wszChild, &idxChild);
|
|
}
|
|
|
|
//
|
|
// Set out params
|
|
//
|
|
*o_ppboChild = pboLastParent;
|
|
|
|
exit:
|
|
delete [] wszParent;
|
|
delete [] wszChild;
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL CImporter::EnumMDPath(
|
|
LPCWSTR i_wszFullPath,
|
|
LPWSTR io_wszPath,
|
|
int* io_iStartIndex)
|
|
/*++
|
|
|
|
Synopsis:
|
|
Starting at io_iStartIndex, this function will find the next token.
|
|
Eg. i_wszFullPath = /LM/w3svc/1
|
|
*io_iStartIndex = 3
|
|
io_wszPath => w3svc
|
|
*io_iStartIndex = 9
|
|
|
|
Arguments: [i_wszFullPath] - Ex. /LM/w3svc/1
|
|
[io_wszPath] - Should be at least same size as i_wszFullPath
|
|
[io_iStartIndex] - 0-based index to start looking from
|
|
|
|
Return Value:
|
|
true if io_wszPath is set.
|
|
|
|
--*/
|
|
{
|
|
MD_ASSERT(i_wszFullPath != NULL);
|
|
MD_ASSERT(io_wszPath != NULL);
|
|
|
|
int idxEnd = *io_iStartIndex;
|
|
int idxStart = *io_iStartIndex;
|
|
|
|
if(i_wszFullPath[idxStart] == MD_PATH_DELIMETERW)
|
|
{
|
|
idxStart++;
|
|
idxEnd++;
|
|
}
|
|
|
|
//
|
|
// If there is no more to enum, just exit and don't set out params
|
|
//
|
|
if(i_wszFullPath[idxStart] == L'\0')
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for(; ; idxEnd++)
|
|
{
|
|
if(i_wszFullPath[idxEnd] == MD_PATH_DELIMETERW)
|
|
{
|
|
break;
|
|
}
|
|
if(i_wszFullPath[idxEnd] == L'\0')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set out params
|
|
//
|
|
*io_iStartIndex = idxEnd;
|
|
memcpy(io_wszPath, &i_wszFullPath[idxStart], sizeof(wchar_t) * (idxEnd-idxStart));
|
|
io_wszPath[idxEnd-idxStart] = L'\0';
|
|
|
|
return TRUE;
|
|
}
|