bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: copy_file_preserving variant that doesn't exit on error?


From: Bruno Haible
Subject: Re: copy_file_preserving variant that doesn't exit on error?
Date: Thu, 12 Jan 2012 03:13:10 +0100
User-agent: KMail/4.7.4 (Linux/3.1.0-1.2-desktop; KDE/4.7.4; x86_64; ; )

Hi Reuben,

I've added your patch, with a couple of modifications:

- After the refactoring that calls qcopy_acl rather than copy_acl,
  two error messages are possible instead of one. Added one more
  GL_COPY_ERR_* value.
- In copy-file.h declare the right function name.
- In the tests I don't find it a good idea to overwrite the source file
  with the destination file, because that can break subsequent tests that
  assume a certain state in the source file. So I added tests for the
  new function. Not as detailed as what you proposed, but the basic function
  is tested.
- In the tests I also had to drop the test with /dev/full, since - unlike
  /dev/null - this device does not exist everywhere. Ex.: on OpenBSD, NetBSD.


2012-01-11  Reuben Thomas  <address@hidden>
            Bruno Haible  <address@hidden>

        copy-file: add error-code-returning variant.
        * lib/copy-file.h (GL_COPY_ERR_*): New enumeration items.
        (qcopy_file_preserving): New declaration.
        * lib/copy-file.c (qcopy_file_preserving): Renamed from
        copy_file_preserving. Change return type to 'int'. Don't emit an error
        message here.
        (copy_file_preserving): New function.
        * tests/test-copy-file.c: Include <stdlib.h>.
        (main): Test qcopy_file_preserving if the environment variable
        NO_STDERR_OUTPUT is set.
        * tests/test-copy-file-1.sh: Invoke test-copy-file.sh a second time,
        with NO_STDERR_OUTPUT
        * tests/test-copy-file-2.sh: Likewise.

--- lib/copy-file.c.orig        Thu Jan 12 03:00:14 2012
+++ lib/copy-file.c     Thu Jan 12 02:07:16 2012
@@ -54,9 +54,10 @@
 
 enum { IO_SIZE = 32 * 1024 };
 
-void
-copy_file_preserving (const char *src_filename, const char *dest_filename)
+int
+qcopy_file_preserving (const char *src_filename, const char *dest_filename)
 {
+  int err = 0;
   int src_fd;
   struct stat statbuf;
   int mode;
@@ -64,40 +65,58 @@
   char *buf = xmalloc (IO_SIZE);
 
   src_fd = open (src_filename, O_RDONLY | O_BINARY);
-  if (src_fd < 0 || fstat (src_fd, &statbuf) < 0)
-    error (EXIT_FAILURE, errno, _("error while opening %s for reading"),
-           quote (src_filename));
+  if (src_fd < 0)
+    {
+      err = GL_COPY_ERR_OPEN_READ;
+      goto error;
+    }
+  if (fstat (src_fd, &statbuf) < 0)
+    {
+      err = GL_COPY_ERR_OPEN_READ;
+      goto error_src;
+    }
 
   mode = statbuf.st_mode & 07777;
 
   dest_fd = open (dest_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
0600);
   if (dest_fd < 0)
-    error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"),
-           quote (dest_filename));
+    {
+      err = GL_COPY_ERR_OPEN_BACKUP_WRITE;
+      goto error_src;
+    }
 
   /* Copy the file contents.  */
   for (;;)
     {
       size_t n_read = safe_read (src_fd, buf, IO_SIZE);
       if (n_read == SAFE_READ_ERROR)
-        error (EXIT_FAILURE, errno, _("error reading %s"),
-               quote (src_filename));
+        {
+          err = GL_COPY_ERR_READ;
+          goto error_src_dest;
+        }
       if (n_read == 0)
         break;
 
       if (full_write (dest_fd, buf, n_read) < n_read)
-        error (EXIT_FAILURE, errno, _("error writing %s"),
-               quote (est_filename));
+        {
+          err = GL_COPY_ERR_WRITE;
+          goto error_src_dest;
+        }
     }
 
   free (buf);
 
 #if !USE_ACL
   if (close (dest_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error writing %s"), quote (dest_filename));
+    {
+      err = GL_COPY_ERR_WRITE;
+      goto error_src;
+    }
   if (close (src_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error after reading %s"),
-           quote (src_filename));
+    {
+      err = GL_COPY_ERR_AFTER_READ;
+      goto error;
+    }
 #endif
 
   /* Preserve the access and modification times.  */
@@ -129,10 +148,11 @@
   switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode))
     {
     case -2:
-      error (EXIT_FAILURE, errno, "%s", quote (src_filename));
+      err = GL_COPY_ERR_GET_ACL;
+      goto error_src_dest;
     case -1:
-      error (EXIT_FAILURE, errno, _("preserving permissions for %s"),
-             quote (dest_filename));
+      err = GL_COPY_ERR_SET_ACL;
+      goto error_src_dest;
     }
 #else
   chmod (dest_filename, mode);
@@ -140,9 +160,63 @@
 
 #if USE_ACL
   if (close (dest_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error writing %s"), quote (dest_filename));
+    {
+      err = GL_COPY_ERR_WRITE;
+      goto error_src;
+    }
   if (close (src_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error after reading %s"),
-           quote (src_filename));
+    {
+      err = GL_COPY_ERR_AFTER_READ;
+      goto error;
+    }
 #endif
+
+  return 0;
+
+ error_src_dest:
+  close (dest_fd);
+ error_src:
+  close (src_fd);
+ error:
+  return err;
+}
+
+void
+copy_file_preserving (const char *src_filename, const char *dest_filename)
+{
+  switch (qcopy_file_preserving (src_filename, dest_filename))
+    {
+    case 0:
+      return;
+
+    case GL_COPY_ERR_OPEN_READ:
+      error (EXIT_FAILURE, errno, _("error while opening %s for reading"),
+             quote (src_filename));
+
+    case GL_COPY_ERR_OPEN_BACKUP_WRITE:
+      error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"),
+             quote (dest_filename));
+
+    case GL_COPY_ERR_READ:
+      error (EXIT_FAILURE, errno, _("error reading %s"),
+             quote (src_filename));
+
+    case GL_COPY_ERR_WRITE:
+      error (EXIT_FAILURE, errno, _("error writing %s"),
+             quote (dest_filename));
+
+    case GL_COPY_ERR_AFTER_READ:
+      error (EXIT_FAILURE, errno, _("error after reading %s"),
+             quote (src_filename));
+
+    case GL_COPY_ERR_GET_ACL:
+      error (EXIT_FAILURE, errno, "%s", quote (src_filename));
+
+    case GL_COPY_ERR_SET_ACL:
+      error (EXIT_FAILURE, errno, _("preserving permissions for %s"),
+             quote (dest_filename));
+
+    default:
+      abort ();
+    }
 }
--- lib/copy-file.h.orig        Thu Jan 12 03:00:15 2012
+++ lib/copy-file.h     Thu Jan 12 02:04:45 2012
@@ -21,6 +21,26 @@
 #endif
 
 
+/* Error codes returned by qcopy_file_preserving.  */
+enum
+{
+  GL_COPY_ERR_OPEN_READ = -1,
+  GL_COPY_ERR_OPEN_BACKUP_WRITE = -2,
+  GL_COPY_ERR_READ = -3,
+  GL_COPY_ERR_WRITE = -4,
+  GL_COPY_ERR_AFTER_READ = -5,
+  GL_COPY_ERR_GET_ACL = -6,
+  GL_COPY_ERR_SET_ACL = -7
+};
+
+/* Copy a regular file: from src_filename to dest_filename.
+   The destination file is assumed to be a backup file.
+   Modification times, owner, group and access permissions are preserved as
+   far as possible.
+   Return 0 if successful, otherwise set errno and return one of the error
+   codes above.  */
+extern int qcopy_file_preserving (const char *src_filename, const char 
*dest_filename);
+
 /* Copy a regular file: from src_filename to dest_filename.
    The destination file is assumed to be a backup file.
    Modification times, owner, group and access permissions are preserved as
--- tests/test-copy-file-1.sh.orig      Thu Jan 12 03:00:15 2012
+++ tests/test-copy-file-1.sh   Thu Jan 12 02:15:02 2012
@@ -10,4 +10,11 @@
 fi
 export TMPDIR
 
-exec "${srcdir}/test-copy-file.sh"
+"${srcdir}/test-copy-file.sh"
+ret1=$?
+NO_STDERR_OUTPUT=1 "${srcdir}/test-copy-file.sh"
+ret2=$?
+case $ret1 in
+  77 ) exit $ret2 ;;
+  * ) exit $ret1 ;;
+esac
--- tests/test-copy-file-2.sh.orig      Thu Jan 12 03:00:15 2012
+++ tests/test-copy-file-2.sh   Thu Jan 12 02:15:14 2012
@@ -6,4 +6,11 @@
 TMPDIR=`pwd`
 export TMPDIR
 
-exec "${srcdir}/test-copy-file.sh"
+"${srcdir}/test-copy-file.sh"
+ret1=$?
+NO_STDERR_OUTPUT=1 "${srcdir}/test-copy-file.sh"
+ret2=$?
+case $ret1 in
+  77 ) exit $ret2 ;;
+  * ) exit $ret1 ;;
+esac
--- tests/test-copy-file.c.orig Thu Jan 12 03:00:15 2012
+++ tests/test-copy-file.c      Thu Jan 12 02:11:56 2012
@@ -20,6 +20,8 @@
 
 #include "copy-file.h"
 
+#include <stdlib.h>
+
 #include "progname.h"
 #include "macros.h"
 
@@ -28,6 +30,7 @@
 {
   const char *file1;
   const char *file2;
+  int null_stderr;
 
   set_program_name (argv[0]);
 
@@ -35,8 +38,12 @@
 
   file1 = argv[1];
   file2 = argv[2];
+  null_stderr = (getenv ("NO_STDERR_OUTPUT") != NULL);
 
-  copy_file_preserving (file1, file2);
+  if (null_stderr)
+    ASSERT (qcopy_file_preserving (file1, file2) == 0);
+  else
+    copy_file_preserving (file1, file2);
 
   return 0;
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]