[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 SYSTEMTIME st;
874 EVENTLOGEOF EofRec;
875 PEVENTLOGRECORD RecBuf;
876 LARGE_INTEGER logFileSize;
877 ULONG RecOffSet;
878 ULONG WriteOffSet;
879
880 if (!Buffer)
881 return FALSE;
882
883 GetSystemTime(&st);
884 SystemTimeToEventTime(&st, &((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 WORD wType,
1129 WORD wCategory,
1130 DWORD dwEventId,
1131 LPCWSTR SourceName,
1132 LPCWSTR ComputerName,
1133 DWORD dwSidLength,
1134 PSID lpUserSid,
1135 WORD wNumStrings,
1136 WCHAR * lpStrings,
1137 DWORD dwDataSize,
1138 LPVOID lpRawData)
1139 {
1140 DWORD dwRecSize;
1141 PEVENTLOGRECORD pRec;
1142 SYSTEMTIME SysTime;
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 % 4 != 0)
1152 dwRecSize += 4 - (dwRecSize % 4);
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 % 4 != 0)
1164 dwRecSize += 4 - (dwRecSize % 4);
1165
1166 dwRecSize += 4;
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 GetSystemTime(&SysTime);
1182 SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
1183 SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
1184
1185 pRec->EventID = dwEventId;
1186 pRec->EventType = wType;
1187 pRec->EventCategory = wCategory;
1188
1189 pos = sizeof(EVENTLOGRECORD);
1190
1191 lstrcpyW((WCHAR *) (Buffer + pos), SourceName);
1192 pos += (lstrlenW(SourceName) + 1) * sizeof(WCHAR);
1193 lstrcpyW((WCHAR *) (Buffer + pos), ComputerName);
1194 pos += (lstrlenW(ComputerName) + 1) * sizeof(WCHAR);
1195
1196 pRec->UserSidOffset = pos;
1197
1198 if (pos % 4 != 0)
1199 pos += 4 - (pos % 4);
1200
1201 if (dwSidLength)
1202 {
1203 CopyMemory(Buffer + pos, lpUserSid, dwSidLength);
1204 pRec->UserSidLength = dwSidLength;
1205 pRec->UserSidOffset = pos;
1206 pos += dwSidLength;
1207 }
1208
1209 pRec->StringOffset = pos;
1210 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1211 {
1212 lstrcpyW((WCHAR *) (Buffer + pos), str);
1213 pos += (lstrlenW(str) + 1) * sizeof(WCHAR);
1214 str += lstrlenW(str) + 1;
1215 }
1216 pRec->NumStrings = wNumStrings;
1217
1218 pRec->DataOffset = pos;
1219 if (dwDataSize)
1220 {
1221 pRec->DataLength = dwDataSize;
1222 CopyMemory(Buffer + pos, lpRawData, dwDataSize);
1223 pos += dwDataSize;
1224 }
1225
1226 if (pos % 4 != 0)
1227 pos += 4 - (pos % 4);
1228
1229 *((PDWORD) (Buffer + pos)) = dwRecSize;
1230
1231 *lpRecSize = dwRecSize;
1232 return Buffer;
1233 }
1234
1235
1236 VOID
1237 LogfReportEvent(WORD wType,
1238 WORD wCategory,
1239 DWORD dwEventId,
1240 WORD wNumStrings,
1241 WCHAR *lpStrings,
1242 DWORD dwDataSize,
1243 LPVOID lpRawData)
1244 {
1245 WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1246 DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
1247 PEVENTSOURCE pEventSource = NULL;
1248 PBYTE logBuffer;
1249 DWORD lastRec;
1250 DWORD recSize;
1251 DWORD dwError;
1252
1253 if (!GetComputerNameW(szComputerName, &dwComputerNameLength))
1254 {
1255 szComputerName[0] = 0;
1256 }
1257
1258 pEventSource = GetEventSourceByName(L"EventLog");
1259 if (pEventSource == NULL)
1260 {
1261 return;
1262 }
1263
1264 lastRec = LogfGetCurrentRecord(pEventSource->LogFile);
1265
1266 logBuffer = LogfAllocAndBuildNewRecord(&recSize,
1267 lastRec,
1268 wType,
1269 wCategory,
1270 dwEventId,
1271 pEventSource->szName,
1272 (LPCWSTR)szComputerName,
1273 0,
1274 NULL,
1275 wNumStrings,
1276 lpStrings,
1277 dwDataSize,
1278 lpRawData);
1279
1280 dwError = LogfWriteData(pEventSource->LogFile, recSize, logBuffer);
1281 if (!dwError)
1282 {
1283 DPRINT1("ERROR WRITING TO EventLog %S\n", pEventSource->LogFile->FileName);
1284 }
1285
1286 LogfFreeRecord(logBuffer);
1287 }