NTSTATUS DPBitmapInit( DP_BITMAP ** bitmap, unsigned long sectorSize, unsigned long byteSize, unsigned long regionSize, unsigned long regionNumber ) { int i = 0; DP_BITMAP * myBitmap = NULL; NTSTATUS status = STATUS_SUCCESS; //检查参数,以免使用了错误的参数导致发生处零错等错误 if (NULL == bitmap || 0 == sectorSize || 0 == byteSize || 0 == regionSize || 0 == regionNumber) { return STATUS_UNSUCCESSFUL; } __try { //分配一个bitmap结构,这是无论如何都要分配的,这个结构相当于一个bitmap的handle if (NULL == (myBitmap = (DP_BITMAP*)DPBitmapAlloc(0, sizeof(DP_BITMAP)))) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } //清空结构 memset(myBitmap, 0, sizeof(DP_BITMAP)); //根据参数对结构中的成员进行赋值 myBitmap->sectorSize = sectorSize; myBitmap->byteSize = byteSize; myBitmap->regionSize = regionSize; myBitmap->regionNumber = regionNumber; myBitmap->regionReferSize = sectorSize * byteSize * regionSize; myBitmap->bitmapReferSize = (__int64)sectorSize * (__int64)byteSize * (__int64)regionSize * (__int64)regionNumber; //分配出regionNumber那么多个指向region的指针,这是一个指针数组 if (NULL == (myBitmap->Bitmap = (tBitmap **)DPBitmapAlloc(0, sizeof(tBitmap*) * regionNumber))) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } //清空指针数组 memset(myBitmap->Bitmap, 0, sizeof(tBitmap*) * regionNumber); * bitmap = myBitmap; status = STATUS_SUCCESS; } __except(EXCEPTION_EXECUTE_HANDLER) { status = STATUS_UNSUCCESSFUL; } if (!NT_SUCCESS(status)) { if (NULL != myBitmap) { DPBitmapFree(myBitmap); } * bitmap = NULL; } return status; }
NTSTATUS DPDispatchPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { //用来指向过滤设备的设备扩展的指针 PDP_FILTER_DEV_EXTENSION DevExt = DeviceObject->DeviceExtension; //返回值 NTSTATUS ntStatus = STATUS_SUCCESS; //用来指向irp stack的指针 PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp); switch(irpsp->MinorFunction) { case IRP_MN_REMOVE_DEVICE: //如果是PnP manager发过来的移除设备的irp,将进入这里 { //这里主要做一些清理工作 if (DevExt->ThreadTermFlag != TRUE && NULL != DevExt->ThreadHandle) { //如果线程还在运行的话需要停止它,这里通过设置线程停止运行的标志并且发送事件信息,让线程自己终止运行 DevExt->ThreadTermFlag = TRUE; KeSetEvent( &DevExt->ReqEvent, (KPRIORITY) 0, FALSE ); //等待线程结束 KeWaitForSingleObject( DevExt->ThreadHandle, Executive, KernelMode, FALSE, NULL ); //解除引用线程对象 ObDereferenceObject(DevExt->ThreadHandle); } if (NULL != DevExt->Bitmap) { //如果还有位图,就释放 DPBitmapFree(DevExt->Bitmap); } if (NULL != DevExt->LowerDevObj) { //如果存在着下层设备,就先去掉挂接 IoDetachDevice(DevExt->LowerDevObj); } if (NULL != DevExt->FltDevObj) { //如果存在过滤设备,就要删除它 IoDeleteDevice(DevExt->FltDevObj); } break; } //这个是PnP 管理器用来询问设备能否支持特殊文件的irp,作为卷的过滤驱动,我们必须处理 case IRP_MN_DEVICE_USAGE_NOTIFICATION: { BOOLEAN setPagable; //如果是询问是否支持休眠文件和dump文件,则直接下发给下层设备去处理 if (irpsp->Parameters.UsageNotification.Type != DeviceUsageTypePaging) { ntStatus = DPSendToNextDriver( DevExt->LowerDevObj, Irp); return ntStatus; } //这里等一下分页计数事件 ntStatus = KeWaitForSingleObject( &DevExt->PagingPathCountEvent, Executive, KernelMode, FALSE, NULL); //setPagable初始化为假,是没有设置过DO_POWER_PAGABLE的意思 setPagable = FALSE; if (!irpsp->Parameters.UsageNotification.InPath && DevExt->PagingPathCount == 1 ) { //如果是PnP manager通知我们将要删去分页文件,且我们目前只剩下最后一个分页文件的时候会进入这里 if (DeviceObject->Flags & DO_POWER_INRUSH) {} else { //到这里说明没有分页文件在这个设备上了,需要设置DO_POWER_PAGABLE这一位了 DeviceObject->Flags |= DO_POWER_PAGABLE; setPagable = TRUE; } } //到这里肯定是关于分页文件的是否可建立查询,或者是删除的通知,我们交给下层设备去做。这里需要用同步的方式给下层设备,也就是说要等待下层设备的返回 ntStatus = DPForwardIrpSync(DevExt->LowerDevObj,Irp); if (NT_SUCCESS(ntStatus)) { //如果发给下层设备的请求成功了,说明下层设备支持这个操作,会执行到这里 //在成功的条件下我们来改变我们自己的计数值,这样就能记录我们现在这个设备上到底有多少个分页文件 IoAdjustPagingPathCount( &DevExt->PagingPathCount, irpsp->Parameters.UsageNotification.InPath); if (irpsp->Parameters.UsageNotification.InPath) { if (DevExt->PagingPathCount == 1) { //如果这个请求是一个建立分页文件的查询请求,并且下层设备支持这个请求,而且这是第一个在这个设备上的分页文件,那么我们需要清除DO_POWER_PAGABLE位 DeviceObject->Flags &= ~DO_POWER_PAGABLE; } } } else { //到这里说明给下层设备发请求失败了,下层设备不支持这个请求,这时候我们需要把之前做过的操作还原 if (setPagable == TRUE) { //根据setPagable变量的值来判断我们之前是否做过对DO_POWER_PAGABLE的设置,如果有的话就清楚这个设置 DeviceObject->Flags &= ~DO_POWER_PAGABLE; setPagable = FALSE; } } //设置分页计数事件 KeSetEvent( &DevExt->PagingPathCountEvent, IO_NO_INCREMENT, FALSE ); //到这里我们就可以完成这个irp请求了 IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } default: break; } return DPSendToNextDriver( DevExt->LowerDevObj, Irp); }
NTSTATUS DPVolumeOnLineCompleteRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOLUME_ONLINE_CONTEXT Context ) { //返回值 NTSTATUS ntStatus = STATUS_SUCCESS; //这个卷设备的dos名字,也就是C,D等 UNICODE_STRING DosName = { 0 }; //在这里Context是不可能为空的,为空就是出错了 ASSERT(Context!=NULL); //下面调用我们自己的VolumeOnline处理 //获取这个卷的dos名字 ntStatus = IoVolumeDeviceToDosName(Context->DevExt->PhyDevObj, &DosName); if (!NT_SUCCESS(ntStatus)) goto ERROUT; //将dos名字变成大写形式 Context->DevExt->VolumeLetter = DosName.Buffer[0]; if (Context->DevExt->VolumeLetter > L'Z') Context->DevExt->VolumeLetter -= (L'a' - L'A'); //我们只保护“D”盘 if (Context->DevExt->VolumeLetter == L'D') { //获取这个卷的基本信息 ntStatus = DPQueryVolumeInformation( Context->DevExt->PhyDevObj, &(Context->DevExt->TotalSizeInByte), &(Context->DevExt->ClusterSizeInByte), &(Context->DevExt->SectorSizeInByte)); if (!NT_SUCCESS(ntStatus)) { goto ERROUT; } //建立这个卷对应的位图 ntStatus = DPBitmapInit( &Context->DevExt->Bitmap, Context->DevExt->SectorSizeInByte, 8, 25600, (DWORD)(Context->DevExt->TotalSizeInByte.QuadPart / (LONGLONG)(25600 * 8 * Context->DevExt->SectorSizeInByte)) + 1); if (!NT_SUCCESS(ntStatus)) goto ERROUT; //对全局量赋值,说明我们找到需要保护的那个设备了 gProtectDevExt = Context->DevExt; } ERROUT: if (!NT_SUCCESS(ntStatus)) { if (NULL != Context->DevExt->Bitmap) { DPBitmapFree(Context->DevExt->Bitmap); } if (NULL != Context->DevExt->TempFile) { ZwClose(Context->DevExt->TempFile); } } if (NULL != DosName.Buffer) { ExFreePool(DosName.Buffer); } //设置等待同步事件,这样可以让我们等待的DeviceIoControl处理过程继续运行 KeSetEvent( Context->Event, 0, FALSE); return STATUS_SUCCESS; }