7d27b950a8d1b0a4d8cd623804f701cf3bf92fb9
[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 PLOGFILE LogfCreate(WCHAR * LogName, WCHAR * FileName)
292 {
293 PLOGFILE LogFile;
294 BOOL bResult, bCreateNew = FALSE;
295
296 LogFile = (LOGFILE *) HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, sizeof(LOGFILE));
297 if (!LogFile)
298 {
299 DPRINT1("Can't allocate heap!\n");
300 return NULL;
301 }
302
303 LogFile->hFile = CreateFile(FileName,
304 GENERIC_READ | GENERIC_WRITE,
305 FILE_SHARE_READ,
306 NULL,
307 OPEN_ALWAYS,
308 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
309 NULL);
310
311 if (LogFile->hFile == INVALID_HANDLE_VALUE)
312 {
313 DPRINT1("Can't create file %S.\n", FileName);
314 HeapFree(MyHeap, 0, LogFile);
315 return NULL;
316 }
317
318 bCreateNew = (GetLastError() == ERROR_ALREADY_EXISTS) ? FALSE : TRUE;
319
320 LogFile->LogName =
321 (WCHAR *) HeapAlloc(MyHeap,
322 HEAP_ZERO_MEMORY,
323 (lstrlenW(LogName) + 1) * sizeof(WCHAR));
324
325 if (LogFile->LogName)
326 lstrcpyW(LogFile->LogName, LogName);
327 else
328 {
329 DPRINT1("Can't allocate heap\n");
330 HeapFree(MyHeap, 0, LogFile);
331 return NULL;
332 }
333
334 LogFile->FileName =
335 (WCHAR *) HeapAlloc(MyHeap,
336 HEAP_ZERO_MEMORY,
337 (lstrlenW(FileName) + 1) * sizeof(WCHAR));
338
339 if (LogFile->FileName)
340 lstrcpyW(LogFile->FileName, FileName);
341 else
342 {
343 DPRINT1("Can't allocate heap\n");
344 goto fail;
345 }
346
347 LogFile->OffsetInfo =
348 (PEVENT_OFFSET_INFO) HeapAlloc(MyHeap,
349 HEAP_ZERO_MEMORY,
350 sizeof(EVENT_OFFSET_INFO) * 64);
351
352 if (!LogFile->OffsetInfo)
353 {
354 DPRINT1("Can't allocate heap\n");
355 goto fail;
356 }
357
358 LogFile->OffsetInfoSize = 64;
359
360 if (bCreateNew)
361 bResult = LogfInitializeNew(LogFile);
362 else
363 bResult = LogfInitializeExisting(LogFile);
364
365 if (!bResult)
366 goto fail;
367
368 RtlInitializeResource(&LogFile->Lock);
369
370 LogfListAddItem(LogFile);
371 return LogFile;
372
373 fail:
374 if (LogFile)
375 {
376 if (LogFile->OffsetInfo)
377 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
378
379 if (LogFile->FileName)
380 HeapFree(MyHeap, 0, LogFile->FileName);
381
382 if (LogFile->LogName)
383 HeapFree(MyHeap, 0, LogFile->LogName);
384
385 HeapFree(MyHeap, 0, LogFile);
386 }
387
388 return NULL;
389 }
390
391 VOID LogfClose(PLOGFILE LogFile)
392 {
393 if (LogFile == NULL)
394 return;
395
396 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
397
398 FlushFileBuffers(LogFile->hFile);
399 CloseHandle(LogFile->hFile);
400 LogfListRemoveItem(LogFile);
401
402 RtlDeleteResource(&LogFile->Lock);
403
404 HeapFree(MyHeap, 0, LogFile->LogName);
405 HeapFree(MyHeap, 0, LogFile->FileName);
406 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
407 HeapFree(MyHeap, 0, LogFile);
408
409 return;
410 }
411
412 VOID LogfCloseAll(VOID)
413 {
414 while (!IsListEmpty(&LogFileListHead))
415 {
416 LogfClose(LogfListHead());
417 }
418
419 DeleteCriticalSection(&LogFileListCs);
420 }
421
422 VOID LogfListInitialize(VOID)
423 {
424 InitializeCriticalSection(&LogFileListCs);
425 InitializeListHead(&LogFileListHead);
426 }
427
428 PLOGFILE LogfListHead(VOID)
429 {
430 return CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry);
431 }
432
433 PLOGFILE LogfListItemByName(WCHAR * Name)
434 {
435 PLIST_ENTRY CurrentEntry;
436 PLOGFILE Result = NULL;
437
438 EnterCriticalSection(&LogFileListCs);
439
440 CurrentEntry = LogFileListHead.Flink;
441 while (CurrentEntry != &LogFileListHead)
442 {
443 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
444 LOGFILE,
445 ListEntry);
446
447 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
448 {
449 Result = Item;
450 break;
451 }
452
453 CurrentEntry = CurrentEntry->Flink;
454 }
455
456 LeaveCriticalSection(&LogFileListCs);
457 return Result;
458 }
459
460 /* Index starting from 1 */
461 INT LogfListItemIndexByName(WCHAR * Name)
462 {
463 PLIST_ENTRY CurrentEntry;
464 INT Result = 0;
465 INT i = 1;
466
467 EnterCriticalSection(&LogFileListCs);
468
469 CurrentEntry = LogFileListHead.Flink;
470 while (CurrentEntry != &LogFileListHead)
471 {
472 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
473 LOGFILE,
474 ListEntry);
475
476 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
477 {
478 Result = i;
479 break;
480 }
481
482 CurrentEntry = CurrentEntry->Flink;
483 i++;
484 }
485
486 LeaveCriticalSection(&LogFileListCs);
487 return Result;
488 }
489
490 /* Index starting from 1 */
491 PLOGFILE LogfListItemByIndex(INT Index)
492 {
493 PLIST_ENTRY CurrentEntry;
494 PLOGFILE Result = NULL;
495 INT i = 1;
496
497 EnterCriticalSection(&LogFileListCs);
498
499 CurrentEntry = LogFileListHead.Flink;
500 while (CurrentEntry != &LogFileListHead)
501 {
502 if (i == Index)
503 {
504 Result = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
505 break;
506 }
507
508 CurrentEntry = CurrentEntry->Flink;
509 i++;
510 }
511
512 LeaveCriticalSection(&LogFileListCs);
513 return Result;
514 }
515
516 INT LogfListItemCount(VOID)
517 {
518 PLIST_ENTRY CurrentEntry;
519 INT i = 0;
520
521 EnterCriticalSection(&LogFileListCs);
522
523 CurrentEntry = LogFileListHead.Flink;
524 while (CurrentEntry != &LogFileListHead)
525 {
526 CurrentEntry = CurrentEntry->Flink;
527 i++;
528 }
529
530 LeaveCriticalSection(&LogFileListCs);
531 return i;
532 }
533
534 VOID LogfListAddItem(PLOGFILE Item)
535 {
536 EnterCriticalSection(&LogFileListCs);
537 InsertTailList(&LogFileListHead, &Item->ListEntry);
538 LeaveCriticalSection(&LogFileListCs);
539 }
540
541 VOID LogfListRemoveItem(PLOGFILE Item)
542 {
543 EnterCriticalSection(&LogFileListCs);
544 RemoveEntryList(&Item->ListEntry);
545 LeaveCriticalSection(&LogFileListCs);
546 }
547
548 static BOOL
549 ReadAnsiLogEntry(HANDLE hFile,
550 LPVOID lpBuffer,
551 DWORD nNumberOfBytesToRead,
552 LPDWORD lpNumberOfBytesRead)
553 {
554 PEVENTLOGRECORD Dst;
555 PEVENTLOGRECORD Src;
556 ANSI_STRING StringA;
557 UNICODE_STRING StringW;
558 LPWSTR SrcPtr;
559 LPSTR DstPtr;
560 LPWSTR SrcString;
561 LPSTR DstString;
562 LPVOID lpUnicodeBuffer = NULL;
563 DWORD dwRead = 0;
564 DWORD i;
565 DWORD dwPadding;
566 DWORD dwEntryLength;
567 PDWORD pLength;
568 NTSTATUS Status;
569 BOOL ret = TRUE;
570
571 *lpNumberOfBytesRead = 0;
572
573 lpUnicodeBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nNumberOfBytesToRead);
574 if (lpUnicodeBuffer == NULL)
575 {
576 DPRINT1("Alloc failed!\n");
577 return FALSE;
578 }
579
580 if (!ReadFile(hFile, lpUnicodeBuffer, nNumberOfBytesToRead, &dwRead, NULL))
581 {
582 DPRINT1("Read failed!\n");
583 ret = FALSE;
584 goto done;
585 }
586
587 Dst = (PEVENTLOGRECORD)lpBuffer;
588 Src = (PEVENTLOGRECORD)lpUnicodeBuffer;
589
590 Dst->TimeGenerated = Src->TimeGenerated;
591 Dst->Reserved = Src->Reserved;
592 Dst->RecordNumber = Src->RecordNumber;
593 Dst->TimeWritten = Src->TimeWritten;
594 Dst->EventID = Src->EventID;
595 Dst->EventType = Src->EventType;
596 Dst->EventCategory = Src->EventCategory;
597 Dst->NumStrings = Src->NumStrings;
598 Dst->UserSidLength = Src->UserSidLength;
599 Dst->DataLength = Src->DataLength;
600
601 SrcPtr = (LPWSTR)((DWORD_PTR)Src + sizeof(EVENTLOGRECORD));
602 DstPtr = (LPSTR)((DWORD_PTR)Dst + sizeof(EVENTLOGRECORD));
603
604 /* Convert the module name */
605 RtlInitUnicodeString(&StringW, SrcPtr);
606 Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
607 if (NT_SUCCESS(Status))
608 {
609 RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
610
611 DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
612
613 RtlFreeAnsiString(&StringA);
614 }
615
616 /* Convert the computer name */
617 if (NT_SUCCESS(Status))
618 {
619 SrcPtr = (PWSTR)((DWORD_PTR)SrcPtr + StringW.MaximumLength);
620
621 RtlInitUnicodeString(&StringW, SrcPtr);
622 Status = RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
623 if (NT_SUCCESS(Status))
624 {
625 RtlCopyMemory(DstPtr, StringA.Buffer, StringA.MaximumLength);
626
627 DstPtr = (PVOID)((DWORD_PTR)DstPtr + StringA.MaximumLength);
628
629 RtlFreeAnsiString(&StringA);
630 }
631 }
632
633 /* Add the padding and the User SID*/
634 if (NT_SUCCESS(Status))
635 {
636 dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr - (DWORD_PTR)Dst) % sizeof(DWORD));
637 RtlZeroMemory(DstPtr, dwPadding);
638
639 DstPtr = (LPSTR)((DWORD_PTR)DstPtr + dwPadding);
640 RtlCopyMemory(DstPtr,
641 (PVOID)((DWORD_PTR)Src + Src->UserSidOffset),
642 Src->UserSidLength);
643
644 Dst->UserSidOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
645 }
646
647
648 /* Convert the strings */
649 if (NT_SUCCESS(Status))
650 {
651 DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->UserSidLength);
652
653 SrcString = (LPWSTR)((DWORD_PTR)Src + (DWORD)Src->StringOffset);
654 DstString = (LPSTR)DstPtr;
655
656 for (i = 0; i < Dst->NumStrings; i++)
657 {
658 RtlInitUnicodeString(&StringW, SrcString);
659
660 RtlUnicodeStringToAnsiString(&StringA, &StringW, TRUE);
661
662 RtlCopyMemory(DstString, StringA.Buffer, StringA.MaximumLength);
663
664 SrcString = (LPWSTR)((DWORD_PTR)SrcString +
665 (DWORD)StringW.MaximumLength);
666
667 DstString = (LPSTR)((DWORD_PTR)DstString +
668 (DWORD)StringA.MaximumLength);
669
670 RtlFreeAnsiString(&StringA);
671 }
672
673 Dst->StringOffset = (DWORD)((DWORD_PTR)DstPtr - (DWORD_PTR)Dst);
674
675
676 /* Copy the binary data */
677 DstPtr = (PVOID)DstString;
678 Dst->DataOffset = (DWORD_PTR)DstPtr - (DWORD_PTR)Dst;
679
680 RtlCopyMemory(DstPtr, (PVOID)((DWORD_PTR)Src + Src->DataOffset), Src->DataLength);
681
682 /* Add the padding */
683 DstPtr = (PVOID)((DWORD_PTR)DstPtr + Src->DataLength);
684 dwPadding = sizeof(DWORD) - (((DWORD_PTR)DstPtr-(DWORD_PTR)Dst) % sizeof(DWORD));
685 RtlZeroMemory(DstPtr, dwPadding);
686
687 dwEntryLength = (DWORD)((DWORD_PTR)DstPtr + dwPadding + sizeof(DWORD) - (DWORD_PTR)Dst);
688
689 /* Set the entry length at the end of the entry*/
690 pLength = (PDWORD)((DWORD_PTR)DstPtr + dwPadding);
691 *pLength = dwEntryLength;
692 Dst->Length = dwEntryLength;
693
694 *lpNumberOfBytesRead = dwEntryLength;
695 }
696
697 done:
698 if (lpUnicodeBuffer != NULL)
699 HeapFree(GetProcessHeap(), 0, lpUnicodeBuffer);
700
701 return ret;
702 }
703
704
705 DWORD LogfReadEvent(PLOGFILE LogFile,
706 DWORD Flags,
707 DWORD * RecordNumber,
708 DWORD BufSize,
709 PBYTE Buffer,
710 DWORD * BytesRead,
711 DWORD * BytesNeeded,
712 BOOL Ansi)
713 {
714 DWORD dwOffset, dwRead, dwRecSize;
715 DWORD dwBufferUsage = 0, dwRecNum;
716
717 if (Flags & EVENTLOG_FORWARDS_READ && Flags & EVENTLOG_BACKWARDS_READ)
718 return ERROR_INVALID_PARAMETER;
719
720 if (!(Flags & EVENTLOG_FORWARDS_READ) && !(Flags & EVENTLOG_BACKWARDS_READ))
721 return ERROR_INVALID_PARAMETER;
722
723 if (!Buffer || !BytesRead || !BytesNeeded)
724 return ERROR_INVALID_PARAMETER;
725
726 if ((*RecordNumber==0) && !(EVENTLOG_SEQUENTIAL_READ))
727 {
728 return ERROR_INVALID_PARAMETER;
729 }
730
731 dwRecNum = *RecordNumber;
732
733 RtlAcquireResourceShared(&LogFile->Lock, TRUE);
734
735 *BytesRead = 0;
736 *BytesNeeded = 0;
737
738 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
739
740 if (!dwOffset)
741 {
742 RtlReleaseResource(&LogFile->Lock);
743 return ERROR_HANDLE_EOF;
744 }
745
746 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
747 INVALID_SET_FILE_POINTER)
748 {
749 DPRINT1("SetFilePointer() failed!\n");
750 goto Done;
751 }
752
753 if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
754 {
755 DPRINT1("ReadFile() failed!\n");
756 goto Done;
757 }
758
759 if (dwRecSize > BufSize)
760 {
761 *BytesNeeded = dwRecSize;
762 RtlReleaseResource(&LogFile->Lock);
763 return ERROR_INSUFFICIENT_BUFFER;
764 }
765
766 if (SetFilePointer(LogFile->hFile,
767 -((LONG) sizeof(DWORD)),
768 NULL,
769 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
770 {
771 DPRINT1("SetFilePointer() failed!\n");
772 goto Done;
773 }
774
775 if (Ansi == TRUE)
776 {
777 if (!ReadAnsiLogEntry(LogFile->hFile, Buffer, dwRecSize, &dwRead))
778 {
779 DPRINT1("ReadAnsiLogEntry() failed!\n");
780 goto Done;
781 }
782 }
783 else
784 {
785 if (!ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL))
786 {
787 DPRINT1("ReadFile() failed!\n");
788 goto Done;
789 }
790 }
791
792 dwBufferUsage += dwRead;
793
794 while (dwBufferUsage <= BufSize)
795 {
796 if (Flags & EVENTLOG_FORWARDS_READ)
797 dwRecNum++;
798 else
799 dwRecNum--;
800
801 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
802 if (!dwOffset)
803 break;
804
805 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
806 INVALID_SET_FILE_POINTER)
807 {
808 DPRINT1("SetFilePointer() failed!\n");
809 goto Done;
810 }
811
812 if (!ReadFile(LogFile->hFile,
813 &dwRecSize,
814 sizeof(DWORD),
815 &dwRead,
816 NULL))
817 {
818 DPRINT1("ReadFile() failed!\n");
819 goto Done;
820 }
821
822 if (dwBufferUsage + dwRecSize > BufSize)
823 break;
824
825 if (SetFilePointer(LogFile->hFile,
826 -((LONG) sizeof(DWORD)),
827 NULL,
828 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
829 {
830 DPRINT1("SetFilePointer() failed!\n");
831 goto Done;
832 }
833
834 if (Ansi == TRUE)
835 {
836 if (!ReadAnsiLogEntry(LogFile->hFile,
837 Buffer + dwBufferUsage,
838 dwRecSize,
839 &dwRead))
840 {
841 DPRINT1("ReadAnsiLogEntry() failed!\n");
842 goto Done;
843 }
844 }
845 else
846 {
847 if (!ReadFile(LogFile->hFile,
848 Buffer + dwBufferUsage,
849 dwRecSize,
850 &dwRead,
851 NULL))
852 {
853 DPRINT1("ReadFile() failed!\n");
854 goto Done;
855 }
856 }
857
858 dwBufferUsage += dwRead;
859 }
860
861 *BytesRead = dwBufferUsage;
862 * RecordNumber = dwRecNum;
863 RtlReleaseResource(&LogFile->Lock);
864 return ERROR_SUCCESS;
865
866 Done:
867 DPRINT1("LogfReadEvent failed with %x\n",GetLastError());
868 RtlReleaseResource(&LogFile->Lock);
869 return GetLastError();
870 }
871
872 BOOL LogfWriteData(PLOGFILE LogFile, DWORD BufSize, PBYTE Buffer)
873 {
874 DWORD dwWritten;
875 DWORD dwRead;
876 SYSTEMTIME st;
877 EVENTLOGEOF EofRec;
878 PEVENTLOGRECORD RecBuf;
879 LARGE_INTEGER logFileSize;
880 ULONG RecOffSet;
881 ULONG WriteOffSet;
882
883 if (!Buffer)
884 return FALSE;
885
886 GetSystemTime(&st);
887 SystemTimeToEventTime(&st, &((PEVENTLOGRECORD) Buffer)->TimeWritten);
888
889 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
890
891 if (!GetFileSizeEx(LogFile->hFile, &logFileSize))
892 {
893 RtlReleaseResource(&LogFile->Lock);
894 return FALSE;
895 }
896
897 /* If the size of the file is over MaxSize */
898 if ((logFileSize.QuadPart + BufSize)> LogFile->Header.MaxSize)
899 {
900 ULONG OverWriteLength = 0;
901 WriteOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
902 RecBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EVENTLOGRECORD));
903 /* Determine how many records need to be overwritten */
904 while (TRUE)
905 {
906 DPRINT("EventLogFile has reached maximume size\n");
907
908 if (!RecBuf)
909 {
910 DPRINT1("Failed to allocate buffer for OldestRecord!\n");
911 HeapFree(GetProcessHeap(), 0, RecBuf);
912 RtlReleaseResource(&LogFile->Lock);
913 return FALSE;
914 }
915
916 /* Get the oldest record data */
917 RecOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
918
919 if (SetFilePointer(LogFile->hFile,
920 RecOffSet,
921 NULL,
922 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
923 {
924 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
925 HeapFree(GetProcessHeap(), 0, RecBuf);
926 RtlReleaseResource(&LogFile->Lock);
927 return FALSE;
928 }
929
930 if (!ReadFile(LogFile->hFile, RecBuf, sizeof(EVENTLOGRECORD), &dwRead, NULL))
931 {
932 DPRINT1("ReadFile() failed!\n");
933 HeapFree(GetProcessHeap(), 0, RecBuf);
934 RtlReleaseResource(&LogFile->Lock);
935 return FALSE;
936 }
937
938 if (RecBuf->Reserved != LOGFILE_SIGNATURE)
939 {
940 DPRINT1("LogFile corrupt!\n");
941 RtlReleaseResource(&LogFile->Lock);
942 return FALSE;
943 }
944
945 LogfDeleteOffsetInformation(LogFile,LogFile->Header.OldestRecordNumber);
946
947 LogFile->Header.OldestRecordNumber++;
948
949 OverWriteLength += RecBuf->Length;
950 /* Check the size of the record as the record adding may be larger */
951 if (OverWriteLength >= BufSize)
952 {
953 DPRINT("Record will fit. Lenght %d, BufSize %d\n", OverWriteLength, BufSize);
954 LogFile->Header.StartOffset = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
955 break;
956 }
957 }
958 HeapFree(GetProcessHeap(), 0, RecBuf);
959 }
960 else
961 WriteOffSet = LogFile->Header.EndOffset;
962
963 if (SetFilePointer(LogFile->hFile,
964 WriteOffSet,
965 NULL,
966 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
967 {
968 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
969 RtlReleaseResource(&LogFile->Lock);
970 return FALSE;
971 }
972
973 if (!WriteFile(LogFile->hFile, Buffer, BufSize, &dwWritten, NULL))
974 {
975 DPRINT1("WriteFile() failed! %d\n", GetLastError());
976 RtlReleaseResource(&LogFile->Lock);
977 return FALSE;
978 }
979
980 if (!LogfAddOffsetInformation(LogFile,
981 LogFile->Header.CurrentRecordNumber,
982 WriteOffSet))
983 {
984 RtlReleaseResource(&LogFile->Lock);
985 return FALSE;
986 }
987
988 LogFile->Header.CurrentRecordNumber++;
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 RtlReleaseResource(&LogFile->Lock);
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 RtlReleaseResource(&LogFile->Lock);
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 RtlReleaseResource(&LogFile->Lock);
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 RtlReleaseResource(&LogFile->Lock);
1042 return FALSE;
1043 }
1044
1045 if (!FlushFileBuffers(LogFile->hFile))
1046 {
1047 DPRINT1("FlushFileBuffers() failed! %d\n", GetLastError());
1048 RtlReleaseResource(&LogFile->Lock);
1049 return FALSE;
1050 }
1051
1052 RtlReleaseResource(&LogFile->Lock);
1053 return TRUE;
1054 }
1055
1056
1057 NTSTATUS
1058 LogfClearFile(PLOGFILE LogFile,
1059 PUNICODE_STRING BackupFileName)
1060 {
1061 RtlAcquireResourceExclusive(&LogFile->Lock, TRUE);
1062
1063 if (BackupFileName->Length > 0)
1064 {
1065 /* FIXME: Write a backup file */
1066 }
1067
1068 LogfInitializeNew(LogFile);
1069
1070 RtlReleaseResource(&LogFile->Lock);
1071
1072 return STATUS_SUCCESS;
1073 }
1074
1075
1076 NTSTATUS
1077 LogfBackupFile(PLOGFILE LogFile,
1078 PUNICODE_STRING BackupFileName)
1079 {
1080 // RtlAcquireResourceShared(&LogFile->Lock, TRUE);
1081
1082 /* FIXME: Write a backup file */
1083
1084 // RtlReleaseResource(&LogFile->Lock);
1085
1086 return STATUS_NOT_IMPLEMENTED;
1087 }
1088
1089
1090 /* Returns 0 if nothing found. */
1091 ULONG LogfOffsetByNumber(PLOGFILE LogFile, DWORD RecordNumber)
1092 {
1093 DWORD i;
1094
1095 for (i = 0; i < LogFile->OffsetInfoNext; i++)
1096 {
1097 if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
1098 return LogFile->OffsetInfo[i].EventOffset;
1099 }
1100 return 0;
1101 }
1102
1103 DWORD LogfGetOldestRecord(PLOGFILE LogFile)
1104 {
1105 return LogFile->Header.OldestRecordNumber;
1106 }
1107
1108 DWORD LogfGetCurrentRecord(PLOGFILE LogFile)
1109 {
1110 return LogFile->Header.CurrentRecordNumber;
1111 }
1112
1113 BOOL LogfDeleteOffsetInformation(PLOGFILE LogFile, ULONG ulNumber)
1114 {
1115 DWORD i;
1116
1117 if (ulNumber != LogFile->OffsetInfo[0].EventNumber)
1118 {
1119 return FALSE;
1120 }
1121
1122 for (i = 0; i < LogFile->OffsetInfoNext - 1; i++)
1123 {
1124 LogFile->OffsetInfo[i].EventNumber = LogFile->OffsetInfo[i + 1].EventNumber;
1125 LogFile->OffsetInfo[i].EventOffset = LogFile->OffsetInfo[i + 1].EventOffset;
1126 }
1127 LogFile->OffsetInfoNext--;
1128 return TRUE;
1129 }
1130
1131 BOOL LogfAddOffsetInformation(PLOGFILE LogFile, ULONG ulNumber, ULONG ulOffset)
1132 {
1133 LPVOID NewOffsetInfo;
1134
1135 if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
1136 {
1137 NewOffsetInfo = HeapReAlloc(MyHeap,
1138 HEAP_ZERO_MEMORY,
1139 LogFile->OffsetInfo,
1140 (LogFile->OffsetInfoSize + 64) *
1141 sizeof(EVENT_OFFSET_INFO));
1142
1143 if (!NewOffsetInfo)
1144 {
1145 DPRINT1("Can't reallocate heap.\n");
1146 return FALSE;
1147 }
1148
1149 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO) NewOffsetInfo;
1150 LogFile->OffsetInfoSize += 64;
1151 }
1152
1153 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
1154 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
1155 LogFile->OffsetInfoNext++;
1156
1157 return TRUE;
1158 }
1159
1160 PBYTE LogfAllocAndBuildNewRecord(LPDWORD lpRecSize,
1161 DWORD dwRecordNumber,
1162 WORD wType,
1163 WORD wCategory,
1164 DWORD dwEventId,
1165 LPCWSTR SourceName,
1166 LPCWSTR ComputerName,
1167 DWORD dwSidLength,
1168 PSID lpUserSid,
1169 WORD wNumStrings,
1170 WCHAR * lpStrings,
1171 DWORD dwDataSize,
1172 LPVOID lpRawData)
1173 {
1174 DWORD dwRecSize;
1175 PEVENTLOGRECORD pRec;
1176 SYSTEMTIME SysTime;
1177 WCHAR *str;
1178 UINT i, pos;
1179 PBYTE Buffer;
1180
1181 dwRecSize =
1182 sizeof(EVENTLOGRECORD) + (lstrlenW(ComputerName) +
1183 lstrlenW(SourceName) + 2) * sizeof(WCHAR);
1184
1185 if (dwRecSize % 4 != 0)
1186 dwRecSize += 4 - (dwRecSize % 4);
1187
1188 dwRecSize += dwSidLength;
1189
1190 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1191 {
1192 dwRecSize += (lstrlenW(str) + 1) * sizeof(WCHAR);
1193 str += lstrlenW(str) + 1;
1194 }
1195
1196 dwRecSize += dwDataSize;
1197 if (dwRecSize % 4 != 0)
1198 dwRecSize += 4 - (dwRecSize % 4);
1199
1200 dwRecSize += 4;
1201
1202 Buffer = HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, dwRecSize);
1203
1204 if (!Buffer)
1205 {
1206 DPRINT1("Can't allocate heap!\n");
1207 return NULL;
1208 }
1209
1210 pRec = (PEVENTLOGRECORD) Buffer;
1211 pRec->Length = dwRecSize;
1212 pRec->Reserved = LOGFILE_SIGNATURE;
1213 pRec->RecordNumber = dwRecordNumber;
1214
1215 GetSystemTime(&SysTime);
1216 SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
1217 SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
1218
1219 pRec->EventID = dwEventId;
1220 pRec->EventType = wType;
1221 pRec->EventCategory = wCategory;
1222
1223 pos = sizeof(EVENTLOGRECORD);
1224
1225 lstrcpyW((WCHAR *) (Buffer + pos), SourceName);
1226 pos += (lstrlenW(SourceName) + 1) * sizeof(WCHAR);
1227 lstrcpyW((WCHAR *) (Buffer + pos), ComputerName);
1228 pos += (lstrlenW(ComputerName) + 1) * sizeof(WCHAR);
1229
1230 pRec->UserSidOffset = pos;
1231
1232 if (pos % 4 != 0)
1233 pos += 4 - (pos % 4);
1234
1235 if (dwSidLength)
1236 {
1237 CopyMemory(Buffer + pos, lpUserSid, dwSidLength);
1238 pRec->UserSidLength = dwSidLength;
1239 pRec->UserSidOffset = pos;
1240 pos += dwSidLength;
1241 }
1242
1243 pRec->StringOffset = pos;
1244 for (i = 0, str = lpStrings; i < wNumStrings; i++)
1245 {
1246 lstrcpyW((WCHAR *) (Buffer + pos), str);
1247 pos += (lstrlenW(str) + 1) * sizeof(WCHAR);
1248 str += lstrlenW(str) + 1;
1249 }
1250 pRec->NumStrings = wNumStrings;
1251
1252 pRec->DataOffset = pos;
1253 if (dwDataSize)
1254 {
1255 pRec->DataLength = dwDataSize;
1256 CopyMemory(Buffer + pos, lpRawData, dwDataSize);
1257 pos += dwDataSize;
1258 }
1259
1260 if (pos % 4 != 0)
1261 pos += 4 - (pos % 4);
1262
1263 *((PDWORD) (Buffer + pos)) = dwRecSize;
1264
1265 *lpRecSize = dwRecSize;
1266 return Buffer;
1267 }
1268
1269
1270 VOID
1271 LogfReportEvent(WORD wType,
1272 WORD wCategory,
1273 DWORD dwEventId,
1274 WORD wNumStrings,
1275 WCHAR *lpStrings,
1276 DWORD dwDataSize,
1277 LPVOID lpRawData)
1278 {
1279 WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1280 DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
1281 PEVENTSOURCE pEventSource = NULL;
1282 PBYTE logBuffer;
1283 DWORD lastRec;
1284 DWORD recSize;
1285 DWORD dwError;
1286
1287 if (!GetComputerNameW(szComputerName, &dwComputerNameLength))
1288 {
1289 szComputerName[0] = 0;
1290 }
1291
1292 pEventSource = GetEventSourceByName(L"EventLog");
1293 if (pEventSource == NULL)
1294 {
1295 return;
1296 }
1297
1298 lastRec = LogfGetCurrentRecord(pEventSource->LogFile);
1299
1300 logBuffer = LogfAllocAndBuildNewRecord(&recSize,
1301 lastRec,
1302 wType,
1303 wCategory,
1304 dwEventId,
1305 pEventSource->szName,
1306 (LPCWSTR)szComputerName,
1307 0,
1308 NULL,
1309 wNumStrings,
1310 lpStrings,
1311 dwDataSize,
1312 lpRawData);
1313
1314 dwError = LogfWriteData(pEventSource->LogFile, recSize, logBuffer);
1315 if (!dwError)
1316 {
1317 DPRINT1("ERROR WRITING TO EventLog %S\n", pEventSource->LogFile->FileName);
1318 }
1319
1320 LogfFreeRecord(logBuffer);
1321 }