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