ReactOS  0.4.14-dev-49-gfb4591c
cleanup.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  Cleanup.c
8 
9 Abstract:
10 
11  This module implements the File Cleanup routine for Fat called by the
12  dispatch driver.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 // The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId (FAT_BUG_CHECK_CLEANUP)
24 
25 //
26 // The local debug trace level
27 //
28 
29 #define Dbg (DEBUG_TRACE_CLEANUP)
30 
31 //
32 // The following little routine exists solely because it need a spin lock.
33 //
34 
35 VOID
37  IN PIRP_CONTEXT IrpContext,
38  IN PVCB Vcb
39  );
40 
41 #ifdef ALLOC_PRAGMA
42 #pragma alloc_text(PAGE, FatCommonCleanup)
43 #pragma alloc_text(PAGE, FatFsdCleanup)
44 #endif
45 
46 
50 NTAPI
51 FatFsdCleanup (
52  _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
54  )
55 
56 /*++
57 
58 Routine Description:
59 
60  This routine implements the FSD part of closing down a handle to a
61  file object.
62 
63 Arguments:
64 
65  VolumeDeviceObject - Supplies the volume device object where the
66  file being Cleanup exists
67 
68  Irp - Supplies the Irp being processed
69 
70 Return Value:
71 
72  NTSTATUS - The FSD status for the IRP
73 
74 --*/
75 
76 {
78  PIRP_CONTEXT IrpContext = NULL;
79 
81 
82  PAGED_CODE();
83 
84  //
85  // If we were called with our file system device object instead of a
86  // volume device object, just complete this request with STATUS_SUCCESS
87  //
88 
89  if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) {
90 
91  Irp->IoStatus.Status = STATUS_SUCCESS;
92  Irp->IoStatus.Information = FILE_OPENED;
93 
95 
96  return STATUS_SUCCESS;
97  }
98 
99  DebugTrace(+1, Dbg, "FatFsdCleanup\n", 0);
100 
101  //
102  // Call the common Cleanup routine, with blocking allowed.
103  //
104 
106 
108 
109  _SEH2_TRY {
110 
111  IrpContext = FatCreateIrpContext( Irp, TRUE );
112 
113  Status = FatCommonCleanup( IrpContext, Irp );
114 
116 
117  //
118  // We had some trouble trying to perform the requested
119  // operation, so we'll abort the I/O request with
120  // the error status that we get back from the
121  // execption code
122  //
123 
124  Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
125  } _SEH2_END;
126 
127  if (TopLevel) { IoSetTopLevelIrp( NULL ); }
128 
130 
131  //
132  // And return to our caller
133  //
134 
135  DebugTrace(-1, Dbg, "FatFsdCleanup -> %08lx\n", Status);
136 
137  UNREFERENCED_PARAMETER( VolumeDeviceObject );
138 
139  return Status;
140 }
141 
142 
143 _Requires_lock_held_(_Global_critical_region_)
144 NTSTATUS
145 FatCommonCleanup (
146  IN PIRP_CONTEXT IrpContext,
147  IN PIRP Irp
148  )
149 
150 /*++
151 
152 Routine Description:
153 
154  This is the common routine for cleanup of a file/directory called by both
155  the fsd and fsp threads.
156 
157  Cleanup is invoked whenever the last handle to a file object is closed.
158  This is different than the Close operation which is invoked when the last
159  reference to a file object is deleted.
160 
161  The function of cleanup is to essentially "cleanup" the file/directory
162  after a user is done with it. The Fcb/Dcb remains around (because MM
163  still has the file object referenced) but is now available for another
164  user to open (i.e., as far as the user is concerned the is now closed).
165 
166  See close for a more complete description of what close does.
167 
168 Arguments:
169 
170  Irp - Supplies the Irp to process
171 
172 Return Value:
173 
174  NTSTATUS - The return status for the operation
175 
176 --*/
177 
178 {
180 
182 
184 
186  PVCB Vcb;
187  PFCB Fcb;
188  PCCB Ccb;
189 
190  BOOLEAN SendUnlockNotification = FALSE;
191 
193 
194  PLARGE_INTEGER TruncateSize = NULL;
195  LARGE_INTEGER LocalTruncateSize;
196 
197  BOOLEAN AcquiredVcb = FALSE;
198  BOOLEAN AcquiredFcb = FALSE;
199 
200 #if (NTDDI_VERSION >= NTDDI_WIN8)
201  BOOLEAN ProcessingDeleteOnClose = FALSE;
202 #endif
203 
204  PAGED_CODE();
205 
207 
208  DebugTrace(+1, Dbg, "FatCommonCleanup\n", 0);
209  DebugTrace( 0, Dbg, "Irp = %p\n", Irp);
210  DebugTrace( 0, Dbg, "->FileObject = %p\n", IrpSp->FileObject);
211 
212  //
213  // Extract and decode the file object
214  //
215 
218 
219  //
220  // Special case the unopened file object. This will occur only when
221  // we are initializing Vcb and IoCreateStreamFileObject is being
222  // called.
223  //
224 
226 
227  DebugTrace(0, Dbg, "Unopened File Object\n", 0);
228 
229  FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
230 
231  DebugTrace(-1, Dbg, "FatCommonCleanup -> STATUS_SUCCESS\n", 0);
232  return STATUS_SUCCESS;
233  }
234 
235  //
236  // If this is not our first time through (for whatever reason)
237  // only see if we have to flush the file.
238  //
239 
240  if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
241 
242  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
245  (TypeOfOpen == UserFileOpen)) {
246 
247  //
248  // Flush the file.
249  //
250 
251  Status = FatFlushFile( IrpContext, Fcb, Flush );
252 
253  if (!NT_SUCCESS(Status)) {
254 
255  FatNormalizeAndRaiseStatus( IrpContext, Status );
256  }
257  }
258 
259  FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
260 
261  DebugTrace(-1, Dbg, "FatCommonCleanup -> STATUS_SUCCESS\n", 0);
262  return STATUS_SUCCESS;
263  }
264 
265  //
266  // If we call change the allocation or call CcUninitialize,
267  // we have to take the Fcb exclusive
268  //
269 
271 
272  NT_ASSERT( Fcb != NULL );
273 
274  (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
275 
276  AcquiredFcb = TRUE;
277 
278  //
279  // Do a check here if this was a DELETE_ON_CLOSE FileObject, and
280  // set the Fcb flag appropriately.
281  //
282 
284 
286 
287  //
288  // Transfer the delete-on-close state to the FCB. We do this rather
289  // than leave the CCB_FLAG_DELETE_ON_CLOSE flag set so that if we
290  // end up breaking an oplock and come in again we won't try to break
291  // the oplock again (and again, and again...).
292  //
293 
296 
297 #if (NTDDI_VERSION >= NTDDI_WIN8)
298  ProcessingDeleteOnClose = TRUE;
299 #endif
300 
301  //
302  // Report this to the dir notify package for a directory.
303  //
304 
305  if (TypeOfOpen == UserDirectoryOpen) {
306 
307 #ifdef _MSC_VER
308 #pragma prefast( suppress:6309, "FullDirectoryName may be NULL if NotifyIrp is also NULL. this indicates the object is being deleted." )
309 #endif
310  FsRtlNotifyFullChangeDirectory( Vcb->NotifySync,
311  &Vcb->DirNotifyList,
312  FileObject->FsContext,
313  NULL,
314  FALSE,
315  FALSE,
316  0,
317  NULL,
318  NULL,
319  NULL );
320  }
321  }
322 
323  //
324  // Now if we may delete the file, drop the Fcb and acquire the Vcb
325  // first. Note that while we own the Fcb exclusive, a file cannot
326  // become DELETE_ON_CLOSE and cannot be opened via CommonCreate.
327  //
328 
329  if ((Fcb->UncleanCount == 1) &&
331  (Fcb->FcbCondition != FcbBad) &&
333 
334  FatReleaseFcb( IrpContext, Fcb );
335  AcquiredFcb = FALSE;
336 
337  (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
338  AcquiredVcb = TRUE;
339 
340  (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
341  AcquiredFcb = TRUE;
342  }
343  }
344 
345  //
346  // For user DASD cleanups, grab the Vcb exclusive.
347  //
348 
349  if (TypeOfOpen == UserVolumeOpen) {
350 
351  (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
352  AcquiredVcb = TRUE;
353  }
354 
355  //
356  // Complete any Notify Irps on this file handle.
357  //
358 
359  if (TypeOfOpen == UserDirectoryOpen) {
360 
361  FsRtlNotifyCleanup( Vcb->NotifySync,
362  &Vcb->DirNotifyList,
363  Ccb );
364  }
365 
366  //
367  // Determine the Fcb state, Good or Bad, for better or for worse.
368  //
369  // We can only read the volume file if VcbCondition is good.
370  //
371 
372  if ( Fcb != NULL) {
373 
374  //
375  // Stop any raises from FatVerifyFcb, unless it is REAL bad.
376  //
377 
378  _SEH2_TRY {
379 
380  _SEH2_TRY {
381 
382  FatVerifyFcb( IrpContext, Fcb );
383 
386 
387  FatResetExceptionState( IrpContext );
388  } _SEH2_END;
389 
390  } _SEH2_FINALLY {
391 
392  if ( _SEH2_AbnormalTermination() ) {
393 
394  //
395  // We will be raising out of here.
396  //
397 
398  if (AcquiredFcb) { FatReleaseFcb( IrpContext, Fcb ); }
399  if (AcquiredVcb) { FatReleaseVcb( IrpContext, Vcb ); }
400  }
401  } _SEH2_END;
402  }
403 
404  _SEH2_TRY {
405 
406 #if (NTDDI_VERSION >= NTDDI_WIN8)
407 
408  //
409  // See if this is a delete-on-close handle on a file or empty directory.
410  // If so we may need to break an oplock. We do this in the try block
411  // so that resources will be properly released.
412  //
413 
414  if (ProcessingDeleteOnClose &&
416  ((NodeType( Fcb ) != FAT_NTC_DCB) ||
417  FatIsDirectoryEmpty( IrpContext, Fcb ))) {
418 
419  Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
420  Irp,
421  OPLOCK_FLAG_CLOSING_DELETE_ON_CLOSE,
422  IrpContext,
424  FatPrePostIrp );
425 
426  if (Status != STATUS_SUCCESS) {
427 
428  if (Status == STATUS_PENDING) {
429 
431  try_return( Status );
432 
433  } else {
434 
435  FatNormalizeAndRaiseStatus( IrpContext, Status );
436  }
437  }
438  }
439 #endif
440 
441  //
442  // Case on the type of open that we are trying to cleanup.
443  // For all cases we need to set the share access to point to the
444  // share access variable (if there is one). After the switch
445  // we then remove the share access and complete the Irp.
446  // In the case of UserFileOpen we actually have a lot more work
447  // to do and we have the FsdLockControl complete the Irp for us.
448  //
449 
450  switch (TypeOfOpen) {
451 
452  case DirectoryFile:
453  case VirtualVolumeFile:
454 
455  DebugTrace(0, Dbg, "Cleanup VirtualVolumeFile/DirectoryFile\n", 0);
456 
457  ShareAccess = NULL;
458 
459  break;
460 
461 
462  case UserVolumeOpen:
463 
464  DebugTrace(0, Dbg, "Cleanup UserVolumeOpen\n", 0);
465 
467 
468  FatCheckForDismount( IrpContext, Vcb, TRUE );
469 
470  //
471  // If this handle had write access, and actually wrote something,
472  // flush the device buffers, and then set the verify bit now
473  // just to be safe (in case there is no dismount).
474  //
475 
476  } else if (FileObject->WriteAccess &&
478 
479  (VOID)FatHijackIrpAndFlushDevice( IrpContext,
480  Irp,
481  Vcb->TargetDeviceObject );
482 
483  SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
484  }
485 
486  //
487  // If the volume is locked by this file object then release
488  // the volume and send notification.
489  //
490 
491  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) &&
492  (Vcb->FileObjectWithVcbLocked == FileObject)) {
493 
494  FatAutoUnlock( IrpContext, Vcb );
495  SendUnlockNotification = TRUE;
496  }
497 
498  ShareAccess = &Vcb->ShareAccess;
499 
500  break;
501 
502  case EaFile:
503 
504  DebugTrace(0, Dbg, "Cleanup EaFileObject\n", 0);
505 
506  ShareAccess = NULL;
507 
508  break;
509 
510  case UserDirectoryOpen:
511 
512  DebugTrace(0, Dbg, "Cleanup UserDirectoryOpen\n", 0);
513 
515 
516  //
517  // Determine here if we should try do delayed close.
518  //
519 
520  if ((Fcb->UncleanCount == 1) &&
521  (Fcb->OpenCount == 1) &&
522  (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0) &&
524  Fcb->FcbCondition == FcbGood) {
525 
526  //
527  // Delay our close.
528  //
529 
531  }
532 
533  //
534  // Clear the deny defrag bit, if the handle we're cleaning up was the one that set it.
535  //
536 
538 
541  }
542 
543  if ((VcbGood == Vcb->VcbCondition) &&
544  !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN)) {
545 
546  FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
547 
548  //
549  // If the directory has a unclean count of 1 then we know
550  // that this is the last handle for the file object. If
551  // we are supposed to delete it, do so.
552  //
553 
554  if ((Fcb->UncleanCount == 1) &&
555  (NodeType(Fcb) == FAT_NTC_DCB) &&
557  (Fcb->FcbCondition == FcbGood) &&
559 
560  if (!FatIsDirectoryEmpty(IrpContext, Fcb)) {
561 
562  //
563  // If there are files in the directory at this point,
564  // forget that we were trying to delete it.
565  //
566 
568 
569  } else {
570 
571 #if (NTDDI_VERSION >= NTDDI_WIN8)
572  NTSTATUS BreakStatus;
573 #endif
574 
575  //
576  // Even if something goes wrong, we cannot turn back!
577  //
578 
579  _SEH2_TRY {
580 
581  DELETE_CONTEXT DeleteContext;
582 
583 
584  //
585  // Before truncating file allocation remember this
586  // info for FatDeleteDirent.
587  //
588 
589  DeleteContext.FileSize = Fcb->Header.FileSize.LowPart;
590  DeleteContext.FirstClusterOfFile = Fcb->FirstClusterOfFile;
591 
592  //
593  // Synchronize here with paging IO
594  //
595 
596  (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
597  TRUE );
598 
599  Fcb->Header.FileSize.LowPart = 0;
600 
601  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
602 
603  //
604  // Truncate the file allocation down to zero
605  //
606 
607  DebugTrace(0, Dbg, "Delete File allocation\n", 0);
608 
609  FatTruncateFileAllocation( IrpContext, Fcb, 0 );
610 
611  if (Fcb->Header.AllocationSize.LowPart == 0) {
612 
613  //
614  // Tunnel and remove the dirent for the directory
615  //
616 
617  DebugTrace(0, Dbg, "Delete the directory dirent\n", 0);
618 
620 
621  FatDeleteDirent( IrpContext, Fcb, &DeleteContext, TRUE );
622 
623  //
624  // Report that we have removed an entry.
625  //
626 
627  FatNotifyReportChange( IrpContext,
628  Vcb,
629  Fcb,
632  }
633 
636 
637  FatResetExceptionState( IrpContext );
638  } _SEH2_END;
639 
640  //
641  // Remove the entry from the name table.
642  // This will ensure that
643  // we will not collide with the Dcb if the user wants
644  // to recreate the same file over again before we
645  // get a close irp.
646  //
647 
648  FatRemoveNames( IrpContext, Fcb );
649 
650 #if (NTDDI_VERSION >= NTDDI_WIN8)
651  //
652  // We've removed the names so break any parent directory oplock.
653  // Directory oplock breaks are always advisory, so we will never
654  // block/get STATUS_PENDING here.
655  //
656 
657  BreakStatus = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb),
658  Irp,
659  (OPLOCK_FLAG_PARENT_OBJECT |
660  OPLOCK_FLAG_REMOVING_FILE_OR_LINK),
661  NULL,
662  NULL,
663  NULL );
664 
665  ASSERT( BreakStatus != STATUS_PENDING );
666 #endif
667  }
668  }
669  }
670 
671  //
672  // Decrement the unclean count.
673  //
674 
675  NT_ASSERT( Fcb->UncleanCount != 0 );
676  Fcb->UncleanCount -= 1;
677 
678  break;
679 
680  case UserFileOpen:
681 
682  DebugTrace(0, Dbg, "Cleanup UserFileOpen\n", 0);
683 
685 
686  //
687  // Determine here if we should do a delayed close.
688  //
689 
690  if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
691  (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
692  (Fcb->UncleanCount == 1) &&
693  (Fcb->OpenCount == 1) &&
696  Fcb->FcbCondition == FcbGood) {
697 
698  //
699  // Delay our close.
700  //
701 
703  }
704 
705  //
706  // Clear the deny defrag bit, if the handle we're cleaning up was the one that set it.
707  //
708 
710 
713  }
714 
715  //
716  // Unlock all outstanding file locks.
717  //
718 
719  (VOID) FsRtlFastUnlockAll( &Fcb->Specific.Fcb.FileLock,
720  FileObject,
722  NULL );
723 
724 
725 
726  //
727  // We can proceed with on-disk updates only if the volume is mounted
728  // and we can still write to it if it hasn't been shutdown. Remember that
729  // we toss all sections in the failed-verify and dismount cases.
730  //
731 
732  if ((Vcb->VcbCondition == VcbGood) &&
733  !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN)) {
734 
735  if (Fcb->FcbCondition == FcbGood) {
736 
737 
738  FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
739 
740  }
741 
742  //
743  // If the file has a unclean count of 1 then we know
744  // that this is the last handle for the file object.
745  //
746 
747  if ( (Fcb->UncleanCount == 1) && (Fcb->FcbCondition == FcbGood) ) {
748 
749  DELETE_CONTEXT DeleteContext;
750 
751  //
752  // Check if we should be deleting the file. The
753  // delete operation really deletes the file but
754  // keeps the Fcb around for close to do away with.
755  //
756 
759 
760  //
761  // Before truncating file allocation remember this
762  // info for FatDeleteDirent.
763  //
764 
765  DeleteContext.FileSize = Fcb->Header.FileSize.LowPart;
766  DeleteContext.FirstClusterOfFile = Fcb->FirstClusterOfFile;
767 
768  DebugTrace(0, Dbg, "Delete File allocation\n", 0);
769 
770  //
771  // Synchronize here with paging IO
772  //
773 
774  (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
775  TRUE );
776 
777  Fcb->Header.FileSize.LowPart = 0;
778  Fcb->Header.ValidDataLength.LowPart = 0;
779  Fcb->ValidDataToDisk = 0;
780 
781  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
782 
783  _SEH2_TRY {
784 
785  FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
786 
789 
790  FatResetExceptionState( IrpContext );
791  } _SEH2_END;
792 
794 
795  } else {
796 
797  //
798  // We must zero between ValidDataLength and FileSize
799  //
800 
802  (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart)) {
803 
804  ULONG ValidDataLength;
805 
806  ValidDataLength = Fcb->Header.ValidDataLength.LowPart;
807 
808  if (ValidDataLength < Fcb->ValidDataToDisk) {
809  ValidDataLength = Fcb->ValidDataToDisk;
810  }
811 
812  //
813  // Recheck, VDD can be >= FS
814  //
815 
816  if (ValidDataLength < Fcb->Header.FileSize.LowPart) {
817 
818  _SEH2_TRY {
819 
820  (VOID)FatZeroData( IrpContext,
821  Vcb,
822  FileObject,
823  ValidDataLength,
824  Fcb->Header.FileSize.LowPart -
825  ValidDataLength );
826 
827  //
828  // Since we just zeroed this, we can now bump
829  // up VDL in the Fcb.
830  //
831 
833  Fcb->Header.ValidDataLength.LowPart =
834  Fcb->Header.FileSize.LowPart;
835 
836  //
837  // We inform Cc of the motion so that the cache map is updated.
838  // This prevents optimized zero-page faults in case the cache
839  // structures are re-used for another handle before they are torn
840  // down by our soon-to-occur uninitialize. If they were, a noncached
841  // producer could write into the region we just zeroed and Cc would
842  // be none the wiser, then our async cached reader comes in and takes
843  // the optimized path, and we get bad (zero) data.
844  //
845  // If this was memory mapped, we don't have to (can't) tell Cc, it'll
846  // figure it out when a cached handle is opened.
847  //
848 
849  if (CcIsFileCached( FileObject )) {
850  CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
851  }
852 
855 
856  FatResetExceptionState( IrpContext );
857  } _SEH2_END;
858  }
859  }
860  }
861 
862  //
863  // See if we are supposed to truncate the file on the last
864  // close. If we cannot wait we'll ship this off to the fsp
865  //
866 
867  _SEH2_TRY {
868 
870 
871  DebugTrace(0, Dbg, "truncate file allocation\n", 0);
872 
873  if (Vcb->VcbCondition == VcbGood) {
874 
875 
876  FatTruncateFileAllocation( IrpContext,
877  Fcb,
878  Fcb->Header.FileSize.LowPart );
879 
880 
881  }
882 
883  //
884  // We also have to get rid of the Cache Map because
885  // this is the only way we have of trashing the
886  // truncated pages.
887  //
888 
889  LocalTruncateSize = Fcb->Header.FileSize;
890  TruncateSize = &LocalTruncateSize;
891 
892  //
893  // Mark the Fcb as having now been truncated, just incase
894  // we have to reship this off to the fsp.
895  //
896 
898  }
899 
900  //
901  // Now check again if we are to delete the file and if
902  // so then we remove the file from the disk.
903  //
904 
906  Fcb->Header.AllocationSize.LowPart == 0) {
907 
908  DebugTrace(0, Dbg, "Delete File\n", 0);
909 
910  //
911  // Now tunnel and delete the dirent
912  //
913 
915 
916  FatDeleteDirent( IrpContext, Fcb, &DeleteContext, TRUE );
917 
918  //
919  // Report that we have removed an entry.
920  //
921 
922  FatNotifyReportChange( IrpContext,
923  Vcb,
924  Fcb,
927  }
928 
931 
932  FatResetExceptionState( IrpContext );
933  } _SEH2_END;
934 
936 
937 #if (NTDDI_VERSION >= NTDDI_WIN8)
938  NTSTATUS BreakStatus;
939 #endif
940  //
941  // Remove the entry from the splay table. This will
942  // ensure that we will not collide with the Fcb if the
943  // user wants to recreate the same file over again
944  // before we get a close irp.
945  //
946  // Note that we remove the name even if we couldn't
947  // truncate the allocation and remove the dirent above.
948  //
949 
950  FatRemoveNames( IrpContext, Fcb );
951 
952 #if (NTDDI_VERSION >= NTDDI_WIN8)
953  //
954  // We've removed the names so break any parent directory oplock.
955  // Directory oplock breaks are always advisory, so we will never
956  // block/get STATUS_PENDING here.
957  //
958 
959  BreakStatus = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb),
960  Irp,
961  (OPLOCK_FLAG_PARENT_OBJECT |
962  OPLOCK_FLAG_REMOVING_FILE_OR_LINK),
963  NULL,
964  NULL,
965  NULL );
966 
967  ASSERT( BreakStatus != STATUS_PENDING );
968 #endif
969  }
970  }
971  }
972 
973  //
974  // We've just finished everything associated with an unclean
975  // fcb so now decrement the unclean count before releasing
976  // the resource.
977  //
978 
979  NT_ASSERT( Fcb->UncleanCount != 0 );
980  Fcb->UncleanCount -= 1;
981  if (!FlagOn( FileObject->Flags, FO_CACHE_SUPPORTED )) {
984  }
985 
986  //
987  // If this was the last cached open, and there are open
988  // non-cached handles, attempt a flush and purge operation
989  // to avoid cache coherency overhead from these non-cached
990  // handles later. We ignore any I/O errors from the flush.
991  //
992 
993  if (FlagOn( FileObject->Flags, FO_CACHE_SUPPORTED ) &&
994  (Fcb->NonCachedUncleanCount != 0) &&
997 
999 
1000  //
1001  // Grab and release PagingIo to serialize ourselves with the lazy writer.
1002  // This will work to ensure that all IO has completed on the cached
1003  // data and we will succesfully tear away the cache section.
1004  //
1005 
1006  ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
1007  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
1008 
1010  NULL,
1011  0,
1012  FALSE );
1013  }
1014 
1015  //
1016  // If the file is invalid, hint to the cache that we should throw everything out.
1017  //
1018 
1019  if ( Fcb->FcbCondition == FcbBad ) {
1020 
1021  TruncateSize = &FatLargeZero;
1022  }
1023 
1024  //
1025  // Cleanup the cache map
1026  //
1027 
1028  CcUninitializeCacheMap( FileObject, TruncateSize, NULL );
1029 
1030  break;
1031 
1032  default:
1033 
1034 #ifdef _MSC_VER
1035 #pragma prefast( suppress: 28159, "if the type of open is unknown then things are very bad." )
1036 #endif
1037  FatBugCheck( TypeOfOpen, 0, 0 );
1038  }
1039 
1040  //
1041  // We must clean up the share access at this time, since we may not
1042  // get a Close call for awhile if the file was mapped through this
1043  // File Object.
1044  //
1045 
1046  if (ShareAccess != NULL) {
1047 
1048  DebugTrace(0, Dbg, "Cleanup the Share access\n", 0);
1050  }
1051 
1052  if ((TypeOfOpen == UserFileOpen)
1053 #if (NTDDI_VERSION >= NTDDI_WIN8)
1054  ||
1056 #endif
1057  ) {
1058 
1059  //
1060  // Coordinate the cleanup operation with the oplock state.
1061  // Cleanup operations can always cleanup immediately.
1062  //
1063 
1065  Irp,
1066  IrpContext,
1067  NULL,
1068  NULL );
1069 
1070  Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
1071  }
1072 
1073  //
1074  // First set the FO_CLEANUP_COMPLETE flag.
1075  //
1076 
1078 
1080 
1081  //
1082  // Now unpin any repinned Bcbs.
1083  //
1084 
1085  FatUnpinRepinnedBcbs( IrpContext );
1086 
1087  //
1088  // If this was deferred flush media, flush the volume.
1089  // We used to do this in lieu of write through for all removable
1090  // media.
1091  //
1092 
1093  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
1094  !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
1095 
1096  //
1097  // Flush the file.
1098  //
1099 
1100  if ((TypeOfOpen == UserFileOpen) &&
1101  FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
1102 
1103  Status = FatFlushFile( IrpContext, Fcb, Flush );
1104  }
1105 
1106  //
1107  // If that worked ok, then see if we should flush the FAT as well.
1108  //
1109 
1110  if (NT_SUCCESS(Status) && Fcb && !FatIsFat12( Vcb) &&
1112 
1113  Status = FatFlushFat( IrpContext, Vcb);
1114 
1115  //
1116  // Also flush the parent directory.
1117  //
1118 
1119  if (NT_SUCCESS(Status) && (Fcb->ParentDcb != NULL)) {
1120 
1121  Status = FatFlushFile( IrpContext, Fcb->ParentDcb, Flush );
1122  }
1123  }
1124 
1125  if (!NT_SUCCESS(Status)) {
1126 
1127  FatNormalizeAndRaiseStatus( IrpContext, Status );
1128  }
1129  }
1130 
1131 #if (NTDDI_VERSION >= NTDDI_WIN8)
1132 
1133  try_exit: NOTHING;
1134 
1135 #endif
1136 
1137  } _SEH2_FINALLY {
1138 
1139  DebugUnwind( FatCommonCleanup );
1140 
1141  if (AcquiredFcb) { FatReleaseFcb( IrpContext, Fcb ); }
1142  if (AcquiredVcb) { FatReleaseVcb( IrpContext, Vcb ); }
1143 
1144  if (SendUnlockNotification) {
1145 
1147  }
1148 
1149  //
1150  // If this is a normal termination then complete the request
1151  //
1152 
1153  if (!_SEH2_AbnormalTermination() &&
1154  (Status != STATUS_PENDING)) {
1155 
1156  FatCompleteRequest( IrpContext, Irp, Status );
1157  }
1158 
1159  DebugTrace(-1, Dbg, "FatCommonCleanup -> %08lx\n", Status);
1160  } _SEH2_END;
1161 
1162  return Status;
1163 }
1164 
1165 VOID
1167  IN PIRP_CONTEXT IrpContext,
1168  IN PVCB Vcb
1169  )
1170 {
1171  KIRQL SavedIrql;
1172 
1173  //
1174  // Unlock the volume.
1175  //
1176 
1177  UNREFERENCED_PARAMETER( IrpContext );
1178 
1179  IoAcquireVpbSpinLock( &SavedIrql );
1180 
1181  ClearFlag( Vcb->Vpb->Flags, (VPB_LOCKED | VPB_DIRECT_WRITES_ALLOWED) );
1182 
1183  Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
1184  Vcb->FileObjectWithVcbLocked = NULL;
1185 
1186  IoReleaseVpbSpinLock( SavedIrql );
1187 }
1188 
1189 
PEPROCESS NTAPI IoGetRequestorProcess(IN PIRP Irp)
Definition: irp.c:1782
BOOLEAN NTAPI CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps)
Definition: fssup.c:384
#define IN
Definition: typedefs.h:38
BOOLEAN NTAPI FsRtlIsNtstatusExpected(IN NTSTATUS NtStatus)
Definition: filter.c:61
#define TRUE
Definition: types.h:120
#define FatNormalizeAndRaiseStatus(IRPCONTEXT, STATUS)
Definition: fatprocs.h:2983
#define FsRtlEnterFileSystem
BOOLEAN FatIsIrpTopLevel(IN PIRP Irp)
Definition: fatdata.c:817
VOID NTAPI CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN OPTIONAL PLARGE_INTEGER FileOffset, IN ULONG Length, OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
Definition: cachesub.c:222
#define VCB_STATE_FLAG_DEFERRED_FLUSH
Definition: fatstruc.h:567
#define FsRtlExitFileSystem
FSRTL_ADVANCED_FCB_HEADER Header
Definition: cdstruc.h:931
#define FatCompleteRequest(IRPCONTEXT, IRP, STATUS)
Definition: fatprocs.h:2621
VOID NTAPI FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
Definition: notify.c:1458
_In_ PIRP Irp
Definition: csq.h:116
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
Definition: cdstruc.h:908
LARGE_INTEGER FatLargeZero
Definition: fatdata.c:62
VOID FatUnpinRepinnedBcbs(IN PIRP_CONTEXT IrpContext)
Definition: cachesup.c:1407
Definition: cdstruc.h:1073
#define FCB_STATE_FLUSH_FAT
Definition: fatstruc.h:1196
#define FatNotifyReportChange(I, V, F, FL, A)
Definition: fatprocs.h:2156
VOID NTAPI FatOplockComplete(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:35
#define FatIsFat12(VCB)
Definition: fatprocs.h:1439
LONG NTSTATUS
Definition: precomp.h:26
#define FatDeviceIsFatFsdo(D)
Definition: fatprocs.h:3083
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
#define FILE_OPENED
Definition: nt_native.h:769
#define FSRTL_VOLUME_UNLOCK
Definition: ntifs_ex.h:443
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
VOID NTAPI IoAcquireVpbSpinLock(OUT PKIRQL Irql)
Definition: volume.c:1209
Definition: cdstruc.h:504
#define VCB_STATE_FLAG_WRITE_PROTECTED
Definition: fatstruc.h:569
#define FILE_NOTIFY_CHANGE_FILE_NAME
SECTION_OBJECT_POINTERS SectionObjectPointers
Definition: fatstruc.h:728
#define FILE_NOTIFY_CHANGE_DIR_NAME
struct _FCB * ParentDcb
Definition: fatstruc.h:835
#define CCB_FLAG_DELETE_ON_CLOSE
Definition: fatstruc.h:1288
ULONG FirstClusterOfFile
Definition: fatstruc.h:1663
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK _In_ USHORT ShareAccess
Definition: create.c:4157
VOID NTAPI IoRemoveShareAccess(IN PFILE_OBJECT FileObject, IN PSHARE_ACCESS ShareAccess)
Definition: file.c:3477
#define PAGED_CODE()
Definition: video.h:57
_SEH2_TRY
Definition: create.c:4250
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2401
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
VOID NTAPI FsRtlNotifyCleanup(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:635
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define CCB_FLAG_DENY_DEFRAG
Definition: fatstruc.h:1351
#define FO_FILE_MODIFIED
Definition: iotypes.h:1745
#define EXCEPTION_CONTINUE_SEARCH
Definition: excpt.h:86
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:593
#define IO_DISK_INCREMENT
Definition: iotypes.h:568
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
Definition: Header.h:8
#define FCB_STATE_PAGING_FILE
Definition: fatstruc.h:1194
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1647
#define CcIsFileCached(FO)
#define VPB_LOCKED
Definition: iotypes.h:1765
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
union _FCB::@693 Specific
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
PNON_PAGED_FCB NonPaged
Definition: fatstruc.h:810
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define FILE_ACTION_REMOVED
#define _SEH2_AbnormalTermination()
Definition: pseh2_64.h:13
#define IoCompleteRequest
Definition: irp.c:1240
NodeType
Definition: Node.h:5
#define FCB_STATE_TRUNCATE_ON_CLOSE
Definition: fatstruc.h:1193
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
PIRP_CONTEXT FatCreateIrpContext(IN PIRP Irp, IN BOOLEAN Wait)
Definition: strucsup.c:2300
struct _FCB::@693::@695 Dcb
#define FCB_STATE_DENY_DEFRAG
Definition: fatstruc.h:1216
VOID FatRemoveNames(IN PIRP_CONTEXT IrpContext, IN PFCB Fcb)
Definition: splaysup.c:222
NTSTATUS FatFlushFat(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: flush.c:801
#define NTDDI_VERSION
Definition: k32.h:33
#define CCB_FLAG_COMPLETE_DISMOUNT
Definition: fatstruc.h:1330
#define DebugUnwind(X)
Definition: fatdata.h:315
#define FatReleaseFcb(IRPCONTEXT, Fcb)
Definition: fatprocs.h:1635
SHARE_ACCESS ShareAccess
Definition: cdstruc.h:1015
NTSTATUS NTAPI FsRtlNotifyVolumeEvent(IN PFILE_OBJECT FileObject, IN ULONG EventCode)
Definition: pnp.c:38
#define FatResetExceptionState(IRPCONTEXT)
Definition: fatprocs.h:2971
#define VCB_STATE_FLAG_LOCKED
Definition: fatstruc.h:558
CLONG NonCachedUncleanCount
Definition: fatstruc.h:887
#define VPB_DIRECT_WRITES_ALLOWED
Definition: iotypes.h:1769
#define FCB_STATE_DELETE_ON_CLOSE
Definition: fatstruc.h:1192
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define try_return(S)
Definition: cdprocs.h:2189
#define Vcb
Definition: cdprocs.h:1425
#define FCB_STATE_DELAY_CLOSE
Definition: fatstruc.h:1202
#define FatIsFileOplockable(F)
Definition: fatprocs.h:2839
FINISHED FatZeroData(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_OBJECT FileObject, IN ULONG StartingZero, IN ULONG ByteCount)
Definition: cachesup.c:1659
#define _Inout_
Definition: no_sal2.h:244
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
_Function_class_(IRP_MJ_CLEANUP)
Definition: cleanup.c:47
* PFILE_OBJECT
Definition: iotypes.h:1955
#define FO_CACHE_SUPPORTED
Definition: iotypes.h:1738
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
ULONG Flags
Definition: ntfs.h:532
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000
#define VOID
Definition: acefi.h:82
CLONG UncleanCount
Definition: fatstruc.h:872
enum _TYPE_OF_OPEN TYPE_OF_OPEN
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:593
#define NOTHING
Definition: env_spec_w32.h:461
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
NTSTATUS NTAPI FsRtlFastUnlockAll(IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, IN PEPROCESS Process, IN PVOID Context OPTIONAL)
Definition: filelock.c:1026
DRIVER_DISPATCH(nfs41_FsdDispatch)
#define Dbg
Definition: cleanup.c:29
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
Status
Definition: gdiplustypes.h:24
#define _In_
Definition: no_sal2.h:204
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define VCB_STATE_FLAG_SHUTDOWN
Definition: fatstruc.h:562
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
PFILE_OBJECT FileObject
Definition: iotypes.h:2813
_SEH2_END
Definition: create.c:4424
ULONG ValidDataToDisk
Definition: fatstruc.h:927
BOOLEAN NTAPI CcUninitializeCacheMap(IN PFILE_OBJECT FileObject, IN OPTIONAL PLARGE_INTEGER TruncateSize, IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
Definition: fssup.c:284
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
#define FatAcquireExclusiveVcb(IC, V)
Definition: fatprocs.h:1451
#define FatIsFastIoPossible(FCB)
Definition: fatprocs.h:2801
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1747
#define FAT_NTC_ROOT_DCB
Definition: nodetype.h:31
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4157
VOID NTAPI CcSetFileSizes(IN PFILE_OBJECT FileObject, IN PCC_FILE_SIZES FileSizes)
Definition: fssup.c:354
struct _FCB::@693::@696 Fcb
_Requires_lock_held_(_Global_critical_region_)
Definition: cleanup.c:25
_SEH2_FINALLY
Definition: create.c:4395
#define FatReleaseVcb(IRPCONTEXT, Vcb)
Definition: fatprocs.h:1631
CLONG OpenCount
Definition: fatstruc.h:880
#define FAT_NTC_DCB
Definition: nodetype.h:30
VOID FatTunnelFcbOrDcb(IN PFCB FcbOrDcb, IN PCCB Ccb OPTIONAL)
Definition: dirsup.c:652
ULONG FirstClusterOfFile
Definition: fatstruc.h:817
#define IRP_MJ_CLEANUP
VOID FatAutoUnlock(IN PIRP_CONTEXT IrpContext, IN PVCB Vcb)
Definition: cleanup.c:1166
unsigned int ULONG
Definition: retypes.h:1
NTSTATUS FatHijackIrpAndFlushDevice(IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PDEVICE_OBJECT TargetDeviceObject)
Definition: flush.c:1101
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
NTSTATUS NTAPI FsRtlCheckOplock(IN POPLOCK Oplock, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:1172
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
#define NTDDI_WIN8
Definition: sdkddkver.h:113
_In_ PFCB Fcb
Definition: cdprocs.h:151
return STATUS_SUCCESS
Definition: btrfs.c:2966
VOID NTAPI FatPrePostIrp(IN PVOID Context, IN PIRP Irp)
Definition: workque.c:91
#define IRP_CONTEXT_FLAG_CLEANUP_BREAKING_OPLOCK
Definition: fatstruc.h:1570
VOID NTAPI IoReleaseVpbSpinLock(IN KIRQL Irql)
Definition: volume.c:1220
ULONG FcbState
Definition: cdstruc.h:977
TYPE_OF_OPEN FatDecodeFileObject(_In_ PFILE_OBJECT FileObject, _Outptr_ PVCB *Vcb, _Outptr_ PFCB *FcbOrDcb, _Outptr_ PCCB *Ccb)
Definition: filobsup.c:176
#define NT_ASSERT
Definition: rtlfuncs.h:3312
FCB_CONDITION FcbCondition
Definition: fatstruc.h:849