From: Reuben Thomas Date: Thu, 12 Jan 2012 02:04:49 +0000 (+0100) Subject: copy-file: add error-code-returning variant. X-Git-Tag: v0.1~1253 X-Git-Url: http://erislabs.net/gitweb/?p=gnulib.git;a=commitdiff_plain;h=24a2f3c6ac107e6b35f1ac9f273b691738ef3f9a 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 . (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. --- diff --git a/ChangeLog b/ChangeLog index 4aed32c09..80b570276 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2012-01-11 Reuben Thomas + Bruno Haible + + 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 . + (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. + 2012-01-10 Bruno Haible copy-file: Use 'quote' module consistently. diff --git a/lib/copy-file.c b/lib/copy-file.c index c4d8600a4..c6719d4d9 100644 --- a/lib/copy-file.c +++ b/lib/copy-file.c @@ -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 @@ copy_file_preserving (const char *src_filename, const char *dest_filename) 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 @@ copy_file_preserving (const char *src_filename, const char *dest_filename) 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 @@ copy_file_preserving (const char *src_filename, const char *dest_filename) #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 (); + } } diff --git a/lib/copy-file.h b/lib/copy-file.h index b28ea37f5..5a8f91857 100644 --- a/lib/copy-file.h +++ b/lib/copy-file.h @@ -21,6 +21,26 @@ extern "C" { #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 diff --git a/tests/test-copy-file-1.sh b/tests/test-copy-file-1.sh index b38c8216c..8998ba5e4 100755 --- a/tests/test-copy-file-1.sh +++ b/tests/test-copy-file-1.sh @@ -10,4 +10,11 @@ else 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 diff --git a/tests/test-copy-file-2.sh b/tests/test-copy-file-2.sh index d4d959f8c..1756f7eb4 100755 --- a/tests/test-copy-file-2.sh +++ b/tests/test-copy-file-2.sh @@ -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 diff --git a/tests/test-copy-file.c b/tests/test-copy-file.c index 23c74081c..3068229f2 100644 --- a/tests/test-copy-file.c +++ b/tests/test-copy-file.c @@ -20,6 +20,8 @@ #include "copy-file.h" +#include + #include "progname.h" #include "macros.h" @@ -28,6 +30,7 @@ main (int argc, char *argv[]) { const char *file1; const char *file2; + int null_stderr; set_program_name (argv[0]); @@ -35,8 +38,12 @@ main (int argc, char *argv[]) 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; }