Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1337 lines
42 KiB

  1. /*
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. FILE.C
  5. Abstract:
  6. This file contains the routines that deal with file-related operations.
  7. Author:
  8. Rajen Shah (rajens) 07-Aug-1991
  9. Revision History:
  10. 29-Aug-1994 Danl
  11. We no longer grow log files in place. So there is no need to
  12. reserve the MaxConfigSize block of memory.
  13. 18-Apr-2001 Danl
  14. Modified the function RevalidateLogHeader to change an ASSERT to a check
  15. in order to return a proper error code if the condition is TRUE
  16. --*/
  17. //
  18. // INCLUDES
  19. //
  20. #include <eventp.h>
  21. #include <alertmsg.h> // ALERT_ELF manifests
  22. //
  23. // Macros
  24. //
  25. #define IS_EOF(Ptr, Size) \
  26. ((Ptr)->Length == ELFEOFRECORDSIZE && \
  27. RtlCompareMemory (Ptr, &EOFRecord, Size) == Size)
  28. #ifdef CORRUPTED
  29. BOOLEAN
  30. VerifyLogIntegrity(
  31. PLOGFILE pLogFile
  32. )
  33. /*++
  34. Routine Description:
  35. This routine walks the log file to verify that it isn't corrupt
  36. Arguments:
  37. A pointer to the LOGFILE structure for the log to validate.
  38. Return Value:
  39. TRUE if log OK
  40. FALSE if it is corrupt
  41. Note:
  42. --*/
  43. {
  44. PEVENTLOGRECORD pEventLogRecord;
  45. PEVENTLOGRECORD pNextRecord;
  46. PVOID PhysicalStart;
  47. PVOID PhysicalEOF;
  48. PVOID BeginRecord;
  49. PVOID EndRecord;
  50. pEventLogRecord =
  51. (PEVENTLOGRECORD)((PBYTE) pLogFile->BaseAddress + pLogFile->BeginRecord);
  52. PhysicalStart =
  53. (PVOID) ((PBYTE) pLogFile->BaseAddress + FILEHEADERBUFSIZE);
  54. PhysicalEOF =
  55. (PVOID) ((PBYTE) pLogFile->BaseAddress + pLogFile->ViewSize);
  56. BeginRecord = (PVOID)((PBYTE) pLogFile->BaseAddress + pLogFile->BeginRecord);
  57. EndRecord = (PVOID)((PBYTE) pLogFile->BaseAddress + pLogFile->EndRecord);
  58. while(pEventLogRecord->Length != ELFEOFRECORDSIZE)
  59. {
  60. pNextRecord =
  61. (PEVENTLOGRECORD) NextRecordPosition(EVENTLOG_FORWARDS_READ,
  62. (PVOID) pEventLogRecord,
  63. pEventLogRecord->Length,
  64. BeginRecord,
  65. EndRecord,
  66. PhysicalEOF,
  67. PhysicalStart);
  68. if (!pNextRecord || pNextRecord->Length == 0)
  69. {
  70. ELF_LOG2(ERROR,
  71. "VerifyLogIntegrity: The %ws logfile is corrupt near %p\n",
  72. pLogFile->LogModuleName->Buffer,
  73. pEventLogRecord);
  74. return FALSE;
  75. }
  76. pEventlogRecord = pNextRecord;
  77. }
  78. return TRUE;
  79. }
  80. #endif // CORRUPTED
  81. NTSTATUS
  82. FlushLogFile(
  83. PLOGFILE pLogFile
  84. )
  85. /*++
  86. Routine Description:
  87. This routine flushes the file specified. It updates the file header,
  88. and then flushes the virtual memory which causes the data to get
  89. written to disk.
  90. Arguments:
  91. pLogFile points to the log file structure.
  92. Return Value:
  93. NONE
  94. Note:
  95. --*/
  96. {
  97. NTSTATUS Status;
  98. IO_STATUS_BLOCK IoStatusBlock;
  99. PVOID BaseAddress;
  100. SIZE_T RegionSize;
  101. PELF_LOGFILE_HEADER pLogFileHeader;
  102. //
  103. // If the dirty bit is set, update the file header before flushing it.
  104. //
  105. if (pLogFile->Flags & ELF_LOGFILE_HEADER_DIRTY)
  106. {
  107. ELF_LOG1(FILES,
  108. "FlushLogFile: %ws log is dirty -- updating header before flushing\n",
  109. pLogFile->LogModuleName->Buffer);
  110. pLogFileHeader = (PELF_LOGFILE_HEADER) pLogFile->BaseAddress;
  111. pLogFile->Flags &= ~ELF_LOGFILE_HEADER_DIRTY; // Remove dirty bit
  112. pLogFileHeader->Flags = pLogFile->Flags;
  113. pLogFileHeader->StartOffset = pLogFile->BeginRecord;
  114. pLogFileHeader->EndOffset = pLogFile->EndRecord;
  115. pLogFileHeader->CurrentRecordNumber = pLogFile->CurrentRecordNumber;
  116. pLogFileHeader->OldestRecordNumber = pLogFile->OldestRecordNumber;
  117. }
  118. //
  119. // Flush the memory in the section that is mapped to the file.
  120. //
  121. BaseAddress = pLogFile->BaseAddress;
  122. RegionSize = pLogFile->ViewSize;
  123. Status = NtFlushVirtualMemory(NtCurrentProcess(),
  124. &BaseAddress,
  125. &RegionSize,
  126. &IoStatusBlock);
  127. return Status;
  128. }
  129. NTSTATUS
  130. ElfpFlushFiles(
  131. VOID
  132. )
  133. /*++
  134. Routine Description:
  135. This routine flushes all the log files and forces them on disk.
  136. It is usually called in preparation for a shutdown or a pause.
  137. Arguments:
  138. NONE
  139. Return Value:
  140. NONE
  141. Note:
  142. --*/
  143. {
  144. PLOGFILE pLogFile;
  145. NTSTATUS Status = STATUS_SUCCESS;
  146. //
  147. // Make sure that there's at least one file to flush
  148. //
  149. if (IsListEmpty(&LogFilesHead))
  150. {
  151. ELF_LOG0(FILES,
  152. "ElfpFlushFiles: No log files -- returning success\n");
  153. return STATUS_SUCCESS;
  154. }
  155. pLogFile = (PLOGFILE) CONTAINING_RECORD(LogFilesHead.Flink, LOGFILE, FileList);
  156. //
  157. // Go through this loop at least once. This ensures that the termination
  158. // condition will work correctly.
  159. //
  160. do
  161. {
  162. Status = FlushLogFile(pLogFile);
  163. if (!NT_SUCCESS(Status))
  164. {
  165. ELF_LOG2(ERROR,
  166. "ElfpFlushFiles: FlushLogFile on %ws log failed %#x\n",
  167. pLogFile->LogModuleName->Buffer,
  168. Status);
  169. }
  170. //
  171. // Get the next one
  172. //
  173. pLogFile = (PLOGFILE) CONTAINING_RECORD(pLogFile->FileList.Flink, LOGFILE, FileList);
  174. }
  175. while ((pLogFile->FileList.Flink != LogFilesHead.Flink) && (NT_SUCCESS(Status)));
  176. return Status;
  177. }
  178. NTSTATUS
  179. ElfpCloseLogFile(
  180. PLOGFILE pLogFile,
  181. DWORD Flags
  182. )
  183. /*++
  184. Routine Description:
  185. This routine undoes whatever is done in ElfOpenLogFile.
  186. Arguments:
  187. pLogFile points to the log file structure.
  188. Return Value:
  189. NTSTATUS.
  190. Note:
  191. --*/
  192. {
  193. PELF_LOGFILE_HEADER pLogFileHeader;
  194. PVOID BaseAddress;
  195. ULONG Size;
  196. ELF_LOG2(FILES,
  197. "ElfpCloseLogfile: Closing and unmapping file %ws (%ws log)\n",
  198. pLogFile->LogFileName->Buffer,
  199. pLogFile->LogModuleName->Buffer);
  200. #ifdef CORRUPTED
  201. //
  202. // Just for debugging a log corruption problem
  203. //
  204. if (!VerifyLogIntegrity(pLogFile))
  205. {
  206. ELF_LOG1(FILES,
  207. "ElfpCloseLogfile: Integrity check failed for file %ws\n",
  208. pLogFile->LogFileName->Buffer);
  209. }
  210. #endif // CORRUPTED
  211. //
  212. // If the dirty bit is set, update the file header before closing it.
  213. // Check to be sure it's not a backup file that just had the dirty
  214. // bit set when it was copied.
  215. //
  216. if (pLogFile->Flags & ELF_LOGFILE_HEADER_DIRTY
  217. &&
  218. !(Flags & ELF_LOG_CLOSE_BACKUP))
  219. {
  220. pLogFile->Flags &= ~(ELF_LOGFILE_HEADER_DIRTY |
  221. ELF_LOGFILE_ARCHIVE_SET ); // Remove dirty &
  222. // archive bits
  223. if(pLogFile->BaseAddress)
  224. {
  225. pLogFileHeader = (PELF_LOGFILE_HEADER) pLogFile->BaseAddress;
  226. pLogFileHeader->StartOffset = pLogFile->BeginRecord;
  227. pLogFileHeader->EndOffset = pLogFile->EndRecord;
  228. pLogFileHeader->CurrentRecordNumber = pLogFile->CurrentRecordNumber;
  229. pLogFileHeader->OldestRecordNumber = pLogFile->OldestRecordNumber;
  230. pLogFileHeader->Flags = pLogFile->Flags;
  231. }
  232. }
  233. //
  234. // Decrement the reference count, and if it goes to zero, unmap the file
  235. // and close the handle. Also force the close if fForceClosed is TRUE.
  236. //
  237. if ((--pLogFile->RefCount == 0) || (Flags & ELF_LOG_CLOSE_FORCE))
  238. {
  239. //
  240. // Last user has gone.
  241. // Close all the views and the file and section handles. Free up
  242. // any extra memory we had reserved, and unlink any structures
  243. //
  244. if (pLogFile->BaseAddress) // Unmap it if it was allocated
  245. {
  246. NtUnmapViewOfSection(NtCurrentProcess(),
  247. pLogFile->BaseAddress);
  248. pLogFile->BaseAddress = NULL;
  249. }
  250. if (pLogFile->SectionHandle)
  251. {
  252. NtClose(pLogFile->SectionHandle);
  253. pLogFile->SectionHandle = NULL;
  254. }
  255. if (pLogFile->FileHandle)
  256. {
  257. NtClose(pLogFile->FileHandle);
  258. pLogFile->FileHandle = NULL;
  259. }
  260. }
  261. return STATUS_SUCCESS;
  262. } // ElfpCloseLogFile
  263. NTSTATUS
  264. RevalidateLogHeader(
  265. PELF_LOGFILE_HEADER pLogFileHeader,
  266. PLOGFILE pLogFile
  267. )
  268. /*++
  269. Routine Description:
  270. This routine is called if we encounter a "dirty" log file. The
  271. routine walks through the file until it finds a signature for a valid log
  272. record. Then it walks backwards from the first record it found until it
  273. finds the EOF record from the other direction. It then walks forward thru
  274. the file until it finds the EOF record, or an invalid record.
  275. It then rebuilds the header and writes it back to the log. If it can't
  276. find any valid records, it rebuilds the header to reflect an empty log
  277. file. If it finds a trashed file, it writes 256 bytes of the log out in
  278. an event to the system log.
  279. Arguments:
  280. pLogFileHeader points to the header of the log file.
  281. pLogFile points to the log file structure.
  282. Return Value:
  283. NTSTATUS.
  284. Note:
  285. This is an expensive routine since it scans the entire file.
  286. It assumes that the records are on DWORD boundaries.
  287. --*/
  288. {
  289. PVOID Start, End;
  290. PDWORD pSignature;
  291. PEVENTLOGRECORD pEvent;
  292. PEVENTLOGRECORD FirstRecord;
  293. PEVENTLOGRECORD FirstPhysicalRecord;
  294. PEVENTLOGRECORD pLastGoodRecord = NULL;
  295. NTSTATUS Status;
  296. IO_STATUS_BLOCK IoStatusBlock;
  297. LARGE_INTEGER ByteOffset;
  298. SIZE_T Size;
  299. int iNumWrap = 0;
  300. ELF_LOG1(FILES,
  301. "RevalidateLogHeader: %ws log had dirty bit set -- revalidating\n",
  302. pLogFile->LogModuleName->Buffer);
  303. //
  304. // BUGBUG: This function is full of return statements from inside the
  305. // try-except block. They need to go away.
  306. //
  307. try
  308. {
  309. //
  310. // Physical start and end of log file (skipping header)
  311. //
  312. Start = (PVOID) ((PBYTE) pLogFile->BaseAddress + FILEHEADERBUFSIZE);
  313. End = (PVOID) ((PBYTE) pLogFile->BaseAddress + pLogFile->ActualMaxFileSize);
  314. //
  315. // First see if the log has wrapped. The EOFRECORDSIZE is for the one
  316. // case where the EOF record wraps so that its final length just replaces
  317. // the next record's starting length
  318. //
  319. pEvent = (PEVENTLOGRECORD) Start;
  320. if (pEvent->Reserved != ELF_LOG_FILE_SIGNATURE
  321. ||
  322. pEvent->RecordNumber != 1
  323. ||
  324. pEvent->Length == ELFEOFRECORDSIZE)
  325. {
  326. ELF_LOG1(FILES,
  327. "RevalidateLogHeader: %ws log has wrapped -- looking for "
  328. "first valid record\n",
  329. pLogFile->LogModuleName->Buffer);
  330. //
  331. // Log has already wrapped, go looking for the first valid record
  332. //
  333. for (pSignature = (PDWORD) Start;
  334. (PVOID) pSignature < End;
  335. pSignature++)
  336. {
  337. if (*pSignature == ELF_LOG_FILE_SIGNATURE)
  338. {
  339. //
  340. // Make sure it's really a record
  341. //
  342. pEvent = CONTAINING_RECORD(pSignature, EVENTLOGRECORD, Reserved);
  343. if (!ValidFilePos(pEvent, Start, End, End, pLogFileHeader, TRUE))
  344. {
  345. //
  346. // Nope, not really, keep trying
  347. //
  348. continue;
  349. }
  350. //
  351. // This is a valid record, Remember this so you can use
  352. // it later
  353. //
  354. FirstPhysicalRecord = pEvent;
  355. ELF_LOG1(FILES,
  356. "RevalidateLogHeader: First physical record in %ws log "
  357. "found at %p\n",
  358. FirstPhysicalRecord);
  359. //
  360. // Walk backwards from here (wrapping if necessary) until
  361. // you hit the EOF record or an invalid record.
  362. //
  363. while (pEvent
  364. &&
  365. ValidFilePos(pEvent, Start, End, End, pLogFileHeader, TRUE))
  366. {
  367. //
  368. // See if it's the EOF record
  369. //
  370. //
  371. // BUGBUG: If (End - pEvent) is less than ELFEOFUNIQUEPART,
  372. // we never validate what should be the remainder of
  373. // the EOF record at the start of the logfile
  374. //
  375. if (IS_EOF(pEvent,
  376. min(ELFEOFUNIQUEPART,
  377. (ULONG_PTR) ((PBYTE) End - (PBYTE) pEvent))))
  378. {
  379. ELF_LOG2(FILES,
  380. "RevalidateLogHeader: Found EOF record (backwards "
  381. "scan) for log %ws at %p\n",
  382. pLogFile->LogModuleName->Buffer,
  383. pEvent);
  384. break;
  385. }
  386. pLastGoodRecord = pEvent;
  387. pEvent = NextRecordPosition (
  388. EVENTLOG_SEQUENTIAL_READ |
  389. EVENTLOG_BACKWARDS_READ,
  390. pEvent,
  391. pEvent->Length,
  392. 0,
  393. 0,
  394. End,
  395. Start);
  396. if(pLastGoodRecord < pEvent)
  397. iNumWrap++;
  398. //
  399. // Make sure we're not in an infinite loop
  400. //
  401. if (pEvent == FirstPhysicalRecord || iNumWrap > 4)
  402. {
  403. ELF_LOG1(FILES,
  404. "RevalidateLogHeader: Infinite loop (backwards scan) "
  405. "in %ws log -- no EOF or invalid record found\n",
  406. pLogFile->LogModuleName->Buffer);
  407. return STATUS_UNSUCCESSFUL;
  408. }
  409. }
  410. //
  411. // Found the first record, now go look for the last
  412. //
  413. ELF_LOG2(FILES,
  414. "RevalidateLogHeader: First valid record in %ws "
  415. "log is at %p\n",
  416. pLogFile->LogModuleName->Buffer,
  417. pLastGoodRecord);
  418. FirstRecord = pLastGoodRecord;
  419. break;
  420. }
  421. }
  422. if (pSignature == End || pLastGoodRecord == NULL)
  423. {
  424. //
  425. // Either there were no valid records in the file or
  426. // the only valid record was the EOF record (which
  427. // means the log is trashed anyhow). Give up
  428. // and we'll set it to an empty log file.
  429. //
  430. ELF_LOG1(FILES,
  431. "RevalidateLogHeader: No valid records found in %ws log\n",
  432. pLogFile->LogModuleName->Buffer);
  433. return STATUS_UNSUCCESSFUL;
  434. }
  435. }
  436. else
  437. {
  438. ELF_LOG1(FILES,
  439. "RevalidateLogHeader: %ws log has not wrapped -- "
  440. "first record is at %p\n",
  441. pLogFile->LogModuleName->Buffer);
  442. //
  443. // We haven't wrapped yet
  444. //
  445. FirstPhysicalRecord = FirstRecord = Start;
  446. }
  447. //
  448. // Now read forward looking for the last good record
  449. //
  450. pEvent = FirstPhysicalRecord;
  451. while (pEvent
  452. &&
  453. ValidFilePos(pEvent, Start, End, End, pLogFileHeader, TRUE))
  454. {
  455. //
  456. // See if it's the EOF record
  457. //
  458. if (IS_EOF(pEvent,
  459. min(ELFEOFUNIQUEPART,
  460. (ULONG_PTR) ((PBYTE) End - (PBYTE) pEvent))))
  461. {
  462. ELF_LOG2(FILES,
  463. "RevalidateLogHeader: Found EOF record (forwards scan) "
  464. "for log %ws at %p\n",
  465. pLogFile->LogModuleName->Buffer,
  466. pEvent);
  467. break;
  468. }
  469. pLastGoodRecord = pEvent;
  470. pEvent = NextRecordPosition(EVENTLOG_SEQUENTIAL_READ |
  471. EVENTLOG_FORWARDS_READ,
  472. pEvent,
  473. pEvent->Length,
  474. 0,
  475. 0,
  476. End,
  477. Start);
  478. if(pLastGoodRecord > pEvent)
  479. iNumWrap++;
  480. //
  481. // Make sure we're not in an infinite loop
  482. //
  483. if (pEvent == FirstPhysicalRecord || iNumWrap > 4)
  484. {
  485. ELF_LOG1(FILES,
  486. "RevalidateLogHeader: Infinite loop (forwards scan) "
  487. "in %ws log -- no EOF or invalid record found\n",
  488. pLogFile->LogModuleName->Buffer);
  489. return(STATUS_UNSUCCESSFUL);
  490. }
  491. }
  492. //
  493. // Now we know the first record (FirstRecord) and the last record
  494. // (pLastGoodRecord) so we can create the header an EOF record and
  495. // write them out (EOF record gets written at pEvent)
  496. //
  497. // First the EOF record
  498. //
  499. //
  500. // If the EOF record was wrapped, we can't write out the entire record at
  501. // once. Instead, we'll write out as much as we can and then write the
  502. // rest out at the beginning of the log
  503. //
  504. Size = min((PBYTE) End - (PBYTE) pEvent, ELFEOFRECORDSIZE);
  505. if (Size != ELFEOFRECORDSIZE)
  506. {
  507. // Make absolutely sure we have enough room to write the remainder of
  508. // the EOF record. Note that this should always be the case since the
  509. // record was wrapped around to begin with. To do this, make sure
  510. // that the number of bytes we're writing after the header is <= the
  511. // offset of the first record from the end of the header
  512. //
  513. //Refer to bug# 359188. This scenario should never happen but because of
  514. //unknown reasons, it happened to occur in one of the log files. so the
  515. //following check which was ASSERT in the earlier version was changed to
  516. //return STATUS_UNSUCCESSFUL
  517. if((ELFEOFRECORDSIZE - Size) <= (ULONG)((PBYTE) FirstRecord
  518. - (PBYTE) pLogFileHeader
  519. - FILEHEADERBUFSIZE))
  520. {
  521. ELF_LOG1(FILES,
  522. "RevalidateLogHeader: Overlapping EOF record "
  523. "in %ws log -- No space for writing remainder of EOF record between file header and first record \n",
  524. pLogFile->LogModuleName->Buffer);
  525. return(STATUS_UNSUCCESSFUL);
  526. }
  527. }
  528. EOFRecord.BeginRecord = (ULONG) ((PBYTE) FirstRecord - (PBYTE) pLogFileHeader);
  529. EOFRecord.EndRecord = (ULONG) ((PBYTE) pEvent - (PBYTE) pLogFileHeader);
  530. EOFRecord.CurrentRecordNumber = pLastGoodRecord->RecordNumber + 1;
  531. EOFRecord.OldestRecordNumber = FirstRecord->RecordNumber;
  532. ByteOffset = RtlConvertUlongToLargeInteger((ULONG) ((PBYTE) pEvent
  533. - (PBYTE) pLogFileHeader));
  534. Status = NtWriteFile(
  535. pLogFile->FileHandle, // Filehandle
  536. NULL, // Event
  537. NULL, // APC routine
  538. NULL, // APC context
  539. &IoStatusBlock, // IO_STATUS_BLOCK
  540. &EOFRecord, // Buffer
  541. (ULONG) Size, // Length
  542. &ByteOffset, // Byteoffset
  543. NULL); // Key
  544. if (!NT_SUCCESS(Status))
  545. {
  546. ELF_LOG2(ERROR,
  547. "RevalidateLogHeader: EOF record write for %ws log failed %#x\n",
  548. pLogFile->LogModuleName->Buffer,
  549. Status);
  550. return Status;
  551. }
  552. if (Size != ELFEOFRECORDSIZE)
  553. {
  554. PBYTE pBuff;
  555. pBuff = (PBYTE) &EOFRecord + Size;
  556. Size = ELFEOFRECORDSIZE - Size;
  557. ByteOffset = RtlConvertUlongToLargeInteger(FILEHEADERBUFSIZE);
  558. // We have already made sure we have enough room to write the remainder of
  559. // the EOF record.
  560. //ASSERT(Size <= (ULONG)((PBYTE) FirstRecord
  561. // - (PBYTE) pLogFileHeader
  562. // - FILEHEADERBUFSIZE));
  563. Status = NtWriteFile(
  564. pLogFile->FileHandle, // Filehandle
  565. NULL, // Event
  566. NULL, // APC routine
  567. NULL, // APC context
  568. &IoStatusBlock, // IO_STATUS_BLOCK
  569. pBuff, // Buffer
  570. (ULONG) Size, // Length
  571. &ByteOffset, // Byteoffset
  572. NULL); // Key
  573. if (!NT_SUCCESS(Status))
  574. {
  575. ELF_LOG2(ERROR,
  576. "RevalidateLogHeader: EOF record write (part 2) for "
  577. "%ws log failed %#x\n",
  578. pLogFile->LogModuleName->Buffer,
  579. Status);
  580. return Status;
  581. }
  582. }
  583. //
  584. // Now the header
  585. //
  586. pLogFileHeader->StartOffset = (ULONG) ((PBYTE) FirstRecord - (PBYTE) pLogFileHeader);
  587. pLogFileHeader->EndOffset = (ULONG) ((PBYTE) pEvent- (PBYTE) pLogFileHeader);
  588. pLogFileHeader->CurrentRecordNumber = pLastGoodRecord->RecordNumber + 1;
  589. pLogFileHeader->OldestRecordNumber = FirstRecord->RecordNumber;
  590. pLogFileHeader->HeaderSize = pLogFileHeader->EndHeaderSize = FILEHEADERBUFSIZE;
  591. pLogFileHeader->Signature = ELF_LOG_FILE_SIGNATURE;
  592. pLogFileHeader->Flags = 0;
  593. if (pLogFileHeader->StartOffset != FILEHEADERBUFSIZE)
  594. {
  595. pLogFileHeader->Flags |= ELF_LOGFILE_HEADER_WRAP;
  596. }
  597. pLogFileHeader->MaxSize = pLogFile->ActualMaxFileSize;
  598. pLogFileHeader->Retention = pLogFile->Retention;
  599. pLogFileHeader->MajorVersion = ELF_VERSION_MAJOR;
  600. pLogFileHeader->MinorVersion = ELF_VERSION_MINOR;
  601. //
  602. // Now flush this to disk to commit it
  603. //
  604. Start = pLogFile->BaseAddress;
  605. Size = FILEHEADERBUFSIZE;
  606. Status = NtFlushVirtualMemory(NtCurrentProcess(),
  607. &Start,
  608. &Size,
  609. &IoStatusBlock);
  610. if (!NT_SUCCESS(Status))
  611. {
  612. ELF_LOG2(ERROR,
  613. "RevalidateLogHeader: NtFlushVirtualMemory for %ws log "
  614. "header failed %#x\n",
  615. pLogFile->LogModuleName->Buffer,
  616. Status);
  617. }
  618. }
  619. except(EXCEPTION_EXECUTE_HANDLER)
  620. {
  621. Status = STATUS_UNSUCCESSFUL;
  622. }
  623. return Status;
  624. }
  625. NTSTATUS
  626. ElfOpenLogFile (
  627. PLOGFILE pLogFile,
  628. ELF_LOG_TYPE LogType
  629. )
  630. /*++
  631. Routine Description:
  632. Open the log file, create it if it does not exist.
  633. Create a section and map a view into the log file.
  634. Write out the header to the file, if it is newly created.
  635. If "dirty", update the "start" and "end" pointers by scanning
  636. the file. Set AUTOWRAP if the "start" does not start right after
  637. the file header.
  638. Arguments:
  639. pLogFile -- pointer to the log file structure, with the relevant data
  640. filled in.
  641. CreateOptions -- options to be passed to NtCreateFile that indicate
  642. whether to open an existing file, or to create it
  643. if it does not exist.
  644. Return Value:
  645. NTSTATUS.
  646. Note:
  647. It is up to the caller to set the RefCount in the Logfile structure.
  648. --*/
  649. {
  650. NTSTATUS Status = STATUS_SUCCESS;
  651. OBJECT_ATTRIBUTES ObjectAttributes;
  652. IO_STATUS_BLOCK IoStatusBlock;
  653. LARGE_INTEGER MaximumSizeOfSection;
  654. LARGE_INTEGER ByteOffset;
  655. PELF_LOGFILE_HEADER pLogFileHeader;
  656. FILE_STANDARD_INFORMATION FileStandardInfo;
  657. ULONG IoStatusInformation;
  658. ULONG FileDesiredAccess;
  659. ULONG SectionDesiredAccess;
  660. ULONG SectionPageProtection;
  661. ULONG CreateOptions;
  662. ULONG CreateDisposition;
  663. SIZE_T ViewSize;
  664. //
  665. // File header in a new file has the "Start" and "End" pointers the
  666. // same since there are no records in the file.
  667. //
  668. static ELF_LOGFILE_HEADER FileHeaderBuf = { FILEHEADERBUFSIZE, // Size
  669. ELF_LOG_FILE_SIGNATURE,
  670. ELF_VERSION_MAJOR,
  671. ELF_VERSION_MINOR,
  672. FILEHEADERBUFSIZE, // Start offset
  673. FILEHEADERBUFSIZE, // End offset
  674. 1, // Next record #
  675. 0, // Oldest record #
  676. 0, // Maxsize
  677. 0, // Flags
  678. 0, // Retention
  679. FILEHEADERBUFSIZE // Size
  680. };
  681. //
  682. // Set the file open and section create options based on the type of log
  683. // file this is.
  684. //
  685. switch (LogType)
  686. {
  687. case ElfNormalLog:
  688. ELF_LOG0(FILES,
  689. "ElfpOpenLogfile: Opening ElfNormalLog\n");
  690. CreateDisposition = FILE_OPEN_IF;
  691. FileDesiredAccess = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
  692. SectionDesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE
  693. | SECTION_QUERY | SECTION_EXTEND_SIZE;
  694. SectionPageProtection = PAGE_READWRITE;
  695. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  696. break;
  697. case ElfSecurityLog:
  698. ELF_LOG0(FILES,
  699. "ElfpOpenLogfile: Opening ElfSecurityLog\n");
  700. CreateDisposition = FILE_OPEN_IF;
  701. FileDesiredAccess = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
  702. SectionDesiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE
  703. | SECTION_QUERY | SECTION_EXTEND_SIZE;
  704. SectionPageProtection = PAGE_READWRITE;
  705. CreateOptions = FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT;
  706. break;
  707. case ElfBackupLog:
  708. ELF_LOG0(FILES,
  709. "ElfpOpenLogfile: Opening ElfBackupLog\n");
  710. CreateDisposition = FILE_OPEN;
  711. FileDesiredAccess = GENERIC_READ | SYNCHRONIZE;
  712. SectionDesiredAccess = SECTION_MAP_READ | SECTION_QUERY;
  713. SectionPageProtection = PAGE_READONLY;
  714. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  715. break;
  716. }
  717. ELF_LOG1(FILES,
  718. "ElfpOpenLogfile: Opening and mapping %ws\n",
  719. pLogFile->LogFileName->Buffer);
  720. if (pLogFile->FileHandle != NULL)
  721. {
  722. //
  723. // The log file is already in use. Do not reopen or remap it.
  724. //
  725. ELF_LOG0(FILES,
  726. "ElfpOpenLogfile: Log file already in use by another module\n");
  727. }
  728. else
  729. {
  730. //
  731. // Initialize the logfile structure so that it is easier to clean
  732. // up.
  733. //
  734. pLogFile->ActualMaxFileSize = ELF_DEFAULT_LOG_SIZE;
  735. pLogFile->Flags = 0;
  736. pLogFile->BaseAddress = NULL;
  737. pLogFile->SectionHandle = NULL;
  738. //
  739. // Set up the object attributes structure for the Log File
  740. //
  741. InitializeObjectAttributes(&ObjectAttributes,
  742. pLogFile->LogFileName,
  743. OBJ_CASE_INSENSITIVE,
  744. NULL,
  745. NULL);
  746. //
  747. // Open the Log File. Create it if it does not exist and it's not
  748. // being opened as a backup file. If creating, create a file of
  749. // the maximum size configured.
  750. //
  751. MaximumSizeOfSection = RtlConvertUlongToLargeInteger(ELF_DEFAULT_LOG_SIZE);
  752. Status = NtCreateFile(&pLogFile->FileHandle,
  753. FileDesiredAccess,
  754. &ObjectAttributes,
  755. &IoStatusBlock,
  756. &MaximumSizeOfSection,
  757. FILE_ATTRIBUTE_NORMAL,
  758. FILE_SHARE_READ,
  759. CreateDisposition,
  760. CreateOptions,
  761. NULL,
  762. 0);
  763. if (!NT_SUCCESS(Status))
  764. {
  765. ELF_LOG2(ERROR,
  766. "ElfpOpenLogfile: Open of %ws log failed %#x\n",
  767. pLogFile->LogModuleName->Buffer,
  768. Status);
  769. goto cleanup;
  770. }
  771. //
  772. // If the file already existed, get its size and use that as the
  773. // actual size of the file.
  774. //
  775. IoStatusInformation = (ULONG) IoStatusBlock.Information;
  776. if (!( IoStatusInformation & FILE_CREATED ))
  777. {
  778. ELF_LOG1(FILES,
  779. "ElfpOpenLogfile: File %ws already exists\n",
  780. pLogFile->LogFileName->Buffer);
  781. Status = NtQueryInformationFile(pLogFile->FileHandle,
  782. &IoStatusBlock,
  783. &FileStandardInfo,
  784. sizeof (FileStandardInfo),
  785. FileStandardInformation);
  786. if (!NT_SUCCESS(Status))
  787. {
  788. ELF_LOG2(ERROR,
  789. "ElfpOpenLogfile: NtQueryInformationFile for %ws failed %#x\n",
  790. pLogFile->LogFileName->Buffer,
  791. Status);
  792. goto cleanup;
  793. }
  794. else
  795. {
  796. ELF_LOG3(FILES,
  797. "ElfpOpenLogfile: Use existing size for %ws log: %#x:%#x\n",
  798. pLogFile->LogModuleName->Buffer,
  799. FileStandardInfo.EndOfFile.HighPart,
  800. FileStandardInfo.EndOfFile.LowPart);
  801. MaximumSizeOfSection.LowPart = FileStandardInfo.EndOfFile.LowPart;
  802. MaximumSizeOfSection.HighPart = FileStandardInfo.EndOfFile.HighPart;
  803. //
  804. // Make sure that the high DWORD of the file size is ZERO.
  805. //
  806. // BUGBUG: Is this OK for 64-bit machines?
  807. //
  808. ASSERT(MaximumSizeOfSection.HighPart == 0);
  809. //
  810. // If the filesize if 0, set it to the minimum size
  811. //
  812. if (MaximumSizeOfSection.LowPart == 0)
  813. {
  814. ELF_LOG1(FILES,
  815. "ElfpOpenLogfile: File was size 0 -- setting it to %#x\n",
  816. ELF_DEFAULT_LOG_SIZE);
  817. MaximumSizeOfSection.LowPart = ELF_DEFAULT_LOG_SIZE;
  818. }
  819. //
  820. // Set actual size of file
  821. //
  822. pLogFile->ActualMaxFileSize = MaximumSizeOfSection.LowPart;
  823. //
  824. // If the size of the log file is reduced, a clear must
  825. // happen for this to take effect
  826. //
  827. if (pLogFile->ActualMaxFileSize > pLogFile->ConfigMaxFileSize)
  828. {
  829. pLogFile->ConfigMaxFileSize = pLogFile->ActualMaxFileSize;
  830. }
  831. }
  832. }
  833. //
  834. // Create a section mapped to the Log File just opened
  835. //
  836. Status = NtCreateSection(
  837. &pLogFile->SectionHandle,
  838. SectionDesiredAccess,
  839. NULL,
  840. &MaximumSizeOfSection,
  841. SectionPageProtection,
  842. SEC_COMMIT,
  843. pLogFile->FileHandle);
  844. if (!NT_SUCCESS(Status))
  845. {
  846. ELF_LOG2(ERROR,
  847. "ElfpOpenLogfile: NtCreateSection for %ws failed %#x\n",
  848. pLogFile->LogFileName->Buffer,
  849. Status);
  850. goto cleanup;
  851. }
  852. //
  853. // Map a view of the Section into the eventlog address space
  854. //
  855. ViewSize = 0;
  856. Status = NtMapViewOfSection(
  857. pLogFile->SectionHandle,
  858. NtCurrentProcess(),
  859. &pLogFile->BaseAddress,
  860. 0,
  861. 0,
  862. NULL,
  863. &ViewSize,
  864. ViewUnmap,
  865. 0,
  866. SectionPageProtection);
  867. pLogFile->ViewSize = (ULONG) ViewSize;
  868. if (!NT_SUCCESS(Status))
  869. {
  870. ELF_LOG2(ERROR,
  871. "ElfpOpenLogfile: NtMapViewOfSection for %ws failed %#x\n",
  872. pLogFile->LogFileName->Buffer,
  873. Status);
  874. goto cleanup;
  875. }
  876. pLogFile->bFullAlertDone = FALSE;
  877. //
  878. // If the file was just created, write out the file header.
  879. //
  880. if (IoStatusInformation & FILE_CREATED)
  881. {
  882. ELF_LOG1(FILES,
  883. "ElfpOpenLogfile: Created file %ws\n",
  884. pLogFile->LogFileName->Buffer);
  885. JustCreated:
  886. FileHeaderBuf.MaxSize = pLogFile->ActualMaxFileSize;
  887. FileHeaderBuf.Flags = 0;
  888. FileHeaderBuf.Retention = pLogFile->Retention;
  889. //
  890. // Copy the header into the file
  891. //
  892. ByteOffset = RtlConvertUlongToLargeInteger(0);
  893. Status = NtWriteFile(
  894. pLogFile->FileHandle, // Filehandle
  895. NULL, // Event
  896. NULL, // APC routine
  897. NULL, // APC context
  898. &IoStatusBlock, // IO_STATUS_BLOCK
  899. &FileHeaderBuf, // Buffer
  900. FILEHEADERBUFSIZE, // Length
  901. &ByteOffset, // Byteoffset
  902. NULL); // Key
  903. if (!NT_SUCCESS(Status))
  904. {
  905. ELF_LOG2(ERROR,
  906. "ElfpOpenLogfile: File header write for %ws failed %#x\n",
  907. pLogFile->LogFileName->Buffer,
  908. Status);
  909. goto cleanup;
  910. }
  911. //
  912. // Copy the "EOF" record right after the header
  913. //
  914. ByteOffset = RtlConvertUlongToLargeInteger(FILEHEADERBUFSIZE);
  915. Status = NtWriteFile(
  916. pLogFile->FileHandle, // Filehandle
  917. NULL, // Event
  918. NULL, // APC routine
  919. NULL, // APC context
  920. &IoStatusBlock, // IO_STATUS_BLOCK
  921. &EOFRecord, // Buffer
  922. ELFEOFRECORDSIZE, // Length
  923. &ByteOffset, // Byteoffset
  924. NULL); // Key
  925. if (!NT_SUCCESS(Status))
  926. {
  927. ELF_LOG2(ERROR,
  928. "ElfpOpenLogfile: EOF record write for %ws failed %#x\n",
  929. pLogFile->LogFileName->Buffer,
  930. Status);
  931. goto cleanup;
  932. }
  933. }
  934. //
  935. // Check to ensure that this is a valid log file. We look at the
  936. // size of the header and the signature to see if they match, as
  937. // well as checking the version number.
  938. //
  939. pLogFileHeader = (PELF_LOGFILE_HEADER) (pLogFile->BaseAddress);
  940. if ((pLogFileHeader->HeaderSize != FILEHEADERBUFSIZE)
  941. ||
  942. (pLogFileHeader->EndHeaderSize != FILEHEADERBUFSIZE)
  943. ||
  944. (pLogFileHeader->Signature != ELF_LOG_FILE_SIGNATURE)
  945. ||
  946. (pLogFileHeader->MajorVersion != ELF_VERSION_MAJOR)
  947. ||
  948. (pLogFileHeader->MinorVersion != ELF_VERSION_MINOR))
  949. {
  950. //
  951. // This file is corrupt -- reset it to an empty log unless
  952. // it's being opened as a backup file. If it is, fail the
  953. // open
  954. //
  955. ELF_LOG1(FILES,
  956. "ElfpOpenLogfile: Invalid file header in %ws\n",
  957. pLogFile->LogFileName->Buffer);
  958. if (LogType == ElfBackupLog)
  959. {
  960. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  961. goto cleanup;
  962. }
  963. else
  964. {
  965. ElfpCreateQueuedAlert(ALERT_ELF_LogFileCorrupt,
  966. 1,
  967. &pLogFile->LogModuleName->Buffer);
  968. //
  969. // Treat it like it was just created
  970. //
  971. goto JustCreated;
  972. }
  973. }
  974. else
  975. {
  976. //
  977. // If the "dirty" bit is set in the file header, then we need to
  978. // revalidate the BeginRecord and EndRecord fields since we did not
  979. // get a chance to write them out before the system was rebooted.
  980. // If the dirty bit is set and it's a backup file, just fail the
  981. // open.
  982. //
  983. if (pLogFileHeader->Flags & ELF_LOGFILE_HEADER_DIRTY)
  984. {
  985. ELF_LOG1(FILES,
  986. "ElfpOpenLogfile: File %ws has dirty header\n",
  987. pLogFile->LogFileName->Buffer);
  988. if (LogType == ElfBackupLog)
  989. {
  990. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  991. goto cleanup;
  992. }
  993. else
  994. {
  995. Status = RevalidateLogHeader (pLogFileHeader, pLogFile);
  996. }
  997. }
  998. if (NT_SUCCESS(Status))
  999. {
  1000. //
  1001. // Set the beginning and end record positions in our
  1002. // data structure as well as the wrap flag if appropriate.
  1003. //
  1004. pLogFile->EndRecord = pLogFileHeader->EndOffset;
  1005. pLogFile->BeginRecord = pLogFileHeader->StartOffset;
  1006. if (pLogFileHeader->Flags & ELF_LOGFILE_HEADER_WRAP)
  1007. {
  1008. pLogFile->Flags |= ELF_LOGFILE_HEADER_WRAP;
  1009. }
  1010. ELF_LOG3(FILES,
  1011. "ElfpOpenLogfile: %ws log -- BeginRecord: %#x, EndRecord: %#x\n",
  1012. pLogFile->LogModuleName->Buffer,
  1013. pLogFile->BeginRecord,
  1014. pLogFile->EndRecord);
  1015. }
  1016. else
  1017. {
  1018. //
  1019. // Couldn't validate the file, treat it like it was just
  1020. // created (turn it into an empty file)
  1021. //
  1022. goto JustCreated;
  1023. }
  1024. #ifdef CORRUPTED
  1025. //
  1026. // Just for debugging a log corruption problem
  1027. //
  1028. if (!VerifyLogIntegrity(pLogFile))
  1029. {
  1030. ELF_LOG1(ERROR,
  1031. "ElfpOpenLogfile: Integrity check failed for %ws\n",
  1032. pLogFile->LogFileName->Buffer);
  1033. }
  1034. #endif // CORRUPTED
  1035. }
  1036. //
  1037. // Fill in the first and last record number values in the LogFile
  1038. // data structure.
  1039. //
  1040. // SS: Save the record number of the first record in this session
  1041. // so that if the cluster service starts after the eventlog service
  1042. // it will be able to forward the pending records for replication
  1043. // when the cluster service registers
  1044. //
  1045. pLogFile->SessionStartRecordNumber = pLogFileHeader->CurrentRecordNumber;
  1046. pLogFile->CurrentRecordNumber = pLogFileHeader->CurrentRecordNumber;
  1047. pLogFile->OldestRecordNumber = pLogFileHeader->OldestRecordNumber;
  1048. }
  1049. return Status;
  1050. cleanup:
  1051. //
  1052. // Clean up anything that got allocated
  1053. //
  1054. if (pLogFile->ViewSize)
  1055. {
  1056. NtUnmapViewOfSection(NtCurrentProcess(), pLogFile->BaseAddress);
  1057. pLogFile->BaseAddress = NULL;
  1058. }
  1059. if (pLogFile->SectionHandle)
  1060. {
  1061. NtClose(pLogFile->SectionHandle);
  1062. pLogFile->SectionHandle = NULL;
  1063. }
  1064. if (pLogFile->FileHandle)
  1065. {
  1066. NtClose (pLogFile->FileHandle);
  1067. pLogFile->FileHandle = NULL;
  1068. }
  1069. return Status;
  1070. }