Sync to trunk revision 63857.
[reactos.git] / base / services / eventlog / file.c
1 /*
2 * PROJECT: ReactOS kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: services/eventlog/file.c
5 * PURPOSE: Event logging service
6 * COPYRIGHT: Copyright 2005 Saveliy Tretiakov
7 Michael Martin
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "eventlog.h"
13
14 #include <ndk/iofuncs.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 static LIST_ENTRY LogFileListHead;
22 static CRITICAL_SECTION LogFileListCs;
23
24 /* FUNCTIONS ****************************************************************/
25
26 static NTSTATUS
27 LogfInitializeNew(PLOGFILE LogFile)
28 {
29 DWORD dwWritten;
30 EVENTLOGEOF EofRec;
31
32 ZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
33 SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
34 SetEndOfFile(LogFile->hFile);
35
36 LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
37 LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
38 LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
39 LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
40 LogFile->Header.MajorVersion = MAJORVER;
41 LogFile->Header.MinorVersion = MINORVER;
42 LogFile->Header.CurrentRecordNumber = 1;
43 LogFile->Header.OldestRecordNumber = 1;
44 /* FIXME: Read MaxSize from registry for this LogFile.
45 But for now limit EventLog size to just under 5K. */
46 LogFile->Header.MaxSize = 5000;
47 LogFile->Header.Signature = LOGFILE_SIGNATURE;
48 if (!WriteFile(LogFile->hFile,
49 &LogFile->Header,
50 sizeof(EVENTLOGHEADER),
51 &dwWritten,
52 NULL))
53 {
54 DPRINT1("WriteFile failed:%d!\n", GetLastError());
55 return STATUS_UNSUCCESSFUL;
56 }
57
58 EofRec.Ones = 0x11111111;
59 EofRec.Twos = 0x22222222;
60 EofRec.Threes = 0x33333333;
61 EofRec.Fours = 0x44444444;
62 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
63 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
64 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
65 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
66 EofRec.BeginRecord = LogFile->Header.StartOffset;
67 EofRec.EndRecord = LogFile->Header.EndOffset;
68
69 if (!WriteFile(LogFile->hFile,
70 &EofRec,
71 sizeof(EVENTLOGEOF),
72 &dwWritten,
73 NULL))
74 {
75 DPRINT1("WriteFile failed:%d!\n", GetLastError());
76 return STATUS_UNSUCCESSFUL;
77 }
78
79 if (!FlushFileBuffers(LogFile->hFile))
80 {
81 DPRINT1("FlushFileBuffers failed:%d!\n", GetLastError());
82 return STATUS_UNSUCCESSFUL;
83 }
84
85 return STATUS_SUCCESS;
86 }
87
88
89 static NTSTATUS
90 LogfInitializeExisting(PLOGFILE LogFile, BOOL Backup)
91 {
92 DWORD dwRead;
93 DWORD dwRecordsNumber = 0;
94 DWORD dwRecSize, dwRecSign, dwFilePointer;
95 PDWORD pdwRecSize2;
96 PEVENTLOGRECORD RecBuf;
97 BOOL OvewrWrittenRecords = FALSE;
98
99 DPRINT("Initializing LogFile %S\n",LogFile->LogName);
100
101 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
102 INVALID_SET_FILE_POINTER)
103 {
104 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
105 return STATUS_EVENTLOG_FILE_CORRUPT;
106 }
107
108 if (!ReadFile(LogFile->hFile,
109 &LogFile->Header,
110 sizeof(EVENTLOGHEADER),
111 &dwRead,
112 NULL))
113 {
114 DPRINT1("ReadFile failed! %d\n", GetLastError());
115 return STATUS_EVENTLOG_FILE_CORRUPT;
116 }
117
118 if (dwRead != sizeof(EVENTLOGHEADER))
119 {
120 DPRINT("EventLog: Invalid file %S.\n", LogFile->FileName);
121 return STATUS_EVENTLOG_FILE_CORRUPT;
122 }
123
124 if (LogFile->Header.HeaderSize != sizeof(EVENTLOGHEADER) ||
125 LogFile->Header.EndHeaderSize != sizeof(EVENTLOGHEADER))
126 {
127 DPRINT("EventLog: Invalid header size in %S.\n", LogFile->FileName);
128 return STATUS_EVENTLOG_FILE_CORRUPT;
129 }
130
131 if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
132 {
133 DPRINT("EventLog: Invalid signature %x in %S.\n",
134 LogFile->Header.Signature, LogFile->FileName);
135 return STATUS_EVENTLOG_FILE_CORRUPT;
136 }
137
138 if (LogFile->Header.EndOffset > GetFileSize(LogFile->hFile, NULL) + 1)
139 {
140 DPRINT("EventLog: Invalid eof offset %x in %S.\n",
141 LogFile->Header.EndOffset, LogFile->FileName);
142 return STATUS_EVENTLOG_FILE_CORRUPT;
143 }
144
145 /* Set the read location to the oldest record */
146 dwFilePointer = SetFilePointer(LogFile->hFile, LogFile->Header.StartOffset, NULL, FILE_BEGIN);
147 if (dwFilePointer == INVALID_SET_FILE_POINTER)
148 {
149 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
150 return STATUS_EVENTLOG_FILE_CORRUPT;
151 }
152
153 for (;;)
154 {
155 dwFilePointer = SetFilePointer(LogFile->hFile, 0, NULL, FILE_CURRENT);
156
157 if (dwFilePointer == INVALID_SET_FILE_POINTER)
158 {
159 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
160 return STATUS_EVENTLOG_FILE_CORRUPT;
161 }
162
163 /* If the EVENTLOGEOF info has been reached and the oldest record was not immediately after the Header */
164 if ((dwFilePointer == LogFile->Header.EndOffset) && (LogFile->Header.StartOffset != sizeof(EVENTLOGHEADER)))
165 {
166 OvewrWrittenRecords = TRUE;
167 /* The file has records that overwrote old ones so read them */
168 dwFilePointer = SetFilePointer(LogFile->hFile, sizeof(EVENTLOGHEADER), NULL, FILE_BEGIN);
169 }
170
171 if (!ReadFile(LogFile->hFile,
172 &dwRecSize,
173 sizeof(dwRecSize),
174 &dwRead,
175 NULL))
176 {
177 DPRINT1("ReadFile failed! %d\n", GetLastError());
178 return STATUS_EVENTLOG_FILE_CORRUPT;
179 }
180
181 if (dwRead != sizeof(dwRecSize))
182 break;
183
184 if (!ReadFile(LogFile->hFile,
185 &dwRecSign,
186 sizeof(dwRecSign),
187 &dwRead,
188 NULL))
189 {
190 DPRINT1("ReadFile() failed! %d\n", GetLastError());
191 return STATUS_EVENTLOG_FILE_CORRUPT;
192 }
193
194 if (dwRead != sizeof(dwRecSize))
195 break;
196
197 if (dwRecSign != LOGFILE_SIGNATURE ||
198 dwRecSize + dwFilePointer > GetFileSize(LogFile->hFile, NULL) + 1 ||
199 dwRecSize < sizeof(EVENTLOGRECORD))
200 {
201 break;
202 }
203
204 if (SetFilePointer(LogFile->hFile,
205 -((LONG) sizeof(DWORD) * 2),
206 NULL,
207 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
208 {
209 DPRINT1("SetFilePointer() failed! %d", GetLastError());
210 return STATUS_EVENTLOG_FILE_CORRUPT;
211 }
212
213 RecBuf = (PEVENTLOGRECORD) HeapAlloc(MyHeap, 0, dwRecSize);
214 if (RecBuf == NULL)
215 {
216 DPRINT1("Can't allocate heap!\n");
217 return STATUS_NO_MEMORY;
218 }
219
220 if (!ReadFile(LogFile->hFile, RecBuf, dwRecSize, &dwRead, NULL))
221 {
222 DPRINT1("ReadFile() failed! %d\n", GetLastError());
223 HeapFree(MyHeap, 0, RecBuf);
224 return STATUS_EVENTLOG_FILE_CORRUPT;
225 }
226
227 if (dwRead != dwRecSize)
228 {
229 HeapFree(MyHeap, 0, RecBuf);
230 break;
231 }
232
233 /* if OvewrWrittenRecords is TRUE and this record has already been read */
234 if ((OvewrWrittenRecords == TRUE) && (RecBuf->RecordNumber == LogFile->Header.OldestRecordNumber))
235 {
236 HeapFree(MyHeap, 0, RecBuf);
237 break;
238 }
239
240 pdwRecSize2 = (PDWORD) (((PBYTE) RecBuf) + dwRecSize - 4);
241
242 if (*pdwRecSize2 != dwRecSize)
243 {
244 DPRINT1("Invalid RecordSizeEnd of record %d (%x) in %S\n",
245 dwRecordsNumber, *pdwRecSize2, LogFile->LogName);
246 HeapFree(MyHeap, 0, RecBuf);
247 break;
248 }
249
250 dwRecordsNumber++;
251
252 if (!LogfAddOffsetInformation(LogFile,
253 RecBuf->RecordNumber,
254 dwFilePointer))
255 {
256 DPRINT1("LogfAddOffsetInformation() failed!\n");
257 HeapFree(MyHeap, 0, RecBuf);
258 return STATUS_EVENTLOG_FILE_CORRUPT;
259 }
260
261 HeapFree(MyHeap, 0, RecBuf);
262 }
263
264 LogFile->Header.CurrentRecordNumber = dwRecordsNumber + LogFile->Header.OldestRecordNumber;
265 if (LogFile->Header.CurrentRecordNumber == 0)
266 LogFile->Header.CurrentRecordNumber = 1;
267
268 /* FIXME: Read MaxSize from registry for this LogFile.
269 But for now limit EventLog size to just under 5K. */
270 LogFile->Header.MaxSize = 5000;
271
272 if (!Backup)
273 {
274 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
275 INVALID_SET_FILE_POINTER)
276 {
277 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
278 return STATUS_EVENTLOG_FILE_CORRUPT;
279 }
280
281 if (!WriteFile(LogFile->hFile,
282 &LogFile->Header,
283 sizeof(EVENTLOGHEADER),
284 &dwRead,
285 NULL))
286 {
287 DPRINT1("WriteFile failed! %d\n", GetLastError());
288 return STATUS_EVENTLOG_FILE_CORRUPT;
289 }
290
291 if (!FlushFileBuffers(LogFile->hFile))
292 {
293 DPRINT1("FlushFileBuffers failed! %d\n", GetLastError());
294 return STATUS_EVENTLOG_FILE_CORRUPT;
295 }
296 }
297
298 return STATUS_SUCCESS;
299 }
300
301
302 NTSTATUS
303 LogfCreate(PLOGFILE *LogFile,
304 WCHAR * LogName,
305 PUNICODE_STRING FileName,
306 BOOL Permanent,
307 BOOL Backup)
308 {
309 OBJECT_ATTRIBUTES ObjectAttributes;
310 IO_STATUS_BLOCK IoStatusBlock;
311 PLOGFILE pLogFile;
312 BOOL bCreateNew = FALSE;
313 NTSTATUS Status = STATUS_SUCCESS;
314
315 pLogFile = (LOGFILE *) HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, sizeof(LOGFILE));
316 if (!pLogFile)
317 {
318 DPRINT1("Can't allocate heap!\n");
319 return STATUS_NO_MEMORY;
320 }
321
322 InitializeObjectAttributes(&ObjectAttributes,
323 FileName,
324 OBJ_CASE_INSENSITIVE,
325 NULL,
326 NULL);
327
328 Status = NtCreateFile(&pLogFile->hFile,
329 Backup ? (GENERIC_READ | SYNCHRONIZE) : (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE),
330 &ObjectAttributes,
331 &IoStatusBlock,
332 NULL,
333 FILE_ATTRIBUTE_NORMAL,
334 FILE_SHARE_READ,
335 Backup ? FILE_OPEN : FILE_OPEN_IF,
336 FILE_SYNCHRONOUS_IO_NONALERT,
337 NULL,
338 0);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT1("Can't create file %wZ (Status: 0x%08lx)\n", FileName, Status);
342 goto fail;
343 }
344
345 bCreateNew = (IoStatusBlock.Information == FILE_CREATED) ? TRUE: FALSE;
346
347 pLogFile->LogName =
348 (WCHAR *) HeapAlloc(MyHeap,
349 HEAP_ZERO_MEMORY,
350 (lstrlenW(LogName) + 1) * sizeof(WCHAR));
351 if (pLogFile->LogName == NULL)
352 {
353 DPRINT1("Can't allocate heap\n");
354 Status = STATUS_NO_MEMORY;
355 goto fail;
356 }
357
358 lstrcpyW(pLogFile->LogName, LogName);
359
360 pLogFile->FileName =
361 (WCHAR *) HeapAlloc(MyHeap,
362 HEAP_ZERO_MEMORY,
363 (lstrlenW(FileName->Buffer) + 1) * sizeof(WCHAR));
364 if (pLogFile->FileName == NULL)
365 {
366 DPRINT1("Can't allocate heap\n");
367 Status = STATUS_NO_MEMORY;
368 goto fail;
369 }
370
371 lstrcpyW(pLogFile->FileName, FileName->Buffer);
372
373 pLogFile->OffsetInfo =
374 (PEVENT_OFFSET_INFO) HeapAlloc(MyHeap,
375 HEAP_ZERO_MEMORY,
376 sizeof(EVENT_OFFSET_INFO) * 64);
377 if (pLogFile->OffsetInfo == NULL)
378 {
379 DPRINT1("Can't allocate heap\n");
380 Status = STATUS_NO_MEMORY;
381 goto fail;
382 }
383
384 pLogFile->OffsetInfoSize = 64;
385
386 pLogFile->Permanent = Permanent;
387
388 if (bCreateNew)
389 Status = LogfInitializeNew(pLogFile);
390 else
391 Status = LogfInitializeExisting(pLogFile, Backup);
392
393 if (!NT_SUCCESS(Status))
394 goto fail;
395
396 RtlInitializeResource(&pLogFile->Lock);
397
398 LogfListAddItem(pLogFile);
399
400 fail:
401 if (!NT_SUCCESS(Status))
402 {
403 if ((pLogFile->hFile != NULL) && (pLogFile->hFile != INVALID_HANDLE_VALUE))
404 CloseHandle(pLogFile->hFile);
405
406 if (pLogFile->OffsetInfo)
407 HeapFree(MyHeap, 0, pLogFile->OffsetInfo);
408
409 if (pLogFile->FileName)
410 HeapFree(MyHeap, 0, pLogFile->FileName);
411
412 if (pLogFile->LogName)
413 HeapFree(MyHeap, 0, pLogFile->LogName);
414
415 HeapFree(MyHeap, 0, pLogFile);
416 }
417 else
418 {
419 *LogFile = pLogFile;
420 }
421
422 return Status;
423 }
424
425
426 VOID
427 LogfClose(PLOGFILE LogFile,
428 BOOL ForceClose)
429 {
430 if (LogFile == NULL)
431 return;
432
433 if ((ForceClose == FALSE) &&
434 (LogFile->Permanent == TRUE))
435 return;
436
437 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
438
439 FlushFileBuffers(LogFile->hFile);
440 CloseHandle(LogFile->hFile);
441 LogfListRemoveItem(LogFile);
442
443 RtlDeleteResource(&LogFile->Lock);
444
445 HeapFree(MyHeap, 0, LogFile->LogName);
446 HeapFree(MyHeap, 0, LogFile->FileName);
447 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
448 HeapFree(MyHeap, 0, LogFile);
449
450 return;
451 }
452
453 VOID LogfCloseAll(VOID)
454 {
455 while (!IsListEmpty(&LogFileListHead))
456 {
457 LogfClose(LogfListHead(), TRUE);
458 }
459
460 DeleteCriticalSection(&LogFileListCs);
461 }
462
463 VOID LogfListInitialize(VOID)
464 {
465 InitializeCriticalSection(&LogFileListCs);
466 InitializeListHead(&LogFileListHead);
467 }
468
469 PLOGFILE LogfListHead(VOID)
470 {
471 return CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry);
472 }
473
474 PLOGFILE LogfListItemByName(WCHAR * Name)
475 {
476 PLIST_ENTRY CurrentEntry;
477 PLOGFILE Result = NULL;
478
479 EnterCriticalSection(&LogFileListCs);
480
481 CurrentEntry = LogFileListHead.Flink;
482 while (CurrentEntry != &LogFileListHead)
483 {
484 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
485 LOGFILE,
486 ListEntry);
487
488 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
489 {
490 Result = Item;
491 break;
492 }
493
494 CurrentEntry = CurrentEntry->Flink;
495 }
496
497 LeaveCriticalSection(&LogFileListCs);
498 return Result;
499 }
500
501 /* Index starting from 1 */
502 INT LogfListItemIndexByName(WCHAR * Name)
503 {
504 PLIST_ENTRY CurrentEntry;
505 INT Result = 0;
506 INT i = 1;
507
508 EnterCriticalSection(&LogFileListCs);
509
510 CurrentEntry = LogFileListHead.Flink;
511 while (CurrentEntry != &LogFileListHead)
512 {
513 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
514 LOGFILE,
515 ListEntry);
516
517 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
518 {
519 Result = i;
520 break;
521 }
522
523 CurrentEntry = CurrentEntry->Flink;
524 i++;
525 }
526
527 LeaveCriticalSection(&LogFileListCs);
528 return Result;
529 }
530
531 /* Index starting from 1 */
532 PLOGFILE LogfListItemByIndex(INT Index)
533 {
534 PLIST_ENTRY CurrentEntry;
535 PLOGFILE Result = NULL;
536 INT i = 1;
537
538 EnterCriticalSection(&LogFileListCs);
539
540 CurrentEntry = LogFileListHead.Flink;
541 while (CurrentEntry != &LogFileListHead)
542 {
543 if (i == Index)
544 {
545 Result = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
546 break;
547 }
548
549 CurrentEntry = CurrentEntry->Flink;
550 i++;
551 }
552
553 LeaveCriticalSection(&LogFileListCs);
554 return Result;
555 }
556
557 INT LogfListItemCount(VOID)
558 {
559 PLIST_ENTRY CurrentEntry;
560 INT i = 0;
561
562 EnterCriticalSection(&LogFileListCs);
563
564 CurrentEntry = LogFileListHead.Flink;
565 while (CurrentEntry != &LogFileListHead)
566 {
567 CurrentEntry = CurrentEntry->Flink;
568 i++;
569 }
570
571 LeaveCriticalSection(&LogFileListCs);
572 return i;
573 }
574
575 VOID LogfListAddItem(PLOGFILE Item)
576 {
577 EnterCriticalSection(&LogFileListCs);
578 InsertTailList(&LogFileListHead, &Item->ListEntry);
579 LeaveCriticalSection(&LogFileListCs);
580 }
581
582 VOID LogfListRemoveItem(PLOGFILE Item)
583 {
584 EnterCriticalSection(&LogFileListCs);
585 RemoveEntryList(&Item->ListEntry);
586 LeaveCriticalSection(&LogFileListCs);
587 }
588
589 static BOOL
590 ReadAnsiLogEntry(HANDLE hFile,
591 LPVOID lpBuffer,
592 DWORD nNumberOfBytesToRead,
593 LPDWORD lpNumberOfBytesRead)
594 {
595 PEVENTLOGRECORD Dst;
596 PEVENTLOGRECORD Src;
597 ANSI_STRING StringA;
598 UNICODE_STRING StringW;
599 LPWSTR SrcPtr;
600 LPSTR DstPtr;
601 LPWSTR SrcString;
602 LPSTR DstString;
603 LPVOID lpUnicodeBuffer = NULL;
604 DWORD dwRead = 0;
605 DWORD i;
606 DWORD dwPadding;
607 DWORD dwEntryLength;
608 PDWORD pLength;
609 NTSTATUS Status;
610 BOOL ret = TRUE;
611
612 *lpNumberOfBytesRead = 0;
613
614 lpUnicodeBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nNumberOfBytesToRead);
615 if (lpUnicodeBuffer == NULL)
616 {
617 DPRINT1("Alloc failed!\n");
618 return FALSE;
619 }
620
621 if (!ReadFile(hFile, lpUnicodeBuffer, nNumberOfBytesToRead, &dwRead, NULL))
622 {
623 DPRINT1("Read failed!\n");
624 ret = FALSE;
625 goto done;
626 }
627
628 Dst = (PEVENTLOGRECORD)lpBuffer;
629 Src = (PEVENTLOGRECORD)lpUnicodeBuffer;
630
631 Dst->TimeGenerated = Src->TimeGenerated;
632 Dst->Reserved = Src->Reserved;
633 Dst->RecordNumber = Src->RecordNumber;
634 Dst->TimeWritten = Src->TimeWritten;
635 Dst->EventID = Src->EventID;
636 Dst->EventType = Src->EventType;
637 Dst->EventCategory = Src->EventCategory;
638 Dst->NumStrings = Src->NumStrings;
639 Dst->UserSidLength = Src->UserSidLength;
640 Dst->DataLength = Src->DataLength;
641
642 SrcPtr = (LPWSTR)((DWORD_PTR)Src + sizeof(EVENTLOGRECORD));
643 DstPtr = (LPSTR)((DWORD_PTR)Dst + sizeof(EVENTLOGRECORD));
644
645 /* Convert the module name */
646 RtlInitUnicodeString(&StringW, SrcPtr);
647 Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
648 if (NT_SUCCESS(Status))
649 {
650 RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
651
652 DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
653
654 RtlFreeAnsiString(&StringA);
655 }
656
657 /* Convert the computer name */
658 if (NT_SUCCESS(Status))
659 {
660 SrcPtr = (PWSTR)((DWORD_PTR)SrcPtr + StringW.MaximumLength);
661
662 RtlInitUnicodeString(&StringW, SrcPtr);
663 Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
664 if (NT_SUCCESS(Status))
665 {
666 RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
667
668 DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
669
670 RtlFreeAnsiString(&StringA);
671 }
672 }
673
674 /* Add the padding and the User SID*/
675 if (NT_SUCCESS(Status))
676 {
677 dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr - (DWORD_PTR)Dst) % sizeof(DWORD));
678 RtlZeroMemory(DstPtr, dwPadding);
679
680 DstPtr = (LPSTR)((DWORD_PTR)DstPtr + dwPadding);
681 RtlCopyMemory(DstPtr,
682 (PVOID)((DWORD_PTR)Src + Src->UserSidOffset),
683 Src->UserSidLength);
684
685 Dst->UserSidOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
686 }
687
688
689 /* Convert the strings */
690 if (NT_SUCCESS(Status))
691 {
692 DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->UserSidLength);
693
694 SrcString = (LPWSTR)((DWORD_PTR)Src + (DWORD)Src->StringOffset);
695 DstString = (LPSTR)DstPtr;
696
697 for (i = 0; i < Dst->NumStrings; i++)
698 {
699 RtlInitUnicodeString(&StringW, SrcString);
700
701 RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
702
703 RtlCopyMemory(DstString, StringA.Buffer, StringA.MaximumLength);
704
705 SrcString = (LPWSTR)((DWORD_PTR)SrcString +
706 (DWORD)StringW.MaximumLength);
707
708 DstString = (LPSTR)((DWORD_PTR)DstString +
709 (DWORD)StringA.MaximumLength);
710
711 RtlFreeAnsiString(&StringA);
712 }
713
714 Dst->StringOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
715
716
717 /* Copy the binary data */
718 DstPtr = (PVOID)DstString;
719 Dst->DataOffset = (DWORD_PTR)DstPtr - (DWORD_PTR)Dst;
720
721 RtlCopyMemory(DstPtr, (PVOID)((DWORD_PTR)Src + Src->DataOffset), Src->DataLength);
722
723 /* Add the padding */
724 DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->DataLength);
725 dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr-(DWORD_PTR)Dst) % sizeof(DWORD));
726 RtlZeroMemory(DstPtr, dwPadding);
727
728 dwEntryLength = (DWORD)((DWORD_PTR)DstPtr + dwPadding + sizeof(DWORD) - (DWORD_PTR)Dst);
729
730 /* Set the entry length at the end of the entry*/
731 pLength = (PDWORD)((DWORD_PTR)DstPtr + dwPadding);
732 *pLength = dwEntryLength;
733 Dst->Length = dwEntryLength;
734
735 *lpNumberOfBytesRead = dwEntryLength;
736 }
737
738 done:
739 if (lpUnicodeBuffer != NULL)
740 HeapFree(GetProcessHeap(), 0, lpUnicodeBuffer);
741
742 return ret;
743 }
744
745
746 DWORD LogfReadEvent(PLOGFILE LogFile,
747 DWORD Flags,
748 DWORD * RecordNumber,
749 DWORD BufSize,
750 PBYTE Buffer,
751 DWORD * BytesRead,
752 DWORD * BytesNeeded,
753 BOOL Ansi)
754 {
755 DWORD dwOffset, dwRead, dwRecSize;
756 DWORD dwBufferUsage = 0, dwRecNum;
757
758 if (Flags & EVENTLOG_FORWARDS_READ && Flags & EVENTLOG_BACKWARDS_READ)
759 return ERROR_INVALID_PARAMETER;
760
761 if (!(Flags & EVENTLOG_FORWARDS_READ) && !(Flags & EVENTLOG_BACKWARDS_READ))
762 return ERROR_INVALID_PARAMETER;
763
764 if (!Buffer || !BytesRead || !BytesNeeded)
765 return ERROR_INVALID_PARAMETER;
766
767 if ((*RecordNumber==0) && !(EVENTLOG_SEQUENTIAL_READ))
768 {
769 return ERROR_INVALID_PARAMETER;
770 }
771
772 dwRecNum = *RecordNumber;
773
774 RtlAcquireResourceShared(&LogFile->Lock, TRUE);
775
776 *BytesRead = 0;
777 *BytesNeeded = 0;
778
779 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
780
781 if (!dwOffset)
782 {
783 RtlReleaseResource(&LogFile->Lock);
784 return ERROR_HANDLE_EOF;
785 }
786
787 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
788 INVALID_SET_FILE_POINTER)
789 {
790 DPRINT1("SetFilePointer() failed!\n");
791 goto Done;
792 }
793
794 if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
795 {
796 DPRINT1("ReadFile() failed!\n");
797 goto Done;
798 }
799
800 if (dwRecSize > BufSize)
801 {
802 *BytesNeeded = dwRecSize;
803 RtlReleaseResource(&LogFile->Lock);
804 return ERROR_INSUFFICIENT_BUFFER;
805 }
806
807 if (SetFilePointer(LogFile->hFile,
808 -((LONG) sizeof(DWORD)),
809 NULL,
810 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
811 {
812 DPRINT1("SetFilePointer() failed!\n");
813 goto Done;
814 }
815
816 if (Ansi == TRUE)
817 {
818 if (!ReadAnsiLogEntry(LogFile->hFile, Buffer, dwRecSize, &dwRead))
819 {
820 DPRINT1("ReadAnsiLogEntry() failed!\n");
821 goto Done;
822 }
823 }
824 else
825 {
826 if (!ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL))
827 {
828 DPRINT1("ReadFile() failed!\n");
829 goto Done;
830 }
831 }
832
833 dwBufferUsage += dwRead;
834
835 while (dwBufferUsage <= BufSize)
836 {
837 if (Flags & EVENTLOG_FORWARDS_READ)
838 dwRecNum++;
839 else
840 dwRecNum--;
841
842 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
843 if (!dwOffset)
844 break;
845
846 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
847 INVALID_SET_FILE_POINTER)
848 {
849 DPRINT1("SetFilePointer() failed!\n");
850 goto Done;
851 }
852
853 if (!ReadFile(LogFile->hFile,
854 &dwRecSize,
855 sizeof(DWORD),
856 &dwRead,
857 NULL))
858 {
859 DPRINT1("ReadFile() failed!\n");
860 goto Done;
861 }
862
863 if (dwBufferUsage + dwRecSize > BufSize)
864 break;
865
866 if (SetFilePointer(LogFile->hFile,
867 -((LONG) sizeof(DWORD)),
868 NULL,
869 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
870 {
871 DPRINT1("SetFilePointer() failed!\n");
872 goto Done;
873 }
874
875 if (Ansi == TRUE)
876 {
877 if (!ReadAnsiLogEntry(LogFile->hFile,
878 Buffer + dwBufferUsage,
879 dwRecSize,
880 &dwRead))
881 {
882 DPRINT1("ReadAnsiLogEntry() failed!\n");
883 goto Done;
884 }
885 }
886 else
887 {
888 if (!ReadFile(LogFile->hFile,
889 Buffer + dwBufferUsage,
890 dwRecSize,
891 &dwRead,
892 NULL))
893 {
894 DPRINT1("ReadFile() failed!\n");
895 goto Done;
896 }
897 }
898
899 dwBufferUsage += dwRead;
900 }
901
902 *BytesRead = dwBufferUsage;
903 * RecordNumber = dwRecNum;
904 RtlReleaseResource(&LogFile->Lock);
905 return ERROR_SUCCESS;
906
907 Done:
908 DPRINT1("LogfReadEvent failed with %x\n",GetLastError());
909 RtlReleaseResource(&LogFile->Lock);
910 return GetLastError();
911 }
912
913 BOOL LogfWriteData(PLOGFILE LogFile, DWORD BufSize, PBYTE Buffer)
914 {
915 DWORD dwWritten;
916 DWORD dwRead;
917 SYSTEMTIME st;
918 EVENTLOGEOF EofRec;
919 PEVENTLOGRECORD RecBuf;
920 LARGE_INTEGER logFileSize;
921 ULONG RecOffSet;
922 ULONG WriteOffSet;
923
924 if (!Buffer)
925 return FALSE;
926
927 GetSystemTime(&st);
928 SystemTimeToEventTime(&st, &((PEVENTLOGRECORD) Buffer)->TimeWritten);
929
930 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
931
932 if (!GetFileSizeEx(LogFile->hFile, &logFileSize))
933 {
934 RtlReleaseResource(&LogFile->Lock);
935 return FALSE;
936 }
937
938 /* If the size of the file is over MaxSize */
939 if ((logFileSize.QuadPart + BufSize)> LogFile->Header.MaxSize)
940 {
941 ULONG OverWriteLength = 0;
942 WriteOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
943 RecBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EVENTLOGRECORD));
944 /* Determine how many records need to be overwritten */
945 while (TRUE)
946 {
947 DPRINT("EventLogFile has reached maximume size\n");
948
949 if (!RecBuf)
950 {
951 DPRINT1("Failed to allocate buffer for OldestRecord!\n");
952 HeapFree(GetProcessHeap(), 0, RecBuf);
953 RtlReleaseResource(&LogFile->Lock);
954 return FALSE;
955 }
956
957 /* Get the oldest record data */
958 RecOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
959
960 if (SetFilePointer(LogFile->hFile,
961 RecOffSet,
962 NULL,
963 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
964 {
965 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
966 HeapFree(GetProcessHeap(), 0, RecBuf);
967 RtlReleaseResource(&LogFile->Lock);
968 return FALSE;
969 }
970
971 if (!ReadFile(LogFile->hFile, RecBuf, sizeof(EVENTLOGRECORD), &dwRead, NULL))
972 {
973 DPRINT1("ReadFile() failed!\n");
974 HeapFree(GetProcessHeap(), 0, RecBuf);
975 RtlReleaseResource(&LogFile->Lock);
976 return FALSE;
977 }
978
979 if (RecBuf->Reserved != LOGFILE_SIGNATURE)
980 {
981 DPRINT1("LogFile corrupt!\n");
982 HeapFree(GetProcessHeap(), 0, RecBuf);
983 RtlReleaseResource(&LogFile->Lock);
984 return FALSE;
985 }
986
987 LogfDeleteOffsetInformation(LogFile,LogFile->Header.OldestRecordNumber);
988
989 LogFile->Header.OldestRecordNumber++;
990
991 OverWriteLength += RecBuf->Length;
992 /* Check the size of the record as the record adding may be larger */
993 if (OverWriteLength >= BufSize)
994 {
995 DPRINT("Record will fit. Length %d, BufSize %d\n", OverWriteLength, BufSize);
996 LogFile->Header.StartOffset = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
997 break;
998 }
999 }
1000 HeapFree(GetProcessHeap(), 0, RecBuf);
1001 }
1002 else
1003 WriteOffSet = LogFile->Header.EndOffset;
1004
1005 if (SetFilePointer(LogFile->hFile,
1006 WriteOffSet,
1007 NULL,
1008 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1009 {
1010 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
1011 RtlReleaseResource(&LogFile->Lock);
1012 return FALSE;
1013 }
1014
1015 if (!WriteFile(LogFile->hFile, Buffer, BufSize, &dwWritten, NULL))
1016 {
1017 DPRINT1("WriteFile() failed! %d\n", GetLastError());
1018 RtlReleaseResource(&LogFile->Lock);
1019 return FALSE;
1020 }
1021
1022 if (!LogfAddOffsetInformation(LogFile,
1023 LogFile->Header.CurrentRecordNumber,
1024 WriteOffSet))
1025 {
1026 RtlReleaseResource(&LogFile->Lock);
1027 return FALSE;
1028 }
1029
1030 LogFile->Header.CurrentRecordNumber++;
1031
1032 if (WriteOffSet == LogFile->Header.EndOffset)
1033 {
1034 LogFile->Header.EndOffset += dwWritten;
1035 }
1036 if (SetFilePointer(LogFile->hFile,
1037 LogFile->Header.EndOffset,
1038 NULL,
1039 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1040 {
1041 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
1042 RtlReleaseResource(&LogFile->Lock);
1043 return FALSE;
1044 }
1045
1046 EofRec.Ones = 0x11111111;
1047 EofRec.Twos = 0x22222222;
1048 EofRec.Threes = 0x33333333;
1049 EofRec.Fours = 0x44444444;
1050 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
1051 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
1052 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1053 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1054 EofRec.BeginRecord = LogFile->Header.StartOffset;
1055 EofRec.EndRecord = LogFile->Header.EndOffset;
1056
1057 if (!WriteFile(LogFile->hFile,
1058 &EofRec,
1059 sizeof(EVENTLOGEOF),
1060 &dwWritten,
1061 NULL))
1062 {
1063 DPRINT1("WriteFile() failed! %d\n", GetLastError());
1064 RtlReleaseResource(&LogFile->Lock);
1065 return FALSE;
1066 }
1067
1068 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
1069 INVALID_SET_FILE_POINTER)
1070 {
1071 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
1072 RtlReleaseResource(&LogFile->Lock);
1073 return FALSE;
1074 }
1075
1076 if (!WriteFile(LogFile->hFile,
1077 &LogFile->Header,
1078 sizeof(EVENTLOGHEADER),
1079 &dwWritten,
1080 NULL))
1081 {
1082 DPRINT1("WriteFile failed! LastError = %d\n", GetLastError());
1083 RtlReleaseResource(&LogFile->Lock);
1084 return FALSE;
1085 }
1086
1087 if (!FlushFileBuffers(LogFile->hFile))
1088 {
1089 DPRINT1("FlushFileBuffers() failed! %d\n", GetLastError());
1090 RtlReleaseResource(&LogFile->Lock);
1091 return FALSE;
1092 }
1093
1094 RtlReleaseResource(&LogFile->Lock);
1095 return TRUE;
1096 }
1097
1098
1099 NTSTATUS
1100 LogfClearFile(PLOGFILE LogFile,
1101 PUNICODE_STRING BackupFileName)
1102 {
1103 NTSTATUS Status;
1104
1105 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
1106
1107 if (BackupFileName->Length > 0)
1108 {
1109 /* Write a backup file */
1110 Status = LogfBackupFile(LogFile,
1111 BackupFileName);
1112 if (!NT_SUCCESS(Status))
1113 {
1114 DPRINT1("LogfBackupFile failed (Status: 0x%08lx)\n", Status);
1115 return Status;
1116 }
1117 }
1118
1119 Status = LogfInitializeNew(LogFile);
1120 if (!NT_SUCCESS(Status))
1121 {
1122 DPRINT1("LogfInitializeNew failed (Status: 0x%08lx)\n", Status);
1123 }
1124
1125 RtlReleaseResource(&LogFile->Lock);
1126
1127 return Status;
1128 }
1129
1130
1131 NTSTATUS
1132 LogfBackupFile(PLOGFILE LogFile,
1133 PUNICODE_STRING BackupFileName)
1134 {
1135 OBJECT_ATTRIBUTES ObjectAttributes;
1136 IO_STATUS_BLOCK IoStatusBlock;
1137 EVENTLOGHEADER Header;
1138 EVENTLOGEOF EofRec;
1139 HANDLE FileHandle = NULL;
1140 ULONG i;
1141 LARGE_INTEGER FileOffset;
1142 NTSTATUS Status;
1143 PUCHAR Buffer = NULL;
1144
1145 DWORD dwOffset, dwRead, dwRecSize;
1146
1147 DPRINT("LogfBackupFile(%p, %wZ)\n", LogFile, BackupFileName);
1148
1149 /* Lock the log file shared */
1150 RtlAcquireResourceShared(&LogFile->Lock, TRUE);
1151
1152 InitializeObjectAttributes(&ObjectAttributes,
1153 BackupFileName,
1154 OBJ_CASE_INSENSITIVE,
1155 NULL,
1156 NULL);
1157
1158 Status = NtCreateFile(&FileHandle,
1159 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1160 &ObjectAttributes,
1161 &IoStatusBlock,
1162 NULL,
1163 FILE_ATTRIBUTE_NORMAL,
1164 FILE_SHARE_READ,
1165 FILE_CREATE,
1166 FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
1167 NULL,
1168 0);
1169 if (!NT_SUCCESS(Status))
1170 {
1171 DPRINT("Can't create backup file %wZ (Status: 0x%08lx)\n", BackupFileName, Status);
1172 goto Done;
1173 }
1174
1175 /* Initialize the (dirty) log file header */
1176 Header.HeaderSize = sizeof(EVENTLOGHEADER);
1177 Header.Signature = LOGFILE_SIGNATURE;
1178 Header.MajorVersion = MAJORVER;
1179 Header.MinorVersion = MINORVER;
1180 Header.StartOffset = sizeof(EVENTLOGHEADER);
1181 Header.EndOffset = sizeof(EVENTLOGHEADER);
1182 Header.CurrentRecordNumber = 1;
1183 Header.OldestRecordNumber = 1;
1184 Header.MaxSize = 0;
1185 Header.Flags = ELF_LOGFILE_HEADER_DIRTY;
1186 Header.Retention = LogFile->Header.Retention;
1187 Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
1188
1189 /* Write the (dirty) log file header */
1190 Status = NtWriteFile(FileHandle,
1191 NULL,
1192 NULL,
1193 NULL,
1194 &IoStatusBlock,
1195 &Header,
1196 sizeof(EVENTLOGHEADER),
1197 NULL,
1198 NULL);
1199 if (!NT_SUCCESS(Status))
1200 {
1201 DPRINT1("Failed to write the log file header (Status: 0x%08lx)\n", Status);
1202 goto Done;
1203 }
1204
1205 for (i = LogFile->Header.OldestRecordNumber; i < LogFile->Header.CurrentRecordNumber; i++)
1206 {
1207 dwOffset = LogfOffsetByNumber(LogFile, i);
1208 if (dwOffset == 0)
1209 break;
1210
1211 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1212 {
1213 DPRINT1("SetFilePointer() failed!\n");
1214 goto Done;
1215 }
1216
1217 if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
1218 {
1219 DPRINT1("ReadFile() failed!\n");
1220 goto Done;
1221 }
1222
1223 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1224 {
1225 DPRINT1("SetFilePointer() failed!\n");
1226 goto Done;
1227 }
1228
1229 Buffer = HeapAlloc(MyHeap, 0, dwRecSize);
1230 if (Buffer == NULL)
1231 {
1232 DPRINT1("HeapAlloc() failed!\n");
1233 goto Done;
1234 }
1235
1236 if (!ReadFile(LogFile->hFile, &Buffer, dwRecSize, &dwRead, NULL))
1237 {
1238 DPRINT1("ReadFile() failed!\n");
1239 goto Done;
1240 }
1241
1242 /* Write the event record */
1243 Status = NtWriteFile(FileHandle,
1244 NULL,
1245 NULL,
1246 NULL,
1247 &IoStatusBlock,
1248 Buffer,
1249 dwRecSize,
1250 NULL,
1251 NULL);
1252 if (!NT_SUCCESS(Status))
1253 {
1254 DPRINT1("NtWriteFile() failed!\n");
1255 goto Done;
1256 }
1257
1258 /* Update the header information */
1259 Header.EndOffset += dwRecSize;
1260
1261 /* Free the buffer */
1262 HeapFree(MyHeap, 0, Buffer);
1263 Buffer = NULL;
1264 }
1265
1266 /* Initialize the EOF record */
1267 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
1268 EofRec.Ones = 0x11111111;
1269 EofRec.Twos = 0x22222222;
1270 EofRec.Threes = 0x33333333;
1271 EofRec.Fours = 0x44444444;
1272 EofRec.BeginRecord = sizeof(EVENTLOGHEADER);
1273 EofRec.EndRecord = Header.EndOffset;
1274 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1275 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1276 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
1277
1278 /* Write the EOF record */
1279 Status = NtWriteFile(FileHandle,
1280 NULL,
1281 NULL,
1282 NULL,
1283 &IoStatusBlock,
1284 &EofRec,
1285 sizeof(EVENTLOGEOF),
1286 NULL,
1287 NULL);
1288 if (!NT_SUCCESS(Status))
1289 {
1290 DPRINT1("NtWriteFile() failed!\n");
1291 goto Done;
1292 }
1293
1294 /* Update the header information */
1295 Header.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1296 Header.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1297 Header.MaxSize = Header.EndOffset + sizeof(EVENTLOGEOF);
1298 Header.Flags = 0;
1299
1300 /* Write the (clean) log file header */
1301 FileOffset.QuadPart = 0;
1302 Status = NtWriteFile(FileHandle,
1303 NULL,
1304 NULL,
1305 NULL,
1306 &IoStatusBlock,
1307 &Header,
1308 sizeof(EVENTLOGHEADER),
1309 &FileOffset,
1310 NULL);
1311 if (!NT_SUCCESS(Status))
1312 {
1313 DPRINT1("NtWriteFile() failed!\n");
1314 }
1315
1316 Done:
1317 /* Free the buffer */
1318 if (Buffer != NULL)
1319 HeapFree(MyHeap, 0, Buffer);
1320
1321 /* Close the backup file */
1322 if (FileHandle != NULL)
1323 NtClose(FileHandle);
1324
1325 /* Unlock the log file */
1326 RtlReleaseResource(&LogFile->Lock);
1327
1328 return Status;
1329 }
1330
1331
1332 /* Returns 0 if nothing found. */
1333 ULONG LogfOffsetByNumber(PLOGFILE LogFile, DWORD RecordNumber)
1334 {
1335 DWORD i;
1336
1337 for (i = 0; i < LogFile->OffsetInfoNext; i++)
1338 {
1339 if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
1340 return LogFile->OffsetInfo[i].EventOffset;
1341 }
1342 return 0;
1343 }
1344
1345 DWORD LogfGetOldestRecord(PLOGFILE LogFile)
1346 {
1347 return LogFile->Header.OldestRecordNumber;
1348 }
1349
1350 DWORD LogfGetCurrentRecord(PLOGFILE LogFile)
1351 {
1352 return LogFile->Header.CurrentRecordNumber;
1353 }
1354
1355 BOOL LogfDeleteOffsetInformation(PLOGFILE LogFile, ULONG ulNumber)
1356 {
1357 DWORD i;
1358
1359 if (ulNumber != LogFile->OffsetInfo[0].EventNumber)
1360 {
1361 return FALSE;
1362 }
1363
1364 for (i = 0; i < LogFile->OffsetInfoNext - 1; i++)
1365 {
1366 LogFile->OffsetInfo[i].EventNumber = LogFile->OffsetInfo[i + 1].EventNumber;
1367 LogFile->OffsetInfo[i].EventOffset = LogFile->OffsetInfo[i + 1].EventOffset;
1368 }
1369 LogFile->OffsetInfoNext--;
1370 return TRUE;
1371 }
1372
1373 BOOL LogfAddOffsetInformation(PLOGFILE LogFile, ULONG ulNumber, ULONG ulOffset)
1374 {
1375 LPVOID NewOffsetInfo;
1376
1377 if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
1378 {
1379 NewOffsetInfo = HeapReAlloc(MyHeap,
1380 HEAP_ZERO_MEMORY,
1381 LogFile->OffsetInfo,
1382 (LogFile->OffsetInfoSize + 64) *
1383 sizeof(EVENT_OFFSET_INFO));
1384
1385 if (!NewOffsetInfo)
1386 {
1387 DPRINT1("Can't reallocate heap.\n");
1388 return FALSE;
1389 }
1390
1391 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO) NewOffsetInfo;
1392 LogFile->OffsetInfoSize += 64;
1393 }
1394
1395 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
1396 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
1397 LogFile->OffsetInfoNext++;
1398
1399 return TRUE;
1400 }
1401
1402 PBYTE LogfAllocAndBuildNewRecord(LPDWORD lpRecSize,
1403 DWORD dwRecordNumber,
1404 WORD wType,
1405 WORD wCategory,
1406 DWORD dwEventId,
1407 LPCWSTR SourceName,
1408 LPCWSTR ComputerName,
1409 DWORD dwSidLength,
1410 PSID lpUserSid,
1411 WORD wNumStrings,
1412 WCHAR * lpStrings,
1413 DWORD dwDataSize,
1414 LPVOID lpRawData)
1415 {
1416 DWORD dwRecSize;
1417 PEVENTLOGRECORD pRec;
1418 SYSTEMTIME SysTime;
1419 WCHAR *str;
1420 UINT i, pos;
1421 PBYTE Buffer;
1422
1423 dwRecSize =
1424 sizeof(EVENTLOGRECORD) + (lstrlenW(ComputerName) +
1425 lstrlenW(SourceName) + 2) * sizeof(WCHAR);
1426
1427 if (dwRecSize % 4 != 0)
1428 dwRecSize += 4 - (dwRecSize % 4);
1429
1430 dwRecSize += dwSidLength;
1431
1432 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1433 {
1434 dwRecSize += (lstrlenW(str) + 1) * sizeof(WCHAR);
1435 str += lstrlenW(str) + 1;
1436 }
1437
1438 dwRecSize += dwDataSize;
1439 if (dwRecSize % 4 != 0)
1440 dwRecSize += 4 - (dwRecSize % 4);
1441
1442 dwRecSize += 4;
1443
1444 Buffer = HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, dwRecSize);
1445
1446 if (!Buffer)
1447 {
1448 DPRINT1("Can't allocate heap!\n");
1449 return NULL;
1450 }
1451
1452 pRec = (PEVENTLOGRECORD) Buffer;
1453 pRec->Length = dwRecSize;
1454 pRec->Reserved = LOGFILE_SIGNATURE;
1455 pRec->RecordNumber = dwRecordNumber;
1456
1457 GetSystemTime(&SysTime);
1458 SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
1459 SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
1460
1461 pRec->EventID = dwEventId;
1462 pRec->EventType = wType;
1463 pRec->EventCategory = wCategory;
1464
1465 pos = sizeof(EVENTLOGRECORD);
1466
1467 lstrcpyW((WCHAR *) (Buffer + pos), SourceName);
1468 pos += (lstrlenW(SourceName) + 1) * sizeof(WCHAR);
1469 lstrcpyW((WCHAR *) (Buffer + pos), ComputerName);
1470 pos += (lstrlenW(ComputerName) + 1) * sizeof(WCHAR);
1471
1472 pRec->UserSidOffset = pos;
1473
1474 if (pos % 4 != 0)
1475 pos += 4 - (pos % 4);
1476
1477 if (dwSidLength)
1478 {
1479 CopyMemory(Buffer + pos, lpUserSid, dwSidLength);
1480 pRec->UserSidLength = dwSidLength;
1481 pRec->UserSidOffset = pos;
1482 pos += dwSidLength;
1483 }
1484
1485 pRec->StringOffset = pos;
1486 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1487 {
1488 lstrcpyW((WCHAR *) (Buffer + pos), str);
1489 pos += (lstrlenW(str) + 1) * sizeof(WCHAR);
1490 str += lstrlenW(str) + 1;
1491 }
1492 pRec->NumStrings = wNumStrings;
1493
1494 pRec->DataOffset = pos;
1495 if (dwDataSize)
1496 {
1497 pRec->DataLength = dwDataSize;
1498 CopyMemory(Buffer + pos, lpRawData, dwDataSize);
1499 pos += dwDataSize;
1500 }
1501
1502 if (pos % 4 != 0)
1503 pos += 4 - (pos % 4);
1504
1505 *((PDWORD) (Buffer + pos)) = dwRecSize;
1506
1507 *lpRecSize = dwRecSize;
1508 return Buffer;
1509 }
1510
1511
1512 VOID
1513 LogfReportEvent(WORD wType,
1514 WORD wCategory,
1515 DWORD dwEventId,
1516 WORD wNumStrings,
1517 WCHAR *lpStrings,
1518 DWORD dwDataSize,
1519 LPVOID lpRawData)
1520 {
1521 WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1522 DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
1523 PEVENTSOURCE pEventSource = NULL;
1524 PBYTE logBuffer;
1525 DWORD lastRec;
1526 DWORD recSize;
1527 DWORD dwError;
1528
1529 if (!GetComputerNameW(szComputerName, &dwComputerNameLength))
1530 {
1531 szComputerName[0] = 0;
1532 }
1533
1534 pEventSource = GetEventSourceByName(L"EventLog");
1535 if (pEventSource == NULL)
1536 {
1537 return;
1538 }
1539
1540 lastRec = LogfGetCurrentRecord(pEventSource->LogFile);
1541
1542 logBuffer = LogfAllocAndBuildNewRecord(&recSize,
1543 lastRec,
1544 wType,
1545 wCategory,
1546 dwEventId,
1547 pEventSource->szName,
1548 (LPCWSTR)szComputerName,
1549 0,
1550 NULL,
1551 wNumStrings,
1552 lpStrings,
1553 dwDataSize,
1554 lpRawData);
1555
1556 dwError = LogfWriteData(pEventSource->LogFile, recSize, logBuffer);
1557 if (!dwError)
1558 {
1559 DPRINT1("ERROR WRITING TO EventLog %S\n", pEventSource->LogFile->FileName);
1560 }
1561
1562 LogfFreeRecord(logBuffer);
1563 }