Wiondows 查询卷设备信息代码实现
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;
}