这次在编写一个windows下的虚拟磁盘时,发现了一个很郁闷的问题,
在查询指定的文件句柄所在的文件系统的信息时考试报缓存区不正确
函数原型是
NTSTATUS
ZwQueryVolumeInformationFile(
IN HANDLE FileHandle, //指定的文件句柄
OUT PIO_STATUS_BLOCK IoStatusBlock, //返回操作结果信息的缓冲区
OUT PVOID FsInformation, //查询结果的缓存区
IN ULONG Length, //缓冲区的长度
IN FS_INFORMATION_CLASS FsInformationClass//查询的类别
);
要查找的数据结构
typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
ULONG FileSystemAttributes;
LONG MaximumComponentNameLength;
ULONG FileSystemNameLength;
WCHAR FileSystemName[1];
} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
其具体情况请看wdk的文档
我在这里的查询类别是FileFsAttributeInformation ,据wdk文档的信息缓存区应该是FILE_FS_ATTRIBUTE_INFORMATION。
我的代码如下
FILE_FS_ATTRIBUTE_INFORMATION pinfo = {0};
status = ZwQueryVolumeInformationFile( hFile ,//已经打开的文件
&IoStatusBlock , //结果信息
&fsInfo ,//数据缓存
sizeof(FILE_FS_ATTRIBUTE_INFORMATION),//数据缓存的大小
FileFsAttributeInformation);
我不知道的大家在上面的信息中能看出上面问题,但是我可以很定的是这个代码在我这里挂了 结果status = STATUS_BUFFER_OVERFLOW,也就是说缓存区不够。着没道理啊。
我们先看一下FILE_FS_ATTRIBUTE_INFORMATION的定义,结构体里面有两个ULONG和一个LONG都是四个字节的,还有一个WCHAR [1]占两个字节,总共是14个字节但是对齐后就是16个字节了。16个字节有问题么?
但是我们冲名字可以看到FileSystemName是表示文件系统的名字,以一个字符作为名字的文件系统谁见过?我还真没见过!在c\c++中数组的名字就是一个指针,也就是说FileSystemName要指向文件系统的名字
这就清楚了,在ZwQueryVolumeInformationFile的内部并没有按照常规的思维方式类处理fsInfo,在前面三个字段就都是对号入座的,而在FileSystemName的位置存入的是一个文件系统的名字的字符串,也就是说可能会超过结构体的空间大小,所以我们在这里传入的缓存区就不应只是一个FILE_FS_ATTRIBUTE_INFORMATION的大小了,否则这个文件系统的名字就没法存储了
在看下我修改了的代码
char fsInfo[50] = {0};
PFILE_FS_ATTRIBUTE_INFORMATION pinfo = (void*)fsInfo;
status = ZwQueryVolumeInformationFile(
pExt->hImageFile , &IoStatusBlock ,
&fsInfo , 50,
FileFsAttributeInformation);
这个代码在我这里就没问题了,其实我们不知道具体要传入的缓冲区大小是多少,因为我们并不知道文件系统的名字,所以只能蒙了。还要注意的是名字是以Unicode的方式存储的,一个字符占两个字节
本人菜鸟