c - 在C中逐位读取整个磁盘的内容

标签 c winapi

我已经尝试使用 DeviceIoControl 将数据放入磁盘的缓冲区 b 中。当我尝试使用诸如 total = b.cylinders.quadpart * b.trackspercylinds * 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);
                }

            }

这段代码看起来正确吗?因为我似乎仍然得到一个负数!

最佳答案

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 字符串作为参数,然后使用 cast隐藏错误。只需对所有 WinAPI 函数使用 Unicode。将编译器警告设置为最高级别,除非您绝对确定,否则不要使用强制转换。此外,ExpandEnvironmentStrings 用于其他字符串,例如 "%windir%"

关于c - 在C中逐位读取整个磁盘的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50541731/

相关文章:

c - 打印一个随机数返回一个负数。 (/开发/随机)

CMake - 包含第三方文件

c - 使用 NpyIter(新 API)直接访问数据是如何工作的? char * 类型如何处理?

c++ - SetWindowSubclass 内的 msftedit.dll RichEdit 控件出现错误 "Access violation reading location 0x00000008"

c++ - 我的代码从另一个进程附加和使用控制台有什么问题?

c++ - Linux 和 MSVC Win32 上 C++ 中模板类实现之间的差异

c++ - 填充矩形类型的 PictureBox,C++ WINAPI

c++ - 如何将我想在 C++ 中使用的 C 库的库路径添加到环境中

c - 从C中的数字字符串中查找数字组合的总和

c++ - boost::threads - 如何正常关机?