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