Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/libbb/copy_file.c

    r1765 r2725  
    66 * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
    77 *
    8  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    9  *
     8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    109 */
    11 
    1210#include "libbb.h"
    1311
     12// FEATURE_NON_POSIX_CP:
     13//
    1414// POSIX: if exists and -i, ask (w/o -i assume yes).
    1515// Then open w/o EXCL (yes, not unlink!).
    1616// If open still fails and -f, try unlink, then try open again.
    1717// Result: a mess:
    18 // If dest is a softlink, we overwrite softlink's destination!
     18// If dest is a (sym)link, we overwrite link destination!
    1919// (or fail, if it points to dir/nonexistent location/etc).
    2020// This is strange, but POSIX-correct.
    2121// coreutils cp has --remove-destination to override this...
    22 //
    23 // NB: we have special code which still allows for "cp file /dev/node"
    24 // to work POSIX-ly (the only realistic case where it makes sense)
    25 
    26 #define DO_POSIX_CP 0  /* 1 - POSIX behavior, 0 - safe behavior */
    27 
    28 // errno must be set to relevant value ("why we cannot create dest?")
    29 // for POSIX mode to give reasonable error message
     22
     23/* Called if open of destination, link creation etc fails.
     24 * errno must be set to relevant value ("why we cannot create dest?")
     25 * to give reasonable error message */
    3026static int ask_and_unlink(const char *dest, int flags)
    3127{
    32 #if DO_POSIX_CP
     28    int e = errno;
     29
     30#if !ENABLE_FEATURE_NON_POSIX_CP
    3331    if (!(flags & (FILEUTILS_FORCE|FILEUTILS_INTERACTIVE))) {
    34         // Either it exists, or the *path* doesnt exist
    35         bb_perror_msg("cannot create '%s'", dest);
     32        /* Either it exists, or the *path* doesnt exist */
     33        bb_perror_msg("can't create '%s'", dest);
    3634        return -1;
    3735    }
    3836#endif
    39     // If !DO_POSIX_CP, act as if -f is always in effect - we don't want
    40     // "cannot create" msg, we want unlink to be done (silently unless -i).
    41 
    42     // TODO: maybe we should do it only if ctty is present?
     37    // else: act as if -f is always in effect.
     38    // We don't want "can't create" msg, we want unlink to be done
     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.
     43
     44    /* TODO: maybe we should do it only if ctty is present? */
    4345    if (flags & FILEUTILS_INTERACTIVE) {
    4446        // We would not do POSIX insanity. -i asks,
     
    4850        fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
    4951        if (!bb_ask_confirmation())
    50             return 0; // not allowed to overwrite
     52            return 0; /* not allowed to overwrite */
    5153    }
    5254    if (unlink(dest) < 0) {
    53         bb_perror_msg("cannot remove '%s'", dest);
    54         return -1; // error
    55     }
    56     return 1; // ok (to try again)
     55#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
     56        if (e == errno && e == ENOENT) {
     57            /* e == ENOTDIR is similar: path has non-dir component,
     58             * but in this case we don't even reach copy_file() */
     59            bb_error_msg("can't create '%s': Path does not exist", dest);
     60            return -1; /* error */
     61        }
     62#endif
     63        errno = e; /* do not use errno from unlink */
     64        bb_perror_msg("can't create '%s'", dest);
     65        return -1; /* error */
     66    }
     67    return 1; /* ok (to try again) */
    5768}
    5869
     
    6273 *    (failures to preserve mode/owner/times are not reported in exit code)
    6374 */
    64 int copy_file(const char *source, const char *dest, int flags)
     75int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
    6576{
    6677    /* This is a recursive function, try to minimize stack usage */
     
    7283    signed char ovr;
    7384
    74 #define FLAGS_DEREF (flags & FILEUTILS_DEREFERENCE)
     85/* Inverse of cp -d ("cp without -d") */
     86#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
    7587
    7688    if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
    77         // This may be a dangling symlink.
    78         // Making [sym]links to dangling symlinks works, so...
     89        /* This may be a dangling symlink.
     90         * Making [sym]links to dangling symlinks works, so... */
    7991        if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
    8092            goto make_links;
    81         bb_perror_msg("cannot stat '%s'", source);
     93        bb_perror_msg("can't stat '%s'", source);
    8294        return -1;
    8395    }
     
    8597    if (lstat(dest, &dest_stat) < 0) {
    8698        if (errno != ENOENT) {
    87             bb_perror_msg("cannot stat '%s'", dest);
     99            bb_perror_msg("can't stat '%s'", dest);
    88100            return -1;
    89101        }
     
    103115        if (lgetfilecon(source, &con) >= 0) {
    104116            if (setfscreatecon(con) < 0) {
    105                 bb_perror_msg("cannot set setfscreatecon %s", con);
     117                bb_perror_msg("can't set setfscreatecon %s", con);
    106118                freecon(con);
    107119                return -1;
     
    110122            setfscreatecon_or_die(NULL);
    111123        } else {
    112             bb_perror_msg("cannot lgetfilecon %s", source);
     124            bb_perror_msg("can't lgetfilecon %s", source);
    113125            return -1;
    114126        }
     
    155167            if (mkdir(dest, mode) < 0) {
    156168                umask(saved_umask);
    157                 bb_perror_msg("cannot create directory '%s'", dest);
     169                bb_perror_msg("can't create directory '%s'", dest);
    158170                return -1;
    159171            }
     
    161173            /* need stat info for add_to_ino_dev_hashtable */
    162174            if (lstat(dest, &dest_stat) < 0) {
    163                 bb_perror_msg("cannot stat '%s'", dest);
     175                bb_perror_msg("can't stat '%s'", dest);
    164176                return -1;
    165177            }
     
    183195                continue;
    184196            new_dest = concat_path_file(dest, d->d_name);
    185             if (copy_file(new_source, new_dest, flags) < 0)
     197            if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0)
    186198                retval = -1;
    187199            free(new_source);
     
    193205         && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
    194206        ) {
    195             bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
     207            bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
    196208            /* retval = -1; - WRONG! copy *WAS* made */
    197209        }
     
    202214        int (*lf)(const char *oldpath, const char *newpath);
    203215 make_links:
    204         // Hmm... maybe
    205         // if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
    206         // (but realpath returns NULL on dangling symlinks...)
     216        /* Hmm... maybe
     217         * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
     218         * (but realpath returns NULL on dangling symlinks...) */
    207219        lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
    208220        if (lf(source, dest) < 0) {
     
    211223                return ovr;
    212224            if (lf(source, dest) < 0) {
    213                 bb_perror_msg("cannot create link '%s'", dest);
     225                bb_perror_msg("can't create link '%s'", dest);
    214226                return -1;
    215227            }
    216228        }
    217229        /* _Not_ jumping to preserve_mode_ugid_time:
    218          * hard/softlinks don't have those */
     230         * (sym)links don't have those */
    219231        return 0;
    220232    }
    221233
    222     if (S_ISREG(source_stat.st_mode)
    223      /* DEREF uses stat, which never returns S_ISLNK() == true. */
     234    if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */
     235        !(flags & FILEUTILS_RECUR)
     236        /* "cp [-opts] regular_file thing2" */
     237     || S_ISREG(source_stat.st_mode)
     238     /* DEREF uses stat, which never returns S_ISLNK() == true.
     239      * So the below is never true: */
    224240     /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
    225241    ) {
    226242        int src_fd;
    227243        int dst_fd;
     244        mode_t new_mode;
     245
     246        if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) {
     247            /* "cp -d symlink dst": create a link */
     248            goto dont_cat;
     249        }
    228250
    229251        if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
     
    236258                        return ovr;
    237259                    if (link(link_target, dest) < 0) {
    238                         bb_perror_msg("cannot create link '%s'", dest);
     260                        bb_perror_msg("can't create link '%s'", dest);
    239261                        return -1;
    240262                    }
     
    249271            return -1;
    250272
    251         /* POSIX way is a security problem versus symlink attacks,
    252          * we do it only for non-symlinks, and only for non-recursive,
    253          * non-interactive cp. NB: it is still racy
    254          * for "cp file /home/bad_user/file" case
    255          * (user can rm file and create a link to /etc/passwd) */
    256         if (DO_POSIX_CP
    257          || (dest_exists && !(flags & (FILEUTILS_RECUR|FILEUTILS_INTERACTIVE))
    258              && !S_ISLNK(dest_stat.st_mode))
    259         ) {
    260             dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, source_stat.st_mode);
    261         } else  /* safe way: */
    262             dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode);
     273        /* Do not try to open with weird mode fields */
     274        new_mode = source_stat.st_mode;
     275        if (!S_ISREG(source_stat.st_mode))
     276            new_mode = 0666;
     277
     278        // POSIX way is a security problem versus (sym)link attacks
     279        if (!ENABLE_FEATURE_NON_POSIX_CP) {
     280            dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
     281        } else { /* safe way: */
     282            dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
     283        }
    263284        if (dst_fd == -1) {
    264285            ovr = ask_and_unlink(dest, flags);
     
    268289            }
    269290            /* It shouldn't exist. If it exists, do not open (symlink attack?) */
    270             dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, source_stat.st_mode);
     291            dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
    271292            if (dst_fd < 0) {
    272293                close(src_fd);
     
    276297
    277298#if ENABLE_SELINUX
    278         if (((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT)
    279             || (flags & FILEUTILS_SET_SECURITY_CONTEXT))
     299        if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT))
    280300         && is_selinux_enabled() > 0
    281301        ) {
     
    297317        if (bb_copyfd_eof(src_fd, dst_fd) == -1)
    298318            retval = -1;
    299         /* Ok, writing side I can understand... */
     319        /* Careful with writing... */
    300320        if (close(dst_fd) < 0) {
    301             bb_perror_msg("cannot close '%s'", dest);
     321            bb_perror_msg("error writing to '%s'", dest);
    302322            retval = -1;
    303323        }
    304324        /* ...but read size is already checked by bb_copyfd_eof */
    305325        close(src_fd);
     326        /* "cp /dev/something new_file" should not
     327         * copy mode of /dev/something */
     328        if (!S_ISREG(source_stat.st_mode))
     329            return retval;
    306330        goto preserve_mode_ugid_time;
    307331    }
     332 dont_cat:
    308333
    309334    /* Source is a symlink or a special file */
     
    321346            free(lpath);
    322347            if (r < 0) {
    323                 bb_perror_msg("cannot create symlink '%s'", dest);
     348                bb_perror_msg("can't create symlink '%s'", dest);
    324349                return -1;
    325350            }
    326351            if (flags & FILEUTILS_PRESERVE_STATUS)
    327352                if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
    328                     bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
     353                    bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
    329354        }
    330355        /* _Not_ jumping to preserve_mode_ugid_time:
     
    336361    ) {
    337362        if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
    338             bb_perror_msg("cannot create '%s'", dest);
     363            bb_perror_msg("can't create '%s'", dest);
    339364            return -1;
    340365        }
     
    350375    /* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
    351376    ) {
    352         struct utimbuf times;
    353 
    354         times.actime = source_stat.st_atime;
    355         times.modtime = source_stat.st_mtime;
     377        struct timeval times[2];
     378
     379        times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime;
     380        times[1].tv_usec = times[0].tv_usec = 0;
    356381        /* BTW, utimes sets usec-precision time - just FYI */
    357         if (utime(dest, &times) < 0)
    358             bb_perror_msg("cannot preserve %s of '%s'", "times", dest);
     382        if (utimes(dest, times) < 0)
     383            bb_perror_msg("can't preserve %s of '%s'", "times", dest);
    359384        if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
    360385            source_stat.st_mode &= ~(S_ISUID | S_ISGID);
    361             bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
     386            bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
    362387        }
    363388        if (chmod(dest, source_stat.st_mode) < 0)
    364             bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
     389            bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
    365390    }
    366391
Note: See TracChangeset for help on using the changeset viewer.