ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

write.c
Go to the documentation of this file.
00001 /*************************************************************************
00002 *
00003 * File: write.c
00004 *
00005 * Module: Ext2 File System Driver (Kernel mode execution only)
00006 *
00007 * Description:
00008 *   Contains code to handle the "Write" dispatch entry point.
00009 *
00010 * Author: Manoj Paul Joseph
00011 *
00012 *
00013 *************************************************************************/
00014 
00015 #include            "ext2fsd.h"
00016 
00017 // define the file specific bug-check id
00018 #define         EXT2_BUG_CHECK_ID               EXT2_FILE_WRITE
00019 
00020 #define         DEBUG_LEVEL                     (DEBUG_TRACE_WRITE)
00021 
00022 
00023 /*************************************************************************
00024 *
00025 * Function: Ext2Write()
00026 *
00027 * Description:
00028 *   The I/O Manager will invoke this routine to handle a write
00029 *   request
00030 *
00031 * Expected Interrupt Level (for execution) :
00032 *
00033 *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
00034 *   to be deferred to a worker thread context)
00035 *
00036 * Return Value: STATUS_SUCCESS/Error
00037 *
00038 *************************************************************************/
00039 NTSTATUS NTAPI Ext2Write(
00040 PDEVICE_OBJECT      DeviceObject,       // the logical volume device object
00041 PIRP                    Irp)                    // I/O Request Packet
00042 {
00043     NTSTATUS                RC = STATUS_SUCCESS;
00044     PtrExt2IrpContext   PtrIrpContext = NULL;
00045     BOOLEAN             AreWeTopLevel = FALSE;
00046 
00047     DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Write IRP Received...", 0);
00048 
00049     //  Ext2BreakPoint();
00050 
00051     FsRtlEnterFileSystem();
00052     ASSERT(DeviceObject);
00053     ASSERT(Irp);
00054 
00055     // set the top level context
00056     AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
00057 
00058     try 
00059     {
00060         // get an IRP context structure and issue the request
00061         PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
00062         ASSERT(PtrIrpContext);
00063 
00064         RC = Ext2CommonWrite(PtrIrpContext, Irp);
00065     } 
00066     except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
00067     {
00068         RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
00069         Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
00070     }
00071 
00072     if (AreWeTopLevel) 
00073     {
00074         IoSetTopLevelIrp(NULL);
00075     }
00076 
00077     FsRtlExitFileSystem();
00078 
00079     return(RC);
00080 }
00081 
00082 
00083 /*************************************************************************
00084 *
00085 * Function: Ext2CommonWrite()
00086 *
00087 * Description:
00088 *   The actual work is performed here. This routine may be invoked in one'
00089 *   of the two possible contexts:
00090 *   (a) in the context of a system worker thread
00091 *   (b) in the context of the original caller
00092 *
00093 * Expected Interrupt Level (for execution) :
00094 *
00095 *  IRQL_PASSIVE_LEVEL
00096 *
00097 * Return Value: STATUS_SUCCESS/Error
00098 *
00099 *************************************************************************/
00100 NTSTATUS NTAPI Ext2CommonWrite(
00101     PtrExt2IrpContext           PtrIrpContext,
00102     PIRP                        PtrIrp)
00103 {
00104 
00105     NTSTATUS                RC = STATUS_SUCCESS;
00106     PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
00107     LARGE_INTEGER           ByteOffset;
00108     uint32                  WriteLength = 0;
00109     uint32                  NumberBytesWritten = 0;
00110     PFILE_OBJECT            PtrFileObject = NULL;
00111     PtrExt2FCB              PtrFCB = NULL;
00112     PtrExt2CCB              PtrCCB = NULL;
00113     PtrExt2VCB              PtrVCB = NULL;
00114     PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
00115     PERESOURCE              PtrResourceAcquired = NULL;
00116     void                    *PtrSystemBuffer = NULL;
00117 
00118     BOOLEAN                 CompleteIrp = TRUE;
00119     BOOLEAN                 PostRequest = FALSE;
00120 
00121     BOOLEAN                 CanWait = FALSE;
00122     BOOLEAN                 PagingIo = FALSE;
00123     BOOLEAN                 NonBufferedIo = FALSE;
00124     BOOLEAN                 SynchronousIo = FALSE;
00125     BOOLEAN                 IsThisADeferredWrite = FALSE;
00126     BOOLEAN                 WritingAtEndOfFile = FALSE;
00127 
00128     EXT2_IO_RUN             *PtrIoRuns = NULL;
00129             
00130     PBCB        PtrPinnedSIndirectBCB = NULL;
00131     PBCB        PtrPinnedDIndirectBCB = NULL;
00132     PBCB        PtrPinnedTIndirectBCB = NULL;
00133     
00134     //  Used to cache the Single Indirect blocks pointed to by 
00135     //  the Double Indirect block
00136     PEXT2_SIBLOCKS          PtrDIArray = NULL;
00137     ULONG                   DIArrayCount = 0;
00138 
00139     //  Used to cache the Single Indirect blocks pointed to by 
00140     //  the Triple Indirect block
00141     PEXT2_SIBLOCKS          PtrTIArray = NULL;
00142     ULONG                   TIArrayCount = 0;
00143 
00144 
00145     try 
00146     {
00147         // First, get a pointer to the current I/O stack location
00148         PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
00149         ASSERT(PtrIoStackLocation);
00150 
00151         PtrFileObject = PtrIoStackLocation->FileObject;
00152         ASSERT(PtrFileObject);
00153 
00154         // If this happens to be a MDL write complete request, then
00155         // allocated MDL can be freed. 
00156         if(PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) 
00157         {
00158             // Caller wants to tell the Cache Manager that a previously
00159             // allocated MDL can be freed.
00160             Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, FALSE);
00161             // The IRP has been completed.
00162             CompleteIrp = FALSE;
00163             try_return(RC = STATUS_SUCCESS);
00164         }
00165 
00166         // If this is a request at IRQL DISPATCH_LEVEL, then post the request 
00167         if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) 
00168         {
00169             CompleteIrp = FALSE;
00170             PostRequest = TRUE;
00171             try_return(RC = STATUS_PENDING);
00172         }
00173 
00174 
00175         // Get the FCB and CCB pointers
00176         Ext2GetFCB_CCB_VCB_FromFileObject ( 
00177             PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
00178 
00179 
00180         // Get some of the parameters supplied to us
00181         ByteOffset = PtrIoStackLocation->Parameters.Write.ByteOffset;
00182         WriteLength = PtrIoStackLocation->Parameters.Write.Length;
00183 
00184         CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
00185         PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE);
00186         NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE);
00187         SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE);
00188 
00189         if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
00190         {
00191             DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Write File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
00192         }
00193         else
00194         {
00195             DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Write File Name : -null-", 0);
00196         }
00197         
00198         DebugTrace( DEBUG_TRACE_SPECIAL,   "  ->ByteCount           = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length);
00199         DebugTrace( DEBUG_TRACE_SPECIAL,   "  ->ByteOffset.LowPart  = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart);
00200         
00201         if( CanWait )
00202         {
00203             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Can Wait ", 0 );
00204         }
00205         else
00206         {
00207             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Can't Wait ", 0 );
00208         }
00209         
00210         if( PagingIo )
00211         {
00212             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Paging Io ", 0 );
00213         }
00214         else
00215         {
00216             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Not Paging Io", 0 );
00217         }
00218 
00219         if( SynchronousIo )
00220         {
00221             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->SynchronousIo ", 0 );
00222         }
00223         else
00224         {
00225             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->ASynchronousIo ", 0 );
00226         }
00227 
00228         if( NonBufferedIo )
00229         {
00230             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->NonBufferedIo", 0 );
00231         }
00232         else
00233         {
00234             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->BufferedIo", 0 );
00235         }
00236         // Check at this point whether the file object being
00237         // used for write really did have write permission requested when the
00238         // create/open operation was performed. 
00239         // Don't do this for paging io...
00240 
00241         if (WriteLength == 0) 
00242         {
00243             // a 0 byte write can be immediately succeeded
00244             try_return();
00245         }
00246 
00247         // Is this a write of the volume itself ?
00248         if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) 
00249         {
00250             //
00251             //      >>>>>>>>>>>>>>>>>>      VOLUME WRITE      <<<<<<<<<<<<<<
00252             //
00253 
00254             //  Validate the offset and length first...
00255             //  .......................................
00256 
00257             // Acquire the volume resource exclusively
00258             if( PtrFileObject )
00259             {
00260                 DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Write]", PtrFileObject);
00261             }
00262 
00263             if( PagingIo )
00264             {
00265                 //  This is Paging IO...
00266 
00267                 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire VCBPaging Exclusively [Write]", 0);
00268                 DebugTraceState( "VCBPaging       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Write]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters );
00269                 
00270                 if( !ExAcquireResourceExclusiveLite( &( PtrVCB->PagingIoResource ), FALSE ) )
00271                 {
00272                     // post the request to be processed in the context of a worker thread
00273                     DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCBPaging Acquisition FAILED [Write]", 0);
00274                     CompleteIrp = FALSE;
00275                     PostRequest = TRUE;
00276                     try_return(RC = STATUS_PENDING);
00277                 }
00278 
00279                 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCBPaging Acquired [Write]", 0);
00280                 PtrResourceAcquired = &(PtrVCB->PagingIoResource);
00281             }
00282             else
00283             {
00284                 //  This is not Paging IO...
00285 
00286                 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire VCB Exclusively [Write]", 0);
00287                 DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Write]", PtrVCB->VCBResource.ActiveCount, 
00288                     PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
00289                 
00290                 if( !ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) )
00291                 {
00292                     // post the request to be processed in the context of a worker thread
00293                     DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCB Acquisition FAILED [Write]", 0);
00294                     CompleteIrp = FALSE;
00295                     PostRequest = TRUE;
00296                     try_return(RC = STATUS_PENDING);
00297                 }
00298 
00299                 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCB Acquired [Write]", 0);
00300                 PtrResourceAcquired = &(PtrVCB->VCBResource);
00301             }
00302             
00303             // Validate the caller supplied offset here
00304             if( !PagingIo )
00305             {
00306                 if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart )
00307                 {
00308                     //  Write extending beyond the end of volume.
00309                     //  Deny access...
00310                     //
00311                     RC = STATUS_END_OF_FILE;
00312                     NumberBytesWritten = 0;
00313                     try_return();
00314                 }
00315             }
00316 
00317             // Lock the callers buffer
00318             if (!NT_SUCCESS(RC = Ext2LockCallersBuffer(PtrIrp, TRUE, WriteLength))) 
00319             {
00320                 try_return();
00321             }
00322 
00323             // Forward the request to the lower level driver
00324             if( PagingIo || NonBufferedIo )
00325             {
00326                 DebugTrace(DEBUG_TRACE_WRITE_DETAILS,  "[Volume Write] PagingIo or NonBufferedIo ", 0);
00327                 CompleteIrp = FALSE;
00328 
00329                 //
00330                 //  Do the write operation...
00331                 //  Send down the IRP to the lower level driver...
00332                 //
00333                 //  Returned Informations and Status will be set by the lower level driver...
00334                 //  The IRP will also be completed by the lower level driver...
00335 
00336                 RC = Ext2PassDownSingleReadWriteIRP (
00337                         PtrIrpContext, PtrIrp, PtrVCB, 
00338                         ByteOffset, WriteLength, SynchronousIo );
00339 
00340                 try_return();
00341             }
00342             else
00343             {
00344                 PBCB        PtrBCB = NULL;
00345                 PVOID       PtrBuffer = NULL;
00346 
00347                 DebugTrace(DEBUG_TRACE_READ_DETAILS,  "[Volume Write] BufferedIo ", 0);
00348                                 //
00349                 //  Let the cache manager worry about this write...
00350                 //  Pinned access should have been initiated.
00351                 //  But checking anyway...
00352                 //
00353                 ASSERT( PtrVCB->PtrStreamFileObject );
00354                 ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap );
00355 
00356                 CcPreparePinWrite( 
00357                     PtrVCB->PtrStreamFileObject,
00358                     &ByteOffset,
00359                     WriteLength,
00360                     FALSE,          //  Don't Zero...
00361                     TRUE,           //  Can Wait...
00362                     &PtrBCB,
00363                     &PtrBuffer);
00364 
00365                 //  Do the write now...
00366                 //  Write to the Pinned buffer...
00367                 //  Cache Manager will do the disk write...
00368                 RtlCopyBytes( PtrBuffer, PtrSystemBuffer, WriteLength );
00369                 //  CcSetDirtyPinnedData( PtrBCB, NULL );
00370                 CcUnpinData( PtrBCB );
00371                 PtrBuffer = NULL;
00372                 PtrBCB = NULL;
00373 
00374                 NumberBytesWritten = WriteLength;
00375 
00376                 //  Go ahead and complete the IRP...
00377             }
00378             try_return();
00379         }
00380 
00381       
00382         IsThisADeferredWrite = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE);
00383 
00384         if (!NonBufferedIo) 
00385         {
00386             /****************************************************************************
00387             if (!CcCanIWrite(PtrFileObject, WriteLength, CanWait, IsThisADeferredWrite)) 
00388             {
00389                 // Cache Manager and/or the VMM does not want us to perform
00390                 // the write at this time. Post the request.
00391                 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_DEFERRED_WRITE);
00392                 CcDeferWrite( PtrFileObject, Ext2DeferredWriteCallBack, PtrIrpContext, PtrIrp, WriteLength, IsThisADeferredWrite);
00393                 CompleteIrp = FALSE;
00394                 try_return( RC = STATUS_PENDING );
00395             }
00396             ****************************************************************************/
00397         }
00398 
00399         // If the write request is directed to a page file 
00400         // send the request directly to the disk
00401         // driver. For requests directed to a page file, you have to trust
00402         // that the offsets will be set correctly by the VMM. You should not
00403         // attempt to acquire any FSD resources either.
00404         if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) 
00405         {
00406             IoMarkIrpPending(PtrIrp);
00407 
00408             // You will need to set a completion routine before invoking a lower level driver.
00409             //  Forward request directly to disk driver.
00410             // Ext2PageFileIo(PtrIrpContext, PtrIrp);
00411 
00412             CompleteIrp = FALSE;
00413 
00414             try_return(RC = STATUS_PENDING);
00415         }
00416 
00417         // Check whether this write operation is targeted
00418         // to a directory object...
00419 
00420         if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) 
00421         {
00422             //
00423             //  Is this a write a result of 
00424             //  cached directory manipulation operatio
00425             //  by the FSD itself?
00426             //
00427             if( PagingIo )
00428             {
00429                 //  Yep! Allow it to proceed...
00430             }
00431             else
00432             {
00433                 //  Nope... User initiated directory writes are not allowed!
00434                 //  Fail this request...
00435                 RC = STATUS_INVALID_DEVICE_REQUEST;
00436                 try_return();
00437             }
00438         }
00439 
00440         PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
00441 
00442         //
00443         //  Synchronizing with other reads and writes...
00444         //  Acquire the appropriate FCB resource exclusively
00445         //
00446         if (PagingIo) 
00447         {
00448             // Try to acquire the FCB PagingIoResource exclusively
00449             DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire FCBpaging Exclusively [Write]", 0);
00450 
00451             if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) 
00452             {
00453                 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCBpaging Acquisition FAILED [Write]", 0);
00454                 CompleteIrp = FALSE;
00455                 PostRequest = TRUE;
00456                 try_return(RC = STATUS_PENDING);
00457             }
00458             // Remember the resource that was acquired
00459             DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCBpaging Acquired [Write]", 0);
00460             PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource);
00461         } 
00462         else 
00463         {
00464             // Try to acquire the FCB MainResource exclusively
00465             DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire FCB Exclusively [Write]", 0);
00466             if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) 
00467             {
00468                 DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCB Acquisition FAILED [Write]", 0);
00469                 CompleteIrp = FALSE;
00470                 PostRequest = TRUE;
00471                 try_return(RC = STATUS_PENDING);
00472             }
00473             // Remember the resource that was acquired
00474             DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCB Acquired [Write]", 0);
00475             PtrResourceAcquired = &(PtrReqdFCB->MainResource);
00476         }
00477 
00478         // Validate start offset and length supplied.
00479         // Here is a special check that determines whether the caller wishes to
00480         // begin the write at current end-of-file (whatever the value of that
00481         // offset might be)
00482         if ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == 0xFFFFFFFF)) 
00483         {
00484             WritingAtEndOfFile = TRUE;
00485             ByteOffset.QuadPart = PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart;
00486         }
00487 
00488         //
00489         //  If this is a Non Cached io and if caching has been initiated,
00490         //  Flush and purge the cache 
00491         //
00492         if (NonBufferedIo && !PagingIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL)) 
00493         {
00494             // Flush and then attempt to purge the cache
00495             CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, WriteLength, &(PtrIrp->IoStatus));
00496             // If the flush failed, return error to the caller
00497             if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) 
00498             {
00499                 try_return();
00500             }
00501 
00502             // Attempt the purge and ignore the return code
00503             CcPurgeCacheSection( &(PtrReqdFCB->SectionObject), (WritingAtEndOfFile ? &(PtrReqdFCB->CommonFCBHeader.FileSize) : &(ByteOffset)),
00504                                         WriteLength, FALSE);
00505             // We are finished with our flushing and purging
00506         }
00507 
00508         if (!PagingIo) 
00509         {
00510             //  Insert code to perform the check here ...
00511             //  
00512             //  if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp,
00513             //      PtrCurrentIoStackLocation)) 
00514             //  {
00515             //      try_return(RC = STATUS_FILE_LOCK_CONFLICT);
00516             //  }
00517         }
00518 
00519         //  Read in the File inode...
00520         Ext2InitializeFCBInodeInfo( PtrFCB );
00521 
00522         if (!PagingIo) 
00523         {
00524             LARGE_INTEGER  CurrentTime;
00525             KeQuerySystemTime( &CurrentTime );
00526             PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart;
00527             PtrFCB->LastWriteTime.QuadPart = CurrentTime.QuadPart;
00528         }
00529 
00530         {
00531             //
00532             // Validate start offset and length supplied.
00533             //
00534             ULONG       LogicalBlockSize = 0;
00535             LONGLONG    NoOfNewBlocksRequired = 0;
00536             LONGLONG    NoOfBytesRequired = 0;
00537             LONGLONG    i;
00538             BOOLEAN     ZeroOut = FALSE;
00539             LARGE_INTEGER   StartOffsetForZeroing;
00540             LARGE_INTEGER   EndOffsetForZeroing;
00541 
00542 
00543             LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
00544         
00545             if ( ByteOffset.QuadPart + WriteLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart )
00546             {
00547                 if( PagingIo )
00548                 {
00549                     //
00550                     //  A paging request never modifies the file size...
00551                     //
00552                     if( ByteOffset.QuadPart 
00553                         >= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
00554                     {
00555                         //  Page request for writing outside the file...
00556                         //  No op this IRP by completing it...
00557                         //
00558                         try_return();
00559                     }
00560                     if( ByteOffset.QuadPart + WriteLength
00561                         > PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
00562                     {
00563                         //  Page request for writing outside the file alocation size...
00564                         //  Truncate the write size so that it is within the allocation limit...
00565                         //
00566                         WriteLength = (ULONG) (PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart - ByteOffset.QuadPart);
00567                     }
00568                 }
00569                 else
00570                 {
00571                     
00572                     //  Starting offset is > file size
00573                     //  Allocate new blocks?
00574                     NoOfBytesRequired = ByteOffset.QuadPart + WriteLength 
00575                             - PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart;
00576 
00577                     if( NoOfBytesRequired )
00578                     {
00579                         NoOfNewBlocksRequired = Ext2Align64( NoOfBytesRequired, LogicalBlockSize ) 
00580                             / LogicalBlockSize;
00581                         for( i = 0; i < NoOfNewBlocksRequired ; i++ )
00582                         {
00583                             Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE );
00584                         }
00585                 
00586                         ZeroOut = TRUE;
00587 
00588                         if( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart < ByteOffset.QuadPart )
00589                         {
00590                             //     Curr EOF --> |                    | <--New EOF
00591                             //  -----------------------------------------------
00592                             //  |               |        |///////////|        |
00593                             //  | File Contents |  Free  |// Write //|  Free  | <- End of Allocation   
00594                             //  |               |        |///////////|        |
00595                             //  -----------------------------------------------
00596                             //                  |                    | 
00597 
00598                             //  Write is beyond the current end of file...
00599                             //  This will create a hole...
00600                             //  Will have to zero this out...
00601 
00602                             //  Start offset is the Current File size
00603                             StartOffsetForZeroing = PtrReqdFCB->CommonFCBHeader.FileSize;
00604                             //  End offset is the point at which this write is going to start
00605                             EndOffsetForZeroing = ByteOffset;
00606                         }
00607                         else
00608                         {
00609                             //             Curr EOF --> |       | <--New EOF
00610                             //  ------------------------------------------
00611                             //  |               |///////////////|        |
00612                             //  | File Contents |//// Write ////|  Free  | <- End of Allocation
00613                             //  |               |///////////////|        |
00614                             //  ------------------------------------------
00615                             //                          |       | 
00616 
00617                             //  Just zero out the end of the file 
00618                             //  not covered by the file size
00619 
00620                             //  Start offset is the New File size
00621                             StartOffsetForZeroing.QuadPart = 
00622                                 ByteOffset.QuadPart + WriteLength;
00623                             //  End offset is the New Allocation size
00624                             EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart;
00625                         }
00626                     }
00627 
00628                     PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart = 
00629                         ByteOffset.QuadPart + WriteLength;              
00630                     
00631                     ASSERT( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart <= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart );
00632 
00633                     Ext2UpdateFileSize( PtrIrpContext, PtrFileObject, PtrFCB );
00634 
00635                     try
00636                     {
00637                         //
00638                         //  Zero the blocks out...
00639                         //  This routine can be used even if caching has not been initiated...
00640                         //
00641                         if( ZeroOut == TRUE && StartOffsetForZeroing.QuadPart != EndOffsetForZeroing.QuadPart )
00642                         {
00643                             CcZeroData( PtrFileObject, 
00644                                 &StartOffsetForZeroing,
00645                                 &EndOffsetForZeroing, 
00646                                 FALSE );
00647                             
00648                             if( EndOffsetForZeroing.QuadPart != PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
00649                             {
00650                                 //  Also zero out the file tip...
00651                                 CcZeroData( PtrFileObject, 
00652                                     &PtrReqdFCB->CommonFCBHeader.FileSize,
00653                                     &PtrReqdFCB->CommonFCBHeader.AllocationSize, 
00654                                     FALSE );
00655                             }
00656                         }
00657                     }
00658                     finally
00659                     {
00660                         //  Swallow an exceptions that are raised...
00661                     }
00662                 }
00663             }
00664         }
00665 
00666         //
00667         //  Branch here for cached vs non-cached I/O
00668         //
00669         if (!NonBufferedIo) 
00670         {
00671 
00672             //  The caller wishes to perform cached I/O. 
00673             //  Initiate caching if it hasn't been done already...
00674             if (PtrFileObject->PrivateCacheMap == NULL) 
00675             {
00676                 CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
00677                     FALSE,      // We will not utilize pin access for this file
00678                     &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
00679                     PtrCCB);        // The context used in callbacks
00680             }
00681 
00682             // Check and see if this request requires a MDL returned to the caller
00683             if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) 
00684             {
00685                 // Caller does want a MDL returned. Note that this mode
00686                 // implies that the caller is prepared to block
00687                 CcPrepareMdlWrite(PtrFileObject, &ByteOffset, WriteLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus));
00688                 NumberBytesWritten = PtrIrp->IoStatus.Information;
00689                 RC = PtrIrp->IoStatus.Status;
00690 
00691                 try_return();
00692             }
00693 
00694             // This is a regular run-of-the-mill cached I/O request. Let the
00695             // Cache Manager worry about it!
00696 
00697             // First though, we need a buffer pointer (address) that is valid
00698             PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp);
00699             ASSERT(PtrSystemBuffer);
00700             if ( !CcCopyWrite(PtrFileObject, &(ByteOffset), WriteLength, CanWait, PtrSystemBuffer)) 
00701             {
00702                 // The caller was not prepared to block and data is not immediately
00703                 // available in the system cache
00704                 CompleteIrp = FALSE;
00705                 PostRequest = TRUE;
00706                 // Mark Irp Pending ...
00707                 try_return(RC = STATUS_PENDING);
00708             } 
00709             else 
00710             {
00711                 // We have the data
00712                 PtrIrp->IoStatus.Status = RC;
00713                 PtrIrp->IoStatus.Information = NumberBytesWritten = WriteLength;
00714             }
00715         }
00716         else // NonBuffered or Paged IO
00717         {
00718 
00719             ULONG       Start = 0;
00720             ULONG       End = 0;
00721             ULONG       LogicalBlockIndex = 0;
00722             ULONG       BytesRemaining = 0;
00723             ULONG       BytesWrittenSoFar = 0;
00724             ULONG       LeftOver = 0;
00725             ULONG       LogicalBlockSize = 0;
00726             ULONG       PhysicalBlockSize = 0;
00727             ULONG       Index = 0;
00728 
00729             LONGLONG    SingleIndirectBlockSize = 0;
00730             LONGLONG    DoubleIndirectBlockSize = 0;
00731             LONGLONG    TripleIndirectBlockSize = 0;
00732             LONGLONG    DirectBlockSize = 0;
00733 
00734             LONGLONG    NoOfDirectBlocks ;
00735             LONGLONG    NoOfSingleIndirectBlocks ;
00736             LONGLONG    NoOfDoubleIndirectBlocks ;
00737             LONGLONG    NoOfTripleIndirectBlocks ;
00738 
00739             ULONG * PtrPinnedSIndirectBlock = NULL;
00740             ULONG * PtrPinnedDIndirectBlock = NULL;
00741             ULONG * PtrPinnedTIndirectBlock = NULL;
00742 
00743             //  Used when reading a Triple Indirect Block...
00744             LONGLONG        FirstCachedDIBlockOffset = 0;
00745 
00746             //  Used when reading a Double Indirect Block...
00747             LONGLONG        FirstCachedSIBlockOffset = 0;
00748 
00749             DebugTrace(DEBUG_TRACE_WRITE_DETAILS,  "[File Write] Paging IO or NonBufferedIo ", 0);
00750 
00751             //  Calculating where the write should start from...
00752             LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
00753             PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize;
00754 
00755             NoOfDirectBlocks =  EXT2_NDIR_BLOCKS ;
00756             NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
00757             NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
00758             NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
00759 
00760             DirectBlockSize =  LogicalBlockSize * NoOfDirectBlocks;
00761             SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks;
00762             DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ;
00763             TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks;
00764 
00765             LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize);
00766 
00767             if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
00768             {
00769                 //
00770                 //  Handle Triple indirect blocks?
00771                 //  A Pop up will do for now...
00772                 //
00773                 UNICODE_STRING ErrorMessage;
00774                 Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" );
00775                 DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "@@@@@@@@  Triple indirect blocks need to be written to! \n@@@@@@@@  This is not supported as yet!", 0);
00776                 /* REACTOS FIXME */
00777                 IoRaiseInformationalHardError(
00778                         /* IO_ERR_DRIVER_ERROR */(NTSTATUS)0xC0040004L,
00779                         &ErrorMessage,
00780                         KeGetCurrentThread( ) );
00781 
00782                 Ext2DeallocateUnicodeString( &ErrorMessage );
00783                 RC = STATUS_INSUFFICIENT_RESOURCES;
00784                 try_return();
00785             }
00786             
00787             if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize &&
00788                 ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) )
00789             {
00790                 LARGE_INTEGER VolumeByteOffset;
00791 
00792                 //
00793                 //  Indirect Blocks required...
00794                 //  Read in the single indirect blocks...
00795                 //
00796                 DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "Reading in some Indirect Blocks", 0);
00797 
00798                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_NDIR_BLOCKS ] * LogicalBlockSize;
00799 
00800                 //
00801                 //  Asking the cache manager to oblige by pinning the single indirect block...
00802                 //
00803                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
00804                    &VolumeByteOffset,
00805                    LogicalBlockSize,
00806                    CanWait,
00807                    &PtrPinnedSIndirectBCB,
00808                    (PVOID*)&PtrPinnedSIndirectBlock )) 
00809                 {
00810                     CompleteIrp = FALSE;
00811                     PostRequest = TRUE;
00812                 
00813                     // Mark Irp Pending ...
00814                     IoMarkIrpPending( PtrIrp );
00815                     RC = STATUS_PENDING;
00816                     try_return();
00817                     DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data", 0);
00818                 }
00819             }
00820             if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize &&
00821                 ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
00822             {
00823                 //
00824                 //  Double Indirect Blocks required...
00825                 //  Read in the double indirect blocks...
00826                 //
00827 
00828                 LONGLONG        StartIndirectBlock;
00829                 LONGLONG        EndIndirectBlock;
00830 
00831                 
00832 
00833                 LARGE_INTEGER VolumeByteOffset;
00834 
00835                 DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Double Indirect Blocks", 0);
00836 
00837                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
00838 
00839                 //
00840                 //  Asking the cache manager to oblige by pinning the double indirect block...
00841                 //
00842                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
00843                    &VolumeByteOffset,
00844                    LogicalBlockSize,
00845                    CanWait,
00846                    &PtrPinnedDIndirectBCB,
00847                    (PVOID*)&PtrPinnedDIndirectBlock )) 
00848                 {
00849                     CompleteIrp = FALSE;
00850                     PostRequest = TRUE;
00851                 
00852                     // Mark Irp Pending ...
00853                     IoMarkIrpPending( PtrIrp );
00854                     RC = STATUS_PENDING;
00855                     try_return();
00856                     DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
00857                 }
00858 
00859                 //  So far so good...
00860                 //  Now determine the single indirect blocks that will have to be read in...
00861                 if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
00862                 {
00863                     //  Request doesnot require any single indirect or direct blocks
00864                     StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
00865                     StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
00866                     StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
00867                 }
00868                 else
00869                 {
00870                     StartIndirectBlock = 0;
00871                 }
00872 
00873                 FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks;
00874 
00875                 if( ByteOffset.QuadPart + WriteLength >= 
00876                     DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
00877                 {
00878                     EndIndirectBlock  = DoubleIndirectBlockSize;
00879                 }
00880                 else
00881                 {
00882                     EndIndirectBlock = ByteOffset.QuadPart + WriteLength - 
00883                                        (DirectBlockSize + SingleIndirectBlockSize);
00884                 }
00885                 EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
00886                 EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
00887     
00888                 DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
00889 
00890                 PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
00891                 {
00892                     ULONG   i;
00893 
00894                     for( i = 0; i < DIArrayCount; i++ )
00895                     {
00896                         VolumeByteOffset.QuadPart =  PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
00897                         if (!CcMapData( PtrVCB->PtrStreamFileObject,
00898                            &VolumeByteOffset,
00899                            LogicalBlockSize,
00900                            CanWait,
00901                            &PtrDIArray[i].PtrBCB,
00902                            (PVOID*)&PtrDIArray[i].PtrSIBlocks)) 
00903                         {
00904                             CompleteIrp = FALSE;
00905                             PostRequest = TRUE;
00906                             IoMarkIrpPending( PtrIrp );
00907                             DIArrayCount = i;
00908                             try_return(RC = STATUS_PENDING);
00909 
00910                             DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
00911                         }
00912                     }
00913                 }
00914             }
00915 
00916 /*          {
00917                 //
00918                 //  Double Indirect Blocks required...
00919                 //  Read in the double indirect blocks...
00920                 //
00921 
00922                 LONGLONG        StartIndirectBlock;
00923                 LONGLONG        EndIndirectBlock;
00924 
00925                 LARGE_INTEGER VolumeByteOffset;
00926 
00927                 DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Double Indirect Blocks", 0);
00928 
00929                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
00930 
00931                 //
00932                 //  Asking the cache manager to oblige by pinning the double indirect block...
00933                 //
00934                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
00935                    &VolumeByteOffset,
00936                    LogicalBlockSize,
00937                    CanWait,
00938                    &PtrPinnedDIndirectBCB,
00939                    (PVOID*)&PtrPinnedDIndirectBlock )) 
00940                 {
00941                     CompleteIrp = FALSE;
00942                     PostRequest = TRUE;
00943                 
00944                     // Mark Irp Pending ...
00945                     IoMarkIrpPending( PtrIrp );
00946                     RC = STATUS_PENDING;
00947                     try_return();
00948                     DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
00949                 }
00950 
00951                 //  So far so good...
00952                 //  Now determine the single indirect blocks that will have to be read in...
00953                 if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
00954                 {
00955                     //  Request doesnot require any single indirect or direct blocks
00956                     StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
00957                     StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
00958                     StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
00959                 }
00960                 else
00961                 {
00962                     StartIndirectBlock = 0;
00963                 }
00964 
00965                 if( ByteOffset.QuadPart + WriteLength >= 
00966                     DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
00967                 {
00968                     EndIndirectBlock  = DoubleIndirectBlockSize;
00969                 }
00970                 else
00971                 {
00972                     EndIndirectBlock = ByteOffset.QuadPart + WriteLength - 
00973                                        (DirectBlockSize + SingleIndirectBlockSize);
00974                     if( EndIndirectBlock % LogicalBlockSize )
00975                     {
00976                         EndIndirectBlock += LogicalBlockSize;
00977                     }
00978                     EndIndirectBlock = EndIndirectBlock / LogicalBlockSize;
00979                     if( EndIndirectBlock % NoOfSingleIndirectBlocks)
00980                     {
00981                         EndIndirectBlock += NoOfSingleIndirectBlocks;
00982                     }
00983                     EndIndirectBlock = EndIndirectBlock / NoOfSingleIndirectBlocks;
00984                 }
00985                 DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
00986                 PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
00987                 {
00988                     ULONG   i;
00989 
00990                     for( i = 0; i < DIArrayCount; i++ )
00991                     {
00992                         VolumeByteOffset.QuadPart =  PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
00993                         if (!CcMapData( PtrVCB->PtrStreamFileObject,
00994                            &VolumeByteOffset,
00995                            LogicalBlockSize,
00996                            CanWait,
00997                            &PtrDIArray[i].PtrBCB,
00998                            (PVOID*)&PtrDIArray[i].PtrSIBlocks)) 
00999                         {
01000                             CompleteIrp = FALSE;
01001                             PostRequest = TRUE;
01002                             IoMarkIrpPending( PtrIrp );
01003                             DIArrayCount = i;
01004                             try_return(RC = STATUS_PENDING);
01005 
01006                             DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
01007                         }
01008                     }
01009                 }
01010             }
01011 */
01012             if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
01013             {
01014                 //
01015                 //  Triple Indirect Blocks required...
01016                 //  Read in the triple indirect blocks...
01017                 //
01018                 LONGLONG        StartTIndirectBlock;
01019                 LONGLONG        EndTIndirectBlock;
01020 
01021                 LONGLONG        StartDIndirectBlock;
01022                 LONGLONG        EndDIndirectBlock;
01023                 LONGLONG        StartIndirectBlock;
01024                 LONGLONG        EndIndirectBlock;
01025 
01026                 LONGLONG        ByteOffsetTillHere = 0;
01027 
01028                 PBCB    TempDIBCB;
01029                 LONG*   TempDIBuffer;
01030 
01031                 ULONG TIArrayIndex = 0;
01032 
01033                 LARGE_INTEGER VolumeByteOffset;
01034 
01035                 DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Triple Indirect Blocks", 0);
01036 
01037                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
01038 
01039                 DebugTrace(DEBUG_TRACE_TRIPLE,   "ByteOffset = 0x%I64X", ByteOffset );
01040                 DebugTrace(DEBUG_TRACE_TRIPLE,   "WriteLength = 0x%lX", WriteLength );
01041                 DebugTrace(DEBUG_TRACE_TRIPLE,   "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
01042                 //
01043                 //  Asking the cache manager to oblige by pinning the triple indirect block...
01044                 //
01045                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
01046                    &VolumeByteOffset,
01047                    LogicalBlockSize,
01048                    CanWait,
01049                    &PtrPinnedTIndirectBCB,
01050                    (PVOID*)&PtrPinnedTIndirectBlock )) 
01051                 {
01052                     CompleteIrp = FALSE;
01053                     PostRequest = TRUE;
01054                 
01055                     // Mark Irp Pending ...
01056                     IoMarkIrpPending( PtrIrp );
01057                     RC = STATUS_PENDING;
01058                     try_return();
01059                     DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
01060                 }
01061 
01062                 //  Determine the no of BCBs that need to be saved...
01063                 if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
01064                 {
01065                     StartTIndirectBlock = ByteOffset.QuadPart;
01066                 }
01067                 else
01068                 {
01069                     StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
01070                 }
01071                 EndTIndirectBlock = ByteOffset.QuadPart + WriteLength;
01072                 TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2;
01073 
01074                 
01075                 PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
01076 
01077                 //  Now determine the double indirect blocks that will have to be read in...
01078                 if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
01079                 {
01080                     //  Request doesnot require any single indirect or direct blocks
01081                     StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
01082                     StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize;
01083                     StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks;
01084 
01085                     ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ;
01086                     //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize;
01087                     FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
01088                 }
01089                 else
01090                 {
01091                     ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
01092                     FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
01093                     StartDIndirectBlock = 0;
01094                 }
01095 
01096                 DebugTrace(DEBUG_TRACE_TRIPLE,   "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere );
01097 
01098                 EndDIndirectBlock  = ByteOffset.QuadPart + WriteLength - 
01099                     (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
01100                 EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ;
01101                 EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks;
01102 
01103                 {
01104                     //  Reading in the necessary double indirect bocks...
01105                     ULONG   i;
01106                     LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock;
01107 
01108                     for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize)
01109                     {
01110                         VolumeByteOffset.QuadPart =  PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize;
01111                         
01112                         DebugTrace(DEBUG_TRACE_TRIPLE,   "Double VolOffset = 0x%I64X", VolumeByteOffset );
01113 
01114                         if( !CcMapData( PtrVCB->PtrStreamFileObject,
01115                            &VolumeByteOffset,
01116                            LogicalBlockSize,
01117                            CanWait,
01118                            &TempDIBCB,
01119                            (PVOID*)&TempDIBuffer) )
01120                         {
01121                             CompleteIrp = FALSE;
01122                             PostRequest = TRUE;
01123                             IoMarkIrpPending( PtrIrp );
01124                             try_return(RC = STATUS_PENDING);
01125                             DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
01126                         }
01127                     
01128                         if( ByteOffset.QuadPart > ByteOffsetTillHere)
01129                         {
01130                             StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere);
01131                             StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
01132                             StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
01133 
01134                             if( TIArrayIndex == 0 )
01135                             {
01136                                 FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks;
01137                             }
01138                         }
01139                         else
01140                         {
01141                             StartIndirectBlock = 0;
01142                         }
01143 
01144                         if( ByteOffset.QuadPart + WriteLength >= ByteOffsetTillHere + DoubleIndirectBlockSize)
01145                         {
01146                             EndIndirectBlock  = DoubleIndirectBlockSize;
01147                         }
01148                         else
01149                         {
01150                             EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ByteOffsetTillHere;
01151                         }
01152                         EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
01153                         EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
01154                     
01155                         {
01156                             ULONG   i;
01157                                 
01158                             for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ )
01159                             {
01160                                 VolumeByteOffset.QuadPart =  TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize;
01161                                 DebugTrace(DEBUG_TRACE_TRIPLE,   "Single VolOffset = 0x%I64X", VolumeByteOffset );
01162 
01163                                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
01164                                    &VolumeByteOffset,
01165                                    LogicalBlockSize,
01166                                    CanWait,
01167                                    &PtrTIArray[ TIArrayIndex ].PtrBCB,
01168                                    (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) 
01169                                 {
01170                                     CompleteIrp = FALSE;
01171                                     PostRequest = TRUE;
01172                                     IoMarkIrpPending( PtrIrp );
01173                                     DIArrayCount = i;
01174                                     try_return(RC = STATUS_PENDING);
01175 
01176                                     DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
01177                                 }
01178                                 TIArrayIndex++;
01179                             }
01180                         }
01181                         CcUnpinData( TempDIBCB );
01182                         TempDIBCB = NULL;
01183                         TempDIBuffer = NULL;
01184                     }
01185                 }
01186                 TIArrayCount = TIArrayIndex;
01187                 
01188                 DebugTrace(DEBUG_TRACE_TRIPLE,   "TIArrayCount = %ld", TIArrayCount );
01189                 DebugTrace(DEBUG_TRACE_TRIPLE,   "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset );
01190             }
01191 
01192             //  
01193             //  Allocating memory for IO Runs
01194             //
01195             Index = ( (WriteLength - 2) / LogicalBlockSize + 2 );
01196             PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) )  );
01197             
01198 
01199             Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) );
01200             BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart );
01201 
01202             if( WriteLength > BytesRemaining )
01203                 End = Start + BytesRemaining;
01204             else
01205                 End = Start + WriteLength;
01206             BytesWrittenSoFar = 0;
01207 
01208             Index = 0;
01209             DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "\nDetermining the write IRPs that have to be passed down...", 0);
01210             
01211             while( 1 )
01212             {
01213                 BytesWrittenSoFar += (End-Start);
01214                 if( LogicalBlockIndex < EXT2_NDIR_BLOCKS )
01215                 {
01216                     //  Direct Block
01217                     PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ];
01218                 }
01219                 else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) )
01220                 {
01221                     //  Single Indirect Block
01222                     PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - EXT2_NDIR_BLOCKS ];
01223                 }
01224                 else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks)  )
01225                 {
01226                     LONGLONG BlockNo;
01227                     LONGLONG IBlockIndex;
01228                     LONGLONG BlockIndex;
01229 
01230                     BlockNo     = LogicalBlockIndex - FirstCachedSIBlockOffset;
01231                     IBlockIndex = BlockNo / NoOfSingleIndirectBlocks;
01232                     BlockIndex  = BlockNo % NoOfSingleIndirectBlocks;
01233 
01234                     //  Double Indirect Block
01235                     PtrIoRuns[ Index ].LogicalBlock = 
01236                         PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];
01237                 }
01238                 else
01239                 {
01240                     //  Triple Indirect Block
01241                     LONGLONG BlockNo;
01242                     LONGLONG IBlockIndex;
01243                     LONGLONG BlockIndex;
01244                     BlockNo     = LogicalBlockIndex - FirstCachedDIBlockOffset;
01245                     IBlockIndex = BlockNo / NoOfSingleIndirectBlocks;
01246                     BlockIndex  = BlockNo % NoOfSingleIndirectBlocks;
01247 
01248                     DbgPrint( "\nBlock No : 0x%I64X   IBlockIndex = 0x%I64X   BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex);
01249 
01250                     if( IBlockIndex >= TIArrayCount )
01251                     {
01252                         Ext2BreakPoint();
01253                     }
01254                     if( BlockIndex >= LogicalBlockSize )
01255                     {
01256                         Ext2BreakPoint();
01257                     }
01258 
01259                     PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];
01260                     DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock );
01261                 }
01262 
01263                 if( PtrIoRuns[ Index ].LogicalBlock == 0 )
01264                 {
01265                     //
01266                     //  Something is wrong...
01267                     //
01268                     Ext2BreakPoint();
01269                     break;
01270 
01271                 }
01272                 PtrIoRuns[ Index ].StartOffset = Start;
01273                 PtrIoRuns[ Index ].EndOffset = End;
01274                 PtrIoRuns[ Index ].PtrAssociatedIrp = NULL;
01275 
01276                 DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Index = (%ld)", LogicalBlockIndex );
01277                 DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Logical Block = (0x%lX)", PtrFCB->IBlock[ LogicalBlockIndex ] );
01278                 DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Start = (0x%lX)", Start );
01279                 DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  End = (0x%lX)  ", End );
01280                 DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Bytes written (0x%lX)", BytesWrittenSoFar );
01281                  
01282                 
01283 
01284                 if( BytesWrittenSoFar >= WriteLength )
01285                     break;
01286                 LogicalBlockIndex++;
01287                 Start = 0;
01288                 LeftOver = WriteLength - BytesWrittenSoFar;
01289                 if( LeftOver > LogicalBlockSize )
01290                     End = LogicalBlockSize;
01291                 else
01292                     End = LeftOver;
01293                 //  Loop over to make the write request...
01294                 Index++;
01295             }
01296             
01297             //
01298             //  Unpin the Indirect Blocks
01299             //
01300             if( PtrPinnedSIndirectBCB )
01301             {
01302                 CcUnpinData( PtrPinnedSIndirectBCB );
01303                 PtrPinnedSIndirectBCB = NULL;
01304                 PtrPinnedSIndirectBlock = NULL;
01305             }
01306             if( PtrPinnedDIndirectBCB )
01307             {
01308                 CcUnpinData( PtrPinnedDIndirectBCB );
01309                 PtrPinnedDIndirectBCB = NULL;
01310                 PtrPinnedDIndirectBlock = NULL;
01311             }
01312             //
01313             //  Pass down Associated IRPs to the Target Device Driver...
01314             //
01315             DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "Passing down the Write IRPs to the disk driver...", 0 );
01316 
01317             RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, WriteLength, PtrIrpContext, PtrFCB, SynchronousIo );
01318             
01319             //
01320             //  Irp will be completed automatically 
01321             //  when all the Associated IRPs are completed
01322             //
01323             if( RC == STATUS_SUCCESS || RC == STATUS_PENDING )
01324             {
01325                 CompleteIrp = FALSE;    
01326             }
01327             try_return();
01328         }
01329 
01330         try_exit:   NOTHING;
01331 
01332     }
01333     finally 
01334     {
01335         if ( PtrIoRuns )
01336         {
01337             DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Write]", PtrIoRuns );
01338             ExFreePool( PtrIoRuns );
01339         }
01340         if( PtrPinnedSIndirectBCB )
01341         {
01342             CcUnpinData( PtrPinnedSIndirectBCB );
01343             PtrPinnedSIndirectBCB = NULL;
01344         }
01345         if( PtrPinnedDIndirectBCB )
01346         {
01347             CcUnpinData( PtrPinnedDIndirectBCB );
01348             PtrPinnedDIndirectBCB = NULL;
01349         }
01350         if ( PtrDIArray )
01351         {
01352             ULONG   i;
01353             for( i = 0; i < DIArrayCount; i++ )
01354             {
01355                 CcUnpinData( PtrDIArray->PtrBCB );
01356             }
01357             DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrDIArray );
01358             ExFreePool( PtrDIArray );
01359             PtrDIArray = NULL;
01360         }           
01361         // Release resources ...
01362         //
01363         if (PtrResourceAcquired) 
01364         {
01365             Ext2ReleaseResource(PtrResourceAcquired);
01366             
01367             DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE,   "*** Resource Released [Write]", 0);
01368             DebugTraceState( "Resource     AC:0x%LX   SW:0x%LX   EX:0x%LX   [Write]", 
01369                 PtrResourceAcquired->ActiveCount, 
01370                 PtrResourceAcquired->NumberOfExclusiveWaiters, 
01371                 PtrResourceAcquired->NumberOfSharedWaiters );
01372             
01373             if( PtrFileObject )
01374             {
01375                 DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Write]", PtrFileObject);
01376             }
01377             if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) )
01378             {
01379                 DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Released [Write]", 0);
01380             }
01381             else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) )
01382             {
01383                 DebugTrace(DEBUG_TRACE_MISC,  "*** VCBPaging Released [Write]", 0);
01384             }
01385             else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) )
01386             {
01387                 DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Paging Resource Released [Write]", 0);
01388             }
01389             else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) )
01390             {
01391                 DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Resource Released [Write]", 0);
01392             }
01393             else
01394             {
01395                 DebugTrace(DEBUG_TRACE_MISC,  "*** Unknown Resource Released [Write]", 0);
01396             }
01397 
01398             PtrResourceAcquired = NULL;
01399         }
01400 
01401         if (PostRequest) 
01402         {
01403             RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
01404         } 
01405         else if ( CompleteIrp && !(RC == STATUS_PENDING)) 
01406         {
01407             // For synchronous I/O, the FSD must maintain the current byte offset
01408             // Do not do this however, if I/O is marked as paging-io
01409             if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) 
01410             {
01411                 PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset,
01412                 RtlConvertUlongToLargeInteger((unsigned long)NumberBytesWritten));
01413             }
01414 
01415             // If the write completed successfully and this was not a paging-io
01416             // operation, set a flag in the CCB that indicates that a write was
01417             // performed and that the file time should be updated at cleanup
01418             if (NT_SUCCESS(RC) && !PagingIo) 
01419             {
01420                 Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_MODIFIED);
01421             }
01422 
01423             // If the file size was changed, set a flag in the FCB indicating that
01424             // this occurred.
01425 
01426             // If the request failed, and we had done some nasty stuff like
01427             // extending the file size (including informing the Cache Manager
01428             // about the new file size), and allocating on-disk space etc., undo
01429             // it at this time.
01430 
01431             // Can complete the IRP here if no exception was encountered
01432             if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) 
01433             {
01434                 PtrIrp->IoStatus.Status = RC;
01435                 PtrIrp->IoStatus.Information = NumberBytesWritten;
01436  
01437                 // complete the IRP
01438                 IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
01439             }
01440 
01441             // Free up the Irp Context
01442             Ext2ReleaseIrpContext(PtrIrpContext);
01443 
01444         } // can we complete the IRP ?
01445         else
01446         {
01447             // Free up the Irp Context
01448             Ext2ReleaseIrpContext(PtrIrpContext);
01449         }
01450     } // end of "finally" processing
01451     return(RC);
01452 }
01453 
01454 
01455 /*************************************************************************
01456 *
01457 * Function: Ext2DeferredWriteCallBack()
01458 *
01459 * Description:
01460 *   Invoked by the cache manager in the context of a worker thread.
01461 *   Typically, you can simply post the request at this point (just
01462 *   as you would have if the original request could not block) to
01463 *   perform the write in the context of a system worker thread.
01464 *
01465 * Expected Interrupt Level (for execution) :
01466 *
01467 *  IRQL_PASSIVE_LEVEL
01468 *
01469 * Return Value: None
01470 *
01471 *************************************************************************/
01472 void NTAPI Ext2DeferredWriteCallBack (
01473 void            *Context1,          // Should be PtrIrpContext
01474 void            *Context2 )         // Should be PtrIrp
01475 {
01476     // You should typically simply post the request to your internal
01477     // queue of posted requests (just as you would if the original write
01478     // could not be completed because the caller could not block).
01479     // Once you post the request, return from this routine. The write
01480     // will then be retried in the context of a system worker thread
01481 }

Generated on Sun May 27 2012 04:17:50 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.