📄 cp.c
字号:
/* If `dest' is not a symlink to a nonexistent file, use the results of stat instead of lstat, so we can copy files into symlinks to directories. */ if (stat (dest, &sbx) == 0) sb = sbx; dest_is_dir = S_ISDIR (sb.st_mode); } if (!dest_is_dir) { if (target_directory) { error (0, 0, _("%s: specified target is not a directory"), quote (dest)); usage (1); } if (n_files > 1) { error (0, 0, _("copying multiple files, but last argument %s is not a directory"), quote (dest)); usage (1); } } if (dest_is_dir) { /* cp file1...filen edir Copy the files `file1' through `filen' to the existing directory `edir'. */ int i; for (i = 0; i < n_files; i++) { char *dst_path; int parent_exists = 1; /* True if dir_name (dst_path) exists. */ struct dir_attr *attr_list; char *arg_in_concat = NULL; char *arg = file[i]; /* Trailing slashes are meaningful (i.e., maybe worth preserving) only in the source file names. */ if (remove_trailing_slashes) strip_trailing_slashes (arg); if (flag_path) { char *arg_no_trailing_slash; /* Use `arg' without trailing slashes in constructing destination file names. Otherwise, we can end up trying to create a directory via `mkdir ("dst/foo/"...', which is not portable. It fails, due to the trailing slash, on at least NetBSD 1.[34] systems. */ ASSIGN_STRDUPA (arg_no_trailing_slash, arg); strip_trailing_slashes (arg_no_trailing_slash); /* Append all of `arg' (minus any trailing slash) to `dest'. */ dst_path = path_concat (dest, arg_no_trailing_slash, &arg_in_concat); if (dst_path == NULL) xalloc_die (); /* For --parents, we have to make sure that the directory dir_name (dst_path) exists. We may have to create a few leading directories. */ parent_exists = !make_path_private (dst_path, arg_in_concat - dst_path, S_IRWXU, (x->verbose ? "%s -> %s\n" : NULL), &attr_list, &new_dst, x->xstat); } else { char *arg_base; /* Append the last component of `arg' to `dest'. */ ASSIGN_BASENAME_STRDUPA (arg_base, arg); /* For `cp -R source/.. dest', don't copy into `dest/..'. */ dst_path = (STREQ (arg_base, "..") ? xstrdup (dest) : path_concat (dest, arg_base, NULL)); } if (!parent_exists) { /* make_path_private failed, so don't even attempt the copy. */ ret = 1; } else { int copy_into_self; ret |= copy (arg, dst_path, new_dst, x, ©_into_self, NULL); if (flag_path) { ret |= re_protect (dst_path, arg_in_concat - dst_path, attr_list, x); } } free (dst_path); } return ret; } else /* if (n_files == 1) */ { char *new_dest; char *source; int unused; struct stat source_stats; if (flag_path) { error (0, 0, _("when preserving paths, the destination must be a directory")); usage (1); } source = file[0]; /* When the force and backup options have been specified and the source and destination are the same name for an existing regular file, convert the user's command, e.g., `cp --force --backup foo foo' to `cp --force foo fooSUFFIX' where SUFFIX is determined by any version control options used. */ if (x->unlink_dest_after_failed_open && x->backup_type != none && STREQ (source, dest) && !new_dst && S_ISREG (sb.st_mode)) { static struct cp_options x_tmp; new_dest = find_backup_file_name (dest, x->backup_type); /* Set x->backup_type to `none' so that the normal backup mechanism is not used when performing the actual copy. backup_type must be set to `none' only *after* the above call to find_backup_file_name -- that function uses backup_type to determine the suffix it applies. */ x_tmp = *x; x_tmp.backup_type = none; x = &x_tmp; if (new_dest == NULL) xalloc_die (); } /* When the destination is specified with a trailing slash and the source exists but is not a directory, convert the user's command `cp source dest/' to `cp source dest/basename(source)'. Doing this ensures that the command `cp non-directory file/' will now fail rather than performing the copy. COPY diagnoses the case of `cp directory non-directory'. */ else if (dest[strlen (dest) - 1] == '/' && lstat (source, &source_stats) == 0 && !S_ISDIR (source_stats.st_mode)) { char *source_base; ASSIGN_BASENAME_STRDUPA (source_base, source); new_dest = (char *) alloca (strlen (dest) + strlen (source_base) + 1); stpcpy (stpcpy (new_dest, dest), source_base); } else { new_dest = (char *) dest; } return copy (source, new_dest, new_dst, x, &unused, NULL); } /* unreachable */}static voidcp_option_init (struct cp_options *x){ x->copy_as_regular = 1; x->dereference = DEREF_UNDEFINED; x->unlink_dest_before_opening = 0; x->unlink_dest_after_failed_open = 0; x->hard_link = 0; x->interactive = I_UNSPECIFIED; x->myeuid = geteuid (); x->move_mode = 0; x->one_file_system = 0; x->preserve_ownership = 0; x->preserve_links = 0; x->preserve_mode = 0; x->preserve_timestamps = 0; x->require_preserve = 0; x->recursive = 0; x->sparse_mode = SPARSE_AUTO; x->symbolic_link = 0; x->set_mode = 0; x->mode = 0; /* Not used. */ x->stdin_tty = 0; /* Find out the current file creation mask, to knock the right bits when using chmod. The creation mask is set to be liberal, so that created directories can be written, even if it would not have been allowed with the mask this process was started with. */ x->umask_kill = ~ umask (0); x->update = 0; x->verbose = 0; x->dest_info = NULL; x->src_info = NULL;}/* Given a string, ARG, containing a comma-separated list of arguments to the --preserve option, set the appropriate fields of X to ON_OFF. */static voiddecode_preserve_arg (char const *arg, struct cp_options *x, int on_off){ enum File_attribute { PRESERVE_MODE, PRESERVE_TIMESTAMPS, PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL }; static enum File_attribute const preserve_vals[] = { PRESERVE_MODE, PRESERVE_TIMESTAMPS, PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL }; /* Valid arguments to the `--reply' option. */ static char const* const preserve_args[] = { "mode", "timestamps", "ownership", "links", "all", 0 }; char *arg_writable = xstrdup (arg); char *s = arg_writable; do { /* find next comma */ char *comma = strchr (s, ','); enum File_attribute val; /* put a NUL in its place */ if (comma) *comma = 0; /* process S. */ val = XARGMATCH ("--preserve", s, preserve_args, preserve_vals); switch (val) { case PRESERVE_MODE: x->preserve_mode = on_off; break; case PRESERVE_TIMESTAMPS: x->preserve_timestamps = on_off; break; case PRESERVE_OWNERSHIP: x->preserve_ownership = on_off; break; case PRESERVE_LINK: x->preserve_links = on_off; break; case PRESERVE_ALL: x->preserve_mode = on_off; x->preserve_timestamps = on_off; x->preserve_ownership = on_off; x->preserve_links = on_off; break; default: abort (); } s = comma; } while (s); free (arg_writable);}intmain (int argc, char **argv){ int c; int make_backups = 0; char *backup_suffix_string; char *version_control_string = NULL; struct cp_options x; int copy_contents = 0; char *target_directory = NULL; program_name = argv[0]; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); atexit (close_stdout); cp_option_init (&x); /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless we'll actually use backup_suffix_string. */ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL)) != -1) { switch (c) { case 0: break; case SPARSE_OPTION: x.sparse_mode = XARGMATCH ("--sparse", optarg, sparse_type_string, sparse_type); break; case 'a': /* Like -dpPR. */ x.dereference = DEREF_NEVER; x.preserve_links = 1; x.preserve_ownership = 1; x.preserve_mode = 1; x.preserve_timestamps = 1; x.require_preserve = 1; x.recursive = 1; break; case 'V': /* FIXME: this is deprecated. Remove it in 2001. */ error (0, 0, _("warning: --version-control (-V) is obsolete; support for\ it\nwill be removed in some future release. Use --backup=%s instead." ), optarg); /* Fall through. */ case 'b': make_backups = 1; if (optarg) version_control_string = optarg; break; case COPY_CONTENTS_OPTION: copy_contents = 1; break; case 'd': x.preserve_links = 1; x.dereference = DEREF_NEVER; break; case 'f': x.unlink_dest_after_failed_open = 1; break; case 'H': x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; break; case 'i': x.interactive = I_ASK_USER; break; case 'l': x.hard_link = 1; break; case 'L': x.dereference = DEREF_ALWAYS; break; case 'P': x.dereference = DEREF_NEVER; break; case NO_PRESERVE_ATTRIBUTES_OPTION: decode_preserve_arg (optarg, &x, 0); break; case PRESERVE_ATTRIBUTES_OPTION: if (optarg == NULL) { /* Fall through to the case for `p' below. */ } else { decode_preserve_arg (optarg, &x, 1); x.require_preserve = 1; break; } case 'p': x.preserve_ownership = 1; x.preserve_mode = 1; x.preserve_timestamps = 1; x.require_preserve = 1; break; case PARENTS_OPTION: flag_path = 1; break; case 'r': case 'R': x.recursive = 1; break; case REPLY_OPTION: x.interactive = XARGMATCH ("--reply", optarg, reply_args, reply_vals); break; case UNLINK_DEST_BEFORE_OPENING: x.unlink_dest_before_opening = 1; break; case STRIP_TRAILING_SLASHES_OPTION: remove_trailing_slashes = 1; break; case 's':#ifdef S_ISLNK x.symbolic_link = 1;#else error (1, 0, _("symbolic links are not supported on this system"));#endif break; case TARGET_DIRECTORY_OPTION: target_directory = optarg; break; case 'u': x.update = 1; break; case 'v': x.verbose = 1; break; case 'x': x.one_file_system = 1; break; case 'S': make_backups = 1; backup_suffix_string = optarg; break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: usage (1); } } if (x.hard_link && x.symbolic_link) { error (0, 0, _("cannot make both hard and symbolic links")); usage (1); } if (backup_suffix_string) simple_backup_suffix = xstrdup (backup_suffix_string); x.backup_type = (make_backups ? xget_version (_("backup type"), version_control_string) : none); if (x.preserve_mode == 1) x.umask_kill = ~ (mode_t) 0; if (x.dereference == DEREF_UNDEFINED) { if (x.recursive) /* This is compatible with FreeBSD. */ x.dereference = DEREF_NEVER; else x.dereference = DEREF_ALWAYS; } /* The key difference between -d (--no-dereference) and not is the version of `stat' to call. */ if (x.dereference == DEREF_NEVER) x.xstat = lstat; else { /* For DEREF_COMMAND_LINE_ARGUMENTS, x.xstat must be stat for each command line argument, but must later be `lstat' for any symlinks that are found via recursive traversal. */ x.xstat = stat; } if (x.recursive) x.copy_as_regular = copy_contents; /* If --force (-f) was specified and we're in link-creation mode, first remove any existing destination file. */ if (x.unlink_dest_after_failed_open && (x.hard_link || x.symbolic_link)) x.unlink_dest_before_opening = 1; /* Allocate space for remembering copied and created files. */ hash_init (); exit_status |= do_copy (argc - optind, argv + optind, target_directory, &x); forget_all (); exit (exit_status);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -