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: Reuben Thomas
Subject: Re: copy_file_preserving variant that doesn't exit on error?
Date: Tue, 2 Aug 2011 18:31:34 +0100

Here's a revised patch to provide error returning copy-file as well as
error-raising copy-file.

Of particular interest:

1. What would you like to call the new function?

2. I haven't yet added a test; from looking at the tests for copy-file
it seems it should suffice to add a call to remove followed by an
asserted call to copy_file_preserving_error (or whatever it's called)
after the call to copy_file_preserving, i.e. just repeat the copy with
the other version of the function.

diff --git a/lib/copy-file.c b/lib/copy-file.c
index f9cd9c0..4ae8427 100644
--- a/lib/copy-file.c
+++ b/lib/copy-file.c
@@ -53,47 +53,79 @@

 enum { IO_SIZE = 32 * 1024 };

-void
-copy_file_preserving (const char *src_filename, const char *dest_filename)
+enum {
+  ERR_OPEN_READ = 1,
+  ERR_OPEN_BACKUP_WRITE,
+  ERR_READ,
+  ERR_WRITE,
+  ERR_AFTER_READ,
+  ERR_ACL
+};
+
+
+int
+_copy_file_preserving (const char *src_filename, const char *dest_filename)
 {
   int src_fd;
   struct stat statbuf;
   int mode;
   int dest_fd;
+  int err = 0;
   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"),
-           src_filename);
+  if (src_fd < 0)
+    {
+      err = ERR_OPEN_READ;
+      goto error;
+    }
+  if (fstat (src_fd, &statbuf) < 0)
+    {
+      err = 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"),
-           dest_filename);
+    {
+      err = 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\""), src_filename);
+        {
+          err = 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\""), dest_filename);
+        {
+          err = ERR_WRITE;
+          goto error_src_dest;
+        }
     }

   free (buf);

 #if !USE_ACL
   if (close (dest_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error writing \"%s\""), dest_filename);
+    {
+      err = ERR_WRITE;
+      goto error_src;
+    }
   if (close (src_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename);
+    {
+      err = ERR_AFTER_READ;
+      goto error;
+    }
 #endif

   /* Preserve the access and modification times.  */
@@ -123,15 +155,73 @@ copy_file_preserving (const char *src_filename,
const char *dest_filename)
   /* Preserve the access permissions.  */
 #if USE_ACL
   if (copy_acl (src_filename, src_fd, dest_filename, dest_fd, mode))
-    exit (EXIT_FAILURE);
+    {
+      err = ERR_ACL;
+      goto error_src_dest;
+    }
 #else
   chmod (dest_filename, mode);
 #endif

 #if USE_ACL
   if (close (dest_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error writing \"%s\""), dest_filename);
+    {
+      err = ERR_WRITE;
+      goto error_src;
+    }
   if (close (src_fd) < 0)
-    error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename);
+    {
+      err = 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 (_copy_file_preserving (src_filename, dest_filename))
+    {
+    case 0:
+      return;
+
+    case ERR_OPEN_READ:
+      error (EXIT_FAILURE, errno, _("error while opening \"%s\" for reading"),
+             src_filename);
+
+    case ERR_OPEN_BACKUP_WRITE:
+      error (EXIT_FAILURE, errno, _("cannot open backup file \"%s\"
for writing"),
+             dest_filename);
+
+    case ERR_READ:
+      error (EXIT_FAILURE, errno, _("error reading \"%s\""), src_filename);
+
+    case ERR_WRITE:
+      error (EXIT_FAILURE, errno, _("error writing \"%s\""), dest_filename);
+
+    case ERR_AFTER_READ:
+      error (EXIT_FAILURE, errno, _("error after reading \"%s\""),
src_filename);
+
+    case ERR_ACL:
+      exit (EXIT_FAILURE);
+
+    default:
+      exit (EXIT_FAILURE);
+    }
+}
+
+
+int
+copy_file_preserving_error (const char *src_filename, const char
*dest_filename)
+{
+  return _copy_file_preserving (src_filename, dest_filename) < 0 ? - 1 : 0;
 }
diff --git a/lib/copy-file.h b/lib/copy-file.h
index cb8b1f7..0f0931c 100644
--- a/lib/copy-file.h
+++ b/lib/copy-file.h
@@ -28,6 +28,9 @@ extern "C" {
    Exit upon failure.  */
 extern void copy_file_preserving (const char *src_filename, const
char *dest_filename);

+/* Error-returning version of copy_file_preserving. */
+extern int copy_file_preserving_error (const char *src_filename,
const char *dest_filename);
+

 #ifdef __cplusplus
 }



reply via email to

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