1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "libbb.h"
19#include "libcoreutils/coreutils.h"
20
21
22
23int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
24int cp_main(int argc, char **argv)
25{
26 struct stat source_stat;
27 struct stat dest_stat;
28 const char *last;
29 const char *dest;
30 int s_flags;
31 int d_flags;
32 int flags;
33 int status;
34 enum {
35 OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
36 OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
37 OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
38 OPT_v = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
39#if ENABLE_FEATURE_CP_LONG_OPTIONS
40 OPT_parents = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+3),
41#endif
42 };
43
44
45
46
47
48
49
50 opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR";
51#if ENABLE_FEATURE_CP_LONG_OPTIONS
52 applet_long_options =
53 "archive\0" No_argument "a"
54 "force\0" No_argument "f"
55 "interactive\0" No_argument "i"
56 "link\0" No_argument "l"
57 "dereference\0" No_argument "L"
58 "no-dereference\0" No_argument "P"
59 "recursive\0" No_argument "R"
60 "symbolic-link\0" No_argument "s"
61 "verbose\0" No_argument "v"
62 "parents\0" No_argument "\xff"
63 ;
64#endif
65
66 flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPv");
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 argc -= optind;
114 argv += optind;
115
116 flags ^= FILEUTILS_DEREFERENCE;
117
118
119
120
121 if (flags & FILEUTILS_DEREF_SOFTLINK)
122 flags |= FILEUTILS_DEREFERENCE;
123
124#if ENABLE_SELINUX
125 if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) {
126 selinux_or_die();
127 }
128#endif
129
130 status = EXIT_SUCCESS;
131 last = argv[argc - 1];
132
133 if (argc == 2) {
134 s_flags = cp_mv_stat2(*argv, &source_stat,
135 (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
136 if (s_flags < 0)
137 return EXIT_FAILURE;
138 d_flags = cp_mv_stat(last, &dest_stat);
139 if (d_flags < 0)
140 return EXIT_FAILURE;
141
142#if ENABLE_FEATURE_CP_LONG_OPTIONS
143 if (flags & OPT_parents) {
144 if (!(d_flags & 2)) {
145 bb_error_msg_and_die("with --parents, the destination must be a directory");
146 }
147 }
148#endif
149
150
151 if (!((s_flags | d_flags) & 2)
152
153 || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
154 ) {
155
156 dest = last;
157 goto DO_COPY;
158 }
159 }
160
161 while (1) {
162#if ENABLE_FEATURE_CP_LONG_OPTIONS
163 if (flags & OPT_parents) {
164 char *dest_dup;
165 char *dest_dir;
166 dest = concat_path_file(last, *argv);
167 dest_dup = xstrdup(dest);
168 dest_dir = dirname(dest_dup);
169 if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) {
170 return EXIT_FAILURE;
171 }
172 free(dest_dup);
173 goto DO_COPY;
174 }
175#endif
176 dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
177 DO_COPY:
178 if (copy_file(*argv, dest, flags) < 0) {
179 status = EXIT_FAILURE;
180 }
181 if (*++argv == last) {
182
183 break;
184 }
185
186 free((void*)dest);
187 }
188
189
190 return status;
191}
192