3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File Read routine for Read called by the
12 Fsd/Fsp dispatch drivers.
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_READ)
34 // This macro just puts a nice little try-except around RtlZeroMemory
37 #define SafeZeroMemory(IC,AT,BYTE_COUNT) { \
39 RtlZeroMemory( (AT), (BYTE_COUNT) ); \
40 } except( EXCEPTION_EXECUTE_HANDLER ) { \
41 CdRaiseStatus( IC, STATUS_INVALID_USER_BUFFER ); \
46 // Read ahead amount used for normal data files
49 #define READ_AHEAD_GRANULARITY (0x10000)
52 #pragma alloc_text(PAGE, CdCommonRead)
58 IN PIRP_CONTEXT IrpContext
,
66 This is the common entry point for NtReadFile calls. For synchronous requests,
67 CommonRead will complete the request in the current thread. If not
68 synchronous the request will be passed to the Fsp if there is a need to
73 Irp - Supplies the Irp to process
77 NTSTATUS - The result of this operation.
82 NTSTATUS Status
= STATUS_SUCCESS
; /* ReactOS Change: GCC Uninit var */
83 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
85 TYPE_OF_OPEN TypeOfOpen
;
95 LONGLONG StartingOffset
;
99 ULONG OriginalByteCount
;
103 BOOLEAN ReleaseFile
= TRUE
;
105 CD_IO_CONTEXT LocalIoContext
;
110 // If this is a zero length read then return SUCCESS immediately.
113 if (IrpSp
->Parameters
.Read
.Length
== 0) {
115 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
116 return STATUS_SUCCESS
;
120 // Decode the file object and verify we support read on this. It
121 // must be a user file, stream file or volume file (for a data disk).
124 TypeOfOpen
= CdDecodeFileObject( IrpContext
, IrpSp
->FileObject
, &Fcb
, &Ccb
);
126 if ((TypeOfOpen
== UnopenedFileObject
) ||
127 (TypeOfOpen
== UserDirectoryOpen
)) {
129 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_DEVICE_REQUEST
);
130 return STATUS_INVALID_DEVICE_REQUEST
;
134 // Examine our input parameters to determine if this is noncached and/or
135 // a paging io operation.
138 Wait
= BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
139 PagingIo
= FlagOn( Irp
->Flags
, IRP_PAGING_IO
);
140 NonCachedIo
= FlagOn( Irp
->Flags
, IRP_NOCACHE
);
141 SynchronousIo
= FlagOn( IrpSp
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
);
145 // Extract the range of the Io.
148 StartingOffset
= IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
;
149 OriginalByteCount
= ByteCount
= IrpSp
->Parameters
.Read
.Length
;
151 ByteRange
= StartingOffset
+ ByteCount
;
154 // Make sure that Dasd access is always non-cached.
157 if (TypeOfOpen
== UserVolumeOpen
) {
163 // Acquire the file shared to perform the read. If we are doing paging IO,
164 // it may be the case that we would have a deadlock imminent because we may
165 // block on shared access, so starve out any exclusive waiters. This requires
166 // a degree of caution - we believe that any paging IO bursts will recede and
167 // allow the exclusive waiter in.
172 CdAcquireFileSharedStarveExclusive( IrpContext
, Fcb
);
176 CdAcquireFileShared( IrpContext
, Fcb
);
180 // Use a try-finally to facilitate cleanup.
186 // Verify the Fcb. Allow reads if this is a DASD handle that is
187 // dismounting the volume.
190 if ((TypeOfOpen
!= UserVolumeOpen
) || (NULL
== Ccb
) ||
191 !FlagOn( Ccb
->Flags
, CCB_FLAG_DISMOUNT_ON_CLOSE
)) {
193 CdVerifyFcbOperation( IrpContext
, Fcb
);
197 // If this is a non-cached then check whether we need to post this
198 // request if this thread can't block.
201 if (!Wait
&& NonCachedIo
) {
204 // XA requests must always be waitable.
207 if (FlagOn( Fcb
->FcbState
, FCB_STATE_RAWSECTOR_MASK
)) {
209 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
210 try_return( Status
= STATUS_CANT_WAIT
);
215 // If this is a user request then verify the oplock and filelock state.
218 if (TypeOfOpen
== UserFileOpen
) {
221 // We check whether we can proceed
222 // based on the state of the file oplocks.
225 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
228 (PVOID
)CdOplockComplete
,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
229 (PVOID
)CdPrePostIrp
);/* ReactOS Change: GCC "assignment from incompatible pointer type" */
232 // If the result is not STATUS_SUCCESS then the Irp was completed
236 if (Status
!= STATUS_SUCCESS
) {
241 try_return( NOTHING
);
245 (Fcb
->FileLock
!= NULL
) &&
246 !FsRtlCheckLockForReadAccess( Fcb
->FileLock
, Irp
)) {
248 try_return( Status
= STATUS_FILE_LOCK_CONFLICT
);
253 // Complete the request if it begins beyond the end of file.
256 if (StartingOffset
>= Fcb
->FileSize
.QuadPart
) {
258 try_return( Status
= STATUS_END_OF_FILE
);
262 // Truncate the read if it extends beyond the end of the file.
265 if (ByteRange
> Fcb
->FileSize
.QuadPart
) {
267 ByteCount
= (ULONG
) (Fcb
->FileSize
.QuadPart
- StartingOffset
);
268 ByteRange
= Fcb
->FileSize
.QuadPart
;
272 // Handle the non-cached read first.
278 // If we have an unaligned transfer then post this request if
279 // we can't wait. Unaligned means that the starting offset
280 // is not on a sector boundary or the read is not integral
284 ReadByteCount
= BlockAlign( Fcb
->Vcb
, ByteCount
);
286 if (SectorOffset( StartingOffset
) ||
287 SectorOffset( ReadByteCount
) ||
288 (ReadByteCount
> OriginalByteCount
)) {
292 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
296 // Make sure we don't overwrite the buffer.
299 ReadByteCount
= ByteCount
;
303 // Initialize the IoContext for the read.
304 // If there is a context pointer, we need to make sure it was
305 // allocated and not a stale stack pointer.
308 if (IrpContext
->IoContext
== NULL
||
309 !FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
)) {
312 // If we can wait, use the context on the stack. Otherwise
313 // we need to allocate one.
318 IrpContext
->IoContext
= &LocalIoContext
;
319 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
323 IrpContext
->IoContext
= CdAllocateIoContext();
324 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
328 RtlZeroMemory( IrpContext
->IoContext
, sizeof( CD_IO_CONTEXT
));
331 // Store whether we allocated this context structure in the structure
335 IrpContext
->IoContext
->AllocatedContext
=
336 BooleanFlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
);
340 KeInitializeEvent( &IrpContext
->IoContext
->SyncEvent
,
346 IrpContext
->IoContext
->ResourceThreadId
= ExGetCurrentResourceThread();
347 IrpContext
->IoContext
->Resource
= Fcb
->Resource
;
348 IrpContext
->IoContext
->RequestedByteCount
= ByteCount
;
351 Irp
->IoStatus
.Information
= ReadByteCount
;
354 // Call one of the NonCacheIo routines to perform the actual
358 if (FlagOn( Fcb
->FcbState
, FCB_STATE_RAWSECTOR_MASK
)) {
360 Status
= CdNonCachedXARead( IrpContext
, Fcb
, StartingOffset
, ReadByteCount
);
364 Status
= CdNonCachedRead( IrpContext
, Fcb
, StartingOffset
, ReadByteCount
);
368 // Don't complete this request now if STATUS_PENDING was returned.
371 if (Status
== STATUS_PENDING
) {
377 // Test is we should zero part of the buffer or update the
378 // synchronous file position.
384 // Convert any unknown error code to IO_ERROR.
387 if (!NT_SUCCESS( Status
)) {
390 // Set the information field to zero.
393 Irp
->IoStatus
.Information
= 0;
396 // Raise if this is a user induced error.
399 if (IoIsErrorUserInduced( Status
)) {
401 CdRaiseStatus( IrpContext
, Status
);
404 Status
= FsRtlNormalizeNtstatus( Status
, STATUS_UNEXPECTED_IO_ERROR
);
407 // Check if there is any portion of the user's buffer to zero.
410 } else if (ReadByteCount
!= ByteCount
) {
412 CdMapUserBuffer( IrpContext
, &UserBuffer
);
414 SafeZeroMemory( IrpContext
,
418 ReadByteCount
- ByteCount
);
420 Irp
->IoStatus
.Information
= ByteCount
;
424 // Update the file position if this is a synchronous request.
427 if (SynchronousIo
&& !PagingIo
&& NT_SUCCESS( Status
)) {
429 IrpSp
->FileObject
->CurrentByteOffset
.QuadPart
= ByteRange
;
433 try_return( NOTHING
);
437 // Handle the cached case. Start by initializing the private
441 if (IrpSp
->FileObject
->PrivateCacheMap
== NULL
) {
444 // Now initialize the cache map.
447 CcInitializeCacheMap( IrpSp
->FileObject
,
448 (PCC_FILE_SIZES
) &Fcb
->AllocationSize
,
450 &CdData
.CacheManagerCallbacks
,
453 CcSetReadAheadGranularity( IrpSp
->FileObject
, READ_AHEAD_GRANULARITY
);
457 // Read from the cache if this is not an Mdl read.
460 if (!FlagOn( IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
463 // If we are in the Fsp now because we had to wait earlier,
464 // we must map the user buffer, otherwise we can use the
465 // user's buffer directly.
468 CdMapUserBuffer( IrpContext
, &SystemBuffer
);
471 // Now try to do the copy.
474 if (!CcCopyRead( IrpSp
->FileObject
,
475 (PLARGE_INTEGER
) &StartingOffset
,
481 try_return( Status
= STATUS_CANT_WAIT
);
485 // If the call didn't succeed, raise the error status
488 if (!NT_SUCCESS( Irp
->IoStatus
.Status
)) {
490 CdNormalizeAndRaiseStatus( IrpContext
, Irp
->IoStatus
.Status
);
494 // Otherwise perform the MdlRead operation.
499 CcMdlRead( IrpSp
->FileObject
,
500 (PLARGE_INTEGER
) &StartingOffset
,
505 Status
= Irp
->IoStatus
.Status
;
509 // Update the current file position in the user file object.
512 if (SynchronousIo
&& !PagingIo
&& NT_SUCCESS( Status
)) {
514 IrpSp
->FileObject
->CurrentByteOffset
.QuadPart
= ByteRange
;
526 CdReleaseFile( IrpContext
, Fcb
);
531 // Post the request if we got CANT_WAIT.
534 if (Status
== STATUS_CANT_WAIT
) {
536 Status
= CdFsdPostRequest( IrpContext
, Irp
);
539 // Otherwise complete the request.
544 CdCompleteRequest( IrpContext
, Irp
, Status
);