1679 lines
45 KiB
C
1679 lines
45 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Read.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the File Read routine for Read called by the
|
||
dispatch driver.
|
||
|
||
Author:
|
||
|
||
David Goebel [DavidGoe] 28-Feb-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "FatProcs.h"
|
||
|
||
//
|
||
// The Bug check file id for this module
|
||
//
|
||
|
||
#define BugCheckFileId (FAT_BUG_CHECK_READ)
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_READ)
|
||
|
||
//
|
||
// Define stack overflow read threshhold. For the x86 we'll use a smaller
|
||
// threshold that for a risc platform.
|
||
//
|
||
|
||
#if defined(_M_IX86)
|
||
#if DBG
|
||
#define OVERFLOW_READ_THRESHHOLD (0xE00)
|
||
#else
|
||
#define OVERFLOW_READ_THRESHHOLD (0xA00)
|
||
#endif // DBG
|
||
#else
|
||
#define OVERFLOW_READ_THRESHHOLD (0x1000)
|
||
#endif // defined(_M_IX86)
|
||
|
||
|
||
//
|
||
// The following procedures handles read stack overflow operations.
|
||
//
|
||
|
||
VOID
|
||
FatStackOverflowRead (
|
||
IN PVOID Context,
|
||
IN PKEVENT Event
|
||
);
|
||
|
||
NTSTATUS
|
||
FatPostStackOverflowRead (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp,
|
||
IN PFCB Fcb
|
||
);
|
||
|
||
VOID
|
||
FatOverflowPagingFileRead (
|
||
IN PVOID Context,
|
||
IN PKEVENT Event
|
||
);
|
||
|
||
//
|
||
// VOID
|
||
// SafeZeroMemory (
|
||
// IN PUCHAR At,
|
||
// IN ULONG ByteCount
|
||
// );
|
||
//
|
||
|
||
//
|
||
// This macro just puts a nice little try-except around RtlZeroMemory
|
||
//
|
||
|
||
#define SafeZeroMemory(AT,BYTE_COUNT) { \
|
||
try { \
|
||
RtlZeroMemory((AT), (BYTE_COUNT)); \
|
||
} except(EXCEPTION_EXECUTE_HANDLER) { \
|
||
FatRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER ); \
|
||
} \
|
||
}
|
||
|
||
//
|
||
// Macro to increment appropriate performance counters.
|
||
//
|
||
|
||
#define CollectReadStats(VCB,OPEN_TYPE,BYTE_COUNT) { \
|
||
PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()]; \
|
||
if (((OPEN_TYPE) == UserFileOpen)) { \
|
||
Stats->UserFileReads += 1; \
|
||
Stats->UserFileReadBytes += (ULONG)(BYTE_COUNT); \
|
||
} else if (((OPEN_TYPE) == VirtualVolumeFile || ((OPEN_TYPE) == DirectoryFile))) { \
|
||
Stats->MetaDataReads += 1; \
|
||
Stats->MetaDataReadBytes += (ULONG)(BYTE_COUNT); \
|
||
} \
|
||
}
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, FatStackOverflowRead)
|
||
#pragma alloc_text(PAGE, FatPostStackOverflowRead)
|
||
#pragma alloc_text(PAGE, FatCommonRead)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
FatFsdRead (
|
||
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the driver entry to the common read routine for NtReadFile calls.
|
||
For synchronous requests, the CommonRead is called with Wait == TRUE,
|
||
which means the request will always be completed in the current thread,
|
||
and never passed to the Fsp. If it is not a synchronous request,
|
||
CommonRead is called with Wait == FALSE, which means the request
|
||
will be passed to the Fsp only if there is a need to block.
|
||
|
||
Arguments:
|
||
|
||
VolumeDeviceObject - Supplies the volume device object where the
|
||
file being Read exists
|
||
|
||
Irp - Supplies the Irp being processed
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The FSD status for the IRP
|
||
|
||
--*/
|
||
|
||
{
|
||
PFCB Fcb;
|
||
NTSTATUS Status;
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
|
||
BOOLEAN TopLevel;
|
||
|
||
DebugTrace(+1, Dbg, "FatFsdRead\n", 0);
|
||
|
||
//
|
||
// Call the common Read routine, with blocking allowed if synchronous
|
||
//
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
//
|
||
// We are first going to do a quick check for paging file IO.
|
||
//
|
||
|
||
Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext);
|
||
|
||
if ((NodeType(Fcb) == FAT_NTC_FCB) &&
|
||
FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
|
||
|
||
//
|
||
// Do the usual STATUS_PENDING things.
|
||
//
|
||
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// If there is not enough stack to do this read, then post this
|
||
// read to the overflow queue.
|
||
//
|
||
|
||
if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
|
||
|
||
KEVENT Event;
|
||
PAGING_FILE_OVERFLOW_PACKET Packet;
|
||
|
||
Packet.Irp = Irp;
|
||
Packet.Fcb = Fcb;
|
||
|
||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||
|
||
FsRtlPostPagingFileStackOverflow( &Packet, &Event, FatOverflowPagingFileRead );
|
||
|
||
//
|
||
// And wait for the worker thread to complete the item
|
||
//
|
||
|
||
(VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Perform the actual IO, it will be completed when the io finishes.
|
||
//
|
||
|
||
FatPagingFileIo( Irp, Fcb );
|
||
}
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
try {
|
||
|
||
TopLevel = FatIsIrpTopLevel( Irp );
|
||
|
||
IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
|
||
|
||
//
|
||
// If this is an Mdl complete request, don't go through
|
||
// common read.
|
||
//
|
||
|
||
if ( FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE) ) {
|
||
|
||
DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 );
|
||
try_return( Status = FatCompleteMdl( IrpContext, Irp ));
|
||
}
|
||
|
||
//
|
||
// We can't handle DPC calls yet, post it.
|
||
//
|
||
|
||
if ( FlagOn(IrpContext->MinorFunction, IRP_MN_DPC) ) {
|
||
|
||
DebugTrace(0, Dbg, "Passing DPC call to Fsp\n", 0 );
|
||
try_return( Status = FatFsdPostRequest( IrpContext, Irp ));
|
||
}
|
||
|
||
//
|
||
// Check if we have enough stack space to process this request. If there
|
||
// isn't enough then we will pass the request off to the stack overflow thread.
|
||
//
|
||
|
||
if ((IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) &&
|
||
((NodeType(Fcb) == FAT_NTC_FCB) ||
|
||
(NodeType(Fcb) == FAT_NTC_DCB) ||
|
||
(NodeType(Fcb) == FAT_NTC_ROOT_DCB))) {
|
||
|
||
DebugTrace(0, Dbg, "Passing StackOverflowRead off\n", 0 );
|
||
try_return( Status = FatPostStackOverflowRead( IrpContext, Irp, Fcb ) );
|
||
}
|
||
|
||
Status = FatCommonRead( IrpContext, Irp );
|
||
|
||
try_exit: NOTHING;
|
||
} except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
|
||
|
||
//
|
||
// We had some trouble trying to perform the requested
|
||
// operation, so we'll abort the I/O request with
|
||
// the error status that we get back from the
|
||
// execption code
|
||
//
|
||
|
||
Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
|
||
}
|
||
|
||
if (TopLevel) { IoSetTopLevelIrp( NULL ); }
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "FatFsdRead -> %08lx\n", Status);
|
||
|
||
UNREFERENCED_PARAMETER( VolumeDeviceObject );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
//
|
||
// Internal support routine
|
||
//
|
||
|
||
NTSTATUS
|
||
FatPostStackOverflowRead (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp,
|
||
IN PFCB Fcb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine posts a read request that could not be processed by
|
||
the fsp thread because of stack overflow potential.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies the request to process.
|
||
|
||
Fcb - Supplies the file.
|
||
|
||
Return Value:
|
||
|
||
STATUS_PENDING.
|
||
|
||
--*/
|
||
|
||
{
|
||
PKEVENT Event;
|
||
PERESOURCE Resource;
|
||
|
||
DebugTrace(0, Dbg, "Getting too close to stack limit pass request to Fsp\n", 0 );
|
||
|
||
//
|
||
// Allocate an event and get shared on the resource we will
|
||
// be later using the common read.
|
||
//
|
||
|
||
Event = FsRtlAllocatePool( NonPagedPool, sizeof(KEVENT) );
|
||
KeInitializeEvent( Event, NotificationEvent, FALSE );
|
||
|
||
if (FlagOn(Irp->Flags, IRP_PAGING_IO) && (Fcb->Header.PagingIoResource != NULL)) {
|
||
|
||
Resource = Fcb->Header.PagingIoResource;
|
||
|
||
} else {
|
||
|
||
Resource = Fcb->Header.Resource;
|
||
}
|
||
|
||
ExAcquireResourceShared( Resource, TRUE );
|
||
|
||
try {
|
||
|
||
//
|
||
// Make the Irp just like a regular post request and
|
||
// then send the Irp to the special overflow thread.
|
||
// After the post we will wait for the stack overflow
|
||
// read routine to set the event that indicates we can
|
||
// now release the scb resource and return.
|
||
//
|
||
|
||
FatPrePostIrp( IrpContext, Irp );
|
||
|
||
//
|
||
// If this read is the result of a verify, we have to
|
||
// tell the overflow read routne to temporarily
|
||
// hijack the Vcb->VerifyThread field so that reads
|
||
// can go through.
|
||
//
|
||
|
||
if (Fcb->Vcb->VerifyThread == KeGetCurrentThread()) {
|
||
|
||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
|
||
}
|
||
|
||
FsRtlPostStackOverflow( IrpContext, Event, FatStackOverflowRead );
|
||
|
||
//
|
||
// And wait for the worker thread to complete the item
|
||
//
|
||
|
||
(VOID) KeWaitForSingleObject( Event, Executive, KernelMode, FALSE, NULL );
|
||
|
||
} finally {
|
||
|
||
ExReleaseResource( Resource );
|
||
|
||
ExFreePool( Event );
|
||
}
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
|
||
//
|
||
// Internal support routine
|
||
//
|
||
|
||
VOID
|
||
FatStackOverflowRead (
|
||
IN PVOID Context,
|
||
IN PKEVENT Event
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes a read request that could not be processed by
|
||
the fsp thread because of stack overflow potential.
|
||
|
||
Arguments:
|
||
|
||
Context - Supplies the IrpContext being processed
|
||
|
||
Event - Supplies the event to be signaled when we are done processing this
|
||
request.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP_CONTEXT IrpContext = Context;
|
||
PKTHREAD SavedVerifyThread = NULL;
|
||
PVCB Vcb;
|
||
|
||
//
|
||
// Make it now look like we can wait for I/O to complete
|
||
//
|
||
|
||
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
|
||
|
||
//
|
||
// If this read was as the result of a verify we have to fake out the
|
||
// the Vcb->VerifyThread field.
|
||
//
|
||
|
||
if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ)) {
|
||
|
||
Vcb = ((PFCB)IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->
|
||
FileObject->FsContext)->Vcb;
|
||
|
||
SavedVerifyThread = Vcb->VerifyThread;
|
||
Vcb->VerifyThread = KeGetCurrentThread();
|
||
}
|
||
|
||
//
|
||
// Do the read operation protected by a try-except clause
|
||
//
|
||
|
||
try {
|
||
|
||
(VOID) FatCommonRead( IrpContext, IrpContext->OriginatingIrp );
|
||
|
||
} except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
|
||
|
||
NTSTATUS ExceptionCode;
|
||
|
||
//
|
||
// We had some trouble trying to perform the requested
|
||
// operation, so we'll abort the I/O request with
|
||
// the error status that we get back from the
|
||
// execption code
|
||
//
|
||
|
||
ExceptionCode = GetExceptionCode();
|
||
|
||
if (ExceptionCode == STATUS_FILE_DELETED) {
|
||
|
||
IrpContext->ExceptionStatus = ExceptionCode = STATUS_END_OF_FILE;
|
||
IrpContext->OriginatingIrp->IoStatus.Information = 0;
|
||
}
|
||
|
||
(VOID) FatProcessException( IrpContext, IrpContext->OriginatingIrp, ExceptionCode );
|
||
}
|
||
|
||
//
|
||
// Restore the original VerifyVolumeThread
|
||
//
|
||
|
||
if (SavedVerifyThread != NULL) {
|
||
|
||
Vcb->VerifyThread = SavedVerifyThread;
|
||
}
|
||
|
||
//
|
||
// Set the stack overflow item's event to tell the original
|
||
// thread that we're done.
|
||
//
|
||
|
||
KeSetEvent( Event, 0, FALSE );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FatCommonRead (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the common read routine for NtReadFile, called from both
|
||
the Fsd, or from the Fsp if a request could not be completed without
|
||
blocking in the Fsd. This routine has no code where it determines
|
||
whether it is running in the Fsd or Fsp. Instead, its actions are
|
||
conditionalized by the Wait input parameter, which determines whether
|
||
it is allowed to block or not. If a blocking condition is encountered
|
||
with Wait == FALSE, however, the request is posted to the Fsp, who
|
||
always calls with WAIT == TRUE.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies the Irp to process
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The return status for the operation
|
||
|
||
--*/
|
||
|
||
{
|
||
PVCB Vcb;
|
||
PFCB FcbOrDcb;
|
||
PCCB Ccb;
|
||
|
||
VBO StartingVbo;
|
||
ULONG ByteCount;
|
||
ULONG RequestedByteCount;
|
||
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PFILE_OBJECT FileObject;
|
||
TYPE_OF_OPEN TypeOfRead;
|
||
|
||
BOOLEAN PostIrp = FALSE;
|
||
BOOLEAN OplockPostIrp = FALSE;
|
||
|
||
BOOLEAN FcbOrDcbAcquired = FALSE;
|
||
|
||
BOOLEAN Wait;
|
||
BOOLEAN PagingIo;
|
||
BOOLEAN NonCachedIo;
|
||
BOOLEAN SynchronousIo;
|
||
|
||
NTSTATUS Status;
|
||
|
||
FAT_IO_CONTEXT StackFatIoContext;
|
||
|
||
//
|
||
// A system buffer is only used if we have to access the
|
||
// buffer directly from the Fsp to clear a portion or to
|
||
// do a synchronous I/O, or a cached transfer. It is
|
||
// possible that our caller may have already mapped a
|
||
// system buffer, in which case we must remember this so
|
||
// we do not unmap it on the way out.
|
||
//
|
||
|
||
PVOID SystemBuffer = NULL;
|
||
|
||
LARGE_INTEGER StartingByte;
|
||
|
||
//
|
||
// Get current Irp stack location.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
FileObject = IrpSp->FileObject;
|
||
|
||
//
|
||
// Initialize the appropriate local variables.
|
||
//
|
||
|
||
Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
|
||
NonCachedIo = BooleanFlagOn(Irp->Flags,IRP_NOCACHE);
|
||
SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
|
||
|
||
DebugTrace(+1, Dbg, "CommonRead\n", 0);
|
||
DebugTrace( 0, Dbg, " Irp = %8lx\n", Irp);
|
||
DebugTrace( 0, Dbg, " ->ByteCount = %8lx\n", IrpSp->Parameters.Read.Length);
|
||
DebugTrace( 0, Dbg, " ->ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.LowPart);
|
||
DebugTrace( 0, Dbg, " ->ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Read.ByteOffset.HighPart);
|
||
|
||
//
|
||
// Extract starting Vbo and offset.
|
||
//
|
||
|
||
StartingByte = IrpSp->Parameters.Read.ByteOffset;
|
||
|
||
StartingVbo = StartingByte.LowPart;
|
||
|
||
ByteCount = IrpSp->Parameters.Read.Length;
|
||
RequestedByteCount = ByteCount;
|
||
|
||
//
|
||
// Check for a null request, and return immediately
|
||
//
|
||
|
||
if (ByteCount == 0) {
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Check for a non-zero high part offset
|
||
//
|
||
|
||
if ( StartingByte.HighPart != 0 ) {
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
|
||
return STATUS_END_OF_FILE;
|
||
}
|
||
|
||
//
|
||
// Extract the nature of the read from the file object, and case on it
|
||
//
|
||
|
||
TypeOfRead = FatDecodeFileObject(FileObject, &Vcb, &FcbOrDcb, &Ccb);
|
||
|
||
//
|
||
// Collect interesting statistics. The FLAG_USER_IO bit will indicate
|
||
// what type of io we're doing in the FatNonCachedIo function.
|
||
//
|
||
|
||
if (PagingIo) {
|
||
CollectReadStats(Vcb, TypeOfRead, ByteCount);
|
||
|
||
if (TypeOfRead == UserFileOpen) {
|
||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
|
||
} else {
|
||
ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If there is a previous STACK FatIoContext pointer, NULL it.
|
||
//
|
||
|
||
if ((IrpContext->FatIoContext != NULL) &&
|
||
FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
|
||
|
||
IrpContext->FatIoContext = NULL;
|
||
}
|
||
|
||
//
|
||
// Allocate if necessary and initialize a FAT_IO_CONTEXT block for
|
||
// all non cached Io, except Cvf file Io. For synchronous Io
|
||
// we use stack storage, otherwise we allocate pool.
|
||
//
|
||
|
||
if (NonCachedIo &&
|
||
!(FcbOrDcb && FlagOn(FcbOrDcb->FcbState,
|
||
FCB_STATE_COMPRESSED_VOLUME_FILE))) {
|
||
|
||
if (IrpContext->FatIoContext == NULL) {
|
||
|
||
if (!Wait) {
|
||
|
||
IrpContext->FatIoContext =
|
||
FsRtlAllocatePool( NonPagedPool, sizeof(FAT_IO_CONTEXT) );
|
||
|
||
} else {
|
||
|
||
IrpContext->FatIoContext = &StackFatIoContext;
|
||
|
||
SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
|
||
}
|
||
}
|
||
|
||
RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
|
||
|
||
if (Wait) {
|
||
|
||
KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
|
||
NotificationEvent,
|
||
FALSE );
|
||
|
||
} else {
|
||
|
||
IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
|
||
ExGetCurrentResourceThread();
|
||
|
||
IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
|
||
ByteCount;
|
||
|
||
IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// These two cases correspond to either a general opened volume, ie.
|
||
// open ("a:"), or a read of the volume file (boot sector + fat(s))
|
||
//
|
||
|
||
if ((TypeOfRead == VirtualVolumeFile) ||
|
||
(TypeOfRead == UserVolumeOpen)) {
|
||
|
||
DebugTrace(0, Dbg, "Type of read is User Volume or virtual volume file\n", 0);
|
||
|
||
if (TypeOfRead == UserVolumeOpen) {
|
||
|
||
//
|
||
// Verify that the volume for this handle is still valid
|
||
//
|
||
|
||
FatQuickVerifyVcb( IrpContext, Vcb );
|
||
|
||
if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE )) {
|
||
|
||
(VOID)ExAcquireResourceExclusive( &Vcb->Resource, TRUE );
|
||
|
||
try {
|
||
|
||
//
|
||
// If the volume isn't locked, flush it.
|
||
//
|
||
|
||
if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
|
||
|
||
FatFlushVolume( IrpContext, Vcb );
|
||
}
|
||
|
||
} finally {
|
||
|
||
ExReleaseResource( &Vcb->Resource );
|
||
}
|
||
|
||
SetFlag( Ccb->Flags, CCB_FLAG_DASD_FLUSH_DONE );
|
||
}
|
||
|
||
if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
|
||
|
||
ULONG VolumeSize;
|
||
|
||
//
|
||
// Make sure we don't try to read past end of volume,
|
||
// reducing the byte count if necessary.
|
||
//
|
||
|
||
VolumeSize = Vcb->Bpb.BytesPerSector *
|
||
(Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
|
||
Vcb->Bpb.LargeSectors);
|
||
|
||
if (StartingVbo >= VolumeSize) {
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
FatCompleteRequest( IrpContext, Irp, STATUS_END_OF_FILE );
|
||
return STATUS_END_OF_FILE;
|
||
}
|
||
|
||
if (ByteCount > VolumeSize - StartingVbo) {
|
||
|
||
ByteCount = VolumeSize - StartingVbo;
|
||
}
|
||
}
|
||
|
||
//
|
||
// For DASD we have to probe and lock the user's buffer
|
||
//
|
||
|
||
FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, ByteCount );
|
||
|
||
//
|
||
// Deal with stupid people who open the volume DASD with
|
||
// caching.
|
||
//
|
||
|
||
if (!IrpContext->FatIoContext) {
|
||
|
||
IrpContext->FatIoContext =
|
||
FsRtlAllocatePool( NonPagedPool, sizeof(FAT_IO_CONTEXT) );
|
||
|
||
RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
|
||
|
||
if (Wait) {
|
||
|
||
KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
|
||
NotificationEvent,
|
||
FALSE );
|
||
|
||
} else {
|
||
|
||
IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
|
||
ByteCount;
|
||
}
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// Virtual volume file open -- increment performance counters.
|
||
//
|
||
|
||
Vcb->Statistics[KeGetCurrentProcessorNumber()].MetaDataDiskReads += 1;
|
||
|
||
}
|
||
|
||
//
|
||
// Read the data and wait for the results
|
||
//
|
||
|
||
FatSingleAsync( IrpContext,
|
||
Vcb,
|
||
StartingVbo,
|
||
ByteCount,
|
||
Irp );
|
||
|
||
if (!Wait) {
|
||
|
||
//
|
||
// We, nor anybody else, need the IrpContext any more.
|
||
//
|
||
|
||
IrpContext->FatIoContext = NULL;
|
||
|
||
FatDeleteIrpContext( IrpContext );
|
||
|
||
DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
FatWaitSync( IrpContext );
|
||
|
||
//
|
||
// If the call didn't succeed, raise the error status
|
||
//
|
||
|
||
if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
|
||
|
||
FatNormalizeAndRaiseStatus( IrpContext, Status );
|
||
}
|
||
|
||
//
|
||
// Update the current file position
|
||
//
|
||
|
||
if (SynchronousIo && !PagingIo) {
|
||
FileObject->CurrentByteOffset.LowPart =
|
||
StartingVbo + Irp->IoStatus.Information;
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
|
||
|
||
FatCompleteRequest( IrpContext, Irp, Status );
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// At this point we know there is an Fcb/Dcb.
|
||
//
|
||
|
||
ASSERT( FcbOrDcb != NULL );
|
||
|
||
//
|
||
// If this is a Cvf file, just send it to the device driver.
|
||
// We assume Mm is a good citizen.
|
||
//
|
||
|
||
if (FlagOn(FcbOrDcb->FcbState, FCB_STATE_COMPRESSED_VOLUME_FILE)) {
|
||
|
||
//
|
||
// If this is the comprerssed file, check the FcbCondition
|
||
//
|
||
|
||
FatVerifyFcb( IrpContext, FcbOrDcb );
|
||
|
||
//
|
||
// If for any reason the Mcb was reset, re-initialize it.
|
||
//
|
||
|
||
if (FcbOrDcb->Header.AllocationSize.LowPart == 0xffffffff) {
|
||
|
||
FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
|
||
}
|
||
|
||
//
|
||
// Do the usual STATUS_PENDING things.
|
||
//
|
||
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// Perform the actual IO, it will be completed when the io finishes.
|
||
//
|
||
|
||
FatPagingFileIo( Irp, FcbOrDcb );
|
||
|
||
//
|
||
// We, nor anybody else, need the IrpContext any more.
|
||
//
|
||
|
||
FatDeleteIrpContext( IrpContext );
|
||
|
||
DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
|
||
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
//
|
||
// Use a try-finally to free Fcb/Dcb and buffers on the way out.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// This case corresponds to a normal user read file.
|
||
//
|
||
|
||
if ( TypeOfRead == UserFileOpen) {
|
||
|
||
ULONG FileSize;
|
||
ULONG ValidDataLength;
|
||
|
||
DebugTrace(0, Dbg, "Type of read is user file open\n", 0);
|
||
|
||
//
|
||
// If this is a noncached transfer and is not a paging I/O, and
|
||
// the file has a data section, then we will do a flush here
|
||
// to avoid stale data problems. Note that we must flush before
|
||
// acquiring the Fcb shared since the write may try to acquire
|
||
// it exclusive.
|
||
//
|
||
|
||
if (!PagingIo && NonCachedIo
|
||
|
||
&&
|
||
|
||
(FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
|
||
|
||
//
|
||
// We hold the main resource exclusive here because the flush
|
||
// may generate a recursive write in this thread. The PagingIo
|
||
// resource is held shared so the drop-and-release serialization
|
||
// below will work.
|
||
//
|
||
|
||
if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
ExAcquireResourceShared( FcbOrDcb->Header.PagingIoResource, TRUE );
|
||
|
||
CcFlushCache( FileObject->SectionObjectPointer,
|
||
&StartingByte,
|
||
ByteCount,
|
||
&Irp->IoStatus );
|
||
|
||
ExReleaseResource( FcbOrDcb->Header.PagingIoResource );
|
||
FatReleaseFcb( IrpContext, FcbOrDcb );
|
||
|
||
if (!NT_SUCCESS( Irp->IoStatus.Status)) {
|
||
|
||
try_return( Irp->IoStatus.Status );
|
||
}
|
||
|
||
//
|
||
// Acquiring and immediately dropping the resource serializes
|
||
// us behind any other writes taking place (either from the
|
||
// lazy writer or modified page writer).
|
||
//
|
||
|
||
ExAcquireResourceExclusive( FcbOrDcb->Header.PagingIoResource, TRUE );
|
||
ExReleaseResource( FcbOrDcb->Header.PagingIoResource );
|
||
}
|
||
|
||
//
|
||
// We need shared access to the Fcb/Dcb before proceeding.
|
||
//
|
||
|
||
if ( PagingIo ) {
|
||
|
||
if (!ExAcquireResourceShared( FcbOrDcb->Header.PagingIoResource,
|
||
Wait )) {
|
||
|
||
DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %08lx shared without waiting\n", FcbOrDcb );
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
if (!Wait) {
|
||
|
||
IrpContext->FatIoContext->Wait.Async.Resource =
|
||
FcbOrDcb->Header.PagingIoResource;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// If this is async I/O directly to the disk we need to check that
|
||
// we don't exhaust the number of times a single thread can
|
||
// acquire the resource. Also, we will wait if there is an
|
||
// exclusive waiter.
|
||
//
|
||
|
||
if (!Wait && NonCachedIo) {
|
||
|
||
if (!FatAcquireSharedFcbWaitForEx( IrpContext, FcbOrDcb )) {
|
||
|
||
DebugTrace( 0,
|
||
Dbg,
|
||
"Cannot acquire FcbOrDcb = %08lx shared without waiting\n",
|
||
FcbOrDcb );
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
if (ExIsResourceAcquiredShared( FcbOrDcb->Header.Resource )
|
||
> MAX_FCB_ASYNC_ACQUIRE) {
|
||
|
||
FcbOrDcbAcquired = TRUE;
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
IrpContext->FatIoContext->Wait.Async.Resource =
|
||
FcbOrDcb->Header.Resource;
|
||
|
||
} else {
|
||
|
||
if (!FatAcquireSharedFcb( IrpContext, FcbOrDcb )) {
|
||
|
||
DebugTrace( 0,
|
||
Dbg,
|
||
"Cannot acquire FcbOrDcb = %08lx shared without waiting\n",
|
||
FcbOrDcb );
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
}
|
||
}
|
||
|
||
FcbOrDcbAcquired = TRUE;
|
||
|
||
//
|
||
// We check whether we can proceed
|
||
// based on the state of the file oplocks.
|
||
//
|
||
|
||
Status = FsRtlCheckOplock( &FcbOrDcb->Specific.Fcb.Oplock,
|
||
Irp,
|
||
IrpContext,
|
||
FatOplockComplete,
|
||
FatPrePostIrp );
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
|
||
OplockPostIrp = TRUE;
|
||
PostIrp = TRUE;
|
||
try_return( NOTHING );
|
||
}
|
||
|
||
//
|
||
// Set the flag indicating if Fast I/O is possible
|
||
//
|
||
|
||
FcbOrDcb->Header.IsFastIoPossible = FatIsFastIoPossible( FcbOrDcb );
|
||
|
||
//
|
||
// Make sure the FcbOrDcb is still good
|
||
//
|
||
|
||
FatVerifyFcb( IrpContext, FcbOrDcb );
|
||
|
||
//
|
||
// We have to check for read access according to the current
|
||
// state of the file locks, and set FileSize from the Fcb.
|
||
//
|
||
|
||
if (!PagingIo &&
|
||
!FsRtlCheckLockForReadAccess( &FcbOrDcb->Specific.Fcb.FileLock,
|
||
Irp )) {
|
||
|
||
try_return( Status = STATUS_FILE_LOCK_CONFLICT );
|
||
}
|
||
|
||
FileSize = FcbOrDcb->Header.FileSize.LowPart;
|
||
ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
|
||
|
||
//
|
||
// If the read starts beyond End of File, return EOF.
|
||
//
|
||
|
||
if (StartingVbo >= FileSize) {
|
||
|
||
DebugTrace( 0, Dbg, "End of File\n", 0 );
|
||
|
||
try_return ( Status = STATUS_END_OF_FILE );
|
||
}
|
||
|
||
//
|
||
// If the read extends beyond EOF, truncate the read
|
||
//
|
||
|
||
if (ByteCount > FileSize - StartingVbo) {
|
||
|
||
ByteCount = FileSize - StartingVbo;
|
||
|
||
RequestedByteCount = ByteCount;
|
||
|
||
if (NonCachedIo && !Wait) {
|
||
|
||
IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
|
||
RequestedByteCount;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// HANDLE THE NON-CACHED CASE
|
||
//
|
||
|
||
if ( NonCachedIo ) {
|
||
|
||
ULONG SectorSize;
|
||
ULONG BytesToRead;
|
||
|
||
BOOLEAN ZeroBeyondValidData = FALSE;
|
||
ULONG ZeroingOffset;
|
||
ULONG BytesToZero;
|
||
|
||
DebugTrace(0, Dbg, "Non cached read.\n", 0);
|
||
|
||
//
|
||
// Start by zeroing any part of the read after Valid Data
|
||
//
|
||
|
||
if (ValidDataLength < FcbOrDcb->ValidDataToDisk) {
|
||
|
||
ValidDataLength = FcbOrDcb->ValidDataToDisk;
|
||
}
|
||
|
||
if ( StartingVbo + ByteCount > ValidDataLength ) {
|
||
|
||
SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
|
||
|
||
if (StartingVbo < ValidDataLength) {
|
||
|
||
//
|
||
// If we can't wait, we must post this.
|
||
//
|
||
|
||
if (!Wait) {
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
ZeroingOffset = ValidDataLength - StartingVbo;
|
||
BytesToZero = ByteCount - ZeroingOffset;
|
||
ZeroBeyondValidData = TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// All we have to do now is sit here and zero the
|
||
// user's buffer, no reading is required.
|
||
//
|
||
|
||
SafeZeroMemory( (PUCHAR)SystemBuffer, ByteCount );
|
||
|
||
Irp->IoStatus.Information = ByteCount;
|
||
|
||
try_return ( Status = STATUS_SUCCESS );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reduce the byte count to actually read if it extends beyond
|
||
// Valid Data Length
|
||
//
|
||
|
||
ByteCount = (ValidDataLength - StartingVbo < ByteCount) ?
|
||
ValidDataLength - StartingVbo : ByteCount;
|
||
//
|
||
// Get the sector size
|
||
//
|
||
|
||
SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
|
||
|
||
//
|
||
// Round up to a sector boundary, and remember if we are
|
||
// reading extra bytes.
|
||
//
|
||
|
||
BytesToRead = (ByteCount + (SectorSize - 1))
|
||
& ~(SectorSize - 1);
|
||
|
||
if (BytesToRead > ByteCount) {
|
||
|
||
//
|
||
// If we can't wait, we must post this.
|
||
//
|
||
|
||
if (!Wait) {
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Just to help alleviate confusion. At this point:
|
||
//
|
||
// RequestedByteCount - is the number of bytes originally
|
||
// taken from the Irp, but constrained
|
||
// to filesize.
|
||
//
|
||
// ByteCount - is RequestedByteCount constrained to
|
||
// ValidDataLength.
|
||
//
|
||
// BytesToRead - is ByteCount rounded up to sector
|
||
// boundry. This is the number of bytes
|
||
// that we must physically read.
|
||
//
|
||
|
||
//
|
||
// If this request is not properly aligned, or extending
|
||
// to a sector boundary would overflow the buffer, send it off
|
||
// on a special-case path.
|
||
//
|
||
|
||
if ( (StartingVbo & (SectorSize - 1)) ||
|
||
(BytesToRead > IrpSp->Parameters.Read.Length) ) {
|
||
|
||
//
|
||
// If we can't wait, we must post this.
|
||
//
|
||
|
||
if (!Wait) {
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
//
|
||
// Do the physical read
|
||
//
|
||
|
||
FatNonCachedNonAlignedRead( IrpContext,
|
||
Irp,
|
||
FcbOrDcb,
|
||
StartingVbo,
|
||
ByteCount );
|
||
|
||
//
|
||
// This routine correctly copied to the byte, so no
|
||
// zeroing is required. Also Set BytesToRead to
|
||
// ByteCount to satify the following ASSERT.
|
||
//
|
||
|
||
ZeroBeyondValidData = FALSE;
|
||
|
||
BytesToRead = ByteCount;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Perform the actual IO
|
||
//
|
||
|
||
if (FatNonCachedIo( IrpContext,
|
||
Irp,
|
||
FcbOrDcb,
|
||
StartingVbo,
|
||
BytesToRead ) == STATUS_PENDING) {
|
||
|
||
IrpContext->FatIoContext = NULL;
|
||
|
||
Irp = NULL;
|
||
|
||
try_return( Status = STATUS_PENDING );
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the call didn't succeed, raise the error status
|
||
//
|
||
|
||
if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
|
||
|
||
FatNormalizeAndRaiseStatus( IrpContext, Status );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Else set the Irp information field to reflect the
|
||
// entire desired read.
|
||
//
|
||
|
||
ASSERT( Irp->IoStatus.Information == BytesToRead );
|
||
|
||
Irp->IoStatus.Information = RequestedByteCount;
|
||
}
|
||
|
||
//
|
||
// If we rounded up to a sector boundry before, zero out
|
||
// the other garbage we read from the disk.
|
||
//
|
||
|
||
if (BytesToRead > ByteCount) {
|
||
|
||
if (SystemBuffer == NULL) {
|
||
|
||
SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
|
||
}
|
||
|
||
SafeZeroMemory( (PUCHAR)SystemBuffer + ByteCount,
|
||
BytesToRead - ByteCount );
|
||
}
|
||
|
||
//
|
||
// If we rounded up to a sector boundry before, zero out
|
||
// the other garbage we read from the disk.
|
||
//
|
||
|
||
if ( ZeroBeyondValidData ) {
|
||
|
||
SafeZeroMemory( (PUCHAR)SystemBuffer + ZeroingOffset,
|
||
BytesToZero );
|
||
}
|
||
|
||
//
|
||
// The transfer is complete.
|
||
//
|
||
|
||
try_return( Status );
|
||
|
||
} // if No Intermediate Buffering
|
||
|
||
|
||
//
|
||
// HANDLE CACHED CASE
|
||
//
|
||
|
||
else {
|
||
|
||
//
|
||
// We delay setting up the file cache until now, in case the
|
||
// caller never does any I/O to the file, and thus
|
||
// FileObject->PrivateCacheMap == NULL.
|
||
//
|
||
|
||
if (FileObject->PrivateCacheMap == NULL) {
|
||
|
||
DebugTrace(0, Dbg, "Initialize cache mapping.\n", 0);
|
||
|
||
//
|
||
// Get the file allocation size, and if it is less than
|
||
// the file size, raise file corrupt error.
|
||
//
|
||
|
||
if (FcbOrDcb->Header.AllocationSize.LowPart == 0xffffffff) {
|
||
|
||
FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
|
||
}
|
||
|
||
if ( FileSize > FcbOrDcb->Header.AllocationSize.LowPart ) {
|
||
|
||
FatPopUpFileCorrupt( IrpContext, FcbOrDcb );
|
||
|
||
FatRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
|
||
}
|
||
|
||
//
|
||
// Now initialize the cache map.
|
||
//
|
||
|
||
CcInitializeCacheMap( FileObject,
|
||
(PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize,
|
||
FALSE,
|
||
&FatData.CacheManagerCallbacks,
|
||
FcbOrDcb );
|
||
|
||
CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY );
|
||
}
|
||
|
||
|
||
//
|
||
// DO A NORMAL CACHED READ, if the MDL bit is not set,
|
||
//
|
||
|
||
DebugTrace(0, Dbg, "Cached read.\n", 0);
|
||
|
||
if (!FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
|
||
|
||
//
|
||
// Get hold of the user's buffer.
|
||
//
|
||
|
||
SystemBuffer = FatMapUserBuffer( IrpContext, Irp );
|
||
|
||
//
|
||
// Now try to do the copy.
|
||
//
|
||
|
||
if (!CcCopyRead( FileObject,
|
||
&StartingByte,
|
||
ByteCount,
|
||
Wait,
|
||
SystemBuffer,
|
||
&Irp->IoStatus )) {
|
||
|
||
DebugTrace( 0, Dbg, "Cached Read could not wait\n", 0 );
|
||
|
||
try_return( PostIrp = TRUE );
|
||
}
|
||
|
||
Status = Irp->IoStatus.Status;
|
||
|
||
ASSERT( NT_SUCCESS( Status ));
|
||
|
||
try_return( Status );
|
||
}
|
||
|
||
|
||
//
|
||
// HANDLE A MDL READ
|
||
//
|
||
|
||
else {
|
||
|
||
DebugTrace(0, Dbg, "MDL read.\n", 0);
|
||
|
||
ASSERT( Wait );
|
||
|
||
CcMdlRead( FileObject,
|
||
&StartingByte,
|
||
ByteCount,
|
||
&Irp->MdlAddress,
|
||
&Irp->IoStatus );
|
||
|
||
Status = Irp->IoStatus.Status;
|
||
|
||
ASSERT( NT_SUCCESS( Status ));
|
||
|
||
try_return( Status );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// These two cases correspond to a system read directory file and
|
||
// ea file.
|
||
//
|
||
|
||
if (( TypeOfRead == DirectoryFile ) || ( TypeOfRead == EaFile)) {
|
||
|
||
ULONG SectorSize;
|
||
|
||
DebugTrace(0, Dbg, "Read Directory or Ea file.\n", 0);
|
||
|
||
//
|
||
// For the noncached case, assert that everything is sector
|
||
// alligned.
|
||
//
|
||
|
||
SectorSize = (ULONG)Vcb->Bpb.BytesPerSector;
|
||
|
||
//
|
||
// We make several assumptions about these two types of files.
|
||
// Make sure all of them are true.
|
||
//
|
||
|
||
ASSERT( NonCachedIo && PagingIo );
|
||
ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
|
||
|
||
//
|
||
// These calls must allways be within the allocation size
|
||
//
|
||
|
||
if (StartingVbo >= FcbOrDcb->Header.AllocationSize.LowPart) {
|
||
|
||
DebugTrace( 0, Dbg, "PagingIo dirent started beyond EOF.\n", 0 );
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
try_return( Status = STATUS_SUCCESS );
|
||
}
|
||
|
||
if ( StartingVbo + ByteCount > FcbOrDcb->Header.AllocationSize.LowPart ) {
|
||
|
||
DebugTrace( 0, Dbg, "PagingIo dirent extending beyond EOF.\n", 0 );
|
||
ByteCount = FcbOrDcb->Header.AllocationSize.LowPart - StartingVbo;
|
||
}
|
||
|
||
//
|
||
// Perform the actual IO
|
||
//
|
||
|
||
if (FatNonCachedIo( IrpContext,
|
||
Irp,
|
||
FcbOrDcb,
|
||
StartingVbo,
|
||
ByteCount ) == STATUS_PENDING) {
|
||
|
||
IrpContext->FatIoContext = NULL;
|
||
|
||
Irp = NULL;
|
||
|
||
try_return( Status = STATUS_PENDING );
|
||
}
|
||
|
||
//
|
||
// If the call didn't succeed, raise the error status
|
||
//
|
||
|
||
if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
|
||
|
||
FatNormalizeAndRaiseStatus( IrpContext, Status );
|
||
|
||
} else {
|
||
|
||
ASSERT( Irp->IoStatus.Information == ByteCount );
|
||
}
|
||
|
||
try_return( Status );
|
||
}
|
||
|
||
//
|
||
// This is the case of a user who openned a directory. No reading is
|
||
// allowed.
|
||
//
|
||
|
||
if ( TypeOfRead == UserDirectoryOpen ) {
|
||
|
||
DebugTrace( 0, Dbg, "CommonRead -> STATUS_INVALID_PARAMETER\n", 0);
|
||
|
||
try_return( Status = STATUS_INVALID_PARAMETER );
|
||
}
|
||
|
||
//
|
||
// If we get this far, something really serious is wrong.
|
||
//
|
||
|
||
DebugDump("Illegal TypeOfRead\n", 0, FcbOrDcb );
|
||
|
||
FatBugCheck( TypeOfRead, 0, 0 );
|
||
|
||
try_exit: NOTHING;
|
||
|
||
//
|
||
// If the request was not posted and there's an Irp, deal with it.
|
||
//
|
||
|
||
if ( Irp ) {
|
||
|
||
if ( !PostIrp ) {
|
||
|
||
ULONG ActualBytesRead;
|
||
|
||
DebugTrace( 0, Dbg, "Completing request with status = %08lx\n",
|
||
Status);
|
||
|
||
DebugTrace( 0, Dbg, " Information = %08lx\n",
|
||
Irp->IoStatus.Information);
|
||
|
||
//
|
||
// Record the total number of bytes actually read
|
||
//
|
||
|
||
ActualBytesRead = Irp->IoStatus.Information;
|
||
|
||
//
|
||
// If the file was opened for Synchronous IO, update the current
|
||
// file position.
|
||
//
|
||
|
||
if (SynchronousIo && !PagingIo) {
|
||
|
||
FileObject->CurrentByteOffset.LowPart =
|
||
StartingVbo + ActualBytesRead;
|
||
}
|
||
|
||
//
|
||
// If this was not PagingIo, mark that the last access
|
||
// time on the dirent needs to be updated on close.
|
||
//
|
||
|
||
if (NT_SUCCESS(Status) && !PagingIo) {
|
||
|
||
SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ );
|
||
}
|
||
|
||
} else {
|
||
|
||
DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );
|
||
|
||
if (!OplockPostIrp) {
|
||
|
||
Status = FatFsdPostRequest( IrpContext, Irp );
|
||
}
|
||
}
|
||
}
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( FatCommonRead );
|
||
|
||
//
|
||
// If the FcbOrDcb has been acquired, release it.
|
||
//
|
||
|
||
if (FcbOrDcbAcquired && Irp) {
|
||
|
||
if ( PagingIo ) {
|
||
|
||
ExReleaseResource( FcbOrDcb->Header.PagingIoResource );
|
||
|
||
} else {
|
||
|
||
FatReleaseFcb( NULL, FcbOrDcb );
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Complete the request if we didn't post it and no exception
|
||
//
|
||
// Note that FatCompleteRequest does the right thing if either
|
||
// IrpContext or Irp are NULL
|
||
//
|
||
|
||
if ( !PostIrp && !AbnormalTermination() ) {
|
||
|
||
FatCompleteRequest( IrpContext, Irp, Status );
|
||
}
|
||
|
||
|
||
DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Local support routine
|
||
//
|
||
|
||
VOID
|
||
FatOverflowPagingFileRead (
|
||
IN PVOID Context,
|
||
IN PKEVENT Event
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine simply call FatPagingFileIo. It is invoked in cases when
|
||
there was not enough stack space to perform the pagefault in the
|
||
original thread. It is also responsible for freeing the packet pool.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies the Irp being processed
|
||
|
||
Fcb - Supplies the paging file Fcb, since we have it handy.
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
|
||
{
|
||
PPAGING_FILE_OVERFLOW_PACKET Packet = Context;
|
||
|
||
FatPagingFileIo( Packet->Irp, Packet->Fcb );
|
||
|
||
//
|
||
// Set the stack overflow item's event to tell the original
|
||
// thread that we're done.
|
||
//
|
||
|
||
KeSetEvent( Event, 0, FALSE );
|
||
|
||
return;
|
||
}
|
||
|
||
|