www.pudn.com > vdksrc.zip > vdkcreate.c
/*
vdkcreate.c
Virtual Disk kernel-mode driver for Windows NT platform
Create disk device object
Copyright (C) 2003 Ken Kato
*/
#include "vdkbase.h"
#include "vdkutil.h"
#include "vdkioctl.h"
#include "vdkaccess.h"
#include "imports.h"
#include "vdkdrv.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, VdkCreateDisk)
#endif // ALLOC_PRAGMA
//
// Create a new disk device
//
NTSTATUS
VdkCreateDisk(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DiskNumber)
{
NTSTATUS status;
// for creating the directory object
ULONG drive_number;
WCHAR dir_buffer[20];
UNICODE_STRING dir_name;
OBJECT_ATTRIBUTES dir_attrib;
HANDLE dir_handle = NULL;
// for creating symbolic links
WCHAR link_buffer[25];
UNICODE_STRING link_name;
BOOLEAN link_created = FALSE;
// for creating device objects
WCHAR obj_buffer[40];
UNICODE_STRING obj_name;
PDEVICE_OBJECT disk_object = NULL;
PDISK_EXTENSION disk_extension = NULL;
// for creating disk device thread
HANDLE thread_handle = NULL;
VDKTRACE(VDKCREATE|VDKINFO,
("[VDK] VdkCreateDevice\n"));
///////////////////////////////////////////////////////
// Create the directory object
// \Device\Harddisk
// -- first create it permanent and then make it temporary.
//
drive_number = IoGetConfigurationInformation()->DiskCount;
do {
swprintf(dir_buffer, L"\\Device\\Harddisk%lu", drive_number);
RtlInitUnicodeString(&dir_name, dir_buffer);
InitializeObjectAttributes(
&dir_attrib, &dir_name, OBJ_PERMANENT, NULL, NULL);
status = ZwCreateDirectoryObject(
&dir_handle, DIRECTORY_ALL_ACCESS, &dir_attrib);
if (status != STATUS_OBJECT_NAME_EXISTS) {
break;
}
}
while (++drive_number < 100);
if (!NT_SUCCESS(status)) {
VDKTRACE(VDKCREATE,
("[VDK] ZwCreateDirectoryObject(%ws) %s\n",
dir_buffer,
VdkStatusStr(status)));
goto cleanup;
}
VDKTRACE(VDKCREATE|VDKINFO,
("[VDK] Created a directory object %ws\n", dir_buffer));
status = ZwMakeTemporaryObject(dir_handle);
if (!NT_SUCCESS(status)) {
VDKTRACE(VDKCREATE,
("[VDK] ZwMakeTemporaryObject() %s\n",
VdkStatusStr(status)));
goto cleanup;
}
///////////////////////////////////////////////////////
// Create the default sumbolic link in the DOS namespace
// \??\VirtualDK
//
swprintf(link_buffer, L"\\??\\" VDK_DEVICE_BASENAME L"%lu", DiskNumber);
RtlInitUnicodeString(&link_name, link_buffer);
status = IoCreateSymbolicLink(&link_name, &dir_name);
if (!NT_SUCCESS(status)) {
VDKTRACE(VDKCREATE,
("[VDK] IoCreateSymbolicLink(%ws) %s\n",
link_buffer,
VdkStatusStr(status)));
goto cleanup;
}
link_created = TRUE;
VDKTRACE(VDKCREATE|VDKINFO,
("[VDK] Created a symbolic link %ws\n", link_buffer));
///////////////////////////////////////////////////////
// Create the disk device object
// \Device\Harddisk\Partition0
//
swprintf(obj_buffer,
L"\\Device\\Harddisk%lu\\Partition0", drive_number);
RtlInitUnicodeString(&obj_name, obj_buffer);
status = IoCreateDevice(
DriverObject,
sizeof(DISK_EXTENSION),
&obj_name,
FILE_DEVICE_DISK,
0,
FALSE,
&disk_object);
if (!NT_SUCCESS(status)) {
VDKTRACE(VDKCREATE, ("[VDK] IoCreateDevice(%ws) %s\n",
obj_buffer,
VdkStatusStr(status)));
goto cleanup;
}
IoGetConfigurationInformation()->DiskCount++;
VDKTRACE(VDKCREATE|VDKINFO,
("[VDK] Created a disk device object %ws\n", obj_buffer));
///////////////////////////////////////////////////////
// Initialize the device object and extension.
//
disk_object->Flags |= DO_DIRECT_IO;
if (DriverObject->DriverUnload) {
// Called from outside the DriverEntry routine
disk_object->Flags &= ~DO_DEVICE_INITIALIZING;
}
disk_extension = (PDISK_EXTENSION)(disk_object->DeviceExtension);
RtlZeroMemory(disk_extension, sizeof(DISK_EXTENSION));
disk_extension->FirstPartition = disk_extension;
disk_extension->DeviceObject = disk_object;
disk_extension->DirectoryHandle = dir_handle;
disk_extension->PhysicalNumber = drive_number;
disk_extension->VirtualNumber = DiskNumber;
//
// Store device name
//
disk_extension->DeviceName.Buffer =
ExAllocatePool(NonPagedPool, obj_name.Length + sizeof(WCHAR));
if (!disk_extension->DeviceName.Buffer) {
VDKTRACE(VDKCREATE,
("[VDK] Failed to allocate device name buffer.\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
disk_extension->DeviceName.Length = obj_name.Length;
disk_extension->DeviceName.MaximumLength = obj_name.Length;
RtlZeroMemory(
disk_extension->DeviceName.Buffer,
obj_name.Length + sizeof(WCHAR));
RtlCopyMemory(
disk_extension->DeviceName.Buffer,
obj_name.Buffer,
obj_name.Length);
//
// Store symbolic link
//
disk_extension->SymbolicLink.Buffer =
ExAllocatePool(NonPagedPool, link_name.Length + sizeof(WCHAR));
if (!disk_extension->SymbolicLink.Buffer) {
VDKTRACE(VDKCREATE,
("[VDK] Failed to allocate symbolic link buffer.\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
disk_extension->SymbolicLink.Length = link_name.Length;
disk_extension->SymbolicLink.MaximumLength = link_name.Length;
RtlZeroMemory(
disk_extension->SymbolicLink.Buffer,
link_name.Length + sizeof(WCHAR));
RtlCopyMemory(
disk_extension->SymbolicLink.Buffer,
link_name.Buffer,
link_name.Length);
///////////////////////////////////////////////////
// Create the disk device thread which performs
// most of actual I/O tasks in the system context
//
InitializeListHead(&disk_extension->ListHead);
KeInitializeSpinLock(&disk_extension->ListLock);
KeInitializeEvent(
&disk_extension->RequestEvent,
SynchronizationEvent,
FALSE);
disk_extension->TerminateThread = FALSE;
status = PsCreateSystemThread(
&thread_handle,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
VdkThread,
disk_object);
if (!NT_SUCCESS(status)) {
VDKTRACE(VDKCREATE,
("[VDK] PsCreateSystemThread() %s\n",
VdkStatusStr(status)));
goto cleanup;
}
status = ObReferenceObjectByHandle(
thread_handle,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&disk_extension->ThreadPointer,
NULL);
ZwClose(thread_handle);
if (!NT_SUCCESS(status)) {
VDKTRACE(VDKCREATE,
("[VDK] ObReferenceObjectByHandle() %s\n",
VdkStatusStr(status)));
goto cleanup;
}
///////////////////////////////////////////////////////
// Create alternate symbolic link
// \??\PhysicalDrive
//
swprintf(link_buffer,
L"\\??\\PhysicalDrive%lu", disk_extension->PhysicalNumber);
RtlInitUnicodeString(&link_name, link_buffer);
disk_extension->AnotherLink.Buffer =
ExAllocatePool(NonPagedPool, link_name.Length + sizeof(WCHAR));
if (disk_extension->AnotherLink.Buffer) {
disk_extension->AnotherLink.Length = link_name.Length;
disk_extension->AnotherLink.MaximumLength = link_name.Length;
RtlZeroMemory(
disk_extension->AnotherLink.Buffer,
link_name.Length + sizeof(WCHAR));
RtlCopyMemory(
disk_extension->AnotherLink.Buffer,
link_name.Buffer,
link_name.Length);
IoCreateSymbolicLink(&link_name, &obj_name);
VDKTRACE(VDKCREATE|VDKINFO,
("[VDK] Created a symbolic link %ws\n", link_buffer));
}
else {
// this is not fatal - it is just that some programs may not
// recognize the virtual drive as a hard disk drive
VDKTRACE(VDKCREATE,
("[VDK] Failed to allocate alternate symlink name buffer.\n"));
}
cleanup:
if (!NT_SUCCESS(status)) {
//
// Delete everything created in this routine
//
// - Disk device thread
// - Disk device object
// - Symbolic links
// - Directory object
//
if (disk_extension) {
//
// Terminate disk device thread
//
if (thread_handle) {
VDKTRACE(VDKCREATE,
("[VDK] Terminating device thread\n"));
disk_extension->TerminateThread = TRUE;
KeSetEvent(
&disk_extension->RequestEvent,
(KPRIORITY) 0,
FALSE);
}
//
// Release the reference pointer
//
if (disk_extension->ThreadPointer) {
VDKTRACE(VDKCREATE,
("[VDK] Releasing the thread reference pointer\n"));
ObDereferenceObject(disk_extension->ThreadPointer);
}
if (disk_extension->DeviceName.Buffer) {
ExFreePool(disk_extension->DeviceName.Buffer);
}
if (disk_extension->SymbolicLink.Buffer) {
ExFreePool(disk_extension->SymbolicLink.Buffer);
}
if (disk_extension->AnotherLink.Buffer) {
ExFreePool(disk_extension->AnotherLink.Buffer);
}
}
//
// Delete default symbolic link
//
if (link_created) {
VDKTRACE(VDKCREATE,
("[VDK] Deleting symbolic link %ws\n", link_buffer));
IoDeleteSymbolicLink(&link_name);
}
//
// Delete disk device object
//
if (disk_object) {
VDKTRACE(VDKCREATE,
("[VDK] Deleting device object %ws\n", obj_buffer));
IoDeleteDevice(disk_object);
}
//
// Delete directory object
//
if (dir_handle) {
VDKTRACE(VDKCREATE,
("[VDK] Closing directory handle %ws\n", dir_buffer));
ZwClose(dir_handle);
}
}
return status;
}