现在,我已经熟悉了DeviceIoControl (ioctl)进程,一次可以从磁盘读取512字节。
我从.\PhysicalDrive的列表中创建一个句柄,并通过IOCTL_STORAGE_QUERY_PROPERTY命令识别它。然后处理所需的数据设备。
此时,我可以通过创建一个循环,每次使用此代码(Qt C++环境)推进读取区域1扇区,从而逐步读取它。
#include <minwindef.h>
#include <devioctl.h>
#include <ntdddisk.h>
#include <ntddscsi.h>
#include <ioapiset.h>
#include <fileapi.h>
#include <handleapi.h>
#include <winbase.h>
...
HANDLE devHandle = NULL;
devHandle = CreateFile(charArray, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0 ,NULL);
unsigned long secCount = 0;
while(true)
{
bSuccess = ReadFile(devHandle, lpSecBuf, 512, &dwRead, NULL);
if (bSuccess & (dwRead < 512))
{
qDebug()<<"EOF";
break;
}
if(!bSuccess)
{
qDebug()<<"No data could be read from the device.";
break;
}
if(bSuccess && dwRead>0)
{
qDebug()<<"Sector "<<secCount<<" data : "<<lpSecBuf;
}
secCount++;
}
这样做的顺序意味着我必须通过扇区一个一个,计数,直到我达到我想要访问的扇区号码。而这并不是最优的性能。
如果我想直接访问特定的区域,比如“转到扇区45535并读取512个字节”,该怎么办?IOCTL操作允许这样的随机访问吗?我知道CreateFile
调用有随机访问标志,但是在那之后呢?据我所见,read函数仍然不允许我将任何参数作为“目的”或类似的东西传递。
例如,HxD --十六进制编辑器--可以立即计算磁盘中的总扇区数,并且可以在任何时候到达某个扇区。我需要的功能类似于这个功能。
我收集了很多关于如何去做的建议,但实际上我在这里陷入了僵局。
任何想法都欢迎。
发布于 2016-12-27 15:12:03
据我所见,read函数仍然不允许我将任何参数作为“目的”或类似的东西传递。
这不是真的-再读一遍关于ReadFile
的文章
lpOverlapped入,出,可选 对于支持字节偏移的hFile,如果使用此参数,则必须指定从文件或设备开始读取的字节偏移量。此偏移量是通过设置重叠结构的偏移量和OffsetHigh成员来指定的。
这是:
使用文件句柄时应注意的事项: ·如果lpOverlapped不是NULL,则读取操作从重叠结构中指定的偏移量开始.
I/O管理器维护当前文件位置。(查找LARGE_INTEGER CurrentByteOffset
成员的FILE_OBJECT
。ReadFile
和WriteFile
通过添加在完成操作时读取或写入的字节数来更新当前文件位置。另外,我们可以通过调用SetFilePointer[Ex]
来设置这个位置。
如果我们以同步模式(没有FILE_FLAG_OVERLAPPED
标志)打开文件,那么所有带有文件的操作都是顺序的--任何新的操作都要到前面的操作还没有完成时才开始执行。
在这种情况下,我们有两个选择:
NULL
的lpOverlapped
指针来制定。lpOverlapped
值传递给ReadFile
或WriteFile
来重置此位置。这样做会自动将当前文件位置更改为该(Offset, OffsetHigh)
值,执行读(写)操作,然后根据实际读(写)的字节数更新位置。这种技术为调用者提供原子寻址和读取(写)服务。因此,根据代码,我们有两个变体:
BOOL _ReadFile(HANDLE hFile, LARGE_INTEGER ByteOffset, PVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead)
{
#if 1
OVERLAPPED ov = {};
ov.Offset = ByteOffset.LowPart;
ov.OffsetHigh = ByteOffset.HighPart;
return ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &ov);
#else
if (SetFilePointerEx(hFile, ByteOffset, 0, FILE_BEGIN))
{
return ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, 0);
}
return FALSE;
#endif
}
当然,与使用SetFilePointer[Ex]
(对内核的附加API调用)相比,原子查找和读(写)要有效得多。
如果我们以异步模式打开文件(带有FILE_FLAG_OVERLAPPED
标志)--多个带有文件的读/写操作可以同时执行。在这种情况下,I/O管理器不能使用FILE_OBJECT
中的文件位置-因为这里的这种未定义的行为。
因此,我们必须始终显式传递具有有效偏移量的lpOverlapped
。如果我们传递一个用于NULL
的lpOverlapped指针-我们得到了ERROR_INVALID_PARAMETER
错误
最后但很重要。来自MSDN (at ReadFile和WriteFile )
系统在ReadFile (WriteFile)返回之前更新重叠偏移量。
这在文档中是不正确和错误的--您可以检查自己是否在操作后没有更新OVERLAPPED
偏移量。可能意味着更新了当前文件位置(CurrentByteOffset
in FILE_OBJECT
)。但是OVERLAPPED
偏移量是在操作后没有更新的。
https://stackoverflow.com/questions/41347444
复制相似问题