|
|
147e83 |
commit be349d7042de84c3c5157a5c1fbcad580aed33e1
|
|
|
147e83 |
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
|
|
|
147e83 |
Date: Thu Dec 4 08:08:37 2014 +0530
|
|
|
147e83 |
|
|
|
147e83 |
ftell: seek to end only when there are unflushed bytes (BZ #17647)
|
|
|
147e83 |
|
|
|
147e83 |
Currently we seek to end of file if there are unflushed writes or the
|
|
|
147e83 |
stream is in write mode, to get the current offset for writing in
|
|
|
147e83 |
append mode, which is the end of file. The latter case (i.e. stream
|
|
|
147e83 |
is in write mode, but no unflushed writes) is unnecessary since it
|
|
|
147e83 |
will only happen when the stream has just been flushed, in which case
|
|
|
147e83 |
the recorded offset ought to be reliable.
|
|
|
147e83 |
|
|
|
147e83 |
Removing that case lets ftell give the correct offset when it follows
|
|
|
147e83 |
an ftruncate. The latter truncates the file, but does not change the
|
|
|
147e83 |
file position, due to which it is permissible to call ftell without an
|
|
|
147e83 |
intervening fseek call.
|
|
|
147e83 |
|
|
|
147e83 |
Tested on x86_64 to verify that the added test case fails without the
|
|
|
147e83 |
patch and succeeds with it, and that there are no additional
|
|
|
147e83 |
regressions due to it.
|
|
|
147e83 |
|
|
|
147e83 |
[BZ #17647]
|
|
|
147e83 |
* libio/fileops.c (do_ftell): Seek only when there are
|
|
|
147e83 |
unflushed writes.
|
|
|
147e83 |
* libio/wfileops.c (do_ftell_wide): Likewise.
|
|
|
147e83 |
* libio/tst-ftell-active-handler.c (do_ftruncate_test): New
|
|
|
147e83 |
test case.
|
|
|
147e83 |
(do_one_test): Call it.
|
|
|
147e83 |
|
|
|
147e83 |
diff --git glibc-2.17-c758a686/libio/fileops.c glibc-2.17-c758a686/libio/fileops.c
|
|
|
147e83 |
index e0d7b76..1fc5719 100644
|
|
|
147e83 |
--- glibc-2.17-c758a686/libio/fileops.c
|
|
|
147e83 |
+++ glibc-2.17-c758a686/libio/fileops.c
|
|
|
147e83 |
@@ -943,15 +943,14 @@ do_ftell (_IO_FILE *fp)
|
|
|
147e83 |
yet. */
|
|
|
147e83 |
if (fp->_IO_buf_base != NULL)
|
|
|
147e83 |
{
|
|
|
147e83 |
- bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
|
|
|
147e83 |
- || _IO_in_put_mode (fp));
|
|
|
147e83 |
+ bool unflushed_writes = (fp->_IO_write_ptr > fp->_IO_write_base);
|
|
|
147e83 |
|
|
|
147e83 |
bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
|
|
|
147e83 |
|
|
|
147e83 |
/* When we have unflushed writes in append mode, seek to the end of the
|
|
|
147e83 |
file and record that offset. This is the only time we change the file
|
|
|
147e83 |
stream state and it is safe since the file handle is active. */
|
|
|
147e83 |
- if (was_writing && append_mode)
|
|
|
147e83 |
+ if (unflushed_writes && append_mode)
|
|
|
147e83 |
{
|
|
|
147e83 |
result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
|
|
|
147e83 |
if (result == _IO_pos_BAD)
|
|
|
147e83 |
@@ -961,7 +960,7 @@ do_ftell (_IO_FILE *fp)
|
|
|
147e83 |
}
|
|
|
147e83 |
|
|
|
147e83 |
/* Adjust for unflushed data. */
|
|
|
147e83 |
- if (!was_writing)
|
|
|
147e83 |
+ if (!unflushed_writes)
|
|
|
147e83 |
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
|
|
|
147e83 |
/* We don't trust _IO_read_end to represent the current file offset when
|
|
|
147e83 |
writing in append mode because the value would have to be shifted to
|
|
|
147e83 |
diff --git glibc-2.17-c758a686/libio/tst-ftell-active-handler.c glibc-2.17-c758a686/libio/tst-ftell-active-handler.c
|
|
|
147e83 |
index e9dc7b3..9f23c55 100644
|
|
|
147e83 |
--- glibc-2.17-c758a686/libio/tst-ftell-active-handler.c
|
|
|
147e83 |
+++ glibc-2.17-c758a686/libio/tst-ftell-active-handler.c
|
|
|
147e83 |
@@ -88,6 +88,95 @@ static size_t file_len;
|
|
|
147e83 |
typedef int (*fputs_func_t) (const void *data, FILE *fp);
|
|
|
147e83 |
fputs_func_t fputs_func;
|
|
|
147e83 |
|
|
|
147e83 |
+/* This test verifies that the offset reported by ftell is correct after the
|
|
|
147e83 |
+ file is truncated using ftruncate. ftruncate does not change the file
|
|
|
147e83 |
+ offset on truncation and hence, SEEK_CUR should continue to point to the
|
|
|
147e83 |
+ old offset and not be changed to the new offset. */
|
|
|
147e83 |
+static int
|
|
|
147e83 |
+do_ftruncate_test (const char *filename)
|
|
|
147e83 |
+{
|
|
|
147e83 |
+ FILE *fp = NULL;
|
|
|
147e83 |
+ int fd;
|
|
|
147e83 |
+ int ret = 0;
|
|
|
147e83 |
+ struct test
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ const char *mode;
|
|
|
147e83 |
+ int fd_mode;
|
|
|
147e83 |
+ } test_modes[] = {
|
|
|
147e83 |
+ {"r+", O_RDWR},
|
|
|
147e83 |
+ {"w", O_WRONLY},
|
|
|
147e83 |
+ {"w+", O_RDWR},
|
|
|
147e83 |
+ {"a", O_WRONLY},
|
|
|
147e83 |
+ {"a+", O_RDWR}
|
|
|
147e83 |
+ };
|
|
|
147e83 |
+
|
|
|
147e83 |
+ for (int j = 0; j < 2; j++)
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ int fileret;
|
|
|
147e83 |
+ printf ("\tftruncate: %s (file, \"%s\"): ",
|
|
|
147e83 |
+ j == 0 ? "fopen" : "fdopen",
|
|
|
147e83 |
+ test_modes[i].mode);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ if (j == 0)
|
|
|
147e83 |
+ fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
|
|
|
147e83 |
+ else
|
|
|
147e83 |
+ fileret = get_handles_fdopen (filename, fd, fp,
|
|
|
147e83 |
+ test_modes[i].fd_mode,
|
|
|
147e83 |
+ test_modes[i].mode);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ if (fileret != 0)
|
|
|
147e83 |
+ return fileret;
|
|
|
147e83 |
+
|
|
|
147e83 |
+ /* Write some data. */
|
|
|
147e83 |
+ size_t written = fputs_func (data, fp);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ if (written == EOF)
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ printf ("fputs[1] failed to write data\n");
|
|
|
147e83 |
+ ret |= 1;
|
|
|
147e83 |
+ }
|
|
|
147e83 |
+
|
|
|
147e83 |
+ /* Record the offset. */
|
|
|
147e83 |
+ long offset = ftell (fp);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ /* Flush data to allow switching active handles. */
|
|
|
147e83 |
+ if (fflush (fp))
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ printf ("Flush failed: %m\n");
|
|
|
147e83 |
+ ret |= 1;
|
|
|
147e83 |
+ }
|
|
|
147e83 |
+
|
|
|
147e83 |
+ /* Now truncate the file. */
|
|
|
147e83 |
+ if (ftruncate (fd, 0) != 0)
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ printf ("Failed to truncate file: %m\n");
|
|
|
147e83 |
+ ret |= 1;
|
|
|
147e83 |
+ }
|
|
|
147e83 |
+
|
|
|
147e83 |
+ /* ftruncate does not change the offset, so there is no need to call
|
|
|
147e83 |
+ anything to be able to switch active handles. */
|
|
|
147e83 |
+ long new_offset = ftell (fp);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ /* The offset should remain unchanged since ftruncate does not update
|
|
|
147e83 |
+ it. */
|
|
|
147e83 |
+ if (offset != new_offset)
|
|
|
147e83 |
+ {
|
|
|
147e83 |
+ printf ("Incorrect offset. Expected %zu, but got %ld\n",
|
|
|
147e83 |
+ offset, new_offset);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ ret |= 1;
|
|
|
147e83 |
+ }
|
|
|
147e83 |
+ else
|
|
|
147e83 |
+ printf ("offset = %ld\n", offset);
|
|
|
147e83 |
+
|
|
|
147e83 |
+ fclose (fp);
|
|
|
147e83 |
+ }
|
|
|
147e83 |
+ }
|
|
|
147e83 |
+
|
|
|
147e83 |
+ return ret;
|
|
|
147e83 |
+}
|
|
|
147e83 |
/* Test that ftell output after a rewind is correct. */
|
|
|
147e83 |
static int
|
|
|
147e83 |
do_rewind_test (const char *filename)
|
|
|
147e83 |
@@ -481,6 +570,7 @@ do_one_test (const char *filename)
|
|
|
147e83 |
ret |= do_write_test (filename);
|
|
|
147e83 |
ret |= do_append_test (filename);
|
|
|
147e83 |
ret |= do_rewind_test (filename);
|
|
|
147e83 |
+ ret |= do_ftruncate_test (filename);
|
|
|
147e83 |
|
|
|
147e83 |
return ret;
|
|
|
147e83 |
}
|
|
|
147e83 |
diff --git glibc-2.17-c758a686/libio/wfileops.c glibc-2.17-c758a686/libio/wfileops.c
|
|
|
147e83 |
index 6a088b1..71281c1 100644
|
|
|
147e83 |
--- glibc-2.17-c758a686/libio/wfileops.c
|
|
|
147e83 |
+++ glibc-2.17-c758a686/libio/wfileops.c
|
|
|
147e83 |
@@ -626,16 +626,15 @@ do_ftell_wide (_IO_FILE *fp)
|
|
|
147e83 |
const wchar_t *wide_read_base;
|
|
|
147e83 |
const wchar_t *wide_read_ptr;
|
|
|
147e83 |
const wchar_t *wide_read_end;
|
|
|
147e83 |
- bool was_writing = ((fp->_wide_data->_IO_write_ptr
|
|
|
147e83 |
- > fp->_wide_data->_IO_write_base)
|
|
|
147e83 |
- || _IO_in_put_mode (fp));
|
|
|
147e83 |
+ bool unflushed_writes = (fp->_wide_data->_IO_write_ptr
|
|
|
147e83 |
+ > fp->_wide_data->_IO_write_base);
|
|
|
147e83 |
|
|
|
147e83 |
bool append_mode = (fp->_flags & _IO_IS_APPENDING) == _IO_IS_APPENDING;
|
|
|
147e83 |
|
|
|
147e83 |
/* When we have unflushed writes in append mode, seek to the end of the
|
|
|
147e83 |
file and record that offset. This is the only time we change the file
|
|
|
147e83 |
stream state and it is safe since the file handle is active. */
|
|
|
147e83 |
- if (was_writing && append_mode)
|
|
|
147e83 |
+ if (unflushed_writes && append_mode)
|
|
|
147e83 |
{
|
|
|
147e83 |
result = _IO_SYSSEEK (fp, 0, _IO_seek_end);
|
|
|
147e83 |
if (result == _IO_pos_BAD)
|
|
|
147e83 |
@@ -674,7 +673,7 @@ do_ftell_wide (_IO_FILE *fp)
|
|
|
147e83 |
struct _IO_codecvt *cv = fp->_codecvt;
|
|
|
147e83 |
int clen = (*cv->__codecvt_do_encoding) (cv);
|
|
|
147e83 |
|
|
|
147e83 |
- if (!was_writing)
|
|
|
147e83 |
+ if (!unflushed_writes)
|
|
|
147e83 |
{
|
|
|
147e83 |
if (clen > 0)
|
|
|
147e83 |
{
|