示例#1
0
文件: vfdioctl.c 项目: layerfsd/Work
//
//	IOCTL commands handler
//
NTSTATUS
VfdDeviceControl (
	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);

	Irp->IoStatus.Information = 0;

	VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
		GetIoControlName(IO_CTRLCODE(io_stack)),
		device_extension->DeviceName.Buffer));

#ifdef VFD_PNP
	status = IoAcquireRemoveLock(&device_extension->RemoveLock, Irp);

	if (!NT_SUCCESS(status)) {
		VFDTRACE(0,
			("Acquire RemoveLock failed %s\n", NtStatusToStr(status)));

		Irp->IoStatus.Status = status;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return status;
	}
#endif	// VFD_PNP

/*
	//	Check if volume verification is required

	if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
		!(io_stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {

		VFDTRACE(VFDWARN,
			("[VFD] %-40s - %s\n",
				GetIoControlName(IO_CTRLCODE(io_stack)),
				GetStatusName(STATUS_VERIFY_REQUIRED)));

		Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;

		IoCompleteRequest(Irp, IO_NO_INCREMENT);

		return STATUS_VERIFY_REQUIRED;
	}
*/

	switch (IO_CTRLCODE(io_stack)) {
	case IOCTL_VFD_OPEN_IMAGE:
		//	Open an image file or create an empty RAM disk.
		//	Only a few checks are done here.
		//	Actual operation is done in device thread

		status = VfdOpenCheck(
			device_extension,
			(PVFD_IMAGE_INFO)Irp->AssociatedIrp.SystemBuffer,
			IO_INPUTLEN(io_stack));

		if (!NT_SUCCESS(status)) {
			break;
		}

		// Pass the task to the device thread
		status = STATUS_PENDING;
		break;

	case IOCTL_VFD_CLOSE_IMAGE:
	case IOCTL_DISK_EJECT_MEDIA:
	case IOCTL_STORAGE_EJECT_MEDIA:
		//	Close the current image file or delete the RAM disk
		//	Only status check is done here.
		//	Actual operation is done in device thread.

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
			break;
		}

		// Pass the task to the device thread
		status = STATUS_PENDING;
		break;

	case IOCTL_VFD_QUERY_IMAGE:
		//	Returns current image file information

		status = VfdQueryImage(
			device_extension,
			(PVFD_IMAGE_INFO)Irp->AssociatedIrp.SystemBuffer,
			IO_OUTPUTLEN(io_stack),
			&Irp->IoStatus.Information);

		break;

	case IOCTL_VFD_SET_LINK:
		// Create / remove a persistent drive letter
		// and store it in the registry

		if (IO_INPUTLEN(io_stack) < sizeof(CHAR)) {
			status = STATUS_INVALID_PARAMETER;
			break;
		}

#ifdef VFD_MOUNT_MANAGER
		if (OsMajorVersion >= 5) {
			//	Windows 2000/XP
			//	Create a drive letter via the mount manager

			status = VfdMountMgrMountPoint(device_extension,
				*(PCHAR)Irp->AssociatedIrp.SystemBuffer);

			//	The new drive letter will be stored in the device extension
			//	and the registry when IOCTL_MOUNTDEV_LINK_CREATED or
			//	IOCTL_MOUNTDEV_LINK_DELETED is issued from the mount manager.
		}
		else
#else	//	VFD_MOUNT_MANAGER
		{
			//	Windows NT style drive letter assignment
			//	Simply create a symbolic link and store the new value

			status = VfdSetLink(device_extension,
				*(PCHAR)Irp->AssociatedIrp.SystemBuffer);

			if (NT_SUCCESS(status)) {
				//	Store the new drive letter into the registry
				status = VfdStoreLink(device_extension);
			}
		}
#endif	//	VFD_MOUNT_MANAGER
		break;

	case IOCTL_VFD_QUERY_LINK:
		//	Return the current persistent drive letter

		if (IO_OUTPUTLEN(io_stack) < sizeof(CHAR)) {
			status = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		*(PCHAR)Irp->AssociatedIrp.SystemBuffer =
			device_extension->DriveLetter;

		Irp->IoStatus.Information = sizeof(CHAR);
		status = STATUS_SUCCESS;
		break;

	case IOCTL_VFD_SET_PROTECT:
		//	Set media protect flag

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
			break;
		}

		device_extension->MediaFlags |= VFD_FLAG_WRITE_PROTECTED;
		status = STATUS_SUCCESS;
		break;

	case IOCTL_VFD_CLEAR_PROTECT:
		//	Clear media protect flag

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
			break;
		}

		device_extension->MediaFlags &= ~VFD_FLAG_WRITE_PROTECTED;
		status = STATUS_SUCCESS;
		break;

	case IOCTL_VFD_RESET_MODIFY:
		//	Reset the data modify flag

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
			break;
		}

		device_extension->MediaFlags &= ~VFD_FLAG_DATA_MODIFIED;
		status = STATUS_SUCCESS;
		break;

	case IOCTL_VFD_QUERY_NUMBER:
		//	Return VFD device number (\??\VirtualFD<n>)

		if (IO_OUTPUTLEN(io_stack) < sizeof(ULONG)) {
			status = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		*(PULONG)Irp->AssociatedIrp.SystemBuffer=
			device_extension->DeviceNumber;

		Irp->IoStatus.Information = sizeof(ULONG);
		status = STATUS_SUCCESS;
		break;

	case IOCTL_VFD_QUERY_NAME:
		//	Return VFD device name (\Device\Floppy<n>)
		//	counted unicode string (not null terminated)

		if (IO_OUTPUTLEN(io_stack) < sizeof(USHORT)) {
			status = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		{
			PUSHORT p = (PUSHORT)Irp->AssociatedIrp.SystemBuffer;

			*p = device_extension->DeviceName.Length;

			if (IO_OUTPUTLEN(io_stack) < sizeof(USHORT) + *p) {

				Irp->IoStatus.Information = sizeof(USHORT);
				status = STATUS_BUFFER_OVERFLOW;
				break;
			}

			RtlCopyMemory(p + 1, device_extension->DeviceName.Buffer, *p);

			Irp->IoStatus.Information = sizeof(USHORT) + *p;
		}

		status = STATUS_SUCCESS;
		break;

	case IOCTL_VFD_QUERY_VERSION:
		//	Return the VFD driver version

		if (IO_OUTPUTLEN(io_stack) < sizeof(ULONG)) {
			status = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		*(PULONG)Irp->AssociatedIrp.SystemBuffer =
			(VFD_DRIVER_MAJOR << 16) | VFD_DRIVER_MINOR | VFD_DEBUG_FLAG;

		Irp->IoStatus.Information = sizeof(ULONG);
		status = STATUS_SUCCESS;
		break;

	//
	//	standard disk and storage I/O control requests
	//

	case IOCTL_DISK_CHECK_VERIFY:
	case IOCTL_STORAGE_CHECK_VERIFY:
	case IOCTL_STORAGE_CHECK_VERIFY2:

		if (IO_OUTPUTLEN(io_stack) >= sizeof(ULONG)) {

			*(PULONG)Irp->AssociatedIrp.SystemBuffer =
				device_extension->MediaChangeCount;

			Irp->IoStatus.Information = sizeof(ULONG);
		}

		status = STATUS_SUCCESS;
		break;

	case IOCTL_DISK_FORMAT_TRACKS:
	case IOCTL_DISK_FORMAT_TRACKS_EX:
		//	Only parameter checks are performed here
		//	Actual operation is done by the device thread

		status = VfdFormatCheck(
			device_extension,
			(PFORMAT_PARAMETERS)Irp->AssociatedIrp.SystemBuffer,
			IO_INPUTLEN(io_stack),
			IO_CTRLCODE(io_stack));

		if (!NT_SUCCESS(status)) {
			break;
		}

		// Pass the task to the device thread
		status = STATUS_PENDING;
		break;

	case IOCTL_DISK_GET_DRIVE_GEOMETRY:
		//	Returns the geometry of current media

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
			break;
		}
		//	fall through

	case IOCTL_DISK_GET_MEDIA_TYPES:
	case IOCTL_STORAGE_GET_MEDIA_TYPES:
		//	Return *the last mounted* disk geometry, although xxx_GET_MEDIA_TYPES
		//	commands are supposed to return all supported media types.
		//	This makes the matter much simpler...;-)
		//	If no image has been mounted yet, 1.44MB media is assumed.

		if (IO_OUTPUTLEN(io_stack) < sizeof(DISK_GEOMETRY)) {
			return STATUS_BUFFER_TOO_SMALL;
		}

		//	Copy appropriate DISK_GEOMETRY into the output buffer

		if (device_extension->Geometry) {
			RtlCopyMemory(
				Irp->AssociatedIrp.SystemBuffer,
				device_extension->Geometry,
				sizeof(DISK_GEOMETRY));
		}
		else {
			//	default = 3.5" 1.44 MB media
			RtlCopyMemory(
				Irp->AssociatedIrp.SystemBuffer,
				&geom_tbl[VFD_MEDIA_F3_1P4],
				sizeof(DISK_GEOMETRY));
		}
		Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);

		status = STATUS_SUCCESS;
		break;

	case IOCTL_DISK_GET_LENGTH_INFO:
		//	Return disk length information
		//	(Windows XP requires this request to be handled)

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
			break;
		}

		if (IO_OUTPUTLEN(io_stack) < sizeof(GET_LENGTH_INFORMATION)) {
			status = STATUS_BUFFER_TOO_SMALL;
			break;
		}

		((PGET_LENGTH_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->Length.QuadPart =
			VFD_SECTOR_TO_BYTE(device_extension->Sectors);

		Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);

		status = STATUS_SUCCESS;
		break;

	case IOCTL_DISK_IS_WRITABLE:
		//	Checks if current media is writable

		if (!device_extension->FileHandle &&
			!device_extension->FileBuffer) {
			status = STATUS_NO_MEDIA_IN_DEVICE;
		}
		else if (device_extension->MediaFlags & VFD_FLAG_WRITE_PROTECTED) {
			status = STATUS_MEDIA_WRITE_PROTECTED;
		}
		else {
			status = STATUS_SUCCESS;
		}
		break;

/*
	case IOCTL_DISK_MEDIA_REMOVAL:
	case IOCTL_STORAGE_MEDIA_REMOVAL:
		//	Since removal lock is irrelevant for virtual disks,
		//	there's really nothing to do here...

		status = STATUS_SUCCESS;
		break;

	case IOCTL_STORAGE_GET_HOTPLUG_INFO:
		{
			PSTORAGE_HOTPLUG_INFO hotplug;

			if (IO_OUTPUTLEN(io_stack) < sizeof(STORAGE_HOTPLUG_INFO)) {
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}

			hotplug = (PSTORAGE_HOTPLUG_INFO)Irp->AssociatedIrp.SystemBuffer;

			RtlZeroMemory(hotplug, sizeof(STORAGE_HOTPLUG_INFO));

			hotplug->Size = sizeof(STORAGE_HOTPLUG_INFO);
			hotplug->MediaRemovable = 1;

			Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
			status = STATUS_SUCCESS;
		}
		break;
*/

#ifdef VFD_MOUNT_MANAGER
	//
	//	IO control requests received from the mount manager
	//	(on Windows 2000 / XP)
	//

	case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
		//	Returns a unique ID for the target device
		status = VfdMountDevUniqueId(
			device_extension,
			Irp->AssociatedIrp.SystemBuffer,
			IO_OUTPUTLEN(io_stack),
			&Irp->IoStatus);
		break;

//	case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY:

	case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
		//	Returns the device name of the target device
		status = VfdMountDevDeviceName(
			device_extension,
			Irp->AssociatedIrp.SystemBuffer,
			IO_OUTPUTLEN(io_stack),
			&Irp->IoStatus);
		break;

	case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
		//	Returns the drive letter link which we want the mount manager
		//	to create.	This request is issued in response to the volume
		//	arrival notification, and the mount manager will create the
		//	symbolic link.
		status = VfdMountDevSuggestedLink(
			device_extension,
			Irp->AssociatedIrp.SystemBuffer,
			IO_OUTPUTLEN(io_stack),
			&Irp->IoStatus);
		break;

	case IOCTL_MOUNTDEV_LINK_CREATED:
	case IOCTL_MOUNTDEV_LINK_DELETED:
		//	Issued after the mount manager created/deleted a symbolic link
		status = VfdMountDevLinkModified(
			device_extension,
			Irp->AssociatedIrp.SystemBuffer,
			IO_INPUTLEN(io_stack),
			IO_CTRLCODE(io_stack));
		break;

/*
	case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
		{
			PMOUNTDEV_STABLE_GUID guid;

			if (IO_OUTPUTLEN(io_stack) < sizeof(MOUNTDEV_STABLE_GUID)) {
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			guid = Irp->AssociatedIrp.SystemBuffer;

			RtlCopyMemory(
				&guid->StableGuid, &VFD_GUID, sizeof(GUID));

			Irp->IoStatus.Information = sizeof(guid);
			status = STATUS_SUCCESS;
		}
		break;
*/
#endif	//	VFD_MOUNT_MANAGER

	default:
		//	Unknown IOCTL request
		status = STATUS_INVALID_DEVICE_REQUEST;
		break;
	}

#if DBG
	if ((NT_SUCCESS(status) && (TraceFlags & VFDINFO) == VFDINFO) ||
		(TraceFlags & VFDWARN) == VFDWARN) {
		VFDTRACE(0,("[VFD] %-40s - %s\n",
			GetIoControlName(IO_CTRLCODE(io_stack)),
			GetStatusName(status)));
	}
#endif

	if (status == STATUS_PENDING) {
		//	Let the device thread perform the operation

		IoMarkIrpPending(Irp);

		ExInterlockedInsertTailList(
			&device_extension->ListHead,
			&Irp->Tail.Overlay.ListEntry,
			&device_extension->ListLock);

		KeSetEvent(
			&device_extension->RequestEvent,
			(KPRIORITY) 0,
			FALSE);
	}
	else {
		//	complete the operation

		Irp->IoStatus.Status = status;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);

#ifdef VFD_PNP
		IoReleaseRemoveLock(&device_extension->RemoveLock, Irp);
#endif	// VFD_PNP
	}

	return status;
}
示例#2
0
文件: vfdrdwr.c 项目: layerfsd/Work
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;
}
示例#3
0
文件: vfdimg.c 项目: Sattvic2/OSDEV
//
//	Open a virtual floppy image file or create an empty ram disk
//
NTSTATUS
VfdOpenImage (
	IN PDEVICE_EXTENSION		DeviceExtension,
	IN PVFD_IMAGE_INFO			ImageInfo)
{
	IO_STATUS_BLOCK				io_status;
	NTSTATUS					status	= STATUS_SUCCESS;
	const DISK_GEOMETRY			*geometry;
	ULONG						sectors;
	ULONG						alignment;

	VFDTRACE(0, ("[VFD] VfdOpenImage - IN\n"));

	//
	//	Store file name in the device extension
	//
	if (ImageInfo->NameLength) {

		if (ImageInfo->NameLength + 1 >
			DeviceExtension->FileName.MaximumLength) {

			//	expand the filename buffer

			if (DeviceExtension->FileName.Buffer) {
				ExFreePool(DeviceExtension->FileName.Buffer);
				RtlZeroMemory(
					&DeviceExtension->FileName,
					sizeof(ANSI_STRING));
			}

			DeviceExtension->FileName.Buffer = (PCHAR)ExAllocatePoolWithTag(
				NonPagedPool, ImageInfo->NameLength + 1, VFD_POOL_TAG);

			if (!DeviceExtension->FileName.Buffer) {
				VFDTRACE(0, ("[VFD] Can't allocate memory for image path\n"));
				return STATUS_INSUFFICIENT_RESOURCES;
			}

			DeviceExtension->FileName.MaximumLength
				= (USHORT)(ImageInfo->NameLength + 1);

			RtlZeroMemory(
				DeviceExtension->FileName.Buffer,
				DeviceExtension->FileName.MaximumLength);
		}

		if (DeviceExtension->FileName.Buffer) {
			RtlCopyMemory(
				DeviceExtension->FileName.Buffer,
				ImageInfo->FileName,
				ImageInfo->NameLength);

			DeviceExtension->FileName.Buffer[ImageInfo->NameLength] = '\0';
		}
	}

	DeviceExtension->FileName.Length = ImageInfo->NameLength;

	//
	//	Get DISK_GEOMETRY and calculate the media capacity
	//	-- validity of the ImageInfo->MediaType value is assured in
	//	the VfdOpenCheck function
	//
	geometry = &geom_tbl[ImageInfo->MediaType];

	sectors =
		geometry->Cylinders.LowPart *
		geometry->TracksPerCylinder *
		geometry->SectorsPerTrack;

	if (ImageInfo->ImageSize != 0 &&
		ImageInfo->ImageSize < VFD_SECTOR_TO_BYTE(sectors)) {

			VFDTRACE(0, ("[VFD] Image is smaller than the media\n"));
			return STATUS_INVALID_PARAMETER;
	}

	//
	//	Prepare a virtual media according to the ImageInfo
	//
	if (ImageInfo->DiskType == VFD_DISKTYPE_FILE) {
		//
		//	open an existing image file
		//
		HANDLE						file_handle;
		OBJECT_ATTRIBUTES			attributes;
		UNICODE_STRING				unicode_name;
		FILE_STANDARD_INFORMATION	file_standard;
		FILE_BASIC_INFORMATION		file_basic;
		FILE_ALIGNMENT_INFORMATION	file_alignment;
		PFILE_OBJECT				file_object;
		BOOLEAN						network_drive;

		//	convert the filename into a unicode string

		status = RtlAnsiStringToUnicodeString(
			&unicode_name, &DeviceExtension->FileName, TRUE);

		if (!NT_SUCCESS(status)) {
			VFDTRACE(0, ("[VFD] Failed to convert filename to UNICODE\n"));
			return status;
		}

		VFDTRACE(VFDINFO,
			("[VFD] Opening %s\n", DeviceExtension->FileName.Buffer));

		//	prepare an object attribute to open

		InitializeObjectAttributes(
			&attributes,
			&unicode_name,
			OBJ_CASE_INSENSITIVE,
			NULL,
			NULL);

		//	open the target file

		status = ZwCreateFile(
			&file_handle,
			GENERIC_READ | GENERIC_WRITE,
			&attributes,
			&io_status,
			NULL,
			FILE_ATTRIBUTE_NORMAL,
			0,
			FILE_OPEN,
			FILE_NON_DIRECTORY_FILE |
			FILE_RANDOM_ACCESS |
			FILE_NO_INTERMEDIATE_BUFFERING |
			FILE_SYNCHRONOUS_IO_NONALERT,
			NULL,
			0);

		RtlFreeUnicodeString(&unicode_name);

		if (!NT_SUCCESS(status)) {
			VFDTRACE(0, ("[VFD] ZwCreateFile - %s\n",
				GetStatusName(status)));
			return status;
		}

		//	Check the file size

		status = ZwQueryInformationFile(
			file_handle,
			&io_status,
			&file_standard,
			sizeof(FILE_STANDARD_INFORMATION),
			FileStandardInformation);

		if (!NT_SUCCESS(status)) {
			VFDTRACE(0,
				("[VFD] ZwQueryInformationFile - FILE_STANDARD_INFORMATION\n"));

			ZwClose(file_handle);
			goto exit_func;
		}

		//	Actual file size can be larger than the media capacity

		if (file_standard.EndOfFile.QuadPart < VFD_SECTOR_TO_BYTE(sectors)) {

			VFDTRACE(0, ("[VFD] file is smaller than the media.\n"));

			status = STATUS_INVALID_PARAMETER;

			ZwClose(file_handle);
			goto exit_func;
		}

		DeviceExtension->ImageSize = file_standard.EndOfFile.LowPart;

		// Find out whether the file is on a local disk or a network drive

		network_drive = FALSE;

		status = ObReferenceObjectByHandle(
			file_handle,
			GENERIC_READ,
			NULL,
			KernelMode,
			&file_object,
			NULL);

		if (NT_SUCCESS(status)) {
			if (file_object && file_object->DeviceObject) {
				VFDTRACE(VFDINFO, ("[VFD] Device type is 0x%08x\n",
					file_object->DeviceObject->DeviceType));

				if (file_object->DeviceObject->DeviceType
					== FILE_DEVICE_NETWORK_FILE_SYSTEM) {
					network_drive = TRUE;
				}

				// how about these types ?
				// FILE_DEVICE_NETWORK
				// FILE_DEVICE_NETWORK_BROWSER
				// FILE_DEVICE_NETWORK_REDIRECTOR
			}
			else {
				VFDTRACE(VFDWARN, ("[VFD Cannot decide the device type\n"));
			}
			ObDereferenceObject(file_object);
		}
		else {
			VFDTRACE(0, ("[VFD] ObReferenceObjectByHandle - %s\n",
				GetStatusName(status)));
		}

		if (!network_drive) {
			// The NT cache manager can deadlock if a filesystem that is using
			// the cache manager is used in a virtual disk that stores its file
			// on a file systemthat is also using the cache manager, this is
			// why we open the file with FILE_NO_INTERMEDIATE_BUFFERING above,
			// however if the file is compressed or encrypted NT will not honor
			// this request and cache it anyway since it need to store the
			// decompressed/unencrypted data somewhere, therefor we put an
			// extra check here and don't alow disk images to be compressed/
			// encrypted.

			status = ZwQueryInformationFile(
				file_handle,
				&io_status,
				&file_basic,
				sizeof(FILE_BASIC_INFORMATION),
				FileBasicInformation);

			if (!NT_SUCCESS(status)) {
				VFDTRACE(0,
					("[VFD] ZwQueryInformationFile - FILE_BASIC_INFORMATION\n"));

				ZwClose(file_handle);
				goto exit_func;
			}

			if (file_basic.FileAttributes
				& (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))
			{
				VFDTRACE(0,
					("[VFD] Image file is compressed and/or encrypted\n"));

				status =  STATUS_ACCESS_DENIED;

				ZwClose(file_handle);
				goto exit_func;
			}
		}

		//	Retrieve the file alignment requirement

		status = ZwQueryInformationFile(
			file_handle,
			&io_status,
			&file_alignment,
			sizeof(FILE_ALIGNMENT_INFORMATION),
			FileAlignmentInformation);

		if (!NT_SUCCESS(status)) {
			VFDTRACE(0,
				("[VFD] ZwQueryInformationFile - FILE_ALIGNMENT_INFORMATION\n"));

			ZwClose(file_handle);
			goto exit_func;
		}

		DeviceExtension->FileHandle = file_handle;

		alignment = file_alignment.AlignmentRequirement;

		VFDTRACE(0, ("[VFD] Opened an image file\n"));
	}
	else {
		//
		//	Create an empty RAM disk
		//
		DeviceExtension->FileBuffer = (PUCHAR)ExAllocatePoolWithTag(
			NonPagedPool,
			VFD_SECTOR_TO_BYTE(sectors),
			VFD_POOL_TAG);

		if (!DeviceExtension->FileBuffer) {
			VFDTRACE(0, ("[VFD] Can't allocate memory for RAM disk\n"));
			return STATUS_INSUFFICIENT_RESOURCES;
		}

		RtlZeroMemory(
			DeviceExtension->FileBuffer,
			VFD_SECTOR_TO_BYTE(sectors));

		if (ImageInfo->ImageSize) {
			DeviceExtension->ImageSize = ImageInfo->ImageSize;
		}
		else {
			DeviceExtension->ImageSize = VFD_SECTOR_TO_BYTE(sectors);
		}

		alignment = FILE_WORD_ALIGNMENT;

		VFDTRACE(0, ("[VFD] Created an empty RAM disk\n"));
	}

	DeviceExtension->MediaChangeCount++;

	DeviceExtension->MediaType	= ImageInfo->MediaType;
	DeviceExtension->MediaFlags	= ImageInfo->MediaFlags;
	DeviceExtension->FileType	= ImageInfo->FileType;
	DeviceExtension->Geometry	= geometry;
	DeviceExtension->Sectors	= sectors;

	VFDTRACE(0, ("[VFD] Media:%d Flag:0x%02x Size:%lu Capacity:%lu\n",
		DeviceExtension->MediaType,
		DeviceExtension->MediaFlags,
		DeviceExtension->ImageSize,
		DeviceExtension->Sectors));

	DeviceExtension->DeviceObject->AlignmentRequirement
		= alignment;

exit_func:
	VFDTRACE(0, ("[VFD] VfdOpenImage - %s\n", GetStatusName(status)));

	return status;
}