2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/cleanup.c
5 * PURPOSE: Cleanup routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES *****************************************************************/
14 /* FUNCTIONS ****************************************************************/
16 /* Last handle to a file object is closed */
19 FatiCleanup(PFAT_IRP_CONTEXT IrpContext
, PIRP Irp
)
21 PIO_STACK_LOCATION IrpSp
;
22 PFILE_OBJECT FileObject
;
23 TYPE_OF_OPEN TypeOfOpen
;
24 PSHARE_ACCESS ShareAccess
;
25 BOOLEAN SendUnlockNotification
= FALSE
;
26 PLARGE_INTEGER TruncateSize
= NULL
;
27 //LARGE_INTEGER LocalTruncateSize;
28 BOOLEAN AcquiredVcb
= FALSE
, AcquiredFcb
= FALSE
;
34 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
36 DPRINT("FatiCleanup\n");
37 DPRINT("\tIrp = %p\n", Irp
);
38 DPRINT("\t->FileObject = %p\n", IrpSp
->FileObject
);
40 FileObject
= IrpSp
->FileObject
;
41 TypeOfOpen
= FatDecodeFileObject(FileObject
, &Vcb
, &Fcb
, &Ccb
);
43 if (TypeOfOpen
== UnopenedFileObject
)
45 DPRINT1("Unopened File Object\n");
47 FatCompleteRequest(IrpContext
, Irp
, STATUS_SUCCESS
);
48 return STATUS_SUCCESS
;
51 if (FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
53 /* Just flush the file */
55 if (FlagOn(Vcb
->State
, VCB_STATE_FLAG_DEFERRED_FLUSH
) &&
56 FlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
) &&
57 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
) &&
58 (TypeOfOpen
== UserFileOpen
))
60 //Status = FatFlushFile(IrpContext, Fcb, Flush);
61 //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status);
65 FatCompleteRequest(IrpContext
, Irp
, STATUS_SUCCESS
);
66 return STATUS_SUCCESS
;
69 if (TypeOfOpen
== UserFileOpen
||
70 TypeOfOpen
== UserDirectoryOpen
)
74 (VOID
)FatAcquireExclusiveFcb(IrpContext
, Fcb
);
78 /* Set FCB flags according to DELETE_ON_CLOSE */
79 if (FlagOn(Ccb
->Flags
, CCB_DELETE_ON_CLOSE
))
81 ASSERT(FatNodeType(Fcb
) != FAT_NTC_ROOT_DCB
);
83 SetFlag(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
);
85 /* Issue a notification */
86 if (TypeOfOpen
== UserDirectoryOpen
)
88 FsRtlNotifyFullChangeDirectory(Vcb
->NotifySync
,
90 FileObject
->FsContext
,
101 /* If file should be deleted, acquire locks */
102 if ((Fcb
->UncleanCount
== 1) &&
103 FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
104 (Fcb
->Condition
!= FcbBad
) &&
105 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
107 FatReleaseFcb(IrpContext
, Fcb
);
110 (VOID
)FatAcquireExclusiveVcb(IrpContext
, Vcb
);
113 (VOID
)FatAcquireExclusiveFcb(IrpContext
, Fcb
);
118 /* Acquire VCB lock if it was a volume open */
119 if (TypeOfOpen
== UserVolumeOpen
)
121 (VOID
)FatAcquireExclusiveVcb(IrpContext
, Vcb
);
125 /* Cleanup all notifications */
126 if (TypeOfOpen
== UserDirectoryOpen
)
128 FsRtlNotifyCleanup(Vcb
->NotifySync
,
141 case VirtualVolumeFile
:
142 DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n");
147 DPRINT("Cleanup UserVolumeOpen\n");
149 if (FlagOn(Ccb
->Flags
, CCB_COMPLETE_DISMOUNT
))
151 FatCheckForDismount( IrpContext
, Vcb
, TRUE
);
152 } else if (FileObject
->WriteAccess
&&
153 FlagOn(FileObject
->Flags
, FO_FILE_MODIFIED
))
158 /* Release the volume and send notification */
159 if (FlagOn(Vcb
->State
, VCB_STATE_FLAG_LOCKED
) &&
160 (Vcb
->FileObjectWithVcbLocked
== FileObject
))
163 SendUnlockNotification
= TRUE
;
166 ShareAccess
= &Vcb
->ShareAccess
;
170 DPRINT1("Cleanup EaFileObject\n");
174 case UserDirectoryOpen
:
175 DPRINT("Cleanup UserDirectoryOpen\n");
177 ShareAccess
= &Fcb
->ShareAccess
;
179 /* Should it be a delayed close? */
180 if ((Fcb
->UncleanCount
== 1) &&
181 (Fcb
->OpenCount
== 1) &&
182 (Fcb
->Dcb
.DirectoryFileOpenCount
== 0) &&
183 !FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
184 Fcb
->Condition
== FcbGood
)
186 /* Yes, a delayed one */
187 SetFlag(Fcb
->State
, FCB_STATE_DELAY_CLOSE
);
190 if (VcbGood
== Vcb
->Condition
)
192 //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
193 //TODO: Actually update dirent
196 if ((Fcb
->UncleanCount
== 1) &&
197 (FatNodeType(Fcb
) == FAT_NTC_DCB
) &&
198 (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
)) &&
199 (Fcb
->Condition
!= FcbBad
) &&
200 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
205 /* Decrement unclean counter */
206 ASSERT(Fcb
->UncleanCount
!= 0);
211 DPRINT("Cleanup UserFileOpen\n");
213 ShareAccess
= &Fcb
->ShareAccess
;
215 /* Should it be a delayed close? */
216 if ((FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
) &&
217 (FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
) &&
218 (Fcb
->UncleanCount
== 1) &&
219 (Fcb
->OpenCount
== 1) &&
220 !FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
221 Fcb
->Condition
== FcbGood
)
223 /* Yes, a delayed one */
224 //SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
225 DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb
, Fcb
->FatHandle
, &Fcb
->FullFileName
);
228 /* Unlock all file locks */
229 FsRtlFastUnlockAll(&Fcb
->Fcb
.Lock
,
231 IoGetRequestorProcess(Irp
),
234 if (Vcb
->Condition
== VcbGood
)
236 if (Fcb
->Condition
!= FcbBad
)
238 //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
239 // TODO: Update on-disk structures
242 if (Fcb
->UncleanCount
== 1 &&
243 Fcb
->Condition
!= FcbBad
)
245 //DELETE_CONTEXT DeleteContext;
247 /* Should this file be deleted on close? */
248 if (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
249 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
255 if (!FlagOn(Fcb
->State
, FCB_STATE_PAGEFILE
) &&
256 (Fcb
->Header
.ValidDataLength
.LowPart
< Fcb
->Header
.FileSize
.LowPart
))
259 ULONG ValidDataLength
;
261 ValidDataLength
= Fcb
->Header
.ValidDataLength
.LowPart
;
263 if (ValidDataLength
< Fcb
->ValidDataToDisk
) {
264 ValidDataLength
= Fcb
->ValidDataToDisk
;
267 if (ValidDataLength
< Fcb
->Header
.FileSize
.LowPart
)
269 FatZeroData( IrpContext
,
273 Fcb
->Header
.FileSize
.LowPart
-
276 Fcb
->ValidDataToDisk
=
277 Fcb
->Header
.ValidDataLength
.LowPart
=
278 Fcb
->Header
.FileSize
.LowPart
;
280 if (CcIsFileCached(FileObject
))
282 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
286 DPRINT1("Zeroing out data is not implemented\n");
290 /* Should the file be truncated on close? */
291 if (FlagOn(Fcb
->State
, FCB_STATE_TRUNCATE_ON_CLOSE
))
293 if (Vcb
->Condition
== VcbGood
)
295 // TODO: Actually truncate the file allocation
299 /* Remove truncation flag */
300 Fcb
->State
&= ~FCB_STATE_TRUNCATE_ON_CLOSE
;
303 /* Check again if it should be deleted */
304 if (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
305 Fcb
->Header
.AllocationSize
.LowPart
== 0)
307 FatNotifyReportChange(IrpContext
,
310 FILE_NOTIFY_CHANGE_FILE_NAME
,
311 FILE_ACTION_REMOVED
);
314 /* Remove the entry from the splay table if the file was deleted */
315 if (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
))
317 FatRemoveNames(IrpContext
, Fcb
);
322 ASSERT(Fcb
->UncleanCount
!= 0);
324 if (!FlagOn(FileObject
->Flags
, FO_CACHE_SUPPORTED
))
326 ASSERT(Fcb
->NonCachedUncleanCount
!= 0);
327 Fcb
->NonCachedUncleanCount
--;
330 if (FlagOn(FileObject
->Flags
, FO_CACHE_SUPPORTED
) &&
331 (Fcb
->NonCachedUncleanCount
!= 0) &&
332 (Fcb
->NonCachedUncleanCount
== Fcb
->UncleanCount
) &&
333 (Fcb
->SectionObjectPointers
.DataSectionObject
!= NULL
))
335 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
337 /* Acquire and release PagingIo to get in sync with lazy writer */
338 ExAcquireResourceExclusiveLite(Fcb
->Header
.PagingIoResource
, TRUE
);
339 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
341 CcPurgeCacheSection(&Fcb
->SectionObjectPointers
,
347 if (Fcb
->Condition
== FcbBad
)
349 //TruncateSize = &FatLargeZero;
353 /* Cleanup the cache map */
354 CcUninitializeCacheMap(FileObject
, TruncateSize
, NULL
);
358 KeBugCheckEx(FAT_FILE_SYSTEM
, __LINE__
, (ULONG_PTR
)TypeOfOpen
, 0, 0);
361 /* Cleanup the share access */
365 DPRINT("Cleaning up the share access\n");
366 IoRemoveShareAccess(FileObject
, ShareAccess
);
369 if (TypeOfOpen
== UserFileOpen
)
372 FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
378 Fcb
->Header
.IsFastIoPossible
= FatIsFastIoPossible(Fcb
);
381 /* Set the FO_CLEANUP_COMPLETE flag */
382 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
384 Status
= STATUS_SUCCESS
;
386 // TODO: Unpin repinned BCBs
387 //FatUnpinRepinnedBcbs(IrpContext);
389 /* Flush the volume if necessary */
390 if (FlagOn(Vcb
->State
, VCB_STATE_FLAG_DEFERRED_FLUSH
) &&
391 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
397 if (AcquiredFcb
) FatReleaseFcb(IrpContext
, Fcb
);
398 if (AcquiredVcb
) FatReleaseVcb(IrpContext
, Vcb
);
400 /* Send volume notification */
401 if (SendUnlockNotification
)
402 FsRtlNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_UNLOCK
);
409 FatCleanup(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
411 PFAT_IRP_CONTEXT IrpContext
;
414 DPRINT("FatCleanup(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
416 /* FatCleanup works only with a volume device object */
417 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
419 /* Complete the request and return success */
420 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
421 Irp
->IoStatus
.Information
= FILE_OPENED
;
423 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
425 return STATUS_SUCCESS
;
428 /* Enter FsRtl critical region */
429 FsRtlEnterFileSystem();
431 /* Build an irp context */
432 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
434 /* Call internal function */
435 Status
= FatiCleanup(IrpContext
, Irp
);
437 /* Leave FsRtl critical region */
438 FsRtlExitFileSystem();