1e5f839b46
- Backport of upstream BZ #5298. Don't flush buffer for ftell. Compute offsets from write pointers instead. (#577950)
195 lines
7.9 KiB
Diff
195 lines
7.9 KiB
Diff
diff -Nrup a/libio/fileops.c b/libio/fileops.c
|
|
--- a/libio/fileops.c 2012-06-30 15:12:34.000000000 -0400
|
|
+++ b/libio/fileops.c 2012-11-28 12:27:00.297009479 -0500
|
|
@@ -978,6 +978,9 @@ _IO_new_file_seekoff (fp, offset, dir, m
|
|
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, m
|
|
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-papped 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, m
|
|
{
|
|
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)
|
|
diff -Nrup a/libio/wfileops.c b/libio/wfileops.c
|
|
--- a/libio/wfileops.c 2012-11-28 10:47:08.906188748 -0500
|
|
+++ b/libio/wfileops.c 2012-11-28 12:34:06.285439028 -0500
|
|
@@ -611,6 +611,10 @@ _IO_wfile_seekoff (fp, offset, dir, mode
|
|
&& (fp->_wide_data->_IO_write_base
|
|
== fp->_wide_data->_IO_write_ptr));
|
|
|
|
+ bool was_writing = ((fp->_wide_data->_IO_write_ptr
|
|
+ > fp->_wide_data->_IO_write_base)
|
|
+ || _IO_in_put_mode (fp));
|
|
+
|
|
if (mode == 0)
|
|
{
|
|
/* XXX For wide stream with backup store it is not very
|
|
@@ -642,11 +646,8 @@ _IO_wfile_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->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
|
|
- || _IO_in_put_mode (fp))
|
|
- if (_IO_switch_to_wget_mode (fp))
|
|
- return WEOF;
|
|
+ else if (was_writing && _IO_switch_to_wget_mode (fp))
|
|
+ return WEOF;
|
|
|
|
if (fp->_wide_data->_IO_buf_base == NULL)
|
|
{
|
|
@@ -677,29 +678,104 @@ _IO_wfile_seekoff (fp, offset, dir, mode
|
|
cv = fp->_codecvt;
|
|
clen = (*cv->__codecvt_do_encoding) (cv);
|
|
|
|
- if (clen > 0)
|
|
+ if (mode != 0 || !was_writing)
|
|
{
|
|
- offset -= (fp->_wide_data->_IO_read_end
|
|
- - fp->_wide_data->_IO_read_ptr) * clen;
|
|
- /* Adjust by readahead in external buffer. */
|
|
- offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
|
+ if (clen > 0)
|
|
+ {
|
|
+ offset -= (fp->_wide_data->_IO_read_end
|
|
+ - fp->_wide_data->_IO_read_ptr) * clen;
|
|
+ /* Adjust by readahead in external buffer. */
|
|
+ offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ int nread;
|
|
+
|
|
+ flushed:
|
|
+ delta = (fp->_wide_data->_IO_read_ptr
|
|
+ - fp->_wide_data->_IO_read_base);
|
|
+ fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
|
|
+ nread = (*cv->__codecvt_do_length) (cv,
|
|
+ &fp->_wide_data->_IO_state,
|
|
+ fp->_IO_read_base,
|
|
+ fp->_IO_read_end, delta);
|
|
+ fp->_IO_read_ptr = fp->_IO_read_base + nread;
|
|
+ fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
|
|
+ offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
|
|
+ }
|
|
}
|
|
else
|
|
{
|
|
- int nread;
|
|
+ char *new_write_ptr = fp->_IO_write_ptr;
|
|
|
|
- delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
|
|
- fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
|
|
- nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
|
|
- fp->_IO_read_base,
|
|
- fp->_IO_read_end, delta);
|
|
- fp->_IO_read_ptr = fp->_IO_read_base + nread;
|
|
- fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
|
|
- offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
|
|
+ if (clen > 0)
|
|
+ offset += (fp->_wide_data->_IO_write_ptr
|
|
+ - fp->_wide_data->_IO_write_base) / clen;
|
|
+ else
|
|
+ {
|
|
+ enum __codecvt_result status;
|
|
+ delta = (fp->_wide_data->_IO_write_ptr
|
|
+ - fp->_wide_data->_IO_write_base);
|
|
+ const wchar_t *write_base = fp->_wide_data->_IO_write_base;
|
|
+
|
|
+ /* FIXME: This actually ends up in two iterations of conversion,
|
|
+ one here and the next when the buffer actually gets flushed.
|
|
+ It may be possible to optimize this in future so that
|
|
+ wdo_write identifies already converted content and does not
|
|
+ redo it. In any case, this is much better than having to
|
|
+ flush buffers for every ftell. */
|
|
+ do
|
|
+ {
|
|
+ /* Ugh, no point trying to avoid the flush. Just do it
|
|
+ and go back to how it was with the read mode. */
|
|
+ if (delta > 0 && new_write_ptr == fp->_IO_buf_end)
|
|
+ {
|
|
+ if (_IO_switch_to_wget_mode (fp))
|
|
+ return WEOF;
|
|
+ goto flushed;
|
|
+ }
|
|
+
|
|
+ const wchar_t *new_wbase = fp->_wide_data->_IO_write_base;
|
|
+ fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
|
|
+ status = (*cv->__codecvt_do_out) (cv,
|
|
+ &fp->_wide_data->_IO_state,
|
|
+ write_base,
|
|
+ write_base + delta,
|
|
+ &new_wbase,
|
|
+ new_write_ptr,
|
|
+ fp->_IO_buf_end,
|
|
+ &new_write_ptr);
|
|
+
|
|
+ delta -= new_wbase - write_base;
|
|
+
|
|
+ /* If there was an error, then return WEOF.
|
|
+ TODO: set buffer state. */
|
|
+ if (__builtin_expect (status == __codecvt_error, 0))
|
|
+ return WEOF;
|
|
+ }
|
|
+ while (delta > 0);
|
|
+ }
|
|
+
|
|
+ /* _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 - new_write_ptr;
|
|
}
|
|
|
|
if (fp->_offset == _IO_pos_BAD)
|
|
- goto dumb;
|
|
+ {
|
|
+ if (mode != 0)
|
|
+ goto dumb;
|
|
+ else
|
|
+ {
|
|
+ result = _IO_SYSSEEK (fp, 0, dir);
|
|
+ if (result == EOF)
|
|
+ return result;
|
|
+ fp->_offset = result;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Make offset absolute, assuming current pointer is file_ptr(). */
|
|
offset += fp->_offset;
|
|
|
|
Binary files a/libio/.wfileops.c.swp and b/libio/.wfileops.c.swp differ
|