reactos/drivers/filesystems/reiserfs/src/read.c

971 lines
28 KiB
C

/*
* COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
* PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
* FILE: read.c
* PURPOSE:
* PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
* HOMEPAGE:
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include "rfsd.h"
/* GLOBALS ***************************************************************/
extern PRFSD_GLOBAL RfsdGlobal;
/* DEFINITIONS *************************************************************/
NTSTATUS
RfsdReadComplete (IN PRFSD_IRP_CONTEXT IrpContext);
NTSTATUS
RfsdReadFile (IN PRFSD_IRP_CONTEXT IrpContext);
NTSTATUS
RfsdReadVolume (IN PRFSD_IRP_CONTEXT IrpContext);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RfsdCompleteIrpContext)
#pragma alloc_text(PAGE, RfsdCopyRead)
#pragma alloc_text(PAGE, RfsdRead)
#pragma alloc_text(PAGE, RfsdReadVolume)
#pragma alloc_text(PAGE, RfsdReadInode)
#pragma alloc_text(PAGE, RfsdReadFile)
#pragma alloc_text(PAGE, RfsdReadComplete)
#endif
/* FUNCTIONS *************************************************************/
/** Proxy to CcCopyRead, which simply asserts the success of the IoStatus. */
BOOLEAN
RfsdCopyRead(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN BOOLEAN Wait,
OUT PVOID Buffer,
OUT PIO_STATUS_BLOCK IoStatus
)
{
BOOLEAN bRet;
PAGED_CODE();
bRet= CcCopyRead(FileObject,
FileOffset,
Length,
Wait,
Buffer,
IoStatus );
if (bRet) {
ASSERT(NT_SUCCESS(IoStatus->Status));
}
return bRet;
/*
PVOID Bcb = NULL;
PVOID Buf = NULL;
if (CcMapData( FileObject,
FileOffset,
Length,
Wait,
&Bcb,
&Buf )) {
RtlCopyMemory(Buffer, Buf, Length);
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = Length;
CcUnpinData(Bcb);
return TRUE;
} else {
// IoStatus->Status = STATUS_
return FALSE;
}
*/
}
__drv_mustHoldCriticalRegion
NTSTATUS
RfsdReadVolume (IN PRFSD_IRP_CONTEXT IrpContext)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRFSD_VCB Vcb = 0;
PRFSD_CCB Ccb;
PRFSD_FCBVCB FcbOrVcb;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
PIO_STACK_LOCATION IoStackLocation;
ULONG Length;
LARGE_INTEGER ByteOffset;
BOOLEAN PagingIo;
BOOLEAN Nocache;
BOOLEAN SynchronousIo;
BOOLEAN MainResourceAcquired = FALSE;
BOOLEAN PagingIoResourceAcquired = FALSE;
PUCHAR Buffer = NULL;
PRFSD_BDL rfsd_bdl = NULL;
PAGED_CODE();
_SEH2_TRY {
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
FileObject = IrpContext->FileObject;
FcbOrVcb = (PRFSD_FCBVCB) FileObject->FsContext;
ASSERT(FcbOrVcb);
if (!(FcbOrVcb->Identifier.Type == RFSDVCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
Ccb = (PRFSD_CCB) FileObject->FsContext2;
Irp = IrpContext->Irp;
Irp->IoStatus.Information = 0;
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
Length = IoStackLocation->Parameters.Read.Length;
ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);
if (Length == 0) {
Irp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
if (Ccb != NULL) {
if(!IsFlagOn(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO)) {
if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) {
Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
}
}
{
RFSD_BDL BlockArray;
if ((ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
(Length & (SECTOR_SIZE - 1)) ) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
Status = RfsdLockUserBuffer(
IrpContext->Irp,
Length,
IoReadAccess );
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
BlockArray.Irp = NULL;
BlockArray.Lba = ByteOffset.QuadPart;;
BlockArray.Offset = 0;
BlockArray.Length = Length;
Status = RfsdReadWriteBlocks(IrpContext,
Vcb,
&BlockArray,
Length,
1,
FALSE );
Irp = IrpContext->Irp;
_SEH2_LEAVE;
}
}
if (Nocache &&
( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
(Length & (SECTOR_SIZE - 1)) )) {
DbgBreak();
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
if (!PagingIo) {
if (!ExAcquireResourceSharedLite(
&Vcb->MainResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
MainResourceAcquired = TRUE;
} else {
if (!ExAcquireResourceSharedLite(
&Vcb->PagingIoResource,
IrpContext->IsSynchronous ))
{
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
PagingIoResourceAcquired = TRUE;
}
if (ByteOffset.QuadPart >=
Vcb->PartitionInformation.PartitionLength.QuadPart ) {
Irp->IoStatus.Information = 0;
Status = STATUS_END_OF_FILE;
_SEH2_LEAVE;
}
if (!Nocache) {
if ((ByteOffset.QuadPart + Length) >
Vcb->PartitionInformation.PartitionLength.QuadPart ){
Length = (ULONG) (
Vcb->PartitionInformation.PartitionLength.QuadPart -
ByteOffset.QuadPart);
Length &= ~((ULONG)SECTOR_SIZE - 1);
}
if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
CcMdlRead(
Vcb->StreamObj,
&ByteOffset,
Length,
&Irp->MdlAddress,
&Irp->IoStatus );
Status = Irp->IoStatus.Status;
} else {
Buffer = RfsdGetUserBuffer(Irp);
if (Buffer == NULL) {
DbgBreak();
Status = STATUS_INVALID_USER_BUFFER;
_SEH2_LEAVE;
}
if (!CcCopyRead(
Vcb->StreamObj,
(PLARGE_INTEGER)&ByteOffset,
Length,
IrpContext->IsSynchronous,
Buffer,
&Irp->IoStatus )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
Status = Irp->IoStatus.Status;
}
} else {
if ((ByteOffset.QuadPart + Length) >
Vcb->PartitionInformation.PartitionLength.QuadPart ) {
Length = (ULONG) (
Vcb->PartitionInformation.PartitionLength.QuadPart -
ByteOffset.QuadPart);
Length &= ~((ULONG)SECTOR_SIZE - 1);
}
Status = RfsdLockUserBuffer(
IrpContext->Irp,
Length,
IoWriteAccess );
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
#if DBG
Buffer = RfsdGetUserBuffer(Irp);
#endif
rfsd_bdl = ExAllocatePoolWithTag(PagedPool, sizeof(RFSD_BDL), RFSD_POOL_TAG);
if (!rfsd_bdl)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
_SEH2_LEAVE;
}
rfsd_bdl->Irp = NULL;
rfsd_bdl->Lba = ByteOffset.QuadPart;
rfsd_bdl->Length = Length;
rfsd_bdl->Offset = 0;
Status = RfsdReadWriteBlocks(IrpContext,
Vcb,
rfsd_bdl,
Length,
1,
FALSE );
Irp = IrpContext->Irp;
if (!Irp)
_SEH2_LEAVE;
}
} _SEH2_FINALLY {
if (PagingIoResourceAcquired) {
ExReleaseResourceForThreadLite(
&Vcb->PagingIoResource,
ExGetCurrentResourceThread());
}
if (MainResourceAcquired) {
ExReleaseResourceForThreadLite(
&Vcb->MainResource,
ExGetCurrentResourceThread());
}
if (rfsd_bdl)
ExFreePool(rfsd_bdl);
if (!IrpContext->ExceptionInProgress) {
if (IrpContext->Irp) {
if (Status == STATUS_PENDING &&
!IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED)) {
Status = RfsdLockUserBuffer(
IrpContext->Irp,
Length,
IoWriteAccess );
if (NT_SUCCESS(Status)) {
Status = RfsdQueueRequest(IrpContext);
} else {
RfsdCompleteIrpContext(IrpContext, Status);
}
} else {
if (NT_SUCCESS(Status)) {
if (!PagingIo) {
if (SynchronousIo) {
IrpContext->FileObject->CurrentByteOffset.QuadPart =
ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
}
IrpContext->FileObject->Flags |= FO_FILE_FAST_IO_READ;
}
}
RfsdCompleteIrpContext(IrpContext, Status);;
}
} else {
RfsdFreeIrpContext(IrpContext);
}
}
} _SEH2_END;
return Status;
}
// [mark] read some goop [from the file pt'd to by inode -- from whatever blocks buildbdl makes] into the buffer
NTSTATUS
RfsdReadInode (
IN PRFSD_IRP_CONTEXT IrpContext, // [may be null]
IN PRFSD_VCB Vcb,
IN PRFSD_KEY_IN_MEMORY Key, // Key that identifies the data on disk to be read. This is simply forwarded through to BuildBDL. (NOTE: IN THIS CASE, THE OFFSET AND TYPE FIELDS MATTER)
IN PRFSD_INODE Inode, // a filled Inode / stat data structure
IN ULONGLONG Offset, // User's requested offset to read within the file (relative to the file)
IN OUT PVOID Buffer, // buffer to read out to
IN ULONG Size, // size of destination buffer
OUT PULONG dwRet ) // some kind of size [probably bytes read?]
{
PRFSD_BDL Bdl = NULL;
ULONG blocks, i, j;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK IoStatus;
ULONGLONG FileSize;
ULONGLONG AllocSize;
PAGED_CODE();
if (dwRet) {
*dwRet = 0;
}
//
// Calculate the inode size
//
FileSize = (ULONGLONG) Inode->i_size;
//KdPrint(("Rfsd: RfsdReadInode: file size = %I64u, offset = %I64u, length = %u\n", FileSize, Offset, Size));
// TODO: temporary hack to get correct alloc size for dir tails... but i doubt 8 works in all cases :-) [what i should really be using is the size of the direct item in the block header!]
// AllocSize = CEILING_ALIGNED(FileSize, (ULONGLONG)Vcb->BlockSize);
// AllocSize = CEILING_ALIGNED(FileSize, (ULONGLONG) 8);
AllocSize = CEILING_ALIGNED(FileSize, (ULONGLONG) 1); // temp hack to ensure that i'll read out EXACTLY the # of bytes he requested
//
// Check inputed parameters: Offset / Size
//
if (Offset >= AllocSize) {
RfsdPrint((DBG_ERROR, "RfsdReadInode: beyond the file range.\n"));
return STATUS_SUCCESS;
}
if (Offset + Size > AllocSize) {
Size = (ULONG)(AllocSize - Offset);
}
//-----------------------------
//
// Build the scatterred block ranges to be read
//
Status = RfsdBuildBDL2(
Vcb, Key, Inode,
&(blocks), &(Bdl)
);
if (!NT_SUCCESS(Status)) {
goto errorout;
}
if (blocks <= 0) {
Status = STATUS_SUCCESS;
goto errorout;
}
{
ULONGLONG bufferPos = 0;
for(i = 0, j = 0; i < blocks; i++) {
if ( // The block is needed for the user's requested contents
// (The user's requested offset lies within the block, or the block's start is within the user's requested range)
( (Offset >= Bdl[i].Offset) && (Offset < (Bdl[i].Offset + Bdl[i].Length)) ) || // The user's offset is within the block's range
( (Bdl[i].Offset >= Offset) && (Bdl[i].Offset < (Offset + Size)) ) // The block's offset is within the user's range
)
{
ULONGLONG offsetFromDisk = Bdl[i].Lba;
ULONGLONG lengthToRead = min(Size - bufferPos, Bdl[i].Length);
j++;
//KdPrint(("Rfsd: blocks = %u, i = %u, j = %u\n", blocks, i, j));
//KdPrint(("Rfsd: Bdl[%u].Lba = %I64u, Bdl[%u].Offset = %I64u, Bdl[%u].Length = %u\n", i, Bdl[i].Lba, i, Bdl[i].Offset, i, Bdl[i].Length));
//KdPrint(("Rfsd: offsetFromDisk = %I64u, lengthToRead = %I64u\n", offsetFromDisk, lengthToRead));
//KdPrint(("Rfsd: Buffer = %p, bufferPos = %I64u\n", Buffer, bufferPos));
IoStatus.Information = 0;
RfsdCopyRead(
Vcb->StreamObj,
(PLARGE_INTEGER) (&offsetFromDisk), // offset (relative to partition)
(ULONG) lengthToRead, // length to read
PIN_WAIT, //
(PVOID)((PUCHAR)Buffer + bufferPos), // buffer to read into
&IoStatus );
Status = IoStatus.Status;
bufferPos += IoStatus.Information;
//KdPrint(("Rfsd: IoStatus.Status = %#x, IoStatus.Information = %u\n", IoStatus.Status, IoStatus.Information));
}
}
}
errorout:
if (Bdl) ExFreePool(Bdl);
if (NT_SUCCESS(Status)) {
if (dwRet) *dwRet = Size;
}
return Status;
}
__drv_mustHoldCriticalRegion
NTSTATUS
RfsdReadFile(IN PRFSD_IRP_CONTEXT IrpContext)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRFSD_VCB Vcb;
PRFSD_FCB Fcb = 0;
PRFSD_CCB Ccb;
PFILE_OBJECT FileObject;
PFILE_OBJECT CacheObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
PIO_STACK_LOCATION IoStackLocation;
ULONG Length;
ULONG ReturnedLength;
LARGE_INTEGER ByteOffset;
BOOLEAN PagingIo;
BOOLEAN Nocache;
BOOLEAN SynchronousIo;
BOOLEAN MainResourceAcquired = FALSE;
BOOLEAN PagingIoResourceAcquired = FALSE;
PUCHAR Buffer;
PAGED_CODE();
_SEH2_TRY {
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
FileObject = IrpContext->FileObject;
Fcb = (PRFSD_FCB) FileObject->FsContext;
ASSERT(Fcb);
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
Ccb = (PRFSD_CCB) FileObject->FsContext2;
Irp = IrpContext->Irp;
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
Length = IoStackLocation->Parameters.Read.Length;
ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
#if defined(_MSC_VER) && !defined(__clang__)
KdPrint(("$$$ " __FUNCTION__ " on key: %x,%xh to read %i bytes at the offset %xh in the file\n",
Fcb->RfsdMcb->Key.k_dir_id, Fcb->RfsdMcb->Key.k_objectid,
Length, ByteOffset.QuadPart));
#endif
PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);
/*
if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED)) {
Status = STATUS_FILE_DELETED;
_SEH2_LEAVE;
}
if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
Status = STATUS_DELETE_PENDING;
_SEH2_LEAVE;
}
*/
if (Length == 0) {
Irp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
_SEH2_LEAVE;
}
if (Nocache &&
(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
Length & (SECTOR_SIZE - 1))) {
Status = STATUS_INVALID_PARAMETER;
DbgBreak();
_SEH2_LEAVE;
}
if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
Status = STATUS_PENDING;
DbgBreak();
_SEH2_LEAVE;
}
if (!PagingIo) {
if (!ExAcquireResourceSharedLite(
&Fcb->MainResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
MainResourceAcquired = TRUE;
if (!FsRtlCheckLockForReadAccess(
&Fcb->FileLockAnchor,
Irp )) {
Status = STATUS_FILE_LOCK_CONFLICT;
_SEH2_LEAVE;
}
} else {
if (!ExAcquireResourceSharedLite(
&Fcb->PagingIoResource,
IrpContext->IsSynchronous )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
PagingIoResourceAcquired = TRUE;
}
if (!Nocache) {
// Attempt cached access...
if ((ByteOffset.QuadPart + (LONGLONG)Length) >
Fcb->Header.FileSize.QuadPart ) {
if (ByteOffset.QuadPart >= (Fcb->Header.FileSize.QuadPart)) {
Irp->IoStatus.Information = 0;
Status = STATUS_END_OF_FILE;
_SEH2_LEAVE;
}
Length =
(ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
}
ReturnedLength = Length;
if (IsDirectory(Fcb)) {
_SEH2_LEAVE;
}
{
if (FileObject->PrivateCacheMap == NULL) {
CcInitializeCacheMap(
FileObject,
(PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
FALSE,
&RfsdGlobal->CacheManagerCallbacks,
Fcb );
}
CacheObject = FileObject;
}
if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
CcMdlRead(
CacheObject,
(&ByteOffset),
Length,
&Irp->MdlAddress,
&Irp->IoStatus );
Status = Irp->IoStatus.Status;
} else {
Buffer = RfsdGetUserBuffer(Irp);
if (Buffer == NULL) {
Status = STATUS_INVALID_USER_BUFFER;
DbgBreak();
_SEH2_LEAVE;
}
if (!CcCopyRead(
CacheObject, // the file object (representing the open operation performed by the thread)
(PLARGE_INTEGER)&ByteOffset, // starting offset IN THE FILE, from where the read should be performed
Length, // number of bytes requested in the read operation
IrpContext->IsSynchronous,
Buffer, // < buffer to read the contents to
&Irp->IoStatus )) {
Status = STATUS_PENDING;
DbgBreak();
_SEH2_LEAVE;
}
Status = Irp->IoStatus.Status;
}
} else {
// Attempt access without the cache...
if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.AllocationSize.QuadPart) {
if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
Irp->IoStatus.Information = 0;
Status = STATUS_END_OF_FILE;
DbgBreak();
_SEH2_LEAVE;
}
Length =
(ULONG)(Fcb->Header.AllocationSize.QuadPart- ByteOffset.QuadPart);
}
ReturnedLength = Length;
/* lock the user buffer into MDL and make them paged-in */
Status = RfsdLockUserBuffer(
IrpContext->Irp,
Length,
IoWriteAccess );
if (NT_SUCCESS(Status)) {
/* Zero the total buffer */
PVOID SystemVA = RfsdGetUserBuffer(IrpContext->Irp);
if (SystemVA) {
RtlZeroMemory(SystemVA, Length);
RfsdPrint((DBG_INFO, "RfsdReadFile: Zero read buffer: Offset=%I64xh Size=%xh ... \n",
ByteOffset.QuadPart, Length));
}
} else {
_SEH2_LEAVE;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Length;
Status = RfsdReadInode(
IrpContext,
Vcb,
&(Fcb->RfsdMcb->Key),
Fcb->Inode,
ByteOffset.QuadPart,
RfsdGetUserBuffer(IrpContext->Irp), // NOTE: Ext2fsd just passes NULL for the buffer, and relies on the initial cache call to retrieve tha data. We'll instead be explicitly putting it into the user's buffer, via a much different mechanism.
Length,
&ReturnedLength);
Irp = IrpContext->Irp;
}
} _SEH2_FINALLY {
if (PagingIoResourceAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->PagingIoResource,
ExGetCurrentResourceThread());
}
if (MainResourceAcquired) {
ExReleaseResourceForThreadLite(
&Fcb->MainResource,
ExGetCurrentResourceThread());
}
if (!IrpContext->ExceptionInProgress) {
if (IrpContext->Irp) {
if (Status == STATUS_PENDING) {
Status = RfsdLockUserBuffer(
IrpContext->Irp,
Length,
IoWriteAccess );
if (NT_SUCCESS(Status)) {
Status = RfsdQueueRequest(IrpContext);
} else {
RfsdCompleteIrpContext(IrpContext, Status);
}
} else {
if (NT_SUCCESS(Status)) {
if (!PagingIo) {
if (SynchronousIo) {
IrpContext->FileObject->CurrentByteOffset.QuadPart =
ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
}
IrpContext->FileObject->Flags |= FO_FILE_FAST_IO_READ;
}
}
RfsdCompleteIrpContext(IrpContext, Status);
}
} else {
RfsdFreeIrpContext(IrpContext);
}
}
} _SEH2_END;
return Status;
}
NTSTATUS
RfsdReadComplete (IN PRFSD_IRP_CONTEXT IrpContext)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PFILE_OBJECT FileObject;
PIRP Irp;
PAGED_CODE();
_SEH2_TRY {
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
FileObject = IrpContext->FileObject;
Irp = IrpContext->Irp;
CcMdlReadComplete(FileObject, Irp->MdlAddress);
Irp->MdlAddress = NULL;
Status = STATUS_SUCCESS;
} _SEH2_FINALLY {
if (!IrpContext->ExceptionInProgress) {
RfsdCompleteIrpContext(IrpContext, Status);
}
} _SEH2_END;
return Status;
}
__drv_mustHoldCriticalRegion
NTSTATUS
RfsdRead (IN PRFSD_IRP_CONTEXT IrpContext)
{
NTSTATUS Status;
PRFSD_VCB Vcb;
PRFSD_FCBVCB FcbOrVcb;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
BOOLEAN bCompleteRequest;
PAGED_CODE();
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
_SEH2_TRY {
if (FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE)) {
// Caller wants to tell the Cache Manager that a previously allocated MDL can be freed.
Status = RfsdReadComplete(IrpContext);
bCompleteRequest = FALSE;
} else {
DeviceObject = IrpContext->DeviceObject;
if (DeviceObject == RfsdGlobal->DeviceObject) {
Status = STATUS_INVALID_DEVICE_REQUEST;
bCompleteRequest = TRUE;
_SEH2_LEAVE;
}
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
if (Vcb->Identifier.Type != RFSDVCB ||
Vcb->Identifier.Size != sizeof(RFSD_VCB) ) {
Status = STATUS_INVALID_DEVICE_REQUEST;
bCompleteRequest = TRUE;
_SEH2_LEAVE;
}
if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
Status = STATUS_TOO_LATE;
bCompleteRequest = TRUE;
_SEH2_LEAVE;
}
FileObject = IrpContext->FileObject;
FcbOrVcb = (PRFSD_FCBVCB) FileObject->FsContext;
if (FcbOrVcb->Identifier.Type == RFSDVCB) {
Status = RfsdReadVolume(IrpContext);
bCompleteRequest = FALSE;
} else if (FcbOrVcb->Identifier.Type == RFSDFCB) {
Status = RfsdReadFile(IrpContext);
bCompleteRequest = FALSE;
} else {
RfsdPrint((DBG_ERROR, "RfsdRead: INVALID PARAMETER ... \n"));
DbgBreak();
Status = STATUS_INVALID_PARAMETER;
bCompleteRequest = TRUE;
}
}
} _SEH2_FINALLY {
if (bCompleteRequest) {
RfsdCompleteIrpContext(IrpContext, Status);
}
} _SEH2_END;
return Status;
}