reactos/modules/rosapps/drivers/vfd/vfdrdwr.c
Pierre Schweitzer 25c7e1a8d0
[VFD] Import the VFD project (Virtual Floppy Drive) which allows creating virtual
floppy drives in ReactOS and mount images on them.
Only the cmd got imported. The GUI interface may come later on.
Note that, as for vcdrom, the driver is left disabled and you need to explicitely
start it through vfd command line interface.

CORE-14090
2017-12-16 21:48:34 +01:00

358 lines
7.8 KiB
C

/*
vfdrdwr.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: Read and Write functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
//
// IRP_MJ_READ and IRP_MJ_WRITE dispatcher
// Insert the IRP into the IRP queue list.
// Actual operation is performed by the device thread
//
#define IO_READ_OFF(p) (p)->Parameters.Read.ByteOffset.QuadPart
#define IO_READ_LEN(p) (p)->Parameters.Read.Length
NTSTATUS
NTAPI
VfdReadWrite (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION device_extension;
PIO_STACK_LOCATION io_stack;
NTSTATUS status;
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
io_stack = IoGetCurrentIrpStackLocation(Irp);
#if DBG
if (DeviceObject && DeviceObject->DeviceExtension &&
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer) {
VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
GetMajorFuncName(io_stack->MajorFunction),
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer));
}
else {
VFDTRACE(VFDINFO, ("[VFD] %-40s %p\n",
GetMajorFuncName(io_stack->MajorFunction),
DeviceObject));
}
#endif // DBG
#ifdef VFD_PNP
if (device_extension->DeviceState != VFD_WORKING) {
// Device is not yet started or being removed, reject any IO request
// TODO: Queue the IRPs
VFDTRACE(VFDWARN, ("[VFD] Device not ready\n"));
status = STATUS_INVALID_DEVICE_STATE;
goto complete_request;
}
else {
status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] Acquire RemoveLock failed: %s\n", GetStatusName(status)));
goto complete_request;
}
}
#endif // VFD_PNP
/*
// Check if volume verification is required
if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
!(io_stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
status = STATUS_VERIFY_REQUIRED;
goto complete_request;
}
*/
// Check if an image is opened
if (!device_extension->FileHandle &&
!device_extension->FileBuffer) {
status = STATUS_NO_MEDIA_IN_DEVICE;
goto complete_request;
}
// Check if write operation is allowed
if (io_stack->MajorFunction == IRP_MJ_WRITE &&
(device_extension->MediaFlags & VFD_FLAG_WRITE_PROTECTED)) {
status = STATUS_MEDIA_WRITE_PROTECTED;
goto complete_request;
}
// Check for invalid parameters. It is an error for the starting offset
// + length to go past the end of the partition, or for the length or
// offset to not be a proper multiple of the sector size.
//
// Others are possible, but we don't check them since we trust the
// file system and they aren't deadly.
if ((IO_READ_OFF(io_stack) + IO_READ_LEN(io_stack)) >
VFD_SECTOR_TO_BYTE(device_extension->Sectors)) {
VFDTRACE(VFDWARN,
("[VFD] Offset:%I64u + Length:%u goes past the media size %lu\n",
IO_READ_OFF(io_stack), IO_READ_LEN(io_stack),
VFD_SECTOR_TO_BYTE(device_extension->Sectors)));
status = STATUS_INVALID_PARAMETER;
goto complete_request;
}
if (!VFD_SECTOR_ALIGNED((IO_READ_LEN(io_stack))) ||
!VFD_SECTOR_ALIGNED((IO_READ_OFF(io_stack)))) {
VFDTRACE(VFDWARN,
("[VFD] Invalid Alignment Offset:%I64u Length:%u\n",
IO_READ_OFF(io_stack), IO_READ_LEN(io_stack)));
status = STATUS_INVALID_PARAMETER;
goto complete_request;
}
// If read/write data length is 0, we are done
if (IO_READ_LEN(io_stack) == 0) {
status = STATUS_SUCCESS;
goto complete_request;
}
// It seems that actual read/write operation is going to take place
// so mark the IRP as pending, insert the IRP into queue list
// then signal the device thread to perform the operation
IoMarkIrpPending(Irp);
ExInterlockedInsertTailList(
&device_extension->ListHead,
&Irp->Tail.Overlay.ListEntry,
&device_extension->ListLock);
KeSetEvent(
&device_extension->RequestEvent,
(KPRIORITY) 0,
FALSE);
VFDTRACE(VFDINFO,("[VFD] %-40s - STATUS_PENDING\n",
GetMajorFuncName(io_stack->MajorFunction)));
return STATUS_PENDING;
complete_request:
// complete the request immediately
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
VFDTRACE(VFDWARN,("[VFD] %-40s - %s\n",
GetMajorFuncName(io_stack->MajorFunction),
GetStatusName(status)));
return status;
}
//
// Substitute for MmGetSystemAddressForMdlSafe
// for NT 4.0 DDK does not provide its equivqlent
// originally written by Bruce Engle for filedisk
//
static PVOID
MmGetSystemAddressForMdlPrettySafe(
IN PMDL Mdl,
IN MM_PAGE_PRIORITY Priority)
{
#if (VER_PRODUCTBUILD >= 2195)
if (OsMajorVersion >= 5) {
return MmGetSystemAddressForMdlSafe(Mdl, Priority);
}
else {
#endif // (VER_PRODUCTBUILD >= 2195)
CSHORT MdlMappingCanFail;
PVOID MappedSystemVa;
MdlMappingCanFail = (CSHORT)(Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL);
Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
MappedSystemVa = MmGetSystemAddressForMdl(Mdl);
if (!MdlMappingCanFail) {
Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;
}
return MappedSystemVa;
#if (VER_PRODUCTBUILD >= 2195)
}
#endif // (VER_PRODUCTBUILD >= 2195)
}
//
// Read sectors from image file or RAM disk buffer into read buffer
//
VOID
VfdReadData(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp,
IN ULONG Length,
IN PLARGE_INTEGER Offset)
{
PVOID buf;
VFDTRACE(VFDINFO,("[VFD] VfdReadData - IN\n"));
buf = MmGetSystemAddressForMdlPrettySafe(
Irp->MdlAddress, NormalPagePriority);
if (!buf) {
VFDTRACE(0,
("[VFD] MmGetSystemAddressForMdlPrettySafe\n"));
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
if (DeviceExtension->FileHandle) {
// Read from image file
Irp->IoStatus.Status = ZwReadFile(
DeviceExtension->FileHandle,
NULL,
NULL,
NULL,
&Irp->IoStatus,
buf,
Length,
Offset,
NULL);
if (NT_SUCCESS(Irp->IoStatus.Status)) {
Irp->IoStatus.Information = Length;
}
else {
VFDTRACE(0,
("[VFD] ZwReadFile - %s\n",
GetStatusName(Irp->IoStatus.Status)));
}
}
else if (DeviceExtension->FileBuffer) {
// Copy from RAM disk buffer
RtlMoveMemory(
buf,
DeviceExtension->FileBuffer + Offset->QuadPart,
Length);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Length;
}
else {
// no image opened
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
}
VFDTRACE(VFDINFO,("[VFD] VfdReadData - %s\n",
GetStatusName(Irp->IoStatus.Status)));
return;
}
//
// Write sectors from write buffer into image file or RAM image buffer
//
VOID
VfdWriteData(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PIRP Irp,
IN ULONG Length,
IN PLARGE_INTEGER Offset)
{
PVOID buf;
VFDTRACE(VFDINFO,("[VFD] VfdWriteData - IN\n"));
buf = MmGetSystemAddressForMdlPrettySafe(
Irp->MdlAddress, NormalPagePriority);
if (!buf) {
VFDTRACE(0,
("[VFD] MmGetSystemAddressForMdlPrettySafe\n"));
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
if (DeviceExtension->FileHandle) {
// Write into image file
Irp->IoStatus.Status = ZwWriteFile(
DeviceExtension->FileHandle,
NULL,
NULL,
NULL,
&Irp->IoStatus,
buf,
Length,
Offset,
NULL);
if (NT_SUCCESS(Irp->IoStatus.Status)) {
Irp->IoStatus.Information = Length;
}
else {
VFDTRACE(0,
("[VFD] ZwWriteFile - %s\n",
GetStatusName(Irp->IoStatus.Status)));
}
}
else if (DeviceExtension->FileBuffer) {
// Deal with the modify flag
if (RtlCompareMemory(
DeviceExtension->FileBuffer + Offset->QuadPart,
buf, Length) != Length) {
DeviceExtension->MediaFlags |= VFD_FLAG_DATA_MODIFIED;
}
// Copy into RAM image buffer
RtlMoveMemory(
DeviceExtension->FileBuffer + Offset->QuadPart,
buf, Length);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Length;
}
else {
// no image opened
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
}
VFDTRACE(VFDINFO,("[VFD] VfdWriteData - %s\n",
GetStatusName(Irp->IoStatus.Status)));
return;
}