Mercurial > hg > octave-lojdl > gnulib-hg
changeset 16273:d50152d6b5d2
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.
author | Reuben Thomas <rrt@sc3d.org> |
---|---|
date | Thu, 12 Jan 2012 03:04:49 +0100 |
parents | 8e1f4b31c39f |
children | 2c5c6ce1dba4 |
files | ChangeLog lib/copy-file.c lib/copy-file.h tests/test-copy-file-1.sh tests/test-copy-file-2.sh tests/test-copy-file.c |
diffstat | 6 files changed, 155 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2012-01-11 Reuben Thomas <rrt@sc3d.org> + Bruno Haible <bruno@clisp.org> + + 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. + 2012-01-10 Bruno Haible <bruno@clisp.org> copy-file: Use 'quote' module consistently.
--- 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 @@ 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 (); + } +}
--- a/lib/copy-file.h +++ b/lib/copy-file.h @@ -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
--- a/tests/test-copy-file-1.sh +++ b/tests/test-copy-file-1.sh @@ -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
--- 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
--- a/tests/test-copy-file.c +++ b/tests/test-copy-file.c @@ -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; }