1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /* 7 8 Module name: Cleanup.cpp 9 10 Abstract: 11 12 Contains code to handle the "Cleanup" dispatch entry point. 13 14 Environment: 15 16 Kernel mode only 17 */ 18 19 #include "udffs.h" 20 21 // define the file specific bug-check id 22 #define UDF_BUG_CHECK_ID UDF_FILE_CLEANUP 23 24 25 /************************************************************************* 26 * 27 * Function: UDFCleanup() 28 * 29 * Description: 30 * The I/O Manager will invoke this routine to handle a cleanup 31 * request 32 * 33 * Expected Interrupt Level (for execution) : 34 * 35 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution 36 * to be deferred to a worker thread context) 37 * 38 * Return Value: STATUS_SUCCESS 39 * 40 *************************************************************************/ 41 NTSTATUS 42 NTAPI 43 UDFCleanup( 44 PDEVICE_OBJECT DeviceObject, // the logical volume device object 45 PIRP Irp // I/O Request Packet 46 ) 47 { 48 NTSTATUS RC = STATUS_SUCCESS; 49 PtrUDFIrpContext PtrIrpContext = NULL; 50 BOOLEAN AreWeTopLevel = FALSE; 51 52 TmPrint(("UDFCleanup\n")); 53 54 FsRtlEnterFileSystem(); 55 ASSERT(DeviceObject); 56 ASSERT(Irp); 57 58 // If we were called with our file system device object instead of a 59 // volume device object, just complete this request with STATUS_SUCCESS 60 if (UDFIsFSDevObj(DeviceObject)) { 61 // this is a cleanup of the FSD itself 62 Irp->IoStatus.Status = RC; 63 Irp->IoStatus.Information = 0; 64 65 if(UDFGlobalData.AutoFormatCount == IoGetCurrentIrpStackLocation(Irp)->FileObject) { 66 UDFPrint(("Deregister Autoformat\n")); 67 UDFGlobalData.AutoFormatCount = NULL; 68 } 69 70 IoCompleteRequest(Irp, IO_NO_INCREMENT); 71 FsRtlExitFileSystem(); 72 return(RC); 73 } 74 75 // set the top level context 76 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 77 78 _SEH2_TRY { 79 80 // get an IRP context structure and issue the request 81 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 82 if(PtrIrpContext) { 83 RC = UDFCommonCleanup(PtrIrpContext, Irp); 84 } else { 85 RC = STATUS_INSUFFICIENT_RESOURCES; 86 Irp->IoStatus.Status = RC; 87 Irp->IoStatus.Information = 0; 88 // complete the IRP 89 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 90 } 91 92 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 93 94 RC = UDFExceptionHandler(PtrIrpContext, Irp); 95 96 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 97 } _SEH2_END; 98 99 if (AreWeTopLevel) { 100 IoSetTopLevelIrp(NULL); 101 } 102 103 FsRtlExitFileSystem(); 104 105 return(RC); 106 } // end UDFCleanup() 107 108 /************************************************************************* 109 * 110 * Function: UDFCommonCleanup() 111 * 112 * Description: 113 * The actual work is performed here. This routine may be invoked in one' 114 * of the two possible contexts: 115 * (a) in the context of a system worker thread 116 * (b) in the context of the original caller 117 * 118 * Expected Interrupt Level (for execution) : 119 * 120 * IRQL_PASSIVE_LEVEL 121 * 122 * Return Value: Does not matter! 123 * 124 *************************************************************************/ 125 NTSTATUS 126 UDFCommonCleanup( 127 PtrUDFIrpContext PtrIrpContext, 128 PIRP Irp) 129 { 130 IO_STATUS_BLOCK IoStatus; 131 NTSTATUS RC = STATUS_SUCCESS; 132 NTSTATUS RC2; 133 PIO_STACK_LOCATION IrpSp = NULL; 134 PFILE_OBJECT FileObject = NULL; 135 PtrUDFFCB Fcb = NULL; 136 PtrUDFCCB Ccb = NULL; 137 PVCB Vcb = NULL; 138 PtrUDFNTRequiredFCB NtReqFcb = NULL; 139 ULONG lc = 0; 140 BOOLEAN AcquiredVcb = FALSE; 141 BOOLEAN AcquiredFCB = FALSE; 142 BOOLEAN AcquiredParentFCB = FALSE; 143 144 // BOOLEAN CompleteIrp = TRUE; 145 // BOOLEAN PostRequest = FALSE; 146 BOOLEAN ChangeTime = FALSE; 147 #ifdef UDF_DBG 148 BOOLEAN CanWait = FALSE; 149 #endif // UDF_DBG 150 BOOLEAN ForcedCleanUp = FALSE; 151 152 PUDF_FILE_INFO NextFileInfo = NULL; 153 #ifdef UDF_DBG 154 UNICODE_STRING CurName; 155 PDIR_INDEX_HDR DirNdx; 156 #endif // UDF_DBG 157 // PUDF_DATALOC_INFO Dloc; 158 159 TmPrint(("UDFCommonCleanup\n")); 160 161 // BrutePoint(); 162 163 _SEH2_TRY { 164 // First, get a pointer to the current I/O stack location 165 IrpSp = IoGetCurrentIrpStackLocation(Irp); 166 if(!IrpSp) try_return(RC = STATUS_INVALID_PARAMETER); 167 168 FileObject = IrpSp->FileObject; 169 170 // Get the FCB and CCB pointers 171 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 172 ASSERT(Ccb); 173 Fcb = Ccb->Fcb; 174 ASSERT(Fcb); 175 176 Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); 177 ASSERT(Vcb); 178 ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); 179 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 180 #ifdef UDF_DBG 181 CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; 182 AdPrint((" %s\n", CanWait ? "Wt" : "nw")); 183 ASSERT(CanWait); 184 #endif // UDF_DBG 185 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); 186 AcquiredVcb = TRUE; 187 // Steps we shall take at this point are: 188 // (a) Acquire the file (FCB) exclusively 189 // (b) Flush file data to disk 190 // (c) Talk to the FSRTL package (if we use it) about pending oplocks. 191 // (d) Notify the FSRTL package for use with pending notification IRPs 192 // (e) Unlock byte-range locks (if any were acquired by process) 193 // (f) Update time stamp values (e.g. fast-IO had been performed) 194 // (g) Inform the Cache Manager to uninitialize Cache Maps ... 195 // and other similar stuff. 196 // BrutePoint(); 197 NtReqFcb = Fcb->NTRequiredFCB; 198 199 if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { 200 AdPrint(("Cleaning up Volume\n")); 201 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount)); 202 203 UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount)); 204 UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount)); 205 if(FileObject->Flags & FO_CACHE_SUPPORTED) { 206 // we've cached close 207 UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount)); 208 } 209 ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1)); 210 211 // If this handle had write access, and actually wrote something, 212 // flush the device buffers, and then set the verify bit now 213 // just to be safe (in case there is no dismount). 214 if( FileObject->WriteAccess && 215 (FileObject->Flags & FO_FILE_MODIFIED)) { 216 217 Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; 218 } 219 // User may decide to close locked volume without call to unlock proc 220 // So, handle this situation properly & unlock it now... 221 if (FileObject == Vcb->VolumeLockFileObject) { 222 Vcb->VolumeLockFileObject = NULL; 223 Vcb->VolumeLockPID = -1; 224 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; 225 Vcb->Vpb->Flags &= ~VPB_LOCKED; 226 UDFNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); 227 } 228 229 MmPrint((" CcUninitializeCacheMap()\n")); 230 CcUninitializeCacheMap(FileObject, NULL, NULL); 231 // reset device 232 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) && 233 (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) { 234 // this call doesn't modify data buffer 235 // it just requires its presence 236 UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); 237 } 238 // We must clean up the share access at this time, since we may not 239 // get a Close call for awhile if the file was mapped through this 240 // File Object. 241 IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) ); 242 243 try_return(RC = STATUS_SUCCESS); 244 } 245 // BrutePoint(); 246 #ifdef UDF_DBG 247 DirNdx = UDFGetDirIndexByFileInfo(Fcb->FileInfo); 248 if(DirNdx) { 249 CurName.Buffer = UDFDirIndex(DirNdx, Fcb->FileInfo->Index)->FName.Buffer; 250 if(CurName.Buffer) { 251 AdPrint(("Cleaning up file: %ws %8.8x\n", CurName.Buffer, FileObject)); 252 } else { 253 AdPrint(("Cleaning up file: ??? \n")); 254 } 255 } 256 #endif //UDF_DBG 257 AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount)); 258 // Acquire parent object 259 if(Fcb->FileInfo->ParentFile) { 260 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); 261 UDFAcquireResourceExclusive(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource),TRUE); 262 } else { 263 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); 264 } 265 AcquiredParentFCB = TRUE; 266 // Acquire current object 267 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 268 UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); 269 AcquiredFCB = TRUE; 270 // dereference object 271 UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount)); 272 UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount)); 273 if(FileObject->Flags & FO_CACHE_SUPPORTED) { 274 // we've cached close 275 UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount)); 276 } 277 ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1)); 278 // check if Ccb being cleaned up has DeleteOnClose flag set 279 #ifndef UDF_READ_ONLY_BUILD 280 if(Ccb->CCBFlags & UDF_CCB_DELETE_ON_CLOSE) { 281 AdPrint((" DeleteOnClose\n")); 282 // Ok, now we'll become 'delete on close'... 283 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 284 Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; 285 FileObject->DeletePending = TRUE; 286 // Report this to the dir notify package for a directory. 287 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 288 FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 289 (PVOID)Ccb, NULL, FALSE, FALSE, 290 0, NULL, NULL, NULL ); 291 } 292 } 293 #endif //UDF_READ_ONLY_BUILD 294 295 if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 296 // Unlock all outstanding file locks. 297 FsRtlFastUnlockAll(&(NtReqFcb->FileLock), 298 FileObject, 299 IoGetRequestorProcess(Irp), 300 NULL); 301 } 302 // get Link count 303 lc = UDFGetFileLinkCount(Fcb->FileInfo); 304 305 #ifndef UDF_READ_ONLY_BUILD 306 if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) && 307 !(Fcb->OpenHandleCount)) { 308 // This can be useful for Streams, those were brutally deleted 309 // (together with parent object) 310 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 311 FileObject->DeletePending = TRUE; 312 313 // we should mark all streams of the file being deleted 314 // for deletion too, if there are no more Links to 315 // main data stream 316 if((lc <= 1) && 317 !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) { 318 RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete 319 } 320 // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE 321 // flag is already set & the file can't be opened 322 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 323 UDFReleaseResource(&(NtReqFcb->MainResource)); 324 AcquiredFCB = FALSE; 325 if(Fcb->FileInfo->ParentFile) { 326 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); 327 UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource)); 328 } else { 329 UDFReleaseResource(&(Vcb->VCBResource)); 330 } 331 AcquiredParentFCB = FALSE; 332 UDFReleaseResource(&(Vcb->VCBResource)); 333 AcquiredVcb = FALSE; 334 335 // Make system to issue last Close request 336 // for our Target ... 337 UDFRemoveFromSystemDelayedQueue(Fcb); 338 339 #ifdef UDF_DELAYED_CLOSE 340 // remove file from our DelayedClose queue 341 UDFRemoveFromDelayedQueue(Fcb); 342 ASSERT(!Fcb->IrpContextLite); 343 #endif //UDF_DELAYED_CLOSE 344 345 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); 346 AcquiredVcb = TRUE; 347 if(Fcb->FileInfo->ParentFile) { 348 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); 349 UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE); 350 } else { 351 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); 352 } 353 AcquiredParentFCB = TRUE; 354 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 355 UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); 356 AcquiredFCB = TRUE; 357 358 // we should set file sizes to zero if there are no more 359 // links to this file 360 if(lc <= 1) { 361 // Synchronize here with paging IO 362 UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource),TRUE); 363 // set file size to zero (for system cache manager) 364 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 365 NtReqFcb->CommonFCBHeader.FileSize.QuadPart = 366 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0; 367 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); 368 369 UDFReleaseResource(&(NtReqFcb->PagingIoResource)); 370 } 371 } 372 #endif //UDF_READ_ONLY_BUILD 373 374 #ifdef UDF_DELAYED_CLOSE 375 if ((Fcb->ReferenceCount == 1) && 376 /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above 377 (!(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)) ) { 378 Fcb->FCBFlags |= UDF_FCB_DELAY_CLOSE; 379 } 380 #endif //UDF_DELAYED_CLOSE 381 382 NextFileInfo = Fcb->FileInfo; 383 384 #ifndef UDF_READ_ONLY_BUILD 385 // do we need to delete it now ? 386 if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) && 387 !(Fcb->OpenHandleCount)) { 388 389 // can we do it ? 390 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 391 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 392 if(!UDFIsDirEmpty__(NextFileInfo)) { 393 // forget about it 394 Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; 395 goto DiscardDelete; 396 } 397 } else 398 if (lc <= 1) { 399 // Synchronize here with paging IO 400 BOOLEAN AcquiredPagingIo; 401 AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb->PagingIoResource)); 402 // set file size to zero (for UdfInfo package) 403 // we should not do this for directories and linked files 404 UDFResizeFile__(Vcb, NextFileInfo, 0); 405 if(AcquiredPagingIo) { 406 UDFReleaseResource(&(NtReqFcb->PagingIoResource)); 407 } 408 } 409 // mark parent object for deletion if requested 410 if((Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) && 411 Fcb->ParentFcb) { 412 ASSERT(!(Fcb->ParentFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 413 Fcb->ParentFcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; 414 } 415 // flush file. It is required by UDFUnlinkFile__() 416 RC = UDFFlushFile__(Vcb, NextFileInfo); 417 if(!NT_SUCCESS(RC)) { 418 AdPrint(("Error flushing file !!!\n")); 419 } 420 // try to unlink 421 if((RC = UDFUnlinkFile__(Vcb, NextFileInfo, TRUE)) == STATUS_CANNOT_DELETE) { 422 // If we can't delete file with Streams due to references, 423 // mark SDir & Streams 424 // for Deletion. We shall also set DELETE_PARENT flag to 425 // force Deletion of the current file later... when curently 426 // opened Streams would be cleaned up. 427 428 // WARNING! We should keep SDir & Streams if there is a 429 // link to this file 430 if(NextFileInfo->Dloc && 431 NextFileInfo->Dloc->SDirInfo && 432 NextFileInfo->Dloc->SDirInfo->Fcb) { 433 434 BrutePoint(); 435 if(!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) { 436 // RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete 437 //#ifdef UDF_ALLOW_PRETEND_DELETED 438 UDFPretendFileDeleted__(Vcb, Fcb->FileInfo); 439 //#endif //UDF_ALLOW_PRETEND_DELETED 440 } 441 goto NotifyDelete; 442 443 } else { 444 // Getting here means that we can't delete file because of 445 // References/PemissionsDenied/Smth.Else, 446 // but not Linked+OpenedStream 447 BrutePoint(); 448 // RC = STATUS_SUCCESS; 449 goto DiscardDelete_1; 450 } 451 } else { 452 DiscardDelete_1: 453 // We have got an ugly ERROR, or 454 // file is deleted, so forget about it 455 ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 456 ForcedCleanUp = TRUE; 457 if(NT_SUCCESS(RC)) 458 Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; 459 Fcb->FCBFlags |= UDF_FCB_DELETED; 460 RC = STATUS_SUCCESS; 461 } 462 NotifyDelete: 463 // We should prevent SetEOF operations on completly 464 // deleted data streams 465 if(lc < 1) { 466 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; 467 } 468 // Report that we have removed an entry. 469 if(UDFIsAStream(NextFileInfo)) { 470 UDFNotifyFullReportChange( Vcb, NextFileInfo, 471 FILE_NOTIFY_CHANGE_STREAM_NAME, 472 FILE_ACTION_REMOVED_STREAM); 473 } else { 474 UDFNotifyFullReportChange( Vcb, NextFileInfo, 475 UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 476 FILE_ACTION_REMOVED); 477 } 478 } else 479 if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { 480 DiscardDelete: 481 UDFNotifyFullReportChange( Vcb, NextFileInfo, 482 ((Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) | 483 ((Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) | 484 0, 485 UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED); 486 } 487 #endif //UDF_READ_ONLY_BUILD 488 489 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 490 // Report to the dir notify package for a directory. 491 FsRtlNotifyCleanup( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb ); 492 } 493 494 // we can't purge Cache when more than one link exists 495 if(lc > 1) { 496 ForcedCleanUp = FALSE; 497 } 498 499 if ( (FileObject->Flags & FO_CACHE_SUPPORTED) && 500 (NtReqFcb->SectionObject.DataSectionObject) ) { 501 BOOLEAN LastNonCached = (!Fcb->CachedOpenHandleCount && 502 Fcb->OpenHandleCount); 503 // If this was the last cached open, and there are open 504 // non-cached handles, attempt a flush and purge operation 505 // to avoid cache coherency overhead from these non-cached 506 // handles later. We ignore any I/O errors from the flush. 507 // We shall not flush deleted files 508 RC = STATUS_SUCCESS; 509 if( LastNonCached 510 || 511 (!Fcb->OpenHandleCount && 512 !ForcedCleanUp) ) { 513 514 #ifndef UDF_READ_ONLY_BUILD 515 LONGLONG OldFileSize, NewFileSize; 516 517 if( (OldFileSize = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) < 518 (NewFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) { 519 /* UDFZeroDataEx(NtReqFcb, 520 OldFileSize, 521 NewFileSize - OldFileSize, 522 TRUE, Vcb, FileObject);*/ 523 524 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileSize; 525 } 526 #endif //UDF_READ_ONLY_BUILD 527 MmPrint((" CcFlushCache()\n")); 528 CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, &IoStatus ); 529 if(!NT_SUCCESS(IoStatus.Status)) { 530 MmPrint((" CcFlushCache() error: %x\n", IoStatus.Status)); 531 RC = IoStatus.Status; 532 } 533 } 534 // If file is deleted or it is last cached open, but there are 535 // some non-cached handles we should purge cache section 536 if(ForcedCleanUp || LastNonCached) { 537 if(NtReqFcb->SectionObject.DataSectionObject) { 538 MmPrint((" CcPurgeCacheSection()\n")); 539 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); 540 } 541 /* MmPrint((" CcPurgeCacheSection()\n")); 542 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/ 543 } 544 // we needn't Flush here. It will be done in UDFCloseFileInfoChain() 545 } 546 547 #ifndef UDF_READ_ONLY_BUILD 548 // Update FileTimes & Attrs 549 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && 550 !(Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | 551 UDF_FCB_DELETED /*| 552 UDF_FCB_DIRECTORY | 553 UDF_FCB_READ_ONLY*/)) && 554 !UDFIsAStreamDir(NextFileInfo)) { 555 LONGLONG NtTime; 556 LONGLONG ASize; 557 KeQuerySystemTime((PLARGE_INTEGER)&NtTime); 558 // Check if we should set ARCHIVE bit & LastWriteTime 559 if(FileObject->Flags & FO_FILE_MODIFIED) { 560 ULONG Attr; 561 PDIR_INDEX_ITEM DirNdx; 562 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index); 563 ASSERT(DirNdx); 564 // Archive bit 565 if(!(Ccb->CCBFlags & UDF_CCB_ATTRIBUTES_SET) && 566 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) { 567 Attr = UDFAttributesToNT(DirNdx, NextFileInfo->Dloc->FileEntry); 568 if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) 569 UDFAttributesToUDF(DirNdx, NextFileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); 570 } 571 // WriteTime 572 if(!(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) && 573 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME)) { 574 UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, &NtTime); 575 NtReqFcb->LastWriteTime.QuadPart = 576 NtReqFcb->LastAccessTime.QuadPart = NtTime; 577 ChangeTime = TRUE; 578 } 579 } 580 if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 581 // Update sizes in DirIndex 582 if(!Fcb->OpenHandleCount) { 583 ASize = UDFGetFileAllocationSize(Vcb, NextFileInfo); 584 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; 585 UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); 586 } else 587 if(FileObject->Flags & FO_FILE_SIZE_CHANGED) { 588 ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo); 589 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; 590 UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); 591 } 592 } 593 // AccessTime 594 if((FileObject->Flags & FO_FILE_FAST_IO_READ) && 595 !(Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) && 596 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ACCESS_TIME)) { 597 UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, NULL); 598 NtReqFcb->LastAccessTime.QuadPart = NtTime; 599 // ChangeTime = TRUE; 600 } 601 // ChangeTime (AttrTime) 602 if(!(Ccb->CCBFlags & UDF_CCB_MODIFY_TIME_SET) && 603 (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ATTR_TIME) && 604 (ChangeTime || (Ccb->CCBFlags & (UDF_CCB_ATTRIBUTES_SET | 605 UDF_CCB_CREATE_TIME_SET | 606 UDF_CCB_ACCESS_TIME_SET | 607 UDF_CCB_WRITE_TIME_SET))) ) { 608 UDFSetFileXTime(NextFileInfo, NULL, NULL, &NtTime, NULL); 609 NtReqFcb->ChangeTime.QuadPart = NtTime; 610 } 611 } 612 #endif //UDF_READ_ONLY_BUILD 613 614 if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY) && 615 ForcedCleanUp) { 616 // flush system cache 617 MmPrint((" CcUninitializeCacheMap()\n")); 618 CcUninitializeCacheMap(FileObject, &(UDFGlobalData.UDFLargeZero), NULL); 619 } else { 620 MmPrint((" CcUninitializeCacheMap()\n")); 621 CcUninitializeCacheMap(FileObject, NULL, NULL); 622 } 623 624 // release resources now. 625 // they'll be acquired in UDFCloseFileInfoChain() 626 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 627 UDFReleaseResource(&(NtReqFcb->MainResource)); 628 AcquiredFCB = FALSE; 629 630 if(Fcb->FileInfo->ParentFile) { 631 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); 632 UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource)); 633 } else { 634 UDFReleaseResource(&(Vcb->VCBResource)); 635 } 636 AcquiredParentFCB = FALSE; 637 // close the chain 638 ASSERT(AcquiredVcb); 639 RC2 = UDFCloseFileInfoChain(Vcb, NextFileInfo, Ccb->TreeLength, TRUE); 640 if(NT_SUCCESS(RC)) 641 RC = RC2; 642 643 Ccb->CCBFlags |= UDF_CCB_CLEANED; 644 645 // We must clean up the share access at this time, since we may not 646 // get a Close call for awhile if the file was mapped through this 647 // File Object. 648 IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) ); 649 650 NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); 651 652 FileObject->Flags |= FO_CLEANUP_COMPLETE; 653 654 try_exit: NOTHING; 655 656 } _SEH2_FINALLY { 657 658 if(AcquiredFCB) { 659 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 660 UDFReleaseResource(&(NtReqFcb->MainResource)); 661 } 662 663 if(AcquiredParentFCB) { 664 if(Fcb->FileInfo->ParentFile) { 665 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); 666 UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource)); 667 } else { 668 UDFReleaseResource(&(Vcb->VCBResource)); 669 } 670 } 671 672 if(AcquiredVcb) { 673 UDFReleaseResource(&(Vcb->VCBResource)); 674 AcquiredVcb = FALSE; 675 } 676 677 if (!_SEH2_AbnormalTermination()) { 678 // complete the IRP 679 Irp->IoStatus.Status = RC; 680 Irp->IoStatus.Information = 0; 681 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 682 // Free up the Irp Context 683 UDFReleaseIrpContext(PtrIrpContext); 684 } 685 686 } _SEH2_END; // end of "__finally" processing 687 return(RC); 688 } // end UDFCommonCleanup() 689 690 /* 691 This routine walks through the tree to RootDir & 692 calls UDFCloseFile__() for each file instance 693 imho, Useful feature 694 */ 695 NTSTATUS 696 UDFCloseFileInfoChain( 697 IN PVCB Vcb, 698 IN PUDF_FILE_INFO fi, 699 IN ULONG TreeLength, 700 IN BOOLEAN VcbAcquired 701 ) 702 { 703 PUDF_FILE_INFO ParentFI; 704 PtrUDFFCB Fcb; 705 PtrUDFFCB ParentFcb = NULL; 706 NTSTATUS RC = STATUS_SUCCESS; 707 NTSTATUS RC2; 708 709 // we can't process Tree until we can acquire Vcb 710 if(!VcbAcquired) 711 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); 712 713 AdPrint(("UDFCloseFileInfoChain\n")); 714 for(; TreeLength && fi; TreeLength--) { 715 716 // close parent chain (if any) 717 // if we started path parsing not from RootDir on Create, 718 // we would never get RootDir here 719 ValidateFileInfo(fi); 720 721 // acquire parent 722 if((ParentFI = fi->ParentFile)) { 723 ParentFcb = fi->Fcb->ParentFcb; 724 ASSERT(ParentFcb); 725 ASSERT(ParentFcb->NTRequiredFCB); 726 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 727 UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE); 728 ASSERT(ParentFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); 729 ASSERT(ParentFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); 730 } else { 731 AdPrint(("Acquiring VCB...\n")); 732 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); 733 AdPrint(("Done\n")); 734 } 735 // acquire current file/dir 736 // we must assure that no more threads try to reuse this object 737 if((Fcb = fi->Fcb)) { 738 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); 739 UDFAcquireResourceExclusive(&(Fcb->NTRequiredFCB->MainResource),TRUE); 740 ASSERT_REF(Fcb->ReferenceCount >= fi->RefCount); 741 if(!(Fcb->FCBFlags & UDF_FCB_DELETED) && 742 (Fcb->FCBFlags & UDF_FCB_VALID)) 743 UDFWriteSecurity(Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc)); 744 RC2 = UDFCloseFile__(Vcb,fi); 745 if(!NT_SUCCESS(RC2)) 746 RC = RC2; 747 ASSERT_REF(Fcb->ReferenceCount > fi->RefCount); 748 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB); 749 UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource)); 750 } else { 751 BrutePoint(); 752 RC2 = UDFCloseFile__(Vcb,fi); 753 if(!NT_SUCCESS(RC2)) 754 RC = RC2; 755 } 756 757 if(ParentFI) { 758 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 759 UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); 760 } else { 761 UDFReleaseResource(&(Vcb->VCBResource)); 762 } 763 fi = ParentFI; 764 } 765 766 if(!VcbAcquired) 767 UDFReleaseResource(&(Vcb->VCBResource)); 768 769 return RC; 770 771 } // end UDFCloseFileInfoChain() 772