2 * PROJECT: ReactOS EventLog Service
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/services/eventlog/file.c
5 * PURPOSE: Event log file support wrappers
6 * COPYRIGHT: Copyright 2005 Saveliy Tretiakov
11 /* INCLUDES ******************************************************************/
14 #include <ndk/iofuncs.h>
15 #include <ndk/kefuncs.h>
20 /* LOG FILE LIST - GLOBALS ***************************************************/
22 static LIST_ENTRY LogFileListHead
;
23 static CRITICAL_SECTION LogFileListCs
;
25 /* LOG FILE LIST - FUNCTIONS *************************************************/
27 VOID
LogfListInitialize(VOID
)
29 InitializeCriticalSection(&LogFileListCs
);
30 InitializeListHead(&LogFileListHead
);
33 PLOGFILE
LogfListItemByName(LPCWSTR Name
)
35 PLIST_ENTRY CurrentEntry
;
36 PLOGFILE Item
, Result
= NULL
;
40 EnterCriticalSection(&LogFileListCs
);
42 CurrentEntry
= LogFileListHead
.Flink
;
43 while (CurrentEntry
!= &LogFileListHead
)
45 Item
= CONTAINING_RECORD(CurrentEntry
, LOGFILE
, ListEntry
);
47 if (Item
->LogName
&& !_wcsicmp(Item
->LogName
, Name
))
53 CurrentEntry
= CurrentEntry
->Flink
;
56 LeaveCriticalSection(&LogFileListCs
);
61 /* Index starting from 1 */
62 DWORD
LogfListItemIndexByName(LPCWSTR Name
)
64 PLIST_ENTRY CurrentEntry
;
70 EnterCriticalSection(&LogFileListCs
);
72 CurrentEntry
= LogFileListHead
.Flink
;
73 while (CurrentEntry
!= &LogFileListHead
)
75 PLOGFILE Item
= CONTAINING_RECORD(CurrentEntry
, LOGFILE
, ListEntry
);
77 if (Item
->LogName
&& !_wcsicmp(Item
->LogName
, Name
))
83 CurrentEntry
= CurrentEntry
->Flink
;
87 LeaveCriticalSection(&LogFileListCs
);
92 /* Index starting from 1 */
93 PLOGFILE
LogfListItemByIndex(DWORD Index
)
95 PLIST_ENTRY CurrentEntry
;
96 PLOGFILE Result
= NULL
;
99 EnterCriticalSection(&LogFileListCs
);
101 CurrentEntry
= LogFileListHead
.Flink
;
102 while (CurrentEntry
!= &LogFileListHead
)
106 Result
= CONTAINING_RECORD(CurrentEntry
, LOGFILE
, ListEntry
);
110 CurrentEntry
= CurrentEntry
->Flink
;
114 LeaveCriticalSection(&LogFileListCs
);
118 DWORD
LogfListItemCount(VOID
)
120 PLIST_ENTRY CurrentEntry
;
123 EnterCriticalSection(&LogFileListCs
);
125 CurrentEntry
= LogFileListHead
.Flink
;
126 while (CurrentEntry
!= &LogFileListHead
)
128 CurrentEntry
= CurrentEntry
->Flink
;
132 LeaveCriticalSection(&LogFileListCs
);
137 LogfListAddItem(PLOGFILE Item
)
139 EnterCriticalSection(&LogFileListCs
);
140 InsertTailList(&LogFileListHead
, &Item
->ListEntry
);
141 LeaveCriticalSection(&LogFileListCs
);
145 LogfListRemoveItem(PLOGFILE Item
)
147 EnterCriticalSection(&LogFileListCs
);
148 RemoveEntryList(&Item
->ListEntry
);
149 LeaveCriticalSection(&LogFileListCs
);
153 /* FUNCTIONS *****************************************************************/
155 // PELF_ALLOCATE_ROUTINE
158 LogfpAlloc(IN SIZE_T Size
,
162 UNREFERENCED_PARAMETER(Tag
);
163 return RtlAllocateHeap(GetProcessHeap(), Flags
, Size
);
169 LogfpFree(IN PVOID Ptr
,
173 UNREFERENCED_PARAMETER(Tag
);
174 RtlFreeHeap(GetProcessHeap(), Flags
, Ptr
);
177 // PELF_FILE_READ_ROUTINE
180 LogfpReadFile(IN PEVTLOGFILE LogFile
,
181 IN PLARGE_INTEGER FileOffset
,
184 OUT PSIZE_T ReadLength OPTIONAL
)
187 PLOGFILE pLogFile
= (PLOGFILE
)LogFile
;
188 IO_STATUS_BLOCK IoStatusBlock
;
193 Status
= NtReadFile(pLogFile
->FileHandle
,
204 *ReadLength
= IoStatusBlock
.Information
;
209 // PELF_FILE_WRITE_ROUTINE
212 LogfpWriteFile(IN PEVTLOGFILE LogFile
,
213 IN PLARGE_INTEGER FileOffset
,
216 OUT PSIZE_T WrittenLength OPTIONAL
)
219 PLOGFILE pLogFile
= (PLOGFILE
)LogFile
;
220 IO_STATUS_BLOCK IoStatusBlock
;
225 Status
= NtWriteFile(pLogFile
->FileHandle
,
236 *WrittenLength
= IoStatusBlock
.Information
;
241 // PELF_FILE_SET_SIZE_ROUTINE
244 LogfpSetFileSize(IN PEVTLOGFILE LogFile
,
245 IN ULONG FileSize
, // SIZE_T
246 IN ULONG OldFileSize
) // SIZE_T
249 PLOGFILE pLogFile
= (PLOGFILE
)LogFile
;
250 IO_STATUS_BLOCK IoStatusBlock
;
251 FILE_END_OF_FILE_INFORMATION FileEofInfo
;
252 FILE_ALLOCATION_INFORMATION FileAllocInfo
;
254 UNREFERENCED_PARAMETER(OldFileSize
);
256 // FIXME: Should we round up FileSize ??
258 FileEofInfo
.EndOfFile
.QuadPart
= FileSize
;
259 Status
= NtSetInformationFile(pLogFile
->FileHandle
,
263 FileEndOfFileInformation
);
264 if (!NT_SUCCESS(Status
))
267 FileAllocInfo
.AllocationSize
.QuadPart
= FileSize
;
268 Status
= NtSetInformationFile(pLogFile
->FileHandle
,
271 sizeof(FileAllocInfo
),
272 FileAllocationInformation
);
277 // PELF_FILE_FLUSH_ROUTINE
280 LogfpFlushFile(IN PEVTLOGFILE LogFile
,
281 IN PLARGE_INTEGER FileOffset
,
284 PLOGFILE pLogFile
= (PLOGFILE
)LogFile
;
285 IO_STATUS_BLOCK IoStatusBlock
;
287 UNREFERENCED_PARAMETER(FileOffset
);
288 UNREFERENCED_PARAMETER(Length
);
290 return NtFlushBuffersFile(pLogFile
->FileHandle
, &IoStatusBlock
);
294 LogfCreate(PLOGFILE
* LogFile
,
296 PUNICODE_STRING FileName
,
303 OBJECT_ATTRIBUTES ObjectAttributes
;
304 IO_STATUS_BLOCK IoStatusBlock
;
305 FILE_STANDARD_INFORMATION FileStdInfo
;
310 pLogFile
= LogfpAlloc(sizeof(*pLogFile
), HEAP_ZERO_MEMORY
, TAG_ELF
);
313 DPRINT1("Cannot allocate heap!\n");
314 return STATUS_NO_MEMORY
;
317 LogNameLen
= (LogName
? wcslen(LogName
) : 0) + 1;
318 pLogFile
->LogName
= LogfpAlloc(LogNameLen
* sizeof(WCHAR
), HEAP_ZERO_MEMORY
, 0);
319 if (pLogFile
->LogName
== NULL
)
321 DPRINT1("Cannot allocate heap\n");
322 Status
= STATUS_NO_MEMORY
;
327 StringCchCopyW(pLogFile
->LogName
, LogNameLen
, LogName
);
329 InitializeObjectAttributes(&ObjectAttributes
,
331 OBJ_CASE_INSENSITIVE
,
335 DPRINT("Going to create or open %wZ\n", FileName
);
336 Status
= NtCreateFile(&pLogFile
->FileHandle
,
337 Backup
? (GENERIC_READ
| SYNCHRONIZE
)
338 : (GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
),
342 FILE_ATTRIBUTE_NORMAL
,
344 Backup
? FILE_OPEN
: FILE_OPEN_IF
,
345 FILE_SYNCHRONOUS_IO_NONALERT
,
348 if (!NT_SUCCESS(Status
))
350 DPRINT1("Cannot create file `%wZ' (Status 0x%08lx)\n", FileName
, Status
);
354 CreateNew
= (IoStatusBlock
.Information
== FILE_CREATED
);
355 DPRINT("%wZ %s successfully\n", FileName
, CreateNew
? "created" : "opened");
358 * Retrieve the log file size and check whether the file is not too large;
359 * this log format only supports files of theoretical size < 0xFFFFFFFF .
361 * As it happens that, on Windows (and ReactOS), retrieving the End-Of-File
362 * information using NtQueryInformationFile with the FileEndOfFileInformation
363 * class is invalid (who knows why...), use instead the FileStandardInformation
364 * class, and the EndOfFile member of the returned FILE_STANDARD_INFORMATION
365 * structure will give the desired information.
367 Status
= NtQueryInformationFile(pLogFile
->FileHandle
,
371 FileStandardInformation
);
372 if (!NT_SUCCESS(Status
))
374 DPRINT1("EventLog: NtQueryInformationFile failed (Status 0x%08lx)\n", Status
);
377 if (FileStdInfo
.EndOfFile
.HighPart
!= 0)
379 DPRINT1("EventLog: Log `%wZ' is too large.\n", FileName
);
380 Status
= STATUS_EVENTLOG_FILE_CORRUPT
; // STATUS_FILE_TOO_LARGE;
384 DPRINT("Initializing LogFile `%S'\n", pLogFile
->LogName
);
386 Status
= ElfCreateFile(&pLogFile
->LogFile
,
388 FileStdInfo
.EndOfFile
.LowPart
,
399 if (!NT_SUCCESS(Status
))
402 pLogFile
->Permanent
= Permanent
;
404 RtlInitializeResource(&pLogFile
->Lock
);
406 LogfListAddItem(pLogFile
);
409 if (!NT_SUCCESS(Status
))
411 if (pLogFile
->FileHandle
!= NULL
)
412 NtClose(pLogFile
->FileHandle
);
414 if (pLogFile
->LogName
)
415 LogfpFree(pLogFile
->LogName
, 0, 0);
417 LogfpFree(pLogFile
, 0, TAG_ELF
);
428 LogfClose(PLOGFILE LogFile
,
434 if (!ForceClose
&& LogFile
->Permanent
)
437 RtlAcquireResourceExclusive(&LogFile
->Lock
, TRUE
);
439 LogfListRemoveItem(LogFile
);
441 ElfCloseFile(&LogFile
->LogFile
);
442 NtClose(LogFile
->FileHandle
);
443 LogfpFree(LogFile
->LogName
, 0, 0);
445 RtlDeleteResource(&LogFile
->Lock
);
447 LogfpFree(LogFile
, 0, TAG_ELF
);
452 VOID
LogfCloseAll(VOID
)
454 EnterCriticalSection(&LogFileListCs
);
456 while (!IsListEmpty(&LogFileListHead
))
458 LogfClose(CONTAINING_RECORD(LogFileListHead
.Flink
, LOGFILE
, ListEntry
), TRUE
);
461 LeaveCriticalSection(&LogFileListCs
);
463 DeleteCriticalSection(&LogFileListCs
);
467 LogfClearFile(PLOGFILE LogFile
,
468 PUNICODE_STRING BackupFileName
)
472 /* Lock the log file exclusive */
473 RtlAcquireResourceExclusive(&LogFile
->Lock
, TRUE
);
475 if (BackupFileName
->Length
> 0)
477 /* Write a backup file */
478 Status
= LogfBackupFile(LogFile
, BackupFileName
);
479 if (!NT_SUCCESS(Status
))
481 DPRINT1("LogfBackupFile failed (Status 0x%08lx)\n", Status
);
486 Status
= ElfReCreateFile(&LogFile
->LogFile
);
487 if (!NT_SUCCESS(Status
))
489 DPRINT1("LogfInitializeNew failed (Status 0x%08lx)\n", Status
);
493 /* Unlock the log file */
494 RtlReleaseResource(&LogFile
->Lock
);
499 LogfBackupFile(PLOGFILE LogFile
,
500 PUNICODE_STRING BackupFileName
)
503 LOGFILE BackupLogFile
;
504 OBJECT_ATTRIBUTES ObjectAttributes
;
505 IO_STATUS_BLOCK IoStatusBlock
;
507 DPRINT("LogfBackupFile(%p, %wZ)\n", LogFile
, BackupFileName
);
509 /* Lock the log file shared */
510 RtlAcquireResourceShared(&LogFile
->Lock
, TRUE
);
512 InitializeObjectAttributes(&ObjectAttributes
,
514 OBJ_CASE_INSENSITIVE
,
518 Status
= NtCreateFile(&BackupLogFile
.FileHandle
,
519 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
523 FILE_ATTRIBUTE_NORMAL
,
526 FILE_WRITE_THROUGH
| FILE_SYNCHRONOUS_IO_NONALERT
,
529 if (!NT_SUCCESS(Status
))
531 DPRINT("Cannot create backup file `%wZ' (Status 0x%08lx)\n", BackupFileName
, Status
);
535 Status
= ElfBackupFile(&LogFile
->LogFile
,
536 &BackupLogFile
.LogFile
);
539 /* Close the backup file */
540 if (BackupLogFile
.FileHandle
!= NULL
)
541 NtClose(BackupLogFile
.FileHandle
);
543 /* Unlock the log file */
544 RtlReleaseResource(&LogFile
->Lock
);
551 ReadRecord(IN PEVTLOGFILE LogFile
,
552 IN ULONG RecordNumber
,
553 OUT PEVENTLOGRECORD Record
,
554 IN SIZE_T BufSize
, // Length
555 OUT PSIZE_T BytesRead OPTIONAL
,
556 OUT PSIZE_T BytesNeeded OPTIONAL
,
560 PEVENTLOGRECORD UnicodeBuffer
= NULL
;
561 PEVENTLOGRECORD Src
, Dst
;
563 UNICODE_STRING StringW
;
564 PVOID SrcPtr
, DstPtr
;
567 DWORD dwRecordLength
;
572 return ElfReadRecord(LogFile
,
586 UnicodeBuffer
= LogfpAlloc(BufSize
, HEAP_ZERO_MEMORY
, TAG_ELF_BUF
);
587 if (UnicodeBuffer
== NULL
)
589 DPRINT1("Alloc failed!\n");
590 return STATUS_NO_MEMORY
;
593 Status
= ElfReadRecord(LogFile
,
599 if (!NT_SUCCESS(Status
))
605 Dst
->Reserved
= Src
->Reserved
;
606 Dst
->RecordNumber
= Src
->RecordNumber
;
607 Dst
->TimeGenerated
= Src
->TimeGenerated
;
608 Dst
->TimeWritten
= Src
->TimeWritten
;
609 Dst
->EventID
= Src
->EventID
;
610 Dst
->EventType
= Src
->EventType
;
611 Dst
->EventCategory
= Src
->EventCategory
;
612 Dst
->NumStrings
= Src
->NumStrings
;
613 Dst
->UserSidLength
= Src
->UserSidLength
;
614 Dst
->DataLength
= Src
->DataLength
;
616 SrcPtr
= (PVOID
)((ULONG_PTR
)Src
+ sizeof(EVENTLOGRECORD
));
617 DstPtr
= (PVOID
)((ULONG_PTR
)Dst
+ sizeof(EVENTLOGRECORD
));
619 /* Convert the module name */
620 RtlInitUnicodeString(&StringW
, SrcPtr
);
621 Status
= RtlUnicodeStringToAnsiString(&StringA
, &StringW
, TRUE
);
622 if (NT_SUCCESS(Status
))
624 RtlCopyMemory(DstPtr
, StringA
.Buffer
, StringA
.MaximumLength
);
625 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ StringA
.MaximumLength
);
627 RtlFreeAnsiString(&StringA
);
631 RtlZeroMemory(DstPtr
, StringW
.MaximumLength
/ sizeof(WCHAR
));
632 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ StringW
.MaximumLength
/ sizeof(WCHAR
));
634 SrcPtr
= (PVOID
)((ULONG_PTR
)SrcPtr
+ StringW
.MaximumLength
);
636 /* Convert the computer name */
637 RtlInitUnicodeString(&StringW
, SrcPtr
);
638 Status
= RtlUnicodeStringToAnsiString(&StringA
, &StringW
, TRUE
);
639 if (NT_SUCCESS(Status
))
641 RtlCopyMemory(DstPtr
, StringA
.Buffer
, StringA
.MaximumLength
);
642 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ StringA
.MaximumLength
);
644 RtlFreeAnsiString(&StringA
);
648 RtlZeroMemory(DstPtr
, StringW
.MaximumLength
/ sizeof(WCHAR
));
649 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ StringW
.MaximumLength
/ sizeof(WCHAR
));
652 /* Add the padding and the User SID */
653 dwPadding
= sizeof(ULONG
) - (((ULONG_PTR
)DstPtr
- (ULONG_PTR
)Dst
) % sizeof(ULONG
));
654 RtlZeroMemory(DstPtr
, dwPadding
);
656 SrcPtr
= (PVOID
)((ULONG_PTR
)Src
+ Src
->UserSidOffset
);
657 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ dwPadding
);
659 Dst
->UserSidOffset
= (DWORD
)((ULONG_PTR
)DstPtr
- (ULONG_PTR
)Dst
);
660 RtlCopyMemory(DstPtr
, SrcPtr
, Src
->UserSidLength
);
662 /* Convert the strings */
663 SrcPtr
= (PVOID
)((ULONG_PTR
)Src
+ Src
->StringOffset
);
664 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ Src
->UserSidLength
);
665 Dst
->StringOffset
= (DWORD
)((ULONG_PTR
)DstPtr
- (ULONG_PTR
)Dst
);
667 for (i
= 0; i
< Dst
->NumStrings
; i
++)
669 RtlInitUnicodeString(&StringW
, SrcPtr
);
670 Status
= RtlUnicodeStringToAnsiString(&StringA
, &StringW
, TRUE
);
671 if (NT_SUCCESS(Status
))
673 RtlCopyMemory(DstPtr
, StringA
.Buffer
, StringA
.MaximumLength
);
674 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ StringA
.MaximumLength
);
676 RtlFreeAnsiString(&StringA
);
680 RtlZeroMemory(DstPtr
, StringW
.MaximumLength
/ sizeof(WCHAR
));
681 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ StringW
.MaximumLength
/ sizeof(WCHAR
));
683 SrcPtr
= (PVOID
)((ULONG_PTR
)SrcPtr
+ StringW
.MaximumLength
);
686 /* Copy the binary data */
687 SrcPtr
= (PVOID
)((ULONG_PTR
)Src
+ Src
->DataOffset
);
688 Dst
->DataOffset
= (ULONG_PTR
)DstPtr
- (ULONG_PTR
)Dst
;
689 RtlCopyMemory(DstPtr
, SrcPtr
, Src
->DataLength
);
690 DstPtr
= (PVOID
)((ULONG_PTR
)DstPtr
+ Src
->DataLength
);
692 /* Add the padding */
693 dwPadding
= sizeof(ULONG
) - (((ULONG_PTR
)DstPtr
- (ULONG_PTR
)Dst
) % sizeof(ULONG
));
694 RtlZeroMemory(DstPtr
, dwPadding
);
696 /* Set the record length at the beginning and the end of the record */
697 dwRecordLength
= (DWORD
)((ULONG_PTR
)DstPtr
+ dwPadding
+ sizeof(ULONG
) - (ULONG_PTR
)Dst
);
698 Dst
->Length
= dwRecordLength
;
699 pLength
= (PDWORD
)((ULONG_PTR
)DstPtr
+ dwPadding
);
700 *pLength
= dwRecordLength
;
703 *BytesRead
= dwRecordLength
;
705 Status
= STATUS_SUCCESS
;
708 LogfpFree(UnicodeBuffer
, 0, TAG_ELF_BUF
);
715 * 'RecordNumber' is a pointer to the record number at which the read operation
716 * should start. If the record number is 0 and the flags given in the 'Flags'
717 * parameter contain EVENTLOG_SEQUENTIAL_READ, an adequate record number is
721 LogfReadEvents(PLOGFILE LogFile
,
732 SIZE_T ReadLength
, NeededSize
;
735 /* Parameters validation */
737 /* EVENTLOG_SEQUENTIAL_READ and EVENTLOG_SEEK_READ are mutually exclusive */
738 if ((Flags
& EVENTLOG_SEQUENTIAL_READ
) && (Flags
& EVENTLOG_SEEK_READ
))
739 return STATUS_INVALID_PARAMETER
;
741 if (!(Flags
& EVENTLOG_SEQUENTIAL_READ
) && !(Flags
& EVENTLOG_SEEK_READ
))
742 return STATUS_INVALID_PARAMETER
;
744 /* EVENTLOG_FORWARDS_READ and EVENTLOG_BACKWARDS_READ are mutually exclusive */
745 if ((Flags
& EVENTLOG_FORWARDS_READ
) && (Flags
& EVENTLOG_BACKWARDS_READ
))
746 return STATUS_INVALID_PARAMETER
;
748 if (!(Flags
& EVENTLOG_FORWARDS_READ
) && !(Flags
& EVENTLOG_BACKWARDS_READ
))
749 return STATUS_INVALID_PARAMETER
;
751 if (!Buffer
|| !BytesRead
|| !BytesNeeded
)
752 return STATUS_INVALID_PARAMETER
;
754 /* In seek read mode, a record number of 0 is invalid */
755 if (!(Flags
& EVENTLOG_SEQUENTIAL_READ
) && (*RecordNumber
== 0))
756 return STATUS_INVALID_PARAMETER
;
758 /* Lock the log file shared */
759 RtlAcquireResourceShared(&LogFile
->Lock
, TRUE
);
762 * In sequential read mode, a record number of 0 means we need
763 * to determine where to start the read operation. Otherwise
764 * we just use the provided record number.
766 if ((Flags
& EVENTLOG_SEQUENTIAL_READ
) && (*RecordNumber
== 0))
768 if (Flags
& EVENTLOG_FORWARDS_READ
)
770 *RecordNumber
= ElfGetOldestRecord(&LogFile
->LogFile
);
772 else // if (Flags & EVENTLOG_BACKWARDS_READ)
774 *RecordNumber
= ElfGetCurrentRecord(&LogFile
->LogFile
) - 1;
778 RecNum
= *RecordNumber
;
786 Status
= ReadRecord(&LogFile
->LogFile
,
788 (PEVENTLOGRECORD
)(Buffer
+ BufferUsage
),
789 BufSize
- BufferUsage
,
793 if (Status
== STATUS_NOT_FOUND
)
795 if (BufferUsage
== 0)
797 Status
= STATUS_END_OF_FILE
;
806 if (Status
== STATUS_BUFFER_TOO_SMALL
)
808 if (BufferUsage
== 0)
810 *BytesNeeded
= NeededSize
;
811 // Status = STATUS_BUFFER_TOO_SMALL;
820 if (!NT_SUCCESS(Status
))
822 DPRINT1("ElfReadRecord failed (Status 0x%08lx)\n", Status
);
826 /* Go to the next event record */
828 * NOTE: This implicitly supposes that all the other record numbers
829 * are consecutive (and do not jump than more than one unit); but if
830 * it is not the case, then we would prefer here to call some
831 * "get_next_record_number" function.
833 if (Flags
& EVENTLOG_FORWARDS_READ
)
835 else // if (Flags & EVENTLOG_BACKWARDS_READ)
838 BufferUsage
+= ReadLength
;
840 while (BufferUsage
<= BufSize
);
842 *BytesRead
= BufferUsage
;
843 *RecordNumber
= RecNum
;
845 Status
= STATUS_SUCCESS
;
848 /* Unlock the log file */
849 RtlReleaseResource(&LogFile
->Lock
);
851 if (!NT_SUCCESS(Status
))
852 DPRINT1("LogfReadEvents failed (Status 0x%08lx)\n", Status
);
858 LogfWriteRecord(PLOGFILE LogFile
,
859 PEVENTLOGRECORD Record
,
863 LARGE_INTEGER SystemTime
;
865 // ASSERT(sizeof(*Record) == sizeof(RecBuf));
867 if (!Record
|| BufSize
< sizeof(*Record
))
868 return STATUS_INVALID_PARAMETER
;
870 /* Lock the log file exclusive */
871 RtlAcquireResourceExclusive(&LogFile
->Lock
, TRUE
);
874 * Retrieve the record written time now, that will also be compared
875 * with the existing events timestamps in case the log is wrapping.
877 NtQuerySystemTime(&SystemTime
);
878 RtlTimeToSecondsSince1970(&SystemTime
, &Record
->TimeWritten
);
880 Status
= ElfWriteRecord(&LogFile
->LogFile
, Record
, BufSize
);
881 if (Status
== STATUS_LOG_FILE_FULL
)
883 /* The event log file is full, queue a message box for the user and exit */
885 DPRINT1("Log file `%S' is full!\n", LogFile
->LogName
);
888 /* Unlock the log file */
889 RtlReleaseResource(&LogFile
->Lock
);
896 LogfAllocAndBuildNewRecord(PSIZE_T pRecSize
,
901 PUNICODE_STRING SourceName
,
902 PUNICODE_STRING ComputerName
,
911 SIZE_T SourceNameSize
, ComputerNameSize
, StringLen
;
913 PEVENTLOGRECORD pRec
;
917 SourceNameSize
= (SourceName
&& SourceName
->Buffer
) ? SourceName
->Length
: 0;
918 ComputerNameSize
= (ComputerName
&& ComputerName
->Buffer
) ? ComputerName
->Length
: 0;
920 RecSize
= sizeof(EVENTLOGRECORD
) + /* Add the sizes of the strings, NULL-terminated */
921 SourceNameSize
+ ComputerNameSize
+ 2*sizeof(UNICODE_NULL
);
923 /* Align on DWORD boundary for the SID */
924 RecSize
= ROUND_UP(RecSize
, sizeof(ULONG
));
926 RecSize
+= dwSidLength
;
928 /* Add the sizes for the strings array */
929 ASSERT((pStrings
== NULL
&& wNumStrings
== 0) ||
930 (pStrings
!= NULL
&& wNumStrings
>= 0));
931 for (i
= 0, str
= pStrings
; i
< wNumStrings
; i
++)
933 StringLen
= wcslen(str
) + 1; // str must be != NULL
934 RecSize
+= StringLen
* sizeof(WCHAR
);
938 /* Add the data size */
939 RecSize
+= dwDataSize
;
941 /* Align on DWORD boundary for the full structure */
942 RecSize
= ROUND_UP(RecSize
, sizeof(ULONG
));
944 /* Size of the trailing 'Length' member */
945 RecSize
+= sizeof(ULONG
);
947 Buffer
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, RecSize
);
950 DPRINT1("Cannot allocate heap!\n");
954 pRec
= (PEVENTLOGRECORD
)Buffer
;
955 pRec
->Length
= RecSize
;
956 pRec
->Reserved
= LOGFILE_SIGNATURE
;
959 * Do not assign here any precomputed record number to the event record.
960 * The true record number will be assigned atomically and sequentially in
961 * LogfWriteRecord, so that all the event records will have consistent and
962 * unique record numbers.
964 pRec
->RecordNumber
= 0;
967 * Set the generated time, and temporarily set the written time
968 * with the generated time.
970 pRec
->TimeGenerated
= Time
;
971 pRec
->TimeWritten
= Time
;
973 pRec
->EventID
= dwEventId
;
974 pRec
->EventType
= wType
;
975 pRec
->EventCategory
= wCategory
;
977 pos
= sizeof(EVENTLOGRECORD
);
979 /* NOTE: Equivalents of RtlStringCbCopyUnicodeString calls */
982 StringCbCopyNW((PWSTR
)(Buffer
+ pos
), SourceNameSize
+ sizeof(UNICODE_NULL
),
983 SourceName
->Buffer
, SourceNameSize
);
985 pos
+= SourceNameSize
+ sizeof(UNICODE_NULL
);
986 if (ComputerNameSize
)
988 StringCbCopyNW((PWSTR
)(Buffer
+ pos
), ComputerNameSize
+ sizeof(UNICODE_NULL
),
989 ComputerName
->Buffer
, ComputerNameSize
);
991 pos
+= ComputerNameSize
+ sizeof(UNICODE_NULL
);
993 /* Align on DWORD boundary for the SID */
994 pos
= ROUND_UP(pos
, sizeof(ULONG
));
996 pRec
->UserSidLength
= 0;
997 pRec
->UserSidOffset
= 0;
1000 RtlCopyMemory(Buffer
+ pos
, pUserSid
, dwSidLength
);
1001 pRec
->UserSidLength
= dwSidLength
;
1002 pRec
->UserSidOffset
= pos
;
1006 pRec
->StringOffset
= pos
;
1007 for (i
= 0, str
= pStrings
; i
< wNumStrings
; i
++)
1009 StringLen
= wcslen(str
) + 1; // str must be != NULL
1010 StringCchCopyW((PWSTR
)(Buffer
+ pos
), StringLen
, str
);
1012 pos
+= StringLen
* sizeof(WCHAR
);
1014 pRec
->NumStrings
= wNumStrings
;
1016 pRec
->DataLength
= 0;
1017 pRec
->DataOffset
= 0;
1020 RtlCopyMemory(Buffer
+ pos
, pRawData
, dwDataSize
);
1021 pRec
->DataLength
= dwDataSize
;
1022 pRec
->DataOffset
= pos
;
1026 /* Align on DWORD boundary for the full structure */
1027 pos
= ROUND_UP(pos
, sizeof(ULONG
));
1029 /* Initialize the trailing 'Length' member */
1030 *((PDWORD
)(Buffer
+ pos
)) = RecSize
;
1032 *pRecSize
= RecSize
;
1037 LogfReportEvent(USHORT wType
,
1046 UNICODE_STRING SourceName
, ComputerName
;
1047 PEVENTLOGRECORD LogBuffer
;
1048 LARGE_INTEGER SystemTime
;
1051 DWORD dwComputerNameLength
;
1052 WCHAR szComputerName
[MAX_COMPUTERNAME_LENGTH
+ 1];
1054 if (!EventLogSource
)
1057 RtlInitUnicodeString(&SourceName
, EventLogSource
->szName
);
1059 dwComputerNameLength
= ARRAYSIZE(szComputerName
);
1060 if (!GetComputerNameW(szComputerName
, &dwComputerNameLength
))
1061 szComputerName
[0] = L
'\0';
1063 RtlInitUnicodeString(&ComputerName
, szComputerName
);
1065 NtQuerySystemTime(&SystemTime
);
1066 RtlTimeToSecondsSince1970(&SystemTime
, &Time
);
1068 LogBuffer
= LogfAllocAndBuildNewRecord(&RecSize
,
1081 if (LogBuffer
== NULL
)
1083 DPRINT1("LogfAllocAndBuildNewRecord failed!\n");
1087 Status
= LogfWriteRecord(EventLogSource
->LogFile
, LogBuffer
, RecSize
);
1088 if (!NT_SUCCESS(Status
))
1090 DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n",
1091 EventLogSource
->LogFile
->LogName
, Status
);
1094 LogfFreeRecord(LogBuffer
);