summaryrefslogtreecommitdiffstats
path: root/private/eventlog/server/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/eventlog/server/file.c')
-rw-r--r--private/eventlog/server/file.c1088
1 files changed, 1088 insertions, 0 deletions
diff --git a/private/eventlog/server/file.c b/private/eventlog/server/file.c
new file mode 100644
index 000000000..63bc7d025
--- /dev/null
+++ b/private/eventlog/server/file.c
@@ -0,0 +1,1088 @@
+/*
+
+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);
+
+}