www.pudn.com > win2ksrc.rar > file.c, change:2000-07-26,size:35164b


/* 
 
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; 
    SIZE_T      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 = NULL; 
    NTSTATUS Status; 
    IO_STATUS_BLOCK IoStatusBlock; 
    LARGE_INTEGER ByteOffset; 
    SIZE_T 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, TRUE)) 
                    { 
                        // 
                        // 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, TRUE)) 
                    { 
                        // 
                        // See if it's the EOF record 
                        // 
 
                        if (IS_EOF(pEvent, 
                                   min (ELFEOFUNIQUEPART, 
                                   (ULONG_PTR) ((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 || pLastGoodRecord == NULL) 
            { 
                // 
                // Either there were no valid records in the file or 
                // the only valid record was the EOF record (which 
                // means the log is trashed anyhow).  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, TRUE)) { 
 
            // 
            // See if it's the EOF record 
            // 
 
            if (IS_EOF(pEvent, min (ELFEOFUNIQUEPART, 
                (ULONG_PTR) ((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 = (ULONG) ((PBYTE) FirstRecord - (PBYTE) pLogFileHeader); 
        EOFRecord.EndRecord = (ULONG) ((PBYTE) pEvent - (PBYTE) pLogFileHeader); 
        EOFRecord.CurrentRecordNumber = 
            pLastGoodRecord->RecordNumber + 1; 
        EOFRecord.OldestRecordNumber = FirstRecord->RecordNumber; 
 
        ByteOffset = RtlConvertUlongToLargeInteger ( 
            (ULONG) ((PBYTE) pEvent - (PBYTE) pLogFileHeader)); 
 
        // 
        // If the EOF record was wrapped, we can't write out the entire record at 
        // once.  Instead, we'll write out as much as we can and then write the 
        // rest out at the beginning of the log 
        // 
 
        Size = min((PBYTE) End - (PBYTE) pEvent, ELFEOFRECORDSIZE); 
 
        Status = NtWriteFile( 
                    pLogFile->FileHandle,   // Filehandle 
                    NULL,                   // Event 
                    NULL,                   // APC routine 
                    NULL,                   // APC context 
                    &IoStatusBlock,         // IO_STATUS_BLOCK 
                    &EOFRecord,             // Buffer 
                    (ULONG)Size,            // Length 
                    &ByteOffset,            // Byteoffset 
                    NULL);                  // Key 
 
        if (!NT_SUCCESS(Status)) { 
 
            ElfDbgPrint(("[ELF]: Log file header write failed 0x%lx\n", 
                Status)); 
            return (Status); 
        } 
 
        if (Size != ELFEOFRECORDSIZE) { 
 
            PBYTE   pBuff; 
 
            pBuff = (PBYTE)&EOFRecord + Size; 
            Size = ELFEOFRECORDSIZE - Size; 
            ByteOffset = RtlConvertUlongToLargeInteger(FILEHEADERBUFSIZE); 
 
            // 
            // Make absolutely sure we have enough room to write the remainder of 
            // the EOF record.  Note that this should always be the case since the 
            // record was wrapped around to begin with.  To do this, make sure 
            // that the number of bytes we're writing after the header is <= the 
            // offset of the first record from the end of the header 
            // 
 
            ASSERT(Size <= (ULONG)((PBYTE) FirstRecord 
                            - (PBYTE) pLogFileHeader 
                            - FILEHEADERBUFSIZE)); 
 
            Status = NtWriteFile( 
                        pLogFile->FileHandle,   // Filehandle 
                        NULL,                   // Event 
                        NULL,                   // APC routine 
                        NULL,                   // APC context 
                        &IoStatusBlock,         // IO_STATUS_BLOCK 
                        pBuff,                  // Buffer 
                        (ULONG)Size,            // Length 
                        &ByteOffset,            // Byteoffset 
                        NULL);                  // Key 
 
            if (!NT_SUCCESS(Status)) { 
 
                ElfDbgPrint(("[ELF]: Write of remainder of log file header failed 0x%lx\n", 
                             Status)); 
 
                return (Status); 
            } 
        } 
 
        // 
        // Now the header 
        // 
 
        pLogFileHeader->StartOffset = (ULONG) ((PBYTE) FirstRecord- (PBYTE) pLogFileHeader); 
        pLogFileHeader->EndOffset = (ULONG) ((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; 
    SIZE_T ViewSize; 
 
    // 
    // 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 = (ULONG)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 
        // 
 
        ViewSize = 0; 
 
        Status = NtMapViewOfSection( 
                        pLogFile->SectionHandle, 
                        NtCurrentProcess(), 
                        &pLogFile->BaseAddress, 
                        0, 
                        0, 
                        NULL, 
                        &ViewSize, 
                        ViewUnmap, 
                        0, 
                        SectionPageProtection); 
 
        pLogFile->ViewSize = (ULONG)ViewSize; 
        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. 
        // 
        //SS:save the record number of the first record in this session 
        //so that if the cluster service starts after the eventlog service 
        //it will be able to forward the pending records for replication 
        //when the cluster service registers 
        pLogFile->SessionStartRecordNumber = pLogFileHeader->CurrentRecordNumber; 
        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); 
 
}