LCOV - code coverage report
Current view: top level - src - cp.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 281 403 69.7 %
Date: 2018-01-30 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /* cp.c  -- file copying (main routines)
       2             :    Copyright (C) 89, 90, 91, 1995-2008 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             : 
      17             :    Written by Torbjorn Granlund, David MacKenzie, and Jim Meyering. */
      18             : 
      19             : #include <config.h>
      20             : #include <stdio.h>
      21             : #include <sys/types.h>
      22             : #include <getopt.h>
      23             : #include <selinux/selinux.h>
      24             : 
      25             : #include "system.h"
      26             : #include "argmatch.h"
      27             : #include "backupfile.h"
      28             : #include "copy.h"
      29             : #include "cp-hash.h"
      30             : #include "error.h"
      31             : #include "filenamecat.h"
      32             : #include "lchmod.h"
      33             : #include "quote.h"
      34             : #include "stat-time.h"
      35             : #include "utimens.h"
      36             : #include "acl.h"
      37             : 
      38             : #if ! HAVE_LCHOWN
      39             : # define lchown(name, uid, gid) chown (name, uid, gid)
      40             : #endif
      41             : 
      42             : #define ASSIGN_BASENAME_STRDUPA(Dest, File_name)        \
      43             :   do                                                    \
      44             :     {                                                   \
      45             :       char *tmp_abns_;                                  \
      46             :       ASSIGN_STRDUPA (tmp_abns_, (File_name));          \
      47             :       Dest = last_component (tmp_abns_);                \
      48             :       strip_trailing_slashes (Dest);                    \
      49             :     }                                                   \
      50             :   while (0)
      51             : 
      52             : /* The official name of this program (e.g., no `g' prefix).  */
      53             : #define PROGRAM_NAME "cp"
      54             : 
      55             : #define AUTHORS "Torbjorn Granlund", "David MacKenzie", "Jim Meyering"
      56             : 
      57             : /* Used by do_copy, make_dir_parents_private, and re_protect
      58             :    to keep a list of leading directories whose protections
      59             :    need to be fixed after copying. */
      60             : struct dir_attr
      61             : {
      62             :   struct stat st;
      63             :   bool restore_mode;
      64             :   size_t slash_offset;
      65             :   struct dir_attr *next;
      66             : };
      67             : 
      68             : /* For long options that have no equivalent short option, use a
      69             :    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
      70             : enum
      71             : {
      72             :   COPY_CONTENTS_OPTION = CHAR_MAX + 1,
      73             :   NO_PRESERVE_ATTRIBUTES_OPTION,
      74             :   PARENTS_OPTION,
      75             :   PRESERVE_ATTRIBUTES_OPTION,
      76             :   REPLY_OPTION,
      77             :   SPARSE_OPTION,
      78             :   STRIP_TRAILING_SLASHES_OPTION,
      79             :   UNLINK_DEST_BEFORE_OPENING
      80             : };
      81             : 
      82             : /* Initial number of entries in each hash table entry's table of inodes.  */
      83             : #define INITIAL_HASH_MODULE 100
      84             : 
      85             : /* Initial number of entries in the inode hash table.  */
      86             : #define INITIAL_ENTRY_TAB_SIZE 70
      87             : 
      88             : /* The invocation name of this program.  */
      89             : char *program_name;
      90             : 
      91             : /* True if the kernel is SELinux enabled.  */
      92             : static bool selinux_enabled;
      93             : 
      94             : /* If true, the command "cp x/e_file e_dir" uses "e_dir/x/e_file"
      95             :    as its destination instead of the usual "e_dir/e_file." */
      96             : static bool parents_option = false;
      97             : 
      98             : /* Remove any trailing slashes from each SOURCE argument.  */
      99             : static bool remove_trailing_slashes;
     100             : 
     101             : static char const *const sparse_type_string[] =
     102             : {
     103             :   "never", "auto", "always", NULL
     104             : };
     105             : static enum Sparse_type const sparse_type[] =
     106             : {
     107             :   SPARSE_NEVER, SPARSE_AUTO, SPARSE_ALWAYS
     108             : };
     109             : ARGMATCH_VERIFY (sparse_type_string, sparse_type);
     110             : 
     111             : /* Valid arguments to the `--reply' option. */
     112             : static char const* const reply_args[] =
     113             : {
     114             :   "yes", "no", "query", NULL
     115             : };
     116             : /* The values that correspond to the above strings. */
     117             : static int const reply_vals[] =
     118             : {
     119             :   I_ALWAYS_YES, I_ALWAYS_NO, I_ASK_USER
     120             : };
     121             : ARGMATCH_VERIFY (reply_args, reply_vals);
     122             : 
     123             : static struct option const long_opts[] =
     124             : {
     125             :   {"archive", no_argument, NULL, 'a'},
     126             :   {"backup", optional_argument, NULL, 'b'},
     127             :   {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION},
     128             :   {"dereference", no_argument, NULL, 'L'},
     129             :   {"force", no_argument, NULL, 'f'},
     130             :   {"interactive", no_argument, NULL, 'i'},
     131             :   {"link", no_argument, NULL, 'l'},
     132             :   {"no-dereference", no_argument, NULL, 'P'},
     133             :   {"no-preserve", required_argument, NULL, NO_PRESERVE_ATTRIBUTES_OPTION},
     134             :   {"no-target-directory", no_argument, NULL, 'T'},
     135             :   {"one-file-system", no_argument, NULL, 'x'},
     136             :   {"parents", no_argument, NULL, PARENTS_OPTION},
     137             :   {"path", no_argument, NULL, PARENTS_OPTION},   /* Deprecated.  */
     138             :   {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION},
     139             :   {"recursive", no_argument, NULL, 'R'},
     140             :   {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING},
     141             :   {"reply", required_argument, NULL, REPLY_OPTION}, /* Deprecated 2005-07-03,
     142             :                                                        remove in 2008. */
     143             :   {"sparse", required_argument, NULL, SPARSE_OPTION},
     144             :   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
     145             :   {"suffix", required_argument, NULL, 'S'},
     146             :   {"symbolic-link", no_argument, NULL, 's'},
     147             :   {"target-directory", required_argument, NULL, 't'},
     148             :   {"update", no_argument, NULL, 'u'},
     149             :   {"verbose", no_argument, NULL, 'v'},
     150             :   {GETOPT_HELP_OPTION_DECL},
     151             :   {GETOPT_VERSION_OPTION_DECL},
     152             :   {NULL, 0, NULL, 0}
     153             : };
     154             : 
     155             : void
     156          73 : usage (int status)
     157             : {
     158          73 :   if (status != EXIT_SUCCESS)
     159          72 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
     160             :              program_name);
     161             :   else
     162             :     {
     163           1 :       printf (_("\
     164             : Usage: %s [OPTION]... [-T] SOURCE DEST\n\
     165             :   or:  %s [OPTION]... SOURCE... DIRECTORY\n\
     166             :   or:  %s [OPTION]... -t DIRECTORY SOURCE...\n\
     167             : "),
     168             :               program_name, program_name, program_name);
     169           1 :       fputs (_("\
     170             : Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
     171             : \n\
     172             : "), stdout);
     173           1 :       fputs (_("\
     174             : Mandatory arguments to long options are mandatory for short options too.\n\
     175             : "), stdout);
     176           1 :       fputs (_("\
     177             :   -a, --archive                same as -dpR\n\
     178             :       --backup[=CONTROL]       make a backup of each existing destination file\n\
     179             :   -b                           like --backup but does not accept an argument\n\
     180             :       --copy-contents          copy contents of special files when recursive\n\
     181             :   -d                           same as --no-dereference --preserve=links\n\
     182             : "), stdout);
     183           1 :       fputs (_("\
     184             :   -f, --force                  if an existing destination file cannot be\n\
     185             :                                  opened, remove it and try again\n\
     186             :   -i, --interactive            prompt before overwrite\n\
     187             :   -H                           follow command-line symbolic links in SOURCE\n\
     188             : "), stdout);
     189           1 :       fputs (_("\
     190             :   -l, --link                   link files instead of copying\n\
     191             :   -L, --dereference            always follow symbolic links in SOURCE\n\
     192             : "), stdout);
     193           1 :       fputs (_("\
     194             :   -P, --no-dereference         never follow symbolic links in SOURCE\n\
     195             : "), stdout);
     196           1 :       fputs (_("\
     197             :   -p                           same as --preserve=mode,ownership,timestamps\n\
     198             :       --preserve[=ATTR_LIST]   preserve the specified attributes (default:\n\
     199             :                                  mode,ownership,timestamps), if possible\n\
     200             :                                  additional attributes: context, links, all\n\
     201             : "), stdout);
     202           1 :       fputs (_("\
     203             :       --no-preserve=ATTR_LIST  don't preserve the specified attributes\n\
     204             :       --parents                use full source file name under DIRECTORY\n\
     205             : "), stdout);
     206           1 :       fputs (_("\
     207             :   -R, -r, --recursive          copy directories recursively\n\
     208             :       --remove-destination     remove each existing destination file before\n\
     209             :                                  attempting to open it (contrast with --force)\n\
     210             : "), stdout);
     211           1 :       fputs (_("\
     212             :       --sparse=WHEN            control creation of sparse files\n\
     213             :       --strip-trailing-slashes  remove any trailing slashes from each SOURCE\n\
     214             :                                  argument\n\
     215             : "), stdout);
     216           1 :       fputs (_("\
     217             :   -s, --symbolic-link          make symbolic links instead of copying\n\
     218             :   -S, --suffix=SUFFIX          override the usual backup suffix\n\
     219             :   -t, --target-directory=DIRECTORY  copy all SOURCE arguments into DIRECTORY\n\
     220             :   -T, --no-target-directory    treat DEST as a normal file\n\
     221             : "), stdout);
     222           1 :       fputs (_("\
     223             :   -u, --update                 copy only when the SOURCE file is newer\n\
     224             :                                  than the destination file or when the\n\
     225             :                                  destination file is missing\n\
     226             :   -v, --verbose                explain what is being done\n\
     227             :   -x, --one-file-system        stay on this file system\n\
     228             : "), stdout);
     229           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     230           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     231           1 :       fputs (_("\
     232             : \n\
     233             : By default, sparse SOURCE files are detected by a crude heuristic and the\n\
     234             : corresponding DEST file is made sparse as well.  That is the behavior\n\
     235             : selected by --sparse=auto.  Specify --sparse=always to create a sparse DEST\n\
     236             : file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\
     237             : Use --sparse=never to inhibit creation of sparse files.\n\
     238             : \n\
     239             : "), stdout);
     240           1 :       fputs (_("\
     241             : The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
     242             : The version control method may be selected via the --backup option or through\n\
     243             : the VERSION_CONTROL environment variable.  Here are the values:\n\
     244             : \n\
     245             : "), stdout);
     246           1 :       fputs (_("\
     247             :   none, off       never make backups (even if --backup is given)\n\
     248             :   numbered, t     make numbered backups\n\
     249             :   existing, nil   numbered if numbered backups exist, simple otherwise\n\
     250             :   simple, never   always make simple backups\n\
     251             : "), stdout);
     252           1 :       fputs (_("\
     253             : \n\
     254             : As a special case, cp makes a backup of SOURCE when the force and backup\n\
     255             : options are given and SOURCE and DEST are the same name for an existing,\n\
     256             : regular file.\n\
     257             : "), stdout);
     258           1 :       emit_bug_reporting_address ();
     259             :     }
     260          73 :   exit (status);
     261             : }
     262             : 
     263             : /* Ensure that the parent directories of CONST_DST_NAME have the
     264             :    correct protections, for the --parents option.  This is done
     265             :    after all copying has been completed, to allow permissions
     266             :    that don't include user write/execute.
     267             : 
     268             :    SRC_OFFSET is the index in CONST_DST_NAME of the beginning of the
     269             :    source directory name.
     270             : 
     271             :    ATTR_LIST is a null-terminated linked list of structures that
     272             :    indicates the end of the filename of each intermediate directory
     273             :    in CONST_DST_NAME that may need to have its attributes changed.
     274             :    The command `cp --parents --preserve a/b/c d/e_dir' changes the
     275             :    attributes of the directories d/e_dir/a and d/e_dir/a/b to match
     276             :    the corresponding source directories regardless of whether they
     277             :    existed before the `cp' command was given.
     278             : 
     279             :    Return true if the parent of CONST_DST_NAME and any intermediate
     280             :    directories specified by ATTR_LIST have the proper permissions
     281             :    when done.  */
     282             : 
     283             : static bool
     284           0 : re_protect (char const *const_dst_name, size_t src_offset,
     285             :             struct dir_attr *attr_list, const struct cp_options *x)
     286             : {
     287             :   struct dir_attr *p;
     288             :   char *dst_name;               /* A copy of CONST_DST_NAME we can change. */
     289             :   char *src_name;               /* The source name in `dst_name'. */
     290             : 
     291           0 :   ASSIGN_STRDUPA (dst_name, const_dst_name);
     292           0 :   src_name = dst_name + src_offset;
     293             : 
     294           0 :   for (p = attr_list; p; p = p->next)
     295             :     {
     296           0 :       dst_name[p->slash_offset] = '\0';
     297             : 
     298             :       /* Adjust the times (and if possible, ownership) for the copy.
     299             :          chown turns off set[ug]id bits for non-root,
     300             :          so do the chmod last.  */
     301             : 
     302           0 :       if (x->preserve_timestamps)
     303             :         {
     304             :           struct timespec timespec[2];
     305             : 
     306           0 :           timespec[0] = get_stat_atime (&p->st);
     307           0 :           timespec[1] = get_stat_mtime (&p->st);
     308             : 
     309           0 :           if (utimens (dst_name, timespec))
     310             :             {
     311           0 :               error (0, errno, _("failed to preserve times for %s"),
     312             :                      quote (dst_name));
     313           0 :               return false;
     314             :             }
     315             :         }
     316             : 
     317           0 :       if (x->preserve_ownership)
     318             :         {
     319           0 :           if (lchown (dst_name, p->st.st_uid, p->st.st_gid) != 0)
     320             :             {
     321           0 :               if (! chown_failure_ok (x))
     322             :                 {
     323           0 :                   error (0, errno, _("failed to preserve ownership for %s"),
     324             :                          quote (dst_name));
     325           0 :                   return false;
     326             :                 }
     327             :               /* Failing to preserve ownership is OK. Still, try to preserve
     328             :                  the group, but ignore the possible error. */
     329           0 :               (void) lchown (dst_name, -1, p->st.st_gid);
     330             :             }
     331             :         }
     332             : 
     333           0 :       if (x->preserve_mode)
     334             :         {
     335           0 :           if (copy_acl (src_name, -1, dst_name, -1, p->st.st_mode) != 0)
     336           0 :             return false;
     337             :         }
     338           0 :       else if (p->restore_mode)
     339             :         {
     340           0 :           if (lchmod (dst_name, p->st.st_mode) != 0)
     341             :             {
     342           0 :               error (0, errno, _("failed to preserve permissions for %s"),
     343             :                      quote (dst_name));
     344           0 :               return false;
     345             :             }
     346             :         }
     347             : 
     348           0 :       dst_name[p->slash_offset] = '/';
     349             :     }
     350           0 :   return true;
     351             : }
     352             : 
     353             : /* Ensure that the parent directory of CONST_DIR exists, for
     354             :    the --parents option.
     355             : 
     356             :    SRC_OFFSET is the index in CONST_DIR (which is a destination
     357             :    directory) of the beginning of the source directory name.
     358             :    Create any leading directories that don't already exist.
     359             :    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
     360             :    string for printing a message after successfully making a directory.
     361             :    The format should take two string arguments: the names of the
     362             :    source and destination directories.
     363             :    Creates a linked list of attributes of intermediate directories,
     364             :    *ATTR_LIST, for re_protect to use after calling copy.
     365             :    Sets *NEW_DST if this function creates parent of CONST_DIR.
     366             : 
     367             :    Return true if parent of CONST_DIR exists as a directory with the proper
     368             :    permissions when done.  */
     369             : 
     370             : /* FIXME: Synch this function with the one in ../lib/mkdir-p.c.  */
     371             : 
     372             : static bool
     373           0 : make_dir_parents_private (char const *const_dir, size_t src_offset,
     374             :                           char const *verbose_fmt_string,
     375             :                           struct dir_attr **attr_list, bool *new_dst,
     376             :                           const struct cp_options *x)
     377             : {
     378             :   struct stat stats;
     379             :   char *dir;            /* A copy of CONST_DIR we can change.  */
     380             :   char *src;            /* Source name in DIR.  */
     381             :   char *dst_dir;        /* Leading directory of DIR.  */
     382             :   size_t dirlen;        /* Length of DIR.  */
     383             : 
     384           0 :   ASSIGN_STRDUPA (dir, const_dir);
     385             : 
     386           0 :   src = dir + src_offset;
     387             : 
     388           0 :   dirlen = dir_len (dir);
     389           0 :   dst_dir = alloca (dirlen + 1);
     390           0 :   memcpy (dst_dir, dir, dirlen);
     391           0 :   dst_dir[dirlen] = '\0';
     392             : 
     393           0 :   *attr_list = NULL;
     394             : 
     395           0 :   if (stat (dst_dir, &stats) != 0)
     396             :     {
     397             :       /* A parent of CONST_DIR does not exist.
     398             :          Make all missing intermediate directories. */
     399             :       char *slash;
     400             : 
     401           0 :       slash = src;
     402           0 :       while (*slash == '/')
     403           0 :         slash++;
     404           0 :       while ((slash = strchr (slash, '/')))
     405             :         {
     406             :           struct dir_attr *new IF_LINT (= NULL);
     407             :           bool missing_dir;
     408             : 
     409           0 :           *slash = '\0';
     410           0 :           missing_dir = (stat (dir, &stats) != 0);
     411             : 
     412           0 :           if (missing_dir | x->preserve_ownership | x->preserve_mode
     413           0 :               | x->preserve_timestamps)
     414             :             {
     415             :               /* Add this directory to the list of directories whose
     416             :                  modes might need fixing later. */
     417             :               struct stat src_st;
     418           0 :               int src_errno = (stat (src, &src_st) != 0
     419           0 :                                ? errno
     420           0 :                                : S_ISDIR (src_st.st_mode)
     421             :                                ? 0
     422           0 :                                : ENOTDIR);
     423           0 :               if (src_errno)
     424             :                 {
     425           0 :                   error (0, src_errno, _("failed to get attributes of %s"),
     426             :                          quote (src));
     427           0 :                   return false;
     428             :                 }
     429             : 
     430           0 :               new = xmalloc (sizeof *new);
     431           0 :               new->st = src_st;
     432           0 :               new->slash_offset = slash - dir;
     433           0 :               new->restore_mode = false;
     434           0 :               new->next = *attr_list;
     435           0 :               *attr_list = new;
     436             :             }
     437             : 
     438           0 :           if (missing_dir)
     439             :             {
     440             :               mode_t src_mode;
     441             :               mode_t omitted_permissions;
     442             :               mode_t mkdir_mode;
     443             : 
     444             :               /* This component does not exist.  We must set
     445             :                  *new_dst and new->st.st_mode inside this loop because,
     446             :                  for example, in the command `cp --parents ../a/../b/c e_dir',
     447             :                  make_dir_parents_private creates only e_dir/../a if
     448             :                  ./b already exists. */
     449           0 :               *new_dst = true;
     450           0 :               src_mode = new->st.st_mode;
     451             : 
     452             :               /* If the ownership or special mode bits might change,
     453             :                  omit some permissions at first, so unauthorized users
     454             :                  cannot nip in before the file is ready.  */
     455           0 :               omitted_permissions = (src_mode
     456           0 :                                      & (x->preserve_ownership
     457           0 :                                         ? S_IRWXG | S_IRWXO
     458           0 :                                         : x->preserve_mode
     459             :                                         ? S_IWGRP | S_IWOTH
     460             :                                         : 0));
     461             : 
     462             :               /* POSIX says mkdir's behavior is implementation-defined when
     463             :                  (src_mode & ~S_IRWXUGO) != 0.  However, common practice is
     464             :                  to ask mkdir to copy all the CHMOD_MODE_BITS, letting mkdir
     465             :                  decide what to do with S_ISUID | S_ISGID | S_ISVTX.  */
     466           0 :               mkdir_mode = src_mode & CHMOD_MODE_BITS & ~omitted_permissions;
     467           0 :               if (mkdir (dir, mkdir_mode) != 0)
     468             :                 {
     469           0 :                   error (0, errno, _("cannot make directory %s"),
     470             :                          quote (dir));
     471           0 :                   return false;
     472             :                 }
     473             :               else
     474             :                 {
     475           0 :                   if (verbose_fmt_string != NULL)
     476           0 :                     printf (verbose_fmt_string, src, dir);
     477             :                 }
     478             : 
     479             :               /* We need search and write permissions to the new directory
     480             :                  for writing the directory's contents. Check if these
     481             :                  permissions are there.  */
     482             : 
     483           0 :               if (lstat (dir, &stats))
     484             :                 {
     485           0 :                   error (0, errno, _("failed to get attributes of %s"),
     486             :                          quote (dir));
     487           0 :                   return false;
     488             :                 }
     489             : 
     490             : 
     491           0 :               if (! x->preserve_mode)
     492             :                 {
     493           0 :                   if (omitted_permissions & ~stats.st_mode)
     494           0 :                     omitted_permissions &= ~ cached_umask ();
     495           0 :                   if (omitted_permissions & ~stats.st_mode
     496           0 :                       || (stats.st_mode & S_IRWXU) != S_IRWXU)
     497             :                     {
     498           0 :                       new->st.st_mode = stats.st_mode | omitted_permissions;
     499           0 :                       new->restore_mode = true;
     500             :                     }
     501             :                 }
     502             : 
     503           0 :               if ((stats.st_mode & S_IRWXU) != S_IRWXU)
     504             :                 {
     505             :                   /* Make the new directory searchable and writable.
     506             :                      The original permissions will be restored later.  */
     507             : 
     508           0 :                   if (lchmod (dir, stats.st_mode | S_IRWXU) != 0)
     509             :                     {
     510           0 :                       error (0, errno, _("setting permissions for %s"),
     511             :                              quote (dir));
     512           0 :                       return false;
     513             :                     }
     514             :                 }
     515             :             }
     516           0 :           else if (!S_ISDIR (stats.st_mode))
     517             :             {
     518           0 :               error (0, 0, _("%s exists but is not a directory"),
     519             :                      quote (dir));
     520           0 :               return false;
     521             :             }
     522             :           else
     523           0 :             *new_dst = false;
     524           0 :           *slash++ = '/';
     525             : 
     526             :           /* Avoid unnecessary calls to `stat' when given
     527             :              file names containing multiple adjacent slashes.  */
     528           0 :           while (*slash == '/')
     529           0 :             slash++;
     530             :         }
     531             :     }
     532             : 
     533             :   /* We get here if the parent of DIR already exists.  */
     534             : 
     535           0 :   else if (!S_ISDIR (stats.st_mode))
     536             :     {
     537           0 :       error (0, 0, _("%s exists but is not a directory"), quote (dst_dir));
     538           0 :       return false;
     539             :     }
     540             :   else
     541             :     {
     542           0 :       *new_dst = false;
     543             :     }
     544           0 :   return true;
     545             : }
     546             : 
     547             : /* FILE is the last operand of this command.
     548             :    Return true if FILE is a directory.
     549             :    But report an error and exit if there is a problem accessing FILE,
     550             :    or if FILE does not exist but would have to refer to an existing
     551             :    directory if it referred to anything at all.
     552             : 
     553             :    If the file exists, store the file's status into *ST.
     554             :    Otherwise, set *NEW_DST.  */
     555             : 
     556             : static bool
     557         100 : target_directory_operand (char const *file, struct stat *st, bool *new_dst)
     558             : {
     559         100 :   int err = (stat (file, st) == 0 ? 0 : errno);
     560         100 :   bool is_a_dir = !err && S_ISDIR (st->st_mode);
     561         100 :   if (err)
     562             :     {
     563          33 :       if (err != ENOENT)
     564           0 :         error (EXIT_FAILURE, err, _("accessing %s"), quote (file));
     565          33 :       *new_dst = true;
     566             :     }
     567         100 :   return is_a_dir;
     568             : }
     569             : 
     570             : /* Scan the arguments, and copy each by calling copy.
     571             :    Return true if successful.  */
     572             : 
     573             : static bool
     574         159 : do_copy (int n_files, char **file, const char *target_directory,
     575             :          bool no_target_directory, struct cp_options *x)
     576             : {
     577             :   struct stat sb;
     578         159 :   bool new_dst = false;
     579         159 :   bool ok = true;
     580             : 
     581         159 :   if (n_files <= !target_directory)
     582             :     {
     583          55 :       if (n_files <= 0)
     584          37 :         error (0, 0, _("missing file operand"));
     585             :       else
     586          18 :         error (0, 0, _("missing destination file operand after %s"),
     587             :                quote (file[0]));
     588          55 :       usage (EXIT_FAILURE);
     589             :     }
     590             : 
     591         104 :   if (no_target_directory)
     592             :     {
     593           2 :       if (target_directory)
     594           0 :         error (EXIT_FAILURE, 0,
     595             :                _("Cannot combine --target-directory (-t) "
     596             :                  "and --no-target-directory (-T)"));
     597           2 :       if (2 < n_files)
     598             :         {
     599           0 :           error (0, 0, _("extra operand %s"), quote (file[2]));
     600           0 :           usage (EXIT_FAILURE);
     601             :         }
     602             :     }
     603         102 :   else if (!target_directory)
     604             :     {
     605         100 :       if (2 <= n_files
     606         100 :           && target_directory_operand (file[n_files - 1], &sb, &new_dst))
     607          20 :         target_directory = file[--n_files];
     608          80 :       else if (2 < n_files)
     609           3 :         error (EXIT_FAILURE, 0, _("target %s is not a directory"),
     610           3 :                quote (file[n_files - 1]));
     611             :     }
     612             : 
     613         101 :   if (target_directory)
     614             :     {
     615             :       /* cp file1...filen edir
     616             :          Copy the files `file1' through `filen'
     617             :          to the existing directory `edir'. */
     618             :       int i;
     619             : 
     620             :       /* Initialize these hash tables only if we'll need them.
     621             :          The problems they're used to detect can arise only if
     622             :          there are two or more files to copy.  */
     623          22 :       if (2 <= n_files)
     624             :         {
     625           7 :           dest_info_init (x);
     626           7 :           src_info_init (x);
     627             :         }
     628             : 
     629          51 :       for (i = 0; i < n_files; i++)
     630             :         {
     631             :           char *dst_name;
     632          29 :           bool parent_exists = true;  /* True if dir_name (dst_name) exists. */
     633             :           struct dir_attr *attr_list;
     634          29 :           char *arg_in_concat = NULL;
     635          29 :           char *arg = file[i];
     636             : 
     637             :           /* Trailing slashes are meaningful (i.e., maybe worth preserving)
     638             :              only in the source file names.  */
     639          29 :           if (remove_trailing_slashes)
     640           0 :             strip_trailing_slashes (arg);
     641             : 
     642          29 :           if (parents_option)
     643             :             {
     644             :               char *arg_no_trailing_slash;
     645             : 
     646             :               /* Use `arg' without trailing slashes in constructing destination
     647             :                  file names.  Otherwise, we can end up trying to create a
     648             :                  directory via `mkdir ("dst/foo/"...', which is not portable.
     649             :                  It fails, due to the trailing slash, on at least
     650             :                  NetBSD 1.[34] systems.  */
     651           0 :               ASSIGN_STRDUPA (arg_no_trailing_slash, arg);
     652           0 :               strip_trailing_slashes (arg_no_trailing_slash);
     653             : 
     654             :               /* Append all of `arg' (minus any trailing slash) to `dest'.  */
     655           0 :               dst_name = file_name_concat (target_directory,
     656             :                                            arg_no_trailing_slash,
     657             :                                            &arg_in_concat);
     658             : 
     659             :               /* For --parents, we have to make sure that the directory
     660             :                  dir_name (dst_name) exists.  We may have to create a few
     661             :                  leading directories. */
     662           0 :               parent_exists =
     663           0 :                 (make_dir_parents_private
     664           0 :                  (dst_name, arg_in_concat - dst_name,
     665           0 :                   (x->verbose ? "%s -> %s\n" : NULL),
     666             :                   &attr_list, &new_dst, x));
     667             :             }
     668             :           else
     669             :             {
     670             :               char *arg_base;
     671             :               /* Append the last component of `arg' to `target_directory'.  */
     672             : 
     673          29 :               ASSIGN_BASENAME_STRDUPA (arg_base, arg);
     674             :               /* For `cp -R source/.. dest', don't copy into `dest/..'. */
     675          58 :               dst_name = (STREQ (arg_base, "..")
     676             :                           ? xstrdup (target_directory)
     677          29 :                           : file_name_concat (target_directory, arg_base,
     678             :                                               NULL));
     679             :             }
     680             : 
     681          29 :           if (!parent_exists)
     682             :             {
     683             :               /* make_dir_parents_private failed, so don't even
     684             :                  attempt the copy.  */
     685           0 :               ok = false;
     686             :             }
     687             :           else
     688             :             {
     689             :               bool copy_into_self;
     690          29 :               ok &= copy (arg, dst_name, new_dst, x, &copy_into_self, NULL);
     691             : 
     692          29 :               if (parents_option)
     693           0 :                 ok &= re_protect (dst_name, arg_in_concat - dst_name,
     694             :                                   attr_list, x);
     695             :             }
     696             : 
     697          29 :           if (parents_option)
     698             :             {
     699           0 :               while (attr_list)
     700             :                 {
     701           0 :                   struct dir_attr *p = attr_list;
     702           0 :                   attr_list = attr_list->next;
     703           0 :                   free (p);
     704             :                 }
     705             :             }
     706             : 
     707          29 :           free (dst_name);
     708             :         }
     709             :     }
     710             :   else /* !target_directory */
     711             :     {
     712             :       char const *new_dest;
     713          79 :       char const *source = file[0];
     714          79 :       char const *dest = file[1];
     715             :       bool unused;
     716             : 
     717          79 :       if (parents_option)
     718             :         {
     719           0 :           error (0, 0,
     720             :                  _("with --parents, the destination must be a directory"));
     721           0 :           usage (EXIT_FAILURE);
     722             :         }
     723             : 
     724             :       /* When the force and backup options have been specified and
     725             :          the source and destination are the same name for an existing
     726             :          regular file, convert the user's command, e.g.,
     727             :          `cp --force --backup foo foo' to `cp --force foo fooSUFFIX'
     728             :          where SUFFIX is determined by any version control options used.  */
     729             : 
     730          79 :       if (x->unlink_dest_after_failed_open
     731           5 :           && x->backup_type != no_backups
     732           3 :           && STREQ (source, dest)
     733           2 :           && !new_dst && S_ISREG (sb.st_mode))
     734           1 :         {
     735             :           static struct cp_options x_tmp;
     736             : 
     737           1 :           new_dest = find_backup_file_name (dest, x->backup_type);
     738             :           /* Set x->backup_type to `no_backups' so that the normal backup
     739             :              mechanism is not used when performing the actual copy.
     740             :              backup_type must be set to `no_backups' only *after* the above
     741             :              call to find_backup_file_name -- that function uses
     742             :              backup_type to determine the suffix it applies.  */
     743           1 :           x_tmp = *x;
     744           1 :           x_tmp.backup_type = no_backups;
     745           1 :           x = &x_tmp;
     746             :         }
     747             :       else
     748             :         {
     749          78 :           new_dest = dest;
     750             :         }
     751             : 
     752          79 :       ok = copy (source, new_dest, 0, x, &unused, NULL);
     753             :     }
     754             : 
     755         101 :   return ok;
     756             : }
     757             : 
     758             : static void
     759         183 : cp_option_init (struct cp_options *x)
     760             : {
     761         183 :   cp_options_default (x);
     762         183 :   x->copy_as_regular = true;
     763         183 :   x->dereference = DEREF_UNDEFINED;
     764         183 :   x->unlink_dest_before_opening = false;
     765         183 :   x->unlink_dest_after_failed_open = false;
     766         183 :   x->hard_link = false;
     767         183 :   x->interactive = I_UNSPECIFIED;
     768         183 :   x->move_mode = false;
     769         183 :   x->one_file_system = false;
     770             : 
     771         183 :   x->preserve_ownership = false;
     772         183 :   x->preserve_links = false;
     773         183 :   x->preserve_mode = false;
     774         183 :   x->preserve_timestamps = false;
     775         183 :   x->preserve_security_context = false;
     776         183 :   x->require_preserve_context = false;
     777             : 
     778         183 :   x->require_preserve = false;
     779         183 :   x->recursive = false;
     780         183 :   x->sparse_mode = SPARSE_AUTO;
     781         183 :   x->symbolic_link = false;
     782         183 :   x->set_mode = false;
     783         183 :   x->mode = 0;
     784             : 
     785             :   /* Not used.  */
     786         183 :   x->stdin_tty = false;
     787             : 
     788         183 :   x->update = false;
     789         183 :   x->verbose = false;
     790             : 
     791             :   /* By default, refuse to open a dangling destination symlink, because
     792             :      in general one cannot do that safely, give the current semantics of
     793             :      open's O_EXCL flag, (which POSIX doesn't even allow cp to use, btw).
     794             :      But POSIX requires it.  */
     795         183 :   x->open_dangling_dest_symlink = getenv ("POSIXLY_CORRECT") != NULL;
     796             : 
     797         183 :   x->dest_info = NULL;
     798         183 :   x->src_info = NULL;
     799         183 : }
     800             : 
     801             : /* Given a string, ARG, containing a comma-separated list of arguments
     802             :    to the --preserve option, set the appropriate fields of X to ON_OFF.  */
     803             : static void
     804          11 : decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
     805             : {
     806             :   enum File_attribute
     807             :     {
     808             :       PRESERVE_MODE,
     809             :       PRESERVE_TIMESTAMPS,
     810             :       PRESERVE_OWNERSHIP,
     811             :       PRESERVE_LINK,
     812             :       PRESERVE_CONTEXT,
     813             :       PRESERVE_ALL
     814             :     };
     815             :   static enum File_attribute const preserve_vals[] =
     816             :     {
     817             :       PRESERVE_MODE, PRESERVE_TIMESTAMPS,
     818             :       PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL
     819             :     };
     820             :   /* Valid arguments to the `--preserve' option. */
     821             :   static char const* const preserve_args[] =
     822             :     {
     823             :       "mode", "timestamps",
     824             :       "ownership", "links", "context", "all", NULL
     825             :     };
     826             :   ARGMATCH_VERIFY (preserve_args, preserve_vals);
     827             : 
     828          11 :   char *arg_writable = xstrdup (arg);
     829          11 :   char *s = arg_writable;
     830             :   do
     831             :     {
     832             :       /* find next comma */
     833          12 :       char *comma = strchr (s, ',');
     834             :       enum File_attribute val;
     835             : 
     836             :       /* If we found a comma, put a NUL in its place and advance.  */
     837          12 :       if (comma)
     838           2 :         *comma++ = 0;
     839             : 
     840             :       /* process S.  */
     841          12 :       val = XARGMATCH ("--preserve", s, preserve_args, preserve_vals);
     842           8 :       switch (val)
     843             :         {
     844           3 :         case PRESERVE_MODE:
     845           3 :           x->preserve_mode = on_off;
     846           3 :           break;
     847             : 
     848           1 :         case PRESERVE_TIMESTAMPS:
     849           1 :           x->preserve_timestamps = on_off;
     850           1 :           break;
     851             : 
     852           1 :         case PRESERVE_OWNERSHIP:
     853           1 :           x->preserve_ownership = on_off;
     854           1 :           break;
     855             : 
     856           1 :         case PRESERVE_LINK:
     857           1 :           x->preserve_links = on_off;
     858           1 :           break;
     859             : 
     860           1 :         case PRESERVE_CONTEXT:
     861           1 :           x->preserve_security_context = on_off;
     862           1 :           x->require_preserve_context = on_off;
     863           1 :           break;
     864             : 
     865           1 :         case PRESERVE_ALL:
     866           1 :           x->preserve_mode = on_off;
     867           1 :           x->preserve_timestamps = on_off;
     868           1 :           x->preserve_ownership = on_off;
     869           1 :           x->preserve_links = on_off;
     870           1 :           if (selinux_enabled)
     871           0 :             x->preserve_security_context = on_off;
     872           1 :           break;
     873             : 
     874           0 :         default:
     875           0 :           abort ();
     876             :         }
     877           8 :       s = comma;
     878             :     }
     879           8 :   while (s);
     880             : 
     881           7 :   free (arg_writable);
     882           7 : }
     883             : 
     884             : int
     885         183 : main (int argc, char **argv)
     886             : {
     887             :   int c;
     888             :   bool ok;
     889         183 :   bool make_backups = false;
     890             :   char *backup_suffix_string;
     891         183 :   char *version_control_string = NULL;
     892             :   struct cp_options x;
     893         183 :   bool copy_contents = false;
     894         183 :   char *target_directory = NULL;
     895         183 :   bool no_target_directory = false;
     896             : 
     897             :   initialize_main (&argc, &argv);
     898         183 :   program_name = argv[0];
     899         183 :   setlocale (LC_ALL, "");
     900             :   bindtextdomain (PACKAGE, LOCALEDIR);
     901             :   textdomain (PACKAGE);
     902             : 
     903         183 :   atexit (close_stdin);
     904             : 
     905         183 :   selinux_enabled = (0 < is_selinux_enabled ());
     906         183 :   cp_option_init (&x);
     907             : 
     908             :   /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
     909             :      we'll actually use backup_suffix_string.  */
     910         183 :   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
     911             : 
     912         490 :   while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:T",
     913             :                            long_opts, NULL))
     914             :          != -1)
     915             :     {
     916         144 :       switch (c)
     917             :         {
     918           3 :         case SPARSE_OPTION:
     919           3 :           x.sparse_mode = XARGMATCH ("--sparse", optarg,
     920             :                                      sparse_type_string, sparse_type);
     921           2 :           break;
     922             : 
     923          35 :         case 'a':               /* Like -dpPR. */
     924          35 :           x.dereference = DEREF_NEVER;
     925          35 :           x.preserve_links = true;
     926          35 :           x.preserve_ownership = true;
     927          35 :           x.preserve_mode = true;
     928          35 :           x.preserve_timestamps = true;
     929          35 :           x.require_preserve = true;
     930          35 :           x.recursive = true;
     931          35 :           break;
     932             : 
     933          22 :         case 'b':
     934          22 :           make_backups = true;
     935          22 :           if (optarg)
     936           6 :             version_control_string = optarg;
     937          22 :           break;
     938             : 
     939           0 :         case COPY_CONTENTS_OPTION:
     940           0 :           copy_contents = true;
     941           0 :           break;
     942             : 
     943           3 :         case 'd':
     944           3 :           x.preserve_links = true;
     945           3 :           x.dereference = DEREF_NEVER;
     946           3 :           break;
     947             : 
     948           7 :         case 'f':
     949           7 :           x.unlink_dest_after_failed_open = true;
     950           7 :           break;
     951             : 
     952           2 :         case 'H':
     953           2 :           x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
     954           2 :           break;
     955             : 
     956           7 :         case 'i':
     957           7 :           x.interactive = I_ASK_USER;
     958           7 :           break;
     959             : 
     960           6 :         case 'l':
     961           6 :           x.hard_link = true;
     962           6 :           break;
     963             : 
     964           1 :         case 'L':
     965           1 :           x.dereference = DEREF_ALWAYS;
     966           1 :           break;
     967             : 
     968           1 :         case 'P':
     969           1 :           x.dereference = DEREF_NEVER;
     970           1 :           break;
     971             : 
     972           2 :         case NO_PRESERVE_ATTRIBUTES_OPTION:
     973           2 :           decode_preserve_arg (optarg, &x, false);
     974           1 :           break;
     975             : 
     976          10 :         case PRESERVE_ATTRIBUTES_OPTION:
     977          10 :           if (optarg == NULL)
     978             :             {
     979             :               /* Fall through to the case for `p' below.  */
     980             :             }
     981             :           else
     982             :             {
     983           9 :               decode_preserve_arg (optarg, &x, true);
     984           6 :               x.require_preserve = true;
     985           6 :               break;
     986             :             }
     987             : 
     988             :         case 'p':
     989           2 :           x.preserve_ownership = true;
     990           2 :           x.preserve_mode = true;
     991           2 :           x.preserve_timestamps = true;
     992           2 :           x.require_preserve = true;
     993           2 :           break;
     994             : 
     995           1 :         case PARENTS_OPTION:
     996           1 :           parents_option = true;
     997           1 :           break;
     998             : 
     999           1 :         case 'r':
    1000             :         case 'R':
    1001           1 :           x.recursive = true;
    1002           1 :           break;
    1003             : 
    1004           2 :         case REPLY_OPTION: /* Deprecated */
    1005           2 :           x.interactive = XARGMATCH ("--reply", optarg,
    1006             :                                      reply_args, reply_vals);
    1007           1 :           error (0, 0,
    1008             :                  _("the --reply option is deprecated; use -i or -f instead"));
    1009           1 :           break;
    1010             : 
    1011           1 :         case UNLINK_DEST_BEFORE_OPENING:
    1012           1 :           x.unlink_dest_before_opening = true;
    1013           1 :           break;
    1014             : 
    1015           1 :         case STRIP_TRAILING_SLASHES_OPTION:
    1016           1 :           remove_trailing_slashes = true;
    1017           1 :           break;
    1018             : 
    1019           8 :         case 's':
    1020           8 :           x.symbolic_link = true;
    1021           8 :           break;
    1022             : 
    1023           7 :         case 't':
    1024           7 :           if (target_directory)
    1025           0 :             error (EXIT_FAILURE, 0,
    1026             :                    _("multiple target directories specified"));
    1027             :           else
    1028             :             {
    1029             :               struct stat st;
    1030           7 :               if (stat (optarg, &st) != 0)
    1031           3 :                 error (EXIT_FAILURE, errno, _("accessing %s"), quote (optarg));
    1032           4 :               if (! S_ISDIR (st.st_mode))
    1033           1 :                 error (EXIT_FAILURE, 0, _("target %s is not a directory"),
    1034             :                        quote (optarg));
    1035             :             }
    1036           3 :           target_directory = optarg;
    1037           3 :           break;
    1038             : 
    1039           3 :         case 'T':
    1040           3 :           no_target_directory = true;
    1041           3 :           break;
    1042             : 
    1043           6 :         case 'u':
    1044           6 :           x.update = true;
    1045           6 :           break;
    1046             : 
    1047           2 :         case 'v':
    1048           2 :           x.verbose = true;
    1049           2 :           break;
    1050             : 
    1051           1 :         case 'x':
    1052           1 :           x.one_file_system = true;
    1053           1 :           break;
    1054             : 
    1055           1 :         case 'S':
    1056           1 :           make_backups = true;
    1057           1 :           backup_suffix_string = optarg;
    1058           1 :           break;
    1059             : 
    1060           1 :         case_GETOPT_HELP_CHAR;
    1061             : 
    1062           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
    1063             : 
    1064           8 :         default:
    1065           8 :           usage (EXIT_FAILURE);
    1066             :         }
    1067             :     }
    1068             : 
    1069         163 :   if (x.hard_link & x.symbolic_link)
    1070             :     {
    1071           1 :       error (0, 0, _("cannot make both hard and symbolic links"));
    1072           1 :       usage (EXIT_FAILURE);
    1073             :     }
    1074             : 
    1075         162 :   if (backup_suffix_string)
    1076           1 :     simple_backup_suffix = xstrdup (backup_suffix_string);
    1077             : 
    1078         160 :   x.backup_type = (make_backups
    1079             :                    ? xget_version (_("backup type"),
    1080             :                                    version_control_string)
    1081         162 :                    : no_backups);
    1082             : 
    1083         160 :   if (x.dereference == DEREF_UNDEFINED)
    1084             :     {
    1085         123 :       if (x.recursive)
    1086             :         /* This is compatible with FreeBSD.  */
    1087           1 :         x.dereference = DEREF_NEVER;
    1088             :       else
    1089         122 :         x.dereference = DEREF_ALWAYS;
    1090             :     }
    1091             : 
    1092         160 :   if (x.recursive)
    1093          33 :     x.copy_as_regular = copy_contents;
    1094             : 
    1095             :   /* If --force (-f) was specified and we're in link-creation mode,
    1096             :      first remove any existing destination file.  */
    1097         160 :   if (x.unlink_dest_after_failed_open & (x.hard_link | x.symbolic_link))
    1098           1 :     x.unlink_dest_before_opening = true;
    1099             : 
    1100         160 :   if (x.preserve_security_context)
    1101             :     {
    1102           1 :       if (!selinux_enabled)
    1103           1 :         error (EXIT_FAILURE, 0,
    1104             :                _("cannot preserve security context "
    1105             :                  "without an SELinux-enabled kernel"));
    1106             :     }
    1107             : 
    1108             :   /* Allocate space for remembering copied and created files.  */
    1109             : 
    1110         159 :   hash_init ();
    1111             : 
    1112         159 :   ok = do_copy (argc - optind, argv + optind,
    1113             :                 target_directory, no_target_directory, &x);
    1114             : 
    1115         101 :   forget_all ();
    1116             : 
    1117         101 :   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
    1118             : }

Generated by: LCOV version 1.10