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
);
227 /* Unlock all file locks */
228 FsRtlFastUnlockAll(&Fcb
->Fcb
.Lock
,
230 IoGetRequestorProcess(Irp
),
233 if (Vcb
->Condition
== VcbGood
)
235 if (Fcb
->Condition
!= FcbBad
)
237 //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
238 // TODO: Update on-disk structures
241 if (Fcb
->UncleanCount
== 1 &&
242 Fcb
->Condition
!= FcbBad
)
244 //DELETE_CONTEXT DeleteContext;
246 /* Should this file be deleted on close? */
247 if (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
248 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
254 if (!FlagOn(Fcb
->State
, FCB_STATE_PAGEFILE
) &&
255 (Fcb
->Header
.ValidDataLength
.LowPart
< Fcb
->Header
.FileSize
.LowPart
))
258 ULONG ValidDataLength
;
260 ValidDataLength
= Fcb
->Header
.ValidDataLength
.LowPart
;
262 if (ValidDataLength
< Fcb
->ValidDataToDisk
) {
263 ValidDataLength
= Fcb
->ValidDataToDisk
;
266 if (ValidDataLength
< Fcb
->Header
.FileSize
.LowPart
)
268 FatZeroData( IrpContext
,
272 Fcb
->Header
.FileSize
.LowPart
-
275 Fcb
->ValidDataToDisk
=
276 Fcb
->Header
.ValidDataLength
.LowPart
=
277 Fcb
->Header
.FileSize
.LowPart
;
279 if (CcIsFileCached(FileObject
))
281 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->Header
.AllocationSize
);
285 DPRINT1("Zeroing out data is not implemented\n");
289 /* Should the file be truncated on close? */
290 if (FlagOn(Fcb
->State
, FCB_STATE_TRUNCATE_ON_CLOSE
))
292 if (Vcb
->Condition
== VcbGood
)
294 // TODO: Actually truncate the file allocation
298 /* Remove truncation flag */
299 Fcb
->State
&= ~FCB_STATE_TRUNCATE_ON_CLOSE
;
302 /* Check again if it should be deleted */
303 if (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
) &&
304 Fcb
->Header
.AllocationSize
.LowPart
== 0)
306 FatNotifyReportChange(IrpContext
,
309 FILE_NOTIFY_CHANGE_FILE_NAME
,
310 FILE_ACTION_REMOVED
);
313 /* Remove the entry from the splay table if the file was deleted */
314 if (FlagOn(Fcb
->State
, FCB_STATE_DELETE_ON_CLOSE
))
316 FatRemoveNames(IrpContext
, Fcb
);
321 ASSERT(Fcb
->UncleanCount
!= 0);
323 if (!FlagOn(FileObject
->Flags
, FO_CACHE_SUPPORTED
))
325 ASSERT(Fcb
->NonCachedUncleanCount
!= 0);
326 Fcb
->NonCachedUncleanCount
--;
329 if (FlagOn(FileObject
->Flags
, FO_CACHE_SUPPORTED
) &&
330 (Fcb
->NonCachedUncleanCount
!= 0) &&
331 (Fcb
->NonCachedUncleanCount
== Fcb
->UncleanCount
) &&
332 (Fcb
->SectionObjectPointers
.DataSectionObject
!= NULL
))
334 CcFlushCache(&Fcb
->SectionObjectPointers
, NULL
, 0, NULL
);
336 /* Acquire and release PagingIo to get in sync with lazy writer */
337 ExAcquireResourceExclusiveLite(Fcb
->Header
.PagingIoResource
, TRUE
);
338 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
340 CcPurgeCacheSection(&Fcb
->SectionObjectPointers
,
346 if (Fcb
->Condition
== FcbBad
)
348 //TruncateSize = &FatLargeZero;
352 /* Cleanup the cache map */
353 CcUninitializeCacheMap(FileObject
, TruncateSize
, NULL
);
357 KeBugCheckEx(FAT_FILE_SYSTEM
, __LINE__
, (ULONG_PTR
)TypeOfOpen
, 0, 0);
360 /* Cleanup the share access */
364 DPRINT("Cleaning up the share access\n");
365 IoRemoveShareAccess(FileObject
, ShareAccess
);
368 if (TypeOfOpen
== UserFileOpen
)
371 FsRtlCheckOplock(&Fcb
->Fcb
.Oplock
,
377 Fcb
->Header
.IsFastIoPossible
= FatIsFastIoPossible(Fcb
);
380 /* Set the FO_CLEANUP_COMPLETE flag */
381 SetFlag(FileObject
->Flags
, FO_CLEANUP_COMPLETE
);
383 Status
= STATUS_SUCCESS
;
385 // TODO: Unpin repinned BCBs
386 //FatUnpinRepinnedBcbs(IrpContext);
388 /* Flush the volume if necessary */
389 if (FlagOn(Vcb
->State
, VCB_STATE_FLAG_DEFERRED_FLUSH
) &&
390 !FlagOn(Vcb
->State
, VCB_STATE_FLAG_WRITE_PROTECTED
))
396 if (AcquiredFcb
) FatReleaseFcb(IrpContext
, Fcb
);
397 if (AcquiredVcb
) FatReleaseVcb(IrpContext
, Vcb
);
399 /* Send volume notification */
400 if (SendUnlockNotification
)
401 FsRtlNotifyVolumeEvent(FileObject
, FSRTL_VOLUME_UNLOCK
);
408 FatCleanup(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
410 PFAT_IRP_CONTEXT IrpContext
;
413 DPRINT("FatCleanup(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
415 /* FatCleanup works only with a volume device object */
416 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
418 /* Complete the request and return success */
419 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
420 Irp
->IoStatus
.Information
= FILE_OPENED
;
422 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
424 return STATUS_SUCCESS
;
427 /* Enter FsRtl critical region */
428 FsRtlEnterFileSystem();
430 /* Build an irp context */
431 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
433 /* Call internal function */
434 Status
= FatiCleanup(IrpContext
, Irp
);
436 /* Leave FsRtl critical region */
437 FsRtlExitFileSystem();