aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-07-05 13:24:17 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-07-05 13:24:17 +0200
commit6f58be07485fd2fbac1b828e5f2c631e7d5bc9e4 (patch)
treea364f5241ce39c3ddbb25d7dbc679639562a38ab
parent2d7b5bfa9bd0b8096bf1ec5069fb6638d538a028 (diff)
downloadbusybox-w32-6f58be07485fd2fbac1b828e5f2c631e7d5bc9e4.tar.gz
busybox-w32-6f58be07485fd2fbac1b828e5f2c631e7d5bc9e4.tar.bz2
busybox-w32-6f58be07485fd2fbac1b828e5f2c631e7d5bc9e4.zip
cp: make "non-POSIX" cp a bit more consistent
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--libbb/copy_file.c62
1 files changed, 28 insertions, 34 deletions
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 4d2f17aa5..ae70cbc0a 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -6,7 +6,6 @@
6 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp> 6 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
7 * 7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 *
10 */ 9 */
11#include "libbb.h" 10#include "libbb.h"
12 11
@@ -16,31 +15,33 @@
16// Then open w/o EXCL (yes, not unlink!). 15// Then open w/o EXCL (yes, not unlink!).
17// If open still fails and -f, try unlink, then try open again. 16// If open still fails and -f, try unlink, then try open again.
18// Result: a mess: 17// Result: a mess:
19// If dest is a softlink, we overwrite softlink's destination! 18// If dest is a (sym)link, we overwrite link destination!
20// (or fail, if it points to dir/nonexistent location/etc). 19// (or fail, if it points to dir/nonexistent location/etc).
21// This is strange, but POSIX-correct. 20// This is strange, but POSIX-correct.
22// coreutils cp has --remove-destination to override this... 21// coreutils cp has --remove-destination to override this...
23//
24// NB: we have special code which still allows for "cp file /dev/node"
25// to work POSIX-ly (the only realistic case where it makes sense)
26 22
27// errno must be set to relevant value ("why we cannot create dest?") 23/* Called if open of destination, link creation etc fails.
28// for POSIX mode to give reasonable error message 24 * errno must be set to relevant value ("why we cannot create dest?")
25 * to give reasonable error message */
29static int ask_and_unlink(const char *dest, int flags) 26static int ask_and_unlink(const char *dest, int flags)
30{ 27{
31 int e = errno; 28 int e = errno;
29
32#if !ENABLE_FEATURE_NON_POSIX_CP 30#if !ENABLE_FEATURE_NON_POSIX_CP
33 if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) { 31 if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
34 // Either it exists, or the *path* doesnt exist 32 /* Either it exists, or the *path* doesnt exist */
35 bb_perror_msg("cannot create '%s'", dest); 33 bb_perror_msg("cannot create '%s'", dest);
36 return -1; 34 return -1;
37 } 35 }
38#endif 36#endif
39 // If ENABLE_FEATURE_NON_POSIX_CP, act as if -f is always in effect 37 // else: act as if -f is always in effect.
40 // - we don't want "cannot create" msg, we want unlink to be done 38 // We don't want "cannot create" msg, we want unlink to be done
41 // (silently unless -i). 39 // (silently unless -i). Why? POSIX cp usually succeeds with
40 // O_TRUNC open of existing file, and user is left ignorantly happy.
41 // With above block unconditionally enabled, non-POSIX cp
42 // will complain a lot more than POSIX one.
42 43
43 // TODO: maybe we should do it only if ctty is present? 44 /* TODO: maybe we should do it only if ctty is present? */
44 if (flags & FILEUTILS_INTERACTIVE) { 45 if (flags & FILEUTILS_INTERACTIVE) {
45 // We would not do POSIX insanity. -i asks, 46 // We would not do POSIX insanity. -i asks,
46 // then _unlinks_ the offender. Presto. 47 // then _unlinks_ the offender. Presto.
@@ -48,7 +49,7 @@ static int ask_and_unlink(const char *dest, int flags)
48 // Or else we will end up having 3 open()s! 49 // Or else we will end up having 3 open()s!
49 fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest); 50 fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
50 if (!bb_ask_confirmation()) 51 if (!bb_ask_confirmation())
51 return 0; // not allowed to overwrite 52 return 0; /* not allowed to overwrite */
52 } 53 }
53 if (unlink(dest) < 0) { 54 if (unlink(dest) < 0) {
54#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE 55#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
@@ -56,14 +57,14 @@ static int ask_and_unlink(const char *dest, int flags)
56 /* e == ENOTDIR is similar: path has non-dir component, 57 /* e == ENOTDIR is similar: path has non-dir component,
57 * but in this case we don't even reach copy_file() */ 58 * but in this case we don't even reach copy_file() */
58 bb_error_msg("cannot create '%s': Path does not exist", dest); 59 bb_error_msg("cannot create '%s': Path does not exist", dest);
59 return -1; // error 60 return -1; /* error */
60 } 61 }
61#endif 62#endif
62 errno = e; 63 errno = e; /* do not use errno from unlink */
63 bb_perror_msg("cannot create '%s'", dest); 64 bb_perror_msg("cannot create '%s'", dest);
64 return -1; // error 65 return -1; /* error */
65 } 66 }
66 return 1; // ok (to try again) 67 return 1; /* ok (to try again) */
67} 68}
68 69
69/* Return: 70/* Return:
@@ -85,8 +86,8 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
85#define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE) 86#define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE)
86 87
87 if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) { 88 if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
88 // This may be a dangling symlink. 89 /* This may be a dangling symlink.
89 // Making [sym]links to dangling symlinks works, so... 90 * Making [sym]links to dangling symlinks works, so... */
90 if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) 91 if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
91 goto make_links; 92 goto make_links;
92 bb_perror_msg("cannot stat '%s'", source); 93 bb_perror_msg("cannot stat '%s'", source);
@@ -212,9 +213,9 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
212 if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) { 213 if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
213 int (*lf)(const char *oldpath, const char *newpath); 214 int (*lf)(const char *oldpath, const char *newpath);
214 make_links: 215 make_links:
215 // Hmm... maybe 216 /* Hmm... maybe
216 // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ? 217 * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
217 // (but realpath returns NULL on dangling symlinks...) 218 * (but realpath returns NULL on dangling symlinks...) */
218 lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link; 219 lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
219 if (lf(source, dest) < 0) { 220 if (lf(source, dest) < 0) {
220 ovr = ask_and_unlink(dest, flags); 221 ovr = ask_and_unlink(dest, flags);
@@ -226,7 +227,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
226 } 227 }
227 } 228 }
228 /* _Not_ jumping to preserve_mode_ugid_time: 229 /* _Not_ jumping to preserve_mode_ugid_time:
229 * hard/softlinks don't have those */ 230 * (sym)links don't have those */
230 return 0; 231 return 0;
231 } 232 }
232 233
@@ -274,19 +275,12 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
274 if (!S_ISREG(source_stat.st_mode)) 275 if (!S_ISREG(source_stat.st_mode))
275 new_mode = 0666; 276 new_mode = 0666;
276 277
277 /* POSIX way is a security problem versus symlink attacks, 278 // POSIX way is a security problem versus (sym)link attacks
278 * we do it only for non-symlinks, and only for non-recursive, 279 if (!ENABLE_FEATURE_NON_POSIX_CP) {
279 * non-interactive cp. NB: it is still racy
280 * for "cp file /home/bad_user/file" case
281 * (user can rm file and create a link to /etc/passwd) */
282 if (!ENABLE_FEATURE_NON_POSIX_CP
283 || (dest_exists
284 && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE))
285 && !S_ISLNK(dest_stat.st_mode))
286 ) {
287 dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode); 280 dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
288 } else /* safe way: */ 281 } else { /* safe way: */
289 dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode); 282 dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
283 }
290 if (dst_fd == -1) { 284 if (dst_fd == -1) {
291 ovr = ask_and_unlink(dest, flags); 285 ovr = ask_and_unlink(dest, flags);
292 if (ovr <= 0) { 286 if (ovr <= 0) {