diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-28 17:49:31 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-28 17:49:31 +0000 |
commit | b9ad75fa602dd72b042b2ea08ce86da50746ab30 (patch) | |
tree | 19445163e0f30e8015eeafbcad091309407ab050 /libbb | |
parent | a38ba59cc3e78db0234cf4c224de6749d8ce759d (diff) | |
download | busybox-w32-b9ad75fa602dd72b042b2ea08ce86da50746ab30.tar.gz busybox-w32-b9ad75fa602dd72b042b2ea08ce86da50746ab30.tar.bz2 busybox-w32-b9ad75fa602dd72b042b2ea08ce86da50746ab30.zip |
copy_file: handle "cp /dev/foo file" (almost) compatibly to coreutils.
(almost because we do not copy mode, which is probably wasn't intended).
+61 bytes.
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/copy_file.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/libbb/copy_file.c b/libbb/copy_file.c index d37d51562..3b83e1216 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c | |||
@@ -81,6 +81,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
81 | signed char dest_exists = 0; | 81 | signed char dest_exists = 0; |
82 | signed char ovr; | 82 | signed char ovr; |
83 | 83 | ||
84 | /* Inverse of cp -d ("cp without -d") */ | ||
84 | #define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE) | 85 | #define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE) |
85 | 86 | ||
86 | if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { | 87 | if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { |
@@ -229,12 +230,22 @@ int copy_file(const char *source, const char *dest, int flags) | |||
229 | return 0; | 230 | return 0; |
230 | } | 231 | } |
231 | 232 | ||
232 | if (S_ISREG(source_stat.st_mode) | 233 | if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */ |
233 | /* DEREF uses stat, which never returns S_ISLNK() == true. */ | 234 | !(flags & FILEUTILS_RECUR) |
235 | /* "cp [-opts] regular_file thing2" */ | ||
236 | || S_ISREG(source_stat.st_mode) | ||
237 | /* DEREF uses stat, which never returns S_ISLNK() == true. | ||
238 | * So the below is never true: */ | ||
234 | /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ | 239 | /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */ |
235 | ) { | 240 | ) { |
236 | int src_fd; | 241 | int src_fd; |
237 | int dst_fd; | 242 | int dst_fd; |
243 | mode_t new_mode; | ||
244 | |||
245 | if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) { | ||
246 | /* "cp -d symlink dst": create a link */ | ||
247 | goto dont_cat; | ||
248 | } | ||
238 | 249 | ||
239 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { | 250 | if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) { |
240 | const char *link_target; | 251 | const char *link_target; |
@@ -258,18 +269,24 @@ int copy_file(const char *source, const char *dest, int flags) | |||
258 | if (src_fd < 0) | 269 | if (src_fd < 0) |
259 | return -1; | 270 | return -1; |
260 | 271 | ||
272 | /* Do not try to open with weird mode fields */ | ||
273 | new_mode = source_stat.st_mode; | ||
274 | if (!S_ISREG(source_stat.st_mode)) | ||
275 | new_mode = 0666; | ||
276 | |||
261 | /* POSIX way is a security problem versus symlink attacks, | 277 | /* POSIX way is a security problem versus symlink attacks, |
262 | * we do it only for non-symlinks, and only for non-recursive, | 278 | * we do it only for non-symlinks, and only for non-recursive, |
263 | * non-interactive cp. NB: it is still racy | 279 | * non-interactive cp. NB: it is still racy |
264 | * for "cp file /home/bad_user/file" case | 280 | * for "cp file /home/bad_user/file" case |
265 | * (user can rm file and create a link to /etc/passwd) */ | 281 | * (user can rm file and create a link to /etc/passwd) */ |
266 | if (DO_POSIX_CP | 282 | if (DO_POSIX_CP |
267 | || (dest_exists && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE)) | 283 | || (dest_exists |
284 | && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE)) | ||
268 | && !S_ISLNK(dest_stat.st_mode)) | 285 | && !S_ISLNK(dest_stat.st_mode)) |
269 | ) { | 286 | ) { |
270 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode); | 287 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); |
271 | } else /* safe way: */ | 288 | } else /* safe way: */ |
272 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); | 289 | dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); |
273 | if (dst_fd == -1) { | 290 | if (dst_fd == -1) { |
274 | ovr = ask_and_unlink(dest, flags); | 291 | ovr = ask_and_unlink(dest, flags); |
275 | if (ovr <= 0) { | 292 | if (ovr <= 0) { |
@@ -277,7 +294,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
277 | return ovr; | 294 | return ovr; |
278 | } | 295 | } |
279 | /* It shouldn't exist. If it exists, do not open (symlink attack?) */ | 296 | /* It shouldn't exist. If it exists, do not open (symlink attack?) */ |
280 | dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode); | 297 | dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); |
281 | if (dst_fd < 0) { | 298 | if (dst_fd < 0) { |
282 | close(src_fd); | 299 | close(src_fd); |
283 | return -1; | 300 | return -1; |
@@ -285,8 +302,7 @@ int copy_file(const char *source, const char *dest, int flags) | |||
285 | } | 302 | } |
286 | 303 | ||
287 | #if ENABLE_SELINUX | 304 | #if ENABLE_SELINUX |
288 | if (((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) | 305 | if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT)) |
289 | || (flags & FILEUTILS_SET_SECURITY_CONTEXT)) | ||
290 | && is_selinux_enabled() > 0 | 306 | && is_selinux_enabled() > 0 |
291 | ) { | 307 | ) { |
292 | security_context_t con; | 308 | security_context_t con; |
@@ -313,8 +329,13 @@ int copy_file(const char *source, const char *dest, int flags) | |||
313 | } | 329 | } |
314 | /* ...but read size is already checked by bb_copyfd_eof */ | 330 | /* ...but read size is already checked by bb_copyfd_eof */ |
315 | close(src_fd); | 331 | close(src_fd); |
332 | /* "cp /dev/something new_file" should not | ||
333 | * copy mode of /dev/something */ | ||
334 | if (!S_ISREG(source_stat.st_mode)) | ||
335 | return retval; | ||
316 | goto preserve_mode_ugid_time; | 336 | goto preserve_mode_ugid_time; |
317 | } | 337 | } |
338 | dont_cat: | ||
318 | 339 | ||
319 | /* Source is a symlink or a special file */ | 340 | /* Source is a symlink or a special file */ |
320 | /* We are lazy here, a bit lax with races... */ | 341 | /* We are lazy here, a bit lax with races... */ |