xbox-kernel/private/ntos/udfx/read.c
2020-09-30 17:17:25 +02:00

304 lines
8.3 KiB
C

/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
read.c
Abstract:
This module implements routines related to handling IRP_MJ_READ.
--*/
#include "udfx.h"
NTSTATUS
UdfxNonCachedReadCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called to process the completion of a non-cached file read.
Arguments:
DeviceObject - Specifies the device object that the I/O request is for.
Irp - Specifies the packet that describes the I/O request.
Context - Specifies the context that was supplied to IoSetCompletionRoutine.
Return Value:
Status of operation.
--*/
{
PIO_STACK_LOCATION IrpSp;
PFILE_OBJECT FileObject;
ULONG ReadLength;
//
// This completion routine is set to be called only on IRP success.
//
ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
IrpSp = IoGetCurrentIrpStackLocation(Irp);
FileObject = IrpSp->FileObject;
ReadLength = IrpSp->Parameters.Read.Length;
//
// Assert that the device handled as many bytes as we programmed it to.
//
ASSERT(Irp->IoStatus.Information == UDF_CD_SECTOR_ALIGN_UP(ReadLength));
//
// Propagate the pending flag up the IRP stack.
//
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
//
// Fix the number of bytes read to the number that we computed inside
// UdfxFsdRead. This number may be less than the actual number of bytes
// read from the device if we're at the end of file.
//
Irp->IoStatus.Information = ReadLength;
//
// If the file is open for synchronous I/O, then we need to update the
// current file position.
//
if (UdfxIsFlagSet(FileObject->Flags, FO_SYNCHRONOUS_IO)) {
FileObject->CurrentByteOffset.QuadPart =
IrpSp->Parameters.Read.ByteOffset.QuadPart + ReadLength;
}
return STATUS_SUCCESS;
}
NTSTATUS
UdfxFsdRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O manager to handle IRP_MJ_READ requests.
Arguments:
DeviceObject - Specifies the device object that the I/O request is for.
Irp - Specifies the packet that describes the I/O request.
Return Value:
Status of operation.
--*/
{
NTSTATUS status;
PUDF_VOLUME_EXTENSION VolumeExtension;
PIO_STACK_LOCATION IrpSp;
PIO_STACK_LOCATION NextIrpSp;
PFILE_OBJECT FileObject;
PUDF_FCB Fcb;
ULONG ReadLength;
BOOLEAN NonCachedEndOfFileTransfer;
ULONGLONG FileBytesRemaining;
ULONGLONG PhysicalByteOffset;
VolumeExtension = (PUDF_VOLUME_EXTENSION)DeviceObject->DeviceExtension;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
NextIrpSp = IoGetNextIrpStackLocation(Irp);
FileObject = IrpSp->FileObject;
Fcb = (PUDF_FCB)FileObject->FsContext;
ReadLength = IrpSp->Parameters.Read.Length;
NonCachedEndOfFileTransfer = FALSE;
//
// Check if the volume has been dismounted.
//
if (VolumeExtension->Dismounted) {
status = STATUS_VOLUME_DISMOUNTED;
goto CleanupAndExit;
}
//
// Ensure that the file object is not for a directory.
//
if (UdfxIsFlagSet(Fcb->Flags, UDF_FCB_DIRECTORY)) {
status = STATUS_INVALID_DEVICE_REQUEST;
goto CleanupAndExit;
}
//
// Disable support for reading from files with data embedded in the file
// identifier descriptor.
//
if (UdfxIsFlagSet(Fcb->Flags, UDF_FCB_EMBEDDED_DATA)) {
status = STATUS_ACCESS_DENIED;
goto CleanupAndExit;
}
//
// If this is a zero length request, then we can complete the IRP now.
//
if (ReadLength == 0) {
Irp->IoStatus.Information = 0;
status = STATUS_SUCCESS;
goto CleanupAndExit;
}
//
// Check if the starting offset is beyond the end of file.
//
if ((ULONGLONG)IrpSp->Parameters.Read.ByteOffset.QuadPart >=
(ULONGLONG)Fcb->FileSize.QuadPart) {
status = STATUS_END_OF_FILE;
goto CleanupAndExit;
}
//
// If the number of bytes to read is greater than the number of bytes
// remaining in the file, then truncate the number of bytes we'll actually
// read.
//
FileBytesRemaining = (ULONGLONG)Fcb->FileSize.QuadPart -
(ULONGLONG)IrpSp->Parameters.Read.ByteOffset.QuadPart;
if ((ULONGLONG)ReadLength >= FileBytesRemaining) {
if (UdfxIsFlagClear(Fcb->Flags, UDF_FCB_VOLUME)) {
//
// If the user's buffer is large enough to hold the logical read
// length rounded up to a sector boundary, then set a flag so that
// the below code will potentially read this part of the file as
// non cached.
//
if (ReadLength >= (UDF_CD_SECTOR_ALIGN_UP(Fcb->FileSize.LowPart) -
IrpSp->Parameters.Read.ByteOffset.LowPart)) {
NonCachedEndOfFileTransfer = TRUE;
}
}
ReadLength = (ULONG)FileBytesRemaining;
}
ASSERT(ReadLength > 0);
//
// Check if we're supposed to bypass the file system cache.
//
// If this is a physical volume file control block, also bypass the cache.
// This was the behavior of the old file systems and it also let's us avoid
// having to deal with the volume case in the cached path.
//
if (UdfxIsFlagSet(Irp->Flags, IRP_NOCACHE) ||
UdfxIsFlagSet(Fcb->Flags, UDF_FCB_VOLUME)) {
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// Lock the user's buffer into memory if necessary.
//
IoLockUserBuffer(Irp, IrpSp->Parameters.Read.Length);
//
// The file is contiguous on disk, so we can pass this IRP down to the
// target device after adjusting the starting byte offset assuming this
// isn't a volume file control block.
//
if (UdfxIsFlagClear(Fcb->Flags, UDF_FCB_VOLUME)) {
NextIrpSp->Parameters.Read.ByteOffset.QuadPart +=
((ULONGLONG)(VolumeExtension->PartitionSectorStart +
Fcb->AllocationSectorStart) << UDF_CD_SECTOR_SHIFT);
}
//
// Limit the number of bytes physically read to the end of the file or
// volume.
//
NextIrpSp->Parameters.Read.Length = UDF_CD_SECTOR_ALIGN_UP(ReadLength);
//
// If the actual number of bytes we're to read is less than the number
// of bytes we'll read from the physical device, then set a completion
// routine to fix IO_STATUS_BLOCK.Information to be the actual number
// of bytes. We'll store the actual number of bytes back in the IRP so
// that we don't have to calculate it again.
//
// If this is a synchronous I/O operation, then set a completion routine
// so that we can update the current file position.
//
// We don't have to do either of the above if the IRP completes with an
// error.
//
if ((IrpSp->Parameters.Read.Length != ReadLength) ||
UdfxIsFlagSet(FileObject->Flags, FO_SYNCHRONOUS_IO)) {
IrpSp->Parameters.Read.Length = ReadLength;
IoSetCompletionRoutine(Irp, UdfxNonCachedReadCompletion, NULL, TRUE,
FALSE, FALSE);
}
//
// Call down to the target device.
//
return IoCallDriver(VolumeExtension->TargetDeviceObject, Irp);
}
//
// Scatter/gather operations are always non-cached.
//
ASSERT(UdfxIsFlagClear(Irp->Flags, IRP_SCATTER_GATHER_OPERATION));
//
// Otherwise, handle reading the data using the file cache.
//
PhysicalByteOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart +
((ULONGLONG)(VolumeExtension->PartitionSectorStart +
Fcb->AllocationSectorStart) << UDF_CD_SECTOR_SHIFT);
status = FscCachedRead(&VolumeExtension->CacheExtension, Irp,
PhysicalByteOffset, ReadLength, NonCachedEndOfFileTransfer);
CleanupAndExit:
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}