-/*************************************************************************
-*
-* File: write.c
-*
-* Module: Ext2 File System Driver (Kernel mode execution only)
-*
-* Description:
-* Contains code to handle the "Write" dispatch entry point.
-*
-* Author: Manoj Paul Joseph
-*
-*
-*************************************************************************/
-
-#include "ext2fsd.h"
-
-// define the file specific bug-check id
-#define EXT2_BUG_CHECK_ID EXT2_FILE_WRITE
-
-#define DEBUG_LEVEL (DEBUG_TRACE_WRITE)
-
-
-/*************************************************************************
-*
-* Function: Ext2Write()
-*
-* Description:
-* The I/O Manager will invoke this routine to handle a write
-* request
-*
-* Expected Interrupt Level (for execution) :
-*
-* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
-* to be deferred to a worker thread context)
-*
-* Return Value: STATUS_SUCCESS/Error
-*
-*************************************************************************/
-NTSTATUS NTAPI Ext2Write(
-PDEVICE_OBJECT DeviceObject, // the logical volume device object
-PIRP Irp) // I/O Request Packet
+/*
+ * COPYRIGHT: See COPYRIGHT.TXT
+ * PROJECT: Ext2 File System Driver for WinNT/2K/XP
+ * FILE: write.c
+ * PROGRAMMER: Matt Wu <mattwu@163.com>
+ * HOMEPAGE: http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+#define DL_FLP DL_DBG
+
+/* DEFINITIONS *************************************************************/
+
+#define EXT2_FLPFLUSH_MAGIC 'FF2E'
+
+typedef struct _EXT2_FLPFLUSH_CONTEXT {
+
+ PEXT2_VCB Vcb;
+ PEXT2_FCB Fcb;
+ PFILE_OBJECT FileObject;
+
+ KDPC Dpc;
+ KTIMER Timer;
+ WORK_QUEUE_ITEM Item;
+
+} EXT2_FLPFLUSH_CONTEXT, *PEXT2_FLPFLUSH_CONTEXT;
+
+VOID NTAPI
+Ext2FloppyFlush(IN PVOID Parameter);
+
+VOID NTAPI
+Ext2FloppyFlushDpc (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2);
+
+
+NTSTATUS
+Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext);
+
+NTSTATUS
+Ext2WriteFile (IN PEXT2_IRP_CONTEXT IrpContext);
+
+NTSTATUS
+Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext);
+
+VOID
+Ext2DeferWrite(IN PEXT2_IRP_CONTEXT, PIRP Irp);
+
+
+/* FUNCTIONS *************************************************************/
+
+VOID NTAPI
+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);
+
+ CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL);
+ }
+
+ IoSetTopLevelIrp(NULL);
+ Ext2FreePool(Parameter, EXT2_FLPFLUSH_MAGIC);
+}
+
+VOID NTAPI
+Ext2FloppyFlushDpc (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+)
+{
+ PEXT2_FLPFLUSH_CONTEXT Context;
+
+ Context = (PEXT2_FLPFLUSH_CONTEXT) DeferredContext;
+
+ DEBUG(DL_FLP, ("Ext2FloppyFlushDpc is to be started...\n"));
+
+ ExQueueWorkItem(&Context->Item, CriticalWorkQueue);
+}
+
+VOID
+Ext2StartFloppyFlushDpc (
+ PEXT2_VCB Vcb,
+ PEXT2_FCB Fcb,
+ PFILE_OBJECT FileObject )
{
- NTSTATUS RC = STATUS_SUCCESS;
- PtrExt2IrpContext PtrIrpContext = NULL;
- BOOLEAN AreWeTopLevel = FALSE;
+ LARGE_INTEGER OneSecond;
+ PEXT2_FLPFLUSH_CONTEXT Context;
- DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Write IRP Received...", 0);
+ ASSERT(IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK));
- // Ext2BreakPoint();
+ Context = Ext2AllocatePool(
+ NonPagedPool,
+ sizeof(EXT2_FLPFLUSH_CONTEXT),
+ EXT2_FLPFLUSH_MAGIC
+ );
- FsRtlEnterFileSystem();
- ASSERT(DeviceObject);
- ASSERT(Irp);
+ if (!Context) {
+ DEBUG(DL_ERR, ( "Ex2StartFloppy...: failed to allocate Context\n"));
+ DbgBreak();
+ return;
+ }
- // set the top level context
- AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
+ KeInitializeTimer(&Context->Timer);
- try
- {
- // get an IRP context structure and issue the request
- PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
- ASSERT(PtrIrpContext);
+ KeInitializeDpc( &Context->Dpc,
+ Ext2FloppyFlushDpc,
+ Context );
- RC = Ext2CommonWrite(PtrIrpContext, Irp);
- }
- except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation()))
- {
- RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
- Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
- }
+ ExInitializeWorkItem( &Context->Item,
+ Ext2FloppyFlush,
+ Context );
- if (AreWeTopLevel)
- {
- IoSetTopLevelIrp(NULL);
- }
+ Context->Vcb = Vcb;
+ Context->Fcb = Fcb;
+ Context->FileObject = FileObject;
- FsRtlExitFileSystem();
+ if (FileObject) {
+ ObReferenceObject(FileObject);
+ }
- return(RC);
+ OneSecond.QuadPart = (LONGLONG)-1*1000*1000*10;
+ KeSetTimer( &Context->Timer,
+ OneSecond,
+ &Context->Dpc );
}
+BOOLEAN
+Ext2ZeroData (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER Start,
+ IN PLARGE_INTEGER End
+ )
+{
+ PEXT2_FCB Fcb;
+ PBCB Bcb;
+ PVOID Ptr;
+ ULONG Size;
+#ifndef __REACTOS__
+ BOOLEAN rc = TRUE;
+#endif
+ ASSERT (End && Start && End->QuadPart > Start->QuadPart);
+ Fcb = (PEXT2_FCB) FileObject->FsContext;
+
+ /* skip data zero if we've already tracked unwritten part */
+ if (0 == ( End->LowPart & (BLOCK_SIZE -1)) &&
+ 0 == (Start->LowPart & (BLOCK_SIZE -1))) {
+
+ if (INODE_HAS_EXTENT(Fcb->Inode)) {
+ return TRUE;
+ } else {
+#if !EXT2_PRE_ALLOCATION_SUPPORT
+ return TRUE;
+#endif
+ }
+ }
+
+ /* clear data in range [Start, End) */
+ return CcZeroData(FileObject, Start, End, Ext2CanIWait());
+}
-/*************************************************************************
-*
-* Function: Ext2CommonWrite()
-*
-* 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: STATUS_SUCCESS/Error
-*
-*************************************************************************/
-NTSTATUS NTAPI Ext2CommonWrite(
- PtrExt2IrpContext PtrIrpContext,
- PIRP PtrIrp)
+VOID
+Ext2DeferWrite(IN PEXT2_IRP_CONTEXT IrpContext, PIRP Irp)
{
+ ASSERT(IrpContext->Irp == Irp);
- NTSTATUS RC = STATUS_SUCCESS;
- PIO_STACK_LOCATION PtrIoStackLocation = NULL;
- LARGE_INTEGER ByteOffset;
- uint32 WriteLength = 0;
- uint32 NumberBytesWritten = 0;
- PFILE_OBJECT PtrFileObject = NULL;
- PtrExt2FCB PtrFCB = NULL;
- PtrExt2CCB PtrCCB = NULL;
- PtrExt2VCB PtrVCB = NULL;
- PtrExt2NTRequiredFCB PtrReqdFCB = NULL;
- PERESOURCE PtrResourceAcquired = NULL;
- void *PtrSystemBuffer = NULL;
-
- BOOLEAN CompleteIrp = TRUE;
- BOOLEAN PostRequest = FALSE;
-
- BOOLEAN CanWait = FALSE;
- BOOLEAN PagingIo = FALSE;
- BOOLEAN NonBufferedIo = FALSE;
- BOOLEAN SynchronousIo = FALSE;
- BOOLEAN IsThisADeferredWrite = FALSE;
- BOOLEAN WritingAtEndOfFile = FALSE;
-
- EXT2_IO_RUN *PtrIoRuns = NULL;
-
- PBCB PtrPinnedSIndirectBCB = NULL;
- PBCB PtrPinnedDIndirectBCB = NULL;
- PBCB PtrPinnedTIndirectBCB = NULL;
-
- // Used to cache the Single Indirect blocks pointed to by
- // the Double Indirect block
- PEXT2_SIBLOCKS PtrDIArray = NULL;
- ULONG DIArrayCount = 0;
-
- // Used to cache the Single Indirect blocks pointed to by
- // the Triple Indirect block
- PEXT2_SIBLOCKS PtrTIArray = NULL;
- ULONG TIArrayCount = 0;
-
-
- try
- {
- // First, get a pointer to the current I/O stack location
- PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
- ASSERT(PtrIoStackLocation);
-
- PtrFileObject = PtrIoStackLocation->FileObject;
- ASSERT(PtrFileObject);
-
- // If this happens to be a MDL write complete request, then
- // allocated MDL can be freed.
- if(PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE)
- {
- // Caller wants to tell the Cache Manager that a previously
- // allocated MDL can be freed.
- Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, FALSE);
- // The IRP has been completed.
- CompleteIrp = FALSE;
- try_return(RC = STATUS_SUCCESS);
- }
-
- // If this is a request at IRQL DISPATCH_LEVEL, then post the request
- if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC)
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- try_return(RC = STATUS_PENDING);
- }
-
-
- // Get the FCB and CCB pointers
- Ext2GetFCB_CCB_VCB_FromFileObject (
- PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
-
-
- // Get some of the parameters supplied to us
- ByteOffset = PtrIoStackLocation->Parameters.Write.ByteOffset;
- WriteLength = PtrIoStackLocation->Parameters.Write.Length;
-
- CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
- PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE);
- NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE);
- SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE);
-
- if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
- {
- DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
- }
- else
- {
- DebugTrace(DEBUG_TRACE_FILE_NAME, " === Write File Name : -null-", 0);
- }
-
- DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteCount = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length);
- DebugTrace( DEBUG_TRACE_SPECIAL, " ->ByteOffset.LowPart = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart);
-
- if( CanWait )
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can Wait ", 0 );
- }
- else
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Can't Wait ", 0 );
- }
-
- if( PagingIo )
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Paging Io ", 0 );
- }
- else
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->Not Paging Io", 0 );
- }
-
- if( SynchronousIo )
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->SynchronousIo ", 0 );
- }
- else
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->ASynchronousIo ", 0 );
- }
-
- if( NonBufferedIo )
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->NonBufferedIo", 0 );
- }
- else
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, " ->BufferedIo", 0 );
- }
- // Check at this point whether the file object being
- // used for write really did have write permission requested when the
- // create/open operation was performed.
- // Don't do this for paging io...
-
- if (WriteLength == 0)
- {
- // a 0 byte write can be immediately succeeded
- try_return();
- }
-
- // Is this a write of the volume itself ?
- if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB)
- {
- //
- // >>>>>>>>>>>>>>>>>> VOLUME WRITE <<<<<<<<<<<<<<
- //
-
- // Validate the offset and length first...
- // .......................................
-
- // Acquire the volume resource exclusively
- if( PtrFileObject )
- {
- DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject);
- }
-
- if( PagingIo )
- {
- // This is Paging IO...
-
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCBPaging Exclusively [Write]", 0);
- DebugTraceState( "VCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters );
-
- if( !ExAcquireResourceExclusiveLite( &( PtrVCB->PagingIoResource ), FALSE ) )
- {
- // post the request to be processed in the context of a worker thread
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquisition FAILED [Write]", 0);
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- try_return(RC = STATUS_PENDING);
- }
-
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCBPaging Acquired [Write]", 0);
- PtrResourceAcquired = &(PtrVCB->PagingIoResource);
- }
- else
- {
- // This is not Paging IO...
-
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Write]", 0);
- DebugTraceState( "VCB AC:0x%LX SW:0x%LX EX:0x%LX [Write]", PtrVCB->VCBResource.ActiveCount,
- PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
-
- if( !ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) )
- {
- // post the request to be processed in the context of a worker thread
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Write]", 0);
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- try_return(RC = STATUS_PENDING);
- }
-
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired [Write]", 0);
- PtrResourceAcquired = &(PtrVCB->VCBResource);
- }
-
- // Validate the caller supplied offset here
- if( !PagingIo )
- {
- if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart )
- {
- // Write extending beyond the end of volume.
- // Deny access...
- //
- RC = STATUS_END_OF_FILE;
- NumberBytesWritten = 0;
- try_return();
- }
- }
-
- // Lock the callers buffer
- if (!NT_SUCCESS(RC = Ext2LockCallersBuffer(PtrIrp, TRUE, WriteLength)))
- {
- try_return();
- }
-
- // Forward the request to the lower level driver
- if( PagingIo || NonBufferedIo )
- {
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[Volume Write] PagingIo or NonBufferedIo ", 0);
- CompleteIrp = FALSE;
-
- //
- // Do the write operation...
- // Send down the IRP to the lower level driver...
- //
- // Returned Informations and Status will be set by the lower level driver...
- // The IRP will also be completed by the lower level driver...
-
- RC = Ext2PassDownSingleReadWriteIRP (
- PtrIrpContext, PtrIrp, PtrVCB,
- ByteOffset, WriteLength, SynchronousIo );
-
- try_return();
- }
- else
- {
- PBCB PtrBCB = NULL;
- PVOID PtrBuffer = NULL;
-
- DebugTrace(DEBUG_TRACE_READ_DETAILS, "[Volume Write] BufferedIo ", 0);
- //
- // Let the cache manager worry about this write...
- // Pinned access should have been initiated.
- // But checking anyway...
- //
- ASSERT( PtrVCB->PtrStreamFileObject );
- ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap );
-
- CcPreparePinWrite(
- PtrVCB->PtrStreamFileObject,
- &ByteOffset,
- WriteLength,
- FALSE, // Don't Zero...
- TRUE, // Can Wait...
- &PtrBCB,
- &PtrBuffer);
-
- // Do the write now...
- // Write to the Pinned buffer...
- // Cache Manager will do the disk write...
- RtlCopyBytes( PtrBuffer, PtrSystemBuffer, WriteLength );
- // CcSetDirtyPinnedData( PtrBCB, NULL );
- CcUnpinData( PtrBCB );
- PtrBuffer = NULL;
- PtrBCB = NULL;
-
- NumberBytesWritten = WriteLength;
-
- // Go ahead and complete the IRP...
- }
- try_return();
- }
-
-
- IsThisADeferredWrite = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE);
-
- if (!NonBufferedIo)
- {
- /****************************************************************************
- if (!CcCanIWrite(PtrFileObject, WriteLength, CanWait, IsThisADeferredWrite))
- {
- // Cache Manager and/or the VMM does not want us to perform
- // the write at this time. Post the request.
- Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_DEFERRED_WRITE);
- CcDeferWrite( PtrFileObject, Ext2DeferredWriteCallBack, PtrIrpContext, PtrIrp, WriteLength, IsThisADeferredWrite);
- CompleteIrp = FALSE;
- try_return( RC = STATUS_PENDING );
- }
- ****************************************************************************/
- }
-
- // If the write request is directed to a page file
- // send the request directly to the disk
- // driver. For requests directed to a page file, you have to trust
- // that the offsets will be set correctly by the VMM. You should not
- // attempt to acquire any FSD resources either.
- if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)
- {
- IoMarkIrpPending(PtrIrp);
-
- // You will need to set a completion routine before invoking a lower level driver.
- // Forward request directly to disk driver.
- // Ext2PageFileIo(PtrIrpContext, PtrIrp);
-
- CompleteIrp = FALSE;
-
- try_return(RC = STATUS_PENDING);
- }
-
- // Check whether this write operation is targeted
- // to a directory object...
-
- if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)
- {
- //
- // Is this a write a result of
- // cached directory manipulation operatio
- // by the FSD itself?
- //
- if( PagingIo )
- {
- // Yep! Allow it to proceed...
- }
- else
- {
- // Nope... User initiated directory writes are not allowed!
- // Fail this request...
- RC = STATUS_INVALID_DEVICE_REQUEST;
- try_return();
- }
- }
-
- PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
-
- //
- // Synchronizing with other reads and writes...
- // Acquire the appropriate FCB resource exclusively
- //
- if (PagingIo)
- {
- // Try to acquire the FCB PagingIoResource exclusively
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCBpaging Exclusively [Write]", 0);
-
- if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait))
- {
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquisition FAILED [Write]", 0);
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- try_return(RC = STATUS_PENDING);
- }
- // Remember the resource that was acquired
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCBpaging Acquired [Write]", 0);
- PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource);
- }
- else
- {
- // Try to acquire the FCB MainResource exclusively
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Write]", 0);
- if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait))
- {
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Write]", 0);
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- try_return(RC = STATUS_PENDING);
- }
- // Remember the resource that was acquired
- DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquired [Write]", 0);
- PtrResourceAcquired = &(PtrReqdFCB->MainResource);
- }
-
- // Validate start offset and length supplied.
- // Here is a special check that determines whether the caller wishes to
- // begin the write at current end-of-file (whatever the value of that
- // offset might be)
- if ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == 0xFFFFFFFF))
- {
- WritingAtEndOfFile = TRUE;
- ByteOffset.QuadPart = PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart;
- }
-
- //
- // If this is a Non Cached io and if caching has been initiated,
- // Flush and purge the cache
- //
- if (NonBufferedIo && !PagingIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL))
- {
- // Flush and then attempt to purge the cache
- CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, WriteLength, &(PtrIrp->IoStatus));
- // If the flush failed, return error to the caller
- if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status))
- {
- try_return();
- }
-
- // Attempt the purge and ignore the return code
- CcPurgeCacheSection( &(PtrReqdFCB->SectionObject), (WritingAtEndOfFile ? &(PtrReqdFCB->CommonFCBHeader.FileSize) : &(ByteOffset)),
- WriteLength, FALSE);
- // We are finished with our flushing and purging
- }
-
- if (!PagingIo)
- {
- // Insert code to perform the check here ...
- //
- // if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp,
- // PtrCurrentIoStackLocation))
- // {
- // try_return(RC = STATUS_FILE_LOCK_CONFLICT);
- // }
- }
-
- // Read in the File inode...
- Ext2InitializeFCBInodeInfo( PtrFCB );
-
- if (!PagingIo)
- {
- LARGE_INTEGER CurrentTime;
- KeQuerySystemTime( &CurrentTime );
- PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart;
- PtrFCB->LastWriteTime.QuadPart = CurrentTime.QuadPart;
- }
-
- {
- //
- // Validate start offset and length supplied.
- //
- ULONG LogicalBlockSize = 0;
- LONGLONG NoOfNewBlocksRequired = 0;
- LONGLONG NoOfBytesRequired = 0;
- LONGLONG i;
- BOOLEAN ZeroOut = FALSE;
- LARGE_INTEGER StartOffsetForZeroing;
- LARGE_INTEGER EndOffsetForZeroing;
-
-
- LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
-
- if ( ByteOffset.QuadPart + WriteLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart )
- {
- if( PagingIo )
- {
- //
- // A paging request never modifies the file size...
- //
- if( ByteOffset.QuadPart
- >= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
- {
- // Page request for writing outside the file...
- // No op this IRP by completing it...
- //
- try_return();
- }
- if( ByteOffset.QuadPart + WriteLength
- > PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
- {
- // Page request for writing outside the file alocation size...
- // Truncate the write size so that it is within the allocation limit...
- //
- WriteLength = (ULONG) (PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart - ByteOffset.QuadPart);
- }
- }
- else
- {
-
- // Starting offset is > file size
- // Allocate new blocks?
- NoOfBytesRequired = ByteOffset.QuadPart + WriteLength
- - PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart;
-
- if( NoOfBytesRequired )
- {
- NoOfNewBlocksRequired = Ext2Align64( NoOfBytesRequired, LogicalBlockSize )
- / LogicalBlockSize;
- for( i = 0; i < NoOfNewBlocksRequired ; i++ )
- {
- Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE );
- }
-
- ZeroOut = TRUE;
-
- if( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart < ByteOffset.QuadPart )
- {
- // Curr EOF --> | | <--New EOF
- // -----------------------------------------------
- // | | |///////////| |
- // | File Contents | Free |// Write //| Free | <- End of Allocation
- // | | |///////////| |
- // -----------------------------------------------
- // | |
-
- // Write is beyond the current end of file...
- // This will create a hole...
- // Will have to zero this out...
-
- // Start offset is the Current File size
- StartOffsetForZeroing = PtrReqdFCB->CommonFCBHeader.FileSize;
- // End offset is the point at which this write is going to start
- EndOffsetForZeroing = ByteOffset;
- }
- else
- {
- // Curr EOF --> | | <--New EOF
- // ------------------------------------------
- // | |///////////////| |
- // | File Contents |//// Write ////| Free | <- End of Allocation
- // | |///////////////| |
- // ------------------------------------------
- // | |
-
- // Just zero out the end of the file
- // not covered by the file size
-
- // Start offset is the New File size
- StartOffsetForZeroing.QuadPart =
- ByteOffset.QuadPart + WriteLength;
- // End offset is the New Allocation size
- EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart;
- }
- }
-
- PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart =
- ByteOffset.QuadPart + WriteLength;
-
- ASSERT( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart <= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart );
-
- Ext2UpdateFileSize( PtrIrpContext, PtrFileObject, PtrFCB );
-
- try
- {
- //
- // Zero the blocks out...
- // This routine can be used even if caching has not been initiated...
- //
- if( ZeroOut == TRUE && StartOffsetForZeroing.QuadPart != EndOffsetForZeroing.QuadPart )
- {
- CcZeroData( PtrFileObject,
- &StartOffsetForZeroing,
- &EndOffsetForZeroing,
- FALSE );
-
- if( EndOffsetForZeroing.QuadPart != PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
- {
- // Also zero out the file tip...
- CcZeroData( PtrFileObject,
- &PtrReqdFCB->CommonFCBHeader.FileSize,
- &PtrReqdFCB->CommonFCBHeader.AllocationSize,
- FALSE );
- }
- }
- }
- finally
- {
- // Swallow an exceptions that are raised...
- }
- }
- }
- }
-
- //
- // Branch here for cached vs non-cached I/O
- //
- if (!NonBufferedIo)
- {
-
- // The caller wishes to perform cached I/O.
- // Initiate caching if it hasn't been done already...
- if (PtrFileObject->PrivateCacheMap == NULL)
- {
- CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
- FALSE, // We will not utilize pin access for this file
- &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
- PtrCCB); // The context used in callbacks
- }
-
- // Check and see if this request requires a MDL returned to the caller
- if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL)
- {
- // Caller does want a MDL returned. Note that this mode
- // implies that the caller is prepared to block
- CcPrepareMdlWrite(PtrFileObject, &ByteOffset, WriteLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus));
- NumberBytesWritten = PtrIrp->IoStatus.Information;
- RC = PtrIrp->IoStatus.Status;
-
- try_return();
- }
-
- // This is a regular run-of-the-mill cached I/O request. Let the
- // Cache Manager worry about it!
-
- // First though, we need a buffer pointer (address) that is valid
- PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp);
- ASSERT(PtrSystemBuffer);
- if ( !CcCopyWrite(PtrFileObject, &(ByteOffset), WriteLength, CanWait, PtrSystemBuffer))
- {
- // The caller was not prepared to block and data is not immediately
- // available in the system cache
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- // Mark Irp Pending ...
- try_return(RC = STATUS_PENDING);
- }
- else
- {
- // We have the data
- PtrIrp->IoStatus.Status = RC;
- PtrIrp->IoStatus.Information = NumberBytesWritten = WriteLength;
- }
- }
- else // NonBuffered or Paged IO
- {
-
- ULONG Start = 0;
- ULONG End = 0;
- ULONG LogicalBlockIndex = 0;
- ULONG BytesRemaining = 0;
- ULONG BytesWrittenSoFar = 0;
- ULONG LeftOver = 0;
- ULONG LogicalBlockSize = 0;
- ULONG PhysicalBlockSize = 0;
- ULONG Index = 0;
-
- LONGLONG SingleIndirectBlockSize = 0;
- LONGLONG DoubleIndirectBlockSize = 0;
- LONGLONG TripleIndirectBlockSize = 0;
- LONGLONG DirectBlockSize = 0;
-
- LONGLONG NoOfDirectBlocks ;
- LONGLONG NoOfSingleIndirectBlocks ;
- LONGLONG NoOfDoubleIndirectBlocks ;
- LONGLONG NoOfTripleIndirectBlocks ;
-
- ULONG * PtrPinnedSIndirectBlock = NULL;
- ULONG * PtrPinnedDIndirectBlock = NULL;
- ULONG * PtrPinnedTIndirectBlock = NULL;
-
- // Used when reading a Triple Indirect Block...
- LONGLONG FirstCachedDIBlockOffset = 0;
-
- // Used when reading a Double Indirect Block...
- LONGLONG FirstCachedSIBlockOffset = 0;
-
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "[File Write] Paging IO or NonBufferedIo ", 0);
-
- // Calculating where the write should start from...
- LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
- PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize;
-
- NoOfDirectBlocks = EXT2_NDIR_BLOCKS ;
- NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
- NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
- NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
-
- DirectBlockSize = LogicalBlockSize * NoOfDirectBlocks;
- SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks;
- DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ;
- TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks;
-
- LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize);
-
- if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
- {
- //
- // Handle Triple indirect blocks?
- // A Pop up will do for now...
- //
- UNICODE_STRING ErrorMessage;
- Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" );
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "@@@@@@@@ Triple indirect blocks need to be written to! \n@@@@@@@@ This is not supported as yet!", 0);
- /* REACTOS FIXME */
- IoRaiseInformationalHardError(
- /* IO_ERR_DRIVER_ERROR */(NTSTATUS)0xC0040004L,
- &ErrorMessage,
- KeGetCurrentThread( ) );
-
- Ext2DeallocateUnicodeString( &ErrorMessage );
- RC = STATUS_INSUFFICIENT_RESOURCES;
- try_return();
- }
-
- if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize &&
- ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) )
- {
- LARGE_INTEGER VolumeByteOffset;
-
- //
- // Indirect Blocks required...
- // Read in the single indirect blocks...
- //
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "Reading in some Indirect Blocks", 0);
-
- VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_NDIR_BLOCKS ] * LogicalBlockSize;
-
- //
- // Asking the cache manager to oblige by pinning the single indirect block...
- //
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrPinnedSIndirectBCB,
- (PVOID*)&PtrPinnedSIndirectBlock ))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
-
- // Mark Irp Pending ...
- IoMarkIrpPending( PtrIrp );
- RC = STATUS_PENDING;
- try_return();
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data", 0);
- }
- }
- if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize &&
- ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
- {
- //
- // Double Indirect Blocks required...
- // Read in the double indirect blocks...
- //
-
- LONGLONG StartIndirectBlock;
- LONGLONG EndIndirectBlock;
-
-
-
- LARGE_INTEGER VolumeByteOffset;
-
- DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0);
-
- VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
-
- //
- // Asking the cache manager to oblige by pinning the double indirect block...
- //
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrPinnedDIndirectBCB,
- (PVOID*)&PtrPinnedDIndirectBlock ))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
-
- // Mark Irp Pending ...
- IoMarkIrpPending( PtrIrp );
- RC = STATUS_PENDING;
- try_return();
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
-
- // So far so good...
- // Now determine the single indirect blocks that will have to be read in...
- if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
- {
- // Request doesnot require any single indirect or direct blocks
- StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
- StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
- StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
- }
- else
- {
- StartIndirectBlock = 0;
- }
-
- FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks;
-
- if( ByteOffset.QuadPart + WriteLength >=
- DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
- {
- EndIndirectBlock = DoubleIndirectBlockSize;
- }
- else
- {
- EndIndirectBlock = ByteOffset.QuadPart + WriteLength -
- (DirectBlockSize + SingleIndirectBlockSize);
- }
- EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
- EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
-
- DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
-
- PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
- {
- ULONG i;
-
- for( i = 0; i < DIArrayCount; i++ )
- {
- VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrDIArray[i].PtrBCB,
- (PVOID*)&PtrDIArray[i].PtrSIBlocks))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- IoMarkIrpPending( PtrIrp );
- DIArrayCount = i;
- try_return(RC = STATUS_PENDING);
-
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
- }
- }
- }
-
-/* {
- //
- // Double Indirect Blocks required...
- // Read in the double indirect blocks...
- //
-
- LONGLONG StartIndirectBlock;
- LONGLONG EndIndirectBlock;
-
- LARGE_INTEGER VolumeByteOffset;
-
- DebugTrace(DEBUG_TRACE_MISC, "Reading in some Double Indirect Blocks", 0);
-
- VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
-
- //
- // Asking the cache manager to oblige by pinning the double indirect block...
- //
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrPinnedDIndirectBCB,
- (PVOID*)&PtrPinnedDIndirectBlock ))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
-
- // Mark Irp Pending ...
- IoMarkIrpPending( PtrIrp );
- RC = STATUS_PENDING;
- try_return();
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
-
- // So far so good...
- // Now determine the single indirect blocks that will have to be read in...
- if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
- {
- // Request doesnot require any single indirect or direct blocks
- StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
- StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
- StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
- }
- else
- {
- StartIndirectBlock = 0;
- }
-
- if( ByteOffset.QuadPart + WriteLength >=
- DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
- {
- EndIndirectBlock = DoubleIndirectBlockSize;
- }
- else
- {
- EndIndirectBlock = ByteOffset.QuadPart + WriteLength -
- (DirectBlockSize + SingleIndirectBlockSize);
- if( EndIndirectBlock % LogicalBlockSize )
- {
- EndIndirectBlock += LogicalBlockSize;
- }
- EndIndirectBlock = EndIndirectBlock / LogicalBlockSize;
- if( EndIndirectBlock % NoOfSingleIndirectBlocks)
- {
- EndIndirectBlock += NoOfSingleIndirectBlocks;
- }
- EndIndirectBlock = EndIndirectBlock / NoOfSingleIndirectBlocks;
- }
- DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
- PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
- {
- ULONG i;
-
- for( i = 0; i < DIArrayCount; i++ )
- {
- VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrDIArray[i].PtrBCB,
- (PVOID*)&PtrDIArray[i].PtrSIBlocks))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- IoMarkIrpPending( PtrIrp );
- DIArrayCount = i;
- try_return(RC = STATUS_PENDING);
-
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
- }
- }
- }
-*/
- if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
- {
- //
- // Triple Indirect Blocks required...
- // Read in the triple indirect blocks...
- //
- LONGLONG StartTIndirectBlock;
- LONGLONG EndTIndirectBlock;
-
- LONGLONG StartDIndirectBlock;
- LONGLONG EndDIndirectBlock;
- LONGLONG StartIndirectBlock;
- LONGLONG EndIndirectBlock;
-
- LONGLONG ByteOffsetTillHere = 0;
-
- PBCB TempDIBCB;
- LONG* TempDIBuffer;
-
- ULONG TIArrayIndex = 0;
-
- LARGE_INTEGER VolumeByteOffset;
-
- DebugTrace(DEBUG_TRACE_MISC, "Reading in some Triple Indirect Blocks", 0);
-
- VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
-
- DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffset = 0x%I64X", ByteOffset );
- DebugTrace(DEBUG_TRACE_TRIPLE, "WriteLength = 0x%lX", WriteLength );
- DebugTrace(DEBUG_TRACE_TRIPLE, "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
- //
- // Asking the cache manager to oblige by pinning the triple indirect block...
- //
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrPinnedTIndirectBCB,
- (PVOID*)&PtrPinnedTIndirectBlock ))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
-
- // Mark Irp Pending ...
- IoMarkIrpPending( PtrIrp );
- RC = STATUS_PENDING;
- try_return();
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
-
- // Determine the no of BCBs that need to be saved...
- if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
- {
- StartTIndirectBlock = ByteOffset.QuadPart;
- }
- else
- {
- StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
- }
- EndTIndirectBlock = ByteOffset.QuadPart + WriteLength;
- TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2;
-
-
- PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
-
- // Now determine the double indirect blocks that will have to be read in...
- if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
- {
- // Request doesnot require any single indirect or direct blocks
- StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
- StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize;
- StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks;
-
- ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ;
- //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize;
- FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
- }
- else
- {
- ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
- FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
- StartDIndirectBlock = 0;
- }
-
- DebugTrace(DEBUG_TRACE_TRIPLE, "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere );
-
- EndDIndirectBlock = ByteOffset.QuadPart + WriteLength -
- (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
- EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ;
- EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks;
-
- {
- // Reading in the necessary double indirect bocks...
- ULONG i;
- LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock;
-
- for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize)
- {
- VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize;
-
- DebugTrace(DEBUG_TRACE_TRIPLE, "Double VolOffset = 0x%I64X", VolumeByteOffset );
-
- if( !CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &TempDIBCB,
- (PVOID*)&TempDIBuffer) )
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- IoMarkIrpPending( PtrIrp );
- try_return(RC = STATUS_PENDING);
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
-
- if( ByteOffset.QuadPart > ByteOffsetTillHere)
- {
- StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere);
- StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
- StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
-
- if( TIArrayIndex == 0 )
- {
- FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks;
- }
- }
- else
- {
- StartIndirectBlock = 0;
- }
-
- if( ByteOffset.QuadPart + WriteLength >= ByteOffsetTillHere + DoubleIndirectBlockSize)
- {
- EndIndirectBlock = DoubleIndirectBlockSize;
- }
- else
- {
- EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ByteOffsetTillHere;
- }
- EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
- EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
-
- {
- ULONG i;
-
- for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ )
- {
- VolumeByteOffset.QuadPart = TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize;
- DebugTrace(DEBUG_TRACE_TRIPLE, "Single VolOffset = 0x%I64X", VolumeByteOffset );
-
- if (!CcMapData( PtrVCB->PtrStreamFileObject,
- &VolumeByteOffset,
- LogicalBlockSize,
- CanWait,
- &PtrTIArray[ TIArrayIndex ].PtrBCB,
- (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks))
- {
- CompleteIrp = FALSE;
- PostRequest = TRUE;
- IoMarkIrpPending( PtrIrp );
- DIArrayCount = i;
- try_return(RC = STATUS_PENDING);
-
- DebugTrace(DEBUG_TRACE_ASYNC, "Cache read failiure while reading in volume meta data - Retrying", 0);
- }
- TIArrayIndex++;
- }
- }
- CcUnpinData( TempDIBCB );
- TempDIBCB = NULL;
- TempDIBuffer = NULL;
- }
- }
- TIArrayCount = TIArrayIndex;
-
- DebugTrace(DEBUG_TRACE_TRIPLE, "TIArrayCount = %ld", TIArrayCount );
- DebugTrace(DEBUG_TRACE_TRIPLE, "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset );
- }
-
- //
- // Allocating memory for IO Runs
- //
- Index = ( (WriteLength - 2) / LogicalBlockSize + 2 );
- PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) ) );
-
-
- Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) );
- BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart );
-
- if( WriteLength > BytesRemaining )
- End = Start + BytesRemaining;
- else
- End = Start + WriteLength;
- BytesWrittenSoFar = 0;
-
- Index = 0;
- DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "\nDetermining the write IRPs that have to be passed down...", 0);
-
- while( 1 )
- {
- BytesWrittenSoFar += (End-Start);
- if( LogicalBlockIndex < EXT2_NDIR_BLOCKS )
- {
- // Direct Block
- PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ];
- }
- else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) )
- {
- // Single Indirect Block
- PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - EXT2_NDIR_BLOCKS ];
- }
- else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks) )
- {
- LONGLONG BlockNo;
- LONGLONG IBlockIndex;
- LONGLONG BlockIndex;
-
- BlockNo = LogicalBlockIndex - FirstCachedSIBlockOffset;
- IBlockIndex = BlockNo / NoOfSingleIndirectBlocks;
- BlockIndex = BlockNo % NoOfSingleIndirectBlocks;
-
- // Double Indirect Block
- PtrIoRuns[ Index ].LogicalBlock =
- PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];
- }
- else
- {
- // Triple Indirect Block
- LONGLONG BlockNo;
- LONGLONG IBlockIndex;
- LONGLONG BlockIndex;
- BlockNo = LogicalBlockIndex - FirstCachedDIBlockOffset;
- IBlockIndex = BlockNo / NoOfSingleIndirectBlocks;
- BlockIndex = BlockNo % NoOfSingleIndirectBlocks;
-
- DbgPrint( "\nBlock No : 0x%I64X IBlockIndex = 0x%I64X BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex);
-
- if( IBlockIndex >= TIArrayCount )
- {
- Ext2BreakPoint();
- }
- if( BlockIndex >= LogicalBlockSize )
- {
- Ext2BreakPoint();
- }
-
- PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];
- DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock );
- }
-
- if( PtrIoRuns[ Index ].LogicalBlock == 0 )
- {
- //
- // Something is wrong...
- //
- Ext2BreakPoint();
- break;
-
- }
- PtrIoRuns[ Index ].StartOffset = Start;
- PtrIoRuns[ Index ].EndOffset = End;
- PtrIoRuns[ Index ].PtrAssociatedIrp = NULL;
-
- DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Index = (%ld)", LogicalBlockIndex );
- DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Logical Block = (0x%lX)", PtrFCB->IBlock[ LogicalBlockIndex ] );
- DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Start = (0x%lX)", Start );
- DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " End = (0x%lX) ", End );
- DebugTrace( DEBUG_TRACE_WRITE_DETAILS, " Bytes written (0x%lX)", BytesWrittenSoFar );
-
-
-
- if( BytesWrittenSoFar >= WriteLength )
- break;
- LogicalBlockIndex++;
- Start = 0;
- LeftOver = WriteLength - BytesWrittenSoFar;
- if( LeftOver > LogicalBlockSize )
- End = LogicalBlockSize;
- else
- End = LeftOver;
- // Loop over to make the write request...
- Index++;
- }
-
- //
- // Unpin the Indirect Blocks
- //
- if( PtrPinnedSIndirectBCB )
- {
- CcUnpinData( PtrPinnedSIndirectBCB );
- PtrPinnedSIndirectBCB = NULL;
- PtrPinnedSIndirectBlock = NULL;
- }
- if( PtrPinnedDIndirectBCB )
- {
- CcUnpinData( PtrPinnedDIndirectBCB );
- PtrPinnedDIndirectBCB = NULL;
- PtrPinnedDIndirectBlock = NULL;
- }
- //
- // Pass down Associated IRPs to the Target Device Driver...
- //
- DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "Passing down the Write IRPs to the disk driver...", 0 );
-
- RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, WriteLength, PtrIrpContext, PtrFCB, SynchronousIo );
-
- //
- // Irp will be completed automatically
- // when all the Associated IRPs are completed
- //
- if( RC == STATUS_SUCCESS || RC == STATUS_PENDING )
- {
- CompleteIrp = FALSE;
- }
- try_return();
- }
-
- try_exit: NOTHING;
-
- }
- finally
- {
- if ( PtrIoRuns )
- {
- DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Write]", PtrIoRuns );
- ExFreePool( PtrIoRuns );
- }
- if( PtrPinnedSIndirectBCB )
- {
- CcUnpinData( PtrPinnedSIndirectBCB );
- PtrPinnedSIndirectBCB = NULL;
- }
- if( PtrPinnedDIndirectBCB )
- {
- CcUnpinData( PtrPinnedDIndirectBCB );
- PtrPinnedDIndirectBCB = NULL;
- }
- if ( PtrDIArray )
- {
- ULONG i;
- for( i = 0; i < DIArrayCount; i++ )
- {
- CcUnpinData( PtrDIArray->PtrBCB );
- }
- DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [Read]", PtrDIArray );
- ExFreePool( PtrDIArray );
- PtrDIArray = NULL;
- }
- // Release resources ...
- //
- if (PtrResourceAcquired)
- {
- Ext2ReleaseResource(PtrResourceAcquired);
-
- DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Write]", 0);
- DebugTraceState( "Resource AC:0x%LX SW:0x%LX EX:0x%LX [Write]",
- PtrResourceAcquired->ActiveCount,
- PtrResourceAcquired->NumberOfExclusiveWaiters,
- PtrResourceAcquired->NumberOfSharedWaiters );
-
- if( PtrFileObject )
- {
- DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Write]", PtrFileObject);
- }
- if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) )
- {
- DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [Write]", 0);
- }
- else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) )
- {
- DebugTrace(DEBUG_TRACE_MISC, "*** VCBPaging Released [Write]", 0);
- }
- else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) )
- {
- DebugTrace(DEBUG_TRACE_MISC, "*** FCB Paging Resource Released [Write]", 0);
- }
- else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) )
- {
- DebugTrace(DEBUG_TRACE_MISC, "*** FCB Resource Released [Write]", 0);
- }
- else
- {
- DebugTrace(DEBUG_TRACE_MISC, "*** Unknown Resource Released [Write]", 0);
- }
-
- PtrResourceAcquired = NULL;
- }
-
- if (PostRequest)
- {
- RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
- }
- else if ( CompleteIrp && !(RC == STATUS_PENDING))
- {
- // For synchronous I/O, the FSD must maintain the current byte offset
- // Do not do this however, if I/O is marked as paging-io
- if (SynchronousIo && !PagingIo && NT_SUCCESS(RC))
- {
- PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset,
- RtlConvertUlongToLargeInteger((unsigned long)NumberBytesWritten));
- }
-
- // If the write completed successfully and this was not a paging-io
- // operation, set a flag in the CCB that indicates that a write was
- // performed and that the file time should be updated at cleanup
- if (NT_SUCCESS(RC) && !PagingIo)
- {
- Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_MODIFIED);
- }
-
- // If the file size was changed, set a flag in the FCB indicating that
- // this occurred.
-
- // If the request failed, and we had done some nasty stuff like
- // extending the file size (including informing the Cache Manager
- // about the new file size), and allocating on-disk space etc., undo
- // it at this time.
-
- // Can complete the IRP here if no exception was encountered
- if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION))
- {
- PtrIrp->IoStatus.Status = RC;
- PtrIrp->IoStatus.Information = NumberBytesWritten;
-
- // complete the IRP
- IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
- }
-
- // Free up the Irp Context
- Ext2ReleaseIrpContext(PtrIrpContext);
-
- } // can we complete the IRP ?
- else
- {
- // Free up the Irp Context
- Ext2ReleaseIrpContext(PtrIrpContext);
- }
- } // end of "finally" processing
- return(RC);
+ Ext2QueueRequest(IrpContext);
}
-/*************************************************************************
-*
-* Function: Ext2DeferredWriteCallBack()
-*
-* Description:
-* Invoked by the cache manager in the context of a worker thread.
-* Typically, you can simply post the request at this point (just
-* as you would have if the original request could not block) to
-* perform the write in the context of a system worker thread.
-*
-* Expected Interrupt Level (for execution) :
-*
-* IRQL_PASSIVE_LEVEL
-*
-* Return Value: None
-*
-*************************************************************************/
-void NTAPI Ext2DeferredWriteCallBack (
-void *Context1, // Should be PtrIrpContext
-void *Context2 ) // Should be PtrIrp
+NTSTATUS
+Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext)
{
- // You should typically simply post the request to your internal
- // queue of posted requests (just as you would if the original write
- // could not be completed because the caller could not block).
- // Once you post the request, return from this routine. The write
- // will then be retried in the context of a system worker thread
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ PEXT2_VCB Vcb;
+ PEXT2_CCB Ccb;
+ PEXT2_FCBVCB FcbOrVcb;
+ PFILE_OBJECT FileObject;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IoStackLocation;
+
+ 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;
+
+ _SEH2_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;
+ _SEH2_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;
+ _SEH2_LEAVE;
+ }
+
+ if (Nocache &&
+ (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
+ Length & (SECTOR_SIZE - 1))) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+
+ if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
+ ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
+ Status = STATUS_PENDING;
+ _SEH2_LEAVE;
+ }
+
+ if (ByteOffset.QuadPart >=
+ Vcb->PartitionInformation.PartitionLength.QuadPart ) {
+ Irp->IoStatus.Information = 0;
+ Status = STATUS_END_OF_FILE;
+ _SEH2_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;
+
+ _SEH2_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;
+ _SEH2_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;
+ _SEH2_LEAVE;
+ }
+
+ if (!CcCopyWrite( Vcb->Volume,
+ (PLARGE_INTEGER)(&ByteOffset),
+ Length,
+ TRUE,
+ Buffer )) {
+ Status = STATUS_PENDING;
+ _SEH2_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)) {
+ _SEH2_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;
+ _SEH2_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) {
+ _SEH2_LEAVE;
+ }
+
+ } else {
+
+ Irp->IoStatus.Information = Length;
+ Status = STATUS_SUCCESS;
+ _SEH2_LEAVE;
+ }
+
+ } else {
+
+ Length &= ~((ULONG)SECTOR_SIZE - 1);
+
+ Status = Ext2LockUserBuffer(
+ IrpContext->Irp,
+ Length,
+ IoWriteAccess );
+
+ if (!NT_SUCCESS(Status)) {
+ _SEH2_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) {
+ _SEH2_LEAVE;
+ }
+ }
+
+ } _SEH2_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);
+ }
+ } _SEH2_END;
+
+ return Status;
+}
+
+NTSTATUS
+Ext2WriteInode (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONGLONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ IN BOOLEAN bDirectIo,
+ OUT PULONG BytesWritten
+)
+{
+ PEXT2_EXTENT Chain = NULL;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ _SEH2_TRY {
+
+ if (BytesWritten) {
+ *BytesWritten = 0;
+ }
+
+ Status = Ext2BuildExtents (
+ IrpContext,
+ Vcb,
+ Mcb,
+ Offset,
+ Size,
+ IsMcbDirectory(Mcb) ? FALSE : TRUE,
+ &Chain
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ _SEH2_LEAVE;
+ }
+
+ if (Chain == NULL) {
+ Status = STATUS_SUCCESS;
+ _SEH2_LEAVE;
+ }
+
+ if (bDirectIo) {
+
+ ASSERT(IrpContext != NULL);
+
+ //
+ // We assume the offset is aligned.
+ //
+
+ Status = Ext2ReadWriteBlocks(
+ IrpContext,
+ Vcb,
+ Chain,
+ Size
+ );
+
+ } else {
+
+ PEXT2_EXTENT Extent;
+ for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {
+
+ if ( !Ext2SaveBuffer(
+ IrpContext,
+ Vcb,
+ Extent->Lba,
+ Extent->Length,
+ (PVOID)((PUCHAR)Buffer + Extent->Offset)
+ )) {
+ _SEH2_LEAVE;
+ }
+ }
+
+ if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
+
+ DEBUG(DL_FLP, ("Ext2WriteInode is starting FlushingDpc...\n"));
+ Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
+ }
+
+ Status = STATUS_SUCCESS;
+ }
+
+ } _SEH2_FINALLY {
+
+ if (Chain) {
+ Ext2DestroyExtentChain(Chain);
+ }
+
+ if (NT_SUCCESS(Status) && BytesWritten) {
+ *BytesWritten = Size;
+ }
+ } _SEH2_END;
+
+ return Status;
+}
+
+NTSTATUS
+Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PEXT2_VCB Vcb;
+ PEXT2_FCB Fcb;
+ PEXT2_CCB Ccb;
+ PFILE_OBJECT FileObject;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStackLocation;
+ PUCHAR Buffer;
+
+ 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;
+#ifndef __REACTOS__
+ BOOLEAN UpdateFileValidSize = FALSE;
+#endif
+ BOOLEAN FileSizesChanged = FALSE;
+ BOOLEAN rc;
+
+
+ _SEH2_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)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ _SEH2_LEAVE;
+ }
+
+ if (IsFileDeleted(Fcb->Mcb) ||
+ (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) {
+ Status = STATUS_FILE_DELETED;
+ _SEH2_LEAVE;
+ }
+
+ if (Length == 0) {
+ Irp->IoStatus.Information = 0;
+ Status = STATUS_SUCCESS;
+ _SEH2_LEAVE;
+ }
+
+ if (Nocache && ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
+ (Length & (SECTOR_SIZE - 1))) ) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+
+ if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
+ ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
+ Status = STATUS_PENDING;
+ _SEH2_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;
+ _SEH2_LEAVE;
+ }
+ }
+ }
+
+ if (IsWritingToEof(ByteOffset)) {
+ ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
+ }
+
+ if (IsDirectory(Fcb) && !PagingIo) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ _SEH2_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;
+ _SEH2_LEAVE;
+ }
+ PagingIoResourceAcquired = TRUE;
+
+ if ( (ByteOffset.QuadPart + Length) > Fcb->Header.AllocationSize.QuadPart) {
+
+ if ( ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
+
+ Status = STATUS_END_OF_FILE;
+ Irp->IoStatus.Information = 0;
+ _SEH2_LEAVE;
+
+ } else {
+
+ Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
+ }
+ }
+
+ } else {
+
+ if (IsDirectory(Fcb)) {
+ _SEH2_LEAVE;
+ }
+
+ if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) {
+ Status = STATUS_PENDING;
+ _SEH2_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;
+ _SEH2_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;
+ _SEH2_LEAVE;
+ }
+
+ if (Ccb != NULL) {
+ Status = FsRtlCheckOplock( &Fcb->Oplock,
+ Irp,
+ IrpContext,
+ Ext2OplockComplete,
+ Ext2LockIrp );
+
+ if (Status != STATUS_SUCCESS) {
+ OpPostIrp = TRUE;
+ _SEH2_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;
+ _SEH2_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;
+ }
+ _SEH2_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;
+ _SEH2_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();
+ _SEH2_LEAVE;
+ }
+ }
+
+ if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) {
+ if (Ext2CanIWait() ||
+ !CcCopyWrite(FileObject, &ByteOffset, Length, TRUE, Buffer)) {
+ Status = STATUS_PENDING;
+ DbgBreak();
+ _SEH2_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 + Length > Fcb->Header.ValidDataLength.QuadPart ) {
+ 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();
+ _SEH2_LEAVE;
+ }
+ }
+ }
+ }
+
+ Status = Ext2LockUserBuffer(
+ IrpContext->Irp,
+ Length,
+ IoReadAccess );
+
+ if (!NT_SUCCESS(Status)) {
+ _SEH2_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) && !PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
+
+ if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
+
+ FileSizesChanged = TRUE;
+
+ 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;
+ }
+
+ if (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 );
+ }
+
+ } _SEH2_FINALLY {
+
+ /*
+ * in case we got excpetions, we need revert MajorFunction
+ * back to IRP_MJ_WRITE. The reason we do this, if 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);
+ }
+ }
+ } _SEH2_END;
+
+ 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
+Ext2WriteComplete (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PFILE_OBJECT FileObject;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ _SEH2_TRY {
+
+ ASSERT(IrpContext);
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ FileObject = IrpContext->FileObject;
+
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ CcMdlWriteComplete(FileObject, &(IrpSp->Parameters.Write.ByteOffset), Irp->MdlAddress);
+ Irp->MdlAddress = NULL;
+ Status = STATUS_SUCCESS;
+
+ } _SEH2_FINALLY {
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ } _SEH2_END;
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2Write (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ NTSTATUS Status;
+ PEXT2_FCBVCB FcbOrVcb;
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+ PEXT2_VCB Vcb;
+ BOOLEAN bCompleteRequest = TRUE;
+
+ ASSERT(IrpContext);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ _SEH2_TRY {
+
+ if (IsFlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE)) {
+
+ Status = Ext2WriteComplete(IrpContext);
+ bCompleteRequest = FALSE;
+
+ } else {
+
+ DeviceObject = IrpContext->DeviceObject;
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ _SEH2_LEAVE;
+ }
+ FileObject = IrpContext->FileObject;
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+
+ if (Vcb->Identifier.Type != EXT2VCB ||
+ Vcb->Identifier.Size != sizeof(EXT2_VCB) ) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+
+ if (IsVcbReadOnly(Vcb)) {
+ Status = STATUS_MEDIA_WRITE_PROTECTED;
+ _SEH2_LEAVE;
+ }
+
+ if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
+ Vcb->LockFile != FileObject ) {
+ Status = STATUS_ACCESS_DENIED;
+ _SEH2_LEAVE;
+ }
+
+ FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
+
+ if (FcbOrVcb->Identifier.Type == EXT2VCB) {
+
+ Status = Ext2WriteVolume(IrpContext);
+ if (!NT_SUCCESS(Status)) {
+ DbgBreak();
+ }
+ bCompleteRequest = FALSE;
+
+ } else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
+
+ if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
+ Status = STATUS_TOO_LATE;
+ _SEH2_LEAVE;
+ }
+
+ Status = Ext2WriteFile(IrpContext);
+ if (!NT_SUCCESS(Status)) {
+ DbgBreak();
+ }
+
+ bCompleteRequest = FALSE;
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ } _SEH2_FINALLY {
+
+ if (bCompleteRequest) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ } _SEH2_END;
+
+ return Status;
}