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.
 
 
 
 
 
 

2010 lines
69 KiB

/*++
Copyright (C) 1999-2001 Microsoft Corporation
Module Name:
ADAPPERF.CPP
Abstract:
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include <wbemcli.h>
#include <cominit.h>
#include <WinMgmtR.h>
#include "ntreg.h"
#include "adapperf.h"
#include "adaputil.h"
#define PL_TIMEOUT 100000 // The timeout value for waiting on a function mutex
#define GUARD_BLOCK "WMIADAP_WMIADAP_WMIADAP_WMIADAP_WMIADAP_WMIADAP_WMIADAP_WMIADAP"
BYTE CAdapSafeBuffer::s_pGuardBytes[] = GUARD_BLOCK;
////////////////////////////////////////////////////////////////////////////////////////////
//
// CAdapSafeDataBlock
//
////////////////////////////////////////////////////////////////////////////////////////////
CAdapSafeBuffer::CAdapSafeBuffer( WString wstrServiceName )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
////////////////////////////////////////////////////////////////////////////////////////////
: m_dwGuardSize ( 0 ),
m_hPerfLibHeap ( NULL ),
m_pRawBuffer ( NULL ),
m_pSafeBuffer ( NULL ),
m_dwSafeBufferSize ( 0 ),
m_pCurrentPtr ( NULL ),
m_dwNumObjects ( 0 ),
m_wstrServiceName ( wstrServiceName )
{
// Initialize the guard byte pattern
// =================================
m_dwGuardSize = sizeof( GUARD_BLOCK );
// Create the private heap
// =======================
m_hPerfLibHeap = HeapCreate( 0, 0x100000, 0 );
// If the private heap could not be created, then use the process heap
// ===================================================================
if ( NULL == m_hPerfLibHeap )
{
m_hPerfLibHeap = GetProcessHeap();
}
}
CAdapSafeBuffer::~CAdapSafeBuffer()
////////////////////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
////////////////////////////////////////////////////////////////////////////////////////////
{
// Deallocate the raw buffer
// =========================
if ( NULL != m_pRawBuffer )
{
HeapFree( m_hPerfLibHeap, 0, m_pRawBuffer );
}
// Destroy the private heap
// ========================
if ( ( NULL != m_hPerfLibHeap ) && ( GetProcessHeap() != m_hPerfLibHeap ) )
{
HeapDestroy( m_hPerfLibHeap );
}
}
HRESULT CAdapSafeBuffer::SetSize( DWORD dwNumBytes )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Sets the size of the safe buffer. Memory is actually allocated for the raw buffer, and
// the safe buffer just sits in the raw buffer between the set of guard bytes
//
// Parameters:
// dwNumBytes - the number of bytes requested for the safe buffer
//
////////////////////////////////////////////////////////////////////////////////////////////
{
HRESULT hr = WBEM_NO_ERROR;
DWORD dwRawBufferSize = 0;
// Check for roll-over
// ===================
if ( dwNumBytes > ( 0xFFFFFFFF - ( 2 * m_dwGuardSize ) ) )
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if ( SUCCEEDED ( hr ) )
{
// Set the total size of the buffer
// ================================
m_dwSafeBufferSize = dwNumBytes;
dwRawBufferSize = dwNumBytes + ( 2 * m_dwGuardSize );
// Allocate the memory
// ===================
if ( NULL == m_pRawBuffer )
{
// First time allocation
// =====================
m_pRawBuffer = (BYTE*) HeapAlloc( m_hPerfLibHeap,
HEAP_ZERO_MEMORY,
dwRawBufferSize );
}
else
{
BYTE * pTmp = (BYTE *)HeapReAlloc( m_hPerfLibHeap,
HEAP_ZERO_MEMORY,
m_pRawBuffer,
dwRawBufferSize );
if (pTmp)
{
m_pRawBuffer = pTmp;
}
else
{
HeapFree(m_hPerfLibHeap,0,m_pRawBuffer);
m_pRawBuffer = NULL;
}
}
if ( NULL != m_pRawBuffer )
{
// Set the safe buffer pointer
// ===========================
m_pSafeBuffer = m_pRawBuffer + m_dwGuardSize;
// Set the prefix guard bytes
// =========================
memcpy( m_pRawBuffer, s_pGuardBytes, m_dwGuardSize );
// Set the suffix guard bytes
// ==========================
memcpy( m_pSafeBuffer + m_dwSafeBufferSize, s_pGuardBytes, m_dwGuardSize );
}
else
{
m_pSafeBuffer = NULL;
m_pCurrentPtr = NULL;
m_dwSafeBufferSize = 0;
hr = WBEM_E_OUT_OF_MEMORY;
}
}
return hr;
}
HRESULT CAdapSafeBuffer::Validate(BOOL * pSentToEventLog)
////////////////////////////////////////////////////////////////////////////////////////////
//
// Validate will compare the size of the pointer displacement matches the byte size
// returned from the collection, validates the guard bytes and walks the blob, verifying
// that all of the pointers are within the boundary of the blob
//
////////////////////////////////////////////////////////////////////////////////////////////
{
HRESULT hr = WBEM_NO_ERROR;
try
{
PERF_OBJECT_TYPE* pObject = (PERF_OBJECT_TYPE*) m_pSafeBuffer;
// Validate that if we have objects, then we have mass
// ===================================================
if ( ( 0 < m_dwNumObjects ) && ( 0 == m_dwDataBlobSize ) )
{
hr = WBEM_E_FAILED;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_BLOB_HAS_NO_SIZE,
(LPCWSTR)m_wstrServiceName );
if (pSentToEventLog) {
*pSentToEventLog = TRUE;
}
}
// Validate that that number of bytes returned is the same as the pointer displacement
// ===================================================================================
if ( SUCCEEDED( hr ) && ( ( m_pCurrentPtr - m_pSafeBuffer ) != m_dwDataBlobSize ) )
{
hr = WBEM_E_FAILED;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_BAD_PERFLIB_INVALID_DATA,
(LPCWSTR)m_wstrServiceName, CHex( hr ) );
if (pSentToEventLog) {
*pSentToEventLog = TRUE;
}
}
if ( SUCCEEDED ( hr ) )
{
// Validate the guard bytes
// ========================
if ( 0 != memcmp( m_pRawBuffer, s_pGuardBytes, m_dwGuardSize) )
{
hr = WBEM_E_FAILED;
CAdapUtility::NTLogEvent( EVENTLOG_ERROR_TYPE,
WBEM_MC_ADAP_BAD_PERFLIB_MEMORY,
(LPCWSTR)m_wstrServiceName, CHex( hr ) );
if (pSentToEventLog) {
*pSentToEventLog = TRUE;
}
}
else
{
if ( 0 != memcmp( m_pSafeBuffer + m_dwSafeBufferSize, s_pGuardBytes, m_dwGuardSize) )
{
hr = WBEM_E_FAILED;
CAdapUtility::NTLogEvent( EVENTLOG_ERROR_TYPE,
WBEM_MC_ADAP_BAD_PERFLIB_MEMORY,
(LPCWSTR)m_wstrServiceName, CHex( hr ) );
if (pSentToEventLog) {
*pSentToEventLog = TRUE;
}
}
}
}
// Validate the blob
// =================
if ( SUCCEEDED( hr ) )
{
for ( int nObject = 0; SUCCEEDED( hr ) && nObject < m_dwNumObjects; nObject++ )
{
PERF_COUNTER_DEFINITION* pCtr = NULL;
DWORD dwCtrBlockSize = 0;
// Validate the object pointer
// ===========================
hr = ValidateSafePointer( (BYTE*) pObject );
if ( SUCCEEDED( hr ) )
{
// Validate the counter definitions
// ================================
if ( 0 == pObject->HeaderLength )
{
hr = WBEM_E_FAILED;
}
else
{
pCtr = ( PERF_COUNTER_DEFINITION* ) ( ( ( BYTE* ) pObject ) + pObject->HeaderLength );
}
}
for( int nCtr = 0; SUCCEEDED( hr ) && nCtr < pObject->NumCounters; nCtr++)
{
hr = ValidateSafePointer( ( BYTE* ) pCtr );
if ( SUCCEEDED( hr ) )
{
dwCtrBlockSize += pCtr->CounterSize;
if ( nCtr < ( pObject->NumCounters - 1 ) )
{
if ( 0 == pCtr->ByteLength )
{
hr = WBEM_E_FAILED;
}
else
{
pCtr = ( PERF_COUNTER_DEFINITION* ) ( ( ( BYTE* ) pCtr ) + pCtr->ByteLength );
}
}
}
}
// Validate the data
// =================
if ( pObject->NumInstances >= 0 )
{
// Blob has instances
// ==================
PERF_INSTANCE_DEFINITION* pInstance = NULL;
if ( 0 == pObject->DefinitionLength )
{
hr = WBEM_E_FAILED;
}
else
{
pInstance = ( PERF_INSTANCE_DEFINITION* ) ( ( ( BYTE* ) pObject ) + pObject->DefinitionLength );
}
// Validate the instances
// ======================
for ( int nInst = 0; SUCCEEDED( hr ) && nInst < pObject->NumInstances; nInst++ )
{
hr = ValidateSafePointer( ( BYTE* ) pInstance );
if ( SUCCEEDED( hr ) )
{
PERF_COUNTER_BLOCK* pCounterBlock = NULL;
// Validate the counter blocks
// ===========================
if ( 0 == pInstance->ByteLength )
{
hr = WBEM_E_FAILED;
}
else
{
pCounterBlock = ( PERF_COUNTER_BLOCK* ) ( ( ( BYTE* ) pInstance ) + pInstance->ByteLength );
hr = ValidateSafePointer( ( BYTE* ) pCounterBlock );
}
if ( SUCCEEDED( hr ) )
{
// Is the counter block the same size as the aggregation of the counter sizes?
// ===========================================================================
if ( ( nInst < pObject->NumInstances - 1 ) && SUCCEEDED( hr ) )
{
pInstance = ( PERF_INSTANCE_DEFINITION* ) ( ( ( BYTE* ) pCounterBlock ) + pCounterBlock->ByteLength );
hr = ValidateSafePointer( (BYTE*) pInstance );
}
//
// validate the size of the last object against
// the 'aperture' of the buffer
//
/*
if (SUCCEEDED(hr) && (nInst == (pObject->NumInstances - 1)))
{
BYTE * pLast = ( ( ( BYTE* ) pCounterBlock ) + pCounterBlock->ByteLength );
// now pLast is 1 byte over the "end" of the buffer
if (pLast > m_pCurrentPtr)
{
hr = WBEM_E_FAILED;
}
}
*/
}
}
}
}
else
{
// Blob is a singleton. Validate the counter blocks
// ================================================
if ( 0 == pObject->DefinitionLength )
{
hr = WBEM_E_FAILED;
}
else
{
PERF_COUNTER_BLOCK* pCounterBlock = ( PERF_COUNTER_BLOCK* ) ( ( ( BYTE* ) pObject ) + pObject->DefinitionLength );
hr = ValidateSafePointer( ( BYTE* ) pCounterBlock );
}
}
// Get the next object as long as one exists
// =========================================
if ( nObject < ( m_dwNumObjects - 1 ) )
{
pObject = (PERF_OBJECT_TYPE*)((BYTE*)pObject + pObject->TotalByteLength);
hr = ValidateSafePointer( ( BYTE* ) pObject );
}
}
}
}
catch(...)
{
hr = WBEM_E_FAILED;
}
return hr;
}
HRESULT CAdapSafeBuffer::ValidateSafePointer( BYTE* pPtr )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Verifys that the pointer is within the blob. The blob occupies the memory starting at
// the beginning of the safe buffer, and termintes at an offset equal to m_dwDataBlobSize
//
// Parameters:
// pPtr - a pointer to be verified
//
////////////////////////////////////////////////////////////////////////////////////////////
{
HRESULT hr = WBEM_NO_ERROR;
// NOTE: The upper limit of the safe buffer is 1 byte less the blob pointer plus the blob size since
// the first byte of the blob is also the first byte. Imagine he case with a blob of size 1.
// =================================================================================================
if ( ( pPtr < m_pSafeBuffer ) || ( pPtr > ( m_pSafeBuffer + m_dwDataBlobSize - 1 ) ) )
{
hr = WBEM_E_FAILED;
}
if ( FAILED ( hr ) )
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_BAD_PERFLIB_INVALID_DATA,
(LPCWSTR)m_wstrServiceName, CHex( hr ) );
}
return hr;
}
HRESULT CAdapSafeBuffer::CopyData( BYTE** ppData, DWORD* pdwNumBytes, DWORD* pdwNumObjects )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Copies the blob data from the private heap into the process heap. The method will
// allocate memory in the process heap.
//
// Parameters:
// ppData - a pointer to an unallocated byte array
//
////////////////////////////////////////////////////////////////////////////////////////////
{
if (NULL == ppData || NULL == pdwNumBytes || NULL == pdwNumObjects) return WBEM_E_INVALID_PARAMETER;
HRESULT hr = WBEM_NO_ERROR;
*ppData = new BYTE[m_dwDataBlobSize];
if ( NULL == *ppData )
{
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
memcpy( *ppData, m_pSafeBuffer, m_dwDataBlobSize );
}
*pdwNumBytes = m_dwDataBlobSize;
*pdwNumObjects = m_dwNumObjects;
return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// CAdapPerfLib
//
////////////////////////////////////////////////////////////////////////////////////////////
CAdapPerfLib::CAdapPerfLib( LPCWSTR pwcsServiceName, DWORD * pLoadStatus )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
// Initializes all member variables, sets the library and function names, opens the library,
// sets the entry point addresses, creates the perflib processing mutex, and opens the
// processing thread.
//
// Parameters:
// pwcsServiceName - A Unicode string specifying the name of the perflib service.
//
////////////////////////////////////////////////////////////////////////////////////////////
: m_wstrServiceName( pwcsServiceName ),
m_pfnOpenProc( NULL ),
m_pfnCollectProc( NULL ),
m_pfnCloseProc( NULL ),
m_pwcsLibrary( NULL ),
m_pwcsOpenProc( NULL ),
m_pwcsCollectProc( NULL ),
m_pwcsCloseProc( NULL ),
m_hLib( NULL ),
m_fOpen( FALSE ),
m_dwStatus( 0 ),
m_pPerfThread( NULL ),
m_hPLMutex( NULL ),
m_fOK( FALSE ),
m_EventLogCalled( FALSE ),
m_CollectOK( TRUE ),
m_dwFirstCtr(2),
m_dwLastCtr(CPerfNameDb::GetSystemReservedHigh())
{
DEBUGTRACE( ( LOG_WMIADAP, "Constructing the %S performance library wrapper.\n", pwcsServiceName ) );
HRESULT hr = WBEM_NO_ERROR;
// Verify that the perflib is loaded
// Initialize the performance library name and entry point names
// =============================================================
hr = VerifyLoaded();
if (FAILED(hr))
{
ERRORTRACE( ( LOG_WMIADAP, "VerifyLoaded for %S hr = %08x.\n", pwcsServiceName, hr ) );
}
// Set the processing status information for this attempt
// ======================================================
if ( SUCCEEDED ( hr ) )
{
if (pLoadStatus)
{
(*pLoadStatus) |= EX_STATUS_LOADABLE;
}
hr = BeginProcessingStatus();
if ( hr == WBEM_S_ALREADY_EXISTS )
{
SetStatus( ADAP_PERFLIB_PREVIOUSLY_PROCESSED );
}
}
m_fOK = SUCCEEDED( hr );
if ( !m_fOK )
{
ERRORTRACE( ( LOG_WMIADAP, "Construction of the %S perflib wrapper failed hr = %08x.\n", pwcsServiceName, hr ) );
}
}
CAdapPerfLib::~CAdapPerfLib( void )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
////////////////////////////////////////////////////////////////////////////////////////////
{
DEBUGTRACE( ( LOG_WMIADAP, "Destructing the %S performance library wrapper.\n", (LPWSTR)m_wstrServiceName) );
delete m_pPerfThread;
// Delete the library and entry point names
// ========================================
delete [] m_pwcsLibrary;
delete [] m_pwcsOpenProc;
delete [] m_pwcsCollectProc;
delete [] m_pwcsCloseProc;
// Free the library
// ================
if ( NULL != m_hLib )
{
try
{
FreeLibrary( m_hLib );
}
catch (...)
{
ERRORTRACE(( LOG_WMIADAP,"FreeLibrary for Service %S threw an exception",(LPWSTR)m_wstrServiceName) );
}
DEBUGTRACE( ( LOG_WMIADAP, "Library for Service %S Freed.\n",(LPWSTR)m_wstrServiceName ) );
}
}
HRESULT CAdapPerfLib::VerifyLoaded()
{
HRESULT hr = WBEM_E_FAILED;
WString wszRegPath = L"SYSTEM\\CurrentControlSet\\Services\\";
wszRegPath += m_wstrServiceName;
wszRegPath += L"\\Performance";
CNTRegistry reg;
int nRet = 0;
nRet = reg.Open( HKEY_LOCAL_MACHINE, wszRegPath );
switch( nRet )
{
case CNTRegistry::no_error:
{
DWORD dwFirstCtr = 0;
DWORD dwLastCtr = 0;
WCHAR* wszObjList = NULL;
if ( ( ( reg.GetDWORD( L"First Counter", &dwFirstCtr ) == CNTRegistry::no_error ) &&
( reg.GetDWORD( L"Last Counter", &dwLastCtr ) == CNTRegistry::no_error ) ) ||
( reg.GetStr( L"Object List", &wszObjList ) == CNTRegistry::no_error ))
{
hr = InitializeEntryPoints(reg,wszRegPath);
if (wszObjList)
{
delete [] wszObjList;
}
if (dwFirstCtr && dwLastCtr)
{
m_dwFirstCtr = dwFirstCtr;
m_dwLastCtr = dwLastCtr;
}
}
else // more special cases
{
if ( m_wstrServiceName.EqualNoCase( L"TCPIP" ) ||
m_wstrServiceName.EqualNoCase( L"TAPISRV") ||
m_wstrServiceName.EqualNoCase( L"PERFOS" ) ||
m_wstrServiceName.EqualNoCase( L"PERFPROC" ) ||
m_wstrServiceName.EqualNoCase( L"PERFDISK" ) ||
m_wstrServiceName.EqualNoCase( L"PERFNET" ) ||
m_wstrServiceName.EqualNoCase( L"SPOOLER" ) ||
m_wstrServiceName.EqualNoCase( L"MSFTPSvc" ) ||
m_wstrServiceName.EqualNoCase( L"RemoteAccess" ) ||
m_wstrServiceName.EqualNoCase( L"WINS" ) ||
m_wstrServiceName.EqualNoCase( L"MacSrv" ) ||
m_wstrServiceName.EqualNoCase( L"AppleTalk" ) ||
m_wstrServiceName.EqualNoCase( L"NM" ) ||
m_wstrServiceName.EqualNoCase( L"RSVP" ) )
{
hr = InitializeEntryPoints(reg,wszRegPath);
}
else
{
hr = WBEM_E_FAILED;
}
}
}break;
case CNTRegistry::not_found:
{
// This shouldn't happen since this is how a perflib is defined
hr = WBEM_E_FAILED;
}break;
case CNTRegistry::access_denied:
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPWSTR)wszRegPath, nRet );
}break;
}
return hr;
}
HRESULT CAdapPerfLib::InitializeEntryPoints(CNTRegistry & reg,WString & wszRegPath){
HRESULT hr = WBEM_S_NO_ERROR;
// see if someone disabled this library
DWORD dwDisable = 0;
if ( CNTRegistry::no_error == reg.GetDWORD( L"Disable Performance Counters", &dwDisable ) &&
(dwDisable != 0) )
{
hr = WBEM_E_FAILED;
}
else
{
hr = WBEM_S_NO_ERROR;
}
// the perflib is OK for the world, see if it os OK for US
if (SUCCEEDED(hr)){
if (!(( reg.GetStr( L"Library", &m_pwcsLibrary ) == CNTRegistry::no_error ) &&
( reg.GetStr( L"Open", &m_pwcsOpenProc ) == CNTRegistry::no_error)&&
( reg.GetStr( L"Collect", &m_pwcsCollectProc ) == CNTRegistry::no_error) &&
( reg.GetStr( L"Close", &m_pwcsCloseProc ) == CNTRegistry::no_error ) ))
{
WString wstrPath(wszRegPath);
if (m_pwcsLibrary == NULL){
wstrPath += L"\\Library";
} else if (m_pwcsCollectProc == NULL) {
wstrPath += L"\\Collect";
}
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPWSTR)wstrPath, CHex( WBEM_E_NOT_AVAILABLE ) );
hr = WBEM_E_FAILED;
} else {
hr = WBEM_S_NO_ERROR;
}
}
return hr;
}
HRESULT CAdapPerfLib::Initialize()
{
// Load the perflib and initialize the procedure addresses
// =======================================================
HRESULT hr = Load();
// Initialize the named function mutex (see WbemPerf for syntax of Mutex name)
// ===========================================================================
if ( SUCCEEDED( hr ) )
{
size_t cchSizeTmp = m_wstrServiceName.Length() + 256;
WCHAR* wcsMutexName = new WCHAR[cchSizeTmp];
if (NULL == wcsMutexName) return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<WCHAR> dmMutexName( wcsMutexName );
StringCchPrintfW( wcsMutexName, cchSizeTmp, L"Global\\%s_Perf_Library_Lock_PID_%x", (WCHAR *)m_wstrServiceName, GetCurrentProcessId() );
m_hPLMutex = CreateMutexW( 0, FALSE, wcsMutexName);
if ( NULL == m_hPLMutex )
{
hr = WBEM_E_FAILED;
}
}
// Create the worker thread
// ========================
if ( SUCCEEDED( hr ) )
{
m_pPerfThread = new CPerfThread( this );
if ( ( NULL == m_pPerfThread) || ( !m_pPerfThread->IsOk() ) )
{
hr = WBEM_E_FAILED;
}
else
{
hr = m_pPerfThread->Open( this );
}
}
if ( FAILED( hr ) )
{
SetStatus( ADAP_PERFLIB_IS_INACTIVE );
}
return hr;
}
HRESULT CAdapPerfLib::GetFileSignature( CheckLibStruct * pCheckLib )
{
HRESULT hr = WBEM_S_NO_ERROR;
if (!pCheckLib){
return WBEM_E_INVALID_PARAMETER;
}
// Get the current library's file time
// ===================================
HANDLE hFile = NULL;
DWORD dwRet = 0;
WCHAR wszFullPath[MAX_PATH];
WCHAR* pwcsTemp = NULL;
if ( 0 != SearchPathW( NULL, m_pwcsLibrary, NULL, MAX_PATH, wszFullPath, &pwcsTemp ) )
{
// Use GetFileAttributes to validate the path.
DWORD dwAttributes = GetFileAttributesW(wszFullPath);
if (dwAttributes == 0xFFFFFFFF) return WBEM_E_FAILED;
// create mask of the attributes that would make an existing file invalid for use
DWORD dwMask = FILE_ATTRIBUTE_DEVICE |
FILE_ATTRIBUTE_DIRECTORY |
FILE_ATTRIBUTE_OFFLINE |
FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_REPARSE_POINT |
FILE_ATTRIBUTE_SPARSE_FILE |
FILE_ATTRIBUTE_SYSTEM |
FILE_ATTRIBUTE_TEMPORARY;
if (dwAttributes & dwMask) return WBEM_E_FAILED;
hFile = CreateFileW( wszFullPath,
GENERIC_READ,
FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( INVALID_HANDLE_VALUE != hFile )
{
OnDelete<HANDLE,BOOL(*)(HANDLE),CloseHandle> CloseMe(hFile);
DWORD dwFileSizeLow = 0;
DWORD dwFileSizeHigh = 0;
__int32 nFileSize = 0;
DWORD dwNumRead = 0;
BYTE* aBuffer = NULL;
dwFileSizeLow = GetFileSize( hFile, &dwFileSizeHigh );
nFileSize = ( dwFileSizeHigh << 32 ) + dwFileSizeLow;
FILETIME ft;
if (GetFileTime(hFile,&ft,NULL,NULL))
{
aBuffer = new BYTE[nFileSize];
CDeleteMe<BYTE> dmBuffer( aBuffer );
if ( NULL != aBuffer )
{
if ( ReadFile( hFile, aBuffer, nFileSize, &dwNumRead, FALSE ) )
{
MD5 md5;
BYTE aSignature[16];
md5.Transform( aBuffer, dwNumRead, aSignature );
// return our data
memcpy(pCheckLib->Signature,aSignature,sizeof(aSignature));
pCheckLib->FileTime = ft;
pCheckLib->FileSize = nFileSize;
}
else
{
hr = WBEM_E_TOO_MUCH_DATA;
}
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
hr = WBEM_E_FAILED;
}
}
else
{
ERRORTRACE((LOG_WMIADAP,"GetFileSignature for %S err %d\n",wszFullPath,GetLastError()));
hr = WBEM_E_FAILED;
}
}
else
{
hr = WBEM_E_NOT_FOUND;
}
return hr;
}
HRESULT CAdapPerfLib::SetFileSignature()
{
HRESULT hr = WBEM_S_NO_ERROR;
CNTRegistry reg;
int nRet = 0;
CheckLibStruct CheckLib;
// Clear the signature buffer
// ==========================
memset( &CheckLib, 0, sizeof(CheckLib) );
// Get the current file time stamp
// ===============================
hr = GetFileSignature( &CheckLib );
// And write it into the registry key
// ==================================
if ( SUCCEEDED( hr ) )
{
WString wstr;
try
{
wstr = L"SYSTEM\\CurrentControlSet\\Services\\";
wstr += m_wstrServiceName;
wstr += L"\\Performance";
}
catch(...)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if ( SUCCEEDED( hr ) )
{
nRet = reg.Open( HKEY_LOCAL_MACHINE , wstr );
switch ( nRet )
{
case CNTRegistry::no_error:
{
}break;
case CNTRegistry::access_denied:
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, nRet );
}
default:
hr = WBEM_E_FAILED;
}
}
if ( SUCCEEDED( hr ) )
{
int nRet1 = reg.SetBinary( ADAP_PERFLIB_SIGNATURE, (PBYTE)&CheckLib.Signature, sizeof( BYTE[16] ) );
int nRet2 = reg.SetBinary( ADAP_PERFLIB_TIME, (PBYTE)&CheckLib.FileTime, sizeof( FILETIME ) );
int nRet3 = reg.SetDWORD( ADAP_PERFLIB_SIZE, CheckLib.FileSize );
if ( (CNTRegistry::no_error == nRet1) &&
(CNTRegistry::no_error == nRet2) &&
(CNTRegistry::no_error == nRet3))
{
// everything OK
}
else if ((CNTRegistry::access_denied == nRet1) ||
(CNTRegistry::access_denied == nRet2) ||
(CNTRegistry::access_denied == nRet3))
{
WString wstrPath = wstr;
wstrPath += ADAP_PERFLIB_SIGNATURE;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstrPath, CNTRegistry::access_denied );
}
else
{
hr = WBEM_E_FAILED;
}
}
}
return hr;
}
HRESULT CAdapPerfLib::CheckFileSignature()
{
HRESULT hr = WBEM_S_SAME;
CNTRegistry reg;
int nRet = 0;
BYTE cCurrentMD5[16];
BYTE* cStoredMD5 = NULL;
// Set the performance key path
// ============================
WString wstr;
try
{
wstr = L"SYSTEM\\CurrentControlSet\\Services\\";
wstr += m_wstrServiceName;
wstr += L"\\Performance";
}
catch(...)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if ( SUCCEEDED( hr ) )
{
// Open the performance key
// ========================
nRet = reg.Open( HKEY_LOCAL_MACHINE , wstr );
switch ( nRet )
{
case CNTRegistry::no_error:
{
}break;
case CNTRegistry::access_denied:
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, nRet );
hr = WBEM_E_FAILED;
}break;
default:
{
hr = WBEM_E_FAILED;
}break;
}
}
if ( SUCCEEDED( hr ) )
{
// Get the stored file signature
// =============================
CheckLibStruct StoredLibStruct;
int nRet1;
int nRet2;
int nRet3;
DWORD dwSizeBlob;
nRet1 = reg.GetBinary( ADAP_PERFLIB_SIGNATURE, (PBYTE*)&cStoredMD5,&dwSizeBlob);
CDeleteMe<BYTE> dmStoredMD5( cStoredMD5 );
if (cStoredMD5)
{
if ( sizeof(cCurrentMD5) == dwSizeBlob)
{
memcpy(&StoredLibStruct.Signature,cStoredMD5,sizeof(StoredLibStruct.Signature));
}
else
{
nRet1 = CNTRegistry::failed;
}
}
BYTE * pFileTime = NULL;
nRet2 = reg.GetBinary( ADAP_PERFLIB_TIME, (PBYTE*)&pFileTime,&dwSizeBlob);
CDeleteMe<BYTE> dmFileTime( pFileTime );
if (pFileTime)
{
if (sizeof(FILETIME) == dwSizeBlob )
{
memcpy(&StoredLibStruct.FileTime,pFileTime,sizeof(FILETIME));
}
else
{
nRet2 = CNTRegistry::failed;
}
}
nRet3 = reg.GetDWORD(ADAP_PERFLIB_SIZE,&StoredLibStruct.FileSize);
if ((CNTRegistry::access_denied == nRet1) ||
(CNTRegistry::access_denied == nRet2) ||
(CNTRegistry::access_denied == nRet3))
{
WString wstrPath = wstr;
wstrPath += ADAP_PERFLIB_SIGNATURE;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstrPath, nRet );
hr = WBEM_E_FAILED;
}
else if ((CNTRegistry::not_found == nRet1) ||
(CNTRegistry::not_found == nRet2) ||
(CNTRegistry::not_found == nRet3))
{
hr = WBEM_S_FALSE;
}
else if((CNTRegistry::out_of_memory == nRet1) ||
(CNTRegistry::out_of_memory == nRet2) ||
(CNTRegistry::out_of_memory == nRet3) ||
(CNTRegistry::failed == nRet1) ||
(CNTRegistry::failed == nRet2) ||
(CNTRegistry::failed == nRet3))
{
hr = WBEM_E_FAILED;
}
if ( SUCCEEDED( hr ) && ( WBEM_S_FALSE != hr ) )
{
// Get the current library's signature
// ===================================
CheckLibStruct CurrentLibStruct;
memset(&CurrentLibStruct,0,sizeof(CheckLibStruct));
hr = GetFileSignature( &CurrentLibStruct );
if ( SUCCEEDED( hr ) )
{
if ( (StoredLibStruct.FileSize == CurrentLibStruct.FileSize) &&
(0 == memcmp( &StoredLibStruct.Signature, &CurrentLibStruct.Signature, sizeof(CurrentLibStruct.Signature) )) &&
(0 == memcmp( &StoredLibStruct.FileTime, &CurrentLibStruct.FileTime, sizeof(FILETIME))) )
{
hr = WBEM_S_ALREADY_EXISTS;
}
else
{
hr = WBEM_S_FALSE;
}
}
}
}
return hr;
}
HRESULT CAdapPerfLib::BeginProcessingStatus()
////////////////////////////////////////////////////////////////////////////////////////////
//
// Opens the registry key, reads the ADAP_PERFLIB_STATUS_KEY, and processes the value as
// follows:
//
// ADAP_PERFLIB_OK: The perflib has been successfully accessed before. Set
// the status flag to ADAP_PERFLIB_PROCESSING
//
// ADAP_PERFLIB_PROCESSING: The perflib caused the process to fail. It is corrupt,
// set the status flag to ADAP_PERFLIB_CORRUPT.
//
// ADAP_PERFLIB_CORRUPT: The perflib is known to be corrupt. Status flag retains
// its value.
//
// No Value: The perflib has not been accessed before. Set the
// status flag to ADAP_PERFLIB_PROCESSING.
//
////////////////////////////////////////////////////////////////////////////////////////////
{
DEBUGTRACE( ( LOG_WMIADAP, "CAdapPerfLib::BeginProcessingStatus()...\n") );
HRESULT hr = WBEM_S_NO_ERROR;
CNTRegistry reg;
// Set the registry path
// =====================
WString wstr;
try
{
wstr = L"SYSTEM\\CurrentControlSet\\Services\\";
wstr += m_wstrServiceName;
wstr += L"\\Performance";
}
catch(...)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if ( SUCCEEDED( hr ) )
{
// Open the services key
// =====================
int nRet = reg.Open( HKEY_LOCAL_MACHINE, wstr );
switch ( nRet )
{
case CNTRegistry::access_denied:
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, nRet );
} break;
case CNTRegistry::no_error:
{
DWORD dwVal;
// Check perflib status
// ====================
hr = CheckFileSignature();
if ( SUCCEEDED( hr ) )
{
if ( WBEM_S_FALSE == hr )
{
// We've got a new perflib, reset the status
// =========================================
hr = SetFileSignature();
if ( SUCCEEDED( hr ) )
{
hr = reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, ADAP_PERFLIB_PROCESSING );
}
}
else // WBEM_S_ALREADY_EXISTS
{
// It's the same perflib, check the status
// =======================================
nRet = reg.GetDWORD( ADAP_PERFLIB_STATUS_KEY, &dwVal );
if ( nRet == CNTRegistry::no_error )
{
switch ( dwVal )
{
case ADAP_PERFLIB_OK: // 0
case ADAP_PERFLIB_PROCESSING: // 1
case ADAP_PERFLIB_BOOBOO: // 2
{
// So far, perflib has behaved within reason. Set it to processing state
// =====================================================================
reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, dwVal + 1 );
//ERRORTRACE( ( LOG_WMIADAP, "Performance library %S status %d\n",(LPWSTR)m_wstrServiceName,dwVal + 1));
}break;
case ADAP_PERFLIB_LASTCHANCE: // 3
{
// Perflib failed in the last access attempt before processing ended. Set as bad perflib
// =====================================================================================
reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, ADAP_PERFLIB_CORRUPT );
ERRORTRACE( ( LOG_WMIADAP, "Performance library %S status was left in the \"Processing\" state.\n",(LPWSTR)m_pwcsLibrary) );
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_BAD_PERFLIB_BAD_LIBRARY,
m_pwcsLibrary, CHex( (DWORD)-1 ) );
hr = WBEM_E_FAILED;
}break;
case ADAP_PERFLIB_CORRUPT: // -1
{
// Sign of a bad perflib. Do not open
// ==================================
ERRORTRACE( ( LOG_WMIADAP, "Performance library for %S has previously been disabled.\n",(LPWSTR)m_wstrServiceName) );
//CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_BAD_LIBRARY, m_pwcsLibrary, CHex( ADAP_PERFLIB_CORRUPT ) );
hr = WBEM_E_FAILED;
}break;
}
}
else if ( nRet == CNTRegistry::not_found )
{
// The status does not exist
// =========================
hr = reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, ADAP_PERFLIB_PROCESSING );
}
}
} else {
DEBUGTRACE( ( LOG_WMIADAP, "CheckFileSignature for %S %08x\n",(LPWSTR)m_wstrServiceName,hr ) );
}
}break;
default:
{
hr = WBEM_E_FAILED;
}break;
}
}
return hr;
}
HRESULT CAdapPerfLib::EndProcessingStatus()
////////////////////////////////////////////////////////////////////////////////////////////
//
// Opens the service registry key, reads the ADAP_PERFLIB_STATUS_KEY, and processes the
// value as follows:
//
// ADAP_PERFLIB_PROCESSING: Valid state. Set status flag to ADAP_PERFLIB_OK.
//
// ADAP_PERFLIB_CORRUPT: Valid state (may have been set during processing).
// Leave status flag as is.
//
// ADAP_PERFLIB_OK: Invalid state. Return an error and log an event.
//
// No Value: Invalid state. Return an error and log an event.
//
////////////////////////////////////////////////////////////////////////////////////////////
{
DEBUGTRACE( ( LOG_WMIADAP, "CAdapPerfLib::EndProcessingStatus()...\n") );
HRESULT hr = WBEM_S_NO_ERROR;
CNTRegistry reg;
WString wstr;
try
{
wstr = L"SYSTEM\\CurrentControlSet\\Services\\";
wstr += m_wstrServiceName;
wstr += L"\\Performance";
}
catch(...)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
if (SUCCEEDED(hr)){
// Open the services key
// =====================
int nRet = reg.Open( HKEY_LOCAL_MACHINE, wstr );
if ( CNTRegistry::access_denied == nRet )
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, nRet );
hr = WBEM_E_FAILED;
}
else if ( CNTRegistry::no_error == nRet )
{
DWORD dwVal = 0;
// Check perflib status
// ====================
if ( CheckStatus( ADAP_PERFLIB_FAILED ) )
{
// If we have a failure, then immediately mark the perflib as corrupt
// ==================================================================
hr = reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, ADAP_PERFLIB_CORRUPT );
if (!m_EventLogCalled){
m_EventLogCalled = TRUE;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_EXCEPTION, (LPCWSTR)m_wstrServiceName, CHex( hr ) );
}
}
else if ( reg.GetDWORD( ADAP_PERFLIB_STATUS_KEY, &dwVal) == CNTRegistry::no_error )
{
switch ( dwVal )
{
case ADAP_PERFLIB_PROCESSING:
case ADAP_PERFLIB_BOOBOO:
case ADAP_PERFLIB_LASTCHANCE:
{
// Perflib is in expected state, reset as long as nothing bad has happened
// =======================================================================
hr = reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, ADAP_PERFLIB_OK );
//ERRORTRACE( ( LOG_WMIADAP, "Performance library %S EndProcessing\n",(LPWSTR)m_wstrServiceName) );
}break;
case ADAP_PERFLIB_CORRUPT:
{
// Valid state. Leave as is.
// ==========================
ERRORTRACE( ( LOG_WMIADAP, "Performance library for %S: status is corrupt.\n",(LPWSTR)m_wstrServiceName) );
hr = WBEM_E_FAILED;
}break;
case ADAP_PERFLIB_OK:
{
if (CheckStatus(ADAP_PERFLIB_IS_INACTIVE))
{
hr = reg.SetDWORD( ADAP_PERFLIB_STATUS_KEY, ADAP_PERFLIB_OK );
}
else
{
// Invalid state
ERRORTRACE( ( LOG_WMIADAP, "Performance library %S: status is still ADAP_PERFLIB_OK.\n",(LPWSTR)m_wstrServiceName) );
hr = WBEM_E_FAILED;
}
}break;
default:
{
// Really bad state
// ================
ERRORTRACE( ( LOG_WMIADAP, "Performance library %S: status is in an unknown state.\n",(LPWSTR)m_wstrServiceName) );
hr = WBEM_E_FAILED;
}
}
}
else
{
// There is no status key. Something wacky has happened
// ====================================================
hr = WBEM_E_FAILED;
}
}
}
return hr;
}
HRESULT CAdapPerfLib::Load()
////////////////////////////////////////////////////////////////////////////////////////////
//
// Loads the library and resolves the addresses for the Open, Collect and Close entry
// points.
//
////////////////////////////////////////////////////////////////////////////////////////////
{
// Redundant, but it's a failsafe in case some perflib shuts this off on us
// during processing
// ========================================================================
SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX );
HRESULT hr = WBEM_S_NO_ERROR;
// Free the library if it has been previously loaded
// =================================================
if ( NULL != m_hLib )
{
try
{
FreeLibrary( m_hLib );
}
catch (...)
{
hr = WBEM_E_CRITICAL_ERROR;
}
}
// Load the predefined library
// ===========================
if ( SUCCEEDED( hr ) )
{
try
{
m_hLib = LoadLibraryExW( m_pwcsLibrary, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
}
catch(...)
{
hr = WBEM_E_CRITICAL_ERROR;
}
}
if ( SUCCEEDED( hr ) && ( NULL != m_hLib ) )
{
DEBUGTRACE( ( LOG_WMIADAP, "** %S Library Loaded.\n", m_wstrServiceName ) );
char szName[256];
DWORD Last1 = 0;
DWORD Last2 = 0;
DWORD Last3 = 0;
// Get the entry point addresses. No Wide version of GetProcAddress? sigh...
// ==========================================================================
if ( NULL != m_pwcsOpenProc )
{
if (0 != WideCharToMultiByte( CP_ACP, 0L, m_pwcsOpenProc, lstrlenW( m_pwcsOpenProc ) + 1,
szName, sizeof(szName), NULL, NULL ))
{
m_pfnOpenProc = (PM_OPEN_PROC*) GetProcAddress( m_hLib, szName );
}
Last1 = GetLastError();
}
if (0 != WideCharToMultiByte( CP_ACP, 0L, m_pwcsCollectProc, lstrlenW( m_pwcsCollectProc ) + 1,
szName, sizeof(szName), NULL, NULL ))
{
m_pfnCollectProc = (PM_COLLECT_PROC*) GetProcAddress( m_hLib, szName );
}
Last2 = GetLastError();
if ( NULL != m_pwcsCloseProc )
{
if (0 != WideCharToMultiByte( CP_ACP, 0L, m_pwcsCloseProc, lstrlenW( m_pwcsCloseProc ) + 1,
szName, sizeof(szName), NULL, NULL ))
{
m_pfnCloseProc = (PM_CLOSE_PROC*) GetProcAddress( m_hLib, szName );
}
Last3 = GetLastError();
}
if ( ( ( ( NULL != m_pwcsOpenProc ) && ( NULL != m_pfnOpenProc) ) || ( NULL == m_pwcsOpenProc ) ) &&
( NULL != m_pfnCollectProc ) &&
( ( ( NULL != m_pwcsCloseProc ) && ( NULL != m_pfnCloseProc ) ) || ( NULL == m_pwcsCloseProc ) ) )
{
hr = WBEM_S_NO_ERROR;
}
else
{
ERRORTRACE( ( LOG_WMIADAP, "A performance library function in %S failed to load.\n",(LPWSTR)m_wstrServiceName) );
WString wstr;
wstr += L"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\";
wstr += m_wstrServiceName;
if ( ( NULL != m_pwcsOpenProc ) && ( NULL == m_pfnOpenProc ) )
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, Last1 );
}
else if ( NULL == m_pfnCollectProc )
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, Last2 );
}
else if (( NULL != m_pwcsCloseProc ) && ( NULL == m_pfnCloseProc ))
{
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_PERFLIB_REG_VALUE_FAILURE,
(LPCWSTR)wstr, Last3 );
}
SetStatus( ADAP_PERFLIB_FAILED );
hr = WBEM_E_FAILED;
}
}
else
{
// If the library fails to load, then send an event, but do not charge a strike
// ============================================================================
ERRORTRACE( ( LOG_WMIADAP, "The performance library for %S failed to load.\n",(LPWSTR)m_wstrServiceName ) );
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_BAD_LIBRARY, m_pwcsLibrary, CHex( hr ) );
hr = WBEM_E_FAILED;
}
return hr;
}
HRESULT CAdapPerfLib::GetBlob( PERF_OBJECT_TYPE** ppPerfBlock, DWORD* pdwNumBytes, DWORD* pdwNumObjects, BOOL fCostly )
{
HRESULT hr = WBEM_S_NO_ERROR;
if ( m_fOpen )
{
hr = m_pPerfThread->GetPerfBlock( this, ppPerfBlock, pdwNumBytes, pdwNumObjects, fCostly );
}
if ( FAILED( hr ) )
{
if (!m_EventLogCalled){
//
//
//WBEM_MC_ADAP_BAD_PERFLIB_BAD_RETURN
//
m_EventLogCalled = TRUE;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_BAD_RETURN , (LPCWSTR)m_wstrServiceName, CHex( hr ) );
}
}
return hr;
}
HRESULT CAdapPerfLib::Close()
{
HRESULT hr = WBEM_S_NO_ERROR;
if ( m_fOpen )
{
m_pPerfThread->Close( this );
}
return hr;
}
HRESULT CAdapPerfLib::Cleanup()
{
HRESULT hr = WBEM_S_NO_ERROR;
// Terminate the worker thread
// ===========================
if ( NULL != m_pPerfThread )
m_pPerfThread->Shutdown();
// Adjust the status
// =================
EndProcessingStatus();
return hr;
}
HRESULT CAdapPerfLib::_Open( void )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Wraps a call to the perflib's open function. Fetches and passes an exports parameter
// to the open function if it exists.
//
// Note: We should use the named mutex to guard around the calls to Open/Collect/Close
//
////////////////////////////////////////////////////////////////////////////////////////////
{
HRESULT hr = WBEM_S_NO_ERROR;
// Check to ensure that the library has not yet been opened
// ========================================================
if ( ( !m_fOpen ) && SUCCEEDED ( hr ) )
{
CNTRegistry reg; // The registry wrapper class
// Build the service path
// ======================
WString wstr = L"SYSTEM\\CurrentControlSet\\Services\\";
wstr += m_wstrServiceName;
// Open the registry
// =================
if ( reg.Open( HKEY_LOCAL_MACHINE, wstr ) == CNTRegistry::no_error )
{
WCHAR* pwcsExports = NULL;
// Get Exports if they are available.
// ==============================================================
if ( reg.MoveToSubkey( L"Linkage" ) == CNTRegistry::no_error )
{
DWORD dwNumBytes = 0;
if (CNTRegistry::no_error != reg.GetMultiStr( L"Export", &pwcsExports, dwNumBytes ))
{
if ( ERROR_FILE_NOT_FOUND == reg.GetLastError())
{
// Linkage with no Export, that is OK
}
else
{
ERRORTRACE((LOG_WMIADAP,"Serivce %S has a non MSDN compliant or invalid Linkage Key\n",(WCHAR *)m_wstrServiceName));
if (CNTRegistry::no_error != reg.GetStr( L"Export", &pwcsExports))
{
pwcsExports = new WCHAR[2];
if (pwcsExports)
{
pwcsExports[0] = 0;
pwcsExports[1] = 0;
}
}
}
}
}
// Call the Open function for the perflib
// ======================================
switch ( WaitForSingleObject( m_hPLMutex, PL_TIMEOUT ) )
{
case WAIT_OBJECT_0:
{
try
{
if ( NULL != m_pfnOpenProc )
{
LONG lRes = m_pfnOpenProc( pwcsExports );
if (lRes == ERROR_SUCCESS )
{
hr = WBEM_S_NO_ERROR;
m_fOpen = TRUE;
}
else
{
SetStatus( ADAP_PERFLIB_IS_INACTIVE );
hr = WBEM_E_NOT_AVAILABLE;
}
DEBUGTRACE( ( LOG_WMIADAP, "Open called for %S returned %d\n", (LPCWSTR)m_wstrServiceName, lRes ) );
}
else
{
hr = WBEM_S_NO_ERROR;
m_fOpen = TRUE;
}
}
catch (...)
{
SetStatus( ADAP_PERFLIB_FAILED );
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Perflib Open function has thrown an exception in %S.\n",(LPWSTR)m_wstrServiceName) );
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_EXCEPTION, (LPCWSTR)m_wstrServiceName, CHex( hr ) );
}
} break;
case WAIT_TIMEOUT:
{
hr = WBEM_E_NOT_AVAILABLE;
ERRORTRACE( ( LOG_WMIADAP, "Perflib access mutex timed out in %S.\n",(LPWSTR)m_wstrServiceName) );
}break;
case WAIT_ABANDONED:
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Perflib access mutex was abandoned in %S.\n",(LPWSTR)m_wstrServiceName) );
}break;
default:
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Unknown error with perflib access mutex in %S.\n",(LPWSTR)m_wstrServiceName) );
}
} // switch
ReleaseMutex( m_hPLMutex );
if ( NULL != pwcsExports )
{
delete [] pwcsExports;
}
} // IF reg.Open
else
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Could not open the %S registry key.\n", wstr ) );
}
}
else
{
ERRORTRACE( ( LOG_WMIADAP, "Performance library %S has not been loaded.\n",(LPWSTR)m_wstrServiceName) );
}
return hr;
}
HRESULT CAdapPerfLib::_GetPerfBlock( PERF_OBJECT_TYPE** ppData, DWORD* pdwBytes, DWORD* pdwNumObjTypes, BOOL fCostly )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Wraps a call to the perflib's collect function. Will create progressively larger buffers
// in a private heap to attempt to fetch the performance data block.
//
// Parameters:
// ppData - a pointer to a buffer pointer for the data blob
// pdwBytes - a pointer to the byte-size of the data blob
// pdwNumObjTypes - a pointer to the number of objects in the data blob
// fCostly - a flag to determine what type of data to collect (costly or global)
//
// NOTE: This should always return perf object type data, since we cannot specify a
// foreign computer, which would cause the collect function to return a PERF_DATA_BLOCK
// structure.
//
////////////////////////////////////////////////////////////////////////////////////////////
{
HRESULT hr = WBEM_S_NO_ERROR;
CAdapSafeBuffer SafeBuffer( m_wstrServiceName ); // The safe buffer
DWORD dwNumBytes = 0; // Byte counter for the buffer size
DWORD dwError = ERROR_MORE_DATA; // The return value for the collect function
DWORD Increment = 0x10000;
// this is a workaround for perfproc.dll
if (0 == wbem_wcsicmp(m_wstrServiceName,L"perfproc"))
{
Increment = 0x100000;
}
// Verify provider status
// ======================
if ( m_fOpen )
{
// Sets the data-to-fetch parameter
// ================================
WCHAR* pwcsValue = ( fCostly ? L"Costly" : L"Global" );
// Start buffer at 64k (the guarded (safe) buffer is 2 * GUARD_BLOCK bytes smaller)
// ==================================================================================
dwNumBytes = Increment;
// Repeatedly attempt to collect the data until successful (buffer is sufficiently
// large), or the attempt fails for a reason other than buffer size
// ===============================================================================
while ( (ERROR_MORE_DATA == dwError ) && ( SUCCEEDED( hr ) ) )
{
// Allocate a raw buffer of size dwNumBytes
// ========================================
if (dwNumBytes > s_MaxSizeCollect)
{
ERRORTRACE((LOG_WMIADAP,"Library %S: Collect function requires more than 0x%08x bytes to complete",(WCHAR *)m_wstrServiceName,s_MaxSizeCollect));
m_CollectOK = FALSE;
hr = WBEM_E_QUOTA_VIOLATION;
break;
}
hr = SafeBuffer.SetSize( dwNumBytes );
if (FAILED(hr)) break;
// Collect the data from the perflib
// =================================
switch ( WaitForSingleObject( m_hPLMutex, PL_TIMEOUT ) )
{
case WAIT_OBJECT_0:
{
try
{
dwError = m_pfnCollectProc( pwcsValue,
SafeBuffer.GetSafeBufferPtrPtr(),
SafeBuffer.GetDataBlobSizePtr(),
SafeBuffer.GetNumObjTypesPtr() );
DEBUGTRACE( ( LOG_WMIADAP, "Collect called for %S returned %d\n", (LPCWSTR)m_wstrServiceName, dwError ) );
}
catch (...)
{
SetStatus( ADAP_PERFLIB_FAILED );
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Perflib Collection function has thrown an exception in %S.\n",(LPCWSTR)m_wstrServiceName) );
if (!m_EventLogCalled){
m_EventLogCalled = TRUE;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_EXCEPTION, (LPCWSTR)m_wstrServiceName, CHex( dwError ) );
}
}
}break;
case WAIT_TIMEOUT:
{
hr = WBEM_E_NOT_AVAILABLE;
ERRORTRACE( ( LOG_WMIADAP, "Perflib access mutex timed out in %S.\n",(LPCWSTR)m_wstrServiceName) );
}break;
case WAIT_ABANDONED:
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Perflib access mutex was abandoned in %S.\n",(LPCWSTR)m_wstrServiceName) );
}break;
default:
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Unknown error with perflib access mutex in %S.\n",(LPCWSTR)m_wstrServiceName) );
}
} // switch
ReleaseMutex( m_hPLMutex );
if ( SUCCEEDED( hr ) )
{
switch (dwError)
{
case ERROR_SUCCESS:
{
//
// the Validate function can call ReportEvent
// by itself, and we don't want to bother user too much
//
hr = SafeBuffer.Validate(&m_EventLogCalled);
if ( SUCCEEDED( hr ) )
{
hr = SafeBuffer.CopyData( (BYTE**) ppData, pdwBytes, pdwNumObjTypes );
}
else
{
// Catastrophic error has occured
// ==============================
SetStatus( ADAP_PERFLIB_FAILED );
if (!m_EventLogCalled)
{
m_EventLogCalled = TRUE;
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE,
WBEM_MC_ADAP_BAD_PERFLIB_INVALID_DATA,
(LPCWSTR)m_wstrServiceName,
CHex(hr));
}
}
} break;
case ERROR_MORE_DATA:
{
dwNumBytes += Increment;
} break;
default:
{
hr = WBEM_E_FAILED;
m_CollectOK = FALSE;
ERRORTRACE( ( LOG_WMIADAP, "Perflib Collection function has returned an unknown error(%d) in %S.\n", dwError,(LPCWSTR)m_wstrServiceName ) );
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_BAD_RETURN, (LPCWSTR)m_wstrServiceName, CHex( dwError ) );
}
} // switch
} // IF SUCCEEDED()
} // WHILE
// Clean up the buffer
// ===================
} // IF CheckStatus
else
{
ERRORTRACE( ( LOG_WMIADAP, "Performance library %S has not been loaded.\n",(LPCWSTR)m_wstrServiceName) );
}
return hr;
}
HRESULT CAdapPerfLib::_Close( void )
////////////////////////////////////////////////////////////////////////////////////////////
//
// Wraps a call to the perflib's close function.
//
////////////////////////////////////////////////////////////////////////////////////////////
{
HRESULT hr = WBEM_S_NO_ERROR;
// Verify that the perflib is actually open
// ========================================
if ( m_fOpen )
{
// Get the mutex
// =============
switch ( WaitForSingleObject( m_hPLMutex, PL_TIMEOUT ) )
{
case WAIT_OBJECT_0:
{
try
{
// And call the function
// =====================
if ( NULL != m_pfnCloseProc )
{
LONG lRet = m_pfnCloseProc();
DEBUGTRACE( ( LOG_WMIADAP, "Close called for %S returned %d\n", (LPCWSTR)m_wstrServiceName, lRet ) );
}
m_fOpen = FALSE;
}
catch (...)
{
// Ooops... something blew, return error code
// ==========================================
SetStatus( ADAP_PERFLIB_FAILED );
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Perflib Close function has thrown an exception in %S.\n",(LPCWSTR)m_wstrServiceName) );
CAdapUtility::NTLogEvent( EVENTLOG_WARNING_TYPE, WBEM_MC_ADAP_BAD_PERFLIB_EXCEPTION, (LPCWSTR)m_wstrServiceName, CHex( hr ) );
}
}break;
case WAIT_TIMEOUT:
{
hr = WBEM_E_NOT_AVAILABLE;
ERRORTRACE( ( LOG_WMIADAP, "Perflib access mutex timed out in %S.\n",(LPCWSTR)m_wstrServiceName) );
}break;
case WAIT_ABANDONED:
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Perflib access mutex was abandoned in %S.\n",(LPCWSTR)m_wstrServiceName) );
}break;
default:
{
hr = WBEM_E_FAILED;
ERRORTRACE( ( LOG_WMIADAP, "Unknown error with perflib access mutex in %S.\n",(LPCWSTR)m_wstrServiceName) );
} }
ReleaseMutex( m_hPLMutex );
}
return hr;
}
HRESULT CAdapPerfLib::SetStatus(DWORD dwStatus)
{
HRESULT hr = WBEM_NO_ERROR;
m_dwStatus |= dwStatus;
return hr;
}
HRESULT CAdapPerfLib::ClearStatus(DWORD dwStatus)
{
HRESULT hr = WBEM_NO_ERROR;
m_dwStatus &= ~dwStatus;
return hr;
}
BOOL CAdapPerfLib::CheckStatus(DWORD dwStatus)
{
return ((m_dwStatus & dwStatus) == dwStatus);
}