这是寒江独钓里面第5章的例子了, 分析自DDK中的RamDisk驱动. 具体来说没有太大的用处, 只是对WDF驱动的套路有个了解吧, 但是这个WDF到现在为止明显没有形成气候. 写个驱动出来, 安装都是很麻烦的事情, 哪里有NT式驱动舒服啊, 不过WDF确实是潮流, 这个也确实不能够忽略..
其实要说NT式驱动能够在浏览器上面显示一个磁盘的话, 这个用Nt式驱动来做也很简单, 前面几章也就做了一个模拟磁盘读写的驱动. 这个驱动的难点是建立一个文件系统, 文件系统的话是比较棘手的一个东西, 这个驱动用的是简单的AT12/16.. 所以写完感觉还是意犹未尽啊!寒江独钓也就一个WDF的例子, 所以我从网上去DOWN了一个NT式驱动的虚拟磁盘的源码, 这两天再分析分析..
都说了这个驱动的难点就是建立文件系统, 其他基本上也没有什么难点, 所以最主要是要搞定FAT16的文件系统. 这个网上大把资料. 搞成FAT32也不是问题. 所以基本上没有什么好说的, 代码注释非常齐全了.
这边是截图和代码:
这边是驱动的头文件:
Windows 内核下最简单的虚拟磁盘驱动, 将所有的读写请求转到内存中
|
WDF驱动, 修改自MicroSoft的例子. 这是头文件
|
编译方法参见就是普通的build就可以. TAB = 8
|
#pragma warning(disable:4201) // nameless struct/union warning
|
#pragma warning(default:4201)
|
#define NT_DEVICE_NAME L"\\Device\\Ramdisk"
|
#define DOS_DEVICE_NAME L"\\DosDevices\\"
|
#define RAMDISK_TAG 'DmaR' // "RamD"
|
#define DOS_DEVNAME_LENGTH (sizeof(DOS_DEVICE_NAME)+sizeof(WCHAR)*10)
|
#define DRIVE_LETTER_LENGTH (sizeof(WCHAR)*10)
|
#define DRIVE_LETTER_BUFFER_SIZE 10
|
#define DOS_DEVNAME_BUFFER_SIZE (sizeof(DOS_DEVICE_NAME) / 2) + 10
|
#define RAMDISK_MEDIA_TYPE 0xF8
|
#define DIR_ENTRIES_PER_SECTOR 16
|
// 这些都是默认参数, 只有在注册表中没有该项才启用, 但是安装文件已经设置了
|
#define DEFAULT_DISK_SIZE (1024*1024*512) // 默认的磁盘大小
|
#define DEFAULT_ROOT_DIR_ENTRIES 512 // 默认根目录入口
|
#define DEFAULT_SECTORS_PER_CLUSTER 2 // 默认柱面扇区数量
|
#define DEFAULT_DRIVE_LETTER L"Z:" // 默认盘符
|
//---------------------------------------------------------------------------
|
typedef struct _DISK_INFO {
|
ULONG DiskSize; // 磁盘的大小以Byte计算, 所以不能够超过4G
|
ULONG RootDirEntries; // 系统上根文件系统的进入点
|
ULONG SectorsPerCluster; // 磁盘的每个族由多少个扇区组成
|
UNICODE_STRING DriveLetter; // 磁盘的盘符
|
} DISK_INFO, *PDISK_INFO;
|
//---------------------------------------------------------------------------
|
typedef struct _DEVICE_EXTENSION {
|
PUCHAR DiskImage; // 指向一块内存区域, 作为内存盘的实际存储空间
|
DISK_GEOMETRY DiskGeometry; // 存储内存盘的物理信息, WinDDK提供
|
DISK_INFO DiskRegInfo; // 我们自己定义的磁盘信息结构, 在安装时存放在注册表中
|
UNICODE_STRING SymbolicLink; // 共享给用户态的符号链接名称
|
WCHAR DriveLetterBuffer[DRIVE_LETTER_BUFFER_SIZE]; //DiskRegInfo中的盘符的存储空间
|
WCHAR DosDeviceNameBuffer[DOS_DEVNAME_BUFFER_SIZE]; //符号连接名的存放空间
|
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME( DEVICE_EXTENSION, DeviceGetExtension )
|
typedef struct _QUEUE_EXTENSION {
|
PDEVICE_EXTENSION DeviceExtension;
|
} QUEUE_EXTENSION, *PQUEUE_EXTENSION;
|
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME( QUEUE_EXTENSION, QueueGetExtension )
|
typedef struct _BOOT_SECTOR {
|
UCHAR bsJump[3]; // 跳转指令, 跳到DBR中的引导程序
|
CCHAR bsOemName[8]; // 卷的OEM名称
|
USHORT bsBytesPerSec; // 每个扇区有多少个字节
|
UCHAR bsSecPerClus; // 每个族有多少个扇区
|
USHORT bsResSectors; // 保留扇区数目, 指的是第一个FAT
|
UCHAR bsFATs; // 这个卷有多少个FAT表
|
USHORT bsRootDirEnts; // 这个卷根入口点有几个
|
USHORT bsSectors; // 这个卷有多少个扇区, 对于大于65535个的扇区卷, 这个字段为0
|
UCHAR bsMedia; // 这个卷的介质类型 RAMDISK_MEDIA_TYPE
|
USHORT bsFATsecs; // 每个FAT表占用多少个扇区
|
USHORT bsSecPerTrack; // 每个磁道有多少个扇区, 我们使用32
|
USHORT bsHeads; // 有多少个磁头, 我们使用2
|
ULONG bsHiddenSecs; // 有多少个隐藏分区, 我们使用0
|
ULONG bsHugeSectors; // 一个卷如果超过65535扇区, 会使用这字段来说明总扇区数
|
UCHAR bsDriveNumber; // 驱动器编号, 未使用
|
UCHAR bsReserved1; // 保留字段
|
UCHAR bsBootSignature; // 磁盘扩展引导区标志, Windows规定必须为 0x29 或者0x28
|
ULONG bsVolumeID; // 磁盘卷ID - set to 0x12345678
|
CCHAR bsLabel[11]; // 磁盘卷标
|
CCHAR bsFileSystemType[8];// 文件系统类型 - FAT12 or FAT16
|
CCHAR bsReserved2[448]; // 保留
|
UCHAR bsSig2[2]; // DBR结束标记, 必须以0x55AA结束 - 0x55, 0xAA
|
} BOOT_SECTOR, *PBOOT_SECTOR;
|
//---------------------------------------------------------------------------
|
typedef struct _DIR_ENTRY {
|
UCHAR deExtension[3]; // 文件扩展名
|
UCHAR deAttributes; // 文件属性
|
UCHAR deReserved; // 系统保留
|
USHORT deStartCluster; // 文件第一个族的编号
|
ULONG deFileSize; // 文件大小
|
} DIR_ENTRY, *PDIR_ENTRY;
|
// Directory Entry Attributes
|
#define DIR_ATTR_READONLY 0x01
|
#define DIR_ATTR_HIDDEN 0x02
|
#define DIR_ATTR_SYSTEM 0x04
|
#define DIR_ATTR_VOLUME 0x08
|
#define DIR_ATTR_DIRECTORY 0x10
|
#define DIR_ATTR_ARCHIVE 0x20
|
DRIVER_INITIALIZE DriverEntry;
|
EVT_WDF_DRIVER_DEVICE_ADD RamDiskEvtDeviceAdd;
|
EVT_WDF_DEVICE_CONTEXT_CLEANUP RamDiskEvtDeviceContextCleanup;
|
EVT_WDF_IO_QUEUE_IO_READ RamDiskEvtIoRead;
|
EVT_WDF_IO_QUEUE_IO_WRITE RamDiskEvtIoWrite;
|
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL RamDiskEvtIoDeviceControl;
|
VOID RamDiskQueryDiskRegParameters( __in PWSTR RegistryPath, __in PDISK_INFO DiskRegInfo );
|
NTSTATUS RamDiskFormatDisk( IN PDEVICE_EXTENSION DeviceExtension );
|
BOOLEAN RamDiskCheckParameters( IN PDEVICE_EXTENSION devExt, IN LARGE_INTEGER ByteOffset, IN size_t Length );
|
这边是驱动的主文件:
Windows 内核下最简单的虚拟磁盘驱动, 将所有的读写请求转到内存中
|
WDF驱动, 修改自MicroSoft的例子. 这是驱动主文件
|
编译方法参见就是普通的build就可以. TAB = 8
|
#pragma alloc_text(INIT, DriverEntry)
|
#pragma alloc_text(PAGE, RamDiskEvtDeviceAdd)
|
#pragma alloc_text(PAGE, RamDiskEvtDeviceContextCleanup)
|
#pragma alloc_text(PAGE, RamDiskQueryDiskRegParameters)
|
#pragma alloc_text(PAGE, RamDiskFormatDisk)
|
//===========================================================================
|
//===========================================================================
|
NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ) {
|
WDF_DRIVER_CONFIG config;
|
KdPrint( ( "Windows Ramdisk Driver - 简单的磁盘过滤框架, 是微软写得.\n" ) );
|
KdPrint( ( "Built %s %s\n", __DATE__, __TIME__ ) );
|
//这边设置了AddDevice函数的地址, 由Pnp调用, 连卸载例程都没有
|
WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd );
|
return WdfDriverCreate( DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
|
&config, WDF_NO_HANDLE );
|
//===========================================================================
|
// 设备读取请求, 类型NT式驱动的IRP_MJ_READ
|
//===========================================================================
|
VOID RamDiskEvtIoRead( WDFQUEUE Queue, WDFREQUEST Request, size_t Length ) {
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
WDF_REQUEST_PARAMETERS Parameters;
|
LARGE_INTEGER ByteOffset;
|
// 从队列扩展中获取设备扩展, 初始化时我们已经关联了设备扩展
|
PDEVICE_EXTENSION devExt = QueueGetExtension( Queue )->DeviceExtension;
|
WDF_REQUEST_PARAMETERS_INIT( &Parameters );
|
// 从请求中获取参数信息, 和IoGetCurrentIrpStackLocation形成对比
|
WdfRequestGetParameters( Request, &Parameters );
|
ByteOffset.QuadPart = Parameters.Parameters.Read.DeviceOffset;
|
//这里自己实现了一个参数检测函数, 由于读取的范围不能够超过磁盘镜像
|
//的大小, 并且必须以扇区对齐, 所以这里需要检测参数. 如果检测失败, 返回错误
|
if ( RamDiskCheckParameters( devExt, ByteOffset, Length ) ) {
|
Status = WdfRequestRetrieveOutputMemory( Request, &hMemory );
|
if( NT_SUCCESS( Status ) ) {
|
// 根据之前获取到的读参数进行内存Copy, 填写这个缓冲区完成读取请求
|
Status = WdfMemoryCopyFromBuffer( hMemory, 0,
|
devExt->DiskImage + ByteOffset.LowPart, Length );
|
KdPrint(( "读取请求来了一次 ByteOffset:%p Length:%d\n",(ULONG)ByteOffset.QuadPart, Length ));
|
// 类似于这号函数IoCompleteRequest
|
WdfRequestCompleteWithInformation( Request, Status, ( ULONG_PTR )Length );
|
//===========================================================================
|
// 设备写入请求, 类型NT式驱动的IRP_MJ_WRITE
|
//===========================================================================
|
VOID RamDiskEvtIoWrite( WDFQUEUE Queue, WDFREQUEST Request, size_t Length ) {
|
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
WDF_REQUEST_PARAMETERS Parameters;
|
LARGE_INTEGER ByteOffset;
|
PDEVICE_EXTENSION devExt = QueueGetExtension( Queue )->DeviceExtension;
|
WDF_REQUEST_PARAMETERS_INIT( &Parameters );
|
// 从请求中获取参数信息, 和IoGetCurrentIrpStackLocation形成对比
|
WdfRequestGetParameters( Request, &Parameters );
|
ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset;
|
if ( RamDiskCheckParameters( devExt, ByteOffset, Length ) ) {
|
Status = WdfRequestRetrieveInputMemory( Request, &hMemory );
|
if( NT_SUCCESS( Status ) ) {
|
Status = WdfMemoryCopyToBuffer( hMemory, 0,
|
devExt->DiskImage + ByteOffset.LowPart, Length );
|
KdPrint(( "写入请求来了一次 ByteOffset:%p Length:%d\n",(ULONG)ByteOffset.QuadPart, Length ));
|
// 类似于这号函数IoCompleteRequest
|
WdfRequestCompleteWithInformation( Request, Status, ( ULONG_PTR )Length );
|
//===========================================================================
|
// 设备控制请求, 类似NT式驱动的IRP_MJ_DEVICE_CONTROL
|
//===========================================================================
|
VOID RamDiskEvtIoDeviceControl( WDFQUEUE Queue, WDFREQUEST Request, size_t OutputBufferLength,
|
size_t InputBufferLength, ULONG IoControlCode ) {
|
ULONG_PTR information = 0;
|
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
|
PDEVICE_EXTENSION devExt = QueueGetExtension( Queue )->DeviceExtension;
|
UNREFERENCED_PARAMETER( OutputBufferLength );
|
UNREFERENCED_PARAMETER( InputBufferLength );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
switch ( IoControlCode ) {
|
// 获取当前分区信息的的DeviceIoControl请求, 要处理
|
case IOCTL_DISK_GET_PARTITION_INFO: {
|
PPARTITION_INFORMATION outputBuffer;
|
// 完成这个请求大部分数据来自于DBR, 所以这里获取指向DBR的指针
|
PBOOT_SECTOR bootSector = ( PBOOT_SECTOR ) devExt->DiskImage;
|
information = sizeof( PARTITION_INFORMATION );
|
// 通过框架函数来获取这个DeviceIoControl请求所携带的缓冲区
|
Status = WdfRequestRetrieveOutputBuffer( Request, sizeof( PARTITION_INFORMATION ), &outputBuffer, &bufSize );
|
if( NT_SUCCESS( Status ) ) {
|
outputBuffer->PartitionType = ( bootSector->bsFileSystemType[4] == '6' ) ?
|
PARTITION_FAT_16 : PARTITION_FAT_12;
|
// BootIndicator为TRUE表示可引导的
|
outputBuffer->BootIndicator = FALSE;
|
// 为TRUE时,系统识别的分区类型,如果为FALSE,系统没有识别的分区类型
|
outputBuffer->RecognizedPartition = TRUE;
|
// 为TRUE时, 分区信息已经改变,如果为FALSE,分区信息并没有改变
|
outputBuffer->RewritePartition = FALSE;
|
outputBuffer->StartingOffset.QuadPart = 0;
|
outputBuffer->PartitionLength.QuadPart = devExt->DiskRegInfo.DiskSize;
|
outputBuffer->HiddenSectors = ( ULONG ) ( 1L );
|
outputBuffer->PartitionNumber = ( ULONG ) ( -1L );
|
KdPrint( ( "获取当前分区信息成功!\n" ) );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
|
PDISK_GEOMETRY outputBuffer;
|
information = sizeof( DISK_GEOMETRY );
|
// 通过框架函数来获取这个DeviceIoControl请求所携带的的输出缓冲区
|
Status = WdfRequestRetrieveOutputBuffer( Request, sizeof( DISK_GEOMETRY ), &outputBuffer, &bufSize );
|
if( NT_SUCCESS( Status ) ) {
|
RtlCopyMemory( outputBuffer, &( devExt->DiskGeometry ), sizeof( DISK_GEOMETRY ) );
|
KdPrint( ( "获取硬盘的物理参数成功!\n" ) );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
case IOCTL_DISK_CHECK_VERIFY:
|
KdPrint( ( "磁盘校验, 直接返回成功!\n" ) );
|
case IOCTL_DISK_IS_WRITABLE:
|
KdPrint( ( "确定磁盘是否可写, 返回True, 直接成功!\n" ) );
|
// 类似于这号函数IoCompleteRequest
|
WdfRequestCompleteWithInformation( Request, Status, information );
|
//===========================================================================
|
//===========================================================================
|
VOID RamDiskEvtDeviceContextCleanup( IN WDFDEVICE Device ) {
|
PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension( Device );
|
if( pDeviceExtension->DiskImage ) {
|
ExFreePool( pDeviceExtension->DiskImage );
|
KdPrint( ( "设备清除函数被调用一次, 释放了申请的物理内存" ) );
|
//===========================================================================
|
// 类似WDM的AddDevice函数, 由Pnp管理器调用
|
//DeviceInit :这个参数是WDF驱动模型自动分配出来的一个数据结构, 用于建立新设别
|
//===========================================================================
|
NTSTATUS RamDiskEvtDeviceAdd( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit ) {
|
PQUEUE_EXTENSION pQueueContext = NULL;
|
PDEVICE_EXTENSION pDeviceExtension;
|
WDF_OBJECT_ATTRIBUTES deviceAttributes;
|
WDF_OBJECT_ATTRIBUTES queueAttributes;
|
WDF_IO_QUEUE_CONFIG ioQueueConfig;
|
DECLARE_CONST_UNICODE_STRING( ntDeviceName, NT_DEVICE_NAME );
|
UNREFERENCED_PARAMETER( Driver );
|
KdPrint( ( "RamDiskEvtDeviceAdd被调用!\n" ) );
|
Status = WdfDeviceInitAssignName( DeviceInit, &ntDeviceName );
|
if ( !NT_SUCCESS( Status ) ) {
|
WdfDeviceInitSetDeviceType( DeviceInit, FILE_DEVICE_DISK );
|
WdfDeviceInitSetIoType( DeviceInit, WdfDeviceIoDirect );
|
WdfDeviceInitSetExclusive( DeviceInit, FALSE );
|
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &deviceAttributes, DEVICE_EXTENSION );
|
//指定清除回调函数, 基本上就类似于NT驱动的IRP_MJ_CLOSE
|
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;
|
Status = WdfDeviceCreate( &DeviceInit, &deviceAttributes, &device );
|
if ( !NT_SUCCESS( Status ) ) {
|
pDeviceExtension = DeviceGetExtension( device );
|
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE ( &ioQueueConfig, WdfIoQueueDispatchSequential );
|
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
|
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead;
|
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite;
|
//指定队列的扩展属性, 注意要和前面的设备扩展区分开来
|
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &queueAttributes, QUEUE_EXTENSION );
|
//到这里属性就配置的差不多了, 可以创建队列了将之前我们创建的设备作为
|
//这个队列的父对象, 这样在设备被销毁的时候这个队列也会被销毁
|
Status = WdfIoQueueCreate( device, &ioQueueConfig, &queueAttributes, &queue );
|
if ( !NT_SUCCESS( Status ) ) {
|
pQueueContext = QueueGetExtension( queue );
|
//初始化队列扩展里的DeviceExtension项, 并将其设置为刚建立的设备
|
//的设备扩展, 这样以后就可以方便的通过队列扩展找到设备扩展了
|
pQueueContext->DeviceExtension = pDeviceExtension;
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
pDeviceExtension->DiskRegInfo.DriveLetter.Buffer = ( PWSTR ) &pDeviceExtension->DriveLetterBuffer;
|
pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength = sizeof( pDeviceExtension->DriveLetterBuffer );
|
// WdfDeviceGetDriver :从设备中获取这个设备对应的驱动对象
|
// WdfDriverGetRegistryPath :获取驱动对象对应的注册表项目
|
RamDiskQueryDiskRegParameters( WdfDriverGetRegistryPath( WdfDeviceGetDriver( device ) ),
|
&pDeviceExtension->DiskRegInfo );
|
//---------------------------------------------------------------------------
|
// 分配等同磁盘大小的内存, 这边用非分页内存, 有点浪费啊
|
// 可以看出来, 微软的人写的代码也很一般, 这边内存分配失败, 还是会返回
|
// 正确, 我倒, 什么工作都没有做, 原来他们说的敲例子的人都是二等开发人员
|
pDeviceExtension->DiskImage = ExAllocatePoolWithTag( NonPagedPool,
|
pDeviceExtension->DiskRegInfo.DiskSize, RAMDISK_TAG );
|
if ( pDeviceExtension->DiskImage ) {
|
UNICODE_STRING deviceName;
|
UNICODE_STRING win32Name;
|
RamDiskFormatDisk( pDeviceExtension );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
// 初始化一个内容为"\\DosDevice\\"的Unicode变量
|
RtlInitUnicodeString( &win32Name, DOS_DEVICE_NAME );
|
// 初始化一个内容为"\\Device\\Ramdisk\\"的Unicode变量
|
RtlInitUnicodeString( &deviceName, NT_DEVICE_NAME );
|
pDeviceExtension->SymbolicLink.Buffer = ( PWSTR ) &pDeviceExtension->DosDeviceNameBuffer;
|
pDeviceExtension->SymbolicLink.MaximumLength = sizeof( pDeviceExtension->DosDeviceNameBuffer );
|
pDeviceExtension->SymbolicLink.Length = win32Name.Length;
|
// 到这里符号连接名是"\\DosDevices\\"
|
RtlCopyUnicodeString( &pDeviceExtension->SymbolicLink, &win32Name );
|
// 在上面的基础之上,读取出来我们设置的盘符 "\\DosDevice\\Z:\"
|
RtlAppendUnicodeStringToString( &pDeviceExtension->SymbolicLink,
|
&pDeviceExtension->DiskRegInfo.DriveLetter );
|
Status = WdfDeviceCreateSymbolicLink( device, &pDeviceExtension->SymbolicLink );
|
//===========================================================================
|
//RegistryPath :欲读取的注册表路径
|
//DiskRegInfo :存放结果信息的结构体指针
|
//===========================================================================
|
VOID RamDiskQueryDiskRegParameters( __in PWSTR RegistryPath, __in PDISK_INFO DiskRegInfo ) {
|
DISK_INFO defDiskRegInfo;
|
RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[5 + 1]; //需要一个后面为NULL
|
//---------------------------------------------------------------------------
|
ASSERT( RegistryPath != NULL );
|
defDiskRegInfo.DiskSize = DEFAULT_DISK_SIZE;
|
defDiskRegInfo.RootDirEntries = DEFAULT_ROOT_DIR_ENTRIES;
|
defDiskRegInfo.SectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;
|
RtlInitUnicodeString( &defDiskRegInfo.DriveLetter, DEFAULT_DRIVE_LETTER );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
RtlZeroMemory( rtlQueryRegTbl, sizeof( rtlQueryRegTbl ) );
|
rtlQueryRegTbl[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
rtlQueryRegTbl[0].Name = L"Parameters";
|
rtlQueryRegTbl[0].EntryContext = NULL;
|
rtlQueryRegTbl[0].DefaultType = ( ULONG_PTR )NULL;
|
rtlQueryRegTbl[0].DefaultData = NULL;
|
rtlQueryRegTbl[0].DefaultLength = ( ULONG_PTR )NULL;
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
rtlQueryRegTbl[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
rtlQueryRegTbl[1].Name = L"DiskSize";
|
rtlQueryRegTbl[1].EntryContext = &DiskRegInfo->DiskSize;
|
rtlQueryRegTbl[1].DefaultType = REG_DWORD;
|
rtlQueryRegTbl[1].DefaultData = &defDiskRegInfo.DiskSize;
|
rtlQueryRegTbl[1].DefaultLength = sizeof( ULONG );
|
rtlQueryRegTbl[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
rtlQueryRegTbl[2].Name = L"RootDirEntries";
|
rtlQueryRegTbl[2].EntryContext = &DiskRegInfo->RootDirEntries;
|
rtlQueryRegTbl[2].DefaultType = REG_DWORD;
|
rtlQueryRegTbl[2].DefaultData = &defDiskRegInfo.RootDirEntries;
|
rtlQueryRegTbl[2].DefaultLength = sizeof( ULONG );
|
rtlQueryRegTbl[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
rtlQueryRegTbl[3].Name = L"SectorsPerCluster";
|
rtlQueryRegTbl[3].EntryContext = &DiskRegInfo->SectorsPerCluster;
|
rtlQueryRegTbl[3].DefaultType = REG_DWORD;
|
rtlQueryRegTbl[3].DefaultData = &defDiskRegInfo.SectorsPerCluster;
|
rtlQueryRegTbl[3].DefaultLength = sizeof( ULONG );
|
rtlQueryRegTbl[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
rtlQueryRegTbl[4].Name = L"DriveLetter";
|
rtlQueryRegTbl[4].EntryContext = &DiskRegInfo->DriveLetter;
|
rtlQueryRegTbl[4].DefaultType = REG_SZ;
|
rtlQueryRegTbl[4].DefaultData = defDiskRegInfo.DriveLetter.Buffer;
|
rtlQueryRegTbl[4].DefaultLength = 0;
|
Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, RegistryPath,
|
rtlQueryRegTbl, NULL, NULL );
|
if ( NT_SUCCESS( Status ) == FALSE ) {
|
DiskRegInfo->DiskSize = defDiskRegInfo.DiskSize;
|
DiskRegInfo->RootDirEntries = defDiskRegInfo.RootDirEntries;
|
DiskRegInfo->SectorsPerCluster = defDiskRegInfo.SectorsPerCluster;
|
RtlCopyUnicodeString( &DiskRegInfo->DriveLetter, &defDiskRegInfo.DriveLetter );
|
//---------------------------------------------------------------------------
|
KdPrint( ( "在注册表中获取磁盘信息!\n" ) );
|
KdPrint( ( "磁盘大小 = 0x%lx\n", DiskRegInfo->DiskSize ) );
|
KdPrint( ( "根目录入口 = 0x%lx\n", DiskRegInfo->RootDirEntries ) );
|
KdPrint( ( "族扇区数 = 0x%lx\n", DiskRegInfo->SectorsPerCluster ) );
|
KdPrint( ( "驱动器盘符 = %wZ\n", &( DiskRegInfo->DriveLetter ) ) );
|
//===========================================================================
|
//===========================================================================
|
NTSTATUS RamDiskFormatDisk( IN PDEVICE_EXTENSION devExt ) {
|
PUCHAR firstFatSector; // 指向第一个FAT表的指针
|
ULONG rootDirEntries; // 记录有多少根目录入口点
|
ULONG sectorsPerCluster; // 每个族有多少个扇区构成
|
USHORT fatType; // 记录FAT文件系统类型, FAT12/16
|
USHORT fatEntries; // 记录FAT表里面有多少个表项
|
USHORT fatSectorCnt; // 用于记录一个FAT表项需要占用多少个扇区
|
PDIR_ENTRY rootDir; // 根目录入口点
|
// 启动扇区指针, 也就是存放的申请的内存首地址
|
PBOOT_SECTOR bootSector = ( PBOOT_SECTOR ) devExt->DiskImage;
|
//---------------------------------------------------------------------------
|
// 确定这个盘的引导扇区是512字节, 然后清空内存
|
ASSERT( sizeof( BOOT_SECTOR ) == 512 );
|
ASSERT( devExt->DiskImage != NULL );
|
RtlZeroMemory( devExt->DiskImage, devExt->DiskRegInfo.DiskSize );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
devExt->DiskGeometry.BytesPerSector = 512;
|
devExt->DiskGeometry.SectorsPerTrack = 32;
|
devExt->DiskGeometry.TracksPerCylinder = 2;
|
devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2;
|
// 磁盘的类型就是我们自己定义的 RAMDISK_MEDIA_TYPE
|
devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE;
|
KdPrint( ( "柱面数: %ld\n 柱面磁道数: %ld\n 磁道扇区数: %ld\n 扇区字节数: %ld\n",
|
devExt->DiskGeometry.Cylinders.QuadPart,
|
devExt->DiskGeometry.TracksPerCylinder,
|
devExt->DiskGeometry.SectorsPerTrack,
|
devExt->DiskGeometry.BytesPerSector ) );
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
rootDirEntries = devExt->DiskRegInfo.RootDirEntries;
|
// 根据用户指定值对每个族有多少个扇区进行初始化
|
sectorsPerCluster = devExt->DiskRegInfo.SectorsPerCluster;
|
// 由于根目录入口点只使用32字节, 但是最少占用一个扇区,
|
// 这里为了充分利用空间, 在用户指定数目不合适时, 会修正这个数目
|
if ( rootDirEntries & ( DIR_ENTRIES_PER_SECTOR - 1 ) ) {
|
rootDirEntries = ( rootDirEntries + ( DIR_ENTRIES_PER_SECTOR - 1 ) ) &
|
~( DIR_ENTRIES_PER_SECTOR - 1 );
|
KdPrint( ( "根目录入口: %ld\n 族扇区数: %ld\n",
|
rootDirEntries, sectorsPerCluster ) );
|
//---------------------------------------------------------------------------
|
// 我们这个磁盘不含有MBR, 直接就是从DBR开始
|
//---------------------------------------------------------------------------
|
// 这里必须使用0xEB和0x90, 这是文件系统的检查标记
|
bootSector->bsJump[0] = 0xeb;
|
bootSector->bsJump[1] = 0x3c;
|
bootSector->bsJump[2] = 0x90;
|
// 填写OEM名称成员, 这里当然是写 JoenRam了, 刚好8个
|
bootSector->bsOemName[0] = 'J';
|
bootSector->bsOemName[1] = 'o';
|
bootSector->bsOemName[2] = 'e';
|
bootSector->bsOemName[3] = 'n';
|
bootSector->bsOemName[4] = 'R';
|
bootSector->bsOemName[5] = 'a';
|
bootSector->bsOemName[6] = 'm';
|
bootSector->bsOemName[7] = ' ';
|
//每个扇区有多少个字节, 这个成员直接取之前初始化磁盘的信息结构
|
bootSector->bsBytesPerSec = ( SHORT )devExt->DiskGeometry.BytesPerSector;
|
bootSector->bsResSectors = 1;
|
// 和正常的卷不同, 为了节省空间, 我们只存放一份FAT表, 而不是通常的两份
|
bootSector->bsRootDirEnts = ( USHORT )rootDirEntries;
|
// 这个磁盘的总扇区数由磁盘总大小和每个扇区的字节数计算得到 磁盘大小/扇区字节
|
bootSector->bsSectors = ( USHORT )( devExt->DiskRegInfo.DiskSize / devExt->DiskGeometry.BytesPerSector );
|
bootSector->bsMedia = ( UCHAR )devExt->DiskGeometry.MediaType;
|
bootSector->bsSecPerClus = ( UCHAR )sectorsPerCluster;
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
// FAT表的表项数目是由总扇区数减去保留的扇区数, 再减去根目录入口点所占用
|
// 的扇区数, 然后除以每族的扇区数, 罪的结果需要+2, 因为FAT第0项, 第1项是保留的
|
fatEntries = ( bootSector->bsSectors - bootSector->bsResSectors - bootSector->bsRootDirEnts /
|
DIR_ENTRIES_PER_SECTOR ) / bootSector->bsSecPerClus + 2;
|
// 上面已经计算出了FAT表的表项数量, 根据这个表项数量首先可以决定到底是用FAT12还是FAT16
|
// 文件系统, 决定了文件系统就可以计算出每个FAT表的表项需要占用多少空间, 进而计算出整个FAT
|
if ( fatEntries > 4087 ) {
|
fatSectorCnt = ( fatEntries * 2 + 511 ) / 512; //一个表项需要占用多少个扇区
|
fatEntries = fatEntries + fatSectorCnt; //记FAT表里面有多少个表项
|
fatSectorCnt = ( fatEntries * 2 + 511 ) / 512; //一个FAT表项需要占用多少个扇区
|
fatSectorCnt = ( ( ( fatEntries * 3 + 1 ) / 2 ) + 511 ) / 512;
|
fatEntries = fatEntries + fatSectorCnt;
|
fatSectorCnt = ( ( ( fatEntries * 3 + 1 ) / 2 ) + 511 ) / 512;
|
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
bootSector->bsFATsecs = fatSectorCnt;
|
bootSector->bsSecPerTrack = ( USHORT )devExt->DiskGeometry.SectorsPerTrack;
|
bootSector->bsHeads = ( USHORT )devExt->DiskGeometry.TracksPerCylinder;
|
// 初始化启动签名, Windows要求必须是0x28 或者0x29
|
bootSector->bsBootSignature = 0x29;
|
bootSector->bsVolumeID = 0x12345678;
|
bootSector->bsLabel[0] = 'J';
|
bootSector->bsLabel[1] = 'o';
|
bootSector->bsLabel[2] = 'e';
|
bootSector->bsLabel[3] = 'n';
|
bootSector->bsLabel[4] = 'D';
|
bootSector->bsLabel[5] = 'i';
|
bootSector->bsLabel[6] = 's';
|
bootSector->bsLabel[7] = 'k';
|
bootSector->bsLabel[8] = ' ';
|
bootSector->bsLabel[9] = ' ';
|
bootSector->bsLabel[10] = ' ';
|
bootSector->bsFileSystemType[0] = 'F';
|
bootSector->bsFileSystemType[1] = 'A';
|
bootSector->bsFileSystemType[2] = 'T';
|
bootSector->bsFileSystemType[3] = '1';
|
bootSector->bsFileSystemType[4] = '?';
|
bootSector->bsFileSystemType[5] = ' ';
|
bootSector->bsFileSystemType[6] = ' ';
|
bootSector->bsFileSystemType[7] = ' ';
|
bootSector->bsFileSystemType[4] = ( fatType == 16 ) ? '6' : '2';
|
bootSector->bsSig2[0] = 0x55;
|
bootSector->bsSig2[1] = 0xAA;
|
//---------------------------------------------------------------------------
|
//上面总算把这个DBR给初始化完了, 接下来需要初始化FAT表
|
//---------------------------------------------------------------------------
|
// 定位到FAT表的起始点, 这里的定位方式是利用了DBR治愈一个扇区这个条件
|
firstFatSector = ( PUCHAR )( bootSector + 1 );
|
firstFatSector[0] = ( UCHAR )devExt->DiskGeometry.MediaType;
|
firstFatSector[1] = 0xFF;
|
firstFatSector[2] = 0xFF;
|
firstFatSector[3] = 0xFF;
|
//---------------------------------------------------------------------------
|
//初始化根目录, 在FAT12/16文件系统中, 通常第一个根目录入口点存储了最终
|
//---------------------------------------------------------------------------
|
// 由于紧跟着FAT表, 所以根目录入口点的表起始位置很好找的
|
rootDir = ( PDIR_ENTRY )( bootSector + 1 + fatSectorCnt );
|
rootDir->deName[0] = 'J';
|
rootDir->deName[1] = 'o';
|
rootDir->deName[2] = 'e';
|
rootDir->deName[3] = 'n';
|
rootDir->deName[4] = 'C';
|
rootDir->deName[5] = 'h';
|
rootDir->deName[6] = 'e';
|
rootDir->deName[7] = 'n';
|
rootDir->deExtension[0] = ' ';
|
rootDir->deExtension[1] = ' ';
|
rootDir->deExtension[2] = ' ';
|
rootDir->deAttributes = DIR_ATTR_VOLUME;
|
KdPrint( ( "格式化磁盘成功!\n" ) );
|
//===========================================================================
|
//===========================================================================
|
BOOLEAN RamDiskCheckParameters( PDEVICE_EXTENSION devExt, LARGE_INTEGER ByteOffset, size_t Length ) {
|
// 读取参数检测, 如果磁盘的大小小于读取的长度, 或者偏移小于0,
|
// 或者偏移大于磁盘大小+读取的长度, 获取长度有没有按照扇区对齐
|
if( devExt->DiskRegInfo.DiskSize < Length || ByteOffset.QuadPart < 0 ||
|
( ( ULONGLONG )ByteOffset.QuadPart > ( devExt->DiskRegInfo.DiskSize - Length ) ) ||
|
( Length & ( devExt->DiskGeometry.BytesPerSector - 1 ) ) ) {
|
KdPrint( ( "参数错误\nByteOffset: %x\n Length: %d\n", ByteOffset, Length ) );
|
文章发表于 2011-11-30 05:16:39,
阅读(2818) | 评论(0) | 转发(0) |