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 archive goes to stdout, verbose goes to stderr */
 361                if (tbInfo->tarFd == STDOUT_FILENO)
 362                        vbFd = stderr;
 363                /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
 364                /* We don't have such excesses here: for us "v" == "vv" */
 365                /* '/' is probably a GNUism */
 366                fprintf(vbFd, "%s%s\n", header_name,
 367                                S_ISDIR(statbuf->st_mode) ? "/" : "");
 368        }
 369
 370        return TRUE;
 371}
 372
 373#if ENABLE_FEATURE_TAR_FROM
 374static int exclude_file(const llist_t *excluded_files, const char *file)
 375{
 376        while (excluded_files) {
 377                if (excluded_files->data[0] == '/') {
 378                        if (fnmatch(excluded_files->data, file,
 379                                                FNM_PATHNAME | FNM_LEADING_DIR) == 0)
 380                                return 1;
 381                } else {
 382                        const char *p;
 383
 384                        for (p = file; p[0] != '\0'; p++) {
 385                                if ((p == file || p[-1] == '/') && p[0] != '/' &&
 386                                        fnmatch(excluded_files->data, p,
 387                                                        FNM_PATHNAME | FNM_LEADING_DIR) == 0)
 388                                        return 1;
 389                        }
 390                }
 391                excluded_files = excluded_files->link;
 392        }
 393
 394        return 0;
 395}
 396#else
 397#define exclude_file(excluded_files, file) 0
 398#endif
 399
 400static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
 401                        void *userData, int depth UNUSED_PARAM)
 402{
 403        struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
 404        const char *header_name;
 405        int inputFileFd = -1;
 406
 407        /* Strip leading '/' (must be before memorizing hardlink's name) */
 408        header_name = fileName;
 409        while (header_name[0] == '/') {
 410                static smallint warned;
 411
 412                if (!warned) {
 413                        bb_error_msg("removing leading '/' from member names");
 414                        warned = 1;
 415                }
 416                header_name++;
 417        }
 418
 419        if (header_name[0] == '\0')
 420                return TRUE;
 421
 422        /* It is against the rules to archive a socket */
 423        if (S_ISSOCK(statbuf->st_mode)) {
 424                bb_error_msg("%s: socket ignored", fileName);
 425                return TRUE;
 426        }
 427
 428        /*
 429         * Check to see if we are dealing with a hard link.
 430         * If so -
 431         * Treat the first occurance of a given dev/inode as a file while
 432         * treating any additional occurances as hard links.  This is done
 433         * by adding the file information to the HardLinkInfo linked list.
 434         */
 435        tbInfo->hlInfo = NULL;
 436        if (statbuf->st_nlink > 1) {
 437                tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
 438                if (tbInfo->hlInfo == NULL)
 439                        addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
 440        }
 441
 442        /* It is a bad idea to store the archive we are in the process of creating,
 443         * so check the device and inode to be sure that this particular file isn't
 444         * the new tarball */
 445        if (tbInfo->statBuf.st_dev == statbuf->st_dev
 446         && tbInfo->statBuf.st_ino == statbuf->st_ino
 447        ) {
 448                bb_error_msg("%s: file is the archive; skipping", fileName);
 449                return TRUE;
 450        }
 451
 452        if (exclude_file(tbInfo->excludeList, header_name))
 453                return SKIP;
 454
 455#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 456        if (strlen(header_name) >= NAME_SIZE) {
 457                bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
 458                return TRUE;
 459        }
 460#endif
 461
 462        /* Is this a regular file? */
 463        if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
 464                /* open the file we want to archive, and make sure all is well */
 465                inputFileFd = open_or_warn(fileName, O_RDONLY);
 466                if (inputFileFd < 0) {
 467                        return FALSE;
 468                }
 469        }
 470
 471        /* Add an entry to the tarball */
 472        if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
 473                return FALSE;
 474        }
 475
 476        /* If it was a regular file, write out the body */
 477        if (inputFileFd >= 0) {
 478                size_t readSize;
 479                /* Write the file to the archive. */
 480                /* We record size into header first, */
 481                /* and then write out file. If file shrinks in between, */
 482                /* tar will be corrupted. So we don't allow for that. */
 483                /* NB: GNU tar 1.16 warns and pads with zeroes */
 484                /* or even seeks back and updates header */
 485                bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 486                ////off_t readSize;
 487                ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 488                ////if (readSize != statbuf->st_size && readSize >= 0) {
 489                ////    bb_error_msg_and_die("short read from %s, aborting", fileName);
 490                ////}
 491
 492                /* Check that file did not grow in between? */
 493                /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
 494
 495                close(inputFileFd);
 496
 497                /* Pad the file up to the tar block size */
 498                /* (a few tricks here in the name of code size) */
 499                readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
 500                memset(block_buf, 0, readSize);
 501                xwrite(tbInfo->tarFd, block_buf, readSize);
 502        }
 503
 504        return TRUE;
 505}
 506
 507#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 508#if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
 509#define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
 510#endif
 511/* Don't inline: vfork scares gcc and pessimizes code */
 512static void NOINLINE vfork_compressor(int tar_fd, int gzip)
 513{
 514        pid_t gzipPid;
 515#if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
 516        const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
 517#elif ENABLE_FEATURE_SEAMLESS_GZ
 518        const char *zip_exec = "gzip";
 519#else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
 520        const char *zip_exec = "bzip2";
 521#endif
 522        // On Linux, vfork never unpauses parent early, although standard
 523        // allows for that. Do we want to waste bytes checking for it?
 524#define WAIT_FOR_CHILD 0
 525        volatile int vfork_exec_errno = 0;
 526        struct fd_pair gzipDataPipe;
 527#if WAIT_FOR_CHILD
 528        struct fd_pair gzipStatusPipe;
 529        xpiped_pair(gzipStatusPipe);
 530#endif
 531        xpiped_pair(gzipDataPipe);
 532
 533        signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
 534
 535#if defined(__GNUC__) && __GNUC__
 536        /* Avoid vfork clobbering */
 537        (void) &zip_exec;
 538#endif
 539
 540        gzipPid = vfork();
 541        if (gzipPid < 0)
 542                bb_perror_msg_and_die("vfork");
 543
 544        if (gzipPid == 0) {
 545                /* child */
 546                /* NB: close _first_, then move fds! */
 547                close(gzipDataPipe.wr);
 548#if WAIT_FOR_CHILD
 549                close(gzipStatusPipe.rd);
 550                /* gzipStatusPipe.wr will close only on exec -
 551                 * parent waits for this close to happen */
 552                fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
 553#endif
 554                xmove_fd(gzipDataPipe.rd, 0);
 555                xmove_fd(tar_fd, 1);
 556                /* exec gzip/bzip2 program/applet */
 557                BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
 558                vfork_exec_errno = errno;
 559                _exit(EXIT_FAILURE);
 560        }
 561
 562        /* parent */
 563        xmove_fd(gzipDataPipe.wr, tar_fd);
 564        close(gzipDataPipe.rd);
 565#if WAIT_FOR_CHILD
 566        close(gzipStatusPipe.wr);
 567        while (1) {
 568                char buf;
 569                int n;
 570
 571                /* Wait until child execs (or fails to) */
 572                n = full_read(gzipStatusPipe.rd, &buf, 1);
 573                if (n < 0 /* && errno == EAGAIN */)
 574                        continue;       /* try it again */
 575        }
 576        close(gzipStatusPipe.rd);
 577#endif
 578        if (vfork_exec_errno) {
 579                errno = vfork_exec_errno;
 580                bb_perror_msg_and_die("cannot exec %s", zip_exec);
 581        }
 582}
 583#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
 584
 585
 586/* gcc 4.2.1 inlines it, making code bigger */
 587static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
 588        int dereferenceFlag, const llist_t *include,
 589        const llist_t *exclude, int gzip)
 590{
 591        int errorFlag = FALSE;
 592        struct TarBallInfo tbInfo;
 593
 594        tbInfo.hlInfoHead = NULL;
 595        tbInfo.tarFd = tar_fd;
 596        tbInfo.verboseFlag = verboseFlag;
 597
 598        /* Store the stat info for the tarball's file, so
 599         * can avoid including the tarball into itself....  */
 600        if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
 601                bb_perror_msg_and_die("cannot stat tar file");
 602
 603#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 604        if (gzip)
 605                vfork_compressor(tbInfo.tarFd, gzip);
 606#endif
 607
 608        tbInfo.excludeList = exclude;
 609
 610        /* Read the directory/files and iterate over them one at a time */
 611        while (include) {
 612                if (!recursive_action(include->data, ACTION_RECURSE |
 613                                (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
 614                                writeFileToTarball, writeFileToTarball, &tbInfo, 0))
 615                {
 616                        errorFlag = TRUE;
 617                }
 618                include = include->link;
 619        }
 620        /* Write two empty blocks to the end of the archive */
 621        memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
 622        xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
 623
 624        /* To be pedantically correct, we would check if the tarball
 625         * is smaller than 20 tar blocks, and pad it if it was smaller,
 626         * but that isn't necessary for GNU tar interoperability, and
 627         * so is considered a waste of space */
 628
 629        /* Close so the child process (if any) will exit */
 630        close(tbInfo.tarFd);
 631
 632        /* Hang up the tools, close up shop, head home */
 633        if (ENABLE_FEATURE_CLEAN_UP)
 634                freeHardLinkInfo(&tbInfo.hlInfoHead);
 635
 636        if (errorFlag)
 637                bb_error_msg("error exit delayed from previous errors");
 638
 639#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 640        if (gzip) {
 641                int status;
 642                if (safe_waitpid(-1, &status, 0) == -1)
 643                        bb_perror_msg("waitpid");
 644                else if (!WIFEXITED(status) || WEXITSTATUS(status))
 645                        /* gzip was killed or has exited with nonzero! */
 646                        errorFlag = TRUE;
 647        }
 648#endif
 649        return errorFlag;
 650}
 651#else
 652int writeTarFile(int tar_fd, int verboseFlag,
 653        int dereferenceFlag, const llist_t *include,
 654        const llist_t *exclude, int gzip);
 655#endif /* FEATURE_TAR_CREATE */
 656
 657#if ENABLE_FEATURE_TAR_FROM
 658static llist_t *append_file_list_to_list(llist_t *list)
 659{
 660        FILE *src_stream;
 661        char *line;
 662        llist_t *newlist = NULL;
 663
 664        while (list) {
 665                src_stream = xfopen_for_read(llist_pop(&list));
 666                while ((line = xmalloc_fgetline(src_stream)) != NULL) {
 667                        /* kill trailing '/' unless the string is just "/" */
 668                        char *cp = last_char_is(line, '/');
 669                        if (cp > line)
 670                                *cp = '\0';
 671                        llist_add_to(&newlist, line);
 672                }
 673                fclose(src_stream);
 674        }
 675        return newlist;
 676}
 677#else
 678#define append_file_list_to_list(x) 0
 679#endif
 680
 681#if ENABLE_FEATURE_SEAMLESS_Z
 682static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
 683{
 684        /* Can't lseek over pipes */
 685        archive_handle->seek = seek_by_read;
 686
 687        /* do the decompression, and cleanup */
 688        if (xread_char(archive_handle->src_fd) != 0x1f
 689         || xread_char(archive_handle->src_fd) != 0x9d
 690        ) {
 691                bb_error_msg_and_die("invalid magic");
 692        }
 693
 694        open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
 695        archive_handle->offset = 0;
 696        while (get_header_tar(archive_handle) == EXIT_SUCCESS)
 697                continue;
 698
 699        /* Can only do one file at a time */
 700        return EXIT_FAILURE;
 701}
 702#else
 703#define get_header_tar_Z NULL
 704#endif
 705
 706#ifdef CHECK_FOR_CHILD_EXITCODE
 707/* Looks like it isn't needed - tar detects malformed (truncated)
 708 * archive if e.g. bunzip2 fails */
 709static int child_error;
 710
 711static void handle_SIGCHLD(int status)
 712{
 713        /* Actually, 'status' is a signo. We reuse it for other needs */
 714
 715        /* Wait for any child without blocking */
 716        if (wait_any_nohang(&status) < 0)
 717                /* wait failed?! I'm confused... */
 718                return;
 719
 720        if (WIFEXITED(status) && WEXITSTATUS(status)==0)
 721                /* child exited with 0 */
 722                return;
 723        /* Cannot happen?
 724        if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
 725        child_error = 1;
 726}
 727#endif
 728
 729enum {
 730        OPTBIT_KEEP_OLD = 7,
 731        USE_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
 732        USE_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
 733        USE_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
 734        USE_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
 735        USE_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
 736        USE_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
 737        USE_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
 738        USE_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
 739        OPTBIT_NOPRESERVE_OWN,
 740        OPTBIT_NOPRESERVE_PERM,
 741        OPT_TEST         = 1 << 0, // t
 742        OPT_EXTRACT      = 1 << 1, // x
 743        OPT_BASEDIR      = 1 << 2, // C
 744        OPT_TARNAME      = 1 << 3, // f
 745        OPT_2STDOUT      = 1 << 4, // O
 746        OPT_P            = 1 << 5, // p
 747        OPT_VERBOSE      = 1 << 6, // v
 748        OPT_KEEP_OLD     = 1 << 7, // k
 749        OPT_CREATE       = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
 750        OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
 751        OPT_BZIP2        = USE_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
 752        OPT_LZMA         = USE_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
 753        OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
 754        OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
 755        OPT_GZIP         = USE_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
 756        OPT_COMPRESS     = USE_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
 757        OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
 758        OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
 759};
 760#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 761static const char tar_longopts[] ALIGN1 =
 762        "list\0"                No_argument       "t"
 763        "extract\0"             No_argument       "x"
 764        "directory\0"           Required_argument "C"
 765        "file\0"                Required_argument "f"
 766        "to-stdout\0"           No_argument       "O"
 767        "same-permissions\0"    No_argument       "p"
 768        "verbose\0"             No_argument       "v"
 769        "keep-old\0"            No_argument       "k"
 770# if ENABLE_FEATURE_TAR_CREATE
 771        "create\0"              No_argument       "c"
 772        "dereference\0"         No_argument       "h"
 773# endif
 774# if ENABLE_FEATURE_SEAMLESS_BZ2
 775        "bzip2\0"               No_argument       "j"
 776# endif
 777# if ENABLE_FEATURE_SEAMLESS_LZMA
 778        "lzma\0"                No_argument       "a"
 779# endif
 780# if ENABLE_FEATURE_TAR_FROM
 781        "files-from\0"          Required_argument "T"
 782        "exclude-from\0"        Required_argument "X"
 783# endif
 784# if ENABLE_FEATURE_SEAMLESS_GZ
 785        "gzip\0"                No_argument       "z"
 786# endif
 787# if ENABLE_FEATURE_SEAMLESS_Z
 788        "compress\0"            No_argument       "Z"
 789# endif
 790        "no-same-owner\0"       No_argument       "\xfd"
 791        "no-same-permissions\0" No_argument       "\xfe"
 792        /* --exclude takes next bit position in option mask, */
 793        /* therefore we have to either put it _after_ --no-same-perm */
 794        /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */
 795# if ENABLE_FEATURE_TAR_FROM
 796        "exclude\0"             Required_argument "\xff"
 797# endif
 798        ;
 799#endif
 800
 801int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 802int tar_main(int argc UNUSED_PARAM, char **argv)
 803{
 804        char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
 805        archive_handle_t *tar_handle;
 806        char *base_dir = NULL;
 807        const char *tar_filename = "-";
 808        unsigned opt;
 809        int verboseFlag = 0;
 810#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 811        llist_t *excludes = NULL;
 812#endif
 813
 814        /* Initialise default values */
 815        tar_handle = init_handle();
 816        tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
 817                             | ARCHIVE_PRESERVE_DATE
 818                             | ARCHIVE_EXTRACT_UNCONDITIONAL;
 819
 820        /* Apparently only root's tar preserves perms (see bug 3844) */
 821        if (getuid() != 0)
 822                tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
 823
 824        /* Prepend '-' to the first argument if required */
 825        opt_complementary = "--:" // first arg is options
 826                "tt:vv:" // count -t,-v
 827                "?:" // bail out with usage instead of error return
 828                "X::T::" // cumulative lists
 829#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 830                "\xff::" // cumulative lists for --exclude
 831#endif
 832                USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
 833                USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
 834                SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
 835#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 836        applet_long_options = tar_longopts;
 837#endif
 838        opt = getopt32(argv,
 839                "txC:f:Opvk"
 840                USE_FEATURE_TAR_CREATE(   "ch"  )
 841                USE_FEATURE_SEAMLESS_BZ2( "j"   )
 842                USE_FEATURE_SEAMLESS_LZMA("a"   )
 843                USE_FEATURE_TAR_FROM(     "T:X:")
 844                USE_FEATURE_SEAMLESS_GZ(  "z"   )
 845                USE_FEATURE_SEAMLESS_Z(   "Z"   )
 846                , &base_dir // -C dir
 847                , &tar_filename // -f filename
 848                USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
 849                USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
 850#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 851                , &excludes // --exclude
 852#endif
 853                , &verboseFlag // combined count for -t and -v
 854                , &verboseFlag // combined count for -t and -v
 855                );
 856        argv += optind;
 857
 858        if (verboseFlag) tar_handle->action_header = header_verbose_list;
 859        if (verboseFlag == 1) tar_handle->action_header = header_list;
 860
 861        if (opt & OPT_EXTRACT)
 862                tar_handle->action_data = data_extract_all;
 863
 864        if (opt & OPT_2STDOUT)
 865                tar_handle->action_data = data_extract_to_stdout;
 866
 867        if (opt & OPT_KEEP_OLD)
 868                tar_handle->ah_flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
 869
 870        if (opt & OPT_NOPRESERVE_OWN)
 871                tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_OWN;
 872
 873        if (opt & OPT_NOPRESERVE_PERM)
 874                tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
 875
 876        if (opt & OPT_GZIP)
 877                get_header_ptr = get_header_tar_gz;
 878
 879        if (opt & OPT_BZIP2)
 880                get_header_ptr = get_header_tar_bz2;
 881
 882        if (opt & OPT_LZMA)
 883                get_header_ptr = get_header_tar_lzma;
 884
 885        if (opt & OPT_COMPRESS)
 886                get_header_ptr = get_header_tar_Z;
 887
 888#if ENABLE_FEATURE_TAR_FROM
 889        tar_handle->reject = append_file_list_to_list(tar_handle->reject);
 890#if ENABLE_FEATURE_TAR_LONG_OPTIONS
 891        /* Append excludes to reject */
 892        while (excludes) {
 893                llist_t *next = excludes->link;
 894                excludes->link = tar_handle->reject;
 895                tar_handle->reject = excludes;
 896                excludes = next;
 897        }
 898#endif
 899        tar_handle->accept = append_file_list_to_list(tar_handle->accept);
 900#endif
 901
 902        /* Setup an array of filenames to work with */
 903        /* TODO: This is the same as in ar, separate function ? */
 904        while (*argv) {
 905                /* kill trailing '/' unless the string is just "/" */
 906                char *cp = last_char_is(*argv, '/');
 907                if (cp > *argv)
 908                        *cp = '\0';
 909                llist_add_to_end(&tar_handle->accept, *argv);
 910                argv++;
 911        }
 912
 913        if (tar_handle->accept || tar_handle->reject)
 914                tar_handle->filter = filter_accept_reject_list;
 915
 916        /* Open the tar file */
 917        {
 918                FILE *tar_stream;
 919                int flags;
 920
 921                if (opt & OPT_CREATE) {
 922                        /* Make sure there is at least one file to tar up.  */
 923                        if (tar_handle->accept == NULL)
 924                                bb_error_msg_and_die("empty archive");
 925
 926                        tar_stream = stdout;
 927                        /* Mimicking GNU tar 1.15.1: */
 928                        flags = O_WRONLY | O_CREAT | O_TRUNC;
 929                } else {
 930                        tar_stream = stdin;
 931                        flags = O_RDONLY;
 932                }
 933
 934                if (LONE_DASH(tar_filename)) {
 935                        tar_handle->src_fd = fileno(tar_stream);
 936                        tar_handle->seek = seek_by_read;
 937                } else {
 938                        if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) {
 939                                get_header_ptr = get_header_tar;
 940                                tar_handle->src_fd = open_zipped(tar_filename);
 941                                if (tar_handle->src_fd < 0)
 942                                        bb_perror_msg_and_die("can't open '%s'", tar_filename);
 943                        } else {
 944                                tar_handle->src_fd = xopen(tar_filename, flags);
 945                        }
 946                }
 947        }
 948
 949        if (base_dir)
 950                xchdir(base_dir);
 951
 952#ifdef CHECK_FOR_CHILD_EXITCODE
 953        /* We need to know whether child (gzip/bzip/etc) exits abnormally */
 954        signal(SIGCHLD, handle_SIGCHLD);
 955#endif
 956
 957        /* create an archive */
 958        if (opt & OPT_CREATE) {
 959#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
 960                int zipMode = 0;
 961                if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
 962                        zipMode = 1;
 963                if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
 964                        zipMode = 2;
 965#endif
 966                /* NB: writeTarFile() closes tar_handle->src_fd */
 967                return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
 968                                tar_handle->accept,
 969                                tar_handle->reject, zipMode);
 970        }
 971
 972        while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
 973                continue;
 974
 975        /* Check that every file that should have been extracted was */
 976        while (tar_handle->accept) {
 977                if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
 978                 && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
 979                ) {
 980                        bb_error_msg_and_die("%s: not found in archive",
 981                                tar_handle->accept->data);
 982                }
 983                tar_handle->accept = tar_handle->accept->link;
 984        }
 985        if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
 986                close(tar_handle->src_fd);
 987
 988        return EXIT_SUCCESS;
 989}
 990