ReactOS 0.4.17-dev-470-gf9e3448
evtlib.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS EventLog File Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: sdk/lib/evtlib/evtlib.c
5 * PURPOSE: Provides functionality for reading and writing
6 * EventLog files in the NT <= 5.2 (.evt) format.
7 * PROGRAMMERS: Copyright 2005 Saveliy Tretiakov
8 * Michael Martin
9 * Hermes Belusca-Maito
10 */
11
12/* INCLUDES ******************************************************************/
13
14#include "evtlib.h"
15
16#define NDEBUG
17#include <debug.h>
18
19#define EVTLTRACE(fmt, ...) DPRINT("EvtLib: " fmt, ##__VA_ARGS__)
20// Once things become stabilized enough, replace all the EVTLTRACE1 by EVTLTRACE
21#define EVTLTRACE1(fmt, ...) DPRINT1("EvtLib: " fmt, ##__VA_ARGS__)
22
23
24/* GLOBALS *******************************************************************/
25
26#define EVENTLOG_FILE_GRANULARITY (64 * 1024)
27
28static const EVENTLOGEOF EOFRecord =
29{
30 sizeof(EOFRecord),
31 0x11111111, 0x22222222, 0x33333333, 0x44444444,
32 0, 0, 0, 0,
33 sizeof(EOFRecord)
34};
35
36/* HELPER FUNCTIONS **********************************************************/
37
38static NTSTATUS
40 IN PEVTLOGFILE LogFile,
45 OUT PLARGE_INTEGER NextOffset OPTIONAL)
46{
50 SIZE_T ReadBufLength = 0, OldReadBufLength;
51
52 ASSERT(LogFile->CurrentSize <= LogFile->Header.MaxSize);
53 ASSERT(ByteOffset->QuadPart <= LogFile->CurrentSize);
54
55 if (ReadLength)
56 *ReadLength = 0;
57
58 if (NextOffset)
59 NextOffset->QuadPart = 0LL;
60
61 /* Read the first part of the buffer */
63 BufSize = min(Length, LogFile->CurrentSize - FileOffset.QuadPart);
64
65 Status = LogFile->FileRead(LogFile,
67 Buffer,
68 BufSize,
69 &ReadBufLength);
70 if (!NT_SUCCESS(Status))
71 {
72 EVTLTRACE("FileRead() failed (Status 0x%08lx)\n", Status);
73 return Status;
74 }
75
76 if (Length > BufSize)
77 {
78 OldReadBufLength = ReadBufLength;
79
80 /*
81 * The buffer was splitted in two, its second part
82 * is to be read at the beginning of the log.
83 */
86 FileOffset.QuadPart = sizeof(EVENTLOGHEADER);
87
88 Status = LogFile->FileRead(LogFile,
90 Buffer,
91 BufSize,
92 &ReadBufLength);
93 if (!NT_SUCCESS(Status))
94 {
95 EVTLTRACE("FileRead() failed (Status 0x%08lx)\n", Status);
96 return Status;
97 }
98 /* Add the read number of bytes from the first read */
99 ReadBufLength += OldReadBufLength;
100 }
101
102 if (ReadLength)
103 *ReadLength = ReadBufLength;
104
105 /* We return the offset just after the end of the read buffer */
106 if (NextOffset)
107 NextOffset->QuadPart = FileOffset.QuadPart + BufSize;
108
109 return Status;
110}
111
112static NTSTATUS
114 IN PEVTLOGFILE LogFile,
117 OUT PSIZE_T WrittenLength OPTIONAL,
119 OUT PLARGE_INTEGER NextOffset OPTIONAL)
120{
124 SIZE_T WrittenBufLength = 0, OldWrittenBufLength;
125
126 /* We must have write access to the log file */
127 ASSERT(!LogFile->ReadOnly);
128
129 /*
130 * It is expected that the log file is already correctly expanded
131 * before we can write in it. Therefore the following assertions hold.
132 */
133 ASSERT(LogFile->CurrentSize <= LogFile->Header.MaxSize);
134 ASSERT(ByteOffset->QuadPart <= LogFile->CurrentSize);
135
136 if (WrittenLength)
137 *WrittenLength = 0;
138
139 if (NextOffset)
140 NextOffset->QuadPart = 0LL;
141
142 /* Write the first part of the buffer */
144 BufSize = min(Length, LogFile->CurrentSize - FileOffset.QuadPart);
145
146 Status = LogFile->FileWrite(LogFile,
147 &FileOffset,
148 Buffer,
149 BufSize,
150 &WrittenBufLength);
151 if (!NT_SUCCESS(Status))
152 {
153 EVTLTRACE("FileWrite() failed (Status 0x%08lx)\n", Status);
154 return Status;
155 }
156
157 if (Length > BufSize)
158 {
159 OldWrittenBufLength = WrittenBufLength;
160
161 /*
162 * The buffer was splitted in two, its second part
163 * is written at the beginning of the log.
164 */
167 FileOffset.QuadPart = sizeof(EVENTLOGHEADER);
168
169 Status = LogFile->FileWrite(LogFile,
170 &FileOffset,
171 Buffer,
172 BufSize,
173 &WrittenBufLength);
174 if (!NT_SUCCESS(Status))
175 {
176 EVTLTRACE("FileWrite() failed (Status 0x%08lx)\n", Status);
177 return Status;
178 }
179 /* Add the written number of bytes from the first write */
180 WrittenBufLength += OldWrittenBufLength;
181
182 /* The log wraps */
183 LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
184 }
185
186 if (WrittenLength)
187 *WrittenLength = WrittenBufLength;
188
189 /* We return the offset just after the end of the written buffer */
190 if (NextOffset)
191 NextOffset->QuadPart = FileOffset.QuadPart + BufSize;
192
193 return Status;
194}
195
196
197/* Returns 0 if nothing is found */
198static ULONG
200 IN PEVTLOGFILE LogFile,
201 IN ULONG RecordNumber)
202{
203 UINT i;
204
205 for (i = 0; i < LogFile->OffsetInfoNext; i++)
206 {
207 if (LogFile->OffsetInfo[i].EventNumber == RecordNumber)
208 return LogFile->OffsetInfo[i].EventOffset;
209 }
210 return 0;
211}
212
213#define OFFSET_INFO_INCREMENT 64
214
215static BOOL
217 IN PEVTLOGFILE LogFile,
218 IN ULONG ulNumber,
219 IN ULONG ulOffset)
220{
221 PVOID NewOffsetInfo;
222
223 if (LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
224 {
225 /* Allocate a new offset table */
226 NewOffsetInfo = LogFile->Allocate((LogFile->OffsetInfoSize + OFFSET_INFO_INCREMENT) *
227 sizeof(EVENT_OFFSET_INFO),
229 TAG_ELF);
230 if (!NewOffsetInfo)
231 {
232 EVTLTRACE1("Cannot reallocate heap.\n");
233 return FALSE;
234 }
235
236 /* Free the old offset table and use the new one */
237 if (LogFile->OffsetInfo)
238 {
239 /* Copy the handles from the old table to the new one */
240 RtlCopyMemory(NewOffsetInfo,
241 LogFile->OffsetInfo,
242 LogFile->OffsetInfoSize * sizeof(EVENT_OFFSET_INFO));
243 LogFile->Free(LogFile->OffsetInfo, 0, TAG_ELF);
244 }
245 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO)NewOffsetInfo;
246 LogFile->OffsetInfoSize += OFFSET_INFO_INCREMENT;
247 }
248
249 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
250 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
251 LogFile->OffsetInfoNext++;
252
253 return TRUE;
254}
255
256static BOOL
258 IN PEVTLOGFILE LogFile,
259 IN ULONG ulNumberMin,
260 IN ULONG ulNumberMax)
261{
262 UINT i;
263
264 if (ulNumberMin > ulNumberMax)
265 return FALSE;
266
267 /* Remove records ulNumberMin to ulNumberMax inclusive */
268 while (ulNumberMin <= ulNumberMax)
269 {
270 /*
271 * As the offset information is listed in increasing order, and we want
272 * to keep the list without holes, we demand that ulNumberMin is the first
273 * element in the list.
274 */
275 if (ulNumberMin != LogFile->OffsetInfo[0].EventNumber)
276 return FALSE;
277
278 /*
279 * RtlMoveMemory(&LogFile->OffsetInfo[0],
280 * &LogFile->OffsetInfo[1],
281 * sizeof(EVENT_OFFSET_INFO) * (LogFile->OffsetInfoNext - 1));
282 */
283 for (i = 0; i < LogFile->OffsetInfoNext - 1; i++)
284 {
285 LogFile->OffsetInfo[i].EventNumber = LogFile->OffsetInfo[i + 1].EventNumber;
286 LogFile->OffsetInfo[i].EventOffset = LogFile->OffsetInfo[i + 1].EventOffset;
287 }
288 LogFile->OffsetInfoNext--;
289
290 /* Go to the next offset information */
291 ulNumberMin++;
292 }
293
294 return TRUE;
295}
296
297
298static NTSTATUS
300 IN PEVTLOGFILE LogFile,
302 IN ULONG MaxSize,
303 IN ULONG Retention)
304{
307 SIZE_T WrittenLength;
308 EVENTLOGEOF EofRec;
309 ULONG InitialSize;
310
311 /* Initialize the event log header */
312 RtlZeroMemory(&LogFile->Header, sizeof(EVENTLOGHEADER));
313
314 LogFile->Header.HeaderSize = sizeof(EVENTLOGHEADER);
315 LogFile->Header.Signature = LOGFILE_SIGNATURE;
316 LogFile->Header.MajorVersion = MAJORVER;
317 LogFile->Header.MinorVersion = MINORVER;
318
319 /* Set the offset to the oldest record */
320 LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
321 /* Set the offset to the ELF_EOF_RECORD */
322 LogFile->Header.EndOffset = sizeof(EVENTLOGHEADER);
323 /* Set the number of the next record that will be added */
324 LogFile->Header.CurrentRecordNumber = 1;
325 /* The event log is empty, there is no record so far */
326 LogFile->Header.OldestRecordNumber = 0;
327
328 /*
329 * Windows keeps the file size in 64 kB chunks. The used log area is tracked
330 * by the header offsets and the EOF record, not by the physical file EOF.
331 */
332 InitialSize = sizeof(EVENTLOGHEADER) + sizeof(EVENTLOGEOF); // TODO: Consider FileSize as well.
333 InitialSize = ROUND_UP(InitialSize, EVENTLOG_FILE_GRANULARITY);
334 LogFile->CurrentSize = InitialSize;
335 Status = LogFile->FileSetSize(LogFile, LogFile->CurrentSize, FileSize);
336 if (!NT_SUCCESS(Status))
337 {
338 EVTLTRACE1("FileSetSize() failed (Status 0x%08lx)\n", Status);
339 return Status;
340 }
341
342 /* Ensure that the log maximum size is greater than the initial file size */
343 MaxSize = max(MaxSize, InitialSize);
344 LogFile->Header.MaxSize = ROUND_UP(MaxSize, EVENTLOG_FILE_GRANULARITY);
345
346 LogFile->Header.Flags = 0;
347 LogFile->Header.Retention = Retention;
348 LogFile->Header.EndHeaderSize = sizeof(EVENTLOGHEADER);
349
350 /* Write the header */
351 FileOffset.QuadPart = 0LL;
352 Status = LogFile->FileWrite(LogFile,
353 &FileOffset,
354 &LogFile->Header,
355 sizeof(EVENTLOGHEADER),
356 &WrittenLength);
357 if (!NT_SUCCESS(Status))
358 {
359 EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
360 return Status;
361 }
362
363 /* Initialize the ELF_EOF_RECORD and write it */
364 RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
365 EofRec.BeginRecord = LogFile->Header.StartOffset;
366 EofRec.EndRecord = LogFile->Header.EndOffset;
367 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
368 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
369
370 Status = LogFile->FileWrite(LogFile,
371 NULL,
372 &EofRec,
373 sizeof(EofRec),
374 &WrittenLength);
375 if (!NT_SUCCESS(Status))
376 {
377 EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
378 return Status;
379 }
380
381 Status = LogFile->FileFlush(LogFile, NULL, 0);
382 if (!NT_SUCCESS(Status))
383 {
384 EVTLTRACE1("FileFlush() failed (Status 0x%08lx)\n", Status);
385 return Status;
386 }
387
388 return STATUS_SUCCESS;
389}
390
391static NTSTATUS
393 IN PEVTLOGFILE LogFile,
395 // IN ULONG MaxSize,
396 IN ULONG Retention)
397{
399 LARGE_INTEGER FileOffset, NextOffset;
401 ULONG RecordNumber = 0;
402 ULONG RecOffset;
403 PULONG pRecSize2;
404 EVENTLOGEOF EofRec;
405 EVENTLOGRECORD RecBuf;
406 PEVENTLOGRECORD pRecBuf;
407 BOOLEAN Wrapping = FALSE;
408 BOOLEAN IsLogDirty = FALSE;
409
410 /* Read the log header */
411 FileOffset.QuadPart = 0LL;
412 Status = LogFile->FileRead(LogFile,
413 &FileOffset,
414 &LogFile->Header,
415 sizeof(EVENTLOGHEADER),
416 &ReadLength);
417 if (!NT_SUCCESS(Status))
418 {
419 EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
420 return STATUS_EVENTLOG_FILE_CORRUPT; // return Status;
421 }
422 if (ReadLength != sizeof(EVENTLOGHEADER))
423 {
424 EVTLTRACE("Invalid file `%wZ'.\n", &LogFile->FileName);
426 }
427
428 /* Header validity checks */
429
430 if (LogFile->Header.HeaderSize != sizeof(EVENTLOGHEADER) ||
431 LogFile->Header.EndHeaderSize != sizeof(EVENTLOGHEADER))
432 {
433 EVTLTRACE("Invalid header size in `%wZ'.\n", &LogFile->FileName);
435 }
436
437 if (LogFile->Header.Signature != LOGFILE_SIGNATURE)
438 {
439 EVTLTRACE("Invalid signature %x in `%wZ'.\n",
440 LogFile->Header.Signature, &LogFile->FileName);
442 }
443
444 IsLogDirty = (LogFile->Header.Flags & ELF_LOGFILE_HEADER_DIRTY);
445
446 /* If the log is read-only (e.g. a backup log) and is dirty, then it is corrupted */
447 if (LogFile->ReadOnly && IsLogDirty)
448 {
449 EVTLTRACE("Read-only log `%wZ' is dirty.\n", &LogFile->FileName);
451 }
452
453 LogFile->CurrentSize = FileSize;
454 // FIXME!! What to do? And what to do if the MaxSize from the registry
455 // is strictly less than the CurrentSize?? Should we "reduce" the log size
456 // by clearing it completely??
457 // --> ANSWER: Save the new MaxSize somewhere, and only when the log is
458 // being cleared, use the new MaxSize to resize (ie. shrink) it.
459 // LogFile->FileSetSize(LogFile, LogFile->CurrentSize, 0);
460
461 /* Adjust the log maximum size if needed */
462 if (LogFile->CurrentSize > LogFile->Header.MaxSize)
463 LogFile->Header.MaxSize = LogFile->CurrentSize;
464
465 /*
466 * Reset the log retention value. The value stored
467 * in the log file is just for information purposes.
468 */
469 LogFile->Header.Retention = Retention;
470
471 /*
472 * For a non-read-only dirty log, the most up-to-date information about
473 * the Start/End offsets and the Oldest and Current event record numbers
474 * are found in the EOF record. We need to locate the EOF record without
475 * relying on the log header's EndOffset, then patch the log header with
476 * the values from the EOF record.
477 */
478 if ((LogFile->Header.EndOffset >= sizeof(EVENTLOGHEADER)) &&
479 (LogFile->Header.EndOffset < LogFile->CurrentSize) &&
480 (LogFile->Header.EndOffset & 3) == 0) // EndOffset % sizeof(ULONG) == 0
481 {
482 /* The header EOF offset may be valid, try to start with it */
483 RecOffset = LogFile->Header.EndOffset;
484 }
485 else
486 {
487 /* The header EOF offset could not be valid, so start from the beginning */
488 RecOffset = sizeof(EVENTLOGHEADER);
489 }
490
491 FileOffset.QuadPart = RecOffset;
492 Wrapping = FALSE;
493
494 for (;;)
495 {
496 if (Wrapping && FileOffset.QuadPart >= RecOffset)
497 {
498 EVTLTRACE1("EOF record not found!\n");
500 }
501
502 /* Attempt to read the fixed part of an EVENTLOGEOF (may wrap) */
503 Status = ReadLogBuffer(LogFile,
504 &EofRec,
506 &ReadLength,
507 &FileOffset,
508 NULL);
509 if (!NT_SUCCESS(Status))
510 {
511 EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
513 }
515 {
516 EVTLTRACE1("Cannot read at most an EOF record!\n");
518 }
519
520 /* Is it an EVENTLOGEOF record? */
522 {
523 DPRINT("Found EOF record at %llx\n", FileOffset.QuadPart);
524
525 /* Got it! Break the loop and continue */
526 break;
527 }
528
529 /* No, continue looping */
530 if (*(PULONG)((ULONG_PTR)&EofRec + sizeof(ULONG)) == *(PULONG)(&EOFRecord))
531 FileOffset.QuadPart += sizeof(ULONG);
532 else
533 if (*(PULONG)((ULONG_PTR)&EofRec + 2*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
534 FileOffset.QuadPart += 2*sizeof(ULONG);
535 else
536 if (*(PULONG)((ULONG_PTR)&EofRec + 3*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
537 FileOffset.QuadPart += 3*sizeof(ULONG);
538 else
539 if (*(PULONG)((ULONG_PTR)&EofRec + 4*sizeof(ULONG)) == *(PULONG)(&EOFRecord))
540 FileOffset.QuadPart += 4*sizeof(ULONG);
541 else
542 FileOffset.QuadPart += 5*sizeof(ULONG); // EVENTLOGEOF_SIZE_FIXED
543
544 if (FileOffset.QuadPart >= LogFile->CurrentSize /* LogFile->Header.MaxSize */)
545 {
546 /* Wrap the offset */
547 FileOffset.QuadPart -= LogFile->CurrentSize /* LogFile->Header.MaxSize */ - sizeof(EVENTLOGHEADER);
548 Wrapping = TRUE;
549 }
550 }
551 /*
552 * The only way to be there is to have found a valid EOF record.
553 * Otherwise the previous loop has failed and STATUS_EVENTLOG_FILE_CORRUPT
554 * was returned.
555 */
556
557 /* Read the full EVENTLOGEOF (may wrap) and validate it */
558 Status = ReadLogBuffer(LogFile,
559 &EofRec,
560 sizeof(EofRec),
561 &ReadLength,
562 &FileOffset,
563 NULL);
564 if (!NT_SUCCESS(Status))
565 {
566 EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
568 }
569 if (ReadLength != sizeof(EofRec))
570 {
571 EVTLTRACE1("Cannot read the full EOF record!\n");
573 }
574
575 /* Complete validity checks */
576 if ((EofRec.RecordSizeEnd != EofRec.RecordSizeBeginning) ||
577 (EofRec.EndRecord != FileOffset.QuadPart))
578 {
579 DPRINT1("EOF record %llx is corrupted (0x%x vs. 0x%x ; 0x%x vs. 0x%llx), expected 0x%x 0x%x!\n",
580 FileOffset.QuadPart,
581 EofRec.RecordSizeEnd, EofRec.RecordSizeBeginning,
582 EofRec.EndRecord, FileOffset.QuadPart,
584 DPRINT1("RecordSizeEnd = 0x%x\n", EofRec.RecordSizeEnd);
585 DPRINT1("RecordSizeBeginning = 0x%x\n", EofRec.RecordSizeBeginning);
586 DPRINT1("EndRecord = 0x%x\n", EofRec.EndRecord);
588 }
589
590 /* The EOF record is valid, break the loop and continue */
591
592 /* If the log is not dirty, the header values should correspond to the EOF ones */
593 if (!IsLogDirty)
594 {
595 if ( (LogFile->Header.StartOffset != EofRec.BeginRecord) ||
596 (LogFile->Header.EndOffset != EofRec.EndRecord) ||
597 (LogFile->Header.CurrentRecordNumber != EofRec.CurrentRecordNumber) ||
598 (LogFile->Header.OldestRecordNumber != EofRec.OldestRecordNumber) )
599 {
600 DPRINT1("\n"
601 "Log header or EOF record is corrupted:\n"
602 " StartOffset: 0x%x, expected 0x%x; EndOffset: 0x%x, expected 0x%x;\n"
603 " CurrentRecordNumber: %d, expected %d; OldestRecordNumber: %d, expected %d.\n",
604 LogFile->Header.StartOffset, EofRec.BeginRecord,
605 LogFile->Header.EndOffset , EofRec.EndRecord,
606 LogFile->Header.CurrentRecordNumber, EofRec.CurrentRecordNumber,
607 LogFile->Header.OldestRecordNumber , EofRec.OldestRecordNumber);
608
610 }
611 }
612
613 /* If the log is dirty, patch the log header with the values from the EOF record */
614 if (!LogFile->ReadOnly && IsLogDirty)
615 {
616 LogFile->Header.StartOffset = EofRec.BeginRecord;
617 LogFile->Header.EndOffset = EofRec.EndRecord;
618 LogFile->Header.CurrentRecordNumber = EofRec.CurrentRecordNumber;
619 LogFile->Header.OldestRecordNumber = EofRec.OldestRecordNumber;
620 }
621
622 /*
623 * FIXME! During operations the EOF record is the one that is the most
624 * updated (its Oldest & Current record numbers are always up-to
625 * date) while the ones from the header may be unsync. When closing
626 * (or flushing?) the event log, the header's record numbers get
627 * updated with the same values as the ones stored in the EOF record.
628 */
629
630 /* Verify Start/End offsets boundaries */
631
632 if ((LogFile->Header.StartOffset >= LogFile->CurrentSize) ||
633 (LogFile->Header.StartOffset & 3) != 0) // StartOffset % sizeof(ULONG) != 0
634 {
635 EVTLTRACE("Invalid start offset 0x%x in `%wZ'.\n",
636 LogFile->Header.StartOffset, &LogFile->FileName);
638 }
639 if ((LogFile->Header.EndOffset >= LogFile->CurrentSize) ||
640 (LogFile->Header.EndOffset & 3) != 0) // EndOffset % sizeof(ULONG) != 0
641 {
642 EVTLTRACE("Invalid EOF offset 0x%x in `%wZ'.\n",
643 LogFile->Header.EndOffset, &LogFile->FileName);
645 }
646
647 if ((LogFile->Header.StartOffset != LogFile->Header.EndOffset) &&
648 (LogFile->Header.MaxSize - LogFile->Header.StartOffset < sizeof(EVENTLOGRECORD)))
649 {
650 /*
651 * If StartOffset does not point to EndOffset i.e. to an EVENTLOGEOF,
652 * it should point to a non-splitted EVENTLOGRECORD.
653 */
654 EVTLTRACE("Invalid start offset 0x%x in `%wZ'.\n",
655 LogFile->Header.StartOffset, &LogFile->FileName);
657 }
658
659 if ((LogFile->Header.StartOffset < LogFile->Header.EndOffset) &&
660 (LogFile->Header.EndOffset - LogFile->Header.StartOffset < sizeof(EVENTLOGRECORD)))
661 {
662 /*
663 * In non-wrapping case, there must be enough space between StartOffset
664 * and EndOffset to contain at least a full EVENTLOGRECORD.
665 */
666 EVTLTRACE("Invalid start offset 0x%x or end offset 0x%x in `%wZ'.\n",
667 LogFile->Header.StartOffset, LogFile->Header.EndOffset, &LogFile->FileName);
669 }
670
671 if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
672 {
673 /*
674 * Non-wrapping case: the (wrapping) free space starting at EndOffset
675 * must be able to contain an EVENTLOGEOF.
676 */
677 if (LogFile->Header.MaxSize - LogFile->Header.EndOffset +
678 LogFile->Header.StartOffset - sizeof(EVENTLOGHEADER) < sizeof(EVENTLOGEOF))
679 {
680 EVTLTRACE("Invalid EOF offset 0x%x in `%wZ'.\n",
681 LogFile->Header.EndOffset, &LogFile->FileName);
683 }
684 }
685 else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
686 {
687 /*
688 * Wrapping case: the free space between EndOffset and StartOffset
689 * must be able to contain an EVENTLOGEOF.
690 */
691 if (LogFile->Header.StartOffset - LogFile->Header.EndOffset < sizeof(EVENTLOGEOF))
692 {
693 EVTLTRACE("Invalid EOF offset 0x%x in `%wZ'.\n",
694 LogFile->Header.EndOffset, &LogFile->FileName);
696 }
697 }
698
699 /* Start enumerating the event records from the beginning */
700 RecOffset = LogFile->Header.StartOffset;
701 FileOffset.QuadPart = RecOffset;
702 Wrapping = FALSE;
703
704 // // FIXME! FIXME!
705 // if (!(LogFile->Header.Flags & ELF_LOGFILE_HEADER_WRAP))
706 // {
707 // DPRINT1("Log file was wrapping but the flag was not set! Fixing...\n");
708 // LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
709 // }
710
711 DPRINT("StartOffset = 0x%x, EndOffset = 0x%x\n",
712 LogFile->Header.StartOffset, LogFile->Header.EndOffset);
713
714 /*
715 * For non-read-only logs of size < MaxSize, reorganize the events
716 * such that they do not wrap as soon as we write new ones.
717 */
718#if 0
719 if (!LogFile->ReadOnly)
720 {
721 pRecBuf = LogFile->Allocate(RecBuf.Length, 0, TAG_ELF_BUF);
722 if (pRecBuf == NULL)
723 {
724 DPRINT1("Cannot allocate temporary buffer, skip event reorganization.\n");
725 goto Continue;
726 }
727
728 // TODO: Do the job!
729 }
730
731Continue:
732
733 DPRINT1("StartOffset = 0x%x, EndOffset = 0x%x\n",
734 LogFile->Header.StartOffset, LogFile->Header.EndOffset);
735#endif
736
737 while (FileOffset.QuadPart != LogFile->Header.EndOffset)
738 {
739 if (Wrapping && FileOffset.QuadPart >= RecOffset)
740 {
741 /* We have finished enumerating all the event records */
742 break;
743 }
744
745 /* Read the next EVENTLOGRECORD header at once (it cannot be split) */
746 Status = LogFile->FileRead(LogFile,
747 &FileOffset,
748 &RecBuf,
749 sizeof(RecBuf),
750 &ReadLength);
751 if (!NT_SUCCESS(Status))
752 {
753 EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
755 }
756 if (ReadLength != sizeof(RecBuf))
757 {
758 DPRINT1("Length != sizeof(RecBuf)\n");
759 break;
760 }
761
762 if (RecBuf.Reserved != LOGFILE_SIGNATURE ||
763 RecBuf.Length < sizeof(EVENTLOGRECORD))
764 {
765 DPRINT1("RecBuf problem\n");
766 break;
767 }
768
769 /* Allocate a full EVENTLOGRECORD (header + data) */
770 pRecBuf = LogFile->Allocate(RecBuf.Length, 0, TAG_ELF_BUF);
771 if (pRecBuf == NULL)
772 {
773 EVTLTRACE1("Cannot allocate heap!\n");
774 return STATUS_NO_MEMORY;
775 }
776
777 /* Attempt to read the full EVENTLOGRECORD (can wrap) */
778 Status = ReadLogBuffer(LogFile,
779 pRecBuf,
780 RecBuf.Length,
781 &ReadLength,
782 &FileOffset,
783 &NextOffset);
784 if (!NT_SUCCESS(Status))
785 {
786 EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
787 LogFile->Free(pRecBuf, 0, TAG_ELF_BUF);
789 }
790 if (ReadLength != RecBuf.Length)
791 {
792 DPRINT1("Oh oh!!\n");
793 LogFile->Free(pRecBuf, 0, TAG_ELF_BUF);
794 break;
795 }
796
797 // /* If OverWrittenRecords is TRUE and this record has already been read */
798 // if (OverWrittenRecords && (pRecBuf->RecordNumber == LogFile->Header.OldestRecordNumber))
799 // {
800 // LogFile->Free(pRecBuf, 0, TAG_ELF_BUF);
801 // break;
802 // }
803
804 pRecSize2 = (PULONG)((ULONG_PTR)pRecBuf + RecBuf.Length - 4);
805
806 if (*pRecSize2 != RecBuf.Length)
807 {
808 EVTLTRACE1("Invalid RecordSizeEnd of record %d (0x%x) in `%wZ'\n",
809 RecordNumber, *pRecSize2, &LogFile->FileName);
810 LogFile->Free(pRecBuf, 0, TAG_ELF_BUF);
811 break;
812 }
813
814 EVTLTRACE("Add new record %d @ offset 0x%x\n", pRecBuf->RecordNumber, FileOffset.QuadPart);
815
816 RecordNumber++;
817
818 if (!ElfpAddOffsetInformation(LogFile,
819 pRecBuf->RecordNumber,
820 FileOffset.QuadPart))
821 {
822 EVTLTRACE1("ElfpAddOffsetInformation() failed!\n");
823 LogFile->Free(pRecBuf, 0, TAG_ELF_BUF);
825 }
826
827 LogFile->Free(pRecBuf, 0, TAG_ELF_BUF);
828
829 if (NextOffset.QuadPart == LogFile->Header.EndOffset)
830 {
831 /* We have finished enumerating all the event records */
832 DPRINT("NextOffset.QuadPart == LogFile->Header.EndOffset, break\n");
833 break;
834 }
835
836 /*
837 * If this was the last event record before the end of the log file,
838 * the next one should start at the beginning of the log and the space
839 * between the last event record and the end of the file is padded.
840 */
841 if (LogFile->Header.MaxSize - NextOffset.QuadPart < sizeof(EVENTLOGRECORD))
842 {
843 /* Wrap to the beginning of the log */
844 DPRINT("Wrap!\n");
845 NextOffset.QuadPart = sizeof(EVENTLOGHEADER);
846 }
847
848 /*
849 * If the next offset to read is below the current offset,
850 * this means we are wrapping.
851 */
852 if (FileOffset.QuadPart > NextOffset.QuadPart)
853 {
854 DPRINT("Wrapping = TRUE;\n");
855 Wrapping = TRUE;
856 }
857
858 /* Move the current offset */
859 FileOffset = NextOffset;
860 }
861
862 /* If the event log was empty, it will now contain one record */
863 if (RecordNumber != 0 && LogFile->Header.OldestRecordNumber == 0)
864 LogFile->Header.OldestRecordNumber = 1;
865
866 LogFile->Header.CurrentRecordNumber = RecordNumber + LogFile->Header.OldestRecordNumber;
867 if (LogFile->Header.CurrentRecordNumber == 0)
868 LogFile->Header.CurrentRecordNumber = 1;
869
870 /* Flush the log if it is not read-only */
871 if (!LogFile->ReadOnly)
872 {
873 Status = ElfFlushFile(LogFile);
874 if (!NT_SUCCESS(Status))
875 {
876 EVTLTRACE1("ElfFlushFile() failed (Status 0x%08lx)\n", Status);
877 return STATUS_EVENTLOG_FILE_CORRUPT; // Status;
878 }
879 }
880
881 return STATUS_SUCCESS;
882}
883
884
885/* FUNCTIONS *****************************************************************/
886
888NTAPI
890 IN OUT PEVTLOGFILE LogFile,
893 IN ULONG MaxSize,
894 IN ULONG Retention,
895 IN BOOLEAN CreateNew,
899 IN PELF_FILE_SET_SIZE_ROUTINE FileSetSize,
900 IN PELF_FILE_WRITE_ROUTINE FileWrite,
901 IN PELF_FILE_READ_ROUTINE FileRead,
902 IN PELF_FILE_FLUSH_ROUTINE FileFlush) // What about Seek ??
903{
905
906 ASSERT(LogFile);
907
908 /* Creating a new log file with the 'ReadOnly' flag set is incompatible */
909 if (CreateNew && ReadOnly)
911
912 RtlZeroMemory(LogFile, sizeof(*LogFile));
913
914 LogFile->Allocate = Allocate;
915 LogFile->Free = Free;
916 LogFile->FileSetSize = FileSetSize;
917 LogFile->FileWrite = FileWrite;
918 LogFile->FileRead = FileRead;
919 LogFile->FileFlush = FileFlush;
920
921 /* Copy the log file name if provided (optional) */
922 RtlInitEmptyUnicodeString(&LogFile->FileName, NULL, 0);
923 if (FileName && FileName->Buffer && FileName->Length &&
924 (FileName->Length <= FileName->MaximumLength))
925 {
926 LogFile->FileName.Buffer = LogFile->Allocate(FileName->Length,
928 TAG_ELF);
929 if (LogFile->FileName.Buffer)
930 {
931 LogFile->FileName.MaximumLength = FileName->Length;
932 RtlCopyUnicodeString(&LogFile->FileName, FileName);
933 }
934 }
935
936 LogFile->OffsetInfo = LogFile->Allocate(OFFSET_INFO_INCREMENT * sizeof(EVENT_OFFSET_INFO),
938 TAG_ELF);
939 if (LogFile->OffsetInfo == NULL)
940 {
941 EVTLTRACE1("Cannot allocate heap\n");
943 goto Quit;
944 }
945 LogFile->OffsetInfoSize = OFFSET_INFO_INCREMENT;
946 LogFile->OffsetInfoNext = 0;
947
948 // FIXME: Always use the regitry values for MaxSize,
949 // even for existing logs!
950
951 // FIXME: On Windows, EventLog uses the MaxSize setting
952 // from the registry itself; the MaxSize from the header
953 // is just for information purposes.
954
955 EVTLTRACE("Initializing log file `%wZ'\n", &LogFile->FileName);
956
957 LogFile->ReadOnly = ReadOnly; // !CreateNew && ReadOnly;
958
959 if (CreateNew)
960 Status = ElfpInitNewFile(LogFile, FileSize, MaxSize, Retention);
961 else
962 Status = ElfpInitExistingFile(LogFile, FileSize, /* MaxSize, */ Retention);
963
964Quit:
965 if (!NT_SUCCESS(Status))
966 {
967 if (LogFile->OffsetInfo)
968 LogFile->Free(LogFile->OffsetInfo, 0, TAG_ELF);
969
970 if (LogFile->FileName.Buffer)
971 LogFile->Free(LogFile->FileName.Buffer, 0, TAG_ELF);
972 }
973
974 return Status;
975}
976
978NTAPI
980 IN PEVTLOGFILE LogFile)
981{
982 ASSERT(LogFile);
983
984 return ElfpInitNewFile(LogFile,
985 LogFile->CurrentSize,
986 LogFile->Header.MaxSize,
987 LogFile->Header.Retention);
988}
989
991NTAPI
993 IN PEVTLOGFILE LogFile,
994 IN PEVTLOGFILE BackupLogFile)
995{
997
999 SIZE_T ReadLength, WrittenLength;
1001 EVENTLOGRECORD RecBuf;
1002 EVENTLOGEOF EofRec;
1003 ULONG i;
1004 ULONG RecOffset;
1005 PVOID Buffer = NULL;
1006
1007 ASSERT(LogFile);
1008
1009 RtlZeroMemory(BackupLogFile, sizeof(*BackupLogFile));
1010
1011 BackupLogFile->FileSetSize = LogFile->FileSetSize;
1012 BackupLogFile->FileWrite = LogFile->FileWrite;
1013 BackupLogFile->FileFlush = LogFile->FileFlush;
1014
1015 // BackupLogFile->CurrentSize = LogFile->CurrentSize;
1016
1017 BackupLogFile->ReadOnly = FALSE;
1018
1019 /* Initialize the (dirty) log file header */
1020 Header = &BackupLogFile->Header;
1021 Header->HeaderSize = sizeof(EVENTLOGHEADER);
1022 Header->Signature = LOGFILE_SIGNATURE;
1023 Header->MajorVersion = MAJORVER;
1024 Header->MinorVersion = MINORVER;
1025 Header->StartOffset = sizeof(EVENTLOGHEADER);
1026 Header->EndOffset = sizeof(EVENTLOGHEADER);
1027 Header->CurrentRecordNumber = 1;
1028 Header->OldestRecordNumber = 0;
1029 Header->MaxSize = LogFile->Header.MaxSize;
1031 Header->Retention = LogFile->Header.Retention;
1032 Header->EndHeaderSize = sizeof(EVENTLOGHEADER);
1033
1034 /* Write the (dirty) log file header */
1035 FileOffset.QuadPart = 0LL;
1036 Status = BackupLogFile->FileWrite(BackupLogFile,
1037 &FileOffset,
1038 Header,
1039 sizeof(EVENTLOGHEADER),
1040 &WrittenLength);
1041 if (!NT_SUCCESS(Status))
1042 {
1043 EVTLTRACE1("Failed to write the log file header (Status 0x%08lx)\n", Status);
1044 goto Quit;
1045 }
1046
1047 for (i = LogFile->Header.OldestRecordNumber; i < LogFile->Header.CurrentRecordNumber; i++)
1048 {
1049 RecOffset = ElfpOffsetByNumber(LogFile, i);
1050 if (RecOffset == 0)
1051 break;
1052
1053 /* Read the next EVENTLOGRECORD header at once (it cannot be split) */
1054 FileOffset.QuadPart = RecOffset;
1055 Status = LogFile->FileRead(LogFile,
1056 &FileOffset,
1057 &RecBuf,
1058 sizeof(RecBuf),
1059 &ReadLength);
1060 if (!NT_SUCCESS(Status))
1061 {
1062 EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
1063 goto Quit;
1064 }
1065
1066 // if (ReadLength != sizeof(RecBuf))
1067 // break;
1068
1069 Buffer = LogFile->Allocate(RecBuf.Length, 0, TAG_ELF_BUF);
1070 if (Buffer == NULL)
1071 {
1072 EVTLTRACE1("Allocate() failed!\n");
1073 goto Quit;
1074 }
1075
1076 /* Read the full EVENTLOGRECORD (header + data) with wrapping */
1077 Status = ReadLogBuffer(LogFile,
1078 Buffer,
1079 RecBuf.Length,
1080 &ReadLength,
1081 &FileOffset,
1082 NULL);
1083 if (!NT_SUCCESS(Status))
1084 {
1085 EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
1086 LogFile->Free(Buffer, 0, TAG_ELF_BUF);
1087 // Status = STATUS_EVENTLOG_FILE_CORRUPT;
1088 goto Quit;
1089 }
1090
1091 /* Write the event record (no wrap for the backup log) */
1092 Status = BackupLogFile->FileWrite(BackupLogFile,
1093 NULL,
1094 Buffer,
1095 RecBuf.Length,
1096 &WrittenLength);
1097 if (!NT_SUCCESS(Status))
1098 {
1099 EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
1100 LogFile->Free(Buffer, 0, TAG_ELF_BUF);
1101 goto Quit;
1102 }
1103
1104 /* Update the header information */
1105 Header->EndOffset += RecBuf.Length;
1106
1107 /* Free the buffer */
1108 LogFile->Free(Buffer, 0, TAG_ELF_BUF);
1109 Buffer = NULL;
1110 }
1111
1112// Quit:
1113
1114 /* Initialize the ELF_EOF_RECORD and write it (no wrap for the backup log) */
1115 RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
1116 EofRec.BeginRecord = Header->StartOffset;
1117 EofRec.EndRecord = Header->EndOffset;
1118 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1119 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1120
1121 Status = BackupLogFile->FileWrite(BackupLogFile,
1122 NULL,
1123 &EofRec,
1124 sizeof(EofRec),
1125 &WrittenLength);
1126 if (!NT_SUCCESS(Status))
1127 {
1128 EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
1129 goto Quit;
1130 }
1131
1132 /* Update the header information */
1133 Header->CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1134 Header->OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1135 Header->MaxSize = ROUND_UP(Header->EndOffset + sizeof(EofRec), sizeof(ULONG));
1136 Header->Flags = 0; // FIXME?
1137
1138 /* Flush the log file - Write the (clean) log file header */
1139 Status = ElfFlushFile(BackupLogFile);
1140
1141Quit:
1142 return Status;
1143}
1144
1146NTAPI
1148 IN PEVTLOGFILE LogFile)
1149{
1152 SIZE_T WrittenLength;
1153
1154 ASSERT(LogFile);
1155
1156 if (LogFile->ReadOnly)
1157 return STATUS_SUCCESS; // STATUS_ACCESS_DENIED;
1158
1159 /*
1160 * NOTE that both the EOF record *AND* the log file header
1161 * are supposed to be already updated!
1162 * We just remove the dirty log bit.
1163 */
1164 LogFile->Header.Flags &= ~ELF_LOGFILE_HEADER_DIRTY;
1165
1166 /* Update the log file header */
1167 FileOffset.QuadPart = 0LL;
1168 Status = LogFile->FileWrite(LogFile,
1169 &FileOffset,
1170 &LogFile->Header,
1171 sizeof(EVENTLOGHEADER),
1172 &WrittenLength);
1173 if (!NT_SUCCESS(Status))
1174 {
1175 EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
1176 return Status;
1177 }
1178
1179 /* Flush the log file */
1180 Status = LogFile->FileFlush(LogFile, NULL, 0);
1181 if (!NT_SUCCESS(Status))
1182 {
1183 EVTLTRACE1("FileFlush() failed (Status 0x%08lx)\n", Status);
1184 return Status;
1185 }
1186
1187 return STATUS_SUCCESS;
1188}
1189
1190VOID
1191NTAPI
1192ElfCloseFile( // ElfFree
1193 IN PEVTLOGFILE LogFile)
1194{
1195 ASSERT(LogFile);
1196
1197 /* Flush the log file */
1198 ElfFlushFile(LogFile);
1199
1200 /* Free the data */
1201 LogFile->Free(LogFile->OffsetInfo, 0, TAG_ELF);
1202
1203 if (LogFile->FileName.Buffer)
1204 LogFile->Free(LogFile->FileName.Buffer, 0, TAG_ELF);
1205 RtlInitEmptyUnicodeString(&LogFile->FileName, NULL, 0);
1206}
1207
1209NTAPI
1211 IN PEVTLOGFILE LogFile,
1212 IN ULONG RecordNumber,
1214 IN SIZE_T BufSize, // Length
1216 OUT PSIZE_T BytesNeeded OPTIONAL)
1217{
1220 ULONG RecOffset;
1221 ULONG RecSize;
1223
1224 ASSERT(LogFile);
1225
1226 if (BytesRead)
1227 *BytesRead = 0;
1228
1229 if (BytesNeeded)
1230 *BytesNeeded = 0;
1231
1232 /* Retrieve the offset of the event record */
1233 RecOffset = ElfpOffsetByNumber(LogFile, RecordNumber);
1234 if (RecOffset == 0)
1235 return STATUS_NOT_FOUND;
1236
1237 /* Retrieve its full size */
1238 FileOffset.QuadPart = RecOffset;
1239 Status = LogFile->FileRead(LogFile,
1240 &FileOffset,
1241 &RecSize,
1242 sizeof(RecSize),
1243 &ReadLength);
1244 if (!NT_SUCCESS(Status))
1245 {
1246 EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
1247 // Status = STATUS_EVENTLOG_FILE_CORRUPT;
1248 return Status;
1249 }
1250
1251 /* Check whether the buffer is big enough to hold the event record */
1252 if (BufSize < RecSize)
1253 {
1254 if (BytesNeeded)
1255 *BytesNeeded = RecSize;
1256
1258 }
1259
1260 /* Read the event record into the buffer */
1261 FileOffset.QuadPart = RecOffset;
1262 Status = ReadLogBuffer(LogFile,
1263 Record,
1264 RecSize,
1265 &ReadLength,
1266 &FileOffset,
1267 NULL);
1268 if (!NT_SUCCESS(Status))
1269 {
1270 EVTLTRACE1("ReadLogBuffer failed (Status 0x%08lx)\n", Status);
1271 // Status = STATUS_EVENTLOG_FILE_CORRUPT;
1272 }
1273
1274 if (BytesRead)
1276
1277 return Status;
1278}
1279
1281NTAPI
1283 IN PEVTLOGFILE LogFile,
1286{
1288 LARGE_INTEGER FileOffset, NextOffset;
1289 SIZE_T ReadLength, WrittenLength;
1290 EVENTLOGEOF EofRec;
1291 EVENTLOGRECORD RecBuf;
1292 ULONG FreeSpace = 0;
1293 ULONG UpperBound;
1294 ULONG RecOffset, WriteOffset;
1295
1296 ASSERT(LogFile);
1297
1298 if (LogFile->ReadOnly)
1299 return STATUS_ACCESS_DENIED;
1300
1301 // ASSERT(sizeof(*Record) == sizeof(RecBuf));
1302
1303 if (!Record || BufSize < sizeof(*Record))
1305
1306 Record->RecordNumber = LogFile->Header.CurrentRecordNumber;
1307
1308 /* Compute the available log free space */
1309 if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
1310 FreeSpace = LogFile->Header.MaxSize - LogFile->Header.EndOffset + LogFile->Header.StartOffset - sizeof(EVENTLOGHEADER);
1311 else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
1312 FreeSpace = LogFile->Header.StartOffset - LogFile->Header.EndOffset;
1313
1314 LogFile->Header.Flags |= ELF_LOGFILE_HEADER_DIRTY;
1315
1316 /* If the event log was empty, it will now contain one record */
1317 if (LogFile->Header.OldestRecordNumber == 0)
1318 LogFile->Header.OldestRecordNumber = 1;
1319
1320 /* By default we append the new record at the old EOF record offset */
1321 WriteOffset = LogFile->Header.EndOffset;
1322
1323 /*
1324 * Check whether the log is going to wrap (the events being overwritten).
1325 */
1326
1327 if (LogFile->Header.StartOffset <= LogFile->Header.EndOffset)
1328 UpperBound = LogFile->Header.MaxSize;
1329 else // if (LogFile->Header.StartOffset > LogFile->Header.EndOffset)
1330 UpperBound = LogFile->Header.StartOffset;
1331
1332 // if (LogFile->Header.MaxSize - WriteOffset < BufSize + sizeof(EofRec))
1333 if (UpperBound - WriteOffset < BufSize + sizeof(EofRec))
1334 {
1335 EVTLTRACE("The event log file has reached maximum size (0x%x), wrapping...\n"
1336 "UpperBound = 0x%x, WriteOffset = 0x%x, BufSize = 0x%x\n",
1337 LogFile->Header.MaxSize, UpperBound, WriteOffset, BufSize);
1338 /* This will be done later */
1339 }
1340
1341 if ( (LogFile->Header.StartOffset < LogFile->Header.EndOffset) &&
1342 (LogFile->Header.MaxSize - WriteOffset < sizeof(RecBuf)) ) // (UpperBound - WriteOffset < sizeof(RecBuf))
1343 {
1344 // ASSERT(UpperBound == LogFile->Header.MaxSize);
1345 // ASSERT(WriteOffset == LogFile->Header.EndOffset);
1346
1347 /*
1348 * We cannot fit the EVENTLOGRECORD header of the buffer before
1349 * the end of the file. We need to pad the end of the log with
1350 * 0x00000027, normally we will need to pad at most 0x37 bytes
1351 * (corresponding to sizeof(EVENTLOGRECORD) - 1).
1352 */
1353
1354 /* Rewind to the beginning of the log, just after the header */
1355 WriteOffset = sizeof(EVENTLOGHEADER);
1356 UpperBound = LogFile->Header.StartOffset;
1357
1358 FreeSpace = LogFile->Header.StartOffset - WriteOffset;
1359
1360 LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
1361 }
1362 /*
1363 * Otherwise, we can fit the header and only part
1364 * of the data will overwrite the oldest records.
1365 *
1366 * It might be possible that all the event record can fit in one piece,
1367 * but that the EOF record needs to be split. This is not a problem,
1368 * EVENTLOGEOF can be splitted while EVENTLOGRECORD cannot be.
1369 */
1370
1371 if (UpperBound - WriteOffset < BufSize + sizeof(EofRec))
1372 {
1373 ULONG OrgOldestRecordNumber, OldestRecordNumber;
1374
1375 // DPRINT("EventLogFile has reached maximum size, wrapping...\n");
1376
1377 OldestRecordNumber = OrgOldestRecordNumber = LogFile->Header.OldestRecordNumber;
1378
1379 // FIXME: Assert whether LogFile->Header.StartOffset is the beginning of a record???
1380 // NOTE: It should be, by construction (and this should have been checked when
1381 // initializing a new, or existing log).
1382
1383 /*
1384 * Determine how many old records need to be overwritten.
1385 * Check the size of the record as the record added may be larger.
1386 * Need to take into account that we append the EOF record.
1387 */
1388 while (FreeSpace < BufSize + sizeof(EofRec))
1389 {
1390 /* Get the oldest record data */
1391 RecOffset = ElfpOffsetByNumber(LogFile, OldestRecordNumber);
1392 if (RecOffset == 0)
1393 {
1394 EVTLTRACE1("Record number %d cannot be found, or log file is full and cannot wrap!\n", OldestRecordNumber);
1395 LogFile->Header.Flags |= ELF_LOGFILE_LOGFULL_WRITTEN;
1396 return STATUS_LOG_FILE_FULL;
1397 }
1398
1399 RtlZeroMemory(&RecBuf, sizeof(RecBuf));
1400
1401 FileOffset.QuadPart = RecOffset;
1402 Status = LogFile->FileRead(LogFile,
1403 &FileOffset,
1404 &RecBuf,
1405 sizeof(RecBuf),
1406 &ReadLength);
1407 if (!NT_SUCCESS(Status))
1408 {
1409 EVTLTRACE1("FileRead() failed (Status 0x%08lx)\n", Status);
1410 // Status = STATUS_EVENTLOG_FILE_CORRUPT;
1411 return Status;
1412 }
1413
1414 if (RecBuf.Reserved != LOGFILE_SIGNATURE)
1415 {
1416 EVTLTRACE1("The event log file is corrupted!\n");
1418 }
1419
1420 /*
1421 * Check whether this event can be overwritten by comparing its
1422 * written timestamp with the log's retention value. This value
1423 * is the time interval, in seconds, that events records are
1424 * protected from being overwritten.
1425 *
1426 * If the retention value is zero the events are always overwritten.
1427 *
1428 * If the retention value is non-zero, when the age of an event,
1429 * in seconds, reaches or exceeds this value, it can be overwritten.
1430 * Also if the events are in the future, we do not overwrite them.
1431 */
1432 if (LogFile->Header.Retention != 0 &&
1433 (Record->TimeWritten < RecBuf.TimeWritten ||
1434 (Record->TimeWritten >= RecBuf.TimeWritten &&
1435 Record->TimeWritten - RecBuf.TimeWritten < LogFile->Header.Retention)))
1436 {
1437 EVTLTRACE1("The event log file is full and cannot wrap because of the retention policy.\n");
1438 LogFile->Header.Flags |= ELF_LOGFILE_LOGFULL_WRITTEN;
1439 return STATUS_LOG_FILE_FULL;
1440 }
1441
1442 /*
1443 * Advance the oldest record number, add the event record length
1444 * (as long as it is valid...) then take account for the possible
1445 * paddind after the record, in case this is the last one at the
1446 * end of the file.
1447 */
1448 OldestRecordNumber++;
1449 RecOffset += RecBuf.Length;
1450 FreeSpace += RecBuf.Length;
1451
1452 /*
1453 * If this was the last event record before the end of the log file,
1454 * the next one should start at the beginning of the log and the space
1455 * between the last event record and the end of the file is padded.
1456 */
1457 if (LogFile->Header.MaxSize - RecOffset < sizeof(EVENTLOGRECORD))
1458 {
1459 /* Add the padding size */
1460 FreeSpace += LogFile->Header.MaxSize - RecOffset;
1461 }
1462 }
1463
1464 EVTLTRACE("Record will fit. FreeSpace %d, BufSize %d\n", FreeSpace, BufSize);
1465
1466 /* The log records are wrapping */
1467 LogFile->Header.Flags |= ELF_LOGFILE_HEADER_WRAP;
1468
1469
1470 // FIXME: May lead to corruption if the other subsequent calls fail...
1471
1472 /*
1473 * We have validated all the region of events to be discarded,
1474 * now we can perform their deletion.
1475 */
1476 ElfpDeleteOffsetInformation(LogFile, OrgOldestRecordNumber, OldestRecordNumber - 1);
1477 LogFile->Header.OldestRecordNumber = OldestRecordNumber;
1478 LogFile->Header.StartOffset = ElfpOffsetByNumber(LogFile, OldestRecordNumber);
1479 if (LogFile->Header.StartOffset == 0)
1480 {
1481 /*
1482 * We have deleted all the existing event records to make place
1483 * for the new one. We can put it at the start of the event log.
1484 */
1485 LogFile->Header.StartOffset = sizeof(EVENTLOGHEADER);
1486 WriteOffset = LogFile->Header.StartOffset;
1487 LogFile->Header.EndOffset = WriteOffset;
1488 }
1489
1490 EVTLTRACE("MaxSize = 0x%x, StartOffset = 0x%x, WriteOffset = 0x%x, EndOffset = 0x%x, BufSize = 0x%x\n"
1491 "OldestRecordNumber = %d\n",
1492 LogFile->Header.MaxSize, LogFile->Header.StartOffset, WriteOffset, LogFile->Header.EndOffset, BufSize,
1493 OldestRecordNumber);
1494 }
1495
1496 /*
1497 * Expand the log file if needed.
1498 * NOTE: It may be needed to perform this task a bit sooner if we need
1499 * such a thing for performing read operations, in the future...
1500 * Or if this operation needs to modify 'FreeSpace'...
1501 */
1502 if (LogFile->CurrentSize < LogFile->Header.MaxSize)
1503 {
1504 ULONG NewSize = WriteOffset + BufSize + sizeof(EofRec);
1505
1506 if (WriteOffset < LogFile->Header.EndOffset || NewSize > LogFile->Header.MaxSize)
1507 NewSize = LogFile->Header.MaxSize;
1508 else
1510
1511 if (NewSize > LogFile->CurrentSize)
1512 {
1513 EVTLTRACE1("Expanding the log file from %lu to %lu\n",
1514 LogFile->CurrentSize, NewSize);
1515 Status = LogFile->FileSetSize(LogFile, NewSize, LogFile->CurrentSize);
1516 if (!NT_SUCCESS(Status))
1517 {
1518 EVTLTRACE1("FileSetSize() failed (Status 0x%08lx)\n", Status);
1519 return Status;
1520 }
1521 LogFile->CurrentSize = NewSize;
1522 }
1523 }
1524
1525 /* Since we can write events in the log, clear the log full flag */
1526 LogFile->Header.Flags &= ~ELF_LOGFILE_LOGFULL_WRITTEN;
1527
1528 /* Pad the end of the log */
1529 // if (LogFile->Header.EndOffset + sizeof(RecBuf) > LogFile->Header.MaxSize)
1530 if (WriteOffset < LogFile->Header.EndOffset)
1531 {
1532 /* Pad all the space from LogFile->Header.EndOffset to LogFile->Header.MaxSize */
1533 WrittenLength = ROUND_DOWN(LogFile->Header.MaxSize - LogFile->Header.EndOffset, sizeof(ULONG));
1534 RtlFillMemoryUlong(&RecBuf, WrittenLength, 0x00000027);
1535
1536 FileOffset.QuadPart = LogFile->Header.EndOffset;
1537 Status = LogFile->FileWrite(LogFile,
1538 &FileOffset,
1539 &RecBuf,
1540 WrittenLength,
1541 &WrittenLength);
1542 if (!NT_SUCCESS(Status))
1543 {
1544 EVTLTRACE1("FileWrite() failed (Status 0x%08lx)\n", Status);
1545 // return Status;
1546 }
1547 }
1548
1549 /* Write the event record buffer with possible wrap at offset sizeof(EVENTLOGHEADER) */
1550 FileOffset.QuadPart = WriteOffset;
1551 Status = WriteLogBuffer(LogFile,
1552 Record,
1553 BufSize,
1554 &WrittenLength,
1555 &FileOffset,
1556 &NextOffset);
1557 if (!NT_SUCCESS(Status))
1558 {
1559 EVTLTRACE1("WriteLogBuffer failed (Status 0x%08lx)\n", Status);
1560 return Status;
1561 }
1562 /* FileOffset now contains the offset just after the end of the record buffer */
1563 FileOffset = NextOffset;
1564
1565 if (!ElfpAddOffsetInformation(LogFile,
1566 Record->RecordNumber,
1567 WriteOffset))
1568 {
1569 return STATUS_NO_MEMORY; // STATUS_EVENTLOG_FILE_CORRUPT;
1570 }
1571
1572 LogFile->Header.CurrentRecordNumber++;
1573 if (LogFile->Header.CurrentRecordNumber == 0)
1574 LogFile->Header.CurrentRecordNumber = 1;
1575
1576 /*
1577 * Write the new EOF record offset just after the event record.
1578 * The EOF record can wrap (be splitted) if less than sizeof(EVENTLOGEOF)
1579 * bytes remains between the end of the record and the end of the log file.
1580 */
1581 LogFile->Header.EndOffset = FileOffset.QuadPart;
1582
1583 RtlCopyMemory(&EofRec, &EOFRecord, sizeof(EOFRecord));
1584 EofRec.BeginRecord = LogFile->Header.StartOffset;
1585 EofRec.EndRecord = LogFile->Header.EndOffset;
1586 EofRec.CurrentRecordNumber = LogFile->Header.CurrentRecordNumber;
1587 EofRec.OldestRecordNumber = LogFile->Header.OldestRecordNumber;
1588
1589 // FileOffset.QuadPart = LogFile->Header.EndOffset;
1590 Status = WriteLogBuffer(LogFile,
1591 &EofRec,
1592 sizeof(EofRec),
1593 &WrittenLength,
1594 &FileOffset,
1595 &NextOffset);
1596 if (!NT_SUCCESS(Status))
1597 {
1598 EVTLTRACE1("WriteLogBuffer failed (Status 0x%08lx)\n", Status);
1599 return Status;
1600 }
1601 FileOffset = NextOffset;
1602
1603 /* Flush the log file */
1604 Status = ElfFlushFile(LogFile);
1605 if (!NT_SUCCESS(Status))
1606 {
1607 EVTLTRACE1("ElfFlushFile() failed (Status 0x%08lx)\n", Status);
1608 return STATUS_EVENTLOG_FILE_CORRUPT; // Status;
1609 }
1610
1611 return Status;
1612}
1613
1614ULONG
1615NTAPI
1617 IN PEVTLOGFILE LogFile)
1618{
1619 ASSERT(LogFile);
1620 return LogFile->Header.OldestRecordNumber;
1621}
1622
1623ULONG
1624NTAPI
1626 IN PEVTLOGFILE LogFile)
1627{
1628 ASSERT(LogFile);
1629 return LogFile->Header.CurrentRecordNumber;
1630}
1631
1632ULONG
1633NTAPI
1635 IN PEVTLOGFILE LogFile)
1636{
1637 ASSERT(LogFile);
1638 return LogFile->Header.Flags;
1639}
1640
1641#if DBG
1642VOID PRINT_HEADER(PEVENTLOGHEADER Header)
1643{
1644 ULONG Flags = Header->Flags;
1645
1646 EVTLTRACE1("PRINT_HEADER(0x%p)\n", Header);
1647
1648 DbgPrint("HeaderSize = %lu\n" , Header->HeaderSize);
1649 DbgPrint("Signature = 0x%x\n", Header->Signature);
1650 DbgPrint("MajorVersion = %lu\n" , Header->MajorVersion);
1651 DbgPrint("MinorVersion = %lu\n" , Header->MinorVersion);
1652 DbgPrint("StartOffset = 0x%x\n", Header->StartOffset);
1653 DbgPrint("EndOffset = 0x%x\n", Header->EndOffset);
1654 DbgPrint("CurrentRecordNumber = %lu\n", Header->CurrentRecordNumber);
1655 DbgPrint("OldestRecordNumber = %lu\n", Header->OldestRecordNumber);
1656 DbgPrint("MaxSize = 0x%x\n", Header->MaxSize);
1657 DbgPrint("Retention = 0x%x\n", Header->Retention);
1658 DbgPrint("EndHeaderSize = %lu\n" , Header->EndHeaderSize);
1659 DbgPrint("Flags: ");
1661 {
1662 DbgPrint("ELF_LOGFILE_HEADER_DIRTY");
1663 Flags &= ~ELF_LOGFILE_HEADER_DIRTY;
1664 }
1665 if (Flags) DbgPrint(" | ");
1667 {
1668 DbgPrint("ELF_LOGFILE_HEADER_WRAP");
1669 Flags &= ~ELF_LOGFILE_HEADER_WRAP;
1670 }
1671 if (Flags) DbgPrint(" | ");
1673 {
1674 DbgPrint("ELF_LOGFILE_LOGFULL_WRITTEN");
1675 Flags &= ~ELF_LOGFILE_LOGFULL_WRITTEN;
1676 }
1677 if (Flags) DbgPrint(" | ");
1679 {
1680 DbgPrint("ELF_LOGFILE_ARCHIVE_SET");
1681 Flags &= ~ELF_LOGFILE_ARCHIVE_SET;
1682 }
1683 if (Flags) DbgPrint(" | 0x%x", Flags);
1684 DbgPrint("\n");
1685}
1686#endif
ULONG ReadLength
#define BufSize
Definition: FsRtlTunnel.c:28
unsigned char BOOLEAN
Definition: actypes.h:127
_In_ PATA_DEVICE_REQUEST _In_ BOOLEAN Allocate
Definition: ata_shared.h:437
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:160
Definition: bufpool.h:45
Definition: Header.h:9
Header(const std::string &filename_)
Definition: Header.h:18
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define ULONG_PTR
Definition: config.h:101
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:33
#define EVTLTRACE(fmt,...)
Definition: evtlib.c:19
static const EVENTLOGEOF EOFRecord
Definition: evtlib.c:28
NTSTATUS NTAPI ElfReCreateFile(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:979
VOID NTAPI ElfCloseFile(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:1192
static BOOL ElfpAddOffsetInformation(IN PEVTLOGFILE LogFile, IN ULONG ulNumber, IN ULONG ulOffset)
Definition: evtlib.c:216
static ULONG ElfpOffsetByNumber(IN PEVTLOGFILE LogFile, IN ULONG RecordNumber)
Definition: evtlib.c:199
static NTSTATUS ElfpInitNewFile(IN PEVTLOGFILE LogFile, IN ULONG FileSize, IN ULONG MaxSize, IN ULONG Retention)
Definition: evtlib.c:299
#define EVENTLOG_FILE_GRANULARITY
Definition: evtlib.c:26
static NTSTATUS ElfpInitExistingFile(IN PEVTLOGFILE LogFile, IN ULONG FileSize, IN ULONG Retention)
Definition: evtlib.c:392
static BOOL ElfpDeleteOffsetInformation(IN PEVTLOGFILE LogFile, IN ULONG ulNumberMin, IN ULONG ulNumberMax)
Definition: evtlib.c:257
NTSTATUS NTAPI ElfWriteRecord(IN PEVTLOGFILE LogFile, IN PEVENTLOGRECORD Record, IN SIZE_T BufSize)
Definition: evtlib.c:1282
static NTSTATUS ReadLogBuffer(IN PEVTLOGFILE LogFile, OUT PVOID Buffer, IN SIZE_T Length, OUT PSIZE_T ReadLength OPTIONAL, IN PLARGE_INTEGER ByteOffset, OUT PLARGE_INTEGER NextOffset OPTIONAL)
Definition: evtlib.c:39
ULONG NTAPI ElfGetOldestRecord(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:1616
NTSTATUS NTAPI ElfFlushFile(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:1147
NTSTATUS NTAPI ElfCreateFile(IN OUT PEVTLOGFILE LogFile, IN PUNICODE_STRING FileName OPTIONAL, IN ULONG FileSize, IN ULONG MaxSize, IN ULONG Retention, IN BOOLEAN CreateNew, IN BOOLEAN ReadOnly, IN PELF_ALLOCATE_ROUTINE Allocate, IN PELF_FREE_ROUTINE Free, IN PELF_FILE_SET_SIZE_ROUTINE FileSetSize, IN PELF_FILE_WRITE_ROUTINE FileWrite, IN PELF_FILE_READ_ROUTINE FileRead, IN PELF_FILE_FLUSH_ROUTINE FileFlush)
Definition: evtlib.c:889
static NTSTATUS WriteLogBuffer(IN PEVTLOGFILE LogFile, IN PVOID Buffer, IN SIZE_T Length, OUT PSIZE_T WrittenLength OPTIONAL, IN PLARGE_INTEGER ByteOffset, OUT PLARGE_INTEGER NextOffset OPTIONAL)
Definition: evtlib.c:113
NTSTATUS NTAPI ElfBackupFile(IN PEVTLOGFILE LogFile, IN PEVTLOGFILE BackupLogFile)
Definition: evtlib.c:992
#define OFFSET_INFO_INCREMENT
Definition: evtlib.c:213
ULONG NTAPI ElfGetCurrentRecord(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:1625
ULONG NTAPI ElfGetFlags(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:1634
NTSTATUS NTAPI ElfReadRecord(IN PEVTLOGFILE LogFile, IN ULONG RecordNumber, OUT PEVENTLOGRECORD Record, IN SIZE_T BufSize, OUT PSIZE_T BytesRead OPTIONAL, OUT PSIZE_T BytesNeeded OPTIONAL)
Definition: evtlib.c:1210
#define EVTLTRACE1(fmt,...)
Definition: evtlib.c:21
NTSTATUS(NTAPI * PELF_FILE_FLUSH_ROUTINE)(IN struct _EVTLOGFILE *LogFile, IN PLARGE_INTEGER FileOffset, IN ULONG Length)
Definition: evtlib.h:196
#define ELF_LOGFILE_ARCHIVE_SET
Definition: evtlib.h:51
PVOID(NTAPI * PELF_ALLOCATE_ROUTINE)(IN SIZE_T Size, IN ULONG Flags, IN ULONG Tag)
Definition: evtlib.h:157
#define ELF_LOGFILE_LOGFULL_WRITTEN
Definition: evtlib.h:50
VOID(NTAPI * PELF_FREE_ROUTINE)(IN PVOID Ptr, IN ULONG Flags, IN ULONG Tag)
Definition: evtlib.h:164
struct _EVENT_OFFSET_INFO * PEVENT_OFFSET_INFO
#define ELF_LOGFILE_HEADER_WRAP
Definition: evtlib.h:49
NTSTATUS(NTAPI * PELF_FILE_SET_SIZE_ROUTINE)(IN struct _EVTLOGFILE *LogFile, IN ULONG FileSize, IN ULONG OldFileSize)
Definition: evtlib.h:189
#define LOGFILE_SIGNATURE
Definition: evtlib.h:43
#define TAG_ELF_BUF
Definition: evtlib.h:152
#define MAJORVER
Definition: evtlib.h:41
#define MINORVER
Definition: evtlib.h:42
#define ELF_LOGFILE_HEADER_DIRTY
Definition: evtlib.h:48
struct _EVENTLOGHEADER EVENTLOGHEADER
#define TAG_ELF
Definition: evtlib.h:151
NTSTATUS(NTAPI * PELF_FILE_READ_ROUTINE)(IN struct _EVTLOGFILE *LogFile, IN PLARGE_INTEGER FileOffset, OUT PVOID Buffer, IN SIZE_T Length, OUT PSIZE_T ReadLength OPTIONAL)
Definition: evtlib.h:171
#define EVENTLOGEOF_SIZE_FIXED
Definition: evtlib.h:139
NTSTATUS(NTAPI * PELF_FILE_WRITE_ROUTINE)(IN struct _EVTLOGFILE *LogFile, IN PLARGE_INTEGER FileOffset, IN PVOID Buffer, IN SIZE_T Length, OUT PSIZE_T WrittenLength OPTIONAL)
Definition: evtlib.h:180
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:732
unsigned int BOOL
Definition: ntddk_ex.h:94
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
Status
Definition: gdiplustypes.h:24
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define DbgPrint
Definition: hal.h:12
unsigned int UINT
Definition: sysinfo.c:13
#define RtlFillMemoryUlong(dst, len, val)
Definition: mkhive.h:55
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define STATUS_LOG_FILE_FULL
Definition: ntstatus.h:719
#define STATUS_EVENTLOG_FILE_CORRUPT
Definition: ntstatus.h:725
@ ReadOnly
Definition: arc.h:89
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define DPRINT
Definition: sndvol32.h:73
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
ULONG EndRecord
Definition: evtlib.h:133
ULONG CurrentRecordNumber
Definition: evtlib.h:134
ULONG BeginRecord
Definition: evtlib.h:132
ULONG RecordSizeBeginning
Definition: evtlib.h:127
ULONG RecordSizeEnd
Definition: evtlib.h:136
ULONG OldestRecordNumber
Definition: evtlib.h:135
DWORD RecordNumber
Definition: winnt_old.h:3084
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:925
#define max(a, b)
Definition: svc.c:63
#define LL
Definition: tui.h:166
ULONG_PTR * PSIZE_T
Definition: typedefs.h:80
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
LONGLONG QuadPart
Definition: typedefs.h:114
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_Must_inspect_result_ _In_ WDFUSBPIPE _In_ WDFREQUEST _In_opt_ WDFMEMORY _In_opt_ PWDFMEMORY_OFFSET WriteOffset
Definition: wdfusb.h:1921
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:815
_In_ struct _KBUGCHECK_REASON_CALLBACK_RECORD * Record
Definition: ketypes.h:320