[FASTFAT_NEW] Fix build with FASTFATDBG set
[reactos.git] / drivers / filesystems / fastfat_new / cleanup.c
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
36 FatAutoUnlock (
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 \f
47 NTSTATUS
48 NTAPI
49 FatFsdCleanup (
50 IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
51 IN PIRP Irp
52 )
53
54 /*++
55
56 Routine Description:
57
58 This routine implements the FSD part of closing down a handle to a
59 file object.
60
61 Arguments:
62
63 VolumeDeviceObject - Supplies the volume device object where the
64 file being Cleanup exists
65
66 Irp - Supplies the Irp being processed
67
68 Return Value:
69
70 NTSTATUS - The FSD status for the IRP
71
72 --*/
73
74 {
75 NTSTATUS Status;
76 PIRP_CONTEXT IrpContext = NULL;
77
78 BOOLEAN TopLevel;
79
80 //
81 // If we were called with our file system device object instead of a
82 // volume device object, just complete this request with STATUS_SUCCESS
83 //
84
85 if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) {
86
87 Irp->IoStatus.Status = STATUS_SUCCESS;
88 Irp->IoStatus.Information = FILE_OPENED;
89
90 IoCompleteRequest( Irp, IO_DISK_INCREMENT );
91
92 return STATUS_SUCCESS;
93 }
94
95 DebugTrace(+1, Dbg, "FatFsdCleanup\n", 0);
96
97 //
98 // Call the common Cleanup routine, with blocking allowed.
99 //
100
101 FsRtlEnterFileSystem();
102
103 TopLevel = FatIsIrpTopLevel( Irp );
104
105 _SEH2_TRY {
106
107 IrpContext = FatCreateIrpContext( Irp, TRUE );
108
109 Status = FatCommonCleanup( IrpContext, Irp );
110
111 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
112
113 //
114 // We had some trouble trying to perform the requested
115 // operation, so we'll abort the I/O request with
116 // the error status that we get back from the
117 // execption code
118 //
119
120 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
121 } _SEH2_END;
122
123 if (TopLevel) { IoSetTopLevelIrp( NULL ); }
124
125 FsRtlExitFileSystem();
126
127 //
128 // And return to our caller
129 //
130
131 DebugTrace(-1, Dbg, "FatFsdCleanup -> %08lx\n", Status);
132
133 UNREFERENCED_PARAMETER( VolumeDeviceObject );
134
135 return Status;
136 }
137
138 \f
139 NTSTATUS
140 FatCommonCleanup (
141 IN PIRP_CONTEXT IrpContext,
142 IN PIRP Irp
143 )
144
145 /*++
146
147 Routine Description:
148
149 This is the common routine for cleanup of a file/directory called by both
150 the fsd and fsp threads.
151
152 Cleanup is invoked whenever the last handle to a file object is closed.
153 This is different than the Close operation which is invoked when the last
154 reference to a file object is deleted.
155
156 The function of cleanup is to essentially "cleanup" the file/directory
157 after a user is done with it. The Fcb/Dcb remains around (because MM
158 still has the file object referenced) but is now available for another
159 user to open (i.e., as far as the user is concerned the is now closed).
160
161 See close for a more complete description of what close does.
162
163 Arguments:
164
165 Irp - Supplies the Irp to process
166
167 Return Value:
168
169 NTSTATUS - The return status for the operation
170
171 --*/
172
173 {
174 NTSTATUS Status;
175
176 PIO_STACK_LOCATION IrpSp;
177
178 PFILE_OBJECT FileObject;
179
180 TYPE_OF_OPEN TypeOfOpen;
181 PVCB Vcb;
182 PFCB Fcb;
183 PCCB Ccb;
184
185 BOOLEAN SendUnlockNotification = FALSE;
186
187 PSHARE_ACCESS ShareAccess;
188
189 PLARGE_INTEGER TruncateSize = NULL;
190 LARGE_INTEGER LocalTruncateSize;
191
192 BOOLEAN AcquiredVcb = FALSE;
193 BOOLEAN AcquiredFcb = FALSE;
194
195 IrpSp = IoGetCurrentIrpStackLocation( Irp );
196
197 DebugTrace(+1, Dbg, "FatCommonCleanup\n", 0);
198 DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
199 DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject);
200
201 //
202 // Extract and decode the file object
203 //
204
205 FileObject = IrpSp->FileObject;
206 TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
207
208 //
209 // Special case the unopened file object. This will occur only when
210 // we are initializing Vcb and IoCreateStreamFileObject is being
211 // called.
212 //
213
214 if (TypeOfOpen == UnopenedFileObject) {
215
216 DebugTrace(0, Dbg, "Unopened File Object\n", 0);
217
218 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
219
220 DebugTrace(-1, Dbg, "FatCommonCleanup -> STATUS_SUCCESS\n", 0);
221 return STATUS_SUCCESS;
222 }
223
224 //
225 // If this is not our first time through (for whatever reason)
226 // only see if we have to flush the file.
227 //
228
229 if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) {
230
231 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
232 FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
233 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED) &&
234 (TypeOfOpen == UserFileOpen)) {
235
236 //
237 // Flush the file.
238 //
239
240 Status = FatFlushFile( IrpContext, Fcb, Flush );
241
242 if (!NT_SUCCESS(Status)) {
243
244 FatNormalizeAndRaiseStatus( IrpContext, Status );
245 }
246 }
247
248 FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
249
250 DebugTrace(-1, Dbg, "FatCommonCleanup -> STATUS_SUCCESS\n", 0);
251 return STATUS_SUCCESS;
252 }
253
254 //
255 // If we call change the allocation or call CcUninitialize,
256 // we have to take the Fcb exclusive
257 //
258
259 if ((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) {
260
261 ASSERT( Fcb != NULL );
262
263 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
264
265 AcquiredFcb = TRUE;
266
267 //
268 // Do a check here if this was a DELETE_ON_CLOSE FileObject, and
269 // set the Fcb flag appropriately.
270 //
271
272 if (FlagOn(Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE)) {
273
274 ASSERT( NodeType(Fcb) != FAT_NTC_ROOT_DCB );
275
276 SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
277
278 //
279 // Report this to the dir notify package for a directory.
280 //
281
282 if (TypeOfOpen == UserDirectoryOpen) {
283
284 FsRtlNotifyFullChangeDirectory( Vcb->NotifySync,
285 &Vcb->DirNotifyList,
286 FileObject->FsContext,
287 NULL,
288 FALSE,
289 FALSE,
290 0,
291 NULL,
292 NULL,
293 NULL );
294 }
295 }
296
297 //
298 // Now if we may delete the file, drop the Fcb and acquire the Vcb
299 // first. Note that while we own the Fcb exclusive, a file cannot
300 // become DELETE_ON_CLOSE and cannot be opened via CommonCreate.
301 //
302
303 if ((Fcb->UncleanCount == 1) &&
304 FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
305 (Fcb->FcbCondition != FcbBad) &&
306 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
307
308 FatReleaseFcb( IrpContext, Fcb );
309 AcquiredFcb = FALSE;
310
311 (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
312 AcquiredVcb = TRUE;
313
314 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
315 AcquiredFcb = TRUE;
316 }
317 }
318
319 //
320 // For user DASD cleanups, grab the Vcb exclusive.
321 //
322
323 if (TypeOfOpen == UserVolumeOpen) {
324
325 (VOID)FatAcquireExclusiveVcb( IrpContext, Vcb );
326 AcquiredVcb = TRUE;
327 }
328
329 //
330 // Complete any Notify Irps on this file handle.
331 //
332
333 if (TypeOfOpen == UserDirectoryOpen) {
334
335 FsRtlNotifyCleanup( Vcb->NotifySync,
336 &Vcb->DirNotifyList,
337 Ccb );
338 }
339
340 //
341 // Determine the Fcb state, Good or Bad, for better or for worse.
342 //
343 // We can only read the volume file if VcbCondition is good.
344 //
345
346 if ( Fcb != NULL) {
347
348 //
349 // Stop any raises from FatVerifyFcb, unless it is REAL bad.
350 //
351
352 _SEH2_TRY {
353
354 _SEH2_TRY {
355
356 FatVerifyFcb( IrpContext, Fcb );
357
358 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
359 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
360
361 FatResetExceptionState( IrpContext );
362 } _SEH2_END;
363
364 } _SEH2_FINALLY {
365
366 if ( _SEH2_AbnormalTermination() ) {
367
368 //
369 // We will be raising out of here.
370 //
371
372 if (AcquiredFcb) { FatReleaseFcb( IrpContext, Fcb ); }
373 if (AcquiredVcb) { FatReleaseVcb( IrpContext, Vcb ); }
374 }
375 } _SEH2_END;
376 }
377
378 _SEH2_TRY {
379
380 //
381 // Case on the type of open that we are trying to cleanup.
382 // For all cases we need to set the share access to point to the
383 // share access variable (if there is one). After the switch
384 // we then remove the share access and complete the Irp.
385 // In the case of UserFileOpen we actually have a lot more work
386 // to do and we have the FsdLockControl complete the Irp for us.
387 //
388
389 switch (TypeOfOpen) {
390
391 case DirectoryFile:
392 case VirtualVolumeFile:
393
394 DebugTrace(0, Dbg, "Cleanup VirtualVolumeFile/DirectoryFile\n", 0);
395
396 ShareAccess = NULL;
397
398 break;
399
400 case UserVolumeOpen:
401
402 DebugTrace(0, Dbg, "Cleanup UserVolumeOpen\n", 0);
403
404 if (FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) {
405
406 FatCheckForDismount( IrpContext, Vcb, TRUE );
407
408 //
409 // If this handle had write access, and actually wrote something,
410 // flush the device buffers, and then set the verify bit now
411 // just to be safe (in case there is no dismount).
412 //
413
414 } else if (FileObject->WriteAccess &&
415 FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
416
417 (VOID)FatHijackIrpAndFlushDevice( IrpContext,
418 Irp,
419 Vcb->TargetDeviceObject );
420
421 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
422 }
423
424 //
425 // If the volume is locked by this file object then release
426 // the volume and send notification.
427 //
428
429 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED) &&
430 (Vcb->FileObjectWithVcbLocked == FileObject)) {
431
432 FatAutoUnlock( IrpContext, Vcb );
433 SendUnlockNotification = TRUE;
434 }
435
436 ShareAccess = &Vcb->ShareAccess;
437
438 break;
439
440 case EaFile:
441
442 DebugTrace(0, Dbg, "Cleanup EaFileObject\n", 0);
443
444 ShareAccess = NULL;
445
446 break;
447
448 case UserDirectoryOpen:
449
450 DebugTrace(0, Dbg, "Cleanup UserDirectoryOpen\n", 0);
451
452 ShareAccess = &Fcb->ShareAccess;
453
454 //
455 // Determine here if we should try do delayed close.
456 //
457
458 if ((Fcb->UncleanCount == 1) &&
459 (Fcb->OpenCount == 1) &&
460 (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0) &&
461 !FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
462 Fcb->FcbCondition == FcbGood) {
463
464 //
465 // Delay our close.
466 //
467
468 SetFlag( Fcb->FcbState, FCB_STATE_DELAY_CLOSE );
469 }
470
471 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
472
473 //
474 // If the directory has a unclean count of 1 then we know
475 // that this is the last handle for the file object. If
476 // we are supposed to delete it, do so.
477 //
478
479 if ((Fcb->UncleanCount == 1) &&
480 (NodeType(Fcb) == FAT_NTC_DCB) &&
481 (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) &&
482 (Fcb->FcbCondition != FcbBad) &&
483 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
484
485 if (!FatIsDirectoryEmpty(IrpContext, Fcb)) {
486
487 //
488 // If there are files in the directory at this point,
489 // forget that we were trying to delete it.
490 //
491
492 ClearFlag( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE );
493
494 } else {
495
496 //
497 // Even if something goes wrong, we cannot turn back!
498 //
499
500 _SEH2_TRY {
501
502 DELETE_CONTEXT DeleteContext;
503
504 //
505 // Before truncating file allocation remember this
506 // info for FatDeleteDirent.
507 //
508
509 DeleteContext.FileSize = Fcb->Header.FileSize.LowPart;
510 DeleteContext.FirstClusterOfFile = Fcb->FirstClusterOfFile;
511
512 //
513 // Synchronize here with paging IO
514 //
515
516 (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
517 TRUE );
518
519 Fcb->Header.FileSize.LowPart = 0;
520
521 ExReleaseResourceLite( Fcb->Header.PagingIoResource );
522
523 if (Vcb->VcbCondition == VcbGood) {
524
525 //
526 // Truncate the file allocation down to zero
527 //
528
529 DebugTrace(0, Dbg, "Delete File allocation\n", 0);
530
531 FatTruncateFileAllocation( IrpContext, Fcb, 0 );
532
533 if (Fcb->Header.AllocationSize.LowPart == 0) {
534
535 //
536 // Tunnel and remove the dirent for the directory
537 //
538
539 DebugTrace(0, Dbg, "Delete the directory dirent\n", 0);
540
541 FatTunnelFcbOrDcb( Fcb, NULL );
542
543 FatDeleteDirent( IrpContext, Fcb, &DeleteContext, TRUE );
544
545 //
546 // Report that we have removed an entry.
547 //
548
549 FatNotifyReportChange( IrpContext,
550 Vcb,
551 Fcb,
552 FILE_NOTIFY_CHANGE_DIR_NAME,
553 FILE_ACTION_REMOVED );
554 }
555 }
556
557 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
558 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
559
560 FatResetExceptionState( IrpContext );
561 } _SEH2_END;
562
563 //
564 // Remove the entry from the name table.
565 // This will ensure that
566 // we will not collide with the Dcb if the user wants
567 // to recreate the same file over again before we
568 // get a close irp.
569 //
570
571 FatRemoveNames( IrpContext, Fcb );
572 }
573 }
574
575 //
576 // Decrement the unclean count.
577 //
578
579 ASSERT( Fcb->UncleanCount != 0 );
580 Fcb->UncleanCount -= 1;
581
582 break;
583
584 case UserFileOpen:
585
586 DebugTrace(0, Dbg, "Cleanup UserFileOpen\n", 0);
587
588 ShareAccess = &Fcb->ShareAccess;
589
590 //
591 // Determine here if we should do a delayed close.
592 //
593
594 if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
595 (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
596 (Fcb->UncleanCount == 1) &&
597 (Fcb->OpenCount == 1) &&
598 !FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
599 Fcb->FcbCondition == FcbGood) {
600
601 //
602 // Delay our close.
603 //
604
605 SetFlag( Fcb->FcbState, FCB_STATE_DELAY_CLOSE );
606 }
607
608 //
609 // Unlock all outstanding file locks.
610 //
611
612 (VOID) FsRtlFastUnlockAll( &Fcb->Specific.Fcb.FileLock,
613 FileObject,
614 IoGetRequestorProcess( Irp ),
615 NULL );
616
617 //
618 // We can proceed with on-disk updates only if the volume is mounted.
619 // Remember that we toss all sections in the failed-verify and dismount
620 // cases.
621 //
622
623 if (Vcb->VcbCondition == VcbGood) {
624
625 if (Fcb->FcbCondition != FcbBad) {
626
627 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
628 }
629
630 //
631 // If the file has a unclean count of 1 then we know
632 // that this is the last handle for the file object.
633 //
634
635 if ( (Fcb->UncleanCount == 1) && (Fcb->FcbCondition != FcbBad) ) {
636
637 DELETE_CONTEXT DeleteContext;
638
639 //
640 // Check if we should be deleting the file. The
641 // delete operation really deletes the file but
642 // keeps the Fcb around for close to do away with.
643 //
644
645 if (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
646 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
647
648 //
649 // Before truncating file allocation remember this
650 // info for FatDeleteDirent.
651 //
652
653 DeleteContext.FileSize = Fcb->Header.FileSize.LowPart;
654 DeleteContext.FirstClusterOfFile = Fcb->FirstClusterOfFile;
655
656 DebugTrace(0, Dbg, "Delete File allocation\n", 0);
657
658 //
659 // Synchronize here with paging IO
660 //
661
662 (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource,
663 TRUE );
664
665 Fcb->Header.FileSize.LowPart = 0;
666 Fcb->Header.ValidDataLength.LowPart = 0;
667 Fcb->ValidDataToDisk = 0;
668
669 ExReleaseResourceLite( Fcb->Header.PagingIoResource );
670
671 _SEH2_TRY {
672
673 FatSetFileSizeInDirent( IrpContext, Fcb, NULL );
674
675 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
676 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
677
678 FatResetExceptionState( IrpContext );
679 } _SEH2_END;
680
681 Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE;
682
683 } else {
684
685 //
686 // We must zero between ValidDataLength and FileSize
687 //
688
689 if (!FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
690 (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart)) {
691
692 ULONG ValidDataLength;
693
694 ValidDataLength = Fcb->Header.ValidDataLength.LowPart;
695
696 if (ValidDataLength < Fcb->ValidDataToDisk) {
697 ValidDataLength = Fcb->ValidDataToDisk;
698 }
699
700 //
701 // Recheck, VDD can be >= FS
702 //
703
704 if (ValidDataLength < Fcb->Header.FileSize.LowPart) {
705
706 _SEH2_TRY {
707
708 (VOID)FatZeroData( IrpContext,
709 Vcb,
710 FileObject,
711 ValidDataLength,
712 Fcb->Header.FileSize.LowPart -
713 ValidDataLength );
714
715 //
716 // Since we just zeroed this, we can now bump
717 // up VDL in the Fcb.
718 //
719
720 Fcb->ValidDataToDisk =
721 Fcb->Header.ValidDataLength.LowPart =
722 Fcb->Header.FileSize.LowPart;
723
724 //
725 // We inform Cc of the motion so that the cache map is updated.
726 // This prevents optimized zero-page faults in case the cache
727 // structures are re-used for another handle before they are torn
728 // down by our soon-to-occur uninitialize. If they were, a noncached
729 // producer could write into the region we just zeroed and Cc would
730 // be none the wiser, then our async cached reader comes in and takes
731 // the optimized path, and we get bad (zero) data.
732 //
733 // If this was memory mapped, we don't have to (can't) tell Cc, it'll
734 // figure it out when a cached handle is opened.
735 //
736
737 if (CcIsFileCached( FileObject )) {
738 CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
739 }
740
741 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
742 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
743
744 FatResetExceptionState( IrpContext );
745 } _SEH2_END;
746 }
747 }
748 }
749
750 //
751 // See if we are supposed to truncate the file on the last
752 // close. If we cannot wait we'll ship this off to the fsp
753 //
754
755 _SEH2_TRY {
756
757 if (FlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE)) {
758
759 DebugTrace(0, Dbg, "truncate file allocation\n", 0);
760
761 if (Vcb->VcbCondition == VcbGood) {
762
763 FatTruncateFileAllocation( IrpContext,
764 Fcb,
765 Fcb->Header.FileSize.LowPart );
766 }
767
768 //
769 // We also have to get rid of the Cache Map because
770 // this is the only way we have of trashing the
771 // truncated pages.
772 //
773
774 LocalTruncateSize = Fcb->Header.FileSize;
775 TruncateSize = &LocalTruncateSize;
776
777 //
778 // Mark the Fcb as having now been truncated, just incase
779 // we have to reship this off to the fsp.
780 //
781
782 Fcb->FcbState &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
783 }
784
785 //
786 // Now check again if we are to delete the file and if
787 // so then we remove the file from the disk.
788 //
789
790 if (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE) &&
791 Fcb->Header.AllocationSize.LowPart == 0) {
792
793 DebugTrace(0, Dbg, "Delete File\n", 0);
794
795 //
796 // Now tunnel and delete the dirent
797 //
798
799 FatTunnelFcbOrDcb( Fcb, Ccb );
800
801 FatDeleteDirent( IrpContext, Fcb, &DeleteContext, TRUE );
802
803 //
804 // Report that we have removed an entry.
805 //
806
807 FatNotifyReportChange( IrpContext,
808 Vcb,
809 Fcb,
810 FILE_NOTIFY_CHANGE_FILE_NAME,
811 FILE_ACTION_REMOVED );
812 }
813
814 } _SEH2_EXCEPT( FsRtlIsNtstatusExpected(_SEH2_GetExceptionCode()) ?
815 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
816
817 FatResetExceptionState( IrpContext );
818 } _SEH2_END;
819
820 if (FlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) {
821
822 //
823 // Remove the entry from the splay table. This will
824 // ensure that we will not collide with the Fcb if the
825 // user wants to recreate the same file over again
826 // before we get a close irp.
827 //
828 // Note that we remove the name even if we couldn't
829 // truncate the allocation and remove the dirent above.
830 //
831
832 FatRemoveNames( IrpContext, Fcb );
833 }
834 }
835 }
836
837 //
838 // We've just finished everything associated with an unclean
839 // fcb so now decrement the unclean count before releasing
840 // the resource.
841 //
842
843 ASSERT( Fcb->UncleanCount != 0 );
844 Fcb->UncleanCount -= 1;
845 if (!FlagOn( FileObject->Flags, FO_CACHE_SUPPORTED )) {
846 ASSERT( Fcb->NonCachedUncleanCount != 0 );
847 Fcb->NonCachedUncleanCount -= 1;
848 }
849
850 //
851 // If this was the last cached open, and there are open
852 // non-cached handles, attempt a flush and purge operation
853 // to avoid cache coherency overhead from these non-cached
854 // handles later. We ignore any I/O errors from the flush.
855 //
856
857 if (FlagOn( FileObject->Flags, FO_CACHE_SUPPORTED ) &&
858 (Fcb->NonCachedUncleanCount != 0) &&
859 (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
860 (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)) {
861
862 CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, NULL );
863
864 //
865 // Grab and release PagingIo to serialize ourselves with the lazy writer.
866 // This will work to ensure that all IO has completed on the cached
867 // data and we will succesfully tear away the cache section.
868 //
869
870 ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
871 ExReleaseResourceLite( Fcb->Header.PagingIoResource );
872
873 CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers,
874 NULL,
875 0,
876 FALSE );
877 }
878
879 //
880 // If the file is invalid, hint to the cache that we should throw everything out.
881 //
882
883 if ( Fcb->FcbCondition == FcbBad ) {
884
885 TruncateSize = &FatLargeZero;
886 }
887
888 //
889 // Cleanup the cache map
890 //
891
892 CcUninitializeCacheMap( FileObject, TruncateSize, NULL );
893
894 break;
895
896 default:
897
898 FatBugCheck( TypeOfOpen, 0, 0 );
899 }
900
901 //
902 // We must clean up the share access at this time, since we may not
903 // get a Close call for awhile if the file was mapped through this
904 // File Object.
905 //
906
907 if (ShareAccess != NULL) {
908
909 DebugTrace(0, Dbg, "Cleanup the Share access\n", 0);
910 IoRemoveShareAccess( FileObject, ShareAccess );
911 }
912
913 if (TypeOfOpen == UserFileOpen) {
914
915 //
916 // Coordinate the cleanup operation with the oplock state.
917 // Cleanup operations can always cleanup immediately.
918 //
919
920 FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock,
921 Irp,
922 IrpContext,
923 NULL,
924 NULL );
925
926 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
927 }
928
929 //
930 // First set the FO_CLEANUP_COMPLETE flag.
931 //
932
933 SetFlag( FileObject->Flags, FO_CLEANUP_COMPLETE );
934
935 Status = STATUS_SUCCESS;
936
937 //
938 // Now unpin any repinned Bcbs.
939 //
940
941 FatUnpinRepinnedBcbs( IrpContext );
942
943 //
944 // If this was deferred flush media, flush the volume.
945 // We used to do this in lieu of write through for all removable
946 // media.
947 //
948
949 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
950 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
951
952 //
953 // Flush the file.
954 //
955
956 if ((TypeOfOpen == UserFileOpen) &&
957 FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
958
959 Status = FatFlushFile( IrpContext, Fcb, Flush );
960 }
961
962 //
963 // If that worked ok, then see if we should flush the FAT as well.
964 //
965
966 if (NT_SUCCESS(Status) && Fcb && !FatIsFat12( Vcb) &&
967 FlagOn( Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {
968
969 Status = FatFlushFat( IrpContext, Vcb);
970 }
971
972 if (!NT_SUCCESS(Status)) {
973
974 FatNormalizeAndRaiseStatus( IrpContext, Status );
975 }
976 }
977
978 } _SEH2_FINALLY {
979
980 DebugUnwind( FatCommonCleanup );
981
982 if (AcquiredFcb) { FatReleaseFcb( IrpContext, Fcb ); }
983 if (AcquiredVcb) { FatReleaseVcb( IrpContext, Vcb ); }
984
985 if (SendUnlockNotification) {
986
987 FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
988 }
989
990 //
991 // If this is a normal termination then complete the request
992 //
993
994 if (!_SEH2_AbnormalTermination()) {
995
996 FatCompleteRequest( IrpContext, Irp, Status );
997 }
998
999 DebugTrace(-1, Dbg, "FatCommonCleanup -> %08lx\n", Status);
1000 } _SEH2_END;
1001
1002 return Status;
1003 }
1004
1005 VOID
1006 FatAutoUnlock (
1007 IN PIRP_CONTEXT IrpContext,
1008 IN PVCB Vcb
1009 )
1010 {
1011 KIRQL SavedIrql;
1012
1013 //
1014 // Unlock the volume.
1015 //
1016
1017 IoAcquireVpbSpinLock( &SavedIrql );
1018
1019 ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED );
1020
1021 Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
1022 Vcb->FileObjectWithVcbLocked = NULL;
1023
1024 IoReleaseVpbSpinLock( SavedIrql );
1025 }
1026
1027