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); } }
VOID PurgeFile(PLKLFCB fcb, BOOLEAN flush_before_purge) { IO_STATUS_BLOCK iosb; ASSERT(fcb); if (flush_before_purge) CcFlushCache(&fcb->section_object, NULL, 0, &iosb); if (fcb->section_object.ImageSectionObject) MmFlushImageSection(&fcb->section_object, MmFlushForWrite); if (fcb->section_object.DataSectionObject) CcPurgeCacheSection(&fcb->section_object, NULL, 0, FALSE); }
__drv_mustHoldCriticalRegion NTSTATUS FFSPurgeFile( IN PFFS_FCB Fcb, IN BOOLEAN FlushBeforePurge) { IO_STATUS_BLOCK IoStatus; PAGED_CODE(); ASSERT(Fcb != NULL); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); if(!IsFlagOn(Fcb->Vcb->Flags, VCB_READ_ONLY) && FlushBeforePurge && !IsFlagOn(Fcb->Vcb->Flags, VCB_WRITE_PROTECTED)) { FFSPrint((DBG_INFO, "FFSPurgeFile: CcFlushCache on %s.\n", Fcb->AnsiFileName.Buffer)); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus); ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); } if (Fcb->SectionObject.ImageSectionObject) { FFSPrint((DBG_INFO, "FFSPurgeFile: MmFlushImageSection on %s.\n", Fcb->AnsiFileName.Buffer)); MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite); } if (Fcb->SectionObject.DataSectionObject) { FFSPrint((DBG_INFO, "FFSPurgeFile: CcPurgeCacheSection on %s.\n", Fcb->AnsiFileName.Buffer)); CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE); } return STATUS_SUCCESS; }
VOID DokanCompleteSetInformation( __in PIRP_ENTRY IrpEntry, __in PEVENT_INFORMATION EventInfo ) { PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status; ULONG info = 0; PDokanCCB ccb; PDokanFCB fcb; UNICODE_STRING oldFileName; FILE_INFORMATION_CLASS infoClass; __try { DDbgPrint("==> DokanCompleteSetInformation\n"); irp = IrpEntry->Irp; irpSp = IrpEntry->IrpSp; ccb = IrpEntry->FileObject->FsContext2; ASSERT(ccb != NULL); ExAcquireResourceExclusiveLite(&ccb->Resource, TRUE); fcb = ccb->Fcb; ASSERT(fcb != NULL); ccb->UserContext = EventInfo->Context; status = EventInfo->Status; info = EventInfo->BufferLength; infoClass = irpSp->Parameters.SetFile.FileInformationClass; RtlZeroMemory(&oldFileName, sizeof(UNICODE_STRING)); if (NT_SUCCESS(status)) { if (infoClass == FileDispositionInformation) { if (EventInfo->Delete.DeleteOnClose) { if (!MmFlushImageSection( &fcb->SectionObjectPointers, MmFlushForDelete)) { DDbgPrint(" Cannot delete user mapped image\n"); status = STATUS_CANNOT_DELETE; } else { ccb->Flags |= DOKAN_DELETE_ON_CLOSE; fcb->Flags |= DOKAN_DELETE_ON_CLOSE; DDbgPrint(" FileObject->DeletePending = TRUE\n"); IrpEntry->FileObject->DeletePending = TRUE; } } else { ccb->Flags &= ~DOKAN_DELETE_ON_CLOSE; fcb->Flags &= ~DOKAN_DELETE_ON_CLOSE; DDbgPrint(" FileObject->DeletePending = FALSE\n"); IrpEntry->FileObject->DeletePending = FALSE; } } // if rename is executed, reassign the file name if(infoClass == FileRenameInformation) { PVOID buffer = NULL; ExAcquireResourceExclusiveLite(&fcb->Resource, TRUE); // this is used to inform rename in the bellow switch case oldFileName.Buffer = fcb->FileName.Buffer; oldFileName.Length = (USHORT)fcb->FileName.Length; oldFileName.MaximumLength = (USHORT)fcb->FileName.Length; // copy new file name buffer = ExAllocatePool(EventInfo->BufferLength+sizeof(WCHAR)); if (buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; ExReleaseResourceLite(&fcb->Resource); ExReleaseResourceLite(&ccb->Resource); __leave; } fcb->FileName.Buffer = buffer; ASSERT(fcb->FileName.Buffer != NULL); RtlZeroMemory(fcb->FileName.Buffer, EventInfo->BufferLength+sizeof(WCHAR)); RtlCopyMemory(fcb->FileName.Buffer, EventInfo->Buffer, EventInfo->BufferLength); fcb->FileName.Length = (USHORT)EventInfo->BufferLength; fcb->FileName.MaximumLength = (USHORT)EventInfo->BufferLength; ExReleaseResourceLite(&fcb->Resource); } } ExReleaseResourceLite(&ccb->Resource); if (NT_SUCCESS(status)) { switch (irpSp->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); break; case FileBasicInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION, FILE_ACTION_MODIFIED); break; case FileDispositionInformation: if (IrpEntry->FileObject->DeletePending) { if (fcb->Flags & DOKAN_FILE_DIRECTORY) { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED); } else { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED); } } break; case FileEndOfFileInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); break; case FileLinkInformation: // TODO: should check whether this is a directory // TODO: should notify new link name //DokanNotifyReportChange(vcb, ccb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED); break; case FilePositionInformation: // this is never used break; case FileRenameInformation: { DokanNotifyReportChange0(fcb, &oldFileName, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_OLD_NAME); // free old file name ExFreePool(oldFileName.Buffer); DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_NEW_NAME); } break; case FileValidDataLengthInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.SetFile.FileInformationClass); break; } } } __finally { irp->IoStatus.Status = status; irp->IoStatus.Information = info; IoCompleteRequest(irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); DDbgPrint("<== DokanCompleteSetInformation\n"); } }
VOID Secondary_TryCloseFilExts( PSECONDARY Secondary ) { PLIST_ENTRY listEntry; Secondary_Reference( Secondary ); if (ExTryToAcquireFastMutex(&Secondary->RecoveryCcbQMutex) == FALSE) { Secondary_Dereference(Secondary); return; } if (BooleanFlagOn(Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { ExReleaseFastMutex(&Secondary->RecoveryCcbQMutex); Secondary_Dereference(Secondary); return; } listEntry = Secondary->RecoveryCcbQueue.Flink; while (listEntry != &Secondary->RecoveryCcbQueue) { PCCB ccb; PFCB fcb; PSECTION_OBJECT_POINTERS section; BOOLEAN dataSectionExists; BOOLEAN imageSectionExists; IRP_CONTEXT IrpContext; ccb = CONTAINING_RECORD( listEntry, CCB, ListEntry ); listEntry = listEntry->Flink; if (ccb->Fcb == NULL) { ASSERT(NDFAT_BUG); continue; } if (NodeType(ccb->Fcb) != FAT_NTC_FCB) continue; fcb = ccb->Fcb; if (fcb->UncleanCount != 0 || fcb->NonCachedUncleanCount != 0) { DebugTrace2( 0, Dbg, ("Secondary_TryCloseFilExts: fcb->FullFileName = %wZ\n", &ccb->Fcb->FullFileName) ); break; } DebugTrace2( 0, Dbg, ("Secondary_TryCloseFilExts: fcb->FullFileName = %wZ\n", &ccb->Fcb->FullFileName) ); RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) ); SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT ); section = &fcb->NonPaged->SectionObjectPointers; if (section == NULL) break; dataSectionExists = (BOOLEAN)(section->DataSectionObject != NULL); imageSectionExists = (BOOLEAN)(section->ImageSectionObject != NULL); if (imageSectionExists) { (VOID)MmFlushImageSection( section, MmFlushForWrite ); } if (dataSectionExists) { CcPurgeCacheSection( section, NULL, 0, FALSE ); } } ExReleaseFastMutex( &Secondary->RecoveryCcbQMutex ); Secondary_Dereference( Secondary ); return; }
__drv_mustHoldCriticalRegion NTSTATUS RfsdPurgeVolume (IN PRFSD_VCB Vcb, IN BOOLEAN FlushBeforePurge ) { PRFSD_FCB Fcb; LIST_ENTRY FcbList; PLIST_ENTRY ListEntry; PFCB_LIST_ENTRY FcbListEntry; PAGED_CODE(); _SEH2_TRY { ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == RFSDVCB) && (Vcb->Identifier.Size == sizeof(RFSD_VCB))); if ( IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { FlushBeforePurge = FALSE; } FcbListEntry= NULL; InitializeListHead(&FcbList); for (ListEntry = Vcb->FcbList.Flink; ListEntry != &Vcb->FcbList; ListEntry = ListEntry->Flink ) { Fcb = CONTAINING_RECORD(ListEntry, RFSD_FCB, Next); Fcb->ReferenceCount++; RfsdPrint((DBG_INFO, "RfsdPurgeVolume: %s refercount=%xh\n", Fcb->AnsiFileName.Buffer, Fcb->ReferenceCount)); FcbListEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FCB_LIST_ENTRY), RFSD_POOL_TAG); if (FcbListEntry) { FcbListEntry->Fcb = Fcb; InsertTailList(&FcbList, &FcbListEntry->Next); } else { RfsdPrint((DBG_ERROR, "RfsdPurgeVolume: Error allocating FcbListEntry ...\n")); } } while (!IsListEmpty(&FcbList)) { ListEntry = RemoveHeadList(&FcbList); FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next); Fcb = FcbListEntry->Fcb; if (ExAcquireResourceExclusiveLite( &Fcb->MainResource, TRUE )) { RfsdPurgeFile(Fcb, FlushBeforePurge); if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) { RemoveEntryList(&Fcb->Next); RfsdFreeFcb(Fcb); } else { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } } ExFreePool(FcbListEntry); } if (FlushBeforePurge) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); } if (Vcb->SectionObject.ImageSectionObject) { MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite); } if (Vcb->SectionObject.DataSectionObject) { CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE); } RfsdPrint((DBG_INFO, "RfsdPurgeVolume: Volume flushed and purged.\n")); } _SEH2_FINALLY { // Nothing } _SEH2_END; return STATUS_SUCCESS; }
NTSTATUS xixfs_PurgeVolume( IN PXIXFS_IRPCONTEXT IrpContext, IN PXIXFS_VCB pVCB, IN BOOLEAN DismountForce ) { NTSTATUS Status = STATUS_SUCCESS; PVOID RestartKey = NULL; PXIXFS_FCB ThisFcb = NULL; PXIXFS_FCB NextFcb = NULL; BOOLEAN RemovedFcb = FALSE; BOOLEAN CanWait = FALSE; uint32 lockedVcbValue = 0; PAGED_CODE(); DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("Enter xixfs_PurgeVolume\n")); ASSERT_EXCLUSIVE_VCB(pVCB); CanWait = XIXCORE_TEST_FLAGS(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT); // // Force any remaining Fcb's in the delayed close queue to be closed. // xixfs_RealCloseFCB(pVCB); // // Acquire the global file resource. // //XifsdAcquireAllFiles( CanWait, pVCB ); // // Loop through each Fcb in the Fcb Table and perform the flush. // while (TRUE) { // // Lock the Vcb to lookup the next Fcb. // XifsdLockVcb( IrpContext, pVCB ); NextFcb = xixfs_FCBTLBGetNextEntry(pVCB, &RestartKey ); // // Reference the NextFcb if present. // if (NextFcb != NULL) { NextFcb->FCBReference += 1; } // // If the last Fcb is present then decrement reference count and call teardown // to see if it should be removed. // if (ThisFcb != NULL) { ThisFcb->FCBReference -= 1; XifsdUnlockVcb( IrpContext, pVCB ); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_PNP|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO|DEBUG_TARGET_REFCOUNT), ("XifsdPurgeVolume FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->XixcoreFcb.LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_PNP|DEBUG_TARGET_FCB|DEBUG_TARGET_VCB|DEBUG_TARGET_REFCOUNT, ("XifsdPurgeVolume FCBLotNumber(%I64d) FCBCleanUp(%ld) VCBCleanup(%ld)\n", ThisFcb->XixcoreFcb.LotNumber, ThisFcb->FCBCleanup, pVCB->VCBCleanup)); xixfs_TeardownStructures( CanWait, ThisFcb, FALSE, &RemovedFcb ); } else { XifsdUnlockVcb( IrpContext, pVCB ); } // // Break out of the loop if no more Fcb's. // if (NextFcb == NULL) { break; } // // Move to the next Fcb. // ThisFcb = NextFcb; // // If there is a image section then see if that can be closed. // if(ThisFcb->XixcoreFcb.FCBType == FCB_TYPE_FILE){ DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("XifsdPurgeVolume FCB(%I64d) \n", ThisFcb->XixcoreFcb.LotNumber)); XifsdAcquireFcbExclusive(TRUE, ThisFcb, FALSE); // Added by ILGU HONG for readonly 09052006 if(!ThisFcb->PtrVCB->XixcoreVcb.IsVolumeWriteProtected){ if (ThisFcb->SectionObject.ImageSectionObject != NULL) { MmFlushImageSection( &ThisFcb->SectionObject, MmFlushForWrite ); } // // If there is a data section then purge this. If there is an image // section then we won't be able to. Remember this if it is our first // error. // CcFlushCache(&ThisFcb->SectionObject, NULL, 0, NULL); //DbgPrint("CcFlush 3 File(%wZ)\n", &ThisFcb->FCBFullPath); } // Added by ILGU HONG for readonly end ExAcquireResourceSharedLite(ThisFcb->PagingIoResource, TRUE); ExReleaseResourceLite( ThisFcb->PagingIoResource ); if ((ThisFcb->SectionObject.DataSectionObject != NULL) && !CcPurgeCacheSection( &ThisFcb->SectionObject, NULL, 0, FALSE ) && (Status == STATUS_SUCCESS)) { Status = STATUS_UNABLE_TO_DELETE_SECTION; } XifsdReleaseFcb(TRUE, ThisFcb); } // // Dereference the internal stream if dismounting. // if (DismountForce && (ThisFcb->XixcoreFcb.FCBType != FCB_TYPE_FILE) && (ThisFcb->XixcoreFcb.FCBType != FCB_TYPE_DIR) && (ThisFcb->FileObject != NULL)) { xixfs_DeleteInternalStream( CanWait, ThisFcb ); } } // // Now look at the Root Index, Metadata, Volume Dasd and VAT Fcbs. // Note that we usually hit the Root Index in the loop above, but // it is possible miss it if it didn't get into the Fcb table in the // first place! // DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("xixfs_PurgeVolume DismountFore (%s)\n", ((DismountForce)?"TRUE":"FALSE"))); if (DismountForce) { if (pVCB->RootDirFCB != NULL) { DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("Deal with RootFCB \n")); ThisFcb = pVCB->RootDirFCB; InterlockedIncrement( &ThisFcb->FCBReference ); if ((ThisFcb->SectionObject.DataSectionObject != NULL) && !CcPurgeCacheSection( &ThisFcb->SectionObject, NULL, 0, FALSE ) && (Status == STATUS_SUCCESS)) { Status = STATUS_UNABLE_TO_DELETE_SECTION; } InterlockedDecrement( &ThisFcb->FCBReference ); /* DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("pVCB->RootDirFCB FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); XifsdLockVcb(IrpContext, pVCB); XifsdDecRefCount(ThisFcb, 1, 1); XifsdUnlockVcb(IrpContext, pVCB); */ DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("pVCB->RootDirFCB FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->XixcoreFcb.LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); xixfs_TeardownStructures( CanWait, ThisFcb, FALSE, &RemovedFcb ); } if (pVCB->MetaFCB != NULL) { DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("Deal with pVCB->MetaFCB \n")); ThisFcb = pVCB->MetaFCB; InterlockedIncrement( &ThisFcb->FCBReference ); if ((ThisFcb->SectionObject.DataSectionObject != NULL) && !CcPurgeCacheSection( &ThisFcb->SectionObject, NULL, 0, FALSE ) && (Status == STATUS_SUCCESS)) { Status = STATUS_UNABLE_TO_DELETE_SECTION; } xixfs_DeleteInternalStream( CanWait, ThisFcb ); InterlockedDecrement( &ThisFcb->FCBReference ); /* DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("pVCB->MetaFCB FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); XifsdLockVcb(IrpContext, pVCB); XifsdDecRefCount(ThisFcb, 1, 1); XifsdUnlockVcb(IrpContext, pVCB); */ DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("pVCB->MetaFCB FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->XixcoreFcb.LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); xixfs_TeardownStructures( CanWait, ThisFcb, FALSE, &RemovedFcb ); } if (pVCB->VolumeDasdFCB != NULL) { DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("Deal with pVCB->VolumeDasdFCB \n")); ThisFcb = pVCB->VolumeDasdFCB; InterlockedIncrement( &ThisFcb->FCBReference ); if ((ThisFcb->SectionObject.DataSectionObject != NULL) && !CcPurgeCacheSection( &ThisFcb->SectionObject, NULL, 0, FALSE ) && (Status == STATUS_SUCCESS)) { Status = STATUS_UNABLE_TO_DELETE_SECTION; } xixfs_DeleteInternalStream( CanWait, ThisFcb ); InterlockedDecrement( &ThisFcb->FCBReference ); /* DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("pVCB->VolumeDasdFCB FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); XifsdLockVcb(IrpContext, pVCB); XifsdDecRefCount(ThisFcb, 1, 1); XifsdUnlockVcb(IrpContext, pVCB); */ DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("pVCB->VolumeDasdFCB FCB(%I64d) VCB %d/%d FCB %d/%d\n", ThisFcb->XixcoreFcb.LotNumber, pVCB->VCBReference, pVCB->VCBUserReference, ThisFcb->FCBReference, ThisFcb->FCBUserReference )); xixfs_TeardownStructures( CanWait, ThisFcb, FALSE, &RemovedFcb ); } } // // Release all of the files. // //XifsdReleaseAllFiles( CanWait, pVCB ); DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("Exit xixfs_PurgeVolume\n")); return Status; }
VOID ReadonlyTryCloseCcb ( IN PREADONLY Readonly ) { PLIST_ENTRY listEntry; Readonly_Reference( Readonly ); if (ExTryToAcquireFastMutex(&Readonly->CcbQMutex) == FALSE) { Readonly_Dereference( Readonly ); return; } listEntry = Readonly->CcbQueue.Flink; while (listEntry != &Readonly->CcbQueue) { PNDAS_CCB ccb = NULL; PNDAS_FCB fcb; PSECTION_OBJECT_POINTERS section; BOOLEAN dataSectionExists; BOOLEAN imageSectionExists; ccb = CONTAINING_RECORD( listEntry, NDAS_CCB, ListEntry ); listEntry = listEntry->Flink; if (ccb->TypeOfOpen != UserFileOpen) break; fcb = ccb->Fcb; if (fcb == NULL) { ASSERT( LFS_BUG ); break; } SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("ReadonlyTryCloseCcb: fcb->FullFileName = %wZ\n", &fcb->FullFileName) ); if (fcb->UncleanCount != 0) { SPY_LOG_PRINT( LFS_DEBUG_SECONDARY_TRACE, ("ReadonlyTryCloseCcb: fcb->FullFileName = %wZ\n", &fcb->FullFileName) ); break; } if (fcb->Header.PagingIoResource != NULL) { ASSERT( LFS_REQUIRED ); break; } section = &fcb->NonPaged->SectionObjectPointers; if (section == NULL) break; //CcFlushCache(section, NULL, 0, &ioStatusBlock); dataSectionExists = (BOOLEAN)(section->DataSectionObject != NULL); imageSectionExists = (BOOLEAN)(section->ImageSectionObject != NULL); if (imageSectionExists) { (VOID)MmFlushImageSection( section, MmFlushForWrite ); } if (dataSectionExists) { CcPurgeCacheSection( section, NULL, 0, FALSE ); } } ExReleaseFastMutex( &Readonly->CcbQMutex ); Readonly_Dereference( Readonly ); return; }
NTSTATUS UDFCloseAllXXXDelayedInDir( IN PVCB Vcb, IN PUDF_FILE_INFO FileInfo, IN BOOLEAN System ) { PUDF_FILE_INFO* PassedList = NULL; ULONG PassedListSize = 0; PUDF_FILE_INFO* FoundList = NULL; ULONG FoundListSize = 0; NTSTATUS RC; ULONG i; BOOLEAN ResAcq = FALSE; BOOLEAN AcquiredVcb = FALSE; UDFNTRequiredFCB* NtReqFcb; PUDF_FILE_INFO CurFileInfo; PFE_LIST_ENTRY CurListPtr; PFE_LIST_ENTRY* ListPtrArray = NULL; _SEH2_TRY { KdPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n")); // Acquire DelayedCloseResource UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); ResAcq = TRUE; UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; RC = UDFBuildTreeItemsList(Vcb, FileInfo, System ? UDFIsLastClose : UDFIsInDelayedCloseQueue, &PassedList, &PassedListSize, &FoundList, &FoundListSize); if(!NT_SUCCESS(RC)) { KdPrint((" UDFBuildTreeItemsList(): error %x\n", RC)); try_return(RC); } if(!FoundList || !FoundListSize) { try_return(RC = STATUS_SUCCESS); } // build array of referenced pointers ListPtrArray = (PFE_LIST_ENTRY*)(MyAllocatePool__(NonPagedPool, FoundListSize*sizeof(PFE_LIST_ENTRY))); if(!ListPtrArray) { KdPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize)); try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } for(i=0;i<FoundListSize;i++) { _SEH2_TRY { CurFileInfo = FoundList[i]; if(!CurFileInfo->ListPtr) { CurFileInfo->ListPtr = (PFE_LIST_ENTRY)(MyAllocatePool__(NonPagedPool, sizeof(FE_LIST_ENTRY))); if(!CurFileInfo->ListPtr) { KdPrint((" Can't alloc ListPtrEntry for items %x\n", i)); try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } CurFileInfo->ListPtr->FileInfo = CurFileInfo; CurFileInfo->ListPtr->EntryRefCount = 0; } CurFileInfo->ListPtr->EntryRefCount++; ListPtrArray[i] = CurFileInfo->ListPtr; } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { BrutePoint(); } _SEH2_END; } UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE; if(System) { // Remove from system queue PtrUDFFCB Fcb; IO_STATUS_BLOCK IoStatus; BOOLEAN NoDelayed = (Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) ? TRUE : FALSE; Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; for(i=FoundListSize;i>0;i--) { UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; _SEH2_TRY { CurListPtr = ListPtrArray[i-1]; CurFileInfo = CurListPtr->FileInfo; if(CurFileInfo && (Fcb = CurFileInfo->Fcb)) { NtReqFcb = Fcb->NTRequiredFCB; ASSERT((ULONG)NtReqFcb > 0x1000); // ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000); if(!(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) && (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) { MmPrint((" CcFlushCache()\n")); CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &IoStatus); } if(NtReqFcb->SectionObject.ImageSectionObject) { MmPrint((" MmFlushImageSection()\n")); MmFlushImageSection(&(NtReqFcb->SectionObject), MmFlushForWrite); } if(NtReqFcb->SectionObject.DataSectionObject) { MmPrint((" CcPurgeCacheSection()\n")); CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); } } else { MmPrint((" Skip item: deleted\n")); } CurListPtr->EntryRefCount--; if(!CurListPtr->EntryRefCount) { if(CurListPtr->FileInfo) CurListPtr->FileInfo->ListPtr = NULL; MyFreePool__(CurListPtr); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { BrutePoint(); } _SEH2_END; UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE; } if(!NoDelayed) Vcb->VCBFlags &= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE; } else { // Remove from internal queue PtrUDFIrpContextLite NextIrpContextLite; for(i=FoundListSize;i>0;i--) { UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; CurListPtr = ListPtrArray[i-1]; CurFileInfo = CurListPtr->FileInfo; if(CurFileInfo && CurFileInfo->Fcb && (NextIrpContextLite = CurFileInfo->Fcb->IrpContextLite)) { RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); if (NextIrpContextLite->Fcb->FCBFlags & UDF_FCB_DIRECTORY) { // BrutePoint(); UDFGlobalData.DirDelayedCloseCount--; } else { UDFGlobalData.DelayedCloseCount--; } UDFDoDelayedClose(NextIrpContextLite); } CurListPtr->EntryRefCount--; if(!CurListPtr->EntryRefCount) { if(CurListPtr->FileInfo) CurListPtr->FileInfo->ListPtr = NULL; MyFreePool__(CurListPtr); } UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE; } } RC = STATUS_SUCCESS; try_exit: NOTHING; } _SEH2_FINALLY {
IO_STATUS_BLOCK NTAPI FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PVCB Vcb, IN PFCB Fcb, IN PACCESS_MASK DesiredAccess, IN USHORT ShareAccess, IN ULONG AllocationSize, IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, IN UCHAR FileAttributes, IN ULONG CreateDisposition, IN BOOLEAN NoEaKnowledge, IN BOOLEAN DeleteOnClose, IN BOOLEAN OpenedAsDos, OUT PBOOLEAN OplockPostIrp) { IO_STATUS_BLOCK Iosb = {{0}}; ACCESS_MASK AddedAccess = 0; BOOLEAN Hidden; BOOLEAN System; PCCB Ccb = NULL; NTSTATUS Status, StatusPrev; /* Acquire exclusive FCB lock */ (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); *OplockPostIrp = FALSE; /* Check if there is a batch oplock */ if (FsRtlCurrentBatchOplock(&Fcb->Fcb.Oplock)) { /* Return with a special information field */ Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY; /* Check the oplock */ Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, IrpContext->Irp, IrpContext, FatOplockComplete, FatPrePostIrp); if (Iosb.Status != STATUS_SUCCESS && Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) { /* The Irp needs to be queued */ *OplockPostIrp = TRUE; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } } /* Validate parameters and modify access */ if (CreateDisposition == FILE_CREATE) { Iosb.Status = STATUS_OBJECT_NAME_COLLISION; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } else if (CreateDisposition == FILE_SUPERSEDE) { SetFlag(AddedAccess, DELETE & ~(*DesiredAccess)); *DesiredAccess |= DELETE; } else if ((CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { SetFlag(AddedAccess, (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) ); *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; } // TODO: Check desired access // TODO: Check if this file is readonly and DeleteOnClose is set /* Validate disposition information */ if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { // TODO: Get this attributes from the dirent Hidden = FALSE; System = FALSE; if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) { DPRINT1("Hidden/system attributes don't match\n"); Iosb.Status = STATUS_ACCESS_DENIED; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } // TODO: Check for write protected volume } /* Check share access */ Iosb.Status = IoCheckShareAccess(*DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess, FALSE); if (!NT_SUCCESS(Iosb.Status)) { /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } /* Check the oplock status after checking for share access */ Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, IrpContext->Irp, IrpContext, FatOplockComplete, FatPrePostIrp ); if (Iosb.Status != STATUS_SUCCESS && Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) { /* The Irp needs to be queued */ *OplockPostIrp = TRUE; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } /* Set Fast I/O flag */ Fcb->Header.IsFastIoPossible = FALSE; //FatiIsFastIoPossible(Fcb); /* Make sure image is not mapped */ if (DeleteOnClose || FlagOn(*DesiredAccess, FILE_WRITE_DATA)) { /* Try to flush the image section */ if (!MmFlushImageSection(&Fcb->SectionObjectPointers, MmFlushForWrite)) { /* Yes, image section exists, set correct status code */ if (DeleteOnClose) Iosb.Status = STATUS_CANNOT_DELETE; else Iosb.Status = STATUS_SHARING_VIOLATION; /* Release the FCB and return */ FatReleaseFcb(IrpContext, Fcb); return Iosb; } } /* Flush the cache if it's non-cached non-pagefile access */ if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) && Fcb->SectionObjectPointers.DataSectionObject && !FlagOn(Fcb->State, FCB_STATE_PAGEFILE)) { /* Set the flag that create is in progress */ SetFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS); /* Flush the cache */ CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL); /* Acquire and release Paging I/O resource before purging the cache section to let lazy writer finish */ ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE); ExReleaseResourceLite( Fcb->Header.PagingIoResource ); /* Delete the cache section */ CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE); /* Clear the flag */ ClearFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS); } /* Check create disposition flags and branch accordingly */ if (CreateDisposition == FILE_OPEN || CreateDisposition == FILE_OPEN_IF) { DPRINT("Opening a file\n"); /* Check if we need to bother with EA */ if (NoEaKnowledge && FALSE /* FatIsFat32(Vcb)*/) { UNIMPLEMENTED; } /* Set up file object */ Ccb = FatCreateCcb(); FatSetFileObject(FileObject, UserFileOpen, Fcb, Ccb); FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers; /* The file is opened */ Iosb.Information = FILE_OPENED; goto SuccComplete; } else if ((CreateDisposition == FILE_SUPERSEDE) || (CreateDisposition == FILE_OVERWRITE) || (CreateDisposition == FILE_OVERWRITE_IF)) { /* Remember previous status */ StatusPrev = Iosb.Status; // TODO: Check system security access /* Perform overwrite operation */ Iosb = FatiOverwriteFile(IrpContext, FileObject, Fcb, AllocationSize, EaBuffer, EaLength, FileAttributes, CreateDisposition, NoEaKnowledge); /* Restore previous status in case of success */ if (Iosb.Status == STATUS_SUCCESS) Iosb.Status = StatusPrev; /* Fall down to completion */ } else { /* We can't get here */ KeBugCheckEx(FAT_FILE_SYSTEM, CreateDisposition, 0, 0, 0); } SuccComplete: /* If all is fine */ if (Iosb.Status != STATUS_PENDING && NT_SUCCESS(Iosb.Status)) { /* Update access if needed */ if (AddedAccess) { /* Remove added access flags from desired access */ ClearFlag(*DesiredAccess, AddedAccess); /* Check share access */ Status = IoCheckShareAccess(*DesiredAccess, ShareAccess, FileObject, &Fcb->ShareAccess, TRUE); /* Make sure it's success */ ASSERT(Status == STATUS_SUCCESS); } else { /* Update the share access */ IoUpdateShareAccess(FileObject, &Fcb->ShareAccess); } /* Clear the delay close */ ClearFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); /* Increase counters */ Fcb->UncleanCount++; Fcb->OpenCount++; Vcb->OpenFileCount++; if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++; if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) Fcb->NonCachedUncleanCount++; // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB } return Iosb; }
VOID FatForceCacheMiss ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN FAT_FLUSH_TYPE FlushType ) /*++ Routine Description: The following routine asks either Cc or Mm to get rid of any cached pages on a file. Note that this will fail if a user has mapped a file. If there is a shared cache map, purge the cache section. Otherwise we have to go and ask Mm to blow away the section. NOTE: This caller MUST own the Vcb exclusive. Arguments: Fcb - Supplies a pointer to an fcb FlushType - Specifies the kind of flushing to perform Return Value: None. --*/ { PVCB Vcb; BOOLEAN ChildrenAcquired = FALSE; PAGED_CODE(); // // If we can't wait, bail. // ASSERT( FatVcbAcquiredExclusive( IrpContext, Fcb->Vcb ) || FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) ); if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } // // If we are purging a directory file object, we must acquire all the // FCBs exclusive so that the parent directory is not being pinned. // Careful, we can collide with something acquiring up the tree like // an unpin repinned flush (FsRtlAcquireFileForCcFlush ...) of a parent // dir on extending writethrough of a child file (oops). So get things // going up the tree, not down. // if ((NodeType(Fcb) != FAT_NTC_FCB) && !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) { PLIST_ENTRY Links; PFCB TempFcb; ChildrenAcquired = TRUE; for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &Fcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) { TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks ); (VOID)FatAcquireExclusiveFcb( IrpContext, TempFcb ); } } (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); // // We use this flag to indicate to a close beneath us that // the Fcb resource should be freed before deleting the Fcb. // Vcb = Fcb->Vcb; SetFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB ); try { BOOLEAN DataSectionExists; BOOLEAN ImageSectionExists; PSECTION_OBJECT_POINTERS Section; if ( FlushType ) { (VOID)FatFlushFile( IrpContext, Fcb, FlushType ); } // // The Flush may have made the Fcb go away // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB)) { Section = &Fcb->NonPaged->SectionObjectPointers; DataSectionExists = (BOOLEAN)(Section->DataSectionObject != NULL); ImageSectionExists = (BOOLEAN)(Section->ImageSectionObject != NULL); // // Note, it is critical to do the Image section first as the // purge of the data section may cause the image section to go // away, but the opposite is not true. // if (ImageSectionExists) { (VOID)MmFlushImageSection( Section, MmFlushForWrite ); } if (DataSectionExists) { CcPurgeCacheSection( Section, NULL, 0, FALSE ); } } } finally { // // If we purging a directory file object, release all the Fcb // resources that we acquired above. The Dcb cannot have vanished // if there were Fcbs underneath it, and the Fcbs couldn't have gone // away since I own the Vcb. // if (ChildrenAcquired) { PLIST_ENTRY Links; PFCB TempFcb; for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &Fcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) { TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks ); FatReleaseFcb( IrpContext, TempFcb ); } } // // Since we have the Vcb exclusive we know that if any closes // come in it is because the CcPurgeCacheSection caused the // Fcb to go away. Also in close, the Fcb was released // before being freed. // if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) { ClearFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS ); FatReleaseFcb( (IRPCONTEXT), Fcb ); } } }