/*++ 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 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 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; }