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


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
Location:
branches/2.2.9/mindi-busybox/archival
Files:
64 added
12 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/archival/Config.in

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    67menu "Archival Utilities"
    78
     9
     10
     11config FEATURE_SEAMLESS_XZ
     12    bool "Make tar, rpm, modprobe etc understand .xz data"
     13    default y
     14    help
     15      Make tar, rpm, modprobe etc understand .xz data.
     16
     17config FEATURE_SEAMLESS_LZMA
     18    bool "Make tar, rpm, modprobe etc understand .lzma data"
     19    default y
     20    help
     21      Make tar, rpm, modprobe etc understand .lzma data.
     22
     23config FEATURE_SEAMLESS_BZ2
     24    bool "Make tar, rpm, modprobe etc understand .bz2 data"
     25    default y
     26    help
     27      Make tar, rpm, modprobe etc understand .bz2 data.
     28
     29config FEATURE_SEAMLESS_GZ
     30    bool "Make tar, rpm, modprobe etc understand .gz data"
     31    default y
     32    help
     33      Make tar, rpm, modprobe etc understand .gz data.
     34
     35config FEATURE_SEAMLESS_Z
     36    bool "Make tar and gunzip understand .Z data"
     37    default n
     38    help
     39      Make tar and gunzip understand .Z data.
     40
    841config AR
    942    bool "ar"
    10     default n
     43    default n  # needs to be improved to be able to replace binutils ar
    1144    help
    1245      ar is an archival utility program used to create, modify, and
    13       extract contents from archives.  An archive is a single file holding
     46      extract contents from archives. An archive is a single file holding
    1447      a collection of other files in a structure that makes it possible to
    1548      retrieve the original individual files (called archive members).
     
    3063
    3164config FEATURE_AR_LONG_FILENAMES
    32     bool "Enable support for long filenames (not need for debs)"
    33     default n
     65    bool "Support for long filenames (not needed for debs)"
     66    default y
    3467    depends on AR
    3568    help
    36       By default the ar format can only store the first 15 characters of the
    37       filename, this option removes that limitation.
     69      By default the ar format can only store the first 15 characters
     70      of the filename, this option removes that limitation.
    3871      It supports the GNU ar long filename method which moves multiple long
    3972      filenames into a the data section of a new ar entry.
    4073
     74config FEATURE_AR_CREATE
     75    bool "Support archive creation"
     76    default y
     77    depends on AR
     78    help
     79      This enables archive creation (-c and -r) with busybox ar.
     80
    4181config BUNZIP2
    4282    bool "bunzip2"
    43     default n
     83    default y
    4484    help
    4585      bunzip2 is a compression utility using the Burrows-Wheeler block
    46       sorting text compression algorithm, and Huffman coding.  Compression
     86      sorting text compression algorithm, and Huffman coding. Compression
    4787      is generally considerably better than that achieved by more
    4888      conventional LZ77/LZ78-based compressors, and approaches the
    4989      performance of the PPM family of statistical compressors.
    5090
    51       The BusyBox bunzip2 applet is limited to de-compression only.
    52       On an x86 system, this applet adds about 11K.
    53 
    5491      Unless you have a specific application which requires bunzip2, you
    5592      should probably say N here.
    5693
     94config BZIP2
     95    bool "bzip2"
     96    default y
     97    help
     98      bzip2 is a compression utility using the Burrows-Wheeler block
     99      sorting text compression algorithm, and Huffman coding. Compression
     100      is generally considerably better than that achieved by more
     101      conventional LZ77/LZ78-based compressors, and approaches the
     102      performance of the PPM family of statistical compressors.
     103
     104      Unless you have a specific application which requires bzip2, you
     105      should probably say N here.
     106
    57107config CPIO
    58108    bool "cpio"
    59     default n
    60     help
    61       cpio is an archival utility program used to create, modify, and extract
    62       contents from archives.
     109    default y
     110    help
     111      cpio is an archival utility program used to create, modify, and
     112      extract contents from archives.
    63113      cpio has 110 bytes of overheads for every stored file.
    64114
     
    66116      "newc" or "crc" format, it cannot create or modify them.
    67117
    68       Unless you have a specific application which requires cpio, you should
    69       probably say N here.
     118      Unless you have a specific application which requires cpio, you
     119      should probably say N here.
     120
     121config FEATURE_CPIO_O
     122    bool "Support for archive creation"
     123    default y
     124    depends on CPIO
     125    help
     126      This implementation of cpio can create cpio archives in the "newc"
     127      format only.
     128
     129config FEATURE_CPIO_P
     130    bool "Support for passthrough mode"
     131    default y
     132    depends on FEATURE_CPIO_O
     133    help
     134      Passthrough mode. Rarely used.
    70135
    71136config DPKG
    72137    bool "dpkg"
    73138    default n
    74     help
    75       dpkg is a medium-level tool to install, build, remove and manage Debian packages.
    76 
    77       This implementation of dpkg has a number of limitations, you should use the
    78       official dpkg if possible.
     139    select FEATURE_SEAMLESS_GZ
     140    help
     141      dpkg is a medium-level tool to install, build, remove and manage
     142      Debian packages.
     143
     144      This implementation of dpkg has a number of limitations,
     145      you should use the official dpkg if possible.
    79146
    80147config DPKG_DEB
    81148    bool "dpkg_deb"
    82149    default n
    83     help
    84       dpkg-deb packs, unpacks and provides information about Debian archives.
     150    select FEATURE_SEAMLESS_GZ
     151    help
     152      dpkg-deb unpacks and provides information about Debian archives.
    85153
    86154      This implementation of dpkg-deb cannot pack archives.
    87155
    88       Unless you have a specific application which requires dpkg-deb, you should
    89       probably say N here.
     156      Unless you have a specific application which requires dpkg-deb,
     157      say N here.
    90158
    91159config FEATURE_DPKG_DEB_EXTRACT_ONLY
    92     bool "extract only (-x)"
     160    bool "Extract only (-x)"
    93161    default n
    94162    depends on DPKG_DEB
    95163    help
    96       This reduces dpkg-deb to the equivalent of "ar -p <deb> data.tar.gz | tar -zx".
    97       However it saves space as none of the extra dpkg-deb, ar or tar options are
    98       needed, they are linked to internally.
     164      This reduces dpkg-deb to the equivalent of
     165      "ar -p <deb> data.tar.gz | tar -zx". However it saves space as none
     166      of the extra dpkg-deb, ar or tar options are needed, they are linked
     167      to internally.
    99168
    100169config GUNZIP
    101170    bool "gunzip"
    102     default n
     171    default y
    103172    help
    104173      gunzip is used to decompress archives created by gzip.
     
    106175      an archive, without decompressing it.
    107176
    108 config FEATURE_GUNZIP_UNCOMPRESS
    109     bool "Uncompress support"
    110     default n
    111     depends on GUNZIP
    112     help
    113       Enable if you want gunzip to have the ability to decompress
    114       archives created by the program compress (not much
    115       used anymore).
    116 
    117177config GZIP
    118178    bool "gzip"
    119     default n
     179    default y
    120180    help
    121181      gzip is used to compress files.
    122182      It's probably the most widely used UNIX compression program.
    123183
     184config FEATURE_GZIP_LONG_OPTIONS
     185    bool "Enable long options"
     186    default y
     187    depends on GZIP && LONG_OPTS
     188    help
     189      Enable use of long options, increases size by about 106 Bytes
     190
     191config LZOP
     192    bool "lzop"
     193    default y
     194    help
     195      Lzop compression/decompresion.
     196
     197config LZOP_COMPR_HIGH
     198    bool "lzop compression levels 7,8,9 (not very useful)"
     199    default n
     200    depends on LZOP
     201    help
     202      High levels (7,8,9) of lzop compression. These levels
     203      are actually slower than gzip at equivalent compression ratios
     204      and take up 3.2K of code.
     205
    124206config RPM2CPIO
    125207    bool "rpm2cpio"
    126     default n
    127     help
    128       Converts an RPM file into a CPIO archive.
     208    default y
     209    help
     210      Converts a RPM file into a CPIO archive.
    129211
    130212config RPM
    131213    bool "rpm"
    132     default n
     214    default y
    133215    help
    134216      Mini RPM applet - queries and extracts RPM packages.
    135 
    136 config FEATURE_RPM_BZ2
    137     bool "Enable handling of rpms with bzip2-compressed data inside"
    138     default n
    139     depends on RPM
    140     help
    141       Enable handling of rpms with bzip2-compressed data inside.
    142217
    143218config TAR
    144219    bool "tar"
    145     default n
     220    default y
    146221    help
    147222      tar is an archiving program. It's commonly used with gzip to
     
    157232      tar archives using the `-c' option.
    158233
    159 config FEATURE_TAR_BZIP2
    160     bool "Enable -j option to handle .tar.bz2 files"
    161     default n
    162     depends on TAR
    163     help
    164       If you enable this option you'll be able to extract
    165       archives compressed with bzip2.
    166 
    167 config FEATURE_TAR_LZMA
    168     bool "Enable -a option to handle .tar.lzma files"
    169     default n
    170     depends on TAR
    171     help
    172       If you enable this option you'll be able to extract
    173       archives compressed with lzma.
     234config FEATURE_TAR_AUTODETECT
     235    bool "Autodetect compressed tarballs"
     236    default y
     237    depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ)
     238    help
     239      With this option tar can automatically detect compressed
     240      tarballs. Currently it works only on files (not pipes etc).
    174241
    175242config FEATURE_TAR_FROM
    176243    bool "Enable -X (exclude from) and -T (include from) options)"
    177     default n
     244    default y
    178245    depends on TAR
    179246    help
     
    181248      a list of files to include or exclude from an archive.
    182249
    183 config FEATURE_TAR_GZIP
    184     bool "Enable -z option"
    185     default y
    186     depends on TAR
    187     help
    188       If you enable this option tar will be able to call gzip,
    189       when creating or extracting tar gziped archives.
    190 
    191 config FEATURE_TAR_COMPRESS
    192     bool "Enable -Z option"
    193     default n
    194     depends on TAR
    195     help
    196       If you enable this option tar will be able to call uncompress,
    197       when extracting .tar.Z archives.
    198 
    199250config FEATURE_TAR_OLDGNU_COMPATIBILITY
    200     bool "Enable support for old tar header format"
    201     default N
    202     depends on TAR
     251    bool "Support for old tar header format"
     252    default y
     253    depends on TAR || DPKG
    203254    help
    204255      This option is required to unpack archives created in
     
    208259config FEATURE_TAR_OLDSUN_COMPATIBILITY
    209260    bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
    210     default N
    211     depends on TAR
     261    default y
     262    depends on TAR || DPKG
    212263    help
    213264      This option is required to unpack archives created by some old
    214       version of Sun's tar (it was calculating checksum using signed arithmetic).
    215       It is said to be fixed in newer Sun tar, but "old" tarballs still exist.
     265      version of Sun's tar (it was calculating checksum using signed
     266      arithmetic). It is said to be fixed in newer Sun tar, but "old"
     267      tarballs still exist.
    216268
    217269config FEATURE_TAR_GNU_EXTENSIONS
    218     bool "Enable support for some GNU tar extensions"
    219     default y
    220     depends on TAR
     270    bool "Support for GNU tar extensions (long filenames)"
     271    default y
     272    depends on TAR || DPKG
    221273    help
    222274      With this option busybox supports GNU long filenames and
     
    225277config FEATURE_TAR_LONG_OPTIONS
    226278    bool "Enable long options"
    227     default n
    228     depends on TAR && GETOPT_LONG
    229     help
    230         Enable use of long options, increases size by about 400 Bytes
     279    default y
     280    depends on TAR && LONG_OPTS
     281    help
     282      Enable use of long options, increases size by about 400 Bytes
     283
     284config FEATURE_TAR_TO_COMMAND
     285    bool "Support for writing to an external program"
     286    default y
     287    depends on TAR && FEATURE_TAR_LONG_OPTIONS
     288    help
     289      If you enable this option you'll be able to instruct tar to send
     290      the contents of each extracted file to the standard input of an
     291      external program.
     292
     293config FEATURE_TAR_UNAME_GNAME
     294    bool "Enable use of user and group names"
     295    default y
     296    depends on TAR
     297    help
     298      Enables use of user and group names in tar. This affects contents
     299      listings (-t) and preserving permissions when unpacking (-p).
     300      +200 bytes.
     301
     302config FEATURE_TAR_NOPRESERVE_TIME
     303    bool "Enable -m (do not preserve time) option"
     304    default y
     305    depends on TAR
     306    help
     307      With this option busybox supports GNU tar -m
     308      (do not preserve time) option.
     309
     310config FEATURE_TAR_SELINUX
     311    bool "Support for extracting SELinux labels"
     312    default n
     313    depends on TAR && SELINUX
     314    help
     315      With this option busybox supports restoring SELinux labels
     316      when extracting files from tar archives.
    231317
    232318config UNCOMPRESS
     
    239325config UNLZMA
    240326    bool "unlzma"
    241     default n
     327    default y
    242328    help
    243329      unlzma is a compression utility using the Lempel-Ziv-Markov chain
    244       compression algorithm, and range coding.  Compression
     330      compression algorithm, and range coding. Compression
    245331      is generally considerably better than that achieved by the bzip2
    246332      compressors.
     
    253339
    254340config FEATURE_LZMA_FAST
    255     bool "Optimze unlzma for speed"
    256     default n
     341    bool "Optimize unlzma for speed"
     342    default y
    257343    depends on UNLZMA
    258344    help
    259       This option reduces decompression time by about 33% at the cost of
    260       a 2K bigger binary.
     345      This option reduces decompression time by about 25% at the cost of
     346      a 1K bigger binary.
     347
     348config LZMA
     349    bool "Provide lzma alias which supports only unpacking"
     350    default y
     351    depends on UNLZMA
     352    help
     353      Enable this option if you want commands like "lzma -d" to work.
     354      IOW: you'll get lzma applet, but it will always require -d option.
     355
     356config UNXZ
     357    bool "unxz"
     358    default y
     359    help
     360      unxz is a unlzma successor.
     361
     362config XZ
     363    bool "Provide xz alias which supports only unpacking"
     364    default y
     365    depends on UNXZ
     366    help
     367      Enable this option if you want commands like "xz -d" to work.
     368      IOW: you'll get xz applet, but it will always require -d option.
    261369
    262370config UNZIP
    263371    bool "unzip"
    264     default n
     372    default y
    265373    help
    266374      unzip will list or extract files from a ZIP archive,
     
    270378      directory of your choice.
    271379
    272 comment "Common options for cpio and tar"
    273     depends on CPIO || TAR
    274 
    275 config FEATURE_UNARCHIVE_TAPE
    276     bool "Enable tape drive support"
    277     default n
    278     depends on CPIO || TAR
    279     help
    280       I don't think this is needed anymore.
    281 
    282 comment "Common options for dpkg and dpkg_deb"
    283     depends on DPKG || DPKG_DEB
    284 
    285 config FEATURE_DEB_TAR_GZ
    286     bool "gzip debian packages (normal)"
    287     default y if DPKG || DPKG_DEB
    288     depends on DPKG || DPKG_DEB
    289     help
    290       This is the default compression method inside the debian ar file.
    291 
    292       If you want compatibility with standard .deb's you should say yes here.
    293 
    294 config FEATURE_DEB_TAR_BZ2
    295     bool "bzip2 debian packages"
    296     default n
    297     depends on DPKG || DPKG_DEB
    298     help
    299       This allows dpkg and dpkg-deb to extract deb's that are compressed internally
    300       with bzip2 instead of gzip.
    301 
    302       You only want this if you are creating your own custom debian packages that
    303       use an internal control.tar.bz2 or data.tar.bz2.
    304 
    305 config FEATURE_DEB_TAR_LZMA
    306     bool "lzma debian packages"
    307     default n
    308     depends on DPKG || DPKG_DEB
    309     help
    310       This allows dpkg and dpkg-deb to extract deb's that are compressed
    311       internally with lzma instead of gzip.
    312 
    313       You only want this if you are creating your own custom debian
    314       packages that use an internal control.tar.lzma or data.tar.lzma.
    315 
    316380endmenu
  • branches/2.2.9/mindi-busybox/archival/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2, see the file LICENSE in this tarball.
     6# Licensed under GPLv2, see file LICENSE in this source tree.
    67
    7 libs-y              += libunarchive/
     8libs-y              += libarchive/
    89
    910lib-y:=
     11
     12
     13
    1014lib-$(CONFIG_AR)        += ar.o
    11 lib-$(CONFIG_BUNZIP2)       += bbunzip.o
    12 lib-$(CONFIG_UNLZMA)        += bbunzip.o
    1315lib-$(CONFIG_CPIO)      += cpio.o
    1416lib-$(CONFIG_DPKG)      += dpkg.o
    1517lib-$(CONFIG_DPKG_DEB)      += dpkg_deb.o
    16 lib-$(CONFIG_GUNZIP)        += bbunzip.o
    17 lib-$(CONFIG_GZIP)      += gzip.o bbunzip.o
    1818lib-$(CONFIG_RPM2CPIO)      += rpm2cpio.o
    1919lib-$(CONFIG_RPM)       += rpm.o
    2020lib-$(CONFIG_TAR)       += tar.o
     21lib-$(CONFIG_UNZIP)     += unzip.o
     22
     23lib-$(CONFIG_LZOP)      += lzop.o bbunzip.o
     24lib-$(CONFIG_GZIP)      += gzip.o bbunzip.o
     25lib-$(CONFIG_BZIP2)     += bzip2.o bbunzip.o
     26
     27lib-$(CONFIG_UNXZ)      += bbunzip.o
     28lib-$(CONFIG_UNLZMA)        += bbunzip.o
     29lib-$(CONFIG_BUNZIP2)       += bbunzip.o
     30lib-$(CONFIG_GUNZIP)        += bbunzip.o
    2131lib-$(CONFIG_UNCOMPRESS)    += bbunzip.o
    22 lib-$(CONFIG_UNZIP)     += unzip.o
  • branches/2.2.9/mindi-busybox/archival/ar.c

    r1765 r2725  
    44 *
    55 * Copyright (C) 2000 by Glenn McGrath
    6  * Written by Glenn McGrath <bug1@iinet.net.au> 1 June 2000
    76 *
    87 * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar.
    98 *
    10  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     10 *
     11 * Archive creation support:
     12 * Copyright (C) 2010 Nokia Corporation. All rights reserved.
     13 * Written by Alexander Shishkin.
    1114 *
    1215 * There is no single standard to adhere to so ar may not portable
     
    1619
    1720#include "libbb.h"
    18 #include "unarchive.h"
    19 
    20 static void header_verbose_list_ar(const file_header_t *file_header)
     21#include "archive.h"
     22#include "ar.h"
     23
     24#if ENABLE_FEATURE_AR_CREATE
     25/* filter out entries with same names as specified on the command line */
     26static char FAST_FUNC filter_replaceable(archive_handle_t *handle)
     27{
     28    if (find_list_entry(handle->accept, handle->file_header->name))
     29        return EXIT_FAILURE;
     30
     31    return EXIT_SUCCESS;
     32}
     33
     34static void output_ar_header(archive_handle_t *handle)
     35{
     36    /* GNU ar 2.19.51.0.14 creates malformed archives
     37     * if input files are >10G. It also truncates files >4GB
     38     * (uses "size mod 4G"). We abort in this case:
     39     * We could add support for up to 10G files, but this is unlikely to be useful.
     40     * Note that unpacking side limits all fields to "unsigned int" data type,
     41     * and treats "all ones" as an error indicator. Thus max we allow here is UINT_MAX-1.
     42     */
     43    enum {
     44        /* for 2nd field: mtime */
     45        MAX11CHARS = UINT_MAX > 0xffffffff ? (unsigned)99999999999 : UINT_MAX-1,
     46        /* for last field: filesize */
     47        MAX10CHARS = UINT_MAX > 0xffffffff ? (unsigned)9999999999 : UINT_MAX-1,
     48    };
     49
     50    struct file_header_t *fh = handle->file_header;
     51
     52    if (handle->offset & 1) {
     53        xwrite(handle->src_fd, "\n", 1);
     54        handle->offset++;
     55    }
     56
     57    /* Careful! The widths should be exact. Fields must be separated */
     58    if (sizeof(off_t) > 4 && fh->size > (off_t)MAX10CHARS) {
     59        bb_error_msg_and_die("'%s' is bigger than ar can handle", fh->name);
     60    }
     61    fdprintf(handle->src_fd, "%-16.16s%-12lu%-6u%-6u%-8o%-10"OFF_FMT"u`\n",
     62            fh->name,
     63            (sizeof(time_t) > 4 && fh->mtime > MAX11CHARS) ? (long)0 : (long)fh->mtime,
     64            fh->uid > 99999 ? 0 : (int)fh->uid,
     65            fh->gid > 99999 ? 0 : (int)fh->gid,
     66            (int)fh->mode & 07777777,
     67            fh->size
     68    );
     69
     70    handle->offset += AR_HEADER_LEN;
     71}
     72
     73/*
     74 * when replacing files in an existing archive, copy from the the
     75 * original archive those files that are to be left intact
     76 */
     77static void FAST_FUNC copy_data(archive_handle_t *handle)
     78{
     79    archive_handle_t *out_handle = handle->ar__out;
     80    struct file_header_t *fh = handle->file_header;
     81
     82    out_handle->file_header = fh;
     83    output_ar_header(out_handle);
     84
     85    bb_copyfd_exact_size(handle->src_fd, out_handle->src_fd, fh->size);
     86    out_handle->offset += fh->size;
     87}
     88
     89static int write_ar_header(archive_handle_t *handle)
     90{
     91    char *fn;
     92    char fn_h[17]; /* 15 + "/" + NUL */
     93    struct stat st;
     94    int fd;
     95
     96    fn = llist_pop(&handle->accept);
     97    if (!fn)
     98        return -1;
     99
     100    xstat(fn, &st);
     101
     102    handle->file_header->mtime = st.st_mtime;
     103    handle->file_header->uid = st.st_uid;
     104    handle->file_header->gid = st.st_gid;
     105    handle->file_header->mode = st.st_mode;
     106    handle->file_header->size = st.st_size;
     107    handle->file_header->name = fn_h;
     108//TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES...
     109    sprintf(fn_h, "%.15s/", bb_basename(fn));
     110
     111    output_ar_header(handle);
     112
     113    fd = xopen(fn, O_RDONLY);
     114    bb_copyfd_exact_size(fd, handle->src_fd, st.st_size);
     115    close(fd);
     116    handle->offset += st.st_size;
     117
     118    return 0;
     119}
     120
     121static int write_ar_archive(archive_handle_t *handle)
     122{
     123    struct stat st;
     124    archive_handle_t *out_handle;
     125
     126    xfstat(handle->src_fd, &st, handle->ar__name);
     127
     128    /* if archive exists, create a new handle for output.
     129     * we create it in place of the old one.
     130     */
     131    if (st.st_size != 0) {
     132        out_handle = init_handle();
     133        xunlink(handle->ar__name);
     134        out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC);
     135        out_handle->accept = handle->accept;
     136    } else {
     137        out_handle = handle;
     138    }
     139
     140    handle->ar__out = out_handle;
     141
     142    xwrite(out_handle->src_fd, AR_MAGIC "\n", AR_MAGIC_LEN + 1);
     143    out_handle->offset += AR_MAGIC_LEN + 1;
     144
     145    /* skip to the end of the archive if we have to append stuff */
     146    if (st.st_size != 0) {
     147        handle->filter = filter_replaceable;
     148        handle->action_data = copy_data;
     149        unpack_ar_archive(handle);
     150    }
     151
     152    while (write_ar_header(out_handle) == 0)
     153        continue;
     154
     155    /* optional, since we exit right after we return */
     156    if (ENABLE_FEATURE_CLEAN_UP) {
     157        close(handle->src_fd);
     158        if (out_handle->src_fd != handle->src_fd)
     159            close(out_handle->src_fd);
     160    }
     161
     162    return EXIT_SUCCESS;
     163}
     164#endif /* FEATURE_AR_CREATE */
     165
     166static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header)
    21167{
    22168    const char *mode = bb_mode_string(file_header->mode);
     
    27173    memmove(&mtime[17], &mtime[20], 4);
    28174    mtime[21] = '\0';
    29     printf("%s %d/%d%7d %s %s\n", &mode[1], file_header->uid, file_header->gid,
    30             (int) file_header->size, &mtime[4], file_header->name);
    31 }
    32 
    33 #define AR_CTX_PRINT        0x01
    34 #define AR_CTX_LIST     0x02
    35 #define AR_CTX_EXTRACT      0x04
    36 #define AR_OPT_PRESERVE_DATE    0x08
    37 #define AR_OPT_VERBOSE      0x10
    38 #define AR_OPT_CREATE       0x20
    39 #define AR_OPT_INSERT       0x40
    40 
    41 int ar_main(int argc, char **argv);
    42 int ar_main(int argc, char **argv)
    43 {
    44     static const char msg_unsupported_err[] ALIGN1 =
    45         "archive %s is not supported";
    46 
     175    printf("%s %u/%u%7"OFF_FMT"u %s %s\n", &mode[1],
     176            (int)file_header->uid, (int)file_header->gid,
     177            file_header->size,
     178            &mtime[4], file_header->name
     179    );
     180}
     181
     182#define AR_OPT_VERBOSE          (1 << 0)
     183#define AR_OPT_PRESERVE_DATE    (1 << 1)
     184/* "ar r" implies create, but warns about it. c suppresses warning.
     185 * bbox accepts but ignores it: */
     186#define AR_OPT_CREATE           (1 << 2)
     187
     188#define AR_CMD_PRINT            (1 << 3)
     189#define FIRST_CMD               AR_CMD_PRINT
     190#define AR_CMD_LIST             (1 << 4)
     191#define AR_CMD_EXTRACT          (1 << 5)
     192#define AR_CMD_INSERT           (1 << 6)
     193
     194int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     195int ar_main(int argc UNUSED_PARAM, char **argv)
     196{
    47197    archive_handle_t *archive_handle;
    48     unsigned opt;
    49     char magic[8];
     198    unsigned opt, t;
    50199
    51200    archive_handle = init_handle();
    52201
    53     /* Prepend '-' to the first argument if required */
    54     opt_complementary = "--:p:t:x:-1:p--tx:t--px:x--pt";
    55     opt = getopt32(argv, "ptxovcr");
    56 
    57     if (opt & AR_CTX_PRINT) {
     202    /* --: prepend '-' to the first argument if required */
     203    /* -1: at least one param is reqd */
     204    /* one of p,t,x[,r] is required */
     205    opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r");
     206    opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r"));
     207    argv += optind;
     208
     209    t = opt / FIRST_CMD;
     210    if (t & (t-1)) /* more than one of p,t,x[,r] are specified */
     211        bb_show_usage();
     212
     213    if (opt & AR_CMD_PRINT) {
    58214        archive_handle->action_data = data_extract_to_stdout;
    59215    }
    60     if (opt & AR_CTX_LIST) {
     216    if (opt & AR_CMD_LIST) {
    61217        archive_handle->action_header = header_list;
    62218    }
    63     if (opt & AR_CTX_EXTRACT) {
     219    if (opt & AR_CMD_EXTRACT) {
    64220        archive_handle->action_data = data_extract_all;
    65221    }
    66222    if (opt & AR_OPT_PRESERVE_DATE) {
    67         archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
     223        archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
    68224    }
    69225    if (opt & AR_OPT_VERBOSE) {
    70226        archive_handle->action_header = header_verbose_list_ar;
    71227    }
    72     if (opt & AR_OPT_CREATE) {
    73         bb_error_msg_and_die(msg_unsupported_err, "creation");
    74     }
    75     if (opt & AR_OPT_INSERT) {
    76         bb_error_msg_and_die(msg_unsupported_err, "insertion");
    77     }
    78 
    79     archive_handle->src_fd = xopen(argv[optind++], O_RDONLY);
    80 
    81     while (optind < argc) {
     228#if ENABLE_FEATURE_AR_CREATE
     229    archive_handle->ar__name = *argv;
     230#endif
     231    archive_handle->src_fd = xopen(*argv++,
     232            (opt & AR_CMD_INSERT)
     233                ? O_RDWR | O_CREAT
     234                : O_RDONLY
     235    );
     236
     237    if (*argv)
    82238        archive_handle->filter = filter_accept_list;
    83         llist_add_to(&(archive_handle->accept), argv[optind++]);
    84     }
    85 
    86     xread(archive_handle->src_fd, magic, 7);
    87     if (strncmp(magic, "!<arch>", 7) != 0) {
    88         bb_error_msg_and_die("invalid ar magic");
    89     }
    90     archive_handle->offset += 7;
    91 
    92     while (get_header_ar(archive_handle) == EXIT_SUCCESS)
    93         continue;
     239    while (*argv) {
     240        llist_add_to_end(&archive_handle->accept, *argv++);
     241    }
     242
     243#if ENABLE_FEATURE_AR_CREATE
     244    if (opt & AR_CMD_INSERT)
     245        return write_ar_archive(archive_handle);
     246#endif
     247
     248    unpack_ar_archive(archive_handle);
    94249
    95250    return EXIT_SUCCESS;
  • branches/2.2.9/mindi-busybox/archival/bbunzip.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  *  Common code for gunzip-like applets
    4  *
    5  *  Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    6  */
    7 
     3 * Common code for gunzip-like applets
     4 *
     5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     6 */
    87#include "libbb.h"
    9 #include "unarchive.h"
     8#include "archive.h"
    109
    1110enum {
    12     OPT_STDOUT = 0x1,
    13     OPT_FORCE = 0x2,
    14 /* gunzip only: */
    15     OPT_VERBOSE = 0x4,
    16     OPT_DECOMPRESS = 0x8,
    17     OPT_TEST = 0x10,
     11    OPT_STDOUT     = 1 << 0,
     12    OPT_FORCE      = 1 << 1,
     13    /* only some decompressors: */
     14    OPT_VERBOSE    = 1 << 2,
     15    OPT_DECOMPRESS = 1 << 3,
     16    OPT_TEST       = 1 << 4,
    1817};
    1918
     
    2928}
    3029
    31 int bbunpack(char **argv,
    32     char* (*make_new_name)(char *filename),
    33     USE_DESKTOP(long long) int (*unpacker)(void)
     30char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
     31{
     32    return xasprintf("%s.%s", filename, expected_ext);
     33}
     34
     35int FAST_FUNC bbunpack(char **argv,
     36    IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info),
     37    char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
     38    const char *expected_ext
    3439)
    3540{
    3641    struct stat stat_buf;
    37     USE_DESKTOP(long long) int status;
     42    IF_DESKTOP(long long) int status;
    3843    char *filename, *new_name;
    3944    smallint exitcode = 0;
     45    unpack_info_t info;
    4046
    4147    do {
     
    5056        if (filename) {
    5157            if (stat(filename, &stat_buf) != 0) {
    52                 bb_perror_msg("%s", filename);
     58                bb_simple_perror_msg(filename);
    5359 err:
    5460                exitcode = 1;
     
    6975        /* Open dst if we are going to unpack to file */
    7076        if (filename) {
    71             new_name = make_new_name(filename);
     77            new_name = make_new_name(filename, expected_ext);
    7278            if (!new_name) {
    7379                bb_error_msg("%s: unknown suffix - ignored", filename);
    7480                goto err;
    7581            }
     82
     83            /* -f: overwrite existing output files */
     84            if (option_mask32 & OPT_FORCE) {
     85                unlink(new_name);
     86            }
     87
    7688            /* O_EXCL: "real" bunzip2 doesn't overwrite files */
    77             /* GNU gunzip goes not bail out, but goes to next file */
     89            /* GNU gunzip does not bail out, but goes to next file */
    7890            if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
    7991                    stat_buf.st_mode))
     
    8799        }
    88100
    89         status = unpacker();
     101        /* memset(&info, 0, sizeof(info)); */
     102        info.mtime = 0; /* so far it has one member only */
     103        status = unpacker(&info);
    90104        if (status < 0)
    91105            exitcode = 1;
     106        xclose(STDOUT_FILENO); /* with error check! */
    92107
    93108        if (filename) {
    94109            char *del = new_name;
    95110            if (status >= 0) {
    96                 /* TODO: restore user/group/times here? */
     111                /* TODO: restore other things? */
     112                if (info.mtime) {
     113                    struct timeval times[2];
     114
     115                    times[1].tv_sec = times[0].tv_sec = info.mtime;
     116                    times[1].tv_usec = times[0].tv_usec = 0;
     117                    /* Note: we closed it first.
     118                     * On some systems calling utimes
     119                     * then closing resets the mtime
     120                     * back to current time. */
     121                    utimes(new_name, times); /* ignoring errors */
     122                }
     123
    97124                /* Delete _compressed_ file */
    98125                del = filename;
     
    120147}
    121148
    122 #if ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNCOMPRESS
    123 
    124 static
    125 char* make_new_name_generic(char *filename, const char *expected_ext)
     149#if ENABLE_UNCOMPRESS || ENABLE_BUNZIP2 || ENABLE_UNLZMA || ENABLE_UNXZ
     150static
     151char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
    126152{
    127153    char *extension = strrchr(filename, '.');
     
    134160    return filename;
    135161}
    136 
    137 #endif
    138 
    139 
    140 /*
    141  *  Modified for busybox by Glenn McGrath <bug1@iinet.net.au>
    142  *  Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
    143  *
    144  *  Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    145  */
    146 
    147 #if ENABLE_BUNZIP2
    148 
    149 static
    150 char* make_new_name_bunzip2(char *filename)
    151 {
    152     return make_new_name_generic(filename, "bz2");
    153 }
    154 
    155 static
    156 USE_DESKTOP(long long) int unpack_bunzip2(void)
    157 {
    158     return unpack_bz2_stream(STDIN_FILENO, STDOUT_FILENO);
    159 }
    160 
    161 int bunzip2_main(int argc, char **argv);
    162 int bunzip2_main(int argc, char **argv)
     162#endif
     163
     164
     165/*
     166 * Uncompress applet for busybox (c) 2002 Glenn McGrath
     167 *
     168 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     169 */
     170#if ENABLE_UNCOMPRESS
     171static
     172IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM)
     173{
     174    IF_DESKTOP(long long) int status = -1;
     175
     176    if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
     177        bb_error_msg("invalid magic");
     178    } else {
     179        status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
     180    }
     181    return status;
     182}
     183int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     184int uncompress_main(int argc UNUSED_PARAM, char **argv)
    163185{
    164186    getopt32(argv, "cf");
    165187    argv += optind;
    166     if (applet_name[2] == 'c')
    167         option_mask32 |= OPT_STDOUT;
    168 
    169     return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2);
    170 }
    171 
     188
     189    return bbunpack(argv, unpack_uncompress, make_new_name_generic, "Z");
     190}
    172191#endif
    173192
     
    186205 *
    187206 * General cleanup to better adhere to the style guide and make use of standard
    188  * busybox functions by Glenn McGrath <bug1@iinet.net.au>
    189  *
    190  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     207 * busybox functions by Glenn McGrath
     208 *
     209 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    191210 *
    192211 * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
     
    200219 * See the file algorithm.doc for the compression algorithms and file formats.
    201220 */
    202 
    203221#if ENABLE_GUNZIP
    204 
    205 static
    206 char* make_new_name_gunzip(char *filename)
     222static
     223char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
    207224{
    208225    char *extension = strrchr(filename, '.');
     
    213230    extension++;
    214231    if (strcmp(extension, "tgz" + 1) == 0
    215 #if ENABLE_FEATURE_GUNZIP_UNCOMPRESS
    216      || strcmp(extension, "Z") == 0
     232#if ENABLE_FEATURE_SEAMLESS_Z
     233     || (extension[0] == 'Z' && extension[1] == '\0')
    217234#endif
    218235    ) {
     
    228245    return filename;
    229246}
    230 
    231 static
    232 USE_DESKTOP(long long) int unpack_gunzip(void)
    233 {
    234     USE_DESKTOP(long long) int status = -1;
     247static
     248IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info)
     249{
     250    IF_DESKTOP(long long) int status = -1;
    235251
    236252    /* do the decompression, and cleanup */
     
    239255
    240256        magic2 = xread_char(STDIN_FILENO);
    241         if (ENABLE_FEATURE_GUNZIP_UNCOMPRESS && magic2 == 0x9d) {
    242             status = uncompress(STDIN_FILENO, STDOUT_FILENO);
     257        if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) {
     258            status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
    243259        } else if (magic2 == 0x8b) {
    244             check_header_gzip_or_die(STDIN_FILENO);
    245             status = unpack_gz_stream(STDIN_FILENO, STDOUT_FILENO);
     260            status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info);
    246261        } else {
    247262            goto bad_magic;
     
    257272    return status;
    258273}
    259 
    260 int gunzip_main(int argc, char **argv);
    261 int gunzip_main(int argc, char **argv)
    262 {
    263     getopt32(argv, "cfvdt");
     274/*
     275 * Linux kernel build uses gzip -d -n. We accept and ignore it.
     276 * Man page says:
     277 * -n --no-name
     278 * gzip: do not save the original file name and time stamp.
     279 * (The original name is always saved if the name had to be truncated.)
     280 * gunzip: do not restore the original file name/time even if present
     281 * (remove only the gzip suffix from the compressed file name).
     282 * This option is the default when decompressing.
     283 * -N --name
     284 * gzip: always save the original file name and time stamp (this is the default)
     285 * gunzip: restore the original file name and time stamp if present.
     286 */
     287int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     288int gunzip_main(int argc UNUSED_PARAM, char **argv)
     289{
     290    getopt32(argv, "cfvdtn");
    264291    argv += optind;
    265292    /* if called as zcat */
     
    267294        option_mask32 |= OPT_STDOUT;
    268295
    269     return bbunpack(argv, make_new_name_gunzip, unpack_gunzip);
    270 }
    271 
     296    return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL);
     297}
     298#endif
     299
     300
     301/*
     302 * Modified for busybox by Glenn McGrath
     303 * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
     304 *
     305 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     306 */
     307//usage:#define bunzip2_trivial_usage
     308//usage:       "[-cf] [FILE]..."
     309//usage:#define bunzip2_full_usage "\n\n"
     310//usage:       "Decompress FILEs (or stdin)\n"
     311//usage:     "\nOptions:"
     312//usage:     "\n    -c  Write to stdout"
     313//usage:     "\n    -f  Force"
     314//usage:#define bzcat_trivial_usage
     315//usage:       "FILE"
     316//usage:#define bzcat_full_usage "\n\n"
     317//usage:       "Decompress to stdout"
     318//applet:IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP))
     319//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat))
     320#if ENABLE_BUNZIP2
     321static
     322IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM)
     323{
     324    return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO);
     325}
     326int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     327int bunzip2_main(int argc UNUSED_PARAM, char **argv)
     328{
     329    getopt32(argv, "cfvdt");
     330    argv += optind;
     331    if (applet_name[2] == 'c') /* bzcat */
     332        option_mask32 |= OPT_STDOUT;
     333
     334    return bbunpack(argv, unpack_bunzip2, make_new_name_generic, "bz2");
     335}
    272336#endif
    273337
     
    279343 * Based on bunzip.c from busybox
    280344 *
    281  * Licensed under GPL v2, see file LICENSE in this tarball for details.
    282  */
    283 
     345 * Licensed under GPLv2, see file LICENSE in this source tree.
     346 */
    284347#if ENABLE_UNLZMA
    285 
    286 static
    287 char* make_new_name_unlzma(char *filename)
    288 {
    289     return make_new_name_generic(filename, "lzma");
    290 }
    291 
    292 static
    293 USE_DESKTOP(long long) int unpack_unlzma(void)
     348static
     349IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM)
    294350{
    295351    return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO);
    296352}
    297 
    298 int unlzma_main(int argc, char **argv);
    299 int unlzma_main(int argc, char **argv)
    300 {
    301     getopt32(argv, "cf");
     353int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     354int unlzma_main(int argc UNUSED_PARAM, char **argv)
     355{
     356    IF_LZMA(int opts =) getopt32(argv, "cfvdt");
     357# if ENABLE_LZMA
     358    /* lzma without -d or -t? */
     359    if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
     360        bb_show_usage();
     361# endif
     362    /* lzcat? */
     363    if (applet_name[2] == 'c')
     364        option_mask32 |= OPT_STDOUT;
     365
    302366    argv += optind;
    303     /* lzmacat? */
    304     if (applet_name[4] == 'c')
     367    return bbunpack(argv, unpack_unlzma, make_new_name_generic, "lzma");
     368}
     369#endif
     370
     371
     372#if ENABLE_UNXZ
     373static
     374IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM)
     375{
     376    struct {
     377        uint32_t v1;
     378        uint16_t v2;
     379    } magic;
     380    xread(STDIN_FILENO, &magic, 6);
     381    if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) {
     382        bb_error_msg("invalid magic");
     383        return -1;
     384    }
     385    return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO);
     386}
     387int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     388int unxz_main(int argc UNUSED_PARAM, char **argv)
     389{
     390    IF_XZ(int opts =) getopt32(argv, "cfvdt");
     391# if ENABLE_XZ
     392    /* xz without -d or -t? */
     393    if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST)))
     394        bb_show_usage();
     395# endif
     396    /* xzcat? */
     397    if (applet_name[2] == 'c')
    305398        option_mask32 |= OPT_STDOUT;
    306399
    307     return bbunpack(argv, make_new_name_unlzma, unpack_unlzma);
    308 }
    309 
    310 #endif
    311 
    312 
    313 /*
    314  *  Uncompress applet for busybox (c) 2002 Glenn McGrath
    315  *
    316  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    317  */
    318 
    319 #if ENABLE_UNCOMPRESS
    320 
    321 static
    322 char* make_new_name_uncompress(char *filename)
    323 {
    324     return make_new_name_generic(filename, "Z");
    325 }
    326 
    327 static
    328 USE_DESKTOP(long long) int unpack_uncompress(void)
    329 {
    330     USE_DESKTOP(long long) int status = -1;
    331 
    332     if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
    333         bb_error_msg("invalid magic");
    334     } else {
    335         status = uncompress(STDIN_FILENO, STDOUT_FILENO);
    336     }
    337     return status;
    338 }
    339 
    340 int uncompress_main(int argc, char **argv);
    341 int uncompress_main(int argc, char **argv)
    342 {
    343     getopt32(argv, "cf");
    344400    argv += optind;
    345 
    346     return bbunpack(argv, make_new_name_uncompress, unpack_uncompress);
    347 }
    348 
    349 #endif
     401    return bbunpack(argv, unpack_unxz, make_new_name_generic, "xz");
     402}
     403#endif
  • branches/2.2.9/mindi-busybox/archival/cpio.c

    r1765 r2725  
    55 * Copyright (C) 2001 by Glenn McGrath
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 *
    99 * Limitations:
    10  *      Doesn't check CRC's
    11  *      Only supports new ASCII and CRC formats
     10 * Doesn't check CRC's
     11 * Only supports new ASCII and CRC formats
    1212 *
    1313 */
    1414#include "libbb.h"
    15 #include "unarchive.h"
    16 
    17 #define CPIO_OPT_EXTRACT                0x01
    18 #define CPIO_OPT_TEST                   0x02
    19 #define CPIO_OPT_UNCONDITIONAL          0x04
    20 #define CPIO_OPT_VERBOSE                0x08
    21 #define CPIO_OPT_FILE                   0x10
    22 #define CPIO_OPT_CREATE_LEADING_DIR     0x20
    23 #define CPIO_OPT_PRESERVE_MTIME         0x40
    24 
    25 int cpio_main(int argc, char **argv);
    26 int cpio_main(int argc, char **argv)
     15#include "archive.h"
     16
     17/* GNU cpio 2.9 --help (abridged):
     18
     19 Modes:
     20  -t, --list                 List the archive
     21  -i, --extract              Extract files from an archive
     22  -o, --create               Create the archive
     23  -p, --pass-through         Copy-pass mode [was ist das?!]
     24
     25 Options valid in any mode:
     26      --block-size=SIZE      I/O block size = SIZE * 512 bytes
     27  -B                         I/O block size = 5120 bytes
     28  -c                         Use the old portable (ASCII) archive format
     29  -C, --io-size=NUMBER       I/O block size in bytes
     30  -f, --nonmatching          Only copy files that do not match given pattern
     31  -F, --file=FILE            Use FILE instead of standard input or output
     32  -H, --format=FORMAT        Use given archive FORMAT
     33  -M, --message=STRING       Print STRING when the end of a volume of the
     34                             backup media is reached
     35  -n, --numeric-uid-gid      If -v, show numeric UID and GID
     36      --quiet                Do not print the number of blocks copied
     37      --rsh-command=COMMAND  Use remote COMMAND instead of rsh
     38  -v, --verbose              Verbosely list the files processed
     39  -V, --dot                  Print a "." for each file processed
     40  -W, --warning=FLAG         Control warning display: 'none','truncate','all';
     41                             multiple options accumulate
     42
     43 Options valid only in --extract mode:
     44  -b, --swap                 Swap both halfwords of words and bytes of
     45                             halfwords in the data (equivalent to -sS)
     46  -r, --rename               Interactively rename files
     47  -s, --swap-bytes           Swap the bytes of each halfword in the files
     48  -S, --swap-halfwords       Swap the halfwords of each word (4 bytes)
     49      --to-stdout            Extract files to standard output
     50  -E, --pattern-file=FILE    Read additional patterns specifying filenames to
     51                             extract or list from FILE
     52      --only-verify-crc      Verify CRC's, don't actually extract the files
     53
     54 Options valid only in --create mode:
     55  -A, --append               Append to an existing archive
     56  -O FILE                    File to use instead of standard output
     57
     58 Options valid only in --pass-through mode:
     59  -l, --link                 Link files instead of copying them, when possible
     60
     61 Options valid in --extract and --create modes:
     62      --absolute-filenames   Do not strip file system prefix components from
     63                             the file names
     64      --no-absolute-filenames Create all files relative to the current dir
     65
     66 Options valid in --create and --pass-through modes:
     67  -0, --null                 A list of filenames is terminated by a NUL
     68  -a, --reset-access-time    Reset the access times of files after reading them
     69  -I FILE                    File to use instead of standard input
     70  -L, --dereference          Dereference symbolic links (copy the files
     71                             that they point to instead of copying the links)
     72  -R, --owner=[USER][:.][GROUP] Set owner of created files
     73
     74 Options valid in --extract and --pass-through modes:
     75  -d, --make-directories     Create leading directories where needed
     76  -m, --preserve-modification-time  Retain mtime when creating files
     77      --no-preserve-owner    Do not change the ownership of the files
     78      --sparse               Write files with blocks of zeros as sparse files
     79  -u, --unconditional        Replace all files unconditionally
     80 */
     81enum {
     82    CPIO_OPT_EXTRACT            = (1 << 0),
     83    CPIO_OPT_TEST               = (1 << 1),
     84    CPIO_OPT_NUL_TERMINATED     = (1 << 2),
     85    CPIO_OPT_UNCONDITIONAL      = (1 << 3),
     86    CPIO_OPT_VERBOSE            = (1 << 4),
     87    CPIO_OPT_CREATE_LEADING_DIR = (1 << 5),
     88    CPIO_OPT_PRESERVE_MTIME     = (1 << 6),
     89    CPIO_OPT_DEREF              = (1 << 7),
     90    CPIO_OPT_FILE               = (1 << 8),
     91    OPTBIT_FILE = 8,
     92    IF_FEATURE_CPIO_O(OPTBIT_CREATE     ,)
     93    IF_FEATURE_CPIO_O(OPTBIT_FORMAT     ,)
     94    IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
     95    IF_LONG_OPTS(     OPTBIT_QUIET      ,)
     96    IF_LONG_OPTS(     OPTBIT_2STDOUT    ,)
     97    CPIO_OPT_CREATE             = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE     )) + 0,
     98    CPIO_OPT_FORMAT             = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT     )) + 0,
     99    CPIO_OPT_PASSTHROUGH        = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
     100    CPIO_OPT_QUIET              = IF_LONG_OPTS(     (1 << OPTBIT_QUIET      )) + 0,
     101    CPIO_OPT_2STDOUT            = IF_LONG_OPTS(     (1 << OPTBIT_2STDOUT    )) + 0,
     102};
     103
     104#define OPTION_STR "it0uvdmLF:"
     105
     106#if ENABLE_FEATURE_CPIO_O
     107static off_t cpio_pad4(off_t size)
     108{
     109    int i;
     110
     111    i = (- size) & 3;
     112    size += i;
     113    while (--i >= 0)
     114        bb_putchar('\0');
     115    return size;
     116}
     117
     118/* Return value will become exit code.
     119 * It's ok to exit instead of return. */
     120static NOINLINE int cpio_o(void)
     121{
     122    static const char trailer[] ALIGN1 = "TRAILER!!!";
     123    struct name_s {
     124        struct name_s *next;
     125        char name[1];
     126    };
     127    struct inodes_s {
     128        struct inodes_s *next;
     129        struct name_s *names;
     130        struct stat st;
     131    };
     132
     133    struct inodes_s *links = NULL;
     134    off_t bytes = 0; /* output bytes count */
     135
     136    while (1) {
     137        const char *name;
     138        char *line;
     139        struct stat st;
     140
     141        line = (option_mask32 & CPIO_OPT_NUL_TERMINATED)
     142                ? bb_get_chunk_from_file(stdin, NULL)
     143                : xmalloc_fgetline(stdin);
     144
     145        if (line) {
     146            /* Strip leading "./[./]..." from the filename */
     147            name = line;
     148            while (name[0] == '.' && name[1] == '/') {
     149                while (*++name == '/')
     150                    continue;
     151            }
     152            if (!*name) { /* line is empty */
     153                free(line);
     154                continue;
     155            }
     156            if ((option_mask32 & CPIO_OPT_DEREF)
     157                    ? stat(name, &st)
     158                    : lstat(name, &st)
     159            ) {
     160 abort_cpio_o:
     161                bb_simple_perror_msg_and_die(name);
     162            }
     163
     164            if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
     165                st.st_size = 0; /* paranoia */
     166
     167            /* Store hardlinks for later processing, dont output them */
     168            if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
     169                struct name_s *n;
     170                struct inodes_s *l;
     171
     172                /* Do we have this hardlink remembered? */
     173                l = links;
     174                while (1) {
     175                    if (l == NULL) {
     176                        /* Not found: add new item to "links" list */
     177                        l = xzalloc(sizeof(*l));
     178                        l->st = st;
     179                        l->next = links;
     180                        links = l;
     181                        break;
     182                    }
     183                    if (l->st.st_ino == st.st_ino) {
     184                        /* found */
     185                        break;
     186                    }
     187                    l = l->next;
     188                }
     189                /* Add new name to "l->names" list */
     190                n = xmalloc(sizeof(*n) + strlen(name));
     191                strcpy(n->name, name);
     192                n->next = l->names;
     193                l->names = n;
     194
     195                free(line);
     196                continue;
     197            }
     198
     199        } else { /* line == NULL: EOF */
     200 next_link:
     201            if (links) {
     202                /* Output hardlink's data */
     203                st = links->st;
     204                name = links->names->name;
     205                links->names = links->names->next;
     206                /* GNU cpio is reported to emit file data
     207                 * only for the last instance. Mimic that. */
     208                if (links->names == NULL)
     209                    links = links->next;
     210                else
     211                    st.st_size = 0;
     212                /* NB: we leak links->names and/or links,
     213                 * this is intended (we exit soon anyway) */
     214            } else {
     215                /* If no (more) hardlinks to output,
     216                 * output "trailer" entry */
     217                name = trailer;
     218                /* st.st_size == 0 is a must, but for uniformity
     219                 * in the output, we zero out everything */
     220                memset(&st, 0, sizeof(st));
     221                /* st.st_nlink = 1; - GNU cpio does this */
     222            }
     223        }
     224
     225        bytes += printf("070701"
     226                        "%08X%08X%08X%08X%08X%08X%08X"
     227                        "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
     228                /* strlen+1: */ "%08X"
     229                /* chksum: */   "00000000" /* (only for "070702" files) */
     230                /* name,NUL: */ "%s%c",
     231                        (unsigned)(uint32_t) st.st_ino,
     232                        (unsigned)(uint32_t) st.st_mode,
     233                        (unsigned)(uint32_t) st.st_uid,
     234                        (unsigned)(uint32_t) st.st_gid,
     235                        (unsigned)(uint32_t) st.st_nlink,
     236                        (unsigned)(uint32_t) st.st_mtime,
     237                        (unsigned)(uint32_t) st.st_size,
     238                        (unsigned)(uint32_t) major(st.st_dev),
     239                        (unsigned)(uint32_t) minor(st.st_dev),
     240                        (unsigned)(uint32_t) major(st.st_rdev),
     241                        (unsigned)(uint32_t) minor(st.st_rdev),
     242                        (unsigned)(strlen(name) + 1),
     243                        name, '\0');
     244        bytes = cpio_pad4(bytes);
     245
     246        if (st.st_size) {
     247            if (S_ISLNK(st.st_mode)) {
     248                char *lpath = xmalloc_readlink_or_warn(name);
     249                if (!lpath)
     250                    goto abort_cpio_o;
     251                bytes += printf("%s", lpath);
     252                free(lpath);
     253            } else { /* S_ISREG */
     254                int fd = xopen(name, O_RDONLY);
     255                fflush_all();
     256                /* We must abort if file got shorter too! */
     257                bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
     258                bytes += st.st_size;
     259                close(fd);
     260            }
     261            bytes = cpio_pad4(bytes);
     262        }
     263
     264        if (!line) {
     265            if (name != trailer)
     266                goto next_link;
     267            /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
     268            return EXIT_SUCCESS;
     269        }
     270
     271        free(line);
     272    } /* end of "while (1)" */
     273}
     274#endif
     275
     276int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     277int cpio_main(int argc UNUSED_PARAM, char **argv)
    27278{
    28279    archive_handle_t *archive_handle;
    29     char *cpio_filename = NULL;
     280    char *cpio_filename;
     281    IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
    30282    unsigned opt;
    31283
    32     /* Initialise */
     284#if ENABLE_LONG_OPTS
     285    applet_long_options =
     286        "extract\0"      No_argument       "i"
     287        "list\0"         No_argument       "t"
     288#if ENABLE_FEATURE_CPIO_O
     289        "create\0"       No_argument       "o"
     290        "format\0"       Required_argument "H"
     291#if ENABLE_FEATURE_CPIO_P
     292        "pass-through\0" No_argument       "p"
     293#endif
     294#endif
     295        "verbose\0"      No_argument       "v"
     296        "quiet\0"        No_argument       "\xff"
     297        "to-stdout\0"    No_argument       "\xfe"
     298        ;
     299#endif
     300
    33301    archive_handle = init_handle();
    34     archive_handle->src_fd = STDIN_FILENO;
    35     archive_handle->seek = seek_by_read;
    36     archive_handle->flags = ARCHIVE_EXTRACT_NEWER | ARCHIVE_PRESERVE_DATE;
    37 
    38     opt = getopt32(argv, "ituvF:dm", &cpio_filename);
     302    /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */
     303    archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
     304
     305    /* As of now we do not enforce this: */
     306    /* -i,-t,-o,-p are mutually exclusive */
     307    /* -u,-d,-m make sense only with -i or -p */
     308    /* -L makes sense only with -o or -p */
     309
     310#if !ENABLE_FEATURE_CPIO_O
     311    opt = getopt32(argv, OPTION_STR, &cpio_filename);
     312    argv += optind;
     313    if (opt & CPIO_OPT_FILE) { /* -F */
     314        xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
     315    }
     316#else
     317    opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
     318    argv += optind;
     319    if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */
     320        xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
     321    }
     322    if (opt & CPIO_OPT_PASSTHROUGH) {
     323        pid_t pid;
     324        struct fd_pair pp;
     325
     326        if (argv[0] == NULL)
     327            bb_show_usage();
     328        if (opt & CPIO_OPT_CREATE_LEADING_DIR)
     329            mkdir(argv[0], 0777);
     330        /* Crude existence check:
     331         * close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
     332         * We can also xopen, fstat, IS_DIR, later fchdir.
     333         * This would check for existence earlier and cleaner.
     334         * As it stands now, if we fail xchdir later,
     335         * child dies on EPIPE, unless it caught
     336         * a diffrerent problem earlier.
     337         * This is good enough for now.
     338         */
     339#if !BB_MMU
     340        pp.rd = 3;
     341        pp.wr = 4;
     342        if (!re_execed) {
     343            close(3);
     344            close(4);
     345            xpiped_pair(pp);
     346        }
     347#else
     348        xpiped_pair(pp);
     349#endif
     350        pid = fork_or_rexec(argv - optind);
     351        if (pid == 0) { /* child */
     352            close(pp.rd);
     353            xmove_fd(pp.wr, STDOUT_FILENO);
     354            goto dump;
     355        }
     356        /* parent */
     357        xchdir(*argv++);
     358        close(pp.wr);
     359        xmove_fd(pp.rd, STDIN_FILENO);
     360        //opt &= ~CPIO_OPT_PASSTHROUGH;
     361        opt |= CPIO_OPT_EXTRACT;
     362        goto skip;
     363    }
     364    /* -o */
     365    if (opt & CPIO_OPT_CREATE) {
     366        if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
     367            bb_show_usage();
     368        if (opt & CPIO_OPT_FILE) {
     369            xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
     370        }
     371 dump:
     372        return cpio_o();
     373    }
     374 skip:
     375#endif
    39376
    40377    /* One of either extract or test options must be given */
     
    45382    if (opt & CPIO_OPT_TEST) {
    46383        /* if both extract and test options are given, ignore extract option */
    47         if (opt & CPIO_OPT_EXTRACT) {
    48             opt &= ~CPIO_OPT_EXTRACT;
    49         }
     384        opt &= ~CPIO_OPT_EXTRACT;
    50385        archive_handle->action_header = header_list;
    51386    }
    52387    if (opt & CPIO_OPT_EXTRACT) {
    53388        archive_handle->action_data = data_extract_all;
     389        if (opt & CPIO_OPT_2STDOUT)
     390            archive_handle->action_data = data_extract_to_stdout;
    54391    }
    55392    if (opt & CPIO_OPT_UNCONDITIONAL) {
    56         archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
    57         archive_handle->flags &= ~ARCHIVE_EXTRACT_NEWER;
     393        archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
     394        archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
    58395    }
    59396    if (opt & CPIO_OPT_VERBOSE) {
     
    64401        }
    65402    }
    66     if (cpio_filename) { /* CPIO_OPT_FILE */
    67         archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);
    68         archive_handle->seek = seek_by_jump;
    69     }
    70403    if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
    71         archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
    72     }
    73 
    74     while (optind < argc) {
     404        archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
     405    }
     406    if (opt & CPIO_OPT_PRESERVE_MTIME) {
     407        archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
     408    }
     409
     410    while (*argv) {
    75411        archive_handle->filter = filter_accept_list;
    76         llist_add_to(&(archive_handle->accept), argv[optind]);
    77         optind++;
    78     }
    79 
    80     while (get_header_cpio(archive_handle) == EXIT_SUCCESS);
     412        llist_add_to(&archive_handle->accept, *argv);
     413        argv++;
     414    }
     415
     416    /* see get_header_cpio */
     417    archive_handle->cpio__blocks = (off_t)-1;
     418    while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
     419        continue;
     420
     421    if (archive_handle->cpio__blocks != (off_t)-1
     422     && !(opt & CPIO_OPT_QUIET)
     423    ) {
     424        fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
     425    }
    81426
    82427    return EXIT_SUCCESS;
  • branches/2.2.9/mindi-busybox/archival/dpkg.c

    r1765 r2725  
    77 *  copyright (c) 2001 by glenn mcgrath
    88 *
     9 *  parts of the version comparison code is plucked from the real dpkg
     10 *  application which is licensed GPLv2 and
     11 *  copyright (c) 1995 Ian Jackson <ian@chiark.greenend.org.uk>
     12 *
    913 *  started life as a busybox implementation of udpkg
    1014 *
    11  * licensed under gplv2 or later, see file license in this tarball for details.
     15 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1216 */
    1317
     
    2630
    2731#include "libbb.h"
    28 #include "unarchive.h"
     32#include <fnmatch.h>
     33#include "archive.h"
    2934
    3035/* note: if you vary hash_prime sizes be aware,
     
    7681} status_node_t;
    7782
    78 /* Were statically declared here, but such a big bss is nommu-unfriendly */
    79 static char **name_hashtable;             /* [NAME_HASH_PRIME + 1] */
    80 static common_node_t **package_hashtable; /* [PACKAGE_HASH_PRIME + 1] */
    81 static status_node_t **status_hashtable;  /* [STATUS_HASH_PRIME + 1] */
     83
     84/* Globals */
     85struct globals {
     86    char          *name_hashtable[NAME_HASH_PRIME + 1];
     87    common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1];
     88    status_node_t *status_hashtable[STATUS_HASH_PRIME + 1];
     89};
     90#define G (*ptr_to_globals)
     91#define name_hashtable    (G.name_hashtable   )
     92#define package_hashtable (G.package_hashtable)
     93#define status_hashtable  (G.status_hashtable )
     94#define INIT_G() do { \
     95    SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
     96} while (0)
     97
    8298
    8399/* Even numbers are for 'extras', like ored dependencies or null */
     
    124140         * shift amount is mod 24 because long int is 32 bit and data
    125141         * to be shifted is 8, don't want to shift data to where it has
    126          * no effect*/
    127         hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24));
     142         * no effect */
     143        hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24);
    128144    }
    129145    *start = (unsigned) hash_num % hash_prime;
     
    134150static int search_name_hashtable(const char *key)
    135151{
    136     unsigned probe_address = 0;
    137     unsigned probe_decrement = 0;
     152    unsigned probe_address;
     153    unsigned probe_decrement;
    138154
    139155    make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME);
     
    156172static unsigned search_status_hashtable(const char *key)
    157173{
    158     unsigned probe_address = 0;
    159     unsigned probe_decrement = 0;
     174    unsigned probe_address;
     175    unsigned probe_decrement;
    160176
    161177    make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME);
     
    172188}
    173189
    174 /* Need to rethink version comparison, maybe the official dpkg has something i can use ? */
    175 static int version_compare_part(const char *version1, const char *version2)
    176 {
    177     int upstream_len1 = 0;
    178     int upstream_len2 = 0;
    179     char *name1_char;
    180     char *name2_char;
    181     int len1 = 0;
    182     int len2 = 0;
    183     int tmp_int;
    184     int ver_num1;
    185     int ver_num2;
    186 
    187     if (version1 == NULL) {
    188         version1 = xstrdup("");
    189     }
    190     if (version2 == NULL) {
    191         version2 = xstrdup("");
    192     }
    193     upstream_len1 = strlen(version1);
    194     upstream_len2 = strlen(version2);
    195 
    196     while ((len1 < upstream_len1) || (len2 < upstream_len2)) {
    197         /* Compare non-digit section */
    198         tmp_int = strcspn(&version1[len1], "0123456789");
    199         name1_char = xstrndup(&version1[len1], tmp_int);
    200         len1 += tmp_int;
    201         tmp_int = strcspn(&version2[len2], "0123456789");
    202         name2_char = xstrndup(&version2[len2], tmp_int);
    203         len2 += tmp_int;
    204         tmp_int = strcmp(name1_char, name2_char);
    205         free(name1_char);
    206         free(name2_char);
    207         if (tmp_int != 0) {
    208             return tmp_int;
    209         }
    210 
    211         /* Compare digits */
    212         tmp_int = strspn(&version1[len1], "0123456789");
    213         name1_char = xstrndup(&version1[len1], tmp_int);
    214         len1 += tmp_int;
    215         tmp_int = strspn(&version2[len2], "0123456789");
    216         name2_char = xstrndup(&version2[len2], tmp_int);
    217         len2 += tmp_int;
    218         ver_num1 = atoi(name1_char);
    219         ver_num2 = atoi(name2_char);
    220         free(name1_char);
    221         free(name2_char);
    222         if (ver_num1 < ver_num2) {
     190static int order(char x)
     191{
     192    return (x == '~' ? -1
     193        : x == '\0' ? 0
     194        : isdigit(x) ? 0
     195        : isalpha(x) ? x
     196        : (unsigned char)x + 256
     197    );
     198}
     199
     200/* This code is taken from dpkg and modified slightly to work with busybox */
     201static int version_compare_part(const char *val, const char *ref)
     202{
     203    if (!val) val = "";
     204    if (!ref) ref = "";
     205
     206    while (*val || *ref) {
     207        int first_diff;
     208
     209        while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) {
     210            int vc = order(*val);
     211            int rc = order(*ref);
     212            if (vc != rc)
     213                return vc - rc;
     214            val++;
     215            ref++;
     216        }
     217
     218        while (*val == '0')
     219            val++;
     220        while (*ref == '0')
     221            ref++;
     222
     223        first_diff = 0;
     224        while (isdigit(*val) && isdigit(*ref)) {
     225            if (first_diff == 0)
     226                first_diff = *val - *ref;
     227            val++;
     228            ref++;
     229        }
     230        if (isdigit(*val))
     231            return 1;
     232        if (isdigit(*ref))
    223233            return -1;
    224         }
    225         if (ver_num1 > ver_num2) {
    226             return 1;
    227         }
     234        if (first_diff)
     235            return first_diff;
    228236    }
    229237    return 0;
     
    238246    char *ch_ver1 = name_hashtable[ver1];
    239247    char *ch_ver2 = name_hashtable[ver2];
    240 
    241     char epoch1, epoch2;
     248    unsigned epoch1 = 0, epoch2 = 0;
     249    char *colon;
    242250    char *deb_ver1, *deb_ver2;
    243     char *ver1_ptr, *ver2_ptr;
    244251    char *upstream_ver1;
    245252    char *upstream_ver2;
     
    247254
    248255    /* Compare epoch */
    249     if (ch_ver1[1] == ':') {
    250         epoch1 = ch_ver1[0];
    251         ver1_ptr = strchr(ch_ver1, ':') + 1;
    252     } else {
    253         epoch1 = '0';
    254         ver1_ptr = ch_ver1;
    255     }
    256     if (ch_ver2[1] == ':') {
    257         epoch2 = ch_ver2[0];
    258         ver2_ptr = strchr(ch_ver2, ':') + 1;
    259     } else {
    260         epoch2 = '0';
    261         ver2_ptr = ch_ver2;
     256    colon = strchr(ch_ver1, ':');
     257    if (colon) {
     258        epoch1 = atoi(ch_ver1);
     259        ch_ver1 = colon + 1;
     260    }
     261    colon = strchr(ch_ver2, ':');
     262    if (colon) {
     263        epoch2 = atoi(ch_ver2);
     264        ch_ver2 = colon + 1;
    262265    }
    263266    if (epoch1 < epoch2) {
    264267        return -1;
    265268    }
    266     else if (epoch1 > epoch2) {
     269    if (epoch1 > epoch2) {
    267270        return 1;
    268271    }
    269272
    270273    /* Compare upstream version */
    271     upstream_ver1 = xstrdup(ver1_ptr);
    272     upstream_ver2 = xstrdup(ver2_ptr);
     274    upstream_ver1 = xstrdup(ch_ver1);
     275    upstream_ver2 = xstrdup(ch_ver2);
    273276
    274277    /* Chop off debian version, and store for later use */
     
    276279    deb_ver2 = strrchr(upstream_ver2, '-');
    277280    if (deb_ver1) {
    278         deb_ver1[0] = '\0';
    279         deb_ver1++;
     281        *deb_ver1++ = '\0';
    280282    }
    281283    if (deb_ver2) {
    282         deb_ver2[0] = '\0';
    283         deb_ver2++;
     284        *deb_ver2++ = '\0';
    284285    }
    285286    result = version_compare_part(upstream_ver1, upstream_ver2);
    286     if (!result)
     287    if (result == 0) {
    287288        /* Compare debian versions */
    288289        result = version_compare_part(deb_ver1, deb_ver2);
     290    }
    289291
    290292    free(upstream_ver1);
     
    313315}
    314316
    315 
    316317static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator)
    317318{
    318     unsigned probe_address = 0;
    319     unsigned probe_decrement = 0;
     319    unsigned probe_address;
     320    unsigned probe_decrement;
    320321
    321322    make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME);
     
    373374static void add_edge_to_node(common_node_t *node, edge_t *edge)
    374375{
    375     node->num_of_edges++;
    376     node->edge = xrealloc(node->edge, sizeof(edge_t) * (node->num_of_edges + 1));
    377     node->edge[node->num_of_edges - 1] = edge;
     376    node->edge = xrealloc_vector(node->edge, 2, node->num_of_edges);
     377    node->edge[node->num_of_edges++] = edge;
    378378}
    379379
     
    411411         && (strcmp(field, field2) != 0)
    412412        ) {
    413             or_edge = xmalloc(sizeof(edge_t));
     413            or_edge = xzalloc(sizeof(edge_t));
    414414            or_edge->type = edge_type + 1;
    415415            or_edge->name = search_name_hashtable(field);
    416             or_edge->version = 0; // tracks the number of alternatives
     416            //or_edge->version = 0; // tracks the number of alternatives
    417417            add_edge_to_node(parent_node, or_edge);
    418418        }
     
    440440                    if (strncmp(version, "=", offset_ch) == 0) {
    441441                        edge->operator = VER_EQUAL;
    442                     }
    443                     else if (strncmp(version, "<<", offset_ch) == 0) {
     442                    } else if (strncmp(version, "<<", offset_ch) == 0) {
    444443                        edge->operator = VER_LESS;
    445                     }
    446                     else if (strncmp(version, "<=", offset_ch) == 0) {
     444                    } else if (strncmp(version, "<=", offset_ch) == 0) {
    447445                        edge->operator = VER_LESS_EQUAL;
    448                     }
    449                     else if (strncmp(version, ">>", offset_ch) == 0) {
     446                    } else if (strncmp(version, ">>", offset_ch) == 0) {
    450447                        edge->operator = VER_MORE;
    451                     }
    452                     else if (strncmp(version, ">=", offset_ch) == 0) {
     448                    } else if (strncmp(version, ">=", offset_ch) == 0) {
    453449                        edge->operator = VER_MORE_EQUAL;
    454450                    } else {
     
    497493
    498494/*
    499  * Gets the next package field from package_buffer, seperated into the field name
     495 * Gets the next package field from package_buffer, separated into the field name
    500496 * and field value, it returns the int offset to the first character of the next field
    501497 */
     
    603599
    604600        if (field_name == NULL) {
    605             goto fill_package_struct_cleanup; /* Oh no, the dreaded goto statement! */
     601            goto fill_package_struct_cleanup;
    606602        }
    607603
     
    736732}
    737733
    738 
    739734static void index_status_file(const char *filename)
    740735{
     
    745740    unsigned status_num;
    746741
    747     status_file = xfopen(filename, "r");
    748     while ((control_buffer = xmalloc_fgets_str(status_file, "\n\n")) != NULL) {
     742    status_file = xfopen_for_read(filename);
     743    while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) {
    749744        const unsigned package_num = fill_package_struct(control_buffer);
    750745        if (package_num != -1) {
     
    787782static void write_status_file(deb_file_t **deb_file)
    788783{
    789     FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r");
    790     FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w");
     784    FILE *old_status_file = xfopen_for_read("/var/lib/dpkg/status");
     785    FILE *new_status_file = xfopen_for_write("/var/lib/dpkg/status.udeb");
    791786    char *package_name;
    792787    char *status_from_file;
     
    799794
    800795    /* Update previously known packages */
    801     while ((control_buffer = xmalloc_fgets_str(old_status_file, "\n\n")) != NULL) {
     796    while ((control_buffer = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) {
    802797        tmp_string = strstr(control_buffer, "Package:");
    803798        if (tmp_string == NULL) {
     
    811806        tmp_string = strstr(control_buffer, "Status:");
    812807        if (tmp_string != NULL) {
    813             /* Seperate the status value from the control buffer */
     808            /* Separate the status value from the control buffer */
    814809            tmp_string += 7;
    815810            tmp_string += strspn(tmp_string, " \n\t");
     
    863858                            break;
    864859                        }
    865                         if ((strcmp(field_name, "Priority") == 0) ||
    866                             (strcmp(field_name, "Section") == 0)) {
     860                        if ((strcmp(field_name, "Priority") == 0)
     861                         || (strcmp(field_name, "Section") == 0)
     862                        ) {
    867863                            fprintf(new_status_file, "%s: %s\n", field_name, field_value);
    868864                        }
     
    871867                    fputs("\n", new_status_file);
    872868                }
    873                 else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
     869                else if (strcmp("config-files", name_hashtable[state_status]) == 0) {
    874870                    /* only change the status line */
    875871                    while (1) {
     
    914910    fclose(new_status_file);
    915911
    916 
    917912    /* Create a separate backfile to dpkg */
    918913    if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) {
    919         struct stat stat_buf;
    920         xstat("/var/lib/dpkg/status", &stat_buf);
     914        if (errno != ENOENT)
     915            bb_error_msg_and_die("can't create backup status file");
    921916        /* Its ok if renaming the status file fails because status
    922917         * file doesnt exist, maybe we are starting from scratch */
     
    924919    }
    925920
    926     if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) {
    927         bb_error_msg_and_die("DANGER: cannot create status file, "
    928             "you need to manually repair your status file");
    929     }
     921    xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status");
    930922}
    931923
     
    948940
    949941    switch (depend_type) {
    950     case EDGE_PRE_DEPENDS:  return get_status(status_num, 3) == search_name_hashtable("installed");
    951     case EDGE_DEPENDS:  return get_status(status_num, 1) == search_name_hashtable("install");
     942    case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed");
     943    case EDGE_DEPENDS:     return get_status(status_num, 1) == search_name_hashtable("install");
    952944    }
    953945    return 0;
    954946}
    955947
    956 static int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count)
     948static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */)
    957949{
    958950    int *conflicts = NULL;
     
    972964    while (deb_file[i] != NULL) {
    973965        const unsigned package_num = deb_file[i]->package;
    974         conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
     966        conflicts = xrealloc_vector(conflicts, 2, conflicts_num);
    975967        conflicts[conflicts_num] = package_num;
    976968        conflicts_num++;
    977969        /* add provides to conflicts list */
    978         for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
     970        for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
    979971            if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
    980972                const int conflicts_package_num = search_package_hashtable(
     
    989981                    package_hashtable[conflicts_package_num] = new_node;
    990982                }
    991                 conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1));
     983                conflicts = xrealloc_vector(conflicts, 2, conflicts_num);
    992984                conflicts[conflicts_num] = conflicts_package_num;
    993985                conflicts_num++;
     
    10761068            if (package_edge->type == EDGE_OR_PRE_DEPENDS
    10771069             || package_edge->type == EDGE_OR_DEPENDS
    1078             ) { /* start an EDGE_OR_ list */
     1070            ) {
     1071                /* start an EDGE_OR_ list */
    10791072                number_of_alternatives = package_edge->version;
    10801073                root_of_alternatives = package_edge;
    10811074                continue;
    10821075            }
    1083             if (number_of_alternatives == 0) {  /* not in the middle of an EDGE_OR_ list */
     1076            if (number_of_alternatives == 0) {  /* not in the middle of an EDGE_OR_ list */
    10841077                number_of_alternatives = 1;
    10851078                root_of_alternatives = NULL;
     
    10881081            package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator);
    10891082
    1090             if (package_edge->type == EDGE_PRE_DEPENDS ||
    1091                 package_edge->type == EDGE_DEPENDS) {
     1083            if (package_edge->type == EDGE_PRE_DEPENDS
     1084             || package_edge->type == EDGE_DEPENDS
     1085            ) {
    10921086                int result=1;
    10931087                status_num = 0;
     
    11571151{
    11581152    FILE *list_stream;
    1159     char **file_list = NULL;
    1160     char *line = NULL;
    1161     int count = 0;
     1153    char **file_list;
     1154    char *line;
     1155    int count;
    11621156
    11631157    /* don't use [xw]fopen here, handle error ourself */
    1164     list_stream = fopen(filename, "r");
     1158    list_stream = fopen_for_read(filename);
    11651159    if (list_stream == NULL) {
    11661160        return NULL;
    11671161    }
    11681162
    1169     while ((line = xmalloc_getline(list_stream)) != NULL) {
    1170         file_list = xrealloc(file_list, sizeof(char *) * (count + 2));
    1171         file_list[count] = line;
    1172         count++;
     1163    file_list = NULL;
     1164    count = 0;
     1165    while ((line = xmalloc_fgetline(list_stream)) != NULL) {
     1166        file_list = xrealloc_vector(file_list, 2, count);
     1167        file_list[count++] = line;
     1168        /*file_list[count] = NULL; - xrealloc_vector did it */
    11731169    }
    11741170    fclose(list_stream);
    11751171
    1176     if (count == 0) {
    1177         return NULL;
    1178     }
    1179     file_list[count] = NULL;
    11801172    return file_list;
    11811173}
     
    12141206}
    12151207
    1216 static int run_package_script(const char *package_name, const char *script_type)
    1217 {
    1218     struct stat path_stat;
     1208static void run_package_script_or_die(const char *package_name, const char *script_type)
     1209{
    12191210    char *script_path;
    12201211    int result;
     
    12221213    script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type);
    12231214
    1224     /* If the file doesnt exist is isnt a fatal */
    1225     result = lstat(script_path, &path_stat) < 0 ? EXIT_SUCCESS : system(script_path);
     1215    /* If the file doesnt exist is isnt fatal */
     1216    result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path);
    12261217    free(script_path);
    1227     return result;
    1228 }
    1229 
     1218    if (result)
     1219        bb_error_msg_and_die("%s failed, exit code %d", script_type, result);
     1220}
     1221
     1222/*
     1223The policy manual defines what scripts get called when and with
     1224what arguments. I realize that busybox does not support all of
     1225these scenarios, but it does support some of them; it does not,
     1226however, run them with any parameters in run_package_script_or_die().
     1227Here are the scripts:
     1228
     1229preinst install
     1230preinst install <old_version>
     1231preinst upgrade <old_version>
     1232preinst abort_upgrade <new_version>
     1233postinst configure <most_recent_version>
     1234postinst abort-upgade <new_version>
     1235postinst abort-remove
     1236postinst abort-remove in-favour <package> <version>
     1237postinst abort-deconfigure in-favor <failed_install_package> removing <conflicting_package> <version>
     1238prerm remove
     1239prerm upgrade <new_version>
     1240prerm failed-upgrade <old_version>
     1241prerm remove in-favor <package> <new_version>
     1242prerm deconfigure in-favour <package> <version> removing <package> <version>
     1243postrm remove
     1244postrm purge
     1245postrm upgrade <new_version>
     1246postrm failed-upgrade <old_version>
     1247postrm abort-install
     1248postrm abort-install <old_version>
     1249postrm abort-upgrade <old_version>
     1250postrm disappear <overwriter> <version>
     1251*/
    12301252static const char *const all_control_files[] = {
    12311253    "preinst", "postinst", "prerm", "postrm",
    12321254    "list", "md5sums", "shlibs", "conffiles",
    1233     "config", "templates", NULL
     1255    "config", "templates"
    12341256};
    12351257
     
    12401262
    12411263    /* Create a list of all /var/lib/dpkg/info/<package> files */
    1242     remove_files = xzalloc(sizeof(all_control_files));
    1243     while (all_control_files[i]) {
    1244         remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, all_control_files[i]);
     1264    remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*));
     1265    while (i < ARRAY_SIZE(all_control_files)) {
     1266        remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s",
     1267                package_name, all_control_files[i]);
    12451268        i++;
    12461269    }
     
    12651288 * scanning the status file. The resulting list, however, is unsorted.
    12661289 */
    1267 static void list_packages(void)
     1290static void list_packages(const char *pattern)
    12681291{
    12691292    int i;
     
    12861309            vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version];
    12871310
     1311            if (pattern && fnmatch(pattern, name_str, 0) != 0)
     1312                continue;
     1313
    12881314            /* get abbreviation for status field 1 */
    12891315            s1 = stat_str[0] == 'i' ? 'i' : 'r';
     
    13151341        printf("Removing %s (%s)...\n", package_name, package_version);
    13161342
    1317     /* run prerm script */
    1318     if (run_package_script(package_name, "prerm") != 0) {
    1319         bb_error_msg_and_die("script failed, prerm failure");
    1320     }
     1343    /* Run prerm script */
     1344    run_package_script_or_die(package_name, "prerm");
    13211345
    13221346    /* Create a list of files to remove, and a separate list of those to keep */
    1323     sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
     1347    sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list");
    13241348    remove_files = create_list(list_name);
    13251349
    1326     sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name);
     1350    sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles");
    13271351    exclude_files = create_list(conffile_name);
    13281352
    13291353    /* Some directories can't be removed straight away, so do multiple passes */
    1330     while (remove_file_array(remove_files, exclude_files)) /*repeat */;
     1354    while (remove_file_array(remove_files, exclude_files))
     1355        continue;
    13311356    free_array(exclude_files);
    13321357    free_array(remove_files);
    13331358
    1334     /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep  */
    1335     exclude_files = xzalloc(sizeof(char*) * 3);
     1359    /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */
     1360    exclude_files = xzalloc(sizeof(exclude_files[0]) * 3);
    13361361    exclude_files[0] = xstrdup(conffile_name);
    1337     exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.postrm", package_name);
     1362    exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm");
    13381363
    13391364    /* Create a list of all /var/lib/dpkg/info/<package> files */
     
    13441369    free_array(exclude_files);
    13451370
    1346     /* rename <package>.conffile to <package>.list */
     1371    /* rename <package>.conffiles to <package>.list
     1372     * The conffiles control file isn't required in Debian packages, so don't
     1373     * error out if it's missing.  */
    13471374    rename(conffile_name, list_name);
    13481375
     
    13621389    printf("Purging %s (%s)...\n", package_name, package_version);
    13631390
    1364     /* run prerm script */
    1365     if (run_package_script(package_name, "prerm") != 0) {
    1366         bb_error_msg_and_die("script failed, prerm failure");
    1367     }
     1391    /* Run prerm script */
     1392    run_package_script_or_die(package_name, "prerm");
    13681393
    13691394    /* Create a list of files to remove */
    1370     sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name);
     1395    sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list");
    13711396    remove_files = create_list(list_name);
    13721397
    1373     exclude_files = xzalloc(sizeof(char*));
    1374 
    13751398    /* Some directories cant be removed straight away, so do multiple passes */
    1376     while (remove_file_array(remove_files, exclude_files)) /* repeat */;
     1399    while (remove_file_array(remove_files, NULL))
     1400        continue;
    13771401    free_array(remove_files);
    13781402
    13791403    /* Create a list of all /var/lib/dpkg/info/<package> files */
    13801404    remove_files = all_control_list(package_name);
     1405
     1406    /* Delete all of them except the postrm script */
     1407    exclude_files = xzalloc(sizeof(exclude_files[0]) * 2);
     1408    exclude_files[0] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm");
    13811409    remove_file_array(remove_files, exclude_files);
     1410    free_array(exclude_files);
     1411
     1412    /* Run and remove postrm script */
     1413    run_package_script_or_die(package_name, "postrm");
     1414    remove_file_array(remove_files, NULL);
     1415
    13821416    free_array(remove_files);
    1383     free(exclude_files);
    1384 
    1385     /* run postrm script */
    1386     if (run_package_script(package_name, "postrm") != 0) {
    1387         bb_error_msg_and_die("postrm failure.. set status to what?");
    1388     }
    13891417
    13901418    /* Change package status */
     
    14131441
    14141442    /* We don't care about data.tar.* or debian-binary, just control.tar.* */
    1415 #if ENABLE_FEATURE_DEB_TAR_GZ
     1443#if ENABLE_FEATURE_SEAMLESS_GZ
    14161444    llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz");
    14171445#endif
    1418 #if ENABLE_FEATURE_DEB_TAR_BZ2
     1446#if ENABLE_FEATURE_SEAMLESS_BZ2
    14191447    llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2");
    14201448#endif
    14211449
    14221450    /* Assign the tar handle as a subarchive of the ar handle */
    1423     ar_handle->sub_archive = tar_handle;
     1451    ar_handle->dpkg__sub_archive = tar_handle;
    14241452}
    14251453
     
    14331461
    14341462    /* We don't care about control.tar.* or debian-binary, just data.tar.* */
    1435 #if ENABLE_FEATURE_DEB_TAR_GZ
     1463#if ENABLE_FEATURE_SEAMLESS_GZ
    14361464    llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz");
    14371465#endif
    1438 #if ENABLE_FEATURE_DEB_TAR_BZ2
     1466#if ENABLE_FEATURE_SEAMLESS_BZ2
    14391467    llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2");
    14401468#endif
    14411469
    14421470    /* Assign the tar handle as a subarchive of the ar handle */
    1443     ar_handle->sub_archive = tar_handle;
     1471    ar_handle->dpkg__sub_archive = tar_handle;
     1472}
     1473
     1474static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle)
     1475{
     1476    unsigned size = archive_handle->file_header->size;
     1477
     1478    archive_handle->dpkg__buffer = xzalloc(size + 1);
     1479    xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size);
    14441480}
    14451481
    14461482static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept)
    14471483{
    1448     ar_handle->sub_archive->action_data = data_extract_to_buffer;
    1449     ar_handle->sub_archive->accept = myaccept;
    1450     ar_handle->sub_archive->filter = filter_accept_list;
     1484    ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer;
     1485    ar_handle->dpkg__sub_archive->accept = myaccept;
     1486    ar_handle->dpkg__sub_archive->filter = filter_accept_list;
    14511487
    14521488    unpack_ar_archive(ar_handle);
    14531489    close(ar_handle->src_fd);
    14541490
    1455     return ar_handle->sub_archive->buffer;
    1456 }
    1457 
    1458 static void data_extract_all_prefix(archive_handle_t *archive_handle)
     1491    return ar_handle->dpkg__sub_archive->dpkg__buffer;
     1492}
     1493
     1494static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll)
     1495{
     1496    FILE *fp;
     1497    char *filename, *line;
     1498
     1499    filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name);
     1500    fp = fopen_for_read(filename);
     1501    free(filename);
     1502    if (fp != NULL) {
     1503        while ((line = xmalloc_fgetline(fp)) != NULL)
     1504            llist_add_to(ll, line);
     1505        fclose(fp);
     1506    }
     1507}
     1508
     1509static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle)
     1510{
     1511    int fd;
     1512    char *name_ptr = archive_handle->file_header->name + 1;
     1513
     1514    /* Is this file marked as config file? */
     1515    if (!find_list_entry(archive_handle->accept, name_ptr))
     1516        return EXIT_SUCCESS; /* no */
     1517
     1518    fd = open(name_ptr, O_RDONLY);
     1519    if (fd >= 0) {
     1520        md5_ctx_t md5;
     1521        char *md5line, *buf;
     1522        int count;
     1523
     1524        /* Calculate MD5 of existing file */
     1525        buf = xmalloc(4096);
     1526        md5_begin(&md5);
     1527        while ((count = safe_read(fd, buf, 4096)) > 0)
     1528            md5_hash(&md5, buf, count);
     1529        md5_end(&md5, buf); /* using buf as result storage */
     1530        close(fd);
     1531
     1532        md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1);
     1533        sprintf(bin2hex(md5line, buf, 16), "  %s", name_ptr);
     1534        free(buf);
     1535
     1536        /* Is it changed after install? */
     1537        if (find_list_entry(archive_handle->accept, md5line) == NULL) {
     1538            printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr);
     1539            archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name);
     1540        }
     1541        free(md5line);
     1542    }
     1543    return EXIT_SUCCESS;
     1544}
     1545
     1546static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
    14591547{
    14601548    char *name_ptr = archive_handle->file_header->name;
    14611549
    1462     name_ptr += strspn(name_ptr, "./");
     1550    /* Skip all leading "/" */
     1551    while (*name_ptr == '/')
     1552        name_ptr++;
     1553    /* Skip all leading "./" and "../" */
     1554    while (name_ptr[0] == '.') {
     1555        if (name_ptr[1] == '.')
     1556            name_ptr++;
     1557        if (name_ptr[1] != '/')
     1558            break;
     1559        name_ptr += 2;
     1560    }
     1561
    14631562    if (name_ptr[0] != '\0') {
    1464         archive_handle->file_header->name = xasprintf("%s%s", archive_handle->buffer, name_ptr);
     1563        archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr);
    14651564        data_extract_all(archive_handle);
    1466     }
    1467 }
     1565        if (fnmatch("*.dpkg-new", archive_handle->file_header->name, 0) == 0) {
     1566            /* remove .dpkg-new suffix */
     1567            archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = '\0';
     1568        }
     1569    }
     1570}
     1571
     1572enum {
     1573    /* Commands */
     1574    OPT_configure            = (1 << 0),
     1575    OPT_install              = (1 << 1),
     1576    OPT_list_installed       = (1 << 2),
     1577    OPT_purge                = (1 << 3),
     1578    OPT_remove               = (1 << 4),
     1579    OPT_unpack               = (1 << 5),
     1580    OPTMASK_cmd              = (1 << 6) - 1,
     1581    /* Options */
     1582    OPT_force                = (1 << 6),
     1583    OPT_force_ignore_depends = (1 << 7),
     1584    OPT_force_confnew        = (1 << 8),
     1585    OPT_force_confold        = (1 << 9),
     1586};
    14681587
    14691588static void unpack_package(deb_file_t *deb_file)
     
    14761595    archive_handle_t *archive_handle;
    14771596    FILE *out_stream;
    1478     llist_t *accept_list = NULL;
    1479     int i = 0;
     1597    llist_t *accept_list;
     1598    llist_t *conffile_list;
     1599    int i;
    14801600
    14811601    /* If existing version, remove it first */
     1602    conffile_list = NULL;
    14821603    if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) {
    14831604        /* Package is already installed, remove old version first */
     
    14851606            name_hashtable[package_hashtable[status_package_num]->version],
    14861607            deb_file->filename);
     1608
     1609        /* Read md5sums from old package */
     1610        if (!(option_mask32 & OPT_force_confold))
     1611            append_control_file_to_llist(package_name, "md5sums", &conffile_list);
     1612
    14871613        remove_package(status_package_num, 0);
    14881614    } else {
     
    14911617
    14921618    /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */
    1493     info_prefix = xasprintf("/var/lib/dpkg/info/%s.", package_name);
     1619    info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "");
    14941620    archive_handle = init_archive_deb_ar(deb_file->filename);
    14951621    init_archive_deb_control(archive_handle);
    14961622
    1497     while (all_control_files[i]) {
     1623    accept_list = NULL;
     1624    i = 0;
     1625    while (i < ARRAY_SIZE(all_control_files)) {
    14981626        char *c = xasprintf("./%s", all_control_files[i]);
    14991627        llist_add_to(&accept_list, c);
    15001628        i++;
    15011629    }
    1502     archive_handle->sub_archive->accept = accept_list;
    1503     archive_handle->sub_archive->filter = filter_accept_list;
    1504     archive_handle->sub_archive->action_data = data_extract_all_prefix;
    1505     archive_handle->sub_archive->buffer = info_prefix;
    1506     archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
     1630    archive_handle->dpkg__sub_archive->accept = accept_list;
     1631    archive_handle->dpkg__sub_archive->filter = filter_accept_list;
     1632    archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
     1633    archive_handle->dpkg__sub_archive->dpkg__buffer = info_prefix;
     1634    archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
    15071635    unpack_ar_archive(archive_handle);
    15081636
    15091637    /* Run the preinst prior to extracting */
    1510     if (run_package_script(package_name, "preinst") != 0) {
    1511         /* when preinst returns exit code != 0 then quit installation process */
    1512         bb_error_msg_and_die("subprocess pre-installation script returned error");
    1513     }
     1638    run_package_script_or_die(package_name, "preinst");
     1639
     1640    /* Don't overwrite existing config files */
     1641    if (!(option_mask32 & OPT_force_confnew))
     1642        append_control_file_to_llist(package_name, "conffiles", &conffile_list);
    15141643
    15151644    /* Extract data.tar.gz to the root directory */
    15161645    archive_handle = init_archive_deb_ar(deb_file->filename);
    15171646    init_archive_deb_data(archive_handle);
    1518     archive_handle->sub_archive->action_data = data_extract_all_prefix;
    1519     archive_handle->sub_archive->buffer = (char*)"/"; /* huh? */
    1520     archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
     1647    archive_handle->dpkg__sub_archive->accept = conffile_list;
     1648    archive_handle->dpkg__sub_archive->filter = filter_rename_config;
     1649    archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
     1650    archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */
     1651    archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
    15211652    unpack_ar_archive(archive_handle);
    15221653
    15231654    /* Create the list file */
    1524     list_filename = xasprintf("/var/lib/dpkg/info/%s.list", package_name);
    1525     out_stream = xfopen(list_filename, "w");
    1526     while (archive_handle->sub_archive->passed) {
     1655    list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list");
     1656    out_stream = xfopen_for_write(list_filename);
     1657    while (archive_handle->dpkg__sub_archive->passed) {
    15271658        /* the leading . has been stripped by data_extract_all_prefix already */
    1528         fputs(archive_handle->sub_archive->passed->data, out_stream);
     1659        fputs(archive_handle->dpkg__sub_archive->passed->data, out_stream);
    15291660        fputc('\n', out_stream);
    1530         archive_handle->sub_archive->passed = archive_handle->sub_archive->passed->link;
     1661        archive_handle->dpkg__sub_archive->passed = archive_handle->dpkg__sub_archive->passed->link;
    15311662    }
    15321663    fclose(out_stream);
     
    15491680
    15501681    /* Run the postinst script */
    1551     if (run_package_script(package_name, "postinst") != 0) {
    1552         /* TODO: handle failure gracefully */
    1553         bb_error_msg_and_die("postinst failure.. set status to what?");
    1554     }
     1682    /* TODO: handle failure gracefully */
     1683    run_package_script_or_die(package_name, "postinst");
     1684
    15551685    /* Change status to reflect success */
    15561686    set_status(status_num, "install", 1);
     
    15581688}
    15591689
    1560 int dpkg_main(int argc, char **argv);
    1561 int dpkg_main(int argc, char **argv)
     1690int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1691int dpkg_main(int argc UNUSED_PARAM, char **argv)
    15621692{
    15631693    deb_file_t **deb_file = NULL;
     
    15701700    int status_num;
    15711701    int i;
    1572     enum {
    1573         OPT_configure = 0x1,
    1574         OPT_force_ignore_depends = 0x2,
    1575         OPT_install = 0x4,
    1576         OPT_list_installed = 0x8,
    1577         OPT_purge = 0x10,
    1578         OPT_remove = 0x20,
    1579         OPT_unpack = 0x40,
    1580     };
    1581 
    1582     opt = getopt32(argv, "CF:ilPru", &str_f);
     1702#if ENABLE_LONG_OPTS
     1703    static const char dpkg_longopts[] ALIGN1 =
     1704// FIXME: we use -C non-compatibly, should be:
     1705// "-C|--audit Check for broken package(s)"
     1706        "configure\0"      No_argument        "C"
     1707        "force\0"          Required_argument  "F"
     1708        "install\0"        No_argument        "i"
     1709        "list\0"           No_argument        "l"
     1710        "purge\0"          No_argument        "P"
     1711        "remove\0"         No_argument        "r"
     1712        "unpack\0"         No_argument        "u"
     1713        "force-depends\0"  No_argument        "\xff"
     1714        "force-confnew\0"  No_argument        "\xfe"
     1715        "force-confold\0"  No_argument        "\xfd"
     1716        ;
     1717#endif
     1718
     1719    INIT_G();
     1720
     1721    IF_LONG_OPTS(applet_long_options = dpkg_longopts);
     1722    opt = getopt32(argv, "CilPruF:", &str_f);
     1723    argv += optind;
    15831724    //if (opt & OPT_configure) ... // -C
    1584     if (opt & OPT_force_ignore_depends) { // -F (--force in official dpkg)
    1585         if (strcmp(str_f, "depends"))
    1586             opt &= ~OPT_force_ignore_depends;
     1725    if (opt & OPT_force) { // -F (--force in official dpkg)
     1726        if (strcmp(str_f, "depends") == 0)
     1727            opt |= OPT_force_ignore_depends;
     1728        else if (strcmp(str_f, "confnew") == 0)
     1729            opt |= OPT_force_confnew;
     1730        else if (strcmp(str_f, "confold") == 0)
     1731            opt |= OPT_force_confold;
     1732        else
     1733            bb_show_usage();
     1734        option_mask32 = opt;
    15871735    }
    15881736    //if (opt & OPT_install) ... // -i
     
    15911739    //if (opt & OPT_remove) ... // -r
    15921740    //if (opt & OPT_unpack) ... // -u (--unpack in official dpkg)
    1593     argc -= optind;
    1594     argv += optind;
    1595     /* check for non-option argument if expected  */
    1596     if (!opt || (!argc && !(opt && OPT_list_installed)))
     1741    if (!(opt & OPTMASK_cmd) /* no cmd */
     1742     || ((opt & OPTMASK_cmd) & ((opt & OPTMASK_cmd)-1)) /* more than one cmd */
     1743    ) {
    15971744        bb_show_usage();
    1598 
    1599     name_hashtable = xzalloc(sizeof(name_hashtable[0]) * (NAME_HASH_PRIME + 1));
    1600     package_hashtable = xzalloc(sizeof(package_hashtable[0]) * (PACKAGE_HASH_PRIME + 1));
    1601     status_hashtable = xzalloc(sizeof(status_hashtable[0]) * (STATUS_HASH_PRIME + 1));
     1745    }
    16021746
    16031747/*  puts("(Reading database ... xxxxx files and directories installed.)"); */
     
    16061750    /* if the list action was given print the installed packages and exit */
    16071751    if (opt & OPT_list_installed) {
    1608         list_packages();
     1752        list_packages(argv[0]); /* param can be NULL */
    16091753        return EXIT_SUCCESS;
    16101754    }
     
    16131757    while (*argv) {
    16141758        /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */
    1615         deb_file = xrealloc(deb_file, sizeof(deb_file[0]) * (deb_count + 2));
     1759        deb_file = xrealloc_vector(deb_file, 2, deb_count);
    16161760        deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0]));
    16171761        if (opt & (OPT_install | OPT_unpack)) {
     
    16261770            deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list);
    16271771            if (deb_file[deb_count]->control_file == NULL) {
    1628                 bb_error_msg_and_die("cannot extract control file");
     1772                bb_error_msg_and_die("can't extract control file");
    16291773            }
    16301774            deb_file[deb_count]->filename = xstrdup(argv[0]);
     
    16941838    /* Check that the deb file arguments are installable */
    16951839    if (!(opt & OPT_force_ignore_depends)) {
    1696         if (!check_deps(deb_file, 0, deb_count)) {
     1840        if (!check_deps(deb_file, 0 /*, deb_count*/)) {
    16971841            bb_error_msg_and_die("dependency check failed");
    16981842        }
  • branches/2.2.9/mindi-busybox/archival/dpkg_deb.c

    r1765 r2725  
    33 * dpkg-deb packs, unpacks and provides information about Debian archives.
    44 *
    5  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    66 */
    77#include "libbb.h"
    8 #include "unarchive.h"
     8#include "archive.h"
    99
    10 #define DPKG_DEB_OPT_CONTENTS   1
    11 #define DPKG_DEB_OPT_CONTROL    2
    12 #define DPKG_DEB_OPT_FIELD  4
    13 #define DPKG_DEB_OPT_EXTRACT    8
    14 #define DPKG_DEB_OPT_EXTRACT_VERBOSE    16
     10#define DPKG_DEB_OPT_CONTENTS         1
     11#define DPKG_DEB_OPT_CONTROL          2
     12#define DPKG_DEB_OPT_FIELD            4
     13#define DPKG_DEB_OPT_EXTRACT          8
     14#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16
    1515
    16 int dpkg_deb_main(int argc, char **argv);
     16int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    1717int dpkg_deb_main(int argc, char **argv)
    1818{
     
    2121    llist_t *control_tar_llist = NULL;
    2222    unsigned opt;
    23     const char *extract_dir = NULL;
    24     short argcount = 1;
     23    const char *extract_dir;
     24    int need_args;
    2525
    2626    /* Setup the tar archive handle */
     
    2929    /* Setup an ar archive handle that refers to the gzip sub archive */
    3030    ar_archive = init_handle();
    31     ar_archive->sub_archive = tar_archive;
     31    ar_archive->dpkg__sub_archive = tar_archive;
    3232    ar_archive->filter = filter_accept_list_reassign;
    3333
    34 #if ENABLE_FEATURE_DEB_TAR_GZ
    35     llist_add_to(&(ar_archive->accept), (char*)"data.tar.gz");
     34#if ENABLE_FEATURE_SEAMLESS_GZ
     35    llist_add_to(&ar_archive->accept, (char*)"data.tar.gz");
    3636    llist_add_to(&control_tar_llist, (char*)"control.tar.gz");
    3737#endif
    38 
    39 #if ENABLE_FEATURE_DEB_TAR_BZ2
    40     llist_add_to(&(ar_archive->accept), (char*)"data.tar.bz2");
     38#if ENABLE_FEATURE_SEAMLESS_BZ2
     39    llist_add_to(&ar_archive->accept, (char*)"data.tar.bz2");
    4140    llist_add_to(&control_tar_llist, (char*)"control.tar.bz2");
    4241#endif
     42#if ENABLE_FEATURE_SEAMLESS_LZMA
     43    llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma");
     44    llist_add_to(&control_tar_llist, (char*)"control.tar.lzma");
     45#endif
    4346
    44     opt_complementary = "?c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX";
     47    opt_complementary = "c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX";
    4548    opt = getopt32(argv, "cefXx");
     49    argv += optind;
     50    argc -= optind;
    4651
    4752    if (opt & DPKG_DEB_OPT_CONTENTS) {
    4853        tar_archive->action_header = header_verbose_list;
    4954    }
     55    extract_dir = NULL;
     56    need_args = 1;
    5057    if (opt & DPKG_DEB_OPT_CONTROL) {
    5158        ar_archive->accept = control_tar_llist;
    5259        tar_archive->action_data = data_extract_all;
    53         if (optind + 1 == argc) {
     60        if (1 == argc) {
    5461            extract_dir = "./DEBIAN";
    5562        } else {
    56             argcount++;
     63            need_args++;
    5764        }
    5865    }
     
    7178    if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) {
    7279        tar_archive->action_data = data_extract_all;
    73         argcount = 2;
     80        need_args = 2;
    7481    }
    7582
    76     if ((optind + argcount) != argc) {
     83    if (need_args != argc) {
    7784        bb_show_usage();
    7885    }
    7986
    80     tar_archive->src_fd = ar_archive->src_fd = xopen(argv[optind++], O_RDONLY);
     87    tar_archive->src_fd = ar_archive->src_fd = xopen(argv[0], O_RDONLY);
    8188
    82     /* Workout where to extract the files */
     89    /* Work out where to extract the files */
    8390    /* 2nd argument is a dir name */
    84     if (argv[optind]) {
    85         extract_dir = argv[optind];
     91    if (argv[1]) {
     92        extract_dir = argv[1];
    8693    }
    8794    if (extract_dir) {
     
    8996        xchdir(extract_dir);
    9097    }
     98
     99    /* Do it */
    91100    unpack_ar_archive(ar_archive);
    92101
    93102    /* Cleanup */
    94     close(ar_archive->src_fd);
     103    if (ENABLE_FEATURE_CLEAN_UP)
     104        close(ar_archive->src_fd);
    95105
    96106    return EXIT_SUCCESS;
  • branches/2.2.9/mindi-busybox/archival/gzip.c

    r1765 r2725  
    1414 * command line handling.
    1515 *
    16  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1717 */
    1818
     
    4141
    4242#include "libbb.h"
     43#include "archive.h"
    4344
    4445
     
    6869#define SMALL_MEM
    6970
    70 #ifndef INBUFSIZ
     71#ifndef INBUFSIZ
    7172#  ifdef SMALL_MEM
    7273#    define INBUFSIZ  0x2000    /* input buffer size */
     
    7677#endif
    7778
    78 #ifndef OUTBUFSIZ
     79#ifndef OUTBUFSIZ
    7980#  ifdef SMALL_MEM
    8081#    define OUTBUFSIZ   8192    /* output buffer size */
     
    267268    type * array
    268269#define ALLOC(type, array, size) \
    269     array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type));
     270    array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type))
    270271#define FREE(array) \
    271272    do { free(array); array = NULL; } while (0)
     
    340341#endif
    341342
    342     uint32_t *crc_32_tab;
     343    /*uint32_t *crc_32_tab;*/
    343344    uint32_t crc;   /* shift register contents */
    344345};
     
    389390
    390391/* ===========================================================================
    391  * Clear input and output buffers
    392  */
    393 static void clear_bufs(void)
    394 {
    395     G1.outcnt = 0;
    396 #ifdef DEBUG
    397     G1.insize = 0;
    398 #endif
    399     G1.isize = 0;
    400 }
    401 
    402 
    403 /* ===========================================================================
    404392 * Run a set of bytes through the crc shift register.  If s is a NULL
    405393 * pointer, then initialize the crc shift register contents instead.
    406394 * Return the current crc in either case.
    407395 */
    408 static uint32_t updcrc(uch * s, unsigned n)
    409 {
    410     uint32_t c = G1.crc;
    411     while (n) {
    412         c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8);
    413         n--;
    414     }
    415     G1.crc = c;
    416     return c;
     396static void updcrc(uch * s, unsigned n)
     397{
     398    G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/);
    417399}
    418400
     
    633615         * or if the match length is less than 2:
    634616         */
    635         if (match[best_len] != scan_end ||
    636             match[best_len - 1] != scan_end1 ||
    637             *match != *scan || *++match != scan[1])
     617        if (match[best_len] != scan_end
     618         || match[best_len - 1] != scan_end1
     619         || *match != *scan || *++match != scan[1]
     620        ) {
    638621            continue;
     622        }
    639623
    640624        /* The check at best_len-1 can be removed because it will be made
     
    687671        bb_error_msg("\\[%d,%d]", start - match, length);
    688672        do {
    689             putc(G1.window[start++], stderr);
     673            bb_putchar_stderr(G1.window[start++]);
    690674        } while (--length != 0);
    691675    }
     
    975959#  define SEND_CODE(c, tree) \
    976960{ \
    977     if (verbose > 1) bb_error_msg("\ncd %3d ",(c)); \
     961    if (verbose > 1) bb_error_msg("\ncd %3d ", (c)); \
    978962    send_bits(tree[c].Code, tree[c].Len); \
    979963}
     
    11861170        Tracec(tree != G2.static_ltree,
    11871171               (stderr, "\nn %3d %c l %2d c %4x (%x) ", n,
    1188                 (isgraph(n) ? n : ' '), len, tree[n].Code,
     1172                (n > ' ' ? n : ' '), len, tree[n].Code,
    11891173                next_code[len] - 1));
    11901174    }
     
    15541538        if ((flag & 1) == 0) {
    15551539            SEND_CODE(lc, ltree);   /* send a literal byte */
    1556             Tracecv(isgraph(lc), (stderr, " '%c' ", lc));
     1540            Tracecv(lc > ' ', (stderr, " '%c' ", lc));
    15571541        } else {
    15581542            /* Here, lc is the match length - MIN_MATCH */
     
    20091993/* ======================================================================== */
    20101994static
    2011 char* make_new_name_gzip(char *filename)
    2012 {
    2013     return xasprintf("%s.gz", filename);
    2014 }
    2015 
    2016 static
    2017 USE_DESKTOP(long long) int pack_gzip(void)
     1995IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM)
    20181996{
    20191997    struct stat s;
    20201998
    2021     clear_bufs();
    2022     s.st_ctime = 0;
    2023     fstat(STDIN_FILENO, &s);
    2024     zip(s.st_ctime);
    2025     return 0;
    2026 }
    2027 
    2028 int gzip_main(int argc, char **argv);
    2029 int gzip_main(int argc, char **argv)
    2030 {
    2031     unsigned opt;
    2032 
    2033     /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
    2034     opt = getopt32(argv, "cfv" USE_GUNZIP("d") "q123456789" );
    2035     option_mask32 &= 0x7; /* Clear -d, ignore -q, -0..9 */
    2036     //if (opt & 0x1) // -c
    2037     //if (opt & 0x2) // -f
    2038     //if (opt & 0x4) // -v
    2039 #if ENABLE_GUNZIP /* gunzip_main may not be visible... */
    2040     if (opt & 0x8) { // -d
    2041         return gunzip_main(argc, argv);
    2042     }
    2043 #endif
    2044     argv += optind;
    2045 
    2046     PTR_TO_GLOBALS = xzalloc(sizeof(struct globals) + sizeof(struct globals2))
    2047             + sizeof(struct globals);
    2048     G2.l_desc.dyn_tree    = G2.dyn_ltree;
    2049     G2.l_desc.static_tree = G2.static_ltree;
    2050     G2.l_desc.extra_bits  = extra_lbits;
    2051     G2.l_desc.extra_base  = LITERALS + 1;
    2052     G2.l_desc.elems       = L_CODES;
    2053     G2.l_desc.max_length  = MAX_BITS;
    2054     //G2.l_desc.max_code    = 0;
    2055 
    2056     G2.d_desc.dyn_tree    = G2.dyn_dtree;
    2057     G2.d_desc.static_tree = G2.static_dtree;
    2058     G2.d_desc.extra_bits  = extra_dbits;
    2059     //G2.d_desc.extra_base  = 0;
    2060     G2.d_desc.elems       = D_CODES;
    2061     G2.d_desc.max_length  = MAX_BITS;
    2062     //G2.d_desc.max_code    = 0;
    2063 
     1999    /* Clear input and output buffers */
     2000    G1.outcnt = 0;
     2001#ifdef DEBUG
     2002    G1.insize = 0;
     2003#endif
     2004    G1.isize = 0;
     2005
     2006    /* Reinit G2.xxx */
     2007    memset(&G2, 0, sizeof(G2));
     2008    G2.l_desc.dyn_tree     = G2.dyn_ltree;
     2009    G2.l_desc.static_tree  = G2.static_ltree;
     2010    G2.l_desc.extra_bits   = extra_lbits;
     2011    G2.l_desc.extra_base   = LITERALS + 1;
     2012    G2.l_desc.elems        = L_CODES;
     2013    G2.l_desc.max_length   = MAX_BITS;
     2014    //G2.l_desc.max_code     = 0;
     2015    G2.d_desc.dyn_tree     = G2.dyn_dtree;
     2016    G2.d_desc.static_tree  = G2.static_dtree;
     2017    G2.d_desc.extra_bits   = extra_dbits;
     2018    //G2.d_desc.extra_base   = 0;
     2019    G2.d_desc.elems        = D_CODES;
     2020    G2.d_desc.max_length   = MAX_BITS;
     2021    //G2.d_desc.max_code     = 0;
    20642022    G2.bl_desc.dyn_tree    = G2.bl_tree;
    20652023    //G2.bl_desc.static_tree = NULL;
     
    20702028    //G2.bl_desc.max_code    = 0;
    20712029
     2030    s.st_ctime = 0;
     2031    fstat(STDIN_FILENO, &s);
     2032    zip(s.st_ctime);
     2033    return 0;
     2034}
     2035
     2036#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
     2037static const char gzip_longopts[] ALIGN1 =
     2038    "stdout\0"              No_argument       "c"
     2039    "to-stdout\0"           No_argument       "c"
     2040    "force\0"               No_argument       "f"
     2041    "verbose\0"             No_argument       "v"
     2042#if ENABLE_GUNZIP
     2043    "decompress\0"          No_argument       "d"
     2044    "uncompress\0"          No_argument       "d"
     2045    "test\0"                No_argument       "t"
     2046#endif
     2047    "quiet\0"               No_argument       "q"
     2048    "fast\0"                No_argument       "1"
     2049    "best\0"                No_argument       "9"
     2050    ;
     2051#endif
     2052
     2053/*
     2054 * Linux kernel build uses gzip -d -n. We accept and ignore -n.
     2055 * Man page says:
     2056 * -n --no-name
     2057 * gzip: do not save the original file name and time stamp.
     2058 * (The original name is always saved if the name had to be truncated.)
     2059 * gunzip: do not restore the original file name/time even if present
     2060 * (remove only the gzip suffix from the compressed file name).
     2061 * This option is the default when decompressing.
     2062 * -N --name
     2063 * gzip: always save the original file name and time stamp (this is the default)
     2064 * gunzip: restore the original file name and time stamp if present.
     2065 */
     2066
     2067int gzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     2068#if ENABLE_GUNZIP
     2069int gzip_main(int argc, char **argv)
     2070#else
     2071int gzip_main(int argc UNUSED_PARAM, char **argv)
     2072#endif
     2073{
     2074    unsigned opt;
     2075
     2076#if ENABLE_FEATURE_GZIP_LONG_OPTIONS
     2077    applet_long_options = gzip_longopts;
     2078#endif
     2079    /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
     2080    opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "q123456789n");
     2081#if ENABLE_GUNZIP /* gunzip_main may not be visible... */
     2082    if (opt & 0x18) // -d and/or -t
     2083        return gunzip_main(argc, argv);
     2084#endif
     2085    option_mask32 &= 0x7; /* ignore -q, -0..9 */
     2086    //if (opt & 0x1) // -c
     2087    //if (opt & 0x2) // -f
     2088    //if (opt & 0x4) // -v
     2089    argv += optind;
     2090
     2091    SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2))
     2092            + sizeof(struct globals));
     2093
    20722094    /* Allocate all global buffers (for DYN_ALLOC option) */
    20732095    ALLOC(uch, G1.l_buf, INBUFSIZ);
     
    20772099    ALLOC(ush, G1.prev, 1L << BITS);
    20782100
    2079     /* Initialise the CRC32 table */
    2080     G1.crc_32_tab = crc32_filltable(NULL, 0);
    2081 
    2082     return bbunpack(argv, make_new_name_gzip, pack_gzip);
    2083 }
     2101    /* Initialize the CRC32 table */
     2102    global_crc32_table = crc32_filltable(NULL, 0);
     2103
     2104    return bbunpack(argv, pack_gzip, append_ext, "gz");
     2105}
  • branches/2.2.9/mindi-busybox/archival/rpm.c

    r1765 r2725  
    55 * Copyright (C) 2001,2002 by Laurence Anderson
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99
    1010#include "libbb.h"
    11 #include "unarchive.h"
    12 
    13 #define RPM_HEADER_MAGIC        "\216\255\350"
     11#include "archive.h"
     12#include "rpm.h"
     13
    1414#define RPM_CHAR_TYPE           1
    1515#define RPM_INT8_TYPE           2
     
    4747#define TAG_BASENAMES           1117
    4848#define TAG_DIRNAMES            1118
     49
    4950#define RPMFILE_CONFIG          (1 << 0)
    5051#define RPMFILE_DOC             (1 << 1)
     
    7172static int tagcount;
    7273
    73 static void extract_cpio_gz(int fd);
     74static void extract_cpio(int fd, const char *source_rpm);
    7475static rpm_index **rpm_gettags(int fd, int *num_tags);
    7576static int bsearch_rpmtag(const void *key, const void *item);
     
    8182static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
    8283
    83 int rpm_main(int argc, char **argv);
     84int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    8485int rpm_main(int argc, char **argv)
    8586{
     
    116117    }
    117118    argv += optind;
    118     argc -= optind;
    119     if (!argc) bb_show_usage();
     119    //argc -= optind;
     120    if (!argv[0]) {
     121        bb_show_usage();
     122    }
    120123
    121124    while (*argv) {
     125        const char *source_rpm;
     126
    122127        rpm_fd = xopen(*argv++, O_RDONLY);
    123128        mytags = rpm_gettags(rpm_fd, &tagcount);
     
    128133        map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
    129134
     135        source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
     136
    130137        if (func & rpm_install) {
    131138            /* Backup any config files */
    132139            loop_through_files(TAG_BASENAMES, fileaction_dobackup);
    133140            /* Extact the archive */
    134             extract_cpio_gz(rpm_fd);
     141            extract_cpio(rpm_fd, source_rpm);
    135142            /* Set the correct file uid/gid's */
    136143            loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
     
    144151                /* Do the nice printout */
    145152                time_t bdate_time;
    146                 struct tm *bdate;
     153                struct tm *bdate_ptm;
    147154                char bdatestring[50];
    148                 printf("Name        : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_PREFIXS, 0) ? rpm_getstr(TAG_PREFIXS, 0) : "(not relocateable)");
    149                 printf("Version     : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_VENDOR, 0) ? rpm_getstr(TAG_VENDOR, 0) : "(none)");
     155                const char *p;
     156
     157                p = rpm_getstr(TAG_PREFIXS, 0);
     158                if (!p) p = "(not relocateable)";
     159                printf("Name        : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p);
     160                p = rpm_getstr(TAG_VENDOR, 0);
     161                if (!p) p = "(none)";
     162                printf("Version     : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p);
    150163                bdate_time = rpm_getint(TAG_BUILDTIME, 0);
    151                 bdate = localtime((time_t *) &bdate_time);
    152                 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate);
     164                bdate_ptm = localtime(&bdate_time);
     165                strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
    153166                printf("Release     : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
    154167                printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
    155                 printf("Group       : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), rpm_getstr(TAG_SOURCERPM, 0));
     168                printf("Group       : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm);
    156169                printf("Size        : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
    157170                printf("URL         : %s\n", rpm_getstr(TAG_URL, 0));
     
    186199}
    187200
    188 static void extract_cpio_gz(int fd)
     201static void extract_cpio(int fd, const char *source_rpm)
    189202{
    190203    archive_handle_t *archive_handle;
    191     unsigned char magic[2];
    192 #if BB_MMU
    193     USE_DESKTOP(long long) int (*xformer)(int src_fd, int dst_fd);
    194     enum { xformer_prog = 0 };
    195 #else
    196     enum { xformer = 0 };
    197     const char *xformer_prog;
    198 #endif
     204
     205    if (source_rpm != NULL) {
     206        /* Binary rpm (it was built from some SRPM), install to root */
     207        xchdir("/");
     208    } /* else: SRPM, install to current dir */
    199209
    200210    /* Initialize */
    201211    archive_handle = init_handle();
    202212    archive_handle->seek = seek_by_read;
    203     //archive_handle->action_header = header_list;
    204213    archive_handle->action_data = data_extract_all;
    205     archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
    206     archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
     214#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
     215    archive_handle->action_header = header_list;
     216    archive_handle->action_data = data_skip;
     217#endif
     218    archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
     219        /* compat: overwrite existing files.
     220         * try "rpm -i foo.src.rpm" few times in a row -
     221         * standard rpm will not complain.
     222         * (TODO? real rpm creates "file;1234" and then renames it) */
     223        | ARCHIVE_UNLINK_OLD;
    207224    archive_handle->src_fd = fd;
    208     archive_handle->offset = 0;
    209 
    210     xread(archive_handle->src_fd, &magic, 2);
    211 #if BB_MMU
    212     xformer = unpack_gz_stream;
    213 #else
    214     xformer_prog = "gunzip";
    215 #endif
    216     if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
    217         if (ENABLE_FEATURE_RPM_BZ2
    218          && (magic[0] == 0x42) && (magic[1] == 0x5a)) {
    219 #if BB_MMU
    220             xformer = unpack_bz2_stream;
    221 #else
    222             xformer_prog = "bunzip2";
    223 #endif
    224     /* We can do better, need modifying unpack_bz2_stream to not require
    225      * first 2 bytes. Not very hard to do... I mean, TODO :) */
    226             xlseek(archive_handle->src_fd, -2, SEEK_CUR);
    227         } else
    228             bb_error_msg_and_die("no gzip"
    229                 USE_FEATURE_RPM_BZ2("/bzip")
    230                 " magic");
    231     } else {
    232         check_header_gzip_or_die(archive_handle->src_fd);
    233 #if !BB_MMU
    234         /* NOMMU version of open_transformer execs an external unzipper that should
    235          * have the file position at the start of the file */
    236         xlseek(archive_handle->src_fd, 0, SEEK_SET);
    237 #endif
    238     }
    239 
    240     xchdir("/"); /* Install RPM's to root */
    241     archive_handle->src_fd = open_transformer(archive_handle->src_fd, xformer, xformer_prog, xformer_prog, "-cf", "-", NULL);
    242     archive_handle->offset = 0;
     225    /*archive_handle->offset = 0; - init_handle() did it */
     226
     227    setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/);
    243228    while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
    244229        continue;
    245230}
    246231
    247 
    248232static rpm_index **rpm_gettags(int fd, int *num_tags)
    249233{
    250     /* We should never need mode than 200, and realloc later */
    251     rpm_index **tags = xzalloc(200 * sizeof(struct rpmtag *));
     234    /* We should never need more than 200 (shrink via realloc later) */
     235    rpm_index **tags = xzalloc(200 * sizeof(tags[0]));
    252236    int pass, tagindex = 0;
    253237
     
    256240    /* 1st pass is the signature headers, 2nd is the main stuff */
    257241    for (pass = 0; pass < 2; pass++) {
    258         struct {
    259             char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
    260             uint8_t version; /* 1 byte version number */
    261             uint32_t reserved; /* 4 bytes reserved */
    262             uint32_t entries; /* Number of entries in header (4 bytes) */
    263             uint32_t size; /* Size of store (4 bytes) */
    264         } header;
     242        struct rpm_header header;
    265243        rpm_index *tmpindex;
    266244        int storepos;
    267245
    268246        xread(fd, &header, sizeof(header));
    269         if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0)
    270             return NULL; /* Invalid magic */
    271         if (header.version != 1)
    272             return NULL; /* This program only supports v1 headers */
     247        if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
     248            return NULL; /* Invalid magic, or not version 1 */
    273249        header.size = ntohl(header.size);
    274250        header.entries = ntohl(header.entries);
    275         storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16;
     251        storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16;
    276252
    277253        while (header.entries--) {
    278             tmpindex = tags[tagindex++] = xmalloc(sizeof(rpm_index));
    279             xread(fd, tmpindex, sizeof(rpm_index));
     254            tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex));
     255            xread(fd, tmpindex, sizeof(*tmpindex));
    280256            tmpindex->tag = ntohl(tmpindex->tag);
    281257            tmpindex->type = ntohl(tmpindex->type);
    282258            tmpindex->count = ntohl(tmpindex->count);
    283259            tmpindex->offset = storepos + ntohl(tmpindex->offset);
    284             if (pass==0)
     260            if (pass == 0)
    285261                tmpindex->tag -= 743;
    286262        }
    287         xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
     263        storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
    288264        /* Skip padding to 8 byte boundary after reading signature headers */
    289         if (pass==0)
    290             xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR);
    291     }
    292     tags = xrealloc(tags, tagindex * sizeof(struct rpmtag *)); /* realloc tags to save space */
     265        if (pass == 0)
     266            xlseek(fd, (-storepos) & 0x7, SEEK_CUR);
     267    }
     268    /* realloc tags to save space */
     269    tags = xrealloc(tags, tagindex * sizeof(tags[0]));
    293270    *num_tags = tagindex;
    294     return tags; /* All done, leave the file at the start of the gzipped cpio archive */
     271    /* All done, leave the file at the start of the gzipped cpio archive */
     272    return tags;
    295273}
    296274
     
    317295    if (!found || itemindex >= found[0]->count)
    318296        return NULL;
    319     if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) {
     297    if (found[0]->type == RPM_STRING_TYPE
     298     || found[0]->type == RPM_I18NSTRING_TYPE
     299     || found[0]->type == RPM_STRING_ARRAY_TYPE
     300    ) {
    320301        int n;
    321         char *tmpstr = (char *) (map + found[0]->offset);
    322         for (n=0; n < itemindex; n++)
     302        char *tmpstr = (char *) map + found[0]->offset;
     303        for (n = 0; n < itemindex; n++)
    323304            tmpstr = tmpstr + strlen(tmpstr) + 1;
    324305        return tmpstr;
     
    338319        return -1;
    339320
    340     tmpint = (int *) (map + found[0]->offset);
     321    tmpint = (int *) ((char *) map + found[0]->offset);
    341322
    342323    if (found[0]->type == RPM_INT32_TYPE) {
     
    381362static void fileaction_setowngrp(char *filename, int fileref)
    382363{
    383     int uid, gid;
    384     uid = xuname2uid(rpm_getstr(TAG_FILEUSERNAME, fileref));
    385     gid = xgroup2gid(rpm_getstr(TAG_FILEGROUPNAME, fileref));
     364    /* real rpm warns: "user foo does not exist - using <you>" */
     365    struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref));
     366    int uid = pw ? pw->pw_uid : getuid(); /* or euid? */
     367    struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref));
     368    int gid = gr ? gr->gr_gid : getgid();
    386369    chown(filename, uid, gid);
    387370}
  • branches/2.2.9/mindi-busybox/archival/rpm2cpio.c

    r1765 r2725  
    55 * Copyright (C) 2001 by Laurence Anderson
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
    99#include "libbb.h"
    10 #include "unarchive.h"
     10#include "archive.h"
     11#include "rpm.h"
    1112
    12 #define RPM_MAGIC "\355\253\356\333"
    13 #define RPM_HEADER_MAGIC "\216\255\350"
     13enum { rpm_fd = STDIN_FILENO };
    1414
    15 struct rpm_lead {
    16     unsigned char magic[4];
    17     uint8_t major, minor;
    18     uint16_t type;
    19     uint16_t archnum;
    20     char name[66];
    21     uint16_t osnum;
    22     uint16_t signature_type;
    23     char reserved[16];
    24 };
    25 
    26 struct rpm_header {
    27     char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
    28     uint8_t version; /* 1 byte version number */
    29     uint32_t reserved; /* 4 bytes reserved */
    30     uint32_t entries; /* Number of entries in header (4 bytes) */
    31     uint32_t size; /* Size of store (4 bytes) */
    32 };
    33 
    34 static void skip_header(int rpm_fd)
     15static unsigned skip_header(void)
    3516{
    3617    struct rpm_header header;
     18    unsigned len;
    3719
    38     xread(rpm_fd, &header, sizeof(struct rpm_header));
    39     if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) {
    40         bb_error_msg_and_die("invalid RPM header magic"); /* Invalid magic */
     20    xread(rpm_fd, &header, sizeof(header));
     21//  if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC_STR, 3) != 0) {
     22//      bb_error_msg_and_die("invalid RPM header magic");
     23//  }
     24//  if (header.version != 1) {
     25//      bb_error_msg_and_die("unsupported RPM header version");
     26//  }
     27    if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) {
     28        bb_error_msg_and_die("invalid RPM header magic or unsupported version");
     29        // ": %x != %x", header.magic_and_ver, htonl(RPM_HEADER_MAGICnVER));
    4130    }
    42     if (header.version != 1) {
    43         bb_error_msg_and_die("unsupported RPM header version"); /* This program only supports v1 headers */
    44     }
    45     header.entries = ntohl(header.entries);
    46     header.size = ntohl(header.size);
    47     lseek (rpm_fd, 16 * header.entries, SEEK_CUR); /* Seek past index entries */
    48     lseek (rpm_fd, header.size, SEEK_CUR); /* Seek past store */
     31
     32    /* Seek past index entries, and past store */
     33    len = 16 * ntohl(header.entries) + ntohl(header.size);
     34    seek_by_jump(rpm_fd, len);
     35
     36    return sizeof(header) + len;
    4937}
    5038
    5139/* No getopt required */
    52 int rpm2cpio_main(int argc, char **argv);
    53 int rpm2cpio_main(int argc, char **argv)
     40int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     41int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
    5442{
    5543    struct rpm_lead lead;
    56     int rpm_fd;
    57     unsigned char magic[2];
     44    unsigned pos;
    5845
    59     if (argc == 1) {
    60         rpm_fd = STDIN_FILENO;
    61     } else {
    62         rpm_fd = xopen(argv[1], O_RDONLY);
     46    if (argv[1]) {
     47        xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd);
     48    }
     49    xread(rpm_fd, &lead, sizeof(lead));
     50
     51    /* Just check the magic, the rest is irrelevant */
     52    if (lead.magic != htonl(RPM_LEAD_MAGIC)) {
     53        bb_error_msg_and_die("invalid RPM magic");
    6354    }
    6455
    65     xread(rpm_fd, &lead, sizeof(struct rpm_lead));
    66     if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) {
    67         bb_error_msg_and_die("invalid RPM magic"); /* Just check the magic, the rest is irrelevant */
    68     }
    69 
    70     /* Skip the signature header */
    71     skip_header(rpm_fd);
    72     lseek(rpm_fd, (8 - (lseek(rpm_fd, 0, SEEK_CUR) % 8)) % 8, SEEK_CUR);
     56    /* Skip the signature header, align to 8 bytes */
     57    pos = skip_header();
     58    seek_by_jump(rpm_fd, (-(int)pos) & 7);
    7359
    7460    /* Skip the main header */
    75     skip_header(rpm_fd);
     61    skip_header();
    7662
    77     xread(rpm_fd, &magic, 2);
    78     if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
    79         bb_error_msg_and_die("invalid gzip magic");
     63#if 0
     64    /* This works, but doesn't report uncompress errors (they happen in child) */
     65    setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/);
     66    if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
     67        bb_error_msg_and_die("error unpacking");
     68#else
     69    /* BLOAT */
     70    {
     71        union {
     72            uint8_t b[4];
     73            uint16_t b16[2];
     74            uint32_t b32[1];
     75        } magic;
     76        IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd);
     77
     78        xread(rpm_fd, magic.b16, sizeof(magic.b16[0]));
     79        if (magic.b16[0] == GZIP_MAGIC) {
     80            unpack = unpack_gz_stream;
     81        } else
     82        if (ENABLE_FEATURE_SEAMLESS_BZ2
     83         && magic.b16[0] == BZIP2_MAGIC
     84        ) {
     85            unpack = unpack_bz2_stream;
     86        } else
     87        if (ENABLE_FEATURE_SEAMLESS_XZ
     88         && magic.b16[0] == XZ_MAGIC1
     89        ) {
     90            xread(rpm_fd, magic.b32, sizeof(magic.b32[0]));
     91            if (magic.b32[0] != XZ_MAGIC2)
     92                goto no_magic;
     93            /* unpack_xz_stream wants fd at position 6, no need to seek */
     94            //xlseek(rpm_fd, -6, SEEK_CUR);
     95            unpack = unpack_xz_stream;
     96        } else {
     97 no_magic:
     98            bb_error_msg_and_die("no gzip"
     99                    IF_FEATURE_SEAMLESS_BZ2("/bzip2")
     100                    IF_FEATURE_SEAMLESS_XZ("/xz")
     101                    " magic");
     102        }
     103        if (unpack(rpm_fd, STDOUT_FILENO) < 0)
     104            bb_error_msg_and_die("error unpacking");
    80105    }
     106#endif
    81107
    82     check_header_gzip_or_die(rpm_fd);
    83     if (unpack_gz_stream(rpm_fd, STDOUT_FILENO) < 0) {
    84         bb_error_msg("error inflating");
     108    if (ENABLE_FEATURE_CLEAN_UP) {
     109        close(rpm_fd);
    85110    }
    86 
    87     close(rpm_fd);
    88111
    89112    return 0;
  • 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 */
  • branches/2.2.9/mindi-busybox/archival/unzip.c

    r1765 r2725  
    88 * All options and features should work in this version.
    99 *
    10  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1111 */
    1212
     
    1717
    1818/* TODO
    19  * Endian issues
    2019 * Zip64 + other methods
    21  * Improve handling of zip format, ie.
    22  * - deferred CRC, comp. & uncomp. lengths (zip header flags bit 3)
    23  * - unix file permissions, etc.
    24  * - central directory
    2520 */
    2621
    2722#include "libbb.h"
    28 #include "unarchive.h"
    29 
    30 #define ZIP_FILEHEADER_MAGIC        SWAP_LE32(0x04034b50)
    31 #define ZIP_CDS_MAGIC           SWAP_LE32(0x02014b50)
    32 #define ZIP_CDS_END_MAGIC       SWAP_LE32(0x06054b50)
    33 #define ZIP_DD_MAGIC            SWAP_LE32(0x08074b50)
     23#include "archive.h"
     24
     25enum {
     26#if BB_BIG_ENDIAN
     27    ZIP_FILEHEADER_MAGIC = 0x504b0304,
     28    ZIP_CDF_MAGIC        = 0x504b0102, /* central directory's file header */
     29    ZIP_CDE_MAGIC        = 0x504b0506, /* "end of central directory" record */
     30    ZIP_DD_MAGIC         = 0x504b0708,
     31#else
     32    ZIP_FILEHEADER_MAGIC = 0x04034b50,
     33    ZIP_CDF_MAGIC        = 0x02014b50,
     34    ZIP_CDE_MAGIC        = 0x06054b50,
     35    ZIP_DD_MAGIC         = 0x08074b50,
     36#endif
     37};
     38
     39#define ZIP_HEADER_LEN 26
    3440
    3541typedef union {
    36     unsigned char raw[26];
     42    uint8_t raw[ZIP_HEADER_LEN];
    3743    struct {
    38         unsigned short version; /* 0-1 */
    39         unsigned short flags;   /* 2-3 */
    40         unsigned short method;  /* 4-5 */
    41         unsigned short modtime; /* 6-7 */
    42         unsigned short moddate; /* 8-9 */
    43         unsigned int crc32 ATTRIBUTE_PACKED;    /* 10-13 */
    44         unsigned int cmpsize ATTRIBUTE_PACKED;  /* 14-17 */
    45         unsigned int ucmpsize ATTRIBUTE_PACKED; /* 18-21 */
    46         unsigned short filename_len;    /* 22-23 */
    47         unsigned short extra_len;       /* 24-25 */
    48     } formatted ATTRIBUTE_PACKED;
    49 } zip_header_t;
    50 
    51 static void unzip_skip(int fd, off_t skip)
     44        uint16_t version;               /* 0-1 */
     45        uint16_t zip_flags;             /* 2-3 */
     46        uint16_t method;                /* 4-5 */
     47        uint16_t modtime;               /* 6-7 */
     48        uint16_t moddate;               /* 8-9 */
     49        uint32_t crc32 PACKED;          /* 10-13 */
     50        uint32_t cmpsize PACKED;        /* 14-17 */
     51        uint32_t ucmpsize PACKED;       /* 18-21 */
     52        uint16_t filename_len;          /* 22-23 */
     53        uint16_t extra_len;             /* 24-25 */
     54    } formatted PACKED;
     55} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */
     56
     57/* Check the offset of the last element, not the length.  This leniency
     58 * allows for poor packing, whereby the overall struct may be too long,
     59 * even though the elements are all in the right place.
     60 */
     61struct BUG_zip_header_must_be_26_bytes {
     62    char BUG_zip_header_must_be_26_bytes[
     63        offsetof(zip_header_t, formatted.extra_len) + 2
     64            == ZIP_HEADER_LEN ? 1 : -1];
     65};
     66
     67#define FIX_ENDIANNESS_ZIP(zip_header) do { \
     68    (zip_header).formatted.version      = SWAP_LE16((zip_header).formatted.version     ); \
     69    (zip_header).formatted.method       = SWAP_LE16((zip_header).formatted.method      ); \
     70    (zip_header).formatted.modtime      = SWAP_LE16((zip_header).formatted.modtime     ); \
     71    (zip_header).formatted.moddate      = SWAP_LE16((zip_header).formatted.moddate     ); \
     72    (zip_header).formatted.crc32        = SWAP_LE32((zip_header).formatted.crc32       ); \
     73    (zip_header).formatted.cmpsize      = SWAP_LE32((zip_header).formatted.cmpsize     ); \
     74    (zip_header).formatted.ucmpsize     = SWAP_LE32((zip_header).formatted.ucmpsize    ); \
     75    (zip_header).formatted.filename_len = SWAP_LE16((zip_header).formatted.filename_len); \
     76    (zip_header).formatted.extra_len    = SWAP_LE16((zip_header).formatted.extra_len   ); \
     77} while (0)
     78
     79#define CDF_HEADER_LEN 42
     80
     81typedef union {
     82    uint8_t raw[CDF_HEADER_LEN];
     83    struct {
     84        /* uint32_t signature; 50 4b 01 02 */
     85        uint16_t version_made_by;       /* 0-1 */
     86        uint16_t version_needed;        /* 2-3 */
     87        uint16_t cdf_flags;             /* 4-5 */
     88        uint16_t method;                /* 6-7 */
     89        uint16_t mtime;                 /* 8-9 */
     90        uint16_t mdate;                 /* 10-11 */
     91        uint32_t crc32;                 /* 12-15 */
     92        uint32_t cmpsize;               /* 16-19 */
     93        uint32_t ucmpsize;              /* 20-23 */
     94        uint16_t file_name_length;      /* 24-25 */
     95        uint16_t extra_field_length;    /* 26-27 */
     96        uint16_t file_comment_length;   /* 28-29 */
     97        uint16_t disk_number_start;     /* 30-31 */
     98        uint16_t internal_file_attributes; /* 32-33 */
     99        uint32_t external_file_attributes PACKED; /* 34-37 */
     100        uint32_t relative_offset_of_local_header PACKED; /* 38-41 */
     101    } formatted PACKED;
     102} cdf_header_t;
     103
     104struct BUG_cdf_header_must_be_42_bytes {
     105    char BUG_cdf_header_must_be_42_bytes[
     106        offsetof(cdf_header_t, formatted.relative_offset_of_local_header) + 4
     107            == CDF_HEADER_LEN ? 1 : -1];
     108};
     109
     110#define FIX_ENDIANNESS_CDF(cdf_header) do { \
     111    (cdf_header).formatted.crc32        = SWAP_LE32((cdf_header).formatted.crc32       ); \
     112    (cdf_header).formatted.cmpsize      = SWAP_LE32((cdf_header).formatted.cmpsize     ); \
     113    (cdf_header).formatted.ucmpsize     = SWAP_LE32((cdf_header).formatted.ucmpsize    ); \
     114    (cdf_header).formatted.file_name_length = SWAP_LE16((cdf_header).formatted.file_name_length); \
     115    (cdf_header).formatted.extra_field_length = SWAP_LE16((cdf_header).formatted.extra_field_length); \
     116    (cdf_header).formatted.file_comment_length = SWAP_LE16((cdf_header).formatted.file_comment_length); \
     117    IF_DESKTOP( \
     118    (cdf_header).formatted.version_made_by = SWAP_LE16((cdf_header).formatted.version_made_by); \
     119    (cdf_header).formatted.external_file_attributes = SWAP_LE32((cdf_header).formatted.external_file_attributes); \
     120    ) \
     121} while (0)
     122
     123#define CDE_HEADER_LEN 16
     124
     125typedef union {
     126    uint8_t raw[CDE_HEADER_LEN];
     127    struct {
     128        /* uint32_t signature; 50 4b 05 06 */
     129        uint16_t this_disk_no;
     130        uint16_t disk_with_cdf_no;
     131        uint16_t cdf_entries_on_this_disk;
     132        uint16_t cdf_entries_total;
     133        uint32_t cdf_size;
     134        uint32_t cdf_offset;
     135        /* uint16_t file_comment_length; */
     136        /* .ZIP file comment (variable size) */
     137    } formatted PACKED;
     138} cde_header_t;
     139
     140struct BUG_cde_header_must_be_16_bytes {
     141    char BUG_cde_header_must_be_16_bytes[
     142        sizeof(cde_header_t) == CDE_HEADER_LEN ? 1 : -1];
     143};
     144
     145#define FIX_ENDIANNESS_CDE(cde_header) do { \
     146    (cde_header).formatted.cdf_offset = SWAP_LE32((cde_header).formatted.cdf_offset); \
     147} while (0)
     148
     149enum { zip_fd = 3 };
     150
     151
     152#if ENABLE_DESKTOP
     153
     154#define PEEK_FROM_END 16384
     155
     156/* NB: does not preserve file position! */
     157static uint32_t find_cdf_offset(void)
    52158{
    53     if (lseek(fd, skip, SEEK_CUR) == (off_t)-1) {
    54         if (errno != ESPIPE)
    55             bb_error_msg_and_die("seek failure");
    56         bb_copyfd_exact_size(fd, -1, skip);
    57     }
     159    cde_header_t cde_header;
     160    unsigned char *p;
     161    off_t end;
     162    unsigned char *buf = xzalloc(PEEK_FROM_END);
     163
     164    end = xlseek(zip_fd, 0, SEEK_END);
     165    end -= PEEK_FROM_END;
     166    if (end < 0)
     167        end = 0;
     168    xlseek(zip_fd, end, SEEK_SET);
     169    full_read(zip_fd, buf, PEEK_FROM_END);
     170
     171    p = buf;
     172    while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) {
     173        if (*p != 'P') {
     174            p++;
     175            continue;
     176        }
     177        if (*++p != 'K')
     178            continue;
     179        if (*++p != 5)
     180            continue;
     181        if (*++p != 6)
     182            continue;
     183        /* we found CDE! */
     184        memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN);
     185        FIX_ENDIANNESS_CDE(cde_header);
     186        free(buf);
     187        return cde_header.formatted.cdf_offset;
     188    }
     189    //free(buf);
     190    bb_error_msg_and_die("can't find file table");
     191};
     192
     193static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr)
     194{
     195    off_t org;
     196
     197    org = xlseek(zip_fd, 0, SEEK_CUR);
     198
     199    if (!cdf_offset)
     200        cdf_offset = find_cdf_offset();
     201
     202    xlseek(zip_fd, cdf_offset + 4, SEEK_SET);
     203    xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN);
     204    FIX_ENDIANNESS_CDF(*cdf_ptr);
     205    cdf_offset += 4 + CDF_HEADER_LEN
     206        + cdf_ptr->formatted.file_name_length
     207        + cdf_ptr->formatted.extra_field_length
     208        + cdf_ptr->formatted.file_comment_length;
     209
     210    xlseek(zip_fd, org, SEEK_SET);
     211    return cdf_offset;
     212};
     213#endif
     214
     215static void unzip_skip(off_t skip)
     216{
     217    if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1)
     218        bb_copyfd_exact_size(zip_fd, -1, skip);
    58219}
    59220
    60 static void unzip_create_leading_dirs(char *fn)
     221static void unzip_create_leading_dirs(const char *fn)
    61222{
    62223    /* Create all leading directories */
     
    68229}
    69230
    70 static int unzip_extract(zip_header_t *zip_header, int src_fd, int dst_fd)
     231static void unzip_extract(zip_header_t *zip_header, int dst_fd)
    71232{
    72233    if (zip_header->formatted.method == 0) {
     
    74235        off_t size = zip_header->formatted.ucmpsize;
    75236        if (size)
    76             bb_copyfd_exact_size(src_fd, dst_fd, size);
     237            bb_copyfd_exact_size(zip_fd, dst_fd, size);
    77238    } else {
    78239        /* Method 8 - inflate */
    79240        inflate_unzip_result res;
    80         /* err = */ inflate_unzip(&res, zip_header->formatted.cmpsize, src_fd, dst_fd);
    81 // we should check for -1 error return
     241        if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0)
     242            bb_error_msg_and_die("inflate error");
    82243        /* Validate decompression - crc */
    83244        if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) {
    84             bb_error_msg("invalid compressed data--%s error", "crc");
    85             return 1;
     245            bb_error_msg_and_die("crc error");
    86246        }
    87247        /* Validate decompression - size */
    88248        if (zip_header->formatted.ucmpsize != res.bytes_out) {
    89             bb_error_msg("invalid compressed data--%s error", "length");
    90             return 1;
    91         }
    92     }
    93     return 0;
     249            /* Don't die. Who knows, maybe len calculation
     250             * was botched somewhere. After all, crc matched! */
     251            bb_error_msg("bad length");
     252        }
     253    }
    94254}
    95255
    96 int unzip_main(int argc, char **argv);
     256int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    97257int unzip_main(int argc, char **argv)
    98258{
     259    enum { O_PROMPT, O_NEVER, O_ALWAYS };
     260
    99261    zip_header_t zip_header;
    100     enum {v_silent, v_normal, v_list} verbosity = v_normal;
    101     enum {o_prompt, o_never, o_always} overwrite = o_prompt;
    102     unsigned int total_size = 0;
    103     unsigned int total_entries = 0;
    104     int src_fd = -1, dst_fd = -1;
    105     char *src_fn = NULL, *dst_fn = NULL;
     262    smallint quiet = 0;
     263    IF_NOT_DESKTOP(const) smallint verbose = 0;
     264    smallint listing = 0;
     265    smallint overwrite = O_PROMPT;
     266#if ENABLE_DESKTOP
     267    uint32_t cdf_offset;
     268#endif
     269    unsigned long total_usize;
     270    unsigned long total_size;
     271    unsigned total_entries;
     272    int dst_fd = -1;
     273    char *src_fn = NULL;
     274    char *dst_fn = NULL;
    106275    llist_t *zaccept = NULL;
    107276    llist_t *zreject = NULL;
    108277    char *base_dir = NULL;
    109     int failed, i, opt, opt_range = 0, list_header_done = 0;
    110     char key_buf[512];
     278    int i, opt;
     279    int opt_range = 0;
     280    char key_buf[80];
    111281    struct stat stat_buf;
    112282
    113     while ((opt = getopt(argc, argv, "-d:lnopqx")) != -1) {
     283/* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP:
     284 *
     285 * # /usr/bin/unzip -qq -v decompress_unlzma.i.zip
     286 *   204372  Defl:N    35278  83%  09-06-09 14:23  0d056252  decompress_unlzma.i
     287 * # /usr/bin/unzip -q -v decompress_unlzma.i.zip
     288 *  Length   Method    Size  Ratio   Date   Time   CRC-32    Name
     289 * --------  ------  ------- -----   ----   ----   ------    ----
     290 *   204372  Defl:N    35278  83%  09-06-09 14:23  0d056252  decompress_unlzma.i
     291 * --------          -------  ---                            -------
     292 *   204372            35278  83%                            1 file
     293 * # /usr/bin/unzip -v decompress_unlzma.i.zip
     294 * Archive:  decompress_unlzma.i.zip
     295 *  Length   Method    Size  Ratio   Date   Time   CRC-32    Name
     296 * --------  ------  ------- -----   ----   ----   ------    ----
     297 *   204372  Defl:N    35278  83%  09-06-09 14:23  0d056252  decompress_unlzma.i
     298 * --------          -------  ---                            -------
     299 *   204372            35278  83%                            1 file
     300 * # unzip -v decompress_unlzma.i.zip
     301 * Archive:  decompress_unlzma.i.zip
     302 *   Length     Date   Time    Name
     303 *  --------    ----   ----    ----
     304 *    204372  09-06-09 14:23   decompress_unlzma.i
     305 *  --------                   -------
     306 *    204372                   1 files
     307 * # /usr/bin/unzip -l -qq decompress_unlzma.i.zip
     308 *    204372  09-06-09 14:23   decompress_unlzma.i
     309 * # /usr/bin/unzip -l -q decompress_unlzma.i.zip
     310 *   Length     Date   Time    Name
     311 *  --------    ----   ----    ----
     312 *    204372  09-06-09 14:23   decompress_unlzma.i
     313 *  --------                   -------
     314 *    204372                   1 file
     315 * # /usr/bin/unzip -l decompress_unlzma.i.zip
     316 * Archive:  decompress_unlzma.i.zip
     317 *   Length     Date   Time    Name
     318 *  --------    ----   ----    ----
     319 *    204372  09-06-09 14:23   decompress_unlzma.i
     320 *  --------                   -------
     321 *    204372                   1 file
     322 */
     323
     324    /* '-' makes getopt return 1 for non-options */
     325    while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) {
    114326        switch (opt_range) {
    115327        case 0: /* Options */
    116328            switch (opt) {
    117329            case 'l': /* List */
    118                 verbosity = v_list;
     330                listing = 1;
    119331                break;
    120332
    121333            case 'n': /* Never overwrite existing files */
    122                 overwrite = o_never;
     334                overwrite = O_NEVER;
    123335                break;
    124336
    125337            case 'o': /* Always overwrite existing files */
    126                 overwrite = o_always;
     338                overwrite = O_ALWAYS;
    127339                break;
    128340
     
    131343
    132344            case 'q': /* Be quiet */
    133                 verbosity = (verbosity == v_normal) ? v_silent : verbosity;
    134                 break;
    135 
    136             case 1 : /* The zip file */
    137                 src_fn = xmalloc(strlen(optarg)+4);
     345                quiet++;
     346                break;
     347
     348            case 'v': /* Verbose list */
     349                IF_DESKTOP(verbose++;)
     350                listing = 1;
     351                break;
     352
     353            case 1: /* The zip file */
     354                /* +5: space for ".zip" and NUL */
     355                src_fn = xmalloc(strlen(optarg) + 5);
    138356                strcpy(src_fn, optarg);
    139357                opt_range++;
     
    142360            default:
    143361                bb_show_usage();
    144 
    145362            }
    146363            break;
     
    149366            if (opt == 1) {
    150367                llist_add_to(&zaccept, optarg);
    151 
    152             } else if (opt == 'd') {
     368                break;
     369            }
     370            if (opt == 'd') {
    153371                base_dir = optarg;
    154372                opt_range += 2;
    155 
    156             } else if (opt == 'x') {
     373                break;
     374            }
     375            if (opt == 'x') {
    157376                opt_range++;
    158 
    159             } else {
    160                 bb_show_usage();
    161             }
    162             break;
     377                break;
     378            }
     379            bb_show_usage();
    163380
    164381        case 2 : /* Exclude files */
    165382            if (opt == 1) {
    166383                llist_add_to(&zreject, optarg);
    167 
    168             } else if (opt == 'd') { /* Extract to base directory */
     384                break;
     385            }
     386            if (opt == 'd') { /* Extract to base directory */
    169387                base_dir = optarg;
    170388                opt_range++;
    171 
    172             } else {
    173                 bb_show_usage();
    174             }
    175             break;
     389                break;
     390            }
     391            /* fall through */
    176392
    177393        default:
     
    186402    /* Open input file */
    187403    if (LONE_DASH(src_fn)) {
    188         src_fd = STDIN_FILENO;
     404        xdup2(STDIN_FILENO, zip_fd);
    189405        /* Cannot use prompt mode since zip data is arriving on STDIN */
    190         overwrite = (overwrite == o_prompt) ? o_never : overwrite;
     406        if (overwrite == O_PROMPT)
     407            overwrite = O_NEVER;
    191408    } else {
    192         static const char *const extn[] = {"", ".zip", ".ZIP"};
     409        static const char extn[][5] = {"", ".zip", ".ZIP"};
    193410        int orig_src_fn_len = strlen(src_fn);
     411        int src_fd = -1;
     412
    194413        for (i = 0; (i < 3) && (src_fd == -1); i++) {
    195414            strcpy(src_fn + orig_src_fn_len, extn[i]);
     
    198417        if (src_fd == -1) {
    199418            src_fn[orig_src_fn_len] = '\0';
    200             bb_error_msg_and_die("cannot open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
    201         }
     419            bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn);
     420        }
     421        xmove_fd(src_fd, zip_fd);
    202422    }
    203423
     
    206426        xchdir(base_dir);
    207427
    208     if (verbosity != v_silent)
    209         printf("Archive:  %s\n", src_fn);
    210 
    211     failed = 0;
    212 
     428    if (quiet <= 1) { /* not -qq */
     429        if (quiet == 0)
     430            printf("Archive:  %s\n", src_fn);
     431        if (listing) {
     432            puts(verbose ?
     433                " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"
     434                "--------  ------  ------- -----   ----   ----   ------    ----"
     435                :
     436                "  Length     Date   Time    Name\n"
     437                " --------    ----   ----    ----"
     438                );
     439        }
     440    }
     441
     442/* Example of an archive with one 0-byte long file named 'z'
     443 * created by Zip 2.31 on Unix:
     444 * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..|
     445 *       sig........ vneed flags compr mtime mdate crc32>
     446 * 0010  00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU|
     447 *      >..... csize...... usize...... fnlen exlen fn ex>
     448 * 0020  54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..|
     449 *      >tra_field......................................
     450 * 0030  00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........|
     451 *       ........... sig........ vmade vneed flags compr
     452 * 0040  42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............|
     453 *       mtime mdate crc32...... csize...... usize......
     454 * 0050  01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................|
     455 *       fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--)
     456 * 0060  00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..|
     457 *      >..... fn extra_field...........................
     458 * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...|
     459 * 0080  34 00 00 00 00 00                               |4.....|
     460 */
     461    total_usize = 0;
     462    total_size = 0;
     463    total_entries = 0;
     464#if ENABLE_DESKTOP
     465    cdf_offset = 0;
     466#endif
    213467    while (1) {
    214         unsigned int magic;
     468        uint32_t magic;
     469        mode_t dir_mode = 0777;
     470#if ENABLE_DESKTOP
     471        mode_t file_mode = 0666;
     472#endif
    215473
    216474        /* Check magic number */
    217         xread(src_fd, &magic, 4);
    218         if (magic == ZIP_CDS_MAGIC) {
     475        xread(zip_fd, &magic, 4);
     476        /* Central directory? It's at the end, so exit */
     477        if (magic == ZIP_CDF_MAGIC)
    219478            break;
    220         } else if (magic != ZIP_FILEHEADER_MAGIC) {
    221             bb_error_msg_and_die("invalid zip magic %08X", magic);
    222         }
     479#if ENABLE_DESKTOP
     480        /* Data descriptor? It was a streaming file, go on */
     481        if (magic == ZIP_DD_MAGIC) {
     482            /* skip over duplicate crc32, cmpsize and ucmpsize */
     483            unzip_skip(3 * 4);
     484            continue;
     485        }
     486#endif
     487        if (magic != ZIP_FILEHEADER_MAGIC)
     488            bb_error_msg_and_die("invalid zip magic %08X", (int)magic);
    223489
    224490        /* Read the file header */
    225         xread(src_fd, zip_header.raw, 26);
    226         zip_header.formatted.version = SWAP_LE32(zip_header.formatted.version);
    227         zip_header.formatted.flags = SWAP_LE32(zip_header.formatted.flags);
    228         zip_header.formatted.method = SWAP_LE32(zip_header.formatted.method);
    229         zip_header.formatted.modtime = SWAP_LE32(zip_header.formatted.modtime);
    230         zip_header.formatted.moddate = SWAP_LE32(zip_header.formatted.moddate);
    231         zip_header.formatted.crc32 = SWAP_LE32(zip_header.formatted.crc32);
    232         zip_header.formatted.cmpsize = SWAP_LE32(zip_header.formatted.cmpsize);
    233         zip_header.formatted.ucmpsize = SWAP_LE32(zip_header.formatted.ucmpsize);
    234         zip_header.formatted.filename_len = SWAP_LE32(zip_header.formatted.filename_len);
    235         zip_header.formatted.extra_len = SWAP_LE32(zip_header.formatted.extra_len);
     491        xread(zip_fd, zip_header.raw, ZIP_HEADER_LEN);
     492        FIX_ENDIANNESS_ZIP(zip_header);
    236493        if ((zip_header.formatted.method != 0) && (zip_header.formatted.method != 8)) {
    237             bb_error_msg_and_die("unsupported compression method %d", zip_header.formatted.method);
    238         }
     494            bb_error_msg_and_die("unsupported method %d", zip_header.formatted.method);
     495        }
     496#if !ENABLE_DESKTOP
     497        if (zip_header.formatted.zip_flags & SWAP_LE16(0x0009)) {
     498            bb_error_msg_and_die("zip flags 1 and 8 are not supported");
     499        }
     500#else
     501        if (zip_header.formatted.zip_flags & SWAP_LE16(0x0001)) {
     502            /* 0x0001 - encrypted */
     503            bb_error_msg_and_die("zip flag 1 (encryption) is not supported");
     504        }
     505
     506        {
     507            cdf_header_t cdf_header;
     508            cdf_offset = read_next_cdf(cdf_offset, &cdf_header);
     509            if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) {
     510                /* 0x0008 - streaming. [u]cmpsize can be reliably gotten
     511                 * only from Central Directory. See unzip_doc.txt */
     512                zip_header.formatted.crc32    = cdf_header.formatted.crc32;
     513                zip_header.formatted.cmpsize  = cdf_header.formatted.cmpsize;
     514                zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize;
     515            }
     516            if ((cdf_header.formatted.version_made_by >> 8) == 3) {
     517                /* this archive is created on Unix */
     518                dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16);
     519            }
     520        }
     521#endif
    239522
    240523        /* Read filename */
    241524        free(dst_fn);
    242525        dst_fn = xzalloc(zip_header.formatted.filename_len + 1);
    243         xread(src_fd, dst_fn, zip_header.formatted.filename_len);
     526        xread(zip_fd, dst_fn, zip_header.formatted.filename_len);
    244527
    245528        /* Skip extra header bytes */
    246         unzip_skip(src_fd, zip_header.formatted.extra_len);
    247 
    248         if ((verbosity == v_list) && !list_header_done){
    249             puts("  Length     Date   Time    Name\n"
    250                  " --------    ----   ----    ----");
    251             list_header_done = 1;
    252         }
     529        unzip_skip(zip_header.formatted.extra_len);
    253530
    254531        /* Filter zip entries */
    255         if (find_list_entry(zreject, dst_fn) ||
    256             (zaccept && !find_list_entry(zaccept, dst_fn))) { /* Skip entry */
     532        if (find_list_entry(zreject, dst_fn)
     533         || (zaccept && !find_list_entry(zaccept, dst_fn))
     534        ) { /* Skip entry */
    257535            i = 'n';
    258536
    259537        } else { /* Extract entry */
    260             total_size += zip_header.formatted.ucmpsize;
    261 
    262             if (verbosity == v_list) { /* List entry */
    263                 unsigned int dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
    264                 printf("%9u  %02u-%02u-%02u %02u:%02u   %s\n",
    265                        zip_header.formatted.ucmpsize,
    266                        (dostime & 0x01e00000) >> 21,
    267                        (dostime & 0x001f0000) >> 16,
    268                        (((dostime & 0xfe000000) >> 25) + 1980) % 100,
    269                        (dostime & 0x0000f800) >> 11,
    270                        (dostime & 0x000007e0) >> 5,
    271                        dst_fn);
    272                 total_entries++;
     538            if (listing) { /* List entry */
     539                unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
     540                if (!verbose) {
     541                    //      "  Length     Date   Time    Name\n"
     542                    //      " --------    ----   ----    ----"
     543                    printf(       "%9u  %02u-%02u-%02u %02u:%02u   %s\n",
     544                        (unsigned)zip_header.formatted.ucmpsize,
     545                        (dostime & 0x01e00000) >> 21,
     546                        (dostime & 0x001f0000) >> 16,
     547                        (((dostime & 0xfe000000) >> 25) + 1980) % 100,
     548                        (dostime & 0x0000f800) >> 11,
     549                        (dostime & 0x000007e0) >> 5,
     550                        dst_fn);
     551                    total_usize += zip_header.formatted.ucmpsize;
     552                } else {
     553                    unsigned long percents = zip_header.formatted.ucmpsize - zip_header.formatted.cmpsize;
     554                    percents = percents * 100;
     555                    if (zip_header.formatted.ucmpsize)
     556                        percents /= zip_header.formatted.ucmpsize;
     557                    //      " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"
     558                    //      "--------  ------  ------- -----   ----   ----   ------    ----"
     559                    printf(      "%8u  Defl:N"    "%9u%4u%%  %02u-%02u-%02u %02u:%02u  %08x  %s\n",
     560                        (unsigned)zip_header.formatted.ucmpsize,
     561                        (unsigned)zip_header.formatted.cmpsize,
     562                        (unsigned)percents,
     563                        (dostime & 0x01e00000) >> 21,
     564                        (dostime & 0x001f0000) >> 16,
     565                        (((dostime & 0xfe000000) >> 25) + 1980) % 100,
     566                        (dostime & 0x0000f800) >> 11,
     567                        (dostime & 0x000007e0) >> 5,
     568                        zip_header.formatted.crc32,
     569                        dst_fn);
     570                    total_usize += zip_header.formatted.ucmpsize;
     571                    total_size += zip_header.formatted.cmpsize;
     572                }
    273573                i = 'n';
    274574            } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */
     
    277577                if (stat(dst_fn, &stat_buf) == -1) {
    278578                    if (errno != ENOENT) {
    279                         bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
     579                        bb_perror_msg_and_die("can't stat '%s'", dst_fn);
    280580                    }
    281                     if (verbosity == v_normal) {
     581                    if (!quiet) {
    282582                        printf("   creating: %s\n", dst_fn);
    283583                    }
    284584                    unzip_create_leading_dirs(dst_fn);
    285                     if (bb_make_directory(dst_fn, 0777, 0)) {
     585                    if (bb_make_directory(dst_fn, dir_mode, 0)) {
    286586                        bb_error_msg_and_die("exiting");
    287587                    }
     
    294594
    295595            } else {  /* Extract file */
    296  _check_file:
     596 check_file:
    297597                if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */
    298598                    if (errno != ENOENT) {
    299                         bb_perror_msg_and_die("cannot stat '%s'",dst_fn);
     599                        bb_perror_msg_and_die("can't stat '%s'", dst_fn);
    300600                    }
    301601                    i = 'y';
    302602                } else { /* File already exists */
    303                     if (overwrite == o_never) {
     603                    if (overwrite == O_NEVER) {
    304604                        i = 'n';
    305605                    } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */
    306                         if (overwrite == o_always) {
     606                        if (overwrite == O_ALWAYS) {
    307607                            i = 'y';
    308608                        } else {
    309609                            printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
    310                             if (!fgets(key_buf, 512, stdin)) {
    311                                 bb_perror_msg_and_die("cannot read input");
     610                            if (!fgets(key_buf, sizeof(key_buf), stdin)) {
     611                                bb_perror_msg_and_die("can't read input");
    312612                            }
    313613                            i = key_buf[0];
    314614                        }
    315615                    } else { /* File is not regular file */
    316                         bb_error_msg_and_die("'%s' exists but is not regular file",dst_fn);
     616                        bb_error_msg_and_die("'%s' exists but is not regular file", dst_fn);
    317617                    }
    318618                }
     
    322622        switch (i) {
    323623        case 'A':
    324             overwrite = o_always;
     624            overwrite = O_ALWAYS;
    325625        case 'y': /* Open file and fall into unzip */
    326626            unzip_create_leading_dirs(dst_fn);
     627#if ENABLE_DESKTOP
     628            dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
     629#else
    327630            dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
     631#endif
    328632        case -1: /* Unzip */
    329             if (verbosity == v_normal) {
     633            if (!quiet) {
    330634                printf("  inflating: %s\n", dst_fn);
    331635            }
    332             if (unzip_extract(&zip_header, src_fd, dst_fd)) {
    333                 failed = 1;
    334             }
     636            unzip_extract(&zip_header, dst_fd);
    335637            if (dst_fd != STDOUT_FILENO) {
    336638                /* closing STDOUT is potentially bad for future business */
     
    340642
    341643        case 'N':
    342             overwrite = o_never;
     644            overwrite = O_NEVER;
    343645        case 'n':
    344646            /* Skip entry data */
    345             unzip_skip(src_fd, zip_header.formatted.cmpsize);
     647            unzip_skip(zip_header.formatted.cmpsize);
    346648            break;
    347649
     
    349651            /* Prompt for new name */
    350652            printf("new name: ");
    351             if (!fgets(key_buf, 512, stdin)) {
    352                 bb_perror_msg_and_die("cannot read input");
     653            if (!fgets(key_buf, sizeof(key_buf), stdin)) {
     654                bb_perror_msg_and_die("can't read input");
    353655            }
    354656            free(dst_fn);
    355657            dst_fn = xstrdup(key_buf);
    356658            chomp(dst_fn);
    357             goto _check_file;
     659            goto check_file;
    358660
    359661        default:
    360             printf("error: invalid response [%c]\n",(char)i);
    361             goto _check_file;
    362         }
    363 
    364         /* Data descriptor section */
    365         if (zip_header.formatted.flags & 4) {
    366             /* skip over duplicate crc, compressed size and uncompressed size */
    367             unzip_skip(src_fd, 12);
    368         }
    369     }
    370 
    371     if (verbosity == v_list) {
    372         printf(" --------                   -------\n"
    373                "%9d                   %d files\n", total_size, total_entries);
    374     }
    375 
    376     return failed;
     662            printf("error: invalid response [%c]\n", (char)i);
     663            goto check_file;
     664        }
     665
     666        total_entries++;
     667    }
     668
     669    if (listing && quiet <= 1) {
     670        if (!verbose) {
     671            //      "  Length     Date   Time    Name\n"
     672            //      " --------    ----   ----    ----"
     673            printf( " --------                   -------\n"
     674                "%9lu"   "                   %u files\n",
     675                total_usize, total_entries);
     676        } else {
     677            unsigned long percents = total_usize - total_size;
     678            percents = percents * 100;
     679            if (total_usize)
     680                percents /= total_usize;
     681            //      " Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n"
     682            //      "--------  ------  ------- -----   ----   ----   ------    ----"
     683            printf( "--------          -------  ---                            -------\n"
     684                "%8lu"              "%17lu%4u%%                            %u files\n",
     685                total_usize, total_size, (unsigned)percents,
     686                total_entries);
     687        }
     688    }
     689
     690    return 0;
    377691}
Note: See TracChangeset for help on using the changeset viewer.