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.

5188 lines
151 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. ASSOCQE.CPP
  5. Abstract:
  6. WinMgmt Association Query Engine
  7. History:
  8. raymcc 04-Jul-99 Adapted from QENGINE.CPP sources by revolutionary means,
  9. as it was 'Independence Day 1999'.
  10. raymcc 31-Jul-99 Finished classref support
  11. raymcc 19-Aug-99 Fixed security & IN/OUT tagging problems.
  12. raymcc 10-Sep-99 Remaining Win2K bugs
  13. raymcc 25-May-00 Assoc-by-rule
  14. --*/
  15. #include "precomp.h"
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <wbemcore.h>
  19. #include <oahelp.inl>
  20. #include <wqllex.h>
  21. #include <wqlnode.h>
  22. //
  23. // parses a string like "REF:aaaa=cccc"
  24. // returns "AAAA=CCCC" (it uses uppercase)
  25. // it does not use more than MaxCch charactes from the dest buffer
  26. // and it sets a null terminator there
  27. //
  28. /////////////////////////////////////////
  29. void parse_REF(WCHAR * pSrc,size_t MaxCch,WCHAR * pOut)
  30. {
  31. if (L'R' == *pSrc || L'r' == *pSrc) pSrc++;
  32. else goto end_;
  33. if (L'E' == *pSrc || L'e' == *pSrc) pSrc++;
  34. else goto end_;
  35. if (L'F' == *pSrc || L'f' == *pSrc) pSrc++;
  36. else goto end_;
  37. if (L':' == *pSrc) pSrc++;
  38. else goto end_;
  39. WCHAR * pEnd = pOut + MaxCch - 1;
  40. while(*pSrc && (ULONG_PTR)pOut < (ULONG_PTR)pEnd)
  41. {
  42. *pOut = ToUpper((WCHAR)*pSrc);
  43. pOut++;
  44. pSrc++;
  45. }
  46. end_:
  47. *pOut = 0;
  48. }
  49. #define WBEM_S_QUERY_OPTIMIZED_OUT 0x48001
  50. //***************************************************************************
  51. //
  52. // Change these to ConfigMgr
  53. //
  54. //***************************************************************************
  55. #define RUNAWAY_QUERY_TEST_THRESHOLD (60000*10)
  56. #define START_ANOTHER_SINK_THRESHOLD (5000)
  57. #define MAX_CONCURRENT_SINKS 5
  58. #define MAX_CLASS_NAME 512 // SEC:REVIEWED
  59. #define DYN_CLASS_CACHE_REUSE_WINDOW 5000
  60. #define MAX_INTERLEAVED_RESOLUTIONS 5
  61. //
  62. //
  63. // CAssocQuery::CAssocQuery
  64. //
  65. //***************************************************************************
  66. // full profiler line coverage
  67. CAssocQuery::CAssocQuery():
  68. m_lRef(0),
  69. m_pDestSink(0),
  70. m_pEndpoint(0),
  71. m_bstrEndpointClass(0),
  72. m_bstrEndpointRelPath(0),
  73. m_bstrEndpointPath(0),
  74. m_bEndpointIsClass(false),
  75. m_dwQueryStartTime(0),
  76. m_dwLastResultTime(0),
  77. m_lActiveSinks(0),
  78. m_hSinkDoneEvent(0),
  79. m_pContext(0),
  80. m_pNs(0),
  81. m_bCancel(false),
  82. m_bLimitNeedsDecrement(false),
  83. m_Parser()
  84. {
  85. CAsyncServiceQueue* pTemp = ConfigMgr::GetAsyncSvcQueue();
  86. if(pTemp)
  87. {
  88. pTemp->IncThreadLimit();
  89. m_bLimitNeedsDecrement = true;
  90. pTemp->Release();
  91. }
  92. }
  93. //
  94. //
  95. // CAssocQuery::~CAssocQuery()
  96. //
  97. //***************************************************************************
  98. // full profiler line coverage
  99. CAssocQuery::~CAssocQuery()
  100. {
  101. // Cleanup.
  102. // ========
  103. SysFreeString(m_bstrEndpointClass);
  104. SysFreeString(m_bstrEndpointRelPath);
  105. SysFreeString(m_bstrEndpointPath);
  106. if (m_hSinkDoneEvent)
  107. CloseHandle(m_hSinkDoneEvent);
  108. EmptyObjectList(m_aMaster);
  109. EmptyObjectList(m_aDynClasses);
  110. // Release objects.
  111. // ================
  112. if (m_pDestSink)
  113. m_pDestSink->Release();
  114. if (m_pEndpoint)
  115. m_pEndpoint->Release();
  116. if (m_pContext)
  117. m_pContext->Release();
  118. if (m_pNs)
  119. m_pNs->Release();
  120. EmptyCandidateEpArray(); // Call this before deleting critsec
  121. if(m_bLimitNeedsDecrement)
  122. {
  123. CAsyncServiceQueue* pTemp = ConfigMgr::GetAsyncSvcQueue();
  124. if(pTemp)
  125. {
  126. pTemp->DecThreadLimit();
  127. pTemp->Release();
  128. }
  129. }
  130. }
  131. //
  132. //
  133. // CAssocQuery::CreateInst
  134. //
  135. // Mini factory
  136. //
  137. //***************************************************************************
  138. // full profiler line coverage
  139. CAssocQuery* CAssocQuery::CreateInst()
  140. {
  141. try
  142. {
  143. CAssocQuery *p = new CAssocQuery(); // CCritSec throws
  144. if (p) p->AddRef();
  145. return p;
  146. }
  147. catch (CX_Exception &)
  148. {
  149. return NULL;
  150. }
  151. }
  152. //***************************************************************************
  153. //
  154. // CAssocQuery::AddRef
  155. //
  156. //***************************************************************************
  157. // full profiler line coverage
  158. ULONG CAssocQuery::AddRef()
  159. {
  160. return InterlockedIncrement(&m_lRef);
  161. }
  162. //***************************************************************************
  163. //
  164. // CAssocQuery::Release
  165. //
  166. //***************************************************************************
  167. // full profiler line coverage
  168. ULONG CAssocQuery::Release()
  169. {
  170. long lRef = InterlockedDecrement(&m_lRef);
  171. if(lRef == 0)
  172. delete this;
  173. return lRef;
  174. }
  175. //***************************************************************************
  176. //
  177. // CAssocQuery::QueryInterface
  178. //
  179. //***************************************************************************
  180. // not called
  181. HRESULT CAssocQuery::QueryInterface(
  182. REFIID riid,
  183. void** ppv
  184. )
  185. {
  186. if (riid == IID_IUnknown)
  187. {
  188. *ppv = (IUnknown *) this;
  189. AddRef();
  190. return S_OK;
  191. }
  192. return E_NOINTERFACE;
  193. }
  194. //***************************************************************************
  195. //
  196. // CAssocQuery::Cancel
  197. //
  198. // Attempts to cancel the query in the prime of its life.
  199. //
  200. //***************************************************************************
  201. // not called
  202. HRESULT CAssocQuery::Cancel()
  203. {
  204. m_bCancel = true;
  205. return WBEM_S_NO_ERROR;
  206. }
  207. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  208. //
  209. // BEGIN FLOW CONTROL
  210. //
  211. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  212. //***************************************************************************
  213. //
  214. // CAssocQuery::Execute
  215. //
  216. // ENTRY POINT from QENGINE.CPP
  217. //
  218. // Attempts to executes a 'references' or 'associators' query.
  219. // Returns status via <pSink>.
  220. //
  221. // Uses the calling thread to coordinate the entire query. The thread
  222. // logically blocks (and does some background work) until the entire query
  223. // is finished and is responsible for sending the final HRESULT
  224. // to the destination sink.
  225. //
  226. // Ref count of 'this' is not changed in this function. On entry,
  227. // the ref count is 1, so the caller makes the Release call.
  228. //
  229. //***************************************************************************
  230. // ok
  231. HRESULT CAssocQuery::Execute(
  232. IN CWbemNamespace *pNs,
  233. IN LPWSTR pszQuery,
  234. IN IWbemContext* pContext,
  235. IN CBasicObjectSink* pSink
  236. )
  237. {
  238. m_dwQueryStartTime = GetCurrentTime();
  239. // Check the Repository.
  240. // =====================
  241. m_pNs = pNs; // Copy this for future use
  242. m_pNs->AddRef();
  243. HRESULT hRes = WBEM_E_FAILED;
  244. IWbemClassObject* pErrorObj = NULL;
  245. // keep the order of these two objects, since CSetStatusOnMe wants ErrObj to be alive
  246. CReleaseMeRef<IWbemClassObject*> rmErr(pErrorObj);
  247. CSetStatusOnMe SetMe(pSink,hRes,pErrorObj);
  248. // Parse the query.
  249. hRes = m_Parser.Parse(pszQuery);
  250. if (FAILED(hRes)) return hRes;
  251. // If the query is KEYSONLY, we can toss out the original
  252. // context object and use a copy with merged in __GET_EXT_KEYS_ONLY
  253. // techniques. Otherwise, we AddRef() the original context.
  254. // =================================================================
  255. BOOL bKeysOnlyQuery = (m_Parser.GetQueryType() & QUERY_TYPE_KEYSONLY) != 0;
  256. if (pContext)
  257. {
  258. if (bKeysOnlyQuery)
  259. {
  260. hRes = pContext->Clone(&m_pContext);
  261. if (FAILED(hRes)) return hRes;
  262. hRes = m_pNs->MergeGetKeysCtx(m_pContext);
  263. if (FAILED(hRes)) return hRes;
  264. }
  265. else
  266. {
  267. m_pContext = pContext; // Yup, this too.
  268. m_pContext->AddRef();
  269. }
  270. }
  271. // At this point, the query and object path are syntactically
  272. // valid. That's all we know. Not much, eh?
  273. //
  274. // Next, get the endpoint referred to in the query.
  275. // ===========================================================
  276. hRes = pNs->Exec_GetObjectByPath((LPWSTR) m_Parser.GetTargetObjPath(),
  277. 0,
  278. pContext,
  279. &m_pEndpoint,
  280. &pErrorObj);
  281. if (FAILED(hRes)) return hRes;
  282. rmErr.release();
  283. pErrorObj = NULL;
  284. // Record whether the endpoint is a class or instance.
  285. CVARIANT v;
  286. m_pEndpoint->Get(L"__GENUS", 0, &v, 0, 0);
  287. if (v.GetLONG() == 1)
  288. m_bEndpointIsClass = true;
  289. else
  290. m_bEndpointIsClass = false;
  291. // Initial validation.
  292. // For SCHEMAONLY, the endpoint must be a class.
  293. // For CLASSDEFS_ONLY, the endpoint must be an instance.
  294. // Otherwise, the endpoint can be either a class or
  295. // instance the association must be an instance.
  296. // ====================================================
  297. if (m_Parser.GetQueryType() & QUERY_TYPE_SCHEMA_ONLY)
  298. {
  299. if (m_bEndpointIsClass == false) return hRes = WBEM_E_INVALID_QUERY;
  300. }
  301. else if (m_Parser.GetQueryType() & QUERY_TYPE_CLASSDEFS_ONLY)
  302. {
  303. if (m_bEndpointIsClass == true) return hRes = WBEM_E_INVALID_QUERY;
  304. // Don't allow CLASSDEFSONLY and RESULTCLASS at the same time.
  305. if (m_Parser.GetResultClass() != 0) return hRes = WBEM_E_INVALID_QUERY;
  306. }
  307. // Get the class hierarchy and other info about the endpoint.
  308. // ==========================================================
  309. hRes = St_GetObjectInfo(m_pEndpoint,
  310. &m_bstrEndpointClass,
  311. &m_bstrEndpointRelPath,
  312. &m_bstrEndpointPath,
  313. m_aEndpointHierarchy);
  314. if (FAILED(hRes)) return hRes;
  315. // Now we at least know if there is going to be a chance.
  316. m_pDestSink = pSink;
  317. m_pDestSink->AddRef();
  318. try
  319. {
  320. BranchToQueryType(); // Forward-only execution, conceptually
  321. }
  322. catch(CX_Exception &)
  323. {
  324. return hRes = WBEM_E_CRITICAL_ERROR;
  325. }
  326. SetMe.dismiss();
  327. return WBEM_S_NO_ERROR;
  328. }
  329. //***************************************************************************
  330. //
  331. // CAssocQuery::BranchToQueryType
  332. //
  333. // This takes over once the query is known to be syntactically valid
  334. // and the endpoint object was found.
  335. //
  336. // Status & results are returned to the destination sink in the
  337. // deeper functions.
  338. //
  339. //***************************************************************************
  340. // ok
  341. void CAssocQuery::BranchToQueryType()
  342. {
  343. // Next, test for <SchemaOnly> or <ClassDefsOnly> query,
  344. // which allows us a short-cut.
  345. // =====================================================
  346. if (m_Parser.GetQueryType() & QUERY_TYPE_SCHEMA_ONLY)
  347. {
  348. ExecSchemaQuery(); // forward-only branch
  349. }
  350. // If here, we are executing a 'normal' query where
  351. // the association must be an instance.
  352. // ================================================
  353. else
  354. {
  355. ExecNormalQuery();
  356. }
  357. }
  358. //****************************************************************************
  359. //
  360. // CAssocQuery::ExecSchemaQuery
  361. //
  362. // This executes a SCHEMAONLY.
  363. //
  364. // 1. Get the list of classes which can reference the endpoint.
  365. // 2. If REFERENCES OF, branch.
  366. // 3. IF ASSOCIATORS OF, branch.
  367. //
  368. // Execution model from this point:
  369. // Deeper functions only Indicate() results or else return hRes to
  370. // caller. The only SetStatus() call for the destination sink
  371. // is at the bottom of this function.
  372. //
  373. //***************************************************************************
  374. // ok
  375. void CAssocQuery::ExecSchemaQuery()
  376. {
  377. HRESULT hRes;
  378. CFlexArray aResultSet;
  379. // (1)
  380. // ===
  381. hRes = BuildMasterAssocClassList(aResultSet);
  382. if (SUCCEEDED(hRes))
  383. {
  384. // (2)
  385. // ===
  386. if (m_Parser.GetQueryType() & QUERY_TYPE_GETREFS)
  387. hRes = SchemaQ_RefsQuery(aResultSet);
  388. // (3)
  389. // ===
  390. else
  391. hRes = SchemaQ_AssocsQuery(aResultSet);
  392. }
  393. m_pDestSink->Return(hRes);
  394. }
  395. //****************************************************************************
  396. //
  397. // CAssocQuery::ExecNormalQuery
  398. //
  399. // This executes a normal query. The association object must be
  400. // an instance pointing to the endpoint. Either endpoint can be a
  401. // class or an instance.
  402. //
  403. //****************************************************************************
  404. // ok
  405. HRESULT CAssocQuery::ExecNormalQuery()
  406. {
  407. HRESULT hRes = WBEM_E_FAILED;
  408. IWbemClassObject * pErrObj = NULL;
  409. CSetStatusOnMe SetMe(m_pDestSink,hRes,pErrObj);
  410. DWORD dwQueryType = m_Parser.GetQueryType();
  411. // Set up some helper events.
  412. // ==========================
  413. m_hSinkDoneEvent = CreateEvent(0,0,0,0);
  414. if (NULL == m_hSinkDoneEvent) return hRes = WBEM_E_OUT_OF_MEMORY;
  415. // Get the list of classes that can participate.
  416. hRes = BuildMasterAssocClassList(m_aMaster);
  417. if (FAILED(hRes)) return hRes;
  418. // Now reduce this to instantiable classes.
  419. hRes = ReduceToRealClasses(m_aMaster);
  420. if (FAILED(hRes)) return hRes;
  421. // Filter class list based on some quick analysis of the query.
  422. hRes = NormalQ_PreQueryClassFilter(m_aMaster);
  423. if (FAILED(hRes)) return hRes;
  424. // Remove non-dynamic classes, as we will get static refs all in one go.
  425. // IMPORTANT: This must remain located after the zero-array size test above,
  426. // because the array size *will* be zero if the relationships are
  427. // all in the repository and we don't want the query to fail!
  428. hRes = RemoveNonDynClasses(m_aMaster);
  429. if (FAILED(hRes)) return hRes;
  430. if (ConfigMgr::ShutdownInProgress()) return hRes = WBEM_E_SHUTTING_DOWN;
  431. // Now, we branch depending on the query type.
  432. // REFERENCES OF
  433. if (dwQueryType & QUERY_TYPE_GETREFS)
  434. {
  435. hRes = NormalQ_ReferencesOf();
  436. }
  437. else // ASSOCIATORS OF
  438. {
  439. hRes = NormalQ_AssociatorsOf();
  440. }
  441. if (FAILED(hRes)) return hRes;
  442. // At this point, we simply wait until the
  443. // total sink count is zero, indicating that the
  444. // query is completed. We look at any errors
  445. // that were reported and determine what to return.
  446. while (m_lActiveSinks)
  447. {
  448. // Break if a sink finishes or 250 milliseconds pass
  449. // =================================================
  450. WaitForSingleObject(m_hSinkDoneEvent, 250);
  451. // If doing an ASSOCIATORS OF query (not with CLASSDEFSONLY)
  452. // then do some background tasking.
  453. // =========================================================
  454. if ((dwQueryType & QUERY_TYPE_GETASSOCS) != 0 &&
  455. (dwQueryType & QUERY_TYPE_CLASSDEFS_ONLY) == 0)
  456. {
  457. hRes = ResolveEpPathsToObjects(MAX_INTERLEAVED_RESOLUTIONS);
  458. }
  459. if (FAILED(hRes)) return hRes;
  460. if (m_bCancel) return hRes = WBEM_E_CALL_CANCELLED;
  461. }
  462. // If an associators query, resolve the endpoints.
  463. // ===============================================
  464. if ((dwQueryType & QUERY_TYPE_GETASSOCS) != 0)
  465. {
  466. hRes = ResolveEpPathsToObjects(-1);
  467. }
  468. return hRes;
  469. }
  470. //****************************************************************************
  471. //
  472. // CAssocQuery::LoadCheck
  473. //
  474. // Checks the load being induced by this query and prevents too much
  475. // concurrency.
  476. //
  477. //****************************************************************************
  478. // ok
  479. HRESULT CAssocQuery::NormalQ_LoadCheck()
  480. {
  481. while (1)
  482. {
  483. if (m_lActiveSinks <= MAX_CONCURRENT_SINKS)
  484. break;
  485. // If we have a lot of active sinks, see if they
  486. // are fairly active, otherwise add another one.
  487. // =============================================
  488. DWORD dwNow = GetCurrentTime();
  489. if (dwNow - m_dwLastResultTime > START_ANOTHER_SINK_THRESHOLD)
  490. break;
  491. if (dwNow - m_dwQueryStartTime > RUNAWAY_QUERY_TEST_THRESHOLD)
  492. return WBEM_E_CRITICAL_ERROR;
  493. Sleep(50); // Yield time to other threads
  494. }
  495. return WBEM_S_NO_ERROR;
  496. }
  497. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  498. //
  499. // END FLOW CONTROL
  500. //
  501. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  502. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  503. //
  504. // BEGIN MASTER ASSOC CLASS LIST MANIPULATION
  505. //
  506. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  507. //****************************************************************************
  508. //
  509. // CAssocQuery::BuildMasterAssocClassList
  510. //
  511. // This function determines all the classes that could reference the
  512. // endpoint, depending on the query type.
  513. //
  514. // Note: If the endpoint is a class and the query type is NOT schema-only,
  515. // this includes weakly typed classes that have HASCLASSREFS qualifiers
  516. // which can actually potentially reference the endpoint.
  517. //
  518. // HRESULT only
  519. // Does not access the destination sink on error.
  520. //
  521. // PARAMETERS:
  522. // <aClasses> On entry, this is empty. On exit, it contains
  523. // ref counted copies of cached classes. The objects
  524. // within it need to be treated as read-only. If they
  525. // are modified in any way, they should be cloned.
  526. //
  527. //****************************************************************************
  528. // ok
  529. HRESULT CAssocQuery::BuildMasterAssocClassList(
  530. IN OUT CFlexArray &aMaster
  531. )
  532. {
  533. CWStringArray aAllRefClasses;
  534. HRESULT hRes;
  535. BOOL bSchemaOnly = (m_Parser.GetQueryType() & QUERY_TYPE_SCHEMA_ONLY) != 0;
  536. // If the endpoint is a class, we want to add in
  537. // classes with HASCLASSREF qualifiers.
  538. // =============================================
  539. if (m_bEndpointIsClass && !bSchemaOnly)
  540. hRes = MergeInClassRefList(aMaster);
  541. // Go to the repository and get all classes which
  542. // can reference this class. Since a lot of duplicates
  543. // can happen, we do a union of the class list as
  544. // we move through it.
  545. // ====================================================
  546. for (int i = 0; i < m_aEndpointHierarchy.Size(); i++)
  547. {
  548. CWStringArray aRefClasses;
  549. hRes = Db_GetRefClasses(m_aEndpointHierarchy[i],aRefClasses);
  550. if (hRes == WBEM_E_NOT_FOUND)
  551. continue; // It might be a dynamic endpoint
  552. else if (FAILED(hRes))
  553. return hRes;
  554. CWStringArray aTmp;
  555. CWStringArray::Union(aAllRefClasses, aRefClasses, aTmp);
  556. aAllRefClasses = aTmp;
  557. }
  558. // Now get each class definition from the repository.
  559. // This results in a lot of redundancy, since we end up
  560. // with subclasses of classes which actually contain
  561. // the references.
  562. // ====================================================
  563. for (i = 0; i < aAllRefClasses.Size(); i++)
  564. {
  565. LPWSTR pszClassName = aAllRefClasses[i];
  566. IWbemClassObject *pObj = 0;
  567. hRes = Db_GetClass(pszClassName,&pObj);
  568. if (FAILED(hRes)) return hRes;
  569. CReleaseMe rmObj(pObj);
  570. // See if the class can really reference the endpoint
  571. // and discard it if not.
  572. hRes = CanClassRefQueryEp(bSchemaOnly, pObj, 0);
  573. if (FAILED(hRes)) continue;
  574. if (CFlexArray::no_error == aMaster.Add(pObj))
  575. {
  576. pObj->AddRef();
  577. }
  578. }
  579. // Now get the dynamic classes from class providers.
  580. // =================================================
  581. hRes = GetDynClasses();
  582. // Eliminate all the classes that cannot really
  583. // reference the endpoint.
  584. // ============================================
  585. for (i = 0; i < m_aDynClasses.Size(); i++)
  586. {
  587. IWbemClassObject *pDynClass = (IWbemClassObject *) m_aDynClasses[i];
  588. hRes = CanClassRefQueryEp(bSchemaOnly, pDynClass, 0);
  589. if (FAILED(hRes)) continue;
  590. // If here, we will keep the dyn class as a result
  591. // set candidate.
  592. if (CFlexArray::no_error == aMaster.Add(pDynClass))
  593. {
  594. pDynClass->AddRef();
  595. }
  596. }
  597. #ifdef DIAGNOSTICS
  598. ClassListDump(L"BuildMasterAssocClassList", aMaster);
  599. #endif
  600. return WBEM_S_NO_ERROR;
  601. }
  602. //****************************************************************************
  603. //
  604. // CAssocQuery::RemoveNonDynClasses
  605. //
  606. // Removes all classes which don't have [dynamic] qualifiers.
  607. // This allows a single query to the repository for all references
  608. // and individual queries to providers to be cleanly separated.
  609. //
  610. //****************************************************************************
  611. // full profiler line coverage
  612. HRESULT CAssocQuery::RemoveNonDynClasses(
  613. IN OUT CFlexArray &aMaster
  614. )
  615. {
  616. HRESULT hRes1, hRes2;
  617. for (int i = 0; i < aMaster.Size(); i++)
  618. {
  619. IWbemClassObject *pClass = (IWbemClassObject *) aMaster[i];
  620. hRes1 = St_ObjHasQualifier(L"dynamic", pClass);
  621. hRes2 = St_ObjHasQualifier(L"rulebased", pClass);
  622. if (FAILED(hRes1) && FAILED(hRes2))
  623. {
  624. aMaster[i] = 0;
  625. pClass->Release();
  626. }
  627. }
  628. aMaster.Compress();
  629. return WBEM_S_NO_ERROR;
  630. }
  631. //****************************************************************************
  632. //
  633. // CAssocQuery::MergeInClassRefList
  634. //
  635. // Builds the list of classes from all sources which have HasClassRefs
  636. // qualifiers. In addition, the class must be capable of referencing
  637. // the endpoint when it is a class.
  638. //
  639. // Precondition: Query endpoint is known to be a class.
  640. //
  641. //****************************************************************************
  642. // ok
  643. HRESULT CAssocQuery::MergeInClassRefList(
  644. IN OUT CFlexArray &aResultSet
  645. )
  646. {
  647. HRESULT hRes;
  648. CFlexArray aTemp;
  649. hRes = Db_GetClassRefClasses(aTemp);
  650. if (FAILED(hRes)) return hRes;
  651. int i;
  652. for (i = 0; i < aTemp.Size() && SUCCEEDED(hRes); i++)
  653. {
  654. IWbemClassObject *pClass = (IWbemClassObject *) aTemp[i];
  655. HRESULT hResInner = CanClassRefQueryEp(FALSE, pClass, 0);
  656. if (SUCCEEDED(hResInner))
  657. {
  658. if (CFlexArray::no_error != aResultSet.Add(pClass))
  659. {
  660. pClass->Release();
  661. hRes = WBEM_E_OUT_OF_MEMORY;
  662. }
  663. }
  664. else
  665. pClass->Release();
  666. }
  667. // final cleanup, start from where the other loop ended
  668. for (int j=i;j<aTemp.Size();j++)
  669. {
  670. IWbemClassObject *pClass = (IWbemClassObject *) aTemp[i];
  671. pClass->Release();
  672. }
  673. return hRes;
  674. }
  675. //****************************************************************************
  676. //
  677. // CAssocQuery::CanClassRefQueryEp
  678. //
  679. // Determines if a class can reference the endpoint class.
  680. //
  681. // This works for both strongly typed and CLASSREF typed objects.
  682. //
  683. // PARAMETERS:
  684. // <bStrict> If TRUE, the match must be exact. The tested
  685. // class must have properties which directly reference
  686. // the endpoint class name. If FALSE, the class
  687. // can have properties which reference any of the
  688. // superclasses of the query endpoint class.
  689. // <pCls> The class to test.
  690. // <paNames> The role properties which would reference the query
  691. // endpoint. (optional). If not NULL, should point to
  692. // an empty array.
  693. //
  694. // Returns:
  695. // WBEM_S_NO_ERROR if so
  696. // WBEM_E_FAILED
  697. //
  698. //****************************************************************************
  699. // partly tested
  700. HRESULT CAssocQuery::CanClassRefQueryEp(
  701. IN BOOL bStrict,
  702. IN IWbemClassObject *pCls,
  703. OUT CWStringArray *paNames
  704. )
  705. {
  706. BOOL bIsACandidate = FALSE;
  707. HRESULT hRes;
  708. CIMTYPE cType;
  709. LONG lFlavor;
  710. LPCWSTR pszRole = m_Parser.GetRole();
  711. // Loop through the properties trying to find a legitimate
  712. // reference to our endpoint class.
  713. // =======================================================
  714. pCls->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  715. while (1)
  716. {
  717. BSTR strPropName = 0;
  718. hRes = pCls->Next(
  719. 0, // Flags
  720. &strPropName, // Name
  721. 0, // Value
  722. &cType, // CIMTYPE
  723. &lFlavor // FLAVOR
  724. );
  725. CSysFreeMe _1(strPropName);
  726. if (hRes == WBEM_S_NO_MORE_DATA)
  727. break;
  728. // If the ROLE property is specified, and this property is not that
  729. // ROLE, we can immediately eliminate it.
  730. // ================================================================
  731. if (pszRole && wbem_wcsicmp(strPropName, pszRole) != 0)
  732. continue;
  733. // Mask out references inherited from parent classes, if strict
  734. // rules in force.
  735. // ============================================================
  736. //if (bStrict && lFlavor == WBEM_FLAVOR_ORIGIN_PROPAGATED)
  737. // continue;
  738. // If the object has reference properties which are not inherited
  739. // from the parent, then it is immediately candidate.
  740. // ===============================================================
  741. hRes = CanPropRefQueryEp(bStrict, strPropName, pCls, 0);
  742. if (SUCCEEDED(hRes))
  743. {
  744. bIsACandidate = TRUE;
  745. if (paNames)
  746. paNames->Add(strPropName);
  747. }
  748. } // Enum of ref properties
  749. pCls->EndEnumeration();
  750. if (bIsACandidate)
  751. return WBEM_S_NO_ERROR;
  752. return WBEM_E_FAILED;
  753. }
  754. //****************************************************************************
  755. //
  756. // CAssocQuery::GetCimTypeForRef
  757. //
  758. //****************************************************************************
  759. //
  760. HRESULT CAssocQuery::GetCimTypeForRef(
  761. IN IWbemClassObject *pCandidate,
  762. IN BSTR pszRole,
  763. OUT BSTR *strCimType
  764. )
  765. {
  766. if (strCimType == 0)
  767. return WBEM_E_INVALID_PARAMETER;
  768. *strCimType = 0;
  769. // Get the qualifier set for the specified <role> property.
  770. // ========================================================
  771. IWbemQualifierSet *pQSet = 0;
  772. HRESULT hRes = pCandidate->GetPropertyQualifierSet(pszRole, &pQSet);
  773. if (FAILED(hRes))
  774. return WBEM_E_NOT_FOUND;
  775. CReleaseMe _1(pQSet);
  776. // Now, get the type of the role.
  777. // ==============================
  778. CVARIANT vCimType;
  779. hRes = pQSet->Get(L"CIMTYPE", 0, &vCimType, 0);
  780. if (FAILED(hRes) || V_VT(&vCimType) != VT_BSTR)
  781. return WBEM_E_FAILED;
  782. // Get the class name from it.
  783. // ===========================
  784. BSTR strRefClass = V_BSTR(&vCimType);
  785. if (wcslen_max(strRefClass,MAX_CLASS_NAME) > MAX_CLASS_NAME)
  786. return WBEM_E_FAILED;
  787. wchar_t ClassName[MAX_CLASS_NAME];
  788. *ClassName = 0;
  789. if (strRefClass)
  790. {
  791. if (wcslen_max(strRefClass,MAX_CLASS_NAME) > MAX_CLASS_NAME) return WBEM_E_FAILED;
  792. parse_REF(strRefClass,MAX_CLASS_NAME,ClassName);
  793. }
  794. if (0 != ClassName[0])
  795. {
  796. *strCimType = SysAllocString(ClassName);
  797. return WBEM_S_NO_ERROR;
  798. }
  799. return WBEM_E_NOT_FOUND;
  800. }
  801. //****************************************************************************
  802. //
  803. // CAssocQuery::DoesAssocInstRefQueryEp
  804. //
  805. // Determines if an association instance actually references the
  806. // query endpoint. Returns the role via which it actually references
  807. // the query endpoint.
  808. //
  809. //****************************************************************************
  810. //
  811. HRESULT CAssocQuery::DoesAssocInstRefQueryEp(
  812. IN IWbemClassObject *pObj,
  813. OUT BSTR *pstrRole
  814. )
  815. {
  816. if (pstrRole == 0 || pObj == 0)
  817. return WBEM_E_INVALID_PARAMETER;
  818. BOOL bIsACandidate = FALSE;
  819. HRESULT hRes;
  820. // Loop through the properties trying to find a legitimate
  821. // reference to our endpoint class.
  822. // =======================================================
  823. pObj->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  824. while (1)
  825. {
  826. BSTR strPropName = 0;
  827. hRes = pObj->Next(
  828. 0, // Flags
  829. &strPropName, // Name
  830. 0, // Value
  831. 0,
  832. 0
  833. );
  834. CSysFreeMe _1(strPropName);
  835. if (hRes == WBEM_S_NO_MORE_DATA)
  836. break;
  837. hRes = RoleTest(m_pEndpoint, pObj, m_pNs, strPropName, ROLETEST_MODE_PATH_VALUE);
  838. if (SUCCEEDED(hRes))
  839. {
  840. *pstrRole = SysAllocString(strPropName);
  841. pObj->EndEnumeration();
  842. return WBEM_S_NO_ERROR;
  843. }
  844. } // Enum of ref properties
  845. pObj->EndEnumeration();
  846. return WBEM_E_NOT_FOUND;
  847. }
  848. //****************************************************************************
  849. //
  850. // CAssocQuery::NormalQ_PreQueryClassFilter
  851. //
  852. // For normal queries, filters the master class list depending on the
  853. // query parameters and the query type to eliminate as many association
  854. // classes as possible from participating in the query. This is done
  855. // entirely by schema-level analysis and the query parameters.
  856. //
  857. // Also, if the query endpoint is a class, then we eliminate dynamic
  858. // classes which don't have HasClassRefs qualifiers.
  859. //
  860. //****************************************************************************
  861. // visual ok
  862. HRESULT CAssocQuery::NormalQ_PreQueryClassFilter(
  863. CFlexArray &aMaster
  864. )
  865. {
  866. HRESULT hRes;
  867. BOOL bChg = FALSE;
  868. CWStringArray aResClassHierarchy; // Result class hierarchy
  869. CWStringArray aAssocClassHierarchy; // Association class hierarchy
  870. IWbemClassObject *pResClass = 0; // Result class object
  871. IWbemClassObject *pAssocClass = 0; // Assoc class object
  872. LPCWSTR pszResultClass = m_Parser.GetResultClass();
  873. LPCWSTR pszAssocClass = m_Parser.GetAssocClass();
  874. // Get the RESULTCLASS.
  875. // ====================
  876. if (pszResultClass)
  877. {
  878. HRESULT hRes = GetClassFromAnywhere(pszResultClass, 0, &pResClass);
  879. if (hRes == WBEM_E_NOT_FOUND)
  880. {
  881. EmptyObjectList(aMaster);
  882. return WBEM_S_NO_ERROR;
  883. }
  884. else if (FAILED(hRes))
  885. return WBEM_E_FAILED;
  886. // Get its hierarchy.
  887. // ==================
  888. hRes = St_GetObjectInfo(
  889. pResClass, 0, 0, 0,
  890. aResClassHierarchy
  891. );
  892. if (FAILED(hRes))
  893. return WBEM_E_FAILED;
  894. // Get all the subclasses.
  895. // =======================
  896. CFlexArray aFamily;
  897. hRes = GetClassDynasty(pszResultClass, aFamily);
  898. OnDelete<CFlexArray &,void(*)(CFlexArray &),EmptyObjectList> ArrRelMe(aFamily);
  899. for (int i = 0; i < aFamily.Size(); i++)
  900. {
  901. CVARIANT vClass;
  902. IWbemClassObject *pCls = (IWbemClassObject *) aFamily[i];
  903. if (FAILED(hRes = pCls->Get(L"__CLASS", 0, &vClass, 0, 0))) return hRes;
  904. if (CFlexArray::no_error != aResClassHierarchy.Add(vClass.GetStr()))
  905. {
  906. return WBEM_E_OUT_OF_MEMORY;
  907. }
  908. }
  909. }
  910. CReleaseMe _1(pResClass);
  911. // If the ASSOCCLASS was specified, get it and its hierarchy.
  912. // ==========================================================
  913. if (pszAssocClass)
  914. {
  915. HRESULT hRes = GetClassFromAnywhere(pszAssocClass, 0, &pAssocClass);
  916. if (hRes == WBEM_E_NOT_FOUND)
  917. {
  918. EmptyObjectList(aMaster);
  919. return WBEM_S_NO_ERROR;
  920. }
  921. else if (FAILED(hRes))
  922. return WBEM_E_FAILED;
  923. // Get its hierarchy.
  924. // ==================
  925. hRes = St_GetObjectInfo(
  926. pAssocClass, 0, 0, 0,
  927. aAssocClassHierarchy
  928. );
  929. if (FAILED(hRes))
  930. return WBEM_E_FAILED;
  931. }
  932. CReleaseMe _2(pAssocClass);
  933. // Prepurge if REFERENCES OF + RESULTCLASS is used
  934. // or ASSOCIATORS OR + ASSOCCLASS. In both of these cases, the master class
  935. // list is largely irrelevant and will be mostly purged because these are present
  936. // in the query.
  937. //
  938. // [a] If RESULTCLASS/ASSOCCLASS is directly mentioned in the master, the master is
  939. // purged and RESULTCLASS/ASSOCCLASS is added.
  940. //
  941. // [b] If RESULTCLASS/ASSOCCLASS is a subclass of a class in the master list, we examine
  942. // its class hierarchy and determine if any of its superclasses appear in
  943. // the master list. If so, we purge the master list and replace it with a
  944. // single entry, containing the RESULTCLASS def.
  945. //
  946. // [c] If RESULTCLASS/ASSOCCLASS is a superclass, we examine each class C in the
  947. // master and determine if any of the superclasses of C are the
  948. // RESULTCLASS/ASSOCCLASS. If so, we retain C in the master. If not, we purge it.
  949. //
  950. LPCWSTR pszTestClass = 0; // RESULTCLASS/ASSOCCLASS alias
  951. IWbemClassObject *pTestClass = 0;
  952. CWStringArray *paTest = 0;
  953. if ((m_Parser.GetQueryType() & QUERY_TYPE_GETREFS) && pszResultClass)
  954. {
  955. pszTestClass = pszResultClass;
  956. pTestClass = pResClass;
  957. paTest = &aResClassHierarchy;
  958. }
  959. if ((m_Parser.GetQueryType() & QUERY_TYPE_GETASSOCS) && pszAssocClass)
  960. {
  961. pszTestClass = pszAssocClass;
  962. pTestClass = pAssocClass;
  963. paTest = &aAssocClassHierarchy;
  964. }
  965. if (pszTestClass && pTestClass && paTest)
  966. {
  967. // Test [a] : Look for direct match.
  968. // =================================
  969. BOOL bPurgeAndReplace = FALSE;
  970. for (int i = 0; i < aMaster.Size(); i++)
  971. {
  972. IWbemClassObject *pClass = (IWbemClassObject *) aMaster[i];
  973. CVARIANT v;
  974. hRes = pClass->Get(L"__CLASS", 0, &v, 0, 0);
  975. if (FAILED(hRes))
  976. return hRes;
  977. if (wbem_wcsicmp(V_BSTR(&v), pszTestClass) == 0)
  978. {
  979. bPurgeAndReplace = TRUE;
  980. }
  981. // Test [b]
  982. // If here, there was no equivalence. So, the test class may be a subclass
  983. // of a class in master. We simply look to see if this class name appears
  984. // in the hierarchy of the result class.
  985. // ===========================================================================
  986. if (!bPurgeAndReplace)
  987. for (int ii = 0; ii < paTest->Size(); ii++)
  988. {
  989. if (wbem_wcsicmp(V_BSTR(&v), paTest->operator[](ii)) == 0)
  990. {
  991. bPurgeAndReplace = TRUE;
  992. break;
  993. }
  994. }
  995. if (bPurgeAndReplace)
  996. {
  997. // Get rid of everything but this one.
  998. // ===================================
  999. EmptyObjectList(aMaster); // Will Release <pClass> once
  1000. if (CFlexArray::no_error == aMaster.Add(pTestClass))
  1001. {
  1002. pTestClass->AddRef();
  1003. }
  1004. break;
  1005. }
  1006. }
  1007. }
  1008. // Process possibly-altered master class list using other filters.
  1009. // ===============================================================
  1010. for (int i = 0; i < aMaster.Size(); i++)
  1011. {
  1012. IWbemClassObject *pClass = (IWbemClassObject *) aMaster[i];
  1013. BOOL bKeep = TRUE;
  1014. CVARIANT v;
  1015. hRes = pClass->Get(L"__CLASS", 0, &v, 0, 0);
  1016. if (FAILED(hRes))
  1017. return hRes;
  1018. // If query type is REFERENCES OF
  1019. // ==============================
  1020. if (m_Parser.GetQueryType() & QUERY_TYPE_GETREFS)
  1021. {
  1022. // ROLE test
  1023. // =========
  1024. LPCWSTR pszRole = m_Parser.GetRole();
  1025. if (pszRole)
  1026. {
  1027. CWStringArray aNames;
  1028. hRes = CanClassRefQueryEp(FALSE, pClass, &aNames);
  1029. if (FAILED(hRes))
  1030. bKeep = FALSE;
  1031. else
  1032. {
  1033. for (int ii = 0; ii < aNames.Size(); ii++)
  1034. {
  1035. if (wbem_wcsicmp(aNames[ii], pszRole) != 0)
  1036. bKeep = FALSE;
  1037. }
  1038. }
  1039. }
  1040. // REQUIREDQUALIFIER test
  1041. // =======================
  1042. LPCWSTR pszRequiredQual = m_Parser.GetRequiredQual();
  1043. if (pszRequiredQual)
  1044. {
  1045. hRes = St_ObjHasQualifier(pszRequiredQual, pClass);
  1046. if (FAILED(hRes))
  1047. {
  1048. // If not in the primary object, check subclasses.
  1049. CFlexArray aDynasty;
  1050. hRes = GetClassDynasty(v.GetStr(), aDynasty);
  1051. if (FAILED(hRes))
  1052. bKeep = FALSE;
  1053. int nCandidateCount = 0;
  1054. for (int ii = 0; ii< aDynasty.Size(); ii++)
  1055. {
  1056. IWbemClassObject *pTestCls = (IWbemClassObject *) aDynasty[ii];
  1057. hRes = St_ObjHasQualifier(pszRequiredQual, pTestCls);
  1058. if (SUCCEEDED(hRes))
  1059. nCandidateCount++;
  1060. }
  1061. EmptyObjectList(aDynasty);
  1062. if (nCandidateCount == 0)
  1063. bKeep = FALSE; // Nobody in the family has the qualifier
  1064. }
  1065. }
  1066. // RESULTCLASS test, test [c]
  1067. // ==========================
  1068. LPCWSTR pszResultClass2 = m_Parser.GetResultClass();
  1069. if (pszResultClass2)
  1070. {
  1071. hRes = St_ObjIsOfClass(pszResultClass2, pClass);
  1072. if (FAILED(hRes))
  1073. bKeep = FALSE;
  1074. }
  1075. }
  1076. // If query type is ASSOCIATORS OF
  1077. // ===============================
  1078. else
  1079. {
  1080. // ROLE test
  1081. // =========
  1082. LPCWSTR pszRole = m_Parser.GetRole();
  1083. if (pszRole)
  1084. {
  1085. CWStringArray aNames;
  1086. hRes = CanClassRefQueryEp(FALSE, pClass, &aNames);
  1087. if (FAILED(hRes))
  1088. bKeep = FALSE;
  1089. else
  1090. {
  1091. bKeep = FALSE;
  1092. for (int ii = 0; ii < aNames.Size(); ii++)
  1093. {
  1094. if (wbem_wcsicmp(aNames[ii], pszRole) == 0)
  1095. bKeep = TRUE;
  1096. }
  1097. }
  1098. }
  1099. // ASSOCCLASS, test[c]
  1100. // ===================
  1101. LPCWSTR pszAssocClass2 = m_Parser.GetAssocClass();
  1102. if (pszAssocClass2)
  1103. {
  1104. hRes = St_ObjIsOfClass(pszAssocClass2, pClass);
  1105. if (FAILED(hRes))
  1106. bKeep = FALSE;
  1107. }
  1108. // REQUIREDASSOCQUALIFER
  1109. // =====================
  1110. LPCWSTR pszRequiredAssocQual = m_Parser.GetRequiredAssocQual();
  1111. if (pszRequiredAssocQual)
  1112. {
  1113. hRes = St_ObjHasQualifier(pszRequiredAssocQual, pClass);
  1114. if (FAILED(hRes))
  1115. {
  1116. // If not in the primary object, check subclasses.
  1117. CFlexArray aDynasty;
  1118. hRes = GetClassDynasty(v.GetStr(), aDynasty);
  1119. if (FAILED(hRes))
  1120. bKeep = FALSE;
  1121. int nCandidateCount = 0;
  1122. for (int ii = 0; ii < aDynasty.Size(); ii++)
  1123. {
  1124. IWbemClassObject *pTestCls = (IWbemClassObject *) aDynasty[ii];
  1125. hRes = St_ObjHasQualifier(pszRequiredAssocQual, pTestCls);
  1126. if (SUCCEEDED(hRes))
  1127. nCandidateCount++;
  1128. }
  1129. EmptyObjectList(aDynasty);
  1130. if (nCandidateCount == 0)
  1131. bKeep = FALSE; // Nobody in the family has the qualifier
  1132. }
  1133. }
  1134. // If RESULTCLASS was used, branch out and see if the association
  1135. // class can even reference it.
  1136. // ==============================================================
  1137. LPCWSTR pszResultClass3 = m_Parser.GetResultClass();
  1138. if (pszResultClass3 && m_bEndpointIsClass == FALSE)
  1139. {
  1140. // The above compound test is to err on the side of safety,
  1141. // as the following function cannot deal with CLASSREFs. So,
  1142. // we simply don't try to prefilter in that case.
  1143. // =========================================================
  1144. hRes = CanAssocClassRefUnkEp(pClass, aResClassHierarchy);
  1145. if (FAILED(hRes))
  1146. bKeep = FALSE;
  1147. }
  1148. // If RESULTROLE is used, ensure the class even has a property of this name.
  1149. // =========================================================================
  1150. LPCWSTR pszResultRole = m_Parser.GetResultRole();
  1151. if (pszResultRole)
  1152. {
  1153. CVARIANT v2;
  1154. hRes = pClass->Get(pszResultRole, 0, &v2, 0, 0);
  1155. if (FAILED(hRes))
  1156. bKeep = FALSE;
  1157. }
  1158. } // end ASSOCIATORS OF test block
  1159. // If query endpoint is a class, eliminate [dynamic] classes which don't
  1160. // have HasClassRefs.
  1161. // ======================================================================
  1162. if (m_bEndpointIsClass)
  1163. {
  1164. hRes = St_ObjHasQualifier(L"dynamic", pClass);
  1165. if (SUCCEEDED(hRes))
  1166. {
  1167. hRes = St_ObjHasQualifier(L"HasClassRefs", pClass);
  1168. if (FAILED(hRes))
  1169. bKeep = FALSE;
  1170. }
  1171. }
  1172. // Yawn. So what did we end up deciding, anyway?
  1173. // ==============================================
  1174. if (bKeep == FALSE)
  1175. {
  1176. aMaster[i] = 0;
  1177. pClass->Release();
  1178. }
  1179. }
  1180. // No Swiss Cheese allowed. Close them holes.
  1181. // ==========================================
  1182. aMaster.Compress();
  1183. return WBEM_S_NO_ERROR;
  1184. }
  1185. //***************************************************************************
  1186. //
  1187. // CAssocQuery::CanAssocClassRefUnkEp
  1188. //
  1189. // Determines if the association class can reference the specified
  1190. // class.
  1191. //
  1192. // Returns:
  1193. // WBEM_S_NO_ERROR if the assoc can reference the specified class.
  1194. // WBEM_E_NOT_FOUND if the assoc cannot reference the class.
  1195. // WBEM_E_FAILED in other cases.
  1196. //
  1197. //***************************************************************************
  1198. //
  1199. HRESULT CAssocQuery::CanAssocClassRefUnkEp(
  1200. IN IWbemClassObject *pAssocClass,
  1201. IN CWStringArray &aUnkEpHierarchy
  1202. )
  1203. {
  1204. HRESULT hRes;
  1205. BOOL bFound = FALSE;
  1206. // Loop through all references and see if any of them can
  1207. // reference any of the classes in the result class hierarchy.
  1208. // ===========================================================
  1209. hRes = pAssocClass->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  1210. while (1)
  1211. {
  1212. BSTR strPropName = 0;
  1213. hRes = pAssocClass->Next(
  1214. 0, // Flags
  1215. &strPropName, // Name
  1216. 0, // Value
  1217. 0,
  1218. 0
  1219. );
  1220. CSysFreeMe _1(strPropName);
  1221. if (hRes == WBEM_S_NO_MORE_DATA)
  1222. break;
  1223. BSTR strCimType = 0;
  1224. hRes = GetCimTypeForRef(pAssocClass, strPropName, &strCimType);
  1225. CSysFreeMe _2(strCimType);
  1226. if (SUCCEEDED(hRes) && strCimType)
  1227. for (int i = 0; i < aUnkEpHierarchy.Size(); i++)
  1228. {
  1229. if (wbem_wcsicmp(aUnkEpHierarchy[i], strCimType) == 0)
  1230. {
  1231. bFound = TRUE;
  1232. break;
  1233. }
  1234. }
  1235. }
  1236. pAssocClass->EndEnumeration();
  1237. if (bFound)
  1238. {
  1239. return WBEM_S_NO_ERROR;
  1240. }
  1241. return WBEM_E_NOT_FOUND;
  1242. }
  1243. //***************************************************************************
  1244. //
  1245. // CAssocQuery::ReduceToRealClasses
  1246. //
  1247. // Reduces the master class list to classes which can be instantiated.
  1248. //
  1249. // To have an instance, a class must
  1250. // 1. Have a [key] or be singleton
  1251. // 2. Not be abstract
  1252. // 3. Not have an instantiable superclass
  1253. //
  1254. // Parameters:
  1255. // IN OUT aMaster Contains the unpruned result inbound
  1256. // and contains the pruned result set outbound
  1257. //
  1258. // Return value:
  1259. // HRESULT The destination sink is not accessed
  1260. //
  1261. //***************************************************************************
  1262. //
  1263. HRESULT CAssocQuery::ReduceToRealClasses(
  1264. IN OUT CFlexArray & aMaster
  1265. )
  1266. {
  1267. HRESULT hRes;
  1268. for (int i = 0; i < aMaster.Size(); i++)
  1269. {
  1270. BOOL bKeep = TRUE;
  1271. IWbemClassObject *pObj = (IWbemClassObject *) aMaster[i];
  1272. // See if class is abstract.
  1273. // =========================
  1274. IWbemQualifierSet *pQSet = 0;
  1275. hRes = pObj->GetQualifierSet(&pQSet);
  1276. if (FAILED(hRes))
  1277. return hRes;
  1278. CReleaseMe _1(pQSet);
  1279. CVARIANT v1, v2, v3;
  1280. HRESULT hResAbstract = pQSet->Get(L"ABSTRACT", 0, &v1, 0);
  1281. HRESULT hResSingleton = pQSet->Get(L"SINGLETON", 0, &v2, 0);
  1282. HRESULT hResDynamic = pQSet->Get(L"DYNAMIC", 0, &v3, 0);
  1283. // See if there is at least one key.
  1284. // =================================
  1285. HRESULT hResHasKeys = WBEM_E_FAILED;
  1286. pObj->BeginEnumeration(WBEM_FLAG_KEYS_ONLY);
  1287. int nCount = 0;
  1288. while (1)
  1289. {
  1290. // Actually, we don't care about anything
  1291. // other than if keys even exist. We
  1292. // do this by simply testing how many
  1293. // times this iterates.
  1294. hRes = pObj->Next(0,0,0,0,0);
  1295. if (hRes == WBEM_S_NO_MORE_DATA)
  1296. break;
  1297. nCount++;
  1298. }
  1299. pObj->EndEnumeration();
  1300. if (nCount)
  1301. hResHasKeys = WBEM_S_NO_ERROR;
  1302. // Decision matrix which perform tests as to whether
  1303. // this is an instantiable class.
  1304. // ==================================================
  1305. if (SUCCEEDED(hResAbstract)) // Abstracts are never instantiable
  1306. bKeep = FALSE;
  1307. else if (SUCCEEDED(hResDynamic)) // Dynamics must be instantiable
  1308. bKeep = TRUE;
  1309. else if (SUCCEEDED(hResHasKeys)) // Must be static/non-abstract
  1310. bKeep = TRUE;
  1311. else if (SUCCEEDED(hResSingleton)) // Must be static/non-abstract
  1312. bKeep = TRUE;
  1313. else
  1314. bKeep = FALSE; // Must be plain old keyless class
  1315. // Final decision to zap or keep.
  1316. // ==============================
  1317. if (!bKeep)
  1318. {
  1319. aMaster[i] = 0;
  1320. pObj->Release();
  1321. }
  1322. }
  1323. aMaster.Compress();
  1324. // Next, eliminate subclass/superclass pairs.
  1325. // ==========================================
  1326. for (i = 0; i < aMaster.Size(); i++)
  1327. {
  1328. IWbemClassObject *pObj = (IWbemClassObject *) aMaster[i];
  1329. CWStringArray aHierarchy;
  1330. hRes = St_GetObjectInfo(pObj, 0, 0, 0, aHierarchy);
  1331. BOOL bKillIt = FALSE;
  1332. if (FAILED(hRes))
  1333. return WBEM_E_FAILED;
  1334. // We now have the class and all of its superclasses in
  1335. // <aHierarchy>. We need to look at all the other classes
  1336. // and see if any of them have a class name mentioned in
  1337. // this array.
  1338. // ========================================================
  1339. for (int i2 = 0; i2 < aMaster.Size(); i2++)
  1340. {
  1341. IWbemClassObject *pTest = (IWbemClassObject *) aMaster[i2];
  1342. if (pTest == 0 || i2 == i)
  1343. continue;
  1344. // If the object has already been eliminated or
  1345. // if we are comparing an object with itself
  1346. CVARIANT v;
  1347. hRes = pTest->Get(L"__CLASS", 0, &v, 0, 0);
  1348. if (FAILED(hRes))
  1349. return hRes;
  1350. LPWSTR pszName = V_BSTR(&v);
  1351. if (pszName == 0)
  1352. return WBEM_E_FAILED;
  1353. bKillIt = FALSE;
  1354. for (int i3 = 0; i3 < aHierarchy.Size(); i3++)
  1355. {
  1356. if (wbem_wcsicmp(aHierarchy[i3], pszName) == 0)
  1357. {
  1358. bKillIt = TRUE;
  1359. break;
  1360. }
  1361. }
  1362. if (bKillIt)
  1363. break;
  1364. }
  1365. if (bKillIt)
  1366. {
  1367. aMaster[i] = 0;
  1368. pObj->Release();
  1369. }
  1370. }
  1371. // Get rid of NULL entries.
  1372. // ========================
  1373. aMaster.Compress();
  1374. #ifdef DIAGNOSTICS
  1375. ClassListDump(L"Reduced Class Set", aMaster);
  1376. #endif
  1377. return WBEM_S_NO_ERROR;
  1378. }
  1379. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  1380. //
  1381. // END MASTER ASSOC CLASS LIST MANIPULATION
  1382. //
  1383. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  1384. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  1385. //
  1386. // BEGIN NORMAL QUERY SUPPORT
  1387. //
  1388. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  1389. //****************************************************************************
  1390. //
  1391. // CAssocQuery::NormalQ_ReferencesOf
  1392. //
  1393. // Entry point for all normal REFERENCES OF queries.
  1394. //
  1395. //****************************************************************************
  1396. // untested; no support for classrefs, autoassocs, or classdefsonly
  1397. HRESULT CAssocQuery::NormalQ_ReferencesOf()
  1398. {
  1399. HRESULT hRes;
  1400. // Issue one-time call into repository for static instances.
  1401. CObjectSink * pSink = CreateSink(FilterForwarder_NormalRefs, L"<objdb refs request>");
  1402. if (NULL == pSink) return WBEM_E_OUT_OF_MEMORY;
  1403. CReleaseMe rmSink(pSink);
  1404. hRes = Db_GetInstRefs(m_bstrEndpointPath,pSink);
  1405. rmSink.release();
  1406. if ( FAILED(hRes) && !(hRes == WBEM_E_NOT_FOUND || hRes == WBEM_E_CALL_CANCELLED))
  1407. {
  1408. // We only go here if the repository is really griping.
  1409. return WBEM_E_FAILED;
  1410. }
  1411. // Check for cancellation.
  1412. if (m_bCancel) return WBEM_E_CALL_CANCELLED;
  1413. hRes = WBEM_S_NO_ERROR;
  1414. // Now get all the dynamic ones.
  1415. // =============================
  1416. for (int i = 0; i < m_aMaster.Size(); i++)
  1417. {
  1418. IWbemClassObject *pClass = (IWbemClassObject *) m_aMaster[i];
  1419. IWbemQualifierSet *pQSet = 0;
  1420. hRes = pClass->GetQualifierSet(&pQSet);
  1421. if (FAILED(hRes)) return hRes;
  1422. CReleaseMe _1(pQSet);
  1423. CVARIANT v1, v2;
  1424. HRESULT hResRuleBased = pQSet->Get(L"RULEBASED", 0, &v1, 0);
  1425. HRESULT hResDynamic = pQSet->Get(L"DYNAMIC", 0, &v2, 0);
  1426. if (SUCCEEDED(hResDynamic))
  1427. {
  1428. // If here, a normal association class.
  1429. //
  1430. // Build the query relative to this class that would select instances
  1431. // which can point to the endpoint.
  1432. // ==================================================================
  1433. // We may be able to infer that keys_only behavior is possible.
  1434. // ============================================================
  1435. IWbemContext *pCopy = 0;
  1436. if (m_pContext)
  1437. {
  1438. if (FAILED(hRes = m_pContext->Clone(&pCopy))) return hRes;
  1439. }
  1440. CReleaseMe rmCtx(pCopy);
  1441. BSTR strQuery = 0;
  1442. if (FAILED(hRes = NormalQ_ConstructRefsQuery(pClass, pCopy, &strQuery))) return hRes;
  1443. CSysFreeMe fm(strQuery);
  1444. // The query may have been optimized out of existence.
  1445. if (hRes == WBEM_S_QUERY_OPTIMIZED_OUT)
  1446. {
  1447. hRes = 0;
  1448. continue;
  1449. }
  1450. // Now submit the query to the sink.
  1451. pSink = CreateSink(FilterForwarder_NormalRefs, strQuery);
  1452. if (NULL == pSink) WBEM_E_OUT_OF_MEMORY;
  1453. CReleaseMe rmSink2(pSink);
  1454. if (FAILED(hRes = CoImpersonateClient())) return hRes;
  1455. OnDelete0<HRESULT(*)(void),CoRevertToSelf> RevertMe;
  1456. BSTR bStrWQL = SysAllocString(L"WQL");
  1457. if (NULL == bStrWQL) return WBEM_E_OUT_OF_MEMORY;;
  1458. CSysFreeMe fm_(bStrWQL);
  1459. if (FAILED(hRes = m_pNs->ExecQueryAsync(bStrWQL, strQuery, 0, pCopy, pSink))) return hRes;
  1460. if (FAILED(hRes = NormalQ_LoadCheck())) return hRes;
  1461. if (m_bCancel) return WBEM_E_CALL_CANCELLED;
  1462. }
  1463. else if (SUCCEEDED(hResRuleBased)) // Rule based
  1464. {
  1465. CFlexArray aTriads;
  1466. OnDelete<CFlexArray &,void(*)(CFlexArray &),SAssocTriad::ArrayCleanup> CleanMe(aTriads);
  1467. if (FAILED(hRes = CoImpersonateClient())) return hRes;
  1468. {
  1469. OnDelete0<HRESULT(*)(void),CoRevertToSelf> RevertMe;
  1470. if (FAILED(hRes = m_pNs->ManufactureAssocs(pClass, m_pEndpoint, m_pContext, v1.GetStr(), aTriads))) return hRes;
  1471. }
  1472. // Now deliver stuff to sink
  1473. pSink = CreateSink(FilterForwarder_NormalRefs, L"<rulebased>");
  1474. if (NULL == pSink) return WBEM_E_OUT_OF_MEMORY;
  1475. CReleaseMe rmSink2(pSink);
  1476. for (int ii = 0; ii < aTriads.Size(); ii++)
  1477. {
  1478. SAssocTriad *pTriad = (SAssocTriad *) aTriads[ii];
  1479. pSink->Indicate(1, &pTriad->m_pAssoc);
  1480. }
  1481. pSink->SetStatus(0, 0, 0, 0);
  1482. }
  1483. }
  1484. return hRes;
  1485. }
  1486. //****************************************************************************
  1487. //
  1488. // CAssocQuery::NormalQ_AssociatorsOf
  1489. //
  1490. // Entry point for all normal ASSOCIATORS OF queries.
  1491. //
  1492. //****************************************************************************
  1493. //
  1494. //
  1495. HRESULT CAssocQuery::NormalQ_AssociatorsOf()
  1496. {
  1497. HRESULT hRes;
  1498. CObjectSink *pSink;
  1499. // Issue one-time call into repository for static instances.
  1500. // =========================================================
  1501. pSink = CreateSink(FilterForwarder_NormalAssocs, L"<objdb assocs request>");
  1502. if (NULL == pSink) return WBEM_E_OUT_OF_MEMORY;
  1503. CReleaseMe rmSink(pSink);
  1504. hRes = Db_GetInstRefs(m_bstrEndpointPath,pSink); // thows
  1505. rmSink.release();
  1506. if (FAILED(hRes) && !(hRes == WBEM_E_NOT_FOUND || hRes == WBEM_E_CALL_CANCELLED))
  1507. {
  1508. // We only go here if the repository is really griping.
  1509. return WBEM_E_FAILED;
  1510. }
  1511. // Check for cancellation.
  1512. if (m_bCancel) return WBEM_E_CALL_CANCELLED;
  1513. hRes = WBEM_S_NO_ERROR;
  1514. // Now get dynamic associations.
  1515. for (int i = 0; i < m_aMaster.Size(); i++)
  1516. {
  1517. IWbemClassObject *pClass = (IWbemClassObject *) m_aMaster[i];
  1518. IWbemQualifierSet *pQSet = 0;
  1519. hRes = pClass->GetQualifierSet(&pQSet);
  1520. if (FAILED(hRes))
  1521. return hRes;
  1522. CReleaseMe _1(pQSet);
  1523. CVARIANT v1, v2;
  1524. HRESULT hResRuleBased = pQSet->Get(L"RULEBASED", 0, &v1, 0);
  1525. HRESULT hResDynamic = pQSet->Get(L"DYNAMIC", 0, &v2, 0);
  1526. if (SUCCEEDED(hResDynamic))
  1527. {
  1528. // Build the query relative to this class that would select instances
  1529. // which can point to the endpoint.
  1530. BSTR strQuery = 0;
  1531. hRes = NormalQ_ConstructRefsQuery(pClass, 0, &strQuery); // thows
  1532. CSysFreeMe fm(strQuery);
  1533. if (FAILED(hRes))
  1534. return WBEM_E_FAILED;
  1535. if (hRes == WBEM_S_QUERY_OPTIMIZED_OUT)
  1536. {
  1537. hRes = 0;
  1538. continue;
  1539. }
  1540. CObjectSink *pInSink = CreateSink(FilterForwarder_NormalAssocs, strQuery);
  1541. if (NULL == pInSink) return WBEM_E_OUT_OF_MEMORY;
  1542. CReleaseMe rmInSink(pInSink);
  1543. IWbemContext *pCopy = 0;
  1544. if (m_pContext)
  1545. {
  1546. if (FAILED(hRes = m_pContext->Clone(&pCopy))) return hRes;
  1547. }
  1548. CReleaseMe rmCtx(pCopy);
  1549. if (FAILED(hRes =m_pNs->MergeGetKeysCtx(pCopy))) return hRes;
  1550. if (FAILED(hRes = CoImpersonateClient())) return hRes;
  1551. OnDelete0<HRESULT(*)(void),CoRevertToSelf> RevertMe;
  1552. BSTR bStrWQL = SysAllocString(L"WQL");
  1553. if (NULL == bStrWQL) return WBEM_E_OUT_OF_MEMORY;
  1554. CSysFreeMe fm_(bStrWQL);
  1555. if (FAILED(hRes = m_pNs->ExecQueryAsync(bStrWQL, strQuery, 0, pCopy, pInSink))) return hRes;
  1556. if (FAILED(hRes = NormalQ_LoadCheck())) return hRes;
  1557. if (m_bCancel) return WBEM_E_CALL_CANCELLED;
  1558. }
  1559. else if (SUCCEEDED(hResRuleBased)) // Rule based
  1560. {
  1561. CFlexArray aTriads;
  1562. OnDelete<CFlexArray &,void(*)(CFlexArray &),SAssocTriad::ArrayCleanup> CleanMe(aTriads);
  1563. if (FAILED(hRes = CoImpersonateClient())) return hRes;
  1564. {
  1565. OnDelete0<HRESULT(*)(void),CoRevertToSelf> RevertMe;
  1566. if (FAILED(hRes = m_pNs->ManufactureAssocs(pClass, m_pEndpoint, m_pContext, v1.GetStr(), aTriads))) return hRes;
  1567. }
  1568. // Now deliver stuff to sink
  1569. pSink = CreateSink(FilterForwarder_NormalRefs, L"<rulebased>");
  1570. if (NULL == pSink) return WBEM_E_OUT_OF_MEMORY;
  1571. CReleaseMe rmSink2(pSink);
  1572. for (int ii = 0; ii < aTriads.Size(); ii++)
  1573. {
  1574. SAssocTriad *pTriad = (SAssocTriad *) aTriads[ii];
  1575. pSink->Indicate(1, &pTriad->m_pEp2);
  1576. }
  1577. pSink->SetStatus(0, 0, 0, 0);
  1578. }
  1579. }
  1580. return hRes;
  1581. }
  1582. //***************************************************************************
  1583. //
  1584. // CAssocQuery::NormalQ_GetRefsOfEndpoint
  1585. //
  1586. // Builds a query text to select association instances which can reference
  1587. // the endpoint instance.
  1588. //
  1589. // Returns:
  1590. // WBEM_S_NO_ERROR
  1591. // A WBEM_E_ code
  1592. //
  1593. //***************************************************************************
  1594. // ok
  1595. HRESULT CAssocQuery::NormalQ_ConstructRefsQuery(
  1596. IN IWbemClassObject *pClass,
  1597. IN OUT IWbemContext *pContextCopy,
  1598. OUT BSTR *strQuery
  1599. )
  1600. {
  1601. if (strQuery == 0)
  1602. return WBEM_E_INVALID_PARAMETER;
  1603. *strQuery = 0;
  1604. HRESULT hRes;
  1605. CVARIANT v;
  1606. // Get the class name of the association we are
  1607. // trying to get instances for.
  1608. // ============================================
  1609. hRes = pClass->Get(L"__CLASS", 0, &v, 0, 0);
  1610. if (FAILED(hRes)) return WBEM_E_FAILED;
  1611. // Build up the query we want.
  1612. // ===========================
  1613. WString wsQuery = "select * from ";
  1614. wsQuery += V_BSTR(&v); // Add in assoc class
  1615. wsQuery += " where ";
  1616. // Next determine which role to use to reach the query endpoint.
  1617. // =============================================================
  1618. CWStringArray aNames;
  1619. hRes = CanClassRefQueryEp(FALSE, pClass, &aNames);
  1620. if (FAILED(hRes))
  1621. return WBEM_E_FAILED;
  1622. // If RESULTROLE is specified in the query, then eliminate
  1623. // it from aNames, since aNames is reserved for roles
  1624. // pointing to the query endpoint.
  1625. // =======================================================
  1626. LPCWSTR pszResultRole = m_Parser.GetResultRole();
  1627. if (pszResultRole)
  1628. {
  1629. for (int i = 0; i < aNames.Size(); i++)
  1630. {
  1631. if (wbem_wcsicmp(aNames[i], pszResultRole) == 0)
  1632. {
  1633. aNames.RemoveAt(i);
  1634. i--;
  1635. }
  1636. }
  1637. }
  1638. // Ensure something is going to point to our endpoint.
  1639. // ===================================================
  1640. if (aNames.Size() == 0)
  1641. return WBEM_S_QUERY_OPTIMIZED_OUT;
  1642. // Now build up the query which refers to the endpoint explicitly.
  1643. // If more than one role works, build up an OR clause.
  1644. // ===============================================================
  1645. while (aNames.Size())
  1646. {
  1647. wsQuery += aNames[0];
  1648. wsQuery += "=\"";
  1649. WString Path(m_bstrEndpointRelPath);
  1650. wsQuery += Path.EscapeQuotes();
  1651. wsQuery += "\"";
  1652. aNames.RemoveAt(0);
  1653. if (aNames.Size())
  1654. wsQuery += " OR ";
  1655. }
  1656. // If here, we have the role to use.
  1657. // =================================
  1658. *strQuery = SysAllocString(wsQuery);
  1659. DEBUGTRACE((LOG_WBEMCORE, "Association Engine: submitting query <%S> to core\n", LPWSTR(wsQuery) ));
  1660. // Determine if association class only has keys anyway, in which
  1661. // case we can merge in the keys_only behavior. In cases
  1662. // where the provider can only enumerate instead of interpret
  1663. // the query, this might help.
  1664. // =============================================================
  1665. if (pContextCopy)
  1666. {
  1667. hRes = AssocClassHasOnlyKeys(pClass);
  1668. if (hRes == WBEM_S_NO_ERROR)
  1669. {
  1670. hRes = m_pNs->MergeGetKeysCtx(pContextCopy);
  1671. }
  1672. }
  1673. return WBEM_S_NO_ERROR;
  1674. }
  1675. //****************************************************************************
  1676. //
  1677. // CAssocQuery::AssocClassHasOnlyKeys
  1678. //
  1679. // Returns WBEM_S_NO_ERROR if the assoc class only has keys.
  1680. //
  1681. //****************************************************************************
  1682. //
  1683. HRESULT CAssocQuery::AssocClassHasOnlyKeys(
  1684. IN IWbemClassObject *pObj
  1685. )
  1686. {
  1687. int nKeyCount = 0;
  1688. HRESULT hRes;
  1689. pObj->BeginEnumeration(WBEM_FLAG_KEYS_ONLY);
  1690. while (1)
  1691. {
  1692. hRes = pObj->Next(0, 0, 0, 0, 0);
  1693. if (hRes == WBEM_S_NO_MORE_DATA)
  1694. break;
  1695. nKeyCount++;
  1696. }
  1697. pObj->EndEnumeration();
  1698. CVARIANT v;
  1699. hRes = pObj->Get(L"__PROPERTY_COUNT", 0, &v, 0, 0);
  1700. if (FAILED(hRes) || v.GetType() != VT_I4)
  1701. return WBEM_E_FAILED;
  1702. if (V_I4(&v) == nKeyCount)
  1703. return WBEM_S_NO_ERROR;
  1704. return WBEM_E_FAILED;
  1705. }
  1706. //****************************************************************************
  1707. //
  1708. // CAssocQuery::FilterFowarder_NormalRefs
  1709. //
  1710. // Filtering and forwarding for REFERENCES OF queries.
  1711. // Handles normal queries and CLASSDEFSONLY queries; not used for
  1712. // SCHEMAONLY queries.
  1713. //
  1714. //****************************************************************************
  1715. // visual ok
  1716. HRESULT CAssocQuery::FilterForwarder_NormalRefs(
  1717. IN IWbemClassObject *pCandidate
  1718. )
  1719. {
  1720. BOOL bKeep = TRUE;
  1721. HRESULT hRes = 0;
  1722. if (pCandidate == 0)
  1723. return WBEM_E_INVALID_PARAMETER;
  1724. // All objects must be instances. We filter out any
  1725. // class definitions.
  1726. // ==================================================
  1727. CVARIANT vGenus;
  1728. pCandidate->Get(L"__GENUS", 0, &vGenus, 0, 0);
  1729. if (vGenus.GetType() == VT_I4 && LONG(vGenus) == 1)
  1730. return WBEM_S_NO_ERROR;
  1731. // The object must pass a security check.
  1732. // ======================================
  1733. hRes = AccessCheck((CWbemObject *) pCandidate);
  1734. if (FAILED(hRes)) return WBEM_S_NO_ERROR;
  1735. // RESULTCLASS test
  1736. // ================
  1737. LPCWSTR pszResultClass = m_Parser.GetResultClass();
  1738. if (pszResultClass)
  1739. {
  1740. hRes = St_ObjIsOfClass(pszResultClass, pCandidate);
  1741. if (FAILED(hRes))
  1742. bKeep = FALSE;
  1743. }
  1744. // Verify the association points to the endpoint and
  1745. // if so, get the role via which it does so.
  1746. // ==================================================
  1747. BSTR strRole = 0;
  1748. hRes = DoesAssocInstRefQueryEp(pCandidate,&strRole);
  1749. CSysFreeMe _1(strRole);
  1750. if (FAILED(hRes))
  1751. bKeep = FALSE;
  1752. // ROLE
  1753. LPCWSTR pszRole = m_Parser.GetRole();
  1754. if (pszRole && strRole)
  1755. {
  1756. if (wbem_wcsicmp(pszRole, strRole) != 0)
  1757. bKeep = FALSE;
  1758. }
  1759. // REQUIREDQUALIFIER test
  1760. LPCWSTR pszRequiredQual = m_Parser.GetRequiredQual();
  1761. if (pszRequiredQual)
  1762. {
  1763. hRes = St_ObjHasQualifier(pszRequiredQual, pCandidate);
  1764. if (FAILED(hRes))
  1765. bKeep = FALSE;
  1766. }
  1767. if (!bKeep)
  1768. return WBEM_S_NO_ERROR;
  1769. // If here, the object is a candidate. If the query type
  1770. // is not CLASSDEFSONLY, then we directly send it back.
  1771. // ======================================================
  1772. if ((m_Parser.GetQueryType() & QUERY_TYPE_CLASSDEFS_ONLY) == 0)
  1773. {
  1774. hRes = m_pDestSink->Indicate(1, &pCandidate);
  1775. return hRes;
  1776. }
  1777. IWbemClassObject *pRetCls = NULL;
  1778. {
  1779. CInCritSec ics(&m_csDeliveredAccess);
  1780. hRes = GetClassDefsOnlyClass(pCandidate, &pRetCls);
  1781. }
  1782. CReleaseMe rmRetClass(pRetCls);
  1783. // We may already have delivered the class in question,
  1784. // so we don't just assume there is a pointer here.
  1785. // ====================================================
  1786. if (SUCCEEDED(hRes) && pRetCls)
  1787. {
  1788. hRes = m_pDestSink->Indicate(1, &pRetCls);
  1789. }
  1790. if (FAILED(hRes))
  1791. return hRes;
  1792. return WBEM_S_OPERATION_CANCELLED;
  1793. }
  1794. //****************************************************************************
  1795. //
  1796. // CAssocQuery::FilterForwarder_NormalAssocs
  1797. //
  1798. // First level association instance filtering for ASSOCIATORS OF queries.
  1799. // Handles normal queries and CLASSDEFSONLY queries; not used for
  1800. // SCHEMAONLY queries.
  1801. //
  1802. //****************************************************************************
  1803. // visual ok
  1804. HRESULT CAssocQuery::FilterForwarder_NormalAssocs(
  1805. IN IWbemClassObject *pAssocInst
  1806. )
  1807. {
  1808. HRESULT hRes = 0;
  1809. BOOL bKeep = TRUE;
  1810. if (pAssocInst == 0)
  1811. return WBEM_E_INVALID_PARAMETER;
  1812. // All objects must be instances. We filter out any
  1813. // class definitions.
  1814. // ==================================================
  1815. CVARIANT vGenus;
  1816. pAssocInst->Get(L"__GENUS", 0, &vGenus, 0, 0);
  1817. if (vGenus.GetType() == VT_I4 && LONG(vGenus) == 1)
  1818. return WBEM_S_NO_ERROR;
  1819. // The object must pass a security check.
  1820. // ======================================
  1821. hRes = AccessCheck((CWbemObject *) pAssocInst);
  1822. if (FAILED(hRes))
  1823. return WBEM_S_NO_ERROR;
  1824. // ASSOCCLASS
  1825. // ==========
  1826. LPCWSTR pszAssocClass = m_Parser.GetAssocClass();
  1827. if (pszAssocClass)
  1828. {
  1829. hRes = St_ObjIsOfClass(pszAssocClass, pAssocInst);
  1830. if (FAILED(hRes))
  1831. bKeep = FALSE;
  1832. }
  1833. // REQUIREDASSOCQUALIFIER
  1834. // ======================
  1835. LPCWSTR pszRequiredAssocQual = m_Parser.GetRequiredAssocQual();
  1836. if (pszRequiredAssocQual)
  1837. {
  1838. hRes = St_ObjHasQualifier(pszRequiredAssocQual, pAssocInst);
  1839. if (FAILED(hRes))
  1840. bKeep = FALSE;
  1841. }
  1842. // ROLE
  1843. // ====
  1844. LPCWSTR pszRole = m_Parser.GetRole();
  1845. if (pszRole)
  1846. {
  1847. hRes = RoleTest(m_pEndpoint, pAssocInst, m_pNs, pszRole, ROLETEST_MODE_PATH_VALUE);
  1848. if (FAILED(hRes))
  1849. bKeep = FALSE;
  1850. }
  1851. // If we have already rejected the instance, just give up without going any further.
  1852. // =================================================================================
  1853. if (bKeep == FALSE)
  1854. return WBEM_S_NO_ERROR;
  1855. // If here, looks like we'll be in the business of actually getting
  1856. // the other endpoint. Other rejections are still possible based
  1857. // on RESULTROLE, however.
  1858. // ================================================================
  1859. // Get the Unknown Ep role.
  1860. // ========================
  1861. hRes = WBEM_S_NO_ERROR;
  1862. // By keeping track of the last property we enumed, we will be able to handle
  1863. // associations with multiple endpoints. (sanjes)
  1864. // ==========================================================================
  1865. BOOL bQueryEndpointFound = FALSE;
  1866. pAssocInst->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  1867. OnDeleteObj0<IWbemClassObject,
  1868. HRESULT(__stdcall IWbemClassObject:: *)(void),IWbemClassObject::EndEnumeration> EndMe(pAssocInst);
  1869. while (hRes == WBEM_S_NO_ERROR)
  1870. {
  1871. // Make sure these are reinitialized on each loop.
  1872. BSTR strUnkEpPath = 0, strUnkEpRole = 0;
  1873. bKeep = TRUE;
  1874. // Just keep passing in the last property we got
  1875. // ==============================================
  1876. hRes = GetUnknownEpRoleAndPath(pAssocInst, &bQueryEndpointFound, &strUnkEpRole, &strUnkEpPath );
  1877. auto_bstr rmUnkEpRole(strUnkEpRole);
  1878. auto_bstr rmUnkEpPath(strUnkEpPath);
  1879. if (FAILED(hRes)) return hRes;;
  1880. if (hRes == WBEM_S_NO_MORE_DATA) break;
  1881. // If we ran out of properties we should quit.
  1882. // ===========================================
  1883. if (SUCCEEDED(hRes))
  1884. {
  1885. // Verify the RESULTROLE.
  1886. // ======================
  1887. LPCWSTR pszResultRole = m_Parser.GetResultRole();
  1888. if (pszResultRole)
  1889. {
  1890. if (wbem_wcsicmp(pszResultRole, rmUnkEpRole.get()) != 0)
  1891. bKeep = FALSE;
  1892. }
  1893. // If here, we have the path of the unknown endpoint.
  1894. // We save it away in a protected array.
  1895. // ==================================================
  1896. if (bKeep)
  1897. hRes = AddEpCandidatePath(rmUnkEpPath.release()); // Acquires pointer
  1898. }
  1899. }
  1900. return WBEM_S_NO_ERROR;
  1901. }
  1902. //****************************************************************************
  1903. //
  1904. // CAssocQuery::AddEpCandidatePath
  1905. //
  1906. // Adds the path to a candidate endpoint. This is an intermediate
  1907. // step in an ASSOCIATORS OF query.
  1908. //
  1909. //****************************************************************************
  1910. // visual ok
  1911. HRESULT CAssocQuery::AddEpCandidatePath(
  1912. IN BSTR strOtherEp
  1913. )
  1914. {
  1915. CInCritSec ics(&m_csCandidateEpAccess);
  1916. if (CFlexArray::no_error != m_aEpCandidates.Add(strOtherEp))
  1917. {
  1918. SysFreeString(strOtherEp);
  1919. return WBEM_E_OUT_OF_MEMORY;
  1920. }
  1921. return WBEM_S_NO_ERROR;
  1922. }
  1923. //****************************************************************************
  1924. //
  1925. // CAssocQuery::EmptyCandidateEpArray
  1926. //
  1927. // Empties the Endpoint candidate array.
  1928. //
  1929. //****************************************************************************
  1930. // visual ok
  1931. void CAssocQuery::EmptyCandidateEpArray()
  1932. {
  1933. CInCritSec ics(&m_csCandidateEpAccess);
  1934. for (int i = 0; i < m_aEpCandidates.Size(); i++)
  1935. SysFreeString((BSTR) m_aEpCandidates[i]);
  1936. m_aEpCandidates.Empty();
  1937. }
  1938. //****************************************************************************
  1939. //
  1940. // CAssocQuery::PerformFinalEpTests
  1941. //
  1942. // Performs all final filter tests on the query endpoint.
  1943. //
  1944. // Returns
  1945. // WBEM_S_NO_ERROR if the object should be retained.
  1946. // WBEM_E_INVALID_OBJECT if the object should not be retained.
  1947. //
  1948. //****************************************************************************
  1949. //
  1950. HRESULT CAssocQuery::PerformFinalEpTests(
  1951. IWbemClassObject *pEp
  1952. )
  1953. {
  1954. BOOL bKeep = TRUE;
  1955. HRESULT hRes;
  1956. // Perform final tests. RESULTROLE
  1957. // was verified in the intermediate stage.
  1958. // =======================================
  1959. LPCWSTR pszResultClass = m_Parser.GetResultClass();
  1960. if (pszResultClass)
  1961. {
  1962. hRes = St_ObjIsOfClass(pszResultClass, pEp);
  1963. if (FAILED(hRes))
  1964. bKeep = FALSE;
  1965. }
  1966. // REQUIREDQUALIFIER test
  1967. // =======================
  1968. LPCWSTR pszRequiredQual = m_Parser.GetRequiredQual();
  1969. if (pszRequiredQual)
  1970. {
  1971. hRes = St_ObjHasQualifier(pszRequiredQual, pEp);
  1972. if (FAILED(hRes))
  1973. bKeep = FALSE;
  1974. }
  1975. if (bKeep)
  1976. return WBEM_S_NO_ERROR;
  1977. return WBEM_E_INVALID_OBJECT;
  1978. }
  1979. //****************************************************************************
  1980. //
  1981. // CAssocQuery::ResolvePathsToObjects
  1982. //
  1983. //****************************************************************************
  1984. //
  1985. HRESULT CAssocQuery::EpClassTest(
  1986. LPCWSTR pszResultClass,
  1987. LPCWSTR strClassName,
  1988. IWbemClassObject *pTestClass
  1989. )
  1990. {
  1991. HRESULT hRes;
  1992. if (pszResultClass == 0 || strClassName == 0 || pTestClass == 0)
  1993. return WBEM_E_INVALID_PARAMETER;
  1994. if (wbem_wcsicmp(pszResultClass, strClassName) == 0)
  1995. return WBEM_S_NO_ERROR;
  1996. // Check the derivation of the class and see if the result class is mentioned.
  1997. // ===========================================================================
  1998. CVARIANT v;
  1999. hRes = pTestClass->Get(L"__DERIVATION", 0,&v, 0, 0);
  2000. if (FAILED(hRes))
  2001. return hRes;
  2002. CSAFEARRAY sa((SAFEARRAY *) v);
  2003. v.Unbind();
  2004. int nNum = sa.GetNumElements();
  2005. for (int j = 0; j < nNum; j++)
  2006. {
  2007. BSTR bstrCls = 0;
  2008. if (FAILED(sa.Get(j, &bstrCls)))
  2009. return WBEM_E_OUT_OF_MEMORY;
  2010. CSysFreeMe _(bstrCls);
  2011. if (wbem_wcsicmp(bstrCls, pszResultClass) == 0)
  2012. return WBEM_S_NO_ERROR;
  2013. }
  2014. return WBEM_E_NOT_FOUND;
  2015. }
  2016. //****************************************************************************
  2017. //
  2018. // CAssocQuery::ResolvePathsToObjects
  2019. //
  2020. // Runs through the existing endpoints and gets the objects, passes them
  2021. // through the final tests sends them to to the caller.
  2022. //
  2023. // Autoassoc support can directly populate the m_aEpCandidates array.
  2024. //
  2025. // <nMaxToProcess> If -1, process all. Otherwise, only process
  2026. // as many as are requested.
  2027. //
  2028. //****************************************************************************
  2029. // visual ok
  2030. HRESULT CAssocQuery::ResolveEpPathsToObjects(
  2031. IN int nMaxToProcess
  2032. )
  2033. {
  2034. if (ConfigMgr::ShutdownInProgress())
  2035. return WBEM_E_SHUTTING_DOWN;
  2036. HRESULT hRes = WBEM_S_NO_ERROR;
  2037. IWbemClassObject *pEp = NULL;
  2038. // If the query type is CLASSDEFS only, reduce the Ep list
  2039. // to a list of class definitions.
  2040. // =======================================================
  2041. if (m_Parser.GetQueryType() & QUERY_TYPE_CLASSDEFS_ONLY)
  2042. ConvertEpListToClassDefsOnly();
  2043. // Determine how much of the ep list to process.
  2044. // =============================================
  2045. int nArraySize;
  2046. {
  2047. CInCritSec ics(&m_csCandidateEpAccess);
  2048. nArraySize = m_aEpCandidates.Size();
  2049. if (nMaxToProcess == -1 || nMaxToProcess > nArraySize)
  2050. nMaxToProcess = nArraySize;
  2051. }
  2052. // RESULTCLASS test
  2053. // ================
  2054. LPCWSTR pszResultClass = m_Parser.GetResultClass();
  2055. // Process each element in EP list.
  2056. // ================================
  2057. for (int i = 0; i < nMaxToProcess; i++)
  2058. {
  2059. pEp = 0;
  2060. // Extract one endpoint.
  2061. // =====================
  2062. BSTR strEpPath = NULL;
  2063. {
  2064. CInCritSec ics(&m_csCandidateEpAccess);
  2065. strEpPath = (BSTR) m_aEpCandidates[0];
  2066. m_aEpCandidates.RemoveAt(0);
  2067. }
  2068. CSysFreeMe _2(strEpPath);
  2069. // Do some analysis on the path.
  2070. // =============================
  2071. BSTR strClassName = 0;
  2072. BOOL bIsClass;
  2073. hRes = St_ObjPathInfo(strEpPath, &strClassName, &bIsClass);
  2074. if (FAILED(hRes))
  2075. {
  2076. hRes = 0;
  2077. continue;
  2078. }
  2079. BOOL bKeep = TRUE;
  2080. CSysFreeMe _1(strClassName);
  2081. // Important optimization: If RESULTCLASS is specified, look
  2082. // up the class definition before trying to get the endpoint
  2083. // just in case it can't pass the test.
  2084. // ==========================================================
  2085. if (pszResultClass)
  2086. {
  2087. // search for RESULTCLASS in derivation list of class from path
  2088. // if not search in derived classes from it
  2089. // Get the class and do a RESULTCLASS test to avoid
  2090. // getting the object.
  2091. // =================================================
  2092. IWbemClassObject *pTestClass;
  2093. hRes = GetClassFromAnywhere(strClassName, 0, &pTestClass);
  2094. if (FAILED(hRes))
  2095. {
  2096. DEBUGTRACE((LOG_WBEMCORE, "Association cannot find class <%S> hr = %08x\n",strClassName,hRes));
  2097. hRes = 0;
  2098. continue;
  2099. }
  2100. CReleaseMe _11(pTestClass);
  2101. // Make sure the endpoint class passes query tests.
  2102. // =================================================
  2103. hRes = EpClassTest(pszResultClass, strClassName, pTestClass);
  2104. if (FAILED(hRes))
  2105. {
  2106. IWbemClassObject *pTestResultClass;
  2107. hRes = GetClassFromAnywhere(pszResultClass, 0, &pTestResultClass);
  2108. if (FAILED(hRes))
  2109. {
  2110. DEBUGTRACE((LOG_WBEMCORE, "Association cannot find class <%S> hr %08x\n", pszResultClass, hRes));
  2111. hRes = 0;
  2112. continue;
  2113. }
  2114. CReleaseMe _111(pTestResultClass);
  2115. hRes = EpClassTest(strClassName, pszResultClass, pTestResultClass);
  2116. if (FAILED(hRes))
  2117. {
  2118. hRes = WBEM_S_NO_ERROR;
  2119. continue;
  2120. }
  2121. }
  2122. }
  2123. // If a class, use our high-speed class getter.
  2124. // ============================================
  2125. if (bIsClass)
  2126. {
  2127. // GetClassFromAnyWhere
  2128. hRes = GetClassFromAnywhere(strClassName, strEpPath, &pEp);
  2129. if (FAILED(hRes))
  2130. {
  2131. DEBUGTRACE((LOG_WBEMCORE, "Association cannot resolve dangling reference <%S> hr = %08x\n",strEpPath,hRes));
  2132. hRes = 0;
  2133. continue;
  2134. }
  2135. }
  2136. // Otherwise, an instance and we go the slow route.
  2137. // ================================================
  2138. else // An instance
  2139. {
  2140. IWbemClassObject* pErrorObj = NULL;
  2141. hRes = m_pNs->Exec_GetObjectByPath(
  2142. strEpPath,
  2143. 0, // Flags
  2144. m_pContext, // Context
  2145. &pEp, // Result obj
  2146. &pErrorObj // Error obj, if any
  2147. );
  2148. CReleaseMe _11(pErrorObj);
  2149. if (FAILED(hRes))
  2150. {
  2151. DEBUGTRACE((LOG_WBEMCORE, "Association cannot resolve reference <%S> hr = %08x\n",strEpPath,hRes));
  2152. hRes = 0;
  2153. continue;
  2154. }
  2155. }
  2156. // So, do we actually have an object, or are we fooling
  2157. // ourselves?
  2158. // =====================================================
  2159. if (!pEp)
  2160. {
  2161. hRes = 0;
  2162. continue;
  2163. }
  2164. // The object must pass a security check.
  2165. // ======================================
  2166. hRes = AccessCheck((CWbemObject *) pEp);
  2167. if (FAILED(hRes))
  2168. {
  2169. pEp->Release();
  2170. hRes = 0;
  2171. continue;
  2172. }
  2173. // If we are going to keep this, send it to the caller.
  2174. // ====================================================
  2175. hRes = PerformFinalEpTests(pEp);
  2176. if (SUCCEEDED(hRes))
  2177. hRes = m_pDestSink->Indicate(1, &pEp);
  2178. pEp->Release();
  2179. hRes = WBEM_S_NO_ERROR;
  2180. }
  2181. return hRes;
  2182. }
  2183. //****************************************************************************
  2184. //
  2185. // CAssocQuery::St_ObjPathPointsToClass
  2186. //
  2187. // Returns WBEM_S_NO_ERROR if the object path points to a class,
  2188. // or WBEM_E_FAILED if not. Can also return codes for invalid paths,
  2189. // out of memory, etc.
  2190. //
  2191. //****************************************************************************
  2192. //
  2193. HRESULT CAssocQuery::St_ObjPathInfo(
  2194. IN LPCWSTR pszPath,
  2195. OUT BSTR *pszClass,
  2196. OUT BOOL *pbIsClass
  2197. )
  2198. {
  2199. CObjectPathParser Parser;
  2200. ParsedObjectPath* pParsedPath = NULL;
  2201. if (pszPath == 0)
  2202. return WBEM_E_INVALID_PARAMETER;
  2203. int nRes = Parser.Parse(pszPath, &pParsedPath);
  2204. if (nRes != CObjectPathParser::NoError ||
  2205. pParsedPath->m_pClass == NULL)
  2206. {
  2207. // Fatal. Bad path in association.
  2208. return WBEM_E_INVALID_OBJECT_PATH;
  2209. }
  2210. if (pbIsClass)
  2211. {
  2212. if (pParsedPath->m_dwNumKeys == 0)
  2213. *pbIsClass = TRUE;
  2214. else
  2215. *pbIsClass = FALSE;
  2216. }
  2217. if (pszClass && pParsedPath->m_pClass)
  2218. *pszClass = SysAllocString(pParsedPath->m_pClass);
  2219. Parser.Free(pParsedPath);
  2220. return WBEM_S_NO_ERROR;
  2221. }
  2222. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2223. //
  2224. // END NORMAL QUERY SUPPORT
  2225. //
  2226. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2227. //***************************************************************************
  2228. //
  2229. //***************************************************************************
  2230. //
  2231. //***************************************************************************
  2232. //
  2233. // CAssocQuery::CanClassRefReachQueryEp
  2234. //
  2235. // Determines whether the property to which pQSet is bound can reach
  2236. // the query endpoint via a CLASSREF qualifier.
  2237. //
  2238. // <pQSet> bound to the property which supposedly references the query
  2239. // endpoint.
  2240. // <bStrict> If true, the reference must directly reference the query
  2241. // endpoint class, if FALSE it may reference any of the superclasses.
  2242. //
  2243. // Returns:
  2244. // WBEM_S_NO_ERROR if the reference occurs.
  2245. // WBEM_E_NOT_FOUND if the references does not occur.
  2246. //
  2247. //***************************************************************************
  2248. // visual ok
  2249. HRESULT CAssocQuery::CanClassRefReachQueryEp(
  2250. IWbemQualifierSet *pQSet,
  2251. BOOL bStrict
  2252. )
  2253. {
  2254. HRESULT hRes;
  2255. CVARIANT v;
  2256. hRes = pQSet->Get(L"CLASSREF", 0, &v, 0);
  2257. if (FAILED(hRes))
  2258. return WBEM_E_NOT_FOUND;
  2259. if (V_VT(&v) != (VT_BSTR | VT_ARRAY))
  2260. return WBEM_E_INVALID_OBJECT;
  2261. CSAFEARRAY sa((SAFEARRAY *) v);
  2262. v.Unbind();
  2263. int nNum = sa.GetNumElements();
  2264. // Iterate through the safearray.
  2265. // ==============================
  2266. for (int i = 0; i < nNum; i++)
  2267. {
  2268. BSTR bstrClass = 0;
  2269. if (FAILED(sa.Get(i, &bstrClass)))
  2270. return WBEM_E_OUT_OF_MEMORY;
  2271. if (bstrClass == 0)
  2272. continue;
  2273. CSysFreeMe _(bstrClass);
  2274. if (bStrict)
  2275. {
  2276. if (wbem_wcsicmp(bstrClass, m_bstrEndpointClass) == 0)
  2277. return WBEM_S_NO_ERROR;
  2278. }
  2279. else for (int i2 = 0; i2 < m_aEndpointHierarchy.Size(); i2++)
  2280. {
  2281. if (wbem_wcsicmp(bstrClass, m_aEndpointHierarchy[i2]) == 0)
  2282. return WBEM_S_NO_ERROR;
  2283. }
  2284. }
  2285. return WBEM_E_NOT_FOUND;
  2286. }
  2287. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2288. //
  2289. // BEGIN HELPER FUNCTIONS
  2290. //
  2291. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2292. //****************************************************************************
  2293. //
  2294. // CAssocQuery::St_GetObjectInfo
  2295. //
  2296. // Returns info about the object, such as its path, class, and
  2297. // class hierarchy.
  2298. //
  2299. //****************************************************************************
  2300. // ok
  2301. HRESULT CAssocQuery::St_GetObjectInfo(
  2302. IN IWbemClassObject *pObj,
  2303. OUT BSTR *pClass,
  2304. OUT BSTR *pRelpath,
  2305. OUT BSTR *pPath,
  2306. OUT CWStringArray &aHierarchy
  2307. )
  2308. {
  2309. HRESULT hRes;
  2310. int nRes;
  2311. CVARIANT v;
  2312. if (!pObj)
  2313. return WBEM_E_INVALID_PARAMETER;
  2314. // Get the owning class.
  2315. // =====================
  2316. hRes = pObj->Get(L"__CLASS", 0, &v, 0, 0);
  2317. if (FAILED(hRes))
  2318. return hRes;
  2319. if (V_VT(&v) != VT_BSTR)
  2320. return WBEM_E_INVALID_OBJECT;
  2321. nRes = aHierarchy.Add(LPWSTR(v));
  2322. if (nRes)
  2323. return WBEM_E_OUT_OF_MEMORY;
  2324. if (pClass)
  2325. {
  2326. *pClass = V_BSTR(&v);
  2327. v.Unbind();
  2328. }
  2329. v.Clear();
  2330. // Get the rel path.
  2331. // =================
  2332. if (pRelpath)
  2333. {
  2334. hRes = pObj->Get(L"__RELPATH", 0, &v, 0, 0);
  2335. if (FAILED(hRes)) return hRes;
  2336. if ( VT_BSTR != V_VT(&v)) return WBEM_E_INVALID_OBJECT;
  2337. *pRelpath = V_BSTR(&v);
  2338. v.Unbind();
  2339. }
  2340. v.Clear();
  2341. if (pPath)
  2342. {
  2343. hRes = pObj->Get(L"__PATH", 0, &v, 0, 0);
  2344. if (FAILED(hRes))
  2345. return hRes;
  2346. *pPath = V_BSTR(&v);
  2347. v.Unbind();
  2348. }
  2349. v.Clear();
  2350. // Get the superclasses.
  2351. // =====================
  2352. hRes = pObj->Get(L"__DERIVATION", 0,&v, 0, 0);
  2353. if (FAILED(hRes))
  2354. return hRes;
  2355. CSAFEARRAY sa((SAFEARRAY *) v);
  2356. v.Unbind();
  2357. int nNum = sa.GetNumElements();
  2358. for (int j = 0; j < nNum; j++)
  2359. {
  2360. BSTR bstrClass = 0;
  2361. nRes = sa.Get(j, &bstrClass);
  2362. if (FAILED(nRes))
  2363. return WBEM_E_OUT_OF_MEMORY;
  2364. CSysFreeMe _(bstrClass);
  2365. nRes = aHierarchy.Add(bstrClass);
  2366. if (nRes)
  2367. return WBEM_E_OUT_OF_MEMORY;
  2368. }
  2369. return WBEM_S_NO_ERROR;
  2370. }
  2371. //****************************************************************************
  2372. //
  2373. // CAssocQuery::GetUnknownEpRoleAndPath
  2374. //
  2375. // Given an association object (class or inst), returns the role and
  2376. // path which references the unknown endpoint.
  2377. //
  2378. // Calling code is responsible for calling BeginEnum/EndEnum
  2379. //
  2380. // All the OUT parameters are optional.
  2381. //
  2382. //****************************************************************************
  2383. //
  2384. HRESULT CAssocQuery::GetUnknownEpRoleAndPath(
  2385. IN IWbemClassObject *pAssoc,
  2386. IN BOOL *pFoundQueryEp,
  2387. OUT BSTR *pszRole,
  2388. OUT BSTR *pszUnkEpPath
  2389. )
  2390. {
  2391. HRESULT hRes = WBEM_E_FAILED;
  2392. if (pAssoc == 0)
  2393. return WBEM_E_INVALID_PARAMETER;
  2394. // Loop through the properties trying to find a legitimate
  2395. // reference to our endpoint class.
  2396. // =======================================================
  2397. // sanjes
  2398. // pAssoc->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  2399. while (1)
  2400. {
  2401. BSTR strPropName = 0;
  2402. hRes = pAssoc->Next(0, &strPropName, 0, 0, 0);
  2403. CSysFreeMe _1(strPropName);
  2404. if (hRes == WBEM_S_NO_MORE_DATA)
  2405. break;
  2406. hRes = RoleTest(m_pEndpoint, pAssoc, m_pNs, strPropName, ROLETEST_MODE_PATH_VALUE);
  2407. if (SUCCEEDED(hRes) && *pFoundQueryEp == FALSE) // The query ep
  2408. {
  2409. *pFoundQueryEp = TRUE;
  2410. continue;
  2411. }
  2412. // If here, we found the prop name which apparently references the
  2413. // other endpoint.
  2414. // ===============================================================
  2415. if (pszRole)
  2416. {
  2417. *pszRole = SysAllocString(strPropName);
  2418. if (NULL == *pszRole) return WBEM_E_OUT_OF_MEMORY;
  2419. }
  2420. CVARIANT vPath;
  2421. hRes = pAssoc->Get(strPropName, 0, &vPath, 0, 0);
  2422. if (FAILED(hRes) || vPath.GetType() != VT_BSTR)
  2423. break;
  2424. if (pszUnkEpPath)
  2425. {
  2426. *pszUnkEpPath = SysAllocString(vPath.GetStr());
  2427. if (NULL == *pszUnkEpPath) return WBEM_E_OUT_OF_MEMORY;
  2428. }
  2429. hRes = WBEM_S_NO_ERROR;
  2430. break;
  2431. }
  2432. // sanjes
  2433. // pAssoc->EndEnumeration();
  2434. return hRes; // Unexpected in real life
  2435. }
  2436. //****************************************************************************
  2437. //
  2438. // CAssocQuery::RoleTest
  2439. //
  2440. // Determines if the <pCandidate> object can point to the <pEndpoint> object
  2441. // via the specified <pszRole> property.
  2442. //
  2443. // Parameters:
  2444. // <pEndpoint> The test endpoint object
  2445. // <pCandidate> The association object which may point to the endpoint.
  2446. // <pszRole> The role to use for the test.
  2447. // <dwMode> One of the ROLETEST_MODE_ constants.
  2448. //
  2449. // Precisely,
  2450. //
  2451. // (1) ROLETEST_MODE_PATH_VALUE
  2452. // The candidate must reference the endpoint exactly via the specified
  2453. // role property, which must contain the path of the endpoint.
  2454. // Requirement: Both <pEndpoint> <pCandidate> can be anything.
  2455. //
  2456. // (2) ROLETEST_MODE_CIMREF_TYPE
  2457. // The role path is NULL and the CIM reference type is used to determine
  2458. // if the endpoint can be referenced. In this case, the CIM reference
  2459. // type must exactly reference the endpoint class.
  2460. // Requirement: Both <pEndpoint> and <pCandidate> are classes.
  2461. //
  2462. // Returns:
  2463. // WBEM_S_NO_ERROR
  2464. // WBEM_E_NOT_FOUND If the role cannot reference the endpoint.
  2465. // WBEM_E_INVALID_PARAMETER ...in most other cases.
  2466. //
  2467. //****************************************************************************
  2468. // visual ok
  2469. HRESULT CAssocQuery::RoleTest(
  2470. IN IWbemClassObject *pEndpoint,
  2471. IN IWbemClassObject *pCandidate,
  2472. IN CWbemNamespace *pNs,
  2473. IN LPCWSTR pszRole,
  2474. IN DWORD dwMode
  2475. )
  2476. {
  2477. HRESULT hRes;
  2478. CVARIANT v;
  2479. BOOL bEndpointIsClass, bCandidateIsClass;
  2480. if (!pszRole || !pEndpoint || !pCandidate)
  2481. return WBEM_E_INVALID_PARAMETER;
  2482. // Get the genus values of the endpoint & candidate.
  2483. // =================================================
  2484. pEndpoint->Get(L"__GENUS", 0, &v, 0, 0);
  2485. if (v.GetLONG() == 1)
  2486. bEndpointIsClass = TRUE;
  2487. else
  2488. bEndpointIsClass = FALSE;
  2489. v.Clear();
  2490. pCandidate->Get(L"__GENUS", 0, &v, 0, 0);
  2491. if (v.GetLONG() == 1)
  2492. bCandidateIsClass = TRUE;
  2493. else
  2494. bCandidateIsClass = FALSE;
  2495. v.Clear();
  2496. // Get the qualifier set for the specified <role> property.
  2497. // ========================================================
  2498. IWbemQualifierSet *pQSet = 0;
  2499. hRes = pCandidate->GetPropertyQualifierSet(pszRole, &pQSet);
  2500. if (FAILED(hRes))
  2501. return WBEM_E_NOT_FOUND;
  2502. CReleaseMe _1(pQSet);
  2503. // Now, get the type of the role.
  2504. // ==============================
  2505. CVARIANT vCimType;
  2506. hRes = pQSet->Get(L"CIMTYPE", 0, &vCimType, 0);
  2507. if (FAILED(hRes) || V_VT(&vCimType) != VT_BSTR)
  2508. return WBEM_E_FAILED;
  2509. // Get the class name from it.
  2510. // ===========================
  2511. wchar_t ClassName[MAX_CLASS_NAME];
  2512. *ClassName = 0;
  2513. BSTR strRefClass = V_BSTR(&vCimType);
  2514. if (strRefClass)
  2515. {
  2516. if (wcslen_max(strRefClass,MAX_CLASS_NAME) > MAX_CLASS_NAME) return WBEM_E_FAILED;
  2517. parse_REF(strRefClass,MAX_CLASS_NAME,ClassName);
  2518. }
  2519. // Once here, 'object ref' types will simply
  2520. // have a zero-length <ClassName> string.
  2521. // Determine which of the four cases we are executing.
  2522. // ===================================================
  2523. if (dwMode == ROLETEST_MODE_CIMREF_TYPE)
  2524. {
  2525. if (bCandidateIsClass == FALSE && bEndpointIsClass == FALSE)
  2526. return WBEM_E_INVALID_PARAMETER;
  2527. if (*ClassName == 0)
  2528. return WBEM_E_NOT_FOUND;
  2529. // See if the class name and the class of the object
  2530. // are the same.
  2531. // ==================================================
  2532. CVARIANT vCls;
  2533. HRESULT hResInner = pEndpoint->Get(L"__CLASS", 0, &vCls, 0, 0);
  2534. if (FAILED(hResInner))
  2535. return hResInner;
  2536. if (wbem_wcsicmp(ClassName, vCls.GetStr()) == 0)
  2537. return WBEM_S_NO_ERROR;
  2538. // Find out if the CIM type string points to the object.
  2539. // =====================================================
  2540. hRes = PathPointsToObj(ClassName, pEndpoint, pNs);
  2541. }
  2542. // The endpoint must be directly and exactly referenced
  2543. // by the role property's *value*.
  2544. // ====================================================
  2545. else if (dwMode == ROLETEST_MODE_PATH_VALUE)
  2546. {
  2547. // Get the value of the role property.
  2548. // ===================================
  2549. CVARIANT vRolePath;
  2550. hRes = pCandidate->Get(pszRole, 0, &vRolePath, 0, 0);
  2551. if (FAILED(hRes))
  2552. return WBEM_E_FAILED;
  2553. if (vRolePath.GetType() == VT_NULL)
  2554. return WBEM_E_NOT_FOUND;
  2555. hRes = PathPointsToObj(vRolePath.GetStr(), pEndpoint, pNs);
  2556. }
  2557. else
  2558. return WBEM_E_INVALID_PARAMETER;
  2559. return hRes;
  2560. }
  2561. //****************************************************************************
  2562. //
  2563. // CAssocQuery::St_ObjIsOfClass
  2564. //
  2565. // Determines if the specified object is of or derives from the specified
  2566. // class.
  2567. //
  2568. // Returns:
  2569. // WBEM_E_INVALID_CLASS if there is no match.
  2570. // WBEM_S_NO_ERROR if there is a match.
  2571. // WBEM_E_* on other failures
  2572. //
  2573. //****************************************************************************
  2574. // visual ok
  2575. HRESULT CAssocQuery::St_ObjIsOfClass(
  2576. IN LPCWSTR pszRequiredClass,
  2577. IN IWbemClassObject *pObj
  2578. )
  2579. {
  2580. if (pszRequiredClass == 0)
  2581. return WBEM_E_INVALID_PARAMETER;
  2582. HRESULT hRes;
  2583. CWStringArray aHierarchy;
  2584. hRes = St_GetObjectInfo(pObj, 0, 0, 0, aHierarchy);
  2585. if (FAILED(hRes))
  2586. return hRes;
  2587. for (int i = 0; i < aHierarchy.Size(); i++)
  2588. if (wbem_wcsicmp(pszRequiredClass, aHierarchy[i]) == 0)
  2589. return WBEM_S_NO_ERROR;
  2590. return WBEM_E_INVALID_CLASS;
  2591. }
  2592. //****************************************************************************
  2593. //
  2594. // CAssocQuery::PathPointsToObj
  2595. //
  2596. // Determines if a particular object path points to the specified object
  2597. // or not. Tries to avoid full object path parsing, if possible.
  2598. //
  2599. // Returns WBEM_S_NO_ERROR, WBEM_E_FAILED
  2600. //
  2601. //****************************************************************************
  2602. // ok
  2603. HRESULT CAssocQuery::PathPointsToObj(
  2604. IN LPCWSTR pszPath,
  2605. IN IWbemClassObject *pObj,
  2606. IN CWbemNamespace *pNs
  2607. )
  2608. {
  2609. HRESULT hRes;
  2610. if (pszPath == 0 || pObj == 0)
  2611. return WBEM_E_INVALID_PARAMETER;
  2612. // Test for simple equality of __RELPATH.
  2613. // ======================================
  2614. CVARIANT vRel;
  2615. hRes = pObj->Get(L"__RELPATH", 0, &vRel, 0, 0);
  2616. if (FAILED(hRes) || VT_BSTR != V_VT(&vRel))
  2617. return WBEM_E_FAILED;
  2618. if (wbem_wcsicmp(pszPath, V_BSTR(&vRel)) == 0)
  2619. return WBEM_S_NO_ERROR;
  2620. // Test for simple equality of __PATH.
  2621. // ===================================
  2622. CVARIANT vFullPath;
  2623. hRes = pObj->Get(L"__PATH", 0, &vFullPath, 0, 0);
  2624. if (FAILED(hRes) || VT_BSTR != V_VT(&vRel))
  2625. return WBEM_E_FAILED;
  2626. if (wbem_wcsicmp(pszPath, V_BSTR(&vFullPath)) == 0)
  2627. return WBEM_S_NO_ERROR;
  2628. // If here, we have to actually parse the object paths
  2629. // in question.
  2630. // ===================================================
  2631. LPWSTR pszNormalizedPath = CQueryEngine::NormalizePath(pszPath, pNs);
  2632. LPWSTR pszNormalizedTargetPath = CQueryEngine::NormalizePath(vFullPath.GetStr(), pNs);
  2633. CDeleteMe <wchar_t> _1(pszNormalizedPath);
  2634. CDeleteMe <wchar_t> _2(pszNormalizedTargetPath);
  2635. if (pszNormalizedPath && pszNormalizedTargetPath)
  2636. if (wbem_wcsicmp(pszNormalizedPath, pszNormalizedTargetPath) == 0)
  2637. return WBEM_S_NO_ERROR;
  2638. return WBEM_E_FAILED;
  2639. }
  2640. //***************************************************************************
  2641. //
  2642. // CAssocQualifierL::St_ObjHasQualifier
  2643. //
  2644. // Determines if an object has a particular qualifier. Used for
  2645. // REQUIREDQUALIFIER or REQUIREDASSOCQUALIFIER tests. The qualifier
  2646. // must be present and not be VARIANT_FALSE.
  2647. // Returns WBEM_S_NO_ERROR if the object has the qualifier.
  2648. // Returns an WBEM_E_ error code otherwise.
  2649. //
  2650. //***************************************************************************
  2651. // visual ok
  2652. HRESULT CAssocQuery::St_ObjHasQualifier(
  2653. IN LPCWSTR pszQualName,
  2654. IN IWbemClassObject *pObj
  2655. )
  2656. {
  2657. if (pszQualName == 0 || wcslen(pszQualName) == 0 || pObj == 0)
  2658. return WBEM_E_INVALID_PARAMETER;
  2659. IWbemQualifierSet *pQSet = 0;
  2660. HRESULT hRes = pObj->GetQualifierSet(&pQSet);
  2661. if (FAILED(hRes))
  2662. return WBEM_E_FAILED;
  2663. CReleaseMe _1(pQSet);
  2664. CVARIANT v;
  2665. hRes = pQSet->Get(pszQualName, 0, &v, 0);
  2666. if (SUCCEEDED(hRes))
  2667. {
  2668. if (V_VT(&v) == VT_BOOL && V_BOOL(&v) == VARIANT_FALSE)
  2669. return WBEM_E_FAILED;
  2670. return WBEM_S_NO_ERROR;
  2671. }
  2672. return WBEM_E_FAILED;
  2673. }
  2674. //***************************************************************************
  2675. //
  2676. // CAssocQuery::St_ReleaseArray
  2677. //
  2678. //***************************************************************************
  2679. // visual ok
  2680. HRESULT CAssocQuery::St_ReleaseArray(
  2681. IN CFlexArray &aObjects
  2682. )
  2683. {
  2684. // Release all the objects.
  2685. // ========================
  2686. for (int i = 0; i < aObjects.Size(); i++)
  2687. {
  2688. IWbemClassObject *p = (IWbemClassObject *) aObjects[i];
  2689. p->Release();
  2690. }
  2691. return WBEM_S_NO_ERROR;
  2692. }
  2693. //****************************************************************************
  2694. //
  2695. // CAssocQuery::Db_GetClass
  2696. //
  2697. // DB abstraction layer. Will make it easier to plug in Quasar engine.
  2698. //
  2699. //****************************************************************************
  2700. // ok
  2701. HRESULT CAssocQuery::Db_GetClass(
  2702. IN LPCWSTR pszClassName,
  2703. OUT IWbemClassObject **pClass
  2704. )
  2705. {
  2706. HRESULT hRes = CRepository::GetObject(
  2707. m_pNs->GetNsSession(),
  2708. m_pNs->GetScope(),
  2709. pszClassName,
  2710. 0,
  2711. pClass
  2712. );
  2713. return hRes;
  2714. }
  2715. //****************************************************************************
  2716. //
  2717. // CAssocQuery::Db_GetInstRefs
  2718. //
  2719. // DB abstraction layer. Will make it easier to plug in Quasar engine.
  2720. //
  2721. //****************************************************************************
  2722. //
  2723. HRESULT CAssocQuery::Db_GetInstRefs(
  2724. IN LPCWSTR pszTargetObj,
  2725. IN IWbemObjectSink *pSink
  2726. )
  2727. {
  2728. HRESULT hRes = CRepository::GetInstanceRefs(
  2729. m_pNs->GetNsSession(),
  2730. m_pNs->GetScope(),
  2731. pszTargetObj,
  2732. pSink
  2733. );
  2734. return hRes;
  2735. }
  2736. //****************************************************************************
  2737. //
  2738. // CAssocQuery::Db_GetClass
  2739. //
  2740. // DB abstraction layer. Will make it easier to plug in Quasar engine.
  2741. //
  2742. //****************************************************************************
  2743. // ok
  2744. HRESULT CAssocQuery::Db_GetRefClasses(
  2745. IN LPCWSTR pszClass,
  2746. OUT CWStringArray &aRefClasses
  2747. )
  2748. {
  2749. HRESULT hRes = CRepository::GetRefClasses(
  2750. m_pNs->GetNsSession(),
  2751. m_pNs->GetNsHandle(),
  2752. pszClass,
  2753. FALSE,
  2754. aRefClasses
  2755. );
  2756. return hRes;
  2757. }
  2758. //***************************************************************************
  2759. //
  2760. // CAssocQuery::Db_GetClassRefClasses
  2761. //
  2762. // Gets all classes with HasClassRefs qualifiers.
  2763. //
  2764. //***************************************************************************
  2765. //
  2766. HRESULT CAssocQuery::Db_GetClassRefClasses(
  2767. IN CFlexArray &aDest
  2768. )
  2769. {
  2770. HRESULT hRes;
  2771. CSynchronousSink* pRefClassSink = CSynchronousSink::Create();
  2772. if (NULL == pRefClassSink) return WBEM_E_OUT_OF_MEMORY;
  2773. pRefClassSink->AddRef();
  2774. CReleaseMe _1(pRefClassSink);
  2775. hRes = CRepository::GetClassesWithRefs(m_pNs->GetNsSession(),m_pNs->GetNsHandle(),pRefClassSink);
  2776. if (FAILED(hRes)) return hRes;
  2777. pRefClassSink->GetStatus(&hRes, NULL, NULL);
  2778. if (FAILED(hRes)) return hRes;
  2779. aDest.Bind(pRefClassSink->GetObjects().GetArray());
  2780. return WBEM_S_NO_ERROR;
  2781. }
  2782. //***************************************************************************
  2783. //
  2784. // CAssocQuery::GetClassFromAnywhere
  2785. //
  2786. // Tries to get a class definition from anywhere as fast as possible.
  2787. // We do this by the following algorithm in a hope to achieve best
  2788. // performance:
  2789. //
  2790. // (1) Search the dynamic class cache
  2791. // (2) Call the database directly for this namespace
  2792. // (3) Call Exec_GetObjectByPath (hoping that an unrelated dyn class
  2793. // provider has the class)
  2794. //
  2795. //***************************************************************************
  2796. // visual ok
  2797. HRESULT CAssocQuery::GetClassFromAnywhere(
  2798. IN LPCWSTR pszEpClassName,
  2799. IN LPCWSTR pszFullClassPath,
  2800. OUT IWbemClassObject **pCls
  2801. )
  2802. {
  2803. HRESULT hRes;
  2804. // Try to find the class in the dynamic class cache.
  2805. // We will only look for classes in our own namespace, however.
  2806. // ============================================================
  2807. hRes = GetDynClass(pszEpClassName, pCls);
  2808. if (SUCCEEDED(hRes))
  2809. return hRes;
  2810. // If here, no luck in the dynamic class cache. Try
  2811. // the repository. We try to use the full path to support
  2812. // the limited cross-namespace support required by
  2813. // SNMP SMIR, etc.
  2814. // ========================================================
  2815. if (pszFullClassPath == 0)
  2816. pszFullClassPath = pszEpClassName;
  2817. hRes = Db_GetClass(pszFullClassPath, pCls);
  2818. if (SUCCEEDED(hRes))
  2819. return hRes;
  2820. // If here, our hopes are nearly dashed. One last chance
  2821. // that a dyn class provider may have it if the
  2822. // class was supplied by a provider other than the
  2823. // one which supplied the association class.
  2824. // =====================================================
  2825. IWbemClassObject* pErrorObj = NULL;
  2826. hRes = m_pNs->Exec_GetObjectByPath(
  2827. (LPWSTR) pszFullClassPath, // Class name
  2828. 0, // Flags
  2829. m_pContext, // Context
  2830. pCls, // Result obj
  2831. &pErrorObj // Error obj, if any
  2832. );
  2833. CReleaseMe _1(pErrorObj);
  2834. // If we found it, great.
  2835. // ======================
  2836. if (SUCCEEDED(hRes))
  2837. return hRes;
  2838. return WBEM_E_NOT_FOUND;
  2839. }
  2840. //***************************************************************************
  2841. //
  2842. // CAssocQuery::St_HasClassRefs
  2843. //
  2844. // Determines if a class has a <HasClassRefs> qualifier.
  2845. //
  2846. // Parameters
  2847. // <pCandidate> Points to the object to be tested (read-only).
  2848. //
  2849. // Return value:
  2850. // WBEM_S_NO_ERROR If the class has a <HasClassRefs> qualifier.
  2851. // WBEM_E_NOT_FOUND If the class doesn't have the qualifier.
  2852. // ...other codes
  2853. //
  2854. //***************************************************************************
  2855. // visual ok
  2856. HRESULT CAssocQuery::St_HasClassRefs(
  2857. IN IWbemClassObject *pCandidate
  2858. )
  2859. {
  2860. if (pCandidate == 0)
  2861. return WBEM_E_INVALID_PARAMETER;
  2862. HRESULT hRes = St_ObjHasQualifier(L"HasClassRefs", pCandidate);
  2863. if (SUCCEEDED(hRes))
  2864. return WBEM_S_NO_ERROR;
  2865. return WBEM_E_NOT_FOUND;
  2866. }
  2867. //***************************************************************************
  2868. //
  2869. // CAssocQuery::AccessCheck
  2870. //
  2871. // Does a security check on a static object to make sure that the user
  2872. // should see it.
  2873. //
  2874. // If the object is in the current namespace anyway, we short-circuit
  2875. // and allow it without a lot of hassle. The guy is obviously one of us
  2876. // and should be allowed to proceed unhindered. In those weird cases where
  2877. // the object was from a foreign namespace, we have to play INS and check
  2878. // on him.
  2879. //
  2880. //***************************************************************************
  2881. HRESULT CAssocQuery::AccessCheck(
  2882. IWbemClassObject *pSrc
  2883. )
  2884. {
  2885. if (pSrc == 0)
  2886. return WBEM_E_INVALID_PARAMETER;
  2887. CWbemObject *pObj = (CWbemObject *) pSrc;
  2888. // Easy case is 9x box where user is cleared for everything
  2889. // ========================================================
  2890. if((m_pNs->GetSecurityFlags() & SecFlagWin9XLocal) != 0)
  2891. return WBEM_S_NO_ERROR;
  2892. // Short-circuit case: We get the __NAMESPACE and see if it
  2893. // the same as the NS in which we are executing the query.
  2894. // ========================================================
  2895. try // native interfaces throws
  2896. {
  2897. LPWSTR pszNamespace = m_pNs->GetName();
  2898. CVar vNs, vServer;
  2899. if (FAILED(pObj->GetProperty(L"__NAMESPACE" , &vNs)) ||vNs.IsNull())
  2900. return WBEM_E_INVALID_OBJECT;
  2901. if (FAILED(pObj->GetProperty(L"__SERVER", &vServer)) || vServer.IsNull())
  2902. return WBEM_E_INVALID_OBJECT;
  2903. // If server name and namespace are the same, we are already implicitly
  2904. // allowed to see the object.
  2905. // ====================================================================
  2906. if (wbem_wcsicmp(LPWSTR(vNs), pszNamespace) == 0 &&
  2907. wbem_wcsicmp(LPWSTR(vServer), ConfigMgr::GetMachineName()) == 0)
  2908. return WBEM_S_NO_ERROR;
  2909. }
  2910. catch (CX_MemoryException &)
  2911. {
  2912. return WBEM_E_OUT_OF_MEMORY;
  2913. }
  2914. catch (CX_Exception &)
  2915. {
  2916. return WBEM_E_CRITICAL_ERROR;
  2917. }
  2918. // If here, we have to do a real check.
  2919. // ====================================
  2920. HRESULT hRes = WBEM_S_NO_ERROR;
  2921. BOOL bRet = TRUE;
  2922. CVar vProp;
  2923. if (FAILED(pObj->GetProperty(L"__Path" , &vProp)) || vProp.IsNull())
  2924. return WBEM_E_INVALID_OBJECT;
  2925. // Parse the object path to get the class involved.
  2926. // ================================================
  2927. CObjectPathParser p;
  2928. ParsedObjectPath* pOutput = 0;
  2929. int nStatus = p.Parse(vProp.GetLPWSTR(), &pOutput);
  2930. if (CObjectPathParser:: NoError != nStatus) return WBEM_E_OUT_OF_MEMORY;
  2931. OnDeleteObj<ParsedObjectPath*,CObjectPathParser,
  2932. void (CObjectPathParser:: *)(ParsedObjectPath *),
  2933. &CObjectPathParser::Free> FreeMe(&p,pOutput);
  2934. if (pOutput->IsLocal(ConfigMgr::GetMachineName()))
  2935. {
  2936. LPWSTR wszNewNamespace = pOutput->GetNamespacePart();
  2937. CDeleteMe<WCHAR> dm1(wszNewNamespace);
  2938. if (NULL == wszNewNamespace) return WBEM_E_OUT_OF_MEMORY;
  2939. if (wbem_wcsicmp(wszNewNamespace, m_pNs->GetName()))
  2940. {
  2941. CWbemNamespace* pNewLocal = CWbemNamespace::CreateInstance();
  2942. if (NULL == pNewLocal) return WBEM_E_OUT_OF_MEMORY;
  2943. CReleaseMe rmNS((IWbemServices *)pNewLocal);
  2944. hRes = pNewLocal->Initialize(wszNewNamespace,
  2945. m_pNs->GetUserName(),
  2946. 0, 0, m_pNs->IsForClient(),
  2947. TRUE,
  2948. m_pNs->GetClientMachine(),
  2949. m_pNs->GetClientProcID(),
  2950. FALSE, NULL);
  2951. if (SUCCEEDED(hRes))
  2952. {
  2953. DWORD dwAccess = pNewLocal->GetUserAccess();
  2954. if ((dwAccess & WBEM_ENABLE) == 0)
  2955. hRes = WBEM_E_ACCESS_DENIED;;
  2956. }
  2957. }
  2958. }
  2959. return hRes;
  2960. }
  2961. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2962. //
  2963. // END HELPER FUNCTIONS
  2964. //
  2965. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2966. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2967. //
  2968. // BEGIN SINK CODE
  2969. //
  2970. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  2971. //***************************************************************************
  2972. //
  2973. // CAssocQuery::CreateSink
  2974. //
  2975. // Creates a sink which is bound this the current query.
  2976. //
  2977. //***************************************************************************
  2978. //
  2979. CObjectSink *CAssocQuery::CreateSink(
  2980. PF_FilterForwarder pfnFilter,
  2981. BSTR strTrackingQuery
  2982. )
  2983. {
  2984. CAssocQE_Sink *p = new CAssocQE_Sink(this, pfnFilter, strTrackingQuery);
  2985. if (p) p->AddRef();
  2986. return p;
  2987. }
  2988. //***************************************************************************
  2989. //
  2990. // CAssocQE_Sink::CAssocQE_Sink
  2991. //
  2992. //***************************************************************************
  2993. //
  2994. CAssocQE_Sink::CAssocQE_Sink(
  2995. CAssocQuery *pQuery,
  2996. PF_FilterForwarder pFilter,
  2997. BSTR strTrackingQuery
  2998. )
  2999. : CObjectSink(0) // Starting ref count
  3000. {
  3001. m_pQuery = pQuery;
  3002. m_pQuery->AddRef();
  3003. m_pfnFilter = pFilter;
  3004. m_lRef = 0;
  3005. m_bQECanceled = FALSE;
  3006. m_bOriginalOpCanceled = FALSE;
  3007. InterlockedIncrement(&m_pQuery->m_lActiveSinks);
  3008. if (strTrackingQuery)
  3009. m_strQuery = SysAllocString(strTrackingQuery);
  3010. }
  3011. //***************************************************************************
  3012. //
  3013. // CAssocQE_Sink::~CAssocQE_Sink
  3014. //
  3015. //***************************************************************************
  3016. // ok
  3017. CAssocQE_Sink::~CAssocQE_Sink()
  3018. {
  3019. InterlockedDecrement(&m_pQuery->m_lActiveSinks);
  3020. m_pQuery->SignalSinkDone();
  3021. m_pQuery->Release();
  3022. SysFreeString(m_strQuery);
  3023. }
  3024. //***************************************************************************
  3025. //
  3026. // CAssocQE_Sink::Indicate
  3027. //
  3028. //***************************************************************************
  3029. // ok
  3030. STDMETHODIMP CAssocQE_Sink::Indicate(
  3031. IN long lNumObjects,
  3032. IN IWbemClassObject** apObj
  3033. )
  3034. {
  3035. HRESULT hRes = WBEM_S_NO_ERROR;
  3036. if (ConfigMgr::ShutdownInProgress())
  3037. return WBEM_E_SHUTTING_DOWN;
  3038. // Short-circuit a cancelled sink.
  3039. // ===============================
  3040. if (m_bQECanceled)
  3041. {
  3042. return hRes;
  3043. }
  3044. for (int i = 0; i < lNumObjects; i++)
  3045. {
  3046. IWbemClassObject *pCandidate = apObj[i];
  3047. if (m_pfnFilter)
  3048. {
  3049. // Call the filter & forward function bound to this
  3050. // sink instance.
  3051. hRes = (m_pQuery->*m_pfnFilter)(pCandidate);
  3052. // Check for out-and-out failure.
  3053. // ==============================
  3054. if (FAILED(hRes))
  3055. {
  3056. m_bQECanceled = TRUE;
  3057. m_pQuery->Cancel();
  3058. break;
  3059. }
  3060. // If we are simply cancelling this one sink due to efficiency
  3061. // reasons, then tell just the provider to cancel, but not the
  3062. // whole query.
  3063. // ============================================================
  3064. if (hRes == WBEM_S_OPERATION_CANCELLED)
  3065. {
  3066. m_bQECanceled = TRUE;
  3067. hRes = WBEM_E_CALL_CANCELLED;
  3068. break;
  3069. }
  3070. }
  3071. }
  3072. m_pQuery->UpdateTime();
  3073. return hRes;
  3074. }
  3075. HRESULT CAssocQE_Sink::Add(IWbemClassObject* pObj)
  3076. {
  3077. return Indicate(1, &pObj);
  3078. }
  3079. //***************************************************************************
  3080. //
  3081. // CAssocQE_Sink::SetStatus
  3082. //
  3083. //***************************************************************************
  3084. //
  3085. STDMETHODIMP CAssocQE_Sink::SetStatus(
  3086. long lFlags,
  3087. long lParam,
  3088. BSTR strParam,
  3089. IWbemClassObject* pObjParam
  3090. )
  3091. {
  3092. m_pQuery->UpdateTime();
  3093. m_pQuery->SignalSinkDone();
  3094. if (FAILED(lParam))
  3095. {
  3096. // TBD report provider error; cancel query
  3097. }
  3098. return WBEM_S_NO_ERROR;
  3099. };
  3100. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3101. //
  3102. // END SINK CODE
  3103. //
  3104. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3105. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3106. //
  3107. // BEGIN CLASSDEFSONLY CODE
  3108. //
  3109. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3110. //***************************************************************************
  3111. //
  3112. // GetClassDefsOnlyClass
  3113. //
  3114. // This takes an association instance, and looks up its class definition.
  3115. // It looks up the parent-most class possible which is non-abstract
  3116. // and instantiable. This class is already in the master class list.
  3117. //
  3118. // It then tags the roles on that class definition with IN or OUT depending
  3119. // on which property actually references the endpoint and which ones do
  3120. // not.
  3121. //
  3122. // Second, it does 'hypothetical' tagging, where the OUT roles are each
  3123. // given an independent pass to see if they *could* reference the
  3124. // query endpoint, and the IN role is examined to see if it could
  3125. // in turn reference the unknowns.
  3126. //
  3127. // Returns
  3128. // WBEM_E_INVALID_OBJECT if the association cannot point to
  3129. // the endpoint in the current query.
  3130. //
  3131. // WBEM_S_NO_ERROR is returned if IN/OUT tagging was properly
  3132. // achieved.
  3133. //
  3134. // WBEM_E_* on other conditions, which indicate drastic failure, such
  3135. // as out-of-memory.
  3136. //
  3137. //***************************************************************************
  3138. //
  3139. HRESULT CAssocQuery::GetClassDefsOnlyClass(
  3140. IN IWbemClassObject *pExample,
  3141. OUT IWbemClassObject **pClass
  3142. )
  3143. {
  3144. if (!pExample || !pClass) return WBEM_E_INVALID_PARAMETER;
  3145. *pClass = 0;
  3146. // Get the class that we need.
  3147. // ===========================
  3148. HRESULT hRes;
  3149. IWbemClassObject *pCandidate = 0;
  3150. hRes = FindParentmostClass(pExample, &pCandidate);
  3151. if (FAILED(hRes)) return hRes;
  3152. CReleaseMe _(pCandidate);
  3153. _variant_t vClassName;
  3154. hRes = pCandidate->Get(L"__CLASS", 0, &vClassName, 0, 0);
  3155. if (FAILED(hRes) || V_VT(&vClassName) != VT_BSTR) return WBEM_E_FAILED;
  3156. // If the class has already been delivered, just quit now.
  3157. // =======================================================
  3158. for (int i = 0; i < m_aDeliveredClasses.Size(); i++)
  3159. {
  3160. if (wbem_wcsicmp(m_aDeliveredClasses[i], V_BSTR(&vClassName)) == 0)
  3161. return WBEM_S_NO_ERROR;
  3162. }
  3163. // If here, it's a new class. Make a copy that we can modify
  3164. // and send back to the user.
  3165. // ==========================================================
  3166. IWbemClassObject *pCopy = 0;
  3167. hRes = pCandidate->Clone(&pCopy);
  3168. if (FAILED(hRes)) return hRes;
  3169. CReleaseMe rmCopy(pCopy);
  3170. hRes = ComputeInOutTags(pExample, pCopy);
  3171. if (FAILED(hRes)) return hRes;
  3172. // Add the class name to the 'delivered' list.
  3173. // ===========================================
  3174. if (CFlexArray::no_error != m_aDeliveredClasses.Add(V_BSTR(&vClassName)))
  3175. return WBEM_E_OUT_OF_MEMORY;
  3176. // Send it back. The additional AddRef is because of the
  3177. // CReleaseMe binding.
  3178. // ======================================================
  3179. *pClass = (IWbemClassObject *)rmCopy.dismiss();
  3180. return WBEM_S_NO_ERROR;
  3181. }
  3182. //***************************************************************************
  3183. //
  3184. // CAssocQuery::TagProp
  3185. //
  3186. // Tags a property in an object with the named qualifier. Used to
  3187. // add IN or OUT to class definitions when executing CLASSDEFSONLY queries.
  3188. //
  3189. //***************************************************************************
  3190. //
  3191. HRESULT CAssocQuery::TagProp(
  3192. IN IWbemClassObject *pObjToTag,
  3193. IN LPCWSTR pszPropName,
  3194. IN LPCWSTR pszInOutTag
  3195. )
  3196. {
  3197. IWbemQualifierSet *pQSet = 0;
  3198. HRESULT hRes = pObjToTag->GetPropertyQualifierSet(pszPropName, &pQSet);
  3199. if (FAILED(hRes))
  3200. return hRes;
  3201. CReleaseMe _1(pQSet);
  3202. CVARIANT v;
  3203. v.SetBool(TRUE);
  3204. pQSet->Put(pszInOutTag, &v, 0);
  3205. return WBEM_S_NO_ERROR;
  3206. }
  3207. //***************************************************************************
  3208. //
  3209. // CAssocQuery::ComputeInOutTags
  3210. //
  3211. // Computes the IN/OUT tags on a class using the specified association
  3212. // instance.
  3213. //
  3214. // Does not deliver the instance to the sink.
  3215. //
  3216. //***************************************************************************
  3217. // ok
  3218. HRESULT CAssocQuery::ComputeInOutTags(
  3219. IN IWbemClassObject *pAssocInst,
  3220. IN IWbemClassObject *pClass
  3221. )
  3222. {
  3223. HRESULT hRes;
  3224. if (pAssocInst == 0 || pClass == 0)
  3225. return WBEM_E_INVALID_PARAMETER;
  3226. try
  3227. {
  3228. // Loop through the properties trying to find a legitimate
  3229. // reference to our endpoint class.
  3230. // =======================================================
  3231. pAssocInst->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  3232. while (1)
  3233. {
  3234. BSTR strPropName = 0;
  3235. hRes = pAssocInst->Next(0,&strPropName,0,0,0);
  3236. CSysFreeMe _1(strPropName);
  3237. if (hRes == WBEM_S_NO_MORE_DATA)
  3238. break;
  3239. hRes = RoleTest(m_pEndpoint, pAssocInst, m_pNs, strPropName, ROLETEST_MODE_PATH_VALUE);
  3240. if (SUCCEEDED(hRes))
  3241. {
  3242. TagProp(pClass, strPropName, L"IN");
  3243. }
  3244. else
  3245. TagProp(pClass, strPropName, L"OUT");
  3246. } // Enum of ref properties
  3247. pAssocInst->EndEnumeration();
  3248. // Try to infer additional IN/OUT flows by examining the
  3249. // class itself. Some of these are only possible, rather
  3250. // the definite. Note that if more than one property
  3251. // has IN flow, {P1=IN, P2=IN, P3=OUT } then by implication each
  3252. // of P1 and P2 can also be OUT, since when one of (P1,P2) is IN
  3253. // the other must be OUT unless there are two refecences to
  3254. // the same object. Obviously, this entire mechanism is weak
  3255. // theoretically. It is only there for the CIM Object Browser
  3256. // to have some good idea that there are 'probably' instances
  3257. // for that particular association.
  3258. // =============================================================
  3259. CWStringArray aClassInProps;
  3260. hRes = CanClassRefQueryEp(FALSE, pClass, &aClassInProps);
  3261. for (int i = 0; i < aClassInProps.Size(); i++)
  3262. {
  3263. TagProp(pClass, aClassInProps[i], L"IN");
  3264. for (int i2 = 0; i2 < aClassInProps.Size(); i2++)
  3265. {
  3266. // Tag all the others as OUTs as well.
  3267. if (wbem_wcsicmp(aClassInProps[i2], aClassInProps[i]) != 0)
  3268. {
  3269. TagProp(pClass, aClassInProps[i], L"OUT");
  3270. }
  3271. }
  3272. }
  3273. }
  3274. catch (CX_MemoryException &) // WString throws
  3275. {
  3276. return WBEM_E_FAILED;
  3277. }
  3278. return WBEM_S_NO_ERROR;
  3279. }
  3280. //***************************************************************************
  3281. //
  3282. // CAssocQuery::FindParentMostClass
  3283. //
  3284. // Finds the parent-most class definition object which is still a 'real'
  3285. // class, of the class name specified. Given {A,B:A,C:B,D:C}, all of
  3286. // which are instantiable, finds 'A' if 'D' is specified in the <pszClass>
  3287. // parameter.
  3288. //
  3289. // Note that the master class list only contains classes from the
  3290. // dynamic portion of the database. Thus, if the association is a static
  3291. // type, we simply look up the first non-abstract class in the repository.
  3292. //
  3293. //***************************************************************************
  3294. //
  3295. HRESULT CAssocQuery::FindParentmostClass(
  3296. IN IWbemClassObject *pAssocInst,
  3297. OUT IWbemClassObject **pClassDef
  3298. )
  3299. {
  3300. HRESULT hRes;
  3301. int i;
  3302. if (pAssocInst == 0 || pClassDef == 0)
  3303. return WBEM_E_INVALID_PARAMETER;
  3304. *pClassDef = 0;
  3305. // Get the class hierarchy of the object.
  3306. // ======================================
  3307. CWStringArray aHierarchy;
  3308. hRes = St_GetObjectInfo(
  3309. pAssocInst,
  3310. 0, 0, 0,
  3311. aHierarchy
  3312. );
  3313. if (FAILED(hRes))
  3314. return hRes;
  3315. IWbemClassObject *pTarget = 0;
  3316. // Traverse the hierarchy, looking for the class def.
  3317. // ==================================================
  3318. for (i = aHierarchy.Size() - 1; i >= 0; i--)
  3319. {
  3320. for (int i2 = 0; i2 < m_aMaster.Size(); i2++)
  3321. {
  3322. IWbemClassObject *pObj = (IWbemClassObject *) m_aMaster[i2];
  3323. CVARIANT vClassName;
  3324. hRes = pObj->Get(L"__CLASS", 0, &vClassName, 0, 0);
  3325. if (FAILED(hRes) || vClassName.GetType() != VT_BSTR)
  3326. return WBEM_E_FAILED;
  3327. if (wbem_wcsicmp(aHierarchy[i], vClassName.GetStr()) == 0)
  3328. {
  3329. pTarget = pObj;
  3330. break;
  3331. }
  3332. }
  3333. if (pTarget)
  3334. break;
  3335. }
  3336. // If the association class was non-dynamic, it won't have been located
  3337. // by the above search. Instead, we will go to the repository and
  3338. // starting with the dynasty superclass, work down to the current class
  3339. // until we find a non-abstract class.
  3340. // ====================================================================
  3341. if (pTarget == 0)
  3342. {
  3343. for (i = aHierarchy.Size() - 1; i >= 0; i--)
  3344. {
  3345. IWbemClassObject *pTest = 0;
  3346. hRes = Db_GetClass(aHierarchy[i], &pTest);
  3347. if (FAILED(hRes))
  3348. break;
  3349. hRes = St_ObjHasQualifier(L"ABSTRACT", pTest);
  3350. if (SUCCEEDED(hRes))
  3351. {
  3352. pTest->Release();
  3353. continue;
  3354. }
  3355. else // This is what we want to send back
  3356. {
  3357. *pClassDef = pTest;
  3358. return WBEM_S_NO_ERROR;
  3359. }
  3360. }
  3361. }
  3362. // Now, see if we found it.
  3363. // ========================
  3364. if (pTarget == 0)
  3365. return WBEM_E_NOT_FOUND;
  3366. pTarget->AddRef();
  3367. *pClassDef = pTarget;
  3368. return WBEM_S_NO_ERROR;
  3369. }
  3370. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3371. //
  3372. // END CLASSDEFSONLY CODE
  3373. //
  3374. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3375. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3376. //
  3377. // BEGIN SCHEMA-ONLY SPECIFIC CODE
  3378. //
  3379. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  3380. //***************************************************************************
  3381. //
  3382. // CAssocQuery::SchemaQ_RefsFilter
  3383. //
  3384. // Reduces the class set of a schemaonly 'references of' query by
  3385. // cutting out anything specified in the filters. The filters applied
  3386. // are RESULTCLASS, REQUIREDQUALIFIER, and ROLE.
  3387. //
  3388. // The size and content of <aSrc> is altered. Objects not used
  3389. // are Released().
  3390. //
  3391. // Returns status in HRESULT, does not access the destination sink on error.
  3392. //
  3393. //***************************************************************************
  3394. // executions=1; no filtering though
  3395. HRESULT CAssocQuery::SchemaQ_RefsFilter(
  3396. IN OUT CFlexArray &aSrc // IN: the unreduced class set, OUT the reduced one
  3397. )
  3398. {
  3399. HRESULT hRes;
  3400. // Loop through the result set, looking for things to toss out.
  3401. // ============================================================
  3402. for (int i = 0; i < aSrc.Size(); i++) // x
  3403. {
  3404. BOOL bIsACandidate = TRUE;
  3405. // Extract this class definition from the source array.
  3406. // ====================================================
  3407. IWbemClassObject *pCls = (IWbemClassObject *) aSrc[i];
  3408. // Start testing.
  3409. //
  3410. // RESULTCLASS --the object must be of the specified
  3411. // class or part of its hierarchy.
  3412. // ==================================================
  3413. LPCWSTR pszResultClass = m_Parser.GetResultClass();
  3414. if (pszResultClass)
  3415. {
  3416. hRes = St_ObjIsOfClass(pszResultClass, pCls);
  3417. if (FAILED(hRes))
  3418. {
  3419. aSrc[i] = 0;
  3420. pCls->Release();
  3421. hRes = 0;
  3422. continue;
  3423. }
  3424. }
  3425. // If here, there either isn't a RESULTCLASS test or we passed it.
  3426. // Next, we try REQUIREDQUALIFIER.
  3427. // ===============================================================
  3428. LPCWSTR pszRequiredQual = m_Parser.GetRequiredQual();
  3429. if (pszRequiredQual)
  3430. {
  3431. hRes = St_ObjHasQualifier(pszRequiredQual, pCls);
  3432. if (FAILED(hRes))
  3433. {
  3434. aSrc[i] = 0;
  3435. pCls->Release();
  3436. hRes = 0;
  3437. continue;
  3438. }
  3439. }
  3440. // Next, we try ROLE.
  3441. // ==================
  3442. LPCWSTR pszRole = m_Parser.GetRole(); // x
  3443. if (pszRole)
  3444. {
  3445. hRes = RoleTest(m_pEndpoint, pCls, m_pNs, pszRole, ROLETEST_MODE_CIMREF_TYPE);
  3446. if (FAILED(hRes))
  3447. {
  3448. aSrc[i] = 0;
  3449. pCls->Release();
  3450. hRes = 0;
  3451. continue;
  3452. }
  3453. }
  3454. }
  3455. aSrc.Compress();
  3456. return WBEM_S_NO_ERROR;
  3457. }
  3458. //****************************************************************************
  3459. //
  3460. // CAssocQuery::TerminateSchemaQuery
  3461. //
  3462. // For schema queries, sends the final result objects to the destination
  3463. // sink and shuts down the query. At this point, all the objects are in
  3464. // the result set array and ready to be delivered.
  3465. //
  3466. //****************************************************************************
  3467. // visual ok
  3468. HRESULT CAssocQuery::SchemaQ_Terminate(
  3469. IN CFlexArray &aResultSet
  3470. )
  3471. {
  3472. HRESULT hRes = WBEM_S_NO_ERROR;
  3473. aResultSet.Compress(); // Remove NULLs
  3474. // Indicate everything.
  3475. // ====================
  3476. if (aResultSet.Size())
  3477. {
  3478. IWbemClassObject **p = (IWbemClassObject **) aResultSet.GetArrayPtr();
  3479. hRes = m_pDestSink->Indicate(aResultSet.Size(), p);
  3480. St_ReleaseArray(aResultSet);
  3481. }
  3482. return hRes;
  3483. }
  3484. //****************************************************************************
  3485. //
  3486. // CAssocQuery::SchemaQ_RefsQuery
  3487. //
  3488. // At this point we have the final list of classes. We now apply any
  3489. // secondary filters and send the result back to the client.
  3490. //
  3491. // (1) We apply all filters specified in the query.
  3492. // (2) If CLASSDEFSONLY, we post filter yet again.
  3493. // (3) Deliver to client
  3494. //
  3495. //****************************************************************************
  3496. // visual ok
  3497. HRESULT CAssocQuery::SchemaQ_RefsQuery(
  3498. IN OUT CFlexArray &aResultSet
  3499. )
  3500. {
  3501. HRESULT hRes;
  3502. // Apply various filters.
  3503. // ======================
  3504. hRes = SchemaQ_RefsFilter(aResultSet);
  3505. if (FAILED(hRes))
  3506. return hRes;
  3507. return SchemaQ_Terminate(aResultSet);
  3508. }
  3509. //****************************************************************************
  3510. //
  3511. // CAssocQuery::SchemaQ_AssocsQuery
  3512. //
  3513. // At this point we have the list of association classes. We apply
  3514. // association-level filters, and then get the other endpoint classes,
  3515. // filtering them in parallel. The final result set is placed in
  3516. // <aOtherEndpoints> and delivered to the user by the final call
  3517. // to SchemaQ_Terminate.
  3518. //
  3519. //****************************************************************************
  3520. // visual ok
  3521. HRESULT CAssocQuery::SchemaQ_AssocsQuery(
  3522. IN CFlexArray &aAssocSet
  3523. )
  3524. {
  3525. HRESULT hRes;
  3526. // Apply association filters.
  3527. // ========================
  3528. hRes = SchemaQ_AssocsFilter(aAssocSet);
  3529. if (FAILED(hRes))
  3530. return hRes;
  3531. // Now, get the other endpoints. We filter them
  3532. // in parallel, due to the good locality of reference
  3533. // in this case.
  3534. // ==================================================
  3535. CFlexArray aOtherEndpoints;
  3536. hRes = SchemaQ_GetAndFilterOtherEndpoints(
  3537. aAssocSet,
  3538. aOtherEndpoints
  3539. );
  3540. St_ReleaseArray(aAssocSet); // Done with the associations themselves
  3541. if (FAILED(hRes))
  3542. return hRes;
  3543. // Apply other-endpoint filters.
  3544. // =============================
  3545. return SchemaQ_Terminate(aOtherEndpoints);
  3546. }
  3547. //***************************************************************************
  3548. //
  3549. // CAssocQuery::ConvertEpListToClassDefsOnly
  3550. //
  3551. // Filters the endpoint list of instances and changes it into the minimal
  3552. // set of class definitions. Classes must be in the same namespace.
  3553. //
  3554. //***************************************************************************
  3555. //
  3556. HRESULT CAssocQuery::ConvertEpListToClassDefsOnly()
  3557. {
  3558. CFlexArray aNew;
  3559. HRESULT hRes;
  3560. BOOL bArrayNeedsCleanup = FALSE;
  3561. CInCritSec ics(&m_csCandidateEpAccess);
  3562. for (int i = 0; i < m_aEpCandidates.Size(); i++)
  3563. {
  3564. BSTR strEpPath = (BSTR) m_aEpCandidates[i];
  3565. if (strEpPath == 0)
  3566. continue;
  3567. BSTR strClassName = 0;
  3568. hRes = St_ObjPathInfo(strEpPath, &strClassName, 0);
  3569. if (FAILED(hRes))
  3570. {
  3571. hRes = 0;
  3572. continue;
  3573. }
  3574. BOOL bFound = FALSE;
  3575. // See if class is in our new destination array.
  3576. // =============================================
  3577. for (int i2 = 0; i2 < aNew.Size(); i2++)
  3578. {
  3579. BSTR strTest = (BSTR) aNew[i2];
  3580. if (wbem_wcsicmp(strClassName, strTest) == 0)
  3581. {
  3582. bFound = TRUE;
  3583. break;
  3584. }
  3585. }
  3586. if (bFound == TRUE)
  3587. SysFreeString(strClassName);
  3588. else
  3589. {
  3590. if (CFlexArray::no_error != aNew.Add(strClassName))
  3591. {
  3592. SysFreeString(strClassName);
  3593. bArrayNeedsCleanup = TRUE;
  3594. break;
  3595. }
  3596. }
  3597. }
  3598. if (bArrayNeedsCleanup)
  3599. {
  3600. for (i = 0; i < aNew.Size(); i++) SysFreeString((BSTR)aNew[i]);
  3601. return WBEM_E_OUT_OF_MEMORY;
  3602. }
  3603. EmptyCandidateEpArray();
  3604. for (i = 0; i < aNew.Size(); i++)
  3605. {
  3606. if (CFlexArray::no_error != m_aEpCandidates.Add(aNew[i]))
  3607. {
  3608. bArrayNeedsCleanup = TRUE;
  3609. break;
  3610. }
  3611. }
  3612. if (bArrayNeedsCleanup)
  3613. {
  3614. // continue from where you finished
  3615. for (; i < aNew.Size(); i++) SysFreeString((BSTR)aNew[i]);
  3616. return WBEM_E_OUT_OF_MEMORY;
  3617. }
  3618. return WBEM_S_NO_ERROR;
  3619. }
  3620. //***************************************************************************
  3621. //
  3622. // CAssocQuery::SchemaQ_AssocsFilter
  3623. //
  3624. // Called during an 'associators of' query, this filters out the
  3625. // classes which don't pass the test for the association classes
  3626. // themselves.
  3627. //
  3628. // Tests for ROLE and REQUIREDASSOCQUALIFIER.
  3629. //
  3630. //***************************************************************************
  3631. // ok
  3632. HRESULT CAssocQuery::SchemaQ_AssocsFilter(
  3633. IN OUT CFlexArray &aSrc
  3634. )
  3635. {
  3636. HRESULT hRes;
  3637. LPCWSTR pszRole = m_Parser.GetRole();
  3638. LPCWSTR pszRequiredAssocQual = m_Parser.GetRequiredAssocQual();
  3639. // If there are no filters anyway, short-circuit.
  3640. // ==============================================
  3641. if (pszRole == 0 && pszRequiredAssocQual == 0)
  3642. {
  3643. return WBEM_S_NO_ERROR;
  3644. }
  3645. // If here, some tests are required.
  3646. // =================================
  3647. for (int i = 0; i < aSrc.Size(); i++)
  3648. {
  3649. IWbemClassObject *pCls = (IWbemClassObject *) aSrc[i];
  3650. // If ROLE is present, ensure query endpoint is referenced
  3651. // by it.
  3652. // =======================================================
  3653. if (pszRole)
  3654. {
  3655. hRes = RoleTest(m_pEndpoint, pCls, m_pNs, pszRole, ROLETEST_MODE_CIMREF_TYPE);
  3656. if (FAILED(hRes))
  3657. {
  3658. aSrc[i] = 0;
  3659. pCls->Release();
  3660. hRes = 0;
  3661. continue;
  3662. }
  3663. }
  3664. // If REQUIREDASSOCQUALIFIER was in the query,
  3665. // ensure it is present.
  3666. // ===========================================
  3667. if (pszRequiredAssocQual)
  3668. {
  3669. hRes = St_ObjHasQualifier(pszRequiredAssocQual, pCls);
  3670. if (FAILED(hRes))
  3671. {
  3672. aSrc[i] = 0;
  3673. pCls->Release();
  3674. hRes = 0;
  3675. continue;
  3676. }
  3677. }
  3678. }
  3679. aSrc.Compress();
  3680. return WBEM_S_NO_ERROR;
  3681. }
  3682. //***************************************************************************
  3683. //
  3684. // CAssocQuery::SchemaQ_GetAndFilterOtherEndpoints
  3685. //
  3686. // Given the set of classes in <aAssocs>, get the other endpoint
  3687. // classes.
  3688. //
  3689. // The filtering is achieved in parallel, since we have locality
  3690. // of reference between the association object and the endpoint.
  3691. //
  3692. // Parameters:
  3693. // <aAssocs> The association classes.
  3694. // <aEndpoints> Receives the endpoint classes.
  3695. //
  3696. // Result:
  3697. // HRESULT Does not access the destination sink.
  3698. //
  3699. //***************************************************************************
  3700. // ok
  3701. HRESULT CAssocQuery::SchemaQ_GetAndFilterOtherEndpoints(
  3702. IN CFlexArray &aAssocs,
  3703. OUT CFlexArray &aEndpoints
  3704. )
  3705. {
  3706. HRESULT hRes;
  3707. for (int i = 0; i < aAssocs.Size(); i++)
  3708. {
  3709. IWbemClassObject *pAssoc = (IWbemClassObject *) aAssocs[i];
  3710. IWbemClassObject *pEpClass = 0;
  3711. // Find the property that references the other endpoint.
  3712. // ====================================================
  3713. BSTR strOtherEpName = 0;
  3714. hRes = SchemaQ_GetOtherEpClassName(pAssoc, &strOtherEpName);
  3715. if (FAILED(hRes))
  3716. continue;
  3717. CSysFreeMe _1(strOtherEpName);
  3718. // If we failed to get a name we should continue.
  3719. if ( S_OK != hRes )
  3720. {
  3721. hRes = 0;
  3722. continue;
  3723. }
  3724. // Now, get that class. The class comes back
  3725. // property AddRef'ed. If we don't use it, then we
  3726. // have to Release it.
  3727. // ===============================================
  3728. hRes = GetClassFromAnywhere(strOtherEpName, 0, &pEpClass);
  3729. if (FAILED(hRes))
  3730. {
  3731. // WE have a dangling reference.
  3732. // =============================
  3733. ERRORTRACE((LOG_WBEMCORE, "Invalid path %S specified in an association class\n", strOtherEpName));
  3734. EmptyObjectList(aEndpoints);
  3735. return WBEM_E_INVALID_OBJECT_PATH;
  3736. }
  3737. //
  3738. // If here, we have the endpoint class in <pEpClass>
  3739. // and the associationclass in pAssoc.
  3740. // Now, apply the filters, both to the association and the endpoint.
  3741. //
  3742. // RESULTCLASS
  3743. // Verify that the class of the endpoint is this
  3744. // or part of its hierarchy.
  3745. // =============================================
  3746. LPCWSTR pszResultClass = m_Parser.GetResultClass();
  3747. if (pszResultClass)
  3748. {
  3749. hRes = St_ObjIsOfClass(pszResultClass, pEpClass);
  3750. if (FAILED(hRes))
  3751. {
  3752. pEpClass->Release();
  3753. hRes = 0;
  3754. continue;
  3755. }
  3756. }
  3757. // ROLE.
  3758. // The association must point back to the endpoint
  3759. // via this.
  3760. // ================================================
  3761. LPCWSTR pszRole = m_Parser.GetRole();
  3762. if (pszRole)
  3763. {
  3764. hRes = RoleTest(m_pEndpoint, pAssoc, m_pNs, pszRole, ROLETEST_MODE_CIMREF_TYPE);
  3765. if (FAILED(hRes))
  3766. {
  3767. pEpClass->Release();
  3768. hRes = 0;
  3769. continue;
  3770. }
  3771. }
  3772. // RESULTROLE
  3773. // The association must point to the other endpoint
  3774. // via this property.
  3775. // ================================================
  3776. LPCWSTR pszResultRole = m_Parser.GetResultRole();
  3777. if (pszResultRole)
  3778. {
  3779. hRes = RoleTest(pEpClass, pAssoc, m_pNs, pszResultRole, ROLETEST_MODE_CIMREF_TYPE);
  3780. if (FAILED(hRes))
  3781. {
  3782. pEpClass->Release();
  3783. hRes = 0;
  3784. continue;
  3785. }
  3786. }
  3787. // ASSOCCLASS
  3788. // Verify that the class of the association is this.
  3789. // =================================================
  3790. LPCWSTR pszAssocClass = m_Parser.GetAssocClass();
  3791. if (pszAssocClass)
  3792. {
  3793. hRes = St_ObjIsOfClass(pszAssocClass, pAssoc);
  3794. if (FAILED(hRes))
  3795. {
  3796. pEpClass->Release();
  3797. hRes = 0;
  3798. continue;
  3799. }
  3800. }
  3801. // REQUIREDQUALIFIER
  3802. // Endpoint must have this qualifier.
  3803. // ===================================
  3804. LPCWSTR pszQual = m_Parser.GetRequiredQual();
  3805. if (pszQual)
  3806. {
  3807. hRes = St_ObjHasQualifier(pszQual, pEpClass);
  3808. if (FAILED(hRes))
  3809. {
  3810. pEpClass->Release();
  3811. hRes = 0;
  3812. continue;
  3813. }
  3814. }
  3815. // REQUIREDASSOCQUALIFIER
  3816. // Association object must have this qualifier.
  3817. // ============================================
  3818. LPCWSTR pszRequiredAssocQual = m_Parser.GetRequiredAssocQual();
  3819. if (pszRequiredAssocQual)
  3820. {
  3821. hRes = St_ObjHasQualifier(pszRequiredAssocQual, pAssoc);
  3822. if (FAILED(hRes))
  3823. {
  3824. pEpClass->Release();
  3825. hRes = 0;
  3826. continue;
  3827. }
  3828. }
  3829. // If here, we passed the barrage of filtering
  3830. // tests and can happily report that the class
  3831. // is part of the result set.
  3832. // ===========================================
  3833. if (CFlexArray::no_error != aEndpoints.Add(pEpClass))
  3834. {
  3835. pEpClass->Release();
  3836. return WBEM_E_OUT_OF_MEMORY;
  3837. }
  3838. }
  3839. return WBEM_S_NO_ERROR;
  3840. }
  3841. //***************************************************************************
  3842. //
  3843. // CAssocQuery::SchemaQ_GetOtherEpClassName
  3844. //
  3845. // Finds the property in the association which references the
  3846. // 'other endpoint' in the query. This is achieved by locating
  3847. // a property which *does* reference the endpoint and assuming that
  3848. // any remaining property must reference the 'other endpoint'.
  3849. // If both references can reach the query endpoint, then no
  3850. // harm is done
  3851. //
  3852. // This function assumes well-formed associations with two
  3853. // references.
  3854. //
  3855. // PARAMETERS:
  3856. // <pAssoc> The association class
  3857. // <strOtherEpName> Receives the name of the class of the 'other endpoint'
  3858. //
  3859. // RESULT:
  3860. // WBEM_S_NO_ERROR, WBEM_E_FAILED
  3861. //
  3862. //***************************************************************************
  3863. // ok
  3864. HRESULT CAssocQuery::SchemaQ_GetOtherEpClassName(
  3865. IN IWbemClassObject *pAssocClass,
  3866. OUT BSTR *strOtherEpName
  3867. )
  3868. {
  3869. HRESULT hRes = WBEM_E_FAILED;
  3870. if (strOtherEpName == 0)
  3871. return hRes;
  3872. *strOtherEpName = 0;
  3873. BOOL bStrict = (m_Parser.GetQueryType() & QUERY_TYPE_SCHEMA_ONLY) != 0;
  3874. // Enumerate just the references.
  3875. // ===============================
  3876. hRes = pAssocClass->BeginEnumeration(WBEM_FLAG_REFS_ONLY);
  3877. if (FAILED(hRes))
  3878. return WBEM_E_FAILED;
  3879. // Loop through the references.
  3880. // ============================
  3881. int nCount = 0;
  3882. while (1)
  3883. {
  3884. CVARIANT vRefPath;
  3885. BSTR strPropName = 0;
  3886. BSTR strEpClass = 0;
  3887. hRes = pAssocClass->Next(
  3888. 0, // Flags
  3889. &strPropName, // Name
  3890. vRefPath, // Value
  3891. 0, // CIM type (refs only already)
  3892. 0 // Flavor
  3893. );
  3894. if (hRes == WBEM_S_NO_MORE_DATA)
  3895. break;
  3896. CSysFreeMe _1(strPropName);
  3897. hRes = CanPropRefQueryEp(bStrict, strPropName, pAssocClass, &strEpClass);
  3898. CSysFreeMe _2(strEpClass);
  3899. if (FAILED(hRes) || nCount)
  3900. {
  3901. // If here on the second iteration or the first iteration
  3902. // with a failure, we have found the 'other endpoint'.
  3903. // ======================================================
  3904. *strOtherEpName = SysAllocString(strEpClass);
  3905. if (*strOtherEpName == 0)
  3906. return WBEM_E_OUT_OF_MEMORY;
  3907. hRes = WBEM_S_NO_ERROR;
  3908. break;
  3909. }
  3910. else
  3911. nCount++;
  3912. }
  3913. pAssocClass->EndEnumeration();
  3914. return hRes;
  3915. }
  3916. //***************************************************************************
  3917. //
  3918. // CAssocQuery::CanPropRefQueryEp
  3919. //
  3920. // For class definitions, determines if the specified property in the
  3921. // object can reference the query endpoint. This works for both strongly
  3922. // typed and CLASSREF typed properties.
  3923. //
  3924. // PARAMETERS:
  3925. // <pszPropName> The property to test. Must be a reference property.
  3926. // <bStrict> If TRUE, then the property must actually reference
  3927. // the class of the endpoint. If FALSE, it may reference
  3928. // any of the superclasses of the endpoint.
  3929. // <pObj> The association object with the property to be tested.
  3930. // <strRefType> Optionally receives the name of the class in the
  3931. // CIMTYPE "REF:Classname>" string, as long as
  3932. // the reference is strongly typed (does not work
  3933. // for CLASSREF types).
  3934. //
  3935. // RETURNS:
  3936. // HRESULT
  3937. // WBEM_S_NO_ERROR if the property can reference the query endpoint.
  3938. // WBEM_E_NOT_FOUND if the property cannot reference the query endpoint.
  3939. // or
  3940. // WBEM_E_INVALID_PARAMETER
  3941. // WBEM_E_FAILED
  3942. //
  3943. //***************************************************************************
  3944. //
  3945. HRESULT CAssocQuery::CanPropRefQueryEp(
  3946. IN BOOL bStrict,
  3947. IN LPWSTR pszPropName,
  3948. IN IWbemClassObject *pObj,
  3949. OUT BSTR *strRefType
  3950. )
  3951. {
  3952. HRESULT hRes;
  3953. wchar_t ClassName[MAX_CLASS_NAME];
  3954. *ClassName = 0;
  3955. if (pszPropName == 0 || pObj == 0)
  3956. return WBEM_E_INVALID_PARAMETER;
  3957. // Get the qualifier set for this property.
  3958. // ========================================
  3959. IWbemQualifierSet *pQSet = 0;
  3960. hRes = pObj->GetPropertyQualifierSet(pszPropName,&pQSet);
  3961. if (FAILED(hRes))
  3962. return WBEM_E_FAILED;
  3963. CReleaseMe _1(pQSet);
  3964. // Now get the CIMTYPE of this reference.
  3965. // ======================================
  3966. CVARIANT v;
  3967. hRes = pQSet->Get(L"CIMTYPE", 0, &v, 0);
  3968. if (FAILED(hRes) || V_VT(&v) != VT_BSTR)
  3969. return WBEM_E_FAILED;
  3970. BSTR strRefClass = V_BSTR(&v);
  3971. if (strRefClass)
  3972. {
  3973. if (wcslen_max(strRefClass,MAX_CLASS_NAME) > MAX_CLASS_NAME) return WBEM_E_FAILED;
  3974. parse_REF(strRefClass,MAX_CLASS_NAME,ClassName);
  3975. }
  3976. // Send a copy of the class name back to the
  3977. // caller, if required.
  3978. // =========================================
  3979. if (strRefType)
  3980. {
  3981. *strRefType = 0;
  3982. if (*ClassName)
  3983. {
  3984. *strRefType = SysAllocString(ClassName);
  3985. if (*strRefType == 0)
  3986. return WBEM_E_OUT_OF_MEMORY;
  3987. }
  3988. }
  3989. // Now see if this class is any of the classes in our
  3990. // query endpoint.
  3991. // ==================================================
  3992. if (*ClassName)
  3993. {
  3994. // If <bStrict> we must match the class name of the
  3995. // query endpoint exactly.
  3996. if (bStrict)
  3997. {
  3998. if (wbem_wcsicmp(ClassName, m_bstrEndpointClass) == 0)
  3999. return WBEM_S_NO_ERROR;
  4000. }
  4001. // Else, any of the superclasses of the endpoint will do.
  4002. else
  4003. {
  4004. for (int i = 0; i < m_aEndpointHierarchy.Size(); i++)
  4005. {
  4006. if (wbem_wcsicmp(ClassName, m_aEndpointHierarchy[i]) == 0)
  4007. return WBEM_S_NO_ERROR;
  4008. }
  4009. }
  4010. }
  4011. // If here, we can try to see if the property has a CLASSREF
  4012. // qualifier instead.
  4013. // =========================================================
  4014. hRes = CanClassRefReachQueryEp(pQSet, bStrict);
  4015. if (SUCCEEDED(hRes))
  4016. return WBEM_S_NO_ERROR;
  4017. // If here, the property doesn't reference the query
  4018. // endpoint in any way.
  4019. // =================================================
  4020. return WBEM_E_NOT_FOUND;
  4021. }
  4022. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4023. //
  4024. // END SCHEMA-ONLY SPECIFIC CODE
  4025. //
  4026. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4027. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4028. //
  4029. // BEGIN DYNAMIC CLASS HELPERS
  4030. //
  4031. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4032. //***************************************************************************
  4033. //
  4034. // ClassNameTest
  4035. //
  4036. // Sort helper
  4037. //
  4038. //***************************************************************************
  4039. //
  4040. static int ClassNameTest(
  4041. IN CFlexArray &Classes,
  4042. IN int nIndex1, // iBackscan
  4043. IN int nIndex2 // iBackscan-nInterval
  4044. )
  4045. {
  4046. HRESULT hr;
  4047. // Name test.
  4048. IWbemClassObject *pC1 = (IWbemClassObject *) Classes[nIndex1];
  4049. IWbemClassObject *pC2 = (IWbemClassObject *) Classes[nIndex2];
  4050. CVARIANT v1, v2;
  4051. hr = pC1->Get(L"__CLASS", 0, &v1, 0, 0);
  4052. if (FAILED(hr) || VT_BSTR != V_VT(&v1)) return 1;
  4053. hr = pC2->Get(L"__CLASS", 0, &v2, 0, 0);
  4054. if (FAILED(hr) || VT_BSTR != V_VT(&v2)) return 1;
  4055. return wbem_wcsicmp(V_BSTR(&v1), V_BSTR(&v2));
  4056. }
  4057. //***************************************************************************
  4058. //
  4059. // CAssocQuery::SortDynClasses
  4060. //
  4061. // Sorts the dynamic classes so they can be binary searched later.
  4062. //
  4063. //***************************************************************************
  4064. //
  4065. void CAssocQuery::SortDynClasses()
  4066. {
  4067. // Shell sort.
  4068. // ===========
  4069. int nSize = m_aDynClasses.Size();
  4070. for (int nInterval = 1; nInterval < nSize / 9; nInterval = nInterval * 3 + 1);
  4071. while (nInterval)
  4072. {
  4073. for (int iCursor = nInterval; iCursor < nSize; iCursor++)
  4074. {
  4075. int iBackscan = iCursor;
  4076. while (iBackscan - nInterval >= 0
  4077. && ClassNameTest(m_aDynClasses, iBackscan, iBackscan-nInterval) < 0)
  4078. {
  4079. // Swap.
  4080. // =====
  4081. IWbemClassObject *pTmp = (IWbemClassObject *) m_aDynClasses[iBackscan - nInterval];
  4082. m_aDynClasses[iBackscan - nInterval] = m_aDynClasses[iBackscan];
  4083. m_aDynClasses[iBackscan] = pTmp;
  4084. iBackscan -= nInterval;
  4085. }
  4086. }
  4087. nInterval /= 3;
  4088. }
  4089. }
  4090. //***************************************************************************
  4091. //
  4092. // CAssocQuery::GetDynClasses
  4093. //
  4094. // Fills the per-query cache with all available dynamic assoc classes.
  4095. //
  4096. //***************************************************************************
  4097. //
  4098. HRESULT CAssocQuery::GetDynClasses()
  4099. {
  4100. CSynchronousSink* pDynClassSink = 0;
  4101. HRESULT hRes = 0;
  4102. // Now, get all dynamic classes.
  4103. // =============================
  4104. pDynClassSink = CSynchronousSink::Create();
  4105. if (NULL == pDynClassSink) return WBEM_E_OUT_OF_MEMORY;
  4106. pDynClassSink->AddRef();
  4107. CReleaseMe _1(pDynClassSink);
  4108. hRes = m_pNs->GetDynamicReferenceClasses( 0L, m_pContext, pDynClassSink );
  4109. if (FAILED(hRes)) return hRes;
  4110. pDynClassSink->Block();
  4111. pDynClassSink->GetStatus(&hRes, NULL, NULL);
  4112. // Now get all the dynamic class definitions.
  4113. CRefedPointerArray<IWbemClassObject>& raObjects = pDynClassSink->GetObjects();
  4114. for (int i = 0; i < raObjects.GetSize(); i++)
  4115. {
  4116. IWbemClassObject *pClsDef = (IWbemClassObject *) raObjects[i];
  4117. if (CFlexArray::no_error == m_aDynClasses.Add(pClsDef))
  4118. {
  4119. pClsDef->AddRef();
  4120. }
  4121. }
  4122. SortDynClasses();
  4123. return WBEM_S_NO_ERROR;
  4124. }
  4125. //***************************************************************************
  4126. //
  4127. // CAssocQuery::GetDynClass
  4128. //
  4129. // Attempts to find the requested class in the dynamic class cache.
  4130. //
  4131. //***************************************************************************
  4132. //
  4133. HRESULT CAssocQuery::GetDynClass(
  4134. IN LPCWSTR pszClassName,
  4135. OUT IWbemClassObject **pCls
  4136. )
  4137. {
  4138. HRESULT hRes;
  4139. if (pCls == 0 || pszClassName == 0)
  4140. return WBEM_E_INVALID_PARAMETER;
  4141. *pCls = 0;
  4142. CFlexArray &a = m_aDynClasses;
  4143. // Binary search the cache.
  4144. // ========================
  4145. int l = 0, u = a.Size() - 1;
  4146. while (l <= u)
  4147. {
  4148. int m = (l + u) / 2;
  4149. IWbemClassObject *pItem = (IWbemClassObject *) a[m];
  4150. CVARIANT vClassName;
  4151. hRes = pItem->Get(L"__CLASS", 0, &vClassName, 0, 0);
  4152. if (FAILED(hRes) || VT_BSTR != V_VT(&vClassName)) return WBEM_E_NOT_FOUND;
  4153. int nRes = wbem_wcsicmp(pszClassName, V_BSTR(&vClassName));
  4154. if (nRes < 0)
  4155. u = m - 1;
  4156. else if (nRes > 0)
  4157. l = m + 1;
  4158. else
  4159. {
  4160. pItem->AddRef();
  4161. *pCls = pItem;
  4162. return WBEM_S_NO_ERROR;
  4163. }
  4164. }
  4165. return WBEM_E_NOT_FOUND;
  4166. }
  4167. //***************************************************************************
  4168. //
  4169. // GetClassDynasty
  4170. //
  4171. // Gets all the classes in a dynasty. The returned array has a
  4172. // set of IWbemClassObject pointers that need releasing.
  4173. //
  4174. //***************************************************************************
  4175. //
  4176. HRESULT CAssocQuery::GetClassDynasty(
  4177. IN LPCWSTR pszClass,
  4178. OUT CFlexArray &aDynasty
  4179. )
  4180. {
  4181. HRESULT hRes;
  4182. CSynchronousSink* pClassSink = CSynchronousSink::Create();
  4183. if (NULL == pClassSink) return WBEM_E_OUT_OF_MEMORY;
  4184. pClassSink->AddRef();
  4185. CReleaseMe _1(pClassSink);
  4186. hRes = m_pNs->Exec_CreateClassEnum( LPWSTR(pszClass), WBEM_FLAG_DEEP, m_pContext, pClassSink);
  4187. if (FAILED(hRes)) return hRes;
  4188. pClassSink->GetStatus(&hRes, NULL, NULL);
  4189. if (FAILED(hRes)) return hRes;
  4190. aDynasty.Bind(pClassSink->GetObjects().GetArray());
  4191. return WBEM_S_NO_ERROR;
  4192. }
  4193. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  4194. //
  4195. // END DYNAMIC CLASS HELPERS
  4196. //
  4197. //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@