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.

576 lines
17 KiB

  1. //--------------------------------------------------------------------------
  2. // LogFile.cpp
  3. // Copyright (C) Microsoft Corporation, 1997 - Rocket Database
  4. //--------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include <winver.h>
  9. #include "clogfile.h"
  10. #include <shlwapi.h>
  11. #include <demand.h>
  12. #include <BadStrFunctions.h>
  13. //--------------------------------------------------------------------------
  14. // LogFileTypes - RX = Receive, TX = Transmit, DB = Debug
  15. //--------------------------------------------------------------------------
  16. static LPSTR s_rgszPrefix[LOGFILE_MAX] = {
  17. "rx",
  18. "tx",
  19. "db"
  20. };
  21. //--------------------------------------------------------------------------
  22. // These are strings that we shouldn't log in plaintext
  23. //--------------------------------------------------------------------------
  24. static LPSTR s_rgszPassPrefix[] = {
  25. "AUTHINFO PASS ",
  26. "PASS ",
  27. NULL
  28. };
  29. //--------------------------------------------------------------------------
  30. // CreateSystemHandleName
  31. //--------------------------------------------------------------------------
  32. HRESULT CreateSystemHandleName(LPCSTR pszBase, LPCSTR pszSpecific,
  33. LPSTR *ppszName)
  34. {
  35. // Locals
  36. HRESULT hr=S_OK;
  37. DWORD cchName;
  38. // Trace
  39. TraceCall("CreateSystemHandleName");
  40. // Invalid Args
  41. Assert(pszBase && pszSpecific && ppszName);
  42. // Init
  43. *ppszName = NULL;
  44. // Compute Length
  45. cchName = lstrlen(pszBase) + lstrlen(pszSpecific) + 15;
  46. // Allocate
  47. IF_NULLEXIT(*ppszName = PszAllocA(cchName));
  48. // Format the name
  49. wnsprintf(*ppszName, cchName, "%s%s", pszBase, pszSpecific);
  50. // Remove backslashes from this string
  51. ReplaceChars(*ppszName, '\\', '_');
  52. // Lower Case
  53. CharLower(*ppszName);
  54. exit:
  55. // Done
  56. return hr;
  57. }
  58. //--------------------------------------------------------------------------
  59. // CreateLogFile
  60. //--------------------------------------------------------------------------
  61. OESTDAPI_(HRESULT) CreateLogFile(HINSTANCE hInst, LPCSTR pszLogFile,
  62. LPCSTR pszPrefix, DWORD cbTruncate, ILogFile **ppLogFile,
  63. DWORD dwShareMode)
  64. {
  65. // Locals
  66. HRESULT hr=S_OK;
  67. CLogFile *pNew=NULL;
  68. // Trace
  69. TraceCall("CreateLogFile");
  70. // Invalid Args
  71. Assert(ppLogFile && pszLogFile);
  72. // Initialize
  73. *ppLogFile = NULL;
  74. // Create me
  75. pNew = new CLogFile;
  76. if (NULL == pNew)
  77. {
  78. hr = TraceResult(E_OUTOFMEMORY);
  79. goto exit;
  80. }
  81. // Open It
  82. IF_FAILEXIT(hr = pNew->Open(hInst, pszLogFile, pszPrefix, cbTruncate, dwShareMode));
  83. // Open It
  84. *ppLogFile = (ILogFile *)pNew;
  85. // Don't release it
  86. pNew = NULL;
  87. exit:
  88. // Cleanup
  89. SafeRelease(pNew);
  90. // Done
  91. return hr;
  92. }
  93. //--------------------------------------------------------------------------
  94. // CLogFile::CLogFile
  95. //--------------------------------------------------------------------------
  96. CLogFile::CLogFile(void)
  97. {
  98. TraceCall("CLogFile::CLogFile");
  99. m_cRef = 1;
  100. m_hMutex = NULL;
  101. m_hFile = INVALID_HANDLE_VALUE;
  102. InitializeCriticalSection(&m_cs);
  103. }
  104. //--------------------------------------------------------------------------
  105. // CLogFile::~CLogFile
  106. //--------------------------------------------------------------------------
  107. CLogFile::~CLogFile(void)
  108. {
  109. TraceCall("CLogFile::~CLogFile");
  110. if (m_hFile != INVALID_HANDLE_VALUE)
  111. CloseHandle_F16(m_hFile);
  112. SafeCloseHandle(m_hMutex);
  113. DeleteCriticalSection(&m_cs);
  114. }
  115. //--------------------------------------------------------------------------
  116. // CLogFile::AddRef
  117. //--------------------------------------------------------------------------
  118. STDMETHODIMP_(ULONG) CLogFile::AddRef(void)
  119. {
  120. TraceCall("CLogFile::AddRef");
  121. return InterlockedIncrement(&m_cRef);
  122. }
  123. //--------------------------------------------------------------------------
  124. // CLogFile::Release
  125. //--------------------------------------------------------------------------
  126. STDMETHODIMP_(ULONG) CLogFile::Release(void)
  127. {
  128. TraceCall("CLogFile::Release");
  129. LONG cRef = InterlockedDecrement(&m_cRef);
  130. if (0 == cRef)
  131. delete this;
  132. return (ULONG)cRef;
  133. }
  134. //--------------------------------------------------------------------------
  135. // CLogFile::QueryInterface
  136. //--------------------------------------------------------------------------
  137. STDMETHODIMP CLogFile::QueryInterface(REFIID riid, LPVOID *ppv)
  138. {
  139. // Locals
  140. HRESULT hr=S_OK;
  141. // Stack
  142. TraceCall("CLogFile::QueryInterface");
  143. // Find IID
  144. if (IID_IUnknown == riid)
  145. *ppv = (IUnknown *)this;
  146. else
  147. {
  148. *ppv = NULL;
  149. hr = TraceResult(E_NOINTERFACE);
  150. goto exit;
  151. }
  152. // AddRef It
  153. ((IUnknown *)*ppv)->AddRef();
  154. exit:
  155. // Done
  156. return hr;
  157. }
  158. //--------------------------------------------------------------------------
  159. // CLogFile::Open
  160. //--------------------------------------------------------------------------
  161. STDMETHODIMP CLogFile::Open(HINSTANCE hInst, LPCSTR pszFile, LPCSTR pszPrefix,
  162. DWORD cbTruncate, DWORD dwShareMode)
  163. {
  164. // Locals
  165. HRESULT hr=S_OK;
  166. CHAR szVersion[MAX_PATH];
  167. CHAR szPath[MAX_PATH];
  168. LPSTR pszInfo=NULL;
  169. DWORD dwVerHnd;
  170. DWORD dwVerInfoSize;
  171. DWORD cbFile;
  172. CHAR szGet[MAX_PATH];
  173. UINT uLen;
  174. LPWORD pdwTrans;
  175. LPSTR pszT;
  176. SYSTEMTIME st;
  177. LPSTR pszVersion;
  178. CHAR szPathMinusExt[MAX_PATH + 2];
  179. CHAR szExt[4];
  180. DWORD dwBytesWritten;
  181. LPSTR pszMutex=NULL;
  182. BOOL fReleaseMutex=FALSE;
  183. int iCurrentLogNum; // For unique logfile generation
  184. // Tracing
  185. TraceCall("CLogFile::Open");
  186. // Save the Prefix
  187. StrCpyN(m_szPrefix, pszPrefix ? pszPrefix : "", ARRAYSIZE(m_szPrefix));
  188. // Create a Mutex Name
  189. IF_FAILEXIT(hr = CreateSystemHandleName(pszFile, "logfile", &pszMutex));
  190. // Create the Mutex
  191. m_hMutex = CreateMutex(NULL, FALSE, pszMutex);
  192. if (m_hMutex == NULL)
  193. {
  194. hr = TraceResult(E_FAIL);
  195. goto exit;
  196. }
  197. // If we have a mutex
  198. if (WAIT_OBJECT_0 != WaitForSingleObject(m_hMutex, INFINITE))
  199. {
  200. hr = TraceResult(E_FAIL);
  201. goto exit;
  202. }
  203. // Release the Mutex
  204. fReleaseMutex = TRUE;
  205. // Split the logfile into path+filename and extension
  206. iCurrentLogNum = 0;
  207. StrCpyN(szPathMinusExt, pszFile, ARRAYSIZE(szPathMinusExt));
  208. pszT = PathFindExtension(szPathMinusExt);
  209. if (pszT && '.' == *pszT)
  210. {
  211. StrCpyN(szExt, pszT + 1, ARRAYSIZE(szExt));
  212. *pszT = '\0'; // Remove extension from path and filename
  213. }
  214. else
  215. {
  216. // Use default extension of "log"
  217. StrCpyN(szExt, "log", ARRAYSIZE(szExt));
  218. }
  219. // Generate first logfile name
  220. wnsprintf(szPath, ARRAYSIZE(szPath), "%s.%s", szPathMinusExt, szExt);
  221. // Open|Create the log file
  222. do
  223. {
  224. m_hFile = CreateFile(szPath, GENERIC_WRITE, dwShareMode, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  225. if (INVALID_HANDLE_VALUE == m_hFile)
  226. {
  227. DWORD dwLastErr;
  228. dwLastErr = GetLastError();
  229. // If file is already in use, then try to create a separate logfile. Otherwise bail.
  230. if (ERROR_SHARING_VIOLATION == dwLastErr)
  231. {
  232. // Generate next unique file name
  233. iCurrentLogNum += 1;
  234. wnsprintf(szPath, ARRAYSIZE(szPath), "%s (%d).%s", szPathMinusExt, iCurrentLogNum, szExt);
  235. }
  236. else
  237. {
  238. hr = TraceResultSz(E_FAIL, _MSG("Can't open logfile %s, GetLastError() = %d", szPath, dwLastErr));
  239. goto exit;
  240. }
  241. }
  242. } while (INVALID_HANDLE_VALUE == m_hFile);
  243. // Get the File Size
  244. cbFile = GetFileSize(m_hFile, NULL);
  245. // Get the size of the file
  246. if (0xFFFFFFFF != cbFile)
  247. {
  248. // Truncate It
  249. if (cbFile >= cbTruncate)
  250. {
  251. // Set the file pointer to the end of the file
  252. if (0xFFFFFFFF == SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN))
  253. {
  254. Assert(FALSE);
  255. hr = TraceResult(E_FAIL);
  256. goto exit;
  257. }
  258. // Set the End of file
  259. if (0 == SetEndOfFile(m_hFile))
  260. {
  261. Assert(FALSE);
  262. hr = TraceResult(E_FAIL);
  263. goto exit;
  264. }
  265. // File is zero-length
  266. cbFile = 0;
  267. }
  268. // Set the file pointer to the end of the file
  269. if (0xFFFFFFFF == SetFilePointer(m_hFile, 0, NULL, FILE_END))
  270. {
  271. Assert(FALSE);
  272. hr = TraceResultSz(E_FAIL, _MSG("Can't seek to the end of the logfile %s, GetLastError() = %d", szPath, GetLastError()));
  273. goto exit;
  274. }
  275. }
  276. // Get Module FileName
  277. GetModuleFileName(hInst, szPath, sizeof(szPath));
  278. // Initialize szVersion
  279. szVersion[0] = '\0';
  280. // Get version information from athena
  281. dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwVerHnd);
  282. if (dwVerInfoSize)
  283. {
  284. // Allocate
  285. IF_NULLEXIT(pszInfo = (LPSTR)g_pMalloc->Alloc(dwVerInfoSize));
  286. // Get version info
  287. if (GetFileVersionInfo(szPath, dwVerHnd, dwVerInfoSize, pszInfo))
  288. {
  289. // VerQueryValue
  290. if (VerQueryValue(pszInfo, "\\VarFileInfo\\Translation", (LPVOID *)&pdwTrans, &uLen) && uLen >= (2 * sizeof(WORD)))
  291. {
  292. // set up buffer for calls to VerQueryValue()
  293. wnsprintf(szGet, ARRAYSIZE(szGet), "\\StringFileInfo\\%04X%04X\\", pdwTrans[0], pdwTrans[1]);
  294. // What is this doing
  295. DWORD cchLen = lstrlen(szGet);
  296. pszT = szGet + cchLen;
  297. // Setup file description
  298. StrCatBuff(szGet, "FileDescription", ARRAYSIZE(szGet));
  299. // Get the file description
  300. if (VerQueryValue(pszInfo, szGet, (LPVOID *)&pszVersion, &uLen) && uLen)
  301. {
  302. StrCpyN(szVersion, pszVersion, ARRAYSIZE(szVersion));
  303. StrCatBuff(szVersion, " ", ARRAYSIZE(szVersion));
  304. }
  305. // Setup Version String
  306. StrCpyN(pszT, "FileVersion", ARRAYSIZE(szGet) - cchLen);
  307. // Get the file version
  308. if (VerQueryValue(pszInfo, szGet, (LPVOID *)&pszVersion, &uLen) && uLen)
  309. StrCatBuff(szVersion, pszVersion, ARRAYSIZE(szVersion));
  310. }
  311. }
  312. }
  313. // Write the Date
  314. GetLocalTime(&st);
  315. wnsprintf(szPath, ARRAYSIZE(szPath), "\r\n%s\r\n%s Log started at %.2d/%.2d/%.4d %.2d:%.2d:%.2d\r\n", szVersion, pszPrefix, st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
  316. // add a new line
  317. WriteFile(m_hFile, szPath, lstrlen(szPath), &dwBytesWritten, NULL);
  318. exit:
  319. // Failure
  320. AssertSz(SUCCEEDED(hr), "Log file could not be opened.");
  321. // Cleanup
  322. if (fReleaseMutex)
  323. ReleaseMutex(m_hMutex);
  324. SafeMemFree(pszInfo);
  325. SafeMemFree(pszMutex);
  326. // Done
  327. return hr;
  328. }
  329. //--------------------------------------------------------------------------
  330. // WriteLogMsg
  331. //--------------------------------------------------------------------------
  332. STDMETHODIMP WriteLogMsg(CLogFile *pLogFile, LOGFILETYPE lft, LPTSTR pszFormat, ...)
  333. {
  334. static TCHAR szBuffer[2048];
  335. va_list arglist;
  336. va_start(arglist, pszFormat);
  337. wvnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszFormat, arglist);
  338. va_end(arglist);
  339. return pLogFile->WriteLog(lft, szBuffer);
  340. }
  341. //--------------------------------------------------------------------------
  342. // CLogFile::TraceLog
  343. //--------------------------------------------------------------------------
  344. STDMETHODIMP CLogFile::TraceLog(SHOWTRACEMASK dwMask, TRACEMACROTYPE tracetype, ULONG ulLine, HRESULT hrResult, LPCSTR pszMessage)
  345. {
  346. // Write the message
  347. if (TRACE_INFO == tracetype && pszMessage)
  348. {
  349. if (ISFLAGSET(dwMask, SHOW_TRACE_INFO))
  350. WriteLogMsg(this, LOGFILE_DB, "0x%08X: L(%d), Info: %s", GetCurrentThreadId(), ulLine, pszMessage);
  351. }
  352. else if (TRACE_RESULT == tracetype && pszMessage)
  353. WriteLogMsg(this, LOGFILE_DB, "0x%08X: L(%d), Result: HRESULT(0x%08X) - GetLastError() = %d - %s", GetCurrentThreadId(), ulLine, hrResult, GetLastError(), pszMessage);
  354. else if (TRACE_RESULT == tracetype && NULL == pszMessage)
  355. WriteLogMsg(this, LOGFILE_DB, "0x%08X: L(%d), Result: HRESULT(0x%08X) - GetLastError() = %d", GetCurrentThreadId(), ulLine, hrResult, GetLastError());
  356. else
  357. Assert(FALSE);
  358. // Done
  359. return hrResult;
  360. }
  361. //--------------------------------------------------------------------------
  362. // CLogFile::WriteLog
  363. //--------------------------------------------------------------------------
  364. STDMETHODIMP CLogFile::WriteLog(LOGFILETYPE lft, LPCSTR pszData)
  365. {
  366. // Locals
  367. HRESULT hr=S_OK;
  368. DWORD bWrite;
  369. DWORD cBytesWritten;
  370. SYSTEMTIME st;
  371. CHAR szLogPrefx[30];
  372. INT cb;
  373. LPSTR *ppszPrefix;
  374. LPSTR pszFree=NULL;
  375. BOOL fReleaseMutex=FALSE;
  376. // Trace
  377. TraceCall("CLogFile::WriteLog");
  378. // File is not open
  379. if (m_hFile == INVALID_HANDLE_VALUE)
  380. return TraceResult(E_UNEXPECTED);
  381. // Invalid Args
  382. Assert(pszData && lft < LOGFILE_MAX);
  383. // Thread Safety
  384. EnterCriticalSection(&m_cs);
  385. // Initialized
  386. Assert(m_hMutex);
  387. // If we have a mutex
  388. if (WAIT_OBJECT_0 != WaitForSingleObject(m_hMutex, INFINITE))
  389. {
  390. hr = TraceResult(E_FAIL);
  391. goto exit;
  392. }
  393. // Release the Mutex
  394. fReleaseMutex = TRUE;
  395. // Get the time
  396. GetLocalTime(&st);
  397. // Write the log prefix and time stamp
  398. wnsprintf(szLogPrefx, ARRAYSIZE(szLogPrefx), "%s: %.2d:%.2d:%.2d [%s] ", m_szPrefix, st.wHour, st.wMinute, st.wSecond, s_rgszPrefix[lft]);
  399. // Set the file pointer to the end of the file (otherwise multiple writers overwrite each other)
  400. if (0xFFFFFFFF == SetFilePointer(m_hFile, 0, NULL, FILE_END))
  401. {
  402. hr = TraceResult(E_FAIL);
  403. goto exit;
  404. }
  405. // Write the time and prefix
  406. if (0 == WriteFile(m_hFile, szLogPrefx, lstrlen(szLogPrefx), &cBytesWritten, NULL))
  407. {
  408. hr = TraceResultSz(E_FAIL, _MSG("Can't write to logfile. GetLastError() = %d", GetLastError()));
  409. goto exit;
  410. }
  411. // Loop through prefixes
  412. for (ppszPrefix = s_rgszPassPrefix; *ppszPrefix; ppszPrefix++)
  413. {
  414. // Does the data start with one of these prefixes
  415. if (0 == StrCmpNI(pszData, *ppszPrefix, lstrlen(*ppszPrefix)))
  416. {
  417. // Dup the buffer that was passed in
  418. IF_NULLEXIT(pszFree = PszDupA(pszData));
  419. // Reset pszData
  420. pszData = pszFree;
  421. // Fixup the buffer
  422. for (LPSTR pszTmp = (LPSTR)pszData + lstrlen(*ppszPrefix); *pszTmp && *pszTmp != '\r'; pszTmp++)
  423. *pszTmp = '*';
  424. // Done
  425. break;
  426. }
  427. }
  428. // Get the length of pszData
  429. cb = lstrlen(pszData);
  430. // write the log data
  431. if (0 == WriteFile(m_hFile, pszData, cb, &cBytesWritten, NULL))
  432. {
  433. hr = TraceResultSz(E_FAIL, _MSG("Can't write to logfile. GetLastError() = %d", GetLastError()));
  434. goto exit;
  435. }
  436. // Add a CRLF if not there already
  437. if (cb < 2 || pszData[cb-1] != '\n' || pszData[cb-2] != '\r')
  438. WriteFile(m_hFile, "\r\n", 2, &cBytesWritten, NULL);
  439. exit:
  440. // Cleanup
  441. if (fReleaseMutex)
  442. ReleaseMutex(m_hMutex);
  443. // Thread Safety
  444. LeaveCriticalSection(&m_cs);
  445. // Cleanup
  446. SafeMemFree(pszFree);
  447. // Done
  448. return hr;
  449. }
  450. //--------------------------------------------------------------------------
  451. // CLogFile::DebugLog
  452. //--------------------------------------------------------------------------
  453. STDMETHODIMP CLogFile::DebugLog(LPCSTR pszData)
  454. {
  455. return WriteLog(LOGFILE_DB, pszData);
  456. }
  457. //--------------------------------------------------------------------------
  458. // CLogFile::DebugLogs
  459. //--------------------------------------------------------------------------
  460. STDMETHODIMP CLogFile::DebugLogs(LPCSTR pszFormat, LPCSTR pszString)
  461. {
  462. // Locals
  463. CHAR szBuffer[1024];
  464. // Build the String
  465. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszFormat, pszString);
  466. // Call Debug Log
  467. return DebugLog(szBuffer);
  468. }
  469. //--------------------------------------------------------------------------
  470. // CLogFile::DebugLogd
  471. //--------------------------------------------------------------------------
  472. STDMETHODIMP CLogFile::DebugLogd(LPCSTR pszFormat, INT d)
  473. {
  474. // Locals
  475. CHAR szBuffer[1024];
  476. // Build the String
  477. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszFormat, d);
  478. // Call Debug Log
  479. return DebugLog(szBuffer);
  480. }