30岁左右的程序员,现在除了奋斗以外,要开始考虑下自己的身体了,到了这个年纪,不能像之前20岁左的年轻人一样不顾一切去拼搏。现在的自己,应该更讲究效率。所以选择公司也很重要。同样,运动开始变得必需了,要开始自己的运动计划,其实也是为了自己有更好的本钱去奋斗。去努力,还有一个考虑是这个年龄的程序员,已经不是一个人,正常的情况下,有儿子有老婆了,你的身体就变得更加的重要。所以,我们要爱惜自己的身体,为自己,为家人,为以后。

Writing a DriverEntry Routine for a Minifilter Driver

微小过滤驱动的DriverEntry例程执行一些全局变量的初始化,驱动注册,初始化过滤。这个例程运行在IRQL=PASSIVE_LEVEL的线程上下文。

Registering the Minifilter Driver
        
         在DriverEntry例程中调用FltRegisterFilter例程,加自己加入到已经注册的微小过滤驱动的列表中去,并给过滤管理器提供一组供其调用的回答函数。
  
          NTSTATUS status;
          status = FltRegisterFilter(
               DriverObject,                  //Driver
               &FilterRegistration,           //Registration
               &MiniSpyData.FilterHandle);    //RetFilter
     
         这里,我们主要看第二个参数,是一个输入参数,类型是FLT_REGISTRATION.
      
  typedef struct _FLT_REGISTRATION {
   USHORT                                       Size;
   USHORT                                       Version;
   FLT_REGISTRATION_FLAGS                       Flags;
   const FLT_CONTEXT_REGISTRATION             *ContextRegistration;
   const FLT_OPERATION_REGISTRATION          *OperationRegistration;
   PFLT_FILTER_UNLOAD_CALLBACK                 FilterUnloadCallback;
   PFLT_INSTANCE_SETUP_CALLBACK               InstanceSetupCallback;
   PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK       InstanceQueryTeardownCallback;
   PFLT_INSTANCE_TEARDOWN_CALLBACK        InstanceTeardownStartCallback;
   PFLT_INSTANCE_TEARDOWN_CALLBACK        InstanceTeardownCompleteCallback;
   PFLT_GENERATE_FILE_NAME                     GenerateFileNameCallback;
   PFLT_NORMALIZE_NAME_COMPONENT           NormalizeNameComponentCallback;
   PFLT_NORMALIZE_CONTEXT_CLEANUP           NormalizeContextCleanupCallback;
  #if FLT_MGR_LONGHORN
   PFLT_TRANSACTION_NOTIFICATION_CALLBACK      TransactionNotificationCallback;
   PFLT_NORMALIZE_NAME_COMPONENT_EX            NormalizeNameComponentExCallback;
  #endif 
  #ifdef FLT_MFG_WIN8
   PFLT_SECTION_CONFLICT_NOTIFICATION_CALLBACK SectionNotificationCallback;
  #endif 
   } FLT_REGISTRATION, *PFLT_REGISTRATION;
   
              这个结构体包含了所有的微小过滤驱动可以处理的操作的回调函数的地址。我们一个一个往下看:
   
   typedef struct _FLT_CONTEXT_REGISTRATION {
    FLT_CONTEXT_TYPE               ContextType;
    FLT_CONTEXT_REGISTRATION_FLAGS Flags;
    PFLT_CONTEXT_CLEANUP_CALLBACK  ContextCleanupCallback;
    SIZE_T                         Size;
    ULONG                          PoolTag;
    PFLT_CONTEXT_ALLOCATE_CALLBACK ContextAllocateCallback;
    PFLT_CONTEXT_FREE_CALLBACK     ContextFreeCallback;
    PVOID                          Reserved1;
   } FLT_CONTEXT_REGISTRATION, *PFLT_CONTEXT_REGISTRATION;
   
             这个我们在上面有看到过,这个是关于对象的上下文空间操作相关的回调函数,但是这个结构用得比较少。
   
            再看下一个:
   
   typedef struct _FLT_OPERATION_REGISTRATION {
    UCHAR                            MajorFunction;
    FLT_OPERATION_REGISTRATION_FLAGS Flags;
    PFLT_PRE_OPERATION_CALLBACK       PreOperation;
    PFLT_POST_OPERATION_CALLBACK     PostOperation;
    PVOID                            Reserved1;
   } FLT_OPERATION_REGISTRATION, *PFLT_OPERATION_REGISTRATION;
   
              我们之前讲到的,IO操作的预签延后操作的回调函数例程在这里定义。
   
              这里,主要是MajorFunction这个域,关于设备的我找到了一些,忽然发现,关于文件的比这多。
   
   Major Function Code      Hexadecimal Code 
   
   IRP_MJ_CREATE       0x00
 
   IRP_MJ_CREATE_NAMED_PIPE    0x01
 
   IRP_MJ_CLOSE       0x02
 
   IRP_MJ_READ        0x03
 
   IRP_MJ_WRITE       0x04
 
   IRP_MJ_QUERY_INFORMATION    0x05
 
   IRP_MJ_SET_INFORMATION     0x06
 
   IRP_MJ_QUERY_EA       0x07
 
   IRP_MJ_SET_EA       0x08
 
   IRP_MJ_FLUSH_BUFFERS     0x09
 
   IRP_MJ_QUERY_VOLUME_INFORMATION   0x0A
 
   IRP_MJ_SET_VOLUME_INFORMATION   0x0B
 
   IRP_MJ_DIRECTORY_CONTROL    0x0C
 
   IRP_MJ_FILE_SYSTEM_CONTROL    0x0D
 
   IRP_MJ_DEVICE_CONTROL     0x0E
 
   IRP_MJ_INTERNAL_DEVICE_CONTROL
   IRP_MJ_SCSI            0x0F
 
   IRP_MJ_SHUTDOWN       0x10
 
   IRP_MJ_LOCK_CONTROL      0x11
 
   IRP_MJ_CLEANUP       0x12
 
   IRP_MJ_CREATE_MAILSLOT     0x13
 
   IRP_MJ_QUERY_SECURITY     0x14
 
   IRP_MJ_SET_SECURITY      0x15
 
   IRP_MJ_POWER       0x16
 
   IRP_MJ_SYSTEM_CONTROL     0x17
 
   IRP_MJ_DEVICE_CHANGE     0x18
 
   IRP_MJ_QUERY_QUOTA      0x19
 
   IRP_MJ_SET_QUOTA      0x1A
 
   IRP_MJ_PNP
   IRP_MJ_MAXIMUM_FUNCTION     0x1B
   
    关于文件的好像比这多。
   
   IRP_MJ_CREATE

IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_DIRECTORY_CONTROL

IRP_MJ_FILE_SYSTEM_CONTROL

IRP_MJ_LOCK_CONTROL

IRP_MJ_PNP

IRP_MJ_QUERY_EA

IRP_MJ_QUERY_INFORMATION

IRP_MJ_QUERY_QUOTA

IRP_MJ_QUERY_SECURITY

IRP_MJ_QUERY_VOLUME_INFORMATION

IRP_MJ_READ

IRP_MJ_SET_EA

IRP_MJ_SET_INFORMATION

IRP_MJ_SET_QUOTA

IRP_MJ_SET_SECURITY

IRP_MJ_SET_VOLUME_INFORMATION

IRP_MJ_WRITE

IRP_MJ_ACQUIRE_FOR_MOD_WRITE

IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION

IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE

IRP_MJ_MDL_READ

IRP_MJ_MDL_READ_COMPLETE

IRP_MJ_MDL_WRITE_COMPLETE

IRP_MJ_NETWORK_QUERY_OPEN

IRP_MJ_PREPARE_MDL_WRITE

FLT_PARAMETERS for IRP_MJ_RELEASE_FOR_MOD_WRITE

IRP_MJ_VOLUME_MOUNT

The following I/O operations do not have parameters:

IRP_MJ_ACQUIRE_FOR_CC_FLUSH
   IRP_MJ_CLEANUP
   IRP_MJ_CLOSE
   IRP_MJ_FLUSH_BUFFERS
   IRP_MJ_RELEASE_FOR_CC_FLUSH
   IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION
   IRP_MJ_SHUTDOWN
   IRP_MJ_VOLUME_DISMOUNT
   
                 当然这里也应该包括文件快速IO.
   
   NTSTATUS status;
   status = FltRegisterFilter(
    DriverObject,                  //Driver
    &FilterRegistration,           //Registration
    &MiniSpyData.FilterHandle);    //RetFilter
    
                这里的第三个参数是一个输入参数,是一个过滤句柄。
   
                我们可以根据这个句柄,调用FltStartFiltering函数,通知过滤管理器,微小过滤驱动已经准备附加到卷上并进行过滤的IO操作。
   
   status = FltStartFiltering( MiniSpyData.FilterHandle );
   if( !NT_SUCCESS( status )) {
    FltUnregisterFilter( MiniSpyData.FilterHandle );
   }
   
                 Returning Status from a Minifilter DriverEntry Routine

在DriverEntry中应该返回合适的NTSTATUS值,如果不是成功的NTSTATUS值被返回FilterUnloadCallback

例程不会被调用,在这种情况下,DriverEntry例程必须释放所有分配的系统资源。

When the FilterUnloadCallback Routine Is Called

非强制的卸载
   
                Non-mandatory unload.这种类型的卸载,在用户模式的应用程序调用FilterUnload,或者内核模式驱动调用

FltUnloadFilter,或者通过命令fltmc unload发生。
   
                Mandatory unload:这里类型的卸载当通过sc stop 或net stop服务请求,用户模式应用程序调用

ControlService函数,传递SERVICE_CONTROL_STOP控制码的时候发生。
   
                对于非强制的卸载,如果微小过滤驱动的FilterUnloadCallback例程返回一个错误或者警告值,比如

STATUS_FLT_DO_NOT_DETACH,过滤管理器不会卸载驱动。
   
                对于强制卸载,不管FilterUnloadCallback返回什么值,过滤管理器都会卸载驱动。
   
               为了去关闭强制卸载功能,微小过滤可以设置FLT_REGISTRATION结构体的Flags成员为

FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP标志。

注意,在系统关机的时候,FilterUnloadCallback例程不会被调用。微小过滤驱动应该在

IRP_MJ_SHUTDOWN的预前操作的回调例程中执行一些操作。
   
               Writing a FilterUnloadCallback Routine
  
              在FilterUnloadCallback例程中,主要执行如下的事情:
   
              关闭所有内核模式下打开的交流服务端口的句柄。
   
              调用 FltCloseCommunicationPort,当用户模式已经打开了一个到交流服务端口的连接,这些连接在

FltCloseCommunicationPort仍然保持。
   
              调用FltUnRegisterFilter去反注册微小过滤驱动。
   
              调用这个函数会导致如下事情发生:
   
              微小过滤驱动的回调例程被卸载。
   
              微小驱动的实例被卸载, InstanceTeardownStartCallback and InstanceTeardownCompleteCallback对于

每一个过滤驱动的实例都会被调用。
   
              如果在卷,实例,流,流句柄上设置了上下文,这些上下文被删除,如果过滤驱动注册了CleanupContext

回调例程,过滤管理器在删除这些上下文之前会调用这些回调函数。如果有任何引用这个不透明的过滤句柄发生,

FltUnregisterFilter会进入等待状态,直到他们被删除。比如,过滤驱动调用FltQueueGenericWorkItem插入一个工作

到系统工作队列中,当这个工作项目还没有被处理。(过滤管理器将调用删除引擎在过滤驱动调用

FltQueueGenericWorkItem然后在工作例程中将其删除)。

还有一种情况是,过滤驱动调用调用了 FltObjectReference or FltGetFilterFromInstance,但是没有调用

FltObjectDereference的情况下。
    
              执行任何全局性的清除操作。
   
              调用ExDeleteResourceLite去删除预前通过调用ExInitializeResourceLite分配的全局资源。
   
              调用ExFreePool或者ExFreePoolWithTag去释放任何预前通过ExAllocatePoolWithTag分配的全局内存。
   
              调用 ExDeleteNPagedLookasideList or ExDeletePagedLookasideList 删除预前通过调用

ExInitializeNPagedLookasideList or ExInitializePagedLookasideList分配的lookaside.

调用Call PsRemoveCreateThreadNotifyRoutine or PsRemoveLoadImageNotifyRoutine 去

删除预前通过PsSetCreateThreadNotifyRoutine or PsSetLoadImageNotifyRoutine, 分配的全局回调例程。

返回合适的NTSTATUS值。
   
             一般返回STATUS_SUCCESS,为了重用不是强制的卸载操作,微小过滤驱动应该调用合适的警告或者错误值比如STATUS_FLT_DO_NOT_DETACH.
   
             Writing Preoperation and Postoperation Callback Routines

微小过滤驱动可以为其想过滤的每一种IO操作注册一个预签操作回调函数和一个延后操作回调函数。
   
            和原始的文件系统过滤驱动不一样,微小过滤驱动可以有选择的处理IO操作。它可以只为感兴趣的IO操作注册预前或者延后操作回调例程。
   
            预前操作回调例程和原始过滤驱动模式的派遣例程相类似。当过滤管理器处理IO操作的时候,它首先查看在微小过滤驱动实例堆栈中为这个IO操作已经注册了回调函数的微小过滤驱动,然后按照约定的顺序依次调用这些回调函数。最上层的函数,其实例有最高的高度值,除非微小过滤驱动已经完成了IO操作,否则,过滤管理器不会将操作发往原始过滤驱动和文件系统。

延后操作的回调例程和原始过滤驱动模式的完成例程很类似。完成例程在IO管理器将其操作传递到下层,等到处理,操作完成的时候,上层的完成例程被得到处理。过滤管理器首先调用有最低高度值的实例的延后操作的回调函数。依次向上传递调用。

Registering Preoperation and Postoperation Callback Routines
 
         面我们讲到,我们注册预前和延后操作回调函数是通过一个结构体,在FltReigisterFilter中注册的,这个结构体是 FLT_OPERATION_REGISTRATION 。
   
        数组中每一个 FLT_OPERATION_REGISTRATION 结构体都是一样的,除了最后一个。每一个都包含如下信息。

       操作的主功能码。
对于读写操作(IRP_MJ_READ and IRP_MJ_WRITE),需要设置flags,指定是否是缓存IO还是分页IO.
一个预前操作回调函数的入口点和一个延后操作回调函数的入口点。
数组中最后一个元素必须是{IRP_MJ_OPERATION_END}
const FLT_OPERATION_REGISTRATION Callbacks[] = {
{IRP_MJ_CREATE,
0,
ScannerPreCreate,
ScannerPostCreate},
{IRP_MJ_CLEANUP,
0,
ScannerPreCleanup,
NULL},
{IRP_MJ_WRITE,
0,
ScannerPreWrite,
NULL},
{IRP_MJ_OPERATION_END}
};
Filtering I/O Operations in a Minifilter Driver
如下是一些注册的约定。
IRP_MJ_CREATE的预前回调函数不能为文件,流,流的句柄,查询或者设置上下文。因为在预前创建的时间,将创建的文件或者流还没有被发现。
IRP_MJ_CLOSE的延后操作的回调函数不能为文件,流,和流的句柄设置或查询上下文。因为那些和其关联的系统内部结构在延后回调函数调用前被释放了。
对于IRP_MJ_CLEANUP或IRP_MJ_CLOSE操作,微小过滤驱动不应该返回失败。这些操作可以被暂停,返回给过滤管理器,通过STATUS_SUCCESS,然而,预前操作回调例程不应该返回失败。
微小过滤驱动不能够为IRP_MJ_SHUTDOWN注册延后操作的回调函数。
Writing Preoperation Callback Routines
如果例程对操作不进行干预,也不需要操作的最后的状态,或者没有为这个操作注册延后回调函数。  传递IO操作没有延后操作回调函数 返回FLT_PREOP_SUCCESS_NO_CALLBACK需要操作的最后状态。传递操作,需要调用延后操作回调函数。    返回FLT_PREOP_SUCCESS_WITH_CALLBACK

过滤驱动必须结束或者向在将来继续进行处理

将操作放在暂停状态,然后使用FltComplete 返回FLT_PREOP_PENDING.

PendedPreOperation.
                          
         延后操作处理必须和派遣例程的调用在同一个线程上下文空间里,这样确保IRQL和本地变量一致。  延后操作的同步

返回FLT_PREOP_SYNCHRONIZE

预前操作回调例程需要结束操作

停止操作,分配一个最终的NTSTATUS值  返回FLT_PREOP_COMPLETE
  
         像派遣例程一样,预前操作的回调例程在IRQL=PASSIVE_LEVEL或IRQL=APC_LEVEL上被调用。通常在IRQL=PASSIVE_LEVEL

的IO请求的原始线程上下文上被调用。对于快速IO和文件系统过滤操作,预前回调例程一直在IRQL=PASSIVE_LEVEL上被调用。
然而,对于基于IRP的操作,如果更高一层过滤或者微小过滤驱动通过工作线程暂停了操作流程,微小过滤驱动的预前回调例程可以在系统工作线程的上下文被调用。
上下文对象不能在IRQL > APC_LEVEL的延后操作回调例程中得到,而是,通过在预前操作得到上下文对象传递给延后操作的回调例程,或在IRQL <= APC_LEVEL上执行处理。
当过滤管理器对于给定的IO操作,调用微小过滤驱动的预前回调例程时,微小过滤驱动临时控制IO操作。微小过滤驱动将重新得到控制直到如下事情发生:
在预前操作回调函数中返回一个不是FLT_PREOP_PENDING的返回值。
在工作例程中调用FltCompletePendedPreOperation结束已经在预前回调函数中已经被暂停的操作。
Passing an I/O Operation Down the Minifilter Driver Instance Stack
当微小过滤驱动的预前回调函数或工作例程返回一个IO操作给过滤管理器,过滤管理器发送操作给微小过滤驱动实例堆栈的下层微小过滤驱动和原始过滤驱动和文件系统进行处理。
微小过滤的预前回调例程通过如下IO操作的状态值返回给过滤管理器。
FLT_PREOP_SUCCESS_NO_CALLBACK (all operation types)
FLT_PREOP_SUCCESS_WITH_CALLBACK (all operation types)
FLT_PREOP_SYNCHRONIZE (IRP-based I/O operations only)
虽然,FLT_PREO_SYNCHRONIZE应该仅仅只对预基于IRP的IO操作的返回,你也可以对另外的一些操作返回这些值。如果对不是基于IRP的IO操作返回这个值,过滤管理器将这个值当FLT_PREOP_SUCCESS_WITH_CALLBACK返回。
对于在预前回调例程中暂停的需要在工作例程进行处理的操作,返回IO操作的状态值是通过调用FltCompletePendedPreOperation重启暂停的IO插座后,设置CallbackStatus参数值返回的。
       Returning FLT_PREOP_SUCCESS_WITH_CALLBACK
     如果在微小过滤驱动的预前回调例程中返回FLT_PREOP_SUCCESS_WITH_CALLBACK,过滤管理器调用在IO完成的处理中调用微小过滤驱动的延后操作的回调函数。
注意:如果微小过滤驱动的预前回调函数返回FLT_PREOP_SUCCESS_WITH_CALLBACK,但是微小过滤驱动没有为其操作注册延后处理的回调函数,系统会发出了一个断言。
如果微小过滤驱动的预前回调函数返回FLT_PREOP_SUCCESS_WITH_CALLBACK,它可以在其输出参数中CompletionContext返回一个非空值。这个参数是一个可选的上下文指针,它会作为参数传递给延后操作的回调例程。延后操作的回调例程在其CompleteContext输入参数中接收到这个指针。
FLT_PREOP_SUCCESS_WITH_CALLBACK状态值可以被用来返回所有类型的IO操作。
Returning FLT_PREOP_SUCCESS_NO_CALLBACK
如果微小过滤驱动的预前操作的回调例程返回FLT_PREOP_SUCCESS_NO_CALLBACK,过滤管理器在IO完成处理中不会调用微小过滤驱动的延后操作的处理例程。
如果微小过滤驱动的预前操作的回调函数返回FLT_PREOP_SUCCESS_NO_CALLBACK,它必须在其输出参数CompletionContext中返回NULL.
FLT_PREOP_SUCCESS_NO_CALLBACK状态值可以被用来返回所有类型的IO操作。
Returning FLT_PREOP_SYNCHRONIZE
如果微小过滤驱动的预前回调函数例程中通过返回FLT_PREOP_SYNCHRONIZE来同步IO操作,过滤管理器在IO完成处理中,调用微小过滤驱动的延后操作的回调函数。
过滤管理器调用微小过滤驱动的延后操作的回调函数在和预前回调函数在同一个线程上下文空间上,在IRQL <= APC_LEVEL(这个是线程上下文,不需要是原始线程上下文)。
注意:如果微小过滤驱动的预前回调函数例程返回了FLT_PREOP_SYNCHRONIZE,但是,微小过滤驱动没有为其IO操作,注册延后回调例程,系统将发出一个断言。
如果微小过滤驱动的预前操作的回调例程返回FLT_PREOP_SYNCHRONIZE,它可以在其输出参数CompletionContext中返回一个非空值。这个参数是一个上下文空间的指针做为参数会传递给相应的延后操作的回调函数。延后操作的回调函数在CompletionConext输入参数中接收这个指针值。
微小过滤驱动的预前回调函数例程应该只对于基于IRP的IO操作返回FLT_PREOP_SYNCHRONIZE,如果,对于另外的操作类型,返回了这个值,过滤管理器将这个值当成FLT_PREOP_SUCCESS_WITH_CALLBACK看待。
为了去探测是不是基于IRP的IO茶轴,可以使用FLT_IS_OPERATION宏。
微小过滤驱动在其预前操作的回调函数中,对于创建操作,不应该返回FLT_PREOP_SYNCHRONIZE,因为这些操作已经被过滤管理器同步了。如果微小过滤驱动为IRP_MJ_CREATE操作已经注册了预前操作和延后操作的回调函数,延后操作的回调函数在IRQL=PASSIVE_LEVEL上被调用,和预前操作的回调函数在同一个线程上下文空间中。
微小过滤驱动禁止在其异步读或写操作返回FLT_PREOP_SYNCHRONIZE,这样操作,会严重降低微小过滤驱动和系统的表现,甚至会引起死锁。修改页写的线程被阻塞。在对基于IRP的读写操作,返回FLT_PREOP_SYNCHRONIZE之前,微小过滤驱动应该调用FltIsOpeationSynchronous函数检查操作是不是同步的。
如下的IO操作不能被同步:
对于文件系统控制操作的锁操作(FSCTL)(MajorFunction是IRP_MJ_FILE_SYSTEM_CONTROL,FsControlCode是FSCTL_REQUEST_FILTER_OPLOCK, FSCTL_REQUEST_BATCH_OPLOCK, FSCTL_REQUEST_OPLOCK_LEVEL_1, or FSCTL_REQUEST_OPLOCK_LEVEL_2)
改变目录操作的通知(MajorFunction is IRP_MJ_DIRECTORY_CONTROL; MinorFunction is IRP_MN_NOTIFY_CHANGE_DIRECTORY).
基于字节的锁请求(MajorFunction is IRP_MJ_LOCK_CONTROL; MinorFunction is IRP_MN_LOCK).
对于这些操作,不能使用FLT_PREOP_SYNCHRONIZE 返回。
Completing an I/O Operation in a Preoperation Callback Routine
结束IO操作意味着停止处理操作,发配一个NTSTAUS值,返回给过滤管理器。
当微小过滤驱动结束一个IO操作,过滤管理器执行如下的动作:
将操作不发往微小过滤驱动的下层微小过滤驱动,原始过滤驱动,或文件系统。
调用微小过滤驱动实例堆栈中的上层微小过滤过滤驱动的延后处理回调例程。
如果当前的微小过滤驱动存在延后处理的回调例程,过滤管理器不会调用它。
微小过滤驱动的预前操作的回调例程通过如下的步骤结束IO操作。
1,为操作设置回调数据结构的IoStatus.Status域为合适NTSTATUS值。
2,返回FLT_PREOP_COMPLETE.
预前操作的回调例程结束IO操作的时候,不要设置输出参数CompletionContext为一个非空值。
微小过滤驱动也可以通过如下的步骤,在预前暂停的IO操作,在工作例程将其结束。
1,为操作设置回调数据结构的IoStatus.Status域为合适NTSTATUS值。
2,在调用FltCompletePendedPreOperation的时候在其CallbackStatus传递为FLT_PREOP_COMPLETE.
当结束一个IO操作的时候,微小过滤驱动必须设置回调数据结构的IoStatus.Status域为一个最终的NTSTATUS值,但是这个NTSTATUS值不能是一个STATUS_PENDING或STATUS_FLT_DISALLOW_FAST_IO值。对于清除或关闭操作,这个预必须是STATUS_SUCCESS.这些操作不能是任何其他的NTSTATUS值。
结束IO操作,通常涉及到操作的成功还是失败,取决预NTSTATUS值。
为了成功IO操作,必须用一个代表成功或NTSTATUS信息值,比如STATUS_SUCCESS.
为了失败IO操作,可以使用一个代表失败或警告的NTSTATUS值,比如STATUS_INVALID_DEVICE_REQUEST or STATUS_BUFFER_OVERFLOW.
NTSTATUS值定义在ntstatus.h中,这些值分为四类,成功,信息,警告和错误。
Disallowing a Fast I/O Operation in a Preoperation Callback Routine
在某些情况下,微小过滤驱动可以选择禁止快速IO操作,而不是完成它。禁止快速IO操作可以避免快速IO的路径被用于操作。
和结束IO操作一样,禁止快速IO也意味着停止处理并将操作返回给过滤管理器。但是,禁止快速IO操作又跟完成它不一样。如果微小过滤驱动禁止了一个从IO管理器发送过来的一个快速IO,IO管理器可能重新发出一个基于IRP等价的操作。
当微小过滤驱动在预前操作的回调例程中禁止快速IO操作的时候,过滤管理器做如下的事情:
不会将请求发往微小过滤驱动的下层微小过滤驱动,原始过滤驱动,或文件系统。
调用当前微小过滤驱动实例堆栈的上层所有的微小过滤驱动延后操作的回调例程。
如果当前微小过滤驱动的延后操作回调例程存在,不调用它。
微小过滤驱动禁止一个快速IO操作,是通过在其预前操作回调例程中返回FLT_PREOP_DISALLOW_FASTIO实现的。
预前操作的回调例程不应该设置回调数据结构的IoStatus.Status域,因为过滤管理器会自动将其设置为STATUS_FLT_DISALLOW_FAST_IO.FLT_PREOP_DISALLOW_FASTIO仅仅只能对快速IO操作返回。为了去探测操作是不是快速IO操作,看FLT_IS_FASTIO_OPERATION.
微小过滤驱动不能对IRP_MJ_SHUTDOWN,IRP_MJ_VOLUME_MOUNT,或IRP_MJ_VOLUME_DISMOUNT操作返回FLT_PREOP_DISALLOW_FASTIO.
Pending an I/O Operation in a Preoperation Callback Routine
微小过滤驱动的预前回调例程可以返回FLT_PREOP_PENDING暂停IO操作,将操作发往系统工作队列中处理。返回这个状态值,声明微小过滤驱动重新获得IO操作的控制,直到调用FltCompletePendedPreOperation恢复IO操作的处理后。
微小过滤驱动的预前操作回调例程通过如下的步骤来暂停IO操作:
1,通过调用例程FltQueueDeferredIoWorkItem,发送IO操作到系统工作队列。
2,返回FLT_PREOP_PENDING.
微小过滤驱动必须暂停所有接收到的IO操作,不应该调用FltQueueDeferredIoWorkItem去暂停操作,因为调用这个例程将导致系统工作队列被冲突。而是,微小过滤驱动应该使用安全取消队列。可以看FltCbdqInitialize.
在下面的条件发生时,调用FltQueueDeferredIoWorkItem会失败:
操作不是基于IRP的IO操作。
操作是一个分页的IO操作。
当前线程的TopLevelIrp域不为空(怎样去找到这个值可以看IoGetTopLevelIrp).
如果微小过滤驱动的预签操作的回调函数返回FLT_PREOP_PENDING,它应该在其输出参数CompleteContext返回NULL.
微小过滤驱动只能对基于IRP的操作返回FLT_PREOP_PENDING.为了去探测操作是否是基于IRP的,看FLT_IS_IRP_OPERATION宏。
从队列中移除并处理IO操作的工作例程,应该调用FltCompletePendedPreOperation去恢复操作的处理。
Writing Postoperation Callback Routines
在延后操作的回调例程中可以做如下的操作;
在回调例程中直接完成工作。所有的完成工作都必须在IRQL <= DISPATCH_LEVEL上进行。
完成结束工作在安全的IRQL上,返回FLT_STATUS_MORE_PROCESSING_REQUIRED将工作重新排到工作线程中去。当工作线程调用FltCompletePendedPostOperation进行延后的处理。
安全取消创建操作。
延后操作的回调例程和原始过滤驱动中的完成例程很类似。
延后操作的回调例程的注册和预前操作的回调例程的注册是一样的。
typedef FLT_POSTOP_CALLBACK_STATUS
(*PFLT_POST_OPERATION_CALLBACK) (
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN PVOID CompletionContext,
IN FLT_POST_OPERATION_FLAGS Flags
);
像完成例程一样,延后操作的回调例程也是在IRQL <= DISPATCH_LEVEL的线程上下文空间被调用。
因为可以在IRQL = DISPATCH_LEVEL上被调用,延后操作回调例程不能够调用那些必须在低优先级下的例程,比如FltLockUseBuffer或RtlCompareUnicodeString.同样的原因,在延后操作回调例程中使用的任何数据结构都必须在非分页内存空间中分配空间。
但是,如下有些情况是例外:
如果微小过滤驱动的预前操作回调例程对于基于IRP的操作返回FLT_PREOP_SYNCHRONIZE,相应的延后操作的回调例程在IRQL <= APC_LEVEL,和预前操作的回调函数运行
在同一个线程上下文空间上。
延后操作回调函数对于快速IO操作在IRQL = PASSIVE_LEVEL上被调用,和预前操作的回调函数在同一个线程上下文空间上。
延后操作的回调函数在IRQL = PASSIVE_LEVEL上被调用,和IRP_MJ_CREATE操作的原始线程上下文在同一个空间。
当过滤管理器调用微小过滤驱动的延后操作的回调函数对给定的IO操作进行处理的时候,微小过滤驱动临时控制IO操作,微小过滤驱动保留控制直到如下的事情发生:
在延后操作的回调例程中返回FLT_POSTOP_FINISHED_PROCESSING.
在延后操作回调例程中被暂停的基于IRP的IO操作,在工作例程中调用FltCompletePendedPostOperation后。
Performing Completion Processing for an I/O Operation
当IO操作被文件系统,原始过滤驱动,或者在微小过滤驱动实例堆栈的更低高度值的微小过滤驱动完成的时候,微小过滤驱动的延后操作的回调例程被调用。
另外,当微小过滤驱动的实例被卸载,过滤管理器对于实例在预前操作回调例程中接收到的在延后操作回调例程中等待的IO操作,进行释放。在这种情况下,
过滤管理器调用微小过滤驱动的延后回调函数,甚至IO操作都没有被结束,并在其Flags的输入参数中设置FLTFL_POST_OPERATION_DRAING.
当flag被设置为FLTFL_POST_OPERATION_DRAINING,微小过滤驱动禁止执行普通的结束操作。而是,执行任何需要的清除,比如释放那些在其预前操作回调分配的装入到CompletionContext参数的内存。然后返回FLT_POSTOP_FINISHED_PROCESSING.
Ensuring that Completion Processing is Performed at Safe IRQL
但是对于那些基于IRP的IO操作,没有被准备同步,可以使用如下两种方法来确保其完成操作的执行在IRQL <= APC_LEVEL上。
第一种方法是对于在延后操作的回调函数中暂停操作,直到完成操作被在IRQL <= APC_LEVEL上处理。
第二种方法是对于延后操作的回调函数调用FltDoCompletionProcessingWhenSafe。FltDoCompletionProcessingWhenSafe仅仅在IRQL >= DISPATCH_LEVEL上暂停IO的处理。
否则,这个例程立即执行微小过滤驱动的safePostCallback例程。
Pending an I/O Operation in a Postoperation Callback Routine
微小过滤驱动的延后操作的回调例程可以通过如下的步骤来暂停IO的操作。
1,调用FltAllocateDeferredIoWorkItem为IO操作分配工作项目。
2,调用FltQueueDeferredIoWorkItem发送IO操作到系统的工作队列。
3,返回FLT_POSTOP_MORE_PROCESSING_REQUIRED.
如果如下的条件为真,调用FltQueueDeferredIoWorkItem会失败。
操作不是基于IRP的IO操作。
操作是一个分页的IO操作。
当前线程的TopLevelIrp是不为NULL的。(可以通过IoGetTopLevelIrp得到这个域)。
IO操作的目标实例正在被卸载(过滤管理器声明这个条件是通过在延后操作的回调函数中设置输入参数Flags为FLTFL_POST_OPERATION_DRAINING).
小过滤驱动应该准备去处理这样的失败。如果你的驱动不能处理这样的失败,你应该考虑在你的延后操作的回调函数中返回FLT_PREOP_SYNCHRONIZE而不是暂停IO操作。
微小过滤驱动的延后操作的回调例程返回FLT_POSTOP_MORE_PROCESSING_REQUIRED以后,过滤管理器不会在为IO操作执行任何进一步的完成操作,直到微小过滤驱动的工作例程调用FltCompletePendedPostOperation将控制返回给过滤管理器。过滤管理器在这种条件下,不会执行任何进一不的操作,甚至工作例程为操作设置回调数据结构IoStatus.Status域为一个失败的NTSTATUS值。
在工作例程中,将工作项目从队列中取出,执行完成操作,然后调用FltCompletePendedPostOperation返回控制给过滤管理器。
Failing an I/O Operation in a Postoperation Callback Routine
微小过滤驱动的延后操作的回调例程可以失败一个IO操作,简单的失败一个IO操作,不会引起操作的取消。微小过滤驱动需要做一些处理让IO操作取消。
举例来说,微小过滤驱动的延后回调函数可以通过如下的步骤去失败一个IRP_MJ_CREATE操作:
1,调用FltCancelFiltOpen去关闭被创建的文件或通过创建操作去打开的文件。注意:FltCancelFileOpen不会取消任何对文件的修改。举例来说:
FltCancelFileOpen不会删除一个新创建的文件或者或者截断文件装入到它之前的大小。
2,设置回调数据结构的IoStauts.Status域为操作的最终的NTSTATUS值。这个值必须是一个有效的错误的NTSTATUS值,比如STATUS_ACCESS_DENIED.
3,设置回调数据结构的IoStatus.Information域的值为0.
4,返回FLT_POSTOP_FINISHED_PROCESSING.
FltCancelFileOpen的调用者必须运行在IRQL <= APC_LEVEL上,微小过滤驱动在为IRP_MJ_CREATE的延后回调函数在可以安全的调用这个函数,因为其IRQL=PASSIVE_LEVEL上,
在创建操作的原始线程上下文空间上。
Modifying the Parameters for an I/O Operation
微小过滤驱动可以为IO操作修改参数。举例来说,微小过滤驱动的预前操作的回调例程可以通过改变操作的目标实例重定位IO操作到不同的卷。新的目标实例和现在的实例必须来自同一个微小过滤驱动,而且在另一个卷上有同样的高度值。
IO操作的参数可以在回调数据结构(FLT_CALLBACK_DATA)和为操作的IO参数快结构(FLT_IO_PARAMETER_BLOCK)中找到.微小过滤驱动的预前和延后回调例程在其输入参数Data中将接收到一个指向回调数据结构的指针。回调数据结构的lopb成员指向IO参数块数据结构。
如果微小过滤驱动的预前回调例程为IO操作修改了其参数。那么在微小过滤驱动实例堆栈中的下层所有的过滤驱动的预前和延后回调例程都将接收到修改的参数。
改的参数不能被当前微小过滤驱动的延后回调函数得到,也不能被微小过滤驱动实例堆栈中的上层所有的微小过滤驱动得到。在所有的条件下,微小过滤驱动的预前和延后回调例程对于给定的IO操作都将接收到同样的输入参数值。
修改了IO操作的参数以后,预前和延后回调例程必须调用FltSetCallbackDataDirty声明它做的修改,除非,它已经修改了回调数据结构的IoStatus域。否则,、过滤管理器将忽略对参数说做的所有修改。FltSetCallbackDataDirty为IO操作设置了回调数据结构的flag为FLTFL_CALLBACK_DATA_DIRTY。微小过滤驱动可以通过测试flag,通过调用FltIsCallbackDataDirty或FltClearCallbackDataDirty.
如果微小过滤驱动预前回调例程为IO操作修改了参数,所有在微小过滤驱动实例堆栈下层的驱动在其预前和延后回调例程的输入参数Data和FltObjects接收到修改的参数。(微小过滤驱动不能够直接修改FltObjects参数的内容,因为它是一个指向FLT_RELATED_OBJECT结构的指针。但是,如果微小过滤驱动为IO操作修改了目标实例或目标文件对象,过滤管理器会修改FLT_RELATED_OBJECTS结构相应的Instance或FileObject,并将其传递到下层的微小过滤驱动)
虽然,在微小过滤驱动的预前回调例程中对参数的修改,其延后回调例程中得不到通知,预前回调例程可以将其修改参数的信息传递给自己的延后回调例程。如果预前回调例程通过返回FLT_PREOP_SUCCESS_WITH_CALLBACK或FLT_PREOP_SYNCHRONIZE传递IO到下层堆栈,它可以将参数修改的信息放入微小过滤驱动定义的CompletionContext输出参数中,过滤管理器将传递这个结构体的指针做出输入参数传递到延后操作的回调例程中。
Determining the Buffering Method for an I/O Operation
像设备驱动一样,文件系统也需要在用户模式应用程序和系统设备之间传输数据。操作系统提供如下的三种方式来访问数据空间。
缓冲区IO方式,IO管理器为操作在非分页内存区域分配一个系统空间。IO管理器从系统空间拷贝数据到应用程序的用户空间,初始化IO操作的线程上下文空间中。反之亦然。
直接IO,IO管理器探测并锁住用户空间。然后创建一个MDL来映射锁住的空间。IO管理器访问初始化IO操作的线程上下文空间。
既不是缓冲区IO,又不是直接IO。IO管理器既不分配系统空间也不锁住用户空间,而是,它直接将原始的用户模式的虚拟地址直接传递到文件系统堆栈。由驱动来保证空间得之的有效性,
并在初始化的线程上下文执行数据拷贝操作。
微小过滤驱动必须在使用用户模式地址前对其地址进行有效性检验。IO管理器和过滤管理器不会验证这些地址,也不会验证传递给微小过滤驱动的指向内部空间的指针的有效性。
所有微软标准的文件系统使用的一般都是第三种方式,既不是缓冲区IO,也不是直接IO.
对于基于IRP的IO操作,访问方法的选择必须依赖特定的操作,一般通过如下的方式:
正在执行的IO操作的类型
文件系统卷的DEVICE_OBJECT的Flags的值。
对于IO控制操作(IOCTL)和文件系统控制操作(FSCTL),IOCTL或FSCTL被定义的传递给CTL_CODE宏TransferTye参数的值。
对于拥有空间的IO操作,通常也使用既不是缓冲区,也不是直接IO的方式。
文件系统回调操作没有缓冲区。
Operations That Can Be IRP-Based or Fast I/O
下面的操作类型既可使是基于IRP也可以是快速IO类型:
IRP_MJ_DEVICE_CONTROL (IRP_MJ_INTERNAL_DEVICE_CONTROL一直是基于IRP的)。
IRP_MJ_QUERY_INFORMAITION,这个域如果FileInformationClass参数是FileBasicInformation, FileStandardInformation, or FileNetworkOpenInformation. 它是快速IO的。
IRP_MJ_READ.微小过滤驱动可以设置FLT_OPERATION_REGISTRATION结构体中的flag为 FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO,可以避免接收到快速IO的类型的IRP_MJ_READ和基于缓存的IRP读请求。
IRP_MJ_WRITE.微小过滤驱动可以设置FLT_OPERATION_REGISTRATION结构体中的flag为 FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO,可以避免接收到快速IO的类型的IRP_MJ_WRITE和基于缓存的IRP写请求。
当任何这些操作是快速IO操作,它通常使用既不是缓冲IO也不是直接IO,即使等价基于IRP的操作使用不同的访问空间的方法。
当IRP_MJ_DEVICE_CONTROL是一个快速IO操作,它就使用既不是缓冲去也不是直接IO的访问方法,不管IOCTL的传输类型。
虽然IRP_MJ_LOCK_CONTROL可以是基于IRP或者快速IO的,但是它没有空间。
IRP-Based I/O Operations That Obey Device Object Flags
如下基于IRP的IO操作,数据访问方法,通过检测文件系统卷的设备对象的Flags的值。
IRP_MJ_DIRECTORY_CONTROL
IRP_MJ_QUERY_EA
IRP_MJ_QUERY_QUOTA
IRP_MJ_READ
IRP_MJ_SET_EA
IRP_MJ_SET_QUOTA
IRP_MJ_WRITE
DO_BUFFERED_IO和DO_DIRECT_IO在Flags成员的使用:
如果DO_BUFFERED_IO标志被设置,操作使用缓冲区IO.
如果DO_DIRECT_IO标志被设置,DO_BUFFERED_IO没有被设置,操作使用直接IO.
如果权限都没有被设置,操作使用既不是缓冲区的也不是直接IO的。
注意:IRP_MJ_READ和IRP_MJ_WRITE可以是基于IRP的操作也可以是基于快速IO的操作。当他们是基于IRP的操作,空间访问方法通过上面的设备对象的flags来指定。当这些操作是基于快速IO的,它们既不使用缓冲区也不是用直接IO。
IRP-Based I/O Operations That Always Use Buffered I/O
如下基于IRP的IO操作一直使用缓冲区IO.不管文件系统卷设备对象的Flags的值:
IRP_MJ_CREATE (EaBuffer parameter)
IRP_MJ_QUERY_INFORMATION
IRP_MJ_QUERY_VOLUME_INFORMATION
IRP_MJ_SET_INFORMATION
IRP_MJ_SET_VOLUME_INFORMATION
注意:IRP_MJ_QUERY_INFORMATION也可以是快速IO操作。当其是快速IO的操作,既不使用缓冲区也不是用直接IO.
IRP-Based I/O Operations That Always Use Neither Buffered Nor Direct I/O
如下基于IRP的IO操作中是使用既不是缓冲区也不是直接IO的方式,不管文件系统卷的设备对象的Flags的值
IRP_MJ_PNP
IRP_MJ_QUERY_SECURITY
IRP_MJ_SET_SECURITY
IRP_MJ_SYSTEM_CONTROL
IRP-Based IOCTL and FSCTL Operations
如下基于IRP的IO操作,数据的访问方法需要根据IOCTL或FSCTL中指定的传输类型决定。
IRP_MJ_DEVICE_CONTROL
IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_INTERNAL_DEVICE_CONTROL
传输类型在CTL_CODE宏的TransferTyep参数指定,为了去得到IOCTL或FSCTL的传输类型,可以使用如下宏
#define METHOD_FROM_CTL_CODE(ctrlCode)         ((ULONG)(ctrlCode & 3))
宏的返回值:
#define METHOD_BUFFERED                 0
#define METHOD_IN_DIRECT                1
#define METHOD_OUT_DIRECT               2
#define METHOD_NEITHER                  3
注意:IRP_MJ_DEVICE_CONTROL也可以是快速IO操作。当它是快速IO操作,它使用既不是缓冲区也不是直接IO的方式访问,不管传输类型。
IRP-Based I/O Operations That Have No Buffers
如下基于IRP的IO操作没有空间,所以也就没有缓冲区方式访问。
IRP_MJ_CREATE_MAILSLOT
IRP_MJ_CREATE_NAMED_PIPE
IRP_MJ_LOCK_CONTROL
Accessing the User Buffers for an I/O Operation
IO操作的结构FLT_PARAMETERS结构体包含一些为操作指定的参数,包含空间内存地址,空间的MDL等。
对于基于IRP的IO操作,操作的空间可以通过如下如下指定:
仅仅MDL (通常是分页IO)
仅仅空间地址。
空间地址和MDL.
对于快速IO操作,仅仅只有用户空间地址被指定。快速IO操作使用空间都是通过既不是缓冲区也不是直接IO,所以也没有MDL参数。
Accessing User Buffers in a Preoperation Callback Routine
微小过滤驱动的预前回调例程对基于IRP的IO操作,应该按如下的方式来对待空间。
检查空间是否存在相应的MDL.MDL的指针可以在操作的FLT_PARAMETERS结构体中的MdlAddress或OutputMdlAddress参数中找到。微小过滤驱动可以调用FltDecodeParameters去查询MDL的指针。
一种得到有效MDL的方法是,通过寻找在回调数据的IO参数控制块数据结构的FLT_IO_PARAMETER_BLOCK中的成员MinorFunction的IRP_MN_MDL标志。
NTSTATUS status;
PMDL *ReadMdl = NULL;
PVOID ReadAddress = NULL;
if (FlagOn(CallbackData->Iopb->MinorFunction, IRP_MN_MDL))
{
ReadMdl = &CallbackData->Iopb->Parameters.Read.MdlAddress;
}
然而,IRP_MN_MDL标志只能被设置用于读和写操作。最好使用FltDecodeParameters例程得到MDL,因为它对于所有的操作检查MDL的有效性。
NTSTATUS status;
PMDL *ReadMdl = NULL;
PVOID ReadAddress = NULL;
status = FltDecodeParameters(CallbackData, &ReadMdl, NULL, NULL, NULL);
如果空间存在一个MDL,调用MmGetSystemAddressForMdlSafe得到空间的系统地址,然后使用这个地址访问数据。
if (*ReadMdl != NULL)
{
ReadAddress = MmGetSystemAddressForMdlSafe(*ReadMdl, NormalPagePriority);
if (ReadAddress == NULL)
{
CallbackData->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
CallbackData->IoStatus.Information = 0;
}
}
如果空间没有MDL,使用空间地址去访问数据。为了确保用户空间的地址有效,微小过滤驱动必须使用如下例程ProbeForRead或ProbeForWrite,所有的空间引用都需要在try/except块中。
预前操作的回调函数在快速IO操作,应该按如下的方式对待空间。
使用空间地址去访问数据(因为快速IO操作没有MDL).
为了确保用户空间地址有效,微小过滤驱动必须使用如下例程ProbeForRead或ProbeForWrite,所有的空间引用都需要在try/except块中。
对于既可能是基于IRP又可能是快速IO类型的操作,所有的空间引用都应该在try/execpt块中,虽然对于那些基于IRP的缓冲区IO,不需要使用这样的安全保护。
Accessing User Buffers in a Postoperation Callback Routine
微小过滤驱动的延后回调例程对基于IRP的IO操作,应该按如下的方式来对待空间。
检查空间是否存在相应的MDL.MDL的指针可以在操作的FLT_PARAMETERS结构体中的MdlAddress或OutputMdlAddress参数中找到。微小过滤驱动可以调用FltDecodeParameters去查询MDL的指针。
一种得到有效MDL的方法是,通过寻找在回调数据的IO参数控制块数据结构的FLT_IO_PARAMETER_BLOCK中的成员MinorFunction的IRP_MN_MDL标志。
NTSTATUS status;
PMDL *ReadMdl = NULL;
PVOID ReadAddress = NULL;
if (FlagOn(CallbackData->Iopb->MinorFunction, IRP_MN_MDL))
{
ReadMdl = &CallbackData->Iopb->Parameters.Read.MdlAddress;
}
然而,IRP_MN_MDL标志只能被设置用于读和写操作。最好使用FltDecodeParameters例程得到MDL,因为它对于所有的操作检查MDL的有效性。
NTSTATUS status;
PMDL *ReadMdl = NULL;
PVOID ReadAddress = NULL;
status = FltDecodeParameters(CallbackData, &ReadMdl, NULL, NULL, NULL);
如果空间存在一个MDL,调用MmGetSystemAddressForMdlSafe得到空间的系统地址,然后使用这个地址访问数据。
if (*ReadMdl != NULL)
{
ReadAddress = MmGetSystemAddressForMdlSafe(*ReadMdl, NormalPagePriority);
if (ReadAddress == NULL)
{
CallbackData->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
CallbackData->IoStatus.Information = 0;
}
}
如果空间没有MDL,通过FLT_IS_SYSTEM_BUFFER宏检查,是否系统缓冲标志被设置。
如果FLT_IS_SYSTEM_BUFFER宏返回TRUE,操作使用的是缓冲区IO,空间可以在IRQL=DISPATCH_LEVEL上安全被访问。
如果FLT_IS_SYSTEM_BUFFER宏返回FALSE,空间不能够在IRQL=DISPATCH_LEVEL被安全访问。如果延后回调例程可以在DISPATCH_LEVEL上被调用。它必须调用FltDoCompletionProcessingWhenSafe去暂停操作直到IRQL <= APC_LEVEL上被处理。FltDoCompletionProcessingWhenSafe的参数SafePostCallback指向的回调例程,应该首先调用FltLockUserBuffer去锁定空间,然后调用MmGetSystemAddressForMdlSafe得到空间的系统地址。
延后操作的回调函数应该在快速IO操作,按照如下的方式来对待空间:
使用空间地址去访问数据(对于快速IO操作,没有MDL).
为了确保用户模式的地址空间有效,微小过滤驱动使用ProbeForRead或ProbeForWrite这样的例程,所有对空间的引用都在try/excetpu块中。
延后操作的回调函数对快速IO的处理需要保证在正确的线程上下文被调用。
延后操作的回调函数对快速IO的处理被保证在IRQL <=APC_LEVEL上被处理,额可以安全的调用FltLockUserBuffer这样的例程。
如下的代码演示了为目录控制操作检查系统空间或快速IO标志,在需要的时候延迟完成操作的处理。
if (*DirectoryControlMdl == NULL)
{
if (FLT_IS_SYSTEM_BUFFER(CallbackData) || FLT_IS_FASTIO_OPERATION(CallbackData))
{
dirBuffer = CallbackData->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
}
else
{
// Defer processing until safe.
if (!FltDoCompletionProcessingWhenSafe(CallbackData, FltObjects, CompletionContext, Flags, Proce ssPostDirCtrlWhenSafe, &retValue))
{
CallbackData->IoStatus.Status = STATUS_UNSUCCESSFUL;
CallbackData->IoStatus.Information = 0;
}
}
}
对于既可能是基于IRP又可能是快速IO类型的操作,所有的空间引用都应该在try/execpt块中,虽然对于那些基于IRP的缓冲区IO,不需要使用这样的安全保护。

Windows驱动_文件系统微小过滤驱动之三微小过滤驱动的操作相关推荐

  1. Windows驱动_文件系统微小过滤驱动之一初识MiniFilter

    人的一生,就那么几十年,所有的人都无法知道下一刻会发生什么,我们活在当下,只能努力将自己目前的工作或生活过好.船到桥头自然直,况且,自己这么多年,经历了多多少少的风浪太多了,说到底还是不够自信,我应该 ...

  2. exfat linux 驱动_(实例)Linux 内核添加exfat驱动

    背景: 由于exfat是常用的文件系统格式,而Linux由于版权的问题,没有在官方中添加有关的驱动. 但是 微软也同意开源了,所以比较新的 Linux 会支持这一块. 为了支持exfat的驱动,我们需 ...

  3. python 仪表驱动_技术文章 | 锐视模块化仪器python驱动使用说明

    原标题:技术文章 | 锐视模块化仪器python驱动使用说明 简仪的硬件驱动都是使用C#用统一接口包装的,所有的MACOs都是开放型的,有明确的方法(Methods)和属性(Properties)定义 ...

  4. Windows驱动_文件系统微小过滤驱动之二驱动的安装和加载

    机会总是留给有准备的人,人生只不过有6到7次机会,极少数的人抓住了,大部分的人,让机会从自己的身边溜走.在机会还没有到来的时候,千万不要气馁,也千万不要放弃.首先,认清自己,很多人,其实都没有将自己认 ...

  5. 联想小新触摸板驱动_如何下载并安装触控板驱动

    操作步骤: 一.Lenovo系列电脑 1.点击这里打开联想官方网站,在示例的位置输入主机编号后,点击"搜索"按钮,查找本机所带的驱动: 2.在操作系统列表中选择对应的操作系统: 3 ...

  6. ac3165 linux驱动_为什么Linux系统没有类似Windows上的还原精灵和影子系统?

    很多从Windows转Linux的用户,面临的最大一个问题,就是Linux上没有还原精灵这种软件.众所周知,作为一个操作系统要想普及,绝不可能只针对懂IT的少部分年轻人,而是需要让不同年龄段,不同职业 ...

  7. 服务器网卡驱动_教你星际蜗牛C款i211网卡服务器咋装Windows sevs2012R2服务器下

    原文作者:诸葛东流 说明 把i211网卡驱动解决,其它驱动都好解决了,用驱动软件可以联网更新驱动:再就是无线WIFI开启设置. 装Windows sevse 2012 R2服务器装机篇 现在说说,无线 ...

  8. 二氧化碳传感器CCS811简单的测试驱动_基于Arduino

    二氧化碳传感器CCS811简单的测试驱动_基于Arduino 目的 简单介绍 由于MOX Sensor材料特性在使用过程中要注意的问题 IC的初始化过程 IC的读数据过程 可配置参数 完整程序代码 数 ...

  9. linux内核源码实战_3.2理解设备驱动和文件系统

    linux内核源码实战_3.2理解设备驱动和文件系统 linux内核源码实战_理解设备驱动和文件系统 理解设备驱动和文件系统 理解设备驱动和文件系统详解 7-文件系统-proc文件系统实现 总结 li ...

最新文章

  1. elasticsearch分布式搜索配置文件详解
  2. android之descendantFocusability用法简析
  3. python是一门什么课程-为什么一定要让孩子学会一门编程语言?
  4. 数组黑科技(偏性能方面)未完待更新...
  5. Spring Security配置错误
  6. 大数计算器概念c语言,用C语言求两个超大整数的和
  7. 这就是飞秋下载早期的学习生涯
  8. 商业智能改变汽车行业
  9. 计算机算法设计与分析 旅行售货员问题
  10. 【caffe】caffe采用multistep,绘制loss曲线出错
  11. spring security reactive获取security context
  12. 【SENCHA TOUCH】改了tomcat的IP访问!java的session失效问题! [ Web 开发]
  13. 用Python写一个记忆翻牌小游戏呀!
  14. B站陈睿团队以内容为王,百万UP主共同成长
  15. HDU 5442 (串的最大表示+KMP)
  16. python爬虫-selenium爬取链家网房源信息
  17. 骑行318、 2016.7.20
  18. 2.6_11 Redis主从复制、哨兵模式、分片集群
  19. 华为云存储服务分享文件的方法
  20. @Reference是干啥的

热门文章

  1. ESP8266(ESP-12F) 第三方库使用 -- SparkFun_APDS9960 (手势识别)
  2. c语言结构体编辑学生成绩管理,【C语言】结构体的应用以及学生成绩管理系统的设计...
  3. 记一则SQL 数据库状态(可疑)(紧急)解决方案
  4. SQL Server高级子查询
  5. simp服务器协议,Redis协议(RESP)规范
  6. 基于HDP版本的YDB安装部署(转)
  7. 超星系统登录,信息爬取
  8. 考研高等数学公式(数学一)
  9. java程序设计汇报ppt_Java程序设计第五章.ppt
  10. log4j.proprties