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

/******************************************************************************
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);
}