2016-12-27 15 views
0

Теперь я уже знаком с процессом 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 работу даже такой случайный доступ? Я понимаю, что есть флаги Random Access для вызова CreateFile, но после этого, что? Насколько мне известно, функция чтения по-прежнему не позволяет мне передавать какие-либо аргументы как «место назначения» или что-то в этом роде.

Например, в шестнадцатеричном редакторе HxD можно сразу подсчитать количество полных секторов на диске и перейти в определенный сектор в любое время. Мне нужна функция, аналогичная этой возможности.

HxD Disk Read Function

Я собрал различные советы относительно того, как это может быть сделано, но я практически зашли в тупик здесь.

Любые идеи приветствуются.

+2

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

+1

вам нужно установить 'offset' и 'OffsetHigh' в' OVERLAPPED' и использовать этот 'OVERLAPPED' как последний параметр в' ReadFile' – RbMm

+0

Я не вижу никакого Qt-кода в этом вопросе ... – MrEricSir

ответ

3

Функция чтения по-прежнему не позволяет мне передавать какие-либо аргументы как «пункт назначения» или что-то в этом роде, насколько я могу судить.

это не так - читать снова о ReadFile

lpOverlapped [в, из, опционально]

Для hFile, который поддерживает смещения байтов, если вы используете этот параметр, необходимо указать смещение байта, с которого начнется чтение из файла или . Это смещение задается установкой элементов Offset и OffsetHigh структуры OVERLAPPED.

и это:

Вопросы для работы с файлом ручки:

• Если lpOverlapped не NULL, то операция чтения начинается по смещению , указанные в OVERLAPPED структуры .. .


диспетчер ввода/вывода поддерживает CUR арендовать файловую позицию. (ищите LARGE_INTEGER CurrentByteOffset член FILE_OBJECT).ReadFile и WriteFile обновляет текущую позицию файла, добавляя количество байтов, считанных или записанных при завершении операции. также мы можем установить эту позицию по телефону SetFilePointer[Ex]

Если мы открываем файл в синхронном режиме (без флага FILE_FLAG_OVERLAPPED), все операции с файлом последовательны - любая новая операция не начинается, пока предыдущий не закончен.

в этом случае у нас есть два варианта:

  1. мы можем указать, что текущая позиция файла смещение будет использоваться. это спецификация может быть сделана передать NULL указатель для lpOverlapped
  2. мы можем сбросить эту позицию, передавая явное значение lpOverlapped к ReadFile или WriteFile. Выполнение этого автоматически изменяет текущую позицию файла на это значение (Offset, OffsetHigh), выполняет операцию чтения (записи), а затем обновляет позицию в соответствии с количеством фактически прочитанных байтов (write). Этот метод предоставляет атомную службу поиска и записи вызывающего абонента.

так кодом мы имеем 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 Manager не может использовать позицию файла в FILE_OBJECT - потому что это неопределенное поведение здесь.

поэтому мы должны всегда явно передавать lpOverlapped с допустимым смещением. если мы передадим указатель NULL для lpOverlapped - мы получили ERROR_INVALID_PARAMETER Ошибка

на последнем, но важно. из MSDN (на ReadFile и WriteFile страниц)

Система обновляет ПЕРЕКРЫВАЕТСЯ смещения перед ReadFile (WriteFile) возвращается.

это неправда и ошибка в документации - вы можете проверить, что OVERLAPPED смещение не обновляется после операции. может означать, что текущая позиция файла (CurrentByteOffset в FILE_OBJECT) обновляется. но опять-таки OVERLAPPED смещение не обновляется после операции

+0

Сначала я отбросил параметр «lpOverlapped», потому что я думал, что это единственное отношение к «асинхронной операции» и не имеет ничего общего со смещением. Я посмотрю на это более строго. Спасибо, что указали это. –

+1

@ DoğukanTunç - я добавляю больше информации для получения максимальной ясности. – RbMm

+0

Благодарим вас за подробное объяснение, это действительно помогло мне понять идею и использовать ее в моем коде. –