- eventlog.h: Add CurrentRecord to EventSource struct as each EventLog handle must...
[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 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include "eventlog.h"
12
13 /* GLOBALS ******************************************************************/
14
15 static LIST_ENTRY LogFileListHead;
16 static CRITICAL_SECTION LogFileListCs;
17
18 /* FUNCTIONS ****************************************************************/
19
20 BOOL LogfInitializeNew(PLOGFILE LogFile)
21 {
22 DWORD dwWritten;
23 EVENTLOGEOF EofRec;
24
25 ZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
26 SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
27 SetEndOfFile(LogFile->hFile);
28
29 LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
30 LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
31 LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
32 LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
33 LogFile->Header.MajorVersion = MAJORVER;
34 LogFile->Header.MinorVersion = MINORVER;
35 LogFile->Header.CurrentRecordNumber = 1;
36 /* FIXME: Read MaxSize from registry for this LogFile.
37 But for now limit EventLog size to just under 5K. */
38 LogFile->Header.MaxSize = 5000;
39 LogFile->Header.Signature = LOGFILE_SIGNATURE;
40 if (!WriteFile(LogFile->hFile,
41 &LogFile->Header,
42 sizeof(EVENTLOGHEADER),
43 &dwWritten,
44 NULL))
45 {
46 DPRINT1("WriteFile failed:%d!\n", GetLastError());
47 return FALSE;
48 }
49
50 EofRec.Ones = 0x11111111;
51 EofRec.Twos = 0x22222222;
52 EofRec.Threes = 0x33333333;
53 EofRec.Fours = 0x44444444;
54 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
55 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
56 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
57 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
58 EofRec.BeginRecord = LogFile->Header.StartOffset;
59 EofRec.EndRecord = LogFile->Header.EndOffset;
60
61 if (!WriteFile(LogFile->hFile,
62 &EofRec,
63 sizeof(EVENTLOGEOF),
64 &dwWritten,
65 NULL))
66 {
67 DPRINT1("WriteFile failed:%d!\n", GetLastError());
68 return FALSE;
69 }
70
71 if (!FlushFileBuffers(LogFile->hFile))
72 {
73 DPRINT1("FlushFileBuffers failed:%d!\n", GetLastError());
74 return FALSE;
75 }
76
77 return TRUE;
78 }
79
80 BOOL LogfInitializeExisting(PLOGFILE LogFile)
81 {
82 DWORD dwRead;
83 DWORD dwRecordsNumber = 0;
84 DWORD dwRecSize, dwRecSign, dwFilePointer;
85 PDWORD pdwRecSize2;
86 PEVENTLOGRECORD RecBuf;
87
88 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
89 INVALID_SET_FILE_POINTER)
90 {
91 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
92 return FALSE;
93 }
94
95 if (!ReadFile(LogFile->hFile,
96 &LogFile->Header,
97 sizeof(EVENTLOGHEADER),
98 &dwRead,
99 NULL))
100 {
101 DPRINT1("ReadFile failed! %d\n", GetLastError());
102 return FALSE;
103 }
104
105 if (dwRead != sizeof(EVENTLOGHEADER))
106 {
107 DPRINT("EventLog: Invalid file %S.\n", LogFile->FileName);
108 return LogfInitializeNew(LogFile);
109 }
110
111 if (LogFile->Header.HeaderSize != sizeof(EVENTLOGHEADER) ||
112 LogFile->Header.EndHeaderSize != sizeof(EVENTLOGHEADER))
113 {
114 DPRINT("EventLog: Invalid header size in %S.\n", LogFile->FileName);
115 return LogfInitializeNew(LogFile);
116 }
117
118 if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
119 {
120 DPRINT("EventLog: Invalid signature %x in %S.\n",
121 LogFile->Header.Signature, LogFile->FileName);
122 return LogfInitializeNew(LogFile);
123 }
124
125 if (LogFile->Header.EndOffset > GetFileSize(LogFile->hFile, NULL) + 1)
126 {
127 DPRINT("EventLog: Invalid eof offset %x in %S.\n",
128 LogFile->Header.EndOffset, LogFile->FileName);
129 return LogfInitializeNew(LogFile);
130 }
131
132 for (;;)
133 {
134 dwFilePointer = SetFilePointer(LogFile->hFile, 0, NULL, FILE_CURRENT);
135
136 if (dwFilePointer == INVALID_SET_FILE_POINTER)
137 {
138 DPRINT1("SetFilePointer failed! %d\n", GetLastError());
139 return FALSE;
140 }
141
142 if (!ReadFile(LogFile->hFile,
143 &dwRecSize,
144 sizeof(dwRecSize),
145 &dwRead,
146 NULL))
147 {
148 DPRINT1("ReadFile failed! %d\n", GetLastError());
149 return FALSE;
150 }
151
152 if (dwRead != sizeof(dwRecSize))
153 break;
154
155 if (!ReadFile(LogFile->hFile,
156 &dwRecSign,
157 sizeof(dwRecSign),
158 &dwRead,
159 NULL))
160 {
161 DPRINT1("ReadFile() failed! %d\n", GetLastError());
162 return FALSE;
163 }
164
165 if (dwRead != sizeof(dwRecSize))
166 break;
167
168 if (dwRecSign != LOGFILE_SIGNATURE ||
169 dwRecSize + dwFilePointer > GetFileSize(LogFile->hFile, NULL) + 1 ||
170 dwRecSize < sizeof(EVENTLOGRECORD))
171 {
172 break;
173 }
174
175 if (SetFilePointer(LogFile->hFile,
176 -((LONG) sizeof(DWORD) * 2),
177 NULL,
178 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
179 {
180 DPRINT1("SetFilePointer() failed! %d", GetLastError());
181 return FALSE;
182 }
183
184 RecBuf = (PEVENTLOGRECORD) HeapAlloc(MyHeap, 0, dwRecSize);
185
186 if (!RecBuf)
187 {
188 DPRINT1("Can't allocate heap!\n");
189 return FALSE;
190 }
191
192 if (!ReadFile(LogFile->hFile, RecBuf, dwRecSize, &dwRead, NULL))
193 {
194 DPRINT1("ReadFile() failed! %d\n", GetLastError());
195 HeapFree(MyHeap, 0, RecBuf);
196 return FALSE;
197 }
198
199 if (dwRead != dwRecSize)
200 {
201 HeapFree(MyHeap, 0, RecBuf);
202 break;
203 }
204
205 pdwRecSize2 = (PDWORD) (((PBYTE) RecBuf) + dwRecSize - 4);
206
207 if (*pdwRecSize2 != dwRecSize)
208 {
209 DPRINT1("Invalid RecordSizeEnd of record %d (%x) in %S\n",
210 dwRecordsNumber, *pdwRecSize2, LogFile->LogName);
211 HeapFree(MyHeap, 0, RecBuf);
212 break;
213 }
214
215 dwRecordsNumber++;
216
217 if (!LogfAddOffsetInformation(LogFile,
218 RecBuf->RecordNumber,
219 dwFilePointer))
220 {
221 DPRINT1("LogfAddOffsetInformation() failed!\n");
222 HeapFree(MyHeap, 0, RecBuf);
223 return FALSE;
224 }
225
226 HeapFree(MyHeap, 0, RecBuf);
227 } // for(;;)
228
229 LogFile->Header.CurrentRecordNumber = dwRecordsNumber + 1;
230 LogFile->Header.OldestRecordNumber = dwRecordsNumber ? 1 : 0; // FIXME
231
232 /* FIXME: Read MaxSize from registry for this LogFile.
233 But for now limit EventLog size to just under 5K. */
234 LogFile->Header.MaxSize = 5000;
235
236 if (!SetFilePointer(LogFile->hFile, 0, NULL, FILE_CURRENT) ==
237 INVALID_SET_FILE_POINTER)
238 {
239 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
240 return FALSE;
241 }
242
243 if (!WriteFile(LogFile->hFile,
244 &LogFile->Header,
245 sizeof(EVENTLOGHEADER),
246 &dwRead,
247 NULL))
248 {
249 DPRINT1("WriteFile failed! %d\n", GetLastError());
250 return FALSE;
251 }
252
253 if (!FlushFileBuffers(LogFile->hFile))
254 {
255 DPRINT1("FlushFileBuffers failed! %d\n", GetLastError());
256 return FALSE;
257 }
258
259 return TRUE;
260 }
261
262 PLOGFILE LogfCreate(WCHAR * LogName, WCHAR * FileName)
263 {
264 PLOGFILE LogFile;
265 BOOL bResult, bCreateNew = FALSE;
266
267 LogFile = (LOGFILE *) HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, sizeof(LOGFILE));
268 if (!LogFile)
269 {
270 DPRINT1("Can't allocate heap!\n");
271 return NULL;
272 }
273
274 LogFile->hFile = CreateFile(FileName,
275 GENERIC_READ | GENERIC_WRITE,
276 FILE_SHARE_READ,
277 NULL,
278 OPEN_ALWAYS,
279 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
280 NULL);
281
282 if (LogFile->hFile == INVALID_HANDLE_VALUE)
283 {
284 DPRINT1("Can't create file %S.\n", FileName);
285 HeapFree(MyHeap, 0, LogFile);
286 return NULL;
287 }
288
289 bCreateNew = (GetLastError() == ERROR_ALREADY_EXISTS) ? FALSE : TRUE;
290
291 LogFile->LogName =
292 (WCHAR *) HeapAlloc(MyHeap,
293 HEAP_ZERO_MEMORY,
294 (lstrlenW(LogName) + 1) * sizeof(WCHAR));
295
296 if (LogFile->LogName)
297 lstrcpyW(LogFile->LogName, LogName);
298 else
299 {
300 DPRINT1("Can't allocate heap\n");
301 HeapFree(MyHeap, 0, LogFile);
302 return NULL;
303 }
304
305 LogFile->FileName =
306 (WCHAR *) HeapAlloc(MyHeap,
307 HEAP_ZERO_MEMORY,
308 (lstrlenW(FileName) + 1) * sizeof(WCHAR));
309
310 if (LogFile->FileName)
311 lstrcpyW(LogFile->FileName, FileName);
312 else
313 {
314 DPRINT1("Can't allocate heap\n");
315 goto fail;
316 }
317
318 LogFile->OffsetInfo =
319 (PEVENT_OFFSET_INFO) HeapAlloc(MyHeap,
320 HEAP_ZERO_MEMORY,
321 sizeof(EVENT_OFFSET_INFO) * 64);
322
323 if (!LogFile->OffsetInfo)
324 {
325 DPRINT1("Can't allocate heap\n");
326 goto fail;
327 }
328
329 LogFile->OffsetInfoSize = 64;
330
331 if (bCreateNew)
332 bResult = LogfInitializeNew(LogFile);
333 else
334 bResult = LogfInitializeExisting(LogFile);
335
336 if (!bResult)
337 goto fail;
338
339 InitializeCriticalSection(&LogFile->cs);
340 LogfListAddItem(LogFile);
341 return LogFile;
342
343 fail:
344 if (LogFile)
345 {
346 if (LogFile->OffsetInfo)
347 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
348
349 if (LogFile->FileName)
350 HeapFree(MyHeap, 0, LogFile->FileName);
351
352 if (LogFile->LogName)
353 HeapFree(MyHeap, 0, LogFile->LogName);
354
355 HeapFree(MyHeap, 0, LogFile);
356 }
357
358 return NULL;
359 }
360
361 VOID LogfClose(PLOGFILE LogFile)
362 {
363 if (LogFile == NULL)
364 return;
365
366 EnterCriticalSection(&LogFile->cs);
367
368 FlushFileBuffers(LogFile->hFile);
369 CloseHandle(LogFile->hFile);
370 LogfListRemoveItem(LogFile);
371
372 DeleteCriticalSection(&LogFile->cs);
373
374 HeapFree(MyHeap, 0, LogFile->LogName);
375 HeapFree(MyHeap, 0, LogFile->FileName);
376 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
377 HeapFree(MyHeap, 0, LogFile);
378
379 return;
380 }
381
382 VOID LogfCloseAll(VOID)
383 {
384 while (!IsListEmpty(&LogFileListHead))
385 {
386 LogfClose(LogfListHead());
387 }
388
389 DeleteCriticalSection(&LogFileListCs);
390 }
391
392 VOID LogfListInitialize(VOID)
393 {
394 InitializeCriticalSection(&LogFileListCs);
395 InitializeListHead(&LogFileListHead);
396 }
397
398 PLOGFILE LogfListHead(VOID)
399 {
400 return CONTAINING_RECORD(LogFileListHead.Flink, LOGFILE, ListEntry);
401 }
402
403 PLOGFILE LogfListItemByName(WCHAR * Name)
404 {
405 PLIST_ENTRY CurrentEntry;
406 PLOGFILE Result = NULL;
407
408 EnterCriticalSection(&LogFileListCs);
409
410 CurrentEntry = LogFileListHead.Flink;
411 while (CurrentEntry != &LogFileListHead)
412 {
413 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
414 LOGFILE,
415 ListEntry);
416
417 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
418 {
419 Result = Item;
420 break;
421 }
422
423 CurrentEntry = CurrentEntry->Flink;
424 }
425
426 LeaveCriticalSection(&LogFileListCs);
427 return Result;
428 }
429
430 /* Index starting from 1 */
431 INT LogfListItemIndexByName(WCHAR * Name)
432 {
433 PLIST_ENTRY CurrentEntry;
434 INT Result = 0;
435 INT i = 1;
436
437 EnterCriticalSection(&LogFileListCs);
438
439 CurrentEntry = LogFileListHead.Flink;
440 while (CurrentEntry != &LogFileListHead)
441 {
442 PLOGFILE Item = CONTAINING_RECORD(CurrentEntry,
443 LOGFILE,
444 ListEntry);
445
446 if (Item->LogName && !lstrcmpi(Item->LogName, Name))
447 {
448 Result = i;
449 break;
450 }
451
452 CurrentEntry = CurrentEntry->Flink;
453 i++;
454 }
455
456 LeaveCriticalSection(&LogFileListCs);
457 return Result;
458 }
459
460 /* Index starting from 1 */
461 PLOGFILE LogfListItemByIndex(INT Index)
462 {
463 PLIST_ENTRY CurrentEntry;
464 PLOGFILE Result = NULL;
465 INT i = 1;
466
467 EnterCriticalSection(&LogFileListCs);
468
469 CurrentEntry = LogFileListHead.Flink;
470 while (CurrentEntry != &LogFileListHead)
471 {
472 if (i == Index)
473 {
474 Result = CONTAINING_RECORD(CurrentEntry, LOGFILE, ListEntry);
475 break;
476 }
477
478 CurrentEntry = CurrentEntry->Flink;
479 i++;
480 }
481
482 LeaveCriticalSection(&LogFileListCs);
483 return Result;
484 }
485
486 INT LogfListItemCount()
487 {
488 PLIST_ENTRY CurrentEntry;
489 INT i = 0;
490
491 EnterCriticalSection(&LogFileListCs);
492
493 CurrentEntry = LogFileListHead.Flink;
494 while (CurrentEntry != &LogFileListHead)
495 {
496 CurrentEntry = CurrentEntry->Flink;
497 i++;
498 }
499
500 LeaveCriticalSection(&LogFileListCs);
501 return i;
502 }
503
504 VOID LogfListAddItem(PLOGFILE Item)
505 {
506 EnterCriticalSection(&LogFileListCs);
507 InsertTailList(&LogFileListHead, &Item->ListEntry);
508 LeaveCriticalSection(&LogFileListCs);
509 }
510
511 VOID LogfListRemoveItem(PLOGFILE Item)
512 {
513 EnterCriticalSection(&LogFileListCs);
514 RemoveEntryList(&Item->ListEntry);
515 LeaveCriticalSection(&LogFileListCs);
516 }
517
518 DWORD LogfReadEvent(PLOGFILE LogFile,
519 DWORD Flags,
520 DWORD * RecordNumber,
521 DWORD BufSize,
522 PBYTE Buffer,
523 DWORD * BytesRead,
524 DWORD * BytesNeeded)
525 {
526 DWORD dwOffset, dwRead, dwRecSize;
527 DWORD dwBufferUsage = 0, dwRecNum;
528
529 if (Flags & EVENTLOG_FORWARDS_READ && Flags & EVENTLOG_BACKWARDS_READ)
530 return ERROR_INVALID_PARAMETER;
531
532 if (!(Flags & EVENTLOG_FORWARDS_READ) && !(Flags & EVENTLOG_BACKWARDS_READ))
533 return ERROR_INVALID_PARAMETER;
534
535 if (!Buffer || !BytesRead || !BytesNeeded)
536 return ERROR_INVALID_PARAMETER;
537
538 if ((*RecordNumber==0) && !(EVENTLOG_SEQUENTIAL_READ))
539 {
540 return ERROR_INVALID_PARAMETER;
541 }
542
543 dwRecNum = *RecordNumber;
544 EnterCriticalSection(&LogFile->cs);
545
546 *BytesRead = 0;
547 *BytesNeeded = 0;
548
549 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
550
551 if (!dwOffset)
552 {
553 LeaveCriticalSection(&LogFile->cs);
554 return ERROR_HANDLE_EOF;
555 }
556
557 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
558 INVALID_SET_FILE_POINTER)
559 {
560 DPRINT1("SetFilePointer() failed!\n");
561 goto Done;
562 }
563
564 if (!ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL))
565 {
566 DPRINT1("ReadFile() failed!\n");
567 goto Done;
568 }
569
570 if (dwRecSize > BufSize)
571 {
572 *BytesNeeded = dwRecSize;
573 LeaveCriticalSection(&LogFile->cs);
574 return ERROR_INSUFFICIENT_BUFFER;
575 }
576
577 if (SetFilePointer(LogFile->hFile,
578 -((LONG) sizeof(DWORD)),
579 NULL,
580 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
581 {
582 DPRINT1("SetFilePointer() failed!\n");
583 goto Done;
584 }
585
586 if (!ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL))
587 {
588 DPRINT1("ReadFile() failed!\n");
589 goto Done;
590 }
591
592 dwBufferUsage += dwRead;
593
594 while (dwBufferUsage <= BufSize)
595 {
596 if (Flags & EVENTLOG_FORWARDS_READ)
597 dwRecNum++;
598 else
599 dwRecNum--;
600
601 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
602 if (!dwOffset)
603 break;
604
605 if (SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN) ==
606 INVALID_SET_FILE_POINTER)
607 {
608 DPRINT1("SetFilePointer() failed!\n");
609 goto Done;
610 }
611
612 if (!ReadFile(LogFile->hFile,
613 &dwRecSize,
614 sizeof(DWORD),
615 &dwRead,
616 NULL))
617 {
618 DPRINT1("ReadFile() failed!\n");
619 goto Done;
620 }
621
622 if (dwBufferUsage + dwRecSize > BufSize)
623 break;
624
625 if (SetFilePointer(LogFile->hFile,
626 -((LONG) sizeof(DWORD)),
627 NULL,
628 FILE_CURRENT) == INVALID_SET_FILE_POINTER)
629 {
630 DPRINT1("SetFilePointer() failed!\n");
631 goto Done;
632 }
633
634 if (!ReadFile(LogFile->hFile,
635 Buffer + dwBufferUsage,
636 dwRecSize,
637 &dwRead,
638 NULL))
639 {
640 DPRINT1("ReadFile() failed!\n");
641 goto Done;
642 }
643
644 dwBufferUsage += dwRead;
645 }
646
647 *BytesRead = dwBufferUsage;
648 * RecordNumber = dwRecNum;
649 LeaveCriticalSection(&LogFile->cs);
650 return ERROR_SUCCESS;
651
652 Done:
653 DPRINT1("LogfReadEvent failed with %x\n",GetLastError());
654 LeaveCriticalSection(&LogFile->cs);
655 return GetLastError();
656 }
657
658 BOOL LogfWriteData(PLOGFILE LogFile, DWORD BufSize, PBYTE Buffer)
659 {
660 DWORD dwWritten;
661 DWORD dwRead;
662 SYSTEMTIME st;
663 EVENTLOGEOF EofRec;
664 PEVENTLOGRECORD RecBuf;
665 LARGE_INTEGER logFileSize;
666 ULONG RecOffSet;
667 if (!Buffer)
668 return FALSE;
669
670 GetSystemTime(&st);
671 SystemTimeToEventTime(&st, &((PEVENTLOGRECORD) Buffer)->TimeWritten);
672
673 EnterCriticalSection(&LogFile->cs);
674
675 if (!GetFileSizeEx(LogFile->hFile, &logFileSize))
676 {
677 return FALSE;
678 }
679
680 /* If the size of the file is over MaxSize */
681 if ((logFileSize.QuadPart + BufSize)> LogFile->Header.MaxSize)
682 {
683 RecBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(EVENTLOGRECORD));
684 /* Determine how many records need to be overwritten */
685 while (TRUE)
686 {
687 DPRINT("EventLogFile has reached maximume size\n");
688
689 if (!RecBuf)
690 {
691 DPRINT1("Failed to allocate buffer for OldestRecord!\n");
692 HeapFree(GetProcessHeap(), 0, RecBuf);
693 LeaveCriticalSection(&LogFile->cs);
694 return FALSE;
695 }
696
697 /* Get the oldest record data */
698 RecOffSet = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
699 if (SetFilePointer(LogFile->hFile,
700 RecOffSet,
701 NULL,
702 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
703 {
704 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
705 HeapFree(GetProcessHeap(), 0, RecBuf);
706 LeaveCriticalSection(&LogFile->cs);
707 return FALSE;
708 }
709
710 if (!ReadFile(LogFile->hFile, RecBuf, sizeof(EVENTLOGRECORD), &dwRead, NULL))
711 {
712 DPRINT1("ReadFile() failed!\n");
713 HeapFree(GetProcessHeap(), 0, RecBuf);
714 LeaveCriticalSection(&LogFile->cs);
715 return FALSE;
716 }
717
718 if (RecBuf->Reserved != LOGFILE_SIGNATURE)
719 {
720 DPRINT1("LogFile corrupt!\n");
721 return FALSE;
722 }
723
724 LogFile->Header.OldestRecordNumber++;
725
726 /* Check the size of the record as the record adding may be larger */
727 if (RecBuf->Length >= BufSize)
728 {
729 DPRINT1("Record will fit\n");
730 LogFile->Header.StartOffset = LogfOffsetByNumber(LogFile, LogFile->Header.OldestRecordNumber);
731 break;
732 }
733 else
734 {
735 DPRINT1("Record wont fit\n");
736 }
737 }
738 HeapFree(GetProcessHeap(), 0, RecBuf);
739 }
740
741 if (SetFilePointer(LogFile->hFile,
742 LogFile->Header.EndOffset,
743 NULL,
744 FILE_BEGIN) == INVALID_SET_FILE_POINTER)
745 {
746 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
747 LeaveCriticalSection(&LogFile->cs);
748 return FALSE;
749 }
750
751 if (!WriteFile(LogFile->hFile, Buffer, BufSize, &dwWritten, NULL))
752 {
753 DPRINT1("WriteFile() failed! %d\n", GetLastError());
754 LeaveCriticalSection(&LogFile->cs);
755 return FALSE;
756 }
757
758 if (!LogfAddOffsetInformation(LogFile,
759 LogFile->Header.CurrentRecordNumber,
760 LogFile->Header.EndOffset))
761 {
762 LeaveCriticalSection(&LogFile->cs);
763 return FALSE;
764 }
765
766 LogFile->Header.CurrentRecordNumber++;
767 LogFile->Header.EndOffset += dwWritten;
768
769 if (LogFile->Header.OldestRecordNumber == 0)
770 LogFile->Header.OldestRecordNumber = 1;
771
772 EofRec.Ones = 0x11111111;
773 EofRec.Twos = 0x22222222;
774 EofRec.Threes = 0x33333333;
775 EofRec.Fours = 0x44444444;
776 EofRec.RecordSizeBeginning = sizeof(EVENTLOGEOF);
777 EofRec.RecordSizeEnd = sizeof(EVENTLOGEOF);
778 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
779 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
780 EofRec.BeginRecord = LogFile->Header.StartOffset;
781 EofRec.EndRecord = LogFile->Header.EndOffset;
782
783 if (!WriteFile(LogFile->hFile,
784 &EofRec,
785 sizeof(EVENTLOGEOF),
786 &dwWritten,
787 NULL))
788 {
789 DPRINT1("WriteFile() failed! %d\n", GetLastError());
790 LeaveCriticalSection(&LogFile->cs);
791 return FALSE;
792 }
793
794 if (SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN) ==
795 INVALID_SET_FILE_POINTER)
796 {
797 DPRINT1("SetFilePointer() failed! %d\n", GetLastError());
798 LeaveCriticalSection(&LogFile->cs);
799 return FALSE;
800 }
801
802 if (!WriteFile(LogFile->hFile,
803 &LogFile->Header,
804 sizeof(EVENTLOGHEADER),
805 &dwWritten,
806 NULL))
807 {
808 DPRINT1("WriteFile failed! LastError = %d\n", GetLastError());
809 LeaveCriticalSection(&LogFile->cs);
810 return FALSE;
811 }
812
813 if (!FlushFileBuffers(LogFile->hFile))
814 {
815 LeaveCriticalSection(&LogFile->cs);
816 DPRINT1("FlushFileBuffers() failed! %d\n", GetLastError());
817 return FALSE;
818 }
819
820 LeaveCriticalSection(&LogFile->cs);
821 return TRUE;
822 }
823
824 ULONG LogfOffsetByNumber(PLOGFILE LogFile, DWORD RecordNumber)
825
826 /* Returns 0 if nothing found. */
827 {
828 DWORD i;
829
830 for (i = 0; i < LogFile->OffsetInfoNext; i++)
831 {
832 if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
833 return LogFile->OffsetInfo[i].EventOffset;
834 }
835 return 0;
836 }
837
838 DWORD LogfGetOldestRecord(PLOGFILE LogFile)
839 {
840 return LogFile->Header.OldestRecordNumber;
841 }
842
843 DWORD LogfGetCurrentRecord(PLOGFILE LogFile)
844 {
845 return LogFile->Header.CurrentRecordNumber;
846 }
847
848 BOOL LogfAddOffsetInformation(PLOGFILE LogFile, ULONG ulNumber, ULONG ulOffset)
849 {
850 LPVOID NewOffsetInfo;
851
852 if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
853 {
854 NewOffsetInfo = HeapReAlloc(MyHeap,
855 HEAP_ZERO_MEMORY,
856 LogFile->OffsetInfo,
857 (LogFile->OffsetInfoSize + 64) *
858 sizeof(EVENT_OFFSET_INFO));
859
860 if (!NewOffsetInfo)
861 {
862 DPRINT1("Can't reallocate heap.\n");
863 return FALSE;
864 }
865
866 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO) NewOffsetInfo;
867 LogFile->OffsetInfoSize += 64;
868 }
869
870 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
871 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
872 LogFile->OffsetInfoNext++;
873
874 return TRUE;
875 }
876
877 PBYTE LogfAllocAndBuildNewRecord(LPDWORD lpRecSize,
878 DWORD dwRecordNumber,
879 WORD wType,
880 WORD wCategory,
881 DWORD dwEventId,
882 LPCWSTR SourceName,
883 LPCWSTR ComputerName,
884 DWORD dwSidLength,
885 PSID lpUserSid,
886 WORD wNumStrings,
887 WCHAR * lpStrings,
888 DWORD dwDataSize,
889 LPVOID lpRawData)
890 {
891 DWORD dwRecSize;
892 PEVENTLOGRECORD pRec;
893 SYSTEMTIME SysTime;
894 WCHAR *str;
895 UINT i, pos, nStrings;
896 PBYTE Buffer;
897
898 dwRecSize =
899 sizeof(EVENTLOGRECORD) + (lstrlenW(ComputerName) +
900 lstrlenW(SourceName) + 2) * sizeof(WCHAR);
901
902 if (dwRecSize % 4 != 0)
903 dwRecSize += 4 - (dwRecSize % 4);
904
905 dwRecSize += dwSidLength;
906
907 for (i = 0, str = lpStrings; i < wNumStrings; i++)
908 {
909 dwRecSize += (lstrlenW(str) + 1) * sizeof(WCHAR);
910 str += lstrlenW(str) + 1;
911 }
912
913 dwRecSize += dwDataSize;
914 if (dwRecSize % 4 != 0)
915 dwRecSize += 4 - (dwRecSize % 4);
916
917 dwRecSize += 4;
918
919 Buffer = (BYTE *) HeapAlloc(MyHeap, HEAP_ZERO_MEMORY, dwRecSize);
920
921 if (!Buffer)
922 {
923 DPRINT1("Can't allocate heap!\n");
924 return NULL;
925 }
926
927 pRec = (PEVENTLOGRECORD) Buffer;
928 pRec->Length = dwRecSize;
929 pRec->Reserved = LOGFILE_SIGNATURE;
930 pRec->RecordNumber = dwRecordNumber;
931
932 GetSystemTime(&SysTime);
933 SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
934 SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
935
936 pRec->EventID = dwEventId;
937 pRec->EventType = wType;
938 pRec->NumStrings = wNumStrings;
939 pRec->EventCategory = wCategory;
940
941 pos = sizeof(EVENTLOGRECORD);
942
943 lstrcpyW((WCHAR *) (Buffer + pos), SourceName);
944 pos += (lstrlenW(SourceName) + 1) * sizeof(WCHAR);
945 lstrcpyW((WCHAR *) (Buffer + pos), ComputerName);
946 pos += (lstrlenW(ComputerName) + 1) * sizeof(WCHAR);
947
948 pRec->UserSidOffset = pos;
949 if (dwSidLength)
950 {
951 if (pos % 4 != 0)
952 pos += 4 - (pos % 4);
953 CopyMemory(Buffer + pos, lpUserSid, dwSidLength);
954 pRec->UserSidLength = dwSidLength;
955 pRec->UserSidOffset = pos;
956 pos += dwSidLength;
957 }
958
959 pRec->StringOffset = pos;
960 for (i = 0, str = lpStrings, nStrings = 0; i < wNumStrings; i++)
961 {
962 lstrcpyW((WCHAR *) (Buffer + pos), str);
963 pos += (lstrlenW(str) + 1) * sizeof(WCHAR);
964 str += lstrlenW(str) + 1;
965 nStrings++;
966 }
967 pRec->NumStrings = nStrings;
968
969 pRec->DataOffset = pos;
970 if (dwDataSize)
971 {
972 pRec->DataLength = dwDataSize;
973 CopyMemory(Buffer + pos, lpRawData, dwDataSize);
974 pos += dwDataSize;
975 }
976
977 if (pos % 4 != 0)
978 pos += 4 - (pos % 4);
979
980 *((PDWORD) (Buffer + pos)) = dwRecSize;
981
982 *lpRecSize = dwRecSize;
983 return Buffer;
984 }