aboutsummaryrefslogtreecommitdiff
path: root/libio/wfileops.c
diff options
context:
space:
mode:
Diffstat (limited to 'libio/wfileops.c')
-rw-r--r--libio/wfileops.c47
1 files changed, 24 insertions, 23 deletions
diff --git a/libio/wfileops.c b/libio/wfileops.c
index 8b2e1080b6..3199861b4d 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -597,12 +597,12 @@ done:
}
/* ftell{,o} implementation for wide mode. Don't modify any state of the file
- pointer while we try to get the current state of the stream. */
+ pointer while we try to get the current state of the stream except in one
+ case, which is when we have unflushed writes in append mode. */
static _IO_off64_t
do_ftell_wide (_IO_FILE *fp)
{
_IO_off64_t result, offset = 0;
- bool use_cached_offset = false;
/* No point looking for offsets in the buffer if it hasn't even been
allocated. */
@@ -615,6 +615,20 @@ do_ftell_wide (_IO_FILE *fp)
> fp->_wide_data->_IO_write_base)
|| _IO_in_put_mode (fp));
+ bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
+
+ /* When we have unflushed writes in append mode, seek to the end of the
+ file and record that offset. This is the only time we change the file
+ stream state and it is safe since the file handle is active. */
+ if (was_writing && append_mode)
+ {
+ result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
+ if (result == _IO_pos_BAD)
+ return EOF;
+ else
+ fp->_offset = result;
+ }
+
/* XXX For wide stream with backup store it is not very
reasonable to determine the offset. The pushed-back
character might require a state change and we need not be
@@ -703,37 +717,24 @@ do_ftell_wide (_IO_FILE *fp)
position is fp._offset - (_IO_read_end - new_write_ptr). */
offset -= fp->_IO_read_end - fp->_IO_write_ptr;
}
-
- /* It is safe to use the cached offset when available if there is
- unbuffered data (indicating that the file handle is active) and
- the handle is not for a file open in a+ mode. The latter
- condition is because there could be a scenario where there is a
- switch from read mode to write mode using an fseek to an arbitrary
- position. In this case, there would be unbuffered data due to be
- appended to the end of the file, but the offset may not
- necessarily be the end of the file. It is fine to use the cached
- offset when the a+ stream is in read mode though, since the offset
- is maintained correctly in that case. Note that this is not a
- comprehensive set of cases when the offset is reliable. The
- offset may be reliable even in some cases where there is no
- unflushed input and the handle is active, but it's just that we
- don't have a way to identify that condition reliably. */
- use_cached_offset = (offset != 0 && fp->_offset != _IO_pos_BAD
- && ((fp->_flags & (_IO_IS_APPENDING | _IO_NO_READS))
- == (_IO_IS_APPENDING | _IO_NO_READS)
- && was_writing));
}
- if (use_cached_offset)
+ if (fp->_offset != _IO_pos_BAD)
result = fp->_offset;
else
- result = get_file_offset (fp);
+ result = _IO_SYSSEEK (fp, 0, _IO_seek_cur);
if (result == EOF)
return result;
result += offset;
+ if (result < 0)
+ {
+ __set_errno (EINVAL);
+ return EOF;
+ }
+
return result;
}