30d935e05de53b0d6764326b2fe3f8eb0b694ac6
[reactos.git] / reactos / 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 BOOL LogfInitializeNew(PLOGFILE LogFile)
22 {
23 DWORD dwWritten;
24 EVENTLOGEOF EofRec;
25
26 ZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
27 SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
28 SetEndOfFile(LogFile->hFile);
29
30 LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
31 LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
32 LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
33 LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
34 LogFile->Header.MajorVersion = MAJORVER;
35 LogFile->Header.MinorVersion = MINORVER;
36 LogFile->Header.CurrentRecordNumber = 1;
37 LogFile->Header.OldestRecordNumber = 1;
38 /* FIXME: Read MaxSize from registry for this LogFile.
39 But for now limit EventLog size to just under 5K. */
40 LogFile->Header.MaxSize = 5000;
41 LogFile->Header.Signature = LOGFILE_SIGNATURE;
42 if (!WriteFile(LogFile->hFile,
43 &LogFile->Header,
44 sizeof(EVENTLOGHEADER),
45 &dwWritten,
46 NULL))
47 {
48 DPRINT1("WriteFile failed:%d!\n", GetLastError());
49 return FALSE;
50 }
51
52 EofRec.Ones = 0x11111111;
53 EofRec.Twos = 0x22222222;
54 EofRec.Threes = 0x33333333;
55 EofRec.Fours = 0x44444444;
56 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
57 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
58 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
59 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
60 EofRec.BeginRecord = LogFile->Header.StartOffset;
61 EofRec.EndRecord = LogFile->Header.EndOffset;
62
63 if (!WriteFile(LogFile->hFile,
64 &EofRec,
65 sizeof(EVENTLOGEOF),
66 &dwWritten,
67 NULL))
68 {
69 DPRINT1("WriteFile failed:%d!\n", GetLastError());
70 return FALSE;
71 }
72
73 if (!FlushFileBuffers(LogFile->hFile))
74 {
75 DPRINT1("FlushFileBuffers failed:%d!\n", GetLastError());
76 return FALSE;
77 }
78
79 return TRUE;
80 }
81
82 BOOL LogfInitializeExisting(PLOGFILE LogFile)
83 {
84 DWORD dwRead;
85 DWORD dwRecordsNumber = 0;
86 DWORD dwRecSize, dwRecSign, dwFilePointer;
87 PDWORD pdwRecSize2;
88 PEVENTLOGRECORD RecBuf;
89 BOOL OvewrWrittenRecords = FALSE;
90
91 DPRINT("Initializing LogFile %S\n",LogFile->LogName);
92
93 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
94 INVALID_SET_FILE_POINTER)
95 {
96 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
97 return FALSE;
98 }
99
100 if (!ReadFile(LogFile->hFile,
101 &LogFile->Header,
102 sizeof(EVENTLOGHEADER),
103 &dwRead,
104 NULL))
105 {
106 DPRINT1("ReadFile failed! %d\n", GetLastError());
107 return FALSE;
108 }
109
110 if (dwRead != sizeof(EVENTLOGHEADER))
111 {
112 DPRINT("EventLog: Invalid file %S.\n", LogFile->FileName);
113 return LogfInitializeNew(LogFile);
114 }
115
116 if (LogFile->Header.HeaderSize != sizeof(EVENTLOGHEADER) ||
117 LogFile->Header.EndHeaderSize != sizeof(EVENTLOGHEADER))
118 {
119 DPRINT("EventLog: Invalid header size in %S.\n", LogFile->FileName);
120 return LogfInitializeNew(LogFile);
121 }
122
123 if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
124 {
125 DPRINT("EventLog: Invalid signature %x in %S.\n",
126 LogFile->Header.Signature, LogFile->FileName);
127 return LogfInitializeNew(LogFile);
128 }
129
130 if (LogFile->Header.EndOffset > GetFileSize(LogFile->hFile, NULL) + 1)
131 {
132 DPRINT("EventLog: Invalid eof offset %x in %S.\n",
133 LogFile->Header.EndOffset, LogFile->FileName);
134 return LogfInitializeNew(LogFile);
135 }
136
137 /* Set the read location to the oldest record */
138 dwFilePointer = SetFilePointer(LogFile->hFile, LogFile->Header.StartOffset, NULL, FILE_BEGIN);
139 if (dwFilePointer == INVALID_SET_FILE_POINTER)
140 {
141 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
142 return FALSE;
143 }
144
145 for (;;)
146 {
147 dwFilePointer = SetFilePointer(LogFile->hFile, 0, NULL, FILE_CURRENT);
148
149 if (dwFilePointer == INVALID_SET_FILE_POINTER)
150 {
151 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
152 return FALSE;
153 }
154
155 /* If the EVENTLOGEOF info has been reached and the oldest record was not immediately after the Header */
156 if ((dwFilePointer == LogFile->Header.EndOffset) && (LogFile->Header.StartOffset != sizeof(EVENTLOGHEADER)))
157 {
158 OvewrWrittenRecords = TRUE;
159 /* The file has records that overwrote old ones so read them */
160 dwFilePointer = SetFilePointer(LogFile->hFile, sizeof(EVENTLOGHEADER), NULL, FILE_BEGIN);
161 }
162
163 if (!ReadFile(LogFile->hFile,
164 &dwRecSize,
165 sizeof(dwRecSize),
166 &dwRead,
167 NULL))
168 {
169 DPRINT1("ReadFile failed! %d\n", GetLastError());
170 return FALSE;
171 }
172
173 if (dwRead != sizeof(dwRecSize))
174 break;
175
176 if (!ReadFile(LogFile->hFile,
177 &dwRecSign,
178 sizeof(dwRecSign),
179 &dwRead,
180 NULL))
181 {
182 DPRINT1("ReadFile() failed! %d\n", GetLastError());
183 return FALSE;
184 }
185
186 if (dwRead != sizeof(dwRecSize))
187 break;
188
189 if (dwRecSign != LOGFILE_SIGNATURE ||
190 dwRecSize + dwFilePointer > GetFileSize(LogFile->hFile, NULL) + 1 ||
191 dwRecSize < sizeof(EVENTLOGRECORD))
192 {
193 break;
194 }
195
196 if (SetFilePointer(LogFile->hFile,
197 -((LONG) sizeof(DWORD) * 2),
198 NULL,
199 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
200 {
201 DPRINT1("SetFilePointer() failed! %d", GetLastError());
202 return FALSE;
203 }
204
205 RecBuf = (PEVENTLOGRECORD) HeapAlloc(MyHeap, 0, dwRecSize);
206
207 if (!RecBuf)
208 {
209 DPRINT1("Can't allocate heap!\n");
210 return FALSE;
211 }
212
213 if (!ReadFile(LogFile->hFile, RecBuf, dwRecSize, &dwRead, NULL))
214 {
215 DPRINT1("ReadFile() failed! %d\n", GetLastError());
216 HeapFree(MyHeap, 0, RecBuf);
217 return FALSE;
218 }
219
220 if (dwRead != dwRecSize)
221 {
222 HeapFree(MyHeap, 0, RecBuf);
223 break;
224 }
225
226 /* if OvewrWrittenRecords is TRUE and this record has already been read */
227 if ((OvewrWrittenRecords == TRUE) && (RecBuf->RecordNumber == LogFile->Header.OldestRecordNumber))
228 {
229 HeapFree(MyHeap, 0, RecBuf);
230 break;
231 }
232
233 pdwRecSize2 = (PDWORD) (((PBYTE) RecBuf) + dwRecSize - 4);
234
235 if (*pdwRecSize2 != dwRecSize)
236 {
237 DPRINT1("Invalid RecordSizeEnd of record %d (%x) in %S\n",
238 dwRecordsNumber, *pdwRecSize2, LogFile->LogName);
239 HeapFree(MyHeap, 0, RecBuf);
240 break;
241 }
242
243 dwRecordsNumber++;
244
245 if (!LogfAddOffsetInformation(LogFile,
246 RecBuf->RecordNumber,
247 dwFilePointer))
248 {
249 DPRINT1("LogfAddOffsetInformation() failed!\n");
250 HeapFree(MyHeap, 0, RecBuf);
251 return FALSE;
252 }
253
254 HeapFree(MyHeap, 0, RecBuf);
255 }
256
257 LogFile->Header.CurrentRecordNumber = dwRecordsNumber + LogFile->Header.OldestRecordNumber;
258 if (LogFile->Header.CurrentRecordNumber == 0)
259 LogFile->Header.CurrentRecordNumber = 1;
260
261 /* FIXME: Read MaxSize from registry for this LogFile.
262 But for now limit EventLog size to just under 5K. */
263 LogFile->Header.MaxSize = 5000;
264
265 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
266 INVALID_SET_FILE_POINTER)
267 {
268 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
269 return FALSE;
270 }
271
272 if (!WriteFile(LogFile->hFile,
273 &LogFile->Header,
274 sizeof(EVENTLOGHEADER),
275 &dwRead,
276 NULL))
277 {
278 DPRINT1("WriteFile failed! %d\n", GetLastError());
279 return FALSE;
280 }
281
282 if (!FlushFileBuffers(LogFile->hFile))
283 {
284 DPRINT1("FlushFileBuffers failed! %d\n", GetLastError());
285 return FALSE;
286 }
287
288 return TRUE;
289 }
290
291
292 NTSTATUS
293 LogfCreate(PLOGFILE *LogFile,
294 WCHAR * LogName,
295 PUNICODE_STRING FileName,
296 BOOL Permanent,
297 BOOL Backup)
298 {
299 OBJECT_ATTRIBUTES ObjectAttributes;
300 IO_STATUS_BLOCK IoStatusBlock;
301 PLOGFILE pLogFile;
302 BOOL bResult, bCreateNew = FALSE;
303 NTSTATUS Status = STATUS_SUCCESS;
304
305 pLogFile = (LOGFILE *) HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, sizeof(LOGFILE));
306 if (!pLogFile)
307 {
308 DPRINT1("Can't allocate heap!\n");
309 return STATUS_NO_MEMORY;
310 }
311
312 InitializeObjectAttributes(&ObjectAttributes,
313 FileName,
314 OBJ_CASE_INSENSITIVE,
315 NULL,
316 NULL);
317
318 Status = NtCreateFile(&pLogFile->hFile,
319 Backup ? (GENERIC_READ | SYNCHRONIZE) : (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE),
320 &ObjectAttributes,
321 &IoStatusBlock,
322 NULL,
323 FILE_ATTRIBUTE_NORMAL,
324 FILE_SHARE_READ,
325 Backup ? FILE_OPEN : FILE_OPEN_IF,
326 FILE_SYNCHRONOUS_IO_NONALERT,
327 NULL,
328 0);
329 if (!NT_SUCCESS(Status))
330 {
331 DPRINT1("Can't create file %wZ (Status: 0x%08lx)\n", FileName, Status);
332 goto fail;
333 }
334
335 bCreateNew = (IoStatusBlock.Information == FILE_CREATED) ? TRUE: FALSE;
336
337 pLogFile->LogName =
338 (WCHAR *) HeapAlloc(MyHeap,
339 HEAP_ZERO_MEMORY,
340 (lstrlenW(LogName) + 1) * sizeof(WCHAR));
341 if (pLogFile->LogName == NULL)
342 {
343 DPRINT1("Can't allocate heap\n");
344 Status = STATUS_NO_MEMORY;
345 goto fail;
346 }
347
348 lstrcpyW(pLogFile->LogName, LogName);
349
350 pLogFile->FileName =
351 (WCHAR *) HeapAlloc(MyHeap,
352 HEAP_ZERO_MEMORY,
353 (lstrlenW(FileName->Buffer) + 1) * sizeof(WCHAR));
354 if (pLogFile->FileName == NULL)
355 {
356 DPRINT1("Can't allocate heap\n");
357 Status = STATUS_NO_MEMORY;
358 goto fail;
359 }
360
361 lstrcpyW(pLogFile->FileName, FileName->Buffer);
362
363 pLogFile->OffsetInfo =
364 (PEVENT_OFFSET_INFO) HeapAlloc(MyHeap,
365 HEAP_ZERO_MEMORY,
366 sizeof(EVENT_OFFSET_INFO) * 64);
367 if (pLogFile->OffsetInfo == NULL)
368 {
369 DPRINT1("Can't allocate heap\n");
370 Status = STATUS_NO_MEMORY;
371 goto fail;
372 }
373
374 pLogFile->OffsetInfoSize = 64;
375
376 pLogFile->Permanent = Permanent;
377
378 if (bCreateNew)
379 bResult = LogfInitializeNew(pLogFile);
380 else
381 bResult = LogfInitializeExisting(pLogFile);
382
383 if (!bResult)
384 {
385 Status = STATUS_UNSUCCESSFUL;
386 goto fail;
387 }
388
389 RtlInitializeResource(&pLogFile->Lock);
390
391 LogfListAddItem(pLogFile);
392
393 fail:
394 if (!NT_SUCCESS(Status))
395 {
396 if ((pLogFile->hFile != NULL) && (pLogFile->hFile != INVALID_HANDLE_VALUE))
397 CloseHandle(pLogFile->hFile);
398
399 if (pLogFile->OffsetInfo)
400 HeapFree(MyHeap, 0, pLogFile->OffsetInfo);
401
402 if (pLogFile->FileName)
403 HeapFree(MyHeap, 0, pLogFile->FileName);
404
405 if (pLogFile->LogName)
406 HeapFree(MyHeap, 0, pLogFile->LogName);
407
408 HeapFree(MyHeap, 0, pLogFile);
409 }
410 else
411 {
412 *LogFile = pLogFile;
413 }
414
415 return Status;
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 }