<译者注:
现在,你得手工安装。
)这个驱动通过提供一些库供微过滤器调用来管理所有的微过滤器。
必要的头文件,库和二进制代码都在微过滤器IFSKit中。
kavU42VRUs
为何要开发一个微文件系统过滤驱动?
.通过更少的工作量,得到更简单的,更可靠的过滤驱动.
.动态加载和卸载,绑定和解除绑定.
.在过滤栈中,绑定到一个合理确定的位置。
.上下文管理。
快捷,干净,可靠的上下文管理,用于文件对象,流,文件,实例和卷.
.一组有用的调用.包括根据文件名寻找,高效存取,和用户态程序之间的通信,以及io排队.
.支持非回环I/O.这样,一个微过滤器发起的I/O请求可以轻松的只让栈中更下面的微过滤器以及文件系统看到了。
y6v3ALoS89
.仅仅过滤感兴趣的操作。
不象旧过滤模型那样必须挂接每个操作入口以便把操作传递到下层.
2.术语
在过滤管理器架构中,定义了一些新的对象。
为了搞清这些,这里将列出一些定义:
过滤器:
在文件系统上执行一些过滤操作的一种驱动.
卷:
在本地文件系统,这个对象指文件系统所管理的逻辑卷.对于网络重定向文件系统,指所有网络请求被重定向的目的。
卷直接对应文件系统(无论本地或者网络>旧过滤模型中的设备对象(DEVICE_OBJECT>.M2ub6vSTnP
实例:
一个过滤器在一个卷上唯一的某层上生成的一个实例化对象。
过滤管理器把所有的IO请求发到卷上的实例栈上。
一个微过滤器在一个卷上可能不止一个实例.规范的例子是FileSpy.有时候把FileSpy的两个实例分别绑定在另一个过滤器的上边和下边。
此时每个实例有一个私有的上下文.这个上下文包含IO操作的日志.可以用来比较一个过滤器上下的IO操作有什么不同。
0YujCfmUCw
文件:
文件系统保存在一个磁盘上的可能包含若干个流的有名字的数据对象.
流:
指一个文件中的物理数据流.
文件对象(FileObject>:
用来描述一个用户对一个文件中的一个物理数据流的一次打开。
回调数据(CallbackData>:
过滤管理器中的一种数据结构,包含了一个操作中的所有信息。
对应于旧过滤模型中的IRP.eUts8ZQVRd
3.微过滤器安装
微过滤器可以通过一个INF文件安装。
INF文件指出了这个微过滤器所支持的实例.实例的具体说明在第5节.每个实例有一组标志,还有一个唯一的数值固定了它在过滤栈中的位置。
sQsAEJkW5T
INF文件中有一个表标明了每个实例的层级.这用来给文件系统过滤的开发商装载他们的微过滤器.有标记标明了这个微过滤器是否需要"自动的绑定".如果是,那么每个新的卷出现的时候,微过滤器都回收到一个通知.它可以在此绑定他们.绑定的时候,inf文件中的层级决定了绑定到什么层次上。
GMsIasNXkA
在微过滤器运行时,文件系统过滤开发商也可以在某个指定的层级上动态的生成一个实例,这可以使用FilterAttachAtAltitude(>调用.这对于开发者来说可以用来进行测试和排除bug.TIrRGchYzg
4.微过滤器注册
微过滤器是内核驱动。
因此它必须导出一个名为DriverEntry的函数。
在驱动加载的时候这个函数第一个被调用.很多微过滤器在DriverEntry(>中调用FltRegisterFilter(>.7EqZcWLZNX
FilterRegisterFilter(>需要传入一个参数。
是一个FLT_REGISTRATION结构.包含了:
一个卸载例程.实例通知回调,一组上下文回调指针,一组文件系统操作回调指针.一般情况下,微过滤过器只捕获一部分操作,因此文件系统操作回调指针可能并不多。
lzq7IGf02E
对于某一种操作,微过滤器可以指定一些附加的标记来指明它是否在所有的情况下都收到它们.比如,如果FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO被指定了,微过滤器就不会收到任何此类IRP的pagingI/O操作。
zvpgeqJ1hk
同样的,如果FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO被指定了,那么只有这类操作的非缓冲请求能看见.(比如说,指定了IRP_MJ_READ类操作,那么所有的缓冲读就都不会被微过滤器捕获了。
NrpoJac3v1
5.开始过滤
当一个微过滤器注册自己,它就应该在某个时间调用函数FltStartFiltering(>来开始过滤。
并不一定要在DriverEntry中调用。
不过大多数微过滤器可能是这样做的。
1nowfTG4KI
这个函数将激发必要的通知,导致微过滤器绑定到卷上然后开始过滤I/O操作。
为此,过滤管理器会通过微过滤器的inf文件遍历它注册过的所有的实例。
fjnFLDa5Zo
每个示例都有一个层级。
一个层级是一个唯一的字符串,(如"100.123456">,这个定义了微过滤器的这个实例在栈上的位置。
商业版本的微过滤器层级将由微软公司来分配。
tfnNhnE6e5
层级的数字越高,这个微过滤器绑定在栈上的位置就越高。
一些示例层级提供给开发者用来实现微过滤器。
这些是仅有的不会被分配的层级。
层级有两个作用:
一是确定两个微过滤器之间的顺序关系,尤其是有时得实现一些不用去考虑个别微过滤器什么时候加载的功能。
HbmVN777sL
比如说,一个加密解密过滤器必须安装在一个防病毒的过滤的下边。
否则,防病毒过滤器无法从已经加密的内容中发现病毒。
另外就是提供了一个最小的测试矩阵,用来测试这些过滤驱动的互容性。
如果这些驱动实例都是按一个指定的顺序在栈中的,那么测试的时候就不用再考虑排列各种不同的顺序了。
V7l4jRB8Hs
在inf文件中,一个实例和一个标记联系在一起。
如果第1个位标记了,那么微过滤器不会在卷出现在系统中的时候得到通知。
这样的实例应该通过过滤管理器编程接口来手工的绑定。
如果第2位被设置了,即使手工的发送了一个绑定请求,微过滤器也不会收到通知来要求绑定一个实例到一个卷。
83lcPA59W9
6.实例的通知
当一个实例生成的时候,一组回调函数提供来通知微过滤器。
通过这些回调,微过滤器可以决定它的实例在什么时候绑定到卷上和从卷上解除了绑定。
mZkklkzaaP
6.1.安装一个实例
回调例程InstatanceSetupCallback(>在下列情况下被调用:
.当一个微过滤器加载的时候,每个存在的卷都会导致这个调用。
.当一个新的卷被mount.
.当FltAttachVolume被调用<内核模式)
.当FltAttachVolumeAtAltitude(>被调用<内核模式)
.当FilterAttach(>被调用<用户模式>
.当FilterAttachAtAltitude(>被调用<用户模式)
在这个过程中,微过滤器决定是否在这个卷上生成实例。
这个回调的原型如下:
typedefNTSTATUS
(*PFLT_INSTANCE_SETUP_CALLBACK>(
INPCFLT_RELATED_OBJECTSFltObjects,
INFLT_INSTANCE_SETUP_FLAGSFlags,
INDEVICE_TYPEVolumeDeviceType,
INFLT_FILESYSTEM_TYPEVolumeFilesystemType
>。
FltObjects结构喊有指向微过滤器,卷,和实例的指针。
这个实例指将要在InstanceSetupCallback(>函数中生成的实例。
Flags标记是什么操作导致激发了InstanceSetupCallback(>:
AVktR43bpw
FLTFL_INSTANCE_SETUP_AUTOMATIC_ATTACHMENT:
这是一个微过滤器注册的时候,一个自动的绑定通知。
过滤管理器为每个刚加载的微过滤器枚举所有的卷。
如果是一个使用者明确的指定一个实例绑定到某一个卷,不会设置有这个标记。
ORjBnOwcEd
FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT:
通过调用FilterAttach(>(用户态>,或者是FilterAttachVolumeAtAltitude(>(用户态>,或者是FltAttachVolume(>(内核态>所发起的一个手工的请求。
2MiJTy0dTT
FLTFL_INSTANCE_SETUP_NEWLY_MOUNTED_VOLUME:
文件系统刚刚挂载(mount>了一个卷,所以呼叫InstanceSetupCallback(>来通知微过滤器,如果它愿意可以生成实例来绑定这个卷。
gIiSpiue7A
在InstanceSetupCallback(>中,微过滤器同时得到了卷设备类型同时,微过滤器可以调用FltGetVolumeProperties(>来获取卷属性。
通过FltSetInstanceContext(>在实例上设置上下文。
当然这是需要绑定的时候。
它甚至可以在卷上打开或者关闭文件。
uEh0U1Yfmh
如果这个回调返回了成功,那么这个实例将绑定到卷上。
如果返回了一个警告或者错误,那么不会绑定。
如果微过滤器没有指定InstanceSetup回调,那么,系统将认为用户总是返回了STATUS_SUCCESS,实例总是会生成并绑定。
IAg9qLsgBX
6.2.控制实例的销毁
InstanceQueryTeardown(>回调仅仅在一个手工解除绑定的请求下被调用。
以下操作可能导致:
WwghWvVhPE
FltDetachVolume(>(内核模式>
FilterDetach(>(用户模式>
如果一个微过滤器没有提供这个回调,那么手工解除绑定是不被支持的。
但是,卷的解挂载asfpsfpi4k
如果这个回调返回成功,那么过滤管理器开始销毁给出的实例。
最后实例的InstanceTeardownStart(>和InstanceTeardownComplete(>会被调用。
如果返回了错误或者警告,手工解除绑定会失败。
推荐的错误代码有:
STATUS_FLT_DO_NOT_DETACH,不过实际上你可以返回任何错误代码。
ooeyYZTjj1
InstanceQueryTeardown(>回调的原型是:
typedefNTSTATUS
(*PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK>(
INPCFLT_RELATED_OBJECTSFltObjects,
INFLT_INSTANCE_QUERY_TEARDOWN_FLAGSFlags
>。
和InstanceSetupCallback(>类似,FltObject指出了与这个销毁操作有关的微过滤器,卷和实例。
BkeGuInkxI
6.3.实例解绑定的同步
如果InstanceTeardownStart(>的时候已经决定要解除绑定,那么这个例程中必须做以下的事情:
PgdO0sRlMo
(1>重设所有的未决的I/O操作<包括预操作和后操作)
(2>保证不会有新的I/O操作进入未决。
(3>对刚刚到达的操作开始最少的工作。
同时,应该做以下操作:
(1>关闭所有打开的文件。
(2>取消所有本过滤器发起的I/O请求。
(3>停止将新的工作任务排队。
然后微过滤器把控制权交还过滤管理器来继续它的销毁过程。
当所有与这个实例相关的操作都排除干净或者完成了,InstanceTeardownComplete(>会被调用。
管理器保证此时所有此实例的存在的操作回调都完成了。
这时微过滤器必须关闭所有这个实例打开的文件。
3cdXwckm15
这两个回调的原型如下:
typedefVOID
(*PFLT_INSTANCE_TEARDOWN_CALLBACK>(
INPCFLT_RELATED_OBJECTSFltObjects,
INFLT_INSTANCE_TEARDOWN_FLAGSReason
>。
FltObjets中有微过滤器,卷和实例。
Resson参数指明这次销毁的原因,可能是以下一些标记的组合:
h8c52WOngM
FLTFL_INSTANCE_TEARDOWN_MANUAL:
这次销毁操作是一个手工的请求。
(FilterDetach(>或者FltDetachVolume(>>.v4bdyGious
FLTFL_INSTANCE_TEARDOWN_FILTER_UNLOAD:
这次销毁操作是因为微过滤器执行卸载或者是选择了把卸载请求失败掉导致的。
J0bm4qMpJ9
FLTFL_INSTANCE_TEARDOWN_MANDATORY_FILTER_UNLOAD:
这次销毁操作是一次强制卸载导致的。
这种情况下不能把卸载请求失败掉。
XVauA9grYP
FLTFL_INSTANCE_TEARDOWN_VOLUME_DISMOUNT:
这次销毁是一个卷被解挂载的结果。
FLTFL_INSTANCE_TEARDOWN_INTERNAL_ERROR:
这次销毁是因为安装实例的时候的一个内部错误导致的,比如内存不足。
bR9C6TJscw
请注意没有返回值。
InstanceTeardownStart(>和InstanceTeardownComplete(>都不能失败。
过滤管理器保证这些例程都运行在PassiveIRQL.pN9LBDdtrd
7.回调支持
7.1回调数据
回调数据类似旧过滤模型下的IRP.微过滤器通过这个结构和过滤管理器交互。
不同的是,回调数据不像IRP那样管理一个栈结构。
回调数据的管理都通过已经明确定义的过滤管理器接口。
并且返回状态值给过滤管理器即可。
DJ8T7nHuGT
FLT_CALLBACK_DATA类型包含了微过滤器描述一个I/O操作所需要的所有的信息。
下面继续详细讲解这个结构中的各个域来说明其中包含的信息:
QF81D7bvUA
Flags:
提供这个操作的一些信息。
一个或多个下面的标记可能被设置在Flags中:
FLTFL_CALLBACK_DATA_IRP_OPERATION:
这个回调数据描述一个IRP操作。
4B7a9QFw9h
FLTFL_CALLBACK_DATA_FAST_IO_OPERATION:
这个回调数据描述一个FastIO操作。
ix6iFA8xoX
FLTFL_CALLBACK_DATA_FS_FILTER_OPERATION:
这个回调描述一个文件系统过滤器操作。
wt6qbkCyDE
FLTFL_CALLBACK_DATA_SYSTEM_BUFFER:
这个操作所用的缓冲是一个系统分配的缓冲。
Kp5zH46zRk
FLTFL_CALLBACK_DATA_GENERATED_IO:
这个操作是由一个微过滤器发起的。
FLTFL_CALLBACK_DATA_REISSUED_IO:
这个操作被一个当前实例之上的过滤器所重新发回给文件系统。
Yl4HdOAA61
FLTFL_CALLBACK_DATA_DRAINING_IO:
只有设置了后操作ch4PJx4BlI
FLTFL_CALLBACK_DATA_POST_OPERATION:
只有设置了后操作qd3YfhxCzo
FLTFL_CALLBACK_DATA_DIRTY:
当一个微过滤器已经改变了这个操作的一个或者多个可变参数的时候,设置这个参数。
这个标记仅仅在Pre-operation过程中设置。
微过滤器必须用FLT_SET_CALLBACK_DATA_DIRTY(>和FLT_CLEAR_CALLBACK_DATA_DIRTY(>来操作这个标记。
E836L11DO5
Thread:
发出这个操作的线程的地址。
Iopb:
指向这个操作的可变参数的指针。
这个结构在后边详叙。
IoStatus:
IO_STATUS_BLOCK结构返回操作最后的状态。
如果一个微过滤器打算结束这个操作,那么必须先设置这个域,然后才能结束这个请求。
对于传递给文件系统去的请求,在后操作过程S42ehLvE3M
TagData:
仅仅在Create操作的后操作回调中有效。
当一个操作的目标文件有一个重解读点501nNvZFis
QueueLinks:
一个链表入口结构。
有时要把回调数据jW1viftGw9
QueueContext[2]:
一组空指针结构,用来传入附加的上下文到工作队列处理过程中。
FilterContext[4]:
一组空指针结构,当回调数据进入了队列,微过滤器可以做任意使用。
不依赖于过滤管理器的内部结构。
xS0DOYWHLP
RequestorMode:
这个操作的者的请求模式。
Iopb域所指的是一个FLT_IO_PARAMETER_BLOCK结构。
包含了回调数据中可以修改的部分。
对比IRP来说,这里相当于IRP的当前栈空间微过滤器必须访问这个结构来得到每次预操作下面是一些更详细的细节:
LOZMkIqI0w
IrpFlags:
IRP中描述这个操作的一些标记。
MajorFunction:
IRP主功能号。
MinorFunction:
IRP辅功能号。
OperationFlags:
即IO_STACK_LOCATION.Flags.
TargetFileObject:
这个操作所影响到的目标文件。
TargetInstance:
管理这个操作的实例。
Parameters:
FLT_PARAMETERS是一个共用体。
描述主功能号和辅功能号所指定的操作的具体参数。
ZKZUQsUJed
除了在预操作回调中不能修改主功能号之外,微过滤器可以修改这个结构中其他的任何参数。
如果参数改变,微过滤器应该调用FLT_SET_CALLBACK_DIRTY(>来注明这个改变。
更多详细的信息将在第8节中讲述。
dGY2mcoKtT
微过滤器在同一个I/O操作的预回调和后回调中,总是会看到参数是一样的。
即使下面的过滤器可能已经修改了这些参数。
这是由