Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
411 views
in Technique[技术] by (71.8m points)

winapi - Reading Data from a Physical Hard Drive

I am trying to develop a program that goes and finds 2 connected unformatted physical drives and read bytes. The program currently runs in the administrator mode since that's the only way I guess the program can see unformatted hard drives. I am using visual studio 2015 and it runs in windows 7 machine.

The problem is that it can only read multiples of 512 (512 is the sector size). Currently the unformatted hard drives are located in disk 2 and 3 slots (they are both SSDs). It first reads 512 bytes (works without an issue) and doesn't do any more reads if it's a formatted hard drive. If it's an unformatted hard drive it goes ahead and read more bytes. If it's hard drive A it then reads the next 1024 bytes and it works (read_amount = 1024). If it's hard drive B it then reads the next 1025 bytes and it doesn't work (read_amount = 0). I am not sure why it can't read a multiple of a 512/sector sizes. My understanding is that when you call "CreateFile()" function with dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, I should be able to read sizes that are not multiples of sector sizes (if you use FILE_FLAG_NO_BUFFERING then you can only read multiples of 512 and I am NOT using that flag). See my code below.

// Hard_Drive_Read.cpp : Defines the entry point for the console application.

// This program assumes you have EXACTLY TWO unformatted hard drives connected to your computer.

#include <Windows.h>
#include <io.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <iomanip>


using namespace std;




int main(int argc, char *argv[])
{
if (argc != 3)
{
    cout << "Need to enter 2 arguments" << endl;
    exit(0);
}

int frames_to_process = atoi(argv[2]);

if (frames_to_process < 1)
{
    cout << "invalid argument 2" << endl;
    exit(0);
}



//HANDLE hDisk_A;
//HANDLE hDisk_B;



LPCTSTR dsksrc = L"\\.\PhysicalDrive";
wchar_t dsk[512] = L"";


bool channel_A_found = false;
bool channel_B_found = false;
char frame_header_A[1024];
char frame_header_B[1025];



HANDLE hDisk;
char buff_read[512];
DWORD read_amount = 0;

for (int i = 0; i < 4; i++)
{


    swprintf(dsk, 511, L"%s%d", dsksrc, i);

    hDisk = CreateFile(dsk, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hDisk == INVALID_HANDLE_VALUE)
    {
        printf("%s%d%s", "couldn't open the drive ", i, "
");
        CloseHandle(hDisk);
    }
    else
    {
        printf("%s%d%s", "successfully open the drive ", i, "
");

        BOOL read_success_1 = ReadFile(hDisk, buff_read, 512, &read_amount, NULL);
        cout << "read amount 1 - " << read_amount << endl;
        if ((read_success_1 == TRUE) && (read_amount == 512))
        {


            if ((buff_read[510] == (char)0x55) && (buff_read[511] == (char)0xAA))  //  test for a formatted drive; is there other identifiers?
            {
                cout << i << " is a formatted drive" << endl;
            }

            else
            {
                cout << "Not a formatted drive, trying to find sync " << endl;


                ofstream writeBinary_Test;

                if (i == 2)
                {
                    writeBinary_Test.open("file_A_test.bin", ofstream::out | ofstream::binary);
                    ReadFile(hDisk, frame_header_A, 1024, &read_amount, NULL);
                    cout << "read amount " << read_amount << endl;
                    writeBinary_Test.write(frame_header_A, 1024);
                    writeBinary_Test.close();
                }

                else if(i == 3)
                {
                    writeBinary_Test.open("file_B_test.bin", ofstream::out | ofstream::binary);
                    ReadFile(hDisk, frame_header_B, 1025, &read_amount, NULL);
                    cout << "read amount " << read_amount << endl;
                    writeBinary_Test.write(frame_header_B, 1025);
                    writeBinary_Test.close();
                }



                LARGE_INTEGER distanceToMove;      
                SetFilePointerEx(hDisk, distanceToMove, NULL, FILE_BEGIN);



            }
        }

        else
        {

        }

    }

    if (channel_A_found && channel_B_found)
    {
        cout << "both drives found" << endl;
        break;
    }
}


if ((channel_A_found == false) || (channel_B_found == false))
{
    cout << "Couldn't Find Hard Drive A or Drive B or Both" << endl;
    cout << "Exiting the program" << endl;
    exit(0);
}


CloseHandle(hDisk);



return 0;
}

Eventually, I want to use SetFilePointerEx() to move around the hard drive and I the program has to work with and data size (not multiples of 512). Therefore, it's imperative I can read sizes that's not multiples of 512. Any ideas of how to fix this program? Am I using my flags properly?

Any help is much appreciated!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The documentation for CreateFile says:

Volume handles can be opened as noncached at the discretion of the particular file system, even when the noncached option is not specified in CreateFile. You should assume that all Microsoft file systems open volume handles as noncached. The restrictions on noncached I/O for files also apply to volumes.

Although it doesn't spell it out explicitly, this applies to drives as well as to volumes.

In practice, this isn't a problem. It is straightforward to write a helper function that returns an arbitrary amount of data from an arbitrary offset, while performing only aligned reads.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...