diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-06-17 12:59:33 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-06-17 12:59:33 +0200 |
| commit | 91bc01c59b1be5c8a198f72078421e0b6e306a18 (patch) | |
| tree | b5138b9f47f34be25b8ab5d25b121016e50c53f4 /coreutils | |
| parent | 894466cc5182a022051868ede316f378071020cd (diff) | |
| download | busybox-w32-91bc01c59b1be5c8a198f72078421e0b6e306a18.tar.gz busybox-w32-91bc01c59b1be5c8a198f72078421e0b6e306a18.tar.bz2 busybox-w32-91bc01c59b1be5c8a198f72078421e0b6e306a18.zip | |
mv: implement -t and -T
function old new delta
mv_main 496 585 +89
.rodata 103188 103242 +54
packed_usage 33549 33590 +41
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 184/0) Total: 184 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'coreutils')
| -rw-r--r-- | coreutils/mv.c | 74 |
1 files changed, 50 insertions, 24 deletions
diff --git a/coreutils/mv.c b/coreutils/mv.c index f5ed9fcfc..eae2e99bb 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c | |||
| @@ -23,13 +23,15 @@ | |||
| 23 | //kbuild:lib-$(CONFIG_MV) += mv.o | 23 | //kbuild:lib-$(CONFIG_MV) += mv.o |
| 24 | 24 | ||
| 25 | //usage:#define mv_trivial_usage | 25 | //usage:#define mv_trivial_usage |
| 26 | //usage: "[-fin] SOURCE DEST\n" | 26 | //usage: "[-finT] SOURCE DEST\n" |
| 27 | //usage: "or: mv [-fin] SOURCE... DIRECTORY" | 27 | //usage: "or: mv [-fin] SOURCE... { -t DIRECTORY | DIRECTORY }" |
| 28 | //usage:#define mv_full_usage "\n\n" | 28 | //usage:#define mv_full_usage "\n\n" |
| 29 | //usage: "Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n" | 29 | //usage: "Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n" |
| 30 | //usage: "\n -f Don't prompt before overwriting" | 30 | //usage: "\n -f Don't prompt before overwriting" |
| 31 | //usage: "\n -i Interactive, prompt before overwrite" | 31 | //usage: "\n -i Interactive, prompt before overwrite" |
| 32 | //usage: "\n -n Don't overwrite an existing file" | 32 | //usage: "\n -n Don't overwrite an existing file" |
| 33 | //usage: "\n -T Refuse to move if DEST is a directory" | ||
| 34 | //usage: "\n -t DIR Move all SOURCEs into DIR" | ||
| 33 | //usage: | 35 | //usage: |
| 34 | //usage:#define mv_example_usage | 36 | //usage:#define mv_example_usage |
| 35 | //usage: "$ mv /tmp/foo /bin/bar\n" | 37 | //usage: "$ mv /tmp/foo /bin/bar\n" |
| @@ -40,7 +42,7 @@ | |||
| 40 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 42 | int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 41 | int mv_main(int argc, char **argv) | 43 | int mv_main(int argc, char **argv) |
| 42 | { | 44 | { |
| 43 | struct stat dest_stat; | 45 | struct stat statbuf; |
| 44 | const char *last; | 46 | const char *last; |
| 45 | const char *dest; | 47 | const char *dest; |
| 46 | unsigned flags; | 48 | unsigned flags; |
| @@ -51,41 +53,66 @@ int mv_main(int argc, char **argv) | |||
| 51 | #define OPT_FORCE (1 << 0) | 53 | #define OPT_FORCE (1 << 0) |
| 52 | #define OPT_INTERACTIVE (1 << 1) | 54 | #define OPT_INTERACTIVE (1 << 1) |
| 53 | #define OPT_NOCLOBBER (1 << 2) | 55 | #define OPT_NOCLOBBER (1 << 2) |
| 54 | #define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) | 56 | #define OPT_DESTNOTDIR (1 << 3) |
| 55 | /* Need at least two arguments. | 57 | #define OPT_DESTDIR (1 << 4) |
| 56 | * If more than one of -f, -i, -n is specified , only the final one | 58 | #define OPT_VERBOSE ((1 << 5) * ENABLE_FEATURE_VERBOSE) |
| 57 | * takes effect (it unsets previous options). | ||
| 58 | */ | ||
| 59 | flags = getopt32long(argv, "^" | 59 | flags = getopt32long(argv, "^" |
| 60 | "finv" | 60 | "finTt:v" |
| 61 | "\0" | 61 | "\0" |
| 62 | "-2:f-in:i-fn:n-fi", | 62 | /* At least one argument. (Usually two+, but -t DIR can have only one) */ |
| 63 | "-1" | ||
| 64 | /* only the final one of -f, -i, -n takes effect */ | ||
| 65 | ":f-in:i-fn:n-fi" | ||
| 66 | /* -t and -T don't mix */ | ||
| 67 | ":t--T:T--t", | ||
| 63 | "interactive\0" No_argument "i" | 68 | "interactive\0" No_argument "i" |
| 64 | "force\0" No_argument "f" | 69 | "force\0" No_argument "f" |
| 65 | "no-clobber\0" No_argument "n" | 70 | "no-clobber\0" No_argument "n" |
| 71 | "no-target-directory\0" No_argument "T" | ||
| 72 | "target-directory\0" Required_argument "t" | ||
| 66 | IF_FEATURE_VERBOSE( | 73 | IF_FEATURE_VERBOSE( |
| 67 | "verbose\0" No_argument "v" | 74 | "verbose\0" No_argument "v", |
| 75 | &last | ||
| 68 | ) | 76 | ) |
| 69 | ); | 77 | ); |
| 70 | argc -= optind; | 78 | argc -= optind; |
| 71 | argv += optind; | 79 | argv += optind; |
| 72 | last = argv[argc - 1]; | ||
| 73 | 80 | ||
| 74 | if (argc == 2) { | 81 | if (!(flags & OPT_DESTDIR)) { |
| 75 | dest_exists = cp_mv_stat(last, &dest_stat); | 82 | last = argv[argc - 1]; |
| 76 | if (dest_exists < 0) { | 83 | if (argc < 2) |
| 77 | return EXIT_FAILURE; | 84 | bb_show_usage(); |
| 78 | } | 85 | if (argc != 2) { |
| 79 | 86 | if (flags & OPT_DESTNOTDIR) | |
| 80 | if (!(dest_exists & 2)) { /* last is not a directory */ | 87 | bb_show_usage(); |
| 81 | dest = last; | 88 | /* "mv A B C... DIR" - target must be dir */ |
| 82 | goto DO_MOVE; | 89 | } else /* argc == 2 */ { |
| 90 | /* "mv A B" - only case where target can be not a dir */ | ||
| 91 | dest_exists = cp_mv_stat(last, &statbuf); | ||
| 92 | if (dest_exists < 0) { /* error other than ENOENT */ | ||
| 93 | return EXIT_FAILURE; | ||
| 94 | } | ||
| 95 | if (!(dest_exists & 2)) { | ||
| 96 | /* last is not a directory */ | ||
| 97 | dest = last; | ||
| 98 | goto DO_MOVE; | ||
| 99 | } | ||
| 100 | /* last is a directory */ | ||
| 101 | if (flags & OPT_DESTNOTDIR) { | ||
| 102 | if (stat(argv[0], &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) | ||
| 103 | bb_error_msg_and_die("'%s' is a directory", last); | ||
| 104 | /* "mv -T DIR1 DIR2" is allowed (renames a dir) */ | ||
| 105 | dest = last; | ||
| 106 | goto DO_MOVE; | ||
| 107 | } | ||
| 108 | /* else: fall through into "do { move SRC to DIR/SRC } while" loop */ | ||
| 83 | } | 109 | } |
| 84 | } | 110 | } |
| 111 | /* else: last is DIR from "t -DIR" */ | ||
| 85 | 112 | ||
| 86 | do { | 113 | do { |
| 87 | dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); | 114 | dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); |
| 88 | dest_exists = cp_mv_stat(dest, &dest_stat); | 115 | dest_exists = cp_mv_stat(dest, &statbuf); |
| 89 | if (dest_exists < 0) { | 116 | if (dest_exists < 0) { |
| 90 | goto RET_1; | 117 | goto RET_1; |
| 91 | } | 118 | } |
| @@ -108,11 +135,10 @@ int mv_main(int argc, char **argv) | |||
| 108 | } | 135 | } |
| 109 | 136 | ||
| 110 | if (rename(*argv, dest) < 0) { | 137 | if (rename(*argv, dest) < 0) { |
| 111 | struct stat source_stat; | ||
| 112 | int source_exists; | 138 | int source_exists; |
| 113 | 139 | ||
| 114 | if (errno != EXDEV | 140 | if (errno != EXDEV |
| 115 | || (source_exists = cp_mv_stat2(*argv, &source_stat, lstat)) < 1 | 141 | || (source_exists = cp_mv_stat2(*argv, &statbuf, lstat)) < 1 |
| 116 | ) { | 142 | ) { |
| 117 | bb_perror_msg("can't rename '%s'", *argv); | 143 | bb_perror_msg("can't rename '%s'", *argv); |
| 118 | } else { | 144 | } else { |
