Source code of Windows XP (NT5)
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.

3834 lines
160 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. log_bin.c
  5. Abstract:
  6. <abstract>
  7. --*/
  8. #include <windows.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <assert.h>
  12. #include <pdh.h>
  13. //#define _SHOW_PDH_MEM_ALLOCS 1
  14. #include "pdhidef.h"
  15. #include "log_bin.h"
  16. #include "log_wmi.h"
  17. #include "strings.h"
  18. #include "pdhmsg.h"
  19. typedef struct _LOG_BIN_CAT_RECORD {
  20. PDHI_BINARY_LOG_RECORD_HEADER RecHeader;
  21. PDHI_LOG_CAT_ENTRY CatEntry;
  22. DWORD dwEntryRecBuff[1];
  23. } LOG_BIN_CAT_RECORD, *PLOG_BIN_CAT_RECORD;
  24. typedef struct _LOG_BIN_CAT_ENTRY {
  25. DWORD dwEntrySize;
  26. DWORD dwOffsetToNextInstance;
  27. DWORD dwEntryOffset;
  28. LOG_BIN_CAT_RECORD bcRec;
  29. } LOG_BIN_CAT_ENTRY, *PLOG_BIN_CAT_ENTRY;
  30. #define RECORD_AT(p,lo) ((PPDHI_BINARY_LOG_RECORD_HEADER)((LPBYTE)(p->lpMappedFileBase) + lo))
  31. LPCSTR PdhiszRecordTerminator = "\r\n";
  32. DWORD PdhidwRecordTerminatorLength = 2;
  33. #define MAX_BINLOG_FILE_SIZE ((LONGLONG)0x0000000040000000)
  34. // dwFlags values
  35. #define WBLR_WRITE_DATA_RECORD 0
  36. #define WBLR_WRITE_LOG_HEADER 1
  37. #define WBLR_WRITE_COUNTER_HEADER 2
  38. PDH_FUNCTION
  39. PdhiWriteOneBinaryLogRecord (
  40. PPDHI_LOG pLog,
  41. LPCVOID pData,
  42. DWORD dwSize,
  43. LPDWORD pdwRtnSize,
  44. DWORD dwFlags)
  45. {
  46. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  47. DWORD dwRtnSize;
  48. LONGLONG llFirstOffset = 0;
  49. LONGLONG llThisOffset =0;
  50. LONGLONG llNextOffset =0;
  51. LONGLONG llLastOffset =0;
  52. LONGLONG llWrapOffset =0;
  53. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  54. DWORD dwRecLen;
  55. LPVOID lpDest = NULL;
  56. LARGE_INTEGER liFileSize;
  57. SetLastError (ERROR_SUCCESS);
  58. if (pLog->lpMappedFileBase != NULL) {
  59. if (dwSize > pLog->llMaxSize) {
  60. // This record is too large to ever fit in this file
  61. pdhStatus = PDH_LOG_FILE_TOO_SMALL;
  62. } else {
  63. // T
  64. if (dwFlags == WBLR_WRITE_DATA_RECORD) {
  65. // this is a mapped file so it's either a circular
  66. // or a limited linear file.
  67. // get the address of the log file header record.
  68. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)
  69. ((LPBYTE)(pLog->lpMappedFileBase) + pLog->dwRecord1Size);
  70. // then write the record using memory functions since the
  71. // file is mapped as a memory section
  72. // 1st see if there's room in the file for this record
  73. llNextOffset = pHeader->Info.NextRecordOffset + dwSize;
  74. if (llNextOffset > pLog->llMaxSize) {
  75. if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
  76. // if circular, then start back at the beginning
  77. llWrapOffset = pHeader->Info.NextRecordOffset;
  78. if ((pLog->llMaxSize - llWrapOffset) > dwSize) {
  79. // This record is too large to ever fit in the rest of this file
  80. pdhStatus = PDH_LOG_FILE_TOO_SMALL;
  81. } else {
  82. llThisOffset = pHeader->Info.FirstDataRecordOffset;
  83. llNextOffset = llThisOffset + dwSize;
  84. llLastOffset = llThisOffset;
  85. llFirstOffset = llThisOffset;
  86. while (llFirstOffset < llNextOffset) {
  87. dwRecLen = RECORD_AT(pLog, llFirstOffset)->dwLength;
  88. if (dwRecLen > 0) {
  89. llFirstOffset += dwRecLen;
  90. } else {
  91. // this record is unused so try it.
  92. break;
  93. }
  94. assert (llFirstOffset < llWrapOffset);
  95. }
  96. }
  97. } else {
  98. // that's all that will fit so return
  99. // file is full error
  100. pdhStatus = PDH_END_OF_LOG_FILE;
  101. dwRtnSize = 0;
  102. }
  103. } else {
  104. // this record will fit in the remaining space of
  105. // the log file so write it
  106. llThisOffset = pHeader->Info.NextRecordOffset;
  107. llLastOffset = llThisOffset;
  108. llWrapOffset = pHeader->Info.WrapOffset;
  109. llFirstOffset = pHeader->Info.FirstRecordOffset;
  110. if (llWrapOffset != 0) {
  111. // check next pointer to see if we're on the
  112. // 2nd or more lap through a circular log
  113. // in which case, the first record should come after the last
  114. while (llNextOffset > llFirstOffset) {
  115. llFirstOffset += RECORD_AT(pLog, llFirstOffset)->dwLength;
  116. // check for running past the end of the file, in which case
  117. // the first record can be found at the beginning of the log
  118. if (llFirstOffset >= llWrapOffset) {
  119. llFirstOffset = pHeader->Info.FirstDataRecordOffset;
  120. llWrapOffset = llNextOffset;
  121. break;
  122. }
  123. }
  124. if (llNextOffset > llWrapOffset) llWrapOffset = llNextOffset;
  125. } else {
  126. // this is just a linear log or a circular log on the first lap
  127. // so there's nothing to do
  128. }
  129. }
  130. if (pdhStatus == ERROR_SUCCESS) {
  131. // test for strays here before continuing
  132. assert (llThisOffset < pLog->llMaxSize);
  133. assert (llNextOffset < pLog->llMaxSize);
  134. assert (llWrapOffset < pLog->llMaxSize);
  135. // here first, this, next and last should be set
  136. // first == the first record to be read from the log
  137. // this == where this record will be placed
  138. // next == where the next record after this one will be placed
  139. // last == the last record in the sequence
  140. // wrap == the last byte used in the log file
  141. // (not necessarily the end of the file)
  142. __try {
  143. // move the caller's data into the file
  144. lpDest = (LPVOID)RECORD_AT(pLog, llThisOffset);
  145. // make sure there's room in the section for this
  146. // record...
  147. if ((llThisOffset + dwSize) <= pLog->llMaxSize) {
  148. // looks like it'll fit
  149. RtlCopyMemory(lpDest, (LPVOID)pData, dwSize);
  150. // update the header fields
  151. pHeader->Info.NextRecordOffset = llNextOffset;
  152. pHeader->Info.FirstRecordOffset = llFirstOffset;
  153. pHeader->Info.LastRecordOffset = llLastOffset;
  154. pHeader->Info.WrapOffset = llWrapOffset;
  155. // write update time stamp
  156. GetSystemTimeAsFileTime ((LPFILETIME)(&pHeader->Info.LastUpdateTime));
  157. if (pdwRtnSize != NULL) {
  158. *pdwRtnSize = dwSize;
  159. }
  160. // update the filesize
  161. if (llNextOffset > pHeader->Info.FileLength) {
  162. pHeader->Info.FileLength = llNextOffset;
  163. }
  164. assert (pHeader->Info.FileLength >= pHeader->Info.WrapOffset);
  165. } else {
  166. // this record is too big for the file
  167. pdhStatus = PDH_LOG_FILE_TOO_SMALL;
  168. }
  169. } __except (EXCEPTION_EXECUTE_HANDLER) {
  170. pdhStatus = GetExceptionCode();
  171. }
  172. } else {
  173. // a error occured so pass it back up to the caller
  174. }
  175. } else {
  176. if (dwFlags == WBLR_WRITE_LOG_HEADER) {
  177. // this goes right at the start of the file
  178. lpDest = (LPVOID)pLog->lpMappedFileBase;
  179. RtlCopyMemory(lpDest, (LPVOID)pData, dwSize);
  180. } else if (dwFlags == WBLR_WRITE_COUNTER_HEADER) {
  181. assert (pLog->dwRecord1Size != 0);
  182. lpDest = (LPVOID)RECORD_AT(pLog, pLog->dwRecord1Size);
  183. RtlCopyMemory(lpDest, (LPVOID)pData, dwSize);
  184. } else {
  185. // This should never happen
  186. assert( dwFlags == WBLR_WRITE_LOG_HEADER
  187. || dwFlags == WBLR_WRITE_COUNTER_HEADER
  188. || dwFlags == WBLR_WRITE_DATA_RECORD);
  189. pdhStatus = PDH_INVALID_ARGUMENT;
  190. }
  191. }
  192. }
  193. } else {
  194. liFileSize.LowPart = GetFileSize (
  195. pLog->hLogFileHandle,
  196. (LPDWORD)&liFileSize.HighPart);
  197. // add in new record to see if it will fit.
  198. liFileSize.QuadPart += dwSize;
  199. // test for maximum allowable filesize
  200. if (liFileSize.QuadPart <= MAX_BINLOG_FILE_SIZE) {
  201. // write the data to the file as a file
  202. if (!WriteFile (pLog->hLogFileHandle,
  203. pData,
  204. dwSize,
  205. pdwRtnSize,
  206. NULL)) {
  207. pdhStatus = GetLastError();
  208. } else {
  209. FlushFileBuffers(pLog->hLogFileHandle);
  210. pdhStatus = ERROR_SUCCESS;
  211. }
  212. } else {
  213. pdhStatus = ERROR_LOG_FILE_FULL;
  214. }
  215. }
  216. return pdhStatus;
  217. }
  218. DWORD
  219. PdhiComputeDwordChecksum (
  220. IN LPVOID pBuffer,
  221. IN DWORD dwBufferSize // in bytes
  222. )
  223. {
  224. LPDWORD pDwVal;
  225. LPBYTE pByteVal;
  226. DWORD dwDwCount;
  227. DWORD dwByteCount;
  228. DWORD dwThisByte;
  229. DWORD dwCheckSum = 0;
  230. DWORD dwByteVal = 0;
  231. if (dwBufferSize > 0) {
  232. dwDwCount = dwBufferSize / sizeof(DWORD);
  233. dwByteCount = dwBufferSize % sizeof(DWORD);
  234. assert (dwByteCount >= 0);
  235. assert (dwByteCount < sizeof(DWORD));
  236. pDwVal = (LPDWORD)pBuffer;
  237. while (dwDwCount != 0) {
  238. dwCheckSum += *pDwVal++;
  239. dwDwCount--;
  240. }
  241. assert (dwDwCount == 0);
  242. assert ((DWORD)((LPBYTE)pDwVal - (LPBYTE)pBuffer) <= dwBufferSize);
  243. pByteVal = (LPBYTE)pDwVal;
  244. dwThisByte = 0;
  245. while (dwThisByte < dwByteCount) {
  246. dwByteVal |= ((*pByteVal & 0x000000FF) << (dwThisByte * 8));
  247. dwThisByte++;
  248. }
  249. assert ((DWORD)((LPBYTE)pByteVal - (LPBYTE)pBuffer) == dwBufferSize);
  250. dwCheckSum += dwByteVal;
  251. }
  252. return dwCheckSum;
  253. }
  254. PPDHI_BINARY_LOG_RECORD_HEADER
  255. PdhiGetSubRecord (
  256. IN PPDHI_BINARY_LOG_RECORD_HEADER pRecord,
  257. IN DWORD dwRecordId
  258. )
  259. // locates the specified sub record in the pRecord Buffer
  260. // the return pointer is between pRecord and pRecord + pRecord->dwLength;
  261. // NULL is returned if the specified record could not be found
  262. // ID values start at 1 for the first sub record in buffer
  263. {
  264. PPDHI_BINARY_LOG_RECORD_HEADER pThisRecord;
  265. DWORD dwRecordType;
  266. DWORD dwRecordLength;
  267. DWORD dwBytesProcessed;
  268. DWORD dwThisSubRecordId;
  269. dwRecordType = ((PPDHI_BINARY_LOG_RECORD_HEADER)pRecord)->dwType;
  270. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pRecord)->dwLength;
  271. pThisRecord = (PPDHI_BINARY_LOG_RECORD_HEADER)((LPBYTE)pRecord +
  272. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  273. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
  274. if (dwBytesProcessed < dwRecordLength) {
  275. dwThisSubRecordId = 1;
  276. while (dwThisSubRecordId < dwRecordId) {
  277. if ((WORD)(pThisRecord->dwType & 0x0000FFFF) == BINLOG_START_WORD) {
  278. // go to next sub record
  279. dwBytesProcessed += pThisRecord->dwLength;
  280. pThisRecord = (PPDHI_BINARY_LOG_RECORD_HEADER)
  281. (((LPBYTE)pThisRecord) + pThisRecord->dwLength);
  282. if (dwBytesProcessed >= dwRecordLength) {
  283. // out of sub-records so exit
  284. break;
  285. } else {
  286. dwThisSubRecordId++;
  287. }
  288. } else {
  289. // we're lost so bail
  290. break;
  291. }
  292. }
  293. } else {
  294. dwThisSubRecordId = 0;
  295. }
  296. if (dwThisSubRecordId == dwRecordId) {
  297. // then validate this is really a record and it's within the
  298. // master record.
  299. if ((WORD)(pThisRecord->dwType & 0x0000FFFF) != BINLOG_START_WORD) {
  300. // bogus record so return a NULL pointer
  301. pThisRecord = NULL;
  302. } else {
  303. // this is OK so return pointer
  304. }
  305. } else {
  306. // record not found so return a NULL pointer
  307. pThisRecord = NULL;
  308. }
  309. return pThisRecord;
  310. }
  311. STATIC_PDH_FUNCTION
  312. PdhiReadBinaryMappedRecord(
  313. IN PPDHI_LOG pLog,
  314. IN DWORD dwRecordId,
  315. IN LPVOID pRecord,
  316. IN DWORD dwMaxSize
  317. )
  318. {
  319. PDH_STATUS pdhStatus= ERROR_SUCCESS;
  320. LPVOID pEndOfFile;
  321. LPVOID pLastRecord;
  322. DWORD dwLastRecordIndex;
  323. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  324. PPDHI_BINARY_LOG_RECORD_HEADER pRecHeader;
  325. LPVOID pLastRecordInLog;
  326. DWORD dwBytesToRead;
  327. DWORD dwBytesRead;
  328. BOOL bStatus;
  329. if (dwRecordId == 0) return PDH_ENTRY_NOT_IN_LOG_FILE; // record numbers start at 1
  330. // see if the file has been mapped
  331. if (pLog->hMappedLogFile == NULL) {
  332. // then it's not mapped so read it using the file system
  333. if ((pLog->dwLastRecordRead == 0) || (dwRecordId < pLog->dwLastRecordRead)) {
  334. // then we know no record has been read yet so assign
  335. // pointer just to be sure
  336. SetFilePointer (pLog->hLogFileHandle, 0, NULL, FILE_BEGIN);
  337. // allocate a new buffer
  338. if (pLog->dwMaxRecordSize < 0x10000) pLog->dwMaxRecordSize = 0x10000;
  339. dwBytesToRead = pLog->dwMaxRecordSize;
  340. // allocate a fresh buffer
  341. if (pLog->pLastRecordRead != NULL) {
  342. G_FREE(pLog->pLastRecordRead);
  343. pLog->pLastRecordRead = NULL;
  344. }
  345. pLog->pLastRecordRead = G_ALLOC (pLog->dwMaxRecordSize);
  346. if (pLog->pLastRecordRead == NULL) {
  347. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  348. } else {
  349. // initialize the first record header
  350. dwBytesToRead = pLog->dwRecord1Size;
  351. dwBytesRead = 0;
  352. bStatus = ReadFile (
  353. pLog->hLogFileHandle,
  354. pLog->pLastRecordRead,
  355. dwBytesToRead,
  356. &dwBytesRead,
  357. NULL);
  358. if (bStatus && (dwBytesRead == pLog->dwRecord1Size)) {
  359. // make sure the buffer is big enough
  360. pLog->dwLastRecordRead = 1;
  361. pdhStatus = ERROR_SUCCESS;
  362. } else {
  363. // unable to read the first record
  364. pdhStatus = PDH_UNABLE_READ_LOG_HEADER;
  365. }
  366. }
  367. } else {
  368. // assume everything is already set up and OK
  369. }
  370. // pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)RECORD_AT(pLog, pLog->dwRecord1Size);
  371. // assert (*(WORD *)&(pHeader->RecHeader.dwType) == BINLOG_START_WORD);
  372. // "seek" to the desired record file pointer should either be pointed
  373. // to the start of a new record or at the end of the file
  374. while ((dwRecordId != pLog->dwLastRecordRead) && (pdhStatus == ERROR_SUCCESS)) {
  375. // clear the buffer
  376. memset (pLog->pLastRecordRead, 0, pLog->dwMaxRecordSize);
  377. // read record header field
  378. dwBytesToRead = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
  379. dwBytesRead = 0;
  380. bStatus = ReadFile (
  381. pLog->hLogFileHandle,
  382. pLog->pLastRecordRead,
  383. dwBytesToRead,
  384. &dwBytesRead,
  385. NULL);
  386. if (bStatus && (dwBytesRead == dwBytesToRead)) {
  387. // make sure the rest of the record will fit in the buffer
  388. pRecHeader = (PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead;
  389. // make sure this is a valid record
  390. if (*(WORD *)&(pRecHeader->dwType) == BINLOG_START_WORD) {
  391. if (pRecHeader->dwLength > pLog->dwMaxRecordSize) {
  392. // realloc the buffer
  393. LPVOID pTmp = pLog->pLastRecordRead;
  394. pLog->dwMaxRecordSize = pRecHeader->dwLength;
  395. pLog->pLastRecordRead = G_REALLOC(pTmp, pLog->dwMaxRecordSize);
  396. if (pLog->pLastRecordRead == NULL) {
  397. G_FREE(pTmp);
  398. }
  399. }
  400. if (pLog->pLastRecordRead != NULL) {
  401. dwBytesToRead = pRecHeader->dwLength - sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
  402. dwBytesRead = 0;
  403. pLastRecord = (LPVOID)((LPBYTE)(pLog->pLastRecordRead) + sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
  404. bStatus = ReadFile (
  405. pLog->hLogFileHandle,
  406. pLastRecord,
  407. dwBytesToRead,
  408. &dwBytesRead,
  409. NULL);
  410. if (bStatus) {
  411. pLog->dwLastRecordRead++;
  412. } else {
  413. pdhStatus = PDH_END_OF_LOG_FILE;
  414. }
  415. } else {
  416. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  417. }
  418. } else {
  419. // file is corrupt
  420. pdhStatus = PDH_INVALID_DATA;
  421. }
  422. } else {
  423. pdhStatus = PDH_END_OF_LOG_FILE;
  424. }
  425. }
  426. // here the result will be success when the specified file has been read or
  427. // a PDH error if not
  428. } else {
  429. // the file has been memory mapped so use that interface
  430. if (pLog->dwLastRecordRead == 0) {
  431. // then we know no record has been read yet so assign
  432. // pointer just to be sure
  433. pLog->pLastRecordRead = pLog->lpMappedFileBase;
  434. pLog->dwLastRecordRead = 1;
  435. }
  436. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)RECORD_AT(pLog, pLog->dwRecord1Size);
  437. assert (*(WORD *)&(pHeader->RecHeader.dwType) == BINLOG_START_WORD);
  438. // "seek" to the desired record
  439. if (dwRecordId < pLog->dwLastRecordRead) {
  440. if (dwRecordId >= BINLOG_FIRST_DATA_RECORD) {
  441. // rewind the file
  442. pLog->pLastRecordRead = (LPVOID)((LPBYTE)pLog->lpMappedFileBase + pHeader->Info.FirstRecordOffset);
  443. pLog->dwLastRecordRead = BINLOG_FIRST_DATA_RECORD;
  444. } else {
  445. // rewind the file
  446. pLog->pLastRecordRead = pLog->lpMappedFileBase;
  447. pLog->dwLastRecordRead = 1;
  448. }
  449. }
  450. // then use the point specified as the end of the file
  451. // if the log file contians a specified Wrap offset, then use that
  452. // if not, then if the file length is specified, use that
  453. // if not, the use the reported file length
  454. pEndOfFile = (LPVOID)((LPBYTE)pLog->lpMappedFileBase);
  455. if (pHeader->Info.WrapOffset > 0) {
  456. pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pHeader->Info.WrapOffset);
  457. assert (pHeader->Info.FileLength >= pHeader->Info.WrapOffset);
  458. } else if (pHeader->Info.FileLength > 0) {
  459. pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pHeader->Info.FileLength);
  460. assert (pHeader->Info.FileLength <= pLog->llFileSize);
  461. } else {
  462. pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pLog->llFileSize);
  463. }
  464. pLastRecord = pLog->pLastRecordRead;
  465. dwLastRecordIndex = pLog->dwLastRecordRead;
  466. __try {
  467. // walk around the file until an access violation occurs or
  468. // the record is found. If an access violation occurs,
  469. // we can assume we went off the end of the file and out
  470. // of the mapped section
  471. // make sure the record has a valid header
  472. if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD ?
  473. (*(WORD *)pLog->pLastRecordRead == BINLOG_START_WORD) : TRUE) {
  474. // then it looks OK so continue
  475. while (pLog->dwLastRecordRead != dwRecordId) {
  476. // go to next record
  477. pLastRecord = pLog->pLastRecordRead;
  478. if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD) {
  479. if (pLog->dwLastRecordRead == BINLOG_HEADER_RECORD) {
  480. // if the last record was the header, then the next record
  481. // is the "first" data , not the first after the header
  482. pLog->pLastRecordRead = (LPVOID)((LPBYTE)pLog->lpMappedFileBase +
  483. pHeader->Info.FirstRecordOffset);
  484. } else {
  485. // if the current record is any record other than the header
  486. // ...then
  487. if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength > 0) {
  488. // go to the next record in the file
  489. pLog->pLastRecordRead = (LPVOID)((LPBYTE)pLog->pLastRecordRead+
  490. ((PPDHI_BINARY_LOG_RECORD_HEADER)
  491. pLog->pLastRecordRead)->dwLength);
  492. // test for exceptions here
  493. if (pLog->pLastRecordRead >= pEndOfFile) {
  494. // find out if this is a circular log or not
  495. if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
  496. // test to see if the file has wrapped
  497. if (pHeader->Info.WrapOffset != 0) {
  498. // then wrap to the beginning of the file
  499. pLog->pLastRecordRead = (LPVOID)((LPBYTE)pLog->lpMappedFileBase +
  500. pHeader->Info.FirstDataRecordOffset);
  501. } else {
  502. // the file is still linear so this is the end
  503. pdhStatus = PDH_END_OF_LOG_FILE;
  504. }
  505. } else {
  506. // this is the end of the file
  507. // so reset to the previous pointer
  508. pdhStatus = PDH_END_OF_LOG_FILE;
  509. }
  510. } else {
  511. // not at the physical end of the file, but if this is a circular
  512. // log, it could be the logical end of the records so test that
  513. // here
  514. if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
  515. pLastRecordInLog = (LPVOID)((LPBYTE)pLog->lpMappedFileBase +
  516. pHeader->Info.LastRecordOffset);
  517. pLastRecordInLog = (LPVOID)((LPBYTE)pLastRecordInLog +
  518. ((PPDHI_BINARY_LOG_RECORD_HEADER)pLastRecordInLog)->dwLength);
  519. if (pLog->pLastRecordRead == pLastRecordInLog) {
  520. // then this is the last record in the log
  521. pdhStatus = PDH_END_OF_LOG_FILE;
  522. }
  523. } else {
  524. // nothing to do since this is a normal case
  525. }
  526. } // end if / if not end of log file
  527. } else {
  528. // length is 0 so we've probably run off the end of the log somehow
  529. pdhStatus = PDH_END_OF_LOG_FILE;
  530. }
  531. } // end if /if not header record
  532. } else {
  533. pLog->pLastRecordRead = (LPBYTE)pLog->pLastRecordRead +
  534. pLog->dwRecord1Size;
  535. }
  536. if (pdhStatus == ERROR_SUCCESS) {
  537. // update pointers & indices
  538. pLog->dwLastRecordRead++;
  539. dwLastRecordIndex = pLog->dwLastRecordRead;
  540. } else {
  541. pLog->pLastRecordRead = pLastRecord;
  542. break; // out of the while loop
  543. }
  544. }
  545. } else {
  546. pdhStatus = PDH_END_OF_LOG_FILE;
  547. }
  548. } __except (EXCEPTION_EXECUTE_HANDLER) {
  549. pLog->pLastRecordRead = pLastRecord;
  550. pLog->dwLastRecordRead = dwLastRecordIndex;
  551. }
  552. }
  553. if (pdhStatus == ERROR_SUCCESS) {
  554. // see if we ended up at the right place
  555. if (pLog->dwLastRecordRead == dwRecordId) {
  556. if (pRecord != NULL) {
  557. // then try to copy it
  558. // if the record ID is 1 then it's the header record so this is
  559. // a special case record that is actually a CR/LF terminated record
  560. if (dwRecordId != BINLOG_TYPE_ID_RECORD) {
  561. if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength <= dwMaxSize) {
  562. // then it'll fit so copy it
  563. memcpy (pRecord, pLog->pLastRecordRead,
  564. ((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength);
  565. pdhStatus = ERROR_SUCCESS;
  566. } else {
  567. // then copy as much as will fit
  568. memcpy (pRecord, pLog->pLastRecordRead, dwMaxSize);
  569. pdhStatus = PDH_MORE_DATA;
  570. }
  571. } else {
  572. // copy the first record and zero terminate it
  573. if (pLog->dwRecord1Size <= dwMaxSize) {
  574. memcpy (pRecord, pLog->pLastRecordRead,
  575. pLog->dwRecord1Size);
  576. // null terminate after string
  577. ((LPBYTE)pRecord)[pLog->dwRecord1Size - PdhidwRecordTerminatorLength + 1] = 0;
  578. } else {
  579. memcpy (pRecord, pLog->pLastRecordRead, dwMaxSize);
  580. pdhStatus = PDH_MORE_DATA;
  581. }
  582. }
  583. } else {
  584. // just return success
  585. // no buffer was passed, but the record pointer has been
  586. // positioned
  587. pdhStatus = ERROR_SUCCESS;
  588. }
  589. } else {
  590. pdhStatus = PDH_END_OF_LOG_FILE;
  591. }
  592. }
  593. return pdhStatus;
  594. }
  595. STATIC_PDH_FUNCTION
  596. PdhiReadOneBinLogRecord (
  597. IN PPDHI_LOG pLog,
  598. IN DWORD dwRecordId,
  599. IN LPVOID pRecord,
  600. IN DWORD dwMaxSize
  601. )
  602. {
  603. PDH_STATUS pdhStatus= ERROR_SUCCESS;
  604. LPVOID pEndOfFile;
  605. LPVOID pLastRecord;
  606. DWORD dwLastRecordIndex = 0;
  607. PPDHI_BINARY_LOG_HEADER_RECORD pHeader = NULL;
  608. BOOL bCircular = FALSE;
  609. DWORD dwRecordSize;
  610. DWORD dwRecordReadSize;
  611. LONGLONG llLastFileOffset;
  612. LPVOID pTmpBuffer;
  613. assert (dwRecordId > 0); // record numbers start at 1
  614. if ( (LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY)
  615. && (dwRecordId == BINLOG_HEADER_RECORD)) {
  616. // special handling for WMI event trace logfile format
  617. //
  618. return PdhiReadWmiHeaderRecord(pLog, pRecord, dwMaxSize);
  619. }
  620. if (pLog->iRunidSQL != 0) {
  621. return PdhiReadBinaryMappedRecord(pLog, dwRecordId, pRecord, dwMaxSize);
  622. }
  623. if (pLog->dwLastRecordRead == 0) {
  624. // then we know no record has been read yet so assign
  625. // pointer just to be sure
  626. pLog->pLastRecordRead = NULL;
  627. pLog->liLastRecordOffset.QuadPart = 0;
  628. SetFilePointer (pLog->hLogFileHandle, pLog->liLastRecordOffset.LowPart,
  629. &pLog->liLastRecordOffset.HighPart, FILE_BEGIN);
  630. if (pLog->liLastRecordOffset.LowPart == INVALID_SET_FILE_POINTER) {
  631. pdhStatus = GetLastError();
  632. }
  633. }
  634. if (pdhStatus == ERROR_SUCCESS) {
  635. // map header to local structure (the header data should be mapped into memory
  636. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)RECORD_AT(pLog, pLog->dwRecord1Size);
  637. assert (*(WORD *)&(pHeader->RecHeader.dwType) == BINLOG_START_WORD);
  638. if (pHeader->Info.WrapOffset > 0) {
  639. bCircular = TRUE;
  640. }
  641. // "seek" to the desired record
  642. if ((dwRecordId < pLog->dwLastRecordRead) || (pLog->dwLastRecordRead == 0)) {
  643. // rewind if not initialized or the desired record is before this one
  644. if (dwRecordId >= BINLOG_FIRST_DATA_RECORD) {
  645. // rewind the file to the first regular record
  646. pLog->liLastRecordOffset.QuadPart = pHeader->Info.FirstRecordOffset;
  647. pLog->dwLastRecordRead = BINLOG_FIRST_DATA_RECORD;
  648. } else {
  649. // rewind the file to the very start of the file
  650. pLog->liLastRecordOffset.QuadPart = 0;
  651. pLog->dwLastRecordRead = 1;
  652. }
  653. pLog->liLastRecordOffset.LowPart = SetFilePointer (pLog->hLogFileHandle, pLog->liLastRecordOffset.LowPart,
  654. &pLog->liLastRecordOffset.HighPart, FILE_BEGIN);
  655. if (pLog->liLastRecordOffset.LowPart == INVALID_SET_FILE_POINTER) {
  656. pdhStatus = GetLastError();
  657. } else {
  658. if (pLog->pLastRecordRead != NULL) {
  659. G_FREE (pLog->pLastRecordRead);
  660. pLog->pLastRecordRead = NULL;
  661. }
  662. if (pLog->dwLastRecordRead == 1) {
  663. // the this is the text ID field
  664. dwRecordSize = pLog->dwRecord1Size;
  665. } else {
  666. dwRecordSize = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
  667. }
  668. pLog->pLastRecordRead = G_ALLOC (dwRecordSize);
  669. if (pLog->pLastRecordRead != NULL) {
  670. // read in the header (or entire record if the 1st record
  671. // otherwise it's a data record
  672. if (ReadFile (pLog->hLogFileHandle,
  673. pLog->pLastRecordRead,
  674. dwRecordSize,
  675. &dwRecordReadSize,
  676. NULL)) {
  677. // then we have the record header or type record so
  678. // complete the operation and read the rest of the record
  679. if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD) {
  680. // the Type ID record is of fixed length and has not header record
  681. dwRecordSize = ((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength;
  682. pTmpBuffer = pLog->pLastRecordRead;
  683. pLog->pLastRecordRead = G_REALLOC(pTmpBuffer, dwRecordSize);
  684. if (pLog->pLastRecordRead != NULL) {
  685. // read in the rest of the record and append it to the header data already read in
  686. // otherwise it's a data record
  687. pLastRecord = (LPVOID)&((LPBYTE)pLog->pLastRecordRead)[sizeof(PDHI_BINARY_LOG_RECORD_HEADER)];
  688. if (ReadFile (pLog->hLogFileHandle,
  689. pLastRecord,
  690. dwRecordSize - sizeof(PDHI_BINARY_LOG_RECORD_HEADER),
  691. &dwRecordReadSize,
  692. NULL)) {
  693. // then we have the record header or type record
  694. pdhStatus = ERROR_SUCCESS;
  695. } else {
  696. pdhStatus = GetLastError();
  697. }
  698. } else {
  699. G_FREE(pTmpBuffer);
  700. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  701. }
  702. }
  703. pdhStatus = ERROR_SUCCESS;
  704. } else {
  705. pdhStatus = GetLastError();
  706. }
  707. } else {
  708. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  709. }
  710. }
  711. }
  712. // then use the point specified as the end of the file
  713. // if the log file contians a specified Wrap offset, then use that
  714. // if not, then if the file length is specified, use that
  715. // if not, the use the reported file length
  716. pEndOfFile = (LPVOID)((LPBYTE)pLog->lpMappedFileBase);
  717. if (pHeader->Info.WrapOffset > 0) {
  718. pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pHeader->Info.WrapOffset);
  719. assert (pHeader->Info.FileLength >= pHeader->Info.WrapOffset);
  720. } else if (pHeader->Info.FileLength > 0) {
  721. pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pHeader->Info.FileLength);
  722. assert (pHeader->Info.FileLength <= pLog->llFileSize);
  723. } else {
  724. pEndOfFile = (LPVOID)((LPBYTE)pEndOfFile + pLog->llFileSize);
  725. }
  726. dwLastRecordIndex = pLog->dwLastRecordRead;
  727. }
  728. if (pdhStatus == ERROR_SUCCESS) {
  729. __try {
  730. // walk around the file until an access violation occurs or
  731. // the record is found. If an access violation occurs,
  732. // we can assume we went off the end of the file and out
  733. // of the mapped section
  734. // make sure the record has a valid header
  735. if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD ?
  736. (*(WORD *)pLog->pLastRecordRead == BINLOG_START_WORD) : TRUE) {
  737. // then it looks OK so continue
  738. while (pLog->dwLastRecordRead != dwRecordId) {
  739. // go to next record
  740. if (pLog->dwLastRecordRead != BINLOG_TYPE_ID_RECORD) {
  741. llLastFileOffset = pLog->liLastRecordOffset.QuadPart;
  742. if (pLog->dwLastRecordRead == BINLOG_HEADER_RECORD) {
  743. // if the last record was the header, then the next record
  744. // is the "first" data , not the first after the header
  745. // the function returns the new offset
  746. pLog->liLastRecordOffset.QuadPart = pHeader->Info.FirstRecordOffset;
  747. pLog->liLastRecordOffset.LowPart = SetFilePointer (pLog->hLogFileHandle,
  748. pLog->liLastRecordOffset.LowPart,
  749. &pLog->liLastRecordOffset.HighPart,
  750. FILE_BEGIN);
  751. } else {
  752. // if the current record is any record other than the header
  753. // ...then
  754. if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength > 0) {
  755. // go to the next record in the file
  756. pLog->liLastRecordOffset.QuadPart += ((PPDHI_BINARY_LOG_RECORD_HEADER)
  757. pLog->pLastRecordRead)->dwLength;
  758. // test for exceptions here
  759. if (pLog->liLastRecordOffset.QuadPart >= pLog->llFileSize) {
  760. // find out if this is a circular log or not
  761. if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
  762. // test to see if the file has wrapped
  763. if (pHeader->Info.WrapOffset != 0) {
  764. // then wrap to the beginning of the file
  765. pLog->liLastRecordOffset.QuadPart =
  766. pHeader->Info.FirstDataRecordOffset;
  767. } else {
  768. // the file is still linear so this is the end
  769. pdhStatus = PDH_END_OF_LOG_FILE;
  770. }
  771. } else {
  772. // this is the end of the file
  773. // so reset to the previous pointer
  774. pdhStatus = PDH_END_OF_LOG_FILE;
  775. }
  776. } else {
  777. // not at the physical end of the file, but if this is a circular
  778. // log, it could be the logical end of the records so test that
  779. // here
  780. if (pLog->dwLogFormat & PDH_LOG_OPT_CIRCULAR) {
  781. if (llLastFileOffset == pHeader->Info.LastRecordOffset) {
  782. // then this is the last record in the log
  783. pdhStatus = PDH_END_OF_LOG_FILE;
  784. }
  785. } else {
  786. // nothing to do since this is a normal case
  787. }
  788. } // end if / if not end of log file
  789. } else {
  790. // length is 0 so we've probably run off the end of the log somehow
  791. pdhStatus = PDH_END_OF_LOG_FILE;
  792. }
  793. // now go to that record
  794. if (pdhStatus == ERROR_SUCCESS) {
  795. pLog->liLastRecordOffset.LowPart = SetFilePointer (pLog->hLogFileHandle,
  796. pLog->liLastRecordOffset.LowPart,
  797. &pLog->liLastRecordOffset.HighPart,
  798. FILE_BEGIN);
  799. }
  800. } // end if /if not header record
  801. } else {
  802. pLog->liLastRecordOffset.QuadPart = pLog->dwRecord1Size;
  803. pLog->liLastRecordOffset.LowPart = SetFilePointer (pLog->hLogFileHandle,
  804. pLog->liLastRecordOffset.LowPart,
  805. &pLog->liLastRecordOffset.HighPart,
  806. FILE_BEGIN);
  807. }
  808. if (pdhStatus == ERROR_SUCCESS) {
  809. // the last record buffer should not be NULL and it should
  810. // be large enough to hold the header
  811. if (pLog->pLastRecordRead != NULL) {
  812. // read in the header (or entire record if the 1st record
  813. // otherwise it's a data record
  814. dwRecordSize = sizeof(PDHI_BINARY_LOG_RECORD_HEADER);
  815. if (ReadFile (pLog->hLogFileHandle,
  816. pLog->pLastRecordRead,
  817. dwRecordSize,
  818. &dwRecordReadSize,
  819. NULL)) {
  820. // then we have the record header or type record
  821. // update pointers & indices
  822. pLog->dwLastRecordRead++;
  823. pdhStatus = ERROR_SUCCESS;
  824. } else {
  825. pdhStatus = GetLastError();
  826. }
  827. } else {
  828. DebugBreak();
  829. }
  830. } else {
  831. break; // out of the while loop
  832. }
  833. }
  834. } else {
  835. pdhStatus = PDH_END_OF_LOG_FILE;
  836. }
  837. } __except (EXCEPTION_EXECUTE_HANDLER) {
  838. pLog->dwLastRecordRead = dwLastRecordIndex;
  839. }
  840. }
  841. // see if we ended up at the right place
  842. if ((pdhStatus == ERROR_SUCCESS) && (pLog->dwLastRecordRead == dwRecordId)) {
  843. if (dwLastRecordIndex != pLog->dwLastRecordRead) {
  844. // then we've move the file pointer so read the entire data record
  845. dwRecordSize = ((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength;
  846. pTmpBuffer = pLog->pLastRecordRead;
  847. pLog->pLastRecordRead = G_REALLOC(pTmpBuffer, dwRecordSize);
  848. if (pLog->pLastRecordRead != NULL) {
  849. // read in the rest of the record and append it to the header data already read in
  850. // otherwise it's a data record
  851. pLastRecord = (LPVOID)&((LPBYTE)pLog->pLastRecordRead)[sizeof(PDHI_BINARY_LOG_RECORD_HEADER)];
  852. if (ReadFile (pLog->hLogFileHandle,
  853. pLastRecord,
  854. dwRecordSize - sizeof(PDHI_BINARY_LOG_RECORD_HEADER),
  855. &dwRecordReadSize,
  856. NULL)) {
  857. // then we have the record header or type record
  858. pdhStatus = ERROR_SUCCESS;
  859. } else {
  860. pdhStatus = GetLastError();
  861. }
  862. } else {
  863. G_FREE(pTmpBuffer);
  864. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  865. }
  866. }
  867. if ((pdhStatus == ERROR_SUCCESS) && (pRecord != NULL)) {
  868. // then try to copy it
  869. // if the record ID is 1 then it's the header record so this is
  870. // a special case record that is actually a CR/LF terminated record
  871. if (dwRecordId != BINLOG_TYPE_ID_RECORD) {
  872. if (((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength <= dwMaxSize) {
  873. // then it'll fit so copy it
  874. RtlCopyMemory(pRecord, pLog->pLastRecordRead,
  875. ((PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead)->dwLength);
  876. pdhStatus = ERROR_SUCCESS;
  877. } else {
  878. // then copy as much as will fit
  879. RtlCopyMemory(pRecord, pLog->pLastRecordRead, dwMaxSize);
  880. pdhStatus = PDH_MORE_DATA;
  881. }
  882. } else {
  883. // copy the first record and zero terminate it
  884. if (pLog->dwRecord1Size <= dwMaxSize) {
  885. RtlCopyMemory(pRecord, pLog->pLastRecordRead,
  886. pLog->dwRecord1Size);
  887. // null terminate after string
  888. ((LPBYTE)pRecord)[pLog->dwRecord1Size - PdhidwRecordTerminatorLength + 1] = 0;
  889. } else {
  890. RtlCopyMemory(pRecord, pLog->pLastRecordRead, dwMaxSize);
  891. pdhStatus = PDH_MORE_DATA;
  892. }
  893. }
  894. } else {
  895. // just return current status value
  896. // no buffer was passed, but the record pointer has been
  897. // positioned
  898. }
  899. } else {
  900. // if successful so far, then return EOF
  901. if (pdhStatus == ERROR_SUCCESS) pdhStatus = PDH_END_OF_LOG_FILE;
  902. }
  903. return pdhStatus;
  904. }
  905. PDH_FUNCTION
  906. PdhiUpdateBinaryLogFileCatalog (
  907. IN PPDHI_LOG pLog
  908. )
  909. {
  910. LPVOID pTempBuffer = NULL;
  911. LPVOID pOldBuffer;
  912. DWORD dwTempBufferSize;
  913. BOOL bWildCardObjects = FALSE;
  914. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  915. // the file must be mapped for this to work
  916. if (pLog->hMappedLogFile == NULL) return PDH_LOG_FILE_OPEN_ERROR;
  917. // read the header record and enum the machine name from the entries
  918. if (pLog->dwMaxRecordSize == 0) {
  919. // no size is defined so start with 64K
  920. pLog->dwMaxRecordSize = 0x010000;
  921. }
  922. dwTempBufferSize = pLog->dwMaxRecordSize;
  923. pTempBuffer = G_ALLOC (dwTempBufferSize);
  924. if (pTempBuffer == NULL) {
  925. return PDH_MEMORY_ALLOCATION_FAILURE;
  926. }
  927. // read in the catalog record at the beginning of the file
  928. while ((pdhStatus = PdhiReadOneBinLogRecord (pLog, BINLOG_HEADER_RECORD,
  929. pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
  930. if (pdhStatus == PDH_MORE_DATA) {
  931. // read the 1st WORD to see if this is a valid record
  932. if (*(WORD *)pTempBuffer == BINLOG_START_WORD) {
  933. // it's a valid record so read the 2nd DWORD to get the
  934. // record size;
  935. dwTempBufferSize = ((DWORD *)pTempBuffer)[1];
  936. if (dwTempBufferSize < pLog->dwMaxRecordSize) {
  937. // then something is bogus so return an error
  938. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  939. break; // out of while loop
  940. } else {
  941. pLog->dwMaxRecordSize = dwTempBufferSize;
  942. }
  943. } else {
  944. // we're lost in this file
  945. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  946. break; // out of while loop
  947. }
  948. // realloc a new buffer
  949. pOldBuffer = pTempBuffer;
  950. pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize);
  951. if (pTempBuffer == NULL) {
  952. // return memory error
  953. G_FREE(pOldBuffer);
  954. assert (GetLastError() == ERROR_SUCCESS);
  955. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  956. break;
  957. }
  958. } else {
  959. // some other error was returned so
  960. // return error from read function
  961. break;
  962. }
  963. }
  964. // if that worked, then examine the catalog record and prepare to scan the file
  965. if (pdhStatus == ERROR_SUCCESS) {
  966. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  967. PPDHI_LOG_COUNTER_PATH pPath;
  968. DWORD dwBytesProcessed;
  969. LONG nItemCount = 0;
  970. LPBYTE pFirstChar;
  971. LPWSTR szThisMachineName;
  972. LPWSTR szThisObjectName;
  973. LPWSTR szThisInstanceName;
  974. WCHAR szThisMachineObjectName[MAX_PATH];
  975. LPWSTR szThisEntriesName;
  976. DWORD dwRecordLength;
  977. DWORD dwNewBuffer = 0;
  978. PLOG_BIN_CAT_ENTRY *ppCatEntryArray = NULL;
  979. PLOG_BIN_CAT_ENTRY pThisCatEntry;
  980. DWORD dwCatEntryArrayUsed = 0;
  981. DWORD dwCatEntryArrayAllocated = 0;
  982. DWORD dwThisCatEntry;
  983. DWORD *pLogIndexArray = NULL;
  984. DWORD dwLogIndexArrayUsed = 0;
  985. DWORD dwLogIndexArrayAllocated = 0;
  986. DWORD dwThisIndex;
  987. DWORD dwCurrentEntryOffset;
  988. // we can assume the record was read successfully so read in the
  989. // objects that match the machine name and detail level criteria
  990. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
  991. pPath = (PPDHI_LOG_COUNTER_PATH)
  992. ((LPBYTE)pTempBuffer + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  993. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  994. while (dwBytesProcessed < dwRecordLength) {
  995. szThisObjectName = NULL;
  996. memset (szThisMachineObjectName, 0, sizeof (szThisMachineObjectName));
  997. pFirstChar = (LPBYTE)&pPath->Buffer[0];
  998. if (pPath->lMachineNameOffset >= 0L) {
  999. // then there's a machine name in this record so get
  1000. // it's size
  1001. szThisMachineName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lMachineNameOffset);
  1002. lstrcatW (szThisMachineObjectName, szThisMachineName);
  1003. } else {
  1004. // no machine name so just add the object name
  1005. }
  1006. if (szThisObjectName >= 0) {
  1007. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  1008. lstrcatW (szThisMachineObjectName, cszBackSlash);
  1009. lstrcatW (szThisMachineObjectName, szThisObjectName);
  1010. } else {
  1011. // no object to copy
  1012. // so clear the string and skip to the next item
  1013. memset (szThisMachineObjectName, 0, sizeof (szThisMachineObjectName));
  1014. }
  1015. if (*szThisMachineObjectName != 0) {
  1016. // search the list of machine/object entries and add this if
  1017. // it's not new.
  1018. if (dwCatEntryArrayUsed > 0) {
  1019. // then there are entries in the array to examine
  1020. for (dwThisCatEntry = 0; dwThisCatEntry < dwCatEntryArrayUsed; dwThisCatEntry++) {
  1021. szThisEntriesName = (LPWSTR)((LPBYTE)(&ppCatEntryArray[dwThisCatEntry]->bcRec.CatEntry) +
  1022. ppCatEntryArray[dwThisCatEntry]->bcRec.CatEntry.dwMachineObjNameOffset);
  1023. if (lstrcmpiW (szThisEntriesName, szThisMachineObjectName) == 0) {
  1024. // match found so no need to add it
  1025. break;
  1026. }
  1027. }
  1028. } else {
  1029. dwThisCatEntry = 0;
  1030. }
  1031. if (dwThisCatEntry == dwCatEntryArrayUsed) {
  1032. dwCatEntryArrayUsed++;
  1033. // this machine/object was not found so allocate a new one
  1034. if (dwCatEntryArrayUsed > dwCatEntryArrayAllocated) {
  1035. // extend the array
  1036. dwCatEntryArrayAllocated += 256; // for starters
  1037. if (ppCatEntryArray == NULL) {
  1038. // then initialize a new one
  1039. ppCatEntryArray = G_ALLOC (
  1040. dwCatEntryArrayAllocated * sizeof(PLOG_BIN_CAT_RECORD));
  1041. } else {
  1042. // extend it
  1043. pOldBuffer = ppCatEntryArray;
  1044. ppCatEntryArray = G_REALLOC(pOldBuffer,
  1045. dwCatEntryArrayAllocated * sizeof(PLOG_BIN_CAT_RECORD));
  1046. }
  1047. if (ppCatEntryArray == NULL) {
  1048. G_FREE(pOldBuffer);
  1049. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1050. }
  1051. }
  1052. if (pdhStatus == ERROR_SUCCESS) {
  1053. assert (dwThisCatEntry == (dwCatEntryArrayUsed - 1));
  1054. // initialize the entry
  1055. // allocate the record buffer
  1056. ppCatEntryArray[dwCatEntryArrayUsed-1] = G_ALLOC(LARGE_BUFFER_SIZE);
  1057. if (ppCatEntryArray[dwCatEntryArrayUsed-1] == NULL) {
  1058. assert (GetLastError() == ERROR_SUCCESS);
  1059. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1060. break; // break out of loop since we can't allocate any memory
  1061. } else {
  1062. pThisCatEntry = ppCatEntryArray[dwCatEntryArrayUsed-1];
  1063. pThisCatEntry->dwEntrySize = (DWORD)G_SIZE(pThisCatEntry);
  1064. // initialize the fields of the new structure
  1065. // start with the record header
  1066. pThisCatEntry->bcRec.RecHeader.dwType = BINLOG_TYPE_CATALOG_ITEM;
  1067. // this field will be filled in when the list is completed
  1068. pThisCatEntry->bcRec.RecHeader.dwLength =0;
  1069. // now initialize the catalog entry record
  1070. // offsets are from the start address of the catalog entry record
  1071. pThisCatEntry->bcRec.CatEntry.dwMachineObjNameOffset =
  1072. sizeof (PDHI_LOG_CAT_ENTRY);
  1073. assert ((LONG)pThisCatEntry->bcRec.CatEntry.dwMachineObjNameOffset ==
  1074. (LONG)((LPBYTE)&pThisCatEntry->bcRec.dwEntryRecBuff[0] -
  1075. (LPBYTE)&pThisCatEntry->bcRec.CatEntry));
  1076. // now copy the machine/object string to the buffer
  1077. lstrcpyW ((LPWSTR)((LPBYTE)&pThisCatEntry->bcRec.CatEntry +
  1078. pThisCatEntry->bcRec.CatEntry.dwMachineObjNameOffset),
  1079. szThisMachineObjectName);
  1080. // the instance string list will follow the machine name
  1081. pThisCatEntry->bcRec.CatEntry.dwInstanceStringOffset =
  1082. pThisCatEntry->bcRec.CatEntry.dwMachineObjNameOffset +
  1083. ((lstrlenW (szThisMachineObjectName) + 1) * sizeof(WCHAR));
  1084. // finish off by initializing the offsets
  1085. // this offset is from the start of the Cat Entry NOT the
  1086. // cat data record.
  1087. pThisCatEntry->dwOffsetToNextInstance =
  1088. // offset to cat entry structure
  1089. (DWORD)((LPBYTE)(&pThisCatEntry->bcRec.CatEntry) -
  1090. (LPBYTE)(pThisCatEntry));
  1091. // offset from there to the instance string list
  1092. pThisCatEntry->dwOffsetToNextInstance +=
  1093. pThisCatEntry->bcRec.CatEntry.dwInstanceStringOffset;
  1094. assert (pThisCatEntry->dwOffsetToNextInstance <
  1095. pThisCatEntry->dwEntrySize);
  1096. }
  1097. } else {
  1098. // error encountered so break from loop
  1099. break;
  1100. }
  1101. } else {
  1102. // already in the list so go continue
  1103. }
  1104. // pThisCatEntry = pointer to the matching structure so
  1105. // add it to the index of counter path items if it has
  1106. // a wild card instance
  1107. dwLogIndexArrayUsed++;
  1108. if (dwLogIndexArrayUsed > dwLogIndexArrayAllocated) {
  1109. // extend the array
  1110. dwLogIndexArrayAllocated += 256; // for starters
  1111. if (pLogIndexArray == NULL) {
  1112. // then initialize a new one
  1113. pLogIndexArray = G_ALLOC (
  1114. dwLogIndexArrayAllocated * sizeof(DWORD));
  1115. } else {
  1116. // extend it
  1117. pOldBuffer = pLogIndexArray;
  1118. pLogIndexArray = G_REALLOC (pOldBuffer,
  1119. dwLogIndexArrayAllocated * sizeof(DWORD));
  1120. if (pLogIndexArray == NULL) {
  1121. G_FREE(pOldBuffer);
  1122. }
  1123. }
  1124. if (pLogIndexArray == NULL) {
  1125. assert (GetLastError() == ERROR_SUCCESS);
  1126. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1127. break; // break out of loop since we can't allocate any memory
  1128. }
  1129. }
  1130. if (pPath->lInstanceOffset >= 0) {
  1131. szThisInstanceName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lInstanceOffset);
  1132. if (*szThisInstanceName == SPLAT_L) {
  1133. // then this is a wild card instance so save it
  1134. pLogIndexArray[dwLogIndexArrayUsed-1] = dwThisCatEntry;
  1135. bWildCardObjects = TRUE; // there's at least 1 item to scan from the file
  1136. } else {
  1137. // this is not a wildcard instance so no instance list
  1138. // entry is necessary
  1139. pLogIndexArray[dwLogIndexArrayUsed-1] = (DWORD)-1;
  1140. }
  1141. } else {
  1142. // this object doesn't have instances
  1143. szThisInstanceName = NULL;
  1144. pLogIndexArray[dwLogIndexArrayUsed-1] = (DWORD)-1;
  1145. }
  1146. } else {
  1147. // no machine or object name to look up
  1148. }
  1149. // get next path entry from log file record
  1150. dwBytesProcessed += pPath->dwLength;
  1151. pPath = (PPDHI_LOG_COUNTER_PATH)
  1152. ((LPBYTE)pPath + pPath->dwLength);
  1153. }
  1154. // If everything is OK so far, fill in the list(s) of instances
  1155. if ((pdhStatus == ERROR_SUCCESS) && (ppCatEntryArray != NULL) && (bWildCardObjects)) {
  1156. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  1157. PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
  1158. PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
  1159. PPDHI_RAW_COUNTER_ITEM pDataItem;
  1160. DWORD dwThisRecordIndex;
  1161. DWORD dwDataItemIndex;
  1162. DWORD dwSize;
  1163. DWORD dwLowSize, dwHighSize;
  1164. LONGLONG llEndOfFileOffset;
  1165. DWORD dwLowPos, dwHighPos;
  1166. DWORD dwBytesWritten;
  1167. // run through the log file and add the instances to the appropriate list
  1168. // look up individual instances in log...
  1169. // read records from file and store instances
  1170. dwThisRecordIndex = BINLOG_FIRST_DATA_RECORD;
  1171. // this call just moves the record pointer
  1172. pdhStatus = PdhiReadOneBinLogRecord (
  1173. pLog, dwThisRecordIndex, NULL, 0);
  1174. while (pdhStatus == ERROR_SUCCESS) {
  1175. pThisMasterRecord =
  1176. (PPDHI_BINARY_LOG_RECORD_HEADER)
  1177. pLog->pLastRecordRead;
  1178. // make sure we haven't left the file
  1179. assert (pThisMasterRecord != NULL);
  1180. assert ((LPBYTE)pThisMasterRecord >
  1181. (LPBYTE)pLog->lpMappedFileBase);
  1182. assert ((LPBYTE)pThisMasterRecord <
  1183. ((LPBYTE)pLog->lpMappedFileBase +
  1184. pLog->llFileSize));
  1185. // examine each entry in the record
  1186. // sub records start with index 1
  1187. for (dwThisIndex = 1; dwThisIndex <= dwLogIndexArrayUsed; dwThisIndex++) {
  1188. pThisSubRecord = PdhiGetSubRecord (
  1189. pThisMasterRecord, dwThisIndex);
  1190. assert (pThisSubRecord != NULL); // this would imply a bad log file
  1191. // only do multi entries
  1192. if ((pThisSubRecord != NULL) &&
  1193. (pThisSubRecord->dwType == BINLOG_TYPE_DATA_MULTI)) {
  1194. // if this is a multi-counter, then this should have an entry
  1195. assert (pLogIndexArray[dwThisIndex] != (DWORD)-1);
  1196. // the array index is 0 based while the records are 1 based
  1197. // so adjust index value here
  1198. pThisCatEntry = ppCatEntryArray[pLogIndexArray[dwThisIndex-1]];
  1199. assert (pThisCatEntry != NULL); // make sure this is a valid entry
  1200. pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)
  1201. ((LPBYTE)pThisSubRecord +
  1202. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  1203. // walk down list of entries and add them to the
  1204. // list of instances (these should already
  1205. // be assembled in parent/instance format)
  1206. for (dwDataItemIndex = 0;
  1207. dwDataItemIndex < pDataBlock->dwItemCount;
  1208. dwDataItemIndex++) {
  1209. pDataItem = &pDataBlock->pItemArray[dwDataItemIndex];
  1210. szThisInstanceName = (LPWSTR)
  1211. (((LPBYTE) pDataBlock) + pDataItem->szName);
  1212. dwNewBuffer = lstrlenW (szThisInstanceName) + 1;
  1213. dwNewBuffer *= sizeof (WCHAR);
  1214. if ((pThisCatEntry->dwOffsetToNextInstance + dwNewBuffer) >=
  1215. pThisCatEntry->dwEntrySize) {
  1216. // grow the buffer
  1217. dwSize = pThisCatEntry->dwEntrySize + LARGE_BUFFER_SIZE;
  1218. pOldBuffer = pThisCatEntry;
  1219. pThisCatEntry = G_REALLOC (pOldBuffer, dwSize);
  1220. if (pThisCatEntry != NULL) {
  1221. // update array
  1222. ppCatEntryArray[pLogIndexArray[dwThisIndex-1]] = pThisCatEntry;
  1223. pThisCatEntry->dwEntrySize = dwSize;
  1224. } else {
  1225. // skip & try the next one
  1226. G_FREE(pOldBuffer);
  1227. continue;
  1228. }
  1229. }
  1230. // copy string to the buffer
  1231. dwNewBuffer = AddUniqueWideStringToMultiSz (
  1232. (LPVOID)((LPBYTE)&pThisCatEntry->bcRec.CatEntry + pThisCatEntry->bcRec.CatEntry.dwInstanceStringOffset),
  1233. szThisInstanceName,
  1234. TRUE);
  1235. // if the string was added to the list, then
  1236. // dwNewBuffer is the size of the resulting MSZ
  1237. // in characters not including the double NULL
  1238. // terminating the MSZ
  1239. // if no string was added, then it is 0
  1240. if (dwNewBuffer > 0) {
  1241. // string was added so update size used.
  1242. // this is the new size of the MSZ instance list
  1243. pThisCatEntry->dwOffsetToNextInstance = dwNewBuffer * sizeof (WCHAR);
  1244. // + the offset of the istance list from the start of the Cat entry
  1245. pThisCatEntry->dwOffsetToNextInstance +=
  1246. pThisCatEntry->bcRec.CatEntry.dwInstanceStringOffset;
  1247. // + the start of the cat entry from the main structure start
  1248. pThisCatEntry->dwOffsetToNextInstance +=
  1249. (DWORD)((DWORD_PTR)&pThisCatEntry->bcRec.CatEntry -
  1250. (DWORD_PTR)pThisCatEntry);
  1251. nItemCount++;
  1252. } else {
  1253. // nothing added so nothing to do
  1254. }
  1255. } // end for each istance entry in the array counter
  1256. } else {
  1257. // this is not an array counter
  1258. }
  1259. } // end for each item in this record
  1260. // go to next record in log file
  1261. pdhStatus = PdhiReadOneBinLogRecord (
  1262. pLog, ++dwThisRecordIndex, NULL, 0);
  1263. } // end while not end of file
  1264. if (pdhStatus == PDH_END_OF_LOG_FILE) {
  1265. // this is good so fix the status
  1266. pdhStatus = ERROR_SUCCESS;
  1267. }
  1268. // update the length fields of the various records
  1269. dwCurrentEntryOffset = 0;
  1270. for (dwThisIndex = 0; dwThisIndex < dwCatEntryArrayUsed; dwThisIndex++) {
  1271. pThisCatEntry = ppCatEntryArray[dwThisIndex];
  1272. // update the record size of the overall record
  1273. pThisCatEntry->bcRec.RecHeader.dwLength =
  1274. (pThisCatEntry->dwOffsetToNextInstance + sizeof(WCHAR)) // to include MSZ term null
  1275. // now subtract offset to record struct in
  1276. // containing structure
  1277. - (DWORD)((DWORD_PTR)(&pThisCatEntry->bcRec) -
  1278. (DWORD_PTR)(pThisCatEntry));
  1279. // update the size of this catalog entry
  1280. pThisCatEntry->bcRec.CatEntry.dwEntrySize =
  1281. (pThisCatEntry->dwOffsetToNextInstance + sizeof(WCHAR)) // to include MSZ term null
  1282. // now subtract offset to record struct in
  1283. // containing structure
  1284. - (DWORD)((DWORD_PTR)(&pThisCatEntry->bcRec.CatEntry) -
  1285. (DWORD_PTR)(pThisCatEntry));
  1286. // update the size of the MSZ instance list string
  1287. pThisCatEntry->bcRec.CatEntry.dwStringSize =
  1288. // size of the entry...
  1289. pThisCatEntry->bcRec.CatEntry.dwEntrySize
  1290. // - the offset to the start of the string
  1291. - pThisCatEntry->bcRec.CatEntry.dwInstanceStringOffset;
  1292. // only entries with strings will be written to the
  1293. // file so only they will have offsets
  1294. if (pThisCatEntry->bcRec.CatEntry.dwStringSize > sizeof(DWORD)) {
  1295. pThisCatEntry->dwEntryOffset = dwCurrentEntryOffset;
  1296. dwCurrentEntryOffset += pThisCatEntry->bcRec.RecHeader.dwLength;
  1297. } else {
  1298. pThisCatEntry->dwEntryOffset = 0;
  1299. }
  1300. #if _DBG
  1301. swprintf (szThisMachineObjectName, (LPCWSTR)L"\nEntry %d: Offset: %d, Rec Len: %d String Len: %d",
  1302. dwThisIndex,
  1303. pThisCatEntry->dwEntryOffset,
  1304. pThisCatEntry->bcRec.RecHeader.dwLength,
  1305. pThisCatEntry->bcRec.CatEntry.dwStringSize );
  1306. OutputDebugStringW (szThisMachineObjectName);
  1307. #endif
  1308. }
  1309. #if _DBG
  1310. swprintf (szThisMachineObjectName, (LPCWSTR)L"\nCatalog Size: %d",
  1311. dwCurrentEntryOffset);
  1312. OutputDebugStringW (szThisMachineObjectName);
  1313. #endif
  1314. // see if the end of file is defined as something other
  1315. // then the physical end of the file (e.g. the last record
  1316. // in a circular log file
  1317. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)
  1318. ((LPBYTE)(pLog->lpMappedFileBase) + pLog->dwRecord1Size);
  1319. assert (*(WORD *)&(pHeader->RecHeader.dwType) == BINLOG_START_WORD);
  1320. // use the greater of Wrap offset or Next Offset
  1321. llEndOfFileOffset = pHeader->Info.WrapOffset;
  1322. if (pHeader->Info.NextRecordOffset > llEndOfFileOffset) {
  1323. llEndOfFileOffset = pHeader->Info.NextRecordOffset;
  1324. }
  1325. // if neither is defined, then use the physical end of file
  1326. if (llEndOfFileOffset == 0) {
  1327. dwLowSize = GetFileSize (pLog->hLogFileHandle, &dwHighSize);
  1328. assert (dwLowSize != 0xFFFFFFFF);
  1329. } else {
  1330. dwLowSize = LODWORD(llEndOfFileOffset);
  1331. dwHighSize = HIDWORD(llEndOfFileOffset);
  1332. }
  1333. // now get ready to update the log file.
  1334. // 1st unmap the view of the file so we can update it
  1335. if (!UnmapViewOfFile(pLog->lpMappedFileBase)) {
  1336. pdhStatus = GetLastError();
  1337. } else {
  1338. pLog->lpMappedFileBase = NULL;
  1339. pLog->pLastRecordRead = NULL;
  1340. CloseHandle (pLog->hMappedLogFile);
  1341. pLog->hMappedLogFile = NULL;
  1342. }
  1343. assert (pdhStatus == ERROR_SUCCESS);
  1344. // lock the file while we fiddle with it
  1345. if (!LockFile (pLog->hLogFileHandle,0,0,dwLowSize, dwHighSize)) {
  1346. pdhStatus = GetLastError ();
  1347. }
  1348. assert (pdhStatus == ERROR_SUCCESS);
  1349. // 3rd move to the end of the file
  1350. dwLowPos = dwLowSize;
  1351. dwHighPos = dwHighSize;
  1352. dwLowPos = SetFilePointer (pLog->hLogFileHandle, dwLowPos, (LONG *)&dwHighPos, FILE_BEGIN);
  1353. if (dwLowPos == 0xFFFFFFFF) {
  1354. pdhStatus = GetLastError ();
  1355. }
  1356. assert (pdhStatus == ERROR_SUCCESS);
  1357. assert (dwLowPos == dwLowSize);
  1358. assert (dwHighPos == dwHighSize);
  1359. // 4th write the new catalog records
  1360. for (dwThisIndex = 0; dwThisIndex < dwCatEntryArrayUsed; dwThisIndex++) {
  1361. pThisCatEntry = ppCatEntryArray[dwThisIndex];
  1362. if (pThisCatEntry->bcRec.CatEntry.dwStringSize > sizeof (DWORD)) {
  1363. // then this entry has something to write
  1364. pdhStatus = PdhiWriteOneBinaryLogRecord (
  1365. pLog,
  1366. (LPCVOID)&pThisCatEntry->bcRec,
  1367. pThisCatEntry->bcRec.RecHeader.dwLength,
  1368. &dwBytesWritten,
  1369. 0);
  1370. if (pdhStatus == ERROR_SUCCESS) {
  1371. // operation succeeded
  1372. assert (dwBytesWritten == pThisCatEntry->bcRec.RecHeader.dwLength);
  1373. }
  1374. } else {
  1375. // this record does not need to be written
  1376. }
  1377. } // end for each machine/object in this log
  1378. // truncate the file here since this must be at the
  1379. // end
  1380. if (!SetEndOfFile (pLog->hLogFileHandle)) {
  1381. pdhStatus = GetLastError();
  1382. }
  1383. // 5th re-map the file to include the new catalog sections
  1384. pdhStatus = PdhiOpenUpdateBinaryLog (pLog);
  1385. assert (pdhStatus == ERROR_SUCCESS);
  1386. // 6th update the catalog entries in the header
  1387. pdhStatus = PdhiReadOneBinLogRecord (pLog, BINLOG_HEADER_RECORD,
  1388. pTempBuffer, dwTempBufferSize);
  1389. assert (pdhStatus == ERROR_SUCCESS);
  1390. // we can assume the record was read successfully so read in the
  1391. // objects that match the machine name and detail level criteria
  1392. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
  1393. // the following will update the temp buffer, when
  1394. // everything is finished, we'll copy this back to the
  1395. // mapped file.
  1396. //
  1397. // enter the location of the Catalog
  1398. ((PPDHI_BINARY_LOG_HEADER_RECORD)pTempBuffer)->Info.CatalogOffset =
  1399. (LONGLONG)(dwLowPos + (dwHighPos << 32));
  1400. // update the catalog time
  1401. GetSystemTimeAsFileTime (
  1402. (FILETIME *)&((PPDHI_BINARY_LOG_HEADER_RECORD)pTempBuffer)->Info.CatalogDate);
  1403. // update the log file update time
  1404. ((PPDHI_BINARY_LOG_HEADER_RECORD)pTempBuffer)->Info.LastUpdateTime =
  1405. ((PPDHI_BINARY_LOG_HEADER_RECORD)pTempBuffer)->Info.CatalogDate;
  1406. // go through each counter path item and insert the catalog offset
  1407. // as appropriate (i.e. only to wild card path entries
  1408. pPath = (PPDHI_LOG_COUNTER_PATH)
  1409. ((LPBYTE)pTempBuffer + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  1410. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  1411. dwThisIndex = 0; // this counter entry index
  1412. while (dwBytesProcessed < dwRecordLength) {
  1413. // get next path entry from log file record
  1414. if (pLogIndexArray[dwThisIndex] != (DWORD)-1) {
  1415. // make sure we're not going to step on anything
  1416. assert (pPath->lMachineNameOffset > 0);
  1417. // then this item has an extended catalog entry
  1418. // so load the offset into the catalog here
  1419. *((LPDWORD)&pPath->Buffer[0]) =
  1420. ppCatEntryArray[pLogIndexArray[dwThisIndex]]->dwEntryOffset;
  1421. } else {
  1422. // skip this and go to the next one
  1423. }
  1424. dwThisIndex++;
  1425. dwBytesProcessed += pPath->dwLength;
  1426. pPath = (PPDHI_LOG_COUNTER_PATH)
  1427. ((LPBYTE)pPath + pPath->dwLength);
  1428. }
  1429. assert (dwThisIndex == dwLogIndexArrayUsed);
  1430. // write the changes to the file
  1431. RtlCopyMemory(pLog->pLastRecordRead, pTempBuffer, dwRecordLength);
  1432. // write changes to disk
  1433. if (!FlushViewOfFile (pLog->lpMappedFileBase, 0)) {
  1434. pdhStatus = GetLastError();
  1435. }
  1436. assert (pdhStatus == ERROR_SUCCESS);
  1437. // unlock the file
  1438. if (!UnlockFile (pLog->hLogFileHandle, 0, 0, dwLowSize, dwHighSize)) {
  1439. pdhStatus = GetLastError();
  1440. }
  1441. // done
  1442. // check the index entries...
  1443. for (dwThisIndex = 0; dwThisIndex < dwCatEntryArrayUsed; dwThisIndex++) {
  1444. pThisCatEntry = ppCatEntryArray[dwThisIndex];
  1445. // free the cat entry
  1446. G_FREE (pThisCatEntry);
  1447. ppCatEntryArray[dwThisIndex] = NULL;
  1448. }
  1449. } else {
  1450. // then there's nothing to list
  1451. }
  1452. if (pLogIndexArray != NULL) G_FREE(pLogIndexArray);
  1453. if (ppCatEntryArray != NULL) G_FREE(ppCatEntryArray);
  1454. }
  1455. if (pTempBuffer != NULL) G_FREE (pTempBuffer);
  1456. return pdhStatus;
  1457. }
  1458. PDH_FUNCTION
  1459. PdhiGetBinaryLogCounterInfo (
  1460. IN PPDHI_LOG pLog,
  1461. IN PPDHI_COUNTER pCounter
  1462. )
  1463. {
  1464. PDH_STATUS pdhStatus;
  1465. DWORD dwIndex;
  1466. DWORD dwPrevious = pCounter->dwIndex;
  1467. PPDHI_COUNTER_PATH pTempPath = NULL;
  1468. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  1469. PPDHI_LOG_COUNTER_PATH pPath;
  1470. DWORD dwBufferSize;
  1471. DWORD dwRecordLength;
  1472. DWORD dwBytesProcessed;
  1473. LPBYTE pFirstChar;
  1474. LPWSTR szThisMachineName;
  1475. LPWSTR szThisObjectName;
  1476. LPWSTR szThisCounterName;
  1477. LPWSTR szThisInstanceName;
  1478. LPWSTR szThisParentName;
  1479. BOOL bCheckThisObject = FALSE;
  1480. DWORD dwTmpIndex;
  1481. // crack the path in to components
  1482. pTempPath = G_ALLOC (LARGE_BUFFER_SIZE);
  1483. if (pTempPath == NULL) {
  1484. return PDH_MEMORY_ALLOCATION_FAILURE;
  1485. }
  1486. dwBufferSize = (DWORD)G_SIZE(pTempPath);
  1487. if (ParseFullPathNameW (pCounter->szFullName, &dwBufferSize, pTempPath, FALSE)) {
  1488. // read the header record to find the matching entry
  1489. pdhStatus = PdhiReadOneBinLogRecord (
  1490. pLog,
  1491. BINLOG_HEADER_RECORD,
  1492. NULL, 0);
  1493. if (pdhStatus == ERROR_SUCCESS) {
  1494. pThisMasterRecord =
  1495. (PPDHI_BINARY_LOG_RECORD_HEADER) pLog->pLastRecordRead;
  1496. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pThisMasterRecord)->dwLength;
  1497. pPath = (PPDHI_LOG_COUNTER_PATH)
  1498. ((LPBYTE)pThisMasterRecord + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  1499. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  1500. dwIndex = 0;
  1501. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  1502. dwTmpIndex = 0;
  1503. while (dwBytesProcessed < dwRecordLength) {
  1504. // go through catalog to find a match
  1505. dwIndex++;
  1506. pFirstChar = (LPBYTE)&pPath->Buffer[0];
  1507. if (dwPrevious != 0 && dwPrevious >= dwIndex) {
  1508. bCheckThisObject = FALSE;
  1509. }
  1510. else if (pPath->lMachineNameOffset >= 0L) {
  1511. // then there's a machine name in this record so get
  1512. // it's size
  1513. szThisMachineName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lMachineNameOffset);
  1514. // if this is for the desired machine, then select the object
  1515. if (lstrcmpiW(szThisMachineName, pTempPath->szMachineName) == 0) {
  1516. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  1517. if (lstrcmpiW(szThisObjectName, pTempPath->szObjectName) == 0) {
  1518. // then this is the object to look up
  1519. bCheckThisObject = TRUE;
  1520. } else {
  1521. // not this object
  1522. szThisObjectName = NULL;
  1523. }
  1524. } else {
  1525. // this machine isn't selected
  1526. }
  1527. } else {
  1528. // there's no machine specified so for this counter so list it by default
  1529. if (pPath->lObjectNameOffset >= 0) {
  1530. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  1531. if (lstrcmpiW(szThisObjectName,pTempPath->szObjectName) == 0) {
  1532. // then this is the object to look up
  1533. bCheckThisObject = TRUE;
  1534. } else {
  1535. // not this object
  1536. szThisObjectName = NULL;
  1537. }
  1538. } else {
  1539. // no object to copy
  1540. szThisObjectName = NULL;
  1541. }
  1542. }
  1543. if (bCheckThisObject) {
  1544. szThisCounterName = (LPWSTR)((LPBYTE)pFirstChar +
  1545. pPath->lCounterOffset);
  1546. if (* szThisCounterName == SPLAT_L) {
  1547. if (pPath->dwFlags & PDHIC_COUNTER_OBJECT) {
  1548. pdhStatus = PdhiGetWmiLogCounterInfo(pLog, pCounter);
  1549. pCounter->dwIndex = dwIndex;
  1550. break;
  1551. }
  1552. else {
  1553. // pPath->dwFlags & PDHIC_COUNTER_BLOCK
  1554. // this is logged counter object. Since all couter
  1555. // objects from the same machine are from the same
  1556. // datablock, dwIndex might be incorrect
  1557. //
  1558. DWORD dwTemp = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  1559. PPDHI_LOG_COUNTER_PATH pLPath = (PPDHI_LOG_COUNTER_PATH)
  1560. ((LPBYTE) pThisMasterRecord + dwTemp);
  1561. DWORD dwLIndex = 0;
  1562. LPBYTE pLChar;
  1563. LPWSTR szMachine;
  1564. pdhStatus = PdhiGetWmiLogCounterInfo(pLog, pCounter);
  1565. while (dwTemp < dwRecordLength) {
  1566. dwLIndex ++;
  1567. if (dwPrevious == 0 || dwPrevious < dwLIndex) {
  1568. pLChar = (LPBYTE)&pLPath->Buffer[0];
  1569. if (pLPath->lMachineNameOffset >= 0L) {
  1570. szMachine = (LPWSTR) ((LPBYTE)pLChar
  1571. + pLPath->lMachineNameOffset);
  1572. if (lstrcmpiW(szMachine,
  1573. pTempPath->szMachineName) == 0) {
  1574. if (pLPath->dwFlags &
  1575. PDHIC_COUNTER_BLOCK) {
  1576. break;
  1577. }
  1578. }
  1579. }
  1580. else if (pLPath->dwFlags & PDHIC_COUNTER_BLOCK) {
  1581. break;
  1582. }
  1583. }
  1584. dwTemp += pLPath->dwLength;
  1585. pLPath = (PPDHI_LOG_COUNTER_PATH)
  1586. ((LPBYTE) pThisMasterRecord + dwTemp);
  1587. }
  1588. if (dwTemp >= dwRecordLength) {
  1589. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  1590. }
  1591. else {
  1592. pCounter->dwIndex = dwLIndex;
  1593. }
  1594. }
  1595. }
  1596. else if (lstrcmpiW(szThisCounterName, pTempPath->szCounterName) == 0) {
  1597. // check instance name
  1598. // get the instance name from this counter and add it to the list
  1599. if (pPath->lInstanceOffset >= 0) {
  1600. szThisInstanceName = (LPWSTR)((LPBYTE)pFirstChar +
  1601. pPath->lInstanceOffset);
  1602. if (*szThisInstanceName != SPLAT_L) {
  1603. if (pPath->lParentOffset >= 0) {
  1604. szThisParentName = (LPWSTR)((LPBYTE)pFirstChar +
  1605. pPath->lParentOffset);
  1606. if (lstrcmpiW(szThisParentName, pTempPath->szParentName) != 0) {
  1607. // wrong parent
  1608. bCheckThisObject = FALSE;
  1609. }
  1610. }
  1611. if (lstrcmpiW(szThisInstanceName, pTempPath->szInstanceName) != 0) {
  1612. // wrong instance
  1613. bCheckThisObject = FALSE;
  1614. }
  1615. if (pTempPath->dwIndex > 0) {
  1616. if (pPath->dwIndex == pTempPath->dwIndex) {
  1617. bCheckThisObject = TRUE;
  1618. }
  1619. else if (pPath->dwIndex == 0) {
  1620. if (dwTmpIndex == pTempPath->dwIndex) {
  1621. bCheckThisObject = TRUE;
  1622. }
  1623. else {
  1624. dwTmpIndex ++;
  1625. bCheckThisObject = FALSE;
  1626. }
  1627. }
  1628. else {
  1629. // wrong index
  1630. bCheckThisObject = FALSE;
  1631. }
  1632. }
  1633. else if ( pPath->dwIndex != 0
  1634. && LOWORD(pLog->dwLogFormat) == PDH_LOG_TYPE_BINARY) {
  1635. bCheckThisObject = FALSE;
  1636. }
  1637. } else {
  1638. // this is a wild card spec
  1639. // so assume it's valid since that's
  1640. // faster than reading the file each time.
  1641. // if the instance DOESN't exist in this
  1642. // file then the appropriate status will
  1643. // be returned in each query.
  1644. }
  1645. } else {
  1646. // there is no instance name to compare
  1647. // so assume it's OK
  1648. }
  1649. if (bCheckThisObject) {
  1650. // fill in the data and return
  1651. // this data is NOT used by the log file reader
  1652. pCounter->plCounterInfo.dwObjectId = 0;
  1653. pCounter->plCounterInfo.lInstanceId = 0;
  1654. if (pPath->lInstanceOffset >= 0) {
  1655. pCounter->plCounterInfo.szInstanceName =
  1656. pCounter->pCounterPath->szInstanceName;
  1657. pCounter->plCounterInfo.dwParentObjectId = 0;
  1658. pCounter->plCounterInfo.szParentInstanceName =
  1659. pCounter->pCounterPath->szParentName;
  1660. } else {
  1661. pCounter->plCounterInfo.szInstanceName = NULL;
  1662. pCounter->plCounterInfo.dwParentObjectId = 0;
  1663. pCounter->plCounterInfo.szParentInstanceName = NULL;
  1664. }
  1665. //define as multi instance if necessary
  1666. // if the user is passing in a "*" character
  1667. if (pCounter->plCounterInfo.szInstanceName != NULL) {
  1668. if (*pCounter->plCounterInfo.szInstanceName == SPLAT_L) {
  1669. pCounter->dwFlags |= PDHIC_MULTI_INSTANCE;
  1670. }
  1671. }
  1672. // this data is used by the log file readers
  1673. pCounter->plCounterInfo.dwCounterId = dwIndex; // entry in log
  1674. pCounter->plCounterInfo.dwCounterType = pPath->dwCounterType;
  1675. pCounter->plCounterInfo.dwCounterSize =
  1676. pPath->dwCounterType & PERF_SIZE_LARGE ?
  1677. sizeof (LONGLONG) : sizeof(DWORD);
  1678. pCounter->plCounterInfo.lDefaultScale = pPath->lDefaultScale;
  1679. pCounter->TimeBase = pPath->llTimeBase;
  1680. pCounter->dwIndex = dwIndex;
  1681. pdhStatus = ERROR_SUCCESS;
  1682. break;
  1683. }
  1684. }
  1685. } else {
  1686. // we aren't interested in this so just ignore it
  1687. }
  1688. // get next path entry from log file record
  1689. dwBytesProcessed += pPath->dwLength;
  1690. pPath = (PPDHI_LOG_COUNTER_PATH)
  1691. ((LPBYTE)pPath + pPath->dwLength);
  1692. } // end while searching the catalog entries
  1693. } else {
  1694. // unable to find desired record so return status
  1695. }
  1696. } else {
  1697. // unable to read the path
  1698. pdhStatus = PDH_INVALID_PATH;
  1699. }
  1700. if (pTempPath != NULL) G_FREE (pTempPath);
  1701. return pdhStatus;
  1702. }
  1703. PDH_FUNCTION
  1704. PdhiOpenInputBinaryLog (
  1705. IN PPDHI_LOG pLog
  1706. )
  1707. {
  1708. PDH_STATUS pdhStatus;
  1709. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  1710. pLog->StreamFile = (FILE *)((DWORD_PTR)(-1));
  1711. // map file header as a memory array for reading
  1712. assert (pLog->hMappedLogFile != NULL); // should be open!
  1713. if ((pLog->hMappedLogFile != NULL) && (pLog->lpMappedFileBase != NULL)) {
  1714. // save size of binary log record header
  1715. pLog->dwRecord1Size = dwFileHeaderLength + // ID characters
  1716. 2 + // quotations
  1717. PdhidwRecordTerminatorLength; // CR/LF terminator
  1718. pLog->dwRecord1Size = QWORD_MULTIPLE(pLog->dwRecord1Size);
  1719. // read the header and get the option flags
  1720. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)
  1721. ((LPBYTE)(pLog->lpMappedFileBase) + pLog->dwRecord1Size);
  1722. assert (*(WORD *)&(pHeader->RecHeader.dwType) == BINLOG_START_WORD);
  1723. pLog->dwLogFormat |= pHeader->Info.dwFlags;
  1724. pdhStatus = ERROR_SUCCESS;
  1725. } else {
  1726. // return PDH Error
  1727. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  1728. }
  1729. pdhStatus = ERROR_SUCCESS;
  1730. return pdhStatus;
  1731. }
  1732. PDH_FUNCTION
  1733. PdhiOpenUpdateBinaryLog (
  1734. IN PPDHI_LOG pLog
  1735. )
  1736. {
  1737. PDH_STATUS pdhStatus;
  1738. LONG lWin32Status;
  1739. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  1740. pLog->StreamFile = (FILE *)((DWORD_PTR)(-1));
  1741. // map file header as a memory array for reading
  1742. assert (pLog->hMappedLogFile != NULL); // should be open!
  1743. if ((pLog->hMappedLogFile != NULL) && (pLog->lpMappedFileBase != NULL)) {
  1744. // save size of binary log record header
  1745. pLog->dwRecord1Size = dwFileHeaderLength + // ID characters
  1746. 2 + // quotations
  1747. PdhidwRecordTerminatorLength; // CR/LF terminator
  1748. pLog->dwRecord1Size = QWORD_MULTIPLE(pLog->dwRecord1Size);
  1749. // read the header and get the option flags
  1750. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)
  1751. ((LPBYTE)(pLog->lpMappedFileBase) + pLog->dwRecord1Size);
  1752. assert (*(WORD *)&(pHeader->RecHeader.dwType) == BINLOG_START_WORD);
  1753. pLog->dwLogFormat |= pHeader->Info.dwFlags;
  1754. pdhStatus = ERROR_SUCCESS;
  1755. } else {
  1756. // return PDH Error
  1757. lWin32Status = GetLastError();
  1758. pdhStatus = PDH_LOG_FILE_OPEN_ERROR;
  1759. }
  1760. pdhStatus = ERROR_SUCCESS;
  1761. return pdhStatus;
  1762. }
  1763. PDH_FUNCTION
  1764. PdhiOpenOutputBinaryLog (
  1765. IN PPDHI_LOG pLog
  1766. )
  1767. {
  1768. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1769. if (pLog->llMaxSize > 0) {
  1770. // this is a circular or limited linear log file so:
  1771. // 1) allocate a file of the desired size,
  1772. pLog->hMappedLogFile = CreateFileMappingW (
  1773. pLog->hLogFileHandle,
  1774. NULL,
  1775. PAGE_READWRITE,
  1776. HIDWORD(pLog->llMaxSize),
  1777. LODWORD(pLog->llMaxSize),
  1778. NULL);
  1779. if (pLog->hMappedLogFile != NULL) {
  1780. // 2) map it as a memory section
  1781. pLog->lpMappedFileBase = MapViewOfFile (
  1782. pLog->hMappedLogFile,
  1783. FILE_MAP_WRITE, 0, 0,
  1784. LODWORD(pLog->llMaxSize));
  1785. if (pLog->lpMappedFileBase == NULL) {
  1786. // close the file mapping and return error
  1787. pdhStatus = GetLastError();
  1788. CloseHandle (pLog->hMappedLogFile);
  1789. pLog->hMappedLogFile = NULL;
  1790. }
  1791. } else {
  1792. pdhStatus = GetLastError();
  1793. pLog->hMappedLogFile = NULL;
  1794. }
  1795. } else {
  1796. // this is just a sequential access file where each record will
  1797. // be appended to the last one
  1798. pLog->StreamFile = (FILE *)((DWORD_PTR)(-1));
  1799. pdhStatus = ERROR_SUCCESS;
  1800. }
  1801. return pdhStatus;
  1802. }
  1803. PDH_FUNCTION
  1804. PdhiCloseBinaryLog (
  1805. IN PPDHI_LOG pLog,
  1806. IN DWORD dwFlags
  1807. )
  1808. {
  1809. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1810. BOOL bStatus;
  1811. LONGLONG llEndOfFile = 0;
  1812. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  1813. BOOL bNeedToCloseHandles = FALSE;
  1814. UNREFERENCED_PARAMETER (dwFlags);
  1815. // if open for reading, then the file is also mapped as a memory section
  1816. if (pLog->lpMappedFileBase != NULL) {
  1817. // if open for output, get "logical" end of file so it
  1818. // can be truncated to to the amount of file used in order to
  1819. // save disk space
  1820. if ((pLog->dwLogFormat & PDH_LOG_ACCESS_MASK) == PDH_LOG_WRITE_ACCESS) {
  1821. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)
  1822. ((LPBYTE)(pLog->lpMappedFileBase) + pLog->dwRecord1Size);
  1823. llEndOfFile = pHeader->Info.WrapOffset;
  1824. if (llEndOfFile < pHeader->Info.NextRecordOffset) {
  1825. llEndOfFile = pHeader->Info.NextRecordOffset;
  1826. }
  1827. }
  1828. pdhStatus = UnmapReadonlyMappedFile (pLog->lpMappedFileBase, &bNeedToCloseHandles);
  1829. assert (pdhStatus == ERROR_SUCCESS);
  1830. pLog->lpMappedFileBase = NULL;
  1831. // for mapped files, this is a pointer into the file/memory section
  1832. // so once the view is unmapped, it's no longer valid
  1833. pLog->pLastRecordRead = NULL;
  1834. }
  1835. if (bNeedToCloseHandles) {
  1836. if (pLog->hMappedLogFile != NULL) {
  1837. bStatus = CloseHandle (pLog->hMappedLogFile);
  1838. assert (bStatus);
  1839. pLog->hMappedLogFile = NULL;
  1840. }
  1841. if (pdhStatus == ERROR_SUCCESS) {
  1842. if (!(FlushFileBuffers (pLog->hLogFileHandle))) {
  1843. pdhStatus = GetLastError();
  1844. }
  1845. } else {
  1846. // close them anyway, but save the status from the prev. call
  1847. FlushFileBuffers (pLog->hLogFileHandle);
  1848. }
  1849. // see if we can truncate the file
  1850. if (llEndOfFile > 0) {
  1851. DWORD dwLoPos, dwHighPos;
  1852. // truncate at the last byte used
  1853. dwLoPos = LODWORD(llEndOfFile);
  1854. dwHighPos = HIDWORD(llEndOfFile);
  1855. dwLoPos = SetFilePointer (pLog->hLogFileHandle,
  1856. dwLoPos, (LONG *)&dwHighPos, FILE_BEGIN);
  1857. if (dwLoPos == 0xFFFFFFFF) {
  1858. pdhStatus = GetLastError ();
  1859. }
  1860. assert (pdhStatus == ERROR_SUCCESS);
  1861. assert (dwLoPos == LODWORD(llEndOfFile));
  1862. assert (dwHighPos == HIDWORD(llEndOfFile));
  1863. if (pdhStatus == ERROR_SUCCESS) {
  1864. if (!SetEndOfFile(pLog->hLogFileHandle)) {
  1865. pdhStatus = GetLastError();
  1866. }
  1867. }
  1868. } // else don't know where the end is so continue
  1869. if (pLog->hLogFileHandle != INVALID_HANDLE_VALUE) {
  1870. bStatus = CloseHandle (pLog->hLogFileHandle);
  1871. assert (bStatus);
  1872. pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
  1873. }
  1874. } else {
  1875. // the handles have already been closed so just
  1876. // clear their values
  1877. pLog->lpMappedFileBase = NULL;
  1878. pLog->hMappedLogFile = NULL;
  1879. pLog->hLogFileHandle = INVALID_HANDLE_VALUE;
  1880. }
  1881. return pdhStatus;
  1882. }
  1883. PDH_FUNCTION
  1884. PdhiWriteBinaryLogHeader (
  1885. IN PPDHI_LOG pLog,
  1886. IN LPCWSTR szUserCaption
  1887. )
  1888. {
  1889. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1890. DWORD dwBytesWritten;
  1891. CHAR szTrailDelim[4];
  1892. DWORD dwTrailSize;
  1893. PPDHI_BINARY_LOG_HEADER_RECORD pLogHeader;
  1894. PPDHI_LOG_COUNTER_PATH pLogCounterBuffer = NULL;
  1895. PPDHI_LOG_COUNTER_PATH pThisLogCounter = NULL;
  1896. PPDHI_COUNTER pThisCounter;
  1897. DWORD dwPathBuffSize;
  1898. DWORD dwBufSize = 0;
  1899. DWORD dwBufToCopy;
  1900. DWORD dwNewSize;
  1901. PCHAR szOutputBuffer = NULL;
  1902. DWORD dwOutputBufferSize = 0;
  1903. DWORD dwOutputBufferUsed = 0;
  1904. PWCHAR pBufferBase;
  1905. LONG lBufferOffset;
  1906. PBYTE pSourceBase;
  1907. LONGLONG llStartingOffset;
  1908. UNREFERENCED_PARAMETER (szUserCaption);
  1909. // this is just used for the header string so it
  1910. // doesn't need to be very large
  1911. dwOutputBufferSize = SMALL_BUFFER_SIZE;
  1912. szOutputBuffer = G_ALLOC (dwOutputBufferSize);
  1913. if (szOutputBuffer == NULL) {
  1914. assert (GetLastError() == ERROR_SUCCESS);
  1915. return PDH_MEMORY_ALLOCATION_FAILURE;
  1916. }
  1917. szTrailDelim[0] = DOUBLEQUOTE_A;
  1918. szTrailDelim[1] = 0;
  1919. szTrailDelim[2] = 0;
  1920. szTrailDelim[3] = 0;
  1921. dwTrailSize = 1;
  1922. // write log file type record
  1923. memset (szOutputBuffer, 0, dwOutputBufferSize);
  1924. lstrcpyA (szOutputBuffer, szTrailDelim);
  1925. lstrcatA (szOutputBuffer, szBinLogFileHeader);
  1926. lstrcatA (szOutputBuffer, szTrailDelim);
  1927. lstrcatA (szOutputBuffer, PdhiszRecordTerminator);
  1928. dwOutputBufferUsed = lstrlenA(szOutputBuffer);
  1929. // align following structures on LONGLONG boundries
  1930. dwOutputBufferUsed = QWORD_MULTIPLE (dwOutputBufferUsed);
  1931. // save size of binary log record header
  1932. pLog->dwRecord1Size = dwOutputBufferUsed;
  1933. // from here on out all records have a 2-byte length field at
  1934. // the beginning to indicate how long the record is
  1935. // go through all the counters in the query and
  1936. // write them to the log file
  1937. pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL;
  1938. if (pThisCounter != NULL) {
  1939. do {
  1940. // get the counter path information from the counter struct
  1941. dwPathBuffSize = (DWORD)G_SIZE (pThisCounter->pCounterPath);
  1942. dwBufToCopy = dwPathBuffSize;
  1943. dwBufToCopy -= (DWORD)((DWORD_PTR)&pThisCounter->pCounterPath->pBuffer[0] -
  1944. (DWORD_PTR)pThisCounter->pCounterPath);
  1945. dwPathBuffSize -= (DWORD)((DWORD_PTR)&pThisCounter->pCounterPath->pBuffer[0] -
  1946. (DWORD_PTR)pThisCounter->pCounterPath);
  1947. dwPathBuffSize += sizeof (PDHI_LOG_COUNTER_PATH) -
  1948. sizeof (WCHAR); // Buffer[0].
  1949. // adjust buffer size for possible wildcard entry
  1950. // note that this may not be used, it'll be allocated in
  1951. // any event
  1952. dwPathBuffSize += sizeof (DWORD);
  1953. // dword align the stuctures
  1954. dwPathBuffSize = QWORD_MULTIPLE(dwPathBuffSize);
  1955. //extend buffer to accomodate this new counter
  1956. if (pLogCounterBuffer == NULL) {
  1957. // then allocate the first one
  1958. dwNewSize = dwPathBuffSize
  1959. + sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  1960. assert (dwNewSize > 0);
  1961. // to make sure the structure size doesn't change accidentally
  1962. assert (sizeof(PDHI_BINARY_LOG_INFO) == 256);
  1963. pLogCounterBuffer = G_ALLOC (dwNewSize);
  1964. if (pLogCounterBuffer == NULL) {
  1965. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1966. goto Cleanup;
  1967. }
  1968. pThisLogCounter = (PPDHI_LOG_COUNTER_PATH)(
  1969. (LPBYTE)pLogCounterBuffer +
  1970. sizeof(PDHI_BINARY_LOG_HEADER_RECORD));
  1971. dwBufSize = dwNewSize;
  1972. } else {
  1973. PPDHI_LOG_COUNTER_PATH pOldCounter = pLogCounterBuffer;
  1974. // extend buffer for new entry
  1975. dwNewSize = (dwBufSize + dwPathBuffSize);
  1976. assert (dwNewSize > 0);
  1977. pLogCounterBuffer = G_REALLOC (pOldCounter, dwNewSize);
  1978. if (pLogCounterBuffer == NULL) {
  1979. G_FREE(pOldCounter);
  1980. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  1981. goto Cleanup;
  1982. }
  1983. pThisLogCounter = (PPDHI_LOG_COUNTER_PATH)
  1984. ((LPBYTE)pLogCounterBuffer + dwBufSize);
  1985. dwBufSize += dwPathBuffSize;
  1986. }
  1987. assert (pLogCounterBuffer != NULL);
  1988. assert (pThisLogCounter != NULL);
  1989. assert (G_SIZE (pLogCounterBuffer) > 0);
  1990. pThisLogCounter->dwLength = dwPathBuffSize;
  1991. pThisLogCounter->dwFlags = pThisCounter->dwFlags;
  1992. pThisLogCounter->dwUserData = pThisCounter->dwUserData;
  1993. pThisLogCounter->dwCounterType =
  1994. pThisCounter->plCounterInfo.dwCounterType;
  1995. pThisLogCounter->lDefaultScale =
  1996. pThisCounter->plCounterInfo.lDefaultScale;
  1997. pThisLogCounter->llTimeBase = pThisCounter->TimeBase;
  1998. // copy the counter path string data to the log buffer, then
  1999. // convert the pointers to offsets
  2000. pSourceBase = &pThisCounter->pCounterPath->pBuffer[0];
  2001. // if this is a wild card path, then move the strings up
  2002. // 1 dword in the buffer allowing the first DWORD of the
  2003. // the buffer to contain the offset into the catalog
  2004. // of the instances found in this log file. This list
  2005. // will be built after the log is closed.
  2006. lBufferOffset = 0; // in WORDS (not bytes)
  2007. if (pThisCounter->pCounterPath->szInstanceName != NULL) {
  2008. if (*pThisCounter->pCounterPath->szInstanceName == SPLAT_L) {
  2009. // this is a wildcard path so save room for the
  2010. // pointer into the catalog
  2011. lBufferOffset = sizeof(DWORD);
  2012. }
  2013. }
  2014. #if DBG
  2015. if (lBufferOffset > 0) *(LPDWORD)(&pThisLogCounter->Buffer[0]) = 0x12345678;
  2016. #endif
  2017. pBufferBase = (PWCHAR)((LPBYTE)&pThisLogCounter->Buffer[0] +
  2018. lBufferOffset);
  2019. RtlCopyMemory((LPVOID) pBufferBase, (LPVOID)pSourceBase, dwBufToCopy);
  2020. // find offsets from the start of the buffer
  2021. if (pThisCounter->pCounterPath->szMachineName != NULL) {
  2022. pThisLogCounter->lMachineNameOffset = lBufferOffset +
  2023. (LONG)((DWORD_PTR)pThisCounter->pCounterPath->szMachineName -
  2024. (DWORD_PTR)pSourceBase);
  2025. //assert (pThisLogCounter->lMachineNameOffset == 0);
  2026. } else {
  2027. pThisLogCounter->lMachineNameOffset = (LONG)-1;
  2028. }
  2029. if (pThisCounter->pCounterPath->szObjectName != NULL) {
  2030. pThisLogCounter->lObjectNameOffset = lBufferOffset +
  2031. (LONG)((DWORD_PTR)pThisCounter->pCounterPath->szObjectName -
  2032. (DWORD_PTR)pSourceBase);
  2033. } else {
  2034. pThisLogCounter->lObjectNameOffset = (LONG)-1;
  2035. }
  2036. if (pThisCounter->pCounterPath->szInstanceName != NULL) {
  2037. pThisLogCounter->lInstanceOffset = lBufferOffset +
  2038. (LONG)((DWORD_PTR)pThisCounter->pCounterPath->szInstanceName -
  2039. (DWORD_PTR)pSourceBase);
  2040. } else {
  2041. pThisLogCounter->lInstanceOffset = (LONG)-1;
  2042. }
  2043. if (pThisCounter->pCounterPath->szParentName != NULL) {
  2044. pThisLogCounter->lParentOffset = lBufferOffset +
  2045. (LONG)((DWORD_PTR)pThisCounter->pCounterPath->szParentName -
  2046. (DWORD_PTR)pSourceBase);
  2047. } else {
  2048. pThisLogCounter->lParentOffset = (LONG)-1;
  2049. }
  2050. pThisLogCounter->dwIndex = pThisCounter->pCounterPath->dwIndex;
  2051. if (pThisCounter->pCounterPath->szCounterName != NULL) {
  2052. pThisLogCounter->lCounterOffset = lBufferOffset +
  2053. (LONG)((DWORD_PTR)pThisCounter->pCounterPath->szCounterName -
  2054. (DWORD_PTR)pSourceBase);
  2055. } else {
  2056. pThisLogCounter->lCounterOffset = (LONG)-1;
  2057. }
  2058. pThisCounter = pThisCounter->next.flink; // go to next in list
  2059. } while (pThisCounter != pLog->pQuery->pCounterListHead);
  2060. if (pdhStatus == ERROR_SUCCESS) {
  2061. assert (dwBufSize < 0x00010000); // just to see if we get any big lists
  2062. // update the record header
  2063. pLogHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)(pLogCounterBuffer);
  2064. pLogHeader->RecHeader.dwType = BINLOG_TYPE_CATALOG_LIST;
  2065. pLogHeader->RecHeader.dwLength = dwBufSize;
  2066. pLogHeader->Info.FileLength = 0;
  2067. pLogHeader->Info.dwLogVersion = BINLOG_VERSION;
  2068. // save the log options only here
  2069. pLogHeader->Info.dwFlags = pLog->dwLogFormat & PDH_LOG_OPT_MASK;
  2070. pLogHeader->Info.StartTime = 0;
  2071. pLogHeader->Info.EndTime = 0;
  2072. pLogHeader->Info.CatalogOffset = 0;
  2073. pLogHeader->Info.CatalogChecksum = PdhiComputeDwordChecksum (
  2074. (LPVOID) &pLogHeader[1], (dwBufSize - sizeof(PDHI_BINARY_LOG_HEADER_RECORD)));
  2075. pLogHeader->Info.CatalogDate = 0;
  2076. // record pointers are all the same for the first record
  2077. llStartingOffset = dwBufSize + pLog->dwRecord1Size;
  2078. pLogHeader->Info.FirstDataRecordOffset = llStartingOffset;
  2079. pLogHeader->Info.FirstRecordOffset = llStartingOffset;
  2080. pLogHeader->Info.LastRecordOffset = llStartingOffset;
  2081. pLogHeader->Info.NextRecordOffset = llStartingOffset;
  2082. pLogHeader->Info.WrapOffset = 0;
  2083. // write log file header to file
  2084. if ((pdhStatus = PdhiWriteOneBinaryLogRecord (pLog,
  2085. (LPCVOID)szOutputBuffer,
  2086. dwOutputBufferUsed,
  2087. &dwBytesWritten,
  2088. WBLR_WRITE_LOG_HEADER)) == ERROR_SUCCESS) {
  2089. // write log contents record to file
  2090. pdhStatus = PdhiWriteOneBinaryLogRecord (pLog,
  2091. (LPCVOID)pLogCounterBuffer,
  2092. dwBufSize,
  2093. &dwBytesWritten,
  2094. WBLR_WRITE_COUNTER_HEADER);
  2095. }
  2096. }
  2097. if (pLogCounterBuffer != NULL) G_FREE (pLogCounterBuffer);
  2098. } else {
  2099. // no counter's assigned to this query
  2100. pdhStatus = PDH_NO_DATA;
  2101. }
  2102. Cleanup:
  2103. if (szOutputBuffer != NULL) G_FREE (szOutputBuffer);
  2104. return pdhStatus;
  2105. }
  2106. PDH_FUNCTION
  2107. PdhiWriteBinaryLogRecord (
  2108. IN PPDHI_LOG pLog,
  2109. IN SYSTEMTIME *stTimeStamp,
  2110. IN LPCWSTR szUserString
  2111. )
  2112. {
  2113. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2114. DWORD dwBytesWritten;
  2115. PPDHI_BINARY_LOG_RECORD_HEADER pLogCounterBuffer = NULL;
  2116. PPDHI_BINARY_LOG_RECORD_HEADER pThisLogCounter = NULL;
  2117. PPDH_RAW_COUNTER pSingleCounter;
  2118. PPDHI_RAW_COUNTER_ITEM_BLOCK pMultiCounter;
  2119. PPDHI_COUNTER pThisCounter;
  2120. DWORD dwCtrBufSize;
  2121. DWORD dwBufSize = 0;
  2122. BOOL bVarCtr;
  2123. DWORD dwNewSize;
  2124. DWORD dwBytesCopied = 0;
  2125. int nItem;
  2126. UNREFERENCED_PARAMETER (stTimeStamp);
  2127. DBG_UNREFERENCED_PARAMETER (szUserString);
  2128. // get first counter in list
  2129. pThisCounter = pLog->pQuery ? pLog->pQuery->pCounterListHead : NULL;
  2130. if (pThisCounter != NULL) {
  2131. do {
  2132. bVarCtr = pThisCounter->dwFlags & PDHIC_MULTI_INSTANCE ?
  2133. TRUE : FALSE;
  2134. if (bVarCtr) {
  2135. dwCtrBufSize = pThisCounter->pThisRawItemList->dwLength;
  2136. } else {
  2137. dwCtrBufSize = sizeof (PDH_RAW_COUNTER);
  2138. }
  2139. // each counter gets a header
  2140. dwCtrBufSize += sizeof (PDHI_BINARY_LOG_RECORD_HEADER);
  2141. //extend buffer to accomodate this new counter
  2142. if (pLogCounterBuffer == NULL) {
  2143. // add in room for the master record header
  2144. // then allocate the first one
  2145. pLogCounterBuffer = G_ALLOC ((dwCtrBufSize + sizeof (PDHI_BINARY_LOG_RECORD_HEADER)));
  2146. // set counter data pointer to just after the master
  2147. // record header
  2148. if (pLogCounterBuffer == NULL) {
  2149. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2150. break;
  2151. }
  2152. pThisLogCounter = (PPDHI_BINARY_LOG_RECORD_HEADER)(
  2153. &pLogCounterBuffer[1]);
  2154. dwBufSize = dwCtrBufSize + sizeof (PDHI_BINARY_LOG_RECORD_HEADER);
  2155. } else {
  2156. PPDHI_BINARY_LOG_RECORD_HEADER pOldBuffer = pLogCounterBuffer;
  2157. // extend buffer for new entry
  2158. dwNewSize = (dwBufSize + dwCtrBufSize);
  2159. assert (dwNewSize);
  2160. pLogCounterBuffer = G_REALLOC (pOldBuffer, dwNewSize);
  2161. if (pLogCounterBuffer == NULL) {
  2162. G_FREE(pOldBuffer);
  2163. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2164. goto Cleanup;
  2165. }
  2166. pThisLogCounter = (PPDHI_BINARY_LOG_RECORD_HEADER)
  2167. ((LPBYTE)pLogCounterBuffer + dwBufSize);
  2168. dwBufSize += dwCtrBufSize;
  2169. }
  2170. assert (pLogCounterBuffer != NULL);
  2171. assert (pThisLogCounter != NULL);
  2172. assert (G_SIZE (pLogCounterBuffer) > 0);
  2173. // set the header fields and data pointer
  2174. assert (dwCtrBufSize < 0x00010000);
  2175. pThisLogCounter->dwLength = LOWORD(dwCtrBufSize);
  2176. // add in size of record header
  2177. dwBytesCopied += sizeof (PDHI_BINARY_LOG_RECORD_HEADER);
  2178. if (bVarCtr) {
  2179. // multiple counter
  2180. pThisLogCounter->dwType = BINLOG_TYPE_DATA_MULTI;
  2181. pMultiCounter = (PPDHI_RAW_COUNTER_ITEM_BLOCK) (
  2182. (LPBYTE)pThisLogCounter +
  2183. sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
  2184. RtlCopyMemory(pMultiCounter,
  2185. pThisCounter->pThisRawItemList,
  2186. pThisCounter->pThisRawItemList->dwLength);
  2187. dwBytesCopied += pThisCounter->pThisRawItemList->dwLength;
  2188. } else {
  2189. // single counter
  2190. pThisLogCounter->dwType = BINLOG_TYPE_DATA_SINGLE;
  2191. pSingleCounter = (PPDH_RAW_COUNTER) (
  2192. (LPBYTE)pThisLogCounter +
  2193. sizeof(PDHI_BINARY_LOG_RECORD_HEADER));
  2194. RtlCopyMemory(pSingleCounter,
  2195. &pThisCounter->ThisValue,
  2196. sizeof (PDH_RAW_COUNTER));
  2197. dwBytesCopied += sizeof (PDH_RAW_COUNTER);
  2198. }
  2199. pThisCounter = pThisCounter->next.flink; // go to next in list
  2200. } while (pThisCounter != pLog->pQuery->pCounterListHead);
  2201. // update the record header
  2202. if (pdhStatus == ERROR_SUCCESS) {
  2203. // add in size of master record header
  2204. dwBytesCopied += sizeof (PDHI_BINARY_LOG_RECORD_HEADER);
  2205. pLogCounterBuffer->dwType = BINLOG_TYPE_DATA;
  2206. // Need to handle the case where the resulting record is
  2207. // greater than 64K in length. Probably by breaking it into
  2208. // multiple records.
  2209. pLogCounterBuffer->dwLength = dwBufSize;
  2210. assert (dwBufSize == dwBytesCopied);
  2211. // write record to file
  2212. pdhStatus = PdhiWriteOneBinaryLogRecord (
  2213. pLog,
  2214. (LPCVOID)pLogCounterBuffer,
  2215. dwBufSize,
  2216. &dwBytesWritten,
  2217. 0);
  2218. }
  2219. if (pLogCounterBuffer != NULL) G_FREE (pLogCounterBuffer);
  2220. } else {
  2221. // no counter's assigned to this query
  2222. pdhStatus = PDH_NO_DATA;
  2223. }
  2224. Cleanup:
  2225. return pdhStatus;
  2226. }
  2227. PDH_FUNCTION
  2228. PdhiEnumMachinesFromBinaryLog (
  2229. PPDHI_LOG pLog,
  2230. LPVOID pBuffer,
  2231. LPDWORD pcchBufferSize,
  2232. BOOL bUnicodeDest
  2233. )
  2234. {
  2235. LPVOID pTempBuffer = NULL;
  2236. LPVOID pOldBuffer;
  2237. DWORD dwTempBufferSize;
  2238. LPVOID LocalBuffer = NULL;
  2239. DWORD dwLocalBufferSize;
  2240. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2241. // read the header record and enum the machine name from the entries
  2242. if (pLog->dwMaxRecordSize == 0) {
  2243. // no size is defined so start with 64K
  2244. pLog->dwMaxRecordSize = 0x010000;
  2245. }
  2246. dwTempBufferSize = pLog->dwMaxRecordSize;
  2247. pTempBuffer = G_ALLOC(dwTempBufferSize);
  2248. if (pTempBuffer == NULL) {
  2249. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2250. goto Cleanup;
  2251. }
  2252. dwLocalBufferSize = MEDIUM_BUFFER_SIZE;
  2253. LocalBuffer = G_ALLOC(dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2254. if (LocalBuffer == NULL) {
  2255. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2256. goto Cleanup;
  2257. }
  2258. // read in the catalog record
  2259. while ((pdhStatus = PdhiReadOneBinLogRecord (pLog, BINLOG_HEADER_RECORD,
  2260. pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
  2261. if (pdhStatus == PDH_MORE_DATA) {
  2262. // read the 1st WORD to see if this is a valid record
  2263. if (*(WORD *)pTempBuffer == BINLOG_START_WORD) {
  2264. // it's a valid record so read the 2nd DWORD to get the
  2265. // record size;
  2266. dwTempBufferSize = ((DWORD *)pTempBuffer)[1];
  2267. if (dwTempBufferSize < pLog->dwMaxRecordSize) {
  2268. // then something is bogus so return an error
  2269. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2270. break; // out of while loop
  2271. } else {
  2272. pLog->dwMaxRecordSize = dwTempBufferSize;
  2273. }
  2274. } else {
  2275. // we're lost in this file
  2276. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2277. break; // out of while loop
  2278. }
  2279. // realloc a new buffer
  2280. pOldBuffer = pTempBuffer;
  2281. pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize);
  2282. if (pTempBuffer == NULL) {
  2283. // return memory error
  2284. G_FREE(pOldBuffer);
  2285. assert (GetLastError() == ERROR_SUCCESS);
  2286. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2287. break;
  2288. }
  2289. } else {
  2290. // some other error was returned so
  2291. // return error from read function
  2292. break;
  2293. }
  2294. }
  2295. if (pdhStatus == ERROR_SUCCESS) {
  2296. PPDHI_LOG_COUNTER_PATH pPath;
  2297. DWORD dwBytesProcessed;
  2298. LONG nItemCount = 0;
  2299. LPBYTE pFirstChar;
  2300. LPWSTR szMachineName;
  2301. DWORD dwRecordLength;
  2302. DWORD dwBufferUsed = 0;
  2303. DWORD dwNewBuffer = 0;
  2304. // we can assume the record was read successfully so read in the
  2305. // machine names
  2306. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
  2307. pPath = (PPDHI_LOG_COUNTER_PATH)
  2308. ((LPBYTE)pTempBuffer + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  2309. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  2310. while (dwBytesProcessed < dwRecordLength) {
  2311. if (pPath->lMachineNameOffset >= 0L) {
  2312. // then there's a machine name in this record so get
  2313. // it's size
  2314. pFirstChar = (LPBYTE)&pPath->Buffer[0];
  2315. szMachineName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lMachineNameOffset);
  2316. dwNewBuffer = (lstrlenW (szMachineName) + 1);
  2317. while (dwNewBuffer + dwBufferUsed > dwLocalBufferSize) {
  2318. pOldBuffer = LocalBuffer;
  2319. dwLocalBufferSize += MEDIUM_BUFFER_SIZE;
  2320. LocalBuffer = G_REALLOC(pOldBuffer,
  2321. dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2322. if (LocalBuffer == NULL) {
  2323. if (pOldBuffer != NULL) G_FREE(pOldBuffer);
  2324. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2325. goto Cleanup;
  2326. }
  2327. }
  2328. dwNewBuffer = AddUniqueWideStringToMultiSz((LPVOID) LocalBuffer, szMachineName, bUnicodeDest);
  2329. if (dwNewBuffer > 0) {
  2330. dwBufferUsed = dwNewBuffer;
  2331. nItemCount ++;
  2332. }
  2333. }
  2334. // get next path entry from log file record
  2335. dwBytesProcessed += pPath->dwLength;
  2336. pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE) pPath + pPath->dwLength);
  2337. }
  2338. if ((nItemCount > 0) && (pdhStatus != PDH_INSUFFICIENT_BUFFER)
  2339. && (pdhStatus != PDH_MORE_DATA)) {
  2340. // then the routine was successful. Errors that occurred
  2341. // while scanning will be ignored as long as at least
  2342. // one entry was successfully read
  2343. pdhStatus = ERROR_SUCCESS;
  2344. }
  2345. if (nItemCount > 0) {
  2346. dwBufferUsed ++;
  2347. }
  2348. if (pBuffer && dwBufferUsed <= * pcchBufferSize) {
  2349. RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2350. }
  2351. else {
  2352. if (pBuffer)
  2353. RtlCopyMemory(pBuffer, LocalBuffer, (* pcchBufferSize) * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2354. pdhStatus = PDH_MORE_DATA;
  2355. }
  2356. *pcchBufferSize = dwBufferUsed;
  2357. }
  2358. Cleanup:
  2359. if (LocalBuffer != NULL) G_FREE(LocalBuffer);
  2360. if (pTempBuffer != NULL) G_FREE(pTempBuffer);
  2361. return pdhStatus;
  2362. }
  2363. PDH_FUNCTION
  2364. PdhiEnumObjectsFromBinaryLog (
  2365. IN PPDHI_LOG pLog,
  2366. IN LPCWSTR szMachineName,
  2367. IN LPVOID pBuffer,
  2368. IN LPDWORD pcchBufferSize,
  2369. IN DWORD dwDetailLevel,
  2370. IN BOOL bUnicodeDest
  2371. )
  2372. {
  2373. LPVOID pTempBuffer = NULL;
  2374. LPVOID pOldBuffer;
  2375. DWORD dwTempBufferSize;
  2376. LPVOID LocalBuffer = NULL;
  2377. DWORD dwLocalBufferSize;
  2378. LPCWSTR szLocalMachine = szMachineName;
  2379. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2380. // read the header record and enum the machine name from the entries
  2381. UNREFERENCED_PARAMETER (dwDetailLevel);
  2382. if (pLog->dwMaxRecordSize == 0) {
  2383. // no size is defined so start with 64K
  2384. pLog->dwMaxRecordSize = 0x010000;
  2385. }
  2386. if (szLocalMachine == NULL) szLocalMachine = szStaticLocalMachineName;
  2387. else if (szLocalMachine[0] == L'\0') szLocalMachine = szStaticLocalMachineName;
  2388. dwTempBufferSize = pLog->dwMaxRecordSize;
  2389. pTempBuffer = G_ALLOC(dwTempBufferSize);
  2390. if (pTempBuffer == NULL) {
  2391. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2392. goto Cleanup;
  2393. }
  2394. dwLocalBufferSize = MEDIUM_BUFFER_SIZE;
  2395. LocalBuffer = G_ALLOC(dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2396. if (LocalBuffer == NULL) {
  2397. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2398. goto Cleanup;
  2399. }
  2400. // read in the catalog record
  2401. while ((pdhStatus = PdhiReadOneBinLogRecord (pLog, BINLOG_HEADER_RECORD,
  2402. pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
  2403. if (pdhStatus == PDH_MORE_DATA) {
  2404. // read the 1st WORD to see if this is a valid record
  2405. if (*(WORD *)pTempBuffer == BINLOG_START_WORD) {
  2406. // it's a valid record so read the 2nd DWORD to get the
  2407. // record size;
  2408. dwTempBufferSize = ((DWORD *)pTempBuffer)[1];
  2409. if (dwTempBufferSize < pLog->dwMaxRecordSize) {
  2410. // then something is bogus so return an error
  2411. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2412. break; // out of while loop
  2413. } else {
  2414. pLog->dwMaxRecordSize = dwTempBufferSize;
  2415. }
  2416. } else {
  2417. // we're lost in this file
  2418. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2419. break; // out of while loop
  2420. }
  2421. // realloc a new buffer
  2422. pOldBuffer = pTempBuffer;
  2423. pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize);
  2424. if (pTempBuffer == NULL) {
  2425. // return memory error
  2426. G_FREE(pOldBuffer);
  2427. assert (GetLastError() == ERROR_SUCCESS);
  2428. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2429. break;
  2430. }
  2431. } else {
  2432. // some other error was returned so
  2433. // return error from read function
  2434. break;
  2435. }
  2436. }
  2437. if (pdhStatus == ERROR_SUCCESS) {
  2438. PPDHI_LOG_COUNTER_PATH pPath;
  2439. DWORD dwBytesProcessed;
  2440. LONG nItemCount = 0;
  2441. LPBYTE pFirstChar;
  2442. LPWSTR szThisMachineName;
  2443. LPWSTR szThisObjectName;
  2444. DWORD dwRecordLength;
  2445. DWORD dwBufferUsed = 0;
  2446. DWORD dwNewBuffer = 0;
  2447. BOOL bCopyThisObject;
  2448. // we can assume the record was read successfully so read in the
  2449. // objects that match the machine name and detail level criteria
  2450. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
  2451. pPath = (PPDHI_LOG_COUNTER_PATH)
  2452. ((LPBYTE)pTempBuffer + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  2453. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  2454. while (dwBytesProcessed < dwRecordLength) {
  2455. bCopyThisObject = FALSE;
  2456. szThisObjectName = NULL;
  2457. pFirstChar = (LPBYTE)&pPath->Buffer[0];
  2458. if (pPath->lMachineNameOffset >= 0L) {
  2459. // then there's a machine name in this record so get
  2460. // it's size
  2461. szThisMachineName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lMachineNameOffset);
  2462. // if this is for the desired machine, then copy this object
  2463. if (lstrcmpiW(szThisMachineName, szLocalMachine) == 0) {
  2464. if (szThisObjectName >= 0) {
  2465. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  2466. bCopyThisObject = TRUE;
  2467. } else {
  2468. // no object to copy
  2469. }
  2470. } else {
  2471. // this machine isn't selected
  2472. }
  2473. } else {
  2474. // there's no machine specified so for this counter so list it by default
  2475. if (szThisObjectName >= 0) {
  2476. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  2477. bCopyThisObject = TRUE;
  2478. } else {
  2479. // no object to copy
  2480. }
  2481. }
  2482. if (bCopyThisObject && szThisObjectName != NULL) {
  2483. // get the size of this object's name
  2484. dwNewBuffer = (lstrlenW(szThisObjectName) + 1);
  2485. while (dwNewBuffer + dwBufferUsed > dwLocalBufferSize) {
  2486. pOldBuffer = LocalBuffer;
  2487. dwLocalBufferSize += MEDIUM_BUFFER_SIZE;
  2488. LocalBuffer = G_REALLOC(pOldBuffer,
  2489. dwLocalBufferSize * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2490. if (LocalBuffer == NULL) {
  2491. if (pOldBuffer != NULL) G_FREE(pOldBuffer);
  2492. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2493. goto Cleanup;
  2494. }
  2495. }
  2496. dwNewBuffer = AddUniqueWideStringToMultiSz((LPVOID) LocalBuffer, szThisObjectName, bUnicodeDest);
  2497. if (dwNewBuffer > 0) {
  2498. dwBufferUsed = dwNewBuffer;
  2499. nItemCount ++;
  2500. }
  2501. }
  2502. // get next path entry from log file record
  2503. dwBytesProcessed += pPath->dwLength;
  2504. pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE)pPath + pPath->dwLength);
  2505. }
  2506. if ((nItemCount > 0) && (pdhStatus != PDH_INSUFFICIENT_BUFFER)
  2507. && (pdhStatus != PDH_MORE_DATA)) {
  2508. // then the routine was successful. Errors that occurred
  2509. // while scanning will be ignored as long as at least
  2510. // one entry was successfully read
  2511. pdhStatus = ERROR_SUCCESS;
  2512. }
  2513. if (nItemCount > 0) {
  2514. dwBufferUsed ++;
  2515. }
  2516. if (pBuffer && dwBufferUsed <= * pcchBufferSize) {
  2517. RtlCopyMemory(pBuffer, LocalBuffer, dwBufferUsed * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2518. }
  2519. else {
  2520. if (pBuffer)
  2521. RtlCopyMemory(pBuffer, LocalBuffer, (* pcchBufferSize) * (bUnicodeDest ? sizeof(WCHAR) : sizeof(CHAR)));
  2522. pdhStatus = PDH_MORE_DATA;
  2523. }
  2524. * pcchBufferSize = dwBufferUsed;
  2525. }
  2526. Cleanup:
  2527. if (LocalBuffer != NULL) G_FREE(LocalBuffer);
  2528. if (pTempBuffer != NULL) G_FREE(pTempBuffer);
  2529. return pdhStatus;
  2530. }
  2531. PDH_FUNCTION
  2532. PdhiEnumObjectItemsFromBinaryLog (
  2533. IN PPDHI_LOG pLog,
  2534. IN LPCWSTR szMachineName,
  2535. IN LPCWSTR szObjectName,
  2536. IN PDHI_COUNTER_TABLE CounterTable,
  2537. IN DWORD dwDetailLevel,
  2538. IN DWORD dwFlags
  2539. )
  2540. {
  2541. LPVOID pTempBuffer = NULL;
  2542. LPVOID pOldBuffer;
  2543. DWORD dwTempBufferSize;
  2544. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2545. PPDHI_INST_LIST pInstList;
  2546. PPDHI_INSTANCE pInstance;
  2547. BOOL bProcessInstance = FALSE;
  2548. UNREFERENCED_PARAMETER (dwDetailLevel);
  2549. UNREFERENCED_PARAMETER (dwFlags);
  2550. // read the header record and enum the machine name from the entries
  2551. if (pLog->dwMaxRecordSize == 0) {
  2552. // no size is defined so start with 64K
  2553. pLog->dwMaxRecordSize = 0x010000;
  2554. }
  2555. dwTempBufferSize = pLog->dwMaxRecordSize;
  2556. pTempBuffer = G_ALLOC (dwTempBufferSize);
  2557. assert (pTempBuffer != NULL);
  2558. if (pTempBuffer == NULL) {
  2559. assert (GetLastError() == ERROR_SUCCESS);
  2560. return PDH_MEMORY_ALLOCATION_FAILURE;
  2561. }
  2562. // read in the catalog record
  2563. while ((pdhStatus = PdhiReadOneBinLogRecord (pLog, BINLOG_HEADER_RECORD,
  2564. pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
  2565. if (pdhStatus == PDH_MORE_DATA) {
  2566. // read the 1st WORD to see if this is a valid record
  2567. if (*(WORD *)pTempBuffer == BINLOG_START_WORD) {
  2568. // it's a valid record so read the 2nd DWORD to get the
  2569. // record size;
  2570. dwTempBufferSize = ((DWORD *)pTempBuffer)[1];
  2571. if (dwTempBufferSize < pLog->dwMaxRecordSize) {
  2572. // then something is bogus so return an error
  2573. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2574. break; // out of while loop
  2575. } else {
  2576. pLog->dwMaxRecordSize = dwTempBufferSize;
  2577. }
  2578. } else {
  2579. // we're lost in this file
  2580. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2581. break; // out of while loop
  2582. }
  2583. // realloc a new buffer
  2584. pOldBuffer = pTempBuffer;
  2585. pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize);
  2586. if (pTempBuffer == NULL) {
  2587. // return memory error
  2588. G_FREE(pOldBuffer);
  2589. assert (GetLastError() == ERROR_SUCCESS);
  2590. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  2591. break;
  2592. }
  2593. } else {
  2594. // some other error was returned so
  2595. // return error from read function
  2596. break;
  2597. }
  2598. }
  2599. if (pdhStatus == ERROR_SUCCESS) {
  2600. PPDHI_BINARY_LOG_HEADER_RECORD pHeader;
  2601. PPDHI_LOG_COUNTER_PATH pPath;
  2602. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  2603. PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
  2604. PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
  2605. PPDHI_RAW_COUNTER_ITEM pDataItem;
  2606. DWORD dwBytesProcessed;
  2607. LONG nItemCount = 0;
  2608. LPBYTE pFirstChar;
  2609. LPWSTR szThisMachineName;
  2610. LPWSTR szThisObjectName;
  2611. LPWSTR szThisCounterName = NULL;
  2612. LPWSTR szThisInstanceName;
  2613. LPWSTR szThisParentName;
  2614. WCHAR szCompositeInstance[1024];
  2615. DWORD dwRecordLength;
  2616. BOOL bCopyThisObject;
  2617. DWORD dwIndex;
  2618. DWORD dwThisRecordIndex;
  2619. DWORD dwDataItemIndex;
  2620. PLOG_BIN_CAT_RECORD pCatRec;
  2621. LPWSTR szWideInstanceName;
  2622. pHeader = (PPDHI_BINARY_LOG_HEADER_RECORD)pTempBuffer;
  2623. // we can assume the record was read successfully so read in the
  2624. // objects that match the machine name and detail level criteria
  2625. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
  2626. pPath = (PPDHI_LOG_COUNTER_PATH)
  2627. ((LPBYTE)pTempBuffer + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  2628. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  2629. dwIndex = 0;
  2630. while (dwBytesProcessed < dwRecordLength) {
  2631. bCopyThisObject = FALSE;
  2632. szThisObjectName = NULL;
  2633. dwIndex++;
  2634. pFirstChar = (LPBYTE)&pPath->Buffer[0];
  2635. if (pPath->lMachineNameOffset >= 0L) {
  2636. // then there's a machine name in this record so get
  2637. // it's size
  2638. szThisMachineName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lMachineNameOffset);
  2639. // if this is for the desired machine, then select the object
  2640. if (lstrcmpiW(szThisMachineName,szMachineName) == 0) {
  2641. if (szThisObjectName >= 0) {
  2642. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  2643. if (lstrcmpiW(szThisObjectName,szObjectName) == 0) {
  2644. // then this is the object to look up
  2645. bCopyThisObject = TRUE;
  2646. } else {
  2647. // not this object
  2648. }
  2649. } else {
  2650. // no object to copy
  2651. }
  2652. } else {
  2653. // this machine isn't selected
  2654. }
  2655. } else {
  2656. // there's no machine specified so for this counter so list it by default
  2657. if (pPath->lObjectNameOffset >= 0) {
  2658. szThisObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  2659. if (lstrcmpiW(szThisObjectName,szObjectName) == 0) {
  2660. // then this is the object to look up
  2661. bCopyThisObject = TRUE;
  2662. } else {
  2663. // not this object
  2664. }
  2665. } else {
  2666. // no object to copy
  2667. }
  2668. }
  2669. if (bCopyThisObject) {
  2670. // if here, then there should be a name
  2671. assert (szThisObjectName != NULL);
  2672. // get the counter name from this counter and add it to the list
  2673. if (pPath->lCounterOffset > 0) {
  2674. szThisCounterName = (LPWSTR)((LPBYTE)pFirstChar +
  2675. pPath->lCounterOffset);
  2676. } else {
  2677. szThisCounterName = NULL;
  2678. bCopyThisObject = FALSE;
  2679. }
  2680. }
  2681. if (bCopyThisObject) {
  2682. pdhStatus = PdhiFindCounterInstList(
  2683. CounterTable,
  2684. szThisCounterName,
  2685. & pInstList);
  2686. if (pdhStatus != ERROR_SUCCESS || pInstList == NULL) {
  2687. continue;
  2688. }
  2689. // check instance now
  2690. // get the instance name from this counter and add it to the list
  2691. if (pPath->lInstanceOffset >= 0) {
  2692. szThisInstanceName = (LPWSTR)((LPBYTE)pFirstChar +
  2693. pPath->lInstanceOffset);
  2694. if (*szThisInstanceName != SPLAT_L) {
  2695. if (pPath->lParentOffset >= 0) {
  2696. szThisParentName = (LPWSTR)((LPBYTE)pFirstChar +
  2697. pPath->lParentOffset);
  2698. lstrcpyW (szCompositeInstance,
  2699. szThisParentName);
  2700. lstrcatW (szCompositeInstance, cszSlash);
  2701. lstrcatW (szCompositeInstance, szThisInstanceName);
  2702. } else {
  2703. lstrcpyW (szCompositeInstance, szThisInstanceName);
  2704. }
  2705. //if (pPath->dwIndex > 0) {
  2706. // _ltow (pPath->dwIndex, (LPWSTR)
  2707. // (szCompositeInstance + lstrlenW(szCompositeInstance)),
  2708. // 10L);
  2709. //}
  2710. pdhStatus = PdhiFindInstance(
  2711. & pInstList->InstList,
  2712. szCompositeInstance,
  2713. TRUE,
  2714. & pInstance);
  2715. if (pdhStatus == ERROR_SUCCESS) {
  2716. nItemCount++;
  2717. }
  2718. } else {
  2719. // only use the catalog if it's up to date and present
  2720. if ((pHeader->Info.CatalogOffset > 0) &&
  2721. (pHeader->Info.LastUpdateTime <= pHeader->Info.CatalogDate)){
  2722. // find catalog record
  2723. pCatRec = (PLOG_BIN_CAT_RECORD)
  2724. // base of mapped log file
  2725. ((LPBYTE)pLog->lpMappedFileBase +
  2726. // + offset to catalog records
  2727. pHeader->Info.CatalogOffset +
  2728. // + offset to the instance entry for this item
  2729. *(LPDWORD)&pPath->Buffer[0]);
  2730. assert (pCatRec != NULL);
  2731. assert (pCatRec->RecHeader.dwType == BINLOG_TYPE_CATALOG_ITEM);
  2732. for (szWideInstanceName = (LPWSTR)((LPBYTE)&pCatRec->CatEntry + pCatRec->CatEntry.dwInstanceStringOffset);
  2733. * szWideInstanceName != 0;
  2734. szWideInstanceName += lstrlenW(szWideInstanceName) + 1) {
  2735. pdhStatus = PdhiFindInstance(
  2736. & pInstList->InstList,
  2737. szWideInstanceName,
  2738. TRUE,
  2739. & pInstance);
  2740. }
  2741. } else if (! bProcessInstance) {
  2742. // look up individual instances in log...
  2743. // read records from file and store instances
  2744. dwThisRecordIndex = BINLOG_FIRST_DATA_RECORD;
  2745. // this call just moved the record pointer
  2746. pdhStatus = PdhiReadOneBinLogRecord (
  2747. pLog, dwThisRecordIndex, NULL, 0);
  2748. while (pdhStatus == ERROR_SUCCESS) {
  2749. PdhiResetInstanceCount(CounterTable);
  2750. pThisMasterRecord =
  2751. (PPDHI_BINARY_LOG_RECORD_HEADER)
  2752. pLog->pLastRecordRead;
  2753. // make sure we haven't left the file
  2754. assert (pThisMasterRecord != NULL);
  2755. assert ((LPBYTE)pThisMasterRecord >
  2756. (LPBYTE)pLog->lpMappedFileBase);
  2757. assert ((LPBYTE)pThisMasterRecord <
  2758. ((LPBYTE)pLog->lpMappedFileBase +
  2759. pLog->llFileSize));
  2760. pThisSubRecord = PdhiGetSubRecord (
  2761. pThisMasterRecord, dwIndex);
  2762. assert (pThisSubRecord != NULL);
  2763. assert (pThisSubRecord->dwType == BINLOG_TYPE_DATA_MULTI);
  2764. if (pThisSubRecord == NULL) {
  2765. // bail on a null record
  2766. pdhStatus = PDH_END_OF_LOG_FILE;
  2767. break;
  2768. }
  2769. pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)
  2770. ((LPBYTE)pThisSubRecord +
  2771. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  2772. // walk down list of entries and add them to the
  2773. // list of instances (these should already
  2774. // be assembled in parent/instance format)
  2775. if (pDataBlock->dwLength > 0) {
  2776. for (dwDataItemIndex = 0;
  2777. dwDataItemIndex < pDataBlock->dwItemCount;
  2778. dwDataItemIndex++) {
  2779. pDataItem = &pDataBlock->pItemArray[dwDataItemIndex];
  2780. szThisInstanceName = (LPWSTR)
  2781. (((LPBYTE) pDataBlock) + pDataItem->szName);
  2782. pdhStatus = PdhiFindInstance(
  2783. & pInstList->InstList,
  2784. szThisInstanceName,
  2785. TRUE,
  2786. & pInstance);
  2787. }
  2788. } else {
  2789. // no data in this record
  2790. }
  2791. if (pdhStatus != ERROR_SUCCESS) {
  2792. // then exit loop, otherwise
  2793. break;
  2794. } else {
  2795. // go to next record in log
  2796. pdhStatus = PdhiReadOneBinLogRecord(
  2797. pLog, ++dwThisRecordIndex, NULL, 0);
  2798. }
  2799. }
  2800. if (pdhStatus == PDH_END_OF_LOG_FILE) {
  2801. pdhStatus = ERROR_SUCCESS;
  2802. }
  2803. if (pdhStatus == ERROR_SUCCESS) {
  2804. bProcessInstance = TRUE;
  2805. }
  2806. }
  2807. }
  2808. }
  2809. memset (szCompositeInstance, 0, (sizeof(szCompositeInstance)));
  2810. }
  2811. // get next path entry from log file record
  2812. dwBytesProcessed += pPath->dwLength;
  2813. pPath = (PPDHI_LOG_COUNTER_PATH) ((LPBYTE)pPath + pPath->dwLength);
  2814. }
  2815. if ((nItemCount > 0) && (pdhStatus != PDH_INSUFFICIENT_BUFFER)
  2816. && (pdhStatus != PDH_MORE_DATA)) {
  2817. // then the routine was successful. Errors that occurred
  2818. // while scanning will be ignored as long as at least
  2819. // one entry was successfully read
  2820. pdhStatus = ERROR_SUCCESS;
  2821. }
  2822. }
  2823. if (pTempBuffer != NULL) G_FREE (pTempBuffer);
  2824. return pdhStatus;
  2825. }
  2826. PDH_FUNCTION
  2827. PdhiGetMatchingBinaryLogRecord (
  2828. IN PPDHI_LOG pLog,
  2829. IN LONGLONG *pStartTime,
  2830. IN LPDWORD pdwIndex
  2831. )
  2832. {
  2833. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  2834. DWORD dwRecordId;
  2835. LONGLONG RecordTimeValue;
  2836. LONGLONG LastTimeValue = 0;
  2837. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  2838. PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
  2839. PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
  2840. PPDH_RAW_COUNTER pRawItem;
  2841. // read the first data record in the log file
  2842. // note that the record read is not copied to the local buffer
  2843. // rather the internal buffer is used in "read-only" mode
  2844. // if the high dword of the time value is 0xFFFFFFFF, then the
  2845. // low dword is the record id to read
  2846. if ((*pStartTime & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000) {
  2847. dwRecordId = (DWORD)(*pStartTime & 0x00000000FFFFFFFF);
  2848. LastTimeValue = *pStartTime;
  2849. if (dwRecordId == 0) return PDH_ENTRY_NOT_IN_LOG_FILE;
  2850. } else {
  2851. dwRecordId = BINLOG_FIRST_DATA_RECORD;
  2852. }
  2853. pdhStatus = PdhiReadOneBinLogRecord (
  2854. pLog,
  2855. dwRecordId,
  2856. NULL,
  2857. 0); // to prevent copying the record
  2858. while ((pdhStatus == ERROR_SUCCESS) && (dwRecordId >= BINLOG_FIRST_DATA_RECORD)) {
  2859. // define pointer to the current record
  2860. pThisMasterRecord =
  2861. (PPDHI_BINARY_LOG_RECORD_HEADER)
  2862. pLog->pLastRecordRead;
  2863. // get timestamp of this record by looking at the first entry in the
  2864. // record.
  2865. assert (pThisMasterRecord->dwType == BINLOG_TYPE_DATA);
  2866. pThisSubRecord =
  2867. (PPDHI_BINARY_LOG_RECORD_HEADER)((LPBYTE)pThisMasterRecord +
  2868. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  2869. switch (pThisSubRecord->dwType) {
  2870. case BINLOG_TYPE_DATA_SINGLE:
  2871. pRawItem = (PPDH_RAW_COUNTER)((LPBYTE)pThisSubRecord +
  2872. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  2873. RecordTimeValue = MAKELONGLONG(
  2874. pRawItem->TimeStamp.dwLowDateTime,
  2875. pRawItem->TimeStamp.dwHighDateTime);
  2876. break;
  2877. case BINLOG_TYPE_DATA_MULTI:
  2878. pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)((LPBYTE)pThisSubRecord +
  2879. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  2880. RecordTimeValue = *(LONGLONG *)&pDataBlock->TimeStamp;
  2881. break;
  2882. default:
  2883. // unknown record type
  2884. assert (FALSE);
  2885. RecordTimeValue = 0;
  2886. break;
  2887. }
  2888. if (RecordTimeValue != 0) {
  2889. if ((*pStartTime == RecordTimeValue) || (*pStartTime == 0)) {
  2890. // found the match so bail here
  2891. LastTimeValue = RecordTimeValue;
  2892. break;
  2893. } else if (RecordTimeValue > *pStartTime) {
  2894. // then this is the first record > than the desired time
  2895. // so the desired value is the one before this one
  2896. // unless it's the first data record of the log
  2897. if (dwRecordId > BINLOG_FIRST_DATA_RECORD) {
  2898. dwRecordId--;
  2899. } else {
  2900. // this hasnt' been initialized yet.
  2901. LastTimeValue = RecordTimeValue;
  2902. }
  2903. break;
  2904. } else {
  2905. // save value for next trip through loop
  2906. LastTimeValue = RecordTimeValue;
  2907. // advance record counter and try the next entry
  2908. dwRecordId++;
  2909. }
  2910. } else {
  2911. // no timestamp field so ignore this record.
  2912. dwRecordId++;
  2913. }
  2914. // read the next record in the file
  2915. pdhStatus = PdhiReadOneBinLogRecord (
  2916. pLog,
  2917. dwRecordId,
  2918. NULL,
  2919. 1); // to prevent copying the record
  2920. }
  2921. if (pdhStatus == ERROR_SUCCESS) {
  2922. // then dwRecordId is the desired entry
  2923. *pdwIndex = dwRecordId;
  2924. *pStartTime = LastTimeValue;
  2925. pdhStatus = ERROR_SUCCESS;
  2926. } else if (dwRecordId < BINLOG_FIRST_DATA_RECORD) {
  2927. // handle special cases for log type field and header record
  2928. *pdwIndex = dwRecordId;
  2929. *pStartTime = LastTimeValue;
  2930. pdhStatus = ERROR_SUCCESS;
  2931. } else {
  2932. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  2933. }
  2934. return pdhStatus;
  2935. }
  2936. PDH_FUNCTION
  2937. PdhiGetCounterFromDataBlock(
  2938. IN PPDHI_LOG pLog,
  2939. IN PVOID pDataBuffer,
  2940. IN PPDHI_COUNTER pCounter);
  2941. PDH_FUNCTION
  2942. PdhiGetCounterValueFromBinaryLog (
  2943. IN PPDHI_LOG pLog,
  2944. IN DWORD dwIndex,
  2945. IN PPDHI_COUNTER pCounter
  2946. )
  2947. {
  2948. PDH_STATUS pdhStatus;
  2949. PPDH_RAW_COUNTER pValue = & pCounter->ThisValue;
  2950. // read the first data record in the log file
  2951. // note that the record read is not copied to the local buffer
  2952. // rather the internal buffer is used in "read-only" mode
  2953. pdhStatus = PdhiReadOneBinLogRecord(pLog, dwIndex, NULL, 0);
  2954. if (pdhStatus == ERROR_SUCCESS) {
  2955. pdhStatus = PdhiGetCounterFromDataBlock(pLog,
  2956. pLog->pLastRecordRead,
  2957. pCounter);
  2958. } else {
  2959. // no more records in log file
  2960. pdhStatus = PDH_NO_MORE_DATA;
  2961. // unable to find entry in the log file
  2962. pValue->CStatus = PDH_CSTATUS_INVALID_DATA;
  2963. pValue->TimeStamp.dwLowDateTime = pValue->TimeStamp.dwHighDateTime = 0;
  2964. pValue->FirstValue = 0;
  2965. pValue->SecondValue = 0;
  2966. pValue->MultiCount = 1;
  2967. }
  2968. return pdhStatus;
  2969. }
  2970. PDH_FUNCTION
  2971. PdhiGetTimeRangeFromBinaryLog (
  2972. IN PPDHI_LOG pLog,
  2973. IN LPDWORD pdwNumEntries,
  2974. IN PPDH_TIME_INFO pInfo,
  2975. IN LPDWORD pdwBufferSize
  2976. )
  2977. /*++
  2978. the first entry in the buffer returned is the total time range covered
  2979. in the file, if there are multiple time blocks in the log file, then
  2980. subsequent entries will identify each segment in the file.
  2981. --*/
  2982. {
  2983. PDH_STATUS pdhStatus;
  2984. LONGLONG llStartTime = MAX_TIME_VALUE;
  2985. LONGLONG llEndTime = MIN_TIME_VALUE;
  2986. LONGLONG llThisTime = (LONGLONG)0;
  2987. DWORD dwThisRecord = BINLOG_FIRST_DATA_RECORD;
  2988. DWORD dwValidEntries = 0;
  2989. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  2990. PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
  2991. PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
  2992. PPDH_RAW_COUNTER pRawItem;
  2993. // read the first data record in the log file
  2994. // note that the record read is not copied to the local buffer
  2995. // rather the internal buffer is used in "read-only" mode
  2996. pdhStatus = PdhiReadOneBinLogRecord (
  2997. pLog,
  2998. dwThisRecord,
  2999. NULL, 0); // to prevent copying the record
  3000. while (pdhStatus == ERROR_SUCCESS) {
  3001. // define pointer to the current record
  3002. pThisMasterRecord =
  3003. (PPDHI_BINARY_LOG_RECORD_HEADER)
  3004. pLog->pLastRecordRead;
  3005. // get timestamp of this record by looking at the first entry in the
  3006. // record.
  3007. assert ((pThisMasterRecord->dwType & 0x0000FFFF) == BINLOG_START_WORD);
  3008. if ((pThisMasterRecord->dwType & BINLOG_TYPE_DATA) == BINLOG_TYPE_DATA) {
  3009. // only evaluate data records
  3010. pThisSubRecord =
  3011. (PPDHI_BINARY_LOG_RECORD_HEADER)((LPBYTE)pThisMasterRecord +
  3012. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  3013. switch (pThisSubRecord->dwType) {
  3014. case BINLOG_TYPE_DATA_SINGLE:
  3015. pRawItem = (PPDH_RAW_COUNTER)((LPBYTE)pThisSubRecord +
  3016. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  3017. llThisTime = MAKELONGLONG(
  3018. pRawItem->TimeStamp.dwLowDateTime,
  3019. pRawItem->TimeStamp.dwHighDateTime);
  3020. break;
  3021. case BINLOG_TYPE_DATA_MULTI:
  3022. pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)((LPBYTE)pThisSubRecord +
  3023. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  3024. llThisTime = MAKELONGLONG(
  3025. pDataBlock->TimeStamp.dwLowDateTime,
  3026. pDataBlock->TimeStamp.dwHighDateTime);
  3027. break;
  3028. default:
  3029. // unknown record type
  3030. assert (FALSE);
  3031. llThisTime = 0;
  3032. break;
  3033. }
  3034. } else {
  3035. llThisTime = 0;
  3036. }
  3037. if (llThisTime > 0) {
  3038. if (llThisTime < llStartTime) {
  3039. llStartTime = llThisTime;
  3040. }
  3041. if (llThisTime > llEndTime) {
  3042. llEndTime = llThisTime;
  3043. }
  3044. dwValidEntries++;
  3045. } else {
  3046. // no timestamp field so ignore this record.
  3047. }
  3048. // read the next record in the file
  3049. pdhStatus = PdhiReadOneBinLogRecord (
  3050. pLog,
  3051. ++dwThisRecord,
  3052. NULL, 0); // to prevent copying the record
  3053. }
  3054. if (pdhStatus == PDH_END_OF_LOG_FILE) {
  3055. // clear out any temp values
  3056. if (llStartTime == MAX_TIME_VALUE) llStartTime = 0;
  3057. if (llEndTime == MIN_TIME_VALUE) llEndTime = 0;
  3058. // then the whole file was read so update the args.
  3059. if (*pdwBufferSize >= sizeof(PDH_TIME_INFO)) {
  3060. *(LONGLONG *)(&pInfo->StartTime) = llStartTime;
  3061. *(LONGLONG *)(&pInfo->EndTime) = llEndTime;
  3062. pInfo->SampleCount = dwValidEntries;
  3063. *pdwBufferSize = sizeof(PDH_TIME_INFO);
  3064. *pdwNumEntries = 1;
  3065. } else {
  3066. pdhStatus = PDH_MORE_DATA;
  3067. }
  3068. pdhStatus = ERROR_SUCCESS;
  3069. } else {
  3070. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  3071. }
  3072. return pdhStatus;
  3073. }
  3074. PDH_FUNCTION
  3075. PdhiReadRawBinaryLogRecord (
  3076. IN PPDHI_LOG pLog,
  3077. IN FILETIME *ftRecord,
  3078. IN PPDH_RAW_LOG_RECORD pBuffer,
  3079. IN LPDWORD pdwBufferLength
  3080. )
  3081. {
  3082. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  3083. LONGLONG llStartTime;
  3084. DWORD dwIndex = 0;
  3085. DWORD dwSizeRequired;
  3086. DWORD dwLocalRecordLength; // including terminating NULL
  3087. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  3088. llStartTime = *(LONGLONG *)ftRecord;
  3089. pdhStatus = PdhiGetMatchingBinaryLogRecord (
  3090. pLog,
  3091. &llStartTime,
  3092. &dwIndex);
  3093. // copy results from internal log buffer if it'll fit.
  3094. if (pdhStatus == ERROR_SUCCESS) {
  3095. if (dwIndex != BINLOG_TYPE_ID_RECORD) {
  3096. // then record is a Binary log type
  3097. pThisMasterRecord =
  3098. (PPDHI_BINARY_LOG_RECORD_HEADER)pLog->pLastRecordRead;
  3099. dwLocalRecordLength = pThisMasterRecord
  3100. ? pThisMasterRecord->dwLength : 0;
  3101. } else {
  3102. // this is a fixed size
  3103. dwLocalRecordLength = pLog->dwRecord1Size;
  3104. }
  3105. dwSizeRequired =
  3106. sizeof (PDH_RAW_LOG_RECORD) - sizeof (UCHAR)
  3107. + dwLocalRecordLength;
  3108. if (*pdwBufferLength >= dwSizeRequired) {
  3109. pBuffer->dwRecordType = (DWORD)(LOWORD(pLog->dwLogFormat));
  3110. pBuffer->dwItems = dwLocalRecordLength;
  3111. // copy it
  3112. if (dwLocalRecordLength > 0) {
  3113. RtlCopyMemory(&pBuffer->RawBytes[0], pLog->pLastRecordRead,
  3114. dwLocalRecordLength);
  3115. }
  3116. pBuffer->dwStructureSize = dwSizeRequired;
  3117. } else {
  3118. pdhStatus = PDH_MORE_DATA;
  3119. }
  3120. *pdwBufferLength = dwSizeRequired;
  3121. }
  3122. return pdhStatus;
  3123. }
  3124. PDH_FUNCTION
  3125. PdhiListHeaderFromBinaryLog (
  3126. IN PPDHI_LOG pLogFile,
  3127. IN LPVOID pBufferArg,
  3128. IN LPDWORD pcchBufferSize,
  3129. IN BOOL bUnicodeDest
  3130. )
  3131. {
  3132. LPVOID pTempBuffer = NULL;
  3133. LPVOID pOldBuffer;
  3134. DWORD dwTempBufferSize;
  3135. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  3136. // read the header record and enum the machine name from the entries
  3137. if (pLogFile->dwMaxRecordSize == 0) {
  3138. // no size is defined so start with 64K
  3139. pLogFile->dwMaxRecordSize = 0x010000;
  3140. }
  3141. dwTempBufferSize = pLogFile->dwMaxRecordSize;
  3142. pTempBuffer = G_ALLOC (dwTempBufferSize);
  3143. assert (pTempBuffer != NULL);
  3144. if (pTempBuffer == NULL) {
  3145. assert (GetLastError() == ERROR_SUCCESS);
  3146. return PDH_MEMORY_ALLOCATION_FAILURE;
  3147. }
  3148. // read in the catalog record
  3149. while ((pdhStatus = PdhiReadOneBinLogRecord (pLogFile, BINLOG_HEADER_RECORD,
  3150. pTempBuffer, dwTempBufferSize)) != ERROR_SUCCESS) {
  3151. if (pdhStatus == PDH_MORE_DATA) {
  3152. // read the 1st WORD to see if this is a valid record
  3153. if (*(WORD *)pTempBuffer == BINLOG_START_WORD) {
  3154. // it's a valid record so read the 2nd DWORD to get the
  3155. // record size;
  3156. dwTempBufferSize = ((DWORD *)pTempBuffer)[1];
  3157. if (dwTempBufferSize < pLogFile->dwMaxRecordSize) {
  3158. // then something is bogus so return an error
  3159. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  3160. break; // out of while loop
  3161. } else {
  3162. pLogFile->dwMaxRecordSize = dwTempBufferSize;
  3163. }
  3164. } else {
  3165. // we're lost in this file
  3166. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  3167. break; // out of while loop
  3168. }
  3169. // realloc a new buffer
  3170. pOldBuffer = pTempBuffer;
  3171. pTempBuffer = G_REALLOC (pOldBuffer, dwTempBufferSize);
  3172. if (pTempBuffer == NULL) {
  3173. // return memory error
  3174. G_FREE(pOldBuffer);
  3175. assert (GetLastError() == ERROR_SUCCESS);
  3176. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  3177. break;
  3178. }
  3179. } else {
  3180. // some other error was returned so
  3181. // return error from read function
  3182. break;
  3183. }
  3184. }
  3185. if (pdhStatus == ERROR_SUCCESS) {
  3186. // walk down list and copy strings to msz buffer
  3187. PPDHI_LOG_COUNTER_PATH pPath;
  3188. DWORD dwBytesProcessed;
  3189. LONG nItemCount = 0;
  3190. LPBYTE pFirstChar;
  3191. PDH_COUNTER_PATH_ELEMENTS_W pdhPathElem;
  3192. WCHAR szPathString[1024];
  3193. DWORD dwRecordLength;
  3194. DWORD dwBufferUsed = 0;
  3195. DWORD dwNewBuffer = 0;
  3196. // we can assume the record was read successfully so read in the
  3197. // machine names
  3198. dwRecordLength = ((PPDHI_BINARY_LOG_RECORD_HEADER)pTempBuffer)->dwLength;
  3199. pPath = (PPDHI_LOG_COUNTER_PATH)
  3200. ((LPBYTE)pTempBuffer + sizeof (PDHI_BINARY_LOG_HEADER_RECORD));
  3201. dwBytesProcessed = sizeof(PDHI_BINARY_LOG_HEADER_RECORD);
  3202. while (dwBytesProcessed < dwRecordLength) {
  3203. if (pPath->lMachineNameOffset >= 0L) {
  3204. // then there's a machine name in this record so get
  3205. // it's size
  3206. memset (&pdhPathElem, 0, sizeof(pdhPathElem));
  3207. pFirstChar = (LPBYTE)&pPath->Buffer[0];
  3208. if (pPath->lMachineNameOffset >= 0) {
  3209. pdhPathElem.szMachineName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lMachineNameOffset);
  3210. }
  3211. if (pPath->lObjectNameOffset >= 0) {
  3212. pdhPathElem.szObjectName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lObjectNameOffset);
  3213. }
  3214. if (pPath->lInstanceOffset >= 0) {
  3215. pdhPathElem.szInstanceName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lInstanceOffset);
  3216. }
  3217. if (pPath->lParentOffset >= 0) {
  3218. pdhPathElem.szParentInstance = (LPWSTR)((LPBYTE)pFirstChar + pPath->lParentOffset);
  3219. }
  3220. if (pPath->dwIndex == 0) {
  3221. // don't display #0 in path
  3222. pdhPathElem.dwInstanceIndex = (DWORD)-1;
  3223. } else {
  3224. pdhPathElem.dwInstanceIndex = pPath->dwIndex;
  3225. }
  3226. if (pPath->lCounterOffset >= 0) {
  3227. pdhPathElem.szCounterName = (LPWSTR)((LPBYTE)pFirstChar + pPath->lCounterOffset);
  3228. }
  3229. dwNewBuffer = sizeof (szPathString) / sizeof(szPathString[0]);
  3230. pdhStatus = PdhMakeCounterPathW (
  3231. &pdhPathElem,
  3232. szPathString,
  3233. &dwNewBuffer,
  3234. 0);
  3235. if (pdhStatus == ERROR_SUCCESS) {
  3236. if (pBufferArg != NULL) {
  3237. // copy string to the buffer
  3238. if ((dwBufferUsed + dwNewBuffer) < *pcchBufferSize) {
  3239. dwNewBuffer = AddUniqueWideStringToMultiSz (
  3240. (LPVOID)pBufferArg,
  3241. szPathString,
  3242. bUnicodeDest);
  3243. } else {
  3244. // this one won't fit, so set the status
  3245. pdhStatus = PDH_MORE_DATA;
  3246. // and update the size required to return
  3247. // add in size of the delimiter
  3248. dwNewBuffer++;
  3249. // update the size of the string required
  3250. dwNewBuffer = dwBufferUsed + dwNewBuffer;
  3251. nItemCount++;
  3252. }
  3253. if (dwNewBuffer > 0) {
  3254. // string was added so update size used.
  3255. dwBufferUsed = dwNewBuffer;
  3256. nItemCount++;
  3257. }
  3258. } else {
  3259. // add in size of the delimiter
  3260. dwNewBuffer++;
  3261. // add size of this string to the size required
  3262. dwBufferUsed += dwNewBuffer;
  3263. nItemCount++;
  3264. }
  3265. } // else ignore this entry
  3266. }
  3267. // get next path entry from log file record
  3268. dwBytesProcessed += pPath->dwLength;
  3269. pPath = (PPDHI_LOG_COUNTER_PATH)
  3270. ((LPBYTE)pPath + pPath->dwLength);
  3271. }
  3272. if ((nItemCount > 0) && (pdhStatus != PDH_INSUFFICIENT_BUFFER)
  3273. && (pdhStatus != PDH_MORE_DATA)) {
  3274. // then the routine was successful. Errors that occurred
  3275. // while scanning will be ignored as long as at least
  3276. // one entry was successfully read
  3277. pdhStatus = ERROR_SUCCESS;
  3278. }
  3279. if (pBufferArg == NULL) {
  3280. // add in size of MSZ null;
  3281. // (AddUnique... already includes this in the return value
  3282. dwBufferUsed++;
  3283. }
  3284. // update the buffer used or required.
  3285. *pcchBufferSize = dwBufferUsed;
  3286. }
  3287. if (pTempBuffer != NULL) G_FREE (pTempBuffer);
  3288. return pdhStatus;
  3289. }
  3290. PDH_FUNCTION
  3291. PdhiGetCounterArrayFromBinaryLog (
  3292. IN PPDHI_LOG pLog,
  3293. IN DWORD dwIndex,
  3294. IN PPDHI_COUNTER pCounter,
  3295. IN OUT PPDHI_RAW_COUNTER_ITEM_BLOCK *ppValue
  3296. )
  3297. {
  3298. PDH_STATUS pdhStatus;
  3299. DWORD dwDataItemIndex;
  3300. PPDHI_BINARY_LOG_RECORD_HEADER pThisMasterRecord;
  3301. PPDHI_BINARY_LOG_RECORD_HEADER pThisSubRecord;
  3302. PPDHI_RAW_COUNTER_ITEM_BLOCK pDataBlock;
  3303. PPDHI_RAW_COUNTER_ITEM_BLOCK pNewArrayHeader;
  3304. // allocate a new array for
  3305. // update counter's Current counter array contents
  3306. // read the first data record in the log file
  3307. // note that the record read is not copied to the local buffer
  3308. // rather the internal buffer is used in "read-only" mode
  3309. pdhStatus = PdhiReadOneBinLogRecord (
  3310. pLog,
  3311. dwIndex,
  3312. NULL, 0); // to prevent copying the record
  3313. if (pdhStatus == ERROR_SUCCESS) {
  3314. // define pointer to the current record
  3315. pThisMasterRecord =
  3316. (PPDHI_BINARY_LOG_RECORD_HEADER)
  3317. pLog->pLastRecordRead;
  3318. // get timestamp of this record by looking at the first entry in the
  3319. // record.
  3320. if (pThisMasterRecord->dwType != BINLOG_TYPE_DATA) return PDH_NO_MORE_DATA;
  3321. pThisSubRecord = PdhiGetSubRecord (
  3322. pThisMasterRecord,
  3323. pCounter->plCounterInfo.dwCounterId);
  3324. if (pThisSubRecord != NULL) {
  3325. switch (pThisSubRecord->dwType) {
  3326. case BINLOG_TYPE_DATA_SINGLE:
  3327. // return data as one instance
  3328. // for now this isn't supported as it won't be hit.
  3329. //
  3330. break;
  3331. case BINLOG_TYPE_DATA_MULTI:
  3332. // cast pointer to this part of the data record
  3333. pDataBlock = (PPDHI_RAW_COUNTER_ITEM_BLOCK)((LPBYTE)pThisSubRecord +
  3334. sizeof (PDHI_BINARY_LOG_RECORD_HEADER));
  3335. // allocate a new buffer for the data
  3336. pNewArrayHeader = (PPDHI_RAW_COUNTER_ITEM_BLOCK) G_ALLOC (pDataBlock->dwLength);
  3337. if (pNewArrayHeader != NULL) {
  3338. // copy the log record to the local buffer
  3339. RtlCopyMemory(pNewArrayHeader, pDataBlock, pDataBlock->dwLength);
  3340. // convert offsets to pointers
  3341. for (dwDataItemIndex = 0;
  3342. dwDataItemIndex < pNewArrayHeader->dwItemCount;
  3343. dwDataItemIndex++) {
  3344. // add in the address of the base of the structure
  3345. // to the offset stored in the field
  3346. pNewArrayHeader->pItemArray[dwDataItemIndex].szName =
  3347. pNewArrayHeader->pItemArray[dwDataItemIndex].szName;
  3348. }
  3349. // clear any old buffers
  3350. if (pCounter->pThisRawItemList != NULL) {
  3351. G_FREE(pCounter->pThisRawItemList);
  3352. pCounter->pThisRawItemList = NULL;
  3353. }
  3354. pCounter->pThisRawItemList = pNewArrayHeader;
  3355. *ppValue = pNewArrayHeader;
  3356. } else {
  3357. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  3358. }
  3359. break;
  3360. default:
  3361. pdhStatus = PDH_LOG_TYPE_NOT_FOUND;
  3362. break;
  3363. }
  3364. } else {
  3365. // entry not found in record
  3366. pdhStatus = PDH_ENTRY_NOT_IN_LOG_FILE;
  3367. }
  3368. } else {
  3369. // no more records in log file
  3370. pdhStatus = PDH_NO_MORE_DATA;
  3371. }
  3372. return pdhStatus;
  3373. }