NTSTATUS 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; }
NTSTATUS VdkReadWrite ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PPART_EXTENSION part_extension; PDISK_EXTENSION disk_extension; PIO_STACK_LOCATION io_stack; // // Set up necessary object and extension pointers. // part_extension = (PPART_EXTENSION)DeviceObject->DeviceExtension; disk_extension = (PDISK_EXTENSION)part_extension->FirstPartition; io_stack = IoGetCurrentIrpStackLocation(Irp); // // Check if the device is a zombie -- closed but not released // READ / WRITE request must succeed or NTFS driver cannot release // the device. // if (part_extension->PartitionOrdinal == VDK_ZOMBIE) { VDKTRACE(0, ("[VDK] %ws %s: ZOMBIE DEVICE\n", part_extension->DeviceName.Buffer, io_stack->MajorFunction == IRP_MJ_WRITE ? "IRP_MJ_WRITE" : "IRP_MJ_READ")); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = IO_READ_LEN(io_stack); IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } // // Check if image is opened // if (!disk_extension || !disk_extension->DiskInfo.DiskType || !part_extension->PartitionInfo.PartitionLength.QuadPart) { VDKTRACE(VDKWARN, ("[VDK] %ws %s: STATUS_DEVICE_NOT_READY\n", part_extension->DeviceName.Buffer, io_stack->MajorFunction == IRP_MJ_WRITE ? "IRP_MJ_WRITE" : "IRP_MJ_READ")); Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DEVICE_NOT_READY; } // // 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) > part_extension->PartitionInfo.PartitionLength.QuadPart) { VDKTRACE(0, ("[VDK] %ws Offset:%I64u + Length:%u goes past partition size:%I64u\n", part_extension->DeviceName.Buffer, IO_READ_OFF(io_stack), IO_READ_LEN(io_stack), part_extension->PartitionInfo.PartitionLength.QuadPart)); Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } if ((IO_READ_LEN(io_stack) & VDK_SECTOR_ALIGNMENT_MASK) || (IO_READ_OFF(io_stack) & VDK_SECTOR_ALIGNMENT_MASK)) { VDKTRACE(0, ("[VDK] %ws Invalid Alignment Offset:%I64u Length:%u\n", part_extension->DeviceName.Buffer, IO_READ_OFF(io_stack), IO_READ_LEN(io_stack))); Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } // // Check if write operation is allowed // if (io_stack->MajorFunction == IRP_MJ_WRITE) { if (disk_extension->DiskInfo.DiskType == VDK_DISKTYPE_READONLY) { VDKTRACE(VDKWRITE | VDKWARN, ("[VDK] %ws IRP_MJ_WRITE: STATUS_MEDIA_WRITE_PROTECTED\n", disk_extension->DeviceName.Buffer)); Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_MEDIA_WRITE_PROTECTED; } else if (disk_extension->DiskInfo.DiskType == VDK_DISKTYPE_WRITEBLOCK) { VDKTRACE(VDKWRITE | VDKINFO, ("[VDK] %ws IRP_MJ_WRITE: Blocked write operation\n", disk_extension->DeviceName.Buffer)); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = IO_READ_LEN(io_stack); IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } } // // If read/write data length is 0, we are done // if (IO_READ_LEN(io_stack) == 0) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } // // The offset passed in is relative to the start of the partition. // We always work from partition 0 (the whole disk) so adjust the // offset. // IO_READ_OFF(io_stack) += part_extension->PartitionInfo.StartingOffset.QuadPart; // // Mark the IRP as pending, insert the IRP into queue list // then signal the device thread to perform the operation // IoMarkIrpPending(Irp); ExInterlockedInsertTailList( &disk_extension->ListHead, &Irp->Tail.Overlay.ListEntry, &disk_extension->ListLock); KeSetEvent( &disk_extension->RequestEvent, (KPRIORITY) 0, FALSE); return STATUS_PENDING; }