vdkupdate.c

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

C
569
字号
/*	vdkupdate.c	Virtual Disk kernel-mode driver for Windows NT platform	Device update routine	Copyright (C) 2003 Ken Kato*/#include "vdkbase.h"#include "vdkutil.h"#include "vdkaccess.h"#include "imports.h"#include "vdkdrv.h"#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, VdkUpdateDevice)#endif	// ALLOC_PRAGMA//// This routine creates, deletes and changes device objects when// the IOCTL_SET_DRIVE_LAYOUT is called.  It also updates the partition// number information in the structure that will be returned to the caller.// This routine can be used even in the GET_INFO case by insuring that// the RewritePartition flag is off for all partitions in the drive layout// structure.//VOIDVdkUpdateDevice(	IN PDEVICE_OBJECT				DiskObject,	IN PDRIVE_LAYOUT_INFORMATION	DriveLayout){	PDISK_EXTENSION			disk_extension;	PPART_EXTENSION			part_extension;	PPARTITION_INFORMATION	partition_info;	ULONG	part_count;	ULONG	part_ordinal;	ULONG	idx;	VDKTRACE(VDKUPDATE | VDKINFO, ("[VDK] VdkUpdateDevice\n"));	//	// The virtual disk is non-partitioned (super-floppy) image	// in this case, entire disk is treated as a single partition	// and device 0 represents the partition.	//	if (DriveLayout->PartitionCount == 1 &&		DriveLayout->PartitionEntry[0].StartingOffset.QuadPart == 0) {		VDKTRACE(VDKUPDATE | VDKWARN,			("[VDK] Non-Partitioned disk\n"));		DriveLayout->PartitionEntry[0].PartitionNumber = 0;		return;	}	//	// First clear all partition numbers in the partition list.	//	part_count	= DriveLayout->PartitionCount;	for (idx = 0; idx < part_count; idx++) {		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].StartingOffset = %I64u\n", idx,			DriveLayout->PartitionEntry[idx].StartingOffset.QuadPart));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].PartitionLength = %I64u\n", idx,			DriveLayout->PartitionEntry[idx].PartitionLength.QuadPart));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].HiddenSectors = %lu\n", idx,			DriveLayout->PartitionEntry[idx].HiddenSectors));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].PartitionNumber = %lu\n", idx,			DriveLayout->PartitionEntry[idx].PartitionNumber));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].PartitionType = %lu\n", idx,			DriveLayout->PartitionEntry[idx].PartitionType));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].BootIndicator = %lu\n", idx,			DriveLayout->PartitionEntry[idx].BootIndicator));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].RecognizedPartition = %lu\n", idx,			DriveLayout->PartitionEntry[idx].RecognizedPartition));		VDKTRACE(VDKUPDATE | VDKINFO,			("[VDK] PartitionEntry[%lu].RewritePartition = %lu\n", idx,			DriveLayout->PartitionEntry[idx].RewritePartition));		DriveLayout->PartitionEntry[idx].PartitionNumber = 0;	}	disk_extension = (PDISK_EXTENSION)DiskObject->DeviceExtension;	part_extension = (PPART_EXTENSION)disk_extension;	//	// Walk through chain of partition devices to determine if	// each existing partition device has a match in the layout list.	//	while (part_extension->NextPartition) {		PPART_EXTENSION prev_part;		prev_part = part_extension;		part_extension =			part_extension->NextPartition->DeviceExtension;		//		// Loop through partition information table to look for match.		//		part_ordinal = 0;		for (idx = 0; idx < part_count; idx++) {			//			// Get partition info entry.			//			partition_info = &DriveLayout->PartitionEntry[idx];			//			// Skip empty or extended partitions			//			if (partition_info->PartitionType == PARTITION_ENTRY_UNUSED ||				IsContainerPartition(partition_info->PartitionType)) {				continue;			}			//			// Advance partition ordinal.			//			part_ordinal++;			//			// Check if start offset and length is the same			//			if (partition_info->StartingOffset.QuadPart ==				part_extension->PartitionInfo.StartingOffset.QuadPart &&				partition_info->PartitionLength.QuadPart ==				part_extension->PartitionInfo.PartitionLength.QuadPart) {				//				// This device matches the partition item in the list.				//				VDKTRACE(VDKUPDATE | VDKINFO,					("[VDK] list item #%u matches object %u\n",					part_extension->PartitionInfo.PartitionNumber,					idx));				partition_info->PartitionNumber					= part_extension->PartitionInfo.PartitionNumber;				//				// update PartitionOrdinal to match the order this partition				// is placed on the disk				//				part_extension->PartitionOrdinal = part_ordinal;				//				// A match is found.  If this partition is marked for update,				// check for a partition type change.				//				if (partition_info->RewritePartition) {					part_extension->PartitionInfo.PartitionType						= partition_info->PartitionType;				}				break;			}		}	// next partition info entry		if (idx == part_count) {			//			// no match was found, indicate the partition represented by			// this partition device is gone.	This device is no longer used			// so remove it from the chain			//			if (!prev_part->NextPartition->Vpb ||				!prev_part->NextPartition->Vpb->ReferenceCount) {				VDKTRACE(VDKUPDATE | VDKINFO,					("[VDK] %ws becomes an orphan.\n",					part_extension->DeviceName.Buffer));				part_extension->PartitionOrdinal	= 0;			}			else {				VDKTRACE(VDKUPDATE | VDKWARN,					("[VDK] %ws becomes a zombie.\n",					part_extension->DeviceName.Buffer));				part_extension->PartitionOrdinal	= VDK_ZOMBIE;			}			prev_part->NextPartition = part_extension->NextPartition;			RtlZeroMemory(				&part_extension->PartitionInfo,				sizeof(part_extension->PartitionInfo));			part_extension->FirstPartition 		= NULL;			part_extension->NextPartition 		= NULL;			if (part_extension->SymbolicLink.Buffer) {				VDKTRACE(VDKUPDATE | VDKINFO,					("[VDK] Deleting 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));			}			part_extension = prev_part;		   	continue;		}		//		// Adjust access type of the device object		//		if (disk_extension->DiskInfo.DiskType == VDK_DISKTYPE_READONLY) {			prev_part->NextPartition->Characteristics |= FILE_READ_ONLY_DEVICE;		}		else {			prev_part->NextPartition->Characteristics &= ~FILE_READ_ONLY_DEVICE;		}	}	// next device in the chain	//	// Make sure each list item has a partition device to represent it.	// In some cases new device objects will be created.	//	part_ordinal = 0;	for (idx = 0; idx < part_count; idx++) {		//		// Partition info entry to work with		//		partition_info = &DriveLayout->PartitionEntry[idx];		//		// Skip empty or extended partitons		//		if (partition_info->PartitionType == PARTITION_ENTRY_UNUSED ||			IsContainerPartition(partition_info->PartitionType)) {			VDKTRACE(VDKUPDATE | VDKINFO,				("[VDK] Skip: item %lu is unused or container\n", idx));			continue;		}		//		// Keep track of position of the partition on the disk		//		part_ordinal++;		//		// Skip partitions which don't need to be updated		//		if (!partition_info->RewritePartition ||	// rewrite flag is off or			partition_info->PartitionNumber) {		// match was found			// no need to update device object for this partition			VDKTRACE(VDKUPDATE | VDKINFO,				("[VDK] Skip: item %lu - matched or not for rewrite\n", idx));			continue;		}		//		// If partition number is still zero then a new device object		// must be associated.		//		if (partition_info->PartitionNumber == 0) {			PDEVICE_OBJECT	part_object;			WCHAR			name_buf[40];			UNICODE_STRING	uni_name;			ULONG			part_num;			NTSTATUS		status;			//			//	First search orphaned partition device available			//			part_object = DiskObject->DriverObject->DeviceObject;			while (part_object) {				if ((!part_object->Vpb || !part_object->Vpb->ReferenceCount) &&					((PPART_EXTENSION)part_object->DeviceExtension)->FirstPartition == NULL) {					break;				}				part_object = part_object->NextDevice;			}			if (part_object) {				if (disk_extension->DiskInfo.DiskType == VDK_DISKTYPE_READONLY) {					part_object->Characteristics |= FILE_READ_ONLY_DEVICE;				}				else {					part_object->Characteristics &= ~FILE_READ_ONLY_DEVICE;				}				//				// Link into the partition list.				//				part_extension->NextPartition = part_object;				part_extension =					(PPART_EXTENSION)part_object->DeviceExtension;			}			else {				//				//	Create a partition device				//				part_num = 0;				do {					swprintf(name_buf,						L"\\Device\\VirtualDiskVolume%u", ++part_num);					RtlInitUnicodeString(&uni_name, name_buf);					status = IoCreateDevice(						DiskObject->DriverObject,						sizeof(PART_EXTENSION),						&uni_name,						FILE_DEVICE_DISK,						(DiskObject->Characteristics & FILE_READ_ONLY_DEVICE),						FALSE,						&part_object);					if (status != STATUS_OBJECT_NAME_COLLISION) {						break;					}				}				while (part_num < 100);				if (!NT_SUCCESS(status)) {					VDKTRACE(VDKUPDATE,						("[VDK] IoCreateDevice(%ws) %s\n",						name_buf,						VdkStatusStr(status)));					continue;				}				VDKTRACE(VDKUPDATE|VDKINFO,					("[VDK] Created a partition device %ws\n",					name_buf));				//				// Set up device object fields.				//				part_object->Flags		|= DO_DIRECT_IO;				part_object->StackSize = DiskObject->StackSize;				part_object->Flags		&= ~DO_DEVICE_INITIALIZING;				//				// Link into the partition chain.				//				part_extension->NextPartition = part_object;				part_extension =					(PPART_EXTENSION)part_object->DeviceExtension;				RtlZeroMemory(part_extension, sizeof(PART_EXTENSION));				//				// Store device name				//				part_extension->DeviceName.Buffer =					ExAllocatePool(NonPagedPool, uni_name.Length + sizeof(WCHAR));				if (part_extension->DeviceName.Buffer) {					part_extension->DeviceName.Length = uni_name.Length;					part_extension->DeviceName.MaximumLength = uni_name.Length;					RtlZeroMemory(						part_extension->DeviceName.Buffer,						uni_name.Length + sizeof(WCHAR));					RtlCopyMemory(						part_extension->DeviceName.Buffer,						uni_name.Buffer,						uni_name.Length);				}				else {					VDKTRACE(VDKUPDATE,						("[VDK] Failed to allocate device name buffer.\n"));				}			}			VDKTRACE(VDKUPDATE | VDKINFO,				("[VDK] Partition List Item %lu uses %ws\n",				idx, part_extension->DeviceName.Buffer));			//			// Set up device extension fields.			//			part_extension->FirstPartition	= disk_extension;			part_extension->NextPartition	= NULL;			//			// Create symbolic link			// Win2K/XP style			//			part_num = 0;			do {				swprintf(name_buf,					L"\\Device\\Harddisk%lu\\Partition%u",					disk_extension->PhysicalNumber, ++part_num);				RtlInitUnicodeString(&uni_name, name_buf);				status = IoCreateSymbolicLink(					&uni_name, &part_extension->DeviceName);				if (status != STATUS_OBJECT_NAME_COLLISION) {					break;				}			}			while (part_num <= 128);			if (NT_SUCCESS(status)) {				VDKTRACE(VDKUPDATE|VDKINFO,					("[VDK] Created a symbolic link %ws\n",					name_buf));				part_extension->SymbolicLink.Buffer =					ExAllocatePool(NonPagedPool, uni_name.Length + sizeof(WCHAR));				if (part_extension->SymbolicLink.Buffer) {					part_extension->SymbolicLink.Length = uni_name.Length;					part_extension->SymbolicLink.MaximumLength = uni_name.Length;					RtlZeroMemory(						part_extension->SymbolicLink.Buffer,						uni_name.Length + sizeof(WCHAR));					RtlCopyMemory(						part_extension->SymbolicLink.Buffer,						uni_name.Buffer,						uni_name.Length);				}				else {					VDKTRACE(VDKUPDATE,						("[VDK] Failed to allocate symlink name buffer.\n"));				}			}			else {				VDKTRACE(VDKUPDATE,					("[VDK] IoCreateSymbolicLink(%ws) %s\n",					name_buf,					VdkStatusStr(status)));			}			partition_info->PartitionNumber = part_num;			//			// informs the Mount Manager of the new device			//#if 0			//			// I can't make this work for the time being...			// I guess I have to learn more about MM & PnP stuff :-(			//			{				PDEVICE_OBJECT	mntmgr_dev;				// Obtain a pointer to the Mount Manager device object				{					UNICODE_STRING	mntmgr_name;					PFILE_OBJECT	mntmgr_file;					RtlInitUnicodeString(						&mntmgr_name,						MOUNTMGR_DEVICE_NAME);					status = IoGetDeviceObjectPointer(						&mntmgr_name,						FILE_READ_ATTRIBUTES,						&mntmgr_file,						&mntmgr_dev);				}				if (NT_SUCCESS(status)) {					IO_STATUS_BLOCK			io_status;					KEVENT					event;					PIRP					irp;					PMOUNTMGR_TARGET_NAME	target_name;					USHORT					target_name_buf[MAXIMUM_FILENAME_LENGTH];					target_name = (PMOUNTMGR_TARGET_NAME)target_name_buf;					target_name->DeviceNameLength =						part_extension->DeviceName.Length;					RtlCopyMemory(						target_name->DeviceName,						part_extension->DeviceName.Buffer,						part_extension->DeviceName.Length);					KeInitializeEvent(&event, NotificationEvent, FALSE);					irp = IoBuildDeviceIoControlRequest(						IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,						mntmgr_dev,						target_name,						sizeof(target_name->DeviceNameLength) + target_name->DeviceNameLength,						NULL,						0,						FALSE,						&event,						&io_status);					if (irp) {						status = IoCallDriver(mntmgr_dev, irp);						if (status == STATUS_PENDING) {							KeWaitForSingleObject(								&event, Executive, KernelMode, FALSE, NULL);							status = io_status.Status;						}					}				}				else {					//					// probably running on Windows NT					//					VDKTRACE(VDKUPDATE | VDKWARN,						("[VDK] Failed to obtain the Mount Manager device object.\n"));				}			}#endif	// 0		}		//		// Update partition extension to match the latest state		//		part_extension->PartitionInfo		= *partition_info;		part_extension->PartitionOrdinal	= part_ordinal;	}	VDKTRACE(VDKUPDATE | VDKINFO, ("[VDK] VdkUpdateDevice - EXIT\n"));	return;}

⌨️ 快捷键说明

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