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.

4025 lines
122 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. event.c
  5. Abstract:
  6. This module contains the event handling logic for sr
  7. There are 3 main entrypoints to this module:
  8. SrHandleEvent
  9. SrHandleRename
  10. SrHandleDirectoryRename
  11. Author:
  12. Paul McDaniel (paulmcd) 18-Apr-2000
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. //
  17. // Private constants.
  18. //
  19. //
  20. // event optimization defines
  21. //
  22. //
  23. // Private types.
  24. //
  25. #define IS_VALID_TRIGGER_ITEM(pObject) \
  26. (((pObject) != NULL) && ((pObject)->Signature == SR_TRIGGER_ITEM_TAG))
  27. typedef struct _SR_TRIGGER_ITEM
  28. {
  29. //
  30. // PagedPool
  31. //
  32. //
  33. // = SR_TRIGGER_ITEM_TAG
  34. //
  35. ULONG Signature;
  36. LIST_ENTRY ListEntry;
  37. PUNICODE_STRING pDirectoryName;
  38. BOOLEAN FreeDirectoryName;
  39. HANDLE DirectoryHandle;
  40. PFILE_OBJECT pDirectoryObject;
  41. ULONG FileEntryLength;
  42. PFILE_DIRECTORY_INFORMATION pFileEntry;
  43. } SR_TRIGGER_ITEM, *PSR_TRIGGER_ITEM;
  44. typedef struct _SR_COUNTED_EVENT
  45. {
  46. //
  47. // NonPagedPool
  48. //
  49. LONG WorkItemCount;
  50. KEVENT Event;
  51. } SR_COUNTED_EVENT, *PSR_COUNTED_EVENT;
  52. #define IS_VALID_BACKUP_DIRECTORY_CONTEXT(pObject) \
  53. (((pObject) != NULL) && ((pObject)->Signature == SR_BACKUP_DIRECTORY_CONTEXT_TAG))
  54. typedef struct _SR_BACKUP_DIRECTORY_CONTEXT
  55. {
  56. //
  57. // PagedPool
  58. //
  59. //
  60. // = SR_BACKUP_DIRECTORY_CONTEXT_TAG
  61. //
  62. ULONG Signature;
  63. WORK_QUEUE_ITEM WorkItem;
  64. PSR_DEVICE_EXTENSION pExtension;
  65. UNICODE_STRING DirectoryName;
  66. BOOLEAN EventDelete;
  67. PSR_COUNTED_EVENT pEvent;
  68. } SR_BACKUP_DIRECTORY_CONTEXT, * PSR_BACKUP_DIRECTORY_CONTEXT;
  69. //
  70. // Private prototypes.
  71. //
  72. NTSTATUS
  73. SrpIsFileStillEligible (
  74. IN PSR_DEVICE_EXTENSION pExtension,
  75. IN PSR_STREAM_CONTEXT pFileContext,
  76. IN SR_EVENT_TYPE EventType,
  77. OUT PBOOLEAN pMonitorFile);
  78. VOID
  79. SrFreeTriggerItem (
  80. IN PSR_TRIGGER_ITEM pItem
  81. );
  82. NTSTATUS
  83. SrTriggerEvents (
  84. IN PSR_DEVICE_EXTENSION pExtension,
  85. IN PUNICODE_STRING pDirectoryName,
  86. IN BOOLEAN EventDelete
  87. );
  88. NTSTATUS
  89. SrHandleDelete(
  90. IN PSR_DEVICE_EXTENSION pExtension,
  91. IN PFILE_OBJECT pFileObject,
  92. IN PSR_STREAM_CONTEXT pFileContext
  93. );
  94. VOID
  95. SrCreateRestoreLocationWorker (
  96. IN PSR_WORK_ITEM pWorkItem
  97. );
  98. NTSTATUS
  99. SrHandleFileChange (
  100. IN PSR_DEVICE_EXTENSION pExtension,
  101. IN SR_EVENT_TYPE EventType,
  102. IN PFILE_OBJECT pFileObject,
  103. IN PUNICODE_STRING pFileName
  104. );
  105. NTSTATUS
  106. SrHandleFileOverwrite(
  107. IN PSR_DEVICE_EXTENSION pExtension,
  108. IN OUT PSR_OVERWRITE_INFO pOverwriteInfo,
  109. IN PSR_STREAM_CONTEXT pFileContext
  110. );
  111. NTSTATUS
  112. SrRenameFileIntoStore(
  113. IN PSR_DEVICE_EXTENSION pExtension,
  114. IN PFILE_OBJECT pFileObject,
  115. IN HANDLE FileHandle,
  116. IN PUNICODE_STRING pOriginalFileName,
  117. IN PUNICODE_STRING pFileName,
  118. IN SR_EVENT_TYPE EventType,
  119. OUT PFILE_RENAME_INFORMATION * ppRenameInfo OPTIONAL
  120. );
  121. //
  122. // linker commands
  123. //
  124. #ifdef ALLOC_PRAGMA
  125. #pragma alloc_text( PAGE, SrpIsFileStillEligible )
  126. #pragma alloc_text( PAGE, SrHandleEvent )
  127. #pragma alloc_text( PAGE, SrLogEvent )
  128. #pragma alloc_text( PAGE, SrHandleDelete )
  129. #pragma alloc_text( PAGE, SrCreateRestoreLocation )
  130. #pragma alloc_text( PAGE, SrCreateRestoreLocationWorker )
  131. #pragma alloc_text( PAGE, SrHandleFileChange )
  132. #pragma alloc_text( PAGE, SrHandleFileOverwrite )
  133. #pragma alloc_text( PAGE, SrRenameFileIntoStore )
  134. #pragma alloc_text( PAGE, SrTriggerEvents )
  135. #pragma alloc_text( PAGE, SrHandleDirectoryRename )
  136. #pragma alloc_text( PAGE, SrHandleFileRenameOutOfMonitoredSpace )
  137. #pragma alloc_text( PAGE, SrHandleOverwriteFailure )
  138. #pragma alloc_text( PAGE, SrFreeTriggerItem )
  139. #endif // ALLOC_PRAGMA
  140. //
  141. // Private globals.
  142. //
  143. //
  144. // Public globals.
  145. //
  146. //
  147. // Public functions.
  148. //
  149. /***************************************************************************++
  150. Routine Description:
  151. Arguments:
  152. Return Value:
  153. NTSTATUS - Completion status. can return STATUS_PENDING.
  154. --***************************************************************************/
  155. NTSTATUS
  156. SrpIsFileStillEligible (
  157. IN PSR_DEVICE_EXTENSION pExtension,
  158. IN PSR_STREAM_CONTEXT pFileContext,
  159. IN SR_EVENT_TYPE EventType,
  160. OUT PBOOLEAN pMonitorFile
  161. )
  162. {
  163. NTSTATUS status = STATUS_SUCCESS;
  164. PAGED_CODE();
  165. *pMonitorFile = TRUE;
  166. //
  167. // If is is not an overwrite, keep going
  168. //
  169. if (!(EventType & SrEventStreamOverwrite))
  170. {
  171. BOOLEAN HasBeenBackedUp;
  172. //
  173. // it is a match, but have we been told to skip it?
  174. // Since this routine can be called without the caller
  175. // having the activity lock acquired, we acquire it now
  176. //
  177. HasBeenBackedUp = SrHasFileBeenBackedUp( pExtension,
  178. &pFileContext->FileName,
  179. pFileContext->StreamNameLength,
  180. EventType );
  181. if (HasBeenBackedUp)
  182. {
  183. //
  184. // skip it
  185. //
  186. *pMonitorFile = FALSE;
  187. SrTrace( CONTEXT_LOG, ("Sr!SrpIsFileStillEligible:NO: (%p) Event=%06x Fl=%03x Use=%d \"%.*S\"\n",
  188. pFileContext,
  189. EventType,
  190. pFileContext->Flags,
  191. pFileContext->UseCount,
  192. (pFileContext->FileName.Length+
  193. pFileContext->StreamNameLength)/
  194. sizeof(WCHAR),
  195. pFileContext->FileName.Buffer));
  196. //
  197. // we are skipping this event due to the history, should we
  198. // log it regardless ?
  199. //
  200. if (EventType & SR_ALWAYS_LOG_EVENT_TYPES)
  201. {
  202. status = SrLogEvent( pExtension,
  203. EventType,
  204. NULL,
  205. &pFileContext->FileName,
  206. RECORD_AGAINST_STREAM( EventType,
  207. pFileContext->StreamNameLength ),
  208. NULL,
  209. NULL,
  210. 0,
  211. NULL );
  212. }
  213. }
  214. }
  215. return status;
  216. }
  217. /***************************************************************************++
  218. Routine Description:
  219. this is the main entry point for event handling.
  220. anytime an interesting event happens this function is called to see
  221. if this file is interesting to monitor, and then actually handles
  222. the event.
  223. it is possible for this to return STATUS_PENDING, in which case you must
  224. call it again after the fsd see's the event so that it can do
  225. post-processing.
  226. Delete is a case where this 2-step event handling happens.
  227. Arguments:
  228. EventType - the event that just occured
  229. pOverwriteInfo - this is only supplied from an MJ_CREATE, for use in
  230. overwrite optimizations
  231. pFileObject - the fileobject that the event occured on.
  232. pFileContext - Optionall a context structure that is passed in. Most
  233. of the time it will be NULL.
  234. Return Value:
  235. NTSTATUS - Completion status. can return STATUS_PENDING.
  236. --***************************************************************************/
  237. NTSTATUS
  238. SrHandleEvent(
  239. IN PSR_DEVICE_EXTENSION pExtension,
  240. IN SR_EVENT_TYPE EventType,
  241. IN PFILE_OBJECT pFileObject,
  242. IN PSR_STREAM_CONTEXT pFileContext OPTIONAL,
  243. IN OUT PSR_OVERWRITE_INFO pOverwriteInfo OPTIONAL,
  244. IN PUNICODE_STRING pFileName2 OPTIONAL
  245. )
  246. {
  247. NTSTATUS Status = STATUS_SUCCESS;
  248. BOOLEAN releaseLock = FALSE;
  249. BOOLEAN releaseContext = FALSE;
  250. BOOLEAN isStillInteresting;
  251. PAGED_CODE();
  252. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  253. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  254. try {
  255. //
  256. // If a context was not passed in then get it now.
  257. //
  258. if (pFileContext == NULL)
  259. {
  260. //
  261. // Get the context for this operation. Create always calls
  262. // with the context parameter fill in so we can always so
  263. // we are NOT in create from this routine
  264. //
  265. Status = SrGetContext( pExtension,
  266. pFileObject,
  267. EventType,
  268. &pFileContext );
  269. if (!NT_SUCCESS( Status ))
  270. {
  271. leave;
  272. }
  273. //
  274. // We only want to release contexts which we have obtained
  275. // ourselves. Mark that we need to release this one
  276. //
  277. releaseContext = TRUE;
  278. }
  279. VALIDATE_FILENAME( &pFileContext->FileName );
  280. #if DBG
  281. //
  282. // Validate we have the correct directory state with the
  283. // given event.
  284. //
  285. if ((EventType & (SrEventDirectoryCreate |
  286. SrEventDirectoryRename |
  287. SrEventDirectoryDelete |
  288. SrEventMountCreate |
  289. SrEventMountDelete)) != 0)
  290. {
  291. ASSERT(FlagOn(pFileContext->Flags,CTXFL_IsDirectory));
  292. }
  293. if ((EventType & (SrEventFileCreate |
  294. SrEventFileRename |
  295. SrEventFileDelete |
  296. SrEventStreamChange |
  297. SrEventStreamOverwrite |
  298. SrEventStreamCreate)) != 0)
  299. {
  300. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_IsDirectory));
  301. }
  302. #endif
  303. //
  304. // If the file is not interesting, leave now
  305. //
  306. if (!FlagOn(pFileContext->Flags,CTXFL_IsInteresting))
  307. {
  308. leave;
  309. }
  310. //
  311. // This looks to see if the file has already been backed up.
  312. // If so it handles the appropriate logging and returns that
  313. // the file is no longer eligible
  314. //
  315. Status = SrpIsFileStillEligible( pExtension,
  316. pFileContext,
  317. EventType,
  318. &isStillInteresting );
  319. if (!NT_SUCCESS( Status ) || !isStillInteresting)
  320. {
  321. leave;
  322. }
  323. //
  324. // Acquire the activity lock now
  325. //
  326. SrAcquireActivityLockShared( pExtension );
  327. releaseLock = TRUE;
  328. //
  329. // Now that we've got the ActivityLock, make sure that the volume
  330. // hasn't been disabled.
  331. //
  332. if (!SR_LOGGING_ENABLED(pExtension))
  333. {
  334. leave;
  335. }
  336. //
  337. // now mark that we are handled this file. it's IMPORTANT that
  338. // we mark it PRIOR to handling the event, to prevent any potential
  339. // recursion issues with io related to handling this file+event.
  340. //
  341. if (EventType & SR_FULL_BACKUP_EVENT_TYPES)
  342. {
  343. //
  344. // if it's a full backup (or create) we don't care about
  345. // subsequent mods
  346. //
  347. Status = SrMarkFileBackedUp( pExtension,
  348. &pFileContext->FileName,
  349. pFileContext->StreamNameLength,
  350. EventType,
  351. SR_IGNORABLE_EVENT_TYPES );
  352. if (!NT_SUCCESS( Status ))
  353. leave;
  354. }
  355. else if (EventType & SR_ONLY_ONCE_EVENT_TYPES)
  356. {
  357. Status = SrMarkFileBackedUp( pExtension,
  358. &pFileContext->FileName,
  359. pFileContext->StreamNameLength,
  360. EventType,
  361. EventType );
  362. if (!NT_SUCCESS( Status ))
  363. leave;
  364. }
  365. //
  366. // should we short circuit out of here for testing mode?
  367. //
  368. if (global->DontBackup)
  369. leave;
  370. //
  371. // and now handle the event
  372. // a manual copy?
  373. //
  374. if ( FlagOn(EventType,SR_MANUAL_COPY_EVENTS) ||
  375. FlagOn(EventType,SrEventNoOptimization) )
  376. {
  377. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_IsDirectory));
  378. //
  379. // copy the file, a change has occurred
  380. //
  381. Status = SrHandleFileChange( pExtension,
  382. EventType,
  383. pFileObject,
  384. &pFileContext->FileName );
  385. if (!NT_SUCCESS( Status ))
  386. leave;
  387. }
  388. //
  389. // we only handle clearing the FCB on delete's. do it now.
  390. //
  391. else if ((FlagOn(EventType,SrEventFileDelete) ||
  392. FlagOn(EventType,SrEventDirectoryDelete)) &&
  393. !FlagOn(EventType,SrEventSimulatedDelete))
  394. {
  395. ASSERT(!FlagOn( EventType, SrEventNoOptimization ));
  396. //
  397. // handle deletes...
  398. //
  399. Status = SrHandleDelete( pExtension,
  400. pFileObject,
  401. pFileContext );
  402. //
  403. // nothing to do if this fails. it already tried
  404. // to manually copy if it had to.
  405. //
  406. if (!NT_SUCCESS( Status ))
  407. leave;
  408. }
  409. else if (FlagOn(EventType,SrEventStreamOverwrite))
  410. {
  411. ASSERT(IS_VALID_OVERWRITE_INFO(pOverwriteInfo));
  412. //
  413. // handle overwrites
  414. //
  415. Status = SrHandleFileOverwrite( pExtension,
  416. pOverwriteInfo,
  417. pFileContext );
  418. if (!NT_SUCCESS( Status ))
  419. leave;
  420. //
  421. // this should really only fail if we can't open the file.
  422. // this means the caller can't also, so his create will fail
  423. // and we have no reason to copy anything.
  424. //
  425. // if it fails it cleans up after itself.
  426. //
  427. // otherwise SrCreateCompletion checks more error scenarios
  428. //
  429. }
  430. else
  431. {
  432. SR_EVENT_TYPE eventToLog;
  433. //
  434. // If we get to here, log the event
  435. //
  436. if (FlagOn( EventType, SrEventStreamCreate ))
  437. {
  438. eventToLog = SrEventFileCreate;
  439. }
  440. else
  441. {
  442. eventToLog = EventType;
  443. }
  444. Status = SrLogEvent( pExtension,
  445. eventToLog,
  446. pFileObject,
  447. &pFileContext->FileName,
  448. (FlagOn( EventType, SrEventStreamCreate ) ?
  449. pFileContext->StreamNameLength :
  450. 0 ),
  451. NULL,
  452. pFileName2,
  453. 0,
  454. NULL );
  455. if (!NT_SUCCESS( Status ))
  456. leave;
  457. }
  458. ASSERT(Status != STATUS_PENDING);
  459. } finally {
  460. //
  461. // check for unhandled exceptions
  462. //
  463. Status = FinallyUnwind(SrHandleEvent, Status);
  464. //
  465. // Check for any bad errors; If the pFileContext is NULL,
  466. // this error was encountered in SrGetContext which already
  467. // generated the volume error.
  468. //
  469. if (CHECK_FOR_VOLUME_ERROR(Status) && pFileContext != NULL)
  470. {
  471. NTSTATUS TempStatus;
  472. //
  473. // trigger the failure notification to the service
  474. //
  475. TempStatus = SrNotifyVolumeError( pExtension,
  476. &pFileContext->FileName,
  477. Status,
  478. EventType );
  479. CHECK_STATUS(TempStatus);
  480. }
  481. //
  482. // Cleanup state
  483. //
  484. if (releaseLock)
  485. {
  486. SrReleaseActivityLock( pExtension );
  487. }
  488. if (releaseContext && (NULL != pFileContext))
  489. {
  490. SrReleaseContext( pFileContext );
  491. NULLPTR(pFileContext);
  492. }
  493. }
  494. RETURN(Status);
  495. } // SrHandleEvent
  496. /***************************************************************************++
  497. Routine Description:
  498. This function packs a log entry and then logs it.
  499. Arguments:
  500. EventType - the event being handled
  501. pFileObject - the fileobject being handled
  502. pFileName - name of the file
  503. pTempName - name of the temp file if any
  504. pFileName2 - name of the dest file if any
  505. Return Value:
  506. NTSTATUS - Completion status.
  507. --***************************************************************************/
  508. NTSTATUS
  509. SrLogEvent(
  510. IN PSR_DEVICE_EXTENSION pExtension,
  511. IN SR_EVENT_TYPE EventType,
  512. IN PFILE_OBJECT pFileObject OPTIONAL,
  513. IN PUNICODE_STRING pFileName,
  514. IN USHORT FileNameStreamLength,
  515. IN PUNICODE_STRING pTempName OPTIONAL,
  516. IN PUNICODE_STRING pFileName2 OPTIONAL,
  517. IN USHORT FileName2StreamLength OPTIONAL,
  518. IN PUNICODE_STRING pShortName OPTIONAL
  519. )
  520. {
  521. NTSTATUS Status;
  522. PSR_LOG_ENTRY pLogEntry = NULL;
  523. PBYTE pDebugBlob = NULL;
  524. ULONG Attributes = 0xFFFFFFFF; // note:paulmcd: this needs
  525. // to be -1 as this
  526. // communicates something
  527. // special to the service
  528. // when logged
  529. ULONG SecurityDescriptorSize = 0;
  530. PSECURITY_DESCRIPTOR SecurityDescriptorPtr = NULL;
  531. WCHAR ShortFileNameBuffer[SR_SHORT_NAME_CHARS+1];
  532. UNICODE_STRING ShortFileName;
  533. PAGED_CODE();
  534. ASSERT(pFileName != NULL);
  535. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  536. VALIDATE_FILENAME( pFileName );
  537. //
  538. // A stream creation event should be translated to a file create by this
  539. // point.
  540. //
  541. ASSERT( !FlagOn( EventType, SrEventStreamCreate ) );
  542. try
  543. {
  544. Status = STATUS_SUCCESS;
  545. //
  546. // make sure we have the activity lock (we might not if we are
  547. // called from IsFileEligible or SrNotifyVolumeError,
  548. // you get the idea this function need to be callable from anywhere) .
  549. //
  550. SrAcquireActivityLockShared( pExtension );
  551. //
  552. // Verify we are still enabled
  553. //
  554. if (!SR_LOGGING_ENABLED(pExtension))
  555. leave;
  556. //
  557. // should we short circuit out of here for testing mode?
  558. //
  559. if (global->DontBackup)
  560. leave;
  561. //
  562. // mask out only the event code
  563. //
  564. EventType = EventType & SrEventLogMask ;
  565. if (pFileObject == NULL)
  566. goto log_it;
  567. //
  568. // For Attribute change/Directory delete operations, get the attributes.
  569. //
  570. if ( EventType & (SrEventAttribChange |
  571. SrEventDirectoryDelete|
  572. SrEventFileDelete |
  573. SrEventStreamOverwrite|
  574. SrEventStreamChange) )
  575. {
  576. FILE_BASIC_INFORMATION BasicInformation;
  577. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  578. //
  579. // we need to get the file attributes
  580. //
  581. Status = SrQueryInformationFile( pExtension->pTargetDevice,
  582. pFileObject,
  583. &BasicInformation,
  584. sizeof( BasicInformation ),
  585. FileBasicInformation,
  586. NULL );
  587. if (!NT_SUCCESS( Status )) {
  588. leave;
  589. }
  590. Attributes = BasicInformation.FileAttributes;
  591. }
  592. if (EventType & (SrEventAclChange |
  593. SrEventDirectoryDelete|
  594. SrEventStreamOverwrite|
  595. SrEventStreamChange|
  596. SrEventFileDelete) )
  597. {
  598. Status = SrGetAclInformation( pFileObject,
  599. pExtension,
  600. &SecurityDescriptorPtr,
  601. &SecurityDescriptorSize );
  602. if (!NT_SUCCESS(Status)) {
  603. leave;
  604. }
  605. //
  606. // did we get any acl info ? if not and this was an aclchange
  607. // event it was triggered on fat and we need to ignore it
  608. //
  609. if (SecurityDescriptorPtr == NULL &&
  610. (EventType & SrEventAclChange))
  611. {
  612. //
  613. // ignore it
  614. //
  615. SrTrace( NOTIFY, ("sr!SrLogEvent: ignoring acl change on %wZ\n",
  616. pFileName ));
  617. leave;
  618. }
  619. }
  620. //
  621. // Should we get the short name now? Only need it if the name
  622. // is changing via rename or delete. When the name changes, we need
  623. // to save the old name. Sometimes the name is passed in, like in
  624. // the file delete case and the file is already gone when we log
  625. // it, so this function can't get the short name. If we are dealing
  626. // with a file that has a named stream, it can't have a shortname
  627. // so we don't need to check for one.
  628. //
  629. if ( (EventType & (SrEventFileRename |
  630. SrEventDirectoryRename|
  631. SrEventFileDelete |
  632. SrEventDirectoryDelete)) &&
  633. (pShortName == NULL) &&
  634. (FileNameStreamLength == 0))
  635. {
  636. RtlInitEmptyUnicodeString( &ShortFileName,
  637. ShortFileNameBuffer,
  638. sizeof(ShortFileNameBuffer) );
  639. Status = SrGetShortFileName( pExtension,
  640. pFileObject,
  641. &ShortFileName );
  642. if (STATUS_OBJECT_NAME_NOT_FOUND == Status)
  643. {
  644. //
  645. // This file doesn't have a short name, so just leave
  646. // pShortName equal to NULL.
  647. //
  648. Status = STATUS_SUCCESS;
  649. }
  650. else if (!NT_SUCCESS(Status))
  651. {
  652. //
  653. // We hit an unexpected error, so leave.
  654. //
  655. leave;
  656. }
  657. else
  658. {
  659. pShortName = &ShortFileName;
  660. }
  661. }
  662. log_it:
  663. //
  664. // we need to make sure our disk structures are good and logging
  665. // has been started.
  666. //
  667. Status = SrCheckVolume(pExtension, FALSE);
  668. if (!NT_SUCCESS(Status)) {
  669. leave;
  670. }
  671. //
  672. // Debug logging
  673. //
  674. SrTrace( LOG_EVENT, ("sr!SrLogEvent(%03X)%s: %.*ls [%wZ]\n",
  675. EventType,
  676. (FlagOn(EventType, SrEventFileDelete) && pFileObject == NULL) ? "[dummy]" : "",
  677. (pFileName->Length + FileNameStreamLength)/sizeof( WCHAR ),
  678. pFileName->Buffer ? pFileName->Buffer : L"",
  679. pShortName ));
  680. #if DBG
  681. if (EventType & (SrEventFileRename|SrEventDirectoryRename))
  682. {
  683. SrTrace( LOG_EVENT, (" to %.*ls\n",
  684. (pFileName2->Length + FileName2StreamLength)/sizeof(WCHAR),
  685. pFileName2->Buffer ? pFileName2->Buffer : L""));
  686. }
  687. #endif
  688. //
  689. // Log it
  690. //
  691. if (DebugFlagSet( ADD_DEBUG_INFO ))
  692. {
  693. //
  694. // Get the debug info only in Checked build
  695. //
  696. pDebugBlob = SR_ALLOCATE_POOL( PagedPool,
  697. SR_LOG_DEBUG_INFO_SIZE,
  698. SR_DEBUG_BLOB_TAG );
  699. if ( pDebugBlob )
  700. {
  701. SrPackDebugInfo( pDebugBlob, SR_LOG_DEBUG_INFO_SIZE );
  702. }
  703. }
  704. //
  705. // This routine will allocate a log entry of the appropriate size
  706. // and fill it with the necessary data. We are responsible for
  707. // freeing the pLogEntry when we are through with it.
  708. //
  709. Status = SrPackLogEntry( &pLogEntry,
  710. EventType,
  711. Attributes,
  712. 0,
  713. SecurityDescriptorPtr,
  714. SecurityDescriptorSize,
  715. pDebugBlob,
  716. pFileName,
  717. FileNameStreamLength,
  718. pTempName,
  719. pFileName2,
  720. FileName2StreamLength,
  721. pExtension,
  722. pShortName );
  723. if (!NT_SUCCESS( Status ))
  724. {
  725. leave;
  726. }
  727. //
  728. // Get the sequence number and log the entry
  729. //
  730. Status = SrGetNextSeqNumber(&pLogEntry->SequenceNum);
  731. if (!NT_SUCCESS( Status ))
  732. leave;
  733. //
  734. // and write the log entry
  735. //
  736. Status = SrLogWrite( pExtension,
  737. NULL,
  738. pLogEntry );
  739. if (!NT_SUCCESS(Status)) {
  740. leave;
  741. }
  742. }
  743. finally
  744. {
  745. Status = FinallyUnwind(SrLogEvent, Status);
  746. SrReleaseActivityLock( pExtension );
  747. if (pLogEntry)
  748. {
  749. SrFreeLogEntry( pLogEntry );
  750. pLogEntry = NULL;
  751. }
  752. if (SecurityDescriptorPtr)
  753. {
  754. SR_FREE_POOL( SecurityDescriptorPtr, SR_SECURITY_DATA_TAG );
  755. SecurityDescriptorPtr = NULL;
  756. }
  757. if ( pDebugBlob )
  758. {
  759. SR_FREE_POOL(pDebugBlob, SR_DEBUG_BLOB_TAG);
  760. pDebugBlob = NULL;
  761. }
  762. }
  763. RETURN(Status);
  764. }
  765. /***************************************************************************++
  766. Routine Description:
  767. this will perform delete functions prior to the fsd seeing
  768. the mj_cleanup we are in the middle of intercepting.
  769. this means either copyfile (if another handle is open) or renaming the
  770. file into our store and undeleting it.
  771. Arguments:
  772. pExtension - SR's device extension for this volume.
  773. pFileObject - the file that is being deleted. we temporarily
  774. undelete it.
  775. pFileContext - SR's context for this file.
  776. Return Value:
  777. NTSTATUS - Completion status. can return STATUS_PENDING.
  778. --***************************************************************************/
  779. NTSTATUS
  780. SrHandleDelete(
  781. IN PSR_DEVICE_EXTENSION pExtension,
  782. IN PFILE_OBJECT pFileObject,
  783. IN PSR_STREAM_CONTEXT pFileContext
  784. )
  785. {
  786. NTSTATUS Status;
  787. IO_STATUS_BLOCK IoStatusBlock;
  788. OBJECT_ATTRIBUTES ObjectAttributes;
  789. HANDLE NewFileHandle = NULL;
  790. PFILE_OBJECT pNewFileObject = NULL;
  791. BOOLEAN DeleteFile = FALSE;
  792. ULONG NumberOfLinks;
  793. # define OPEN_WITH_DELETE_PENDING_RETRY_COUNT 5
  794. INT openRetryCount;
  795. BOOLEAN IsDirectory;
  796. FILE_DISPOSITION_INFORMATION DeleteInfo;
  797. SRP_NAME_CONTROL OriginalFileName;
  798. PUNICODE_STRING pOriginalFileName;
  799. BOOLEAN cleanupNameCtrl = FALSE;
  800. PAGED_CODE();
  801. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  802. ASSERT(pFileContext != NULL);
  803. ASSERT(pFileContext->FileName.Length > 0);
  804. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  805. ASSERT( ExIsResourceAcquiredShared( &pExtension->ActivityLock ) );
  806. IsDirectory = BooleanFlagOn(pFileContext->Flags,CTXFL_IsDirectory);
  807. try {
  808. if (!IsDirectory)
  809. {
  810. //
  811. // If this is not a directory, we need to get the original name that
  812. // the user used to open this file so that we properly maintain
  813. // the name tunneling that the system provides.
  814. //
  815. SrpInitNameControl( &OriginalFileName );
  816. cleanupNameCtrl = TRUE;
  817. Status = SrpGetFileName( pExtension,
  818. pFileObject,
  819. &OriginalFileName );
  820. if (!NT_SUCCESS( Status ))
  821. leave;
  822. //
  823. // We've got the name that the user originally opened the file
  824. // with. We don't want to do anything to normalize the name
  825. // because to ensure that we don't break name tunneling we want to
  826. // use the same name that the user used to do our rename into the
  827. // store. We have our normalized name for this file in the file
  828. // context and we will use that for all logging purposes.
  829. pOriginalFileName = &(OriginalFileName.Name);
  830. }
  831. else
  832. {
  833. pOriginalFileName = &(pFileContext->FileName);
  834. }
  835. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  836. //
  837. // Setup now for the open we are doing
  838. //
  839. InitializeObjectAttributes( &ObjectAttributes,
  840. pOriginalFileName,
  841. OBJ_KERNEL_HANDLE,
  842. NULL,
  843. NULL );
  844. //
  845. // Someone might delete the file between the time we mark the file
  846. // undeleted and the time we open it. We will try a few times
  847. // before giving up.
  848. //
  849. for (openRetryCount=OPEN_WITH_DELETE_PENDING_RETRY_COUNT;;) {
  850. //
  851. // undelete the file so that i can create a new FILE_OBJECT for this
  852. // file. i need to create a new FILE_OBJECT in order to get a HANDLE.
  853. // i can't get a handle of off this file object as the handle count is 0,
  854. // we are processing this in CLEANUP.
  855. //
  856. DeleteInfo.DeleteFile = FALSE;
  857. Status = SrSetInformationFile( pExtension->pTargetDevice,
  858. pFileObject,
  859. &DeleteInfo,
  860. sizeof(DeleteInfo),
  861. FileDispositionInformation );
  862. if (!NT_SUCCESS( Status ))
  863. leave;
  864. //
  865. // make sure to "re" delete the file later
  866. //
  867. DeleteFile = TRUE;
  868. //
  869. // Open the file.
  870. //
  871. // This open and all operations on this handle will only be seen by
  872. // filters BELOW SR on the filter stack.
  873. //
  874. Status = SrIoCreateFile( &NewFileHandle,
  875. FILE_READ_ATTRIBUTES|SYNCHRONIZE,
  876. &ObjectAttributes,
  877. &IoStatusBlock,
  878. NULL,
  879. FILE_ATTRIBUTE_NORMAL,
  880. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  881. FILE_OPEN_IF, // OPEN_ALWAYS
  882. FILE_SYNCHRONOUS_IO_NONALERT
  883. | FILE_WRITE_THROUGH
  884. | (IsDirectory ? FILE_DIRECTORY_FILE : 0)
  885. | FILE_OPEN_FOR_BACKUP_INTENT,
  886. NULL,
  887. 0, // EaLength
  888. IO_IGNORE_SHARE_ACCESS_CHECK,
  889. pExtension->pTargetDevice );
  890. //
  891. // If we don't get STATUS_DELETE_PENDING just go on
  892. //
  893. if (STATUS_DELETE_PENDING != Status) {
  894. break;
  895. }
  896. //
  897. // If we get STATUS_DELETE_PENDING then someone did a
  898. // SetInformation to mark the file for delete between the time
  899. // we cleared the state and did the open. We are simply going to
  900. // try this again. After too many retries we will fail the
  901. // operation and return.
  902. //
  903. if (--openRetryCount <= 0) {
  904. SrTrace( NOTIFY, ("sr!SrHandleDelete: Tried %d times to open \"%wZ\", status is still STATUS_DELETE_PENDING, giving up\n",
  905. OPEN_WITH_DELETE_PENDING_RETRY_COUNT,
  906. &(pFileContext->FileName)));
  907. leave;
  908. }
  909. }
  910. //
  911. // If we get this error it means we found a reparse point on a file
  912. // and the filter that handles it is gone. We can not copy the file
  913. // so give that up. After pondering it was decided that we should
  914. // not stop logging so we will clear the error and return.
  915. //
  916. if (STATUS_IO_REPARSE_TAG_NOT_HANDLED == Status ||
  917. STATUS_REPARSE_POINT_NOT_RESOLVED == Status)
  918. {
  919. SrTrace( NOTIFY, ("sr!SrHandleDelete: Error %x ignored trying to open \"%wZ\" for copy\n",
  920. Status,
  921. &(pFileContext->FileName) ));
  922. Status = STATUS_SUCCESS;
  923. leave;
  924. }
  925. //
  926. // Any other error should quit
  927. //
  928. if (!NT_SUCCESS( Status ))
  929. leave;
  930. //
  931. // reference the file object
  932. //
  933. Status = ObReferenceObjectByHandle( NewFileHandle,
  934. 0,
  935. *IoFileObjectType,
  936. KernelMode,
  937. (PVOID *) &pNewFileObject,
  938. NULL );
  939. if (!NT_SUCCESS( Status ))
  940. leave;
  941. //
  942. // handle directory delete's
  943. //
  944. if (IsDirectory)
  945. {
  946. //
  947. // Log the event
  948. //
  949. Status = SrLogEvent ( pExtension,
  950. SrEventDirectoryDelete,
  951. pNewFileObject,
  952. &(pFileContext->FileName),
  953. pFileContext->StreamNameLength,
  954. NULL, // pTempName
  955. NULL, // pFileName2
  956. 0,
  957. NULL ); // pShortName
  958. if (!NT_SUCCESS( Status ))
  959. leave;
  960. //
  961. // all done
  962. //
  963. leave;
  964. }
  965. //
  966. // Check to make sure that this is not a delete of a stream. If
  967. // there is no stream name, we may be able to do our rename
  968. // optimization instead of doing a full backup.
  969. //
  970. if (pFileContext->StreamNameLength == 0)
  971. {
  972. //
  973. // how many links does this file have?
  974. //
  975. Status = SrGetNumberOfLinks( pExtension->pTargetDevice,
  976. pNewFileObject,
  977. &NumberOfLinks);
  978. if (!NT_SUCCESS( Status )) {
  979. leave;
  980. }
  981. if (NumberOfLinks <= 1) {
  982. //
  983. // Try to do the rename optimization here to just rename the
  984. // file about to be deleted into our store. If this fails, we will
  985. // try to just do a full backup of the file.
  986. //
  987. // If the rename succeeds, this will also log the action.
  988. //
  989. ASSERT( pOriginalFileName != NULL );
  990. Status = SrRenameFileIntoStore( pExtension,
  991. pNewFileObject,
  992. NewFileHandle,
  993. pOriginalFileName,
  994. &(pFileContext->FileName),
  995. SrEventFileDelete,
  996. NULL );
  997. if (NT_SUCCESS( Status )) {
  998. //
  999. // Mark this file context as uninteresting now that it is
  1000. // renamed into the store.
  1001. //
  1002. SrMakeContextUninteresting( pFileContext );
  1003. //
  1004. // The rename was successful, so we do not need to re-delete
  1005. // the file.
  1006. //
  1007. DeleteFile = FALSE;
  1008. leave;
  1009. }
  1010. }
  1011. }
  1012. //
  1013. // We either couldn't do the rename optimization (because this is a
  1014. // stream delete or the file has hardlinks) or the rename optimization
  1015. // failed, so just do a full copy of the file as if a change happened.
  1016. // Do this AFTER we undelete the file so that the NtCreateFile will
  1017. // work in SrBackupFile. We will re-delete the file when we are
  1018. // finished.
  1019. //
  1020. Status = SrHandleFileChange( pExtension,
  1021. SrEventFileDelete,
  1022. pNewFileObject,
  1023. &(pFileContext->FileName) );
  1024. if (Status == STATUS_FILE_IS_A_DIRECTORY)
  1025. {
  1026. //
  1027. // This is a change to a stream on a directory. For now these
  1028. // operations are not supported, so we will just ignore this
  1029. // operation.
  1030. //
  1031. Status = STATUS_SUCCESS;
  1032. }
  1033. CHECK_STATUS( Status );
  1034. } finally {
  1035. //
  1036. // check for unhandled exceptions
  1037. //
  1038. Status = FinallyUnwind(SrHandleDelete, Status);
  1039. if (DeleteFile)
  1040. {
  1041. NTSTATUS TempStatus;
  1042. //
  1043. // "re" delete the file again, we are all done
  1044. //
  1045. DeleteInfo.DeleteFile = TRUE;
  1046. TempStatus = SrSetInformationFile( pExtension->pTargetDevice,
  1047. pFileObject,
  1048. &DeleteInfo,
  1049. sizeof(DeleteInfo),
  1050. FileDispositionInformation );
  1051. //
  1052. // bug#173339: ntfs apparently will not let you delete an already
  1053. // deleted file. this file could have been deleted again while
  1054. // we were in the middle of processing as we are aborting here
  1055. // due to multiple opens. attempt to undelete it and delete it
  1056. // to prove that this is the case.
  1057. //
  1058. if (TempStatus == STATUS_CANNOT_DELETE ||
  1059. TempStatus == STATUS_DIRECTORY_NOT_EMPTY)
  1060. {
  1061. TempStatus = STATUS_SUCCESS;
  1062. }
  1063. CHECK_STATUS(TempStatus);
  1064. }
  1065. if (pNewFileObject != NULL)
  1066. {
  1067. ObDereferenceObject(pNewFileObject);
  1068. }
  1069. if (NewFileHandle != NULL)
  1070. {
  1071. ZwClose(NewFileHandle);
  1072. }
  1073. if (cleanupNameCtrl)
  1074. {
  1075. SrpCleanupNameControl( &OriginalFileName );
  1076. }
  1077. }
  1078. RETURN(Status);
  1079. } // SrHandleDelete
  1080. /***************************************************************************++
  1081. Routine Description:
  1082. this will create a fresh restore location and current restore point.
  1083. it queue's off to the EX work queue to make sure that we are running in
  1084. the system token context so that we can access protected directories.
  1085. Arguments:
  1086. pNtVolumeName - the nt name of the volume
  1087. Return Value:
  1088. NTSTATUS - Completion status.
  1089. --***************************************************************************/
  1090. NTSTATUS
  1091. SrCreateRestoreLocation(
  1092. IN PSR_DEVICE_EXTENSION pExtension
  1093. )
  1094. {
  1095. NTSTATUS Status;
  1096. SR_WORK_ITEM WorkItem;
  1097. PAGED_CODE();
  1098. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pExtension ) );
  1099. ASSERT(IS_ACTIVITY_LOCK_ACQUIRED_EXCLUSIVE( pExtension ) ||
  1100. IS_LOG_LOCK_ACQUIRED_EXCLUSIVE( pExtension ));
  1101. //
  1102. // We need to create a new restore location
  1103. //
  1104. RtlZeroMemory( &WorkItem, sizeof(SR_WORK_ITEM) );
  1105. WorkItem.Signature = SR_WORK_ITEM_TAG;
  1106. KeInitializeEvent( &WorkItem.Event, NotificationEvent, FALSE );
  1107. WorkItem.Parameter1 = pExtension;
  1108. //
  1109. // Queue this off to another thread so that our thread token is
  1110. // NT AUTHORITY\SYSTEM. This way we can access the system volume info
  1111. // folder .
  1112. //
  1113. ExInitializeWorkItem( &WorkItem.WorkItem,
  1114. &SrCreateRestoreLocationWorker,
  1115. &WorkItem );
  1116. ExQueueWorkItem( &WorkItem.WorkItem,
  1117. CriticalWorkQueue );
  1118. //
  1119. // Wait for it to finish
  1120. //
  1121. Status = KeWaitForSingleObject( &WorkItem.Event,
  1122. Executive,
  1123. KernelMode,
  1124. FALSE,
  1125. NULL );
  1126. ASSERT(NT_SUCCESS(Status));
  1127. //
  1128. // Get the status code
  1129. //
  1130. RETURN( WorkItem.Status );
  1131. }
  1132. /***************************************************************************++
  1133. Routine Description:
  1134. this will create a fresh restore location and current restore point.
  1135. this is run off the EX work queue to make sure that we are running in
  1136. the system token context so that we can access protected directories.
  1137. Arguments:
  1138. pContext - the context (Parameter 1 is the nt name of the volume)
  1139. --***************************************************************************/
  1140. VOID
  1141. SrCreateRestoreLocationWorker(
  1142. IN PSR_WORK_ITEM pWorkItem
  1143. )
  1144. {
  1145. NTSTATUS Status;
  1146. HANDLE Handle = NULL;
  1147. ULONG CharCount;
  1148. PUNICODE_STRING pDirectoryName = NULL;
  1149. IO_STATUS_BLOCK IoStatusBlock;
  1150. OBJECT_ATTRIBUTES ObjectAttributes;
  1151. PSR_DEVICE_EXTENSION pExtension;
  1152. PUNICODE_STRING pVolumeName;
  1153. BOOLEAN DirectoryCreated;
  1154. struct {
  1155. FILE_FS_ATTRIBUTE_INFORMATION Info;
  1156. WCHAR Buffer[ 50 ];
  1157. } FileFsAttrInfoBuffer;
  1158. ASSERT(IS_VALID_WORK_ITEM(pWorkItem));
  1159. PAGED_CODE();
  1160. pExtension = (PSR_DEVICE_EXTENSION) pWorkItem->Parameter1;
  1161. ASSERT( IS_VALID_SR_DEVICE_EXTENSION( pExtension ) );
  1162. pVolumeName = pExtension->pNtVolumeName;
  1163. ASSERT(pVolumeName != NULL);
  1164. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  1165. //
  1166. // grab a filename buffer
  1167. //
  1168. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pDirectoryName);
  1169. if (!NT_SUCCESS( Status )) {
  1170. goto SrCreateRestoreLocationWorker_Cleanup;
  1171. }
  1172. //
  1173. // First make sure the system volume info directory is there
  1174. //
  1175. /* ISSUE-mollybro-2002-04-05 SR cannot use RtlCreateSystemVolumeInformationFolder API to create this directory.
  1176. We explicitly do NOT use the routine RtlCreateSystemVolumeInformationFolder
  1177. here because of a concern about recursion. We are holding the volume's
  1178. activity lock exclusive when we spawn this worker thread to create our
  1179. directories. The Rtl routine will issue IOs to the top of the fs stack
  1180. which could cause filters above us to generate IO on this volume in this
  1181. worker thread that would deadlock with the thread that is waiting for this
  1182. worker thread to finished this initialization work.
  1183. For Longhorn, we should consider how to work around this so that SR can
  1184. use the common RtlCreateSystemVolumeInformationFolder API, but for now we
  1185. will continue to do this ourselves until we can rearchitect things to
  1186. avoid these potential deadlocks.
  1187. */
  1188. CharCount = swprintf( pDirectoryName->Buffer,
  1189. VOLUME_FORMAT SYSTEM_VOLUME_INFORMATION,
  1190. pVolumeName );
  1191. pDirectoryName->Length = (USHORT)CharCount * sizeof(WCHAR);
  1192. InitializeObjectAttributes( &ObjectAttributes,
  1193. pDirectoryName,
  1194. OBJ_KERNEL_HANDLE,
  1195. NULL,
  1196. NULL );
  1197. Status = SrIoCreateFile( &Handle,
  1198. FILE_LIST_DIRECTORY
  1199. |WRITE_OWNER|WRITE_DAC|SYNCHRONIZE,
  1200. &ObjectAttributes,
  1201. &IoStatusBlock,
  1202. NULL,
  1203. FILE_ATTRIBUTE_NORMAL
  1204. | FILE_ATTRIBUTE_HIDDEN
  1205. | FILE_ATTRIBUTE_SYSTEM,
  1206. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1207. FILE_OPEN_IF, // OPEN_ALWAYS
  1208. FILE_DIRECTORY_FILE
  1209. | FILE_WRITE_THROUGH
  1210. | FILE_SYNCHRONOUS_IO_NONALERT
  1211. | FILE_OPEN_FOR_BACKUP_INTENT,
  1212. NULL,
  1213. 0, // EaLength
  1214. 0,
  1215. pExtension->pTargetDevice );
  1216. if (!NT_SUCCESS( Status )) {
  1217. goto SrCreateRestoreLocationWorker_Cleanup;
  1218. }
  1219. DirectoryCreated = (IoStatusBlock.Information != FILE_OPENED);
  1220. //
  1221. // Query for the volume properties to see if this volume supports
  1222. // ACLs or compression.
  1223. //
  1224. Status = ZwQueryVolumeInformationFile( Handle,
  1225. &IoStatusBlock,
  1226. &FileFsAttrInfoBuffer.Info,
  1227. sizeof(FileFsAttrInfoBuffer),
  1228. FileFsAttributeInformation );
  1229. if (!NT_SUCCESS( Status )) {
  1230. goto SrCreateRestoreLocationWorker_Cleanup;
  1231. }
  1232. //
  1233. // If we created the System Volume Information directory and this volume
  1234. // supports ACLs, we now need to put ACLs on this directory.
  1235. //
  1236. if (DirectoryCreated &&
  1237. FlagOn( FileFsAttrInfoBuffer.Info.FileSystemAttributes, FILE_PERSISTENT_ACLS )) {
  1238. SrTrace(NOTIFY, ("sr!srCreateRestoreLocation: setting ACL on sysvolinfo\n"));
  1239. //
  1240. // put the local system dacl on the folder (not so bad if it fails)
  1241. //
  1242. Status = SrSetFileSecurity( Handle, SrAclTypeSystemVolumeInformationDirectory );
  1243. if (!NT_SUCCESS( Status )) {
  1244. goto SrCreateRestoreLocationWorker_Cleanup;
  1245. }
  1246. }
  1247. //
  1248. // We are done with the SVI handle, so close it.
  1249. //
  1250. ZwClose( Handle );
  1251. Handle = NULL;
  1252. //
  1253. // and now create our _restore directory
  1254. //
  1255. CharCount = swprintf( pDirectoryName->Buffer,
  1256. VOLUME_FORMAT RESTORE_LOCATION,
  1257. pVolumeName,
  1258. global->MachineGuid );
  1259. pDirectoryName->Length = (USHORT)CharCount * sizeof(WCHAR);
  1260. InitializeObjectAttributes( &ObjectAttributes,
  1261. pDirectoryName,
  1262. OBJ_KERNEL_HANDLE,
  1263. NULL,
  1264. NULL );
  1265. Status = SrIoCreateFile( &Handle,
  1266. FILE_LIST_DIRECTORY
  1267. |WRITE_OWNER|WRITE_DAC|SYNCHRONIZE,
  1268. &ObjectAttributes,
  1269. &IoStatusBlock,
  1270. NULL,
  1271. FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
  1272. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1273. FILE_OPEN_IF, // OPEN_ALWAYS
  1274. FILE_DIRECTORY_FILE
  1275. | FILE_SYNCHRONOUS_IO_NONALERT
  1276. | FILE_WRITE_THROUGH
  1277. | FILE_OPEN_FOR_BACKUP_INTENT,
  1278. NULL,
  1279. 0, // EaLength
  1280. 0,
  1281. pExtension->pTargetDevice );
  1282. if (!NT_SUCCESS( Status )) {
  1283. goto SrCreateRestoreLocationWorker_Cleanup;
  1284. }
  1285. //
  1286. // Make sure the ACL and compression are set correctly
  1287. //
  1288. if ((IoStatusBlock.Information == FILE_OPENED) ||
  1289. (IoStatusBlock.Information == FILE_CREATED)) {
  1290. USHORT CompressionState;
  1291. if (FileFsAttrInfoBuffer.Info.FileSystemAttributes & FILE_PERSISTENT_ACLS) {
  1292. SrTrace(NOTIFY, ("sr!srCreateRestoreLocation: setting ACL on _restore{}\n"));
  1293. //
  1294. // This volume supports ACLS, so set the proper ACLs on the _restore
  1295. // directory.
  1296. //
  1297. Status = SrSetFileSecurity( Handle, SrAclTypeRestoreDirectoryAndFiles );
  1298. if (!NT_SUCCESS( Status )) {
  1299. goto SrCreateRestoreLocationWorker_Cleanup;
  1300. }
  1301. }
  1302. if (FileFsAttrInfoBuffer.Info.FileSystemAttributes & FILE_FILE_COMPRESSION) {
  1303. //
  1304. // Ensure that this folder is NOT marked for compression.
  1305. // This inherits down to files created later in this folder. This
  1306. // should speed up our writes for copies and decrease the chance
  1307. // of stack overflow while we are doing our backup operations.
  1308. //
  1309. // The service will come along and compress the file in the
  1310. // directory at a later time.
  1311. //
  1312. CompressionState = COMPRESSION_FORMAT_NONE;
  1313. Status = ZwFsControlFile( Handle,
  1314. NULL, // Event
  1315. NULL, // ApcRoutine
  1316. NULL, // ApcContext
  1317. &IoStatusBlock,
  1318. FSCTL_SET_COMPRESSION,
  1319. &CompressionState,
  1320. sizeof(CompressionState),
  1321. NULL, // OutputBuffer
  1322. 0 );
  1323. ASSERT(Status != STATUS_PENDING);
  1324. CHECK_STATUS(Status);
  1325. }
  1326. }
  1327. //
  1328. // All done (just needed to create it)
  1329. //
  1330. ZwClose(Handle);
  1331. Handle = NULL;
  1332. //
  1333. // Now we need to create our current restore point sub directory
  1334. //
  1335. //
  1336. // We don't need to acquire a lock to read the current restore location
  1337. // because whoever scheduled this workitem already has the ActivityLock
  1338. // and will not release it until we return. This will prevent the
  1339. // value from changing.
  1340. //
  1341. CharCount = swprintf( &pDirectoryName->Buffer[pDirectoryName->Length/sizeof(WCHAR)],
  1342. L"\\" RESTORE_POINT_PREFIX L"%d",
  1343. global->FileConfig.CurrentRestoreNumber );
  1344. pDirectoryName->Length += (USHORT)CharCount * sizeof(WCHAR);
  1345. InitializeObjectAttributes( &ObjectAttributes,
  1346. pDirectoryName,
  1347. OBJ_KERNEL_HANDLE,
  1348. NULL,
  1349. NULL );
  1350. Status = SrIoCreateFile( &Handle,
  1351. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1352. &ObjectAttributes,
  1353. &IoStatusBlock,
  1354. NULL,
  1355. FILE_ATTRIBUTE_NORMAL,
  1356. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1357. FILE_OPEN_IF, // OPEN_ALWAYS
  1358. FILE_DIRECTORY_FILE
  1359. | FILE_WRITE_THROUGH
  1360. | FILE_SYNCHRONOUS_IO_NONALERT
  1361. | FILE_OPEN_FOR_BACKUP_INTENT,
  1362. NULL,
  1363. 0, // EaLength
  1364. 0,
  1365. pExtension->pTargetDevice );
  1366. if (!NT_SUCCESS( Status )) {
  1367. goto SrCreateRestoreLocationWorker_Cleanup;
  1368. }
  1369. //
  1370. // Again, if we created this directory, we need to set the ACL on it.
  1371. //
  1372. if (IoStatusBlock.Information != FILE_OPENED) {
  1373. if (FileFsAttrInfoBuffer.Info.FileSystemAttributes & FILE_PERSISTENT_ACLS) {
  1374. SrTrace(NOTIFY, ("sr!srCreateRestoreLocation: setting ACL on RP\n"));
  1375. //
  1376. // This volume supports ACLS, so set the proper ACLs on the _restore
  1377. // directory.
  1378. //
  1379. Status = SrSetFileSecurity( Handle, SrAclTypeRPDirectory );
  1380. if (!NT_SUCCESS( Status )) {
  1381. goto SrCreateRestoreLocationWorker_Cleanup;
  1382. }
  1383. }
  1384. }
  1385. //
  1386. // all done (just needed to create it) no acl's on this subfolder,
  1387. // it inherit from the parent (everyone=full control)
  1388. //
  1389. ZwClose(Handle);
  1390. Handle = NULL;
  1391. SrTrace( NOTIFY, ("SR!SrCreateRestoreLocationWorker(%wZ)\n",
  1392. pVolumeName ));
  1393. SrCreateRestoreLocationWorker_Cleanup:
  1394. if (Handle != NULL)
  1395. {
  1396. ZwClose(Handle);
  1397. Handle = NULL;
  1398. }
  1399. if (pDirectoryName != NULL)
  1400. {
  1401. SrFreeFileNameBuffer(pDirectoryName);
  1402. pDirectoryName = NULL;
  1403. }
  1404. pWorkItem->Status = Status;
  1405. KeSetEvent(&pWorkItem->Event, 0, FALSE);
  1406. } // SrCreateRestoreLocationWorker
  1407. /***************************************************************************++
  1408. Routine Description:
  1409. this handles any change event to the file that requires the file to be
  1410. copied. it generates the dest file name then copies the source file to
  1411. the dest file.
  1412. Arguments:
  1413. EventType - the event that occurred
  1414. pFileObject - the file object that just changed
  1415. pFileName - the name of the file that changed
  1416. Return Value:
  1417. NTSTATUS - Completion status.
  1418. --***************************************************************************/
  1419. NTSTATUS
  1420. SrHandleFileChange(
  1421. IN PSR_DEVICE_EXTENSION pExtension,
  1422. IN SR_EVENT_TYPE EventType,
  1423. IN PFILE_OBJECT pFileObject,
  1424. IN PUNICODE_STRING pFileName
  1425. )
  1426. {
  1427. NTSTATUS Status;
  1428. PUNICODE_STRING pDestFileName = NULL;
  1429. PAGED_CODE();
  1430. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  1431. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  1432. ASSERT(pFileName != NULL);
  1433. ASSERT( ExIsResourceAcquiredShared( &pExtension->ActivityLock ) );
  1434. //
  1435. // we need to make sure our disk structures are good and logging
  1436. // has been started.
  1437. //
  1438. Status = SrCheckVolume(pExtension, FALSE);
  1439. if (!NT_SUCCESS( Status ))
  1440. goto end;
  1441. //
  1442. // get the name of the destination file for this guy
  1443. //
  1444. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pDestFileName);
  1445. if (!NT_SUCCESS( Status ))
  1446. goto end;
  1447. Status = SrGetDestFileName( pExtension,
  1448. pFileName,
  1449. pDestFileName );
  1450. if (!NT_SUCCESS_NO_DBGBREAK( Status ))
  1451. goto end;
  1452. Status = SrBackupFileAndLog( pExtension,
  1453. EventType,
  1454. pFileObject,
  1455. pFileName,
  1456. pDestFileName,
  1457. TRUE );
  1458. if (!NT_SUCCESS_NO_DBGBREAK( Status ))
  1459. goto end;
  1460. end:
  1461. if (pDestFileName != NULL)
  1462. {
  1463. SrFreeFileNameBuffer(pDestFileName);
  1464. pDestFileName = NULL;
  1465. }
  1466. #if DBG
  1467. //
  1468. // When dealing with modifications to streams on directories, this
  1469. // is a valid error code to return.
  1470. //
  1471. if (Status == STATUS_FILE_IS_A_DIRECTORY)
  1472. {
  1473. return Status;
  1474. }
  1475. #endif
  1476. RETURN(Status);
  1477. } // SrHandleFileChange
  1478. /***************************************************************************++
  1479. Routine Description:
  1480. this will perform the optimization for overwrites. this consists of a
  1481. rename and empty file create so that the caller will be allowed to
  1482. overwrite like normal.
  1483. // NOTE: MollyBro 7-Dec-2000
  1484. //
  1485. // We cannot use the RENAME optimization here because we create
  1486. // the following window --
  1487. // Between the time we rename the file into our store and the
  1488. // time we create the stub file to take its place, there is no
  1489. // file by this name in the directory. Another request
  1490. // could come in and try to create this same file with the
  1491. // FILE_CREATE flag set. This operation would then succeed
  1492. // when it would have failed had SR not been doing its work.
  1493. //
  1494. // This is likely to break apps in hard-to-repeat ways, so just to
  1495. // be safe, we will do a full backup here.
  1496. //
  1497. Arguments:
  1498. pFileObject - the file object that just changed
  1499. pFileName - the name of the file
  1500. Return Value:
  1501. NTSTATUS - Completion status.
  1502. see comments above.
  1503. --***************************************************************************/
  1504. NTSTATUS
  1505. SrHandleFileOverwrite(
  1506. IN PSR_DEVICE_EXTENSION pExtension,
  1507. IN OUT PSR_OVERWRITE_INFO pOverwriteInfo,
  1508. IN PSR_STREAM_CONTEXT pFileContext
  1509. )
  1510. {
  1511. NTSTATUS Status;
  1512. PIO_STACK_LOCATION pIrpSp;
  1513. OBJECT_ATTRIBUTES ObjectAttributes;
  1514. HANDLE FileHandle = NULL;
  1515. PFILE_OBJECT pFileObject = NULL;
  1516. IO_STATUS_BLOCK IoStatusBlock;
  1517. ULONG DesiredAccess;
  1518. ULONG DesiredAttributes;
  1519. ULONG CreateOptions;
  1520. BOOLEAN SharingViolation = FALSE;
  1521. BOOLEAN MarkFile = FALSE;
  1522. BOOLEAN MountInPath = FALSE;
  1523. PUNICODE_STRING pTempFileName = NULL;
  1524. HANDLE TempFileHandle = NULL;
  1525. PUNICODE_STRING pFileName;
  1526. #if 0 /* NO_RENAME --- See note in function header block */
  1527. BOOLEAN RenamedFile = FALSE;
  1528. PFILE_RENAME_INFORMATION pRenameInformation = NULL;
  1529. #endif
  1530. PAGED_CODE();
  1531. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  1532. ASSERT(IS_VALID_OVERWRITE_INFO(pOverwriteInfo));
  1533. ASSERT(IS_VALID_IRP(pOverwriteInfo->pIrp));
  1534. ASSERT(pFileContext != NULL);
  1535. pFileName = &(pFileContext->FileName);
  1536. ASSERT( ExIsResourceAcquiredShared( &pExtension->ActivityLock ) );
  1537. try {
  1538. pIrpSp = IoGetCurrentIrpStackLocation(pOverwriteInfo->pIrp);
  1539. //
  1540. // we are now all done with the inputs, clear the outputs
  1541. //
  1542. RtlZeroMemory(pOverwriteInfo, sizeof(*pOverwriteInfo));
  1543. pOverwriteInfo->Signature = SR_OVERWRITE_INFO_TAG;
  1544. Status = STATUS_SUCCESS;
  1545. //
  1546. // we need to use a combination of the caller's requested desired
  1547. // access and the minimum required desired access to overwite a file.
  1548. //
  1549. // this way we gaurantee that if this NtCreateFile works, than the
  1550. // callers MJ_CREATE would also work. we absolutely need to avoid any
  1551. // possibilty of the driver's NtCreateFile working in a scenario that
  1552. // the user-mode MJ_CREATE will subsequently fail. if that were to
  1553. // happen, we would have overwritten the file when normally it would
  1554. // have failed, thus changing the behaviour of the os. very bad.
  1555. //
  1556. //
  1557. // start with the callers access requested
  1558. //
  1559. if (pIrpSp->Parameters.Create.SecurityContext == NULL)
  1560. {
  1561. pOverwriteInfo->IgnoredFile = TRUE;
  1562. Status = STATUS_SUCCESS;
  1563. leave;
  1564. }
  1565. DesiredAccess = pIrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  1566. //
  1567. // now add on FILE_GENERIC_WRITE .
  1568. //
  1569. // FILE_GENERIC_WRITE is the least amount of access you must be able to
  1570. // get to overwrite a file. you don't have to ask for it, but you
  1571. // must have it. that is.. you can ask for READ access with overwrite
  1572. // specified, and the file will be overwritten, only if you had
  1573. // FILE_GENERIC_WRITE in addition to the read access
  1574. //
  1575. DesiredAccess |= FILE_GENERIC_WRITE;
  1576. //
  1577. // BUGBUG: the check for matching attributes only happens if OVERWRITE is
  1578. // set. we might need to manually check this . paulmcd 5/3/2000
  1579. //
  1580. DesiredAttributes = pIrpSp->Parameters.Create.FileAttributes;
  1581. //
  1582. // pass them back so that create can fix it if it fails really bad
  1583. //
  1584. pOverwriteInfo->CreateFileAttributes = DesiredAttributes;
  1585. //
  1586. // first open the file to see if there is one there
  1587. //
  1588. InitializeObjectAttributes( &ObjectAttributes,
  1589. pFileName,
  1590. OBJ_KERNEL_HANDLE // don't let usermode trash myhandle
  1591. |OBJ_FORCE_ACCESS_CHECK, // force ACL checking
  1592. NULL, // Root Directory
  1593. NULL );
  1594. //
  1595. // Setup the CreateOptions. Always use FILE_SYNCHRONOUS_IO_NONALERT,
  1596. // but propagate FILE_OPEN_FOR_BACKUP_INTENT if that is set in the
  1597. // FullCreateOptions.
  1598. //
  1599. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT | FILE_WRITE_THROUGH;
  1600. if (FlagOn( pIrpSp->Parameters.Create.SecurityContext->FullCreateOptions,
  1601. FILE_OPEN_FOR_BACKUP_INTENT )) {
  1602. SetFlag( CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT );
  1603. }
  1604. #if 0 /* NO_RENAME --- See note in function header block */
  1605. //
  1606. // notice the ShareAccess is set to 0. we want this file exclusive.
  1607. // if there are any other opens.. this optimization will fail and
  1608. // we'll copy the file manually.
  1609. //
  1610. //
  1611. // BUGBUG: paulmcd 5/31 . what if this is an EFS file being OpenRaw'd
  1612. // it doesn't require FILE_GENERIC_WRITE .
  1613. //
  1614. Status = ZwCreateFile( &FileHandle,
  1615. DesiredAccess,
  1616. &ObjectAttributes,
  1617. &IoStatusBlock,
  1618. NULL, // AllocationSize
  1619. DesiredAttributes,
  1620. 0, // ShareAccess
  1621. FILE_OPEN, // OPEN_EXISTING
  1622. CreateOptions,
  1623. NULL,
  1624. 0 ); // EaLength
  1625. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1626. {
  1627. //
  1628. // this is ok.. the file that is being overwritten (at least
  1629. // CREATE_ALWAYS) doesn't exist. nothing to backup.
  1630. //
  1631. //
  1632. // we log this in SrCreateCompletion so that we know the create
  1633. // worked first
  1634. //
  1635. Status = STATUS_SUCCESS;
  1636. leave;
  1637. }
  1638. else if (Status == STATUS_SHARING_VIOLATION)
  1639. {
  1640. SharingViolation = TRUE;
  1641. Status = STATUS_SUCCESS;
  1642. }
  1643. else if (Status == STATUS_OBJECT_NAME_INVALID ||
  1644. Status == STATUS_OBJECT_PATH_INVALID ||
  1645. Status == STATUS_OBJECT_PATH_NOT_FOUND )
  1646. {
  1647. //
  1648. // the file is not a valid filename. no overwrite will happen.
  1649. //
  1650. pOverwriteInfo->IgnoredFile = TRUE;
  1651. Status = STATUS_SUCCESS;
  1652. leave;
  1653. }
  1654. else if (NT_SUCCESS_NO_DBGBREAK(Status) == FALSE)
  1655. {
  1656. //
  1657. // we failed opening it. this means the caller will fail opening it
  1658. // that's ok.
  1659. //
  1660. pOverwriteInfo->IgnoredFile = TRUE;
  1661. Status = STATUS_SUCCESS;
  1662. leave;
  1663. }
  1664. #endif /* NO_RENAME */
  1665. //
  1666. // at this point it's not a NEW file create that is going to work,
  1667. // double check that we should actually be interested in the MODIFY
  1668. // of this file
  1669. //
  1670. {
  1671. BOOLEAN HasFileBeenBackedUp;
  1672. HasFileBeenBackedUp = SrHasFileBeenBackedUp( pExtension,
  1673. pFileName,
  1674. pFileContext->StreamNameLength,
  1675. SrEventStreamChange );
  1676. if (HasFileBeenBackedUp)
  1677. {
  1678. //
  1679. // we don't care . skip it
  1680. //
  1681. Status = STATUS_SUCCESS;
  1682. leave;
  1683. }
  1684. }
  1685. #if 0 /* NO_RENAME */
  1686. //
  1687. // otherwise resume processing
  1688. //
  1689. if (SharingViolation)
  1690. {
  1691. //
  1692. // copy the file manually, we got a sharing violation, someone else
  1693. // has this file open. try to open it again allowing for sharing.
  1694. //
  1695. #endif
  1696. //
  1697. // Note: In this path, if the operation will be successful, the name
  1698. // we have should be a file. It is possible to get a directory down
  1699. // this path if the directory name could be an interesting file name
  1700. // (like c:\test.exe\) and the user has opened the directory for
  1701. // OVERWRITE, OVERWRITE_IF, or SUPERCEDE. The user's open will fail,
  1702. // so we just want to catch this problem as soon as possible by adding
  1703. // the FILE_NON_DIRECTORY_FILE CreateOption to avoid doing
  1704. // unnecessary work.
  1705. //
  1706. Status = SrIoCreateFile( &FileHandle,
  1707. DesiredAccess,
  1708. &ObjectAttributes,
  1709. &IoStatusBlock,
  1710. NULL, // AllocationSize
  1711. DesiredAttributes,
  1712. pIrpSp->Parameters.Create.ShareAccess,// ShareAccess
  1713. FILE_OPEN, // OPEN_EXISTING
  1714. CreateOptions | FILE_NON_DIRECTORY_FILE,
  1715. NULL,
  1716. 0, // EaLength
  1717. 0,
  1718. pExtension->pTargetDevice );
  1719. // NO_RENAME
  1720. // NOTE: We have to add some more error handling here since we
  1721. // are not doing the ZwCreateFile above.
  1722. //
  1723. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1724. {
  1725. //
  1726. // this is ok.. the file that is being overwritten (at least
  1727. // CREATE_ALWAYS) doesn't exist. nothing to backup.
  1728. //
  1729. //
  1730. // we log this in SrCreateCompletion so that we know the create
  1731. // worked first
  1732. //
  1733. Status = STATUS_SUCCESS;
  1734. leave;
  1735. }
  1736. else if (Status == STATUS_SHARING_VIOLATION)
  1737. {
  1738. //
  1739. // Caller can't open this file either, so don't worry about
  1740. // this file.
  1741. //
  1742. pOverwriteInfo->IgnoredFile = TRUE;
  1743. Status = STATUS_SUCCESS;
  1744. leave;
  1745. #if 0 /* NO_RENAME */
  1746. SharingViolation = TRUE;
  1747. Status = STATUS_SUCCESS;
  1748. #endif /* NO_RENAME */
  1749. }
  1750. #if 0 /* NO_RENAME */
  1751. else if (Status == STATUS_OBJECT_NAME_INVALID ||
  1752. Status == STATUS_OBJECT_PATH_INVALID ||
  1753. Status == STATUS_OBJECT_PATH_NOT_FOUND )
  1754. {
  1755. //
  1756. // the file is not a valid filename. no overwrite will happen.
  1757. //
  1758. pOverwriteInfo->IgnoredFile = TRUE;
  1759. Status = STATUS_SUCCESS;
  1760. leave;
  1761. }
  1762. #endif /* NO_RENAME */
  1763. else if (!NT_SUCCESS_NO_DBGBREAK(Status))
  1764. {
  1765. //
  1766. // we failed opening it. this means the caller will fail opening it
  1767. // that's ok.
  1768. //
  1769. pOverwriteInfo->IgnoredFile = TRUE;
  1770. Status = STATUS_SUCCESS;
  1771. leave;
  1772. }
  1773. //
  1774. // otherwise we are able to open it (so is the caller).
  1775. //
  1776. // Go ahead and copy off the file.
  1777. //
  1778. //
  1779. // reference the file object
  1780. //
  1781. Status = ObReferenceObjectByHandle( FileHandle,
  1782. 0,
  1783. *IoFileObjectType,
  1784. KernelMode,
  1785. (PVOID *) &pFileObject,
  1786. NULL );
  1787. if (!NT_SUCCESS( Status ))
  1788. leave;
  1789. //
  1790. // check for reparse/mount points
  1791. //
  1792. Status = SrCheckForMountsInPath( pExtension,
  1793. pFileObject,
  1794. &MountInPath );
  1795. if (!NT_SUCCESS( Status ))
  1796. leave;
  1797. //
  1798. // do we have a mount in the path
  1799. //
  1800. if (MountInPath)
  1801. {
  1802. //
  1803. // ignore this, we should reparse and come back.
  1804. //
  1805. pOverwriteInfo->IgnoredFile = TRUE;
  1806. Status = STATUS_SUCCESS;
  1807. leave;
  1808. }
  1809. Status = SrHandleFileChange( pExtension,
  1810. SrEventStreamChange,
  1811. pFileObject,
  1812. pFileName );
  1813. if (!NT_SUCCESS( Status ))
  1814. leave;
  1815. //
  1816. // we've handled this file
  1817. //
  1818. MarkFile = TRUE;
  1819. //
  1820. // let the caller know we copied the file
  1821. //
  1822. pOverwriteInfo->CopiedFile = TRUE;
  1823. Status = STATUS_SUCCESS;
  1824. leave;
  1825. #if 0 /* NO_RENAME */
  1826. }
  1827. //
  1828. // if the open succeeded, we have the right access
  1829. //
  1830. //
  1831. // reference the file object
  1832. //
  1833. Status = ObReferenceObjectByHandle( FileHandle,
  1834. 0,
  1835. *IoFileObjectType,
  1836. KernelMode,
  1837. (PVOID *) &pFileObject,
  1838. NULL );
  1839. if (!NT_SUCCESS( Status ))
  1840. leave;
  1841. //
  1842. // check for reparse/mount points
  1843. //
  1844. Status = SrCheckForMountsInPath( pExtension,
  1845. pFileObject,
  1846. &MountInPath );
  1847. if (!NT_SUCCESS( Status ))
  1848. leave;
  1849. //
  1850. // do we have a new name?
  1851. //
  1852. if (MountInPath)
  1853. {
  1854. //
  1855. // ignore this, we should reparse and come back.
  1856. //
  1857. pOverwriteInfo->IgnoredFile = TRUE;
  1858. Status = STATUS_SUCCESS;
  1859. leave;
  1860. }
  1861. //
  1862. // this get's complicated. when we rename this file out of this
  1863. // directory, the directory could temporarily be empty. this is bad
  1864. // as if sr.sys was never there, that directory would never have
  1865. // been empty. empty directories can be deleted. bug#163292 shows
  1866. // an example where we changed this semantic and broke somebody.
  1867. //
  1868. // we need to preserve the fact that this is a non-empty directory
  1869. //
  1870. // create an empty, delete_on_close, dummy file that will exist
  1871. // until we are done to keep the directory non-empty.
  1872. //
  1873. //
  1874. // first find the filename part in the full path
  1875. //
  1876. Status = SrFindCharReverse( pFileName->Buffer,
  1877. pFileName->Length,
  1878. L'\\',
  1879. &pToken,
  1880. &TokenLength );
  1881. if (!NT_SUCCESS( Status ))
  1882. leave;
  1883. Status = SrAllocateFileNameBuffer( pFileName->Length
  1884. - TokenLength
  1885. + SR_UNIQUE_TEMP_FILE_LENGTH,
  1886. &pTempFileName );
  1887. if (!NT_SUCCESS( Status ))
  1888. leave;
  1889. //
  1890. // and put our unique filename on there
  1891. //
  1892. pTempFileName->Length = pFileName->Length - (USHORT)TokenLength;
  1893. RtlCopyMemory( pTempFileName->Buffer,
  1894. pFileName->Buffer,
  1895. pTempFileName->Length );
  1896. RtlCopyMemory( &pTempFileName->Buffer[pTempFileName->Length/sizeof(WCHAR)],
  1897. SR_UNIQUE_TEMP_FILE,
  1898. SR_UNIQUE_TEMP_FILE_LENGTH );
  1899. pTempFileName->Length += SR_UNIQUE_TEMP_FILE_LENGTH;
  1900. pTempFileName->Buffer[pTempFileName->Length/sizeof(WCHAR)] = UNICODE_NULL;
  1901. InitializeObjectAttributes( &ObjectAttributes,
  1902. pTempFileName,
  1903. OBJ_KERNEL_HANDLE,
  1904. NULL,
  1905. NULL );
  1906. Status = ZwCreateFile( &TempFileHandle,
  1907. FILE_GENERIC_WRITE|DELETE,
  1908. &ObjectAttributes,
  1909. &IoStatusBlock,
  1910. NULL, // AllocationSize
  1911. FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
  1912. 0, // ShareAccess
  1913. FILE_CREATE, // CREATE_NEW
  1914. FILE_SYNCHRONOUS_IO_NONALERT|FILE_DELETE_ON_CLOSE,
  1915. NULL,
  1916. 0 ); // EaLength
  1917. if (Status == STATUS_OBJECT_NAME_COLLISION)
  1918. {
  1919. //
  1920. // there is already a file by this name. bummer. continue
  1921. // hoping that this file is not deleted so we get to maintain
  1922. // our non-empty directory status. this is ok and even normal
  1923. // if 2 overwrites are happening at the same time in the same
  1924. // directory.
  1925. //
  1926. //
  1927. // BUGBUG : paulmcd: 12/2000 : we need to fix this window also
  1928. // if we put back the rename opt code. we can't let this dummy
  1929. // file go away
  1930. //
  1931. Status = STATUS_SUCCESS;
  1932. }
  1933. else if (!NT_SUCCESS( Status ))
  1934. leave;
  1935. //
  1936. // now rename the file to the restore location
  1937. //
  1938. Status = SrRenameFileIntoStore( pExtension,
  1939. pFileObject,
  1940. FileHandle,
  1941. pFileName,
  1942. SrEventStreamOverwrite,
  1943. &pRenameInformation );
  1944. if (!NT_SUCCESS( Status ))
  1945. leave;
  1946. ASSERT(pRenameInformation != NULL);
  1947. //
  1948. // we have just renamed the file
  1949. //
  1950. RenamedFile = TRUE;
  1951. //
  1952. // and now create an empty dummy file that matches the original file
  1953. // attribs and security descriptor.
  1954. //
  1955. // we reuse SrBackupFile in this case for code-reuse. we reverse the flow
  1956. // and copy from the restore location into the volume, telling it not to
  1957. // copy any data streams.
  1958. //
  1959. RenamedFileName.Length = (USHORT)pRenameInformation->FileNameLength;
  1960. RenamedFileName.MaximumLength = (USHORT)pRenameInformation->FileNameLength;
  1961. RenamedFileName.Buffer = &pRenameInformation->FileName[0];
  1962. //
  1963. // ignore JUST this create+acl change, it's our dummy backupfile
  1964. //
  1965. Status = SrMarkFileBackedUp( pExtension,
  1966. pFileName,
  1967. SrEventFileCreate|SrEventAclChange );
  1968. if (!NT_SUCCESS( Status ))
  1969. leave;
  1970. Status = SrBackupFileAndLog( pExtension,
  1971. SrEventInvalid, // don't log this
  1972. pFileObject,
  1973. &RenamedFileName,
  1974. pFileName,
  1975. FALSE );
  1976. if (!NT_SUCCESS( Status ))
  1977. leave;
  1978. //
  1979. // restore the history back to before we added CREATE's (above just prior
  1980. // to the BackupFileKernelMode) .
  1981. //
  1982. Status = SrResetBackupHistory(pExtension, pFileName, RecordedEvents);
  1983. if (!NT_SUCCESS( Status ))
  1984. leave;
  1985. //
  1986. // we've handled this file
  1987. //
  1988. MarkFile = TRUE;
  1989. //
  1990. // let the caller know we renamed the file
  1991. //
  1992. pOverwriteInfo->RenamedFile = TRUE;
  1993. pOverwriteInfo->pRenameInformation = pRenameInformation;
  1994. pRenameInformation = NULL;
  1995. Status = STATUS_SUCCESS;
  1996. #endif /* NO_RENAME */
  1997. } finally {
  1998. //
  1999. // check for unhandled exceptions
  2000. //
  2001. Status = FinallyUnwind(SrHandleFileOverwrite, Status);
  2002. if (MarkFile)
  2003. {
  2004. NTSTATUS TempStatus;
  2005. ASSERT(NT_SUCCESS(Status));
  2006. //
  2007. // we have to mark that we handled the MODIFY, in order to ignore
  2008. // all subsequent MODIFY's
  2009. //
  2010. TempStatus = SrMarkFileBackedUp( pExtension,
  2011. pFileName,
  2012. pFileContext->StreamNameLength,
  2013. SrEventStreamChange,
  2014. SR_IGNORABLE_EVENT_TYPES );
  2015. CHECK_STATUS(TempStatus);
  2016. }
  2017. #if 0 /* NO_RENAME --- See note in function header block */
  2018. //
  2019. // did we fail AFTER renaming the file?
  2020. //
  2021. if (!NT_SUCCESS( Status ) && RenamedFile)
  2022. {
  2023. NTSTATUS TempStatus;
  2024. //
  2025. // put the file back! we might have to overwrite if our
  2026. // dummy file is there. we want to force this file back
  2027. // to it's old name.
  2028. //
  2029. ASSERT(pRenameInformation != NULL);
  2030. pRenameInformation->ReplaceIfExists = TRUE;
  2031. pRenameInformation->RootDirectory = NULL;
  2032. pRenameInformation->FileNameLength = pFileName->Length;
  2033. ASSERT(pFileName->Length <= SR_MAX_FILENAME_LENGTH);
  2034. RtlCopyMemory( &pRenameInformation->FileName[0],
  2035. pFileName->Buffer,
  2036. pFileName->Length );
  2037. TempStatus = ZwSetInformationFile( FileHandle,
  2038. &IoStatusBlock,
  2039. pRenameInformation,
  2040. SR_RENAME_BUFFER_LENGTH,
  2041. FileRenameInformation );
  2042. //
  2043. // we did the best we could!
  2044. //
  2045. ASSERTMSG("sr!SrHandleFileOverwrite: couldn't fix the failed rename, file lost!", NT_SUCCESS_NO_DBGBREAK(TempStatus));
  2046. }
  2047. if (pRenameInformation != NULL)
  2048. {
  2049. SR_FREE_POOL(pRenameInformation, SR_RENAME_BUFFER_TAG);
  2050. pRenameInformation = NULL;
  2051. }
  2052. #endif
  2053. if (pFileObject != NULL)
  2054. {
  2055. ObDereferenceObject(pFileObject);
  2056. pFileObject = NULL;
  2057. }
  2058. if (FileHandle != NULL)
  2059. {
  2060. ZwClose(FileHandle);
  2061. FileHandle = NULL;
  2062. }
  2063. if (TempFileHandle != NULL)
  2064. {
  2065. ZwClose(TempFileHandle);
  2066. TempFileHandle = NULL;
  2067. }
  2068. if (pTempFileName != NULL)
  2069. {
  2070. SrFreeFileNameBuffer(pTempFileName);
  2071. pTempFileName = NULL;
  2072. }
  2073. } // finally
  2074. RETURN(Status);
  2075. } // SrHandleFileOverwrite
  2076. /***************************************************************************++
  2077. Routine Description:
  2078. this will rename the file into the restore location.
  2079. this is for delete optimizations.
  2080. Arguments:
  2081. pExtension - SR's device extension for the volume on which this
  2082. file resides.
  2083. pFileObject - the file object to set the info on (created using
  2084. IoCreateFileSpecifyDeviceObjectHint).
  2085. FileHandle - a handle for use in queries. (created using
  2086. IoCreateFileSpecifyDeviceObjectHint).
  2087. pFileName - the original for the file that is about to be renamed.
  2088. EventType - the type of event that is causing this rename.
  2089. ppRenameInfo - you can know where we put it if you like
  2090. Return Value:
  2091. NTSTATUS - Completion status.
  2092. --***************************************************************************/
  2093. NTSTATUS
  2094. SrRenameFileIntoStore(
  2095. IN PSR_DEVICE_EXTENSION pExtension,
  2096. IN PFILE_OBJECT pFileObject,
  2097. IN HANDLE FileHandle,
  2098. IN PUNICODE_STRING pOriginalFileName,
  2099. IN PUNICODE_STRING pFileName,
  2100. IN SR_EVENT_TYPE EventType,
  2101. OUT PFILE_RENAME_INFORMATION * ppRenameInfo OPTIONAL
  2102. )
  2103. {
  2104. NTSTATUS Status;
  2105. IO_STATUS_BLOCK IoStatusBlock;
  2106. ULONG FileNameLength;
  2107. PUCHAR pDestLocation;
  2108. PFILE_RENAME_INFORMATION pRenameInformation = NULL;
  2109. PUNICODE_STRING pDestFileName = NULL;
  2110. FILE_STANDARD_INFORMATION FileInformation;
  2111. BOOLEAN RenamedFile = FALSE;
  2112. PUNICODE_STRING pShortName = NULL;
  2113. WCHAR ShortFileNameBuffer[SR_SHORT_NAME_CHARS+1];
  2114. UNICODE_STRING ShortFileName;
  2115. PAGED_CODE();
  2116. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  2117. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  2118. ASSERT(FileHandle != NULL);
  2119. ASSERT(FlagOn( pFileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION ));
  2120. try {
  2121. //
  2122. // Is our volume properly setup?
  2123. //
  2124. Status = SrCheckVolume(pExtension, FALSE);
  2125. if (!NT_SUCCESS( Status ))
  2126. leave;
  2127. //
  2128. // Do we have enough room in the data store for this file?
  2129. //
  2130. Status = SrCheckFreeDiskSpace( FileHandle, pExtension->pNtVolumeName );
  2131. if (!NT_SUCCESS( Status ))
  2132. leave;
  2133. //
  2134. // do we need to get the short name prior to the rename (for
  2135. // delete's) .
  2136. //
  2137. if (FlagOn( EventType, SrEventFileDelete ))
  2138. {
  2139. RtlInitEmptyUnicodeString( &ShortFileName,
  2140. ShortFileNameBuffer,
  2141. sizeof(ShortFileNameBuffer) );
  2142. Status = SrGetShortFileName( pExtension,
  2143. pFileObject,
  2144. &ShortFileName );
  2145. if (STATUS_OBJECT_NAME_NOT_FOUND == Status)
  2146. {
  2147. //
  2148. // This file doesn't have a short name, so just leave
  2149. // pShortName equal to NULL.
  2150. //
  2151. Status = STATUS_SUCCESS;
  2152. }
  2153. else if (!NT_SUCCESS(Status))
  2154. {
  2155. //
  2156. // We hit an unexpected error, so leave.
  2157. //
  2158. leave;
  2159. }
  2160. else
  2161. {
  2162. pShortName = &ShortFileName;
  2163. }
  2164. }
  2165. //
  2166. // now prepare to rename the file
  2167. //
  2168. pRenameInformation = SR_ALLOCATE_POOL( PagedPool,
  2169. SR_RENAME_BUFFER_LENGTH,
  2170. SR_RENAME_BUFFER_TAG );
  2171. if (pRenameInformation == NULL)
  2172. {
  2173. Status = STATUS_INSUFFICIENT_RESOURCES;
  2174. leave;
  2175. }
  2176. //
  2177. // and get a buffer for a string
  2178. //
  2179. Status = SrAllocateFileNameBuffer( SR_MAX_FILENAME_LENGTH,
  2180. &pDestFileName );
  2181. if (!NT_SUCCESS( Status ))
  2182. leave;
  2183. Status = SrGetDestFileName( pExtension,
  2184. pFileName,
  2185. pDestFileName );
  2186. if (!NT_SUCCESS( Status ))
  2187. leave;
  2188. pDestLocation = (PUCHAR)&pRenameInformation->FileName[0];
  2189. //
  2190. // save this now as it get's overwritten.
  2191. //
  2192. FileNameLength = pDestFileName->Length;
  2193. //
  2194. // and make sure it's in the right spot for the rename info now
  2195. //
  2196. RtlMoveMemory( pDestLocation,
  2197. pDestFileName->Buffer,
  2198. pDestFileName->Length + sizeof(WCHAR) );
  2199. //
  2200. // now initialize the rename info struct
  2201. //
  2202. pRenameInformation->ReplaceIfExists = TRUE;
  2203. pRenameInformation->RootDirectory = NULL;
  2204. pRenameInformation->FileNameLength = FileNameLength;
  2205. SrTrace( NOTIFY, ("SR!SrRenameFileIntoStore:\n\t%wZ\n\tto %ws\n",
  2206. pFileName,
  2207. SrpFindFilePartW(&pRenameInformation->FileName[0]) ));
  2208. //
  2209. // and perform the rename
  2210. //
  2211. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  2212. Status = ZwSetInformationFile( FileHandle,
  2213. &IoStatusBlock,
  2214. pRenameInformation,
  2215. SR_FILENAME_BUFFER_LENGTH,
  2216. FileRenameInformation );
  2217. if (!NT_SUCCESS( Status ))
  2218. leave;
  2219. //
  2220. // we have now renamed the file
  2221. //
  2222. RenamedFile = TRUE;
  2223. //
  2224. // now get the filesize we just renamed
  2225. //
  2226. Status = ZwQueryInformationFile( FileHandle,
  2227. &IoStatusBlock,
  2228. &FileInformation,
  2229. sizeof(FileInformation),
  2230. FileStandardInformation );
  2231. if (!NT_SUCCESS( Status ) ||
  2232. NT_SUCCESS(IoStatusBlock.Status) == FALSE)
  2233. {
  2234. leave;
  2235. }
  2236. //
  2237. // and update the byte count as we moved this into the store
  2238. //
  2239. Status = SrUpdateBytesWritten( pExtension,
  2240. FileInformation.EndOfFile.QuadPart );
  2241. if (!NT_SUCCESS( Status ))
  2242. leave;
  2243. //
  2244. // paulmcd: 5/24/2000 decided not to do this and let the link
  2245. // tracking system hack their code to make shortcuts not work in
  2246. // our store.
  2247. //
  2248. #if 0
  2249. //
  2250. // strip out the object if of the newly renamed file.
  2251. // this prevents any existing shortcuts to link into our restore
  2252. // location. this file should be considered gone from the fs
  2253. //
  2254. Status = ZwFsControlFile( FileHandle, // file handle
  2255. NULL, // event
  2256. NULL, // apc routine
  2257. NULL, // apc context
  2258. &IoStatusBlock, // iosb
  2259. FSCTL_DELETE_OBJECT_ID, // FsControlCode
  2260. NULL, // input buffer
  2261. 0, // input buffer length
  2262. NULL, // OutputBuffer for data from the FS
  2263. 0 ); // OutputBuffer Length
  2264. //
  2265. // no big deal if this fails, it might not have had one.
  2266. //
  2267. CHECK_STATUS(Status);
  2268. Status = STATUS_SUCCESS;
  2269. #endif
  2270. //
  2271. // Now Log event
  2272. //
  2273. Status = SrLogEvent( pExtension,
  2274. EventType,
  2275. pFileObject,
  2276. pFileName,
  2277. 0,
  2278. pDestFileName,
  2279. NULL,
  2280. 0,
  2281. pShortName );
  2282. if (!NT_SUCCESS( Status ))
  2283. leave;
  2284. //
  2285. // now strip the owner SID so that the old user no longer charged
  2286. // quota for this file. it's in our store.
  2287. //
  2288. // its important to do this after we call SrLogEvent, as SrLogEvent
  2289. // needs to query the valid security descriptor for logging.
  2290. //
  2291. Status = SrSetFileSecurity( FileHandle, SrAclTypeRPFiles );
  2292. if (!NT_SUCCESS( Status ))
  2293. {
  2294. leave;
  2295. }
  2296. //
  2297. // does the caller want to know where we just renamed it to?
  2298. //
  2299. if (ppRenameInfo != NULL)
  2300. {
  2301. //
  2302. // let him own the buffer
  2303. //
  2304. *ppRenameInfo = pRenameInformation;
  2305. pRenameInformation = NULL;
  2306. }
  2307. } finally {
  2308. Status = FinallyUnwind(SrRenameFileIntoStore, Status);
  2309. //
  2310. // it better have succeeded or we better have the rename info around
  2311. //
  2312. //
  2313. // did we fail AFTER we renamed the file ? we need to clean up after
  2314. // ourselves if we did.
  2315. //
  2316. if (!NT_SUCCESS( Status ) &&
  2317. RenamedFile &&
  2318. pRenameInformation != NULL)
  2319. {
  2320. NTSTATUS TempStatus;
  2321. SrTraceSafe( NOTIFY, ("SR!SrRenameFileIntoStore:FAILED!:renaming it back\n"));
  2322. pRenameInformation->ReplaceIfExists = TRUE;
  2323. pRenameInformation->RootDirectory = NULL;
  2324. pRenameInformation->FileNameLength = pOriginalFileName->Length;
  2325. RtlCopyMemory( &pRenameInformation->FileName[0],
  2326. pOriginalFileName->Buffer,
  2327. pOriginalFileName->Length );
  2328. //
  2329. // and perform the rename
  2330. //
  2331. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  2332. TempStatus = ZwSetInformationFile( FileHandle,
  2333. &IoStatusBlock,
  2334. pRenameInformation,
  2335. SR_FILENAME_BUFFER_LENGTH,
  2336. FileRenameInformation );
  2337. //
  2338. // we did the best we could!
  2339. //
  2340. ASSERTMSG("sr!SrRenameFileIntoStore: couldn't fix the failed rename, file lost!", NT_SUCCESS_NO_DBGBREAK(TempStatus));
  2341. }
  2342. if (pRenameInformation != NULL)
  2343. {
  2344. SR_FREE_POOL(pRenameInformation, SR_RENAME_BUFFER_TAG);
  2345. pRenameInformation = NULL;
  2346. }
  2347. if (pDestFileName != NULL)
  2348. {
  2349. SrFreeFileNameBuffer(pDestFileName);
  2350. pDestFileName = NULL;
  2351. }
  2352. }
  2353. RETURN(Status);
  2354. } // SrRenameFileIntoStore
  2355. /***************************************************************************++
  2356. Routine Description:
  2357. this routine is called in the rename code path. if a directory is being
  2358. renamed out of monitored space, we simulate delete's for all of the files
  2359. in that directory.
  2360. Arguments:
  2361. EventDelete - TRUE if we should trigger deletes, FALSE to trigger creates
  2362. Return Value:
  2363. NTSTATUS - Completion status.
  2364. --***************************************************************************/
  2365. NTSTATUS
  2366. SrTriggerEvents(
  2367. IN PSR_DEVICE_EXTENSION pExtension,
  2368. IN PUNICODE_STRING pDirectoryName,
  2369. IN BOOLEAN EventDelete
  2370. )
  2371. {
  2372. NTSTATUS Status;
  2373. OBJECT_ATTRIBUTES ObjectAttributes;
  2374. IO_STATUS_BLOCK IoStatusBlock;
  2375. ULONG FileNameLength;
  2376. PUNICODE_STRING pFileName = NULL;
  2377. HANDLE FileHandle = NULL;
  2378. PFILE_OBJECT pFileObject = NULL;
  2379. UNICODE_STRING StarFilter;
  2380. PSR_TRIGGER_ITEM pCurrentItem = NULL;
  2381. LIST_ENTRY DirectoryList;
  2382. PAGED_CODE();
  2383. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  2384. try {
  2385. InitializeListHead(&DirectoryList);
  2386. //
  2387. // allocate the first work item
  2388. //
  2389. pCurrentItem = SR_ALLOCATE_STRUCT( PagedPool,
  2390. SR_TRIGGER_ITEM,
  2391. SR_TRIGGER_ITEM_TAG );
  2392. if (pCurrentItem == NULL)
  2393. {
  2394. Status = STATUS_INSUFFICIENT_RESOURCES;
  2395. leave;
  2396. }
  2397. RtlZeroMemory(pCurrentItem, sizeof(SR_TRIGGER_ITEM));
  2398. pCurrentItem->Signature = SR_TRIGGER_ITEM_TAG;
  2399. pCurrentItem->pDirectoryName = pDirectoryName;
  2400. pCurrentItem->FreeDirectoryName = FALSE;
  2401. //
  2402. // make sure noboby is using this one passed in the arg list.
  2403. //
  2404. pDirectoryName = NULL;
  2405. //
  2406. // allocate a single temp filename buffer
  2407. //
  2408. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, &pFileName);
  2409. if (!NT_SUCCESS( Status ))
  2410. leave;
  2411. //
  2412. // start our outer most directory handler
  2413. //
  2414. start_directory:
  2415. SrTrace( RENAME, ("sr!SrTriggerEvents: starting dir=%wZ\n",
  2416. pCurrentItem->pDirectoryName ));
  2417. //
  2418. // Open the directory for list access
  2419. //
  2420. InitializeObjectAttributes( &ObjectAttributes,
  2421. pCurrentItem->pDirectoryName,
  2422. OBJ_KERNEL_HANDLE,
  2423. NULL,
  2424. NULL );
  2425. Status = SrIoCreateFile( &pCurrentItem->DirectoryHandle,
  2426. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  2427. &ObjectAttributes,
  2428. &IoStatusBlock,
  2429. NULL, // AllocationSize
  2430. FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL,
  2431. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,// ShareAccess
  2432. FILE_OPEN, // OPEN_EXISTING
  2433. FILE_DIRECTORY_FILE
  2434. | FILE_OPEN_FOR_BACKUP_INTENT
  2435. | FILE_SYNCHRONOUS_IO_NONALERT,
  2436. NULL,
  2437. 0, // EaLength
  2438. IO_IGNORE_SHARE_ACCESS_CHECK,
  2439. pExtension->pTargetDevice );
  2440. if (!NT_SUCCESS( Status ))
  2441. leave;
  2442. //
  2443. // reference the file object
  2444. //
  2445. Status = ObReferenceObjectByHandle( pCurrentItem->DirectoryHandle,
  2446. 0,
  2447. *IoFileObjectType,
  2448. KernelMode,
  2449. (PVOID *) &pCurrentItem->pDirectoryObject,
  2450. NULL );
  2451. if (!NT_SUCCESS( Status ))
  2452. leave;
  2453. //
  2454. // for creates: log the directory event first
  2455. //
  2456. if (!EventDelete)
  2457. {
  2458. Status = SrHandleEvent( pExtension,
  2459. SrEventDirectoryCreate|SrEventIsDirectory,
  2460. pCurrentItem->pDirectoryObject,
  2461. NULL,
  2462. NULL,
  2463. NULL ); // pFileName2
  2464. if (!NT_SUCCESS( Status ))
  2465. leave;
  2466. }
  2467. StarFilter.Length = sizeof(WCHAR);
  2468. StarFilter.MaximumLength = sizeof(WCHAR);
  2469. StarFilter.Buffer = L"*";
  2470. pCurrentItem->FileEntryLength = SR_FILE_ENTRY_LENGTH;
  2471. pCurrentItem->pFileEntry = (PFILE_DIRECTORY_INFORMATION)(
  2472. SR_ALLOCATE_ARRAY( PagedPool,
  2473. UCHAR,
  2474. pCurrentItem->FileEntryLength,
  2475. SR_FILE_ENTRY_TAG ) );
  2476. if (pCurrentItem->pFileEntry == NULL)
  2477. {
  2478. Status = STATUS_INSUFFICIENT_RESOURCES;
  2479. leave;
  2480. }
  2481. //
  2482. // start the enumeration
  2483. //
  2484. Status = ZwQueryDirectoryFile( pCurrentItem->DirectoryHandle,
  2485. NULL,
  2486. NULL,
  2487. NULL,
  2488. &IoStatusBlock,
  2489. pCurrentItem->pFileEntry,
  2490. pCurrentItem->FileEntryLength,
  2491. FileDirectoryInformation,
  2492. TRUE, // ReturnSingleEntry
  2493. &StarFilter,
  2494. TRUE ); // RestartScan
  2495. if (Status == STATUS_NO_MORE_FILES)
  2496. {
  2497. Status = STATUS_SUCCESS;
  2498. goto finish_directory;
  2499. }
  2500. else if (!NT_SUCCESS( Status ))
  2501. {
  2502. leave;
  2503. }
  2504. //
  2505. // enumerate all of the files in this directory and back them up
  2506. //
  2507. while (TRUE)
  2508. {
  2509. //
  2510. // skip "." and ".."
  2511. //
  2512. if ((pCurrentItem->pFileEntry->FileNameLength == sizeof(WCHAR) &&
  2513. pCurrentItem->pFileEntry->FileName[0] == L'.') ||
  2514. (pCurrentItem->pFileEntry->FileNameLength == (sizeof(WCHAR)*2) &&
  2515. pCurrentItem->pFileEntry->FileName[0] == L'.' &&
  2516. pCurrentItem->pFileEntry->FileName[1] == L'.') )
  2517. {
  2518. //
  2519. // skip it
  2520. //
  2521. }
  2522. //
  2523. // is this a directory?
  2524. //
  2525. else if (pCurrentItem->pFileEntry->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2526. {
  2527. PSR_TRIGGER_ITEM pParentItem;
  2528. PUNICODE_STRING pDirNameBuffer;
  2529. USHORT DirNameLength;
  2530. //
  2531. // remember a pointer to the parent item
  2532. //
  2533. pParentItem = pCurrentItem;
  2534. //
  2535. // insert the old item to the list, we'll get back to it
  2536. //
  2537. InsertTailList(&DirectoryList, &pCurrentItem->ListEntry);
  2538. pCurrentItem = NULL;
  2539. //
  2540. // allocate a new current trigger item
  2541. //
  2542. pCurrentItem = SR_ALLOCATE_STRUCT( PagedPool,
  2543. SR_TRIGGER_ITEM,
  2544. SR_TRIGGER_ITEM_TAG );
  2545. if (pCurrentItem == NULL)
  2546. {
  2547. Status = STATUS_INSUFFICIENT_RESOURCES;
  2548. leave;
  2549. }
  2550. RtlZeroMemory(pCurrentItem, sizeof(SR_TRIGGER_ITEM));
  2551. pCurrentItem->Signature = SR_TRIGGER_ITEM_TAG;
  2552. //
  2553. // allocate a file name buffer
  2554. //
  2555. DirNameLength = (USHORT)(pParentItem->pDirectoryName->Length
  2556. + sizeof(WCHAR)
  2557. + pParentItem->pFileEntry->FileNameLength);
  2558. Status = SrAllocateFileNameBuffer( DirNameLength,
  2559. &pDirNameBuffer );
  2560. if (!NT_SUCCESS( Status ))
  2561. leave;
  2562. //
  2563. // construct a full path string for the sub directory
  2564. //
  2565. pDirNameBuffer->Length = DirNameLength;
  2566. RtlCopyMemory( pDirNameBuffer->Buffer,
  2567. pParentItem->pDirectoryName->Buffer,
  2568. pParentItem->pDirectoryName->Length );
  2569. pDirNameBuffer->Buffer
  2570. [pParentItem->pDirectoryName->Length/sizeof(WCHAR)] = L'\\';
  2571. RtlCopyMemory( &pDirNameBuffer->Buffer[(pParentItem->pDirectoryName->Length/sizeof(WCHAR)) + 1],
  2572. pParentItem->pFileEntry->FileName,
  2573. pParentItem->pFileEntry->FileNameLength );
  2574. pDirNameBuffer->Buffer
  2575. [pDirNameBuffer->Length/sizeof(WCHAR)] = UNICODE_NULL;
  2576. pCurrentItem->pDirectoryName = pDirNameBuffer;
  2577. pCurrentItem->FreeDirectoryName = TRUE;
  2578. //
  2579. // now process this child directory
  2580. //
  2581. goto start_directory;
  2582. }
  2583. else
  2584. {
  2585. //
  2586. // open the file, first construct a full path string to the file
  2587. //
  2588. FileNameLength = pCurrentItem->pDirectoryName->Length
  2589. + sizeof(WCHAR)
  2590. + pCurrentItem->pFileEntry->FileNameLength;
  2591. if (FileNameLength > pFileName->MaximumLength)
  2592. {
  2593. Status = STATUS_BUFFER_OVERFLOW;
  2594. leave;
  2595. }
  2596. pFileName->Length = (USHORT)FileNameLength;
  2597. RtlCopyMemory( pFileName->Buffer,
  2598. pCurrentItem->pDirectoryName->Buffer,
  2599. pCurrentItem->pDirectoryName->Length );
  2600. pFileName->Buffer[pCurrentItem->pDirectoryName->Length/sizeof(WCHAR)] = L'\\';
  2601. RtlCopyMemory( &(pFileName->Buffer[(pCurrentItem->pDirectoryName->Length/sizeof(WCHAR)) + 1]),
  2602. pCurrentItem->pFileEntry->FileName,
  2603. pCurrentItem->pFileEntry->FileNameLength );
  2604. SrTrace(RENAME, ("sr!SrTriggerEvents: file=%wZ\n", pFileName));
  2605. InitializeObjectAttributes( &ObjectAttributes,
  2606. pFileName,
  2607. OBJ_KERNEL_HANDLE,
  2608. NULL,
  2609. NULL );
  2610. ASSERT(FileHandle == NULL);
  2611. Status = SrIoCreateFile( &FileHandle,
  2612. FILE_READ_ATTRIBUTES|SYNCHRONIZE,
  2613. &ObjectAttributes,
  2614. &IoStatusBlock,
  2615. NULL, // AllocationSize
  2616. FILE_ATTRIBUTE_NORMAL,
  2617. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,// ShareAccess
  2618. FILE_OPEN, // OPEN_EXISTING
  2619. FILE_SEQUENTIAL_ONLY
  2620. | FILE_WRITE_THROUGH
  2621. | FILE_NO_INTERMEDIATE_BUFFERING
  2622. | FILE_NON_DIRECTORY_FILE
  2623. | FILE_OPEN_FOR_BACKUP_INTENT
  2624. | FILE_SYNCHRONOUS_IO_NONALERT,
  2625. NULL,
  2626. 0, // EaLength
  2627. IO_IGNORE_SHARE_ACCESS_CHECK,
  2628. pExtension->pTargetDevice );
  2629. if (!NT_SUCCESS( Status ))
  2630. leave;
  2631. //
  2632. // reference the file object
  2633. //
  2634. Status = ObReferenceObjectByHandle( FileHandle,
  2635. 0,
  2636. *IoFileObjectType,
  2637. KernelMode,
  2638. (PVOID *) &pFileObject,
  2639. NULL );
  2640. if (!NT_SUCCESS( Status ))
  2641. leave;
  2642. //
  2643. // simulate a delete event happening on this file
  2644. //
  2645. Status = SrHandleEvent( pExtension,
  2646. EventDelete ?
  2647. (SrEventFileDelete|SrEventNoOptimization|SrEventSimulatedDelete) :
  2648. SrEventFileCreate,
  2649. pFileObject,
  2650. NULL,
  2651. NULL,
  2652. NULL );
  2653. if (!NT_SUCCESS( Status ))
  2654. leave;
  2655. //
  2656. // all done with these
  2657. //
  2658. ObDereferenceObject(pFileObject);
  2659. pFileObject = NULL;
  2660. ZwClose(FileHandle);
  2661. FileHandle = NULL;
  2662. }
  2663. continue_directory:
  2664. //
  2665. // is there another file?
  2666. //
  2667. Status = ZwQueryDirectoryFile( pCurrentItem->DirectoryHandle,
  2668. NULL,
  2669. NULL,
  2670. NULL,
  2671. &IoStatusBlock,
  2672. pCurrentItem->pFileEntry,
  2673. pCurrentItem->FileEntryLength,
  2674. FileDirectoryInformation,
  2675. TRUE, // ReturnSingleEntry
  2676. NULL, // FileName
  2677. FALSE ); // RestartScan
  2678. if (Status == STATUS_NO_MORE_FILES)
  2679. {
  2680. Status = STATUS_SUCCESS;
  2681. break;
  2682. }
  2683. else if (!NT_SUCCESS( Status ))
  2684. {
  2685. leave;
  2686. }
  2687. } // while (TRUE)
  2688. finish_directory:
  2689. //
  2690. // for deletes: simulate the event at the end.
  2691. //
  2692. if (EventDelete)
  2693. {
  2694. Status = SrHandleEvent( pExtension,
  2695. SrEventDirectoryDelete|SrEventIsDirectory|SrEventSimulatedDelete,
  2696. pCurrentItem->pDirectoryObject,
  2697. NULL,
  2698. NULL,
  2699. NULL ); // pFileName2
  2700. if (!NT_SUCCESS( Status ))
  2701. leave;
  2702. }
  2703. //
  2704. // we just finished a directory item, remove it and free it
  2705. //
  2706. SrFreeTriggerItem(pCurrentItem);
  2707. pCurrentItem = NULL;
  2708. //
  2709. // is there another one ?
  2710. //
  2711. if (IsListEmpty(&DirectoryList) == FALSE)
  2712. {
  2713. PLIST_ENTRY pListEntry;
  2714. //
  2715. // finish it
  2716. //
  2717. pListEntry = RemoveTailList(&DirectoryList);
  2718. pCurrentItem = CONTAINING_RECORD( pListEntry,
  2719. SR_TRIGGER_ITEM,
  2720. ListEntry );
  2721. ASSERT(IS_VALID_TRIGGER_ITEM(pCurrentItem));
  2722. SrTrace( RENAME, ("sr!SrTriggerEvents: resuming dir=%wZ\n",
  2723. pCurrentItem->pDirectoryName ));
  2724. goto continue_directory;
  2725. }
  2726. //
  2727. // all done
  2728. //
  2729. } finally {
  2730. Status = FinallyUnwind(SrTriggerEvents, Status);
  2731. if (pFileObject != NULL)
  2732. {
  2733. ObDereferenceObject(pFileObject);
  2734. pFileObject = NULL;
  2735. }
  2736. if (FileHandle != NULL)
  2737. {
  2738. ZwClose(FileHandle);
  2739. FileHandle = NULL;
  2740. }
  2741. if (pFileName != NULL)
  2742. {
  2743. SrFreeFileNameBuffer(pFileName);
  2744. pFileName = NULL;
  2745. }
  2746. if (pCurrentItem != NULL)
  2747. {
  2748. ASSERT(NT_SUCCESS_NO_DBGBREAK(Status) == FALSE);
  2749. SrFreeTriggerItem(pCurrentItem);
  2750. pCurrentItem = NULL;
  2751. }
  2752. ASSERT(IsListEmpty(&DirectoryList) ||
  2753. NT_SUCCESS_NO_DBGBREAK(Status) == FALSE);
  2754. while (IsListEmpty(&DirectoryList) == FALSE)
  2755. {
  2756. PLIST_ENTRY pListEntry;
  2757. pListEntry = RemoveTailList(&DirectoryList);
  2758. pCurrentItem = CONTAINING_RECORD( pListEntry,
  2759. SR_TRIGGER_ITEM,
  2760. ListEntry );
  2761. ASSERT(IS_VALID_TRIGGER_ITEM(pCurrentItem));
  2762. SrFreeTriggerItem(pCurrentItem);
  2763. }
  2764. }
  2765. RETURN(Status);
  2766. } // SrTriggerEvents
  2767. /***************************************************************************++
  2768. Routine Description:
  2769. this is the second phase handling of a rename. if a directory is renamed
  2770. from non-monitored space to monitored space, we need to enumerate the
  2771. new directory and simluate (trigger) create events for each new file.
  2772. this results in a log entry being created for each new file that was
  2773. added .
  2774. Arguments:
  2775. --***************************************************************************/
  2776. NTSTATUS
  2777. SrHandleDirectoryRename(
  2778. IN PSR_DEVICE_EXTENSION pExtension,
  2779. IN PUNICODE_STRING pDirectoryName,
  2780. IN BOOLEAN EventDelete
  2781. )
  2782. {
  2783. NTSTATUS Status;
  2784. PAGED_CODE();
  2785. try {
  2786. //
  2787. // Acquire the activily lock for the volume
  2788. //
  2789. SrAcquireActivityLockShared( pExtension );
  2790. Status = STATUS_SUCCESS;
  2791. //
  2792. // did we just get disabled?
  2793. //
  2794. if (!SR_LOGGING_ENABLED(pExtension))
  2795. leave;
  2796. //
  2797. // don't check the volume yet, we don't if there is anything
  2798. // interesting even though this could be a new restore point.
  2799. // SrHandleEvent will check the volume (SrTriggerEvents calls it) .
  2800. //
  2801. //
  2802. // it's a directory. fire events on all of the children,
  2803. // as they are moving also!
  2804. //
  2805. Status = SrTriggerEvents( pExtension,
  2806. pDirectoryName,
  2807. EventDelete );
  2808. if (!NT_SUCCESS( Status ))
  2809. leave;
  2810. } finally {
  2811. Status = FinallyUnwind(SrHandleDirectoryRename, Status);
  2812. //
  2813. // check for any bad errors
  2814. //
  2815. if (CHECK_FOR_VOLUME_ERROR(Status))
  2816. {
  2817. NTSTATUS TempStatus;
  2818. //
  2819. // trigger the failure notification to the service
  2820. //
  2821. TempStatus = SrNotifyVolumeError( pExtension,
  2822. pDirectoryName,
  2823. Status,
  2824. SrEventDirectoryRename );
  2825. CHECK_STATUS(TempStatus);
  2826. }
  2827. SrReleaseActivityLock( pExtension );
  2828. }
  2829. RETURN(Status);
  2830. } // SrHandleDirectoryRename
  2831. /***************************************************************************++
  2832. Routine Description:
  2833. This handles when a file is being renamed out of monitored space
  2834. and we need to backup the file before the rename. We return the name
  2835. of the destination file we created so it can be logged with the
  2836. operation if the rename is successful.
  2837. Arguments:
  2838. pFileObject - the file object that just changed
  2839. pFileName - the name of the file that changed
  2840. ppDestFileName - this returns the allocated destination file name (if one
  2841. is defined, so it can be logged with the entry)
  2842. Return Value:
  2843. NTSTATUS - Completion status.
  2844. --***************************************************************************/
  2845. NTSTATUS
  2846. SrHandleFileRenameOutOfMonitoredSpace(
  2847. IN PSR_DEVICE_EXTENSION pExtension,
  2848. IN PFILE_OBJECT pFileObject,
  2849. IN PSR_STREAM_CONTEXT pFileContext,
  2850. OUT PBOOLEAN pOptimizeDelete,
  2851. OUT PUNICODE_STRING *ppDestFileName
  2852. )
  2853. {
  2854. ULONGLONG BytesWritten;
  2855. NTSTATUS Status;
  2856. BOOLEAN HasFileBeenBackedUp;
  2857. BOOLEAN releaseLock = FALSE;
  2858. PAGED_CODE();
  2859. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  2860. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  2861. ASSERT( pFileContext != NULL );
  2862. //
  2863. // Initialize return parameters
  2864. //
  2865. *pOptimizeDelete = FALSE;
  2866. *ppDestFileName = NULL;
  2867. //
  2868. // See if the file has already been backed up because of a delete. If so
  2869. // don't do it again.
  2870. //
  2871. HasFileBeenBackedUp = SrHasFileBeenBackedUp( pExtension,
  2872. &(pFileContext->FileName),
  2873. pFileContext->StreamNameLength,
  2874. SrEventFileDelete );
  2875. if (HasFileBeenBackedUp)
  2876. {
  2877. *pOptimizeDelete = TRUE;
  2878. return STATUS_SUCCESS;
  2879. }
  2880. //
  2881. // Handle backing up the file
  2882. //
  2883. try {
  2884. //
  2885. // Allocate a buffer to hold destination name
  2886. //
  2887. Status = SrAllocateFileNameBuffer(SR_MAX_FILENAME_LENGTH, ppDestFileName);
  2888. if (!NT_SUCCESS( Status ))
  2889. leave;
  2890. //
  2891. // Acquire the activily lock for the volume
  2892. //
  2893. SrAcquireActivityLockShared( pExtension );
  2894. releaseLock = TRUE;
  2895. //
  2896. // we need to make sure our disk structures are good and logging
  2897. // has been started.
  2898. //
  2899. Status = SrCheckVolume(pExtension, FALSE);
  2900. if (!NT_SUCCESS( Status ))
  2901. leave;
  2902. //
  2903. // Generate a destination file name
  2904. //
  2905. Status = SrGetDestFileName( pExtension,
  2906. &(pFileContext->FileName),
  2907. *ppDestFileName );
  2908. if (!NT_SUCCESS( Status ))
  2909. leave;
  2910. //
  2911. // Backup the file
  2912. //
  2913. Status = SrBackupFile( pExtension,
  2914. pFileObject,
  2915. &(pFileContext->FileName),
  2916. *ppDestFileName,
  2917. TRUE,
  2918. &BytesWritten,
  2919. NULL );
  2920. if (Status == SR_STATUS_IGNORE_FILE)
  2921. {
  2922. //
  2923. // We weren't able to open the file because it was encrypted in
  2924. // another context. Unfortunately, we cannot recover from this
  2925. // error, so return the actual error of STATUS_ACCESS_DENIED.
  2926. //
  2927. Status = STATUS_ACCESS_DENIED;
  2928. CHECK_STATUS( Status );
  2929. leave;
  2930. }
  2931. else if (!NT_SUCCESS(Status))
  2932. leave;
  2933. //
  2934. // Update the bytes written.
  2935. //
  2936. Status = SrUpdateBytesWritten(pExtension, BytesWritten);
  2937. if (!NT_SUCCESS(Status))
  2938. leave;
  2939. }
  2940. finally
  2941. {
  2942. if (releaseLock)
  2943. {
  2944. SrReleaseActivityLock( pExtension );
  2945. }
  2946. //
  2947. // If we are returning an error then do not return the string
  2948. // (and free it).
  2949. //
  2950. if (!NT_SUCCESS_NO_DBGBREAK(Status) && (NULL != *ppDestFileName))
  2951. {
  2952. SrFreeFileNameBuffer(*ppDestFileName);
  2953. *ppDestFileName = NULL;
  2954. }
  2955. }
  2956. return Status;
  2957. }
  2958. /***************************************************************************++
  2959. Routine Description:
  2960. this routine is called from the mj_create completion routine. it
  2961. happens if the mj_create failed in it's overwrite, but we thought it was
  2962. going to work and renamed the destination file out from under the
  2963. overwrite. in this case we have to cleanup after ourselves.
  2964. Arguments:
  2965. --***************************************************************************/
  2966. NTSTATUS
  2967. SrHandleOverwriteFailure(
  2968. IN PSR_DEVICE_EXTENSION pExtension,
  2969. IN PUNICODE_STRING pOriginalFileName,
  2970. IN ULONG CreateFileAttributes,
  2971. IN PFILE_RENAME_INFORMATION pRenameInformation
  2972. )
  2973. {
  2974. NTSTATUS Status;
  2975. NTSTATUS TempStatus;
  2976. HANDLE FileHandle = NULL;
  2977. UNICODE_STRING FileName;
  2978. OBJECT_ATTRIBUTES ObjectAttributes;
  2979. IO_STATUS_BLOCK IoStatusBlock;
  2980. PAGED_CODE();
  2981. try {
  2982. SrAcquireActivityLockShared( pExtension );
  2983. //
  2984. // open the file that we renamed to.
  2985. //
  2986. FileName.Length = (USHORT)pRenameInformation->FileNameLength;
  2987. FileName.MaximumLength = (USHORT)pRenameInformation->FileNameLength;
  2988. FileName.Buffer = &pRenameInformation->FileName[0];
  2989. InitializeObjectAttributes( &ObjectAttributes,
  2990. &FileName,
  2991. OBJ_KERNEL_HANDLE,
  2992. NULL,
  2993. NULL );
  2994. Status = SrIoCreateFile( &FileHandle,
  2995. DELETE|SYNCHRONIZE,
  2996. &ObjectAttributes,
  2997. &IoStatusBlock,
  2998. NULL, // AllocationSize
  2999. CreateFileAttributes,
  3000. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,// ShareAccess
  3001. FILE_OPEN, // OPEN_EXISTING
  3002. FILE_SYNCHRONOUS_IO_NONALERT
  3003. | FILE_WRITE_THROUGH,
  3004. NULL,
  3005. 0, // EaLength
  3006. IO_IGNORE_SHARE_ACCESS_CHECK,
  3007. pExtension->pTargetDevice );
  3008. if (!NT_SUCCESS( Status ))
  3009. leave;
  3010. pRenameInformation->ReplaceIfExists = TRUE;
  3011. pRenameInformation->RootDirectory = NULL;
  3012. pRenameInformation->FileNameLength = pOriginalFileName->Length;
  3013. RtlCopyMemory( &pRenameInformation->FileName[0],
  3014. pOriginalFileName->Buffer,
  3015. pOriginalFileName->Length );
  3016. RtlZeroMemory(&IoStatusBlock, sizeof(IoStatusBlock));
  3017. Status = ZwSetInformationFile( FileHandle,
  3018. &IoStatusBlock,
  3019. pRenameInformation,
  3020. SR_FILENAME_BUFFER_LENGTH,
  3021. FileRenameInformation );
  3022. if (!NT_SUCCESS( Status ))
  3023. leave;
  3024. } finally {
  3025. //
  3026. // always report a volume failure
  3027. //
  3028. TempStatus = SrNotifyVolumeError( pExtension,
  3029. pOriginalFileName,
  3030. STATUS_UNEXPECTED_IO_ERROR,
  3031. SrEventStreamOverwrite );
  3032. if (NT_SUCCESS(TempStatus) == FALSE && NT_SUCCESS(Status))
  3033. {
  3034. //
  3035. // only return this if we are not hiding some existing error
  3036. // status code
  3037. //
  3038. Status = TempStatus;
  3039. }
  3040. SrReleaseActivityLock( pExtension );
  3041. if (FileHandle != NULL)
  3042. {
  3043. ZwClose(FileHandle);
  3044. FileHandle = NULL;
  3045. }
  3046. }
  3047. RETURN(Status);
  3048. } // SrFixOverwriteFailure
  3049. VOID
  3050. SrFreeTriggerItem(
  3051. IN PSR_TRIGGER_ITEM pItem
  3052. )
  3053. {
  3054. PAGED_CODE();
  3055. ASSERT(IS_VALID_TRIGGER_ITEM(pItem));
  3056. if (pItem->FreeDirectoryName && pItem->pDirectoryName != NULL)
  3057. {
  3058. SrFreeFileNameBuffer(pItem->pDirectoryName);
  3059. pItem->pDirectoryName = NULL;
  3060. }
  3061. if (pItem->pFileEntry != NULL)
  3062. {
  3063. SR_FREE_POOL(pItem->pFileEntry, SR_FILE_ENTRY_TAG);
  3064. pItem->pFileEntry = NULL;
  3065. }
  3066. if (pItem->pDirectoryObject != NULL)
  3067. {
  3068. ObDereferenceObject(pItem->pDirectoryObject);
  3069. pItem->pDirectoryObject = NULL;
  3070. }
  3071. if (pItem->DirectoryHandle != NULL)
  3072. {
  3073. ZwClose(pItem->DirectoryHandle);
  3074. pItem->DirectoryHandle = NULL;
  3075. }
  3076. SR_FREE_POOL_WITH_SIG(pItem, SR_TRIGGER_ITEM_TAG);
  3077. } // SrFreeTriggerItem