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
576 lines
17 KiB
//--------------------------------------------------------------------------
|
|
// LogFile.cpp
|
|
// Copyright (C) Microsoft Corporation, 1997 - Rocket Database
|
|
//--------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <winver.h>
|
|
#include "clogfile.h"
|
|
#include <shlwapi.h>
|
|
#include <demand.h>
|
|
#include <BadStrFunctions.h>
|
|
|
|
//--------------------------------------------------------------------------
|
|
// LogFileTypes - RX = Receive, TX = Transmit, DB = Debug
|
|
//--------------------------------------------------------------------------
|
|
static LPSTR s_rgszPrefix[LOGFILE_MAX] = {
|
|
"rx",
|
|
"tx",
|
|
"db"
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// These are strings that we shouldn't log in plaintext
|
|
//--------------------------------------------------------------------------
|
|
static LPSTR s_rgszPassPrefix[] = {
|
|
"AUTHINFO PASS ",
|
|
"PASS ",
|
|
NULL
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CreateSystemHandleName
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CreateSystemHandleName(LPCSTR pszBase, LPCSTR pszSpecific,
|
|
LPSTR *ppszName)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD cchName;
|
|
|
|
// Trace
|
|
TraceCall("CreateSystemHandleName");
|
|
|
|
// Invalid Args
|
|
Assert(pszBase && pszSpecific && ppszName);
|
|
|
|
// Init
|
|
*ppszName = NULL;
|
|
|
|
// Compute Length
|
|
cchName = lstrlen(pszBase) + lstrlen(pszSpecific) + 15;
|
|
|
|
// Allocate
|
|
IF_NULLEXIT(*ppszName = PszAllocA(cchName));
|
|
|
|
// Format the name
|
|
wnsprintf(*ppszName, cchName, "%s%s", pszBase, pszSpecific);
|
|
|
|
// Remove backslashes from this string
|
|
ReplaceChars(*ppszName, '\\', '_');
|
|
|
|
// Lower Case
|
|
CharLower(*ppszName);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CreateLogFile
|
|
//--------------------------------------------------------------------------
|
|
OESTDAPI_(HRESULT) CreateLogFile(HINSTANCE hInst, LPCSTR pszLogFile,
|
|
LPCSTR pszPrefix, DWORD cbTruncate, ILogFile **ppLogFile,
|
|
DWORD dwShareMode)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CLogFile *pNew=NULL;
|
|
|
|
// Trace
|
|
TraceCall("CreateLogFile");
|
|
|
|
// Invalid Args
|
|
Assert(ppLogFile && pszLogFile);
|
|
|
|
// Initialize
|
|
*ppLogFile = NULL;
|
|
|
|
// Create me
|
|
pNew = new CLogFile;
|
|
if (NULL == pNew)
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// Open It
|
|
IF_FAILEXIT(hr = pNew->Open(hInst, pszLogFile, pszPrefix, cbTruncate, dwShareMode));
|
|
|
|
// Open It
|
|
*ppLogFile = (ILogFile *)pNew;
|
|
|
|
// Don't release it
|
|
pNew = NULL;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pNew);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::CLogFile
|
|
//--------------------------------------------------------------------------
|
|
CLogFile::CLogFile(void)
|
|
{
|
|
TraceCall("CLogFile::CLogFile");
|
|
m_cRef = 1;
|
|
m_hMutex = NULL;
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::~CLogFile
|
|
//--------------------------------------------------------------------------
|
|
CLogFile::~CLogFile(void)
|
|
{
|
|
TraceCall("CLogFile::~CLogFile");
|
|
if (m_hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle_F16(m_hFile);
|
|
SafeCloseHandle(m_hMutex);
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::AddRef
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CLogFile::AddRef(void)
|
|
{
|
|
TraceCall("CLogFile::AddRef");
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::Release
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CLogFile::Release(void)
|
|
{
|
|
TraceCall("CLogFile::Release");
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::QueryInterface
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Stack
|
|
TraceCall("CLogFile::QueryInterface");
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TraceResult(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::Open
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::Open(HINSTANCE hInst, LPCSTR pszFile, LPCSTR pszPrefix,
|
|
DWORD cbTruncate, DWORD dwShareMode)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CHAR szVersion[MAX_PATH];
|
|
CHAR szPath[MAX_PATH];
|
|
LPSTR pszInfo=NULL;
|
|
DWORD dwVerHnd;
|
|
DWORD dwVerInfoSize;
|
|
DWORD cbFile;
|
|
CHAR szGet[MAX_PATH];
|
|
UINT uLen;
|
|
LPWORD pdwTrans;
|
|
LPSTR pszT;
|
|
SYSTEMTIME st;
|
|
LPSTR pszVersion;
|
|
CHAR szPathMinusExt[MAX_PATH + 2];
|
|
CHAR szExt[4];
|
|
DWORD dwBytesWritten;
|
|
LPSTR pszMutex=NULL;
|
|
BOOL fReleaseMutex=FALSE;
|
|
int iCurrentLogNum; // For unique logfile generation
|
|
|
|
// Tracing
|
|
TraceCall("CLogFile::Open");
|
|
|
|
// Save the Prefix
|
|
StrCpyN(m_szPrefix, pszPrefix ? pszPrefix : "", ARRAYSIZE(m_szPrefix));
|
|
|
|
// Create a Mutex Name
|
|
IF_FAILEXIT(hr = CreateSystemHandleName(pszFile, "logfile", &pszMutex));
|
|
|
|
// Create the Mutex
|
|
m_hMutex = CreateMutex(NULL, FALSE, pszMutex);
|
|
if (m_hMutex == NULL)
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// If we have a mutex
|
|
if (WAIT_OBJECT_0 != WaitForSingleObject(m_hMutex, INFINITE))
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Release the Mutex
|
|
fReleaseMutex = TRUE;
|
|
|
|
// Split the logfile into path+filename and extension
|
|
iCurrentLogNum = 0;
|
|
StrCpyN(szPathMinusExt, pszFile, ARRAYSIZE(szPathMinusExt));
|
|
pszT = PathFindExtension(szPathMinusExt);
|
|
if (pszT && '.' == *pszT)
|
|
{
|
|
StrCpyN(szExt, pszT + 1, ARRAYSIZE(szExt));
|
|
*pszT = '\0'; // Remove extension from path and filename
|
|
}
|
|
else
|
|
{
|
|
// Use default extension of "log"
|
|
StrCpyN(szExt, "log", ARRAYSIZE(szExt));
|
|
}
|
|
|
|
// Generate first logfile name
|
|
wnsprintf(szPath, ARRAYSIZE(szPath), "%s.%s", szPathMinusExt, szExt);
|
|
|
|
// Open|Create the log file
|
|
do
|
|
{
|
|
m_hFile = CreateFile(szPath, GENERIC_WRITE, dwShareMode, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE == m_hFile)
|
|
{
|
|
DWORD dwLastErr;
|
|
|
|
dwLastErr = GetLastError();
|
|
// If file is already in use, then try to create a separate logfile. Otherwise bail.
|
|
if (ERROR_SHARING_VIOLATION == dwLastErr)
|
|
{
|
|
// Generate next unique file name
|
|
iCurrentLogNum += 1;
|
|
wnsprintf(szPath, ARRAYSIZE(szPath), "%s (%d).%s", szPathMinusExt, iCurrentLogNum, szExt);
|
|
}
|
|
else
|
|
{
|
|
hr = TraceResultSz(E_FAIL, _MSG("Can't open logfile %s, GetLastError() = %d", szPath, dwLastErr));
|
|
goto exit;
|
|
}
|
|
}
|
|
} while (INVALID_HANDLE_VALUE == m_hFile);
|
|
|
|
// Get the File Size
|
|
cbFile = GetFileSize(m_hFile, NULL);
|
|
|
|
// Get the size of the file
|
|
if (0xFFFFFFFF != cbFile)
|
|
{
|
|
// Truncate It
|
|
if (cbFile >= cbTruncate)
|
|
{
|
|
// Set the file pointer to the end of the file
|
|
if (0xFFFFFFFF == SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN))
|
|
{
|
|
Assert(FALSE);
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Set the End of file
|
|
if (0 == SetEndOfFile(m_hFile))
|
|
{
|
|
Assert(FALSE);
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// File is zero-length
|
|
cbFile = 0;
|
|
}
|
|
|
|
// Set the file pointer to the end of the file
|
|
if (0xFFFFFFFF == SetFilePointer(m_hFile, 0, NULL, FILE_END))
|
|
{
|
|
Assert(FALSE);
|
|
hr = TraceResultSz(E_FAIL, _MSG("Can't seek to the end of the logfile %s, GetLastError() = %d", szPath, GetLastError()));
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Get Module FileName
|
|
GetModuleFileName(hInst, szPath, sizeof(szPath));
|
|
|
|
// Initialize szVersion
|
|
szVersion[0] = '\0';
|
|
|
|
// Get version information from athena
|
|
dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwVerHnd);
|
|
if (dwVerInfoSize)
|
|
{
|
|
// Allocate
|
|
IF_NULLEXIT(pszInfo = (LPSTR)g_pMalloc->Alloc(dwVerInfoSize));
|
|
|
|
// Get version info
|
|
if (GetFileVersionInfo(szPath, dwVerHnd, dwVerInfoSize, pszInfo))
|
|
{
|
|
// VerQueryValue
|
|
if (VerQueryValue(pszInfo, "\\VarFileInfo\\Translation", (LPVOID *)&pdwTrans, &uLen) && uLen >= (2 * sizeof(WORD)))
|
|
{
|
|
// set up buffer for calls to VerQueryValue()
|
|
wnsprintf(szGet, ARRAYSIZE(szGet), "\\StringFileInfo\\%04X%04X\\", pdwTrans[0], pdwTrans[1]);
|
|
|
|
// What is this doing
|
|
DWORD cchLen = lstrlen(szGet);
|
|
pszT = szGet + cchLen;
|
|
|
|
// Setup file description
|
|
StrCatBuff(szGet, "FileDescription", ARRAYSIZE(szGet));
|
|
|
|
// Get the file description
|
|
if (VerQueryValue(pszInfo, szGet, (LPVOID *)&pszVersion, &uLen) && uLen)
|
|
{
|
|
StrCpyN(szVersion, pszVersion, ARRAYSIZE(szVersion));
|
|
StrCatBuff(szVersion, " ", ARRAYSIZE(szVersion));
|
|
}
|
|
|
|
// Setup Version String
|
|
StrCpyN(pszT, "FileVersion", ARRAYSIZE(szGet) - cchLen);
|
|
|
|
// Get the file version
|
|
if (VerQueryValue(pszInfo, szGet, (LPVOID *)&pszVersion, &uLen) && uLen)
|
|
StrCatBuff(szVersion, pszVersion, ARRAYSIZE(szVersion));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the Date
|
|
GetLocalTime(&st);
|
|
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);
|
|
|
|
// add a new line
|
|
WriteFile(m_hFile, szPath, lstrlen(szPath), &dwBytesWritten, NULL);
|
|
|
|
exit:
|
|
// Failure
|
|
AssertSz(SUCCEEDED(hr), "Log file could not be opened.");
|
|
|
|
// Cleanup
|
|
if (fReleaseMutex)
|
|
ReleaseMutex(m_hMutex);
|
|
SafeMemFree(pszInfo);
|
|
SafeMemFree(pszMutex);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// WriteLogMsg
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP WriteLogMsg(CLogFile *pLogFile, LOGFILETYPE lft, LPTSTR pszFormat, ...)
|
|
{
|
|
static TCHAR szBuffer[2048];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, pszFormat);
|
|
wvnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
return pLogFile->WriteLog(lft, szBuffer);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::TraceLog
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::TraceLog(SHOWTRACEMASK dwMask, TRACEMACROTYPE tracetype, ULONG ulLine, HRESULT hrResult, LPCSTR pszMessage)
|
|
{
|
|
// Write the message
|
|
if (TRACE_INFO == tracetype && pszMessage)
|
|
{
|
|
if (ISFLAGSET(dwMask, SHOW_TRACE_INFO))
|
|
WriteLogMsg(this, LOGFILE_DB, "0x%08X: L(%d), Info: %s", GetCurrentThreadId(), ulLine, pszMessage);
|
|
}
|
|
else if (TRACE_RESULT == tracetype && pszMessage)
|
|
WriteLogMsg(this, LOGFILE_DB, "0x%08X: L(%d), Result: HRESULT(0x%08X) - GetLastError() = %d - %s", GetCurrentThreadId(), ulLine, hrResult, GetLastError(), pszMessage);
|
|
else if (TRACE_RESULT == tracetype && NULL == pszMessage)
|
|
WriteLogMsg(this, LOGFILE_DB, "0x%08X: L(%d), Result: HRESULT(0x%08X) - GetLastError() = %d", GetCurrentThreadId(), ulLine, hrResult, GetLastError());
|
|
else
|
|
Assert(FALSE);
|
|
|
|
// Done
|
|
return hrResult;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::WriteLog
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::WriteLog(LOGFILETYPE lft, LPCSTR pszData)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD bWrite;
|
|
DWORD cBytesWritten;
|
|
SYSTEMTIME st;
|
|
CHAR szLogPrefx[30];
|
|
INT cb;
|
|
LPSTR *ppszPrefix;
|
|
LPSTR pszFree=NULL;
|
|
BOOL fReleaseMutex=FALSE;
|
|
|
|
// Trace
|
|
TraceCall("CLogFile::WriteLog");
|
|
|
|
// File is not open
|
|
if (m_hFile == INVALID_HANDLE_VALUE)
|
|
return TraceResult(E_UNEXPECTED);
|
|
|
|
// Invalid Args
|
|
Assert(pszData && lft < LOGFILE_MAX);
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
// Initialized
|
|
Assert(m_hMutex);
|
|
|
|
// If we have a mutex
|
|
if (WAIT_OBJECT_0 != WaitForSingleObject(m_hMutex, INFINITE))
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Release the Mutex
|
|
fReleaseMutex = TRUE;
|
|
|
|
// Get the time
|
|
GetLocalTime(&st);
|
|
|
|
// Write the log prefix and time stamp
|
|
wnsprintf(szLogPrefx, ARRAYSIZE(szLogPrefx), "%s: %.2d:%.2d:%.2d [%s] ", m_szPrefix, st.wHour, st.wMinute, st.wSecond, s_rgszPrefix[lft]);
|
|
|
|
// Set the file pointer to the end of the file (otherwise multiple writers overwrite each other)
|
|
if (0xFFFFFFFF == SetFilePointer(m_hFile, 0, NULL, FILE_END))
|
|
{
|
|
hr = TraceResult(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Write the time and prefix
|
|
if (0 == WriteFile(m_hFile, szLogPrefx, lstrlen(szLogPrefx), &cBytesWritten, NULL))
|
|
{
|
|
hr = TraceResultSz(E_FAIL, _MSG("Can't write to logfile. GetLastError() = %d", GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
// Loop through prefixes
|
|
for (ppszPrefix = s_rgszPassPrefix; *ppszPrefix; ppszPrefix++)
|
|
{
|
|
// Does the data start with one of these prefixes
|
|
if (0 == StrCmpNI(pszData, *ppszPrefix, lstrlen(*ppszPrefix)))
|
|
{
|
|
// Dup the buffer that was passed in
|
|
IF_NULLEXIT(pszFree = PszDupA(pszData));
|
|
|
|
// Reset pszData
|
|
pszData = pszFree;
|
|
|
|
// Fixup the buffer
|
|
for (LPSTR pszTmp = (LPSTR)pszData + lstrlen(*ppszPrefix); *pszTmp && *pszTmp != '\r'; pszTmp++)
|
|
*pszTmp = '*';
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get the length of pszData
|
|
cb = lstrlen(pszData);
|
|
|
|
// write the log data
|
|
if (0 == WriteFile(m_hFile, pszData, cb, &cBytesWritten, NULL))
|
|
{
|
|
hr = TraceResultSz(E_FAIL, _MSG("Can't write to logfile. GetLastError() = %d", GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
// Add a CRLF if not there already
|
|
if (cb < 2 || pszData[cb-1] != '\n' || pszData[cb-2] != '\r')
|
|
WriteFile(m_hFile, "\r\n", 2, &cBytesWritten, NULL);
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (fReleaseMutex)
|
|
ReleaseMutex(m_hMutex);
|
|
|
|
// Thread Safety
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
// Cleanup
|
|
SafeMemFree(pszFree);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::DebugLog
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::DebugLog(LPCSTR pszData)
|
|
{
|
|
return WriteLog(LOGFILE_DB, pszData);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::DebugLogs
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::DebugLogs(LPCSTR pszFormat, LPCSTR pszString)
|
|
{
|
|
// Locals
|
|
CHAR szBuffer[1024];
|
|
|
|
// Build the String
|
|
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszFormat, pszString);
|
|
|
|
// Call Debug Log
|
|
return DebugLog(szBuffer);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CLogFile::DebugLogd
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CLogFile::DebugLogd(LPCSTR pszFormat, INT d)
|
|
{
|
|
// Locals
|
|
CHAR szBuffer[1024];
|
|
|
|
// Build the String
|
|
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), pszFormat, d);
|
|
|
|
// Call Debug Log
|
|
return DebugLog(szBuffer);
|
|
}
|