289 lines
6 KiB
C
289 lines
6 KiB
C
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
readwrite.c
|
|
|
|
Abstract:
|
|
|
|
This file contains RAM disk driver code for reading from and writing to
|
|
a RAM disk.
|
|
|
|
Author:
|
|
|
|
Chuck Lenzmeier (ChuckL) 2001
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
NTSTATUS
|
|
RamdiskReadWrite (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system to read from or write to a
|
|
device that we control.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device on which
|
|
I/O is to be performed
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PDISK_EXTENSION diskExtension;
|
|
PIO_STACK_LOCATION irpSp;
|
|
ULONGLONG ioOffset;
|
|
ULONG ioLength;
|
|
|
|
//
|
|
// Get the device extension pointer. Get parameters from the IRP.
|
|
//
|
|
|
|
|
|
diskExtension = DeviceObject->DeviceExtension;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ioOffset = irpSp->Parameters.Read.ByteOffset.QuadPart;
|
|
ioLength = irpSp->Parameters.Read.Length;
|
|
|
|
//
|
|
// If this is not a disk PDO, we can't handle this IRP.
|
|
//
|
|
|
|
if ( diskExtension->DeviceType != RamdiskDeviceTypeDiskPdo ) {
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
goto complete_irp;
|
|
}
|
|
|
|
DBGPRINT( DBG_READWRITE, DBG_PAINFUL,
|
|
("RamdiskReadWrite: offset %I64x, length %x\n", ioOffset, ioLength) );
|
|
|
|
//
|
|
// If it's a zero-length operation, we don't have to do anything.
|
|
//
|
|
|
|
if ( ioLength == 0 ) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
goto complete_irp;
|
|
}
|
|
|
|
//
|
|
// Check for invalid parameters:
|
|
// The transfer must be sector aligned.
|
|
// The length cannot cause the offset to wrap.
|
|
// The transfer cannot go beyond the end of the disk.
|
|
// Writes cannot be performed on a readonly disk.
|
|
//
|
|
|
|
if ( ((ioOffset | ioLength) & (diskExtension->BytesPerSector - 1)) != 0 ) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete_irp;
|
|
}
|
|
|
|
if ( (ioOffset + ioLength) < ioOffset ) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto complete_irp;
|
|
}
|
|
|
|
if ( (ioOffset + ioLength) > diskExtension->DiskLength ) {
|
|
|
|
status = STATUS_NONEXISTENT_SECTOR;
|
|
goto complete_irp;
|
|
}
|
|
|
|
if ( (irpSp->MajorFunction == IRP_MJ_WRITE) && diskExtension->Options.Readonly ) {
|
|
|
|
status = STATUS_MEDIA_WRITE_PROTECTED;
|
|
goto complete_irp;
|
|
}
|
|
|
|
//
|
|
// If the RAM disk is not file-backed, then the disk image is in memory,
|
|
// and we can do the operation regardless of what context we're in. If the
|
|
// RAM disk is file-backed, we need to be in thread context to do the
|
|
// operation.
|
|
//
|
|
|
|
if ( RAMDISK_IS_FILE_BACKED(diskExtension->DiskType) ) {
|
|
|
|
status = SendIrpToThread( DeviceObject, Irp );
|
|
if ( status != STATUS_PENDING ) {
|
|
goto complete_irp;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
status = RamdiskReadWriteReal(
|
|
Irp,
|
|
diskExtension
|
|
);
|
|
|
|
complete_irp:
|
|
|
|
//
|
|
// Complete the IRP.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
|
|
|
return status;
|
|
|
|
} // RamdiskReadWrite
|
|
|
|
NTSTATUS
|
|
RamdiskReadWriteReal (
|
|
IN PIRP Irp,
|
|
IN PDISK_EXTENSION DiskExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called in thread context to perform a read or a write.
|
|
|
|
Arguments:
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request
|
|
|
|
DiskExtension - a pointer to the device extension for the target device
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the status of the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PUCHAR bufferAddress;
|
|
PUCHAR diskByteAddress;
|
|
ULONGLONG ioOffset;
|
|
ULONG ioLength;
|
|
ULONG mappedLength;
|
|
|
|
//
|
|
// Get a system-space pointer to the user's buffer. A system address must
|
|
// be used because we may already have left the original caller's address
|
|
// space.
|
|
//
|
|
|
|
ASSERT( Irp->MdlAddress != NULL );
|
|
|
|
bufferAddress = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
|
|
|
|
if ( bufferAddress == NULL ) {
|
|
|
|
//
|
|
// Unable to get a pointer to the user's buffer.
|
|
//
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Get parameters from the IRP.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
ioOffset = irpSp->Parameters.Read.ByteOffset.QuadPart;
|
|
ioLength = irpSp->Parameters.Read.Length;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
while ( ioLength != 0 ) {
|
|
|
|
//
|
|
// Map the appropriate RAM disk pages.
|
|
//
|
|
|
|
diskByteAddress = RamdiskMapPages( DiskExtension, ioOffset, ioLength, &mappedLength );
|
|
|
|
if ( diskByteAddress == NULL ) {
|
|
|
|
//
|
|
// Unable to map the RAM disk.
|
|
//
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
ASSERT( mappedLength <= ioLength );
|
|
|
|
Irp->IoStatus.Information += mappedLength;
|
|
|
|
//
|
|
// Copy the data in the appropriate direction.
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
switch ( irpSp->MajorFunction ) {
|
|
|
|
case IRP_MJ_READ:
|
|
|
|
RtlCopyMemory( bufferAddress, diskByteAddress, mappedLength );
|
|
break;
|
|
|
|
case IRP_MJ_WRITE:
|
|
|
|
RtlCopyMemory( diskByteAddress, bufferAddress, mappedLength );
|
|
break;
|
|
|
|
default:
|
|
|
|
ASSERT( FALSE );
|
|
status = STATUS_INVALID_PARAMETER;
|
|
ioLength = mappedLength;
|
|
}
|
|
|
|
//
|
|
// Unmap the previously mapped pages.
|
|
//
|
|
|
|
RamdiskUnmapPages( DiskExtension, diskByteAddress, ioOffset, mappedLength );
|
|
|
|
ioLength -= mappedLength;
|
|
ioOffset += mappedLength;
|
|
bufferAddress += mappedLength;
|
|
}
|
|
|
|
return status;
|
|
|
|
} // RamdiskReadWriteReal
|
|
|