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