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

    11.文件和目录的生成打开,关闭与删除

    我们已经分析了读,写与读类似。文件系统还有其他的操作。比如文件或目录的打开(打开已经存在的或者创建新的),关闭。文件或目录的移动,删除。

    实际上FILE_OBJECT并不仅仅指文件对象。在windows文件系统中,目录和文件都是用FileObject来抽象的。这里产生一个问题,对于一个已经有的FileObject,我如何判断这是一个目录还是一个文件呢?

    对于一个已经存在的FileObject,我没有找到除了发送IRP来向卷设备询问这个FileObject的信息之外更好的办法。自己发送IRP很麻 烦。不是我很乐意做的那种事情。但是FileObject都是在CreateFile的时候诞生的。在诞生的过程中,确实有机会得到这个即将诞生的 FileObject,是一个文件还是一个目录。

    Create的时候,获得当前IO_STACK_LOCATION,假设为irpsp,那么irpsp->Parameters.Create的结构为:

    struct {
    PIO_SECURITY_CONTEXT SecurityContext;
    ULONG Options;
    USHORT FileAttributes;
    USHORT ShareAccess;
    ULONG EaLength;
    };

    这个结构中的参数是与CreateFile这个api中的参数对应的,请自己研究。我先写一些函数包装来方便读取irpsp.

    _inline wd_ulong wd_irpsp_file_opts(wd_irpsp *irpsp)
    {
    return irpsp->Parameters.Create.Options;
    }

    _inline wd_ushort wd_irpsp_file_attrs(wd_irpsp *irpsp)
    {
    return irpsp->Parameters.Create.FileAttributes;
    }

    enum {wd_file_opt_dir = FILE_DIRECTORY_FILE};
    enum {wd_file_attr_dir = FILE_ATTRIBUTE_DIRECTORY};

    然后我们搞清上边Options和FileAttributes的意思。是不是Options里边有FILE_DIRECTORY_FILE标记就表示这 是一个目录?实际上,CreateOpen是一种尝试性的动作。无论如何,我们只有当CreateOpen成功的时候,判断FileObject才有意 义。否则是空谈。

    成功有两种可能,一是已经打开了原有的文件或者目录,另一种是新建立了文件或者目录。Options里边带有FILE_DIRECTORY_FILE表示 打开或者生成的对象是一个目录。那么,如果在Create的完成函数中,证实生成或者打开是成功的,那么返回得到的FILE_OBJECT,确实应该是一 个目录。

    当我经常要使用我过滤时得到的文件或者目录对象的时候,我一般在Create成功的的时候捕获他们,并把他们记录在一个“集合”中。这时你得写一个用来表 示“集合”的数据结构。你可以用链表或者数组,只是注意保证多线程安全性。因为Create的时候已经得到了属性表示FileObject是否是目录,你 就没有必要再发送IRP来询问FileObject的Attribute了。

    对了上边有FileAttributes。但是这个东西并不可靠。因为在生成或者打开的时候,你只需要设置Options。我认为这个字段并无法说明你打开的文件对象是目录。

    这你需要设置一下Create的完成函数。如果设置这里不再重复,请参考上边对文件读操作。

    wd_stat my_create_comp(in wd_dev *dev,
    in wd_irp *irp,
    in wd_void *context)
    {
    wd_irpsp *irpsp = wd_irp_cur_sp(irp);
    wd_file *file = wd_irpsp_file(irpsp);

    UNREFERENCED_PARAMETER(dev);

    if(wd_suc(wd_irp_status(irp))
    {
    // 如果成功了,把这个FileObject记录到集合里,这是一个
    // 刚刚打开或者生成的目录
    if(file &&
    (wd_irpsp_file_opts(irpsp) & wd_file_opt_dir))
    add_obj_to_set(file);
    }
    return wd_irp_status(irp);
    }

    这里顺便解释一下UNREFERENCED_PARAMETER宏。我曾经不理解这个宏的意思。其实就是因为本函数传入了三个参数,这些参数你未必会用 到。如果你不用的话,大家知道c编译器会发出一条警告。一般认为驱动应该去掉所有的警告,所以用了这个宏来“使用”一下没有用到过的参数。你完全可以不用 他们。

    现在所有的目录都被你记录。那么得到一个FileObject的时候,判断一下这个FileObject在不在你的集合里,如果在,就说明是目录,反之是文件。

    当这个FileObject被关闭的时候你应该把它从你的集合中删除。你可以捕获Close的IRP来做这个。记得本教程很早以前,我们已经安装过 my_close函数的来处理IRP(请回忆或者翻阅第3节的内容),那么很简单了,在该函数中从你的集合中删除该FileObject即可。作为保险的 做法,应该观察一下关闭是否成功。如果成功的话,再进行你的从集合中删除元素工作。

    因为判断FileObject是文件还是目录的问题,我们已经见识了文件的打开和关闭工作。现在看一下文件是如何被删除的。

    删除的操作,第一步是打开文件,打开文件的时候必须设置为可以删除。如果打开失败,则直接导致无法删除文件。第二步设置文件属性为用于删除,第三步关闭文件即可。关闭的时候,文件被系统删除。

    不过请注意这里的“删除”并非把文件删除到回收站。如果要测试,你必须按住shift彻底删除文件。文件删除到回收站只是一种改名操作。改名操作我们留到以后再讨论。

    第一步是打开文件,我应该可以在文件被打开的时候,捕获到的irpsp的参数,记得前边的参数结构,中间有:

    PIO_SECURITY_CONTEXT SecurityContext;

    相关的结构如下:

    typedef struct _IO_SECURITY_CONTEXT {
    PSECURITY_QUALITY_OF_SERVICE SecurityQos;
    PACCESS_STATE AccessState;
    ACCESS_MASK DesiredAccess;
    ULONG FullCreateOptions;
    } IO_SECURITY_CONTEXT, *PIO_SECURITY_CONTEXT;

    注意其中的DesiredAccess,其中必须有DELETE标记,才可以删除文件。

    第二步是设置为”关闭时删除”。这是通过发送一个IRP(Set Information)来设置的。捕获主功能码为IRP_MJ_SET_INFORMATION的IRP后:
    首先,IrpSp->Parameters.SetFile.FileInformationClass应该为FileDispositionInformation。

    然后,Irp->AssociatedIrp.SystemBuffer指向一个如下的结构:

    typedef struct _FILE_DISPOSITION_INFORMATION {
    BOOLEAN DeleteFile;
    } FILE_DISPOSITION_INFORMATION;

    如果DeleteFile为TRUE,那么这是一个删除文件的操作。文件将在这个FileObject Close的时候被删除。

    以上的我都未实际调试,也不再提供示例的代码。有兴趣的读者请自己完成。
  • 相关阅读:
    python的多线程是否没有用了
    解决“mongoengine.fields.ImproperlyConfigured: PIL library was not found”报错
    Django JSON 时间
    伪装浏览器根据经纬度解析地理位置
    Excel——使用VLOOKUP函数关联跨工作薄数据
    Python发送邮件(支持中文)
    Excel实用技巧
    修改tomcat应用日志默认编码格式
    AWS多个EIP的解决方案
    解决荣耀7烦人的情景智能提醒
  • 原文地址:https://www.cnblogs.com/jasononline/p/1231776.html
Copyright © 2011-2022 走看看