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

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. SaveSchema.cpp
  5. Abstract:
  6. Implementation of the helper functions that are used to determine
  7. if a schema compilation is needed, and if needed they invoke the
  8. appropriate classes to create a schema extensions file
  9. (MD_SCHEMA_EXTENSION_FILE_NAMEW), that contains the schema extension
  10. descriptions, and invoke a schema compile to generate the schema bin format.
  11. Author:
  12. Varsha Jayasimha (varshaj) 30-Nov-1999
  13. Revision History:
  14. --*/
  15. #include "precomp.hxx"
  16. #define cMaxContainedClass 75
  17. #define cMaxProperty 250
  18. int _cdecl MyCompareStrings(const void *a,
  19. const void *b)
  20. {
  21. return _wcsicmp(*(LPWSTR*)a, *(LPWSTR*)b);
  22. }
  23. /***************************************************************************++
  24. Routine Description:
  25. Helper function used by qsort. Compares to strings, but compares it only
  26. up until the first comma.
  27. --***************************************************************************/
  28. int _cdecl MyCompareCommaDelimitedStrings(const void *a,
  29. const void *b)
  30. {
  31. LPWSTR wszStringAStart = ((DELIMITEDSTRING*)a)->pwszStringStart;
  32. LPWSTR wszStringBStart = ((DELIMITEDSTRING*)b)->pwszStringStart;
  33. LPWSTR wszStringAEnd = ((DELIMITEDSTRING*)a)->pwszStringEnd;
  34. LPWSTR wszStringBEnd = ((DELIMITEDSTRING*)b)->pwszStringEnd;
  35. int iret = 0;
  36. SIZE_T cchA = wszStringAEnd - wszStringAStart;
  37. SIZE_T cchB = wszStringBEnd - wszStringBStart;
  38. //
  39. // Do not attempt to null terminate the string because you may be
  40. // hitting a read-only page.
  41. //
  42. iret = _wcsnicmp(wszStringAStart, wszStringBStart, __min(cchA, cchB));
  43. if((0 == iret) &&
  44. (cchA != cchB)
  45. )
  46. {
  47. iret = cchA < cchB ? -1 : 1;
  48. }
  49. return iret;
  50. }
  51. /***************************************************************************++
  52. Routine Description:
  53. Gets the global helper object that has the pointer to the meta tables.
  54. Arguments:
  55. [in] Bool that indicates whether to fail or not.
  56. Return Value:
  57. HRESULT
  58. --***************************************************************************/
  59. HRESULT InitializeGlobalISTHelper(BOOL i_bFailIfBinFileAbsent)
  60. {
  61. return ::GetGlobalHelper(i_bFailIfBinFileAbsent,
  62. &g_pGlobalISTHelper);
  63. }
  64. void ReleaseGlobalISTHelper()
  65. {
  66. if(NULL != g_pGlobalISTHelper)
  67. {
  68. delete g_pGlobalISTHelper;
  69. g_pGlobalISTHelper = NULL;
  70. }
  71. }
  72. /***************************************************************************++
  73. Routine Description:
  74. This function saves the schema only if something has changed in the schema
  75. since the last save.
  76. Arguments:
  77. [in] Schema file name.
  78. [in] Security attributes for the file.
  79. Return Value:
  80. HRESULT
  81. --***************************************************************************/
  82. HRESULT SaveSchemaIfNeeded(LPCWSTR i_wszSchemaFileName,
  83. PSECURITY_ATTRIBUTES i_pSecurityAtrributes)
  84. {
  85. HRESULT hr = S_OK;
  86. if(NULL == g_pGlobalISTHelper)
  87. {
  88. //
  89. // g_pGlobalISTHelper will not be initialized if
  90. // ReadAllDataFromXML is not called. This can happen
  91. // during an upgrade scneario i.e IIS5.0/5.1 to IIS6.0
  92. // We attempt to initialize it here. Note that we do
  93. // not fail if bin file is absent - just go with
  94. // the shipped schema.
  95. //
  96. BOOL bFailIfBinFileAbsent = FALSE;
  97. hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
  98. }
  99. if(g_dwSchemaChangeNumber != g_dwLastSchemaChangeNumber)
  100. {
  101. DBGINFOW((DBG_CONTEXT,
  102. L"[SaveSchemaIfNeeded] Calling SaveSchema. Last save schema change number: %d. Current schema change number: %d.\n",
  103. g_dwLastSchemaChangeNumber,
  104. g_dwSchemaChangeNumber));
  105. hr = SaveSchema(i_wszSchemaFileName,
  106. i_pSecurityAtrributes);
  107. if(SUCCEEDED(hr))
  108. {
  109. g_dwLastSchemaChangeNumber = g_dwSchemaChangeNumber;
  110. //
  111. // SaveSchema will reinitialize the GlobalISTHelper if the schema has changed.
  112. //
  113. DBGINFOW((DBG_CONTEXT,
  114. L"[SaveSchemaIfNeeded] Done Saving schema. Updating last save schema change number to: %d. Current schema change number: %d.\n",
  115. g_dwLastSchemaChangeNumber,
  116. g_dwSchemaChangeNumber));
  117. }
  118. }
  119. else
  120. {
  121. DBGINFOW((DBG_CONTEXT,
  122. 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",
  123. g_dwLastSchemaChangeNumber,
  124. g_dwSchemaChangeNumber));
  125. }
  126. return hr;
  127. }
  128. /***************************************************************************++
  129. Routine Description:
  130. This function saves the schema and compiles schema information into the
  131. bin file.
  132. Arguments:
  133. [in] Schema file name.
  134. [in] Security attributes for the file.
  135. Return Value:
  136. HRESULT
  137. --***************************************************************************/
  138. HRESULT SaveSchema(LPCWSTR i_wszSchemaFileName,
  139. PSECURITY_ATTRIBUTES i_pSecurityAtrributes)
  140. {
  141. HRESULT hr;
  142. CMDBaseObject* pObjSchema = NULL;
  143. CMDBaseObject* pObjProperties = NULL;
  144. CWriter* pCWriter = NULL;
  145. CMBSchemaWriter* pSchemaWriter = NULL;
  146. LPWSTR wszSchema = L"Schema";
  147. LPWSTR wszProperties = L"Properties";
  148. ISimpleTableDispenser2* pISTDisp = NULL;
  149. IMetabaseSchemaCompiler* pCompiler = NULL;
  150. //
  151. // Get a pointer to the compiler to get the bin file name.
  152. //
  153. hr = DllGetSimpleObjectByIDEx( eSERVERWIRINGMETA_TableDispenser, IID_ISimpleTableDispenser2, (VOID**)&pISTDisp, WSZ_PRODUCT_IIS );
  154. if(FAILED(hr))
  155. {
  156. DBGINFOW((DBG_CONTEXT,
  157. L"[SaveSchema] DllGetSimpleObjectByIDEx failed with hr = 0x%x.\n",hr));
  158. goto exit;
  159. }
  160. hr = pISTDisp->QueryInterface(IID_IMetabaseSchemaCompiler,
  161. (LPVOID*)&pCompiler);
  162. if(FAILED(hr))
  163. {
  164. DBGINFOW((DBG_CONTEXT,
  165. L"[SaveSchema] QueryInterface on compiler failed with hr = 0x%x.\n",hr));
  166. goto exit;
  167. }
  168. //
  169. // Get the Properties object
  170. //
  171. pObjSchema = g_pboMasterRoot->GetChildObject((LPSTR&)wszSchema,
  172. &hr,
  173. TRUE);
  174. if(FAILED(hr) || (NULL == pObjSchema))
  175. {
  176. DBGINFOW((DBG_CONTEXT,
  177. L"[SaveSchema] Unable to open /Schema. GetChildObject failed with hr = 0x%x.\n",hr));
  178. goto exit;
  179. }
  180. pObjProperties = pObjSchema->GetChildObject((LPSTR&)wszProperties,
  181. &hr,
  182. TRUE);
  183. if(FAILED(hr) || (NULL == pObjProperties))
  184. {
  185. DBGINFOW((DBG_CONTEXT,
  186. L"[SaveSchema] Unable to open /Schema/Properties. GetChildObject failed with hr = 0x%x.\n",hr));
  187. goto exit;
  188. }
  189. //
  190. // Create the writer object
  191. //
  192. DBGINFOW((DBG_CONTEXT,
  193. L"[SaveSchema] Initializing writer with write file: %s bin file: %s.\n",
  194. g_wszSchemaExtensionFile,
  195. g_pGlobalISTHelper->m_wszBinFileForMeta));
  196. //
  197. // Assert the g_GlobalISTHelper are valid
  198. //
  199. MD_ASSERT(g_pGlobalISTHelper != NULL);
  200. pCWriter = new CWriter();
  201. if(NULL == pCWriter)
  202. {
  203. hr = E_OUTOFMEMORY;
  204. }
  205. else
  206. {
  207. //
  208. // Bug #512868 If someone had attrib-ed an existing extenstion file
  209. // be read-only then we could land up in a state where we will not be
  210. // able to recreate the extensions file. Hence attrib the extensions
  211. // file to be read-write if it exists. An extensions file can be
  212. // around only if a previous compile has failed.
  213. //
  214. ResetFileAttributesIfNeeded((LPTSTR)g_wszSchemaExtensionFile,
  215. TRUE);
  216. hr = pCWriter->Initialize(g_wszSchemaExtensionFile,
  217. g_pGlobalISTHelper,
  218. NULL);
  219. }
  220. if(FAILED(hr))
  221. {
  222. DBGINFOW((DBG_CONTEXT,
  223. L"[SaveSchema] Error while saving schema tree. Cannot initialize writer. Failed with hr = 0x%x.\n", hr));
  224. goto exit;
  225. }
  226. //
  227. // First create the IIsConfigObject collection
  228. //
  229. hr = CreateIISConfigObjectCollection(pObjProperties,
  230. pCWriter,
  231. &pSchemaWriter);
  232. if(FAILED(hr))
  233. {
  234. goto exit;
  235. }
  236. //
  237. // Create all other collections
  238. //
  239. hr = CreateNonIISConfigObjectCollections(pObjSchema,
  240. pCWriter,
  241. &pSchemaWriter);
  242. if(FAILED(hr))
  243. {
  244. goto exit;
  245. }
  246. if(pSchemaWriter)
  247. {
  248. //
  249. // If pSchemaWriter has a valid Value, then some extensions were found - write it.
  250. //
  251. hr = pCWriter->BeginWrite(eWriter_Schema,
  252. i_pSecurityAtrributes);
  253. if(FAILED(hr))
  254. {
  255. DBGINFOW((DBG_CONTEXT,
  256. L"[SaveSchema] Error while saving schema tree. CWriter::BeginWrite failed with hr = 0x%x.\n", hr));
  257. goto exit;
  258. }
  259. hr = pSchemaWriter->WriteSchema();
  260. if(FAILED(hr))
  261. {
  262. DBGINFOW((DBG_CONTEXT,
  263. L"[SaveSchema] Error while saving schema tree. CMBSchemaWriter::WriteSchema. Failed with hr = 0x%x.\n", hr));
  264. goto exit;
  265. }
  266. hr = pCWriter->EndWrite(eWriter_Schema);
  267. if(FAILED(hr))
  268. {
  269. DBGINFOW((DBG_CONTEXT,
  270. L"[SaveSchema] Error while saving schema tree. CWriter::EndWrite Failed with hr = 0x%x.\n", hr));
  271. goto exit;
  272. }
  273. //
  274. // Trigger compilation
  275. //
  276. //
  277. // Must close the file prior to calling compile schema, else will get a sharing violation.
  278. //
  279. delete pCWriter;
  280. pCWriter = NULL;
  281. hr = CompileIntoBin(pCompiler,
  282. g_wszSchemaExtensionFile,
  283. i_wszSchemaFileName);
  284. if(FAILED(hr))
  285. {
  286. DBGINFOW((DBG_CONTEXT,
  287. L"[SaveSchema] CompileSchema from %s failed with hr = 0x%x.\n",
  288. g_wszSchemaExtensionFile, hr));
  289. }
  290. else
  291. {
  292. if(!DeleteFileW(g_wszSchemaExtensionFile))
  293. {
  294. hr = HRESULT_FROM_WIN32(GetLastError());
  295. DBGINFOW((DBG_CONTEXT,
  296. L"[CompileIfNeeded] Compile from schema extensions file: %s succeeded, but cannot cleanup the extensions file:%s. Delete file failed with hr = 0x%x.\n",
  297. g_wszSchemaExtensionFile,
  298. g_wszSchemaExtensionFile,
  299. hr));
  300. hr = S_OK;
  301. }
  302. goto exit;
  303. }
  304. }
  305. else
  306. {
  307. DBGINFOW((DBG_CONTEXT,
  308. L"[SaveSchema] No extensions found. - Either schema tree was changed, but no extensions added, or all extensions were deleted.\n"));
  309. }
  310. //
  311. // If you reach here it means that:
  312. // A. Schema changes occured to the in-memory /Schema tree, but either
  313. // there were no extensions or all extensions were deleted.
  314. // (This is inferred when pSchemaWriter in NULL)
  315. // or
  316. // B. Schema compile failed.
  317. // For A: Compile from shipped schema.
  318. // For B: Check for an existing schema file. If found make sure that the
  319. // bin file is valid. If bin file is not valid try compiling from the
  320. // schema file. If schema file is not found, compile from shipped schema.
  321. //
  322. if(pSchemaWriter)
  323. {
  324. //
  325. // This is case B.
  326. //
  327. if(-1 != GetFileAttributesW(i_wszSchemaFileName))
  328. {
  329. if(NULL == g_pGlobalISTHelper)
  330. {
  331. BOOL bFailIfBinFileAbsent = TRUE;
  332. hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
  333. if(SUCCEEDED(hr))
  334. {
  335. goto exit;
  336. }
  337. else
  338. {
  339. DBGINFOW((DBG_CONTEXT,
  340. L"[SaveSchema] Unable to get the the bin file name. (Assuming file missing or invalid). InitializeGlobalISTHelper failed with hr = 0x%x.\n",hr));
  341. }
  342. }
  343. else
  344. {
  345. //
  346. // Schema file present and valid - goto exit
  347. // As long as we have a valid g_pGlobalISTHelper, it holds on
  348. // to a reference to the bin file and the bin file cannot be
  349. // invalidated.
  350. //
  351. goto exit;
  352. }
  353. DBGINFOW((DBG_CONTEXT,
  354. L"[SaveSchema] Compiling from schema file %s\n", i_wszSchemaFileName));
  355. hr = CompileIntoBinFromSchemaFile(pCompiler,
  356. i_wszSchemaFileName);
  357. if(SUCCEEDED(hr))
  358. {
  359. goto exit;
  360. }
  361. }
  362. }
  363. //
  364. // If you reach here it is either case A or the last part of case B.
  365. // Recreate from shipped schema
  366. //
  367. DBGINFOW((DBG_CONTEXT,
  368. L"[SaveSchema] Schema file not found. Compiling from shipped schema\n"));
  369. hr = CompileIntoBin(pCompiler,
  370. NULL,
  371. i_wszSchemaFileName);
  372. exit:
  373. if(SUCCEEDED(hr))
  374. {
  375. if(NULL == g_pGlobalISTHelper)
  376. {
  377. BOOL bFailIfBinFileAbsent = TRUE;
  378. hr = InitializeGlobalISTHelper(bFailIfBinFileAbsent);
  379. if(FAILED(hr))
  380. {
  381. DBGINFOW((DBG_CONTEXT,
  382. L"[SaveSchema] Unable to get the the bin file name. (Assuming file is invalid). InitializeGlobalISTHelper failed with hr = 0x%x.\n",hr));
  383. }
  384. }
  385. if(SUCCEEDED(hr))
  386. {
  387. hr = UpdateTimeStamp((LPWSTR)i_wszSchemaFileName,
  388. g_pGlobalISTHelper->m_wszBinFileForMeta);
  389. if(FAILED(hr))
  390. {
  391. DBGINFOW((DBG_CONTEXT,
  392. L"[CompileIfNeeded] UpdateTimeStamp failed with hr = 0x%x.\n",hr));
  393. }
  394. }
  395. }
  396. if(NULL != pSchemaWriter)
  397. {
  398. delete pSchemaWriter;
  399. }
  400. if(NULL != pCWriter)
  401. {
  402. delete pCWriter;
  403. }
  404. if(NULL != pCompiler)
  405. {
  406. pCompiler->Release();
  407. }
  408. if(NULL != pISTDisp)
  409. {
  410. pISTDisp->Release();
  411. }
  412. return hr;
  413. }
  414. /***************************************************************************++
  415. Routine Description:
  416. This function creates the non-IIsConfigObject collection *extensions* to
  417. the schema.
  418. Arguments:
  419. [in] Object that contains the schema tree.
  420. [in] The writter object.
  421. [in,out] The schema object - this gets created if it is not already created
  422. Return Value:
  423. HRESULT
  424. --***************************************************************************/
  425. HRESULT CreateNonIISConfigObjectCollections(CMDBaseObject* i_pObjSchema,
  426. CWriter* i_pCWriter,
  427. CMBSchemaWriter** io_pSchemaWriter)
  428. {
  429. CMDBaseObject* pObjClasses = NULL;
  430. CMDBaseObject* pObjClass = NULL;
  431. DWORD dwEnumClassIndex = 0;
  432. static LPCWSTR wszSeparator = L",";
  433. LPWSTR wszClasses = L"Classes";
  434. HRESULT hr = S_OK;
  435. //
  436. // Open the Classes key
  437. //
  438. pObjClasses = i_pObjSchema->GetChildObject((LPSTR&)wszClasses,
  439. &hr,
  440. TRUE);
  441. if(FAILED(hr) || (NULL == pObjClasses))
  442. {
  443. DBGINFOW((DBG_CONTEXT,
  444. L"[SaveSchema] Unable to open /Schema/Classes. GetChildObject failed with hr = 0x%x.\n",hr));
  445. return hr;
  446. }
  447. for(dwEnumClassIndex=0,
  448. pObjClass=pObjClasses->EnumChildObject(dwEnumClassIndex++);
  449. (SUCCEEDED(hr)) && (pObjClass!=NULL);
  450. pObjClass=pObjClasses->EnumChildObject(dwEnumClassIndex++))
  451. {
  452. //
  453. // Save all the properties for this class in temp variables
  454. //
  455. LPCWSTR wszOptProp = NULL;
  456. LPCWSTR wszMandProp = NULL;
  457. LPCWSTR wszContainedClassList = NULL;
  458. BOOL bContainer = FALSE;
  459. BOOL* pbContainer = &bContainer;
  460. LPCWSTR wszClassName = (LPCWSTR)pObjClass->GetName(TRUE);
  461. CMBCollectionWriter* pCollectionWriter = NULL;
  462. CMDBaseData* pObjData = NULL;
  463. DWORD dwEnumIndex = 0;
  464. for(dwEnumIndex=0,
  465. pObjData=pObjClass->EnumDataObject(dwEnumIndex++,
  466. 0,
  467. ALL_METADATA,
  468. ALL_METADATA);
  469. (SUCCEEDED(hr)) && (pObjData!=NULL);
  470. pObjData=pObjClass->EnumDataObject(dwEnumIndex++,
  471. 0,
  472. ALL_METADATA,
  473. ALL_METADATA))
  474. {
  475. DWORD dwID = pObjData->GetIdentifier();
  476. if(MD_SCHEMA_CLASS_OPT_PROPERTIES == dwID)
  477. {
  478. wszOptProp = (LPCWSTR)pObjData->GetData(TRUE);
  479. }
  480. else if(MD_SCHEMA_CLASS_MAND_PROPERTIES == dwID)
  481. {
  482. wszMandProp = (LPCWSTR)pObjData->GetData(TRUE);
  483. }
  484. else if(dwID == MD_SCHEMA_CLASS_CONTAINER)
  485. {
  486. pbContainer = (BOOL*)pObjData->GetData(TRUE);
  487. }
  488. else if(dwID == MD_SCHEMA_CLASS_CONTAINMENT)
  489. {
  490. wszContainedClassList = (LPCWSTR)pObjData->GetData(TRUE);
  491. }
  492. }
  493. //
  494. // Get collection writer for IIsConfigObject
  495. //
  496. // DBGINFOW((DBG_CONTEXT,
  497. // L"[CreateNonIISConfigObjectCollections] Class %s Mand Prop:%s. Opt Prop: %s\n",
  498. // wszClassName,
  499. // wszMandProp,
  500. // wszOptProp));
  501. // Assert that pbContainer is non-null.
  502. MD_ASSERT(pbContainer != NULL);
  503. if(ClassDiffersFromShippedSchema(wszClassName,
  504. *pbContainer,
  505. (LPWSTR)wszContainedClassList) ||
  506. ClassPropertiesDifferFromShippedSchema(wszClassName,
  507. (LPWSTR)wszOptProp,
  508. (LPWSTR)wszMandProp)
  509. )
  510. {
  511. DBGINFOW((DBG_CONTEXT,
  512. L"[SaveSchema] Saving collection: %s.\n",wszClassName));
  513. hr = GetCollectionWriter(i_pCWriter,
  514. io_pSchemaWriter,
  515. &pCollectionWriter,
  516. wszClassName,
  517. *pbContainer,
  518. wszContainedClassList);
  519. if(FAILED(hr))
  520. {
  521. return hr;
  522. }
  523. hr = ParseAndAddPropertiesToNonIISConfigObjectCollection(wszOptProp,
  524. FALSE,
  525. pCollectionWriter);
  526. if(FAILED(hr))
  527. {
  528. DBGINFOW((DBG_CONTEXT,
  529. 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));
  530. return hr;
  531. }
  532. hr = ParseAndAddPropertiesToNonIISConfigObjectCollection(wszMandProp,
  533. TRUE,
  534. pCollectionWriter);
  535. if(FAILED(hr))
  536. {
  537. DBGINFOW((DBG_CONTEXT,
  538. 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));
  539. return hr;
  540. }
  541. }
  542. }
  543. return hr;
  544. }
  545. /***************************************************************************++
  546. Routine Description:
  547. It parses the list of properties and adds it to a Non_IIsConfigObject
  548. collection.
  549. Arguments:
  550. [in] List of properties
  551. [in] Bool that indicates manditory or optional.
  552. [in,out] The collection object - this gets created if it is not already created
  553. Return Value:
  554. HRESULT
  555. --***************************************************************************/
  556. HRESULT
  557. ParseAndAddPropertiesToNonIISConfigObjectCollection(LPCWSTR i_wszProperties,
  558. BOOL i_bManditory,
  559. CMBCollectionWriter* i_pCollectionWriter)
  560. {
  561. CMBPropertyWriter *pProperty = NULL;
  562. HRESULT hr = S_OK;
  563. static WCHAR wchSeparator = L',';
  564. WCHAR* pwszStartProperty = NULL;
  565. WCHAR* pwszEndProperty = NULL;
  566. if(NULL == i_wszProperties || 0 == *i_wszProperties)
  567. {
  568. return S_OK;
  569. }
  570. pwszStartProperty = (LPWSTR)i_wszProperties;
  571. for ( ; ; )
  572. {
  573. pwszEndProperty = wcschr(pwszStartProperty, wchSeparator);
  574. if(0 != *pwszStartProperty)
  575. {
  576. hr = i_pCollectionWriter->GetMBPropertyWriter(pwszStartProperty,
  577. i_bManditory,
  578. &pProperty);
  579. if(FAILED(hr))
  580. {
  581. return hr;
  582. }
  583. }
  584. if(NULL != pwszEndProperty)
  585. {
  586. pwszStartProperty = ++pwszEndProperty;
  587. }
  588. else
  589. {
  590. break;
  591. }
  592. }
  593. return hr;
  594. }
  595. /***************************************************************************++
  596. Routine Description:
  597. Looks up the schema and determines if a property is in the shipped
  598. schema or not.
  599. Arguments:
  600. [in] Writer object.
  601. [in] property id.
  602. Return Value:
  603. HRESULT
  604. --***************************************************************************/
  605. BOOL PropertyNotInShippedSchema(CWriter* i_pCWriter,
  606. DWORD i_dwIdentifier)
  607. {
  608. HRESULT hr = S_OK;
  609. ULONG aColSearch[] = {iCOLUMNMETA_Table,
  610. iCOLUMNMETA_ID
  611. };
  612. ULONG cColSearch = sizeof(aColSearch)/sizeof(ULONG);
  613. LPVOID apvSearch[cCOLUMNMETA_NumberOfColumns];
  614. apvSearch[iCOLUMNMETA_Table] = (LPVOID)i_pCWriter->m_pCWriterGlobalHelper->m_wszTABLE_IIsConfigObject;
  615. apvSearch[iCOLUMNMETA_ID] = (LPVOID)&i_dwIdentifier;
  616. BOOL bPropertyNotInShippedSchema = TRUE;
  617. ULONG iRow = 0;
  618. ULONG iStartRow = 0;
  619. ULONG iCol = iCOLUMNMETA_SchemaGeneratorFlags;
  620. DWORD* pdwMetaFlagsEx = NULL;
  621. hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTColumnMetaByTableAndID->GetRowIndexBySearch(iStartRow,
  622. cColSearch,
  623. aColSearch,
  624. NULL,
  625. apvSearch,
  626. &iRow);
  627. if(SUCCEEDED(hr))
  628. {
  629. hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTColumnMetaByTableAndID->GetColumnValues(iRow,
  630. 1,
  631. &iCol,
  632. NULL,
  633. (LPVOID*)&pdwMetaFlagsEx);
  634. if(SUCCEEDED(hr) && (((*pdwMetaFlagsEx)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
  635. {
  636. bPropertyNotInShippedSchema = FALSE;
  637. }
  638. }
  639. if(E_ST_NOMOREROWS == hr)
  640. {
  641. //
  642. // See if property is a shipped tag.
  643. //
  644. bPropertyNotInShippedSchema = TagNotInShippedSchema(i_pCWriter,
  645. i_dwIdentifier);
  646. }
  647. else if(FAILED(hr))
  648. {
  649. //
  650. // Trace a message saying internal catalog error
  651. //
  652. DBGINFOW((DBG_CONTEXT,
  653. L"[PropertyNotInShippedSchema] Internal catalog error. Could not determine if property was not in shipped schema. Assuming it is not. hr = 0x%x.\n", hr));
  654. }
  655. return bPropertyNotInShippedSchema;
  656. } // PropertyNotInShippedSchema
  657. /***************************************************************************++
  658. Routine Description:
  659. Looks up the schema and determines if a tag is in the shipped
  660. schema or not.
  661. Arguments:
  662. [in] Writer object.
  663. [in] property id.
  664. Return Value:
  665. HRESULT
  666. --***************************************************************************/
  667. BOOL TagNotInShippedSchema(CWriter* i_pCWriter,
  668. DWORD i_dwIdentifier)
  669. {
  670. HRESULT hr = S_OK;
  671. ULONG aColSearch[] = {iTAGMETA_Table,
  672. iTAGMETA_ID
  673. };
  674. ULONG cColSearch = sizeof(aColSearch)/sizeof(ULONG);
  675. LPVOID apvSearch[cCOLUMNMETA_NumberOfColumns];
  676. BOOL bTagNotInShippedSchema = TRUE;
  677. ULONG iStartRow = 0;
  678. ULONG iColIndex = iTAGMETA_ColumnIndex;
  679. DWORD* pdwColIndex = NULL;
  680. apvSearch[iTAGMETA_Table] = (LPVOID)g_pGlobalISTHelper->m_wszTABLE_IIsConfigObject;
  681. apvSearch[iTAGMETA_ID] = (LPVOID)&i_dwIdentifier;
  682. hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTTagMetaByTableAndID->GetRowIndexBySearch(iStartRow,
  683. cColSearch,
  684. aColSearch,
  685. NULL,
  686. apvSearch,
  687. &iStartRow);
  688. if(SUCCEEDED(hr))
  689. {
  690. hr = i_pCWriter->m_pCWriterGlobalHelper->m_pISTTagMetaByTableAndID->GetColumnValues(iStartRow,
  691. 1,
  692. &iColIndex,
  693. NULL,
  694. (LPVOID*)&pdwColIndex);
  695. if(SUCCEEDED(hr))
  696. {
  697. //
  698. // Lookup the property to see if it is shipped.
  699. //
  700. LPVOID a_Identity[] = {(LPVOID)g_pGlobalISTHelper->m_wszTABLE_IIsConfigObject,
  701. (LPVOID)pdwColIndex
  702. };
  703. ULONG iRow=0;
  704. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetRowIndexByIdentity(NULL,
  705. a_Identity,
  706. &iRow);
  707. if(SUCCEEDED(hr))
  708. {
  709. DWORD* pdwExtended = NULL;
  710. ULONG iColPropertyMetaFlagsEx = iCOLUMNMETA_SchemaGeneratorFlags;
  711. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(iRow,
  712. 1,
  713. &iColPropertyMetaFlagsEx,
  714. NULL,
  715. (LPVOID*)&pdwExtended);
  716. if(SUCCEEDED(hr) && (((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
  717. {
  718. //
  719. // Found at least one property that is not in the shipped schema
  720. //
  721. bTagNotInShippedSchema = FALSE;
  722. }
  723. //
  724. // Else condition means it failed or it was a shipped property
  725. // if(FAILED(hr) || ( (((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) != 0))
  726. //
  727. }
  728. }
  729. } // If GetRowIndexBySearch succeeds
  730. return bTagNotInShippedSchema;
  731. } // TagNotInShippedSchema
  732. /***************************************************************************++
  733. Routine Description:
  734. Looks up the schema and determines if a class has any extensions or if it
  735. an extended (ie new) class.
  736. Arguments:
  737. [in] Class name
  738. [in] Container class or not.
  739. [in] Container class list.
  740. Return Value:
  741. HRESULT
  742. --***************************************************************************/
  743. BOOL ClassDiffersFromShippedSchema(LPCWSTR i_wszClassName,
  744. BOOL i_bIsContainer,
  745. LPWSTR i_wszContainedClassList)
  746. {
  747. HRESULT hr = S_OK;
  748. BOOL bClassDiffersFromShippedSchema = TRUE;
  749. ULONG aiCol [] = {iTABLEMETA_SchemaGeneratorFlags,
  750. iTABLEMETA_ContainerClassList
  751. };
  752. ULONG cCol = sizeof(aiCol)/sizeof(ULONG);
  753. LPVOID apv[cTABLEMETA_NumberOfColumns];
  754. ULONG iRow = 0;
  755. hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetRowIndexByIdentity(NULL,
  756. (LPVOID*)&i_wszClassName,
  757. &iRow);
  758. if(SUCCEEDED(hr))
  759. {
  760. hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetColumnValues(iRow,
  761. cCol,
  762. aiCol,
  763. NULL,
  764. apv);
  765. if(SUCCEEDED(hr))
  766. {
  767. if(((*(DWORD*)apv[iTABLEMETA_SchemaGeneratorFlags]) & (fTABLEMETA_EXTENDED|fTABLEMETA_USERDEFINED)) == 0)
  768. {
  769. if(MatchClass(i_bIsContainer,
  770. i_wszContainedClassList,
  771. apv)
  772. )
  773. {
  774. bClassDiffersFromShippedSchema = FALSE;
  775. }
  776. }
  777. }
  778. else
  779. {
  780. //
  781. // Trace a message saying internal catalog error
  782. //
  783. DBGINFOW((DBG_CONTEXT,
  784. L"[ClassDiffersFromShippedSchema] Internal catalog error. Could not determine if class was not in shipped schema. Assuming it is not. hr = 0x%x.\n", hr));
  785. }
  786. }
  787. else if(E_ST_NOMOREROWS != hr)
  788. {
  789. //
  790. // Trace a message saying internal catalog error
  791. //
  792. DBGINFOW((DBG_CONTEXT,
  793. L"[ClassDiffersFromShippedSchema] Internal catalog error. Could not determine if class was not in shipped schema. Assuming it is not. hr = 0x%x.\n", hr));
  794. }
  795. return bClassDiffersFromShippedSchema;
  796. } // ClassDiffersFromShippedSchema
  797. /***************************************************************************++
  798. Routine Description:
  799. Looks up the schema and matches a class.
  800. Arguments:
  801. [in] Container class or not.
  802. [in] Container class list.
  803. [in] Class attributes.
  804. Return Value:
  805. HRESULT
  806. --***************************************************************************/
  807. BOOL MatchClass(BOOL i_bIsContainer,
  808. LPWSTR i_wszContainedClassList,
  809. LPVOID* i_apv)
  810. {
  811. BOOL bMatch = TRUE;
  812. DWORD fIsContained = (*(DWORD*)i_apv[iTABLEMETA_SchemaGeneratorFlags]) & fTABLEMETA_CONTAINERCLASS;
  813. //
  814. // Compare the container property 1st and only if they equal compare the container class list
  815. //
  816. if( i_bIsContainer &&
  817. (fIsContained != fTABLEMETA_CONTAINERCLASS)
  818. )
  819. {
  820. bMatch = FALSE;
  821. }
  822. else if (!i_bIsContainer &&
  823. (fIsContained == fTABLEMETA_CONTAINERCLASS)
  824. )
  825. {
  826. bMatch = FALSE;
  827. }
  828. else
  829. {
  830. bMatch = MatchCommaDelimitedStrings(i_wszContainedClassList,
  831. (LPWSTR)i_apv[iTABLEMETA_ContainerClassList]);
  832. }
  833. return bMatch;
  834. } // MatchClass
  835. /***************************************************************************++
  836. Routine Description:
  837. Checks to see if two comma delimited strings match.
  838. Arguments:
  839. [in] Comma delimited string.
  840. [in] Comma delimited string.
  841. Return Value:
  842. HRESULT
  843. --***************************************************************************/
  844. BOOL MatchCommaDelimitedStrings(LPWSTR i_wszString1,
  845. LPWSTR i_wszString2)
  846. {
  847. BOOL bMatch = FALSE;
  848. DELIMITEDSTRING aStringFixed1[cMaxContainedClass];
  849. DELIMITEDSTRING aStringFixed2[cMaxContainedClass];
  850. DELIMITEDSTRING* aString1 = aStringFixed1;
  851. DELIMITEDSTRING* aString2 = aStringFixed2;
  852. ULONG cString1 = cMaxContainedClass;
  853. ULONG cString2 = cMaxContainedClass;
  854. ULONG iString1 = 0;
  855. ULONG iString2 = 0;
  856. BOOL bReAlloced1 = FALSE;
  857. BOOL bReAlloced2 = FALSE;
  858. HRESULT hr = S_OK;
  859. if(NULL == i_wszString1 || 0 == *i_wszString1)
  860. {
  861. if(NULL == i_wszString2 || 0 == *i_wszString2)
  862. {
  863. bMatch = TRUE;
  864. }
  865. }
  866. else if(NULL == i_wszString2 || 0 == *i_wszString2)
  867. {
  868. bMatch = FALSE; // Means i_wszString1 != NULL and i_wszString2 == NULL
  869. }
  870. else if(wcscmp(i_wszString1, i_wszString2) == 0)
  871. {
  872. bMatch = TRUE;
  873. }
  874. else
  875. {
  876. //
  877. // Construct an array of individual strings
  878. // and compare the array
  879. //
  880. hr = CommaDelimitedStringToArray(i_wszString1,
  881. &aString1,
  882. &iString1,
  883. &cString1,
  884. &bReAlloced1);
  885. if(FAILED(hr))
  886. {
  887. goto exit;
  888. }
  889. hr = CommaDelimitedStringToArray(i_wszString2,
  890. &aString2,
  891. &iString2,
  892. &cString2,
  893. &bReAlloced2);
  894. if(FAILED(hr))
  895. {
  896. goto exit;
  897. }
  898. bMatch = MatchDelimitedStringArray(aString1,
  899. iString1,
  900. aString2,
  901. iString2);
  902. }
  903. exit:
  904. if(aString1 != aStringFixed1)
  905. {
  906. delete [] aString1;
  907. }
  908. if(aString2 != aStringFixed2)
  909. {
  910. delete [] aString2;
  911. }
  912. return bMatch;
  913. } // MatchCommaDelimitedStrings
  914. /***************************************************************************++
  915. Routine Description:
  916. Converts a comma delimited string to an array.
  917. Arguments:
  918. [in] Comma delimited string.
  919. [in,out] Array.
  920. [in,out] Current index in the array.
  921. [in,out] Max count of the array. (i.e. max it can hold)
  922. [in,out] Bool which indecates if the array has been realloced.
  923. Return Value:
  924. HRESULT
  925. --***************************************************************************/
  926. HRESULT CommaDelimitedStringToArray(LPWSTR i_wszString,
  927. DELIMITEDSTRING** io_apDelimitedString,
  928. ULONG* io_piDelimitedString,
  929. ULONG* io_pcMaxDelimitedString,
  930. BOOL* io_pbReAlloced)
  931. {
  932. LPWSTR wszSubStringStart = NULL;
  933. LPWSTR wszSubStringEnd = NULL;
  934. HRESULT hr = S_OK;
  935. wszSubStringStart = i_wszString;
  936. while(NULL != wszSubStringStart)
  937. {
  938. DELIMITEDSTRING DelimitedString;
  939. wszSubStringEnd = wcschr(wszSubStringStart, L',');
  940. DelimitedString.pwszStringStart = wszSubStringStart;
  941. if(NULL != wszSubStringEnd)
  942. {
  943. DelimitedString.pwszStringEnd = wszSubStringEnd;
  944. }
  945. else
  946. {
  947. // Point to the terminating NULL.
  948. DelimitedString.pwszStringEnd = wszSubStringStart + wcslen(wszSubStringStart);
  949. }
  950. hr = AddDelimitedStringToArray(&DelimitedString,
  951. io_piDelimitedString,
  952. io_pcMaxDelimitedString,
  953. io_pbReAlloced,
  954. io_apDelimitedString);
  955. if(FAILED(hr))
  956. {
  957. return hr;
  958. }
  959. if(wszSubStringEnd != NULL)
  960. {
  961. wszSubStringStart = ++wszSubStringEnd;
  962. }
  963. else
  964. {
  965. wszSubStringStart = wszSubStringEnd;
  966. }
  967. }
  968. return S_OK;
  969. }
  970. /***************************************************************************++
  971. Routine Description:
  972. Adds the string to the array.
  973. Arguments:
  974. [in] String to add.
  975. [in,out] Current index in the array.
  976. [in,out] Max count of the array. (i.e. max it can hold)
  977. [in,out] Bool which indecates if the array has been realloced.
  978. [in,out] Array.
  979. Return Value:
  980. HRESULT
  981. --***************************************************************************/
  982. HRESULT AddDelimitedStringToArray(DELIMITEDSTRING* i_pDelimitedString,
  983. ULONG* io_piDelimitedString,
  984. ULONG* io_pcMaxDelimitedString,
  985. BOOL* io_pbReAlloced,
  986. DELIMITEDSTRING** io_apDelimitedString)
  987. {
  988. HRESULT hr = S_OK;
  989. if(*io_piDelimitedString >= *io_pcMaxDelimitedString)
  990. {
  991. hr = ReAllocate(*io_piDelimitedString,
  992. *io_pbReAlloced,
  993. io_apDelimitedString,
  994. io_pcMaxDelimitedString);
  995. if(FAILED(hr))
  996. {
  997. return hr;
  998. }
  999. *io_pbReAlloced = TRUE;
  1000. }
  1001. (*io_apDelimitedString)[(*io_piDelimitedString)++] = (*i_pDelimitedString);
  1002. return hr;
  1003. }
  1004. HRESULT ReAllocate(ULONG i_iDelimitedString,
  1005. BOOL i_bReAlloced,
  1006. DELIMITEDSTRING** io_apDelimitedString,
  1007. ULONG* io_pcDelimitedString)
  1008. {
  1009. DELIMITEDSTRING* pSav = NULL;
  1010. pSav = new DELIMITEDSTRING[*io_pcDelimitedString + cMaxContainedClass];
  1011. if(NULL == pSav)
  1012. {
  1013. return E_OUTOFMEMORY;
  1014. }
  1015. *io_pcDelimitedString = *io_pcDelimitedString + cMaxContainedClass;
  1016. memset(pSav, 0, sizeof(DELIMITEDSTRING)*(*io_pcDelimitedString));
  1017. if(NULL != *io_apDelimitedString)
  1018. {
  1019. memcpy(pSav, *io_apDelimitedString, sizeof(DELIMITEDSTRING)*i_iDelimitedString);
  1020. if(i_bReAlloced)
  1021. {
  1022. delete [] *io_apDelimitedString;
  1023. *io_apDelimitedString = NULL;
  1024. }
  1025. }
  1026. *io_apDelimitedString = pSav;
  1027. return S_OK;
  1028. }
  1029. /***************************************************************************++
  1030. Routine Description:
  1031. Compares two string arrays.
  1032. Arguments:
  1033. Return Value:
  1034. HRESULT
  1035. --***************************************************************************/
  1036. BOOL MatchDelimitedStringArray(DELIMITEDSTRING* i_aString1,
  1037. ULONG i_cString1,
  1038. DELIMITEDSTRING* i_aString2,
  1039. ULONG i_cString2)
  1040. {
  1041. DBG_ASSERT((i_cString1 > 0) && (i_cString2 >0));
  1042. if(i_cString1 != i_cString2)
  1043. {
  1044. return FALSE;
  1045. }
  1046. qsort((void*)i_aString1, i_cString1, sizeof(DELIMITEDSTRING), MyCompareCommaDelimitedStrings);
  1047. qsort((void*)i_aString2, i_cString2, sizeof(DELIMITEDSTRING), MyCompareCommaDelimitedStrings);
  1048. for(ULONG i=0; i<i_cString1; i++)
  1049. {
  1050. if(0 != MyCompareCommaDelimitedStrings(&(i_aString1[i]),
  1051. &(i_aString2[i]))
  1052. )
  1053. {
  1054. return FALSE;
  1055. }
  1056. }
  1057. return TRUE;
  1058. }
  1059. /***************************************************************************++
  1060. Routine Description:
  1061. Looks at the optinal and manditory properties of a class and determines
  1062. if ti differs fromt the shipped schema.
  1063. Arguments:
  1064. [in] Class name.
  1065. [in] Optional properties.
  1066. [in] Manditory properties.
  1067. [in] Writer object.
  1068. Return Value:
  1069. HRESULT
  1070. --***************************************************************************/
  1071. BOOL ClassPropertiesDifferFromShippedSchema(LPCWSTR i_wszClassName,
  1072. LPWSTR i_wszOptProperties,
  1073. LPWSTR i_wszMandProperties)
  1074. {
  1075. BOOL bClassPropertiesDifferFromShippedSchema = FALSE;
  1076. ULONG i = 0;
  1077. HRESULT hr = S_OK;
  1078. DELIMITEDSTRING aPropertyFixed[cMaxProperty];
  1079. ULONG cProperty = cMaxProperty;
  1080. ULONG iProperty = 0;
  1081. DELIMITEDSTRING* aProperty = aPropertyFixed;
  1082. BOOL bReAlloced = FALSE;
  1083. if( ((NULL == i_wszOptProperties) || (0 == *i_wszOptProperties)) &&
  1084. ((NULL == i_wszMandProperties) || (0 == *i_wszMandProperties))
  1085. )
  1086. {
  1087. //
  1088. // It is true that you cannot delete all shipped properties from a shipped class,
  1089. // because every shipped class that we know of has at least one location property.
  1090. // But there may be previously added extension that were deleted, so assume something
  1091. // changed, when there are no properties.
  1092. //
  1093. bClassPropertiesDifferFromShippedSchema = TRUE;
  1094. goto exit;
  1095. }
  1096. //
  1097. // Now create an array of
  1098. // mand + opt properties
  1099. //
  1100. if((NULL != i_wszOptProperties) && (0 != *i_wszOptProperties))
  1101. {
  1102. hr = CommaDelimitedStringToArray(i_wszOptProperties,
  1103. &aProperty,
  1104. &iProperty,
  1105. &cProperty,
  1106. &bReAlloced);
  1107. if(FAILED(hr))
  1108. {
  1109. goto exit;
  1110. }
  1111. }
  1112. if((NULL != i_wszMandProperties) && (0 != *i_wszMandProperties))
  1113. {
  1114. hr = CommaDelimitedStringToArray(i_wszMandProperties,
  1115. &aProperty,
  1116. &iProperty,
  1117. &cProperty,
  1118. &bReAlloced);
  1119. if(FAILED(hr))
  1120. {
  1121. goto exit;
  1122. }
  1123. }
  1124. for(i=0; i<iProperty; i++ )
  1125. {
  1126. LPWSTR wszPropertyName = aProperty[i].pwszStringStart;
  1127. LPWSTR wszEnd = aProperty[i].pwszStringEnd;
  1128. WCHAR wchEndSav;
  1129. ULONG aColSearchProperty[] = {iCOLUMNMETA_Table,
  1130. iCOLUMNMETA_InternalName
  1131. };
  1132. ULONG cColSearchProperty = sizeof(aColSearchProperty)/sizeof(ULONG);
  1133. LPVOID apvSearchProperty[cCOLUMNMETA_NumberOfColumns];
  1134. ULONG iStartRowProperty = 0;
  1135. ULONG iColPropertyMetaFlagsEx = iCOLUMNMETA_SchemaGeneratorFlags;
  1136. DWORD* pdwExtended = NULL;
  1137. //
  1138. // Null terminate the property name and initialize it.
  1139. // Hence on gotos until you reset it.
  1140. //
  1141. wchEndSav = *wszEnd;
  1142. *wszEnd = L'\0';
  1143. apvSearchProperty[iCOLUMNMETA_Table] = (LPVOID)i_wszClassName;
  1144. apvSearchProperty[iCOLUMNMETA_InternalName] = (LPVOID)wszPropertyName;
  1145. //
  1146. // See if the property is found in the class and see if it is shipped
  1147. //
  1148. hr = g_pGlobalISTHelper->m_pISTColumnMetaByTableAndName->GetRowIndexBySearch(iStartRowProperty,
  1149. cColSearchProperty,
  1150. aColSearchProperty,
  1151. NULL,
  1152. apvSearchProperty,
  1153. &iStartRowProperty);
  1154. if(SUCCEEDED(hr))
  1155. {
  1156. hr = g_pGlobalISTHelper->m_pISTColumnMetaByTableAndName->GetColumnValues(iStartRowProperty,
  1157. 1,
  1158. &iColPropertyMetaFlagsEx,
  1159. NULL,
  1160. (LPVOID*)&pdwExtended);
  1161. if(FAILED(hr) || ( ((*pdwExtended) & (fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) != 0))
  1162. {
  1163. //
  1164. // Found at least one property that is not in the shipped schema
  1165. //
  1166. bClassPropertiesDifferFromShippedSchema = TRUE;
  1167. }
  1168. //
  1169. // Else condition means it succeeded and it was a shipped property
  1170. // if(SUCCEEDED(hr) && ( ((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
  1171. //
  1172. }
  1173. else
  1174. {
  1175. //
  1176. // May be its a tag value. Check if it is in the tag meta
  1177. //
  1178. ULONG aColSearchTag[] = {iTAGMETA_Table,
  1179. iTAGMETA_InternalName
  1180. };
  1181. ULONG cColSearchTag = sizeof(aColSearchTag)/sizeof(ULONG);
  1182. LPVOID apvSearchTag[cTAGMETA_NumberOfColumns];
  1183. ULONG iStartRowTag = 0;
  1184. ULONG iColIndex = iTAGMETA_ColumnIndex;
  1185. DWORD* pdwColumnIndex = NULL;
  1186. apvSearchTag[iTAGMETA_Table] = (LPVOID)i_wszClassName;
  1187. apvSearchTag[iTAGMETA_InternalName] = (LPVOID)wszPropertyName;
  1188. hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndName->GetRowIndexBySearch(iStartRowTag,
  1189. cColSearchTag,
  1190. aColSearchTag,
  1191. NULL,
  1192. apvSearchTag,
  1193. &iStartRowTag);
  1194. if(FAILED(hr))
  1195. {
  1196. bClassPropertiesDifferFromShippedSchema = TRUE;
  1197. }
  1198. else
  1199. {
  1200. //
  1201. // Check if the parent property of this tag is shipped, if it is not,
  1202. // then this becomes a non-shipped tag
  1203. //
  1204. hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndName->GetColumnValues(iStartRowTag,
  1205. 1,
  1206. &iColIndex,
  1207. NULL,
  1208. (LPVOID*)&pdwColumnIndex);
  1209. if(SUCCEEDED(hr))
  1210. {
  1211. LPVOID a_Identity[] = {(LPVOID)i_wszClassName,
  1212. (LPVOID)pdwColumnIndex
  1213. };
  1214. ULONG iRow = 0;
  1215. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetRowIndexByIdentity(NULL,
  1216. a_Identity,
  1217. &iRow);
  1218. if(SUCCEEDED(hr))
  1219. {
  1220. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(iRow,
  1221. 1,
  1222. &iColPropertyMetaFlagsEx,
  1223. NULL,
  1224. (LPVOID*)&pdwExtended);
  1225. if(FAILED(hr) || ( ((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) != 0))
  1226. {
  1227. //
  1228. // Found at least one property that is not in the shipped schema
  1229. //
  1230. bClassPropertiesDifferFromShippedSchema = TRUE;
  1231. }
  1232. //
  1233. // Else condition means it succeeded and it was a shipped property
  1234. // if(SUCCEEDED(hr) && ( ((*pdwExtended)&(fCOLUMNMETA_EXTENDED|fCOLUMNMETA_USERDEFINED)) == 0))
  1235. //
  1236. }
  1237. }
  1238. else
  1239. {
  1240. bClassPropertiesDifferFromShippedSchema = TRUE;
  1241. }
  1242. }
  1243. }
  1244. //
  1245. // Restore the property name
  1246. //
  1247. *wszEnd = wchEndSav;
  1248. if(FAILED(hr) || bClassPropertiesDifferFromShippedSchema)
  1249. {
  1250. goto exit;
  1251. }
  1252. }
  1253. exit:
  1254. if(FAILED(hr))
  1255. {
  1256. bClassPropertiesDifferFromShippedSchema = TRUE;
  1257. }
  1258. if(aProperty != aPropertyFixed)
  1259. {
  1260. delete [] aProperty;
  1261. }
  1262. return bClassPropertiesDifferFromShippedSchema;
  1263. } // ClassPropertiesDifferFromShippedSchema
  1264. /***************************************************************************++
  1265. Routine Description:
  1266. Creates the IIsConfigObject collection - This collection has complete
  1267. definitions of all properties.
  1268. Arguments:
  1269. [in] Properties object.
  1270. [in,out] Writer object.
  1271. [in,out] Schema Writer object.
  1272. Return Value:
  1273. HRESULT
  1274. --***************************************************************************/
  1275. HRESULT CreateIISConfigObjectCollection(CMDBaseObject* i_pObjProperties,
  1276. CWriter* i_pCWriter,
  1277. CMBSchemaWriter** io_pSchemaWriter)
  1278. {
  1279. HRESULT hr = S_OK;
  1280. CMBCollectionWriter* pCollectionWriter = NULL;
  1281. hr = SaveNames(i_pObjProperties,
  1282. i_pCWriter,
  1283. io_pSchemaWriter,
  1284. &pCollectionWriter);
  1285. if(FAILED(hr))
  1286. {
  1287. return hr;
  1288. }
  1289. hr = SaveTypes(i_pObjProperties,
  1290. i_pCWriter,
  1291. io_pSchemaWriter,
  1292. &pCollectionWriter);
  1293. if(FAILED(hr))
  1294. {
  1295. return hr;
  1296. }
  1297. hr = SaveDefaults(i_pObjProperties,
  1298. i_pCWriter,
  1299. io_pSchemaWriter,
  1300. &pCollectionWriter);
  1301. if(FAILED(hr))
  1302. {
  1303. return hr;
  1304. }
  1305. return hr;
  1306. }
  1307. /***************************************************************************++
  1308. Routine Description:
  1309. Saves the extended roperty name
  1310. Arguments:
  1311. [in] Metabase properties object.
  1312. [in,out] Writer object.
  1313. [in,out] Schema Writer object.
  1314. [in,out] Collection Writer object.
  1315. Return Value:
  1316. HRESULT
  1317. --***************************************************************************/
  1318. HRESULT SaveNames(CMDBaseObject* i_pObjProperties,
  1319. CWriter* i_pCWriter,
  1320. CMBSchemaWriter** io_pSchemaWriter,
  1321. CMBCollectionWriter** io_pCollectionWriter)
  1322. {
  1323. HRESULT hr = S_OK;
  1324. CMDBaseObject* pObjNames = NULL;
  1325. CMDBaseData* pObjData = NULL;
  1326. DWORD dwEnumIndex = 0;
  1327. LPWSTR wszNames = L"Names";
  1328. //
  1329. // Get the names object
  1330. //
  1331. pObjNames = i_pObjProperties->GetChildObject((LPSTR&)wszNames,
  1332. &hr,
  1333. TRUE);
  1334. if(FAILED(hr) || (NULL == pObjNames))
  1335. {
  1336. DBGINFOW((DBG_CONTEXT,
  1337. L"[SaveSchema] Unable to open /Schema/Properties/Names. GetChildObject failed with hr = 0x%x.\n",hr));
  1338. return hr;
  1339. }
  1340. //
  1341. // Populate the Column meta array by enumerating the names key.
  1342. //
  1343. for(dwEnumIndex=0,
  1344. pObjData=pObjNames->EnumDataObject(dwEnumIndex++,
  1345. 0,
  1346. ALL_METADATA,
  1347. ALL_METADATA);
  1348. (SUCCEEDED(hr)) && (pObjData!=NULL);
  1349. pObjData=pObjNames->EnumDataObject(dwEnumIndex++,
  1350. 0,
  1351. ALL_METADATA,
  1352. ALL_METADATA))
  1353. {
  1354. CMBPropertyWriter *pProperty = NULL;
  1355. if(pObjData->GetDataType() != STRING_METADATA)
  1356. {
  1357. DBGINFOW((DBG_CONTEXT,
  1358. L"[SaveSchema] Encountered non-string data in the names tree of the schema. Ignoring entry for this ID: %d \n",pObjData->GetIdentifier()));
  1359. continue;
  1360. }
  1361. if(PropertyNotInShippedSchema(i_pCWriter,
  1362. pObjData->GetIdentifier())
  1363. )
  1364. {
  1365. if(NULL == *io_pCollectionWriter)
  1366. {
  1367. hr = GetCollectionWriter(i_pCWriter,
  1368. io_pSchemaWriter,
  1369. io_pCollectionWriter,
  1370. wszTABLE_IIsConfigObject,
  1371. FALSE,
  1372. NULL);
  1373. if(FAILED(hr))
  1374. {
  1375. return hr;
  1376. }
  1377. }
  1378. hr = (*io_pCollectionWriter)->GetMBPropertyWriter(pObjData->GetIdentifier(),
  1379. &pProperty);
  1380. if(FAILED(hr))
  1381. {
  1382. DBGINFOW((DBG_CONTEXT,
  1383. L"[SaveSchema] Error while saving names tree. GetPropertyWriter for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
  1384. return hr;
  1385. }
  1386. pProperty->AddNameToProperty((LPCWSTR)(pObjData->GetData(TRUE)));
  1387. }
  1388. }
  1389. //
  1390. // Must call create index else it will keep adding duplicate property entries.
  1391. //
  1392. return hr;
  1393. } // SaveNames
  1394. /***************************************************************************++
  1395. Routine Description:
  1396. Saves the extended roperty type
  1397. Arguments:
  1398. [in] Metabase properties object.
  1399. [in,out] Writer object.
  1400. [in,out] Schema Writer object.
  1401. [in,out] Collection Writer object.
  1402. Return Value:
  1403. HRESULT
  1404. --***************************************************************************/
  1405. HRESULT SaveTypes(CMDBaseObject* i_pObjProperties,
  1406. CWriter* i_pCWriter,
  1407. CMBSchemaWriter** io_pSchemaWriter,
  1408. CMBCollectionWriter** io_pCollectionWriter)
  1409. {
  1410. HRESULT hr = S_OK;
  1411. CMDBaseObject* pObjTypes = NULL;
  1412. CMDBaseData* pObjData = NULL;
  1413. DWORD dwEnumIndex = 0;
  1414. LPWSTR wszTypes = L"Types";
  1415. //
  1416. // Get the Types object
  1417. //
  1418. pObjTypes = i_pObjProperties->GetChildObject((LPSTR&)wszTypes,
  1419. &hr,
  1420. TRUE);
  1421. if(FAILED(hr) || (NULL == pObjTypes))
  1422. {
  1423. DBGINFOW((DBG_CONTEXT,
  1424. L"[SaveSchema] Unable to open /Schema/Properties/Types. GetChildObject failed with hr = 0x%x.\n",hr));
  1425. return hr;
  1426. }
  1427. for(dwEnumIndex=0,
  1428. pObjData=pObjTypes->EnumDataObject(dwEnumIndex++,
  1429. 0,
  1430. ALL_METADATA,
  1431. ALL_METADATA);
  1432. (SUCCEEDED(hr)) && (pObjData!=NULL);
  1433. pObjData=pObjTypes->EnumDataObject(dwEnumIndex++,
  1434. 0,
  1435. ALL_METADATA,
  1436. ALL_METADATA))
  1437. {
  1438. CMBPropertyWriter *pProperty = NULL;
  1439. if(pObjData->GetDataType() != BINARY_METADATA ||
  1440. pObjData->GetDataLen(TRUE) != sizeof(PropValue))
  1441. {
  1442. DBGINFOW((DBG_CONTEXT,
  1443. 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",
  1444. pObjData->GetIdentifier(),
  1445. pObjData->GetDataType(),
  1446. BINARY_METADATA,
  1447. pObjData->GetDataLen(TRUE),
  1448. sizeof(PropValue)));
  1449. if(pObjData->GetDataType() == STRING_METADATA )
  1450. {
  1451. DBGINFOW((DBG_CONTEXT,
  1452. L"Data: %s.\n",
  1453. pObjData->GetData(TRUE)
  1454. ));
  1455. }
  1456. continue;
  1457. }
  1458. if(PropertyNotInShippedSchema(i_pCWriter,
  1459. pObjData->GetIdentifier())
  1460. )
  1461. {
  1462. if(NULL == *io_pCollectionWriter)
  1463. {
  1464. hr = GetCollectionWriter(i_pCWriter,
  1465. io_pSchemaWriter,
  1466. io_pCollectionWriter,
  1467. wszTABLE_IIsConfigObject,
  1468. FALSE,
  1469. NULL);
  1470. if(FAILED(hr))
  1471. {
  1472. return hr;
  1473. }
  1474. }
  1475. hr = (*io_pCollectionWriter)->GetMBPropertyWriter(pObjData->GetIdentifier(),
  1476. &pProperty);
  1477. if(FAILED(hr))
  1478. {
  1479. DBGINFOW((DBG_CONTEXT,
  1480. L"[SaveSchema] Error while saving types tree. GetPropertyWriter for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
  1481. return hr;
  1482. }
  1483. hr = pProperty->AddTypeToProperty((PropValue*)(pObjData->GetData(TRUE)));
  1484. if(FAILED(hr))
  1485. {
  1486. DBGINFOW((DBG_CONTEXT,
  1487. L"[SaveSchema] Error while saving types tree. AddTypeToProperty for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
  1488. return hr;
  1489. }
  1490. }
  1491. }
  1492. return hr;
  1493. }
  1494. /***************************************************************************++
  1495. Routine Description:
  1496. Saves the extended roperty default
  1497. Arguments:
  1498. [in] Metabase properties object.
  1499. [in,out] Writer object.
  1500. [in,out] Schema Writer object.
  1501. [in,out] Collection Writer object.
  1502. Return Value:
  1503. HRESULT
  1504. --***************************************************************************/
  1505. HRESULT SaveDefaults(CMDBaseObject* i_pObjProperties,
  1506. CWriter* i_pCWriter,
  1507. CMBSchemaWriter** io_pSchemaWriter,
  1508. CMBCollectionWriter** io_pCollectionWriter)
  1509. {
  1510. HRESULT hr = S_OK;
  1511. CMDBaseObject* pObjDefaults = NULL;
  1512. CMDBaseData* pObjData = NULL;
  1513. DWORD dwEnumIndex = 0;
  1514. LPWSTR wszDefaults = L"Defaults";
  1515. //
  1516. // Get the Defaults object
  1517. //
  1518. pObjDefaults = i_pObjProperties->GetChildObject((LPSTR&)wszDefaults,
  1519. &hr,
  1520. TRUE);
  1521. if(FAILED(hr) || (NULL == pObjDefaults))
  1522. {
  1523. DBGINFOW((DBG_CONTEXT,
  1524. L"[SaveSchema] Unable to open /Schema/Properties/Defaults. GetChildObject failed with hr = 0x%x.\n",hr));
  1525. return hr;
  1526. }
  1527. for(dwEnumIndex=0,
  1528. pObjData=pObjDefaults->EnumDataObject(dwEnumIndex++,
  1529. 0,
  1530. ALL_METADATA,
  1531. ALL_METADATA);
  1532. (SUCCEEDED(hr)) && (pObjData!=NULL);
  1533. pObjData=pObjDefaults->EnumDataObject(dwEnumIndex++,
  1534. 0,
  1535. ALL_METADATA,
  1536. ALL_METADATA))
  1537. {
  1538. CMBPropertyWriter *pProperty = NULL;
  1539. if(PropertyNotInShippedSchema(i_pCWriter,
  1540. pObjData->GetIdentifier())
  1541. )
  1542. {
  1543. if(NULL == *io_pCollectionWriter)
  1544. {
  1545. hr = GetCollectionWriter(i_pCWriter,
  1546. io_pSchemaWriter,
  1547. io_pCollectionWriter,
  1548. wszTABLE_IIsConfigObject,
  1549. FALSE,
  1550. NULL);
  1551. if(FAILED(hr))
  1552. {
  1553. return hr;
  1554. }
  1555. }
  1556. hr = (*io_pCollectionWriter)->GetMBPropertyWriter(pObjData->GetIdentifier(),
  1557. &pProperty);
  1558. if(FAILED(hr))
  1559. {
  1560. DBGINFOW((DBG_CONTEXT,
  1561. L"[SaveSchema] Error while saving defaults tree. GetPropertyWriter for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
  1562. return hr;
  1563. }
  1564. hr = pProperty->AddDefaultToProperty((BYTE*)(pObjData->GetData(TRUE)),
  1565. pObjData->GetDataLen(TRUE));
  1566. if(FAILED(hr))
  1567. {
  1568. DBGINFOW((DBG_CONTEXT,
  1569. L"[SaveSchema] Error while saving types tree. AddDefaultToProperty for ID:%d failed with hr = 0x%x.\n",pObjData->GetIdentifier(), hr));
  1570. return hr;
  1571. }
  1572. }
  1573. }
  1574. return hr;
  1575. }
  1576. /***************************************************************************++
  1577. Routine Description:
  1578. Saves the extended roperty name
  1579. Arguments:
  1580. [in,out] Writer object.
  1581. [in,out] Schema Writer object.
  1582. [in,out] Collection Writer object.
  1583. [in] Collection name
  1584. [in] Bool that indicates container
  1585. [in] Container class list
  1586. Return Value:
  1587. HRESULT
  1588. --***************************************************************************/
  1589. HRESULT GetCollectionWriter(CWriter* i_pCWriter,
  1590. CMBSchemaWriter** io_pSchemaWriter,
  1591. CMBCollectionWriter** io_pCollectionWriter,
  1592. LPCWSTR i_wszCollectionName,
  1593. BOOL i_bContainer,
  1594. LPCWSTR i_wszContainerClassList)
  1595. {
  1596. HRESULT hr = S_OK;
  1597. if(NULL != *io_pCollectionWriter)
  1598. {
  1599. return S_OK;
  1600. }
  1601. //
  1602. // Get the schema writer if it has not been created
  1603. //
  1604. if(NULL == *io_pSchemaWriter)
  1605. {
  1606. hr = i_pCWriter->GetMetabaseSchemaWriter(io_pSchemaWriter);
  1607. if(FAILED(hr))
  1608. {
  1609. DBGINFOW((DBG_CONTEXT,
  1610. L"[SaveSchema] Error while saving schema tree. Unable to get schema writer failed with hr = 0x%x.\n", hr));
  1611. return hr;
  1612. }
  1613. }
  1614. //
  1615. // Get collection writer for the collection
  1616. //
  1617. hr = (*io_pSchemaWriter)->GetCollectionWriter(i_wszCollectionName,
  1618. i_bContainer,
  1619. i_wszContainerClassList,
  1620. io_pCollectionWriter);
  1621. if(FAILED(hr))
  1622. {
  1623. DBGINFOW((DBG_CONTEXT,
  1624. L"[SaveSchema] GetCollectionWriter for %s failed with hr = 0x%x.\n",
  1625. i_wszCollectionName, hr));
  1626. return hr;
  1627. }
  1628. return S_OK;
  1629. }