以随机访问模式访问原始磁盘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十六进制编辑器可以立即计算磁盘中总扇区的数量,并且可以随时访问某个扇区。我需要的功能与此功能类似。

HxD Disk Read Function

我收集的各种秘诀,它是如何做到的,但我在一个僵局是几乎在这里。

任何想法都会受到欢迎。

+2

[SetFilePointer(https://msdn.microsoft.com/en-us/library/windows/desktop/aa365541.aspx) –

+1

你需要设置'offset'和'OVERLAPPED'中的OffsetHigh'并使用'OVERLAPPED'作为'ReadFile'中的最后一个参数 – RbMm

+0

我在这个问题中看不到任何Qt代码... – MrEricSir

阅读功能仍然不允许我传递任何参数作为 “目标”或类似的东西,据我所知。

这是不正确的 - 再读约ReadFile

lpOverlapped的[IN,OUT,可选]

对于支持字节偏移,如果你使用这个参数,你 必须指定HFILE一个字节偏移量,从该文件或 设备开始读取。该偏移量通过设置OVERLAPPED结构的Offset和OffsetHigh 成员来指定。

这:

注意事项与文件处理工作:

•如果lpOverlapped不为NULL,则读操作的是在重叠的结构中指定的偏移 开始.. 。


的I/O管理维护CUR租文件位置。 (寻找LARGE_INTEGER CurrentByteOffsetFILE_OBJECT的成员)。ReadFileWriteFile通过在完成操作时添加读取或写入的字节数来更新当前文件位置。我们也可以通过电话,如果我们打开同步模式文件(不FILE_FLAG_OVERLAPPED标志)与文件顺序设置这个位置SetFilePointer[Ex]

所有操作 - 任何新的行动不会开始执行,直到先前没有完成。

在这种情况下

我们有两个选择:

  1. 我们可以指定当前文件位置偏移来使用。本说明书 可以使通过传递NULL指针 lpOverlapped
  2. 我们可以通过传递明确lpOverlappedReadFileWriteFile重置这个位置。这样做会自动将当前文件位置 更改为(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(在ReadFileWriteFile页)

系统更新OVERLAPPED抵消之前ReadFile的WriteFile的) 回报。

这是不正确的,在文档中的错误 - 你可以检查自己,OVERLAPPED偏移不会在操作后更新。可能意味着当前文件位置(CurrentByteOffsetFILE_OBJECT)被更新。但同样OVERLAPPED偏移量是手术后没有更新

+0

我一开始就放弃了'lpOverlapped'参数,因为我认为它是仅与“异步操作”有关,与偏移映射无关。我会更严格地研究它。谢谢你指出。 –

+1

@DoğukanTunç - 我添加更多的信息来回答最大的清晰度 – RbMm

+0

谢谢你的详细解释,它真的帮助我理解这个想法,并在我的代码中使用它。 –