Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/archival/tar.c


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/archival/tar.c

    r2725 r3232  
    2424 */
    2525
     26/* TODO: security with -C DESTDIR option can be enhanced.
     27 * Consider tar file created via:
     28 * $ tar cvf bug.tar anything.txt
     29 * $ ln -s /tmp symlink
     30 * $ tar --append -f bug.tar symlink
     31 * $ rm symlink
     32 * $ mkdir symlink
     33 * $ tar --append -f bug.tar symlink/evil.py
     34 *
     35 * This will result in an archive which contains:
     36 * $ tar --list -f bug.tar
     37 * anything.txt
     38 * symlink
     39 * symlink/evil.py
     40 *
     41 * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given.
     42 * This doesn't feel right, and IIRC GNU tar doesn't do that.
     43 */
     44
    2645#include <fnmatch.h>
    2746#include "libbb.h"
    28 #include "archive.h"
     47#include "bb_archive.h"
    2948/* FIXME: Stop using this non-standard feature */
    3049#ifndef FNM_LEADING_DIR
     
    4261#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
    4362/* Do not pass gzip flag to writeTarFile() */
    44 #define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
    45     writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
     63#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
     64    writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
    4665#endif
    4766
     
    246265    PUT_OCTAL(header.gid, statbuf->st_gid);
    247266    memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
    248     PUT_OCTAL(header.mtime, statbuf->st_mtime);
     267    /* users report that files with negative st_mtime cause trouble, so: */
     268    PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
    249269
    250270    /* Enter the user and group names */
     
    298318        header.typeflag = FIFOTYPE;
    299319    } else if (S_ISREG(statbuf->st_mode)) {
    300         if (sizeof(statbuf->st_size) > 4
    301          && statbuf->st_size > (off_t)0777777777777LL
     320        /* header.size field is 12 bytes long */
     321        /* Does octal-encoded size fit? */
     322        uoff_t filesize = statbuf->st_size;
     323        if (sizeof(filesize) <= 4
     324         || filesize <= (uoff_t)0777777777777LL
    302325        ) {
     326            PUT_OCTAL(header.size, filesize);
     327        }
     328        /* Does base256-encoded size fit?
     329         * It always does unless off_t is wider than 64 bits.
     330         */
     331        else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     332#if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */
     333         && (filesize <= 0x3fffffffffffffffffffffffLL)
     334#endif
     335        ) {
     336            /* GNU tar uses "base-256 encoding" for very large numbers.
     337             * Encoding is binary, with highest bit always set as a marker
     338             * and sign in next-highest bit:
     339             * 80 00 .. 00 - zero
     340             * bf ff .. ff - largest positive number
     341             * ff ff .. ff - minus 1
     342             * c0 00 .. 00 - smallest negative number
     343             */
     344            char *p8 = header.size + sizeof(header.size);
     345            do {
     346                *--p8 = (uint8_t)filesize;
     347                filesize >>= 8;
     348            } while (p8 != header.size);
     349            *p8 |= 0x80;
     350        } else {
    303351            bb_error_msg_and_die("can't store file '%s' "
    304352                "of size %"OFF_FMT"u, aborting",
     
    306354        }
    307355        header.typeflag = REGTYPE;
    308         PUT_OCTAL(header.size, statbuf->st_size);
    309356    } else {
    310357        bb_error_msg("%s: unknown file type", fileName);
     
    379426    DBG("writeFileToTarball('%s')", fileName);
    380427
    381     /* Strip leading '/' (must be before memorizing hardlink's name) */
    382     header_name = fileName;
    383     while (header_name[0] == '/') {
    384         static smallint warned;
    385 
    386         if (!warned) {
    387             bb_error_msg("removing leading '/' from member names");
    388             warned = 1;
    389         }
    390         header_name++;
    391     }
     428    /* Strip leading '/' and such (must be before memorizing hardlink's name) */
     429    header_name = strip_unsafe_prefix(fileName);
    392430
    393431    if (header_name[0] == '\0')
     
    561599/* gcc 4.2.1 inlines it, making code bigger */
    562600static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
    563     int dereferenceFlag, const llist_t *include,
     601    int recurseFlags, const llist_t *include,
    564602    const llist_t *exclude, int gzip)
    565603{
     
    584622    /* Read the directory/files and iterate over them one at a time */
    585623    while (include) {
    586         if (!recursive_action(include->data, ACTION_RECURSE |
    587                 (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
     624        if (!recursive_action(include->data, recurseFlags,
    588625                writeFileToTarball, writeFileToTarball, &tbInfo, 0)
    589626        ) {
     
    625662#else
    626663int writeTarFile(int tar_fd, int verboseFlag,
    627     int dereferenceFlag, const llist_t *include,
     664    int recurseFlags, const llist_t *include,
    628665    const llist_t *exclude, int gzip);
    629666#endif /* FEATURE_TAR_CREATE */
     
    637674
    638675    while (list) {
    639         src_stream = xfopen_for_read(llist_pop(&list));
     676        src_stream = xfopen_stdin(llist_pop(&list));
    640677        while ((line = xmalloc_fgetline(src_stream)) != NULL) {
    641678            /* kill trailing '/' unless the string is just "/" */
     
    653690#endif
    654691
    655 #if ENABLE_FEATURE_SEAMLESS_Z
    656 static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
    657 {
    658     /* Can't lseek over pipes */
    659     archive_handle->seek = seek_by_read;
    660 
    661     /* do the decompression, and cleanup */
    662     if (xread_char(archive_handle->src_fd) != 0x1f
    663      || xread_char(archive_handle->src_fd) != 0x9d
    664     ) {
    665         bb_error_msg_and_die("invalid magic");
    666     }
    667 
    668     open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
    669     archive_handle->offset = 0;
    670     while (get_header_tar(archive_handle) == EXIT_SUCCESS)
    671         continue;
    672 
    673     /* Can only do one file at a time */
    674     return EXIT_FAILURE;
    675 }
    676 #else
    677 # define get_header_tar_Z NULL
    678 #endif
    679 
    680 #ifdef CHECK_FOR_CHILD_EXITCODE
    681 /* Looks like it isn't needed - tar detects malformed (truncated)
    682  * archive if e.g. bunzip2 fails */
    683 static int child_error;
    684 
    685 static void handle_SIGCHLD(int status)
    686 {
    687     /* Actually, 'status' is a signo. We reuse it for other needs */
    688 
    689     /* Wait for any child without blocking */
    690     if (wait_any_nohang(&status) < 0)
    691         /* wait failed?! I'm confused... */
    692         return;
    693 
    694     if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
    695         /* child exited with 0 */
    696         return;
    697     /* Cannot happen?
    698     if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
    699     child_error = 1;
    700 }
    701 #endif
    702 
    703692//usage:#define tar_trivial_usage
    704 //usage:       "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z")
    705 //usage:    IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a")
    706 //usage:    IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] "
    707 //usage:    IF_FEATURE_TAR_FROM("[-X FILE] ")
    708 //usage:       "[-f TARFILE] [-C DIR] [FILE]..."
     693//usage:    "-[" IF_FEATURE_TAR_CREATE("c") "xt"
     694//usage:    IF_FEATURE_SEAMLESS_Z("Z")
     695//usage:    IF_FEATURE_SEAMLESS_GZ("z")
     696//usage:    IF_FEATURE_SEAMLESS_XZ("J")
     697//usage:    IF_FEATURE_SEAMLESS_BZ2("j")
     698//usage:    IF_FEATURE_SEAMLESS_LZMA("a")
     699//usage:    IF_FEATURE_TAR_CREATE("h")
     700//usage:    IF_FEATURE_TAR_NOPRESERVE_TIME("m")
     701//usage:    "vO] "
     702//usage:    IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ")
     703//usage:    "[-f TARFILE] [-C DIR] [FILE]..."
    709704//usage:#define tar_full_usage "\n\n"
    710705//usage:    IF_FEATURE_TAR_CREATE("Create, extract, ")
     
    717712//usage:     "\n    x   Extract"
    718713//usage:     "\n    t   List"
    719 //usage:     "\nOptions:"
    720714//usage:     "\n    f   Name of TARFILE ('-' for stdin/out)"
    721715//usage:     "\n    C   Change to DIR before operation"
    722716//usage:     "\n    v   Verbose"
     717//usage:    IF_FEATURE_SEAMLESS_Z(
     718//usage:     "\n    Z   (De)compress using compress"
     719//usage:    )
    723720//usage:    IF_FEATURE_SEAMLESS_GZ(
    724721//usage:     "\n    z   (De)compress using gzip"
     722//usage:    )
     723//usage:    IF_FEATURE_SEAMLESS_XZ(
     724//usage:     "\n    J   (De)compress using xz"
    725725//usage:    )
    726726//usage:    IF_FEATURE_SEAMLESS_BZ2(
     
    729729//usage:    IF_FEATURE_SEAMLESS_LZMA(
    730730//usage:     "\n    a   (De)compress using lzma"
    731 //usage:    )
    732 //usage:    IF_FEATURE_SEAMLESS_Z(
    733 //usage:     "\n    Z   (De)compress using compress"
    734731//usage:    )
    735732//usage:     "\n    O   Extract to stdout"
     
    756753//  p   same-permissions
    757754//  k   keep-old
     755//  no-recursion
    758756//  numeric-owner
    759757//  no-same-permissions
     
    772770    IF_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
    773771    IF_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
    774     IF_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,) // 16th bit
     772    IF_FEATURE_SEAMLESS_XZ(  OPTBIT_XZ          ,) // 16th bit
     773    IF_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
    775774    IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
    776775#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     776    OPTBIT_NORECURSION,
    777777    IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND   ,)
    778778    OPTBIT_NUMERIC_OWNER,
     
    796796    OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
    797797    OPT_GZIP         = IF_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
     798    OPT_XZ           = IF_FEATURE_SEAMLESS_XZ(  (1 << OPTBIT_XZ          )) + 0, // J
    798799    OPT_COMPRESS     = IF_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
    799800    OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
     801    OPT_NORECURSION     = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION    )) + 0, // no-recursion
    800802    OPT_2COMMAND        = IF_FEATURE_TAR_TO_COMMAND(  (1 << OPTBIT_2COMMAND       )) + 0, // to-command
    801803    OPT_NUMERIC_OWNER   = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER  )) + 0, // numeric-owner
    802804    OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
    803805    OPT_OVERWRITE       = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE      )) + 0, // overwrite
     806
     807    OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
    804808};
    805809#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     
    834838    "gzip\0"                No_argument       "z"
    835839# endif
     840# if ENABLE_FEATURE_SEAMLESS_XZ
     841    "xz\0"                  No_argument       "J"
     842# endif
    836843# if ENABLE_FEATURE_SEAMLESS_Z
    837844    "compress\0"            No_argument       "Z"
     
    840847    "touch\0"               No_argument       "m"
    841848# endif
     849    "no-recursion\0"    No_argument       "\xfa"
    842850# if ENABLE_FEATURE_TAR_TO_COMMAND
    843851    "to-command\0"      Required_argument "\xfb"
     
    860868int tar_main(int argc UNUSED_PARAM, char **argv)
    861869{
    862     char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
    863870    archive_handle_t *tar_handle;
    864871    char *base_dir = NULL;
     
    883890    opt_complementary = "--:" // first arg is options
    884891        "tt:vv:" // count -t,-v
    885         "?:" // bail out with usage instead of error return
    886         "X::T::" // cumulative lists
     892        IF_FEATURE_TAR_FROM("X::T::") // cumulative lists
    887893#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
    888894        "\xff::" // cumulative lists for --exclude
     
    928934        IF_FEATURE_TAR_FROM(     "T:X:")
    929935        IF_FEATURE_SEAMLESS_GZ(  "z"   )
     936        IF_FEATURE_SEAMLESS_XZ(  "J"   )
    930937        IF_FEATURE_SEAMLESS_Z(   "Z"   )
    931938        IF_FEATURE_TAR_NOPRESERVE_TIME("m")
     
    957964        signal(SIGPIPE, SIG_IGN);
    958965        tar_handle->action_data = data_extract_to_command;
     966        IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());)
    959967    }
    960968
     
    975983        tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
    976984    }
    977 
    978     if (opt & OPT_GZIP)
    979         get_header_ptr = get_header_tar_gz;
    980 
    981     if (opt & OPT_BZIP2)
    982         get_header_ptr = get_header_tar_bz2;
    983 
    984     if (opt & OPT_LZMA)
    985         get_header_ptr = get_header_tar_lzma;
    986 
    987     if (opt & OPT_COMPRESS)
    988         get_header_ptr = get_header_tar_Z;
    989985
    990986    if (opt & OPT_NOPRESERVE_TIME)
     
    10401036            if (ENABLE_FEATURE_TAR_AUTODETECT
    10411037             && flags == O_RDONLY
    1042              && get_header_ptr == get_header_tar
     1038             && !(opt & OPT_ANY_COMPRESS)
    10431039            ) {
    10441040                tar_handle->src_fd = open_zipped(tar_filename);
     
    10541050        xchdir(base_dir);
    10551051
    1056 #ifdef CHECK_FOR_CHILD_EXITCODE
    1057     /* We need to know whether child (gzip/bzip/etc) exits abnormally */
    1058     signal(SIGCHLD, handle_SIGCHLD);
    1059 #endif
     1052    //if (SEAMLESS_COMPRESSION || OPT_COMPRESS)
     1053    //  /* We need to know whether child (gzip/bzip/etc) exits abnormally */
     1054    //  signal(SIGCHLD, check_errors_in_children);
    10601055
    10611056    /* Create an archive */
     
    10691064#endif
    10701065        /* NB: writeTarFile() closes tar_handle->src_fd */
    1071         return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
     1066        return writeTarFile(tar_handle->src_fd, verboseFlag,
     1067                (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
     1068                | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
    10721069                tar_handle->accept,
    10731070                tar_handle->reject, zipMode);
    10741071    }
    10751072
    1076     while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
     1073    if (opt & OPT_ANY_COMPRESS) {
     1074        USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
     1075        USE_FOR_NOMMU(const char *xformer_prog;)
     1076
     1077        if (opt & OPT_COMPRESS)
     1078            USE_FOR_MMU(xformer = unpack_Z_stream;)
     1079            USE_FOR_NOMMU(xformer_prog = "uncompress";)
     1080        if (opt & OPT_GZIP)
     1081            USE_FOR_MMU(xformer = unpack_gz_stream;)
     1082            USE_FOR_NOMMU(xformer_prog = "gunzip";)
     1083        if (opt & OPT_BZIP2)
     1084            USE_FOR_MMU(xformer = unpack_bz2_stream;)
     1085            USE_FOR_NOMMU(xformer_prog = "bunzip2";)
     1086        if (opt & OPT_LZMA)
     1087            USE_FOR_MMU(xformer = unpack_lzma_stream;)
     1088            USE_FOR_NOMMU(xformer_prog = "unlzma";)
     1089        if (opt & OPT_XZ)
     1090            USE_FOR_MMU(xformer = unpack_xz_stream;)
     1091            USE_FOR_NOMMU(xformer_prog = "unxz";)
     1092
     1093        open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
     1094        /* Can't lseek over pipes */
     1095        tar_handle->seek = seek_by_read;
     1096        /*tar_handle->offset = 0; - already is */
     1097    }
     1098
     1099    while (get_header_tar(tar_handle) == EXIT_SUCCESS)
    10771100        continue;
    10781101
     
    10901113        close(tar_handle->src_fd);
    10911114
     1115    if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
     1116        check_errors_in_children(0);
     1117        return bb_got_signal;
     1118    }
    10921119    return EXIT_SUCCESS;
    10931120}
Note: See TracChangeset for help on using the changeset viewer.