Sync with trunk revision 64099.
[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 if(LogName)
359 StringCchCopy(pLogFile->LogName,lstrlenW(LogName) + 1, LogName);
360
361 pLogFile->FileName =
362 (WCHAR *) HeapAlloc(MyHeap,
363 HEAP_ZERO_MEMORY,
364 (lstrlenW(FileName->Buffer) + 1) * sizeof(WCHAR));
365 if (pLogFile->FileName == NULL)
366 {
367 DPRINT1("Can't allocate heap\n");
368 Status = STATUS_NO_MEMORY;
369 goto fail;
370 }
371
372 StringCchCopy(pLogFile->FileName, lstrlenW(FileName->Buffer) + 1, FileName->Buffer);
373
374 pLogFile->OffsetInfo =
375 (PEVENT_OFFSET_INFO) HeapAlloc(MyHeap,
376 HEAP_ZERO_MEMORY,
377 sizeof(EVENT_OFFSET_INFO) * 64);
378 if (pLogFile->OffsetInfo == NULL)
379 {
380 DPRINT1("Can't allocate heap\n");
381 Status = STATUS_NO_MEMORY;
382 goto fail;
383 }
384
385 pLogFile->OffsetInfoSize = 64;
386
387 pLogFile->Permanent = Permanent;
388
389 if (bCreateNew)
390 Status = LogfInitializeNew(pLogFile);
391 else
392 Status = LogfInitializeExisting(pLogFile, Backup);
393
394 if (!NT_SUCCESS(Status))
395 goto fail;
396
397 RtlInitializeResource(&pLogFile->Lock);
398
399 LogfListAddItem(pLogFile);
400
401 fail:
402 if (!NT_SUCCESS(Status))
403 {
404 if ((pLogFile->hFile != NULL) && (pLogFile->hFile != INVALID_HANDLE_VALUE))
405 CloseHandle(pLogFile->hFile);
406
407 if (pLogFile->OffsetInfo)
408 HeapFree(MyHeap, 0, pLogFile->OffsetInfo);
409
410 if (pLogFile->FileName)
411 HeapFree(MyHeap, 0, pLogFile->FileName);
412
413 if (pLogFile->LogName)
414 HeapFree(MyHeap, 0, pLogFile->LogName);
415
416 HeapFree(MyHeap, 0, pLogFile);
417 }
418 else
419 {
420 *LogFile = pLogFile;
421 }
422
423 return Status;
424 }
425
426
427 VOID
428 LogfClose(PLOGFILE LogFile,
429 BOOL ForceClose)
430 {
431 if (LogFile == NULL)
432 return;
433
434 if ((ForceClose == FALSE) &&
435 (LogFile->Permanent == TRUE))
436 return;
437
438 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
439
440 FlushFileBuffers(LogFile->hFile);
441 CloseHandle(LogFile->hFile);
442 LogfListRemoveItem(LogFile);
443
444 RtlDeleteResource(&LogFile->Lock);
445
446 HeapFree(MyHeap, 0, LogFile->LogName);
447 HeapFree(MyHeap, 0, LogFile->FileName);
448 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
449 HeapFree(MyHeap, 0, LogFile);
450
451 return;
452 }
453
454 VOID LogfCloseAll(VOID)
455 {
456 while (!IsListEmpty(&LogFileListHead))
457 {
458 LogfClose(LogfListHead(), TRUE);
459 }
460
461 DeleteCriticalSection(&LogFileListCs);
462 }
463
464 VOID LogfListInitialize(VOID)
465 {
466 InitializeCriticalSection(&LogFileListCs);
467 InitializeListHead(&LogFileListHead);
468 }
469
470 PLOGFILE LogfListHead(VOID)
471 {
472 return CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry);
473 }
474
475 PLOGFILE LogfListItemByName(WCHAR * Name)
476 {
477 PLIST_ENTRY CurrentEntry;
478 PLOGFILE Result = NULL;
479
480 EnterCriticalSection(&LogFileListCs);
481
482 CurrentEntry = LogFileListHead.Flink;
483 while (CurrentEntry != &LogFileListHead)
484 {
485 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
486 LOGFILE,
487 ListEntry);
488
489 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
490 {
491 Result = Item;
492 break;
493 }
494
495 CurrentEntry = CurrentEntry->Flink;
496 }
497
498 LeaveCriticalSection(&LogFileListCs);
499 return Result;
500 }
501
502 /* Index starting from 1 */
503 INT LogfListItemIndexByName(WCHAR * Name)
504 {
505 PLIST_ENTRY CurrentEntry;
506 INT Result = 0;
507 INT i = 1;
508
509 EnterCriticalSection(&LogFileListCs);
510
511 CurrentEntry = LogFileListHead.Flink;
512 while (CurrentEntry != &LogFileListHead)
513 {
514 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
515 LOGFILE,
516 ListEntry);
517
518 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
519 {
520 Result = i;
521 break;
522 }
523
524 CurrentEntry = CurrentEntry->Flink;
525 i++;
526 }
527
528 LeaveCriticalSection(&LogFileListCs);
529 return Result;
530 }
531
532 /* Index starting from 1 */
533 PLOGFILE LogfListItemByIndex(INT Index)
534 {
535 PLIST_ENTRY CurrentEntry;
536 PLOGFILE Result = NULL;
537 INT i = 1;
538
539 EnterCriticalSection(&LogFileListCs);
540
541 CurrentEntry = LogFileListHead.Flink;
542 while (CurrentEntry != &LogFileListHead)
543 {
544 if (i == Index)
545 {
546 Result = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
547 break;
548 }
549
550 CurrentEntry = CurrentEntry->Flink;
551 i++;
552 }
553
554 LeaveCriticalSection(&LogFileListCs);
555 return Result;
556 }
557
558 INT LogfListItemCount(VOID)
559 {
560 PLIST_ENTRY CurrentEntry;
561 INT i = 0;
562
563 EnterCriticalSection(&LogFileListCs);
564
565 CurrentEntry = LogFileListHead.Flink;
566 while (CurrentEntry != &LogFileListHead)
567 {
568 CurrentEntry = CurrentEntry->Flink;
569 i++;
570 }
571
572 LeaveCriticalSection(&LogFileListCs);
573 return i;
574 }
575
576 VOID LogfListAddItem(PLOGFILE Item)
577 {
578 EnterCriticalSection(&LogFileListCs);
579 InsertTailList(&LogFileListHead, &Item->ListEntry);
580 LeaveCriticalSection(&LogFileListCs);
581 }
582
583 VOID LogfListRemoveItem(PLOGFILE Item)
584 {
585 EnterCriticalSection(&LogFileListCs);
586 RemoveEntryList(&Item->ListEntry);
587 LeaveCriticalSection(&LogFileListCs);
588 }
589
590 static BOOL
591 ReadAnsiLogEntry(HANDLE hFile,
592 LPVOID lpBuffer,
593 DWORD nNumberOfBytesToRead,
594 LPDWORD lpNumberOfBytesRead)
595 {
596 PEVENTLOGRECORD Dst;
597 PEVENTLOGRECORD Src;
598 ANSI_STRING StringA;
599 UNICODE_STRING StringW;
600 LPWSTR SrcPtr;
601 LPSTR DstPtr;
602 LPWSTR SrcString;
603 LPSTR DstString;
604 LPVOID lpUnicodeBuffer = NULL;
605 DWORD dwRead = 0;
606 DWORD i;
607 DWORD dwPadding;
608 DWORD dwEntryLength;
609 PDWORD pLength;
610 NTSTATUS Status;
611 BOOL ret = TRUE;
612
613 *lpNumberOfBytesRead = 0;
614
615 lpUnicodeBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nNumberOfBytesToRead);
616 if (lpUnicodeBuffer == NULL)
617 {
618 DPRINT1("Alloc failed!\n");
619 return FALSE;
620 }
621
622 if (!ReadFile(hFile, lpUnicodeBuffer, nNumberOfBytesToRead, &dwRead, NULL))
623 {
624 DPRINT1("Read failed!\n");
625 ret = FALSE;
626 goto done;
627 }
628
629 Dst = (PEVENTLOGRECORD)lpBuffer;
630 Src = (PEVENTLOGRECORD)lpUnicodeBuffer;
631
632 Dst->TimeGenerated = Src->TimeGenerated;
633 Dst->Reserved = Src->Reserved;
634 Dst->RecordNumber = Src->RecordNumber;
635 Dst->TimeWritten = Src->TimeWritten;
636 Dst->EventID = Src->EventID;
637 Dst->EventType = Src->EventType;
638 Dst->EventCategory = Src->EventCategory;
639 Dst->NumStrings = Src->NumStrings;
640 Dst->UserSidLength = Src->UserSidLength;
641 Dst->DataLength = Src->DataLength;
642
643 SrcPtr = (LPWSTR)((DWORD_PTR)Src + sizeof(EVENTLOGRECORD));
644 DstPtr = (LPSTR)((DWORD_PTR)Dst + sizeof(EVENTLOGRECORD));
645
646 /* Convert the module name */
647 RtlInitUnicodeString(&StringW, SrcPtr);
648 Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
649 if (NT_SUCCESS(Status))
650 {
651 RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
652
653 DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
654
655 RtlFreeAnsiString(&StringA);
656 }
657
658 /* Convert the computer name */
659 if (NT_SUCCESS(Status))
660 {
661 SrcPtr = (PWSTR)((DWORD_PTR)SrcPtr + StringW.MaximumLength);
662
663 RtlInitUnicodeString(&StringW, SrcPtr);
664 Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
665 if (NT_SUCCESS(Status))
666 {
667 RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
668
669 DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
670
671 RtlFreeAnsiString(&StringA);
672 }
673 }
674
675 /* Add the padding and the User SID*/
676 if (NT_SUCCESS(Status))
677 {
678 dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr - (DWORD_PTR)Dst) % sizeof(DWORD));
679 RtlZeroMemory(DstPtr, dwPadding);
680
681 DstPtr = (LPSTR)((DWORD_PTR)DstPtr + dwPadding);
682 RtlCopyMemory(DstPtr,
683 (PVOID)((DWORD_PTR)Src + Src->UserSidOffset),
684 Src->UserSidLength);
685
686 Dst->UserSidOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
687 }
688
689
690 /* Convert the strings */
691 if (NT_SUCCESS(Status))
692 {
693 DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->UserSidLength);
694
695 SrcString = (LPWSTR)((DWORD_PTR)Src + (DWORD)Src->StringOffset);
696 DstString = (LPSTR)DstPtr;
697
698 for (i = 0; i < Dst->NumStrings; i++)
699 {
700 RtlInitUnicodeString(&StringW, SrcString);
701
702 RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
703
704 RtlCopyMemory(DstString, StringA.Buffer, StringA.MaximumLength);
705
706 SrcString = (LPWSTR)((DWORD_PTR)SrcString +
707 (DWORD)StringW.MaximumLength);
708
709 DstString = (LPSTR)((DWORD_PTR)DstString +
710 (DWORD)StringA.MaximumLength);
711
712 RtlFreeAnsiString(&StringA);
713 }
714
715 Dst->StringOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
716
717
718 /* Copy the binary data */
719 DstPtr = (PVOID)DstString;
720 Dst->DataOffset = (DWORD_PTR)DstPtr - (DWORD_PTR)Dst;
721
722 RtlCopyMemory(DstPtr, (PVOID)((DWORD_PTR)Src + Src->DataOffset), Src->DataLength);
723
724 /* Add the padding */
725 DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->DataLength);
726 dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr-(DWORD_PTR)Dst) % sizeof(DWORD));
727 RtlZeroMemory(DstPtr, dwPadding);
728
729 dwEntryLength = (DWORD)((DWORD_PTR)DstPtr + dwPadding + sizeof(DWORD) - (DWORD_PTR)Dst);
730
731 /* Set the entry length at the end of the entry*/
732 pLength = (PDWORD)((DWORD_PTR)DstPtr + dwPadding);
733 *pLength = dwEntryLength;
734 Dst->Length = dwEntryLength;
735
736 *lpNumberOfBytesRead = dwEntryLength;
737 }
738
739 done:
740 if (lpUnicodeBuffer != NULL)
741 HeapFree(GetProcessHeap(), 0, lpUnicodeBuffer);
742
743 return ret;
744 }
745
746
747 DWORD LogfReadEvent(PLOGFILE LogFile,
748 DWORD Flags,
749 DWORD * RecordNumber,
750 DWORD BufSize,
751 PBYTE Buffer,
752 DWORD * BytesRead,
753 DWORD * BytesNeeded,
754 BOOL Ansi)
755 {
756 DWORD dwOffset, dwRead, dwRecSize;
757 DWORD dwBufferUsage = 0, dwRecNum;
758
759 if (Flags & EVENTLOG_FORWARDS_READ && Flags & EVENTLOG_BACKWARDS_READ)
760 return ERROR_INVALID_PARAMETER;
761
762 if (!(Flags & EVENTLOG_FORWARDS_READ) && !(Flags & EVENTLOG_BACKWARDS_READ))
763 return ERROR_INVALID_PARAMETER;
764
765 if (!Buffer || !BytesRead || !BytesNeeded)
766 return ERROR_INVALID_PARAMETER;
767
768 if ((*RecordNumber==0) && !(EVENTLOG_SEQUENTIAL_READ))
769 {
770 return ERROR_INVALID_PARAMETER;
771 }
772
773 dwRecNum = *RecordNumber;
774
775 RtlAcquireResourceShared(&LogFile->Lock, TRUE);
776
777 *BytesRead = 0;
778 *BytesNeeded = 0;
779
780 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
781
782 if (!dwOffset)
783 {
784 RtlReleaseResource(&LogFile->Lock);
785 return ERROR_HANDLE_EOF;
786 }
787
788 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
789 INVALID_SET_FILE_POINTER)
790 {
791 DPRINT1("SetFilePointer() failed!\n");
792 goto Done;
793 }
794
795 if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
796 {
797 DPRINT1("ReadFile() failed!\n");
798 goto Done;
799 }
800
801 if (dwRecSize > BufSize)
802 {
803 *BytesNeeded = dwRecSize;
804 RtlReleaseResource(&LogFile->Lock);
805 return ERROR_INSUFFICIENT_BUFFER;
806 }
807
808 if (SetFilePointer(LogFile->hFile,
809 -((LONG) sizeof(DWORD)),
810 NULL,
811 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
812 {
813 DPRINT1("SetFilePointer() failed!\n");
814 goto Done;
815 }
816
817 if (Ansi == TRUE)
818 {
819 if (!ReadAnsiLogEntry(LogFile->hFile, Buffer, dwRecSize, &dwRead))
820 {
821 DPRINT1("ReadAnsiLogEntry() failed!\n");
822 goto Done;
823 }
824 }
825 else
826 {
827 if (!ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL))
828 {
829 DPRINT1("ReadFile() failed!\n");
830 goto Done;
831 }
832 }
833
834 dwBufferUsage += dwRead;
835
836 while (dwBufferUsage <= BufSize)
837 {
838 if (Flags & EVENTLOG_FORWARDS_READ)
839 dwRecNum++;
840 else
841 dwRecNum--;
842
843 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
844 if (!dwOffset)
845 break;
846
847 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
848 INVALID_SET_FILE_POINTER)
849 {
850 DPRINT1("SetFilePointer() failed!\n");
851 goto Done;
852 }
853
854 if (!ReadFile(LogFile->hFile,
855 &dwRecSize,
856 sizeof(DWORD),
857 &dwRead,
858 NULL))
859 {
860 DPRINT1("ReadFile() failed!\n");
861 goto Done;
862 }
863
864 if (dwBufferUsage + dwRecSize > BufSize)
865 break;
866
867 if (SetFilePointer(LogFile->hFile,
868 -((LONG) sizeof(DWORD)),
869 NULL,
870 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
871 {
872 DPRINT1("SetFilePointer() failed!\n");
873 goto Done;
874 }
875
876 if (Ansi == TRUE)
877 {
878 if (!ReadAnsiLogEntry(LogFile->hFile,
879 Buffer + dwBufferUsage,
880 dwRecSize,
881 &dwRead))
882 {
883 DPRINT1("ReadAnsiLogEntry() failed!\n");
884 goto Done;
885 }
886 }
887 else
888 {
889 if (!ReadFile(LogFile->hFile,
890 Buffer + dwBufferUsage,
891 dwRecSize,
892 &dwRead,
893 NULL))
894 {
895 DPRINT1("ReadFile() failed!\n");
896 goto Done;
897 }
898 }
899
900 dwBufferUsage += dwRead;
901 }
902
903 *BytesRead = dwBufferUsage;
904 * RecordNumber = dwRecNum;
905 RtlReleaseResource(&LogFile->Lock);
906 return ERROR_SUCCESS;
907
908 Done:
909 DPRINT1("LogfReadEvent failed with %x\n",GetLastError());
910 RtlReleaseResource(&LogFile->Lock);
911 return GetLastError();
912 }
913
914 BOOL LogfWriteData(PLOGFILE LogFile, DWORD BufSize, PBYTE Buffer)
915 {
916 DWORD dwWritten;
917 DWORD dwRead;
918 SYSTEMTIME st;
919 EVENTLOGEOF EofRec;
920 PEVENTLOGRECORD RecBuf;
921 LARGE_INTEGER logFileSize;
922 ULONG RecOffSet;
923 ULONG WriteOffSet;
924
925 if (!Buffer)
926 return FALSE;
927
928 GetSystemTime(&st);
929 SystemTimeToEventTime(&st, &((PEVENTLOGRECORD) Buffer)->TimeWritten);
930
931 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
932
933 if (!GetFileSizeEx(LogFile->hFile, &logFileSize))
934 {
935 RtlReleaseResource(&LogFile->Lock);
936 return FALSE;
937 }
938
939 /* If the size of the file is over MaxSize */
940 if ((logFileSize.QuadPart + BufSize)> LogFile->Header.MaxSize)
941 {
942 ULONG OverWriteLength = 0;
943 WriteOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
944 RecBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EVENTLOGRECORD));
945 /* Determine how many records need to be overwritten */
946 while (TRUE)
947 {
948 DPRINT("EventLogFile has reached maximume size\n");
949
950 if (!RecBuf)
951 {
952 DPRINT1("Failed to allocate buffer for OldestRecord!\n");
953 HeapFree(GetProcessHeap(), 0, RecBuf);
954 RtlReleaseResource(&LogFile->Lock);
955 return FALSE;
956 }
957
958 /* Get the oldest record data */
959 RecOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
960
961 if (SetFilePointer(LogFile->hFile,
962 RecOffSet,
963 NULL,
964 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
965 {
966 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
967 HeapFree(GetProcessHeap(), 0, RecBuf);
968 RtlReleaseResource(&LogFile->Lock);
969 return FALSE;
970 }
971
972 if (!ReadFile(LogFile->hFile, RecBuf, sizeof(EVENTLOGRECORD), &dwRead, NULL))
973 {
974 DPRINT1("ReadFile() failed!\n");
975 HeapFree(GetProcessHeap(), 0, RecBuf);
976 RtlReleaseResource(&LogFile->Lock);
977 return FALSE;
978 }
979
980 if (RecBuf->Reserved != LOGFILE_SIGNATURE)
981 {
982 DPRINT1("LogFile corrupt!\n");
983 HeapFree(GetProcessHeap(), 0, RecBuf);
984 RtlReleaseResource(&LogFile->Lock);
985 return FALSE;
986 }
987
988 LogfDeleteOffsetInformation(LogFile,LogFile->Header.OldestRecordNumber);
989
990 LogFile->Header.OldestRecordNumber++;
991
992 OverWriteLength += RecBuf->Length;
993 /* Check the size of the record as the record adding may be larger */
994 if (OverWriteLength >= BufSize)
995 {
996 DPRINT("Record will fit. Length %d, BufSize %d\n", OverWriteLength, BufSize);
997 LogFile->Header.StartOffset = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
998 break;
999 }
1000 }
1001 HeapFree(GetProcessHeap(), 0, RecBuf);
1002 }
1003 else
1004 WriteOffSet = LogFile->Header.EndOffset;
1005
1006 if (SetFilePointer(LogFile->hFile,
1007 WriteOffSet,
1008 NULL,
1009 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1010 {
1011 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
1012 RtlReleaseResource(&LogFile->Lock);
1013 return FALSE;
1014 }
1015
1016 if (!WriteFile(LogFile->hFile, Buffer, BufSize, &dwWritten, NULL))
1017 {
1018 DPRINT1("WriteFile() failed! %d\n", GetLastError());
1019 RtlReleaseResource(&LogFile->Lock);
1020 return FALSE;
1021 }
1022
1023 if (!LogfAddOffsetInformation(LogFile,
1024 LogFile->Header.CurrentRecordNumber,
1025 WriteOffSet))
1026 {
1027 RtlReleaseResource(&LogFile->Lock);
1028 return FALSE;
1029 }
1030
1031 LogFile->Header.CurrentRecordNumber++;
1032
1033 if (WriteOffSet == LogFile->Header.EndOffset)
1034 {
1035 LogFile->Header.EndOffset += dwWritten;
1036 }
1037 if (SetFilePointer(LogFile->hFile,
1038 LogFile->Header.EndOffset,
1039 NULL,
1040 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1041 {
1042 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
1043 RtlReleaseResource(&LogFile->Lock);
1044 return FALSE;
1045 }
1046
1047 EofRec.Ones = 0x11111111;
1048 EofRec.Twos = 0x22222222;
1049 EofRec.Threes = 0x33333333;
1050 EofRec.Fours = 0x44444444;
1051 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
1052 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
1053 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1054 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1055 EofRec.BeginRecord = LogFile->Header.StartOffset;
1056 EofRec.EndRecord = LogFile->Header.EndOffset;
1057
1058 if (!WriteFile(LogFile->hFile,
1059 &EofRec,
1060 sizeof(EVENTLOGEOF),
1061 &dwWritten,
1062 NULL))
1063 {
1064 DPRINT1("WriteFile() failed! %d\n", GetLastError());
1065 RtlReleaseResource(&LogFile->Lock);
1066 return FALSE;
1067 }
1068
1069 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
1070 INVALID_SET_FILE_POINTER)
1071 {
1072 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
1073 RtlReleaseResource(&LogFile->Lock);
1074 return FALSE;
1075 }
1076
1077 if (!WriteFile(LogFile->hFile,
1078 &LogFile->Header,
1079 sizeof(EVENTLOGHEADER),
1080 &dwWritten,
1081 NULL))
1082 {
1083 DPRINT1("WriteFile failed! LastError = %d\n", GetLastError());
1084 RtlReleaseResource(&LogFile->Lock);
1085 return FALSE;
1086 }
1087
1088 if (!FlushFileBuffers(LogFile->hFile))
1089 {
1090 DPRINT1("FlushFileBuffers() failed! %d\n", GetLastError());
1091 RtlReleaseResource(&LogFile->Lock);
1092 return FALSE;
1093 }
1094
1095 RtlReleaseResource(&LogFile->Lock);
1096 return TRUE;
1097 }
1098
1099
1100 NTSTATUS
1101 LogfClearFile(PLOGFILE LogFile,
1102 PUNICODE_STRING BackupFileName)
1103 {
1104 NTSTATUS Status;
1105
1106 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
1107
1108 if (BackupFileName->Length > 0)
1109 {
1110 /* Write a backup file */
1111 Status = LogfBackupFile(LogFile,
1112 BackupFileName);
1113 if (!NT_SUCCESS(Status))
1114 {
1115 DPRINT1("LogfBackupFile failed (Status: 0x%08lx)\n", Status);
1116 return Status;
1117 }
1118 }
1119
1120 Status = LogfInitializeNew(LogFile);
1121 if (!NT_SUCCESS(Status))
1122 {
1123 DPRINT1("LogfInitializeNew failed (Status: 0x%08lx)\n", Status);
1124 }
1125
1126 RtlReleaseResource(&LogFile->Lock);
1127
1128 return Status;
1129 }
1130
1131
1132 NTSTATUS
1133 LogfBackupFile(PLOGFILE LogFile,
1134 PUNICODE_STRING BackupFileName)
1135 {
1136 OBJECT_ATTRIBUTES ObjectAttributes;
1137 IO_STATUS_BLOCK IoStatusBlock;
1138 EVENTLOGHEADER Header;
1139 EVENTLOGEOF EofRec;
1140 HANDLE FileHandle = NULL;
1141 ULONG i;
1142 LARGE_INTEGER FileOffset;
1143 NTSTATUS Status;
1144 PUCHAR Buffer = NULL;
1145
1146 DWORD dwOffset, dwRead, dwRecSize;
1147
1148 DPRINT("LogfBackupFile(%p, %wZ)\n", LogFile, BackupFileName);
1149
1150 /* Lock the log file shared */
1151 RtlAcquireResourceShared(&LogFile->Lock, TRUE);
1152
1153 InitializeObjectAttributes(&ObjectAttributes,
1154 BackupFileName,
1155 OBJ_CASE_INSENSITIVE,
1156 NULL,
1157 NULL);
1158
1159 Status = NtCreateFile(&FileHandle,
1160 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
1161 &ObjectAttributes,
1162 &IoStatusBlock,
1163 NULL,
1164 FILE_ATTRIBUTE_NORMAL,
1165 FILE_SHARE_READ,
1166 FILE_CREATE,
1167 FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
1168 NULL,
1169 0);
1170 if (!NT_SUCCESS(Status))
1171 {
1172 DPRINT("Can't create backup file %wZ (Status: 0x%08lx)\n", BackupFileName, Status);
1173 goto Done;
1174 }
1175
1176 /* Initialize the (dirty) log file header */
1177 Header.HeaderSize = sizeof(EVENTLOGHEADER);
1178 Header.Signature = LOGFILE_SIGNATURE;
1179 Header.MajorVersion = MAJORVER;
1180 Header.MinorVersion = MINORVER;
1181 Header.StartOffset = sizeof(EVENTLOGHEADER);
1182 Header.EndOffset = sizeof(EVENTLOGHEADER);
1183 Header.CurrentRecordNumber = 1;
1184 Header.OldestRecordNumber = 1;
1185 Header.MaxSize = 0;
1186 Header.Flags = ELF_LOGFILE_HEADER_DIRTY;
1187 Header.Retention = LogFile->Header.Retention;
1188 Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
1189
1190 /* Write the (dirty) log file header */
1191 Status = NtWriteFile(FileHandle,
1192 NULL,
1193 NULL,
1194 NULL,
1195 &IoStatusBlock,
1196 &Header,
1197 sizeof(EVENTLOGHEADER),
1198 NULL,
1199 NULL);
1200 if (!NT_SUCCESS(Status))
1201 {
1202 DPRINT1("Failed to write the log file header (Status: 0x%08lx)\n", Status);
1203 goto Done;
1204 }
1205
1206 for (i = LogFile->Header.OldestRecordNumber; i < LogFile->Header.CurrentRecordNumber; i++)
1207 {
1208 dwOffset = LogfOffsetByNumber(LogFile, i);
1209 if (dwOffset == 0)
1210 break;
1211
1212 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1213 {
1214 DPRINT1("SetFilePointer() failed!\n");
1215 goto Done;
1216 }
1217
1218 if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
1219 {
1220 DPRINT1("ReadFile() failed!\n");
1221 goto Done;
1222 }
1223
1224 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
1225 {
1226 DPRINT1("SetFilePointer() failed!\n");
1227 goto Done;
1228 }
1229
1230 Buffer = HeapAlloc(MyHeap, 0, dwRecSize);
1231 if (Buffer == NULL)
1232 {
1233 DPRINT1("HeapAlloc() failed!\n");
1234 goto Done;
1235 }
1236
1237 if (!ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL))
1238 {
1239 DPRINT1("ReadFile() failed!\n");
1240 goto Done;
1241 }
1242
1243 /* Write the event record */
1244 Status = NtWriteFile(FileHandle,
1245 NULL,
1246 NULL,
1247 NULL,
1248 &IoStatusBlock,
1249 Buffer,
1250 dwRecSize,
1251 NULL,
1252 NULL);
1253 if (!NT_SUCCESS(Status))
1254 {
1255 DPRINT1("NtWriteFile() failed! (Status: 0x%08lx)\n", Status);
1256 goto Done;
1257 }
1258
1259 /* Update the header information */
1260 Header.EndOffset += dwRecSize;
1261
1262 /* Free the buffer */
1263 HeapFree(MyHeap, 0, Buffer);
1264 Buffer = NULL;
1265 }
1266
1267 /* Initialize the EOF record */
1268 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
1269 EofRec.Ones = 0x11111111;
1270 EofRec.Twos = 0x22222222;
1271 EofRec.Threes = 0x33333333;
1272 EofRec.Fours = 0x44444444;
1273 EofRec.BeginRecord = sizeof(EVENTLOGHEADER);
1274 EofRec.EndRecord = Header.EndOffset;
1275 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1276 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1277 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
1278
1279 /* Write the EOF record */
1280 Status = NtWriteFile(FileHandle,
1281 NULL,
1282 NULL,
1283 NULL,
1284 &IoStatusBlock,
1285 &EofRec,
1286 sizeof(EVENTLOGEOF),
1287 NULL,
1288 NULL);
1289 if (!NT_SUCCESS(Status))
1290 {
1291 DPRINT1("NtWriteFile() failed!\n");
1292 goto Done;
1293 }
1294
1295 /* Update the header information */
1296 Header.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1297 Header.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1298 Header.MaxSize = Header.EndOffset + sizeof(EVENTLOGEOF);
1299 Header.Flags = 0;
1300
1301 /* Write the (clean) log file header */
1302 FileOffset.QuadPart = 0;
1303 Status = NtWriteFile(FileHandle,
1304 NULL,
1305 NULL,
1306 NULL,
1307 &IoStatusBlock,
1308 &Header,
1309 sizeof(EVENTLOGHEADER),
1310 &FileOffset,
1311 NULL);
1312 if (!NT_SUCCESS(Status))
1313 {
1314 DPRINT1("NtWriteFile() failed! (Status: 0x%08lx)\n", Status);
1315 }
1316
1317 Done:
1318 /* Free the buffer */
1319 if (Buffer != NULL)
1320 HeapFree(MyHeap, 0, Buffer);
1321
1322 /* Close the backup file */
1323 if (FileHandle != NULL)
1324 NtClose(FileHandle);
1325
1326 /* Unlock the log file */
1327 RtlReleaseResource(&LogFile->Lock);
1328
1329 return Status;
1330 }
1331
1332
1333 /* Returns 0 if nothing found. */
1334 ULONG LogfOffsetByNumber(PLOGFILE LogFile, DWORD RecordNumber)
1335 {
1336 DWORD i;
1337
1338 for (i = 0; i < LogFile->OffsetInfoNext; i++)
1339 {
1340 if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
1341 return LogFile->OffsetInfo[i].EventOffset;
1342 }
1343 return 0;
1344 }
1345
1346 DWORD LogfGetOldestRecord(PLOGFILE LogFile)
1347 {
1348 return LogFile->Header.OldestRecordNumber;
1349 }
1350
1351 DWORD LogfGetCurrentRecord(PLOGFILE LogFile)
1352 {
1353 return LogFile->Header.CurrentRecordNumber;
1354 }
1355
1356 BOOL LogfDeleteOffsetInformation(PLOGFILE LogFile, ULONG ulNumber)
1357 {
1358 DWORD i;
1359
1360 if (ulNumber != LogFile->OffsetInfo[0].EventNumber)
1361 {
1362 return FALSE;
1363 }
1364
1365 for (i = 0; i < LogFile->OffsetInfoNext - 1; i++)
1366 {
1367 LogFile->OffsetInfo[i].EventNumber = LogFile->OffsetInfo[i + 1].EventNumber;
1368 LogFile->OffsetInfo[i].EventOffset = LogFile->OffsetInfo[i + 1].EventOffset;
1369 }
1370 LogFile->OffsetInfoNext--;
1371 return TRUE;
1372 }
1373
1374 BOOL LogfAddOffsetInformation(PLOGFILE LogFile, ULONG ulNumber, ULONG ulOffset)
1375 {
1376 LPVOID NewOffsetInfo;
1377
1378 if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
1379 {
1380 NewOffsetInfo = HeapReAlloc(MyHeap,
1381 HEAP_ZERO_MEMORY,
1382 LogFile->OffsetInfo,
1383 (LogFile->OffsetInfoSize + 64) *
1384 sizeof(EVENT_OFFSET_INFO));
1385
1386 if (!NewOffsetInfo)
1387 {
1388 DPRINT1("Can't reallocate heap.\n");
1389 return FALSE;
1390 }
1391
1392 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO) NewOffsetInfo;
1393 LogFile->OffsetInfoSize += 64;
1394 }
1395
1396 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
1397 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
1398 LogFile->OffsetInfoNext++;
1399
1400 return TRUE;
1401 }
1402
1403 PBYTE LogfAllocAndBuildNewRecord(LPDWORD lpRecSize,
1404 DWORD dwRecordNumber,
1405 WORD wType,
1406 WORD wCategory,
1407 DWORD dwEventId,
1408 LPCWSTR SourceName,
1409 LPCWSTR ComputerName,
1410 DWORD dwSidLength,
1411 PSID lpUserSid,
1412 WORD wNumStrings,
1413 WCHAR * lpStrings,
1414 DWORD dwDataSize,
1415 LPVOID lpRawData)
1416 {
1417 DWORD dwRecSize;
1418 PEVENTLOGRECORD pRec;
1419 SYSTEMTIME SysTime;
1420 WCHAR *str;
1421 UINT i, pos;
1422 PBYTE Buffer;
1423
1424 dwRecSize =
1425 sizeof(EVENTLOGRECORD) + (lstrlenW(ComputerName) +
1426 lstrlenW(SourceName) + 2) * sizeof(WCHAR);
1427
1428 if (dwRecSize % 4 != 0)
1429 dwRecSize += 4 - (dwRecSize % 4);
1430
1431 dwRecSize += dwSidLength;
1432
1433 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1434 {
1435 dwRecSize += (lstrlenW(str) + 1) * sizeof(WCHAR);
1436 str += lstrlenW(str) + 1;
1437 }
1438
1439 dwRecSize += dwDataSize;
1440 if (dwRecSize % 4 != 0)
1441 dwRecSize += 4 - (dwRecSize % 4);
1442
1443 dwRecSize += 4;
1444
1445 Buffer = HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, dwRecSize);
1446
1447 if (!Buffer)
1448 {
1449 DPRINT1("Can't allocate heap!\n");
1450 return NULL;
1451 }
1452
1453 pRec = (PEVENTLOGRECORD) Buffer;
1454 pRec->Length = dwRecSize;
1455 pRec->Reserved = LOGFILE_SIGNATURE;
1456 pRec->RecordNumber = dwRecordNumber;
1457
1458 GetSystemTime(&SysTime);
1459 SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
1460 SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
1461
1462 pRec->EventID = dwEventId;
1463 pRec->EventType = wType;
1464 pRec->EventCategory = wCategory;
1465
1466 pos = sizeof(EVENTLOGRECORD);
1467
1468 lstrcpyW((WCHAR *) (Buffer + pos), SourceName);
1469 pos += (lstrlenW(SourceName) + 1) * sizeof(WCHAR);
1470 lstrcpyW((WCHAR *) (Buffer + pos), ComputerName);
1471 pos += (lstrlenW(ComputerName) + 1) * sizeof(WCHAR);
1472
1473 pRec->UserSidOffset = pos;
1474
1475 if (pos % 4 != 0)
1476 pos += 4 - (pos % 4);
1477
1478 if (dwSidLength)
1479 {
1480 CopyMemory(Buffer + pos, lpUserSid, dwSidLength);
1481 pRec->UserSidLength = dwSidLength;
1482 pRec->UserSidOffset = pos;
1483 pos += dwSidLength;
1484 }
1485
1486 pRec->StringOffset = pos;
1487 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1488 {
1489 lstrcpyW((WCHAR *) (Buffer + pos), str);
1490 pos += (lstrlenW(str) + 1) * sizeof(WCHAR);
1491 str += lstrlenW(str) + 1;
1492 }
1493 pRec->NumStrings = wNumStrings;
1494
1495 pRec->DataOffset = pos;
1496 if (dwDataSize)
1497 {
1498 pRec->DataLength = dwDataSize;
1499 CopyMemory(Buffer + pos, lpRawData, dwDataSize);
1500 pos += dwDataSize;
1501 }
1502
1503 if (pos % 4 != 0)
1504 pos += 4 - (pos % 4);
1505
1506 *((PDWORD) (Buffer + pos)) = dwRecSize;
1507
1508 *lpRecSize = dwRecSize;
1509 return Buffer;
1510 }
1511
1512
1513 VOID
1514 LogfReportEvent(WORD wType,
1515 WORD wCategory,
1516 DWORD dwEventId,
1517 WORD wNumStrings,
1518 WCHAR *lpStrings,
1519 DWORD dwDataSize,
1520 LPVOID lpRawData)
1521 {
1522 WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1523 DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
1524 PEVENTSOURCE pEventSource = NULL;
1525 PBYTE logBuffer;
1526 DWORD lastRec;
1527 DWORD recSize;
1528 DWORD dwError;
1529
1530 if (!GetComputerNameW(szComputerName, &dwComputerNameLength))
1531 {
1532 szComputerName[0] = 0;
1533 }
1534
1535 pEventSource = GetEventSourceByName(L"EventLog");
1536 if (pEventSource == NULL)
1537 {
1538 return;
1539 }
1540
1541 lastRec = LogfGetCurrentRecord(pEventSource->LogFile);
1542
1543 logBuffer = LogfAllocAndBuildNewRecord(&recSize,
1544 lastRec,
1545 wType,
1546 wCategory,
1547 dwEventId,
1548 pEventSource->szName,
1549 (LPCWSTR)szComputerName,
1550 0,
1551 NULL,
1552 wNumStrings,
1553 lpStrings,
1554 dwDataSize,
1555 lpRawData);
1556
1557 dwError = LogfWriteData(pEventSource->LogFile, recSize, logBuffer);
1558 if (!dwError)
1559 {
1560 DPRINT1("ERROR WRITING TO EventLog %S\n", pEventSource->LogFile->FileName);
1561 }
1562
1563 LogfFreeRecord(logBuffer);
1564 }