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