vdkioctl.c

来自「Virtual Disk Driver」· C语言 代码 · 共 1,626 行 · 第 1/3 页

C
1,626
字号
/*	vdkdrv.c	Virtual Disk kernel-mode driver for Windows NT platform	Device IO control routine	Copyright (C) 2003 Ken Kato*/#include "vdkbase.h"#include "vdkutil.h"#include "vdkver.h"#include "vdkioctl.h"#include "vdkfile.h"#include "vdkaccess.h"#include "imports.h"#include "vdkdrv.h"#if (DBG && VER_PRODUCTBUILD < 2195)#define FILE_AUTOGENERATED_DEVICE_NAME	0x00000080#define FILE_DEVICE_SECURE_OPEN 		0x00000100#define VPB_REMOVE_PENDING				0x00000008#define VPB_RAW_MOUNT					0x00000010#endif#define IO_INPUTLEN(p)	(p)->Parameters.DeviceIoControl.InputBufferLength#define IO_OUTPUTLEN(p)	(p)->Parameters.DeviceIoControl.OutputBufferLength//// Handle various IOCTL commands//NTSTATUSVdkDeviceControl (	IN PDEVICE_OBJECT	DeviceObject,	IN PIRP 			Irp){	PPART_EXTENSION		part_extension;	PDISK_EXTENSION		disk_extension;	PIO_STACK_LOCATION	io_stack;	NTSTATUS			status;	//	// Set up necessary object and extension pointers.	//	part_extension =		(PPART_EXTENSION)DeviceObject->DeviceExtension;	disk_extension =		(PDISK_EXTENSION)part_extension->FirstPartition;	io_stack = IoGetCurrentIrpStackLocation(Irp);	VDKTRACE(VDKIOCTL | VDKINFO,		("[VDK] %ws %s\n",		part_extension->DeviceName.Buffer,		IoControlCodeToStr(io_stack->Parameters.DeviceIoControl.IoControlCode)));	Irp->IoStatus.Information = 0;	switch (io_stack->Parameters.DeviceIoControl.IoControlCode) {	//	// Operation:	Returns VDK driver version	// Target:		any device	// Input:		none	// Output:		ULONG driver version	// Status:		STATUS_SUCCESS	//	case IOCTL_VDK_GET_VERSION:		{			if (IO_OUTPUTLEN(io_stack) >= sizeof(ULONG)) {				*(PULONG)Irp->AssociatedIrp.SystemBuffer =#if DBG					VDK_DRIVER_VERSION_VAL | 0x00008000;#else	// DBG					VDK_DRIVER_VERSION_VAL;#endif	// DBG				Irp->IoStatus.Information = sizeof(ULONG);			}			status = STATUS_SUCCESS;			break;		}	//	// Operation:	Open image file(s).	// Target:		disk device only	// Input:		VDK_OPEN_FILE_INFO open file information	// Output:		none	// Status:		STATUS_INVALID_DEVICE_REQUEST	not a disk device	//				STATUS_DEVICE_BUSY				image is already opened	//				STATUS_INVALID_PARAMETER		invalid input parameter	//				STATUS_INSUFFICIENT_RESOURSES	resource allocation error	//				...or other status returned by system function call	//	case IOCTL_VDK_OPEN_FILE:		{#ifdef VDK_SUPPORT_NETWORK			SECURITY_QUALITY_OF_SERVICE sqos;#endif	// VDK_SUPPORT_NETWORK			//			//	Check device type			//			if ((PPART_EXTENSION)disk_extension != part_extension) {				VDKTRACE(VDKIOCTL,					("[VDK] %ws is not a disk device\n",					part_extension->DeviceName.Buffer));				status = STATUS_INVALID_DEVICE_REQUEST;				break;			}			//			// Check device status			//			if (disk_extension->DiskInfo.DiskType) {				status = STATUS_DEVICE_BUSY;				break;			}			if (disk_extension->PartitionOrdinal == VDK_ZOMBIE) {				//				//	The device can be a zombie				//				if (DeviceObject->Vpb && DeviceObject->Vpb->ReferenceCount > 1) {					VDKTRACE(VDKIOCTL|VDKWARN,						("[VDK] %ws is a zombie\n",						disk_extension->DeviceName.Buffer));					status = STATUS_DEVICE_BUSY;					break;				}				//	This device is no longer a zombie				VDKTRACE(VDKIOCTL|VDKWARN,					("[VDK] %ws is no longer a zombie\n",					disk_extension->DeviceName.Buffer));				disk_extension->PartitionOrdinal = 0;			}			//			// Check input parameter			//			status = VdkOpenCheckParam(				(PVDK_OPEN_FILE_INFO)Irp->AssociatedIrp.SystemBuffer,				IO_INPUTLEN(io_stack));			if (!NT_SUCCESS(status)) {				break;			}#ifdef VDK_SUPPORT_NETWORK			//			// create security context that matches the calling process' context			//			if (disk_extension->SecurityContext) {				SeDeleteClientSecurity(disk_extension->SecurityContext);			}			else {				disk_extension->SecurityContext = ExAllocatePool(					NonPagedPool, sizeof(SECURITY_CLIENT_CONTEXT));				if (!disk_extension->SecurityContext) {					VDKTRACE(VDKIOCTL,						("[VDK] IOCTL_VDK_OPEN_FILE: ExAllocatePool\n"));					status = STATUS_INSUFFICIENT_RESOURCES;					break;				}			}			RtlZeroMemory(&sqos, sizeof(sqos));			sqos.Length = sizeof(sqos);			sqos.ImpersonationLevel = SecurityImpersonation;			sqos.ContextTrackingMode = SECURITY_STATIC_TRACKING;			sqos.EffectiveOnly = FALSE;			SeCreateClientSecurity(				PsGetCurrentThread(),				&sqos,				FALSE,				disk_extension->SecurityContext);#endif	// VDK_SUPPORT_NETWORK			//			// The device thread will do the rest of the job			//			status = STATUS_PENDING;			break;		}	//	// Operation:	configure devices to match the virtual disk's	//				partition layout	// Target: 		disk device only	// Input:		none	// Output:		ULONG size of partition layout information which would be	//				returned by IOCTL_DISK_GET_DRIVE_LAYOUT	// Status:		STATUS_INVALID_DEVICE_REQUEST	not a disk device	//				...or other status returned by system function call	//	case IOCTL_VDK_UPDATE_DEVICE:		{			PDRIVE_LAYOUT_INFORMATION drive_layout;			ULONG idx;			//			//	Check device type			//			if ((PPART_EXTENSION)disk_extension != part_extension) {				VDKTRACE(VDKIOCTL,					("[VDK] %ws is not a disk device\n",					part_extension->DeviceName.Buffer));				status = STATUS_INVALID_DEVICE_REQUEST;				break;			}			status = STATUS_SUCCESS;			if (disk_extension->PartitionOrdinal == VDK_ZOMBIE) {				if (!DeviceObject->Vpb || DeviceObject->Vpb->ReferenceCount == 1) {					//	This device is no longer a zombie					VDKTRACE(VDKIOCTL|VDKWARN,						("[VDK] %ws is no longer a zombie\n",						disk_extension->DeviceName.Buffer));					disk_extension->PartitionOrdinal = 0;				}				break;			}			if (!disk_extension->DiskInfo.DiskType) {				break;			}			//			//	Read partition information from virtual disk			//			status = IoReadPartitionTable(				disk_extension->DeviceObject,				VDK_BYTES_PER_SECTOR,				FALSE,				&drive_layout);			if (!NT_SUCCESS(status)) {				VDKTRACE(VDKIOCTL,					("[VDK] IOCTL_VDK_UPDATE_DEVICE: IoReadPartitionTable %s\n",					VdkStatusStr(status)));				break;			}			if (!drive_layout) {				status = STATUS_DRIVER_INTERNAL_ERROR;				VDKTRACE(VDKIOCTL,					("[VDK] IOCTL_VDK_UPDATE_DEVICE: IoReadPartitionTable %s\n",					VdkStatusStr(status)));				break;			}			//			// Create / Delete / Update device objects according to partition table			//			for (idx = 0; idx < drive_layout->PartitionCount; idx++) {				drive_layout->PartitionEntry[idx].RewritePartition = TRUE;			}			VdkUpdateDevice(disk_extension->DeviceObject, drive_layout);			ExFreePool(drive_layout);			break;		}	//	// Operation:	Close image file(s)	// Target:		disk device only	// Input:		!= 0	the volume has been dismounted	//				0		the volume has not been dismounted	// Output:		none	// Status:		STATUS_INVALID_DEVICE_REQUEST	not a disk device	//				STATUS_DEVICE_NOT_READY			image is not opened	//				...or other status returned by system function call	//	case IOCTL_VDK_CLOSE_FILE:		{			//			// check device type			//			if ((PPART_EXTENSION)disk_extension != part_extension) {				VDKTRACE(VDKIOCTL,					("[VDK] %ws is not a disk device\n",					part_extension->DeviceName.Buffer));				status = STATUS_INVALID_DEVICE_REQUEST;				break;			}			//			//	Check device status			//			if (!disk_extension->DiskInfo.DiskType) {				status = STATUS_DEVICE_NOT_READY;				break;			}			//			// Change DiskType so that no one will use the file hereafter			//			disk_extension->DiskInfo.DiskType = VDK_DISKTYPE_NONE;			//			// The device thread will do the rest of the job			//			status = STATUS_PENDING;			break;		}	//	// Operation:	Returns total size of image file information	// Target: 		disk device only	// Input:		none	// Output:		ULONG required buffer size for IOCTL_VDK_QUERY_FILE	// Status:		STATUS_INVALID_DEVICE_REQUEST	not a disk device	//				STATUS_BUFFER_TOO_SMALL			output buffer too small	//	case IOCTL_VDK_QUERY_FILE_SIZE:		{			//			//	Check device type			//			if ((PPART_EXTENSION)disk_extension != part_extension) {				VDKTRACE(VDKIOCTL,					("[VDK] %ws is not a disk device\n",					part_extension->DeviceName.Buffer));				status = STATUS_INVALID_DEVICE_REQUEST;				break;			}			//			// Check output buffer length			//			if (IO_OUTPUTLEN(io_stack) < sizeof(ULONG)) {				status = STATUS_BUFFER_TOO_SMALL;				break;			}			//			// Store required buffer size			//			if (disk_extension->DiskInfo.DiskType) {				*(PULONG)Irp->AssociatedIrp.SystemBuffer =					FIELD_OFFSET(VDK_OPEN_FILE_INFO, Files) +					(sizeof(VDK_OPEN_FILE_ITEM) * disk_extension->DiskInfo.FilesTotal) +					disk_extension->DiskInfo.BufferLen;			}			else {				*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0;			}			Irp->IoStatus.Information = sizeof(ULONG);			status = STATUS_SUCCESS;			break;		}	//	// Operation:	Returns current image file information	// Target: 		disk device only	// Input:		none	// Output:		VDK_OPEN_FILE_INFO	image file information	// Status:		STATUS_INVALID_DEVICE_REQUEST	not a disk device	//				STATUS_BUFFER_TOO_SMALL			output buffer too small	//	case IOCTL_VDK_QUERY_FILE:		{			PVDK_OPEN_FILE_INFO open_file;			ULONG	fixed_size;			ULONG	idx;			//			//	Check device type			//			if ((PPART_EXTENSION)disk_extension != part_extension) {				VDKTRACE(VDKIOCTL,					("[VDK] %ws is not a disk device\n",					part_extension->DeviceName.Buffer));				status = STATUS_INVALID_DEVICE_REQUEST;				break;			}			//			// image is opened ?			//			if (!disk_extension->DiskInfo.DiskType) {				// nothing to return				status = STATUS_SUCCESS;				break;			}			//			// calculate necessaty buffer length			//			fixed_size =				FIELD_OFFSET(VDK_OPEN_FILE_INFO, Files) +				(sizeof(VDK_OPEN_FILE_ITEM) * disk_extension->DiskInfo.FilesTotal);			//			// Check output buffer length			//			if (IO_OUTPUTLEN(io_stack) <				fixed_size + disk_extension->DiskInfo.BufferLen) {				status = STATUS_BUFFER_TOO_SMALL;				break;			}			//			// Store disk information			//			open_file = (PVDK_OPEN_FILE_INFO)Irp->AssociatedIrp.SystemBuffer;			open_file->DiskType		= disk_extension->DiskInfo.DiskType;			open_file->Capacity		= disk_extension->DiskInfo.Capacity;			open_file->Cylinders	= disk_extension->DiskInfo.Cylinders;			open_file->Tracks		= disk_extension->DiskInfo.Tracks;			open_file->Sectors		= disk_extension->DiskInfo.Sectors;			open_file->FilesTotal	= disk_extension->DiskInfo.FilesTotal;			//			// Store each file information			//			for (idx = 0; idx < disk_extension->DiskInfo.FilesTotal; idx++) {				PVDK_FILE_INFO	file_item;				PVDK_OPEN_FILE_ITEM	open_item;				file_item = &(disk_extension->DiskInfo.Files[idx]);				open_item = &(open_file->Files[idx]);				open_item->FileType		= file_item->FileType;				open_item->Capacity		= file_item->Capacity;				open_item->NameLength	= file_item->NameLength;			}			//			// copy filenames following the fixed info			//			if (disk_extension->DiskInfo.BufferLen) {				RtlCopyMemory(					(PCHAR)open_file + fixed_size,					disk_extension->DiskInfo.NameBuffer,					disk_extension->DiskInfo.BufferLen);			}			Irp->IoStatus.Information =				fixed_size + disk_extension->DiskInfo.BufferLen;			status = STATUS_SUCCESS;			break;		}	//	// Operation:	Returns number of partition devices attached to	//				the current disk device	// Target: 		disk device only	// Input:		none	// Output:		ULONG	number of partition devices	// Status:		STATUS_INVALID_DEVICE_REQUEST	not a disk device	//				STATUS_BUFFER_TOO_SMALL			output buffer too small	//	case IOCTL_VDK_NUMBER_OF_PARTS:		{			PDEVICE_OBJECT device_obj;			ULONG num_parts;			//			//	Check device type			//			if ((PPART_EXTENSION)disk_extension != part_extension) {				VDKTRACE(VDKIOCTL,					("[VDK] %ws is not a disk device\n",					part_extension->DeviceName.Buffer));				status = STATUS_INVALID_DEVICE_REQUEST;				break;			}			//			// Check output buffer length			//			if (IO_OUTPUTLEN(io_stack) < sizeof(ULONG)) {				status = STATUS_BUFFER_TOO_SMALL;				break;			}			//			//	Count partition devices			//			num_parts = 0;			device_obj = disk_extension->NextPartition;			while (device_obj) {				num_parts++;				device_obj = ((PPART_EXTENSION)device_obj->DeviceExtension)->NextPartition;			}			*(PULONG)Irp->AssociatedIrp.SystemBuffer = num_parts;			Irp->IoStatus.Information = sizeof(ULONG);			status = STATUS_SUCCESS;			break;		}	//	// Operation:	Create new virtual disk device	// Target:		any device	// Input:		none	// Output:		none	//	case IOCTL_VDK_CREATE_DISK:		//		//	Actual operation is performed in the device thread, for		//	directory object must be created in the system thread context		//		status = STATUS_PENDING;		break;	//	// Operation:	Delete the last created virtual disk device	// Target:		any device	// Input:		none	// Output:		none

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?