1 /* 2 * PROJECT: VFAT Filesystem 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Cleanup routines 5 * COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com> 6 * Copyright 2014-2018 Pierre Schweitzer <pierre@reactos.org> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include "vfat.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* FUNCTIONS ****************************************************************/ 17 18 /* 19 * FUNCTION: Cleans up after a file has been closed. 20 * Returns whether the device was deleted 21 */ 22 static 23 BOOLEAN 24 VfatCleanupFile( 25 PVFAT_IRP_CONTEXT IrpContext) 26 { 27 PVFATFCB pFcb; 28 PVFATCCB pCcb; 29 BOOLEAN IsVolume; 30 PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt; 31 PFILE_OBJECT FileObject = IrpContext->FileObject; 32 BOOLEAN Deleted = FALSE; 33 34 DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n", 35 IrpContext->DeviceExt, FileObject); 36 37 /* FIXME: handle file/directory deletion here */ 38 pFcb = (PVFATFCB)FileObject->FsContext; 39 if (!pFcb) 40 return FALSE; 41 42 IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME); 43 if (IsVolume) 44 { 45 pFcb->OpenHandleCount--; 46 DeviceExt->OpenHandleCount--; 47 48 if (pFcb->OpenHandleCount != 0) 49 { 50 IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess); 51 } 52 } 53 else 54 { 55 ExAcquireResourceExclusiveLite(&pFcb->MainResource, TRUE); 56 ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource, TRUE); 57 58 pCcb = FileObject->FsContext2; 59 if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE)) 60 { 61 pFcb->Flags |= FCB_DELETE_PENDING; 62 } 63 64 /* Notify about the cleanup */ 65 FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync, 66 &(IrpContext->DeviceExt->NotifyList), 67 FileObject->FsContext2); 68 69 pFcb->OpenHandleCount--; 70 DeviceExt->OpenHandleCount--; 71 72 if (!vfatFCBIsDirectory(pFcb) && 73 FsRtlAreThereCurrentFileLocks(&pFcb->FileLock)) 74 { 75 /* remove all locks this process have on this file */ 76 FsRtlFastUnlockAll(&pFcb->FileLock, 77 FileObject, 78 IoGetRequestorProcess(IrpContext->Irp), 79 NULL); 80 } 81 82 if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY)) 83 { 84 VfatUpdateEntry (DeviceExt, pFcb); 85 } 86 87 if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) && 88 pFcb->OpenHandleCount == 0) 89 { 90 if (vfatFCBIsDirectory(pFcb) && 91 !VfatIsDirectoryEmpty(DeviceExt, pFcb)) 92 { 93 pFcb->Flags &= ~FCB_DELETE_PENDING; 94 } 95 else 96 { 97 PFILE_OBJECT tmpFileObject; 98 tmpFileObject = pFcb->FileObject; 99 if (tmpFileObject != NULL) 100 { 101 pFcb->FileObject = NULL; 102 CcUninitializeCacheMap(tmpFileObject, NULL, NULL); 103 ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED); 104 ObDereferenceObject(tmpFileObject); 105 } 106 107 pFcb->RFCB.ValidDataLength.QuadPart = 0; 108 pFcb->RFCB.FileSize.QuadPart = 0; 109 pFcb->RFCB.AllocationSize.QuadPart = 0; 110 } 111 } 112 113 /* Uninitialize the cache (should be done even if caching was never initialized) */ 114 CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL); 115 116 if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) && 117 pFcb->OpenHandleCount == 0) 118 { 119 VfatDelEntry(DeviceExt, pFcb, NULL); 120 121 vfatReportChange(DeviceExt, 122 pFcb, 123 (vfatFCBIsDirectory(pFcb) ? 124 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME), 125 FILE_ACTION_REMOVED); 126 } 127 128 if (pFcb->OpenHandleCount != 0) 129 { 130 IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess); 131 } 132 /* FIXME: causes FS corruption and breaks selfhosting/testbots and so on */ 133 #if 0 134 /* If that's the last open handle we just closed, try to see whether 135 * we can delay close operation 136 */ 137 else if (!BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) && !BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE) && 138 !BooleanFlagOn(pFcb->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME)) 139 { 140 /* This is only allowed if that's a directory with no open files 141 * OR if it's a file with no section opened 142 */ 143 if ((vfatFCBIsDirectory(pFcb) && IsListEmpty(&pFcb->ParentListHead)) || 144 (!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL && 145 FileObject->SectionObjectPointer->ImageSectionObject == NULL)) 146 { 147 DPRINT("Delaying close of: %wZ\n", &pFcb->PathNameU); 148 SetFlag(pFcb->Flags, FCB_DELAYED_CLOSE); 149 } 150 } 151 #endif 152 153 FileObject->Flags |= FO_CLEANUP_COMPLETE; 154 #ifdef KDBG 155 pFcb->Flags |= FCB_CLEANED_UP; 156 #endif 157 158 ExReleaseResourceLite(&pFcb->PagingIoResource); 159 ExReleaseResourceLite(&pFcb->MainResource); 160 } 161 162 #ifdef ENABLE_SWAPOUT 163 if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING)) 164 { 165 Deleted = VfatCheckForDismount(DeviceExt, TRUE); 166 } 167 #endif 168 169 return Deleted; 170 } 171 172 /* 173 * FUNCTION: Cleans up after a file has been closed. 174 */ 175 NTSTATUS 176 VfatCleanup( 177 PVFAT_IRP_CONTEXT IrpContext) 178 { 179 BOOLEAN Deleted; 180 181 DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp); 182 183 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) 184 { 185 IrpContext->Irp->IoStatus.Information = 0; 186 return STATUS_SUCCESS; 187 } 188 189 ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE); 190 Deleted = VfatCleanupFile(IrpContext); 191 if (!Deleted) ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); 192 193 IrpContext->Irp->IoStatus.Information = 0; 194 return STATUS_SUCCESS; 195 } 196 197 /* EOF */ 198