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.

1304 lines
38 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. History.cpp
  5. Abstract:
  6. This file contains the implementation of the CHCPHistory class,
  7. which implements the data collection functionality.
  8. Revision History:
  9. Davide Massarenti (Dmassare) 07/22/99
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. #include "strsafe.h"
  14. /////////////////////////////////////////////////////////////////////////////
  15. #define SAFETY_LIMIT_UPPER (10*1024*1024)
  16. #define SAFETY_LIMIT_LOWER ( 5*1024*1024)
  17. #define DATABASE_VERSION (1)
  18. #define TEXT_INDEX L"history_db.xml"
  19. #define TEXT_TAG_HC_HISTORY L"HC_History"
  20. #define TEXT_ATTR_HC_VERSION L"Version"
  21. #define TEXT_ATTR_HC_SEQ L"Sequence"
  22. #define TEXT_ATTR_HC_TIMESTAMP L"Timestamp"
  23. #define TEXT_TAG_CIM L"CIM"
  24. #define TEXT_TAG_PROVIDER L"Provider"
  25. #define TEXT_ATTR_PROVIDER_NAMESPACE L"Namespace"
  26. #define TEXT_ATTR_PROVIDER_CLASS L"Class"
  27. #define TEXT_TAG_CD L"CollectedData"
  28. #define TEXT_ATTR_CD_FILE L"File"
  29. #define TEXT_ATTR_CD_SEQ L"Sequence"
  30. #define TEXT_ATTR_CD_CRC L"CRC"
  31. #define TEXT_ATTR_CD_TIMESTAMP_T0 L"Timestamp_T0"
  32. #define TEXT_ATTR_CD_TIMESTAMP_T1 L"Timestamp_T1"
  33. #define TEXT_TAG_DATASPEC L"DataSpec"
  34. #define TEXT_TAG_WQL L"WQL"
  35. #define TEXT_ATTR_WQL_NAMESPACE L"Namespace"
  36. #define TEXT_ATTR_WQL_CLASS L"Class"
  37. /////////////////////////////////////////////////////////////////////////////
  38. typedef std::list< MPC::wstring > FileList;
  39. typedef FileList::iterator FileIter;
  40. typedef FileList::const_iterator FileIterConst;
  41. class CompareNocase
  42. {
  43. MPC::NocaseCompare m_cmp;
  44. MPC::wstring& m_str;
  45. public:
  46. explicit CompareNocase( MPC::wstring& str ) : m_str(str) {}
  47. bool operator()( const MPC::wstring& str ) { return m_cmp( str, m_str ); }
  48. };
  49. /////////////////////////////////////////////////////////////////////////////
  50. static HRESULT Local_ConvertDateToString( /*[in] */ DATE dDate ,
  51. /*[out]*/ MPC::wstring& szDate )
  52. {
  53. //
  54. // Use CIM conversion.
  55. //
  56. return MPC::ConvertDateToString( dDate, szDate, /*fGMT*/false, /*fCIM*/true, 0 );
  57. }
  58. static HRESULT Local_ConvertStringToDate( /*[in] */ const MPC::wstring& szDate ,
  59. /*[out]*/ DATE& dDate )
  60. {
  61. return MPC::ConvertStringToDate( szDate, dDate, /*fGMT*/false, /*fCIM*/true, 0 );
  62. }
  63. ////////////////////////////////////////////////////////////////////////////////
  64. /////////////////////////////////////////////////////////////////////////////
  65. /////////////////////////////////////////////////////////////////////////////
  66. /////////////////////////////////////////////////////////////////////////////
  67. //
  68. // WMIHistory::Data Class
  69. //
  70. /////////////////////////////////////////////////////////////////////////////
  71. WMIHistory::Data::Data( /*[in]*/ Provider* wmihp )
  72. {
  73. m_wmihp = wmihp; // Provider* m_wmihp;
  74. // MPC::wstring m_szFile;
  75. m_lSequence = wmihp->m_wmihd->m_lSequence_Latest; // LONG m_lSequence;
  76. m_dwCRC = 0; // DWORD m_dwCRC;
  77. m_dTimestampT0 = 0; // DATE m_dTimestampT0;
  78. m_dTimestampT1 = 0; // DATE m_dTimestampT1;
  79. m_fDontDelete = false; // bool m_fDontDelete;
  80. }
  81. WMIHistory::Data::~Data()
  82. {
  83. if(m_fDontDelete == false)
  84. {
  85. MPC::wstring szFile( m_szFile ); m_wmihp->m_wmihd->GetFullPathName( szFile );
  86. (void)MPC::DeleteFile( szFile );
  87. }
  88. }
  89. /////////////////////////////////////////////////////////////////////////////
  90. HRESULT WMIHistory::Data::get_File( /*[out]*/ MPC::wstring& szFile )
  91. {
  92. szFile = m_szFile;
  93. return S_OK;
  94. }
  95. HRESULT WMIHistory::Data::get_Sequence( /*[out]*/ LONG& lSequence )
  96. {
  97. lSequence = m_lSequence;
  98. return S_OK;
  99. }
  100. HRESULT WMIHistory::Data::get_TimestampT0( /*[out]*/ DATE& dTimestampT0 )
  101. {
  102. dTimestampT0 = m_dTimestampT0;
  103. return S_OK;
  104. }
  105. HRESULT WMIHistory::Data::get_TimestampT1( /*[out]*/ DATE& dTimestampT1 )
  106. {
  107. dTimestampT1 = m_dTimestampT1;
  108. return S_OK;
  109. }
  110. /////////////////////////////////////////////////////////////////////////////
  111. bool WMIHistory::Data::IsSnapshot()
  112. {
  113. return (m_dTimestampT1 == 0);
  114. }
  115. /////////////////////////////////////////////////////////////////////////////
  116. HRESULT WMIHistory::Data::LoadCIM( /*[in]*/ MPC::XmlUtil& xml )
  117. {
  118. __HCP_FUNC_ENTRY( "WMIHistory::Data::LoadCIM" );
  119. HRESULT hr;
  120. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihp->m_wmihd->LoadCIM( m_szFile.c_str(), xml, TEXT_TAG_CIM ));
  121. hr = S_OK;
  122. __HCP_FUNC_CLEANUP;
  123. __HCP_FUNC_EXIT(hr);
  124. }
  125. /////////////////////////////////////////////////////////////////////////////
  126. /////////////////////////////////////////////////////////////////////////////
  127. /////////////////////////////////////////////////////////////////////////////
  128. /////////////////////////////////////////////////////////////////////////////
  129. //
  130. // WMIHistory::Provider Class
  131. //
  132. /////////////////////////////////////////////////////////////////////////////
  133. WMIHistory::Provider::Provider( Database* wmihd )
  134. {
  135. m_wmihd = wmihd; // Database* m_wmihd;
  136. // DataList m_lstData;
  137. // DataList m_lstDataTmp;
  138. // MPC::wstring m_szNamespace;
  139. // MPC::wstring m_szClass;
  140. // MPC::wstring m_szWQL;
  141. }
  142. WMIHistory::Provider::~Provider()
  143. {
  144. MPC::CallDestructorForAll( m_lstData );
  145. MPC::CallDestructorForAll( m_lstDataTmp );
  146. }
  147. /////////////////////////////////////////////////////////////////////////////
  148. HRESULT WMIHistory::Provider::enum_Data( /*[out]*/ DataIterConst& itBegin ,
  149. /*[out]*/ DataIterConst& itEnd )
  150. {
  151. itBegin = m_lstData.begin();
  152. itEnd = m_lstData.end ();
  153. return S_OK;
  154. }
  155. HRESULT WMIHistory::Provider::get_Namespace( /*[out]*/ MPC::wstring& szNamespace )
  156. {
  157. szNamespace = m_szNamespace;
  158. return S_OK;
  159. }
  160. HRESULT WMIHistory::Provider::get_Class( /*[out]*/ MPC::wstring& szClass )
  161. {
  162. szClass = m_szClass;
  163. return S_OK;
  164. }
  165. HRESULT WMIHistory::Provider::get_WQL( /*[out]*/ MPC::wstring& szWQL )
  166. {
  167. szWQL = m_szWQL;
  168. return S_OK;
  169. }
  170. /////////////////////////////////////////////////////////////////////////////
  171. HRESULT WMIHistory::Provider::insert_Snapshot( /*[in]*/ Data* wmihpd ,
  172. /*[in]*/ bool fPersist )
  173. {
  174. __HCP_FUNC_ENTRY( "WMIHistory::Provider::insert_Snapshot" );
  175. HRESULT hr;
  176. m_lstData .remove ( wmihpd );
  177. m_lstDataTmp.remove ( wmihpd );
  178. m_lstData .push_front( wmihpd );
  179. //
  180. // If we add a new snapshot, we need to link the first delta to it.
  181. //
  182. if(wmihpd->IsSnapshot())
  183. {
  184. Data* wmihpd_Delta;
  185. __MPC_EXIT_IF_METHOD_FAILS(hr, get_Delta( 0, wmihpd_Delta ));
  186. if(wmihpd_Delta)
  187. {
  188. wmihpd_Delta->m_dTimestampT1 = wmihpd->m_dTimestampT0;
  189. }
  190. }
  191. //
  192. // Only keep the snapshot's file if the flag is set.
  193. //
  194. if(fPersist) wmihpd->m_fDontDelete = true;
  195. hr = S_OK;
  196. __HCP_FUNC_CLEANUP;
  197. __HCP_FUNC_EXIT(hr);
  198. }
  199. HRESULT WMIHistory::Provider::remove_Snapshot( /*[in]*/ Data* wmihpd ,
  200. /*[in]*/ bool fPersist )
  201. {
  202. __HCP_FUNC_ENTRY( "WMIHistory::Provider::remove_Snapshot" );
  203. HRESULT hr;
  204. m_lstData .remove( wmihpd );
  205. m_lstDataTmp.remove( wmihpd );
  206. //
  207. // Only delete the snapshot's file if the flag is set.
  208. //
  209. if(fPersist) wmihpd->m_fDontDelete = false;
  210. delete wmihpd;
  211. hr = S_OK;
  212. __HCP_FUNC_EXIT(hr);
  213. }
  214. /////////////////////////////////////////////////////////////////////////////
  215. HRESULT WMIHistory::Provider::alloc_Snapshot( /*[in] */ MPC::XmlUtil& xmlNode ,
  216. /*[out]*/ Data* & wmihpd )
  217. {
  218. __HCP_FUNC_ENTRY( "WMIHistory::Provider::alloc_Snapshot" );
  219. HRESULT hr;
  220. MPC::wstring szFile;
  221. Data* wmihpdTmp = NULL;
  222. wmihpd = NULL;
  223. //
  224. // Purge deltas if low on disk space.
  225. //
  226. __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureFreeSpace());
  227. //
  228. // Generate a new name.
  229. //
  230. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->GetNewUniqueFileName( szFile ));
  231. //
  232. // Create a new Collected Data object.
  233. //
  234. __MPC_EXIT_IF_ALLOC_FAILS(hr, wmihpdTmp, new Data( this ));
  235. wmihpdTmp->m_szFile = szFile;
  236. wmihpdTmp->m_dTimestampT0 = m_wmihd->m_dTimestamp;
  237. //
  238. // Save it.
  239. //
  240. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->SaveCIM( szFile.c_str(), xmlNode, wmihpdTmp->m_dwCRC ));
  241. m_lstDataTmp.push_back( wmihpdTmp );
  242. //
  243. // Return the pointer to the caller.
  244. //
  245. wmihpd = wmihpdTmp;
  246. wmihpdTmp = NULL;
  247. hr = S_OK;
  248. __HCP_FUNC_CLEANUP;
  249. if(wmihpdTmp) delete wmihpdTmp;
  250. __HCP_FUNC_EXIT(hr);
  251. }
  252. HRESULT WMIHistory::Provider::get_Snapshot( /*[out]*/ Data*& wmihpd )
  253. {
  254. DataIter it;
  255. wmihpd = NULL;
  256. for(it=m_lstData.begin(); it != m_lstData.end(); it++)
  257. {
  258. if((*it)->IsSnapshot())
  259. {
  260. wmihpd = *it;
  261. break;
  262. }
  263. }
  264. return S_OK;
  265. }
  266. HRESULT WMIHistory::Provider::get_Delta( /*[in] */ int iIndex ,
  267. /*[out]*/ Data*& wmihpd )
  268. {
  269. DataIter it;
  270. wmihpd = NULL;
  271. for(it=m_lstData.begin(); it != m_lstData.end(); it++)
  272. {
  273. if((*it)->IsSnapshot() == false)
  274. {
  275. if(iIndex-- == 0)
  276. {
  277. wmihpd = *it;
  278. break;
  279. }
  280. }
  281. }
  282. return S_OK;
  283. }
  284. HRESULT WMIHistory::Provider::get_Date( /*[in] */ DATE dDate ,
  285. /*[out]*/ Data*& wmihpd )
  286. {
  287. DataIter it;
  288. wmihpd = NULL;
  289. for(it=m_lstData.begin(); it != m_lstData.end(); it++)
  290. {
  291. if((*it)->m_dTimestampT0 == dDate)
  292. {
  293. wmihpd = *it;
  294. break;
  295. }
  296. }
  297. return S_OK;
  298. }
  299. HRESULT WMIHistory::Provider::get_Sequence( /*[in]*/ LONG lSequence ,
  300. /*[out]*/ Data*& wmihpd )
  301. {
  302. DataIter it;
  303. wmihpd = NULL;
  304. for(it=m_lstData.begin(); it != m_lstData.end(); it++)
  305. {
  306. if((*it)->m_lSequence == lSequence)
  307. {
  308. wmihpd = *it;
  309. break;
  310. }
  311. }
  312. return S_OK;
  313. }
  314. /////////////////////////////////////////////////////////////////////////////
  315. HRESULT WMIHistory::Provider::ComputeDiff( /*[in] */ Data* wmihpd_T0 ,
  316. /*[in] */ Data* wmihpd_T1 ,
  317. /*[out]*/ Data*& wmihpd )
  318. {
  319. __HCP_FUNC_ENTRY( "WMIHistory::Provider::ComputeDiff" );
  320. HRESULT hr;
  321. MPC::wstring szFile;
  322. wmihpd = NULL;
  323. //
  324. // Purge deltas if low on disk space.
  325. //
  326. __MPC_EXIT_IF_METHOD_FAILS(hr, EnsureFreeSpace());
  327. //
  328. // Generate a new name.
  329. //
  330. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->GetNewUniqueFileName( szFile ));
  331. //
  332. // Create a new Collected Data object.
  333. //
  334. __MPC_EXIT_IF_ALLOC_FAILS(hr, wmihpd, new Data( this ));
  335. m_lstDataTmp.push_back( wmihpd );
  336. wmihpd->m_szFile = szFile;
  337. wmihpd->m_dTimestampT0 = wmihpd_T0->m_dTimestampT0;
  338. wmihpd->m_dTimestampT1 = wmihpd_T1->m_dTimestampT0;
  339. wmihpd->m_lSequence = wmihpd_T1->m_lSequence - 1; // Decrement by one, so in the sequence order the delta comes before the snapshot.
  340. {
  341. MPC::wstring szPreviousFile = wmihpd_T0->m_szFile; m_wmihd->GetFullPathName( szPreviousFile );
  342. MPC::wstring szNextFile = wmihpd_T1->m_szFile; m_wmihd->GetFullPathName( szNextFile );
  343. MPC::wstring szDeltaFile = wmihpd ->m_szFile; m_wmihd->GetFullPathName( szDeltaFile );
  344. CComBSTR bstrPreviousFile = szPreviousFile.c_str();
  345. CComBSTR bstrNextFile = szNextFile .c_str();
  346. CComBSTR bstrDeltaFile = szDeltaFile .c_str();
  347. VARIANT_BOOL fCreated;
  348. //
  349. // Calculate the delta...
  350. //
  351. __MPC_EXIT_IF_METHOD_FAILS(hr, WMIParser::CompareSnapshots( bstrPreviousFile, bstrNextFile, bstrDeltaFile, &fCreated ));
  352. if(fCreated == VARIANT_FALSE)
  353. {
  354. //
  355. // No differences, so return a NULL pointer.
  356. //
  357. __MPC_EXIT_IF_METHOD_FAILS(hr, remove_Snapshot( wmihpd )); wmihpd = NULL;
  358. }
  359. else
  360. {
  361. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ComputeCRC( wmihpd->m_dwCRC, bstrDeltaFile ));
  362. }
  363. }
  364. hr = S_OK;
  365. __HCP_FUNC_CLEANUP;
  366. __HCP_FUNC_EXIT(hr);
  367. }
  368. HRESULT WMIHistory::Provider::EnsureFreeSpace()
  369. {
  370. __HCP_FUNC_ENTRY( "WMIHistory::Provider::EnsureFreeSpace" );
  371. HRESULT hr;
  372. MPC::wstring szBase; m_wmihd->GetFullPathName( szBase ); // Get the path of the database.
  373. ULARGE_INTEGER liFree;
  374. ULARGE_INTEGER liTotal;
  375. while(1)
  376. {
  377. LONG lMinSequence = -1;
  378. bool fRemoved = false;
  379. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetDiskSpace( szBase, liFree, liTotal ));
  380. //
  381. // Enough space, so exit.
  382. //
  383. if(liFree.HighPart > 0 ||
  384. liFree.LowPart > SAFETY_LIMIT_UPPER )
  385. {
  386. break;
  387. }
  388. //
  389. // Do two passes, the first to get the lowest sequence number, the second to remove the items.
  390. //
  391. for(int pass=0; pass<2; pass++)
  392. {
  393. WMIHistory::Database::ProvIterConst prov_itBegin;
  394. WMIHistory::Database::ProvIterConst prov_itEnd;
  395. WMIHistory::Database::ProvIterConst prov_it;
  396. __MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->get_Providers( prov_itBegin, prov_itEnd ));
  397. for(prov_it=prov_itBegin; prov_it!=prov_itEnd; prov_it++)
  398. {
  399. Provider* wmihp = *prov_it;
  400. if(pass == 0)
  401. {
  402. //
  403. // First pass, get the lowest sequence number for this provider.
  404. //
  405. DataIterConst it;
  406. for(it=wmihp->m_lstData.begin(); it!=wmihp->m_lstData.end(); it++)
  407. {
  408. Data* wmihpd = *it;
  409. LONG lSequence;
  410. if(wmihpd->IsSnapshot()) continue;
  411. __MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_Sequence( lSequence ));
  412. if(lMinSequence == -1 ||
  413. lMinSequence > lSequence )
  414. {
  415. lMinSequence = lSequence;
  416. }
  417. }
  418. }
  419. else
  420. {
  421. //
  422. // Second pass, remove an item from this provider, if it has the lowest sequence number.
  423. //
  424. Data* wmihpd;
  425. __MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Sequence( lMinSequence, wmihpd ));
  426. if(wmihpd)
  427. {
  428. __MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->remove_Snapshot( wmihpd ));
  429. fRemoved = true;
  430. }
  431. }
  432. }
  433. }
  434. if(fRemoved == false) break;
  435. }
  436. //
  437. // Too little space, fail.
  438. //
  439. if(liFree.HighPart == 0 &&
  440. liFree.LowPart < SAFETY_LIMIT_LOWER )
  441. {
  442. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_DISK_FULL);
  443. }
  444. hr = S_OK;
  445. __HCP_FUNC_CLEANUP;
  446. __HCP_FUNC_EXIT(hr);
  447. }
  448. /////////////////////////////////////////////////////////////////////////////
  449. /////////////////////////////////////////////////////////////////////////////
  450. /////////////////////////////////////////////////////////////////////////////
  451. //
  452. // WMIHistory::Database Class
  453. //
  454. /////////////////////////////////////////////////////////////////////////////
  455. WMIHistory::Database::Database() : MPC::NamedMutex( NULL )
  456. {
  457. // ProvList m_lstProviders;
  458. // MPC::wstring m_szBase;
  459. // MPC::wstring m_szSchema;
  460. m_lSequence = 0; // LONG m_lSequence;
  461. m_lSequence_Latest = 0; // LONG m_lSequence_Latest;
  462. m_dTimestamp = MPC::GetLocalTime(); // DATE m_dTimestamp;
  463. m_dTimestamp_Latest = 0; // DATE m_dTimestamp_Latest;
  464. }
  465. WMIHistory::Database::~Database()
  466. {
  467. MPC::CallDestructorForAll( m_lstProviders );
  468. }
  469. void WMIHistory::Database::GetFullPathName( /*[in]*/ MPC::wstring& szFile )
  470. {
  471. MPC::wstring szFullFile;
  472. szFullFile = m_szBase;
  473. szFullFile.append( L"\\" );
  474. szFullFile.append( szFile );
  475. szFile = szFullFile;
  476. }
  477. HRESULT WMIHistory::Database::GetNewUniqueFileName( /*[in]*/ MPC::wstring& szFile )
  478. {
  479. WCHAR rgBuf[64];
  480. //Bug 578172, Change to safe functions (replaced swprintf with safe function)
  481. StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"CollectedData_%ld.xml", ++m_lSequence );
  482. szFile = rgBuf;
  483. return S_OK;
  484. }
  485. HRESULT WMIHistory::Database::PurgeFiles()
  486. {
  487. __HCP_FUNC_ENTRY( "WMIHistory::Database::PurgeFiles" );
  488. HRESULT hr;
  489. MPC::wstring szFullFile;
  490. MPC::FileSystemObject fso( m_szBase.c_str() );
  491. MPC::FileSystemObject::List fso_lst;
  492. MPC::FileSystemObject::IterConst fso_it;
  493. FileList name_lst;
  494. FileIterConst name_it;
  495. ProvIter it;
  496. bool fRewrite = false;
  497. //
  498. // Enumerate all the providers and delete delta files not in time order. Also, remove items refering to non-existing files.
  499. //
  500. for(it=m_lstProviders.begin(); it != m_lstProviders.end(); it++)
  501. {
  502. Provider::DataIterConst itBegin;
  503. Provider::DataIterConst itEnd;
  504. Data* wmihpd;
  505. while(1)
  506. {
  507. DATE dTimestamp = 0;
  508. //
  509. // Get the time of the last snapshot.
  510. //
  511. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->get_Snapshot( wmihpd ));
  512. if(wmihpd)
  513. {
  514. __MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT0( dTimestamp ));
  515. }
  516. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->enum_Data( itBegin, itEnd ));
  517. for( ;itBegin != itEnd; itBegin++)
  518. {
  519. wmihpd = *itBegin;
  520. //
  521. // Does the file exist and have the same CRC?
  522. //
  523. {
  524. DWORD dwCRC;
  525. szFullFile = wmihpd->m_szFile; GetFullPathName( szFullFile );
  526. if(MPC::FileSystemObject::IsFile( szFullFile.c_str() ) == false)
  527. {
  528. break;
  529. }
  530. if(FAILED(MPC::ComputeCRC( dwCRC, szFullFile.c_str() )) || dwCRC != wmihpd->m_dwCRC)
  531. {
  532. break;
  533. }
  534. }
  535. if(wmihpd->IsSnapshot() == false)
  536. {
  537. //
  538. // Is timestamp in the proper order?
  539. //
  540. DATE dTimestampDelta;
  541. __MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT1( dTimestampDelta ));
  542. if(dTimestampDelta != dTimestamp)
  543. {
  544. break;
  545. }
  546. }
  547. //
  548. // Everything is ok, proceed to the next delta.
  549. //
  550. __MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT0( dTimestamp ));
  551. }
  552. //
  553. // No delta has been removed, so break out of the loop.
  554. //
  555. if(itBegin == itEnd) break;
  556. fRewrite = true;
  557. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->remove_Snapshot( wmihpd, true ));
  558. }
  559. }
  560. //
  561. // Create a list of files to be kept. Insert the database itself.
  562. //
  563. szFullFile = TEXT_INDEX;
  564. GetFullPathName ( szFullFile );
  565. name_lst.push_back( szFullFile );
  566. //
  567. // Insert all the providers' files.
  568. //
  569. for(it=m_lstProviders.begin(); it != m_lstProviders.end(); it++)
  570. {
  571. Provider::DataIterConst itBegin;
  572. Provider::DataIterConst itEnd;
  573. __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->enum_Data( itBegin, itEnd ));
  574. while(itBegin != itEnd)
  575. {
  576. szFullFile = (*itBegin++)->m_szFile;
  577. GetFullPathName ( szFullFile );
  578. name_lst.push_back( szFullFile );
  579. }
  580. }
  581. ////////////////////////////////////////
  582. //
  583. // Inspect the database directory.
  584. //
  585. __MPC_EXIT_IF_METHOD_FAILS(hr, fso.CreateDir( true ));
  586. //
  587. // Delete any subdirectory.
  588. //
  589. __MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFolders( fso_lst ));
  590. for(fso_it=fso_lst.begin(); fso_it != fso_lst.end(); fso_it++)
  591. {
  592. __MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->Delete( true, false ));
  593. }
  594. fso_lst.clear();
  595. //
  596. // For each file, if it's not in the database, delete it.
  597. //
  598. __MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFiles( fso_lst ));
  599. for(fso_it=fso_lst.begin(); fso_it != fso_lst.end(); fso_it++)
  600. {
  601. __MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->get_Path( szFullFile ));
  602. name_it = std::find_if( name_lst.begin(), name_lst.end(), CompareNocase( szFullFile ) );
  603. if(name_it == name_lst.end())
  604. {
  605. __MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->Delete( false, false ));
  606. }
  607. }
  608. fso_lst.clear();
  609. //
  610. // In case an entry has been removed, rewrite the DB to disk.
  611. //
  612. if(fRewrite)
  613. {
  614. __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
  615. }
  616. hr = S_OK;
  617. __HCP_FUNC_CLEANUP;
  618. __HCP_FUNC_EXIT(hr);
  619. }
  620. /////////////////////////////////////////////////////////////////////////////
  621. HRESULT WMIHistory::Database::Init( /*[in]*/ LPCWSTR szBase ,
  622. /*[in]*/ LPCWSTR szSchema )
  623. {
  624. __HCP_FUNC_ENTRY( "WMIHistory::Database::Init" );
  625. HRESULT hr;
  626. MPC::XmlUtil xml;
  627. bool fLoaded;
  628. bool fFound;
  629. __MPC_PARAMCHECK_BEGIN(hr)
  630. __MPC_PARAMCHECK_STRING_NOT_EMPTY(szSchema);
  631. __MPC_PARAMCHECK_END();
  632. m_szSchema = szSchema; MPC::SubstituteEnvVariables( m_szSchema );
  633. if(szBase)
  634. {
  635. m_szBase = szBase; MPC::SubstituteEnvVariables( m_szBase );
  636. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( m_szBase ));
  637. __MPC_EXIT_IF_METHOD_FAILS(hr, GetLock( 100 ));
  638. }
  639. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.Load( m_szSchema.c_str(), TEXT_TAG_DATASPEC, fLoaded, &fFound ));
  640. if(fLoaded == false ||
  641. fFound == false )
  642. {
  643. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_OPEN_FAILED);
  644. }
  645. else
  646. {
  647. CComPtr<IXMLDOMNodeList> xdnlList;
  648. CComPtr<IXMLDOMNode> xdnNode;
  649. MPC::wstring szValue;
  650. CComVariant vValue;
  651. //
  652. // Parse WQLs.
  653. //
  654. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetNodes( TEXT_TAG_WQL, &xdnlList ));
  655. for(;SUCCEEDED(hr = xdnlList->nextNode( &xdnNode )) && xdnNode != NULL; xdnNode = NULL)
  656. {
  657. Provider* wmihp;
  658. //
  659. // Create a new provider.
  660. //
  661. __MPC_EXIT_IF_ALLOC_FAILS(hr, wmihp, new Provider( this ));
  662. m_lstProviders.push_back( wmihp );
  663. //
  664. // Read its properties.
  665. //
  666. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_WQL_NAMESPACE, szValue, fFound, xdnNode ));
  667. if(fFound == false)
  668. {
  669. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_BAD_FORMAT);
  670. }
  671. wmihp->m_szNamespace = szValue;
  672. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_WQL_CLASS, szValue, fFound, xdnNode ));
  673. if(fFound == false)
  674. {
  675. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_BAD_FORMAT);
  676. }
  677. wmihp->m_szClass = szValue;
  678. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetValue( NULL, vValue, fFound, xdnNode ));
  679. if(fFound)
  680. {
  681. if(SUCCEEDED(vValue.ChangeType( VT_BSTR )))
  682. {
  683. wmihp->m_szWQL = OLE2W( vValue.bstrVal );
  684. }
  685. }
  686. }
  687. }
  688. hr = S_OK;
  689. __HCP_FUNC_CLEANUP;
  690. __HCP_FUNC_EXIT(hr);
  691. }
  692. HRESULT WMIHistory::Database::Load()
  693. {
  694. __HCP_FUNC_ENTRY( "WMIHistory::Database::Load" );
  695. HRESULT hr;
  696. MPC::XmlUtil xml;
  697. //
  698. // Load the database.
  699. //
  700. if(SUCCEEDED(LoadCIM( TEXT_INDEX, xml, TEXT_TAG_HC_HISTORY )))
  701. {
  702. CComPtr<IXMLDOMNodeList> xdnlList;
  703. CComPtr<IXMLDOMNode> xdnNode;
  704. MPC::wstring szValue;
  705. bool fFound;
  706. LONG lVersion;
  707. //
  708. // First of all, check database version.
  709. //
  710. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_HC_VERSION, lVersion, fFound ));
  711. if(fFound && lVersion == DATABASE_VERSION)
  712. {
  713. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_HC_SEQ, m_lSequence, fFound ));
  714. m_lSequence_Latest = m_lSequence;
  715. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_HC_TIMESTAMP, szValue, fFound ));
  716. if(fFound)
  717. {
  718. __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertStringToDate( szValue, m_dTimestamp_Latest ));
  719. }
  720. //
  721. // Enumerate all the PROVIDER elements.
  722. //
  723. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetNodes( TEXT_TAG_PROVIDER, &xdnlList ));
  724. for(;SUCCEEDED(hr = xdnlList->nextNode( &xdnNode )) && xdnNode != NULL; xdnNode = NULL)
  725. {
  726. Provider* wmihp;
  727. MPC::wstring szNamespace;
  728. MPC::wstring szClass;
  729. //
  730. // Read the attributes.
  731. //
  732. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_PROVIDER_NAMESPACE, szValue, fFound, xdnNode ));
  733. if(fFound)
  734. {
  735. szNamespace = szValue;
  736. }
  737. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_PROVIDER_CLASS, szValue, fFound, xdnNode ));
  738. if(fFound)
  739. {
  740. szClass = szValue;
  741. }
  742. //
  743. // If the provider is present in the Schema, parse it.
  744. //
  745. __MPC_EXIT_IF_METHOD_FAILS(hr, find_Provider( NULL, &szNamespace, &szClass, wmihp ));
  746. if(wmihp)
  747. {
  748. MPC::XmlUtil xmlSub( xdnNode );
  749. CComPtr<IXMLDOMNodeList> xdnlSubList;
  750. CComPtr<IXMLDOMNode> xdnSubNode;
  751. //
  752. // Enumerate all the COLLECTEDDATA elements.
  753. //
  754. __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetNodes( TEXT_TAG_CD, &xdnlSubList ));
  755. for(;SUCCEEDED(hr = xdnlSubList->nextNode( &xdnSubNode )) && xdnSubNode != NULL; xdnSubNode = NULL)
  756. {
  757. MPC::wstring szTimestamp;
  758. MPC::wstring szFile;
  759. LONG lSequence = 0;
  760. long lCRC = 0;
  761. DATE dTimestampT0 = 0;
  762. DATE dTimestampT1 = 0;
  763. //
  764. // Read the attributes.
  765. //
  766. __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_FILE, szFile, fFound, xdnSubNode ));
  767. __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_SEQ, lSequence, fFound, xdnSubNode ));
  768. __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_CRC, lCRC , fFound, xdnSubNode ));
  769. __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T0, szTimestamp, fFound, xdnSubNode ));
  770. if(fFound)
  771. {
  772. __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertStringToDate( szTimestamp, dTimestampT0 ));
  773. }
  774. __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T1, szTimestamp, fFound, xdnSubNode ));
  775. if(fFound)
  776. {
  777. __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertStringToDate( szTimestamp, dTimestampT1 ));
  778. }
  779. if(szFile.length() && dTimestampT0 != 0)
  780. {
  781. Data* wmihpd;
  782. //
  783. // Create a new Collected Data object.
  784. //
  785. __MPC_EXIT_IF_ALLOC_FAILS(hr, wmihpd, new Data( wmihp ));
  786. wmihp->m_lstData.push_back( wmihpd );
  787. wmihpd->m_szFile = szFile;
  788. wmihpd->m_lSequence = lSequence;
  789. wmihpd->m_dwCRC = lCRC;
  790. wmihpd->m_dTimestampT0 = dTimestampT0;
  791. wmihpd->m_dTimestampT1 = dTimestampT1;
  792. wmihpd->m_fDontDelete = true;
  793. }
  794. }
  795. }
  796. }
  797. }
  798. }
  799. __MPC_EXIT_IF_METHOD_FAILS(hr, PurgeFiles());
  800. hr = S_OK;
  801. __HCP_FUNC_CLEANUP;
  802. __HCP_FUNC_EXIT(hr);
  803. }
  804. HRESULT WMIHistory::Database::Save()
  805. {
  806. __HCP_FUNC_ENTRY( "WMIHistory::Database::Save" );
  807. HRESULT hr;
  808. MPC::XmlUtil xml;
  809. ProvIter it;
  810. MPC::wstring szValue;
  811. bool fFound;
  812. //
  813. // Create a new database.
  814. //
  815. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.New( TEXT_TAG_HC_HISTORY ));
  816. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_HC_VERSION, (LONG)DATABASE_VERSION, fFound ));
  817. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_HC_SEQ, m_lSequence, fFound ));
  818. __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertDateToString( m_dTimestamp, szValue ));
  819. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_HC_TIMESTAMP, szValue, fFound ));
  820. //
  821. // Enumerate all the providers.
  822. //
  823. for(it=m_lstProviders.begin(); it != m_lstProviders.end(); it++)
  824. {
  825. Provider* wmihp = *it;
  826. Provider::DataIterConst itSub;
  827. CComPtr<IXMLDOMNode> xdnNode;
  828. long lMaxDeltas = WMIHISTORY_MAX_NUMBER_OF_DELTAS;
  829. //
  830. // Don't generate a "Provider" element if there's no data associated with it.
  831. //
  832. if(wmihp->m_lstData.size() == 0)
  833. {
  834. continue;
  835. }
  836. //
  837. // Create a PROVIDER element.
  838. //
  839. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_PROVIDER, &xdnNode ));
  840. //
  841. // Set its attributes.
  842. //
  843. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_PROVIDER_NAMESPACE, wmihp->m_szNamespace, fFound, xdnNode ));
  844. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_PROVIDER_CLASS , wmihp->m_szClass , fFound, xdnNode ));
  845. //
  846. // Enumerate all the collected data entries.
  847. //
  848. for(itSub=wmihp->m_lstData.begin(); itSub != wmihp->m_lstData.end(); itSub++)
  849. {
  850. Data* wmihpd = *itSub;
  851. if(lMaxDeltas-- < 0) // Don't count initial snapshot.
  852. {
  853. //
  854. // Exceed maximum number of deltas, start purgeing oldest ones.
  855. //
  856. wmihpd->m_fDontDelete = false;
  857. }
  858. else
  859. {
  860. CComPtr<IXMLDOMNode> xdnSubNode;
  861. //
  862. // Create a COLLECTEDDATA element.
  863. //
  864. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_CD, &xdnSubNode, xdnNode ));
  865. //
  866. // Set its attributes.
  867. //
  868. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_FILE, wmihpd->m_szFile , fFound, xdnSubNode ));
  869. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_SEQ , wmihpd->m_lSequence, fFound, xdnSubNode ));
  870. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_CRC , wmihpd->m_dwCRC , fFound, xdnSubNode ));
  871. __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertDateToString( wmihpd->m_dTimestampT0, szValue ));
  872. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T0, szValue, fFound, xdnSubNode ));
  873. if(wmihpd->m_dTimestampT1)
  874. {
  875. __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertDateToString( wmihpd->m_dTimestampT1, szValue ));
  876. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T1, szValue, fFound, xdnSubNode ));
  877. }
  878. }
  879. }
  880. }
  881. {
  882. DWORD dwCRC; // Not used.
  883. __MPC_EXIT_IF_METHOD_FAILS(hr, SaveCIM( TEXT_INDEX, xml, dwCRC ));
  884. }
  885. hr = S_OK;
  886. __HCP_FUNC_CLEANUP;
  887. __HCP_FUNC_EXIT(hr);
  888. }
  889. /////////////////////////////////////////////////////////////////////////////
  890. HRESULT WMIHistory::Database::get_Providers( /*[out]*/ ProvIterConst& itBegin ,
  891. /*[out]*/ ProvIterConst& itEnd )
  892. {
  893. itBegin = m_lstProviders.begin();
  894. itEnd = m_lstProviders.end ();
  895. return S_OK;
  896. }
  897. HRESULT WMIHistory::Database::find_Provider( /*[in]*/ ProvIterConst* it ,
  898. /*[in]*/ const MPC::wstring* szNamespace,
  899. /*[in]*/ const MPC::wstring* szClass ,
  900. /*[in]*/ Provider* & wmihp )
  901. {
  902. ProvIterConst itFake;
  903. MPC::NocaseCompare cmp;
  904. wmihp = NULL;
  905. //
  906. // If the caller hasn't provider an iterator, provide a local one,
  907. // pointing to the beginning of the list.
  908. //
  909. if(it == NULL)
  910. {
  911. it = &itFake; itFake = m_lstProviders.begin();
  912. }
  913. while(*it != m_lstProviders.end())
  914. {
  915. Provider* prov = *(*it)++;
  916. if((szNamespace == NULL || cmp( *szNamespace, prov->m_szNamespace )) &&
  917. (szClass == NULL || cmp( *szClass , prov->m_szClass )) )
  918. {
  919. wmihp = prov;
  920. break;
  921. }
  922. }
  923. return S_OK;
  924. }
  925. /////////////////////////////////////////////////////////////////////////////
  926. HRESULT WMIHistory::Database::LoadCIM( /*[in]*/ LPCWSTR szFile ,
  927. /*[in]*/ MPC::XmlUtil& xml ,
  928. /*[in]*/ LPCWSTR szTag )
  929. {
  930. __HCP_FUNC_ENTRY( "WMIHistory::Database::LoadCIM" );
  931. HRESULT hr;
  932. MPC::wstring szFullFile = szFile; GetFullPathName( szFullFile );
  933. bool fLoaded;
  934. bool fFound;
  935. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.Load( szFullFile.c_str(), szTag, fLoaded, &fFound ));
  936. if(fLoaded == false ||
  937. fFound == false )
  938. {
  939. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
  940. }
  941. hr = S_OK;
  942. __HCP_FUNC_CLEANUP;
  943. __HCP_FUNC_EXIT(hr);
  944. }
  945. HRESULT WMIHistory::Database::SaveCIM( /*[in]*/ LPCWSTR szFile ,
  946. /*[in]*/ MPC::XmlUtil& xml ,
  947. /*[out]*/ DWORD& dwCRC )
  948. {
  949. __HCP_FUNC_ENTRY( "WMIHistory::Database::SaveCIM" );
  950. HRESULT hr;
  951. MPC::wstring szFullFile = szFile; GetFullPathName( szFullFile );
  952. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.Save ( szFullFile.c_str() ));
  953. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ComputeCRC( dwCRC, szFullFile.c_str() ));
  954. hr = S_OK;
  955. __HCP_FUNC_CLEANUP;
  956. __HCP_FUNC_EXIT(hr);
  957. }
  958. HRESULT WMIHistory::Database::GetLock( /*[in]*/ DWORD dwMilliseconds )
  959. {
  960. __HCP_FUNC_ENTRY( "WMIHistory::Database::GetLock" );
  961. HRESULT hr;
  962. WCHAR szMutexName[MAX_PATH];
  963. LPWSTR szPos;
  964. //
  965. // If the database directory is set, protect it using a mutex.
  966. //
  967. if(m_szBase.length())
  968. {
  969. //Bug 578172, Change to safe functions (replaced swprintf with safe function)
  970. StringCchPrintfW( szMutexName, ARRAYSIZE(szMutexName),L"PCHMUTEX_%s", m_szBase.c_str() );
  971. //
  972. // Make sure no strange characters are present in the mutex name.
  973. //
  974. for(szPos=szMutexName; *szPos; szPos++)
  975. {
  976. *szPos = (WCHAR)towlower( *szPos );
  977. if(*szPos == ':' ||
  978. *szPos == '/' ||
  979. *szPos == '\\' )
  980. {
  981. *szPos = '_';
  982. }
  983. }
  984. __MPC_EXIT_IF_METHOD_FAILS(hr, SetName( szMutexName ));
  985. __MPC_EXIT_IF_METHOD_FAILS(hr, Acquire( dwMilliseconds ));
  986. }
  987. hr = S_OK;
  988. __HCP_FUNC_CLEANUP;
  989. __HCP_FUNC_EXIT(hr);
  990. }