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.
687 lines
17 KiB
687 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1995-1996 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
ilogfile.cxx
|
|
|
|
Abstract:
|
|
This module defines helper functions for File logging
|
|
|
|
Author:
|
|
|
|
Murali R. Krishnan ( MuraliK ) 21-FEb-1996
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
#define BLOCK_INC_SIZE 1
|
|
|
|
#if !defined(STATUS_DISK_FULL)
|
|
#define STATUS_DISK_FULL 0xC000007FL
|
|
#endif
|
|
|
|
ILOG_FILE::ILOG_FILE(
|
|
VOID
|
|
)
|
|
/*++
|
|
This function constructs a new File object used for handling
|
|
log files.
|
|
|
|
The reference count is used to count the number of owners
|
|
of this object. It starts off with 1.
|
|
the ILOG_FILE::OpenFileForAppend() function
|
|
inrements refcount when a new owner is given this object
|
|
the ILOG_FILE::CloseFile() function
|
|
derements refcount when an owner relinquishes the object
|
|
|
|
--*/
|
|
:
|
|
m_hFile ( INVALID_HANDLE_VALUE),
|
|
m_pvBuffer ( NULL),
|
|
m_cbBufferUsed ( 0),
|
|
m_hMemFile ( NULL),
|
|
m_nGranules ( 0),
|
|
m_strFileName ( )
|
|
{
|
|
SYSTEM_INFO sysInfo;
|
|
|
|
m_qwFilePos.QuadPart = 0;
|
|
m_mapSize.QuadPart = 0;
|
|
|
|
GetSystemInfo(&sysInfo);
|
|
m_dwAllocationGranularity = sysInfo.dwAllocationGranularity;
|
|
|
|
if ( m_dwAllocationGranularity == 0 ) {
|
|
m_dwAllocationGranularity = 0x10000;
|
|
}
|
|
|
|
} // ILOG_FILE::ILOG_FILE()
|
|
|
|
|
|
|
|
|
|
ILOG_FILE::~ILOG_FILE(VOID)
|
|
/*++
|
|
This function cleans up state maintained within the object -
|
|
freeing up the memory and closing file handle.
|
|
It then destroys all state information maintained.
|
|
|
|
The reference count should be zero, indicating this object is no more in use.
|
|
|
|
--*/
|
|
{
|
|
CloseFile();
|
|
|
|
return;
|
|
} // ILOG_FILE::~ILOG_FILE()
|
|
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::ExpandMapping(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
m_mapSize.QuadPart = m_mapSize.QuadPart + (ULONGLONG)(BLOCK_INC_SIZE * m_dwAllocationGranularity);
|
|
|
|
/*
|
|
//
|
|
// This check is removed as now condition isn't true becuase we are not limited by 32 bit
|
|
// truncation size
|
|
//
|
|
if ( (newMapSize.QuadPart < m_mapSize.QuadPart) || (m_mapSize.QuadPart > m_qwTruncateSize.QuadPart) ) {
|
|
IIS_PRINTF((buff,"Cannot expand mapping. "
|
|
"New size %d will exceed truncation size %d\n",
|
|
newMapSize, m_qwTruncateSize));
|
|
|
|
SetLastError( ERROR_DISK_FULL );
|
|
return(FALSE);
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Destroy the old and create a new mapping
|
|
//
|
|
|
|
DestroyMapping( );
|
|
|
|
return(CreateMapping( ));
|
|
|
|
} // ExpandMapping
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::CreateMapping(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// find the next file mapping window
|
|
//
|
|
ULARGE_INTEGER qwStart;
|
|
ULARGE_INTEGER qwTmp;
|
|
|
|
DWORD dwSize;
|
|
|
|
|
|
//DWORD dwSize;
|
|
|
|
qwStart.QuadPart = m_qwFilePos.QuadPart;
|
|
qwStart.LowPart = qwStart.LowPart - (qwStart.LowPart % m_dwAllocationGranularity);
|
|
|
|
|
|
m_hMemFile = CreateFileMapping(
|
|
m_hFile,
|
|
NULL,
|
|
PAGE_READWRITE,
|
|
m_mapSize.HighPart,
|
|
m_mapSize.LowPart,
|
|
NULL ) ;
|
|
|
|
if ( m_hMemFile == NULL ) {
|
|
|
|
#if 0
|
|
IIS_PRINTF((buff,"Error %d in CreateFileMapping[%s][size = %d]\n",
|
|
GetLastError(), m_strFileName.QueryStr(),
|
|
m_mapSize ));
|
|
#endif
|
|
SetLastError( ERROR_DISK_FULL );
|
|
return(FALSE);
|
|
}
|
|
|
|
qwTmp.QuadPart = m_mapSize.QuadPart - qwStart.QuadPart;
|
|
dwSize = qwTmp.LowPart;
|
|
|
|
|
|
qwTmp.QuadPart = m_qwFilePos.QuadPart - qwStart.QuadPart;
|
|
m_cbBufferUsed = qwTmp.LowPart;
|
|
|
|
|
|
m_pvBuffer = MapViewOfFile(
|
|
m_hMemFile,
|
|
FILE_MAP_ALL_ACCESS,
|
|
qwStart.HighPart,
|
|
qwStart.LowPart,
|
|
dwSize
|
|
);
|
|
|
|
if ( m_pvBuffer == NULL ) {
|
|
IIS_PRINTF((buff,"Error %d in MapViewOfFile[%s][%d:%d,%d]\n",
|
|
GetLastError(), m_strFileName.QueryStr(),
|
|
qwStart.HighPart,qwStart.LowPart, dwSize ));
|
|
DestroyMapping();
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
} // CreateMapping
|
|
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::Write(
|
|
IN PCHAR pvData,
|
|
IN DWORD cbData
|
|
)
|
|
/*++
|
|
This function writes the data present in the input buffer of specified
|
|
length to the file.
|
|
For performance reasons, the function actually buffers data in the
|
|
internal buffers of ILOG_FILE object. Such buffered data is flushed
|
|
to disk later on when buffer (chain) is full or when
|
|
a flush call is made from a scheduled flush.
|
|
|
|
Arguments:
|
|
pvData pointer to buffer containing data to be written
|
|
cbData count of characters of data to be written.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is any error.
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER oldFilePos;
|
|
ULARGE_INTEGER newFilePos;
|
|
|
|
BOOL fReturn = TRUE;
|
|
|
|
if ( m_hMemFile == NULL ) {
|
|
SetLastError( ERROR_INVALID_PARAMETER);
|
|
return ( FALSE);
|
|
}
|
|
|
|
//
|
|
// Bug 110351: Need try-except blocks around CopyMemory for dealing
|
|
// with compressed files
|
|
//
|
|
|
|
oldFilePos.QuadPart = m_qwFilePos.QuadPart;
|
|
newFilePos.QuadPart = m_qwFilePos.QuadPart + (ULONGLONG)cbData;
|
|
|
|
//
|
|
// copy part of the data to the end of the buffer
|
|
//
|
|
|
|
if (newFilePos.QuadPart > m_mapSize.QuadPart ) {
|
|
|
|
ULARGE_INTEGER qwSpace;
|
|
DWORD dwSpace;
|
|
|
|
qwSpace.QuadPart = m_mapSize.QuadPart - m_qwFilePos.QuadPart;
|
|
|
|
dwSpace = qwSpace.LowPart;
|
|
|
|
__try
|
|
{
|
|
CopyMemory(
|
|
(LPBYTE)m_pvBuffer + m_cbBufferUsed,
|
|
(PVOID)pvData,
|
|
dwSpace
|
|
);
|
|
|
|
}
|
|
__except( ( _exception_code() == STATUS_IN_PAGE_ERROR ||
|
|
_exception_code() == STATUS_DISK_FULL ) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH )
|
|
{
|
|
SetLastError( _exception_code() );
|
|
goto error_exit;
|
|
}
|
|
|
|
cbData -= dwSpace;
|
|
pvData += dwSpace;
|
|
m_cbBufferUsed += dwSpace;
|
|
m_qwFilePos.QuadPart = m_qwFilePos.QuadPart + qwSpace.QuadPart;
|
|
|
|
|
|
if ( !ExpandMapping( ) )
|
|
{
|
|
DWORD err = GetLastError();
|
|
SetLastError(err);
|
|
goto error_exit;
|
|
}
|
|
}
|
|
|
|
__try
|
|
{
|
|
CopyMemory(
|
|
(LPBYTE)m_pvBuffer + m_cbBufferUsed,
|
|
pvData,
|
|
cbData
|
|
);
|
|
}
|
|
__except(( _exception_code() == STATUS_IN_PAGE_ERROR ||
|
|
_exception_code() == STATUS_DISK_FULL ) ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH )
|
|
{
|
|
SetLastError( _exception_code() );
|
|
goto error_exit;
|
|
}
|
|
|
|
m_cbBufferUsed += cbData;
|
|
|
|
m_qwFilePos.QuadPart = m_qwFilePos.QuadPart + (ULONGLONG)cbData;
|
|
|
|
return ( fReturn);
|
|
|
|
error_exit:
|
|
|
|
m_qwFilePos.QuadPart = oldFilePos.QuadPart;
|
|
CloseFile( );
|
|
return(FALSE);
|
|
|
|
|
|
} // ILOG_FILE::Write()
|
|
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::Open(
|
|
IN LPCSTR pszFileName,
|
|
IN DWORD dwTruncationSize,
|
|
IN BOOL fLogEvent
|
|
)
|
|
/*++
|
|
This function opens up a new file for appending data.
|
|
This function automatically sets the file pointer to be
|
|
at the end of file to just enable append to file.
|
|
|
|
This function should be called after locking this object
|
|
|
|
Arguments:
|
|
pszFileName - name of the file to open
|
|
dwTruncationSize
|
|
fLogEvent - Produce an event log if Open fails.
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is any failure.
|
|
|
|
--*/
|
|
{
|
|
BOOL fRet;
|
|
HANDLE hToken = NULL;
|
|
|
|
if ( dwTruncationSize < MIN_FILE_TRUNCATION_SIZE ) {
|
|
dwTruncationSize = MIN_FILE_TRUNCATION_SIZE;
|
|
}
|
|
|
|
m_qwTruncateSize.HighPart = 0;
|
|
m_qwTruncateSize.LowPart = dwTruncationSize;
|
|
|
|
m_nGranules = BLOCK_INC_SIZE;
|
|
m_mapSize.QuadPart = UInt32x32To64(m_nGranules,m_dwAllocationGranularity);
|
|
m_strFileName.Copy(pszFileName);
|
|
|
|
//
|
|
// 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();
|
|
}
|
|
|
|
fRet = OpenFile( pszFileName, fLogEvent);
|
|
|
|
if ( hToken != NULL )
|
|
{
|
|
SetThreadToken( NULL, hToken );
|
|
}
|
|
|
|
return fRet;
|
|
|
|
} // ILOG_FILE::Open
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::OpenFile(
|
|
IN LPCSTR pszFileName,
|
|
IN BOOL fLogEvent
|
|
)
|
|
{
|
|
ULARGE_INTEGER qwTmp;
|
|
DWORD err = NO_ERROR;
|
|
|
|
|
|
m_qwFilePos.QuadPart = 0;
|
|
m_pvBuffer = NULL;
|
|
m_cbBufferUsed = 0;
|
|
|
|
//
|
|
// 1. Create a new file -- open a file if it already exists
|
|
//
|
|
|
|
m_hFile = CreateFile(pszFileName,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|
NULL, // security attributes
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL); // template file handle
|
|
|
|
if ( m_hFile == INVALID_HANDLE_VALUE ) {
|
|
|
|
err = GetLastError();
|
|
|
|
|
|
if ( (g_eventLog != NULL) && fLogEvent) {
|
|
|
|
const CHAR* tmpString[1];
|
|
tmpString[0] = pszFileName;
|
|
|
|
g_eventLog->LogEvent(
|
|
LOG_EVENT_CREATE_FILE_ERROR,
|
|
1,
|
|
tmpString,
|
|
err
|
|
);
|
|
}
|
|
|
|
IIS_PRINTF((buff,"CreateFile[%s] error %d\n",
|
|
pszFileName, err));
|
|
|
|
SetLastError(err);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// 2. Set the file pointer at the end of the file (append mode)
|
|
//
|
|
|
|
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
|
|
|
|
if ( !PositionToEOF( &m_qwFilePos ) ) {
|
|
err = GetLastError();
|
|
goto error_exit;
|
|
}
|
|
|
|
qwTmp.HighPart = 0;
|
|
qwTmp.LowPart = BLOCK_INC_SIZE * m_dwAllocationGranularity;
|
|
|
|
while ( m_qwFilePos.QuadPart >= m_mapSize.QuadPart ) {
|
|
|
|
m_mapSize.QuadPart = m_mapSize.QuadPart + qwTmp.QuadPart;
|
|
m_nGranules += BLOCK_INC_SIZE;
|
|
}
|
|
|
|
/*
|
|
// not anymore a problem for 64b file possition offsets
|
|
if ( m_mapSize.QuadPart >= m_qwTruncateSize.QuadPart ) {
|
|
IIS_PRINTF((buff,"[OpenFile] Truncate size[%d] exceeded[%d]\n",
|
|
m_qwTruncateSize, m_mapSize));
|
|
err = ERROR_INSUFFICIENT_BUFFER;
|
|
goto error_exit;
|
|
}
|
|
*/
|
|
}
|
|
|
|
if ( !CreateMapping( ) ) {
|
|
err = GetLastError();
|
|
goto error_exit;
|
|
}
|
|
|
|
return ( TRUE );
|
|
|
|
error_exit:
|
|
|
|
CloseFile( );
|
|
SetLastError(err);
|
|
return(FALSE);
|
|
|
|
} // ILOG_FILE::OpenFile()
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::PositionToEOF(
|
|
ULARGE_INTEGER *pFilePos
|
|
)
|
|
/*++
|
|
Determine where to begin append operation
|
|
|
|
This function should be called after locking this object
|
|
|
|
Arguments:
|
|
pFilePos - updated with position where to begin append if success
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is any failure.
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER qwFileSize;
|
|
ULARGE_INTEGER qwFilePos;
|
|
BOOL fReturn = FALSE;
|
|
DWORD dwRet;
|
|
|
|
//
|
|
// If file size multiple of BLOCK_INC_SIZE * m_dwAllocationGranularity
|
|
// then it is likely that file has not been closed properly.
|
|
// If this is the case we need to get the position of the last
|
|
// zero char in the file and start logging there.
|
|
//
|
|
|
|
|
|
qwFileSize.QuadPart = 0;
|
|
qwFileSize.LowPart = GetFileSize( m_hFile,&qwFileSize.HighPart);
|
|
|
|
|
|
if (qwFileSize.LowPart != FILE_SIZE_LOW_MAX || GetLastError()==NO_ERROR)
|
|
{
|
|
if ( (qwFileSize.LowPart == 0) ||
|
|
(qwFileSize.LowPart % m_dwAllocationGranularity) != 0 )
|
|
{
|
|
|
|
qwFilePos.QuadPart = 0;
|
|
|
|
dwRet = SetFilePointer(m_hFile,
|
|
qwFilePos.LowPart,
|
|
(PLONG)(&qwFilePos.HighPart),
|
|
FILE_END);
|
|
|
|
if (dwRet != FILE_SIZE_LOW_MAX || GetLastError()==NO_ERROR)
|
|
{
|
|
|
|
pFilePos->QuadPart = qwFileSize.QuadPart;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
IIS_PRINTF((buff,"SetFilePointer[END] failed %d\n",
|
|
GetLastError()));
|
|
return(FALSE);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// find last zero char in file
|
|
//
|
|
ULARGE_INTEGER lLow;
|
|
ULARGE_INTEGER lHigh;
|
|
ULARGE_INTEGER lLast;
|
|
ULARGE_INTEGER lMiddle;
|
|
CHAR ch;
|
|
DWORD dwRead;
|
|
|
|
lLow.QuadPart = 0;
|
|
lHigh.QuadPart = qwFileSize.QuadPart - 1;
|
|
lLast.QuadPart = qwFileSize.QuadPart;
|
|
|
|
fReturn = TRUE;
|
|
|
|
while ( lLow.QuadPart <= lHigh.QuadPart ) {
|
|
|
|
lMiddle.QuadPart = lLow.QuadPart + (lHigh.QuadPart - lLow.QuadPart) / 2;
|
|
|
|
dwRet = SetFilePointer( m_hFile,
|
|
lMiddle.LowPart,
|
|
(PLONG)(&lMiddle.HighPart),
|
|
FILE_BEGIN);
|
|
|
|
if (dwRet==FILE_SIZE_LOW_MAX && GetLastError()!=NO_ERROR)
|
|
{
|
|
fReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
if ( ReadFile( m_hFile, &ch, 1, &dwRead, NULL ) ) {
|
|
if ( ch == '\0' ) {
|
|
lHigh.QuadPart = lMiddle.QuadPart - 1;
|
|
lLast.QuadPart = lMiddle.QuadPart;
|
|
} else {
|
|
lLow.QuadPart = lMiddle.QuadPart + 1;
|
|
}
|
|
} else {
|
|
fReturn = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( fReturn ) {
|
|
IIS_PRINTF((buff,"[ilogfile.cxx], set log pos:%I64u\n",
|
|
lLast.QuadPart ));
|
|
|
|
dwRet = SetFilePointer( m_hFile,
|
|
lLast.LowPart,
|
|
(PLONG)(&lLast.HighPart),
|
|
FILE_BEGIN );
|
|
|
|
if (dwRet!=FILE_SIZE_LOW_MAX || GetLastError()==NO_ERROR)
|
|
{
|
|
pFilePos->QuadPart = lLast.QuadPart;
|
|
} else
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
IIS_PRINTF((buff,"GetFilePosition failed with %d\n",
|
|
GetLastError()));
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ILOG_FILE::CloseFile(VOID)
|
|
/*++
|
|
This function closes the open file. It flushes out file data
|
|
before closing the file.
|
|
|
|
This function should be called after locking this object
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is any failure.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwRet;
|
|
|
|
DestroyMapping( );
|
|
|
|
if ( m_hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// set the pointer to the end of file
|
|
//
|
|
|
|
dwRet = SetFilePointer( m_hFile,
|
|
m_qwFilePos.LowPart,
|
|
(PLONG)(&m_qwFilePos.HighPart),
|
|
FILE_BEGIN);
|
|
|
|
if ( dwRet==FILE_SIZE_LOW_MAX && GetLastError()!=NO_ERROR )
|
|
{
|
|
|
|
IIS_PRINTF((buff,"SetFilePointer[Pos = %I64u] failed with %d\n",
|
|
m_qwFilePos.QuadPart, GetLastError()));
|
|
|
|
}
|
|
|
|
SetEndOfFile( m_hFile );
|
|
CloseHandle( m_hFile);
|
|
m_hFile = INVALID_HANDLE_VALUE; // store the invalid handle
|
|
}
|
|
|
|
return (TRUE);
|
|
} // ILOG_FILE::CloseFile()
|
|
|
|
|
|
|
|
VOID
|
|
ILOG_FILE::DestroyMapping(
|
|
VOID
|
|
)
|
|
/*++
|
|
This function closes the open file. It flushes out file data
|
|
before closing the file.
|
|
|
|
This function should be called after locking this object
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Returns:
|
|
TRUE on success and FALSE if there is any failure.
|
|
|
|
--*/
|
|
{
|
|
/* NKJ -- why do we need to flush?
|
|
if ( m_hFile != INVALID_HANDLE_VALUE) {
|
|
FlushFileBuffers( m_hFile);
|
|
}
|
|
*/
|
|
|
|
if ( m_pvBuffer != NULL ) {
|
|
/* FlushViewOfFile( m_pvBuffer, 0 ); * NKJ */
|
|
UnmapViewOfFile( m_pvBuffer );
|
|
m_pvBuffer = NULL;
|
|
}
|
|
|
|
if (m_hMemFile!=NULL) {
|
|
CloseHandle( m_hMemFile );
|
|
m_hMemFile = NULL;
|
|
}
|
|
return;
|
|
} // ILOG_FILE::DestroyMapping
|