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