Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwrite.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
1.7.6.1
|