vdkthread.c

来自「Virtual Disk Driver」· C语言 代码 · 共 621 行

C
621
字号
/*	vdkthread.c	Virtual Disk kernel-mode driver for Windows NT platform	Device thread routines	Copyright (C) 2003 Ken Kato*/#include "vdkbase.h"#include "vdkutil.h"#include "vdkioctl.h"#include "vdkfile.h"#include "vdkaccess.h"#include "imports.h"#include "vdkdrv.h"static NTSTATUSVdkOpen(	IN PDEVICE_OBJECT	DiskObject,	IN PVDK_OPEN_FILE_INFO 	OpenFile);static NTSTATUSVdkClose(	IN PDISK_EXTENSION	DiskExtension);static NTSTATUSVdkFormat(	IN PVDK_DISK_INFO	DiskInfo,	IN PFORMAT_PARAMETERS	FormatParam);#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, VdkOpen)#pragma alloc_text(PAGE, VdkClose)#pragma alloc_text(PAGE, VdkFormat)#endif	// ALLOC_PRAGMA//// 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 == 0) {		StoreCurrentOsVersion();	}	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}//// Device dedicated thread routine// Handles read, write, open, close operation//VOIDVdkThread (	IN PVOID Context)	// Disk device object{	PDEVICE_OBJECT		disk_object;	PDISK_EXTENSION		disk_extension;	PLIST_ENTRY 		request;	PIRP				irp;	PIO_STACK_LOCATION	io_stack;	disk_object = (PDEVICE_OBJECT)Context;	disk_extension = (PDISK_EXTENSION)disk_object->DeviceExtension;	KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);	for (;;) {		//		// wait for the request event to be signalled		//		KeWaitForSingleObject(			&disk_extension->RequestEvent,			Executive,			KernelMode,			FALSE,			NULL);		//		// terminate request ?		//		if (disk_extension->TerminateThread) {			VDKTRACE(VDKINFO,				("[VDK] Exitting device thread\n"));			PsTerminateSystemThread(STATUS_SUCCESS);		}		//		// perform requested task		//		while ((request = ExInterlockedRemoveHeadList(			&disk_extension->ListHead, &disk_extension->ListLock)) != NULL) {			irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);			io_stack = IoGetCurrentIrpStackLocation(irp);			irp->IoStatus.Information = 0;			switch (io_stack->MajorFunction) {			case IRP_MJ_READ:				if (!disk_extension->DiskInfo.DiskType) {					irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;					VDKTRACE(VDKWARN | VDKREAD,						("[VDK] IRP_MJ_READ: STATUS_DEVICE_NOT_READY\n"));					break;				}				irp->IoStatus.Status = VdkReadSector(					&disk_extension->DiskInfo,					(ULONG)(io_stack->Parameters.Read.ByteOffset.QuadPart >>						VDK_BYTE_SHIFT_TO_SECTOR),					io_stack->Parameters.Read.Length >>						VDK_BYTE_SHIFT_TO_SECTOR,					MmGetSystemAddressForMdlPrettySafe(						irp->MdlAddress, NormalPagePriority));				if (NT_SUCCESS(irp->IoStatus.Status)) {					irp->IoStatus.Information =						io_stack->Parameters.Read.Length;				}				break;			case IRP_MJ_WRITE:				if (!disk_extension->DiskInfo.DiskType) {					irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;					VDKTRACE(VDKWARN | VDKWRITE,						("[VDK] IRP_MJ_READ: STATUS_DEVICE_NOT_READY\n"));					break;				}				irp->IoStatus.Status = VdkWriteSector(					&disk_extension->DiskInfo,					(ULONG)(io_stack->Parameters.Write.ByteOffset.QuadPart >>						VDK_BYTE_SHIFT_TO_SECTOR),					io_stack->Parameters.Write.Length >>						VDK_BYTE_SHIFT_TO_SECTOR,					MmGetSystemAddressForMdlPrettySafe(						irp->MdlAddress, NormalPagePriority));				if (NT_SUCCESS(irp->IoStatus.Status)) {					irp->IoStatus.Information =						io_stack->Parameters.Read.Length;				}				break;			case IRP_MJ_DEVICE_CONTROL:				switch (io_stack->Parameters.DeviceIoControl.IoControlCode) {				case IOCTL_VDK_OPEN_FILE:#ifdef VDK_SUPPORT_NETWORK					SeImpersonateClient(disk_extension->SecurityContext, NULL);#endif	// VDK_SUPPORT_NETWORK					irp->IoStatus.Status = VdkOpen(						disk_object,						(PVDK_OPEN_FILE_INFO)irp->AssociatedIrp.SystemBuffer);#ifdef VDK_SUPPORT_NETWORK					PsRevertToSelf();#endif	// VDK_SUPPORT_NETWORK					break;				case IOCTL_VDK_CLOSE_FILE:					//					// Mark this device as a zombie if the volume is not dismounted					//					if ((io_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) ||						!*(PULONG)irp->AssociatedIrp.SystemBuffer) &&						disk_object->Vpb &&						disk_object->Vpb->ReferenceCount > 1) {						VDKTRACE(VDKIOCTL|VDKWARN,							("[VDK] %ws becomes a zombie\n",							disk_extension->DeviceName.Buffer));						disk_extension->PartitionOrdinal = VDK_ZOMBIE;					}					irp->IoStatus.Status = VdkClose(disk_extension);					break;				case IOCTL_VDK_CREATE_DISK:					{						PDEVICE_OBJECT	device_obj;						ULONG	disk_num = 0;						device_obj = disk_object->DriverObject->DeviceObject;						//						//	count number of existing virtual disk devices						//						while (device_obj) {							if (((PPART_EXTENSION)device_obj->DeviceExtension)->FirstPartition								== (PDISK_EXTENSION)device_obj->DeviceExtension) {								disk_num++;							}							device_obj = device_obj->NextDevice;						}						if (disk_num >= VDK_MAXIMUM_DISK_NUM) {							VDKTRACE(VDKCREATE|VDKWARN,								("[VDK] No more disk devies.\n"));							irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;							break;						}						//						//	create new virtual disk device						//						irp->IoStatus.Status = VdkCreateDisk(disk_object->DriverObject, disk_num);						break;					}				case IOCTL_VDK_DELETE_DISK:					{						PDEVICE_OBJECT device_obj;						PDISK_EXTENSION disk_ext = NULL;						device_obj = disk_object->DriverObject->DeviceObject;						//						//	Look for the last created disk device (first in the chain)						//						while (device_obj) {							disk_ext = (PDISK_EXTENSION)device_obj->DeviceExtension;							if (disk_ext == disk_ext->FirstPartition) {								break;							}							device_obj = device_obj->NextDevice;						}						if (!device_obj) {							VDKTRACE(VDKDELETE,								("[VDK] Disk device not found\n"));							irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;							break;						}						//						//	Check if the device can be deleted						//						if (disk_ext->VirtualNumber == 0) {							VDKTRACE(VDKDELETE,								("[VDK] Cannot delete disk 0\n"));							irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;							break;						}						if (disk_ext->DiskInfo.DiskType) {							VDKTRACE(VDKDELETE,								("[VDK] Device %ws in use.\n",								disk_ext->DeviceName.Buffer));							irp->IoStatus.Status = STATUS_DEVICE_BUSY;							break;						}						if (device_obj->Vpb && device_obj->Vpb->ReferenceCount) {							VDKTRACE(VDKDELETE,								("[VDK] Device %ws reference count %lu\n",								disk_ext->DeviceName.Buffer,								device_obj->Vpb->ReferenceCount));							irp->IoStatus.Status = STATUS_DEVICE_BUSY;							break;						}						//						//	Delete the device						//						VdkDeleteDevice(device_obj);						irp->IoStatus.Status = STATUS_SUCCESS;						break;					}				default:					// This shouldn't happen...					irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;				}				VDKTRACE((VDKINFO | VDKIOCTL),					("[VDK] IRP_MJ_DEVICE_CONTROL\n"));#if DBG				if ((TraceFlags & VDKIOCTL)	&&					(!NT_SUCCESS(irp->IoStatus.Status) || (TraceFlags & VDKINFO) == VDKINFO)) {					PrintIoCtrlStatus(						disk_extension->DeviceName.Buffer,						io_stack->Parameters.DeviceIoControl.IoControlCode,						irp->IoStatus.Status);				}#endif	// DBG				break;			default:				// This shouldn't happen...				irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;				VDKTRACE(0,					("[VDK] Unknown major function 0x%08lu\n",					io_stack->MajorFunction));			}			if (irp->IoStatus.Status == STATUS_FILE_FORCED_CLOSED) {				//				// File has been forced to close e.g. due to network condition				// Must update driver status				//				VDKTRACE(VDKIOCTL|VDKWARN,					("[VDK] %ws becomes a zombie due to forced close.\n",					disk_extension->DeviceName.Buffer));				disk_extension->DiskInfo.DiskType = VDK_DISKTYPE_NONE;				disk_extension->PartitionOrdinal = VDK_ZOMBIE;				VdkClose(disk_extension);			}			//			// complete the request			//			if (NT_SUCCESS(irp->IoStatus.Status)) {				IoCompleteRequest(irp, IO_DISK_INCREMENT);			}			else {				IoCompleteRequest(irp, IO_NO_INCREMENT);			}		} // while	} // for (;;)}//// Open image file(s)//NTSTATUSVdkOpen(	IN PDEVICE_OBJECT		DiskObject,	IN PVDK_OPEN_FILE_INFO 	OpenFile){	PDISK_EXTENSION	disk_extension;	ULONG			idx;	NTSTATUS		status = STATUS_SUCCESS;	VDKTRACE(VDKOPEN | VDKINFO,("[VDK] VdkOpen - IN\n"));	//	// set necessary pointers	//	disk_extension = (PDISK_EXTENSION)DiskObject->DeviceExtension;	//	// open files in the OPEN_FILE list	//	status = VdkOpenDisk(OpenFile, &disk_extension->DiskInfo);	if (!NT_SUCCESS(status)) {		goto exit_func;	}	//	// Retrieve alignment requirement for each file and use the	// largest value as this device's alignment requirement.	//	for (idx = 0; idx < disk_extension->DiskInfo.FilesTotal; idx++) {		if (disk_extension->DiskInfo.Files[idx].FileHandle) {			IO_STATUS_BLOCK	io_status;			FILE_ALIGNMENT_INFORMATION	file_alignment;			status = ZwQueryInformationFile(				disk_extension->DiskInfo.Files[idx].FileHandle,				&io_status,				&file_alignment,				sizeof(FILE_ALIGNMENT_INFORMATION),				FileAlignmentInformation);			if (!NT_SUCCESS(status)) {				VDKTRACE(VDKOPEN,					("[VDK] ZwQueryInformationFile - FILE_ALIGNMENT_INFORMATION %s\n",					VdkStatusStr(status)));				goto exit_func;			}			if (DiskObject->AlignmentRequirement <				file_alignment.AlignmentRequirement) {				DiskObject->AlignmentRequirement =					file_alignment.AlignmentRequirement;			}		}	}	//	// store disk disk capacity also in this device's partition info	//	disk_extension->PartitionInfo.PartitionLength.QuadPart =		(LONGLONG)disk_extension->DiskInfo.Capacity << VDK_BYTE_SHIFT_TO_SECTOR;	//	// Adjust device characteristics	//	if (disk_extension->DiskInfo.DiskType == VDK_DISKTYPE_READONLY) {		DiskObject->Characteristics |= FILE_READ_ONLY_DEVICE;	}	else {		DiskObject->Characteristics &= ~FILE_READ_ONLY_DEVICE;	}exit_func:	VDKTRACE(VDKOPEN | VDKINFO, ("[VDK] VdkOpen - OUT\n"));	return status;}//// Close current image file(s)//NTSTATUSVdkClose(	IN PDISK_EXTENSION		DiskExtension){	PDEVICE_OBJECT	next_partition;	NTSTATUS 		status = STATUS_SUCCESS;	VDKTRACE(VDKCLOSE | VDKINFO, ("[VDK] VdkClose - IN\n"));	//	// Detach all partition devices from the disk device	//	RtlZeroMemory(		&DiskExtension->PartitionInfo,		sizeof(DiskExtension->PartitionInfo));	next_partition = DiskExtension->NextPartition;	DiskExtension->NextPartition = NULL;	while (next_partition) {		PDEVICE_OBJECT current_part = next_partition;		PPART_EXTENSION part_extension = current_part->DeviceExtension;		next_partition = part_extension->NextPartition;		if (!current_part->Vpb || !current_part->Vpb->ReferenceCount) {			VDKTRACE(VDKCLOSE | VDKINFO,				("[VDK] Deleting %ws from device chain.\n",				part_extension->DeviceName.Buffer));			VdkDeleteDevice(current_part);		}		else {			//			//	the device cannot be deleted yet			//			VDKTRACE(VDKCLOSE | VDKWARN,				("[VDK] %ws becomes a zombie.\n",				part_extension->DeviceName.Buffer));			RtlZeroMemory(				&part_extension->PartitionInfo,				sizeof(part_extension->PartitionInfo));			part_extension->PartitionOrdinal	= VDK_ZOMBIE;			part_extension->FirstPartition 		= NULL;			part_extension->NextPartition 		= NULL;			if (part_extension->SymbolicLink.Buffer) {				VDKTRACE(VDKCLOSE | VDKINFO,					("[VDK] Deleting a symbolic link %ws\n",					part_extension->SymbolicLink.Buffer));				IoDeleteSymbolicLink(&part_extension->SymbolicLink);				ExFreePool(part_extension->SymbolicLink.Buffer);				RtlZeroMemory(					&part_extension->SymbolicLink,					sizeof(part_extension->SymbolicLink));			}		}	}	//	// Close all files and release resources	//	VdkCloseDisk(&DiskExtension->DiskInfo);	VDKTRACE(VDKCLOSE | VDKINFO, ("[VDK] VdkClose - OUT\n"));	return status;}//// Default fill character for format operation//#define MEDIA_FORMAT_FILL_DATA	0xf6//// Format tracks// Actually, just fills specified range of tracks with fill characters//NTSTATUSVdkFormat(	IN PVDK_DISK_INFO		DiskInfo,	IN PFORMAT_PARAMETERS	FormatParam){	PUCHAR				format_buffer;	ULONG				start_offset;	ULONG				end_offset;	NTSTATUS			status;	VDKTRACE(VDKFORMAT | VDKINFO,		("[VDK] VdkFormat\n"));	//	// prepare format buffer	//	{		ULONG buf_length =			DiskInfo->Sectors << VDK_BYTE_SHIFT_TO_SECTOR;		format_buffer = ExAllocatePool(PagedPool, buf_length);		if (format_buffer == NULL) {			VDKTRACE(VDKFORMAT,				("[VDK] cannot allocate format buffer\n"));			return STATUS_INSUFFICIENT_RESOURCES;		}		RtlFillMemory(format_buffer, buf_length, MEDIA_FORMAT_FILL_DATA);	}	//	// Prepare format parameters	//	start_offset =		(FormatParam->StartCylinderNumber * DiskInfo->Tracks +		FormatParam->StartHeadNumber) *		DiskInfo->Sectors;	end_offset =		(FormatParam->EndCylinderNumber * DiskInfo->Tracks +		FormatParam->EndHeadNumber) *		DiskInfo->Sectors;	VDKTRACE(VDKFORMAT | VDKINFO,		("[VDK] Formatting sectors %lu - %lu\n",		start_offset, end_offset));	do {		status = VdkWriteSector(			DiskInfo,			start_offset,			DiskInfo->Sectors,			format_buffer);		if (!NT_SUCCESS(status)) {			break;		}		start_offset += DiskInfo->Sectors;	}	while (start_offset <= end_offset);	ExFreePool(format_buffer);	return status;}// End Of File

⌨️ 快捷键说明

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