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.
 
 
 
 
 
 

2366 lines
102 KiB

/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
log_bin.c
Abstract:
<abstract>
--*/
#include <windows.h>
#include <strsafe.h>
#include <pdh.h>
#include "pdhidef.h"
#include "log_bin.h"
#include "log_wmi.h"
#include "strings.h"
#include "pdhmsg.h"
typedef struct _LOG_BIN_CAT_RECORD {
PDHI_BINARY_LOG_RECORD_HEADER RecHeader;
PDHI_LOG_CAT_ENTRY CatEntry;
DWORD dwEntryRecBuff[1];
} LOG_BIN_CAT_RECORD, * PLOG_BIN_CAT_RECORD;
typedef struct _LOG_BIN_CAT_ENTRY {
DWORD dwEntrySize;
DWORD dwOffsetToNextInstance;
DWORD dwEntryOffset;
LOG_BIN_CAT_RECORD bcRec;
} LOG_BIN_CAT_ENTRY, * PLOG_BIN_CAT_ENTRY;
#define RECORD_AT(p,lo) ((PPDHI_BINARY_LOG_RECORD_HEADER) ((LPBYTE) (p->lpMappedFileBase) + lo))
LPCSTR PdhiszRecordTerminator = "\r\n";
DWORD PdhidwRecordTerminatorLength = 2;
#define MAX_BINLOG_FILE_SIZE ((LONGLONG) 0x0000000040000000)
// dwFlags values
#define WBLR_WRITE_DATA_RECORD 0
#define WBLR_WRITE_LOG_HEADER 1
#define WBLR_WRITE_COUNTER_HEADER 2
DWORD
PdhiComputeDwordChecksum(
LPVOID pBuffer,
DWORD dwBufferSize // in bytes
)
{
LPDWORD pDwVal;
LPBYTE pByteVal;
DWORD dwDwCount;
DWORD dwByteCount;
DWORD dwThisByte;
DWORD dwCheckSum = 0;
DWORD dwByteVal = 0;
if (dwBufferSize > 0) {
dwDwCount = dwBufferSize / sizeof(DWORD);
dwByteCount = dwBufferSize % sizeof(DWORD);
pDwVal = (LPDWORD) pBuffer;
while (dwDwCount != 0) {
dwCheckSum += * pDwVal ++;
dwDwCount --;
}
pByteVal = (LPBYTE) pDwVal;
dwThisByte = 0;
while (dwThisByte < dwByteCount) {
dwByteVal |= ((* pByteVal & 0x000000FF) << (dwThisByte * 8));
dwThisByte ++;
}
dwCheckSum += dwByteVal;
}
return dwCheckSum;
}
PPDHI_BINARY_LOG_RECORD_HEADER
PdhiGetSubRecord(
PPDHI_BINARY_LOG_RECORD_HEADER pRecord,
DWORD dwRecordId
)
// locates the specified sub record in the pRecord Buffer
// the return pointer is between pRecord and pRecord + pRecord->dwLength;
// NULL is returned if the specified record could not be found
// ID values start at 1 for the first sub record in buffer
{
PPDHI_BINARY_LOG_RECORD_HEADER pThisRecord;
DWORD dwRecordType;
DWORD dwRecordLength;
DWORD dwBytesProcessed;
DWORD dwThisSubRecordId;
dwRecordType = ((PPDHI_BINARY_LOG_RECORD_HEADER) pRecord)->dwType;
dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER) pRecord)->dwLength;
pThisRecord = (PPDHI_BINARY_LOG_RECORD_HEADER)((LPBYTE) pRecord + sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
dwBytesProcessed = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
if (dwBytesProcessed < dwRecordLength) {
dwThisSubRecordId = 1;
while (dwThisSubRecordId < dwRecordId) {
if ((WORD) (pThisRecord->dwType & 0x0000FFFF) == BINLOG_START_WORD) {
// go to next sub record
dwBytesProcessed += pThisRecord->dwLength;
pThisRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) (((LPBYTE) pThisRecord) + pThisRecord->dwLength);
if (dwBytesProcessed >= dwRecordLength) {
// out of sub-records so exit
break;
}
else {
dwThisSubRecordId ++;
}
}
else {
// we're lost so bail
break;
}
}
}
else {
dwThisSubRecordId = 0;
}
if (dwThisSubRecordId == dwRecordId) {
// then validate this is really a record and it's within the
// master record.
if ((WORD)(pThisRecord->dwType & 0x0000FFFF) != BINLOG_START_WORD) {
// bogus record so return a NULL pointer
pThisRecord = NULL;
}
else {
// this is OK so return pointer
}
}
else {
// record not found so return a NULL pointer
pThisRecord = NULL;
}
return pThisRecord;
}
STATIC_PDH_FUNCTION
PdhiReadBinaryMappedRecord(
PPDHI_LOG pLog,
DWORD dwRecordId,
LPVOID pRecord,
DWORD dwMaxSize
)
{
PDH_STATUS pdhStatus= ERROR_SUCCESS;
LPVOID pEndOfFile;
LPVOID pLastRecord;
DWORD dwLastRecordIndex;
PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
PPDHI_BINARY_LOG_RECORD_HEADER pRecHeader;
LPVOID pLastRecordInLog;
DWORD dwBytesToRead;
DWORD dwBytesRead;
BOOL bStatus;
if (dwRecordId == 0) return PDH_ENTRY_NOT_IN_LOG_FILE; // record numbers start at 1
// see if the file has been mapped
if (pLog->hMappedLogFile == NULL) {
// then it's not mapped so read it using the file system
if ((pLog->dwLastRecordRead == 0) || (dwRecordId < pLog->dwLastRecordRead)) {
// then we know no record has been read yet so assign
// pointer just to be sure
SetFilePointer(pLog->hLogFileHandle, 0, NULL, FILE_BEGIN);
// allocate a new buffer
if (pLog->dwMaxRecordSize < 0x10000) pLog->dwMaxRecordSize = 0x10000;
dwBytesToRead = pLog->dwMaxRecordSize;
// allocate a fresh buffer
if (pLog->pLastRecordRead != NULL) {
G_FREE(pLog->pLastRecordRead);
pLog->pLastRecordRead = NULL;
}
pLog->pLastRecordRead = G_ALLOC(pLog->dwMaxRecordSize);
if (pLog->pLastRecordRead == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
else {
// initialize the first record header
dwBytesToRead = pLog->dwRecord1Size;
dwBytesRead = 0;
bStatus = ReadFile(pLog->hLogFileHandle, pLog->pLastRecordRead, dwBytesToRead, & dwBytesRead, NULL);
if (bStatus && (dwBytesRead == pLog->dwRecord1Size)) {
// make sure the buffer is big enough
pLog->dwLastRecordRead = 1;
pdhStatus = ERROR_SUCCESS;
}
else {
// unable to read the first record
pdhStatus = PDH_UNABLE_READ_LOG_HEADER;
}
}
}
else {
// assume everything is already set up and OK
}
// "seek" to the desired record file pointer should either be pointed
// to the start of a new record or at the end of the file
while ((dwRecordId != pLog->dwLastRecordRead) && (pdhStatus == ERROR_SUCCESS)) {
// clear the buffer
ZeroMemory(pLog->pLastRecordRead, pLog->dwMaxRecordSize);
// read record header field
dwBytesToRead = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
dwBytesRead = 0;
bStatus = ReadFile(pLog->hLogFileHandle, pLog->pLastRecordRead, dwBytesToRead, & dwBytesRead, NULL);
if (bStatus && (dwBytesRead == dwBytesToRead)) {
// make sure the rest of the record will fit in the buffer
pRecHeader = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
// make sure this is a valid record
if (*(WORD *)&(pRecHeader->dwType) == BINLOG_START_WORD) {
if (pRecHeader->dwLength > pLog->dwMaxRecordSize) {
LPVOID pTmp = pLog->pLastRecordRead;
// realloc the buffer
pLog->dwMaxRecordSize = pRecHeader->dwLength;
pLog->pLastRecordRead = G_REALLOC(pTmp, pLog->dwMaxRecordSize);
if (pLog->pLastRecordRead == NULL) {
G_FREE(pTmp);
}
}
if (pLog->pLastRecordRead != NULL) {
dwBytesToRead = pRecHeader->dwLength - sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
dwBytesRead = 0;
pLastRecord = (LPVOID)((LPBYTE)(pLog->pLastRecordRead) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
bStatus = ReadFile(pLog->hLogFileHandle, pLastRecord, dwBytesToRead, & dwBytesRead, NULL);
if (bStatus) {
pLog->dwLastRecordRead ++;
}
else {
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
else {
// file is corrupt
pdhStatus = PDH_INVALID_DATA;
}
}
else {
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
// here the result will be success when the specified file has been read or
// a PDH error if not
}
else {
// the file has been memory mapped so use that interface
if (pLog->dwLastRecordRead == 0) {
// then we know no record has been read yet so assign
// pointer just to be sure
pLog->pLastRecordRead = pLog->lpMappedFileBase;
pLog->dwLastRecordRead = 1;
}
pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD) RECORD_AT(pLog, pLog->dwRecord1Size);
// "seek" to the desired record
if (dwRecordId < pLog->dwLastRecordRead) {
if (dwRecordId >= BINLOG_FIRST_DATA_RECORD) {
// rewind the file
pLog->pLastRecordRead = (LPVOID)((LPBYTE) pLog->lpMappedFileBase + pHeader->Info.FirstRecordOffset);
pLog->dwLastRecordRead = BINLOG_FIRST_DATA_RECORD;
}
else {
// rewind the file
pLog->pLastRecordRead = pLog->lpMappedFileBase;
pLog->dwLastRecordRead = 1;
}
}
// then use the point specified as the end of the file
// if the log file contians a specified Wrap offset, then use that
// if not, then if the file length is specified, use that
// if not, the use the reported file length
pEndOfFile = (LPVOID) ((LPBYTE) pLog->lpMappedFileBase);
if (pHeader->Info.WrapOffset > 0) {
pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pHeader->Info.WrapOffset);
}
else if (pHeader->Info.FileLength > 0) {
pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pHeader->Info.FileLength);
}
else {
pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pLog->llFileSize);
}
pLastRecord = pLog->pLastRecordRead;
dwLastRecordIndex = pLog->dwLastRecordRead;
__try {
// walk around the file until an access violation occurs or
// the record is found. If an access violation occurs,
// we can assume we went off the end of the file and out
// of the mapped section
// make sure the record has a valid header
if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD ?
(* (WORD *) pLog->pLastRecordRead == BINLOG_START_WORD) : TRUE) {
// then it looks OK so continue
while (pLog->dwLastRecordRead != dwRecordId) {
// go to next record
pLastRecord = pLog->pLastRecordRead;
if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD) {
if (pLog->dwLastRecordRead == BINLOG_HEADER_RECORD) {
// if the last record was the header, then the next record
// is the "first" data , not the first after the header
pLog->pLastRecordRead = (LPVOID)((LPBYTE) pLog->lpMappedFileBase +
pHeader->Info.FirstRecordOffset);
}
else {
// if the current record is any record other than the header
// ...then
if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength > 0) {
// go to the next record in the file
pLog->pLastRecordRead = (LPVOID) ((LPBYTE) pLog->pLastRecordRead +
((PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead)->dwLength);
// test for exceptions here
if (pLog->pLastRecordRead >= pEndOfFile) {
// find out if this is a circular log or not
if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
// test to see if the file has wrapped
if (pHeader->Info.WrapOffset != 0) {
// then wrap to the beginning of the file
pLog->pLastRecordRead = (LPVOID)((LPBYTE)pLog->lpMappedFileBase +
pHeader->Info.FirstDataRecordOffset);
}
else {
// the file is still linear so this is the end
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
// this is the end of the file
// so reset to the previous pointer
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
// not at the physical end of the file, but if this is a circular
// log, it could be the logical end of the records so test that
// here
if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
pLastRecordInLog = (LPVOID)((LPBYTE)pLog->lpMappedFileBase +
pHeader->Info.LastRecordOffset);
pLastRecordInLog = (LPVOID)((LPBYTE)pLastRecordInLog +
((PPDHI_BINARY_LOG_RECORD_HEADER)pLastRecordInLog)->dwLength);
if (pLog->pLastRecordRead == pLastRecordInLog) {
// then this is the last record in the log
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
// nothing to do since this is a normal case
}
} // end if / if not end of log file
}
else {
// length is 0 so we've probably run off the end of the log somehow
pdhStatus = PDH_END_OF_LOG_FILE;
}
} // end if /if not header record
}
else {
pLog->pLastRecordRead = (LPBYTE) pLog->pLastRecordRead + pLog->dwRecord1Size;
}
if (pdhStatus == ERROR_SUCCESS) {
// update pointers & indices
pLog->dwLastRecordRead ++;
dwLastRecordIndex = pLog->dwLastRecordRead;
}
else {
pLog->pLastRecordRead = pLastRecord;
break; // out of the while loop
}
}
}
else {
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pLog->pLastRecordRead = pLastRecord;
pLog->dwLastRecordRead = dwLastRecordIndex;
}
}
if (pdhStatus == ERROR_SUCCESS) {
// see if we ended up at the right place
if (pLog->dwLastRecordRead == dwRecordId) {
if (pRecord != NULL) {
// then try to copy it
// if the record ID is 1 then it's the header record so this is
// a special case record that is actually a CR/LF terminated record
if (dwRecordId != BINLOG_TYPE_ID_RECORD) {
if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength <= dwMaxSize) {
// then it'll fit so copy it
memcpy(pRecord, pLog->pLastRecordRead,
((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength);
pdhStatus = ERROR_SUCCESS;
}
else {
// then copy as much as will fit
memcpy(pRecord, pLog->pLastRecordRead, dwMaxSize);
pdhStatus = PDH_MORE_DATA;
}
}
else {
// copy the first record and zero terminate it
if (pLog->dwRecord1Size <= dwMaxSize) {
memcpy(pRecord, pLog->pLastRecordRead, pLog->dwRecord1Size);
// null terminate after string
((LPBYTE) pRecord)[pLog->dwRecord1Size - PdhidwRecordTerminatorLength + 1] = 0;
}
else {
memcpy(pRecord, pLog->pLastRecordRead, dwMaxSize);
pdhStatus = PDH_MORE_DATA;
}
}
}
else {
// just return success
// no buffer was passed, but the record pointer has been
// positioned
pdhStatus = ERROR_SUCCESS;
}
}
else {
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
return pdhStatus;
}
STATIC_PDH_FUNCTION
PdhiReadOneBinLogRecord(
PPDHI_LOG pLog,
DWORD dwRecordId,
LPVOID pRecord,
DWORD dwMaxSize
)
{
PDH_STATUS pdhStatus= ERROR_SUCCESS;
LPVOID pEndOfFile;
LPVOID pLastRecord;
DWORD dwLastRecordIndex = 0;
PPDHI_BINARY_LOG_HEADER_RECORD pHeader = NULL;
BOOL bCircular = FALSE;
DWORD dwRecordSize;
DWORD dwRecordReadSize;
LONGLONG llLastFileOffset;
LPVOID pTmpBuffer;
if ((LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) && (dwRecordId == BINLOG_HEADER_RECORD)) {
// special handling for WMI event trace logfile format
//
return PdhiReadWmiHeaderRecord(pLog, pRecord, dwMaxSize);
}
if (pLog->iRunidSQL != 0) {
return PdhiReadBinaryMappedRecord(pLog, dwRecordId, pRecord, dwMaxSize);
}
if (pLog->dwLastRecordRead == 0) {
// then we know no record has been read yet so assign
// pointer just to be sure
pLog->pLastRecordRead = NULL;
pLog->liLastRecordOffset.QuadPart = 0;
SetFilePointer(pLog->hLogFileHandle,
pLog->liLastRecordOffset.LowPart,
& pLog->liLastRecordOffset.HighPart, FILE_BEGIN);
if (pLog->liLastRecordOffset.LowPart == INVALID_SET_FILE_POINTER) {
pdhStatus = GetLastError();
}
}
if (pdhStatus == ERROR_SUCCESS) {
// map header to local structure (the header data should be mapped into memory
pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)RECORD_AT(pLog, pLog->dwRecord1Size);
if (pHeader->Info.WrapOffset > 0) {
bCircular = TRUE;
}
// "seek" to the desired record
if ((dwRecordId < pLog->dwLastRecordRead) || (pLog->dwLastRecordRead == 0)) {
// rewind if not initialized or the desired record is before this one
if (dwRecordId >= BINLOG_FIRST_DATA_RECORD) {
// rewind the file to the first regular record
pLog->liLastRecordOffset.QuadPart = pHeader->Info.FirstRecordOffset;
pLog->dwLastRecordRead = BINLOG_FIRST_DATA_RECORD;
}
else {
// rewind the file to the very start of the file
pLog->liLastRecordOffset.QuadPart = 0;
pLog->dwLastRecordRead = 1;
}
pLog->liLastRecordOffset.LowPart = SetFilePointer(pLog->hLogFileHandle,
pLog->liLastRecordOffset.LowPart,
& pLog->liLastRecordOffset.HighPart,
FILE_BEGIN);
if (pLog->liLastRecordOffset.LowPart == INVALID_SET_FILE_POINTER) {
pdhStatus = GetLastError();
}
else {
if (pLog->pLastRecordRead != NULL) {
G_FREE(pLog->pLastRecordRead);
pLog->pLastRecordRead = NULL;
}
if (pLog->dwLastRecordRead == 1) {
// the this is the text ID field
dwRecordSize = pLog->dwRecord1Size;
}
else {
dwRecordSize = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
}
pLog->pLastRecordRead = G_ALLOC(dwRecordSize);
if (pLog->pLastRecordRead != NULL) {
// read in the header (or entire record if the 1st record
// otherwise it's a data record
if (ReadFile(pLog->hLogFileHandle, pLog->pLastRecordRead, dwRecordSize, & dwRecordReadSize, NULL)) {
// then we have the record header or type record so
// complete the operation and read the rest of the record
if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD) {
// the Type ID record is of fixed length and has not header record
dwRecordSize = ((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength;
pTmpBuffer = pLog->pLastRecordRead;
pLog->pLastRecordRead = G_REALLOC(pTmpBuffer, dwRecordSize);
if (pLog->pLastRecordRead != NULL) {
// read in the rest of the record and append it to the header data already read in
// otherwise it's a data record
pLastRecord = (LPVOID) & ((LPBYTE) pLog->pLastRecordRead)[sizeof(PDHI_BINARY_LOG_RECORD_HEADER)];
if (ReadFile(pLog->hLogFileHandle,
pLastRecord,
dwRecordSize - sizeof(PDHI_BINARY_LOG_RECORD_HEADER),
& dwRecordReadSize,
NULL)) {
// then we have the record header or type record
pdhStatus = ERROR_SUCCESS;
}
else {
pdhStatus = GetLastError();
}
}
else {
G_FREE(pTmpBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
pdhStatus = ERROR_SUCCESS;
}
else {
pdhStatus = GetLastError();
}
}
else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
}
// then use the point specified as the end of the file
// if the log file contians a specified Wrap offset, then use that
// if not, then if the file length is specified, use that
// if not, the use the reported file length
pEndOfFile = (LPVOID)((LPBYTE) pLog->lpMappedFileBase);
if (pHeader->Info.WrapOffset > 0) {
pEndOfFile = (LPVOID)((LPBYTE) pEndOfFile + pHeader->Info.WrapOffset);
}
else if (pHeader->Info.FileLength > 0) {
pEndOfFile = (LPVOID)((LPBYTE) pEndOfFile + pHeader->Info.FileLength);
}
else {
pEndOfFile = (LPVOID)((LPBYTE) pEndOfFile + pLog->llFileSize);
}
dwLastRecordIndex = pLog->dwLastRecordRead;
}
if (pdhStatus == ERROR_SUCCESS) {
__try {
// walk around the file until an access violation occurs or
// the record is found. If an access violation occurs,
// we can assume we went off the end of the file and out
// of the mapped section
// make sure the record has a valid header
if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD ?
(* (WORD *) pLog->pLastRecordRead == BINLOG_START_WORD) : TRUE) {
// then it looks OK so continue
while (pLog->dwLastRecordRead != dwRecordId) {
// go to next record
if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD) {
llLastFileOffset = pLog->liLastRecordOffset.QuadPart;
if (pLog->dwLastRecordRead == BINLOG_HEADER_RECORD) {
// if the last record was the header, then the next record
// is the "first" data , not the first after the header
// the function returns the new offset
pLog->liLastRecordOffset.QuadPart = pHeader->Info.FirstRecordOffset;
pLog->liLastRecordOffset.LowPart = SetFilePointer(pLog->hLogFileHandle,
pLog->liLastRecordOffset.LowPart,
& pLog->liLastRecordOffset.HighPart,
FILE_BEGIN);
}
else {
// if the current record is any record other than the header
// ...then
if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength > 0) {
// go to the next record in the file
pLog->liLastRecordOffset.QuadPart += ((PPDHI_BINARY_LOG_RECORD_HEADER)
pLog->pLastRecordRead)->dwLength;
// test for exceptions here
if (pLog->liLastRecordOffset.QuadPart >= pLog->llFileSize) {
// find out if this is a circular log or not
if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
// test to see if the file has wrapped
if (pHeader->Info.WrapOffset != 0) {
// then wrap to the beginning of the file
pLog->liLastRecordOffset.QuadPart = pHeader->Info.FirstDataRecordOffset;
}
else {
// the file is still linear so this is the end
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
// this is the end of the file
// so reset to the previous pointer
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
// not at the physical end of the file, but if this is a circular
// log, it could be the logical end of the records so test that
// here
if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
if (llLastFileOffset == pHeader->Info.LastRecordOffset) {
// then this is the last record in the log
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
else {
// nothing to do since this is a normal case
}
} // end if / if not end of log file
}
else {
// length is 0 so we've probably run off the end of the log somehow
pdhStatus = PDH_END_OF_LOG_FILE;
}
// now go to that record
if (pdhStatus == ERROR_SUCCESS) {
pLog->liLastRecordOffset.LowPart = SetFilePointer(pLog->hLogFileHandle,
pLog->liLastRecordOffset.LowPart,
& pLog->liLastRecordOffset.HighPart,
FILE_BEGIN);
}
} // end if /if not header record
}
else {
pLog->liLastRecordOffset.QuadPart = pLog->dwRecord1Size;
pLog->liLastRecordOffset.LowPart = SetFilePointer(pLog->hLogFileHandle,
pLog->liLastRecordOffset.LowPart,
& pLog->liLastRecordOffset.HighPart,
FILE_BEGIN);
}
if (pdhStatus == ERROR_SUCCESS) {
// the last record buffer should not be NULL and it should
// be large enough to hold the header
if (pLog->pLastRecordRead != NULL) {
// read in the header (or entire record if the 1st record
// otherwise it's a data record
dwRecordSize = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
if (ReadFile(pLog->hLogFileHandle,
pLog->pLastRecordRead,
dwRecordSize,
& dwRecordReadSize,
NULL)) {
// then we have the record header or type record
// update pointers & indices
pLog->dwLastRecordRead ++;
pdhStatus = ERROR_SUCCESS;
}
else {
pdhStatus = GetLastError();
}
}
else {
DebugBreak();
}
}
else {
break; // out of the while loop
}
}
}
else {
pdhStatus = PDH_END_OF_LOG_FILE;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pLog->dwLastRecordRead = dwLastRecordIndex;
}
}
// see if we ended up at the right place
if ((pdhStatus == ERROR_SUCCESS) && (pLog->dwLastRecordRead == dwRecordId)) {
if (dwLastRecordIndex != pLog->dwLastRecordRead) {
// then we've move the file pointer so read the entire data record
dwRecordSize = ((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength;
pTmpBuffer = pLog->pLastRecordRead;
pLog->pLastRecordRead = G_REALLOC(pTmpBuffer, dwRecordSize);
if (pLog->pLastRecordRead != NULL) {
// read in the rest of the record and append it to the header data already read in
// otherwise it's a data record
pLastRecord = (LPVOID)&((LPBYTE)pLog->pLastRecordRead)[sizeof(PDHI_BINARY_LOG_RECORD_HEADER)];
if (ReadFile(pLog->hLogFileHandle,
pLastRecord,
dwRecordSize - sizeof(PDHI_BINARY_LOG_RECORD_HEADER),
& dwRecordReadSize,
NULL)) {
// then we have the record header or type record
pdhStatus = ERROR_SUCCESS;
}
else {
pdhStatus = GetLastError();
}
}
else {
G_FREE(pTmpBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
}
if ((pdhStatus == ERROR_SUCCESS) && (pRecord != NULL)) {
// then try to copy it
// if the record ID is 1 then it's the header record so this is
// a special case record that is actually a CR/LF terminated record
if (dwRecordId != BINLOG_TYPE_ID_RECORD) {
if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength <= dwMaxSize) {
// then it'll fit so copy it
RtlCopyMemory(pRecord, pLog->pLastRecordRead,
((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength);
pdhStatus = ERROR_SUCCESS;
}
else {
// then copy as much as will fit
RtlCopyMemory(pRecord, pLog->pLastRecordRead, dwMaxSize);
pdhStatus = PDH_MORE_DATA;
}
}
else {
// copy the first record and zero terminate it
if (pLog->dwRecord1Size <= dwMaxSize) {
RtlCopyMemory(pRecord, pLog->pLastRecordRead, pLog->dwRecord1Size);
// null terminate after string
((LPBYTE) pRecord)[pLog->dwRecord1Size - PdhidwRecordTerminatorLength + 1] = 0;
}
else {
RtlCopyMemory(pRecord, pLog->pLastRecordRead, dwMaxSize);
pdhStatus = PDH_MORE_DATA;
}
}
}
else {
// just return current status value
// no buffer was passed, but the record pointer has been
// positioned
}
}
else {
// if successful so far, then return EOF
if (pdhStatus == ERROR_SUCCESS) pdhStatus = PDH_END_OF_LOG_FILE;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetBinaryLogCounterInfo(
PPDHI_LOG pLog,
PPDHI_COUNTER pCounter
)
{
PDH_STATUS pdhStatus;
DWORD dwIndex;
DWORD dwPrevious = pCounter->dwIndex;
PPDHI_COUNTER_PATH pTempPath = NULL;
PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
PPDHI_LOG_COUNTER_PATH pPath;
DWORD dwBufferSize;
DWORD dwRecordLength;
DWORD dwBytesProcessed;
DWORD dwTmpIndex;
LPBYTE pFirstChar;
LPWSTR szThisMachineName;
LPWSTR szThisObjectName;
LPWSTR szThisCounterName;
LPWSTR szThisInstanceName;
LPWSTR szThisParentName;
BOOL bCheckThisObject = FALSE;
// crack the path in to components
pTempPath = G_ALLOC(LARGE_BUFFER_SIZE);
if (pTempPath == NULL) {
return PDH_MEMORY_ALLOCATION_FAILURE;
}
dwBufferSize = (DWORD) G_SIZE(pTempPath);
if (ParseFullPathNameW(pCounter->szFullName, &dwBufferSize, pTempPath, FALSE)) {
// read the header record to find the matching entry
pdhStatus = PdhiReadOneBinLogRecord(pLog, BINLOG_HEADER_RECORD, NULL, 0);
if (pdhStatus == ERROR_SUCCESS) {
pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER) pThisMasterRecord)->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pThisMasterRecord + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
dwIndex = 0;
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
dwTmpIndex = 0;
while (dwBytesProcessed < dwRecordLength) {
// go through catalog to find a match
dwIndex ++;
pFirstChar = (LPBYTE) & pPath->Buffer[0];
if (dwPrevious != 0 && dwPrevious >= dwIndex) {
bCheckThisObject = FALSE;
}
else if (pPath->lMachineNameOffset >= 0L) {
// then there's a machine name in this record so get
// it's size
szThisMachineName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lMachineNameOffset);
// if this is for the desired machine, then select the object
if (lstrcmpiW(szThisMachineName, pTempPath->szMachineName) == 0) {
szThisObjectName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
if (lstrcmpiW(szThisObjectName, pTempPath->szObjectName) == 0) {
// then this is the object to look up
bCheckThisObject = TRUE;
}
else {
// not this object
szThisObjectName = NULL;
}
}
else {
// this machine isn't selected
}
}
else {
// there's no machine specified so for this counter so list it by default
if (pPath->lObjectNameOffset >= 0) {
szThisObjectName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
if (lstrcmpiW(szThisObjectName,pTempPath->szObjectName) == 0) {
// then this is the object to look up
bCheckThisObject = TRUE;
}
else {
// not this object
szThisObjectName = NULL;
}
}
else {
// no object to copy
szThisObjectName = NULL;
}
}
if (bCheckThisObject) {
szThisCounterName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lCounterOffset);
if (* szThisCounterName == SPLAT_L) {
pdhStatus = PdhiGetWmiLogCounterInfo(pLog, pCounter);
pCounter->dwIndex = dwIndex;
break;
}
else if (lstrcmpiW(szThisCounterName, pTempPath->szCounterName) == 0) {
// check instance name
// get the instance name from this counter and add it to the list
if (pPath->lInstanceOffset >= 0) {
szThisInstanceName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lInstanceOffset);
if (*szThisInstanceName != SPLAT_L) {
if (pPath->lParentOffset >= 0) {
szThisParentName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lParentOffset);
if (lstrcmpiW(szThisParentName, pTempPath->szParentName) != 0) {
// wrong parent
bCheckThisObject = FALSE;
}
}
if (lstrcmpiW(szThisInstanceName, pTempPath->szInstanceName) != 0) {
// wrong instance
bCheckThisObject = FALSE;
}
if (pTempPath->dwIndex > 0) {
if (pPath->dwIndex == pTempPath->dwIndex) {
bCheckThisObject = TRUE;
}
else if (pPath->dwIndex == 0) {
if (dwTmpIndex == pTempPath->dwIndex) {
bCheckThisObject = TRUE;
}
else {
dwTmpIndex ++;
bCheckThisObject = FALSE;
}
}
else if (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_RETIRED_BIN) {
if (dwTmpIndex == pTempPath->dwIndex) {
bCheckThisObject = TRUE;
}
else {
dwTmpIndex ++;
bCheckThisObject = FALSE;
}
}
else {
// wrong index
bCheckThisObject = FALSE;
}
}
else if (pPath->dwIndex != 0 && LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
bCheckThisObject = FALSE;
}
}
else {
// this is a wild card spec
// so assume it's valid since that's
// faster than reading the file each time.
// if the instance DOESN't exist in this
// file then the appropriate status will
// be returned in each query.
}
}
else {
// there is no instance name to compare
// so assume it's OK
}
if (bCheckThisObject) {
// fill in the data and return
// this data is NOT used by the log file reader
pCounter->plCounterInfo.dwObjectId = 0;
pCounter->plCounterInfo.lInstanceId = 0;
if (pPath->lInstanceOffset >= 0) {
pCounter->plCounterInfo.szInstanceName = pCounter->pCounterPath->szInstanceName;
pCounter->plCounterInfo.dwParentObjectId = 0;
pCounter->plCounterInfo.szParentInstanceName = pCounter->pCounterPath->szParentName;
}
else {
pCounter->plCounterInfo.szInstanceName = NULL;
pCounter->plCounterInfo.dwParentObjectId = 0;
pCounter->plCounterInfo.szParentInstanceName = NULL;
}
//define as multi instance if necessary
// if the user is passing in a "*" character
if (pCounter->plCounterInfo.szInstanceName != NULL) {
if (*pCounter->plCounterInfo.szInstanceName == SPLAT_L) {
pCounter->dwFlags |= PDHIC_MULTI_INSTANCE;
}
}
// this data is used by the log file readers
pCounter->plCounterInfo.dwCounterId = dwIndex; // entry in log
pCounter->plCounterInfo.dwCounterType = pPath->dwCounterType;
pCounter->plCounterInfo.dwCounterSize = pPath->dwCounterType & PERF_SIZE_LARGE ?
sizeof (LONGLONG) : sizeof(DWORD);
pCounter->plCounterInfo.lDefaultScale = pPath->lDefaultScale;
pCounter->TimeBase = pPath->llTimeBase;
pCounter->dwIndex = dwIndex;
pdhStatus = ERROR_SUCCESS;
break;
}
}
}
else {
// we aren't interested in this so just ignore it
}
// get next path entry from log file record
dwBytesProcessed += pPath->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pPath + pPath->dwLength);
} // end while searching the catalog entries
}
else {
// unable to find desired record so return status
}
}
else {
// unable to read the path
pdhStatus = PDH_INVALID_PATH;
}
G_FREE(pTempPath);
return pdhStatus;
}
PDH_FUNCTION
PdhiOpenInputBinaryLog(
PPDHI_LOG pLog
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
pLog->StreamFile = (FILE *) ((DWORD_PTR) (-1));
// map file header as a memory array for reading
if ((pLog->hMappedLogFile != NULL) && (pLog->lpMappedFileBase != NULL)) {
// save size of binary log record header
pLog->dwRecord1Size = dwFileHeaderLength + // ID characters
2 + // quotations
PdhidwRecordTerminatorLength; // CR/LF terminator
pLog->dwRecord1Size = QWORD_MULTIPLE(pLog->dwRecord1Size);
// read the header and get the option flags
pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD) ((LPBYTE) (pLog->lpMappedFileBase) + pLog->dwRecord1Size);
pLog->dwLogFormat |= pHeader->Info.dwFlags;
}
else {
// return PDH Error
pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiCloseBinaryLog(
PPDHI_LOG pLog,
DWORD dwFlags
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
BOOL bStatus;
LONGLONG llEndOfFile = 0;
PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
BOOL bNeedToCloseHandles = FALSE;
UNREFERENCED_PARAMETER (dwFlags);
// if open for reading, then the file is also mapped as a memory section
if (pLog->lpMappedFileBase != NULL) {
// if open for output, get "logical" end of file so it
// can be truncated to to the amount of file used in order to
// save disk space
if ((pLog->dwLogFormat & PDH_LOG_ACCESS_MASK) == PDH_LOG_WRITE_ACCESS) {
pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD) ((LPBYTE) (pLog->lpMappedFileBase) + pLog->dwRecord1Size);
llEndOfFile = pHeader->Info.WrapOffset;
if (llEndOfFile < pHeader->Info.NextRecordOffset) {
llEndOfFile = pHeader->Info.NextRecordOffset;
}
}
pdhStatus = UnmapReadonlyMappedFile(pLog->lpMappedFileBase, &bNeedToCloseHandles);
pLog->lpMappedFileBase = NULL;
// for mapped files, this is a pointer into the file/memory section
// so once the view is unmapped, it's no longer valid
pLog->pLastRecordRead = NULL;
}
if (bNeedToCloseHandles) {
if (pLog->hMappedLogFile != NULL) {
bStatus = CloseHandle(pLog->hMappedLogFile);
pLog->hMappedLogFile = NULL;
}
if (pdhStatus == ERROR_SUCCESS) {
if (! (FlushFileBuffers(pLog->hLogFileHandle))) {
pdhStatus = GetLastError();
}
}
else {
// close them anyway, but save the status from the prev. call
FlushFileBuffers(pLog->hLogFileHandle);
}
// see if we can truncate the file
if (llEndOfFile > 0) {
DWORD dwLoPos, dwHighPos;
// truncate at the last byte used
dwLoPos = LODWORD(llEndOfFile);
dwHighPos = HIDWORD(llEndOfFile);
dwLoPos = SetFilePointer (pLog->hLogFileHandle, dwLoPos, (LONG *) & dwHighPos, FILE_BEGIN);
if (dwLoPos == 0xFFFFFFFF) {
pdhStatus = GetLastError ();
}
if (pdhStatus == ERROR_SUCCESS) {
if (! SetEndOfFile(pLog->hLogFileHandle)) {
pdhStatus = GetLastError();
}
}
} // else don't know where the end is so continue
if (pLog->hLogFileHandle != INVALID_HANDLE_VALUE) {
bStatus = CloseHandle(pLog->hLogFileHandle);
pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
}
}
else {
// the handles have already been closed so just
// clear their values
pLog->lpMappedFileBase = NULL;
pLog->hMappedLogFile = NULL;
pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumMachinesFromBinaryLog(
PPDHI_LOG pLog,
LPVOID pBuffer,
LPDWORD pcchBufferSize,
BOOL bUnicodeDest
)
{
LPVOID pTempBuffer = NULL;
LPVOID pOldBuffer;
DWORD dwTempBufferSize;
LPVOID LocalBuffer = NULL;
DWORD dwLocalBufferSize;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
// read the header record and enum the machine name from the entries
if (pLog->dwMaxRecordSize == 0) {
// no size is defined so start with 64K
pLog->dwMaxRecordSize = 0x010000;
}
dwTempBufferSize = pLog->dwMaxRecordSize;
pTempBuffer = G_ALLOC(dwTempBufferSize);
if (pTempBuffer == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
dwLocalBufferSize = MEDIUM_BUFFER_SIZE;
LocalBuffer = G_ALLOC(dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
if (LocalBuffer == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
// read in the catalog record
while ((pdhStatus = PdhiReadOneBinLogRecord(
pLog, BINLOG_HEADER_RECORD, pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
if (pdhStatus == PDH_MORE_DATA) {
// read the 1st WORD to see if this is a valid record
if (* (WORD *) pTempBuffer == BINLOG_START_WORD) {
// it's a valid record so read the 2nd DWORD to get the
// record size;
dwTempBufferSize = ((DWORD *) pTempBuffer)[1];
if (dwTempBufferSize < pLog->dwMaxRecordSize) {
// then something is bogus so return an error
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
else {
pLog->dwMaxRecordSize = dwTempBufferSize;
}
}
else {
// we're lost in this file
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
// realloc a new buffer
pOldBuffer = pTempBuffer;
pTempBuffer = G_REALLOC(pOldBuffer, dwTempBufferSize);
if (pTempBuffer == NULL) {
// return memory error
G_FREE(pOldBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
}
else {
// some other error was returned so
// return error from read function
break;
}
}
if (pdhStatus == ERROR_SUCCESS) {
PPDHI_LOG_COUNTER_PATH pPath;
DWORD dwBytesProcessed;
LONG nItemCount = 0;
LPBYTE pFirstChar;
LPWSTR szMachineName;
DWORD dwRecordLength;
DWORD dwBufferUsed = 0;
DWORD dwNewBuffer = 0;
// we can assume the record was read successfully so read in the
// machine names
dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER) pTempBuffer)->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pTempBuffer + sizeof(PDHI_BINARY_LOG_HEADER_RECORD));
dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
while (dwBytesProcessed < dwRecordLength) {
if (pPath->lMachineNameOffset >= 0L) {
// then there's a machine name in this record so get
// it's size
pFirstChar = (LPBYTE) & pPath->Buffer[0];
szMachineName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lMachineNameOffset);
dwNewBuffer = (lstrlenW (szMachineName) + 1);
while (dwNewBuffer + dwBufferUsed > dwLocalBufferSize) {
pOldBuffer = LocalBuffer;
dwLocalBufferSize += MEDIUM_BUFFER_SIZE;
LocalBuffer = G_REALLOC(pOldBuffer,
dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
if (LocalBuffer == NULL) {
if (pOldBuffer != NULL) G_FREE(pOldBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
}
pdhStatus = AddUniqueWideStringToMultiSz((LPVOID) LocalBuffer,
szMachineName,
dwLocalBufferSize - dwBufferUsed,
& dwNewBuffer,
bUnicodeDest);
if (pdhStatus == ERROR_SUCCESS) {
if (dwNewBuffer > 0) {
dwBufferUsed = dwNewBuffer;
nItemCount ++;
}
}
else {
if (pdhStatus == PDH_MORE_DATA) pdhStatus = PDH_INVALID_DATA;
goto Cleanup;
}
}
// get next path entry from log file record
dwBytesProcessed += pPath->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pPath + pPath->dwLength);
}
if (nItemCount > 0 && pdhStatus != PDH_MORE_DATA) {
// then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = ERROR_SUCCESS;
}
if (nItemCount > 0) {
dwBufferUsed ++;
}
if (pBuffer && dwBufferUsed <= * pcchBufferSize) {
RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
}
else {
if (pBuffer) {
RtlCopyMemory(pBuffer,
LocalBuffer,
(* pcchBufferSize) * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
}
pdhStatus = PDH_MORE_DATA;
}
* pcchBufferSize = dwBufferUsed;
}
Cleanup:
G_FREE(LocalBuffer);
G_FREE(pTempBuffer);
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumObjectsFromBinaryLog(
PPDHI_LOG pLog,
LPCWSTR szMachineName,
LPVOID pBuffer,
LPDWORD pcchBufferSize,
DWORD dwDetailLevel,
BOOL bUnicodeDest
)
{
LPVOID pTempBuffer = NULL;
LPVOID pOldBuffer;
DWORD dwTempBufferSize;
LPVOID LocalBuffer = NULL;
DWORD dwLocalBufferSize;
LPCWSTR szLocalMachine = szMachineName;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
// read the header record and enum the machine name from the entries
UNREFERENCED_PARAMETER(dwDetailLevel);
if (pLog->dwMaxRecordSize == 0) {
// no size is defined so start with 64K
pLog->dwMaxRecordSize = 0x010000;
}
if (szLocalMachine == NULL) szLocalMachine = szStaticLocalMachineName;
else if (szLocalMachine[0] == L'\0') szLocalMachine = szStaticLocalMachineName;
dwTempBufferSize = pLog->dwMaxRecordSize;
pTempBuffer = G_ALLOC(dwTempBufferSize);
if (pTempBuffer == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
dwLocalBufferSize = MEDIUM_BUFFER_SIZE;
LocalBuffer = G_ALLOC(dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
if (LocalBuffer == NULL) {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
// read in the catalog record
while ((pdhStatus = PdhiReadOneBinLogRecord(pLog, BINLOG_HEADER_RECORD,
pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
if (pdhStatus == PDH_MORE_DATA) {
// read the 1st WORD to see if this is a valid record
if (* (WORD *) pTempBuffer == BINLOG_START_WORD) {
// it's a valid record so read the 2nd DWORD to get the
// record size;
dwTempBufferSize = ((DWORD *) pTempBuffer)[1];
if (dwTempBufferSize < pLog->dwMaxRecordSize) {
// then something is bogus so return an error
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
else {
pLog->dwMaxRecordSize = dwTempBufferSize;
}
}
else {
// we're lost in this file
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
// realloc a new buffer
pOldBuffer = pTempBuffer;
pTempBuffer = G_REALLOC(pOldBuffer, dwTempBufferSize);
if (pTempBuffer == NULL) {
// return memory error
G_FREE(pOldBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
}
else {
// some other error was returned so
// return error from read function
break;
}
}
if (pdhStatus == ERROR_SUCCESS) {
PPDHI_LOG_COUNTER_PATH pPath;
DWORD dwBytesProcessed;
LONG nItemCount = 0;
LPBYTE pFirstChar;
LPWSTR szThisMachineName;
LPWSTR szThisObjectName;
DWORD dwRecordLength;
DWORD dwBufferUsed = 0;
DWORD dwNewBuffer = 0;
BOOL bCopyThisObject;
// we can assume the record was read successfully so read in the
// objects that match the machine name and detail level criteria
dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pTempBuffer + sizeof(PDHI_BINARY_LOG_HEADER_RECORD));
dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
while (dwBytesProcessed < dwRecordLength) {
bCopyThisObject = FALSE;
szThisObjectName = NULL;
pFirstChar = (LPBYTE) & pPath->Buffer[0];
if (pPath->lMachineNameOffset >= 0L) {
// then there's a machine name in this record so get
// it's size
szThisMachineName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lMachineNameOffset);
// if this is for the desired machine, then copy this object
if (lstrcmpiW(szThisMachineName, szLocalMachine) == 0) {
if (szThisObjectName >= 0) {
szThisObjectName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
bCopyThisObject = TRUE;
}
else {
// no object to copy
}
}
else {
// this machine isn't selected
}
}
else {
// there's no machine specified so for this counter so list it by default
if (szThisObjectName >= 0) {
szThisObjectName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
bCopyThisObject = TRUE;
}
else {
// no object to copy
}
}
if (bCopyThisObject && szThisObjectName != NULL) {
// get the size of this object's name
dwNewBuffer = (lstrlenW(szThisObjectName) + 1);
while (dwNewBuffer + dwBufferUsed > dwLocalBufferSize) {
pOldBuffer = LocalBuffer;
dwLocalBufferSize += MEDIUM_BUFFER_SIZE;
LocalBuffer = G_REALLOC(pOldBuffer,
dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
if (LocalBuffer == NULL) {
if (pOldBuffer != NULL) G_FREE(pOldBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
goto Cleanup;
}
}
pdhStatus = AddUniqueWideStringToMultiSz((LPVOID) LocalBuffer,
szThisObjectName,
dwLocalBufferSize - dwBufferUsed,
& dwNewBuffer,
bUnicodeDest);
if (pdhStatus == ERROR_SUCCESS) {
if (dwNewBuffer > 0) {
dwBufferUsed = dwNewBuffer;
nItemCount ++;
}
}
else {
if (pdhStatus == PDH_MORE_DATA) pdhStatus = PDH_INVALID_DATA;
goto Cleanup;
}
}
// get next path entry from log file record
dwBytesProcessed += pPath->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE)pPath + pPath->dwLength);
}
if (nItemCount > 0 && pdhStatus != PDH_MORE_DATA) {
// then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = ERROR_SUCCESS;
}
if (nItemCount > 0) {
dwBufferUsed ++;
}
if (pBuffer && dwBufferUsed <= * pcchBufferSize) {
RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
}
else {
if (pBuffer) {
RtlCopyMemory(pBuffer,
LocalBuffer,
(* pcchBufferSize) * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
}
pdhStatus = PDH_MORE_DATA;
}
* pcchBufferSize = dwBufferUsed;
}
Cleanup:
G_FREE(LocalBuffer);
G_FREE(pTempBuffer);
return pdhStatus;
}
PDH_FUNCTION
PdhiEnumObjectItemsFromBinaryLog(
PPDHI_LOG pLog,
LPCWSTR szMachineName,
LPCWSTR szObjectName,
PDHI_COUNTER_TABLE CounterTable,
DWORD dwDetailLevel,
DWORD dwFlags
)
{
LPVOID pTempBuffer = NULL;
LPVOID pOldBuffer;
DWORD dwTempBufferSize;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
PPDHI_INST_LIST pInstList;
PPDHI_INSTANCE pInstance;
BOOL bProcessInstance = FALSE;
UNREFERENCED_PARAMETER(dwDetailLevel);
UNREFERENCED_PARAMETER(dwFlags);
// read the header record and enum the machine name from the entries
if (pLog->dwMaxRecordSize == 0) {
// no size is defined so start with 64K
pLog->dwMaxRecordSize = 0x010000;
}
dwTempBufferSize = pLog->dwMaxRecordSize;
pTempBuffer = G_ALLOC (dwTempBufferSize);
if (pTempBuffer == NULL) {
return PDH_MEMORY_ALLOCATION_FAILURE;
}
// read in the catalog record
while ((pdhStatus = PdhiReadOneBinLogRecord(
pLog, BINLOG_HEADER_RECORD, pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
if (pdhStatus == PDH_MORE_DATA) {
// read the 1st WORD to see if this is a valid record
if (* (WORD *) pTempBuffer == BINLOG_START_WORD) {
// it's a valid record so read the 2nd DWORD to get the
// record size;
dwTempBufferSize = ((DWORD *) pTempBuffer)[1];
if (dwTempBufferSize < pLog->dwMaxRecordSize) {
// then something is bogus so return an error
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
else {
pLog->dwMaxRecordSize = dwTempBufferSize;
}
}
else {
// we're lost in this file
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
// realloc a new buffer
pOldBuffer = pTempBuffer;
pTempBuffer = G_REALLOC(pOldBuffer, dwTempBufferSize);
if (pTempBuffer == NULL) {
// return memory error
G_FREE(pOldBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
}
else {
// some other error was returned so
// return error from read function
break;
}
}
if (pdhStatus == ERROR_SUCCESS) {
PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
PPDHI_LOG_COUNTER_PATH pPath;
PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
PPDHI_RAW_COUNTER_ITEM pDataItem;
DWORD dwBytesProcessed;
LONG nItemCount = 0;
LPBYTE pFirstChar;
LPWSTR szThisMachineName;
LPWSTR szThisObjectName;
LPWSTR szThisCounterName = NULL;
LPWSTR szThisInstanceName;
LPWSTR szThisParentName;
WCHAR szCompositeInstance[SMALL_BUFFER_SIZE];
DWORD dwRecordLength;
BOOL bCopyThisObject;
DWORD dwIndex;
DWORD dwThisRecordIndex;
DWORD dwDataItemIndex;
PLOG_BIN_CAT_RECORD pCatRec;
LPWSTR szWideInstanceName;
pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD) pTempBuffer;
// we can assume the record was read successfully so read in the
// objects that match the machine name and detail level criteria
dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER) pTempBuffer)->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pTempBuffer + sizeof(PDHI_BINARY_LOG_HEADER_RECORD));
dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
dwIndex = 0;
while (dwBytesProcessed < dwRecordLength) {
bCopyThisObject = FALSE;
szThisObjectName = NULL;
dwIndex ++;
pFirstChar = (LPBYTE) & pPath->Buffer[0];
if (pPath->lMachineNameOffset >= 0L) {
// then there's a machine name in this record so get
// it's size
szThisMachineName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lMachineNameOffset);
// if this is for the desired machine, then select the object
if (lstrcmpiW(szThisMachineName,szMachineName) == 0) {
if (szThisObjectName >= 0) {
szThisObjectName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
if (lstrcmpiW(szThisObjectName,szObjectName) == 0) {
// then this is the object to look up
bCopyThisObject = TRUE;
}
else {
// not this object
}
}
else {
// no object to copy
}
}
else {
// this machine isn't selected
}
}
else {
// there's no machine specified so for this counter so list it by default
if (pPath->lObjectNameOffset >= 0) {
szThisObjectName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
if (lstrcmpiW(szThisObjectName,szObjectName) == 0) {
// then this is the object to look up
bCopyThisObject = TRUE;
}
else {
// not this object
}
}
else {
// no object to copy
}
}
if (bCopyThisObject) {
// if here, then there should be a name
// get the counter name from this counter and add it to the list
if (pPath->lCounterOffset > 0) {
szThisCounterName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lCounterOffset);
}
else {
szThisCounterName = NULL;
bCopyThisObject = FALSE;
}
}
if (bCopyThisObject) {
pdhStatus = PdhiFindCounterInstList(CounterTable, szThisCounterName, & pInstList);
if (pdhStatus != ERROR_SUCCESS || pInstList == NULL) {
continue;
}
// check instance now
// get the instance name from this counter and add it to the list
if (pPath->lInstanceOffset >= 0) {
szThisInstanceName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lInstanceOffset);
if (* szThisInstanceName != SPLAT_L) {
if (pPath->lParentOffset >= 0) {
szThisParentName = (LPWSTR)((LPBYTE) pFirstChar + pPath->lParentOffset);
StringCchPrintfW(szCompositeInstance, SMALL_BUFFER_SIZE, L"%ws%ws%ws",
szThisParentName, cszSlash, szThisInstanceName);
}
else {
StringCchCopyW(szCompositeInstance, SMALL_BUFFER_SIZE, szThisInstanceName);
}
//if (pPath->dwIndex > 0) {
// _ltow (pPath->dwIndex, (LPWSTR)
// (szCompositeInstance + lstrlenW(szCompositeInstance)),
// 10L);
//}
pdhStatus = PdhiFindInstance(& pInstList->InstList, szCompositeInstance, TRUE, & pInstance);
if (pdhStatus == ERROR_SUCCESS) {
nItemCount ++;
}
}
else {
// only use the catalog if it's up to date and present
if ((pHeader->Info.CatalogOffset > 0) &&
(pHeader->Info.LastUpdateTime <= pHeader->Info.CatalogDate)){
// find catalog record
pCatRec = (PLOG_BIN_CAT_RECORD)
// base of mapped log file
((LPBYTE) pLog->lpMappedFileBase +
// + offset to catalog records
pHeader->Info.CatalogOffset +
// + offset to the instance entry for this item
* (LPDWORD) & pPath->Buffer[0]);
for (szWideInstanceName = (LPWSTR)((LPBYTE) & pCatRec->CatEntry + pCatRec->CatEntry.dwInstanceStringOffset);
* szWideInstanceName != 0;
szWideInstanceName += lstrlenW(szWideInstanceName) + 1) {
pdhStatus = PdhiFindInstance(
& pInstList->InstList, szWideInstanceName, TRUE, & pInstance);
}
}
else if (! bProcessInstance) {
// look up individual instances in log...
// read records from file and store instances
dwThisRecordIndex = BINLOG_FIRST_DATA_RECORD;
// this call just moved the record pointer
pdhStatus = PdhiReadOneBinLogRecord (pLog, dwThisRecordIndex, NULL, 0);
while (pdhStatus == ERROR_SUCCESS) {
PdhiResetInstanceCount(CounterTable);
pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
// make sure we haven't left the file
pThisSubRecord = PdhiGetSubRecord(pThisMasterRecord, dwIndex);
if (pThisSubRecord == NULL) {
// bail on a null record
pdhStatus = PDH_END_OF_LOG_FILE;
break;
}
pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK) ((LPBYTE) pThisSubRecord +
sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
// walk down list of entries and add them to the
// list of instances (these should already
// be assembled in parent/instance format)
if (pDataBlock->dwLength > 0) {
for (dwDataItemIndex = 0;
dwDataItemIndex < pDataBlock->dwItemCount;
dwDataItemIndex++) {
pDataItem = & pDataBlock->pItemArray[dwDataItemIndex];
szThisInstanceName = (LPWSTR) (((LPBYTE) pDataBlock) + pDataItem->szName);
pdhStatus = PdhiFindInstance(
& pInstList->InstList, szThisInstanceName, TRUE, & pInstance);
}
}
else {
// no data in this record
}
if (pdhStatus != ERROR_SUCCESS) {
// then exit loop, otherwise
break;
}
else {
// go to next record in log
pdhStatus = PdhiReadOneBinLogRecord(pLog, ++ dwThisRecordIndex, NULL, 0);
}
}
if (pdhStatus == PDH_END_OF_LOG_FILE) {
pdhStatus = ERROR_SUCCESS;
}
if (pdhStatus == ERROR_SUCCESS) {
bProcessInstance = TRUE;
}
}
}
}
memset(szCompositeInstance, 0, (sizeof(szCompositeInstance)));
}
// get next path entry from log file record
dwBytesProcessed += pPath->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pPath + pPath->dwLength);
}
if (nItemCount > 0 && pdhStatus != PDH_MORE_DATA) {
// then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = ERROR_SUCCESS;
}
}
G_FREE(pTempBuffer);
return pdhStatus;
}
PDH_FUNCTION
PdhiGetMatchingBinaryLogRecord(
PPDHI_LOG pLog,
LONGLONG * pStartTime,
LPDWORD pdwIndex
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
DWORD dwRecordId;
LONGLONG RecordTimeValue;
LONGLONG LastTimeValue = 0;
PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
PPDH_RAW_COUNTER pRawItem;
// read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
// if the high dword of the time value is 0xFFFFFFFF, then the
// low dword is the record id to read
if ((* pStartTime & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000) {
dwRecordId = (DWORD) (* pStartTime & 0x00000000FFFFFFFF);
LastTimeValue = *pStartTime;
if (dwRecordId == 0) return PDH_ENTRY_NOT_IN_LOG_FILE;
}
else {
dwRecordId = BINLOG_FIRST_DATA_RECORD;
}
pdhStatus = PdhiReadOneBinLogRecord(pLog, dwRecordId, NULL, 0); // to prevent copying the record
while ((pdhStatus == ERROR_SUCCESS) && (dwRecordId >= BINLOG_FIRST_DATA_RECORD)) {
// define pointer to the current record
pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
// get timestamp of this record by looking at the first entry in the
// record.
pThisSubRecord = (PPDHI_BINARY_LOG_RECORD_HEADER)((LPBYTE) pThisMasterRecord +
sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
switch (pThisSubRecord->dwType) {
case BINLOG_TYPE_DATA_SINGLE:
pRawItem = (PPDH_RAW_COUNTER)((LPBYTE) pThisSubRecord + sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
RecordTimeValue = MAKELONGLONG(pRawItem->TimeStamp.dwLowDateTime, pRawItem->TimeStamp.dwHighDateTime);
break;
case BINLOG_TYPE_DATA_MULTI:
pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)((LPBYTE) pThisSubRecord +
sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
RecordTimeValue = * (LONGLONG *) & pDataBlock->TimeStamp;
break;
default:
// unknown record type
RecordTimeValue = 0;
break;
}
if (RecordTimeValue != 0) {
if ((*pStartTime == RecordTimeValue) || (*pStartTime == 0)) {
// found the match so bail here
LastTimeValue = RecordTimeValue;
break;
}
else if (RecordTimeValue > * pStartTime) {
// then this is the first record > than the desired time
// so the desired value is the one before this one
// unless it's the first data record of the log
if (dwRecordId > BINLOG_FIRST_DATA_RECORD) {
dwRecordId--;
}
else {
// this hasnt' been initialized yet.
LastTimeValue = RecordTimeValue;
}
break;
}
else {
// save value for next trip through loop
LastTimeValue = RecordTimeValue;
// advance record counter and try the next entry
dwRecordId ++;
}
}
else {
// no timestamp field so ignore this record.
dwRecordId ++;
}
// read the next record in the file
pdhStatus = PdhiReadOneBinLogRecord(pLog, dwRecordId, NULL, 1); // to prevent copying the record
}
if (pdhStatus == ERROR_SUCCESS) {
// then dwRecordId is the desired entry
* pdwIndex = dwRecordId;
* pStartTime = LastTimeValue;
pdhStatus = ERROR_SUCCESS;
}
else if (dwRecordId < BINLOG_FIRST_DATA_RECORD) {
// handle special cases for log type field and header record
* pdwIndex = dwRecordId;
* pStartTime = LastTimeValue;
pdhStatus = ERROR_SUCCESS;
}
else {
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetCounterFromDataBlock(
PPDHI_LOG pLog,
PVOID pDataBuffer,
PPDHI_COUNTER pCounter
);
PDH_FUNCTION
PdhiGetCounterValueFromBinaryLog(
PPDHI_LOG pLog,
DWORD dwIndex,
PPDHI_COUNTER pCounter
)
{
PDH_STATUS pdhStatus;
PPDH_RAW_COUNTER pValue = & pCounter->ThisValue;
// read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
pdhStatus = PdhiReadOneBinLogRecord(pLog, dwIndex, NULL, 0);
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhiGetCounterFromDataBlock(pLog, pLog->pLastRecordRead, pCounter);
} else {
// no more records in log file
pdhStatus = PDH_NO_MORE_DATA;
// unable to find entry in the log file
pValue->CStatus = PDH_CSTATUS_INVALID_DATA;
pValue->TimeStamp.dwLowDateTime = pValue->TimeStamp.dwHighDateTime = 0;
pValue->FirstValue = 0;
pValue->SecondValue = 0;
pValue->MultiCount = 1;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiGetTimeRangeFromBinaryLog(
PPDHI_LOG pLog,
LPDWORD pdwNumEntries,
PPDH_TIME_INFO pInfo,
LPDWORD pdwBufferSize
)
/*++
the first entry in the buffer returned is the total time range covered
in the file, if there are multiple time blocks in the log file, then
subsequent entries will identify each segment in the file.
--*/
{
PDH_STATUS pdhStatus;
LONGLONG llStartTime = MAX_TIME_VALUE;
LONGLONG llEndTime = MIN_TIME_VALUE;
LONGLONG llThisTime = (LONGLONG) 0;
DWORD dwThisRecord = BINLOG_FIRST_DATA_RECORD;
DWORD dwValidEntries = 0;
PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
PPDH_RAW_COUNTER pRawItem;
// read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
pdhStatus = PdhiReadOneBinLogRecord(pLog, dwThisRecord, NULL, 0); // to prevent copying the record
while (pdhStatus == ERROR_SUCCESS) {
// define pointer to the current record
pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
// get timestamp of this record by looking at the first entry in the
// record.
if ((pThisMasterRecord->dwType & BINLOG_TYPE_DATA) == BINLOG_TYPE_DATA) {
// only evaluate data records
pThisSubRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) ((LPBYTE) pThisMasterRecord +
sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
switch (pThisSubRecord->dwType) {
case BINLOG_TYPE_DATA_SINGLE:
pRawItem = (PPDH_RAW_COUNTER)((LPBYTE) pThisSubRecord + sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
llThisTime = MAKELONGLONG(pRawItem->TimeStamp.dwLowDateTime, pRawItem->TimeStamp.dwHighDateTime);
break;
case BINLOG_TYPE_DATA_MULTI:
pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)((LPBYTE) pThisSubRecord +
sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
llThisTime = MAKELONGLONG(pDataBlock->TimeStamp.dwLowDateTime, pDataBlock->TimeStamp.dwHighDateTime);
break;
default:
// unknown record type
llThisTime = 0;
break;
}
}
else {
llThisTime = 0;
}
if (llThisTime > 0) {
if (llThisTime < llStartTime) {
llStartTime = llThisTime;
}
if (llThisTime > llEndTime) {
llEndTime = llThisTime;
}
dwValidEntries ++;
}
else {
// no timestamp field so ignore this record.
}
// read the next record in the file
pdhStatus = PdhiReadOneBinLogRecord(pLog, ++ dwThisRecord, NULL, 0); // to prevent copying the record
}
if (pdhStatus == PDH_END_OF_LOG_FILE) {
// clear out any temp values
if (llStartTime == MAX_TIME_VALUE) llStartTime = 0;
if (llEndTime == MIN_TIME_VALUE) llEndTime = 0;
// then the whole file was read so update the args.
if (* pdwBufferSize >= sizeof(PDH_TIME_INFO)) {
* (LONGLONG *) (& pInfo->StartTime) = llStartTime;
* (LONGLONG *) (& pInfo->EndTime) = llEndTime;
pInfo->SampleCount = dwValidEntries;
* pdwBufferSize = sizeof(PDH_TIME_INFO);
* pdwNumEntries = 1;
}
else {
pdhStatus = PDH_MORE_DATA;
}
pdhStatus = ERROR_SUCCESS;
}
else {
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiReadRawBinaryLogRecord(
PPDHI_LOG pLog,
FILETIME * ftRecord,
PPDH_RAW_LOG_RECORD pBuffer,
LPDWORD pdwBufferLength
)
{
PDH_STATUS pdhStatus = ERROR_SUCCESS;
LONGLONG llStartTime;
DWORD dwIndex = 0;
DWORD dwSizeRequired;
DWORD dwLocalRecordLength; // including terminating NULL
PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
llStartTime = * (LONGLONG *) ftRecord;
pdhStatus = PdhiGetMatchingBinaryLogRecord(pLog, & llStartTime, & dwIndex);
// copy results from internal log buffer if it'll fit.
if (pdhStatus == ERROR_SUCCESS) {
if (dwIndex != BINLOG_TYPE_ID_RECORD) {
// then record is a Binary log type
pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
dwLocalRecordLength = pThisMasterRecord ? pThisMasterRecord->dwLength : 0;
}
else {
// this is a fixed size
dwLocalRecordLength = pLog->dwRecord1Size;
}
dwSizeRequired = sizeof(PDH_RAW_LOG_RECORD) - sizeof (UCHAR) + dwLocalRecordLength;
if (* pdwBufferLength >= dwSizeRequired) {
pBuffer->dwRecordType = (DWORD)(LOWORD(pLog->dwLogFormat));
pBuffer->dwItems = dwLocalRecordLength;
// copy it
if (pLog->pLastRecordRead != NULL && dwLocalRecordLength > 0) {
RtlCopyMemory(& pBuffer->RawBytes[0], pLog->pLastRecordRead, dwLocalRecordLength);
}
pBuffer->dwStructureSize = dwSizeRequired;
}
else {
pdhStatus = PDH_MORE_DATA;
}
* pdwBufferLength = dwSizeRequired;
}
return pdhStatus;
}
PDH_FUNCTION
PdhiListHeaderFromBinaryLog(
PPDHI_LOG pLogFile,
LPVOID pBufferArg,
LPDWORD pcchBufferSize,
BOOL bUnicodeDest
)
{
LPVOID pTempBuffer = NULL;
LPVOID pOldBuffer;
DWORD dwTempBufferSize;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
// read the header record and enum the machine name from the entries
if (pLogFile->dwMaxRecordSize == 0) {
// no size is defined so start with 64K
pLogFile->dwMaxRecordSize = 0x010000;
}
dwTempBufferSize = pLogFile->dwMaxRecordSize;
pTempBuffer = G_ALLOC(dwTempBufferSize);
if (pTempBuffer == NULL) {
return PDH_MEMORY_ALLOCATION_FAILURE;
}
// read in the catalog record
while ((pdhStatus = PdhiReadOneBinLogRecord(
pLogFile, BINLOG_HEADER_RECORD, pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
if (pdhStatus == PDH_MORE_DATA) {
// read the 1st WORD to see if this is a valid record
if (* (WORD *) pTempBuffer == BINLOG_START_WORD) {
// it's a valid record so read the 2nd DWORD to get the
// record size;
dwTempBufferSize = ((DWORD *) pTempBuffer)[1];
if (dwTempBufferSize < pLogFile->dwMaxRecordSize) {
// then something is bogus so return an error
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
else {
pLogFile->dwMaxRecordSize = dwTempBufferSize;
}
}
else {
// we're lost in this file
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
break; // out of while loop
}
// realloc a new buffer
pOldBuffer = pTempBuffer;
pTempBuffer = G_REALLOC(pOldBuffer, dwTempBufferSize);
if (pTempBuffer == NULL) {
// return memory error
G_FREE(pOldBuffer);
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
break;
}
}
else {
// some other error was returned so
// return error from read function
break;
}
}
if (pdhStatus == ERROR_SUCCESS) {
// walk down list and copy strings to msz buffer
PPDHI_LOG_COUNTER_PATH pPath;
DWORD dwBytesProcessed;
LONG nItemCount = 0;
LPBYTE pFirstChar;
PDH_COUNTER_PATH_ELEMENTS_W pdhPathElem;
WCHAR szPathString[1024];
DWORD dwRecordLength;
DWORD dwBufferUsed = 0;
DWORD dwNewBuffer = 0;
// we can assume the record was read successfully so read in the
// machine names
dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pTempBuffer + sizeof(PDHI_BINARY_LOG_HEADER_RECORD));
dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
while (dwBytesProcessed < dwRecordLength) {
if (pPath->lMachineNameOffset >= 0L) {
// then there's a machine name in this record so get
// it's size
memset(& pdhPathElem, 0, sizeof(pdhPathElem));
pFirstChar = (LPBYTE) & pPath->Buffer[0];
if (pPath->lMachineNameOffset >= 0) {
pdhPathElem.szMachineName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lMachineNameOffset);
}
if (pPath->lObjectNameOffset >= 0) {
pdhPathElem.szObjectName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lObjectNameOffset);
}
if (pPath->lInstanceOffset >= 0) {
pdhPathElem.szInstanceName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lInstanceOffset);
}
if (pPath->lParentOffset >= 0) {
pdhPathElem.szParentInstance = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lParentOffset);
}
if (pPath->dwIndex == 0) {
// don't display #0 in path
pdhPathElem.dwInstanceIndex = (DWORD) -1;
}
else {
pdhPathElem.dwInstanceIndex = pPath->dwIndex;
}
if (pPath->lCounterOffset >= 0) {
pdhPathElem.szCounterName = (LPWSTR) ((LPBYTE) pFirstChar + pPath->lCounterOffset);
}
dwNewBuffer = sizeof (szPathString) / sizeof(szPathString[0]);
pdhStatus = PdhMakeCounterPathW(& pdhPathElem, szPathString, & dwNewBuffer, 0);
if (pdhStatus == ERROR_SUCCESS) {
if (pBufferArg != NULL && (dwBufferUsed + dwNewBuffer + 1) < * pcchBufferSize) {
pdhStatus = AddUniqueWideStringToMultiSz((LPVOID) pBufferArg,
szPathString,
* pcchBufferSize - dwBufferUsed,
& dwNewBuffer,
bUnicodeDest);
if (pdhStatus == ERROR_SUCCESS) {
if (dwNewBuffer > 0) {
// string was added so update size used.
dwBufferUsed = dwNewBuffer;
nItemCount ++;
}
}
else if (pdhStatus == PDH_MORE_DATA) {
dwBufferUsed += dwNewBuffer;
nItemCount ++;
}
}
else {
// this one won't fit, so set the status
pdhStatus = PDH_MORE_DATA;
// and update the size required to return
// add size of this string and delimiter to the size required.
dwBufferUsed += (dwNewBuffer + 1);
nItemCount ++;
}
} // else ignore this entry
}
// get next path entry from log file record
dwBytesProcessed += pPath->dwLength;
pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pPath + pPath->dwLength);
}
if (nItemCount > 0 && pdhStatus != PDH_MORE_DATA) {
// then the routine was successful. Errors that occurred
// while scanning will be ignored as long as at least
// one entry was successfully read
pdhStatus = ERROR_SUCCESS;
}
if (pBufferArg == NULL) {
// add in size of MSZ null;
// (AddUnique... already includes this in the return value
dwBufferUsed ++;
}
// update the buffer used or required.
* pcchBufferSize = dwBufferUsed;
}
G_FREE(pTempBuffer);
return pdhStatus;
}
PDH_FUNCTION
PdhiGetCounterArrayFromBinaryLog(
PPDHI_LOG pLog,
DWORD dwIndex,
PPDHI_COUNTER pCounter,
PPDHI_RAW_COUNTER_ITEM_BLOCK * ppValue
)
{
PDH_STATUS pdhStatus;
DWORD dwDataItemIndex;
PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
PPDHI_RAW_COUNTER_ITEM_BLOCK pNewArrayHeader;
// allocate a new array for
// update counter's Current counter array contents
// read the first data record in the log file
// note that the record read is not copied to the local buffer
// rather the internal buffer is used in "read-only" mode
pdhStatus = PdhiReadOneBinLogRecord(pLog, dwIndex, NULL, 0); // to prevent copying the record
if (pdhStatus == ERROR_SUCCESS) {
// define pointer to the current record
pThisMasterRecord = (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
// get timestamp of this record by looking at the first entry in the
// record.
if (pThisMasterRecord->dwType != BINLOG_TYPE_DATA) return PDH_NO_MORE_DATA;
pThisSubRecord = PdhiGetSubRecord(pThisMasterRecord, pCounter->plCounterInfo.dwCounterId);
if (pThisSubRecord != NULL) {
switch (pThisSubRecord->dwType) {
case BINLOG_TYPE_DATA_SINGLE:
// return data as one instance
// for now this isn't supported as it won't be hit.
//
break;
case BINLOG_TYPE_DATA_MULTI:
// cast pointer to this part of the data record
pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK) ((LPBYTE) pThisSubRecord +
sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
// allocate a new buffer for the data
pNewArrayHeader = (PPDHI_RAW_COUNTER_ITEM_BLOCK) G_ALLOC(pDataBlock->dwLength);
if (pNewArrayHeader != NULL) {
// copy the log record to the local buffer
RtlCopyMemory(pNewArrayHeader, pDataBlock, pDataBlock->dwLength);
// convert offsets to pointers
for (dwDataItemIndex = 0; dwDataItemIndex < pNewArrayHeader->dwItemCount; dwDataItemIndex ++) {
// add in the address of the base of the structure
// to the offset stored in the field
pNewArrayHeader->pItemArray[dwDataItemIndex].szName =
pNewArrayHeader->pItemArray[dwDataItemIndex].szName;
}
// clear any old buffers
if (pCounter->pThisRawItemList != NULL) {
G_FREE(pCounter->pThisRawItemList);
pCounter->pThisRawItemList = NULL;
}
pCounter->pThisRawItemList = pNewArrayHeader;
* ppValue = pNewArrayHeader;
}
else {
pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
}
break;
default:
pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
break;
}
}
else {
// entry not found in record
pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
}
}
else {
// no more records in log file
pdhStatus = PDH_NO_MORE_DATA;
}
return pdhStatus;
}