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.

3619 lines
94 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. srlog.c
  5. Abstract:
  6. this file implements the sr logging functionality
  7. Author:
  8. Kanwaljit Marok (kmarok) 01-May-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "srdefs.h"
  13. //
  14. // Some SR_LOG related macros
  15. //
  16. #define MAX_RENAME_TRIES 1000
  17. #define SR_LOG_FLAGS_ENABLE 0x00000001
  18. #define SR_LOG_FLAGS_DIRTY 0x00000010
  19. #define SR_MAX_LOG_FILE_SIZE (1024*1024)
  20. //
  21. // system volume information\_restore{machineguid}
  22. //
  23. #define SR_DATASTORE_PREFIX_LENGTH 79 * sizeof(WCHAR)
  24. //
  25. // Length of \_restore.{machineguid}\RPXX\S0000000.ACL
  26. //
  27. #define SR_ACL_FILENAME_LENGTH (SR_DATASTORE_PREFIX_LENGTH + \
  28. 32* sizeof(WCHAR))
  29. #define SR_INLINE_ACL_SIZE(AclInfoSize) (sizeof(RECORD_HEADER)+ AclInfoSize)
  30. #define SR_FILE_ACL_SIZE(pVolumeName) (sizeof(RECORD_HEADER) + \
  31. pVolumeName->Length + \
  32. SR_ACL_FILENAME_LENGTH)
  33. #define UPDATE_LOG_OFFSET( pLogContext, BytesWritten ) \
  34. ((pLogContext)->FileOffset += BytesWritten)
  35. #define RESET_LOG_BUFFER( pLogContext ) \
  36. ((pLogContext)->BufferOffset = 0, \
  37. (pLogContext)->LastBufferOffset = 0)
  38. #define RESET_LOG_CONTEXT( pLogContext ) \
  39. ((pLogContext)->FileOffset = 0, \
  40. RESET_LOG_BUFFER( pLogContext ), \
  41. (pLogContext)->LoggingFlags = 0, \
  42. (pLogContext)->AllocationSize = 0)
  43. #define SET_ENABLE_FLAG( pLogContext ) \
  44. SetFlag( pLogContext->LoggingFlags, SR_LOG_FLAGS_ENABLE )
  45. #define CLEAR_ENABLE_FLAG( pLogContext ) \
  46. ClearFlag( pLogContext->LoggingFlags, SR_LOG_FLAGS_ENABLE )
  47. #define SET_DIRTY_FLAG( pLogContext ) \
  48. SetFlag( pLogContext->LoggingFlags, SR_LOG_FLAGS_DIRTY)
  49. #define CLEAR_DIRTY_FLAG( pLogContext ) \
  50. ClearFlag( pLogContext->LoggingFlags, SR_LOG_FLAGS_DIRTY )
  51. //
  52. // Context passed to SrCreateFile
  53. //
  54. typedef struct _SR_OPEN_CONTEXT {
  55. //
  56. // Path to file
  57. //
  58. PUNICODE_STRING pPath;
  59. //
  60. // Handle will be returned here
  61. //
  62. HANDLE Handle;
  63. //
  64. // Open options
  65. //
  66. ACCESS_MASK DesiredAccess;
  67. ULONG FileAttributes;
  68. ULONG ShareAccess;
  69. ULONG CreateDisposition;
  70. ULONG CreateOptions;
  71. PSR_DEVICE_EXTENSION pExtension;
  72. } SR_OPEN_CONTEXT, *PSR_OPEN_CONTEXT;
  73. //
  74. // Note : These api can be called only when the FileSystem
  75. // is online and it is safe to read/write data.
  76. //
  77. VOID
  78. SrPackString(
  79. IN PBYTE pBuffer,
  80. IN DWORD BufferSize,
  81. IN DWORD RecordType,
  82. IN PUNICODE_STRING pString
  83. );
  84. NTSTATUS
  85. SrPackLogHeader(
  86. IN PSR_LOG_HEADER *ppLogHeader,
  87. IN PUNICODE_STRING pVolumePath
  88. );
  89. NTSTATUS
  90. SrPackAclInformation(
  91. IN PBYTE pBuffer,
  92. IN PSECURITY_DESCRIPTOR pSecInfo,
  93. IN ULONG SecInfoSize,
  94. IN PSR_DEVICE_EXTENSION pExtension,
  95. IN BOOLEAN bInline
  96. );
  97. VOID
  98. SrLoggerFlushDpc(
  99. IN PKDPC Dpc,
  100. IN PVOID DeferredContext,
  101. IN PVOID SystemArgument1,
  102. IN PVOID SystemArgument2
  103. );
  104. VOID
  105. SrLoggerFlushWorkItem (
  106. IN PDEVICE_OBJECT DeviceObject,
  107. IN PVOID Context
  108. );
  109. VOID
  110. SrLoggerAddLogContext(
  111. IN PSR_LOGGER_CONTEXT pLoggerInfo,
  112. IN PSR_LOG_CONTEXT pLogContext
  113. );
  114. NTSTATUS
  115. SrLoggerRemoveLogContext(
  116. IN PSR_LOGGER_CONTEXT pLoggerInfo,
  117. IN PSR_LOG_CONTEXT pLogContext
  118. );
  119. NTSTATUS
  120. SrLogOpen(
  121. IN PSR_LOG_CONTEXT pLogContext
  122. );
  123. NTSTATUS
  124. SrLogClose(
  125. IN PSR_LOG_CONTEXT pLogContext
  126. );
  127. NTSTATUS
  128. SrLogCheckAndRename(
  129. IN PSR_DEVICE_EXTENSION pExtension,
  130. IN PUNICODE_STRING pLogPath
  131. );
  132. NTSTATUS
  133. SrpLogWriteSynchronous(
  134. IN PSR_DEVICE_EXTENSION pExtension,
  135. IN PSR_LOG_CONTEXT pLogContext,
  136. IN PSR_LOG_ENTRY pLogEntry
  137. );
  138. #ifndef SYNC_LOG_WRITE
  139. NTSTATUS
  140. SrpLogWriteAsynchronous(
  141. IN PSR_DEVICE_EXTENSION pExtension,
  142. IN PSR_LOG_CONTEXT pLogContext,
  143. IN PSR_LOG_ENTRY pLogEntry
  144. );
  145. #endif
  146. NTSTATUS
  147. SrLogFlush (
  148. IN PSR_LOG_CONTEXT pLogContext
  149. );
  150. NTSTATUS
  151. SrLogSwitch(
  152. IN PSR_LOG_CONTEXT pLogContext
  153. );
  154. NTSTATUS
  155. SrGetRestorePointPath(
  156. IN PUNICODE_STRING pVolumeName,
  157. IN USHORT RestPtPathLength,
  158. OUT PUNICODE_STRING pRestPtPath
  159. );
  160. NTSTATUS
  161. SrGetAclFileName(
  162. IN PUNICODE_STRING pVolumeName,
  163. IN USHORT AclFileNameLength,
  164. OUT PUNICODE_STRING pAclFileName
  165. );
  166. NTSTATUS
  167. SrCreateFile(
  168. IN PSR_OPEN_CONTEXT pOpenContext
  169. );
  170. //
  171. // linker commands
  172. //
  173. #ifdef ALLOC_PRAGMA
  174. #pragma alloc_text( PAGE, SrPackString )
  175. #pragma alloc_text( PAGE, SrPackLogEntry )
  176. #pragma alloc_text( PAGE, SrPackLogHeader )
  177. #pragma alloc_text( PAGE, SrPackDebugInfo )
  178. #pragma alloc_text( PAGE, SrPackAclInformation )
  179. #pragma alloc_text( PAGE, SrLoggerStart )
  180. #pragma alloc_text( PAGE, SrLoggerStop )
  181. #pragma alloc_text( PAGE, SrLoggerFlushWorkItem )
  182. #pragma alloc_text( PAGE, SrLoggerAddLogContext )
  183. #pragma alloc_text( PAGE, SrLoggerRemoveLogContext )
  184. #pragma alloc_text( PAGE, SrLoggerSwitchLogs )
  185. #pragma alloc_text( PAGE, SrCreateFile )
  186. #pragma alloc_text( PAGE, SrLogOpen )
  187. #pragma alloc_text( PAGE, SrLogClose )
  188. #pragma alloc_text( PAGE, SrLogCheckAndRename )
  189. #pragma alloc_text( PAGE, SrLogStart )
  190. #pragma alloc_text( PAGE, SrLogStop )
  191. #pragma alloc_text( PAGE, SrLogFlush )
  192. #ifdef SYNC_LOG_WRITE
  193. #pragma alloc_text( PAGE, SrpLogWriteSynchronous )
  194. #else
  195. #pragma alloc_text( PAGE, SrpLogWriteAsynchronous )
  196. #endif
  197. #pragma alloc_text( PAGE, SrLogFlush )
  198. #pragma alloc_text( PAGE, SrLogWrite )
  199. #pragma alloc_text( PAGE, SrLogSwitch )
  200. #pragma alloc_text( PAGE, SrGetRestorePointPath )
  201. #pragma alloc_text( PAGE, SrGetLogFileName )
  202. #pragma alloc_text( PAGE, SrGetAclFileName )
  203. #pragma alloc_text( PAGE, SrGetAclInformation )
  204. #endif // ALLOC_PRAGMA
  205. /////////////////////////////////////////////////////////////////////
  206. //
  207. // Packing/Marshaling Routines : Marshals information into records
  208. //
  209. /////////////////////////////////////////////////////////////////////
  210. //++
  211. // Function:
  212. // SrPackString
  213. //
  214. // Description:
  215. // This function packs a string into a record.
  216. //
  217. // Arguments:
  218. // Pointer to memory to create the entry
  219. // Size of memory
  220. // Entry type
  221. // Pointer to unicode string
  222. //
  223. // Return Value:
  224. // None
  225. //--
  226. static
  227. VOID
  228. SrPackString(
  229. IN PBYTE pBuffer,
  230. IN DWORD BufferSize,
  231. IN DWORD RecordType,
  232. IN PUNICODE_STRING pString
  233. )
  234. {
  235. PRECORD_HEADER pHeader = (PRECORD_HEADER)pBuffer;
  236. PAGED_CODE();
  237. UNREFERENCED_PARAMETER( BufferSize );
  238. ASSERT( pBuffer );
  239. ASSERT( pString );
  240. pHeader->RecordSize = STRING_RECORD_SIZE( pString );
  241. ASSERT( pHeader->RecordSize <= BufferSize );
  242. pHeader->RecordType = RecordType;
  243. //
  244. // Copy string contents
  245. //
  246. RtlCopyMemory( pBuffer + sizeof(RECORD_HEADER),
  247. pString->Buffer,
  248. pString->Length );
  249. //
  250. // Add null terminator
  251. //
  252. *(PWCHAR)( pBuffer + sizeof(RECORD_HEADER) + pString->Length ) = UNICODE_NULL;
  253. } // SrPackString
  254. //++
  255. // Function:
  256. // SrPackLogEntry
  257. //
  258. // Description:
  259. // This function allocates and fills a SR_LOG_ENTRY structure. The
  260. // caller is responsible for freeing the memory returned in ppLogEntry.
  261. //
  262. // Arguments:
  263. // ppLogEntry - Pointer to a SR_LOG_ENTRY pointer. This gets set to the
  264. // the log entry structure that is allocated and initialized by this
  265. // routine.
  266. // EntryType - The type of log entry this is.
  267. // Attributes - The attributes for this file.
  268. // SequenceNum - The sequence number for this log entry.
  269. // pAclInfo - The ACL information for the file being modified, if needed.
  270. // AclInfoSize - The size in bytes of pAclInfo, if needed.
  271. // pDebugBlob - The debug blob to log, if needed.
  272. // pPath1 - The first full path for the file or dir that this log entry
  273. // pertains to, if needed.
  274. // Path1StreamLength - The length of the stream component of the name
  275. // in pPath1, if needed.
  276. // pTempPath - The path to the temporary file in the restore location,
  277. // if needed.
  278. // pPath2 - The second full path for the file or dir that this log entry
  279. // pertains to, if needed.
  280. // Path2StreamLength - The length of the stream component of the name
  281. // in pPath2, if needed.
  282. // pExtension - The SR device extension for this volume.
  283. // pShortName - The short name for the file or dir that this log entry
  284. // pertains to, if needed.
  285. //
  286. // Return Value:
  287. // This function returns STATUS_INSUFFICIENT_RESOURCES if it cannot
  288. // allocate a log entry record large enough to store this entry.
  289. //
  290. // If there is a problem getting the ACL info, that error status is
  291. // returned.
  292. //
  293. // If one of the parameters is ill-formed, STATUS_INVALID_PARAMETER
  294. // is returned.
  295. //
  296. // Otherwise, STATUS_SUCCESS is returned.
  297. //--
  298. NTSTATUS
  299. SrPackLogEntry(
  300. OUT PSR_LOG_ENTRY *ppLogEntry,
  301. IN ULONG EntryType,
  302. IN ULONG Attributes,
  303. IN INT64 SequenceNum,
  304. IN PSECURITY_DESCRIPTOR pAclInfo OPTIONAL,
  305. IN ULONG AclInfoSize OPTIONAL,
  306. IN PVOID pDebugBlob OPTIONAL,
  307. IN PUNICODE_STRING pPath1,
  308. IN USHORT Path1StreamLength,
  309. IN PUNICODE_STRING pTempPath OPTIONAL,
  310. IN PUNICODE_STRING pPath2 OPTIONAL,
  311. IN USHORT Path2StreamLength OPTIONAL,
  312. IN PSR_DEVICE_EXTENSION pExtension,
  313. IN PUNICODE_STRING pShortName OPTIONAL
  314. )
  315. {
  316. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  317. DWORD Size = 0;
  318. DWORD RequiredSize = 0;
  319. DWORD RecordSize = 0;
  320. PBYTE pLoc = NULL;
  321. DWORD EntryFlags = 0;
  322. BOOLEAN bAclInline = TRUE;
  323. PUCHAR pBuffer = NULL;
  324. PUNICODE_STRING pVolumeName;
  325. PSR_LOG_DEBUG_INFO pDebugInfo = (PSR_LOG_DEBUG_INFO) pDebugBlob;
  326. //
  327. // Unicode strings used for string manipulation.
  328. //
  329. UNICODE_STRING Path1Fix;
  330. UNICODE_STRING TempPathFix;
  331. UNICODE_STRING Path2Fix;
  332. PAGED_CODE();
  333. ASSERT( pPath1 != NULL );
  334. ASSERT( pExtension != NULL );
  335. ASSERT( ppLogEntry != NULL );
  336. pVolumeName = pExtension->pNtVolumeName;
  337. ASSERT( pVolumeName != NULL );
  338. // ====================================================================
  339. //
  340. // Prepare the necessary fields for the log entry.
  341. //
  342. // ====================================================================
  343. //
  344. // Remove the volume prefix from pPath1 and add the stream name to the
  345. // visible portion of the name, if there is one.
  346. //
  347. ASSERT( RtlPrefixUnicodeString( pVolumeName, pPath1, FALSE ) );
  348. ASSERT( IS_VALID_SR_STREAM_STRING( pPath1, Path1StreamLength ) );
  349. Path1Fix.Length = Path1Fix.MaximumLength = (pPath1->Length + Path1StreamLength) - pVolumeName->Length;
  350. Path1Fix.Buffer = (PWSTR)((PBYTE)pPath1->Buffer + pVolumeName->Length);
  351. //
  352. // Find the file name component of the pTempPath if that was passed in.
  353. //
  354. if (pTempPath != NULL)
  355. {
  356. PWSTR pFileName = NULL;
  357. ULONG FileNameLength;
  358. Status = SrFindCharReverse( pTempPath->Buffer,
  359. pTempPath->Length,
  360. L'\\',
  361. &pFileName,
  362. &FileNameLength );
  363. if (!NT_SUCCESS( Status ))
  364. {
  365. Status = STATUS_INVALID_PARAMETER;
  366. goto SrPackLogEntry_Exit;
  367. }
  368. ASSERT( pFileName != NULL );
  369. //
  370. // Move past the leading '\\'
  371. //
  372. pFileName++;
  373. FileNameLength -= sizeof( WCHAR );
  374. TempPathFix.Length = TempPathFix.MaximumLength = (USHORT) FileNameLength;
  375. TempPathFix.Buffer = pFileName;
  376. }
  377. //
  378. // Remove the volume prefix from pPath2 if that was provided. Also, add
  379. // the stream component to the visible portion of the name, if there
  380. // is a stream component.
  381. //
  382. if (pPath2 != NULL)
  383. {
  384. ASSERT( IS_VALID_SR_STREAM_STRING( pPath2, Path2StreamLength ) );
  385. if (RtlPrefixUnicodeString( pVolumeName,
  386. pPath2,
  387. FALSE ))
  388. {
  389. Path2Fix.Length = Path2Fix.MaximumLength = (pPath2->Length + Path2StreamLength) - pVolumeName->Length;
  390. Path2Fix.Buffer = (PWSTR)((PBYTE)pPath2->Buffer + pVolumeName->Length);
  391. }
  392. else
  393. {
  394. Path2Fix.Length = Path2Fix.MaximumLength = (pPath2->Length + Path2StreamLength);
  395. Path2Fix.Buffer = pPath2->Buffer;
  396. }
  397. }
  398. // ====================================================================
  399. //
  400. // Calculate the total size needed for the log entry based on the
  401. // components that we must log.
  402. //
  403. // ====================================================================
  404. // First, account for the SR_LOG_ENTRY header.
  405. RequiredSize = FIELD_OFFSET(SR_LOG_ENTRY, SubRecords);
  406. // Count pPath1
  407. RequiredSize += ( STRING_RECORD_SIZE(&Path1Fix) );
  408. // Count pTempPath, if we've got one
  409. if (pTempPath)
  410. {
  411. RequiredSize += ( STRING_RECORD_SIZE(&TempPathFix) );
  412. }
  413. // Count pPath2, if we've got one
  414. if (pPath2)
  415. {
  416. RequiredSize += ( STRING_RECORD_SIZE(&Path2Fix) );
  417. }
  418. // Count pAclInfo, if we've got one. At this point, we assume that the
  419. // Acl will be stored inline.
  420. if( pAclInfo )
  421. {
  422. RequiredSize += SR_INLINE_ACL_SIZE( AclInfoSize );
  423. }
  424. // Count pDebugInfo, if we've got any
  425. if (pDebugInfo)
  426. {
  427. RequiredSize += pDebugInfo->Header.RecordSize;
  428. }
  429. // Count pShortName, if we've got one
  430. if (pShortName != NULL && pShortName->Length > 0)
  431. {
  432. RequiredSize += ( STRING_RECORD_SIZE(pShortName) );
  433. }
  434. //
  435. // increment the size to accomodate the entry size at the end
  436. //
  437. RequiredSize += sizeof(DWORD);
  438. // ====================================================================
  439. //
  440. // Check if we meet the buffer size requirements and initialize the
  441. // record if we do.
  442. //
  443. // ====================================================================
  444. //
  445. // First, determine if we should keep the AclInfo inline or not.
  446. //
  447. if (SR_INLINE_ACL_SIZE( AclInfoSize ) > SR_MAX_INLINE_ACL_SIZE)
  448. {
  449. SrTrace( LOG, ("SR!Changing Acl to Non-resident form\n"));
  450. bAclInline = FALSE;
  451. RequiredSize -= SR_INLINE_ACL_SIZE( AclInfoSize );
  452. RequiredSize += SR_FILE_ACL_SIZE( pVolumeName );
  453. }
  454. //
  455. // Now allocate the buffer that will hold the log entry.
  456. //
  457. pBuffer = SrAllocateLogEntry( RequiredSize );
  458. if (pBuffer == NULL)
  459. {
  460. Status = STATUS_INSUFFICIENT_RESOURCES;
  461. goto SrPackLogEntry_Exit;
  462. }
  463. // ====================================================================
  464. //
  465. // We've got a big enough LogEntry, so now properly fill the LogEntry.
  466. //
  467. // ====================================================================
  468. //
  469. // Initialize the static part of SR_LOG_ENTRY
  470. //
  471. RtlZeroMemory( pBuffer, RequiredSize );
  472. //
  473. // StreamOverwrite should be StreamChange
  474. //
  475. if (EntryType == SrEventStreamOverwrite)
  476. {
  477. EntryType = SrEventStreamChange;
  478. }
  479. ((PSR_LOG_ENTRY) pBuffer)->MagicNum = SR_LOG_MAGIC_NUMBER;
  480. ((PSR_LOG_ENTRY) pBuffer)->EntryType = EntryType;
  481. ((PSR_LOG_ENTRY) pBuffer)->EntryFlags = EntryFlags;
  482. ((PSR_LOG_ENTRY) pBuffer)->Attributes = Attributes;
  483. ((PSR_LOG_ENTRY) pBuffer)->SequenceNum = SequenceNum;
  484. Size = FIELD_OFFSET( SR_LOG_ENTRY, SubRecords );
  485. //
  486. // add first filename string
  487. //
  488. pLoc = pBuffer + Size;
  489. RecordSize = STRING_RECORD_SIZE( &Path1Fix );
  490. SrPackString( pLoc,
  491. RecordSize,
  492. RecordTypeFirstPath,
  493. &Path1Fix );
  494. Size += RecordSize;
  495. //
  496. // add temp filename if passed
  497. //
  498. if( pTempPath )
  499. {
  500. pLoc = pBuffer + Size;
  501. RecordSize = STRING_RECORD_SIZE( &TempPathFix );
  502. SrPackString( pLoc,
  503. RecordSize,
  504. RecordTypeTempPath,
  505. &TempPathFix );
  506. ((PSR_LOG_ENTRY) pBuffer)->EntryFlags |= ENTRYFLAGS_TEMPPATH;
  507. Size += RecordSize;
  508. }
  509. //
  510. // add second filename string if passed in
  511. //
  512. if( pPath2 )
  513. {
  514. pLoc = pBuffer + Size;
  515. RecordSize = STRING_RECORD_SIZE( &Path2Fix );
  516. SrPackString( pLoc,
  517. RecordSize,
  518. RecordTypeSecondPath,
  519. &Path2Fix );
  520. ((PSR_LOG_ENTRY) pBuffer)->EntryFlags |= ENTRYFLAGS_SECONDPATH;
  521. Size += RecordSize;
  522. }
  523. //
  524. // Pack and add the Acl information appropriately
  525. //
  526. if( pAclInfo )
  527. {
  528. pLoc = pBuffer + Size;
  529. Status = SrPackAclInformation( pLoc,
  530. pAclInfo,
  531. AclInfoSize,
  532. pExtension,
  533. bAclInline );
  534. if (!NT_SUCCESS( Status ))
  535. goto SrPackLogEntry_Exit;
  536. ((PSR_LOG_ENTRY) pBuffer)->EntryFlags |= ENTRYFLAGS_ACLINFO;
  537. if (bAclInline)
  538. {
  539. Size += SR_INLINE_ACL_SIZE( AclInfoSize );
  540. }
  541. else
  542. {
  543. Size += SR_FILE_ACL_SIZE( pVolumeName );
  544. }
  545. }
  546. //
  547. // Pack debug info if passed in
  548. //
  549. if (pDebugBlob)
  550. {
  551. pLoc = pBuffer + Size;
  552. RtlCopyMemory( pLoc,
  553. pDebugInfo,
  554. pDebugInfo->Header.RecordSize );
  555. ((PSR_LOG_ENTRY) pBuffer)->EntryFlags |= ENTRYFLAGS_DEBUGINFO;
  556. Size += pDebugInfo->Header.RecordSize;
  557. }
  558. //
  559. // pack and add the short name, if supplied
  560. //
  561. if (pShortName != NULL && pShortName->Length > 0)
  562. {
  563. pLoc = pBuffer + Size;
  564. RecordSize = STRING_RECORD_SIZE( pShortName );
  565. SrPackString( pLoc,
  566. RecordSize,
  567. RecordTypeShortName,
  568. pShortName );
  569. ((PSR_LOG_ENTRY) pBuffer)->EntryFlags |= ENTRYFLAGS_SHORTNAME;
  570. Size += RecordSize;
  571. }
  572. //
  573. // increment the size to accomodate the entry size at the end
  574. //
  575. Size += sizeof(DWORD);
  576. //
  577. // fill in the header fields : record size, record type and
  578. // update the size at the end
  579. //
  580. ((PSR_LOG_ENTRY) pBuffer)->Header.RecordSize = Size;
  581. ((PSR_LOG_ENTRY) pBuffer)->Header.RecordType = RecordTypeLogEntry;
  582. UPDATE_END_SIZE( pBuffer, Size );
  583. *ppLogEntry = (PSR_LOG_ENTRY) pBuffer;
  584. Status = STATUS_SUCCESS;
  585. SrPackLogEntry_Exit:
  586. RETURN(Status);
  587. } // SrPackLogEntry
  588. //++
  589. // Function:
  590. // SrPackLogHeader
  591. //
  592. // Description:
  593. // This function creates a proper SR_LOG_HEADER entry. It allocates
  594. // the LogEntry structure so that it is big enough to store this header.
  595. //
  596. // Note: The caller is responsible for freeing the SR_LOG_ENTRY allocated.
  597. //
  598. // Arguments:
  599. // ppLogHeader - Pointer to the PSR_LOG_HEADER that get set to the
  600. // allocated log header address.
  601. // pVolumePath - The volume path for this volume.
  602. //
  603. // Return Value:
  604. // Returns STATUS_INSUFFICIENT_RESOURCES if the SR_LOG_ENTRY cannot
  605. // be allocated. Otherwise, it returns STATUS_SUCCESS.
  606. //--
  607. NTSTATUS
  608. SrPackLogHeader(
  609. IN PSR_LOG_HEADER *ppLogHeader,
  610. IN PUNICODE_STRING pVolumePath
  611. )
  612. {
  613. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  614. DWORD RequiredSize = 0;
  615. DWORD SubRecordSize = 0;
  616. DWORD Size = 0;
  617. PBYTE pLoc = NULL;
  618. PBYTE pBuffer = NULL;
  619. PAGED_CODE();
  620. ASSERT( ppLogHeader != NULL );
  621. ASSERT( pVolumePath != NULL );
  622. // ====================================================================
  623. //
  624. // First, figure out how much of the buffer we need to use.
  625. //
  626. // ====================================================================
  627. RequiredSize = FIELD_OFFSET(SR_LOG_HEADER, SubRecords);
  628. // Count the volume path.
  629. RequiredSize += ( STRING_RECORD_SIZE(pVolumePath) );
  630. // Increment the size to accomodate the LogHeader size at the end
  631. RequiredSize += sizeof(DWORD);
  632. // ====================================================================
  633. //
  634. // Second, make sure that the buffer passed in is large enough for
  635. // the LogHeader.
  636. //
  637. // ====================================================================
  638. Size = FIELD_OFFSET(SR_LOG_HEADER, SubRecords);
  639. pBuffer = SrAllocateLogEntry( RequiredSize );
  640. if (pBuffer == NULL)
  641. {
  642. //
  643. // Not enough memory to pack the entry
  644. //
  645. Status = STATUS_INSUFFICIENT_RESOURCES;
  646. goto SrPackLogHeader_Exit;
  647. }
  648. //
  649. // Initialize the static part of SR_LOG_HEADER
  650. //
  651. RtlZeroMemory( pBuffer, RequiredSize );
  652. ((PSR_LOG_HEADER) pBuffer)->MagicNum = SR_LOG_MAGIC_NUMBER ;
  653. ((PSR_LOG_HEADER) pBuffer)->LogVersion = SR_LOG_VERSION ;
  654. // ====================================================================
  655. //
  656. // Finally, the buffer is large enough for the LogHeader, so fill
  657. // the buffer with the header.
  658. //
  659. // ====================================================================
  660. Size = FIELD_OFFSET(SR_LOG_HEADER, SubRecords);
  661. //
  662. // Add the volume prefix
  663. //
  664. pLoc = (PBYTE)(&((PSR_LOG_HEADER)pBuffer)->SubRecords);
  665. SubRecordSize = STRING_RECORD_SIZE( pVolumePath );
  666. SrPackString( pLoc,
  667. SubRecordSize,
  668. RecordTypeVolumePath,
  669. pVolumePath );
  670. Size += SubRecordSize;
  671. //
  672. // Increment the size to accomodate the LogHeader size at the end
  673. //
  674. Size += sizeof(DWORD);
  675. //
  676. // Fill in the header fields : record size, record type and
  677. // update the size at the end
  678. //
  679. ASSERT( RequiredSize == Size );
  680. ((PSR_LOG_HEADER) pBuffer)->Header.RecordSize = Size;
  681. ((PSR_LOG_HEADER) pBuffer)->Header.RecordType = RecordTypeLogHeader;
  682. UPDATE_END_SIZE( pBuffer, Size );
  683. *ppLogHeader = (PSR_LOG_HEADER) pBuffer;
  684. Status = STATUS_SUCCESS;
  685. SrPackLogHeader_Exit:
  686. RETURN( Status );
  687. } // SrPackLogHeader
  688. //++
  689. // Function:
  690. // SrPackDebugInfo
  691. //
  692. // Description:
  693. // This function creates a properly formatted debug info from
  694. // the supplied data. if NULL is passed instead of the buffer
  695. // then the API returns the size required to pack the entry.
  696. //
  697. // Arguments:
  698. // Pointer to log entry buffer
  699. //
  700. // Return Value:
  701. // This function returns STATUS_XXX
  702. //--
  703. NTSTATUS
  704. SrPackDebugInfo(
  705. IN PBYTE pBuffer,
  706. IN DWORD BufferSize
  707. )
  708. {
  709. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  710. DWORD Size = 0;
  711. PCHAR pStr;
  712. PEPROCESS peProcess;
  713. PAGED_CODE();
  714. ASSERT( pBuffer != NULL );
  715. Size = sizeof(SR_LOG_DEBUG_INFO);
  716. if (BufferSize < Size)
  717. {
  718. //
  719. // Not enough memory to pack the entry
  720. //
  721. Status = STATUS_INSUFFICIENT_RESOURCES;
  722. goto SrPackDebugInfo_Exit;
  723. }
  724. //
  725. // fill in the header fields : record size, record type
  726. //
  727. ((PSR_LOG_DEBUG_INFO)pBuffer)->Header.RecordSize = Size;
  728. ((PSR_LOG_DEBUG_INFO)pBuffer)->Header.RecordType =
  729. RecordTypeDebugInfo;
  730. ((PSR_LOG_DEBUG_INFO)pBuffer)->ThreadId = PsGetCurrentThreadId() ;
  731. ((PSR_LOG_DEBUG_INFO)pBuffer)->ProcessId = PsGetCurrentProcessId();
  732. pStr = ((PSR_LOG_DEBUG_INFO)pBuffer)->ProcessName;
  733. *pStr = 0;
  734. peProcess = PsGetCurrentProcess();
  735. RtlCopyMemory( pStr,
  736. ((PBYTE)peProcess) + global->ProcNameOffset,
  737. PROCESS_NAME_MAX );
  738. pStr[ PROCESS_NAME_MAX ] = 0;
  739. Status = STATUS_SUCCESS;
  740. SrPackDebugInfo_Exit:
  741. RETURN(Status);
  742. } // SrPackDebugInfo
  743. //++
  744. // Function:
  745. // SrPackAclInformation
  746. //
  747. // Description:
  748. // This function creates a properly formatted Acl record from
  749. // the supplied data.
  750. //
  751. // Arguments:
  752. // Pointer to log entry buffer
  753. //
  754. // Return Value:
  755. // This function returns STATUS_XXX
  756. //--
  757. NTSTATUS
  758. SrPackAclInformation(
  759. IN PBYTE pBuffer,
  760. IN PSECURITY_DESCRIPTOR pSecInfo,
  761. IN ULONG SecInfoSize,
  762. IN PSR_DEVICE_EXTENSION pExtension,
  763. IN BOOLEAN bInline
  764. )
  765. {
  766. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  767. PRECORD_HEADER pHeader = (PRECORD_HEADER)pBuffer;
  768. PUNICODE_STRING pAclFileName = NULL;
  769. HANDLE AclFileHandle = NULL;
  770. PUNICODE_STRING pVolumeName;
  771. PAGED_CODE();
  772. ASSERT( pExtension != NULL );
  773. pVolumeName = pExtension->pNtVolumeName;
  774. ASSERT( pVolumeName != NULL );
  775. try
  776. {
  777. ASSERT( pBuffer != NULL );
  778. ASSERT( pSecInfo != NULL );
  779. ASSERT( SecInfoSize != 0 );
  780. //
  781. // CODEWORK: Convert ACL to Self contained form ??
  782. //
  783. if (bInline)
  784. {
  785. //
  786. // Just format and put the contents into the buffer
  787. //
  788. pHeader->RecordSize = sizeof( RECORD_HEADER ) +
  789. SecInfoSize;
  790. pHeader->RecordType = RecordTypeAclInline;
  791. RtlCopyMemory( pBuffer + sizeof(RECORD_HEADER),
  792. pSecInfo,
  793. SecInfoSize );
  794. Status = STATUS_SUCCESS;
  795. }
  796. else
  797. {
  798. SR_OPEN_CONTEXT OpenContext;
  799. IO_STATUS_BLOCK IoStatusBlock;
  800. //
  801. // Write the contents out to a temp file and create a
  802. // AclFile record.
  803. //
  804. Status = SrAllocateFileNameBuffer( SR_MAX_FILENAME_LENGTH,
  805. &pAclFileName );
  806. if (!NT_SUCCESS( Status ))
  807. leave;
  808. Status = SrGetAclFileName( pVolumeName,
  809. SR_FILENAME_BUFFER_LENGTH,
  810. pAclFileName );
  811. if (!NT_SUCCESS( Status ))
  812. leave;
  813. //
  814. // Open Acl file and write the security info in that file
  815. //
  816. OpenContext.pPath = pAclFileName;
  817. OpenContext.Handle = NULL;
  818. OpenContext.DesiredAccess = FILE_GENERIC_WRITE | SYNCHRONIZE;
  819. OpenContext.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  820. OpenContext.ShareAccess = 0;
  821. OpenContext.CreateDisposition = FILE_OVERWRITE_IF; // OPEN always
  822. OpenContext.CreateOptions = /*FILE_NO_INTERMEDIATE_BUFFERING |*/
  823. FILE_WRITE_THROUGH |
  824. FILE_SYNCHRONOUS_IO_NONALERT;
  825. OpenContext.pExtension = pExtension;
  826. Status = SrPostSyncOperation(SrCreateFile,
  827. &OpenContext);
  828. if (NT_SUCCESS(Status))
  829. {
  830. LARGE_INTEGER Offset;
  831. ASSERT(OpenContext.Handle != NULL);
  832. AclFileHandle = OpenContext.Handle;
  833. Offset.QuadPart = 0;
  834. Status = ZwWriteFile( AclFileHandle,
  835. NULL, // Event
  836. NULL, // ApcRoutine
  837. NULL, // ApcContext
  838. &IoStatusBlock,
  839. pSecInfo,
  840. SecInfoSize,
  841. &Offset, // ByteOffset
  842. NULL ); // Key
  843. if (NT_SUCCESS(Status))
  844. {
  845. //
  846. // Create AclFile type entry
  847. //
  848. SrPackString( pBuffer,
  849. STRING_RECORD_SIZE( pAclFileName ),
  850. RecordTypeAclFile,
  851. pAclFileName );
  852. }
  853. } else {
  854. ASSERT(OpenContext.Handle == NULL);
  855. }
  856. }
  857. }
  858. finally
  859. {
  860. if (pAclFileName != NULL)
  861. {
  862. SrFreeFileNameBuffer( pAclFileName );
  863. pAclFileName = NULL;
  864. }
  865. if (AclFileHandle != NULL)
  866. {
  867. ZwClose(AclFileHandle);
  868. AclFileHandle = NULL;
  869. }
  870. }
  871. RETURN(Status);
  872. } // SrPackAclInformation
  873. /////////////////////////////////////////////////////////////////////
  874. //
  875. // Logger Routines : Manipulate Logger object
  876. //
  877. /////////////////////////////////////////////////////////////////////
  878. //++
  879. // Function:
  880. // SrLoggerStart
  881. //
  882. // Description:
  883. // This function initializes the logger and enables the flushing
  884. // routines.
  885. //
  886. // Arguments:
  887. // PDEVICE_OBJECT pDeviceObject
  888. // PSR_LOGGER_CONTEXT * pLogger
  889. //
  890. // Return Value:
  891. // STATUS_XXX
  892. //--
  893. NTSTATUS
  894. SrLoggerStart(
  895. IN PDEVICE_OBJECT pDeviceObject,
  896. OUT PSR_LOGGER_CONTEXT * ppLogger
  897. )
  898. {
  899. NTSTATUS Status;
  900. PSR_LOGGER_CONTEXT pInitInfo = NULL;
  901. PIO_WORKITEM pWorkItem = NULL;
  902. UNREFERENCED_PARAMETER( pDeviceObject );
  903. ASSERT(IS_VALID_DEVICE_OBJECT(pDeviceObject));
  904. ASSERT(ppLogger != NULL);
  905. PAGED_CODE();
  906. try
  907. {
  908. Status = STATUS_SUCCESS;
  909. *ppLogger = NULL;
  910. //
  911. // Allocate Logging Init info from NonPagedPool
  912. //
  913. pInitInfo = SR_ALLOCATE_STRUCT( NonPagedPool,
  914. SR_LOGGER_CONTEXT,
  915. SR_LOGGER_CONTEXT_TAG );
  916. if (pInitInfo == NULL)
  917. {
  918. Status = STATUS_INSUFFICIENT_RESOURCES;
  919. leave;
  920. }
  921. RtlZeroMemory( pInitInfo, sizeof( SR_LOGGER_CONTEXT ) );
  922. pInitInfo->Signature = SR_LOGGER_CONTEXT_TAG;
  923. pInitInfo->ActiveContexts = 0;
  924. #ifdef USE_LOOKASIDE
  925. //
  926. // Initialize Lookaside list used in logging module
  927. //
  928. ExInitializeNPagedLookasideList( &pInitInfo->LogBufferLookaside,
  929. NULL,
  930. NULL,
  931. 0,
  932. _globals.LogBufferSize,
  933. SR_LOG_BUFFER_TAG,
  934. 0 );
  935. #endif
  936. #ifndef SYNC_LOG_WRITE
  937. //
  938. // Allocate work item for the DPC
  939. //
  940. pWorkItem = IoAllocateWorkItem(global->pControlDevice);
  941. if (pWorkItem == NULL) {
  942. Status = STATUS_INSUFFICIENT_RESOURCES;
  943. leave;
  944. }
  945. //
  946. // Initialize Dpc and timer object
  947. //
  948. KeInitializeTimer( &pInitInfo->Timer );
  949. KeInitializeDpc ( &pInitInfo->Dpc,
  950. SrLoggerFlushDpc,
  951. pWorkItem );
  952. //
  953. // Start the timer for log flushing
  954. //
  955. KeSetTimer( &pInitInfo->Timer,
  956. global->LogFlushDueTime,
  957. &pInitInfo->Dpc );
  958. #endif
  959. *ppLogger = pInitInfo;
  960. } finally {
  961. Status = FinallyUnwind(SrLoggerStart, Status);
  962. if (!NT_SUCCESS( Status ))
  963. {
  964. if (pInitInfo != NULL) {
  965. SrLoggerStop( pInitInfo );
  966. }
  967. *ppLogger = pInitInfo = NULL;
  968. if (pWorkItem != NULL) {
  969. IoFreeWorkItem(pWorkItem);
  970. }
  971. pWorkItem = NULL;
  972. }
  973. }
  974. RETURN(Status);
  975. } // SrLoggerStart
  976. //++
  977. // Function:
  978. // SrLoggerStop
  979. //
  980. // Description:
  981. // This function stops the logger and frees the related resources
  982. //
  983. // Arguments:
  984. // LoggerInfo pointer
  985. //
  986. // Return Value:
  987. // STATUS_XXX
  988. //--
  989. //++
  990. NTSTATUS
  991. SrLoggerStop(
  992. IN PSR_LOGGER_CONTEXT pLogger
  993. )
  994. {
  995. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  996. PAGED_CODE();
  997. ASSERT(IS_VALID_LOGGER_CONTEXT(pLogger));
  998. try {
  999. //
  1000. // Stop the timer routines
  1001. //
  1002. KeCancelTimer( &pLogger->Timer );
  1003. //
  1004. // Active log contexts must be zero other wise we are leaking
  1005. //
  1006. ASSERT( pLogger->ActiveContexts == 0 );
  1007. #ifdef USE_LOOKASIDE
  1008. //
  1009. // Free the lookaside lists
  1010. //
  1011. if (IS_LOOKASIDE_INITIALIZED(&pLogger->LogEntryLookaside))
  1012. {
  1013. ExDeletePagedLookasideList(
  1014. &pLogger->LogEntryLookaside);
  1015. }
  1016. if (IS_LOOKASIDE_INITIALIZED(&pLogger->LogBufferLookaside))
  1017. {
  1018. ExDeleteNPagedLookasideList(
  1019. &pLogger->LogBufferLookaside);
  1020. }
  1021. #endif
  1022. SR_FREE_POOL_WITH_SIG( pLogger, SR_LOGGER_CONTEXT_TAG );
  1023. Status = STATUS_SUCCESS;
  1024. } finally {
  1025. Status = FinallyUnwind(SrLoggerStop, Status);
  1026. }
  1027. RETURN(Status);
  1028. } // SrLoggerStop
  1029. #ifndef SYNC_LOG_WRITE
  1030. //++
  1031. // Function:
  1032. // SrLoggerFlushDpc
  1033. //
  1034. // Description:
  1035. // This function is a DPC called to flush the log buffers. This will
  1036. // queue a workitem to flush the buffers. This should not be paged.
  1037. //
  1038. // Arguments:
  1039. // IN PKDPC Dpc
  1040. // IN PVOID DeferredContext
  1041. // IN PVOID SystemArgument1
  1042. // IN PVOID SystemArgument2
  1043. //
  1044. // Return Value:
  1045. // None
  1046. //--
  1047. VOID
  1048. SrLoggerFlushDpc(
  1049. IN PKDPC Dpc,
  1050. IN PVOID DeferredContext,
  1051. IN PVOID SystemArgument1,
  1052. IN PVOID SystemArgument2
  1053. )
  1054. {
  1055. PIO_WORKITEM pSrWorkItem;
  1056. UNREFERENCED_PARAMETER( Dpc );
  1057. UNREFERENCED_PARAMETER( SystemArgument1 );
  1058. UNREFERENCED_PARAMETER( SystemArgument2 );
  1059. SrTrace( LOG, ("SR!SrLoggerFlushDpc Called...\n"));
  1060. pSrWorkItem = (PIO_WORKITEM) DeferredContext;
  1061. ASSERT(pSrWorkItem != NULL);
  1062. IoQueueWorkItem( pSrWorkItem,
  1063. SrLoggerFlushWorkItem,
  1064. DelayedWorkQueue,
  1065. pSrWorkItem );
  1066. } // SrLoggerFlushDpc
  1067. //++
  1068. // Function:
  1069. // SrLoggerFlushWorkItem
  1070. //
  1071. // Description:
  1072. // This Workitem queued by DPC will actually flush the log buffers.
  1073. //
  1074. // Arguments:
  1075. // IN PDEVICE_OBJECT DeviceObject
  1076. // IN PVOID Context
  1077. //
  1078. // Return Value:
  1079. // None
  1080. //--
  1081. VOID
  1082. SrLoggerFlushWorkItem (
  1083. IN PDEVICE_OBJECT DeviceObject,
  1084. IN PVOID Context
  1085. )
  1086. {
  1087. NTSTATUS Status;
  1088. PLIST_ENTRY pListEntry;
  1089. PSR_DEVICE_EXTENSION pExtension;
  1090. PAGED_CODE();
  1091. UNREFERENCED_PARAMETER(DeviceObject);
  1092. UNREFERENCED_PARAMETER(Context);
  1093. SrTrace(LOG, ("sr!SrLoggerFlushWorkItem: enter\n"));
  1094. try {
  1095. //
  1096. // Grab the DeviceExtensionListLock as we are about to
  1097. // iterate through this list. Since we are only going to be
  1098. // reading this list, we can get this lock shared.
  1099. //
  1100. SrAcquireDeviceExtensionListLockShared();
  1101. Status = STATUS_SUCCESS;
  1102. #if DBG
  1103. //
  1104. // sleep for twice the DPC interval to prove that 2 DPC's
  1105. // are not coming in at the same time
  1106. //
  1107. if (global->DebugControl & SR_DEBUG_DELAY_DPC)
  1108. {
  1109. LARGE_INTEGER Interval;
  1110. Interval.QuadPart = -1 * (10 * NANO_FULL_SECOND);
  1111. KeDelayExecutionThread(KernelMode, TRUE, &Interval);
  1112. }
  1113. #endif
  1114. ASSERT( global->pLogger != NULL );
  1115. //
  1116. // loop over all volumes flushing data to the disk.
  1117. //
  1118. for (pListEntry = global->DeviceExtensionListHead.Flink;
  1119. pListEntry != &global->DeviceExtensionListHead;
  1120. pListEntry = pListEntry->Flink)
  1121. {
  1122. pExtension = CONTAINING_RECORD( pListEntry,
  1123. SR_DEVICE_EXTENSION,
  1124. ListEntry );
  1125. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  1126. //
  1127. // Do a quick unsafe check to see if we have started logging this
  1128. // volume yet. If it appears we haven't, just continue onto the
  1129. // next entry in the list. If logging is just about to begin,
  1130. // we catch it on the next firing of this timer.
  1131. //
  1132. if (pExtension->pLogContext == NULL) {
  1133. continue;
  1134. }
  1135. //
  1136. // It looks like we have started to log, so get the necessary
  1137. // locks and do our work to flush the volume.
  1138. //
  1139. try {
  1140. SrAcquireActivityLockExclusive( pExtension );
  1141. if (pExtension->pLogContext != NULL)
  1142. {
  1143. //
  1144. // yes, flush for this volume
  1145. //
  1146. Status = SrLogFlush( pExtension->pLogContext );
  1147. if (!NT_SUCCESS( Status ))
  1148. {
  1149. //
  1150. // Disable volume
  1151. //
  1152. Status = SrNotifyVolumeError( pExtension,
  1153. pExtension->pLogContext->pLogFilePath,
  1154. Status,
  1155. SrEventVolumeError );
  1156. //
  1157. // Stop Logging
  1158. //
  1159. SrLogStop( pExtension, TRUE, TRUE );
  1160. }
  1161. }
  1162. } finally {
  1163. SrReleaseActivityLock( pExtension );
  1164. }
  1165. }
  1166. } finally {
  1167. Status = FinallyUnwind(SrLoggerFlushWorkItem, Status);
  1168. //
  1169. // fire the timer again, do this with the global lock
  1170. // held so that it can be cancelled in SrLoggerStop.
  1171. //
  1172. //
  1173. // The DPC is going to reuse the work item
  1174. //
  1175. KeSetTimer( &global->pLogger->Timer,
  1176. global->LogFlushDueTime,
  1177. &global->pLogger->Dpc );
  1178. SrReleaseDeviceExtensionListLock();
  1179. }
  1180. SrTrace(LOG, ("sr!SrLoggerFlushWorkItem: exit\n"));
  1181. } // SrLoggerFlushWorkItem
  1182. #endif
  1183. //++
  1184. // Function:
  1185. // SrLoggerAddLogContext
  1186. //
  1187. // Description:
  1188. // This function adds a given Log Context to the logger
  1189. //
  1190. // Arguments:
  1191. // pointer to LoggerInfo
  1192. // pointer to LogContext
  1193. //
  1194. // Return Value:
  1195. // STATUS_XXX
  1196. //--
  1197. VOID
  1198. SrLoggerAddLogContext(
  1199. IN PSR_LOGGER_CONTEXT pLogger,
  1200. IN PSR_LOG_CONTEXT pLogContext
  1201. )
  1202. {
  1203. PAGED_CODE();
  1204. UNREFERENCED_PARAMETER( pLogContext );
  1205. ASSERT(IS_VALID_LOGGER_CONTEXT(pLogger));
  1206. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  1207. InterlockedIncrement(&pLogger->ActiveContexts);
  1208. } // SrLoggerAddLogContext
  1209. //++
  1210. // Function:
  1211. // SrLoggerRemoveLogContext
  1212. //
  1213. // Description:
  1214. // This Workitem queued by DPC will actually flush the log buffers.
  1215. //
  1216. // Arguments:
  1217. // pointer to LoggerInfo
  1218. // pointer to LogContext
  1219. //
  1220. // Return Value:
  1221. // STATUS_XXX
  1222. //--
  1223. NTSTATUS
  1224. SrLoggerRemoveLogContext(
  1225. IN PSR_LOGGER_CONTEXT pLogger,
  1226. IN PSR_LOG_CONTEXT pLogContext
  1227. )
  1228. {
  1229. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1230. PAGED_CODE();
  1231. UNREFERENCED_PARAMETER( pLogContext );
  1232. ASSERT(IS_VALID_LOGGER_CONTEXT(pLogger));
  1233. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  1234. InterlockedDecrement(&pLogger->ActiveContexts);
  1235. Status = STATUS_SUCCESS;
  1236. RETURN(Status);
  1237. } // SrLoggerRemoveLogContext
  1238. //++
  1239. // Function:
  1240. // SrLoggerSwitchLogs
  1241. //
  1242. // Description:
  1243. // This function loops thru the log contexts and switches all the
  1244. // log contexts
  1245. //
  1246. // Arguments:
  1247. // pointer to LoggerInfo
  1248. //
  1249. // Return Value:
  1250. // STATUS_XXX
  1251. //--
  1252. NTSTATUS
  1253. SrLoggerSwitchLogs(
  1254. IN PSR_LOGGER_CONTEXT pLogger
  1255. )
  1256. {
  1257. NTSTATUS Status;
  1258. PLIST_ENTRY pListEntry;
  1259. PSR_DEVICE_EXTENSION pExtension;
  1260. PAGED_CODE();
  1261. UNREFERENCED_PARAMETER( pLogger );
  1262. ASSERT(IS_VALID_LOGGER_CONTEXT(pLogger));
  1263. Status = STATUS_SUCCESS;
  1264. try {
  1265. SrAcquireDeviceExtensionListLockShared();
  1266. //
  1267. // loop over all volumes switching their logs
  1268. //
  1269. for (pListEntry = _globals.DeviceExtensionListHead.Flink;
  1270. pListEntry != &_globals.DeviceExtensionListHead;
  1271. pListEntry = pListEntry->Flink)
  1272. {
  1273. pExtension = CONTAINING_RECORD( pListEntry,
  1274. SR_DEVICE_EXTENSION,
  1275. ListEntry );
  1276. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  1277. //
  1278. // We only have to do work if this is a volume device object,
  1279. // not if this is a device object that is attached to a file
  1280. // system's control device object.
  1281. //
  1282. if (FlagOn( pExtension->FsType, SrFsControlDeviceObject ))
  1283. {
  1284. continue;
  1285. }
  1286. try {
  1287. SrAcquireActivityLockExclusive( pExtension );
  1288. //
  1289. // have we started logging on this volume?
  1290. //
  1291. if (pExtension->pLogContext != NULL)
  1292. {
  1293. //
  1294. // yes, switch for this volume
  1295. //
  1296. Status = SrLogSwitch(pExtension->pLogContext);
  1297. }
  1298. else
  1299. {
  1300. Status = SrLogNormalize( pExtension );
  1301. }
  1302. if (!NT_SUCCESS( Status ))
  1303. {
  1304. //
  1305. // Disable volume
  1306. //
  1307. Status = SrNotifyVolumeError( pExtension,
  1308. NULL,
  1309. Status,
  1310. SrEventVolumeError );
  1311. if (pExtension->pLogContext != NULL)
  1312. {
  1313. //
  1314. // Stop Logging
  1315. //
  1316. SrLogStop( pExtension, TRUE, TRUE );
  1317. }
  1318. }
  1319. } finally {
  1320. Status = FinallyUnwind(SrLoggerSwitchLogs, Status);
  1321. SrReleaseActivityLock( pExtension );
  1322. }
  1323. }
  1324. } finally {
  1325. Status = FinallyUnwind(SrLoggerSwitchLogs, Status);
  1326. SrReleaseDeviceExtensionListLock();
  1327. }
  1328. RETURN(Status);
  1329. } // SrLoggerSwitchLogs
  1330. /////////////////////////////////////////////////////////////////////
  1331. //
  1332. // Log Routines : Manipulate individual Logs
  1333. //
  1334. /////////////////////////////////////////////////////////////////////
  1335. //++
  1336. // Function:
  1337. // SrCreateFile
  1338. //
  1339. // Description:
  1340. // This function just does a create on file, no sync needed
  1341. // written so that it can be called in a separate thread to avoid
  1342. // stack overflows via SrIoCreateFile
  1343. //
  1344. // Arguments:
  1345. //
  1346. // pOpenContext - pointer to the open context
  1347. //
  1348. // Return Value:
  1349. // This function returns STATUS_XXX
  1350. //--
  1351. NTSTATUS
  1352. SrCreateFile(
  1353. IN PSR_OPEN_CONTEXT pOpenContext
  1354. )
  1355. {
  1356. OBJECT_ATTRIBUTES ObjectAttributes;
  1357. IO_STATUS_BLOCK IoStatusBlock;
  1358. NTSTATUS Status;
  1359. PAGED_CODE();
  1360. ASSERT(pOpenContext != NULL);
  1361. ASSERT(pOpenContext->pPath != NULL);
  1362. SrTrace(LOG, ("Opening file %wZ", pOpenContext->pPath));
  1363. InitializeObjectAttributes( &ObjectAttributes,
  1364. pOpenContext->pPath,
  1365. OBJ_KERNEL_HANDLE,
  1366. NULL,
  1367. NULL );
  1368. ASSERT( pOpenContext->pExtension != NULL );
  1369. Status = SrIoCreateFile(
  1370. &pOpenContext->Handle,
  1371. pOpenContext->DesiredAccess,
  1372. &ObjectAttributes,
  1373. &IoStatusBlock,
  1374. NULL, // AllocationSize
  1375. pOpenContext->FileAttributes,
  1376. pOpenContext->ShareAccess,
  1377. pOpenContext->CreateDisposition,
  1378. pOpenContext->CreateOptions,
  1379. NULL, // EaBuffer
  1380. 0, // EaLength
  1381. 0,
  1382. pOpenContext->pExtension->pTargetDevice );
  1383. return Status;
  1384. }
  1385. //++
  1386. // Function:
  1387. // SrLogOpen
  1388. //
  1389. // Description:
  1390. // This function creates a log file, no sync needed as it is always
  1391. // called internally
  1392. //
  1393. // Arguments:
  1394. // Pointer to open context
  1395. //
  1396. // Return Value:
  1397. // This function returns STATUS_XXX
  1398. //--
  1399. NTSTATUS
  1400. SrLogOpen(
  1401. IN PSR_LOG_CONTEXT pLogContext
  1402. )
  1403. {
  1404. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1405. PSR_LOG_HEADER pLogHeader = NULL;
  1406. SR_OPEN_CONTEXT OpenContext;
  1407. PAGED_CODE();
  1408. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  1409. ASSERT(pLogContext->pLogFilePath != NULL );
  1410. ASSERT(pLogContext->LogHandle == NULL );
  1411. ASSERT(pLogContext->pLogFileObject == NULL);
  1412. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) ||
  1413. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) );
  1414. try
  1415. {
  1416. SrTrace(FUNC_ENTRY, ("SR!SrLogOpen\n"));
  1417. //
  1418. // Initialize the open context with the file create parameters
  1419. //
  1420. OpenContext.pPath = pLogContext->pLogFilePath;;
  1421. OpenContext.Handle = NULL;
  1422. OpenContext.DesiredAccess = FILE_GENERIC_WRITE |
  1423. SYNCHRONIZE |
  1424. FILE_APPEND_DATA;
  1425. OpenContext.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1426. OpenContext.ShareAccess = FILE_SHARE_READ;
  1427. OpenContext.CreateDisposition = FILE_OVERWRITE_IF; // OPEN always
  1428. OpenContext.CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  1429. OpenContext.pExtension = pLogContext->pExtension;
  1430. SrTrace(LOG, ("Opening Log in another thread %wZ", pLogContext->pLogFilePath));
  1431. Status = SrPostSyncOperation(SrCreateFile,
  1432. &OpenContext);
  1433. if (NT_SUCCESS(Status))
  1434. {
  1435. SrTrace(LOG, (" - Succeeded\n"));
  1436. ASSERT(OpenContext.Handle != NULL);
  1437. pLogContext->LogHandle = OpenContext.Handle;
  1438. //
  1439. // Also get the file object associated with this handle.
  1440. //
  1441. Status = ObReferenceObjectByHandle( pLogContext->LogHandle,
  1442. 0,
  1443. *IoFileObjectType,
  1444. KernelMode,
  1445. (PVOID *) &(pLogContext->pLogFileObject),
  1446. NULL );
  1447. if (!NT_SUCCESS( Status ))
  1448. {
  1449. leave;
  1450. }
  1451. //
  1452. // Initialize log context poperly for this log
  1453. //
  1454. #ifndef SYNC_LOG_WRITE
  1455. RtlZeroMemory( pLogContext->pLogBuffer, _globals.LogBufferSize );
  1456. #endif
  1457. RESET_LOG_CONTEXT( pLogContext );
  1458. //
  1459. // Enable log context
  1460. //
  1461. SET_ENABLE_FLAG(pLogContext);
  1462. //
  1463. // CODEWORK:kmarok: need to decide if we want to preallocate
  1464. // the log file and do it here
  1465. //
  1466. //
  1467. // Write the log header as the first entry into
  1468. // the newly created log
  1469. //
  1470. Status = SrPackLogHeader( &pLogHeader,
  1471. pLogContext->pLogFilePath);
  1472. if (!NT_SUCCESS( Status ))
  1473. leave;
  1474. Status = SrLogWrite( NULL,
  1475. pLogContext,
  1476. (PSR_LOG_ENTRY)pLogHeader );
  1477. if (!NT_SUCCESS( Status ))
  1478. leave;
  1479. //
  1480. // Clear dirty flag because we haven't actually written any
  1481. // data
  1482. //
  1483. CLEAR_DIRTY_FLAG(pLogContext);
  1484. }
  1485. else
  1486. {
  1487. SrTrace(LOG, (" - Failed (0x%X) \n", Status));
  1488. }
  1489. } finally {
  1490. Status = FinallyUnwind(SrLogOpen, Status);
  1491. if (!NT_SUCCESS( Status ))
  1492. {
  1493. //
  1494. // Since the open failed, disable the log
  1495. //
  1496. CLEAR_ENABLE_FLAG(pLogContext);
  1497. if (pLogContext->pLogFileObject != NULL)
  1498. {
  1499. ObDereferenceObject( pLogContext->pLogFileObject );
  1500. pLogContext->pLogFileObject = NULL;
  1501. }
  1502. if (pLogContext->LogHandle)
  1503. {
  1504. ZwClose( pLogContext->LogHandle );
  1505. pLogContext->LogHandle = NULL;
  1506. }
  1507. }
  1508. if (pLogHeader != NULL)
  1509. {
  1510. SrFreeLogEntry( pLogHeader );
  1511. NULLPTR( pLogHeader );
  1512. }
  1513. }
  1514. RETURN(Status);
  1515. } // SrLogOpen
  1516. //++
  1517. // Function:
  1518. // SrLogClose
  1519. //
  1520. // Description:
  1521. // This function closes the current log
  1522. //
  1523. // Arguments:
  1524. // Pointer to Log Context
  1525. //
  1526. // Return Value:
  1527. // This function returns STATUS_XXX
  1528. //--
  1529. NTSTATUS
  1530. SrLogClose(
  1531. IN PSR_LOG_CONTEXT pLogContext
  1532. )
  1533. {
  1534. NTSTATUS Status = STATUS_SUCCESS;
  1535. NTSTATUS TempStatus = STATUS_SUCCESS;
  1536. PAGED_CODE();
  1537. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  1538. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) ||
  1539. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) );
  1540. //
  1541. // Flush & Close the log file
  1542. //
  1543. if ( pLogContext->LogHandle )
  1544. {
  1545. #ifndef SYNC_LOG_WRITE
  1546. //
  1547. // We only need to force flush here if we are not doing synchronous
  1548. // log writes.
  1549. //
  1550. Status = SrLogFlush( pLogContext );
  1551. #endif
  1552. //
  1553. // The close operation is only going to fail if the LogHandle
  1554. // is invalid. We need to close the handle even if we hit an
  1555. // error trying to flush the log, but it is the value returned from
  1556. // flushing the log that the caller really cares about, not the
  1557. // return value from closing the handle, so just store it in a
  1558. // temp variable and validate in checked builds.
  1559. //
  1560. ObDereferenceObject( pLogContext->pLogFileObject );
  1561. TempStatus = ZwClose( pLogContext->LogHandle );
  1562. CHECK_STATUS( TempStatus );
  1563. }
  1564. //
  1565. // modify the log context to indicate the log is closed
  1566. // donot clear the LogBuffer member ( reused )
  1567. //
  1568. pLogContext->LogHandle = NULL;
  1569. pLogContext->pLogFileObject = NULL;
  1570. RESET_LOG_CONTEXT(pLogContext);
  1571. RETURN( Status );
  1572. } // SrLogClose
  1573. //++
  1574. // Function:
  1575. // SrLogCheckAndRename
  1576. //
  1577. // Description:
  1578. // This function checks and backsup a log file
  1579. //
  1580. // Arguments:
  1581. // pExtension - The SR_DEVICE_EXTENSION for this volume.
  1582. // pLogPath - The full path and file name to the change log.
  1583. //
  1584. // Return Value:
  1585. // This function returns STATUS_XXX
  1586. //--
  1587. NTSTATUS
  1588. SrLogCheckAndRename(
  1589. IN PSR_DEVICE_EXTENSION pExtension,
  1590. IN PUNICODE_STRING pLogPath
  1591. )
  1592. {
  1593. INT i = 1;
  1594. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1595. HANDLE LogHandle = NULL;
  1596. PUNICODE_STRING pRenamedFile = NULL;
  1597. PFILE_RENAME_INFORMATION pRenameInformation = NULL;
  1598. ULONG CharCount;
  1599. ULONG RenameInformationLength;
  1600. IO_STATUS_BLOCK IoStatusBlock;
  1601. SR_OPEN_CONTEXT OpenContext;
  1602. PAGED_CODE();
  1603. ASSERT( pLogPath != NULL );
  1604. SrTrace(FUNC_ENTRY, ("SR!SrLogCheckAndRename\n"));
  1605. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) ||
  1606. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension) );
  1607. try
  1608. {
  1609. //
  1610. // Do the create
  1611. //
  1612. OpenContext.pPath = pLogPath;
  1613. OpenContext.Handle = NULL;
  1614. OpenContext.DesiredAccess = DELETE;
  1615. OpenContext.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1616. OpenContext.ShareAccess = 0;
  1617. OpenContext.CreateDisposition = FILE_OPEN;
  1618. OpenContext.CreateOptions = FILE_NO_INTERMEDIATE_BUFFERING
  1619. | FILE_SYNCHRONOUS_IO_NONALERT;
  1620. OpenContext.pExtension = pExtension;
  1621. Status = SrPostSyncOperation(SrCreateFile,
  1622. &OpenContext);
  1623. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  1624. !NT_SUCCESS( Status ))
  1625. {
  1626. ASSERT(OpenContext.Handle == NULL);
  1627. //
  1628. // we need to check for file not found status
  1629. //
  1630. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1631. {
  1632. Status = STATUS_SUCCESS;
  1633. }
  1634. leave;
  1635. }
  1636. //
  1637. // File exists so try to rename the file
  1638. //
  1639. LogHandle = OpenContext.Handle;
  1640. ASSERT(LogHandle != NULL);
  1641. RenameInformationLength = sizeof(FILE_RENAME_INFORMATION)
  1642. + pLogPath->Length
  1643. + sizeof(WCHAR) // the "."
  1644. + MAX_ULONG_LENGTH // the "%d"
  1645. + sizeof(WCHAR) ; // a NULL
  1646. pRenameInformation = SR_ALLOCATE_POOL( PagedPool,
  1647. RenameInformationLength,
  1648. SR_RENAME_BUFFER_TAG );
  1649. if (pRenameInformation == NULL)
  1650. {
  1651. Status = STATUS_INSUFFICIENT_RESOURCES;
  1652. leave;
  1653. }
  1654. Status = SrAllocateFileNameBuffer( pLogPath->Length
  1655. + sizeof(WCHAR) // the "."
  1656. + MAX_ULONG_LENGTH, // the "%d"
  1657. &pRenamedFile );
  1658. if (!NT_SUCCESS( Status ))
  1659. leave;
  1660. while( 1 )
  1661. {
  1662. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  1663. //
  1664. // Construct possible backup filename
  1665. //
  1666. RtlCopyMemory( pRenamedFile->Buffer,
  1667. pLogPath->Buffer,
  1668. pLogPath->Length );
  1669. pRenamedFile->Length = pLogPath->Length;
  1670. //
  1671. // and append backup suffix
  1672. //
  1673. CharCount = swprintf( &pRenamedFile->Buffer[
  1674. pRenamedFile->Length/sizeof(WCHAR)],
  1675. L".%d",
  1676. i++ );
  1677. ASSERT(CharCount <= MAX_ULONG_LENGTH);
  1678. pRenamedFile->Length += (USHORT)CharCount * sizeof(WCHAR);
  1679. ASSERT(pRenamedFile->Length <= pRenamedFile->MaximumLength);
  1680. //
  1681. // now initialize the rename info struct
  1682. //
  1683. RtlCopyMemory( (PUCHAR)&pRenameInformation->FileName[0],
  1684. pRenamedFile->Buffer,
  1685. pRenamedFile->Length + sizeof(WCHAR) );
  1686. pRenameInformation->ReplaceIfExists = FALSE;
  1687. pRenameInformation->RootDirectory = NULL;
  1688. pRenameInformation->FileNameLength = pRenamedFile->Length;
  1689. SrTrace( LOG, ("SR!SrLogCheckAndRename: renaming to %ws\n",
  1690. &pRenameInformation->FileName[0] ));
  1691. Status = ZwSetInformationFile( LogHandle,
  1692. &IoStatusBlock,
  1693. pRenameInformation,
  1694. RenameInformationLength,
  1695. FileRenameInformation );
  1696. if ( NT_SUCCESS_NO_DBGBREAK( Status ) ||
  1697. (Status != STATUS_OBJECT_NAME_COLLISION) ||
  1698. (i > MAX_RENAME_TRIES) )
  1699. {
  1700. break;
  1701. }
  1702. }
  1703. //
  1704. // To get DBG messages for unexpected errors in DEBUG builds...
  1705. //
  1706. CHECK_STATUS( Status );
  1707. }
  1708. finally
  1709. {
  1710. if ( LogHandle != NULL )
  1711. {
  1712. ZwClose(LogHandle);
  1713. LogHandle = NULL;
  1714. }
  1715. if ( pRenamedFile != NULL )
  1716. {
  1717. SrFreeFileNameBuffer( pRenamedFile );
  1718. pRenamedFile = NULL;
  1719. }
  1720. if ( pRenameInformation != NULL )
  1721. {
  1722. SR_FREE_POOL(pRenameInformation, SR_RENAME_BUFFER_TAG);
  1723. pRenameInformation = NULL;
  1724. }
  1725. }
  1726. RETURN(Status);
  1727. } // SrLogCheckAndRename
  1728. //
  1729. // Public API implementation
  1730. //
  1731. //++
  1732. // Function:
  1733. // SrLogStart
  1734. //
  1735. // Description:
  1736. // This function prepares the driver for Logging
  1737. // requests.
  1738. //
  1739. // Arguments:
  1740. // Pointer to Log Path
  1741. // Pointer to device extension
  1742. // Pointer to handle
  1743. //
  1744. // Return Value:
  1745. // This function returns STATUS_XXX
  1746. //--
  1747. NTSTATUS
  1748. SrLogStart(
  1749. IN PUNICODE_STRING pLogPath,
  1750. IN PSR_DEVICE_EXTENSION pExtension,
  1751. OUT PSR_LOG_CONTEXT * ppLogContext
  1752. )
  1753. {
  1754. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1755. PSR_LOG_CONTEXT pLogContext = NULL;
  1756. PAGED_CODE();
  1757. ASSERT(pLogPath != NULL);
  1758. ASSERT(ppLogContext != NULL);
  1759. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) ||
  1760. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension ));
  1761. try
  1762. {
  1763. *ppLogContext = NULL;
  1764. //
  1765. // should we short circuit out of here for testing mode?
  1766. //
  1767. if (!SR_LOGGING_ENABLED( pExtension ) ||
  1768. _globals.DontBackup)
  1769. {
  1770. leave;
  1771. }
  1772. *ppLogContext = SR_ALLOCATE_STRUCT( PagedPool,
  1773. SR_LOG_CONTEXT,
  1774. SR_LOG_CONTEXT_TAG );
  1775. if ( *ppLogContext == NULL )
  1776. {
  1777. Status = STATUS_INSUFFICIENT_RESOURCES;
  1778. leave;
  1779. }
  1780. pLogContext = *ppLogContext;
  1781. RtlZeroMemory( pLogContext, sizeof(SR_LOG_CONTEXT) );
  1782. pLogContext->Signature = SR_LOG_CONTEXT_TAG;
  1783. pLogContext->pExtension = pExtension;
  1784. //
  1785. // grab a buffer to store the file name
  1786. //
  1787. Status = SrAllocateFileNameBuffer( pLogPath->Length,
  1788. &(pLogContext->pLogFilePath) );
  1789. if (!NT_SUCCESS( Status ))
  1790. leave;
  1791. //
  1792. // Store our backpointer to the device extension
  1793. //
  1794. pLogContext->pExtension = pExtension;
  1795. //
  1796. // Save the filename in the context
  1797. //
  1798. RtlCopyMemory( pLogContext->pLogFilePath->Buffer,
  1799. pLogPath->Buffer,
  1800. pLogPath->Length );
  1801. pLogContext->pLogFilePath->Buffer
  1802. [pLogPath->Length/sizeof(WCHAR)] = UNICODE_NULL;
  1803. pLogContext->pLogFilePath->Length = pLogPath->Length;
  1804. #ifndef SYNC_LOG_WRITE
  1805. //
  1806. // We only need a buffer to cache the log entries if we are doing
  1807. // asynchronous log writes.
  1808. //
  1809. pLogContext->pLogBuffer = SrAllocateLogBuffer( _globals.LogBufferSize );
  1810. if ( pLogContext->pLogBuffer == NULL )
  1811. {
  1812. Status = STATUS_INSUFFICIENT_RESOURCES;
  1813. leave;
  1814. }
  1815. #endif
  1816. //
  1817. // rename the old log file if one exists
  1818. //
  1819. Status = SrLogCheckAndRename( pExtension, pLogContext->pLogFilePath);
  1820. if (!NT_SUCCESS(Status))
  1821. leave;
  1822. //
  1823. // try and open the log file
  1824. //
  1825. Status = SrLogOpen( pLogContext );
  1826. if (NT_SUCCESS(Status))
  1827. {
  1828. //
  1829. // Add the context to the logger
  1830. //
  1831. //
  1832. SrLoggerAddLogContext( global->pLogger,
  1833. pLogContext );
  1834. }
  1835. //
  1836. // Important: We should not fail after calling SrLoggerAddContext above
  1837. // because the finally clause assumes that if there's a failure,
  1838. // SrLoggerAddContext was not called yet. If this changes, use a
  1839. // BOOLEAN to appropriately indicate if SrLoggerAddContext is already
  1840. // called and use that to condition the call in the finally clause.
  1841. //
  1842. }
  1843. finally
  1844. {
  1845. Status = FinallyUnwind(SrLogStart, Status);
  1846. //
  1847. // if we are unsuccessful for some reason then clean up
  1848. // the logging structs (if necessary) .
  1849. //
  1850. if ((!NT_SUCCESS( Status )) && (pLogContext != NULL))
  1851. {
  1852. //
  1853. // We assume as per note above that the context count is not
  1854. // incremented. Increment it now because SrLogStop will decrement it
  1855. //
  1856. SrLoggerAddLogContext(global->pLogger,
  1857. pLogContext);
  1858. //
  1859. // Stop the log
  1860. //
  1861. SrLogStop( pExtension, TRUE, TRUE );
  1862. *ppLogContext = pLogContext = NULL;
  1863. }
  1864. }
  1865. RETURN(Status);
  1866. } // SrLogStart
  1867. //++
  1868. // Function:
  1869. // SrLogStop
  1870. //
  1871. // Description:
  1872. // This function closes / frees any resources used
  1873. // SR logging
  1874. //
  1875. // Arguments:
  1876. // pExtension - The SR device extension on this volume which contains
  1877. // our logging information.
  1878. // PurgeContexts - TRUE if we should purge all our contexts at this time
  1879. // CheckLog - TRUE if we should try to check and rename the log at
  1880. // this time. Note that checking the log could cause the volume
  1881. // to be remounted at this time. Therefore, if we don't want
  1882. // that to happen (i.e., during shutdown), CheckLog should be
  1883. // FALSE.
  1884. //
  1885. // Return Value:
  1886. // This function returns STATUS_XXX
  1887. //--
  1888. NTSTATUS
  1889. SrLogStop(
  1890. IN PSR_DEVICE_EXTENSION pExtension,
  1891. IN BOOLEAN PurgeContexts,
  1892. IN BOOLEAN CheckLog
  1893. )
  1894. {
  1895. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1896. PSR_LOG_CONTEXT pLogContext = pExtension->pLogContext;
  1897. PAGED_CODE();
  1898. //
  1899. // context must have been intialized by calling SrLogStart
  1900. //
  1901. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  1902. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) ||
  1903. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) );
  1904. try
  1905. {
  1906. //
  1907. // If we are diabling the volume then free all of the contexts
  1908. //
  1909. if (PurgeContexts)
  1910. {
  1911. SrDeleteAllContexts( pExtension );
  1912. }
  1913. //
  1914. // Close the log handle
  1915. //
  1916. if ( pLogContext->LogHandle )
  1917. {
  1918. SrTrace( LOG, ("Stopped logging : %wZ\n",
  1919. pLogContext->pLogFilePath));
  1920. Status = SrLogClose( pLogContext );
  1921. //
  1922. // Rename this log to the backup log for uniformity.
  1923. //
  1924. if (NT_SUCCESS(Status) && CheckLog)
  1925. {
  1926. Status = SrLogCheckAndRename( pExtension,
  1927. pLogContext->pLogFilePath );
  1928. }
  1929. }
  1930. //
  1931. // Remove the context from logger
  1932. //
  1933. SrLoggerRemoveLogContext( global->pLogger,
  1934. pLogContext );
  1935. //
  1936. // Free buffers
  1937. //
  1938. #ifdef SYNC_LOG_WRITE
  1939. //
  1940. // If we are doing synchronous log writes, we shouldn't have a
  1941. // buffer to free here.
  1942. //
  1943. ASSERT( pLogContext->pLogBuffer == NULL );
  1944. #else
  1945. //
  1946. // If we are doing asynchronous log writes, we need to free the buffer
  1947. // used to collect log entries.
  1948. //
  1949. if ( pLogContext->pLogBuffer )
  1950. {
  1951. SrFreeLogBuffer( pLogContext->pLogBuffer );
  1952. pLogContext->pLogBuffer = NULL;
  1953. }
  1954. #endif
  1955. if ( pLogContext->pLogFilePath )
  1956. {
  1957. SrFreeFileNameBuffer( pLogContext->pLogFilePath );
  1958. pLogContext->pLogFilePath = NULL;
  1959. }
  1960. SR_FREE_POOL_WITH_SIG(pLogContext, SR_LOG_CONTEXT_TAG);
  1961. //
  1962. // Set logging state in extension
  1963. //
  1964. pExtension->pLogContext = NULL;
  1965. pExtension->DriveChecked = FALSE;
  1966. Status = STATUS_SUCCESS;
  1967. }
  1968. finally
  1969. {
  1970. Status = FinallyUnwind(SrLogStop, Status);
  1971. }
  1972. RETURN(Status);
  1973. } // SrLogStop
  1974. //++
  1975. // Function:
  1976. // SrLogNormalize
  1977. //
  1978. // Description:
  1979. // This function ensures that any closed change.log files have been
  1980. // renamed to change[#].log format for restore. Since we can't always
  1981. // ensure that the change.log got renamed when the log was stopped (we
  1982. // can't do this on shutdown), we need to do this normalization for
  1983. // Restore.
  1984. //
  1985. // Arguments:
  1986. // pExtension - The SR Device Extension for this volume.
  1987. //
  1988. // Return Value:
  1989. // This function returns STATUS_SUCCESS if we were able to do the
  1990. // log normalization or the appropriate error code otherwise.
  1991. //--
  1992. NTSTATUS
  1993. SrLogNormalize (
  1994. IN PSR_DEVICE_EXTENSION pExtension
  1995. )
  1996. {
  1997. NTSTATUS status;
  1998. PUNICODE_STRING pLogPath = NULL;
  1999. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) ||
  2000. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) );
  2001. //
  2002. // Check to see if we have a restore location for this volume yet.
  2003. // If not, we don't have to do any more work.
  2004. //
  2005. status = SrCheckForRestoreLocation( pExtension );
  2006. if (!NT_SUCCESS_NO_DBGBREAK( status ))
  2007. {
  2008. status = STATUS_SUCCESS;
  2009. goto SrLogNormalize_Exit;
  2010. }
  2011. //
  2012. // We do have a restore location, so build up the log path.
  2013. //
  2014. status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pLogPath);
  2015. if (!NT_SUCCESS(status))
  2016. {
  2017. goto SrLogNormalize_Exit;
  2018. }
  2019. status = SrGetLogFileName( pExtension->pNtVolumeName,
  2020. SR_FILENAME_BUFFER_LENGTH,
  2021. pLogPath );
  2022. if (!NT_SUCCESS(status))
  2023. {
  2024. goto SrLogNormalize_Exit;
  2025. }
  2026. status = SrLogCheckAndRename( pExtension, pLogPath );
  2027. SrLogNormalize_Exit:
  2028. if (pLogPath != NULL)
  2029. {
  2030. SrFreeFileNameBuffer( pLogPath );
  2031. }
  2032. RETURN( status );
  2033. }
  2034. //++
  2035. // Function:
  2036. // SrLogWrite
  2037. //
  2038. // Description:
  2039. // This function writes the entry into the log cache and
  2040. // flushes the cache in case the entry cannot fit in.
  2041. //
  2042. // Arguments:
  2043. // Pointer to Device object
  2044. //
  2045. // Return Value:
  2046. // This function returns STATUS_XXX
  2047. //--
  2048. NTSTATUS
  2049. SrLogWrite(
  2050. IN PSR_DEVICE_EXTENSION pOptionalExtension OPTIONAL,
  2051. IN PSR_LOG_CONTEXT pOptionalLogContext OPTIONAL,
  2052. IN PSR_LOG_ENTRY pLogEntry
  2053. )
  2054. {
  2055. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2056. PSR_LOG_CONTEXT pLogContext = NULL;
  2057. PSR_DEVICE_EXTENSION pExtension = NULL;
  2058. PAGED_CODE();
  2059. ASSERT(pOptionalExtension == NULL || IS_VALID_SR_DEVICE_EXTENSION(pOptionalExtension));
  2060. ASSERT(pOptionalExtension != NULL || pOptionalLogContext != NULL);
  2061. ASSERT(pLogEntry != NULL);
  2062. if (pOptionalExtension != NULL)
  2063. {
  2064. //
  2065. // We need to ensure that the volume hasn't been disabled before
  2066. // we do anything.
  2067. //
  2068. if (pOptionalExtension->Disabled) {
  2069. Status = STATUS_SUCCESS;
  2070. goto SrLogWrite_Exit;
  2071. }
  2072. //
  2073. // we need to make sure our disk structures are good and logging
  2074. // has been started. it's possible we have been called simply to
  2075. // log and logging was stopped due to volume lock. we have to
  2076. // check with the global lock held.
  2077. //
  2078. Status = SrCheckVolume(pOptionalExtension, FALSE);
  2079. if (!NT_SUCCESS( Status ))
  2080. goto SrLogWrite_Exit;
  2081. pLogContext = pOptionalExtension->pLogContext;
  2082. }
  2083. else
  2084. {
  2085. //
  2086. // use the free form context passed in (only SrLogOpen does this)
  2087. //
  2088. pLogContext = pOptionalLogContext;
  2089. }
  2090. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  2091. if (pLogContext == NULL)
  2092. {
  2093. //
  2094. // this is unexpected, but need to protect against
  2095. //
  2096. Status = STATUS_INVALID_PARAMETER;
  2097. CHECK_STATUS(Status);
  2098. goto SrLogWrite_Exit;
  2099. }
  2100. pExtension = pLogContext->pExtension;
  2101. ASSERT( pExtension != NULL );
  2102. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_SHARED( pExtension ) ||
  2103. IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) );
  2104. try {
  2105. SrAcquireLogLockExclusive( pExtension );
  2106. //
  2107. // Check to make sure the volume is still enabled.
  2108. //
  2109. if (!SR_LOGGING_ENABLED( pExtension ))
  2110. {
  2111. Status = STATUS_SUCCESS;
  2112. leave;
  2113. }
  2114. //
  2115. // bail if logging is disabled for this context
  2116. //
  2117. if (!FlagOn(pLogContext->LoggingFlags, SR_LOG_FLAGS_ENABLE))
  2118. {
  2119. leave;
  2120. }
  2121. //
  2122. // check the log file, if it is greater than 1Mb switch the log
  2123. //
  2124. if ( (pLogContext->FileOffset +
  2125. pLogContext->BufferOffset +
  2126. pLogEntry->Header.RecordSize) > SR_MAX_LOG_FILE_SIZE )
  2127. {
  2128. Status = SrLogSwitch( pLogContext );
  2129. if (!NT_SUCCESS( Status ))
  2130. {
  2131. leave;
  2132. }
  2133. }
  2134. #ifdef SYNC_LOG_WRITE
  2135. Status = SrpLogWriteSynchronous( pExtension,
  2136. pLogContext,
  2137. pLogEntry);
  2138. #else
  2139. Status = SrpLogWriteAsynchronous( pExtension,
  2140. pLogContext,
  2141. pLogEntry);
  2142. #endif
  2143. } finally {
  2144. Status = FinallyUnwind(SrLogWrite, Status);
  2145. SrReleaseLogLock(pExtension);
  2146. }
  2147. SrLogWrite_Exit:
  2148. RETURN(Status);
  2149. } // SrLogWrite
  2150. //++
  2151. // Function:
  2152. // SrLogWriteSynchronous
  2153. //
  2154. // Description:
  2155. //
  2156. // This function writes each log entry to the current change log
  2157. // and ensures the updated change log is flushed to disk before
  2158. // it returns.
  2159. //
  2160. // Arguments:
  2161. //
  2162. // pExtension - The device extension for the volume whose change
  2163. // log is going to be updated.
  2164. // pLogContext - The log context that contains the information
  2165. // about which change log should updated.
  2166. // pLogEntry - The log entry to be written.
  2167. //
  2168. // Return Value:
  2169. // This function returns STATUS_XXX
  2170. //--
  2171. NTSTATUS
  2172. SrpLogWriteSynchronous(
  2173. IN PSR_DEVICE_EXTENSION pExtension,
  2174. IN PSR_LOG_CONTEXT pLogContext,
  2175. IN PSR_LOG_ENTRY pLogEntry
  2176. )
  2177. {
  2178. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2179. PAGED_CODE();
  2180. UNREFERENCED_PARAMETER( pExtension );
  2181. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pExtension ) );
  2182. ASSERT( IS_VALID_LOG_CONTEXT( pLogContext ) );
  2183. ASSERT( pLogEntry != NULL );
  2184. ASSERT( IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) );
  2185. //
  2186. // In this mode, we are not buffering the log entries, so just point
  2187. // the pLogContext->pLogBuffer to the current pLogEntry so save the
  2188. // copy into the buffer.
  2189. //
  2190. ASSERT( pLogContext->pLogBuffer == NULL );
  2191. pLogContext->pLogBuffer = (PBYTE) pLogEntry;
  2192. pLogContext->BufferOffset = pLogEntry->Header.RecordSize;
  2193. SET_DIRTY_FLAG(pLogContext);
  2194. Status = SrLogFlush( pLogContext );
  2195. //
  2196. // Clear out the pLogBuffer reference to the pLogEntry whether or
  2197. // not the flush succeeded.
  2198. //
  2199. pLogContext->pLogBuffer = NULL;
  2200. RETURN(Status);
  2201. }
  2202. #ifndef SYNC_LOG_WRITE
  2203. //++
  2204. // Function:
  2205. // SrLogWriteAsynchronous
  2206. //
  2207. // Description:
  2208. //
  2209. // This function buffers log writes then flushes the writes when the
  2210. // buffer is full.
  2211. //
  2212. // Arguments:
  2213. //
  2214. // pExtension - The device extension for the volume whose change
  2215. // log is going to be updated.
  2216. // pLogContext - The log context that contains the information
  2217. // about which change log should updated.
  2218. // pLogEntry - The log entry to be written.
  2219. //
  2220. // Return Value:
  2221. // This function returns STATUS_XXX
  2222. //--
  2223. NTSTATUS
  2224. SrpLogWriteAsynchronous(
  2225. IN PSR_DEVICE_EXTENSION pExtension,
  2226. IN PSR_LOG_CONTEXT pLogContext,
  2227. IN PSR_LOG_ENTRY pLogEntry
  2228. )
  2229. {
  2230. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2231. PAGED_CODE();
  2232. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pExtension ) );
  2233. ASSERT( IS_VALID_LOG_CONTEXT( pLogContext ) );
  2234. ASSERT( pLogEntry != NULL );
  2235. ASSERT( IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) );
  2236. //
  2237. // Check if the entry can fit into the current buffer, if not
  2238. // then adjust the last entry of the buffer and write it down
  2239. // to the disk
  2240. //
  2241. if ( (pLogContext->BufferOffset + pLogEntry->Header.RecordSize) >
  2242. _globals.LogBufferSize )
  2243. {
  2244. //
  2245. // check to make sure we have 50mb free, we are about to
  2246. // grow the file
  2247. //
  2248. Status = SrCheckFreeDiskSpace( pLogContext->LogHandle,
  2249. pExtension->pNtVolumeName );
  2250. if (!NT_SUCCESS( Status ))
  2251. {
  2252. goto SrpLogWriteAsynchronous_Exit;
  2253. }
  2254. //
  2255. // set the dirty flag because we have updated the buffer
  2256. //
  2257. SET_DIRTY_FLAG(pLogContext);
  2258. Status = SrLogFlush( pLogContext );
  2259. if (!NT_SUCCESS( Status ))
  2260. {
  2261. goto SrpLogWriteAsynchronous_Exit;
  2262. }
  2263. //
  2264. // Check to make sure that the pLogEntry itself isn't bigger
  2265. // than the _globals.LogBufferSize.
  2266. //
  2267. if (pLogEntry->Header.RecordSize > _globals.LogBufferSize)
  2268. {
  2269. PBYTE pLogBuffer;
  2270. //
  2271. // The log was just successfully flushed, therefore there should
  2272. // be no data in the buffer yet.
  2273. //
  2274. ASSERT( pLogContext->BufferOffset == 0 );
  2275. //
  2276. // For synchronous writes, we don't expect there to be a log buffer
  2277. // in the context so we will save this off in a local and NULL
  2278. // this parameter in the pLogContext while we make this call.
  2279. //
  2280. pLogBuffer = pLogContext->pLogBuffer;
  2281. pLogContext->pLogBuffer = NULL;
  2282. Status = SrpLogWriteSynchronous( pExtension,
  2283. pLogContext,
  2284. pLogEntry );
  2285. //
  2286. // We ALWAYS need to restore this pointer in the pLogContext.
  2287. //
  2288. pLogContext->pLogBuffer = pLogBuffer;
  2289. CHECK_STATUS( Status );
  2290. //
  2291. // Whether we succeeded or failed, we want to skip the logic below
  2292. // and exit now.
  2293. //
  2294. goto SrpLogWriteAsynchronous_Exit;
  2295. }
  2296. }
  2297. //
  2298. // We now have enough room in the buffer for this pLogEntry, so append the
  2299. // entry to the buffer.
  2300. //
  2301. RtlCopyMemory( pLogContext->pLogBuffer + pLogContext->BufferOffset,
  2302. pLogEntry,
  2303. pLogEntry->Header.RecordSize );
  2304. //
  2305. // Update buffer pointers to reflect the entry has been added
  2306. //
  2307. pLogContext->LastBufferOffset = pLogContext->BufferOffset;
  2308. pLogContext->BufferOffset += pLogEntry->Header.RecordSize;
  2309. SET_DIRTY_FLAG(pLogContext);
  2310. //
  2311. // We were able to copy into the buffer successfully, so return
  2312. // STATUS_SUCCESS.
  2313. //
  2314. Status = STATUS_SUCCESS;
  2315. SrpLogWriteAsynchronous_Exit:
  2316. RETURN(Status);
  2317. }
  2318. #endif
  2319. //++
  2320. // Function:
  2321. // SrLogFlush
  2322. //
  2323. // Description:
  2324. // This function flushes the buffer contents in memory
  2325. // to the log, it doesn't increment file offset in the
  2326. // log context.
  2327. //
  2328. // Arguments:
  2329. // Pointer to new Log Context
  2330. //
  2331. // Return Value:
  2332. // This function returns STATUS_XXX
  2333. //--
  2334. NTSTATUS
  2335. SrLogFlush(
  2336. IN PSR_LOG_CONTEXT pLogContext
  2337. )
  2338. {
  2339. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2340. IO_STATUS_BLOCK IoStatusBlock;
  2341. BOOLEAN ExtendLogFile = FALSE;
  2342. PAGED_CODE();
  2343. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  2344. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) ||
  2345. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE(pLogContext->pExtension));
  2346. SrTrace(FUNC_ENTRY, ("SR!SrLogFlush\n") );
  2347. //
  2348. // should we short circuit out of here for testing mode?
  2349. //
  2350. if (global->DontBackup)
  2351. {
  2352. Status = STATUS_SUCCESS;
  2353. goto SrLogFlush_Exit;
  2354. }
  2355. //
  2356. // bail if the context is disabled
  2357. //
  2358. if (!FlagOn( pLogContext->LoggingFlags, SR_LOG_FLAGS_ENABLE ))
  2359. {
  2360. goto SrLogFlush_Exit;
  2361. }
  2362. ASSERT( pLogContext->LogHandle != NULL );
  2363. if (FlagOn( pLogContext->LoggingFlags, SR_LOG_FLAGS_DIRTY ))
  2364. {
  2365. SrTrace( LOG, ("Flushing Log :%wZ", pLogContext->pLogFilePath));
  2366. //
  2367. // Do we need to extend our log file? We can possibly loop here if
  2368. // the amount of data we need to write is greater than our
  2369. // allocation unit. We want to make sure that if we do have to extend
  2370. // the file that we have at least extended it enough for our
  2371. // current write.
  2372. //
  2373. while ((pLogContext->BufferOffset + pLogContext->FileOffset) >
  2374. pLogContext->AllocationSize)
  2375. {
  2376. //
  2377. // This file will need to be extended for this write.
  2378. //
  2379. ExtendLogFile = TRUE;
  2380. pLogContext->AllocationSize += _globals.LogAllocationUnit;
  2381. }
  2382. if (ExtendLogFile)
  2383. {
  2384. FILE_ALLOCATION_INFORMATION fileAllocInfo;
  2385. fileAllocInfo.AllocationSize.QuadPart = pLogContext->AllocationSize;
  2386. Status = SrSetInformationFile( pLogContext->pExtension->pTargetDevice,
  2387. pLogContext->pLogFileObject,
  2388. &fileAllocInfo,
  2389. sizeof( fileAllocInfo ),
  2390. FileAllocationInformation );
  2391. if ((Status == STATUS_NO_SUCH_DEVICE) ||
  2392. (Status == STATUS_INVALID_HANDLE) ||
  2393. !NT_SUCCESS( Status ))
  2394. {
  2395. SrTrace( LOG, ("SrLogFlush: Log extension failed: 0x%x\n", Status) );
  2396. goto SrLogFlush_Exit;
  2397. }
  2398. }
  2399. //
  2400. // Write the buffer to the disk. We have opened this file in append
  2401. // only mode, so the file system will maintain the current file
  2402. // position for us. This handle was open for SYNCHRONOUS access,
  2403. // therefore, this IO will not return until it has completed.
  2404. //
  2405. ASSERT( pLogContext->pLogBuffer != NULL );
  2406. Status = ZwWriteFile( pLogContext->LogHandle,
  2407. NULL, // Event
  2408. NULL, // ApcRoutine
  2409. NULL, // ApcContext
  2410. &IoStatusBlock,
  2411. pLogContext->pLogBuffer,
  2412. pLogContext->BufferOffset,
  2413. NULL, // ByteOffset
  2414. NULL ); // Key
  2415. //
  2416. // Handle STATUS_NO_SUCH_DEVICE because we expect this when
  2417. // HotPlugable devices are removed by surprise.
  2418. //
  2419. // Handle STATUS_INVALID_HANDLE because we expect this when
  2420. // a force-dismount came through on a volume.
  2421. //
  2422. if ((Status == STATUS_NO_SUCH_DEVICE) ||
  2423. (Status == STATUS_INVALID_HANDLE) ||
  2424. !NT_SUCCESS( Status ))
  2425. {
  2426. SrTrace( LOG,("SrLogFlush: Write failed: 0x%x\n", Status) );
  2427. goto SrLogFlush_Exit;
  2428. }
  2429. Status = SrFlushBuffers( pLogContext->pExtension->pTargetDevice,
  2430. pLogContext->pLogFileObject );
  2431. if (!NT_SUCCESS( Status ))
  2432. {
  2433. SrTrace( LOG,("SrLogFlush: Flush failed: 0x%x\n", Status) );
  2434. goto SrLogFlush_Exit;
  2435. }
  2436. SrTrace( LOG,("SrLogFlush: Flush succeeded!\n"));
  2437. //
  2438. // We've dumped the buffer to disk, so update our file offset with the
  2439. // number of bytes we have written, reset our buffer pointer, and
  2440. // clear the dirty flag on this log context since it is no longer
  2441. // dirty.
  2442. //
  2443. ASSERT( pLogContext->BufferOffset == IoStatusBlock.Information );
  2444. UPDATE_LOG_OFFSET( pLogContext, pLogContext->BufferOffset );
  2445. RESET_LOG_BUFFER( pLogContext );
  2446. CLEAR_DIRTY_FLAG( pLogContext );
  2447. }
  2448. //
  2449. // If we got here, the flush was successful, so return that status.
  2450. //
  2451. Status = STATUS_SUCCESS;
  2452. SrLogFlush_Exit:
  2453. #if DBG
  2454. if (Status == STATUS_NO_SUCH_DEVICE ||
  2455. Status == STATUS_INVALID_HANDLE)
  2456. {
  2457. return Status;
  2458. }
  2459. #endif
  2460. RETURN(Status);
  2461. } // SrLogFlush
  2462. //++
  2463. // Function:
  2464. // SrLogSwitch
  2465. //
  2466. // Description:
  2467. // This function Switches the current log to the
  2468. // new log.
  2469. //
  2470. // Arguments:
  2471. // Pointer to new log context.
  2472. //
  2473. // Return Value:
  2474. // This function returns STATUS_XXX
  2475. //--
  2476. NTSTATUS
  2477. SrLogSwitch(
  2478. IN PSR_LOG_CONTEXT pLogContext
  2479. )
  2480. {
  2481. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2482. PAGED_CODE();
  2483. ASSERT(IS_VALID_LOG_CONTEXT(pLogContext));
  2484. ASSERT( IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) ||
  2485. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pLogContext->pExtension ) );
  2486. //
  2487. // bail if the context is disabled
  2488. //
  2489. if (!FlagOn( pLogContext->LoggingFlags, SR_LOG_FLAGS_ENABLE ))
  2490. {
  2491. Status = STATUS_UNSUCCESSFUL;
  2492. goto SrLogSwitch_Exit;
  2493. }
  2494. if (pLogContext->LogHandle)
  2495. {
  2496. //
  2497. // flush and close current log ( close - flushes also )
  2498. //
  2499. Status = SrLogClose(pLogContext);
  2500. if ( NT_SUCCESS(Status) )
  2501. {
  2502. //
  2503. // rename the old log file if one exists
  2504. //
  2505. Status = SrLogCheckAndRename( pLogContext->pExtension,
  2506. pLogContext->pLogFilePath );
  2507. if (NT_SUCCESS(Status))
  2508. {
  2509. //
  2510. // try and open the log file
  2511. //
  2512. Status = SrLogOpen( pLogContext );
  2513. }
  2514. }
  2515. }
  2516. SrLogSwitch_Exit:
  2517. RETURN(Status);
  2518. } // SrLogSwitch
  2519. /////////////////////////////////////////////////////////////////////
  2520. //
  2521. // Misc Routines : Misc routines required by the logging module
  2522. //
  2523. /////////////////////////////////////////////////////////////////////
  2524. //++
  2525. // Function:
  2526. // SrGetRestorePointPath
  2527. //
  2528. // Description:
  2529. // This function creates a path for the restore point dir.
  2530. //
  2531. // Arguments:
  2532. // Pointer to log entry buffer
  2533. // Length of the Log filename buffer
  2534. // Pointer to the Log filename buffer
  2535. //
  2536. // Return Value:
  2537. // This function returns STATUS_XXX
  2538. //--
  2539. NTSTATUS
  2540. SrGetRestorePointPath(
  2541. IN PUNICODE_STRING pVolumeName,
  2542. IN USHORT RestPtPathLength,
  2543. OUT PUNICODE_STRING pRestPtPath
  2544. )
  2545. {
  2546. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2547. ULONG CharCount;
  2548. PAGED_CODE();
  2549. ASSERT(pVolumeName != NULL);
  2550. ASSERT(pRestPtPath != NULL);
  2551. try
  2552. {
  2553. //
  2554. // Copy the volume name in the log file
  2555. //
  2556. pRestPtPath->Buffer = (PWSTR)(pRestPtPath+1);
  2557. //
  2558. // TODO:(CODEWORK: grab a lock around global?)
  2559. //
  2560. //
  2561. // construct our restore point location string
  2562. //
  2563. CharCount = swprintf( pRestPtPath->Buffer,
  2564. VOLUME_FORMAT RESTORE_LOCATION,
  2565. pVolumeName,
  2566. global->MachineGuid );
  2567. pRestPtPath->Length = (USHORT)CharCount * sizeof(WCHAR);
  2568. pRestPtPath->MaximumLength = RestPtPathLength;
  2569. if ( pRestPtPath->Length > RestPtPathLength )
  2570. {
  2571. Status = STATUS_INSUFFICIENT_RESOURCES;
  2572. leave;
  2573. }
  2574. //
  2575. // Append the restore point directory
  2576. //
  2577. CharCount = swprintf(
  2578. &pRestPtPath->Buffer[pRestPtPath->Length/sizeof(WCHAR)],
  2579. L"\\" RESTORE_POINT_PREFIX L"%d\\",
  2580. global->FileConfig.CurrentRestoreNumber );
  2581. pRestPtPath->Length += (USHORT)CharCount * sizeof(WCHAR);
  2582. pRestPtPath->MaximumLength = RestPtPathLength;
  2583. if ( pRestPtPath->Length > RestPtPathLength )
  2584. {
  2585. Status = STATUS_INSUFFICIENT_RESOURCES;
  2586. leave;
  2587. }
  2588. //
  2589. // NULL terminate it
  2590. //
  2591. pRestPtPath->Buffer[pRestPtPath->Length/sizeof(WCHAR)] = UNICODE_NULL;
  2592. Status = STATUS_SUCCESS;
  2593. }
  2594. finally
  2595. {
  2596. }
  2597. RETURN(Status);
  2598. } // SrGetRestorePointPath
  2599. //++
  2600. // Function:
  2601. // SrGetLogFileName
  2602. //
  2603. // Description:
  2604. // This function creates a path for change log in restore point dir.
  2605. //
  2606. // Arguments:
  2607. // Pointer to log entry buffer
  2608. // Length of the Log filename buffer
  2609. // Pointer to the Log filename buffer
  2610. //
  2611. // Return Value:
  2612. // This function returns STATUS_XXX
  2613. //--
  2614. NTSTATUS
  2615. SrGetLogFileName(
  2616. IN PUNICODE_STRING pVolumeName,
  2617. IN USHORT LogFileNameLength,
  2618. OUT PUNICODE_STRING pLogFileName
  2619. )
  2620. {
  2621. NTSTATUS Status;
  2622. PAGED_CODE();
  2623. ASSERT(pVolumeName != NULL);
  2624. ASSERT(pLogFileName != NULL);
  2625. //
  2626. // Get restore point path
  2627. //
  2628. Status = SrGetRestorePointPath( pVolumeName,
  2629. LogFileNameLength,
  2630. pLogFileName );
  2631. if (NT_SUCCESS(Status))
  2632. {
  2633. //
  2634. // Append changelog file name
  2635. //
  2636. Status = RtlAppendUnicodeToString( pLogFileName, s_cszCurrentChangeLog );
  2637. }
  2638. RETURN(Status);
  2639. } // SrGetLogFileName
  2640. //++
  2641. // Function:
  2642. // SrGetAclFileName
  2643. //
  2644. // Description:
  2645. // This function creates a path for Acl file in restore point dir.
  2646. //
  2647. // Arguments:
  2648. // Pointer to log entry buffer
  2649. // Length of the Log filename buffer
  2650. // Pointer to the Log filename buffer
  2651. //
  2652. // Return Value:
  2653. // This function returns STATUS_XXX
  2654. //--
  2655. NTSTATUS
  2656. SrGetAclFileName(
  2657. IN PUNICODE_STRING pVolumeName,
  2658. IN USHORT AclFileNameLength,
  2659. OUT PUNICODE_STRING pAclFileName
  2660. )
  2661. {
  2662. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  2663. ULONG CharCount;
  2664. ULONG NextFileNumber;
  2665. PAGED_CODE();
  2666. ASSERT(pVolumeName != NULL);
  2667. ASSERT(pAclFileName != NULL);
  2668. //
  2669. // Get restore point path
  2670. //
  2671. Status = SrGetRestorePointPath( pVolumeName,
  2672. AclFileNameLength,
  2673. pAclFileName );
  2674. if (NT_SUCCESS(Status))
  2675. {
  2676. //
  2677. // Generate a new file number and append it to the path above
  2678. //
  2679. Status = SrGetNextFileNumber(&NextFileNumber);
  2680. if (!NT_SUCCESS( Status ))
  2681. goto End;
  2682. //
  2683. // use the "S" prefix (e.g. "S0000001.Acl" )
  2684. //
  2685. CharCount = swprintf( &pAclFileName->Buffer[pAclFileName->Length/sizeof(WCHAR)],
  2686. ACL_FILE_PREFIX L"%07d" ACL_FILE_SUFFIX,
  2687. NextFileNumber );
  2688. pAclFileName->Length += (USHORT)CharCount * sizeof(WCHAR);
  2689. if ( pAclFileName->Length > AclFileNameLength )
  2690. {
  2691. goto End;
  2692. }
  2693. //
  2694. // NULL terminate it
  2695. //
  2696. pAclFileName->Buffer[pAclFileName->Length/sizeof(WCHAR)]=UNICODE_NULL;
  2697. }
  2698. End:
  2699. RETURN(Status);
  2700. } // SrGetAclFileName
  2701. //++
  2702. // Function:
  2703. // SrGetAclInformation
  2704. //
  2705. // Description:
  2706. // This function gets the acl information from the given file
  2707. // and packs it into a sub-record
  2708. //
  2709. // Arguments:
  2710. // Pointer to filename
  2711. // Pointer to variable to return the address of security info
  2712. // Pointer to variable to return the size of security info
  2713. //
  2714. // Return Value:
  2715. // This function returns STATUS_XXX
  2716. //--
  2717. NTSTATUS
  2718. SrGetAclInformation (
  2719. IN PFILE_OBJECT pFileObject,
  2720. IN PSR_DEVICE_EXTENSION pExtension,
  2721. OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor,
  2722. OUT PULONG pSizeNeeded
  2723. )
  2724. {
  2725. NTSTATUS Status = STATUS_SUCCESS;
  2726. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  2727. ULONG SizeNeeded = 256;
  2728. struct
  2729. {
  2730. FILE_FS_ATTRIBUTE_INFORMATION Info;
  2731. WCHAR Buffer[ 50 ];
  2732. } FileFsAttrInfoBuffer;
  2733. PAGED_CODE();
  2734. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  2735. ASSERT(pSizeNeeded != NULL);
  2736. ASSERT(ppSecurityDescriptor != NULL);
  2737. try
  2738. {
  2739. *ppSecurityDescriptor = NULL;
  2740. *pSizeNeeded = 0;
  2741. //
  2742. // First check if we already know if the fs supports acls
  2743. // Do this check now so we can leave real fast if the volume
  2744. // doesn't support ACLs
  2745. //
  2746. if (pExtension->CachedFsAttributes &&
  2747. (!FlagOn(pExtension->FsAttributes, FILE_PERSISTENT_ACLS))) {
  2748. leave;
  2749. }
  2750. //
  2751. // Check if the file system supports acl stuff if necessary
  2752. //
  2753. if (!pExtension->CachedFsAttributes) {
  2754. //
  2755. // We need to check now
  2756. //
  2757. Status = SrQueryVolumeInformationFile( pExtension->pTargetDevice,
  2758. pFileObject,
  2759. &FileFsAttrInfoBuffer.Info,
  2760. sizeof(FileFsAttrInfoBuffer),
  2761. FileFsAttributeInformation,
  2762. NULL );
  2763. if (!NT_SUCCESS( Status ))
  2764. leave;
  2765. //
  2766. // Stow away the attributes for later use
  2767. //
  2768. pExtension->CachedFsAttributes = TRUE;
  2769. pExtension->FsAttributes = FileFsAttrInfoBuffer.Info.FileSystemAttributes;
  2770. if (!FlagOn(pExtension->FsAttributes, FILE_PERSISTENT_ACLS))
  2771. leave;
  2772. }
  2773. //
  2774. // Read in the security information from the source file
  2775. // (looping until we get a big enough buffer).
  2776. //
  2777. while (TRUE )
  2778. {
  2779. //
  2780. // Alloc a buffer to hold the security info.
  2781. //
  2782. pSecurityDescriptor = SR_ALLOCATE_ARRAY( PagedPool,
  2783. UCHAR,
  2784. SizeNeeded,
  2785. SR_SECURITY_DATA_TAG );
  2786. if (NULL == pSecurityDescriptor)
  2787. {
  2788. Status = STATUS_INSUFFICIENT_RESOURCES;
  2789. leave;
  2790. }
  2791. //
  2792. // Query the security info
  2793. //
  2794. Status = SrQuerySecurityObject( pExtension->pTargetDevice,
  2795. pFileObject,
  2796. DACL_SECURITY_INFORMATION
  2797. |SACL_SECURITY_INFORMATION
  2798. |OWNER_SECURITY_INFORMATION
  2799. |GROUP_SECURITY_INFORMATION,
  2800. pSecurityDescriptor,
  2801. SizeNeeded,
  2802. &SizeNeeded );
  2803. //
  2804. // Not enough buffer?
  2805. //
  2806. if (STATUS_BUFFER_TOO_SMALL == Status ||
  2807. STATUS_BUFFER_OVERFLOW == Status)
  2808. {
  2809. //
  2810. // Get a bigger buffer and try again.
  2811. //
  2812. SR_FREE_POOL( pSecurityDescriptor,
  2813. SR_SECURITY_DATA_TAG );
  2814. pSecurityDescriptor = NULL;
  2815. SizeNeeded *= 2;
  2816. continue;
  2817. }
  2818. break;
  2819. }
  2820. if (!NT_SUCCESS( Status ))
  2821. leave;
  2822. //
  2823. // Security descriptor should be self relative.
  2824. //
  2825. ASSERT(((PISECURITY_DESCRIPTOR_RELATIVE)pSecurityDescriptor)->Control & SE_SELF_RELATIVE);
  2826. //
  2827. // return the security information
  2828. //
  2829. *ppSecurityDescriptor = pSecurityDescriptor;
  2830. pSecurityDescriptor = NULL;
  2831. *pSizeNeeded = SizeNeeded;
  2832. SrTrace( LOG, ("sr!SrGetAclInformation: returning [0x%p,%d]\n",
  2833. *ppSecurityDescriptor,
  2834. SizeNeeded ));
  2835. } finally {
  2836. Status = FinallyUnwind(SrGetAclInformation, Status);
  2837. if (pSecurityDescriptor != NULL)
  2838. {
  2839. SR_FREE_POOL( pSecurityDescriptor, SR_SECURITY_DATA_TAG );
  2840. pSecurityDescriptor = NULL;
  2841. }
  2842. }
  2843. RETURN(Status);
  2844. } // SrGetAclInformation