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