Don't flush write buffer for ftell
[BZ #5298] Use write pointer state along with the file offset and/or the read pointers to get the current file position.
This commit is contained in:
parent
4573c6b098
commit
adb26faefe
|
@ -1,3 +1,10 @@
|
|||
2012-09-28 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
|
||||
[BZ #5298]
|
||||
* libio/fileops.c (_IO_new_file_seekoff): Don't flush buffer
|
||||
for ftell. Compute offsets from write pointers instead.
|
||||
* libio/wfileops.c (_IO_wfile_seekoff): Likewise.
|
||||
|
||||
2012-09-28 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
|
||||
[BZ #14543]
|
||||
|
|
13
NEWS
13
NEWS
|
@ -9,12 +9,13 @@ Version 2.17
|
|||
|
||||
* The following bugs are resolved with this release:
|
||||
|
||||
1349, 3479, 5044, 5400, 6778, 6808, 9685, 9914, 10014, 10038, 11607,
|
||||
13412, 13542, 13629, 13679, 13696, 13717, 13741, 13939, 13966, 14042,
|
||||
14090, 14150, 14151, 14154, 14157, 14166, 14173, 14195, 14237, 14252,
|
||||
14283, 14298, 14303, 14307, 14328, 14331, 14336, 14337, 14347, 14349,
|
||||
14376, 14459, 14476, 14505, 14510, 14516, 14518, 14519, 14530, 14532,
|
||||
14538, 14543, 14544, 14545, 14562, 14576, 14579, 14583, 14587, 14621.
|
||||
1349, 3479, 5044, 5298, 5400, 6778, 6808, 9685, 9914, 10014, 10038,
|
||||
11607, 13412, 13542, 13629, 13679, 13696, 13717, 13741, 13939, 13966,
|
||||
14042, 14090, 14150, 14151, 14154, 14157, 14166, 14173, 14195, 14237,
|
||||
14252, 14283, 14298, 14303, 14307, 14328, 14331, 14336, 14337, 14347,
|
||||
14349, 14376, 14459, 14476, 14505, 14510, 14516, 14518, 14519, 14530,
|
||||
14532, 14538, 14543, 14544, 14545, 14562, 14576, 14579, 14583, 14587,
|
||||
14621.
|
||||
|
||||
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
|
||||
Optimized versions of memcpy, memset, and memcmp added for System z10 and
|
||||
|
|
|
@ -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)
|
||||
|
|
116
libio/wfileops.c
116
libio/wfileops.c
|
@ -613,6 +613,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
|
||||
|
@ -644,11 +648,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)
|
||||
{
|
||||
|
@ -679,29 +680,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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue