Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2699 lines
81 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: common.cxx
  4. //
  5. // Contents: The common methods for logsvr and the log sub-projects
  6. //
  7. // Classes: LOGCLASS Actually, this is a macroname that is defined
  8. // at compile time
  9. //
  10. // Functions: DelString(PCHAR *)
  11. // LOGCLASS ::InitLogging(VOID)
  12. // LOGCLASS ::FreeLogging(VOID)
  13. // LOGCLASS ::SetLogFile(VOID)
  14. // LOGCLASS ::AddComponent(PCHAR, PCHAR)
  15. // LOGCLASS ::SetEventCount(VOID)
  16. // LOGCLASS ::LogOpen(VOID)
  17. // LOGCLASS ::OpenLogFile(VOID)
  18. // LOGCLASS ::LogData(VOID)
  19. // LOGCLASS ::WriteToLogFile(VOID)
  20. // LOGCLASS ::WriteHeader(VOID)
  21. // LOGCLASS ::WriteBinItem(CHAR, PVOID, USHORT)
  22. // LOGCLASS ::CheckDir(PCHAR)
  23. // LOGCLASS ::NewString(PCHAR *, CPPSZ)
  24. // LOGCLASS ::SetInfo(CPPSZ, CPPSZ, CPPSZ, CPPSZ)
  25. // LOGCLASS ::SetStrData(PCHAR, va_list)
  26. // LOGCLASS ::CloseLogFile(VOID)
  27. // LOGCLASS ::SetBinData(USHORT, PVOID)
  28. // LOGCLASS ::LogPrintf(HANDLE, PCHAR, ...)
  29. // LOGCLASS ::FlushLogFile(USHORT)
  30. // LOGCLASS ::SetIsComPort(CPPSZ)
  31. // LOGCLASS ::LogEventCountVOID)
  32. //
  33. // History: 26-Sep-90 DaveWi Initial Coding
  34. // 18-Oct-90 DaveWi Redesigned to be #included in log.cxx
  35. // and logsvr.cxx.
  36. // 25-Sep-91 BryanT Converted to C 7.0
  37. // 14-Oct-91 SarahJ DCR 527 - changed WriteBinItem to not
  38. // pad length argument to fixed length
  39. // 30-Oct-91 SarahJ removed def for CCHMAXPATH
  40. // 30-Oct-91 SarahJ removed addition of 11 spaces after event
  41. // count for no purpose in LogEventCount
  42. // 14-Nov-91 SarahJ replaced code to pad the event count
  43. // with spaces as it has a purpose! Also
  44. // explained padding in comment with code.
  45. // 09-Feb-92 BryanT Win32 work and general cleanup.
  46. // 16-Jul-92 DeanE Added wchar string support by changing
  47. // vsprintf to w4vsprintf
  48. // BUGBUG - the above addition may still
  49. // not work because the string formed is
  50. // then processed by non wchar functions
  51. // 1-Aug-92 DwightKr Renamed CPCHAR as CPPSZ. CPCHAR
  52. // conflicted with the 297 version of
  53. // windows.h
  54. // 17-Sep-92 SarahJ Bug fixes and memory usage improvements
  55. // 30-Oct-92 Sarahj Removed the use of pszTester from mn:
  56. // or elsewhere
  57. //
  58. //--------------------------------------------------------------------
  59. #include <pch.cxx>
  60. // BUGBUG Precompiled header does not work on Alpha for some unknown reason and
  61. // so we temporarily remove it.
  62. // #pragma hdrstop
  63. VOID DelString(PCHAR *psz);
  64. VOID DelString(LPWSTR *wsz);
  65. #define LOGCLASS Log
  66. //
  67. // The SEEK_TO macro takes two different arguments. Either FILE_BEGIN
  68. // which makes it seek to the beginning of the file or FILE_END where
  69. // it seeks to the end.
  70. //
  71. #define SEEK_TO(n) \
  72. ((fIsComPort==FALSE && \
  73. ~0 == SetFilePointer(hLogFile,0,NULL,(n)) ? -1 : NO_ERROR))
  74. #define COUNT_BUFLEN 12 // Buf len for logged data len buffer
  75. #define SLASH_STRING "\\"
  76. #define wSLASH_STRING L"\\"
  77. //+-------------------------------------------------------------------
  78. //
  79. // Function: DelString(PCHAR *)
  80. //
  81. // Synopsis: Given a pointer to a string, delete the memory if necessary
  82. // and set the pointer to NULL
  83. //
  84. // Arguments: [pszOrig] Original string to delete
  85. //
  86. // Returns: <nothing>
  87. //
  88. // History: ??-???-?? ???????? Created
  89. //
  90. //--------------------------------------------------------------------
  91. VOID DelString(PCHAR *pszOrig)
  92. {
  93. if (*pszOrig != NULL)
  94. {
  95. delete *pszOrig;
  96. *pszOrig = NULL;
  97. }
  98. }
  99. //+-------------------------------------------------------------------
  100. //
  101. // Function: DelString(LPWSTR *)
  102. //
  103. // Synopsis: Given a pointer to a string, delete the memory if necessary
  104. // and set the pointer to NULL
  105. //
  106. // Arguments: [wszOrig] Original string to delete
  107. //
  108. // Returns: <nothing>
  109. //
  110. // History: ??-???-?? ???????? Created
  111. //
  112. //--------------------------------------------------------------------
  113. VOID DelString(LPWSTR *wszOrig)
  114. {
  115. if (*wszOrig != NULL)
  116. {
  117. delete *wszOrig;
  118. *wszOrig = NULL;
  119. }
  120. }
  121. //+-------------------------------------------------------------------
  122. //
  123. // Function: wcNametoMbs(PCHAR *)
  124. //
  125. // Synopsis: Given a pointer to a WCHAR string, return a CHAR copy
  126. //
  127. // Arguments: [pwcName] - WCHAR string to copy
  128. //
  129. // Returns: <nothing>
  130. //
  131. // History: ??-???-?? ???????? Created
  132. //
  133. //--------------------------------------------------------------------
  134. PCHAR LOGCLASS::wcNametombs(PWCHAR pwcName)
  135. {
  136. PCHAR pszName = NULL;
  137. if (pwcName != NULL)
  138. {
  139. size_t sizLen = wcslen(pwcName);
  140. if ((pszName = new char[sizLen+1]) == NULL)
  141. {
  142. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  143. }
  144. else
  145. {
  146. memset(pszName, 0, sizLen +1);
  147. if (wcstombs(pszName, pwcName, sizLen) == (size_t)0)
  148. {
  149. delete[] pszName;
  150. ulLastError = ERROR_INVALID_DATA;
  151. }
  152. }
  153. }
  154. return pszName;
  155. }
  156. //+-------------------------------------------------------------------
  157. //
  158. // Class: LOGCLASS (Actually, this is a macroname that is defined
  159. // at compile time)
  160. //
  161. // Purpose:
  162. //
  163. // Interface:
  164. //
  165. // History: ??-???-?? ???????? Created
  166. //
  167. // Notes: The macro LOGCLASS is set in 'makefile'. The methods in
  168. // the file are used in the Log class and in the LogSvr class.
  169. // In the makefile for building the Log class library log.lib,
  170. // LOGCLASS is defined as "Log". In building logsvr.exe,
  171. // LOGCLASS is defined as "LogSvr". This was done because the
  172. // original version of this code was developed under
  173. // Glockenspiel 1.x which does not support multiple inheritance
  174. // and the inheritance tree for the classes which Log and LogSvr
  175. // inherit are such that this was the best way to allow for
  176. // maintaining only one version of these methods.
  177. //
  178. //--------------------------------------------------------------------
  179. //+-------------------------------------------------------------------
  180. //
  181. // Member: LOGCLASS ::InitLogging(VOID)
  182. //
  183. // Synopsis: Initialize the classes data members.
  184. //
  185. // Modifies:
  186. //
  187. // History: ??-???-?? ???????? Created
  188. //
  189. //--------------------------------------------------------------------
  190. void LOGCLASS :: InitLogging(VOID)
  191. {
  192. pszLoggingDir = NULL;
  193. pszMachineName = NULL;
  194. pszObjectName = NULL;
  195. pszTestName = NULL;
  196. pszPath = NULL;
  197. pszStatus = NULL;
  198. pszVariation = NULL;
  199. pvBinData = NULL;
  200. pszStrData = NULL;
  201. pszLogFileName = NULL;
  202. wszLoggingDir = NULL;
  203. wszMachineName = NULL;
  204. wszObjectName = NULL;
  205. wszTestName = NULL;
  206. wszPath = NULL;
  207. wszStatus = NULL;
  208. wszVariation = NULL;
  209. wszStrData = NULL;
  210. wszLogFileName = NULL;
  211. fIsComPort = FALSE;
  212. fFlushWrites = FALSE;
  213. fInfoSet = FALSE;
  214. ulEventCount = 0L;
  215. ulEventTime = 0L;
  216. usBinLen = 0;
  217. hLogFile = INVALID_HANDLE_VALUE;
  218. }
  219. //+-------------------------------------------------------------------
  220. //
  221. // Member: LOGCLASS ::FreeLogging(VOID)
  222. //
  223. // Synopsis: Reset existing Logging members back to initial state
  224. //
  225. // History: ??-???-?? ???????? Created
  226. //
  227. //--------------------------------------------------------------------
  228. void LOGCLASS :: FreeLogging()
  229. {
  230. va_list vaDummy = LOG_VA_NULL;
  231. CloseLogFile();
  232. fIsComPort = FALSE;
  233. fFlushWrites = FALSE;
  234. fInfoSet = FALSE;
  235. if(FALSE == fIsUnicode)
  236. {
  237. SetLoggingDir((PCHAR) NULL);
  238. SetMachineName((PCHAR) NULL);
  239. SetObjectName((PCHAR) NULL);
  240. SetTestName((PCHAR) NULL);
  241. SetPath((PCHAR) NULL);
  242. SetStatus((PCHAR) NULL);
  243. SetVariation((PCHAR) NULL);
  244. SetStrData((PCHAR) NULL, vaDummy);
  245. }
  246. else
  247. {
  248. SetLoggingDir((LPWSTR) NULL);
  249. SetMachineName((LPWSTR) NULL);
  250. SetObjectName((LPWSTR) NULL);
  251. SetTestName((LPWSTR) NULL);
  252. SetPath((LPWSTR) NULL);
  253. SetStatus((LPWSTR) NULL);
  254. SetVariation((LPWSTR) NULL);
  255. SetStrData((LPWSTR) NULL, vaDummy);
  256. }
  257. ulEventCount = 0L;
  258. ulEventTime = 0L;
  259. SetBinData(0, NULL);
  260. }
  261. //+-------------------------------------------------------------------
  262. //
  263. // Member: LOGCLASS ::SetLogFile(VOID)
  264. //
  265. // Synopsis: Combine the logging file name components into a full path
  266. // file name. If this new file name is not the same as that
  267. // referenced by element pszLogFileName, switch to log data
  268. // into the file in this new name.
  269. //
  270. // Returns: NO_ERROR if successful
  271. // ERROR_INVALID_PARAMETER
  272. // ERROR_NOT_ENOUGH_MEMORY
  273. // Any error from AddComponent, CheckDir, SetLogFileName,
  274. // or SetEventCount
  275. //
  276. // Modifies:
  277. //
  278. // History: ??-???-?? ???????? Created
  279. //
  280. //--------------------------------------------------------------------
  281. ULONG LOGCLASS :: SetLogFile()
  282. {
  283. // if unicode, use the unicode version
  284. if(TRUE == fIsUnicode)
  285. {
  286. return wSetLogFile();
  287. }
  288. if (((pszLoggingDir != (PCHAR) NULL) &&
  289. (strlen(pszLoggingDir) > _MAX_PATH)) ||
  290. ((pszPath != NULL) && (strlen(pszPath) > _MAX_PATH)))
  291. {
  292. return ERROR_INVALID_PARAMETER;
  293. }
  294. PCHAR pszNewFileName = new char[_MAX_PATH + 1];
  295. if(pszNewFileName == NULL)
  296. {
  297. return ERROR_NOT_ENOUGH_MEMORY;
  298. }
  299. //
  300. // Are we going to log to a COM port?
  301. //
  302. if(SetIsComPort((const char *)pszLoggingDir) != FALSE)
  303. {
  304. fIsComPort = TRUE; // Yes.
  305. strcpy(pszNewFileName, pszLoggingDir);
  306. }
  307. else
  308. {
  309. if(SetIsComPort((const char *)pszPath) != FALSE)
  310. {
  311. fIsComPort = TRUE; // Yes, locally
  312. strcpy(pszNewFileName, pszPath);
  313. }
  314. else
  315. {
  316. //
  317. // No -
  318. // For each component of the new log file path, append it to the
  319. // root logging directory. Make sure only one back-slash exists
  320. // between each appended path component.
  321. //
  322. if(pszLoggingDir != NULL && *pszLoggingDir != NULLTERM)
  323. {
  324. strcpy(pszNewFileName, pszLoggingDir);
  325. }
  326. else
  327. {
  328. *pszNewFileName = NULLTERM;
  329. }
  330. ulLastError =
  331. AddComponent(pszNewFileName, pszPath) ||
  332. AddComponent(pszNewFileName, pszTestName);
  333. }
  334. }
  335. //
  336. // The the new file name was successfully built, see if it the same as
  337. // the name of the currently open log file (if one is open). If is not
  338. // the same file name, close the open one (if open) and open the new
  339. // logging file. If the open is successful, save the name of the newly
  340. // opened file for the next time thru here.
  341. //
  342. // A later version of this method could be written to create a LRU queue
  343. // of some max number of open logging files. This version just keeps one
  344. // file open at a time, closing it only to switch to a different log file.
  345. //
  346. if(ulLastError == NO_ERROR)
  347. {
  348. if(fIsComPort == FALSE)
  349. {
  350. strcat(pszNewFileName, (const char *)".LOG");
  351. }
  352. if((pszLogFileName == NULL) ||
  353. (hLogFile == INVALID_HANDLE_VALUE) ||
  354. _stricmp(pszNewFileName, pszLogFileName) != SAME)
  355. {
  356. CloseLogFile(); // Make sure it is really closed
  357. //
  358. // Make sure the directory part of the logging file name exists.
  359. // Make each sub-directory that does not exist, then open the
  360. // logging file.
  361. //
  362. ulLastError = CheckDir(pszNewFileName);
  363. if(ulLastError == NO_ERROR)
  364. {
  365. DWORD dwFlags = GENERIC_WRITE;
  366. if(fIsComPort == FALSE)
  367. {
  368. dwFlags |= GENERIC_READ;
  369. }
  370. hLogFile = CreateFileA(pszNewFileName,
  371. dwFlags,
  372. FILE_SHARE_READ | FILE_SHARE_WRITE,
  373. NULL, OPEN_ALWAYS,
  374. FILE_ATTRIBUTE_NORMAL, NULL);
  375. if(hLogFile == INVALID_HANDLE_VALUE)
  376. {
  377. ulLastError = GetLastError();
  378. }
  379. else
  380. {
  381. if(SEEK_TO(FILE_END) != NO_ERROR)
  382. {
  383. ulLastError = GetLastError();
  384. }
  385. else
  386. {
  387. ulLastError =
  388. SetLogFileName((const char *) pszNewFileName) ||
  389. SetEventCount();
  390. }
  391. }
  392. }
  393. }
  394. }
  395. delete [] pszNewFileName;
  396. return ulLastError;
  397. }
  398. //+-------------------------------------------------------------------
  399. //
  400. // Member: LOGCLASS ::wSetLogFile(VOID)
  401. //
  402. // Synopsis: Combine the logging file name components into a full path
  403. // file name. If this new file name is not the same as that
  404. // referenced by element pszLogFileName, switch to log data
  405. // into the file in this new name.
  406. //
  407. // Returns: NO_ERROR if successful
  408. // ERROR_INVALID_PARAMETER
  409. // ERROR_NOT_ENOUGH_MEMORY
  410. // Any error from AddComponent, CheckDir, SetLogFileName,
  411. // or SetEventCount
  412. //
  413. // Modifies:
  414. //
  415. // History: ??-???-?? ???????? Created
  416. //
  417. //--------------------------------------------------------------------
  418. ULONG LOGCLASS :: wSetLogFile()
  419. {
  420. CHK_UNICODE(TRUE);
  421. if(((wszLoggingDir != NULL) &&
  422. (wcslen(wszLoggingDir) > _MAX_PATH)) ||
  423. ((wszPath != NULL) && (wcslen(wszPath) > _MAX_PATH)))
  424. {
  425. return ERROR_INVALID_PARAMETER;
  426. }
  427. LPWSTR wszNewFileName = new WCHAR[_MAX_PATH + 1];
  428. if(wszNewFileName == NULL)
  429. {
  430. return ERROR_NOT_ENOUGH_MEMORY;
  431. }
  432. //
  433. // Are we going to log to a COM port?
  434. //
  435. if(SetIsComPort((LPCWSTR) wszLoggingDir) != FALSE)
  436. {
  437. fIsComPort = TRUE; // Yes.
  438. wcscpy(wszNewFileName, wszLoggingDir);
  439. }
  440. else
  441. {
  442. if(SetIsComPort((LPCWSTR) wszPath) != FALSE)
  443. {
  444. fIsComPort = TRUE; // Yes, locally
  445. wcscpy(wszNewFileName, wszPath);
  446. }
  447. else
  448. {
  449. //
  450. // No -
  451. // For each component of the new log file path, append it to the
  452. // root logging directory. Make sure only one back-slash exists
  453. // between each appended path component.
  454. //
  455. if(wszLoggingDir != NULL && *wszLoggingDir != wNULLTERM)
  456. {
  457. wcscpy(wszNewFileName, wszLoggingDir);
  458. }
  459. else
  460. {
  461. *wszNewFileName = wNULLTERM;
  462. }
  463. ulLastError = AddComponent(wszNewFileName, wszPath) ||
  464. AddComponent(wszNewFileName, wszTestName);
  465. }
  466. }
  467. //
  468. // The the new file name was successfully built, see if it the same as
  469. // the name of the currently open log file (if one is open). If is not
  470. // the same file name, close the open one (if open) and open the new
  471. // logging file. If the open is successful, save the name of the newly
  472. // opened file for the next time thru here.
  473. //
  474. // A later version of this method could be written to create a LRU queue
  475. // of some max number of open logging files. This version just keeps one
  476. // file open at a time, closing it only to switch to a different log file.
  477. //
  478. if (ulLastError == NO_ERROR)
  479. {
  480. if(fIsComPort == FALSE)
  481. {
  482. wcscat(wszNewFileName, L".LOG");
  483. }
  484. if((wszLogFileName == NULL) || (hLogFile == INVALID_HANDLE_VALUE) ||
  485. _wcsicmp(wszNewFileName, wszLogFileName) != SAME)
  486. {
  487. CloseLogFile(); // Make sure it is really closed
  488. //
  489. // Make sure the directory part of the logging file name exists.
  490. // Make each sub-directory that does not exist, then open the
  491. // logging file.
  492. //
  493. ulLastError = CheckDir(wszNewFileName);
  494. if(ulLastError == NO_ERROR)
  495. {
  496. DWORD dwFlags = GENERIC_WRITE;
  497. if(fIsComPort == FALSE)
  498. {
  499. dwFlags |= GENERIC_READ;
  500. }
  501. hLogFile = CreateFileW(wszNewFileName,
  502. dwFlags,
  503. FILE_SHARE_READ | FILE_SHARE_WRITE,
  504. NULL, OPEN_ALWAYS,
  505. FILE_ATTRIBUTE_NORMAL, NULL);
  506. if(hLogFile == INVALID_HANDLE_VALUE)
  507. {
  508. ulLastError = GetLastError();
  509. }
  510. else
  511. {
  512. if(SEEK_TO(FILE_END) != NO_ERROR)
  513. {
  514. ulLastError = GetLastError();
  515. }
  516. else
  517. {
  518. ulLastError = SetLogFileName((LPCWSTR) wszNewFileName)
  519. || SetEventCount();
  520. }
  521. }
  522. }
  523. }
  524. }
  525. delete [] wszNewFileName;
  526. return ulLastError;
  527. }
  528. //+-------------------------------------------------------------------
  529. //
  530. // Member: LOGCLASS ::AddComponent(PCHAR, PCHAR)
  531. //
  532. // Synopsis: Append a path component to the given string in szNewName.
  533. // Make sure there is one and only one '\' between each
  534. // component and no trailing '\' is present.
  535. //
  536. // Arguments: [szNewName] - Pointer to exist path (must not be NULL)
  537. // [szComponent] - New component to add
  538. //
  539. // Returns: NO_ERROR if successful
  540. // ERROR_INVALID_NAME
  541. //
  542. // Modifies:
  543. //
  544. // History: ??-???-?? ???????? Created
  545. //
  546. //--------------------------------------------------------------------
  547. ULONG LOGCLASS :: AddComponent(PCHAR szNewName, PCHAR szComponent)
  548. {
  549. CHK_UNICODE(FALSE);
  550. PCHAR pch = NULL;
  551. // Path component provided?
  552. if (szComponent != NULL && *szComponent != NULLTERM)
  553. {
  554. int nLen = strlen((const char *)szComponent);
  555. //
  556. // Trim trailing and leading '\'s from the component to be appended,
  557. // then append the component to the file name.
  558. //
  559. pch = szComponent + nLen;
  560. while (pch > szComponent)
  561. {
  562. if (*pch == SLASH)
  563. {
  564. *pch = NULLTERM;
  565. pch--;
  566. }
  567. else
  568. {
  569. break;
  570. }
  571. }
  572. pch = szComponent;
  573. while (*pch == SLASH)
  574. {
  575. pch++;
  576. }
  577. //
  578. // Append one '\' to the file name then append the given component.
  579. //
  580. if (strlen((const char *)szNewName) + nLen + 1 < _MAX_PATH)
  581. {
  582. nLen = strlen((const char *)szNewName);
  583. if (nLen > 0)
  584. { // Add component separater
  585. szNewName[ nLen++] = SLASH;
  586. }
  587. strcpy(&szNewName[nLen], (const char *)pch);
  588. }
  589. else
  590. {
  591. ulLastError = ERROR_INVALID_NAME;
  592. }
  593. }
  594. return(ulLastError);
  595. }
  596. //+-------------------------------------------------------------------
  597. //
  598. // Member: LOGCLASS ::AddComponent(LPWSTR, LPWSTR)
  599. //
  600. // Synopsis: Append a path component to the given string in szNewName.
  601. // Make sure there is one and only one '\' between each
  602. // component and no trailing '\' is present.
  603. //
  604. // Arguments: [wszNewName] - Pointer to exist path (must not be NULL)
  605. // [wszComponent] - New component to add
  606. //
  607. // Returns: NO_ERROR if successful
  608. // ERROR_INVALID_NAME
  609. //
  610. // Modifies:
  611. //
  612. // History: ??-???-?? ???????? Created
  613. //
  614. //--------------------------------------------------------------------
  615. ULONG LOGCLASS :: AddComponent(LPWSTR wszNewName, LPWSTR wszComponent)
  616. {
  617. CHK_UNICODE(TRUE);
  618. LPWSTR wch = NULL;
  619. // Path component provided?
  620. if(wszComponent != NULL && *wszComponent != wNULLTERM)
  621. {
  622. int nLen = wcslen((LPWSTR) wszComponent);
  623. //
  624. // Trim trailing and leading backslash from the component to be
  625. // appended, then append the component to the file name.
  626. //
  627. wch = wszComponent + nLen;
  628. while(wch > wszComponent)
  629. {
  630. if(*wch == wSLASH)
  631. {
  632. *wch = wNULLTERM;
  633. wch--;
  634. }
  635. else
  636. {
  637. break;
  638. }
  639. }
  640. wch = wszComponent;
  641. while(*wch == wSLASH)
  642. {
  643. wch++;
  644. }
  645. //
  646. // Append one backslash to the file name then append the
  647. // given component.
  648. //
  649. if(wcslen(wszNewName) + nLen + 1 < _MAX_PATH)
  650. {
  651. nLen = wcslen(wszNewName);
  652. if(nLen > 0)
  653. { // Add component separater
  654. wszNewName[nLen++] = wSLASH;
  655. }
  656. wcscpy(&wszNewName[nLen], wch);
  657. }
  658. else
  659. {
  660. ulLastError = ERROR_INVALID_NAME;
  661. }
  662. }
  663. return ulLastError;
  664. }
  665. //+-------------------------------------------------------------------
  666. //
  667. // Member: LOGCLASS ::SetEventCount(VOID)
  668. //
  669. // Synopsis: This version assumes the current event count is in ASCII
  670. // format at beginning of the file. It is also assumed that
  671. // the value is in the range 0-65535 so it will fit in a small
  672. // buffer and in a USHORT.
  673. //
  674. // Returns: NO_ERROR if successful
  675. // Values from GetLastError() after CRT function is called
  676. // CORRUPT_LOG_FILE
  677. // ERROR_NOT_ENOUGH_MEMORY
  678. //
  679. // Notes: This should not need converting to unicode - dda
  680. //
  681. // History: ??-???-?? ???????? Created
  682. //
  683. //--------------------------------------------------------------------
  684. ULONG LOGCLASS :: SetEventCount()
  685. {
  686. //
  687. // If we're using a COM port, set the EventCount to 0 since
  688. // we can't read from it anyway
  689. //
  690. if(fIsComPort != FALSE)
  691. {
  692. ulEventCount = 0L;
  693. return NO_ERROR;
  694. }
  695. //
  696. // This version assumes the log file is a binary file, not normally
  697. // readable by the user without the LOGVIEWER utility. It seeks to
  698. // the beginning of the file, reads into zsCount, translates szCount
  699. // to a ULONG, and seeks to the end.
  700. //
  701. if(SEEK_TO(FILE_BEGIN) != NO_ERROR)
  702. {
  703. ulLastError = GetLastError();
  704. }
  705. else
  706. {
  707. LONG lLen = GetFileSize(hLogFile, NULL);
  708. if(lLen == -1L)
  709. {
  710. ulLastError = GetLastError();
  711. }
  712. else if(lLen < MIN_LINE_HDR_LEN)
  713. {
  714. ulEventCount = 0L; // The file has been newly created
  715. }
  716. else
  717. {
  718. PCHAR pszTmp = new CHAR[LINE_HDR_LEN+1];
  719. // Read the data line header
  720. if(pszTmp != NULL)
  721. {
  722. //
  723. // SarahJ - Event count is held in a ulong therefore its
  724. // maximum length as ascii will be 10 digits - and at this
  725. // point you have a mega file! This means that the maximum
  726. // length that the data can be is 2, and 99.9% of the time
  727. // will be 1. The below code depends on at most 2 chars being
  728. // used for the length. First read MIN_LINE_HDR_LEN bytes
  729. // then read 1 more byte to find the :.
  730. //
  731. DWORD dwBytesRead;
  732. if(FALSE == ReadFile(hLogFile, (LPVOID) pszTmp,
  733. MIN_LINE_HDR_LEN, &dwBytesRead, NULL) ||
  734. MIN_LINE_HDR_LEN != dwBytesRead)
  735. {
  736. ulLastError = GetLastError();
  737. }
  738. else
  739. {
  740. PCHAR pchTmp = &pszTmp[MIN_LINE_HDR_LEN - 1];
  741. if(*pchTmp != ':')
  742. {
  743. if(FALSE == ReadFile(hLogFile, (LPVOID) pszTmp,
  744. 1, &dwBytesRead, NULL) ||
  745. 1 != dwBytesRead)
  746. {
  747. ulLastError = GetLastError();
  748. }
  749. }
  750. else if(*pchTmp != ':')
  751. {
  752. ulEventCount = 0L;
  753. }
  754. else
  755. {
  756. *pchTmp = NULLTERM;
  757. // Get the # bytes in the event count value. The line
  758. // starts with x: where x is the LOG_EVENTS_ID
  759. // ID character.
  760. if(*pszTmp == LOG_EVENTS)
  761. {
  762. ULONG ulLen = (ULONG) atoi(&pszTmp[2]);
  763. if(ulLen > 0)
  764. {
  765. PCHAR pszCount = new CHAR[ulLen + 1];
  766. if(pszCount != NULL)
  767. {
  768. // Read the event count value
  769. if(FALSE == ReadFile(hLogFile,
  770. (LPVOID) pszTmp,
  771. ulLen, &dwBytesRead,
  772. NULL) ||
  773. ulLen != dwBytesRead)
  774. {
  775. ulLastError = GetLastError();
  776. ulEventCount = 0L;
  777. }
  778. else
  779. {
  780. pszCount[ulLen] = NULLTERM;
  781. ulEventCount = atol(pszCount);
  782. }
  783. delete pszCount;
  784. }
  785. else
  786. {
  787. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  788. ulEventCount = 0L;
  789. }
  790. }
  791. else
  792. {
  793. ulEventCount = 0L;
  794. }
  795. }
  796. else
  797. {
  798. ulLastError = CORRUPT_LOG_FILE;
  799. ulEventCount = 0L;
  800. }
  801. }
  802. delete pszTmp;
  803. }
  804. }
  805. else
  806. {
  807. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  808. ulEventCount = 0L;
  809. }
  810. }
  811. }
  812. return ulLastError;
  813. }
  814. //+-------------------------------------------------------------------
  815. //
  816. // Member: LOGCLASS ::LogOpen(VOID)
  817. //
  818. // Synopsis: If we are not in the LogSvr and if logging remotly, try
  819. // to a START record to the server. If not, or if the attempt
  820. // fails, log the data locally. This may require opening the
  821. // local log file.
  822. //
  823. // Returns: NO_ERROR if successful
  824. // Results from Remote(), SetLogFile(), or OpenLogFile()
  825. //
  826. // Modifies:
  827. //
  828. // History: ??-???-?? ???????? Created
  829. //
  830. //--------------------------------------------------------------------
  831. ULONG LOGCLASS :: LogOpen()
  832. {
  833. if(hLogFile == INVALID_HANDLE_VALUE)
  834. {
  835. //
  836. // Something failed in the remote logging attempt, or this is our
  837. // first call to open the log file, so set up to log locally.
  838. //
  839. ulLastError = SetLogFile();
  840. if(ulLastError != NO_ERROR)
  841. {
  842. return ulLastError; // Setup failed... Don't go any further.
  843. }
  844. }
  845. return OpenLogFile();
  846. }
  847. //+-------------------------------------------------------------------
  848. //
  849. // Member: LOGCLASS ::OpenLogFile(VOID)
  850. //
  851. // Synopsis: This version assumes that SetLogFile has already been called.
  852. //
  853. // Returns: Value of GetLastError() if a CRT function fails otherwise,
  854. // return code from FlushLogFile()
  855. //
  856. // Modifies:
  857. //
  858. // History: ??-???-?? ???????? Created
  859. //
  860. //--------------------------------------------------------------------
  861. ULONG LOGCLASS :: OpenLogFile()
  862. {
  863. long lLen;
  864. //
  865. // If the logging file is empty, write a header to the file and set the
  866. // event counter to zero.
  867. //
  868. if(fIsComPort == FALSE)
  869. {
  870. lLen = GetFileSize(hLogFile, NULL);
  871. if(lLen == -1L)
  872. {
  873. ulLastError = GetLastError();
  874. return ulLastError;
  875. }
  876. }
  877. else
  878. {
  879. lLen = 0L;
  880. }
  881. if(lLen < LINE_HDR_LEN)
  882. {
  883. if(SEEK_TO(FILE_BEGIN) != NO_ERROR)
  884. {
  885. ulLastError = GetLastError();
  886. }
  887. else
  888. {
  889. ulLastError = WriteHeader();
  890. }
  891. }
  892. return FlushLogFile(ulLastError);
  893. }
  894. //+-------------------------------------------------------------------
  895. //
  896. // Member: LOGCLASS ::LogData(VOID)
  897. //
  898. // Synopsis: If logging remotely, try to send data to the server. If
  899. // not, or if the attempt fails, log the data locally. This
  900. // may require opening the local log file.
  901. //
  902. // Returns: Result from WriteToLogFile
  903. //
  904. // Modifies:
  905. //
  906. // History: ??-???-?? ???????? Created
  907. //
  908. //--------------------------------------------------------------------
  909. ULONG LOGCLASS :: LogData()
  910. {
  911. if(hLogFile == INVALID_HANDLE_VALUE)
  912. {
  913. //
  914. // This is our first call to open the log file
  915. //
  916. ulLastError = SetLogFile();
  917. if(ulLastError != NO_ERROR)
  918. {
  919. return ulLastError; // Setup failed; Don't go any further.
  920. }
  921. }
  922. // Log file opened OK, so write the data
  923. return WriteToLogFile();
  924. }
  925. //+-------------------------------------------------------------------
  926. //
  927. // Member: LOGCLASS ::WriteToLogFile(VOID)
  928. //
  929. // Synopsis: Write data out to the log file.
  930. //
  931. // Returns: NO_ERROR if successful
  932. //
  933. // Modifies:
  934. //
  935. // History: ??-???-?? ???????? Created
  936. //
  937. //--------------------------------------------------------------------
  938. ULONG LOGCLASS :: WriteToLogFile()
  939. {
  940. // use unicode method
  941. if(TRUE == fIsUnicode)
  942. {
  943. return wWriteToLogFile();
  944. }
  945. char chBuf[COUNT_BUFLEN];
  946. int cLen = sprintf(chBuf, "%lu", ulEventCount + 1);
  947. ulLastError = WriteBinItem(LOG_EVENT_NUM, (PVOID) chBuf, cLen);
  948. if(ulLastError == NO_ERROR)
  949. {
  950. //
  951. // If the event time has not already been set, set it to the
  952. // current system time.
  953. //
  954. cLen = sprintf(chBuf, "%lu", (ulEventTime==0L) ?
  955. time((time_t *) NULL) : ulEventTime);
  956. ulLastError = WriteBinItem(LOG_EVENT_TIME,
  957. (PVOID) chBuf, strlen((const char *)chBuf))
  958. || WriteBinItem(LOG_MACHINE,
  959. (PVOID) pszMachineName,
  960. (pszMachineName == NULL) ?
  961. 0 : strlen((const char *)pszMachineName))
  962. || WriteBinItem(LOG_OBJECT,
  963. (PVOID) pszObjectName,
  964. (pszObjectName == NULL) ?
  965. 0 : strlen((const char *)pszObjectName))
  966. || WriteBinItem(LOG_VARIATION,
  967. (PVOID) pszVariation,
  968. (pszVariation == NULL) ?
  969. 0 : strlen((const char *)pszVariation))
  970. || WriteBinItem(LOG_STATUS,
  971. (PVOID) pszStatus,
  972. (pszStatus == NULL) ?
  973. 0 : strlen((const char *)pszStatus))
  974. || WriteBinItem(LOG_STRING,
  975. (PVOID) pszStrData,
  976. (pszStrData == NULL) ?
  977. 0 : strlen((const char *)pszStrData))
  978. || WriteBinItem(LOG_BINARY, pvBinData, usBinLen);
  979. if(ulLastError == NO_ERROR)
  980. {
  981. ++ulEventCount; // Increment the count of logged events
  982. if(pszStatus != NULL
  983. && strcmp(pszStatus, LOG_DONE_TXT) == SAME)
  984. {
  985. CloseLogFile(); // Make sure the data has been flushed
  986. }
  987. }
  988. }
  989. // Clean up in preparation for next packet
  990. va_list vaDummy = LOG_VA_NULL;
  991. SetStatus((PCHAR) NULL);
  992. SetVariation((PCHAR) NULL);
  993. ulEventTime = 0L;
  994. SetBinData(0, NULL);
  995. SetStrData((PCHAR) NULL, vaDummy);
  996. return FlushLogFile(ulLastError);
  997. }
  998. //+-------------------------------------------------------------------
  999. //
  1000. // Member: LOGCLASS ::wWriteToLogFile(VOID)
  1001. //
  1002. // Synopsis: Write data out to the log file.
  1003. //
  1004. // Returns: NO_ERROR if successful
  1005. //
  1006. // Modifies:
  1007. //
  1008. // History: ??-???-?? ???????? Created
  1009. //
  1010. //--------------------------------------------------------------------
  1011. ULONG LOGCLASS :: wWriteToLogFile()
  1012. {
  1013. CHK_UNICODE(TRUE);
  1014. WCHAR wchBuf[COUNT_BUFLEN];
  1015. int cLen = swprintf(wchBuf, L"%lu", ulEventCount + 1);
  1016. ulLastError = WriteBinItem(LOG_EVENT_NUM, (PVOID) wchBuf,
  1017. cLen * sizeof(WCHAR));
  1018. if(ulLastError == NO_ERROR)
  1019. {
  1020. //
  1021. // If the event time has not already been set, set it to the
  1022. // current system time.
  1023. //
  1024. cLen = swprintf(wchBuf, L"%lu", (ulEventTime==0L) ?
  1025. time((time_t *) NULL) : ulEventTime);
  1026. ulLastError = WriteBinItem(LOG_EVENT_TIME,
  1027. (PVOID) wchBuf,
  1028. wcslen(wchBuf) * sizeof(WCHAR))
  1029. || WriteBinItem(LOG_MACHINE,
  1030. (PVOID) wszMachineName,
  1031. (wszMachineName == NULL) ?
  1032. 0 : wcslen(wszMachineName) * sizeof(WCHAR))
  1033. || WriteBinItem(LOG_OBJECT,
  1034. (PVOID) wszObjectName,
  1035. (wszObjectName == NULL) ?
  1036. 0 : wcslen(wszObjectName) * sizeof(WCHAR))
  1037. || WriteBinItem(LOG_VARIATION,
  1038. (PVOID) wszVariation,
  1039. (wszVariation == NULL) ?
  1040. 0 : wcslen(wszVariation) * sizeof(WCHAR))
  1041. || WriteBinItem(LOG_STATUS,
  1042. (PVOID) wszStatus,
  1043. (wszStatus == NULL) ?
  1044. 0 : wcslen(wszStatus) * sizeof(WCHAR))
  1045. || WriteBinItem(LOG_STRING,
  1046. (PVOID) wszStrData,
  1047. (wszStrData == NULL) ?
  1048. 0 : wcslen(wszStrData) * sizeof(WCHAR))
  1049. || WriteBinItem(LOG_BINARY, pvBinData, usBinLen);
  1050. if(ulLastError == NO_ERROR)
  1051. {
  1052. ++ulEventCount; // Increment the count of logged events
  1053. if(wszStatus != NULL &&
  1054. wcscmp(wszStatus, wLOG_DONE_TXT) == SAME)
  1055. {
  1056. CloseLogFile(); // Make sure the data has been flushed
  1057. }
  1058. }
  1059. }
  1060. // Clean up in preparation for next packet
  1061. va_list vaDummy = LOG_VA_NULL;
  1062. SetStatus((LPWSTR) NULL);
  1063. SetVariation((LPWSTR) NULL);
  1064. ulEventTime = 0L;
  1065. SetBinData(0, NULL);
  1066. SetStrData((LPWSTR) NULL, vaDummy);
  1067. return FlushLogFile(ulLastError);
  1068. }
  1069. //+-------------------------------------------------------------------
  1070. //
  1071. // Member: LOGCLASS ::WriteHeader(VOID)
  1072. //
  1073. // Synopsis: Write data about this logging file. This only happens
  1074. // when the file is first created.
  1075. //
  1076. // Returns: NO_ERROR if successful
  1077. //
  1078. // Modifies:
  1079. //
  1080. // History: ??-???-?? ???????? Created
  1081. //
  1082. //--------------------------------------------------------------------
  1083. ULONG LOGCLASS :: WriteHeader()
  1084. {
  1085. LogEventCount();
  1086. if (ulLastError == NO_ERROR)
  1087. {
  1088. if(FALSE == fIsUnicode)
  1089. {
  1090. ulLastError = WriteBinItem(LOG_TEST_NAME, (PVOID) pszTestName,
  1091. (pszTestName == NULL) ?
  1092. 0 : strlen(pszTestName));
  1093. if (ulLastError == NO_ERROR)
  1094. {
  1095. char chBuf[COUNT_BUFLEN];
  1096. // Show when log file was started
  1097. int cLen = sprintf(chBuf, "%lu", time((time_t *)NULL));
  1098. ulLastError =
  1099. WriteBinItem(LOG_TEST_TIME, (PVOID) chBuf, cLen) ||
  1100. WriteBinItem(LOG_SERVER, (PVOID) NULL, 0);
  1101. }
  1102. }
  1103. else
  1104. {
  1105. ulLastError = WriteBinItem(LOG_TEST_NAME, (PVOID) wszTestName,
  1106. (wszTestName == NULL) ? 0 :
  1107. wcslen(wszTestName) * sizeof(WCHAR));
  1108. if (ulLastError == NO_ERROR)
  1109. {
  1110. WCHAR wchBuf[COUNT_BUFLEN];
  1111. // Show when log file was started
  1112. int cLen = swprintf(wchBuf, L"%lu", time((time_t *)NULL));
  1113. ulLastError =
  1114. WriteBinItem(LOG_TEST_TIME, (PVOID) wchBuf,
  1115. cLen * sizeof(WCHAR)) ||
  1116. WriteBinItem(LOG_SERVER, (PVOID) NULL, 0);
  1117. }
  1118. }
  1119. }
  1120. return ulLastError;
  1121. }
  1122. //+-------------------------------------------------------------------
  1123. //
  1124. // Member: LOGCLASS ::WriteBinItem(CHAR, PVOID, ULONG)
  1125. //
  1126. // Synopsis: Attempt to write Binary data to the log file
  1127. //
  1128. // Arguments: [chMark] The Item ID for the data
  1129. // [pvItem] Pointer to the data data
  1130. // [ulItemLen] Length of data to write
  1131. //
  1132. // Returns: NO_ERROR if successful
  1133. //
  1134. // Modifies:
  1135. //
  1136. // History: ??-???-?? ???????? Created
  1137. // 19-Sep_92 SarahJ Changed length to be ULONG so
  1138. // Data 32K can be written (note
  1139. // with header stuff it is > 32K)
  1140. //
  1141. //--------------------------------------------------------------------
  1142. ULONG LOGCLASS :: WriteBinItem(CHAR chMark,
  1143. PVOID pvItem,
  1144. ULONG ulItemLen)
  1145. {
  1146. if(fIsComPort != FALSE && chMark == LOG_BINARY)
  1147. {
  1148. return NO_ERROR; // Do not send binary data to a COM port
  1149. }
  1150. //
  1151. // Write everything at the end of the file except for the # events in
  1152. // the file.
  1153. //
  1154. if(SEEK_TO((chMark == LOG_EVENTS)? FILE_BEGIN : FILE_END) != NO_ERROR)
  1155. {
  1156. ulLastError = GetLastError();
  1157. return ulLastError;
  1158. }
  1159. CHAR szLen[LINE_HDR_LEN+1];
  1160. //
  1161. // Every field of data starts with a header of the form 'x:nnnnn:' where
  1162. // 'x' is the given ID char and nnnnn is the # of bytes of data.
  1163. //
  1164. int nLen = sprintf(szLen, "%c:%u:", chMark, ulItemLen);
  1165. //
  1166. // SarahJ - changed to not pad the number out to LINE_HDR_LEN -3, but to
  1167. // use minimum # of digits as per DCR 527
  1168. //
  1169. // We do not have to check dwBytesWritten because WriteFile will
  1170. // fail on a file if all bytes not written.
  1171. DWORD dwBytesWritten;
  1172. if(FALSE == WriteFile(hLogFile, (CONST LPVOID) szLen, nLen,
  1173. &dwBytesWritten, NULL))
  1174. {
  1175. ulLastError = GetLastError();
  1176. return ulLastError;
  1177. }
  1178. if(ulItemLen > 0 && ulLastError == NO_ERROR)
  1179. {
  1180. if(FALSE == WriteFile(hLogFile, (CONST LPVOID) pvItem, ulItemLen,
  1181. &dwBytesWritten, NULL))
  1182. {
  1183. ulLastError = GetLastError();
  1184. return ulLastError;
  1185. }
  1186. }
  1187. // Every field of data ends with a '\n'
  1188. if(FALSE == WriteFile(hLogFile, (CONST LPVOID) "\n", sizeof(CHAR),
  1189. &dwBytesWritten, NULL))
  1190. {
  1191. ulLastError = GetLastError();
  1192. }
  1193. // carriage return for com port
  1194. if(fIsComPort == TRUE &&
  1195. FALSE == WriteFile(hLogFile, (CONST LPVOID) "\r", sizeof(CHAR),
  1196. &dwBytesWritten, NULL))
  1197. {
  1198. ulLastError = GetLastError();
  1199. }
  1200. return ulLastError;
  1201. }
  1202. //+-------------------------------------------------------------------
  1203. //
  1204. // Member: LOGCLASS ::CheckDir(PCHAR)
  1205. //
  1206. // Synopsis: Make sure each subdirectory in the given path exists.
  1207. //
  1208. // Arguments: [pszRelPath] - Pathname to check, relative to
  1209. // current directory
  1210. //
  1211. // Returns: NO_ERROR if the the directory does exist or was
  1212. // successfully made. A GetLastError() value otherwise.
  1213. //
  1214. //
  1215. //
  1216. // Modifies:
  1217. //
  1218. // History: ??-???-?? ???????? Created
  1219. // 92-Apr-17 DwightKr Added EINVAL to _mkdir() check. We'll
  1220. // get this back on the N386 compiler if
  1221. // the directory already exists
  1222. // 01-Jul-92 Lizch Gutted routine to use much simpler ctcopy code
  1223. // courtesy of DwightKr
  1224. //
  1225. // 16-Sep-92 SarahJ Added check that _fullpath does not return NULL
  1226. // to fix bug 300
  1227. //
  1228. //--------------------------------------------------------------------
  1229. ULONG LOGCLASS :: CheckDir(PCHAR pszRelPath)
  1230. {
  1231. CHK_UNICODE(FALSE);
  1232. char *pszToken;
  1233. char *pszFileName;
  1234. char pszPath[_MAX_PATH];
  1235. char szDirToMake[_MAX_PATH] = "\0";
  1236. if(fIsComPort != FALSE)
  1237. {
  1238. return NO_ERROR; // COM port directories are an oxymoran.
  1239. }
  1240. if(0 != GetFullPathNameA(pszRelPath, _MAX_PATH - 1, pszPath, &pszFileName))
  1241. {
  1242. #ifdef TRACE
  1243. printf("Making directory %s\n", pszPath);
  1244. #endif
  1245. // First, we need to remove the filename off the
  1246. // end of the path so we do not create a dir with it! Look for
  1247. // the last backslash. It is either at the end (no file - error),
  1248. // the beginning (file at root - error), somewhere in between, or
  1249. // not at all.
  1250. if(NULL == (pszFileName = strrchr(pszPath, '\\')) ||
  1251. pszFileName == pszPath ||
  1252. '\0' == *(pszFileName + 1))
  1253. {
  1254. *pszPath = '\0';
  1255. }
  1256. else
  1257. {
  1258. *pszFileName = '\0';
  1259. }
  1260. // Just blindly create directories based on the backslashes parsed
  1261. // by strtok. We will look at the return from GetLastError to
  1262. // if we were successful at the end.
  1263. pszToken = strtok(pszPath, SLASH_STRING);
  1264. while(pszToken != NULL)
  1265. {
  1266. strcat(szDirToMake, pszToken);
  1267. if(CreateDirectoryA(szDirToMake, NULL) == TRUE)
  1268. {
  1269. #ifdef TRACE
  1270. printf ("Made directory %s\n", szDirToMake);
  1271. #endif
  1272. ulLastError = NO_ERROR;
  1273. }
  1274. else
  1275. {
  1276. #ifdef TRACE
  1277. printf("Didn't make directory %s\n", szDirToMake);
  1278. #endif
  1279. ulLastError = GetLastError();
  1280. }
  1281. pszToken = strtok(NULL, SLASH_STRING);
  1282. if(pszToken != NULL)
  1283. {
  1284. strcat(szDirToMake, SLASH_STRING);
  1285. }
  1286. }
  1287. // Leave error checking until we have tryed to add all directories -
  1288. // we might as well simply check whether the final addition worked.
  1289. // At this point, if the error return indicates the path already
  1290. // exists as a directory or file, we need to error out if it is
  1291. // actually a file.
  1292. if(ulLastError == ERROR_FILE_EXISTS ||
  1293. ulLastError == ERROR_ACCESS_DENIED ||
  1294. ulLastError == ERROR_ALREADY_EXISTS)
  1295. {
  1296. DWORD dwAttr;
  1297. // Now check if it is a directory, in which case we are OK, else if
  1298. // it is a file we need to error out.
  1299. if(~0 == (dwAttr = GetFileAttributesA(szDirToMake)))
  1300. {
  1301. ulLastError = GetLastError();
  1302. }
  1303. else
  1304. {
  1305. if(FILE_ATTRIBUTE_DIRECTORY == dwAttr)
  1306. {
  1307. #ifdef TRACE
  1308. printf ("Path already existed - success!\n");
  1309. #endif
  1310. ulLastError = NO_ERROR;
  1311. }
  1312. }
  1313. }
  1314. }
  1315. else // GetFullPathName failed
  1316. {
  1317. ulLastError = GetLastError();
  1318. fprintf(stderr, "Bad relative path %s\n", pszRelPath);
  1319. #ifdef DBG
  1320. *szDirToMake = '\0'; // just done for below error message
  1321. #endif
  1322. }
  1323. #ifdef DBG
  1324. if(ulLastError != NO_ERROR)
  1325. {
  1326. fprintf(stderr, "Fatal error making logging directory:\n\t\t %s.\n"
  1327. "Error %u.\n", szDirToMake, ulLastError);
  1328. }
  1329. #endif
  1330. return ulLastError;
  1331. }
  1332. //+-------------------------------------------------------------------
  1333. //
  1334. // Member: LOGCLASS ::CheckDir(LPWSTR)
  1335. //
  1336. // Synopsis: Make sure each subdirectory in the given path exists.
  1337. //
  1338. // Arguments: [wszRelPath] - Pathname to check, relative to
  1339. // current directory
  1340. //
  1341. // Returns: NO_ERROR if the the directory does exist or was
  1342. // successfully made. An GetLastError() value otherwise.
  1343. //
  1344. //
  1345. //
  1346. // Modifies:
  1347. //
  1348. // History: ??-???-?? ???????? Created
  1349. // 92-Apr-17 DwightKr Added EINVAL to _mkdir() check. We'll
  1350. // get this back on the N386 compiler if
  1351. // the directory already exists
  1352. // 01-Jul-92 Lizch Gutted routine to use much simpler ctcopy code
  1353. // courtesy of DwightKr
  1354. //
  1355. // 16-Sep-92 SarahJ Added check that _fullpath does not return NULL
  1356. // to fix bug 300
  1357. //
  1358. //--------------------------------------------------------------------
  1359. ULONG LOGCLASS :: CheckDir(LPWSTR wszRelPath)
  1360. {
  1361. CHK_UNICODE(TRUE);
  1362. LPWSTR wszFileName;
  1363. LPWSTR wszToken;
  1364. WCHAR wszPath[_MAX_PATH];
  1365. WCHAR wszDirToMake[_MAX_PATH] = L"\0";
  1366. if(fIsComPort != FALSE)
  1367. {
  1368. return NO_ERROR; // COM port directories are an oxymoran.
  1369. }
  1370. // check good directory name - is the NULL valid??
  1371. if(0 != GetFullPathNameW(wszRelPath, _MAX_PATH - 1, wszPath, NULL))
  1372. {
  1373. #ifdef TRACE
  1374. printf("Making directory %ls\n", wszPath);
  1375. #endif
  1376. // First, we need to remove the filename off the
  1377. // end of the path so we do not create a dir with it! Look for
  1378. // the last backslash. It is either at the end (no file - error),
  1379. // the beginning (file at root - error), somewhere in between, or
  1380. // not at all.
  1381. if(NULL == (wszFileName = wcsrchr(wszPath, '\\')) ||
  1382. wszFileName == wszPath ||
  1383. '\0' == *(wszFileName + 1))
  1384. {
  1385. *wszPath = '\0';
  1386. }
  1387. else
  1388. {
  1389. *wszFileName = '\0';
  1390. }
  1391. // Just blindly create directories based on the backslashes parsed
  1392. // by wcstok. We will look at the return from GetLastError to
  1393. // if we were successful at the end.
  1394. wszToken = wcstok(wszPath, wSLASH_STRING);
  1395. while(wszToken != NULL)
  1396. {
  1397. wcscat(wszDirToMake, wszToken);
  1398. if(CreateDirectoryW(wszDirToMake, NULL) == TRUE)
  1399. {
  1400. #ifdef TRACE
  1401. fprintf(stderr, "Made directory %ls\n", wszDirToMake);
  1402. #endif
  1403. ulLastError = NO_ERROR;
  1404. }
  1405. else
  1406. {
  1407. #ifdef TRACE
  1408. fprintf(stderr, "Didn't make directory %ls\n", wszDirToMake);
  1409. #endif
  1410. ulLastError = GetLastError();
  1411. }
  1412. wszToken = wcstok(NULL, wSLASH_STRING);
  1413. if(wszToken != NULL)
  1414. {
  1415. wcscat(wszDirToMake, wSLASH_STRING);
  1416. }
  1417. }
  1418. // Leave error checking until we have tryed to add all directories -
  1419. // we might as well simply check whether the final addition worked.
  1420. // At this point, if the error return indicates the path already
  1421. // exists as a directory or file, we need to error out if it is
  1422. // actually a file.
  1423. if(ulLastError == ERROR_FILE_EXISTS ||
  1424. ulLastError == ERROR_ALREADY_EXISTS)
  1425. {
  1426. DWORD dwAttr;
  1427. // Now check if it is a directory, in which case we are OK, else if
  1428. // it is a file we need to error out.
  1429. if(~0 == (dwAttr = GetFileAttributesW(wszDirToMake)))
  1430. {
  1431. ulLastError = GetLastError();
  1432. }
  1433. else
  1434. {
  1435. if(FILE_ATTRIBUTE_DIRECTORY == dwAttr)
  1436. {
  1437. #ifdef TRACE
  1438. fprintf(stderr, "Path already existed - success!\n");
  1439. #endif
  1440. ulLastError = NO_ERROR;
  1441. }
  1442. }
  1443. }
  1444. }
  1445. else // GetFullPathName failed
  1446. {
  1447. ulLastError = GetLastError();
  1448. fprintf(stderr, "Bad relative path %ls\n", wszRelPath);
  1449. #ifdef DBG
  1450. *wszDirToMake = L'\0'; // just done for below error message
  1451. #endif
  1452. }
  1453. #ifdef DBG
  1454. if(ulLastError != NO_ERROR)
  1455. {
  1456. fprintf(stderr, "Fatal error making logging directory:\n\t\t %ls.\n"
  1457. "Error %u.\n", wszDirToMake, ulLastError);
  1458. }
  1459. #endif
  1460. return ulLastError;
  1461. }
  1462. //+-------------------------------------------------------------------
  1463. //
  1464. // Member: LOGCLASS ::NewString(PCHAR *, const char *)
  1465. //
  1466. // Synopsis: This method will delete the existing string if it exists,
  1467. // and (if a new string is given) will create and return a
  1468. // duplicate string.
  1469. // The assumption, here, is that the original pointer was
  1470. // properly initialized to NULL prior to calling this method
  1471. // the firsttime for that original string.
  1472. //
  1473. // Arguments: [pszOrig] - The original string
  1474. // [pszNewStr] - The new and improved string
  1475. //
  1476. // Returns: Returns NULL if 'new' fails or if pszNew is NULL.
  1477. //
  1478. // Modifies:
  1479. //
  1480. // History: ??-???-?? ???????? Created
  1481. //
  1482. //--------------------------------------------------------------------
  1483. ULONG LOGCLASS :: NewString(PCHAR *pszOrig, const char * pszNewStr)
  1484. {
  1485. CHK_UNICODE(FALSE);
  1486. DelString(pszOrig);
  1487. // If a new string was given, duplicate it.
  1488. if(pszNewStr != NULL)
  1489. {
  1490. *pszOrig = new char[strlen(pszNewStr) + 1];
  1491. if(*pszOrig == NULL)
  1492. {
  1493. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  1494. }
  1495. else
  1496. {
  1497. strcpy(*pszOrig, pszNewStr);
  1498. }
  1499. }
  1500. return ulLastError;
  1501. }
  1502. //+-------------------------------------------------------------------
  1503. //
  1504. // Member: LOGCLASS ::NewString(LPWSTR *, LPCWSTR)
  1505. //
  1506. // Synopsis: This method will delete the existing string if it exists,
  1507. // and (if a new string is given) will create and return a
  1508. // duplicate string.
  1509. // The assumption, here, is that the original pointer was
  1510. // properly initialized to NULL prior to calling this method
  1511. // the firsttime for that original string.
  1512. //
  1513. // Arguments: [wszOrig] - The original string
  1514. // [wszNewStr] - The new and improved string
  1515. //
  1516. // Returns: Returns NULL if 'new' fails or if pszNew is NULL.
  1517. //
  1518. // Modifies:
  1519. //
  1520. // History: ??-???-?? ???????? Created
  1521. //
  1522. //--------------------------------------------------------------------
  1523. ULONG LOGCLASS :: NewString(LPWSTR *wszOrig, LPCWSTR wszNewStr)
  1524. {
  1525. CHK_UNICODE(TRUE);
  1526. DelString(wszOrig);
  1527. // If a new string was given, duplicate it.
  1528. if(wszNewStr != NULL)
  1529. {
  1530. *wszOrig = new WCHAR[wcslen(wszNewStr) + 1];
  1531. if(*wszOrig == NULL)
  1532. {
  1533. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  1534. }
  1535. else
  1536. {
  1537. wcscpy(*wszOrig, wszNewStr);
  1538. }
  1539. }
  1540. return ulLastError;
  1541. }
  1542. //+-------------------------------------------------------------------
  1543. //
  1544. // Member: LOGCLASS ::SetInfo(const char *, const char *,
  1545. // const char *, const char *)
  1546. //
  1547. // Synopsis: Set the logging information about the test being run.
  1548. // User is set to pszTest OR logged on username OR MY_NAME in
  1549. // that order of preference.
  1550. // Machinename is set to computername OR MY_NAME in
  1551. // that order of preference.
  1552. //
  1553. //
  1554. // Arguments: [pszSrvr] - Name of logging server
  1555. // [pszTest] - Name of the test being run
  1556. // [pszSubPath] - Log file path qualifier
  1557. // [pszObject] - Name of object logging the data
  1558. //
  1559. // Returns: USHORT - NO_ERROR (NO_ERROR) if successful. Otherwise,
  1560. // the return value from SetTestName,
  1561. // SetTester, SetPath, or SerObjectName.
  1562. //
  1563. // Modifies:
  1564. //
  1565. // History: ??-???-?? ???????? Created
  1566. // 09-Feb-92 BryanT Added Win32 support
  1567. // 01-Jul-92 Lizch Fixed bug where testername was getting
  1568. // overwritten if machinename not set.
  1569. // 30-Jul-92 SarahJ Fixed memory trashing bug - SetTester
  1570. // & SetmachineName were trashing environment
  1571. // variables
  1572. // 30-Oct-92 SarahJ Removed all signs of pszTester - it
  1573. // was only mis-used
  1574. //--------------------------------------------------------------------
  1575. ULONG LOGCLASS :: SetInfo(const char * pszSrvr,
  1576. const char * pszTest,
  1577. const char * pszSubPath,
  1578. const char * pszObject)
  1579. {
  1580. CHK_UNICODE(FALSE);
  1581. //BUGBUG Temp code
  1582. LPSTR pszTempMachineName = "MyMachineName";
  1583. ulLastError =
  1584. SetTestName(pszTest) ||
  1585. SetPath(pszSubPath) ||
  1586. SetObjectName(pszObject);
  1587. if(ulLastError != NO_ERROR)
  1588. {
  1589. return ulLastError;
  1590. }
  1591. if(pszMachineName == NULL)
  1592. {
  1593. //
  1594. // Get network computername. The computername field
  1595. // is used for pszMachineName
  1596. //
  1597. #if defined (__WIN32__) || defined (WIN32)
  1598. LPBYTE lpbBuffer = NULL;
  1599. /* BUGBUG
  1600. PCHAR pszName;
  1601. */
  1602. //
  1603. // Then, get the machine name, if not already set.
  1604. //
  1605. if(pszMachineName == NULL)
  1606. {
  1607. // BUGBUG Temporary code
  1608. SetMachineName(pszTempMachineName);
  1609. // BUGBUG End of temporary code
  1610. /* BUGBUG
  1611. if(NERR_Success == NetWkstaGetInfo(NULL, 101, &lpbBuffer))
  1612. {
  1613. pszName =
  1614. wcNametombs((PWCHAR) ((PWKSTA_INFO_101)lpbBuffer)->
  1615. wki101_computername);
  1616. SetMachineName(pszName);
  1617. NetApiBufferFree(lpbBuffer);
  1618. delete pszName;
  1619. }
  1620. */
  1621. }
  1622. #else
  1623. /* BUGBUG
  1624. USHORT usAvail = 0;
  1625. USHORT usRC = NetWkstaGetInfo(NULL, 10, NULL, 0, &usAvail);
  1626. if(usRC == NERR_BufTooSmall && usAvail > 0)
  1627. {
  1628. PCHAR pchBuf = (PCHAR)new CHAR[usAvail];
  1629. if(pchBuf != NULL)
  1630. {
  1631. usRC = NetWkstaGetInfo(NULL, 10, pchBuf, usAvail, &usAvail);
  1632. if(usRC == NO_ERROR)
  1633. {
  1634. if(pszMachineName == NULL)
  1635. {
  1636. SetMachineName(((struct wksta_info_10 *)
  1637. pchBuf)->wki10_computername);
  1638. }
  1639. }
  1640. delete pchBuf;
  1641. }
  1642. }
  1643. */
  1644. // BUGBUG Temporary code
  1645. SetMachineName(pszTempMachineName);
  1646. // BUGBUG End of temporary code
  1647. #endif // defined (__WIN32__) || (WIN32)
  1648. if(pszMachineName == NULL)
  1649. {
  1650. fprintf(stderr, "ERROR! machine name not set\n");
  1651. }
  1652. }
  1653. if(ulLastError == NO_ERROR)
  1654. {
  1655. fInfoSet = TRUE; // Note that info has been set
  1656. }
  1657. return ulLastError;
  1658. }
  1659. //+-------------------------------------------------------------------
  1660. //
  1661. // Member: LOGCLASS ::SetInfo(LPCWSTR, LPCWSTR,
  1662. // LPCWSTR, LPCWSTR)
  1663. //
  1664. // Synopsis: Set the logging information about the test being run.
  1665. // User is set to pszTest OR logged on username OR MY_NAME in
  1666. // that order of preference.
  1667. // Machinename is set to computername OR MY_NAME in
  1668. // that order of preference.
  1669. //
  1670. //
  1671. // Arguments: [wszSrvr] - Name of logging server
  1672. // [wszTest] - Name of the test being run
  1673. // [wszSubPath] - Log file path qualifier
  1674. // [wszObject] - Name of object logging the data
  1675. //
  1676. // Returns: USHORT - NO_ERROR (NO_ERROR) if successful. Otherwise,
  1677. // the return value from SetTestName,
  1678. // SetTester, SetPath, or SerObjectName.
  1679. //
  1680. // Modifies:
  1681. //
  1682. // History: ??-???-?? ???????? Created
  1683. // 09-Feb-92 BryanT Added Win32 support
  1684. // 01-Jul-92 Lizch Fixed bug where testername was getting
  1685. // overwritten if machinename not set.
  1686. // 30-Jul-92 SarahJ Fixed memory trashing bug - SetTester
  1687. // & SetmachineName were trashing environment
  1688. // variables
  1689. // 30-Oct-92 SarahJ Removed all signs of pszTester - it
  1690. // was only mis-used
  1691. //--------------------------------------------------------------------
  1692. ULONG LOGCLASS :: SetInfo(LPCWSTR wszSrvr,
  1693. LPCWSTR wszTest,
  1694. LPCWSTR wszSubPath,
  1695. LPCWSTR wszObject)
  1696. {
  1697. CHK_UNICODE(TRUE);
  1698. ulLastError =
  1699. SetTestName(wszTest) ||
  1700. SetPath(wszSubPath) ||
  1701. SetObjectName(wszObject);
  1702. if(ulLastError != NO_ERROR)
  1703. {
  1704. return ulLastError;
  1705. }
  1706. if(wszMachineName == NULL)
  1707. {
  1708. //
  1709. // Get network computername. The computername field
  1710. // is used for pszMachineName
  1711. //
  1712. #if defined (__WIN32__) || defined (WIN32)
  1713. /* BUGBUG
  1714. LPBYTE lpbBuffer;
  1715. //
  1716. // Then, get the machine name, if not already set.
  1717. //
  1718. if(wszMachineName == NULL)
  1719. {
  1720. if(NERR_Success == NetWkstaGetInfo(NULL, 101, &lpbBuffer))
  1721. {
  1722. SetMachineName((LPWSTR) (((PWKSTA_INFO_101)lpbBuffer)->
  1723. wki101_computername));
  1724. NetApiBufferFree(lpbBuffer);
  1725. }
  1726. }
  1727. */
  1728. #else
  1729. USHORT usAvail = 0;
  1730. // BUGBUG
  1731. // USHORT usRC = NetWkstaGetInfo(NULL, 10, NULL, 0, &usAvail);
  1732. if(usRC == NERR_BufTooSmall && usAvail > 0)
  1733. {
  1734. LPWSTR wchBuf = new WCHAR[usAvail];
  1735. if(wchBuf != NULL)
  1736. {
  1737. // BUGBUG
  1738. // usRC = NetWkstaGetInfo(NULL, 10, pchBuf, usAvail, &usAvail);
  1739. if(usRC == NO_ERROR)
  1740. {
  1741. if(wszMachineName == NULL)
  1742. {
  1743. SetMachineName(((struct wksta_info_10 *)
  1744. pchBuf)->wki10_computername);
  1745. }
  1746. }
  1747. delete wchBuf;
  1748. }
  1749. }
  1750. #endif // defined (__WIN32__) || (WIN32)
  1751. if(wszMachineName == NULL)
  1752. {
  1753. fprintf(stderr, "ERROR! machine name not set\n");
  1754. }
  1755. }
  1756. if(ulLastError == NO_ERROR)
  1757. {
  1758. fInfoSet = TRUE; // Note that info has been set
  1759. }
  1760. return ulLastError;
  1761. }
  1762. //+-------------------------------------------------------------------
  1763. //
  1764. // Member: LOGCLASS ::SetStrData(PCHAR, va_list)
  1765. //
  1766. // Synopsis: Set the string information that is to be logged.
  1767. //
  1768. // Effects: Create a temporary buffer for the formatted string, format
  1769. // the string and copy the new formated string to pszStrData.
  1770. // This version limits the formatted string to STRBUFSIZ chars.
  1771. // See LOG.H for STRBUFSIZ value. The only check I know how
  1772. // to make is to strlen the format string. It not a fool-proof
  1773. // check but it's better than nothing...
  1774. //
  1775. // Arguments: [pszFmt] - Format to use for writing the string (printf-like)
  1776. // [pArgs] - Arguments to print
  1777. //
  1778. // Returns: NO_ERROR if successful
  1779. //
  1780. // Modifies:
  1781. //
  1782. // History: ??-???-?? ???????? Created
  1783. // 16-Sep-92 SarahJ changed code to use _vsnprintf
  1784. // so that we allocate 1K first
  1785. // if that is too small then 32K
  1786. //
  1787. //--------------------------------------------------------------------
  1788. ULONG LOGCLASS :: SetStrData(PCHAR pszFmt, va_list pArgs)
  1789. {
  1790. CHK_UNICODE(FALSE);
  1791. if (pszFmt == NULL || *pszFmt == NULLTERM)
  1792. {
  1793. NewString(&pszStrData, NULL);
  1794. }
  1795. else
  1796. {
  1797. //
  1798. // Start off by allocating 1K
  1799. //
  1800. PCHAR szTmpBuf = new CHAR[STDSTRBUFSIZ];
  1801. if (szTmpBuf == NULL)
  1802. {
  1803. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  1804. }
  1805. else
  1806. {
  1807. // note _vsnprintf returns -1 if szTmpBuf gets more than 1K
  1808. int iLen;
  1809. if ((iLen = _vsnprintf(szTmpBuf,
  1810. STDSTRBUFSIZ - 1,
  1811. pszFmt,
  1812. pArgs)) >= 0)
  1813. {
  1814. ulLastError = NewString(&pszStrData, (const char *)szTmpBuf);
  1815. }
  1816. else if (iLen == -1)
  1817. {
  1818. //
  1819. // So we have more than 1K data, so lets leap to allocating 32K
  1820. //
  1821. delete [] szTmpBuf;
  1822. szTmpBuf = new CHAR[HUGESTRBUFSIZ];
  1823. if (szTmpBuf == NULL)
  1824. {
  1825. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  1826. }
  1827. else if ((iLen =_vsnprintf(szTmpBuf,
  1828. HUGESTRBUFSIZ - 1,
  1829. pszFmt,
  1830. pArgs)) >= 0)
  1831. {
  1832. ulLastError = NewString(&pszStrData,
  1833. (const char *) szTmpBuf);
  1834. }
  1835. else if (iLen == -1) //we have a ton of date - so truncate
  1836. {
  1837. strcpy(&szTmpBuf[HUGESTRBUFSIZ - STR_TRUNC_LEN - 2],
  1838. STR_TRUNCATION);
  1839. ulLastError = NewString(&pszStrData,
  1840. (const char *) szTmpBuf);
  1841. }
  1842. }
  1843. if (iLen < -1) // from either _vsnprintf
  1844. {
  1845. ulLastError = TOM_CORRUPT_LOG_DATA;
  1846. }
  1847. delete [] szTmpBuf;
  1848. }
  1849. }
  1850. return ulLastError;
  1851. }
  1852. //+-------------------------------------------------------------------
  1853. //
  1854. // Member: LOGCLASS ::SetStrData(LPWSTR, va_list)
  1855. //
  1856. // Synopsis: Set the string information that is to be logged.
  1857. //
  1858. // Effects: Create a temporary buffer for the formatted string, format
  1859. // the string and copy the new formated string to pszStrData.
  1860. // This version limits the formatted string to STRBUFSIZ chars.
  1861. // See LOG.H for STRBUFSIZ value. The only check I know how
  1862. // to make is to strlen the format string. It not a fool-proof
  1863. // check but it's better than nothing...
  1864. //
  1865. // Arguments: [wszFmt] - Format to use for writing the string (printf-like)
  1866. // [pArgs] - Arguments to print
  1867. //
  1868. // Returns: NO_ERROR if successful
  1869. //
  1870. // Modifies:
  1871. //
  1872. // History: ??-???-?? ???????? Created
  1873. // 16-Sep-92 SarahJ changed code to use _vsnprintf
  1874. // so that we allocate 1K first
  1875. // if that is too small then 32K
  1876. //
  1877. //--------------------------------------------------------------------
  1878. ULONG LOGCLASS :: SetStrData(LPWSTR wszFmt, va_list pArgs)
  1879. {
  1880. CHK_UNICODE(TRUE);
  1881. if(wszFmt == NULL || *wszFmt == wNULLTERM)
  1882. {
  1883. NewString(&wszStrData, NULL);
  1884. }
  1885. else
  1886. {
  1887. //
  1888. // Start off by allocating 1K
  1889. //
  1890. LPWSTR wszTmpBuf = new WCHAR[STDSTRBUFSIZ];
  1891. if(wszTmpBuf == NULL)
  1892. {
  1893. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  1894. }
  1895. else
  1896. {
  1897. // note _vsnprintf returns -1 if szTmpBuf gets more than 1K
  1898. int iLen;
  1899. if((iLen = _vsnwprintf(wszTmpBuf, STDSTRBUFSIZ - 1,
  1900. wszFmt, pArgs))
  1901. >= 0)
  1902. {
  1903. ulLastError = NewString(&wszStrData, (LPCWSTR) wszTmpBuf);
  1904. }
  1905. else if(iLen == -1)
  1906. {
  1907. //
  1908. // So we have more than 1K data, so lets leap to allocating 32K
  1909. //
  1910. delete [] wszTmpBuf;
  1911. wszTmpBuf = new WCHAR[HUGESTRBUFSIZ];
  1912. if(wszTmpBuf == NULL)
  1913. {
  1914. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  1915. }
  1916. else if((iLen = _vsnwprintf(wszTmpBuf, HUGESTRBUFSIZ-1,
  1917. wszFmt, pArgs))
  1918. >= 0)
  1919. {
  1920. ulLastError = NewString(&wszStrData,
  1921. (LPCWSTR) wszTmpBuf);
  1922. }
  1923. else if(iLen == -1) //we have a ton of date - so truncate
  1924. {
  1925. wcscpy(&wszTmpBuf[HUGESTRBUFSIZ - STR_TRUNC_LEN - 2],
  1926. wSTR_TRUNCATION);
  1927. ulLastError = NewString(&wszStrData, (LPCWSTR) wszTmpBuf);
  1928. }
  1929. }
  1930. if(iLen < -1) // from either _vsnwprintf
  1931. {
  1932. ulLastError = TOM_CORRUPT_LOG_DATA;
  1933. }
  1934. delete [] wszTmpBuf;
  1935. }
  1936. }
  1937. return ulLastError;
  1938. }
  1939. //+-------------------------------------------------------------------
  1940. //
  1941. // Member: LOGCLASS ::CloseLogFile(VOID)
  1942. //
  1943. // Synopsis: If a logging file is open, write event count to the
  1944. // beginning of the file and close the file
  1945. //
  1946. // Returns: <nothing> - sets ulLastError if there is an error
  1947. //
  1948. // Modifies:
  1949. //
  1950. // History: ??-???-?? ???????? Created
  1951. //
  1952. //--------------------------------------------------------------------
  1953. void LOGCLASS :: CloseLogFile(VOID)
  1954. {
  1955. if(hLogFile != INVALID_HANDLE_VALUE)
  1956. {
  1957. LogEventCount();
  1958. if (ulLastError == NO_ERROR && SEEK_TO(FILE_END) != NO_ERROR)
  1959. {
  1960. ulLastError = GetLastError();
  1961. }
  1962. CloseHandle(hLogFile);
  1963. hLogFile = INVALID_HANDLE_VALUE;
  1964. }
  1965. if(FALSE == fIsUnicode)
  1966. {
  1967. SetLogFileName((PCHAR) NULL);
  1968. }
  1969. else
  1970. {
  1971. SetLogFileName((LPWSTR) NULL);
  1972. }
  1973. }
  1974. //+-------------------------------------------------------------------
  1975. //
  1976. // Member: LOGCLASS ::SetBinData(USHORT, PVOID)
  1977. //
  1978. // Synopsis: Given a buffer of binary data, copy it into the internal
  1979. // temp buffer.
  1980. //
  1981. // Arguments: [usBytes] - Number of bytes to transfer
  1982. // [pvData] - Pointer to data buffer
  1983. //
  1984. // Returns: NO_ERROR if successful
  1985. //
  1986. // Modifies:
  1987. //
  1988. // History: ??-???-?? ???????? Created
  1989. //
  1990. //--------------------------------------------------------------------
  1991. ULONG LOGCLASS :: SetBinData(USHORT usBytes, PVOID pvData)
  1992. {
  1993. if(pvBinData != NULL)
  1994. {
  1995. delete pvBinData;
  1996. pvBinData = NULL;
  1997. usBinLen = 0;
  1998. }
  1999. if(usBytes > 0 && pvData != NULL)
  2000. {
  2001. // Change to BYTE support WCHAR and CHAR transparently
  2002. // PUCHAR puchData = (PUCHAR)new CHAR[usBytes];
  2003. PBYTE pbData = new BYTE[usBytes];
  2004. if(pbData == NULL)
  2005. {
  2006. usBinLen = 0;
  2007. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  2008. }
  2009. else
  2010. {
  2011. memcpy(pbData, pvData, (size_t)usBytes);
  2012. usBinLen = usBytes;
  2013. pvBinData = (PVOID)pbData;
  2014. ulLastError = NO_ERROR;
  2015. }
  2016. }
  2017. else if((usBytes > 0 && pvData == NULL)
  2018. || (usBytes == 0 && pvData != NULL))
  2019. {
  2020. ulLastError = ERROR_INVALID_PARAMETER;
  2021. }
  2022. else
  2023. {
  2024. ulLastError = NO_ERROR;
  2025. }
  2026. return ulLastError;
  2027. }
  2028. //+-------------------------------------------------------------------
  2029. //
  2030. // Member: LOGCLASS ::LogPrintf(HANDLE, PCHAR, ...)
  2031. //
  2032. // Synopsis: This version has a max formared output of STRBUFSIZ
  2033. // (see log.h). The only check I know how to make is to
  2034. // strlen the format string. It is not fool-proof but it's
  2035. // better than nothing. The method allows a printf-like format
  2036. // and args to be written to a file opened with 'open()'.
  2037. //
  2038. // Arguments: [nHandle] - Output File handle
  2039. // [pszFmt] - Format string for output
  2040. // [...] - Data to pass printf()
  2041. //
  2042. // Returns: NO_ERROR if successful
  2043. //
  2044. // Modifies:
  2045. //
  2046. // History: ??-???-?? ???????? Created
  2047. // 16-Sep-92 SarahJ Changed this function to at most write
  2048. // STDSTRBUFSIZ bytes.
  2049. //
  2050. // Note: I have assumed that LogPrintf does not print > 1K
  2051. // and can find no use with more data.
  2052. // If I am wrong then the code from SetStrData should be
  2053. // copied here.
  2054. //
  2055. //--------------------------------------------------------------------
  2056. int LOGCLASS :: LogPrintf(HANDLE hHandle, PCHAR pszFmt, ...)
  2057. {
  2058. CHK_UNICODE(FALSE);
  2059. if(pszFmt == NULL || strlen(pszFmt) >= STDSTRBUFSIZ)
  2060. {
  2061. ulLastError = ERROR_INVALID_PARAMETER;
  2062. }
  2063. else
  2064. {
  2065. PCHAR szTmpBuf = new CHAR[STDSTRBUFSIZ];
  2066. if(szTmpBuf == NULL)
  2067. {
  2068. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  2069. }
  2070. else
  2071. {
  2072. va_list pMarker;
  2073. va_start(pMarker, pszFmt);
  2074. // On other error, return will be negative and not -1...
  2075. int nLen = _vsnprintf(szTmpBuf, STDSTRBUFSIZ - 1, pszFmt, pMarker);
  2076. // ...if -1 then buffer has more than STDSTRBUFSIZ chars in it,
  2077. // but we will not support more in this method - truncate.
  2078. if(nLen == -1)
  2079. {
  2080. nLen = (STDSTRBUFSIZ - 1) * sizeof(CHAR);
  2081. }
  2082. DWORD dwBytesWritten;
  2083. if(nLen >= 0)
  2084. {
  2085. if(FALSE == WriteFile(hHandle, (CONST LPVOID) szTmpBuf, nLen,
  2086. &dwBytesWritten, NULL))
  2087. {
  2088. ulLastError = NO_ERROR;
  2089. }
  2090. else
  2091. {
  2092. ulLastError = GetLastError();
  2093. }
  2094. }
  2095. else
  2096. {
  2097. ulLastError = ERROR_INVALID_PARAMETER;
  2098. }
  2099. delete szTmpBuf;
  2100. }
  2101. }
  2102. return ulLastError;
  2103. }
  2104. //+-------------------------------------------------------------------
  2105. //
  2106. // Member: LOGCLASS ::LogPrintf(HANDLE, LPWSTR, ...)
  2107. //
  2108. // Synopsis: This version has a max formared output of STRBUFSIZ
  2109. // (see log.h). The only check I know how to make is to
  2110. // strlen the format string. It is not fool-proof but it's
  2111. // better than nothing. The method allows a printf-like format
  2112. // and args to be written to a file opened with 'open()'.
  2113. //
  2114. // Arguments: [hHandle] - Output File handle
  2115. // [wszFmt] - Format string for output
  2116. // [...] - Data to pass printf()
  2117. //
  2118. // Returns: NO_ERROR if successful
  2119. //
  2120. // Modifies:
  2121. //
  2122. // History: ??-???-?? ???????? Created
  2123. // 16-Sep-92 SarahJ Changed this function to at most write
  2124. // STDSTRBUFSIZ bytes.
  2125. //
  2126. // Note: I have assumed that LogPrintf does not print > 1K
  2127. // and can find no use with more data.
  2128. // If I am wrong then the code from SetStrData should be
  2129. // copied here.
  2130. //
  2131. //--------------------------------------------------------------------
  2132. int LOGCLASS :: LogPrintf(HANDLE hHandle, LPWSTR wszFmt, ...)
  2133. {
  2134. CHK_UNICODE(TRUE);
  2135. if(wszFmt == NULL || wcslen(wszFmt) >= STDSTRBUFSIZ)
  2136. {
  2137. ulLastError = ERROR_INVALID_PARAMETER;
  2138. }
  2139. else
  2140. {
  2141. LPWSTR wszTmpBuf = new WCHAR[STDSTRBUFSIZ];
  2142. if(wszTmpBuf == NULL)
  2143. {
  2144. ulLastError = ERROR_NOT_ENOUGH_MEMORY;
  2145. }
  2146. else
  2147. {
  2148. va_list pMarker;
  2149. va_start(pMarker, wszFmt);
  2150. int nLen = _vsnwprintf(wszTmpBuf, STDSTRBUFSIZ - 1, wszFmt,
  2151. pMarker);
  2152. if(nLen == -1) // if -1 then buffer has STDSTRBUFSIZ char in it
  2153. {
  2154. nLen = (STDSTRBUFSIZ - 1) * sizeof(WCHAR);
  2155. }
  2156. DWORD dwBytesWritten;
  2157. if(nLen >= 0)
  2158. {
  2159. if(FALSE == WriteFile(hHandle, (CONST LPVOID) wszTmpBuf, nLen,
  2160. &dwBytesWritten, NULL))
  2161. {
  2162. ulLastError = NO_ERROR;
  2163. }
  2164. else
  2165. {
  2166. ulLastError = GetLastError();
  2167. }
  2168. }
  2169. else
  2170. {
  2171. ulLastError = ERROR_INVALID_PARAMETER;
  2172. }
  2173. delete wszTmpBuf;
  2174. }
  2175. }
  2176. return ulLastError;
  2177. }
  2178. //+-------------------------------------------------------------------
  2179. //
  2180. // Member: LOGCLASS ::FlushLogFile(USHORT)
  2181. //
  2182. // Synopsis: This version checks if flushing was requested. If yes,
  2183. // the logging file is closed. The method simply retirns
  2184. // it's parameter which, in the calling code is the value
  2185. // of ulLastError.
  2186. //
  2187. // Arguments: [usErr] - Return value
  2188. //
  2189. // Returns: Whatever is passed as the first argument
  2190. //
  2191. // Modifies:
  2192. //
  2193. // History: ??-???-?? ???????? Created
  2194. //
  2195. //------------------------------------------------------------------
  2196. ULONG LOGCLASS :: FlushLogFile(ULONG ulErr)
  2197. {
  2198. if(fFlushWrites != FALSE && hLogFile != INVALID_HANDLE_VALUE)
  2199. {
  2200. CloseHandle(hLogFile);
  2201. hLogFile = INVALID_HANDLE_VALUE;
  2202. if(FALSE == fIsUnicode)
  2203. {
  2204. SetLogFileName((PCHAR) NULL);
  2205. }
  2206. else
  2207. {
  2208. SetLogFileName((LPWSTR) NULL);
  2209. }
  2210. fIsComPort = FALSE;
  2211. }
  2212. return ulErr;
  2213. }
  2214. //+-------------------------------------------------------------------
  2215. //
  2216. // Member: LOGCLASS ::SetIsComPort(const char *)
  2217. //
  2218. // Synopsis: This version sets the element fIsComPort to TRUE if the
  2219. // given name is that of a COM port, else FALSE. This
  2220. // version checks if the given file name is "COMn*" where
  2221. // 'n' is a numerical value > 0.
  2222. //
  2223. // Arguments: [pszFileName] - The file name to test
  2224. //
  2225. // Returns: TRUE if it is a comm port, FALSE otherwise
  2226. //
  2227. // Modifies:
  2228. //
  2229. // History: ??-???-?? ???????? Created
  2230. //
  2231. //--------------------------------------------------------------------
  2232. BOOL LOGCLASS :: SetIsComPort(const char * pszFileName)
  2233. {
  2234. CHK_UNICODE(FALSE);
  2235. BOOL fRC = TRUE;
  2236. if ((pszFileName != NULL) &&
  2237. (*pszFileName != NULLTERM) &&
  2238. (_strnicmp(pszFileName, (const char *)"COM", 3) == SAME) &&
  2239. (strlen(pszFileName) > 3))
  2240. {
  2241. PCHAR cp = (PCHAR)&pszFileName[3];
  2242. // Make sure everything after COM is a digit
  2243. do
  2244. {
  2245. if (!isdigit(*cp))
  2246. {
  2247. fRC = FALSE;
  2248. }
  2249. } while (fRC && ++cp);
  2250. }
  2251. else
  2252. {
  2253. fRC = FALSE;
  2254. }
  2255. return(fRC);
  2256. }
  2257. //+-------------------------------------------------------------------
  2258. //
  2259. // Member: LOGCLASS ::SetIsComPort(LPCWSTR)
  2260. //
  2261. // Synopsis: This version sets the element fIsComPort to TRUE if the
  2262. // given name is that of a COM port, else FALSE. This
  2263. // version checks if the given file name is "COMn*" where
  2264. // 'n' is a numerical value > 0.
  2265. //
  2266. // Arguments: [wszFileName] - The file name to test
  2267. //
  2268. // Returns: TRUE if it is a comm port, FALSE otherwise
  2269. //
  2270. // Modifies:
  2271. //
  2272. // History: ??-???-?? ???????? Created
  2273. //
  2274. //--------------------------------------------------------------------
  2275. BOOL LOGCLASS :: SetIsComPort(LPCWSTR wszFileName)
  2276. {
  2277. CHK_UNICODE(TRUE);
  2278. BOOL fRC = TRUE;
  2279. if((wszFileName != NULL) && (*wszFileName != NULLTERM) &&
  2280. (_wcsnicmp(wszFileName, L"COM", 3) == SAME) &&
  2281. (wcslen(wszFileName) > 3))
  2282. {
  2283. LPWSTR cp = (LPWSTR) &wszFileName[3];
  2284. // Make sure everything after COM is a digit
  2285. do
  2286. {
  2287. if(!isdigit(*cp))
  2288. {
  2289. fRC = FALSE;
  2290. }
  2291. }
  2292. while(fRC && ++cp);
  2293. }
  2294. else
  2295. {
  2296. fRC = FALSE;
  2297. }
  2298. return fRC;
  2299. }
  2300. //+-------------------------------------------------------------------
  2301. //
  2302. // Member: LOGCLASS ::LogEventCount(VOID)
  2303. //
  2304. // Synopsis: This method causes the number of logged events that are
  2305. // in this file is written into this log file.
  2306. //
  2307. // Returns: <nothing>
  2308. //
  2309. // Modifies:
  2310. //
  2311. // History: ??-???-?? ???????? Created
  2312. //
  2313. //--------------------------------------------------------------------
  2314. void LOGCLASS :: LogEventCount()
  2315. {
  2316. if(TRUE == fIsUnicode)
  2317. {
  2318. wLogEventCount();
  2319. return;
  2320. }
  2321. CHAR chBuf[COUNT_BUFLEN];
  2322. int cLen = sprintf(chBuf, "%lu", ulEventCount);
  2323. //
  2324. // The event count needs to be padded so that as the count gets larger
  2325. // we can insert in the file without overwriting the next line
  2326. //
  2327. while(cLen < COUNT_BUFLEN - 1)
  2328. {
  2329. chBuf[cLen++] = ' ';
  2330. }
  2331. chBuf[COUNT_BUFLEN - 1] = NULLTERM;
  2332. WriteBinItem(LOG_EVENTS, (PVOID) chBuf, COUNT_BUFLEN - 1);
  2333. }
  2334. //+-------------------------------------------------------------------
  2335. //
  2336. // Member: LOGCLASS :: wLogEventCount(VOID)
  2337. //
  2338. // Synopsis: This method causes the number of logged events that are
  2339. // in this file is written into this log file.
  2340. //
  2341. // Returns: <nothing>
  2342. //
  2343. // Modifies:
  2344. //
  2345. // History: ??-???-?? ???????? Created
  2346. //
  2347. //--------------------------------------------------------------------
  2348. void LOGCLASS :: wLogEventCount()
  2349. {
  2350. CHK_UNICODE(TRUE);
  2351. WCHAR wchBuf[COUNT_BUFLEN];
  2352. int cLen = swprintf(wchBuf, L"%lu", ulEventCount);
  2353. //
  2354. // The event count needs to be padded so that as the count gets larger
  2355. // we can insert in the file without overwriting the next line
  2356. //
  2357. while(cLen < COUNT_BUFLEN - 1)
  2358. {
  2359. wchBuf[cLen++] = L' ';
  2360. }
  2361. wchBuf[COUNT_BUFLEN - 1] = wNULLTERM;
  2362. WriteBinItem(LOG_EVENTS, (PVOID) wchBuf,
  2363. (COUNT_BUFLEN - 1) * sizeof(WCHAR));
  2364. }