来自FILE_END的SetFilePointer始终对卷句柄失败

时间:2016-06-10 02:15:51

标签: c++ c windows winapi

我只想从FILE_END向后移动卷句柄的文件指针。不幸的是,无论我传递给它的任何输入值,操作都会失败!

我使用以下代码:

HANDLE vol_handle = CreateFile ("\\\\.\\C:",
                         GENERIC_READ | GENERIC_WRITE,
                         FILE_SHARE_READ | FILE_SHARE_WRITE,
                         NULL, OPEN_EXISTING, 0, NULL);

if (vol_handle == INVALID_HANDLE_VALUE)
{
    printf("Failed to create volume handle!\n");
    print_last_error(GetLastError());
    return ERROR;
}
printf("Handle acquired for volume %s \n", VOLUME);

long int dist = 512000; // 500 KB forwards

SetLastError(0);
int result = SetFilePointer (vol_handle, dist, NULL, FILE_BEGIN);
if (result == INVALID_SET_FILE_POINTER)
{
    printf("SetFilePointer (BEGIN) FAILED!\n");
    print_last_error(GetLastError());
}
else
    printf("SetFilePointer (BEGIN) SUCCESS!\n");

dist = -5120; // 50 KB backwards

SetLastError(0);
result = SetFilePointer (vol_handle, dist, NULL, FILE_END);
if (result == INVALID_SET_FILE_POINTER)
{
    printf("SetFilePointer (END) FAILED!\n");
    print_last_error(GetLastError());
}
else
    printf("SetFilePointer (END) SUCCESS!\n");

SetLastError(0);
result = SetFilePointer (vol_handle, dist, NULL, FILE_CURRENT);
if (result == INVALID_SET_FILE_POINTER)
{
    printf("SetFilePointer (CURRENT) FAILED!\n", offset_low_part);
    print_last_error(GetLastError());
}
else
    printf("SetFilePointer (CURRENT) SUCCESS!\n");

输出:

  Handle acquired for volume \\.\C:
  SetFilePointer (BEGIN) SUCCESS!
  SetFilePointer (END) FAILED!
     Error 0x57: The parameter is incorrect.
  SetFilePointer (CURRENT) SUCCESS!

正如您所看到的,该搜索适用于FILE_BEGINFILE_CURRENT,但FILE_END的错误代码始终失败,错误代码为0x57(十进制为87),表示:

  The parameter is incorrect

请注意,将dist更改为正值并不会改变这种情况。

我在这里缺少什么?

(注意:在最新的Code :: Blocks IDE 16.01中使用MinGW编译器和管理员权限在Windows-5.1.2600(XP SP3)上进行测试)

注意:这绝对不是this question的重复,因为我没有访问物理磁盘(卷访问与物理磁盘不同),距离值是512的倍数字节(逻辑扇区大小)。如果距离长度不正确,那么另一个寻求(BEGIN和CURRENT)也会失败,但他们不会。

更新

根据Rohans'回答,我使用以下代码执行了另一项检查:

long long int offset_64 = 5120000 // 5000 KB distance;
long int offset_low_part = -(0xffffffff & offset_64);
long int offset_hig_part = offset_64 >> 32;

printf("offset_64 = %lld\n", offset_64);
printf("low_part  = %ld\n", offset_low_part);
printf("high_part = %ld\n\n", offset_hig_part);

// Get volume handle using CreateFile(...) exactly as before;

SetLastError(0);
int result = SetFilePointer (vol_handle, offset_low_part, &offset_hig_part, FILE_END);

if (result == INVALID_SET_FILE_POINTER)
{
    print_last_error(GetLastError());
    printf("Failed to set file pointer!\n");
    printf("high_part after SetFilePointer = %ld\n", offset_hig_part);
    return ERROR;
}

虽然我相信Rohans'重要的是,它仍然没有解决问题:

offset_64 = 5120000
low_part  = -5120000
high_part = 0

Handle acquired for volume \\.\C:
Error 0x57: The parameter is incorrect.
Failed to set file pointer!
high_part after SetFilePointer = 0

使用low_part的正值并不会改变这种情况。

更新

根据David Heffernan在下面的评论,我承认使用SetFilePointerEx可以缩短和简化此代码,但结果仍然相同,操作无法从FILE_END寻求在音量处理上。

2 个答案:

答案 0 :(得分:3)

这并不令人惊讶。卷不是文件,因此它没有文件结束位置。

Windows 当然可以使用卷长度作为文件结束位置,但没有特别的理由来处理这种特殊情况。

您必须自己计算偏移量。

答案 1 :(得分:2)

您可能必须在api调用中传递第3个参数的非NULL值。

result = SetFilePointer (vol_handle, dist, NULL, FILE_END);
//-----------------------------------------^

所以改为

LONG distToMoveHigh = 0;
result = SetFilePointer (vol_handle, dist, &distToMoveHigh, FILE_END);
...

MSDN页面上提到的原因是

  

如果lpDistanceToMoveHigh为NULL并且新文件位置不适合32位值,则该函数将失败并返回INVALID_SET_FILE_POINTER。

当您使用音量时,它很可能是> 2GB。因此SetFilePointer() api如果成功,将无法返回新的偏移量。