# HG changeset patch # User Eric Blake # Date 1304365103 21600 # Node ID fa93679417c10a100b238fcd3c8033385f62aae0 # Parent ead32d10a3f020e60844f53079759e62f3e622f0 fclose: add some tests POSIX requires that fclose() on seekable input streams rewind back to the next byte not actually given to the application. Glibc fails this test. See: http://sourceware.org/bugzilla/show_bug.cgi?id=3746 http://sourceware.org/bugzilla/show_bug.cgi?id=12724 Likewise for FreeBSD. Cygwin 1.7.9 and Solaris 10 pass, however. * modules/fclose-tests: New test module. * tests/test-fclose.c: New file. Signed-off-by: Eric Blake diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2011-05-02 Eric Blake + fclose: add some tests + * modules/fclose-tests: New test module. + * tests/test-fclose.c: New file. + * doc/posix-functions/fclose.texi (fclose): Document the bug. + fclose: reduced dependencies * modules/fclose (Depends-on): Switch from fflush/fseeko to simpler lseek. diff --git a/doc/posix-functions/fclose.texi b/doc/posix-functions/fclose.texi --- a/doc/posix-functions/fclose.texi +++ b/doc/posix-functions/fclose.texi @@ -17,6 +17,10 @@ Portability problems not fixed by Gnulib: @itemize @item +On some platforms, this function fails to set the file position of a +seekable input stream to the byte after the last one actually read: +glibc 2.13, FreeBSD. +@item On Windows platforms (excluding Cygwin), this function does not set @code{errno} upon failure. @end itemize diff --git a/modules/fclose-tests b/modules/fclose-tests new file mode 100644 --- /dev/null +++ b/modules/fclose-tests @@ -0,0 +1,10 @@ +Files: +tests/test-fclose.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-fclose +check_PROGRAMS += test-fclose diff --git a/tests/test-fclose.c b/tests/test-fclose.c new file mode 100644 --- /dev/null +++ b/tests/test-fclose.c @@ -0,0 +1,90 @@ +/* Test of fclose module. + Copyright (C) 2011 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Eric Blake. */ + +#include + +#include + +#include "signature.h" +SIGNATURE_CHECK (fclose, int, (FILE *)); + +#include +#include +#include +#include +#include + +#include "macros.h" + +#define BASE "test-fclose.t" + +int +main (int argc, char **argv) +{ + const char buf[] = "hello world"; + int fd; + int fd2; + FILE *f; + + /* Prepare a seekable file. */ + fd = open (BASE, O_RDWR | O_CREAT | O_TRUNC, 0600); + ASSERT (0 <= fd); + ASSERT (write (fd, buf, sizeof buf) == sizeof buf); + ASSERT (lseek (fd, 1, SEEK_SET) == 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. */ + fd2 = dup (fd); + ASSERT (0 <= fd2); + f = fdopen (fd2, "w"); + ASSERT (f); + ASSERT (fputc (buf[1], f) == buf[1]); + ASSERT (fclose (f) == 0); + errno = 0; + ASSERT (lseek (fd2, 0, SEEK_CUR) == -1); + ASSERT (errno == EBADF); + ASSERT (lseek (fd, 0, SEEK_CUR) == 2); + + /* Likewise for an input stream. */ + fd2 = dup (fd); + ASSERT (0 <= fd2); + f = fdopen (fd2, "r"); + ASSERT (f); + ASSERT (fgetc (f) == buf[2]); + ASSERT (fclose (f) == 0); + errno = 0; + ASSERT (lseek (fd2, 0, SEEK_CUR) == -1); + ASSERT (errno == EBADF); + ASSERT (lseek (fd, 0, SEEK_CUR) == 3); + + /* Test that fclose() sets errno if someone else closes the stream + fd behind the back of stdio. */ + f = fdopen (fd, "w+"); + ASSERT (f); + ASSERT (close (fd) == 0); + errno = 0; + ASSERT (fclose (f) == EOF); + ASSERT (errno == EBADF); + + /* Clean up. */ + ASSERT (remove (BASE) == 0); + + return 0; +}