Question

I'm trying to get into Qt and as a project I want to try and pull a binary image from a hard drive in Windows. This is what I have:

QFile dsk("//./PhysicalDrive1");
dsk.open(QIODevice::ReadOnly);
QByteArray readBytes = dsk.read(512);
dsk.close();
QFile img("C:/out.bin");
img.open(QIODevice::WriteOnly);
img.write(readBytes);
img.close();

When I run it, it creates the file, but when I view it in a hex editor, it says:

ëR.NTFS    ..........ø..?.ÿ.€.......€.€.ÿç......UT..............ö.......ì§á.Íá.`....ú3ÀŽÐ¼.|ûhÀ...hf.ˈ...f.>..NTFSu.´A»ªUÍ.r..ûUªu.÷Á..u.éÝ..ƒì.h..´HŠ...‹ô..Í.ŸƒÄ.žX.rá;...uÛ£..Á.....Z3Û¹. +Èfÿ.......ŽÂÿ...èK.+Èwï¸.»Í.f#Àu-f.ûTCPAu$.ù..r..h.».hp..h..fSfSfU...h¸.fa..Í.3À¿(.¹Ø.üóªé_...f`..f¡..f.....fh....fP.Sh..h..´BŠ.....‹ôÍ.fY[ZfYfY..‚..fÿ.......ŽÂÿ...u¼..faàø.è.. û.è..ôëý´.‹ð¬<.t.´.»..Í.ëòÃ..A disk read error occurred...BOOTMGR is missing...BOOTMGR is compressed...Press Ctrl+Alt+Del to restart...Œ©¾Ö..Uª

Is there a better way of doing this? I tried running it as admin, but still no dice. Any help would be much appreciated.


Update:

I changed the code a bit. Now if I specify a dd images as the input it writes the image perfectly, but when I try to use a disk as the input it only writes 0x00.

QTextStream(stdout) << "Start\n";

QFile dsk("//./d:");
//QFile dsk("//./PhysicalDrive1");
//QFile dsk("//?/Device/Harddisk1/Partition0");
//QFile dsk("//./Volume{e988ffc3-3512-11e3-99d8-806e6f6e6963}");
//QFile dsk("//./Volume{04bbc7e2-a450-11e3-a9d9-902b34d5484f}");
//QFile dsk("C:/out_2.bin");
if (!dsk.open(QIODevice::ReadOnly))
    qDebug() << "Failed to open:" << dsk.errorString();
qDebug() << "Size:" << dsk.size() << "\n";

// Blank out image file
QFile img(dst);
img.open(QIODevice::WriteOnly);
img.write(0);
img.close();

// Read and write operations
while (!dsk.atEnd())
{
    QByteArray readBytes = dsk.readLine();
    qDebug() << "Reading: " << readBytes.size() << "\n";
    QFile img(dst);
    if (!img.open(QIODevice::Append))
        qDebug() << "Failed to open:" << img.errorString();
    img.write(readBytes);
}
QTextStream(stdout) << "End\n";

I guess the real problem I'm having is how to open a volume with QFile in Windows. I tried a few variants, but to no avail.

Was it helpful?

Solution 2

Right, so your code has several flaws as follows:

  1. It is using hard coded windows paths. This could be appropriate for debugging or an example, but probably not for the final code.

  2. It does not check whether the operations succeed.

  3. It does not print the error strings when the operations fail.

  4. You only read 512 bytes maximum.

  5. You are doing a simple copy when QFile::copy() could do the same.

  6. You do not need to close these descriptors explicitly since it is RAII you work with, not low-level C, luckily.

  7. You may be having the filesystem mounted, and Windows might impose some limitation in that regard. Make sure that filesystems on the physical drive ("D: in your case?") are not mounted if you happen to read from physical drive as opposed to a binary image.

This is the code what I would write if I were you:

// "input.bin" can be replaced with any binary or physical drive
// you wish to back up about your physical drive.
QFile dsk("input.bin");
if (!dsk.open(QIODevice::ReadOnly))
    qDebug() << "Failed to open:" << dsk.errorString();

QFile img("output.bin");
if (!img.open(QIODevice::WriteOnly))
    qDebug() << "Failed to open:" << img.errorString();

QFileInfo fileInfo(dsk.fileName());
qint64 size = fileInfo.size();
for (qint64 bytes = 0; bytes < size, bytes+=data.size()) {
    readBytes = myInputFile.read(chunkSize);
    if (readBytes.isEmpty()) {
        qDebug() << "no data was currently available for reading, or that an error occurred, error string:" << dsk.errorString();
    } else {
        if (img.write(readBytes) != readBytes.size())
            qDebug() << "Failed to write all:" << img.errorString();
    }
}

Theoretically, you could even add this loop if you cannot unmount, provided you are only interested in the file contents itself, but then you are going towards compression:

QDirIterator it("D:/", QDirIterator::Subdirectories);
while (it.hasNext()) {
    // backup each file: it.next()
}

This is probably not what you may want here though, so just mentioning it for completeness.

OTHER TIPS

New versions of Windows added a rule that you cannot use the raw disk object to access parts of the disk that are owned by a mounted filesystem, even with administrator access.

You can use \\\\.\\PhysicalDrive1 therefore only to read the boot sector, plus any gaps between partitions. Partitions that contain recognized filesystems have to be read via the volume object corresponding to the partition. Or first lock/unmount the filesystem.

See also How to WriteFile to a PhysicalDrive (Windows 7) without getting ERROR_ACCESS_DENIED?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top