NTSTATUS Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; ULONG ReturnedLength = 0; LARGE_INTEGER ByteOffset; BOOLEAN OpPostIrp = FALSE; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; BOOLEAN PagingIoResourceAcquired = FALSE; PUCHAR Buffer; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; ASSERT(Fcb); ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache)); if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) || IsFileDeleted(Fcb->Mcb)) { Status = STATUS_FILE_DELETED; __leave; } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) || Length & (SECTOR_SIZE - 1))) { Status = STATUS_INVALID_PARAMETER; DbgBreak(); __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; DbgBreak(); __leave; } if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) { CcFlushCache( FileObject->SectionObjectPointer, &ByteOffset, Length, &Irp->IoStatus ); if (!NT_SUCCESS(Irp->IoStatus.Status)) { __leave; } } ReturnedLength = Length; if (PagingIo) { if (!ExAcquireResourceSharedLite( &Fcb->PagingIoResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } PagingIoResourceAcquired = TRUE; } else { if (Nocache) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } else { if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; } if (!FsRtlCheckLockForReadAccess( &Fcb->FileLockAnchor, Irp )) { Status = STATUS_FILE_LOCK_CONFLICT; __leave; } } 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; __leave; } ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } if (!IsDirectory(Fcb) && Ccb != NULL) { Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, Ext2OplockComplete, Ext2LockIrp ); if (Status != STATUS_SUCCESS) { OpPostIrp = TRUE; __leave; } // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); } if (!Nocache) { if (IsDirectory(Fcb)) { __leave; } if (FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( FileObject, (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize), FALSE, &Ext2Global->CacheManagerCallbacks, Fcb ); CcSetReadAheadGranularity( FileObject, READ_AHEAD_GRANULARITY ); } if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcMdlRead( FileObject, (&ByteOffset), ReturnedLength, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { Status = STATUS_INVALID_USER_BUFFER; DbgBreak(); __leave; } if (!CcCopyRead(FileObject, &ByteOffset, ReturnedLength, Ext2CanIWait(), Buffer, &Irp->IoStatus)) { if (Ext2CanIWait() || !CcCopyRead(FileObject, &ByteOffset, ReturnedLength, TRUE, Buffer, &Irp->IoStatus)) { Status = STATUS_PENDING; DbgBreak(); __leave; } } Status = Irp->IoStatus.Status; } } else { ULONG BytesRead = ReturnedLength; PUCHAR SystemVA = Ext2GetUserBuffer(IrpContext->Irp); if (ByteOffset.QuadPart + BytesRead > Fcb->Header.ValidDataLength.QuadPart) { if (ByteOffset.QuadPart >= Fcb->Header.ValidDataLength.QuadPart) { if (SystemVA) { SafeZeroMemory(SystemVA, Length); } Irp->IoStatus.Information = ReturnedLength; Status = STATUS_SUCCESS; __leave; } else { BytesRead = (ULONG)(Fcb->Header.ValidDataLength.QuadPart - ByteOffset.QuadPart); if (SystemVA) { SafeZeroMemory(SystemVA + BytesRead, Length - BytesRead); } } } Status = Ext2LockUserBuffer( IrpContext->Irp, BytesRead, IoReadAccess ); if (!NT_SUCCESS(Status)) { __leave; } Status = Ext2ReadInode( IrpContext, Vcb, Fcb->Mcb, ByteOffset.QuadPart, NULL, BytesRead, TRUE, NULL ); /* we need re-queue this request in case STATUS_CANT_WAIT and fail it in other failure cases */ if (!NT_SUCCESS(Status)) { __leave; } /* pended by low level device */ if (Status == STATUS_PENDING) { IrpContext->Irp = Irp = NULL; __leave; } Irp = IrpContext->Irp; ASSERT(Irp); Status = Irp->IoStatus.Status; if (!NT_SUCCESS(Status)) { Ext2NormalizeAndRaiseStatus(IrpContext, Status); } } Irp->IoStatus.Information = ReturnedLength; } __finally { if (Irp) { if (PagingIoResourceAcquired) { ExReleaseResourceLite(&Fcb->PagingIoResource); } if (MainResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); } } if (!OpPostIrp && !IrpContext->ExceptionInProgress) { if (Irp) { if ( Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { if (NT_SUCCESS(Status)) { if (!PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } FileObject->Flags |= FO_FILE_FAST_IO_READ; } } Ext2CompleteIrpContext(IrpContext, Status); } } else { Ext2FreeIrpContext(IrpContext); } } } DEBUG(DL_IO, ("Ext2ReadFile: %wZ fetch at Off=%I64xh Len=%xh Paging=%xh Nocache=%xh Returned=%xh Status=%xh\n", &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache, ReturnedLength, Status)); return Status; }
NTSTATUS Ext2ReadVolume (IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_CCB Ccb = NULL; PEXT2_FCBVCB FcbOrVcb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL; ULONG Length; LARGE_INTEGER ByteOffset; BOOLEAN PagingIo; BOOLEAN Nocache; BOOLEAN SynchronousIo; BOOLEAN MainResourceAcquired = FALSE; PUCHAR Buffer = NULL; EXT2_EXTENT BlockArray; __try { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); FileObject = IrpContext->FileObject; FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext; ASSERT(FcbOrVcb); if (!(FcbOrVcb->Identifier.Type == EXT2VCB && (PVOID)FcbOrVcb == (PVOID)Vcb)) { Status = STATUS_INVALID_DEVICE_REQUEST; __leave; } Ccb = (PEXT2_CCB) FileObject->FsContext2; Irp = IrpContext->Irp; Irp->IoStatus.Information = 0; IoStackLocation = IoGetCurrentIrpStackLocation(Irp); Length = IoStackLocation->Parameters.Read.Length; ByteOffset = IoStackLocation->Parameters.Read.ByteOffset; PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO); Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE) || (Ccb != NULL); SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); if (PagingIo) { ASSERT(Nocache); } if (Length == 0) { Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; __leave; } if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) { ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC); Status = STATUS_PENDING; __leave; } if (ByteOffset.QuadPart >= Vcb->PartitionInformation.PartitionLength.QuadPart ) { Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; __leave; } if (ByteOffset.QuadPart + Length > Vcb->Header.FileSize.QuadPart) { Length = (ULONG)(Vcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); } /* * User direct volume access */ if (Ccb != NULL && !PagingIo) { if (!ExAcquireResourceExclusiveLite( &Vcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; __leave; } MainResourceAcquired = TRUE; if (!FlagOn(Ccb->Flags, CCB_VOLUME_DASD_PURGE)) { if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { Ext2FlushVolume(IrpContext, Vcb, FALSE); } SetFlag(Ccb->Flags, CCB_VOLUME_DASD_PURGE); } ExReleaseResourceLite(&Vcb->MainResource); MainResourceAcquired = FALSE; /* will do Nocache i/o */ } /* * I/O to volume StreamObject */ if (!Nocache) { if (IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) { CcMdlRead( Vcb->Volume, &ByteOffset, Length, &Irp->MdlAddress, &Irp->IoStatus ); Status = Irp->IoStatus.Status; } else { Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; __leave; } if (!CcCopyRead( Vcb->Volume, &ByteOffset, Length, Ext2CanIWait(), Buffer, &Irp->IoStatus )) { Status = STATUS_PENDING; __leave; } Status = Irp->IoStatus.Status; } } else { Length &= ~((ULONG)SECTOR_SIZE - 1); Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (!NT_SUCCESS(Status)) { __leave; } BlockArray.Irp = NULL; BlockArray.Lba = ByteOffset.QuadPart; BlockArray.Offset = 0; BlockArray.Length = Length; BlockArray.Next = NULL; Status = Ext2ReadWriteBlocks(IrpContext, Vcb, &BlockArray, Length ); Irp = IrpContext->Irp; if (!Irp) { __leave; } } } __finally { if (MainResourceAcquired) { ExReleaseResourceLite(&Vcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Irp) { if (Status == STATUS_PENDING && !IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED)) { Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess ); if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { if (NT_SUCCESS(Status)) { if (!PagingIo) { if (SynchronousIo) { FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information; } FileObject->Flags |= FO_FILE_FAST_IO_READ; } } Ext2CompleteIrpContext(IrpContext, Status);; } } else { Ext2FreeIrpContext(IrpContext); } } } return Status; }
NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); UINT8* data; PFILE_OBJECT FileObject = IrpSp->FileObject; fcb* fcb = FileObject->FsContext; UINT64 start; ULONG length, bytes_read; NTSTATUS Status; BOOL top_level; FsRtlEnterFileSystem(); top_level = is_top_level(Irp); TRACE("read\n"); Irp->IoStatus.Information = 0; if (IrpSp->MinorFunction & IRP_MN_COMPLETE) { CcMdlReadComplete(IrpSp->FileObject, Irp->MdlAddress); Irp->MdlAddress = NULL; Status = STATUS_SUCCESS; bytes_read = 0; goto exit; } start = IrpSp->Parameters.Read.ByteOffset.QuadPart; length = IrpSp->Parameters.Read.Length; bytes_read = 0; if (!fcb || !fcb->Vcb || !fcb->subvol) { Status = STATUS_INTERNAL_ERROR; // FIXME - invalid param error? goto exit; } TRACE("file = %S (fcb = %p)\n", file_desc(FileObject), fcb); TRACE("offset = %llx, length = %x\n", start, length); TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "TRUE" : "FALSE", Irp->Flags & IRP_NOCACHE ? "TRUE" : "FALSE"); if (fcb->type == BTRFS_TYPE_DIRECTORY) { Status = STATUS_INVALID_DEVICE_REQUEST; goto exit; } if (!(Irp->Flags & IRP_PAGING_IO) && !FsRtlCheckLockForReadAccess(&fcb->lock, Irp)) { WARN("tried to read locked region\n"); Status = STATUS_FILE_LOCK_CONFLICT; goto exit; } if (length == 0) { WARN("tried to read zero bytes\n"); Status = STATUS_SUCCESS; goto exit; } if (start >= fcb->Header.FileSize.QuadPart) { TRACE("tried to read with offset after file end (%llx >= %llx)\n", start, fcb->Header.FileSize.QuadPart); Status = STATUS_END_OF_FILE; goto exit; } TRACE("FileObject %p fcb %p FileSize = %llx st_size = %llx (%p)\n", FileObject, fcb, fcb->Header.FileSize.QuadPart, fcb->inode_item.st_size, &fcb->inode_item.st_size); // int3; if (Irp->Flags & IRP_NOCACHE || !(IrpSp->MinorFunction & IRP_MN_MDL)) { data = map_user_buffer(Irp); if (Irp->MdlAddress && !data) { ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } if (length + start > fcb->Header.ValidDataLength.QuadPart) { RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), length - (fcb->Header.ValidDataLength.QuadPart - start)); length = fcb->Header.ValidDataLength.QuadPart - start; } } if (!(Irp->Flags & IRP_NOCACHE)) { BOOL wait; Status = STATUS_SUCCESS; _SEH2_TRY { if (!FileObject->PrivateCacheMap) { CC_FILE_SIZES ccfs; ccfs.AllocationSize = fcb->Header.AllocationSize; ccfs.FileSize = fcb->Header.FileSize; ccfs.ValidDataLength = fcb->Header.ValidDataLength; TRACE("calling CcInitializeCacheMap (%llx, %llx, %llx)\n", ccfs.AllocationSize.QuadPart, ccfs.FileSize.QuadPart, ccfs.ValidDataLength.QuadPart); CcInitializeCacheMap(FileObject, &ccfs, FALSE, cache_callbacks, FileObject); CcSetReadAheadGranularity(FileObject, READ_AHEAD_GRANULARITY); } // FIXME - uncomment this when async is working // wait = IoIsOperationSynchronous(Irp) ? TRUE : FALSE; wait = TRUE; if (IrpSp->MinorFunction & IRP_MN_MDL) { CcMdlRead(FileObject,&IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus); } else { TRACE("CcCopyRead(%p, %llx, %x, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus); TRACE("sizes = %llx, %llx, %llx\n", fcb->Header.AllocationSize, fcb->Header.FileSize, fcb->Header.ValidDataLength); if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) { TRACE("CcCopyRead failed\n"); IoMarkIrpPending(Irp); Status = STATUS_PENDING; goto exit; } TRACE("CcCopyRead finished\n"); } } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (NT_SUCCESS(Status)) { Status = Irp->IoStatus.Status; bytes_read = Irp->IoStatus.Information; } else ERR("EXCEPTION - %08x\n", Status); } else {