以随机访问模式C ++访问原始磁盘

时间:2016-12-27 14:58:39

标签: c++ winapi ioctl

现在,我已经熟悉DeviceIoControl(ioctl)进程,并且可以按顺序从磁盘读取,一次512字节。

我从\。\ PhysicalDrive列表中创建一个句柄,并通过IOCTL_STORAGE_QUERY_PROPERTY命令识别它。然后处理所需的数据设备。

此时,我可以通过创建一个循环来逐步读取它,每次使用此代码(Qt C ++环境)推进读取区域1扇区

load ("file.RData")    

Encoding(df1$TEAM)<-"latin1"
Encoding(df2$TEAM)<-"latin1"
Encoding(df3$Team)<-"latin1"

按顺序执行此操作意味着我必须一个接一个地遍历各个扇区,直到达到我想要访问的扇区号。而且这在表现上并不是最优的。

如果我想直接访问特定区域,例如“转到扇区45535并读取512字节”,该怎么办? IOCTL操作是否允许这样的随机访问?我知道#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++; } 电话有随机访问标志,但在那之后,什么?就我所见,read函数仍然不允许我将任何参数作为“目标”或类似的东西传递。

例如,HxD十六进制编辑器可以立即计算磁盘中总扇区的数量,并且可以随时转到某个扇区。我需要的功能与此功能类似。

HxD Disk Read Function

我已经收集了关于如何做到的各种提示,但我实际上陷入僵局。

欢迎任何想法。

1 个答案:

答案 0 :(得分:3)

  

读取功能仍然不允许我传递任何参数   &#34;目的地&#34;或者类似的东西,据我所见。

这不是真的 - 再次阅读ReadFile

  

lpOverlapped [in,out,optional]

     

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

和此:

  

使用文件句柄的注意事项:

     

•如果lpOverlapped不为NULL,则读取操作从偏移处开始   在OVERLAPPED结构中指定...

I / O管理器维护当前文件位置。 (查找FILE_OBJECTLARGE_INTEGER CurrentByteOffset成员)。 ReadFileWriteFile通过添加完成操作时读取或写入的字节数来更新当前文件位置。我们也可以通过电话SetFilePointer[Ex]

设置此职位

如果我们以同步模式打开文件(没有FILE_FLAG_OVERLAPPED标志),所有带文件的操作都是顺序的 - 任何新操作都不会开始执行,直到之前没有完成。

在这种情况下,我们有两个选择:

  1. 我们可以指定使用当前文件位置偏移量。这个 规范可以通过传递NULL指针来实现 lpOverlapped
  2. 我们可以通过明确lpOverlapped来重置此位置 价值为ReadFileWriteFile。这样做会自动更改 当前文件位置为(Offset, OffsetHigh)值, 执行读(写)操作,然后更新位置 根据实际读取的字节数(写入)。这个 技术为调用者提供原子搜索和读取(写入)服务。
  3. 所以通过代码我们有两个变种:

    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。如果我们为lpOverlapped传递NULL指针 - 我们得到ERROR_INVALID_PARAMETER错误

    最后但很重要。来自MSDN(ReadFileWriteFile页)

      

    系统在 ReadFile 之前更新 OVERLAPPED 偏移量( WriteFile )   回报。

    这不是真的,也不是文档中的错误 - 您可以检查一下OVERLAPPED偏移量在操作后是否未更新。可能意味着更新当前文件位置(CurrentByteOffset中的FILE_OBJECT)。但操作后再次OVERLAPPED偏移未更新