【问题标题】:Moving the file pointer of a disk with SetFilePointerEx [closed]使用 SetFilePointerEx 移动磁盘的文件指针 [关闭]
【发布时间】:2023-03-13 06:32:01
【问题描述】:

我正在尝试使用SetFilePointerEx() 将磁盘的文件指针移动到特定偏移量(文件的最后一个簇)。计算出的偏移量是:

LARGE_INTEGER dist;
dist.QuadPart = (output1.QuadPart * dwBytesPerSect) + ((lastExtent + lengthOfExtent - 1) * totalClusterSize);
BOOL res = SetFilePointerEx(hDevice, dist, nullptr, FILE_BEGIN);
if (!res){
    // handle error
    DWORD error = GetLastError();
    cout<<GetLastError()<<endl;
    cout << "'There is an error with SetFilePointerEX" << endl;
}
cout<<"This is the SetFilePointer distance: \n\n"<<dist.QuadPart;

然后我使用Readfile() 读取最后一个 4k 簇块:

DWORD nRead;
unsigned char *buff;
buff = new unsigned char[totalClusterSize];

BOOL fileFromVol = ReadFile(hDevice,   //C drive
                buff,
                4096,
                &nRead,
                NULL);

if (fileFromVol == 0){         //Error handling
    cout << "Error with fileFromVol" << "\n\n";
    DWORD error = GetLastError();
    cout<<error<<endl;
        if (error == ERROR_ACCESS_DENIED){
            cout << "error_access_denied"<<endl;
        }
}
cout<<"\n\n"<<buff<<"\n\n";
memset(buff,NULL,4096);

所以我的文件偏移量dist.QuadPart 始终保持不变,但每次我在同一个文件上运行我的程序时,我的读取缓冲区 (buff) 都会更改十六进制值。

首次运行示例:

This is the SetFilePointer distance:

3689362889266376704

008F4264

第二次运行示例:

This is the SetFilePointer distance:

3689362889266376704

00E53CE8

任何想法为什么它不断变化?

下一步,我需要将零写入集群。我可以使用memset() 在最后一个集群位置写零吗?

【问题讨论】:

  • 不就是打印buff[0]的地址吗?为什么每次都不会改变?
  • 我正在尝试从指定文件(如文本文件)的最后一个集群中读取数据,如果我不修改文件,数据不应该保持不变吗?
  • 几点:您不应该将簇大小硬编码为 4096。您需要获取正在处理的卷的簇大小(每个簇的扇区数 * 每个扇区的字节数)和使用该值分配集群缓冲区并执行读取。此外,您的集群缓冲区是一个 4096 ints 的数组(x86 上是 16KB) - 它应该是一个字节数组。
  • 您没有打印文件中的数据。您正在打印堆栈分配缓冲区的地址。由于各种因素(例如 ASLR),每次运行程序或调用函数时,该缓冲区的地址都会发生变化。
  • 所以对于数组我应该使用 unsigned char [每个簇的扇区 * 每个扇区的字节数]?如何判断我是否从同一个文件句柄中读取数据?我的下一步是将数据写入文件偏移量,但我不想将数据写入错误的位置(系统文件)。

标签: c++ winapi


【解决方案1】:

您要打印的值是缓冲区的地址,而不是其内容。而且缓冲区的地址是不固定的。当然,争论为什么缓冲区的地址会改变有点没有实际意义,因为您实际上想打印出缓冲区的内容。

像这样打印出数组的第一个元素:

cout<<"\n\n"<<buff[0]<<"\n\n";

您应该会看到从磁盘读取的值。

其他一些cmets:

  1. 不要对缓冲区大小进行硬编码。您必须确保它是扇区大小的倍数。
  2. 你的缓冲区应该是unsigned char*而不是unsigned int*
  3. 检查值nRead,以防缓冲区仅部分填充。

【讨论】:

  • 我把缓冲区改成:
    unsigned char *buff; buff = new unsigned char[totalClusterSize];
    当我 cout 时,nRead 的值显示为 0。对于我尝试的每个文件,我对 buff[0] 的 cout 都是“=”。不知道这意味着什么。
  • 表示没有读取任何字节。很多可能的原因。
  • 有什么常见的地方可以检查读取错误吗?
  • 首先检查您是否可以从头开始阅读。然后仔细阅读所有文档。创建文件和读取文件。这来自 CreateFile 文档可能是相关的:注意要读取或写入卷的最后几个扇区,您必须调用 DeviceIoControl 并指定 FSCTL_ALLOW_EXTENDED_DASD_IO。这指示文件系统驱动程序不要对分区读取或写入调用执行任何 I/O 边界检查。相反,边界检查由设备驱动程序执行。
  • 好的,我想我可能做错了。截至目前,我有 2 个 DevicIoControl 调用。第一个 DeviceIoControl 具有控制代码FSCTL_GET_RETRIEVAL_POINTERS,用于查找文件范围的范围信息。第二个 DeviceIoControl 调用 FSCTL_GET_RETRIEVAL_POINTER_BASE 以查找有关 vcn 的驱动器上的 infomartion(因为我们不能假设它从 0 开始)。我应该第三次使用FSCTL_ALLOW_EXTENDED_DASD_IO 调用它吗?我的第二次调用应该是文件句柄而不是驱动器句柄吗?
猜你喜欢
  • 2018-01-09
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
相关资源
最近更新 更多