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

  • 本文关键字:磁盘 读取 c winapi
  • 更新时间 :
  • 英文 :


我尝试使用DeviceIoControl将数据放入有关磁盘的缓冲区b中。当我尝试使用类似 total = b.cylinders.quadpart * b.trackspercylinders * b.sectorpertrack * 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("%dn", t1.QuadPart);
int t2 = dg.TracksPerCylinder;
printf("%dn", t2);
int t3 = dg.SectorsPerTrack;
printf("%dn", t2);
int t4 = dg.BytesPerSector;
printf("%dn", 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: %dn", 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: %dn", 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("%lldn", t1.QuadPart);
printf("%dn", t2);
printf("%dn", t3);
printf("%dn", t4);
printf("%llun", 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 Mbn", (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 Mbn", (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隐藏错误。只需将Unicode用于所有WinAPI函数即可。将编译器警告设置为最高级别,除非绝对确定,否则不要使用强制转换。另外ExpandEnvironmentStrings是用于其他字符串,例如"%windir%".

(编辑:在编辑中提供的截图中,事实证明变量的实际类型是正确的,但问题出在输出中 - 您正在使用%d打印long long值,这会打印signed int。对于unsigned long long,你应该使用%llu,对于signed long long,它是%lld

您的total变量似乎是一个signed int,在您的配置中,它(显然是 Windows x86-32 或 x86-64 PC(是 32 位宽,因此可以存储高达 2147483647 (2³¹−1( 或 2 GB 减去一个字节的值。

您应该将其更改为unsigned long long(或从stdint.huint64_t(。

另请注意,将int乘以int会产生int— 因此,如果您预计乘法的结果大于 2³¹−1,则两个乘法中至少必须有一个long long

在这种特定情况下,b.Cylinders.QuadPart已经是一个long long(虽然不是unsigned,但至少在 9 年没有容量超过 2018 EB 的磁盘(,所以乘法的结果也将是一个long long,但通常你应该像unsigned long long total = ((unsigned long long) uintA) * uintB * uintC * uintD一样执行大整数乘法。

最新更新