(转载)Windows文件系统过滤驱动开发教程 联系客服

发布时间 : 星期五 文章(转载)Windows文件系统过滤驱动开发教程更新完毕开始阅读1b486c1614791711cc79175f

if(ext->storage_dev == NULL) {

wd_skip_io_stack(irp);

return wd_irp_call(attached_dev,irp); }

// 到了这里,确认是对文件的读

wd_ustr_init_em(&name,name_buf,512); if(file)

wd_file_get_name((wd_void *)file,&name); else {

wd_skip_io_stack(irp);

return wd_irp_call(attached_dev,irp); }

wd_printf1(\wd_printf1(\wd_printf1(\wd_printf1(\

// 以上我已经打印了读请求的相关参数,下面我希望得到读出的内容 wd_event_init(&event);

// 先拷贝当前io_stack,然后再指定完成例程

wd_copy_io_stack(irp);

wd_irp_set_comp(irp,my_disp_read_comp,&event);

// 对实际设备呼叫irp

status = wd_irp_call(attached_dev,irp); if(status == wd_stat_pending) wd_event_wait(&event);

wd_printf1(\

// 如果此时status = 0,那么内容应该就在Irp->UserBuffer中,请自己打印... wd_printf1(\

return wd_irp_over(irp); }

然后是my_disp_read_comp的内容,可以看见只是简单的设置事件,然后返回wd_stat_more_processing.

wd_stat my_disp_read_comp(in wd_dev *dev,

in wd_irp *irp,

in wd_void *context) {

wd_event * event= (wd_event *)context;

UNREFERENCED_PARAMETER(dev); UNREFERENCED_PARAMETER(irp); wd_event_set(event);

return wd_stat_more_processing; }

尽管已经写了很多,尽管我们得到了读过程的所有参数和结果,我们依然不知道如果自己写一个文件系统,该如何完成读请求,或者过滤驱动中,如何修改读请求等等.我们下一节继续讨论读操作.

9 完成读操作

除非是一个完整的文件系统,完成读操作似乎是不必要的。过滤驱动一般只需要把请求交给下层的实际文件系统来完成。但是有时候比如加解密操作,我希望从下层读到数据,解密后,我自己来完成这一IRP请求。

这里要谈到IRP的minor function code.以前已经讨论到如果major function code 是IRP_MJ_READ则是Read请求。实际上有些主功能号下面有一些子功能号,如果是IRP_MJ_READ,检查其MINOR,应该有几种情况:IRP_MN_NORMAL,IRP_MN_MDL,IRP_MN_MDL|IRP_COMPLETE(这个其实就是IRP_MN_MDL_COMPLETE).还有其他几种情况,资料上有解释,但是我没自己调试过,也就不胡说了。只拿自己调试过的几种情况来说说。

先写个函数,得到次功能号。

_inline wd_uchar wd_irpsp_minor(wd_io_stack *irpsp) {

return irpsp->MinorFunction; }

enum {

wd_mn_mdl = IRP_MN_MDL,

wd_mn_mdl_comp = IRP_MN_MDL_COMPLETE, wd_mn_normal = IRP_MN_NORMAL };

希望你喜欢我重新定义过的次功能号码。

wd_mn_normal的情况完全与上一节同(读者可能要骂了,上一节明明说就是这样的,结果还有其他的情况,那不是骗人么?但是微软的东西例外就是多,我也实在拿他没办法... ).

注意如上节所叙述,wd_mn_normal的情况,既有可能是在Irp->MdlAddress中返回数据,也可能是在Irp->UserBuffer中返回数据,这个取决于Device的标志.

但是如果次功能号为wd_mn_mdl则完全不是这个意思。这种irp一进来看数据,就赫然发现Irp->MdlAddress和Irp->UserBuffer都为空。那你得到数据后把数据往哪里拷贝呢?

wd_mn_mdl的意思是请自己分配一个mdl,然后把mdl指向你的数据所在的空间,然后返回给上层。自然mdl是要释放的,换句话说事业使用完毕要归还,所以又有wd_mn_mdl_comp,意思是一个mdl已经使用完毕,可以释放了。

mdl用于描述内存的位置。据说和NDIS_BUFFER用的是同一个结构。这里不深究,我写一些函数来分配和释放mdl,并把mdl指向内存位置或者得到mdl所指向的内存:

// 释放mdl

_inline wd_void wd_mdl_free(wd_mdl *mdl) {

IoFreeMdl(mdl); }

// 这个这个东西分配mdl,缓冲必须是非分页的。可以在dispatch level跑。 _inline wd_mdl *wd_mdl_alloc(wd_void* buf, wd_ulong length) {

wd_mdl * pmdl = IoAllocateMdl(buf,length,wd_false,wd_false,NULL); if(pmdl == NULL) return NULL;

MmBuildMdlForNonPagedPool(pmdl); return pmdl; }

// 这个函数分配一个mdl,并且带有一片内存 _inline wd_mdl *wd_mdl_malloc(wd_ulong length) {

wd_mdl *mdl;

wd_void *point = wd_malloc(wd_false,length); if(point == NULL) return NULL;

mdl = wd_mdl_alloc(point,length); if(mdl == NULL)

{

wd_free(point); return NULL; }

return mdl; }

// 这个函数释放mdl并释放mdl所带的内存。 _inline wd_void wd_mdl_mfree(wd_mdl *mdl) {

wd_void *point = wd_mdl_vaddr(mdl); wd_mdl_free(mdl); wd_free(point); }

// 得到地址。如果想往一个MdlAddress里边拷贝数据 ... _inline wd_void *wd_mdl_vaddr(wd_mdl *mdl) {

return MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority); }

另外我通过这两个函数来设置和获取Irp上的mdl.

_inline wd_mdl *wd_irp_mdl(wd_irp *irp) {

return irp->MdlAddress; }

_inline wd_void wd_irp_mdl_set(wd_irp *irp, wd_mdl *mdl) {

irp->MdlAddress = mdl; }

一个函数获得UserBuffer.

_inline wd_void * wd_irp_user_buf(wd_irp *irp) {

return irp->UserBuffer; }

要完成请求还有一个问题。就是irp->IoStatus.Information.在这里你必须填上实际读取得到的字节数字。不然上层不知道有多少数据返回。这个数字不一定与你的请求的长度等同(其实我认为几乎只要是成功,就应该都是等同的,唯一的例外是读取到文件结束的地方,长度不够了的情况)。我用下边两个函数来获取和设置这个数值: