/************************************************************************* * * Function: Ext2CommonClose() * * Description: * The actual work is performed here. This routine may be invoked in one' * of the two possible contexts: * (a) in the context of a system worker thread * (b) in the context of the original caller * * Expected Interrupt Level (for execution) : * * IRQL_PASSIVE_LEVEL * * Return Value: Does not matter! * *************************************************************************/ NTSTATUS NTAPI Ext2CommonClose( PtrExt2IrpContext PtrIrpContext, PIRP PtrIrp, BOOLEAN FirstAttempt ) { NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION PtrIoStackLocation = NULL; PFILE_OBJECT PtrFileObject = NULL; PtrExt2FCB PtrFCB = NULL; PtrExt2CCB PtrCCB = NULL; PtrExt2VCB PtrVCB = NULL; PtrExt2NTRequiredFCB PtrReqdFCB = NULL; PERESOURCE PtrResourceAcquired = NULL; PERESOURCE PtrPagingIoResourceAcquired = NULL; BOOLEAN CompleteIrp = TRUE; BOOLEAN PostRequest = FALSE; BOOLEAN AcquiredVCB = FALSE; BOOLEAN BlockForResource; int i = 1; try { // First, get a pointer to the current I/O stack location PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); ASSERT(PtrIoStackLocation); PtrFileObject = PtrIoStackLocation->FileObject; ASSERT(PtrFileObject); if( !PtrFileObject->FsContext2 ) { // This must be a Cleanup request received // as a result of IoCreateStreamFileObject // Only such a File object would have a NULL CCB DebugTrace( DEBUG_TRACE_SPECIAL, " === Close with NULL CCB", 0); if( PtrFileObject ) { DebugTrace( DEBUG_TRACE_SPECIAL, "###### File Pointer 0x%LX [Close]", PtrFileObject); } try_return(); } // Get the FCB and CCB pointers Ext2GetFCB_CCB_VCB_FromFileObject ( PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB ); PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ASSERT( PtrVCB ); if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer ) //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer ) { DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer ); } else { DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -null-", 0); } // (a) Acquiring the VCBResource Exclusively... // This is done to synchronise with the close and cleanup routines... // if( ExTryToAcquireResourceExclusiveLite(&(PtrVCB->VCBResource) ) ) BlockForResource = !FirstAttempt; if( !FirstAttempt ) { DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Close]", 0); } else { DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [Close]", 0); } if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } i = 1; while( !AcquiredVCB ) { DebugTraceState( "VCB AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); if(! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) ) { DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [Close]", 0); if( BlockForResource && i != 1000 ) { LARGE_INTEGER Delay; //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); Delay.QuadPart = -500 * i; KeDelayExecutionThread( KernelMode, FALSE, &Delay ); DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); } else { if( i == 1000 ) DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); PostRequest = TRUE; try_return( RC = STATUS_PENDING ); } } else { DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired in [Close]", 0); AcquiredVCB = TRUE; } i *= 10; } // (b) Acquire the file (FCB) exclusively if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) { // This FCB is an FCB indeed. ;) // So acquiring it exclusively... // This is done to synchronise with read/write routines... if( !FirstAttempt ) { DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire FCB Exclusively [Close]", 0); } else { DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [Close]", 0); } if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } PtrReqdFCB = &PtrFCB->NTRequiredFCB; i = 1; while( !PtrResourceAcquired ) { DebugTraceState( "FCBMain AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters ); if(! ExAcquireResourceExclusiveLite( &(PtrReqdFCB->MainResource), FALSE ) ) { DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); if( BlockForResource && i != 1000 ) { LARGE_INTEGER Delay; //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY ); Delay.QuadPart = -500 * i; KeDelayExecutionThread( KernelMode, FALSE, &Delay ); DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); } else { if( i == 1000 ) DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); PostRequest = TRUE; try_return( RC = STATUS_PENDING ); } } else { DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); PtrResourceAcquired = & ( PtrReqdFCB->MainResource ); } i *= 10; } i = 1; while( !PtrPagingIoResourceAcquired ) { DebugTraceState( "FCBPaging AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters ); if(! ExAcquireResourceExclusiveLite( &(PtrReqdFCB->PagingIoResource), FALSE ) ) { DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [Close]", 0); if( BlockForResource && i != 1000 ) { LARGE_INTEGER Delay; // KeSetPriorityThread( PsGetCurrentThread(), LOW_REALTIME_PRIORITY ); Delay.QuadPart = -500 * i; KeDelayExecutionThread( KernelMode, FALSE, &Delay ); DebugTrace(DEBUG_TRACE_MISC, "*** Retrying... after 50 * %ld ms [Close]", i); } else { if( i == 1000 ) DebugTrace(DEBUG_TRACE_MISC, "*** Reposting... [Close]", 0 ); PostRequest = TRUE; try_return( RC = STATUS_PENDING ); } } else { DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [Close]", 0); PtrPagingIoResourceAcquired = & ( PtrReqdFCB->PagingIoResource ); } i *= 10; } // (c) Delete the CCB structure (free memory) RemoveEntryList( &PtrCCB->NextCCB ); Ext2ReleaseCCB( PtrCCB ); PtrFileObject->FsContext2 = NULL; // (d) Decrementing the Reference Count... if( PtrFCB->ReferenceCount ) { InterlockedDecrement( &PtrFCB->ReferenceCount ); } else { Ext2BreakPoint(); } DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount = 0x%lX [Close]", PtrFCB->ReferenceCount ); DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Close]", PtrFCB->OpenHandleCount ); if( PtrFCB->ReferenceCount == 0 ) { // Attempting to update time stamp values // Errors are ignored... // Not considered as critical errors... { ULONG CreationTime, AccessTime, ModificationTime; EXT2_INODE Inode; CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) ) { // Update time stamps in the inode... Inode.i_ctime = CreationTime; Inode.i_atime = AccessTime; Inode.i_mtime = ModificationTime; // Updating the inode... Ext2WriteInode( NULL, PtrVCB, PtrFCB->INodeNo, &Inode ); } } if( PtrFCB->INodeNo == EXT2_ROOT_INO ) { // // Root Directory FCB // Preserve this // FSD has a File Object for this FCB... // DebugTrace(DEBUG_TRACE_MISC, "^^^^^Root Directory FCB ; leaveing it alone[Close]", 0); // Do nothing... } else if( PtrFCB->DcbFcb.Dcb.PtrDirFileObject ) { // // If this is a FCB created on the FSD's initiative // Leave it alone // DebugTrace(DEBUG_TRACE_MISC, "^^^^^FCB Created on the FSD's initiative; leaveing it alone[Close]", 0); if( !PtrFCB->ClosableFCBs.OnClosableFCBList ) { InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, &PtrFCB->ClosableFCBs.ClosableFCBList ); PtrVCB->ClosableFCBs.Count++; PtrFCB->ClosableFCBs.OnClosableFCBList = TRUE; } if( PtrVCB->ClosableFCBs.Count > EXT2_MAXCLOSABLE_FCBS_UL ) { PtrExt2FCB PtrTempFCB = NULL; // Checking if Closable FCBs are too many in number... // Shouldn't block the // Should do this asynchronously... // Maybe later... PLIST_ENTRY PtrEntry = NULL; PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); PtrTempFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); if( Ext2CloseClosableFCB( PtrTempFCB ) ) { DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Close]", PtrTempFCB ); ExFreePool( PtrTempFCB ); PtrVCB->ClosableFCBs.Count--; } else { // Put the FCB back in the list... InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, &PtrTempFCB->ClosableFCBs.ClosableFCBList ); } DebugTrace( DEBUG_TRACE_SPECIAL, "ClosableFCBs Count = %ld [Close]", PtrVCB->ClosableFCBs.Count ); } } else { // Remove this FCB as well... DebugTrace(DEBUG_TRACE_MISC, "^^^^^Deleting FCB [Close]", 0); RemoveEntryList( &PtrFCB->NextFCB ); if ( PtrPagingIoResourceAcquired ) { Ext2ReleaseResource(PtrPagingIoResourceAcquired); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrPagingIoResourceAcquired->ActiveCount, PtrPagingIoResourceAcquired->NumberOfExclusiveWaiters, PtrPagingIoResourceAcquired->NumberOfSharedWaiters ); PtrPagingIoResourceAcquired = NULL; } if ( PtrResourceAcquired ) { Ext2ReleaseResource(PtrResourceAcquired); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrResourceAcquired->ActiveCount, PtrResourceAcquired->NumberOfExclusiveWaiters, PtrResourceAcquired->NumberOfSharedWaiters ); if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } PtrResourceAcquired = NULL; } Ext2ReleaseFCB( PtrFCB ); } } CompleteIrp = TRUE; } else { // This must be a volume close... // What do I do now? ;) DebugTrace(DEBUG_TRACE_MISC, "VCB Close Requested !!!", 0); CompleteIrp = TRUE; } try_return(); try_exit: NOTHING; } finally { if ( PtrPagingIoResourceAcquired ) { Ext2ReleaseResource(PtrPagingIoResourceAcquired); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrPagingIoResourceAcquired->ActiveCount, PtrPagingIoResourceAcquired->NumberOfExclusiveWaiters, PtrPagingIoResourceAcquired->NumberOfSharedWaiters ); PtrPagingIoResourceAcquired = NULL; } if ( PtrResourceAcquired ) { Ext2ReleaseResource(PtrResourceAcquired); DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [Close]", 0); DebugTraceState( "Resource AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrResourceAcquired->ActiveCount, PtrResourceAcquired->NumberOfExclusiveWaiters, PtrResourceAcquired->NumberOfSharedWaiters ); if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } PtrResourceAcquired = NULL; } if (AcquiredVCB) { ASSERT(PtrVCB); Ext2ReleaseResource(&(PtrVCB->VCBResource)); DebugTraceState( "VCB AC:0x%LX EX:0x%LX SW:0x%LX [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters ); DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Close]", 0); AcquiredVCB = FALSE; if( PtrFileObject ) { DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject); } } if( PostRequest ) { RC = Ext2PostRequest(PtrIrpContext, PtrIrp); } else if( CompleteIrp && RC != STATUS_PENDING ) { // complete the IRP IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT ); Ext2ReleaseIrpContext( PtrIrpContext ); } } // end of "finally" processing return(RC); }
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; }