]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Use fwriteerror() for reliable signalling of write error during stream output.
authorBruno Haible <bruno@clisp.org>
Thu, 18 Sep 2003 15:57:53 +0000 (15:57 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:11:00 +0000 (12:11 +0200)
17 files changed:
gettext-runtime/lib/ChangeLog
gettext-runtime/lib/Makefile.am
gettext-runtime/lib/Makefile.msvc
gettext-runtime/lib/Makefile.vms
gettext-tools/ChangeLog
gettext-tools/lib/ChangeLog
gettext-tools/lib/Makefile.am
gettext-tools/lib/Makefile.msvc
gettext-tools/lib/Makefile.vms
gettext-tools/lib/fwriteerror.c [new file with mode: 0644]
gettext-tools/lib/fwriteerror.h [new file with mode: 0644]
gettext-tools/src/ChangeLog
gettext-tools/src/write-java.c
gettext-tools/src/write-mo.c
gettext-tools/src/write-po.c
gettext-tools/src/write-tcl.c
gettext-tools/windows/gettextlib.def

index 2432f58ab6bc3c98b728d7d4216f087c2016ebed..ec1f087d27ff5b16a584d685b9c73d163b878184 100644 (file)
@@ -1,3 +1,11 @@
+2003-09-14  Bruno Haible  <bruno@clisp.org>
+
+       * Makefile.am (libgrt_a_SOURCES): Add fwriteerror.h, fwriteerror.c.
+       * Makefile.msvc (OBJECTS): Add fwriteerror.obj.
+       (fwriteerror.obj): New rule.
+       * Makefile.vms (OBJECTS): Add fwriteerror.obj.
+       (fwriteerror.obj): New rule.
+
 2003-09-13  Bruno Haible  <bruno@clisp.org>
 
        * Makefile.am (libgrt_a_SOURCES): Add closeout.h, closeout.c.
index 8078a3567513a23cd948d36e8959b0d222472c7a..4113aa78940fd3a5dfb8f9da8378c0dc901bf84d 100644 (file)
@@ -30,6 +30,7 @@ libgrt_a_SOURCES = \
   ../../gettext-tools/lib/closeout.h ../../gettext-tools/lib/closeout.c \
   ../../gettext-tools/lib/error.h ../../gettext-tools/lib/error.c \
   ../../gettext-tools/lib/exit.h \
+  ../../gettext-tools/lib/fwriteerror.h ../../gettext-tools/lib/fwriteerror.c \
   ../../gettext-tools/lib/getopt.h ../../gettext-tools/lib/getopt.c ../../gettext-tools/lib/getopt1.c \
   ../../gettext-tools/lib/pathmax.h \
   ../../gettext-tools/lib/progname.h ../../gettext-tools/lib/progname.c ../../gettext-tools/lib/progreloc.c \
index 01dcb3b3f1a10724bbfec8874799764e7fda7e6a..930b22eada6fb6d66b16d286d69406edf89d9006 100644 (file)
@@ -52,7 +52,7 @@ RM = -del
 
 SHELL = /bin/sh
 
-OBJECTS = basename.obj closeout.obj error.obj getopt.obj getopt1.obj progname.obj progreloc.obj relocatable.obj xmalloc.obj xstrdup.obj
+OBJECTS = basename.obj closeout.obj error.obj fwriteerror.obj getopt.obj getopt1.obj progname.obj progreloc.obj relocatable.obj xmalloc.obj xstrdup.obj
 
 all : grt.lib
 
@@ -65,6 +65,9 @@ closeout.obj : ..\..\gettext-tools\lib\closeout.c
 error.obj : ..\..\gettext-tools\lib\error.c
        $(CC) $(INCLUDES) $(CFLAGS) -c ..\..\gettext-tools\lib\error.c
 
+fwriteerror.obj : ..\..\gettext-tools\lib\fwriteerror.c
+       $(CC) $(INCLUDES) $(CFLAGS) -c ..\..\gettext-tools\lib\fwriteerror.c
+
 getopt.obj : ..\..\gettext-tools\lib\getopt.c
        $(CC) $(INCLUDES) $(CFLAGS) -c ..\..\gettext-tools\lib\getopt.c
 
index af9d560db621990867b4d0cbc99469d67e0e71bc..06d450a494692f6c345ad4480389088c74b1093a 100644 (file)
@@ -27,7 +27,7 @@ RM = delete
 
 #### End of system configuration section. ####
 
-OBJECTS = basename.obj,closeout.obj,error.obj,getopt.obj,getopt1.obj,progname.obj,progreloc.obj,relocatable.obj,xmalloc.obj,xstrdup.obj
+OBJECTS = basename.obj,closeout.obj,error.obj,fwriteerror.obj,getopt.obj,getopt1.obj,progname.obj,progreloc.obj,relocatable.obj,xmalloc.obj,xstrdup.obj
 
 all : grt.olb
        write sys$output "Nothing else to be done for 'all'."
@@ -41,6 +41,9 @@ closeout.obj : [-.-.gettext-tools.lib]closeout.c
 error.obj : [-.-.gettext-tools.lib]error.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) [-.-.gettext-tools.lib]error.c
 
+fwriteerror.obj : [-.-.gettext-tools.lib]fwriteerror.c
+       $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) [-.-.gettext-tools.lib]fwriteerror.c
+
 getopt.obj : [-.-.gettext-tools.lib]getopt.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) [-.-.gettext-tools.lib]getopt.c
 
index c1aac57bdb90c87f52c6324241a1f2b3fff30957..9ed08e3cc41497cae36f8d2ade09118df5bc3002 100644 (file)
@@ -1,3 +1,7 @@
+2003-09-14  Bruno Haible  <bruno@clisp.org>
+
+       * windows/gettextlib.def: Export fwriteerror.
+
 2003-09-13  Bruno Haible  <bruno@clisp.org>
 
        * windows/gettextlib.def: Export close_stdout.
index 5948692368907cbb8990d3ca5741d77cd2ec904a..3a70d780209506158935c54483f988e31b5cc3f1 100644 (file)
@@ -1,3 +1,14 @@
+2003-09-14  Bruno Haible  <bruno@clisp.org>
+
+       * fwriteerror.h: New file.
+       * fwriteerror.c: New file.
+       * Makefile.am (libgettextlib_la_SOURCES): Add fwriteerror.h,
+       fwriteerror.c.
+       * Makefile.msvc (OBJECTS): Add fwriteerror.obj.
+       (fwriteerror.obj): New rule.
+       * Makefile.vms (OBJECTS): Add fwriteerror.obj.
+       (fwriteerror.obj): New rule.
+
 2003-09-13  Bruno Haible  <bruno@clisp.org>
 
        * closeout.h: New file, from gnulib with modifications.
index 3e437bb00214a5a88e7d1bf71333bf2fa04ab988..b6addbb808e15538eef240d436a8a3c86adcc2c3 100644 (file)
@@ -46,6 +46,7 @@ libgettextlib_la_SOURCES = \
   findprog.h findprog.c \
   fstrcmp.h fstrcmp.c \
   full-write.h full-write.c \
+  fwriteerror.h fwriteerror.c \
   gcd.h gcd.c \
   getopt.h getopt.c getopt1.c \
   hash.h hash.c \
index f90705cf19c0739c174345b0ab8cfd318eeb5e8e..b099e9702729ebfd8503a55fdb85758b3a3bb046 100644 (file)
@@ -93,6 +93,7 @@ OBJECTS = \
   findprog.obj \
   fstrcmp.obj \
   full-write.obj \
+  fwriteerror.obj \
   gcd.obj \
   getopt.obj getopt1.obj \
   hash.obj \
@@ -171,6 +172,9 @@ fstrcmp.obj : fstrcmp.c
 full-write.obj : full-write.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c full-write.c
 
+fwriteerror.obj : fwriteerror.c
+       $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c fwriteerror.c
+
 gcd.obj : gcd.c
        $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c gcd.c
 
index bd70f258a4fd39ec5044498f34f7b6c408875675..e199087bb6e594ebe526f9b48788a596422695e7 100644 (file)
@@ -51,6 +51,7 @@ OBJECTS = \
   findprog.obj, \
   fstrcmp.obj, \
   full-write.obj, \
+  fwriteerror.obj, \
   gcd.obj, \
   getopt.obj, getopt1.obj, \
   hash.obj, \
@@ -132,6 +133,9 @@ fstrcmp.obj : fstrcmp.c
 full-write.obj : full-write.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) full-write.c
 
+fwriteerror.obj : fwriteerror.c
+       $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) fwriteerror.c
+
 gcd.obj : gcd.c
        $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) gcd.c
 
diff --git a/gettext-tools/lib/fwriteerror.c b/gettext-tools/lib/fwriteerror.c
new file mode 100644 (file)
index 0000000..364db86
--- /dev/null
@@ -0,0 +1,122 @@
+/* Detect write error on a stream.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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 <config.h>
+#endif
+
+/* Specification.  */
+#include "fwriteerror.h"
+
+#include <errno.h>
+
+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/gettext-tools/lib/fwriteerror.h b/gettext-tools/lib/fwriteerror.h
new file mode 100644 (file)
index 0000000..82cf5f1
--- /dev/null
@@ -0,0 +1,51 @@
+/* Detect write error on a stream.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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 <stdio.h>
+
+/* 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);
index daa38c8ea6ba4257461a07c17ee52675fbf6340f..8fa8b8472f972c9b9520f71ae16a862ce314f83d 100644 (file)
@@ -1,3 +1,18 @@
+2003-09-14  Bruno Haible  <bruno@clisp.org>
+
+       * write-mo.c: Include fwriterror.h.
+       (msgdomain_write_mo): Use fwriteerror, to get right errno value in
+       error message about write error.
+       * write-po.c: Include fwriterror.h.
+       (msgdomain_list_print): Use fwriteerror, to get right errno value in
+       error message about write error.
+       * write-java.c: Include fwriterror.h.
+       (msgdomain_write_java): Use fwriteerror, to get right errno value in
+       error message about write error.
+       * write-tcl.c: Include fwriterror.h.
+       (msgdomain_write_tcl): Use fwriteerror, to get right errno value in
+       error message about write error.
+
 2003-09-18  Bruno Haible  <bruno@clisp.org>
 
        * xgettext.c (from_current_source_encoding): Use multiline_error,
index da8c76d04af9d1886b2e32c32dc5372d446100af..d8b200b903653422031c379c0071bc26c6c0d8e6 100644 (file)
@@ -74,6 +74,7 @@
 #include "po-charset.h"
 #include "xmalloc.h"
 #include "pathname.h"
+#include "fwriteerror.h"
 #include "tmpdir.h"
 #include "utf8-ucs4.h"
 #include "gettext.h"
@@ -1151,7 +1152,7 @@ msgdomain_write_java (message_list_ty *mlp, const char *canon_encoding,
 
   write_java_code (java_file, class_name, mlp, assume_java2);
 
-  if (fflush (java_file) || ferror (java_file))
+  if (fwriteerror (java_file))
     {
       error (0, errno, _("error while writing \"%s\" file"), java_file_name);
       fclose (java_file);
index 53e69013feb0d6886847dd3913f530ee80f8be54..adba88388239ddb484d15d9332c48b4f1c925ae7 100644 (file)
@@ -44,6 +44,7 @@
 #include "format.h"
 #include "xmalloc.h"
 #include "binary-io.h"
+#include "fwriteerror.h"
 #include "exit.h"
 #include "gettext.h"
 
@@ -701,7 +702,7 @@ msgdomain_write_mo (message_list_ty *mlp,
          write_table (output_file, mlp);
 
          /* Make sure nothing went wrong.  */
-         if (fflush (output_file) || ferror (output_file))
+         if (fwriteerror (output_file))
            error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
                   file_name);
 
index 985179e028ca46f8e54b1813e18dab5c022b92ff..4befb108fa82270b09978f8c05f82c0c87f33efc 100644 (file)
@@ -42,6 +42,7 @@
 #include "write-properties.h"
 #include "xmalloc.h"
 #include "strstr.h"
+#include "fwriteerror.h"
 #include "exit.h"
 #include "error-progname.h"
 #include "error.h"
@@ -1091,7 +1092,7 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
     msgdomain_list_print_po (mdlp, fp, debug);
 
   /* Make sure nothing went wrong.  */
-  if (fflush (fp) || ferror (fp))
+  if (fwriteerror (fp))
     error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
           filename);
 
index b99a10372bf95ab54c0edb78cd7b8f1936a3c77e..4b0146bf1a525e5b8651c293f9e79af926f07ca7 100644 (file)
@@ -36,6 +36,7 @@
 #include "po-charset.h"
 #include "xmalloc.h"
 #include "pathname.h"
+#include "fwriteerror.h"
 #include "exit.h"
 #include "utf8-ucs4.h"
 #include "gettext.h"
@@ -197,7 +198,7 @@ but the Tcl message catalog format doesn't support plural handling\n")));
     write_msg (output_file, mlp, frobbed_locale_name);
 
     /* Make sure nothing went wrong.  */
-    if (fflush (output_file) || ferror (output_file))
+    if (fwriteerror (output_file))
       error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
             file_name);
 
index 96c6653f97a757576ce0e7f552740c5677cffbc7..d28f12e71ee9660e165f541dc1cb9e5459be6b7f 100644 (file)
@@ -45,6 +45,7 @@ find_entry
 find_in_path
 fstrcmp
 full_write
+fwriteerror
 gcd
 getopt_long
 get_version