/*
- X P L O G G E R . C
-
* Purpose:
* Code to support the Log File for the Sample Transport Provider.
*
* Copyright 1992-1995 Microsoft Corporation. All Rights Reserved.
*/
#include "xppch.h"
static HANDLE hLogHandle = INVALID_HANDLE_VALUE;
static DWORD dwLogLowWater = 0;
static DWORD dwLogHiWater = (DWORD) -1;
static TCHAR chLogFileName[MAX_PATH];
#define BUFSIZE 255 /* Size of buffer to use for LogPrintf */
static TCHAR _xpbuf[BUFSIZE];
/*
- InitTransportLog
-
* Purpose:
* Called by TransportLogon() logic to start logging.
*
* Parameters:
* lpxpl Session object. We'll need it
* to get the logfile name and
* size constraints.
* ulFlags Flags. Not used at present.
*
* Returns:
* hLogHandle Handle of open Log File.
* dwLogLowWater "Low Water Mark" of Log File.
* dwLogHiWater "High Water Mark" of Log File.
* chLogFileName Filename of open Log File.
*
* Operation:
* If a file is already open, this transport session doesn't want to log
* events, or the filename given is null, return to caller. Open the
* file and save the filename into chLogFileName. Store water marks into
* the appropriate variables. Save the handle. We grab the Critical
* Section here because it is possible to Init the logging at times
* other than TransportLogon. This makes it necessary to protect this
* section of code.
*/
void
InitTransportLog(LPXPL lpxpl, ULONG ulFlags)
{
LPSPropValue lpPropArray = lpxpl->lpPropArray;
ULONG ulSessFlags;
LPTSTR lpszFileName;
HANDLE hTempHandle;
DWORD dwOffset;
ULONG ulLow, ulHigh;
/* Use the critical section here */
EnterCriticalSection(&(lpxpl->lpxppParent->csTransport));
/* Are we already logging? If so there's nothing to do here. */
if (hLogHandle != INVALID_HANDLE_VALUE)
{
DebugTrace("Already logging to %s\n", chLogFileName);
goto ret;
}
/* Logging isn't on. Would this session like it turned on? */
ulSessFlags = (ArrayIndex(PR_SAMPLE_FLAGS, lpPropArray)).Value.ul;
if (!(ulSessFlags & PR_SAMPLE_FLAG_LOG_EVENTS))
{
DebugTrace("Log flag isn't on, logfile won't be opened\n");
goto ret;
}
/* We're going to log if we can. Get the filename and see if it
makes any sense. If so, try to open it. */
lpszFileName = (ArrayIndex(PR_SAMPLE_LOGFILE, lpPropArray)).Value.LPSZ;
if (!lpszFileName || !*lpszFileName)
{
DebugTrace("LogFile name wasn't given, logfile won't be opened\n");
goto ret;
}
hTempHandle = CreateFile(lpszFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_RANDOM_ACCESS,
NULL);
if (hTempHandle == INVALID_HANDLE_VALUE)
{
DebugTrace("Error %x opening logfile\n", GetLastError());
goto ret;
}
/* The log file is open. Seek to the end so we can resume logging. */
dwOffset = SetFilePointer(hTempHandle, 0L, NULL, FILE_END);
if (dwOffset == -1)
{
DebugTrace("Error %x seeking to end of logfile\n", GetLastError());
CloseHandle(hTempHandle);
goto ret;
}
/* Get the relevant data into the local structures. */
lstrcpy(chLogFileName, lpszFileName);
hLogHandle = hTempHandle;
ulLow = (ArrayIndex(PR_SAMPLE_LOGLOWWATER, lpPropArray)).Value.ul;
ulHigh = (ArrayIndex(PR_SAMPLE_LOGHIGHWATER, lpPropArray)).Value.ul;
if (ulHigh)
{
dwLogHiWater = ulHigh * 1024;
dwLogLowWater = ulLow * 1024;
}
ret:
/* Release the critical section */
LeaveCriticalSection(&(lpxpl->lpxppParent->csTransport));
return;
}
/*
- DeInitTransportLog
-
* Purpose:
* Called by DeinitTransport() to turn off all session logging.
*
* Parameters:
* ulFlags Flags. Not used at present.
*
* Returns:
* none.
*
* Operation:
* If we have a file open, try to close it. Reinitialize structures
* whether we succeeded or not.
*/
void
DeInitTransportLog(ULONG ulFlags)
{
if (hLogHandle != INVALID_HANDLE_VALUE)
{
if (!CloseHandle(hLogHandle))
DebugTrace("Unable to close logfile %s\n", chLogFileName);
hLogHandle = INVALID_HANDLE_VALUE;
dwLogHiWater = (DWORD) -1L;
dwLogLowWater = 0;
*chLogFileName = '\0';
}
}
/*
- PrintfTransportLog
-
* Purpose:
* Called by various parts of the Transport to log information (if
* logging is currently active).
*
* Parameters:
* fmt Start of variable argument list.
*
* Returns:
* none.
*
* Operation:
* Format the input data and call PutsTransportLog to write to logfile.
* Current maximum length permitted is 255 characters (and is NOT
* protected!).
*/
void __cdecl
PrintfTransportLog(LPTSTR fmt,...)
{
va_list marker;
va_start(marker, fmt);
if (hLogHandle != INVALID_HANDLE_VALUE)
{
if (wvsprintf((LPTSTR) _xpbuf, fmt, marker))
PutsTransportLog((LPTSTR) _xpbuf);
}
va_end(marker);
}
/*
- PutsTransportLog
-
* Purpose:
* Called mostly by PrintfTransportLog. Writes a single line to the
* logfile if it's open.
*
* Parameters:
* str String that wants to be written.
*
* Returns:
* none.
*
* Operation:
* If we have set a high water mark, get the current logfile size. If it
* exceeds the high water mark, move back by the amount of the low water
* mark, find a line ending, read everything to the end, write to the
* front of the file, and truncate to that location.
*
* Create a line consisting of the date and time, the input string, and
* line ending characters. Write this line to the logfile.
*/
void
PutsTransportLog(LPTSTR str)
{
DWORD cWritten;
SYSTEMTIME stOurTime;
TCHAR tchData[512];
HGLOBAL hGlobal = (HGLOBAL) 0L;
LPVOID lpvBuf = NULL;
if (hLogHandle == INVALID_HANDLE_VALUE)
return;
/* See if we want to be adjusting the file size. */
if (dwLogHiWater != -1)
{
DWORD finfo;
/* Get the current file size */
finfo = GetFileSize(hLogHandle, NULL);
if (finfo == 0xFFFFFFFF)
{
DebugTrace("Error %x getting logfile info\n", GetLastError());
DeInitTransportLog(LOG_DEINIT_HURRY);
return;
}
/* Is it time to trim back? If so, let's do it. */
if (finfo > dwLogHiWater)
{
DWORD dwOffset;
ULONG ulT, ulLowWater;
char *lpbT;
/* Allocate a buffer to read dwLogLowWater bytes. If
dwLogLowWater > 32K, use 32K. */
ulLowWater = (dwLogLowWater > 32000L ? 32000L : dwLogLowWater);
if (ulLowWater == 0L)
goto Truncate;
hGlobal = GlobalAlloc(GPTR, (UINT) ulLowWater);
if (hGlobal == NULL)
{
DebugTrace("Attempt to GlobalAlloc %l bytes for lowwater buffer failed\n", ulLowWater);
goto Truncate;
}
lpvBuf = (LPVOID) GlobalLock(hGlobal);
if (lpvBuf == NULL)
{
DebugTrace("Attempt to Lock allocated memory buffer failed\n");
goto Truncate;
}
/* Reposition the pointer back by the size of ulLowWater. */
dwOffset = SetFilePointer(hLogHandle, 0L - ulLowWater, NULL, FILE_CURRENT);
if (dwOffset == -1)
{
DebugTrace("Error %x seeking to low water mark\n", GetLastError());
DeInitTransportLog(LOG_DEINIT_HURRY);
return;
}
/* Read (ulLowWater) bytes from that position. */
if (!ReadFile(hLogHandle, lpvBuf, ulLowWater, &cWritten, NULL))
{
DebugTrace("Attempt to read %l bytes for low water copy failed, error = %lx\n", ulLowWater, GetLastError());
goto Truncate;
}
Assert(cWritten == ulLowWater);
/* Find the first newline from that point */
for (ulT = 0, lpbT = (char *)lpvBuf; ulT < ulLowWater; lpbT++, ulT++)
{
if (*lpbT == '\n')
break;
}
/* Did the search fail? If so, truncate the file to zero. */
if (ulT == ulLowWater)
{
ulLowWater = 0L;
Truncate:
/* We failed for some reason. Deallocate the buffer if
any and truncate the file to ulLowWater. */
if (lpvBuf)
GlobalUnlock(hGlobal);
if (hGlobal)
(void)GlobalFree(hGlobal);
dwOffset = SetFilePointer(hLogHandle, ulLowWater, NULL, FILE_BEGIN);
if (dwOffset == -1)
{
DebugTrace("Error %x seeking to low water mark\n", GetLastError());
DeInitTransportLog(LOG_DEINIT_HURRY);
return;
}
goto Adjusted;
}
/* We found a newline. Skip over it and write the remaining
data from the file start, if any. */
ulT++;
lpbT++;
dwOffset = SetFilePointer(hLogHandle, 0L, NULL, FILE_BEGIN);
if (dwOffset == -1)
{
if (lpvBuf)
GlobalUnlock(hGlobal);
if (hGlobal)
(void)GlobalFree(hGlobal);
DebugTrace("Error %x seeking to file start\n", GetLastError());
DeInitTransportLog(LOG_DEINIT_HURRY);
return;
}
if (ulT < ulLowWater)
{
cWritten = 0;
WriteFile(hLogHandle, (LPVOID) lpbT, (DWORD) (ulLowWater - ulT), &cWritten, NULL);
Assert((cWritten + ulT) == ulLowWater);
}
GlobalUnlock(hGlobal);
GlobalFree(hGlobal);
Adjusted:
if (!SetEndOfFile(hLogHandle))
{
DebugTrace("Error %x setting EOF\n", GetLastError());
DeInitTransportLog(LOG_DEINIT_HURRY);
return;
}
}
}
/* We can't handle more than 490 characters on a input line. */
Assert(lstrlen(str) < 490L);
GetLocalTime(&stOurTime);
wsprintf(tchData, TEXT("%04d/%02d/%02d %02d:%02d:%02d %s\r\n"),
stOurTime.wYear, stOurTime.wMonth, stOurTime.wDay,
stOurTime.wHour, stOurTime.wMinute, stOurTime.wSecond,
str);
WriteFile(hLogHandle, tchData, (DWORD) (lstrlen(tchData) * sizeof(TCHAR)), &cWritten, NULL);
}