mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 14:18:41 +00:00
![Pierre Schweitzer](/assets/img/avatar_default.png)
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
358 lines
7.8 KiB
C
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;
|
|
}
|