summaryrefslogtreecommitdiff
path: root/libc/libio
diff options
context:
space:
mode:
authorjoseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2011-05-15 12:22:50 +0000
committerjoseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2011-05-15 12:22:50 +0000
commitbc5b8c65ef17547cbab9141d66798bbb3cae9c2a (patch)
treec41d5e47bf1ebffbe2fc7461f0131e7a8b16dc49 /libc/libio
parentc0ce886c9f6b0580924e4f21180602f5e72d6570 (diff)
downloadeglibc2-bc5b8c65ef17547cbab9141d66798bbb3cae9c2a.tar.gz
Merge changes between r13800 and r13831 from /fsf/trunk.
git-svn-id: svn://svn.eglibc.org/trunk@13832 7b3dc134-2b1b-0410-93df-9e9f96275f8d
Diffstat (limited to 'libc/libio')
-rw-r--r--libc/libio/Makefile4
-rw-r--r--libc/libio/bug-fclose1.c132
-rw-r--r--libc/libio/fileops.c16
-rw-r--r--libc/libio/tst_putwc.c11
4 files changed, 153 insertions, 10 deletions
diff --git a/libc/libio/Makefile b/libc/libio/Makefile
index 6df1f4ba0..dd083c640 100644
--- a/libc/libio/Makefile
+++ b/libc/libio/Makefile
@@ -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
@@ -67,7 +67,7 @@ tests = test-fmemopen tst-ext tst-ext2 \
tst-mmap2-eofsync tst-mmap-offend bug-fopena+ \
bug-ungetc2 bug-ungetc3 bug-ungetc4 \
tst-memstream1 tst-memstream2 \
- bug-memstream1 tst-popen1
+ bug-memstream1 tst-popen1 bug-fclose1
tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+= tst-swscanf tst-fgetws tst-fopenloc tst-setvbuf1 \
tst-ungetwc1 tst-ungetwc2 bug-ftell bug-ungetwc2 \
diff --git a/libc/libio/bug-fclose1.c b/libc/libio/bug-fclose1.c
new file mode 100644
index 000000000..f1e09f5d4
--- /dev/null
+++ b/libc/libio/bug-fclose1.c
@@ -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;
+}
diff --git a/libc/libio/fileops.c b/libc/libio/fileops.c
index 9b03a9c55..1f7356540 100644
--- a/libc/libio/fileops.c
+++ b/libc/libio/fileops.c
@@ -161,19 +161,27 @@ 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 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;
+ }
else
write_status = 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
diff --git a/libc/libio/tst_putwc.c b/libc/libio/tst_putwc.c
index 1fd21e26c..c6e7a9dbd 100644
--- a/libc/libio/tst_putwc.c
+++ b/libc/libio/tst_putwc.c
@@ -1,5 +1,5 @@
/* Simple test of putwc in the C locale.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
@@ -74,13 +74,16 @@ do_test (void)
/* Now close the file, open it again, and read again. */
if (fclose (fp) != 0)
{
- printf ("failure during fclose(): %m");
+ printf ("failure during fclose: %m\n");
res = 1;
}
fp = fopen (outname, "r");
if (fp == NULL)
- error (EXIT_FAILURE, errno, "cannot reopen file");
+ {
+ printf ("cannot reopen file: %m\n");
+ return 1;
+ }
/* We can remove the file now. */
remove (outname);
@@ -104,7 +107,7 @@ do_test (void)
if (fclose (fp) != 0)
{
- puts ("failure during fclose()");
+ printf ("failure during fclose: %m\n");
res = 1;
}