This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Ping! On Thu, Feb 20, 2014 at 10:59:04PM +0530, Siddhesh Poyarekar wrote: > Hi, > > So this is take 3 for this fix: > > ftell semantics are distinct from fseek(SEEK_CUR) especially when it > is called on a file handler that is not yet active. Due to this > caveat, much care needs to be taken while modifying the handler data > and hence, this first iteration on separating out ftell focusses on > maintaining handler data integrity at all times while it figures out > the current stream offset. The result is that it makes a syscall for > every offset request. > > There is scope for optimizing this by caching offsets when we know > that the handler is active. A simple way to find out is when the > buffers have data. It is not so simple to find this out when the > buffer is empty without adding some kind of flag. I have done this in > Patch 2/2. > > I have verified on x86_64 that there are no regressions in the > testsuite resulting fomr this patch. The patch also includes a test > case that tests ftell behaviour at various points before and after the > streame handle becomes active. > > Siddhesh > > [BZ #16532] > * libio/libioP.h (get_file_offset): New function. > * libio/fileops.c (get_file_offset): Likewise. > (do_ftell): Likewise. > (_IO_new_file_seekoff): Split out ftell logic. > * libio/wfileops.c (do_ftell_wide): Likewise. > (_IO_wfile_seekoff): Split out ftell logic. > * libio/tst-ftell-active-handler.c: New test case. > * libio/Makefile (tests): Add it. > > > --- > libio/Makefile | 2 +- > libio/fileops.c | 93 ++++++---- > libio/libioP.h | 1 + > libio/tst-ftell-active-handler.c | 366 +++++++++++++++++++++++++++++++++++++++ > libio/wfileops.c | 224 +++++++++++++----------- > 5 files changed, 553 insertions(+), 133 deletions(-) > create mode 100644 libio/tst-ftell-active-handler.c > > diff --git a/libio/Makefile b/libio/Makefile > index 8c333ce..8ccd80f 100644 > --- a/libio/Makefile > +++ b/libio/Makefile > @@ -60,7 +60,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ > tst-wmemstream1 tst-wmemstream2 \ > bug-memstream1 bug-wmemstream1 \ > tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ > - tst-fwrite-error tst-ftell-partial-wide > + tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler > ifeq (yes,$(build-shared)) > # Add test-fopenloc only if shared library is enabled since it depends on > # shared localedata objects. > diff --git a/libio/fileops.c b/libio/fileops.c > index a3499be..a177302 100644 > --- a/libio/fileops.c > +++ b/libio/fileops.c > @@ -931,6 +931,59 @@ _IO_file_sync_mmap (_IO_FILE *fp) > > > _IO_off64_t > +get_file_offset (_IO_FILE *fp) > +{ > + if ((fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING) > + { > + struct stat64 st; > + bool ret = (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode)); > + if (ret) > + return st.st_size; > + else > + return EOF; > + } > + else > + return _IO_SYSSEEK (fp, 0, _IO_seek_cur); > +} > + > + > +/* ftell{,o} implementation. Don't modify any state of the file pointer while > + we try to get the current state of the stream. */ > +static _IO_off64_t > +do_ftell (_IO_FILE *fp) > +{ > + _IO_off64_t result; > + > + result = get_file_offset (fp); > + > + if (result == EOF) > + return result; > + > + /* No point looking at unflushed data if we haven't allocated buffers > + yet. */ > + if (fp->_IO_buf_base != NULL) > + { > + bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base > + || _IO_in_put_mode (fp)); > + > + /* Adjust for unflushed data. */ > + if (!was_writing) > + result -= fp->_IO_read_end - fp->_IO_read_ptr; > + else > + result += fp->_IO_write_ptr - fp->_IO_read_end; > + } > + > + if (result < 0) > + { > + __set_errno (EINVAL); > + return EOF; > + } > + > + return result; > +} > + > + > +_IO_off64_t > _IO_new_file_seekoff (fp, offset, dir, mode) > _IO_FILE *fp; > _IO_off64_t offset; > @@ -940,6 +993,13 @@ _IO_new_file_seekoff (fp, offset, dir, mode) > _IO_off64_t result; > _IO_off64_t delta, new_offset; > long count; > + > + /* Short-circuit into a separate function. We don't want to mix any > + functionality and we don't want to touch anything inside the FILE > + object. */ > + if (mode == 0) > + return do_ftell (fp); > + > /* POSIX.1 8.2.3.7 says that after a call the fflush() the file > offset of the underlying file must be exact. */ > int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end > @@ -948,9 +1008,6 @@ _IO_new_file_seekoff (fp, offset, dir, mode) > 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. */ > - > /* Flush unwritten characters. > (This may do an unneeded write if we seek within the buffer. > But to be able to switch to reading, we would need to set > @@ -958,7 +1015,7 @@ _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. */ > - else if (was_writing && _IO_switch_to_get_mode (fp)) > + if (was_writing && _IO_switch_to_get_mode (fp)) > return EOF; > > if (fp->_IO_buf_base == NULL) > @@ -978,30 +1035,10 @@ _IO_new_file_seekoff (fp, offset, dir, mode) > { > case _IO_seek_cur: > /* Adjust for read-ahead (bytes is buffer). */ > - 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; > - } > + offset -= fp->_IO_read_end - fp->_IO_read_ptr; > > if (fp->_offset == _IO_pos_BAD) > - { > - if (mode != 0) > - goto dumb; > - else > - { > - result = _IO_SYSSEEK (fp, 0, dir); > - if (result == EOF) > - return result; > - > - fp->_offset = result; > - } > - } > + goto dumb; > /* Make offset absolute, assuming current pointer is file_ptr(). */ > offset += fp->_offset; > if (offset < 0) > @@ -1028,10 +1065,6 @@ _IO_new_file_seekoff (fp, offset, dir, mode) > } > /* At this point, dir==_IO_seek_set. */ > > - /* If we are only interested in the current position we've found it now. */ > - if (mode == 0) > - return offset; > - > /* If destination is within current buffer, optimize: */ > if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL > && !_IO_in_backup (fp)) > diff --git a/libio/libioP.h b/libio/libioP.h > index 4ca723c..8a7b85b 100644 > --- a/libio/libioP.h > +++ b/libio/libioP.h > @@ -397,6 +397,7 @@ extern void _IO_wdoallocbuf (_IO_FILE *) __THROW; > libc_hidden_proto (_IO_wdoallocbuf) > extern void _IO_unsave_wmarkers (_IO_FILE *) __THROW; > extern unsigned _IO_adjust_wcolumn (unsigned, const wchar_t *, int) __THROW; > +extern _IO_off64_t get_file_offset (_IO_FILE *fp); > > /* Marker-related function. */ > > diff --git a/libio/tst-ftell-active-handler.c b/libio/tst-ftell-active-handler.c > new file mode 100644 > index 0000000..aac2923 > --- /dev/null > +++ b/libio/tst-ftell-active-handler.c > @@ -0,0 +1,366 @@ > +/* Verify that ftell returns the correct value at various points before and > + after the handler on which it is called becomes active. > + Copyright (C) 2014 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + <http://www.gnu.org/licenses/>. */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <errno.h> > +#include <unistd.h> > +#include <fcntl.h> > +#include <locale.h> > +#include <wchar.h> > + > +static int do_test (void); > + > +#define TEST_FUNCTION do_test () > +#include "../test-skeleton.c" > + > +#define get_handles_fdopen(filename, fd, fp, fd_mode, mode) \ > +({ \ > + int ret = 0; \ > + (fd) = open ((filename), (fd_mode), 0); \ > + if ((fd) == -1) \ > + { \ > + printf ("open failed: %m\n"); \ > + ret = 1; \ > + } \ > + else \ > + { \ > + (fp) = fdopen ((fd), (mode)); \ > + if ((fp) == NULL) \ > + { \ > + printf ("fdopen failed: %m\n"); \ > + close (fd); \ > + ret = 1; \ > + } \ > + } \ > + ret; \ > +}) > + > +#define get_handles_fopen(filename, fd, fp, mode) \ > +({ \ > + int ret = 0; \ > + (fp) = fopen ((filename), (mode)); \ > + if ((fp) == NULL) \ > + { \ > + printf ("fopen failed: %m\n"); \ > + ret = 1; \ > + } \ > + else \ > + { \ > + (fd) = fileno (fp); \ > + if ((fd) == -1) \ > + { \ > + printf ("fileno failed: %m\n"); \ > + ret = 1; \ > + } \ > + } \ > + ret; \ > +}) > + > +static const void *data; > +static const char *char_data = "abcdef"; > +static const wchar_t *wide_data = L"abcdef"; > +static size_t data_len; > +/* Maintain the current file length for validation. */ > +static size_t file_len; > + > +typedef int (*fputs_func_t) (const void *data, FILE *fp); > +fputs_func_t fputs_func; > + > +/* Test that the value of ftell is not cached when the stream handle is not > + active. */ > +static int > +do_ftell_test (const char *filename) > +{ > + int ret = 0; > + struct test > + { > + const char *mode; > + int fd_mode; > + size_t old_off; > + size_t new_off; > + } test_modes[] = { > + {"w", O_WRONLY, 0, data_len}, > + {"w+", O_RDWR, 0, data_len}, > + {"r+", O_RDWR, 0, data_len}, > + {"a", O_WRONLY, data_len, 2 * data_len}, > + {"a+", O_RDWR, 2 * data_len, 3 * data_len}, > + }; > + for (int j = 0; j < 2; j++) > + { > + for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) > + { > + FILE *fp; > + int fd; > + printf ("\tftell: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen", > + test_modes[i].mode); > + > + if (j == 0) > + ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, > + test_modes[i].mode); > + else > + ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); > + > + if (ret != 0) > + return 1; > + > + long off = ftell (fp); > + if (off != test_modes[i].old_off) > + { > + printf ("Incorrect old offset. Expected %zu but got %ld, ", > + test_modes[i].old_off, off); > + ret |= 1; > + } > + else > + printf ("old offset = %ld, ", off); > + > + int ret = write (fd, data, data_len); > + off = ftell (fp); > + > + if (off != test_modes[i].new_off) > + { > + printf ("Incorrect new offset. Expected %zu but got %ld\n", > + test_modes[i].old_off, off); > + ret |= 1; > + } > + else > + printf ("new offset = %ld\n", off); > + > + fclose (fp); > + } > + } > + > + return ret; > +} > + > +/* This test opens the file for writing, moves the file offset of the > + underlying file, writes out data and then checks if ftell trips on it. */ > +static int > +do_write_test (const char *filename) > +{ > + FILE *fp = NULL; > + int fd; > + int ret = 0; > + struct test > + { > + const char *mode; > + int fd_mode; > + } test_modes[] = { > + {"w", O_WRONLY}, > + {"w+", O_RDWR}, > + {"r+", O_RDWR} > + }; > + > + for (int j = 0; j < 2; j++) > + { > + for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) > + { > + printf ("\twrite: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen", > + test_modes[i].mode); > + > + if (j == 0) > + ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); > + else > + ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, > + test_modes[i].mode); > + > + if (ret != 0) > + return ret; > + > + /* Move offset to just before the end of the file. */ > + off_t ret = lseek (fd, file_len - 1, SEEK_SET); > + if (ret == -1) > + { > + printf ("lseek failed: %m\n"); > + ret |= 1; > + } > + > + /* Write some data. */ > + size_t written = fputs_func (data, fp); > + > + if (written == EOF) > + { > + printf ("fputs[1] failed to write data\n"); > + ret |= 1; > + } > + > + /* Verify that the offset points to the end of the file. */ > + long offset = ftell (fp); > + file_len = file_len - 1 + data_len; > + > + if (offset != file_len) > + { > + printf ("Incorrect offset. Expected %zu, but got %ld\n", > + file_len, offset); > + > + ret |= 1; > + } > + > + printf ("offset = %ld\n", offset); > + fclose (fp); > + } > + } > + > + return ret; > +} > + > +/* This test opens a file in append mode, writes some data, and then verifies > + that ftell does not trip over it. */ > +static int > +do_append_test (const char *filename) > +{ > + FILE *fp = NULL; > + int ret = 0; > + int fd; > + > + struct test > + { > + const char *mode; > + int fd_mode; > + } test_modes[] = { > + {"a", O_WRONLY}, > + {"a+", O_RDWR} > + }; > + > + for (int j = 0; j < 2; j++) > + { > + for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++) > + { > + printf ("\tappend: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen", > + test_modes[i].mode); > + > + if (j == 0) > + ret = get_handles_fopen (filename, fd, fp, test_modes[i].mode); > + else > + ret = get_handles_fdopen (filename, fd, fp, test_modes[i].fd_mode, > + test_modes[i].mode); > + > + if (ret != 0) > + return ret; > + > + /* Write some data. */ > + size_t written = fputs_func (data, fp); > + > + if (written == EOF) > + { > + printf ("fputs[1] failed to write all data\n"); > + ret |= 1; > + } > + > + /* Verify that the offset points to the end of the file. */ > + long offset = ftell (fp); > + file_len += data_len; > + > + if (offset != file_len) > + { > + printf ("Incorrect offset. Expected %zu, but got %ld\n", > + file_len, offset); > + > + ret |= 1; > + } > + > + printf ("offset = %ld\n", offset); > + fclose (fp); > + } > + } > + > + return ret; > +} > + > +static int > +do_one_test (const char *filename) > +{ > + int ret = 0; > + > + ret |= do_ftell_test (filename); > + ret |= do_write_test (filename); > + ret |= do_append_test (filename); > + > + return ret; > +} > + > +static int > +do_test (void) > +{ > + int ret = 0; > + FILE *fp = NULL; > + char *filename; > + size_t written; > + int fd = create_temp_file ("tst-active-handler-tmp.", &filename); > + > + if (fd == -1) > + { > + printf ("create_temp_file: %m\n"); > + return 1; > + } > + > + fp = fdopen (fd, "w"); > + if (fp == NULL) > + { > + printf ("fdopen[0]: %m\n"); > + close (fd); > + return 1; > + } > + > + data = char_data; > + data_len = strlen (char_data); > + file_len = strlen (char_data); > + written = fputs (data, fp); > + > + if (written == EOF) > + { > + printf ("fputs[1] failed to write data\n"); > + ret = 1; > + } > + > + fclose (fp); > + if (ret) > + return ret; > + > + /* Tests for regular files. */ > + puts ("Regular mode:"); > + fputs_func = (fputs_func_t) fputs; > + data = char_data; > + data_len = strlen (char_data); > + ret |= do_one_test (filename); > + > + /* Truncate the file before repeating the tests in wide mode. */ > + fp = fopen (filename, "w"); > + if (fp == NULL) > + { > + printf ("fopen failed %m\n"); > + return 1; > + } > + fclose (fp); > + > + /* Tests for wide files. */ > + puts ("Wide mode:"); > + if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) > + { > + printf ("Cannot set en_US.UTF-8 locale.\n"); > + return 1; > + } > + fputs_func = (fputs_func_t) fputws; > + data = wide_data; > + data_len = wcslen (wide_data); > + ret |= do_one_test (filename); > + > + return ret; > +} > diff --git a/libio/wfileops.c b/libio/wfileops.c > index 9cebe77..eda7828 100644 > --- a/libio/wfileops.c > +++ b/libio/wfileops.c > @@ -596,29 +596,22 @@ done: > return 0; > } > > -_IO_off64_t > -_IO_wfile_seekoff (fp, offset, dir, mode) > - _IO_FILE *fp; > - _IO_off64_t offset; > - int dir; > - int mode; > +static _IO_off64_t > +do_ftell_wide (_IO_FILE *fp) > { > - _IO_off64_t result; > - _IO_off64_t delta, new_offset; > - long int count; > - /* POSIX.1 8.2.3.7 says that after a call the fflush() the file > - offset of the underlying file must be exact. */ > - int must_be_exact = ((fp->_wide_data->_IO_read_base > - == fp->_wide_data->_IO_read_end) > - && (fp->_wide_data->_IO_write_base > - == fp->_wide_data->_IO_write_ptr)); > + _IO_off64_t result, offset = 0; > > - bool was_writing = ((fp->_wide_data->_IO_write_ptr > - > fp->_wide_data->_IO_write_base) > - || _IO_in_put_mode (fp)); > - > - if (mode == 0) > + /* No point looking for offsets in the buffer if it hasn't even been > + allocated. */ > + if (fp->_wide_data->_IO_buf_base != NULL) > { > + const wchar_t *wide_read_base; > + const wchar_t *wide_read_ptr; > + const wchar_t *wide_read_end; > + bool was_writing = ((fp->_wide_data->_IO_write_ptr > + > fp->_wide_data->_IO_write_base) > + || _IO_in_put_mode (fp)); > + > /* 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 > @@ -633,14 +626,117 @@ _IO_wfile_seekoff (fp, offset, dir, mode) > return -1; > } > > - /* There is no more data in the backup buffer. We can > - switch back. */ > - _IO_switch_to_main_wget_area (fp); > + /* Nothing in the backup store, so note the backed up pointers > + without changing the state. */ > + wide_read_base = fp->_wide_data->_IO_save_base; > + wide_read_ptr = wide_read_base; > + wide_read_end = fp->_wide_data->_IO_save_end; > + } > + else > + { > + wide_read_base = fp->_wide_data->_IO_read_base; > + wide_read_ptr = fp->_wide_data->_IO_read_ptr; > + wide_read_end = fp->_wide_data->_IO_read_end; > } > > - dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */ > + struct _IO_codecvt *cv = fp->_codecvt; > + int clen = (*cv->__codecvt_do_encoding) (cv); > + > + if (!was_writing) > + { > + if (clen > 0) > + { > + offset -= (wide_read_end - wide_read_ptr) * clen; > + offset -= fp->_IO_read_end - fp->_IO_read_ptr; > + } > + else > + { > + int nread; > + > + size_t delta = wide_read_ptr - wide_read_base; > + __mbstate_t state = fp->_wide_data->_IO_last_state; > + nread = (*cv->__codecvt_do_length) (cv, &state, > + fp->_IO_read_base, > + fp->_IO_read_end, delta); > + offset -= fp->_IO_read_end - fp->_IO_read_base - nread; > + } > + } > + else > + { > + if (clen > 0) > + offset += (fp->_wide_data->_IO_write_ptr > + - fp->_wide_data->_IO_write_base) * clen; > + else > + { > + size_t delta = (fp->_wide_data->_IO_write_ptr > + - fp->_wide_data->_IO_write_base); > + > + /* Allocate enough space for the conversion. */ > + size_t outsize = delta * sizeof (wchar_t); > + char *out = malloc (outsize); > + char *outstop = out; > + const wchar_t *in = fp->_wide_data->_IO_write_base; > + > + enum __codecvt_result status; > + > + __mbstate_t state = fp->_wide_data->_IO_last_state; > + status = (*cv->__codecvt_do_out) (cv, &state, > + in, in + delta, &in, > + out, out + outsize, &outstop); > + > + /* We don't check for __codecvt_partial because it can be > + returned on one of two conditions: either the output > + buffer is full or the input sequence is incomplete. We > + take care to allocate enough buffer and our input > + sequences must be complete since they are accepted as > + wchar_t; if not, then that is an error. */ > + if (__glibc_unlikely (status != __codecvt_ok)) > + return WEOF; > + > + offset += outstop - out; > + } > + > + /* _IO_read_end coincides with fp._offset, so the actual file position > + is fp._offset - (_IO_read_end - new_write_ptr). */ > + offset -= fp->_IO_read_end - fp->_IO_write_ptr; > + } > } > > + result = get_file_offset (fp); > + > + if (result == EOF) > + return result; > + > + result += offset; > + > + return result; > +} > + > +_IO_off64_t > +_IO_wfile_seekoff (fp, offset, dir, mode) > + _IO_FILE *fp; > + _IO_off64_t offset; > + int dir; > + int mode; > +{ > + _IO_off64_t result; > + _IO_off64_t delta, new_offset; > + long int count; > + > + if (mode == 0) > + return do_ftell_wide (fp); > + > + /* POSIX.1 8.2.3.7 says that after a call the fflush() the file > + offset of the underlying file must be exact. */ > + int must_be_exact = ((fp->_wide_data->_IO_read_base > + == fp->_wide_data->_IO_read_end) > + && (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)); > + > /* Flush unwritten characters. > (This may do an unneeded write if we seek within the buffer. > But to be able to switch to reading, we would need to set > @@ -648,7 +744,7 @@ _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. */ > - else if (was_writing && _IO_switch_to_wget_mode (fp)) > + if (was_writing && _IO_switch_to_wget_mode (fp)) > return WEOF; > > if (fp->_wide_data->_IO_buf_base == NULL) > @@ -693,7 +789,6 @@ _IO_wfile_seekoff (fp, offset, dir, mode) > { > 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; > @@ -706,80 +801,9 @@ _IO_wfile_seekoff (fp, offset, dir, mode) > offset -= fp->_IO_read_end - fp->_IO_read_base - nread; > } > } > - else > - { > - char *new_write_ptr = fp->_IO_write_ptr; > - > - if (clen > 0) > - offset += (fp->_wide_data->_IO_write_ptr > - - fp->_wide_data->_IO_write_base) / clen; > - else > - { > - enum __codecvt_result status = __codecvt_ok; > - 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 > - { > - /* There is not enough space in the buffer to do the entire > - conversion, so there is no point trying to avoid the > - buffer flush. Just do it and go back to how it was with > - the read mode. */ > - if (status == __codecvt_partial > - || (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 (__glibc_unlikely (status == __codecvt_error)) > - 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) > - { > - if (mode != 0) > - goto dumb; > - else > - { > - result = _IO_SYSSEEK (fp, 0, dir); > - if (result == EOF) > - return result; > - fp->_offset = result; > - } > - } > + goto dumb; > > /* Make offset absolute, assuming current pointer is file_ptr(). */ > offset += fp->_offset; > @@ -802,10 +826,6 @@ _IO_wfile_seekoff (fp, offset, dir, mode) > } > /* At this point, dir==_IO_seek_set. */ > > - /* If we are only interested in the current position we've found it now. */ > - if (mode == 0) > - return offset; > - > /* If destination is within current buffer, optimize: */ > if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL > && !_IO_in_backup (fp)) > -- > 1.8.3.1 >
Attachment:
pgphTysxpP601.pgp
Description: PGP signature
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |