Saveliy Tretiakov <saveliyt@mail.ru>:
[reactos.git] / reactos / services / eventlog / file.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS
4 * FILE: services/eventlog/file.c
5 * PURPOSE: Event logging service
6 * PROGRAMMER: Saveliy Tretiakov (saveliyt@mail.ru)
7 */
8
9 #include "eventlog.h"
10
11 PLOGFILE _LogListHead = NULL;
12 extern HANDLE MyHeap;
13
14 BOOL LogfInitializeNew(PLOGFILE LogFile)
15 {
16 DWORD dwWritten;
17 EOF_RECORD EofRec;
18
19 ZeroMemory(&LogFile->Header, sizeof(FILE_HEADER));
20 SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
21 SetEndOfFile(LogFile->hFile);
22
23 LogFile->Header.SizeOfHeader = sizeof(FILE_HEADER);
24 LogFile->Header.SizeOfHeader2 = sizeof(FILE_HEADER);
25 LogFile->Header.FirstRecordOffset = sizeof(FILE_HEADER);
26 LogFile->Header.EofOffset = sizeof(FILE_HEADER);
27 LogFile->Header.MajorVersion = MAJORVER;
28 LogFile->Header.MinorVersion = MINORVER;
29 LogFile->Header.NextRecord = 1;
30
31 LogFile->Header.Signature = LOGFILE_SIGNATURE;
32 WriteFile(LogFile->hFile,
33 &LogFile->Header,
34 sizeof(FILE_HEADER),
35 &dwWritten,
36 NULL);
37
38 EofRec.Ones = 0x11111111;
39 EofRec.Twos = 0x22222222;
40 EofRec.Threes = 0x33333333;
41 EofRec.Fours = 0x44444444;
42 EofRec.Size1 = sizeof(EOF_RECORD);
43 EofRec.Size2 = sizeof(EOF_RECORD);
44 EofRec.NextRecordNumber = LogFile->Header.NextRecord;
45 EofRec.OldestRecordNumber = LogFile->Header.OldestRecord;
46 EofRec.StartOffset = LogFile->Header.FirstRecordOffset;
47 EofRec.EndOffset = LogFile->Header.EofOffset;
48
49 WriteFile(LogFile->hFile, &EofRec, sizeof(EOF_RECORD), &dwWritten, NULL);
50
51 FlushFileBuffers(LogFile->hFile);
52
53 return TRUE;
54 }
55
56 BOOL LogfInitializeExisting(PLOGFILE LogFile)
57 {
58 DWORD dwRead;
59 DWORD dwRecordsNumber = 0;
60 DWORD dwRecSize, dwRecSign, dwFilePointer;
61 PDWORD pdwRecSize2;
62 PEVENTLOGRECORD RecBuf;
63
64 SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
65 ReadFile(LogFile->hFile,
66 &LogFile->Header,
67 sizeof(FILE_HEADER),
68 &dwRead, NULL);
69
70 if(dwRead != sizeof(FILE_HEADER))
71 {
72 DPRINT("EventLog: Invalid file %S.\n", LogFile->FileName);
73 return LogfInitializeNew(LogFile);
74 }
75
76 if(LogFile->Header.SizeOfHeader != sizeof(FILE_HEADER) ||
77 LogFile->Header.SizeOfHeader2 != sizeof(FILE_HEADER))
78 {
79 DPRINT("EventLog: Invalid header size in %S.\n", LogFile->FileName);
80 return LogfInitializeNew(LogFile);
81 }
82
83 if(LogFile->Header.Signature != LOGFILE_SIGNATURE)
84 {
85 DPRINT("EventLog: Invalid signature %x in %S.\n",
86 LogFile->Header.Signature,
87 LogFile->FileName);
88 return LogfInitializeNew(LogFile);
89 }
90
91 if(LogFile->Header.EofOffset > GetFileSize(LogFile->hFile, NULL)+1)
92 {
93 DPRINT("EventLog: Invalid eof offset %x in %S.\n",
94 LogFile->Header.EofOffset,
95 LogFile->FileName);
96 return LogfInitializeNew(LogFile);
97 }
98
99 for(;;)
100 {
101 dwFilePointer = SetFilePointer(LogFile->hFile,
102 0,
103 NULL,
104 FILE_CURRENT);
105
106 ReadFile(LogFile->hFile,
107 &dwRecSize,
108 sizeof(dwRecSize),
109 &dwRead,
110 NULL);
111
112 if(dwRead != sizeof(dwRecSize))
113 break;
114
115 ReadFile(LogFile->hFile,
116 &dwRecSign,
117 sizeof(dwRecSign),
118 &dwRead,
119 NULL);
120
121 if(dwRead != sizeof(dwRecSize))
122 break;
123
124 if(dwRecSign != LOGFILE_SIGNATURE ||
125 dwRecSize + dwFilePointer > GetFileSize(LogFile->hFile, NULL)+1 ||
126 dwRecSize < sizeof(EVENTLOGRECORD))
127 {
128 break;
129 }
130
131 SetFilePointer(LogFile->hFile, -((LONG)sizeof(DWORD)*2), NULL, FILE_CURRENT);
132 RecBuf = (PEVENTLOGRECORD) HeapAlloc(MyHeap, 0, dwRecSize);
133 ReadFile(LogFile->hFile,
134 RecBuf,
135 dwRecSize,
136 &dwRead,
137 NULL);
138
139 if(dwRead != dwRecSize)
140 {
141 HeapFree(MyHeap, 0, RecBuf);
142 break;
143 }
144
145 pdwRecSize2 = (PDWORD)(((PBYTE)RecBuf)+dwRecSize-4);
146 if(*pdwRecSize2 != dwRecSize)
147 {
148 DPRINT("EventLog: Invalid size2 of record %d (%x) in %s\n",
149 dwRecordsNumber,
150 *pdwRecSize2,
151 LogFile->LogName);
152 HeapFree(MyHeap, 0, RecBuf);
153 break;
154 }
155
156 dwRecordsNumber++;
157
158 if(!LogfAddOffsetInformation(LogFile, RecBuf->RecordNumber, dwFilePointer))
159 {
160 HeapFree(MyHeap, 0, RecBuf);
161 return FALSE;
162 }
163
164 HeapFree(MyHeap, 0, RecBuf);
165 }//for(;;)
166
167 LogFile->Header.NextRecord = dwRecordsNumber+1;
168 LogFile->Header.OldestRecord = dwRecordsNumber ? 1 : 0; //FIXME
169
170 SetFilePointer(LogFile->hFile, 0, 0, FILE_CURRENT);
171 WriteFile(LogFile->hFile,
172 &LogFile->Header,
173 sizeof(FILE_HEADER),
174 &dwRead,
175 NULL);
176 FlushFileBuffers(LogFile->hFile);
177
178 return TRUE;
179 }
180
181 PLOGFILE LogfCreate(WCHAR *LogName,
182 WCHAR *FileName)
183 {
184 PLOGFILE LogFile;
185 BOOL bResult, bCreateNew = FALSE;
186
187 LogFile = HeapAlloc(MyHeap,
188 HEAP_ZERO_MEMORY,
189 sizeof(LOGFILE));
190 if(!LogFile)
191 {
192 DbgPrint("EventLog: Can't allocate heap\n");
193 return NULL;
194 }
195
196 LogFile->hFile = CreateFile(FileName,
197 GENERIC_READ | GENERIC_WRITE,
198 FILE_SHARE_READ,
199 NULL,
200 OPEN_ALWAYS,
201 FILE_ATTRIBUTE_NORMAL |
202 FILE_FLAG_RANDOM_ACCESS,
203 NULL);
204
205 if(LogFile->hFile == INVALID_HANDLE_VALUE)
206 {
207 DbgPrint("EventLog: Can't open file %S.\n", FileName);
208 HeapFree(MyHeap, 0, LogFile);
209 return NULL;
210 }
211
212 bCreateNew = GetLastError() == ERROR_ALREADY_EXISTS ? FALSE : TRUE;
213
214 LogFile->LogName = HeapAlloc(MyHeap,
215 HEAP_ZERO_MEMORY,
216 (lstrlenW(LogName)+1)*sizeof(WCHAR));
217 if(LogFile->LogName)
218 lstrcpyW(LogFile->LogName, LogName);
219 else
220 {
221 DPRINT("EventLog: Can't allocate heap\n");
222 HeapFree(MyHeap, 0, LogFile);
223 return NULL;
224 }
225
226 LogFile->FileName = HeapAlloc(MyHeap,
227 HEAP_ZERO_MEMORY,
228 (lstrlenW(FileName)+1)*sizeof(WCHAR));
229 if(LogFile->FileName)
230 lstrcpyW(LogFile->FileName, FileName);
231 else
232 {
233 DPRINT("EventLog: Can't allocate heap\n");
234 HeapFree(MyHeap, 0, LogFile->LogName);
235 HeapFree(MyHeap, 0, LogFile);
236 return NULL;
237 }
238
239
240 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO)
241 HeapAlloc(MyHeap,
242 HEAP_ZERO_MEMORY,
243 sizeof(EVENT_OFFSET_INFO)*64);
244
245 if(!LogFile->OffsetInfo)
246 {
247 DPRINT("EventLog: Can't allocate heap\n");
248 HeapFree(MyHeap, 0, LogFile->FileName);
249 HeapFree(MyHeap, 0, LogFile->LogName);
250 HeapFree(MyHeap, 0, LogFile);
251 return NULL;
252 }
253
254 LogFile->OffsetInfoSize = 64;
255
256 if(bCreateNew)
257 bResult = LogfInitializeNew(LogFile);
258 else bResult = LogfInitializeExisting(LogFile);
259
260 if(!bResult)
261 {
262 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
263 HeapFree(MyHeap, 0, LogFile->FileName);
264 HeapFree(MyHeap, 0, LogFile->LogName);
265 HeapFree(MyHeap, 0, LogFile);
266 return NULL;
267 }
268
269 InitializeCriticalSection(&LogFile->cs);
270 LogfListAddItem(LogFile);
271 return LogFile;
272 }
273
274 VOID LogfClose(PLOGFILE LogFile)
275 {
276 if(LogFile == NULL)
277 return;
278
279 EnterCriticalSection(&LogFile->cs);
280
281 FlushFileBuffers(LogFile->hFile);
282 CloseHandle(LogFile->hFile);
283
284 LogfListRemoveItem(LogFile);
285 DeleteCriticalSection(&LogFile->cs);
286
287 HeapFree(MyHeap, 0, LogFile->LogName);
288 HeapFree(MyHeap, 0, LogFile->FileName);
289 HeapFree(MyHeap, 0, LogFile->OffsetInfo);
290 HeapFree(MyHeap, 0, LogFile);
291
292 return;
293 }
294
295 PLOGFILE LogfListHead()
296 {
297 return _LogListHead;
298 }
299
300 PLOGFILE LogfListItemByName(WCHAR *Name)
301 {
302 PLOGFILE Item;
303 Item = LogfListHead();
304 while(Item)
305 {
306 if(Item->LogName && lstrcmpW(Item->LogName, Name)==0)
307 return Item;
308 Item = (PLOGFILE)Item->Next;
309 }
310 return NULL;
311 }
312
313 PLOGFILE LogfListItemByIndex(INT Index)
314 {
315 INT i = 0;
316 PLOGFILE Item;
317 Item = LogfListHead();
318 while(Item)
319 {
320 if(i == Index)
321 return Item;
322 i++;
323 Item = (PLOGFILE)Item->Next;
324 }
325 return NULL;
326 }
327
328 INT LogfListItemCount()
329 {
330 PLOGFILE Item = NULL;
331 INT i = 1;
332 Item = LogfListHead();
333 if(Item)
334 {
335 while(Item->Next)
336 {
337 i++;
338 Item = (PLOGFILE) Item->Next;
339 }
340 return i;
341 }
342 else return 0;
343 }
344
345 VOID LogfListAddItem(PLOGFILE Item)
346 {
347 PLOGFILE List;
348
349 List = LogfListHead();
350
351 if(List)
352 {
353 while(List->Next)
354 List = (PLOGFILE)List->Next;
355 Item->Prev = (PVOID)List;
356 Item->Next = NULL;
357 InterlockedExchange((PLONG)&List->Next, (LONG)Item);
358 }
359 else {
360 Item->Next = NULL;
361 Item->Prev = NULL;
362 InterlockedExchange((PLONG)&_LogListHead, (LONG)Item);
363 }
364 }
365
366 VOID LogfListRemoveItem(PLOGFILE Item)
367 {
368 if(Item->Prev)
369 {
370 InterlockedExchange((PLONG)&((PLOGFILE)Item->Prev)->Next,
371 (LONG)Item->Next);
372 }
373 else {
374 InterlockedExchange((PLONG)&_LogListHead, (LONG)Item->Next);
375 }
376 }
377
378 BOOL LogfReadEvent(PLOGFILE LogFile,
379 DWORD Flags,
380 DWORD RecordNumber,
381 DWORD BufSize,
382 PBYTE Buffer,
383 DWORD *BytesRead,
384 DWORD *BytesNeeded)
385 {
386 DWORD dwOffset, dwRead, dwRecSize;
387 DWORD dwBufferUsage = 0, dwRecNum;
388
389 if(Flags & EVENTLOG_FORWARDS_READ &&
390 Flags & EVENTLOG_BACKWARDS_READ)
391 {
392 return FALSE;
393 }
394
395 if(!(Flags & EVENTLOG_FORWARDS_READ) &&
396 !(Flags & EVENTLOG_BACKWARDS_READ))
397 {
398 return FALSE;
399 }
400
401 if(!Buffer || !BytesRead || !BytesNeeded)
402 {
403 return FALSE;
404 }
405
406 dwRecNum = RecordNumber;
407 EnterCriticalSection(&LogFile->cs);
408 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
409
410 if(!dwOffset)
411 {
412 LeaveCriticalSection(&LogFile->cs);
413 return FALSE;
414 }
415
416 SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN);
417 ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL);
418 if(dwRecSize > BufSize)
419 {
420 *BytesRead = 0;
421 *BytesNeeded = dwRecSize;
422 SetLastError(ERROR_INSUFFICIENT_BUFFER);
423 LeaveCriticalSection(&LogFile->cs);
424 return FALSE;
425 }
426
427 SetFilePointer(LogFile->hFile,
428 -((LONG)sizeof(DWORD)),
429 NULL,
430 FILE_CURRENT);
431
432 ReadFile(LogFile->hFile, Buffer, dwRecSize, &dwRead, NULL);
433 dwBufferUsage+=dwRead;
434
435 while(dwBufferUsage<BufSize)
436 {
437 if(Flags & EVENTLOG_FORWARDS_READ)
438 dwRecNum++;
439 else dwRecNum--;
440
441 dwOffset = LogfOffsetByNumber(LogFile, dwRecNum);
442 if(!dwOffset) break;
443
444 SetFilePointer(LogFile->hFile, dwOffset, NULL, FILE_BEGIN);
445 ReadFile(LogFile->hFile, &dwRecSize, sizeof(DWORD), &dwRead, NULL);
446 if(dwBufferUsage+dwRecSize>BufSize)break;
447
448 SetFilePointer(LogFile->hFile,
449 -((LONG)sizeof(DWORD)),
450 NULL,
451 FILE_CURRENT);
452
453 ReadFile(LogFile->hFile,
454 Buffer+dwBufferUsage,
455 dwRecSize,
456 &dwRead,
457 NULL);
458
459 dwBufferUsage+=dwRead;
460 }
461
462 *BytesRead = dwBufferUsage;
463 LeaveCriticalSection(&LogFile->cs);
464 return TRUE;
465 }
466
467 BOOL LogfWriteData(PLOGFILE LogFile,
468 DWORD BufSize,
469 PBYTE Buffer)
470 {
471 DWORD dwWritten;
472 SYSTEMTIME st;
473 EOF_RECORD EofRec;
474 BOOL bResult;
475
476 if(!Buffer)
477 {
478 return FALSE;
479 }
480
481 GetSystemTime(&st);
482 SystemTimeToEventTime(&st, &((PEVENTLOGRECORD)Buffer)->TimeWritten);
483
484 EnterCriticalSection(&LogFile->cs);
485
486 SetFilePointer(LogFile->hFile, LogFile->Header.EofOffset, NULL, FILE_BEGIN);
487 WriteFile(LogFile->hFile, Buffer, BufSize, &dwWritten, NULL);
488
489 if(BufSize != dwWritten)
490 {
491 LeaveCriticalSection(&LogFile->cs);
492 return FALSE;
493 }
494
495 if(!LogfAddOffsetInformation(LogFile,
496 LogFile->Header.NextRecord,
497 LogFile->Header.EofOffset))
498 {
499 LeaveCriticalSection(&LogFile->cs);
500 return FALSE;
501 }
502
503 LogFile->Header.NextRecord++;
504 LogFile->Header.EofOffset += dwWritten;
505
506 if(LogFile->Header.OldestRecord == 0)
507 LogFile->Header.OldestRecord = 1;
508
509 EofRec.Ones = 0x11111111;
510 EofRec.Twos = 0x22222222;
511 EofRec.Threes = 0x33333333;
512 EofRec.Fours = 0x44444444;
513 EofRec.Size1 = sizeof(EOF_RECORD);
514 EofRec.Size2 = sizeof(EOF_RECORD);
515 EofRec.NextRecordNumber = LogFile->Header.NextRecord;
516 EofRec.OldestRecordNumber = LogFile->Header.OldestRecord;
517 EofRec.StartOffset = LogFile->Header.FirstRecordOffset;
518 EofRec.EndOffset = LogFile->Header.EofOffset;
519
520 WriteFile(LogFile->hFile, &EofRec, sizeof(EOF_RECORD), &dwWritten, NULL);
521
522 SetFilePointer(LogFile->hFile, 0, NULL, FILE_BEGIN);
523 bResult = WriteFile(LogFile->hFile,
524 &LogFile->Header,
525 sizeof(FILE_HEADER),
526 &dwWritten,
527 NULL);
528
529 if(!bResult)
530 {
531 DPRINT("WriteFile failed! LastError = %d\n", GetLastError());
532 LeaveCriticalSection(&LogFile->cs);
533 return FALSE;
534 }
535
536 if(!FlushFileBuffers(LogFile->hFile))
537 DPRINT("FlushFileBuffers() failed!\n");
538
539 LeaveCriticalSection(&LogFile->cs);
540 return TRUE;
541 }
542
543 ULONG LogfOffsetByNumber(PLOGFILE LogFile,
544 DWORD RecordNumber)
545 /* Returns NULL if nothing found. */
546 {
547 DWORD i;
548 for(i = 0; i < LogFile->OffsetInfoNext; i++)
549 if(LogFile->OffsetInfo[i].EventNumber == RecordNumber)
550 return LogFile->OffsetInfo[i].EventOffset;
551 return 0;
552 }
553
554 DWORD LogfGetOldestRecord(PLOGFILE LogFile)
555 {
556 return LogFile->Header.OldestRecord;
557 }
558
559 BOOL LogfAddOffsetInformation(PLOGFILE LogFile,
560 ULONG ulNumber,
561 ULONG ulOffset)
562 {
563 LPVOID NewOffsetInfo;
564
565 if(LogFile->OffsetInfoNext == LogFile->OffsetInfoSize)
566 {
567 NewOffsetInfo = HeapReAlloc(MyHeap,
568 HEAP_ZERO_MEMORY,
569 LogFile->OffsetInfo,
570 (LogFile->OffsetInfoSize+64)*
571 sizeof(EVENT_OFFSET_INFO));
572 if(!NewOffsetInfo)
573 {
574 DbgPrint("EventLog: Can't reallocate heap.\n");
575 return FALSE;
576 }
577
578 LogFile->OffsetInfo = (PEVENT_OFFSET_INFO)NewOffsetInfo;
579 LogFile->OffsetInfoSize+=64;
580 }
581
582 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventNumber = ulNumber;
583 LogFile->OffsetInfo[LogFile->OffsetInfoNext].EventOffset = ulOffset;
584 LogFile->OffsetInfoNext++;
585
586 return TRUE;
587 }
588
589 DWORD LogfBuildNewRecord(PBYTE Buffer,
590 DWORD dwRecordNumber,
591 WORD wType,
592 WORD wCategory,
593 DWORD dwEventId,
594 LPCWSTR SourceName,
595 LPCWSTR ComputerName,
596 DWORD dwSidLength,
597 PSID lpUserSid,
598 WORD wNumStrings,
599 WCHAR *lpStrings,
600 DWORD dwDataSize,
601 LPVOID lpRawData)
602 {
603 DWORD dwRecSize;
604 PEVENTLOGRECORD pRec;
605 SYSTEMTIME SysTime;
606 WCHAR *str;
607 UINT i, pos, nStrings;
608
609 dwRecSize = sizeof(EVENTLOGRECORD) + (lstrlenW(ComputerName) +
610 lstrlenW(SourceName) + 2)*sizeof(WCHAR);
611
612 if(dwRecSize % 4 != 0) dwRecSize += 4 - (dwRecSize % 4);
613 dwRecSize += dwSidLength;
614
615 for(i = 0, str = lpStrings; i < wNumStrings; i++)
616 {
617 dwRecSize += (lstrlenW(str)+1)*sizeof(WCHAR);
618 str += lstrlenW(str)+1;
619 }
620
621 dwRecSize += dwDataSize;
622 if(dwRecSize % 4 != 0) dwRecSize += 4 - (dwRecSize % 4);
623 dwRecSize+=4;
624
625 if(!Buffer)
626 {
627 return dwRecSize;
628 }
629
630 ZeroMemory(Buffer, dwRecSize);
631 pRec = (PEVENTLOGRECORD)Buffer;
632 pRec->Length = dwRecSize;
633 pRec->Reserved = LOGFILE_SIGNATURE;
634 pRec->RecordNumber = dwRecordNumber;
635
636 GetSystemTime(&SysTime);
637 SystemTimeToEventTime(&SysTime, &pRec->TimeGenerated);
638 SystemTimeToEventTime(&SysTime, &pRec->TimeWritten);
639
640 pRec->EventID = dwEventId;
641 pRec->EventType = wType;
642 pRec->NumStrings = wNumStrings;
643 pRec->EventCategory = wCategory;
644
645 pos = sizeof(EVENTLOGRECORD);
646
647 lstrcpyW((WCHAR*)(Buffer+pos), SourceName);
648 pos+=(lstrlenW(SourceName)+1)*sizeof(WCHAR);
649 lstrcpyW((WCHAR*)(Buffer+pos), ComputerName);
650 pos+=(lstrlenW(ComputerName)+1)*sizeof(WCHAR);
651
652 pRec->UserSidOffset = pos;
653 if(dwSidLength)
654 {
655 if(pos % 4 != 0) pos += 4 - (pos % 4);
656 CopyMemory(Buffer+pos, lpUserSid, dwSidLength);
657 pRec->UserSidLength = dwSidLength;
658 pRec->UserSidOffset = pos;
659 pos+=dwSidLength;
660 }
661
662 pRec->StringOffset = pos;
663 for(i = 0, str = lpStrings, nStrings = 0; i < wNumStrings; i++)
664 {
665 lstrcpyW((WCHAR*)(Buffer+pos), str);
666 pos += (lstrlenW(str)+1)*sizeof(WCHAR);
667 str += lstrlenW(str)+1;
668 nStrings++;
669 }
670 pRec->NumStrings = nStrings;
671
672 pRec->DataOffset = pos;
673 if(dwDataSize)
674 {
675 pRec->DataLength = dwDataSize;
676 CopyMemory(Buffer+pos, lpRawData, dwDataSize);
677 pos += dwDataSize;
678 }
679
680 if(pos % 4 != 0) pos += 4 - (pos % 4);
681 *((PDWORD)(Buffer+pos)) = dwRecSize;
682
683 return TRUE;
684 }