VOID FFSSyncUninitializeCacheMap( IN PFILE_OBJECT FileObject) { CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent; NTSTATUS WaitStatus; LARGE_INTEGER FFSLargeZero = {0, 0}; KeInitializeEvent(&UninitializeCompleteEvent.Event, SynchronizationEvent, FALSE); CcUninitializeCacheMap(FileObject, &FFSLargeZero, &UninitializeCompleteEvent); WaitStatus = KeWaitForSingleObject(&UninitializeCompleteEvent.Event, Executive, KernelMode, FALSE, NULL); ASSERT (NT_SUCCESS(WaitStatus)); }
VOID FlushFcb(__in PDokanFCB fcb, __in_opt PFILE_OBJECT fileObject) { if (fcb == NULL) { return; } if (fcb->SectionObjectPointers.ImageSectionObject != NULL) { DDbgPrint(" MmFlushImageSection FileName: %wZ FileCount: %lu.\n", &fcb->FileName, fcb->FileCount); MmFlushImageSection(&fcb->SectionObjectPointers, MmFlushForWrite); DDbgPrint(" MmFlushImageSection done FileName: %wZ FileCount: %lu.\n", &fcb->FileName, fcb->FileCount); } if (fcb->SectionObjectPointers.DataSectionObject != NULL) { DDbgPrint(" CcFlushCache FileName: %wZ FileCount: %lu.\n", &fcb->FileName, fcb->FileCount); ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE); if (fileObject != NULL) { CcUninitializeCacheMap(fileObject, NULL, NULL); } ExReleaseResourceLite(&fcb->PagingIoResource); DDbgPrint(" CcFlushCache done FileName: %wZ FileCount: %lu.\n", &fcb->FileName, fcb->FileCount); } }
static NTSTATUS CdfsCleanupFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject) /* * FUNCTION: Cleans up after a file has been closed. */ { PFCB Fcb; DPRINT("CdfsCleanupFile(DeviceExt %p, FileObject %p)\n", DeviceExt, FileObject); Fcb = FileObject->FsContext; if (!Fcb) { return STATUS_SUCCESS; } /* Notify about the cleanup */ FsRtlNotifyCleanup(DeviceExt->NotifySync, &(DeviceExt->NotifyList), FileObject->FsContext2); /* Uninitialize file cache if initialized for this file object. */ if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->SharedCacheMap) { CcUninitializeCacheMap (FileObject, NULL, NULL); } return STATUS_SUCCESS; }
VOID NtfsReleaseFCB(PNTFS_VCB Vcb, PNTFS_FCB Fcb) { KIRQL oldIrql; DPRINT("releasing FCB at %p: %S, refCount:%d\n", Fcb, Fcb->PathName, Fcb->RefCount); KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql); Fcb->RefCount--; if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb)) { RemoveEntryList(&Fcb->FcbListEntry); KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); CcUninitializeCacheMap(Fcb->FileObject, NULL, NULL); NtfsDestroyFCB(Fcb); } else { KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql); } }
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject) { /* * Complete the cleanup of a FileNode. Remove its share access and * finalize its cache. * * NOTE: If the FileNode is not being deleted (!FileNode->DeletePending) * the FileNode REMAINS in the Context table until Close time! * This is so that if there are mapped views or write behind's pending * when a file gets reopened the FileNode will be correctly reused. * * The FileNode must be acquired exclusive (Main) when calling this function. */ PAGED_CODE(); PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0; BOOLEAN DeletePending; BOOLEAN DeletedFromContextTable = FALSE; FspFsvolDeviceLockContextTable(FsvolDeviceObject); IoRemoveShareAccess(FileObject, &FileNode->ShareAccess); if (0 == --FileNode->HandleCount) { DeletePending = 0 != FileNode->DeletePending; MemoryBarrier(); if (DeletePending) { PTruncateSize = &TruncateSize; if (0 == --FileNode->OpenCount) FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, &DeletedFromContextTable); } else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { /* * Even when the FileInfo is expired, this is the best guess for a file size * without asking the user-mode file system. */ TruncateSize = FileNode->Header.FileSize; PTruncateSize = &TruncateSize; } } FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); CcUninitializeCacheMap(FileObject, PTruncateSize, 0); if (DeletedFromContextTable) FspFileNodeDereference(FileNode); }
VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, const FSP_FSCTL_FILE_INFO *FileInfo) { PAGED_CODE(); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); UINT64 AllocationSize = FileInfo->AllocationSize > FileInfo->FileSize ? FileInfo->AllocationSize : FileInfo->FileSize; UINT64 AllocationUnit; AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize * FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit; AllocationSize = (AllocationSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit; FileNode->Header.AllocationSize.QuadPart = AllocationSize; FileNode->Header.FileSize.QuadPart = FileInfo->FileSize; FileNode->FileAttributes = FileInfo->FileAttributes; FileNode->ReparseTag = FileInfo->ReparseTag; FileNode->CreationTime = FileInfo->CreationTime; FileNode->LastAccessTime = FileInfo->LastAccessTime; FileNode->LastWriteTime = FileInfo->LastWriteTime; FileNode->ChangeTime = FileInfo->ChangeTime; FileNode->InfoExpirationTime = FspExpirationTimeFromMillis( FsvolDeviceExtension->VolumeParams.FileInfoTimeout); FileNode->InfoChangeNumber++; if (0 != CcFileObject) { NTSTATUS Result = FspCcSetFileSizes( CcFileObject, (PCC_FILE_SIZES)&FileNode->Header.AllocationSize); if (!NT_SUCCESS(Result)) { DEBUGLOG("FspCcSetFileSizes error: %s", NtStatusSym(Result)); DEBUGBREAK_CRIT(); CcUninitializeCacheMap(CcFileObject, 0, 0); } } }
NTSTATUS AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; AFSDeviceExt *pDeviceExt = NULL; IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); AFSFcb *pFcb = NULL; AFSCcb *pCcb = NULL; PFILE_OBJECT pFileObject = NULL; AFSFcb *pRootFcb = NULL; AFSDeviceExt *pControlDeviceExt = NULL; IO_STATUS_BLOCK stIoSB; AFSObjectInfoCB *pObjectInfo = NULL; AFSFileCleanupCB stFileCleanup; ULONG ulNotificationFlags = 0; __try { if( AFSRDRDeviceObject == NULL) { // // Let this through, it's a cleanup on the library control device // try_return( ntStatus); } pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; // // Set some initial variables to make processing easier // pFileObject = pIrpSp->FileObject; pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; if( pFcb == NULL) { try_return( ntStatus); } pObjectInfo = pFcb->ObjectInformation; pRootFcb = pObjectInfo->VolumeCB->RootFcb; RtlZeroMemory( &stFileCleanup, sizeof( AFSFileCleanupCB)); stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); stFileCleanup.Identifier = (ULONGLONG)pFileObject; // // Perform the cleanup functionality depending on the type of node it is // switch( pFcb->Header.NodeTypeCode) { case AFS_ROOT_ALL: { AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); AFSReleaseResource( &pFcb->NPFcb->Resource); FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync, &pControlDeviceExt->Specific.Control.DirNotifyList, pCcb); break; } case AFS_IOCTL_FCB: { AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL && pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) { InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } // // This Fcb represents a file // case AFS_FILE_FCB: { // // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); // // If the handle has write permission ... // if( (pCcb->GrantedAccess & FILE_WRITE_DATA) && CcIsFileCached( pIrpSp->FileObject)) { __try { CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, NULL, 0, &stIoSB); if( !NT_SUCCESS( stIoSB.Status)) { AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", &pCcb->FullFileName, pObjectInfo->FileId.Cell, pObjectInfo->FileId.Volume, pObjectInfo->FileId.Vnode, pObjectInfo->FileId.Unique, stIoSB.Status, stIoSB.Information); ntStatus = stIoSB.Status; } } __except( EXCEPTION_EXECUTE_HANDLER) { ntStatus = GetExceptionCode(); } } // // Uninitialize the cache map. This call is unconditional. // AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n", pFcb, pFileObject); CcUninitializeCacheMap( pFileObject, NULL, NULL); // // Unlock all outstanding locks on the file, again, unconditionally // (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock, pFileObject, IoGetRequestorProcess( Irp), NULL); // // Tell the service to unlock all on the file // ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL; // // Perform some final common processing // ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); if( pFcb->ObjectInformation->ParentObjectInformation != NULL) { stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; } stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { stFileCleanup.AllocationSize = pObjectInfo->EndOfFile; stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) { stFileCleanup.CreateTime = pObjectInfo->CreationTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) { stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) { stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME)) { stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME); } } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME)) { stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime; } // // If the count has dropped to zero and there is a pending delete // then delete the node // if( pFcb->OpenHandleCount == 0 && BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { // // Stop anything possibly in process // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Specific.File.ExtentsResource, PsGetCurrentThread()); AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, TRUE); pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED; KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete, 0, FALSE); AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Specific.File.ExtentsResource, PsGetCurrentThread()); AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource); // // Before telling the server about the deleted file, tear down all extents for // the file // AFSTearDownFcbExtents( pFcb, &pCcb->AuthGroup); ntStatus = STATUS_SUCCESS; ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n", &pCcb->FullFileName, ntStatus); ntStatus = STATUS_SUCCESS; ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); } else { ntStatus = STATUS_SUCCESS; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n", &pCcb->FullFileName, pCcb->DirectoryCB); SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); ASSERT( pObjectInfo->ParentObjectInformation != NULL); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, (ULONG)FILE_ACTION_REMOVED); // // Now that the service has the entry has deleted we need to remove it from the parent // tree so another lookup on the node will fail // if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) { AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ removing entry\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, pCcb->DirectoryCB); AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); } } } else { if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { ULONG ulNotifyFilter = 0; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)ulNotifyFilter, (ULONG)FILE_ACTION_MODIFIED); } // // Attempt to flush any dirty extents to the server. This may be a little // aggressive, to flush whenever the handle is closed, but it ensures // coherency. // if( (pCcb->GrantedAccess & FILE_WRITE_DATA) && pFcb->Specific.File.ExtentsDirtyCount != 0) { AFSFlushExtents( pFcb, &pCcb->AuthGroup); } if( pFcb->OpenHandleCount == 0) { // // Wait for any outstanding queued flushes to complete // AFSWaitOnQueuedFlushes( pFcb); ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE; } // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); } // // Remove the share access at this time since we may not get the close for sometime on this FO. // IoRemoveShareAccess( pFileObject, &pFcb->ShareAccess); // // We don't need the name array after the user closes the handle on the file // if( pCcb->NameArray != NULL) { AFSFreeNameArray( pCcb->NameArray); pCcb->NameArray = NULL; } // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL) { ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } // // Root or directory node // case AFS_ROOT_FCB: { // // Set the root Fcb to this node // pRootFcb = pFcb; // // Fall through to below // } case AFS_DIRECTORY_FCB: { // // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); // // Perform some final common processing // ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); if( pFcb->ObjectInformation->ParentObjectInformation != NULL) { stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; } stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) { stFileCleanup.CreateTime = pObjectInfo->CreationTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) { stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) { stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); } } // // If the count has dropped to zero and there is a pending delete // then delete the node // if( pFcb->OpenHandleCount == 0 && BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { // // Try to notify the service about the delete // ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n", &pCcb->FullFileName, ntStatus); ntStatus = STATUS_SUCCESS; ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); } else { ntStatus = STATUS_SUCCESS; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n", &pCcb->FullFileName, pCcb->DirectoryCB); SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); ASSERT( pObjectInfo->ParentObjectInformation != NULL); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, (ULONG)FILE_ACTION_REMOVED); // // Now that the service has the entry has deleted we need to remove it from the parent // tree so another lookup on the node will fail // if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) { AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, pCcb->DirectoryCB); AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); } } } // // If there have been any updates to the node then push it to // the service // else { if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { ULONG ulNotifyFilter = 0; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); if( pObjectInfo->ParentObjectInformation != NULL) { ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)ulNotifyFilter, (ULONG)FILE_ACTION_MODIFIED); } } // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); } // // Release the notification for this directory if there is one // FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync, &pControlDeviceExt->Specific.Control.DirNotifyList, pCcb); // // Remove the share access at this time since we may not get the close for sometime on this FO. // IoRemoveShareAccess( pFileObject, &pFcb->ShareAccess); // // We don't need the name array after the user closes the handle on the file // if( pCcb->NameArray != NULL) { AFSFreeNameArray( pCcb->NameArray); pCcb->NameArray = NULL; } // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL) { ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } case AFS_SYMBOLIC_LINK_FCB: case AFS_MOUNT_POINT_FCB: case AFS_DFS_LINK_FCB: case AFS_INVALID_FCB: { // // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions // AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); // // Perform some final common processing // ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); if( pFcb->ObjectInformation->ParentObjectInformation != NULL) { stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; } stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) { stFileCleanup.CreateTime = pObjectInfo->CreationTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) { stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); } if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) { stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); } } // // If the count has dropped to zero and there is a pending delete // then delete the node // if( pFcb->OpenHandleCount == 0 && BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { // // Try to notify the service about the delete // ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; // // Push the request to the service // ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); if( !NT_SUCCESS( ntStatus) && ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n", &pCcb->FullFileName, ntStatus); ntStatus = STATUS_SUCCESS; ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); } else { ntStatus = STATUS_SUCCESS; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n", &pCcb->FullFileName, pCcb->DirectoryCB); SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); ASSERT( pObjectInfo->ParentObjectInformation != NULL); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, (ULONG)FILE_ACTION_REMOVED); // // Now that the service has the entry has deleted we need to remove it from the parent // tree so another lookup on the node will fail // if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) { AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, pCcb->DirectoryCB); AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup DE %p for %wZ NOT removing entry due to flag set\n", pCcb->DirectoryCB, &pCcb->DirectoryCB->NameInformation.FileName); } } } // // If there have been any updates to the node then push it to // the service // else { if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) { ULONG ulNotifyFilter = 0; ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); if( pObjectInfo->ParentObjectInformation != NULL) { ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, pCcb, (ULONG)ulNotifyFilter, (ULONG)FILE_ACTION_MODIFIED); } } // // Indicate the file access mode that is being released // stFileCleanup.FileAccess = pCcb->FileAccess; AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, &pCcb->AuthGroup, &pCcb->DirectoryCB->NameInformation.FileName, &pObjectInfo->FileId, &stFileCleanup, sizeof( AFSFileCleanupCB), NULL, NULL); } // // Remove the share access at this time since we may not get the close for sometime on this FO. // IoRemoveShareAccess( pFileObject, &pFcb->ShareAccess); // // We don't need the name array after the user closes the handle on the file // if( pCcb->NameArray != NULL) { AFSFreeNameArray( pCcb->NameArray); pCcb->NameArray = NULL; } // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL) { ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } case AFS_SPECIAL_SHARE_FCB: { AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); ASSERT( pFcb->OpenHandleCount != 0); InterlockedDecrement( &pFcb->OpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n", pFcb, pFcb->OpenHandleCount); // // Decrement the open child handle count // if( pObjectInfo->ParentObjectInformation != NULL && pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) { InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n", pObjectInfo->ParentObjectInformation, pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); } // // And finally, release the Fcb if we acquired it. // AFSReleaseResource( &pFcb->NPFcb->Resource); break; } default: AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_WARNING, "AFSCleanup Processing unknown node type %d\n", pFcb->Header.NodeTypeCode); break; } try_exit: if( pFileObject != NULL) { // // Setup the fileobject flags to indicate cleanup is complete. // SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE); } // // Complete the request // AFSCompleteRequest( Irp, ntStatus); }
NTSTATUS DokanDispatchCleanup( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) /*++ Routine Description: This device control dispatcher handles Cleanup IRP. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; PDokanCCB ccb = NULL; PDokanFCB fcb = NULL; PEVENT_CONTEXT eventContext; ULONG eventLength; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanCleanup"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); // Cleanup must be success in any case if (fileObject == NULL) { DDbgPrint(" fileObject == NULL"); status = STATUS_SUCCESS; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_SUCCESS; __leave; } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (fileObject->SectionObjectPointer != NULL && fileObject->SectionObjectPointer->DataSectionObject != NULL) { CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE); CcUninitializeCacheMap(fileObject, NULL, NULL); } fileObject->Flags |= FO_CLEANUP_COMPLETE; eventContext->Context = ccb->UserContext; //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy the filename to EventContext from ccb eventContext->Cleanup.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Cleanup.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // register this IRP to pending IRP list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanCleanup"); FsRtlExitFileSystem(); } return status; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdCleanup (IN PRFSD_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PRFSD_VCB Vcb = 0; BOOLEAN VcbResourceAcquired = FALSE; PFILE_OBJECT FileObject; PRFSD_FCB Fcb = 0; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoAcquired = FALSE; PRFSD_CCB Ccb; PIRP Irp; PAGED_CODE(); _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == RFSDICX) && (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (DeviceObject == RfsdGlobal->DeviceObject) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } VcbResourceAcquired = TRUE; FileObject = IrpContext->FileObject; Fcb = (PRFSD_FCB) FileObject->FsContext; if (!Fcb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (Fcb->Identifier.Type == RFSDVCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject) ) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; RfsdClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } Vcb->OpenHandleCount--; if (!Vcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); } Status = STATUS_SUCCESS; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == RFSDFCB) && (Fcb->Identifier.Size == sizeof(RFSD_FCB))); /* if ( !IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE)) */ { #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbResourceAcquired = TRUE; } Ccb = (PRFSD_CCB) FileObject->FsContext2; if (!Ccb) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) { Status = RfsdFlushFile(Fcb); } _SEH2_LEAVE; } ASSERT((Ccb->Identifier.Type == RFSDCCB) && (Ccb->Identifier.Size == sizeof(RFSD_CCB))); Irp = IrpContext->Irp; Fcb->OpenHandleCount--; if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED )) { Fcb->NonCachedOpenCount--; } Vcb->OpenFileHandleCount--; if (IsFlagOn(Fcb->Flags, FCB_DELETE_ON_CLOSE)) { SetFlag(Fcb->Flags, FCB_DELETE_PENDING); if (IsDirectory(Fcb)) { FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Fcb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } } if (IsDirectory(Fcb)) { FsRtlNotifyCleanup( Vcb->NotifySync, &Vcb->NotifyList, Ccb ); } else { // // Drop any byte range locks this process may have on the file. // FsRtlFastUnlockAll( &Fcb->FileLockAnchor, FileObject, IoGetRequestorProcess(Irp), NULL ); // // If there are no byte range locks owned by other processes on the // file the fast I/O read/write functions doesn't have to check for // locks so we set IsFastIoPossible to FastIoIsPossible again. // if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) { if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) { RfsdPrint(( DBG_INFO, ": %-16.16s %-31s %s\n", RfsdGetCurrentProcessName(), "FastIoIsPossible", Fcb->AnsiFileName.Buffer )); Fcb->Header.IsFastIoPossible = FastIoIsPossible; } } } if ( IsFlagOn( FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedOpenCount != 0) && (Fcb->NonCachedOpenCount == Fcb->ReferenceCount) && (Fcb->SectionObject.DataSectionObject != NULL)) { if( !IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); } ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE); ExReleaseResourceLite(&(Fcb->PagingIoResource)); CcPurgeCacheSection( &Fcb->SectionObject, NULL, 0, FALSE ); } if (Fcb->OpenHandleCount == 0) { if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { // // Have to delete this file... // #ifdef _MSC_VER #pragma prefast( suppress: 28137, "by design" ) #endif if (!ExAcquireResourceExclusiveLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbPagingIoAcquired = TRUE; DbgBreak(); #if DISABLED Status = RfsdDeleteFile(IrpContext, Vcb, Fcb); if (NT_SUCCESS(Status)) { if (IsDirectory(Fcb)) { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED ); } else { RfsdNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED ); } } #endif if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread() ); FcbPagingIoAcquired = FALSE; } } } if (!IsDirectory(Fcb) && FileObject->PrivateCacheMap) { RfsdPrint((DBG_INFO, "RfsdCleanup: CcUninitializeCacheMap is called for %s.\n", Fcb->AnsiFileName.Buffer )); CcUninitializeCacheMap( FileObject, (PLARGE_INTEGER)(&(Fcb->Header.FileSize)), NULL ); } if (!Fcb->OpenHandleCount) { IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); } RfsdPrint((DBG_INFO, "RfsdCleanup: OpenCount: %u ReferCount: %u %s\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer )); Status = STATUS_SUCCESS; if (FileObject) { SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); } } _SEH2_FINALLY { if (FcbPagingIoAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread() ); } if (FcbResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread() ); } if (VcbResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { RfsdQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; RfsdCompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
NTSTATUS FatCommonClose ( IN PVCB Vcb, IN PFCB Fcb, IN PCCB Ccb, IN TYPE_OF_OPEN TypeOfOpen, IN BOOLEAN Wait, OUT PBOOLEAN VcbDeleted OPTIONAL ) /*++ Routine Description: This is the common routine for closing a file/directory called by both the fsd and fsp threads. Close is invoked whenever the last reference to a file object is deleted. Cleanup is invoked when the last handle to a file object is closed, and is called before close. The function of close is to completely tear down and remove the fcb/dcb/ccb structures associated with the file object. Arguments: Fcb - Supplies the file to process. Wait - If this is TRUE we are allowed to block for the Vcb, if FALSE then we must try to acquire the Vcb anyway. VcbDeleted - Returns whether the VCB was deleted by this call. Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PDCB ParentDcb; BOOLEAN RecursiveClose; BOOLEAN LocalVcbDeleted; IRP_CONTEXT IrpContext; #if __NDAS_FAT_SECONDARY__ BOOLEAN volDoResourceAcquired = FALSE; BOOLEAN send2Primary = FALSE; BOOLEAN volDoCcb = FALSE; _U64 primaryFileHandle; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN volDoSessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; #endif PAGED_CODE(); DebugTrace(+1, Dbg, "FatCommonClose...\n", 0); // // Initailize the callers variable, if needed. // LocalVcbDeleted = FALSE; if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } // // Special case the unopened file object // if (TypeOfOpen == UnopenedFileObject) { DebugTrace(0, Dbg, "Close unopened file object\n", 0); Status = STATUS_SUCCESS; DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); return Status; } // // Set up our stack IrpContext. // RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT; IrpContext.NodeByteSize = sizeof( IrpContext ); IrpContext.MajorFunction = IRP_MJ_CLOSE; IrpContext.Vcb = Vcb; if (Wait) { SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); } #if __NDAS_FAT_SECONDARY__ if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) SetFlag( IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { if (!FlagOn(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT)) { return STATUS_PENDING; } volDoResourceAcquired = SecondaryAcquireResourceSharedStarveExclusiveLite( &IrpContext, &volDo->Resource, BooleanFlagOn(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT) ); if (volDoResourceAcquired == FALSE) { ASSERT( FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ); // It's not always garented continue; return STATUS_PENDING; } } if (volDo->NetdiskEnableMode == NETDISK_SECONDARY && !FlagOn(volDo->NetdiskPartitionInformation.Flags, NETDISK_PARTITION_INFORMATION_FLAG_INDIRECT)) { if (TypeOfOpen == VirtualVolumeFile || TypeOfOpen == DirectoryFile) { SetFlag( IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); } } #endif // // Acquire exclusive access to the Vcb and enqueue the irp if we didn't // get access. // #if __NDAS_FAT_SECONDARY__ if (!(FlagOn(IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT) ? ExAcquireResourceExclusiveLite( &Vcb->SecondaryResource, Wait ) : ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait ))) { if (volDoResourceAcquired) { ASSERT( ExIsResourceAcquiredSharedLite(&volDo->Resource) ); SecondaryReleaseResourceLite( NULL, &volDo->Resource ); } return STATUS_PENDING; } #else if (!ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait )) { return STATUS_PENDING; } #endif // // The following test makes sure that we don't blow away an Fcb if we // are trying to do a Supersede/Overwrite open above us. This test // does not apply for the EA file. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) && Vcb->EaFcb != Fcb) { #if __NDAS_FAT_SECONDARY__ if (FlagOn(IrpContext.NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT)) ExReleaseResourceLite( &Vcb->SecondaryResource ); else ExReleaseResourceLite( &Vcb->Resource ); if (volDoResourceAcquired) { ASSERT( ExIsResourceAcquiredSharedLite(&volDo->Resource) ); SecondaryReleaseResourceLite( NULL, &volDo->Resource ); } #else ExReleaseResourceLite( &Vcb->Resource ); #endif return STATUS_PENDING; } // // Setting the following flag prevents recursive closes of directory file // objects, which are handled in a special case loop. // if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS) ) { RecursiveClose = TRUE; } else { SetFlag(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS); RecursiveClose = FALSE; // // Since we are at the top of the close chain, we need to add // a reference to the VCB. This will keep it from going away // on us until we are ready to check for a dismount below. // Vcb->OpenFileCount += 1; } try { // // Case on the type of open that we are trying to close. // switch (TypeOfOpen) { case VirtualVolumeFile: DebugTrace(0, Dbg, "Close VirtualVolumeFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( &(Vcb->InternalOpenCount) ); InterlockedDecrement( &(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case UserVolumeOpen: DebugTrace(0, Dbg, "Close UserVolumeOpen\n", 0); #if __NDAS_FAT_SECONDARY__ if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { volDoCcb = TRUE; if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { if ( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ) Fcb->CorruptedCcbCloseCount --; send2Primary = FALSE; } else send2Primary = TRUE; primaryFileHandle = Ccb->PrimaryFileHandle; ExAcquireFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); RemoveEntryList( &Ccb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); InitializeListHead( &Ccb->ListEntry ); Ccb->FileObject = NULL; if (Ccb->Buffer) ExFreePool( Ccb->Buffer ); Ccb->FileObject = NULL; InterlockedDecrement( &Vcb->SecondaryOpenFileCount ); } else { Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } } if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_OPEN_BY_PRIMARY_SESSION)) { InterlockedDecrement( &Vcb->PrimaryOpenFileCount ); } FatDeleteCcb( &IrpContext, &Ccb ); if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { InterlockedDecrement( &Fcb->OpenCount ); if (Fcb->OpenCount == 0) { ExAcquireFastMutex( &volDo->Secondary->FcbQMutex ); RemoveEntryList( &Fcb->ListEntry ); InitializeListHead( &Fcb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->FcbQMutex ); Fcb->Header.NodeTypeCode = FAT_NTC_FCB; FatDeleteFcb( &IrpContext, &Fcb ); Secondary_Dereference( volDo->Secondary ); } } else { try_return( Status = STATUS_SUCCESS ); } #else Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); try_return( Status = STATUS_SUCCESS ); #endif break; case EaFile: DebugTrace(0, Dbg, "Close EaFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( &(Vcb->InternalOpenCount) ); InterlockedDecrement( &(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case DirectoryFile: DebugTrace(0, Dbg, "Close DirectoryFile\n", 0); InterlockedDecrement( &Fcb->Specific.Dcb.DirectoryFileOpenCount ); // // Remove this internal open from the count. // InterlockedDecrement( &(Vcb->InternalOpenCount) ); // // If this is the root directory, it is a residual open // as well. // if (NodeType( Fcb ) == FAT_NTC_ROOT_DCB) { InterlockedDecrement( &(Vcb->ResidualOpenCount) ); } // // If this is a recursive close, just return here. // if ( RecursiveClose ) { try_return( Status = STATUS_SUCCESS ); } else { break; } case UserDirectoryOpen: case UserFileOpen: DebugTrace(0, Dbg, "Close UserFileOpen/UserDirectoryOpen\n", 0); // // Uninitialize the cache map if we no longer need to use it // if ((NodeType(Fcb) == FAT_NTC_DCB) && IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) && (Fcb->OpenCount == 1) && (Fcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject = Fcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize the stream file object\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); // // Dereference the directory file. This may cause a close // Irp to be processed, so we need to do this before we destory // the Fcb. // Fcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); } #if __NDAS_FAT__ if (TypeOfOpen == UserFileOpen) { ExAcquireFastMutex( &Fcb->NonPaged->CcbQMutex ); Ccb->FileObject = NULL; Ccb->Fcb = NULL; RemoveEntryList( &Ccb->FcbListEntry ); InitializeListHead( &Ccb->FcbListEntry ); ExReleaseFastMutex( &Fcb->NonPaged->CcbQMutex ); } #endif Fcb->OpenCount -= 1; #if __NDAS_FAT_SECONDARY__ if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { volDoCcb = TRUE; if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { if ( FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ) Fcb->CorruptedCcbCloseCount --; send2Primary = FALSE; } else send2Primary = TRUE; primaryFileHandle = Ccb->PrimaryFileHandle; ExAcquireFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); RemoveEntryList( &Ccb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->RecoveryCcbQMutex ); InitializeListHead( &Ccb->ListEntry ); Ccb->FileObject = NULL; if (Ccb->Buffer) ExFreePool( Ccb->Buffer ); InterlockedDecrement( &Vcb->SecondaryOpenFileCount ); Ccb->FileObject = NULL; } else { Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } } if (FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_OPEN_BY_PRIMARY_SESSION)) { InterlockedDecrement( &Vcb->PrimaryOpenFileCount ); } FatDeleteCcb( &IrpContext, &Ccb ); if (Fcb && FlagOn(Fcb->NdasFatFlags, ND_FAT_FCB_FLAG_SECONDARY)) { if (Fcb->OpenCount == 0) { ExAcquireFastMutex( &volDo->Secondary->FcbQMutex ); RemoveEntryList( &Fcb->ListEntry ); InitializeListHead( &Fcb->ListEntry ); ExReleaseFastMutex( &volDo->Secondary->FcbQMutex ); Fcb->Header.NodeTypeCode = FAT_NTC_FCB; FatDeleteFcb( &IrpContext, &Fcb ); Secondary_Dereference( volDo->Secondary ); } } #else Fcb->OpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); #endif break; default: FatBugCheck( TypeOfOpen, 0, 0 ); } #if __NDAS_FAT_SECONDARY__ if (send2Primary) { Status = STATUS_SUCCESS; volDoSessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( &IrpContext, &volDo->SessionResource, BooleanFlagOn(IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) || FlagOn(volDo->Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { Status = STATUS_SUCCESS; leave; } secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_CLOSE, 0 ); if (secondaryRequest == NULL) { ASSERT( FALSE ); leave; } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_CLOSE, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Fcb; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_CLOSE; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = primaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); KeClearEvent( &secondaryRequest->CompleteEvent ); if (Status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); } if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) { ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; ASSERT( ndfsWinxpReplytHeader->Status == STATUS_SUCCESS ); leave; } ASSERT( secondaryRequest->ExecuteStatus != STATUS_SUCCESS ); } if (volDoCcb == TRUE) { Status = STATUS_SUCCESS; leave; } #endif // // At this point we've cleaned up any on-disk structure that needs // to be done, and we can now update the in-memory structures. // Now if this is an unreferenced FCB or if it is // an unreferenced DCB (not the root) then we can remove // the fcb and set our ParentDcb to non null. // if (((NodeType(Fcb) == FAT_NTC_FCB) && (Fcb->OpenCount == 0)) || ((NodeType(Fcb) == FAT_NTC_DCB) && (IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) && (Fcb->OpenCount == 0) && (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0))) { ParentDcb = Fcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &Fcb ); // // Uninitialize our parent's cache map if we no longer need // to use it. // while ((NodeType(ParentDcb) == FAT_NTC_DCB) && IsListEmpty(&ParentDcb->Specific.Dcb.ParentDcbQueue) && (ParentDcb->OpenCount == 0) && (ParentDcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject; DirectoryFileObject = ParentDcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); ParentDcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); // // Now, if the ObDereferenceObject() caused the final close // to come in, then blow away the Fcb and continue up, // otherwise wait for Mm to to dereference its file objects // and stop here.. // if ( ParentDcb->Specific.Dcb.DirectoryFileOpenCount == 0) { PDCB CurrentDcb; CurrentDcb = ParentDcb; ParentDcb = CurrentDcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &CurrentDcb ); } else { break; } } } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { DebugUnwind( FatCommonClose ); #if __NDAS_FAT_SECONDARY__ if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); if (volDoSessionResourceAcquired) { SecondaryReleaseResourceLite( &IrpContext, &volDo->SessionResource ); } if (volDoResourceAcquired) { ASSERT( ExIsResourceAcquiredSharedLite(&volDo->Resource) ); SecondaryReleaseResourceLite( NULL, &volDo->Resource ); } #endif // // We are done processing the close. If we are the top of the close // chain, see if the VCB can go away. We have biased the open count by // one, so we need to take that into account. // if (!RecursiveClose) { // // See if there is only one open left. If so, it is ours. We only want // to check for a dismount if a dismount is not already in progress. // We also only do this if the caller can handle the VCB going away. // This is determined by whether they passed in the VcbDeleted argument. // if (Vcb->OpenFileCount == 1 && !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) && ARGUMENT_PRESENT( VcbDeleted )) { // // We need the global lock, which must be acquired before the // VCB. Since we already have the VCB, we have to drop and // reaquire here. Note that we always want to wait from this // point on. Note that the VCB cannot go away, since we have // biased the open file count. // FatReleaseVcb( &IrpContext, Vcb ); SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); FatAcquireExclusiveGlobal( &IrpContext ); FatAcquireExclusiveVcb( &IrpContext, Vcb ); // // We have our locks in the correct order. Remove our // extra open and check for a dismount. Note that if // something changed while we dropped the lock, it will // not matter, since the dismount code does the correct // checks to make sure the volume can really go away. // Vcb->OpenFileCount -= 1; LocalVcbDeleted = FatCheckForDismount( &IrpContext, Vcb, FALSE ); FatReleaseGlobal( &IrpContext ); // // Let the caller know what happened, if they want this information. // if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } } else { // // The volume cannot go away now. Just remove our extra reference. // Vcb->OpenFileCount -= 1; } // // If the VCB is still around, clear our recursion flag. // if (!LocalVcbDeleted) { ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS ); } } // // Only release the VCB if it did not go away. // if (!LocalVcbDeleted) { FatReleaseVcb( &IrpContext, Vcb ); } DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); } return Status; }
NTSTATUS DokanDispatchFlush( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PVOID buffer; NTSTATUS status = STATUS_INVALID_PARAMETER; PDokanFCB fcb; PDokanCCB ccb; PDokanVCB vcb; PEVENT_CONTEXT eventContext; ULONG eventLength; PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanFlush\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_SUCCESS; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_SUCCESS; __leave; } DokanPrintFileName(fileObject); ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy file name to be flushed eventContext->Flush.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Flush.FileName, fcb->FileName.Buffer, fcb->FileName.Length); CcUninitializeCacheMap(fileObject, NULL, NULL); //fileObject->Flags &= FO_CLEANUP_COMPLETE; // register this IRP to waiting IRP list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { // if status is not pending, must complete current IRPs if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } else { DDbgPrint(" STATUS_PENDING\n"); } DDbgPrint("<== DokanFlush\n"); FsRtlExitFileSystem(); } return status; }
/* 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); DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb, Fcb->FatHandle, &Fcb->FullFileName); } /* 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 XixFsdCommonCleanUp( IN PXIFS_IRPCONTEXT pIrpContext ) { NTSTATUS RC = STATUS_SUCCESS; PXIFS_FCB pFCB = NULL; PXIFS_CCB pCCB = NULL; PXIFS_VCB pVCB = NULL; PFILE_OBJECT pFileObject = NULL; TYPE_OF_OPEN TypeOfOpen = UnopenedFileObject; PIRP pIrp = NULL; PIO_STACK_LOCATION pIrpSp = NULL; KIRQL SavedIrql; PXIFS_LCB pLCB = NULL; PXIFS_FCB pParentFCB = NULL; BOOLEAN Wait = FALSE; BOOLEAN VCBAcquired = FALSE; BOOLEAN ParentFCBAcquired = FALSE; BOOLEAN CanWait = FALSE; BOOLEAN AttemptTeardown = FALSE; BOOLEAN SendUnlockNotification = FALSE; PAGED_CODE(); DebugTrace((DEBUG_LEVEL_TRACE), (DEBUG_TARGET_CLEANUP|DEBUG_TARGET_IRPCONTEXT), ("Enter XifsdCommonCleanUp pIrpContext(%p)\n", pIrpContext)); ASSERT_IRPCONTEXT(pIrpContext); pIrp = pIrpContext->Irp; ASSERT(pIrp); // check if open request is releated to file system CDO { PDEVICE_OBJECT DeviceObject = pIrpContext->TargetDeviceObject; ASSERT(DeviceObject); if (DeviceObject == XiGlobalData.XifsControlDeviceObject) { RC = STATUS_SUCCESS; DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CLEANUP), ("CDO Device TargetDevide(%p).\n", DeviceObject)); XixFsdCompleteRequest(pIrpContext,RC,0); return(RC); } } if(pIrpContext->VCB == NULL){ DebugTrace(DEBUG_LEVEL_TRACE, DEBUG_TARGET_CLEANUP, ("pIrpContext->VCB == NULL.\n")); RC = STATUS_SUCCESS; XixFsdCompleteRequest(pIrpContext, RC, 0); return RC; } pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp); pFileObject = pIrpSp->FileObject; ASSERT(pFileObject); TypeOfOpen = XixFsdDecodeFileObject(pFileObject, &pFCB, &pCCB); if(TypeOfOpen <= StreamFileOpen){ DebugTrace((DEBUG_LEVEL_TRACE|DEBUG_LEVEL_INFO), DEBUG_TARGET_CLEANUP, ("TypeOfOpen <= StreamFileOpen.\n")); XixFsdCompleteRequest(pIrpContext, STATUS_SUCCESS, 0); return STATUS_SUCCESS; } CanWait = XifsdCheckFlagBoolean(pIrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT); if(CanWait == FALSE){ DebugTrace((DEBUG_LEVEL_TRACE|DEBUG_LEVEL_INFO), (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_IRPCONTEXT), ("PostRequest IrpCxt(%p) Irp(%p)\n", pIrpContext, pIrp)); RC = XixFsdPostRequest(pIrpContext, pIrp); return RC; } ASSERT_FCB(pFCB); pVCB = pFCB->PtrVCB; ASSERT_VCB(pVCB); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_RESOURCE|DEBUG_TARGET_VCB), ("Acquire exclusive pVCB(%p) VCBResource(%p).\n", pVCB, &pVCB->VCBResource)); if((TypeOfOpen == UserVolumeOpen) && XifsdCheckFlagBoolean(pFileObject->Flags, FO_FILE_MODIFIED)) { XifsdAcquireVcbExclusive(CanWait, pVCB, FALSE); VCBAcquired = TRUE; } XifsdAcquireFcbExclusive(CanWait, pFCB, FALSE); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_RESOURCE| DEBUG_TARGET_FCB), ("Acquire exclusive FCB(%p) FCBResource(%p).\n", pFCB, pFCB->FCBResource)); XifsdSetFlag(pFileObject->Flags, FO_CLEANUP_COMPLETE); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_RESOURCE| DEBUG_TARGET_FCB), ("Set File Object Flags(0x%x)\n", pFileObject->Flags)); //IoRemoveShareAccess( pFileObject, &pFCB->FCBShareAccess ); try{ switch(TypeOfOpen){ case UserDirectoryOpen: if(XifsdCheckFlagBoolean(pCCB->CCBFlags, XIFSD_CCB_FLAG_NOFITY_SET)) { DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_ALL, ("CompletionFilter Notify CleanUp (%wZ) pCCB(%p)\n", &pFCB->FCBName, pCCB)); FsRtlNotifyCleanup(pVCB->NotifyIRPSync, &pVCB->NextNotifyIRP, pCCB); //DbgPrint("Notify CleanUp (%wZ) pCCB(%p)\n", &pFCB->FCBName, pCCB); } //DbgPrint("CleanUp (%wZ) pCCB(%p) pCCB->CCBFlags(%x)\n", &pFCB->FCBName, pCCB, pCCB->CCBFlags); DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_ALL, ("!!!!CleanUp (%wZ) pCCB(%p)\n", &pFCB->FCBName, pCCB)); IoRemoveShareAccess( pFileObject, &pFCB->FCBShareAccess ); break; case UserFileOpen: // // Coordinate the cleanup operation with the oplock state. // Oplock cleanup operations can always cleanup immediately so no // need to check for STATUS_PENDING. // FsRtlCheckOplock( &pFCB->FCBOplock, pIrp, pIrpContext, NULL, NULL ); // // Unlock all outstanding file locks. // if (pFCB->FCBFileLock != NULL) { FsRtlFastUnlockAll( pFCB->FCBFileLock, pFileObject, IoGetRequestorProcess( pIrp ), NULL ); } // // Check the fast io state. // XifsdLockFcb( pIrpContext, pFCB ); pFCB->IsFastIoPossible = XixFsdCheckFastIoPossible( pFCB ); XifsdUnlockFcb( pIrpContext, pFCB ); /* if((pFCB->HasLock != FCB_FILE_LOCK_HAS) && (!XifsdCheckFlagBoolean(pFCB->FCBFlags, XIFSD_FCB_OPEN_WRITE)) && XifsdCheckFlagBoolean(pFileObject->Flags, FO_CACHE_SUPPORTED) && (pFCB->FCBCleanup == 1) ){ if(pFCB->SectionObject.DataSectionObject != NULL) { CcFlushCache(&(pFCB->SectionObject), NULL, 0, NULL); ExAcquireResourceSharedLite(pFCB->PagingIoResource, TRUE); ExReleaseResourceLite( pFCB->PagingIoResource ); CcPurgeCacheSection( &(pFCB->SectionObject), NULL, 0, FALSE ); } } */ if( XifsdCheckFlagBoolean(pFileObject->Flags, FO_CACHE_SUPPORTED) && (pFCB->FcbNonCachedOpenCount > 1) && ((pFCB->FcbNonCachedOpenCount + 1) == pFCB->FCBCleanup) ) { if(pFCB->SectionObject.DataSectionObject != NULL) { // changed by ILGU HONG for readonly 09052006 if(!pFCB->PtrVCB->IsVolumeWriteProctected) CcFlushCache(&(pFCB->SectionObject), NULL, 0, NULL); // changed by ILGU HONG for readonly end //DbgPrint("CcFlush 1 File(%wZ)\n", &pFCB->FCBFullPath); ExAcquireResourceSharedLite(pFCB->PagingIoResource, TRUE); ExReleaseResourceLite( pFCB->PagingIoResource ); CcPurgeCacheSection( &(pFCB->SectionObject), NULL, 0, FALSE ); } } /* else if(pFCB->FCBCleanup == 1 ){ if(XifsdCheckFlagBoolean(pFileObject->Flags, FO_CACHE_SUPPORTED)){ if(pFCB->SectionObject.DataSectionObject != NULL) { CcFlushCache(&(pFCB->SectionObject), NULL, 0, NULL); ExAcquireResourceSharedLite(pFCB->PagingIoResource, TRUE); ExReleaseResourceLite( pFCB->PagingIoResource ); CcPurgeCacheSection( &(pFCB->SectionObject), NULL, 0, FALSE ); } } if(XifsdCheckFlagBoolean(pFCB->FCBFlags,XIFSD_FCB_MODIFIED_FILE)){ XixFsdUpdateFCB(pFCB); } } */ IoRemoveShareAccess( pFileObject, &pFCB->FCBShareAccess ); // // Cleanup the cache map. // CcUninitializeCacheMap( pFileObject, NULL, NULL ); break; case UserVolumeOpen: break; default: break; } if((TypeOfOpen == UserDirectoryOpen) || (TypeOfOpen == UserFileOpen)){ if(pFCB->FCBCleanup == 1 ){ if(XifsdCheckFlagBoolean(pFCB->FCBFlags,XIFSD_FCB_MODIFIED_FILE)){ // changed by ILGU HONG for readonly 09052006 if(!pFCB->PtrVCB->IsVolumeWriteProctected){ XixFsdUpdateFCB(pFCB); if(pFCB->WriteStartOffset != -1){ //DbgPrint("Set Update Information!!!\n"); XixFsdSendFileChangeRC( TRUE, pVCB->HostMac, pFCB->LotNumber, pVCB->DiskId, pVCB->PartitionId, pFCB->FileSize.QuadPart, pFCB->RealAllocationSize, pFCB->WriteStartOffset ); pFCB->WriteStartOffset = -1; } } // changed by ILGU HONG for readonly end } } if(XifsdCheckFlagBoolean(pCCB->CCBFlags, XIFSD_CCB_FLAGS_DELETE_ON_CLOSE)){ if(pFCB == pFCB->PtrVCB->RootDirFCB){ XifsdClearFlag(pCCB->CCBFlags, XIFSD_CCB_FLAGS_DELETE_ON_CLOSE); XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); }else{ XifsdSetFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); } } // changed by ILGU HONG for readonly 09082006 if(XifsdCheckFlagBoolean(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE) && (!pFCB->PtrVCB->IsVolumeWriteProctected) ){ // changed by ILGU HONG for readonly end if(pFCB->FCBCleanup == 1){ //DbgPrint(" !!!Delete Entry From table (%wZ) .\n", &pFCB->FCBFullPath); ASSERT_CCB(pCCB); pLCB = pCCB->PtrLCB; ASSERT_LCB(pLCB); pParentFCB = pLCB->ParentFcb; ASSERT_FCB(pParentFCB); pFCB->FileSize.QuadPart = 0; pFCB->ValidDataLength.QuadPart = 0; if(pFCB->FCBType == FCB_TYPE_FILE){ XifsdReleaseFcb(TRUE, pFCB); XifsdAcquireFcbExclusive(TRUE, pParentFCB, FALSE); ParentFCBAcquired = TRUE; XifsdAcquireFcbExclusive(TRUE, pFCB, FALSE); RC = DeleteParentChild(pIrpContext, pParentFCB, &pLCB->FileName); if(!NT_SUCCESS(RC)){ DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL, ("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName)); //XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); RC = STATUS_SUCCESS; goto pass_through; } XifsdClearFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_DELETE_ON_CLOSE); XifsdSetFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_LINK_IS_GONE); XixFsdRemovePrefix(TRUE, pLCB); // // Now Decrement the reference counts for the parent and drop the Vcb. // XifsdLockVcb(pIrpContext,pVCB); DebugTrace( DEBUG_LEVEL_INFO, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT), ("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", pParentFCB->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, pParentFCB->FCBReference, pParentFCB->FCBUserReference )); XifsdDecRefCount( pParentFCB, 1, 1 ); DebugTrace( DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT), ("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", pParentFCB->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, pParentFCB->FCBReference, pParentFCB->FCBUserReference )); XifsdUnlockVcb( pIrpContext, pVCB ); if(!NT_SUCCESS(RC)){ DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL, ("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName)); XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); RC = STATUS_SUCCESS; goto pass_through; } }else { RC = XixFsReLoadFileFromFcb(pFCB); if(!NT_SUCCESS(RC)){ DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL, ("Fail XixFsReLoadFileFromFcb (%wZ)\n", &pFCB->FCBName)); XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); RC = STATUS_SUCCESS; goto pass_through; } if(pFCB->ChildCount != 0){ XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); RC = STATUS_SUCCESS; goto pass_through; } XifsdReleaseFcb(TRUE, pFCB); XifsdAcquireFcbExclusive(TRUE, pParentFCB, FALSE); ParentFCBAcquired = TRUE; XifsdAcquireFcbExclusive(TRUE, pFCB, FALSE); RC = DeleteParentChild(pIrpContext, pParentFCB, &pLCB->FileName); if(!NT_SUCCESS(RC)){ DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL, ("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName)); //ifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); RC = STATUS_SUCCESS; goto pass_through; } XifsdClearFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_DELETE_ON_CLOSE); XifsdSetFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_LINK_IS_GONE); XixFsdRemovePrefix(TRUE, pLCB); // // Now Decrement the reference counts for the parent and drop the Vcb. // XifsdLockVcb(pIrpContext,pVCB); DebugTrace( DEBUG_LEVEL_INFO, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT), ("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", pParentFCB->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, pParentFCB->FCBReference, pParentFCB->FCBUserReference )); XifsdDecRefCount( pParentFCB, 1, 1 ); DebugTrace( DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT), ("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", pParentFCB->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, pParentFCB->FCBReference, pParentFCB->FCBUserReference )); XifsdUnlockVcb( pIrpContext, pVCB ); if(!NT_SUCCESS(RC)){ DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL, ("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName)); XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE); RC = STATUS_SUCCESS; goto pass_through; } } //XixFsdDeleteUpdateFCB(pFCB); XixFsdSendRenameLinkBC( TRUE, XIFS_SUBTYPE_FILE_DEL, pVCB->HostMac, pFCB->LotNumber, pVCB->DiskId, pVCB->PartitionId, pFCB->ParentLotNumber, 0 ); } } } pass_through: XifsdLockVcb(pIrpContext, pVCB); if(XifsdCheckFlagBoolean(pFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { ASSERT(pFCB->FcbNonCachedOpenCount > 0); pFCB->FcbNonCachedOpenCount --; } XifsdDecrementClenupCount(pFCB); DebugTrace(DEBUG_LEVEL_ALL, DEBUG_TARGET_ALL, ("Cleanup Name(%wZ) FCBLotNumber(%I64d) FCBCleanUp(%ld) VCBCleanup(%ld) pCCB(%p) FileObject(%p)\n", &pFCB->FCBName, pFCB->LotNumber, pFCB->FCBCleanup, pVCB->VCBCleanup, pCCB, pFileObject )); XifsdUnlockVcb( pIrpContext, pVCB ); AttemptTeardown = (pVCB->VCBCleanup == 0 && pVCB->VCBState == XIFSD_VCB_STATE_VOLUME_DISMOUNTED ); if(pFileObject == pVCB->LockVolumeFileObject){ ASSERT(XifsdCheckFlagBoolean(pVCB->VCBFlags, XIFSD_VCB_FLAGS_VOLUME_LOCKED)); IoAcquireVpbSpinLock(&SavedIrql); XifsdClearFlag(pVCB->PtrVPB->Flags, VPB_LOCKED); IoReleaseVpbSpinLock( SavedIrql ); XifsdClearFlag(pVCB->VCBFlags, XIFSD_VCB_FLAGS_VOLUME_LOCKED); pVCB->LockVolumeFileObject = NULL; SendUnlockNotification = TRUE; } /* if( (pFCB->FCBCleanup == 0) && (!XifsdCheckFlagBoolean(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE)) ){ DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_CLEANUP|DEBUG_TARGET_IRPCONTEXT| DEBUG_TARGET_ALL), ("CleanUp Release Lot Lock LotNumber(%ld)\n", pFCB->LotNumber)); XifsdLotUnLock(pVCB, pVCB->TargetDeviceObject, pFCB->LotNumber); pFCB->HasLock = FCB_FILE_LOCK_INVALID; } */ // // We must clean up the share access at this time, since we may not // get a Close call for awhile if the file was mapped through this // File Object. // }finally{ XifsdReleaseFcb(pIrpContext, pFCB); if(ParentFCBAcquired) { XifsdReleaseFcb(TRUE,pParentFCB); } if (SendUnlockNotification) { FsRtlNotifyVolumeEvent( pFileObject, FSRTL_VOLUME_UNLOCK ); } if (VCBAcquired) { XifsdReleaseVcb( pIrpContext, pVCB); } } if (AttemptTeardown) { XifsdAcquireVcbExclusive( CanWait, pVCB, FALSE ); try { XixFsdPurgeVolume( pIrpContext, pVCB, FALSE ); } finally { XifsdReleaseVcb( pIrpContext, pVCB ); } } // // If this is a normal termination then complete the request // DebugTrace((DEBUG_LEVEL_TRACE), (DEBUG_TARGET_CLEANUP|DEBUG_TARGET_IRPCONTEXT), ("Exit XifsdCommonCleanUp pIrpContext(%p)\n", pIrpContext)); XixFsdCompleteRequest( pIrpContext, STATUS_SUCCESS, 0 ); return STATUS_SUCCESS; }
VOID NtfsCreateInternalStreamCommon ( IN PIRP_CONTEXT IrpContext, IN PSCB Scb, IN BOOLEAN UpdateScb, IN BOOLEAN CompressedStream, IN UNICODE_STRING const *StreamName ) /*++ Routine Description: This routine is called to prepare a stream file associated with a particular attribute of a file. On return, the Scb for the attribute will have an associated stream file object. On return, this stream file will have been initialized through the cache manager. TEMPCODE The following assumptions have been made or if open issue, still unresolved. - Assume. The call to create Scb will initialize the Mcb for the non-resident case. - Assume. When this file is created I increment the open count but not the unclean count for this Scb. When we are done with the stream file, we should uninitialize it and dereference it. We also set the file object pointer to NULL. Close will then do the correct thing. - Assume. Since this call is likely to be followed shortly by either a read or write, the cache map is initialized here. Arguments: Scb - Supplies the address to store the Scb for this attribute and stream file. This will exist on return from this function. UpdateScb - Indicates if the caller wants to update the Scb from the attribute. CompressedStream - Supplies TRUE if caller wishes to create the compressed stream. StreamName - Internal stream name or NULL is there isn't one available. This is a constant value so we don't have to allocate any pool. Return Value: None. --*/ { PVCB Vcb = Scb->Vcb; CC_FILE_SIZES CcFileSizes; PFILE_OBJECT CallersFileObject; PFILE_OBJECT *FileObjectPtr = &Scb->FileObject; PFILE_OBJECT UnwindStreamFile = NULL; BOOLEAN UnwindInitializeCacheMap = FALSE; BOOLEAN DecrementScbCleanup = FALSE; BOOLEAN AcquiredMutex = FALSE; ASSERT_IRP_CONTEXT( IrpContext ); PAGED_CODE(); DebugTrace( +1, Dbg2, ("NtfsCreateInternalAttributeStream\n") ); DebugTrace( 0, Dbg2, ("Scb -> %08lx\n", Scb) ); // // Change FileObjectPtr if he wants the compressed stream // #if (__NDAS_NTFS_DBG__ && __NDAS_NTFS_SECONDARY__) if (FlagOn(Scb->Fcb->NdasNtfsFlags, NDAS_NTFS_FCB_FLAG_SECONDARY)) ASSERT( FALSE ); #endif #ifdef COMPRESS_ON_WIRE if (CompressedStream) { FileObjectPtr = &Scb->Header.FileObjectC; } #endif // // If there is no file object, we create one and initialize // it. // if (*FileObjectPtr == NULL) { // // Only acquire the mutex if we don't have the file exclusive. // if (!NtfsIsExclusiveScb( Scb )) { KeWaitForSingleObject( &StreamFileCreationMutex, Executive, KernelMode, FALSE, NULL ); AcquiredMutex = TRUE; } try { // // Someone could have gotten there first. // if (*FileObjectPtr == NULL) { UnwindStreamFile = IoCreateStreamFileObjectLite( NULL, Scb->Vcb->Vpb->RealDevice); if (ARGUMENT_PRESENT( StreamName )) { UnwindStreamFile->FileName.MaximumLength = StreamName->MaximumLength; UnwindStreamFile->FileName.Length = StreamName->Length; UnwindStreamFile->FileName.Buffer = StreamName->Buffer; } // // Propagate any flags from the caller's FileObject to our // stream file that the Cache Manager may look at, so we do not // miss hints like sequential only or temporary. // if (!FlagOn(Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE) && (IrpContext->OriginatingIrp != NULL) && (CallersFileObject = IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject)) { SetFlag( UnwindStreamFile->Flags, CallersFileObject->Flags & NTFS_FO_PROPAGATE_TO_STREAM ); } UnwindStreamFile->SectionObjectPointer = &Scb->NonpagedScb->SegmentObject; // // For a compressed stream, we have to use separate section // object pointers. // #ifdef COMPRESS_ON_WIRE if (CompressedStream) { UnwindStreamFile->SectionObjectPointer = &Scb->NonpagedScb->SegmentObjectC; } #endif // // If we have created the stream file, we set it to type // 'StreamFileOpen' // NtfsSetFileObject( UnwindStreamFile, StreamFileOpen, Scb, NULL ); if (FlagOn( Scb->ScbState, SCB_STATE_TEMPORARY )) { SetFlag( UnwindStreamFile->Flags, FO_TEMPORARY_FILE ); } // // Initialize the fields of the file object. // UnwindStreamFile->ReadAccess = TRUE; UnwindStreamFile->WriteAccess = TRUE; UnwindStreamFile->DeleteAccess = TRUE; // // Increment the open count and set the section // object pointers. We don't set the unclean count as the // cleanup call has already occurred. // NtfsIncrementCloseCounts( Scb, TRUE, FALSE ); // // Increment the cleanup count in this Scb to prevent the // Scb from going away if the cache call fails. // InterlockedIncrement( &Scb->CleanupCount ); DecrementScbCleanup = TRUE; // // If the Scb header has not been initialized, we will do so now. // if (UpdateScb && !FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) { NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL ); } // // If this is a compressed stream and the file is not already // marked as MODIFIED_NO_WRITE then do it now. Use the // Extended flag field in the Fsrtl header for this. Since this // is the only place we make this call with FsContext2 == NULL, // it does not matter how we leave the FsRtl header flag.! // NtfsAcquireFsrtlHeader( Scb ); ClearFlag(Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE); if (!FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) && !FlagOn( Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE ) && !CompressedStream) { SetFlag(Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE); } NtfsReleaseFsrtlHeader( Scb ); // // Check if we need to initialize the cache map for the stream file. // The size of the section to map will be the current allocation // for the stream file. // if (UnwindStreamFile->PrivateCacheMap == NULL) { BOOLEAN PinAccess; CcFileSizes = *(PCC_FILE_SIZES)&Scb->Header.AllocationSize; // // If this is a stream with Usa protection, we want to tell // the Cache Manager we do not need to get any valid data // callbacks. We do this by having xxMax sitting in // ValidDataLength for the call, but we have to restore the // correct value afterwards. // // We also do this for all of the stream files created during // restart. This has the effect of telling Mm to always // fault the page in from disk. Don't generate a zero page if // push up the file size during restart. // if (FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE )) { CcFileSizes.ValidDataLength.QuadPart = MAXLONGLONG; } PinAccess = (BOOLEAN) (Scb->AttributeTypeCode != $DATA || FlagOn(Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE | FCB_STATE_SYSTEM_FILE) || FlagOn( Scb->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ) || CompressedStream); // // Bias this for the Usn journal. // if (FlagOn( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL )) { CcFileSizes.AllocationSize.QuadPart -= Vcb->UsnCacheBias; CcFileSizes.FileSize.QuadPart -= Vcb->UsnCacheBias; } CcInitializeCacheMap( UnwindStreamFile, &CcFileSizes, PinAccess, &NtfsData.CacheManagerCallbacks, (PCHAR)Scb + CompressedStream ); UnwindInitializeCacheMap = TRUE; } // // Now call Cc to set the log handle for the file. // if (FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) && (Scb != Vcb->LogFileScb)) { CcSetLogHandleForFile( UnwindStreamFile, Vcb->LogHandle, &LfsFlushToLsn ); } // // It is now safe to store the stream file in the Scb. We wait // until now because we don't want an unsafe tester to use the // file object until the cache is initialized. // *FileObjectPtr = UnwindStreamFile; } } finally { DebugUnwind( NtfsCreateInternalAttributeStream ); // // Undo our work if an error occurred. // if (AbnormalTermination()) { // // Uninitialize the cache file if we initialized it. // if (UnwindInitializeCacheMap) { CcUninitializeCacheMap( UnwindStreamFile, NULL, NULL ); } // // Dereference the stream file if we created it. // if (UnwindStreamFile != NULL) { // // Clear the internal file name constant // NtfsClearInternalFilename( UnwindStreamFile ); ObDereferenceObject( UnwindStreamFile ); } } // // Restore the Scb cleanup count. // if (DecrementScbCleanup) { InterlockedDecrement( &Scb->CleanupCount ); } if (AcquiredMutex) { KeReleaseMutant( &StreamFileCreationMutex, IO_NO_INCREMENT, FALSE, FALSE ); } DebugTrace( -1, Dbg2, ("NtfsCreateInternalAttributeStream -> VOID\n") ); } } return; }
BOOLEAN NtfsDeleteInternalAttributeStream ( IN PSCB Scb, IN ULONG ForceClose, IN ULONG CompressedStreamOnly ) /*++ Routine Description: This routine is the inverse of NtfsCreateInternalAttributeStream. It uninitializes the cache map and dereferences the stream file object. It is coded defensively, in case the stream file object does not exist or the cache map has not been initialized. Arguments: Scb - Supplies the Scb for which the stream file is to be deleted. ForceClose - Indicates if we to immediately close everything down or if we are willing to let Mm slowly migrate things out. CompressedStreamOnly - Indicates if we only want to delete the compressed stream. Return Value: BOOLEAN - TRUE if we dereference a file object, FALSE otherwise. --*/ { PFILE_OBJECT FileObject; #ifdef COMPRESS_ON_WIRE PFILE_OBJECT FileObjectC; #endif BOOLEAN Dereferenced = FALSE; PAGED_CODE(); // // We normally already have the paging Io resource. If we do // not, then it is typically some cleanup path of create or // whatever. This code assumes that if we cannot get the paging // Io resource, then there is other activity still going on, // and it is ok to not delete the stream! For example, it could // be the lazy writer, who definitely needs the stream. // if ( #ifdef COMPRESS_ON_WIRE ((Scb->FileObject != NULL) || (Scb->Header.FileObjectC != NULL)) && #else (Scb->FileObject != NULL) && #endif ((Scb->Header.PagingIoResource == NULL) || ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, FALSE ))) { KeWaitForSingleObject( &StreamFileCreationMutex, Executive, KernelMode, FALSE, NULL ); // // Capture both file objects and clear the fields so no one else // can access them. // if (CompressedStreamOnly) { FileObject = NULL; } else { FileObject = Scb->FileObject; Scb->FileObject = NULL; // // Clear the internal file name constant // NtfsClearInternalFilename( FileObject ); } #ifdef COMPRESS_ON_WIRE FileObjectC = Scb->Header.FileObjectC; Scb->Header.FileObjectC = NULL; #endif KeReleaseMutant( &StreamFileCreationMutex, IO_NO_INCREMENT, FALSE, FALSE ); if (Scb->Header.PagingIoResource != NULL) { ExReleaseResourceLite( Scb->Header.PagingIoResource ); } // // Now dereference each file object. // if (FileObject != NULL) { // // We shouldn't be deleting the internal stream objects of the MFT & co, unless // we are in the dismounting, restarting or mounting path. // ASSERT( (((PSCB) FileObject->FsContext)->Header.NodeTypeCode != NTFS_NTC_SCB_MFT) || FlagOn( Scb->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ) || FlagOn( Scb->Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) || !FlagOn( Scb->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) || Scb->Vcb->RootIndexScb == NULL ); if (FileObject->PrivateCacheMap != NULL) { CcUninitializeCacheMap( FileObject, (ForceClose ? &Li0 : NULL), NULL ); } ObDereferenceObject( FileObject ); Dereferenced = TRUE; } #ifdef COMPRESS_ON_WIRE if (FileObjectC != NULL) { if (FileObjectC->PrivateCacheMap != NULL) { CcUninitializeCacheMap( FileObjectC, (ForceClose ? &Li0 : NULL), NULL ); } // // For the compressed stream, deallocate the additional // section object pointers. // ObDereferenceObject( FileObjectC ); Dereferenced = TRUE; } #endif } return Dereferenced; }
NTSTATUS FatCommonClose ( IN PVCB Vcb, IN PFCB Fcb, IN PCCB Ccb, IN TYPE_OF_OPEN TypeOfOpen, IN BOOLEAN Wait, IN BOOLEAN TopLevel, OUT PBOOLEAN VcbDeleted OPTIONAL ) /*++ Routine Description: This is the common routine for closing a file/directory called by both the fsd and fsp threads. Close is invoked whenever the last reference to a file object is deleted. Cleanup is invoked when the last handle to a file object is closed, and is called before close. The function of close is to completely tear down and remove the fcb/dcb/ccb structures associated with the file object. Arguments: Fcb - Supplies the file to process. Wait - If this is TRUE we are allowed to block for the Vcb, if FALSE then we must try to acquire the Vcb anyway. TopLevel - If this is TRUE this is a top level request. VcbDeleted - Returns whether the VCB was deleted by this call. Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_SUCCESS; PDCB ParentDcb; BOOLEAN RecursiveClose; BOOLEAN LocalVcbDeleted; IRP_CONTEXT IrpContext; PAGED_CODE(); DebugTrace(+1, Dbg, "FatCommonClose...\n", 0); // // Initailize the callers variable, if needed. // LocalVcbDeleted = FALSE; if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } // // Special case the unopened file object // if (TypeOfOpen == UnopenedFileObject) { DebugTrace(0, Dbg, "Close unopened file object\n", 0); Status = STATUS_SUCCESS; DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); return Status; } // // Set up our stack IrpContext. // RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT; IrpContext.NodeByteSize = sizeof( IrpContext ); IrpContext.MajorFunction = IRP_MJ_CLOSE; IrpContext.Vcb = Vcb; if (Wait) { SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); } // // Acquire exclusive access to the Vcb and enqueue the irp if we didn't // get access. // #pragma prefast( suppress: 28137, "prefast wants Wait to be a constant, but that's not possible for fastfat" ) if (!ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait )) { return STATUS_PENDING; } // // The following test makes sure that we don't blow away an Fcb if we // are trying to do a Supersede/Overwrite open above us. This test // does not apply for the EA file. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) && Vcb->EaFcb != Fcb) { ExReleaseResourceLite( &Vcb->Resource ); return STATUS_PENDING; } // // Setting the following flag prevents recursive closes of directory file // objects, which are handled in a special case loop. // if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS) ) { RecursiveClose = TRUE; } else { SetFlag(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS); RecursiveClose = FALSE; // // Since we are at the top of the close chain, we need to add // a reference to the VCB. This will keep it from going away // on us until we are ready to check for a dismount below. // Vcb->OpenFileCount += 1; } try { // // Case on the type of open that we are trying to close. // switch (TypeOfOpen) { case VirtualVolumeFile: DebugTrace(0, Dbg, "Close VirtualVolumeFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) ); InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case UserVolumeOpen: DebugTrace(0, Dbg, "Close UserVolumeOpen\n", 0); Vcb->DirectAccessOpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); try_return( Status = STATUS_SUCCESS ); break; case EaFile: DebugTrace(0, Dbg, "Close EaFile\n", 0); // // Remove this internal, residual open from the count. // InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) ); InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) ); try_return( Status = STATUS_SUCCESS ); break; case DirectoryFile: DebugTrace(0, Dbg, "Close DirectoryFile\n", 0); InterlockedDecrement( (LONG*)&Fcb->Specific.Dcb.DirectoryFileOpenCount ); // // Remove this internal open from the count. // InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) ); // // If this is the root directory, it is a residual open // as well. // if (NodeType( Fcb ) == FAT_NTC_ROOT_DCB) { InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) ); } // // If this is a recursive close, just return here. // if ( RecursiveClose ) { try_return( Status = STATUS_SUCCESS ); } else { break; } case UserDirectoryOpen: case UserFileOpen: DebugTrace(0, Dbg, "Close UserFileOpen/UserDirectoryOpen\n", 0); // // Uninitialize the cache map if we no longer need to use it // if ((NodeType(Fcb) == FAT_NTC_DCB) && IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) && (Fcb->OpenCount == 1) && (Fcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject = Fcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize the stream file object\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); // // Dereference the directory file. This may cause a close // Irp to be processed, so we need to do this before we destory // the Fcb. // Fcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); } Fcb->OpenCount -= 1; Vcb->OpenFileCount -= 1; if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; } FatDeleteCcb( &IrpContext, &Ccb ); break; default: #pragma prefast( suppress: 28159, "if the type of open is unknown, we seriously messed up." ) FatBugCheck( TypeOfOpen, 0, 0 ); } // // At this point we've cleaned up any on-disk structure that needs // to be done, and we can now update the in-memory structures. // Now if this is an unreferenced FCB or if it is // an unreferenced DCB (not the root) then we can remove // the fcb and set our ParentDcb to non null. // if (((NodeType(Fcb) == FAT_NTC_FCB) && (Fcb->OpenCount == 0)) || ((NodeType(Fcb) == FAT_NTC_DCB) && (IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) && (Fcb->OpenCount == 0) && (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0))) { ParentDcb = Fcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &Fcb ); // // Uninitialize our parent's cache map if we no longer need // to use it. // while ((NodeType(ParentDcb) == FAT_NTC_DCB) && IsListEmpty(&ParentDcb->Specific.Dcb.ParentDcbQueue) && (ParentDcb->OpenCount == 0) && (ParentDcb->Specific.Dcb.DirectoryFile != NULL)) { PFILE_OBJECT DirectoryFileObject; DirectoryFileObject = ParentDcb->Specific.Dcb.DirectoryFile; DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0); CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); ParentDcb->Specific.Dcb.DirectoryFile = NULL; ObDereferenceObject( DirectoryFileObject ); // // Now, if the ObDereferenceObject() caused the final close // to come in, then blow away the Fcb and continue up, // otherwise wait for Mm to to dereference its file objects // and stop here.. // if ( ParentDcb->Specific.Dcb.DirectoryFileOpenCount == 0) { PDCB CurrentDcb; CurrentDcb = ParentDcb; ParentDcb = CurrentDcb->ParentDcb; SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); FatDeleteFcb( &IrpContext, &CurrentDcb ); } else { break; } } } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { DebugUnwind( FatCommonClose ); // // We are done processing the close. If we are the top of the close // chain, see if the VCB can go away. We have biased the open count by // one, so we need to take that into account. // if (!RecursiveClose) { // // See if there is only one open left. If so, it is ours. We only want // to check for a dismount if a dismount is not already in progress. // We also only do this if the Vcb condition is not VcbGood and the // caller can handle the VCB going away. This is determined by whether // they passed in the VcbDeleted argument. This request also needs // to be top level. // if (Vcb->OpenFileCount == 1 && Vcb->VcbCondition != VcbGood && !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) && ARGUMENT_PRESENT( VcbDeleted ) && TopLevel) { // // We need the global lock, which must be acquired before the // VCB. Since we already have the VCB, we have to drop and // reaquire here. Note that we always want to wait from this // point on. Note that the VCB cannot go away, since we have // biased the open file count. // FatReleaseVcb( &IrpContext, Vcb ); SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); #pragma prefast( suppress: 28137, "prefast wants the wait parameter in this macro expansion to be a constant, unfortunately this is not possible" ) FatAcquireExclusiveGlobal( &IrpContext ); FatAcquireExclusiveVcb( &IrpContext, Vcb ); // // We have our locks in the correct order. Remove our // extra open and check for a dismount. Note that if // something changed while we dropped the lock, it will // not matter, since the dismount code does the correct // checks to make sure the volume can really go away. // Vcb->OpenFileCount -= 1; LocalVcbDeleted = FatCheckForDismount( &IrpContext, Vcb, FALSE ); FatReleaseGlobal( &IrpContext ); // // Let the caller know what happened, if they want this information. // if (ARGUMENT_PRESENT( VcbDeleted )) { *VcbDeleted = LocalVcbDeleted; } } else { // // The volume cannot go away now. Just remove our extra reference. // Vcb->OpenFileCount -= 1; } // // If the VCB is still around, clear our recursion flag. // if (!LocalVcbDeleted) { ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS ); } } // // Only release the VCB if it did not go away. // if (!LocalVcbDeleted) { FatReleaseVcb( &IrpContext, Vcb ); } DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status); } return Status; }
/************************************************************************* * * Function: UDFCommonCleanup() * * Description: * The actual work is performed here. This routine may be invoked in one' * of the two possible contexts: * (a) in the context of a system worker thread * (b) in the context of the original caller * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: Does not matter! * *************************************************************************/ NTSTATUS UDFCommonCleanup( PtrUDFIrpContext PtrIrpContext, PIRP Irp) { IO_STATUS_BLOCK IoStatus; NTSTATUS RC = STATUS_SUCCESS; NTSTATUS RC2; PIO_STACK_LOCATION IrpSp = NULL; PFILE_OBJECT FileObject = NULL; PtrUDFFCB Fcb = NULL; PtrUDFCCB Ccb = NULL; PVCB Vcb = NULL; PtrUDFNTRequiredFCB NtReqFcb = NULL; ULONG lc = 0; BOOLEAN AcquiredVcb = FALSE; BOOLEAN AcquiredFCB = FALSE; BOOLEAN AcquiredParentFCB = FALSE; // BOOLEAN CompleteIrp = TRUE; // BOOLEAN PostRequest = FALSE; BOOLEAN ChangeTime = FALSE; #ifdef UDF_DBG BOOLEAN CanWait = FALSE; #endif // UDF_DBG BOOLEAN ForcedCleanUp = FALSE; PUDF_FILE_INFO NextFileInfo = NULL; #ifdef UDF_DBG UNICODE_STRING CurName; PDIR_INDEX_HDR DirNdx; #endif // UDF_DBG // PUDF_DATALOC_INFO Dloc; TmPrint(("UDFCommonCleanup\n")); // BrutePoint(); _SEH2_TRY { // First, get a pointer to the current I/O stack location IrpSp = IoGetCurrentIrpStackLocation(Irp); if(!IrpSp) try_return(RC = STATUS_INVALID_PARAMETER); FileObject = IrpSp->FileObject; // Get the FCB and CCB pointers Ccb = (PtrUDFCCB)(FileObject->FsContext2); ASSERT(Ccb); Fcb = Ccb->Fcb; ASSERT(Fcb); Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ASSERT(Vcb); ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; #ifdef UDF_DBG CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; AdPrint((" %s\n", CanWait ? "Wt" : "nw")); ASSERT(CanWait); #endif // UDF_DBG UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; // Steps we shall take at this point are: // (a) Acquire the file (FCB) exclusively // (b) Flush file data to disk // (c) Talk to the FSRTL package (if we use it) about pending oplocks. // (d) Notify the FSRTL package for use with pending notification IRPs // (e) Unlock byte-range locks (if any were acquired by process) // (f) Update time stamp values (e.g. fast-IO had been performed) // (g) Inform the Cache Manager to uninitialize Cache Maps ... // and other similar stuff. // BrutePoint(); NtReqFcb = Fcb->NTRequiredFCB; if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { AdPrint(("Cleaning up Volume\n")); AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount)); UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount)); UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount)); if(FileObject->Flags & FO_CACHE_SUPPORTED) { // we've cached close UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount)); } ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1)); // If this handle had write access, and actually wrote something, // flush the device buffers, and then set the verify bit now // just to be safe (in case there is no dismount). if( FileObject->WriteAccess && (FileObject->Flags & FO_FILE_MODIFIED)) { Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME; } // User may decide to close locked volume without call to unlock proc // So, handle this situation properly & unlock it now... if (FileObject == Vcb->VolumeLockFileObject) { Vcb->VolumeLockFileObject = NULL; Vcb->VolumeLockPID = -1; Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; Vcb->Vpb->Flags &= ~VPB_LOCKED; UDFNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); } MmPrint((" CcUninitializeCacheMap()\n")); CcUninitializeCacheMap(FileObject, NULL, NULL); // reset device if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) && (Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) { // this call doesn't modify data buffer // it just requires its presence UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE); } // We must clean up the share access at this time, since we may not // get a Close call for awhile if the file was mapped through this // File Object. IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) ); try_return(RC = STATUS_SUCCESS); } // BrutePoint(); #ifdef UDF_DBG DirNdx = UDFGetDirIndexByFileInfo(Fcb->FileInfo); if(DirNdx) { CurName.Buffer = UDFDirIndex(DirNdx, Fcb->FileInfo->Index)->FName.Buffer; if(CurName.Buffer) { AdPrint(("Cleaning up file: %ws %8.8x\n", CurName.Buffer, FileObject)); } else { AdPrint(("Cleaning up file: ??? \n")); } } #endif //UDF_DBG AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount)); // Acquire parent object if(Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); UDFAcquireResourceExclusive(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource),TRUE); } else { UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); } AcquiredParentFCB = TRUE; // Acquire current object UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); AcquiredFCB = TRUE; // dereference object UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount)); UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount)); if(FileObject->Flags & FO_CACHE_SUPPORTED) { // we've cached close UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount)); } ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1)); // check if Ccb being cleaned up has DeleteOnClose flag set #ifndef UDF_READ_ONLY_BUILD if(Ccb->CCBFlags & UDF_CCB_DELETE_ON_CLOSE) { AdPrint((" DeleteOnClose\n")); // Ok, now we'll become 'delete on close'... ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; FileObject->DeletePending = TRUE; // Report this to the dir notify package for a directory. if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } } #endif //UDF_READ_ONLY_BUILD if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { // Unlock all outstanding file locks. FsRtlFastUnlockAll(&(NtReqFcb->FileLock), FileObject, IoGetRequestorProcess(Irp), NULL); } // get Link count lc = UDFGetFileLinkCount(Fcb->FileInfo); #ifndef UDF_READ_ONLY_BUILD if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) && !(Fcb->OpenHandleCount)) { // This can be useful for Streams, those were brutally deleted // (together with parent object) ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); FileObject->DeletePending = TRUE; // we should mark all streams of the file being deleted // for deletion too, if there are no more Links to // main data stream if((lc <= 1) && !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) { RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete } // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE // flag is already set & the file can't be opened UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); UDFReleaseResource(&(NtReqFcb->MainResource)); AcquiredFCB = FALSE; if(Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource)); } else { UDFReleaseResource(&(Vcb->VCBResource)); } AcquiredParentFCB = FALSE; UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE; // Make system to issue last Close request // for our Target ... UDFRemoveFromSystemDelayedQueue(Fcb); #ifdef UDF_DELAYED_CLOSE // remove file from our DelayedClose queue UDFRemoveFromDelayedQueue(Fcb); ASSERT(!Fcb->IrpContextLite); #endif //UDF_DELAYED_CLOSE UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; if(Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE); } else { UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); } AcquiredParentFCB = TRUE; UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); AcquiredFCB = TRUE; // we should set file sizes to zero if there are no more // links to this file if(lc <= 1) { // Synchronize here with paging IO UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource),TRUE); // set file size to zero (for system cache manager) // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NtReqFcb->CommonFCBHeader.FileSize.QuadPart = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0; CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); UDFReleaseResource(&(NtReqFcb->PagingIoResource)); } } #endif //UDF_READ_ONLY_BUILD #ifdef UDF_DELAYED_CLOSE if ((Fcb->ReferenceCount == 1) && /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above (!(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)) ) { Fcb->FCBFlags |= UDF_FCB_DELAY_CLOSE; } #endif //UDF_DELAYED_CLOSE NextFileInfo = Fcb->FileInfo; #ifndef UDF_READ_ONLY_BUILD // do we need to delete it now ? if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) && !(Fcb->OpenHandleCount)) { // can we do it ? if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); if(!UDFIsDirEmpty__(NextFileInfo)) { // forget about it Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; goto DiscardDelete; } } else if (lc <= 1) { // Synchronize here with paging IO BOOLEAN AcquiredPagingIo; AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb->PagingIoResource)); // set file size to zero (for UdfInfo package) // we should not do this for directories and linked files UDFResizeFile__(Vcb, NextFileInfo, 0); if(AcquiredPagingIo) { UDFReleaseResource(&(NtReqFcb->PagingIoResource)); } } // mark parent object for deletion if requested if((Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) && Fcb->ParentFcb) { ASSERT(!(Fcb->ParentFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); Fcb->ParentFcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; } // flush file. It is required by UDFUnlinkFile__() RC = UDFFlushFile__(Vcb, NextFileInfo); if(!NT_SUCCESS(RC)) { AdPrint(("Error flushing file !!!\n")); } // try to unlink if((RC = UDFUnlinkFile__(Vcb, NextFileInfo, TRUE)) == STATUS_CANNOT_DELETE) { // If we can't delete file with Streams due to references, // mark SDir & Streams // for Deletion. We shall also set DELETE_PARENT flag to // force Deletion of the current file later... when curently // opened Streams would be cleaned up. // WARNING! We should keep SDir & Streams if there is a // link to this file if(NextFileInfo->Dloc && NextFileInfo->Dloc->SDirInfo && NextFileInfo->Dloc->SDirInfo->Fcb) { BrutePoint(); if(!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) { // RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete //#ifdef UDF_ALLOW_PRETEND_DELETED UDFPretendFileDeleted__(Vcb, Fcb->FileInfo); //#endif //UDF_ALLOW_PRETEND_DELETED } goto NotifyDelete; } else { // Getting here means that we can't delete file because of // References/PemissionsDenied/Smth.Else, // but not Linked+OpenedStream BrutePoint(); // RC = STATUS_SUCCESS; goto DiscardDelete_1; } } else { DiscardDelete_1: // We have got an ugly ERROR, or // file is deleted, so forget about it ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); ForcedCleanUp = TRUE; if(NT_SUCCESS(RC)) Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; Fcb->FCBFlags |= UDF_FCB_DELETED; RC = STATUS_SUCCESS; } NotifyDelete: // We should prevent SetEOF operations on completly // deleted data streams if(lc < 1) { NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; } // Report that we have removed an entry. if(UDFIsAStream(NextFileInfo)) { UDFNotifyFullReportChange( Vcb, NextFileInfo, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM); } else { UDFNotifyFullReportChange( Vcb, NextFileInfo, UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED); } } else if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { DiscardDelete: UDFNotifyFullReportChange( Vcb, NextFileInfo, ((Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) | ((Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) | 0, UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED); } #endif //UDF_READ_ONLY_BUILD if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { // Report to the dir notify package for a directory. FsRtlNotifyCleanup( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb ); } // we can't purge Cache when more than one link exists if(lc > 1) { ForcedCleanUp = FALSE; } if ( (FileObject->Flags & FO_CACHE_SUPPORTED) && (NtReqFcb->SectionObject.DataSectionObject) ) { BOOLEAN LastNonCached = (!Fcb->CachedOpenHandleCount && Fcb->OpenHandleCount); // If this was the last cached open, and there are open // non-cached handles, attempt a flush and purge operation // to avoid cache coherency overhead from these non-cached // handles later. We ignore any I/O errors from the flush. // We shall not flush deleted files RC = STATUS_SUCCESS; if( LastNonCached || (!Fcb->OpenHandleCount && !ForcedCleanUp) ) { #ifndef UDF_READ_ONLY_BUILD LONGLONG OldFileSize, NewFileSize; if( (OldFileSize = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) < (NewFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) { /* UDFZeroDataEx(NtReqFcb, OldFileSize, NewFileSize - OldFileSize, TRUE, Vcb, FileObject);*/ NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileSize; } #endif //UDF_READ_ONLY_BUILD MmPrint((" CcFlushCache()\n")); CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, &IoStatus ); if(!NT_SUCCESS(IoStatus.Status)) { MmPrint((" CcFlushCache() error: %x\n", IoStatus.Status)); RC = IoStatus.Status; } } // If file is deleted or it is last cached open, but there are // some non-cached handles we should purge cache section if(ForcedCleanUp || LastNonCached) { if(NtReqFcb->SectionObject.DataSectionObject) { MmPrint((" CcPurgeCacheSection()\n")); CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); } /* MmPrint((" CcPurgeCacheSection()\n")); CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/ } // we needn't Flush here. It will be done in UDFCloseFileInfoChain() } #ifndef UDF_READ_ONLY_BUILD // Update FileTimes & Attrs if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && !(Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | UDF_FCB_DELETED /*| UDF_FCB_DIRECTORY | UDF_FCB_READ_ONLY*/)) && !UDFIsAStreamDir(NextFileInfo)) { LONGLONG NtTime; LONGLONG ASize; KeQuerySystemTime((PLARGE_INTEGER)&NtTime); // Check if we should set ARCHIVE bit & LastWriteTime if(FileObject->Flags & FO_FILE_MODIFIED) { ULONG Attr; PDIR_INDEX_ITEM DirNdx; DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index); ASSERT(DirNdx); // Archive bit if(!(Ccb->CCBFlags & UDF_CCB_ATTRIBUTES_SET) && (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) { Attr = UDFAttributesToNT(DirNdx, NextFileInfo->Dloc->FileEntry); if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) UDFAttributesToUDF(DirNdx, NextFileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); } // WriteTime if(!(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) && (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME)) { UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, &NtTime); NtReqFcb->LastWriteTime.QuadPart = NtReqFcb->LastAccessTime.QuadPart = NtTime; ChangeTime = TRUE; } } if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { // Update sizes in DirIndex if(!Fcb->OpenHandleCount) { ASize = UDFGetFileAllocationSize(Vcb, NextFileInfo); // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); } else if(FileObject->Flags & FO_FILE_SIZE_CHANGED) { ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo); NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); } } // AccessTime if((FileObject->Flags & FO_FILE_FAST_IO_READ) && !(Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) && (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ACCESS_TIME)) { UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, NULL); NtReqFcb->LastAccessTime.QuadPart = NtTime; // ChangeTime = TRUE; } // ChangeTime (AttrTime) if(!(Ccb->CCBFlags & UDF_CCB_MODIFY_TIME_SET) && (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ATTR_TIME) && (ChangeTime || (Ccb->CCBFlags & (UDF_CCB_ATTRIBUTES_SET | UDF_CCB_CREATE_TIME_SET | UDF_CCB_ACCESS_TIME_SET | UDF_CCB_WRITE_TIME_SET))) ) { UDFSetFileXTime(NextFileInfo, NULL, NULL, &NtTime, NULL); NtReqFcb->ChangeTime.QuadPart = NtTime; } } #endif //UDF_READ_ONLY_BUILD if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY) && ForcedCleanUp) { // flush system cache MmPrint((" CcUninitializeCacheMap()\n")); CcUninitializeCacheMap(FileObject, &(UDFGlobalData.UDFLargeZero), NULL); } else { MmPrint((" CcUninitializeCacheMap()\n")); CcUninitializeCacheMap(FileObject, NULL, NULL); } // release resources now. // they'll be acquired in UDFCloseFileInfoChain() UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); UDFReleaseResource(&(NtReqFcb->MainResource)); AcquiredFCB = FALSE; if(Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource)); } else { UDFReleaseResource(&(Vcb->VCBResource)); } AcquiredParentFCB = FALSE; // close the chain ASSERT(AcquiredVcb); RC2 = UDFCloseFileInfoChain(Vcb, NextFileInfo, Ccb->TreeLength, TRUE); if(NT_SUCCESS(RC)) RC = RC2; Ccb->CCBFlags |= UDF_CCB_CLEANED; // We must clean up the share access at this time, since we may not // get a Close call for awhile if the file was mapped through this // File Object. IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) ); NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); FileObject->Flags |= FO_CLEANUP_COMPLETE; try_exit: NOTHING; } _SEH2_FINALLY { if(AcquiredFCB) { UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); UDFReleaseResource(&(NtReqFcb->MainResource)); } if(AcquiredParentFCB) { if(Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB); UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource)); } else { UDFReleaseResource(&(Vcb->VCBResource)); } } if(AcquiredVcb) { UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE; } if (!_SEH2_AbnormalTermination()) { // complete the IRP Irp->IoStatus.Status = RC; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_DISK_INCREMENT); // Free up the Irp Context UDFReleaseIrpContext(PtrIrpContext); } } _SEH2_END; // end of "__finally" processing return(RC); } // end UDFCommonCleanup()
NTSTATUS CdCommonCleanup ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for cleanup of a file/directory called by both the fsd and fsp threads. Cleanup is invoked whenever the last handle to a file object is closed. This is different than the Close operation which is invoked when the last reference to a file object is deleted. The function of cleanup is to essentially "cleanup" the file/directory after a user is done with it. The Fcb/Dcb remains around (because MM still has the file object referenced) but is now available for another user to open (i.e., as far as the user is concerned the is now closed). See close for a more complete description of what close does. We do no synchronization in this routine until we get to the point where we modify the counts, share access and volume lock field. We need to update the Fcb and Vcb to show that a user handle has been closed. The following structures and fields are affected. Vcb: VolumeLockFileObject - Did the user lock the volume with this file object. VcbState - Check if we are unlocking the volume here. VcbCleanup - Count of outstanding handles on the volume. DirNotifyQueue - If this file object has pending DirNotify Irps. Fcb: ShareAccess - If this is a user handle. FcbCleanup - Count of outstanding handles on this Fcb. Oplock - Any outstanding oplocks on this file object. FileLock - Any outstanding filelocks on this file object. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation. --*/ { PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; BOOLEAN SendUnlockNotification = FALSE; BOOLEAN AttemptTeardown; PVCB Vcb; PFCB Fcb; PCCB Ccb; KIRQL SavedIrql; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_IRP( Irp ); // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS. // if (IrpContext->Vcb == NULL) { CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } // // Get the file object out of the Irp and decode the type of open. // FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject; TypeOfOpen = CdDecodeFileObject( IrpContext, FileObject, &Fcb, &Ccb ); // // No work here for either an UnopenedFile object or a StreamFileObject. // if (TypeOfOpen <= StreamFileOpen) { CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; } // // Keep a local pointer to the Vcb. // Vcb = Fcb->Vcb; // // Synchronise with reads while we set the cleanup complete // flag on this fileobject. Once this flag is set, any further // reads will be rejected (CdVerifyFcbOperation) // CdAcquireFileExclusive( IrpContext, Fcb); // // Set the flag in the FileObject to indicate that cleanup is complete. // SetFlag( FileObject->Flags, FO_CLEANUP_COMPLETE ); CdReleaseFile( IrpContext, Fcb); // // Acquire the current file. // CdAcquireFcbExclusive( IrpContext, Fcb, FALSE ); // // Use a try-finally to facilitate cleanup. // try { // // Case on the type of open that we are trying to cleanup. // switch (TypeOfOpen) { case UserDirectoryOpen: // // Check if we need to complete any dir notify Irps on this file object. // FsRtlNotifyCleanup( Vcb->NotifySync, &Vcb->DirNotifyList, Ccb ); break; case UserFileOpen: // // Coordinate the cleanup operation with the oplock state. // Oplock cleanup operations can always cleanup immediately so no // need to check for STATUS_PENDING. // FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, NULL, NULL ); // // Unlock all outstanding file locks. // if (Fcb->FileLock != NULL) { FsRtlFastUnlockAll( Fcb->FileLock, FileObject, IoGetRequestorProcess( Irp ), NULL ); } // // Cleanup the cache map. // CcUninitializeCacheMap( FileObject, NULL, NULL ); // // Check the fast io state. // CdLockFcb( IrpContext, Fcb ); Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb ); CdUnlockFcb( IrpContext, Fcb ); break; case UserVolumeOpen : break; default : CdBugCheck( TypeOfOpen, 0, 0 ); } // // Now lock the Vcb in order to modify the fields in the in-memory // structures. // CdLockVcb( IrpContext, Vcb ); // // Decrement the cleanup counts in the Vcb and Fcb. // CdDecrementCleanupCounts( IrpContext, Fcb ); // // If the cleanup count hit zero and the volume is not mounted, we // will want to try to spark teardown. // AttemptTeardown = (Vcb->VcbCleanup == 0 && Vcb->VcbCondition == VcbNotMounted); // // If this file object has locked the volume then perform the unlock operation. // We do this regardless of explicit or implicit (no share DASD open) lock. // if (FileObject == Vcb->VolumeLockFileObject) { ASSERT( FlagOn( Vcb->VcbState, VCB_STATE_LOCKED)); IoAcquireVpbSpinLock( &SavedIrql ); ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED); ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED ); Vcb->VolumeLockFileObject = NULL; SendUnlockNotification = TRUE; IoReleaseVpbSpinLock( SavedIrql ); } CdUnlockVcb( IrpContext, Vcb ); // // We must clean up the share access at this time, since we may not // get a Close call for awhile if the file was mapped through this // File Object. // IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); } finally { CdReleaseFcb( IrpContext, Fcb ); if (SendUnlockNotification) { FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK ); } } // // If appropriate, try to spark teardown by purging the volume. Should // this very fileobject we were cleaning up be the last reason for the // volume to remain, teardown will commence on completion of this Irp. // if (AttemptTeardown) { CdAcquireVcbExclusive( IrpContext, Vcb, FALSE ); try { CdPurgeVolume( IrpContext, Vcb, FALSE ); } finally { CdReleaseVcb( IrpContext, Vcb ); } } // // If this is a normal termination then complete the request // CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS ); return STATUS_SUCCESS; }
NTSTATUS Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_SUCCESS; PEXT2_VCB Vcb; PFILE_OBJECT FileObject; PEXT2_FCB Fcb; PEXT2_CCB Ccb; PIRP Irp; PEXT2_MCB Mcb; BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoResourceAcquired = FALSE; __try { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_SUCCESS; __leave; } Irp = IrpContext->Irp; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); if (!IsVcbInited(Vcb)) { Status = STATUS_SUCCESS; __leave; } FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; if (!Fcb || (Fcb->Identifier.Type != EXT2VCB && Fcb->Identifier.Type != EXT2FCB)) { Status = STATUS_SUCCESS; __leave; } Mcb = Fcb->Mcb; Ccb = (PEXT2_CCB) FileObject->FsContext2; if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { Status = STATUS_SUCCESS; __leave; } VcbResourceAcquired = ExAcquireResourceExclusiveLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (Fcb->Identifier.Type == EXT2VCB) { if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) && (Vcb->LockFile == FileObject) ) { ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = NULL; Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED); } if (Ccb) { Ext2DerefXcb(&Vcb->OpenHandleCount); Ext2DerefXcb(&Vcb->OpenVolumeCount); } IoRemoveShareAccess(FileObject, &Vcb->ShareAccess); Status = STATUS_SUCCESS; __leave; } ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) { if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) { Status = Ext2FlushFile(IrpContext, Fcb, Ccb); } __leave; } if (Ccb == NULL) { Status = STATUS_SUCCESS; __leave; } if (IsDirectory(Fcb)) { if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, Ccb, NULL, FALSE, FALSE, 0, NULL, NULL, NULL ); } FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb); } ExReleaseResourceLite(&Vcb->MainResource); VcbResourceAcquired = FALSE; FcbResourceAcquired = ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); ASSERT((Ccb->Identifier.Type == EXT2CCB) && (Ccb->Identifier.Size == sizeof(EXT2_CCB))); Ext2DerefXcb(&Vcb->OpenHandleCount); Ext2DerefXcb(&Fcb->OpenHandleCount); if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE; } if (IsDirectory(Fcb)) { ext3_release_dir(Fcb->Inode, &Ccb->filp); } else { if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) && !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) { LARGE_INTEGER SysTime; KeQuerySystemTime(&SysTime); Fcb->Inode->i_atime = Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime); Fcb->Mcb->LastAccessTime = Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime); Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); Ext2NotifyReportChange( IrpContext, Vcb, Fcb->Mcb, FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS, FILE_ACTION_MODIFIED ); } FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, NULL, NULL ); Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { Fcb->NonCachedOpenCount--; } if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); } // // Drop any byte range locks this process may have on the file. // FsRtlFastUnlockAll( &Fcb->FileLockAnchor, FileObject, IoGetRequestorProcess(Irp), NULL ); // // If there are no byte range locks owned by other processes on the // file the fast I/O read/write functions doesn't have to check for // locks so we set IsFastIoPossible to FastIoIsPossible again. // if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) { if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) { #if EXT2_DEBUG DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n", Ext2GetCurrentProcessName(), "FastIoIsPossible", &Fcb->Mcb->FullName )); #endif Fcb->Header.IsFastIoPossible = FastIoIsPossible; } } if (Fcb->OpenHandleCount == 0 && (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE) || IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) ) { LARGE_INTEGER Size; ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE); FcbPagingIoResourceAcquired = TRUE; Size.QuadPart = CEILING_ALIGNED(ULONGLONG, (ULONGLONG)Fcb->Mcb->Inode.i_size, (ULONGLONG)BLOCK_SIZE); if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size); Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart = Fcb->Mcb->Inode.i_size; Fcb->Header.AllocationSize = Size; if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } } ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE); ExReleaseResourceLite(&Fcb->PagingIoResource); FcbPagingIoResourceAcquired = FALSE; } } if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) { // // Ext2DeleteFile will acquire these lock inside // if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); FcbResourceAcquired = FALSE; } // // this file is to be deleted ... // if (Ccb->SymLink) { Mcb = Ccb->SymLink; FileObject->DeletePending = FALSE; } Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); if (NT_SUCCESS(Status)) { if (IsMcbDirectory(Mcb)) { Ext2NotifyReportChange( IrpContext, Vcb, Mcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED ); } else { Ext2NotifyReportChange( IrpContext, Vcb, Mcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED ); } } // // re-acquire the main resource lock // FcbResourceAcquired = ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } } if (!IsDirectory(Fcb)) { if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) && (Fcb->SectionObject.DataSectionObject != NULL)) { if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) && !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) { CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL); } if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) { ExReleaseResourceLite(&(Fcb->PagingIoResource)); } CcPurgeCacheSection( &Fcb->SectionObject, NULL, 0, FALSE ); } CcUninitializeCacheMap(FileObject, NULL, NULL); } IoRemoveShareAccess(FileObject, &Fcb->ShareAccess); DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n", Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName)); Status = STATUS_SUCCESS; if (FileObject) { SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); } } __finally { if (FcbPagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } if (VcbResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; Ext2CompleteIrpContext(IrpContext, Status); } } } return Status; }