Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/archival/tar.c


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

Legend:

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

    r1765 r2725  
    44 *
    55 * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg
    6  *  Glenn McGrath <bug1@iinet.net.au>
     6 *  by Glenn McGrath
    77 *
    88 * Note, that as of BusyBox-0.43, tar has been completely rewritten from the
     
    1616 *  Permission is granted to use, distribute, or modify this source,
    1717 *  provided that this copyright notice remains intact.
    18  *  Permission to distribute sash derived code under the GPL has been granted.
     18 *  Permission to distribute sash derived code under GPL has been granted.
    1919 *
    2020 * Based in part on the tar implementation from busybox-0.28
    2121 *  Copyright (C) 1995 Bruce Perens
    2222 *
    23  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     23 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    2424 */
    2525
    2626#include <fnmatch.h>
    27 #include <getopt.h>
    2827#include "libbb.h"
    29 #include "unarchive.h"
     28#include "archive.h"
     29/* FIXME: Stop using this non-standard feature */
     30#ifndef FNM_LEADING_DIR
     31# define FNM_LEADING_DIR 0
     32#endif
     33
     34
     35//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
     36#define DBG(...) ((void)0)
     37
    3038
    3139#define block_buf bb_common_bufsiz1
    3240
     41
     42#if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2
     43/* Do not pass gzip flag to writeTarFile() */
     44#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \
     45    writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude)
     46#endif
     47
     48
    3349#if ENABLE_FEATURE_TAR_CREATE
    34 
    35 /* Tar file constants  */
    36 
    37 #define TAR_BLOCK_SIZE      512
    38 
    39 /* POSIX tar Header Block, from POSIX 1003.1-1990  */
    40 #define NAME_SIZE      100
    41 #define NAME_SIZE_STR "100"
    42 typedef struct TarHeader TarHeader;
    43 struct TarHeader {        /* byte offset */
    44     char name[NAME_SIZE];     /*   0-99 */
    45     char mode[8];             /* 100-107 */
    46     char uid[8];              /* 108-115 */
    47     char gid[8];              /* 116-123 */
    48     char size[12];            /* 124-135 */
    49     char mtime[12];           /* 136-147 */
    50     char chksum[8];           /* 148-155 */
    51     char typeflag;            /* 156-156 */
    52     char linkname[NAME_SIZE]; /* 157-256 */
    53     char magic[6];            /* 257-262 */
    54     char version[2];          /* 263-264 */
    55     char uname[32];           /* 265-296 */
    56     char gname[32];           /* 297-328 */
    57     char devmajor[8];         /* 329-336 */
    58     char devminor[8];         /* 337-344 */
    59     char prefix[155];         /* 345-499 */
    60     char padding[12];         /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
    61 };
    6250
    6351/*
     
    6654** Even these functions use the xxxHardLinkInfo() functions.
    6755*/
    68 typedef struct HardLinkInfo HardLinkInfo;
    69 struct HardLinkInfo {
    70     HardLinkInfo *next; /* Next entry in list */
    71     dev_t dev;          /* Device number */
    72     ino_t ino;          /* Inode number */
    73     short linkCount;    /* (Hard) Link Count */
    74     char name[1];       /* Start of filename (must be last) */
    75 };
     56typedef struct HardLinkInfo {
     57    struct HardLinkInfo *next; /* Next entry in list */
     58    dev_t dev;                 /* Device number */
     59    ino_t ino;                 /* Inode number */
     60//  short linkCount;           /* (Hard) Link Count */
     61    char name[1];              /* Start of filename (must be last) */
     62} HardLinkInfo;
    7663
    7764/* Some info to be carried along when creating a new tarball */
    78 typedef struct TarBallInfo TarBallInfo;
    79 struct TarBallInfo {
    80     int tarFd;              /* Open-for-write file descriptor
    81                                for the tarball */
    82     struct stat statBuf;    /* Stat info for the tarball, letting
    83                                us know the inode and device that the
    84                                tarball lives, so we can avoid trying
    85                                to include the tarball into itself */
    86     int verboseFlag;        /* Whether to print extra stuff or not */
    87     const llist_t *excludeList; /* List of files to not include */
    88     HardLinkInfo *hlInfoHead;   /* Hard Link Tracking Information */
    89     HardLinkInfo *hlInfo;   /* Hard Link Info for the current file */
    90 };
     65typedef struct TarBallInfo {
     66    int tarFd;                      /* Open-for-write file descriptor
     67                                     * for the tarball */
     68    int verboseFlag;                /* Whether to print extra stuff or not */
     69    const llist_t *excludeList;     /* List of files to not include */
     70    HardLinkInfo *hlInfoHead;       /* Hard Link Tracking Information */
     71    HardLinkInfo *hlInfo;           /* Hard Link Info for the current file */
     72//TODO: save only st_dev + st_ino
     73    struct stat tarFileStatBuf;     /* Stat info for the tarball, letting
     74                                     * us know the inode and device that the
     75                                     * tarball lives, so we can avoid trying
     76                                     * to include the tarball into itself */
     77} TarBallInfo;
    9178
    9279/* A nice enum with all the possible tar file content types */
    93 enum TarFileType {
     80enum {
    9481    REGTYPE = '0',      /* regular file */
    9582    REGTYPE0 = '\0',    /* regular file (ancient bug compat) */
     
    10491    GNULONGNAME = 'L',  /* GNU long (>100 chars) file name */
    10592};
    106 typedef enum TarFileType TarFileType;
    10793
    10894/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
    109 static void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,
     95static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr,
    11096                    struct stat *statbuf,
    11197                    const char *fileName)
     
    119105    hlInfo->dev = statbuf->st_dev;
    120106    hlInfo->ino = statbuf->st_ino;
    121     hlInfo->linkCount = statbuf->st_nlink;
     107//  hlInfo->linkCount = statbuf->st_nlink;
    122108    strcpy(hlInfo->name, fileName);
    123109}
    124110
    125 static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr)
     111static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr)
    126112{
    127113    HardLinkInfo *hlInfo;
     
    139125}
    140126
    141 /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
    142 static HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)
     127/* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */
     128static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf)
    143129{
    144130    while (hlInfo) {
    145         if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev))
     131        if (statbuf->st_ino == hlInfo->ino
     132         && statbuf->st_dev == hlInfo->dev
     133        ) {
     134            DBG("found hardlink:'%s'", hlInfo->name);
    146135            break;
     136        }
    147137        hlInfo = hlInfo->next;
    148138    }
     
    155145static void putOctal(char *cp, int len, off_t value)
    156146{
    157     char tempBuffer[sizeof(off_t)*3+1];
     147    char tempBuffer[sizeof(off_t)*3 + 1];
    158148    char *tempString = tempBuffer;
    159149    int width;
     
    173163#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
    174164
    175 static void chksum_and_xwrite(int fd, struct TarHeader* hp)
     165static void chksum_and_xwrite(int fd, struct tar_header_t* hp)
    176166{
    177167    /* POSIX says that checksum is done on unsigned bytes
     
    215205        "00000000000",
    216206    };
    217     struct TarHeader header;
     207    struct tar_header_t header;
    218208    int size;
    219209
     
    242232
    243233/* Write out a tar header for the specified file/directory/whatever */
    244 void BUG_tar_header_size(void);
    245234static int writeTarHeader(struct TarBallInfo *tbInfo,
    246235        const char *header_name, const char *fileName, struct stat *statbuf)
    247236{
    248     struct TarHeader header;
    249 
    250     if (sizeof(header) != 512)
    251         BUG_tar_header_size();
    252 
    253     memset(&header, 0, sizeof(struct TarHeader));
     237    struct tar_header_t header;
     238
     239    memset(&header, 0, sizeof(header));
    254240
    255241    strncpy(header.name, header_name, sizeof(header.name));
     
    315301         && statbuf->st_size > (off_t)0777777777777LL
    316302        ) {
    317             bb_error_msg_and_die("cannot store file '%s' "
    318                 "of size %"OFF_FMT"d, aborting",
     303            bb_error_msg_and_die("can't store file '%s' "
     304                "of size %"OFF_FMT"u, aborting",
    319305                fileName, statbuf->st_size);
    320306        }
     
    341327        FILE *vbFd = stdout;
    342328
    343         if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */
     329        /* If archive goes to stdout, verbose goes to stderr */
     330        if (tbInfo->tarFd == STDOUT_FILENO)
    344331            vbFd = stderr;
    345332        /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
     
    359346        if (excluded_files->data[0] == '/') {
    360347            if (fnmatch(excluded_files->data, file,
    361                         FNM_PATHNAME | FNM_LEADING_DIR) == 0)
     348                    FNM_PATHNAME | FNM_LEADING_DIR) == 0)
    362349                return 1;
    363350        } else {
     
    365352
    366353            for (p = file; p[0] != '\0'; p++) {
    367                 if ((p == file || p[-1] == '/') && p[0] != '/' &&
    368                     fnmatch(excluded_files->data, p,
    369                             FNM_PATHNAME | FNM_LEADING_DIR) == 0)
     354                if ((p == file || p[-1] == '/')
     355                 && p[0] != '/'
     356                 && fnmatch(excluded_files->data, p,
     357                        FNM_PATHNAME | FNM_LEADING_DIR) == 0
     358                ) {
    370359                    return 1;
     360                }
    371361            }
    372362        }
     
    377367}
    378368#else
    379 #define exclude_file(excluded_files, file) 0
    380 #endif
    381 
    382 static int writeFileToTarball(const char *fileName, struct stat *statbuf,
    383             void *userData, int depth ATTRIBUTE_UNUSED)
     369# define exclude_file(excluded_files, file) 0
     370#endif
     371
     372static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
     373            void *userData, int depth UNUSED_PARAM)
    384374{
    385375    struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
    386376    const char *header_name;
    387377    int inputFileFd = -1;
     378
     379    DBG("writeFileToTarball('%s')", fileName);
     380
     381    /* Strip leading '/' (must be before memorizing hardlink's name) */
     382    header_name = fileName;
     383    while (header_name[0] == '/') {
     384        static smallint warned;
     385
     386        if (!warned) {
     387            bb_error_msg("removing leading '/' from member names");
     388            warned = 1;
     389        }
     390        header_name++;
     391    }
     392
     393    if (header_name[0] == '\0')
     394        return TRUE;
     395
     396    /* It is against the rules to archive a socket */
     397    if (S_ISSOCK(statbuf->st_mode)) {
     398        bb_error_msg("%s: socket ignored", fileName);
     399        return TRUE;
     400    }
    388401
    389402    /*
     
    395408     */
    396409    tbInfo->hlInfo = NULL;
    397     if (statbuf->st_nlink > 1) {
     410    if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) {
     411        DBG("'%s': st_nlink > 1", header_name);
    398412        tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf);
    399         if (tbInfo->hlInfo == NULL)
    400             addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, fileName);
    401     }
    402 
    403     /* It is against the rules to archive a socket */
    404     if (S_ISSOCK(statbuf->st_mode)) {
    405         bb_error_msg("%s: socket ignored", fileName);
    406         return TRUE;
     413        if (tbInfo->hlInfo == NULL) {
     414            DBG("'%s': addHardLinkInfo", header_name);
     415            addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name);
     416        }
    407417    }
    408418
     
    410420     * so check the device and inode to be sure that this particular file isn't
    411421     * the new tarball */
    412     if (tbInfo->statBuf.st_dev == statbuf->st_dev &&
    413         tbInfo->statBuf.st_ino == statbuf->st_ino) {
     422    if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
     423     && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
     424    ) {
    414425        bb_error_msg("%s: file is the archive; skipping", fileName);
    415426        return TRUE;
    416427    }
    417428
    418     header_name = fileName;
    419     while (header_name[0] == '/') {
    420         static smallint warned;
    421 
    422         if (!warned) {
    423             bb_error_msg("removing leading '/' from member names");
    424             warned = 1;
    425         }
    426         header_name++;
    427     }
     429    if (exclude_file(tbInfo->excludeList, header_name))
     430        return SKIP;
    428431
    429432#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
    430     if (strlen(fileName) >= NAME_SIZE) {
     433    if (strlen(header_name) >= NAME_SIZE) {
    431434        bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
    432435        return TRUE;
    433436    }
    434437#endif
    435 
    436     if (header_name[0] == '\0')
    437         return TRUE;
    438 
    439     if (exclude_file(tbInfo->excludeList, header_name))
    440         return SKIP;
    441438
    442439    /* Is this a regular file? */
     
    485482}
    486483
    487 static int writeTarFile(const int tar_fd, const int verboseFlag,
    488     const unsigned long dereferenceFlag, const llist_t *include,
    489     const llist_t *exclude, const int gzip)
    490 {
    491     pid_t gzipPid = 0;
     484#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
     485# if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
     486#  define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
     487# endif
     488/* Don't inline: vfork scares gcc and pessimizes code */
     489static void NOINLINE vfork_compressor(int tar_fd, int gzip)
     490{
     491    pid_t gzipPid;
     492# if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
     493    const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
     494# elif ENABLE_FEATURE_SEAMLESS_GZ
     495    const char *zip_exec = "gzip";
     496# else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
     497    const char *zip_exec = "bzip2";
     498# endif
     499    // On Linux, vfork never unpauses parent early, although standard
     500    // allows for that. Do we want to waste bytes checking for it?
     501# define WAIT_FOR_CHILD 0
     502    volatile int vfork_exec_errno = 0;
     503    struct fd_pair gzipDataPipe;
     504# if WAIT_FOR_CHILD
     505    struct fd_pair gzipStatusPipe;
     506    xpiped_pair(gzipStatusPipe);
     507# endif
     508    xpiped_pair(gzipDataPipe);
     509
     510    signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
     511
     512# if defined(__GNUC__) && __GNUC__
     513    /* Avoid vfork clobbering */
     514    (void) &zip_exec;
     515# endif
     516
     517    gzipPid = xvfork();
     518
     519    if (gzipPid == 0) {
     520        /* child */
     521        /* NB: close _first_, then move fds! */
     522        close(gzipDataPipe.wr);
     523# if WAIT_FOR_CHILD
     524        close(gzipStatusPipe.rd);
     525        /* gzipStatusPipe.wr will close only on exec -
     526         * parent waits for this close to happen */
     527        fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC);
     528# endif
     529        xmove_fd(gzipDataPipe.rd, 0);
     530        xmove_fd(tar_fd, 1);
     531        /* exec gzip/bzip2 program/applet */
     532        BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
     533        vfork_exec_errno = errno;
     534        _exit(EXIT_FAILURE);
     535    }
     536
     537    /* parent */
     538    xmove_fd(gzipDataPipe.wr, tar_fd);
     539    close(gzipDataPipe.rd);
     540# if WAIT_FOR_CHILD
     541    close(gzipStatusPipe.wr);
     542    while (1) {
     543        char buf;
     544        int n;
     545
     546        /* Wait until child execs (or fails to) */
     547        n = full_read(gzipStatusPipe.rd, &buf, 1);
     548        if (n < 0 /* && errno == EAGAIN */)
     549            continue;   /* try it again */
     550    }
     551    close(gzipStatusPipe.rd);
     552# endif
     553    if (vfork_exec_errno) {
     554        errno = vfork_exec_errno;
     555        bb_perror_msg_and_die("can't execute '%s'", zip_exec);
     556    }
     557}
     558#endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
     559
     560
     561/* gcc 4.2.1 inlines it, making code bigger */
     562static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
     563    int dereferenceFlag, const llist_t *include,
     564    const llist_t *exclude, int gzip)
     565{
    492566    int errorFlag = FALSE;
    493567    struct TarBallInfo tbInfo;
    494568
    495569    tbInfo.hlInfoHead = NULL;
    496 
    497     fchmod(tar_fd, 0644);
    498570    tbInfo.tarFd = tar_fd;
    499571    tbInfo.verboseFlag = verboseFlag;
     
    501573    /* Store the stat info for the tarball's file, so
    502574     * can avoid including the tarball into itself....  */
    503     if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
    504         bb_perror_msg_and_die("cannot stat tar file");
    505 
    506     if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) {
    507         int gzipDataPipe[2] = { -1, -1 };
    508         int gzipStatusPipe[2] = { -1, -1 };
    509         volatile int vfork_exec_errno = 0;
    510         const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
    511 
    512         xpipe(gzipDataPipe);
    513         xpipe(gzipStatusPipe);
    514 
    515         signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
    516 
    517 #if defined(__GNUC__) && __GNUC__
    518         /* Avoid vfork clobbering */
    519         (void) &include;
    520         (void) &errorFlag;
    521         (void) &zip_exec;
    522 #endif
    523 
    524         gzipPid = vfork();
    525 
    526         if (gzipPid == 0) {
    527             dup2(gzipDataPipe[0], 0);
    528             close(gzipDataPipe[1]);
    529 
    530             dup2(tbInfo.tarFd, 1);
    531 
    532             close(gzipStatusPipe[0]);
    533             fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC);  /* close on exec shows success */
    534 
    535             BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
    536             vfork_exec_errno = errno;
    537 
    538             close(gzipStatusPipe[1]);
    539             exit(-1);
    540         } else if (gzipPid > 0) {
    541             close(gzipDataPipe[0]);
    542             close(gzipStatusPipe[1]);
    543 
    544             while (1) {
    545                 char buf;
    546 
    547                 int n = full_read(gzipStatusPipe[0], &buf, 1);
    548 
    549                 if (n == 0 && vfork_exec_errno != 0) {
    550                     errno = vfork_exec_errno;
    551                     bb_perror_msg_and_die("cannot exec %s", zip_exec);
    552                 } else if ((n < 0) && (errno == EAGAIN || errno == EINTR))
    553                     continue;   /* try it again */
    554                 break;
    555             }
    556             close(gzipStatusPipe[0]);
    557 
    558             tbInfo.tarFd = gzipDataPipe[1];
    559         } else bb_perror_msg_and_die("vfork gzip");
    560     }
     575    xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file");
     576
     577#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
     578    if (gzip)
     579        vfork_compressor(tbInfo.tarFd, gzip);
     580#endif
    561581
    562582    tbInfo.excludeList = exclude;
     
    566586        if (!recursive_action(include->data, ACTION_RECURSE |
    567587                (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
    568                 writeFileToTarball, writeFileToTarball, &tbInfo, 0))
    569         {
     588                writeFileToTarball, writeFileToTarball, &tbInfo, 0)
     589        ) {
    570590            errorFlag = TRUE;
    571591        }
     
    591611        bb_error_msg("error exit delayed from previous errors");
    592612
    593     if (gzipPid) {
     613#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
     614    if (gzip) {
    594615        int status;
    595         if (waitpid(gzipPid, &status, 0) == -1)
     616        if (safe_waitpid(-1, &status, 0) == -1)
    596617            bb_perror_msg("waitpid");
    597618        else if (!WIFEXITED(status) || WEXITSTATUS(status))
     
    599620            errorFlag = TRUE;
    600621    }
     622#endif
    601623    return errorFlag;
    602624}
    603625#else
    604 int writeTarFile(const int tar_fd, const int verboseFlag,
    605     const unsigned long dereferenceFlag, const llist_t *include,
    606     const llist_t *exclude, const int gzip);
     626int writeTarFile(int tar_fd, int verboseFlag,
     627    int dereferenceFlag, const llist_t *include,
     628    const llist_t *exclude, int gzip);
    607629#endif /* FEATURE_TAR_CREATE */
    608630
     
    611633{
    612634    FILE *src_stream;
    613     llist_t *cur = list;
    614     llist_t *tmp;
    615635    char *line;
    616636    llist_t *newlist = NULL;
    617637
    618     while (cur) {
    619         src_stream = xfopen(cur->data, "r");
    620         tmp = cur;
    621         cur = cur->link;
    622         free(tmp);
    623         while ((line = xmalloc_getline(src_stream)) != NULL) {
     638    while (list) {
     639        src_stream = xfopen_for_read(llist_pop(&list));
     640        while ((line = xmalloc_fgetline(src_stream)) != NULL) {
    624641            /* kill trailing '/' unless the string is just "/" */
    625642            char *cp = last_char_is(line, '/');
     
    633650}
    634651#else
    635 #define append_file_list_to_list(x) 0
    636 #endif
    637 
    638 #if ENABLE_FEATURE_TAR_COMPRESS
    639 static char get_header_tar_Z(archive_handle_t *archive_handle)
     652# define append_file_list_to_list(x) 0
     653#endif
     654
     655#if ENABLE_FEATURE_SEAMLESS_Z
     656static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
    640657{
    641658    /* Can't lseek over pipes */
     
    649666    }
    650667
    651     archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress, "uncompress", "uncompress", "-cf", "-", NULL);
     668    open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
    652669    archive_handle->offset = 0;
    653670    while (get_header_tar(archive_handle) == EXIT_SUCCESS)
    654         /* nothing */;
     671        continue;
    655672
    656673    /* Can only do one file at a time */
     
    658675}
    659676#else
    660 #define get_header_tar_Z NULL
     677# define get_header_tar_Z NULL
    661678#endif
    662679
     
    671688
    672689    /* Wait for any child without blocking */
    673     if (waitpid(-1, &status, WNOHANG) < 0)
     690    if (wait_any_nohang(&status) < 0)
    674691        /* wait failed?! I'm confused... */
    675692        return;
    676693
    677     if (WIFEXITED(status) && WEXITSTATUS(status)==0)
     694    if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
    678695        /* child exited with 0 */
    679696        return;
     
    684701#endif
    685702
     703//usage:#define tar_trivial_usage
     704//usage:       "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z")
     705//usage:    IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a")
     706//usage:    IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] "
     707//usage:    IF_FEATURE_TAR_FROM("[-X FILE] ")
     708//usage:       "[-f TARFILE] [-C DIR] [FILE]..."
     709//usage:#define tar_full_usage "\n\n"
     710//usage:    IF_FEATURE_TAR_CREATE("Create, extract, ")
     711//usage:    IF_NOT_FEATURE_TAR_CREATE("Extract ")
     712//usage:    "or list files from a tar file\n"
     713//usage:     "\nOperation:"
     714//usage:    IF_FEATURE_TAR_CREATE(
     715//usage:     "\n    c   Create"
     716//usage:    )
     717//usage:     "\n    x   Extract"
     718//usage:     "\n    t   List"
     719//usage:     "\nOptions:"
     720//usage:     "\n    f   Name of TARFILE ('-' for stdin/out)"
     721//usage:     "\n    C   Change to DIR before operation"
     722//usage:     "\n    v   Verbose"
     723//usage:    IF_FEATURE_SEAMLESS_GZ(
     724//usage:     "\n    z   (De)compress using gzip"
     725//usage:    )
     726//usage:    IF_FEATURE_SEAMLESS_BZ2(
     727//usage:     "\n    j   (De)compress using bzip2"
     728//usage:    )
     729//usage:    IF_FEATURE_SEAMLESS_LZMA(
     730//usage:     "\n    a   (De)compress using lzma"
     731//usage:    )
     732//usage:    IF_FEATURE_SEAMLESS_Z(
     733//usage:     "\n    Z   (De)compress using compress"
     734//usage:    )
     735//usage:     "\n    O   Extract to stdout"
     736//usage:    IF_FEATURE_TAR_CREATE(
     737//usage:     "\n    h   Follow symlinks"
     738//usage:    )
     739//usage:    IF_FEATURE_TAR_NOPRESERVE_TIME(
     740//usage:     "\n    m   Don't restore mtime"
     741//usage:    )
     742//usage:    IF_FEATURE_TAR_FROM(
     743//usage:    IF_FEATURE_TAR_LONG_OPTIONS(
     744//usage:     "\n    exclude File to exclude"
     745//usage:    )
     746//usage:     "\n    X   File with names to exclude"
     747//usage:     "\n    T   File with names to include"
     748//usage:    )
     749//usage:
     750//usage:#define tar_example_usage
     751//usage:       "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
     752//usage:       "$ tar -cf /tmp/tarball.tar /usr/local\n"
     753
     754// Supported but aren't in --help:
     755//  o   no-same-owner
     756//  p   same-permissions
     757//  k   keep-old
     758//  numeric-owner
     759//  no-same-permissions
     760//  overwrite
     761//IF_FEATURE_TAR_TO_COMMAND(
     762//  to-command
     763//)
     764
    686765enum {
    687     OPTBIT_KEEP_OLD = 7,
    688     USE_FEATURE_TAR_CREATE(  OPTBIT_CREATE      ,)
    689     USE_FEATURE_TAR_CREATE(  OPTBIT_DEREFERENCE ,)
    690     USE_FEATURE_TAR_BZIP2(   OPTBIT_BZIP2       ,)
    691     USE_FEATURE_TAR_LZMA(    OPTBIT_LZMA        ,)
    692     USE_FEATURE_TAR_FROM(    OPTBIT_INCLUDE_FROM,)
    693     USE_FEATURE_TAR_FROM(    OPTBIT_EXCLUDE_FROM,)
    694     USE_FEATURE_TAR_GZIP(    OPTBIT_GZIP        ,)
    695     USE_FEATURE_TAR_COMPRESS(OPTBIT_COMPRESS    ,)
    696     OPTBIT_NOPRESERVE_OWN,
     766    OPTBIT_KEEP_OLD = 8,
     767    IF_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
     768    IF_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
     769    IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
     770    IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
     771    IF_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
     772    IF_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
     773    IF_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
     774    IF_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,) // 16th bit
     775    IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,)
     776#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     777    IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND   ,)
     778    OPTBIT_NUMERIC_OWNER,
    697779    OPTBIT_NOPRESERVE_PERM,
     780    OPTBIT_OVERWRITE,
     781#endif
    698782    OPT_TEST         = 1 << 0, // t
    699783    OPT_EXTRACT      = 1 << 1, // x
     
    701785    OPT_TARNAME      = 1 << 3, // f
    702786    OPT_2STDOUT      = 1 << 4, // O
    703     OPT_P            = 1 << 5, // p
    704     OPT_VERBOSE      = 1 << 6, // v
    705     OPT_KEEP_OLD     = 1 << 7, // k
    706     OPT_CREATE       = USE_FEATURE_TAR_CREATE(  (1<<OPTBIT_CREATE      )) + 0, // c
    707     OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(  (1<<OPTBIT_DEREFERENCE )) + 0, // h
    708     OPT_BZIP2        = USE_FEATURE_TAR_BZIP2(   (1<<OPTBIT_BZIP2       )) + 0, // j
    709     OPT_LZMA         = USE_FEATURE_TAR_LZMA(    (1<<OPTBIT_LZMA        )) + 0, // a
    710     OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(    (1<<OPTBIT_INCLUDE_FROM)) + 0, // T
    711     OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(    (1<<OPTBIT_EXCLUDE_FROM)) + 0, // X
    712     OPT_GZIP         = USE_FEATURE_TAR_GZIP(    (1<<OPTBIT_GZIP        )) + 0, // z
    713     OPT_COMPRESS     = USE_FEATURE_TAR_COMPRESS((1<<OPTBIT_COMPRESS    )) + 0, // Z
    714     OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
    715     OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
     787    OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner
     788    OPT_P            = 1 << 6, // p
     789    OPT_VERBOSE      = 1 << 7, // v
     790    OPT_KEEP_OLD     = 1 << 8, // k
     791    OPT_CREATE       = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
     792    OPT_DEREFERENCE  = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
     793    OPT_BZIP2        = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
     794    OPT_LZMA         = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
     795    OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
     796    OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
     797    OPT_GZIP         = IF_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
     798    OPT_COMPRESS     = IF_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
     799    OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m
     800    OPT_2COMMAND        = IF_FEATURE_TAR_TO_COMMAND(  (1 << OPTBIT_2COMMAND       )) + 0, // to-command
     801    OPT_NUMERIC_OWNER   = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER  )) + 0, // numeric-owner
     802    OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
     803    OPT_OVERWRITE       = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE      )) + 0, // overwrite
    716804};
    717805#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     
    722810    "file\0"                Required_argument "f"
    723811    "to-stdout\0"           No_argument       "O"
     812    /* do not restore owner */
     813    /* Note: GNU tar handles 'o' as no-same-owner only on extract,
     814     * on create, 'o' is --old-archive. We do not support --old-archive. */
     815    "no-same-owner\0"       No_argument       "o"
    724816    "same-permissions\0"    No_argument       "p"
    725817    "verbose\0"             No_argument       "v"
     
    729821    "dereference\0"         No_argument       "h"
    730822# endif
    731 # if ENABLE_FEATURE_TAR_BZIP2
     823# if ENABLE_FEATURE_SEAMLESS_BZ2
    732824    "bzip2\0"               No_argument       "j"
    733825# endif
    734 # if ENABLE_FEATURE_TAR_LZMA
     826# if ENABLE_FEATURE_SEAMLESS_LZMA
    735827    "lzma\0"                No_argument       "a"
    736828# endif
     
    739831    "exclude-from\0"        Required_argument "X"
    740832# endif
    741 # if ENABLE_FEATURE_TAR_GZIP
     833# if ENABLE_FEATURE_SEAMLESS_GZ
    742834    "gzip\0"                No_argument       "z"
    743835# endif
    744 # if ENABLE_FEATURE_TAR_COMPRESS
     836# if ENABLE_FEATURE_SEAMLESS_Z
    745837    "compress\0"            No_argument       "Z"
    746838# endif
    747     "no-same-owner\0"       No_argument       "\xfd"
    748     "no-same-permissions\0" No_argument       "\xfe"
     839# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME
     840    "touch\0"               No_argument       "m"
     841# endif
     842# if ENABLE_FEATURE_TAR_TO_COMMAND
     843    "to-command\0"      Required_argument "\xfb"
     844# endif
     845    /* use numeric uid/gid from tar header, not textual */
     846    "numeric-owner\0"       No_argument       "\xfc"
     847    /* do not restore mode */
     848    "no-same-permissions\0" No_argument       "\xfd"
     849    /* on unpack, open with O_TRUNC and !O_EXCL */
     850    "overwrite\0"           No_argument       "\xfe"
    749851    /* --exclude takes next bit position in option mask, */
    750     /* therefore we have to either put it _after_ --no-same-perm */
    751     /* or add OPT[BIT]_EXCLUDE before OPT[BIT]_NOPRESERVE_OWN */
     852    /* therefore we have to put it _after_ --no-same-permissions */
    752853# if ENABLE_FEATURE_TAR_FROM
    753854    "exclude\0"             Required_argument "\xff"
     
    756857#endif
    757858
    758 int tar_main(int argc, char **argv);
    759 int tar_main(int argc, char **argv)
    760 {
    761     char (*get_header_ptr)(archive_handle_t *) = get_header_tar;
     859int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     860int tar_main(int argc UNUSED_PARAM, char **argv)
     861{
     862    char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
    762863    archive_handle_t *tar_handle;
    763864    char *base_dir = NULL;
     
    771872    /* Initialise default values */
    772873    tar_handle = init_handle();
    773     tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS
    774                       | ARCHIVE_PRESERVE_DATE
    775                       | ARCHIVE_EXTRACT_UNCONDITIONAL;
     874    tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS
     875                         | ARCHIVE_RESTORE_DATE
     876                         | ARCHIVE_UNLINK_OLD;
     877
     878    /* Apparently only root's tar preserves perms (see bug 3844) */
     879    if (getuid() != 0)
     880        tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
    776881
    777882    /* Prepend '-' to the first argument if required */
     
    783888        "\xff::" // cumulative lists for --exclude
    784889#endif
    785         USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
    786         USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
    787         SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
     890        IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
     891        IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
     892        IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
    788893#if ENABLE_FEATURE_TAR_LONG_OPTIONS
    789894    applet_long_options = tar_longopts;
    790895#endif
     896#if ENABLE_DESKTOP
     897    if (argv[1] && argv[1][0] != '-') {
     898        /* Compat:
     899         * 1st argument without dash handles options with parameters
     900         * differently from dashed one: it takes *next argv[i]*
     901         * as paramenter even if there are more chars in 1st argument:
     902         *  "tar fx TARFILE" - "x" is not taken as f's param
     903         *  but is interpreted as -x option
     904         *  "tar -xf TARFILE" - dashed equivalent of the above
     905         *  "tar -fx ..." - "x" is taken as f's param
     906         * getopt32 wouldn't handle 1st command correctly.
     907         * Unfortunately, people do use such commands.
     908         * We massage argv[1] to work around it by moving 'f'
     909         * to the end of the string.
     910         * More contrived "tar fCx TARFILE DIR" still fails,
     911         * but such commands are much less likely to be used.
     912         */
     913        char *f = strchr(argv[1], 'f');
     914        if (f) {
     915            while (f[1] != '\0') {
     916                *f = f[1];
     917                f++;
     918            }
     919            *f = 'f';
     920        }
     921    }
     922#endif
    791923    opt = getopt32(argv,
    792         "txC:f:Opvk"
    793         USE_FEATURE_TAR_CREATE(  "ch"  )
    794         USE_FEATURE_TAR_BZIP2(   "j"   )
    795         USE_FEATURE_TAR_LZMA(    "a"   )
    796         USE_FEATURE_TAR_FROM(    "T:X:")
    797         USE_FEATURE_TAR_GZIP(    "z"   )
    798         USE_FEATURE_TAR_COMPRESS("Z"   )
     924        "txC:f:Oopvk"
     925        IF_FEATURE_TAR_CREATE(   "ch"  )
     926        IF_FEATURE_SEAMLESS_BZ2( "j"   )
     927        IF_FEATURE_SEAMLESS_LZMA("a"   )
     928        IF_FEATURE_TAR_FROM(     "T:X:")
     929        IF_FEATURE_SEAMLESS_GZ(  "z"   )
     930        IF_FEATURE_SEAMLESS_Z(   "Z"   )
     931        IF_FEATURE_TAR_NOPRESERVE_TIME("m")
    799932        , &base_dir // -C dir
    800933        , &tar_filename // -f filename
    801         USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
    802         USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
     934        IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
     935        IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
     936        IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command
    803937#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
    804938        , &excludes // --exclude
     
    807941        , &verboseFlag // combined count for -t and -v
    808942        );
     943    //bb_error_msg("opt:%08x", opt);
     944    argv += optind;
    809945
    810946    if (verboseFlag) tar_handle->action_header = header_verbose_list;
     
    817953        tar_handle->action_data = data_extract_to_stdout;
    818954
     955    if (opt & OPT_2COMMAND) {
     956        putenv((char*)"TAR_FILETYPE=f");
     957        signal(SIGPIPE, SIG_IGN);
     958        tar_handle->action_data = data_extract_to_command;
     959    }
     960
    819961    if (opt & OPT_KEEP_OLD)
    820         tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
    821 
    822     if (opt & OPT_NOPRESERVE_OWN)
    823         tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN;
     962        tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
     963
     964    if (opt & OPT_NUMERIC_OWNER)
     965        tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
     966
     967    if (opt & OPT_NOPRESERVE_OWNER)
     968        tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER;
    824969
    825970    if (opt & OPT_NOPRESERVE_PERM)
    826         tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM;
     971        tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM;
     972
     973    if (opt & OPT_OVERWRITE) {
     974        tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD;
     975        tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
     976    }
    827977
    828978    if (opt & OPT_GZIP)
     
    838988        get_header_ptr = get_header_tar_Z;
    839989
     990    if (opt & OPT_NOPRESERVE_TIME)
     991        tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
     992
    840993#if ENABLE_FEATURE_TAR_FROM
    841994    tar_handle->reject = append_file_list_to_list(tar_handle->reject);
    842 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
     995# if ENABLE_FEATURE_TAR_LONG_OPTIONS
    843996    /* Append excludes to reject */
    844997    while (excludes) {
     
    8481001        excludes = next;
    8491002    }
    850 #endif
     1003# endif
    8511004    tar_handle->accept = append_file_list_to_list(tar_handle->accept);
    8521005#endif
    8531006
    854     /* Check if we are reading from stdin */
    855     if (argv[optind] && *argv[optind] == '-') {
    856         /* Default is to read from stdin, so just skip to next arg */
    857         optind++;
    858     }
    859 
    8601007    /* Setup an array of filenames to work with */
    861     /* TODO: This is the same as in ar, separate function ? */
    862     while (optind < argc) {
     1008    /* TODO: This is the same as in ar, make a separate function? */
     1009    while (*argv) {
    8631010        /* kill trailing '/' unless the string is just "/" */
    864         char *cp = last_char_is(argv[optind], '/');
    865         if (cp > argv[optind])
     1011        char *cp = last_char_is(*argv, '/');
     1012        if (cp > *argv)
    8661013            *cp = '\0';
    867         llist_add_to_end(&tar_handle->accept, argv[optind]);
    868         optind++;
     1014        llist_add_to_end(&tar_handle->accept, *argv);
     1015        argv++;
    8691016    }
    8701017
     
    8741021    /* Open the tar file */
    8751022    {
    876         FILE *tar_stream;
    877         int flags;
     1023        int tar_fd = STDIN_FILENO;
     1024        int flags = O_RDONLY;
    8781025
    8791026        if (opt & OPT_CREATE) {
    880             /* Make sure there is at least one file to tar up. */
     1027            /* Make sure there is at least one file to tar up */
    8811028            if (tar_handle->accept == NULL)
    8821029                bb_error_msg_and_die("empty archive");
    8831030
    884             tar_stream = stdout;
     1031            tar_fd = STDOUT_FILENO;
    8851032            /* Mimicking GNU tar 1.15.1: */
    886             flags = O_WRONLY|O_CREAT|O_TRUNC;
    887         /* was doing unlink; open(O_WRONLY|O_CREAT|O_EXCL); why? */
    888         } else {
    889             tar_stream = stdin;
    890             flags = O_RDONLY;
     1033            flags = O_WRONLY | O_CREAT | O_TRUNC;
    8911034        }
    8921035
    8931036        if (LONE_DASH(tar_filename)) {
    894             tar_handle->src_fd = fileno(tar_stream);
     1037            tar_handle->src_fd = tar_fd;
    8951038            tar_handle->seek = seek_by_read;
    8961039        } else {
    897             tar_handle->src_fd = xopen(tar_filename, flags);
     1040            if (ENABLE_FEATURE_TAR_AUTODETECT
     1041             && flags == O_RDONLY
     1042             && get_header_ptr == get_header_tar
     1043            ) {
     1044                tar_handle->src_fd = open_zipped(tar_filename);
     1045                if (tar_handle->src_fd < 0)
     1046                    bb_perror_msg_and_die("can't open '%s'", tar_filename);
     1047            } else {
     1048                tar_handle->src_fd = xopen(tar_filename, flags);
     1049            }
    8981050        }
    8991051    }
     
    9071059#endif
    9081060
    909     /* create an archive */
     1061    /* Create an archive */
    9101062    if (opt & OPT_CREATE) {
     1063#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
    9111064        int zipMode = 0;
    912         if (ENABLE_FEATURE_TAR_GZIP && get_header_ptr == get_header_tar_gz)
     1065        if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP))
    9131066            zipMode = 1;
    914         if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2)
     1067        if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2))
    9151068            zipMode = 2;
     1069#endif
    9161070        /* NB: writeTarFile() closes tar_handle->src_fd */
    9171071        return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
     
    9211075
    9221076    while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
    923         /* nothing */;
     1077        continue;
    9241078
    9251079    /* Check that every file that should have been extracted was */
Note: See TracChangeset for help on using the changeset viewer.