X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fcopy-file.c;h=04d518df5a6ea7c98bf30a8a1594a468790ab2a9;hb=1276a2c5f24c0c932426aca9c899fa524d2443f2;hp=8befdfe02dd618fdc44f775f3d514e614afde774;hpb=222b0486b7db1b09293e05512873d633440efcb3;p=gnulib.git diff --git a/lib/copy-file.c b/lib/copy-file.c index 8befdfe02..04d518df5 100644 --- a/lib/copy-file.c +++ b/lib/copy-file.c @@ -1,11 +1,11 @@ /* Copying of files. - Copyright (C) 2001-2003 Free Software Foundation, Inc. + Copyright (C) 2001-2003, 2006-2007, 2009-2014 Free Software Foundation, Inc. Written by Bruno Haible , 2001. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,13 +13,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ -#ifdef HAVE_CONFIG_H -# include -#endif +#include /* Specification. */ #include "copy-file.h" @@ -27,11 +24,9 @@ #include #include #include +#include #include - -#ifdef HAVE_UNISTD_H -# include -#endif +#include #if HAVE_UTIME || HAVE_UTIMES # if HAVE_UTIME_H @@ -42,53 +37,88 @@ #endif #include "error.h" +#include "ignore-value.h" #include "safe-read.h" #include "full-write.h" +#include "acl.h" #include "binary-io.h" -#include "exit.h" +#include "quote.h" #include "gettext.h" +#include "xalloc.h" #define _(str) gettext (str) -void -copy_file_preserving (const char *src_filename, const char *dest_filename) +/* The results of open() in this file are not used with fchdir, + therefore save some unnecessary work in fchdir.c. */ +#undef open +#undef close + +enum { IO_SIZE = 32 * 1024 }; + +int +qcopy_file_preserving (const char *src_filename, const char *dest_filename) { + int err = 0; int src_fd; struct stat statbuf; int mode; int dest_fd; - char buf[4096]; - const size_t buf_size = sizeof (buf); + 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 = 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"), - 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, buf_size); + 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 = GL_COPY_ERR_READ; + goto error_src_dest; + } if (n_read == 0) - break; + break; if (full_write (dest_fd, buf, n_read) < n_read) - error (EXIT_FAILURE, errno, _("error writing \"%s\""), dest_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\""), dest_filename); + { + err = GL_COPY_ERR_WRITE; + goto error_src; + } if (close (src_fd) < 0) - error (EXIT_FAILURE, errno, _("error after reading \"%s\""), src_filename); + { + err = GL_COPY_ERR_AFTER_READ; + goto error; + } +#endif /* Preserve the access and modification times. */ #if HAVE_UTIME @@ -111,9 +141,83 @@ copy_file_preserving (const char *src_filename, const char *dest_filename) #if HAVE_CHOWN /* Preserve the owner and group. */ - chown (dest_filename, statbuf.st_uid, statbuf.st_gid); + ignore_value (chown (dest_filename, statbuf.st_uid, statbuf.st_gid)); #endif /* Preserve the access permissions. */ +#if USE_ACL + switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode)) + { + case -2: + err = GL_COPY_ERR_GET_ACL; + goto error_src_dest; + case -1: + err = GL_COPY_ERR_SET_ACL; + goto error_src_dest; + } +#else chmod (dest_filename, mode); +#endif + +#if USE_ACL + if (close (dest_fd) < 0) + { + err = GL_COPY_ERR_WRITE; + goto error_src; + } + if (close (src_fd) < 0) + { + 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 (); + } }