Wiondows 查询卷设备信息代码实现

简介: NTSTATUS DPQueryVolumeInformation( PDEVICE_OBJECT DevObj, LARGE_INTEGER * TotalSize, DWORD * ClusterSize, DWO...
NTSTATUS DPQueryVolumeInformation( PDEVICE_OBJECT DevObj, LARGE_INTEGER * TotalSize, DWORD * ClusterSize, DWORD * SectorSize ) { #define _FileSystemNameLength 64 //定义FAT16文件系统签名的偏移量 #define FAT16_SIG_OFFSET 54 //定义FAT32文件系统签名的偏移量 #define FAT32_SIG_OFFSET 82 //定义NTFS文件系统签名的偏移量 #define NTFS_SIG_OFFSET 3 //这是FAT16文件系统的标志 const UCHAR FAT16FLG[4] = {'F','A','T','1'}; //这是FAT32文件系统的标志 const UCHAR FAT32FLG[4] = {'F','A','T','3'}; //这是NTFS文件系统的标志 const UCHAR NTFSFLG[4] = {'N','T','F','S'}; //返回值 NTSTATUS ntStatus = STATUS_SUCCESS; //用来读取卷DBR扇区的数据缓冲区 BYTE DBR[512] = { 0 }; //DBR扇区有512个bytes大小 ULONG DBRLength = 512; //以下是三个指针,统一指向读取的DBR数据,但是这三个指针的类型分别代表FAT16,FAT32和NTFS类型文件系统的DBR数据结构 PDP_NTFS_BOOT_SECTOR pNtfsBootSector = (PDP_NTFS_BOOT_SECTOR)DBR; PDP_FAT32_BOOT_SECTOR pFat32BootSector = (PDP_FAT32_BOOT_SECTOR)DBR; PDP_FAT16_BOOT_SECTOR pFat16BootSector = (PDP_FAT16_BOOT_SECTOR)DBR; //读取的偏移量,对于DBR来说是卷的起始位置,所以偏移量为0 LARGE_INTEGER readOffset = { 0 }; //读取时的io操作状态 IO_STATUS_BLOCK ios; //为了同步读取所设置的同步事件 KEVENT Event; //为了同步读取所需要构建的irp指针 PIRP pIrp = NULL; //下面我们首先从指定的卷设备上读取偏移量为0的一个扇区,也就是这个卷的DBR扇区,准备加以分析 //因为我们要同步读取,所以先初始化一个为了同步读取设置的事件 KeInitializeEvent(&Event, NotificationEvent, FALSE); //构造一个irp用来发给卷设备来读取信息 pIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ, DevObj, DBR, DBRLength, &readOffset, &ios ); if (NULL == pIrp) { goto ERROUT; } //设置完成函数,并且将同步事件作为完成函数的参数传入 IoSetCompletionRoutine( pIrp, DPQueryVolumeInformationCompletionRoutine, &Event, TRUE, TRUE, TRUE ); //调用目标设备去处理这个irp ntStatus = IoCallDriver(DevObj, pIrp); if(ntStatus = STATUS_PENDING) { //如果下层设备一时不能完成这个irp请求,我们就等 ntStatus = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); //将返回值设置为这个io操作的状态 ntStatus = pIrp->IoStatus.Status; if (!NT_SUCCESS(ntStatus)) { goto ERROUT; } } if (*(DWORD*)NTFSFLG == *(DWORD*)&DBR[NTFS_SIG_OFFSET]) { //通过比较标志发现这个卷是一个ntfs文件系统的卷,下面根据ntfs卷的DBR定义来对各种需要获取的值进行赋值操作 *SectorSize = (DWORD)(pNtfsBootSector->BytesPerSector); *ClusterSize = (*SectorSize) * (DWORD)(pNtfsBootSector->SectorsPerCluster); TotalSize->QuadPart = (LONGLONG)(*SectorSize) * (LONGLONG)pNtfsBootSector->TotalSectors; } else if (*(DWORD*)FAT32FLG == *(DWORD*)&DBR[FAT32_SIG_OFFSET]) { //通过比较标志发现这个卷是一个ntfs文件系统的卷,下面根据ntfs卷的DBR定义来对各种需要获取的值进行赋值操作 *SectorSize = (DWORD)(pFat32BootSector->BytesPerSector); *ClusterSize = (*SectorSize) * (DWORD)(pFat32BootSector->SectorsPerCluster); TotalSize->QuadPart = (LONGLONG)(*SectorSize) * (LONGLONG)(pFat32BootSector->LargeSectors + pFat32BootSector->Sectors); } else if (*(DWORD*)FAT16FLG == *(DWORD*)&DBR[FAT16_SIG_OFFSET]) { //通过比较标志发现这个卷是一个ntfs文件系统的卷,下面根据ntfs卷的DBR定义来对各种需要获取的值进行赋值操作 *SectorSize = (DWORD)(pFat16BootSector->BytesPerSector); *ClusterSize = (*SectorSize) * (DWORD)(pFat16BootSector->SectorsPerCluster); TotalSize->QuadPart = (LONGLONG)(*SectorSize) * (LONGLONG)(pFat16BootSector->LargeSectors + pFat16BootSector->Sectors); } else { //走到这里,可能是其它任何文件系统,但是不是windows认识的文件系统,我们统一返回错 ntStatus = STATUS_UNSUCCESSFUL; } ERROUT: if (NULL != pIrp) { IoFreeIrp(pIrp); } return ntStatus; } 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'); //我们只保护“F”盘 if (Context->DevExt->VolumeLetter == L'F') { //获取这个卷的基本信息 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; }
目录
相关文章
|
7月前
|
JavaScript 定位技术
详尽分享缓冲区点查询(在地图上点击一点,查询一定范围内的信息)
详尽分享缓冲区点查询(在地图上点击一点,查询一定范围内的信息)
37 0
|
8月前
|
JavaScript 算法 Java
看不惯各种信息收集表,我手写了一个身份证号输入组件
`shigen`是一位专注于Java、Python、Vue和Shell等技术的博主,分享知识和成长经历。为应对需频繁输入身份证号码的情况,`shigen`决定研究身份证校验机制。研究过程中,了解到身份证号码的生成规则,包括18位数字及校验码计算。通过编写JavaScript代码,实现了两个级别的身份证号码验证:一级仅检查基本格式,二级则加入校验码计算,确保符合生成规则。代码示例展示了逐步增强的验证功能,防止随意修改身份证号码。欢迎交流讨论,共同进步!
88 3
看不惯各种信息收集表,我手写了一个身份证号输入组件
|
8月前
|
存储 移动开发 小程序
利用微搭搭建信息查询小程序
利用微搭搭建信息查询小程序
|
8月前
|
API
uniapp开启蓝牙并判断搜索内容的方法
uniapp开启蓝牙并判断搜索内容的方法
237 0
|
数据挖掘 API
手机在网状态API 查询功能分析
手机在网状态API 查询功能分析
187 1
|
测试技术 API
API接口的测试步骤和返回数据展示
接口测试是软件测试中的一个重要环节,主要是为了验证软件的接口是否符合需求规范,是否能够正常地被调用。
132 0
|
JSON 前端开发 Java
基于Springboot外卖系统16:菜品修改模块+菜品信息回显+ID查询口味列表+组装数据并返回
在菜品管理列表页面点击修改按钮,跳转到修改菜品页面,在修改页面回显菜品相关信息并进行修改,最后点击确定按钮完成修改操作。
236 0
|
前端开发 容器
微搭低代码实现查询功能
微搭低代码实现查询功能
微搭低代码实现查询功能
|
JSON 测试技术 数据库
接口测试平台代码实现31:接口列表增删备注功能
接口测试平台代码实现31:接口列表增删备注功能
接口测试平台代码实现31:接口列表增删备注功能
|
存储 测试技术
接口测试平台代码实现32:接口列表备注功能
接口测试平台代码实现32:接口列表备注功能
接口测试平台代码实现32:接口列表备注功能