[Top][All Lists]
[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;
}
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/09
- Re: copy_file_preserving variant that doesn't exit on error?, Jim Meyering, 2012/01/10
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/10
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/10
- Re: copy_file_preserving variant that doesn't exit on error?, Bruno Haible, 2012/01/10
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/10
- Re: copy_file_preserving variant that doesn't exit on error?, Bruno Haible, 2012/01/10
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/11
- Re: copy_file_preserving variant that doesn't exit on error?, Bruno Haible, 2012/01/11
- Re: copy_file_preserving variant that doesn't exit on error?,
Bruno Haible <=
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/12
- Re: copy_file_preserving variant that doesn't exit on error?, Jim Meyering, 2012/01/12
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/12
- Re: copy_file_preserving variant that doesn't exit on error?, Bruno Haible, 2012/01/12
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/12
- Re: copy_file_preserving variant that doesn't exit on error?, Bruno Haible, 2012/01/12
- Re: copy_file_preserving variant that doesn't exit on error?, Reuben Thomas, 2012/01/12