Reputation: 33627
I do not understand why the following code, which sets the position of an open file handle relative to the base (i. e. sets the absolute position) succeeds when trying to set a positive position for an empty file that's open for reading only:
LARGE_INTEGER offset;
offset.QuadPart = 100;
LARGE_INTEGER pos = {0};
return ::SetFilePointerEx(_h, offset, &pos, FILE_BEGIN) != 0;
It returns a non-zero result, and the pos
variable receives the value 100. That behavior is counter-intuitive for a GENRIC_READ file of size zero, what is the logic? I understand that this is normal behavior for files with write access.
P. S. The file is not overlapped and overall as simple as it can be with no fancy flags.
Does SetFilePointerEx
ever fail at all for valid handles, positive absolute positions and plain files?
Upvotes: 0
Views: 148
Reputation: 33804
SetFilePointerEx
internally call ZwSetInformationFile
with FilePositionInformation. the FILE_POSITION_INFORMATION
used as input.
exist only such restriction on this value
If the file was opened or created with the
FILE_NO_INTERMEDIATE_BUFFERING
option, the value ofCurrentByteOffset
must be an integral multiple of the sector size of the underlying device.
also, always must be 0 <= CurrentByteOffset.QuadPart
- so position must be not negative.
no more restriction on position value. you can set it to any, not depend from file size. this call even never go to file system but handle by I/O manager.
all what he doing - set CurrentByteOffset
in FILE_OBJECT
how this is used ? when we call ZwReadFile
or ZwWriteFile
- the optional parameter ByteOffset
exist
Pointer to a variable that specifies the starting byte offset in the file where the read operation will begin. If an attempt is made to read beyond the end of the file, ZwReadFile returns an error.
If the call to ZwCreateFile set either of the CreateOptions flags FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT, the I/O Manager maintains the current file position. If so, the caller of ZwReadFile can specify that the current file position offset be used instead of an explicit ByteOffset value. This specification can be made by using one of the following methods:
Specify a pointer to a LARGE_INTEGER value with the HighPart member set to -1 and the LowPart member set to the system-defined value FILE_USE_FILE_POINTER_POSITION.
Pass a NULL pointer for ByteOffset.
ZwReadFile updates the current file position by adding the number of bytes read when it completes the read operation, if it is using the current file position maintained by the I/O Manager.
Even when the I/O Manager is maintaining the current file position, the caller can reset this position by passing an explicit ByteOffset value to ZwReadFile. Doing this automatically changes the current file position to that ByteOffset value, performs the read operation, and then updates the position according to the number of bytes actually read. This technique gives the caller atomic seek-and-read service.
so we can or explicit pass ByteOffset
value or use additional api call for set it first in FILE_OBJECT
and then I/O manager take it from here, if no explicit ByteOffset
pointer.
note - in case asynchronous I/O - we need always explicit pass ByteOffset
value or call just fail (exception for pipes and mailslot files)
in case ReadFile
and WriteFile
- ByteOffset
taken from OVERLAPPED
parameter. if it is 0 - the ByteOffset
set to 0 pointer and CurrentByteOffset
from FILE_OBJECT
is used. and if pointer to OVERLAPPED
not 0 - the exactly value from OVERLAPPED
is explicit passed as ByteOffset
value and CurrentByteOffset
in FILE_OBJECT
is ignored.
also always is ok use pointer to OVERLAPPED
- not only for asynchronous file handles. simply for asynchronous - this is mandatory parameter and for synchronous is optional.
really faster and better - direct pass pointer to api call (read/write) than use separate api call, which take time, can (theoretical) fail, etc
use SetFilePointer
may be exist sense only in legacu code, where it called from huge count of places, for not modify too many code
Upvotes: 2