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.

1103 lines
42 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. ReLog.c
  5. Abstract:
  6. Program to test relogging to a log file
  7. Author:
  8. Bob Watson (bobw) 2-apr-97
  9. Revision History:
  10. --*/
  11. #include <windows.h>
  12. #include <tchar.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <pdh.h>
  17. #include <pdhmsg.h>
  18. #include "resource.h"
  19. #include "varg.c"
  20. #include "relog.h"
  21. /*
  22. LPCTSTR cszInputSwitch = (LPCTSTR)TEXT("/input:");
  23. LPCTSTR cszOutputSwitch = (LPCTSTR)TEXT("/output:");
  24. LPCTSTR cszSettingsSwitch = (LPCTSTR)TEXT("/settings:");
  25. LPCTSTR cszLogtypeSwitch = (LPCTSTR)TEXT("/logtype:");
  26. LPCTSTR cszFilterSwitch = (LPCTSTR)TEXT("/filter:");
  27. LPCTSTR cszStartTime = (LPCTSTR)TEXT("/starttime:");
  28. LPCTSTR cszEndTime = (LPCTSTR)TEXT("/endtime:");
  29. LPCTSTR cszListSwitch = (LPCTSTR)TEXT("/list");
  30. LPCTSTR cszAppendSwitch = (LPCTSTR)TEXT("/append");
  31. */
  32. VARG_RECORD Commands[] = {
  33. VARG_HELP( VARG_FLAG_OPTIONAL )
  34. VARG_BOOL( IDS_PARAM_APPEND, VARG_FLAG_OPTIONAL, FALSE )
  35. VARG_STR ( IDS_PARAM_COUNTERFILE, VARG_FLAG_OPTIONAL, _T("") )
  36. VARG_STR ( IDS_PARAM_FORMAT,VARG_FLAG_OPTIONAL,_T("BLG") )
  37. VARG_MSZ ( IDS_PARAM_INPUT, VARG_FLAG_REQUIRED|VARG_FLAG_NOFLAG, _T("") )
  38. VARG_INT ( IDS_PARAM_INTERVAL, VARG_FLAG_OPTIONAL, 0 )
  39. VARG_TIME( IDS_PARAM_BEGIN, VARG_FLAG_OPTIONAL|VARG_FLAG_ARG_TIME )
  40. VARG_TIME( IDS_PARAM_END, VARG_FLAG_OPTIONAL|VARG_FLAG_ARG_TIME )
  41. VARG_STR ( IDS_PARAM_OUTPUT, VARG_FLAG_OPTIONAL, _T("") )
  42. VARG_BOOL( IDS_PARAM_QUERY, VARG_FLAG_OPTIONAL, FALSE )
  43. VARG_TERMINATOR
  44. };
  45. enum _Commands {
  46. eHelp,
  47. eAppend,
  48. eCounters,
  49. eFormat,
  50. eInput,
  51. eInterval,
  52. eBegin,
  53. eEnd,
  54. eOutput,
  55. eQuery
  56. };
  57. LPCTSTR cszBinType = (LPCTSTR)TEXT("bin");
  58. LPCTSTR cszBlgType = (LPCTSTR)TEXT("blg");
  59. LPCTSTR cszCsvType = (LPCTSTR)TEXT("csv");
  60. LPCTSTR cszTsvType = (LPCTSTR)TEXT("tsv");
  61. LPCSTR cszBinLogFileHeader = "\"(PDH-BIN 4.0)\"\n";
  62. LPCSTR cszTextRecordTerminator = "\n";
  63. //LPCTSTR cszRelogVersionStr = (LPCWSTR)TEXT(RELOG_VERSION_ID);
  64. #define TextRecordTerminatorSize 1 // size of the string above
  65. FILE *fSettingsFile = NULL;
  66. #define DBG_SHOW_STATUS_PRINTS 1
  67. #define DBG_NO_STATUS_PRINTS 0
  68. DWORD dwDbgPrintLevel = DBG_NO_STATUS_PRINTS;
  69. #define ALLOW_REOPEN_OF_SETTINGS_FILE FALSE
  70. // assume string format of YYYY-MM-DD-hh:mm:ss
  71. // 0123456789012345678
  72. // value is index of the first char of that field
  73. #define DATE_STRING_LENGTH 19
  74. #define DATE_SECONDS_OFFSET 17
  75. #define DATE_MINUTES_OFFSET 14
  76. #define DATE_HOURS_OFFSET 11
  77. #define DATE_DAYS_OFFSET 8
  78. #define DATE_MONTH_OFFSET 5
  79. #define NORMAL_MODE 1
  80. #define LIST_MODE 2
  81. #define SUMMARY_MODE 3
  82. #define APPEND_MODE 4
  83. #define HEADER_MODE 5
  84. // structures lifted from pdh\log_bin.h
  85. typedef struct _PDHI_BINARY_LOG_RECORD_HEADER {
  86. DWORD dwType;
  87. DWORD dwLength;
  88. } PDHI_BINARY_LOG_RECORD_HEADER, *PPDHI_BINARY_LOG_RECORD_HEADER;
  89. //
  90. // the first data record after the log file type record is
  91. // an information record followed by the list of counters contained in this
  92. // log file. the record length is the size of the info header record and
  93. // all the counter info blocks in bytes.
  94. // note that this record can occur later in the log file if the query
  95. // is changed or the log file is appended.
  96. //
  97. typedef struct _PDHI_BINARY_LOG_INFO {
  98. LONGLONG FileLength; // file space allocated (optional)
  99. DWORD dwLogVersion; // version stamp
  100. DWORD dwFlags; // option flags
  101. LONGLONG StartTime;
  102. LONGLONG EndTime;
  103. LONGLONG CatalogOffset; // offset in file to wild card catalog
  104. LONGLONG CatalogChecksum; // checksum of catalog header
  105. LONGLONG CatalogDate; // date/time catalog was updated
  106. LONGLONG FirstRecordOffset; // pointer to first record [to read] in log
  107. LONGLONG LastRecordOffset; // pointer to last record [to read] in log
  108. LONGLONG NextRecordOffset; // pointer to where next one goes
  109. LONGLONG WrapOffset; // pointer to last byte used in file
  110. LONGLONG LastUpdateTime; // date/time last record was written
  111. LONGLONG FirstDataRecordOffset; // location of first data record in file
  112. // makes the info struct 256 bytes
  113. // and leaves room for future information
  114. DWORD dwReserved[38];
  115. } PDHI_BINARY_LOG_INFO, *PPDHI_BINARY_LOG_INFO;
  116. typedef struct _PDHI_BINARY_LOG_HEADER_RECORD {
  117. PDHI_BINARY_LOG_RECORD_HEADER RecHeader;
  118. PDHI_BINARY_LOG_INFO Info;
  119. } PDHI_BINARY_LOG_HEADER_RECORD, *PPDHI_BINARY_LOG_HEADER_RECORD;
  120. // new but unexported pdh functions
  121. // these will need to be moved to the PDH.H file
  122. // in the final shipped version
  123. #ifdef UNICODE
  124. PDH_FUNCTION
  125. PdhListLogFileHeaderW (
  126. IN LPCWSTR szFileName,
  127. IN LPWSTR mszHeaderList,
  128. IN LPDWORD pcchHeaderListSize
  129. );
  130. #define PdhListLogFileHeader PdhListLogFileHeaderW
  131. #else //ANSI
  132. PDH_FUNCTION
  133. PdhListLogFileHeaderA (
  134. IN LPCSTR szFileName,
  135. IN LPSTR mszHeaderList,
  136. IN LPDWORD pcchHeaderListSize
  137. );
  138. #define PdhListLogFileHeader PdhListLogFileHeaderA
  139. #endif
  140. DWORD
  141. GetOutputLogType( LPTSTR str )
  142. {
  143. DWORD dwLogType = PDH_LOG_TYPE_CSV;
  144. if (_tcscmp(str, cszBinType) == 0) {
  145. dwLogType = PDH_LOG_TYPE_BINARY;
  146. } else if (_tcscmp(str, cszBlgType) == 0) {
  147. dwLogType = PDH_LOG_TYPE_BINARY;
  148. } else if (_tcscmp(str, cszCsvType) == 0) {
  149. dwLogType = PDH_LOG_TYPE_CSV;
  150. } else if (_tcscmp(str, cszTsvType) == 0) {
  151. dwLogType = PDH_LOG_TYPE_TSV;
  152. } else {
  153. // return unknown
  154. dwLogType = PDH_LOG_TYPE_UNDEFINED;
  155. }
  156. return dwLogType;
  157. }
  158. DWORD
  159. DoListMode (
  160. LPCTSTR szInputFile,
  161. LPCTSTR szOutputFile
  162. )
  163. {
  164. // BUGBUG: note these should be dynamically allocated
  165. LPTSTR szReturnBuffer;
  166. TCHAR szMachineList[32768];
  167. TCHAR szWildPath[32768];
  168. // end bugbug
  169. PDH_STATUS pdhStatus;
  170. DWORD dwBufSize;
  171. DWORD dwMlSize;
  172. LPTSTR szThisString;
  173. LPTSTR szThisMachine;
  174. FILE *fOut = NULL;
  175. DWORD dwNumEntries;
  176. PDH_TIME_INFO pInfo[2];
  177. DWORD dwBufferSize = (sizeof(pInfo));
  178. SYSTEMTIME stLogTime;
  179. dwMlSize = sizeof(szMachineList) / sizeof(szMachineList[0]);
  180. pdhStatus = PdhEnumMachines (
  181. szInputFile,
  182. szMachineList,
  183. &dwMlSize);
  184. if ((pdhStatus == ERROR_SUCCESS) && (dwMlSize > 0)) {
  185. if (*szOutputFile == 0) {
  186. fOut = stdout;
  187. } else {
  188. fOut = _tfopen (szOutputFile, (LPCTSTR)TEXT("wt"));
  189. }
  190. pdhStatus = PdhGetDataSourceTimeRange (
  191. szInputFile,
  192. &dwNumEntries,
  193. &pInfo[0],
  194. &dwBufferSize);
  195. if (pdhStatus == ERROR_SUCCESS) {
  196. _ftprintf(fOut, (LPCTSTR)TEXT("\nLogfile: \"%s\" contains %d Records."), szInputFile, pInfo[0].SampleCount);
  197. // write time range out to file
  198. FileTimeToSystemTime ((FILETIME *)(&pInfo[0].StartTime), &stLogTime);
  199. _ftprintf(fOut, (LPCTSTR)TEXT("\n Start Time: %4.4d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d"),
  200. stLogTime.wYear, stLogTime.wMonth, stLogTime.wDay,
  201. stLogTime.wHour, stLogTime.wMinute, stLogTime.wSecond);
  202. FileTimeToSystemTime ((FILETIME *)(&pInfo[0].EndTime), &stLogTime);
  203. _ftprintf(fOut, (LPCTSTR)TEXT("\n End Time: %4.4d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d"),
  204. stLogTime.wYear, stLogTime.wMonth, stLogTime.wDay,
  205. stLogTime.wHour, stLogTime.wMinute, stLogTime.wSecond);
  206. }
  207. for (szThisMachine = szMachineList;
  208. *szThisMachine != 0;
  209. szThisMachine += _tcsclen(szThisMachine)) {
  210. if (*szThisMachine != _T('\\')) {
  211. _tcscpy (szWildPath, (LPCTSTR)TEXT("\\\\"));
  212. _tcscat (szWildPath, szThisMachine);
  213. _tcscat (szWildPath, (LPCTSTR)TEXT("\\*(*)\\*"));
  214. } else {
  215. _tcscpy (szWildPath, szThisMachine);
  216. _tcscat (szWildPath, (LPCTSTR)TEXT("\\*(*)\\*"));
  217. }
  218. dwBufSize = 512000;
  219. szReturnBuffer = HeapAlloc (GetProcessHeap(),
  220. HEAP_ZERO_MEMORY,
  221. dwBufSize * sizeof(TCHAR));
  222. if (szReturnBuffer != NULL) {
  223. pdhStatus = PdhExpandWildCardPath (
  224. szInputFile,
  225. szWildPath,
  226. szReturnBuffer,
  227. &dwBufSize,
  228. 0);
  229. if (dwBufSize != 0) {
  230. if (fOut == stdout) {
  231. _ftprintf (fOut, (LPCTSTR)TEXT("\nCounters contained in \"%s\":\n"), szInputFile);
  232. }
  233. for (szThisString = szReturnBuffer;
  234. *szThisString != 0;
  235. szThisString += _tcsclen(szThisString) + 1) {
  236. _ftprintf (fOut, (LPCTSTR)TEXT("%s\n"), szThisString);
  237. }
  238. } else {
  239. _tprintf ((LPCTSTR)TEXT("\nError 0x%8.8x (%d) returned from enumeration of machine %s in %s"),
  240. pdhStatus, (DWORD)(pdhStatus & 0x0000FFFF),
  241. szThisMachine,
  242. szInputFile);
  243. }
  244. HeapFree (GetProcessHeap(), 0, szReturnBuffer);
  245. }
  246. }
  247. } else {
  248. // unable to list log file contents
  249. _tprintf ((LPCTSTR)TEXT("\nError 0x%8.8x (%d) returned from enumeration of %s"),
  250. pdhStatus, (DWORD)(pdhStatus & 0x0000FFFF),
  251. szInputFile);
  252. }
  253. return ERROR_SUCCESS;
  254. }
  255. DWORD
  256. DoHeaderListMode (
  257. LPCTSTR szInputFile,
  258. LPCTSTR szOutputFile
  259. )
  260. {
  261. // end bugbug
  262. PDH_STATUS pdhStatus;
  263. LPTSTR szThisString;
  264. FILE *fOut = NULL;
  265. DWORD dwType = 0L;
  266. HLOG hLog = NULL;
  267. LPTSTR mszHeaderList;
  268. DWORD cchHeaderListSize = 0x80000; // 512K
  269. DWORD dwNumEntries;
  270. PDH_TIME_INFO pInfo[2];
  271. DWORD dwBufferSize = (sizeof(pInfo));
  272. SYSTEMTIME stLogTime;
  273. mszHeaderList = (LPTSTR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cchHeaderListSize * sizeof(TCHAR));
  274. if (mszHeaderList != NULL) {
  275. pdhStatus = PdhListLogFileHeader (
  276. szInputFile,
  277. mszHeaderList,
  278. &cchHeaderListSize);
  279. if (pdhStatus == ERROR_SUCCESS) {
  280. if (*szOutputFile == 0) {
  281. fOut = stdout;
  282. } else {
  283. fOut = _tfopen (szOutputFile, (LPCTSTR)TEXT("wt"));
  284. }
  285. pdhStatus = PdhGetDataSourceTimeRange (
  286. szInputFile,
  287. &dwNumEntries,
  288. &pInfo[0],
  289. &dwBufferSize);
  290. if (pdhStatus == ERROR_SUCCESS) {
  291. _ftprintf(fOut, (LPCTSTR)TEXT("\nLogfile: \"%s\" contains %d Records."), szInputFile, pInfo[0].SampleCount);
  292. // write time range out to file
  293. FileTimeToSystemTime ((FILETIME *)(&pInfo[0].StartTime), &stLogTime);
  294. _ftprintf(fOut, (LPCTSTR)TEXT("\n Start Time: %4.4d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d"),
  295. stLogTime.wYear, stLogTime.wMonth, stLogTime.wDay,
  296. stLogTime.wHour, stLogTime.wMinute, stLogTime.wSecond);
  297. FileTimeToSystemTime ((FILETIME *)(&pInfo[0].EndTime), &stLogTime);
  298. _ftprintf(fOut, (LPCTSTR)TEXT("\n End Time: %4.4d-%2.2d-%2.2d-%2.2d:%2.2d:%2.2d"),
  299. stLogTime.wYear, stLogTime.wMonth, stLogTime.wDay,
  300. stLogTime.wHour, stLogTime.wMinute, stLogTime.wSecond);
  301. }
  302. if (fOut == stdout) {
  303. _ftprintf (fOut, (LPCTSTR)TEXT("\nCounters contained in %s\n"), szInputFile);
  304. }
  305. for (szThisString = mszHeaderList;
  306. *szThisString != 0;
  307. szThisString += _tcsclen(szThisString) + 1) {
  308. _ftprintf (fOut, (LPCTSTR)TEXT("%s\n"), szThisString);
  309. }
  310. } else {
  311. // unable to list log file contents
  312. _tprintf ((LPCTSTR)TEXT("\nError 0x%8.8x (%d) returned from enumeration of %s"),
  313. pdhStatus, (DWORD)(pdhStatus & 0x0000FFFF),
  314. szInputFile);
  315. }
  316. HeapFree (GetProcessHeap(), HEAP_ZERO_MEMORY, mszHeaderList);
  317. }
  318. return ERROR_SUCCESS;
  319. }
  320. HRESULT GetCountersFromFile( HQUERY hQuery )
  321. {
  322. TCHAR buffer[MAXSTR];
  323. HCOUNTER pCounter;
  324. HRESULT hr;
  325. LPTSTR strCounter = NULL;
  326. FILE* f = _tfopen( Commands[eCounters].strValue, _T("r") );
  327. if( !f ){
  328. return GetLastError();
  329. }
  330. while( NULL != _fgetts( buffer, MAXSTR, f ) ){
  331. if( buffer[0] == ';' || // comments
  332. buffer[0] == '#' ){
  333. continue;
  334. }
  335. Chomp(buffer);
  336. strCounter = _tcstok( buffer, _T("\"\n") );
  337. if( strCounter != NULL ){
  338. hr = PdhAddCounter(
  339. hQuery,
  340. buffer,
  341. 0,
  342. &pCounter
  343. );
  344. }
  345. }
  346. fclose( f );
  347. return ERROR_SUCCESS;
  348. }
  349. DWORD
  350. DoNormalMode (
  351. LPCTSTR szInputFile,
  352. LPCTSTR szOutputFile,
  353. LPCTSTR szSettingsFile,
  354. DWORD dwOutputLogType,
  355. PDH_TIME_INFO pdhTimeInfo,
  356. DWORD dwFilterCount
  357. )
  358. {
  359. DWORD dwNumOutputCounters = 0;
  360. DWORD dwRecCount = 0;
  361. DWORD dwFiltered;
  362. LONG Status = ERROR_SUCCESS;
  363. PDH_STATUS PdhStatus;
  364. PDH_RAW_COUNTER RawValue;
  365. LPTSTR szCounterPath = NULL;
  366. HQUERY hQuery = NULL;
  367. HLOG hOutLog = NULL;
  368. HLOG hInLog = NULL;
  369. HCOUNTER hCounter = NULL;
  370. HCOUNTER hLastGoodCounter = NULL;
  371. DWORD dwType;
  372. DWORD dwOpenMode;
  373. LPTSTR szReturnBuffer;
  374. TCHAR szMachineList[32768];
  375. TCHAR szWildPath[32768];
  376. // end bugbug
  377. PDH_STATUS pdhStatus;
  378. DWORD dwBufSize;
  379. DWORD dwMlSize;
  380. LPTSTR szThisString;
  381. LPTSTR szThisMachine;
  382. FILE *fOut = NULL;
  383. if (Status == ERROR_SUCCESS) {
  384. _tprintf ((LPCTSTR)TEXT("\nRelogging: \"%s\" to \"%s\""), szInputFile, szOutputFile);
  385. PdhStatus = PdhOpenQuery (szInputFile, 0L, &hQuery);
  386. if (PdhStatus != ERROR_SUCCESS) {
  387. Status = PdhStatus;
  388. _tprintf ((LPCTSTR)TEXT("\nPdhOpenQuery returned: 0x%8.8x (%d)"), PdhStatus, PdhStatus);
  389. }
  390. }
  391. if (Status == ERROR_SUCCESS) {
  392. if (*szSettingsFile == 0) {
  393. if (dwOutputLogType == PDH_LOG_TYPE_BINARY) {
  394. // load all counters from input file into query
  395. LPTSTR mszHeaderList;
  396. DWORD cchHeaderListSize = 0x80000; // 512K
  397. mszHeaderList = (LPTSTR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cchHeaderListSize * sizeof(TCHAR));
  398. if (mszHeaderList != NULL) {
  399. PdhStatus = PdhListLogFileHeader (
  400. szInputFile,
  401. mszHeaderList,
  402. &cchHeaderListSize);
  403. if (PdhStatus == ERROR_SUCCESS) {
  404. // we can recycle the hCounter value since we don't need it for anything after this.
  405. for (szCounterPath = mszHeaderList;
  406. *szCounterPath != 0;
  407. szCounterPath += _tcsclen(szCounterPath) + 1) {
  408. PdhStatus = PdhAddCounter (hQuery, szCounterPath, 0L, &hCounter);
  409. if (PdhStatus != ERROR_SUCCESS) {
  410. _tprintf ((LPCTSTR)TEXT("\nUnable to add \"%s\", error: 0x%8.8x (%d)"), szCounterPath, PdhStatus, PdhStatus);
  411. } else {
  412. hLastGoodCounter = hCounter;
  413. dwNumOutputCounters++;
  414. if (dwDbgPrintLevel == DBG_SHOW_STATUS_PRINTS) {
  415. _tprintf ((LPCTSTR)TEXT("\nRelogging \"%s\""), szCounterPath);
  416. }
  417. }
  418. }
  419. }
  420. HeapFree (GetProcessHeap(), 0, mszHeaderList);
  421. }
  422. } else {
  423. // enumerate each counter for all non-binary log types
  424. dwMlSize = sizeof(szMachineList) / sizeof(szMachineList[0]);
  425. pdhStatus = PdhEnumMachines (
  426. szInputFile,
  427. szMachineList,
  428. &dwMlSize);
  429. if ((pdhStatus == ERROR_SUCCESS) && (dwMlSize > 0)) {
  430. for (szThisMachine = szMachineList;
  431. *szThisMachine != 0;
  432. szThisMachine += _tcsclen(szThisMachine)) {
  433. if (*szThisMachine != _T('\\')) {
  434. _tcscpy (szWildPath, (LPCTSTR)TEXT("\\\\"));
  435. _tcscat (szWildPath, szThisMachine);
  436. _tcscat (szWildPath, (LPCTSTR)TEXT("\\*(*)\\*"));
  437. } else {
  438. _tcscpy (szWildPath, szThisMachine);
  439. _tcscat (szWildPath, (LPCTSTR)TEXT("\\*(*)\\*"));
  440. }
  441. dwBufSize = 512000;
  442. szReturnBuffer = HeapAlloc (GetProcessHeap(),
  443. HEAP_ZERO_MEMORY,
  444. dwBufSize * sizeof(TCHAR));
  445. if (szReturnBuffer != NULL) {
  446. pdhStatus = PdhExpandWildCardPath (
  447. szInputFile,
  448. szWildPath,
  449. szReturnBuffer,
  450. &dwBufSize,
  451. 0);
  452. if (dwBufSize != 0) {
  453. for (szThisString = szReturnBuffer;
  454. *szThisString != 0;
  455. szThisString += _tcsclen(szThisString) + 1) {
  456. PdhStatus = PdhAddCounter (hQuery, szThisString, 0L, &hCounter);
  457. if (PdhStatus != ERROR_SUCCESS) {
  458. _tprintf ((LPCTSTR)TEXT("\nUnable to add \"%s\", error: 0x%8.8x (%d)"), szThisString, PdhStatus, PdhStatus);
  459. } else {
  460. hLastGoodCounter = hCounter;
  461. dwNumOutputCounters++;
  462. if (dwDbgPrintLevel == DBG_SHOW_STATUS_PRINTS) {
  463. _tprintf ((LPCTSTR)TEXT("\nAdded \"%s\", error: 0x%8.8x (%d)"), szThisString, PdhStatus, PdhStatus);
  464. }
  465. }
  466. }
  467. }
  468. HeapFree (GetProcessHeap(), 0, szReturnBuffer);
  469. } else {
  470. // unable to allocate memory
  471. PdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  472. }
  473. } // end for each machine in the log file
  474. } else {
  475. // unable to list machines
  476. // return PDH status
  477. }
  478. }
  479. } else {
  480. // we can recycle the hCounter value since we don't need it for anything after this.
  481. GetCountersFromFile( hQuery );
  482. }
  483. }
  484. if ((Status == ERROR_SUCCESS) && (dwNumOutputCounters > 0)) {
  485. dwOpenMode = PDH_LOG_WRITE_ACCESS | PDH_LOG_CREATE_ALWAYS;
  486. PdhStatus = PdhOpenLog (szOutputFile,
  487. dwOpenMode,
  488. &dwOutputLogType,
  489. hQuery,
  490. 0L,
  491. NULL,
  492. &hOutLog);
  493. if (PdhStatus != ERROR_SUCCESS) {
  494. Status = PdhStatus;
  495. _tprintf ((LPCTSTR)TEXT("\nUnable to open \"%s\" for output, error: 0x%8.8x (%d)"), szOutputFile, PdhStatus, PdhStatus);
  496. } else {
  497. // set query range
  498. PdhStatus = PdhSetQueryTimeRange (hQuery, &pdhTimeInfo);
  499. // copy log data to output log
  500. PdhStatus = PdhUpdateLog (hOutLog, NULL);
  501. while (PdhStatus == ERROR_SUCCESS) {
  502. dwRecCount++;
  503. dwFiltered = 1;
  504. while ((dwFiltered < dwFilterCount) && (PdhStatus == ERROR_SUCCESS)) {
  505. PdhStatus = PdhCollectQueryData(hQuery);
  506. if (PdhStatus == ERROR_SUCCESS) {
  507. PdhStatus = PdhGetRawCounterValue (
  508. hLastGoodCounter,
  509. &dwType,
  510. &RawValue);
  511. if (PdhStatus == ERROR_SUCCESS) {
  512. // check for bogus timestamps as an inidcation we ran off the end of the file
  513. if ((*(LONGLONG *)&RawValue.TimeStamp == 0) ||
  514. (*(LONGLONG *)&RawValue.TimeStamp >= pdhTimeInfo.EndTime)){
  515. PdhStatus = PDH_END_OF_LOG_FILE;
  516. }
  517. }
  518. }
  519. dwFiltered++;
  520. }
  521. if (PdhStatus == ERROR_SUCCESS) {
  522. PdhStatus = PdhUpdateLog (hOutLog, NULL);
  523. }
  524. }
  525. // PdhStatus should be either PDH_END_OF_LOG_FILE or PDH_NO_MORE_DATA when
  526. // the loop above exits, if that's the case then reset status to SUCCESS
  527. // otherwise display the error
  528. if ((PdhStatus == PDH_END_OF_LOG_FILE) || (PdhStatus == PDH_NO_MORE_DATA)) {
  529. PdhStatus = ERROR_SUCCESS;
  530. } else {
  531. printf ("\nPdhUpdateLog returned: 0x%8.8x (%d)", PdhStatus, PdhStatus);
  532. }
  533. // update log catalog while we're at it
  534. //
  535. // BUGBUG: For now this isn't working very well so this step
  536. // will be skipped until it works better (5.1 maybe?)
  537. /*
  538. if (dwOutputLogType == PDH_LOG_TYPE_BINARY) {
  539. PdhStatus = PdhUpdateLogFileCatalog (hOutLog);
  540. if (PdhStatus != ERROR_SUCCESS) {
  541. Status = PdhStatus;
  542. _tprintf ((LPCTSTR)TEXT("\nPdhUpdateLogFileCatalog returned: 0x%8.8x (%d)"), PdhStatus, PdhStatus);
  543. }
  544. }
  545. */
  546. PdhStatus = PdhCloseLog (hOutLog, 0L);
  547. if (PdhStatus != ERROR_SUCCESS) {
  548. Status = PdhStatus;
  549. printf ("\nPdhCloseLog returned: 0x%8.8x (%d)", PdhStatus, PdhStatus);
  550. } else {
  551. hOutLog = NULL;
  552. }
  553. }
  554. }
  555. if (hQuery != NULL) {
  556. PdhStatus = PdhCloseQuery (hQuery);
  557. if (PdhStatus != ERROR_SUCCESS) {
  558. Status = PdhStatus;
  559. printf ("\nPdhCloseLog returned: 0x%8.8x (%d)", PdhStatus, PdhStatus);
  560. } else {
  561. hQuery = NULL;
  562. hCounter = NULL;
  563. }
  564. }
  565. if (Status == ERROR_SUCCESS) {
  566. _tprintf ((LPCTSTR)TEXT("\n%d records from %s have been relogged to %s"), dwRecCount, szInputFile, szOutputFile);
  567. }
  568. return Status;
  569. }
  570. DWORD
  571. DoAppendFiles (
  572. IN LPCTSTR szAppendFile,
  573. IN LPCTSTR szBaseFile,
  574. IN DWORD dwFilterCount
  575. )
  576. /*
  577. append data records from Append file to base file if they
  578. contain the same counter data
  579. (and hopefully append file starts after base file)
  580. */
  581. {
  582. HANDLE hTempFile;
  583. TCHAR szTempFileName[MAX_PATH];
  584. TCHAR szTempDirPath[MAX_PATH];
  585. DWORD dwReturn = ERROR_SUCCESS;
  586. PDH_STATUS pdhStatus;
  587. DWORD dwFiltered;
  588. DWORD dwAppendLogType;
  589. DWORD dwBaseLogType;
  590. HLOG hAppendLogFile;
  591. HLOG hBaseLogFile;
  592. LPTSTR mszBaseFileHeader;
  593. DWORD cchBaseFileHeaderSize;
  594. LPTSTR mszAppendFileHeader;
  595. DWORD cchAppendFileHeaderSize;
  596. PPDH_RAW_LOG_RECORD pRawRecord;
  597. DWORD dwRecordBuffSize;
  598. DWORD dwRecordSize;
  599. DWORD dwRecordIdx;
  600. BOOL bStatus;
  601. DWORD dwBytesWritten;
  602. PPDHI_BINARY_LOG_HEADER_RECORD pBinLogHead;
  603. FILETIME ftValue;
  604. DWORD dwLogRecType;
  605. BOOL bIsDataRecord;
  606. // see if the file headers match
  607. // read headers of log files
  608. cchBaseFileHeaderSize = 0x80000;
  609. mszBaseFileHeader = (LPTSTR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cchBaseFileHeaderSize * sizeof(TCHAR));
  610. if (mszBaseFileHeader != NULL) {
  611. pdhStatus = PdhListLogFileHeader (
  612. szBaseFile,
  613. mszBaseFileHeader,
  614. &cchBaseFileHeaderSize);
  615. if (pdhStatus == ERROR_SUCCESS) {
  616. cchAppendFileHeaderSize = 0x80000;
  617. mszAppendFileHeader = (LPTSTR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cchAppendFileHeaderSize * sizeof(TCHAR));
  618. if (mszAppendFileHeader != NULL) {
  619. pdhStatus = PdhListLogFileHeader (
  620. szAppendFile,
  621. mszAppendFileHeader,
  622. &cchAppendFileHeaderSize);
  623. if (pdhStatus == ERROR_SUCCESS) {
  624. // compare buffers
  625. if (cchAppendFileHeaderSize == cchBaseFileHeaderSize) {
  626. if (memcmp(mszAppendFileHeader, mszBaseFileHeader, cchBaseFileHeaderSize) == 0) {
  627. // same
  628. pdhStatus = ERROR_SUCCESS;
  629. } else {
  630. // different
  631. _tprintf ((LPCTSTR)TEXT("\nInput file counter list is different from that of the output file."));
  632. pdhStatus = ERROR_DATATYPE_MISMATCH;
  633. }
  634. } else {
  635. _tprintf ((LPCTSTR)TEXT("\nInput file counter list is different from that of the output file."));
  636. // different sizes
  637. pdhStatus = ERROR_DATATYPE_MISMATCH;
  638. }
  639. } else {
  640. // unable to read append file
  641. _tprintf ((LPCTSTR)TEXT("\nUnable to read the input file header."));
  642. }
  643. HeapFree (GetProcessHeap(), HEAP_ZERO_MEMORY, mszAppendFileHeader);
  644. } else {
  645. _tprintf ((LPCTSTR)TEXT("\nUnable to allocate an internal memory buffer."));
  646. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  647. }
  648. } else {
  649. // unable to read base file header
  650. _tprintf ((LPCTSTR)TEXT("\nUnable to read the output file header."));
  651. }
  652. HeapFree (GetProcessHeap(), HEAP_ZERO_MEMORY, mszBaseFileHeader);
  653. } else {
  654. pdhStatus = PDH_MEMORY_ALLOCATION_FAILURE;
  655. }
  656. if (pdhStatus == ERROR_SUCCESS) {
  657. // the files have matching headers so get ready to copy them
  658. // create temporary output file name
  659. GetTempPath (MAX_PATH, szTempDirPath);
  660. GetTempFileName (szTempDirPath, (LPCTSTR)TEXT("PDH"), 0, szTempFileName);
  661. hTempFile = CreateFile (
  662. szTempFileName,
  663. GENERIC_READ | GENERIC_WRITE,
  664. 0,
  665. NULL,
  666. OPEN_EXISTING, // the file is created by GetTempFileName above (go figure)
  667. FILE_ATTRIBUTE_NORMAL,
  668. NULL);
  669. if (hTempFile != INVALID_HANDLE_VALUE) {
  670. // open log files
  671. pdhStatus = PdhOpenLog (
  672. szBaseFile,
  673. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  674. &dwBaseLogType,
  675. NULL,
  676. 0,
  677. NULL,
  678. &hBaseLogFile);
  679. if (pdhStatus == ERROR_SUCCESS) {
  680. pdhStatus = PdhOpenLog (
  681. szAppendFile,
  682. PDH_LOG_READ_ACCESS | PDH_LOG_OPEN_EXISTING,
  683. &dwAppendLogType,
  684. NULL,
  685. 0,
  686. NULL,
  687. &hAppendLogFile);
  688. if (pdhStatus == ERROR_SUCCESS) {
  689. dwRecordIdx = 1;
  690. ftValue.dwHighDateTime = 0xFFFFFFFF;
  691. ftValue.dwLowDateTime = dwRecordIdx;
  692. dwRecordBuffSize = 0x80000;
  693. pRawRecord = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, dwRecordBuffSize);
  694. if (pRawRecord != NULL) {
  695. dwFiltered = 1;
  696. // write headers from first file to temp file
  697. while (pdhStatus == ERROR_SUCCESS) {
  698. ftValue.dwHighDateTime = 0xFFFFFFFF;
  699. ftValue.dwLowDateTime = dwRecordIdx;
  700. dwRecordSize = dwRecordBuffSize;
  701. pdhStatus = PdhReadRawLogRecord (
  702. hBaseLogFile,
  703. ftValue,
  704. pRawRecord,
  705. &dwRecordSize);
  706. if (pdhStatus == ERROR_SUCCESS) {
  707. bIsDataRecord = TRUE;
  708. if (dwRecordIdx == 1) {
  709. bIsDataRecord = FALSE;
  710. } else if ((dwRecordIdx == 2) && (pRawRecord->dwRecordType == PDH_LOG_TYPE_BINARY)) {
  711. pBinLogHead = (PPDHI_BINARY_LOG_HEADER_RECORD)&pRawRecord->RawBytes[0];
  712. // only linear files can be appended
  713. if (pBinLogHead->Info.WrapOffset == 0) {
  714. // now fix up the fields in the header so they'll work
  715. // with the new combined file
  716. pBinLogHead->Info.FileLength = 0; // file space allocated (optional)
  717. pBinLogHead->Info.CatalogOffset = 0; // the catalog is removed
  718. pBinLogHead->Info.CatalogChecksum = 0;
  719. pBinLogHead->Info.CatalogDate = 0; // date/time catalog was updated
  720. //pBinLogHead->Info.FirstRecordOffset = 0; // pointer to first record [to read] in log
  721. pBinLogHead->Info.LastRecordOffset = 0; // pointer to last record [to read] in log
  722. pBinLogHead->Info.NextRecordOffset = 0; // pointer to where next one goes
  723. pBinLogHead->Info.WrapOffset = 0; // pointer to last byte used in file
  724. pBinLogHead->Info.LastUpdateTime = 0; // date/time last record was written
  725. pBinLogHead->Info.FirstDataRecordOffset = 0; // location of first data record in file
  726. } else {
  727. // file is circular so bail
  728. pdhStatus = PDH_UNKNOWN_LOG_FORMAT;
  729. }
  730. bIsDataRecord = FALSE;
  731. }
  732. if (pdhStatus == ERROR_SUCCESS) {
  733. // write the first 2 records of the base file
  734. // then only the data records after that
  735. if ((dwRecordIdx > 2) && (pRawRecord->dwRecordType == PDH_LOG_TYPE_BINARY)) {
  736. // it must be a data record or else skip it
  737. dwLogRecType = *((LPDWORD)&pRawRecord->RawBytes[0]);
  738. if ((dwLogRecType & 0x00FF0000) != 0x00030000) {
  739. // then this is not a data record
  740. // so skip it and get next record
  741. dwRecordIdx++;
  742. continue;
  743. }
  744. }
  745. if ((!bIsDataRecord) || (dwFiltered == dwFilterCount)) {
  746. // write the record to the output file
  747. bStatus = WriteFile (
  748. hTempFile,
  749. &pRawRecord->RawBytes[0],
  750. pRawRecord->dwItems,
  751. &dwBytesWritten,
  752. NULL);
  753. if (!bStatus || (dwBytesWritten != pRawRecord->dwItems)) {
  754. pdhStatus = GetLastError();
  755. } else {
  756. // reset the count
  757. dwFiltered = 1;
  758. }
  759. } else {
  760. // skip this one
  761. if (bIsDataRecord) dwFiltered += 1;
  762. }
  763. // get next record
  764. dwRecordIdx++;
  765. }
  766. } else if (pdhStatus == PDH_INSUFFICIENT_BUFFER) {
  767. // BUGBUG: expand and retry
  768. } else {
  769. if ((pdhStatus == PDH_END_OF_LOG_FILE) || (pdhStatus == PDH_ENTRY_NOT_IN_LOG_FILE)) {
  770. // fix up return codes to continue
  771. pdhStatus = ERROR_SUCCESS;
  772. } else {
  773. _tprintf ((LPCTSTR)TEXT("\n ReadRaw returned %d (0x%8.8x)"), pdhStatus, pdhStatus);
  774. }
  775. // bail
  776. break;
  777. }
  778. }
  779. // add records from new file
  780. if (pdhStatus == ERROR_SUCCESS) {
  781. dwRecordIdx = 1;
  782. ftValue.dwHighDateTime = 0xFFFFFFFF;
  783. ftValue.dwLowDateTime = dwRecordIdx;
  784. if (pRawRecord != NULL) {
  785. // write headers from first file to temp file
  786. while (pdhStatus == ERROR_SUCCESS) {
  787. ftValue.dwHighDateTime = 0xFFFFFFFF;
  788. ftValue.dwLowDateTime = dwRecordIdx;
  789. dwRecordSize = dwRecordBuffSize;
  790. pdhStatus = PdhReadRawLogRecord (
  791. hAppendLogFile,
  792. ftValue,
  793. pRawRecord,
  794. &dwRecordSize);
  795. if (pdhStatus == ERROR_SUCCESS) {
  796. bIsDataRecord = TRUE;
  797. if (dwRecordIdx == 1) {
  798. bIsDataRecord = FALSE;
  799. } else if ((dwRecordIdx == 2) && (pRawRecord->dwRecordType == PDH_LOG_TYPE_BINARY)) {
  800. // write only the data records to the output file
  801. // if this isn't the first record, then it must be a data record or
  802. // or else skip it
  803. dwLogRecType = *((LPDWORD)&pRawRecord->RawBytes[0]);
  804. if ((pRawRecord->dwRecordType == PDH_LOG_TYPE_BINARY) &&
  805. ((dwLogRecType & 0x00FF0000) != 0x00030000)) {
  806. // then this is not a data record
  807. // so skip it and get next record
  808. dwRecordIdx++;
  809. continue;
  810. }
  811. }
  812. if ((!bIsDataRecord) || (dwFiltered == dwFilterCount)) {
  813. bStatus = WriteFile (
  814. hTempFile,
  815. &pRawRecord->RawBytes[0],
  816. pRawRecord->dwItems,
  817. &dwBytesWritten,
  818. NULL);
  819. if (!bStatus || (dwBytesWritten != pRawRecord->dwItems)) {
  820. pdhStatus = GetLastError();
  821. } else {
  822. // reset the count
  823. dwFiltered = 1;
  824. }
  825. } else {
  826. // skip this one
  827. if (bIsDataRecord) dwFiltered += 1;
  828. }
  829. // get next record
  830. dwRecordIdx++;
  831. } else if (pdhStatus == PDH_INSUFFICIENT_BUFFER) {
  832. // BUGBUG: expand and retry
  833. } else {
  834. if ((pdhStatus == PDH_END_OF_LOG_FILE) || (pdhStatus == PDH_ENTRY_NOT_IN_LOG_FILE)) {
  835. // fix up return codes to continue
  836. pdhStatus = ERROR_SUCCESS;
  837. } else {
  838. _tprintf ((LPCTSTR)TEXT("\n ReadRaw returned %d (0x%8.8x)"), pdhStatus, pdhStatus);
  839. }
  840. // bail
  841. break;
  842. }
  843. }
  844. } else {
  845. // no buffer
  846. }
  847. }
  848. // clean up
  849. PdhCloseLog (hAppendLogFile,0);
  850. PdhCloseLog (hBaseLogFile,0);
  851. CloseHandle (hTempFile);
  852. // shuffle the files around to make it look like it was appended
  853. if (pdhStatus == ERROR_SUCCESS) {
  854. if (CopyFile (szTempFileName, szBaseFile, FALSE)) {
  855. DeleteFile (szTempFileName);
  856. }
  857. }
  858. } else {
  859. // alloc fail
  860. _tprintf ((LPCTSTR)TEXT("\nUnable to allocate temporary memory buffer."));
  861. }
  862. } else {
  863. //unable to open new file for reading
  864. _tprintf ((LPCTSTR)TEXT("\nUnable to open input file for reading."));
  865. dwReturn = pdhStatus;
  866. PdhCloseLog (hBaseLogFile,0);
  867. CloseHandle (hTempFile);
  868. DeleteFile (szTempFileName);
  869. }
  870. } else {
  871. //unable to open base file for reading
  872. _tprintf ((LPCTSTR)TEXT("\nUnable to open output file for reading."));
  873. dwReturn = pdhStatus;
  874. CloseHandle (hTempFile);
  875. DeleteFile (szTempFileName);
  876. }
  877. } else {
  878. // unable to create temp file
  879. _tprintf ((LPCTSTR)TEXT("\nUnable to create temporary file in temp dir."));
  880. dwReturn = GetLastError();
  881. }
  882. } else {
  883. dwReturn = pdhStatus;
  884. }
  885. return dwReturn;
  886. }
  887. int
  888. __cdecl
  889. wmain(
  890. int argc,
  891. _TCHAR *argv[]
  892. )
  893. /*
  894. relog
  895. /Input:<filename>
  896. /Output:<filename>
  897. /Settings:<settings filename>
  898. /Logtype:[BIN|BLG|TSV|CSV]
  899. /StartTime:yyyy-mm-dd-hh:mm:ss
  900. /EndTime;yyyy-mm-dd-hh:mm:ss
  901. /Filter:n
  902. */
  903. {
  904. LONG Status = ERROR_SUCCESS;
  905. DWORD dwOutputLogType = PDH_LOG_TYPE_UNDEFINED;
  906. DWORD dwFilterCount = 1;
  907. DWORD dwMode = NORMAL_MODE;
  908. PDH_TIME_INFO pdhTimeInfo;
  909. DWORD dwPdhVersion = 0;
  910. ParseCmd( argc, argv );
  911. Status = PdhGetDllVersion (&dwPdhVersion);
  912. dwOutputLogType = GetOutputLogType( Commands[eFormat].strValue );
  913. pdhTimeInfo.StartTime = 0;
  914. pdhTimeInfo.EndTime = 0;
  915. if( Commands[eBegin].bDefined ){
  916. FILETIME ft;
  917. SystemTimeToFileTime( &Commands[eBegin].stValue, &ft );
  918. pdhTimeInfo.StartTime = *(LONGLONG *)&ft;
  919. }
  920. if( Commands[eEnd].bDefined ){
  921. FILETIME ft;
  922. SystemTimeToFileTime( &Commands[eEnd].stValue, &ft );
  923. pdhTimeInfo.EndTime = *(LONGLONG *)&ft;
  924. }
  925. pdhTimeInfo.SampleCount = 0;
  926. // szXXXFile cannot be NULL at this point!
  927. if ( Commands[eQuery].bValue ) {
  928. dwMode = LIST_MODE;
  929. } else if (Commands[eAppend].bValue ) {
  930. dwMode = APPEND_MODE;
  931. }
  932. if (Status == ERROR_SUCCESS) {
  933. switch (dwMode) {
  934. case HEADER_MODE:
  935. Status = DoHeaderListMode (
  936. Commands[eInput].strValue,
  937. Commands[eOutput].strValue);
  938. break;
  939. case LIST_MODE:
  940. Status = DoListMode (
  941. Commands[eInput].strValue,
  942. Commands[eOutput].strValue);
  943. break;
  944. case APPEND_MODE:
  945. Status = DoAppendFiles (
  946. Commands[eInput].strValue,
  947. Commands[eOutput].strValue,
  948. Commands[eInterval].nValue );
  949. break;
  950. case NORMAL_MODE:
  951. default:
  952. Status = DoNormalMode (
  953. Commands[eInput].strValue,
  954. Commands[eOutput].strValue,
  955. Commands[eCounters].strValue,
  956. dwOutputLogType,
  957. pdhTimeInfo,
  958. Commands[eInterval].nValue);
  959. break;
  960. }
  961. }
  962. return Status;
  963. }