Читайте содержимое всего диска по крупицам в C - PullRequest
0 голосов
/ 26 мая 2018

Я пытался использовать DeviceIoControl, чтобы получить данные в буфер b на диске.Когда я пытаюсь использовать что-то вроде total = b.cylinders.quadpart * b.trackspercylinders * b.sectorspertrack * b.bytespersector, я получаю в итоге отрицательное число.Теперь я не знаю, как оценить общее количество секторов на диске для запуска цикла for и использовать функцию readfile для распечатки содержимого.Фрагмент кода для того же был бы очень полезен.

TCHAR cOutputPath0[32000];
char strPath[] = "\\\\.\\PhysicalDrive0";
        ExpandEnvironmentStrings((LPCTSTR)strPath, cOutputPath0, (sizeof(cOutputPath0) / sizeof(*cOutputPath0)));

        HANDLE drive = CreateFile(cOutputPath0, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

        DWORD br = 0;
        DISK_GEOMETRY dg;

        DeviceIoControl(drive, IOCTL_DISK_GET_DRIVE_GEOMETRY, 0, 0, &dg, sizeof(dg), &br, 0);

            TCHAR sectorData[32000];

            LARGE_INTEGER t1 = dg.Cylinders;
            printf("%d\n", t1.QuadPart);
            int t2 = dg.TracksPerCylinder;
            printf("%d\n", t2);
            int t3 = dg.SectorsPerTrack;
            printf("%d\n", t2);
            int t4 = dg.BytesPerSector;
            printf("%d\n", t2);

            unsigned long long total = t1.QuadPart*t2*t3*t4;
            unsigned long long j;

            printf("%d", total);

            for (j = 0; j < total; j++) {
                LARGE_INTEGER pos;
                pos.QuadPart = j* dg.BytesPerSector;
                SetFilePointerEx(drive, pos, 0, FILE_BEGIN);
                if (ReadFile(drive, sectorData, dg.BytesPerSector, &br, NULL) && br == dg.BytesPerSector) {
                    printf("%s", sectorData);
                }

            }

Этот код кажется правильным для этого?Потому что я все еще, кажется, получаю отрицательное число!

Ответы [ 2 ]

0 голосов
/ 29 мая 2018
В этом случае

CreateFile может легко потерпеть неудачу либо потому, что требуется доступ администратора, либо потому, что "\\\\.\\PhysicalDrive0" - это неправильный диск.Базовая проверка ошибок настоятельно рекомендуется для любой файловой операции.

Запустите программу с правами администратора и убедитесь, что "\\\\.\\PhysicalDrive0" - правильный диск (это не всегда C:\)

SetFilePointerEx не требуется, если вы читаете файл впоследовательность.Указатель файла автоматически перемещается вперед после каждого ReadFile

#define UNICODE
#include <stdio.h>
#include <Windows.h>

int main(void)
{
    HANDLE handle = CreateFile(L"\\\\.\\PhysicalDrive0",
        GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);

    if(handle == INVALID_HANDLE_VALUE)
    {
        //wrong disk, or admin access required
        DWORD err = GetLastError();
        printf("!CreateFile, GetLastError: %d\n", err);
        CloseHandle(handle);
        return 0;
    }

    DWORD br = 0;
    DISK_GEOMETRY dg;
    if(!DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY,
        0, 0, &dg, sizeof(dg), &br, 0))
    {
        DWORD err = GetLastError();
        printf("!DeviceIoControl, GetLastError: %d\n", err);
        return 0;
    }

    LARGE_INTEGER t1 = dg.Cylinders;
    int t2 = dg.TracksPerCylinder;
    int t3 = dg.SectorsPerTrack;
    int t4 = dg.BytesPerSector;
    unsigned long long total = t1.QuadPart*t2*t3*t4;

    printf("%lld\n", t1.QuadPart);
    printf("%d\n", t2);
    printf("%d\n", t3);
    printf("%d\n", t4);
    printf("%llu\n", total);

    //setup a counter
    long long i = 0;

    int bufsize = dg.BytesPerSector;
    char *buf = malloc(bufsize);
    while(ReadFile(handle, buf, bufsize, &br, NULL))
    {
        if(!br)
            break;

        //print update
        if((i % 1000) == 0)
            printf("%.2f Mb\n", (double)i * bufsize / 1000000.0f);
        i++;
    }

    free(buf);
    CloseHandle(handle);
    return 0;
}

Обратите внимание, что приведенное выше считывает один сектор за раз.Это полезно, если вы хотите исследовать каждый сектор отдельно, но это также медленно.

Метод ниже показывает чтение 100 секторов одновременно.Это быстрее, но немного сложнее, потому что оно включает сектора, которые не обязательно связаны между собой.Чтобы проверить, вы можете разбить buf на различные сектора.

//read N number of dg.BytesPerSector for each pass
int N = 100;
int bufsize = dg.BytesPerSector * N;
char *buf = malloc(bufsize);
while(ReadFile(handle, buf, bufsize, &br, NULL))
{
    if(!br)
        break;

    //print update
    if((i % 1000) == 0)
        printf("%.2f Mb\n", (double)i * bufsize / 1000000.0f);
    i++;

    //look for *.cpp files which have the string `#include` in them:
    //buf includes N sectors
    //look for `#include` in each sector and print the first 100 characters
    for(int j = 0; j < N * dg.BytesPerSector; j += dg.BytesPerSector)
        if(strstr(&buf[j], "#include"))
            printf("%.100s ...\n", &buf[j]);
}


Примечание: вы используете (LPCTSTR)strPath, который предполагает, что программа скомпилирована с определением UNICODE (как следуетбыть) но вы используете строку ANSI в качестве аргумента, а затем используете приведение, чтобы скрыть ошибку.Просто используйте Unicode для всех функций WinAPI.Установите предупреждение компилятора на самый высокий уровень и не используйте приведение, если вы не абсолютно уверены.Также ExpandEnvironmentStrings для других строк, таких как "%windir%".
0 голосов
/ 26 мая 2018

(Правка. В фрагменте, который вы указали при редактировании, оказалось, что фактический тип переменной правильный, но проблема в выводе - вы печатаете long long значения с %d, который печатает signed int. Для unsigned long long вы должны использовать %llu, а для signed long long это %lld.)

Ваша переменная total выглядит как signed int, который в вашей конфигурации - по-видимому, ПК с Windows x86-32 или x86-64 - имеет ширину 32 бита и, таким образом, может хранить значения до 2147483647 (2 ¹ -1) или 2 ГБ минус один байт.

Вы должны изменить его на unsigned long long (или uint64_t с stdint.h).

Также обратите внимание, что умножение int на int приводит к int - так что, если вы ожидаетерезультат умножения должен быть больше чем 2³¹ − 1, по крайней мере один из двух мультипликаторов должен быть long long.

В этом конкретном случае b.Cylinders.QuadPart уже является long long (не unsigned хотя, но нет дисков объемом более 9 эксабайт, по крайней мере, в 2018 году), поэтому результат умноженияn тоже будет long long, но обычно вы должны выполнять большое целочисленное умножение, например unsigned long long total = ((unsigned long long) uintA) * uintB * uintC * uintD.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...