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.

2226 lines
68 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. ReadSchema.cpp
  5. Abstract:
  6. Implementation of the helper functions that are used to read
  7. schema information from the config stuctures into the metabase.
  8. Author:
  9. Varsha Jayasimha (varshaj) 30-Nov-1999
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. DWORD GetMetabaseFlags(DWORD i_CatalogFlag)
  14. {
  15. return i_CatalogFlag & 0x00000003; // First two bits represent metabase flag property.
  16. }
  17. /***************************************************************************++
  18. Routine Description:
  19. Reads the schema fromthe catalog into the schema tree.
  20. Arguments:
  21. [in] Storage pointer.
  22. [in] Filetime pointer.
  23. Return Value:
  24. HRESULT
  25. --***************************************************************************/
  26. HRESULT ReadSchema(IIS_CRYPTO_STORAGE* i_pStorage,
  27. FILETIME* i_pFileTime)
  28. {
  29. HRESULT hr = S_OK;
  30. CMDBaseObject* pboReadSchema = NULL;
  31. if(FAILED(hr))
  32. {
  33. goto exit;
  34. }
  35. hr = ReadMetaObject(pboReadSchema,
  36. (LPWSTR)g_wszSlashSchema,
  37. i_pFileTime,
  38. TRUE);
  39. if(FAILED(hr))
  40. {
  41. goto exit;
  42. }
  43. hr = ReadSchemaProperties(pboReadSchema,
  44. i_pStorage);
  45. if(FAILED(hr))
  46. {
  47. goto exit;
  48. }
  49. hr = ReadProperties(i_pStorage,
  50. i_pFileTime);
  51. if(FAILED(hr))
  52. {
  53. goto exit;
  54. }
  55. hr = ReadClasses(i_pStorage,
  56. i_pFileTime);
  57. if(FAILED(hr))
  58. {
  59. goto exit;
  60. }
  61. exit:
  62. return hr;
  63. } // ReadSchema
  64. /***************************************************************************++
  65. Routine Description:
  66. Reads the properties in the root of the schema.
  67. Arguments:
  68. [in] Pointer to the metabase object.
  69. [in] Storage pointer.
  70. Return Value:
  71. HRESULT
  72. --***************************************************************************/
  73. HRESULT ReadSchemaProperties(CMDBaseObject* i_pboRead,
  74. IIS_CRYPTO_STORAGE* i_pStorage)
  75. {
  76. HRESULT hr = S_OK;
  77. hr = ReadAdminACL(i_pboRead,
  78. i_pStorage);
  79. if(FAILED(hr))
  80. {
  81. return hr;
  82. }
  83. hr = ReadLargestMetaID(i_pboRead,
  84. i_pStorage);
  85. if(FAILED(hr))
  86. {
  87. return hr;
  88. }
  89. return hr;
  90. } // ReadSchemaProperties
  91. /***************************************************************************++
  92. Routine Description:
  93. Construct the Admin ACL property
  94. Arguments:
  95. [in] Pointer to the metabase object.
  96. [in] Storage pointer.
  97. Return Value:
  98. HRESULT
  99. --***************************************************************************/
  100. HRESULT ReadAdminACL(CMDBaseObject* i_pboRead,
  101. IIS_CRYPTO_STORAGE* )
  102. {
  103. BOOL b = FALSE;
  104. DWORD dwLength = 0;
  105. PSECURITY_DESCRIPTOR pSD = NULL;
  106. PSECURITY_DESCRIPTOR outpSD = NULL;
  107. DWORD cboutpSD = 0;
  108. PACL pACLNew = NULL;
  109. DWORD cbACL = 0;
  110. PSID pAdminsSID = NULL;
  111. PSID pEveryoneSID = NULL;
  112. BOOL bWellKnownSID = FALSE;
  113. HRESULT hr = S_OK;
  114. DWORD dwRes = 0;
  115. DWORD dwMetaIDAdminACL = MD_ADMIN_ACL;
  116. DWORD dwAttributesAdminACL = METADATA_INHERIT | METADATA_REFERENCE | METADATA_SECURE;
  117. DWORD dwUserTypeAdminACL = IIS_MD_UT_SERVER;
  118. DWORD dwDataTypeAdminACL = BINARY_METADATA;
  119. LPVOID a_pv[cMBProperty_NumberOfColumns];
  120. ULONG a_Size[cMBProperty_NumberOfColumns];
  121. //
  122. // Initialize a new security descriptor
  123. //
  124. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
  125. SECURITY_DESCRIPTOR_MIN_LENGTH);
  126. if (!pSD)
  127. {
  128. hr = E_OUTOFMEMORY;
  129. goto exit;
  130. }
  131. InitializeSecurityDescriptor(pSD,
  132. SECURITY_DESCRIPTOR_REVISION);
  133. //
  134. // Get Local Admins Sid
  135. //
  136. dwRes = GetPrincipalSID (L"Administrators",
  137. &pAdminsSID,
  138. &bWellKnownSID);
  139. if(ERROR_SUCCESS != dwRes)
  140. {
  141. hr = HRESULT_FROM_WIN32(dwRes);
  142. goto exit;
  143. }
  144. //
  145. // Get everyone Sid
  146. //
  147. GetPrincipalSID (L"Everyone", &pEveryoneSID, &bWellKnownSID);
  148. //
  149. // Initialize a new ACL, which only contains 2 aaace
  150. //
  151. cbACL = sizeof(ACL) +
  152. (sizeof(ACCESS_ALLOWED_ACE) +
  153. GetLengthSid(pAdminsSID) - sizeof(DWORD)) +
  154. (sizeof(ACCESS_ALLOWED_ACE) +
  155. GetLengthSid(pEveryoneSID) - sizeof(DWORD));
  156. pACLNew = (PACL) LocalAlloc(LPTR,
  157. cbACL);
  158. if (!pACLNew)
  159. {
  160. hr = E_OUTOFMEMORY;
  161. goto exit;
  162. }
  163. InitializeAcl(pACLNew,
  164. cbACL,
  165. ACL_REVISION);
  166. AddAccessAllowedAce(pACLNew,
  167. ACL_REVISION,
  168. FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE,
  169. pAdminsSID);
  170. AddAccessAllowedAce(pACLNew,
  171. ACL_REVISION,
  172. FILE_GENERIC_READ,
  173. pEveryoneSID);
  174. //
  175. // Add the ACL to the security descriptor
  176. //
  177. b = SetSecurityDescriptorDacl(pSD,
  178. TRUE,
  179. pACLNew,
  180. FALSE);
  181. if(!b)
  182. {
  183. hr = GetLastError();
  184. hr = HRESULT_FROM_WIN32(hr);
  185. goto exit;
  186. }
  187. b = SetSecurityDescriptorOwner(pSD,
  188. pAdminsSID,
  189. TRUE);
  190. if(!b)
  191. {
  192. hr = GetLastError();
  193. hr = HRESULT_FROM_WIN32(hr);
  194. goto exit;
  195. }
  196. b = SetSecurityDescriptorGroup(pSD,
  197. pAdminsSID,
  198. TRUE);
  199. if(!b)
  200. {
  201. hr = GetLastError();
  202. hr = HRESULT_FROM_WIN32(hr);
  203. goto exit;
  204. }
  205. //
  206. // Security descriptor blob must be self relative
  207. //
  208. b = MakeSelfRelativeSD(pSD,
  209. outpSD,
  210. &cboutpSD);
  211. outpSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GPTR,
  212. cboutpSD);
  213. if (!outpSD)
  214. {
  215. hr = E_OUTOFMEMORY;
  216. goto exit;
  217. }
  218. b = MakeSelfRelativeSD(pSD,
  219. outpSD,
  220. &cboutpSD);
  221. if(!b)
  222. {
  223. hr = GetLastError();
  224. hr = HRESULT_FROM_WIN32(hr);
  225. goto exit;
  226. }
  227. //
  228. // below this modify pSD to outpSD
  229. //
  230. //
  231. // Apply the new security descriptor to the file
  232. //
  233. dwLength = GetSecurityDescriptorLength(outpSD);
  234. //
  235. // Apply the new security descriptor to the file
  236. //
  237. //
  238. // Read all the property names. If the property is a flag, then read
  239. // all the flag names as well.
  240. //
  241. a_pv[iMBProperty_Name] = NULL;
  242. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchema;
  243. a_pv[iMBProperty_ID] = &dwMetaIDAdminACL;
  244. a_pv[iMBProperty_Attributes] = &dwAttributesAdminACL;
  245. a_pv[iMBProperty_UserType] = &dwUserTypeAdminACL;
  246. a_pv[iMBProperty_Type] = &dwDataTypeAdminACL;
  247. a_pv[iMBProperty_Value] = (LPBYTE)outpSD;
  248. a_Size[iMBProperty_Value] = dwLength;
  249. hr = ReadDataObject(i_pboRead,
  250. a_pv,
  251. a_Size,
  252. NULL, // We should not be passing crypto object here, if we do it will attempt to decrypt it because the attribute is sucure.
  253. TRUE);
  254. exit :
  255. //
  256. //Cleanup:
  257. // both of Administrators and Everyone are well-known SIDs, use FreeSid() to free them.
  258. //
  259. if (outpSD)
  260. GlobalFree(outpSD);
  261. if (pAdminsSID)
  262. FreeSid(pAdminsSID);
  263. if (pEveryoneSID)
  264. FreeSid(pEveryoneSID);
  265. if (pSD)
  266. LocalFree((HLOCAL) pSD);
  267. if (pACLNew)
  268. LocalFree((HLOCAL) pACLNew);
  269. return (hr);
  270. }
  271. /***************************************************************************++
  272. Routine Description:
  273. Helper function to read construct the Admin ACL.
  274. Arguments:
  275. Return Value:
  276. HRESULT
  277. --***************************************************************************/
  278. DWORD GetPrincipalSID (LPWSTR Principal,
  279. PSID *Sid,
  280. BOOL *pbWellKnownSID)
  281. {
  282. SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY;
  283. SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY;
  284. PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority = NULL;
  285. BYTE Count = 0;
  286. DWORD dwRID[8];
  287. *pbWellKnownSID = TRUE;
  288. memset(&(dwRID[0]), 0, 8 * sizeof(DWORD));
  289. if ( wcscmp(Principal,L"Administrators") == 0 )
  290. {
  291. //
  292. // Administrators group
  293. //
  294. pSidIdentifierAuthority = &SidIdentifierNTAuthority;
  295. Count = 2;
  296. dwRID[0] = SECURITY_BUILTIN_DOMAIN_RID;
  297. dwRID[1] = DOMAIN_ALIAS_RID_ADMINS;
  298. }
  299. else if ( wcscmp(Principal,L"System") == 0)
  300. {
  301. //
  302. // SYSTEM
  303. //
  304. pSidIdentifierAuthority = &SidIdentifierNTAuthority;
  305. Count = 1;
  306. dwRID[0] = SECURITY_LOCAL_SYSTEM_RID;
  307. }
  308. else if ( wcscmp(Principal,L"Interactive") == 0)
  309. {
  310. //
  311. // INTERACTIVE
  312. //
  313. pSidIdentifierAuthority = &SidIdentifierNTAuthority;
  314. Count = 1;
  315. dwRID[0] = SECURITY_INTERACTIVE_RID;
  316. }
  317. else if ( wcscmp(Principal,L"Everyone") == 0)
  318. {
  319. //
  320. // Everyone
  321. //
  322. pSidIdentifierAuthority = &SidIdentifierWORLDAuthority;
  323. Count = 1;
  324. dwRID[0] = SECURITY_WORLD_RID;
  325. }
  326. else
  327. {
  328. *pbWellKnownSID = FALSE;
  329. }
  330. if (*pbWellKnownSID)
  331. {
  332. if ( !AllocateAndInitializeSid(pSidIdentifierAuthority,
  333. (BYTE)Count,
  334. dwRID[0],
  335. dwRID[1],
  336. dwRID[2],
  337. dwRID[3],
  338. dwRID[4],
  339. dwRID[5],
  340. dwRID[6],
  341. dwRID[7],
  342. Sid) )
  343. return GetLastError();
  344. } else {
  345. // get regular account sid
  346. DWORD sidSize;
  347. WCHAR refDomain [256];
  348. DWORD refDomainSize;
  349. DWORD returnValue;
  350. SID_NAME_USE snu;
  351. sidSize = 0;
  352. refDomainSize = 255;
  353. LookupAccountNameW(NULL,
  354. Principal,
  355. *Sid,
  356. &sidSize,
  357. refDomain,
  358. &refDomainSize,
  359. &snu);
  360. returnValue = GetLastError();
  361. if (returnValue != ERROR_INSUFFICIENT_BUFFER)
  362. return returnValue;
  363. *Sid = (PSID) malloc (sidSize);
  364. refDomainSize = 255;
  365. if(NULL == *Sid)
  366. {
  367. return ERROR_NOT_ENOUGH_MEMORY;
  368. }
  369. else if (!LookupAccountNameW(NULL,
  370. Principal,
  371. *Sid,
  372. &sidSize,
  373. refDomain,
  374. &refDomainSize,
  375. &snu))
  376. {
  377. return GetLastError();
  378. }
  379. }
  380. return ERROR_SUCCESS;
  381. }
  382. /***************************************************************************++
  383. Routine Description:
  384. Reads the largest metabase id available so far from the schema.
  385. Arguments:
  386. [in] Pointer to the metabase object.
  387. [in] Storage pointer.
  388. Return Value:
  389. HRESULT
  390. --***************************************************************************/
  391. HRESULT ReadLargestMetaID(CMDBaseObject* i_pboRead,
  392. IIS_CRYPTO_STORAGE* i_pStorage)
  393. {
  394. HRESULT hr = S_OK;
  395. DWORD* pdwLargestID = NULL;
  396. DWORD dwLargestIDDefault = IIS_MD_ADSI_METAID_BEGIN;
  397. DWORD dwMetaIDMetaID = MD_SCHEMA_METAID;
  398. DWORD dwAttributesMetaID = METADATA_NO_ATTRIBUTES;
  399. DWORD dwUserTypeMetaID = IIS_MD_UT_SERVER;
  400. DWORD dwDataTypeMetaID = DWORD_METADATA;
  401. ULONG iCol = iTABLEMETA_ExtendedVersion; // Largest ID is stored in this column
  402. ULONG iRow = 0;
  403. LPWSTR wszTable = wszTABLE_IIsConfigObject;
  404. LPVOID a_pv[cMBProperty_NumberOfColumns];
  405. ULONG a_Size[cMBProperty_NumberOfColumns];
  406. hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetRowIndexByIdentity(NULL,
  407. (LPVOID*)&wszTable,
  408. &iRow);
  409. if(SUCCEEDED(hr))
  410. {
  411. hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetColumnValues(iRow,
  412. 1,
  413. &iCol,
  414. NULL,
  415. (LPVOID*)&pdwLargestID);
  416. }
  417. if(FAILED(hr))
  418. {
  419. DBGINFOW((DBG_CONTEXT,
  420. L"[SetLargestMetaID] Unable to read largest meta id from the meta tables. GetColumnValues failed with hr = 0x%x. Will default it to %d.\n",
  421. hr,
  422. dwLargestIDDefault));
  423. hr = S_OK;
  424. pdwLargestID = &dwLargestIDDefault;
  425. }
  426. a_pv[iMBProperty_Name] = NULL;
  427. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchema;
  428. a_pv[iMBProperty_ID] = &dwMetaIDMetaID;
  429. a_pv[iMBProperty_Attributes] = &dwAttributesMetaID;
  430. a_pv[iMBProperty_UserType] = &dwUserTypeMetaID;
  431. a_pv[iMBProperty_Type] = &dwDataTypeMetaID;
  432. a_pv[iMBProperty_Value] = (LPBYTE)pdwLargestID;
  433. a_Size[iMBProperty_Value] = sizeof(DWORD);
  434. hr = ReadDataObject(i_pboRead,
  435. a_pv,
  436. a_Size,
  437. i_pStorage,
  438. TRUE);
  439. return hr;
  440. }
  441. /***************************************************************************++
  442. Routine Description:
  443. Reads the properties into the schema tree.
  444. Arguments:
  445. [in] Pointer to the metabase object.
  446. [in] Storage pointer.
  447. Return Value:
  448. HRESULT
  449. --***************************************************************************/
  450. HRESULT ReadProperties(IIS_CRYPTO_STORAGE* i_pStorage,
  451. FILETIME* i_pFileTime)
  452. {
  453. HRESULT hr = S_OK;
  454. CMDBaseObject* pboReadProperties = NULL;
  455. CMDBaseObject* pboReadNames = NULL;
  456. CMDBaseObject* pboReadTypes = NULL;
  457. CMDBaseObject* pboReadDefaults = NULL;
  458. ULONG i = 0;
  459. ULONG iColIndex = 0;
  460. LPVOID a_Identity[] = {(LPVOID)g_pGlobalISTHelper->m_wszTABLE_IIsConfigObject,
  461. (LPVOID)&iColIndex
  462. };
  463. LPWSTR wszTable = NULL;
  464. LPVOID a_pv[cCOLUMNMETA_NumberOfColumns];
  465. ULONG a_Size[cCOLUMNMETA_NumberOfColumns];
  466. ULONG a_iCol[] = {iCOLUMNMETA_Table,
  467. iCOLUMNMETA_Index,
  468. iCOLUMNMETA_InternalName,
  469. iCOLUMNMETA_Type,
  470. iCOLUMNMETA_MetaFlags,
  471. iCOLUMNMETA_SchemaGeneratorFlags,
  472. iCOLUMNMETA_DefaultValue,
  473. iCOLUMNMETA_StartingNumber,
  474. iCOLUMNMETA_EndingNumber,
  475. iCOLUMNMETA_ID,
  476. iCOLUMNMETA_UserType,
  477. iCOLUMNMETA_Attributes
  478. };
  479. ULONG cCol = sizeof(a_iCol)/sizeof(ULONG);
  480. //
  481. // Initialize all the meta objects.
  482. //
  483. hr = ReadMetaObject(pboReadProperties,
  484. (LPWSTR)g_wszSlashSchemaSlashProperties,
  485. i_pFileTime,
  486. TRUE);
  487. if(FAILED(hr))
  488. {
  489. goto exit;
  490. }
  491. hr = ReadMetaObject(pboReadNames,
  492. (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashNames,
  493. i_pFileTime,
  494. TRUE);
  495. if(FAILED(hr))
  496. {
  497. goto exit;
  498. }
  499. hr = ReadMetaObject(pboReadTypes,
  500. (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashTypes,
  501. i_pFileTime,
  502. TRUE);
  503. if(FAILED(hr))
  504. {
  505. goto exit;
  506. }
  507. hr = ReadMetaObject(pboReadDefaults,
  508. (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashDefaults,
  509. i_pFileTime,
  510. TRUE);
  511. if(FAILED(hr))
  512. {
  513. goto exit;
  514. }
  515. //
  516. // Get the row index of the first column and then iterate thru the table until
  517. // e_st_nomorerows or the table difffers
  518. //
  519. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetRowIndexByIdentity(NULL,
  520. a_Identity,
  521. &i);
  522. if(FAILED(hr))
  523. {
  524. if(E_ST_NOMOREROWS == hr)
  525. {
  526. hr = S_OK;
  527. }
  528. goto exit;
  529. }
  530. //
  531. // For each property in this table, construct the name, type and default
  532. // in the metabase tree
  533. //
  534. for(;;i++)
  535. {
  536. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(i,
  537. cCol,
  538. a_iCol,
  539. a_Size,
  540. a_pv);
  541. if(E_ST_NOMOREROWS == hr)
  542. {
  543. hr = S_OK;
  544. break;
  545. }
  546. else if(FAILED(hr))
  547. {
  548. goto exit;
  549. }
  550. if(NULL == wszTable)
  551. {
  552. wszTable = (LPWSTR)a_pv[iCOLUMNMETA_Table];
  553. }
  554. if(wszTable != (LPWSTR)a_pv[iCOLUMNMETA_Table])
  555. {
  556. //
  557. // reached another table break
  558. //
  559. break;
  560. }
  561. MD_ASSERT(NULL != (DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]);
  562. if(fCOLUMNMETA_HIDDEN == (fCOLUMNMETA_HIDDEN & (*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags])))
  563. {
  564. //
  565. // Do not read hidden properties. All these properties have the
  566. // "HIDDEN" schemagenerator flag set on them.
  567. //
  568. continue;
  569. }
  570. hr = ReadPropertyNames(pboReadNames,
  571. a_pv,
  572. a_Size,
  573. i_pStorage);
  574. if(FAILED(hr))
  575. {
  576. goto exit;
  577. }
  578. hr = ReadPropertyTypes(pboReadTypes,
  579. a_pv,
  580. a_Size,
  581. i_pStorage);
  582. if(FAILED(hr))
  583. {
  584. goto exit;
  585. }
  586. if((*(DWORD*)a_pv[iCOLUMNMETA_MetaFlags]) & fCOLUMNMETA_FLAG)
  587. {
  588. hr = ReadAllFlags(i_pStorage,
  589. pboReadTypes,
  590. pboReadNames,
  591. pboReadDefaults,
  592. *(DWORD*)a_pv[iCOLUMNMETA_Index],
  593. *(DWORD*)a_pv[iCOLUMNMETA_ID],
  594. GetMetabaseFlags(*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]),
  595. *(DWORD*)a_pv[iCOLUMNMETA_Attributes],
  596. *(DWORD*)a_pv[iCOLUMNMETA_UserType],
  597. (*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]) & fCOLUMNMETA_MULTISTRING);
  598. if(FAILED(hr))
  599. {
  600. goto exit;
  601. }
  602. }
  603. hr = ReadPropertyDefaults(pboReadDefaults,
  604. a_pv,
  605. a_Size,
  606. i_pStorage);
  607. if(FAILED(hr))
  608. {
  609. goto exit;
  610. }
  611. }
  612. exit:
  613. return hr;
  614. } // ReadProperties
  615. /***************************************************************************++
  616. Routine Description:
  617. Reads names of properties into the schema.
  618. Arguments:
  619. [in] Pointer to the metabase object.
  620. [in] Array that hold catalog schema information about the property.
  621. [in] Array that holds count of bytes for the above.
  622. [in] Storage pointer.
  623. Return Value:
  624. HRESULT
  625. --***************************************************************************/
  626. HRESULT ReadPropertyNames(CMDBaseObject* i_pboRead,
  627. LPVOID* i_apv,
  628. ULONG* i_aSize,
  629. IIS_CRYPTO_STORAGE* i_pStorage)
  630. {
  631. HRESULT hr = S_OK;
  632. LPVOID a_pv[cMBProperty_NumberOfColumns];
  633. ULONG a_Size[cMBProperty_NumberOfColumns];
  634. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  635. DWORD dwType = STRING_METADATA;
  636. DWORD dwUserType = IIS_MD_UT_SERVER;
  637. //
  638. // Read all the property names. If the property is a flag, then read
  639. // all the flag names as well.
  640. //
  641. a_pv[iMBProperty_Name] = i_apv[iCOLUMNMETA_InternalName];
  642. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashNames;
  643. a_pv[iMBProperty_ID] = i_apv[iCOLUMNMETA_ID];
  644. a_pv[iMBProperty_Attributes] = &dwAttributes;
  645. a_pv[iMBProperty_UserType] = &dwUserType;
  646. a_pv[iMBProperty_Type] = &dwType;
  647. a_pv[iMBProperty_Value] = i_apv[iCOLUMNMETA_InternalName];
  648. a_Size[iMBProperty_Value] = i_aSize[iCOLUMNMETA_InternalName];
  649. hr = ReadDataObject(i_pboRead,
  650. a_pv,
  651. a_Size,
  652. i_pStorage,
  653. TRUE);
  654. return hr;
  655. } // ReadPropertyNames
  656. /***************************************************************************++
  657. Routine Description:
  658. Reads names of flags into the schema.
  659. Arguments:
  660. [in] Pointer to the metabase object.
  661. [in] Array that hold catalog schema information about the flags.
  662. [in] Array that holds count of bytes for the above.
  663. [in] Storage pointer.
  664. Return Value:
  665. HRESULT
  666. --***************************************************************************/
  667. HRESULT ReadFlagNames(CMDBaseObject* i_pboRead,
  668. LPVOID* i_apv,
  669. ULONG* i_aSize,
  670. IIS_CRYPTO_STORAGE* i_pStorage)
  671. {
  672. HRESULT hr = S_OK;
  673. LPVOID a_pv[cMBProperty_NumberOfColumns];
  674. ULONG a_Size[cMBProperty_NumberOfColumns];
  675. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  676. DWORD dwType = STRING_METADATA;
  677. DWORD dwUserType = IIS_MD_UT_SERVER;
  678. //
  679. // Read all the property names. If the property is a flag, then read
  680. // all the flag names as well.
  681. //
  682. a_pv[iMBProperty_Name] = i_apv[iTAGMETA_InternalName];
  683. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashNames;
  684. a_pv[iMBProperty_ID] = i_apv[iTAGMETA_ID];
  685. a_pv[iMBProperty_Attributes] = &dwAttributes;
  686. a_pv[iMBProperty_UserType] = &dwUserType;
  687. a_pv[iMBProperty_Type] = &dwType;
  688. a_pv[iMBProperty_Value] = i_apv[iTAGMETA_InternalName];
  689. a_Size[iMBProperty_Value] = i_aSize[iTAGMETA_InternalName];
  690. hr = ReadDataObject(i_pboRead,
  691. a_pv,
  692. a_Size,
  693. i_pStorage,
  694. TRUE);
  695. return hr;
  696. } // ReadFlagNames
  697. /***************************************************************************++
  698. Routine Description:
  699. Reads type information about the properties into the schema.
  700. Arguments:
  701. [in] Pointer to the metabase object.
  702. [in] Array that hold catalog schema information about the property.
  703. [in] Array that holds count of bytes for the above.
  704. [in] Storage pointer.
  705. Return Value:
  706. HRESULT
  707. --***************************************************************************/
  708. HRESULT ReadPropertyTypes(CMDBaseObject* i_pboRead,
  709. LPVOID* i_apv,
  710. ULONG* ,
  711. IIS_CRYPTO_STORAGE* i_pStorage)
  712. {
  713. HRESULT hr = S_OK;
  714. LPVOID a_pv[cMBProperty_NumberOfColumns];
  715. ULONG a_Size[cMBProperty_NumberOfColumns];
  716. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  717. DWORD dwType = BINARY_METADATA;
  718. DWORD dwUserType = IIS_MD_UT_SERVER;
  719. PropValue propVal;
  720. DWORD dwMetaFlagsEx = *(DWORD*)(i_apv[iCOLUMNMETA_SchemaGeneratorFlags]);
  721. memset(&propVal, 0, sizeof(PropValue));
  722. //
  723. // Read all the property type. If the property is a flag, then read
  724. // all the type for the flag names as well.
  725. //
  726. propVal.dwMetaID = *(DWORD*)(i_apv[iCOLUMNMETA_ID]);
  727. propVal.dwPropID = *(DWORD*)(i_apv[iCOLUMNMETA_ID]); // Note: This is different from the meta id if it is a flag.
  728. propVal.dwSynID = SynIDFromMetaFlagsEx(dwMetaFlagsEx);
  729. propVal.dwMetaType = GetMetabaseType(*(DWORD*)(i_apv[iCOLUMNMETA_Type]),
  730. *(DWORD*)(i_apv[iCOLUMNMETA_MetaFlags]));
  731. if(DWORD_METADATA == propVal.dwMetaType)
  732. {
  733. propVal.dwMinRange = *(DWORD*)(i_apv[iCOLUMNMETA_StartingNumber]);
  734. propVal.dwMaxRange = *(DWORD*)(i_apv[iCOLUMNMETA_EndingNumber]);
  735. }
  736. else
  737. {
  738. //
  739. // Ensure that non-DWORDs have no starting/ending numbers
  740. //
  741. propVal.dwMinRange = 0;
  742. propVal.dwMaxRange = 0;
  743. }
  744. propVal.dwFlags = GetMetabaseFlags(*(DWORD*)i_apv[iCOLUMNMETA_SchemaGeneratorFlags]);
  745. propVal.dwMask = 0; // This gets filled in for flag values only.
  746. propVal.dwMetaFlags = *(DWORD*)(i_apv[iCOLUMNMETA_Attributes]);
  747. propVal.dwUserGroup = *(DWORD*)(i_apv[iCOLUMNMETA_UserType]);
  748. propVal.fMultiValued = ((*(DWORD*)i_apv[iCOLUMNMETA_MetaFlags])&fCOLUMNMETA_MULTISTRING)?1:0; // Ensure that this gets set in the schema as multivalued
  749. propVal.dwDefault = 0;
  750. propVal.szDefault = NULL;
  751. a_pv[iMBProperty_Name] = i_apv[iCOLUMNMETA_InternalName];
  752. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashTypes;
  753. a_pv[iMBProperty_ID] = i_apv[iCOLUMNMETA_ID];
  754. a_pv[iMBProperty_Attributes] = &dwAttributes;
  755. a_pv[iMBProperty_UserType] = &dwUserType;
  756. a_pv[iMBProperty_Type] = &dwType;
  757. a_pv[iMBProperty_Value] = (LPVOID)&propVal;
  758. a_Size[iMBProperty_Value] = sizeof(PropValue);
  759. hr = ReadDataObject(i_pboRead,
  760. a_pv,
  761. a_Size,
  762. i_pStorage,
  763. TRUE);
  764. return hr;
  765. } // ReadPropertyTypes
  766. /***************************************************************************++
  767. Routine Description:
  768. Reads all flag properties into the schema.
  769. Arguments:
  770. [in] Storage pointer.
  771. [in] Pointer to the metabase object that holds the types tree.
  772. [in] Pointer to the metabase object that holds the names tree.
  773. [in] Pointer to the metabase object that holds the default value tree.
  774. [in] Column index of the parent flag property.
  775. [in] Meta Id of the parent flag property.
  776. [in] Flags of the parent flag property.
  777. [in] Attribute of the parent flag property.
  778. [in] Usertype of the parent flag property.
  779. [in] Multivalued attribute of the parent flag property.
  780. Return Value:
  781. HRESULT
  782. --***************************************************************************/
  783. HRESULT ReadAllFlags(IIS_CRYPTO_STORAGE* i_pStorage,
  784. CMDBaseObject* i_pboReadType,
  785. CMDBaseObject* i_pboReadName,
  786. CMDBaseObject* i_pboReadDefault,
  787. DWORD i_dwColumnIndex,
  788. DWORD i_dwMetaID,
  789. DWORD i_dwFlags,
  790. DWORD i_dwAttributes,
  791. DWORD i_dwUserType,
  792. DWORD i_dwMultivalued)
  793. {
  794. ULONG i = 0;
  795. ULONG iStartRow = 0;
  796. HRESULT hr = S_OK;
  797. LPVOID a_pvSearch[cTAGMETA_NumberOfColumns];
  798. ULONG aColSearch[] = {iTAGMETA_Table,
  799. iTAGMETA_ColumnIndex
  800. };
  801. ULONG cColSearch = sizeof(aColSearch)/sizeof(ULONG);
  802. LPWSTR wszTable = NULL;
  803. a_pvSearch[iTAGMETA_Table] = g_pGlobalISTHelper->m_wszTABLE_IIsConfigObject;
  804. a_pvSearch[iTAGMETA_ColumnIndex] = (LPVOID)&i_dwColumnIndex;
  805. hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndColumnIndex->GetRowIndexBySearch(iStartRow,
  806. cColSearch,
  807. aColSearch,
  808. NULL,
  809. a_pvSearch,
  810. &iStartRow);
  811. if(E_ST_NOMOREROWS == hr)
  812. {
  813. hr = S_OK;
  814. goto exit;
  815. }
  816. else if(FAILED(hr))
  817. {
  818. DBGINFOW((DBG_CONTEXT,
  819. L"[ReadAllFlags] Unable to read flags. GetRowIndexBySearch failed with hr = 0x%x.\n",
  820. hr));
  821. goto exit;
  822. }
  823. for(i=iStartRow;;i++)
  824. {
  825. LPVOID a_pv[cTAGMETA_NumberOfColumns];
  826. ULONG a_Size[cTAGMETA_NumberOfColumns];
  827. ULONG a_iCol[] = {iTAGMETA_Table,
  828. iTAGMETA_ColumnIndex,
  829. iTAGMETA_InternalName,
  830. iTAGMETA_Value,
  831. iTAGMETA_ID
  832. };
  833. ULONG cCol = sizeof(a_iCol)/sizeof(ULONG);
  834. hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndColumnIndex->GetColumnValues(i,
  835. cCol,
  836. a_iCol,
  837. a_Size,
  838. a_pv);
  839. if(E_ST_NOMOREROWS == hr)
  840. {
  841. hr = S_OK;
  842. break;
  843. }
  844. else if(FAILED(hr))
  845. {
  846. goto exit;
  847. }
  848. if(NULL == wszTable)
  849. {
  850. // Save the table name from the read cache so that you can do a pointer compare below.
  851. wszTable = (LPWSTR)a_pv[iTAGMETA_Table];
  852. }
  853. if((wszTable != a_pv[iTAGMETA_Table]) ||
  854. (i_dwColumnIndex != *(DWORD*)a_pv[iTAGMETA_ColumnIndex])
  855. )
  856. {
  857. //
  858. // Done with all tags of this column, in this table hence exit.
  859. //
  860. goto exit;
  861. }
  862. hr = ReadFlagTypes(i_pboReadType,
  863. i_pStorage,
  864. i_dwMetaID,
  865. i_dwFlags,
  866. i_dwAttributes,
  867. i_dwUserType,
  868. i_dwMultivalued,
  869. a_pv,
  870. a_Size);
  871. if(FAILED(hr))
  872. {
  873. goto exit;
  874. }
  875. hr = ReadFlagNames(i_pboReadName,
  876. a_pv,
  877. a_Size,
  878. i_pStorage);
  879. if(FAILED(hr))
  880. {
  881. goto exit;
  882. }
  883. hr = ReadFlagDefaults(i_pboReadDefault,
  884. a_pv,
  885. a_Size,
  886. i_pStorage);
  887. if(FAILED(hr))
  888. {
  889. goto exit;
  890. }
  891. }
  892. exit:
  893. return hr;
  894. } // ReadAllFlagTypes
  895. #define IIS_SYNTAX_ID_BOOL_BITMASK 7
  896. /***************************************************************************++
  897. Routine Description:
  898. Reads all flag type information into the schema.
  899. Arguments:
  900. [in] Pointer to the metabase object that holds the types tree.
  901. [in] Storage pointer.
  902. [in] Meta Id of the parent flag property.
  903. [in] Flags of the parent flag property.
  904. [in] Attribute of the parent flag property.
  905. [in] Usertype of the parent flag property.
  906. [in] Multivalued attribute of the parent flag property.
  907. [in] Array that hold catalog schema information about the flag.
  908. [in] Array that holds count of bytes for the above.
  909. Return Value:
  910. HRESULT
  911. --***************************************************************************/
  912. HRESULT ReadFlagTypes(CMDBaseObject* i_pboRead,
  913. IIS_CRYPTO_STORAGE* i_pStorage,
  914. DWORD i_dwMetaID,
  915. DWORD i_dwFlags,
  916. DWORD i_dwAttributes,
  917. DWORD i_dwUserType,
  918. DWORD i_dwMultivalued,
  919. LPVOID* i_apv,
  920. ULONG* )
  921. {
  922. HRESULT hr = S_OK;
  923. LPVOID a_pv[cMBProperty_NumberOfColumns];
  924. ULONG a_Size[cMBProperty_NumberOfColumns];
  925. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  926. DWORD dwType = BINARY_METADATA;
  927. DWORD dwUserType = IIS_MD_UT_SERVER;
  928. PropValue propVal;
  929. DWORD dwFlagSynID = IIS_SYNTAX_ID_BOOL_BITMASK;
  930. DWORD dwFlagType = DWORD_METADATA;
  931. memset(&propVal, 0, sizeof(PropValue));
  932. //
  933. // Read all the property type. If the property is a flag, then read
  934. // all the type for the flag names as well.
  935. //
  936. propVal.dwMetaID = i_dwMetaID;
  937. propVal.dwPropID = *(DWORD*)(i_apv[iTAGMETA_ID]); // This is different from the meta id if it is a flag.
  938. propVal.dwSynID = dwFlagSynID;
  939. propVal.dwMetaType = dwFlagType;
  940. propVal.dwMaxRange = 0;
  941. propVal.dwMinRange = 0;
  942. propVal.dwFlags = i_dwFlags; // Set to parent prop flags
  943. propVal.dwMask = *(DWORD*)(i_apv[iTAGMETA_Value]); // Set to parent prop flags
  944. propVal.dwMetaFlags = i_dwAttributes; // Set to parent prop flags
  945. propVal.dwUserGroup = i_dwUserType; // Set to parent prop flags
  946. propVal.fMultiValued = i_dwMultivalued; // Set to parent prop flags
  947. propVal.dwDefault = 0;
  948. propVal.szDefault = NULL;
  949. a_pv[iMBProperty_Name] = NULL;
  950. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashTypes;
  951. a_pv[iMBProperty_ID] = i_apv[iTAGMETA_ID];
  952. a_pv[iMBProperty_Attributes] = &dwAttributes;
  953. a_pv[iMBProperty_UserType] = &dwUserType;
  954. a_pv[iMBProperty_Type] = &dwType;
  955. a_pv[iMBProperty_Value] = (LPVOID)&propVal;
  956. a_Size[iMBProperty_Value] = sizeof(PropValue);
  957. hr = ReadDataObject(i_pboRead,
  958. a_pv,
  959. a_Size,
  960. i_pStorage,
  961. TRUE);
  962. return hr;
  963. } // ReadFlagTypes
  964. /***************************************************************************++
  965. Routine Description:
  966. Reads property defaults into the schema.
  967. Arguments:
  968. [in] Pointer to the metabase object that holds property defaults.
  969. [in] Array that hold catalog schema information about the property.
  970. [in] Array that holds count of bytes for the above.
  971. [in] Storage pointer.
  972. Return Value:
  973. HRESULT
  974. --***************************************************************************/
  975. HRESULT ReadPropertyDefaults(CMDBaseObject* i_pboRead,
  976. LPVOID* i_apv,
  977. ULONG* i_aSize,
  978. IIS_CRYPTO_STORAGE* i_pStorage)
  979. {
  980. HRESULT hr = S_OK;
  981. LPVOID a_pv[cMBProperty_NumberOfColumns];
  982. ULONG a_Size[cMBProperty_NumberOfColumns];
  983. DWORD dwType = GetMetabaseType(*(DWORD*)i_apv[iCOLUMNMETA_Type],
  984. *(DWORD*)i_apv[iCOLUMNMETA_MetaFlags]);
  985. LPVOID pvValue = NULL;
  986. ULONG cbSize = NULL;
  987. DWORD dwZero = 0;
  988. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  989. //
  990. // Read all the property names. If the property is a flag, then read
  991. // all the flag names as well.
  992. //
  993. a_pv[iMBProperty_Name] = i_apv[iCOLUMNMETA_InternalName];
  994. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashDefaults;
  995. a_pv[iMBProperty_ID] = i_apv[iCOLUMNMETA_ID];
  996. a_pv[iMBProperty_Attributes] = &dwAttributes; // NO_ATTRIBUTES since it will attempt to decrypt.
  997. a_pv[iMBProperty_UserType] = i_apv[iCOLUMNMETA_UserType];
  998. a_pv[iMBProperty_Type] = &dwType;
  999. if((dwType == DWORD_METADATA) && (NULL == i_apv[iCOLUMNMETA_DefaultValue]))
  1000. {
  1001. pvValue = &dwZero;
  1002. cbSize = sizeof(DWORD);
  1003. }
  1004. else if(((dwType == MULTISZ_METADATA) || (dwType == STRING_METADATA) || (dwType == EXPANDSZ_METADATA)) &&
  1005. ((NULL == i_apv[iCOLUMNMETA_DefaultValue]) || (0 == *(BYTE*)(i_apv[iCOLUMNMETA_DefaultValue])))
  1006. )
  1007. {
  1008. if(dwType == MULTISZ_METADATA)
  1009. {
  1010. pvValue = g_wszEmptyMultisz; // Two nulls.
  1011. cbSize = g_cchEmptyMultisz * sizeof(WCHAR);
  1012. }
  1013. else if((dwType == STRING_METADATA) || (dwType == EXPANDSZ_METADATA))
  1014. {
  1015. pvValue = g_wszEmptyWsz;
  1016. cbSize = g_cchEmptyWsz * sizeof(WCHAR); // One null.
  1017. }
  1018. }
  1019. else
  1020. {
  1021. pvValue = i_apv[iCOLUMNMETA_DefaultValue];
  1022. cbSize = i_aSize[iCOLUMNMETA_DefaultValue];
  1023. }
  1024. a_pv[iMBProperty_Value] = pvValue;
  1025. a_Size[iMBProperty_Value] = cbSize;
  1026. hr = ReadDataObject(i_pboRead,
  1027. a_pv,
  1028. a_Size,
  1029. i_pStorage,
  1030. TRUE);
  1031. if(FAILED(hr))
  1032. {
  1033. DBGINFOW((DBG_CONTEXT,
  1034. L"[ReadPropertyDefaults] Could not read property %s:%d.\npv=%d.\ncb=%d.\n",
  1035. i_apv[iCOLUMNMETA_InternalName],
  1036. *(DWORD*)i_apv[iCOLUMNMETA_ID],
  1037. pvValue,
  1038. cbSize));
  1039. if(NULL != pvValue)
  1040. {
  1041. DBGINFOW((DBG_CONTEXT,
  1042. L"[ReadPropertyDefaults]*pv=%d.\n",
  1043. *(WORD*)pvValue));
  1044. }
  1045. }
  1046. return hr;
  1047. } // ReadPropertyDefaults
  1048. /***************************************************************************++
  1049. Routine Description:
  1050. Reads all flag defaults into the schema.
  1051. Arguments:
  1052. [in] Pointer to the metabase object that holds the defaults.
  1053. [in] Array that hold catalog schema information about the flag.
  1054. [in] Array that holds count of bytes for the above.
  1055. [in] Storage pointer.
  1056. Return Value:
  1057. HRESULT
  1058. --***************************************************************************/
  1059. HRESULT ReadFlagDefaults(CMDBaseObject* i_pboRead,
  1060. LPVOID* i_apv,
  1061. ULONG* ,
  1062. IIS_CRYPTO_STORAGE* i_pStorage)
  1063. {
  1064. HRESULT hr = S_OK;
  1065. LPVOID a_pv[cMBProperty_NumberOfColumns];
  1066. ULONG a_Size[cMBProperty_NumberOfColumns];
  1067. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  1068. DWORD dwType = DWORD_METADATA;
  1069. DWORD dwUserType = IIS_MD_UT_SERVER;
  1070. //
  1071. // TODO: Is this a correct assumption? I noticed that default values for
  1072. // flags was being set to 0 or -1. This doesnt make any sense. How can a
  1073. // flag have a default value other than its own value? This is not
  1074. //captured in our new schema, so just putting it as 0.
  1075. //
  1076. DWORD dwFlagDefaults = 0;
  1077. //
  1078. // Read all the property names. If the property is a flag, then read
  1079. // all the flag names as well.
  1080. //
  1081. a_pv[iMBProperty_Name] = i_apv[iTAGMETA_InternalName];
  1082. a_pv[iMBProperty_Location] = (LPWSTR)g_wszSlashSchemaSlashPropertiesSlashDefaults;
  1083. a_pv[iMBProperty_ID] = i_apv[iTAGMETA_ID];
  1084. a_pv[iMBProperty_Attributes] = &dwAttributes;
  1085. a_pv[iMBProperty_UserType] = &dwUserType;
  1086. a_pv[iMBProperty_Type] = &dwType;
  1087. a_pv[iMBProperty_Value] = &dwFlagDefaults;
  1088. a_Size[iMBProperty_Value] = sizeof(DWORD);
  1089. hr = ReadDataObject(i_pboRead,
  1090. a_pv,
  1091. a_Size,
  1092. i_pStorage,
  1093. TRUE);
  1094. return hr;
  1095. } // ReadFlagDefaults
  1096. /***************************************************************************++
  1097. Routine Description:
  1098. Reads all classes into the schema.
  1099. Arguments:
  1100. [in] Storage pointer.
  1101. [in] Filetime pointer.
  1102. Return Value:
  1103. HRESULT
  1104. --***************************************************************************/
  1105. HRESULT ReadClasses(IIS_CRYPTO_STORAGE* i_pStorage,
  1106. FILETIME* i_pFileTime)
  1107. {
  1108. HRESULT hr = S_OK;
  1109. CMDBaseObject* pboReadClasses = NULL;
  1110. ULONG i = 0;
  1111. LPVOID a_pv[cTABLEMETA_NumberOfColumns];
  1112. ULONG a_Size[cTABLEMETA_NumberOfColumns];
  1113. ULONG a_iCol[] = {iTABLEMETA_InternalName,
  1114. iTABLEMETA_MetaFlags,
  1115. iTABLEMETA_SchemaGeneratorFlags,
  1116. iTABLEMETA_ContainerClassList
  1117. };
  1118. ULONG cCol = sizeof(a_iCol)/sizeof(ULONG);
  1119. hr = ReadMetaObject(pboReadClasses,
  1120. (LPWSTR)g_wszSlashSchemaSlashClasses,
  1121. i_pFileTime,
  1122. TRUE);
  1123. if(FAILED(hr))
  1124. {
  1125. goto exit;
  1126. }
  1127. for(i=0;;i++)
  1128. {
  1129. hr = g_pGlobalISTHelper->m_pISTTableMetaForMetabaseTables->GetColumnValues(i,
  1130. cCol,
  1131. a_iCol,
  1132. a_Size,
  1133. a_pv);
  1134. if(E_ST_NOMOREROWS == hr)
  1135. {
  1136. hr = S_OK;
  1137. break;
  1138. }
  1139. else if(FAILED(hr))
  1140. {
  1141. goto exit;
  1142. }
  1143. MD_ASSERT(NULL != (DWORD*)a_pv[iTABLEMETA_MetaFlags]);
  1144. if(fTABLEMETA_HIDDEN == (fTABLEMETA_HIDDEN & (*(DWORD*)a_pv[iTABLEMETA_MetaFlags])))
  1145. {
  1146. //
  1147. // Do not read hidden classes. All these classes have the "HIDDEN" MetaFlag set on them.
  1148. // Eg: IIsConfigObject,MetabaseBaseClass, MBProperty, MBPropertyDiff, IIsInheritedProperties
  1149. //
  1150. continue;
  1151. }
  1152. hr = ReadClass(a_pv,
  1153. a_Size,
  1154. i_pStorage,
  1155. i_pFileTime);
  1156. if(FAILED(hr))
  1157. {
  1158. DBGINFOW((DBG_CONTEXT,
  1159. L"[ReadClasses] Could not read information for class: %s.\nReadClass failed with hr=0x%x.\n",
  1160. a_pv[iTABLEMETA_InternalName],
  1161. hr));
  1162. }
  1163. }
  1164. exit:
  1165. return hr;
  1166. } // ReadClasses
  1167. /***************************************************************************++
  1168. Routine Description:
  1169. Reads a class into the schema.
  1170. Arguments:
  1171. [in] Array that hold catalog schema information about the class.
  1172. [in] Array that holds count of bytes for the above.
  1173. [in] Storage pointer.
  1174. [in] Filetime pointer.
  1175. Return Value:
  1176. HRESULT
  1177. --***************************************************************************/
  1178. HRESULT ReadClass(LPVOID* i_apv,
  1179. ULONG* ,
  1180. IIS_CRYPTO_STORAGE* i_pStorage,
  1181. FILETIME* i_pFileTime)
  1182. {
  1183. HRESULT hr = S_OK;
  1184. CMDBaseObject* pboReadClass = NULL;
  1185. WCHAR wszClassPathFixed[MAX_PATH];
  1186. ULONG cchClassPath = 0;
  1187. WCHAR* wszClassPath = wszClassPathFixed;
  1188. WCHAR* wszEnd = NULL;
  1189. ULONG cchClassName = (ULONG)wcslen((LPWSTR)i_apv[iTABLEMETA_InternalName]);
  1190. DWORD dwID = 0;
  1191. DWORD dwType = DWORD_METADATA;
  1192. DWORD dwUserType = IIS_MD_UT_SERVER;
  1193. DWORD dwAttributes = METADATA_NO_ATTRIBUTES;
  1194. DWORD dwValue = 0;
  1195. LPVOID a_pv[cMBProperty_NumberOfColumns];
  1196. ULONG a_Size[cMBProperty_NumberOfColumns];
  1197. LPWSTR wszManditory = NULL;
  1198. LPWSTR wszOptional = NULL;
  1199. //
  1200. // Construct the ClassPath and read the meta object.
  1201. //
  1202. cchClassPath = g_cchSlashSchemaSlashClasses +
  1203. g_cchSlash +
  1204. cchClassName;
  1205. if((cchClassPath + 1) > MAX_PATH)
  1206. {
  1207. wszClassPath = new WCHAR[cchClassPath + 1];
  1208. if(NULL == wszClassPath)
  1209. {
  1210. hr = E_OUTOFMEMORY;
  1211. goto exit;
  1212. }
  1213. }
  1214. wszEnd = wszClassPath;
  1215. memcpy(wszEnd, g_wszSlashSchemaSlashClasses, g_cchSlashSchemaSlashClasses*sizeof(WCHAR));
  1216. wszEnd = wszEnd + g_cchSlashSchemaSlashClasses;
  1217. memcpy(wszEnd, g_wszSlash, g_cchSlash*sizeof(WCHAR));
  1218. wszEnd = wszEnd + g_cchSlash;
  1219. memcpy(wszEnd, i_apv[iTABLEMETA_InternalName], cchClassName*sizeof(WCHAR));
  1220. wszEnd = wszEnd + cchClassName;
  1221. *wszEnd = L'\0';
  1222. hr = ReadMetaObject(pboReadClass,
  1223. wszClassPath,
  1224. i_pFileTime,
  1225. TRUE);
  1226. if(FAILED(hr))
  1227. {
  1228. DBGINFOW((DBG_CONTEXT,
  1229. L"[ReadClasses] ReadMetaObject for class: %s failed with hr=0x%x.\n",
  1230. wszClassPath,
  1231. hr));
  1232. goto exit;
  1233. }
  1234. //
  1235. // Initialize a_pv to write data objects
  1236. //
  1237. a_pv[iMBProperty_Name] = NULL;
  1238. a_pv[iMBProperty_ID] = &dwID;
  1239. a_pv[iMBProperty_Location] = wszClassPath;
  1240. a_pv[iMBProperty_Attributes] = &dwAttributes;
  1241. a_pv[iMBProperty_UserType] = &dwUserType;
  1242. a_pv[iMBProperty_Type] = &dwType;
  1243. //
  1244. // Read the data object that corresponds to container class property
  1245. //
  1246. dwID = MD_SCHEMA_CLASS_CONTAINER;
  1247. dwType = DWORD_METADATA;
  1248. dwValue = ((*(DWORD*)(i_apv[iTABLEMETA_SchemaGeneratorFlags])) & fTABLEMETA_CONTAINERCLASS)?1:0; // Need to set true or false.
  1249. a_pv[iMBProperty_Value] = &dwValue;
  1250. a_Size[iMBProperty_Value] = sizeof(DWORD);
  1251. hr = ReadDataObject(pboReadClass,
  1252. a_pv,
  1253. a_Size,
  1254. i_pStorage,
  1255. TRUE);
  1256. if(FAILED(hr))
  1257. {
  1258. DBGINFOW((DBG_CONTEXT,
  1259. L"[ReadClasses] ReadDataObject for class: %s, property: Container failed with hr=0x%x.\n",
  1260. wszClassPath,
  1261. hr));
  1262. goto exit;
  1263. }
  1264. //
  1265. // Read the data object that corresponds to container class list property
  1266. //
  1267. dwID = MD_SCHEMA_CLASS_CONTAINMENT;
  1268. dwType = STRING_METADATA;
  1269. if(NULL == i_apv[iTABLEMETA_ContainerClassList])
  1270. {
  1271. a_pv[iMBProperty_Value] = g_wszEmptyWsz;
  1272. a_Size[iMBProperty_Value] = (g_cchEmptyWsz)*sizeof(WCHAR);
  1273. }
  1274. else
  1275. {
  1276. a_pv[iMBProperty_Value] = i_apv[iTABLEMETA_ContainerClassList];
  1277. a_Size[iMBProperty_Value] = (ULONG)(wcslen((LPWSTR)i_apv[iTABLEMETA_ContainerClassList])+1)*sizeof(WCHAR);
  1278. }
  1279. hr = ReadDataObject(pboReadClass,
  1280. a_pv,
  1281. a_Size,
  1282. i_pStorage,
  1283. TRUE);
  1284. if(FAILED(hr))
  1285. {
  1286. goto exit;
  1287. }
  1288. //
  1289. // Read properties for this class.
  1290. //
  1291. hr = GetProperties((LPCWSTR)i_apv[iTABLEMETA_InternalName],
  1292. &wszOptional,
  1293. &wszManditory);
  1294. if(FAILED(hr))
  1295. {
  1296. goto exit;
  1297. }
  1298. //
  1299. // Read data object that corresponds to optional property list
  1300. //
  1301. dwID = MD_SCHEMA_CLASS_OPT_PROPERTIES;
  1302. dwType = STRING_METADATA;
  1303. if(NULL == wszOptional)
  1304. {
  1305. a_pv[iMBProperty_Value] = g_wszEmptyWsz;
  1306. a_Size[iMBProperty_Value] = (g_cchEmptyWsz)*sizeof(WCHAR);
  1307. }
  1308. else
  1309. {
  1310. a_pv[iMBProperty_Value] = wszOptional;
  1311. a_Size[iMBProperty_Value] = (ULONG)(wcslen(wszOptional)+1)*sizeof(WCHAR);
  1312. }
  1313. // DBGINFOW((DBG_CONTEXT,
  1314. // L"[ReadClasses] Class: %s has Optional Properties: %s.\n",
  1315. // wszClassPath,
  1316. // a_pv[iMBProperty_Value]));
  1317. hr = ReadDataObject(pboReadClass,
  1318. a_pv,
  1319. a_Size,
  1320. i_pStorage,
  1321. TRUE);
  1322. if(FAILED(hr))
  1323. {
  1324. goto exit;
  1325. }
  1326. //
  1327. // Read data object that corresponds to maditory property list
  1328. //
  1329. dwID = MD_SCHEMA_CLASS_MAND_PROPERTIES;
  1330. dwType = STRING_METADATA;
  1331. if(NULL == wszManditory)
  1332. {
  1333. a_pv[iMBProperty_Value] = g_wszEmptyWsz;
  1334. a_Size[iMBProperty_Value] = (g_cchEmptyWsz)*sizeof(WCHAR);
  1335. }
  1336. else
  1337. {
  1338. a_pv[iMBProperty_Value] = wszManditory;
  1339. a_Size[iMBProperty_Value] = (ULONG)(wcslen(wszManditory)+1)*sizeof(WCHAR);
  1340. }
  1341. // DBGINFOW((DBG_CONTEXT,
  1342. // L"[ReadClasses] Class: %s has Manditory Properties: %s.\n",
  1343. // wszClassPath,
  1344. // a_pv[iMBProperty_Value]));
  1345. hr = ReadDataObject(pboReadClass,
  1346. a_pv,
  1347. a_Size,
  1348. i_pStorage,
  1349. TRUE);
  1350. if(FAILED(hr))
  1351. {
  1352. goto exit;
  1353. }
  1354. exit:
  1355. if(wszClassPathFixed != wszClassPath)
  1356. {
  1357. delete [] wszClassPath;
  1358. wszClassPath = NULL;
  1359. }
  1360. if(NULL != wszManditory)
  1361. {
  1362. delete [] wszManditory;
  1363. wszManditory = NULL;
  1364. }
  1365. if(NULL != wszOptional)
  1366. {
  1367. delete [] wszOptional;
  1368. wszOptional = NULL;
  1369. }
  1370. return hr;
  1371. } // ReadClasses
  1372. /***************************************************************************++
  1373. Routine Description:
  1374. Given a class it constructs the optional and manditory property lists
  1375. Arguments:
  1376. [in] Class name.
  1377. [out] Optional properties.
  1378. [out] Manditory properties.
  1379. Return Value:
  1380. HRESULT
  1381. --***************************************************************************/
  1382. HRESULT GetProperties(LPCWSTR i_wszTable,
  1383. LPWSTR* o_pwszOptional,
  1384. LPWSTR* o_pwszManditory)
  1385. {
  1386. HRESULT hr = S_OK;
  1387. LPVOID a_pv[cCOLUMNMETA_NumberOfColumns];
  1388. ULONG a_iCol[] = { iCOLUMNMETA_Table,
  1389. iCOLUMNMETA_InternalName,
  1390. iCOLUMNMETA_Index,
  1391. iCOLUMNMETA_MetaFlags,
  1392. iCOLUMNMETA_SchemaGeneratorFlags,
  1393. iCOLUMNMETA_ID
  1394. };
  1395. ULONG cCol = sizeof(a_iCol)/sizeof(ULONG);
  1396. WCHAR* wszEndOpt = NULL;
  1397. WCHAR* wszEndMand = NULL;
  1398. ULONG cchOptional = 0;
  1399. ULONG cchManditory = 0;
  1400. ULONG iColIndex = 0;
  1401. LPVOID a_Identity[] = {(LPVOID)i_wszTable,
  1402. (LPVOID)&iColIndex
  1403. };
  1404. LPWSTR wszTable = NULL;
  1405. ULONG iStartRow = 0;
  1406. ULONG i = 0;
  1407. MD_ASSERT(NULL != o_pwszOptional);
  1408. MD_ASSERT(NULL != o_pwszManditory);
  1409. *o_pwszOptional = NULL;
  1410. *o_pwszManditory = NULL;
  1411. //
  1412. // Get the row index of the first column and then iterate thru the table until
  1413. // e_st_nomorerows or the table difffers
  1414. //
  1415. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetRowIndexByIdentity(NULL,
  1416. a_Identity,
  1417. &iStartRow);
  1418. if(FAILED(hr))
  1419. {
  1420. if(E_ST_NOMOREROWS == hr)
  1421. {
  1422. hr = S_OK;
  1423. }
  1424. goto exit;
  1425. }
  1426. //
  1427. // Count the optional and maditory property lengths.
  1428. //
  1429. for(i=iStartRow;;i++)
  1430. {
  1431. ULONG* pcCh = NULL;
  1432. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(i,
  1433. cCol,
  1434. a_iCol,
  1435. NULL,
  1436. a_pv);
  1437. if(E_ST_NOMOREROWS == hr)
  1438. {
  1439. hr = S_OK;
  1440. break;
  1441. }
  1442. else if(FAILED(hr))
  1443. {
  1444. DBGINFOW((DBG_CONTEXT,
  1445. L"[GetProperties] GetColumnValues (count) failed with hr = 0x%x. Index: %d\n",
  1446. hr, i));
  1447. goto exit;
  1448. }
  1449. if(NULL == wszTable)
  1450. {
  1451. // Save the table name from the read cache so that you can do a pointer compare below.
  1452. wszTable = (LPWSTR)a_pv[iCOLUMNMETA_Table];
  1453. }
  1454. if(wszTable != a_pv[iCOLUMNMETA_Table])
  1455. {
  1456. //
  1457. // reached another table break
  1458. //
  1459. break;
  1460. }
  1461. if(MD_LOCATION == *(DWORD*)a_pv[iCOLUMNMETA_ID])
  1462. {
  1463. //
  1464. // Do NOT read in the location property.
  1465. //
  1466. continue;
  1467. }
  1468. MD_ASSERT(NULL != (DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]);
  1469. if(fCOLUMNMETA_HIDDEN == (fCOLUMNMETA_HIDDEN & (*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags])))
  1470. {
  1471. //
  1472. // Do not read hidden properties. All these properties have the
  1473. // "HIDDEN" schemagenerator flag set on them.
  1474. //
  1475. continue;
  1476. }
  1477. if((*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]) & fCOLUMNMETA_MANDATORY)
  1478. {
  1479. cchManditory = cchManditory + (ULONG)wcslen((LPWSTR)a_pv[iCOLUMNMETA_InternalName]) + 1 ; // For comma
  1480. pcCh = &cchManditory;
  1481. }
  1482. else
  1483. {
  1484. cchOptional = cchOptional + (ULONG)wcslen((LPWSTR)a_pv[iCOLUMNMETA_InternalName]) + 1; // For comma
  1485. pcCh = &cchOptional;
  1486. }
  1487. if((*(DWORD*)a_pv[iCOLUMNMETA_MetaFlags]) & fCOLUMNMETA_FLAG)
  1488. {
  1489. hr = AddFlagValuesToPropertyList((LPWSTR)i_wszTable,
  1490. *(DWORD*)a_pv[iCOLUMNMETA_Index],
  1491. pcCh,
  1492. NULL);
  1493. if(FAILED(hr))
  1494. {
  1495. DBGINFOW((DBG_CONTEXT,
  1496. L"[GetProperties] AddFlagValuesToPropertyList for %s:%s failed with hr = 0x%x.\n",
  1497. i_wszTable,
  1498. a_pv[iCOLUMNMETA_InternalName],
  1499. hr
  1500. ));
  1501. goto exit;
  1502. }
  1503. }
  1504. }
  1505. if(cchManditory > 0)
  1506. {
  1507. *o_pwszManditory = new WCHAR[cchManditory+1];
  1508. if(NULL == *o_pwszManditory)
  1509. {
  1510. hr = E_OUTOFMEMORY;
  1511. goto exit;
  1512. }
  1513. **o_pwszManditory = 0;
  1514. wszEndMand = *o_pwszManditory;
  1515. }
  1516. if(cchOptional > 0)
  1517. {
  1518. *o_pwszOptional = new WCHAR[cchOptional+1];
  1519. if(NULL == *o_pwszOptional)
  1520. {
  1521. hr = E_OUTOFMEMORY;
  1522. goto exit;
  1523. }
  1524. **o_pwszOptional= 0;
  1525. wszEndOpt = *o_pwszOptional;
  1526. }
  1527. //
  1528. // Count the optional and maditory property lengths.
  1529. //
  1530. wszTable = NULL;
  1531. for(i=iStartRow; ;i++)
  1532. {
  1533. ULONG cchName = 0;
  1534. LPWSTR* pwszPropertyList = NULL;
  1535. hr = g_pGlobalISTHelper->m_pISTColumnMeta->GetColumnValues(i,
  1536. cCol,
  1537. a_iCol,
  1538. NULL,
  1539. a_pv);
  1540. if(E_ST_NOMOREROWS == hr)
  1541. {
  1542. hr = S_OK;
  1543. break;
  1544. }
  1545. else if(FAILED(hr))
  1546. {
  1547. DBGINFOW((DBG_CONTEXT,
  1548. L"[GetProperties] GetColumnValues (copy) failed with hr = 0x%x. Index: %d\n",
  1549. hr, i));
  1550. goto exit;
  1551. }
  1552. if(NULL == wszTable)
  1553. {
  1554. // Save the table name from the read cache so that you can do a pointer compare below.
  1555. wszTable = (LPWSTR)a_pv[iCOLUMNMETA_Table];
  1556. }
  1557. if(wszTable != a_pv[iCOLUMNMETA_Table])
  1558. {
  1559. //
  1560. // reached another table break
  1561. //
  1562. break;
  1563. }
  1564. if(MD_LOCATION == *(DWORD*)a_pv[iCOLUMNMETA_ID])
  1565. {
  1566. //
  1567. // Do NOT read in the location property.
  1568. //
  1569. continue;
  1570. }
  1571. MD_ASSERT(NULL != (DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]);
  1572. if(fCOLUMNMETA_HIDDEN == (fCOLUMNMETA_HIDDEN & (*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags])))
  1573. {
  1574. //
  1575. // Do not read hidden properties. All these properties have the
  1576. // "HIDDEN" schemagenerator flag set on them.
  1577. //
  1578. continue;
  1579. }
  1580. cchName = (ULONG)wcslen((LPWSTR)a_pv[iCOLUMNMETA_InternalName]);
  1581. if((*(DWORD*)a_pv[iCOLUMNMETA_SchemaGeneratorFlags]) & fCOLUMNMETA_MANDATORY)
  1582. {
  1583. MD_ASSERT(wszEndMand != NULL);
  1584. memcpy(wszEndMand, a_pv[iCOLUMNMETA_InternalName], cchName*sizeof(WCHAR));
  1585. wszEndMand = wszEndMand + cchName;
  1586. memcpy(wszEndMand, g_wszComma, g_cchComma*sizeof(WCHAR));
  1587. wszEndMand = wszEndMand + g_cchComma;
  1588. pwszPropertyList = &wszEndMand;
  1589. }
  1590. else
  1591. {
  1592. MD_ASSERT(wszEndOpt != NULL);
  1593. memcpy(wszEndOpt, a_pv[iCOLUMNMETA_InternalName], cchName*sizeof(WCHAR));
  1594. wszEndOpt = wszEndOpt + cchName;
  1595. memcpy(wszEndOpt, g_wszComma, g_cchComma*sizeof(WCHAR));
  1596. wszEndOpt = wszEndOpt + g_cchComma;
  1597. pwszPropertyList = &wszEndOpt;
  1598. }
  1599. if((*(DWORD*)a_pv[iCOLUMNMETA_MetaFlags]) & fCOLUMNMETA_FLAG)
  1600. {
  1601. hr = AddFlagValuesToPropertyList((LPWSTR)i_wszTable,
  1602. *(DWORD*)a_pv[iCOLUMNMETA_Index],
  1603. NULL,
  1604. pwszPropertyList);
  1605. if(FAILED(hr))
  1606. {
  1607. DBGINFOW((DBG_CONTEXT,
  1608. L"[GetProperties] AddFlagValuesToPropertyList for %s:%s failed with hr = 0x%x.\n",
  1609. i_wszTable,
  1610. a_pv[iCOLUMNMETA_InternalName],
  1611. hr
  1612. ));
  1613. goto exit;
  1614. }
  1615. }
  1616. }
  1617. if(cchManditory > 0)
  1618. {
  1619. wszEndMand--;
  1620. *wszEndMand = L'\0';
  1621. }
  1622. if(cchOptional > 0)
  1623. {
  1624. wszEndOpt--;
  1625. *wszEndOpt = L'\0';
  1626. }
  1627. exit:
  1628. return hr;
  1629. } // GetProperties
  1630. /***************************************************************************++
  1631. Routine Description:
  1632. Adds the flag values to the (optional or manditory) property lists
  1633. Arguments:
  1634. [in] Class name.
  1635. [in] index
  1636. [out] Count of chars.
  1637. [in out] Property list with all flag values added to it.
  1638. Return Value:
  1639. HRESULT
  1640. --***************************************************************************/
  1641. HRESULT AddFlagValuesToPropertyList(LPWSTR i_wszTable,
  1642. ULONG i_dwIndex,
  1643. ULONG* io_pcCh,
  1644. LPWSTR* io_pwszPropertyList)
  1645. {
  1646. ULONG a_iCol[] = { iTAGMETA_InternalName,
  1647. iTAGMETA_ColumnIndex,
  1648. iTAGMETA_Table
  1649. };
  1650. ULONG cCol = sizeof(a_iCol)/sizeof(ULONG);
  1651. LPVOID a_pv[cTAGMETA_NumberOfColumns];
  1652. ULONG aColSearchTag[] = {iTAGMETA_Table,
  1653. iTAGMETA_ColumnIndex
  1654. };
  1655. ULONG cColSearchTag = sizeof(aColSearchTag)/sizeof(ULONG);
  1656. ULONG iStartRow = 0;
  1657. LPWSTR wszEnd = NULL;
  1658. HRESULT hr = S_OK;
  1659. LPWSTR wszTable = NULL;
  1660. if(NULL != io_pwszPropertyList && NULL != *io_pwszPropertyList)
  1661. {
  1662. wszEnd = *io_pwszPropertyList;
  1663. }
  1664. a_pv[iTAGMETA_Table] = i_wszTable;
  1665. a_pv[iTAGMETA_ColumnIndex] = (LPVOID)&i_dwIndex;
  1666. hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndColumnIndex->GetRowIndexBySearch(iStartRow,
  1667. cColSearchTag,
  1668. aColSearchTag,
  1669. NULL,
  1670. a_pv,
  1671. (ULONG*)&iStartRow);
  1672. if(E_ST_NOMOREROWS == hr)
  1673. {
  1674. DBGINFOW((DBG_CONTEXT,
  1675. L"[AddFlagValuesToPropertyList] No flags found for %s:%d.\n",
  1676. i_wszTable,
  1677. i_dwIndex));
  1678. hr = S_OK;
  1679. goto exit;
  1680. }
  1681. else if(FAILED(hr))
  1682. {
  1683. DBGINFOW((DBG_CONTEXT,
  1684. L"[AddFlagValuesToPropertyList] GetRowIndexBySearch for %s failed with hr = 0x%x.\n",
  1685. wszTABLE_TAGMETA,
  1686. hr));
  1687. goto exit;
  1688. }
  1689. for(ULONG iRow=iStartRow;;iRow++)
  1690. {
  1691. ULONG cchName = 0;
  1692. hr = g_pGlobalISTHelper->m_pISTTagMetaByTableAndColumnIndex->GetColumnValues(iRow,
  1693. cCol,
  1694. a_iCol,
  1695. NULL,
  1696. a_pv);
  1697. if(E_ST_NOMOREROWS == hr)
  1698. {
  1699. hr = S_OK;
  1700. break;
  1701. }
  1702. else if(FAILED(hr))
  1703. {
  1704. DBGINFOW((DBG_CONTEXT,
  1705. L"[AddFlagValuesToPropertyList] GetColumnValues for %s index %i failed with hr = 0x%x.\n",
  1706. wszTABLE_TAGMETA,
  1707. iRow,
  1708. hr));
  1709. goto exit;
  1710. }
  1711. if(NULL == wszTable)
  1712. {
  1713. wszTable = (LPWSTR)a_pv[iTAGMETA_Table];
  1714. }
  1715. if((wszTable != (LPWSTR)a_pv[iTAGMETA_Table]) ||
  1716. (i_dwIndex != *(DWORD*)a_pv[iTAGMETA_ColumnIndex])
  1717. )
  1718. {
  1719. //
  1720. // Reached another table, done with the tags of this table
  1721. //
  1722. break;
  1723. }
  1724. cchName = (ULONG)wcslen((LPWSTR)a_pv[iTAGMETA_InternalName]);
  1725. if(NULL != io_pcCh)
  1726. {
  1727. *io_pcCh = *io_pcCh + cchName + 1; // for comma
  1728. }
  1729. if(NULL != wszEnd)
  1730. {
  1731. memcpy(wszEnd, a_pv[iTAGMETA_InternalName], cchName*sizeof(WCHAR));
  1732. wszEnd = wszEnd + cchName;
  1733. memcpy(wszEnd, g_wszComma, g_cchComma*sizeof(WCHAR));
  1734. wszEnd = wszEnd + g_cchComma;
  1735. }
  1736. }
  1737. if(NULL != io_pwszPropertyList)
  1738. {
  1739. *io_pwszPropertyList = wszEnd;
  1740. }
  1741. exit:
  1742. return hr;
  1743. } // AddFlagValuesToPropertyList