diff options
Diffstat (limited to 'private/eventlog/server/file.c')
-rw-r--r-- | private/eventlog/server/file.c | 1088 |
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); + +} |