mirror of
https://github.com/reactos/reactos.git
synced 2024-10-05 00:43:21 +00:00
971 lines
28 KiB
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;
|
|
}
|