busybox/archival/tar.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Mini tar implementation for busybox
   4 *
   5 * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
   6 *  by Glenn McGrath
   7 *
   8 * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
   9 * ground up.  It still has remnants of the old code lying about, but it is
  10 * very different now (i.e., cleaner, less global variables, etc.)
  11 *
  12 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  13 *
  14 * Based in part in the tar implementation in sash
  15 *  Copyright (c) 1999 by David I. Bell
  16 *  Permission is granted to use, distribute, or modify this source,
  17 *  provided that this copyright notice remains intact.
  18 *  Permission to distribute sash derived code under GPL has been granted.
  19 *
  20 * Based in part on the tar implementation from busybox-0.28
  21 *  Copyright (C) 1995 Bruce Perens
  22 *
  23 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  24 */
  25/* TODO: security with -C DESTDIR option can be enhanced.
  26 * Consider tar file created via:
  27 * $ tar cvf bug.tar anything.txt
  28 * $ ln -s /tmp symlink
  29 * $ tar --append -f bug.tar symlink
  30 * $ rm symlink
  31 * $ mkdir symlink
  32 * $ tar --append -f bug.tar symlink/evil.py
  33 *
  34 * This will result in an archive which contains:
  35 * $ tar --list -f bug.tar
  36 * anything.txt
  37 * symlink
  38 * symlink/evil.py
  39 *
  40 * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given.
  41 * This doesn't feel right, and IIRC GNU tar doesn't do that.
  42 */
  43
  44//config:config TAR
  45//config:       bool "tar"
  46//config:       default y
  47//config:       help
  48//config:         tar is an archiving program. It's commonly used with gzip to
  49//config:         create compressed archives. It's probably the most widely used
  50//config:         UNIX archive program.
  51//config:
  52//config:config FEATURE_TAR_CREATE
  53//config:       bool "Enable archive creation"
  54//config:       default y
  55//config:       depends on TAR
  56//config:       help
  57//config:         If you enable this option you'll be able to create
  58//config:         tar archives using the `-c' option.
  59//config:
  60//config:config FEATURE_TAR_AUTODETECT
  61//config:       bool "Autodetect compressed tarballs"
  62//config:       default y
  63//config:       depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ)
  64//config:       help
  65//config:         With this option tar can automatically detect compressed
  66//config:         tarballs. Currently it works only on files (not pipes etc).
  67//config:
  68//config:config FEATURE_TAR_FROM
  69//config:       bool "Enable -X (exclude from) and -T (include from) options)"
  70//config:       default y
  71//config:       depends on TAR
  72//config:       help
  73//config:         If you enable this option you'll be able to specify
  74//config:         a list of files to include or exclude from an archive.
  75//config:
  76//config:config FEATURE_TAR_OLDGNU_COMPATIBILITY
  77//config:       bool "Support for old tar header format"
  78//config:       default y
  79//config:       depends on TAR || DPKG
  80//config:       help
  81//config:         This option is required to unpack archives created in
  82//config:         the old GNU format; help to kill this old format by
  83//config:         repacking your ancient archives with the new format.
  84//config:
  85//config:config FEATURE_TAR_OLDSUN_COMPATIBILITY
  86//config:       bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
  87//config:       default y
  88//config:       depends on TAR || DPKG
  89//config:       help
  90//config:         This option is required to unpack archives created by some old
  91//config:         version of Sun's tar (it was calculating checksum using signed
  92//config:         arithmetic). It is said to be fixed in newer Sun tar, but "old"
  93//config:         tarballs still exist.
  94//config:
  95//config:config FEATURE_TAR_GNU_EXTENSIONS
  96//config:       bool "Support for GNU tar extensions (long filenames)"
  97//config:       default y
  98//config:       depends on TAR || DPKG
  99//config:       help
 100//config:         With this option busybox supports GNU long filenames and
 101//config:         linknames.
 102//config:
 103//config:config FEATURE_TAR_LONG_OPTIONS
 104//config:       bool "Enable long options"
 105//config:       default y
 106//config:       depends on TAR && LONG_OPTS
 107//config:       help
 108//config:         Enable use of long options, increases size by about 400 Bytes
 109//config:
 110//config:config FEATURE_TAR_TO_COMMAND
 111//config:       bool "Support for writing to an external program"
 112//config:       default y
 113//config:       depends on TAR && FEATURE_TAR_LONG_OPTIONS
 114//config:       help
 115//config:         If you enable this option you'll be able to instruct tar to send
 116//config:         the contents of each extracted file to the standard input of an
 117//config:         external program.
 118//config:
 119//config:config FEATURE_TAR_UNAME_GNAME
 120//config:       bool "Enable use of user and group names"
 121//config:       default y
 122//config:       depends on TAR
 123//config:       help
 124//config:         Enables use of user and group names in tar. This affects contents
 125//config:         listings (-t) and preserving permissions when unpacking (-p).
 126//config:         +200 bytes.
 127//config:
 128//config:config FEATURE_TAR_NOPRESERVE_TIME
 129//config:       bool "Enable -m (do not preserve time) option"
 130//config:       default y
 131//config:       depends on TAR
 132//config:       help
 133//config:         With this option busybox supports GNU tar -m
 134//config:         (do not preserve time) option.
 135//config:
 136//config:config FEATURE_TAR_SELINUX
 137//config:       bool "Support for extracting SELinux labels"
 138//config:       default n
 139//config:       depends on TAR && SELINUX
 140//config:       help
 141//config:         With this option busybox supports restoring SELinux labels
 142//config:         when extracting files from tar archives.
 143
 144//applet:IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP))
 145//kbuild:lib-$(CONFIG_TAR) += tar.o
 146
 147#include <fnmatch.h>
 148#include "libbb.h"
 149#include "common_bufsiz.h"
 150#include "bb_archive.h"
 151/* FIXME: Stop using this non-standard feature */
 152#ifndef FNM_LEADING_DIR
 153# define FNM_LEADING_DIR 0
 154#endif
 155
 156#if 0
 157# define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
 158#else
 159# define DBG(...) ((void)0)
 160#endif
 161#define DBG_OPTION_PARSING 0
 162
 163
 164#define block_buf bb_common_bufsiz1
 165#define INIT_G() do { setup_common_bufsiz(); } while (0)
 166
 167
 168#if ENABLE_FEATURE_TAR_CREATE
 169
 170/*
 171** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
 172** the only functions that deal with the HardLinkInfo structure.
 173** Even these functions use the xxxHardLinkInfo() functions.
 174*/
 175typedef struct HardLinkInfo {
 176        struct HardLinkInfo *next; /* Next entry in list */
 177        dev_t dev;                 /* Device number */
 178        ino_t ino;                 /* Inode number */
 179//      short linkCount;           /* (Hard) Link Count */
 180        char name[1];              /* Start of filename (must be last) */
 181} HardLinkInfo;
 182
 183/* Some info to be carried along when creating a new tarball */
 184typedef struct TarBallInfo {
 185        int tarFd;                      /* Open-for-write file descriptor
 186                                         * for the tarball */
 187        int verboseFlag;                /* Whether to print extra stuff or not */
 188        const llist_t *excludeList;     /* List of files to not include */
 189        HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
 190        HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
 191//TODO: save only st_dev + st_ino
 192        struct stat tarFileStatBuf;     /* Stat info for the tarball, letting
 193                                         * us know the inode and device that the
 194                                         * tarball lives, so we can avoid trying
 195                                         * to include the tarball into itself */
 196} TarBallInfo;
 197
 198/* A nice enum with all the possible tar file content types */
 199enum {
 200        REGTYPE = '0',          /* regular file */
 201        REGTYPE0 = '\0',        /* regular file (ancient bug compat) */
 202        LNKTYPE = '1',          /* hard link */
 203        SYMTYPE = '2',          /* symbolic link */
 204        CHRTYPE = '3',          /* character special */
 205        BLKTYPE = '4',          /* block special */
 206        DIRTYPE = '5',          /* directory */
 207        FIFOTYPE = '6',         /* FIFO special */
 208        CONTTYPE = '7',         /* reserved */
 209        GNULONGLINK = 'K',      /* GNU long (>100 chars) link name */
 210        GNULONGNAME = 'L',      /* GNU long (>100 chars) file name */
 211};
 212
 213/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
 214static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
 215                                        struct stat *statbuf,
 216                                        const char *fileName)
 217{
 218        /* Note: hlInfoHeadPtr can never be NULL! */
 219        HardLinkInfo *hlInfo;
 220
 221        hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
 222        hlInfo->next = *hlInfoHeadPtr;
 223        *hlInfoHeadPtr = hlInfo;
 224        hlInfo->dev = statbuf->st_dev;
 225        hlInfo->ino = statbuf->st_ino;
 226//      hlInfo->linkCount = statbuf->st_nlink;
 227        strcpy(hlInfo->name, fileName);
 228}
 229
 230static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
 231{
 232        HardLinkInfo *hlInfo;
 233        HardLinkInfo *hlInfoNext;
 234
 235        if (hlInfoHeadPtr) {
 236                hlInfo = *hlInfoHeadPtr;
 237                while (hlInfo) {
 238                        hlInfoNext = hlInfo->next;
 239                        free(hlInfo);
 240                        hlInfo = hlInfoNext;
 241                }
 242                *hlInfoHeadPtr = NULL;
 243        }
 244}
 245
 246/* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */
 247static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
 248{
 249        while (hlInfo) {
 250                if (statbuf->st_ino == hlInfo->ino
 251                 && statbuf->st_dev == hlInfo->dev
 252                ) {
 253                        DBG("found hardlink:'%s'", hlInfo->name);
 254                        break;
 255                }
 256                hlInfo = hlInfo->next;
 257        }
 258        return hlInfo;
 259}
 260
 261/* Put an octal string into the specified buffer.
 262 * The number is zero padded and possibly null terminated.
 263 * Stores low-order bits only if whole value does not fit. */
 264static void putOctal(char *cp, int len, off_t value)
 265{
 266        char tempBuffer[sizeof(off_t)*3 + 1];
 267        char *tempString = tempBuffer;
 268        int width;
 269
 270        width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
 271        tempString += (width - len);
 272
 273        /* If string has leading zeroes, we can drop one */
 274        /* and field will have trailing '\0' */
 275        /* (increases chances of compat with other tars) */
 276        if (tempString[0] == '0')
 277                tempString++;
 278
 279        /* Copy the string to the field */
 280        memcpy(cp, tempString, len);
 281}
 282#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
 283
 284static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
 285{
 286        /* POSIX says that checksum is done on unsigned bytes
 287         * (Sun and HP-UX gets it wrong... more details in
 288         * GNU tar source) */
 289        const unsigned char *cp;
 290        int chksum, size;
 291
 292        strcpy(hp->magic, "ustar  ");
 293
 294        /* Calculate and store the checksum (i.e., the sum of all of the bytes of
 295         * the header).  The checksum field must be filled with blanks for the
 296         * calculation.  The checksum field is formatted differently from the
 297         * other fields: it has 6 digits, a null, then a space -- rather than
 298         * digits, followed by a null like the other fields... */
 299        memset(hp->chksum, ' ', sizeof(hp->chksum));
 300        cp = (const unsigned char *) hp;
 301        chksum = 0;
 302        size = sizeof(*hp);
 303        do { chksum += *cp++; } while (--size);
 304        putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
 305
 306        /* Now write the header out to disk */
 307        xwrite(fd, hp, sizeof(*hp));
 308}
 309
 310#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 311static void writeLongname(int fd, int type, const char *name, int dir)
 312{
 313        static const struct {
 314                char mode[8];             /* 100-107 */
 315                char uid[8];              /* 108-115 */
 316                char gid[8];              /* 116-123 */
 317                char size[12];            /* 124-135 */
 318                char mtime[12];           /* 136-147 */
 319        } prefilled = {
 320                "0000000",
 321                "0000000",
 322                "0000000",
 323                "00000000000",
 324                "00000000000",
 325        };
 326        struct tar_header_t header;
 327        int size;
 328
 329        dir = !!dir; /* normalize: 0/1 */
 330        size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
 331        /* + dir: account for possible '/' */
 332
 333        memset(&header, 0, sizeof(header));
 334        strcpy(header.name, "././@LongLink");
 335        memcpy(header.mode, prefilled.mode, sizeof(prefilled));
 336        PUT_OCTAL(header.size, size);
 337        header.typeflag = type;
 338        chksum_and_xwrite(fd, &header);
 339
 340        /* Write filename[/] and pad the block. */
 341        /* dir=0: writes 'name<NUL>', pads */
 342        /* dir=1: writes 'name', writes '/<NUL>', pads */
 343        dir *= 2;
 344        xwrite(fd, name, size - dir);
 345        xwrite(fd, "/", dir);
 346        size = (-size) & (TAR_BLOCK_SIZE-1);
 347        memset(&header, 0, size);
 348        xwrite(fd, &header, size);
 349}
 350#endif
 351
 352/* Write out a tar header for the specified file/directory/whatever */
 353static int writeTarHeader(struct TarBallInfo *tbInfo,
 354                const char *header_name, const char *fileName, struct stat *statbuf)
 355{
 356        struct tar_header_t header;
 357
 358        memset(&header, 0, sizeof(header));
 359
 360        strncpy(header.name, header_name, sizeof(header.name));
 361
 362        /* POSIX says to mask mode with 07777. */
 363        PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
 364        PUT_OCTAL(header.uid, statbuf->st_uid);
 365        PUT_OCTAL(header.gid, statbuf->st_gid);
 366        memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
 367        /* users report that files with negative st_mtime cause trouble, so: */
 368        PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0);
 369
 370        /* Enter the user and group names */
 371        safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
 372        safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
 373
 374        if (tbInfo->hlInfo) {
 375                /* This is a hard link */
 376                header.typeflag = LNKTYPE;
 377                strncpy(header.linkname, tbInfo->hlInfo->name,
 378                                sizeof(header.linkname));
 379#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 380                /* Write out long linkname if needed */
 381                if (header.linkname[sizeof(header.linkname)-1])
 382                        writeLongname(tbInfo->tarFd, GNULONGLINK,
 383                                        tbInfo->hlInfo->name, 0);
 384#endif
 385        } else if (S_ISLNK(statbuf->st_mode)) {
 386                char *lpath = xmalloc_readlink_or_warn(fileName);
 387                if (!lpath)
 388                        return FALSE;
 389                header.typeflag = SYMTYPE;
 390                strncpy(header.linkname, lpath, sizeof(header.linkname));
 391#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 392                /* Write out long linkname if needed */
 393                if (header.linkname[sizeof(header.linkname)-1])
 394                        writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
 395#else
 396                /* If it is larger than 100 bytes, bail out */
 397                if (header.linkname[sizeof(header.linkname)-1]) {
 398                        free(lpath);
 399                        bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
 400                        return FALSE;
 401                }
 402#endif
 403                free(lpath);
 404        } else if (S_ISDIR(statbuf->st_mode)) {
 405                header.typeflag = DIRTYPE;
 406                /* Append '/' only if there is a space for it */
 407                if (!header.name[sizeof(header.name)-1])
 408                        header.name[strlen(header.name)] = '/';
 409        } else if (S_ISCHR(statbuf->st_mode)) {
 410                header.typeflag = CHRTYPE;
 411                PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
 412                PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
 413        } else if (S_ISBLK(statbuf->st_mode)) {
 414                header.typeflag = BLKTYPE;
 415                PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
 416                PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
 417        } else if (S_ISFIFO(statbuf->st_mode)) {
 418                header.typeflag = FIFOTYPE;
 419        } else if (S_ISREG(statbuf->st_mode)) {
 420                /* header.size field is 12 bytes long */
 421                /* Does octal-encoded size fit? */
 422                uoff_t filesize = statbuf->st_size;
 423                if (sizeof(filesize) <= 4
 424                 || filesize <= (uoff_t)0777777777777LL
 425                ) {
 426                        PUT_OCTAL(header.size, filesize);
 427                }
 428                /* Does base256-encoded size fit?
 429                 * It always does unless off_t is wider than 64 bits.
 430                 */
 431                else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 432#if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */
 433                 && (filesize <= 0x3fffffffffffffffffffffffLL)
 434#endif
 435                ) {
 436                        /* GNU tar uses "base-256 encoding" for very large numbers.
 437                         * Encoding is binary, with highest bit always set as a marker
 438                         * and sign in next-highest bit:
 439                         * 80 00 .. 00 - zero
 440                         * bf ff .. ff - largest positive number
 441                         * ff ff .. ff - minus 1
 442                         * c0 00 .. 00 - smallest negative number
 443                         */
 444                        char *p8 = header.size + sizeof(header.size);
 445                        do {
 446                                *--p8 = (uint8_t)filesize;
 447                                filesize >>= 8;
 448                        } while (p8 != header.size);
 449                        *p8 |= 0x80;
 450                } else {
 451                        bb_error_msg_and_die("can't store file '%s' "
 452                                "of size %"OFF_FMT"u, aborting",
 453                                fileName, statbuf->st_size);
 454                }
 455                header.typeflag = REGTYPE;
 456        } else {
 457                bb_error_msg("%s: unknown file type", fileName);
 458                return FALSE;
 459        }
 460
 461#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 462        /* Write out long name if needed */
 463        /* (we, like GNU tar, output long linkname *before* long name) */
 464        if (header.name[sizeof(header.name)-1])
 465                writeLongname(tbInfo->tarFd, GNULONGNAME,
 466                                header_name, S_ISDIR(statbuf->st_mode));
 467#endif
 468
 469        /* Now write the header out to disk */
 470        chksum_and_xwrite(tbInfo->tarFd, &header);
 471
 472        /* Now do the verbose thing (or not) */
 473        if (tbInfo->verboseFlag) {
 474                FILE *vbFd = stdout;
 475
 476                /* If archive goes to stdout, verbose goes to stderr */
 477                if (tbInfo->tarFd == STDOUT_FILENO)
 478                        vbFd = stderr;
 479                /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
 480                /* We don't have such excesses here: for us "v" == "vv" */
 481                /* '/' is probably a GNUism */
 482                fprintf(vbFd, "%s%s\n", header_name,
 483                                S_ISDIR(statbuf->st_mode) ? "/" : "");
 484        }
 485
 486        return TRUE;
 487}
 488
 489#if ENABLE_FEATURE_TAR_FROM
 490static int exclude_file(const llist_t *excluded_files, const char *file)
 491{
 492        while (excluded_files) {
 493                if (excluded_files->data[0] == '/') {
 494                        if (fnmatch(excluded_files->data, file,
 495                                        FNM_PATHNAME | FNM_LEADING_DIR) == 0)
 496                                return 1;
 497                } else {
 498                        const char *p;
 499
 500                        for (p = file; p[0] != '\0'; p++) {
 501                                if ((p == file || p[-1] == '/')
 502                                 && p[0] != '/'
 503                                 && fnmatch(excluded_files->data, p,
 504                                                FNM_PATHNAME | FNM_LEADING_DIR) == 0
 505                                ) {
 506                                        return 1;
 507                                }
 508                        }
 509                }
 510                excluded_files = excluded_files->link;
 511        }
 512
 513        return 0;
 514}
 515#else
 516# define exclude_file(excluded_files, file) 0
 517#endif
 518
 519static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
 520                        void *userData, int depth UNUSED_PARAM)
 521{
 522        struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
 523        const char *header_name;
 524        int inputFileFd = -1;
 525
 526        DBG("writeFileToTarball('%s')", fileName);
 527
 528        /* Strip leading '/' and such (must be before memorizing hardlink's name) */
 529        header_name = strip_unsafe_prefix(fileName);
 530
 531        if (header_name[0] == '\0')
 532                return TRUE;
 533
 534        /* It is against the rules to archive a socket */
 535        if (S_ISSOCK(statbuf->st_mode)) {
 536                bb_error_msg("%s: socket ignored", fileName);
 537                return TRUE;
 538        }
 539
 540        /*
 541         * Check to see if we are dealing with a hard link.
 542         * If so -
 543         * Treat the first occurance of a given dev/inode as a file while
 544         * treating any additional occurances as hard links.  This is done
 545         * by adding the file information to the HardLinkInfo linked list.
 546         */
 547        tbInfo->hlInfo = NULL;
 548        if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
 549                DBG("'%s': st_nlink > 1", header_name);
 550                tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
 551                if (tbInfo->hlInfo == NULL) {
 552                        DBG("'%s': addHardLinkInfo", header_name);
 553                        addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
 554                }
 555        }
 556
 557        /* It is a bad idea to store the archive we are in the process of creating,
 558         * so check the device and inode to be sure that this particular file isn't
 559         * the new tarball */
 560        if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
 561         && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
 562        ) {
 563                bb_error_msg("%s: file is the archive; skipping", fileName);
 564                return TRUE;
 565        }
 566
 567        if (exclude_file(tbInfo->excludeList, header_name))
 568                return SKIP;
 569
 570#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 571        if (strlen(header_name) >= NAME_SIZE) {
 572                bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
 573                return TRUE;
 574        }
 575#endif
 576
 577        /* Is this a regular file? */
 578        if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
 579                /* open the file we want to archive, and make sure all is well */
 580                inputFileFd = open_or_warn(fileName, O_RDONLY);
 581                if (inputFileFd < 0) {
 582                        return FALSE;
 583                }
 584        }
 585
 586        /* Add an entry to the tarball */
 587        if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
 588                return FALSE;
 589        }
 590
 591        /* If it was a regular file, write out the body */
 592        if (inputFileFd >= 0) {
 593                size_t readSize;
 594                /* Write the file to the archive. */
 595                /* We record size into header first, */
 596                /* and then write out file. If file shrinks in between, */
 597                /* tar will be corrupted. So we don't allow for that. */
 598                /* NB: GNU tar 1.16 warns and pads with zeroes */
 599                /* or even seeks back and updates header */
 600                bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 601                ////off_t readSize;
 602                ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 603                ////if (readSize != statbuf->st_size && readSize >= 0) {
 604                ////    bb_error_msg_and_die("short read from %s, aborting", fileName);
 605                ////}
 606
 607                /* Check that file did not grow in between? */
 608                /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
 609
 610                close(inputFileFd);
 611
 612                /* Pad the file up to the tar block size */
 613                /* (a few tricks here in the name of code size) */
 614                readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
 615                memset(block_buf, 0, readSize);
 616                xwrite(tbInfo->tarFd, block_buf, readSize);
 617        }
 618
 619        return TRUE;
 620}
 621
 622#if SEAMLESS_COMPRESSION
 623/* Don't inline: vfork scares gcc and pessimizes code */
 624static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
 625{
 626        pid_t gzipPid;
 627
 628        // On Linux, vfork never unpauses parent early, although standard
 629        // allows for that. Do we want to waste bytes checking for it?
 630# define WAIT_FOR_CHILD 0
 631        volatile int vfork_exec_errno = 0;
 632        struct fd_pair gzipDataPipe;
 633# if WAIT_FOR_CHILD
 634        struct fd_pair gzipStatusPipe;
 635        xpiped_pair(gzipStatusPipe);
 636# endif
 637        xpiped_pair(gzipDataPipe);
 638
 639        signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
 640
 641        gzipPid = xvfork();
 642
 643        if (gzipPid == 0) {
 644                /* child */
 645                /* NB: close _first_, then move fds! */
 646                close(gzipDataPipe.wr);
 647# if WAIT_FOR_CHILD
 648                close(gzipStatusPipe.rd);
 649                /* gzipStatusPipe.wr will close only on exec -
 650                 * parent waits for this close to happen */
 651                fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
 652# endif
 653                xmove_fd(gzipDataPipe.rd, 0);
 654                xmove_fd(tar_fd, 1);
 655                /* exec gzip/bzip2 program/applet */
 656                BB_EXECLP(gzip, gzip, "-f", (char *)0);
 657                vfork_exec_errno = errno;
 658                _exit(EXIT_FAILURE);
 659        }
 660
 661        /* parent */
 662        xmove_fd(gzipDataPipe.wr, tar_fd);
 663        close(gzipDataPipe.rd);
 664# if WAIT_FOR_CHILD
 665        close(gzipStatusPipe.wr);
 666        while (1) {
 667                char buf;
 668                int n;
 669
 670                /* Wait until child execs (or fails to) */
 671                n = full_read(gzipStatusPipe.rd, &buf, 1);
 672                if (n < 0 /* && errno == EAGAIN */)
 673                        continue;       /* try it again */
 674        }
 675        close(gzipStatusPipe.rd);
 676# endif
 677        if (vfork_exec_errno) {
 678                errno = vfork_exec_errno;
 679                bb_perror_msg_and_die("can't execute '%s'", gzip);
 680        }
 681}
 682#endif /* SEAMLESS_COMPRESSION */
 683
 684
 685#if !SEAMLESS_COMPRESSION
 686/* Do not pass gzip flag to writeTarFile() */
 687#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \
 688        writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude)
 689#endif
 690/* gcc 4.2.1 inlines it, making code bigger */
 691static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
 692        int recurseFlags, const llist_t *include,
 693        const llist_t *exclude, const char *gzip)
 694{
 695        int errorFlag = FALSE;
 696        struct TarBallInfo tbInfo;
 697
 698        tbInfo.hlInfoHead = NULL;
 699        tbInfo.tarFd = tar_fd;
 700        tbInfo.verboseFlag = verboseFlag;
 701
 702        /* Store the stat info for the tarball's file, so
 703         * can avoid including the tarball into itself....  */
 704        xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
 705
 706#if SEAMLESS_COMPRESSION
 707        if (gzip)
 708                vfork_compressor(tbInfo.tarFd, gzip);
 709#endif
 710
 711        tbInfo.excludeList = exclude;
 712
 713        /* Read the directory/files and iterate over them one at a time */
 714        while (include) {
 715                if (!recursive_action(include->data, recurseFlags,
 716                                writeFileToTarball, writeFileToTarball, &tbInfo, 0)
 717                ) {
 718                        errorFlag = TRUE;
 719                }
 720                include = include->link;
 721        }
 722        /* Write two empty blocks to the end of the archive */
 723        memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
 724        xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
 725
 726        /* To be pedantically correct, we would check if the tarball
 727         * is smaller than 20 tar blocks, and pad it if it was smaller,
 728         * but that isn't necessary for GNU tar interoperability, and
 729         * so is considered a waste of space */
 730
 731        /* Close so the child process (if any) will exit */
 732        close(tbInfo.tarFd);
 733
 734        /* Hang up the tools, close up shop, head home */
 735        if (ENABLE_FEATURE_CLEAN_UP)
 736                freeHardLinkInfo(&tbInfo.hlInfoHead);
 737
 738        if (errorFlag)
 739                bb_error_msg("error exit delayed from previous errors");
 740
 741#if SEAMLESS_COMPRESSION
 742        if (gzip) {
 743                int status;
 744                if (safe_waitpid(-1, &status, 0) == -1)
 745                        bb_perror_msg("waitpid");
 746                else if (!WIFEXITED(status) || WEXITSTATUS(status))
 747                        /* gzip was killed or has exited with nonzero! */
 748                        errorFlag = TRUE;
 749        }
 750#endif
 751        return errorFlag;
 752}
 753#else /* !FEATURE_TAR_CREATE */
 754# define writeTarFile(...) 0
 755#endif
 756
 757#if ENABLE_FEATURE_TAR_FROM
 758static llist_t *append_file_list_to_list(llist_t *list)
 759{
 760        FILE *src_stream;
 761        char *line;
 762        llist_t *newlist = NULL;
 763
 764        while (list) {
 765                src_stream = xfopen_stdin(llist_pop(&list));
 766                while ((line = xmalloc_fgetline(src_stream)) != NULL) {
 767                        /* kill trailing '/' unless the string is just "/" */
 768                        char *cp = last_char_is(line, '/');
 769                        if (cp > line)
 770                                *cp = '\0';
 771                        llist_add_to_end(&newlist, line);
 772                }
 773                fclose(src_stream);
 774        }
 775        return newlist;
 776}
 777#endif
 778
 779//usage:#define tar_trivial_usage
 780//usage:        "-[" IF_FEATURE_TAR_CREATE("c") "xt"
 781//usage:        IF_FEATURE_SEAMLESS_Z("Z")
 782//usage:        IF_FEATURE_SEAMLESS_GZ("z")
 783//usage:        IF_FEATURE_SEAMLESS_XZ("J")
 784//usage:        IF_FEATURE_SEAMLESS_BZ2("j")
 785//usage:        IF_FEATURE_SEAMLESS_LZMA("a")
 786//usage:        IF_FEATURE_TAR_CREATE("h")
 787//usage:        IF_FEATURE_TAR_NOPRESERVE_TIME("m")
 788//usage:        "vO] "
 789//usage:        IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ")
 790//usage:        "[-f TARFILE] [-C DIR] [FILE]..."
 791//usage:#define tar_full_usage "\n\n"
 792//usage:        IF_FEATURE_TAR_CREATE("Create, extract, ")
 793//usage:        IF_NOT_FEATURE_TAR_CREATE("Extract ")
 794//usage:        "or list files from a tar file\n"
 795//usage:     "\nOperation:"
 796//usage:        IF_FEATURE_TAR_CREATE(
 797//usage:     "\n        c       Create"
 798//usage:        )
 799//usage:     "\n        x       Extract"
 800//usage:     "\n        t       List"
 801//usage:     "\n        f       Name of TARFILE ('-' for stdin/out)"
 802//usage:     "\n        C       Change to DIR before operation"
 803//usage:     "\n        v       Verbose"
 804//usage:        IF_FEATURE_SEAMLESS_Z(
 805//usage:     "\n        Z       (De)compress using compress"
 806//usage:        )
 807//usage:        IF_FEATURE_SEAMLESS_GZ(
 808//usage:     "\n        z       (De)compress using gzip"
 809//usage:        )
 810//usage:        IF_FEATURE_SEAMLESS_XZ(
 811//usage:     "\n        J       (De)compress using xz"
 812//usage:        )
 813//usage:        IF_FEATURE_SEAMLESS_BZ2(
 814//usage:     "\n        j       (De)compress using bzip2"
 815//usage:        )
 816//usage:        IF_FEATURE_SEAMLESS_LZMA(
 817//usage:     "\n        a       (De)compress using lzma"
 818//usage:        )
 819//usage:     "\n        O       Extract to stdout"
 820//usage:        IF_FEATURE_TAR_CREATE(
 821//usage:     "\n        h       Follow symlinks"
 822//usage:        )
 823//usage:        IF_FEATURE_TAR_NOPRESERVE_TIME(
 824//usage:     "\n        m       Don't restore mtime"
 825//usage:        )
 826//usage:        IF_FEATURE_TAR_FROM(
 827//usage:        IF_FEATURE_TAR_LONG_OPTIONS(
 828//usage:     "\n        exclude File to exclude"
 829//usage:        )
 830//usage:     "\n        X       File with names to exclude"
 831//usage:     "\n        T       File with names to include"
 832//usage:        )
 833//usage:
 834//usage:#define tar_example_usage
 835//usage:       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
 836//usage:       "$ tar -cf /tmp/tarball.tar /usr/local\n"
 837
 838// Supported but aren't in --help:
 839//      o       no-same-owner
 840//      p       same-permissions
 841//      k       keep-old
 842//      no-recursion
 843//      numeric-owner
 844//      no-same-permissions
 845//      overwrite
 846//IF_FEATURE_TAR_TO_COMMAND(
 847//      to-command
 848//)
 849
 850enum {
 851        OPTBIT_KEEP_OLD = 8,
 852        IF_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
 853        IF_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
 854        IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
 855        IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
 856        IF_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
 857        IF_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
 858        IF_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
 859        IF_FEATURE_SEAMLESS_XZ(  OPTBIT_XZ          ,) // 16th bit
 860        IF_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
 861        IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
 862#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 863        OPTBIT_STRIP_COMPONENTS,
 864        OPTBIT_NORECURSION,
 865        IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND   ,)
 866        OPTBIT_NUMERIC_OWNER,
 867        OPTBIT_NOPRESERVE_PERM,
 868        OPTBIT_OVERWRITE,
 869#endif
 870        OPT_TEST         = 1 << 0, // t
 871        OPT_EXTRACT      = 1 << 1, // x
 872        OPT_BASEDIR      = 1 << 2, // C
 873        OPT_TARNAME      = 1 << 3, // f
 874        OPT_2STDOUT      = 1 << 4, // O
 875        OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner
 876        OPT_P            = 1 << 6, // p
 877        OPT_VERBOSE      = 1 << 7, // v
 878        OPT_KEEP_OLD     = 1 << 8, // k
 879        OPT_CREATE       = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
 880        OPT_DEREFERENCE  = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
 881        OPT_BZIP2        = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
 882        OPT_LZMA         = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
 883        OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
 884        OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
 885        OPT_GZIP         = IF_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
 886        OPT_XZ           = IF_FEATURE_SEAMLESS_XZ(  (1 << OPTBIT_XZ          )) + 0, // J
 887        OPT_COMPRESS     = IF_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
 888        OPT_NOPRESERVE_TIME  = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
 889        OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0, // strip-components
 890        OPT_NORECURSION      = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION    )) + 0, // no-recursion
 891        OPT_2COMMAND         = IF_FEATURE_TAR_TO_COMMAND(  (1 << OPTBIT_2COMMAND       )) + 0, // to-command
 892        OPT_NUMERIC_OWNER    = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER  )) + 0, // numeric-owner
 893        OPT_NOPRESERVE_PERM  = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
 894        OPT_OVERWRITE        = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE      )) + 0, // overwrite
 895
 896        OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS),
 897};
 898#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 899static const char tar_longopts[] ALIGN1 =
 900        "list\0"                No_argument       "t"
 901        "extract\0"             No_argument       "x"
 902        "directory\0"           Required_argument "C"
 903        "file\0"                Required_argument "f"
 904        "to-stdout\0"           No_argument       "O"
 905        /* do not restore owner */
 906        /* Note: GNU tar handles 'o' as no-same-owner only on extract,
 907         * on create, 'o' is --old-archive. We do not support --old-archive. */
 908        "no-same-owner\0"       No_argument       "o"
 909        "same-permissions\0"    No_argument       "p"
 910        "verbose\0"             No_argument       "v"
 911        "keep-old\0"            No_argument       "k"
 912# if ENABLE_FEATURE_TAR_CREATE
 913        "create\0"              No_argument       "c"
 914        "dereference\0"         No_argument       "h"
 915# endif
 916# if ENABLE_FEATURE_SEAMLESS_BZ2
 917        "bzip2\0"               No_argument       "j"
 918# endif
 919# if ENABLE_FEATURE_SEAMLESS_LZMA
 920        "lzma\0"                No_argument       "a"
 921# endif
 922# if ENABLE_FEATURE_TAR_FROM
 923        "files-from\0"          Required_argument "T"
 924        "exclude-from\0"        Required_argument "X"
 925# endif
 926# if ENABLE_FEATURE_SEAMLESS_GZ
 927        "gzip\0"                No_argument       "z"
 928# endif
 929# if ENABLE_FEATURE_SEAMLESS_XZ
 930        "xz\0"                  No_argument       "J"
 931# endif
 932# if ENABLE_FEATURE_SEAMLESS_Z
 933        "compress\0"            No_argument       "Z"
 934# endif
 935# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
 936        "touch\0"               No_argument       "m"
 937# endif
 938        "strip-components\0"    Required_argument "\xf9"
 939        "no-recursion\0"        No_argument       "\xfa"
 940# if ENABLE_FEATURE_TAR_TO_COMMAND
 941        "to-command\0"          Required_argument "\xfb"
 942# endif
 943        /* use numeric uid/gid from tar header, not textual */
 944        "numeric-owner\0"       No_argument       "\xfc"
 945        /* do not restore mode */
 946        "no-same-permissions\0" No_argument       "\xfd"
 947        /* on unpack, open with O_TRUNC and !O_EXCL */
 948        "overwrite\0"           No_argument       "\xfe"
 949        /* --exclude takes next bit position in option mask, */
 950        /* therefore we have to put it _after_ --no-same-permissions */
 951# if ENABLE_FEATURE_TAR_FROM
 952        "exclude\0"             Required_argument "\xff"
 953# endif
 954        ;
 955#endif
 956
 957int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 958int tar_main(int argc UNUSED_PARAM, char **argv)
 959{
 960        archive_handle_t *tar_handle;
 961        char *base_dir = NULL;
 962        const char *tar_filename = "-";
 963        unsigned opt;
 964        int verboseFlag = 0;
 965#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 966        llist_t *excludes = NULL;
 967#endif
 968        INIT_G();
 969
 970        /* Initialise default values */
 971        tar_handle = init_handle();
 972        tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
 973                             | ARCHIVE_RESTORE_DATE
 974                             | ARCHIVE_UNLINK_OLD;
 975
 976        /* Apparently only root's tar preserves perms (see bug 3844) */
 977        if (getuid() != 0)
 978                tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
 979
 980        /* Prepend '-' to the first argument if required */
 981        opt_complementary = "--:" // first arg is options
 982                "tt:vv:" // count -t,-v
 983#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 984                "\xff::" // --exclude=PATTERN is a list
 985#endif
 986                IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
 987                IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
 988                IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive
 989#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 990                ":\xf9+" // --strip-components=NUM
 991#endif
 992        ;
 993#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 994        applet_long_options = tar_longopts;
 995#endif
 996#if ENABLE_DESKTOP
 997        /* Lie to buildroot when it starts asking stupid questions. */
 998        if (argv[1] && strcmp(argv[1], "--version") == 0) {
 999                // Output of 'tar --version' examples:
1000                // tar (GNU tar) 1.15.1
1001                // tar (GNU tar) 1.25
1002                // bsdtar 2.8.3 - libarchive 2.8.3
1003                puts("tar (busybox) " BB_VER);
1004                return 0;
1005        }
1006        if (argv[1] && argv[1][0] != '-') {
1007                /* Compat:
1008                 * 1st argument without dash handles options with parameters
1009                 * differently from dashed one: it takes *next argv[i]*
1010                 * as paramenter even if there are more chars in 1st argument:
1011                 *  "tar fx TARFILE" - "x" is not taken as f's param
1012                 *  but is interpreted as -x option
1013                 *  "tar -xf TARFILE" - dashed equivalent of the above
1014                 *  "tar -fx ..." - "x" is taken as f's param
1015                 * getopt32 wouldn't handle 1st command correctly.
1016                 * Unfortunately, people do use such commands.
1017                 * We massage argv[1] to work around it by moving 'f'
1018                 * to the end of the string.
1019                 * More contrived "tar fCx TARFILE DIR" still fails,
1020                 * but such commands are much less likely to be used.
1021                 */
1022                char *f = strchr(argv[1], 'f');
1023                if (f) {
1024                        while (f[1] != '\0') {
1025                                *f = f[1];
1026                                f++;
1027                        }
1028                        *f = 'f';
1029                }
1030        }
1031#endif
1032        opt = getopt32(argv,
1033                "txC:f:Oopvk"
1034                IF_FEATURE_TAR_CREATE(   "ch"    )
1035                IF_FEATURE_SEAMLESS_BZ2( "j"     )
1036                IF_FEATURE_SEAMLESS_LZMA("a"     )
1037                IF_FEATURE_TAR_FROM(     "T:*X:*")
1038                IF_FEATURE_SEAMLESS_GZ(  "z"     )
1039                IF_FEATURE_SEAMLESS_XZ(  "J"     )
1040                IF_FEATURE_SEAMLESS_Z(   "Z"     )
1041                IF_FEATURE_TAR_NOPRESERVE_TIME("m")
1042                IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components
1043                , &base_dir // -C dir
1044                , &tar_filename // -f filename
1045                IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
1046                IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
1047#if ENABLE_FEATURE_TAR_LONG_OPTIONS
1048                , &tar_handle->tar__strip_components // --strip-components
1049#endif
1050                IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command
1051#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
1052                , &excludes // --exclude
1053#endif
1054                , &verboseFlag // combined count for -t and -v
1055                , &verboseFlag // combined count for -t and -v
1056                );
1057#if DBG_OPTION_PARSING
1058        bb_error_msg("opt: 0x%08x", opt);
1059# define showopt(o) bb_error_msg("opt & %s(%x): %x", #o, o, opt & o);
1060        showopt(OPT_TEST            );
1061        showopt(OPT_EXTRACT         );
1062        showopt(OPT_BASEDIR         );
1063        showopt(OPT_TARNAME         );
1064        showopt(OPT_2STDOUT         );
1065        showopt(OPT_NOPRESERVE_OWNER);
1066        showopt(OPT_P               );
1067        showopt(OPT_VERBOSE         );
1068        showopt(OPT_KEEP_OLD        );
1069        showopt(OPT_CREATE          );
1070        showopt(OPT_DEREFERENCE     );
1071        showopt(OPT_BZIP2           );
1072        showopt(OPT_LZMA            );
1073        showopt(OPT_INCLUDE_FROM    );
1074        showopt(OPT_EXCLUDE_FROM    );
1075        showopt(OPT_GZIP            );
1076        showopt(OPT_XZ              );
1077        showopt(OPT_COMPRESS        );
1078        showopt(OPT_NOPRESERVE_TIME );
1079        showopt(OPT_STRIP_COMPONENTS);
1080        showopt(OPT_NORECURSION     );
1081        showopt(OPT_2COMMAND        );
1082        showopt(OPT_NUMERIC_OWNER   );
1083        showopt(OPT_NOPRESERVE_PERM );
1084        showopt(OPT_OVERWRITE       );
1085        showopt(OPT_ANY_COMPRESS    );
1086        bb_error_msg("base_dir:'%s'", base_dir);
1087        bb_error_msg("tar_filename:'%s'", tar_filename);
1088        bb_error_msg("verboseFlag:%d", verboseFlag);
1089        bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command);
1090        bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components);
1091        return 0;
1092# undef showopt
1093#endif
1094        argv += optind;
1095
1096        if (verboseFlag)
1097                tar_handle->action_header = header_verbose_list;
1098        if (verboseFlag == 1)
1099                tar_handle->action_header = header_list;
1100
1101        if (opt & OPT_EXTRACT)
1102                tar_handle->action_data = data_extract_all;
1103
1104        if (opt & OPT_2STDOUT)
1105                tar_handle->action_data = data_extract_to_stdout;
1106
1107        if (opt & OPT_2COMMAND) {
1108                putenv((char*)"TAR_FILETYPE=f");
1109                signal(SIGPIPE, SIG_IGN);
1110                tar_handle->action_data = data_extract_to_command;
1111                IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());)
1112        }
1113
1114        if (opt & OPT_KEEP_OLD)
1115                tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1116
1117        if (opt & OPT_NUMERIC_OWNER)
1118                tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
1119
1120        if (opt & OPT_NOPRESERVE_OWNER)
1121                tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
1122
1123        if (opt & OPT_NOPRESERVE_PERM)
1124                tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
1125
1126        if (opt & OPT_OVERWRITE) {
1127                tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
1128                tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
1129        }
1130
1131        if (opt & OPT_NOPRESERVE_TIME)
1132                tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
1133
1134#if ENABLE_FEATURE_TAR_FROM
1135        tar_handle->reject = append_file_list_to_list(tar_handle->reject);
1136# if ENABLE_FEATURE_TAR_LONG_OPTIONS
1137        /* Append excludes to reject */
1138        while (excludes) {
1139                llist_t *next = excludes->link;
1140                excludes->link = tar_handle->reject;
1141                tar_handle->reject = excludes;
1142                excludes = next;
1143        }
1144# endif
1145        tar_handle->accept = append_file_list_to_list(tar_handle->accept);
1146#endif
1147
1148        /* Setup an array of filenames to work with */
1149        /* TODO: This is the same as in ar, make a separate function? */
1150        while (*argv) {
1151                /* kill trailing '/' unless the string is just "/" */
1152                char *cp = last_char_is(*argv, '/');
1153                if (cp > *argv)
1154                        *cp = '\0';
1155                llist_add_to_end(&tar_handle->accept, *argv);
1156                argv++;
1157        }
1158
1159        if (tar_handle->accept || tar_handle->reject)
1160                tar_handle->filter = filter_accept_reject_list;
1161
1162        /* Open the tar file */
1163        {
1164                int tar_fd = STDIN_FILENO;
1165                int flags = O_RDONLY;
1166
1167                if (opt & OPT_CREATE) {
1168                        /* Make sure there is at least one file to tar up */
1169                        if (tar_handle->accept == NULL)
1170                                bb_error_msg_and_die("empty archive");
1171
1172                        tar_fd = STDOUT_FILENO;
1173                        /* Mimicking GNU tar 1.15.1: */
1174                        flags = O_WRONLY | O_CREAT | O_TRUNC;
1175                }
1176
1177                if (LONE_DASH(tar_filename)) {
1178                        tar_handle->src_fd = tar_fd;
1179                        tar_handle->seek = seek_by_read;
1180                } else {
1181                        if (ENABLE_FEATURE_TAR_AUTODETECT
1182                         && flags == O_RDONLY
1183                         && !(opt & OPT_ANY_COMPRESS)
1184                        ) {
1185                                tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0);
1186                                if (tar_handle->src_fd < 0)
1187                                        bb_perror_msg_and_die("can't open '%s'", tar_filename);
1188                        } else {
1189                                tar_handle->src_fd = xopen(tar_filename, flags);
1190                        }
1191                }
1192        }
1193
1194        if (base_dir)
1195                xchdir(base_dir);
1196
1197        //if (SEAMLESS_COMPRESSION)
1198        //      /* We need to know whether child (gzip/bzip/etc) exits abnormally */
1199        //      signal(SIGCHLD, check_errors_in_children);
1200
1201#if ENABLE_FEATURE_TAR_CREATE
1202        /* Create an archive */
1203        if (opt & OPT_CREATE) {
1204# if SEAMLESS_COMPRESSION
1205                const char *zipMode = NULL;
1206                if (opt & OPT_COMPRESS)
1207                        zipMode = "compress";
1208                if (opt & OPT_GZIP)
1209                        zipMode = "gzip";
1210                if (opt & OPT_BZIP2)
1211                        zipMode = "bzip2";
1212                if (opt & OPT_LZMA)
1213                        zipMode = "lzma";
1214                if (opt & OPT_XZ)
1215                        zipMode = "xz";
1216# endif
1217                /* NB: writeTarFile() closes tar_handle->src_fd */
1218                return writeTarFile(tar_handle->src_fd, verboseFlag,
1219                                (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0)
1220                                | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE),
1221                                tar_handle->accept,
1222                                tar_handle->reject, zipMode);
1223        }
1224#endif
1225
1226        if (opt & OPT_ANY_COMPRESS) {
1227                USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);)
1228                USE_FOR_NOMMU(const char *xformer_prog;)
1229
1230                if (opt & OPT_COMPRESS)
1231                        USE_FOR_MMU(xformer = unpack_Z_stream;)
1232                        USE_FOR_NOMMU(xformer_prog = "uncompress";)
1233                if (opt & OPT_GZIP)
1234                        USE_FOR_MMU(xformer = unpack_gz_stream;)
1235                        USE_FOR_NOMMU(xformer_prog = "gunzip";)
1236                if (opt & OPT_BZIP2)
1237                        USE_FOR_MMU(xformer = unpack_bz2_stream;)
1238                        USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1239                if (opt & OPT_LZMA)
1240                        USE_FOR_MMU(xformer = unpack_lzma_stream;)
1241                        USE_FOR_NOMMU(xformer_prog = "unlzma";)
1242                if (opt & OPT_XZ)
1243                        USE_FOR_MMU(xformer = unpack_xz_stream;)
1244                        USE_FOR_NOMMU(xformer_prog = "unxz";)
1245
1246                fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1247                /* Can't lseek over pipes */
1248                tar_handle->seek = seek_by_read;
1249                /*tar_handle->offset = 0; - already is */
1250        }
1251
1252        /* Zero processed headers (== empty file) is not a valid tarball.
1253         * We (ab)use bb_got_signal as exitcode here,
1254         * because check_errors_in_children() uses _it_ as error indicator.
1255         */
1256        bb_got_signal = EXIT_FAILURE;
1257
1258        while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1259                bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */
1260
1261        /* Check that every file that should have been extracted was */
1262        while (tar_handle->accept) {
1263                if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
1264                 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
1265                ) {
1266                        bb_error_msg_and_die("%s: not found in archive",
1267                                tar_handle->accept->data);
1268                }
1269                tar_handle->accept = tar_handle->accept->link;
1270        }
1271        if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
1272                close(tar_handle->src_fd);
1273
1274        if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
1275                /* Set bb_got_signal to 1 if a child died with !0 exitcode */
1276                check_errors_in_children(0);
1277        }
1278
1279        return bb_got_signal;
1280}
1281