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