Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

513 lines
12 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: detect.cpp
  6. //
  7. // Description:
  8. //
  9. // Implementation for the Detect() function
  10. //
  11. //=======================================================================
  12. #include "iuengine.h"
  13. #include "iuxml.h"
  14. #include <logging.h>
  15. #include <StringUtil.h>
  16. #include <download.h>
  17. #include "schemamisc.h"
  18. #include "expression.h"
  19. #include <iucommon.h>
  20. //
  21. // define constants used in this file
  22. //
  23. #define C_INDEX_STATUS_INSTALLED 0
  24. #define C_INDEX_STATUS_UPTODATE 1
  25. #define C_INDEX_STATUS_NEWVERSION 2
  26. #define C_INDEX_STATUS_EXCLUDED 3
  27. #define C_INDEX_STATUS_FORCE 4
  28. #define C_INDEX_STATUS_COMPUTER 5 // <computerSystem>
  29. #define C_INDEX_ARRAY_SIZE 6
  30. //
  31. // declare macros used in this cpp file
  32. //
  33. /**
  34. * deckare the constants used to manipulate the result of Detect() method
  35. */
  36. /**
  37. * used in <detection> tag, to tell the detection result. This result
  38. * should overwrite the rest of <expression>, if any
  39. */
  40. extern const LONG IUDET_INSTALLED; /* mask for <installed> result */
  41. extern const LONG IUDET_INSTALLED_NULL; /* mask for <installed> missing */
  42. extern const LONG IUDET_UPTODATE; /* mask for <upToDate> result */
  43. extern const LONG IUDET_UPTODATE_NULL; /* mask for <upToDate> missing */
  44. extern const LONG IUDET_NEWERVERSION; /* mask for <newerVersion> result */
  45. extern const LONG IUDET_NEWERVERSION_NULL; /* mask for <newerVersion> missing */
  46. extern const LONG IUDET_EXCLUDED; /* mask for <excluded> result */
  47. extern const LONG IUDET_EXCLUDED_NULL; /* mask for <excluded> missing */
  48. extern const LONG IUDET_FORCE; /* mask for <force> result */
  49. extern const LONG IUDET_FORCE_NULL; /* mask for <force> missing */
  50. extern const LONG IUDET_COMPUTER; // mask for <computerSystem> result
  51. extern const LONG IUDET_COMPUTER_NULL; // <computerSystem> missing
  52. const DetResultMask[6][2] = {
  53. {IUDET_INSTALLED, IUDET_INSTALLED_NULL},
  54. {IUDET_UPTODATE, IUDET_UPTODATE_NULL},
  55. {IUDET_NEWERVERSION, IUDET_NEWERVERSION_NULL},
  56. {IUDET_EXCLUDED, IUDET_EXCLUDED_NULL},
  57. {IUDET_FORCE, IUDET_FORCE_NULL},
  58. {IUDET_COMPUTER, IUDET_COMPUTER_NULL}
  59. };
  60. //
  61. // local macros
  62. //
  63. #define ReturnIfHrFail(hr) if (FAILED(hr)) {LOG_ErrorMsg(hr); return hr;}
  64. #define GotoCleanupIfNull(p) if (p) goto CleanUp
  65. #define SetDetResultFromDW(arr, index, dw, bit, bitNull) \
  66. if (bitNull == (dw & bitNull)) \
  67. arr[index] = -1; \
  68. else \
  69. arr[index] = (bit == (dw & bit)) ? 1 : 0;
  70. /////////////////////////////////////////////////////////////////////////
  71. //
  72. // Private function DoDetection()
  73. // do detection on one item
  74. //
  75. // Input:
  76. // one item node
  77. //
  78. // Output:
  79. // detect result: array of integer, each represents a result
  80. // of one element. indexes are defined as C_INDEX_STATUS_XXX
  81. // value: <0 expresison not present
  82. // =0 evalues to FALSE
  83. // >0 evalues to TRUE
  84. //
  85. //
  86. // Return:
  87. // S_OK if everything fine or error code
  88. /////////////////////////////////////////////////////////////////////////
  89. HRESULT
  90. DoDetection(
  91. IXMLDOMNode* pNode, // one item node
  92. BOOL fIsItemNode, // need to go down 1 level to get detection node
  93. int* pResultArray // array of result
  94. )
  95. {
  96. LOG_Block("DoDetection");
  97. int i;
  98. BOOL fRet = FALSE;
  99. BOOL fNeedReleaseNode = FALSE;
  100. HRESULT hr = S_OK;
  101. BSTR bstrNodeName = NULL;
  102. BSTR bstrText = NULL;
  103. IXMLDOMNode* pDetectionNode = NULL;
  104. IXMLDOMNode* pDetectionChild = NULL;
  105. IXMLDOMNode* pExpression = NULL;
  106. USES_IU_CONVERSION;
  107. if (fIsItemNode)
  108. {
  109. hr = pNode->selectSingleNode(KEY_DETECTION, &pDetectionNode);
  110. if (S_FALSE == hr || NULL == pDetectionNode)
  111. {
  112. hr = E_INVALIDARG; // no detection node found!
  113. LOG_ErrorMsg(hr);
  114. return hr;
  115. }
  116. }
  117. else
  118. {
  119. pDetectionNode = pNode;
  120. }
  121. if (NULL == pDetectionNode)
  122. {
  123. //
  124. // no detection node. Legal schema though.
  125. // nothing we can do, so bail out.
  126. //
  127. LOG_XML(_T("no detection node found for this item! Returns S_FALSE, so it won't be reported"));
  128. return S_FALSE;
  129. }
  130. //
  131. // initialize result array
  132. //
  133. for (i = 0; i < C_INDEX_ARRAY_SIZE; i++)
  134. {
  135. pResultArray[i] = -1;
  136. }
  137. //
  138. // detection node may have a list of child nodes, each child node has
  139. // a different name for different purpose of detection.
  140. // each child node contains one and only one expression node
  141. //
  142. LOG_XML(_T("No costom detection DLL found. Detection children..."));
  143. (void) pDetectionNode->get_firstChild(&pDetectionChild);
  144. while (NULL != pDetectionChild)
  145. {
  146. //
  147. // for each child, see if it is a known detection child
  148. //
  149. (void) pDetectionChild->get_nodeName(&bstrNodeName);
  150. static const BSTR C_DETX_NAME[] = {
  151. KEY_INSTALLED,
  152. KEY_UPTODATE,
  153. KEY_NEWERVERSION,
  154. KEY_EXCLUDED,
  155. KEY_FORCE,
  156. KEY_COMPUTERSYSTEM
  157. };
  158. for (i = 0; i < ARRAYSIZE(C_DETX_NAME); i++)
  159. {
  160. if (CompareBSTRsEqual(bstrNodeName, C_DETX_NAME[i]))
  161. {
  162. //
  163. // found this child node is a known detection node
  164. //
  165. if (C_INDEX_STATUS_COMPUTER == i)
  166. {
  167. //
  168. // if this is the computerSystem detection,
  169. // then we ignore all child nodes, just do a simple
  170. // function call to find out if this machine matches
  171. // the manufacturer and model
  172. //
  173. hr = DetectComputerSystem(pDetectionChild, &fRet);
  174. }
  175. else
  176. //
  177. // get the expression node from this child node
  178. //
  179. if (SUCCEEDED(hr = pDetectionChild->get_firstChild(&pExpression)))
  180. {
  181. if (NULL != pExpression)
  182. {
  183. hr = DetectExpression(pExpression, &fRet);
  184. LOG_XML(_T("Detection result for tag %s = %d, returns 0x%08x"), OLE2T(bstrNodeName), fRet?1:0, hr);
  185. }
  186. else
  187. {
  188. //
  189. // if there is no child, this is an empty detection type,
  190. // then we will treat this as "ALWAYS TRUE", and reset hr so
  191. // this "always true" result can be sent out
  192. //
  193. fRet = TRUE;
  194. hr = S_OK;
  195. }
  196. SafeReleaseNULL(pExpression);
  197. }
  198. //
  199. // store the detection result
  200. //
  201. pResultArray[i] = (fRet) ? 1 : 0;
  202. break; // done with current node
  203. }
  204. }
  205. SafeSysFreeString(bstrNodeName);
  206. if (FAILED(hr))
  207. {
  208. //
  209. // report error to log file
  210. //
  211. IXMLDOMNode* pIdentityNode = NULL, *pProviderNode = NULL;
  212. BSTR bstrIdentStr = NULL;
  213. char* pNodeType = (fIsItemNode) ? "Provider:" : "Item:";
  214. //
  215. // we need to find out the identity string of this node
  216. //
  217. if (fIsItemNode)
  218. {
  219. //
  220. // this is an item node, containing identity node
  221. //
  222. (void)FindNode(pNode, KEY_IDENTITY, &pIdentityNode);
  223. }
  224. else
  225. {
  226. //
  227. // this is the detection node of a provider
  228. //
  229. if (SUCCEEDED(pNode->get_parentNode(&pProviderNode)) && NULL != pProviderNode)
  230. {
  231. (void)FindNode(pProviderNode, KEY_IDENTITY, &pIdentityNode);
  232. }
  233. }
  234. //
  235. // if we have a valid identity node
  236. //
  237. if (NULL != pIdentityNode &&
  238. SUCCEEDED(UtilGetUniqIdentityStr(pIdentityNode, &bstrIdentStr, 0x0)) &&
  239. NULL != bstrIdentStr)
  240. {
  241. //
  242. // output log about the error
  243. //
  244. #if defined(UNICODE) || defined(_UNICODE)
  245. LogError(hr, "Found error during detection %hs %ls", pNodeType, bstrIdentStr);
  246. #else
  247. LogError(hr, "Found error during detection %s %s", pNodeType, OLE2T(bstrIdentStr));
  248. #endif
  249. SysFreeString(bstrIdentStr);
  250. }
  251. SafeReleaseNULL(pProviderNode);
  252. SafeReleaseNULL(pIdentityNode);
  253. //
  254. // if any one detection returns fail, then this detection node is
  255. // not valid - it means something wrong in the detection
  256. // data. we will just ignore this detection, no output for it.
  257. //
  258. break;
  259. }
  260. //
  261. // try next detection child
  262. //
  263. IXMLDOMNode* pNextNode = NULL;
  264. pDetectionChild->get_nextSibling(&pNextNode);
  265. SafeReleaseNULL(pDetectionChild);
  266. pDetectionChild = pNextNode;
  267. }
  268. SafeReleaseNULL(pDetectionChild);
  269. if (fIsItemNode)
  270. {
  271. SafeReleaseNULL(pDetectionNode);
  272. }
  273. return hr;
  274. }
  275. /////////////////////////////////////////////////////////////////////////////
  276. // public function Detect()
  277. //
  278. // Do detection.
  279. // Input:
  280. // bstrXmlCatalog - the xml catalog portion containing items to be detected
  281. // Output:
  282. // pbstrXmlItems - the detected items in xml format
  283. // e.g.
  284. // <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" installed="1" force="1"/>
  285. /////////////////////////////////////////////////////////////////////////////
  286. HRESULT WINAPI CEngUpdate::Detect(BSTR bstrXmlCatalog, DWORD dwFlags, BSTR *pbstrXmlItems)
  287. {
  288. HRESULT hr = S_OK;
  289. IXMLDOMNodeList* pProviderList = NULL;
  290. IXMLDOMNodeList* pProvChildList = NULL;
  291. IXMLDOMNode* pCurProvider = NULL;
  292. IXMLDOMNode* pCurNode = NULL;
  293. CXmlCatalog xmlCatalog;
  294. CXmlItems ItemList; // result item list
  295. HANDLE_NODE hNode;
  296. int DetStatus[C_INDEX_ARRAY_SIZE];
  297. int i;
  298. DWORD dwDownloadFlags = 0;
  299. LOG_Block("Detect()");
  300. //#if defined(_DEBUG) || defined(DEBUG)
  301. USES_IU_CONVERSION;
  302. //#endif
  303. if (NULL == bstrXmlCatalog || NULL == pbstrXmlItems)
  304. {
  305. hr = E_INVALIDARG;
  306. LOG_ErrorMsg(hr);
  307. return hr;
  308. }
  309. LOG_XML(_T("Catalog=%s"), OLE2T(bstrXmlCatalog));
  310. // Set Global Offline Flag - checked by XML Classes to disable Validation (schemas are on the net)
  311. if (dwFlags & FLAG_OFFLINE_MODE)
  312. {
  313. m_fOfflineMode = TRUE;
  314. }
  315. else
  316. {
  317. m_fOfflineMode = FALSE;
  318. }
  319. //
  320. // Convert bstrXmlCatalog to XMLDOM
  321. //
  322. hr = xmlCatalog.LoadXMLDocument(bstrXmlCatalog, m_fOfflineMode);
  323. ReturnIfHrFail(hr);
  324. LOG_XML(_T("Catalog has been loaded into XMLDOM"));
  325. //
  326. // get the list of providers from catalog
  327. //
  328. pProviderList = xmlCatalog.GetProviders();
  329. if (NULL == pProviderList)
  330. {
  331. LOG_Error(_T("No provider found!"));
  332. return E_INVALIDARG;
  333. }
  334. //
  335. // get the first provider
  336. //
  337. (void) pProviderList->nextNode(&pCurProvider);
  338. //
  339. // for each provider, process their item list
  340. //
  341. while (NULL != pCurProvider)
  342. {
  343. //
  344. // get the children list from this node
  345. //
  346. pCurProvider->get_childNodes(&pProvChildList);
  347. if (NULL != pProvChildList)
  348. {
  349. long n;
  350. //
  351. // loop through the list to process each item of catalog
  352. //
  353. long iProvChildren = 0;
  354. pProvChildList->get_length(&iProvChildren);
  355. BOOL fProviderOkay = TRUE;
  356. BSTR bstrHref = NULL;
  357. //
  358. // process each child of this provider to see
  359. // if there is any detection node or any item node,
  360. //
  361. for (n = 0; n < iProvChildren && fProviderOkay; n++)
  362. {
  363. pProvChildList->get_item(n, &pCurNode);
  364. BOOL fIsItemNode = DoesNodeHaveName(pCurNode, KEY_ITEM);
  365. if (fIsItemNode ||
  366. DoesNodeHaveName(pCurNode, KEY_DETECTION))
  367. {
  368. //
  369. // initialize the status result array
  370. //
  371. for (i = 0; i < C_INDEX_ARRAY_SIZE; i++)
  372. {
  373. DetStatus[i] = -1; // init to not present
  374. }
  375. //
  376. // detect each pression of this detection node of this item
  377. // error reported inside this function
  378. //
  379. if (S_OK == DoDetection(pCurNode, fIsItemNode, DetStatus))
  380. {
  381. //
  382. // add the item to the item list
  383. //
  384. if (SUCCEEDED(ItemList.AddItem(fIsItemNode ? pCurNode : pCurProvider, &hNode)) && HANDLE_NODE_INVALID != hNode)
  385. {
  386. //
  387. // update the detection status result of this item
  388. //
  389. ItemList.AddDetectResult(
  390. hNode,
  391. DetStatus[C_INDEX_STATUS_INSTALLED],
  392. DetStatus[C_INDEX_STATUS_UPTODATE],
  393. DetStatus[C_INDEX_STATUS_NEWVERSION],
  394. DetStatus[C_INDEX_STATUS_EXCLUDED],
  395. DetStatus[C_INDEX_STATUS_FORCE],
  396. DetStatus[C_INDEX_STATUS_COMPUTER]
  397. );
  398. ItemList.SafeCloseHandleNode(hNode);
  399. }
  400. }
  401. }
  402. SafeReleaseNULL(pCurNode);
  403. } // end of this item
  404. //SafeReleaseNULL(pCurNode); // in case it's not item node
  405. } // end of non-empty node list of this provider
  406. //
  407. // finished processing the current provider
  408. //
  409. SafeReleaseNULL(pProvChildList);
  410. SafeReleaseNULL(pCurProvider);
  411. //
  412. // try to get a hold of the next provider
  413. //
  414. (void) pProviderList->nextNode(&pCurProvider);
  415. } // end of iterating provider list
  416. //
  417. // output the detection reuslt as an item list
  418. //
  419. ItemList.GetItemsBSTR(pbstrXmlItems);
  420. LOG_XML(_T("Result=%s"), *pbstrXmlItems);
  421. //
  422. // done
  423. //
  424. SafeReleaseNULL(pProviderList);
  425. return S_OK;
  426. }