前面3篇,已经读完了绑定一个文件系统被挂载时,绑定的操作。这里得说一下总体的框架视角下,需要绑定的东西。
1:变动回调里实现绑定,这个绑定是文件系统被挂载或取消时,需要实现的。
2:变动回调已经掉过了,就是说文件过滤驱动已经加载,并运行。新来某个文件系统的储存设备,也需要绑定。
这里变动回调里面已经绑定了已经存在的卷设备,那么新加上来的存储设备,如何绑定?看下面:
在实际过程中,文件过滤驱动是在已经运行的OS上运行,那个时候已经有某个文件系统已经挂载了,如果这个时候新插一个同
文件系统的U盘,或其他的储存设备,这个时候的文件系统变动回调是不会被调用的。那么新上来的储存设备什么时候绑定呢?
这里就不得不说,为什么在DriverEntry里面要绑定文件系统的控制设备CDO了。目的只有一个,获取发送给文件系统控制设备的
文件系统控制请求。既是要获取的就是IRP_MJ_FILE_SYSTEM_CONTROL。从这些控制的IRP中能够得到足够的信息,确定一个
卷被挂载,这样才有可能去绑定文件系统的卷设备。
在第1篇的DriverEntry里面,设置IRP_MJ_FILE_SYSTEM_CONTROL时,已经提过。这个IRP会在一个新的存储设备被系统发现,并
在文件系统中生成一个与之对应的卷设备,这个过程的开始的时候,我们的文件过滤驱动就会收到这么一个IRP,同时,次功能号为:
IRP_MN_MOUNT。因为这个时候,我们的过滤驱动已经加载了,如果没加载之前就来了一个新的存储设备,那么我们的驱动加载时
走的路,就是变动回调里面绑定的过程。所以要说的,这个IRP_MJ_FILE_SYSTEM_CONTROL,是文件过滤驱动加载之后才会有的。
这句话是废话,可以忽略。
下面这个函数,在卷设备挂载或卸载的时候,都会被调用。在挂载的时候,绑定卷设备。
NTSTATUS
SpyFsControl (
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp
)
{
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp );
PAGED_CODE();
//
// 判断是否是我们自己的文件过滤驱动设备,该设备就是DriverEntry里面的IoCreateDevice创建的设备。
// 保存在全局变量:gControlDeviceObject 中的。
//
if (gControlDeviceObject == DeviceObject) {
//
// 判断是否设置了SPYDEBUG_TRACE_IRP_OPS标志位。如果设置了,调用函数:SpyDumpIrpOperation
// 该函数位于fpyLib.c中,相当简单。函数内部,1:获取IO_STACK_LOCATION,然后调用函数:GetIrpName
// 来获取IRP的Major功能号名和Minor功能号名,这个函数位于:irpNames.c中;
// 2:根据参数1,选择打印是pre操作还是post操作。
// 这个函数的作用就是打印log,无关紧要,可以不看。
//
if (FlagOn( gFileSpyDebugLevel, SPYDEBUG_TRACE_IRP_OPS )) {
SpyDumpIrpOperation( TRUE, Irp );
}
//
// 如果这个设备,是我们的文件控制设备,而不是一个挂载上来的卷设备,则是个无效请求,直接返回。
//
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_INVALID_DEVICE_REQUEST;
}
ASSERT(IS_FILESPY_DEVICE_OBJECT( DeviceObject ));
//
// 次功能号的处理。下面的次功能号的详细信息,参考:《文件过滤驱动中若干知识》中的第10点。
//
switch (pIrpSp->MinorFunction) {
case IRP_MN_MOUNT_VOLUME:
return SpyFsControlMountVolume ( DeviceObject, Irp );
case IRP_MN_LOAD_FILE_SYSTEM:
return SpyFsControlLoadFileSystem ( DeviceObject, Irp );
case IRP_MN_USER_FS_REQUEST:
{
switch (pIrpSp->Parameters.FileSystemControl.FsControlCode) {
case FSCTL_DISMOUNT_VOLUME:
{
PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
SPY_LOG_PRINT( SPYDEBUG_DISPLAY_ATTACHMENT_NAMES,
("FILESPY!SpyFsControl: Dismounting volume %p \"%wZ\"\n",
devExt->NLExtHeader.AttachedToDeviceObject,
&devExt->NLExtHeader.DeviceName) );
break;
}
}
break;
}
}
//
// 直接传递给默认派遣函数,后面说这个函数。
//
return SpyPassThrough( DeviceObject, Irp );
}