aboutsummaryrefslogtreecommitdiff
path: root/coreutils/cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/cp.c')
-rw-r--r--coreutils/cp.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 71a29396f..2c0b90bc9 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -20,7 +20,6 @@
20 20
21/* This is a NOEXEC applet. Be very careful! */ 21/* This is a NOEXEC applet. Be very careful! */
22 22
23
24int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 23int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
25int cp_main(int argc, char **argv) 24int cp_main(int argc, char **argv)
26{ 25{
@@ -31,12 +30,16 @@ int cp_main(int argc, char **argv)
31 int s_flags; 30 int s_flags;
32 int d_flags; 31 int d_flags;
33 int flags; 32 int flags;
34 int status = 0; 33 int status;
35 enum { 34 enum {
36 OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1), 35 OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
37 OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)), 36 OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
38 OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1), 37 OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
39 OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2), 38 OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
39 OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3),
40#if ENABLE_FEATURE_CP_LONG_OPTIONS
41 OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+4),
42#endif
40 }; 43 };
41 44
42 // Need at least two arguments 45 // Need at least two arguments
@@ -46,6 +49,20 @@ int cp_main(int argc, char **argv)
46 // -R (and therefore -r) turns on -d (coreutils does this) 49 // -R (and therefore -r) turns on -d (coreutils does this)
47 // -a = -pdR 50 // -a = -pdR
48 opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL"; 51 opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL";
52#if ENABLE_FEATURE_CP_LONG_OPTIONS
53 applet_long_options =
54 "archive\0" No_argument "a"
55 "force\0" No_argument "f"
56 "interactive\0" No_argument "i"
57 "link\0" No_argument "l"
58 "dereference\0" No_argument "L"
59 "no-dereference\0" No_argument "P"
60 "recursive\0" No_argument "R"
61 "symbolic-link\0" No_argument "s"
62 "verbose\0" No_argument "v"
63 "parents\0" No_argument "\xff"
64 ;
65#endif
49 // -v (--verbose) is ignored 66 // -v (--verbose) is ignored
50 flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHv"); 67 flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHv");
51 /* Options of cp from GNU coreutils 6.10: 68 /* Options of cp from GNU coreutils 6.10:
@@ -62,8 +79,9 @@ int cp_main(int argc, char **argv)
62 * -d same as --no-dereference --preserve=links 79 * -d same as --no-dereference --preserve=links
63 * -p same as --preserve=mode,ownership,timestamps 80 * -p same as --preserve=mode,ownership,timestamps
64 * -c same as --preserve=context 81 * -c same as --preserve=context
82 * --parents
83 * use full source file name under DIRECTORY
65 * NOT SUPPORTED IN BBOX: 84 * NOT SUPPORTED IN BBOX:
66 * long options are not supported (even those above).
67 * --backup[=CONTROL] 85 * --backup[=CONTROL]
68 * make a backup of each existing destination file 86 * make a backup of each existing destination file
69 * -b like --backup but does not accept an argument 87 * -b like --backup but does not accept an argument
@@ -73,8 +91,6 @@ int cp_main(int argc, char **argv)
73 * preserve attributes (default: mode,ownership,timestamps), 91 * preserve attributes (default: mode,ownership,timestamps),
74 * if possible additional attributes: security context,links,all 92 * if possible additional attributes: security context,links,all
75 * --no-preserve=ATTR_LIST 93 * --no-preserve=ATTR_LIST
76 * --parents
77 * use full source file name under DIRECTORY
78 * --remove-destination 94 * --remove-destination
79 * remove each existing destination file before attempting to open 95 * remove each existing destination file before attempting to open
80 * --sparse=WHEN 96 * --sparse=WHEN
@@ -115,39 +131,61 @@ int cp_main(int argc, char **argv)
115 } 131 }
116#endif 132#endif
117 133
134 status = EXIT_SUCCESS;
118 last = argv[argc - 1]; 135 last = argv[argc - 1];
119 /* If there are only two arguments and... */ 136 /* If there are only two arguments and... */
120 if (argc == 2) { 137 if (argc == 2) {
121 s_flags = cp_mv_stat2(*argv, &source_stat, 138 s_flags = cp_mv_stat2(*argv, &source_stat,
122 (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); 139 (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
123 if (s_flags < 0) 140 if (s_flags < 0)
124 return EXIT_FAILURE; 141 return EXIT_FAILURE;
125 d_flags = cp_mv_stat(last, &dest_stat); 142 d_flags = cp_mv_stat(last, &dest_stat);
126 if (d_flags < 0) 143 if (d_flags < 0)
127 return EXIT_FAILURE; 144 return EXIT_FAILURE;
128 145
129 /* ...if neither is a directory or... */ 146#if ENABLE_FEATURE_CP_LONG_OPTIONS
130 if ( !((s_flags | d_flags) & 2) || 147 if (flags & OPT_parents) {
131 /* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */ 148 if (!(d_flags & 2)) {
132 ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) 149 bb_error_msg_and_die("with --parents, the destination must be a directory");
150 }
151 }
152#endif
153
154 /* ...if neither is a directory... */
155 if (!((s_flags | d_flags) & 2)
156 /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */
157 || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
133 ) { 158 ) {
134 /* ...do a simple copy. */ 159 /* Do a simple copy */
135 dest = last; 160 dest = last;
136 goto DO_COPY; /* NB: argc==2 -> *++argv==last */ 161 goto DO_COPY; /* NB: argc==2 -> *++argv==last */
137 } 162 }
138 } 163 }
139 164
140 while (1) { 165 while (1) {
166#if ENABLE_FEATURE_CP_LONG_OPTIONS
167 if (flags & OPT_parents) {
168 char *dest_dup;
169 char *dest_dir;
170 dest = concat_path_file(last, *argv);
171 dest_dup = xstrdup(dest);
172 dest_dir = dirname(dest_dup);
173 if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) {
174 return EXIT_FAILURE;
175 }
176 free(dest_dup);
177 goto DO_COPY;
178 }
179#endif
141 dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); 180 dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
142 DO_COPY: 181 DO_COPY:
143 if (copy_file(*argv, dest, flags) < 0) { 182 if (copy_file(*argv, dest, flags) < 0) {
144 status = 1; 183 status = EXIT_FAILURE;
145 } 184 }
185 free((void*)dest);
146 if (*++argv == last) { 186 if (*++argv == last) {
147 /* possibly leaking dest... */
148 break; 187 break;
149 } 188 }
150 free((void*)dest);
151 } 189 }
152 190
153 /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */ 191 /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */