Reputation: 870
I simply want to move the file-pointer of a volume handle backwards from FILE_END
. Unfortunately, the operation fails regardless of any input value I pass to it !
I'm using the following code:
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");
The output:
Handle acquired for volume \\.\C: SetFilePointer (BEGIN) SUCCESS! SetFilePointer (END) FAILED! Error 0x57: The parameter is incorrect. SetFilePointer (CURRENT) SUCCESS!
As you can see, the seek works fine for FILE_BEGIN
and FILE_CURRENT
, but it always fails for FILE_END
with error code 0x57
(87 in decimal) saying:
The parameter is incorrect
Note that changing dist
to a positive value doesn't change the situation.
What am I missing here?
( NOTE: Testing on Windows-5.1.2600 (XP SP3) in latest Code::Blocks IDE 16.01 with MinGW compiler, and Administrator privileges )
NOTE: This is absolutely not a duplicate of this question, since I am not accessing physical disk (volume access is different from physical disk) and the distance value is a multiple of 512 bytes (the logical sector size). If the distance length was incorrect, then the other seeks (BEGIN and CURRENT) would have failed as well, yet they don't.
Based on Rohans' answer, I performed another check with the following code:
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;
}
Although I believe Rohans' point is important, it still doesn't solve the problem:
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
Using a positive value for low_part
doesn't change the situation.
Based on David Heffernan's comment below, I acknowledge that this code can be shorter and easier using SetFilePointerEx
, but the result is still the same and the operation fails to seek from FILE_END
on the volume handle.
Upvotes: 1
Views: 3039
Reputation: 53386
You may have to pass the non-NULL value for 3rd parameter in the api call.
result = SetFilePointer (vol_handle, dist, NULL, FILE_END);
//-----------------------------------------^
So change that to
LONG distToMoveHigh = 0;
result = SetFilePointer (vol_handle, dist, &distToMoveHigh, FILE_END);
...
The reason as mentioned on the MSDN page is
If lpDistanceToMoveHigh is NULL and the new file position does not fit in a 32-bit value, the function fails and returns INVALID_SET_FILE_POINTER.
As you are working with volume its likely to be > 2GB. So the SetFilePointer()
api will not be able to return you new offset if its successful.
Upvotes: 2
Reputation: 36348
This is unsurprising. A volume is not a file, so it does not have an end-of-file position.
Windows could of course use the volume length as the end of file position, but there's no particular reason for it to handle this special case.
You will have to calculate the offset yourself.
Upvotes: 4