WindowsXP-SP1/inetsrv/iis/svcs/infocomm/log/plugin/ilogfile.cxx
2020-09-30 16:53:49 +02:00

695 lines
17 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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);
}
if ( TsIsWindows95() ) {
ZeroMemory(
(PCHAR)((PCHAR)m_pvBuffer + m_cbBufferUsed),
dwSize - m_cbBufferUsed);
}
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;
LONG HiFilePos = 0;
//
// 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:%ld\n",
lLast ));
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 = %d] failed with %d\n",
m_qwFilePos, 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