首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在随机访问模式C++中访问原始磁盘

在随机访问模式C++中访问原始磁盘
EN

Stack Overflow用户
提问于 2016-12-27 14:58:39
回答 1查看 1K关注 0票数 0

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

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

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

代码语言:javascript
运行
复制
#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 --十六进制编辑器--可以立即计算磁盘中的总扇区数,并且可以在任何时候到达某个扇区。我需要的功能类似于这个功能。

我收集了很多关于如何去做的建议,但实际上我在这里陷入了僵局。

任何想法都欢迎。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-27 15:12:03

据我所见,read函数仍然不允许我将任何参数作为“目的”或类似的东西传递。

这不是真的-再读一遍关于ReadFile的文章

lpOverlapped入,出,可选 对于支持字节偏移的hFile,如果使用此参数,则必须指定从文件或设备开始读取的字节偏移量。此偏移量是通过设置重叠结构的偏移量和OffsetHigh成员来指定的。

这是:

使用文件句柄时应注意的事项: ·如果lpOverlapped不是NULL,则读取操作从重叠结构中指定的偏移量开始.

I/O管理器维护当前文件位置。(查找LARGE_INTEGER CurrentByteOffset成员的FILE_OBJECTReadFileWriteFile通过添加在完成操作时读取或写入的字节数来更新当前文件位置。另外,我们可以通过调用SetFilePointer[Ex]来设置这个位置。

如果我们以同步模式(没有FILE_FLAG_OVERLAPPED标志)打开文件,那么所有带有文件的操作都是顺序的--任何新的操作都要到前面的操作还没有完成时才开始执行。

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

  1. 我们可以指定使用当前文件位置偏移量。此规范可以通过传递用于NULLlpOverlapped指针来制定。
  2. 我们可以通过将显式lpOverlapped值传递给ReadFileWriteFile来重置此位置。这样做会自动将当前文件位置更改为该(Offset, OffsetHigh)值,执行读(写)操作,然后根据实际读(写)的字节数更新位置。这种技术为调用者提供原子寻址和读取(写)服务。

因此,根据代码,我们有两个变体:

代码语言:javascript
运行
复制
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 ReadFileWriteFile )

系统在ReadFile (WriteFile)返回之前更新重叠偏移量。

这在文档中是不正确和错误的--您可以检查自己是否在操作后没有更新OVERLAPPED偏移量。可能意味着更新了当前文件位置(CurrentByteOffset in FILE_OBJECT)。但是OVERLAPPED偏移量是在操作后没有更新的

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41347444

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档