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