test: read.c Source File

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

# read.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989-1993  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     read.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the code to implement the NtReadFile system service.
    00012
    00013 Author:
    00014
    00015     Darryl E. Havens (darrylh) 14-Apr-1989
    00016
    00017 Environment:
    00018
    00019     Kernel mode
    00020
    00021 Revision History:
    00022
    00023
    00024 --*/
    00025
    00026 #include "iop.h"
    00027
    00028 ULONG IopCacheHitIncrement = 0;
    00029
    00030 #ifdef ALLOC_PRAGMA
    00031 #pragma alloc_text(PAGE, NtReadFile)
    00032 #pragma alloc_text(PAGE, NtReadFileScatter)
    00033 #endif
    00034
    00035 NTSTATUS
    00036 NtReadFile(
    00037     IN HANDLE FileHandle,
    00038     IN HANDLE Event OPTIONAL,
    00039     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    00040     IN PVOID ApcContext OPTIONAL,
    00041     OUT PIO_STATUS_BLOCK IoStatusBlock,
    00042     OUT PVOID Buffer,
    00043     IN ULONG Length,
    00044     IN PLARGE_INTEGER ByteOffset OPTIONAL,
    00045     IN PULONG Key OPTIONAL
    00046     )
    00047
    00048 /*++
    00049
    00050 Routine Description:
    00051
    00052     This service reads Length bytes of data from the file associated with
    00053     FileHandle starting at ByteOffset and puts the data into the caller's
    00054     Buffer.  If the end of the file is reached before Length bytes have
    00055     been read, then the operation will terminate.  The actual length of
    00056     the data read from the file will be returned in the second longword
    00057     of the IoStatusBlock.
    00058
    00059 Arguments:
    00060
    00061     FileHandle - Supplies a handle to the file to be read.
    00062
    00063     Event - Optionally supplies an event to be signaled when the read operation
    00064         is complete.
    00065
    00066     ApcRoutine - Optionally supplies an APC routine to be executed when the read
    00067         operation is complete.
    00068
    00069     ApcContext - Supplies a context parameter to be passed to the ApcRoutine, if
    00070         an ApcRoutine was specified.
    00071
    00072     IoStatusBlock - Address of the caller's I/O status block.
    00073
    00074     Buffer - Address of buffer to receive the data read from the file.
    00075
    00076     Length - Supplies the length, in bytes, of the data to read from the file.
    00077
    00078     ByteOffset - Optionally specifies the starting byte offset within the file
    00079         to begin the read operation.  If not specified and the file is open
    00080         for synchronous I/O, then the current file position is used.  If the
    00081         file is not opened for synchronous I/O and the parameter is not
    00082         specified, then it is an error.
    00083
    00084     Key - Optionally specifies a key to be used if there are locks associated
    00085         with the file.
    00086
    00087 Return Value:
    00088
    00089     The status returned is success if the read operation was properly queued
    00090     to the I/O system.  Once the read completes the status of the operation
    00091     can be determined by examining the Status field of the I/O status block.
    00092
    00093 --*/
    00094
    00095 {
    00096     PIRP irp;
    00097     NTSTATUS status;
    00098     PFILE_OBJECT fileObject;
    00099     PDEVICE_OBJECT deviceObject;
    00100     PFAST_IO_DISPATCH fastIoDispatch;
    00101     KPROCESSOR_MODE requestorMode;
    00102     PIO_STACK_LOCATION irpSp;
    00103     NTSTATUS exceptionCode;
    00104     BOOLEAN synchronousIo;
    00105     PKEVENT eventObject = (PKEVENT) NULL;
    00106     ULONG keyValue = 0;
    00107     LARGE_INTEGER fileOffset = {0,0};
    00108     PULONG majorFunction;
    00109
    00110     PAGED_CODE();
    00111
    00112     //
    00113     // Get the previous mode;  i.e., the mode of the caller.
    00114     //
    00115
    00116     requestorMode = KeGetPreviousMode();
    00117
    00118     //
    00119     // Reference the file object so the target device can be found.  Note
    00120     // that if the caller does not have read access to the file, the operation
    00121     // will fail.
    00122     //
    00123
    00124     status = ObReferenceObjectByHandle( FileHandle,
    00125                                         FILE_READ_DATA,
    00126                                         IoFileObjectType,
    00127                                         requestorMode,
    00128                                         (PVOID *) &fileObject,
    00129                                         NULL );
    00130     if (!NT_SUCCESS( status )) {
    00131         return status;
    00132     }
    00133
    00134     //
    00135     // Get the address of the target device object.
    00136     //
    00137
    00138     deviceObject = IoGetRelatedDeviceObject( fileObject );
    00139
    00140     if (requestorMode != KernelMode) {
    00141
    00142         //
    00143         // The caller's access mode is not kernel so probe each of the arguments
    00144         // and capture them as necessary.  If any failures occur, the condition
    00145         // handler will be invoked to handle them.  It will simply cleanup and
    00146         // return an access violation status code back to the system service
    00147         // dispatcher.
    00148         //
    00149
    00150         try {
    00151
    00152             //
    00153             // The IoStatusBlock parameter must be writeable by the caller.
    00154             //
    00155
    00156             ProbeForWriteIoStatusEx(IoStatusBlock , ApcRoutine);
    00157
    00158             //
    00159             // The caller's data buffer must be writable from the caller's
    00160             // mode.  This check ensures that this is the case.  Since the
    00161             // buffer address is captured, the caller cannot change it,
    00162             // even though he/she can change the protection from another
    00163             // thread.  This error will be caught by the probe/lock or
    00164             // buffer copy operations later.
    00165             //
    00166
    00167             ProbeForWrite( Buffer, Length, sizeof( UCHAR ) );
    00168
    00169             //
    00170             // If this file has an I/O completion port associated w/it, then
    00171             // ensure that the caller did not supply an APC routine, as the
    00172             // two are mutually exclusive methods for I/O completion
    00173             // notification.
    00174             //
    00175
    00176             if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
    00177                 ObDereferenceObject( fileObject );
    00178                 return STATUS_INVALID_PARAMETER;
    00179             }
    00180
    00181             //
    00182             // Also ensure that the ByteOffset parameter is readable from
    00183             // the caller's mode and capture it if it is present.
    00184             //
    00185
    00186             if (ARGUMENT_PRESENT( ByteOffset )) {
    00187                 ProbeForRead( ByteOffset,
    00188                               sizeof( LARGE_INTEGER ),
    00189                               sizeof( ULONG ) );
    00190                 fileOffset = *ByteOffset;
    00191             }
    00192
    00193             //
    00194             // Check to see whether the caller has opened the file without
    00195             // intermediate buffering.  If so, perform the following Buffer
    00196             // and ByteOffset parameter checks differently.
    00197             //
    00198
    00199             if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    00200
    00201                 //
    00202                 // The file was opened without intermediate buffering enabled.
    00203                 // Check that the Buffer is properly aligned, and that the
    00204                 // length is an integral number of 512-byte blocks.
    00205                 //
    00206
    00207                 if ((deviceObject->SectorSize &&
    00208                     (Length & (deviceObject->SectorSize - 1))) ||
    00209                     (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
    00210
    00211                     //
    00212                     // Check for sector sizes that are not a power of two.
    00213                     //
    00214
    00215                     if ((deviceObject->SectorSize &&
    00216                         Length % deviceObject->SectorSize) ||
    00217                         (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
    00218                         ObDereferenceObject( fileObject );
    00219                         return STATUS_INVALID_PARAMETER;
    00220                     }
    00221                 }
    00222
    00223                 //
    00224                 // If a ByteOffset parameter was specified, ensure that it
    00225                 // is a valid argument.
    00226                 //
    00227
    00228                 if (ARGUMENT_PRESENT( ByteOffset )) {
    00229                     if (deviceObject->SectorSize &&
    00230                         (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
    00231                         ObDereferenceObject( fileObject );
    00232                         return STATUS_INVALID_PARAMETER;
    00233                     }
    00234                 }
    00235             }
    00236
    00237             //
    00238             // Finally, ensure that if there is a key parameter specified it
    00239             // is readable by the caller.
    00240             //
    00241
    00242             if (ARGUMENT_PRESENT( Key )) {
    00243                 keyValue = ProbeAndReadUlong( Key );
    00244             }
    00245
    00246         } except(IopExceptionFilter( GetExceptionInformation(), &exceptionCode )) {
    00247
    00248             //
    00249             // An exception was incurred while attempting to probe the
    00250             // caller's parameters.  Dereference the file object and return
    00251             // an appropriate error status code.
    00252             //
    00253
    00254             ObDereferenceObject( fileObject );
    00255             return exceptionCode;
    00256
    00257         }
    00258
    00259     } else {
    00260
    00261         //
    00262         // The caller's mode is kernel.  Get the same parameters that are
    00263         // required from any other mode.
    00264         //
    00265
    00266         if (ARGUMENT_PRESENT( ByteOffset )) {
    00267             fileOffset = *ByteOffset;
    00268         }
    00269
    00270         if (ARGUMENT_PRESENT( Key )) {
    00271             keyValue = *Key;
    00272         }
    00273
    00274 #if DBG
    00275         if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    00276
    00277             //
    00278             // The file was opened without intermediate buffering enabled.
    00279             // Check that the Buffer is properly aligned, and that the
    00280             // length is an integral number of the block size.
    00281             //
    00282
    00283             if ((deviceObject->SectorSize &&
    00284                 (Length & (deviceObject->SectorSize - 1))) ||
    00285                 (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
    00286
    00287                 //
    00288                 // Check for sector sizes that are not a power of two.
    00289                 //
    00290
    00291                 if ((deviceObject->SectorSize &&
    00292                     Length % deviceObject->SectorSize) ||
    00293                     (ULONG_PTR) Buffer & deviceObject->AlignmentRequirement) {
    00294                     ObDereferenceObject( fileObject );
    00295                     ASSERT( FALSE );
    00296                     return STATUS_INVALID_PARAMETER;
    00297                 }
    00298             }
    00299
    00300             //
    00301             // If a ByteOffset parameter was specified, ensure that it
    00302             // is a valid argument.
    00303             //
    00304
    00305             if (ARGUMENT_PRESENT( ByteOffset )) {
    00306                 if (deviceObject->SectorSize &&
    00307                     (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
    00308                     ObDereferenceObject( fileObject );
    00309                     ASSERT( FALSE );
    00310                     return STATUS_INVALID_PARAMETER;
    00311                 }
    00312             }
    00313         }
    00314 #endif // DBG
    00315     }
    00316
    00317     //
    00318     // Get the address of the event object and set the event to the Not-
    00319     // Signaled state, if an one was specified.  Note here too, that if
    00320     // the handle does not refer to an event, then the reference will fail.
    00321     //
    00322
    00323     if (ARGUMENT_PRESENT( Event )) {
    00324         status = ObReferenceObjectByHandle( Event,
    00325                                             EVENT_MODIFY_STATE,
    00326                                             ExEventObjectType,
    00327                                             requestorMode,
    00328                                             (PVOID *) &eventObject,
    00329                                             NULL );
    00330         if (!NT_SUCCESS( status )) {
    00331             ObDereferenceObject( fileObject );
    00332             return status;
    00333         } else {
    00334             KeClearEvent( eventObject );
    00335         }
    00336     }
    00337
    00338     //
    00339     // Get the address of the driver object's Fast I/O dispatch structure.
    00340     //
    00341
    00342     fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
    00343
    00344     //
    00345     // Make a special check here to determine whether this is a synchronous
    00346     // I/O operation.  If it is, then wait here until the file is owned by
    00347     // the current thread.
    00348     //
    00349
    00350     if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    00351
    00352         BOOLEAN interrupted;
    00353
    00354         if (!IopAcquireFastLock( fileObject )) {
    00355             status = IopAcquireFileObjectLock( fileObject,
    00356                                                requestorMode,
    00357                                                (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    00358                                                &interrupted );
    00359             if (interrupted) {
    00360                 if (eventObject) {
    00361                     ObDereferenceObject( eventObject );
    00362                 }
    00363                 ObDereferenceObject( fileObject );
    00364                 return status;
    00365             }
    00366         }
    00367
    00368         if (!ARGUMENT_PRESENT( ByteOffset ) ||
    00369             (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
    00370             fileOffset.HighPart == -1)) {
    00371             fileOffset = fileObject->CurrentByteOffset;
    00372         }
    00373
    00374         //
    00375         // Turbo read support.  If the file is currently cached on this
    00376         // file object, then call the Cache Manager directly via FastIoRead
    00377         // and try to successfully complete the request here.  Note if
    00378         // FastIoRead returns FALSE or we get an I/O error, we simply
    00379         // fall through and go the "long way" and create an Irp.
    00380         //
    00381
    00382         if (fileObject->PrivateCacheMap) {
    00383
    00384             IO_STATUS_BLOCK localIoStatus;
    00385
    00386             ASSERT(fastIoDispatch && fastIoDispatch->FastIoRead);
    00387
    00388             //
    00389             //  Negative file offsets are illegal.
    00390             //
    00391
    00392             if (fileOffset.HighPart < 0) {
    00393                 if (eventObject) {
    00394                     ObDereferenceObject( eventObject );
    00395                 }
    00396                 IopReleaseFileObjectLock( fileObject );
    00397                 ObDereferenceObject( fileObject );
    00398                 return STATUS_INVALID_PARAMETER;
    00399             }
    00400
    00401             if (fastIoDispatch->FastIoRead( fileObject,
    00402                                             &fileOffset,
    00403                                             Length,
    00404                                             TRUE,
    00405                                             keyValue,
    00406                                             Buffer,
    00407                                             &localIoStatus,
    00408                                             deviceObject )
    00409
    00410                     &&
    00411
    00412                 ((localIoStatus.Status == STATUS_SUCCESS) ||
    00413                  (localIoStatus.Status == STATUS_BUFFER_OVERFLOW) ||
    00414                  (localIoStatus.Status == STATUS_END_OF_FILE))) {
    00415
    00416                 //
    00417                 // Boost the priority of the current thread so that it appears
    00418                 // as if it just did I/O.  This causes background jobs that
    00419                 // get cache hits to be more responsive in terms of getting
    00420                 // more CPU time.
    00421                 //
    00422
    00423                 if (IopCacheHitIncrement) {
    00424                     KeBoostPriorityThread( &PsGetCurrentThread()->Tcb,
    00425                                            (KPRIORITY) IopCacheHitIncrement );
    00426                 }
    00427
    00428                 //
    00429                 // Carefully return the I/O status.
    00430                 //
    00431
    00432                 IopUpdateReadOperationCount( );
    00433                 IopUpdateReadTransferCount( (ULONG)localIoStatus.Information );
    00434
    00435                 try {
    00436                     *IoStatusBlock = localIoStatus;
    00437                 } except( EXCEPTION_EXECUTE_HANDLER ) {
    00438                     localIoStatus.Status = GetExceptionCode();
    00439                     localIoStatus.Information = 0;
    00440                 }
    00441
    00442                 //
    00443                 // If an event was specified, set it.
    00444                 //
    00445
    00446                 if (ARGUMENT_PRESENT( Event )) {
    00447                     KeSetEvent( eventObject, 0, FALSE );
    00448                     ObDereferenceObject( eventObject );
    00449                 }
    00450
    00451                 //
    00452                 // Note that the file object event need not be set to the
    00453                 // Signaled state, as it is already set.
    00454                 //
    00455
    00456                 //
    00457                 // Cleanup and return.
    00458                 //
    00459
    00460                 IopReleaseFileObjectLock( fileObject );
    00461                 ObDereferenceObject( fileObject );
    00462
    00463                 return localIoStatus.Status;
    00464             }
    00465         }
    00466         synchronousIo = TRUE;
    00467
    00468     } else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {
    00469
    00470         //
    00471         // The file is not open for synchronous I/O operations, but the
    00472         // caller did not specify a ByteOffset parameter.
    00473         //
    00474
    00475         if (eventObject) {
    00476             ObDereferenceObject( eventObject );
    00477         }
    00478         ObDereferenceObject( fileObject );
    00479         return STATUS_INVALID_PARAMETER;
    00480     } else {
    00481         synchronousIo = FALSE;
    00482     }
    00483
    00484     //
    00485     //  Negative file offsets are illegal.
    00486     //
    00487
    00488     if (fileOffset.HighPart < 0) {
    00489         if (eventObject) {
    00490             ObDereferenceObject( eventObject );
    00491         }
    00492         if (synchronousIo) {
    00493             IopReleaseFileObjectLock( fileObject );
    00494         }
    00495         ObDereferenceObject( fileObject );
    00496         return STATUS_INVALID_PARAMETER;
    00497     }
    00498
    00499     //
    00500     // Set the file object to the Not-Signaled state.
    00501     //
    00502
    00503     KeClearEvent( &fileObject->Event );
    00504
    00505     //
    00506     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    00507     // The allocation is performed with an exception handler in case the
    00508     // caller does not have enough quota to allocate the packet.
    00509
    00510     irp = IopAllocateIrp( deviceObject->StackSize, TRUE );
    00511     if (!irp) {
    00512
    00513         //
    00514         // An IRP could not be allocated.  Cleanup and return an appropriate
    00515         // error status code.
    00516         //
    00517
    00518         IopAllocateIrpCleanup( fileObject, eventObject );
    00519
    00520         return STATUS_INSUFFICIENT_RESOURCES;
    00521     }
    00522     irp->Tail.Overlay.OriginalFileObject = fileObject;
    00523     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00524     irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
    00525     irp->RequestorMode = requestorMode;
    00526     irp->PendingReturned = FALSE;
    00527     irp->Cancel = FALSE;
    00528     irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
    00529
    00530     //
    00531     // Fill in the service independent parameters in the IRP.
    00532     //
    00533
    00534     irp->UserEvent = eventObject;
    00535     irp->UserIosb = IoStatusBlock;
    00536     irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
    00537     irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
    00538
    00539     //
    00540     // Get a pointer to the stack location for the first driver.  This will be
    00541     // used to pass the original function codes and parameters.  Note that
    00542     // setting the major function here also sets:
    00543     //
    00544     //      MinorFunction = 0;
    00545     //      Flags = 0;
    00546     //      Control = 0;
    00547     //
    00548
    00549     irpSp = IoGetNextIrpStackLocation( irp );
    00550     majorFunction = (PULONG) (&irpSp->MajorFunction);
    00551     *majorFunction = IRP_MJ_READ;
    00552     irpSp->FileObject = fileObject;
    00553
    00554     //
    00555     // Now determine whether this device expects to have data buffered to it
    00556     // or whether it performs direct I/O.  This is based on the DO_BUFFERED_IO
    00557     // flag in the device object.  If the flag is set, then a system buffer is
    00558     // allocated and the driver's data will be copied into it.  Otherwise, a
    00559     // Memory Descriptor List (MDL) is allocated and the caller's buffer is
    00560     // locked down using it.
    00561     //
    00562
    00563     irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
    00564     irp->MdlAddress = (PMDL) NULL;
    00565
    00566     if (deviceObject->Flags & DO_BUFFERED_IO) {
    00567
    00568         //
    00569         // The device does not support direct I/O.  Allocate a system buffer
    00570         // and specify that it should be deallocated on completion.  Also
    00571         // indicate that this is an input operation so the data will be copied
    00572         // into the caller's buffer.  This is done using an exception handler
    00573         // that will perform cleanup if the operation fails.  Note that this
    00574         // is only done if the operation has a non-zero length.
    00575         //
    00576
    00577         if (Length) {
    00578
    00579             try {
    00580
    00581                 //
    00582                 // Allocate the intermediary system buffer from nonpaged pool
    00583                 // and charge quota for it.
    00584                 //
    00585
    00586                 irp->AssociatedIrp.SystemBuffer =
    00587                     ExAllocatePoolWithQuota( NonPagedPoolCacheAligned, Length );
    00588
    00589             } except(EXCEPTION_EXECUTE_HANDLER) {
    00590
    00591                 //
    00592                 // An exception was incurred while either probing the caller's
    00593                 // buffer or allocating the system buffer.  Determine what
    00594                 // actually happened, clean everything up, and return an
    00595                 // appropriate error status code.
    00596                 //
    00597
    00598                 IopExceptionCleanup( fileObject,
    00599                                      irp,
    00600                                      eventObject,
    00601                                      (PKEVENT) NULL );
    00602
    00603                 return GetExceptionCode();
    00604
    00605             }
    00606
    00607             //
    00608             // Remember the address of the caller's buffer so the copy can take
    00609             // place during I/O completion.  Also, set the flags so that the
    00610             // completion code knows to do the copy and to deallocate the buffer.
    00611             //
    00612
    00613             irp->UserBuffer = Buffer;
    00614             irp->Flags = IRP_BUFFERED_IO |
    00615                          IRP_DEALLOCATE_BUFFER |
    00616                          IRP_INPUT_OPERATION;
    00617
    00618         } else {
    00619
    00620             //
    00621             // This is a zero-length read.  Simply indicate that this is
    00622             // buffered I/O, and pass along the request.  The buffer will
    00623             // not be set to deallocate so the completion path does not
    00624             // have to special-case the length.
    00625             //
    00626
    00627             irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
    00628
    00629         }
    00630
    00631     } else if (deviceObject->Flags & DO_DIRECT_IO) {
    00632
    00633         //
    00634         // This is a direct I/O operation.  Allocate an MDL and invoke the
    00635         // memory management routine to lock the buffer into memory.  This
    00636         // is done using an exception handler that will perform cleanup if
    00637         // the operation fails.  Note that no MDL is allocated, nor is any
    00638         // memory probed or locked if the length of the request was zero.
    00639         //
    00640
    00641         PMDL mdl;
    00642
    00643         irp->Flags = 0;
    00644
    00645         if (Length) {
    00646
    00647             try {
    00648
    00649                 //
    00650                 // Allocate an MDL, charging quota for it, and hang it off of
    00651                 // the IRP.  Probe and lock the pages associated with the
    00652                 // caller's buffer for write access and fill in the MDL with
    00653                 // the PFNs of those pages.
    00654                 //
    00655
    00656                 mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );
    00657                 if (mdl == NULL) {
    00658                     ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
    00659                 }
    00660                 MmProbeAndLockPages( mdl, requestorMode, IoWriteAccess );
    00661
    00662             } except(EXCEPTION_EXECUTE_HANDLER) {
    00663
    00664                 //
    00665                 // An exception was incurred while either probing the caller's
    00666                 // buffer or allocating the MDL.  Determine what actually
    00667                 // happened, clean everything up, and return an appropriate
    00668                 // error status code.
    00669                 //
    00670
    00671                 IopExceptionCleanup( fileObject,
    00672                                      irp,
    00673                                      eventObject,
    00674                                      (PKEVENT) NULL );
    00675
    00676                 return GetExceptionCode();
    00677
    00678             }
    00679
    00680         }
    00681
    00682     } else {
    00683
    00684         //
    00685         // Pass the address of the user's buffer so the driver has access to
    00686         // it.  It is now the driver's responsibility to do everything.
    00687         //
    00688
    00689         irp->Flags = 0;
    00690         irp->UserBuffer = Buffer;
    00691     }
    00692
    00693     //
    00694     // If this read operation is supposed to be performed with caching disabled
    00695     // set the disable flag in the IRP so no caching is performed.
    00696     //
    00697
    00698     if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    00699         irp->Flags |= IRP_NOCACHE | IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
    00700     } else {
    00701         irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
    00702     }
    00703
    00704     //
    00705     // Copy the caller's parameters to the service-specific portion of the
    00706     // IRP.
    00707     //
    00708
    00709     irpSp->Parameters.Read.Length = Length;
    00710     irpSp->Parameters.Read.Key = keyValue;
    00711     irpSp->Parameters.Read.ByteOffset = fileOffset;
    00712
    00713     //
    00714     // Queue the packet, call the driver, and synchronize appopriately with
    00715     // I/O completion.
    00716     //
    00717
    00718     status =  IopSynchronousServiceTail( deviceObject,
    00719                                          irp,
    00720                                          fileObject,
    00721                                          TRUE,
    00722                                          requestorMode,
    00723                                          synchronousIo,
    00724                                          ReadTransfer );
    00725
    00726     return status;
    00727 }
    00728
    00729 NTSTATUS
    00730 NtReadFileScatter(
    00731     IN HANDLE FileHandle,
    00732     IN HANDLE Event OPTIONAL,
    00733     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    00734     IN PVOID ApcContext OPTIONAL,
    00735     OUT PIO_STATUS_BLOCK IoStatusBlock,
    00736     IN PFILE_SEGMENT_ELEMENT SegmentArray,
    00737     IN ULONG Length,
    00738     IN PLARGE_INTEGER ByteOffset OPTIONAL,
    00739     IN PULONG Key OPTIONAL
    00740     )
    00741
    00742 /*++
    00743
    00744 Routine Description:
    00745
    00746     This service reads Length bytes of data from the file associated with
    00747     FileHandle starting at ByteOffset and puts the data into the caller's
    00748     buffer segments.  The buffer segments are not virtually contiguous,
    00749     but are 8 KB in length and alignment. If the end of the file is reached
    00750     before Length bytes have been read, then the operation will terminate.
    00751     The actual length of the data read from the file will be returned in
    00752     the second longword of the IoStatusBlock.
    00753
    00754 Arguments:
    00755
    00756     FileHandle - Supplies a handle to the file to be read.
    00757
    00758     Event - Unused the I/O must use a completion port.
    00759
    00760     ApcRoutine - Optionally supplies an APC routine to be executed when the read
    00761         operation is complete.
    00762
    00763     ApcContext - Supplies a context parameter to be passed to the ApcRoutine, if
    00764         an ApcRoutine was specified.
    00765
    00766     IoStatusBlock - Address of the caller's I/O status block.
    00767
    00768     SegmentArray - An array of buffer segment pointers that specify
    00769         where the data should be placed.
    00770
    00771     Length - Supplies the length, in bytes, of the data to read from the file.
    00772
    00773     ByteOffset - Optionally specifies the starting byte offset within the file
    00774         to begin the read operation.  If not specified and the file is open
    00775         for synchronous I/O, then the current file position is used.  If the
    00776         file is not opened for synchronous I/O and the parameter is not
    00777         specified, then it is an error.
    00778
    00779     Key - Unused.
    00780
    00781 Return Value:
    00782
    00783     The status returned is success if the read operation was properly queued
    00784     to the I/O system.  Once the read completes the status of the operation
    00785     can be determined by examining the Status field of the I/O status block.
    00786
    00787 Notes:
    00788
    00789     This interface is only supported for no buffering and asynchronous I/O.
    00790
    00791 --*/
    00792
    00793 {
    00794     PIRP irp;
    00795     NTSTATUS status;
    00796     PFILE_OBJECT fileObject;
    00797     PDEVICE_OBJECT deviceObject;
    00798     PFAST_IO_DISPATCH fastIoDispatch;
    00799     PFILE_SEGMENT_ELEMENT capturedArray = NULL;
    00800     KPROCESSOR_MODE requestorMode;
    00801     PIO_STACK_LOCATION irpSp;
    00802     NTSTATUS exceptionCode;
    00803     PKEVENT eventObject = (PKEVENT) NULL;
    00804     ULONG keyValue = 0;
    00805     ULONG elementCount;
    00806     LARGE_INTEGER fileOffset = {0,0};
    00807     PULONG majorFunction;
    00808     ULONG i;
    00809     BOOLEAN synchronousIo;
    00810
    00811     PAGED_CODE();
    00812
    00813     //
    00814     // Get the previous mode;  i.e., the mode of the caller.
    00815     //
    00816
    00817     requestorMode = KeGetPreviousMode();
    00818
    00819     //
    00820     // Reference the file object so the target device can be found.  Note
    00821     // that if the caller does not have read access to the file, the operation
    00822     // will fail.
    00823     //
    00824
    00825     status = ObReferenceObjectByHandle( FileHandle,
    00826                                         FILE_READ_DATA,
    00827                                         IoFileObjectType,
    00828                                         requestorMode,
    00829                                         (PVOID *) &fileObject,
    00830                                         NULL );
    00831     if (!NT_SUCCESS( status )) {
    00832         return status;
    00833     }
    00834
    00835     //
    00836     // Get the address of the target device object.
    00837     //
    00838
    00839     deviceObject = IoGetRelatedDeviceObject( fileObject );
    00840
    00841     //
    00842     // Verify this is a valid scatter read request.  In particular it must be
    00843     // non cached, asynchronous, use completion ports, non buffer I/O device
    00844     // and directed at a file system device.
    00845     //
    00846
    00847     if (!(fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) ||
    00848         (fileObject->Flags & FO_SYNCHRONOUS_IO) ||
    00849         deviceObject->Flags & DO_BUFFERED_IO ||
    00850         (deviceObject->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
    00851          deviceObject->DeviceType != FILE_DEVICE_DFS &&
    00852          deviceObject->DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
    00853          deviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
    00854          deviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
    00855          deviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM &&
    00856          deviceObject->DeviceType != FILE_DEVICE_DFS_VOLUME )) {
    00857
    00858         ObDereferenceObject( fileObject );
    00859         return STATUS_INVALID_PARAMETER;
    00860     }
    00861
    00862     elementCount = BYTES_TO_PAGES(Length);
    00863
    00864     if (requestorMode != KernelMode) {
    00865
    00866         //
    00867         // The caller's access mode is not kernel so probe each of the arguments
    00868         // and capture them as necessary.  If any failures occur, the condition
    00869         // handler will be invoked to handle them.  It will simply cleanup and
    00870         // return an access violation status code back to the system service
    00871         // dispatcher.
    00872         //
    00873
    00874         try {
    00875
    00876             //
    00877             // The IoStatusBlock parameter must be writeable by the caller.
    00878             //
    00879
    00880             ProbeForWriteIoStatusEx( IoStatusBlock , ApcRoutine);
    00881
    00882             //
    00883             // If this file has an I/O completion port associated w/it, then
    00884             // ensure that the caller did not supply an APC routine, as the
    00885             // two are mutually exclusive methods for I/O completion
    00886             // notification.
    00887             //
    00888
    00889             if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
    00890                 ObDereferenceObject( fileObject );
    00891                 return STATUS_INVALID_PARAMETER;
    00892             }
    00893
    00894             //
    00895             // Also ensure that the ByteOffset parameter is readable from
    00896             // the caller's mode and capture it if it is present.
    00897             //
    00898
    00899             if (ARGUMENT_PRESENT( ByteOffset )) {
    00900                 ProbeForRead( ByteOffset,
    00901                               sizeof( LARGE_INTEGER ),
    00902                               sizeof( ULONG ) );
    00903                 fileOffset = *ByteOffset;
    00904             }
    00905
    00906             //
    00907             // Check to see whether the caller has opened the file without
    00908             // intermediate buffering.  If so, perform the following ByteOffset
    00909             // parameter check differently.
    00910             //
    00911
    00912             if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    00913
    00914                 //
    00915                 // The file was opened without intermediate buffering enabled.
    00916                 // Check that the Buffer is properly aligned, and that the
    00917                 // length is an integral number of 512-byte blocks.
    00918                 //
    00919
    00920                 if ((deviceObject->SectorSize &&
    00921                     (Length & (deviceObject->SectorSize - 1)))) {
    00922
    00923                     //
    00924                     // Check for sector sizes that are not a power of two.
    00925                     //
    00926
    00927                     if ((deviceObject->SectorSize &&
    00928                         Length % deviceObject->SectorSize)) {
    00929                         ObDereferenceObject( fileObject );
    00930                         return STATUS_INVALID_PARAMETER;
    00931                     }
    00932                 }
    00933
    00934                 //
    00935                 // If a ByteOffset parameter was specified, ensure that it
    00936                 // is a valid argument.
    00937                 //
    00938
    00939                 if (ARGUMENT_PRESENT( ByteOffset )) {
    00940                     if (deviceObject->SectorSize &&
    00941                         (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
    00942                         ObDereferenceObject( fileObject );
    00943                         return STATUS_INVALID_PARAMETER;
    00944                     }
    00945                 }
    00946             }
    00947
    00948             //
    00949             // The SegmentArray paramter must be accessible.
    00950             //
    00951
    00952 #ifdef _X86_
    00953             ProbeForRead( SegmentArray,
    00954                           elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
    00955                           sizeof( ULONG )
    00956                           );
    00957 #elif defined(_WIN64)
    00958
    00959             //
    00960             // If we are a wow64 process, follow the X86 rules
    00961             //
    00962
    00963             if (PsGetCurrentProcess()->Wow64Process) {
    00964                 ProbeForRead( SegmentArray,
    00965                               elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
    00966                               sizeof( ULONG )
    00967                               );
    00968             } else {
    00969                 ProbeForRead( SegmentArray,
    00970                               elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
    00971                               TYPE_ALIGNMENT( FILE_SEGMENT_ELEMENT )
    00972                               );
    00973             }
    00974 #else
    00975             ProbeForRead( SegmentArray,
    00976                           elementCount * sizeof( FILE_SEGMENT_ELEMENT ),
    00977                           TYPE_ALIGNMENT( FILE_SEGMENT_ELEMENT )
    00978                           );
    00979 #endif
    00980
    00981             if (Length != 0) {
    00982
    00983                 //
    00984                 // Capture the segment array so it cannot be changed after
    00985                 // it has been looked at.
    00986                 //
    00987
    00988                 capturedArray = ExAllocatePoolWithQuota( PagedPool,
    00989                                                 elementCount * sizeof( FILE_SEGMENT_ELEMENT )
    00990                                                 );
    00991
    00992                 RtlCopyMemory( capturedArray,
    00993                                SegmentArray,
    00994                                elementCount * sizeof( FILE_SEGMENT_ELEMENT )
    00995                                );
    00996
    00997                 SegmentArray = capturedArray;
    00998
    00999                 //
    01000                 // Verify that all the addresses are page aligned.
    01001                 //
    01002
    01003                 for (i = 0; i < elementCount; i++) {
    01004
    01005                     if ( SegmentArray[i].Alignment & (PAGE_SIZE - 1)) {
    01006                         ExRaiseStatus( STATUS_INVALID_PARAMETER );
    01007                     }
    01008                 }
    01009             }
    01010
    01011             //
    01012             // Finally, ensure that if there is a key parameter specified it
    01013             // is readable by the caller.
    01014             //
    01015
    01016             if (ARGUMENT_PRESENT( Key )) {
    01017                 keyValue = ProbeAndReadUlong( Key );
    01018             }
    01019
    01020         } except(IopExceptionFilter( GetExceptionInformation(), &exceptionCode )) {
    01021
    01022             //
    01023             // An exception was incurred while attempting to probe the
    01024             // caller's parameters.  Dereference the file object and return
    01025             // an appropriate error status code.
    01026             //
    01027
    01028             ObDereferenceObject( fileObject );
    01029             if (capturedArray != NULL) {
    01030                 ExFreePool( capturedArray );
    01031             }
    01032             return exceptionCode;
    01033
    01034         }
    01035
    01036     } else {
    01037
    01038         //
    01039         // The caller's mode is kernel.  Get the same parameters that are
    01040         // required from any other mode.
    01041         //
    01042
    01043         if (ARGUMENT_PRESENT( ByteOffset )) {
    01044             fileOffset = *ByteOffset;
    01045         }
    01046
    01047         if (ARGUMENT_PRESENT( Key )) {
    01048             keyValue = *Key;
    01049         }
    01050
    01051 #if DBG
    01052         if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    01053
    01054             //
    01055             // The file was opened without intermediate buffering enabled.
    01056             // Check that the the length is an integral number of the block
    01057             //  size.
    01058             //
    01059
    01060             if ((deviceObject->SectorSize &&
    01061                 (Length & (deviceObject->SectorSize - 1)))) {
    01062
    01063                 //
    01064                 // Check for sector sizes that are not a power of two.
    01065                 //
    01066
    01067                 if ((deviceObject->SectorSize &&
    01068                     Length % deviceObject->SectorSize)) {
    01069                     ObDereferenceObject( fileObject );
    01070                     ASSERT( FALSE );
    01071                     return STATUS_INVALID_PARAMETER;
    01072                 }
    01073             }
    01074
    01075             //
    01076             // If a ByteOffset parameter was specified, ensure that it
    01077             // is a valid argument.
    01078             //
    01079
    01080             if (ARGUMENT_PRESENT( ByteOffset )) {
    01081                 if (deviceObject->SectorSize &&
    01082                     (fileOffset.LowPart & (deviceObject->SectorSize - 1))) {
    01083                     ObDereferenceObject( fileObject );
    01084                     ASSERT( FALSE );
    01085                     return STATUS_INVALID_PARAMETER;
    01086                 }
    01087             }
    01088         }
    01089
    01090         if (Length != 0) {
    01091
    01092             //
    01093             // Verify that all the addresses are page aligned.
    01094             //
    01095
    01096             for (i = 0; i < elementCount; i++) {
    01097
    01098                 if ( SegmentArray[i].Alignment & (PAGE_SIZE - 1)) {
    01099
    01100                     ObDereferenceObject( fileObject );
    01101                     ASSERT(FALSE);
    01102                     return STATUS_INVALID_PARAMETER;
    01103                 }
    01104             }
    01105         }
    01106 #endif // DBG
    01107     }
    01108
    01109     //
    01110     // Get the address of the event object and set the event to the Not-
    01111     // Signaled state, if an one was specified.  Note here too, that if
    01112     // the handle does not refer to an event, then the reference will fail.
    01113     //
    01114
    01115     if (ARGUMENT_PRESENT( Event )) {
    01116         status = ObReferenceObjectByHandle( Event,
    01117                                             EVENT_MODIFY_STATE,
    01118                                             ExEventObjectType,
    01119                                             requestorMode,
    01120                                             (PVOID *) &eventObject,
    01121                                             NULL );
    01122         if (!NT_SUCCESS( status )) {
    01123             ObDereferenceObject( fileObject );
    01124             if (capturedArray != NULL) {
    01125                 ExFreePool( capturedArray );
    01126             }
    01127             return status;
    01128         } else {
    01129             KeClearEvent( eventObject );
    01130         }
    01131     }
    01132
    01133     //
    01134     // Get the address of the driver object's Fast I/O dispatch structure.
    01135     //
    01136
    01137     fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
    01138
    01139     //
    01140     // Make a special check here to determine whether this is a synchronous
    01141     // I/O operation.  If it is, then wait here until the file is owned by
    01142     // the current thread.
    01143     //
    01144
    01145     if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
    01146
    01147         BOOLEAN interrupted;
    01148
    01149         if (!IopAcquireFastLock( fileObject )) {
    01150             status = IopAcquireFileObjectLock( fileObject,
    01151                                                requestorMode,
    01152                                                (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
    01153                                                &interrupted );
    01154             if (interrupted) {
    01155                 if (eventObject) {
    01156                     ObDereferenceObject( eventObject );
    01157                 }
    01158                 ObDereferenceObject( fileObject );
    01159                 if (capturedArray != NULL) {
    01160                     ExFreePool( capturedArray );
    01161                 }
    01162                 return status;
    01163             }
    01164         }
    01165
    01166         if (!ARGUMENT_PRESENT( ByteOffset ) ||
    01167             (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
    01168             fileOffset.HighPart == -1)) {
    01169             fileOffset = fileObject->CurrentByteOffset;
    01170         }
    01171
    01172         synchronousIo = TRUE;
    01173
    01174     } else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {
    01175
    01176         //
    01177         // The file is not open for synchronous I/O operations, but the
    01178         // caller did not specify a ByteOffset parameter.
    01179         //
    01180
    01181         if (eventObject) {
    01182             ObDereferenceObject( eventObject );
    01183         }
    01184         ObDereferenceObject( fileObject );
    01185         if (capturedArray != NULL) {
    01186             ExFreePool( capturedArray );
    01187         }
    01188         return STATUS_INVALID_PARAMETER;
    01189     } else {
    01190         synchronousIo = FALSE;
    01191     }
    01192
    01193     //
    01194     //  Negative file offsets are illegal.
    01195     //
    01196
    01197     if (fileOffset.HighPart < 0) {
    01198         if (eventObject) {
    01199             ObDereferenceObject( eventObject );
    01200         }
    01201         if (synchronousIo) {
    01202             IopReleaseFileObjectLock( fileObject );
    01203         }
    01204         ObDereferenceObject( fileObject );
    01205         if (capturedArray != NULL) {
    01206             ExFreePool( capturedArray );
    01207         }
    01208         return STATUS_INVALID_PARAMETER;
    01209     }
    01210
    01211     //
    01212     // Set the file object to the Not-Signaled state.
    01213     //
    01214
    01215     KeClearEvent( &fileObject->Event );
    01216
    01217     //
    01218     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    01219     // The allocation is performed with an exception handler in case the
    01220     // caller does not have enough quota to allocate the packet.
    01221
    01222     irp = IopAllocateIrp( deviceObject->StackSize, TRUE );
    01223     if (!irp) {
    01224
    01225         //
    01226         // An IRP could not be allocated.  Cleanup and return an appropriate
    01227         // error status code.
    01228         //
    01229
    01230         IopAllocateIrpCleanup( fileObject, eventObject );
    01231
    01232         if (capturedArray != NULL) {
    01233             ExFreePool( capturedArray );
    01234         }
    01235         return STATUS_INSUFFICIENT_RESOURCES;
    01236     }
    01237     irp->Tail.Overlay.OriginalFileObject = fileObject;
    01238     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    01239     irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
    01240     irp->RequestorMode = requestorMode;
    01241     irp->PendingReturned = FALSE;
    01242     irp->Cancel = FALSE;
    01243     irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
    01244
    01245     //
    01246     // Fill in the service independent parameters in the IRP.
    01247     //
    01248
    01249     irp->UserEvent = eventObject;
    01250     irp->UserIosb = IoStatusBlock;
    01251     irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
    01252     irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
    01253
    01254     //
    01255     // Get a pointer to the stack location for the first driver.  This will be
    01256     // used to pass the original function codes and parameters.  Note that
    01257     // setting the major function here also sets:
    01258     //
    01259     //      MinorFunction = 0;
    01260     //      Flags = 0;
    01261     //      Control = 0;
    01262     //
    01263
    01264     irpSp = IoGetNextIrpStackLocation( irp );
    01265     majorFunction = (PULONG) (&irpSp->MajorFunction);
    01266     *majorFunction = IRP_MJ_READ;
    01267     irpSp->FileObject = fileObject;
    01268
    01269     //
    01270     // Always allocate a Memory Descriptor List (MDL) and lock down the
    01271     // caller's buffer. This way the file system do not have change to
    01272     // build a scatter MDL. Note buffered I/O is not supported for this
    01273     // routine.
    01274     //
    01275
    01276     irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
    01277     irp->MdlAddress = (PMDL) NULL;
    01278
    01279
    01280     //
    01281     // This is a direct I/O operation.  Allocate an MDL and invoke the
    01282     // memory management routine to lock the buffer into memory.  This
    01283     // is done using an exception handler that will perform cleanup if
    01284     // the operation fails.  Note that no MDL is allocated, nor is any
    01285     // memory probed or locked if the length of the request was zero.
    01286     //
    01287
    01288     irp->Flags = 0;
    01289
    01290     if (Length) {
    01291
    01292         PMDL mdl;
    01293
    01294         try {
    01295
    01296             //
    01297             // Allocate an MDL, charging quota for it, and hang it off of
    01298             // the IRP.  Probe and lock the pages associated with the
    01299             // caller's buffer for write access and fill in the MDL with
    01300             // the PFNs of those pages.
    01301             //
    01302
    01303             mdl = IoAllocateMdl( (PVOID)(ULONG_PTR) SegmentArray[0].Buffer, Length, FALSE, TRUE, irp );
    01304             if (mdl == NULL) {
    01305                 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
    01306             }
    01307
    01308             //
    01309             // The address of the first file segment is used as a base
    01310             // address.
    01311             //
    01312
    01313             MmProbeAndLockSelectedPages( mdl,
    01314                                          SegmentArray,
    01315                                          requestorMode,
    01316                                          IoWriteAccess );
    01317
    01318             irp->UserBuffer = (PVOID)(ULONG_PTR) SegmentArray[0].Buffer;
    01319
    01320         } except(EXCEPTION_EXECUTE_HANDLER) {
    01321
    01322             //
    01323             // An exception was incurred while either probing the caller's
    01324             // buffer or allocating the MDL.  Determine what actually
    01325             // happened, clean everything up, and return an appropriate
    01326             // error status code.
    01327             //
    01328
    01329             IopExceptionCleanup( fileObject,
    01330                                  irp,
    01331                                  eventObject,
    01332                                  (PKEVENT) NULL );
    01333
    01334             if (capturedArray != NULL) {
    01335                 ExFreePool( capturedArray );
    01336             }
    01337             return GetExceptionCode();
    01338
    01339         }
    01340
    01341     }
    01342
    01343     //
    01344     // We are done with the captured buffer.
    01345     //
    01346
    01347     if (capturedArray != NULL) {
    01348         ExFreePool( capturedArray );
    01349     }
    01350
    01351     //
    01352     // If this read operation is supposed to be performed with caching disabled
    01353     // set the disable flag in the IRP so no caching is performed.
    01354     //
    01355
    01356     if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {
    01357         irp->Flags |= IRP_NOCACHE | IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
    01358     } else {
    01359         irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
    01360     }
    01361
    01362     //
    01363     // Copy the caller's parameters to the service-specific portion of the
    01364     // IRP.
    01365     //
    01366
    01367     irpSp->Parameters.Read.Length = Length;
    01368     irpSp->Parameters.Read.Key = keyValue;
    01369     irpSp->Parameters.Read.ByteOffset = fileOffset;
    01370
    01371     //
    01372     // Queue the packet, call the driver, and synchronize appopriately with
    01373     // I/O completion.
    01374     //
    01375
    01376     status =  IopSynchronousServiceTail( deviceObject,
    01377                                          irp,
    01378                                          fileObject,
    01379                                          TRUE,
    01380                                          requestorMode,
    01381                                          synchronousIo,
    01382                                          ReadTransfer );
    01383
    01384     return status;
    01385
    01386 }