test: udfs/read.c File Reference

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# read.c File Reference

`#include "UdfProcs.h"`

Go to the source code of this file.

## Defines

#define | BugCheckFileId (UDFS_BUG_CHECK_READ)
#define | Dbg (UDFS_DEBUG_LEVEL_READ)
#define | SafeZeroMemory(IC, AT, BYTE_COUNT)
#define | READ_AHEAD_GRANULARITY (0x10000)

## Functions

NTSTATUS | UdfCommonRead (IN PIRP_CONTEXT IrpContext, IN PIRP Irp)

## Define Documentation

#define BugCheckFileId (UDFS_BUG_CHECK_READ)

| Definition at line 28 of file udfs/read.c.

#define Dbg (UDFS_DEBUG_LEVEL_READ)

| Definition at line 34 of file udfs/read.c.

#define READ_AHEAD_GRANULARITY (0x10000)

| Definition at line 60 of file udfs/read.c. Referenced by UdfCommonRead().

#define SafeZeroMemory | ( | IC,
|  | AT,
|  | BYTE_COUNT |  | ) |

Value:

    {                  \
        try {                                                   \
            RtlZeroMemory( (AT), (BYTE_COUNT) );                \
        } except( EXCEPTION_EXECUTE_HANDLER ) {                 \
             UdfRaiseStatus( IC, STATUS_INVALID_USER_BUFFER );   \
        }                                                       \
    }

Definition at line 48 of file udfs/read.c.

Referenced by UdfCommonRead().

## Function Documentation

NTSTATUS UdfCommonRead | ( | IN PIRP_CONTEXT | IrpContext,
|  | IN PIRP | Irp
| ) |

Definition at line 68 of file udfs/read.c.

References Add2Ptr, ASSERT, BooleanFlagOn, BytesFromSectors, _UDF_DATA::CacheManagerCallbacks, CcCopyRead(), CcInitializeCacheMap(), CcMdlRead(), CcSetReadAheadGranularity(), ClearFlag, _FILE_OBJECT::CurrentByteOffset, DebugUnwind, _FCB::EmbeddedOffset, _FCB::EmbeddedVsn, ExGetCurrentResourceThread, FALSE, FCB_STATE_EMBEDDED_DATA, _FCB::FcbState, _IO_STACK_LOCATION::FileObject, FlagOn, _IRP::Flags, _FILE_OBJECT::Flags, FO_SYNCHRONOUS_IO, FsRtlCheckLockForReadAccess(), FsRtlCheckOplock(), FsRtlNormalizeNtstatus(), IoGetCurrentIrpStackLocation, IoIsErrorUserInduced, _IRP::IoStatus, Irp, IRP_CONTEXT_FLAG_ALLOC_IO, IRP_CONTEXT_FLAG_WAIT, IRP_MN_MDL, IRP_NOCACHE, IRP_PAGING_IO, KeInitializeEvent, _IRP::MdlAddress, _VCB::MetadataFcb, NT_SUCCESS, NTSTATUS(), NULL, PAGED_CODE, _IO_STACK_LOCATION::Parameters, PCC_FILE_SIZES, _FILE_OBJECT::PrivateCacheMap, READ_AHEAD_GRANULARITY, SafeZeroMemory, SectorAlign, SectorOffset, SetFlag, Status, SynchronousIo, TRUE, try_leave, TYPE_OF_OPEN, UDF_IO_CONTEXT, UdfAcquireFileShared, UdfAcquireFileSharedStarveExclusive, UdfAllocateIoContext, UdfCompleteRequest(), UdfData, UdfDecodeFileObject(), UdfFsdPostRequest(), UdfMapUserBuffer, UdfNonCachedRead(), UdfNormalizeAndRaiseStatus(), UdfOplockComplete(), UdfPrePostIrp(), UdfRaiseStatus(), UdfReleaseFile, UdfVerifyFcbOperation(), UnopenedFileObject, UserDirectoryOpen, UserFileOpen, UserVolumeOpen, and _FCB::Vcb.

Referenced by UdfFsdDispatch(), and UdfFspDispatch().

    00075                    :
    00076
    00077     This is the common entry point for NtReadFile calls.  For synchronous requests,
    00078     CommonRead will complete the request in the current thread.  If not
    00079     synchronous the request will be passed to the Fsp if there is a need to
    00080     block.
    00081
    00082 Arguments:
    00083
    00084     Irp - Supplies the Irp to process
    00085
    00086 Return Value:
    00087
    00088     NTSTATUS - The result of this operation.
    00089
    00090 --*/
    00091
    00092 {
    00093     NTSTATUS Status;
    00094     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
    00095
    00096     TYPE_OF_OPEN TypeOfOpen;
    00097     PFCB Fcb;
    00098     PCCB Ccb;
    00099     PVCB Vcb;
    00100
    00101     BOOLEAN Wait;
    00102     ULONG PagingIo;
    00103     ULONG SynchronousIo;
    00104     ULONG NonCachedIo;
    00105
    00106     LONGLONG StartingOffset;
    00107     LONGLONG ByteRange;
    00108     ULONG ByteCount;
    00109     ULONG ReadByteCount;
    00110     ULONG OriginalByteCount;
    00111
    00112     PVOID SystemBuffer, UserBuffer;
    00113
    00114     BOOLEAN ReleaseFile = TRUE;
    00115
    00116     PFILE_OBJECT MappingFileObject;
    00117
    00118     UDF_IO_CONTEXT LocalIoContext;
    00119
    00120     PAGED_CODE();
    00121
    00122     //
    00123     //  If this is a zero length read then return SUCCESS immediately.
    00124     //
    00125
    00126     if (IrpSp->Parameters.Read.Length == 0) {
    00127
    00128         UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
    00129         return STATUS_SUCCESS;
    00130     }
    00131
    00132     //
    00133     //  Decode the file object and verify we support read on this.  It
    00134     //  must be a user file, stream file or volume file (for a data disk).
    00135     //
    00136
    00137     TypeOfOpen = UdfDecodeFileObject( IrpSp->FileObject, &Fcb, &Ccb );
    00138
    00139     Vcb = Fcb->Vcb;
    00140
    00141     if ((TypeOfOpen == UnopenedFileObject) || (TypeOfOpen == UserDirectoryOpen)) {
    00142
    00143         UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
    00144         return STATUS_INVALID_DEVICE_REQUEST;
    00145     }
    00146
    00147     //
    00148     //  Examine our input parameters to determine if this is noncached and/or
    00149     //  a paging io operation.
    00150     //
    00151
    00152     Wait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
    00153     PagingIo = FlagOn( Irp->Flags, IRP_PAGING_IO );
    00154     NonCachedIo = FlagOn( Irp->Flags, IRP_NOCACHE );
    00155     SynchronousIo = FlagOn( IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO );
    00156
    00157     //
    00158     //  Extract the range of the Io.
    00159     //
    00160
    00161     StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart;
    00162     OriginalByteCount = ByteCount = IrpSp->Parameters.Read.Length;
    00163
    00164     ByteRange = StartingOffset + ByteCount;
    00165
    00166     //
    00167     //  Make sure that Dasd access is always non-cached.
    00168     //
    00169
    00170     if (TypeOfOpen == UserVolumeOpen) {
    00171
    00172         NonCachedIo = TRUE;
    00173     }
    00174
    00175     //
    00176     //  Acquire the file shared to perform the read.  If we are doing paging IO,
    00177     //  it may be the case that we would have a deadlock imminent because we may
    00178     //  block on shared access, so starve out any exclusive waiters.  This requires
    00179     //  a degree of caution - we believe that any paging IO bursts will recede and
    00180     //  allow the exclusive waiter in.
    00181     //
    00182
    00183     if (PagingIo) {
    00184
    00185         UdfAcquireFileSharedStarveExclusive( IrpContext, Fcb );
    00186
    00187     } else {
    00188
    00189         UdfAcquireFileShared( IrpContext, Fcb );
    00190     }
    00191
    00192     //
    00193     //  Use a try-finally to facilitate cleanup.
    00194     //
    00195
    00196     try {
    00197
    00198         //
    00199         //  Verify the Fcb.
    00200         //
    00201
    00202         UdfVerifyFcbOperation( IrpContext, Fcb );
    00203
    00204         //
    00205         //  If this is a user request then verify the oplock and filelock state.
    00206         //
    00207
    00208         if (TypeOfOpen == UserFileOpen) {
    00209
    00210             //
    00211             //  We check whether we can proceed
    00212             //  based on the state of the file oplocks.
    00213             //
    00214
    00215             Status = FsRtlCheckOplock( &Fcb->Oplock,
    00216                                        Irp,
    00217                                        IrpContext,
    00218                                        UdfOplockComplete,
    00219                                        UdfPrePostIrp );
    00220
    00221             //
    00222             //  If the result is not STATUS_SUCCESS then the Irp was completed
    00223             //  elsewhere.
    00224             //
    00225
    00226             if (Status != STATUS_SUCCESS) {
    00227
    00228                 Irp = NULL;
    00229                 IrpContext = NULL;
    00230
    00231                 try_leave( Status );
    00232             }
    00233
    00234             if (!PagingIo &&
    00235                 (Fcb->FileLock != NULL) &&
    00236                 !FsRtlCheckLockForReadAccess( Fcb->FileLock, Irp )) {
    00237
    00238                 try_leave( Status = STATUS_FILE_LOCK_CONFLICT );
    00239             }
    00240         }
    00241
    00242         //
    00243         //  Complete the request if it begins beyond the end of file.
    00244         //
    00245
    00246         if (StartingOffset >= Fcb->FileSize.QuadPart) {
    00247
    00248             try_leave( Status = STATUS_END_OF_FILE );
    00249         }
    00250
    00251         //
    00252         //  Truncate the read if it extends beyond the end of the file.
    00253         //
    00254
    00255         if (ByteRange > Fcb->FileSize.QuadPart) {
    00256
    00257             ByteCount = (ULONG) (Fcb->FileSize.QuadPart - StartingOffset);
    00258             ByteRange = Fcb->FileSize.QuadPart;
    00259         }
    00260
    00261         //
    00262         //  Now if the data is embedded in the ICB, map through the metadata
    00263         //  stream to retrieve the bytes.
    00264         //
    00265
    00266         if (FlagOn( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA )) {
    00267
    00268             //
    00269             //  The metadata stream better be here by now.
    00270             //
    00271
    00272             ASSERT( Vcb->MetadataFcb->FileObject != NULL );
    00273
    00274             //
    00275             //  Bias our starting offset by the offset of the ICB in the metadata
    00276             //  stream plus the offset of the data bytes in that ICB.  Obviously,
    00277             //  we aren't doing non-cached IO here.
    00278             //
    00279
    00280             StartingOffset += (BytesFromSectors( Vcb, Fcb->EmbeddedVsn ) + Fcb->EmbeddedOffset);
    00281             MappingFileObject = Vcb->MetadataFcb->FileObject;
    00282             NonCachedIo = FALSE;
    00283
    00284         //
    00285         //  We are mapping through the caller's fileobject
    00286         //
    00287
    00288         } else {
    00289
    00290             MappingFileObject = IrpSp->FileObject;
    00291         }
    00292
    00293         //
    00294         //  Handle the non-cached read first.
    00295         //
    00296
    00297         if (NonCachedIo) {
    00298
    00299             //
    00300             //  If we have an unaligned transfer then post this request if
    00301             //  we can't wait.  Unaligned means that the starting offset
    00302             //  is not on a sector boundary or the read is not integral
    00303             //  sectors.
    00304             //
    00305
    00306             ReadByteCount = SectorAlign( Vcb, ByteCount );
    00307
    00308             if (SectorOffset( Vcb,  StartingOffset ) ||
    00309                 (ReadByteCount > OriginalByteCount)) {
    00310
    00311                 if (!Wait) {
    00312
    00313                     UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
    00314                 }
    00315
    00316                 //
    00317                 //  Make sure we don't overwrite the buffer.
    00318                 //
    00319
    00320                 ReadByteCount = ByteCount;
    00321             }
    00322
    00323             //
    00324             //  Initialize the IoContext for the read.
    00325             //  If there is a context pointer, we need to make sure it was
    00326             //  allocated and not a stale stack pointer.
    00327             //
    00328
    00329             if (IrpContext->IoContext == NULL ||
    00330                 !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
    00331
    00332                 //
    00333                 //  If we can wait, use the context on the stack.  Otherwise
    00334                 //  we need to allocate one.
    00335                 //
    00336
    00337                 if (Wait) {
    00338
    00339                     IrpContext->IoContext = &LocalIoContext;
    00340                     ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
    00341
    00342                 } else {
    00343
    00344                     IrpContext->IoContext = UdfAllocateIoContext();
    00345                     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
    00346                 }
    00347             }
    00348
    00349             RtlZeroMemory( IrpContext->IoContext, sizeof( UDF_IO_CONTEXT ));
    00350
    00351             //
    00352             //  Store whether we allocated this context structure in the structure
    00353             //  itself.
    00354             //
    00355
    00356             IrpContext->IoContext->AllocatedContext =
    00357                 BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
    00358
    00359             if (Wait) {
    00360
    00361                 KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
    00362                                    NotificationEvent,
    00363                                    FALSE );
    00364
    00365             } else {
    00366
    00367                 IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
    00368                 IrpContext->IoContext->Resource = Fcb->Resource;
    00369                 IrpContext->IoContext->RequestedByteCount = ByteCount;
    00370             }
    00371
    00372             Irp->IoStatus.Information = ReadByteCount;
    00373
    00374             //
    00375             //  Call the NonCacheIo routine to perform the actual read.
    00376             //
    00377
    00378             Status = UdfNonCachedRead( IrpContext, Fcb, StartingOffset, ReadByteCount );
    00379
    00380             //
    00381             //  Don't complete this request now if STATUS_PENDING was returned.
    00382             //
    00383
    00384             if (Status == STATUS_PENDING) {
    00385
    00386                 Irp = NULL;
    00387                 ReleaseFile = FALSE;
    00388
    00389             //
    00390             //  Test is we should zero part of the buffer or update the
    00391             //  synchronous file position.
    00392             //
    00393
    00394             } else {
    00395
    00396                 //
    00397                 //  Convert any unknown error code to IO_ERROR.
    00398                 //
    00399
    00400                 if (!NT_SUCCESS( Status )) {
    00401
    00402                     //
    00403                     //  Set the information field to zero.
    00404                     //
    00405
    00406                     Irp->IoStatus.Information = 0;
    00407
    00408                     //
    00409                     //  Raise if this is a user induced error.
    00410                     //
    00411
    00412                     if (IoIsErrorUserInduced( Status )) {
    00413
    00414                         UdfRaiseStatus( IrpContext, Status );
    00415                     }
    00416
    00417                     Status = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR );
    00418
    00419                 //
    00420                 //  Check if there is any portion of the user's buffer to zero.
    00421                 //
    00422
    00423                 } else if (ReadByteCount != ByteCount) {
    00424
    00425                     UdfMapUserBuffer( IrpContext, &UserBuffer );
    00426
    00427                     SafeZeroMemory( IrpContext,
    00428                                     Add2Ptr( UserBuffer,
    00429                                              ByteCount,
    00430                                              PVOID ),
    00431                                     ReadByteCount - ByteCount );
    00432
    00433                     Irp->IoStatus.Information = ByteCount;
    00434                 }
    00435
    00436                 //
    00437                 //  Update the file position if this is a synchronous request.
    00438                 //
    00439
    00440                 if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
    00441
    00442                     IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
    00443                 }
    00444             }
    00445
    00446             try_leave( NOTHING );
    00447         }
    00448
    00449         //
    00450         //  Handle the cached case.  Start by initializing the private
    00451         //  cache map.
    00452         //
    00453
    00454         if (MappingFileObject->PrivateCacheMap == NULL) {
    00455
    00456             //
    00457             //  The metadata Fcb stream was fired up before any data read.  We should never
    00458             //  see it here.
    00459             //
    00460
    00461             ASSERT( MappingFileObject != Vcb->MetadataFcb->FileObject );
    00462
    00463             //
    00464             //  Now initialize the cache map.
    00465             //
    00466
    00467             CcInitializeCacheMap( IrpSp->FileObject,
    00468                                   (PCC_FILE_SIZES) &Fcb->AllocationSize,
    00469                                   FALSE,
    00470                                   &UdfData.CacheManagerCallbacks,
    00471                                   Fcb );
    00472
    00473             CcSetReadAheadGranularity( IrpSp->FileObject, READ_AHEAD_GRANULARITY );
    00474         }
    00475
    00476         //
    00477         //  Read from the cache if this is not an Mdl read.
    00478         //
    00479
    00480         if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
    00481
    00482             //
    00483             // If we are in the Fsp now because we had to wait earlier,
    00484             // we must map the user buffer, otherwise we can use the
    00485             // user's buffer directly.
    00486             //
    00487
    00488             UdfMapUserBuffer( IrpContext, &SystemBuffer);
    00489
    00490             //
    00491             // Now try to do the copy.
    00492             //
    00493
    00494             if (!CcCopyRead( MappingFileObject,
    00495                              (PLARGE_INTEGER) &StartingOffset,
    00496                              ByteCount,
    00497                              Wait,
    00498                              SystemBuffer,
    00499                              &Irp->IoStatus )) {
    00500
    00501                 try_leave( Status = STATUS_CANT_WAIT );
    00502             }
    00503
    00504             //
    00505             //  If the call didn't succeed, raise the error status
    00506             //
    00507
    00508             if (!NT_SUCCESS( Irp->IoStatus.Status )) {
    00509
    00510                 UdfNormalizeAndRaiseStatus( IrpContext, Irp->IoStatus.Status );
    00511             }
    00512
    00513             Status = Irp->IoStatus.Status;
    00514
    00515         //
    00516         //  Otherwise perform the MdlRead operation.
    00517         //
    00518
    00519         } else {
    00520
    00521             CcMdlRead( MappingFileObject,
    00522                        (PLARGE_INTEGER) &StartingOffset,
    00523                        ByteCount,
    00524                        &Irp->MdlAddress,
    00525                        &Irp->IoStatus );
    00526
    00527             Status = Irp->IoStatus.Status;
    00528         }
    00529
    00530         //
    00531         //  Update the current file position in the user file object.
    00532         //
    00533
    00534         if (SynchronousIo && !PagingIo && NT_SUCCESS( Status )) {
    00535
    00536             IrpSp->FileObject->CurrentByteOffset.QuadPart = ByteRange;
    00537         }
    00538
    00539     } finally {
    00540
    00541         DebugUnwind( "UdfCommonRead" );
    00542
    00543         //
    00544         //  Release the Fcb.
    00545         //
    00546
    00547         if (ReleaseFile) {
    00548
    00549             UdfReleaseFile( IrpContext, Fcb );
    00550         }
    00551     }
    00552
    00553     //
    00554     //  Post the request if we got CANT_WAIT.
    00555     //
    00556
    00557     if (Status == STATUS_CANT_WAIT) {
    00558
    00559         Status = UdfFsdPostRequest( IrpContext, Irp );
    00560
    00561     //
    00562     //  Otherwise complete the request.
    00563     //
    00564
    00565     } else {
    00566
    00567         UdfCompleteRequest( IrpContext, Irp, Status );
    00568     }
    00569
    00570     return Status;
    00571 }