ReactOS  0.4.12-dev-916-gffc4e30
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 */
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  */
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 */
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  */
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,
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");
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;
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: ");
1634  {
1635  DbgPrint("ELF_LOGFILE_HEADER_DIRTY");
1637  }
1638  if (Flags) DbgPrint(" | ");
1640  {
1641  DbgPrint("ELF_LOGFILE_HEADER_WRAP");
1643  }
1644  if (Flags) DbgPrint(" | ");
1646  {
1647  DbgPrint("ELF_LOGFILE_LOGFULL_WRITTEN");
1649  }
1650  if (Flags) DbgPrint(" | ");
1652  {
1653  DbgPrint("ELF_LOGFILE_ARCHIVE_SET");
1655  }
1656  if (Flags) DbgPrint(" | 0x%x", Flags);
1657  DbgPrint("\n");
1658 }
1659 #endif
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 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
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
VOID(NTAPI * PELF_FREE_ROUTINE)(IN PVOID Ptr, IN ULONG Flags, IN ULONG Tag)
Definition: evtlib.h:164
Definition: arc.h:80
#define OFFSET_INFO_INCREMENT
Definition: evtlib.c:211
#define STATUS_LOG_FILE_FULL
Definition: ntstatus.h:611
LONG NTSTATUS
Definition: precomp.h:26
#define STATUS_EVENTLOG_FILE_CORRUPT
Definition: ntstatus.h:617
#define EVENTLOGEOF_SIZE_FIXED
Definition: evtlib.h:139
#define EVTLTRACE1(...)
Definition: evtlib.c:21
ULONG RecordSizeBeginning
Definition: evtlib.h:127
NTSTATUS(NTAPI * PELF_FILE_SET_SIZE_ROUTINE)(IN struct _EVTLOGFILE *LogFile, IN ULONG FileSize, IN ULONG OldFileSize)
Definition: evtlib.h:189
#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)
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
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
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
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
Definition: Header.h:8
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned char BOOLEAN
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
void * PVOID
Definition: retypes.h:9
#define RtlFillMemoryUlong(dst, len, val)
Definition: mkhive.h:55
#define STATUS_NOT_FOUND
Definition: shellext.h:67
#define LOGFILE_SIGNATURE
Definition: evtlib.h:43
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
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
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
volatile int Continue
Definition: gdblib.c:102
#define TAG_ELF
Definition: evtlib.h:151
#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
ULONG BeginRecord
Definition: evtlib.h:132
DWORD RecordNumber
Definition: winnt_old.h:2639
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
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 CurrentRecordNumber
Definition: evtlib.h:134
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:30
ULONG_PTR SIZE_T
Definition: typedefs.h:78
ULONG NTAPI ElfGetFlags(IN PEVTLOGFILE LogFile)
Definition: evtlib.c:1607
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_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:151
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
Header(const std::string &filename_)
Definition: Header.h:18
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define DPRINT1
Definition: precomp.h:8
#define EVTLTRACE(...)
Definition: evtlib.c:19
#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
return STATUS_SUCCESS
Definition: btrfs.c:2725
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
NTSTATUS(NTAPI * PELF_FILE_FLUSH_ROUTINE)(IN struct _EVTLOGFILE *LogFile, IN PLARGE_INTEGER FileOffset, IN ULONG Length)
Definition: evtlib.h:196
LONGLONG QuadPart
Definition: typedefs.h:112
IN PDCB IN PCCB IN VBO IN OUT PULONG OUT PDIRENT OUT PBCB OUT PVBO ByteOffset
Definition: fatprocs.h:716
static BOOL ElfpDeleteOffsetInformation(IN PEVTLOGFILE LogFile, IN ULONG ulNumberMin, IN ULONG ulNumberMax)
Definition: evtlib.c:255
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68