Search code examples
cfilewinapiio

How do I set the size of a file opened with FILE_FLAG_OVERLAPPED?


One article suggests: "You have to call SetFilePointer before calling SetEndOfFile" but the documentation for SetFilePointer explicitly states: "The file pointer that is identified by the value of the hFile parameter is not used for overlapped read and write operations.".

Edit: I opened a file with FILE_FLAG_OVERLAPPED, did a SetFilePointer to 4MB and called SetEndOfFile. I then did SetFilePointer to zero bytes from FILE_BEGIN and then wrote to it with OVERLAPPED structure's Offset and OffsetHigh flag set to 0xFFFFFFFF. The write happened at the end of the file i.e. starting from the 4MB mark.


Solution

  • "The file pointer that is identified by the value of the hFile parameter is not used for overlapped read and write operations."

    yes. this is correct. but not for all I/O operations, but only for read and write ( and several others), but not for SetFilePointer ( NtSetInformationFile with FilePositionInformation )

    at first - what is file pointer ? look at FILE_OBJECT structure - the CurrentByteOffset - member that specifies the file offset, in bytes, associated with the file object - and so called file pointer in win32

    note, that this member basically managed by I/O manager itself and not by (filesystem) driver.

    we can get and set this member by call NtQueryInformationFile and NtSetInformationFile with FilePositionInformation

    despite here noted :

    The caller must have opened the file with FILE_SYNCHRONOUS_IO_ALERT or FILE_SYNCHRONOUS_IO_NONALERT flag specified in the CreateOptions parameter.

    this is not exactly true, even if file opened without this flags ( i.e. with FILE_FLAG_OVERLAPPED ) - usually this work (depend drom driver implementation). simply if file opened as synchronous - this operation handled by I/O manager itself (driver even not called). in case asynchronous file - request passed to driver. the filesystem drivers(fastfat, ntfs) handle this request by update CurrentByteOffset too.

    why this for read/write ? because look for signature of this api - it have (optional for synchronous handles) ByteOffset parameter - and if it present - it used, otherwise it taked from CurrentByteOffset in FILE_OBJECT. for asynchronous handles - ByteOffset is mandatory parameter - it always must be not 0 ( or system return error invalid parameter) - so CurrentByteOffset in asynchronous read/write I/O never used. but this is not related to NtSetInformationFile

    what is SetFilePointer do ? it call NtSetInformationFile with FilePositionInformation ( really it also call and NtQueryInformationFile too).

    what is SetEndOfFile do ? it first call NtQueryInformationFile with FilePositionInformation - for get value of CurrentByteOffset (which you set by SetFilePointer ) and then call NtSetInformationFile with FileEndOfFileInformation and FileAllocationInformation ( this call is optimization only).

    so SetFilePointer with SetEndOfFile will be work for any files. but not efficient. i suggest never use SetFilePointer at all. for concrete task - simply call NtSetInformationFile (the best) or if you not like ntapi - use SetFileInformationByHandle with FileEndOfFileInfo + FileAllocationInfo

            FILE_END_OF_FILE_INFO eof = { * };
            SetFileInformationByHandle(hFile, FileEndOfFileInfo, &eof, sizeof(eof));
            SetFileInformationByHandle(hFile, FileAllocationInfo, &eof, sizeof(eof));