Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2139 lines
69 KiB

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
SaveSchema.cpp
Abstract:
Implementation of the helper functions that are used to determine
if a schema compilation is needed, and if needed they invoke the
appropriate classes to create a schema extensions file
(MD_SCHEMA_EXTENSION_FILE_NAMEW), that contains the schema extension
descriptions, and invoke a schema compile to generate the schema bin format.
Author:
Varsha Jayasimha (varshaj) 30-Nov-1999
Revision History:
--*/
#include "precomp.hxx"
#define cMaxContainedClass 75
#define cMaxProperty 250
int _cdecl MyCompareStrings(const void *a,
const void *b)
{
return _wcsicmp(*(LPWSTR*)a, *(LPWSTR*)b);
}
/***************************************************************************++
Routine Description:
Helper function used by qsort. Compares to strings, but compares it only
up until the first comma.
--***************************************************************************/
int _cdecl MyCompareCommaDelimitedStrings(const void *a,
const void *b)
{
LPWSTR wszStringAStart = ((DELIMITEDSTRING*)a)->pwszStringStart;
LPWSTR wszStringBStart = ((DELIMITEDSTRING*)b)->pwszStringStart;
LPWSTR wszStringAEnd = ((DELIMITEDSTRING*)a)->pwszStringEnd;
LPWSTR wszStringBEnd = ((DELIMITEDSTRING*)b)->pwszStringEnd;
int iret = 0;
SIZE_T cchA = wszStringAEnd - wszStringAStart;
SIZE_T cchB = wszStringBEnd - wszStringBStart;
//
// Do not attempt to null terminate the string because you may be
// hitting a read-only page.
//
iret = _wcsnicmp(wszStringAStart, wszStringBStart, __min(cchA, cchB));
if((0 == iret) &&
(cchA != cchB)
)
{
iret = cchA < cchB ? -1 : 1;
}
return iret;
}
/***************************************************************************++
Routine Description:
Gets the global helper object that has the pointer to the meta tables.
Arguments:
[in] Bool that indicates whether to fail or not.
Return Value:
HRESULT
--***************************************************************************/
HRESULT InitializeGlobalISTHelper(BOOL i_bFailIfBinFileAbsent)
{
return ::GetGlobalHelper(i_bFailIfBinFileAbsent,
&g_pGlobalISTHelper);
}
void ReleaseGlobalISTHelper()
{
if(NULL != g_pGlobalISTHelper)
{
delete g_pGlobalISTHelper;
g_pGlobalISTHelper = NULL;
}
}
/***************************************************************************++
Routine Description:
This function saves the schema only if something has changed in the schema
since the last save.
Arguments:
[in] Schema file name.
[in] Security attributes for the file.
Return Value:
HRESULT
--***************************************************************************/
HRESULT SaveSchemaIfNeeded(LPCWSTR i_wszSchemaFileName,
PSECURITY_ATTRIBUTES i_pSecurityAtrributes)
{
HRESULT hr = S_OK;
if(NULL == g_pGlobalISTHelper)
{
//
// g_pGlobalISTHelper will not be initialized if
// ReadAllDataFromXML is not called. This can happen
// during an upgrade scneario i.e IIS5.0/5.1 to IIS6.0
// We attempt to initialize it here. Note that we do
// not fail if bin file is absent - just go with
// the shipped schema.
//
BOOL bFailIfBinFileAbsent = FALSE;
hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
}
if(g_dwSchemaChangeNumber != g_dwLastSchemaChangeNumber)
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchemaIfNeeded] Calling SaveSchema. Last save schema change number: %d. Current schema change number: %d.\n",
g_dwLastSchemaChangeNumber,
g_dwSchemaChangeNumber));
hr = SaveSchema(i_wszSchemaFileName,
i_pSecurityAtrributes);
if(SUCCEEDED(hr))
{
g_dwLastSchemaChangeNumber = g_dwSchemaChangeNumber;
//
// SaveSchema will reinitialize the GlobalISTHelper if the schema has changed.
//
DBGINFOW((DBG_CONTEXT,
L"[SaveSchemaIfNeeded] Done Saving schema. Updating last save schema change number to: %d. Current schema change number: %d.\n",
g_dwLastSchemaChangeNumber,
g_dwSchemaChangeNumber));
}
}
else
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchemaIfNeeded] No need saving schema because schema has not changed since last save. Last save schema change number: %d. Current schema change number: %d.\n",
g_dwLastSchemaChangeNumber,
g_dwSchemaChangeNumber));
}
return hr;
}
/***************************************************************************++
Routine Description:
This function saves the schema and compiles schema information into the
bin file.
Arguments:
[in] Schema file name.
[in] Security attributes for the file.
Return Value:
HRESULT
--***************************************************************************/
HRESULT SaveSchema(LPCWSTR i_wszSchemaFileName,
PSECURITY_ATTRIBUTES i_pSecurityAtrributes)
{
HRESULT hr;
CMDBaseObject* pObjSchema = NULL;
CMDBaseObject* pObjProperties = NULL;
CWriter* pCWriter = NULL;
CMBSchemaWriter* pSchemaWriter = NULL;
LPWSTR wszSchema = L"Schema";
LPWSTR wszProperties = L"Properties";
ISimpleTableDispenser2* pISTDisp = NULL;
IMetabaseSchemaCompiler* pCompiler = NULL;
//
// Get a pointer to the compiler to get the bin file name.
//
hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",hr));
goto exit;
}
hr = pISTDisp->QueryInterface(IID_IMetabaseSchemaCompiler,
(LPVOID*)&pCompiler);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] QueryInterface on compiler failed with hr = 0x%x.\n",hr));
goto exit;
}
//
// Get the Properties object
//
pObjSchema = g_pboMasterRoot->GetChildObject((LPSTR&)wszSchema,
&hr,
TRUE);
if(FAILED(hr) || (NULL == pObjSchema))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to open /Schema. GetChildObject failed with hr = 0x%x.\n",hr));
goto exit;
}
pObjProperties = pObjSchema->GetChildObject((LPSTR&)wszProperties,
&hr,
TRUE);
if(FAILED(hr) || (NULL == pObjProperties))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to open /Schema/Properties. GetChildObject failed with hr = 0x%x.\n",hr));
goto exit;
}
//
// Create the writer object
//
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Initializing writer with write file: %s bin file: %s.\n",
g_wszSchemaExtensionFile,
g_pGlobalISTHelper->m_wszBinFileForMeta));
//
// Assert the g_GlobalISTHelper are valid
//
MD_ASSERT(g_pGlobalISTHelper != NULL);
pCWriter = new CWriter();
if(NULL == pCWriter)
{
hr = E_OUTOFMEMORY;
}
else
{
//
// Bug #512868 If someone had attrib-ed an existing extenstion file
// be read-only then we could land up in a state where we will not be
// able to recreate the extensions file. Hence attrib the extensions
// file to be read-write if it exists. An extensions file can be
// around only if a previous compile has failed.
//
ResetFileAttributesIfNeeded((LPTSTR)g_wszSchemaExtensionFile,
TRUE);
hr = pCWriter->Initialize(g_wszSchemaExtensionFile,
g_pGlobalISTHelper,
NULL);
}
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving schema tree. Cannot initialize writer. Failed with hr = 0x%x.\n", hr));
goto exit;
}
//
// First create the IIsConfigObject collection
//
hr = CreateIISConfigObjectCollection(pObjProperties,
pCWriter,
&pSchemaWriter);
if(FAILED(hr))
{
goto exit;
}
//
// Create all other collections
//
hr = CreateNonIISConfigObjectCollections(pObjSchema,
pCWriter,
&pSchemaWriter);
if(FAILED(hr))
{
goto exit;
}
if(pSchemaWriter)
{
//
// If pSchemaWriter has a valid Value, then some extensions were found - write it.
//
hr = pCWriter->BeginWrite(eWriter_Schema,
i_pSecurityAtrributes);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving schema tree. CWriter::BeginWrite failed with hr = 0x%x.\n", hr));
goto exit;
}
hr = pSchemaWriter->WriteSchema();
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving schema tree. CMBSchemaWriter::WriteSchema. Failed with hr = 0x%x.\n", hr));
goto exit;
}
hr = pCWriter->EndWrite(eWriter_Schema);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving schema tree. CWriter::EndWrite Failed with hr = 0x%x.\n", hr));
goto exit;
}
//
// Trigger compilation
//
//
// Must close the file prior to calling compile schema, else will get a sharing violation.
//
delete pCWriter;
pCWriter = NULL;
hr = CompileIntoBin(pCompiler,
g_wszSchemaExtensionFile,
i_wszSchemaFileName);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] CompileSchema from %s failed with hr = 0x%x.\n",
g_wszSchemaExtensionFile, hr));
}
else
{
if(!DeleteFileW(g_wszSchemaExtensionFile))
{
hr = HRESULT_FROM_WIN32(GetLastError());
DBGINFOW((DBG_CONTEXT,
L"[CompileIfNeeded] Compile from schema extensions file: %s succeeded, but cannot cleanup the extensions file:%s. Delete file failed with hr = 0x%x.\n",
g_wszSchemaExtensionFile,
g_wszSchemaExtensionFile,
hr));
hr = S_OK;
}
goto exit;
}
}
else
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] No extensions found. - Either schema tree was changed, but no extensions added, or all extensions were deleted.\n"));
}
//
// If you reach here it means that:
// A. Schema changes occured to the in-memory /Schema tree, but either
// there were no extensions or all extensions were deleted.
// (This is inferred when pSchemaWriter in NULL)
// or
// B. Schema compile failed.
// For A: Compile from shipped schema.
// For B: Check for an existing schema file. If found make sure that the
// bin file is valid. If bin file is not valid try compiling from the
// schema file. If schema file is not found, compile from shipped schema.
//
if(pSchemaWriter)
{
//
// This is case B.
//
if(-1 != GetFileAttributesW(i_wszSchemaFileName))
{
if(NULL == g_pGlobalISTHelper)
{
BOOL bFailIfBinFileAbsent = TRUE;
hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
if(SUCCEEDED(hr))
{
goto exit;
}
else
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to get the the bin file name. (Assuming file missing or invalid). InitializeGlobalISTHelper failed with hr = 0x%x.\n",hr));
}
}
else
{
//
// Schema file present and valid - goto exit
// As long as we have a valid g_pGlobalISTHelper, it holds on
// to a reference to the bin file and the bin file cannot be
// invalidated.
//
goto exit;
}
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Compiling from schema file %s\n", i_wszSchemaFileName));
hr = CompileIntoBinFromSchemaFile(pCompiler,
i_wszSchemaFileName);
if(SUCCEEDED(hr))
{
goto exit;
}
}
}
//
// If you reach here it is either case A or the last part of case B.
// Recreate from shipped schema
//
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Schema file not found. Compiling from shipped schema\n"));
hr = CompileIntoBin(pCompiler,
NULL,
i_wszSchemaFileName);
exit:
if(SUCCEEDED(hr))
{
if(NULL == g_pGlobalISTHelper)
{
BOOL bFailIfBinFileAbsent = TRUE;
hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to get the the bin file name. (Assuming file is invalid). InitializeGlobalISTHelper failed with hr = 0x%x.\n",hr));
}
}
if(SUCCEEDED(hr))
{
hr = UpdateTimeStamp((LPWSTR)i_wszSchemaFileName,
g_pGlobalISTHelper->m_wszBinFileForMeta);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[CompileIfNeeded] UpdateTimeStamp failed with hr = 0x%x.\n",hr));
}
}
}
if(NULL != pSchemaWriter)
{
delete pSchemaWriter;
}
if(NULL != pCWriter)
{
delete pCWriter;
}
if(NULL != pCompiler)
{
pCompiler->Release();
}
if(NULL != pISTDisp)
{
pISTDisp->Release();
}
return hr;
}
/***************************************************************************++
Routine Description:
This function creates the non-IIsConfigObject collection *extensions* to
the schema.
Arguments:
[in] Object that contains the schema tree.
[in] The writter object.
[in,out] The schema object - this gets created if it is not already created
Return Value:
HRESULT
--***************************************************************************/
HRESULT CreateNonIISConfigObjectCollections(CMDBaseObject* i_pObjSchema,
CWriter* i_pCWriter,
CMBSchemaWriter** io_pSchemaWriter)
{
CMDBaseObject* pObjClasses = NULL;
CMDBaseObject* pObjClass = NULL;
DWORD dwEnumClassIndex = 0;
static LPCWSTR wszSeparator = L",";
LPWSTR wszClasses = L"Classes";
HRESULT hr = S_OK;
//
// Open the Classes key
//
pObjClasses = i_pObjSchema->GetChildObject((LPSTR&)wszClasses,
&hr,
TRUE);
if(FAILED(hr) || (NULL == pObjClasses))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to open /Schema/Classes. GetChildObject failed with hr = 0x%x.\n",hr));
return hr;
}
for(dwEnumClassIndex=0,
pObjClass=pObjClasses->EnumChildObject(dwEnumClassIndex++);
(SUCCEEDED(hr)) && (pObjClass!=NULL);
pObjClass=pObjClasses->EnumChildObject(dwEnumClassIndex++))
{
//
// Save all the properties for this class in temp variables
//
LPCWSTR wszOptProp = NULL;
LPCWSTR wszMandProp = NULL;
LPCWSTR wszContainedClassList = NULL;
BOOL bContainer = FALSE;
BOOL* pbContainer = &bContainer;
LPCWSTR wszClassName = (LPCWSTR)pObjClass->GetName(TRUE);
CMBCollectionWriter* pCollectionWriter = NULL;
CMDBaseData* pObjData = NULL;
DWORD dwEnumIndex = 0;
for(dwEnumIndex=0,
pObjData=pObjClass->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA);
(SUCCEEDED(hr)) && (pObjData!=NULL);
pObjData=pObjClass->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA))
{
DWORD dwID = pObjData->GetIdentifier();
if(MD_SCHEMA_CLASS_OPT_PROPERTIES == dwID)
{
wszOptProp = (LPCWSTR)pObjData->GetData(TRUE);
}
else if(MD_SCHEMA_CLASS_MAND_PROPERTIES == dwID)
{
wszMandProp = (LPCWSTR)pObjData->GetData(TRUE);
}
else if(dwID == MD_SCHEMA_CLASS_CONTAINER)
{
pbContainer = (BOOL*)pObjData->GetData(TRUE);
}
else if(dwID == MD_SCHEMA_CLASS_CONTAINMENT)
{
wszContainedClassList = (LPCWSTR)pObjData->GetData(TRUE);
}
}
//
// Get collection writer for IIsConfigObject
//
// DBGINFOW((DBG_CONTEXT,
// L"[CreateNonIISConfigObjectCollections] Class %s Mand Prop:%s. Opt Prop: %s\n",
// wszClassName,
// wszMandProp,
// wszOptProp));
// Assert that pbContainer is non-null.
MD_ASSERT(pbContainer != NULL);
if(ClassDiffersFromShippedSchema(wszClassName,
*pbContainer,
(LPWSTR)wszContainedClassList) ||
ClassPropertiesDifferFromShippedSchema(wszClassName,
(LPWSTR)wszOptProp,
(LPWSTR)wszMandProp)
)
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Saving collection: %s.\n",wszClassName));
hr = GetCollectionWriter(i_pCWriter,
io_pSchemaWriter,
&pCollectionWriter,
wszClassName,
*pbContainer,
wszContainedClassList);
if(FAILED(hr))
{
return hr;
}
hr = ParseAndAddPropertiesToNonIISConfigObjectCollection(wszOptProp,
FALSE,
pCollectionWriter);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving classes tree. Could not add optional properties %s for class %s failed with hr = 0x%x.\n",wszOptProp, wszClassName, hr));
return hr;
}
hr = ParseAndAddPropertiesToNonIISConfigObjectCollection(wszMandProp,
TRUE,
pCollectionWriter);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving classes tree. Could not add manditory properties %s for class %s failed with hr = 0x%x.\n",wszMandProp, wszClassName, hr));
return hr;
}
}
}
return hr;
}
/***************************************************************************++
Routine Description:
It parses the list of properties and adds it to a Non_IIsConfigObject
collection.
Arguments:
[in] List of properties
[in] Bool that indicates manditory or optional.
[in,out] The collection object - this gets created if it is not already created
Return Value:
HRESULT
--***************************************************************************/
HRESULT
ParseAndAddPropertiesToNonIISConfigObjectCollection(LPCWSTR i_wszProperties,
BOOL i_bManditory,
CMBCollectionWriter* i_pCollectionWriter)
{
CMBPropertyWriter *pProperty = NULL;
HRESULT hr = S_OK;
static WCHAR wchSeparator = L',';
WCHAR* pwszStartProperty = NULL;
WCHAR* pwszEndProperty = NULL;
if(NULL == i_wszProperties || 0 == *i_wszProperties)
{
return S_OK;
}
pwszStartProperty = (LPWSTR)i_wszProperties;
for ( ; ; )
{
pwszEndProperty = wcschr(pwszStartProperty, wchSeparator);
if(0 != *pwszStartProperty)
{
hr = i_pCollectionWriter->GetMBPropertyWriter(pwszStartProperty,
i_bManditory,
&pProperty);
if(FAILED(hr))
{
return hr;
}
}
if(NULL != pwszEndProperty)
{
pwszStartProperty = ++pwszEndProperty;
}
else
{
break;
}
}
return hr;
}
/***************************************************************************++
Routine Description:
Looks up the schema and determines if a property is in the shipped
schema or not.
Arguments:
[in] Writer object.
[in] property id.
Return Value:
HRESULT
--***************************************************************************/
BOOL PropertyNotInShippedSchema(CWriter* i_pCWriter,
DWORD i_dwIdentifier)
{
HRESULT hr = S_OK;
ULONG aColSearch[] = {iCOLUMNMETA_Table,
iCOLUMNMETA_ID
};
ULONG cColSearch = sizeof(aColSearch)/sizeof(ULONG);
LPVOID apvSearch[cCOLUMNMETA_NumberOfColumns];
apvSearch[iCOLUMNMETA_Table] = (LPVOID)i_pCWriter->m_pCWriterGlobalHelper->m_wszTABLE_IIsConfigObject;
apvSearch[iCOLUMNMETA_ID] = (LPVOID)&i_dwIdentifier;
BOOL bPropertyNotInShippedSchema = TRUE;
ULONG iRow = 0;
ULONG iStartRow = 0;
ULONG iCol = iCOLUMNMETA_SchemaGeneratorFlags;
DWORD* pdwMetaFlagsEx = NULL;
hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTColumnMetaByTableAndID->GetRowIndexBySearch(iStartRow,
cColSearch,
aColSearch,
NULL,
apvSearch,
&iRow);
if(SUCCEEDED(hr))
{
hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTColumnMetaByTableAndID->GetColumnValues(iRow,
1,
&iCol,
NULL,
(LPVOID*)&pdwMetaFlagsEx);
if(SUCCEEDED(hr) && (((*pdwMetaFlagsEx)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
{
bPropertyNotInShippedSchema = FALSE;
}
}
if(E_ST_NOMOREROWS == hr)
{
//
// See if property is a shipped tag.
//
bPropertyNotInShippedSchema = TagNotInShippedSchema(i_pCWriter,
i_dwIdentifier);
}
else if(FAILED(hr))
{
//
// Trace a message saying internal catalog error
//
DBGINFOW((DBG_CONTEXT,
L"[PropertyNotInShippedSchema] Internal catalog error. Could not determine if property was not in shipped schema. Assuming it is not. hr = 0x%x.\n", hr));
}
return bPropertyNotInShippedSchema;
} // PropertyNotInShippedSchema
/***************************************************************************++
Routine Description:
Looks up the schema and determines if a tag is in the shipped
schema or not.
Arguments:
[in] Writer object.
[in] property id.
Return Value:
HRESULT
--***************************************************************************/
BOOL TagNotInShippedSchema(CWriter* i_pCWriter,
DWORD i_dwIdentifier)
{
HRESULT hr = S_OK;
ULONG aColSearch[] = {iTAGMETA_Table,
iTAGMETA_ID
};
ULONG cColSearch = sizeof(aColSearch)/sizeof(ULONG);
LPVOID apvSearch[cCOLUMNMETA_NumberOfColumns];
BOOL bTagNotInShippedSchema = TRUE;
ULONG iStartRow = 0;
ULONG iColIndex = iTAGMETA_ColumnIndex;
DWORD* pdwColIndex = NULL;
apvSearch[iTAGMETA_Table] = (LPVOID)g_pGlobalISTHelper->m_wszTABLE_IIsConfigObject;
apvSearch[iTAGMETA_ID] = (LPVOID)&i_dwIdentifier;
hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTTagMetaByTableAndID->GetRowIndexBySearch(iStartRow,
cColSearch,
aColSearch,
NULL,
apvSearch,
&iStartRow);
if(SUCCEEDED(hr))
{
hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTTagMetaByTableAndID->GetColumnValues(iStartRow,
1,
&iColIndex,
NULL,
(LPVOID*)&pdwColIndex);
if(SUCCEEDED(hr))
{
//
// Lookup the property to see if it is shipped.
//
LPVOID a_Identity[] = {(LPVOID)g_pGlobalISTHelper->m_wszTABLE_IIsConfigObject,
(LPVOID)pdwColIndex
};
ULONG iRow=0;
hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetRowIndexByIdentity(NULL,
a_Identity,
&iRow);
if(SUCCEEDED(hr))
{
DWORD* pdwExtended = NULL;
ULONG iColPropertyMetaFlagsEx = iCOLUMNMETA_SchemaGeneratorFlags;
hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(iRow,
1,
&iColPropertyMetaFlagsEx,
NULL,
(LPVOID*)&pdwExtended);
if(SUCCEEDED(hr) && (((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
{
//
// Found at least one property that is not in the shipped schema
//
bTagNotInShippedSchema = FALSE;
}
//
// Else condition means it failed or it was a shipped property
// if(FAILED(hr) || ( (((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) != 0))
//
}
}
} // If GetRowIndexBySearch succeeds
return bTagNotInShippedSchema;
} // TagNotInShippedSchema
/***************************************************************************++
Routine Description:
Looks up the schema and determines if a class has any extensions or if it
an extended (ie new) class.
Arguments:
[in] Class name
[in] Container class or not.
[in] Container class list.
Return Value:
HRESULT
--***************************************************************************/
BOOL ClassDiffersFromShippedSchema(LPCWSTR i_wszClassName,
BOOL i_bIsContainer,
LPWSTR i_wszContainedClassList)
{
HRESULT hr = S_OK;
BOOL bClassDiffersFromShippedSchema = TRUE;
ULONG aiCol [] = {iTABLEMETA_SchemaGeneratorFlags,
iTABLEMETA_ContainerClassList
};
ULONG cCol = sizeof(aiCol)/sizeof(ULONG);
LPVOID apv[cTABLEMETA_NumberOfColumns];
ULONG iRow = 0;
hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetRowIndexByIdentity(NULL,
(LPVOID*)&i_wszClassName,
&iRow);
if(SUCCEEDED(hr))
{
hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetColumnValues(iRow,
cCol,
aiCol,
NULL,
apv);
if(SUCCEEDED(hr))
{
if(((*(DWORD*)apv[iTABLEMETA_SchemaGeneratorFlags]) & (fTABLEMETA_EXTENDED|fTABLEMETA_USERDEFINED)) == 0)
{
if(MatchClass(i_bIsContainer,
i_wszContainedClassList,
apv)
)
{
bClassDiffersFromShippedSchema = FALSE;
}
}
}
else
{
//
// Trace a message saying internal catalog error
//
DBGINFOW((DBG_CONTEXT,
L"[ClassDiffersFromShippedSchema] Internal catalog error. Could not determine if class was not in shipped schema. Assuming it is not. hr = 0x%x.\n", hr));
}
}
else if(E_ST_NOMOREROWS != hr)
{
//
// Trace a message saying internal catalog error
//
DBGINFOW((DBG_CONTEXT,
L"[ClassDiffersFromShippedSchema] Internal catalog error. Could not determine if class was not in shipped schema. Assuming it is not. hr = 0x%x.\n", hr));
}
return bClassDiffersFromShippedSchema;
} // ClassDiffersFromShippedSchema
/***************************************************************************++
Routine Description:
Looks up the schema and matches a class.
Arguments:
[in] Container class or not.
[in] Container class list.
[in] Class attributes.
Return Value:
HRESULT
--***************************************************************************/
BOOL MatchClass(BOOL i_bIsContainer,
LPWSTR i_wszContainedClassList,
LPVOID* i_apv)
{
BOOL bMatch = TRUE;
DWORD fIsContained = (*(DWORD*)i_apv[iTABLEMETA_SchemaGeneratorFlags]) & fTABLEMETA_CONTAINERCLASS;
//
// Compare the container property 1st and only if they equal compare the container class list
//
if( i_bIsContainer &&
(fIsContained != fTABLEMETA_CONTAINERCLASS)
)
{
bMatch = FALSE;
}
else if (!i_bIsContainer &&
(fIsContained == fTABLEMETA_CONTAINERCLASS)
)
{
bMatch = FALSE;
}
else
{
bMatch = MatchCommaDelimitedStrings(i_wszContainedClassList,
(LPWSTR)i_apv[iTABLEMETA_ContainerClassList]);
}
return bMatch;
} // MatchClass
/***************************************************************************++
Routine Description:
Checks to see if two comma delimited strings match.
Arguments:
[in] Comma delimited string.
[in] Comma delimited string.
Return Value:
HRESULT
--***************************************************************************/
BOOL MatchCommaDelimitedStrings(LPWSTR i_wszString1,
LPWSTR i_wszString2)
{
BOOL bMatch = FALSE;
DELIMITEDSTRING aStringFixed1[cMaxContainedClass];
DELIMITEDSTRING aStringFixed2[cMaxContainedClass];
DELIMITEDSTRING* aString1 = aStringFixed1;
DELIMITEDSTRING* aString2 = aStringFixed2;
ULONG cString1 = cMaxContainedClass;
ULONG cString2 = cMaxContainedClass;
ULONG iString1 = 0;
ULONG iString2 = 0;
BOOL bReAlloced1 = FALSE;
BOOL bReAlloced2 = FALSE;
HRESULT hr = S_OK;
if(NULL == i_wszString1 || 0 == *i_wszString1)
{
if(NULL == i_wszString2 || 0 == *i_wszString2)
{
bMatch = TRUE;
}
}
else if(NULL == i_wszString2 || 0 == *i_wszString2)
{
bMatch = FALSE; // Means i_wszString1 != NULL and i_wszString2 == NULL
}
else if(wcscmp(i_wszString1, i_wszString2) == 0)
{
bMatch = TRUE;
}
else
{
//
// Construct an array of individual strings
// and compare the array
//
hr = CommaDelimitedStringToArray(i_wszString1,
&aString1,
&iString1,
&cString1,
&bReAlloced1);
if(FAILED(hr))
{
goto exit;
}
hr = CommaDelimitedStringToArray(i_wszString2,
&aString2,
&iString2,
&cString2,
&bReAlloced2);
if(FAILED(hr))
{
goto exit;
}
bMatch = MatchDelimitedStringArray(aString1,
iString1,
aString2,
iString2);
}
exit:
if(aString1 != aStringFixed1)
{
delete [] aString1;
}
if(aString2 != aStringFixed2)
{
delete [] aString2;
}
return bMatch;
} // MatchCommaDelimitedStrings
/***************************************************************************++
Routine Description:
Converts a comma delimited string to an array.
Arguments:
[in] Comma delimited string.
[in,out] Array.
[in,out] Current index in the array.
[in,out] Max count of the array. (i.e. max it can hold)
[in,out] Bool which indecates if the array has been realloced.
Return Value:
HRESULT
--***************************************************************************/
HRESULT CommaDelimitedStringToArray(LPWSTR i_wszString,
DELIMITEDSTRING** io_apDelimitedString,
ULONG* io_piDelimitedString,
ULONG* io_pcMaxDelimitedString,
BOOL* io_pbReAlloced)
{
LPWSTR wszSubStringStart = NULL;
LPWSTR wszSubStringEnd = NULL;
HRESULT hr = S_OK;
wszSubStringStart = i_wszString;
while(NULL != wszSubStringStart)
{
DELIMITEDSTRING DelimitedString;
wszSubStringEnd = wcschr(wszSubStringStart, L',');
DelimitedString.pwszStringStart = wszSubStringStart;
if(NULL != wszSubStringEnd)
{
DelimitedString.pwszStringEnd = wszSubStringEnd;
}
else
{
// Point to the terminating NULL.
DelimitedString.pwszStringEnd = wszSubStringStart + wcslen(wszSubStringStart);
}
hr = AddDelimitedStringToArray(&DelimitedString,
io_piDelimitedString,
io_pcMaxDelimitedString,
io_pbReAlloced,
io_apDelimitedString);
if(FAILED(hr))
{
return hr;
}
if(wszSubStringEnd != NULL)
{
wszSubStringStart = ++wszSubStringEnd;
}
else
{
wszSubStringStart = wszSubStringEnd;
}
}
return S_OK;
}
/***************************************************************************++
Routine Description:
Adds the string to the array.
Arguments:
[in] String to add.
[in,out] Current index in the array.
[in,out] Max count of the array. (i.e. max it can hold)
[in,out] Bool which indecates if the array has been realloced.
[in,out] Array.
Return Value:
HRESULT
--***************************************************************************/
HRESULT AddDelimitedStringToArray(DELIMITEDSTRING* i_pDelimitedString,
ULONG* io_piDelimitedString,
ULONG* io_pcMaxDelimitedString,
BOOL* io_pbReAlloced,
DELIMITEDSTRING** io_apDelimitedString)
{
HRESULT hr = S_OK;
if(*io_piDelimitedString >= *io_pcMaxDelimitedString)
{
hr = ReAllocate(*io_piDelimitedString,
*io_pbReAlloced,
io_apDelimitedString,
io_pcMaxDelimitedString);
if(FAILED(hr))
{
return hr;
}
*io_pbReAlloced = TRUE;
}
(*io_apDelimitedString)[(*io_piDelimitedString)++] = (*i_pDelimitedString);
return hr;
}
HRESULT ReAllocate(ULONG i_iDelimitedString,
BOOL i_bReAlloced,
DELIMITEDSTRING** io_apDelimitedString,
ULONG* io_pcDelimitedString)
{
DELIMITEDSTRING* pSav = NULL;
pSav = new DELIMITEDSTRING[*io_pcDelimitedString + cMaxContainedClass];
if(NULL == pSav)
{
return E_OUTOFMEMORY;
}
*io_pcDelimitedString = *io_pcDelimitedString + cMaxContainedClass;
memset(pSav, 0, sizeof(DELIMITEDSTRING)*(*io_pcDelimitedString));
if(NULL != *io_apDelimitedString)
{
memcpy(pSav, *io_apDelimitedString, sizeof(DELIMITEDSTRING)*i_iDelimitedString);
if(i_bReAlloced)
{
delete [] *io_apDelimitedString;
*io_apDelimitedString = NULL;
}
}
*io_apDelimitedString = pSav;
return S_OK;
}
/***************************************************************************++
Routine Description:
Compares two string arrays.
Arguments:
Return Value:
HRESULT
--***************************************************************************/
BOOL MatchDelimitedStringArray(DELIMITEDSTRING* i_aString1,
ULONG i_cString1,
DELIMITEDSTRING* i_aString2,
ULONG i_cString2)
{
DBG_ASSERT((i_cString1 > 0) && (i_cString2 >0));
if(i_cString1 != i_cString2)
{
return FALSE;
}
qsort((void*)i_aString1, i_cString1, sizeof(DELIMITEDSTRING), MyCompareCommaDelimitedStrings);
qsort((void*)i_aString2, i_cString2, sizeof(DELIMITEDSTRING), MyCompareCommaDelimitedStrings);
for(ULONG i=0; i<i_cString1; i++)
{
if(0 != MyCompareCommaDelimitedStrings(&(i_aString1[i]),
&(i_aString2[i]))
)
{
return FALSE;
}
}
return TRUE;
}
/***************************************************************************++
Routine Description:
Looks at the optinal and manditory properties of a class and determines
if ti differs fromt the shipped schema.
Arguments:
[in] Class name.
[in] Optional properties.
[in] Manditory properties.
[in] Writer object.
Return Value:
HRESULT
--***************************************************************************/
BOOL ClassPropertiesDifferFromShippedSchema(LPCWSTR i_wszClassName,
LPWSTR i_wszOptProperties,
LPWSTR i_wszMandProperties)
{
BOOL bClassPropertiesDifferFromShippedSchema = FALSE;
ULONG i = 0;
HRESULT hr = S_OK;
DELIMITEDSTRING aPropertyFixed[cMaxProperty];
ULONG cProperty = cMaxProperty;
ULONG iProperty = 0;
DELIMITEDSTRING* aProperty = aPropertyFixed;
BOOL bReAlloced = FALSE;
if( ((NULL == i_wszOptProperties) || (0 == *i_wszOptProperties)) &&
((NULL == i_wszMandProperties) || (0 == *i_wszMandProperties))
)
{
//
// It is true that you cannot delete all shipped properties from a shipped class,
// because every shipped class that we know of has at least one location property.
// But there may be previously added extension that were deleted, so assume something
// changed, when there are no properties.
//
bClassPropertiesDifferFromShippedSchema = TRUE;
goto exit;
}
//
// Now create an array of
// mand + opt properties
//
if((NULL != i_wszOptProperties) && (0 != *i_wszOptProperties))
{
hr = CommaDelimitedStringToArray(i_wszOptProperties,
&aProperty,
&iProperty,
&cProperty,
&bReAlloced);
if(FAILED(hr))
{
goto exit;
}
}
if((NULL != i_wszMandProperties) && (0 != *i_wszMandProperties))
{
hr = CommaDelimitedStringToArray(i_wszMandProperties,
&aProperty,
&iProperty,
&cProperty,
&bReAlloced);
if(FAILED(hr))
{
goto exit;
}
}
for(i=0; i<iProperty; i++ )
{
LPWSTR wszPropertyName = aProperty[i].pwszStringStart;
LPWSTR wszEnd = aProperty[i].pwszStringEnd;
WCHAR wchEndSav;
ULONG aColSearchProperty[] = {iCOLUMNMETA_Table,
iCOLUMNMETA_InternalName
};
ULONG cColSearchProperty = sizeof(aColSearchProperty)/sizeof(ULONG);
LPVOID apvSearchProperty[cCOLUMNMETA_NumberOfColumns];
ULONG iStartRowProperty = 0;
ULONG iColPropertyMetaFlagsEx = iCOLUMNMETA_SchemaGeneratorFlags;
DWORD* pdwExtended = NULL;
//
// Null terminate the property name and initialize it.
// Hence on gotos until you reset it.
//
wchEndSav = *wszEnd;
*wszEnd = L'\0';
apvSearchProperty[iCOLUMNMETA_Table] = (LPVOID)i_wszClassName;
apvSearchProperty[iCOLUMNMETA_InternalName] = (LPVOID)wszPropertyName;
//
// See if the property is found in the class and see if it is shipped
//
hr = g_pGlobalISTHelper->m_pISTColumnMetaByTableAndName->GetRowIndexBySearch(iStartRowProperty,
cColSearchProperty,
aColSearchProperty,
NULL,
apvSearchProperty,
&iStartRowProperty);
if(SUCCEEDED(hr))
{
hr = g_pGlobalISTHelper->m_pISTColumnMetaByTableAndName->GetColumnValues(iStartRowProperty,
1,
&iColPropertyMetaFlagsEx,
NULL,
(LPVOID*)&pdwExtended);
if(FAILED(hr) || ( ((*pdwExtended) & (fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) != 0))
{
//
// Found at least one property that is not in the shipped schema
//
bClassPropertiesDifferFromShippedSchema = TRUE;
}
//
// Else condition means it succeeded and it was a shipped property
// if(SUCCEEDED(hr) && ( ((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
//
}
else
{
//
// May be its a tag value. Check if it is in the tag meta
//
ULONG aColSearchTag[] = {iTAGMETA_Table,
iTAGMETA_InternalName
};
ULONG cColSearchTag = sizeof(aColSearchTag)/sizeof(ULONG);
LPVOID apvSearchTag[cTAGMETA_NumberOfColumns];
ULONG iStartRowTag = 0;
ULONG iColIndex = iTAGMETA_ColumnIndex;
DWORD* pdwColumnIndex = NULL;
apvSearchTag[iTAGMETA_Table] = (LPVOID)i_wszClassName;
apvSearchTag[iTAGMETA_InternalName] = (LPVOID)wszPropertyName;
hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndName->GetRowIndexBySearch(iStartRowTag,
cColSearchTag,
aColSearchTag,
NULL,
apvSearchTag,
&iStartRowTag);
if(FAILED(hr))
{
bClassPropertiesDifferFromShippedSchema = TRUE;
}
else
{
//
// Check if the parent property of this tag is shipped, if it is not,
// then this becomes a non-shipped tag
//
hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndName->GetColumnValues(iStartRowTag,
1,
&iColIndex,
NULL,
(LPVOID*)&pdwColumnIndex);
if(SUCCEEDED(hr))
{
LPVOID a_Identity[] = {(LPVOID)i_wszClassName,
(LPVOID)pdwColumnIndex
};
ULONG iRow = 0;
hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetRowIndexByIdentity(NULL,
a_Identity,
&iRow);
if(SUCCEEDED(hr))
{
hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(iRow,
1,
&iColPropertyMetaFlagsEx,
NULL,
(LPVOID*)&pdwExtended);
if(FAILED(hr) || ( ((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) != 0))
{
//
// Found at least one property that is not in the shipped schema
//
bClassPropertiesDifferFromShippedSchema = TRUE;
}
//
// Else condition means it succeeded and it was a shipped property
// if(SUCCEEDED(hr) && ( ((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
//
}
}
else
{
bClassPropertiesDifferFromShippedSchema = TRUE;
}
}
}
//
// Restore the property name
//
*wszEnd = wchEndSav;
if(FAILED(hr) || bClassPropertiesDifferFromShippedSchema)
{
goto exit;
}
}
exit:
if(FAILED(hr))
{
bClassPropertiesDifferFromShippedSchema = TRUE;
}
if(aProperty != aPropertyFixed)
{
delete [] aProperty;
}
return bClassPropertiesDifferFromShippedSchema;
} // ClassPropertiesDifferFromShippedSchema
/***************************************************************************++
Routine Description:
Creates the IIsConfigObject collection - This collection has complete
definitions of all properties.
Arguments:
[in] Properties object.
[in,out] Writer object.
[in,out] Schema Writer object.
Return Value:
HRESULT
--***************************************************************************/
HRESULT CreateIISConfigObjectCollection(CMDBaseObject* i_pObjProperties,
CWriter* i_pCWriter,
CMBSchemaWriter** io_pSchemaWriter)
{
HRESULT hr = S_OK;
CMBCollectionWriter* pCollectionWriter = NULL;
hr = SaveNames(i_pObjProperties,
i_pCWriter,
io_pSchemaWriter,
&pCollectionWriter);
if(FAILED(hr))
{
return hr;
}
hr = SaveTypes(i_pObjProperties,
i_pCWriter,
io_pSchemaWriter,
&pCollectionWriter);
if(FAILED(hr))
{
return hr;
}
hr = SaveDefaults(i_pObjProperties,
i_pCWriter,
io_pSchemaWriter,
&pCollectionWriter);
if(FAILED(hr))
{
return hr;
}
return hr;
}
/***************************************************************************++
Routine Description:
Saves the extended roperty name
Arguments:
[in] Metabase properties object.
[in,out] Writer object.
[in,out] Schema Writer object.
[in,out] Collection Writer object.
Return Value:
HRESULT
--***************************************************************************/
HRESULT SaveNames(CMDBaseObject* i_pObjProperties,
CWriter* i_pCWriter,
CMBSchemaWriter** io_pSchemaWriter,
CMBCollectionWriter** io_pCollectionWriter)
{
HRESULT hr = S_OK;
CMDBaseObject* pObjNames = NULL;
CMDBaseData* pObjData = NULL;
DWORD dwEnumIndex = 0;
LPWSTR wszNames = L"Names";
//
// Get the names object
//
pObjNames = i_pObjProperties->GetChildObject((LPSTR&)wszNames,
&hr,
TRUE);
if(FAILED(hr) || (NULL == pObjNames))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to open /Schema/Properties/Names. GetChildObject failed with hr = 0x%x.\n",hr));
return hr;
}
//
// Populate the Column meta array by enumerating the names key.
//
for(dwEnumIndex=0,
pObjData=pObjNames->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA);
(SUCCEEDED(hr)) && (pObjData!=NULL);
pObjData=pObjNames->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA))
{
CMBPropertyWriter *pProperty = NULL;
if(pObjData->GetDataType() != STRING_METADATA)
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Encountered non-string data in the names tree of the schema. Ignoring entry for this ID: %d \n",pObjData->GetIdentifier()));
continue;
}
if(PropertyNotInShippedSchema(i_pCWriter,
pObjData->GetIdentifier())
)
{
if(NULL == *io_pCollectionWriter)
{
hr = GetCollectionWriter(i_pCWriter,
io_pSchemaWriter,
io_pCollectionWriter,
wszTABLE_IIsConfigObject,
FALSE,
NULL);
if(FAILED(hr))
{
return hr;
}
}
hr = (*io_pCollectionWriter)->GetMBPropertyWriter(pObjData->GetIdentifier(),
&pProperty);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving names tree. GetPropertyWriter for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
return hr;
}
pProperty->AddNameToProperty((LPCWSTR)(pObjData->GetData(TRUE)));
}
}
//
// Must call create index else it will keep adding duplicate property entries.
//
return hr;
} // SaveNames
/***************************************************************************++
Routine Description:
Saves the extended roperty type
Arguments:
[in] Metabase properties object.
[in,out] Writer object.
[in,out] Schema Writer object.
[in,out] Collection Writer object.
Return Value:
HRESULT
--***************************************************************************/
HRESULT SaveTypes(CMDBaseObject* i_pObjProperties,
CWriter* i_pCWriter,
CMBSchemaWriter** io_pSchemaWriter,
CMBCollectionWriter** io_pCollectionWriter)
{
HRESULT hr = S_OK;
CMDBaseObject* pObjTypes = NULL;
CMDBaseData* pObjData = NULL;
DWORD dwEnumIndex = 0;
LPWSTR wszTypes = L"Types";
//
// Get the Types object
//
pObjTypes = i_pObjProperties->GetChildObject((LPSTR&)wszTypes,
&hr,
TRUE);
if(FAILED(hr) || (NULL == pObjTypes))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to open /Schema/Properties/Types. GetChildObject failed with hr = 0x%x.\n",hr));
return hr;
}
for(dwEnumIndex=0,
pObjData=pObjTypes->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA);
(SUCCEEDED(hr)) && (pObjData!=NULL);
pObjData=pObjTypes->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA))
{
CMBPropertyWriter *pProperty = NULL;
if(pObjData->GetDataType() != BINARY_METADATA ||
pObjData->GetDataLen(TRUE) != sizeof(PropValue))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Encountered non-binary data in the type tree of the schema.\nIgnoring type entry for this ID: %d.\nType: %d.(Expected %d)\nLength: %d(Expected %d).\n",
pObjData->GetIdentifier(),
pObjData->GetDataType(),
BINARY_METADATA,
pObjData->GetDataLen(TRUE),
sizeof(PropValue)));
if(pObjData->GetDataType() == STRING_METADATA )
{
DBGINFOW((DBG_CONTEXT,
L"Data: %s.\n",
pObjData->GetData(TRUE)
));
}
continue;
}
if(PropertyNotInShippedSchema(i_pCWriter,
pObjData->GetIdentifier())
)
{
if(NULL == *io_pCollectionWriter)
{
hr = GetCollectionWriter(i_pCWriter,
io_pSchemaWriter,
io_pCollectionWriter,
wszTABLE_IIsConfigObject,
FALSE,
NULL);
if(FAILED(hr))
{
return hr;
}
}
hr = (*io_pCollectionWriter)->GetMBPropertyWriter(pObjData->GetIdentifier(),
&pProperty);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving types tree. GetPropertyWriter for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
return hr;
}
hr = pProperty->AddTypeToProperty((PropValue*)(pObjData->GetData(TRUE)));
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving types tree. AddTypeToProperty for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
return hr;
}
}
}
return hr;
}
/***************************************************************************++
Routine Description:
Saves the extended roperty default
Arguments:
[in] Metabase properties object.
[in,out] Writer object.
[in,out] Schema Writer object.
[in,out] Collection Writer object.
Return Value:
HRESULT
--***************************************************************************/
HRESULT SaveDefaults(CMDBaseObject* i_pObjProperties,
CWriter* i_pCWriter,
CMBSchemaWriter** io_pSchemaWriter,
CMBCollectionWriter** io_pCollectionWriter)
{
HRESULT hr = S_OK;
CMDBaseObject* pObjDefaults = NULL;
CMDBaseData* pObjData = NULL;
DWORD dwEnumIndex = 0;
LPWSTR wszDefaults = L"Defaults";
//
// Get the Defaults object
//
pObjDefaults = i_pObjProperties->GetChildObject((LPSTR&)wszDefaults,
&hr,
TRUE);
if(FAILED(hr) || (NULL == pObjDefaults))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Unable to open /Schema/Properties/Defaults. GetChildObject failed with hr = 0x%x.\n",hr));
return hr;
}
for(dwEnumIndex=0,
pObjData=pObjDefaults->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA);
(SUCCEEDED(hr)) && (pObjData!=NULL);
pObjData=pObjDefaults->EnumDataObject(dwEnumIndex++,
0,
ALL_METADATA,
ALL_METADATA))
{
CMBPropertyWriter *pProperty = NULL;
if(PropertyNotInShippedSchema(i_pCWriter,
pObjData->GetIdentifier())
)
{
if(NULL == *io_pCollectionWriter)
{
hr = GetCollectionWriter(i_pCWriter,
io_pSchemaWriter,
io_pCollectionWriter,
wszTABLE_IIsConfigObject,
FALSE,
NULL);
if(FAILED(hr))
{
return hr;
}
}
hr = (*io_pCollectionWriter)->GetMBPropertyWriter(pObjData->GetIdentifier(),
&pProperty);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving defaults tree. GetPropertyWriter for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
return hr;
}
hr = pProperty->AddDefaultToProperty((BYTE*)(pObjData->GetData(TRUE)),
pObjData->GetDataLen(TRUE));
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving types tree. AddDefaultToProperty for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
return hr;
}
}
}
return hr;
}
/***************************************************************************++
Routine Description:
Saves the extended roperty name
Arguments:
[in,out] Writer object.
[in,out] Schema Writer object.
[in,out] Collection Writer object.
[in] Collection name
[in] Bool that indicates container
[in] Container class list
Return Value:
HRESULT
--***************************************************************************/
HRESULT GetCollectionWriter(CWriter* i_pCWriter,
CMBSchemaWriter** io_pSchemaWriter,
CMBCollectionWriter** io_pCollectionWriter,
LPCWSTR i_wszCollectionName,
BOOL i_bContainer,
LPCWSTR i_wszContainerClassList)
{
HRESULT hr = S_OK;
if(NULL != *io_pCollectionWriter)
{
return S_OK;
}
//
// Get the schema writer if it has not been created
//
if(NULL == *io_pSchemaWriter)
{
hr = i_pCWriter->GetMetabaseSchemaWriter(io_pSchemaWriter);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] Error while saving schema tree. Unable to get schema writer failed with hr = 0x%x.\n", hr));
return hr;
}
}
//
// Get collection writer for the collection
//
hr = (*io_pSchemaWriter)->GetCollectionWriter(i_wszCollectionName,
i_bContainer,
i_wszContainerClassList,
io_pCollectionWriter);
if(FAILED(hr))
{
DBGINFOW((DBG_CONTEXT,
L"[SaveSchema] GetCollectionWriter for %s failed with hr = 0x%x.\n",
i_wszCollectionName, hr));
return hr;
}
return S_OK;
}