/*

Copyright (c) 1990  Microsoft Corporation

Module Name:

    FILE.C

Abstract:

    This file contains the routines that deal with file-related operations.

Author:

    Rajen Shah  (rajens)    07-Aug-1991

Revision History:

    29-Aug-1994     Danl
        We no longer grow log files in place.  So there is no need to
        reserve the MaxConfigSize block of memory.

--*/

//
// INCLUDES
//

#include <eventp.h>
#include <alertmsg.h>  // ALERT_ELF manifests

//
// Macros
//

#define IS_EOF(Ptr, Size) \
    (Ptr)->Length == ELFEOFRECORDSIZE && \
        RtlCompareMemory (Ptr, &EOFRecord, Size) == Size

#ifdef CORRUPTED


BOOLEAN
VerifyLogIntegrity(
    PLOGFILE pLogFile
    )
/*++

Routine Description:

    This routine walks the log file to verify that it isn't corrupt


Arguments:

    A pointer to the LOGFILE structure for the log to validate.

Return Value:

    TRUE if log OK
    FALSE if it is corrupt

Note:


--*/
{

    PEVENTLOGRECORD pEventLogRecord;
    PVOID PhysicalStart;
    PVOID PhysicalEOF;
    PVOID BeginRecord;
    PVOID EndRecord;

    pEventLogRecord =
        (PEVENTLOGRECORD)((PBYTE) pLogFile->BaseAddress + pLogFile->BeginRecord);
    PhysicalStart =
        (PVOID) ((PBYTE) pLogFile->BaseAddress + FILEHEADERBUFSIZE);
    PhysicalEOF =
        (PVOID) ((PBYTE) pLogFile->BaseAddress + pLogFile->ViewSize);
    BeginRecord = (PVOID)((PBYTE) pLogFile->BaseAddress + pLogFile->BeginRecord);
    EndRecord = (PVOID)((PBYTE) pLogFile->BaseAddress + pLogFile->EndRecord);

    while(pEventLogRecord->Length != ELFEOFRECORDSIZE) {

        pEventLogRecord = (PEVENTLOGRECORD) NextRecordPosition (
            EVENTLOG_FORWARDS_READ,
            (PVOID) pEventLogRecord,
            pEventLogRecord->Length,
            BeginRecord,
            EndRecord,
            PhysicalEOF,
            PhysicalStart
            );

        if (!pEventLogRecord || pEventLogRecord->Length == 0) {

            ElfDbgPrintNC(("[ELF] The %ws logfile is corrupt\n",
                pLogFile->LogModuleName->Buffer));
            return(FALSE);
        }
    }

    return(TRUE);

}

#endif // CORRUPTED


NTSTATUS
FlushLogFile (
    PLOGFILE    pLogFile
    )

/*++

Routine Description:

    This routine flushes the file specified. It updates the file header,
    and then flushes the virtual memory which causes the data to get
    written to disk.

Arguments:

    pLogFile points to the log file structure.

Return Value:

    NONE

Note:


--*/
{
    NTSTATUS    Status;
    IO_STATUS_BLOCK IoStatusBlock;
    PVOID       BaseAddress;
    ULONG       RegionSize;
    PELF_LOGFILE_HEADER pLogFileHeader;

    //
    // If the dirty bit is set, update the file header before flushing it.
    //
    if (pLogFile->Flags & ELF_LOGFILE_HEADER_DIRTY) {

        pLogFileHeader = (PELF_LOGFILE_HEADER) pLogFile->BaseAddress;

        pLogFile->Flags &= ~ELF_LOGFILE_HEADER_DIRTY; // Remove dirty bit
        pLogFileHeader->Flags = pLogFile->Flags;

        pLogFileHeader->StartOffset = pLogFile->BeginRecord;
        pLogFileHeader->EndOffset   = pLogFile->EndRecord;
        pLogFileHeader->CurrentRecordNumber = pLogFile->CurrentRecordNumber;
        pLogFileHeader->OldestRecordNumber = pLogFile->OldestRecordNumber;
    }

    //
    // Flush the memory in the section that is mapped to the file.
    //
    BaseAddress = pLogFile->BaseAddress;
    RegionSize = pLogFile->ViewSize;

    Status = NtFlushVirtualMemory(
                    NtCurrentProcess(),
                    &BaseAddress,
                    &RegionSize,
                    &IoStatusBlock
                    );

    return (Status);

}



NTSTATUS
ElfpFlushFiles (
    )

/*++

Routine Description:

    This routine flushes all the log files and forces them on disk.
    It is usually called in preparation for a shutdown or a pause.

Arguments:

    NONE

Return Value:

    NONE

Note:


--*/

{

    PLOGFILE    pLogFile;
    NTSTATUS    Status = STATUS_SUCCESS;

    //
    // Make sure that there's at least one file to flush
    //

    if (IsListEmpty (&LogFilesHead) ) {
        return(STATUS_SUCCESS);
    }

    pLogFile
        = (PLOGFILE)
                CONTAINING_RECORD(LogFilesHead.Flink, LOGFILE, FileList);

    //
    // Go through this loop at least once. This ensures that the termination
    // condition will work correctly.
    //
    do {

        Status = FlushLogFile (pLogFile);

        pLogFile =                      // Get next one
            (PLOGFILE)
                CONTAINING_RECORD(pLogFile->FileList.Flink, LOGFILE, FileList);

    } while (   (pLogFile->FileList.Flink != LogFilesHead.Flink)
             && (NT_SUCCESS(Status)) ) ;

    return (Status);
}




NTSTATUS
ElfpCloseLogFile (
    PLOGFILE    pLogFile,
    DWORD       Flags
    )

/*++

Routine Description:

    This routine undoes whatever is done in ElfOpenLogFile.

Arguments:

    pLogFile points to the log file structure.

Return Value:

    NTSTATUS.

Note:


--*/
{
    NTSTATUS    Status = STATUS_SUCCESS;
    PELF_LOGFILE_HEADER pLogFileHeader;
    PVOID BaseAddress;
    ULONG Size;

    ElfDbgPrint(("[ELF] Closing and unmapping log file:  %ws\n",
        pLogFile->LogFileName->Buffer));

#ifdef CORRUPTED

    //
    // Just for debugging a log corruption problem
    //

    if (!VerifyLogIntegrity(pLogFile)) {
       ElfDbgPrintNC(("[ELF] Integrity check failed in ElfpCloseLogFile\n"));
    }

#endif // CORRUPTED

    //
    // If the dirty bit is set, update the file header before closing it.
    // Check to be sure it's not a backup file that just had the dirty
    // bit set when it was copied.
    //

    if (pLogFile->Flags & ELF_LOGFILE_HEADER_DIRTY &&
        !(Flags & ELF_LOG_CLOSE_BACKUP)) {
        pLogFileHeader = (PELF_LOGFILE_HEADER) pLogFile->BaseAddress;
        pLogFileHeader->StartOffset = pLogFile->BeginRecord;
        pLogFileHeader->EndOffset   = pLogFile->EndRecord;
        pLogFileHeader->CurrentRecordNumber = pLogFile->CurrentRecordNumber;
        pLogFileHeader->OldestRecordNumber = pLogFile->OldestRecordNumber;
        pLogFile->Flags &= ~(ELF_LOGFILE_HEADER_DIRTY |
                                ELF_LOGFILE_ARCHIVE_SET);   // Remove dirty &
                                                            // archive bits
        pLogFileHeader->Flags = pLogFile->Flags;
    }

    //
    // Decrement the reference count, and if it goes to zero, unmap the file
    // and close the handle. Also force the close if fForceClosed is TRUE.
    //

    if ((--pLogFile->RefCount == 0) || Flags & ELF_LOG_CLOSE_FORCE) {

        //
        // Last user has gone.
        // Close all the views and the file and section handles.  Free up
        // any extra memory we had reserved, and unlink any structures
        //

        if (pLogFile->BaseAddress)     // Unmap it if it was allocated
            NtUnmapViewOfSection (
                NtCurrentProcess(),
                pLogFile->BaseAddress
                );

        if (pLogFile->SectionHandle)
            NtClose ( pLogFile->SectionHandle );

        if (pLogFile->FileHandle)
            NtClose ( pLogFile->FileHandle );
    }

    return (Status);

} // ElfpCloseLogFile


NTSTATUS
RevalidateLogHeader (
                PELF_LOGFILE_HEADER pLogFileHeader,
                PLOGFILE pLogFile
                )


/*++

Routine Description:

    This routine is called if we encounter a "dirty" log file. The
    routine walks through the file until it finds a signature for a valid log
    record.  It then walks forward thru the file until it finds the EOF
    record, or an invalid record.  Then it walks backwards from the first
    record it found until it finds the EOF record from the other direction.
    It then rebuilds the header and writes it back to the log.  If it can't
    find any valid records, it rebuilds the header to reflect an empty log
    file.  If it finds a trashed file, it writes 256 bytes of the log out in
    an event to the system log.

Arguments:

    pLogFileHeader points to the header of the log file.
    pLogFile points to the log file structure.

Return Value:

    NTSTATUS.

Note:

    This is an expensive routine since it scans the entire file.

    It assumes that the records are on DWORD boundaries.

--*/
{
    PVOID Start, End;
    PDWORD pSignature;
    PEVENTLOGRECORD pEvent;
    PEVENTLOGRECORD FirstRecord;
    PEVENTLOGRECORD FirstPhysicalRecord;
    PEVENTLOGRECORD pLastGoodRecord;
    NTSTATUS Status;
    IO_STATUS_BLOCK IoStatusBlock;
    LARGE_INTEGER ByteOffset;
    ULONG Size;

    ElfDbgPrint(("[ELF] Log file had dirty bit set, revalidating\n"));

    try {

        //
        // Physical start and end of log file (skipping header)
        //

        Start = (PVOID) ((PBYTE)pLogFile->BaseAddress + FILEHEADERBUFSIZE);
        End = (PVOID) ((PBYTE)pLogFile->BaseAddress +
            pLogFile->ActualMaxFileSize);

        //
        // First see if the log has wrapped.  The EOFRECORDSIZE is for the one
        // case where the EOF record wraps so that it's final length just replaces
        // the next records starting length
        //

        pEvent = (PEVENTLOGRECORD) Start;

        if (pEvent->Reserved != ELF_LOG_FILE_SIGNATURE
          || pEvent->RecordNumber != 1 || pEvent->Length == ELFEOFRECORDSIZE) {

            //
            // Log has already wrapped, go looking for the first valid record
            //

            for (pSignature = (PDWORD) Start; (PVOID)pSignature < End;
                    pSignature++) {

                    if (*pSignature == ELF_LOG_FILE_SIGNATURE) {

                        //
                        // Make sure it's really a record
                        //

                        pEvent = CONTAINING_RECORD(pSignature, EVENTLOGRECORD,
                            Reserved);
                        if (!ValidFilePos(pEvent, Start, End, End,
                            pLogFileHeader)) {
                                //
                                // Nope, not really, keep trying
                                //

                                continue;
                        }

                        //
                        // This is a valid record, Remember this so you can use
                        // it later
                        //

                        FirstPhysicalRecord = pEvent;

                        //
                        // Walk backwards from here (wrapping if necessary) until
                        // you hit the EOF record or an invalid record.
                        //

                        while (pEvent && ValidFilePos(pEvent, Start, End, End, pLogFileHeader)) {

                            //
                            // See if it's the EOF record
                            //

                            if (IS_EOF(pEvent,
                                min (ELFEOFUNIQUEPART,
                                (PBYTE) End - (PBYTE) pEvent))) {

                                    break;
                            }

                            pLastGoodRecord = pEvent;
                            pEvent = NextRecordPosition (
                                EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ,
                                pEvent,
                                pEvent->Length,
                                0,
                                0,
                                End,
                                Start);

                            //
                            // Make sure we're not in an infinite loop
                            //

                            if (pEvent == FirstPhysicalRecord) {
                                return(STATUS_UNSUCCESSFUL);
                            }
                        }

                        //
                        // Found the first record, now go look for the last
                        //

                        FirstRecord = pLastGoodRecord;
                        break;
                    }
            }

            if (pSignature == End) {

                //
                // We couldn't find one valid record in the whole log.  Give
                // up and we'll set it to an empty log file
                //

                return(STATUS_UNSUCCESSFUL);
            }
        }
        else {

            //
            // We haven't wrapped yet
            //

            FirstPhysicalRecord = FirstRecord = Start;
        }


        //
        // Now read forward looking for the last good record
        //

        pEvent = FirstPhysicalRecord;

        while (pEvent && ValidFilePos(pEvent, Start, End, End, pLogFileHeader)) {

            //
            // See if it's the EOF record
            //

            if (IS_EOF(pEvent, min (ELFEOFUNIQUEPART,
                (PBYTE) End - (PBYTE) pEvent))) {

                break;
            }

            pLastGoodRecord = pEvent;
            pEvent = NextRecordPosition (
                EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
                pEvent,
                pEvent->Length,
                0,
                0,
                End,
                Start);

            //
            // Make sure we're not in an infinite loop
            //

            if (pEvent == FirstPhysicalRecord) {
                return(STATUS_UNSUCCESSFUL);
            }
        }

        //
        // Now we know the first record (FirstRecord) and the last record
        // (pLastGoodRecord) so we can create the header an EOF record and
        // write them out (EOF record gets written at pEvent)
        //
        // First the EOF record
        //

        EOFRecord.BeginRecord = (PBYTE) FirstRecord - (PBYTE) pLogFileHeader;
        EOFRecord.EndRecord = (PBYTE) pEvent - (PBYTE) pLogFileHeader;
        EOFRecord.CurrentRecordNumber =
            pLastGoodRecord->RecordNumber + 1;
        EOFRecord.OldestRecordNumber = FirstRecord->RecordNumber;

        ByteOffset = RtlConvertUlongToLargeInteger (
            (PBYTE) pEvent - (PBYTE) pLogFileHeader);
        Status = NtWriteFile(
                    pLogFile->FileHandle,   // Filehandle
                    NULL,                   // Event
                    NULL,                   // APC routine
                    NULL,                   // APC context
                    &IoStatusBlock,         // IO_STATUS_BLOCK
                    &EOFRecord,             // Buffer
                    ELFEOFRECORDSIZE,       // Length
                    &ByteOffset,            // Byteoffset
                    NULL);                  // Key

        if (!NT_SUCCESS(Status)) {

            ElfDbgPrint(("[ELF]: Log file header write failed 0x%lx\n",
                Status));
            return (Status);
        }

        //
        // Now the header
        //

        pLogFileHeader->StartOffset = (PBYTE) FirstRecord- (PBYTE) pLogFileHeader;
        pLogFileHeader->EndOffset = (PBYTE) pEvent- (PBYTE) pLogFileHeader;
        pLogFileHeader->CurrentRecordNumber =
            pLastGoodRecord->RecordNumber + 1;
        pLogFileHeader->OldestRecordNumber = FirstRecord->RecordNumber;
        pLogFileHeader->HeaderSize = pLogFileHeader->EndHeaderSize = FILEHEADERBUFSIZE;
        pLogFileHeader->Signature = ELF_LOG_FILE_SIGNATURE;
        pLogFileHeader->Flags = 0;

        if (pLogFileHeader->StartOffset != FILEHEADERBUFSIZE)
            pLogFileHeader->Flags |= ELF_LOGFILE_HEADER_WRAP;

        pLogFileHeader->MaxSize = pLogFile->ActualMaxFileSize;
        pLogFileHeader->Retention = pLogFile->Retention;
        pLogFileHeader->MajorVersion = ELF_VERSION_MAJOR;
        pLogFileHeader->MinorVersion = ELF_VERSION_MINOR;

        //
        // Now flush this to disk to commit it
        //

        Start = pLogFile->BaseAddress;
        Size = FILEHEADERBUFSIZE;

        Status = NtFlushVirtualMemory(
                        NtCurrentProcess(),
                        &Start,
                        &Size,
                        &IoStatusBlock
                        );

    }
    except (EXCEPTION_EXECUTE_HANDLER) {
        return(STATUS_UNSUCCESSFUL);
    }

    return (Status);

}


NTSTATUS
ElfOpenLogFile (
    PLOGFILE    pLogFile,
    ELF_LOG_TYPE LogType
    )

/*++

Routine Description:

    Open the log file, create it if it does not exist.
    Create a section and map a view into the log file.
    Write out the header to the file, if it is newly created.
    If "dirty", update the "start" and "end" pointers by scanning
    the file. Set AUTOWRAP if the "start" does not start right after
    the file header.

Arguments:

    pLogFile points to the log file structure, with the relevant data
             filled in.

    CreateOptions are the options to be passed to NtCreateFile which
             indicate whether to open an existing file, or to create it
             if it does not exist.

Return Value:

    NTSTATUS.

Note:

    It is up to the caller to set the RefCount in the Logfile structure.

--*/
{
    NTSTATUS    Status = STATUS_SUCCESS;
    OBJECT_ATTRIBUTES ObjectAttributes;
    IO_STATUS_BLOCK IoStatusBlock;
    LARGE_INTEGER MaximumSizeOfSection;
    LARGE_INTEGER ByteOffset;
    PELF_LOGFILE_HEADER pLogFileHeader;
    FILE_STANDARD_INFORMATION FileStandardInfo;
    ULONG IoStatusInformation;
    ULONG FileDesiredAccess;
    ULONG SectionDesiredAccess;
    ULONG SectionPageProtection;
    ULONG CreateOptions;
    ULONG CreateDisposition;

    //
    // File header in a new file has the "Start" and "End" pointers the
    // same since there are no records in the file.
    //

    static ELF_LOGFILE_HEADER FileHeaderBuf = {FILEHEADERBUFSIZE, // Size
                                         ELF_LOG_FILE_SIGNATURE,
                                         ELF_VERSION_MAJOR,
                                         ELF_VERSION_MINOR,
                                         FILEHEADERBUFSIZE, // Start offset
                                         FILEHEADERBUFSIZE, // End offset
                                         1,                 // Next record #
                                         0,                 // Oldest record #
                                         0,                 // Maxsize
                                         0,                 // Flags
                                         0,                 // Retention
                                         FILEHEADERBUFSIZE  // Size
                                         };

    //
    // Set the file open and section create options based on the type of log
    // file this is.
    //

    switch (LogType) {

        case ElfNormalLog:
            CreateDisposition = FILE_OPEN_IF;
            FileDesiredAccess = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
            SectionDesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE |
                    SECTION_QUERY | SECTION_EXTEND_SIZE;
            SectionPageProtection = PAGE_READWRITE;
            CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
            break;

        case ElfSecurityLog:
            CreateDisposition = FILE_OPEN_IF;
            FileDesiredAccess = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
            SectionDesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE |
                    SECTION_QUERY | SECTION_EXTEND_SIZE;
            SectionPageProtection = PAGE_READWRITE;
            CreateOptions = FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT;
            break;

        case ElfBackupLog:
            CreateDisposition = FILE_OPEN;
            FileDesiredAccess = GENERIC_READ | SYNCHRONIZE;
            SectionDesiredAccess = SECTION_MAP_READ | SECTION_QUERY;
            SectionPageProtection = PAGE_READONLY;
            CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
            break;

    }

    ElfDbgPrint (("[ELF] Opening and mapping %ws\n",
        pLogFile->LogFileName->Buffer));

    if (pLogFile->FileHandle != NULL) {

        //
        // The log file is already in use. Do not reopen or remap it.
        //

        ElfDbgPrint(("[ELF] Log file already in use by another module\n"));

    } else {

        //
        // Initialize the logfile structure so that it is easier to clean
        // up.
        //

        pLogFile->ActualMaxFileSize = ELF_DEFAULT_LOG_SIZE;
        pLogFile->Flags = 0;
        pLogFile->BaseAddress = NULL;
        pLogFile->SectionHandle = NULL;


        //
        // Set up the object attributes structure for the Log File
        //

        InitializeObjectAttributes(
                        &ObjectAttributes,
                        pLogFile->LogFileName,
                        OBJ_CASE_INSENSITIVE,
                        NULL,
                        NULL
                        );

        //
        // Open the Log File. Create it if it does not exist and it's not
        // being opened as a backup file.  If creating, create a file of
        // the maximum size configured.
        //

        MaximumSizeOfSection =
                RtlConvertUlongToLargeInteger (ELF_DEFAULT_LOG_SIZE);

        Status = NtCreateFile(
                    &pLogFile->FileHandle,
                    FileDesiredAccess,
                    &ObjectAttributes,
                    &IoStatusBlock,
                    &MaximumSizeOfSection,
                    FILE_ATTRIBUTE_NORMAL,
                    FILE_SHARE_READ,
                    CreateDisposition,
                    CreateOptions,
                    NULL,
                    0);

        if (!NT_SUCCESS(Status)) {
            ElfDbgPrint(("[ELF] Log File Open Failed 0x%lx\n", Status));
            goto cleanup;
        }

        //
        // If the file already existed, get its size and use that as the
        // actual size of the file.
        //

        IoStatusInformation = IoStatusBlock.Information;            // Save it away

        if (!( IoStatusInformation & FILE_CREATED )) {
            ElfDbgPrint (("[Elf] Log file exists.\n"));

            Status = NtQueryInformationFile (
                        pLogFile->FileHandle,
                        &IoStatusBlock,
                        &FileStandardInfo,
                        sizeof (FileStandardInfo),
                        FileStandardInformation
                        );

            if (!NT_SUCCESS(Status)) {
                ElfDbgPrint(("[ELF] QueryInformation failed 0x%lx\n", Status));
                goto cleanup;
            } else {


                ElfDbgPrint(("[ELF] Use existing log file size: 0x%lx:%lx\n",
                     FileStandardInfo.EndOfFile.HighPart,
                     FileStandardInfo.EndOfFile.LowPart
                    ));

                MaximumSizeOfSection.LowPart =
                            FileStandardInfo.EndOfFile.LowPart;
                MaximumSizeOfSection.HighPart =
                            FileStandardInfo.EndOfFile.HighPart;

                //
                // Make sure that the high DWORD of the file size is ZERO.
                //

                ASSERT (MaximumSizeOfSection.HighPart == 0);

                //
                // If the filesize if 0, set it to the minimum size
                //

                if (MaximumSizeOfSection.LowPart == 0) {
                    MaximumSizeOfSection.LowPart = ELF_DEFAULT_LOG_SIZE;
                }

                //
                // Set actual size of file
                //

                pLogFile->ActualMaxFileSize =
                        MaximumSizeOfSection.LowPart;

                //
                // If the size of the log file is reduced, a clear must
                // happen for this to take effect
                //

                if (pLogFile->ActualMaxFileSize > pLogFile->ConfigMaxFileSize) {
                    pLogFile->ConfigMaxFileSize = pLogFile->ActualMaxFileSize;
                }

            }
        }

        //
        // Create a section mapped to the Log File just opened
        //

        Status = NtCreateSection(
                    &pLogFile->SectionHandle,
                    SectionDesiredAccess,
                    NULL,
                    &MaximumSizeOfSection,
                    SectionPageProtection,
                    SEC_COMMIT,
                    pLogFile->FileHandle
                    );


        if (!NT_SUCCESS(Status)) {

            ElfDbgPrintNC(("[ELF] Log Mem Section Create Failed 0x%lx\n",
                Status));
            goto cleanup;
        }

        //
        // Map a view of the Section into the eventlog address space
        //

        pLogFile->ViewSize = 0;                 // Initialize value to zero

        Status = NtMapViewOfSection(
                        pLogFile->SectionHandle,
                        NtCurrentProcess(),
                        &pLogFile->BaseAddress,
                        0,
                        0,
                        NULL,
                        &pLogFile->ViewSize,
                        ViewUnmap,
                        0,
                        SectionPageProtection);

        if (!NT_SUCCESS(Status)) {

            ElfDbgPrintNC(("[ELF] Log Mem Sect Map View failed 0x%lx\n",
                Status));
            goto cleanup;
        }

        //
        // If the file was just created, write out the file header.
        //

        if ( IoStatusInformation & FILE_CREATED ) {
            ElfDbgPrint(("[ELF] File was created\n"));
JustCreated:
            FileHeaderBuf.MaxSize = pLogFile->ActualMaxFileSize;
            FileHeaderBuf.Flags   = 0;
            FileHeaderBuf.Retention     = pLogFile->Retention;

            //
            // Copy the header into the file
            //

            ByteOffset = RtlConvertUlongToLargeInteger ( 0 );
            Status = NtWriteFile(
                        pLogFile->FileHandle,   // Filehandle
                        NULL,                   // Event
                        NULL,                   // APC routine
                        NULL,                   // APC context
                        &IoStatusBlock,         // IO_STATUS_BLOCK
                        &FileHeaderBuf,         // Buffer
                        FILEHEADERBUFSIZE,      // Length
                        &ByteOffset,            // Byteoffset
                        NULL);                  // Key


            if (!NT_SUCCESS(Status)) {

                ElfDbgPrint(("[ELF]: Log file header write failed 0x%lx\n",
                    Status));
                goto cleanup;
            }

            //
            // Copy the "EOF" record right after the header
            //

            ByteOffset = RtlConvertUlongToLargeInteger ( FILEHEADERBUFSIZE );
            Status = NtWriteFile(
                        pLogFile->FileHandle,   // Filehandle
                        NULL,                   // Event
                        NULL,                   // APC routine
                        NULL,                   // APC context
                        &IoStatusBlock,         // IO_STATUS_BLOCK
                        &EOFRecord,             // Buffer
                        ELFEOFRECORDSIZE,       // Length
                        &ByteOffset,            // Byteoffset
                        NULL);                  // Key

            if (!NT_SUCCESS(Status)) {

                ElfDbgPrint(("[ELF]: Log file header write failed 0x%lx\n",
                    Status));
                goto cleanup;
            }
        }

        //
        // Check to ensure that this is a valid log file. We look at the
        // size of the header and the signature to see if they match, as
        // well as checking the version number.
        //

        pLogFileHeader = (PELF_LOGFILE_HEADER)(pLogFile->BaseAddress);

        if (  (pLogFileHeader->HeaderSize != FILEHEADERBUFSIZE)
            ||(pLogFileHeader->EndHeaderSize != FILEHEADERBUFSIZE)
            ||(pLogFileHeader->Signature  != ELF_LOG_FILE_SIGNATURE)
            ||(pLogFileHeader->MajorVersion != ELF_VERSION_MAJOR)
            ||(pLogFileHeader->MinorVersion != ELF_VERSION_MINOR)) {

                //
                // This file is corrupt, reset it to an empty log, unless
                // it's being opened as a backup file, if it is, fail the
                // open
                //

                ElfDbgPrint(("[ELF] Invalid file header found\n"));

                if (LogType == ElfBackupLog) {

                   Status = STATUS_EVENTLOG_FILE_CORRUPT;
                   goto cleanup;
                }
                else {
                    ElfpCreateQueuedAlert(ALERT_ELF_LogFileCorrupt, 1,
                        &pLogFile->LogModuleName->Buffer);
                    //
                    // Treat it like it was just created
                    //

                    goto JustCreated;
                }
        }
        else {

            //
            // If the "dirty" bit is set in the file header, then we need to
            // revalidate the BeginRecord and EndRecord fields since we did not
            // get a chance to write them out before the system was rebooted.
            // If the dirty bit is set and it's a backup file, just fail the
            // open.
            //

            if (pLogFileHeader->Flags & ELF_LOGFILE_HEADER_DIRTY) {

                if (LogType == ElfBackupLog) {

                   Status = STATUS_EVENTLOG_FILE_CORRUPT;
                   goto cleanup;
                }
                else {
                   Status = RevalidateLogHeader (pLogFileHeader, pLogFile);
                }
            }

            if (NT_SUCCESS(Status)) {

                //
                // Set the beginning and end record positions in our
                // data structure as well as the wrap flag if appropriate.
                //

                pLogFile->EndRecord = pLogFileHeader->EndOffset;
                pLogFile->BeginRecord = pLogFileHeader->StartOffset;
                if (pLogFileHeader->Flags & ELF_LOGFILE_HEADER_WRAP) {
                    pLogFile->Flags |= ELF_LOGFILE_HEADER_WRAP;
                }

                ElfDbgPrint(("[ELF] BeginRecord: 0x%lx     EndRecord: 0x%lx \n",
                  pLogFile->BeginRecord, pLogFile->EndRecord));
            }
            else {

                //
                // Couldn't validate the file, treat it like it was just
                // created (turn it into an empty file)
                //

                goto JustCreated;
            }

#ifdef CORRUPTED

            //
            // Just for debugging a log corruption problem
            //

            if (!VerifyLogIntegrity(pLogFile)) {
               ElfDbgPrintNC(("[ELF] Integrity check failed in ElfOpenLogFile\n"));
            }
#endif // CORRUPTED

        }

        //
        // Fill in the first and last record number values in the LogFile
        // data structure.
        //

        pLogFile->CurrentRecordNumber = pLogFileHeader->CurrentRecordNumber;
        pLogFile->OldestRecordNumber = pLogFileHeader->OldestRecordNumber;

    }

    return (Status);

cleanup:

    // Clean up anything that got allocated

    if (pLogFile->ViewSize) {
        NtUnmapViewOfSection(NtCurrentProcess(), pLogFile->BaseAddress);
    }

    if (pLogFile->SectionHandle) {
        NtClose(pLogFile->SectionHandle);
    }

    if (pLogFile->FileHandle) {
        NtClose (pLogFile->FileHandle);
    }

    return (Status);

}
