1 /* 2 * COPYRIGHT: See COPYRIGHT.TXT 3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP 4 * FILE: cleanup.c 5 * PROGRAMMER: Matt Wu <mattwu@163.com> 6 * HOMEPAGE: http://www.ext2fsd.com 7 * UPDATE HISTORY: 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "ext2fs.h" 13 14 /* GLOBALS ***************************************************************/ 15 16 extern PEXT2_GLOBAL Ext2Global; 17 18 /* DEFINITIONS *************************************************************/ 19 20 NTSTATUS 21 Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) 22 { 23 PDEVICE_OBJECT DeviceObject; 24 NTSTATUS Status = STATUS_SUCCESS; 25 PEXT2_VCB Vcb = NULL; 26 PFILE_OBJECT FileObject; 27 PEXT2_FCB Fcb = NULL; 28 PEXT2_CCB Ccb = NULL; 29 PIRP Irp = NULL; 30 PEXT2_MCB Mcb = NULL; 31 32 33 BOOLEAN VcbResourceAcquired = FALSE; 34 BOOLEAN FcbResourceAcquired = FALSE; 35 BOOLEAN FcbPagingIoResourceAcquired = FALSE; 36 BOOLEAN SymLinkDelete = FALSE; 37 38 _SEH2_TRY { 39 40 ASSERT(IrpContext != NULL); 41 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 42 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 43 44 DeviceObject = IrpContext->DeviceObject; 45 if (IsExt2FsDevice(DeviceObject)) { 46 Status = STATUS_SUCCESS; 47 _SEH2_LEAVE; 48 } 49 50 Irp = IrpContext->Irp; 51 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 52 ASSERT(Vcb != NULL); 53 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 54 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 55 56 if (!IsVcbInited(Vcb)) { 57 Status = STATUS_SUCCESS; 58 _SEH2_LEAVE; 59 } 60 61 FileObject = IrpContext->FileObject; 62 Fcb = (PEXT2_FCB) FileObject->FsContext; 63 if (!Fcb || (Fcb->Identifier.Type != EXT2VCB && 64 Fcb->Identifier.Type != EXT2FCB)) { 65 Status = STATUS_SUCCESS; 66 _SEH2_LEAVE; 67 } 68 Mcb = Fcb->Mcb; 69 Ccb = (PEXT2_CCB) FileObject->FsContext2; 70 71 if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { 72 Status = STATUS_SUCCESS; 73 _SEH2_LEAVE; 74 } 75 76 if (Fcb->Identifier.Type == EXT2VCB) { 77 78 ExAcquireResourceExclusiveLite( 79 &Vcb->MainResource, TRUE); 80 VcbResourceAcquired = TRUE; 81 82 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && 83 Vcb->LockFile == FileObject ){ 84 85 ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); 86 Vcb->LockFile = NULL; 87 Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED); 88 } 89 90 if (Ccb) { 91 Ext2DerefXcb(&Vcb->OpenHandleCount); 92 Ext2DerefXcb(&Vcb->OpenVolumeCount); 93 } 94 95 IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); 96 97 Status = STATUS_SUCCESS; 98 _SEH2_LEAVE; 99 } 100 101 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 102 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 103 104 FcbResourceAcquired = 105 ExAcquireResourceExclusiveLite( 106 &Fcb->MainResource, 107 TRUE 108 ); 109 110 if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { 111 if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && 112 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) && 113 !IsVcbReadOnly(Vcb) ) { 114 Status = Ext2FlushFile(IrpContext, Fcb, Ccb); 115 } 116 _SEH2_LEAVE; 117 } 118 119 if (Ccb == NULL) { 120 Status = STATUS_SUCCESS; 121 _SEH2_LEAVE; 122 } 123 124 if (IsDirectory(Fcb)) { 125 if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { 126 SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); 127 128 FsRtlNotifyFullChangeDirectory( 129 Vcb->NotifySync, 130 &Vcb->NotifyList, 131 Ccb, 132 NULL, 133 FALSE, 134 FALSE, 135 0, 136 NULL, 137 NULL, 138 NULL ); 139 } 140 141 FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb); 142 } 143 144 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 145 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 146 147 Ext2DerefXcb(&Vcb->OpenHandleCount); 148 Ext2DerefXcb(&Fcb->OpenHandleCount); 149 150 if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { 151 Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE; 152 } 153 154 if (IsDirectory(Fcb)) { 155 156 ext3_release_dir(Fcb->Inode, &Ccb->filp); 157 158 } else { 159 160 if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && 161 !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) { 162 163 LARGE_INTEGER SysTime; 164 KeQuerySystemTime(&SysTime); 165 166 Fcb->Inode->i_atime = 167 Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime); 168 Fcb->Mcb->LastAccessTime = 169 Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime); 170 171 Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); 172 173 Ext2NotifyReportChange( 174 IrpContext, 175 Vcb, 176 Fcb->Mcb, 177 FILE_NOTIFY_CHANGE_ATTRIBUTES | 178 FILE_NOTIFY_CHANGE_LAST_WRITE | 179 FILE_NOTIFY_CHANGE_LAST_ACCESS, 180 FILE_ACTION_MODIFIED ); 181 } 182 183 FsRtlCheckOplock( &Fcb->Oplock, 184 Irp, 185 IrpContext, 186 NULL, 187 NULL ); 188 189 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); 190 191 if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { 192 Fcb->NonCachedOpenCount--; 193 } 194 195 if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { 196 if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) { 197 SymLinkDelete = TRUE; 198 } else { 199 SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); 200 } 201 } 202 203 // 204 // Drop any byte range locks this process may have on the file. 205 // 206 207 FsRtlFastUnlockAll( 208 &Fcb->FileLockAnchor, 209 FileObject, 210 IoGetRequestorProcess(Irp), 211 NULL ); 212 213 // 214 // If there are no byte range locks owned by other processes on the 215 // file the fast I/O read/write functions doesn't have to check for 216 // locks so we set IsFastIoPossible to FastIoIsPossible again. 217 // 218 if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) { 219 if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) { 220 #if EXT2_DEBUG 221 DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n", 222 Ext2GetCurrentProcessName(), 223 "FastIoIsPossible", 224 &Fcb->Mcb->FullName 225 )); 226 #endif 227 228 Fcb->Header.IsFastIoPossible = FastIoIsPossible; 229 } 230 } 231 232 if (Fcb->OpenHandleCount == 0 && FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE | 233 FCB_ALLOC_IN_SETINFO) ){ 234 235 if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_SETINFO)) { 236 if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) { 237 if (!INODE_HAS_EXTENT(Fcb->Inode)) { 238 #if EXT2_PRE_ALLOCATION_SUPPORT 239 _SEH2_TRY { 240 CcZeroData( FileObject, 241 &Fcb->Header.ValidDataLength, 242 &Fcb->Header.AllocationSize, 243 TRUE); 244 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 245 DbgBreak(); 246 } _SEH2_END; 247 #endif 248 } 249 } 250 } 251 252 if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) { 253 254 LARGE_INTEGER Size; 255 256 ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE); 257 FcbPagingIoResourceAcquired = TRUE; 258 259 Size.QuadPart = CEILING_ALIGNED(ULONGLONG, 260 (ULONGLONG)Fcb->Mcb->Inode.i_size, 261 (ULONGLONG)BLOCK_SIZE); 262 if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { 263 264 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size); 265 Fcb->Header.AllocationSize = Size; 266 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size; 267 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) 268 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; 269 if (CcIsFileCached(FileObject)) { 270 CcSetFileSizes(FileObject, 271 (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 272 } 273 } 274 ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE|FCB_ALLOC_IN_SETINFO); 275 ExReleaseResourceLite(&Fcb->PagingIoResource); 276 FcbPagingIoResourceAcquired = FALSE; 277 } 278 } 279 } 280 281 IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); 282 283 if (!IsDirectory(Fcb)) { 284 285 if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && 286 (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) && 287 (Fcb->SectionObject.DataSectionObject != NULL)) { 288 289 if (!IsVcbReadOnly(Vcb)) { 290 CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); 291 ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); 292 } 293 294 /* purge cache if all remaining openings are non-cached */ 295 if (Fcb->NonCachedOpenCount > 0 || 296 IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { 297 if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) { 298 ExReleaseResourceLite(&(Fcb->PagingIoResource)); 299 } 300 301 /* CcPurge could generate recursive IRP_MJ_CLOSE request */ 302 CcPurgeCacheSection( &Fcb->SectionObject, 303 NULL, 304 0, 305 FALSE ); 306 } 307 } 308 309 CcUninitializeCacheMap(FileObject, NULL, NULL); 310 } 311 312 if (SymLinkDelete || 313 (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) && 314 Fcb->OpenHandleCount == 0) ) { 315 316 // 317 // Ext2DeleteFile will acquire these lock inside 318 // 319 320 if (FcbResourceAcquired) { 321 ExReleaseResourceLite(&Fcb->MainResource); 322 FcbResourceAcquired = FALSE; 323 } 324 325 // 326 // this file is to be deleted ... 327 // 328 if (Ccb->SymLink) { 329 Mcb = Ccb->SymLink; 330 FileObject->DeletePending = FALSE; 331 } 332 333 Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); 334 335 if (NT_SUCCESS(Status)) { 336 if (IsMcbDirectory(Mcb)) { 337 Ext2NotifyReportChange( IrpContext, Vcb, Mcb, 338 FILE_NOTIFY_CHANGE_DIR_NAME, 339 FILE_ACTION_REMOVED ); 340 } else { 341 Ext2NotifyReportChange( IrpContext, Vcb, Mcb, 342 FILE_NOTIFY_CHANGE_FILE_NAME, 343 FILE_ACTION_REMOVED ); 344 } 345 } 346 347 // 348 // re-acquire the main resource lock 349 // 350 351 FcbResourceAcquired = 352 ExAcquireResourceExclusiveLite( 353 &Fcb->MainResource, 354 TRUE 355 ); 356 if (!SymLinkDelete) { 357 SetFlag(FileObject->Flags, FO_FILE_MODIFIED); 358 if (CcIsFileCached(FileObject)) { 359 CcSetFileSizes(FileObject, 360 (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); 361 } 362 } 363 } 364 365 DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n", 366 Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName)); 367 368 Status = STATUS_SUCCESS; 369 370 if (FileObject) { 371 SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); 372 } 373 374 } _SEH2_FINALLY { 375 376 if (FcbPagingIoResourceAcquired) { 377 ExReleaseResourceLite(&Fcb->PagingIoResource); 378 } 379 380 if (FcbResourceAcquired) { 381 ExReleaseResourceLite(&Fcb->MainResource); 382 } 383 384 if (VcbResourceAcquired) { 385 ExReleaseResourceLite(&Vcb->MainResource); 386 } 387 388 if (!IrpContext->ExceptionInProgress) { 389 if (Status == STATUS_PENDING) { 390 Ext2QueueRequest(IrpContext); 391 } else { 392 IrpContext->Irp->IoStatus.Status = Status; 393 Ext2CompleteIrpContext(IrpContext, Status); 394 } 395 } 396 } _SEH2_END; 397 398 return Status; 399 } 400