static NTSTATUS VfatFlushFile( PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb) { IO_STATUS_BLOCK IoStatus; NTSTATUS Status; DPRINT("VfatFlushFile(DeviceExt %p, Fcb %p) for '%wZ'\n", DeviceExt, Fcb, &Fcb->PathNameU); CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, &IoStatus); if (IoStatus.Status == STATUS_INVALID_PARAMETER) { /* FIXME: Caching was possible not initialized */ IoStatus.Status = STATUS_SUCCESS; } if (Fcb->Flags & FCB_IS_DIRTY) { Status = VfatUpdateEntry(Fcb); if (!NT_SUCCESS(Status)) { IoStatus.Status = Status; } } return IoStatus.Status; }
/************************************************************************* * * Function: Ext2FlushAFile() * * Description: * Tell the Cache Manager to perform a flush. * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: None * *************************************************************************/ void NTAPI Ext2FlushAFile( PtrExt2NTRequiredFCB PtrReqdFCB, PIO_STATUS_BLOCK PtrIoStatus) { CcFlushCache(&(PtrReqdFCB->SectionObject), NULL, 0, PtrIoStatus); return; }
static NTSTATUS VfatFlushFile( PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb) { IO_STATUS_BLOCK IoStatus; NTSTATUS Status; DPRINT("VfatFlushFile(DeviceExt %p, Fcb %p) for '%wZ'\n", DeviceExt, Fcb, &Fcb->PathNameU); CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, &IoStatus); if (IoStatus.Status == STATUS_INVALID_PARAMETER) { /* FIXME: Caching was possible not initialized */ IoStatus.Status = STATUS_SUCCESS; } ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE); if (BooleanFlagOn(Fcb->Flags, FCB_IS_DIRTY)) { Status = VfatUpdateEntry(DeviceExt, Fcb); if (!NT_SUCCESS(Status)) { IoStatus.Status = Status; } } ExReleaseResourceLite(&DeviceExt->DirResource); return IoStatus.Status; }
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); } }
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge) { /* * The FileNode must be acquired exclusive (Full) when calling this function. */ PAGED_CODE(); LARGE_INTEGER FlushOffset; PLARGE_INTEGER PFlushOffset = &FlushOffset; FSP_FSCTL_FILE_INFO FileInfo; IO_STATUS_BLOCK IoStatus = { STATUS_SUCCESS }; FlushOffset.QuadPart = FlushOffset64; if (FILE_WRITE_TO_END_OF_FILE == FlushOffset.LowPart && -1L == FlushOffset.HighPart) { if (FspFileNodeTryGetFileInfo(FileNode, &FileInfo)) FlushOffset.QuadPart = FileInfo.FileSize; else PFlushOffset = 0; /* we don't know how big the file is, so flush it all! */ } /* it is unclear if the Cc* calls below can raise or not; wrap them just in case */ try { if (0 != FspMvCcCoherencyFlushAndPurgeCache) { /* if we are on Win7+ use CcCoherencyFlushAndPurgeCache */ FspMvCcCoherencyFlushAndPurgeCache( &FileNode->NonPaged->SectionObjectPointers, PFlushOffset, FlushLength, &IoStatus, FlushAndPurge ? 0 : CC_FLUSH_AND_PURGE_NO_PURGE); if (STATUS_CACHE_PAGE_LOCKED == IoStatus.Status) IoStatus.Status = STATUS_SUCCESS; } else { /* do it the old-fashioned way; non-cached and mmap'ed I/O are non-coherent */ CcFlushCache(&FileNode->NonPaged->SectionObjectPointers, PFlushOffset, FlushLength, &IoStatus); if (NT_SUCCESS(IoStatus.Status)) { if (FlushAndPurge) CcPurgeCacheSection(&FileNode->NonPaged->SectionObjectPointers, PFlushOffset, FlushLength, FALSE); IoStatus.Status = STATUS_SUCCESS; } } } except (EXCEPTION_EXECUTE_HANDLER) { IoStatus.Status = GetExceptionCode(); } return IoStatus.Status; }
VOID FFSFloppyFlush( IN PVOID Parameter) { PFFS_FLPFLUSH_CONTEXT Context; PFILE_OBJECT FileObject; PFFS_FCB Fcb; PFFS_VCB Vcb; Context = (PFFS_FLPFLUSH_CONTEXT) Parameter; FileObject = Context->FileObject; Fcb = Context->Fcb; Vcb = Context->Vcb; FFSPrint((DBG_USER, "FFSFloppyFlushing ...\n")); IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); if (Vcb) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL); } if (FileObject) { ASSERT(Fcb == (PFFS_FCB)FileObject->FsContext); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL); ObDereferenceObject(FileObject); } IoSetTopLevelIrp(NULL); ExFreePool(Parameter); }
VOID Ext2FloppyFlush(IN PVOID Parameter) { PEXT2_FLPFLUSH_CONTEXT Context; PFILE_OBJECT FileObject; PEXT2_FCB Fcb; PEXT2_VCB Vcb; Context = (PEXT2_FLPFLUSH_CONTEXT) Parameter; FileObject = Context->FileObject; Fcb = Context->Fcb; Vcb = Context->Vcb; DEBUG(DL_FLP, ("Ext2FloppyFlushing ...\n")); IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); if (FileObject) { ASSERT(Fcb == (PEXT2_FCB)FileObject->FsContext); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL); ObDereferenceObject(FileObject); } if (Vcb) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); Ext2DropBH(Vcb); CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL); ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); } IoSetTopLevelIrp(NULL); Ext2FreePool(Parameter, EXT2_FLPFLUSH_MAGIC); }
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; }
NTSTATUS Ext2FlushFile ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_FCB Fcb, IN PEXT2_CCB Ccb ) { IO_STATUS_BLOCK IoStatus; ASSERT(Fcb != NULL); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); _SEH2_TRY { /* update timestamp and achieve attribute */ if (Ccb != NULL) { if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) { LARGE_INTEGER SysTime; KeQuerySystemTime(&SysTime); Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime); Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime); Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode); } } if (IsDirectory(Fcb)) { IoStatus.Status = STATUS_SUCCESS; _SEH2_LEAVE; } DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n", Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer)); CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus); ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); } _SEH2_FINALLY { /* do cleanup here */ } _SEH2_END; return IoStatus.Status; }
NTSTATUS Ext2FlushVolume ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN BOOLEAN bShutDown ) { IO_STATUS_BLOCK IoStatus; DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n")); ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus); return IoStatus.Status; }
BOOLEAN NTAPI CcFlushImageSection(PSECTION_OBJECT_POINTERS SectionObjectPointer, MMFLUSH_TYPE FlushType) { PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap; PNOCC_BCB Bcb; PLIST_ENTRY Entry; IO_STATUS_BLOCK IOSB; BOOLEAN Result = TRUE; if (!Map) return TRUE; for (Entry = Map->AssociatedBcb.Flink; Entry != &Map->AssociatedBcb; Entry = Entry->Flink) { Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList); if (!Bcb->Dirty) continue; switch (FlushType) { case MmFlushForDelete: CcPurgeCacheSection(SectionObjectPointer, &Bcb->FileOffset, Bcb->Length, FALSE); break; case MmFlushForWrite: CcFlushCache(SectionObjectPointer, &Bcb->FileOffset, Bcb->Length, &IOSB); break; } } return Result; }
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; }
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 DokanDispatchWrite(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; NTSTATUS status = STATUS_INVALID_PARAMETER; PEVENT_CONTEXT eventContext; ULONG eventLength; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; PVOID buffer; BOOLEAN writeToEoF = FALSE; BOOLEAN isPagingIo = FALSE; BOOLEAN isNonCached = FALSE; BOOLEAN isSynchronousIo = FALSE; BOOLEAN fcbLocked = FALSE; __try { DDbgPrint("==> DokanWrite\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; // // If this is a zero length write then return SUCCESS immediately. // if (irpSp->Parameters.Write.Length == 0) { DDbgPrint(" Parameters.Write.Length == 0\n"); Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; __leave; } if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_DEVICE_REQUEST; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) { status = STATUS_INVALID_PARAMETER; __leave; } if (Irp->MdlAddress) { DDbgPrint(" use MdlAddress\n"); buffer = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress); } else { DDbgPrint(" use UserBuffer\n"); buffer = Irp->UserBuffer; } if (buffer == NULL) { DDbgPrint(" buffer == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } if (irpSp->Parameters.Write.ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1) { writeToEoF = TRUE; } if (Irp->Flags & IRP_PAGING_IO) { isPagingIo = TRUE; } if (Irp->Flags & IRP_NOCACHE) { isNonCached = TRUE; } if (fileObject->Flags & FO_SYNCHRONOUS_IO) { isSynchronousIo = TRUE; } if (!isPagingIo && (fileObject->SectionObjectPointer != NULL) && (fileObject->SectionObjectPointer->DataSectionObject != NULL)) { ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, writeToEoF ? NULL : &irpSp->Parameters.Write.ByteOffset, irpSp->Parameters.Write.Length, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, writeToEoF ? NULL : &irpSp->Parameters.Write.ByteOffset, irpSp->Parameters.Write.Length, FALSE); ExReleaseResourceLite(&fcb->PagingIoResource); } // Cannot write at end of the file when using paging IO if (writeToEoF && isPagingIo) { DDbgPrint(" writeToEoF & isPagingIo\n"); Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; __leave; } // the length of EventContext is sum of length to write and length of file // name DokanFCBLockRO(fcb); fcbLocked = TRUE; eventLength = sizeof(EVENT_CONTEXT) + irpSp->Parameters.Write.Length + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); // no more memory! if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; // DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // When the length is bigger than usual event notitfication buffer, // saves pointer in DiverContext to copy EventContext after allocating // more bigger memory. Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = eventContext; if (isPagingIo) { DDbgPrint(" Paging IO\n"); eventContext->FileFlags |= DOKAN_PAGING_IO; } if (isSynchronousIo) { DDbgPrint(" Synchronous IO\n"); eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO; } if (isNonCached) { DDbgPrint(" Nocache\n"); eventContext->FileFlags |= DOKAN_NOCACHE; } // offset of file to write eventContext->Operation.Write.ByteOffset = irpSp->Parameters.Write.ByteOffset; if (writeToEoF) { eventContext->FileFlags |= DOKAN_WRITE_TO_END_OF_FILE; DDbgPrint(" WriteOffset = end of file\n"); } if (isSynchronousIo && ((irpSp->Parameters.Write.ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) && (irpSp->Parameters.Write.ByteOffset.HighPart == -1))) { // NOTE: // http://msdn.microsoft.com/en-us/library/ms795960.aspx // Do not check IrpSp->Parameters.Write.ByteOffset.QuadPart == 0 // Probably the document is wrong. eventContext->Operation.Write.ByteOffset.QuadPart = fileObject->CurrentByteOffset.QuadPart; } // the size of buffer to write eventContext->Operation.Write.BufferLength = irpSp->Parameters.Write.Length; // the offset from the begining of structure // the contents to write will be copyed to this offset eventContext->Operation.Write.BufferOffset = FIELD_OFFSET(EVENT_CONTEXT, Operation.Write.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // adds last null char // copies the content to write to EventContext RtlCopyMemory((PCHAR)eventContext + eventContext->Operation.Write.BufferOffset, buffer, irpSp->Parameters.Write.Length); // copies file name eventContext->Operation.Write.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Write.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // When eventlength is less than event notification buffer, // returns it to user-mode using pending event. if (eventLength <= EVENT_CONTEXT_MAX_SIZE) { DDbgPrint(" Offset %d:%d, Length %d\n", irpSp->Parameters.Write.ByteOffset.HighPart, irpSp->Parameters.Write.ByteOffset.LowPart, irpSp->Parameters.Write.Length); // EventContext is no longer needed, clear it Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; // // We now check whether we can proceed based on the state of // the file oplocks. // // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } } // register this IRP to IRP waiting list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); // Resuests bigger memory // eventContext will be freed later using // Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] } else { // the length at lest file name can be stored ULONG requestContextLength = max( sizeof(EVENT_CONTEXT), eventContext->Operation.Write.BufferOffset); PEVENT_CONTEXT requestContext = AllocateEventContext(vcb->Dcb, Irp, requestContextLength, ccb); // no more memory! if (requestContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; DokanFreeEventContext(eventContext); __leave; } DDbgPrint(" Offset %d:%d, Length %d (request)\n", irpSp->Parameters.Write.ByteOffset.HighPart, irpSp->Parameters.Write.ByteOffset.LowPart, irpSp->Parameters.Write.Length); // copies from begining of EventContext to the end of file name RtlCopyMemory(requestContext, eventContext, eventContext->Operation.Write.BufferOffset); // puts actual size of RequestContext requestContext->Length = requestContextLength; // requsts enough size to copy EventContext requestContext->Operation.Write.RequestLength = eventLength; // // We now check whether we can proceed based on the state of // the file oplocks. // // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, requestContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(requestContext); Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; DokanFreeEventContext(eventContext); } __leave; } } // regiters this IRP to IRP wainting list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, requestContext, 0); } } __finally { if(fcbLocked) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanWrite\n"); } return status; }
NTSTATUS Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext) { PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; PUCHAR Buffer = NULL; LARGE_INTEGER ByteOffset; ULONG ReturnedLength = 0; ULONG Length; NTSTATUS Status = STATUS_UNSUCCESSFUL; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN Nocache = FALSE; BOOLEAN SynchronousIo = FALSE; BOOLEAN RecursiveWriteThrough = FALSE; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; BOOLEAN UpdateFileValidSize = FALSE; BOOLEAN FileSizesChanged = FALSE; BOOLEAN rc; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; Ccb = (PEXT2_CCB) FileObject->FsContext2; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } if (IsFileDeleted(Fcb->Mcb) || (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) { Status = STATUS_FILE_DELETED; __leave; } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && ByteOffset.HighPart == -1) { ByteOffset = FileObject->CurrentByteOffset; } else if (IsWritingToEof(ByteOffset)) { ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } if (Nocache && !PagingIo && ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) || (Length & (SECTOR_SIZE - 1))) ) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if ( !CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain ) ) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite( FileObject, (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite, IrpContext, Irp, Length, bAgain ); bDeferred = TRUE; Status = STATUS_PENDING; __leave; } } } if (IsDirectory(Fcb) && !PagingIo) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } if (IsFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && !IrpContext->IsTopLevel) { PIRP TopIrp; TopIrp = IoGetTopLevelIrp(); if ( (ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG && NodeType(TopIrp) == IO_TYPE_IRP) { PIO_STACK_LOCATION IrpStack; IrpStack = IoGetCurrentIrpStackLocation(TopIrp); if ((IrpStack->MajorFunction == IRP_MJ_WRITE) && (IrpStack->FileObject->FsContext == FileObject->FsContext) && !FlagOn(TopIrp->Flags, IRP_NOCACHE) ) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); RecursiveWriteThrough = TRUE; } } } if (PagingIo) { if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, TRUE)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; __leave; } else { ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } else { ReturnedLength = Length; } } else { if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) { Status = STATUS_ACCESS_DENIED; __leave; } if (IsDirectory(Fcb)) { __leave; } if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; // // Do flushing for such cases // if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject != NULL) { ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache( &(Fcb->SectionObject), &ByteOffset, CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE), &(Irp->IoStatus)); ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcPurgeCacheSection( &(Fcb->SectionObject), &(ByteOffset), CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE), FALSE ); } if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLockAnchor, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } if (Ccb != NULL) { Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, Ext2OplockComplete, Ext2LockIrp ); if (Status != STATUS_SUCCESS) { OpPostIrp = TRUE; __leave; } // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); } // // Extend the inode size when the i/o is beyond the file end ? // if ((ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) { LARGE_INTEGER AllocationSize, Last; if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); Last.QuadPart = Fcb->Header.AllocationSize.QuadPart; AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length); AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG, (ULONGLONG)AllocationSize.QuadPart, (ULONGLONG)BLOCK_SIZE); /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks for indirect files, otherwise we might get gabage data in holes */ IrpContext->MajorFunction += IRP_MJ_MAXIMUM_FUNCTION; Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize); IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION; if (AllocationSize.QuadPart > Last.QuadPart) { Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart; SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE); } ExReleaseResourceLite(&Fcb->PagingIoResource); PagingIoResourceAcquired = FALSE; if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { if (NT_SUCCESS(Status)) { DbgBreak(); Status = STATUS_UNSUCCESSFUL; } __leave; } if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } Fcb->Header.FileSize.QuadPart = Fcb->Inode->i_size = ByteOffset.QuadPart + Length; Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED; FileSizesChanged = TRUE; if (Fcb->Header.FileSize.QuadPart >= 0x80000000 && !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE); Ext2SaveSuper(IrpContext, Vcb); } DEBUG(DL_IO, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n", &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart)); } ReturnedLength = Length; } if (!Nocache) { if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &Ext2Global->CacheManagerCallbacks, Fcb ); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY ); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( FileObject, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); rc = Ext2ZeroData(IrpContext, Vcb, FileObject, &Fcb->Header.ValidDataLength, &ByteOffset); if (!rc) { Status = STATUS_PENDING; DbgBreak(); __leave; } } if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) { if (Ext2CanIWait() || !CcCopyWrite(FileObject, &ByteOffset, Length, TRUE, Buffer)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) { Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; } else { if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length) Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length; } CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); FileSizesChanged = TRUE; } Status = STATUS_SUCCESS; } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { DEBUG(DL_FLP, ("Ext2WriteFile is starting FlushingDpc...\n")); Ext2StartFloppyFlushDpc(Vcb, Fcb, FileObject); } } } else { if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) { /* let this irp wait, since it has to be synchronous */ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); rc = Ext2ZeroData(IrpContext, Vcb, FileObject, &Fcb->Header.ValidDataLength, &ByteOffset); if (!rc) { Status = STATUS_PENDING; DbgBreak(); __leave; } } } Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = ReturnedLength; Status = Ext2WriteInode( IrpContext, Vcb, Fcb->Mcb, (ULONGLONG)(ByteOffset.QuadPart), NULL, ReturnedLength, TRUE, &Length ); Irp = IrpContext->Irp; if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) { if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) { FileSizesChanged = TRUE; if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) { if (!PagingIo) Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length; Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; } else { if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length) Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length; } if (!PagingIo && CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } DEBUG(DL_IO, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n", &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart, Fcb->Header.AllocationSize.QuadPart, ByteOffset.QuadPart, Length)); } } } if (FileSizesChanged) { FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED; Ext2NotifyReportChange( IrpContext, Vcb, Fcb->Mcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED ); } } __finally { /* * in case we got excpetions, we need revert MajorFunction * back to IRP_MJ_WRITE. The reason we do this, is to tell * Ext2ExpandFile to allocate unwritten extent or don't add * new blocks for indirect files. */ if (IrpContext->MajorFunction > IRP_MJ_MAXIMUM_FUNCTION) IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION; if (Irp) { if (PagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (MainResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } } if (!OpPostIrp && !IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT ) { if (!bDeferred) { Status = Ext2QueueRequest(IrpContext); } } else { if (NT_SUCCESS(Status) && !PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } SetFlag(FileObject->Flags, FO_FILE_MODIFIED); SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d " "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset, Length, PagingIo, Nocache, ReturnedLength, Fcb->Header.ValidDataLength.QuadPart,Fcb->Header.FileSize.QuadPart, Fcb->Inode->i_size, Status)); return Status; }
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; }
NTSTATUS xixfs_FlusVolume( IN PXIXFS_IRPCONTEXT IrpContext, IN PXIXFS_VCB pVCB ) { 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_FlusVolume\n")); ASSERT_EXCLUSIVE_VCB(pVCB); CanWait = XIXCORE_TEST_FLAGS(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT); xixfs_RealCloseFCB(pVCB); while (TRUE) { 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 ); } 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); //ExAcquireResourceShared(ThisFcb->PagingIoResource, TRUE); if(XIXCORE_TEST_FLAGS(ThisFcb->XixcoreFcb.FCBFlags, XIXCORE_FCB_CACHED_FILE)){ // Added by ILGU HONG for readonly 09052006 if(!ThisFcb->PtrVCB->XixcoreVcb.IsVolumeWriteProtected){ CcFlushCache(&ThisFcb->SectionObject, NULL, 0, NULL); } // Added by ILGU HONG for readonly end } //ExReleaseResource(ThisFcb->PagingIoResource); XifsdReleaseFcb(TRUE, ThisFcb); } } DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_DIRINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_FILEINFO), ("Exit xixfs_FlusVolume\n")); return STATUS_SUCCESS; }
NTSTATUS DokanDispatchRead(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) /*++ Routine Description: This device control dispatcher handles read IRPs. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; ULONG bufferLength; LARGE_INTEGER byteOffset; NTSTATUS status = STATUS_INVALID_PARAMETER; ULONG readLength = 0; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; PVOID currentAddress = NULL; PEVENT_CONTEXT eventContext; ULONG eventLength; BOOLEAN fcbLocked = FALSE; BOOLEAN isPagingIo = FALSE; BOOLEAN isSynchronousIo = FALSE; BOOLEAN noCache = FALSE; __try { DDbgPrint("==> DokanRead\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; // // If this is a zero length read then return SUCCESS immediately. // if (irpSp->Parameters.Read.Length == 0) { DDbgPrint(" Parameters.Read.Length == 0 \n"); Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; __leave; } if (irpSp->MinorFunction == IRP_MN_COMPLETE) { Irp->MdlAddress = NULL; status = STATUS_SUCCESS; __leave; } if (fileObject == NULL && Irp->MdlAddress != NULL) { DDbgPrint(" Reads by File System Recognizers\n"); currentAddress = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress); if (currentAddress == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // here we could return the bootsector. If we don't have one // the requested read lenght must be returned as requested readLength = irpSp->Parameters.Read.Length; status = STATUS_SUCCESS; __leave; } if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_DEVICE_REQUEST; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_DEVICE_REQUEST; __leave; } bufferLength = irpSp->Parameters.Read.Length; if (irpSp->Parameters.Read.ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && irpSp->Parameters.Read.ByteOffset.HighPart == -1) { // irpSp->Parameters.Read.ByteOffset == NULL don't need check? DDbgPrint("use FileObject ByteOffset\n"); byteOffset = fileObject->CurrentByteOffset; } else { byteOffset = irpSp->Parameters.Read.ByteOffset; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); DDbgPrint(" ByteCount:%lu ByteOffset:%I64d\n", bufferLength, byteOffset.QuadPart); if (bufferLength == 0) { status = STATUS_SUCCESS; readLength = 0; __leave; } // make a MDL for UserBuffer that can be used later on another thread // context if (Irp->MdlAddress == NULL) { status = DokanAllocateMdl(Irp, irpSp->Parameters.Read.Length); if (!NT_SUCCESS(status)) { __leave; } } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) { DDbgPrint(" DOKAN_FILE_DIRECTORY %p\n", fcb); status = STATUS_INVALID_PARAMETER; __leave; } if (Irp->Flags & IRP_PAGING_IO) { isPagingIo = TRUE; } if (fileObject->Flags & FO_SYNCHRONOUS_IO) { isSynchronousIo = TRUE; } if (Irp->Flags & IRP_NOCACHE) { noCache = TRUE; } if (!isPagingIo && (fileObject->SectionObjectPointer != NULL) && (fileObject->SectionObjectPointer->DataSectionObject != NULL)) { ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, &irpSp->Parameters.Read.ByteOffset, irpSp->Parameters.Read.Length, NULL); ExReleaseResourceLite(&fcb->PagingIoResource); } DokanFCBLockRO(fcb); fcbLocked = TRUE; // length of EventContext is sum of file name length and itself 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); if (isPagingIo) { DDbgPrint(" Paging IO\n"); eventContext->FileFlags |= DOKAN_PAGING_IO; } if (isSynchronousIo) { DDbgPrint(" Synchronous IO\n"); eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO; } if (noCache) { DDbgPrint(" Nocache\n"); eventContext->FileFlags |= DOKAN_NOCACHE; } // offset of file to read eventContext->Operation.Read.ByteOffset = byteOffset; // buffer size for read // user-mode file system application can return this size eventContext->Operation.Read.BufferLength = irpSp->Parameters.Read.Length; // copy the accessed file name eventContext->Operation.Read.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Read.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // // We now check whether we can proceed based on the state of // the file oplocks. // if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } // // We have to check for read access according to the current // state of the file locks, and set FileSize from the Fcb. // // FsRtlCheckLockForReadAccess does not block. if (!FsRtlCheckLockForReadAccess(&fcb->FileLock, Irp)) { status = STATUS_FILE_LOCK_CONFLICT; __leave; } } // register this IRP to pending IPR list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if(fcbLocked) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, readLength); DDbgPrint("<== DokanRead\n"); } return status; }
NTKERNELAPI BOOLEAN CcSetPrivateWriteFile( PFILE_OBJECT FileObject ) /*++ Routine Description: This routine will instruct the cache manager to treat the file as a private-write stream, so that a caller can implement a private logging mechanism for it. We will turn on both Mm's modify-no-write and our disable-write-behind, and disallow non-aware flush/purge for the file. Caching must already be initiated on the file. This routine is only exported to the kernel. Arguments: FileObject - File to make private-write. Return Value: None. --*/ { PSHARED_CACHE_MAP SharedCacheMap; BOOLEAN Disabled; KIRQL OldIrql; PVACB Vacb; ULONG ActivePage; ULONG PageIsDirty; // // Pick up the file exclusive to synchronize against readahead and // other purge/map activity. // FsRtlAcquireFileExclusive( FileObject ); // // Get a pointer to the SharedCacheMap. Be sure to release the FileObject // in case an error condition forces a premature exit. // if ((FileObject->SectionObjectPointer == NULL) || ((SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap) == NULL)){ FsRtlReleaseFile( FileObject ); return FALSE; } // // Unmap all the views in preparation for making the disable mw call. // // // We still need to wait for any dangling cache read or writes. // // In fact we have to loop and wait because the lazy writer can // sneak in and do an CcGetVirtualAddressIfMapped, and we are not // synchronized. // // This is the same bit of code that our purge will do. We assume // that a private writer has succesfully blocked out other activity. // // // If there is an active Vacb, then delete it now (before waiting!). // CcAcquireMasterLock( &OldIrql ); GetActiveVacbAtDpcLevel( SharedCacheMap, Vacb, ActivePage, PageIsDirty ); CcReleaseMasterLock( OldIrql ); if (Vacb != NULL) { CcFreeActiveVacb( SharedCacheMap, Vacb, ActivePage, PageIsDirty ); } while ((SharedCacheMap->Vacbs != NULL) && !CcUnmapVacbArray( SharedCacheMap, NULL, 0, FALSE )) { CcWaitOnActiveCount( SharedCacheMap ); } // // Knock the file down. // CcFlushCache( FileObject->SectionObjectPointer, NULL, 0, NULL ); // // Now the file is clean and unmapped. We can still have a racing // lazy writer, though. // // We just wait for the lazy writer queue to drain before disabling // modified write. There may be a better way to do this by having // an event for the WRITE_QUEUED flag. ? This would also let us // dispense with the pagingio pick/drop in the FS cache coherency // paths, but there could be reasons why CcFlushCache shouldn't // always do such a block. Investigate this. // // This wait takes on the order of ~.5s avg. case. // CcAcquireMasterLock( &OldIrql ); if (FlagOn( SharedCacheMap->Flags, WRITE_QUEUED ) || FlagOn( SharedCacheMap->Flags, READ_AHEAD_QUEUED )) { CcReleaseMasterLock( OldIrql ); FsRtlReleaseFile( FileObject ); CcWaitForCurrentLazyWriterActivity(); FsRtlAcquireFileExclusive( FileObject ); } else { CcReleaseMasterLock( OldIrql ); } // // Now set the flags and return. We do not set our MODIFIED_WRITE_DISABLED // since we don't want to fully promote this cache map. Future? // Disabled = MmDisableModifiedWriteOfSection( FileObject->SectionObjectPointer ); if (Disabled) { CcAcquireMasterLock( &OldIrql ); SetFlag(SharedCacheMap->Flags, DISABLE_WRITE_BEHIND | PRIVATE_WRITE); CcReleaseMasterLock( OldIrql ); } // // Now release the file for regular operation. // FsRtlReleaseFile( FileObject ); return Disabled; }
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; }
NTSTATUS FFSv1WriteInode( IN PFFS_IRP_CONTEXT IrpContext, IN PFFS_VCB Vcb, IN PFFSv1_INODE dinode1, IN ULONGLONG offset, IN PVOID Buffer, IN ULONG size, IN BOOLEAN bWriteToDisk, OUT PULONG dwRet) { PFFS_BDL ffs_bdl = NULL; ULONG blocks, i; NTSTATUS Status = STATUS_UNSUCCESSFUL; ULONG Totalblocks; LONGLONG AllocSize; if (dwRet) { *dwRet = 0; } Totalblocks = (dinode1->di_blocks); AllocSize = ((LONGLONG)(FFSDataBlocks(Vcb, Totalblocks)) << BLOCK_BITS); if ((LONGLONG)offset >= AllocSize) { FFSPrint((DBG_ERROR, "FFSv1WriteInode: beyond the file range.\n")); return STATUS_SUCCESS; } if ((LONGLONG)offset + size > AllocSize) { size = (ULONG)(AllocSize - offset); } blocks = FFSv1BuildBDL(IrpContext, Vcb, dinode1, offset, size, &ffs_bdl); if (blocks <= 0) { return STATUS_SUCCESS; } #if DBG { ULONG dwTotal = 0; FFSPrint((DBG_INFO, "FFSv1WriteInode: BDLCount = %xh Size=%xh Off=%xh\n", blocks, size, offset)); for(i = 0; i < blocks; i++) { FFSPrint((DBG_INFO, "FFSv1WriteInode: Lba=%I64xh Len=%xh Off=%xh\n", ffs_bdl[i].Lba, ffs_bdl[i].Length, ffs_bdl[i].Offset)); dwTotal += ffs_bdl[i].Length; } if (dwTotal != size) { FFSBreakPoint(); } FFSPrint((DBG_INFO, "FFSv1WriteInode: Total = %xh (WriteToDisk=%x)\n", dwTotal, bWriteToDisk)); } #endif if (bWriteToDisk) { #if 0 for(i = 0; i < blocks; i++) { { CcFlushCache(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ffs_bdl[i].Lba), ffs_bdl[i].Length, NULL); if (Vcb->SectionObject.DataSectionObject != NULL) { ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcPurgeCacheSection(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ffs_bdl[i].Lba), ffs_bdl[i].Length, FALSE); } } } #endif // assume offset is aligned. Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, size, blocks, FALSE); } else { for(i = 0; i < blocks; i++) { if(!FFSSaveBuffer(IrpContext, Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length, (PVOID)((PUCHAR)Buffer + ffs_bdl[i].Offset))) goto errorout; } if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { FFSPrint((DBG_USER, "FFSv1WriteInode is starting FlushingDpc...\n")); FFSStartFloppyFlushDpc(Vcb, NULL, NULL); } Status = STATUS_SUCCESS; } errorout: if (ffs_bdl) ExFreePool(ffs_bdl); if (NT_SUCCESS(Status)) { if (dwRet) *dwRet = size; } return Status; }
NTSTATUS AFSFlushBuffers( IN PDEVICE_OBJECT LibDeviceObject, IN PIRP Irp) { UNREFERENCED_PARAMETER(LibDeviceObject); AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; NTSTATUS ntStatus = STATUS_SUCCESS; IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); PFILE_OBJECT pFileObject = pIrpSp->FileObject; AFSFcb *pFcb = (AFSFcb *)pFileObject->FsContext; AFSCcb *pCcb = (AFSCcb *)pFileObject->FsContext2; IO_STATUS_BLOCK iosb = {0}; BOOLEAN bReleaseSectionObject = FALSE; pIrpSp = IoGetCurrentIrpStackLocation( Irp); __Enter { if( pFcb == NULL) { AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSFlushBuffers Attempted access (%p) when pFcb == NULL\n", Irp)); try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); } if( pFcb->Header.NodeTypeCode == AFS_ROOT_FCB || pFcb->Header.NodeTypeCode == AFS_ROOT_ALL ) { // // Once we support ADS's on directories we need to perform a flush ehre // try_return( ntStatus = STATUS_SUCCESS); } else if (pFcb->Header.NodeTypeCode != AFS_FILE_FCB) { // // Nothing to flush Everything but files are write through // try_return( ntStatus = STATUS_INVALID_PARAMETER); } AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT, AFS_TRACE_LEVEL_VERBOSE, "AFSFlushBuffers Acquiring Fcb SectionObject lock %p SHARED %08lX\n", &pFcb->NPFcb->SectionObjectResource, PsGetCurrentThread())); AFSAcquireShared( &pFcb->NPFcb->SectionObjectResource, TRUE); bReleaseSectionObject = TRUE; // // The flush consists of two parts. We firstly flush our // cache (if we have one), then we tell the service to write // to the remote server // __try { CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, NULL, 0, &iosb); if (!NT_SUCCESS( iosb.Status )) { AFSDbgTrace(( AFS_SUBSYSTEM_IO_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSFlushBuffers CcFlushCache [1] failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", pFcb->ObjectInformation->FileId.Cell, pFcb->ObjectInformation->FileId.Volume, pFcb->ObjectInformation->FileId.Vnode, pFcb->ObjectInformation->FileId.Unique, iosb.Status, iosb.Information)); try_return( ntStatus = iosb.Status ); } } __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation())) { try_return( ntStatus = GetExceptionCode()); } if( !BooleanFlagOn( pRDRDevExt->DeviceFlags, AFS_DEVICE_FLAG_DIRECT_SERVICE_IO)) { AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT, AFS_TRACE_LEVEL_VERBOSE, "AFSFlushBuffers Releasing Fcb SectionObject lock %p SHARED %08lX\n", &pFcb->NPFcb->SectionObjectResource, PsGetCurrentThread())); AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource); bReleaseSectionObject = FALSE; // // Now, flush to the server - if there is stuff to do // ntStatus = AFSFlushExtents( pFcb, &pCcb->AuthGroup); if( !NT_SUCCESS( ntStatus)) { AFSReleaseExtentsWithFlush( pFcb, &pCcb->AuthGroup, TRUE); ntStatus = STATUS_SUCCESS; } } try_exit: if ( bReleaseSectionObject) { AFSDbgTrace(( AFS_SUBSYSTEM_LOCK_PROCESSING|AFS_SUBSYSTEM_SECTION_OBJECT, AFS_TRACE_LEVEL_VERBOSE, "AFSFlushBuffers Releasing Fcb SectionObject lock %p SHARED %08lX\n", &pFcb->NPFcb->SectionObjectResource, PsGetCurrentThread())); AFSReleaseResource( &pFcb->NPFcb->SectionObjectResource); } AFSCompleteRequest( Irp, ntStatus); } return ntStatus; }
__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 FFSWriteVolume( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = NULL; PFFS_CCB Ccb = NULL; PFFS_FCBVCB FcbOrVcb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PFFS_FCBVCB)FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == FFSVCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PFFS_CCB)FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE); Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE); SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE); FFSPrint((DBG_INFO, "FFSWriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } // For the case of "Direct Access Storage Device", we // need flush/purge the cache if (Ccb != NULL) { ExAcquireResourceExclusive(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; Status = FFSPurgeVolume(Vcb, TRUE); ExReleaseResource(&Vcb->MainResource); MainResourceAcquired = FALSE; if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) { if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } } { FFS_BDL BlockArray; if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) || (Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart;; BlockArray.Offset = 0; BlockArray.Length = Length; Status = FFSReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length, 1, FALSE); Irp = IrpContext->Irp; __leave; } } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (ByteOffset.QuadPart >= Vcb->PartitionInformation.PartitionLength.QuadPart) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } #if FALSE if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if (!CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)FFSDeferWrite, IrpContext, Irp, Length, bAgain); bDeferred = TRUE; FFSBreakPoint(); Status = STATUS_PENDING; __leave; } } #endif if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusive(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcFlushCache(&(Vcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResource(&Vcb->PagingIoResource); CcPurgeCacheSection(&(Vcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE); ExReleaseResource(&Vcb->MainResource); MainResourceAcquired = FALSE; } if (!PagingIo) { if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { /* ULONG ResShCnt, ResExCnt; ResShCnt = ExIsResourceAcquiredSharedLite(&Vcb->PagingIoResource); ResExCnt = ExIsResourceAcquiredExclusiveLite(&Vcb->PagingIoResource); FFSPrint((DBG_USER, "PagingIoRes: %xh:%xh Synchronous=%xh\n", ResShCnt, ResExCnt, IrpContext->IsSynchronous)); */ if (Ccb) { if (!ExAcquireResourceSharedLite( &Vcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } } if (!Nocache) { if ((ByteOffset.QuadPart + Length) > Vcb->PartitionInformation.PartitionLength.QuadPart ) { Length = (ULONG) ( Vcb->PartitionInformation.PartitionLength.QuadPart - ByteOffset.QuadPart); Length &= ~((ULONG)SECTOR_SIZE - 1); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( Vcb->StreamObj, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; } else { Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite(Vcb->StreamObj, (PLARGE_INTEGER)(&ByteOffset), Length, TRUE, Buffer)) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; FFSAddMcbEntry(Vcb, ByteOffset.QuadPart, (LONGLONG)Length); } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } } else { PFFS_BDL ffs_bdl = NULL; ULONG Blocks = 0; LONGLONG DirtyStart; LONGLONG DirtyLba; LONGLONG DirtyLength; LONGLONG RemainLength; if ((ByteOffset.QuadPart + Length) > Vcb->PartitionInformation.PartitionLength.QuadPart) { Length = (ULONG)( Vcb->PartitionInformation.PartitionLength.QuadPart - ByteOffset.QuadPart); Length &= ~((ULONG)SECTOR_SIZE - 1); } Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } ffs_bdl = ExAllocatePool(PagedPool, (Length / Vcb->BlockSize) * sizeof(FFS_BDL)); if (!ffs_bdl) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } DirtyLba = ByteOffset.QuadPart; RemainLength = (LONGLONG)Length; while (RemainLength > 0) { DirtyStart = DirtyLba; if (FFSLookupMcbEntry(Vcb, DirtyStart, &DirtyLba, &DirtyLength, (PLONGLONG)NULL, (PLONGLONG)NULL, (PULONG)NULL)) { if (DirtyLba == -1) { DirtyLba = DirtyStart + DirtyLength; RemainLength = ByteOffset.QuadPart + (LONGLONG)Length - DirtyLba; continue; } ffs_bdl[Blocks].Irp = NULL; ffs_bdl[Blocks].Lba = DirtyLba; ffs_bdl[Blocks].Offset = (ULONG)((LONGLONG)Length + DirtyStart - RemainLength - DirtyLba); if (DirtyLba + DirtyLength > DirtyStart + RemainLength) { ffs_bdl[Blocks].Length = (ULONG)(DirtyStart + RemainLength - DirtyLba); RemainLength = 0; } else { ffs_bdl[Blocks].Length = (ULONG)DirtyLength; RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength); } DirtyLba = DirtyStart + DirtyLength; Blocks++; } else { if (Blocks == 0) { if (ffs_bdl) ExFreePool(ffs_bdl); // // Lookup fails at the first time, ie. // no dirty blocks in the run // FFSBreakPoint(); if (RemainLength == (LONGLONG)Length) Status = STATUS_SUCCESS; else Status = STATUS_UNSUCCESSFUL; __leave; } else { break; } } } if (Blocks > 0) { Status = FFSReadWriteBlocks(IrpContext, Vcb, ffs_bdl, Length, Blocks, FALSE); Irp = IrpContext->Irp; if (NT_SUCCESS(Status)) { ULONG i; for (i = 0; i < Blocks; i++) { FFSRemoveMcbEntry(Vcb, ffs_bdl[i].Lba, ffs_bdl[i].Length); } } if (ffs_bdl) ExFreePool(ffs_bdl); if (!Irp) __leave; } else { if (ffs_bdl) ExFreePool(ffs_bdl); Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; __leave; } } } __finally { if (PagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->PagingIoResource, ExGetCurrentResourceThread()); } if (MainResourceAcquired) { ExReleaseResourceForThreadLite( &Vcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if(!bDeferred) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } FFSCompleteIrpContext(IrpContext, Status); } } else { FFSFreeIrpContext(IrpContext); } } } return Status; }
NTSTATUS DokanDispatchSetInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; PIO_STACK_LOCATION irpSp; PVOID buffer; PFILE_OBJECT fileObject; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; ULONG eventLength; PFILE_OBJECT targetFileObject; PEVENT_CONTEXT eventContext; BOOLEAN isPagingIo = FALSE; BOOLEAN fcbLocked = FALSE; PFILE_END_OF_FILE_INFORMATION pInfoEoF = NULL; vcb = DeviceObject->DeviceExtension; __try { DDbgPrint("==> DokanSetInformationn\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } ccb = (PDokanCCB)fileObject->FsContext2; ASSERT(ccb != NULL); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); buffer = Irp->AssociatedIrp.SystemBuffer; if (Irp->Flags & IRP_PAGING_IO) { isPagingIo = TRUE; } fcb = ccb->Fcb; ASSERT(fcb != NULL); switch (irpSp->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: DDbgPrint( " FileAllocationInformation %lld\n", ((PFILE_ALLOCATION_INFORMATION)buffer)->AllocationSize.QuadPart); break; case FileBasicInformation: DDbgPrint(" FileBasicInformation\n"); break; case FileDispositionInformation: DDbgPrint(" FileDispositionInformation\n"); break; case FileEndOfFileInformation: if ((fileObject->SectionObjectPointer != NULL) && (fileObject->SectionObjectPointer->DataSectionObject != NULL)) { pInfoEoF = (PFILE_END_OF_FILE_INFORMATION)buffer; if (!MmCanFileBeTruncated(fileObject->SectionObjectPointer, &pInfoEoF->EndOfFile)) { status = STATUS_USER_MAPPED_FILE; __leave; } if (!isPagingIo) { ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE); ExReleaseResourceLite(&fcb->PagingIoResource); } } DDbgPrint(" FileEndOfFileInformation %lld\n", ((PFILE_END_OF_FILE_INFORMATION)buffer)->EndOfFile.QuadPart); break; case FileLinkInformation: DDbgPrint(" FileLinkInformation\n"); break; case FilePositionInformation: { PFILE_POSITION_INFORMATION posInfo; posInfo = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(posInfo != NULL); DDbgPrint(" FilePositionInformation %lld\n", posInfo->CurrentByteOffset.QuadPart); fileObject->CurrentByteOffset = posInfo->CurrentByteOffset; status = STATUS_SUCCESS; __leave; } break; case FileRenameInformation: DDbgPrint(" FileRenameInformation\n"); break; case FileValidDataLengthInformation: DDbgPrint(" FileValidDataLengthInformation\n"); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.SetFile.FileInformationClass); break; } // // when this IRP is not handled in swich case // // calcurate the size of EVENT_CONTEXT // it is sum of file name length and size of FileInformation DokanFCBLockRW(fcb); fcbLocked = TRUE; eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length + irpSp->Parameters.SetFile.Length; targetFileObject = irpSp->Parameters.SetFile.FileObject; if (targetFileObject) { DDbgPrint(" FileObject Specified %wZ\n", &(targetFileObject->FileName)); eventLength += targetFileObject->FileName.Length; } eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; eventContext->Operation.SetFile.FileInformationClass = irpSp->Parameters.SetFile.FileInformationClass; // the size of FileInformation eventContext->Operation.SetFile.BufferLength = irpSp->Parameters.SetFile.Length; // the offset from begining of structure to fill FileInfo eventContext->Operation.SetFile.BufferOffset = FIELD_OFFSET(EVENT_CONTEXT, Operation.SetFile.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // the last null char BOOLEAN isRenameOrLink = irpSp->Parameters.SetFile.FileInformationClass == FileRenameInformation || irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation; if (!isRenameOrLink) { // copy FileInformation RtlCopyMemory( (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset, Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.SetFile.Length); } if (isRenameOrLink) { // We need to hanle FileRenameInformation separetly because the structure // of FILE_RENAME_INFORMATION // has HANDLE type field, which size is different in 32 bit and 64 bit // environment. // This cases problems when driver is 64 bit and user mode library is 32 // bit. PFILE_RENAME_INFORMATION renameInfo = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; PDOKAN_RENAME_INFORMATION renameContext = (PDOKAN_RENAME_INFORMATION)( (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset); // This code assumes FILE_RENAME_INFORMATION and FILE_LINK_INFORMATION // have // the same typse and fields. ASSERT(sizeof(FILE_RENAME_INFORMATION) == sizeof(FILE_LINK_INFORMATION)); renameContext->ReplaceIfExists = renameInfo->ReplaceIfExists; renameContext->FileNameLength = renameInfo->FileNameLength; RtlCopyMemory(renameContext->FileName, renameInfo->FileName, renameInfo->FileNameLength); if (targetFileObject != NULL) { // if Parameters.SetFile.FileObject is specified, replase // FILE_RENAME_INFO's file name by // FileObject's file name. The buffer size is already adjusted. DDbgPrint(" renameContext->FileNameLength %d\n", renameContext->FileNameLength); DDbgPrint(" renameContext->FileName %ws\n", renameContext->FileName); RtlZeroMemory(renameContext->FileName, renameContext->FileNameLength); PFILE_OBJECT parentFileObject = targetFileObject->RelatedFileObject; if (parentFileObject != NULL) { RtlCopyMemory(renameContext->FileName, parentFileObject->FileName.Buffer, parentFileObject->FileName.Length); RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, L"\\"); RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, targetFileObject->FileName.Buffer); renameContext->FileNameLength = targetFileObject->FileName.Length + parentFileObject->FileName.Length + sizeof(WCHAR); } else { RtlCopyMemory(renameContext->FileName, targetFileObject->FileName.Buffer, targetFileObject->FileName.Length); renameContext->FileNameLength = targetFileObject->FileName.Length; } } if (irpSp->Parameters.SetFile.FileInformationClass == FileRenameInformation) { DDbgPrint(" rename: %wZ => %ls, FileCount = %u\n", fcb->FileName, renameContext->FileName, (ULONG)fcb->FileCount); } } // copy the file name eventContext->Operation.SetFile.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.SetFile.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } // register this IRP to waiting IRP list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if(fcbLocked) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanSetInformation\n"); } 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 Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_CCB Ccb = NULL; PEXT2_FCBVCB FcbOrVcb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo = FALSE; BOOLEAN Nocache = FALSE; BOOLEAN SynchronousIo = FALSE; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; PEXT2_EXTENT Chain = NULL; EXT2_EXTENT BlockArray; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE) || (Ccb != NULL); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2WriteVolume: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (ByteOffset.QuadPart >= Vcb->PartitionInformation.PartitionLength.QuadPart ) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if ( !CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain ) ) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite( FileObject, (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite, IrpContext, Irp, Length, bAgain ); bDeferred = TRUE; Status = STATUS_PENDING; __leave; } } } /* * User direct volume access */ if (Ccb != NULL && !PagingIo) { if (!FlagOn(Ccb->Flags, CCB_VOLUME_DASD_PURGE)) { if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { Status = Ext2PurgeVolume( Vcb, TRUE); } SetFlag(Ccb->Flags, CCB_VOLUME_DASD_PURGE); } if (!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) { if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } } } else if (Nocache && !PagingIo && (Vcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcFlushCache( &(Vcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); CcPurgeCacheSection( &(Vcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE ); ExReleaseResourceLite(&Vcb->MainResource); MainResourceAcquired = FALSE; } if ( (ByteOffset.QuadPart + Length) > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } if (!Nocache) { if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite ( Vcb->Volume, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite( Vcb->Volume, (PLARGE_INTEGER)(&ByteOffset), Length, TRUE, Buffer )) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; Ext2AddVcbExtent(Vcb, ByteOffset.QuadPart, (LONGLONG)Length); } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } } else if (PagingIo) { LONGLONG DirtyStart; LONGLONG DirtyLba; LONGLONG DirtyLength; LONGLONG RemainLength; PEXT2_EXTENT Extent = NULL; PEXT2_EXTENT List = NULL; Length &= ~((ULONG)SECTOR_SIZE - 1); Status = Ext2LockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } DirtyLba = ByteOffset.QuadPart; RemainLength = (LONGLONG) Length; ASSERT(Length >= SECTOR_SIZE); while (RemainLength > 0) { DirtyStart = DirtyLba; ASSERT(DirtyStart >= ByteOffset.QuadPart); ASSERT(DirtyStart <= ByteOffset.QuadPart + Length); if (Ext2LookupVcbExtent(Vcb, DirtyStart, &DirtyLba, &DirtyLength)) { if (DirtyLba == -1) { DirtyLba = DirtyStart + DirtyLength; if (ByteOffset.QuadPart + Length > DirtyLba) { RemainLength = ByteOffset.QuadPart + Length - DirtyLba; ASSERT(DirtyStart >= ByteOffset.QuadPart); ASSERT(DirtyStart <= ByteOffset.QuadPart + Length); } else { RemainLength = 0; } continue; } ASSERT(DirtyLba <= DirtyStart); Extent = Ext2AllocateExtent(); if (!Extent) { DEBUG(DL_ERR, ( "Ex2WriteVolume: failed to allocate Extent\n")); Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } Extent->Irp = NULL; Extent->Lba = DirtyLba; Extent->Offset = (ULONG)( DirtyStart + Length - RemainLength - DirtyLba ); ASSERT(Extent->Offset <= Length); if (DirtyLba + DirtyLength >= DirtyStart + RemainLength) { Extent->Length = (ULONG)( DirtyLba + RemainLength - DirtyStart ); ASSERT(Extent->Length <= Length); RemainLength = 0; } else { Extent->Length = (ULONG)(DirtyLength + DirtyLba - DirtyStart); RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength); ASSERT(RemainLength <= (LONGLONG)Length); ASSERT(Extent->Length <= Length); } ASSERT(Extent->Length >= SECTOR_SIZE); DirtyLba = DirtyStart + DirtyLength; if (List) { List->Next = Extent; List = Extent; } else { Chain = List = Extent; } } else { if (RemainLength > SECTOR_SIZE) { DirtyLba = DirtyStart + SECTOR_SIZE; RemainLength -= SECTOR_SIZE; } else { RemainLength = 0; } } } if (Chain) { Status = Ext2ReadWriteBlocks(IrpContext, Vcb, Chain, Length ); Irp = IrpContext->Irp; if (NT_SUCCESS(Status)) { for (Extent = Chain; Extent != NULL; Extent = Extent->Next) { Ext2RemoveVcbExtent(Vcb, Extent->Lba, Extent->Length); } } if (!Irp) { __leave; } } else { Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; __leave; } } else { Length &= ~((ULONG)SECTOR_SIZE - 1); Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart; BlockArray.Offset = 0; BlockArray.Length = Length; BlockArray.Next = NULL; Status = Ext2ReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length ); if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; } Irp = IrpContext->Irp; if (!Irp) { __leave; } } } __finally { if (MainResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if (!bDeferred) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoReadAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); } } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } if (Chain) { Ext2DestroyExtentChain(Chain); } } return Status; }
NTSTATUS FFSWriteFile( IN PFFS_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFFS_VCB Vcb = NULL; PFFS_FCB Fcb = NULL; PFFS_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PFILE_OBJECT CacheObject; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; BOOLEAN bNeedExtending = FALSE; BOOLEAN bAppendFile = FALSE; BOOLEAN bDeferred = FALSE; PUCHAR Buffer = NULL; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == FFSICX) && (IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PFFS_VCB)DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == FFSVCB) && (Vcb->Identifier.Size == sizeof(FFS_VCB))); FileObject = IrpContext->FileObject; Fcb = (PFFS_FCB)FileObject->FsContext; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == FFSFCB) && (Fcb->Identifier.Size == sizeof(FFS_FCB))); Ccb = (PFFS_CCB)FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Write.Length; ByteOffset = IoStackLocation->Parameters.Write.ByteOffset; PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE); Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE); SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE); FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", ByteOffset.QuadPart, Length, PagingIo, Nocache)); /* if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) { Status = STATUS_FILE_DELETED; __leave; } if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_DELETE_PENDING; __leave; } */ if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } #if FALSE if (!Nocache) { BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); BOOLEAN bWait = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED); if (!CcCanIWrite( FileObject, Length, (bWait && bQueue), bAgain)) { SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED); CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)FFSDeferWrite, IrpContext, Irp, Length, bAgain); bDeferred = TRUE; FFSBreakPoint(); Status = STATUS_PENDING; __leave; } } #endif if (IsEndOfFile(ByteOffset)) { bAppendFile = TRUE; ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart; } if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } // // Do flushing for such cases // if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) { ExAcquireResourceExclusive(&Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); MainResourceAcquired = TRUE; ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), &ByteOffset, Length, &(Irp->IoStatus)); ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); if (!NT_SUCCESS(Irp->IoStatus.Status)) { Status = Irp->IoStatus.Status; __leave; } ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResource(&Fcb->PagingIoResource); CcPurgeCacheSection(&(Fcb->SectionObject), (PLARGE_INTEGER)&(ByteOffset), Length, FALSE); ExReleaseResource(&Fcb->MainResource); MainResourceAcquired = FALSE; } if (!PagingIo) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { /* ULONG ResShCnt, ResExCnt; ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource); ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource); FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n", Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous)); */ if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IrpContext->IsSynchronous)) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } if (!PagingIo) { if (!FsRtlCheckLockForWriteAccess( &Fcb->FileLockAnchor, Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } if (Nocache) { if ((ByteOffset.QuadPart + Length) > Fcb->Header.AllocationSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) { Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; __leave; } else { if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart)) { Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart); } } } } if (!Nocache) { if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) { __leave; } if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &FFSGlobal->CacheManagerCallbacks, Fcb); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY); CcSetFileSizes( FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); } CacheObject = FileObject; // // Need extending the size of inode ? // if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) > (ULONG)(Fcb->Header.FileSize.QuadPart))) { LARGE_INTEGER ExtendSize; LARGE_INTEGER FileSize; bNeedExtending = TRUE; FileSize = Fcb->Header.FileSize; ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length); if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) { if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize)) { Status = STATUS_INSUFFICIENT_RESOURCES; __leave; } } { Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart; Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart; } if (FileObject->PrivateCacheMap) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); if (ByteOffset.QuadPart > FileSize.QuadPart) { FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, ByteOffset.QuadPart - FileSize.QuadPart); } if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart) { FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart); } } if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1)) { Status = STATUS_SUCCESS; } FFSNotifyReportChange( IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcPrepareMdlWrite( CacheObject, (&ByteOffset), Length, &Irp->MdlAddress, &Irp->IoStatus); Status = Irp->IoStatus.Status; } else { Buffer = FFSGetUserBuffer(Irp); if (Buffer == NULL) { FFSBreakPoint(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyWrite( CacheObject, (PLARGE_INTEGER)&ByteOffset, Length, IrpContext->IsSynchronous, Buffer)) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; } if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = Length; if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n")); FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject); } } } else { ReturnedLength = Length; Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { __leave; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = Length; Status = FFSv1WriteInode( IrpContext, Vcb, Fcb->dinode1, (ULONGLONG)(ByteOffset.QuadPart), NULL, Length, TRUE, &ReturnedLength); Irp = IrpContext->Irp; } } __finally { if (PagingIoResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->PagingIoResource, ExGetCurrentResourceThread()); } if (MainResourceAcquired) { ExReleaseResourceForThreadLite( &Fcb->MainResource, ExGetCurrentResourceThread()); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING) { if (!bDeferred) { Status = FFSLockUserBuffer( IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = FFSQueueRequest(IrpContext); } else { FFSCompleteIrpContext(IrpContext, Status); } } } else { if (NT_SUCCESS(Status)) { if (SynchronousIo && !PagingIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } if (!PagingIo) { SetFlag(FileObject->Flags, FO_FILE_MODIFIED); SetFlag(Fcb->Flags, FCB_FILE_MODIFIED); } } FFSCompleteIrpContext(IrpContext, Status); } } else { FFSFreeIrpContext(IrpContext); } } } return Status; }
NTSTATUS Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; PUCHAR Buffer; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) || IsFileDeleted(Fcb->Mcb)) { Status = STATUS_FILE_DELETED; __leave; } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; DbgBreak(); __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; DbgBreak(); __leave; } if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) { CcFlushCache( FileObject->SectionObjectPointer, &ByteOffset, Length, &Irp->IoStatus ); if (!NT_SUCCESS(Irp->IoStatus.Status)) { __leave; } } ReturnedLength = Length; if (PagingIo) { if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } else { if (Nocache) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } if (!FsRtlCheckLockForReadAccess( &Fcb->FileLockAnchor, Irp )) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.FileSize.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.FileSize.QuadPart) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } if (!IsDirectory(Fcb) && Ccb != NULL) { Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, Ext2OplockComplete, Ext2LockIrp ); if (Status != STATUS_SUCCESS) { OpPostIrp = TRUE; __leave; } // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); } if (!Nocache) { if (IsDirectory(Fcb)) { __leave; } if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &Ext2Global->CacheManagerCallbacks, Fcb ); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY ); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcMdlRead( FileObject, (&ByteOffset), ReturnedLength, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { Status = STATUS_INVALID_USER_BUFFER; DbgBreak(); __leave; } if (!CcCopyRead(FileObject, &ByteOffset, ReturnedLength, Ext2CanIWait(), Buffer, &Irp->IoStatus)) { if (Ext2CanIWait() || !CcCopyRead(FileObject, &ByteOffset, ReturnedLength, TRUE, Buffer, &Irp->IoStatus)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } Status = Irp->IoStatus.Status; } } else { ULONG BytesRead = ReturnedLength; PUCHAR SystemVA = Ext2GetUserBuffer(IrpContext->Irp); if (ByteOffset.QuadPart + BytesRead > Fcb->Header.ValidDataLength.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.ValidDataLength.QuadPart) { if (SystemVA) { SafeZeroMemory(SystemVA, Length); } Irp->IoStatus.Information = ReturnedLength; Status = STATUS_SUCCESS; __leave; } else { BytesRead = (ULONG)(Fcb->Header.ValidDataLength.QuadPart - ByteOffset.QuadPart); if (SystemVA) { SafeZeroMemory(SystemVA + BytesRead, Length - BytesRead); } } } Status = Ext2LockUserBuffer( IrpContext->Irp, BytesRead, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Status = Ext2ReadInode( IrpContext, Vcb, Fcb->Mcb, ByteOffset.QuadPart, NULL, BytesRead, TRUE, NULL ); /* we need re-queue this request in case STATUS_CANT_WAIT and fail it in other failure cases */ if (!NT_SUCCESS(Status)) { __leave; } /* pended by low level device */ if (Status == STATUS_PENDING) { IrpContext->Irp = Irp = NULL; __leave; } Irp = IrpContext->Irp; ASSERT(Irp); Status = Irp->IoStatus.Status; if (!NT_SUCCESS(Status)) { Ext2NormalizeAndRaiseStatus(IrpContext, Status); } } Irp->IoStatus.Information = ReturnedLength; } __finally { if (Irp) { if (PagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (MainResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } } if (!OpPostIrp && !IrpContext->ExceptionInProgress) { if (Irp) { if ( Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { if (NT_SUCCESS(Status)) { if (!PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } FileObject->Flags |= FO_FILE_FAST_IO_READ; } } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2ReadFile: %wZ fetch at Off=%I64xh Len=%xh Paging=%xh Nocache=%xh Returned=%xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache, ReturnedLength, Status)); return Status; }