diff options
Diffstat (limited to 'libio/fileops.c')
-rw-r--r-- | libio/fileops.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/libio/fileops.c b/libio/fileops.c index e22efdec13..173091cc6c 100644 --- a/libio/fileops.c +++ b/libio/fileops.c @@ -978,6 +978,9 @@ _IO_new_file_seekoff (fp, offset, dir, mode) int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end && fp->_IO_write_base == fp->_IO_write_ptr); + bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base + || _IO_in_put_mode (fp)); + if (mode == 0) dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ @@ -988,10 +991,8 @@ _IO_new_file_seekoff (fp, offset, dir, mode) which assumes file_ptr() is eGptr. Anyway, since we probably end up flushing when we close(), it doesn't make much difference.) FIXME: simulate mem-mapped files. */ - - if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp)) - if (_IO_switch_to_get_mode (fp)) - return EOF; + else if (was_writing && _IO_switch_to_get_mode (fp)) + return EOF; if (fp->_IO_buf_base == NULL) { @@ -1010,7 +1011,17 @@ _IO_new_file_seekoff (fp, offset, dir, mode) { case _IO_seek_cur: /* Adjust for read-ahead (bytes is buffer). */ - offset -= fp->_IO_read_end - fp->_IO_read_ptr; + if (mode != 0 || !was_writing) + offset -= fp->_IO_read_end - fp->_IO_read_ptr; + else + { + /* _IO_read_end coincides with fp._offset, so the actual file position + is fp._offset - (_IO_read_end - new_write_ptr). This is fine + even if fp._offset is not set, since fp->_IO_read_end is then at + _IO_buf_base and this adjustment is for unbuffered output. */ + offset -= fp->_IO_read_end - fp->_IO_write_ptr; + } + if (fp->_offset == _IO_pos_BAD) { if (mode != 0) |