reactos/base/services/eventlog/file.c
David Quintana 9c589bb131 Sync with trunk r62754.
svn path=/branches/shell-experiments/; revision=62756
2014-04-15 23:01:15 +00:00

1563 lines
44 KiB
C

/*
* PROJECT: ReactOS kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: services/eventlog/file.c
* PURPOSE: Event logging service
* COPYRIGHT: Copyright 2005 Saveliy Tretiakov
Michael Martin
*/
/* INCLUDES *****************************************************************/
#include "eventlog.h"
#include <ndk/iofuncs.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
static LIST_ENTRY LogFileListHead;
static CRITICAL_SECTION LogFileListCs;
/* FUNCTIONS ****************************************************************/
static NTSTATUS
LogfInitializeNew(PLOGFILE LogFile)
{
DWORD dwWritten;
EVENTLOGEOF EofRec;
ZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
SetEndOfFile(LogFile->hFile);
LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
LogFile->Header.MajorVersion = MAJORVER;
LogFile->Header.MinorVersion = MINORVER;
LogFile->Header.CurrentRecordNumber = 1;
LogFile->Header.OldestRecordNumber = 1;
/* FIXME: Read MaxSize from registry for this LogFile.
But for now limit EventLog size to just under 5K. */
LogFile->Header.MaxSize = 5000;
LogFile->Header.Signature = LOGFILE_SIGNATURE;
if (!WriteFile(LogFile->hFile,
&LogFile->Header,
sizeof(EVENTLOGHEADER),
&dwWritten,
NULL))
{
DPRINT1("WriteFile failed:%d!\n", GetLastError());
return STATUS_UNSUCCESSFUL;
}
EofRec.Ones = 0x11111111;
EofRec.Twos = 0x22222222;
EofRec.Threes = 0x33333333;
EofRec.Fours = 0x44444444;
EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
EofRec.BeginRecord = LogFile->Header.StartOffset;
EofRec.EndRecord = LogFile->Header.EndOffset;
if (!WriteFile(LogFile->hFile,
&EofRec,
sizeof(EVENTLOGEOF),
&dwWritten,
NULL))
{
DPRINT1("WriteFile failed:%d!\n", GetLastError());
return STATUS_UNSUCCESSFUL;
}
if (!FlushFileBuffers(LogFile->hFile))
{
DPRINT1("FlushFileBuffers failed:%d!\n", GetLastError());
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
static NTSTATUS
LogfInitializeExisting(PLOGFILE LogFile, BOOL Backup)
{
DWORD dwRead;
DWORD dwRecordsNumber = 0;
DWORD dwRecSize, dwRecSign, dwFilePointer;
PDWORD pdwRecSize2;
PEVENTLOGRECORD RecBuf;
BOOL OvewrWrittenRecords = FALSE;
DPRINT("Initializing LogFile %S\n",LogFile->LogName);
if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (!ReadFile(LogFile->hFile,
&LogFile->Header,
sizeof(EVENTLOGHEADER),
&dwRead,
NULL))
{
DPRINT1("ReadFile failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (dwRead != sizeof(EVENTLOGHEADER))
{
DPRINT("EventLog: Invalid file %S.\n", LogFile->FileName);
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (LogFile->Header.HeaderSize != sizeof(EVENTLOGHEADER) ||
LogFile->Header.EndHeaderSize != sizeof(EVENTLOGHEADER))
{
DPRINT("EventLog: Invalid header size in %S.\n", LogFile->FileName);
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
{
DPRINT("EventLog: Invalid signature %x in %S.\n",
LogFile->Header.Signature, LogFile->FileName);
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (LogFile->Header.EndOffset > GetFileSize(LogFile->hFile, NULL) + 1)
{
DPRINT("EventLog: Invalid eof offset %x in %S.\n",
LogFile->Header.EndOffset, LogFile->FileName);
return STATUS_EVENTLOG_FILE_CORRUPT;
}
/* Set the read location to the oldest record */
dwFilePointer = SetFilePointer(LogFile->hFile, LogFile->Header.StartOffset, NULL, FILE_BEGIN);
if (dwFilePointer == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
for (;;)
{
dwFilePointer = SetFilePointer(LogFile->hFile, 0, NULL, FILE_CURRENT);
if (dwFilePointer == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
/* If the EVENTLOGEOF info has been reached and the oldest record was not immediately after the Header */
if ((dwFilePointer == LogFile->Header.EndOffset) && (LogFile->Header.StartOffset != sizeof(EVENTLOGHEADER)))
{
OvewrWrittenRecords = TRUE;
/* The file has records that overwrote old ones so read them */
dwFilePointer = SetFilePointer(LogFile->hFile, sizeof(EVENTLOGHEADER), NULL, FILE_BEGIN);
}
if (!ReadFile(LogFile->hFile,
&dwRecSize,
sizeof(dwRecSize),
&dwRead,
NULL))
{
DPRINT1("ReadFile failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (dwRead != sizeof(dwRecSize))
break;
if (!ReadFile(LogFile->hFile,
&dwRecSign,
sizeof(dwRecSign),
&dwRead,
NULL))
{
DPRINT1("ReadFile() failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (dwRead != sizeof(dwRecSize))
break;
if (dwRecSign != LOGFILE_SIGNATURE ||
dwRecSize + dwFilePointer > GetFileSize(LogFile->hFile, NULL) + 1 ||
dwRecSize < sizeof(EVENTLOGRECORD))
{
break;
}
if (SetFilePointer(LogFile->hFile,
-((LONG) sizeof(DWORD) * 2),
NULL,
FILE_CURRENT) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed! %d", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
RecBuf = (PEVENTLOGRECORD) HeapAlloc(MyHeap, 0, dwRecSize);
if (RecBuf == NULL)
{
DPRINT1("Can't allocate heap!\n");
return STATUS_NO_MEMORY;
}
if (!ReadFile(LogFile->hFile, RecBuf, dwRecSize, &dwRead, NULL))
{
DPRINT1("ReadFile() failed! %d\n", GetLastError());
HeapFree(MyHeap, 0, RecBuf);
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (dwRead != dwRecSize)
{
HeapFree(MyHeap, 0, RecBuf);
break;
}
/* if OvewrWrittenRecords is TRUE and this record has already been read */
if ((OvewrWrittenRecords == TRUE) && (RecBuf->RecordNumber == LogFile->Header.OldestRecordNumber))
{
HeapFree(MyHeap, 0, RecBuf);
break;
}
pdwRecSize2 = (PDWORD) (((PBYTE) RecBuf) + dwRecSize - 4);
if (*pdwRecSize2 != dwRecSize)
{
DPRINT1("Invalid RecordSizeEnd of record %d (%x) in %S\n",
dwRecordsNumber, *pdwRecSize2, LogFile->LogName);
HeapFree(MyHeap, 0, RecBuf);
break;
}
dwRecordsNumber++;
if (!LogfAddOffsetInformation(LogFile,
RecBuf->RecordNumber,
dwFilePointer))
{
DPRINT1("LogfAddOffsetInformation() failed!\n");
HeapFree(MyHeap, 0, RecBuf);
return STATUS_EVENTLOG_FILE_CORRUPT;
}
HeapFree(MyHeap, 0, RecBuf);
}
LogFile->Header.CurrentRecordNumber = dwRecordsNumber + LogFile->Header.OldestRecordNumber;
if (LogFile->Header.CurrentRecordNumber == 0)
LogFile->Header.CurrentRecordNumber = 1;
/* FIXME: Read MaxSize from registry for this LogFile.
But for now limit EventLog size to just under 5K. */
LogFile->Header.MaxSize = 5000;
if (!Backup)
{
if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (!WriteFile(LogFile->hFile,
&LogFile->Header,
sizeof(EVENTLOGHEADER),
&dwRead,
NULL))
{
DPRINT1("WriteFile failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
if (!FlushFileBuffers(LogFile->hFile))
{
DPRINT1("FlushFileBuffers failed! %d\n", GetLastError());
return STATUS_EVENTLOG_FILE_CORRUPT;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
LogfCreate(PLOGFILE *LogFile,
WCHAR * LogName,
PUNICODE_STRING FileName,
BOOL Permanent,
BOOL Backup)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
PLOGFILE pLogFile;
BOOL bCreateNew = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
pLogFile = (LOGFILE *) HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, sizeof(LOGFILE));
if (!pLogFile)
{
DPRINT1("Can't allocate heap!\n");
return STATUS_NO_MEMORY;
}
InitializeObjectAttributes(&ObjectAttributes,
FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile(&pLogFile->hFile,
Backup ? (GENERIC_READ | SYNCHRONIZE) : (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE),
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
Backup ? FILE_OPEN : FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't create file %wZ (Status: 0x%08lx)\n", FileName, Status);
goto fail;
}
bCreateNew = (IoStatusBlock.Information == FILE_CREATED) ? TRUE: FALSE;
pLogFile->LogName =
(WCHAR *) HeapAlloc(MyHeap,
HEAP_ZERO_MEMORY,
(lstrlenW(LogName) + 1) * sizeof(WCHAR));
if (pLogFile->LogName == NULL)
{
DPRINT1("Can't allocate heap\n");
Status = STATUS_NO_MEMORY;
goto fail;
}
lstrcpyW(pLogFile->LogName, LogName);
pLogFile->FileName =
(WCHAR *) HeapAlloc(MyHeap,
HEAP_ZERO_MEMORY,
(lstrlenW(FileName->Buffer) + 1) * sizeof(WCHAR));
if (pLogFile->FileName == NULL)
{
DPRINT1("Can't allocate heap\n");
Status = STATUS_NO_MEMORY;
goto fail;
}
lstrcpyW(pLogFile->FileName, FileName->Buffer);
pLogFile->OffsetInfo =
(PEVENT_OFFSET_INFO) HeapAlloc(MyHeap,
HEAP_ZERO_MEMORY,
sizeof(EVENT_OFFSET_INFO) * 64);
if (pLogFile->OffsetInfo == NULL)
{
DPRINT1("Can't allocate heap\n");
Status = STATUS_NO_MEMORY;
goto fail;
}
pLogFile->OffsetInfoSize = 64;
pLogFile->Permanent = Permanent;
if (bCreateNew)
Status = LogfInitializeNew(pLogFile);
else
Status = LogfInitializeExisting(pLogFile, Backup);
if (!NT_SUCCESS(Status))
goto fail;
RtlInitializeResource(&pLogFile->Lock);
LogfListAddItem(pLogFile);
fail:
if (!NT_SUCCESS(Status))
{
if ((pLogFile->hFile != NULL) && (pLogFile->hFile != INVALID_HANDLE_VALUE))
CloseHandle(pLogFile->hFile);
if (pLogFile->OffsetInfo)
HeapFree(MyHeap, 0, pLogFile->OffsetInfo);
if (pLogFile->FileName)
HeapFree(MyHeap, 0, pLogFile->FileName);
if (pLogFile->LogName)
HeapFree(MyHeap, 0, pLogFile->LogName);
HeapFree(MyHeap, 0, pLogFile);
}
else
{
*LogFile = pLogFile;
}
return Status;
}
VOID
LogfClose(PLOGFILE LogFile,
BOOL ForceClose)
{
if (LogFile == NULL)
return;
if ((ForceClose == FALSE) &&
(LogFile->Permanent == TRUE))
return;
RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
FlushFileBuffers(LogFile->hFile);
CloseHandle(LogFile->hFile);
LogfListRemoveItem(LogFile);
RtlDeleteResource(&LogFile->Lock);
HeapFree(MyHeap, 0, LogFile->LogName);
HeapFree(MyHeap, 0, LogFile->FileName);
HeapFree(MyHeap, 0, LogFile->OffsetInfo);
HeapFree(MyHeap, 0, LogFile);
return;
}
VOID LogfCloseAll(VOID)
{
while (!IsListEmpty(&LogFileListHead))
{
LogfClose(LogfListHead(), TRUE);
}
DeleteCriticalSection(&LogFileListCs);
}
VOID LogfListInitialize(VOID)
{
InitializeCriticalSection(&LogFileListCs);
InitializeListHead(&LogFileListHead);
}
PLOGFILE LogfListHead(VOID)
{
return CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry);
}
PLOGFILE LogfListItemByName(WCHAR * Name)
{
PLIST_ENTRY CurrentEntry;
PLOGFILE Result = NULL;
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink;
while (CurrentEntry != &LogFileListHead)
{
PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
LOGFILE,
ListEntry);
if (Item->LogName && !lstrcmpi(Item->LogName, Name))
{
Result = Item;
break;
}
CurrentEntry = CurrentEntry->Flink;
}
LeaveCriticalSection(&LogFileListCs);
return Result;
}
/* Index starting from 1 */
INT LogfListItemIndexByName(WCHAR * Name)
{
PLIST_ENTRY CurrentEntry;
INT Result = 0;
INT i = 1;
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink;
while (CurrentEntry != &LogFileListHead)
{
PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
LOGFILE,
ListEntry);
if (Item->LogName && !lstrcmpi(Item->LogName, Name))
{
Result = i;
break;
}
CurrentEntry = CurrentEntry->Flink;
i++;
}
LeaveCriticalSection(&LogFileListCs);
return Result;
}
/* Index starting from 1 */
PLOGFILE LogfListItemByIndex(INT Index)
{
PLIST_ENTRY CurrentEntry;
PLOGFILE Result = NULL;
INT i = 1;
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink;
while (CurrentEntry != &LogFileListHead)
{
if (i == Index)
{
Result = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
break;
}
CurrentEntry = CurrentEntry->Flink;
i++;
}
LeaveCriticalSection(&LogFileListCs);
return Result;
}
INT LogfListItemCount(VOID)
{
PLIST_ENTRY CurrentEntry;
INT i = 0;
EnterCriticalSection(&LogFileListCs);
CurrentEntry = LogFileListHead.Flink;
while (CurrentEntry != &LogFileListHead)
{
CurrentEntry = CurrentEntry->Flink;
i++;
}
LeaveCriticalSection(&LogFileListCs);
return i;
}
VOID LogfListAddItem(PLOGFILE Item)
{
EnterCriticalSection(&LogFileListCs);
InsertTailList(&LogFileListHead, &Item->ListEntry);
LeaveCriticalSection(&LogFileListCs);
}
VOID LogfListRemoveItem(PLOGFILE Item)
{
EnterCriticalSection(&LogFileListCs);
RemoveEntryList(&Item->ListEntry);
LeaveCriticalSection(&LogFileListCs);
}
static BOOL
ReadAnsiLogEntry(HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead)
{
PEVENTLOGRECORD Dst;
PEVENTLOGRECORD Src;
ANSI_STRING StringA;
UNICODE_STRING StringW;
LPWSTR SrcPtr;
LPSTR DstPtr;
LPWSTR SrcString;
LPSTR DstString;
LPVOID lpUnicodeBuffer = NULL;
DWORD dwRead = 0;
DWORD i;
DWORD dwPadding;
DWORD dwEntryLength;
PDWORD pLength;
NTSTATUS Status;
BOOL ret = TRUE;
*lpNumberOfBytesRead = 0;
lpUnicodeBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nNumberOfBytesToRead);
if (lpUnicodeBuffer == NULL)
{
DPRINT1("Alloc failed!\n");
return FALSE;
}
if (!ReadFile(hFile, lpUnicodeBuffer, nNumberOfBytesToRead, &dwRead, NULL))
{
DPRINT1("Read failed!\n");
ret = FALSE;
goto done;
}
Dst = (PEVENTLOGRECORD)lpBuffer;
Src = (PEVENTLOGRECORD)lpUnicodeBuffer;
Dst->TimeGenerated = Src->TimeGenerated;
Dst->Reserved = Src->Reserved;
Dst->RecordNumber = Src->RecordNumber;
Dst->TimeWritten = Src->TimeWritten;
Dst->EventID = Src->EventID;
Dst->EventType = Src->EventType;
Dst->EventCategory = Src->EventCategory;
Dst->NumStrings = Src->NumStrings;
Dst->UserSidLength = Src->UserSidLength;
Dst->DataLength = Src->DataLength;
SrcPtr = (LPWSTR)((DWORD_PTR)Src + sizeof(EVENTLOGRECORD));
DstPtr = (LPSTR)((DWORD_PTR)Dst + sizeof(EVENTLOGRECORD));
/* Convert the module name */
RtlInitUnicodeString(&StringW, SrcPtr);
Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
if (NT_SUCCESS(Status))
{
RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
RtlFreeAnsiString(&StringA);
}
/* Convert the computer name */
if (NT_SUCCESS(Status))
{
SrcPtr = (PWSTR)((DWORD_PTR)SrcPtr + StringW.MaximumLength);
RtlInitUnicodeString(&StringW, SrcPtr);
Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
if (NT_SUCCESS(Status))
{
RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
RtlFreeAnsiString(&StringA);
}
}
/* Add the padding and the User SID*/
if (NT_SUCCESS(Status))
{
dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr - (DWORD_PTR)Dst) % sizeof(DWORD));
RtlZeroMemory(DstPtr, dwPadding);
DstPtr = (LPSTR)((DWORD_PTR)DstPtr + dwPadding);
RtlCopyMemory(DstPtr,
(PVOID)((DWORD_PTR)Src + Src->UserSidOffset),
Src->UserSidLength);
Dst->UserSidOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
}
/* Convert the strings */
if (NT_SUCCESS(Status))
{
DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->UserSidLength);
SrcString = (LPWSTR)((DWORD_PTR)Src + (DWORD)Src->StringOffset);
DstString = (LPSTR)DstPtr;
for (i = 0; i < Dst->NumStrings; i++)
{
RtlInitUnicodeString(&StringW, SrcString);
RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
RtlCopyMemory(DstString, StringA.Buffer, StringA.MaximumLength);
SrcString = (LPWSTR)((DWORD_PTR)SrcString +
(DWORD)StringW.MaximumLength);
DstString = (LPSTR)((DWORD_PTR)DstString +
(DWORD)StringA.MaximumLength);
RtlFreeAnsiString(&StringA);
}
Dst->StringOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
/* Copy the binary data */
DstPtr = (PVOID)DstString;
Dst->DataOffset = (DWORD_PTR)DstPtr - (DWORD_PTR)Dst;
RtlCopyMemory(DstPtr, (PVOID)((DWORD_PTR)Src + Src->DataOffset), Src->DataLength);
/* Add the padding */
DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->DataLength);
dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr-(DWORD_PTR)Dst) % sizeof(DWORD));
RtlZeroMemory(DstPtr, dwPadding);
dwEntryLength = (DWORD)((DWORD_PTR)DstPtr + dwPadding + sizeof(DWORD) - (DWORD_PTR)Dst);
/* Set the entry length at the end of the entry*/
pLength = (PDWORD)((DWORD_PTR)DstPtr + dwPadding);
*pLength = dwEntryLength;
Dst->Length = dwEntryLength;
*lpNumberOfBytesRead = dwEntryLength;
}
done:
if (lpUnicodeBuffer != NULL)
HeapFree(GetProcessHeap(), 0, lpUnicodeBuffer);
return ret;
}
DWORD LogfReadEvent(PLOGFILE LogFile,
DWORD Flags,
DWORD * RecordNumber,
DWORD BufSize,
PBYTE Buffer,
DWORD * BytesRead,
DWORD * BytesNeeded,
BOOL Ansi)
{
DWORD dwOffset, dwRead, dwRecSize;
DWORD dwBufferUsage = 0, dwRecNum;
if (Flags & EVENTLOG_FORWARDS_READ && Flags & EVENTLOG_BACKWARDS_READ)
return ERROR_INVALID_PARAMETER;
if (!(Flags & EVENTLOG_FORWARDS_READ) && !(Flags & EVENTLOG_BACKWARDS_READ))
return ERROR_INVALID_PARAMETER;
if (!Buffer || !BytesRead || !BytesNeeded)
return ERROR_INVALID_PARAMETER;
if ((*RecordNumber==0) && !(EVENTLOG_SEQUENTIAL_READ))
{
return ERROR_INVALID_PARAMETER;
}
dwRecNum = *RecordNumber;
RtlAcquireResourceShared(&LogFile->Lock, TRUE);
*BytesRead = 0;
*BytesNeeded = 0;
dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
if (!dwOffset)
{
RtlReleaseResource(&LogFile->Lock);
return ERROR_HANDLE_EOF;
}
if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed!\n");
goto Done;
}
if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
{
DPRINT1("ReadFile() failed!\n");
goto Done;
}
if (dwRecSize > BufSize)
{
*BytesNeeded = dwRecSize;
RtlReleaseResource(&LogFile->Lock);
return ERROR_INSUFFICIENT_BUFFER;
}
if (SetFilePointer(LogFile->hFile,
-((LONG) sizeof(DWORD)),
NULL,
FILE_CURRENT) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed!\n");
goto Done;
}
if (Ansi == TRUE)
{
if (!ReadAnsiLogEntry(LogFile->hFile, Buffer, dwRecSize, &dwRead))
{
DPRINT1("ReadAnsiLogEntry() failed!\n");
goto Done;
}
}
else
{
if (!ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL))
{
DPRINT1("ReadFile() failed!\n");
goto Done;
}
}
dwBufferUsage += dwRead;
while (dwBufferUsage <= BufSize)
{
if (Flags & EVENTLOG_FORWARDS_READ)
dwRecNum++;
else
dwRecNum--;
dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
if (!dwOffset)
break;
if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed!\n");
goto Done;
}
if (!ReadFile(LogFile->hFile,
&dwRecSize,
sizeof(DWORD),
&dwRead,
NULL))
{
DPRINT1("ReadFile() failed!\n");
goto Done;
}
if (dwBufferUsage + dwRecSize > BufSize)
break;
if (SetFilePointer(LogFile->hFile,
-((LONG) sizeof(DWORD)),
NULL,
FILE_CURRENT) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed!\n");
goto Done;
}
if (Ansi == TRUE)
{
if (!ReadAnsiLogEntry(LogFile->hFile,
Buffer + dwBufferUsage,
dwRecSize,
&dwRead))
{
DPRINT1("ReadAnsiLogEntry() failed!\n");
goto Done;
}
}
else
{
if (!ReadFile(LogFile->hFile,
Buffer + dwBufferUsage,
dwRecSize,
&dwRead,
NULL))
{
DPRINT1("ReadFile() failed!\n");
goto Done;
}
}
dwBufferUsage += dwRead;
}
*BytesRead = dwBufferUsage;
* RecordNumber = dwRecNum;
RtlReleaseResource(&LogFile->Lock);
return ERROR_SUCCESS;
Done:
DPRINT1("LogfReadEvent failed with %x\n",GetLastError());
RtlReleaseResource(&LogFile->Lock);
return GetLastError();
}
BOOL LogfWriteData(PLOGFILE LogFile, DWORD BufSize, PBYTE Buffer)
{
DWORD dwWritten;
DWORD dwRead;
SYSTEMTIME st;
EVENTLOGEOF EofRec;
PEVENTLOGRECORD RecBuf;
LARGE_INTEGER logFileSize;
ULONG RecOffSet;
ULONG WriteOffSet;
if (!Buffer)
return FALSE;
GetSystemTime(&st);
SystemTimeToEventTime(&st, &((PEVENTLOGRECORD) Buffer)->TimeWritten);
RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
if (!GetFileSizeEx(LogFile->hFile, &logFileSize))
{
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
/* If the size of the file is over MaxSize */
if ((logFileSize.QuadPart + BufSize)> LogFile->Header.MaxSize)
{
ULONG OverWriteLength = 0;
WriteOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
RecBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EVENTLOGRECORD));
/* Determine how many records need to be overwritten */
while (TRUE)
{
DPRINT("EventLogFile has reached maximume size\n");
if (!RecBuf)
{
DPRINT1("Failed to allocate buffer for OldestRecord!\n");
HeapFree(GetProcessHeap(), 0, RecBuf);
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
/* Get the oldest record data */
RecOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
if (SetFilePointer(LogFile->hFile,
RecOffSet,
NULL,
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, RecBuf);
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (!ReadFile(LogFile->hFile, RecBuf, sizeof(EVENTLOGRECORD), &dwRead, NULL))
{
DPRINT1("ReadFile() failed!\n");
HeapFree(GetProcessHeap(), 0, RecBuf);
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (RecBuf->Reserved != LOGFILE_SIGNATURE)
{
DPRINT1("LogFile corrupt!\n");
HeapFree(GetProcessHeap(), 0, RecBuf);
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
LogfDeleteOffsetInformation(LogFile,LogFile->Header.OldestRecordNumber);
LogFile->Header.OldestRecordNumber++;
OverWriteLength += RecBuf->Length;
/* Check the size of the record as the record adding may be larger */
if (OverWriteLength >= BufSize)
{
DPRINT("Record will fit. Length %d, BufSize %d\n", OverWriteLength, BufSize);
LogFile->Header.StartOffset = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
break;
}
}
HeapFree(GetProcessHeap(), 0, RecBuf);
}
else
WriteOffSet = LogFile->Header.EndOffset;
if (SetFilePointer(LogFile->hFile,
WriteOffSet,
NULL,
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (!WriteFile(LogFile->hFile, Buffer, BufSize, &dwWritten, NULL))
{
DPRINT1("WriteFile() failed! %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (!LogfAddOffsetInformation(LogFile,
LogFile->Header.CurrentRecordNumber,
WriteOffSet))
{
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
LogFile->Header.CurrentRecordNumber++;
if (WriteOffSet == LogFile->Header.EndOffset)
{
LogFile->Header.EndOffset += dwWritten;
}
if (SetFilePointer(LogFile->hFile,
LogFile->Header.EndOffset,
NULL,
FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
EofRec.Ones = 0x11111111;
EofRec.Twos = 0x22222222;
EofRec.Threes = 0x33333333;
EofRec.Fours = 0x44444444;
EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
EofRec.BeginRecord = LogFile->Header.StartOffset;
EofRec.EndRecord = LogFile->Header.EndOffset;
if (!WriteFile(LogFile->hFile,
&EofRec,
sizeof(EVENTLOGEOF),
&dwWritten,
NULL))
{
DPRINT1("WriteFile() failed! %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (!WriteFile(LogFile->hFile,
&LogFile->Header,
sizeof(EVENTLOGHEADER),
&dwWritten,
NULL))
{
DPRINT1("WriteFile failed! LastError = %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
if (!FlushFileBuffers(LogFile->hFile))
{
DPRINT1("FlushFileBuffers() failed! %d\n", GetLastError());
RtlReleaseResource(&LogFile->Lock);
return FALSE;
}
RtlReleaseResource(&LogFile->Lock);
return TRUE;
}
NTSTATUS
LogfClearFile(PLOGFILE LogFile,
PUNICODE_STRING BackupFileName)
{
NTSTATUS Status;
RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
if (BackupFileName->Length > 0)
{
/* Write a backup file */
Status = LogfBackupFile(LogFile,
BackupFileName);
if (!NT_SUCCESS(Status))
{
DPRINT1("LogfBackupFile failed (Status: 0x%08lx)\n", Status);
return Status;
}
}
Status = LogfInitializeNew(LogFile);
if (!NT_SUCCESS(Status))
{
DPRINT1("LogfInitializeNew failed (Status: 0x%08lx)\n", Status);
}
RtlReleaseResource(&LogFile->Lock);
return Status;
}
NTSTATUS
LogfBackupFile(PLOGFILE LogFile,
PUNICODE_STRING BackupFileName)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
EVENTLOGHEADER Header;
EVENTLOGEOF EofRec;
HANDLE FileHandle = NULL;
ULONG i;
LARGE_INTEGER FileOffset;
NTSTATUS Status;
PUCHAR Buffer = NULL;
DWORD dwOffset, dwRead, dwRecSize;
DPRINT("LogfBackupFile(%p, %wZ)\n", LogFile, BackupFileName);
/* Lock the log file shared */
RtlAcquireResourceShared(&LogFile->Lock, TRUE);
InitializeObjectAttributes(&ObjectAttributes,
BackupFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile(&FileHandle,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_CREATE,
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT("Can't create backup file %wZ (Status: 0x%08lx)\n", BackupFileName, Status);
goto Done;
}
/* Initialize the (dirty) log file header */
Header.HeaderSize = sizeof(EVENTLOGHEADER);
Header.Signature = LOGFILE_SIGNATURE;
Header.MajorVersion = MAJORVER;
Header.MinorVersion = MINORVER;
Header.StartOffset = sizeof(EVENTLOGHEADER);
Header.EndOffset = sizeof(EVENTLOGHEADER);
Header.CurrentRecordNumber = 1;
Header.OldestRecordNumber = 1;
Header.MaxSize = 0;
Header.Flags = ELF_LOGFILE_HEADER_DIRTY;
Header.Retention = LogFile->Header.Retention;
Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
/* Write the (dirty) log file header */
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&Header,
sizeof(EVENTLOGHEADER),
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to write the log file header (Status: 0x%08lx)\n", Status);
goto Done;
}
for (i = LogFile->Header.OldestRecordNumber; i < LogFile->Header.CurrentRecordNumber; i++)
{
dwOffset = LogfOffsetByNumber(LogFile, i);
if (dwOffset == 0)
break;
if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed!\n");
goto Done;
}
if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
{
DPRINT1("ReadFile() failed!\n");
goto Done;
}
if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
DPRINT1("SetFilePointer() failed!\n");
goto Done;
}
Buffer = HeapAlloc(MyHeap, 0, dwRecSize);
if (Buffer == NULL)
{
DPRINT1("HeapAlloc() failed!\n");
goto Done;
}
if (!ReadFile(LogFile->hFile, &Buffer, dwRecSize, &dwRead, NULL))
{
DPRINT1("ReadFile() failed!\n");
goto Done;
}
/* Write the event record */
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
dwRecSize,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed!\n");
goto Done;
}
/* Update the header information */
Header.EndOffset += dwRecSize;
/* Free the buffer */
HeapFree(MyHeap, 0, Buffer);
Buffer = NULL;
}
/* Initialize the EOF record */
EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
EofRec.Ones = 0x11111111;
EofRec.Twos = 0x22222222;
EofRec.Threes = 0x33333333;
EofRec.Fours = 0x44444444;
EofRec.BeginRecord = sizeof(EVENTLOGHEADER);
EofRec.EndRecord = Header.EndOffset;
EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
/* Write the EOF record */
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&EofRec,
sizeof(EVENTLOGEOF),
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed!\n");
goto Done;
}
/* Update the header information */
Header.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
Header.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
Header.MaxSize = Header.EndOffset + sizeof(EVENTLOGEOF);
Header.Flags = 0;
/* Write the (clean) log file header */
FileOffset.QuadPart = 0;
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&Header,
sizeof(EVENTLOGHEADER),
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed!\n");
}
Done:
/* Free the buffer */
if (Buffer != NULL)
HeapFree(MyHeap, 0, Buffer);
/* Close the backup file */
if (FileHandle != NULL)
NtClose(FileHandle);
/* Unlock the log file */
RtlReleaseResource(&LogFile->Lock);
return Status;
}
/* Returns 0 if nothing found. */
ULONG LogfOffsetByNumber(PLOGFILE LogFile, DWORD RecordNumber)
{
DWORD i;
for (i = 0; i < LogFile->OffsetInfoNext; i++)
{
if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
return LogFile->OffsetInfo[i].EventOffset;
}
return 0;
}
DWORD LogfGetOldestRecord(PLOGFILE LogFile)
{
return LogFile->Header.OldestRecordNumber;
}
DWORD LogfGetCurrentRecord(PLOGFILE LogFile)
{
return LogFile->Header.CurrentRecordNumber;
}
BOOL LogfDeleteOffsetInformation(PLOGFILE LogFile, ULONG ulNumber)
{
DWORD i;
if (ulNumber != LogFile->OffsetInfo[0].EventNumber)
{
return FALSE;
}
for (i = 0; i < LogFile->OffsetInfoNext - 1; i++)
{
LogFile->OffsetInfo[i].EventNumber = LogFile->OffsetInfo[i + 1].EventNumber;
LogFile->OffsetInfo[i].EventOffset = LogFile->OffsetInfo[i + 1].EventOffset;
}
LogFile->OffsetInfoNext--;
return TRUE;
}
BOOL LogfAddOffsetInformation(PLOGFILE LogFile, ULONG ulNumber, ULONG ulOffset)
{
LPVOID NewOffsetInfo;
if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
{
NewOffsetInfo = HeapReAlloc(MyHeap,
HEAP_ZERO_MEMORY,
LogFile->OffsetInfo,
(LogFile->OffsetInfoSize + 64) *
sizeof(EVENT_OFFSET_INFO));
if (!NewOffsetInfo)
{
DPRINT1("Can't reallocate heap.\n");
return FALSE;
}
LogFile->OffsetInfo = (PEVENT_OFFSET_INFO) NewOffsetInfo;
LogFile->OffsetInfoSize += 64;
}
LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
LogFile->OffsetInfoNext++;
return TRUE;
}
PBYTE LogfAllocAndBuildNewRecord(LPDWORD lpRecSize,
DWORD dwRecordNumber,
WORD wType,
WORD wCategory,
DWORD dwEventId,
LPCWSTR SourceName,
LPCWSTR ComputerName,
DWORD dwSidLength,
PSID lpUserSid,
WORD wNumStrings,
WCHAR * lpStrings,
DWORD dwDataSize,
LPVOID lpRawData)
{
DWORD dwRecSize;
PEVENTLOGRECORD pRec;
SYSTEMTIME SysTime;
WCHAR *str;
UINT i, pos;
PBYTE Buffer;
dwRecSize =
sizeof(EVENTLOGRECORD) + (lstrlenW(ComputerName) +
lstrlenW(SourceName) + 2) * sizeof(WCHAR);
if (dwRecSize % 4 != 0)
dwRecSize += 4 - (dwRecSize % 4);
dwRecSize += dwSidLength;
for (i = 0, str = lpStrings; i < wNumStrings; i++)
{
dwRecSize += (lstrlenW(str) + 1) * sizeof(WCHAR);
str += lstrlenW(str) + 1;
}
dwRecSize += dwDataSize;
if (dwRecSize % 4 != 0)
dwRecSize += 4 - (dwRecSize % 4);
dwRecSize += 4;
Buffer = HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, dwRecSize);
if (!Buffer)
{
DPRINT1("Can't allocate heap!\n");
return NULL;
}
pRec = (PEVENTLOGRECORD) Buffer;
pRec->Length = dwRecSize;
pRec->Reserved = LOGFILE_SIGNATURE;
pRec->RecordNumber = dwRecordNumber;
GetSystemTime(&SysTime);
SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
pRec->EventID = dwEventId;
pRec->EventType = wType;
pRec->EventCategory = wCategory;
pos = sizeof(EVENTLOGRECORD);
lstrcpyW((WCHAR *) (Buffer + pos), SourceName);
pos += (lstrlenW(SourceName) + 1) * sizeof(WCHAR);
lstrcpyW((WCHAR *) (Buffer + pos), ComputerName);
pos += (lstrlenW(ComputerName) + 1) * sizeof(WCHAR);
pRec->UserSidOffset = pos;
if (pos % 4 != 0)
pos += 4 - (pos % 4);
if (dwSidLength)
{
CopyMemory(Buffer + pos, lpUserSid, dwSidLength);
pRec->UserSidLength = dwSidLength;
pRec->UserSidOffset = pos;
pos += dwSidLength;
}
pRec->StringOffset = pos;
for (i = 0, str = lpStrings; i < wNumStrings; i++)
{
lstrcpyW((WCHAR *) (Buffer + pos), str);
pos += (lstrlenW(str) + 1) * sizeof(WCHAR);
str += lstrlenW(str) + 1;
}
pRec->NumStrings = wNumStrings;
pRec->DataOffset = pos;
if (dwDataSize)
{
pRec->DataLength = dwDataSize;
CopyMemory(Buffer + pos, lpRawData, dwDataSize);
pos += dwDataSize;
}
if (pos % 4 != 0)
pos += 4 - (pos % 4);
*((PDWORD) (Buffer + pos)) = dwRecSize;
*lpRecSize = dwRecSize;
return Buffer;
}
VOID
LogfReportEvent(WORD wType,
WORD wCategory,
DWORD dwEventId,
WORD wNumStrings,
WCHAR *lpStrings,
DWORD dwDataSize,
LPVOID lpRawData)
{
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
PEVENTSOURCE pEventSource = NULL;
PBYTE logBuffer;
DWORD lastRec;
DWORD recSize;
DWORD dwError;
if (!GetComputerNameW(szComputerName, &dwComputerNameLength))
{
szComputerName[0] = 0;
}
pEventSource = GetEventSourceByName(L"EventLog");
if (pEventSource == NULL)
{
return;
}
lastRec = LogfGetCurrentRecord(pEventSource->LogFile);
logBuffer = LogfAllocAndBuildNewRecord(&recSize,
lastRec,
wType,
wCategory,
dwEventId,
pEventSource->szName,
(LPCWSTR)szComputerName,
0,
NULL,
wNumStrings,
lpStrings,
dwDataSize,
lpRawData);
dwError = LogfWriteData(pEventSource->LogFile, recSize, logBuffer);
if (!dwError)
{
DPRINT1("ERROR WRITING TO EventLog %S\n", pEventSource->LogFile->FileName);
}
LogfFreeRecord(logBuffer);
}