Blame SOURCES/glibc-rh1156331.patch

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
 	    {