|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
schemadynamic.cpp
Abstract:
This file contains the implementation of the CDynSchema class. This class contains the dynamic schema structures. It also contains the rules for populating the schema structures.
Author:
Mohit Srivastava 28-Nov-00
Revision History:
--*/
#include "iisprov.h"
#define USE_DEFAULT_VALUES
#define USE_DEFAULT_BINARY_VALUES
CDynSchema* g_pDynSch = NULL;
HRESULT CDynSchema::Initialize() /*++
Synopsis: If fails, object must be destroyed. If succeeds, object is ready for use.
Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == false); DBG_ASSERT(m_bInitSuccessful == false);
HRESULT hr = WBEM_S_NO_ERROR;
m_bInitCalled = true;
hr = m_hashProps.Wmi_Initialize(); if(FAILED(hr)) { goto exit; } hr = m_hashClasses.Wmi_Initialize(); if(FAILED(hr)) { goto exit; }
hr = m_hashAssociations.Wmi_Initialize(); if(FAILED(hr)) { goto exit; }
hr = m_hashKeyTypes.Wmi_Initialize(); if(FAILED(hr)) { goto exit; }
hr = m_poolAssociations.Initialize(10); if(FAILED(hr)) { goto exit; }
hr = m_poolClasses.Initialize(10); if(FAILED(hr)) { goto exit; }
hr = m_poolProps.Initialize(10); if(FAILED(hr)) { goto exit; }
hr = m_poolKeyTypes.Initialize(10); if(FAILED(hr)) { goto exit; }
hr = m_poolKeyTypeNodes.Initialize(10); if(FAILED(hr)) { goto exit; }
hr = m_spoolStrings.Initialize(); if(FAILED(hr)) { goto exit; }
hr = m_apoolPMbp.Initialize(); if(FAILED(hr)) { goto exit; }
hr = m_apoolBytes.Initialize(); if(FAILED(hr)) { goto exit; }
exit: if(SUCCEEDED(hr)) { m_bInitSuccessful = true; } return hr; }
void CDynSchema::LogConflicts(LPCWSTR wszSettingsClassName) // Logs an error in system events if a schema conflict occurs
{ WMI_ASSOCIATION *pWmiAssoc = NULL; WMI_CLASS* pWmiSettingsClass = NULL;
if (SUCCEEDED(m_hashClasses.Wmi_GetByKey(wszSettingsClassName, &pWmiSettingsClass)) || SUCCEEDED(m_hashAssociations.Wmi_GetByKey(wszSettingsClassName, &pWmiAssoc))) {
const WCHAR * EventLogStrings[2]; const LPCWSTR wszErrorString = L"WMI Schema warning - class already exists";
EventLogStrings[0] = wszSettingsClassName; EventLogStrings[1] = wszErrorString;
EVENT_LOG m_EventLog(L"WMI Schema");
m_EventLog.LogEvent( TYPE_E_NAMECONFLICT, // message id
2, // count of strings
EventLogStrings, // array of strings
0 // error code
); } }
HRESULT CDynSchema::RulePopulateFromStatic() /*++
Synopsis: Populates hashtables with pointers to hardcoded schema.
Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true);
HRESULT hr = WBEM_S_NO_ERROR;
//
// Populate Properties
//
if(METABASE_PROPERTY_DATA::s_MetabaseProperties != NULL) { METABASE_PROPERTY* pStatMbpCurrent; for(ULONG i = 0; ; i++) { pStatMbpCurrent = METABASE_PROPERTY_DATA::s_MetabaseProperties[i]; if(pStatMbpCurrent == NULL) { break; } hr = m_hashProps.Wmi_Insert(pStatMbpCurrent->pszPropName, pStatMbpCurrent); if(FAILED(hr)) { goto exit; } } }
//
// Populate KeyTypes
//
METABASE_KEYTYPE** apMetabaseKeyTypes; apMetabaseKeyTypes = METABASE_KEYTYPE_DATA::s_MetabaseKeyTypes; for(ULONG i = 0; apMetabaseKeyTypes[i] != NULL; i++) { if( apMetabaseKeyTypes[i]->m_pszName != NULL ) { apMetabaseKeyTypes[i]->m_pKtListInverseCCL = NULL; hr = m_hashKeyTypes.Wmi_Insert(apMetabaseKeyTypes[i]->m_pszName, apMetabaseKeyTypes[i]); if(FAILED(hr)) { goto exit; } } }
exit: return hr; }
HRESULT CDynSchema::Rule2PopulateFromStatic() /*++
Synopsis: Populates hashtables with pointers to hardcoded schema.
Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true);
HRESULT hr = S_OK; int i;
//
// Populate Classes
//
WMI_CLASS* pStatWmiClassCurrent; for(i = 0; ; i++) { pStatWmiClassCurrent = WMI_CLASS_DATA::s_WmiClasses[i]; if(pStatWmiClassCurrent == NULL) { break; } hr = m_hashClasses.Wmi_Insert( pStatWmiClassCurrent->pszClassName, pStatWmiClassCurrent); if(FAILED(hr)) { goto exit; } }
//
// Populate Associations
//
WMI_ASSOCIATION* pStatWmiAssocCurrent; for(i = 0; ; i++) { pStatWmiAssocCurrent = WMI_ASSOCIATION_DATA::s_WmiAssociations[i]; if(pStatWmiAssocCurrent == NULL) { break; } hr = m_hashAssociations.Wmi_Insert( pStatWmiAssocCurrent->pszAssociationName, pStatWmiAssocCurrent); if(FAILED(hr)) { goto exit; } }
exit: return hr; }
HRESULT CDynSchema::RuleKeyType( const CTableMeta *i_pTableMeta) /*++
Synopsis: If not already in hashtable of keytypes, a keytype structure is allocated thru the keytype pool. Then, a pointer to it is inserted in hashtable.
Arguments: [i_pTableMeta] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pTableMeta != NULL);
HRESULT hr = WBEM_S_NO_ERROR; HRESULT hrTemp = WBEM_S_NO_ERROR; METABASE_KEYTYPE* pktNew; LPWSTR wszNew;
hrTemp = m_hashKeyTypes.Wmi_GetByKey( i_pTableMeta->TableMeta.pInternalName, &pktNew); if(FAILED(hrTemp)) { hr = m_spoolStrings.GetNewString(i_pTableMeta->TableMeta.pInternalName, &wszNew); if(FAILED(hr)) { goto exit; } hr = m_poolKeyTypes.GetNewElement(&pktNew); if(FAILED(hr)) { goto exit; } pktNew->m_pszName = wszNew; pktNew->m_pKtListInverseCCL = NULL; m_hashKeyTypes.Wmi_Insert(wszNew, pktNew); if(FAILED(hr)) { goto exit; } }
exit: return hr; }
HRESULT CDynSchema::RuleWmiClassDescription( const CTableMeta* i_pTableMeta, WMI_CLASS* i_pElementClass, WMI_CLASS* i_pSettingClass) const /*++
Synopsis: Sets WMI_CLASS::pDescription if needed. This pointer will be invalid after initialization since it points to catalog.
Arguments: [i_pTableMeta] - [i_pElementClass] - [i_pSettingClass] -
Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pTableMeta != NULL); DBG_ASSERT(i_pElementClass != NULL); DBG_ASSERT(i_pSettingClass != NULL);
HRESULT hr = WBEM_S_NO_ERROR;
if(i_pTableMeta->TableMeta.pDescription != NULL) { i_pElementClass->pszDescription = i_pTableMeta->TableMeta.pDescription; i_pSettingClass->pszDescription = i_pTableMeta->TableMeta.pDescription; }
return hr; }
HRESULT CDynSchema::RuleWmiClass( const CTableMeta* i_pTableMeta, WMI_CLASS** o_ppElementClass, WMI_CLASS** o_ppSettingClass, DWORD io_adwIgnoredProps[], BOOL i_bUserDefined) /*++
Synopsis: Creates an Element and Setting class based on i_pTableMeta->TableMeta.pInternalName. If not in hashtable of classes, these classes are inserted.
At bottom, RuleProperties is called to set up list of properties for each class.
Arguments: [i_pTableMeta] - [o_ppElementClass] - can be NULL [o_ppSettingClass] - can be NULL Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pTableMeta != NULL);
WMI_CLASS* pWmiClass = NULL; WMI_CLASS* pWmiSettingsClass = NULL; LPWSTR wszClassName, wszSettingsClassName; LPWSTR wszParentClassName, wszParentSettingsClassName; HRESULT hr = WBEM_S_NO_ERROR; HRESULT hrTemp = WBEM_S_NO_ERROR;
ULONG cPropsAndTagsRW = 0; ULONG cPropsAndTagsRO = 0;
ULONG iShipped = 0;
CColumnMeta* pColumnMeta; ULONG cchTable;
//
// Ignore table if it has no name
//
if(i_pTableMeta->TableMeta.pInternalName == NULL) { hr = WBEM_S_NO_ERROR; goto exit; }
//
// Determine iShipped and Parent Classes
//
if(fTABLEMETA_USERDEFINED & *i_pTableMeta->TableMeta.pSchemaGeneratorFlags) { iShipped = USER_DEFINED_TO_REPOSITORY; DBG_ASSERT(iShipped != USER_DEFINED_NOT_TO_REPOSITORY); wszParentClassName = g_wszExtElementParent; wszParentSettingsClassName = g_wszExtSettingParent; } else { if(fTABLEMETA_EXTENDED & *i_pTableMeta->TableMeta.pSchemaGeneratorFlags) { iShipped = EXTENDED; } else { iShipped = SHIPPED_TO_MOF; } wszParentClassName = g_wszElementParent; wszParentSettingsClassName = g_wszSettingParent; }
//
// Determine number of RO and RW properties
//
for(ULONG idxProps = 0; idxProps < i_pTableMeta->ColCount(); idxProps++) { pColumnMeta = i_pTableMeta->paColumns[idxProps]; if(*pColumnMeta->ColumnMeta.pSchemaGeneratorFlags & fCOLUMNMETA_CACHE_PROPERTY_MODIFIED) { cPropsAndTagsRW += pColumnMeta->cNrTags + 1; } else { cPropsAndTagsRO += pColumnMeta->cNrTags + 1; } }
cchTable = wcslen(i_pTableMeta->TableMeta.pInternalName);
//
// The keytype should already exist.
//
METABASE_KEYTYPE* pktTemp; hrTemp = m_hashKeyTypes.Wmi_GetByKey(i_pTableMeta->TableMeta.pInternalName, &pktTemp); if( FAILED(hrTemp) ) { goto exit; }
//
// The Element class (named PrefixC)
//
hr = m_spoolStrings.GetNewArray(g_cchIIs_+cchTable+1, &wszClassName); if(FAILED(hr)) { goto exit; } memcpy(wszClassName, g_wszIIs_, sizeof(WCHAR)*g_cchIIs_); memcpy(&wszClassName[g_cchIIs_], i_pTableMeta->TableMeta.pInternalName, sizeof(WCHAR)*(cchTable+1));
if (i_bUserDefined) { LogConflicts(wszClassName); }
if(FAILED(m_hashClasses.Wmi_GetByKey(wszClassName, &pWmiClass))) { hr = m_poolClasses.GetNewElement(&pWmiClass); if(FAILED(hr)) { goto exit; } pWmiClass->pkt = pktTemp; pWmiClass->pszClassName = wszClassName; pWmiClass->pszMetabaseKey = L"/LM"; pWmiClass->pszKeyName = L"Name"; pWmiClass->ppMethod = NULL; pWmiClass->pszParentClass = wszParentClassName; pWmiClass->bCreateAllowed = true; pWmiClass->pszDescription = NULL;
hr = m_hashClasses.Wmi_Insert(wszClassName, pWmiClass); if(FAILED(hr)) { goto exit; } } pWmiClass->ppmbp = NULL; pWmiClass->dwExtended = iShipped;
//
// The Settings class (named PrefixCSetting)
//
hr = m_spoolStrings.GetNewArray(g_cchIIs_+cchTable+g_cchSettings+1, &wszSettingsClassName); if(FAILED(hr)) { goto exit; } memcpy(wszSettingsClassName, g_wszIIs_, sizeof(WCHAR)*g_cchIIs_); memcpy(&wszSettingsClassName[g_cchIIs_], i_pTableMeta->TableMeta.pInternalName, sizeof(WCHAR)*cchTable); memcpy(&wszSettingsClassName[g_cchIIs_+cchTable], g_wszSettings, sizeof(WCHAR)*(g_cchSettings+1));
if (i_bUserDefined) { LogConflicts(wszSettingsClassName); }
if(FAILED(m_hashClasses.Wmi_GetByKey(wszSettingsClassName, &pWmiSettingsClass))) { hr = m_poolClasses.GetNewElement(&pWmiSettingsClass); if(FAILED(hr)) { goto exit; } pWmiSettingsClass->pkt = pktTemp; pWmiSettingsClass->pszClassName = wszSettingsClassName; pWmiSettingsClass->pszMetabaseKey = L"/LM"; pWmiSettingsClass->pszKeyName = L"Name"; pWmiSettingsClass->ppMethod = NULL; pWmiSettingsClass->pszParentClass = wszParentSettingsClassName; pWmiSettingsClass->bCreateAllowed = true; pWmiSettingsClass->pszDescription = NULL;
hr = m_hashClasses.Wmi_Insert(wszSettingsClassName, pWmiSettingsClass); if(FAILED(hr)) { goto exit; } } pWmiSettingsClass->ppmbp = NULL; pWmiSettingsClass->dwExtended = iShipped;
//
// Fill in the ppmbp field
//
hr = RuleProperties( i_pTableMeta, cPropsAndTagsRO, pWmiClass, cPropsAndTagsRW, pWmiSettingsClass, io_adwIgnoredProps); if(FAILED(hr)) { goto exit; }
exit: if(SUCCEEDED(hr)) { if(o_ppElementClass != NULL) { *o_ppElementClass = pWmiClass; } if(o_ppSettingClass != NULL) { *o_ppSettingClass = pWmiSettingsClass; } } return hr; }
HRESULT CDynSchema::RuleProperties( const CTableMeta* i_pTableMeta, ULONG i_cPropsAndTagsRO, WMI_CLASS* io_pWmiClass, ULONG i_cPropsAndTagsRW, WMI_CLASS* io_pWmiSettingsClass, DWORD io_adwIgnoredProps[]) /*++
Synopsis: Given i_pTableMeta, puts the properties either under the Element class or under the Setting class.
Arguments: [i_pTableMeta] - [i_cPropsAndTagsRO] - [o_papMbp] - [i_cPropsAndTagsRW] - [o_papMbpSettings] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pTableMeta != NULL); DBG_ASSERT(io_pWmiClass != NULL); DBG_ASSERT(io_pWmiSettingsClass != NULL); // DBG_ASSERT(sizeof(io_awszIgnoredProps) >= sizeof(g_awszPropIgnoreList));
HRESULT hr = WBEM_S_NO_ERROR; CColumnMeta* pColumnMeta = NULL; METABASE_PROPERTY* pMbp; ULONG idxProps = 0; ULONG idxTags = 0;
ULONG idxPropsAndTagsRO = 0; ULONG idxPropsAndTagsRW = 0;
METABASE_PROPERTY*** papMbp = &io_pWmiClass->ppmbp; METABASE_PROPERTY*** papMbpSettings = &io_pWmiSettingsClass->ppmbp;
//
// Allocate enough memory for the RO properties
//
if(i_cPropsAndTagsRO > 0) { hr = m_apoolPMbp.GetNewArray(i_cPropsAndTagsRO+1, papMbp); if(FAILED(hr)) { goto exit; } memset(*papMbp, 0, (1+i_cPropsAndTagsRO)*sizeof(METABASE_PROPERTY*)); }
//
// Allocate enough memory for the RW properties
//
if(i_cPropsAndTagsRW > 0) { hr = m_apoolPMbp.GetNewArray(i_cPropsAndTagsRW+1, papMbpSettings); if(FAILED(hr)) { goto exit; } memset(*papMbpSettings, 0, (1+i_cPropsAndTagsRW)*sizeof(METABASE_PROPERTY*)); }
//
// Walk thru all the properties
//
for (idxProps=0, idxPropsAndTagsRO = 0, idxPropsAndTagsRW = 0; idxProps < i_pTableMeta->ColCount(); ++idxProps) { pColumnMeta = i_pTableMeta->paColumns[idxProps];
//
// Ignore property if its in g_adwPropIgnoreList and store the prop in
// io_adwIgnoredProps
//
if( (*pColumnMeta->ColumnMeta.pSchemaGeneratorFlags & fCOLUMNMETA_HIDDEN) || IgnoreProperty(io_pWmiClass->pkt, *(pColumnMeta->ColumnMeta.pID), io_adwIgnoredProps) ) { continue; }
//
// Call RulePropertiesHelper if Property is not already in the
// properties hashtable
//
if(FAILED(m_hashProps.Wmi_GetByKey(pColumnMeta->ColumnMeta.pInternalName, &pMbp))) { hr = RulePropertiesHelper(pColumnMeta, &pMbp, NULL); if(FAILED(hr)) { goto exit; } }
//
// If RW, put pointer to property in Setting class, else in Element
// class.
//
if(*pColumnMeta->ColumnMeta.pSchemaGeneratorFlags & fCOLUMNMETA_CACHE_PROPERTY_MODIFIED) { (*papMbpSettings)[idxPropsAndTagsRW] = pMbp; idxPropsAndTagsRW++; } else { (*papMbp)[idxPropsAndTagsRO] = pMbp; idxPropsAndTagsRO++; }
//
// Same steps as above, except for the tags.
//
for(idxTags=0; idxTags < pColumnMeta->cNrTags; idxTags++) { if(FAILED(m_hashProps.Wmi_GetByKey(pColumnMeta->paTags[idxTags]->pInternalName, &pMbp))) { hr = RulePropertiesHelper(pColumnMeta, &pMbp, &idxTags); if(FAILED(hr)) { goto exit; } } if(*pColumnMeta->ColumnMeta.pSchemaGeneratorFlags & fCOLUMNMETA_CACHE_PROPERTY_MODIFIED) { (*papMbpSettings)[idxPropsAndTagsRW] = pMbp; idxPropsAndTagsRW++; } else { (*papMbp)[idxPropsAndTagsRO] = pMbp; idxPropsAndTagsRO++; } } }
exit: return hr; }
HRESULT CDynSchema::RulePropertiesHelper( const CColumnMeta* i_pColumnMeta, METABASE_PROPERTY** o_ppMbp, ULONG* i_idxTag) /*++
Synopsis: This class creates a property and inserts it into the hashtable of props. PRECONDITION: The property does not exist in the hashtable yet. i_idxTag is null if you want to insert the property. else you want to insert a tag, and *i_idxTag is the index of the tag
Arguments: [i_pColumnMeta] - [o_ppMbp] - [i_idxTag] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pColumnMeta != NULL); DBG_ASSERT(o_ppMbp != NULL);
HRESULT hr = WBEM_S_NO_ERROR; METABASE_PROPERTY* pMbp = NULL; hr = m_poolProps.GetNewElement(&pMbp); if(FAILED(hr)) { goto exit; }
if(i_idxTag == NULL) { pMbp->dwMDMask = 0; hr = m_spoolStrings.GetNewString( i_pColumnMeta->ColumnMeta.pInternalName, &(pMbp->pszPropName)); if(FAILED(hr)) { goto exit; } } else { pMbp->dwMDMask = *(i_pColumnMeta->paTags[*i_idxTag]->pValue); hr = m_spoolStrings.GetNewString( i_pColumnMeta->paTags[*i_idxTag]->pInternalName, &(pMbp->pszPropName)); if(FAILED(hr)) { goto exit; } } pMbp->dwMDIdentifier = *(i_pColumnMeta->ColumnMeta.pID); pMbp->dwMDUserType = *(i_pColumnMeta->ColumnMeta.pUserType);
switch(*(i_pColumnMeta->ColumnMeta.pType)) { case eCOLUMNMETA_int32: if(fCOLUMNMETA_BOOL & *(i_pColumnMeta->ColumnMeta.pMetaFlags)) { if(pMbp->dwMDMask == 0) { pMbp->dwMDMask = ALL_BITS_ON; } } pMbp->dwMDDataType = DWORD_METADATA; pMbp->pDefaultValue = NULL; #ifdef USE_DEFAULT_VALUES
if(i_pColumnMeta->ColumnMeta.pDefaultValue != NULL) { pMbp->dwDefaultValue = *((DWORD*)(i_pColumnMeta->ColumnMeta.pDefaultValue)); pMbp->pDefaultValue = &pMbp->dwDefaultValue; } #endif
break; case eCOLUMNMETA_String: if(fCOLUMNMETA_MULTISTRING & *(i_pColumnMeta->ColumnMeta.pMetaFlags)) { pMbp->dwMDDataType = MULTISZ_METADATA; } else if(fCOLUMNMETA_EXPANDSTRING & *(i_pColumnMeta->ColumnMeta.pMetaFlags)) { pMbp->dwMDDataType = EXPANDSZ_METADATA; } else { pMbp->dwMDDataType = STRING_METADATA; } //
// Default values.
//
pMbp->pDefaultValue = NULL; #ifdef USE_DEFAULT_VALUES
if(i_pColumnMeta->ColumnMeta.pDefaultValue != NULL) { if(pMbp->dwMDDataType != MULTISZ_METADATA) { hr = m_spoolStrings.GetNewString( (LPWSTR)i_pColumnMeta->ColumnMeta.pDefaultValue, (LPWSTR*)&pMbp->pDefaultValue); if(FAILED(hr)) { goto exit; } } else { bool bLastCharNull = false; ULONG idx = 0; ULONG iLen = 0; LPWSTR msz = (LPWSTR)i_pColumnMeta->ColumnMeta.pDefaultValue;
do { bLastCharNull = msz[idx] == L'\0' ? true : false; } while( !(msz[++idx] == L'\0' && bLastCharNull) ); iLen = idx+1;
hr = m_spoolStrings.GetNewArray( iLen, (LPWSTR*)&pMbp->pDefaultValue); if(FAILED(hr)) { goto exit; } memcpy( pMbp->pDefaultValue, i_pColumnMeta->ColumnMeta.pDefaultValue, sizeof(WCHAR)*iLen); } } #endif
break; case eCOLUMNMETA_BYTES: pMbp->dwMDDataType = BINARY_METADATA; pMbp->pDefaultValue = NULL; #ifdef USE_DEFAULT_VALUES
#ifdef USE_DEFAULT_BINARY_VALUES
if( i_pColumnMeta->ColumnMeta.pDefaultValue != NULL ) { hr = m_apoolBytes.GetNewArray( i_pColumnMeta->cbDefaultValue, (BYTE**)&pMbp->pDefaultValue); if(FAILED(hr)) { goto exit; } memcpy( pMbp->pDefaultValue, i_pColumnMeta->ColumnMeta.pDefaultValue, i_pColumnMeta->cbDefaultValue); //
// Use dwDefaultValue to store the length.
//
pMbp->dwDefaultValue = i_pColumnMeta->cbDefaultValue; } #endif
#endif
break; default: pMbp->dwMDDataType = -1; pMbp->pDefaultValue = NULL; break; } pMbp->dwMDAttributes = *(i_pColumnMeta->ColumnMeta.pAttributes); if(*i_pColumnMeta->ColumnMeta.pSchemaGeneratorFlags & fCOLUMNMETA_CACHE_PROPERTY_MODIFIED) { pMbp->fReadOnly = FALSE; } else { pMbp->fReadOnly = TRUE; }
hr = m_hashProps.Wmi_Insert(pMbp->pszPropName, pMbp); if(FAILED(hr)) { goto exit; }
exit: if(SUCCEEDED(hr)) { *o_ppMbp = pMbp; } return hr; }
bool CDynSchema::IgnoreProperty( METABASE_KEYTYPE* io_pkt, DWORD i_dwPropId, DWORD io_adwIgnored[]) /*++
Synopsis: Checks to see if i_wszProp is in g_adwPropIgnoreList. If it is, sets next free element in io_adwIgnored to point to this.
Arguments: [i_wszProp] - [io_adwIgnored] - Must be as big as g_adwPropIgnoreList. Allocated AND must be memset to 0 by caller. Return Value: true if property is in the ignore list. false otherwise.
--*/ { DBG_ASSERT(io_pkt);
if(g_adwPropIgnoreList == NULL) { return false; }
if( io_pkt == &METABASE_KEYTYPE_DATA::s_IIsObject && i_dwPropId == MD_KEY_TYPE ) { return false; }
for(ULONG i = 0; i < g_cElemPropIgnoreList; i++) { if(i_dwPropId == g_adwPropIgnoreList[i]) { for(ULONG j = 0; j < g_cElemPropIgnoreList; j++) { if(io_adwIgnored[j] == NULL) { io_adwIgnored[j] = g_adwPropIgnoreList[i]; break; } } return true; } }
return false; }
#if 0
bool CDynSchema::IgnoreProperty(LPCWSTR i_wszProp) /*++
Synopsis: Checks to see if i_wszProp is in g_adwPropIgnoreList
Arguments: [i_wszProp] - Return Value:
--*/ { DBG_ASSERT(i_wszProp != NULL);
if(g_adwPropIgnoreList == NULL) { return false; }
for(ULONG i = 0; i < g_cElemPropIgnoreList; i++) { if(_wcsicmp(i_wszProp, g_adwPropIgnoreList[i]) == 0) { return true; } }
return false; } #endif
HRESULT CDynSchema::RuleGenericAssociations( WMI_CLASS* i_pcElement, WMI_CLASS* i_pcSetting, WMI_ASSOCIATION_TYPE* i_pAssocType, ULONG i_iShipped) /*++
Synopsis: Create the Element/Setting association.
Arguments: [i_pcElement] - [i_pcSetting] - [i_iShipped] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pcElement != NULL); DBG_ASSERT(i_pcSetting != NULL); DBG_ASSERT(i_pAssocType != NULL);
HRESULT hr = WBEM_S_NO_ERROR;
LPWSTR wszElement = i_pcElement->pszClassName; LPWSTR wszSetting = i_pcSetting->pszClassName; LPWSTR wszParent = NULL; LPWSTR wszAssocName; WMI_ASSOCIATION* pWmiAssoc;
ULONG cchElement = wcslen(wszElement); ULONG cchSetting = wcslen(wszSetting);
hr = m_spoolStrings.GetNewArray(cchElement+cchSetting+2+1, &wszAssocName); if(FAILED(hr)) { goto exit; } wcscpy(wszAssocName, wszElement); wcscat(wszAssocName, L"_"); wcscat(wszAssocName, wszSetting);
hr = m_poolAssociations.GetNewElement(&pWmiAssoc); if(FAILED(hr)) { goto exit; }
if(i_iShipped == USER_DEFINED_TO_REPOSITORY || i_iShipped == USER_DEFINED_NOT_TO_REPOSITORY) { wszParent = i_pAssocType->pszExtParent; } else { wszParent = i_pAssocType->pszParent; }
pWmiAssoc->pszAssociationName = wszAssocName; pWmiAssoc->pcLeft = i_pcElement; pWmiAssoc->pcRight = i_pcSetting; pWmiAssoc->pType = i_pAssocType; pWmiAssoc->fFlags = 0; pWmiAssoc->pszParentClass = wszParent; pWmiAssoc->dwExtended = i_iShipped;
hr = m_hashAssociations.Wmi_Insert(wszAssocName, pWmiAssoc); if(FAILED(hr)) { goto exit; }
exit: return hr; }
void CDynSchema::RuleWmiClassServices( WMI_CLASS* i_pElement, WMI_CLASS* i_pSetting) /*++
Synopsis: Sets the bCreateAllowed fields to false if necessary. i_pSetting must be the corresponding Setting class to i_pElement.
Also sets i_pElement->pszParentClass
Arguments: [i_pElement] - [i_pSetting] - Return Value:
--*/ { DBG_ASSERT(i_pElement != NULL); DBG_ASSERT(i_pSetting != NULL); DBG_ASSERT(m_bInitSuccessful == true);
//
// Element Class Suffixes for which Create will be disallowed
//
static LPCWSTR const wszService = L"Service"; static const ULONG cchService = wcslen(wszService);
//
// We only care about shipped classes
//
if( i_pElement->dwExtended != SHIPPED_TO_MOF && i_pElement->dwExtended != SHIPPED_NOT_TO_MOF ) { return; }
ULONG cchElement = wcslen(i_pElement->pszClassName);
if( cchElement >= cchService && _wcsicmp(wszService, &i_pElement->pszClassName[cchElement-cchService]) == 0 ) { i_pElement->bCreateAllowed = false; i_pElement->pszParentClass = L"Win32_Service"; i_pSetting->bCreateAllowed = false; } }
HRESULT CDynSchema::RuleWmiClassInverseCCL( const METABASE_KEYTYPE* pktGroup, METABASE_KEYTYPE* pktPart) /*++
Synopsis: Adds pktGroup to pktPart's inverse container class list
Arguments: [pktGroup] - [pktPart] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(pktGroup != NULL); DBG_ASSERT(pktPart != NULL);
HRESULT hr = WBEM_S_NO_ERROR; METABASE_KEYTYPE_NODE* pktnode = NULL;
hr = m_poolKeyTypeNodes.GetNewElement(&pktnode); if(FAILED(hr)) { goto exit; }
pktnode->m_pKt = pktGroup; pktnode->m_pKtNext = pktPart->m_pKtListInverseCCL;
pktPart->m_pKtListInverseCCL = pktnode;
exit: return hr; }
HRESULT CDynSchema::RuleGroupPartAssociations( const CTableMeta *i_pTableMeta) /*++
Synopsis: Walks thru container class list to create Group/Part associations. Also calls RuleWmiClassInverseCCL for each contained class to create inverse container class list.
Arguments: [i_pTableMeta] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pTableMeta != NULL);
HRESULT hr = WBEM_S_NO_ERROR; WMI_ASSOCIATION *pWmiAssoc; WMI_CLASS *pWmiClassLeft; WMI_CLASS *pWmiClassRight;
LPWSTR wszCCL = NULL; // Needs to be cleaned up
LPWSTR wszGroupClass = NULL; // Ptr to catalog
LPWSTR wszPartClass = NULL; // Ptr to catalog
LPWSTR wszAssocName = NULL; // Ptr to pool
LPWSTR wszTemp = NULL; // Needs to be cleaned up
static LPCWSTR wszSeps = L", ";
ULONG cchGroupClass = 0; ULONG cchPartClass = 0; ULONG cchCCL = 0;
wszGroupClass = i_pTableMeta->TableMeta.pInternalName; cchGroupClass = wcslen(wszGroupClass); hr = m_hashClasses.Wmi_GetByKey(wszGroupClass, &pWmiClassLeft); if(FAILED(hr)) { goto exit; }
if(i_pTableMeta->TableMeta.pContainerClassList && i_pTableMeta->TableMeta.pContainerClassList[0] != L'\0') { //
// Make copy of CCL so we can wcstok
//
cchCCL = wcslen(i_pTableMeta->TableMeta.pContainerClassList); wszCCL = new WCHAR[cchCCL+1]; if(wszCCL == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; } memcpy(wszCCL, i_pTableMeta->TableMeta.pContainerClassList, sizeof(WCHAR)*(cchCCL+1));
//
// we will use wszTemp to construct assoc name (GroupClass_PartClass)
//
wszTemp = new WCHAR[cchGroupClass+1+cchCCL+1]; if(wszTemp == NULL) { hr = WBEM_E_OUT_OF_MEMORY; goto exit; }
for(wszPartClass = wcstok(wszCCL, wszSeps); wszPartClass != NULL; wszPartClass = wcstok(NULL, wszSeps)) { hr = m_hashClasses.Wmi_GetByKey(wszPartClass, &pWmiClassRight); if(FAILED(hr)) { //
// This just means there is a class in the container list that
// doesn't exist.
//
hr = WBEM_S_NO_ERROR; continue; }
//
// Construct association name
//
cchPartClass = wcslen(wszPartClass); memcpy(wszTemp, wszGroupClass, sizeof(WCHAR)*cchGroupClass); memcpy(wszTemp+cchGroupClass, L"_", sizeof(WCHAR)); memcpy( wszTemp + cchGroupClass + 1, wszPartClass, sizeof(WCHAR)*(cchPartClass+1));
hr = m_hashAssociations.Wmi_GetByKey(wszTemp, &pWmiAssoc); if(SUCCEEDED(hr)) { if( pWmiClassLeft->dwExtended != USER_DEFINED_TO_REPOSITORY && pWmiClassLeft->dwExtended != USER_DEFINED_NOT_TO_REPOSITORY && pWmiClassRight->dwExtended != USER_DEFINED_TO_REPOSITORY && pWmiClassRight->dwExtended != USER_DEFINED_NOT_TO_REPOSITORY ) { //
// This means we already put this shipped association in, but it is
// not a conflict.
// We need this because this method is called twice for each
// group class.
//
continue; } } hr = WBEM_S_NO_ERROR;
//
// TODO: Move this outside?
//
hr = RuleWmiClassInverseCCL(pWmiClassLeft->pkt, pWmiClassRight->pkt); if(FAILED(hr)) { goto exit; }
hr = m_spoolStrings.GetNewString( wszTemp, cchGroupClass+1+cchPartClass, // cch
&wszAssocName); if(FAILED(hr)) { goto exit; }
hr = m_poolAssociations.GetNewElement(&pWmiAssoc); if(FAILED(hr)) { goto exit; }
pWmiAssoc->pszAssociationName = wszAssocName; pWmiAssoc->pcLeft = pWmiClassLeft; pWmiAssoc->pcRight = pWmiClassRight; pWmiAssoc->pType = &WMI_ASSOCIATION_TYPE_DATA::s_Component; pWmiAssoc->fFlags = 0;
if( pWmiClassLeft->dwExtended == EXTENDED || pWmiClassLeft->dwExtended == USER_DEFINED_TO_REPOSITORY || pWmiClassRight->dwExtended == EXTENDED || pWmiClassRight->dwExtended == USER_DEFINED_TO_REPOSITORY) { pWmiAssoc->pszParentClass = g_wszExtGroupPartAssocParent; pWmiAssoc->dwExtended = USER_DEFINED_TO_REPOSITORY; } else { pWmiAssoc->pszParentClass = g_wszGroupPartAssocParent; pWmiAssoc->dwExtended = SHIPPED_TO_MOF; } hr = m_hashAssociations.Wmi_Insert(wszAssocName, pWmiAssoc); if(FAILED(hr)) { goto exit; } } }
exit: delete [] wszCCL; delete [] wszTemp; return hr; }
HRESULT CDynSchema::RuleSpecialAssociations( DWORD i_adwIgnoredProps[], WMI_CLASS* i_pElement) /*++
Synopsis: Creates IPSecurity and AdminACL associations
Arguments: [i_adwIgnoredProps[]] - [i_pElement] - Return Value:
--*/ { DBG_ASSERT(i_pElement != NULL); HRESULT hr = WBEM_S_NO_ERROR; bool bCreateIPSecAssoc = false; bool bCreateAdminACLAssoc = false; DWORD dwExtended = SHIPPED_TO_MOF;
if(i_pElement->dwExtended != SHIPPED_TO_MOF && i_pElement->dwExtended != EXTENDED && i_pElement->dwExtended != USER_DEFINED_TO_REPOSITORY) { return hr; }
if (USER_DEFINED_TO_REPOSITORY == i_pElement->dwExtended) { dwExtended = USER_DEFINED_TO_REPOSITORY; }
for(ULONG i = 0; i < g_cElemPropIgnoreList && i_adwIgnoredProps[i] != 0; i++) { if(i_adwIgnoredProps[i] == MD_IP_SEC) { bCreateIPSecAssoc = true; } else if(i_adwIgnoredProps[i] == MD_ADMIN_ACL) { bCreateAdminACLAssoc = true; } }
if(bCreateIPSecAssoc) { hr = RuleGenericAssociations( i_pElement, &WMI_CLASS_DATA::s_IPSecurity, &WMI_ASSOCIATION_TYPE_DATA::s_IPSecurity, dwExtended); if(FAILED(hr)) { return hr; } }
if(bCreateAdminACLAssoc) { hr = RuleGenericAssociations( i_pElement, &WMI_CLASS_DATA::s_AdminACL, &WMI_ASSOCIATION_TYPE_DATA::s_AdminACL, dwExtended); if(FAILED(hr)) { return hr; } }
return hr; }
HRESULT CDynSchema::ConstructFlatInverseContainerList() /*++
Synopsis: Constructs an "inverse flat container class list". This list is stored in m_abKtContainers, an array of size iNumKeys*iNumKeys. The first iNumKeys entries are for Key #1 and then so on. Let's call this row 1. In row 1, entry i corresponds to Key #i. This entry [1,i] is set to true if Key #1 can be contained somewhere under Key #i. For instance, [IIsWebDirectory, IIsWebService] is true since an IIsWebService can contain an IIsWebServer which can contain an IIsWebDirectory.
Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true);
ULONG iNumKeys = m_hashKeyTypes.Wmi_GetNumElements();
m_abKtContainers = new bool[iNumKeys * iNumKeys]; if(m_abKtContainers == NULL) { return WBEM_E_OUT_OF_MEMORY; }
memset(m_abKtContainers, 0, iNumKeys * iNumKeys * sizeof(bool));
CHashTable<METABASE_KEYTYPE*>::iterator iter; CHashTable<METABASE_KEYTYPE*>::iterator iterEnd = m_hashKeyTypes.end(); for (iter = m_hashKeyTypes.begin(); iter != iterEnd; ++iter) { CHashTable<METABASE_KEYTYPE*>::Record* pRec = iter.Record(); METABASE_KEYTYPE_NODE* pktnode = pRec->m_data->m_pKtListInverseCCL; while(pktnode != NULL) { ConstructFlatInverseContainerListHelper( pktnode->m_pKt, &m_abKtContainers[pRec->m_idx * iNumKeys]); pktnode = pktnode->m_pKtNext; } }
return WBEM_S_NO_ERROR; }
//
// TODO: Prove this will always terminate.
//
void CDynSchema::ConstructFlatInverseContainerListHelper( const METABASE_KEYTYPE* i_pkt, bool* io_abList) /*++
Synopsis: This walks the inverse container class list of i_pkt. For each entry, we call ConstructFlatInverseContainerListHelper and mark all the keytypes we see on the way. We terminate when we hit a keytype we've already seen or if there are no more keytypes in the inverse container class list.
Arguments: [i_pkt] - [io_abList] - --*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pkt != NULL); DBG_ASSERT(io_abList != NULL);
ULONG idx; METABASE_KEYTYPE* pktDummy; HRESULT hr = WBEM_S_NO_ERROR;
hr = m_hashKeyTypes.Wmi_GetByKey(i_pkt->m_pszName, &pktDummy, &idx); if(FAILED(hr)) { DBG_ASSERT(false && "Keytype should be in hashtable of keytypes"); return; } if(io_abList[idx] == true) return;
io_abList[idx] = true;
METABASE_KEYTYPE_NODE* pktnode = i_pkt->m_pKtListInverseCCL; while(pktnode != NULL) { ConstructFlatInverseContainerListHelper(pktnode->m_pKt, io_abList); pktnode = pktnode->m_pKtNext; } }
bool CDynSchema::IsContainedUnder(METABASE_KEYTYPE* i_pktParent, METABASE_KEYTYPE* i_pktChild) /*++
Synopsis: Uses m_abKtContainers described above to determine whether i_pktChild can be contained somewhere under i_pktParent.
Arguments: [i_pktParent] - [i_pktChild] - Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pktParent != NULL); DBG_ASSERT(i_pktChild != NULL);
HRESULT hr = WBEM_S_NO_ERROR; METABASE_KEYTYPE* pktDummy; ULONG idxParent; ULONG idxChild;
hr = m_hashKeyTypes.Wmi_GetByKey(i_pktParent->m_pszName, &pktDummy, &idxParent); if(FAILED(hr)) { return false; } hr = m_hashKeyTypes.Wmi_GetByKey(i_pktChild->m_pszName, &pktDummy, &idxChild); if(FAILED(hr)) { return false; }
return m_abKtContainers[idxChild * m_hashKeyTypes.Wmi_GetNumElements() + idxParent]; }
void CDynSchema::ToConsole() { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true);
/*CHashTableElement<WMI_CLASS *>* pElement;
m_hashClasses.Enum(NULL, &pElement); while(pElement != NULL) { wprintf(L"%s\n", pElement->m_data->pszClassName); // wprintf(L"\tShipped: %d\n", pElement->m_iShipped);
wprintf(L"\tKT: %s\n", pElement->m_data->pkt->m_pszName); wprintf(L"\tKN: %s\n", pElement->m_data->pszKeyName); wprintf(L"\tMK: %s\n", pElement->m_data->pszMetabaseKey); METABASE_PROPERTY** ppmbp = pElement->m_data->ppmbp; for(ULONG q = 0; ppmbp != NULL && ppmbp[q] != NULL; q++) { wprintf(L"\tProp: %s\n", ppmbp[q]->pszPropName); } pElement = pElement->m_pNext; }
ULONG i;
m_hashKeyTypes.ToConsole();
WMI_CLASS *pWmiClass; for(i = 0; i < m_poolClasses.GetUsed(); i++) { pWmiClass = m_poolClasses.Lookup(i); wprintf( L"%s KT: %d\n", pWmiClass->pszClassName, pWmiClass->pkt ); for(ULONG j = 0; ; j++) { if(pWmiClass->ppmbp[j] == NULL) { break; } wprintf(L"\t%s\tId: %d\tUT: %d\tDT: %d\tMSK: %d\tAttr: %d\tRO: %d\n", pWmiClass->ppmbp[j]->pszPropName, pWmiClass->ppmbp[j]->dwMDIdentifier, pWmiClass->ppmbp[j]->dwMDUserType, pWmiClass->ppmbp[j]->dwMDDataType, pWmiClass->ppmbp[j]->dwMDMask, pWmiClass->ppmbp[j]->dwMDAttributes, pWmiClass->ppmbp[j]->fReadOnly); } } WMI_ASSOCIATION *pWmiAssoc; for(i = 0; i < m_poolAssociations.GetUsed(); i++) { pWmiAssoc = m_poolAssociations.Lookup(i); wprintf(L"%s\n", pWmiAssoc->pszAssociationName); wprintf(L"\t%s\n\t%s\n", pWmiAssoc->pcLeft->pszClassName, pWmiAssoc->pcRight->pszClassName); }
for(unsigned int q = 0; q < m_poolProps.GetUsed(); q++) { METABASE_PROPERTY* qt = m_poolProps.Lookup(q); wprintf(L"%s\n", qt->pszPropName); }*/ }
HRESULT CDynSchema::RulePopulateFromDynamic( CSchemaExtensions* i_pCatalog, BOOL i_bUserDefined) { DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pCatalog != NULL);
HRESULT hr = WBEM_S_NO_ERROR; ULONG i = 0; CTableMeta* pTableMeta = NULL; WMI_CLASS* pElementClass = NULL; WMI_CLASS* pSettingClass = NULL; DWORD adwIgnoredProps[g_cElemPropIgnoreList];
DWORD dwUserDefined = 0;
while(pTableMeta = i_pCatalog->EnumTables(&i)) { dwUserDefined = (fTABLEMETA_USERDEFINED & *pTableMeta->TableMeta.pSchemaGeneratorFlags); if( (i_bUserDefined && !dwUserDefined) || (!i_bUserDefined && dwUserDefined) ) { continue; }
memset(adwIgnoredProps, 0, g_cElemPropIgnoreList*sizeof(DWORD)); pElementClass = NULL; pSettingClass = NULL;
hr = RuleKeyType(pTableMeta); if(FAILED(hr)) { return hr; }
DBG_ASSERT(pTableMeta->TableMeta.pInternalName); hr = RuleWmiClass( pTableMeta, &pElementClass, &pSettingClass, adwIgnoredProps, i_bUserDefined); if(FAILED(hr)) { return hr; } DBG_ASSERT(pElementClass != NULL); DBG_ASSERT(pSettingClass != NULL);
if ( (NULL == pElementClass) || (NULL == pSettingClass) ) { return E_FAIL; }
hr = RuleGenericAssociations( pElementClass, pSettingClass, &WMI_ASSOCIATION_TYPE_DATA::s_ElementSetting, pElementClass->dwExtended); if(FAILED(hr)) { return hr; }
hr = RuleSpecialAssociations( adwIgnoredProps, pElementClass); if(FAILED(hr)) { return hr; }
RuleWmiClassServices(pElementClass, pSettingClass);
hr = RuleWmiClassDescription(pTableMeta, pElementClass, pSettingClass); if(FAILED(hr)) { return hr; } }
i = 0; while(pTableMeta = i_pCatalog->EnumTables(&i)) { dwUserDefined = (fTABLEMETA_USERDEFINED & *pTableMeta->TableMeta.pSchemaGeneratorFlags);
if(!i_bUserDefined && dwUserDefined) { continue; }
hr = RuleGroupPartAssociations(pTableMeta); if(FAILED(hr)) { return hr; } }
return hr; }
HRESULT CDynSchema::RunRules( CSchemaExtensions* i_pCatalog, bool i_bUseExtensions) /*++
Synopsis: Does all the work
Arguments: [i_pCatalog] - This function calls Initialize. Don't call Init outside this function. Return Value:
--*/ { DBG_ASSERT(m_bInitCalled == true); DBG_ASSERT(m_bInitSuccessful == true); DBG_ASSERT(i_pCatalog != NULL);
HRESULT hr = S_OK; ULONG i = 0;
//
// TODO: Don't think I need this
//
if(m_bRulesRun) { return hr; }
hr = RulePopulateFromStatic(); if(FAILED(hr)) { return hr; }
hr = Rule2PopulateFromStatic(); if(FAILED(hr)) { return hr; }
hr = i_pCatalog->Initialize(i_bUseExtensions); if(FAILED(hr)) { return hr; }
hr = RulePopulateFromDynamic( i_pCatalog, false); // shipped schema
if(FAILED(hr)) { return hr; } hr = RulePopulateFromDynamic( i_pCatalog, true); // user-defined schema
if(FAILED(hr)) { return hr; }
hr = ConstructFlatInverseContainerList();
if(SUCCEEDED(hr)) { m_bRulesRun = true; }
return hr; }
|