|
|
/******************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name: History.cpp
Abstract: This file contains the implementation of the CHCPHistory class, which implements the data collection functionality.
Revision History: Davide Massarenti (Dmassare) 07/22/99 created
******************************************************************************/
#include "stdafx.h"
#include "strsafe.h"
/////////////////////////////////////////////////////////////////////////////
#define SAFETY_LIMIT_UPPER (10*1024*1024)
#define SAFETY_LIMIT_LOWER ( 5*1024*1024)
#define DATABASE_VERSION (1)
#define TEXT_INDEX L"history_db.xml"
#define TEXT_TAG_HC_HISTORY L"HC_History"
#define TEXT_ATTR_HC_VERSION L"Version"
#define TEXT_ATTR_HC_SEQ L"Sequence"
#define TEXT_ATTR_HC_TIMESTAMP L"Timestamp"
#define TEXT_TAG_CIM L"CIM"
#define TEXT_TAG_PROVIDER L"Provider"
#define TEXT_ATTR_PROVIDER_NAMESPACE L"Namespace"
#define TEXT_ATTR_PROVIDER_CLASS L"Class"
#define TEXT_TAG_CD L"CollectedData"
#define TEXT_ATTR_CD_FILE L"File"
#define TEXT_ATTR_CD_SEQ L"Sequence"
#define TEXT_ATTR_CD_CRC L"CRC"
#define TEXT_ATTR_CD_TIMESTAMP_T0 L"Timestamp_T0"
#define TEXT_ATTR_CD_TIMESTAMP_T1 L"Timestamp_T1"
#define TEXT_TAG_DATASPEC L"DataSpec"
#define TEXT_TAG_WQL L"WQL"
#define TEXT_ATTR_WQL_NAMESPACE L"Namespace"
#define TEXT_ATTR_WQL_CLASS L"Class"
/////////////////////////////////////////////////////////////////////////////
typedef std::list< MPC::wstring > FileList; typedef FileList::iterator FileIter; typedef FileList::const_iterator FileIterConst;
class CompareNocase { MPC::NocaseCompare m_cmp; MPC::wstring& m_str; public: explicit CompareNocase( MPC::wstring& str ) : m_str(str) {}
bool operator()( const MPC::wstring& str ) { return m_cmp( str, m_str ); } };
/////////////////////////////////////////////////////////////////////////////
static HRESULT Local_ConvertDateToString( /*[in] */ DATE dDate , /*[out]*/ MPC::wstring& szDate ) { //
// Use CIM conversion.
//
return MPC::ConvertDateToString( dDate, szDate, /*fGMT*/false, /*fCIM*/true, 0 ); }
static HRESULT Local_ConvertStringToDate( /*[in] */ const MPC::wstring& szDate , /*[out]*/ DATE& dDate ) { return MPC::ConvertStringToDate( szDate, dDate, /*fGMT*/false, /*fCIM*/true, 0 ); }
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// WMIHistory::Data Class
//
/////////////////////////////////////////////////////////////////////////////
WMIHistory::Data::Data( /*[in]*/ Provider* wmihp ) { m_wmihp = wmihp; // Provider* m_wmihp;
// MPC::wstring m_szFile;
m_lSequence = wmihp->m_wmihd->m_lSequence_Latest; // LONG m_lSequence;
m_dwCRC = 0; // DWORD m_dwCRC;
m_dTimestampT0 = 0; // DATE m_dTimestampT0;
m_dTimestampT1 = 0; // DATE m_dTimestampT1;
m_fDontDelete = false; // bool m_fDontDelete;
}
WMIHistory::Data::~Data() { if(m_fDontDelete == false) { MPC::wstring szFile( m_szFile ); m_wmihp->m_wmihd->GetFullPathName( szFile );
(void)MPC::DeleteFile( szFile ); } }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Data::get_File( /*[out]*/ MPC::wstring& szFile ) { szFile = m_szFile;
return S_OK; }
HRESULT WMIHistory::Data::get_Sequence( /*[out]*/ LONG& lSequence ) { lSequence = m_lSequence;
return S_OK; }
HRESULT WMIHistory::Data::get_TimestampT0( /*[out]*/ DATE& dTimestampT0 ) { dTimestampT0 = m_dTimestampT0;
return S_OK; }
HRESULT WMIHistory::Data::get_TimestampT1( /*[out]*/ DATE& dTimestampT1 ) { dTimestampT1 = m_dTimestampT1;
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
bool WMIHistory::Data::IsSnapshot() { return (m_dTimestampT1 == 0); }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Data::LoadCIM( /*[in]*/ MPC::XmlUtil& xml ) { __HCP_FUNC_ENTRY( "WMIHistory::Data::LoadCIM" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihp->m_wmihd->LoadCIM( m_szFile.c_str(), xml, TEXT_TAG_CIM ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// WMIHistory::Provider Class
//
/////////////////////////////////////////////////////////////////////////////
WMIHistory::Provider::Provider( Database* wmihd ) { m_wmihd = wmihd; // Database* m_wmihd;
// DataList m_lstData;
// DataList m_lstDataTmp;
// MPC::wstring m_szNamespace;
// MPC::wstring m_szClass;
// MPC::wstring m_szWQL;
}
WMIHistory::Provider::~Provider() { MPC::CallDestructorForAll( m_lstData ); MPC::CallDestructorForAll( m_lstDataTmp ); }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Provider::enum_Data( /*[out]*/ DataIterConst& itBegin , /*[out]*/ DataIterConst& itEnd ) { itBegin = m_lstData.begin(); itEnd = m_lstData.end ();
return S_OK; }
HRESULT WMIHistory::Provider::get_Namespace( /*[out]*/ MPC::wstring& szNamespace ) { szNamespace = m_szNamespace;
return S_OK; }
HRESULT WMIHistory::Provider::get_Class( /*[out]*/ MPC::wstring& szClass ) { szClass = m_szClass;
return S_OK; }
HRESULT WMIHistory::Provider::get_WQL( /*[out]*/ MPC::wstring& szWQL ) { szWQL = m_szWQL;
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Provider::insert_Snapshot( /*[in]*/ Data* wmihpd , /*[in]*/ bool fPersist ) { __HCP_FUNC_ENTRY( "WMIHistory::Provider::insert_Snapshot" );
HRESULT hr;
m_lstData .remove ( wmihpd ); m_lstDataTmp.remove ( wmihpd ); m_lstData .push_front( wmihpd );
//
// If we add a new snapshot, we need to link the first delta to it.
//
if(wmihpd->IsSnapshot()) { Data* wmihpd_Delta;
__MPC_EXIT_IF_METHOD_FAILS(hr, get_Delta( 0, wmihpd_Delta )); if(wmihpd_Delta) { wmihpd_Delta->m_dTimestampT1 = wmihpd->m_dTimestampT0; } }
//
// Only keep the snapshot's file if the flag is set.
//
if(fPersist) wmihpd->m_fDontDelete = true;
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Provider::remove_Snapshot( /*[in]*/ Data* wmihpd , /*[in]*/ bool fPersist ) { __HCP_FUNC_ENTRY( "WMIHistory::Provider::remove_Snapshot" );
HRESULT hr;
m_lstData .remove( wmihpd ); m_lstDataTmp.remove( wmihpd );
//
// Only delete the snapshot's file if the flag is set.
//
if(fPersist) wmihpd->m_fDontDelete = false; delete wmihpd;
hr = S_OK;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Provider::alloc_Snapshot( /*[in] */ MPC::XmlUtil& xmlNode , /*[out]*/ Data* & wmihpd ) { __HCP_FUNC_ENTRY( "WMIHistory::Provider::alloc_Snapshot" );
HRESULT hr; MPC::wstring szFile; Data* wmihpdTmp = NULL;
wmihpd = NULL;
//
// Purge deltas if low on disk space.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureFreeSpace());
//
// Generate a new name.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->GetNewUniqueFileName( szFile ));
//
// Create a new Collected Data object.
//
__MPC_EXIT_IF_ALLOC_FAILS(hr, wmihpdTmp, new Data( this )); wmihpdTmp->m_szFile = szFile; wmihpdTmp->m_dTimestampT0 = m_wmihd->m_dTimestamp;
//
// Save it.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->SaveCIM( szFile.c_str(), xmlNode, wmihpdTmp->m_dwCRC )); m_lstDataTmp.push_back( wmihpdTmp );
//
// Return the pointer to the caller.
//
wmihpd = wmihpdTmp; wmihpdTmp = NULL;
hr = S_OK;
__HCP_FUNC_CLEANUP;
if(wmihpdTmp) delete wmihpdTmp;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Provider::get_Snapshot( /*[out]*/ Data*& wmihpd ) { DataIter it;
wmihpd = NULL;
for(it=m_lstData.begin(); it != m_lstData.end(); it++) { if((*it)->IsSnapshot()) { wmihpd = *it; break; } }
return S_OK; }
HRESULT WMIHistory::Provider::get_Delta( /*[in] */ int iIndex , /*[out]*/ Data*& wmihpd ) { DataIter it;
wmihpd = NULL;
for(it=m_lstData.begin(); it != m_lstData.end(); it++) { if((*it)->IsSnapshot() == false) { if(iIndex-- == 0) { wmihpd = *it; break; } } }
return S_OK; }
HRESULT WMIHistory::Provider::get_Date( /*[in] */ DATE dDate , /*[out]*/ Data*& wmihpd ) { DataIter it;
wmihpd = NULL;
for(it=m_lstData.begin(); it != m_lstData.end(); it++) { if((*it)->m_dTimestampT0 == dDate) { wmihpd = *it; break; } }
return S_OK; }
HRESULT WMIHistory::Provider::get_Sequence( /*[in]*/ LONG lSequence , /*[out]*/ Data*& wmihpd ) { DataIter it;
wmihpd = NULL;
for(it=m_lstData.begin(); it != m_lstData.end(); it++) { if((*it)->m_lSequence == lSequence) { wmihpd = *it; break; } }
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Provider::ComputeDiff( /*[in] */ Data* wmihpd_T0 , /*[in] */ Data* wmihpd_T1 , /*[out]*/ Data*& wmihpd ) { __HCP_FUNC_ENTRY( "WMIHistory::Provider::ComputeDiff" );
HRESULT hr; MPC::wstring szFile;
wmihpd = NULL;
//
// Purge deltas if low on disk space.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, EnsureFreeSpace());
//
// Generate a new name.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->GetNewUniqueFileName( szFile ));
//
// Create a new Collected Data object.
//
__MPC_EXIT_IF_ALLOC_FAILS(hr, wmihpd, new Data( this )); m_lstDataTmp.push_back( wmihpd );
wmihpd->m_szFile = szFile; wmihpd->m_dTimestampT0 = wmihpd_T0->m_dTimestampT0; wmihpd->m_dTimestampT1 = wmihpd_T1->m_dTimestampT0; wmihpd->m_lSequence = wmihpd_T1->m_lSequence - 1; // Decrement by one, so in the sequence order the delta comes before the snapshot.
{ MPC::wstring szPreviousFile = wmihpd_T0->m_szFile; m_wmihd->GetFullPathName( szPreviousFile ); MPC::wstring szNextFile = wmihpd_T1->m_szFile; m_wmihd->GetFullPathName( szNextFile ); MPC::wstring szDeltaFile = wmihpd ->m_szFile; m_wmihd->GetFullPathName( szDeltaFile ); CComBSTR bstrPreviousFile = szPreviousFile.c_str(); CComBSTR bstrNextFile = szNextFile .c_str(); CComBSTR bstrDeltaFile = szDeltaFile .c_str(); VARIANT_BOOL fCreated;
//
// Calculate the delta...
//
__MPC_EXIT_IF_METHOD_FAILS(hr, WMIParser::CompareSnapshots( bstrPreviousFile, bstrNextFile, bstrDeltaFile, &fCreated )); if(fCreated == VARIANT_FALSE) { //
// No differences, so return a NULL pointer.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, remove_Snapshot( wmihpd )); wmihpd = NULL; } else { __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ComputeCRC( wmihpd->m_dwCRC, bstrDeltaFile )); } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Provider::EnsureFreeSpace() { __HCP_FUNC_ENTRY( "WMIHistory::Provider::EnsureFreeSpace" );
HRESULT hr; MPC::wstring szBase; m_wmihd->GetFullPathName( szBase ); // Get the path of the database.
ULARGE_INTEGER liFree; ULARGE_INTEGER liTotal;
while(1) { LONG lMinSequence = -1; bool fRemoved = false;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetDiskSpace( szBase, liFree, liTotal ));
//
// Enough space, so exit.
//
if(liFree.HighPart > 0 || liFree.LowPart > SAFETY_LIMIT_UPPER ) { break; }
//
// Do two passes, the first to get the lowest sequence number, the second to remove the items.
//
for(int pass=0; pass<2; pass++) { WMIHistory::Database::ProvIterConst prov_itBegin; WMIHistory::Database::ProvIterConst prov_itEnd; WMIHistory::Database::ProvIterConst prov_it;
__MPC_EXIT_IF_METHOD_FAILS(hr, m_wmihd->get_Providers( prov_itBegin, prov_itEnd )); for(prov_it=prov_itBegin; prov_it!=prov_itEnd; prov_it++) { Provider* wmihp = *prov_it;
if(pass == 0) { //
// First pass, get the lowest sequence number for this provider.
//
DataIterConst it;
for(it=wmihp->m_lstData.begin(); it!=wmihp->m_lstData.end(); it++) { Data* wmihpd = *it; LONG lSequence;
if(wmihpd->IsSnapshot()) continue;
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_Sequence( lSequence ));
if(lMinSequence == -1 || lMinSequence > lSequence ) { lMinSequence = lSequence; } } } else { //
// Second pass, remove an item from this provider, if it has the lowest sequence number.
//
Data* wmihpd;
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->get_Sequence( lMinSequence, wmihpd )); if(wmihpd) { __MPC_EXIT_IF_METHOD_FAILS(hr, wmihp->remove_Snapshot( wmihpd )); fRemoved = true; } } } }
if(fRemoved == false) break; }
//
// Too little space, fail.
//
if(liFree.HighPart == 0 && liFree.LowPart < SAFETY_LIMIT_LOWER ) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_DISK_FULL); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// WMIHistory::Database Class
//
/////////////////////////////////////////////////////////////////////////////
WMIHistory::Database::Database() : MPC::NamedMutex( NULL ) { // ProvList m_lstProviders;
// MPC::wstring m_szBase;
// MPC::wstring m_szSchema;
m_lSequence = 0; // LONG m_lSequence;
m_lSequence_Latest = 0; // LONG m_lSequence_Latest;
m_dTimestamp = MPC::GetLocalTime(); // DATE m_dTimestamp;
m_dTimestamp_Latest = 0; // DATE m_dTimestamp_Latest;
}
WMIHistory::Database::~Database() { MPC::CallDestructorForAll( m_lstProviders ); }
void WMIHistory::Database::GetFullPathName( /*[in]*/ MPC::wstring& szFile ) { MPC::wstring szFullFile;
szFullFile = m_szBase; szFullFile.append( L"\\" ); szFullFile.append( szFile );
szFile = szFullFile; }
HRESULT WMIHistory::Database::GetNewUniqueFileName( /*[in]*/ MPC::wstring& szFile ) { WCHAR rgBuf[64];
//Bug 578172, Change to safe functions (replaced swprintf with safe function)
StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"CollectedData_%ld.xml", ++m_lSequence ); szFile = rgBuf;
return S_OK; }
HRESULT WMIHistory::Database::PurgeFiles() { __HCP_FUNC_ENTRY( "WMIHistory::Database::PurgeFiles" );
HRESULT hr; MPC::wstring szFullFile; MPC::FileSystemObject fso( m_szBase.c_str() ); MPC::FileSystemObject::List fso_lst; MPC::FileSystemObject::IterConst fso_it; FileList name_lst; FileIterConst name_it; ProvIter it; bool fRewrite = false;
//
// Enumerate all the providers and delete delta files not in time order. Also, remove items refering to non-existing files.
//
for(it=m_lstProviders.begin(); it != m_lstProviders.end(); it++) { Provider::DataIterConst itBegin; Provider::DataIterConst itEnd; Data* wmihpd;
while(1) { DATE dTimestamp = 0;
//
// Get the time of the last snapshot.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->get_Snapshot( wmihpd )); if(wmihpd) { __MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT0( dTimestamp )); }
__MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->enum_Data( itBegin, itEnd )); for( ;itBegin != itEnd; itBegin++) { wmihpd = *itBegin;
//
// Does the file exist and have the same CRC?
//
{ DWORD dwCRC;
szFullFile = wmihpd->m_szFile; GetFullPathName( szFullFile );
if(MPC::FileSystemObject::IsFile( szFullFile.c_str() ) == false) { break; }
if(FAILED(MPC::ComputeCRC( dwCRC, szFullFile.c_str() )) || dwCRC != wmihpd->m_dwCRC) { break; } }
if(wmihpd->IsSnapshot() == false) { //
// Is timestamp in the proper order?
//
DATE dTimestampDelta;
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT1( dTimestampDelta )); if(dTimestampDelta != dTimestamp) { break; } }
//
// Everything is ok, proceed to the next delta.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, wmihpd->get_TimestampT0( dTimestamp )); }
//
// No delta has been removed, so break out of the loop.
//
if(itBegin == itEnd) break;
fRewrite = true; __MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->remove_Snapshot( wmihpd, true )); } }
//
// Create a list of files to be kept. Insert the database itself.
//
szFullFile = TEXT_INDEX; GetFullPathName ( szFullFile ); name_lst.push_back( szFullFile );
//
// Insert all the providers' files.
//
for(it=m_lstProviders.begin(); it != m_lstProviders.end(); it++) { Provider::DataIterConst itBegin; Provider::DataIterConst itEnd;
__MPC_EXIT_IF_METHOD_FAILS(hr, (*it)->enum_Data( itBegin, itEnd )); while(itBegin != itEnd) { szFullFile = (*itBegin++)->m_szFile; GetFullPathName ( szFullFile ); name_lst.push_back( szFullFile ); } }
////////////////////////////////////////
//
// Inspect the database directory.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.CreateDir( true ));
//
// Delete any subdirectory.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFolders( fso_lst )); for(fso_it=fso_lst.begin(); fso_it != fso_lst.end(); fso_it++) { __MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->Delete( true, false )); } fso_lst.clear();
//
// For each file, if it's not in the database, delete it.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFiles( fso_lst )); for(fso_it=fso_lst.begin(); fso_it != fso_lst.end(); fso_it++) { __MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->get_Path( szFullFile ));
name_it = std::find_if( name_lst.begin(), name_lst.end(), CompareNocase( szFullFile ) ); if(name_it == name_lst.end()) { __MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->Delete( false, false )); } } fso_lst.clear();
//
// In case an entry has been removed, rewrite the DB to disk.
//
if(fRewrite) { __MPC_EXIT_IF_METHOD_FAILS(hr, Save()); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Database::Init( /*[in]*/ LPCWSTR szBase , /*[in]*/ LPCWSTR szSchema ) { __HCP_FUNC_ENTRY( "WMIHistory::Database::Init" );
HRESULT hr; MPC::XmlUtil xml; bool fLoaded; bool fFound;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(szSchema); __MPC_PARAMCHECK_END();
m_szSchema = szSchema; MPC::SubstituteEnvVariables( m_szSchema ); if(szBase) { m_szBase = szBase; MPC::SubstituteEnvVariables( m_szBase );
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( m_szBase ));
__MPC_EXIT_IF_METHOD_FAILS(hr, GetLock( 100 )); }
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.Load( m_szSchema.c_str(), TEXT_TAG_DATASPEC, fLoaded, &fFound )); if(fLoaded == false || fFound == false ) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_OPEN_FAILED); } else { CComPtr<IXMLDOMNodeList> xdnlList; CComPtr<IXMLDOMNode> xdnNode; MPC::wstring szValue; CComVariant vValue;
//
// Parse WQLs.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetNodes( TEXT_TAG_WQL, &xdnlList )); for(;SUCCEEDED(hr = xdnlList->nextNode( &xdnNode )) && xdnNode != NULL; xdnNode = NULL) { Provider* wmihp;
//
// Create a new provider.
//
__MPC_EXIT_IF_ALLOC_FAILS(hr, wmihp, new Provider( this )); m_lstProviders.push_back( wmihp );
//
// Read its properties.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_WQL_NAMESPACE, szValue, fFound, xdnNode )); if(fFound == false) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_BAD_FORMAT); } wmihp->m_szNamespace = szValue;
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_WQL_CLASS, szValue, fFound, xdnNode )); if(fFound == false) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_BAD_FORMAT); } wmihp->m_szClass = szValue;
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetValue( NULL, vValue, fFound, xdnNode )); if(fFound) { if(SUCCEEDED(vValue.ChangeType( VT_BSTR ))) { wmihp->m_szWQL = OLE2W( vValue.bstrVal ); } } } }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Database::Load() { __HCP_FUNC_ENTRY( "WMIHistory::Database::Load" );
HRESULT hr; MPC::XmlUtil xml;
//
// Load the database.
//
if(SUCCEEDED(LoadCIM( TEXT_INDEX, xml, TEXT_TAG_HC_HISTORY ))) { CComPtr<IXMLDOMNodeList> xdnlList; CComPtr<IXMLDOMNode> xdnNode; MPC::wstring szValue; bool fFound; LONG lVersion;
//
// First of all, check database version.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_HC_VERSION, lVersion, fFound )); if(fFound && lVersion == DATABASE_VERSION) { __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_HC_SEQ, m_lSequence, fFound )); m_lSequence_Latest = m_lSequence;
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_HC_TIMESTAMP, szValue, fFound )); if(fFound) { __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertStringToDate( szValue, m_dTimestamp_Latest )); }
//
// Enumerate all the PROVIDER elements.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetNodes( TEXT_TAG_PROVIDER, &xdnlList )); for(;SUCCEEDED(hr = xdnlList->nextNode( &xdnNode )) && xdnNode != NULL; xdnNode = NULL) { Provider* wmihp; MPC::wstring szNamespace; MPC::wstring szClass;
//
// Read the attributes.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_PROVIDER_NAMESPACE, szValue, fFound, xdnNode )); if(fFound) { szNamespace = szValue; }
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( NULL, TEXT_ATTR_PROVIDER_CLASS, szValue, fFound, xdnNode )); if(fFound) { szClass = szValue; }
//
// If the provider is present in the Schema, parse it.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, find_Provider( NULL, &szNamespace, &szClass, wmihp )); if(wmihp) { MPC::XmlUtil xmlSub( xdnNode ); CComPtr<IXMLDOMNodeList> xdnlSubList; CComPtr<IXMLDOMNode> xdnSubNode;
//
// Enumerate all the COLLECTEDDATA elements.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetNodes( TEXT_TAG_CD, &xdnlSubList )); for(;SUCCEEDED(hr = xdnlSubList->nextNode( &xdnSubNode )) && xdnSubNode != NULL; xdnSubNode = NULL) { MPC::wstring szTimestamp; MPC::wstring szFile; LONG lSequence = 0; long lCRC = 0; DATE dTimestampT0 = 0; DATE dTimestampT1 = 0;
//
// Read the attributes.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_FILE, szFile, fFound, xdnSubNode ));
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_SEQ, lSequence, fFound, xdnSubNode )); __MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_CRC, lCRC , fFound, xdnSubNode ));
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T0, szTimestamp, fFound, xdnSubNode )); if(fFound) { __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertStringToDate( szTimestamp, dTimestampT0 )); }
__MPC_EXIT_IF_METHOD_FAILS(hr, xmlSub.GetAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T1, szTimestamp, fFound, xdnSubNode )); if(fFound) { __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertStringToDate( szTimestamp, dTimestampT1 )); }
if(szFile.length() && dTimestampT0 != 0) { Data* wmihpd;
//
// Create a new Collected Data object.
//
__MPC_EXIT_IF_ALLOC_FAILS(hr, wmihpd, new Data( wmihp )); wmihp->m_lstData.push_back( wmihpd );
wmihpd->m_szFile = szFile; wmihpd->m_lSequence = lSequence; wmihpd->m_dwCRC = lCRC; wmihpd->m_dTimestampT0 = dTimestampT0; wmihpd->m_dTimestampT1 = dTimestampT1; wmihpd->m_fDontDelete = true; } } } } } }
__MPC_EXIT_IF_METHOD_FAILS(hr, PurgeFiles());
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Database::Save() { __HCP_FUNC_ENTRY( "WMIHistory::Database::Save" );
HRESULT hr; MPC::XmlUtil xml; ProvIter it; MPC::wstring szValue; bool fFound;
//
// Create a new database.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.New( TEXT_TAG_HC_HISTORY ));
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_HC_VERSION, (LONG)DATABASE_VERSION, fFound ));
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_HC_SEQ, m_lSequence, fFound ));
__MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertDateToString( m_dTimestamp, szValue )); __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_HC_TIMESTAMP, szValue, fFound ));
//
// Enumerate all the providers.
//
for(it=m_lstProviders.begin(); it != m_lstProviders.end(); it++) { Provider* wmihp = *it; Provider::DataIterConst itSub; CComPtr<IXMLDOMNode> xdnNode; long lMaxDeltas = WMIHISTORY_MAX_NUMBER_OF_DELTAS;
//
// Don't generate a "Provider" element if there's no data associated with it.
//
if(wmihp->m_lstData.size() == 0) { continue; }
//
// Create a PROVIDER element.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_PROVIDER, &xdnNode ));
//
// Set its attributes.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_PROVIDER_NAMESPACE, wmihp->m_szNamespace, fFound, xdnNode )); __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_PROVIDER_CLASS , wmihp->m_szClass , fFound, xdnNode ));
//
// Enumerate all the collected data entries.
//
for(itSub=wmihp->m_lstData.begin(); itSub != wmihp->m_lstData.end(); itSub++) { Data* wmihpd = *itSub;
if(lMaxDeltas-- < 0) // Don't count initial snapshot.
{ //
// Exceed maximum number of deltas, start purgeing oldest ones.
//
wmihpd->m_fDontDelete = false; } else { CComPtr<IXMLDOMNode> xdnSubNode;
//
// Create a COLLECTEDDATA element.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.CreateNode( TEXT_TAG_CD, &xdnSubNode, xdnNode ));
//
// Set its attributes.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_FILE, wmihpd->m_szFile , fFound, xdnSubNode )); __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_SEQ , wmihpd->m_lSequence, fFound, xdnSubNode )); __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_CRC , wmihpd->m_dwCRC , fFound, xdnSubNode ));
__MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertDateToString( wmihpd->m_dTimestampT0, szValue )); __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T0, szValue, fFound, xdnSubNode ));
if(wmihpd->m_dTimestampT1) { __MPC_EXIT_IF_METHOD_FAILS(hr, Local_ConvertDateToString( wmihpd->m_dTimestampT1, szValue )); __MPC_EXIT_IF_METHOD_FAILS(hr, xml.PutAttribute( NULL, TEXT_ATTR_CD_TIMESTAMP_T1, szValue, fFound, xdnSubNode )); } } } }
{ DWORD dwCRC; // Not used.
__MPC_EXIT_IF_METHOD_FAILS(hr, SaveCIM( TEXT_INDEX, xml, dwCRC )); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Database::get_Providers( /*[out]*/ ProvIterConst& itBegin , /*[out]*/ ProvIterConst& itEnd ) { itBegin = m_lstProviders.begin(); itEnd = m_lstProviders.end ();
return S_OK; }
HRESULT WMIHistory::Database::find_Provider( /*[in]*/ ProvIterConst* it , /*[in]*/ const MPC::wstring* szNamespace, /*[in]*/ const MPC::wstring* szClass , /*[in]*/ Provider* & wmihp ) { ProvIterConst itFake; MPC::NocaseCompare cmp;
wmihp = NULL;
//
// If the caller hasn't provider an iterator, provide a local one,
// pointing to the beginning of the list.
//
if(it == NULL) { it = &itFake; itFake = m_lstProviders.begin(); }
while(*it != m_lstProviders.end()) { Provider* prov = *(*it)++;
if((szNamespace == NULL || cmp( *szNamespace, prov->m_szNamespace )) && (szClass == NULL || cmp( *szClass , prov->m_szClass )) ) { wmihp = prov; break; } }
return S_OK; }
/////////////////////////////////////////////////////////////////////////////
HRESULT WMIHistory::Database::LoadCIM( /*[in]*/ LPCWSTR szFile , /*[in]*/ MPC::XmlUtil& xml , /*[in]*/ LPCWSTR szTag ) { __HCP_FUNC_ENTRY( "WMIHistory::Database::LoadCIM" );
HRESULT hr; MPC::wstring szFullFile = szFile; GetFullPathName( szFullFile ); bool fLoaded; bool fFound;
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.Load( szFullFile.c_str(), szTag, fLoaded, &fFound )); if(fLoaded == false || fFound == false ) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Database::SaveCIM( /*[in]*/ LPCWSTR szFile , /*[in]*/ MPC::XmlUtil& xml , /*[out]*/ DWORD& dwCRC ) { __HCP_FUNC_ENTRY( "WMIHistory::Database::SaveCIM" );
HRESULT hr; MPC::wstring szFullFile = szFile; GetFullPathName( szFullFile );
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.Save ( szFullFile.c_str() )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ComputeCRC( dwCRC, szFullFile.c_str() ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
HRESULT WMIHistory::Database::GetLock( /*[in]*/ DWORD dwMilliseconds ) { __HCP_FUNC_ENTRY( "WMIHistory::Database::GetLock" );
HRESULT hr; WCHAR szMutexName[MAX_PATH]; LPWSTR szPos;
//
// If the database directory is set, protect it using a mutex.
//
if(m_szBase.length()) { //Bug 578172, Change to safe functions (replaced swprintf with safe function)
StringCchPrintfW( szMutexName, ARRAYSIZE(szMutexName),L"PCHMUTEX_%s", m_szBase.c_str() );
//
// Make sure no strange characters are present in the mutex name.
//
for(szPos=szMutexName; *szPos; szPos++) { *szPos = (WCHAR)towlower( *szPos );
if(*szPos == ':' || *szPos == '/' || *szPos == '\\' ) { *szPos = '_'; } }
__MPC_EXIT_IF_METHOD_FAILS(hr, SetName( szMutexName )); __MPC_EXIT_IF_METHOD_FAILS(hr, Acquire( dwMilliseconds )); }
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr); }
|