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.

968 lines
22 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: History.CPP
  6. // Author: Charles Ma, 10/13/2000
  7. //
  8. // Revision History:
  9. //
  10. //
  11. //
  12. // Description:
  13. //
  14. // Class to handle history log
  15. //
  16. //=======================================================================
  17. #include "iuengine.h"
  18. #include <iucommon.h>
  19. #include <fileutil.h>
  20. #include <StringUtil.h>
  21. #include <shlwapi.h> // for PathAppend() API
  22. #include "history.h"
  23. const TCHAR C_V3_LOG_FILE[] = _T("wuhistv3.log");
  24. const TCHAR C_LOG_FILE[] = _T("iuhist.xml");
  25. const TCHAR C_LOG_FILE_CORP[] = _T("iuhist_catalog.xml");
  26. const TCHAR C_LOG_FILE_CORP_ADMIN[] = _T("iuhist_catalogAdmin.xml");
  27. const OLECHAR C_IU_CORP_SITE[] = L"IU_CORP_SITE";
  28. const OLECHAR C_HISTORICALSPEED[] = L"GetHistoricalSpeed";
  29. //
  30. // we use a global mutex name to let all clients, including services
  31. // on terminal servers gain exclusive access for updating history on disk
  32. //
  33. #if defined(UNICODE) || defined(_UNICODE)
  34. const TCHAR C_MUTEX_NAME[] = _T("Global\\6D7495AB-399E-4768-89CC-9444202E8412");
  35. #else
  36. const TCHAR C_MUTEX_NAME[] = _T("6D7495AB-399E-4768-89CC-9444202E8412");
  37. #endif
  38. #define CanSaveHistory (NULL != m_hMutex)
  39. #define ReturnFailedAllocSetHrMsg(x) {if (NULL == (x)) {hr = E_OUTOFMEMORY; LOG_ErrorMsg(hr); return hr;}}
  40. CIUHistory::CIUHistory()
  41. : m_pszDownloadBasePath(NULL),
  42. m_bstrCurrentClientName(NULL)
  43. {
  44. LOG_Block("CIUHisotry::CIUHistory()");
  45. m_pxmlExisting = new CXmlItems(TRUE);
  46. m_pxmlDownload = new CXmlItems(FALSE);
  47. m_pxmlInstall = new CXmlItems(FALSE);
  48. m_hMutex = CreateMutex(
  49. NULL, // no security descriptor
  50. FALSE, // mutex object not owned, yet
  51. C_MUTEX_NAME
  52. );
  53. if (NULL == m_hMutex)
  54. {
  55. DWORD dwErr = GetLastError();
  56. LOG_ErrorMsg(dwErr);
  57. m_ErrorCode = HRESULT_FROM_WIN32(GetLastError());
  58. }
  59. else
  60. {
  61. LOG_Out(_T("Mutex created okay"));
  62. m_ErrorCode = S_OK;
  63. }
  64. m_fSavePending = FALSE;
  65. }
  66. CIUHistory::~CIUHistory()
  67. {
  68. if (m_fSavePending)
  69. {
  70. SaveHistoryToDisk();
  71. }
  72. if (CanSaveHistory)
  73. {
  74. CloseHandle(m_hMutex);
  75. }
  76. if (NULL != m_pxmlExisting)
  77. {
  78. delete m_pxmlExisting;
  79. }
  80. if (NULL != m_pxmlDownload)
  81. {
  82. delete m_pxmlDownload;
  83. }
  84. if (NULL != m_pxmlInstall)
  85. {
  86. delete m_pxmlInstall;
  87. }
  88. SafeHeapFree(m_pszDownloadBasePath);
  89. SysFreeString(m_bstrCurrentClientName);
  90. }
  91. // ------------------------------------------------------------------
  92. //
  93. // public function SetDownloadBasePath()
  94. // this function should be called before AddHistoryItemDownloadStatus()
  95. // for corporate case to set the download path that the user has input,
  96. // so that we know where to save the history log.
  97. //
  98. // ------------------------------------------------------------------
  99. HRESULT CIUHistory::SetDownloadBasePath(LPCTSTR pszDownloadedBasePath)
  100. {
  101. LOG_Block("SetDownloadBasePath()");
  102. if (NULL != pszDownloadedBasePath)
  103. {
  104. HRESULT hr = S_OK;
  105. if (NULL != m_pszDownloadBasePath)
  106. {
  107. //
  108. // most likely user called SetDownloadBasePath() at least twice
  109. // within the same instance of this class
  110. //
  111. SafeHeapFree(m_pszDownloadBasePath);
  112. }
  113. m_pszDownloadBasePath = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof (TCHAR));
  114. if (NULL == m_pszDownloadBasePath)
  115. {
  116. LOG_ErrorMsg(E_OUTOFMEMORY);
  117. return E_OUTOFMEMORY;
  118. }
  119. hr = StringCchCopyEx(m_pszDownloadBasePath, MAX_PATH, pszDownloadedBasePath,
  120. NULL, NULL, MISTSAFE_STRING_FLAGS);
  121. if (FAILED(hr))
  122. {
  123. SafeHeapFree(m_pszDownloadBasePath);
  124. LOG_ErrorMsg(hr);
  125. return hr;
  126. }
  127. BSTR bstrCorpSite = SysAllocString(C_IU_CORP_SITE);
  128. SetClientName(bstrCorpSite);
  129. SafeSysFreeString(bstrCorpSite);
  130. }
  131. return S_OK;
  132. }
  133. // ------------------------------------------------------------------
  134. //
  135. // public function AddHistoryItemDownloadStatus()
  136. // this function should be called when you want to record the
  137. // download status of this item. A new history item will be
  138. // added to the history file
  139. //
  140. // ------------------------------------------------------------------
  141. HRESULT CIUHistory::AddHistoryItemDownloadStatus(
  142. CXmlCatalog* pCatalog,
  143. HANDLE_NODE hCatalogItem, // a handle points to node in catalog
  144. _HISTORY_STATUS enDownloadStatus,
  145. LPCTSTR lpcszDownloadedTo,
  146. LPCTSTR lpcszClient,
  147. DWORD dwErrorCode /*= 0*/
  148. )
  149. {
  150. LOG_Block("AddHistoryItemDownloadStatus()");
  151. HRESULT hr = S_OK;
  152. HANDLE_NODE hDownloadItem = HANDLE_NODE_INVALID;
  153. ReturnFailedAllocSetHrMsg(m_pxmlDownload);
  154. if (NULL == lpcszClient || _T('\0') == lpcszClient[0])
  155. {
  156. hr = E_INVALIDARG;
  157. LOG_ErrorMsg(hr);
  158. return hr;
  159. }
  160. if (!CanSaveHistory)
  161. {
  162. return m_ErrorCode;
  163. }
  164. BSTR bstrDownloadedTo = NULL;
  165. BSTR bstrClient = T2BSTR(lpcszClient);
  166. BSTR bstrDownloadStatus = GetBSTRStatus(enDownloadStatus);
  167. //
  168. // append a new node
  169. //
  170. hr = m_pxmlDownload->AddItem(pCatalog, hCatalogItem, &hDownloadItem);
  171. if (SUCCEEDED(hr))
  172. {
  173. m_pxmlDownload->AddTimeStamp(hDownloadItem);
  174. if (0 != dwErrorCode)
  175. {
  176. m_pxmlDownload->AddDownloadStatus(hDownloadItem, bstrDownloadStatus, dwErrorCode);
  177. }
  178. else
  179. {
  180. m_pxmlDownload->AddDownloadStatus(hDownloadItem, bstrDownloadStatus);
  181. }
  182. bstrDownloadedTo = T2BSTR(lpcszDownloadedTo);
  183. m_pxmlDownload->AddDownloadPath(hDownloadItem, bstrDownloadedTo);
  184. m_pxmlDownload->AddClientInfo(hDownloadItem, bstrClient);
  185. m_pxmlDownload->CloseItem(hDownloadItem);
  186. m_fSavePending = TRUE;
  187. }
  188. SetClientName(bstrClient);
  189. SysFreeString(bstrDownloadedTo);
  190. SysFreeString(bstrClient);
  191. SysFreeString(bstrDownloadStatus);
  192. return hr;
  193. }
  194. // ------------------------------------------------------------------
  195. //
  196. // public function AddHistoryItemInstallStatus()
  197. // this function should be called when you want to record the
  198. // install status of this item. This function will go to the
  199. // existing history tree and find the first item that matches
  200. // the identity of hCatalogItem, and assume that one as
  201. // the one you want to modify the install status
  202. //
  203. //
  204. // return:
  205. // HRESULT - S_OK if succeeded
  206. // - E_HANDLE if can't find hCatalogItem from
  207. // the current history log tree
  208. // - or other HRESULT error
  209. //
  210. // ------------------------------------------------------------------
  211. HRESULT CIUHistory::AddHistoryItemInstallStatus(
  212. CXmlCatalog* pCatalog,
  213. HANDLE_NODE hCatalogItem, // a handle points to node in catalog
  214. _HISTORY_STATUS enInstallStatus,
  215. LPCTSTR lpcszClient,
  216. BOOL fNeedsReboot,
  217. DWORD dwErrorCode /*= 0*/
  218. )
  219. {
  220. LOG_Block("AddHistoryItemInstallStatus()");
  221. HRESULT hr = S_OK;
  222. HANDLE_NODE hInstallItem = HANDLE_NODE_INVALID;
  223. ReturnFailedAllocSetHrMsg(m_pxmlInstall);
  224. if (!CanSaveHistory)
  225. {
  226. return m_ErrorCode;
  227. }
  228. BSTR bstrClient = NULL;
  229. BSTR bstrInstallStatus = GetBSTRStatus(enInstallStatus);
  230. //
  231. // append a new node
  232. //
  233. hr = m_pxmlInstall->AddItem(pCatalog, hCatalogItem, &hInstallItem);
  234. if (SUCCEEDED(hr))
  235. {
  236. m_pxmlInstall->AddTimeStamp(hInstallItem);
  237. if (0 != dwErrorCode)
  238. {
  239. m_pxmlInstall->AddInstallStatus(hInstallItem, bstrInstallStatus, fNeedsReboot, dwErrorCode);
  240. }
  241. else
  242. {
  243. m_pxmlInstall->AddInstallStatus(hInstallItem, bstrInstallStatus, fNeedsReboot);
  244. }
  245. bstrClient = T2BSTR(lpcszClient);
  246. m_pxmlInstall->AddClientInfo(hInstallItem, bstrClient);
  247. m_pxmlInstall->CloseItem(hInstallItem);
  248. m_fSavePending = TRUE;
  249. }
  250. SysFreeString(bstrClient);
  251. SysFreeString(bstrInstallStatus);
  252. return hr;
  253. }
  254. // ------------------------------------------------------------------
  255. //
  256. // public function UpdateHistoryItemInstallStatus()
  257. // this function should be called when you want to record the
  258. // install status of this item. This function will go to the
  259. // existing history tree and find the first item that matches
  260. // the identity of hCatalogItem, and assume that one as
  261. // the one you want to modify the install status
  262. //
  263. //
  264. // return:
  265. // HRESULT - S_OK if succeeded
  266. // - E_HANDLE if can't find hCatalogItem from
  267. // the current history log tree
  268. // - or other HRESULT error
  269. //
  270. // ------------------------------------------------------------------
  271. HRESULT CIUHistory::UpdateHistoryItemInstallStatus(
  272. CXmlCatalog* pCatalog,
  273. HANDLE_NODE hCatalogItem, // a handle points to node in catalog
  274. _HISTORY_STATUS enInstallStatus,
  275. BOOL fNeedsReboot,
  276. DWORD dwErrorCode /*= 0*/
  277. )
  278. {
  279. LOG_Block("UpdateHistoryItemInstallStatus()");
  280. HRESULT hr = S_OK;
  281. HANDLE_NODE hInstallItem = HANDLE_NODE_INVALID;
  282. ReturnFailedAllocSetHrMsg(m_pxmlInstall);
  283. if (!CanSaveHistory)
  284. {
  285. return m_ErrorCode;
  286. }
  287. BSTR bstrInstallStatus = GetBSTRStatus(enInstallStatus);
  288. //
  289. // append a new node
  290. //
  291. hr = m_pxmlInstall->FindItem(pCatalog, hCatalogItem, &hInstallItem);
  292. if (SUCCEEDED(hr))
  293. {
  294. m_pxmlInstall->AddTimeStamp(hInstallItem);
  295. if (0 != dwErrorCode)
  296. {
  297. m_pxmlInstall->UpdateItemInstallStatus(hInstallItem, bstrInstallStatus, fNeedsReboot, dwErrorCode);
  298. }
  299. else
  300. {
  301. m_pxmlInstall->UpdateItemInstallStatus(hInstallItem, bstrInstallStatus, fNeedsReboot);
  302. }
  303. m_pxmlInstall->CloseItem(hInstallItem);
  304. m_fSavePending = TRUE;
  305. }
  306. SysFreeString(bstrInstallStatus);
  307. return hr;
  308. }
  309. /*
  310. // ------------------------------------------------------------------
  311. //
  312. // public function RetrieveItemDownloadPath()
  313. // this function will go to the existing history tree and find
  314. // the first item that matches the identity of hCatalogItem, and
  315. // assume that's the one you want to retrieve the download path from
  316. //
  317. // return:
  318. // HRESULT - S_OK if succeeded
  319. // - E_HANDLE if can't find hCatalogItem from
  320. // the current history log tree
  321. // - or other HRESULT error
  322. //
  323. // ------------------------------------------------------------------
  324. HRESULT CIUHistory::RetrieveItemDownloadPath(
  325. CXmlCatalog* pCatalog,
  326. HANDLE_NODE hCatalogItem, // a handle points to node in catalog
  327. BSTR* pbstrDownloadPath
  328. )
  329. {
  330. HRESULT hr = S_OK;
  331. if (NULL == m_Existing.'DocumentPtr())
  332. {
  333. //
  334. // need to read the existing history
  335. //
  336. WaitForSingleObject(m_hMutex, INFINITE);
  337. hr = ReadHistoryFromDisk(NULL);
  338. if (FAILED(hr))
  339. {
  340. //
  341. // if we can't load the existing history
  342. // we can't do anything here
  343. //
  344. ReleaseMutex(m_hMutex);
  345. return hr;
  346. }
  347. ReleaseMutex(m_hMutex);
  348. }
  349. hr = m_Existing.GetItemDownloadPath(pCatalog, hCatalogItem, pbstrDownloadPath);
  350. return hr;
  351. }
  352. */
  353. // ------------------------------------------------------------------
  354. //
  355. // public function ReadHistoryFromDisk()
  356. // this function will read the history from the given file
  357. //
  358. // if the file path is NULL, assumes default IU log file locally
  359. //
  360. // ------------------------------------------------------------------
  361. HRESULT CIUHistory::ReadHistoryFromDisk(LPCTSTR lpszLogFile, BOOL fCorpAdmin /*= FALSE*/)
  362. {
  363. LOG_Block("ReadHistoryFromDisk()");
  364. HRESULT hr = S_OK;
  365. TCHAR szLogPath[MAX_PATH];
  366. ReturnFailedAllocSetHrMsg(m_pxmlExisting);
  367. //
  368. // check to see if we use designated path (comsumer)
  369. // or user-specified path (corporate)
  370. //
  371. if ((NULL == lpszLogFile || _T('\0') == lpszLogFile[0]) && !fCorpAdmin)
  372. {
  373. GetIndustryUpdateDirectory(szLogPath);
  374. hr = PathCchAppend(szLogPath, ARRAYSIZE(szLogPath), C_LOG_FILE);
  375. if (FAILED(hr))
  376. {
  377. LOG_ErrorMsg(hr);
  378. return hr;
  379. }
  380. }
  381. else
  382. {
  383. //
  384. // this is corporate case to read log file from
  385. // a server location
  386. //
  387. if (fCorpAdmin)
  388. {
  389. GetIndustryUpdateDirectory(szLogPath);
  390. hr = PathCchAppend(szLogPath, ARRAYSIZE(szLogPath), C_LOG_FILE_CORP_ADMIN);
  391. if (FAILED(hr))
  392. {
  393. LOG_ErrorMsg(hr);
  394. return hr;
  395. }
  396. }
  397. else
  398. {
  399. hr = StringCchCopyEx(szLogPath, ARRAYSIZE(szLogPath), lpszLogFile,
  400. NULL, NULL, MISTSAFE_STRING_FLAGS);
  401. if (FAILED(hr))
  402. {
  403. LOG_ErrorMsg(hr);
  404. return hr;
  405. }
  406. hr = PathCchAppend(szLogPath, ARRAYSIZE(szLogPath), C_LOG_FILE_CORP);
  407. if (FAILED(hr))
  408. {
  409. LOG_ErrorMsg(hr);
  410. return hr;
  411. }
  412. }
  413. }
  414. //
  415. // if we are not passing in the class file path buffer,
  416. // then update the class path buffer with this new path
  417. //
  418. if (szLogPath != m_szLogFilePath)
  419. {
  420. hr = StringCchCopyEx(m_szLogFilePath, ARRAYSIZE(m_szLogFilePath), szLogPath,
  421. NULL, NULL, MISTSAFE_STRING_FLAGS);
  422. if (FAILED(hr))
  423. {
  424. LOG_ErrorMsg(hr);
  425. return hr;
  426. }
  427. }
  428. //
  429. // load the xml file
  430. //
  431. m_pxmlExisting->Clear();
  432. BSTR bstrLogPath = T2BSTR(szLogPath);
  433. hr = m_pxmlExisting->LoadXMLDocumentFile(bstrLogPath);
  434. SysFreeString(bstrLogPath);
  435. return hr;
  436. }
  437. // ------------------------------------------------------------------
  438. //
  439. // public function SaveHistoryToDisk()
  440. // this function will re-read the history in exclusive mode, and
  441. // merge the newly added data to the tree (so we don't overwrite
  442. // new changes made by other instances of this control) and
  443. // write it back
  444. //
  445. // ------------------------------------------------------------------
  446. HRESULT CIUHistory::SaveHistoryToDisk(void)
  447. {
  448. LOG_Block("SaveHistoryToDisk()");
  449. HRESULT hr = S_OK, hr2 = S_OK;
  450. BSTR bstrLogFilePath = NULL;
  451. ReturnFailedAllocSetHrMsg(m_pxmlExisting);
  452. ReturnFailedAllocSetHrMsg(m_pxmlDownload);
  453. ReturnFailedAllocSetHrMsg(m_pxmlInstall);
  454. if (!CanSaveHistory)
  455. {
  456. return m_ErrorCode;
  457. }
  458. if (!m_fSavePending)
  459. {
  460. //
  461. // nothing to save
  462. //
  463. return S_OK;
  464. }
  465. //
  466. // first, we need to gain exclusive access
  467. // to the log file before reading it
  468. //
  469. // since this is not a long process, so I
  470. // don't think we need to take care of WM_QUIT
  471. // message
  472. //
  473. WaitForSingleObject(m_hMutex, INFINITE);
  474. BSTR bstrCorpSite = SysAllocString(C_IU_CORP_SITE);
  475. ReturnFailedAllocSetHrMsg(bstrCorpSite);
  476. if (!CompareBSTRsEqual(bstrCorpSite, m_bstrCurrentClientName))
  477. {
  478. SysFreeString(bstrCorpSite);
  479. //
  480. // re-read history file
  481. //
  482. hr = ReadHistoryFromDisk(NULL);
  483. //
  484. // comment out...if we get failure on reading,
  485. // we recreate a new history file later when saving.
  486. //
  487. //if (FAILED(hr))
  488. //{
  489. // //
  490. // // if we can't load the existing history
  491. // // we can't do anything here
  492. // //
  493. // ReleaseMutex(m_hMutex);
  494. // return hr;
  495. //}
  496. //
  497. // merge changes:
  498. //
  499. // loop through m_Download, insert each node to top of m_Existing
  500. //
  501. hr = m_pxmlExisting->MergeItemDownloaded(m_pxmlDownload);
  502. if (FAILED(hr))
  503. {
  504. ReleaseMutex(m_hMutex);
  505. return hr;
  506. }
  507. //
  508. // loop through m_Install, for each node in m_Install
  509. // find the one in m_Existing, update install status
  510. //
  511. hr = m_pxmlExisting->UpdateItemInstalled(m_pxmlInstall);
  512. if (FAILED(hr))
  513. {
  514. ReleaseMutex(m_hMutex);
  515. return hr;
  516. }
  517. //
  518. // save the xml file
  519. //
  520. bstrLogFilePath = T2BSTR(m_szLogFilePath);
  521. hr = m_pxmlExisting->SaveXMLDocument(bstrLogFilePath);
  522. SafeSysFreeString(bstrLogFilePath);
  523. if (SUCCEEDED(hr))
  524. {
  525. m_fSavePending = FALSE;
  526. }
  527. }
  528. else
  529. {
  530. //
  531. // this is the corporate case...
  532. //
  533. SysFreeString(bstrCorpSite);
  534. if (NULL != m_pszDownloadBasePath && _T('\0') != m_pszDownloadBasePath[0])
  535. {
  536. //
  537. // re-read corp history from download base folder
  538. //
  539. ReadHistoryFromDisk(m_pszDownloadBasePath);
  540. //
  541. // merge new items downloaded
  542. //
  543. hr = m_pxmlExisting->MergeItemDownloaded(m_pxmlDownload);
  544. if (FAILED(hr))
  545. {
  546. ReleaseMutex(m_hMutex);
  547. return hr;
  548. }
  549. //
  550. // save the xml file
  551. //
  552. bstrLogFilePath = T2BSTR(m_szLogFilePath);
  553. hr = m_pxmlExisting->SaveXMLDocument(bstrLogFilePath);
  554. SafeSysFreeString(bstrLogFilePath);
  555. }
  556. //
  557. // re-read corp admin history from windowsupdate folder
  558. //
  559. ReadHistoryFromDisk(m_pszDownloadBasePath, TRUE);
  560. //
  561. // merge new items downloaded
  562. //
  563. hr2 = m_pxmlExisting->MergeItemDownloaded(m_pxmlDownload);
  564. if (FAILED(hr2))
  565. {
  566. ReleaseMutex(m_hMutex);
  567. return hr2;
  568. }
  569. //
  570. // save the xml file
  571. //
  572. bstrLogFilePath = T2BSTR(m_szLogFilePath);
  573. hr2 = m_pxmlExisting->SaveXMLDocument(bstrLogFilePath);
  574. SafeSysFreeString(bstrLogFilePath);
  575. if (SUCCEEDED(hr) && SUCCEEDED(hr2))
  576. {
  577. m_fSavePending = FALSE;
  578. }
  579. }
  580. ReleaseMutex(m_hMutex);
  581. SysFreeString(bstrLogFilePath);
  582. hr = SUCCEEDED(hr) ? hr2 : hr;
  583. return hr;
  584. }
  585. // ------------------------------------------------------------------
  586. //
  587. // public function to set the client name
  588. //
  589. // a client name is used to put in history to denode who
  590. // caused download/install happened.
  591. //
  592. // ------------------------------------------------------------------
  593. void CIUHistory::SetClientName(BSTR bstrClientName)
  594. {
  595. if (NULL != m_bstrCurrentClientName)
  596. {
  597. SysFreeString(m_bstrCurrentClientName);
  598. m_bstrCurrentClientName = NULL;
  599. }
  600. if (NULL != bstrClientName)
  601. {
  602. m_bstrCurrentClientName = SysAllocString(bstrClientName);
  603. }
  604. }
  605. // ------------------------------------------------------------------
  606. //
  607. // public function GetHistory
  608. //
  609. // read the current history XML file and convert it
  610. // into bstr to pass out
  611. //
  612. // ------------------------------------------------------------------
  613. HRESULT CIUHistory::GetHistoryStr(
  614. LPCTSTR lpszLogFile,
  615. BSTR BeginDateTime,
  616. BSTR EndDateTime,
  617. BSTR* pbstrHistory)
  618. {
  619. LOG_Block("GetHistoryStr()");
  620. HRESULT hr = S_OK;
  621. ReturnFailedAllocSetHrMsg(m_pxmlExisting);
  622. //
  623. // need to read the existing history
  624. //
  625. WaitForSingleObject(m_hMutex, INFINITE);
  626. BSTR bstrCorpSite = SysAllocString(C_IU_CORP_SITE);
  627. if (bstrCorpSite == NULL)
  628. {
  629. hr = E_OUTOFMEMORY;
  630. goto done;
  631. }
  632. if (CompareBSTRsEqual(bstrCorpSite, m_bstrCurrentClientName))
  633. {
  634. TCHAR szLogPath[MAX_PATH];
  635. TCHAR szLogFileParam[MAX_PATH];
  636. if (lpszLogFile != NULL && lpszLogFile[0] != _T('\0'))
  637. {
  638. hr = StringCchCopyEx(szLogFileParam, ARRAYSIZE(szLogFileParam), lpszLogFile,
  639. NULL, NULL, MISTSAFE_STRING_FLAGS);
  640. if (FAILED(hr))
  641. {
  642. LOG_ErrorMsg(hr);
  643. goto done;
  644. }
  645. hr = PathCchAddBackslash(szLogFileParam, ARRAYSIZE(szLogFileParam));
  646. if (FAILED(hr))
  647. {
  648. LOG_ErrorMsg(hr);
  649. goto done;
  650. }
  651. }
  652. else
  653. {
  654. szLogFileParam[0] = _T('\0');
  655. }
  656. //
  657. // corporate case
  658. //
  659. GetIndustryUpdateDirectory(szLogPath);
  660. if (_T('\0') == szLogFileParam[0] || !lstrcmpi(szLogPath, szLogFileParam))
  661. {
  662. // corp admin history
  663. hr = ReadHistoryFromDisk(szLogPath, TRUE);
  664. }
  665. else
  666. {
  667. // corp history
  668. hr = ReadHistoryFromDisk(lpszLogFile);
  669. }
  670. }
  671. else
  672. {
  673. HRESULT hrAppend;
  674. //
  675. // consumer case
  676. //
  677. hr = ReadHistoryFromDisk(NULL);
  678. //
  679. // migrate V3 history to iuhist.xml
  680. // - if succeeded, save the updated iuhist.xml file and delete wuhistv3.log
  681. // - if failed, just log error and keep using the current iuhist.xml
  682. //
  683. TCHAR szLogPath[MAX_PATH];
  684. GetWindowsUpdateV3Directory(szLogPath);
  685. hrAppend = PathCchAppend(szLogPath, ARRAYSIZE(szLogPath), C_V3_LOG_FILE);
  686. if (FAILED(hrAppend))
  687. {
  688. LOG_ErrorMsg(hrAppend);
  689. if (SUCCEEDED(hr))
  690. hr = hrAppend;
  691. goto done;
  692. }
  693. if (0xffffffff != GetFileAttributes(szLogPath))
  694. {
  695. // V3 history file "wuhistv3.log" exists, so start migration
  696. if (FAILED(m_pxmlExisting->MigrateV3History(szLogPath)))
  697. {
  698. LOG_Out(_T("Failed to migrate v3 consumer history"));
  699. }
  700. else
  701. {
  702. BSTR bstrLogFilePath = T2BSTR(m_szLogFilePath);
  703. if (FAILED(m_pxmlExisting->SaveXMLDocument(bstrLogFilePath)))
  704. {
  705. LOG_Out(_T("Failed to save the updated history file %s"), m_szLogFilePath);
  706. }
  707. else
  708. {
  709. DeleteFile(szLogPath);
  710. }
  711. SafeSysFreeString(bstrLogFilePath);
  712. }
  713. }
  714. }
  715. done:
  716. ReleaseMutex(m_hMutex);
  717. SafeSysFreeString(bstrCorpSite);
  718. if (FAILED(hr))
  719. {
  720. //
  721. // if we can't load the existing history
  722. // we can't do anything here. Return empty string.
  723. //
  724. *pbstrHistory = SysAllocString(L"");
  725. LOG_Out(_T("Loading the history xml file failed"));
  726. return S_FALSE;
  727. }
  728. //
  729. // traverse history tree, inspect each node
  730. // to see if time/clientName fit. If not, delete it
  731. // then output the string
  732. //
  733. hr = m_pxmlExisting->GetFilteredHistoryBSTR(BeginDateTime, EndDateTime, m_bstrCurrentClientName, pbstrHistory);
  734. return hr;
  735. }
  736. // *****************************************************************
  737. //
  738. // IUENGINE.DLL Public API:
  739. //
  740. // *****************************************************************
  741. HRESULT WINAPI CEngUpdate::GetHistory(
  742. BSTR bstrDateTimeFrom,
  743. BSTR bstrDateTimeTo,
  744. BSTR bstrClient,
  745. BSTR bstrPath,
  746. BSTR* pbstrLog)
  747. {
  748. LOG_Block("GetHistory()");
  749. USES_IU_CONVERSION;
  750. HRESULT hr = S_OK;
  751. BSTR bsStart = NULL;
  752. BSTR bsEnd = NULL;
  753. CIUHistory cHistory;
  754. //
  755. // first, check to see if this is to ask historical speed
  756. //
  757. if (NULL != bstrClient && lstrcmpiW(C_HISTORICALSPEED, (LPWSTR)((LPOLESTR) bstrClient)) == 0)
  758. {
  759. HKEY hKey = NULL;
  760. TCHAR szSpeed[32];
  761. DWORD dwSpeed = 0x0;
  762. DWORD dwSize = sizeof(dwSpeed);
  763. LONG lResult = ERROR_SUCCESS;
  764. //
  765. // get speed here from reg; if failure, dwSpeed remains to be 0.
  766. //
  767. if (ERROR_SUCCESS == (lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, 0, KEY_READ, &hKey)))
  768. {
  769. lResult = RegQueryValueEx(hKey, REGVAL_HISTORICALSPEED, NULL, NULL, (LPBYTE)&dwSpeed, &dwSize);
  770. RegCloseKey(hKey);
  771. if (ERROR_SUCCESS != lResult)
  772. {
  773. *pbstrLog = SysAllocString(L"0");
  774. LOG_Out(_T("GetHistoricalSpeed registry key not found, it must be no downloads happened yet"));
  775. return hr;
  776. }
  777. }
  778. else
  779. {
  780. *pbstrLog = SysAllocString(L"0");
  781. LOG_ErrorMsg((DWORD)lResult);
  782. return hr;
  783. }
  784. hr = StringCchPrintfEx(szSpeed, ARRAYSIZE(szSpeed), NULL, NULL, MISTSAFE_STRING_FLAGS,
  785. _T("%d"), dwSpeed);
  786. if (FAILED(hr))
  787. {
  788. *pbstrLog = SysAllocString(L"0");
  789. LOG_ErrorMsg(hr);
  790. return hr;
  791. }
  792. *pbstrLog = SysAllocString(T2OLE(szSpeed));
  793. LOG_Out(_T("GetHistoricalSpeed get called! Return value %s"), szSpeed);
  794. return hr;
  795. }
  796. //
  797. // really asking history log
  798. //
  799. //
  800. // set the client name
  801. //
  802. if (NULL != bstrClient && SysStringLen(bstrClient) > 0)
  803. {
  804. LOG_Out(_T("Set client name as %s"), OLE2T(bstrClient));
  805. cHistory.SetClientName(bstrClient);
  806. }
  807. else
  808. {
  809. LOG_Out(_T("Set client name as NULL"));
  810. cHistory.SetClientName(NULL);
  811. }
  812. //
  813. // for script: they may pass empty string. we treat them
  814. // as NULL
  815. //
  816. if (NULL != bstrDateTimeFrom && SysStringLen(bstrDateTimeFrom) > 0)
  817. {
  818. LOG_Out(_T("DateTimeFrom=%s"), OLE2T(bstrDateTimeFrom));
  819. bsStart = bstrDateTimeFrom;
  820. }
  821. if (NULL != bstrDateTimeTo && SysStringLen(bstrDateTimeTo) > 0)
  822. {
  823. LOG_Out(_T("DateTimeTo=%s"), OLE2T(bstrDateTimeTo));
  824. bsEnd = bstrDateTimeTo;
  825. }
  826. //
  827. // we do NOT validate the format of these two date/time strings.
  828. // They are supposed to be in XML datetime format. If not, then
  829. // the returned history logs may be filtered incorrectly.
  830. //
  831. hr = cHistory.GetHistoryStr(OLE2T(bstrPath), bsStart, bsEnd, pbstrLog);
  832. SysFreeString(bsStart);
  833. SysFreeString(bsEnd);
  834. return hr;
  835. }