[EVTLIB]: Create a EvtLib library for manipulating the event log file format from...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 25 Oct 2016 23:50:31 +0000 (23:50 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 25 Oct 2016 23:50:31 +0000 (23:50 +0000)
[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

reactos/base/services/eventlog/CMakeLists.txt
reactos/base/services/eventlog/eventlog.c
reactos/base/services/eventlog/eventlog.h
reactos/base/services/eventlog/file.c
reactos/base/services/eventlog/logport.c
reactos/base/services/eventlog/rpc.c
reactos/sdk/lib/evtlib/CMakeLists.txt [new file with mode: 0644]
reactos/sdk/lib/evtlib/evtlib.c [new file with mode: 0644]
reactos/sdk/lib/evtlib/evtlib.h [new file with mode: 0644]

index 994dbe5..b5c4909 100644 (file)
@@ -1,5 +1,6 @@
 
 include_directories(
+    ${REACTOS_SOURCE_DIR}/sdk/lib/evtlib
     ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl
     ${CMAKE_CURRENT_BINARY_DIR})
 
@@ -15,12 +16,13 @@ list(APPEND SOURCE
     ${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)
index d6b70a1..edb23bb 100644 (file)
@@ -541,49 +541,6 @@ bye_bye:
     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;
index 455d677..fc64b5b 100644 (file)
 #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;
@@ -128,7 +75,6 @@ typedef struct _LOGHANDLE
 /* eventlog.c */
 extern PEVENTSOURCE EventLogSource;
 
-VOID PRINT_HEADER(PEVENTLOGHEADER header);
 VOID PRINT_RECORD(PEVENTLOGRECORD pRec);
 
 
@@ -150,7 +96,28 @@ PLOGFILE LogfListItemByIndex(DWORD Index);
 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,
@@ -164,31 +131,8 @@ 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,
index 3e22ed9..1b88907 100644 (file)
@@ -24,20 +24,6 @@ static CRITICAL_SECTION LogFileListCs;
 
 /* 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);
@@ -164,1087 +150,468 @@ LogfListRemoveItem(PLOGFILE Item)
 }
 
 
-/* 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));
@@ -1323,23 +690,22 @@ ReadAnsiLogEntry(IN  PLOGFILE LogFile,
     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;
 }
@@ -1362,10 +728,9 @@ LogfReadEvents(PLOGFILE LogFile,
                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 */
 
@@ -1390,6 +755,9 @@ LogfReadEvents(PLOGFILE LogFile,
     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
@@ -1399,102 +767,61 @@ LogfReadEvents(PLOGFILE LogFile,
     {
         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 */
         /*
@@ -1504,47 +831,43 @@ LogfReadEvents(PLOGFILE LogFile,
          * "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);
 
     /*
@@ -1554,570 +877,13 @@ LogfWriteRecord(PLOGFILE LogFile,
     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);
@@ -2301,7 +1067,7 @@ LogfReportEvent(USHORT wType,
                                            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",
index 64779bc..0af242a 100644 (file)
@@ -187,11 +187,11 @@ NTSTATUS ProcessPortMessage(VOID)
 
             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);
                 }
             }
 
index f5e7230..40290fc 100644 (file)
 #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);
@@ -45,6 +50,17 @@ DWORD WINAPI RpcThreadRoutine(LPVOID lpParameter)
         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;
 }
 
@@ -143,7 +159,9 @@ Done:
     if (NT_SUCCESS(Status))
     {
         /* Append log handle */
+        EnterCriticalSection(&LogHandleListCs);
         InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry);
+        LeaveCriticalSection(&LogHandleListCs);
         *LogHandle = pLogHandle;
     }
     else
@@ -199,7 +217,9 @@ Done:
     if (NT_SUCCESS(Status))
     {
         /* Append log handle */
+        EnterCriticalSection(&LogHandleListCs);
         InsertTailList(&LogHandleListHead, &pLogHandle->LogHandleListEntry);
+        LeaveCriticalSection(&LogHandleListCs);
         *LogHandle = pLogHandle;
     }
     else
@@ -215,21 +235,28 @@ static PLOGHANDLE
 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;
 }
 
 
@@ -242,7 +269,10 @@ ElfDeleteEventLogHandle(PIELF_HANDLE LogHandle)
     if (!pLogHandle)
         return STATUS_INVALID_HANDLE;
 
+    EnterCriticalSection(&LogHandleListCs);
     RemoveEntryList(&pLogHandle->LogHandleListEntry);
+    LeaveCriticalSection(&LogHandleListCs);
+
     LogfClose(pLogHandle->LogFile, FALSE);
 
     HeapFree(GetProcessHeap(), 0, pLogHandle);
@@ -321,6 +351,7 @@ ElfrNumberOfRecords(
 {
     PLOGHANDLE pLogHandle;
     PLOGFILE pLogFile;
+    ULONG OldestRecordNumber, CurrentRecordNumber;
 
     DPRINT("ElfrNumberOfRecords()\n");
 
@@ -333,11 +364,19 @@ ElfrNumberOfRecords(
 
     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;
@@ -345,8 +384,7 @@ ElfrNumberOfRecords(
     else
     {
         /* The log contains events */
-        *NumberOfRecords = pLogFile->Header.CurrentRecordNumber -
-                           pLogFile->Header.OldestRecordNumber;
+        *NumberOfRecords = CurrentRecordNumber - OldestRecordNumber;
     }
 
     return STATUS_SUCCESS;
@@ -360,6 +398,7 @@ ElfrOldestRecord(
     PULONG OldestRecordNumber)
 {
     PLOGHANDLE pLogHandle;
+    PLOGFILE pLogFile;
 
     pLogHandle = ElfGetLogHandleEntryByHandle(LogHandle);
     if (!pLogHandle)
@@ -368,7 +407,15 @@ ElfrOldestRecord(
     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;
 }
@@ -624,7 +671,7 @@ ElfrIntReportEventW(
                                            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",
@@ -1068,11 +1115,17 @@ ElfrGetLogInformation(
 {
     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:
@@ -1086,12 +1139,7 @@ ElfrGetLogInformation(
                 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;
         }
 
@@ -1100,6 +1148,9 @@ ElfrGetLogInformation(
             break;
     }
 
+    /* Unlock the log file */
+    RtlReleaseResource(&pLogFile->Lock);
+
     return Status;
 }
 
@@ -1109,14 +1160,25 @@ NTSTATUS
 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;
 }
 
 
diff --git a/reactos/sdk/lib/evtlib/CMakeLists.txt b/reactos/sdk/lib/evtlib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0a86343
--- /dev/null
@@ -0,0 +1,5 @@
+
+## FIXME: Make the library cross-compiling aware (like cmlib or inflib)
+
+add_library(evtlib evtlib.c)
+add_dependencies(evtlib xdk)
diff --git a/reactos/sdk/lib/evtlib/evtlib.c b/reactos/sdk/lib/evtlib/evtlib.c
new file mode 100644 (file)
index 0000000..78c8554
--- /dev/null
@@ -0,0 +1,1660 @@
+/*
+ * 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
diff --git a/reactos/sdk/lib/evtlib/evtlib.h b/reactos/sdk/lib/evtlib/evtlib.h
new file mode 100644 (file)
index 0000000..ce13fd0
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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__ */