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 + -
显示快捷键?