Home | Info | Community | Development | myReactOS | Contact Us
Definition at line 100 of file write.c.
Referenced by Ext2CommonDispatch(), and Ext2Write().
{ 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); }