(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
copy-file.c
       1  /* Copying of files.
       2     Copyright (C) 2001-2003, 2006-2007, 2009-2023 Free Software Foundation, Inc.
       3     Written by Bruno Haible <haible@clisp.cons.org>, 2001.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation, either version 3 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  
      19  #include <config.h>
      20  
      21  /* Specification.  */
      22  #include "copy-file.h"
      23  
      24  #include <errno.h>
      25  #include <fcntl.h>
      26  #include <stddef.h>
      27  #include <stdlib.h>
      28  #include <sys/stat.h>
      29  #include <unistd.h>
      30  
      31  #include "error.h"
      32  #include "ignore-value.h"
      33  #include "safe-read.h"
      34  #include "full-write.h"
      35  #include "stat-time.h"
      36  #include "utimens.h"
      37  #include "acl.h"
      38  #include "binary-io.h"
      39  #include "quote.h"
      40  #include "gettext.h"
      41  
      42  #define _(str) gettext (str)
      43  
      44  enum { IO_SIZE = 32 * 1024 };
      45  
      46  int
      47  qcopy_file_preserving (const char *src_filename, const char *dest_filename)
      48  {
      49    int err = 0;
      50    int src_fd;
      51    struct stat statbuf;
      52    int mode;
      53    int dest_fd;
      54  
      55    src_fd = open (src_filename, O_RDONLY | O_BINARY | O_CLOEXEC);
      56    if (src_fd < 0)
      57      return GL_COPY_ERR_OPEN_READ;
      58    if (fstat (src_fd, &statbuf) < 0)
      59      {
      60        err = GL_COPY_ERR_OPEN_READ;
      61        goto error_src;
      62      }
      63  
      64    mode = statbuf.st_mode & 07777;
      65    off_t inbytes = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
      66    bool empty_regular_file = inbytes == 0;
      67  
      68    dest_fd = open (dest_filename,
      69                    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_CLOEXEC,
      70                    0600);
      71    if (dest_fd < 0)
      72      {
      73        err = GL_COPY_ERR_OPEN_BACKUP_WRITE;
      74        goto error_src;
      75      }
      76  
      77    /* Copy the file contents.  FIXME: Do not copy holes.  */
      78    while (0 < inbytes)
      79      {
      80        size_t copy_max = -1;
      81        copy_max -= copy_max % IO_SIZE;
      82        size_t len = inbytes < copy_max ? inbytes : copy_max;
      83        ssize_t copied = copy_file_range (src_fd, NULL, dest_fd, NULL, len, 0);
      84        if (copied <= 0)
      85          break;
      86        inbytes -= copied;
      87      }
      88  
      89    /* Finish up with read/write, in case the file was not a regular
      90       file, or the file shrank or had I/O errors (in which case find
      91       whether it was a read or write error).  Read empty regular files
      92       since they might be in /proc with their true sizes unknown until
      93       they are read.  */
      94    if (inbytes != 0 || empty_regular_file)
      95      {
      96        char smallbuf[1024];
      97        int bufsize = IO_SIZE;
      98        char *buf = malloc (bufsize);
      99        if (!buf)
     100          buf = smallbuf, bufsize = sizeof smallbuf;
     101  
     102        while (true)
     103          {
     104            size_t n_read = safe_read (src_fd, buf, bufsize);
     105            if (n_read == 0)
     106              break;
     107            if (n_read == SAFE_READ_ERROR)
     108              {
     109                err = GL_COPY_ERR_READ;
     110                break;
     111              }
     112            if (full_write (dest_fd, buf, n_read) < n_read)
     113              {
     114                err = GL_COPY_ERR_WRITE;
     115                break;
     116              }
     117          }
     118  
     119        if (buf != smallbuf)
     120          free (buf);
     121        if (err)
     122          goto error_src_dest;
     123      }
     124  
     125  #if !USE_ACL
     126    if (close (dest_fd) < 0)
     127      {
     128        err = GL_COPY_ERR_WRITE;
     129        goto error_src;
     130      }
     131    if (close (src_fd) < 0)
     132      return GL_COPY_ERR_AFTER_READ;
     133  #endif
     134  
     135    /* Preserve the access and modification times.  */
     136    {
     137      struct timespec ts[2];
     138  
     139      ts[0] = get_stat_atime (&statbuf);
     140      ts[1] = get_stat_mtime (&statbuf);
     141      utimens (dest_filename, ts);
     142    }
     143  
     144  #if HAVE_CHOWN
     145    /* Preserve the owner and group.  */
     146    ignore_value (chown (dest_filename, statbuf.st_uid, statbuf.st_gid));
     147  #endif
     148  
     149    /* Preserve the access permissions.  */
     150  #if USE_ACL
     151    switch (qcopy_acl (src_filename, src_fd, dest_filename, dest_fd, mode))
     152      {
     153      case -2:
     154        err = GL_COPY_ERR_GET_ACL;
     155        goto error_src_dest;
     156      case -1:
     157        err = GL_COPY_ERR_SET_ACL;
     158        goto error_src_dest;
     159      }
     160  #else
     161    chmod (dest_filename, mode);
     162  #endif
     163  
     164  #if USE_ACL
     165    if (close (dest_fd) < 0)
     166      {
     167        err = GL_COPY_ERR_WRITE;
     168        goto error_src;
     169      }
     170    if (close (src_fd) < 0)
     171      return GL_COPY_ERR_AFTER_READ;
     172  #endif
     173  
     174    return 0;
     175  
     176   error_src_dest:
     177    close (dest_fd);
     178   error_src:
     179    close (src_fd);
     180    return err;
     181  }
     182  
     183  void
     184  copy_file_preserving (const char *src_filename, const char *dest_filename)
     185  {
     186    switch (qcopy_file_preserving (src_filename, dest_filename))
     187      {
     188      case 0:
     189        return;
     190  
     191      case GL_COPY_ERR_OPEN_READ:
     192        error (EXIT_FAILURE, errno, _("error while opening %s for reading"),
     193               quote (src_filename));
     194  
     195      case GL_COPY_ERR_OPEN_BACKUP_WRITE:
     196        error (EXIT_FAILURE, errno, _("cannot open backup file %s for writing"),
     197               quote (dest_filename));
     198  
     199      case GL_COPY_ERR_READ:
     200        error (EXIT_FAILURE, errno, _("error reading %s"),
     201               quote (src_filename));
     202  
     203      case GL_COPY_ERR_WRITE:
     204        error (EXIT_FAILURE, errno, _("error writing %s"),
     205               quote (dest_filename));
     206  
     207      case GL_COPY_ERR_AFTER_READ:
     208        error (EXIT_FAILURE, errno, _("error after reading %s"),
     209               quote (src_filename));
     210  
     211      case GL_COPY_ERR_GET_ACL:
     212        error (EXIT_FAILURE, errno, "%s", quote (src_filename));
     213  
     214      case GL_COPY_ERR_SET_ACL:
     215        error (EXIT_FAILURE, errno, _("preserving permissions for %s"),
     216               quote (dest_filename));
     217  
     218      default:
     219        abort ();
     220      }
     221  }