总版主
|
阅读:2828回复:4
Windows文件系统过滤驱动开发教程(3)
Windows文件系统过滤驱动开发教程
3.分发例程,fast io 上一节仅仅生成了控制设备对象。但是不要忘记,驱动开发的主要工作是撰写分发例程(dispatch functions.).接上一接,我们已经知道自己的DriverObject保存在上文代码的driver中。现在我写如下一个函数来指定一个默认的dispatch function给它。 //-----------------wdf.h中的代码---------------------- typedef PDRIVER_DISPATCH wd_disp_fuc; _inline wd_void wd_drv_set_dispatch(in wd_drv* driver, in wd_disp_fuc disp) { wd_size i; for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) driver->MajorFunction = disp; } 在前边的wd_main中,我只要加 wd_drv_set_dispatch(driver,my_dispatch_func); 就为这个驱动指定了一个默认的Dispatch Function.所有的irp请求,都会被发送到这个函数。但是,我可能不希望这个函数处理过于复杂,而希望把一些常见的请求独立出来,如Read,Write,Create,Close,那我又写了几个函数专门用来设置这几个Dispatch Functions. //-----------------wdf.h中的代码---------------------- _inline wd_void wd_drv_set_read( in wd_drv* driver, in wd_disp_fuc read) { driver->MajorFunction[IRP_MJ_READ] = read; } _inline wd_void wd_drv_set_write( in wd_drv* driver, in wd_disp_fuc write) { driver->MajorFunction[IRP_MJ_WRITE] = write; } wd_void wd_drv_set_create(in wd_drv* driver, in wd_disp_fuc create) { driver->MajorFunction[IRP_MJ_CREATE] = create; driver->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = create; driver->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = create; } wd_void wd_drv_set_file_sys_control(in wd_drv* driver, in wd_disp_fuc control) { driver->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = control; } wd_void wd_drv_set_clean_up(in wd_drv* driver, in wd_disp_fuc clean_up) { driver->MajorFunction[IRP_MJ_CLEANUP] = clean_up; } wd_void wd_drv_set_close(in wd_drv* driver, in wd_disp_fuc close) { driver->MajorFunction[IRP_MJ_CLOSE] = close; } 别看我罗列n多代码,其实就是在设置driver->MajorFunction这个数组而已。因此在wd_main对dispatch functions的设置,就变成了下边这样的: // 开始设置几个分发例程 wd_drv_set_dispatch(driver,my_disp_default); wd_drv_set_create(driver,my_disp_create); wd_drv_set_clean_up(driver,my_disp_clean_up); wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl); wd_drv_set_close(driver,my_disp_close); wd_drv_set_read(driver,my_disp_read); wd_drv_set_write(driver,my_disp_write); 下面的任务都在写my_xxx系列的这些函数了。但是对于这个DriverObject的设置,还并不是仅仅这么简单。 由于你的驱动将要绑定到文件系统驱动的上边,文件系统除了处理正常的IRP之外,还要处理所谓的FastIo.FastIo是Cache Manager调用所引发的一种没有irp的请求。换句话说,除了正常的Dispatch Functions之外,你还得为DriverObject撰写另一组Fast Io Functions.这组函数的指针在driver->FastIoDispatch.我不知道这个指针留空会不会导致系统崩溃。在这里本来是没有空间的,所以为了保存这一组指针,你必须自己分配空间。 下面是我常用的内存分配函数。 //-----------------wdf.h中的代码---------------------- // 最简单的分配内存的函数,可以指定分页非分页 _inline wd_pvoid wd_malloc(wd_bool paged,wd_size size) { if(paged) return ExAllocatePool(PagedPool,size); else return ExAllocatePool(NonPagedPool,size); } // 释放内存 _inline wd_void wd_free(wd_pvoid point) { ExFreePool(point); } _inline wd_void wd_memzero( wd_pvoid point, wd_size size) { RtlZeroMemory(point,size); } 有了上边的基础,我就可以自己写一个初始化FastIoDispatch指针的函数。 //-----------------wdf.h中的代码---------------------- wd_bool wd_fio_disp_init(wd_drv *driver,wd_ulong size) { wd_fio_disp *disp = wd_malloc(wd_false,size); if(disp == wd_null) return wd_false; wd_memzero((wd_pvoid)disp,size); driver->FastIoDispatch = disp; driver->FastIoDispatch->SizeOfFastIoDispatch = size; return wd_true; } 这个函数为FastIoDispacth指针分配足够的空间并填写它的大小。下面是再写一系列的函数来设置这个函数指针数组。实际上,FastIo接口函数实在太多了,所以我仅仅写出这些设置函数的几个作为例子: //-----------------wdf.h中的代码---------------------- _inline wd_void wd_fio_disp_set_query_standard( wd_drv *driver, wd_fio_query_standard_func func) { driver->FastIoDispatch->FastIoQueryStandardInfo = func; } _inline wd_void wd_fio_disp_set_io_lock( wd_drv *driver, wd_fio_io_lock_func func) { driver->FastIoDispatch->FastIoLock = func; } _inline wd_void wd_fio_disp_set_io_unlock_s( wd_drv *driver, wd_fio_unlock_single_func func) { driver->FastIoDispatch->FastIoUnlockSingle = func; } ... 好,如果你坚持读到了这里,应该表示祝贺了。我们回顾一下,wd_main中,应该做哪些工作。 a.生成一个控制设备。当然此前你必须给控制设置指定名称。 b.设置Dispatch Functions. c.设置Fast Io Functions. // ----------------wd_main 的近况---------------------------- ... wd_dev *g_cdo = NULL; wd_stat wd_main(in wd_drv* driver, in wd_ustr* reg_path) { wd_ustr name; wd_stat status = wd_stat_suc; // 然后我生成控制设备,虽然现在我的控制设备什么都不干 wd_ustr_init(&name,L\"\\FileSystem\\Filters\\our_fs_filters\"); status = wdff_cdo_create(driver,0,&name,&g_cdo); if(!wd_suc(status)) { if(status == wd_stat_path_not_found) { // 这种情况发生于FileSystemFilters路径不存在。这个路径是 // 在xp上才加上的。所以2000下可能会运行到这里 wd_ustr_init(&name,L\"\\FileSystem\\our_fs_filters\"); status = wdff_cdo_create(driver,0,&name,&g_cdo); }; if(!wd_suc(status)) { wd_printf0(\"error: create cdo failed.rn\"); return status; } } wd_printf0(\"success: create cdo ok.rn\"); // 开始设置几个分发例程 wd_drv_set_dispatch(driver,my_disp_default); wd_drv_set_create(driver,my_disp_create); wd_drv_set_clean_up(driver,my_disp_clean_up); wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl); wd_drv_set_close(driver,my_disp_close); wd_drv_set_read(driver,my_disp_read); wd_drv_set_write(driver,my_disp_write); // 指定fast io处理函数 if(!wd_fio_disp_init(driver,sizeof(wd_fio_disp))) { wd_dev_del(g_cdo); wd_printf0(\"error: fast io disp init failed.rn\"); return wd_stat_insufficient_res; } // 下面指定的这些函数都定义在wdf_filter_fio.h中,其实这些函数都统 // 一的返回了false wd_fio_disp_set_check( driver, my_fio_check); wd_fio_disp_set_read( driver, my_fio_read); wd_fio_disp_set_write( driver, my_fio_write); wd_fio_disp_set_query_basic( driver, my_fio_query_basic_info); ... } FastIo函数个数数量不明,我只觉得很多。因此不打算全部罗列,以\"...\"敷衍之。某些读者可能会认为这些代码无法调试安装。其实您可以参考sfilter中的示例自己完成这些代码。 现在我们的my_xxx系列的函数还没有开始写,因此驱动也不能编译通过。在后边的内容中再逐步介绍。 [编辑 - 4/19/05 by znsoft] |
沙发#
发布于:2004-10-21 10:13
期待继续! :D :D
|
|
板凳#
发布于:2004-10-21 13:31
顺便介绍下FASTIO接口介绍
FASTIO接口介绍 作者:陆麟 转载请征得作者同意. 2003.3.22 -------------------------------------------------------------------------------- NT下FASTIO是一套IO MANAGER与DEVICE DRIVER沟通的另外一套API. 在进行基于IRP为基础的接口调用前, IO MANAGER会尝试使用FAST IO接口来加速各种IO操作. FASTIO本身的文档并不多见, 本篇就是要介绍一下FASTIO接口. FastIoCheckIfPossible, 此调用并不是IO MANAGER直接调用. 而是被FsRtlXXX系列函数调用. 用于确认读写操作是否可以用FASTIO接口进行. FastIoRead/FastIoWrite, 很明显, 是读写处理的调用. FastIoQueryBasicInfo/FastIoQueryStandardInfo, 用于获取各种文件信息. 例如创建,修改日期等. FastIoLock/FastIoUnlockSingle/FastIoUnlockAll/FastIoUnlockAllByKey,用于对文件的锁定操作. 在NT中.有2中锁定需要存在.1.排他性锁. 2.共享锁. 排他性锁在写操作前获取,不准其他进程获得写操作权限, 而共享锁则代表需要读文件某区间. 禁止有写动作出现. 在同一地址上, 如果有多个共享锁请求, 那是被允许的. FastIoDeviceControl用于提供NtDeviceIoControlFile的支持. AcquireFileForNtCreateSection/ReleaseFileForNtCreateSection是NTFS在映射文件内容到内存页面前进行的操作. FastIoDetachDevice, 当REMOVABLE介质被拿走后, FILE SYSTEM的DEVICE对象会在任意的时刻被销毁. 只有正确处理这个调用才能把上层DEVICE和将要销毁的DEVICE脱钩. 如果不解决这个函数, 系统会当. FastIoQueryNetworkOpenInfo, 当CIFS也就是网上邻居,更准确的说是网络重定向驱动尝试获取文件信息, 会使用这个调用. 该调用是因为各种历史原因而产生. 当时设计CIFS时为避免多次在网上传输文件信息请求, 在NT4时传输协议增加了一个FileNetworkOpenInformation的网络文件请求. 而FSD则增加了这个接口. 用于在一次操作中获得所有的文件信息. 客户段发送FileNetworkOpenInformation, 服务器端的FSD用本接口完成信息填写. FastIoAcquireForModWrite, Modified Page Writer会调用这个接口来获取文件锁. 如果实现这个接口. 则能使得文件锁定范围减小到调用指定的范围. 不实现此接口, 整个文件被锁. FastIoPrepareMdlWrite, FSD提供MDL. 以后向此MDL写入数据就代表向文件写入数据. 调用参数中有FILE_BOJECT描述要写的目标文件. FastIoMdlWriteComplete, 写操作完成. FSD回收MDL. FastIoReadCompressed, 当此调用被调用时, 读到的数据是压缩后的.应该兼容于标准的NT提供的压缩库. 因为调用者负责解压缩. FastIoWriteCompressed,当此调用被调用时, 可以将数据是压缩后存储. FastIoMdlReadCompressed/FastIoMdlReadCompleteCompressed, MDL版本的压缩读. 当后一个接口被调用时,MDL必须被释放. FastIoMdlWriteCompressed/FastIoMdlWriteCompleteCompressed, MDL版本的压缩写.当后一个接口被调用时,MDL必须被释放. FastIoQueryOpen, 这不是打开文件的操作. 但是却提供了一个IRP_MJ_CREATE的IRP. 我在以前版本的SECUSTAR的软件中错误地实现了功能. 这个操作是打开文件/获取文件基本信息/关闭文件的一个操作. FastIoReleaseForModWrite,释放FastIoAcquireForModWrite调用所占有的LOCK. FastIoAcquireForCcFlush/FastIoReleaseForCcFlush FsRtl会调用此接口,在LAZY WRITE线程将要把修改后的文件数据写入前调用.获取文件锁. |
|
|
地板#
发布于:2004-10-23 17:31
兄弟,果然厉害
|
|
|
地下室#
发布于:2005-04-12 20:20
好文章,再推一把3333
|
|
|