对FileDisk源码研究

    FileDisk其实说到底也就是对磁盘的一些操作,其原理也相对简单,不像文件过滤驱动那么复杂,FileDisk也只用到了一套接口IRP_MJ_CREATE等,相对来说结构是比较简单的,下面是我对filedisk代码的一些注释,其实还有二个问题没搞太懂,还有一些小细节,不太清楚有些变量是用来搞什么的,还有几个小函数没弄太清楚,把问题放到最后再说。
 
#include
#include
#include
#include
//
// We include some stuff from newer DDK:s here so that one
// version of the driver for all versions of Windows can
// be compiled with the Windows NT 4.0 DDK.
//
#if (VER_PRODUCTBUILD < 2195)
#define FILE_DEVICE_MASS_STORAGE            0x0000002d
#define IOCTL_STORAGE_CHECK_VERIFY2         CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FILE_ATTRIBUTE_ENCRYPTED            0x00004000
#endif
#if (VER_PRODUCTBUILD < 2600)
#define IOCTL_DISK_GET_PARTITION_INFO_EX    CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DISK_GET_LENGTH_INFO          CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
typedef enum _PARTITION_STYLE {
    PARTITION_STYLE_MBR,
    PARTITION_STYLE_GPT
} PARTITION_STYLE;
typedef unsigned __int64 ULONG64, *PULONG64;
typedef struct _PARTITION_INFORMATION_MBR {
    UCHAR   PartitionType;
    BOOLEAN BootIndicator;
    BOOLEAN RecognizedPartition;
    ULONG   HiddenSectors;
} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;
typedef struct _PARTITION_INFORMATION_GPT {
    GUID    PartitionType;
    GUID    PartitionId;
    ULONG64 Attributes;
    WCHAR   Name[36];
} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;
typedef struct _PARTITION_INFORMATION_EX {
    PARTITION_STYLE PartitionStyle;
    LARGE_INTEGER   StartingOffset;
    LARGE_INTEGER   PartitionLength;
    ULONG           PartitionNumber;
    BOOLEAN         RewritePartition;
    union {
        PARTITION_INFORMATION_MBR Mbr;
        PARTITION_INFORMATION_GPT Gpt;
    };
} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;
typedef struct _GET_LENGTH_INFORMATION {
    LARGE_INTEGER Length;
} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
#endif // (VER_PRODUCTBUILD < 2600)
//
// We include some stuff from ntifs.h here so that
// the driver can be compiled with only the DDK.
//
#define TOKEN_SOURCE_LENGTH 8
typedef enum _TOKEN_TYPE {
    TokenPrimary = 1,
    TokenImpersonation
} TOKEN_TYPE;
typedef struct _TOKEN_SOURCE {
    CCHAR   SourceName[TOKEN_SOURCE_LENGTH];
    LUID    SourceIdentifier;
} TOKEN_SOURCE, *PTOKEN_SOURCE;
typedef struct _TOKEN_CONTROL {
    LUID            TokenId;
    LUID            AuthenticationId;
    LUID            ModifiedId;
    TOKEN_SOURCE    TokenSource;
} TOKEN_CONTROL, *PTOKEN_CONTROL;
typedef struct _SECURITY_CLIENT_CONTEXT {
    SECURITY_QUALITY_OF_SERVICE SecurityQos;
    PACCESS_TOKEN               ClientToken;
    BOOLEAN                     DirectlyAccessClientToken;
    BOOLEAN                     DirectAccessEffectiveOnly;
    BOOLEAN                     ServerIsRemote;
    TOKEN_CONTROL               ClientTokenControl;
} SECURITY_CLIENT_CONTEXT, *PSECURITY_CLIENT_CONTEXT;
#define PsDereferenceImpersonationToken(T)  \
            {if (ARGUMENT_PRESENT(T)) {     \
                (ObDereferenceObject((T))); \
            } else {                        \
                ;                           \
            }                               \
}
#define PsDereferencePrimaryToken(T) (ObDereferenceObject((T)))
NTKERNELAPI
VOID
PsRevertToSelf (
    VOID
);
NTKERNELAPI
NTSTATUS
SeCreateClientSecurity (
    IN PETHREAD                     Thread,
    IN PSECURITY_QUALITY_OF_SERVICE QualityOfService,
    IN BOOLEAN                      RemoteClient,
    OUT PSECURITY_CLIENT_CONTEXT    ClientContext
);
#define SeDeleteClientSecurity(C)  {                                           \
            if (SeTokenType((C)->ClientToken) == TokenPrimary) {               \
                PsDereferencePrimaryToken( (C)->ClientToken );                 \
            } else {                                                           \
                PsDereferenceImpersonationToken( (C)->ClientToken );           \
            }                                                                  \
}
NTKERNELAPI
VOID
SeImpersonateClient (
    IN PSECURITY_CLIENT_CONTEXT ClientContext,
    IN PETHREAD                 ServerThread OPTIONAL
);
NTKERNELAPI
TOKEN_TYPE
SeTokenType (
    IN PACCESS_TOKEN Token
);
#ifndef SE_IMPERSONATE_PRIVILEGE
#define SE_IMPERSONATE_PRIVILEGE        (29L)
#endif
#define TOKEN_ASSIGN_PRIMARY            (0x0001)
#define TOKEN_DUPLICATE                 (0x0002)
#define TOKEN_IMPERSONATE               (0x0004)
#define TOKEN_QUERY                     (0x0008)
#define TOKEN_QUERY_SOURCE              (0x0010)
#define TOKEN_ADJUST_PRIVILEGES         (0x0020)
#define TOKEN_ADJUST_GROUPS             (0x0040)
#define TOKEN_ADJUST_DEFAULT            (0x0080)
#define TOKEN_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED |\
                          TOKEN_ASSIGN_PRIMARY     |\
                          TOKEN_DUPLICATE          |\
                          TOKEN_IMPERSONATE        |\
                          TOKEN_QUERY              |\
                          TOKEN_QUERY_SOURCE       |\
                          TOKEN_ADJUST_PRIVILEGES  |\
                          TOKEN_ADJUST_GROUPS      |\
                          TOKEN_ADJUST_DEFAULT)
typedef struct _TOKEN_PRIVILEGES {
    ULONG               PrivilegeCount;
    LUID_AND_ATTRIBUTES Privileges[1];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenProcessToken (
    IN HANDLE       ProcessHandle,
    IN ACCESS_MASK  DesiredAccess,
    OUT PHANDLE     TokenHandle
);
NTSYSAPI
NTSTATUS
NTAPI
NtAdjustPrivilegesToken (
    IN HANDLE               TokenHandle,
    IN BOOLEAN              DisableAllPrivileges,
    IN PTOKEN_PRIVILEGES    NewState,
    IN ULONG                BufferLength,
    OUT PTOKEN_PRIVILEGES   PreviousState OPTIONAL,
    OUT PULONG              ReturnLength
);
//
// For backward compatibility with Windows NT 4.0 by Bruce Engle.
//
#ifndef MmGetSystemAddressForMdlSafe
#define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) MmGetSystemAddressForMdlPrettySafe(MDL)
PVOID
MmGetSystemAddressForMdlPrettySafe (
    PMDL Mdl
    )
{
    CSHORT  MdlMappingCanFail;
    PVOID   MappedSystemVa;
    MdlMappingCanFail = Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL;
    Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
    MappedSystemVa = MmGetSystemAddressForMdl(Mdl);
    if (MdlMappingCanFail == 0)
    {
        Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;
    }
    return MappedSystemVa;
}
#endif
#include "filedisk.h"
#define PARAMETER_KEY           L"\\Parameters"
#define NUMBEROFDEVICES_VALUE   L"NumberOfDevices"
#define DEFAULT_NUMBEROFDEVICES 4
#define SECTOR_SIZE             512
#define TOC_DATA_TRACK          0x04
HANDLE dir_handle;
typedef struct _DEVICE_EXTENSION {
 //media_in_device是指这个设备是否已经指定了一个文件作为存储媒质。
 //这是一个用文件来虚拟磁盘的驱动。那么一个磁盘应该对应一个实际存在的文件。
 //读写这个磁盘的请求最终转变为对文件的读写。
 //如果一个磁盘设备对象还没有指定文件,那么这个内容是FALSE。
    BOOLEAN                     media_in_device;
 //file_handle是文件句柄。也就是这个虚拟磁盘所对应的文件。
    HANDLE                      file_handle;
 //file_information是这个文件的一些信息。
    ANSI_STRING                 file_name;
   
 LARGE_INTEGER               file_size;
 
 //read_only是否只读
    BOOLEAN                     read_only;
 //访问文件的时候需要使用的一个线程客户安全性上下文
    PSECURITY_CLIENT_CONTEXT    security_client_context;
 //是一个链表头。一部分irp(windows发来的请求包)被放入这个链表中。
 //我们为每个磁盘对象开启一个系统线程(处理线程),专门用来处理这些请求。
    LIST_ENTRY                  list_head;
 //是为了保证链表读写同步的锁
    KSPIN_LOCK                  list_lock;
 //是一个事件。当链表中没有请求的时候,处理请求的系统线程并不做任何事情,
 //而只等待这个事件。当有请求到来,我们把请求放入链表,然后设置这个事件。
 //处理线程就会开始处理这些请求。
    KEVENT                      request_event;
 //是线程的指针,用来最后等待这个线程的结束。
    PVOID                       thread_pointer;
 //是一个标志。如果设置为TRUE,处理线程执行的时候检测到这个,就会把自己终止掉。
    BOOLEAN                     terminate_thread;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS
DriverEntry (
    IN PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING  RegistryPath
);
NTSTATUS
FileDiskCreateDevice (
    IN PDRIVER_OBJECT   DriverObject,
    IN ULONG            Number,
    IN DEVICE_TYPE      DeviceType
);
VOID
FileDiskUnload (
    IN PDRIVER_OBJECT   DriverObject
);
PDEVICE_OBJECT
FileDiskDeleteDevice (
    IN PDEVICE_OBJECT   DeviceObject
);
NTSTATUS
FileDiskCreateClose (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);
NTSTATUS
FileDiskReadWrite (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);
NTSTATUS
FileDiskDeviceControl (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);
VOID
FileDiskThread (
    IN PVOID            Context
);
NTSTATUS
FileDiskOpenFile (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);
NTSTATUS
FileDiskCloseFile (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp
);
NTSTATUS
FileDiskAdjustPrivilege (
    IN ULONG            Privilege,
    IN BOOLEAN          Enable
);
int swprintf(wchar_t *, const wchar_t *, ...);
#pragma code_seg("INIT")

// 驱动程序入口
NTSTATUS
DriverEntry (
    IN PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING  RegistryPath
    )
{
 //放驱动参数的路径
    UNICODE_STRING              parameter_path;
  //query_table[0] = " \\Device\\FileDisk0";
  //query_table[1] = " \\Device\\FileDisk1";
  //query_table[2] = " \\Device\\FileDisk2";
       RTL_QUERY_REGISTRY_TABLE       query_table[2];
       ULONG                                             n_devices;
       NTSTATUS                                       status;
       UNICODE_STRING                           device_dir_name;
       OBJECT_ATTRIBUTES                     object_attributes;
       ULONG                                             n;
       USHORT                                           n_created_devices;
       parameter_path.Length = 0;
 
  // 注册表路径的长度
  //这参数用途在哪里,这个长度用在下一个函数,申请存放路径buffer的长度;
       parameter_path.MaximumLength = RegistryPath->Length + sizeof(PARAMETER_KEY);
  //这里是用来存放注册表路径的Buffer,用到刚刚求出的长度,
       parameter_path.Buffer = (PWSTR) ExAllocatePool(PagedPool, parameter_path.MaximumLength);
       if (parameter_path.Buffer == NULL)
       {
               return STATUS_INSUFFICIENT_RESOURCES;
       }
  // copies a source string to a destination string
  //在这里就把驱动注册表的路径放到我们申请的Buffer中了,同时还有长度,因为parameter_path是
  //UNICODE_STRING类型结构体;
       RtlCopyUnicodeString(&parameter_path, RegistryPath);
  //concatenates the supplied Unicode string to a buffered
  //现在parameter_path就是驱动参数的完整路径
  //这个函数把PARAMETER_KEY加在了注册表路径buffer的后面,这里组成了一个完整的路径;
       RtlAppendUnicodeToString (&parameter_path, PARAMETER_KEY);
  //把query_table[0]的内容全置空
       RtlZeroMemory(&query_table[0], sizeof(query_table));
       query_table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
 
  //驱动注册表健值的名字NumberOfDevices;
       query_table[0].Name = NUMBEROFDEVICES_VALUE; // L"NumberOfDevices"
       query_table[0].EntryContext = &n_devices;
 
  //#define RTL_REGISTRY_ABSOLUTE         0   
  // Path is a full path
  //allows the caller to query several values from the registry subtree with a single call.
  //这个函数查询注册表里的数据
       status = RtlQueryRegistryValues(
               RTL_REGISTRY_ABSOLUTE,
               parameter_path.Buffer,
               &query_table[0],
               NULL,
               NULL
               );
       ExFreePool(parameter_path.Buffer);
       if (!NT_SUCCESS(status))
       {
               KdPrint(("FileDisk: Query registry failed, using default values.\n"));
               n_devices = DEFAULT_NUMBEROFDEVICES;
       }
 
  //#define DEVICE_DIR_NAME         _T(" \\Device")           DEVICE_BASE_NAME
       RtlInitUnicodeString(&device_dir_name, DEVICE_DIR_NAME);
       InitializeObjectAttribut es(
               &object_attributes,
               &device_dir_name,
               OBJ_PERMANENT,
               NULL,
               NULL
               );
  //创建一个目录名为" \\Device";
       status = ZwCreateDirectoryObject(
               &dir_handle,
               DIRECTORY_ALL_ACCESS,
               &object_attributes
               );
       if (!NT_SUCCESS(status))
       {
               return status;
       }
 
  //changes the attributes of an object to make it temporary(暂时的)
       ZwMakeTemporaryObject(dir_handle);
       for (n = 0, n_created_devices = 0; n < n_devices; n++)
       {
    //#define FILE_DEVICE_DISK                               0x00000007
    //生成一个磁盘设备对象
               status = FileDiskCreateDevice(DriverObject, n, FILE_DEVICE_DISK);
               if (NT_SUCCESS(status))
               {
                       n_created_devices++;
               }
       }
       for (n = 0; n < n_devices; n++)
       {
    //#define FILE_DEVICE_CD_ROM                           0x00000002
    //生成一个磁盘设备对象
               status = FileDiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);
               if (NT_SUCCESS(status))
               {
                       n_created_devices++;
               }
       }
  //通过DeviceTree 可以看到上面二个FOR循环生成了8个设备,n_devices = 4;
       if (n_created_devices == 0)
       {
               ZwClose(dir_handle);
               return status;
       }
       DriverObject->MajorFunction[IRP_MJ_CREATE]                 = FileDiskCreateClose;
       DriverObject->MajorFunction[IRP_MJ_CLOSE]                   = FileDiskCreateClose;
       DriverObject->MajorFunction[IRP_MJ_READ]                     = FileDiskReadWrite;
       DriverObject->MajorFunction[IRP_MJ_WRITE]                   = FileDiskReadWrite;
       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileDiskDeviceControl;
       DriverObject->DriverUnload = FileDiskUnload;
       return STATUS_SUCCESS;
}

//生成一个磁盘设备对象
//可以通过DeviceTree可以看到;
NTSTATUS
FileDiskCreateDevice (
       IN PDRIVER_OBJECT     DriverObject,
       IN ULONG                       Number,
       IN DEVICE_TYPE           DeviceType
       )
{
  //存放设备对象名子的数组
       WCHAR                             device_name_buffer[MAXIMUM_FILENAME_LENGTH];
       UNICODE_STRING           device_name;
       NTSTATUS                       status;
       PDEVICE_OBJECT           device_object;
       PDEVICE_EXTENSION     device_extension;
       HANDLE                           thread_handle;
       ASSERT(DriverObject != NULL);
       if (DeviceType == FILE_DEVICE_CD_ROM)
       {
               swprintf(
                       device_name_buffer,
                       DEVICE_NAME_PREFIX L"Cd" L"%u",
                       Number
                       );
       }
       else
       {
               swprintf(
                       device_name_buffer,
                       DEVICE_NAME_PREFIX L"%u",
                       Number
                       );
       }
       RtlInitUnicodeString(&device_name, device_name_buffer);
       status = IoCreateDevice(
               DriverObject,
               sizeof(DEVICE_EXTENSION),
               &device_name,
               DeviceType,
               0,
               FALSE,
               &device_object
               );
       if (!NT_SUCCESS(status))
       {
               return status;
       }
       device_object->Flags |= DO_DIRECT_IO;
       device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
       device_extension->media_in_device = FALSE;
       if (DeviceType == FILE_DEVICE_CD_ROM)
       {
               device_object->Characteristics |= FILE_READ_ONLY_DEVICE;
               device_extension->read_only = TRUE;
       }
       InitializeListHead(&device_extension->list_head);
       KeInitializeSpinLock(&device_extension->list_lock);
       KeInitializeEvent(
               &device_extension->request_event,
               SynchronizationEvent,
               FALSE
               );
       device_extension->terminate_thread = FALSE;
       //生成一个系统线程
  //前面说到为每一个磁盘设备对象生成了一个系统线程,用来处理Irp。
  //系统线程的生成用以下的调用:
       status = PsCreateSystemThread(
               &thread_handle,
               (ACCESS_MASK) 0L,
               NULL,
               NULL,
               NULL,
               FileDiskThread,
               device_object
               );
       if (!NT_SUCCESS(status))
       {
               IoDeleteDevice(device_object);
               return status;
       }
  //device_object是我所生成的磁盘设备对象。作为线程上下文传入。
  //便于我们在线程中得到设备对象指针,然后得到设备扩展。
  //稍后我们要把线程对象的指针保留下来存到设备扩展中。这使用
       status = ObReferenceObjectByHandl e(
               thread_handle,
               THREAD_ALL_ACCESS,
               NULL,
               KernelMode,
               &device_extension->thread_pointer,
               NULL
               );
       if (!NT_SUCCESS(status))
       {
               ZwClose(thread_handle);
               device_extension->terminate_thread = TRUE;
               KeSetEvent(
                       &device_extension->request_event,
                       (KPRIORITY) 0,
                       FALSE
                       );
               IoDeleteDevice(device_object);
               return status;
       }
       ZwClose(thread_handle);
       return STATUS_SUCCESS;
}
#pragma code_seg("PAGE")
VOID
FileDiskUnload (
       IN PDRIVER_OBJECT DriverObject
       )
{
       PDEVICE_OBJECT device_object;
       PAGED_CODE();
       device_object = DriverObject->DeviceObject;
       while (device_object)
       {
               device_object = FileDiskDeleteDevice(device_object);
       }
       ZwClose(dir_handle);
}
PDEVICE_OBJECT
FileDiskDeleteDevice (
       IN PDEVICE_OBJECT DeviceObject
       )
{
       PDEVICE_EXTENSION     device_extension;
       PDEVICE_OBJECT           next_device_object;
       PAGED_CODE();
       ASSERT(DeviceObject != NULL);
       device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
       device_extension->terminate_thread = TRUE;
  //sets an event object to a signaled state if the event was not already signaled,
  //and returns the previous state of the event object.
       KeSetEvent(
               &device_extension->request_event,
               (KPRIORITY) 0,
               FALSE
               );
       KeWaitForSingleObject(
               device_extension->thread_pointer,
               Executive,
               KernelMode,
               FALSE,
               NULL
               );
       ObDereferenceObject(device_extension->thread_pointer);
       if (device_extension->security_client_context != NULL)
       {
               SeDeleteClientSecurity(device_extension->security_client_context);
               ExFreePool(device_extension->security_client_context);
       }
       next_device_object = DeviceObject->NextDevice;
       IoDeleteDevice(DeviceObject);
       return next_device_object;
}
 
//这里需要Create和Close是为了通信。让应用程序可以打开这些磁盘设备来设置一些信息。
//打开关闭非常简单,都是对irp无条件返回成功:
NTSTATUS
FileDiskCreateClose (
       IN PDEVICE_OBJECT     DeviceObject,
       IN PIRP                         Irp
       )
{
  //PAGED_CODE()是一个调试用的宏。如果一个函数被定义在可分页交换的段中,
  //那么它执行时的中断级别必须满足一定的要求。PAGED_CODE()用来检测是否符合。
  //如果不行,调试版本中这里会出现失败。这个宏仅仅在调试版本下有效。
       PAGED_CODE();
       Irp->IoStatus.Status = STATUS_SUCCESS;
       Irp->IoStatus.Information = FILE_OPENED;
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
       return STATUS_SUCCESS;
}
#pragma code_seg()

//DDK里有一个例子disk,它的读写非常复杂。而本方案的读写是对文件的读写。
//所以相对简单一些。基本的过程如下:   
//1.得到设备扩展。     
//2.检查是否已经打开了文件。如果没有,直接返回失败。   
//3.对于长度为0的读写,直接返回成功。 
//4.把请求加入设备扩展中的请求队列中,设置事件让处理线程运行处理。
//5.返回等待。
//你固然可以在读写例程中直接读写文件。
//但是这不符合惯例。读写文件需要消耗的时间比较长,
//应该让系统尽快得到答复以便可以干其他的事情。
//此外这个函数很容易重入,我们希望把读写请求的完成序列化,
//为此我们并不在这里直接读写文件。而是把请求放入队列中。
//为每个磁盘设备对象生成一个系统线程,来依次处理这些请求。
NTSTATUS
FileDiskReadWrite (
       IN PDEVICE_OBJECT     DeviceObject,
       IN PIRP                         Irp
       )
{
       PDEVICE_EXTENSION     device_extension;
       PIO_STACK_LOCATION   io_stack;
 
  //得到设备扩展;
       device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  //上面得到了设备扩展,那么我检查这个磁盘是否已经有物理媒质(也就是一个文件用来模拟磁盘空间)。 
  如果没有打开过文件,就返回失败   
  if (!device_extension->media_in_device)
       {
               Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
               Irp->IoStatus.Information = 0;
               IoCompleteRequest(Irp, IO_NO_INCREMENT);
               return STATUS_NO_MEDIA_IN_DEVICE;
       }
 
  //想得到要读多长的时候要得到Irp的当前栈空间:
  //irp当前栈空间里有具体的要读写的长度,以及别的重要信息;
       io_stack = IoGetCurrentIrpStackLoca tion(Irp);
  // 读0长的时候立刻成功
       if (io_stack->Parameters.Read.Length == 0)
       {
               Irp->IoStatus.Status = STATUS_SUCCESS;
               Irp->IoStatus.Information = 0;
               IoCompleteRequest(Irp, IO_NO_INCREMENT);
               return STATUS_SUCCESS;
       }
  //然后就可以把Irp放到队列里去等待完成了:
  // 标志pending
       IoMarkIrpPending(Irp);
 
  // 把请求写入链表
       ExInterlockedInsertTailL ist(
               &device_extension->list_head,
               &Irp->Tail.Overlay.ListEntry,
               &device_extension->list_lock
               );
  // 设置事件。让线程循环运行。
       KeSetEvent(
               &device_extension->request_event,
               (KPRIORITY) 0,
               FALSE
               );
       return STATUS_PENDING;
  //到此读写例程完成。至于真正的读写完成在处理线程中。
}

//设备控制(Device Control)是除了读、写之外最重要的操作之一。
//对磁盘来说,windows通过发送设备控制请求来询问磁盘的一些信息。
//收到设备控制请求之后,应该首先得到控制功能号,然后根据不同的控制功能号进行不同的处理.
//这些功能号有些是windows固有的,有些是由自己定义的。
NTSTATUS
FileDiskDeviceControl (
       IN PDEVICE_OBJECT     DeviceObject,
       IN PIRP                         Irp
       )
{
       PDEVICE_EXTENSION     device_extension;
       PIO_STACK_LOCATION   io_stack;
       NTSTATUS                       status;
  //得到设备扩展
       device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  //得到当前设备栈
       io_stack = IoGetCurrentIrpStackLoca tion(Irp);
  // 判断如果是还没有加载物理媒质就返回失败。但是     
  // IOCTL_FILE_DISK_OPEN_FILE是自定义的功能号,专     
  // 用来加载物理媒质的,所以排除在外
       if (!device_extension->media_in_device &&
               io_stack->Parameters.DeviceIoControl.IoControlCode !=
               IOCTL_FILE_DISK_OPEN_FILE)
       {
               Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
               Irp->IoStatus.Information = 0;
               IoCompleteRequest(Irp, IO_NO_INCREMENT);
               return STATUS_NO_MEDIA_IN_DEVICE;
       }
  //有很多的设备控制码要处理。这些请求都有参数,从输入空间得到参数后,
  //把返回结果写到输出空间。无论什么请求,
  //其输入和输出空间都是Irp->AssociatedIrp.SystemBuffer,
  //但是每种请求的参数和返回都有自己的格式,需要参考相应的文档。
       switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
       {
  //根据不同的功能号处理不同的操作;
       case IOCTL_FILE_DISK_OPEN_FILE:
               {
                       SECURITY_QUALITY_OF_SERVICE security_quality_of_service;
                       if (device_extension->media_in_device)
                       {
                               KdPrint(("FileDisk: IOCTL_FILE_DISK_OPEN_FILE: Media already opened\n"));
                               status = STATUS_INVALID_DEVICE_REQUEST;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>                              sizeof(OPEN_FILE_INFORMATION))
                       {
                               status = STATUS_INVALID_PARAMETER;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>                              sizeof(OPEN_FILE_INFORMATION) +
                               ((POPEN_FILE_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->FileNameLength -
                               sizeof(UCHAR))
                       {
                               status = STATUS_INVALID_PARAMETER;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       if (device_extension->security_client_context != NULL)
                       {
                               SeDeleteClientSecurity(device_extension->security_client_context);
                       }
                       else
                       {
                               device_extension->security_client_context =
                                       ExAllocatePool(NonPagedPool, sizeof(SECURITY_CLIENT_CONTEXT));
                       }
                       RtlZeroMemory(&security_quality_of_service, sizeof(SECURITY_QUALITY_OF_SERVICE));
                       security_quality_of_service.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
                       security_quality_of_service.ImpersonationLevel = SecurityImpersonation;
                       security_quality_of_service.ContextTrackingMode = SECURITY_STATIC_TRACKING;
                       security_quality_of_service.EffectiveOnly = FALSE;
                       SeCreateClientSecurity(
                               PsGetCurrentThread(),
                               &security_quality_of_service,
                               FALSE,
                               device_extension->security_client_context
                               );
                       IoMarkIrpPending(Irp);
                       ExInterlockedInsertTailL ist(
                               &device_extension->list_head,
                               &Irp->Tail.Overlay.ListEntry,
                               &device_extension->list_lock
                               );
                       KeSetEvent(
                               &device_extension->request_event,
                               (KPRIORITY) 0,
                               FALSE
                               );
                       status = STATUS_PENDING;
                       break;
               }
       case IOCTL_FILE_DISK_CLOSE_FILE:
               {
                       IoMarkIrpPending(Irp);
                       ExInterlockedInsertTailL ist(
                               &device_extension->list_head,
                               &Irp->Tail.Overlay.ListEntry,
                               &device_extension->list_lock
                               );
                       KeSetEvent(
                               &device_extension->request_event,
                               (KPRIORITY) 0,
                               FALSE
                               );
                       status = STATUS_PENDING;
                       break;
               }
       case IOCTL_FILE_DISK_QUERY_FILE:
               {
                       POPEN_FILE_INFORMATION open_file_information;
                       if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>                              sizeof(OPEN_FILE_INFORMATION) + device_extension->file_name.Length - sizeof(UCHAR))
                       {
                               status = STATUS_BUFFER_TOO_SMALL;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       open_file_information = (POPEN_FILE_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
                       open_file_information->FileSize.QuadPart = device_extension->file_size.QuadPart;
                       open_file_information->ReadOnly = device_extension->read_only;
                       open_file_information->FileNameLength = device_extension->file_name.Length;
                       RtlCopyMemory(
                               open_file_information->FileName,
                               device_extension->file_name.Buffer,
                               device_extension->file_name.Length
                               );
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = sizeof(OPEN_FILE_INFORMATION) +
                               open_file_information->FileNameLength - sizeof(UCHAR);
                       break;
               }
  //下面的4个功能号检查磁盘的有效性。现在一律返回有效,这个请求简单,不带参数。
       case IOCTL_DISK_CHECK_VERIFY:
       case IOCTL_CDROM_CHECK_VERIFY:
       case IOCTL_STORAGE_CHECK_VERIFY:
       case IOCTL_STORAGE_CHECK_VERIFY2:
               {
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = 0;
                       break;
               }
  //下面这个请求获得磁盘的物理属性:
  //请注意你要把结果写入到一个DISK_GEOMETRY结构中并把这个结构返回到
  //Irp->AssociatedIrp.SystemBuffer中。这个结构的定义如下:   
    //typedef struct _DISK_GEOMETRY
    //{LARGE_INTEGER Cylinders;           磁柱个数           
    //MEDIA_TYPE MediaType;                   媒质类型           
    //ULONG TracksPerCylinder;             每个磁柱上的磁道数             
    //ULONG SectorsPerTrack;                 每个磁道上的扇区数             
    //ULONG BytesPerSector;                   每个扇区上的字节数
    //} DISK_GEOMETRY, *PDISK_GEOMETRY;
  //以上这个结构说明来自ddk文档。你必须"如实"的返回这些数据。
       case IOCTL_DISK_GET_DRIVE_GEOMETRY:
       case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
               {
                       PDISK_GEOMETRY   disk_geometry;
                       ULONGLONG             length;
                       if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>                              sizeof(DISK_GEOMETRY))
                       {
                               status = STATUS_BUFFER_TOO_SMALL;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
                       length = device_extension->file_size.QuadPart;
                       disk_geometry->Cylinders.QuadPart = length / SECTOR_SIZE / 32 / 2;
                       disk_geometry->MediaType = FixedMedia;
                       disk_geometry->TracksPerCylinder = 2;
                       disk_geometry->SectorsPerTrack = 32;
                       disk_geometry->BytesPerSector = SECTOR_SIZE;
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
                       break;
               }

       case IOCTL_DISK_GET_LENGTH_INFO:
               {
                       PGET_LENGTH_INFORMATION get_length_information;
                       if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>                              sizeof(GET_LENGTH_INFORMATION))
                       {
                               status = STATUS_BUFFER_TOO_SMALL;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       get_length_information = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
                       get_length_information->Length.QuadPart = device_extension->file_size.QuadPart;
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
               break;
               }
  //此外比较重要的是获取分区信息,获取分区信息有两个功能号
  //IOCTL_DISK_GET_PARTITION_INFO和IOCTL_DISK_GET_PARTITION_INFO_EX,
  //其处理过程是类似的,只是返回结果的结构不同
       case IOCTL_DISK_GET_PARTITION_INFO:
               {
                       PPARTITION_INFORMATION   partition_information;
                       ULONGLONG                             length;
                       if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>                              sizeof(PARTITION_INFORMATION))
                       {
                               status = STATUS_BUFFER_TOO_SMALL;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       partition_information = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
                       length = device_extension->file_size.QuadPart;
                       partition_information->StartingOffset.QuadPart = 0;
                       partition_information->PartitionLength.QuadPart = length;
                       partition_information->HiddenSectors = 1;
                       partition_information->PartitionNumber = 0;
                       partition_information->PartitionType = 0;
                       partition_information->BootIndicator = FALSE;
                       partition_information->RecognizedPartition = FALSE;
                       partition_information->RewritePartition = FALSE;
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
                       break;
               }
       case IOCTL_DISK_GET_PARTITION_INFO_EX:
               {
                       PPARTITION_INFORMATION_EX     partition_information_ex;
                       ULONGLONG                                     length;
                       if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>                              sizeof(PARTITION_INFORMATION_EX))
                       {
                               status = STATUS_BUFFER_TOO_SMALL;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       partition_information_ex = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
                       length = device_extension->file_size.QuadPart;
                       partition_information_ex->PartitionStyle = PARTITION_STYLE_MBR;
                       partition_information_ex->StartingOffset.QuadPart = 0;
                       partition_information_ex->PartitionLength.QuadPart = length;
                       partition_information_ex->PartitionNumber = 0;
                       partition_information_ex->RewritePartition = FALSE;
                       partition_information_ex->Mbr.PartitionType = 0;
                       partition_information_ex->Mbr.BootIndicator = FALSE;
                       partition_information_ex->Mbr.RecognizedPartition = FALSE;
                       partition_information_ex->Mbr.HiddenSectors = 1;
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
                       break;
               }
       case IOCTL_DISK_IS_WRITABLE:
               {
                       if (!device_extension->read_only)
                       {
                               status = STATUS_SUCCESS;
                       }
                       else
                       {
                               status = STATUS_MEDIA_WRITE_PROTECTED;
                       }
                       Irp->IoStatus.Information = 0;
                       break;
               }
       case IOCTL_DISK_MEDIA_REMOVAL:
       case IOCTL_STORAGE_MEDIA_REMOVAL:
               {
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = 0;
                       break;
               }
       case IOCTL_CDROM_READ_TOC:
               {
                       PCDROM_TOC cdrom_toc;
                       if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>                              sizeof(CDROM_TOC))
                       {
                               status = STATUS_BUFFER_TOO_SMALL;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       cdrom_toc = (PCDROM_TOC) Irp->AssociatedIrp.SystemBuffer;
                       RtlZeroMemory(cdrom_toc, sizeof(CDROM_TOC));
                       cdrom_toc->FirstTrack = 1;
                       cdrom_toc->LastTrack = 1;
                       cdrom_toc->TrackData[0].Control = TOC_DATA_TRACK;
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = sizeof(CDROM_TOC);
                       break;
               }
       case IOCTL_DISK_SET_PARTITION_INFO:
               {
                       if (device_extension->read_only)
                       {
                               status = STATUS_MEDIA_WRITE_PROTECTED;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>                              sizeof(SET_PARTITION_INFORMATION))
                       {
                               status = STATUS_INVALID_PARAMETER;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = 0;
                       break;
               }
       case IOCTL_DISK_VERIFY:
               {
                       PVERIFY_INFORMATION verify_information;
                       if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>                              sizeof(VERIFY_INFORMATION))
                       {
                               status = STATUS_INVALID_PARAMETER;
                               Irp->IoStatus.Information = 0;
                               break;
                       }
                       verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
                       status = STATUS_SUCCESS;
                       Irp->IoStatus.Information = verify_information->Length;
                       break;
               }
       default:
               {
                       KdPrint((
                               "FileDisk: Unknown IoControlCode %#x\n",
                               io_stack->Parameters.DeviceIoControl.IoControlCode
                               ));
                       status = STATUS_INVALID_DEVICE_REQUEST;
                       Irp->IoStatus.Information = 0;
               }
       }
       if (status != STATUS_PENDING)
       {
               Irp->IoStatus.Status = status;
               IoCompleteRequest(Irp, IO_NO_INCREMENT);
       }
       return status;
}

//线程的启动函数是FileDiskThread。它实现了以下的功能:
//1.获得设备扩展
//2.设置线程优先级。
//3.进入死循环。首先等待事件的发生(device_extension->request_event),避免空循环消耗资源。
//4.检查终止标志(device_extension->terminate_thread)。如果外部要求终止,就使用
//PsTerminateSystemThread(STATUS_SUCCESS)终止它。
//5.检查请求链表(device_extension->list_head),若有请求,则完成他们。
VOID
FileDiskThread (
       IN PVOID Context
       )
{
       PDEVICE_OBJECT           device_object;
       PDEVICE_EXTENSION     device_extension;
       PLIST_ENTRY                 request;
       PIRP                               irp;
       PIO_STACK_LOCATION   io_stack;
       PUCHAR                           system_buffer;
       PUCHAR                           buffer;
       ASSERT(Context != NULL);
       device_object = (PDEVICE_OBJECT) Context;
       device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
       KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
       FileDiskAdjustPrivilege(SE_IMPERSONATE_PRIVILEGE, TRUE);
       for (;;)
       {
               KeWaitForSingleObject(
                       &device_extension->request_event,
                       Executive,
                       KernelMode,
                       FALSE,
                       NULL
                       );
               if (device_extension->terminate_thread)
               {
                       PsTerminateSystemThread(STATUS_SUCCESS);
               }
               while (request = ExInterlockedRemoveHeadL ist(
                       &device_extension->list_head,
                       &device_extension->list_lock
                       ))
               {
                       irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
                       io_stack = IoGetCurrentIrpStackLoca tion(irp);
      //IRP请求放到栈中,判断请求类型是靠io_stack->MajorFunction要分别的;
                       switch (io_stack->MajorFunction)
                       {
                       case IRP_MJ_READ:
                               system_buffer = (PUCHAR) MmGetSystemAddressForMdl Safe(irp->MdlAddress, NormalPagePriority);
                               if (system_buffer == NULL)
                               {
                                       irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                                       irp->IoStatus.Information = 0;
                                       break;
                               }
                               buffer = (PUCHAR) ExAllocatePool(PagedPool, io_stack->Parameters.Read.Length);
                               if (buffer == NULL)
                               {
                                       irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                                       irp->IoStatus.Information = 0;
                                       break;
                               }
                               ZwReadFile(
                                       device_extension->file_handle,
                                       NULL,
                                       NULL,
                                       NULL,
                                       &irp->IoStatus,
                                       buffer,
                                       io_stack->Parameters.Read.Length,
                                       &io_stack->Parameters.Read.ByteOffset,
                                       NULL
                                       );
                               RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length);
                               ExFreePool(buffer);
                               break;
                       case IRP_MJ_WRITE:
                               if ((io_stack->Parameters.Write.ByteOffset.QuadPart +
                                         io_stack->Parameters.Write.Length) >
                                         device_extension->file_size.QuadPart)
                               {
                                       irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                                       irp->IoStatus.Information = 0;
                               }
                               ZwWriteFile(
                                       device_extension->file_handle,
                                       NULL,
                                       NULL,
                                       NULL,
                                       &irp->IoStatus,
                                       MmGetSystemAddressForMdl Safe(irp->MdlAddress, NormalPagePriority),
                                       io_stack->Parameters.Write.Length,
                                       &io_stack->Parameters.Write.ByteOffset,
                                       NULL
                                       );
                               break;
                       case IRP_MJ_DEVICE_CONTROL:
                               switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
                               {
                               case IOCTL_FILE_DISK_OPEN_FILE:
                                       SeImpersonateClient(device_extension->security_client_context, NULL);
                                       irp->IoStatus.Status = FileDiskOpenFile(device_object, irp);
                                       PsRevertToSelf();
                                       break;
                               case IOCTL_FILE_DISK_CLOSE_FILE:
                                       irp->IoStatus.Status = FileDiskCloseFile(device_object, irp);
                                       break;
                               default:
                                       irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
                               }
                               break;
                       default:
                               irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
                       }
      //最后都用IoCompleteRequest完成这些请求
                       IoCompleteRequest(
                               irp,
                               (CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?
                               IO_DISK_INCREMENT : IO_NO_INCREMENT)
                               );
               }
       }
}
#pragma code_seg("PAGE")
NTSTATUS
FileDiskOpenFile (
       IN PDEVICE_OBJECT     DeviceObject,
       IN PIRP                         Irp
       )
{
       PDEVICE_EXTENSION                             device_extension;
       POPEN_FILE_INFORMATION                   open_file_information;
       UNICODE_STRING                                   ufile_name;
       NTSTATUS                                               status;
       OBJECT_ATTRIBUTES                             object_attributes;
       FILE_END_OF_FILE_INFORMATION       file_eof;
       FILE_BASIC_INFORMATION                   file_basic;
       FILE_STANDARD_INFORMATION             file_standard;
       FILE_ALIGNMENT_INFORMATION           file_alignment;
       PAGED_CODE();
       ASSERT(DeviceObject != NULL);
       ASSERT(Irp != NULL);
       device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
       open_file_information = (POPEN_FILE_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
       if (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
       {
               device_extension->read_only = open_file_information->ReadOnly;
       }
       device_extension->file_name.Length = open_file_information->FileNameLength;
       device_extension->file_name.MaximumLength = open_file_information->FileNameLength;
       device_extension->file_name.Buffer = ExAllocatePool(NonPagedPool, open_file_information->FileNameLength);
       RtlCopyMemory(
               device_extension->file_name.Buffer,
               open_file_information->FileName,
               open_file_information->FileNameLength
               );
       status = RtlAnsiStringToUnicodeSt ring(
               &ufile_name,
               &device_extension->file_name,
               TRUE
               );
       if (!NT_SUCCESS(status))
       {
               ExFreePool(device_extension->file_name.Buffer);
               Irp->IoStatus.Status = status;
               Irp->IoStatus.Information = 0;
               return status;
       }
       InitializeObjectAttribut es(
               &object_attributes,
               &ufile_name,
               OBJ_CASE_INSENSITIVE,
               NULL,
               NULL
               );
       status = ZwCreateFile(
               &device_extension->file_handle,
               device_extension->read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
               &object_attributes,
               &Irp->IoStatus,
               NULL,
               FILE_ATTRIBUTE_NORMAL,
               device_extension->read_only ? FILE_SHARE_READ : 0,
               FILE_OPEN,
               FILE_NON_DIRECTORY_FILE |
               FILE_RANDOM_ACCESS |
               FILE_NO_INTERMEDIATE_BUFFERING |
               FILE_SYNCHRONOUS_IO_NONALERT,
               NULL,
               0
               );
       if (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NO_SUCH_FILE)
       {
               if (device_extension->read_only || open_file_information->FileSize.QuadPart == 0)
               {
                       ExFreePool(device_extension->file_name.Buffer);
                       RtlFreeUnicodeString(&ufile_name);
                       Irp->IoStatus.Status = STATUS_NO_SUCH_FILE;
                       Irp->IoStatus.Information = 0;
                       return STATUS_NO_SUCH_FILE;
               }
               else
               {
                       status = ZwCreateFile(
                               &device_extension->file_handle,
                               GENERIC_READ | GENERIC_WRITE,
                               &object_attributes,
                               &Irp->IoStatus,
                               &open_file_information->FileSize,
                               FILE_ATTRIBUTE_NORMAL,
                               0,
                               FILE_OPEN_IF,
                               FILE_NON_DIRECTORY_FILE |
                               FILE_RANDOM_ACCESS |
                               FILE_NO_INTERMEDIATE_BUFFERING |
                               FILE_SYNCHRONOUS_IO_NONALERT,
                               NULL,
                               0
                               );
                       if (!NT_SUCCESS(status))
                       {
                               ExFreePool(device_extension->file_name.Buffer);
                               RtlFreeUnicodeString(&ufile_name);
                               return status;
                       }
                       if (Irp->IoStatus.Information == FILE_CREATED)
                       {
                               file_eof.EndOfFile.QuadPart = open_file_information->FileSize.QuadPart;
                               status = ZwSetInformationFile(
                                       device_extension->file_handle,
                                       &Irp->IoStatus,
                                       &file_eof,
                                       sizeof(FILE_END_OF_FILE_INFORMATION),
                                       FileEndOfFileInformation
                                       );
                               if (!NT_SUCCESS(status))
                               {
                                       ExFreePool(device_extension->file_name.Buffer);
                                       RtlFreeUnicodeString(&ufile_name);
                                       ZwClose(device_extension->file_handle);
                                       return status;
                               }
                       }
               }
       }
       else if (!NT_SUCCESS(status))
       {
               ExFreePool(device_extension->file_name.Buffer);
               RtlFreeUnicodeString(&ufile_name);
               return status;
       }
       RtlFreeUnicodeString(&ufile_name);
       status = ZwQueryInformationFile(
               device_extension->file_handle,
               &Irp->IoStatus,
               &file_basic,
               sizeof(FILE_BASIC_INFORMATION),
               FileBasicInformation
               );
       if (!NT_SUCCESS(status))
       {
               ExFreePool(device_extension->file_name.Buffer);
               ZwClose(device_extension->file_handle);
               return status;
       }
       status = ZwQueryInformationFile(
               device_extension->file_handle,
               &Irp->IoStatus,
               &file_standard,
               sizeof(FILE_STANDARD_INFORMATION),
               FileStandardInformation
               );
       if (!NT_SUCCESS(status))
       {
               ExFreePool(device_extension->file_name.Buffer);
               ZwClose(device_extension->file_handle);
               return status;
       }
       device_extension->file_size.QuadPart = file_standard.EndOfFile.QuadPart;
       status = ZwQueryInformationFile(
               device_extension->file_handle,
               &Irp->IoStatus,
               &file_alignment,
               sizeof(FILE_ALIGNMENT_INFORMATION),
               FileAlignmentInformation
               );
       if (!NT_SUCCESS(status))
       {
               ExFreePool(device_extension->file_name.Buffer);
               ZwClose(device_extension->file_handle);
               return status;
       }
       DeviceObject->AlignmentRequirement = file_alignment.AlignmentRequirement;
       if (device_extension->read_only)
       {
               DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
       }
       else
       {
               DeviceObject->Characteristics &= ~FILE_READ_ONLY_DEVICE;
       }
       device_extension->media_in_device = TRUE;
       Irp->IoStatus.Status = STATUS_SUCCESS;
       Irp->IoStatus.Information = 0;
       return STATUS_SUCCESS;
}
NTSTATUS
FileDiskCloseFile (
       IN PDEVICE_OBJECT     DeviceObject,
       IN PIRP                         Irp
       )
{
       PDEVICE_EXTENSION device_extension;
       PAGED_CODE();
       ASSERT(DeviceObject != NULL);
       ASSERT(Irp != NULL);
       device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
       ExFreePool(device_extension->file_name.Buffer);
       ZwClose(device_extension->file_handle);
       device_extension->media_in_device = FALSE;
       Irp->IoStatus.Status = STATUS_SUCCESS;
       Irp->IoStatus.Information = 0;
       return STATUS_SUCCESS;
}
NTSTATUS
FileDiskAdjustPrivilege (
       IN ULONG       Privilege,
       IN BOOLEAN   Enable
       )
{
       NTSTATUS                       status;
       HANDLE                           token_handle;
       TOKEN_PRIVILEGES       token_privileges;
       PAGED_CODE();
       status = ZwOpenProcessToken(
               NtCurrentProcess(),
               TOKEN_ALL_ACCESS,
               &token_handle
               );
       if (!NT_SUCCESS(status))
       {
               return status;
       }
       token_privileges.PrivilegeCount = 1;
       token_privileges.Privileges[0].Luid = RtlConvertUlongToLuid(Privilege);
       token_privileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
       //
       // Normaly one would use ZwAdjustPrivilegesToken but it is only available
       // on Windows 2000 and later versions, however since we are in a system
       // thread does ExGetPreviousMode always return KernelMode and therefore
       // can NtAdjustPrivilegesToken be used directly.
       //
       status = NtAdjustPrivilegesToken(
               token_handle,
               FALSE,
               &token_privileges,
               sizeof(token_privileges),
               NULL,
               NULL
               );
       ZwClose(token_handle);
       return status;
}

第一个问题就是设备是怎么通知线程去处理IRP请求的?
第二个问题是挂载出现一个磁盘是怎么实现的,原理是什么?

接下来的任务就是解决这二个问题,同时解决一些变量,和几个函数等相关细节问题,
以前一个朋友对我说过,一个人功底怎么样,要看细节。
转自看雪的CCDeath 【文章标题】: WinMount虚拟磁盘深入研究(-)之filedisk源代码详细分析 【下载地址】: 自己搜索下载 【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教! -------------------------------------------------------------------------------- 【详细过程】 我的驱动入门三终结版,还再学习中。由于个人也有些事情要处理,研究起刘涛涛WinMount的虚拟 磁盘,而且这方面的书籍,貌似乎没见过,只有傻傻的几K代码存在,没注释什么的,整体框架也没说。 虚拟光驱用实现文件来模拟磁盘的原理,是文件系统驱动程序。 把filedisk驱动安装,查看install.txt文件。 1.Copy the driver (filedisk.sys) to %systemroot%\system32\drivers\. 2.Import filedisk.reg to the Registry. 3.Reboot. 4.Use the program filedisk.exe to mount/umount files, for an example of use see the file example.txt. 可以不用重起机子的方法,找一个动载加载驱动工具:DriverMonitor不错了。然后在“开始菜单”-> "运行"输入 "net start filedisk" 出现:“ 请求的服务已经启动”。这个必须得成功才行哦。 接下来注意点。cmd后 出现这个目录 C:\Documents and Settings \Administrator>,在接下来敲入 filedisk /mount 0 c:\temp\filedisk.img 8M f: C:\Documents and Settings \Administrator>filedisk /mount 0 c:\temp\filedisk.img 8M r: 回车一下。 出现"FileDisk:系统找不到指定路径" 。原因就出在这 "c:\temp\filedisk.img" 中的C:\temp要这个目录才行。至于 filedisk.img不是必须,会自动创建。 如果有出现"FileDisk:函数不正确" 中的“filedisk /mount 0 ”中"0"代号已经被使用。可以改为"1". 查看一下,结果就出现一个还未格式化 8M R磁盘,查看C:\temp下生成一个filedisk.img也8M。想卸载 掉"filedisk /umount r:". 还可以创建很大的虚拟磁盘,你把"8M"改换其他的就是了。 以上如果都没出现结果,基本上就没兴趣继续研究下去了,我看到了很多人初学filedisk都遇到以上这 些问题(包括我在内) ,把我折腾了半天。 先来分析驱动层代码,后来分析应用层代码。更详细的请看附件里的源代码。我对代码工程方式重新布 局,用起来更方便。 ===================================//先来分析驱动层代码 1.对filedisk.h进行分析 #define FILE_DEVICE_FILE_DISK 0x8000//用户定义范围0x8000~ #define IOCTL_FILE_DISK_OPEN_FILE CTL_CODE(FILE_DEVICE_FILE_DISK, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_FILE_DISK_CLOSE_FILE CTL_CODE(FILE_DEVICE_FILE_DISK, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_FILE_DISK_QUERY_FILE CTL_CODE(FILE_DEVICE_FILE_DISK, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS) typedef struct _OPEN_FILE_INFORMATION { LARGE_INTEGER FileSize;//文件大小 BOOLEAN ReadOnly;//只读属性 USHORT Fil
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值