zoukankan      html  css  js  c++  java
  • Windows文件系统过滤驱动开发教程(10)

    Windows文件系统过滤驱动开发教程

    注: 有任何问题与建议请加QQ16191935,邮箱MFC_Tan_Wen@163.com

    工作忙,好久没有来过了,请大家谅解。

    10 自己发送Irp完成读请求

    关于这个有一篇文档解释得很详细,不过我认为示例的代码有点太简略了,这篇文档在IFS所附带的OSR文档中,请自己寻找。

    为何要自己发送Irp?在一个文件过滤驱动中,如果你打算读写文件,可以试用ZwReadFile.但是这有一些问题。Zw系列的Native API使

    用句柄。而句柄是有线程环境限制的。此外也有中断级别的限制。再说,Zw系列函数来读写文件,最终还是要发出Irp,又会被自己的过滤驱动

    捕获到。结果带来判断上的困难。对资源也是浪费。那么最应该的办法是什么呢?当然是直接对卷设备发Irp了。

    但是Irp是非常复杂的数据结构,而且又被微软所构造的很多未空开的部件所处理。所以自己发irp并不是一件简单的事情。

    比较万能的方法是IoAllocateIrp,分配后自己逐个填写。问题是细节实在太多,很多无文档可寻。有兴趣的应该看看我上边所提及的

    那篇文章“Rolling Your Own”。

    有意思的是这篇文章后来提到了捷径,就是利用三个函数:

    IoBuildAsynchronousFsdRequest(...)
    IoBuildSynchronousFsdRequest(...)
    IoBuildDeviceIoControlRequest(...)

    于是我参考了他这方面的示例代码,发现运行良好,程序也很简单。建议怕深入研究的选手就可以使用我下边提供的方法了。

    首先的建议是使用IoBuildAsynchronousFsdRequest(),而不要使用同步的那个。使用异步的Irp使irp和线程无关。而你的过滤驱动一

    般很难把握当前线程(如果你开一个系统线程来专门读取文件那例外)。此时,你可以轻松的在Irp的完成函数中删除你分配过的Irp,避免去追

    究和线程相关的事情。

    但是这个方法有局限性。文档指出,这个方法仅仅能用于IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_FLUSH_BUFFERS,和IRP_MJ_SHUTDOWN.

    刚好我这里仅仅要求完成文件读。

    用Irp完成文件读需要一个FILE_OBJECT.FileObject是比Zw系列所用的句柄更好的东西。因为这个FileObject是和线程无关的。你可以

    放心的在未知的线程中使用他。

    自己要获得一个FILE_OBJECT必须自己发送IRP_MJ_CREATE的IRP.这又不是一件轻松的事情。不过我跳过了这个问题。因为我是文件系

    统过滤驱动,所以我从上面发来的IRP中得到FILE_OBJECT,然后再构造自己的IRP使用这个FILE_OBJECT,我发现运行很好。

    但是又出现一个问题,如果IRP的irp->Flags中有IRP_PAGING(或者说是Cache管理器所发来的IRP)标记,则其FileObject我获得并使

    用后,老是返回错误。阅读网上的经验表明,带有IRP_PAGINGE的FileObject不可以使用.于是我避免使用这时的FileObject.我总是使用不带

    IRP_PAGING的Irp(认为是用户程序发来的读请求)的FileObject。

    好,现在废话很多了,现在来看看构造irp的代码:

    _inline wd_irp *wd_irp_fsd_read_alloc(wd_dev *dev,
    wd_void *buf,
    wd_ulong length,
    wd_lgint *offset,
    wd_io_stat_block *io_stat)
    {
    return IoBuildAsynchronousFsdRequest(IRP_MJ_READ,dev,
    buf,length,
    offset,
    io_stat);
    }

    io_stat我不知道是做何用,我一般填写NULL.类型是PIO_STATUS_BLOCK.buf则是缓冲。在Irp中被用做UserBuffer接收数据。offset是

    这次读的偏移量。

    以上函数构造一个读irp.请注意,此时您还没有设置FileObject.实际上我是这样发出请求的:

    irp = wd_irp_fsd_read_alloc(dev,buf,len,&start,NULL);
    if(irp == NULL)
    return;
    irpsp = wd_irp_next_sp(irp);
    wd_irpsp_file_set(irpsp,file);
    wd_irp_comp(irp,my_req_comp,context);

    请注意wd_irp_next_sp,我是得到了这个irp的下一个IO_STACK_LOCATION,然后我设置了FileObject.接下来应该设置了完成后,我就

    可以发送请求了!请求发送完毕后,一旦系统完成请求就会调用你的my_req_comp.

    再看看my_req_comp如何收场:

    wd_stat my_req_comp(in wd_dev *dev,
    in wd_irp *irp,
    in wd_void *context)
    {

    // 请注意,无论成功还是失败,我都得在这里彻底销毁irp
    wd_irp_send_by_myself_free(irp);

    // 返回这个,仅仅是因为irp我已经销毁,不想让系统再次销毁它而已。
    return wd_stat_more_processing;
    }

    wd_stat_more_prcessing就是STATUS_MORE_PROCESSING_REQUIRED。之所以返回这个,是因为我已经把irp给删除了。我不想windows系

    统再对这个irp做什么。所以干脆说我还要继续处理,这样避免了io管理器再去动用这个irp的可能。

    最后是那个irp删除函数的代码:

    _inline wd_void wd_irp_send_by_myself_free(wd_irp *irp)
    {
    if (irp->MdlAddress)
    {
    MmUnmapLockedPages(MmGetSystemAddressForMdl(irp->MdlAddress),
    irp->MdlAddress);
    MmUnlockPages(irp->MdlAddress);
    IoFreeMdl(irp->MdlAddress);
    }
    IoFreeIrp(irp);
    };

    因为我自己没有分配过MdlAddress下去过。所以如果下边返回了MDL,我得附带清理它。

    好了,祝愿你心情愉快。如果你何我一样懒惰的话,不妨就用上边的简单方法自己发irp来读文件了。
  • 相关阅读:
    rest_framework学习之路
    jQuery操作cookie
    Cookie和Session
    HTTP之Content-Type
    HTTP协议
    Python之random模块
    HTML5(FileRdeader)
    Python之re模块
    LINQ基础 之 LINQ TO SQL (二)
    LINQ基础(一)
  • 原文地址:https://www.cnblogs.com/jasononline/p/1231775.html
Copyright © 2011-2022 走看看