_filelengthi64 reads the size on disk and misses bytes still in the stdio write buffer, so a valid negative SEEK_END seek after an unflushed fwrite was rejected with EINVAL. Flush first, and cover it with a test that seeks from the end right after a buffered write.
Co-authored-by: Opensource55 <[email protected]>
The UCRT drops a stream's read buffer before its `lseek` to a negative target fails with
`EINVAL`, so a rejected `fseeko` or `fsetpos` left the stream at the descriptor's read-ahead
offset: after 4 of 8 buffered bytes, a rejected `fsetpos` to -1 reported the position as 8 and
the next read returned EOF. FreeBSD 11.4's `_fseeko` keeps the buffer and the position when
`_sseek` fails.
`fseeko` now rejects a target before the start of the file before the host stream is touched,
computing the base from `_ftelli64` for `SEEK_CUR` and `_filelengthi64` for `SEEK_END`, and
answers `EINVAL` with the stream unchanged. A target that is not negative still goes to
`_fseeki64`, and a host seek that fails for another reason behaves as before.
`file_position` gains the three rejected targets: `fsetpos` to -1 after 4 buffered bytes,
`fseeko` with `SEEK_CUR` past the start, and `fseeko` with `SEEK_END` past the start; each
asserts `EINVAL`, an unchanged `fgetpos` and the next byte read.
On Windows, std::tmpfile() returns NULL with errno 22 when %TEMP%
contains a character outside the ANSI code page, where GetTempPathA
returns '?' in its place. Fifteen tests that capture output through it
aborted. TemporaryFile::Open() opens a unique delete-on-close file under
temp_directory_path() with _wfopen; other hosts keep std::tmpfile().
Part of #13083
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FilePosition checked fgetpos and fsetpos only on a freshly written
stream. It now reads three bytes and requires fgetpos to give 3, reads
to end of file and requires fsetpos back to 3 to clear the end-of-file
indicator (C11 7.21.9.3) so the next fgetc returns the fourth byte, and
requires fsetpos to -1 to fail with EINVAL as FreeBSD's fseeko does.
A rejected seek on Windows still moves the stream, because the UCRT
drops its read buffer before the failing lseek: recorded in libc's
technical debt instead of asserted.
Co-Authored-By: Claude Opus 5.5 <[email protected]>