Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}