From 96a66d44e6496b976ff6ece7d836f2a37f2c7ed1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 15 Sep 2003 19:15:22 +0000 Subject: [PATCH] New module 'fwriteerror'. --- ChangeLog | 5 ++ lib/ChangeLog | 5 ++ lib/fwriteerror.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ lib/fwriteerror.h | 51 ++++++++++++++++++ modules/fwriteerror | 19 +++++++ 5 files changed, 202 insertions(+) create mode 100644 lib/fwriteerror.c create mode 100644 lib/fwriteerror.h create mode 100644 modules/fwriteerror diff --git a/ChangeLog b/ChangeLog index db1fdeb0fe..3b5350ce6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-09-14 Bruno Haible + + * modules/fwriteerror: New file. + * MODULES.html.sh (func_all_modules): Add fwriteerror. + 2003-09-12 Paul Eggert * modules/argmatch, modules/exitfail, modules/fatal, modules/obstack, diff --git a/lib/ChangeLog b/lib/ChangeLog index 31d07b6003..904cc9c89f 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,8 @@ +2003-09-14 Bruno Haible + + * fwriteerror.h: New file. + * fwriteerror.c: New file. + 2003-09-14 Jim Meyering * getloadavg.c: Correct cpp indentation. diff --git a/lib/fwriteerror.c b/lib/fwriteerror.c new file mode 100644 index 0000000000..364db86093 --- /dev/null +++ b/lib/fwriteerror.c @@ -0,0 +1,122 @@ +/* Detect write error on a stream. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +/* Specification. */ +#include "fwriteerror.h" + +#include + +int +fwriteerror (FILE *fp) +{ + /* Need to + 1. test the error indicator of the stream, + 2. flush the buffers (what fclose() would do), testing for error again. + We can equally well swap these steps; this leads to smaller code. */ + + /* Clear errno, so that on non-POSIX systems the caller doesn't see a + wrong value of errno when we return -1. */ + errno = 0; + + if (fflush (fp)) + return -1; /* errno is set here */ + + if (ferror (fp)) + { + /* The stream had an error earlier, but its errno was lost. If the + error was not temporary, we can get the same errno by writing and + flushing one more byte. We can do so because at this point the + stream's contents is garbage anyway. */ + if (fputc ('\0', fp) == EOF) + return -1; /* errno is set here */ + if (fflush (fp)) + return -1; /* errno is set here */ + /* Give up on errno. */ + errno = 0; + return -1; + } + + return 0; +} + + +#if TEST + +/* Name of a file on which writing fails. On systems without /dev/full, + you can choose a filename on a full filesystem. */ +#define UNWRITABLE_FILE "/dev/full" + +int +main () +{ + static int sizes[] = + { + 511, 512, 513, + 1023, 1024, 1025, + 2047, 2048, 2049, + 4095, 4096, 4097, + 8191, 8192, 8193 + }; + static char dummy[8193]; + unsigned int i, j; + + for (i = 0; i < sizeof (sizes) / sizeof (sizes[0]); i++) + { + size_t size = sizes[i]; + + for (j = 0; j < 2; j++) + { + /* Run a test depending on i and j: + Write size bytes and then calls fflush if j==1. */ + FILE *stream = fopen (UNWRITABLE_FILE, "w"); + + if (stream == NULL) + { + fprintf (stderr, "Test %u:%u: could not open file\n", i, j); + continue; + } + + fwrite (dummy, 347, 1, stream); + fwrite (dummy, size - 347, 1, stream); + if (j) + fflush (stream); + + if (fwriteerror (stream) == -1) + { + if (errno != ENOSPC) + fprintf (stderr, "Test %u:%u: fwriteerror ok, errno = %d\n", + i, j, errno); + } + else + fprintf (stderr, "Test %u:%u: fwriteerror found no error!\n", + i, j); + + if (fclose (stream)) + fprintf (stderr, "Test %u:%u: fclose failed, errno = %d\n", + i, j, errno); + } + } + + return 0; +} + +#endif diff --git a/lib/fwriteerror.h b/lib/fwriteerror.h new file mode 100644 index 0000000000..82cf5f18e3 --- /dev/null +++ b/lib/fwriteerror.h @@ -0,0 +1,51 @@ +/* Detect write error on a stream. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Bruno Haible , 2003. + + 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* There are two approaches for detecting a write error on a stream opened + for writing: + + (a) Test the return value of every fwrite() or fprintf() call, and react + immediately. + (b) Just before fclose(), test the error indicator in the stream and + the return value of the final fflush() or fclose() call. + + The benefit of (a) is that non file related errors (such that ENOMEM during + fprintf) and temporary error conditions can be diagnosed accurately. + + A theoretical benefit of (a) is also that, on POSIX systems, in the case of + an ENOSPC error, errno is set and can be used by error() to provide a more + accurate error message. But in practice, this benefit is not big because + users can easily figure out by themselves why a file cannot be written to, + and furthermore the function fwriteerror() can provide errno as well. + + The big drawback of (a) is extensive error checking code: Every function + which does stream output must return an error indicator. + + This file provides support for (b). */ + +#include + +/* Write out the not yet written buffered contents of the stream FP, and then + test whether some error occurred on the stream FP. FP must be a stream + opened for writing. + Return 0 if no error occurred. In this case it can be assumed that + fclose (fp) will succeed. + Return -1 and set errno if there was an error. The errno value will be 0 + if the cause of the error cannot be determined. + */ +extern int fwriteerror (FILE *fp); diff --git a/modules/fwriteerror b/modules/fwriteerror new file mode 100644 index 0000000000..b360b91278 --- /dev/null +++ b/modules/fwriteerror @@ -0,0 +1,19 @@ +Description: +Detect write error on a stream. + +Files: +lib/fwriteerror.h +lib/fwriteerror.c + +Depends-on: + +configure.ac: + +Makefile.am: +lib_SOURCES += fwriteerror.h fwriteerror.c + +Include: +"fwriteerror.h" + +Maintainer: +Bruno Haible -- 2.30.2