Leaked source code of windows server 2003
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.

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