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 the 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 tarball for details.
  24 */
  25
  26#include <fnmatch.h>
  27#include "libbb.h"
  28#include "unarchive.h"
  29
  30/* FIXME: Stop using this non-standard feature */
  31#ifndef FNM_LEADING_DIR
  32#define FNM_LEADING_DIR 0
  33#endif
  34
  35
  36#define block_buf bb_common_bufsiz1
  37
  38
  39#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
  40/* Do not pass gzip flag to writeTarFile() */
  41#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
  42        writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
  43#endif
  44
  45
  46#if ENABLE_FEATURE_TAR_CREATE
  47
  48/* Tar file constants  */
  49
  50#define TAR_BLOCK_SIZE          512
  51
  52/* POSIX tar Header Block, from POSIX 1003.1-1990  */
  53#define NAME_SIZE      100
  54#define NAME_SIZE_STR "100"
  55typedef struct TarHeader TarHeader;
  56struct TarHeader {                /* byte offset */
  57        char name[NAME_SIZE];     /*   0-99 */
  58        char mode[8];             /* 100-107 */
  59        char uid[8];              /* 108-115 */
  60        char gid[8];              /* 116-123 */
  61        char size[12];            /* 124-135 */
  62        char mtime[12];           /* 136-147 */
  63        char chksum[8];           /* 148-155 */
  64        char typeflag;            /* 156-156 */
  65        char linkname[NAME_SIZE]; /* 157-256 */
  66        /* POSIX:   "ustar" NUL "00" */
  67        /* GNU tar: "ustar  " NUL */
  68        /* Normally it's defined as magic[6] followed by
  69         * version[2], but we put them together to save code.
  70         */
  71        char magic[8];            /* 257-264 */
  72        char uname[32];           /* 265-296 */
  73        char gname[32];           /* 297-328 */
  74        char devmajor[8];         /* 329-336 */
  75        char devminor[8];         /* 337-344 */
  76        char prefix[155];         /* 345-499 */
  77        char padding[12];         /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */
  78};
  79
  80/*
  81** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
  82** the only functions that deal with the HardLinkInfo structure.
  83** Even these functions use the xxxHardLinkInfo() functions.
  84*/
  85typedef struct HardLinkInfo HardLinkInfo;
  86struct HardLinkInfo {
  87        HardLinkInfo *next;     /* Next entry in list */
  88        dev_t dev;              /* Device number */
  89        ino_t ino;              /* Inode number */
  90        short linkCount;        /* (Hard) Link Count */
  91        char name[1];           /* Start of filename (must be last) */
  92};
  93
  94/* Some info to be carried along when creating a new tarball */
  95typedef struct TarBallInfo TarBallInfo;
  96struct TarBallInfo {
  97        int tarFd;                      /* Open-for-write file descriptor
  98                                         * for the tarball */
  99        struct stat statBuf;            /* Stat info for the tarball, letting
 100                                         * us know the inode and device that the
 101                                         * tarball lives, so we can avoid trying
 102                                         * to include the tarball into itself */
 103        int verboseFlag;                /* Whether to print extra stuff or not */
 104        const llist_t *excludeList;     /* List of files to not include */
 105        HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
 106        HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
 107};
 108
 109/* A nice enum with all the possible tar file content types */
 110enum TarFileType {
 111        REGTYPE = '0',          /* regular file */
 112        REGTYPE0 = '\0',        /* regular file (ancient bug compat) */
 113        LNKTYPE = '1',          /* hard link */
 114        SYMTYPE = '2',          /* symbolic link */
 115        CHRTYPE = '3',          /* character special */
 116        BLKTYPE = '4',          /* block special */
 117        DIRTYPE = '5',          /* directory */
 118        FIFOTYPE = '6',         /* FIFO special */
 119        CONTTYPE = '7',         /* reserved */
 120        GNULONGLINK = 'K',      /* GNU long (>100 chars) link name */
 121        GNULONGNAME = 'L',      /* GNU long (>100 chars) file name */
 122};
 123typedef enum TarFileType TarFileType;
 124
 125/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
 126static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
 127                                        struct stat *statbuf,
 128                                        const char *fileName)
 129{
 130        /* Note: hlInfoHeadPtr can never be NULL! */
 131        HardLinkInfo *hlInfo;
 132
 133        hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
 134        hlInfo->next = *hlInfoHeadPtr;
 135        *hlInfoHeadPtr = hlInfo;
 136        hlInfo->dev = statbuf->st_dev;
 137        hlInfo->ino = statbuf->st_ino;
 138        hlInfo->linkCount = statbuf->st_nlink;
 139        strcpy(hlInfo->name, fileName);
 140}
 141
 142static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
 143{
 144        HardLinkInfo *hlInfo;
 145        HardLinkInfo *hlInfoNext;
 146
 147        if (hlInfoHeadPtr) {
 148                hlInfo = *hlInfoHeadPtr;
 149                while (hlInfo) {
 150                        hlInfoNext = hlInfo->next;
 151                        free(hlInfo);
 152                        hlInfo = hlInfoNext;
 153                }
 154                *hlInfoHeadPtr = NULL;
 155        }
 156}
 157
 158/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
 159static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
 160{
 161        while (hlInfo) {
 162                if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))
 163                        break;
 164                hlInfo = hlInfo->next;
 165        }
 166        return hlInfo;
 167}
 168
 169/* Put an octal string into the specified buffer.
 170 * The number is zero padded and possibly null terminated.
 171 * Stores low-order bits only if whole value does not fit. */
 172static void putOctal(char *cp, int len, off_t value)
 173{
 174        char tempBuffer[sizeof(off_t)*3+1];
 175        char *tempString = tempBuffer;
 176        int width;
 177
 178        width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
 179        tempString += (width - len);
 180
 181        /* If string has leading zeroes, we can drop one */
 182        /* and field will have trailing '\0' */
 183        /* (increases chances of compat with other tars) */
 184        if (tempString[0] == '0')
 185                tempString++;
 186
 187        /* Copy the string to the field */
 188        memcpy(cp, tempString, len);
 189}
 190#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
 191
 192static void chksum_and_xwrite(int fd, struct TarHeader* hp)
 193{
 194        /* POSIX says that checksum is done on unsigned bytes
 195         * (Sun and HP-UX gets it wrong... more details in
 196         * GNU tar source) */
 197        const unsigned char *cp;
 198        int chksum, size;
 199
 200        strcpy(hp->magic, "ustar  ");
 201
 202        /* Calculate and store the checksum (i.e., the sum of all of the bytes of
 203         * the header).  The checksum field must be filled with blanks for the
 204         * calculation.  The checksum field is formatted differently from the
 205         * other fields: it has 6 digits, a null, then a space -- rather than
 206         * digits, followed by a null like the other fields... */
 207        memset(hp->chksum, ' ', sizeof(hp->chksum));
 208        cp = (const unsigned char *) hp;
 209        chksum = 0;
 210        size = sizeof(*hp);
 211        do { chksum += *cp++; } while (--size);
 212        putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
 213
 214        /* Now write the header out to disk */
 215        xwrite(fd, hp, sizeof(*hp));
 216}
 217
 218#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 219static void writeLongname(int fd, int type, const char *name, int dir)
 220{
 221        static const struct {
 222                char mode[8];             /* 100-107 */
 223                char uid[8];              /* 108-115 */
 224                char gid[8];              /* 116-123 */
 225                char size[12];            /* 124-135 */
 226                char mtime[12];           /* 136-147 */
 227        } prefilled = {
 228                "0000000",
 229                "0000000",
 230                "0000000",
 231                "00000000000",
 232                "00000000000",
 233        };
 234        struct TarHeader header;
 235        int size;
 236
 237        dir = !!dir; /* normalize: 0/1 */
 238        size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
 239        /* + dir: account for possible '/' */
 240
 241        memset(&header, 0, sizeof(header));
 242        strcpy(header.name, "././@LongLink");
 243        memcpy(header.mode, prefilled.mode, sizeof(prefilled));
 244        PUT_OCTAL(header.size, size);
 245        header.typeflag = type;
 246        chksum_and_xwrite(fd, &header);
 247
 248        /* Write filename[/] and pad the block. */
 249        /* dir=0: writes 'name<NUL>', pads */
 250        /* dir=1: writes 'name', writes '/<NUL>', pads */
 251        dir *= 2;
 252        xwrite(fd, name, size - dir);
 253        xwrite(fd, "/", dir);
 254        size = (-size) & (TAR_BLOCK_SIZE-1);
 255        memset(&header, 0, size);
 256        xwrite(fd, &header, size);
 257}
 258#endif
 259
 260/* Write out a tar header for the specified file/directory/whatever */
 261void BUG_tar_header_size(void);
 262static int writeTarHeader(struct TarBallInfo *tbInfo,
 263                const char *header_name, const char *fileName, struct stat *statbuf)
 264{
 265        struct TarHeader header;
 266
 267        if (sizeof(header) != 512)
 268                BUG_tar_header_size();
 269
 270        memset(&header, 0, sizeof(struct TarHeader));
 271
 272        strncpy(header.name, header_name, sizeof(header.name));
 273
 274        /* POSIX says to mask mode with 07777. */
 275        PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
 276        PUT_OCTAL(header.uid, statbuf->st_uid);
 277        PUT_OCTAL(header.gid, statbuf->st_gid);
 278        memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
 279        PUT_OCTAL(header.mtime, statbuf->st_mtime);
 280
 281        /* Enter the user and group names */
 282        safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
 283        safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
 284
 285        if (tbInfo->hlInfo) {
 286                /* This is a hard link */
 287                header.typeflag = LNKTYPE;
 288                strncpy(header.linkname, tbInfo->hlInfo->name,
 289                                sizeof(header.linkname));
 290#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 291                /* Write out long linkname if needed */
 292                if (header.linkname[sizeof(header.linkname)-1])
 293                        writeLongname(tbInfo->tarFd, GNULONGLINK,
 294                                        tbInfo->hlInfo->name, 0);
 295#endif
 296        } else if (S_ISLNK(statbuf->st_mode)) {
 297                char *lpath = xmalloc_readlink_or_warn(fileName);
 298                if (!lpath)
 299                        return FALSE;
 300                header.typeflag = SYMTYPE;
 301                strncpy(header.linkname, lpath, sizeof(header.linkname));
 302#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 303                /* Write out long linkname if needed */
 304                if (header.linkname[sizeof(header.linkname)-1])
 305                        writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
 306#else
 307                /* If it is larger than 100 bytes, bail out */
 308                if (header.linkname[sizeof(header.linkname)-1]) {
 309                        free(lpath);
 310                        bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
 311                        return FALSE;
 312                }
 313#endif
 314                free(lpath);
 315        } else if (S_ISDIR(statbuf->st_mode)) {
 316                header.typeflag = DIRTYPE;
 317                /* Append '/' only if there is a space for it */
 318                if (!header.name[sizeof(header.name)-1])
 319                        header.name[strlen(header.name)] = '/';
 320        } else if (S_ISCHR(statbuf->st_mode)) {
 321                header.typeflag = CHRTYPE;
 322                PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
 323                PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
 324        } else if (S_ISBLK(statbuf->st_mode)) {
 325                header.typeflag = BLKTYPE;
 326                PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
 327                PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
 328        } else if (S_ISFIFO(statbuf->st_mode)) {
 329                header.typeflag = FIFOTYPE;
 330        } else if (S_ISREG(statbuf->st_mode)) {
 331                if (sizeof(statbuf->st_size) > 4
 332                 && statbuf->st_size > (off_t)0777777777777LL
 333                ) {
 334                        bb_error_msg_and_die("cannot store file '%s' "
 335                                "of size %"OFF_FMT"d, aborting",
 336                                fileName, statbuf->st_size);
 337                }
 338                header.typeflag = REGTYPE;
 339                PUT_OCTAL(header.size, statbuf->st_size);
 340        } else {
 341                bb_error_msg("%s: unknown file type", fileName);
 342                return FALSE;
 343        }
 344
 345#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 346        /* Write out long name if needed */
 347        /* (we, like GNU tar, output long linkname *before* long name) */
 348        if (header.name[sizeof(header.name)-1])
 349                writeLongname(tbInfo->tarFd, GNULONGNAME,
 350                                header_name, S_ISDIR(statbuf->st_mode));
 351#endif
 352
 353        /* Now write the header out to disk */
 354        chksum_and_xwrite(tbInfo->tarFd, &header);
 355
 356        /* Now do the verbose thing (or not) */
 357        if (tbInfo->verboseFlag) {
 358                FILE *vbFd = stdout;
 359
 360                if (tbInfo->tarFd == STDOUT_FILENO)     /* If the archive goes to stdout, verbose to stderr */
 361                        vbFd = stderr;
 362                /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
 363                /* We don't have such excesses here: for us "v" == "vv" */
 364                /* '/' is probably a GNUism */
 365                fprintf(vbFd, "%s%s\n", header_name,
 366                                S_ISDIR(statbuf->st_mode) ? "/" : "");
 367        }
 368
 369        return TRUE;
 370}
 371
 372#if ENABLE_FEATURE_TAR_FROM
 373static int exclude_file(const llist_t *excluded_files, const char *file)
 374{
 375        while (excluded_files) {
 376                if (excluded_files->data[0] == '/') {
 377                        if (fnmatch(excluded_files->data, file,
 378                                                FNM_PATHNAME | FNM_LEADING_DIR) == 0)
 379                                return 1;
 380                } else {
 381                        const char *p;
 382
 383                        for (p = file; p[0] != '\0'; p++) {
 384                                if ((p == file || p[-1] == '/') && p[0] != '/' &&
 385                                        fnmatch(excluded_files->data, p,
 386                                                        FNM_PATHNAME | FNM_LEADING_DIR) == 0)
 387                                        return 1;
 388                        }
 389                }
 390                excluded_files = excluded_files->link;
 391        }
 392
 393        return 0;
 394}
 395#else
 396#define exclude_file(excluded_files, file) 0
 397#endif
 398
 399static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
 400                        void *userData, int depth UNUSED_PARAM)
 401{
 402        struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
 403        const char *header_name;
 404        int inputFileFd = -1;
 405
 406        /* Strip leading '/' (must be before memorizing hardlink's name) */
 407        header_name = fileName;
 408        while (header_name[0] == '/') {
 409                static smallint warned;
 410
 411                if (!warned) {
 412                        bb_error_msg("removing leading '/' from member names");
 413                        warned = 1;
 414                }
 415                header_name++;
 416        }
 417
 418        if (header_name[0] == '\0')
 419                return TRUE;
 420
 421        /* It is against the rules to archive a socket */
 422        if (S_ISSOCK(statbuf->st_mode)) {
 423                bb_error_msg("%s: socket ignored", fileName);
 424                return TRUE;
 425        }
 426
 427        /*
 428         * Check to see if we are dealing with a hard link.
 429         * If so -
 430         * Treat the first occurance of a given dev/inode as a file while
 431         * treating any additional occurances as hard links.  This is done
 432         * by adding the file information to the HardLinkInfo linked list.
 433         */
 434        tbInfo->hlInfo = NULL;
 435        if (statbuf->st_nlink > 1) {
 436                tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
 437                if (tbInfo->hlInfo == NULL)
 438                        addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
 439        }
 440
 441        /* It is a bad idea to store the archive we are in the process of creating,
 442         * so check the device and inode to be sure that this particular file isn't
 443         * the new tarball */
 444        if (tbInfo->statBuf.st_dev == statbuf->st_dev
 445         && tbInfo->statBuf.st_ino == statbuf->st_ino
 446        ) {
 447                bb_error_msg("%s: file is the archive; skipping", fileName);
 448                return TRUE;
 449        }
 450
 451        if (exclude_file(tbInfo->excludeList, header_name))
 452                return SKIP;
 453
 454#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 455        if (strlen(header_name) >= NAME_SIZE) {
 456                bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
 457                return TRUE;
 458        }
 459#endif
 460
 461        /* Is this a regular file? */
 462        if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
 463                /* open the file we want to archive, and make sure all is well */
 464                inputFileFd = open_or_warn(fileName, O_RDONLY);
 465                if (inputFileFd < 0) {
 466                        return FALSE;
 467                }
 468        }
 469
 470        /* Add an entry to the tarball */
 471        if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
 472                return FALSE;
 473        }
 474
 475        /* If it was a regular file, write out the body */
 476        if (inputFileFd >= 0) {
 477                size_t readSize;
 478                /* Write the file to the archive. */
 479                /* We record size into header first, */
 480                /* and then write out file. If file shrinks in between, */
 481                /* tar will be corrupted. So we don't allow for that. */
 482                /* NB: GNU tar 1.16 warns and pads with zeroes */
 483                /* or even seeks back and updates header */
 484                bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 485                ////off_t readSize;
 486                ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 487                ////if (readSize != statbuf->st_size && readSize >= 0) {
 488                ////    bb_error_msg_and_die("short read from %s, aborting", fileName);
 489                ////}
 490
 491                /* Check that file did not grow in between? */
 492                /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
 493
 494                close(inputFileFd);
 495
 496                /* Pad the file up to the tar block size */
 497                /* (a few tricks here in the name of code size) */
 498                readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
 499                memset(block_buf, 0, readSize);
 500                xwrite(tbInfo->tarFd, block_buf, readSize);
 501        }
 502
 503        return TRUE;
 504}
 505
 506#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 507#if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
 508#define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
 509#endif
 510/* Don't inline: vfork scares gcc and pessimizes code */
 511static void NOINLINE vfork_compressor(int tar_fd, int gzip)
 512{
 513        pid_t gzipPid;
 514#if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
 515        const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
 516#elif ENABLE_FEATURE_SEAMLESS_GZ
 517        const char *zip_exec = "gzip";
 518#else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
 519        const char *zip_exec = "bzip2";
 520#endif
 521        // On Linux, vfork never unpauses parent early, although standard
 522        // allows for that. Do we want to waste bytes checking for it?
 523#define WAIT_FOR_CHILD 0
 524        volatile int vfork_exec_errno = 0;
 525        struct fd_pair gzipDataPipe;
 526#if WAIT_FOR_CHILD
 527        struct fd_pair gzipStatusPipe;
 528        xpiped_pair(gzipStatusPipe);
 529#endif
 530        xpiped_pair(gzipDataPipe);
 531
 532        signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
 533
 534#if defined(__GNUC__) && __GNUC__
 535        /* Avoid vfork clobbering */
 536        (void) &zip_exec;
 537#endif
 538
 539        gzipPid = vfork();
 540        if (gzipPid < 0)
 541                bb_perror_msg_and_die("vfork");
 542
 543        if (gzipPid == 0) {
 544                /* child */
 545                /* NB: close _first_, then move fds! */
 546                close(gzipDataPipe.wr);
 547#if WAIT_FOR_CHILD
 548                close(gzipStatusPipe.rd);
 549                /* gzipStatusPipe.wr will close only on exec -
 550                 * parent waits for this close to happen */
 551                fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
 552#endif
 553                xmove_fd(gzipDataPipe.rd, 0);
 554                xmove_fd(tar_fd, 1);
 555                /* exec gzip/bzip2 program/applet */
 556                BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
 557                vfork_exec_errno = errno;
 558                _exit(EXIT_FAILURE);
 559        }
 560
 561        /* parent */
 562        xmove_fd(gzipDataPipe.wr, tar_fd);
 563        close(gzipDataPipe.rd);
 564#if WAIT_FOR_CHILD
 565        close(gzipStatusPipe.wr);
 566        while (1) {
 567                char buf;
 568                int n;
 569
 570                /* Wait until child execs (or fails to) */
 571                n = full_read(gzipStatusPipe.rd, &buf, 1);
 572                if (n < 0 /* && errno == EAGAIN */)
 573                        continue;       /* try it again */
 574        }
 575        close(gzipStatusPipe.rd);
 576#endif
 577        if (vfork_exec_errno) {
 578                errno = vfork_exec_errno;
 579                bb_perror_msg_and_die("cannot exec %s", zip_exec);
 580        }
 581}
 582#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
 583
 584
 585/* gcc 4.2.1 inlines it, making code bigger */
 586static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
 587        int dereferenceFlag, const llist_t *include,
 588        const llist_t *exclude, int gzip)
 589{
 590        int errorFlag = FALSE;
 591        struct TarBallInfo tbInfo;
 592
 593        tbInfo.hlInfoHead = NULL;
 594
 595        fchmod(tar_fd, 0644);
 596        tbInfo.tarFd = tar_fd;
 597        tbInfo.verboseFlag = verboseFlag;
 598
 599        /* Store the stat info for the tarball's file, so
 600         * can avoid including the tarball into itself....  */
 601        if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
 602                bb_perror_msg_and_die("cannot stat tar file");
 603
 604#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 605        if (gzip)
 606                vfork_compressor(tbInfo.tarFd, gzip);
 607#endif
 608
 609        tbInfo.excludeList = exclude;
 610
 611        /* Read the directory/files and iterate over them one at a time */
 612        while (include) {
 613                if (!recursive_action(include->data, ACTION_RECURSE |
 614                                (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
 615                                writeFileToTarball, writeFileToTarball, &tbInfo, 0))
 616                {
 617                        errorFlag = TRUE;
 618                }
 619                include = include->link;
 620        }
 621        /* Write two empty blocks to the end of the archive */
 622        memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
 623        xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
 624
 625        /* To be pedantically correct, we would check if the tarball
 626         * is smaller than 20 tar blocks, and pad it if it was smaller,
 627         * but that isn't necessary for GNU tar interoperability, and
 628         * so is considered a waste of space */
 629
 630        /* Close so the child process (if any) will exit */
 631        close(tbInfo.tarFd);
 632
 633        /* Hang up the tools, close up shop, head home */
 634        if (ENABLE_FEATURE_CLEAN_UP)
 635                freeHardLinkInfo(&tbInfo.hlInfoHead);
 636
 637        if (errorFlag)
 638                bb_error_msg("error exit delayed from previous errors");
 639
 640#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 641        if (gzip) {
 642                int status;
 643                if (safe_waitpid(-1, &status, 0) == -1)
 644                        bb_perror_msg("waitpid");
 645                else if (!WIFEXITED(status) || WEXITSTATUS(status))
 646                        /* gzip was killed or has exited with nonzero! */
 647                        errorFlag = TRUE;
 648        }
 649#endif
 650        return errorFlag;
 651}
 652#else
 653int writeTarFile(int tar_fd, int verboseFlag,
 654        int dereferenceFlag, const llist_t *include,
 655        const llist_t *exclude, int gzip);
 656#endif /* FEATURE_TAR_CREATE */
 657
 658#if ENABLE_FEATURE_TAR_FROM
 659static llist_t *append_file_list_to_list(llist_t *list)
 660{
 661        FILE *src_stream;
 662        char *line;
 663        llist_t *newlist = NULL;
 664
 665        while (list) {
 666                src_stream = xfopen_for_read(llist_pop(&list));
 667                while ((line = xmalloc_fgetline(src_stream)) != NULL) {
 668                        /* kill trailing '/' unless the string is just "/" */
 669                        char *cp = last_char_is(line, '/');
 670                        if (cp > line)
 671                                *cp = '\0';
 672                        llist_add_to(&newlist, line);
 673                }
 674                fclose(src_stream);
 675        }
 676        return newlist;
 677}
 678#else
 679#define append_file_list_to_list(x) 0
 680#endif
 681
 682#if ENABLE_FEATURE_SEAMLESS_Z
 683static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
 684{
 685        /* Can't lseek over pipes */
 686        archive_handle->seek = seek_by_read;
 687
 688        /* do the decompression, and cleanup */
 689        if (xread_char(archive_handle->src_fd) != 0x1f
 690         || xread_char(archive_handle->src_fd) != 0x9d
 691        ) {
 692                bb_error_msg_and_die("invalid magic");
 693        }
 694
 695        open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
 696        archive_handle->offset = 0;
 697        while (get_header_tar(archive_handle) == EXIT_SUCCESS)
 698                continue;
 699
 700        /* Can only do one file at a time */
 701        return EXIT_FAILURE;
 702}
 703#else
 704#define get_header_tar_Z NULL
 705#endif
 706
 707#ifdef CHECK_FOR_CHILD_EXITCODE
 708/* Looks like it isn't needed - tar detects malformed (truncated)
 709 * archive if e.g. bunzip2 fails */
 710static int child_error;
 711
 712static void handle_SIGCHLD(int status)
 713{
 714        /* Actually, 'status' is a signo. We reuse it for other needs */
 715
 716        /* Wait for any child without blocking */
 717        if (wait_any_nohang(&status) < 0)
 718                /* wait failed?! I'm confused... */
 719                return;
 720
 721        if (WIFEXITED(status) && WEXITSTATUS(status)==0)
 722                /* child exited with 0 */
 723                return;
 724        /* Cannot happen?
 725        if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
 726        child_error = 1;
 727}
 728#endif
 729
 730enum {
 731        OPTBIT_KEEP_OLD = 7,
 732        USE_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
 733        USE_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
 734        USE_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
 735        USE_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
 736        USE_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
 737        USE_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
 738        USE_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
 739        USE_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
 740        OPTBIT_NOPRESERVE_OWN,
 741        OPTBIT_NOPRESERVE_PERM,
 742        OPT_TEST         = 1 << 0, // t
 743        OPT_EXTRACT      = 1 << 1, // x
 744        OPT_BASEDIR      = 1 << 2, // C
 745        OPT_TARNAME      = 1 << 3, // f
 746        OPT_2STDOUT      = 1 << 4, // O
 747        OPT_P            = 1 << 5, // p
 748        OPT_VERBOSE      = 1 << 6, // v
 749        OPT_KEEP_OLD     = 1 << 7, // k
 750        OPT_CREATE       = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
 751        OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
 752        OPT_BZIP2        = USE_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
 753        OPT_LZMA         = USE_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
 754        OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
 755        OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
 756        OPT_GZIP         = USE_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
 757        OPT_COMPRESS     = USE_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
 758        OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
 759        OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
 760};
 761#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 762static const char tar_longopts[] ALIGN1 =
 763        "list\0"                No_argument       "t"
 764        "extract\0"             No_argument       "x"
 765        "directory\0"           Required_argument "C"
 766        "file\0"                Required_argument "f"
 767        "to-stdout\0"           No_argument       "O"
 768        "same-permissions\0"    No_argument       "p"
 769        "verbose\0"             No_argument       "v"
 770        "keep-old\0"            No_argument       "k"
 771# if ENABLE_FEATURE_TAR_CREATE
 772        "create\0"              No_argument       "c"
 773        "dereference\0"         No_argument       "h"
 774# endif
 775# if ENABLE_FEATURE_SEAMLESS_BZ2
 776        "bzip2\0"               No_argument       "j"
 777# endif
 778# if ENABLE_FEATURE_SEAMLESS_LZMA
 779        "lzma\0"                No_argument       "a"
 780# endif
 781# if ENABLE_FEATURE_TAR_FROM
 782        "files-from\0"          Required_argument "T"
 783        "exclude-from\0"        Required_argument "X"
 784# endif
 785# if ENABLE_FEATURE_SEAMLESS_GZ
 786        "gzip\0"                No_argument       "z"
 787# endif
 788# if ENABLE_FEATURE_SEAMLESS_Z
 789        "compress\0"            No_argument       "Z"
 790# endif
 791        "no-same-owner\0"       No_argument       "\xfd"
 792        "no-same-permissions\0" No_argument       "\xfe"
 793        /* --exclude takes next bit position in option mask, */
 794        /* therefore we have to either put it _after_ --no-same-perm */
 795        /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */
 796# if ENABLE_FEATURE_TAR_FROM
 797        "exclude\0"             Required_argument "\xff"
 798# endif
 799        ;
 800#endif
 801
 802int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 803int tar_main(int argc UNUSED_PARAM, char **argv)
 804{
 805        char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
 806        archive_handle_t *tar_handle;
 807        char *base_dir = NULL;
 808        const char *tar_filename = "-";
 809        unsigned opt;
 810        int verboseFlag = 0;
 811#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 812        llist_t *excludes = NULL;
 813#endif
 814
 815        /* Initialise default values */
 816        tar_handle = init_handle();
 817        tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
 818                             | ARCHIVE_PRESERVE_DATE
 819                             | ARCHIVE_EXTRACT_UNCONDITIONAL;
 820
 821        /* Apparently only root's tar preserves perms (see bug 3844) */
 822        if (getuid() != 0)
 823                tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
 824
 825        /* Prepend '-' to the first argument if required */
 826        opt_complementary = "--:" // first arg is options
 827                "tt:vv:" // count -t,-v
 828                "?:" // bail out with usage instead of error return
 829                "X::T::" // cumulative lists
 830#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 831                "\xff::" // cumulative lists for --exclude
 832#endif
 833                USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
 834                USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
 835                SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
 836#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 837        applet_long_options = tar_longopts;
 838#endif
 839        opt = getopt32(argv,
 840                "txC:f:Opvk"
 841                USE_FEATURE_TAR_CREATE(   "ch"  )
 842                USE_FEATURE_SEAMLESS_BZ2( "j"   )
 843                USE_FEATURE_SEAMLESS_LZMA("a"   )
 844                USE_FEATURE_TAR_FROM(     "T:X:")
 845                USE_FEATURE_SEAMLESS_GZ(  "z"   )
 846                USE_FEATURE_SEAMLESS_Z(   "Z"   )
 847                , &base_dir // -C dir
 848                , &tar_filename // -f filename
 849                USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
 850                USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
 851#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 852                , &excludes // --exclude
 853#endif
 854                , &verboseFlag // combined count for -t and -v
 855                , &verboseFlag // combined count for -t and -v
 856                );
 857        argv += optind;
 858
 859        if (verboseFlag) tar_handle->action_header = header_verbose_list;
 860        if (verboseFlag == 1) tar_handle->action_header = header_list;
 861
 862        if (opt & OPT_EXTRACT)
 863                tar_handle->action_data = data_extract_all;
 864
 865        if (opt & OPT_2STDOUT)
 866                tar_handle->action_data = data_extract_to_stdout;
 867
 868        if (opt & OPT_KEEP_OLD)
 869                tar_handle->ah_flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
 870
 871        if (opt & OPT_NOPRESERVE_OWN)
 872                tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_OWN;
 873
 874        if (opt & OPT_NOPRESERVE_PERM)
 875                tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
 876
 877        if (opt & OPT_GZIP)
 878                get_header_ptr = get_header_tar_gz;
 879
 880        if (opt & OPT_BZIP2)
 881                get_header_ptr = get_header_tar_bz2;
 882
 883        if (opt & OPT_LZMA)
 884                get_header_ptr = get_header_tar_lzma;
 885
 886        if (opt & OPT_COMPRESS)
 887                get_header_ptr = get_header_tar_Z;
 888
 889#if ENABLE_FEATURE_TAR_FROM
 890        tar_handle->reject = append_file_list_to_list(tar_handle->reject);
 891#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 892        /* Append excludes to reject */
 893        while (excludes) {
 894                llist_t *next = excludes->link;
 895                excludes->link = tar_handle->reject;
 896                tar_handle->reject = excludes;
 897                excludes = next;
 898        }
 899#endif
 900        tar_handle->accept = append_file_list_to_list(tar_handle->accept);
 901#endif
 902
 903        /* Setup an array of filenames to work with */
 904        /* TODO: This is the same as in ar, separate function ? */
 905        while (*argv) {
 906                /* kill trailing '/' unless the string is just "/" */
 907                char *cp = last_char_is(*argv, '/');
 908                if (cp > *argv)
 909                        *cp = '\0';
 910                llist_add_to_end(&tar_handle->accept, *argv);
 911                argv++;
 912        }
 913
 914        if (tar_handle->accept || tar_handle->reject)
 915                tar_handle->filter = filter_accept_reject_list;
 916
 917        /* Open the tar file */
 918        {
 919                FILE *tar_stream;
 920                int flags;
 921
 922                if (opt & OPT_CREATE) {
 923                        /* Make sure there is at least one file to tar up.  */
 924                        if (tar_handle->accept == NULL)
 925                                bb_error_msg_and_die("empty archive");
 926
 927                        tar_stream = stdout;
 928                        /* Mimicking GNU tar 1.15.1: */
 929                        flags = O_WRONLY | O_CREAT | O_TRUNC;
 930                } else {
 931                        tar_stream = stdin;
 932                        flags = O_RDONLY;
 933                }
 934
 935                if (LONE_DASH(tar_filename)) {
 936                        tar_handle->src_fd = fileno(tar_stream);
 937                        tar_handle->seek = seek_by_read;
 938                } else {
 939                        if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) {
 940                                get_header_ptr = get_header_tar;
 941                                tar_handle->src_fd = open_zipped(tar_filename);
 942                                if (tar_handle->src_fd < 0)
 943                                        bb_perror_msg_and_die("can't open '%s'", tar_filename);
 944                        } else {
 945                                tar_handle->src_fd = xopen(tar_filename, flags);
 946                        }
 947                }
 948        }
 949
 950        if (base_dir)
 951                xchdir(base_dir);
 952
 953#ifdef CHECK_FOR_CHILD_EXITCODE
 954        /* We need to know whether child (gzip/bzip/etc) exits abnormally */
 955        signal(SIGCHLD, handle_SIGCHLD);
 956#endif
 957
 958        /* create an archive */
 959        if (opt & OPT_CREATE) {
 960#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 961                int zipMode = 0;
 962                if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
 963                        zipMode = 1;
 964                if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
 965                        zipMode = 2;
 966#endif
 967                /* NB: writeTarFile() closes tar_handle->src_fd */
 968                return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
 969                                tar_handle->accept,
 970                                tar_handle->reject, zipMode);
 971        }
 972
 973        while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
 974                continue;
 975
 976        /* Check that every file that should have been extracted was */
 977        while (tar_handle->accept) {
 978                if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
 979                 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
 980                ) {
 981                        bb_error_msg_and_die("%s: not found in archive",
 982                                tar_handle->accept->data);
 983                }
 984                tar_handle->accept = tar_handle->accept->link;
 985        }
 986        if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
 987                close(tar_handle->src_fd);
 988
 989        return EXIT_SUCCESS;
 990}
 991