以随机访问模式访问原始磁盘C++
现在,我已经熟悉DeviceIoControl(ioctl)进程,并且可以从磁盘中按顺序读取512个字节。以随机访问模式访问原始磁盘C++
我从\。\ PhysicalDrive(s)列表创建一个句柄,并通过IOCTL_STORAGE_QUERY_PROPERTY命令识别它。然后处理所需的数据设备。
此时,我可以通过创建一个循环,进入读取区域每次1个扇区与此代码(Qt的C++环境)
#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
调用随机访问标志,但在那之后,什么?就我所见,阅读功能仍然不允许我将任何参数作为“目的地”或类似的东西传递。
例如,HxD十六进制编辑器可以立即计算磁盘中总扇区的数量,并且可以随时访问某个扇区。我需要的功能与此功能类似。
我收集的各种秘诀,它是如何做到的,但我在一个僵局是几乎在这里。
任何想法都会受到欢迎。
阅读功能仍然不允许我传递任何参数作为 “目标”或类似的东西,据我所知。
这是不正确的 - 再读约ReadFile
lpOverlapped的[IN,OUT,可选]
对于支持字节偏移,如果你使用这个参数,你 必须指定HFILE一个字节偏移量,从该文件或 设备开始读取。该偏移量通过设置OVERLAPPED结构的Offset和OffsetHigh 成员来指定。
这:
注意事项与文件处理工作:
•如果lpOverlapped不为NULL,则读操作的是在重叠的结构中指定的偏移 开始.. 。
的I/O管理维护CUR租文件位置。 (寻找LARGE_INTEGER CurrentByteOffset
FILE_OBJECT
的成员)。ReadFile
和WriteFile
通过在完成操作时添加读取或写入的字节数来更新当前文件位置。我们也可以通过电话,如果我们打开同步模式文件(不FILE_FLAG_OVERLAPPED
标志)与文件顺序设置这个位置SetFilePointer[Ex]
所有操作 - 任何新的行动不会开始执行,直到先前没有完成。
在这种情况下我们有两个选择:
- 我们可以指定当前文件位置偏移来使用。本说明书 可以使通过传递
NULL
指针lpOverlapped
- 我们可以通过传递明确
lpOverlapped
值ReadFile
或WriteFile
重置这个位置。这样做会自动将当前文件位置 更改为(Offset, OffsetHigh)
值, 执行读取(写入)操作,然后根据实际读取(写入)的字节数更新位置 。这种技术为调用者提供了原子查找和读取(写入)服务。
所以通过代码,我们有2个变种:
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(在ReadFile和WriteFile页)
系统更新OVERLAPPED抵消之前ReadFile的(WriteFile的) 回报。
这是不正确的,在文档中的错误 - 你可以检查自己,OVERLAPPED
偏移不会在操作后更新。可能意味着当前文件位置(CurrentByteOffset
在FILE_OBJECT
)被更新。但同样OVERLAPPED
偏移量是手术后没有更新
我一开始就放弃了'lpOverlapped'参数,因为我认为它是仅与“异步操作”有关,与偏移映射无关。我会更严格地研究它。谢谢你指出。 –
@DoğukanTunç - 我添加更多的信息来回答最大的清晰度 – RbMm
谢谢你的详细解释,它真的帮助我理解这个想法,并在我的代码中使用它。 –
[SetFilePointer(https://msdn.microsoft.com/en-us/library/windows/desktop/aa365541.aspx) –
你需要设置'offset'和'OVERLAPPED'中的OffsetHigh'并使用'OVERLAPPED'作为'ReadFile'中的最后一个参数 – RbMm
我在这个问题中看不到任何Qt代码... – MrEricSir