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.
 
 
 
 
 
 

1283 lines
29 KiB

/*++
Copyright (c) 1995-1996 Microsoft Corporation
Module Name :
filectl.cxx
Abstract:
OLE control to handle file logging object
Author:
Terence Kwan ( terryk ) 18-Sep-1996
Project:
IIS Logging 3.0
--*/
#include "precomp.hxx"
#include "initguid.h"
#include <ilogobj.hxx>
#include "filectl.hxx"
#include <issched.hxx>
#include <atlimpl.cpp>
#define LOG_FILE_SLOP 512
//
// tick minute.
//
#define TICK_MINUTE (60 * 1000)
//************************************************************************************
VOID
LogWriteEvent(
IN LPCSTR InstanceName,
IN BOOL fResume
);
//
// globals
//
LPEVENT_LOG g_eventLog = NULL;
CLogFileCtrl::CLogFileCtrl(
VOID
)
:
m_fFirstLog ( TRUE),
m_pLogFile ( NULL),
m_fDiskFullShutdown ( FALSE),
m_fUsingCustomHeaders ( FALSE),
m_sequence ( 1),
m_TickResumeOpen ( 0),
m_strLogFileName ( ),
m_dwSchedulerCookie ( 0),
m_fInTerminate ( FALSE)
/*++
Routine Description:
Contructor for the log file control
Arguments:
Return Value:
--*/
{
//
// initialize all the internal variable
//
ZeroMemory( &m_stCurrentFile, sizeof( m_stCurrentFile));
INITIALIZE_CRITICAL_SECTION( &m_csLock );
}
//************************************************************************************
// CLogFileCtrl::~CLogFileCtrl - Destructor
CLogFileCtrl::~CLogFileCtrl()
/*++
Routine Description:
destructor for the log file control
Arguments:
Return Value:
--*/
{
TerminateLog();
DeleteCriticalSection( &m_csLock );
}
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::InitializeLog(
LPCSTR szInstanceName,
LPCSTR pszMetabasePath,
CHAR* pvIMDCOM )
/*++
Routine Description:
Initialize log
Arguments:
cbSize - size of the service name
RegKey - service name
dwInstanceOf - instance number
Return Value:
--*/
{
//
// get the default parameters
//
m_strInstanceName.Copy(szInstanceName);
m_strMetabasePath.Copy(pszMetabasePath);
m_pvIMDCOM = (LPVOID)pvIMDCOM;
//
// get the registry value
//
(VOID)GetRegParameters(
pszMetabasePath,
pvIMDCOM );
return 0;
}
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::TerminateLog(
VOID
)
/*++
Routine Description:
clean up the log
Arguments:
Return Value:
--*/
{
Lock( );
m_fInTerminate = TRUE;
if ( m_pLogFile!=NULL) {
m_pLogFile->CloseFile( );
delete m_pLogFile;
m_pLogFile = NULL;
}
if (m_dwSchedulerCookie)
{
RemoveWorkItem(m_dwSchedulerCookie);
}
m_dwSchedulerCookie = 0;
m_fInTerminate = FALSE;
Unlock( );
return(TRUE);
}
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::LogInformation(
IInetLogInformation * ppvDataObj
)
/*++
Routine Description:
log information
Arguments:
ppvDataObj - COM Logging object
Return Value:
--*/
{
SYSTEMTIME stNow;
CHAR tmpBuf[512];
DWORD dwSize = sizeof(tmpBuf);
PCHAR pBuf = tmpBuf;
DWORD err;
retry:
err = NO_ERROR;
if ( FormatLogBuffer(ppvDataObj,
pBuf,
&dwSize,
&stNow // time is returned
)
)
{
WriteLogInformation(stNow, pBuf, dwSize, FALSE, FALSE);
}
else
{
err = GetLastError();
IIS_PRINTF((buff,"FormatLogBuffer failed with %d\n",GetLastError()));
if ( (err == ERROR_INSUFFICIENT_BUFFER) &&
( pBuf == tmpBuf ) &&
(dwSize <= MAX_LOG_RECORD_LEN) )
{
pBuf = (PCHAR)LocalAlloc( 0, dwSize );
if ( pBuf != NULL )
{
goto retry;
}
}
}
if ( (pBuf != tmpBuf) && (pBuf != NULL) )
{
LocalFree( pBuf );
}
return(0);
} // LogInformation
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::GetConfig( DWORD, BYTE * log)
/*++
Routine Description:
get configuration information
Arguments:
cbSize - size of the data structure
log - log configuration data structure
Return Value:
--*/
{
InternalGetConfig( (PINETLOG_CONFIGURATIONA)log );
return(0L);
}
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::QueryExtraLoggingFields(
IN PDWORD pcbSize,
PCHAR pszFieldsList
)
/*++
Routine Description:
get configuration information
Arguments:
cbSize - size of the data structure
log - log configuration data structure
Return Value:
--*/
{
InternalGetExtraLoggingFields( pcbSize, pszFieldsList );
return(0L);
}
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::LogCustomInformation(
IN DWORD,
IN PCUSTOM_LOG_DATA,
IN LPSTR
)
{
return(0L);
}
//************************************************************************************
void
CLogFileCtrl::InternalGetExtraLoggingFields(
PDWORD pcbSize,
TCHAR *pszFieldsList
)
{
pszFieldsList[0]=_T('\0');
pszFieldsList[1]=_T('\0');
*pcbSize = 2;
}
//************************************************************************************
VOID
CLogFileCtrl::InternalGetConfig(
IN PINETLOG_CONFIGURATIONA pLogConfig
)
/*++
Routine Description:
internal; get configuration information function.
Arguments:
log - log configuration data structure
Return Value:
--*/
{
pLogConfig->inetLogType = INET_LOG_TO_FILE;
strcpy(
pLogConfig->u.logFile.rgchLogFileDirectory,
QueryLogFileDirectory()
);
pLogConfig->u.logFile.cbSizeForTruncation = QuerySizeForTruncation();
pLogConfig->u.logFile.ilPeriod = QueryPeriod();
pLogConfig->u.logFile.ilFormat = QueryLogFormat();
}
//************************************************************************************
STDMETHODIMP
CLogFileCtrl::SetConfig(
DWORD,
BYTE * log
)
/*++
Routine Description:
set the log configuration information
Arguments:
cbSize - size of the configuration data structure
log - log information
Return Value:
--*/
{
//
// write the configuration information to the registry
//
PINETLOG_CONFIGURATIONA pLogConfig = (PINETLOG_CONFIGURATIONA)log;
SetSizeForTruncation( pLogConfig->u.logFile.cbSizeForTruncation );
SetPeriod( pLogConfig->u.logFile.ilPeriod );
SetLogFileDirectory( pLogConfig->u.logFile.rgchLogFileDirectory );
return(0L);
} // CLogFileCtrl::SetConfig
//************************************************************************************
DWORD
CLogFileCtrl::GetRegParameters(
IN LPCSTR pszRegKey,
IN LPVOID
)
/*++
Routine Description:
get the registry value
Arguments:
strRegKey - registry key
Return Value:
--*/
{
DWORD err = NO_ERROR;
MB mb( (IMDCOM*) m_pvIMDCOM );
DWORD dwSize;
CHAR szTmp[MAX_PATH+1];
DWORD cbTmp = sizeof(szTmp);
CHAR buf[MAX_PATH+1];
DWORD dwPeriod;
if ( !mb.Open("") ) {
err = GetLastError();
return(err);
}
//
// Get log file period
//
if ( mb.GetDword(
pszRegKey,
MD_LOGFILE_PERIOD,
IIS_MD_UT_SERVER,
&dwPeriod ) )
{
//
// Make sure it is within bounds
//
if ( dwPeriod > INET_LOG_PERIOD_HOURLY )
{
IIS_PRINTF((buff,"Invalid log period %d, set to %d\n",
dwPeriod, DEFAULT_LOG_FILE_PERIOD));
dwPeriod = DEFAULT_LOG_FILE_PERIOD;
}
}
else
{
dwPeriod = DEFAULT_LOG_FILE_PERIOD;
}
SetPeriod( dwPeriod );
//
// Get truncate size
//
if ( dwPeriod == INET_LOG_PERIOD_NONE )
{
SetSizeForTruncation ( DEFAULT_LOG_FILE_TRUNCATE_SIZE );
if ( mb.GetDword( pszRegKey,
MD_LOGFILE_TRUNCATE_SIZE,
IIS_MD_UT_SERVER,
&dwSize ) )
{
if ( dwSize < MIN_FILE_TRUNCATION_SIZE )
{
dwSize = MIN_FILE_TRUNCATION_SIZE;
IIS_PRINTF((buff,
"Setting truncation size to %d\n", dwSize));
}
SetSizeForTruncation( dwSize );
}
}
else
{
SetSizeForTruncation( NO_FILE_TRUNCATION );
}
//
// Get directory
//
if ( !mb.GetExpandString(
pszRegKey,
MD_LOGFILE_DIRECTORY,
IIS_MD_UT_SERVER,
szTmp,
&cbTmp ) )
{
lstrcpy(szTmp,
DEFAULT_LOG_FILE_DIRECTORY_NT );
}
mb.Close();
ExpandEnvironmentStrings( szTmp, buf, MAX_PATH+1 );
SetLogFileDirectory( buf );
return(err);
} // CLogFileCtrl::GetRegParameters
//************************************************************************************
BOOL
CLogFileCtrl::OpenLogFile(
IN PSYSTEMTIME pst
)
/*++
Routine Description:
internal routine to open file.
Arguments:
Return Value:
--*/
{
BOOL fReturn = TRUE;
BOOL bRet = FALSE;
HANDLE hToken = NULL;
DWORD dwError = NO_ERROR;
CHAR rgchPath[ MAX_PATH + 1 + 32];
if ( m_pLogFile != NULL) {
//
// already a log file is open. return silently
//
IIS_PRINTF( ( buff,
" Log File %s is already open ( %p)\n",
m_strLogFileName.QueryStr(), m_pLogFile));
} else {
//
// If this the first time we opened, get the file name
//
if ( m_fFirstLog || (QueryPeriod() != INET_LOG_PERIOD_NONE) ) {
m_fFirstLog = FALSE;
FormNewLogFileName( pst );
}
//
// Append log file name to path to form the path of file to be opened.
//
if ( (m_strLogFileName.QueryCCH() +
m_strLogFileDirectory.QueryCCH() >= MAX_PATH) ||
(m_strLogFileDirectory.QueryCCH() < 3) ) {
fReturn = FALSE;
if ( (g_eventLog != NULL) && !m_fDiskFullShutdown) {
const CHAR* tmpString[1];
tmpString[0] = rgchPath;
g_eventLog->LogEvent(
LOG_EVENT_CREATE_DIR_ERROR,
1,
tmpString,
ERROR_BAD_PATHNAME );
}
SetLastError( ERROR_BAD_PATHNAME );
goto exit;
}
lstrcpy( rgchPath, QueryLogFileDirectory());
// if ( rgchPath[strlen(rgchPath)-1] != '\\' ) {
if ( *CharPrev(rgchPath, rgchPath + strlen(rgchPath)) != '\\' ) {
lstrcat( rgchPath, "\\");
}
lstrcat( rgchPath, QueryInstanceName() );
//
// There is a small chance that this function could be called (indirectly)
// from an INPROC ISAPI completion thread (HSE_REQ_DONE). In this case
// the thread token is the impersonated user and may not have permissions
// to open the log file (especially if the user is the IUSR_ account).
// To be paranoid, let's revert to LOCAL_SYSTEM anyways before opening.
//
if ( OpenThreadToken( GetCurrentThread(),
TOKEN_ALL_ACCESS,
FALSE,
&hToken ) )
{
DBG_ASSERT( hToken != NULL );
RevertToSelf();
}
// Allow logging to mapped drives
bRet = IISCreateDirectory( rgchPath, TRUE );
dwError = GetLastError();
if ( hToken != NULL )
{
SetThreadToken( NULL, hToken );
SetLastError( dwError );
}
if ( !bRet ) {
if ( (g_eventLog != NULL) && !m_fDiskFullShutdown) {
const CHAR* tmpString[1];
tmpString[0] = rgchPath;
g_eventLog->LogEvent(
LOG_EVENT_CREATE_DIR_ERROR,
1,
tmpString,
GetLastError()
);
}
IIS_PRINTF((buff,"IISCreateDir[%s] error %d\n",
rgchPath, GetLastError()));
fReturn = FALSE;
goto exit;
}
lstrcat( rgchPath, "\\");
lstrcat( rgchPath, m_strLogFileName.QueryStr());
m_pLogFile = new ILOG_FILE( );
if (m_pLogFile != NULL) {
if ( m_pLogFile->Open(
rgchPath,
QuerySizeForTruncation(),
!m_fDiskFullShutdown
) ) {
m_pLogFile->QueryFileSize(&m_cbTotalWritten);
} else {
delete m_pLogFile;
m_pLogFile = NULL;
fReturn = FALSE;
}
} else {
IIS_PRINTF((buff,"Unable to allocate ILOG_FILE[err %d]\n",
GetLastError()));
fReturn = FALSE;
}
}
exit:
return ( fReturn);
} // CLogFileCtrl::OpenLogFile
//************************************************************************************
BOOL
CLogFileCtrl::WriteLogDirectives(
IN DWORD Sludge
)
/*++
Routine Description:
virtual function for the sub class to log directives to the file.
Arguments:
Sludge - number of additional bytes that needs to be written
together with the directives
Return Value:
TRUE, ok
FALSE, not enough space to write.
--*/
{
//
// if we will overflow, open another file
//
if ( IsFileOverFlowForCB( Sludge ) ) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
DBGPRINTF((DBG_CONTEXT,
"Unable to write directive\n"));
return(FALSE);
}
return TRUE;
} // CLogFileCtrl::WriteLogDirectives
//************************************************************************************
BOOL
CLogFileCtrl::WriteCustomLogDirectives(
IN DWORD
)
{
return TRUE;
}
//************************************************************************************
VOID
CLogFileCtrl::I_FormNewLogFileName(
IN LPSYSTEMTIME pstNow,
IN LPCSTR LogNamePrefix
)
{
CHAR tmpBuf[MAX_PATH+1];
WORD wYear = ( pstNow->wYear % 100); // retain just last 2 digits.
switch ( QueryPeriod( ) ) {
case INET_LOG_PERIOD_HOURLY:
wsprintf( tmpBuf, "%.2s%02.2u%02u%02u%02u.%s",
LogNamePrefix,
wYear,
pstNow->wMonth,
pstNow->wDay,
pstNow->wHour,
DEFAULT_LOG_FILE_EXTENSION);
break;
case INET_LOG_PERIOD_DAILY:
wsprintf( tmpBuf, "%.2s%02.2u%02u%02u.%s",
LogNamePrefix,
wYear,
pstNow->wMonth,
pstNow->wDay,
DEFAULT_LOG_FILE_EXTENSION);
break;
case INET_LOG_PERIOD_WEEKLY:
wsprintf( tmpBuf, "%.2s%02.2u%02u%02u.%s",
LogNamePrefix,
wYear,
pstNow->wMonth,
WeekOfMonth(pstNow),
DEFAULT_LOG_FILE_EXTENSION);
break;
case INET_LOG_PERIOD_MONTHLY:
wsprintf( tmpBuf, "%.2s%02u%02u.%s",
LogNamePrefix,
wYear,
pstNow->wMonth,
DEFAULT_LOG_FILE_EXTENSION);
break;
case INET_LOG_PERIOD_NONE:
default:
wsprintf(tmpBuf, "%.6s%u.%s",
LogNamePrefix,
m_sequence,
DEFAULT_LOG_FILE_EXTENSION);
m_sequence++;
break;
} // switch()
m_strLogFileName.Copy(tmpBuf);
return;
}
//************************************************************************************
VOID
CLogFileCtrl::SetLogFileDirectory(
IN LPCSTR pszDir
)
{
STR tmpStr;
HANDLE hFile;
WIN32_FIND_DATA findData;
DWORD maxFileSize = 0;
m_strLogFileDirectory.Copy(pszDir);
//
// if period is not none, then return
//
if ( QueryPeriod() != INET_LOG_PERIOD_NONE ) {
return;
}
//
// Get the starting sequence number
//
m_sequence = 1;
//
// Append instance name and the pattern.
// should look like c:\winnt\system32\logfiles\w3svc1\inetsv*.log
//
tmpStr.Copy(pszDir);
// if ( pszDir[tmpStr.QueryCCH()-1] != '\\' ) {
if ( *CharPrev(pszDir, pszDir + tmpStr.QueryCCH()) != '\\' ) {
tmpStr.Append("\\");
}
tmpStr.Append( QueryInstanceName() );
tmpStr.Append( "\\" );
tmpStr.Append( QueryNoPeriodPattern() );
hFile = FindFirstFile( tmpStr.QueryStr(), &findData );
if ( hFile == INVALID_HANDLE_VALUE ) {
return;
}
do {
PCHAR ptr;
DWORD sequence = 1;
ptr = strchr(findData.cFileName, '.');
if (ptr != NULL ) {
*ptr = '\0';
ptr = findData.cFileName;
while ( *ptr != '\0' ) {
if ( isdigit((UCHAR)(*ptr)) ) {
sequence = atoi( ptr );
break;
}
ptr++;
}
if ( sequence > m_sequence ) {
maxFileSize = findData.nFileSizeLow;
m_sequence = sequence;
DBGPRINTF((DBG_CONTEXT,
"Sequence start is %d[%d]\n", sequence, maxFileSize));
}
}
} while ( FindNextFile( hFile, &findData ) );
FindClose(hFile);
if ( (maxFileSize+LOG_FILE_SLOP) > QuerySizeForTruncation() ) {
m_sequence++;
}
return;
} // SetLogFileDirectory
//************************************************************************************
VOID
CLogFileCtrl::WriteLogInformation(
IN SYSTEMTIME& stNow,
IN PCHAR pBuf,
IN DWORD dwSize,
IN BOOL fCustom,
IN BOOL fResetHeaders
)
/*++
Routine Description:
write log line to file
Arguments:
stNow Present Time
fResetHeaders TRUE -> Reset headers, FALSE -> Don't reset headers
pBuf Pointer to Log Line
dwSize Number of characters in pBuf
fCustom TRUE -> Using custom logging, FALSE -> normal logging
Return Value:
--*/
{
BOOL fOpenNewFile;
DWORD err = NO_ERROR;
DWORD tickCount = 0;
Lock ( );
if ( m_pLogFile != NULL )
{
if ( QueryPeriod() == INET_LOG_PERIOD_DAILY )
{
fOpenNewFile = (m_stCurrentFile.wDay != stNow.wDay) ||
(m_stCurrentFile.wMonth != stNow.wMonth);
}
else
{
fOpenNewFile = IsBeginningOfNewPeriod( QueryPeriod(),
&m_stCurrentFile,
&stNow) ||
IsFileOverFlowForCB( dwSize);
//
// Reset headers if day is over. Used for weekly or unlimited files.
//
if ( !fOpenNewFile && !fResetHeaders)
{
fResetHeaders = (m_stCurrentFile.wDay != stNow.wDay) ||
(m_stCurrentFile.wMonth != stNow.wMonth);
}
}
}
else
{
fOpenNewFile = TRUE;
}
if (fOpenNewFile )
{
//
// open a file only after every minute when we hit disk full
//
if ( m_TickResumeOpen != 0 )
{
tickCount = GetTickCount( );
if ( (tickCount < m_TickResumeOpen) ||
((tickCount + TICK_MINUTE) < tickCount ) ) // The Tick counter is about to wrap.
{
goto exit_tick;
}
}
retry_open:
//
// Close existing log
//
TerminateLog();
//
// Open new log file
//
if ( OpenLogFile( &stNow ) )
{
//
// Schedule Callback for closing log file and set flag for writing directives.
//
ScheduleCallback(stNow);
fResetHeaders = TRUE;
}
else
{
err = GetLastError();
//
// The file is already bigger than the truncate size
// try another one.
//
if ( err == ERROR_INSUFFICIENT_BUFFER )
{
FormNewLogFileName( &stNow );
err = NO_ERROR;
goto retry_open;
}
goto exit;
}
}
//
// Reset Headers if needed
//
if ((fResetHeaders) || (fCustom != m_fUsingCustomHeaders))
{
BOOL fSucceeded;
if (fCustom)
{
m_fUsingCustomHeaders = TRUE;
fSucceeded = WriteCustomLogDirectives(dwSize);
}
else
{
m_fUsingCustomHeaders = FALSE;
fSucceeded = WriteLogDirectives(dwSize);
}
if (!fSucceeded)
{
err = GetLastError( );
if ( err == ERROR_INSUFFICIENT_BUFFER )
{
FormNewLogFileName( &stNow );
err = NO_ERROR;
goto retry_open;
}
TerminateLog();
goto exit;
}
//
// record the time of opening of this new file
//
m_stCurrentFile = stNow;
}
//
// write it to the buffer
//
if ( m_pLogFile->Write(pBuf, dwSize) )
{
IncrementBytesWritten(dwSize);
//
// If this had been shutdown, log event for reactivation
//
if ( m_fDiskFullShutdown )
{
m_fDiskFullShutdown = FALSE;
m_TickResumeOpen = 0;
LogWriteEvent( QueryInstanceName(), TRUE );
}
}
else
{
err = GetLastError();
TerminateLog( );
}
exit:
if ( err == ERROR_DISK_FULL )
{
if ( !m_fDiskFullShutdown )
{
m_fDiskFullShutdown = TRUE;
LogWriteEvent( QueryInstanceName(), FALSE );
}
m_TickResumeOpen = GetTickCount();
m_TickResumeOpen += TICK_MINUTE;
}
exit_tick:
Unlock( );
} // LogInformation
//************************************************************************************
DWORD
CLogFileCtrl::ScheduleCallback(SYSTEMTIME& stNow)
{
DWORD dwTimeRemaining = 0;
switch (m_dwPeriod)
{
case INET_LOG_PERIOD_HOURLY:
dwTimeRemaining = 60*60 -
(stNow.wMinute*60 +
stNow.wSecond);
break;
case INET_LOG_PERIOD_DAILY:
dwTimeRemaining = 24*60*60 -
(stNow.wHour*60*60 +
stNow.wMinute*60 +
stNow.wSecond);
break;
case INET_LOG_PERIOD_WEEKLY:
dwTimeRemaining = 7*24*60*60 -
(stNow.wDayOfWeek*24*60*60 +
stNow.wHour*60*60 +
stNow.wMinute*60 +
stNow.wSecond);
break;
case INET_LOG_PERIOD_MONTHLY:
DWORD dwNumDays = 31;
if ( (4 == stNow.wMonth) || // April
(6 == stNow.wMonth) || // June
(9 == stNow.wMonth) || // September
(11 == stNow.wMonth) // November
)
{
dwNumDays = 30;
}
if (2 == stNow.wMonth) // February
{
if ((stNow.wYear % 4 == 0 && stNow.wYear % 100 != 0) || stNow.wYear % 400 == 0)
{
//
// leap year.
//
dwNumDays = 29;
}
else
{
dwNumDays = 28;
}
}
dwTimeRemaining = dwNumDays*24*60*60 -
(stNow.wDay*24*60*60 +
stNow.wHour*60*60 +
stNow.wMinute*60 +
stNow.wSecond);
break;
}
//
// Convert remaining time to millisecs
//
dwTimeRemaining = dwTimeRemaining*1000 - stNow.wMilliseconds;
if (dwTimeRemaining)
{
m_dwSchedulerCookie = ScheduleWorkItem(
LoggingSchedulerCallback,
this,
dwTimeRemaining,
FALSE);
}
return(m_dwSchedulerCookie);
}
//************************************************************************************
CHAR * SkipWhite( CHAR * pch )
{
while ( ISWHITEA( *pch ) )
{
pch++;
}
return pch;
}
//************************************************************************************
DWORD
FastDwToA(
CHAR* pBuf,
DWORD dwV
)
/*++
Routine Description:
Convert DWORD to ascii (decimal )
returns length ( w/o trailing '\0' )
Arguments:
pBuf - buffer where to store converted value
dwV - value to convert
Return Value:
length of ascii string
--*/
{
DWORD v;
if ( dwV < 10 ) {
pBuf[0] = (CHAR)('0'+dwV);
pBuf[1] = '\0';
return 1;
} else if ( dwV < 100 ) {
pBuf[0] = (CHAR)((dwV/10) + '0');
pBuf[1] = (CHAR)((dwV%10) + '0');
pBuf[2] = '\0';
return 2;
} else if ( dwV < 1000 ) {
pBuf[0] = (CHAR)((v=dwV/100) + '0');
dwV -= v * 100;
pBuf[1] = (CHAR)((dwV/10) + '0');
pBuf[2] = (CHAR)((dwV%10) + '0');
pBuf[3] = '\0';
return 3;
} else if ( dwV < 10000 ) {
pBuf[0] = (CHAR)((v=dwV/1000) + '0');
dwV -= v * 1000;
pBuf[1] = (CHAR)((v=dwV/100) + '0');
dwV -= v * 100;
pBuf[2] = (CHAR)((dwV/10) + '0');
pBuf[3] = (CHAR)((dwV%10) + '0');
pBuf[4] = '\0';
return 4;
}
_ultoa(dwV, pBuf, 10);
return (DWORD)strlen(pBuf);
} // FastDwToA
//************************************************************************************
VOID
LogWriteEvent(
IN LPCSTR InstanceName,
IN BOOL fResume
)
{
if ( g_eventLog != NULL ) {
const CHAR* tmpString[1];
tmpString[0] = InstanceName;
g_eventLog->LogEvent(
fResume ?
LOG_EVENT_RESUME_LOGGING :
LOG_EVENT_DISK_FULL_SHUTDOWN,
1,
tmpString,
0);
}
return;
} // LogWriteEvent
//************************************************************************************
VOID WINAPI LoggingSchedulerCallback( PVOID pContext)
{
CLogFileCtrl *pLog = (CLogFileCtrl *) pContext;
//
// There is a possibility of deadlock if another thread is inside TerminateLog
// stuck in RemoveWorkItem, waiting for this callback thread to complete. To
// prevent that we use the synchronization flag - m_fInTerminate.
//
pLog->m_dwSchedulerCookie = 0;
if (!pLog->m_fInTerminate)
{
pLog->TerminateLog();
}
}
//************************************************************************************