/*++ 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