Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2218 lines
71 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. setInformation.c
  5. Abstract:
  6. this is the major function code dispatch filter layer.
  7. Author:
  8. Neal Christiansen (nealch) 5-Feb-2001
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Local prototypes
  14. //
  15. NTSTATUS
  16. SrpSetRenameInfo(
  17. IN PSR_DEVICE_EXTENSION pExtension,
  18. IN PIRP pIrp
  19. );
  20. NTSTATUS
  21. SrpSetLinkInfo(
  22. IN PSR_DEVICE_EXTENSION pExtension,
  23. IN PIRP pIrp
  24. );
  25. NTSTATUS
  26. SrpReplacingDestinationFile (
  27. IN PSR_DEVICE_EXTENSION pExtension,
  28. IN PFILE_OBJECT pDestFileObject,
  29. IN PSR_STREAM_CONTEXT pDestFileContext
  30. );
  31. VOID
  32. SrpSetRenamingState(
  33. IN PSR_DEVICE_EXTENSION pExtension,
  34. IN PSR_STREAM_CONTEXT pFileContext
  35. );
  36. BOOLEAN
  37. SrpCheckForSameFile (
  38. IN PFILE_OBJECT pFileObject1,
  39. IN PFILE_OBJECT pFileObject2
  40. );
  41. //
  42. // Linker commands
  43. //
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text( PAGE, SrSetInformation )
  46. #pragma alloc_text( PAGE, SrpSetRenameInfo )
  47. #pragma alloc_text( PAGE, SrpSetLinkInfo )
  48. #pragma alloc_text( PAGE, SrpReplacingDestinationFile )
  49. #pragma alloc_text( PAGE, SrpSetRenamingState )
  50. #pragma alloc_text( PAGE, SrpCheckForSameFile )
  51. #endif // ALLOC_PRAGMA
  52. /***************************************************************************++
  53. Routine Description:
  54. Handle SetInformation IRPS
  55. Arguments:
  56. Return Value:
  57. NTSTATUS - Status code.
  58. --***************************************************************************/
  59. NTSTATUS
  60. SrSetInformation(
  61. IN PDEVICE_OBJECT DeviceObject,
  62. IN PIRP pIrp
  63. )
  64. {
  65. PSR_DEVICE_EXTENSION pExtension;
  66. PIO_STACK_LOCATION pIrpSp;
  67. NTSTATUS eventStatus;
  68. FILE_INFORMATION_CLASS FileInformationClass;
  69. PUNICODE_STRING pRenameNewDirectoryName = NULL;
  70. PSR_STREAM_CONTEXT pOrigFileContext = NULL;
  71. //
  72. // < dispatch!
  73. //
  74. PAGED_CODE();
  75. ASSERT(IS_VALID_DEVICE_OBJECT(DeviceObject));
  76. ASSERT(IS_VALID_IRP(pIrp));
  77. //
  78. // Is this a function for our device (vs an attachee).
  79. //
  80. if (DeviceObject == _globals.pControlDevice)
  81. {
  82. return SrMajorFunction(DeviceObject, pIrp);
  83. }
  84. //
  85. // else it is a device we've attached to, grab our extension
  86. //
  87. ASSERT(IS_SR_DEVICE_OBJECT(DeviceObject));
  88. pExtension = DeviceObject->DeviceExtension;
  89. //
  90. // See if logging is enabled and we don't care about this type of IO
  91. // to the file systems' control device objects.
  92. //
  93. if (!SR_LOGGING_ENABLED(pExtension) ||
  94. SR_IS_FS_CONTROL_DEVICE(pExtension))
  95. {
  96. goto SrSetInformation_Skip;
  97. }
  98. //
  99. // Just pass through all paging IO. We catch all write's prior to
  100. // the cache manager even seeing them.
  101. //
  102. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  103. if (FlagOn(pIrp->Flags, IRP_PAGING_IO))
  104. {
  105. goto SrSetInformation_Skip;
  106. }
  107. //
  108. // Ignore files with no name
  109. //
  110. if (FILE_OBJECT_IS_NOT_POTENTIALLY_INTERESTING( pIrpSp->FileObject ) ||
  111. FILE_OBJECT_DOES_NOT_HAVE_VPB( pIrpSp->FileObject ))
  112. {
  113. goto SrSetInformation_Skip;
  114. }
  115. //
  116. // Handle the necessary event based on the FileInformationClass.
  117. // Note that the FileLinkInformation and FileRenameInformation (when
  118. // renaming a directory in some cases) require synchronization
  119. // with a completion routine so that we can see the final status.
  120. //
  121. FileInformationClass = pIrpSp->Parameters.SetFile.FileInformationClass;
  122. switch (FileInformationClass)
  123. {
  124. case FileEndOfFileInformation: // SetEndOfFile
  125. case FileAllocationInformation:
  126. {
  127. PSR_STREAM_CONTEXT pFileContext;
  128. //
  129. // Get the context now so we can determine if this is a
  130. // directory or not
  131. //
  132. eventStatus = SrGetContext( pExtension,
  133. pIrpSp->FileObject,
  134. SrEventStreamChange,
  135. &pFileContext );
  136. if (!NT_SUCCESS( eventStatus ))
  137. {
  138. goto SrSetInformation_Skip;
  139. }
  140. //
  141. // If this is a directory don't bother logging because the
  142. // operation will fail.
  143. //
  144. if (FlagOn(pFileContext->Flags,CTXFL_IsInteresting) &&
  145. !FlagOn(pFileContext->Flags,CTXFL_IsDirectory))
  146. {
  147. SrHandleEvent( pExtension,
  148. SrEventStreamChange,
  149. pIrpSp->FileObject,
  150. pFileContext,
  151. NULL,
  152. NULL );
  153. }
  154. //
  155. // Release the context
  156. //
  157. SrReleaseContext( pFileContext );
  158. break;
  159. }
  160. case FileDispositionInformation: // DeleteFile - handled in MJ_CLEANUP
  161. case FilePositionInformation: // SetFilePosition
  162. //
  163. // we can skip these
  164. //
  165. break;
  166. case FileBasicInformation: // SetFileAttributes
  167. {
  168. PFILE_BASIC_INFORMATION pBasicInformation;
  169. //
  170. // ignore time changes. for sure we need to ignore changes
  171. // to LastAccessTime updates.
  172. //
  173. // for now we only care about attrib changes (like adding hidden)
  174. //
  175. pBasicInformation = pIrp->AssociatedIrp.SystemBuffer;
  176. if ((pBasicInformation != NULL) &&
  177. (pIrpSp->Parameters.SetFile.Length >=
  178. sizeof(FILE_BASIC_INFORMATION)) &&
  179. (pBasicInformation->FileAttributes != 0))
  180. {
  181. //
  182. // Handle this event
  183. //
  184. SrHandleEvent( pExtension,
  185. SrEventAttribChange,
  186. pIrpSp->FileObject,
  187. NULL,
  188. NULL,
  189. NULL );
  190. }
  191. break;
  192. }
  193. case FileRenameInformation: // Rename
  194. {
  195. PFILE_RENAME_INFORMATION pRenameInfo;
  196. //
  197. // Handle this event, SrHandleRename will check for eligibility
  198. //
  199. pRenameInfo = (PFILE_RENAME_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
  200. if ((pRenameInfo == NULL) ||
  201. (pIrpSp->Parameters.SetFile.Length < sizeof(FILE_RENAME_INFORMATION)) ||
  202. (pIrpSp->Parameters.SetFile.Length <
  203. (FIELD_OFFSET(FILE_RENAME_INFORMATION, FileName) +
  204. pRenameInfo->FileNameLength)) )
  205. {
  206. //
  207. // We don't have valid rename information, so just skip this
  208. // operation.
  209. //
  210. goto SrSetInformation_Skip;
  211. }
  212. return SrpSetRenameInfo( pExtension, pIrp );
  213. }
  214. case FileLinkInformation: //Create HardLink
  215. {
  216. PFILE_LINK_INFORMATION pLinkInfo;
  217. //
  218. // Handle this event, SrHandleRename will check for eligibility
  219. //
  220. pLinkInfo = (PFILE_LINK_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
  221. if ((pLinkInfo == NULL) ||
  222. (pIrpSp->Parameters.SetFile.Length < sizeof(FILE_LINK_INFORMATION)) ||
  223. (pIrpSp->Parameters.SetFile.Length <
  224. FIELD_OFFSET(FILE_LINK_INFORMATION, FileName) + pLinkInfo->FileNameLength) )
  225. {
  226. //
  227. // We don't have valid Link information, so just skip this
  228. // operation.
  229. //
  230. goto SrSetInformation_Skip;
  231. }
  232. return SrpSetLinkInfo( pExtension, pIrp );
  233. }
  234. default:
  235. //
  236. // Handle all other setInformation calls
  237. //
  238. SrHandleEvent( pExtension,
  239. SrEventAttribChange,
  240. pIrpSp->FileObject,
  241. NULL,
  242. NULL,
  243. NULL );
  244. break;
  245. }
  246. SrSetInformation_Skip:
  247. //
  248. // We don't need to wait for this operation to complete, so just
  249. // skip our stack location and pass this IO on to the next driver.
  250. //
  251. IoSkipCurrentIrpStackLocation( pIrp );
  252. return IoCallDriver( pExtension->pTargetDevice, pIrp );
  253. }
  254. /***************************************************************************++
  255. Routine Description:
  256. This handles renames and is called from SrSetInformation.
  257. This bypasses the normal path of SrHandleEvent as work needs to be done
  258. even if the file is not interesting. It's possible that the new name
  259. is an interesting name, which needs to be logged as a new create. Plus
  260. it might be clobbering an interesting file, in which case we need to
  261. backup that interesting file.
  262. Arguments:
  263. pExtension - SR extension for this volume
  264. pIrp - the Irp for this operation
  265. Return Value:
  266. NTSTATUS - Completion status.
  267. --***************************************************************************/
  268. NTSTATUS
  269. SrpSetRenameInfo(
  270. IN PSR_DEVICE_EXTENSION pExtension,
  271. IN PIRP pIrp
  272. )
  273. {
  274. NTSTATUS eventStatus = STATUS_SUCCESS;
  275. NTSTATUS IrpStatus;
  276. PFILE_OBJECT pFileObject;
  277. PFILE_RENAME_INFORMATION pRenameInfo;
  278. PIO_STACK_LOCATION pIrpSp;
  279. PUNICODE_STRING pNewName = NULL;
  280. USHORT NewNameStreamLength = 0;
  281. UNICODE_STRING NameToOpen;
  282. PUNICODE_STRING pDestFileName = NULL;
  283. PSR_STREAM_CONTEXT pFileContext = NULL;
  284. PSR_STREAM_CONTEXT pNewFileContext = NULL;
  285. HANDLE newFileHandle = NULL;
  286. PFILE_OBJECT pNewFileObject = NULL;
  287. ULONG CreateOptions;
  288. OBJECT_ATTRIBUTES ObjectAttributes;
  289. IO_STATUS_BLOCK IoStatusBlock;
  290. BOOLEAN NewNameInteresting = FALSE;
  291. BOOLEAN newNameIsDirectory;
  292. BOOLEAN releaseLock = FALSE;
  293. BOOLEAN setRenamingStateInFileContext = FALSE;
  294. BOOLEAN doPostProcessing = FALSE;
  295. BOOLEAN renamingSelf = FALSE;
  296. KEVENT eventToWaitOn;
  297. PUNICODE_STRING pShortName = NULL;
  298. UNICODE_STRING shortName;
  299. WCHAR shortNameBuffer[SR_SHORT_NAME_CHARS+1];
  300. BOOLEAN optimizeDelete = FALSE;
  301. BOOLEAN streamRename = FALSE;
  302. BOOLEAN fileBackedUp = FALSE;
  303. BOOLEAN exceedMaxPath = FALSE;
  304. //
  305. // The following macro must be at the end of local declarations
  306. // since it declares a variable only in DBG builds.
  307. //
  308. DECLARE_EXPECT_ERROR_FLAG(expectError);
  309. PAGED_CODE();
  310. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  311. ASSERT( IS_VALID_IRP( pIrp ) );
  312. pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
  313. pFileObject = pIrpSp->FileObject;
  314. pRenameInfo = pIrp->AssociatedIrp.SystemBuffer;
  315. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  316. //
  317. // Initalize return values
  318. //
  319. try
  320. {
  321. //
  322. // does the caller have DELETE access (it's required).
  323. //
  324. if (pFileObject->DeleteAccess == 0)
  325. leave;
  326. //
  327. // should we short circuit out of here for testing mode?
  328. //
  329. if (global->DontBackup)
  330. leave;
  331. //
  332. // Get the context for the current file
  333. //
  334. eventStatus = SrGetContext( pExtension,
  335. pFileObject,
  336. SrEventFileRename,
  337. &pFileContext );
  338. if (!NT_SUCCESS( eventStatus ))
  339. leave;
  340. //
  341. // If this is not a directory then see if the extension is
  342. // interesting.
  343. //
  344. if (!FlagOn(pFileContext->Flags,CTXFL_IsDirectory))
  345. {
  346. UNICODE_STRING destName;
  347. destName.Buffer = pRenameInfo->FileName;
  348. destName.Length = (USHORT)pRenameInfo->FileNameLength;
  349. destName.MaximumLength = (USHORT)pRenameInfo->FileNameLength;
  350. //
  351. // First check to see if this is a stream name change. If so,
  352. // we determine the "interesting-ness" of the new name from
  353. // the "interesting-ness" of the current name.
  354. //
  355. if ((destName.Length > 0) &&
  356. (destName.Buffer[0] == L':'))
  357. {
  358. //
  359. // This is a stream rename, so the "interesting-ness" of the
  360. // new name is the same as the "interesting-ness" of the old
  361. // name, since "interesting-ness" is determined by the file
  362. // name with out the stream component.
  363. //
  364. NewNameInteresting = BooleanFlagOn( pFileContext->Flags,
  365. CTXFL_IsInteresting );
  366. streamRename = TRUE;
  367. }
  368. else
  369. {
  370. //
  371. // This is not a stream name change, so see if this new name
  372. // has an interesting extension.
  373. //
  374. eventStatus = SrIsExtInteresting( &destName,
  375. &NewNameInteresting );
  376. if (!NT_SUCCESS( eventStatus ))
  377. leave;
  378. }
  379. }
  380. else
  381. {
  382. //
  383. // all directories are interesting unless explicitly excluded.
  384. //
  385. NewNameInteresting = TRUE;
  386. }
  387. //
  388. // If both are not interesting, ignore it. we make this check
  389. // twice in this routine. Once here to weed out any non-interesting
  390. // events, and another after checking path exclusions, because some
  391. // that was potentially interesting could have just become non
  392. // interesting. This let's us get out quicker for non interesting
  393. // renames.
  394. //
  395. if (!FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && !NewNameInteresting)
  396. {
  397. //
  398. // Neither the file we are renaming or the new name are
  399. // interesting. But we still need to cleanup the context
  400. // because it may be renamed to something interesting in
  401. // the future.
  402. //
  403. SrpSetRenamingState( pExtension,
  404. pFileContext );
  405. setRenamingStateInFileContext = TRUE;
  406. leave;
  407. }
  408. //
  409. // check the path exclusions
  410. //
  411. //
  412. // Get the full path for the target. Note that we will translate
  413. // reasonable errors to status success and return. This way we
  414. // will not log the event because we know the real operation should
  415. // fail.
  416. //
  417. {
  418. BOOLEAN reasonableErrorInDestPath = FALSE;
  419. eventStatus = SrpExpandDestPath( pExtension,
  420. pRenameInfo->RootDirectory,
  421. pRenameInfo->FileNameLength,
  422. pRenameInfo->FileName,
  423. pFileContext,
  424. pFileObject,
  425. &pNewName,
  426. &NewNameStreamLength,
  427. &reasonableErrorInDestPath );
  428. if (!NT_SUCCESS_NO_DBGBREAK( eventStatus ))
  429. {
  430. if (reasonableErrorInDestPath)
  431. {
  432. SET_EXPECT_ERROR_FLAG( expectError );
  433. eventStatus = STATUS_SUCCESS;
  434. }
  435. leave;
  436. }
  437. }
  438. ASSERT(pNewName != NULL);
  439. //
  440. // We now have the full destination name (whew!)
  441. //
  442. //
  443. // Check to see if the target for the rename is longer than
  444. // SR_MAX_FILENAME_LENGTH. If it is, we will treat the target name as
  445. // uninteresting.
  446. //
  447. if (!IS_FILENAME_VALID_LENGTH( pExtension,
  448. pNewName,
  449. NewNameStreamLength ))
  450. {
  451. NewNameInteresting = FALSE;
  452. exceedMaxPath = TRUE;
  453. if (!FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && !NewNameInteresting)
  454. {
  455. //
  456. // Neither the file we are renaming or the new name are
  457. // interesting. But we still need to cleanup the context
  458. // because it may be renamed to something interesting in
  459. // the future.
  460. //
  461. SrpSetRenamingState( pExtension,
  462. pFileContext );
  463. setRenamingStateInFileContext = TRUE;
  464. leave;
  465. }
  466. }
  467. //
  468. // We only need to do the following sets of checks if this is not
  469. // a stream rename.
  470. //
  471. if (!streamRename && !exceedMaxPath)
  472. {
  473. //
  474. // See if we are still on the same volume
  475. //
  476. if (!RtlPrefixUnicodeString( pExtension->pNtVolumeName,
  477. pNewName,
  478. TRUE ))
  479. {
  480. //
  481. // We are not on the same volume. This is possible if they used
  482. // some sort of symbolic link that was not understood. For the
  483. // most part these can be ignored, this is not a win32 client.
  484. // CODEWORK:paulmcd: we could expand the sym links ourselves
  485. //
  486. ASSERT(!"SR: Figure out how rename switched volumes unexpectedly!");
  487. SrTrace( NOTIFY, ("sr!SrHandleRename: ignoring rename to %wZ, used symlink\n",
  488. pNewName ));
  489. SET_EXPECT_ERROR_FLAG( expectError );
  490. leave;
  491. }
  492. //
  493. // Now see if the new path is interesting.
  494. //
  495. eventStatus = SrIsPathInteresting( pNewName,
  496. pExtension->pNtVolumeName,
  497. BooleanFlagOn(pFileContext->Flags,CTXFL_IsDirectory),
  498. &NewNameInteresting );
  499. if (!NT_SUCCESS( eventStatus ))
  500. leave;
  501. //
  502. // if both are not interesting, ignore it
  503. //
  504. if (!FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && !NewNameInteresting)
  505. {
  506. //
  507. // Neither the file we are renaming or the new name are
  508. // interesting. But we still need to cleanup the context
  509. // because it may be renamed to something interesting in
  510. // the future.
  511. //
  512. SrpSetRenamingState( pExtension,
  513. pFileContext );
  514. setRenamingStateInFileContext = TRUE;
  515. leave;
  516. }
  517. }
  518. /////////////////////////////////////////////////////////////////////
  519. //
  520. // See if destination file exists
  521. //
  522. /////////////////////////////////////////////////////////////////////
  523. //
  524. // Always open the destination file to see if it is there, even if
  525. // it is not interesting. We do this because we need a resonable
  526. // guess if the operation is going to fail or succeed so we don't
  527. // log the wrong information.
  528. //
  529. // If we've got a stream open, we need to play some tricks to get the
  530. // stream component exposed in the file name.
  531. //
  532. if (streamRename)
  533. {
  534. NameToOpen.Length = pNewName->Length + NewNameStreamLength;
  535. }
  536. else
  537. {
  538. NameToOpen.Length = pNewName->Length;
  539. }
  540. NameToOpen.MaximumLength = pNewName->MaximumLength;
  541. NameToOpen.Buffer = pNewName->Buffer;
  542. InitializeObjectAttributes( &ObjectAttributes,
  543. &NameToOpen,
  544. (OBJ_KERNEL_HANDLE | // don't let usermode trash myhandle
  545. OBJ_FORCE_ACCESS_CHECK), // force ACL checking
  546. NULL,
  547. NULL );
  548. //
  549. // start out assuming the dest file is a directory if the source
  550. // file is one then set the desired create options
  551. //
  552. newNameIsDirectory = BooleanFlagOn(pFileContext->Flags,CTXFL_IsDirectory);
  553. CreateOptions = (newNameIsDirectory ? FILE_DIRECTORY_FILE : 0);
  554. RetryOpenExisting:
  555. eventStatus = SrIoCreateFile( &newFileHandle,
  556. DELETE,
  557. &ObjectAttributes,
  558. &IoStatusBlock,
  559. NULL, // AllocationSize
  560. FILE_ATTRIBUTE_NORMAL,
  561. FILE_SHARE_READ|
  562. FILE_SHARE_WRITE|
  563. FILE_SHARE_DELETE, // ShareAccess
  564. FILE_OPEN, // OPEN_EXISTING
  565. FILE_SYNCHRONOUS_IO_NONALERT |
  566. CreateOptions,
  567. NULL,
  568. 0, // EaLength
  569. IO_IGNORE_SHARE_ACCESS_CHECK,
  570. pExtension->pTargetDevice );
  571. if (eventStatus == STATUS_OBJECT_NAME_NOT_FOUND)
  572. {
  573. //
  574. // looks like there is no new file
  575. //
  576. eventStatus = STATUS_SUCCESS;
  577. }
  578. else if (eventStatus == STATUS_ACCESS_DENIED)
  579. {
  580. //
  581. // We don't have permission to open this file with the
  582. // permission necessary to replace the target file, so the
  583. // caller's request should also fail. We can stop our
  584. // processing now and exit, but we don't need to disable the
  585. // volume.
  586. //
  587. eventStatus = STATUS_SUCCESS;
  588. SET_EXPECT_ERROR_FLAG( expectError );
  589. leave;
  590. }
  591. else if (eventStatus == STATUS_NOT_A_DIRECTORY)
  592. {
  593. //
  594. // are we renaming a directory to a file? this is ok, but we need
  595. // to open the target as a file, not a directory
  596. //
  597. if (CreateOptions == 0)
  598. {
  599. //
  600. // we already tried the reopen, it didn't work, bad.
  601. //
  602. ASSERT(!"SR: This is an unexpected error, figure out how we got it!");
  603. leave;
  604. }
  605. CreateOptions = 0;
  606. newNameIsDirectory = FALSE;
  607. goto RetryOpenExisting;
  608. //
  609. // was there some other error ?
  610. //
  611. }
  612. else if (eventStatus == STATUS_SHARING_VIOLATION ||
  613. !NT_SUCCESS( eventStatus ))
  614. {
  615. leave;
  616. }
  617. else
  618. {
  619. ASSERT(NT_SUCCESS(eventStatus));
  620. //
  621. // SUCCESS! the dest file already exists.. are we allowed to
  622. // clobber it?
  623. //
  624. //
  625. // reference the file object
  626. //
  627. eventStatus = ObReferenceObjectByHandle( newFileHandle,
  628. 0,
  629. *IoFileObjectType,
  630. KernelMode,
  631. &pNewFileObject,
  632. NULL );
  633. if (!NT_SUCCESS( eventStatus ))
  634. leave;
  635. //
  636. // See if we are renaming to our self. If so then don't log the
  637. // destination but do log the rename.
  638. //
  639. renamingSelf = SrpCheckForSameFile( pFileObject,
  640. pNewFileObject );
  641. //
  642. // We know the destination exists, see if we are allowed to clobber
  643. // it. If not and we are not renaming to our self then the operation
  644. // will fail, don't bother handling it.
  645. //
  646. if (!pRenameInfo->ReplaceIfExists && !renamingSelf)
  647. {
  648. SET_EXPECT_ERROR_FLAG( expectError );
  649. leave;
  650. }
  651. //
  652. // Note: Directories cannot be renamed over other directories,
  653. // the file system doesn't allow it (unless they are being renamed
  654. // over themselves). However, directories can
  655. // be renamed over other files.
  656. //
  657. // Quit if renaming a directory over a different directory because
  658. // we know that will fail.
  659. //
  660. if (FlagOn(pFileContext->Flags,CTXFL_IsDirectory) &&
  661. (newNameIsDirectory))
  662. {
  663. #if DBG
  664. if (!renamingSelf)
  665. {
  666. SET_EXPECT_ERROR_FLAG( expectError );
  667. }
  668. #endif
  669. leave;
  670. }
  671. //
  672. // If the destination file is not our own file then handle
  673. // creating a deletion event.
  674. //
  675. if (!renamingSelf)
  676. {
  677. //
  678. // Get the context for the destination file. We do this now
  679. // so that we can mark that we are renaming this file. This
  680. // will cause anyone else who tries to access this file while
  681. // the rename in progress to create a temporary context.
  682. // We do this so there won't be any windows when someone
  683. // tries to access the wrong file and gets the wrong state.
  684. // NOTE: We do want to do this even for files which are NOT
  685. // interesting so the context is updated correctly.
  686. //
  687. eventStatus = SrGetContext( pExtension,
  688. pNewFileObject,
  689. SrEventFileDelete|
  690. SrEventNoOptimization|
  691. SrEventSimulatedDelete,
  692. &pNewFileContext );
  693. if (!NT_SUCCESS( eventStatus ))
  694. leave;
  695. //
  696. // If we are renaming to a directory just leave because this
  697. // will fail. Release the context.
  698. //
  699. if (FlagOn(pNewFileContext->Flags,CTXFL_IsDirectory))
  700. {
  701. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_IsDirectory));
  702. newNameIsDirectory = TRUE;
  703. SrReleaseContext( pNewFileContext );
  704. pNewFileContext = NULL; //so we don't free it later
  705. leave;
  706. }
  707. //
  708. // The destination file exists and is interesting, log that we
  709. // are delting it.
  710. //
  711. if (NewNameInteresting)
  712. {
  713. //
  714. // Log that we are changing the destination file
  715. //
  716. eventStatus = SrpReplacingDestinationFile(
  717. pExtension,
  718. pNewFileObject,
  719. pNewFileContext );
  720. if (!NT_SUCCESS( eventStatus ))
  721. leave;
  722. fileBackedUp = TRUE;
  723. //
  724. // These names can be different because one could be a
  725. // short name and one could be a long name for the same
  726. // file.
  727. //
  728. // ASSERT((NULL == pNewFileContext) ||
  729. // RtlEqualUnicodeString(pNewName,
  730. // &pNewFileContext->FileName,
  731. // TRUE));
  732. }
  733. }
  734. }
  735. //
  736. // Whether the file existed or not, handle purging our logging state
  737. //
  738. if (NewNameInteresting)
  739. {
  740. //
  741. // clear the backup history for this new file
  742. //
  743. if (newNameIsDirectory)
  744. {
  745. //
  746. // we need to clear all entries that prefix match this
  747. // dest directory, so that they now have new histories as
  748. // they are potentially new files.
  749. //
  750. HashProcessEntries( pExtension->pBackupHistory,
  751. SrResetHistory,
  752. pNewName );
  753. }
  754. else
  755. {
  756. //
  757. // its a simple file, clear the single entry
  758. //
  759. eventStatus = SrResetBackupHistory( pExtension,
  760. pNewName,
  761. NewNameStreamLength,
  762. SrEventInvalid );
  763. if (!NT_SUCCESS( eventStatus ))
  764. leave;
  765. }
  766. }
  767. //
  768. // When we get here we think the operation will succeed. Mark
  769. // the contexts so we won't try to use them while we are in
  770. // the middle of the rename
  771. //
  772. SrpSetRenamingState( pExtension, pFileContext );
  773. setRenamingStateInFileContext = TRUE;
  774. //
  775. // At this point we think the rename will succeed and we care
  776. // about it.
  777. //
  778. // If this is a stream rename, see if we have already backed
  779. // up the file. If not, we need to do that backup now.
  780. //
  781. // We don't just log renames of stream renames because Win32 doesn't
  782. // support renaming streams. Therefore, it is difficult for Restore
  783. // do undo this rename. Since stream rename occur infrequently, we
  784. // just do a full backup here. This also means that we don't need
  785. // to do any work after the rename operation has completed.
  786. //
  787. if (streamRename && !fileBackedUp)
  788. {
  789. eventStatus = SrpReplacingDestinationFile( pExtension,
  790. pFileObject,
  791. pFileContext );
  792. leave;
  793. }
  794. //
  795. // Get the sort name of the source file so we can
  796. // log it.
  797. //
  798. RtlInitEmptyUnicodeString( &shortName,
  799. shortNameBuffer,
  800. sizeof(shortNameBuffer) );
  801. eventStatus = SrGetShortFileName( pExtension,
  802. pFileObject,
  803. &shortName );
  804. if (STATUS_OBJECT_NAME_NOT_FOUND == eventStatus)
  805. {
  806. //
  807. // This file doesn't have a short name, so just leave
  808. // pShortName equal to NULL.
  809. //
  810. eventStatus = STATUS_SUCCESS;
  811. }
  812. else if (!NT_SUCCESS(eventStatus))
  813. {
  814. //
  815. // We hit an unexpected error, so leave.
  816. //
  817. leave;
  818. }
  819. else
  820. {
  821. pShortName = &shortName;
  822. }
  823. //
  824. // See if this a file or directory moving OUT of monitored space.
  825. // If so we need to do some work before the file is moved.
  826. //
  827. if (FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && !NewNameInteresting)
  828. {
  829. if (FlagOn(pFileContext->Flags,CTXFL_IsDirectory))
  830. {
  831. //
  832. // This is a directory, create delete events for all
  833. // interesting files in the tree before it goes away because
  834. // of the rename.
  835. //
  836. eventStatus = SrHandleDirectoryRename( pExtension,
  837. &pFileContext->FileName,
  838. TRUE );
  839. if (!NT_SUCCESS( eventStatus ))
  840. leave;
  841. }
  842. else
  843. {
  844. UNICODE_STRING volRestoreLoc;
  845. UNICODE_STRING destName;
  846. //
  847. // It's a file moving out of monitored space, back it up
  848. // before the rename.
  849. //
  850. // Make sure we aren't renaming it into our special store, we
  851. // want to ignore those operations. Get the store name.
  852. //
  853. RtlInitUnicodeString( &volRestoreLoc, GENERAL_RESTORE_LOCATION);
  854. //
  855. // Get the destination name with the volume name stripped off
  856. // the front (Since we know we are on the same volume).
  857. //
  858. ASSERT(pNewName->Length >= pExtension->pNtVolumeName->Length);
  859. destName.Buffer = &pNewName->Buffer[
  860. pExtension->pNtVolumeName->Length /
  861. sizeof(WCHAR) ];
  862. destName.Length = pNewName->Length -
  863. pExtension->pNtVolumeName->Length;
  864. destName.MaximumLength = destName.Length;
  865. if (RtlPrefixUnicodeString( &volRestoreLoc,
  866. &destName,
  867. TRUE ))
  868. {
  869. //
  870. // it is going to our store. skip it
  871. //
  872. leave;
  873. }
  874. eventStatus = SrHandleFileRenameOutOfMonitoredSpace(
  875. pExtension,
  876. pFileObject,
  877. pFileContext,
  878. &optimizeDelete,
  879. &pDestFileName );
  880. if (!NT_SUCCESS( eventStatus ))
  881. {
  882. leave;
  883. }
  884. #if DBG
  885. if (optimizeDelete)
  886. {
  887. ASSERT( pDestFileName == NULL );
  888. }
  889. else
  890. {
  891. ASSERT( pDestFileName != NULL );
  892. }
  893. #endif
  894. }
  895. }
  896. //
  897. // Mark that we want to do post-operation processing
  898. //
  899. doPostProcessing = TRUE;
  900. }
  901. finally
  902. {
  903. //
  904. // If the destination file is open, close it now (so we can do the rename)
  905. //
  906. if (pNewFileObject != NULL)
  907. {
  908. ObDereferenceObject(pNewFileObject);
  909. NULLPTR(pNewFileObject);
  910. }
  911. if (newFileHandle != NULL)
  912. {
  913. ZwClose(newFileHandle);
  914. NULLPTR(newFileHandle);
  915. }
  916. }
  917. /////////////////////////////////////////////////////////////////////
  918. //
  919. // Send the operation to the file system
  920. //
  921. /////////////////////////////////////////////////////////////////////
  922. //
  923. // Setup to wait for the operation to complete
  924. //
  925. KeInitializeEvent( &eventToWaitOn, NotificationEvent, FALSE );
  926. IoCopyCurrentIrpStackLocationToNext( pIrp );
  927. IoSetCompletionRoutine( pIrp,
  928. SrStopProcessingCompletion,
  929. &eventToWaitOn,
  930. TRUE,
  931. TRUE,
  932. TRUE );
  933. IrpStatus = IoCallDriver(pExtension->pTargetDevice, pIrp);
  934. if (STATUS_PENDING == IrpStatus)
  935. {
  936. NTSTATUS localStatus;
  937. localStatus = KeWaitForSingleObject( &eventToWaitOn,
  938. Executive,
  939. KernelMode,
  940. FALSE,
  941. NULL );
  942. ASSERT(STATUS_SUCCESS == localStatus);
  943. }
  944. //
  945. // The operation has completed, get the final status from the Irp.
  946. //
  947. IrpStatus = pIrp->IoStatus.Status;
  948. //
  949. // We are done with the Irp, so complete it now.
  950. //
  951. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  952. try
  953. {
  954. //
  955. // In DBG builds, this will verify that the operation failed with the
  956. // file system when we expected it to. Otherwise, it will assert so
  957. // we can debug why we missed this case.
  958. //
  959. CHECK_FOR_EXPECTED_ERROR( expectError, IrpStatus );
  960. //
  961. // leave if:
  962. // - the rename failed
  963. // - we got an error eariler in setting up for the rename
  964. // - they tolds us to not continue processing
  965. //
  966. if (!NT_SUCCESS_NO_DBGBREAK( IrpStatus ) ||
  967. !NT_SUCCESS_NO_DBGBREAK( eventStatus ) ||
  968. !doPostProcessing)
  969. {
  970. leave;
  971. }
  972. ASSERT(pFileContext != NULL);
  973. /////////////////////////////////////////////////////////////////////
  974. //
  975. // LOG EVENTS FOR ORIGINAL FILE
  976. //
  977. /////////////////////////////////////////////////////////////////////
  978. //
  979. // We are now going to log the rename, grab the activity lock
  980. //
  981. SrAcquireActivityLockShared( pExtension );
  982. releaseLock = TRUE;
  983. //
  984. // Now that we have the shared activity lock, check that the volume
  985. // hasn't been disable before we do unnecessary work.
  986. //
  987. if (!SR_LOGGING_ENABLED(pExtension))
  988. leave;
  989. //
  990. // is this the first interesting event on this volume?
  991. //
  992. eventStatus = SrCheckVolume( pExtension, FALSE );
  993. if (!NT_SUCCESS( eventStatus ))
  994. leave;
  995. //
  996. // Log the correct state
  997. //
  998. if (FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && NewNameInteresting)
  999. {
  1000. //
  1001. // Both files are interesting, log the rename
  1002. //
  1003. #if DBG
  1004. if (pShortName != NULL )
  1005. {
  1006. ASSERT(shortName.Length > 0 && shortName.Length <= (12*sizeof(WCHAR)));
  1007. }
  1008. #endif
  1009. SrLogEvent( pExtension,
  1010. ((FlagOn(pFileContext->Flags,CTXFL_IsDirectory)) ?
  1011. SrEventDirectoryRename :
  1012. SrEventFileRename),
  1013. pFileObject,
  1014. &pFileContext->FileName,
  1015. pFileContext->StreamNameLength,
  1016. NULL,
  1017. pNewName,
  1018. NewNameStreamLength,
  1019. pShortName );
  1020. }
  1021. else if (FlagOn(pFileContext->Flags,CTXFL_IsDirectory))
  1022. {
  1023. if (!FlagOn(pFileContext->Flags,CTXFL_IsInteresting) &&
  1024. NewNameInteresting)
  1025. {
  1026. //
  1027. // The rename on the directory succeeded and the directory was
  1028. // renamed INTO monitored space. We need to log creates for all
  1029. // the children of this directory.
  1030. //
  1031. eventStatus = SrHandleDirectoryRename( pExtension,
  1032. pNewName,
  1033. FALSE );
  1034. if (!NT_SUCCESS( eventStatus ))
  1035. leave;
  1036. }
  1037. //
  1038. // We logged all of the directory operations before it occured
  1039. // for the case of moving a directory OUT of monitored space
  1040. //
  1041. }
  1042. else if (FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && !NewNameInteresting)
  1043. {
  1044. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_IsDirectory));
  1045. //
  1046. // Since the "interesting-ness" of a file is determined at the
  1047. // file level, a stream rename should never get down this path.
  1048. //
  1049. ASSERT( pFileContext->StreamNameLength == 0);
  1050. //
  1051. // Log this as a delete (we backed up the file before the
  1052. // rename occured).
  1053. //
  1054. if (optimizeDelete)
  1055. {
  1056. //
  1057. // This file was either created during this restore point or
  1058. // has already been backed up, therefore, we want to log the
  1059. // a delete that has been optimized out.
  1060. //
  1061. eventStatus = SrLogEvent( pExtension,
  1062. SrEventFileDelete,
  1063. NULL,
  1064. &pFileContext->FileName,
  1065. 0,
  1066. NULL,
  1067. NULL,
  1068. 0,
  1069. NULL );
  1070. }
  1071. else
  1072. {
  1073. eventStatus = SrLogEvent( pExtension,
  1074. SrEventFileDelete,
  1075. pFileObject,
  1076. &pFileContext->FileName,
  1077. 0,
  1078. pDestFileName,
  1079. NULL,
  1080. 0,
  1081. &shortName );
  1082. }
  1083. if (!NT_SUCCESS( eventStatus ))
  1084. leave;
  1085. }
  1086. else if (!FlagOn(pFileContext->Flags,CTXFL_IsInteresting) && NewNameInteresting)
  1087. {
  1088. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_IsDirectory));
  1089. //
  1090. // Since the "interesting-ness" of a file is determined at the
  1091. // file level, a stream rename should never get down this path.
  1092. //
  1093. ASSERT( NewNameStreamLength == 0);
  1094. //
  1095. // it's a file being brought into monitored space, log it
  1096. //
  1097. eventStatus = SrLogEvent( pExtension,
  1098. SrEventFileCreate,
  1099. NULL, // pFileObject
  1100. pNewName,
  1101. 0,
  1102. NULL,
  1103. NULL,
  1104. 0,
  1105. NULL );
  1106. if (!NT_SUCCESS( eventStatus ))
  1107. leave;
  1108. //
  1109. // ignore later mods
  1110. //
  1111. eventStatus = SrMarkFileBackedUp( pExtension,
  1112. pNewName,
  1113. 0,
  1114. SrEventFileCreate,
  1115. SR_IGNORABLE_EVENT_TYPES );
  1116. if (!NT_SUCCESS( eventStatus ))
  1117. leave;
  1118. }
  1119. }
  1120. finally
  1121. {
  1122. //
  1123. // Check for any bad errors if this operation succeeded;
  1124. // If the pFileContext is NULL, this error was encountered in
  1125. // SrGetContext which already generated the volume error.
  1126. //
  1127. if (NT_SUCCESS_NO_DBGBREAK( IrpStatus ) &&
  1128. CHECK_FOR_VOLUME_ERROR(eventStatus) &&
  1129. (pFileContext != NULL))
  1130. {
  1131. //
  1132. // trigger the failure notification to the service
  1133. //
  1134. SrNotifyVolumeError( pExtension,
  1135. &pFileContext->FileName,
  1136. eventStatus,
  1137. FlagOn(pFileContext->Flags,CTXFL_IsDirectory) ?
  1138. SrEventDirectoryRename:
  1139. SrEventFileRename );
  1140. }
  1141. if (releaseLock)
  1142. {
  1143. SrReleaseActivityLock( pExtension );
  1144. }
  1145. if (NULL != pNewName)
  1146. {
  1147. SrFreeFileNameBuffer(pNewName);
  1148. NULLPTR(pNewName);
  1149. }
  1150. if (NULL != pDestFileName)
  1151. {
  1152. SrFreeFileNameBuffer(pDestFileName);
  1153. NULLPTR(pDestFileName);
  1154. }
  1155. //
  1156. // Cleanup contexts from rename state
  1157. //
  1158. if (pFileContext != NULL)
  1159. {
  1160. if (setRenamingStateInFileContext)
  1161. {
  1162. if (FlagOn(pFileContext->Flags,CTXFL_IsDirectory))
  1163. {
  1164. ASSERT(pExtension->ContextCtrl.AllContextsTemporary > 0);
  1165. InterlockedDecrement( &pExtension->ContextCtrl.AllContextsTemporary );
  1166. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_DoNotUse));
  1167. }
  1168. else
  1169. {
  1170. ASSERT(FlagOn(pFileContext->Flags,CTXFL_DoNotUse));
  1171. }
  1172. SrDeleteContext( pExtension, pFileContext );
  1173. }
  1174. else
  1175. {
  1176. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_DoNotUse));
  1177. }
  1178. SrReleaseContext( pFileContext );
  1179. NULLPTR(pFileContext);
  1180. }
  1181. if (pNewFileContext != NULL)
  1182. {
  1183. ASSERT(!FlagOn(pNewFileContext->Flags,CTXFL_IsDirectory));
  1184. SrReleaseContext( pNewFileContext );
  1185. NULLPTR(pNewFileContext);
  1186. }
  1187. }
  1188. return IrpStatus;
  1189. }
  1190. /***************************************************************************++
  1191. Routine Description:
  1192. This handles the creation of hardlinks and is called from SrSetInformation.
  1193. This bypasses the normal path of SrHandleEvent to handle the following
  1194. cases:
  1195. - If an interesting file is going to be overwritten as the result of this
  1196. hardlink being created, we must backup the original file.
  1197. - If a hardlink with an interesting name is being created, we need to log
  1198. this file creation.
  1199. Arguments:
  1200. pExtension - the SR device extension for this volume.
  1201. pIrp - the Irp representing this SetLinkInformation operation.
  1202. Return Value:
  1203. NTSTATUS - Completion status.
  1204. --***************************************************************************/
  1205. NTSTATUS
  1206. SrpSetLinkInfo(
  1207. IN PSR_DEVICE_EXTENSION pExtension,
  1208. IN PIRP pIrp
  1209. )
  1210. {
  1211. NTSTATUS EventStatus = STATUS_SUCCESS;
  1212. NTSTATUS IrpStatus;
  1213. PFILE_OBJECT pFileObject;
  1214. PFILE_LINK_INFORMATION pLinkInfo;
  1215. PIO_STACK_LOCATION pIrpSp;
  1216. PUNICODE_STRING pLinkName = NULL;
  1217. USHORT LinkNameStreamLength = 0;
  1218. PSR_STREAM_CONTEXT pFileContext = NULL;
  1219. PSR_STREAM_CONTEXT pLinkFileContext = NULL;
  1220. HANDLE LinkFileHandle = NULL;
  1221. PFILE_OBJECT pLinkFileObject = NULL;
  1222. OBJECT_ATTRIBUTES ObjectAttributes;
  1223. IO_STATUS_BLOCK IoStatusBlock;
  1224. BOOLEAN LinkNameInteresting = FALSE;
  1225. BOOLEAN ReleaseLock = FALSE;
  1226. BOOLEAN DoPostProcessing = FALSE;
  1227. KEVENT EventToWaitOn;
  1228. //
  1229. // The following macro must be at the end of local declarations
  1230. // since it declares a variable only in DBG builds.
  1231. //
  1232. DECLARE_EXPECT_ERROR_FLAG( ExpectError );
  1233. PAGED_CODE();
  1234. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  1235. ASSERT( IS_VALID_IRP( pIrp ) );
  1236. pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
  1237. pFileObject = pIrpSp->FileObject;
  1238. pLinkInfo = pIrp->AssociatedIrp.SystemBuffer;
  1239. ASSERT(IS_VALID_FILE_OBJECT(pFileObject));
  1240. try
  1241. {
  1242. //
  1243. // should we short circuit out of here for testing mode?
  1244. //
  1245. if (global->DontBackup)
  1246. leave;
  1247. //
  1248. // Get the context for the current file
  1249. //
  1250. EventStatus = SrGetContext( pExtension,
  1251. pFileObject,
  1252. SrEventFileCreate,
  1253. &pFileContext );
  1254. if (!NT_SUCCESS( EventStatus ))
  1255. leave;
  1256. //
  1257. // If this is a directory, then we don't care about this operation
  1258. // since it is not possible to create hardlinks on directories.
  1259. //
  1260. if (FlagOn( pFileContext->Flags, CTXFL_IsDirectory ))
  1261. leave;
  1262. //
  1263. // We are creating a hardlink on this file. While we do the processing
  1264. // mark this context as CTXFL_DoNotUse so that other users of this
  1265. // stream will be guaranteed to get correct information.
  1266. //
  1267. RtlInterlockedSetBitsDiscardReturn(&pFileContext->Flags,CTXFL_DoNotUse);
  1268. /////////////////////////////////////////////////////////////////////
  1269. //
  1270. // Check to see if the hardlink name is interesting
  1271. //
  1272. /////////////////////////////////////////////////////////////////////
  1273. {
  1274. UNICODE_STRING destName;
  1275. destName.Buffer = pLinkInfo->FileName;
  1276. destName.Length = (USHORT)pLinkInfo->FileNameLength;
  1277. destName.MaximumLength = (USHORT)pLinkInfo->FileNameLength;
  1278. EventStatus = SrIsExtInteresting( &destName,
  1279. &LinkNameInteresting );
  1280. if (!NT_SUCCESS( EventStatus ))
  1281. {
  1282. leave;
  1283. }
  1284. }
  1285. //
  1286. // Get the full path for the hardlink name. Note that we will
  1287. // translate reasonable errors to status success and return. This way
  1288. // we will not log the event because we know the real operation should
  1289. // fail.
  1290. //
  1291. {
  1292. BOOLEAN reasonableErrorInDestPath = FALSE;
  1293. EventStatus = SrpExpandDestPath( pExtension,
  1294. pLinkInfo->RootDirectory,
  1295. pLinkInfo->FileNameLength,
  1296. pLinkInfo->FileName,
  1297. pFileContext,
  1298. pFileObject,
  1299. &pLinkName,
  1300. &LinkNameStreamLength,
  1301. &reasonableErrorInDestPath );
  1302. if (!NT_SUCCESS_NO_DBGBREAK( EventStatus ))
  1303. {
  1304. if (reasonableErrorInDestPath)
  1305. {
  1306. SET_EXPECT_ERROR_FLAG( ExpectError );
  1307. EventStatus = STATUS_SUCCESS;
  1308. }
  1309. leave;
  1310. }
  1311. //
  1312. // We can't have a stream component in this name, so if we do have
  1313. // one, this is also a malformed link name.
  1314. //
  1315. if (LinkNameStreamLength > 0)
  1316. {
  1317. SET_EXPECT_ERROR_FLAG( ExpectError );
  1318. EventStatus = STATUS_SUCCESS;
  1319. leave;
  1320. }
  1321. }
  1322. ASSERT(pLinkName != NULL);
  1323. //
  1324. // We now have the full destination name (whew!)
  1325. // See if we are still on the same volume
  1326. //
  1327. if (!RtlPrefixUnicodeString( pExtension->pNtVolumeName,
  1328. pLinkName,
  1329. TRUE ))
  1330. {
  1331. //
  1332. // Hardlinks must be on the same volume so this operation will
  1333. // fail.
  1334. //
  1335. SET_EXPECT_ERROR_FLAG( ExpectError );
  1336. leave;
  1337. }
  1338. //
  1339. // Make sure that the link name is not too long for us to monitor.
  1340. //
  1341. if (!IS_FILENAME_VALID_LENGTH( pExtension, pLinkName, 0 ))
  1342. {
  1343. //
  1344. // Link name is too long for us, so just leave now.
  1345. //
  1346. LinkNameInteresting = FALSE;
  1347. leave;
  1348. }
  1349. //
  1350. // Now see if the new path is interesting.
  1351. //
  1352. EventStatus = SrIsPathInteresting( pLinkName,
  1353. pExtension->pNtVolumeName,
  1354. FALSE,
  1355. &LinkNameInteresting );
  1356. if (!NT_SUCCESS( EventStatus ))
  1357. {
  1358. leave;
  1359. }
  1360. if (!LinkNameInteresting)
  1361. {
  1362. //
  1363. // The link name is not interesting so just cut out now.
  1364. //
  1365. leave;
  1366. }
  1367. /////////////////////////////////////////////////////////////////////
  1368. //
  1369. // See if hardlink file exists
  1370. //
  1371. /////////////////////////////////////////////////////////////////////
  1372. //
  1373. // If the hardlink name exists, we may need to back it up before this
  1374. // operation gets down to the file system.
  1375. //
  1376. InitializeObjectAttributes( &ObjectAttributes,
  1377. pLinkName,
  1378. (OBJ_KERNEL_HANDLE |
  1379. OBJ_FORCE_ACCESS_CHECK), // force ACL checking
  1380. NULL,
  1381. NULL );
  1382. EventStatus = SrIoCreateFile( &LinkFileHandle,
  1383. SYNCHRONIZE,
  1384. &ObjectAttributes,
  1385. &IoStatusBlock,
  1386. NULL, // AllocationSize
  1387. FILE_ATTRIBUTE_NORMAL,
  1388. FILE_SHARE_READ|
  1389. FILE_SHARE_WRITE|
  1390. FILE_SHARE_DELETE, // ShareAccess
  1391. FILE_OPEN, // OPEN_EXISTING
  1392. FILE_SYNCHRONOUS_IO_NONALERT |
  1393. FILE_NON_DIRECTORY_FILE,
  1394. NULL,
  1395. 0, // EaLength
  1396. IO_IGNORE_SHARE_ACCESS_CHECK,
  1397. pExtension->pTargetDevice );
  1398. if (EventStatus == STATUS_OBJECT_NAME_NOT_FOUND)
  1399. {
  1400. //
  1401. // looks like there is no new file
  1402. //
  1403. EventStatus = STATUS_SUCCESS;
  1404. }
  1405. else if (EventStatus == STATUS_ACCESS_DENIED)
  1406. {
  1407. //
  1408. // We don't have permission to open this file with the
  1409. // permission necessary to replace the target file, so the
  1410. // caller's request should also fail. We can stop our
  1411. // processing now and exit, but we don't need to disable the
  1412. // volume.
  1413. //
  1414. SET_EXPECT_ERROR_FLAG( ExpectError );
  1415. EventStatus = STATUS_SUCCESS;
  1416. leave;
  1417. }
  1418. else if (EventStatus == STATUS_FILE_IS_A_DIRECTORY)
  1419. {
  1420. //
  1421. // Does the hardlink name currently name a directory? This is not
  1422. // allowed, so just ignore the operation since it will fail.
  1423. //
  1424. SET_EXPECT_ERROR_FLAG( ExpectError );
  1425. EventStatus = STATUS_SUCCESS;
  1426. leave;
  1427. }
  1428. else if (!NT_SUCCESS( EventStatus ))
  1429. {
  1430. //
  1431. // We hit an unexpected error and we will handle this error
  1432. // below.
  1433. //
  1434. leave;
  1435. }
  1436. else
  1437. {
  1438. BOOLEAN linkingToSelf;
  1439. ASSERT(NT_SUCCESS(EventStatus));
  1440. //
  1441. // SUCCESS! the dest file already exists.. are we allowed to
  1442. // clobber it?
  1443. //
  1444. if (!pLinkInfo->ReplaceIfExists)
  1445. leave;
  1446. //
  1447. // We are allowed to overwrite the existing file, so now check
  1448. // to make sure that we aren't just recreating a hardlink that
  1449. // already exists.
  1450. //
  1451. EventStatus = ObReferenceObjectByHandle( LinkFileHandle,
  1452. 0,
  1453. *IoFileObjectType,
  1454. KernelMode,
  1455. &pLinkFileObject,
  1456. NULL );
  1457. if (!NT_SUCCESS( EventStatus ))
  1458. leave;
  1459. linkingToSelf = SrpCheckForSameFile( pFileObject,
  1460. pLinkFileObject );
  1461. //
  1462. // We only need to backup the hardlink file if we are not
  1463. // recreating a link to ourself.
  1464. //
  1465. if (!linkingToSelf)
  1466. {
  1467. //
  1468. // Get the context for the destination file.
  1469. //
  1470. EventStatus = SrGetContext( pExtension,
  1471. pLinkFileObject,
  1472. SrEventFileDelete|
  1473. SrEventNoOptimization|
  1474. SrEventSimulatedDelete,
  1475. &pLinkFileContext );
  1476. if (!NT_SUCCESS( EventStatus ))
  1477. leave;
  1478. ASSERT(!FlagOn(pLinkFileContext->Flags,CTXFL_IsDirectory));
  1479. ASSERT(FlagOn(pLinkFileContext->Flags,CTXFL_IsInteresting));
  1480. //
  1481. // Log that we are changing the destination file
  1482. //
  1483. EventStatus = SrpReplacingDestinationFile( pExtension,
  1484. pLinkFileObject,
  1485. pLinkFileContext );
  1486. if (!NT_SUCCESS( EventStatus ))
  1487. leave;
  1488. }
  1489. else
  1490. {
  1491. //
  1492. // We are just recreating an existing link to ourself. There
  1493. // is no need to log this.
  1494. //
  1495. leave;
  1496. }
  1497. }
  1498. //
  1499. // We have successfully gotten to this point, so we want to do
  1500. // post-operation processing to log the link creation.
  1501. //
  1502. DoPostProcessing = TRUE;
  1503. }
  1504. finally
  1505. {
  1506. //
  1507. // If the destination file is open, close it now (so we can do the rename)
  1508. //
  1509. if (NULL != pLinkFileObject)
  1510. {
  1511. ObDereferenceObject(pLinkFileObject);
  1512. NULLPTR(pLinkFileObject);
  1513. }
  1514. if (NULL != LinkFileHandle)
  1515. {
  1516. ZwClose(LinkFileHandle);
  1517. NULLPTR(LinkFileHandle);
  1518. }
  1519. if (NULL != pLinkFileContext)
  1520. {
  1521. SrReleaseContext( pLinkFileContext );
  1522. NULLPTR(pLinkFileContext);
  1523. }
  1524. }
  1525. /////////////////////////////////////////////////////////////////////
  1526. //
  1527. // Send the operation to the file system
  1528. //
  1529. /////////////////////////////////////////////////////////////////////
  1530. //
  1531. // Setup to wait for the operation to complete.
  1532. //
  1533. KeInitializeEvent( &EventToWaitOn, NotificationEvent, FALSE );
  1534. IoCopyCurrentIrpStackLocationToNext( pIrp );
  1535. IoSetCompletionRoutine( pIrp,
  1536. SrStopProcessingCompletion,
  1537. &EventToWaitOn,
  1538. TRUE,
  1539. TRUE,
  1540. TRUE );
  1541. IrpStatus = IoCallDriver(pExtension->pTargetDevice, pIrp);
  1542. if (STATUS_PENDING == IrpStatus)
  1543. {
  1544. NTSTATUS localStatus;
  1545. localStatus = KeWaitForSingleObject( &EventToWaitOn,
  1546. Executive,
  1547. KernelMode,
  1548. FALSE,
  1549. NULL );
  1550. ASSERT(STATUS_SUCCESS == localStatus);
  1551. }
  1552. //
  1553. // The operation has completed, get the final status from the Irp.
  1554. //
  1555. IrpStatus = pIrp->IoStatus.Status;
  1556. //
  1557. // We are done with the Irp, so complete it now.
  1558. //
  1559. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1560. try
  1561. {
  1562. //
  1563. // In DBG builds, this will verify that the operation failed with the
  1564. // file system when we expected it to. Otherwise, it will assert so
  1565. // we can debug why we missed this case.
  1566. //
  1567. CHECK_FOR_EXPECTED_ERROR( ExpectError, IrpStatus );
  1568. //
  1569. // leave if:
  1570. // - the link failed
  1571. // - we got an error eariler in setting up for the link
  1572. // - they tolds us to not continue processing
  1573. //
  1574. if (!NT_SUCCESS_NO_DBGBREAK( IrpStatus ) ||
  1575. !NT_SUCCESS_NO_DBGBREAK( EventStatus ) ||
  1576. !DoPostProcessing)
  1577. {
  1578. leave;
  1579. }
  1580. ASSERT(pLinkName != NULL);
  1581. /////////////////////////////////////////////////////////////////////
  1582. //
  1583. // Log the file creation for the hardlink file.
  1584. //
  1585. /////////////////////////////////////////////////////////////////////
  1586. //
  1587. // Before we do the logging work, we need to grab the activity lock
  1588. //
  1589. SrAcquireActivityLockShared( pExtension );
  1590. ReleaseLock = TRUE;
  1591. //
  1592. // Now that we have the shared activity lock, check that the volume
  1593. // hasn't been disable before we do unnecessary work.
  1594. //
  1595. if (!SR_LOGGING_ENABLED(pExtension))
  1596. leave;
  1597. //
  1598. // Is this the first interesting event on this volume?
  1599. //
  1600. EventStatus = SrCheckVolume( pExtension, FALSE );
  1601. if (!NT_SUCCESS( EventStatus ))
  1602. leave;
  1603. //
  1604. // Log the file creation
  1605. //
  1606. EventStatus = SrLogEvent( pExtension,
  1607. SrEventFileCreate,
  1608. NULL, // pFileObject
  1609. pLinkName,
  1610. 0,
  1611. NULL,
  1612. NULL,
  1613. 0,
  1614. NULL );
  1615. if (!NT_SUCCESS( EventStatus ))
  1616. leave;
  1617. //
  1618. // ignore later modifications
  1619. //
  1620. EventStatus = SrMarkFileBackedUp( pExtension,
  1621. pLinkName,
  1622. 0,
  1623. SrEventFileCreate,
  1624. SR_IGNORABLE_EVENT_TYPES );
  1625. }
  1626. finally
  1627. {
  1628. //
  1629. // Check for any bad errors if this operation was successful.
  1630. //
  1631. if (NT_SUCCESS_NO_DBGBREAK( IrpStatus ) &&
  1632. CHECK_FOR_VOLUME_ERROR( EventStatus ))
  1633. {
  1634. //
  1635. // trigger the failure notification to the service
  1636. //
  1637. SrNotifyVolumeError( pExtension,
  1638. pLinkName,
  1639. EventStatus,
  1640. SrEventFileCreate );
  1641. }
  1642. if (ReleaseLock)
  1643. {
  1644. SrReleaseActivityLock( pExtension );
  1645. }
  1646. if (NULL != pLinkName)
  1647. {
  1648. SrFreeFileNameBuffer(pLinkName);
  1649. NULLPTR(pLinkName);
  1650. }
  1651. if (NULL != pFileContext)
  1652. {
  1653. if (FlagOn(pFileContext->Flags,CTXFL_DoNotUse))
  1654. {
  1655. //
  1656. // We marked this context as DoNotUse, so we need to delete it from
  1657. // the lists now that we are done with it.
  1658. //
  1659. SrDeleteContext( pExtension, pFileContext );
  1660. }
  1661. SrReleaseContext( pFileContext );
  1662. NULLPTR(pFileContext);
  1663. }
  1664. }
  1665. return IrpStatus;
  1666. }
  1667. /***************************************************************************++
  1668. Routine Description:
  1669. The destination file exists, log that it is being replaced.
  1670. Arguments:
  1671. Return Value:
  1672. NTSTATUS - Completion status.
  1673. --***************************************************************************/
  1674. NTSTATUS
  1675. SrpReplacingDestinationFile (
  1676. IN PSR_DEVICE_EXTENSION pExtension,
  1677. IN PFILE_OBJECT pDestFileObject,
  1678. IN PSR_STREAM_CONTEXT pDestFileContext
  1679. )
  1680. {
  1681. NTSTATUS status;
  1682. try
  1683. {
  1684. //
  1685. // We are now going to log the destination file getting clobbered,
  1686. // grab the volume's activity lock now.
  1687. //
  1688. SrAcquireActivityLockShared( pExtension );
  1689. //
  1690. // Now that we have the shared activity lock, check that the volume
  1691. // hasn't been disable before we do unnecessary work.
  1692. //
  1693. if (!SR_LOGGING_ENABLED(pExtension))
  1694. {
  1695. status = SR_STATUS_VOLUME_DISABLED;
  1696. leave;
  1697. }
  1698. //
  1699. // setup volume if we need to
  1700. //
  1701. status = SrCheckVolume( pExtension, FALSE );
  1702. if (!NT_SUCCESS( status ))
  1703. leave;
  1704. //
  1705. // now simulate a delete on the destination file
  1706. //
  1707. ASSERT(!FlagOn(pDestFileContext->Flags,CTXFL_IsDirectory));
  1708. status = SrHandleEvent( pExtension,
  1709. SrEventFileDelete|
  1710. SrEventNoOptimization|
  1711. SrEventSimulatedDelete,
  1712. pDestFileObject,
  1713. pDestFileContext,
  1714. NULL,
  1715. NULL );
  1716. if (!NT_SUCCESS( status ))
  1717. leave;
  1718. }
  1719. finally
  1720. {
  1721. //
  1722. // Release the activity lock
  1723. //
  1724. SrReleaseActivityLock( pExtension );
  1725. }
  1726. return status;
  1727. }
  1728. /***************************************************************************++
  1729. Routine Description:
  1730. Set correct state if we are renaming. This would be:
  1731. - If renaming a directory mark that ALL contexts become temporary.
  1732. We do this because we don't track all the names for all of the
  1733. contexts
  1734. Arguments:
  1735. Return Value:
  1736. NTSTATUS - Status code.
  1737. --***************************************************************************/
  1738. VOID
  1739. SrpSetRenamingState (
  1740. IN PSR_DEVICE_EXTENSION pExtension,
  1741. IN PSR_STREAM_CONTEXT pFileContext
  1742. )
  1743. {
  1744. //
  1745. // Neither the file we are renaming or the new name are
  1746. // interesting. But we still need to cleanup the context
  1747. // because it may be renamed to something interesting in
  1748. // the future.
  1749. //
  1750. if (FlagOn(pFileContext->Flags,CTXFL_IsDirectory))
  1751. {
  1752. //
  1753. // Since we don't save names for contexts that are not
  1754. // interesting, on directory renames we mark the device
  1755. // extension so that all contexts will become temporary
  1756. // and then we flush all existing contexts. We clear this
  1757. // state during the post-setInformation to guarentee there
  1758. // is no window when we will get the wrong state.
  1759. //
  1760. InterlockedIncrement( &pExtension->ContextCtrl.AllContextsTemporary );
  1761. SrDeleteAllContexts( pExtension );
  1762. }
  1763. else
  1764. {
  1765. //
  1766. // Mark that this context should not be used (because we are
  1767. // renaming it). We will delete this context in the post-
  1768. // rename handling.
  1769. //
  1770. RtlInterlockedSetBitsDiscardReturn(&pFileContext->Flags,CTXFL_DoNotUse);
  1771. }
  1772. }
  1773. /***************************************************************************++
  1774. Routine Description:
  1775. This will determine if the two files represent the same stream of a file
  1776. by comparing the FsContext of the file objects.
  1777. Arguments:
  1778. pExtension - SR's device extension for this volume.
  1779. pFileObject1 - The first file in the comparison
  1780. pFileObject2 - The second file in the comparison
  1781. retAreSame - Is set to TRUE if the two files are the same,
  1782. FALSE otherwise.
  1783. Return Value:
  1784. NTSTATUS - Completion status.
  1785. --***************************************************************************/
  1786. BOOLEAN
  1787. SrpCheckForSameFile (
  1788. IN PFILE_OBJECT pFileObject1,
  1789. IN PFILE_OBJECT pFileObject2
  1790. )
  1791. {
  1792. if (pFileObject1->FsContext == pFileObject2->FsContext)
  1793. {
  1794. return TRUE;
  1795. }
  1796. else
  1797. {
  1798. return FALSE;
  1799. }
  1800. }