[EVENTLOG]: Make usage of this library.
CORE-11868 #resolve #comment Committed in r73035.
[EVENTLOG]: Protect the global handle table with a lock as it seems to me that this needs serialization. Please notify me if you think this is not actually necessary (and I'll revert that in case).
svn path=/trunk/; revision=73035
include_directories(
+ ${REACTOS_SOURCE_DIR}/sdk/lib/evtlib
${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl
${CMAKE_CURRENT_BINARY_DIR})
${CMAKE_CURRENT_BINARY_DIR}/eventlogrpc_s.c)
add_executable(eventlog ${SOURCE} eventlog.rc)
+add_pch(eventlog eventlog.h SOURCE)
if(NOT MSVC)
target_link_libraries(eventlog ${PSEH_LIB})
endif()
set_module_type(eventlog win32cui UNICODE)
+target_link_libraries(eventlog evtlib)
add_importlibs(eventlog advapi32 rpcrt4 msvcrt kernel32 ntdll)
-add_pch(eventlog eventlog.h SOURCE)
add_cd_file(TARGET eventlog DESTINATION reactos/system32 FOR all)
return RetCode;
}
-VOID PRINT_HEADER(PEVENTLOGHEADER header)
-{
- ULONG Flags = header->Flags;
-
- DPRINT("HeaderSize = %lu\n", header->HeaderSize);
- DPRINT("Signature = 0x%x\n", header->Signature);
- DPRINT("MajorVersion = %lu\n", header->MajorVersion);
- DPRINT("MinorVersion = %lu\n", header->MinorVersion);
- DPRINT("StartOffset = %lu\n", header->StartOffset);
- DPRINT("EndOffset = 0x%x\n", header->EndOffset);
- DPRINT("CurrentRecordNumber = %lu\n", header->CurrentRecordNumber);
- DPRINT("OldestRecordNumber = %lu\n", header->OldestRecordNumber);
- DPRINT("MaxSize = 0x%x\n", header->MaxSize);
- DPRINT("Retention = 0x%x\n", header->Retention);
- DPRINT("EndHeaderSize = %lu\n", header->EndHeaderSize);
- DPRINT("Flags: ");
- if (Flags & ELF_LOGFILE_HEADER_DIRTY)
- {
- DPRINT("ELF_LOGFILE_HEADER_DIRTY");
- Flags &= ~ELF_LOGFILE_HEADER_DIRTY;
- }
- if (Flags) DPRINT(" | ");
- if (Flags & ELF_LOGFILE_HEADER_WRAP)
- {
- DPRINT("ELF_LOGFILE_HEADER_WRAP");
- Flags &= ~ELF_LOGFILE_HEADER_WRAP;
- }
- if (Flags) DPRINT(" | ");
- if (Flags & ELF_LOGFILE_LOGFULL_WRITTEN)
- {
- DPRINT("ELF_LOGFILE_LOGFULL_WRITTEN");
- Flags &= ~ELF_LOGFILE_LOGFULL_WRITTEN;
- }
- if (Flags) DPRINT(" | ");
- if (Flags & ELF_LOGFILE_ARCHIVE_SET)
- {
- DPRINT("ELF_LOGFILE_ARCHIVE_SET");
- Flags &= ~ELF_LOGFILE_ARCHIVE_SET;
- }
- if (Flags) DPRINT(" | 0x%x", Flags);
- DPRINT("\n");
-}
-
VOID PRINT_RECORD(PEVENTLOGRECORD pRec)
{
UINT i;
#define ROUND_DOWN(n, align) (((ULONG)n) & ~((align) - 1l))
#define ROUND_UP(n, align) ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
+#include <evtlib.h>
+
#include <eventlogrpc_s.h>
#include <strsafe.h>
+// FIXME: For that we may directly include NTOS header??
typedef struct _IO_ERROR_LPC
{
PORT_MESSAGE Header;
IO_ERROR_LOG_MESSAGE Message;
} IO_ERROR_LPC, *PIO_ERROR_LPC;
+// C_ASSERT(sizeof(IO_ERROR_LPC) == 0x100);
-/*
- * Our file format will be compatible with NT's
- */
-#define MAJORVER 1
-#define MINORVER 1
-#define LOGFILE_SIGNATURE 0x654c664c
-
-/*
- * Flags used in logfile header
- */
-#define ELF_LOGFILE_HEADER_DIRTY 1
-#define ELF_LOGFILE_HEADER_WRAP 2
-#define ELF_LOGFILE_LOGFULL_WRITTEN 4
-#define ELF_LOGFILE_ARCHIVE_SET 8
-
-/* FIXME: MSDN reads that the following two structs are in winnt.h. Are they? */
-typedef struct _EVENTLOGHEADER
-{
- ULONG HeaderSize;
- ULONG Signature;
- ULONG MajorVersion;
- ULONG MinorVersion;
- ULONG StartOffset;
- ULONG EndOffset;
- ULONG CurrentRecordNumber;
- ULONG OldestRecordNumber;
- ULONG MaxSize;
- ULONG Flags;
- ULONG Retention;
- ULONG EndHeaderSize;
-} EVENTLOGHEADER, *PEVENTLOGHEADER;
-
-typedef struct _EVENTLOGEOF
-{
- ULONG RecordSizeBeginning;
- ULONG Ones;
- ULONG Twos;
- ULONG Threes;
- ULONG Fours;
- ULONG BeginRecord;
- ULONG EndRecord;
- ULONG CurrentRecordNumber;
- ULONG OldestRecordNumber;
- ULONG RecordSizeEnd;
-} EVENTLOGEOF, *PEVENTLOGEOF;
-
-#define EVENTLOGEOF_SIZE_FIXED (5 * sizeof(ULONG))
-C_ASSERT(EVENTLOGEOF_SIZE_FIXED == FIELD_OFFSET(EVENTLOGEOF, BeginRecord));
-
-typedef struct _EVENT_OFFSET_INFO
-{
- ULONG EventNumber;
- ULONG EventOffset;
-} EVENT_OFFSET_INFO, *PEVENT_OFFSET_INFO;
+/* Defined in evtlib.h */
+// #define LOGFILE_SIGNATURE 0x654c664c // "LfLe"
typedef struct _LOGFILE
{
- HANDLE hFile;
- EVENTLOGHEADER Header;
- ULONG CurrentSize; /* Equivalent to the file size, is <= MaxSize and can be extended to MaxSize if needed */
+ EVTLOGFILE LogFile;
+ HANDLE FileHandle;
WCHAR *LogName;
- WCHAR *FileName;
RTL_RESOURCE Lock;
- PEVENT_OFFSET_INFO OffsetInfo;
- ULONG OffsetInfoSize;
- ULONG OffsetInfoNext;
BOOL Permanent;
LIST_ENTRY ListEntry;
} LOGFILE, *PLOGFILE;
/* eventlog.c */
extern PEVENTSOURCE EventLogSource;
-VOID PRINT_HEADER(PEVENTLOGHEADER header);
VOID PRINT_RECORD(PEVENTLOGRECORD pRec);
PLOGFILE LogfListItemByName(LPCWSTR Name);
// DWORD LogfListItemIndexByName(WCHAR * Name);
+NTSTATUS
+LogfCreate(PLOGFILE* LogFile,
+ PCWSTR LogName,
+ PUNICODE_STRING FileName,
+ ULONG MaxSize,
+ ULONG Retention,
+ BOOLEAN Permanent,
+ BOOLEAN Backup);
+
+VOID
+LogfClose(PLOGFILE LogFile,
+ BOOLEAN ForceClose);
+
+VOID LogfCloseAll(VOID);
+
+NTSTATUS
+LogfClearFile(PLOGFILE LogFile,
+ PUNICODE_STRING BackupFileName);
+NTSTATUS
+LogfBackupFile(PLOGFILE LogFile,
+ PUNICODE_STRING BackupFileName);
NTSTATUS
LogfReadEvents(PLOGFILE LogFile,
NTSTATUS
LogfWriteRecord(PLOGFILE LogFile,
- ULONG BufSize, // SIZE_T
- PEVENTLOGRECORD Record);
-
-NTSTATUS
-LogfClearFile(PLOGFILE LogFile,
- PUNICODE_STRING BackupFileName);
-
-NTSTATUS
-LogfBackupFile(PLOGFILE LogFile,
- PUNICODE_STRING BackupFileName);
-
-NTSTATUS
-LogfCreate(PLOGFILE* LogFile,
- PCWSTR LogName,
- PUNICODE_STRING FileName,
- ULONG ulMaxSize,
- ULONG ulRetention,
- BOOLEAN Permanent,
- BOOLEAN Backup);
-
-VOID
-LogfClose(PLOGFILE LogFile,
- BOOLEAN ForceClose);
-
-VOID LogfCloseAll(VOID);
+ PEVENTLOGRECORD Record,
+ SIZE_T BufSize);
PEVENTLOGRECORD
LogfAllocAndBuildNewRecord(PSIZE_T pRecSize,
/* LOG FILE LIST - FUNCTIONS *************************************************/
-VOID LogfCloseAll(VOID)
-{
- EnterCriticalSection(&LogFileListCs);
-
- while (!IsListEmpty(&LogFileListHead))
- {
- LogfClose(CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry), TRUE);
- }
-
- LeaveCriticalSection(&LogFileListCs);
-
- DeleteCriticalSection(&LogFileListCs);
-}
-
VOID LogfListInitialize(VOID)
{
InitializeCriticalSection(&LogFileListCs);
}
-/* GLOBALS *******************************************************************/
+/* FUNCTIONS *****************************************************************/
-static const EVENTLOGEOF EOFRecord =
+// PELF_ALLOCATE_ROUTINE
+static
+PVOID NTAPI
+LogfpAlloc(IN SIZE_T Size,
+ IN ULONG Flags,
+ IN ULONG Tag)
{
- sizeof(EOFRecord),
- 0x11111111, 0x22222222, 0x33333333, 0x44444444,
- 0, 0, 0, 0,
- sizeof(EOFRecord)
-};
+ UNREFERENCED_PARAMETER(Tag);
+ return RtlAllocateHeap(GetProcessHeap(), Flags, Size);
+}
-/* FUNCTIONS *****************************************************************/
+// PELF_FREE_ROUTINE
+static
+VOID NTAPI
+LogfpFree(IN PVOID Ptr,
+ IN ULONG Flags)
+{
+ RtlFreeHeap(GetProcessHeap(), Flags, Ptr);
+}
-static NTSTATUS
-ReadLogBuffer(IN PLOGFILE LogFile,
- OUT PIO_STATUS_BLOCK IoStatusBlock,
- OUT PVOID Buffer,
- IN ULONG Length,
- IN PLARGE_INTEGER ByteOffset,
- OUT PLARGE_INTEGER NextOffset OPTIONAL)
+// PELF_FILE_READ_ROUTINE
+static
+NTSTATUS NTAPI
+LogfpReadFile(IN PEVTLOGFILE LogFile,
+ IN PLARGE_INTEGER FileOffset,
+ OUT PVOID Buffer,
+ IN SIZE_T Length,
+ OUT PSIZE_T ReadLength OPTIONAL)
{
NTSTATUS Status;
- ULONG BufSize;
- LARGE_INTEGER FileOffset;
-
- ASSERT(LogFile->CurrentSize <= LogFile->Header.MaxSize);
- // ASSERT(ByteOffset->QuadPart <= LogFile->Header.MaxSize);
- ASSERT(ByteOffset->QuadPart <= LogFile->CurrentSize);
-
- if (NextOffset)
- NextOffset->QuadPart = 0LL;
+ PLOGFILE pLogFile = (PLOGFILE)LogFile;
+ IO_STATUS_BLOCK IoStatusBlock;
- /* Read the first part of the buffer */
- FileOffset = *ByteOffset;
- BufSize = min(Length, LogFile->CurrentSize - FileOffset.QuadPart);
+ if (ReadLength)
+ *ReadLength = 0;
- Status = NtReadFile(LogFile->hFile,
+ Status = NtReadFile(pLogFile->FileHandle,
NULL,
NULL,
NULL,
- IoStatusBlock,
+ &IoStatusBlock,
Buffer,
- BufSize,
- &FileOffset,
+ Length,
+ FileOffset,
NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- return Status;
- }
-
- if (Length > BufSize)
- {
- ULONG_PTR Information = IoStatusBlock->Information;
-
- /*
- * The buffer was splitted in two, its second part
- * is to be read at the beginning of the log.
- */
- Buffer = (PVOID)((ULONG_PTR)Buffer + BufSize);
- BufSize = Length - BufSize;
- FileOffset.QuadPart = sizeof(EVENTLOGHEADER);
-
- Status = NtReadFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- IoStatusBlock,
- Buffer,
- BufSize,
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- return Status;
- }
- /* Add the read number of bytes from the first read */
- IoStatusBlock->Information += Information;
- }
- /* We return the offset just after the end of the read buffer */
- if (NextOffset)
- NextOffset->QuadPart = FileOffset.QuadPart + BufSize;
+ if (ReadLength)
+ *ReadLength = IoStatusBlock.Information;
return Status;
}
-static NTSTATUS
-WriteLogBuffer(IN PLOGFILE LogFile,
- OUT PIO_STATUS_BLOCK IoStatusBlock,
- IN PVOID Buffer,
- IN ULONG Length,
- IN PLARGE_INTEGER ByteOffset,
- OUT PLARGE_INTEGER NextOffset OPTIONAL)
+// PELF_FILE_WRITE_ROUTINE
+static
+NTSTATUS NTAPI
+LogfpWriteFile(IN PEVTLOGFILE LogFile,
+ IN PLARGE_INTEGER FileOffset,
+ IN PVOID Buffer,
+ IN SIZE_T Length,
+ OUT PSIZE_T WrittenLength OPTIONAL)
{
NTSTATUS Status;
- ULONG BufSize;
- LARGE_INTEGER FileOffset;
-
- ASSERT(LogFile->CurrentSize <= LogFile->Header.MaxSize);
- ASSERT(ByteOffset->QuadPart <= LogFile->Header.MaxSize);
- ASSERT(ByteOffset->QuadPart <= LogFile->CurrentSize);
-
- if (NextOffset)
- NextOffset->QuadPart = 0LL;
+ PLOGFILE pLogFile = (PLOGFILE)LogFile;
+ IO_STATUS_BLOCK IoStatusBlock;
- /* Write the first part of the buffer */
- FileOffset = *ByteOffset;
- BufSize = min(Length, LogFile->CurrentSize /* LogFile->Header.MaxSize */ - FileOffset.QuadPart);
+ if (WrittenLength)
+ *WrittenLength = 0;
- Status = NtWriteFile(LogFile->hFile,
+ Status = NtWriteFile(pLogFile->FileHandle,
NULL,
NULL,
NULL,
- IoStatusBlock,
+ &IoStatusBlock,
Buffer,
- BufSize,
- &FileOffset,
+ Length,
+ FileOffset,
NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- return Status;
- }
-
- if (Length > BufSize)
- {
- ULONG_PTR Information = IoStatusBlock->Information;
- /*
- * The buffer was splitted in two, its second part is written
- * at the beginning of the log.
- */
- Buffer = (PVOID)((ULONG_PTR)Buffer + BufSize);
- BufSize = Length - BufSize;
- FileOffset.QuadPart = sizeof(EVENTLOGHEADER);
-
- Status = NtWriteFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- IoStatusBlock,
- Buffer,
- BufSize,
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- return Status;
- }
- /* Add the written number of bytes from the first write */
- IoStatusBlock->Information += Information;
-
- /* The log wraps */
- LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
- }
-
- /* We return the offset just after the end of the written buffer */
- if (NextOffset)
- NextOffset->QuadPart = FileOffset.QuadPart + BufSize;
+ if (WrittenLength)
+ *WrittenLength = IoStatusBlock.Information;
return Status;
}
-
-/* Returns 0 if nothing is found */
-static 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;
-}
-
-static BOOL
-LogfAddOffsetInformation(PLOGFILE LogFile,
- ULONG ulNumber,
- ULONG ulOffset)
+// PELF_FILE_SET_SIZE_ROUTINE
+static
+NTSTATUS NTAPI
+LogfpSetFileSize(IN PEVTLOGFILE LogFile,
+ IN ULONG FileSize, // SIZE_T
+ IN ULONG OldFileSize) // SIZE_T
{
- PVOID NewOffsetInfo;
+ NTSTATUS Status;
+ PLOGFILE pLogFile = (PLOGFILE)LogFile;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_END_OF_FILE_INFORMATION FileEofInfo;
+ FILE_ALLOCATION_INFORMATION FileAllocInfo;
- if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
- {
- NewOffsetInfo = HeapReAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- LogFile->OffsetInfo,
- (LogFile->OffsetInfoSize + 64) *
- sizeof(EVENT_OFFSET_INFO));
+ UNREFERENCED_PARAMETER(OldFileSize);
- if (!NewOffsetInfo)
- {
- DPRINT1("Cannot reallocate heap.\n");
- return FALSE;
- }
+ // FIXME: Should we round up FileSize ??
- LogFile->OffsetInfo = (PEVENT_OFFSET_INFO)NewOffsetInfo;
- LogFile->OffsetInfoSize += 64;
- }
+ FileEofInfo.EndOfFile.QuadPart = FileSize;
+ Status = NtSetInformationFile(pLogFile->FileHandle,
+ &IoStatusBlock,
+ &FileEofInfo,
+ sizeof(FileEofInfo),
+ FileEndOfFileInformation);
+ if (!NT_SUCCESS(Status))
+ return Status;
- LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
- LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
- LogFile->OffsetInfoNext++;
+ FileAllocInfo.AllocationSize.QuadPart = FileSize;
+ Status = NtSetInformationFile(pLogFile->FileHandle,
+ &IoStatusBlock,
+ &FileAllocInfo,
+ sizeof(FileAllocInfo),
+ FileAllocationInformation);
- return TRUE;
+ return Status;
}
-static BOOL
-LogfDeleteOffsetInformation(PLOGFILE LogFile,
- ULONG ulNumberMin,
- ULONG ulNumberMax)
+// PELF_FILE_FLUSH_ROUTINE
+static
+NTSTATUS NTAPI
+LogfpFlushFile(IN PEVTLOGFILE LogFile,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length)
{
- DWORD i;
-
- if (ulNumberMin > ulNumberMax)
- return FALSE;
-
- /* Remove records ulNumberMin to ulNumberMax inclusive */
- while (ulNumberMin <= ulNumberMax)
- {
- /*
- * As the offset information is listed in increasing order, and we want
- * to keep the list without holes, we demand that ulNumberMin is the first
- * element in the list.
- */
- if (ulNumberMin != LogFile->OffsetInfo[0].EventNumber)
- return FALSE;
-
- /*
- * RtlMoveMemory(&LogFile->OffsetInfo[0],
- * &LogFile->OffsetInfo[1],
- * sizeof(EVENT_OFFSET_INFO) * (LogFile->OffsetInfoNext - 1));
- */
- 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--;
+ PLOGFILE pLogFile = (PLOGFILE)LogFile;
+ IO_STATUS_BLOCK IoStatusBlock;
- /* Go to the next offset information */
- ulNumberMin++;
- }
+ UNREFERENCED_PARAMETER(FileOffset);
+ UNREFERENCED_PARAMETER(Length);
- return TRUE;
+ return NtFlushBuffersFile(pLogFile->FileHandle, &IoStatusBlock);
}
-static NTSTATUS
-LogfInitializeNew(PLOGFILE LogFile,
- ULONG ulMaxSize,
- ULONG ulRetention)
+NTSTATUS
+LogfCreate(PLOGFILE* LogFile,
+ PCWSTR LogName,
+ PUNICODE_STRING FileName,
+ ULONG MaxSize,
+ ULONG Retention,
+ BOOLEAN Permanent,
+ BOOLEAN Backup)
{
NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
- LARGE_INTEGER FileOffset;
- EVENTLOGEOF EofRec;
-
- /* Initialize the event log header */
- RtlZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
-
- LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
- LogFile->Header.Signature = LOGFILE_SIGNATURE;
- LogFile->Header.MajorVersion = MAJORVER;
- LogFile->Header.MinorVersion = MINORVER;
-
- /* Set the offset to the oldest record */
- LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
- /* Set the offset to the ELF_EOF_RECORD */
- LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
- /* Set the number of the next record that will be added */
- LogFile->Header.CurrentRecordNumber = 1;
- /* The event log is empty, there is no record so far */
- LogFile->Header.OldestRecordNumber = 0;
-
- // FIXME: Windows' EventLog log file sizes are always multiple of 64kB
- // but that does not mean the real log size is == file size.
-
- /* Round MaxSize to be a multiple of ULONG (normally on Windows: multiple of 64 kB) */
- LogFile->Header.MaxSize = ROUND_UP(ulMaxSize, sizeof(ULONG));
- LogFile->CurrentSize = LogFile->Header.MaxSize;
-
- LogFile->Header.Flags = 0;
- LogFile->Header.Retention = ulRetention;
- LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
-
- /* Write the header */
- SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
- SetEndOfFile(LogFile->hFile);
-
- FileOffset.QuadPart = 0LL;
- Status = NtWriteFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &LogFile->Header,
- sizeof(EVENTLOGHEADER),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
+ FILE_STANDARD_INFORMATION FileStdInfo;
+ PLOGFILE pLogFile;
+ SIZE_T LogNameLen;
+ BOOLEAN CreateNew;
+
+ pLogFile = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pLogFile));
+ if (!pLogFile)
{
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- return Status;
+ DPRINT1("Cannot allocate heap!\n");
+ return STATUS_NO_MEMORY;
}
- /* Initialize the ELF_EOF_RECORD and write it */
- RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
- EofRec.BeginRecord = LogFile->Header.StartOffset;
- EofRec.EndRecord = LogFile->Header.EndOffset;
- EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
- EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
-
- Status = NtWriteFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &EofRec,
- sizeof(EofRec),
- NULL,
- NULL);
- if (!NT_SUCCESS(Status))
+ LogNameLen = (LogName ? wcslen(LogName) : 0) + 1;
+ pLogFile->LogName = RtlAllocateHeap(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ LogNameLen * sizeof(WCHAR));
+ if (pLogFile->LogName == NULL)
{
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- return Status;
+ DPRINT1("Cannot allocate heap\n");
+ Status = STATUS_NO_MEMORY;
+ goto Quit;
}
- Status = NtFlushBuffersFile(LogFile->hFile, &IoStatusBlock);
+ if (LogName)
+ StringCchCopyW(pLogFile->LogName, LogNameLen, LogName);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ FileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ DPRINT1("Going to create or open %wZ\n", FileName);
+ Status = NtCreateFile(&pLogFile->FileHandle,
+ 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("NtFlushBuffersFile failed (Status 0x%08lx)\n", Status);
- return Status;
+ DPRINT1("Cannot create file `%wZ' (Status 0x%08lx)\n", FileName, Status);
+ goto Quit;
}
- return STATUS_SUCCESS;
-}
+ CreateNew = (IoStatusBlock.Information == FILE_CREATED);
+ DPRINT1("%wZ %s successfully\n", FileName, CreateNew ? "created" : "opened");
-static NTSTATUS
-LogfInitializeExisting(PLOGFILE LogFile,
- BOOLEAN Backup)
-{
- NTSTATUS Status;
- IO_STATUS_BLOCK IoStatusBlock;
- LARGE_INTEGER FileOffset, NextOffset;
- LARGE_INTEGER LogFileSize;
- DWORD dwRecordsNumber = 0;
- ULONG RecOffset;
- PDWORD pdwRecSize2;
- EVENTLOGEOF EofRec;
- EVENTLOGRECORD RecBuf;
- PEVENTLOGRECORD pRecBuf;
- BOOLEAN Wrapping = FALSE;
- BOOLEAN IsLogDirty = FALSE;
-
- DPRINT("Initializing LogFile %S\n", LogFile->LogName);
-
- /* Read the log header */
- FileOffset.QuadPart = 0LL;
- Status = NtReadFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &LogFile->Header,
- sizeof(EVENTLOGHEADER),
- &FileOffset,
- NULL);
+ /*
+ * Retrieve the log file size and check whether the file is not too large;
+ * this log format only supports files of theoretical size < 0xFFFFFFFF .
+ *
+ * As it happens that, on Windows (and ReactOS), retrieving the End-Of-File
+ * information using NtQueryInformationFile with the FileEndOfFileInformation
+ * class is invalid (who knows why...), use instead the FileStandardInformation
+ * class, and the EndOfFile member of the returned FILE_STANDARD_INFORMATION
+ * structure will give the desired information.
+ */
+ Status = NtQueryInformationFile(pLogFile->FileHandle,
+ &IoStatusBlock,
+ &FileStdInfo,
+ sizeof(FileStdInfo),
+ FileStandardInformation);
if (!NT_SUCCESS(Status))
{
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- return STATUS_EVENTLOG_FILE_CORRUPT;
+ DPRINT1("EventLog: NtQueryInformationFile failed (Status 0x%08lx)\n", Status);
+ goto Quit;
}
- if (IoStatusBlock.Information != sizeof(EVENTLOGHEADER))
+ if (FileStdInfo.EndOfFile.HighPart != 0)
{
- DPRINT("EventLog: Invalid file %S.\n", LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
+ DPRINT1("EventLog: Log `%wZ' is too large.\n", FileName);
+ Status = STATUS_EVENTLOG_FILE_CORRUPT; // STATUS_FILE_TOO_LARGE;
+ goto Quit;
}
- /* Header validity checks */
+ DPRINT("Initializing LogFile `%S'\n", pLogFile->LogName);
+
+ Status = ElfCreateFile(&pLogFile->LogFile,
+ FileName,
+ FileStdInfo.EndOfFile.LowPart,
+ MaxSize,
+ Retention,
+ CreateNew,
+ Backup,
+ LogfpAlloc,
+ LogfpFree,
+ LogfpSetFileSize,
+ LogfpWriteFile,
+ LogfpReadFile,
+ LogfpFlushFile);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
- 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;
- }
+ pLogFile->Permanent = Permanent;
- if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
- {
- DPRINT("EventLog: Invalid signature %x in %S.\n",
- LogFile->Header.Signature, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
+ RtlInitializeResource(&pLogFile->Lock);
- IsLogDirty = (LogFile->Header.Flags & ELF_LOGFILE_HEADER_DIRTY);
+ LogfListAddItem(pLogFile);
- /* If the log is a backup log that is dirty, then it is corrupted */
- if (Backup && IsLogDirty)
+Quit:
+ if (!NT_SUCCESS(Status))
{
- DPRINT("EventLog: Backup log %S is dirty.\n", LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
+ if (pLogFile->FileHandle != NULL)
+ NtClose(pLogFile->FileHandle);
- /*
- * Retrieve the log file size and check whether the file is not too large;
- * this log format only supports files of theoretical size < 0xFFFFFFFF .
- */
- if (!GetFileSizeEx(LogFile->hFile, &LogFileSize))
- return I_RpcMapWin32Status(GetLastError());
+ if (pLogFile->LogName)
+ RtlFreeHeap(GetProcessHeap(), 0, pLogFile->LogName);
- if (LogFileSize.HighPart != 0)
+ RtlFreeHeap(GetProcessHeap(), 0, pLogFile);
+ }
+ else
{
- DPRINT1("EventLog: Log %S is too large.\n", LogFile->FileName);
- // return STATUS_FILE_TOO_LARGE;
- return STATUS_EVENTLOG_FILE_CORRUPT;
+ *LogFile = pLogFile;
}
- LogFile->CurrentSize = LogFileSize.LowPart; // LogFileSize.QuadPart;
+ return Status;
+}
- /* Adjust the log maximum size if needed */
- if (LogFile->CurrentSize > LogFile->Header.MaxSize)
- LogFile->Header.MaxSize = LogFile->CurrentSize;
+VOID
+LogfClose(PLOGFILE LogFile,
+ BOOLEAN ForceClose)
+{
+ if (LogFile == NULL)
+ return;
- /*
- * In a non-backup dirty log, the most up-to-date information about
- * the Start/End offsets and the Oldest and Current event record numbers
- * are found in the EOF record. We need to locate the EOF record without
- * relying on the log header's EndOffset, then patch the log header with
- * the values from the EOF record.
- */
- if ((LogFile->Header.EndOffset >= sizeof(EVENTLOGHEADER)) &&
- (LogFile->Header.EndOffset < LogFile->CurrentSize) &&
- (LogFile->Header.EndOffset & 3) == 0) // EndOffset % sizeof(ULONG) == 0
- {
- /* The header EOF offset may be valid, try to start with it */
- RecOffset = LogFile->Header.EndOffset;
- }
- else
- {
- /* The header EOF offset could not be valid, so start from the beginning */
- RecOffset = sizeof(EVENTLOGHEADER);
- }
+ if (!ForceClose && LogFile->Permanent)
+ return;
- FileOffset.QuadPart = RecOffset;
- Wrapping = FALSE;
+ RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
- for (;;)
- {
- if (Wrapping && FileOffset.QuadPart >= RecOffset)
- {
- DPRINT1("EOF record not found!\n");
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
+ LogfListRemoveItem(LogFile);
- /* Attempt to read the fixed part of an EVENTLOGEOF (may wrap) */
- Status = ReadLogBuffer(LogFile,
- &IoStatusBlock,
- &EofRec,
- EVENTLOGEOF_SIZE_FIXED,
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- if (IoStatusBlock.Information != EVENTLOGEOF_SIZE_FIXED)
- {
- DPRINT1("Cannot read at most an EOF record!\n");
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
+ ElfCloseFile(&LogFile->LogFile);
+ NtClose(LogFile->FileHandle);
+ RtlFreeHeap(GetProcessHeap(), 0, LogFile->LogName);
- /* Is it an EVENTLOGEOF record? */
- if (RtlCompareMemory(&EofRec, &EOFRecord, EVENTLOGEOF_SIZE_FIXED) == EVENTLOGEOF_SIZE_FIXED)
- {
- DPRINT("Found EOF record at %llx\n", FileOffset.QuadPart);
+ RtlDeleteResource(&LogFile->Lock);
- /* Got it! Break the loop and continue */
- break;
- }
+ RtlFreeHeap(GetProcessHeap(), 0, LogFile);
- /* No, continue looping */
- if (*(PULONG)((ULONG_PTR)&EofRec + sizeof(ULONG)) == *(PULONG)(&EOFRecord))
- FileOffset.QuadPart += sizeof(ULONG);
- else
- if (*(PULONG)((ULONG_PTR)&EofRec + 2*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
- FileOffset.QuadPart += 2*sizeof(ULONG);
- else
- if (*(PULONG)((ULONG_PTR)&EofRec + 3*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
- FileOffset.QuadPart += 3*sizeof(ULONG);
- else
- if (*(PULONG)((ULONG_PTR)&EofRec + 4*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
- FileOffset.QuadPart += 4*sizeof(ULONG);
- else
- FileOffset.QuadPart += 5*sizeof(ULONG); // EVENTLOGEOF_SIZE_FIXED
+ return;
+}
- if (FileOffset.QuadPart >= LogFile->CurrentSize /* LogFile->Header.MaxSize */)
- {
- /* Wrap the offset */
- FileOffset.QuadPart -= LogFile->CurrentSize /* LogFile->Header.MaxSize */ - sizeof(EVENTLOGHEADER);
- Wrapping = TRUE;
- }
- }
- /*
- * The only way to be there is to have found a valid EOF record.
- * Otherwise the previous loop has failed and STATUS_EVENTLOG_FILE_CORRUPT
- * was returned.
- */
+VOID LogfCloseAll(VOID)
+{
+ EnterCriticalSection(&LogFileListCs);
- /* Read the full EVENTLOGEOF (may wrap) and validate it */
- Status = ReadLogBuffer(LogFile,
- &IoStatusBlock,
- &EofRec,
- sizeof(EofRec),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- if (IoStatusBlock.Information != sizeof(EofRec))
+ while (!IsListEmpty(&LogFileListHead))
{
- DPRINT1("Cannot read the full EOF record!\n");
- return STATUS_EVENTLOG_FILE_CORRUPT;
+ LogfClose(CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry), TRUE);
}
- /* Complete validity checks */
- if ((EofRec.RecordSizeEnd != EofRec.RecordSizeBeginning) ||
- (EofRec.EndRecord != FileOffset.QuadPart))
- {
- DPRINT1("EOF record %llx is corrupted (0x%x vs. 0x%x ; 0x%x vs. 0x%llx), expected %x %x!\n", FileOffset.QuadPart,
- EofRec.RecordSizeEnd, EofRec.RecordSizeBeginning,
- EofRec.EndRecord, FileOffset.QuadPart,
- EOFRecord.RecordSizeEnd, EOFRecord.RecordSizeBeginning);
- DPRINT1("RecordSizeEnd = %x\n", EofRec.RecordSizeEnd);
- DPRINT1("RecordSizeBeginning = %x\n", EofRec.RecordSizeBeginning);
- DPRINT1("EndRecord = %x\n", EofRec.EndRecord);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
+ LeaveCriticalSection(&LogFileListCs);
+
+ DeleteCriticalSection(&LogFileListCs);
+}
+
+NTSTATUS
+LogfClearFile(PLOGFILE LogFile,
+ PUNICODE_STRING BackupFileName)
+{
+ NTSTATUS Status;
- /* The EOF record is valid, break the loop and continue */
+ /* Lock the log file exclusive */
+ RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
- /* If the log is not dirty, the header values should correspond to the EOF ones */
- if (!IsLogDirty)
+ if (BackupFileName->Length > 0)
{
- if ( (LogFile->Header.StartOffset != EofRec.BeginRecord) ||
- (LogFile->Header.EndOffset != EofRec.EndRecord) ||
- (LogFile->Header.CurrentRecordNumber != EofRec.CurrentRecordNumber) ||
- (LogFile->Header.OldestRecordNumber != EofRec.OldestRecordNumber) )
+ /* Write a backup file */
+ Status = LogfBackupFile(LogFile, BackupFileName);
+ if (!NT_SUCCESS(Status))
{
- DPRINT1("\n"
- "Log header or EOF record is corrupted:\n"
- " StartOffset: 0x%x, expected 0x%x; EndOffset: 0x%x, expected 0x%x;\n"
- " CurrentRecordNumber: %d, expected %d; OldestRecordNumber: %d, expected %d.\n",
- LogFile->Header.StartOffset, EofRec.BeginRecord,
- LogFile->Header.EndOffset , EofRec.EndRecord,
- LogFile->Header.CurrentRecordNumber, EofRec.CurrentRecordNumber,
- LogFile->Header.OldestRecordNumber , EofRec.OldestRecordNumber);
-
- return STATUS_EVENTLOG_FILE_CORRUPT;
+ DPRINT1("LogfBackupFile failed (Status 0x%08lx)\n", Status);
+ goto Quit;
}
}
- /* If the log is dirty, patch the log header with the values from the EOF record */
- if (!Backup && IsLogDirty)
- {
- LogFile->Header.StartOffset = EofRec.BeginRecord;
- LogFile->Header.EndOffset = EofRec.EndRecord;
- LogFile->Header.CurrentRecordNumber = EofRec.CurrentRecordNumber;
- LogFile->Header.OldestRecordNumber = EofRec.OldestRecordNumber;
- }
-
- /*
- * FIXME! During operations the EOF record is the one that is the most
- * updated (its Oldest & Current record numbers are always up-to
- * date) while the ones from the header may be unsync. When closing
- * (or flushing?) the event log, the header's record numbers get
- * updated with the same values as the ones stored in the EOF record.
- */
-
- /* Verify Start/End offsets boundaries */
-
- if ((LogFile->Header.StartOffset >= LogFile->CurrentSize) ||
- (LogFile->Header.StartOffset & 3) != 0) // StartOffset % sizeof(ULONG) != 0
- {
- DPRINT("EventLog: Invalid start offset %x in %S.\n",
- LogFile->Header.StartOffset, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- if ((LogFile->Header.EndOffset >= LogFile->CurrentSize) ||
- (LogFile->Header.EndOffset & 3) != 0) // EndOffset % sizeof(ULONG) != 0
- {
- DPRINT("EventLog: Invalid EOF offset %x in %S.\n",
- LogFile->Header.EndOffset, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
-
- if ((LogFile->Header.StartOffset != LogFile->Header.EndOffset) &&
- (LogFile->Header.MaxSize - LogFile->Header.StartOffset < sizeof(EVENTLOGRECORD)))
- {
- /*
- * If StartOffset does not point to EndOffset i.e. to an EVENTLOGEOF,
- * it should point to a non-splitted EVENTLOGRECORD.
- */
- DPRINT("EventLog: Invalid start offset %x in %S.\n",
- LogFile->Header.StartOffset, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
-
- if ((LogFile->Header.StartOffset < LogFile->Header.EndOffset) &&
- (LogFile->Header.EndOffset - LogFile->Header.StartOffset < sizeof(EVENTLOGRECORD)))
- {
- /*
- * In non-wrapping case, there must be enough space between StartOffset
- * and EndOffset to contain at least a full EVENTLOGRECORD.
- */
- DPRINT("EventLog: Invalid start offset %x or end offset %x in %S.\n",
- LogFile->Header.StartOffset, LogFile->Header.EndOffset, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
-
- if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
- {
- /*
- * Non-wrapping case: the (wrapping) free space starting at EndOffset
- * must be able to contain an EVENTLOGEOF.
- */
- if (LogFile->Header.MaxSize - LogFile->Header.EndOffset +
- LogFile->Header.StartOffset - sizeof(EVENTLOGHEADER) < sizeof(EVENTLOGEOF))
- {
- DPRINT("EventLog: Invalid EOF offset %x in %S.\n",
- LogFile->Header.EndOffset, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- }
- else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
- {
- /*
- * Wrapping case: the free space between EndOffset and StartOffset
- * must be able to contain an EVENTLOGEOF.
- */
- if (LogFile->Header.StartOffset - LogFile->Header.EndOffset < sizeof(EVENTLOGEOF))
- {
- DPRINT("EventLog: Invalid EOF offset %x in %S.\n",
- LogFile->Header.EndOffset, LogFile->FileName);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- }
-
- /* Start enumerating the event records from the beginning */
- RecOffset = LogFile->Header.StartOffset;
- FileOffset.QuadPart = RecOffset;
- Wrapping = FALSE;
-
- // // FIXME! FIXME!
- // if (!(LogFile->Header.Flags & ELF_LOGFILE_HEADER_WRAP))
- // {
- // DPRINT1("Log file was wrapping but the flag was not set! Fixing...\n");
- // LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
- // }
-
- DPRINT("StartOffset = %x, EndOffset = %x\n",
- LogFile->Header.StartOffset, LogFile->Header.EndOffset);
-
- /*
- * For non-backup logs of size < MaxSize, reorganize the events such that
- * they do not wrap as soon as we write new ones.
- */
-#if 0
- if (!Backup)
- {
- pRecBuf = RtlAllocateHeap(GetProcessHeap(), 0, RecBuf.Length);
- if (pRecBuf == NULL)
- {
- DPRINT1("Cannot allocate temporary buffer, skip event reorganization.\n");
- goto Continue;
- }
-
- // TODO: Do the job!
- }
-
-Continue:
-
- DPRINT("StartOffset = %x, EndOffset = %x\n",
- LogFile->Header.StartOffset, LogFile->Header.EndOffset);
-#endif
-
- while (FileOffset.QuadPart != LogFile->Header.EndOffset)
- {
- if (Wrapping && FileOffset.QuadPart >= RecOffset)
- {
- /* We have finished enumerating all the event records */
- break;
- }
-
- /* Read the next EVENTLOGRECORD header at once (it cannot be split) */
- Status = NtReadFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &RecBuf,
- sizeof(RecBuf),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- if (IoStatusBlock.Information != sizeof(RecBuf))
- {
- DPRINT("Length != sizeof(RecBuf)\n");
- break;
- }
-
- if (RecBuf.Reserved != LOGFILE_SIGNATURE ||
- RecBuf.Length < sizeof(EVENTLOGRECORD))
- {
- DPRINT("RecBuf problem\n");
- break;
- }
-
- /* Allocate a full EVENTLOGRECORD (header + data) */
- pRecBuf = RtlAllocateHeap(GetProcessHeap(), 0, RecBuf.Length);
- if (pRecBuf == NULL)
- {
- DPRINT1("Cannot allocate heap!\n");
- return STATUS_NO_MEMORY;
- }
-
- /* Attempt to read the full EVENTLOGRECORD (can wrap) */
- Status = ReadLogBuffer(LogFile,
- &IoStatusBlock,
- pRecBuf,
- RecBuf.Length,
- &FileOffset,
- &NextOffset);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
- RtlFreeHeap(GetProcessHeap(), 0, pRecBuf);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
- if (IoStatusBlock.Information != RecBuf.Length)
- {
- DPRINT1("Oh oh!!\n");
- RtlFreeHeap(GetProcessHeap(), 0, pRecBuf);
- break;
- }
-
- // /* If OverWrittenRecords is TRUE and this record has already been read */
- // if (OverWrittenRecords && (pRecBuf->RecordNumber == LogFile->Header.OldestRecordNumber))
- // {
- // RtlFreeHeap(GetProcessHeap(), 0, pRecBuf);
- // break;
- // }
-
- pdwRecSize2 = (PDWORD)((ULONG_PTR)pRecBuf + RecBuf.Length - 4);
-
- if (*pdwRecSize2 != RecBuf.Length)
- {
- DPRINT1("Invalid RecordSizeEnd of record %d (%x) in %S\n",
- dwRecordsNumber, *pdwRecSize2, LogFile->LogName);
- RtlFreeHeap(GetProcessHeap(), 0, pRecBuf);
- break;
- }
-
- DPRINT("Add new record %d - %x\n", pRecBuf->RecordNumber, FileOffset.QuadPart);
-
- dwRecordsNumber++;
-
- if (!LogfAddOffsetInformation(LogFile,
- pRecBuf->RecordNumber,
- FileOffset.QuadPart))
- {
- DPRINT1("LogfAddOffsetInformation() failed!\n");
- RtlFreeHeap(GetProcessHeap(), 0, pRecBuf);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
-
- RtlFreeHeap(GetProcessHeap(), 0, pRecBuf);
-
- if (NextOffset.QuadPart == LogFile->Header.EndOffset)
- {
- /* We have finished enumerating all the event records */
- DPRINT("NextOffset.QuadPart == LogFile->Header.EndOffset, break\n");
- break;
- }
-
- /*
- * If this was the last event record before the end of the log file,
- * the next one should start at the beginning of the log and the space
- * between the last event record and the end of the file is padded.
- */
- if (LogFile->Header.MaxSize - NextOffset.QuadPart < sizeof(EVENTLOGRECORD))
- {
- /* Wrap to the beginning of the log */
- DPRINT("Wrap!\n");
- NextOffset.QuadPart = sizeof(EVENTLOGHEADER);
- }
-
- /*
- * If the next offset to read is below the current offset,
- * this means we are wrapping.
- */
- if (FileOffset.QuadPart > NextOffset.QuadPart)
- {
- DPRINT("Wrapping = TRUE;\n");
- Wrapping = TRUE;
- }
-
- /* Move the current offset */
- FileOffset = NextOffset;
- }
-
- /* If the event log was empty, it will now contain one record */
- if (dwRecordsNumber != 0 && LogFile->Header.OldestRecordNumber == 0)
- LogFile->Header.OldestRecordNumber = 1;
-
- LogFile->Header.CurrentRecordNumber = dwRecordsNumber + LogFile->Header.OldestRecordNumber;
- if (LogFile->Header.CurrentRecordNumber == 0)
- LogFile->Header.CurrentRecordNumber = 1;
-
- if (!Backup)
+ Status = ElfReCreateFile(&LogFile->LogFile);
+ if (!NT_SUCCESS(Status))
{
- FileOffset.QuadPart = 0LL;
- Status = NtWriteFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &LogFile->Header,
- sizeof(EVENTLOGHEADER),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
-
- Status = NtFlushBuffersFile(LogFile->hFile, &IoStatusBlock);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtFlushBuffersFile failed (Status 0x%08lx)\n", Status);
- return STATUS_EVENTLOG_FILE_CORRUPT;
- }
+ DPRINT1("LogfInitializeNew failed (Status 0x%08lx)\n", Status);
}
- return STATUS_SUCCESS;
+Quit:
+ /* Unlock the log file */
+ RtlReleaseResource(&LogFile->Lock);
+ return Status;
}
NTSTATUS
-LogfCreate(PLOGFILE* LogFile,
- PCWSTR LogName,
- PUNICODE_STRING FileName,
- ULONG ulMaxSize,
- ULONG ulRetention,
- BOOLEAN Permanent,
- BOOLEAN Backup)
+LogfBackupFile(PLOGFILE LogFile,
+ PUNICODE_STRING BackupFileName)
{
- NTSTATUS Status = STATUS_SUCCESS;
+ NTSTATUS Status;
+ LOGFILE BackupLogFile;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
- PLOGFILE pLogFile;
- SIZE_T LogNameLen;
- BOOLEAN CreateNew = FALSE;
- pLogFile = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LOGFILE));
- if (!pLogFile)
- {
- DPRINT1("Cannot allocate heap!\n");
- return STATUS_NO_MEMORY;
- }
+ DPRINT1("LogfBackupFile(%p, %wZ)\n", LogFile, BackupFileName);
+
+ /* Lock the log file shared */
+ RtlAcquireResourceShared(&LogFile->Lock, TRUE);
InitializeObjectAttributes(&ObjectAttributes,
- FileName,
+ BackupFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
- Status = NtCreateFile(&pLogFile->hFile,
- Backup ? (GENERIC_READ | SYNCHRONIZE)
- : (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE),
+ Status = NtCreateFile(&BackupLogFile.FileHandle,
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
- Backup ? FILE_OPEN : FILE_OPEN_IF,
- FILE_SYNCHRONOUS_IO_NONALERT,
+ FILE_CREATE,
+ FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
- DPRINT1("Cannot create file %wZ (Status: 0x%08lx)\n", FileName, Status);
- goto Quit;
- }
-
- CreateNew = (IoStatusBlock.Information == FILE_CREATED);
-
- LogNameLen = (LogName ? wcslen(LogName) : 0) + 1;
- pLogFile->LogName = RtlAllocateHeap(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- LogNameLen * sizeof(WCHAR));
- if (pLogFile->LogName == NULL)
- {
- DPRINT1("Cannot allocate heap\n");
- Status = STATUS_NO_MEMORY;
- goto Quit;
- }
-
- if (LogName)
- StringCchCopyW(pLogFile->LogName, LogNameLen, LogName);
-
- pLogFile->FileName = RtlAllocateHeap(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- /*(wcslen(FileName->Buffer) + 1) * sizeof(WCHAR)*/
- FileName->Length + sizeof(UNICODE_NULL));
- if (pLogFile->FileName == NULL)
- {
- DPRINT1("Cannot allocate heap\n");
- Status = STATUS_NO_MEMORY;
+ DPRINT("Cannot create backup file `%wZ' (Status 0x%08lx)\n", BackupFileName, Status);
goto Quit;
}
- StringCchCopyW(pLogFile->FileName,
- /*wcslen(FileName->Buffer) + 1*/ (FileName->Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR),
- FileName->Buffer);
-
- pLogFile->OffsetInfo = RtlAllocateHeap(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof(EVENT_OFFSET_INFO) * 64);
- if (pLogFile->OffsetInfo == NULL)
- {
- DPRINT1("Cannot allocate heap\n");
- Status = STATUS_NO_MEMORY;
- goto Quit;
- }
- pLogFile->OffsetInfoSize = 64;
- pLogFile->OffsetInfoNext = 0;
-
- pLogFile->Permanent = Permanent;
-
- // FIXME: Always use the regitry values for MaxSize & Retention,
- // even for existing logs!
-
- // FIXME: On Windows, EventLog uses the MaxSize setting
- // from the registry itself; the MaxSize from the header
- // is just for information purposes.
-
- if (CreateNew)
- Status = LogfInitializeNew(pLogFile, ulMaxSize, ulRetention);
- else
- Status = LogfInitializeExisting(pLogFile, Backup);
-
- if (!NT_SUCCESS(Status))
- goto Quit;
-
- RtlInitializeResource(&pLogFile->Lock);
-
- LogfListAddItem(pLogFile);
+ Status = ElfBackupFile(&LogFile->LogFile,
+ &BackupLogFile.LogFile);
Quit:
- if (!NT_SUCCESS(Status))
- {
- if ((pLogFile->hFile != NULL) && (pLogFile->hFile != INVALID_HANDLE_VALUE))
- NtClose(pLogFile->hFile);
-
- if (pLogFile->OffsetInfo)
- RtlFreeHeap(GetProcessHeap(), 0, pLogFile->OffsetInfo);
-
- if (pLogFile->FileName)
- RtlFreeHeap(GetProcessHeap(), 0, pLogFile->FileName);
-
- if (pLogFile->LogName)
- RtlFreeHeap(GetProcessHeap(), 0, pLogFile->LogName);
+ /* Close the backup file */
+ if (BackupLogFile.FileHandle != NULL)
+ NtClose(BackupLogFile.FileHandle);
- RtlFreeHeap(GetProcessHeap(), 0, pLogFile);
- }
- else
- {
- *LogFile = pLogFile;
- }
+ /* Unlock the log file */
+ RtlReleaseResource(&LogFile->Lock);
return Status;
}
-VOID
-LogfClose(PLOGFILE LogFile,
- BOOLEAN ForceClose)
-{
- IO_STATUS_BLOCK IoStatusBlock;
-
- if (LogFile == NULL)
- return;
-
- if (!ForceClose && LogFile->Permanent)
- return;
-
- RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
-
- NtFlushBuffersFile(LogFile->hFile, &IoStatusBlock);
- NtClose(LogFile->hFile);
- LogfListRemoveItem(LogFile);
-
- RtlDeleteResource(&LogFile->Lock);
-
- RtlFreeHeap(GetProcessHeap(), 0, LogFile->LogName);
- RtlFreeHeap(GetProcessHeap(), 0, LogFile->FileName);
- RtlFreeHeap(GetProcessHeap(), 0, LogFile->OffsetInfo);
- RtlFreeHeap(GetProcessHeap(), 0, LogFile);
-
- return;
-}
-
static NTSTATUS
-ReadAnsiLogEntry(IN PLOGFILE LogFile,
- OUT PIO_STATUS_BLOCK IoStatusBlock,
- OUT PVOID Buffer,
- IN ULONG Length,
- IN PLARGE_INTEGER ByteOffset,
- OUT PLARGE_INTEGER NextOffset OPTIONAL)
+ReadRecord(IN PEVTLOGFILE LogFile,
+ IN ULONG RecordNumber,
+ OUT PEVENTLOGRECORD Record,
+ IN SIZE_T BufSize, // Length
+ OUT PSIZE_T BytesRead OPTIONAL,
+ OUT PSIZE_T BytesNeeded OPTIONAL,
+ IN BOOLEAN Ansi)
{
NTSTATUS Status;
- PVOID UnicodeBuffer = NULL;
+ PEVENTLOGRECORD UnicodeBuffer = NULL;
PEVENTLOGRECORD Src, Dst;
ANSI_STRING StringA;
UNICODE_STRING StringW;
PVOID SrcPtr, DstPtr;
- // DWORD dwRead;
DWORD i;
DWORD dwPadding;
- DWORD dwEntryLength;
+ DWORD dwRecordLength;
PDWORD pLength;
- IoStatusBlock->Information = 0;
+ if (!Ansi)
+ {
+ return ElfReadRecord(LogFile,
+ RecordNumber,
+ Record,
+ BufSize,
+ BytesRead,
+ BytesNeeded);
+ }
+
+ if (BytesRead)
+ *BytesRead = 0;
- UnicodeBuffer = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, Length);
+ if (BytesNeeded)
+ *BytesNeeded = 0;
+
+ UnicodeBuffer = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, BufSize);
if (UnicodeBuffer == NULL)
{
DPRINT1("Alloc failed!\n");
return STATUS_NO_MEMORY;
}
- Status = ReadLogBuffer(LogFile,
- IoStatusBlock,
+ Status = ElfReadRecord(LogFile,
+ RecordNumber,
UnicodeBuffer,
- Length,
- ByteOffset,
- NextOffset);
+ BufSize,
+ BytesRead,
+ BytesNeeded);
if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
- // Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto done;
- }
- // dwRead = IoStatusBlock->Information;
+ goto Quit;
- Src = (PEVENTLOGRECORD)UnicodeBuffer;
- Dst = (PEVENTLOGRECORD)Buffer;
+ Src = UnicodeBuffer;
+ Dst = Record;
- Dst->Reserved = Src->Reserved;
- Dst->RecordNumber = Src->RecordNumber;
+ Dst->Reserved = Src->Reserved;
+ Dst->RecordNumber = Src->RecordNumber;
Dst->TimeGenerated = Src->TimeGenerated;
- Dst->TimeWritten = Src->TimeWritten;
- Dst->EventID = Src->EventID;
- Dst->EventType = Src->EventType;
+ Dst->TimeWritten = Src->TimeWritten;
+ Dst->EventID = Src->EventID;
+ Dst->EventType = Src->EventType;
Dst->EventCategory = Src->EventCategory;
- Dst->NumStrings = Src->NumStrings;
+ Dst->NumStrings = Src->NumStrings;
Dst->UserSidLength = Src->UserSidLength;
- Dst->DataLength = Src->DataLength;
+ Dst->DataLength = Src->DataLength;
SrcPtr = (PVOID)((ULONG_PTR)Src + sizeof(EVENTLOGRECORD));
DstPtr = (PVOID)((ULONG_PTR)Dst + sizeof(EVENTLOGRECORD));
DstPtr = (PVOID)((ULONG_PTR)DstPtr + Src->DataLength);
/* Add the padding */
- dwPadding = sizeof(ULONG) - (((ULONG_PTR)DstPtr-(ULONG_PTR)Dst) % sizeof(ULONG));
+ dwPadding = sizeof(ULONG) - (((ULONG_PTR)DstPtr - (ULONG_PTR)Dst) % sizeof(ULONG));
RtlZeroMemory(DstPtr, dwPadding);
- dwEntryLength = (DWORD)((ULONG_PTR)DstPtr + dwPadding + sizeof(ULONG) - (ULONG_PTR)Dst);
-
- /* Set the entry length at the end of the entry */
+ /* Set the record length at the beginning and the end of the record */
+ dwRecordLength = (DWORD)((ULONG_PTR)DstPtr + dwPadding + sizeof(ULONG) - (ULONG_PTR)Dst);
+ Dst->Length = dwRecordLength;
pLength = (PDWORD)((ULONG_PTR)DstPtr + dwPadding);
- *pLength = dwEntryLength;
- Dst->Length = dwEntryLength;
+ *pLength = dwRecordLength;
- IoStatusBlock->Information = dwEntryLength;
+ if (BytesRead)
+ *BytesRead = dwRecordLength;
Status = STATUS_SUCCESS;
-done:
- if (UnicodeBuffer != NULL)
- RtlFreeHeap(GetProcessHeap(), 0, UnicodeBuffer);
+Quit:
+ RtlFreeHeap(GetProcessHeap(), 0, UnicodeBuffer);
return Status;
}
BOOLEAN Ansi)
{
NTSTATUS Status;
- IO_STATUS_BLOCK IoStatusBlock;
- LARGE_INTEGER FileOffset;
- DWORD dwOffset, dwRead, dwRecSize;
- DWORD dwBufferUsage, dwRecNum;
+ ULONG RecNum;
+ SIZE_T ReadLength, NeededSize;
+ ULONG BufferUsage;
/* Parameters validation */
if (!(Flags & EVENTLOG_SEQUENTIAL_READ) && (*RecordNumber == 0))
return STATUS_INVALID_PARAMETER;
+ /* Lock the log file shared */
+ RtlAcquireResourceShared(&LogFile->Lock, TRUE);
+
/*
* In sequential read mode, a record number of 0 means we need
* to determine where to start the read operation. Otherwise
{
if (Flags & EVENTLOG_FORWARDS_READ)
{
- *RecordNumber = LogFile->Header.OldestRecordNumber;
+ *RecordNumber = ElfGetOldestRecord(&LogFile->LogFile);
}
else // if (Flags & EVENTLOG_BACKWARDS_READ)
{
- *RecordNumber = LogFile->Header.CurrentRecordNumber - 1;
+ *RecordNumber = ElfGetCurrentRecord(&LogFile->LogFile) - 1;
}
}
- dwRecNum = *RecordNumber;
-
- RtlAcquireResourceShared(&LogFile->Lock, TRUE);
+ RecNum = *RecordNumber;
*BytesRead = 0;
*BytesNeeded = 0;
- dwBufferUsage = 0;
+ BufferUsage = 0;
do
{
- dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
- if (dwOffset == 0)
+ Status = ReadRecord(&LogFile->LogFile,
+ RecNum,
+ (PEVENTLOGRECORD)(Buffer + BufferUsage),
+ BufSize - BufferUsage,
+ &ReadLength,
+ &NeededSize,
+ Ansi);
+ if (Status == STATUS_NOT_FOUND)
{
- if (dwBufferUsage == 0)
+ if (BufferUsage == 0)
{
- RtlReleaseResource(&LogFile->Lock);
- return STATUS_END_OF_FILE;
+ Status = STATUS_END_OF_FILE;
+ goto Quit;
}
else
{
break;
}
}
-
- FileOffset.QuadPart = dwOffset;
- Status = NtReadFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &dwRecSize,
- sizeof(dwRecSize),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- // Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto Done;
- }
- // dwRead = IoStatusBlock.Information;
-
- if (dwBufferUsage + dwRecSize > BufSize)
+ else
+ if (Status == STATUS_BUFFER_TOO_SMALL)
{
- if (dwBufferUsage == 0)
+ if (BufferUsage == 0)
{
- *BytesNeeded = dwRecSize;
- RtlReleaseResource(&LogFile->Lock);
- return STATUS_BUFFER_TOO_SMALL;
+ *BytesNeeded = NeededSize;
+ // Status = STATUS_BUFFER_TOO_SMALL;
+ goto Quit;
}
else
{
break;
}
}
-
- FileOffset.QuadPart = dwOffset;
- if (Ansi)
- {
- Status = ReadAnsiLogEntry(LogFile,
- &IoStatusBlock,
- Buffer + dwBufferUsage,
- dwRecSize,
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadAnsiLogEntry failed (Status 0x%08lx)\n", Status);
- // Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto Done;
- }
- }
else
+ if (!NT_SUCCESS(Status))
{
- Status = ReadLogBuffer(LogFile,
- &IoStatusBlock,
- Buffer + dwBufferUsage,
- dwRecSize,
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
- // Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto Done;
- }
+ DPRINT1("ElfReadRecord failed (Status 0x%08lx)\n", Status);
+ goto Quit;
}
- dwRead = IoStatusBlock.Information;
/* Go to the next event record */
/*
* "get_next_record_number" function.
*/
if (Flags & EVENTLOG_FORWARDS_READ)
- dwRecNum++;
+ RecNum++;
else // if (Flags & EVENTLOG_BACKWARDS_READ)
- dwRecNum--;
+ RecNum--;
- dwBufferUsage += dwRead;
+ BufferUsage += ReadLength;
}
- while (dwBufferUsage <= BufSize);
+ while (BufferUsage <= BufSize);
- *BytesRead = dwBufferUsage;
- *RecordNumber = dwRecNum;
- RtlReleaseResource(&LogFile->Lock);
- return STATUS_SUCCESS;
+ *BytesRead = BufferUsage;
+ *RecordNumber = RecNum;
-Done:
- DPRINT1("LogfReadEvents failed (Status 0x%08lx)\n", Status);
+ Status = STATUS_SUCCESS;
+
+Quit:
+ /* Unlock the log file */
RtlReleaseResource(&LogFile->Lock);
+
+ if (!NT_SUCCESS(Status))
+ DPRINT1("LogfReadEvents failed (Status 0x%08lx)\n", Status);
+
return Status;
}
NTSTATUS
LogfWriteRecord(PLOGFILE LogFile,
- ULONG BufSize, // SIZE_T
- PEVENTLOGRECORD Record)
+ PEVENTLOGRECORD Record,
+ SIZE_T BufSize)
{
NTSTATUS Status;
- IO_STATUS_BLOCK IoStatusBlock;
- LARGE_INTEGER FileOffset, NextOffset;
- DWORD dwWritten;
- // DWORD dwRead;
LARGE_INTEGER SystemTime;
- EVENTLOGEOF EofRec;
- EVENTLOGRECORD RecBuf;
- ULONG FreeSpace = 0;
- ULONG UpperBound;
- ULONG RecOffset, WriteOffset;
// ASSERT(sizeof(*Record) == sizeof(RecBuf));
if (!Record || BufSize < sizeof(*Record))
return STATUS_INVALID_PARAMETER;
+ /* Lock the log file exclusive */
RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
/*
NtQuerySystemTime(&SystemTime);
RtlTimeToSecondsSince1970(&SystemTime, &Record->TimeWritten);
- Record->RecordNumber = LogFile->Header.CurrentRecordNumber;
-
- /* Compute the available log free space */
- if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
- FreeSpace = LogFile->Header.MaxSize - LogFile->Header.EndOffset + LogFile->Header.StartOffset - sizeof(EVENTLOGHEADER);
- else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
- FreeSpace = LogFile->Header.StartOffset - LogFile->Header.EndOffset;
-
- LogFile->Header.Flags |= ELF_LOGFILE_HEADER_DIRTY;
-
- /* If the event log was empty, it will now contain one record */
- if (LogFile->Header.OldestRecordNumber == 0)
- LogFile->Header.OldestRecordNumber = 1;
-
- /* By default we append the new record at the old EOF record offset */
- WriteOffset = LogFile->Header.EndOffset;
-
- /*
- * Check whether the log is going to wrap (the events being overwritten).
- */
-
- if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
- UpperBound = LogFile->Header.MaxSize;
- else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
- UpperBound = LogFile->Header.StartOffset;
-
- // if (LogFile->Header.MaxSize - WriteOffset < BufSize + sizeof(EofRec))
- if (UpperBound - WriteOffset < BufSize + sizeof(EofRec))
- {
- DPRINT("EventLogFile has reached maximum size (%x), wrapping...\n"
- "UpperBound = %x, WriteOffset = %x, BufSize = %x\n",
- LogFile->Header.MaxSize, UpperBound, WriteOffset, BufSize);
- /* This will be done later */
- }
-
- if ( (LogFile->Header.StartOffset < LogFile->Header.EndOffset) &&
- (LogFile->Header.MaxSize - WriteOffset < sizeof(RecBuf)) ) // (UpperBound - WriteOffset < sizeof(RecBuf))
- {
- // ASSERT(UpperBound == LogFile->Header.MaxSize);
- // ASSERT(WriteOffset == LogFile->Header.EndOffset);
-
- /*
- * We cannot fit the EVENTLOGRECORD header of the buffer before
- * the end of the file. We need to pad the end of the log with
- * 0x00000027, normally we will need to pad at most 0x37 bytes
- * (corresponding to sizeof(EVENTLOGRECORD) - 1).
- */
-
- /* Rewind to the beginning of the log, just after the header */
- WriteOffset = sizeof(EVENTLOGHEADER);
- /**/UpperBound = LogFile->Header.StartOffset;/**/
-
- FreeSpace = LogFile->Header.StartOffset - WriteOffset;
-
- LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
- }
- /*
- * Otherwise, we can fit the header and only part
- * of the data will overwrite the oldest records.
- *
- * It might be possible that all the event record can fit in one piece,
- * but that the EOF record needs to be split. This is not a problem,
- * EVENTLOGEOF can be splitted while EVENTLOGRECORD cannot be.
- */
-
- if (UpperBound - WriteOffset < BufSize + sizeof(EofRec))
- {
- ULONG OrgOldestRecordNumber, OldestRecordNumber;
-
- // DPRINT("EventLogFile has reached maximum size, wrapping...\n");
-
- OldestRecordNumber = OrgOldestRecordNumber = LogFile->Header.OldestRecordNumber;
-
- // FIXME: Assert whether LogFile->Header.StartOffset is the beginning of a record???
- // NOTE: It should be, by construction (and this should have been checked when
- // initializing a new, or existing log).
-
- /*
- * Determine how many old records need to be overwritten.
- * Check the size of the record as the record added may be larger.
- * Need to take into account that we append the EOF record.
- */
- while (FreeSpace < BufSize + sizeof(EofRec))
- {
- /* Get the oldest record data */
- RecOffset = LogfOffsetByNumber(LogFile, OldestRecordNumber);
- if (RecOffset == 0)
- {
- // TODO: It cannot, queue a message box for the user and exit.
- // See also below...
- DPRINT1("Record number %d cannot be found, or LogFile is full and cannot wrap!\n", OldestRecordNumber);
- Status = STATUS_LOG_FILE_FULL; // STATUS_LOG_FULL;
- goto Quit;
- }
-
- RtlZeroMemory(&RecBuf, sizeof(RecBuf));
-
- FileOffset.QuadPart = RecOffset;
- Status = NtReadFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &RecBuf,
- sizeof(RecBuf),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- // Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto Quit;
- }
- // dwRead = IoStatusBlock.Information;
-
- if (RecBuf.Reserved != LOGFILE_SIGNATURE)
- {
- DPRINT1("LogFile corrupt!\n");
- Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto Quit;
- }
-
- /*
- * Check whether this event can be overwritten by comparing its
- * written timestamp with the log's retention value. This value
- * is the time interval, in seconds, that events records are
- * protected from being overwritten.
- *
- * If the retention value is zero the events are always overwritten.
- *
- * If the retention value is non-zero, when the age of an event,
- * in seconds, reaches or exceeds this value, it can be overwritten.
- * Also if the events are in the future, we do not overwrite them.
- */
- if (LogFile->Header.Retention != 0 &&
- (Record->TimeWritten < RecBuf.TimeWritten ||
- (Record->TimeWritten >= RecBuf.TimeWritten &&
- Record->TimeWritten - RecBuf.TimeWritten < LogFile->Header.Retention)))
- {
- // TODO: It cannot, queue a message box for the user and exit.
- DPRINT1("LogFile is full and cannot wrap!\n");
- Status = STATUS_LOG_FILE_FULL; // STATUS_LOG_FULL;
- goto Quit;
- }
-
- /*
- * Advance the oldest record number, add the event record length
- * (as long as it is valid...) then take account for the possible
- * paddind after the record, in case this is the last one at the
- * end of the file.
- */
- OldestRecordNumber++;
- RecOffset += RecBuf.Length;
- FreeSpace += RecBuf.Length;
-
- /*
- * If this was the last event record before the end of the log file,
- * the next one should start at the beginning of the log and the space
- * between the last event record and the end of the file is padded.
- */
- if (LogFile->Header.MaxSize - RecOffset < sizeof(EVENTLOGRECORD))
- {
- /* Add the padding size */
- FreeSpace += LogFile->Header.MaxSize - RecOffset;
- }
- }
-
- DPRINT("Record will fit. FreeSpace %d, BufSize %d\n", FreeSpace, BufSize);
-
- /* The log records are wrapping */
- LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
-
-
- // FIXME: May lead to corruption if the other subsequent calls fail...
-
- /*
- * We have validated all the region of events to be discarded,
- * now we can perform their deletion.
- */
- LogfDeleteOffsetInformation(LogFile, OrgOldestRecordNumber, OldestRecordNumber - 1);
- LogFile->Header.OldestRecordNumber = OldestRecordNumber;
- LogFile->Header.StartOffset = LogfOffsetByNumber(LogFile, OldestRecordNumber);
- if (LogFile->Header.StartOffset == 0)
- {
- /*
- * We have deleted all the existing event records to make place
- * for the new one. We can put it at the start of the event log.
- */
- LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
- WriteOffset = LogFile->Header.StartOffset;
- LogFile->Header.EndOffset = WriteOffset;
- }
-
- DPRINT1("MaxSize = %x, StartOffset = %x, WriteOffset = %x, EndOffset = %x, BufSize = %x\n"
- "OldestRecordNumber = %d\n",
- LogFile->Header.MaxSize, LogFile->Header.StartOffset, WriteOffset, LogFile->Header.EndOffset, BufSize,
- OldestRecordNumber);
- }
-
- /*
- * Expand the log file if needed.
- * NOTE: It may be needed to perform this task a bit sooner if we need
- * such a thing for performing read operations, in the future...
- * Or if this operation needs to modify 'FreeSpace'...
- */
- if (LogFile->CurrentSize < LogFile->Header.MaxSize)
- {
- DPRINT1("Expanding the log file from %lu to %lu\n",
- LogFile->CurrentSize, LogFile->Header.MaxSize);
-
- /* For the moment this is a trivial operation */
- LogFile->CurrentSize = LogFile->Header.MaxSize;
- }
-
- /* Pad the end of the log */
- // if (LogFile->Header.EndOffset + sizeof(RecBuf) > LogFile->Header.MaxSize)
- if (WriteOffset < LogFile->Header.EndOffset)
- {
- /* Pad all the space from LogFile->Header.EndOffset to LogFile->Header.MaxSize */
- dwWritten = ROUND_DOWN(LogFile->Header.MaxSize - LogFile->Header.EndOffset, sizeof(ULONG));
- RtlFillMemoryUlong(&RecBuf, dwWritten, 0x00000027);
-
- FileOffset.QuadPart = LogFile->Header.EndOffset;
- Status = NtWriteFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &RecBuf,
- dwWritten,
- &FileOffset,
- NULL);
- // dwWritten = IoStatusBlock.Information;
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- // goto Quit;
- }
- }
-
- /* Write the event record buffer with possible wrap at offset sizeof(EVENTLOGHEADER) */
- FileOffset.QuadPart = WriteOffset;
- Status = WriteLogBuffer(LogFile,
- &IoStatusBlock,
- Record,
- BufSize,
- &FileOffset,
- &NextOffset);
- // dwWritten = IoStatusBlock.Information;
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("WriteLogBuffer failed (Status 0x%08lx)\n", Status);
- goto Quit;
- }
- /* FileOffset now contains the offset just after the end of the record buffer */
- FileOffset = NextOffset;
-
- if (!LogfAddOffsetInformation(LogFile,
- Record->RecordNumber,
- WriteOffset))
- {
- Status = STATUS_NO_MEMORY; // STATUS_EVENTLOG_FILE_CORRUPT;
- goto Quit;
- }
-
- LogFile->Header.CurrentRecordNumber++;
- if (LogFile->Header.CurrentRecordNumber == 0)
- LogFile->Header.CurrentRecordNumber = 1;
-
- /*
- * Write the new EOF record offset just after the event record.
- * The EOF record can wrap (be splitted) if less than sizeof(EVENTLOGEOF)
- * bytes remains between the end of the record and the end of the log file.
- */
- LogFile->Header.EndOffset = FileOffset.QuadPart;
-
- RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
- EofRec.BeginRecord = LogFile->Header.StartOffset;
- EofRec.EndRecord = LogFile->Header.EndOffset;
- EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
- EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
-
- // FileOffset.QuadPart = LogFile->Header.EndOffset;
- Status = WriteLogBuffer(LogFile,
- &IoStatusBlock,
- &EofRec,
- sizeof(EofRec),
- &FileOffset,
- &NextOffset);
- // dwWritten = IoStatusBlock.Information;
- if (!NT_SUCCESS(Status))
+ Status = ElfWriteRecord(&LogFile->LogFile, Record, BufSize);
+ if (Status == STATUS_LOG_FILE_FULL)
{
- DPRINT1("WriteLogBuffer failed (Status 0x%08lx)\n", Status);
- goto Quit;
+ /* The event log file is full, queue a message box for the user and exit */
+ // TODO!
+ DPRINT1("Log file `%S' is full!\n", LogFile->LogName);
}
- FileOffset = NextOffset;
-
- LogFile->Header.Flags &= ELF_LOGFILE_HEADER_DIRTY;
-
- /* Update the event log header */
- FileOffset.QuadPart = 0LL;
- Status = NtWriteFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &LogFile->Header,
- sizeof(EVENTLOGHEADER),
- &FileOffset,
- NULL);
- // dwWritten = IoStatusBlock.Information;
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile failed (Status 0x%08lx)\n", Status);
- goto Quit;
- }
-
- Status = NtFlushBuffersFile(LogFile->hFile, &IoStatusBlock);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtFlushBuffersFile failed (Status 0x%08lx)\n", Status);
- goto Quit;
- }
-
- Status = STATUS_SUCCESS;
-
-Quit:
- RtlReleaseResource(&LogFile->Lock);
- return Status;
-}
-
-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);
- goto Quit;
- }
- }
-
- Status = LogfInitializeNew(LogFile,
- LogFile->Header.MaxSize,
- LogFile->Header.Retention);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("LogfInitializeNew failed (Status: 0x%08lx)\n", Status);
- }
-
-Quit:
- RtlReleaseResource(&LogFile->Lock);
- return Status;
-}
-
-NTSTATUS
-LogfBackupFile(PLOGFILE LogFile,
- PUNICODE_STRING BackupFileName)
-{
- NTSTATUS Status;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatusBlock;
- LARGE_INTEGER FileOffset;
- HANDLE FileHandle = NULL;
- EVENTLOGHEADER Header;
- EVENTLOGRECORD RecBuf;
- EVENTLOGEOF EofRec;
- ULONG i;
- ULONG RecOffset;
- PVOID Buffer = NULL;
-
- // DWORD dwRead;
-
- DPRINT1("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("Cannot create backup file %wZ (Status: 0x%08lx)\n", BackupFileName, Status);
- goto Done;
- }
-
- /* Initialize the (dirty) log file header */
- Header.HeaderSize = sizeof(Header);
- Header.Signature = LOGFILE_SIGNATURE;
- Header.MajorVersion = MAJORVER;
- Header.MinorVersion = MINORVER;
- Header.StartOffset = sizeof(Header);
- Header.EndOffset = sizeof(Header);
- Header.CurrentRecordNumber = 1;
- Header.OldestRecordNumber = 0;
- Header.MaxSize = LogFile->Header.MaxSize;
- Header.Flags = ELF_LOGFILE_HEADER_DIRTY;
- Header.Retention = LogFile->Header.Retention;
- Header.EndHeaderSize = sizeof(Header);
-
- /* Write the (dirty) log file header */
- FileOffset.QuadPart = 0LL;
- Status = NtWriteFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &Header,
- sizeof(Header),
- &FileOffset,
- 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++)
- {
- RecOffset = LogfOffsetByNumber(LogFile, i);
- if (RecOffset == 0)
- break;
-
- /* Read the next EVENTLOGRECORD header at once (it cannot be split) */
- FileOffset.QuadPart = RecOffset;
- Status = NtReadFile(LogFile->hFile,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &RecBuf,
- sizeof(RecBuf),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
- goto Done;
- }
- // dwRead = IoStatusBlock.Information;
-
- // if (dwRead != sizeof(RecBuf))
- // break;
-
- Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RecBuf.Length);
- if (Buffer == NULL)
- {
- DPRINT1("RtlAllocateHeap() failed!\n");
- goto Done;
- }
-
- /* Read the full EVENTLOGRECORD (header + data) with wrapping */
- Status = ReadLogBuffer(LogFile,
- &IoStatusBlock,
- Buffer,
- RecBuf.Length,
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
- RtlFreeHeap(GetProcessHeap(), 0, Buffer);
- // Status = STATUS_EVENTLOG_FILE_CORRUPT;
- goto Done;
- }
- // dwRead = IoStatusBlock.Information;
-
- /* Write the event record (no wrap for the backup log) */
- Status = NtWriteFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- Buffer,
- RecBuf.Length,
- NULL,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile() failed! (Status: 0x%08lx)\n", Status);
- RtlFreeHeap(GetProcessHeap(), 0, Buffer);
- goto Done;
- }
-
- /* Update the header information */
- Header.EndOffset += RecBuf.Length;
-
- /* Free the buffer */
- RtlFreeHeap(GetProcessHeap(), 0, Buffer);
- Buffer = NULL;
- }
-
- /* Initialize the EOF record */
- RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
- EofRec.BeginRecord = Header.StartOffset;
- EofRec.EndRecord = Header.EndOffset;
- EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
- EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
-
- /* Write the EOF record (no wrap for the backup log) */
- Status = NtWriteFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &EofRec,
- sizeof(EofRec),
- 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 = ROUND_UP(Header.EndOffset + sizeof(EofRec), sizeof(ULONG));
- Header.Flags = 0;
-
- /* Write the (clean) log file header */
- FileOffset.QuadPart = 0LL;
- Status = NtWriteFile(FileHandle,
- NULL,
- NULL,
- NULL,
- &IoStatusBlock,
- &Header,
- sizeof(Header),
- &FileOffset,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtWriteFile() failed! (Status: 0x%08lx)\n", Status);
- }
-
-Done:
- /* Close the backup file */
- if (FileHandle != NULL)
- NtClose(FileHandle);
/* Unlock the log file */
RtlReleaseResource(&LogFile->Lock);
dwDataSize,
pRawData);
- Status = LogfWriteRecord(EventLogSource->LogFile, RecSize, LogBuffer);
+ Status = LogfWriteRecord(EventLogSource->LogFile, LogBuffer, RecSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
if (!onLiveCD && SystemLog)
{
- Status = LogfWriteRecord(SystemLog, RecSize, pRec);
+ Status = LogfWriteRecord(SystemLog, pRec, RecSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
- SystemLog->FileName, Status);
+ SystemLog->LogName, Status);
}
}
#include <debug.h>
static LIST_ENTRY LogHandleListHead;
+static CRITICAL_SECTION LogHandleListCs;
/* FUNCTIONS ****************************************************************/
+static NTSTATUS
+ElfDeleteEventLogHandle(PIELF_HANDLE LogHandle);
+
DWORD WINAPI RpcThreadRoutine(LPVOID lpParameter)
{
RPC_STATUS Status;
+ InitializeCriticalSection(&LogHandleListCs);
InitializeListHead(&LogHandleListHead);
Status = RpcServerUseProtseqEpW(L"ncacn_np", 20, L"\\pipe\\EventLog", NULL);
if (Status != RPC_S_OK)
{
DPRINT("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
- return 0;
+ goto Quit;
}
Status = RpcServerRegisterIf(eventlog_v0_0_s_ifspec, NULL, NULL);
if (Status != RPC_S_OK)
{
DPRINT("RpcServerRegisterIf() failed (Status %lx)\n", Status);
- return 0;
+ goto Quit;
}
Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
DPRINT("RpcServerListen() failed (Status %lx)\n", Status);
}
+ EnterCriticalSection(&LogHandleListCs);
+ while (!IsListEmpty(&LogHandleListHead))
+ {
+ IELF_HANDLE LogHandle = (IELF_HANDLE)CONTAINING_RECORD(LogHandleListHead.Flink, LOGHANDLE, LogHandleListEntry);
+ ElfDeleteEventLogHandle(&LogHandle);
+ }
+ LeaveCriticalSection(&LogHandleListCs);
+
+Quit:
+ DeleteCriticalSection(&LogHandleListCs);
+
return 0;
}
if (NT_SUCCESS(Status))
{
/* Append log handle */
+ EnterCriticalSection(&LogHandleListCs);
InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry);
+ LeaveCriticalSection(&LogHandleListCs);
*LogHandle = pLogHandle;
}
else
if (NT_SUCCESS(Status))
{
/* Append log handle */
+ EnterCriticalSection(&LogHandleListCs);
InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry);
+ LeaveCriticalSection(&LogHandleListCs);
*LogHandle = pLogHandle;
}
else
ElfGetLogHandleEntryByHandle(IELF_HANDLE EventLogHandle)
{
PLIST_ENTRY CurrentEntry;
- PLOGHANDLE pLogHandle;
+ PLOGHANDLE Handle, pLogHandle = NULL;
+
+ EnterCriticalSection(&LogHandleListCs);
CurrentEntry = LogHandleListHead.Flink;
while (CurrentEntry != &LogHandleListHead)
{
- pLogHandle = CONTAINING_RECORD(CurrentEntry,
- LOGHANDLE,
- LogHandleListEntry);
+ Handle = CONTAINING_RECORD(CurrentEntry,
+ LOGHANDLE,
+ LogHandleListEntry);
CurrentEntry = CurrentEntry->Flink;
- if (pLogHandle == EventLogHandle)
- return pLogHandle;
+ if (Handle == EventLogHandle)
+ {
+ pLogHandle = Handle;
+ break;
+ }
}
- return NULL;
+ LeaveCriticalSection(&LogHandleListCs);
+
+ return pLogHandle;
}
if (!pLogHandle)
return STATUS_INVALID_HANDLE;
+ EnterCriticalSection(&LogHandleListCs);
RemoveEntryList(&pLogHandle->LogHandleListEntry);
+ LeaveCriticalSection(&LogHandleListCs);
+
LogfClose(pLogHandle->LogFile, FALSE);
HeapFree(GetProcessHeap(), 0, pLogHandle);
{
PLOGHANDLE pLogHandle;
PLOGFILE pLogFile;
+ ULONG OldestRecordNumber, CurrentRecordNumber;
DPRINT("ElfrNumberOfRecords()\n");
pLogFile = pLogHandle->LogFile;
+ /* Lock the log file shared */
+ RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
+
+ OldestRecordNumber = ElfGetOldestRecord(&pLogFile->LogFile);
+ CurrentRecordNumber = ElfGetCurrentRecord(&pLogFile->LogFile);
+
+ /* Unlock the log file */
+ RtlReleaseResource(&pLogFile->Lock);
+
DPRINT("Oldest: %lu Current: %lu\n",
- pLogFile->Header.OldestRecordNumber,
- pLogFile->Header.CurrentRecordNumber);
+ OldestRecordNumber, CurrentRecordNumber);
- if (pLogFile->Header.OldestRecordNumber == 0)
+ if (OldestRecordNumber == 0)
{
/* OldestRecordNumber == 0 when the log is empty */
*NumberOfRecords = 0;
else
{
/* The log contains events */
- *NumberOfRecords = pLogFile->Header.CurrentRecordNumber -
- pLogFile->Header.OldestRecordNumber;
+ *NumberOfRecords = CurrentRecordNumber - OldestRecordNumber;
}
return STATUS_SUCCESS;
PULONG OldestRecordNumber)
{
PLOGHANDLE pLogHandle;
+ PLOGFILE pLogFile;
pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
if (!pLogHandle)
if (!OldestRecordNumber)
return STATUS_INVALID_PARAMETER;
- *OldestRecordNumber = pLogHandle->LogFile->Header.OldestRecordNumber;
+ pLogFile = pLogHandle->LogFile;
+
+ /* Lock the log file shared */
+ RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
+
+ *OldestRecordNumber = ElfGetOldestRecord(&pLogFile->LogFile);
+
+ /* Unlock the log file */
+ RtlReleaseResource(&pLogFile->Lock);
return STATUS_SUCCESS;
}
DataSize,
Data);
- Status = LogfWriteRecord(pLogHandle->LogFile, RecSize, LogBuffer);
+ Status = LogfWriteRecord(pLogHandle->LogFile, LogBuffer, RecSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
{
NTSTATUS Status = STATUS_SUCCESS;
PLOGHANDLE pLogHandle;
+ PLOGFILE pLogFile;
pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
if (!pLogHandle)
return STATUS_INVALID_HANDLE;
+ pLogFile = pLogHandle->LogFile;
+
+ /* Lock the log file shared */
+ RtlAcquireResourceShared(&pLogFile->Lock, TRUE);
+
switch (InfoLevel)
{
case EVENTLOG_FULL_INFO:
break;
}
- /*
- * FIXME. To check whether an event log is "full" one needs
- * to compare its current size with respect to the maximum
- * size threshold "MaxSize" contained in its header.
- */
- efi->dwFull = 0;
+ efi->dwFull = !!(ElfGetFlags(&pLogFile->LogFile) & ELF_LOGFILE_LOGFULL_WRITTEN);
break;
}
break;
}
+ /* Unlock the log file */
+ RtlReleaseResource(&pLogFile->Lock);
+
return Status;
}
ElfrFlushEL(
IELF_HANDLE LogHandle)
{
+ NTSTATUS Status;
PLOGHANDLE pLogHandle;
+ PLOGFILE pLogFile;
pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
if (!pLogHandle)
return STATUS_INVALID_HANDLE;
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ pLogFile = pLogHandle->LogFile;
+
+ /* Lock the log file exclusive */
+ RtlAcquireResourceExclusive(&pLogFile->Lock, TRUE);
+
+ Status = ElfFlushFile(&pLogFile->LogFile);
+
+ /* Unlock the log file */
+ RtlReleaseResource(&pLogFile->Lock);
+
+ return Status;
}
--- /dev/null
+
+## FIXME: Make the library cross-compiling aware (like cmlib or inflib)
+
+add_library(evtlib evtlib.c)
+add_dependencies(evtlib xdk)
--- /dev/null
+/*
+ * PROJECT: ReactOS EventLog File Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: sdk/lib/evtlib/evtlib.c
+ * PURPOSE: Provides a library for reading and writing EventLog files
+ * in the NT <= 5.2 (.evt) format.
+ * PROGRAMMERS: Copyright 2005 Saveliy Tretiakov
+ * Michael Martin
+ * Hermes Belusca-Maito
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "evtlib.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#define EVTLTRACE(...) DPRINT("EvtLib: " __VA_ARGS__)
+// Once things become stabilized enough, replace all the EVTLTRACE1 by EVTLTRACE
+#define EVTLTRACE1(...) DPRINT1("EvtLib: " __VA_ARGS__)
+
+
+/* GLOBALS *******************************************************************/
+
+static const EVENTLOGEOF EOFRecord =
+{
+ sizeof(EOFRecord),
+ 0x11111111, 0x22222222, 0x33333333, 0x44444444,
+ 0, 0, 0, 0,
+ sizeof(EOFRecord)
+};
+
+/* HELPER FUNCTIONS **********************************************************/
+
+static NTSTATUS
+ReadLogBuffer(
+ IN PEVTLOGFILE LogFile,
+ OUT PVOID Buffer,
+ IN SIZE_T Length,
+ OUT PSIZE_T ReadLength OPTIONAL,
+ IN PLARGE_INTEGER ByteOffset,
+ OUT PLARGE_INTEGER NextOffset OPTIONAL)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset;
+ SIZE_T BufSize;
+ SIZE_T ReadBufLength = 0, OldReadBufLength;
+
+ ASSERT(LogFile->CurrentSize <= LogFile->Header.MaxSize);
+ ASSERT(ByteOffset->QuadPart <= LogFile->CurrentSize);
+
+ if (ReadLength)
+ *ReadLength = 0;
+
+ if (NextOffset)
+ NextOffset->QuadPart = 0LL;
+
+ /* Read the first part of the buffer */
+ FileOffset = *ByteOffset;
+ BufSize = min(Length, LogFile->CurrentSize - FileOffset.QuadPart);
+
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ Buffer,
+ BufSize,
+ &ReadBufLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE("FileRead() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ if (Length > BufSize)
+ {
+ OldReadBufLength = ReadBufLength;
+
+ /*
+ * The buffer was splitted in two, its second part
+ * is to be read at the beginning of the log.
+ */
+ Buffer = (PVOID)((ULONG_PTR)Buffer + BufSize);
+ BufSize = Length - BufSize;
+ FileOffset.QuadPart = sizeof(EVENTLOGHEADER);
+
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ Buffer,
+ BufSize,
+ &ReadBufLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE("FileRead() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+ /* Add the read number of bytes from the first read */
+ ReadBufLength += OldReadBufLength;
+ }
+
+ if (ReadLength)
+ *ReadLength = ReadBufLength;
+
+ /* We return the offset just after the end of the read buffer */
+ if (NextOffset)
+ NextOffset->QuadPart = FileOffset.QuadPart + BufSize;
+
+ return Status;
+}
+
+static NTSTATUS
+WriteLogBuffer(
+ IN PEVTLOGFILE LogFile,
+ IN PVOID Buffer,
+ IN SIZE_T Length,
+ OUT PSIZE_T WrittenLength OPTIONAL,
+ IN PLARGE_INTEGER ByteOffset,
+ OUT PLARGE_INTEGER NextOffset OPTIONAL)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset;
+ SIZE_T BufSize;
+ SIZE_T WrittenBufLength = 0, OldWrittenBufLength;
+
+ /* We must have write access to the log file */
+ ASSERT(!LogFile->ReadOnly);
+
+ /*
+ * It is expected that the log file is already correctly expanded
+ * before we can write in it. Therefore the following assertions hold.
+ */
+ ASSERT(LogFile->CurrentSize <= LogFile->Header.MaxSize);
+ ASSERT(ByteOffset->QuadPart <= LogFile->CurrentSize);
+
+ if (WrittenLength)
+ *WrittenLength = 0;
+
+ if (NextOffset)
+ NextOffset->QuadPart = 0LL;
+
+ /* Write the first part of the buffer */
+ FileOffset = *ByteOffset;
+ BufSize = min(Length, LogFile->CurrentSize - FileOffset.QuadPart);
+
+ Status = LogFile->FileWrite(LogFile,
+ &FileOffset,
+ Buffer,
+ BufSize,
+ &WrittenBufLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE("FileWrite() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ if (Length > BufSize)
+ {
+ OldWrittenBufLength = WrittenBufLength;
+
+ /*
+ * The buffer was splitted in two, its second part
+ * is written at the beginning of the log.
+ */
+ Buffer = (PVOID)((ULONG_PTR)Buffer + BufSize);
+ BufSize = Length - BufSize;
+ FileOffset.QuadPart = sizeof(EVENTLOGHEADER);
+
+ Status = LogFile->FileWrite(LogFile,
+ &FileOffset,
+ Buffer,
+ BufSize,
+ &WrittenBufLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE("FileWrite() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+ /* Add the written number of bytes from the first write */
+ WrittenBufLength += OldWrittenBufLength;
+
+ /* The log wraps */
+ LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
+ }
+
+ if (WrittenLength)
+ *WrittenLength = WrittenBufLength;
+
+ /* We return the offset just after the end of the written buffer */
+ if (NextOffset)
+ NextOffset->QuadPart = FileOffset.QuadPart + BufSize;
+
+ return Status;
+}
+
+
+/* Returns 0 if nothing is found */
+static ULONG
+ElfpOffsetByNumber(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG RecordNumber)
+{
+ UINT i;
+
+ for (i = 0; i < LogFile->OffsetInfoNext; i++)
+ {
+ if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
+ return LogFile->OffsetInfo[i].EventOffset;
+ }
+ return 0;
+}
+
+#define OFFSET_INFO_INCREMENT 64
+
+static BOOL
+ElfpAddOffsetInformation(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG ulNumber,
+ IN ULONG ulOffset)
+{
+ PVOID NewOffsetInfo;
+
+ if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
+ {
+ /* Allocate a new offset table */
+ NewOffsetInfo = LogFile->Allocate((LogFile->OffsetInfoSize + OFFSET_INFO_INCREMENT) *
+ sizeof(EVENT_OFFSET_INFO),
+ HEAP_ZERO_MEMORY,
+ TAG_ELF);
+ if (!NewOffsetInfo)
+ {
+ EVTLTRACE1("Cannot reallocate heap.\n");
+ return FALSE;
+ }
+
+ /* Free the old offset table and use the new one */
+ if (LogFile->OffsetInfo)
+ {
+ /* Copy the handles from the old table to the new one */
+ RtlCopyMemory(NewOffsetInfo,
+ LogFile->OffsetInfo,
+ LogFile->OffsetInfoSize * sizeof(EVENT_OFFSET_INFO));
+ LogFile->Free(LogFile->OffsetInfo, 0);
+ }
+ LogFile->OffsetInfo = (PEVENT_OFFSET_INFO)NewOffsetInfo;
+ LogFile->OffsetInfoSize += OFFSET_INFO_INCREMENT;
+ }
+
+ LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
+ LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
+ LogFile->OffsetInfoNext++;
+
+ return TRUE;
+}
+
+static BOOL
+ElfpDeleteOffsetInformation(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG ulNumberMin,
+ IN ULONG ulNumberMax)
+{
+ UINT i;
+
+ if (ulNumberMin > ulNumberMax)
+ return FALSE;
+
+ /* Remove records ulNumberMin to ulNumberMax inclusive */
+ while (ulNumberMin <= ulNumberMax)
+ {
+ /*
+ * As the offset information is listed in increasing order, and we want
+ * to keep the list without holes, we demand that ulNumberMin is the first
+ * element in the list.
+ */
+ if (ulNumberMin != LogFile->OffsetInfo[0].EventNumber)
+ return FALSE;
+
+ /*
+ * RtlMoveMemory(&LogFile->OffsetInfo[0],
+ * &LogFile->OffsetInfo[1],
+ * sizeof(EVENT_OFFSET_INFO) * (LogFile->OffsetInfoNext - 1));
+ */
+ 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--;
+
+ /* Go to the next offset information */
+ ulNumberMin++;
+ }
+
+ return TRUE;
+}
+
+
+static NTSTATUS
+ElfpInitNewFile(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG FileSize,
+ IN ULONG MaxSize,
+ IN ULONG Retention)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset;
+ SIZE_T WrittenLength;
+ EVENTLOGEOF EofRec;
+
+ /* Initialize the event log header */
+ RtlZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
+
+ LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
+ LogFile->Header.Signature = LOGFILE_SIGNATURE;
+ LogFile->Header.MajorVersion = MAJORVER;
+ LogFile->Header.MinorVersion = MINORVER;
+
+ /* Set the offset to the oldest record */
+ LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
+ /* Set the offset to the ELF_EOF_RECORD */
+ LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
+ /* Set the number of the next record that will be added */
+ LogFile->Header.CurrentRecordNumber = 1;
+ /* The event log is empty, there is no record so far */
+ LogFile->Header.OldestRecordNumber = 0;
+
+ // FIXME: Windows' EventLog log file sizes are always multiple of 64kB
+ // but that does not mean the real log size is == file size.
+
+ /* Round MaxSize to be a multiple of ULONG (normally on Windows: multiple of 64 kB) */
+ LogFile->Header.MaxSize = ROUND_UP(MaxSize, sizeof(ULONG));
+ LogFile->CurrentSize = LogFile->Header.MaxSize; // or: FileSize ??
+ LogFile->FileSetSize(LogFile, LogFile->CurrentSize, 0);
+
+ LogFile->Header.Flags = 0;
+ LogFile->Header.Retention = Retention;
+ LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
+
+ /* Write the header */
+ FileOffset.QuadPart = 0LL;
+ Status = LogFile->FileWrite(LogFile,
+ &FileOffset,
+ &LogFile->Header,
+ sizeof(EVENTLOGHEADER),
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ /* Initialize the ELF_EOF_RECORD and write it */
+ RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
+ EofRec.BeginRecord = LogFile->Header.StartOffset;
+ EofRec.EndRecord = LogFile->Header.EndOffset;
+ EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
+ EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
+
+ Status = LogFile->FileWrite(LogFile,
+ NULL,
+ &EofRec,
+ sizeof(EofRec),
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ Status = LogFile->FileFlush(LogFile, NULL, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileFlush() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+ElfpInitExistingFile(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG FileSize,
+ // IN ULONG MaxSize,
+ IN ULONG Retention)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset, NextOffset;
+ SIZE_T ReadLength;
+ ULONG RecordNumber = 0;
+ ULONG RecOffset;
+ PULONG pRecSize2;
+ EVENTLOGEOF EofRec;
+ EVENTLOGRECORD RecBuf;
+ PEVENTLOGRECORD pRecBuf;
+ BOOLEAN Wrapping = FALSE;
+ BOOLEAN IsLogDirty = FALSE;
+
+ /* Read the log header */
+ FileOffset.QuadPart = 0LL;
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ &LogFile->Header,
+ sizeof(EVENTLOGHEADER),
+ &ReadLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
+ return STATUS_EVENTLOG_FILE_CORRUPT; // return Status;
+ }
+ if (ReadLength != sizeof(EVENTLOGHEADER))
+ {
+ EVTLTRACE("Invalid file `%wZ'.\n", &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ /* Header validity checks */
+
+ if (LogFile->Header.HeaderSize != sizeof(EVENTLOGHEADER) ||
+ LogFile->Header.EndHeaderSize != sizeof(EVENTLOGHEADER))
+ {
+ EVTLTRACE("Invalid header size in `%wZ'.\n", &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
+ {
+ EVTLTRACE("Invalid signature %x in `%wZ'.\n",
+ LogFile->Header.Signature, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ IsLogDirty = (LogFile->Header.Flags & ELF_LOGFILE_HEADER_DIRTY);
+
+ /* If the log is read-only (e.g. a backup log) and is dirty, then it is corrupted */
+ if (LogFile->ReadOnly && IsLogDirty)
+ {
+ EVTLTRACE("Read-only log `%wZ' is dirty.\n", &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ LogFile->CurrentSize = FileSize;
+ // FIXME!! What to do? And what to do if the MaxSize from the registry
+ // is strictly less than the CurrentSize?? Should we "reduce" the log size
+ // by clearing it completely??
+ // --> ANSWER: Save the new MaxSize somewhere, and only when the log is
+ // being cleared, use the new MaxSize to resize (ie. shrink) it.
+ // LogFile->FileSetSize(LogFile, LogFile->CurrentSize, 0);
+
+ /* Adjust the log maximum size if needed */
+ if (LogFile->CurrentSize > LogFile->Header.MaxSize)
+ LogFile->Header.MaxSize = LogFile->CurrentSize;
+
+ /*
+ * Reset the log retention value. The value stored
+ * in the log file is just for information purposes.
+ */
+ LogFile->Header.Retention = Retention;
+
+ /*
+ * For a non-read-only dirty log, the most up-to-date information about
+ * the Start/End offsets and the Oldest and Current event record numbers
+ * are found in the EOF record. We need to locate the EOF record without
+ * relying on the log header's EndOffset, then patch the log header with
+ * the values from the EOF record.
+ */
+ if ((LogFile->Header.EndOffset >= sizeof(EVENTLOGHEADER)) &&
+ (LogFile->Header.EndOffset < LogFile->CurrentSize) &&
+ (LogFile->Header.EndOffset & 3) == 0) // EndOffset % sizeof(ULONG) == 0
+ {
+ /* The header EOF offset may be valid, try to start with it */
+ RecOffset = LogFile->Header.EndOffset;
+ }
+ else
+ {
+ /* The header EOF offset could not be valid, so start from the beginning */
+ RecOffset = sizeof(EVENTLOGHEADER);
+ }
+
+ FileOffset.QuadPart = RecOffset;
+ Wrapping = FALSE;
+
+ for (;;)
+ {
+ if (Wrapping && FileOffset.QuadPart >= RecOffset)
+ {
+ EVTLTRACE1("EOF record not found!\n");
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ /* Attempt to read the fixed part of an EVENTLOGEOF (may wrap) */
+ Status = ReadLogBuffer(LogFile,
+ &EofRec,
+ EVENTLOGEOF_SIZE_FIXED,
+ &ReadLength,
+ &FileOffset,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ if (ReadLength != EVENTLOGEOF_SIZE_FIXED)
+ {
+ EVTLTRACE1("Cannot read at most an EOF record!\n");
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ /* Is it an EVENTLOGEOF record? */
+ if (RtlCompareMemory(&EofRec, &EOFRecord, EVENTLOGEOF_SIZE_FIXED) == EVENTLOGEOF_SIZE_FIXED)
+ {
+ DPRINT1("Found EOF record at %llx\n", FileOffset.QuadPart);
+
+ /* Got it! Break the loop and continue */
+ break;
+ }
+
+ /* No, continue looping */
+ if (*(PULONG)((ULONG_PTR)&EofRec + sizeof(ULONG)) == *(PULONG)(&EOFRecord))
+ FileOffset.QuadPart += sizeof(ULONG);
+ else
+ if (*(PULONG)((ULONG_PTR)&EofRec + 2*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
+ FileOffset.QuadPart += 2*sizeof(ULONG);
+ else
+ if (*(PULONG)((ULONG_PTR)&EofRec + 3*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
+ FileOffset.QuadPart += 3*sizeof(ULONG);
+ else
+ if (*(PULONG)((ULONG_PTR)&EofRec + 4*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
+ FileOffset.QuadPart += 4*sizeof(ULONG);
+ else
+ FileOffset.QuadPart += 5*sizeof(ULONG); // EVENTLOGEOF_SIZE_FIXED
+
+ if (FileOffset.QuadPart >= LogFile->CurrentSize /* LogFile->Header.MaxSize */)
+ {
+ /* Wrap the offset */
+ FileOffset.QuadPart -= LogFile->CurrentSize /* LogFile->Header.MaxSize */ - sizeof(EVENTLOGHEADER);
+ Wrapping = TRUE;
+ }
+ }
+ /*
+ * The only way to be there is to have found a valid EOF record.
+ * Otherwise the previous loop has failed and STATUS_EVENTLOG_FILE_CORRUPT
+ * was returned.
+ */
+
+ /* Read the full EVENTLOGEOF (may wrap) and validate it */
+ Status = ReadLogBuffer(LogFile,
+ &EofRec,
+ sizeof(EofRec),
+ &ReadLength,
+ &FileOffset,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ if (ReadLength != sizeof(EofRec))
+ {
+ EVTLTRACE1("Cannot read the full EOF record!\n");
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ /* Complete validity checks */
+ if ((EofRec.RecordSizeEnd != EofRec.RecordSizeBeginning) ||
+ (EofRec.EndRecord != FileOffset.QuadPart))
+ {
+ DPRINT1("EOF record %llx is corrupted (0x%x vs. 0x%x ; 0x%x vs. 0x%llx), expected 0x%x 0x%x!\n",
+ FileOffset.QuadPart,
+ EofRec.RecordSizeEnd, EofRec.RecordSizeBeginning,
+ EofRec.EndRecord, FileOffset.QuadPart,
+ EOFRecord.RecordSizeEnd, EOFRecord.RecordSizeBeginning);
+ DPRINT1("RecordSizeEnd = 0x%x\n", EofRec.RecordSizeEnd);
+ DPRINT1("RecordSizeBeginning = 0x%x\n", EofRec.RecordSizeBeginning);
+ DPRINT1("EndRecord = 0x%x\n", EofRec.EndRecord);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ /* The EOF record is valid, break the loop and continue */
+
+ /* If the log is not dirty, the header values should correspond to the EOF ones */
+ if (!IsLogDirty)
+ {
+ if ( (LogFile->Header.StartOffset != EofRec.BeginRecord) ||
+ (LogFile->Header.EndOffset != EofRec.EndRecord) ||
+ (LogFile->Header.CurrentRecordNumber != EofRec.CurrentRecordNumber) ||
+ (LogFile->Header.OldestRecordNumber != EofRec.OldestRecordNumber) )
+ {
+ DPRINT1("\n"
+ "Log header or EOF record is corrupted:\n"
+ " StartOffset: 0x%x, expected 0x%x; EndOffset: 0x%x, expected 0x%x;\n"
+ " CurrentRecordNumber: %d, expected %d; OldestRecordNumber: %d, expected %d.\n",
+ LogFile->Header.StartOffset, EofRec.BeginRecord,
+ LogFile->Header.EndOffset , EofRec.EndRecord,
+ LogFile->Header.CurrentRecordNumber, EofRec.CurrentRecordNumber,
+ LogFile->Header.OldestRecordNumber , EofRec.OldestRecordNumber);
+
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ }
+
+ /* If the log is dirty, patch the log header with the values from the EOF record */
+ if (!LogFile->ReadOnly && IsLogDirty)
+ {
+ LogFile->Header.StartOffset = EofRec.BeginRecord;
+ LogFile->Header.EndOffset = EofRec.EndRecord;
+ LogFile->Header.CurrentRecordNumber = EofRec.CurrentRecordNumber;
+ LogFile->Header.OldestRecordNumber = EofRec.OldestRecordNumber;
+ }
+
+ /*
+ * FIXME! During operations the EOF record is the one that is the most
+ * updated (its Oldest & Current record numbers are always up-to
+ * date) while the ones from the header may be unsync. When closing
+ * (or flushing?) the event log, the header's record numbers get
+ * updated with the same values as the ones stored in the EOF record.
+ */
+
+ /* Verify Start/End offsets boundaries */
+
+ if ((LogFile->Header.StartOffset >= LogFile->CurrentSize) ||
+ (LogFile->Header.StartOffset & 3) != 0) // StartOffset % sizeof(ULONG) != 0
+ {
+ EVTLTRACE("Invalid start offset 0x%x in `%wZ'.\n",
+ LogFile->Header.StartOffset, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ if ((LogFile->Header.EndOffset >= LogFile->CurrentSize) ||
+ (LogFile->Header.EndOffset & 3) != 0) // EndOffset % sizeof(ULONG) != 0
+ {
+ EVTLTRACE("Invalid EOF offset 0x%x in `%wZ'.\n",
+ LogFile->Header.EndOffset, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ if ((LogFile->Header.StartOffset != LogFile->Header.EndOffset) &&
+ (LogFile->Header.MaxSize - LogFile->Header.StartOffset < sizeof(EVENTLOGRECORD)))
+ {
+ /*
+ * If StartOffset does not point to EndOffset i.e. to an EVENTLOGEOF,
+ * it should point to a non-splitted EVENTLOGRECORD.
+ */
+ EVTLTRACE("Invalid start offset 0x%x in `%wZ'.\n",
+ LogFile->Header.StartOffset, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ if ((LogFile->Header.StartOffset < LogFile->Header.EndOffset) &&
+ (LogFile->Header.EndOffset - LogFile->Header.StartOffset < sizeof(EVENTLOGRECORD)))
+ {
+ /*
+ * In non-wrapping case, there must be enough space between StartOffset
+ * and EndOffset to contain at least a full EVENTLOGRECORD.
+ */
+ EVTLTRACE("Invalid start offset 0x%x or end offset 0x%x in `%wZ'.\n",
+ LogFile->Header.StartOffset, LogFile->Header.EndOffset, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
+ {
+ /*
+ * Non-wrapping case: the (wrapping) free space starting at EndOffset
+ * must be able to contain an EVENTLOGEOF.
+ */
+ if (LogFile->Header.MaxSize - LogFile->Header.EndOffset +
+ LogFile->Header.StartOffset - sizeof(EVENTLOGHEADER) < sizeof(EVENTLOGEOF))
+ {
+ EVTLTRACE("Invalid EOF offset 0x%x in `%wZ'.\n",
+ LogFile->Header.EndOffset, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ }
+ else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
+ {
+ /*
+ * Wrapping case: the free space between EndOffset and StartOffset
+ * must be able to contain an EVENTLOGEOF.
+ */
+ if (LogFile->Header.StartOffset - LogFile->Header.EndOffset < sizeof(EVENTLOGEOF))
+ {
+ EVTLTRACE("Invalid EOF offset 0x%x in `%wZ'.\n",
+ LogFile->Header.EndOffset, &LogFile->FileName);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ }
+
+ /* Start enumerating the event records from the beginning */
+ RecOffset = LogFile->Header.StartOffset;
+ FileOffset.QuadPart = RecOffset;
+ Wrapping = FALSE;
+
+ // // FIXME! FIXME!
+ // if (!(LogFile->Header.Flags & ELF_LOGFILE_HEADER_WRAP))
+ // {
+ // DPRINT1("Log file was wrapping but the flag was not set! Fixing...\n");
+ // LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
+ // }
+
+ DPRINT1("StartOffset = 0x%x, EndOffset = 0x%x\n",
+ LogFile->Header.StartOffset, LogFile->Header.EndOffset);
+
+ /*
+ * For non-read-only logs of size < MaxSize, reorganize the events
+ * such that they do not wrap as soon as we write new ones.
+ */
+#if 0
+ if (!LogFile->ReadOnly)
+ {
+ pRecBuf = LogFile->Allocate(RecBuf.Length, 0, TAG_ELF_BUF);
+ if (pRecBuf == NULL)
+ {
+ DPRINT1("Cannot allocate temporary buffer, skip event reorganization.\n");
+ goto Continue;
+ }
+
+ // TODO: Do the job!
+ }
+
+Continue:
+
+ DPRINT1("StartOffset = 0x%x, EndOffset = 0x%x\n",
+ LogFile->Header.StartOffset, LogFile->Header.EndOffset);
+#endif
+
+ while (FileOffset.QuadPart != LogFile->Header.EndOffset)
+ {
+ if (Wrapping && FileOffset.QuadPart >= RecOffset)
+ {
+ /* We have finished enumerating all the event records */
+ break;
+ }
+
+ /* Read the next EVENTLOGRECORD header at once (it cannot be split) */
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ &RecBuf,
+ sizeof(RecBuf),
+ &ReadLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ if (ReadLength != sizeof(RecBuf))
+ {
+ DPRINT1("Length != sizeof(RecBuf)\n");
+ break;
+ }
+
+ if (RecBuf.Reserved != LOGFILE_SIGNATURE ||
+ RecBuf.Length < sizeof(EVENTLOGRECORD))
+ {
+ DPRINT1("RecBuf problem\n");
+ break;
+ }
+
+ /* Allocate a full EVENTLOGRECORD (header + data) */
+ pRecBuf = LogFile->Allocate(RecBuf.Length, 0, TAG_ELF_BUF);
+ if (pRecBuf == NULL)
+ {
+ EVTLTRACE1("Cannot allocate heap!\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Attempt to read the full EVENTLOGRECORD (can wrap) */
+ Status = ReadLogBuffer(LogFile,
+ pRecBuf,
+ RecBuf.Length,
+ &ReadLength,
+ &FileOffset,
+ &NextOffset);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
+ LogFile->Free(pRecBuf, 0);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+ if (ReadLength != RecBuf.Length)
+ {
+ DPRINT1("Oh oh!!\n");
+ LogFile->Free(pRecBuf, 0);
+ break;
+ }
+
+ // /* If OverWrittenRecords is TRUE and this record has already been read */
+ // if (OverWrittenRecords && (pRecBuf->RecordNumber == LogFile->Header.OldestRecordNumber))
+ // {
+ // LogFile->Free(pRecBuf, 0);
+ // break;
+ // }
+
+ pRecSize2 = (PULONG)((ULONG_PTR)pRecBuf + RecBuf.Length - 4);
+
+ if (*pRecSize2 != RecBuf.Length)
+ {
+ EVTLTRACE1("Invalid RecordSizeEnd of record %d (0x%x) in `%wZ'\n",
+ RecordNumber, *pRecSize2, &LogFile->FileName);
+ LogFile->Free(pRecBuf, 0);
+ break;
+ }
+
+ EVTLTRACE1("Add new record %d @ offset 0x%x\n", pRecBuf->RecordNumber, FileOffset.QuadPart);
+
+ RecordNumber++;
+
+ if (!ElfpAddOffsetInformation(LogFile,
+ pRecBuf->RecordNumber,
+ FileOffset.QuadPart))
+ {
+ EVTLTRACE1("ElfpAddOffsetInformation() failed!\n");
+ LogFile->Free(pRecBuf, 0);
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ LogFile->Free(pRecBuf, 0);
+
+ if (NextOffset.QuadPart == LogFile->Header.EndOffset)
+ {
+ /* We have finished enumerating all the event records */
+ DPRINT1("NextOffset.QuadPart == LogFile->Header.EndOffset, break\n");
+ break;
+ }
+
+ /*
+ * If this was the last event record before the end of the log file,
+ * the next one should start at the beginning of the log and the space
+ * between the last event record and the end of the file is padded.
+ */
+ if (LogFile->Header.MaxSize - NextOffset.QuadPart < sizeof(EVENTLOGRECORD))
+ {
+ /* Wrap to the beginning of the log */
+ DPRINT1("Wrap!\n");
+ NextOffset.QuadPart = sizeof(EVENTLOGHEADER);
+ }
+
+ /*
+ * If the next offset to read is below the current offset,
+ * this means we are wrapping.
+ */
+ if (FileOffset.QuadPart > NextOffset.QuadPart)
+ {
+ DPRINT1("Wrapping = TRUE;\n");
+ Wrapping = TRUE;
+ }
+
+ /* Move the current offset */
+ FileOffset = NextOffset;
+ }
+
+ /* If the event log was empty, it will now contain one record */
+ if (RecordNumber != 0 && LogFile->Header.OldestRecordNumber == 0)
+ LogFile->Header.OldestRecordNumber = 1;
+
+ LogFile->Header.CurrentRecordNumber = RecordNumber + LogFile->Header.OldestRecordNumber;
+ if (LogFile->Header.CurrentRecordNumber == 0)
+ LogFile->Header.CurrentRecordNumber = 1;
+
+ /* Flush the log if it is not read-only */
+ if (!LogFile->ReadOnly)
+ {
+ Status = ElfFlushFile(LogFile);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ElfFlushFile() failed (Status 0x%08lx)\n", Status);
+ return STATUS_EVENTLOG_FILE_CORRUPT; // Status;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+/* FUNCTIONS *****************************************************************/
+
+NTSTATUS
+NTAPI
+ElfCreateFile(
+ IN PEVTLOGFILE LogFile,
+ IN PUNICODE_STRING FileName OPTIONAL,
+ IN ULONG FileSize,
+ IN ULONG MaxSize,
+ IN ULONG Retention,
+ IN BOOLEAN CreateNew,
+ IN BOOLEAN ReadOnly,
+ IN PELF_ALLOCATE_ROUTINE Allocate,
+ IN PELF_FREE_ROUTINE Free,
+ IN PELF_FILE_SET_SIZE_ROUTINE FileSetSize,
+ IN PELF_FILE_WRITE_ROUTINE FileWrite,
+ IN PELF_FILE_READ_ROUTINE FileRead,
+ IN PELF_FILE_FLUSH_ROUTINE FileFlush) // What about Seek ??
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ASSERT(LogFile);
+
+ /* Creating a new log file with the 'ReadOnly' flag set is incompatible */
+ if (CreateNew && ReadOnly)
+ return STATUS_INVALID_PARAMETER;
+
+ RtlZeroMemory(LogFile, sizeof(*LogFile));
+
+ LogFile->Allocate = Allocate;
+ LogFile->Free = Free;
+ LogFile->FileSetSize = FileSetSize;
+ LogFile->FileWrite = FileWrite;
+ LogFile->FileRead = FileRead;
+ LogFile->FileFlush = FileFlush;
+
+ /* Copy the log file name if provided (optional) */
+ RtlInitEmptyUnicodeString(&LogFile->FileName, NULL, 0);
+ if (FileName && FileName->Buffer && FileName->Length &&
+ (FileName->Length <= FileName->MaximumLength))
+ {
+ LogFile->FileName.Buffer = LogFile->Allocate(FileName->Length,
+ HEAP_ZERO_MEMORY,
+ TAG_ELF);
+ if (LogFile->FileName.Buffer)
+ {
+ LogFile->FileName.MaximumLength = FileName->Length;
+ RtlCopyUnicodeString(&LogFile->FileName, FileName);
+ }
+ }
+
+ LogFile->OffsetInfo = LogFile->Allocate(OFFSET_INFO_INCREMENT * sizeof(EVENT_OFFSET_INFO),
+ HEAP_ZERO_MEMORY,
+ TAG_ELF);
+ if (LogFile->OffsetInfo == NULL)
+ {
+ EVTLTRACE1("Cannot allocate heap\n");
+ Status = STATUS_NO_MEMORY;
+ goto Quit;
+ }
+ LogFile->OffsetInfoSize = OFFSET_INFO_INCREMENT;
+ LogFile->OffsetInfoNext = 0;
+
+ // FIXME: Always use the regitry values for MaxSize,
+ // even for existing logs!
+
+ // FIXME: On Windows, EventLog uses the MaxSize setting
+ // from the registry itself; the MaxSize from the header
+ // is just for information purposes.
+
+ EVTLTRACE("Initializing log file `%wZ'\n", &LogFile->FileName);
+
+ LogFile->ReadOnly = ReadOnly; // !CreateNew && ReadOnly;
+
+ if (CreateNew)
+ Status = ElfpInitNewFile(LogFile, FileSize, MaxSize, Retention);
+ else
+ Status = ElfpInitExistingFile(LogFile, FileSize, /* MaxSize, */ Retention);
+
+Quit:
+ if (!NT_SUCCESS(Status))
+ {
+ if (LogFile->OffsetInfo)
+ LogFile->Free(LogFile->OffsetInfo, 0);
+
+ if (LogFile->FileName.Buffer)
+ LogFile->Free(LogFile->FileName.Buffer, 0);
+ }
+
+ return Status;
+
+}
+
+NTSTATUS
+NTAPI
+ElfReCreateFile(
+ IN PEVTLOGFILE LogFile)
+{
+ ASSERT(LogFile);
+
+ return ElfpInitNewFile(LogFile,
+ LogFile->CurrentSize,
+ LogFile->Header.MaxSize,
+ LogFile->Header.Retention);
+}
+
+NTSTATUS
+NTAPI
+ElfBackupFile(
+ IN PEVTLOGFILE LogFile,
+ IN PEVTLOGFILE BackupLogFile)
+{
+ NTSTATUS Status;
+
+ LARGE_INTEGER FileOffset;
+ SIZE_T ReadLength, WrittenLength;
+ PEVENTLOGHEADER Header;
+ EVENTLOGRECORD RecBuf;
+ EVENTLOGEOF EofRec;
+ ULONG i;
+ ULONG RecOffset;
+ PVOID Buffer = NULL;
+
+ ASSERT(LogFile);
+
+ RtlZeroMemory(BackupLogFile, sizeof(*BackupLogFile));
+
+ BackupLogFile->FileSetSize = LogFile->FileSetSize;
+ BackupLogFile->FileWrite = LogFile->FileWrite;
+ BackupLogFile->FileFlush = LogFile->FileFlush;
+
+ // BackupLogFile->CurrentSize = LogFile->CurrentSize;
+
+ BackupLogFile->ReadOnly = FALSE;
+
+ /* Initialize the (dirty) log file header */
+ Header = &BackupLogFile->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 = 0;
+ Header->MaxSize = LogFile->Header.MaxSize;
+ Header->Flags = ELF_LOGFILE_HEADER_DIRTY;
+ Header->Retention = LogFile->Header.Retention;
+ Header->EndHeaderSize = sizeof(EVENTLOGHEADER);
+
+ /* Write the (dirty) log file header */
+ FileOffset.QuadPart = 0LL;
+ Status = BackupLogFile->FileWrite(BackupLogFile,
+ &FileOffset,
+ Header,
+ sizeof(EVENTLOGHEADER),
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("Failed to write the log file header (Status 0x%08lx)\n", Status);
+ goto Quit;
+ }
+
+ for (i = LogFile->Header.OldestRecordNumber; i < LogFile->Header.CurrentRecordNumber; i++)
+ {
+ RecOffset = ElfpOffsetByNumber(LogFile, i);
+ if (RecOffset == 0)
+ break;
+
+ /* Read the next EVENTLOGRECORD header at once (it cannot be split) */
+ FileOffset.QuadPart = RecOffset;
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ &RecBuf,
+ sizeof(RecBuf),
+ &ReadLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
+ goto Quit;
+ }
+
+ // if (ReadLength != sizeof(RecBuf))
+ // break;
+
+ Buffer = LogFile->Allocate(RecBuf.Length, 0, TAG_ELF_BUF);
+ if (Buffer == NULL)
+ {
+ EVTLTRACE1("Allocate() failed!\n");
+ goto Quit;
+ }
+
+ /* Read the full EVENTLOGRECORD (header + data) with wrapping */
+ Status = ReadLogBuffer(LogFile,
+ Buffer,
+ RecBuf.Length,
+ &ReadLength,
+ &FileOffset,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
+ LogFile->Free(Buffer, 0);
+ // Status = STATUS_EVENTLOG_FILE_CORRUPT;
+ goto Quit;
+ }
+
+ /* Write the event record (no wrap for the backup log) */
+ Status = BackupLogFile->FileWrite(BackupLogFile,
+ NULL,
+ Buffer,
+ RecBuf.Length,
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
+ LogFile->Free(Buffer, 0);
+ goto Quit;
+ }
+
+ /* Update the header information */
+ Header->EndOffset += RecBuf.Length;
+
+ /* Free the buffer */
+ LogFile->Free(Buffer, 0);
+ Buffer = NULL;
+ }
+
+// Quit:
+
+ /* Initialize the ELF_EOF_RECORD and write it (no wrap for the backup log) */
+ RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
+ EofRec.BeginRecord = Header->StartOffset;
+ EofRec.EndRecord = Header->EndOffset;
+ EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
+ EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
+
+ Status = BackupLogFile->FileWrite(BackupLogFile,
+ NULL,
+ &EofRec,
+ sizeof(EofRec),
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
+ goto Quit;
+ }
+
+ /* Update the header information */
+ Header->CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
+ Header->OldestRecordNumber = LogFile->Header.OldestRecordNumber;
+ Header->MaxSize = ROUND_UP(Header->EndOffset + sizeof(EofRec), sizeof(ULONG));
+ Header->Flags = 0; // FIXME?
+
+ /* Flush the log file - Write the (clean) log file header */
+ Status = ElfFlushFile(BackupLogFile);
+
+Quit:
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+ElfFlushFile(
+ IN PEVTLOGFILE LogFile)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset;
+ SIZE_T WrittenLength;
+
+ ASSERT(LogFile);
+
+ if (LogFile->ReadOnly)
+ return STATUS_SUCCESS; // STATUS_ACCESS_DENIED;
+
+ /*
+ * NOTE that both the EOF record *AND* the log file header
+ * are supposed to be already updated!
+ * We just remove the dirty log bit.
+ */
+ LogFile->Header.Flags &= ~ELF_LOGFILE_HEADER_DIRTY;
+
+ /* Update the log file header */
+ FileOffset.QuadPart = 0LL;
+ Status = LogFile->FileWrite(LogFile,
+ &FileOffset,
+ &LogFile->Header,
+ sizeof(EVENTLOGHEADER),
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ /* Flush the log file */
+ Status = LogFile->FileFlush(LogFile, NULL, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileFlush() failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+ElfCloseFile( // ElfFree
+ IN PEVTLOGFILE LogFile)
+{
+ ASSERT(LogFile);
+
+ /* Flush the log file */
+ ElfFlushFile(LogFile);
+
+ /* Free the data */
+ LogFile->Free(LogFile->OffsetInfo, 0);
+
+ if (LogFile->FileName.Buffer)
+ LogFile->Free(LogFile->FileName.Buffer, 0);
+ RtlInitEmptyUnicodeString(&LogFile->FileName, NULL, 0);
+}
+
+NTSTATUS
+NTAPI
+ElfReadRecord(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG RecordNumber,
+ OUT PEVENTLOGRECORD Record,
+ IN SIZE_T BufSize, // Length
+ OUT PSIZE_T BytesRead OPTIONAL,
+ OUT PSIZE_T BytesNeeded OPTIONAL)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset;
+ ULONG RecOffset;
+ SIZE_T RecSize;
+ SIZE_T ReadLength;
+
+ ASSERT(LogFile);
+
+ if (BytesRead)
+ *BytesRead = 0;
+
+ if (BytesNeeded)
+ *BytesNeeded = 0;
+
+ /* Retrieve the offset of the event record */
+ RecOffset = ElfpOffsetByNumber(LogFile, RecordNumber);
+ if (RecOffset == 0)
+ return STATUS_NOT_FOUND;
+
+ /* Retrieve its full size */
+ FileOffset.QuadPart = RecOffset;
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ &RecSize,
+ sizeof(RecSize),
+ &ReadLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
+ // Status = STATUS_EVENTLOG_FILE_CORRUPT;
+ return Status;
+ }
+
+ /* Check whether the buffer is big enough to hold the event record */
+ if (BufSize < RecSize)
+ {
+ if (BytesNeeded)
+ *BytesNeeded = RecSize;
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Read the event record into the buffer */
+ FileOffset.QuadPart = RecOffset;
+ Status = ReadLogBuffer(LogFile,
+ Record,
+ RecSize,
+ &ReadLength,
+ &FileOffset,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
+ // Status = STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ if (BytesRead)
+ *BytesRead = ReadLength;
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+ElfWriteRecord(
+ IN PEVTLOGFILE LogFile,
+ IN PEVENTLOGRECORD Record,
+ IN SIZE_T BufSize)
+{
+ NTSTATUS Status;
+ LARGE_INTEGER FileOffset, NextOffset;
+ SIZE_T ReadLength, WrittenLength;
+ EVENTLOGEOF EofRec;
+ EVENTLOGRECORD RecBuf;
+ ULONG FreeSpace = 0;
+ ULONG UpperBound;
+ ULONG RecOffset, WriteOffset;
+
+ ASSERT(LogFile);
+
+ if (LogFile->ReadOnly)
+ return STATUS_ACCESS_DENIED;
+
+ // ASSERT(sizeof(*Record) == sizeof(RecBuf));
+
+ if (!Record || BufSize < sizeof(*Record))
+ return STATUS_INVALID_PARAMETER;
+
+ Record->RecordNumber = LogFile->Header.CurrentRecordNumber;
+
+ /* Compute the available log free space */
+ if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
+ FreeSpace = LogFile->Header.MaxSize - LogFile->Header.EndOffset + LogFile->Header.StartOffset - sizeof(EVENTLOGHEADER);
+ else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
+ FreeSpace = LogFile->Header.StartOffset - LogFile->Header.EndOffset;
+
+ LogFile->Header.Flags |= ELF_LOGFILE_HEADER_DIRTY;
+
+ /* If the event log was empty, it will now contain one record */
+ if (LogFile->Header.OldestRecordNumber == 0)
+ LogFile->Header.OldestRecordNumber = 1;
+
+ /* By default we append the new record at the old EOF record offset */
+ WriteOffset = LogFile->Header.EndOffset;
+
+ /*
+ * Check whether the log is going to wrap (the events being overwritten).
+ */
+
+ if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
+ UpperBound = LogFile->Header.MaxSize;
+ else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
+ UpperBound = LogFile->Header.StartOffset;
+
+ // if (LogFile->Header.MaxSize - WriteOffset < BufSize + sizeof(EofRec))
+ if (UpperBound - WriteOffset < BufSize + sizeof(EofRec))
+ {
+ EVTLTRACE("The event log file has reached maximum size (0x%x), wrapping...\n"
+ "UpperBound = 0x%x, WriteOffset = 0x%x, BufSize = 0x%x\n",
+ LogFile->Header.MaxSize, UpperBound, WriteOffset, BufSize);
+ /* This will be done later */
+ }
+
+ if ( (LogFile->Header.StartOffset < LogFile->Header.EndOffset) &&
+ (LogFile->Header.MaxSize - WriteOffset < sizeof(RecBuf)) ) // (UpperBound - WriteOffset < sizeof(RecBuf))
+ {
+ // ASSERT(UpperBound == LogFile->Header.MaxSize);
+ // ASSERT(WriteOffset == LogFile->Header.EndOffset);
+
+ /*
+ * We cannot fit the EVENTLOGRECORD header of the buffer before
+ * the end of the file. We need to pad the end of the log with
+ * 0x00000027, normally we will need to pad at most 0x37 bytes
+ * (corresponding to sizeof(EVENTLOGRECORD) - 1).
+ */
+
+ /* Rewind to the beginning of the log, just after the header */
+ WriteOffset = sizeof(EVENTLOGHEADER);
+ /**/UpperBound = LogFile->Header.StartOffset;/**/
+
+ FreeSpace = LogFile->Header.StartOffset - WriteOffset;
+
+ LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
+ }
+ /*
+ * Otherwise, we can fit the header and only part
+ * of the data will overwrite the oldest records.
+ *
+ * It might be possible that all the event record can fit in one piece,
+ * but that the EOF record needs to be split. This is not a problem,
+ * EVENTLOGEOF can be splitted while EVENTLOGRECORD cannot be.
+ */
+
+ if (UpperBound - WriteOffset < BufSize + sizeof(EofRec))
+ {
+ ULONG OrgOldestRecordNumber, OldestRecordNumber;
+
+ // DPRINT("EventLogFile has reached maximum size, wrapping...\n");
+
+ OldestRecordNumber = OrgOldestRecordNumber = LogFile->Header.OldestRecordNumber;
+
+ // FIXME: Assert whether LogFile->Header.StartOffset is the beginning of a record???
+ // NOTE: It should be, by construction (and this should have been checked when
+ // initializing a new, or existing log).
+
+ /*
+ * Determine how many old records need to be overwritten.
+ * Check the size of the record as the record added may be larger.
+ * Need to take into account that we append the EOF record.
+ */
+ while (FreeSpace < BufSize + sizeof(EofRec))
+ {
+ /* Get the oldest record data */
+ RecOffset = ElfpOffsetByNumber(LogFile, OldestRecordNumber);
+ if (RecOffset == 0)
+ {
+ EVTLTRACE1("Record number %d cannot be found, or log file is full and cannot wrap!\n", OldestRecordNumber);
+ LogFile->Header.Flags |= ELF_LOGFILE_LOGFULL_WRITTEN;
+ return STATUS_LOG_FILE_FULL;
+ }
+
+ RtlZeroMemory(&RecBuf, sizeof(RecBuf));
+
+ FileOffset.QuadPart = RecOffset;
+ Status = LogFile->FileRead(LogFile,
+ &FileOffset,
+ &RecBuf,
+ sizeof(RecBuf),
+ &ReadLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
+ // Status = STATUS_EVENTLOG_FILE_CORRUPT;
+ return Status;
+ }
+
+ if (RecBuf.Reserved != LOGFILE_SIGNATURE)
+ {
+ EVTLTRACE1("The event log file is corrupted!\n");
+ return STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ /*
+ * Check whether this event can be overwritten by comparing its
+ * written timestamp with the log's retention value. This value
+ * is the time interval, in seconds, that events records are
+ * protected from being overwritten.
+ *
+ * If the retention value is zero the events are always overwritten.
+ *
+ * If the retention value is non-zero, when the age of an event,
+ * in seconds, reaches or exceeds this value, it can be overwritten.
+ * Also if the events are in the future, we do not overwrite them.
+ */
+ if (LogFile->Header.Retention != 0 &&
+ (Record->TimeWritten < RecBuf.TimeWritten ||
+ (Record->TimeWritten >= RecBuf.TimeWritten &&
+ Record->TimeWritten - RecBuf.TimeWritten < LogFile->Header.Retention)))
+ {
+ EVTLTRACE1("The event log file is full and cannot wrap because of the retention policy.\n");
+ LogFile->Header.Flags |= ELF_LOGFILE_LOGFULL_WRITTEN;
+ return STATUS_LOG_FILE_FULL;
+ }
+
+ /*
+ * Advance the oldest record number, add the event record length
+ * (as long as it is valid...) then take account for the possible
+ * paddind after the record, in case this is the last one at the
+ * end of the file.
+ */
+ OldestRecordNumber++;
+ RecOffset += RecBuf.Length;
+ FreeSpace += RecBuf.Length;
+
+ /*
+ * If this was the last event record before the end of the log file,
+ * the next one should start at the beginning of the log and the space
+ * between the last event record and the end of the file is padded.
+ */
+ if (LogFile->Header.MaxSize - RecOffset < sizeof(EVENTLOGRECORD))
+ {
+ /* Add the padding size */
+ FreeSpace += LogFile->Header.MaxSize - RecOffset;
+ }
+ }
+
+ EVTLTRACE("Record will fit. FreeSpace %d, BufSize %d\n", FreeSpace, BufSize);
+
+ /* The log records are wrapping */
+ LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
+
+
+ // FIXME: May lead to corruption if the other subsequent calls fail...
+
+ /*
+ * We have validated all the region of events to be discarded,
+ * now we can perform their deletion.
+ */
+ ElfpDeleteOffsetInformation(LogFile, OrgOldestRecordNumber, OldestRecordNumber - 1);
+ LogFile->Header.OldestRecordNumber = OldestRecordNumber;
+ LogFile->Header.StartOffset = ElfpOffsetByNumber(LogFile, OldestRecordNumber);
+ if (LogFile->Header.StartOffset == 0)
+ {
+ /*
+ * We have deleted all the existing event records to make place
+ * for the new one. We can put it at the start of the event log.
+ */
+ LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
+ WriteOffset = LogFile->Header.StartOffset;
+ LogFile->Header.EndOffset = WriteOffset;
+ }
+
+ DPRINT1("MaxSize = 0x%x, StartOffset = 0x%x, WriteOffset = 0x%x, EndOffset = 0x%x, BufSize = 0x%x\n"
+ "OldestRecordNumber = %d\n",
+ LogFile->Header.MaxSize, LogFile->Header.StartOffset, WriteOffset, LogFile->Header.EndOffset, BufSize,
+ OldestRecordNumber);
+ }
+
+ /*
+ * Expand the log file if needed.
+ * NOTE: It may be needed to perform this task a bit sooner if we need
+ * such a thing for performing read operations, in the future...
+ * Or if this operation needs to modify 'FreeSpace'...
+ */
+ if (LogFile->CurrentSize < LogFile->Header.MaxSize)
+ {
+ EVTLTRACE1("Expanding the log file from %lu to %lu\n",
+ LogFile->CurrentSize, LogFile->Header.MaxSize);
+
+ LogFile->CurrentSize = LogFile->Header.MaxSize;
+ LogFile->FileSetSize(LogFile, LogFile->CurrentSize, 0);
+ }
+
+ /* Since we can write events in the log, clear the log full flag */
+ LogFile->Header.Flags &= ~ELF_LOGFILE_LOGFULL_WRITTEN;
+
+ /* Pad the end of the log */
+ // if (LogFile->Header.EndOffset + sizeof(RecBuf) > LogFile->Header.MaxSize)
+ if (WriteOffset < LogFile->Header.EndOffset)
+ {
+ /* Pad all the space from LogFile->Header.EndOffset to LogFile->Header.MaxSize */
+ WrittenLength = ROUND_DOWN(LogFile->Header.MaxSize - LogFile->Header.EndOffset, sizeof(ULONG));
+ RtlFillMemoryUlong(&RecBuf, WrittenLength, 0x00000027);
+
+ FileOffset.QuadPart = LogFile->Header.EndOffset;
+ Status = LogFile->FileWrite(LogFile,
+ &FileOffset,
+ &RecBuf,
+ WrittenLength,
+ &WrittenLength);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
+ // return Status;
+ }
+ }
+
+ /* Write the event record buffer with possible wrap at offset sizeof(EVENTLOGHEADER) */
+ FileOffset.QuadPart = WriteOffset;
+ Status = WriteLogBuffer(LogFile,
+ Record,
+ BufSize,
+ &WrittenLength,
+ &FileOffset,
+ &NextOffset);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("WriteLogBuffer failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+ /* FileOffset now contains the offset just after the end of the record buffer */
+ FileOffset = NextOffset;
+
+ if (!ElfpAddOffsetInformation(LogFile,
+ Record->RecordNumber,
+ WriteOffset))
+ {
+ return STATUS_NO_MEMORY; // STATUS_EVENTLOG_FILE_CORRUPT;
+ }
+
+ LogFile->Header.CurrentRecordNumber++;
+ if (LogFile->Header.CurrentRecordNumber == 0)
+ LogFile->Header.CurrentRecordNumber = 1;
+
+ /*
+ * Write the new EOF record offset just after the event record.
+ * The EOF record can wrap (be splitted) if less than sizeof(EVENTLOGEOF)
+ * bytes remains between the end of the record and the end of the log file.
+ */
+ LogFile->Header.EndOffset = FileOffset.QuadPart;
+
+ RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
+ EofRec.BeginRecord = LogFile->Header.StartOffset;
+ EofRec.EndRecord = LogFile->Header.EndOffset;
+ EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
+ EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
+
+ // FileOffset.QuadPart = LogFile->Header.EndOffset;
+ Status = WriteLogBuffer(LogFile,
+ &EofRec,
+ sizeof(EofRec),
+ &WrittenLength,
+ &FileOffset,
+ &NextOffset);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("WriteLogBuffer failed (Status 0x%08lx)\n", Status);
+ return Status;
+ }
+ FileOffset = NextOffset;
+
+ /* Flush the log file */
+ Status = ElfFlushFile(LogFile);
+ if (!NT_SUCCESS(Status))
+ {
+ EVTLTRACE1("ElfFlushFile() failed (Status 0x%08lx)\n", Status);
+ return STATUS_EVENTLOG_FILE_CORRUPT; // Status;
+ }
+
+ return Status;
+}
+
+ULONG
+NTAPI
+ElfGetOldestRecord(
+ IN PEVTLOGFILE LogFile)
+{
+ ASSERT(LogFile);
+ return LogFile->Header.OldestRecordNumber;
+}
+
+ULONG
+NTAPI
+ElfGetCurrentRecord(
+ IN PEVTLOGFILE LogFile)
+{
+ ASSERT(LogFile);
+ return LogFile->Header.CurrentRecordNumber;
+}
+
+ULONG
+NTAPI
+ElfGetFlags(
+ IN PEVTLOGFILE LogFile)
+{
+ ASSERT(LogFile);
+ return LogFile->Header.Flags;
+}
+
+#if DBG
+VOID PRINT_HEADER(PEVENTLOGHEADER Header)
+{
+ ULONG Flags = Header->Flags;
+
+ EVTLTRACE1("PRINT_HEADER(0x%p)\n", Header);
+
+ DbgPrint("HeaderSize = %lu\n" , Header->HeaderSize);
+ DbgPrint("Signature = 0x%x\n", Header->Signature);
+ DbgPrint("MajorVersion = %lu\n" , Header->MajorVersion);
+ DbgPrint("MinorVersion = %lu\n" , Header->MinorVersion);
+ DbgPrint("StartOffset = 0x%x\n", Header->StartOffset);
+ DbgPrint("EndOffset = 0x%x\n", Header->EndOffset);
+ DbgPrint("CurrentRecordNumber = %lu\n", Header->CurrentRecordNumber);
+ DbgPrint("OldestRecordNumber = %lu\n", Header->OldestRecordNumber);
+ DbgPrint("MaxSize = 0x%x\n", Header->MaxSize);
+ DbgPrint("Retention = 0x%x\n", Header->Retention);
+ DbgPrint("EndHeaderSize = %lu\n" , Header->EndHeaderSize);
+ DbgPrint("Flags: ");
+ if (Flags & ELF_LOGFILE_HEADER_DIRTY)
+ {
+ DbgPrint("ELF_LOGFILE_HEADER_DIRTY");
+ Flags &= ~ELF_LOGFILE_HEADER_DIRTY;
+ }
+ if (Flags) DbgPrint(" | ");
+ if (Flags & ELF_LOGFILE_HEADER_WRAP)
+ {
+ DbgPrint("ELF_LOGFILE_HEADER_WRAP");
+ Flags &= ~ELF_LOGFILE_HEADER_WRAP;
+ }
+ if (Flags) DbgPrint(" | ");
+ if (Flags & ELF_LOGFILE_LOGFULL_WRITTEN)
+ {
+ DbgPrint("ELF_LOGFILE_LOGFULL_WRITTEN");
+ Flags &= ~ELF_LOGFILE_LOGFULL_WRITTEN;
+ }
+ if (Flags) DbgPrint(" | ");
+ if (Flags & ELF_LOGFILE_ARCHIVE_SET)
+ {
+ DbgPrint("ELF_LOGFILE_ARCHIVE_SET");
+ Flags &= ~ELF_LOGFILE_ARCHIVE_SET;
+ }
+ if (Flags) DbgPrint(" | 0x%x", Flags);
+ DbgPrint("\n");
+}
+#endif
--- /dev/null
+/*
+ * PROJECT: ReactOS EventLog File Library
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: sdk/lib/evtlib/evtlib.h
+ * PURPOSE: Provides a library for reading and writing EventLog files
+ * in the NT <= 5.2 (.evt) format.
+ * PROGRAMMERS: Copyright 2005 Saveliy Tretiakov
+ * Michael Martin
+ * Hermes Belusca-Maito
+ */
+
+#ifndef __EVTLIB_H__
+#define __EVTLIB_H__
+
+/* PSDK/NDK Headers */
+// #define WIN32_NO_STATUS
+// #include <windef.h>
+// #include <winbase.h>
+// #include <winnt.h>
+
+#define NTOS_MODE_USER
+#include <ndk/rtlfuncs.h>
+
+#ifndef ROUND_DOWN
+#define ROUND_DOWN(n, align) (((ULONG)n) & ~((align) - 1l))
+#endif
+
+#ifndef ROUND_UP
+#define ROUND_UP(n, align) ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
+#endif
+
+/*
+ * Our file format will be compatible with NT's
+ */
+#define MAJORVER 1
+#define MINORVER 1
+#define LOGFILE_SIGNATURE 0x654c664c // "LfLe"
+
+/*
+ * Flags used in the logfile header
+ */
+#define ELF_LOGFILE_HEADER_DIRTY 1
+#define ELF_LOGFILE_HEADER_WRAP 2
+#define ELF_LOGFILE_LOGFULL_WRITTEN 4
+#define ELF_LOGFILE_ARCHIVE_SET 8
+
+/*
+ * On-disk event log structures (log file header, event record and EOF record).
+ * NOTE: Contrary to what MSDN claims, both the EVENTLOGHEADER and EVENTLOGEOF
+ * structures are absent from winnt.h .
+ */
+
+#include <pshpack4.h> // pshpack1
+
+// ELF_LOGFILE_HEADER
+typedef struct _EVENTLOGHEADER
+{
+ ULONG HeaderSize;
+ ULONG Signature;
+ ULONG MajorVersion;
+ ULONG MinorVersion;
+ ULONG StartOffset;
+ ULONG EndOffset;
+ ULONG CurrentRecordNumber;
+ ULONG OldestRecordNumber;
+ ULONG MaxSize;
+ ULONG Flags;
+ ULONG Retention;
+ ULONG EndHeaderSize;
+} EVENTLOGHEADER, *PEVENTLOGHEADER;
+
+
+/* Those flags and structure are defined in winnt.h */
+#ifndef _WINNT_
+
+/* EventType flags */
+#define EVENTLOG_SUCCESS 0
+#define EVENTLOG_ERROR_TYPE 1
+#define EVENTLOG_WARNING_TYPE 2
+#define EVENTLOG_INFORMATION_TYPE 4
+#define EVENTLOG_AUDIT_SUCCESS 8
+#define EVENTLOG_AUDIT_FAILURE 16
+
+typedef struct _EVENTLOGRECORD
+{
+ ULONG Length; /* Length of full record, including the data portion */
+ ULONG Reserved;
+ ULONG RecordNumber;
+ ULONG TimeGenerated;
+ ULONG TimeWritten;
+ ULONG EventID;
+ USHORT EventType;
+ USHORT NumStrings; /* Number of strings in the 'Strings' array */
+ USHORT EventCategory;
+ USHORT ReservedFlags;
+ ULONG ClosingRecordNumber;
+ ULONG StringOffset;
+ ULONG UserSidLength;
+ ULONG UserSidOffset;
+ ULONG DataLength; /* Length of the data portion */
+ ULONG DataOffset; /* Offset from beginning of record */
+/*
+ * Length-varying data:
+ *
+ * WCHAR SourceName[];
+ * WCHAR ComputerName[];
+ * SID UserSid; // Must be aligned on a DWORD boundary
+ * WCHAR Strings[];
+ * BYTE Data[];
+ * CHAR Pad[]; // Padding for DWORD boundary
+ * ULONG Length; // Same as the first 'Length' member at the beginning
+ */
+} EVENTLOGRECORD, *PEVENTLOGRECORD;
+
+#endif // _WINNT_
+
+
+// ELF_EOF_RECORD
+typedef struct _EVENTLOGEOF
+{
+ ULONG RecordSizeBeginning;
+ ULONG Ones;
+ ULONG Twos;
+ ULONG Threes;
+ ULONG Fours;
+ ULONG BeginRecord;
+ ULONG EndRecord;
+ ULONG CurrentRecordNumber;
+ ULONG OldestRecordNumber;
+ ULONG RecordSizeEnd;
+} EVENTLOGEOF, *PEVENTLOGEOF;
+
+#define EVENTLOGEOF_SIZE_FIXED (5 * sizeof(ULONG))
+C_ASSERT(EVENTLOGEOF_SIZE_FIXED == FIELD_OFFSET(EVENTLOGEOF, BeginRecord));
+
+#include <poppack.h>
+
+
+typedef struct _EVENT_OFFSET_INFO
+{
+ ULONG EventNumber;
+ ULONG EventOffset;
+} EVENT_OFFSET_INFO, *PEVENT_OFFSET_INFO;
+
+#define TAG_ELF ' flE'
+#define TAG_ELF_BUF 'BflE'
+
+struct _EVTLOGFILE;
+
+typedef PVOID
+(NTAPI *PELF_ALLOCATE_ROUTINE)(
+ IN SIZE_T Size,
+ IN ULONG Flags,
+ IN ULONG Tag
+);
+
+typedef VOID
+(NTAPI *PELF_FREE_ROUTINE)(
+ IN PVOID Ptr,
+ IN ULONG Flags
+);
+
+typedef NTSTATUS
+(NTAPI *PELF_FILE_READ_ROUTINE)(
+ IN struct _EVTLOGFILE* LogFile,
+ IN PLARGE_INTEGER FileOffset,
+ OUT PVOID Buffer,
+ IN SIZE_T Length,
+ OUT PSIZE_T ReadLength OPTIONAL
+);
+
+typedef NTSTATUS
+(NTAPI *PELF_FILE_WRITE_ROUTINE)(
+ IN struct _EVTLOGFILE* LogFile,
+ IN PLARGE_INTEGER FileOffset,
+ IN PVOID Buffer,
+ IN SIZE_T Length,
+ OUT PSIZE_T WrittenLength OPTIONAL
+);
+
+typedef NTSTATUS
+(NTAPI *PELF_FILE_SET_SIZE_ROUTINE)(
+ IN struct _EVTLOGFILE* LogFile,
+ IN ULONG FileSize,
+ IN ULONG OldFileSize
+);
+
+typedef NTSTATUS
+(NTAPI *PELF_FILE_FLUSH_ROUTINE)(
+ IN struct _EVTLOGFILE* LogFile,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length
+);
+
+typedef struct _EVTLOGFILE
+{
+ PELF_ALLOCATE_ROUTINE Allocate;
+ PELF_FREE_ROUTINE Free;
+ PELF_FILE_SET_SIZE_ROUTINE FileSetSize;
+ PELF_FILE_WRITE_ROUTINE FileWrite;
+ PELF_FILE_READ_ROUTINE FileRead;
+ PELF_FILE_FLUSH_ROUTINE FileFlush;
+
+ EVENTLOGHEADER Header;
+ ULONG CurrentSize; /* Equivalent to the file size, is <= MaxSize and can be extended to MaxSize if needed */
+ UNICODE_STRING FileName;
+ PEVENT_OFFSET_INFO OffsetInfo;
+ ULONG OffsetInfoSize;
+ ULONG OffsetInfoNext;
+ BOOLEAN ReadOnly;
+} EVTLOGFILE, *PEVTLOGFILE;
+
+
+NTSTATUS
+NTAPI
+ElfCreateFile(
+ IN PEVTLOGFILE LogFile,
+ IN PUNICODE_STRING FileName OPTIONAL,
+ IN ULONG FileSize,
+ IN ULONG MaxSize,
+ IN ULONG Retention,
+ IN BOOLEAN CreateNew,
+ IN BOOLEAN ReadOnly,
+ IN PELF_ALLOCATE_ROUTINE Allocate,
+ IN PELF_FREE_ROUTINE Free,
+ IN PELF_FILE_SET_SIZE_ROUTINE FileSetSize,
+ IN PELF_FILE_WRITE_ROUTINE FileWrite,
+ IN PELF_FILE_READ_ROUTINE FileRead,
+ IN PELF_FILE_FLUSH_ROUTINE FileFlush); // What about Seek ??
+
+NTSTATUS
+NTAPI
+ElfReCreateFile(
+ IN PEVTLOGFILE LogFile);
+
+// NTSTATUS
+// ElfClearFile(PEVTLOGFILE LogFile);
+
+NTSTATUS
+NTAPI
+ElfBackupFile(
+ IN PEVTLOGFILE LogFile,
+ IN PEVTLOGFILE BackupLogFile);
+
+NTSTATUS
+NTAPI
+ElfFlushFile(
+ IN PEVTLOGFILE LogFile);
+
+VOID
+NTAPI
+ElfCloseFile( // ElfFree
+ IN PEVTLOGFILE LogFile);
+
+NTSTATUS
+NTAPI
+ElfReadRecord(
+ IN PEVTLOGFILE LogFile,
+ IN ULONG RecordNumber,
+ OUT PEVENTLOGRECORD Record,
+ IN SIZE_T BufSize, // Length
+ OUT PSIZE_T BytesRead OPTIONAL,
+ OUT PSIZE_T BytesNeeded OPTIONAL);
+
+NTSTATUS
+NTAPI
+ElfWriteRecord(
+ IN PEVTLOGFILE LogFile,
+ IN PEVENTLOGRECORD Record,
+ IN SIZE_T BufSize);
+
+ULONG
+NTAPI
+ElfGetOldestRecord(
+ IN PEVTLOGFILE LogFile);
+
+ULONG
+NTAPI
+ElfGetCurrentRecord(
+ IN PEVTLOGFILE LogFile);
+
+ULONG
+NTAPI
+ElfGetFlags(
+ IN PEVTLOGFILE LogFile);
+
+#if DBG
+VOID PRINT_HEADER(PEVENTLOGHEADER Header);
+#endif
+
+#endif /* __EVTLIB_H__ */