]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix file descriptor position after fclose
authorUlrich Drepper <drepper@gmail.com>
Sat, 14 May 2011 01:08:45 +0000 (21:08 -0400)
committerUlrich Drepper <drepper@gmail.com>
Sat, 14 May 2011 01:08:45 +0000 (21:08 -0400)
fclose should leave the file descriptor position after the last read
or written byte.

ChangeLog
NEWS
libio/Makefile
libio/bug-fclose1.c [new file with mode: 0644]
libio/fileops.c

index 824ec0e1cccee81247d50f8f4d2d2ed1de5453aa..3ca2d5856dcb9624a8614dc643530b63c06c7fa4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2011-05-13  Ulrich Drepper  <drepper@gmail.com>
+
+       [BZ #12724]
+       * libio/fileops.c (_IO_new_file_close_it): Always flush when
+       currently writing and seek to current position when not.
+       * libio/Makefile (tests): Add bug-fclose1.
+       * libio/bug-fclose1.c: New file.
+
 2011-05-12  Ulrich Drepper  <drepper@gmail.com>
 
        [BZ #12511]
diff --git a/NEWS b/NEWS
index b8afa6e6992ba47245d42ff78d5112393f31f4d0..2fc193cf23ba0f57a325e2c63bedfa3344f52415 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2011-5-11
+GNU C Library NEWS -- history of user-visible changes.  2011-5-13
 Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -13,7 +13,8 @@ Version 2.14
   12052, 12158, 12178, 12200, 12346, 12393, 12420, 12445, 12449, 12454,
   12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527, 12541, 12545,
   12551, 12583, 12587, 12597, 12611, 12625, 12631, 12650, 12653, 12655,
-  12660, 12681, 12685, 12711, 12713, 12714, 12717, 12723, 12734, 12738
+  12660, 12681, 12685, 12711, 12713, 12714, 12717, 12723, 12724, 12734,
+  12738
 
 * The RPC implementation in libc is obsoleted.  Old programs keep working
   but new programs cannot be linked with the routines in libc anymore.
index 83b9458dc2b2360bb8ef7d14d71fa1da2cb09523..ec309048411e0394c7534d3c05c4d296a1f4a29b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-2004,2006,2007,2008,2009 Free Software Foundation, Inc.
+# Copyright (C) 1995-2004,2006-2009,2011 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
@@ -58,7 +58,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
        tst-memstream1 tst-memstream2 \
        tst-wmemstream1 tst-wmemstream2 \
        bug-memstream1 bug-wmemstream1 \
-       tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos
+       tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos bug-fclose1
 test-srcs = test-freopen
 
 all: # Make this the default target; it will be defined in Rules.
diff --git a/libio/bug-fclose1.c b/libio/bug-fclose1.c
new file mode 100644 (file)
index 0000000..f1e09f5
--- /dev/null
@@ -0,0 +1,132 @@
+// BZ #12724
+
+static void do_prepare (void);
+#define PREPARE(argc, argv) do_prepare ()
+static int do_test (void);
+#define TEST_FUNCTION do_test()
+#include "../test-skeleton.c"
+
+
+static int fd;
+
+
+static void
+do_prepare (void)
+{
+  fd = create_temp_file ("bug-fclose1.", NULL);
+  if (fd == -1)
+    {
+      printf ("cannot create temporary file: %m\n");
+      exit (1);
+    }
+}
+
+
+static int
+do_test (void)
+{
+  static const char pattern[] = "hello world";
+
+  /* Prepare a seekable file.  */
+  if (write (fd, pattern, sizeof pattern) != sizeof pattern)
+    {
+      printf ("cannot write pattern: %m\n");
+      return 1;
+    }
+  if (lseek (fd, 1, SEEK_SET) != 1)
+    {
+      printf ("cannot seek after write: %m\n");
+      return 1;
+    }
+
+  /* Create an output stream visiting the file; when it is closed, all
+     other file descriptors visiting the file must see the new file
+     position.  */
+  int fd2 = dup (fd);
+  if (fd2 < 0)
+    {
+      printf ("cannot duplicate descriptor for writing: %m\n");
+      return 1;
+    }
+  FILE *f = fdopen (fd2, "w");
+  if (f == NULL)
+    {
+      printf ("first fdopen failed: %m\n");
+      return 1;
+    }
+  if (fputc (pattern[1], f) != pattern[1])
+    {
+      printf ("fputc failed: %m\n");
+      return 1;
+    }
+  if (fclose (f) != 0)
+    {
+      printf ("first fclose failed: %m\n");
+      return 1;
+    }
+  errno = 0;
+  if (lseek (fd2, 0, SEEK_CUR) != -1)
+    {
+      printf ("lseek after fclose after write did not fail\n");
+      return 1;
+    }
+  if (errno != EBADF)
+    {
+      printf ("lseek after fclose after write did not fail with EBADF: %m\n");
+      return 1;
+    }
+  off_t o = lseek (fd, 0, SEEK_CUR);
+  if (o != 2)
+    {
+      printf ("\
+lseek on original descriptor after first fclose returned %ld, expected 2\n",
+             (long int) o);
+      return 1;
+    }
+
+  /* Likewise for an input stream.  */
+  fd2 = dup (fd);
+  if (fd2 < 0)
+     {
+      printf ("cannot duplicate descriptor for reading: %m\n");
+      return 1;
+    }
+  f = fdopen (fd2, "r");
+   if (f == NULL)
+    {
+      printf ("second fdopen failed: %m\n");
+      return 1;
+    }
+   char c = fgetc (f);
+   if (c != pattern[2])
+     {
+       printf ("getc returned %c, expected %c\n", c, pattern[2]);
+       return 1;
+     }
+  if (fclose (f) != 0)
+    {
+      printf ("second fclose failed: %m\n");
+      return 1;
+    }
+  errno = 0;
+  if (lseek (fd2, 0, SEEK_CUR) != -1)
+    {
+      printf ("lseek after fclose after read did not fail\n");
+      return 1;
+    }
+  if (errno != EBADF)
+    {
+      printf ("lseek after fclose after read did not fail with EBADF: %m\n");
+      return 1;
+    }
+  o = lseek (fd, 0, SEEK_CUR);
+  if (o != 3)
+    {
+      printf ("\
+lseek on original descriptor after second fclose returned %ld, expected 3\n",
+             (long int) o);
+      return 1;
+    }
+
+  return 0;
+}
index ea730ac95ab70abe791294b284bb5fb8b2b22563..678e32a641e332935863dbb93f5968e902beadc1 100644 (file)
@@ -160,19 +160,25 @@ int
 _IO_new_file_close_it (fp)
      _IO_FILE *fp;
 {
-  int write_status, close_status;
   if (!_IO_file_is_open (fp))
     return EOF;
 
-  if ((fp->_flags & _IO_NO_WRITES) == 0
-      && (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)
+  int write_status;
+  if (_IO_in_put_mode (fp))
     write_status = _IO_do_flush (fp);
-  else
-    write_status = 0;
+  else if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
+          && !_IO_in_backup (fp))
+    {
+      off64_t o = _IO_SEEKOFF (fp, 0, _IO_seek_cur, 0);
+      if (o == WEOF)
+       write_status = EOF;
+      else
+       write_status = _IO_SYSSEEK (fp, o, SEEK_SET) < 0 ? EOF : 0;
+    }
 
   INTUSE(_IO_unsave_markers) (fp);
 
-  close_status = _IO_SYSCLOSE (fp);
+  int close_status = _IO_SYSCLOSE (fp);
 
   /* Free buffer. */
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T