/* FUNCTIONS ****************************************************************/
+/* Last handle to a file object is closed */
+NTSTATUS
+NTAPI
+FatiCleanup(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_OBJECT FileObject;
+ TYPE_OF_OPEN TypeOfOpen;
+ PSHARE_ACCESS ShareAccess;
+ BOOLEAN SendUnlockNotification = FALSE;
+ PLARGE_INTEGER TruncateSize = NULL;
+ //LARGE_INTEGER LocalTruncateSize;
+ BOOLEAN AcquiredVcb = FALSE, AcquiredFcb = FALSE;
+ NTSTATUS Status;
+ PVCB Vcb;
+ PFCB Fcb;
+ PCCB Ccb;
+
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ DPRINT("FatiCleanup\n");
+ DPRINT("\tIrp = %p\n", Irp);
+ DPRINT("\t->FileObject = %p\n", IrpSp->FileObject);
+
+ FileObject = IrpSp->FileObject;
+ TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb);
+
+ if (TypeOfOpen == UnopenedFileObject)
+ {
+ DPRINT1("Unopened File Object\n");
+
+ FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
+ return STATUS_SUCCESS;
+ }
+
+ if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ))
+ {
+ /* Just flush the file */
+
+ if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
+ FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
+ !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED) &&
+ (TypeOfOpen == UserFileOpen))
+ {
+ //Status = FatFlushFile(IrpContext, Fcb, Flush);
+ //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status);
+ UNIMPLEMENTED;
+ }
+
+ FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
+ return STATUS_SUCCESS;
+ }
+
+ if (TypeOfOpen == UserFileOpen ||
+ TypeOfOpen == UserDirectoryOpen)
+ {
+ ASSERT(Fcb != NULL);
+
+ (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
+
+ AcquiredFcb = TRUE;
+
+ /* Set FCB flags according to DELETE_ON_CLOSE */
+ if (FlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))
+ {
+ ASSERT(FatNodeType(Fcb) != FAT_NTC_ROOT_DCB);
+
+ SetFlag(Fcb->State, FCB_STATE_DELETE_ON_CLOSE);
+
+ /* Issue a notification */
+ if (TypeOfOpen == UserDirectoryOpen)
+ {
+ FsRtlNotifyFullChangeDirectory(Vcb->NotifySync,
+ &Vcb->NotifyList,
+ FileObject->FsContext,
+ NULL,
+ FALSE,
+ FALSE,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ }
+ }
+
+ /* If file should be deleted, acquire locks */
+ if ((Fcb->UncleanCount == 1) &&
+ FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
+ (Fcb->Condition != FcbBad) &&
+ !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
+ {
+ FatReleaseFcb(IrpContext, Fcb);
+ AcquiredFcb = FALSE;
+
+ (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
+ AcquiredVcb = TRUE;
+
+ (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
+ AcquiredFcb = TRUE;
+ }
+ }
+
+ /* Acquire VCB lock if it was a volume open */
+ if (TypeOfOpen == UserVolumeOpen)
+ {
+ (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
+ AcquiredVcb = TRUE;
+ }
+
+ /* Cleanup all notifications */
+ if (TypeOfOpen == UserDirectoryOpen)
+ {
+ FsRtlNotifyCleanup(Vcb->NotifySync,
+ &Vcb->NotifyList,
+ Ccb);
+ }
+
+ if (Fcb)
+ {
+ //TODO: FatVerifyFcb
+ }
+
+ switch (TypeOfOpen)
+ {
+ case DirectoryFile:
+ case VirtualVolumeFile:
+ DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n");
+ ShareAccess = NULL;
+ break;
+
+ case UserVolumeOpen:
+ DPRINT("Cleanup UserVolumeOpen\n");
+
+ if (FlagOn(Ccb->Flags, CCB_COMPLETE_DISMOUNT))
+ {
+ FatCheckForDismount( IrpContext, Vcb, TRUE );
+ } else if (FileObject->WriteAccess &&
+ FlagOn(FileObject->Flags, FO_FILE_MODIFIED))
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Release the volume and send notification */
+ if (FlagOn(Vcb->State, VCB_STATE_FLAG_LOCKED) &&
+ (Vcb->FileObjectWithVcbLocked == FileObject))
+ {
+ UNIMPLEMENTED;
+ SendUnlockNotification = TRUE;
+ }
+
+ ShareAccess = &Vcb->ShareAccess;
+ break;
+
+ case EaFile:
+ DPRINT1("Cleanup EaFileObject\n");
+ ShareAccess = NULL;
+ break;
+
+ case UserDirectoryOpen:
+ DPRINT("Cleanup UserDirectoryOpen\n");
+
+ ShareAccess = &Fcb->ShareAccess;
+
+ /* Should it be a delayed close? */
+ if ((Fcb->UncleanCount == 1) &&
+ (Fcb->OpenCount == 1) &&
+ (Fcb->Dcb.DirectoryFileOpenCount == 0) &&
+ !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
+ Fcb->Condition == FcbGood)
+ {
+ /* Yes, a delayed one */
+ SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
+ }
+
+ if (VcbGood == Vcb->Condition)
+ {
+ //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
+ //TODO: Actually update dirent
+ }
+
+ if ((Fcb->UncleanCount == 1) &&
+ (FatNodeType(Fcb) == FAT_NTC_DCB) &&
+ (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) &&
+ (Fcb->Condition != FcbBad) &&
+ !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Decrement unclean counter */
+ ASSERT(Fcb->UncleanCount != 0);
+ Fcb->UncleanCount--;
+ break;
+
+ case UserFileOpen:
+ DPRINT("Cleanup UserFileOpen\n");
+
+ ShareAccess = &Fcb->ShareAccess;
+
+ /* Should it be a delayed close? */
+ if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
+ (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
+ (Fcb->UncleanCount == 1) &&
+ (Fcb->OpenCount == 1) &&
+ !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
+ Fcb->Condition == FcbGood)
+ {
+ /* Yes, a delayed one */
+ SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
+ }
+
+ /* Unlock all file locks */
+ FsRtlFastUnlockAll(&Fcb->Fcb.Lock,
+ FileObject,
+ IoGetRequestorProcess(Irp),
+ NULL);
+
+ if (Vcb->Condition == VcbGood)
+ {
+ if (Fcb->Condition != FcbBad)
+ {
+ //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
+ // TODO: Update on-disk structures
+ }
+
+ if (Fcb->UncleanCount == 1 &&
+ Fcb->Condition != FcbBad)
+ {
+ //DELETE_CONTEXT DeleteContext;
+
+ /* Should this file be deleted on close? */
+ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
+ !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
+ {
+ UNIMPLEMENTED;
+ }
+ else
+ {
+ if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) &&
+ (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart))
+ {
+#if 0
+ ULONG ValidDataLength;
+
+ ValidDataLength = Fcb->Header.ValidDataLength.LowPart;
+
+ if (ValidDataLength < Fcb->ValidDataToDisk) {
+ ValidDataLength = Fcb->ValidDataToDisk;
+ }
+
+ if (ValidDataLength < Fcb->Header.FileSize.LowPart)
+ {
+ FatZeroData( IrpContext,
+ Vcb,
+ FileObject,
+ ValidDataLength,
+ Fcb->Header.FileSize.LowPart -
+ ValidDataLength );
+
+ Fcb->ValidDataToDisk =
+ Fcb->Header.ValidDataLength.LowPart =
+ Fcb->Header.FileSize.LowPart;
+
+ if (CcIsFileCached(FileObject))
+ {
+ CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
+ }
+ }
+#endif
+ DPRINT1("Zeroing out data is not implemented\n");
+ }
+ }
+
+ /* Should the file be truncated on close? */
+ if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE))
+ {
+ if (Vcb->Condition == VcbGood)
+ {
+ // TODO: Actually truncate the file allocation
+ UNIMPLEMENTED;
+ }
+
+ /* Remove truncation flag */
+ Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
+ }
+
+ /* Check again if it should be deleted */
+ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
+ Fcb->Header.AllocationSize.LowPart == 0)
+ {
+ FatNotifyReportChange(IrpContext,
+ Vcb,
+ Fcb,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_ACTION_REMOVED);
+ }
+
+ /* Remove the entry from the splay table if the file was deleted */
+ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE))
+ {
+ FatRemoveNames(IrpContext, Fcb);
+ }
+ }
+ }
+
+ ASSERT(Fcb->UncleanCount != 0);
+ Fcb->UncleanCount--;
+ if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
+ {
+ ASSERT(Fcb->NonCachedUncleanCount != 0);
+ Fcb->NonCachedUncleanCount--;
+ }
+
+ if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
+ (Fcb->NonCachedUncleanCount != 0) &&
+ (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
+ (Fcb->SectionObjectPointers.DataSectionObject != NULL))
+ {
+ CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
+
+ /* Acquire and release PagingIo to get in sync with lazy writer */
+ ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE);
+ ExReleaseResourceLite(Fcb->Header.PagingIoResource);
+
+ CcPurgeCacheSection(&Fcb->SectionObjectPointers,
+ NULL,
+ 0,
+ FALSE);
+ }
+
+ if (Fcb->Condition == FcbBad)
+ {
+ //TruncateSize = &FatLargeZero;
+ UNIMPLEMENTED;
+ }
+
+ /* Cleanup the cache map */
+ CcUninitializeCacheMap(FileObject, TruncateSize, NULL);
+ break;
+
+ default:
+ KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0);
+ }
+
+ /* Cleanup the share access */
+
+ if (ShareAccess)
+ {
+ DPRINT("Cleaning up the share access\n");
+ IoRemoveShareAccess(FileObject, ShareAccess);
+ }
+
+ if (TypeOfOpen == UserFileOpen)
+ {
+ /* Update oplocks */
+ FsRtlCheckOplock(&Fcb->Fcb.Oplock,
+ Irp,
+ IrpContext,
+ NULL,
+ NULL);
+
+ Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);
+ }
+
+ /* Set the FO_CLEANUP_COMPLETE flag */
+ SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
+
+ Status = STATUS_SUCCESS;
+
+ // TODO: Unpin repinned BCBs
+ //FatUnpinRepinnedBcbs(IrpContext);
+
+ /* Flush the volume if necessary */
+ if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
+ !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Cleanup */
+ if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb);
+ if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb);
+
+ /* Send volume notification */
+ if (SendUnlockNotification)
+ FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);
+
+ return Status;
+}
+
NTSTATUS
NTAPI
FatCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
- DPRINT1("FatCleanup(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+ PFAT_IRP_CONTEXT IrpContext;
+ NTSTATUS Status;
+
+ DPRINT("FatCleanup(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
+
+ /* FatCleanup works only with a volume device object */
+ if (DeviceObject == FatGlobalData.DiskDeviceObject)
+ {
+ /* Complete the request and return success */
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = FILE_OPENED;
+
+ IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Enter FsRtl critical region */
+ FsRtlEnterFileSystem();
+
+ /* Build an irp context */
+ IrpContext = FatBuildIrpContext(Irp, TRUE);
+
+ /* Call internal function */
+ Status = FatiCleanup(IrpContext, Irp);
+
+ /* Leave FsRtl critical region */
+ FsRtlExitFileSystem();
- return STATUS_NOT_IMPLEMENTED;
+ return Status;
}
/* EOF */