cp: implement -t DIR
function old new delta packed_usage 33713 33734 +21 .rodata 103670 103672 +2 cp_main 506 500 -6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 23/-6) Total: 17 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
1de709fda2
commit
0ec52d438a
130
coreutils/cp.c
130
coreutils/cp.c
@ -37,8 +37,55 @@
|
|||||||
|
|
||||||
/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */
|
/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */
|
||||||
|
|
||||||
|
// Options of cp from GNU coreutils 6.10:
|
||||||
|
// -a, --archive
|
||||||
|
// -f, --force
|
||||||
|
// -i, --interactive
|
||||||
|
// -l, --link
|
||||||
|
// -L, --dereference
|
||||||
|
// -P, --no-dereference
|
||||||
|
// -R, -r, --recursive
|
||||||
|
// -s, --symbolic-link
|
||||||
|
// -v, --verbose
|
||||||
|
// -H follow command-line symbolic links in SOURCE
|
||||||
|
// -d same as --no-dereference --preserve=links
|
||||||
|
// -p same as --preserve=mode,ownership,timestamps
|
||||||
|
// -c same as --preserve=context
|
||||||
|
// -u, --update
|
||||||
|
// copy only when the SOURCE file is newer than the destination
|
||||||
|
// file or when the destination file is missing
|
||||||
|
// --remove-destination
|
||||||
|
// remove each existing destination file before attempting to open
|
||||||
|
// --parents
|
||||||
|
// use full source file name under DIRECTORY
|
||||||
|
// -T, --no-target-directory
|
||||||
|
// treat DEST as a normal file
|
||||||
|
// NOT SUPPORTED IN BBOX:
|
||||||
|
// --backup[=CONTROL]
|
||||||
|
// make a backup of each existing destination file
|
||||||
|
// -b like --backup but does not accept an argument
|
||||||
|
// --copy-contents
|
||||||
|
// copy contents of special files when recursive
|
||||||
|
// --preserve[=ATTR_LIST]
|
||||||
|
// preserve attributes (default: mode,ownership,timestamps),
|
||||||
|
// if possible additional attributes: security context,links,all
|
||||||
|
// --no-preserve=ATTR_LIST
|
||||||
|
// --sparse=WHEN
|
||||||
|
// control creation of sparse files
|
||||||
|
// --strip-trailing-slashes
|
||||||
|
// remove any trailing slashes from each SOURCE argument
|
||||||
|
// -S, --suffix=SUFFIX
|
||||||
|
// override the usual backup suffix
|
||||||
|
// -t, --target-directory=DIRECTORY
|
||||||
|
// copy all SOURCE arguments into DIRECTORY
|
||||||
|
// -x, --one-file-system
|
||||||
|
// stay on this file system
|
||||||
|
// -Z, --context=CONTEXT
|
||||||
|
// (SELinux) set SELinux security context of copy to CONTEXT
|
||||||
|
|
||||||
//usage:#define cp_trivial_usage
|
//usage:#define cp_trivial_usage
|
||||||
//usage: "[-arPLHpfilsTu] SOURCE... DEST"
|
//usage: "[-arPLHpfilsTu] SOURCE DEST\n"
|
||||||
|
//usage: "or: cp [-arPLHpfilsu] SOURCE... { -t DIRECTORY | DIRECTORY }"
|
||||||
//usage:#define cp_full_usage "\n\n"
|
//usage:#define cp_full_usage "\n\n"
|
||||||
//usage: "Copy SOURCEs to DEST\n"
|
//usage: "Copy SOURCEs to DEST\n"
|
||||||
//usage: "\n -a Same as -dpR"
|
//usage: "\n -a Same as -dpR"
|
||||||
@ -53,7 +100,8 @@
|
|||||||
//usage: "\n -f Overwrite"
|
//usage: "\n -f Overwrite"
|
||||||
//usage: "\n -i Prompt before overwrite"
|
//usage: "\n -i Prompt before overwrite"
|
||||||
//usage: "\n -l,-s Create (sym)links"
|
//usage: "\n -l,-s Create (sym)links"
|
||||||
//usage: "\n -T Treat DEST as a normal file"
|
//usage: "\n -T Refuse to copy if DEST is a directory"
|
||||||
|
//usage: "\n -t DIR Copy all SOURCEs into DIR"
|
||||||
//usage: "\n -u Copy only newer files"
|
//usage: "\n -u Copy only newer files"
|
||||||
|
|
||||||
#include "libbb.h"
|
#include "libbb.h"
|
||||||
@ -73,14 +121,12 @@ int cp_main(int argc, char **argv)
|
|||||||
int flags;
|
int flags;
|
||||||
int status;
|
int status;
|
||||||
enum {
|
enum {
|
||||||
FILEUTILS_CP_OPTNUM = sizeof(FILEUTILS_CP_OPTSTR)-1,
|
|
||||||
#if ENABLE_FEATURE_CP_LONG_OPTIONS
|
#if ENABLE_FEATURE_CP_LONG_OPTIONS
|
||||||
/*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTNUM */
|
/*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTNUM */
|
||||||
OPT_parents = 1 << (FILEUTILS_CP_OPTNUM+1),
|
OPT_parents = 1 << (FILEUTILS_CP_OPTNUM+1),
|
||||||
OPT_reflink = 1 << (FILEUTILS_CP_OPTNUM+2),
|
OPT_reflink = 1 << (FILEUTILS_CP_OPTNUM+2),
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ENABLE_FEATURE_CP_LONG_OPTIONS
|
#if ENABLE_FEATURE_CP_LONG_OPTIONS
|
||||||
# if ENABLE_FEATURE_CP_REFLINK
|
# if ENABLE_FEATURE_CP_REFLINK
|
||||||
char *reflink = NULL;
|
char *reflink = NULL;
|
||||||
@ -94,7 +140,8 @@ int cp_main(int argc, char **argv)
|
|||||||
// -r and -R are the same
|
// -r and -R are the same
|
||||||
// -R (and therefore -r) turns on -d (coreutils does this)
|
// -R (and therefore -r) turns on -d (coreutils does this)
|
||||||
// -a = -pdR
|
// -a = -pdR
|
||||||
"-2:l--s:s--l:Pd:rRd:Rd:apdR",
|
/* At least one argument. (Usually two+, but -t DIR can have only one) */
|
||||||
|
"-1:l--s:s--l:Pd:rRd:Rd:apdR",
|
||||||
"archive\0" No_argument "a"
|
"archive\0" No_argument "a"
|
||||||
"force\0" No_argument "f"
|
"force\0" No_argument "f"
|
||||||
"interactive\0" No_argument "i"
|
"interactive\0" No_argument "i"
|
||||||
@ -110,6 +157,9 @@ int cp_main(int argc, char **argv)
|
|||||||
"parents\0" No_argument "\xfe"
|
"parents\0" No_argument "\xfe"
|
||||||
# if ENABLE_FEATURE_CP_REFLINK
|
# if ENABLE_FEATURE_CP_REFLINK
|
||||||
"reflink\0" Optional_argument "\xfd"
|
"reflink\0" Optional_argument "\xfd"
|
||||||
|
# endif
|
||||||
|
, &last
|
||||||
|
# if ENABLE_FEATURE_CP_REFLINK
|
||||||
, &reflink
|
, &reflink
|
||||||
# endif
|
# endif
|
||||||
);
|
);
|
||||||
@ -128,55 +178,10 @@ int cp_main(int argc, char **argv)
|
|||||||
flags = getopt32(argv, "^"
|
flags = getopt32(argv, "^"
|
||||||
FILEUTILS_CP_OPTSTR
|
FILEUTILS_CP_OPTSTR
|
||||||
"\0"
|
"\0"
|
||||||
"-2:l--s:s--l:Pd:rRd:Rd:apdR"
|
"-1:l--s:s--l:Pd:rRd:Rd:apdR"
|
||||||
|
, &last
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
/* Options of cp from GNU coreutils 6.10:
|
|
||||||
* -a, --archive
|
|
||||||
* -f, --force
|
|
||||||
* -i, --interactive
|
|
||||||
* -l, --link
|
|
||||||
* -L, --dereference
|
|
||||||
* -P, --no-dereference
|
|
||||||
* -R, -r, --recursive
|
|
||||||
* -s, --symbolic-link
|
|
||||||
* -v, --verbose
|
|
||||||
* -H follow command-line symbolic links in SOURCE
|
|
||||||
* -d same as --no-dereference --preserve=links
|
|
||||||
* -p same as --preserve=mode,ownership,timestamps
|
|
||||||
* -c same as --preserve=context
|
|
||||||
* -u, --update
|
|
||||||
* copy only when the SOURCE file is newer than the destination
|
|
||||||
* file or when the destination file is missing
|
|
||||||
* --remove-destination
|
|
||||||
* remove each existing destination file before attempting to open
|
|
||||||
* --parents
|
|
||||||
* use full source file name under DIRECTORY
|
|
||||||
* -T, --no-target-directory
|
|
||||||
* treat DEST as a normal file
|
|
||||||
* NOT SUPPORTED IN BBOX:
|
|
||||||
* --backup[=CONTROL]
|
|
||||||
* make a backup of each existing destination file
|
|
||||||
* -b like --backup but does not accept an argument
|
|
||||||
* --copy-contents
|
|
||||||
* copy contents of special files when recursive
|
|
||||||
* --preserve[=ATTR_LIST]
|
|
||||||
* preserve attributes (default: mode,ownership,timestamps),
|
|
||||||
* if possible additional attributes: security context,links,all
|
|
||||||
* --no-preserve=ATTR_LIST
|
|
||||||
* --sparse=WHEN
|
|
||||||
* control creation of sparse files
|
|
||||||
* --strip-trailing-slashes
|
|
||||||
* remove any trailing slashes from each SOURCE argument
|
|
||||||
* -S, --suffix=SUFFIX
|
|
||||||
* override the usual backup suffix
|
|
||||||
* -t, --target-directory=DIRECTORY
|
|
||||||
* copy all SOURCE arguments into DIRECTORY
|
|
||||||
* -x, --one-file-system
|
|
||||||
* stay on this file system
|
|
||||||
* -Z, --context=CONTEXT
|
|
||||||
* (SELinux) set SELinux security context of copy to CONTEXT
|
|
||||||
*/
|
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
/* Reverse this bit. If there is -d, bit is not set: */
|
/* Reverse this bit. If there is -d, bit is not set: */
|
||||||
@ -195,15 +200,22 @@ int cp_main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
status = EXIT_SUCCESS;
|
status = EXIT_SUCCESS;
|
||||||
last = argv[argc - 1];
|
if (!(flags & FILEUTILS_TARGET_DIR)) {
|
||||||
/* If there are only two arguments and... */
|
last = argv[argc - 1];
|
||||||
if (argc == 2) {
|
if (argc < 2)
|
||||||
|
bb_show_usage();
|
||||||
|
if (argc != 2) {
|
||||||
|
if (flags & FILEUTILS_NO_TARGET_DIR)
|
||||||
|
bb_show_usage();
|
||||||
|
/* "cp A B C... DIR" - target must be dir */
|
||||||
|
} else /* argc == 2 */ {
|
||||||
|
/* "cp A B" - only case where target can be not a dir */
|
||||||
s_flags = cp_mv_stat2(*argv, &source_stat,
|
s_flags = cp_mv_stat2(*argv, &source_stat,
|
||||||
(flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
|
(flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
|
||||||
if (s_flags < 0)
|
if (s_flags < 0) /* error other than ENOENT */
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
d_flags = cp_mv_stat(last, &dest_stat);
|
d_flags = cp_mv_stat(last, &dest_stat);
|
||||||
if (d_flags < 0)
|
if (d_flags < 0) /* error other than ENOENT */
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
if (flags & FILEUTILS_NO_TARGET_DIR) { /* -T */
|
if (flags & FILEUTILS_NO_TARGET_DIR) { /* -T */
|
||||||
@ -235,9 +247,9 @@ int cp_main(int argc, char **argv)
|
|||||||
dest = last;
|
dest = last;
|
||||||
goto DO_COPY; /* NB: argc==2 -> *++argv==last */
|
goto DO_COPY; /* NB: argc==2 -> *++argv==last */
|
||||||
}
|
}
|
||||||
} else if (flags & FILEUTILS_NO_TARGET_DIR) {
|
}
|
||||||
bb_simple_error_msg_and_die("too many arguments");
|
|
||||||
}
|
}
|
||||||
|
/* else: last is DIR from "t -DIR" */
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
#if ENABLE_FEATURE_CP_LONG_OPTIONS
|
#if ENABLE_FEATURE_CP_LONG_OPTIONS
|
||||||
|
@ -460,13 +460,18 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th
|
|||||||
FILEUTILS_VERBOSE = (1 << 12) * ENABLE_FEATURE_VERBOSE, /* -v */
|
FILEUTILS_VERBOSE = (1 << 12) * ENABLE_FEATURE_VERBOSE, /* -v */
|
||||||
FILEUTILS_UPDATE = 1 << 13, /* -u */
|
FILEUTILS_UPDATE = 1 << 13, /* -u */
|
||||||
FILEUTILS_NO_TARGET_DIR = 1 << 14, /* -T */
|
FILEUTILS_NO_TARGET_DIR = 1 << 14, /* -T */
|
||||||
|
FILEUTILS_TARGET_DIR = 1 << 15, /* -t DIR */
|
||||||
#if ENABLE_SELINUX
|
#if ENABLE_SELINUX
|
||||||
FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 15, /* -c */
|
FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 16, /* -c */
|
||||||
#endif
|
#endif
|
||||||
FILEUTILS_RMDEST = 1 << (16 - !ENABLE_SELINUX), /* --remove-destination */
|
#define FILEUTILS_CP_OPTSTR "pdRfilsLHarPvuTt:" IF_SELINUX("c")
|
||||||
/* bit 17 skipped for "cp --parents" */
|
/* How many bits in FILEUTILS_CP_OPTSTR? */
|
||||||
FILEUTILS_REFLINK = 1 << (18 - !ENABLE_SELINUX), /* cp --reflink=auto */
|
FILEUTILS_CP_OPTNUM = 17 - !ENABLE_SELINUX,
|
||||||
FILEUTILS_REFLINK_ALWAYS = 1 << (19 - !ENABLE_SELINUX), /* cp --reflink[=always] */
|
|
||||||
|
FILEUTILS_RMDEST = 1 << (17 - !ENABLE_SELINUX), /* --remove-destination */
|
||||||
|
/* bit 18 skipped for "cp --parents" */
|
||||||
|
FILEUTILS_REFLINK = 1 << (19 - !ENABLE_SELINUX), /* cp --reflink=auto */
|
||||||
|
FILEUTILS_REFLINK_ALWAYS = 1 << (20 - !ENABLE_SELINUX), /* cp --reflink[=always] */
|
||||||
/*
|
/*
|
||||||
* Hole. cp may have some bits set here,
|
* Hole. cp may have some bits set here,
|
||||||
* they should not affect remove_file()/copy_file()
|
* they should not affect remove_file()/copy_file()
|
||||||
@ -476,7 +481,7 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th
|
|||||||
#endif
|
#endif
|
||||||
FILEUTILS_IGNORE_CHMOD_ERR = 1 << 31,
|
FILEUTILS_IGNORE_CHMOD_ERR = 1 << 31,
|
||||||
};
|
};
|
||||||
#define FILEUTILS_CP_OPTSTR "pdRfilsLHarPvuT" IF_SELINUX("c")
|
|
||||||
extern int remove_file(const char *path, int flags) FAST_FUNC;
|
extern int remove_file(const char *path, int flags) FAST_FUNC;
|
||||||
/* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
|
/* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
|
||||||
* the source, not copy (unless "source" is a directory).
|
* the source, not copy (unless "source" is a directory).
|
||||||
|
Loading…
Reference in New Issue
Block a user