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.

1034 lines
32 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Cleanup.c
  5. Abstract:
  6. This module implements the File Cleanup routine for Fat called by the
  7. dispatch driver.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 28-Dec-1989
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (FAT_BUG_CHECK_CLEANUP)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (DEBUG_TRACE_CLEANUP)
  23. //
  24. // The following little routine exists solely because it need a spin lock.
  25. //
  26. VOID
  27. FatAutoUnlock (
  28. IN PIRP_CONTEXT IrpContext,
  29. IN PVCB Vcb
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text(PAGE, FatCommonCleanup)
  33. #pragma alloc_text(PAGE, FatFsdCleanup)
  34. #endif
  35. NTSTATUS
  36. FatFsdCleanup (
  37. IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
  38. IN PIRP Irp
  39. )
  40. /*++
  41. Routine Description:
  42. This routine implements the FSD part of closing down a handle to a
  43. file object.
  44. Arguments:
  45. VolumeDeviceObject - Supplies the volume device object where the
  46. file being Cleanup exists
  47. Irp - Supplies the Irp being processed
  48. Return Value:
  49. NTSTATUS - The FSD status for the IRP
  50. --*/
  51. {
  52. NTSTATUS Status;
  53. PIRP_CONTEXT IrpContext = NULL;
  54. BOOLEAN TopLevel;
  55. //
  56. // If we were called with our file system device object instead of a
  57. // volume device object, just complete this request with STATUS_SUCCESS
  58. //
  59. if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) {
  60. Irp->IoStatus.Status = STATUS_SUCCESS;
  61. Irp->IoStatus.Information = FILE_OPENED;
  62. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  63. return STATUS_SUCCESS;
  64. }
  65. DebugTrace(+1, Dbg, "FatFsdCleanup\n", 0);
  66. //
  67. // Call the common Cleanup routine, with blocking allowed.
  68. //
  69. FsRtlEnterFileSystem();
  70. TopLevel = FatIsIrpTopLevel( Irp );
  71. try {
  72. IrpContext = FatCreateIrpContext( Irp, TRUE );
  73. Status = FatCommonCleanup( IrpContext, Irp );
  74. } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
  75. //
  76. // We had some trouble trying to perform the requested
  77. // operation, so we'll abort the I/O request with
  78. // the error status that we get back from the
  79. // execption code
  80. //
  81. Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
  82. }
  83. if (TopLevel) { IoSetTopLevelIrp( NULL ); }
  84. FsRtlExitFileSystem();
  85. //
  86. // And return to our caller
  87. //
  88. DebugTrace(-1, Dbg, "FatFsdCleanup -> %08lx\n", Status);
  89. UNREFERENCED_PARAMETER( VolumeDeviceObject );
  90. return Status;
  91. }
  92. NTSTATUS
  93. FatCommonCleanup (
  94. IN PIRP_CONTEXT IrpContext,
  95. IN PIRP Irp
  96. )
  97. /*++
  98. Routine Description:
  99. This is the common routine for cleanup of a file/directory called by both
  100. the fsd and fsp threads.
  101. Cleanup is invoked whenever the last handle to a file object is closed.
  102. This is different than the Close operation which is invoked when the last
  103. reference to a file object is deleted.
  104. The function of cleanup is to essentially "cleanup" the file/directory
  105. after a user is done with it. The Fcb/Dcb remains around (because MM
  106. still has the file object referenced) but is now available for another
  107. user to open (i.e., as far as the user is concerned the is now closed).
  108. See close for a more complete description of what close does.
  109. Arguments:
  110. Irp - Supplies the Irp to process
  111. Return Value:
  112. NTSTATUS - The return status for the operation
  113. --*/
  114. {
  115. NTSTATUS Status;
  116. PIO_STACK_LOCATION IrpSp;
  117. PFILE_OBJECT FileObject;
  118. TYPE_OF_OPEN TypeOfOpen;
  119. PVCB Vcb;
  120. PFCB Fcb;
  121. PCCB Ccb;
  122. BOOLEAN SendUnlockNotification = FALSE;
  123. PSHARE_ACCESS ShareAccess;
  124. PLARGE_INTEGER TruncateSize = NULL;
  125. LARGE_INTEGER LocalTruncateSize;
  126. BOOLEAN AcquiredVcb = FALSE;
  127. BOOLEAN AcquiredFcb = FALSE;
  128. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  129. DebugTrace(+1, Dbg, "FatCommonCleanup\n", 0);
  130. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  131. DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject);
  132. //
  133. // Extract and decode the file object
  134. //
  135. FileObject = IrpSp->FileObject;
  136. TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
  137. //
  138. // Special case the unopened file object. This will occur only when
  139. // we are initializing Vcb and IoCreateStreamFileObject is being
  140. // called.
  141. //
  142. if (TypeOfOpen == UnopenedFileObject) {
  143. DebugTrace(0, Dbg, "Unopened File Object\n", 0);
  144. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  145. DebugTrace(-1, Dbg, "FatCommonCleanup -> STATUS_SUCCESS\n", 0);
  146. return STATUS_SUCCESS;
  147. }
  148. //
  149. // If this is not our first time through (for whatever reason)
  150. // only see if we have to flush the file.
  151. //
  152. if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
  153. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
  154. FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
  155. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) &&
  156. (TypeOfOpen == UserFileOpen)) {
  157. //
  158. // Flush the file.
  159. //
  160. Status = FatFlushFile( IrpContext, Fcb, Flush );
  161. if (!NT_SUCCESS(Status)) {
  162. FatNormalizeAndRaiseStatus( IrpContext, Status );
  163. }
  164. }
  165. FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  166. DebugTrace(-1, Dbg, "FatCommonCleanup -> STATUS_SUCCESS\n", 0);
  167. return STATUS_SUCCESS;
  168. }
  169. //
  170. // If we call change the allocation or call CcUninitialize,
  171. // we have to take the Fcb exclusive
  172. //
  173. if ((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) {
  174. ASSERT( Fcb != NULL );
  175. (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
  176. AcquiredFcb = TRUE;
  177. //
  178. // Do a check here if this was a DELETE_ON_CLOSE FileObject, and
  179. // set the Fcb flag appropriately.
  180. //
  181. if (FlagOn(Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE)) {
  182. ASSERT( NodeType(Fcb) != FAT_NTC_ROOT_DCB );
  183. SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
  184. //
  185. // Report this to the dir notify package for a directory.
  186. //
  187. if (TypeOfOpen == UserDirectoryOpen) {
  188. FsRtlNotifyFullChangeDirectory( Vcb->NotifySync,
  189. &Vcb->DirNotifyList,
  190. FileObject->FsContext,
  191. NULL,
  192. FALSE,
  193. FALSE,
  194. 0,
  195. NULL,
  196. NULL,
  197. NULL );
  198. }
  199. }
  200. //
  201. // Now if we may delete the file, drop the Fcb and acquire the Vcb
  202. // first. Note that while we own the Fcb exclusive, a file cannot
  203. // become DELETE_ON_CLOSE and cannot be opened via CommonCreate.
  204. //
  205. if ((Fcb->UncleanCount == 1) &&
  206. FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
  207. (Fcb->FcbCondition != FcbBad) &&
  208. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  209. FatReleaseFcb( IrpContext, Fcb );
  210. AcquiredFcb = FALSE;
  211. (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
  212. AcquiredVcb = TRUE;
  213. (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
  214. AcquiredFcb = TRUE;
  215. }
  216. }
  217. //
  218. // For user DASD cleanups, grab the Vcb exclusive.
  219. //
  220. if (TypeOfOpen == UserVolumeOpen) {
  221. (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
  222. AcquiredVcb = TRUE;
  223. }
  224. //
  225. // Complete any Notify Irps on this file handle.
  226. //
  227. if (TypeOfOpen == UserDirectoryOpen) {
  228. FsRtlNotifyCleanup( Vcb->NotifySync,
  229. &Vcb->DirNotifyList,
  230. Ccb );
  231. }
  232. //
  233. // Determine the Fcb state, Good or Bad, for better or for worse.
  234. //
  235. // We can only read the volume file if VcbCondition is good.
  236. //
  237. if ( Fcb != NULL) {
  238. //
  239. // Stop any raises from FatVerifyFcb, unless it is REAL bad.
  240. //
  241. try {
  242. try {
  243. FatVerifyFcb( IrpContext, Fcb );
  244. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  245. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  246. FatResetExceptionState( IrpContext );
  247. }
  248. } finally {
  249. if ( AbnormalTermination() ) {
  250. //
  251. // We will be raising out of here.
  252. //
  253. if (AcquiredFcb) { FatReleaseFcb( IrpContext, Fcb ); }
  254. if (AcquiredVcb) { FatReleaseVcb( IrpContext, Vcb ); }
  255. }
  256. }
  257. }
  258. try {
  259. //
  260. // Case on the type of open that we are trying to cleanup.
  261. // For all cases we need to set the share access to point to the
  262. // share access variable (if there is one). After the switch
  263. // we then remove the share access and complete the Irp.
  264. // In the case of UserFileOpen we actually have a lot more work
  265. // to do and we have the FsdLockControl complete the Irp for us.
  266. //
  267. switch (TypeOfOpen) {
  268. case DirectoryFile:
  269. case VirtualVolumeFile:
  270. DebugTrace(0, Dbg, "Cleanup VirtualVolumeFile/DirectoryFile\n", 0);
  271. ShareAccess = NULL;
  272. break;
  273. case UserVolumeOpen:
  274. DebugTrace(0, Dbg, "Cleanup UserVolumeOpen\n", 0);
  275. if (FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) {
  276. FatCheckForDismount( IrpContext, Vcb, TRUE );
  277. //
  278. // If this handle had write access, and actually wrote something,
  279. // flush the device buffers, and then set the verify bit now
  280. // just to be safe (in case there is no dismount).
  281. //
  282. } else if (FileObject->WriteAccess &&
  283. FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
  284. (VOID)FatHijackIrpAndFlushDevice( IrpContext,
  285. Irp,
  286. Vcb->TargetDeviceObject );
  287. SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
  288. }
  289. //
  290. // If the volume is locked by this file object then release
  291. // the volume and send notification.
  292. //
  293. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) &&
  294. (Vcb->FileObjectWithVcbLocked == FileObject)) {
  295. FatAutoUnlock( IrpContext, Vcb );
  296. SendUnlockNotification = TRUE;
  297. }
  298. ShareAccess = &Vcb->ShareAccess;
  299. break;
  300. case EaFile:
  301. DebugTrace(0, Dbg, "Cleanup EaFileObject\n", 0);
  302. ShareAccess = NULL;
  303. break;
  304. case UserDirectoryOpen:
  305. DebugTrace(0, Dbg, "Cleanup UserDirectoryOpen\n", 0);
  306. ShareAccess = &Fcb->ShareAccess;
  307. //
  308. // Determine here if we should try do delayed close.
  309. //
  310. if ((Fcb->UncleanCount == 1) &&
  311. (Fcb->OpenCount == 1) &&
  312. (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0) &&
  313. !FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
  314. Fcb->FcbCondition == FcbGood) {
  315. //
  316. // Delay our close.
  317. //
  318. SetFlag( Fcb->FcbState, FCB_STATE_DELAY_CLOSE );
  319. }
  320. FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
  321. //
  322. // If the directory has a unclean count of 1 then we know
  323. // that this is the last handle for the file object. If
  324. // we are supposed to delete it, do so.
  325. //
  326. if ((Fcb->UncleanCount == 1) &&
  327. (NodeType(Fcb) == FAT_NTC_DCB) &&
  328. (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) &&
  329. (Fcb->FcbCondition != FcbBad) &&
  330. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  331. if (!FatIsDirectoryEmpty(IrpContext, Fcb)) {
  332. //
  333. // If there are files in the directory at this point,
  334. // forget that we were trying to delete it.
  335. //
  336. ClearFlag( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
  337. } else {
  338. //
  339. // Even if something goes wrong, we cannot turn back!
  340. //
  341. try {
  342. DELETE_CONTEXT DeleteContext;
  343. //
  344. // Before truncating file allocation remember this
  345. // info for FatDeleteDirent.
  346. //
  347. DeleteContext.FileSize = Fcb->Header.FileSize.LowPart;
  348. DeleteContext.FirstClusterOfFile = Fcb->FirstClusterOfFile;
  349. //
  350. // Synchronize here with paging IO
  351. //
  352. (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
  353. TRUE );
  354. Fcb->Header.FileSize.LowPart = 0;
  355. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  356. if (Vcb->VcbCondition == VcbGood) {
  357. //
  358. // Truncate the file allocation down to zero
  359. //
  360. DebugTrace(0, Dbg, "Delete File allocation\n", 0);
  361. FatTruncateFileAllocation( IrpContext, Fcb, 0 );
  362. if (Fcb->Header.AllocationSize.LowPart == 0) {
  363. //
  364. // Tunnel and remove the dirent for the directory
  365. //
  366. DebugTrace(0, Dbg, "Delete the directory dirent\n", 0);
  367. FatTunnelFcbOrDcb( Fcb, NULL );
  368. FatDeleteDirent( IrpContext, Fcb, &DeleteContext, TRUE );
  369. //
  370. // Report that we have removed an entry.
  371. //
  372. FatNotifyReportChange( IrpContext,
  373. Vcb,
  374. Fcb,
  375. FILE_NOTIFY_CHANGE_DIR_NAME,
  376. FILE_ACTION_REMOVED );
  377. }
  378. }
  379. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  380. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  381. FatResetExceptionState( IrpContext );
  382. }
  383. //
  384. // Remove the entry from the name table.
  385. // This will ensure that
  386. // we will not collide with the Dcb if the user wants
  387. // to recreate the same file over again before we
  388. // get a close irp.
  389. //
  390. FatRemoveNames( IrpContext, Fcb );
  391. }
  392. }
  393. //
  394. // Decrement the unclean count.
  395. //
  396. ASSERT( Fcb->UncleanCount != 0 );
  397. Fcb->UncleanCount -= 1;
  398. break;
  399. case UserFileOpen:
  400. DebugTrace(0, Dbg, "Cleanup UserFileOpen\n", 0);
  401. ShareAccess = &Fcb->ShareAccess;
  402. //
  403. // Determine here if we should do a delayed close.
  404. //
  405. if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
  406. (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
  407. (Fcb->UncleanCount == 1) &&
  408. (Fcb->OpenCount == 1) &&
  409. !FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
  410. Fcb->FcbCondition == FcbGood) {
  411. //
  412. // Delay our close.
  413. //
  414. SetFlag( Fcb->FcbState, FCB_STATE_DELAY_CLOSE );
  415. }
  416. //
  417. // Unlock all outstanding file locks.
  418. //
  419. (VOID) FsRtlFastUnlockAll( &Fcb->Specific.Fcb.FileLock,
  420. FileObject,
  421. IoGetRequestorProcess( Irp ),
  422. NULL );
  423. //
  424. // We can proceed with on-disk updates only if the volume is mounted.
  425. // Remember that we toss all sections in the failed-verify and dismount
  426. // cases.
  427. //
  428. if (Vcb->VcbCondition == VcbGood) {
  429. if (Fcb->FcbCondition != FcbBad) {
  430. FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
  431. }
  432. //
  433. // If the file has a unclean count of 1 then we know
  434. // that this is the last handle for the file object.
  435. //
  436. if ( (Fcb->UncleanCount == 1) && (Fcb->FcbCondition != FcbBad) ) {
  437. DELETE_CONTEXT DeleteContext;
  438. //
  439. // Check if we should be deleting the file. The
  440. // delete operation really deletes the file but
  441. // keeps the Fcb around for close to do away with.
  442. //
  443. if (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
  444. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  445. //
  446. // Before truncating file allocation remember this
  447. // info for FatDeleteDirent.
  448. //
  449. DeleteContext.FileSize = Fcb->Header.FileSize.LowPart;
  450. DeleteContext.FirstClusterOfFile = Fcb->FirstClusterOfFile;
  451. DebugTrace(0, Dbg, "Delete File allocation\n", 0);
  452. //
  453. // Synchronize here with paging IO
  454. //
  455. (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
  456. TRUE );
  457. Fcb->Header.FileSize.LowPart = 0;
  458. Fcb->Header.ValidDataLength.LowPart = 0;
  459. Fcb->ValidDataToDisk = 0;
  460. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  461. try {
  462. FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
  463. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  464. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  465. FatResetExceptionState( IrpContext );
  466. }
  467. Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
  468. } else {
  469. //
  470. // We must zero between ValidDataLength and FileSize
  471. //
  472. if (!FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
  473. (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart)) {
  474. ULONG ValidDataLength;
  475. ValidDataLength = Fcb->Header.ValidDataLength.LowPart;
  476. if (ValidDataLength < Fcb->ValidDataToDisk) {
  477. ValidDataLength = Fcb->ValidDataToDisk;
  478. }
  479. //
  480. // Recheck, VDD can be >= FS
  481. //
  482. if (ValidDataLength < Fcb->Header.FileSize.LowPart) {
  483. try {
  484. (VOID)FatZeroData( IrpContext,
  485. Vcb,
  486. FileObject,
  487. ValidDataLength,
  488. Fcb->Header.FileSize.LowPart -
  489. ValidDataLength );
  490. //
  491. // Since we just zeroed this, we can now bump
  492. // up VDL in the Fcb.
  493. //
  494. Fcb->ValidDataToDisk =
  495. Fcb->Header.ValidDataLength.LowPart =
  496. Fcb->Header.FileSize.LowPart;
  497. //
  498. // We inform Cc of the motion so that the cache map is updated.
  499. // This prevents optimized zero-page faults in case the cache
  500. // structures are re-used for another handle before they are torn
  501. // down by our soon-to-occur uninitialize. If they were, a noncached
  502. // producer could write into the region we just zeroed and Cc would
  503. // be none the wiser, then our async cached reader comes in and takes
  504. // the optimized path, and we get bad (zero) data.
  505. //
  506. // If this was memory mapped, we don't have to (can't) tell Cc, it'll
  507. // figure it out when a cached handle is opened.
  508. //
  509. if (CcIsFileCached( FileObject )) {
  510. CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
  511. }
  512. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  513. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  514. FatResetExceptionState( IrpContext );
  515. }
  516. }
  517. }
  518. }
  519. //
  520. // See if we are supposed to truncate the file on the last
  521. // close. If we cannot wait we'll ship this off to the fsp
  522. //
  523. try {
  524. if (FlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE)) {
  525. DebugTrace(0, Dbg, "truncate file allocation\n", 0);
  526. if (Vcb->VcbCondition == VcbGood) {
  527. FatTruncateFileAllocation( IrpContext,
  528. Fcb,
  529. Fcb->Header.FileSize.LowPart );
  530. }
  531. //
  532. // We also have to get rid of the Cache Map because
  533. // this is the only way we have of trashing the
  534. // truncated pages.
  535. //
  536. LocalTruncateSize = Fcb->Header.FileSize;
  537. TruncateSize = &LocalTruncateSize;
  538. //
  539. // Mark the Fcb as having now been truncated, just incase
  540. // we have to reship this off to the fsp.
  541. //
  542. Fcb->FcbState &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
  543. }
  544. //
  545. // Now check again if we are to delete the file and if
  546. // so then we remove the file from the disk.
  547. //
  548. if (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
  549. Fcb->Header.AllocationSize.LowPart == 0) {
  550. DebugTrace(0, Dbg, "Delete File\n", 0);
  551. //
  552. // Now tunnel and delete the dirent
  553. //
  554. FatTunnelFcbOrDcb( Fcb, Ccb );
  555. FatDeleteDirent( IrpContext, Fcb, &DeleteContext, TRUE );
  556. //
  557. // Report that we have removed an entry.
  558. //
  559. FatNotifyReportChange( IrpContext,
  560. Vcb,
  561. Fcb,
  562. FILE_NOTIFY_CHANGE_FILE_NAME,
  563. FILE_ACTION_REMOVED );
  564. }
  565. } except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
  566. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
  567. FatResetExceptionState( IrpContext );
  568. }
  569. if (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) {
  570. //
  571. // Remove the entry from the splay table. This will
  572. // ensure that we will not collide with the Fcb if the
  573. // user wants to recreate the same file over again
  574. // before we get a close irp.
  575. //
  576. // Note that we remove the name even if we couldn't
  577. // truncate the allocation and remove the dirent above.
  578. //
  579. FatRemoveNames( IrpContext, Fcb );
  580. }
  581. }
  582. }
  583. //
  584. // We've just finished everything associated with an unclean
  585. // fcb so now decrement the unclean count before releasing
  586. // the resource.
  587. //
  588. ASSERT( Fcb->UncleanCount != 0 );
  589. Fcb->UncleanCount -= 1;
  590. if (!FlagOn( FileObject->Flags, FO_CACHE_SUPPORTED )) {
  591. ASSERT( Fcb->NonCachedUncleanCount != 0 );
  592. Fcb->NonCachedUncleanCount -= 1;
  593. }
  594. //
  595. // If this was the last cached open, and there are open
  596. // non-cached handles, attempt a flush and purge operation
  597. // to avoid cache coherency overhead from these non-cached
  598. // handles later. We ignore any I/O errors from the flush.
  599. //
  600. if (FlagOn( FileObject->Flags, FO_CACHE_SUPPORTED ) &&
  601. (Fcb->NonCachedUncleanCount != 0) &&
  602. (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
  603. (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)) {
  604. CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, NULL );
  605. //
  606. // Grab and release PagingIo to serialize ourselves with the lazy writer.
  607. // This will work to ensure that all IO has completed on the cached
  608. // data and we will succesfully tear away the cache section.
  609. //
  610. ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
  611. ExReleaseResourceLite( Fcb->Header.PagingIoResource );
  612. CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers,
  613. NULL,
  614. 0,
  615. FALSE );
  616. }
  617. //
  618. // If the file is invalid, hint to the cache that we should throw everything out.
  619. //
  620. if ( Fcb->FcbCondition == FcbBad ) {
  621. TruncateSize = &FatLargeZero;
  622. }
  623. //
  624. // Cleanup the cache map
  625. //
  626. CcUninitializeCacheMap( FileObject, TruncateSize, NULL );
  627. break;
  628. default:
  629. FatBugCheck( TypeOfOpen, 0, 0 );
  630. }
  631. //
  632. // We must clean up the share access at this time, since we may not
  633. // get a Close call for awhile if the file was mapped through this
  634. // File Object.
  635. //
  636. if (ShareAccess != NULL) {
  637. DebugTrace(0, Dbg, "Cleanup the Share access\n", 0);
  638. IoRemoveShareAccess( FileObject, ShareAccess );
  639. }
  640. if (TypeOfOpen == UserFileOpen) {
  641. //
  642. // Coordinate the cleanup operation with the oplock state.
  643. // Cleanup operations can always cleanup immediately.
  644. //
  645. FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock,
  646. Irp,
  647. IrpContext,
  648. NULL,
  649. NULL );
  650. Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
  651. }
  652. //
  653. // First set the FO_CLEANUP_COMPLETE flag.
  654. //
  655. SetFlag( FileObject->Flags, FO_CLEANUP_COMPLETE );
  656. Status = STATUS_SUCCESS;
  657. //
  658. // Now unpin any repinned Bcbs.
  659. //
  660. FatUnpinRepinnedBcbs( IrpContext );
  661. //
  662. // If this was deferred flush media, flush the volume.
  663. // We used to do this in lieu of write through for all removable
  664. // media.
  665. //
  666. if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
  667. !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
  668. //
  669. // Flush the file.
  670. //
  671. if ((TypeOfOpen == UserFileOpen) &&
  672. FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
  673. Status = FatFlushFile( IrpContext, Fcb, Flush );
  674. }
  675. //
  676. // If that worked ok, then see if we should flush the FAT as well.
  677. //
  678. if (NT_SUCCESS(Status) && Fcb && !FatIsFat12( Vcb) &&
  679. FlagOn( Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {
  680. Status = FatFlushFat( IrpContext, Vcb);
  681. }
  682. if (!NT_SUCCESS(Status)) {
  683. FatNormalizeAndRaiseStatus( IrpContext, Status );
  684. }
  685. }
  686. } finally {
  687. DebugUnwind( FatCommonCleanup );
  688. if (AcquiredFcb) { FatReleaseFcb( IrpContext, Fcb ); }
  689. if (AcquiredVcb) { FatReleaseVcb( IrpContext, Vcb ); }
  690. if (SendUnlockNotification) {
  691. FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
  692. }
  693. //
  694. // If this is a normal termination then complete the request
  695. //
  696. if (!AbnormalTermination()) {
  697. FatCompleteRequest( IrpContext, Irp, Status );
  698. }
  699. DebugTrace(-1, Dbg, "FatCommonCleanup -> %08lx\n", Status);
  700. }
  701. return Status;
  702. }
  703. VOID
  704. FatAutoUnlock (
  705. IN PIRP_CONTEXT IrpContext,
  706. IN PVCB Vcb
  707. )
  708. {
  709. KIRQL SavedIrql;
  710. //
  711. // Unlock the volume.
  712. //
  713. IoAcquireVpbSpinLock( &SavedIrql );
  714. ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED );
  715. Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
  716. Vcb->FileObjectWithVcbLocked = NULL;
  717. IoReleaseVpbSpinLock( SavedIrql );
  718. }