Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/archival/tar.c


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

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

    r821 r1770  
    2424 */
    2525
    26 #include <fcntl.h>
     26#include <fnmatch.h>
    2727#include <getopt.h>
    28 #include <search.h>
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <unistd.h>
    32 #include <fnmatch.h>
    33 #include <string.h>
    34 #include <errno.h>
    35 #include <signal.h>
    36 #include <sys/wait.h>
    37 #include <sys/socket.h>
    38 #include <sys/sysmacros.h>     /* major() and minor() */
     28#include "libbb.h"
    3929#include "unarchive.h"
    40 #include "busybox.h"
    41 
    42 #ifdef CONFIG_FEATURE_TAR_CREATE
     30
     31#define block_buf bb_common_bufsiz1
     32
     33#if ENABLE_FEATURE_TAR_CREATE
    4334
    4435/* Tar file constants  */
     
    4738
    4839/* POSIX tar Header Block, from POSIX 1003.1-1990  */
    49 #define NAME_SIZE           100
    50 struct TarHeader {      /* byte offset */
    51     char name[NAME_SIZE];   /*   0-99 */
    52     char mode[8];       /* 100-107 */
    53     char uid[8];        /* 108-115 */
    54     char gid[8];        /* 116-123 */
    55     char size[12];      /* 124-135 */
    56     char mtime[12];     /* 136-147 */
    57     char chksum[8];     /* 148-155 */
    58     char typeflag;      /* 156-156 */
    59     char linkname[NAME_SIZE];   /* 157-256 */
    60     char magic[6];      /* 257-262 */
    61     char version[2];    /* 263-264 */
    62     char uname[32];     /* 265-296 */
    63     char gname[32];     /* 297-328 */
    64     char devmajor[8];   /* 329-336 */
    65     char devminor[8];   /* 337-344 */
    66     char prefix[155];   /* 345-499 */
    67     char padding[12];   /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */
     40#define NAME_SIZE      100
     41#define NAME_SIZE_STR "100"
     42typedef struct TarHeader TarHeader;
     43struct 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) */
    6861};
    69 typedef struct TarHeader TarHeader;
    7062
    7163/*
    72 ** writeTarFile(),  writeFileToTarball(), and writeTarHeader() are
     64** writeTarFile(), writeFileToTarball(), and writeTarHeader() are
    7365** the only functions that deal with the HardLinkInfo structure.
    7466** Even these functions use the xxxHardLinkInfo() functions.
     
    8476
    8577/* Some info to be carried along when creating a new tarball */
     78typedef struct TarBallInfo TarBallInfo;
    8679struct TarBallInfo {
    87     char *fileName;         /* File name of the tarball */
    8880    int tarFd;              /* Open-for-write file descriptor
    8981                               for the tarball */
     
    9789    HardLinkInfo *hlInfo;   /* Hard Link Info for the current file */
    9890};
    99 typedef struct TarBallInfo TarBallInfo;
    10091
    10192/* A nice enum with all the possible tar file content types */
     
    116107
    117108/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
    118 static inline void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,
     109static void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr,
    119110                    struct stat *statbuf,
    120                     const char *name)
     111                    const char *fileName)
    121112{
    122113    /* Note: hlInfoHeadPtr can never be NULL! */
    123114    HardLinkInfo *hlInfo;
    124115
    125     hlInfo = (HardLinkInfo *) xmalloc(sizeof(HardLinkInfo) + strlen(name));
     116    hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName));
    126117    hlInfo->next = *hlInfoHeadPtr;
    127118    *hlInfoHeadPtr = hlInfo;
     
    129120    hlInfo->ino = statbuf->st_ino;
    130121    hlInfo->linkCount = statbuf->st_nlink;
    131     strcpy(hlInfo->name, name);
     122    strcpy(hlInfo->name, fileName);
    132123}
    133124
    134125static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr)
    135126{
    136     HardLinkInfo *hlInfo = NULL;
    137     HardLinkInfo *hlInfoNext = NULL;
     127    HardLinkInfo *hlInfo;
     128    HardLinkInfo *hlInfoNext;
    138129
    139130    if (hlInfoHeadPtr) {
     
    146137        *hlInfoHeadPtr = NULL;
    147138    }
    148     return;
    149139}
    150140
    151141/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */
    152 static inline HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)
     142static HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf)
    153143{
    154144    while (hlInfo) {
     
    157147        hlInfo = hlInfo->next;
    158148    }
    159     return (hlInfo);
     149    return hlInfo;
    160150}
    161151
    162152/* Put an octal string into the specified buffer.
    163  * The number is zero and space padded and possibly null padded.
    164  * Returns TRUE if successful.  */
    165 static int putOctal(char *cp, int len, long value)
    166 {
    167     int tempLength;
    168     char tempBuffer[32];
     153 * The number is zero padded and possibly null terminated.
     154 * Stores low-order bits only if whole value does not fit. */
     155static void putOctal(char *cp, int len, off_t value)
     156{
     157    char tempBuffer[sizeof(off_t)*3+1];
    169158    char *tempString = tempBuffer;
    170 
    171     /* Create a string of the specified length with an initial space,
    172      * leading zeroes and the octal number, and a trailing null.  */
    173     sprintf(tempString, "%0*lo", len - 1, value);
    174 
    175     /* If the string is too large, suppress the leading space. */
    176     tempLength = strlen(tempString) + 1;
    177     if (tempLength > len) {
    178         tempLength--;
     159    int width;
     160
     161    width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value);
     162    tempString += (width - len);
     163
     164    /* If string has leading zeroes, we can drop one */
     165    /* and field will have trailing '\0' */
     166    /* (increases chances of compat with other tars) */
     167    if (tempString[0] == '0')
    179168        tempString++;
    180     }
    181 
    182     /* If the string is still too large, suppress the trailing null.  */
    183     if (tempLength > len)
    184         tempLength--;
    185 
    186     /* If the string is still too large, fail.  */
    187     if (tempLength > len)
    188         return FALSE;
    189 
    190     /* Copy the string to the field.  */
     169
     170    /* Copy the string to the field */
    191171    memcpy(cp, tempString, len);
    192 
    193     return TRUE;
    194 }
     172}
     173#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b))
     174
     175static void chksum_and_xwrite(int fd, struct TarHeader* hp)
     176{
     177    /* POSIX says that checksum is done on unsigned bytes
     178     * (Sun and HP-UX gets it wrong... more details in
     179     * GNU tar source) */
     180    const unsigned char *cp;
     181    int chksum, size;
     182
     183    strcpy(hp->magic, "ustar  ");
     184
     185    /* Calculate and store the checksum (i.e., the sum of all of the bytes of
     186     * the header).  The checksum field must be filled with blanks for the
     187     * calculation.  The checksum field is formatted differently from the
     188     * other fields: it has 6 digits, a null, then a space -- rather than
     189     * digits, followed by a null like the other fields... */
     190    memset(hp->chksum, ' ', sizeof(hp->chksum));
     191    cp = (const unsigned char *) hp;
     192    chksum = 0;
     193    size = sizeof(*hp);
     194    do { chksum += *cp++; } while (--size);
     195    putOctal(hp->chksum, sizeof(hp->chksum)-1, chksum);
     196
     197    /* Now write the header out to disk */
     198    xwrite(fd, hp, sizeof(*hp));
     199}
     200
     201#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     202static void writeLongname(int fd, int type, const char *name, int dir)
     203{
     204    static const struct {
     205        char mode[8];             /* 100-107 */
     206        char uid[8];              /* 108-115 */
     207        char gid[8];              /* 116-123 */
     208        char size[12];            /* 124-135 */
     209        char mtime[12];           /* 136-147 */
     210    } prefilled = {
     211        "0000000",
     212        "0000000",
     213        "0000000",
     214        "00000000000",
     215        "00000000000",
     216    };
     217    struct TarHeader header;
     218    int size;
     219
     220    dir = !!dir; /* normalize: 0/1 */
     221    size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */
     222    /* + dir: account for possible '/' */
     223
     224    memset(&header, 0, sizeof(header));
     225    strcpy(header.name, "././@LongLink");
     226    memcpy(header.mode, prefilled.mode, sizeof(prefilled));
     227    PUT_OCTAL(header.size, size);
     228    header.typeflag = type;
     229    chksum_and_xwrite(fd, &header);
     230
     231    /* Write filename[/] and pad the block. */
     232    /* dir=0: writes 'name<NUL>', pads */
     233    /* dir=1: writes 'name', writes '/<NUL>', pads */
     234    dir *= 2;
     235    xwrite(fd, name, size - dir);
     236    xwrite(fd, "/", dir);
     237    size = (-size) & (TAR_BLOCK_SIZE-1);
     238    memset(&header, 0, size);
     239    xwrite(fd, &header, size);
     240}
     241#endif
    195242
    196243/* Write out a tar header for the specified file/directory/whatever */
    197 static inline int writeTarHeader(struct TarBallInfo *tbInfo,
    198         const char *header_name, const char *real_name, struct stat *statbuf)
    199 {
    200     long chksum = 0;
     244void BUG_tar_header_size(void);
     245static int writeTarHeader(struct TarBallInfo *tbInfo,
     246        const char *header_name, const char *fileName, struct stat *statbuf)
     247{
    201248    struct TarHeader header;
    202     const unsigned char *cp = (const unsigned char *) &header;
    203     ssize_t size = sizeof(struct TarHeader);
    204 
    205     memset(&header, 0, size);
    206 
    207     safe_strncpy(header.name, header_name, sizeof(header.name));
    208 
    209     putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
    210     putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
    211     putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
    212     putOctal(header.size, sizeof(header.size), 0);  /* Regular file size is handled later */
    213     putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
    214     strcpy(header.magic, "ustar  ");
    215 
    216     /* Enter the user and group names (default to root if it fails) */
    217     if (bb_getpwuid(header.uname, statbuf->st_uid, sizeof(header.uname)) == NULL)
    218         strcpy(header.uname, "root");
    219     if (bb_getgrgid(header.gname, statbuf->st_gid, sizeof(header.gname)) == NULL)
    220         strcpy(header.gname, "root");
     249
     250    if (sizeof(header) != 512)
     251        BUG_tar_header_size();
     252
     253    memset(&header, 0, sizeof(struct TarHeader));
     254
     255    strncpy(header.name, header_name, sizeof(header.name));
     256
     257    /* POSIX says to mask mode with 07777. */
     258    PUT_OCTAL(header.mode, statbuf->st_mode & 07777);
     259    PUT_OCTAL(header.uid, statbuf->st_uid);
     260    PUT_OCTAL(header.gid, statbuf->st_gid);
     261    memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */
     262    PUT_OCTAL(header.mtime, statbuf->st_mtime);
     263
     264    /* Enter the user and group names */
     265    safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname));
     266    safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname));
    221267
    222268    if (tbInfo->hlInfo) {
     
    225271        strncpy(header.linkname, tbInfo->hlInfo->name,
    226272                sizeof(header.linkname));
     273#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     274        /* Write out long linkname if needed */
     275        if (header.linkname[sizeof(header.linkname)-1])
     276            writeLongname(tbInfo->tarFd, GNULONGLINK,
     277                    tbInfo->hlInfo->name, 0);
     278#endif
    227279    } else if (S_ISLNK(statbuf->st_mode)) {
    228         char *lpath = xreadlink(real_name);
    229 
    230         if (!lpath)     /* Already printed err msg inside xreadlink() */
    231             return (FALSE);
     280        char *lpath = xmalloc_readlink_or_warn(fileName);
     281        if (!lpath)
     282            return FALSE;
    232283        header.typeflag = SYMTYPE;
    233284        strncpy(header.linkname, lpath, sizeof(header.linkname));
     285#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     286        /* Write out long linkname if needed */
     287        if (header.linkname[sizeof(header.linkname)-1])
     288            writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0);
     289#else
     290        /* If it is larger than 100 bytes, bail out */
     291        if (header.linkname[sizeof(header.linkname)-1]) {
     292            free(lpath);
     293            bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
     294            return FALSE;
     295        }
     296#endif
    234297        free(lpath);
    235298    } else if (S_ISDIR(statbuf->st_mode)) {
    236299        header.typeflag = DIRTYPE;
    237         strncat(header.name, "/", sizeof(header.name));
     300        /* Append '/' only if there is a space for it */
     301        if (!header.name[sizeof(header.name)-1])
     302            header.name[strlen(header.name)] = '/';
    238303    } else if (S_ISCHR(statbuf->st_mode)) {
    239304        header.typeflag = CHRTYPE;
    240         putOctal(header.devmajor, sizeof(header.devmajor),
    241                  major(statbuf->st_rdev));
    242         putOctal(header.devminor, sizeof(header.devminor),
    243                  minor(statbuf->st_rdev));
     305        PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
     306        PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
    244307    } else if (S_ISBLK(statbuf->st_mode)) {
    245308        header.typeflag = BLKTYPE;
    246         putOctal(header.devmajor, sizeof(header.devmajor),
    247                  major(statbuf->st_rdev));
    248         putOctal(header.devminor, sizeof(header.devminor),
    249                  minor(statbuf->st_rdev));
     309        PUT_OCTAL(header.devmajor, major(statbuf->st_rdev));
     310        PUT_OCTAL(header.devminor, minor(statbuf->st_rdev));
    250311    } else if (S_ISFIFO(statbuf->st_mode)) {
    251312        header.typeflag = FIFOTYPE;
    252313    } else if (S_ISREG(statbuf->st_mode)) {
     314        if (sizeof(statbuf->st_size) > 4
     315         && statbuf->st_size > (off_t)0777777777777LL
     316        ) {
     317            bb_error_msg_and_die("cannot store file '%s' "
     318                "of size %"OFF_FMT"d, aborting",
     319                fileName, statbuf->st_size);
     320        }
    253321        header.typeflag = REGTYPE;
    254         putOctal(header.size, sizeof(header.size), statbuf->st_size);
     322        PUT_OCTAL(header.size, statbuf->st_size);
    255323    } else {
    256         bb_error_msg("%s: Unknown file type", real_name);
    257         return (FALSE);
    258     }
    259 
    260     /* Calculate and store the checksum (i.e., the sum of all of the bytes of
    261      * the header).  The checksum field must be filled with blanks for the
    262      * calculation.  The checksum field is formatted differently from the
    263      * other fields: it has [6] digits, a null, then a space -- rather than
    264      * digits, followed by a null like the other fields... */
    265     memset(header.chksum, ' ', sizeof(header.chksum));
    266     cp = (const unsigned char *) &header;
    267     while (size-- > 0)
    268         chksum += *cp++;
    269     putOctal(header.chksum, 7, chksum);
     324        bb_error_msg("%s: unknown file type", fileName);
     325        return FALSE;
     326    }
     327
     328#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
     329    /* Write out long name if needed */
     330    /* (we, like GNU tar, output long linkname *before* long name) */
     331    if (header.name[sizeof(header.name)-1])
     332        writeLongname(tbInfo->tarFd, GNULONGNAME,
     333                header_name, S_ISDIR(statbuf->st_mode));
     334#endif
    270335
    271336    /* Now write the header out to disk */
    272     if ((size =
    273          bb_full_write(tbInfo->tarFd, (char *) &header,
    274                     sizeof(struct TarHeader))) < 0) {
    275         bb_error_msg(bb_msg_io_error, real_name);
    276         return (FALSE);
    277     }
    278     /* Pad the header up to the tar block size */
    279     for (; size < TAR_BLOCK_SIZE; size++) {
    280         write(tbInfo->tarFd, "\0", 1);
    281     }
     337    chksum_and_xwrite(tbInfo->tarFd, &header);
     338
    282339    /* Now do the verbose thing (or not) */
    283 
    284340    if (tbInfo->verboseFlag) {
    285341        FILE *vbFd = stdout;
     
    287343        if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */
    288344            vbFd = stderr;
    289 
    290         fprintf(vbFd, "%s\n", header.name);
    291     }
    292 
    293     return (TRUE);
    294 }
    295 
    296 # ifdef CONFIG_FEATURE_TAR_FROM
    297 static inline int exclude_file(const llist_t *excluded_files, const char *file)
     345        /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */
     346        /* We don't have such excesses here: for us "v" == "vv" */
     347        /* '/' is probably a GNUism */
     348        fprintf(vbFd, "%s%s\n", header_name,
     349                S_ISDIR(statbuf->st_mode) ? "/" : "");
     350    }
     351
     352    return TRUE;
     353}
     354
     355#if ENABLE_FEATURE_TAR_FROM
     356static int exclude_file(const llist_t *excluded_files, const char *file)
    298357{
    299358    while (excluded_files) {
     
    317376    return 0;
    318377}
    319 # else
     378#else
    320379#define exclude_file(excluded_files, file) 0
    321 # endif
     380#endif
    322381
    323382static int writeFileToTarball(const char *fileName, struct stat *statbuf,
    324                               void *userData)
     383            void *userData, int depth ATTRIBUTE_UNUSED)
    325384{
    326385    struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
     
    329388
    330389    /*
    331        ** Check to see if we are dealing with a hard link.
    332        ** If so -
    333        ** Treat the first occurance of a given dev/inode as a file while
    334        ** treating any additional occurances as hard links.  This is done
    335        ** by adding the file information to the HardLinkInfo linked list.
     390     * Check to see if we are dealing with a hard link.
     391     * If so -
     392     * Treat the first occurance of a given dev/inode as a file while
     393     * treating any additional occurances as hard links.  This is done
     394     * by adding the file information to the HardLinkInfo linked list.
    336395     */
    337396    tbInfo->hlInfo = NULL;
     
    345404    if (S_ISSOCK(statbuf->st_mode)) {
    346405        bb_error_msg("%s: socket ignored", fileName);
    347         return (TRUE);
     406        return TRUE;
    348407    }
    349408
     
    354413        tbInfo->statBuf.st_ino == statbuf->st_ino) {
    355414        bb_error_msg("%s: file is the archive; skipping", fileName);
    356         return (TRUE);
     415        return TRUE;
    357416    }
    358417
    359418    header_name = fileName;
    360419    while (header_name[0] == '/') {
    361         static int alreadyWarned = FALSE;
    362 
    363         if (alreadyWarned == FALSE) {
    364             bb_error_msg("Removing leading '/' from member names");
    365             alreadyWarned = TRUE;
     420        static smallint warned;
     421
     422        if (!warned) {
     423            bb_error_msg("removing leading '/' from member names");
     424            warned = 1;
    366425        }
    367426        header_name++;
    368427    }
    369428
     429#if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS
    370430    if (strlen(fileName) >= NAME_SIZE) {
    371         bb_error_msg(bb_msg_name_longer_than_foo, NAME_SIZE);
    372         return (TRUE);
    373     }
     431        bb_error_msg("names longer than "NAME_SIZE_STR" chars not supported");
     432        return TRUE;
     433    }
     434#endif
    374435
    375436    if (header_name[0] == '\0')
    376437        return TRUE;
    377438
    378     if (ENABLE_FEATURE_TAR_FROM &&
    379             exclude_file(tbInfo->excludeList, header_name)) {
     439    if (exclude_file(tbInfo->excludeList, header_name))
    380440        return SKIP;
    381     }
    382441
    383442    /* Is this a regular file? */
    384     if ((tbInfo->hlInfo == NULL) && (S_ISREG(statbuf->st_mode))) {
    385 
     443    if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
    386444        /* open the file we want to archive, and make sure all is well */
    387         if ((inputFileFd = open(fileName, O_RDONLY)) < 0) {
    388             bb_perror_msg("%s: Cannot open", fileName);
    389             return (FALSE);
     445        inputFileFd = open_or_warn(fileName, O_RDONLY);
     446        if (inputFileFd < 0) {
     447            return FALSE;
    390448        }
    391449    }
     
    393451    /* Add an entry to the tarball */
    394452    if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
    395         return (FALSE);
     453        return FALSE;
    396454    }
    397455
    398456    /* If it was a regular file, write out the body */
    399     if (inputFileFd >= 0 ) {
    400         ssize_t readSize = 0;
    401 
    402         /* write the file to the archive */
    403         readSize = bb_copyfd_eof(inputFileFd, tbInfo->tarFd);
     457    if (inputFileFd >= 0) {
     458        size_t readSize;
     459        /* Write the file to the archive. */
     460        /* We record size into header first, */
     461        /* and then write out file. If file shrinks in between, */
     462        /* tar will be corrupted. So we don't allow for that. */
     463        /* NB: GNU tar 1.16 warns and pads with zeroes */
     464        /* or even seeks back and updates header */
     465        bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
     466        ////off_t readSize;
     467        ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
     468        ////if (readSize != statbuf->st_size && readSize >= 0) {
     469        ////    bb_error_msg_and_die("short read from %s, aborting", fileName);
     470        ////}
     471
     472        /* Check that file did not grow in between? */
     473        /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */
     474
    404475        close(inputFileFd);
    405476
    406477        /* Pad the file up to the tar block size */
    407         for (; (readSize % TAR_BLOCK_SIZE) != 0; readSize++)
    408             write(tbInfo->tarFd, "\0", 1);
    409     }
    410 
    411     return (TRUE);
    412 }
    413 
    414 static inline int writeTarFile(const int tar_fd, const int verboseFlag,
     478        /* (a few tricks here in the name of code size) */
     479        readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1);
     480        memset(block_buf, 0, readSize);
     481        xwrite(tbInfo->tarFd, block_buf, readSize);
     482    }
     483
     484    return TRUE;
     485}
     486
     487static int writeTarFile(const int tar_fd, const int verboseFlag,
    415488    const unsigned long dereferenceFlag, const llist_t *include,
    416489    const llist_t *exclude, const int gzip)
    417490{
    418491    pid_t gzipPid = 0;
    419 
    420492    int errorFlag = FALSE;
    421     ssize_t size;
    422493    struct TarBallInfo tbInfo;
    423494
     
    431502     * can avoid including the tarball into itself....  */
    432503    if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0)
    433         bb_perror_msg_and_die("Couldnt stat tar file");
     504        bb_perror_msg_and_die("cannot stat tar file");
    434505
    435506    if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) {
     
    437508        int gzipStatusPipe[2] = { -1, -1 };
    438509        volatile int vfork_exec_errno = 0;
    439         char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
    440 
    441 
    442         if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0)
    443             bb_perror_msg_and_die("create pipe");
    444 
    445         signal(SIGPIPE, SIG_IGN);   /* we only want EPIPE on errors */
    446 
    447 # if __GNUC__
    448             /* Avoid vfork clobbering */
    449             (void) &include;
    450             (void) &errorFlag;
    451             (void) &zip_exec;
    452 # endif
     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
    453523
    454524        gzipPid = vfork();
     
    458528            close(gzipDataPipe[1]);
    459529
    460             if (tbInfo.tarFd != 1)
    461                 dup2(tbInfo.tarFd, 1);
     530            dup2(tbInfo.tarFd, 1);
    462531
    463532            close(gzipStatusPipe[0]);
    464533            fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC);  /* close on exec shows success */
    465534
    466             execlp(zip_exec, zip_exec, "-f", NULL);
     535            BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
    467536            vfork_exec_errno = errno;
    468537
     
    476545                char buf;
    477546
    478                 int n = bb_full_read(gzipStatusPipe[0], &buf, 1);
     547                int n = full_read(gzipStatusPipe[0], &buf, 1);
    479548
    480549                if (n == 0 && vfork_exec_errno != 0) {
    481550                    errno = vfork_exec_errno;
    482                     bb_perror_msg_and_die("Could not exec %s", zip_exec);
     551                    bb_perror_msg_and_die("cannot exec %s", zip_exec);
    483552                } else if ((n < 0) && (errno == EAGAIN || errno == EINTR))
    484553                    continue;   /* try it again */
     
    495564    /* Read the directory/files and iterate over them one at a time */
    496565    while (include) {
    497         if (!recursive_action(include->data, TRUE, dereferenceFlag,
    498                 FALSE, writeFileToTarball, writeFileToTarball, &tbInfo))
     566        if (!recursive_action(include->data, ACTION_RECURSE |
     567                (dereferenceFlag ? ACTION_FOLLOWLINKS : 0),
     568                writeFileToTarball, writeFileToTarball, &tbInfo, 0))
    499569        {
    500570            errorFlag = TRUE;
     
    503573    }
    504574    /* Write two empty blocks to the end of the archive */
    505     for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++)
    506         write(tbInfo.tarFd, "\0", 1);
     575    memset(block_buf, 0, 2*TAR_BLOCK_SIZE);
     576    xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE);
    507577
    508578    /* To be pedantically correct, we would check if the tarball
     
    519589
    520590    if (errorFlag)
    521         bb_error_msg("Error exit delayed from previous errors");
    522 
    523     if (gzipPid && waitpid(gzipPid, NULL, 0)==-1)
    524         bb_error_msg("Couldnt wait");
    525 
    526     return !errorFlag;
     591        bb_error_msg("error exit delayed from previous errors");
     592
     593    if (gzipPid) {
     594        int status;
     595        if (waitpid(gzipPid, &status, 0) == -1)
     596            bb_perror_msg("waitpid");
     597        else if (!WIFEXITED(status) || WEXITSTATUS(status))
     598            /* gzip was killed or has exited with nonzero! */
     599            errorFlag = TRUE;
     600    }
     601    return errorFlag;
    527602}
    528603#else
     
    530605    const unsigned long dereferenceFlag, const llist_t *include,
    531606    const llist_t *exclude, const int gzip);
    532 #endif  /* tar_create */
    533 
    534 #ifdef CONFIG_FEATURE_TAR_FROM
     607#endif /* FEATURE_TAR_CREATE */
     608
     609#if ENABLE_FEATURE_TAR_FROM
    535610static llist_t *append_file_list_to_list(llist_t *list)
    536611{
     
    542617
    543618    while (cur) {
    544         src_stream = bb_xfopen(cur->data, "r");
     619        src_stream = xfopen(cur->data, "r");
    545620        tmp = cur;
    546621        cur = cur->link;
    547622        free(tmp);
    548         while ((line = bb_get_chomped_line_from_file(src_stream)) != NULL)
    549                 llist_add_to(&newlist, line);
     623        while ((line = xmalloc_getline(src_stream)) != NULL) {
     624            /* kill trailing '/' unless the string is just "/" */
     625            char *cp = last_char_is(line, '/');
     626            if (cp > line)
     627                *cp = '\0';
     628            llist_add_to(&newlist, line);
     629        }
    550630        fclose(src_stream);
    551631    }
     
    553633}
    554634#else
    555 #define append_file_list_to_list(x) 0
    556 #endif
    557 
    558 #ifdef CONFIG_FEATURE_TAR_COMPRESS
     635#define append_file_list_to_list(x) 0
     636#endif
     637
     638#if ENABLE_FEATURE_TAR_COMPRESS
    559639static char get_header_tar_Z(archive_handle_t *archive_handle)
    560640{
    561     /* Cant lseek over pipe's */
    562     archive_handle->seek = seek_by_char;
     641    /* Can't lseek over pipes */
     642    archive_handle->seek = seek_by_read;
    563643
    564644    /* do the decompression, and cleanup */
    565     if (bb_xread_char(archive_handle->src_fd) != 0x1f ||
    566         bb_xread_char(archive_handle->src_fd) != 0x9d)
    567     {
    568         bb_error_msg_and_die("Invalid magic");
    569     }
    570 
    571     archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress);
     645    if (xread_char(archive_handle->src_fd) != 0x1f
     646     || xread_char(archive_handle->src_fd) != 0x9d
     647    ) {
     648        bb_error_msg_and_die("invalid magic");
     649    }
     650
     651    archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress, "uncompress", "uncompress", "-cf", "-", NULL);
    572652    archive_handle->offset = 0;
    573     while (get_header_tar(archive_handle) == EXIT_SUCCESS);
     653    while (get_header_tar(archive_handle) == EXIT_SUCCESS)
     654        /* nothing */;
    574655
    575656    /* Can only do one file at a time */
    576     return(EXIT_FAILURE);
     657    return EXIT_FAILURE;
    577658}
    578659#else
    579 #define get_header_tar_Z    0
    580 #endif
    581 
    582 #define CTX_TEST                          (1 << 0)
    583 #define CTX_EXTRACT                       (1 << 1)
    584 #define TAR_OPT_BASEDIR                   (1 << 2)
    585 #define TAR_OPT_TARNAME                   (1 << 3)
    586 #define TAR_OPT_2STDOUT                   (1 << 4)
    587 #define TAR_OPT_P                         (1 << 5)
    588 #define TAR_OPT_VERBOSE                   (1 << 6)
    589 #define TAR_OPT_KEEP_OLD                  (1 << 7)
    590 
    591 #define TAR_OPT_AFTER_START               8
    592 
    593 #define CTX_CREATE                        (1 << (TAR_OPT_AFTER_START))
    594 #define TAR_OPT_DEREFERENCE               (1 << (TAR_OPT_AFTER_START + 1))
    595 #ifdef CONFIG_FEATURE_TAR_CREATE
    596 # define TAR_OPT_STR_CREATE               "ch"
    597 # define TAR_OPT_AFTER_CREATE             TAR_OPT_AFTER_START + 2
    598 #else
    599 # define TAR_OPT_STR_CREATE               ""
    600 # define TAR_OPT_AFTER_CREATE             TAR_OPT_AFTER_START
    601 #endif
    602 
    603 #define TAR_OPT_BZIP2                     (1 << (TAR_OPT_AFTER_CREATE))
    604 #ifdef CONFIG_FEATURE_TAR_BZIP2
    605 # define TAR_OPT_STR_BZIP2                "j"
    606 # define TAR_OPT_AFTER_BZIP2              TAR_OPT_AFTER_CREATE + 1
    607 #else
    608 # define TAR_OPT_STR_BZIP2                ""
    609 # define TAR_OPT_AFTER_BZIP2              TAR_OPT_AFTER_CREATE
    610 #endif
    611 
    612 #define TAR_OPT_LZMA                      (1 << (TAR_OPT_AFTER_BZIP2))
    613 #ifdef CONFIG_FEATURE_TAR_LZMA
    614 # define TAR_OPT_STR_LZMA                 "a"
    615 # define TAR_OPT_AFTER_LZMA               TAR_OPT_AFTER_BZIP2 + 1
    616 #else
    617 # define TAR_OPT_STR_LZMA                 ""
    618 # define TAR_OPT_AFTER_LZMA               TAR_OPT_AFTER_BZIP2
    619 #endif
    620 
    621 #define TAR_OPT_INCLUDE_FROM              (1 << (TAR_OPT_AFTER_LZMA))
    622 #define TAR_OPT_EXCLUDE_FROM              (1 << (TAR_OPT_AFTER_LZMA + 1))
    623 #ifdef CONFIG_FEATURE_TAR_FROM
    624 # define TAR_OPT_STR_FROM                 "T:X:"
    625 # define TAR_OPT_AFTER_FROM               TAR_OPT_AFTER_LZMA + 2
    626 #else
    627 # define TAR_OPT_STR_FROM                 ""
    628 # define TAR_OPT_AFTER_FROM               TAR_OPT_AFTER_LZMA
    629 #endif
    630 
    631 #define TAR_OPT_GZIP                      (1 << (TAR_OPT_AFTER_FROM))
    632 #ifdef CONFIG_FEATURE_TAR_GZIP
    633 # define TAR_OPT_STR_GZIP                 "z"
    634 # define TAR_OPT_AFTER_GZIP               TAR_OPT_AFTER_FROM + 1
    635 #else
    636 # define TAR_OPT_STR_GZIP                 ""
    637 # define TAR_OPT_AFTER_GZIP               TAR_OPT_AFTER_FROM
    638 #endif
    639 
    640 #define TAR_OPT_UNCOMPRESS                (1 << (TAR_OPT_AFTER_GZIP))
    641 #ifdef CONFIG_FEATURE_TAR_COMPRESS
    642 # define TAR_OPT_STR_COMPRESS             "Z"
    643 # define TAR_OPT_AFTER_COMPRESS           TAR_OPT_AFTER_GZIP + 1
    644 #else
    645 # define TAR_OPT_STR_COMPRESS             ""
    646 # define TAR_OPT_AFTER_COMPRESS           TAR_OPT_AFTER_GZIP
    647 #endif
    648 
    649 #define TAR_OPT_NOPRESERVE_OWN            (1 << (TAR_OPT_AFTER_COMPRESS))
    650 #define TAR_OPT_NOPRESERVE_PERM           (1 << (TAR_OPT_AFTER_COMPRESS + 1))
    651 #define TAR_OPT_STR_NOPRESERVE            "\203\213"
    652 #define TAR_OPT_AFTER_NOPRESERVE          TAR_OPT_AFTER_COMPRESS + 2
    653 
    654 static const char tar_options[]="txC:f:Opvk" \
    655     TAR_OPT_STR_CREATE \
    656     TAR_OPT_STR_BZIP2 \
    657     TAR_OPT_STR_LZMA \
    658     TAR_OPT_STR_FROM \
    659     TAR_OPT_STR_GZIP \
    660     TAR_OPT_STR_COMPRESS \
    661     TAR_OPT_STR_NOPRESERVE;
    662 
    663 #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS
    664 static const struct option tar_long_options[] = {
    665     { "list",               0,  NULL,   't' },
    666     { "extract",            0,  NULL,   'x' },
    667     { "directory",          1,  NULL,   'C' },
    668     { "file",               1,  NULL,   'f' },
    669     { "to-stdout",          0,  NULL,   'O' },
    670     { "same-permissions",   0,  NULL,   'p' },
    671     { "verbose",            0,  NULL,   'v' },
    672     { "keep-old",           0,  NULL,   'k' },
    673     { "no-same-owner",      0,  NULL,   '\203' },
    674     { "no-same-permissions",0,  NULL,   '\213' },
    675 # ifdef CONFIG_FEATURE_TAR_CREATE
    676     { "create",             0,  NULL,   'c' },
    677     { "dereference",        0,  NULL,   'h' },
     660#define get_header_tar_Z NULL
     661#endif
     662
     663#ifdef CHECK_FOR_CHILD_EXITCODE
     664/* Looks like it isn't needed - tar detects malformed (truncated)
     665 * archive if e.g. bunzip2 fails */
     666static int child_error;
     667
     668static void handle_SIGCHLD(int status)
     669{
     670    /* Actually, 'status' is a signo. We reuse it for other needs */
     671
     672    /* Wait for any child without blocking */
     673    if (waitpid(-1, &status, WNOHANG) < 0)
     674        /* wait failed?! I'm confused... */
     675        return;
     676
     677    if (WIFEXITED(status) && WEXITSTATUS(status)==0)
     678        /* child exited with 0 */
     679        return;
     680    /* Cannot happen?
     681    if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
     682    child_error = 1;
     683}
     684#endif
     685
     686enum {
     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,
     697    OPTBIT_NOPRESERVE_PERM,
     698    OPT_TEST         = 1 << 0, // t
     699    OPT_EXTRACT      = 1 << 1, // x
     700    OPT_BASEDIR      = 1 << 2, // C
     701    OPT_TARNAME      = 1 << 3, // f
     702    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
     716};
     717#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     718static const char tar_longopts[] ALIGN1 =
     719    "list\0"                No_argument       "t"
     720    "extract\0"             No_argument       "x"
     721    "directory\0"           Required_argument "C"
     722    "file\0"                Required_argument "f"
     723    "to-stdout\0"           No_argument       "O"
     724    "same-permissions\0"    No_argument       "p"
     725    "verbose\0"             No_argument       "v"
     726    "keep-old\0"            No_argument       "k"
     727# if ENABLE_FEATURE_TAR_CREATE
     728    "create\0"              No_argument       "c"
     729    "dereference\0"         No_argument       "h"
    678730# endif
    679 # ifdef CONFIG_FEATURE_TAR_BZIP2
    680     { "bzip2",              0,  NULL,   'j' },
     731# if ENABLE_FEATURE_TAR_BZIP2
     732    "bzip2\0"               No_argument       "j"
    681733# endif
    682 # ifdef CONFIG_FEATURE_TAR_LZMA
    683     { "lzma",               0,  NULL,   'a' },
     734# if ENABLE_FEATURE_TAR_LZMA
     735    "lzma\0"                No_argument       "a"
    684736# endif
    685 # ifdef CONFIG_FEATURE_TAR_FROM
    686     { "files-from",         1,  NULL,   'T' },
    687     { "exclude-from",       1,  NULL,   'X' },
    688     { "exclude",            1,  NULL,   '\n' },
     737# if ENABLE_FEATURE_TAR_FROM
     738    "files-from\0"          Required_argument "T"
     739    "exclude-from\0"        Required_argument "X"
    689740# endif
    690 # ifdef CONFIG_FEATURE_TAR_GZIP
    691     { "gzip",               0,  NULL,   'z' },
     741# if ENABLE_FEATURE_TAR_GZIP
     742    "gzip\0"                No_argument       "z"
    692743# endif
    693 # ifdef CONFIG_FEATURE_TAR_COMPRESS
    694     { "compress",           0,  NULL,   'Z' },
     744# if ENABLE_FEATURE_TAR_COMPRESS
     745    "compress\0"            No_argument       "Z"
    695746# endif
    696     { 0,                    0, 0, 0 }
    697 };
    698 #else
    699 #define tar_long_options    0
    700 #endif
    701 
     747    "no-same-owner\0"       No_argument       "\xfd"
     748    "no-same-permissions\0" No_argument       "\xfe"
     749    /* --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 */
     752# if ENABLE_FEATURE_TAR_FROM
     753    "exclude\0"             Required_argument "\xff"
     754# endif
     755    ;
     756#endif
     757
     758int tar_main(int argc, char **argv);
    702759int tar_main(int argc, char **argv)
    703760{
     
    706763    char *base_dir = NULL;
    707764    const char *tar_filename = "-";
    708     unsigned long opt;
     765    unsigned opt;
     766    int verboseFlag = 0;
     767#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
    709768    llist_t *excludes = NULL;
     769#endif
    710770
    711771    /* Initialise default values */
    712772    tar_handle = init_handle();
    713     tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL;
     773    tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS
     774                      | ARCHIVE_PRESERVE_DATE
     775                      | ARCHIVE_EXTRACT_UNCONDITIONAL;
    714776
    715777    /* Prepend '-' to the first argument if required */
    716     bb_opt_complementally = ENABLE_FEATURE_TAR_CREATE ?
    717         "--:X::T::\n::c:t:x:?:c--tx:t--cx:x--ct" :
    718         "--:X::T::\n::t:x:?:t--x:x--t";
    719     if (ENABLE_FEATURE_TAR_LONG_OPTIONS)
    720         bb_applet_long_options = tar_long_options;
    721     opt = bb_getopt_ulflags(argc, argv, tar_options,
    722                 &base_dir,      /* Change to dir <optarg> */
    723                 &tar_filename /* archive filename */
    724 #ifdef CONFIG_FEATURE_TAR_FROM
    725                 , &(tar_handle->accept),
    726                 &(tar_handle->reject),
    727                 &excludes
    728 #endif
    729                 );
    730 
    731     if (opt & CTX_TEST) {
    732         if ((tar_handle->action_header == header_list) ||
    733             (tar_handle->action_header == header_verbose_list))
    734         {
    735                 tar_handle->action_header = header_verbose_list;
    736         } else tar_handle->action_header = header_list;
    737     }
    738     if((opt & CTX_EXTRACT) && tar_handle->action_data != data_extract_to_stdout)
     778    opt_complementary = "--:" // first arg is options
     779        "tt:vv:" // count -t,-v
     780        "?:" // bail out with usage instead of error return
     781        "X::T::" // cumulative lists
     782#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
     783        "\xff::" // cumulative lists for --exclude
     784#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
     788#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     789    applet_long_options = tar_longopts;
     790#endif
     791    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"   )
     799        , &base_dir // -C dir
     800        , &tar_filename // -f filename
     801        USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
     802        USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
     803#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
     804        , &excludes // --exclude
     805#endif
     806        , &verboseFlag // combined count for -t and -v
     807        , &verboseFlag // combined count for -t and -v
     808        );
     809
     810    if (verboseFlag) tar_handle->action_header = header_verbose_list;
     811    if (verboseFlag == 1) tar_handle->action_header = header_list;
     812
     813    if (opt & OPT_EXTRACT)
    739814        tar_handle->action_data = data_extract_all;
    740815
    741     if (opt & TAR_OPT_2STDOUT)
     816    if (opt & OPT_2STDOUT)
    742817        tar_handle->action_data = data_extract_to_stdout;
    743818
    744     if (opt & TAR_OPT_VERBOSE) {
    745         if ((tar_handle->action_header == header_list) ||
    746             (tar_handle->action_header == header_verbose_list))
    747         {
    748             tar_handle->action_header = header_verbose_list;
    749         } else
    750             tar_handle->action_header = header_list;
    751     }
    752     if (opt & TAR_OPT_KEEP_OLD)
     819    if (opt & OPT_KEEP_OLD)
    753820        tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL;
    754821
    755     if (opt & TAR_OPT_NOPRESERVE_OWN)
     822    if (opt & OPT_NOPRESERVE_OWN)
    756823        tar_handle->flags |= ARCHIVE_NOPRESERVE_OWN;
    757824
    758     if (opt & TAR_OPT_NOPRESERVE_PERM)
     825    if (opt & OPT_NOPRESERVE_PERM)
    759826        tar_handle->flags |= ARCHIVE_NOPRESERVE_PERM;
    760827
    761     if (ENABLE_FEATURE_TAR_GZIP && (opt & TAR_OPT_GZIP))
     828    if (opt & OPT_GZIP)
    762829        get_header_ptr = get_header_tar_gz;
    763830
    764     if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2))
     831    if (opt & OPT_BZIP2)
    765832        get_header_ptr = get_header_tar_bz2;
    766833
    767     if (ENABLE_FEATURE_TAR_LZMA && (opt & TAR_OPT_LZMA))
     834    if (opt & OPT_LZMA)
    768835        get_header_ptr = get_header_tar_lzma;
    769836
    770     if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS))
     837    if (opt & OPT_COMPRESS)
    771838        get_header_ptr = get_header_tar_Z;
    772839
    773     if (ENABLE_FEATURE_TAR_FROM) {
    774         tar_handle->reject = append_file_list_to_list(tar_handle->reject);
    775         /* Append excludes to reject */
    776         while (excludes) {
    777             llist_t *temp = excludes->link;
    778             excludes->link = tar_handle->reject;
    779             tar_handle->reject = excludes;
    780             excludes = temp;
    781         }
    782         tar_handle->accept = append_file_list_to_list(tar_handle->accept);
    783     }
     840#if ENABLE_FEATURE_TAR_FROM
     841    tar_handle->reject = append_file_list_to_list(tar_handle->reject);
     842#if ENABLE_FEATURE_TAR_LONG_OPTIONS
     843    /* Append excludes to reject */
     844    while (excludes) {
     845        llist_t *next = excludes->link;
     846        excludes->link = tar_handle->reject;
     847        tar_handle->reject = excludes;
     848        excludes = next;
     849    }
     850#endif
     851    tar_handle->accept = append_file_list_to_list(tar_handle->accept);
     852#endif
    784853
    785854    /* Check if we are reading from stdin */
     
    792861    /* TODO: This is the same as in ar, separate function ? */
    793862    while (optind < argc) {
    794         char *filename_ptr = last_char_is(argv[optind], '/');
    795         if (filename_ptr > argv[optind])
    796             *filename_ptr = '\0';
    797 
    798         llist_add_to(&(tar_handle->accept), argv[optind]);
     863        /* kill trailing '/' unless the string is just "/" */
     864        char *cp = last_char_is(argv[optind], '/');
     865        if (cp > argv[optind])
     866            *cp = '\0';
     867        llist_add_to_end(&tar_handle->accept, argv[optind]);
    799868        optind++;
    800869    }
    801870
    802     if ((tar_handle->accept) || (tar_handle->reject))
     871    if (tar_handle->accept || tar_handle->reject)
    803872        tar_handle->filter = filter_accept_reject_list;
    804873
     
    808877        int flags;
    809878
    810         if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) {
     879        if (opt & OPT_CREATE) {
    811880            /* Make sure there is at least one file to tar up.  */
    812881            if (tar_handle->accept == NULL)
     
    814883
    815884            tar_stream = stdout;
    816             flags = O_WRONLY | O_CREAT | O_EXCL;
    817             unlink(tar_filename);
     885            /* 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? */
    818888        } else {
    819889            tar_stream = stdin;
     
    821891        }
    822892
    823         if ((tar_filename[0] == '-') && (tar_filename[1] == '\0')) {
     893        if (LONE_DASH(tar_filename)) {
    824894            tar_handle->src_fd = fileno(tar_stream);
    825             tar_handle->seek = seek_by_char;
     895            tar_handle->seek = seek_by_read;
    826896        } else {
    827             tar_handle->src_fd = bb_xopen(tar_filename, flags);
     897            tar_handle->src_fd = xopen(tar_filename, flags);
    828898        }
    829899    }
    830900
    831901    if (base_dir)
    832         bb_xchdir(base_dir);
     902        xchdir(base_dir);
     903
     904#ifdef CHECK_FOR_CHILD_EXITCODE
     905    /* We need to know whether child (gzip/bzip/etc) exits abnormally */
     906    signal(SIGCHLD, handle_SIGCHLD);
     907#endif
    833908
    834909    /* create an archive */
    835     if (ENABLE_FEATURE_TAR_CREATE && (opt & CTX_CREATE)) {
    836         int verboseFlag = FALSE;
     910    if (opt & OPT_CREATE) {
    837911        int zipMode = 0;
    838 
    839912        if (ENABLE_FEATURE_TAR_GZIP && get_header_ptr == get_header_tar_gz)
    840913            zipMode = 1;
    841914        if (ENABLE_FEATURE_TAR_BZIP2 && get_header_ptr == get_header_tar_bz2)
    842915            zipMode = 2;
    843 
    844         if ((tar_handle->action_header == header_list) ||
    845                 (tar_handle->action_header == header_verbose_list))
    846         {
    847             verboseFlag = TRUE;
    848         }
    849         writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERENCE,
     916        /* NB: writeTarFile() closes tar_handle->src_fd */
     917        return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE,
    850918                tar_handle->accept,
    851             tar_handle->reject, zipMode);
    852     } else {
    853         while (get_header_ptr(tar_handle) == EXIT_SUCCESS);
    854 
    855         /* Check that every file that should have been extracted was */
    856         while (tar_handle->accept) {
    857             if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
    858                 && !find_list_entry(tar_handle->passed, tar_handle->accept->data))
    859             {
    860                 bb_error_msg_and_die("%s: Not found in archive", tar_handle->accept->data);
    861             }
    862             tar_handle->accept = tar_handle->accept->link;
    863         }
    864     }
    865 
    866     if (ENABLE_FEATURE_CLEAN_UP && tar_handle->src_fd != STDIN_FILENO)
     919                tar_handle->reject, zipMode);
     920    }
     921
     922    while (get_header_ptr(tar_handle) == EXIT_SUCCESS)
     923        /* nothing */;
     924
     925    /* Check that every file that should have been extracted was */
     926    while (tar_handle->accept) {
     927        if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
     928         && !find_list_entry(tar_handle->passed, tar_handle->accept->data)
     929        ) {
     930            bb_error_msg_and_die("%s: not found in archive",
     931                tar_handle->accept->data);
     932        }
     933        tar_handle->accept = tar_handle->accept->link;
     934    }
     935    if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
    867936        close(tar_handle->src_fd);
    868937
    869     return(EXIT_SUCCESS);
    870 }
     938    return EXIT_SUCCESS;
     939}
Note: See TracChangeset for help on using the changeset viewer.