Now, I'm already familiar with the DeviceIoControl (ioctl) process and can read from a disk sequentially, 512 bytes at a time.
I create a handle from the list of \.\PhysicalDrive(s) and identify it via IOCTL_STORAGE_QUERY_PROPERTY command. Then process the desired device for data.
At this point, I can read it progressively by creating a loop that advances the read area 1 sector each time with this code (Qt C++ environment)
#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++;
}
Doing this sequentially means I have to progress through the sectors one by one, counting, until I reach the sector number I want to access. And this is not very optimal in performance.
What if I wanted to access a specific region directly, like "go to sector 45535 and read 512 bytes"? Does IOCTL operation even allow random access like this? I understand there are Random Access flags to a CreateFile
call but after that, what? The read function still doesn't allow me to pass any arguments as "destination" or something like that, as far as I can see.
For example, HxD the hex editor can count the number of total sectors in a disk immediately and can go to a certain sector at any time. The function I need is similar to this capability.
I have collected various tips as to how it can be done but I'm practically at an impasse here.
Any ideas would be welcome.
this is not true - read again about
ReadFile
and this:
the I/O Manager maintains the current file position. ( look for
LARGE_INTEGER CurrentByteOffset
member ofFILE_OBJECT
).ReadFile
andWriteFile
updates the current file position by adding the number of bytes read or written when it completes the operation. also we can set this position by callSetFilePointer[Ex]
if we open file in synchronous mode (without
FILE_FLAG_OVERLAPPED
flag) all operations with file is sequential - any new operation not begin execute until previous not finished.in this case we have two options :
NULL
pointer forlpOverlapped
lpOverlapped
value toReadFile
orWriteFile
. Doing this automatically changes the current file position to that(Offset, OffsetHigh)
value, performs the read(write) operation, and then updates the position according to the number of bytes actually read(write). This technique gives the caller atomic seek-and-read(write) service.so by code we have 2 variants:
of course atomic seek-and-read(write) much more effective compare using
SetFilePointer[Ex]
(additional API call to kernel).if we open file in asynchronous mode (with
FILE_FLAG_OVERLAPPED
flag) - multiple read/write operations with file can executed at same time. in this case I/O Manager can not use the file position inFILE_OBJECT
- because this undefined behavior here.so we must always explicit pass
lpOverlapped
with valid offset. if we pass aNULL
pointer for lpOverlapped - we gotERROR_INVALID_PARAMETER
errorat the last but important. from MSDN (at ReadFile and WriteFile pages)
this is not true and mistake in documentation - you can check yourself that
OVERLAPPED
offset not updated after operation. may be mean that current file position (CurrentByteOffset
inFILE_OBJECT
) is updated. but againOVERLAPPED
offset is not updated after operation