Source code of Windows XP (NT5)
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.

1737 lines
42 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MetaUtil object
  6. File: ChkMeta.cpp
  7. Owner: t-BrianM
  8. This file contains implementations of the CheckSchema and CheckKey
  9. methods of the main MetaUtil class.
  10. ===================================================================*/
  11. #include "stdafx.h"
  12. #include "MetaUtil.h"
  13. #include "MUtilObj.h"
  14. #include "ChkMeta.h"
  15. /*------------------------------------------------------------------
  16. * C M e t a U t i l (check portion)
  17. */
  18. /*===================================================================
  19. CMetaUtil::CheckSchema
  20. Check the schema of a given machine for errors.
  21. Directly Generates:
  22. MUTIL_CHK_NO_SCHEMA
  23. MUTIL_CHK_NO_PROPERTIES
  24. MUTIL_CHK_NO_PROP_NAMES
  25. MUTIL_CHK_NO_PROP_TYPES
  26. MUTIL_CHK_NO_CLASSES
  27. Parameters:
  28. bstrMachine [in] Base key of the machine to check
  29. ppIReturn [out, retval] interface for the output error collection
  30. Returns:
  31. E_OUTOFMEMORY if allocation fails.
  32. E_INVALIDARG ppIReturn == NULL
  33. S_OK on success
  34. ===================================================================*/
  35. STDMETHODIMP CMetaUtil::CheckSchema(BSTR bstrMachine,
  36. ICheckErrorCollection **ppIReturn)
  37. {
  38. TRACE0("MetaUtil: CMetaUtil::CheckSchema\n");
  39. ASSERT_NULL_OR_POINTER(ppIReturn, ICheckErrorCollection *);
  40. if ((ppIReturn == NULL)) {
  41. return ::ReportError(E_INVALIDARG);
  42. }
  43. USES_CONVERSION;
  44. HRESULT hr;
  45. TCHAR tszMachine[ADMINDATA_MAX_NAME_LEN];
  46. if (bstrMachine) {
  47. _tcscpy(tszMachine, OLE2T(bstrMachine));
  48. CannonizeKey(tszMachine);
  49. }
  50. else {
  51. tszMachine[0] = _T('\0');
  52. }
  53. // Create the CheckErrorCollection
  54. CComObject<CCheckErrorCollection> *pCErrorCol = NULL;
  55. ATLTRY(pCErrorCol = new CComObject<CCheckErrorCollection>);
  56. if (pCErrorCol == NULL) {
  57. return ::ReportError(E_OUTOFMEMORY);
  58. }
  59. // Open the Machine Key
  60. METADATA_HANDLE hMDMachine = NULL;
  61. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  62. L"",
  63. METADATA_PERMISSION_READ,
  64. MUTIL_OPEN_KEY_TIMEOUT,
  65. &hMDMachine);
  66. if (FAILED(hr)) {
  67. return ::ReportError(hr);
  68. }
  69. // Make sure "Schema" exists
  70. if (!KeyExists(hMDMachine, _T("Schema"))) {
  71. AddError(pCErrorCol,
  72. MUTIL_CHK_NO_SCHEMA,
  73. MUTIL_CHK_NO_SCHEMA_S,
  74. tszMachine,
  75. NULL,
  76. 0);
  77. goto LDone; // Can't do anything else
  78. }
  79. // Make sure "Schema/Properties" exists
  80. if (!KeyExists(hMDMachine, _T("Schema/Properties"))) {
  81. AddError(pCErrorCol,
  82. MUTIL_CHK_NO_PROPERTIES,
  83. MUTIL_CHK_NO_PROPERTIES_S,
  84. tszMachine,
  85. _T("Schema"),
  86. 0);
  87. goto LClasses; // Can't do anything else with properties
  88. }
  89. // Make sure "Schema/Properties/Names" exists
  90. if (!KeyExists(hMDMachine, _T("Schema/Properties/Names"))) {
  91. AddError(pCErrorCol,
  92. MUTIL_CHK_NO_PROP_NAMES,
  93. MUTIL_CHK_NO_PROP_NAMES_S,
  94. tszMachine,
  95. _T("Schema/Properties"),
  96. 0);
  97. goto LPropTypes; // Can't do anything else with names
  98. }
  99. // Check property names
  100. hr = CheckPropertyNames(pCErrorCol, hMDMachine, tszMachine);
  101. if (FAILED(hr)) {
  102. goto LError;
  103. }
  104. LPropTypes:
  105. // Make sure "Schema/Properties/Types" exists
  106. if (!KeyExists(hMDMachine, _T("Schema/Properties/Types"))) {
  107. AddError(pCErrorCol,
  108. MUTIL_CHK_NO_PROP_TYPES,
  109. MUTIL_CHK_NO_PROP_TYPES_S,
  110. tszMachine,
  111. _T("Schema/Properties"),
  112. 0);
  113. goto LClasses; // Can't do anything else with types
  114. }
  115. // Check property types
  116. hr = CheckPropertyTypes(pCErrorCol, hMDMachine, tszMachine);
  117. if (FAILED(hr)) {
  118. goto LError;
  119. }
  120. LClasses:
  121. // Make sure "Schema/Classes" exists
  122. if (!KeyExists(hMDMachine, _T("Schema/Classes"))) {
  123. AddError(pCErrorCol,
  124. MUTIL_CHK_NO_CLASSES,
  125. MUTIL_CHK_NO_CLASSES_S,
  126. tszMachine,
  127. _T("Schema"),
  128. 0);
  129. goto LDone; // Can't do anything else
  130. }
  131. // Check classes
  132. hr = CheckClasses(pCErrorCol, hMDMachine, tszMachine);
  133. if (FAILED(hr)) {
  134. goto LError;
  135. }
  136. LDone:
  137. // Close the Machine Key
  138. m_pIMeta->CloseKey(hMDMachine);
  139. // Set the interface to ICheckErrorCollection
  140. hr = pCErrorCol->QueryInterface(IID_ICheckErrorCollection, (void **) ppIReturn);
  141. if (FAILED(hr)) {
  142. return ::ReportError(hr);
  143. }
  144. ASSERT(*ppIReturn != NULL);
  145. return S_OK;
  146. LError:
  147. if (pCErrorCol != NULL) {
  148. delete pCErrorCol;
  149. }
  150. if (hMDMachine != NULL) {
  151. m_pIMeta->CloseKey(hMDMachine);
  152. }
  153. return hr;
  154. }
  155. /*===================================================================
  156. CMetaUtil::CheckPropertyNames
  157. Private function to check the "Schema/Properties/Names" key of a
  158. given machine.
  159. o Make sure that each name entry is of type STRING_METADATA
  160. o Make sure that each name is unique
  161. Directly Generates:
  162. MUTIL_CHK_PROP_NAME_BAD_TYPE
  163. MUTIL_CHK_PROP_NAME_NOT_UNIQUE
  164. MUTIL_CHK_PROP_NAME_NOT_CASE_UNIQUE
  165. Parameters:
  166. pCErrorCol Pointer to the error collection to put errors in
  167. hMDMachine Open metabase handle for the machine key
  168. tszMachine Name of the machine key
  169. Returns:
  170. E_OUTOFMEMORY if allocation fails.
  171. S_OK on success
  172. ===================================================================*/
  173. HRESULT CMetaUtil::CheckPropertyNames(CComObject<CCheckErrorCollection> *pCErrorCol,
  174. METADATA_HANDLE hMDMachine,
  175. LPTSTR tszMachine)
  176. {
  177. ASSERT_POINTER(pCErrorCol, CComObject<CCheckErrorCollection>);
  178. ASSERT_STRING(tszMachine);
  179. USES_CONVERSION;
  180. HRESULT hr;
  181. int iDataIndex;
  182. METADATA_RECORD mdr;
  183. DWORD dwReqDataLen;
  184. DWORD dwDataBufLen;
  185. BYTE *lpDataBuf = NULL;
  186. LPTSTR tszName;
  187. CNameTable CPropNameTable;
  188. //Setup the return buffer
  189. dwDataBufLen = 256;
  190. lpDataBuf = new BYTE[dwDataBufLen];
  191. if (lpDataBuf == NULL) {
  192. return E_OUTOFMEMORY;
  193. }
  194. // For Each Data Item
  195. iDataIndex = 0;
  196. mdr.dwMDIdentifier = 0;
  197. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  198. mdr.dwMDUserType = ALL_METADATA;
  199. mdr.dwMDDataType = ALL_METADATA;
  200. mdr.dwMDDataLen = dwDataBufLen;
  201. mdr.pbMDData = (PBYTE) lpDataBuf;
  202. mdr.dwMDDataTag = 0;
  203. hr = m_pIMeta->EnumData(hMDMachine,
  204. L"Schema/Properties/Names",
  205. &mdr,
  206. iDataIndex,
  207. &dwReqDataLen);
  208. while (SUCCEEDED(hr)) {
  209. // Datatype must be STRING_METADATA
  210. if (mdr.dwMDDataType != STRING_METADATA) {
  211. AddError(pCErrorCol,
  212. MUTIL_CHK_PROP_NAME_BAD_TYPE,
  213. MUTIL_CHK_PROP_NAME_BAD_TYPE_S,
  214. tszMachine,
  215. _T("Schema/Properties/Names"),
  216. mdr.dwMDIdentifier);
  217. }
  218. else { // mdr.dwMDDataType == STRING_METADATA
  219. // Check uniqueness of the name
  220. tszName = W2T(reinterpret_cast<LPWSTR> (lpDataBuf));
  221. if (CPropNameTable.IsCaseSenDup(tszName)) {
  222. // Not unique
  223. AddError(pCErrorCol,
  224. MUTIL_CHK_PROP_NAME_NOT_UNIQUE,
  225. MUTIL_CHK_PROP_NAME_NOT_UNIQUE_S,
  226. tszMachine,
  227. _T("Schema/Properties/Names"),
  228. mdr.dwMDIdentifier);
  229. }
  230. else if (CPropNameTable.IsCaseInsenDup(tszName)) {
  231. // Case sensitive unique
  232. AddError(pCErrorCol,
  233. MUTIL_CHK_PROP_NAME_NOT_CASE_UNIQUE,
  234. MUTIL_CHK_PROP_NAME_NOT_CASE_UNIQUE_S,
  235. tszMachine,
  236. _T("Schema/Properties/Names"),
  237. mdr.dwMDIdentifier);
  238. // Add it to pick up case sensitive collisions
  239. hr = CPropNameTable.Add(tszName);
  240. if (FAILED(hr)) {
  241. goto LError;
  242. }
  243. }
  244. else {
  245. // Unique
  246. hr = CPropNameTable.Add(tszName);
  247. if (FAILED(hr)) {
  248. goto LError;
  249. }
  250. }
  251. }
  252. // Next data item
  253. iDataIndex++;
  254. mdr.dwMDIdentifier = 0;
  255. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  256. mdr.dwMDUserType = ALL_METADATA;
  257. mdr.dwMDDataType = ALL_METADATA;
  258. mdr.dwMDDataLen = dwDataBufLen;
  259. mdr.pbMDData = (PBYTE) lpDataBuf;
  260. mdr.dwMDDataTag = 0;
  261. hr = m_pIMeta->EnumData(hMDMachine,
  262. L"Schema/Properties/Names",
  263. &mdr,
  264. iDataIndex,
  265. &dwReqDataLen);
  266. }
  267. // Make sure we ran out of items
  268. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  269. goto LError;
  270. }
  271. delete lpDataBuf;
  272. return S_OK;
  273. LError:
  274. if (lpDataBuf != NULL) {
  275. delete lpDataBuf;
  276. }
  277. return hr;
  278. }
  279. /*===================================================================
  280. CMetaUtil::CheckPropertyTypes
  281. Private function to check the "Schema/Properties/Types" key of a
  282. given machine.
  283. o Make sure that each type entry is of type BINARY_METADATA
  284. o Make sure that the type data is valid
  285. o mdrDataRec.dwMDDataLen == sizeof(PropValue)
  286. o PropValue.dwMetaID != 0
  287. o PropValue.dwMetaType != ALL_METADATA
  288. o PropValue.dwUserGroup != ALL_METADATA
  289. o (PropValue.dwMetaFlags & METADATA_PARTIAL_PATH) != METADATA_PARTIAL_PATH
  290. o (PropValue.dwMetaFlags & METADATA_ISINHERITED) != METADATA_ISINHERITED
  291. Directly Generates:
  292. MUTIL_CHK_PROP_TYPE_BAD_TYPE
  293. MUTIL_CHK_PROP_TYPE_BAD_DATA
  294. Parameters:
  295. pCErrorCol Pointer to the error collection to put errors in
  296. hMDMachine Open metabase handle for the machine key
  297. tszMachine Name of the machine key
  298. Returns:
  299. E_OUTOFMEMORY if allocation fails.
  300. S_OK on success
  301. ===================================================================*/
  302. HRESULT CMetaUtil::CheckPropertyTypes(CComObject<CCheckErrorCollection> *pCErrorCol,
  303. METADATA_HANDLE hMDMachine,
  304. LPTSTR tszMachine)
  305. {
  306. ASSERT_POINTER(pCErrorCol, CComObject<CCheckErrorCollection>);
  307. ASSERT_STRING(tszMachine);
  308. USES_CONVERSION;
  309. HRESULT hr;
  310. int iDataIndex;
  311. METADATA_RECORD mdr;
  312. DWORD dwReqDataLen;
  313. DWORD dwDataBufLen;
  314. UCHAR *lpDataBuf = NULL;
  315. PropValue *pPropType;
  316. //Setup the return buffer
  317. dwDataBufLen = 256;
  318. lpDataBuf = new UCHAR[dwDataBufLen];
  319. if (lpDataBuf == NULL) {
  320. return E_OUTOFMEMORY;
  321. }
  322. // For Each Data Item
  323. iDataIndex = 0;
  324. mdr.dwMDIdentifier = 0;
  325. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  326. mdr.dwMDUserType = ALL_METADATA;
  327. mdr.dwMDDataType = ALL_METADATA;
  328. mdr.dwMDDataLen = dwDataBufLen;
  329. mdr.pbMDData = (PBYTE) lpDataBuf;
  330. mdr.dwMDDataTag = 0;
  331. hr = m_pIMeta->EnumData(hMDMachine,
  332. L"Schema/Properties/Types",
  333. &mdr,
  334. iDataIndex,
  335. &dwReqDataLen);
  336. while (SUCCEEDED(hr)) {
  337. // Datatype must be BINARY_METADATA
  338. if (mdr.dwMDDataType != BINARY_METADATA) {
  339. AddError(pCErrorCol,
  340. MUTIL_CHK_PROP_TYPE_BAD_TYPE,
  341. MUTIL_CHK_PROP_TYPE_BAD_TYPE_S,
  342. tszMachine,
  343. _T("Schema/Properties/Types"),
  344. mdr.dwMDIdentifier);
  345. }
  346. else { // mdr.dwMDDataType == BINARY_METADATA
  347. // Validate the data
  348. pPropType = reinterpret_cast<PropValue *> (lpDataBuf);
  349. if ((mdr.dwMDDataLen != sizeof(PropValue)) ||
  350. (pPropType->dwMetaID == 0) ||
  351. (pPropType->dwMetaType == ALL_METADATA) ||
  352. (pPropType->dwUserGroup == ALL_METADATA) ||
  353. ((pPropType->dwMetaFlags & METADATA_PARTIAL_PATH) == METADATA_PARTIAL_PATH) ||
  354. ((pPropType->dwMetaFlags & METADATA_ISINHERITED) == METADATA_ISINHERITED)) {
  355. AddError(pCErrorCol,
  356. MUTIL_CHK_PROP_TYPE_BAD_DATA,
  357. MUTIL_CHK_PROP_TYPE_BAD_DATA_S,
  358. tszMachine,
  359. _T("Schema/Properties/Types"),
  360. mdr.dwMDIdentifier);
  361. }
  362. }
  363. // Next data item
  364. iDataIndex++;
  365. mdr.dwMDIdentifier = 0;
  366. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  367. mdr.dwMDUserType = ALL_METADATA;
  368. mdr.dwMDDataType = ALL_METADATA;
  369. mdr.dwMDDataLen = dwDataBufLen;
  370. mdr.pbMDData = (PBYTE) lpDataBuf;
  371. mdr.dwMDDataTag = 0;
  372. hr = m_pIMeta->EnumData(hMDMachine,
  373. L"Schema/Properties/Types",
  374. &mdr,
  375. iDataIndex,
  376. &dwReqDataLen);
  377. }
  378. // Make sure we ran out of items
  379. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  380. goto LError;
  381. }
  382. delete lpDataBuf;
  383. return S_OK;
  384. LError:
  385. if (lpDataBuf != NULL) {
  386. delete lpDataBuf;
  387. }
  388. return hr;
  389. }
  390. /*===================================================================
  391. CMetaUtil::CheckClasses
  392. Private method to check the "Schema/Classes" key of a given machine.
  393. o Make sure that each class name is unique
  394. o Make sure that each class has a MANDATORY subkey
  395. o Make sure that each class has a OPTIONAL subkey
  396. o Make sure that each default property value is valid
  397. Directly Generates:
  398. MUTIL_CHK_CLASS_NOT_CASE_UNIQUE
  399. MUTIL_CHK_CLASS_NO_MANDATORY
  400. MUTIL_CHK_CLASS_NO_OPTIONAL
  401. Parameters:
  402. pCErrorCol Pointer to the error collection to put errors in
  403. hMDMachine Open metabase handle for the machine key
  404. tszMachine Name of the machine key
  405. Returns:
  406. E_OUTOFMEMORY if allocation fails.
  407. S_OK on success
  408. ===================================================================*/
  409. HRESULT CMetaUtil::CheckClasses(CComObject<CCheckErrorCollection> *pCErrorCol,
  410. METADATA_HANDLE hMDMachine,
  411. LPTSTR tszMachine)
  412. {
  413. ASSERT_POINTER(pCErrorCol, CComObject<CCheckErrorCollection>);
  414. ASSERT_STRING(tszMachine);
  415. USES_CONVERSION;
  416. HRESULT hr;
  417. int iKeyIndex;
  418. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  419. LPTSTR tszSubKey;
  420. CNameTable CClassNameTable;
  421. // For each Class key
  422. iKeyIndex = 0;
  423. hr = m_pIMeta->EnumKeys(hMDMachine,
  424. L"Schema/Classes",
  425. wszSubKey,
  426. iKeyIndex);
  427. while (SUCCEEDED(hr)) {
  428. tszSubKey = W2T(wszSubKey);
  429. // Build the full key
  430. TCHAR tszFullKey[ADMINDATA_MAX_NAME_LEN];
  431. _tcscpy(tszFullKey, _T("/Schema/Classes/"));
  432. _tcscat(tszFullKey, tszSubKey);
  433. // Class name is unique
  434. if (CClassNameTable.IsCaseInsenDup(tszSubKey)) {
  435. // Case sensitive unique
  436. AddError(pCErrorCol,
  437. MUTIL_CHK_CLASS_NOT_CASE_UNIQUE,
  438. MUTIL_CHK_CLASS_NOT_CASE_UNIQUE_S,
  439. tszFullKey,
  440. NULL,
  441. 0);
  442. }
  443. else {
  444. // Unique
  445. hr = CClassNameTable.Add(tszSubKey);
  446. if (FAILED(hr)) {
  447. goto LError;
  448. }
  449. }
  450. // Open the class key
  451. METADATA_HANDLE hMDClass = NULL;
  452. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  453. T2W(tszFullKey),
  454. METADATA_PERMISSION_READ,
  455. MUTIL_OPEN_KEY_TIMEOUT,
  456. &hMDClass);
  457. if (FAILED(hr)) {
  458. return ::ReportError(hr);
  459. }
  460. // Mandatory key exists
  461. if (!KeyExists(hMDClass, _T("Mandatory"))) {
  462. AddError(pCErrorCol,
  463. MUTIL_CHK_CLASS_NO_MANDATORY,
  464. MUTIL_CHK_CLASS_NO_MANDATORY_S,
  465. tszFullKey,
  466. NULL,
  467. 0);
  468. }
  469. else {
  470. // Make sure default mandatory settings make sense
  471. CheckClassProperties(pCErrorCol,
  472. hMDClass,
  473. tszFullKey,
  474. _T("Mandatory"));
  475. }
  476. // Optional key exits
  477. if (!KeyExists(hMDClass, _T("Optional"))) {
  478. AddError(pCErrorCol,
  479. MUTIL_CHK_CLASS_NO_OPTIONAL,
  480. MUTIL_CHK_CLASS_NO_OPTIONAL_S,
  481. tszFullKey,
  482. NULL,
  483. 0);
  484. }
  485. else {
  486. // Make sure default optional settings make sense
  487. CheckClassProperties(pCErrorCol,
  488. hMDClass,
  489. tszFullKey,
  490. _T("Optional"));
  491. }
  492. // Close the class key
  493. m_pIMeta->CloseKey(hMDClass);
  494. // Next key
  495. iKeyIndex++;
  496. hr = m_pIMeta->EnumKeys(hMDMachine,
  497. L"Schema/Classes",
  498. wszSubKey,
  499. iKeyIndex);
  500. }
  501. // Make sure we ran out of items
  502. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  503. goto LError;
  504. }
  505. return S_OK;
  506. LError:
  507. return ::ReportError(hr);
  508. }
  509. /*===================================================================
  510. CMetaUtil::CheckClassProperties
  511. Private method to check the properties under
  512. "Schema/Classes/_Class_/Madatory" and "Schema/Classes/_Class_/Optional".
  513. o Make sure that the class property type is compatible with the
  514. type under "Schema/Properties/Types"
  515. o DataType must match
  516. o UserType must match
  517. o Attributes must be a superset of the type attributes
  518. Directly Generates:
  519. MUTIL_CHK_CLASS_PROP_BAD_TYPE
  520. Parameters:
  521. pCErrorCol Pointer to the error collection to put errors in
  522. hMDClassKey Open metabase handle for the "Schema/Classes/_Class_" key
  523. tszClassKey Full path of the "Schema/Classes/_Class_" key
  524. tszClassSubKey Name of the specific class sub-key ("Mandatory"
  525. or "Optional")
  526. Returns:
  527. E_OUTOFMEMORY if allocation fails.
  528. S_OK on success
  529. ===================================================================*/
  530. HRESULT CMetaUtil::CheckClassProperties(CComObject<CCheckErrorCollection> *pCErrorCol,
  531. METADATA_HANDLE hMDClassKey,
  532. LPTSTR tszClassKey,
  533. LPTSTR tszClassSubKey)
  534. {
  535. ASSERT_POINTER(pCErrorCol, CComObject<CCheckErrorCollection>);
  536. ASSERT_STRING(tszClassKey);
  537. ASSERT_STRING(tszClassSubKey);
  538. USES_CONVERSION;
  539. HRESULT hr;
  540. int iDataIndex;
  541. METADATA_RECORD mdr;
  542. DWORD dwReqDataLen;
  543. DWORD dwDataBufLen;
  544. BYTE *lpDataBuf = NULL;
  545. // Setup the return buffer
  546. dwDataBufLen = 1024;
  547. lpDataBuf = new BYTE[dwDataBufLen];
  548. if (lpDataBuf == NULL) {
  549. return ::ReportError(E_OUTOFMEMORY);
  550. }
  551. // For each property
  552. iDataIndex = 0;
  553. mdr.dwMDIdentifier = 0;
  554. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  555. mdr.dwMDUserType = ALL_METADATA;
  556. mdr.dwMDDataType = ALL_METADATA;
  557. mdr.dwMDDataLen = dwDataBufLen;
  558. mdr.pbMDData = (PBYTE) lpDataBuf;
  559. mdr.dwMDDataTag = 0;
  560. hr = m_pIMeta->EnumData(hMDClassKey,
  561. T2W(tszClassSubKey),
  562. &mdr,
  563. iDataIndex,
  564. &dwReqDataLen);
  565. while (SUCCEEDED(hr) || (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
  566. if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
  567. delete lpDataBuf;
  568. dwDataBufLen = dwReqDataLen;
  569. lpDataBuf = new BYTE[dwDataBufLen];
  570. if (lpDataBuf == NULL) {
  571. return ::ReportError(E_OUTOFMEMORY);
  572. }
  573. }
  574. else {
  575. // Get the property information
  576. CPropInfo *pCPropInfo;
  577. PropValue *pTypeInfo;
  578. // Get the property info from the Schema Table
  579. pCPropInfo = m_pCSchemaTable->GetPropInfo(tszClassKey, mdr.dwMDIdentifier);
  580. if ((pCPropInfo == NULL) ||
  581. (pCPropInfo->GetTypeInfo() == NULL)) {
  582. // Error: no property type information for class property
  583. AddError(pCErrorCol,
  584. MUTIL_CHK_CLASS_PROP_NO_TYPE,
  585. MUTIL_CHK_CLASS_PROP_NO_TYPE_S,
  586. tszClassKey,
  587. tszClassSubKey,
  588. mdr.dwMDIdentifier);
  589. }
  590. else {
  591. pTypeInfo = pCPropInfo->GetTypeInfo();
  592. // Validate the property defaults :
  593. // DataType must match
  594. // UserType must match
  595. // Attributes must be a superset of the type attributes
  596. if (mdr.dwMDDataType != pTypeInfo->dwMetaType) {
  597. AddError(pCErrorCol,
  598. MUTIL_CHK_CLASS_PROP_BAD_DATA_TYPE,
  599. MUTIL_CHK_CLASS_PROP_BAD_DATA_TYPE_S,
  600. tszClassKey,
  601. tszClassSubKey,
  602. mdr.dwMDIdentifier);
  603. }
  604. if (mdr.dwMDUserType != pTypeInfo->dwUserGroup) {
  605. AddError(pCErrorCol,
  606. MUTIL_CHK_CLASS_PROP_BAD_USER_TYPE,
  607. MUTIL_CHK_CLASS_PROP_BAD_USER_TYPE_S,
  608. tszClassKey,
  609. tszClassSubKey,
  610. mdr.dwMDIdentifier);
  611. }
  612. if ((mdr.dwMDAttributes & pTypeInfo->dwMetaFlags) != pTypeInfo->dwMetaFlags) {
  613. AddError(pCErrorCol,
  614. MUTIL_CHK_CLASS_PROP_BAD_ATTR,
  615. MUTIL_CHK_CLASS_PROP_BAD_ATTR_S,
  616. tszClassKey,
  617. tszClassSubKey,
  618. mdr.dwMDIdentifier);
  619. }
  620. }
  621. // Next property
  622. iDataIndex++;
  623. }
  624. mdr.dwMDIdentifier = 0;
  625. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  626. mdr.dwMDUserType = ALL_METADATA;
  627. mdr.dwMDDataType = ALL_METADATA;
  628. mdr.dwMDDataLen = dwDataBufLen;
  629. mdr.pbMDData = (PBYTE) lpDataBuf;
  630. mdr.dwMDDataTag = 0;
  631. hr = m_pIMeta->EnumData(hMDClassKey,
  632. T2W(tszClassSubKey),
  633. &mdr,
  634. iDataIndex,
  635. &dwReqDataLen);
  636. }
  637. // Make sure we ran out of items
  638. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  639. delete lpDataBuf;
  640. return ::ReportError(hr);
  641. }
  642. delete lpDataBuf;
  643. return S_OK;
  644. }
  645. /*===================================================================
  646. CMetaUtil::CheckKey
  647. Check a given key for errors.
  648. Directly Generates:
  649. MUTIL_CHK_DATA_TOO_BIG
  650. MUTIL_CHK_NO_NAME_ENTRY
  651. MUTIL_CHK_NO_TYPE_ENTRY
  652. MUTIL_CHK_BAD_TYPE
  653. MUTIL_CHK_CLSID_NOT_FOUND
  654. MUTIL_CHK_MTX_PACK_ID_NOT_FOUND
  655. MUTIL_CHK_KEY_TOO_BIG
  656. Parameters:
  657. bstrKey [in] Key to check
  658. ppIReturn [out, retval] interface for the output error collection
  659. Returns:
  660. E_OUTOFMEMORY if allocation fails.
  661. E_INVALIDARG if bstrKey == NULL or ppIReturn == NULL
  662. S_OK on success
  663. ===================================================================*/
  664. STDMETHODIMP CMetaUtil::CheckKey(BSTR bstrKey,
  665. ICheckErrorCollection **ppIReturn)
  666. {
  667. TRACE0("MetaUtil: CMetaUtil::CheckKey\n");
  668. ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
  669. ASSERT_NULL_OR_POINTER(ppIReturn, ICheckErrorCollection *);
  670. if ((bstrKey == NULL) || (ppIReturn == NULL)) {
  671. return ::ReportError(E_INVALIDARG);
  672. }
  673. USES_CONVERSION;
  674. HRESULT hr;
  675. TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
  676. METADATA_HANDLE hMDKey = NULL;
  677. BYTE *lpDataBuf = NULL;
  678. DWORD dwKeySize = 0;
  679. _tcscpy(tszKey, OLE2T(bstrKey));
  680. CannonizeKey(tszKey);
  681. // Create the CheckErrorCollection
  682. CComObject<CCheckErrorCollection> *pCErrorCol = NULL;
  683. ATLTRY(pCErrorCol = new CComObject<CCheckErrorCollection>);
  684. if (pCErrorCol == NULL) {
  685. return ::ReportError(E_OUTOFMEMORY);
  686. }
  687. // If it's in the schema or IISAdmin, don't check
  688. if (::KeyIsInSchema(tszKey) || ::KeyIsInIISAdmin(tszKey)) {
  689. goto LDone;
  690. }
  691. // Open the key
  692. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  693. T2W(tszKey),
  694. METADATA_PERMISSION_READ,
  695. MUTIL_OPEN_KEY_TIMEOUT,
  696. &hMDKey);
  697. if (FAILED(hr)) {
  698. return ::ReportError(hr);
  699. }
  700. // TODO: Hard coded checks for expected subkeys
  701. int iDataIndex;
  702. METADATA_RECORD mdrDataRec;
  703. DWORD dwReqDataLen;
  704. DWORD dwDataBufLen;
  705. //Setup the return buffer
  706. dwDataBufLen = 1024;
  707. lpDataBuf = new BYTE[dwDataBufLen];
  708. if (lpDataBuf == NULL) {
  709. return ::ReportError(E_OUTOFMEMORY);
  710. }
  711. // For each property
  712. iDataIndex = 0;
  713. mdrDataRec.dwMDIdentifier = 0;
  714. mdrDataRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  715. mdrDataRec.dwMDUserType = ALL_METADATA;
  716. mdrDataRec.dwMDDataType = ALL_METADATA;
  717. mdrDataRec.dwMDDataLen = dwDataBufLen;
  718. mdrDataRec.pbMDData = (PBYTE) lpDataBuf;
  719. mdrDataRec.dwMDDataTag = 0;
  720. hr = m_pIMeta->EnumData(hMDKey,
  721. NULL,
  722. &mdrDataRec,
  723. iDataIndex,
  724. &dwReqDataLen);
  725. while (SUCCEEDED(hr) || (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
  726. if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
  727. delete lpDataBuf;
  728. dwDataBufLen = dwReqDataLen;
  729. lpDataBuf = new BYTE[dwDataBufLen];
  730. if (lpDataBuf == NULL) {
  731. hr = E_OUTOFMEMORY;
  732. goto LError;
  733. }
  734. hr = S_OK; // Loop again
  735. }
  736. else {
  737. // Check property data size
  738. if (mdrDataRec.dwMDDataLen > m_dwMaxPropSize) {
  739. AddError(pCErrorCol,
  740. MUTIL_CHK_DATA_TOO_BIG,
  741. MUTIL_CHK_DATA_TOO_BIG_S,
  742. tszKey,
  743. NULL,
  744. mdrDataRec.dwMDIdentifier);
  745. }
  746. // Add to the key size
  747. dwKeySize += mdrDataRec.dwMDDataLen;
  748. CPropInfo *pCPropInfo;
  749. PropValue *pTypeInfo;
  750. pCPropInfo = m_pCSchemaTable->GetPropInfo(tszKey, mdrDataRec.dwMDIdentifier);
  751. // Property should have a name entry
  752. if ((pCPropInfo == NULL) || (pCPropInfo->GetName() == NULL)) {
  753. AddError(pCErrorCol,
  754. MUTIL_CHK_NO_NAME_ENTRY,
  755. MUTIL_CHK_NO_NAME_ENTRY_S,
  756. tszKey,
  757. NULL,
  758. mdrDataRec.dwMDIdentifier);
  759. }
  760. // Property should have a type entry
  761. if ((pCPropInfo == NULL) || (pCPropInfo->GetTypeInfo() == NULL)) {
  762. AddError(pCErrorCol,
  763. MUTIL_CHK_NO_TYPE_ENTRY,
  764. MUTIL_CHK_NO_TYPE_ENTRY_S,
  765. tszKey,
  766. NULL,
  767. mdrDataRec.dwMDIdentifier);
  768. }
  769. else {
  770. // Check property type
  771. // DataType must match
  772. // UserType must match
  773. // Attributes must be a superset of the type attributes
  774. pTypeInfo = pCPropInfo->GetTypeInfo();
  775. if (mdrDataRec.dwMDDataType != pTypeInfo->dwMetaType) {
  776. AddError(pCErrorCol,
  777. MUTIL_CHK_BAD_DATA_TYPE,
  778. MUTIL_CHK_BAD_DATA_TYPE_S,
  779. tszKey,
  780. NULL,
  781. mdrDataRec.dwMDIdentifier);
  782. }
  783. if (mdrDataRec.dwMDUserType != pTypeInfo->dwUserGroup) {
  784. AddError(pCErrorCol,
  785. MUTIL_CHK_BAD_USER_TYPE,
  786. MUTIL_CHK_BAD_USER_TYPE_S,
  787. tszKey,
  788. NULL,
  789. mdrDataRec.dwMDIdentifier);
  790. }
  791. if ((mdrDataRec.dwMDAttributes & pTypeInfo->dwMetaFlags) != pTypeInfo->dwMetaFlags) {
  792. AddError(pCErrorCol,
  793. MUTIL_CHK_BAD_ATTR,
  794. MUTIL_CHK_BAD_ATTR_S,
  795. tszKey,
  796. NULL,
  797. mdrDataRec.dwMDIdentifier);
  798. }
  799. }
  800. // Hard coded property checks (hard coded logic)
  801. if ((mdrDataRec.dwMDIdentifier == MD_APP_WAM_CLSID) ||
  802. (mdrDataRec.dwMDIdentifier == MD_LOG_PLUGIN_ORDER)) {
  803. // If property is a CLSID
  804. if (!CheckCLSID(W2T(reinterpret_cast<LPWSTR> (lpDataBuf)))) {
  805. AddError(pCErrorCol,
  806. MUTIL_CHK_CLSID_NOT_FOUND,
  807. MUTIL_CHK_CLSID_NOT_FOUND_S,
  808. tszKey,
  809. NULL,
  810. mdrDataRec.dwMDIdentifier);
  811. }
  812. }
  813. else if (mdrDataRec.dwMDIdentifier == MD_APP_PACKAGE_ID) {
  814. // Property is a Transaction Server package
  815. if (!CheckMTXPackage(W2T(reinterpret_cast<LPWSTR> (lpDataBuf)))) {
  816. AddError(pCErrorCol,
  817. MUTIL_CHK_MTX_PACK_ID_NOT_FOUND,
  818. MUTIL_CHK_MTX_PACK_ID_NOT_FOUND_S,
  819. tszKey,
  820. NULL,
  821. mdrDataRec.dwMDIdentifier);
  822. }
  823. }
  824. else if ((mdrDataRec.dwMDIdentifier == MD_VR_PATH) ||
  825. (mdrDataRec.dwMDIdentifier == MD_FILTER_IMAGE_PATH)) {
  826. // Property is a path
  827. BOOL fResult;
  828. hr = CheckIfFileExists(W2T(reinterpret_cast<LPWSTR> (lpDataBuf)), &fResult);
  829. if (SUCCEEDED(hr) && !fResult) {
  830. AddError(pCErrorCol,
  831. MUTIL_CHK_PATH_NOT_FOUND,
  832. MUTIL_CHK_PATH_NOT_FOUND_S,
  833. tszKey,
  834. NULL,
  835. mdrDataRec.dwMDIdentifier);
  836. }
  837. }
  838. // Next property
  839. iDataIndex++;
  840. }
  841. mdrDataRec.dwMDIdentifier = 0;
  842. mdrDataRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  843. mdrDataRec.dwMDUserType = ALL_METADATA;
  844. mdrDataRec.dwMDDataType = ALL_METADATA;
  845. mdrDataRec.dwMDDataLen = dwDataBufLen;
  846. mdrDataRec.pbMDData = (PBYTE) lpDataBuf;
  847. mdrDataRec.dwMDDataTag = 0;
  848. hr = m_pIMeta->EnumData(hMDKey,
  849. NULL,
  850. &mdrDataRec,
  851. iDataIndex,
  852. &dwReqDataLen);
  853. }
  854. // Make sure we ran out of items
  855. if (HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) {
  856. goto LError;
  857. }
  858. // Check total size of key
  859. if (dwKeySize > m_dwMaxKeySize) {
  860. AddError(pCErrorCol,
  861. MUTIL_CHK_KEY_TOO_BIG,
  862. MUTIL_CHK_KEY_TOO_BIG_S,
  863. tszKey,
  864. NULL,
  865. 0);
  866. }
  867. // Check the KeyType property against schema class information
  868. hr = CheckKeyType(pCErrorCol, hMDKey, tszKey);
  869. if (FAILED(hr)) {
  870. goto LError;
  871. }
  872. delete lpDataBuf;
  873. // Close the key
  874. m_pIMeta->CloseKey(hMDKey);
  875. LDone:
  876. // Set the interface to ICheckErrorCollection
  877. hr = pCErrorCol->QueryInterface(IID_ICheckErrorCollection, (void **) ppIReturn);
  878. if (FAILED(hr)) {
  879. return ::ReportError(hr);
  880. }
  881. ASSERT(*ppIReturn != NULL);
  882. return S_OK;
  883. LError:
  884. if (pCErrorCol != NULL) {
  885. delete pCErrorCol;
  886. }
  887. if (hMDKey != NULL) {
  888. m_pIMeta->CloseKey(hMDKey);
  889. }
  890. if (lpDataBuf != NULL) {
  891. delete lpDataBuf;
  892. }
  893. return hr;
  894. }
  895. /*===================================================================
  896. CMetaUtil::AddError
  897. Add an error to a given error collection. Uses the string table to
  898. get the error description.
  899. Parameters:
  900. pCErrorCol Pointer to the error collection to put errors in
  901. lId Identifing constant of the type of error
  902. lSeverity Severity of the error
  903. tszKey Base part of the key where the error occurred
  904. tszSubKey NULL or second part of the key where the error occured
  905. dwProperty Id of the property where the error occured or 0
  906. Returns:
  907. E_OUTOFMEMORY if allocation fails.
  908. E_INVALIDARG if bstrMachine == NULL or ppIReturn == NULL
  909. S_OK on success
  910. Notes:
  911. I split the key parameter into 2 parts, because of the nature of
  912. the metabase API's taking 2 part keys, often you are working
  913. with keys in 2 parts. This takes the responsibility for combining
  914. them from the caller, simplifying the caller and eliminating
  915. redundancy.
  916. ===================================================================*/
  917. void CMetaUtil::AddError(CComObject<CCheckErrorCollection> *pCErrorCol,
  918. long lId,
  919. long lSeverity,
  920. LPCTSTR tszKey,
  921. LPCTSTR tszSubKey,
  922. DWORD dwProperty)
  923. {
  924. ASSERT_POINTER(pCErrorCol, CComObject<CCheckErrorCollection>);
  925. ASSERT_STRING(tszKey);
  926. ASSERT_NULL_OR_STRING(tszSubKey);
  927. long lNumErrors;
  928. pCErrorCol->get_Count(&lNumErrors);
  929. if (((DWORD) lNumErrors) == m_dwMaxNumErrors) {
  930. lId = MUTIL_CHK_TOO_MANY_ERRORS;
  931. lSeverity = MUTIL_CHK_TOO_MANY_ERRORS_S;
  932. tszKey = _T("");
  933. tszSubKey = NULL;
  934. dwProperty = 0;
  935. }
  936. else if (((DWORD) lNumErrors) > m_dwMaxNumErrors) {
  937. // Too many errors, bail
  938. return;
  939. }
  940. // Get the description
  941. TCHAR tszDescription[1024];
  942. LoadString(_Module.GetResourceInstance(), IDS_CHK_BASE + lId, tszDescription, 1024);
  943. // Build the full key
  944. TCHAR tszFullKey[ADMINDATA_MAX_NAME_LEN];
  945. if (tszSubKey == NULL) {
  946. _tcscpy(tszFullKey, tszKey);
  947. }
  948. else {
  949. _tcscpy(tszFullKey, tszKey);
  950. _tcscat(tszFullKey, _T("/"));
  951. _tcscat(tszFullKey, tszSubKey);
  952. }
  953. // Report the error
  954. pCErrorCol->AddError(lId, lSeverity, tszDescription, tszFullKey, dwProperty);
  955. }
  956. /*===================================================================
  957. CMetaUtil::KeyExists
  958. Private function to see if a given key exists.
  959. Parameters:
  960. hMDKey Open metabase read handle
  961. tszSubKey Subkey to check relatetive to hMDKey
  962. Returns:
  963. TRUE if the key exists. A key is considered to exist if on
  964. an open call, it is opened or ERROR_PATH_BUSY or
  965. ERROR_ACCESS_DENIED is returned.
  966. FALSE otherwise
  967. ===================================================================*/
  968. BOOL CMetaUtil::KeyExists(METADATA_HANDLE hMDKey, LPTSTR tszSubKey)
  969. {
  970. ASSERT_NULL_OR_STRING(tszSubKey);
  971. //Attempt to open the key
  972. USES_CONVERSION;
  973. HRESULT hr;
  974. METADATA_HANDLE hMDSubKey;
  975. hr = m_pIMeta->OpenKey(hMDKey,
  976. T2W(tszSubKey),
  977. METADATA_PERMISSION_READ,
  978. MUTIL_OPEN_KEY_TIMEOUT,
  979. &hMDSubKey);
  980. if (FAILED(hr)) {
  981. // Why?
  982. if ((HRESULT_CODE(hr) == ERROR_PATH_BUSY) ||
  983. (HRESULT_CODE(hr) == ERROR_ACCESS_DENIED)) {
  984. // It exists, just can't get to it
  985. return TRUE;
  986. }
  987. else {
  988. // Assume that it doesn't exist
  989. return FALSE;
  990. }
  991. }
  992. else { // SUCCEEDED(hr)
  993. m_pIMeta->CloseKey(hMDSubKey);
  994. return TRUE;
  995. }
  996. }
  997. /*===================================================================
  998. CMetaUtil::PropertyExists
  999. Private function to see if a given property exists.
  1000. Parameters:
  1001. hMDKey Open metabase read handle
  1002. tszSubKey Subkey to check relatetive to hMDKey
  1003. dwId Id of the property to check
  1004. Returns:
  1005. TRUE if the property exists. A property is considered to exist if
  1006. on an GetData call, it is retrived or ERROR_INSUFFICENT_BUFFER
  1007. or ERROR_ACCESS_DENIED is returned.
  1008. FALSE otherwise
  1009. ===================================================================*/
  1010. BOOL CMetaUtil::PropertyExists(METADATA_HANDLE hMDKey,
  1011. LPTSTR tszSubKey,
  1012. DWORD dwId)
  1013. {
  1014. ASSERT_NULL_OR_STRING(tszSubKey);
  1015. USES_CONVERSION;
  1016. HRESULT hr;
  1017. LPWSTR wszSubKey;
  1018. METADATA_RECORD mdr;
  1019. BYTE *lpDataBuf = NULL;
  1020. DWORD dwDataBufLen;
  1021. DWORD dwReqDataLen;
  1022. if (tszSubKey == NULL) {
  1023. wszSubKey = NULL;
  1024. }
  1025. else {
  1026. wszSubKey = T2W(tszSubKey);
  1027. }
  1028. //Setup the return buffer
  1029. dwDataBufLen = 256;
  1030. lpDataBuf = new BYTE[dwDataBufLen];
  1031. if (lpDataBuf == NULL) {
  1032. return FALSE;
  1033. }
  1034. // See if there is a KeyType property MD_KEY_TYPE
  1035. mdr.dwMDIdentifier = dwId;
  1036. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  1037. mdr.dwMDUserType = ALL_METADATA;
  1038. mdr.dwMDDataType = ALL_METADATA;
  1039. mdr.dwMDDataLen = dwDataBufLen;
  1040. mdr.pbMDData = (PBYTE) lpDataBuf;
  1041. mdr.dwMDDataTag = 0;
  1042. hr = m_pIMeta->GetData(hMDKey, wszSubKey, &mdr, &dwReqDataLen);
  1043. delete lpDataBuf;
  1044. if (SUCCEEDED(hr) ||
  1045. (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) ||
  1046. (HRESULT_CODE(hr) == ERROR_ACCESS_DENIED)) {
  1047. return TRUE;
  1048. }
  1049. else {
  1050. return FALSE;
  1051. }
  1052. }
  1053. /*===================================================================
  1054. CMetaUtil::CheckCLSID
  1055. Private function to look up a CLSID in the local registry.
  1056. Parameters:
  1057. tszCLSID CLSID to check in string format.
  1058. Returns:
  1059. TRUE if the CLSID is in the local registry
  1060. FALSE otherwise
  1061. ===================================================================*/
  1062. BOOL CMetaUtil::CheckCLSID(LPCTSTR tszCLSID) {
  1063. ASSERT_STRING(tszCLSID);
  1064. HKEY hCLSIDsKey;
  1065. HKEY hCLSIDKey;
  1066. LONG lRet;
  1067. // Open HKEY_CLASSES_ROOT\CLSID
  1068. lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT,
  1069. _T("CLSID"),
  1070. 0,
  1071. KEY_READ,
  1072. &hCLSIDsKey);
  1073. if (lRet != ERROR_SUCCESS) {
  1074. return FALSE;
  1075. }
  1076. // Open the specific CLSID
  1077. lRet = RegOpenKeyEx(hCLSIDsKey,
  1078. tszCLSID,
  1079. 0,
  1080. KEY_READ,
  1081. &hCLSIDKey);
  1082. if (lRet != ERROR_SUCCESS) {
  1083. RegCloseKey(hCLSIDsKey);
  1084. return FALSE;
  1085. }
  1086. // Close the keys
  1087. RegCloseKey(hCLSIDsKey);
  1088. RegCloseKey(hCLSIDKey);
  1089. return TRUE;
  1090. }
  1091. /*===================================================================
  1092. CMetaUtil::CheckMTXPackage
  1093. Private function to look up a Microsoft Transaction Server package
  1094. identifier (GUID) in the local registry.
  1095. Parameters:
  1096. tszPackId MTX package identifier (GUID) in string format
  1097. Returns:
  1098. TRUE if the package id is in the local registry
  1099. FALSE otherwise
  1100. ===================================================================*/
  1101. BOOL CMetaUtil::CheckMTXPackage(LPCTSTR tszPackId) {
  1102. ASSERT_STRING(tszPackId);
  1103. HKEY hMTSPackKey;
  1104. HKEY hPackIdKey;
  1105. LONG lRet;
  1106. // Open HKEY_LOCAL_MACHINE\Software\Microsoft\Transaction Server\Packages
  1107. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1108. _T("Software\\Microsoft\\Transaction Server\\Packages"),
  1109. 0,
  1110. KEY_READ,
  1111. &hMTSPackKey);
  1112. if (lRet != ERROR_SUCCESS) {
  1113. return FALSE;
  1114. }
  1115. // Open the specific package id
  1116. lRet = RegOpenKeyEx(hMTSPackKey,
  1117. tszPackId,
  1118. 0,
  1119. KEY_READ,
  1120. &hPackIdKey);
  1121. if (lRet != ERROR_SUCCESS) {
  1122. RegCloseKey(hMTSPackKey);
  1123. return FALSE;
  1124. }
  1125. // Close the keys
  1126. RegCloseKey(hMTSPackKey);
  1127. RegCloseKey(hPackIdKey);
  1128. return TRUE;
  1129. }
  1130. /*===================================================================
  1131. CMetaUtil::CheckKeyType
  1132. Private method to check class information on a non-schema key via
  1133. the KeyType property.
  1134. Directly Generates:
  1135. MUTIL_CHK_NO_KEYTYPE
  1136. MUTIL_CHK_NO_KEYTYPE_NOT_FOUND
  1137. Parameters:
  1138. pCErrorCol Pointer to the error collection to put errors in
  1139. hMDKey Open metabase handle for the key to check
  1140. tszKey Full path of the key to check
  1141. Returns:
  1142. E_OUTOFMEMORY if allocation fails.
  1143. S_OK on success
  1144. ===================================================================*/
  1145. HRESULT CMetaUtil::CheckKeyType(CComObject<CCheckErrorCollection> *pCErrorCol,
  1146. METADATA_HANDLE hMDKey,
  1147. LPTSTR tszKey)
  1148. {
  1149. ASSERT_POINTER(pCErrorCol, CComObject<CCheckErrorCollection>);
  1150. ASSERT_STRING(tszKey);
  1151. USES_CONVERSION;
  1152. HRESULT hr;
  1153. METADATA_RECORD mdr;
  1154. BYTE *lpDataBuf = NULL;
  1155. DWORD dwDataBufLen;
  1156. DWORD dwReqDataLen;
  1157. //Setup the return buffer
  1158. dwDataBufLen = 256;
  1159. lpDataBuf = new BYTE[dwDataBufLen];
  1160. if (lpDataBuf == NULL) {
  1161. return ::ReportError(E_OUTOFMEMORY);
  1162. }
  1163. // See if there is a KeyType property MD_KEY_TYPE
  1164. mdr.dwMDIdentifier = MD_KEY_TYPE;
  1165. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  1166. mdr.dwMDUserType = ALL_METADATA;
  1167. mdr.dwMDDataType = ALL_METADATA;
  1168. mdr.dwMDDataLen = dwDataBufLen;
  1169. mdr.pbMDData = (PBYTE) lpDataBuf;
  1170. mdr.dwMDDataTag = 0;
  1171. hr = m_pIMeta->GetData(hMDKey, NULL, &mdr, &dwReqDataLen);
  1172. if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
  1173. // Try a bigger buffer
  1174. delete lpDataBuf;
  1175. dwDataBufLen = dwReqDataLen;
  1176. lpDataBuf = new BYTE[dwDataBufLen];
  1177. if (lpDataBuf == NULL) {
  1178. hr = E_OUTOFMEMORY;
  1179. goto LError;
  1180. }
  1181. mdr.dwMDIdentifier = MD_KEY_TYPE;
  1182. mdr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  1183. mdr.dwMDUserType = ALL_METADATA;
  1184. mdr.dwMDDataType = ALL_METADATA;
  1185. mdr.dwMDDataLen = dwDataBufLen;
  1186. mdr.pbMDData = (PBYTE) lpDataBuf;
  1187. mdr.dwMDDataTag = 0;
  1188. hr = m_pIMeta->GetData(hMDKey, NULL, &mdr, &dwReqDataLen);
  1189. }
  1190. if (hr == MD_ERROR_DATA_NOT_FOUND) {
  1191. // Error: KeyType property not found
  1192. AddError(pCErrorCol,
  1193. MUTIL_CHK_NO_KEYTYPE,
  1194. MUTIL_CHK_NO_KEYTYPE_S,
  1195. tszKey,
  1196. NULL,
  1197. 0);
  1198. goto LDone;
  1199. }
  1200. else if (FAILED(hr)) {
  1201. // Unexpected error
  1202. goto LError;
  1203. }
  1204. else {
  1205. // KeyType property exists, get class information
  1206. LPTSTR tszClassName;
  1207. CClassInfo *pCClassInfo;
  1208. tszClassName = W2T(reinterpret_cast<LPWSTR> (lpDataBuf));
  1209. pCClassInfo = m_pCSchemaTable->GetClassInfo(tszKey, tszClassName);
  1210. if (pCClassInfo == NULL) {
  1211. // Error: KeyType does not map to a class
  1212. AddError(pCErrorCol,
  1213. MUTIL_CHK_NO_KEYTYPE_NOT_FOUND,
  1214. MUTIL_CHK_NO_KEYTYPE_NOT_FOUND_S,
  1215. tszKey,
  1216. NULL,
  1217. MD_KEY_TYPE);
  1218. goto LDone;
  1219. }
  1220. else { // KeyType maps to a class name
  1221. // Check mandatory properties
  1222. CClassPropInfo *pCMandatoryList;
  1223. pCMandatoryList = m_pCSchemaTable->GetMandatoryClassPropList(tszKey, tszClassName);
  1224. while (pCMandatoryList != NULL) {
  1225. // Make sure the property exists
  1226. if (!PropertyExists(hMDKey, NULL, pCMandatoryList->GetId())) {
  1227. AddError(pCErrorCol,
  1228. MUTIL_CHK_MANDATORY_PROP_MISSING,
  1229. MUTIL_CHK_MANDATORY_PROP_MISSING_S,
  1230. tszKey,
  1231. NULL,
  1232. pCMandatoryList->GetId());
  1233. }
  1234. // Next mandatory list element
  1235. pCMandatoryList = pCMandatoryList->GetListNext();
  1236. }
  1237. }
  1238. }
  1239. LDone:
  1240. delete lpDataBuf;
  1241. return S_OK;
  1242. LError:
  1243. if (lpDataBuf != NULL) {
  1244. delete lpDataBuf;
  1245. }
  1246. return hr;
  1247. }
  1248. /*===================================================================
  1249. CMetaUtil::CheckIfFileExists
  1250. Private function to check if there is indeed a file or dir at the
  1251. path indicated.
  1252. Parameters:
  1253. tszFSPath The filesystem path to check.
  1254. pfExists Returns true if the file or dir at the path exists,
  1255. false if it does not. Indeterminate in error cases.
  1256. Returns:
  1257. S_OK on success.
  1258. other HRESULTs from subroutines otherwise.
  1259. ===================================================================*/
  1260. HRESULT CMetaUtil::CheckIfFileExists(LPCTSTR tszFSPath,
  1261. BOOL *pfExists)
  1262. {
  1263. ASSERT_STRING(tszFSPath);
  1264. DWORD dwResult;
  1265. DWORD dwLastError;
  1266. HRESULT hr = S_OK;
  1267. dwResult = GetFileAttributes(tszFSPath);
  1268. if (dwResult == 0xFFFFFFFF) {
  1269. dwLastError = GetLastError();
  1270. if ((dwLastError == ERROR_FILE_NOT_FOUND) || (dwLastError == ERROR_PATH_NOT_FOUND)) {
  1271. // The file or dir doesn't exist
  1272. *pfExists = FALSE;
  1273. } else {
  1274. // Some other error occurred (access denied, etc.)
  1275. hr = HRESULT_FROM_WIN32(dwLastError);
  1276. *pfExists = FALSE; // Callers shouldn't be looking at this
  1277. }
  1278. } else {
  1279. // The file or dir is there
  1280. *pfExists = TRUE;
  1281. }
  1282. return hr;
  1283. }
  1284. /*------------------------------------------------------------------
  1285. * C N a m e T a b l e E n t r y
  1286. */
  1287. /*===================================================================
  1288. CNameTableEntry::Init
  1289. Constructor
  1290. Parameters:
  1291. tszName Name to add to the table
  1292. Returns:
  1293. E_OUTOFMEMORY if allocation failed
  1294. S_OK on success
  1295. ===================================================================*/
  1296. HRESULT CNameTableEntry::Init(LPCTSTR tszName)
  1297. {
  1298. ASSERT_STRING(tszName);
  1299. m_tszName = new TCHAR[_tcslen(tszName) + 1];
  1300. if (m_tszName == NULL) {
  1301. return E_OUTOFMEMORY;
  1302. }
  1303. _tcscpy(m_tszName, tszName);
  1304. return S_OK;
  1305. }
  1306. /*------------------------------------------------------------------
  1307. * C N a m e T a b l e
  1308. */
  1309. /*===================================================================
  1310. CNameTable::CNameTable
  1311. Constructor
  1312. Parameters:
  1313. None
  1314. Returns:
  1315. Nothing
  1316. ===================================================================*/
  1317. CNameTable::CNameTable()
  1318. {
  1319. // Clear the hash table
  1320. memset(m_rgpNameTable, 0, NAME_TABLE_HASH_SIZE * sizeof(CNameTableEntry *));
  1321. }
  1322. /*===================================================================
  1323. CNameTable::~CNameTable
  1324. Destructor
  1325. Parameters:
  1326. None
  1327. Returns:
  1328. Nothing
  1329. ===================================================================*/
  1330. CNameTable::~CNameTable()
  1331. {
  1332. int iIndex;
  1333. CNameTableEntry *pCDelete;
  1334. // For each hash table entry
  1335. for (iIndex =0; iIndex < NAME_TABLE_HASH_SIZE; iIndex++) {
  1336. // While the entry is not empty
  1337. while (m_rgpNameTable[iIndex] != NULL) {
  1338. // Nuke the first table entry
  1339. ASSERT_POINTER(m_rgpNameTable[iIndex], CNameTableEntry);
  1340. pCDelete = m_rgpNameTable[iIndex];
  1341. m_rgpNameTable[iIndex] = pCDelete->m_pCHashNext;
  1342. delete pCDelete;
  1343. }
  1344. }
  1345. }
  1346. /*===================================================================
  1347. CNameTable::IsCaseSenDup
  1348. Checks for a name table entry with the same case sensitive name.
  1349. Parameters:
  1350. tszName Name to check for a duplicate entry
  1351. Returns:
  1352. TRUE if a duplicate entry is found
  1353. FALSE otherwise
  1354. ===================================================================*/
  1355. BOOL CNameTable::IsCaseSenDup(LPCTSTR tszName)
  1356. {
  1357. ASSERT_STRING(tszName);
  1358. int iPos;
  1359. CNameTableEntry *pCLoop;
  1360. iPos = Hash(tszName);
  1361. pCLoop = m_rgpNameTable[iPos];
  1362. while (pCLoop != NULL) {
  1363. ASSERT_POINTER(pCLoop, CNameTableEntry);
  1364. ASSERT_STRING(pCLoop->m_tszName);
  1365. if (_tcscmp(tszName, pCLoop->m_tszName) == 0) {
  1366. return TRUE;
  1367. }
  1368. pCLoop = pCLoop->m_pCHashNext;
  1369. }
  1370. return FALSE;
  1371. }
  1372. /*===================================================================
  1373. CNameTable::IsCaseInsenDup
  1374. Checks for a name table entry with the same case insensitive name.
  1375. Parameters:
  1376. tszName Name to check for a duplicate entry
  1377. Returns:
  1378. TRUE if a duplicate entry is found
  1379. FALSE otherwise
  1380. ===================================================================*/
  1381. BOOL CNameTable::IsCaseInsenDup(LPCTSTR tszName)
  1382. {
  1383. ASSERT_STRING(tszName);
  1384. int iPos;
  1385. CNameTableEntry *pCLoop;
  1386. iPos = Hash(tszName);
  1387. pCLoop = m_rgpNameTable[iPos];
  1388. while (pCLoop != NULL) {
  1389. ASSERT_POINTER(pCLoop, CNameTableEntry);
  1390. ASSERT_STRING(pCLoop->m_tszName);
  1391. if (_tcsicmp(tszName, pCLoop->m_tszName) == 0) {
  1392. return TRUE;
  1393. }
  1394. pCLoop = pCLoop->m_pCHashNext;
  1395. }
  1396. return FALSE;
  1397. }
  1398. /*===================================================================
  1399. CNameTable::Add
  1400. Adds an entry to the name table
  1401. Parameters:
  1402. tszName Name to add to table
  1403. Returns:
  1404. E_OUTOFMEMORY on allocation failure
  1405. S_OK on success
  1406. ===================================================================*/
  1407. HRESULT CNameTable::Add(LPCTSTR tszName)
  1408. {
  1409. ASSERT_STRING(tszName);
  1410. // Create an entry
  1411. HRESULT hr;
  1412. CNameTableEntry *pCNew;
  1413. pCNew = new CNameTableEntry;
  1414. if (pCNew == NULL) {
  1415. return E_OUTOFMEMORY;
  1416. }
  1417. hr = pCNew->Init(tszName);
  1418. if (FAILED(hr)){
  1419. delete pCNew;
  1420. return hr;
  1421. }
  1422. // Add it to the table
  1423. int iPos;
  1424. iPos = Hash(tszName);
  1425. pCNew->m_pCHashNext = m_rgpNameTable[iPos];
  1426. m_rgpNameTable[iPos] = pCNew;
  1427. return S_OK;
  1428. }
  1429. /*===================================================================
  1430. CNameTable::Hash
  1431. Private hash function for the name table. The hash is case
  1432. insensitive.
  1433. Parameters:
  1434. tszName Name to hash
  1435. Returns:
  1436. Hash value for the input name.
  1437. ===================================================================*/
  1438. int CNameTable::Hash(LPCTSTR tszName)
  1439. {
  1440. ASSERT_STRING(tszName);
  1441. unsigned int uiSum;
  1442. unsigned int uiIndex;
  1443. uiSum = 0;
  1444. for (uiIndex=0; uiIndex < _tcslen(tszName); uiIndex++) {
  1445. // Make CharUpper do single character conversions
  1446. uiSum += _totlower(tszName[uiIndex]);
  1447. }
  1448. return (uiSum % NAME_TABLE_HASH_SIZE);
  1449. }