Patch from Aurelien Jacobs to add unlzma. (A new decompression type,

see www.7-zip.org)
This commit is contained in:
Rob Landley 2006-01-20 18:28:50 +00:00
parent 7a43bd07e6
commit c1d69906a0
12 changed files with 691 additions and 5 deletions

View File

@ -157,6 +157,14 @@ config CONFIG_FEATURE_TAR_BZIP2
If you enable this option you'll be able to extract
archives compressed with bzip2.
config CONFIG_FEATURE_TAR_LZMA
bool " Enable -a option to handle .tar.lzma files"
default n
depends on CONFIG_TAR
help
If you enable this option you'll be able to extract
archives compressed with lzma.
config CONFIG_FEATURE_TAR_FROM
bool " Enable -X (exclude from) and -T (include from) options)"
default n
@ -212,6 +220,29 @@ config CONFIG_UNCOMPRESS
uncompress is used to decompress archives created by compress.
Not much used anymore, replaced by gzip/gunzip.
config CONFIG_UNLZMA
bool "unlzma"
default n
help
unlzma is a compression utility using the Lempel-Ziv-Markov chain
compression algorithm, and range coding. Compression
is generally considerably better than that achieved by the bzip2
compressors.
The BusyBox unlzma applet is limited to de-compression only.
On an x86 system, this applet adds about 4K.
Unless you have a specific application which requires unlzma, you
should probably say N here.
config CONFIG_FEATURE_LZMA_FAST
bool " Optimze unlzma for speed"
default n
depends on CONFIG_UNLZMA
help
This option reduce decompression time by about 33% at the cost of
a 2K bigger binary.
config CONFIG_UNZIP
bool "unzip"
default n
@ -255,4 +286,15 @@ config CONFIG_FEATURE_DEB_TAR_BZ2
You only want this if you are creating your own custom debian packages that
use an internal control.tar.bz2 or data.tar.bz2.
config CONFIG_FEATURE_DEB_TAR_LZMA
bool " lzma debian packages"
default n
depends on CONFIG_DPKG || CONFIG_DPKG_DEB
help
This allows dpkg and dpkg-deb to extract deb's that are compressed
internally with lzma instead of gzip.
You only want this if you are creating your own custom debian
packages that use an internal control.tar.lzma or data.tar.lzma.
endmenu

View File

@ -14,6 +14,7 @@ ARCHIVAL-y:=
ARCHIVAL-$(CONFIG_APT_GET) +=
ARCHIVAL-$(CONFIG_AR) += ar.o
ARCHIVAL-$(CONFIG_BUNZIP2) += bunzip2.o
ARCHIVAL-$(CONFIG_UNLZMA) += unlzma.o
ARCHIVAL-$(CONFIG_CPIO) += cpio.o
ARCHIVAL-$(CONFIG_DPKG) += dpkg.o
ARCHIVAL-$(CONFIG_DPKG_DEB) += dpkg_deb.o

View File

@ -51,17 +51,20 @@ DPKG_FILES:= \
LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
LIBUNARCHIVE-$(CONFIG_BUNZIP2) += decompress_bunzip2.o
LIBUNARCHIVE-$(CONFIG_UNLZMA) += decompress_unlzma.o
LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o
LIBUNARCHIVE-$(CONFIG_DPKG) += $(DPKG_FILES)
LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o
LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o
LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o
LIBUNARCHIVE-$(CONFIG_GUNZIP) += $(GUNZIP_FILES)
LIBUNARCHIVE-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o
LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o
LIBUNARCHIVE-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o
LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o
LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o
LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o
LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_GZIP) += $(GUNZIP_FILES) get_header_tar_gz.o
LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o
LIBUNARCHIVE-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o

View File

@ -0,0 +1,347 @@
/*
* Small lzma deflate implementation.
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
* Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
* Copyright (C) 1999-2005 Igor Pavlov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <byteswap.h>
#include "libbb.h"
#include "rangecoder.h"
typedef struct {
uint8_t pos;
uint32_t dict_size;
uint64_t dst_size;
} __attribute__ ((packed)) lzma_header_t;
#define LZMA_BASE_SIZE 1846
#define LZMA_LIT_SIZE 768
#define LZMA_NUM_POS_BITS_MAX 4
#define LZMA_LEN_NUM_LOW_BITS 3
#define LZMA_LEN_NUM_MID_BITS 3
#define LZMA_LEN_NUM_HIGH_BITS 8
#define LZMA_LEN_CHOICE 0
#define LZMA_LEN_CHOICE_2 (LZMA_LEN_CHOICE + 1)
#define LZMA_LEN_LOW (LZMA_LEN_CHOICE_2 + 1)
#define LZMA_LEN_MID (LZMA_LEN_LOW \
+ (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS)))
#define LZMA_LEN_HIGH (LZMA_LEN_MID \
+(1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS)))
#define LZMA_NUM_LEN_PROBS (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS))
#define LZMA_NUM_STATES 12
#define LZMA_NUM_LIT_STATES 7
#define LZMA_START_POS_MODEL_INDEX 4
#define LZMA_END_POS_MODEL_INDEX 14
#define LZMA_NUM_FULL_DISTANCES (1 << (LZMA_END_POS_MODEL_INDEX >> 1))
#define LZMA_NUM_POS_SLOT_BITS 6
#define LZMA_NUM_LEN_TO_POS_STATES 4
#define LZMA_NUM_ALIGN_BITS 4
#define LZMA_MATCH_MIN_LEN 2
#define LZMA_IS_MATCH 0
#define LZMA_IS_REP (LZMA_IS_MATCH + (LZMA_NUM_STATES <<LZMA_NUM_POS_BITS_MAX))
#define LZMA_IS_REP_G0 (LZMA_IS_REP + LZMA_NUM_STATES)
#define LZMA_IS_REP_G1 (LZMA_IS_REP_G0 + LZMA_NUM_STATES)
#define LZMA_IS_REP_G2 (LZMA_IS_REP_G1 + LZMA_NUM_STATES)
#define LZMA_IS_REP_0_LONG (LZMA_IS_REP_G2 + LZMA_NUM_STATES)
#define LZMA_POS_SLOT (LZMA_IS_REP_0_LONG \
+ (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX))
#define LZMA_SPEC_POS (LZMA_POS_SLOT \
+(LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS))
#define LZMA_ALIGN (LZMA_SPEC_POS \
+ LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX)
#define LZMA_LEN_CODER (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS))
#define LZMA_REP_LEN_CODER (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS)
#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS)
int unlzma(int src_fd, int dst_fd)
{
lzma_header_t header;
int lc, pb, lp;
uint32_t pos_state_mask;
uint32_t literal_pos_mask;
uint32_t pos;
uint16_t *p;
uint16_t *prob;
uint16_t *prob_lit;
int num_bits;
int num_probs;
rc_t rc;
int i, mi;
uint8_t *buffer;
uint8_t previous_byte = 0;
size_t buffer_pos = 0, global_pos = 0;
int len = 0;
int state = 0;
uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
if (read(src_fd, &header, sizeof(header)) != sizeof(header))
bb_error_msg_and_die("can't read header");
if (header.pos >= (9 * 5 * 5))
bb_error_msg_and_die("bad header");
mi = header.pos / 9;
lc = header.pos % 9;
pb = mi / 5;
lp = mi % 5;
pos_state_mask = (1 << pb) - 1;
literal_pos_mask = (1 << lp) - 1;
#if __BYTE_ORDER == __BIG_ENDIAN
header.dict_size = bswap_32(header.dict_size);
header.dst_size = bswap_64(header.dst_size);
#endif /* __BYTE_ORDER */
if (header.dict_size == 0)
header.dict_size = 1;
buffer = xmalloc(MIN(header.dst_size, header.dict_size));
num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
p = xmalloc(num_probs * sizeof(*p));
num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
for (i = 0; i < num_probs; i++)
p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
rc_init(&rc, src_fd, 0x10000);
while (global_pos + buffer_pos < header.dst_size) {
int pos_state = (buffer_pos + global_pos) & pos_state_mask;
prob =
p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
if (rc_is_bit_0(&rc, prob)) {
mi = 1;
rc_update_bit_0(&rc, prob);
prob = (p + LZMA_LITERAL + (LZMA_LIT_SIZE
* ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
+ (previous_byte >> (8 - lc)))));
if (state >= LZMA_NUM_LIT_STATES) {
int match_byte;
pos = buffer_pos - rep0;
while (pos >= header.dict_size)
pos += header.dict_size;
match_byte = buffer[pos];
do {
int bit;
match_byte <<= 1;
bit = match_byte & 0x100;
prob_lit = prob + 0x100 + bit + mi;
if (rc_get_bit(&rc, prob_lit, &mi)) {
if (!bit)
break;
} else {
if (bit)
break;
}
} while (mi < 0x100);
}
while (mi < 0x100) {
prob_lit = prob + mi;
rc_get_bit(&rc, prob_lit, &mi);
}
previous_byte = (uint8_t) mi;
buffer[buffer_pos++] = previous_byte;
if (buffer_pos == header.dict_size) {
buffer_pos = 0;
global_pos += header.dict_size;
write(dst_fd, buffer, header.dict_size);
}
if (state < 4)
state = 0;
else if (state < 10)
state -= 3;
else
state -= 6;
} else {
int offset;
uint16_t *prob_len;
rc_update_bit_1(&rc, prob);
prob = p + LZMA_IS_REP + state;
if (rc_is_bit_0(&rc, prob)) {
rc_update_bit_0(&rc, prob);
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
prob = p + LZMA_LEN_CODER;
} else {
rc_update_bit_1(&rc, prob);
prob = p + LZMA_IS_REP_G0 + state;
if (rc_is_bit_0(&rc, prob)) {
rc_update_bit_0(&rc, prob);
prob = (p + LZMA_IS_REP_0_LONG
+ (state << LZMA_NUM_POS_BITS_MAX) + pos_state);
if (rc_is_bit_0(&rc, prob)) {
rc_update_bit_0(&rc, prob);
state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
pos = buffer_pos - rep0;
while (pos >= header.dict_size)
pos += header.dict_size;
previous_byte = buffer[pos];
buffer[buffer_pos++] = previous_byte;
if (buffer_pos == header.dict_size) {
buffer_pos = 0;
global_pos += header.dict_size;
write(dst_fd, buffer, header.dict_size);
}
continue;
} else {
rc_update_bit_1(&rc, prob);
}
} else {
uint32_t distance;
rc_update_bit_1(&rc, prob);
prob = p + LZMA_IS_REP_G1 + state;
if (rc_is_bit_0(&rc, prob)) {
rc_update_bit_0(&rc, prob);
distance = rep1;
} else {
rc_update_bit_1(&rc, prob);
prob = p + LZMA_IS_REP_G2 + state;
if (rc_is_bit_0(&rc, prob)) {
rc_update_bit_0(&rc, prob);
distance = rep2;
} else {
rc_update_bit_1(&rc, prob);
distance = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = distance;
}
state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
prob = p + LZMA_REP_LEN_CODER;
}
prob_len = prob + LZMA_LEN_CHOICE;
if (rc_is_bit_0(&rc, prob_len)) {
rc_update_bit_0(&rc, prob_len);
prob_len = (prob + LZMA_LEN_LOW
+ (pos_state << LZMA_LEN_NUM_LOW_BITS));
offset = 0;
num_bits = LZMA_LEN_NUM_LOW_BITS;
} else {
rc_update_bit_1(&rc, prob_len);
prob_len = prob + LZMA_LEN_CHOICE_2;
if (rc_is_bit_0(&rc, prob_len)) {
rc_update_bit_0(&rc, prob_len);
prob_len = (prob + LZMA_LEN_MID
+ (pos_state << LZMA_LEN_NUM_MID_BITS));
offset = 1 << LZMA_LEN_NUM_LOW_BITS;
num_bits = LZMA_LEN_NUM_MID_BITS;
} else {
rc_update_bit_1(&rc, prob_len);
prob_len = prob + LZMA_LEN_HIGH;
offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
+ (1 << LZMA_LEN_NUM_MID_BITS));
num_bits = LZMA_LEN_NUM_HIGH_BITS;
}
}
rc_bit_tree_decode(&rc, prob_len, num_bits, &len);
len += offset;
if (state < 4) {
int pos_slot;
state += LZMA_NUM_LIT_STATES;
prob =
p + LZMA_POS_SLOT +
((len <
LZMA_NUM_LEN_TO_POS_STATES ? len :
LZMA_NUM_LEN_TO_POS_STATES - 1)
<< LZMA_NUM_POS_SLOT_BITS);
rc_bit_tree_decode(&rc, prob, LZMA_NUM_POS_SLOT_BITS,
&pos_slot);
if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
num_bits = (pos_slot >> 1) - 1;
rep0 = 2 | (pos_slot & 1);
if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
rep0 <<= num_bits;
prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
} else {
num_bits -= LZMA_NUM_ALIGN_BITS;
while (num_bits--)
rep0 = (rep0 << 1) | rc_direct_bit(&rc);
prob = p + LZMA_ALIGN;
rep0 <<= LZMA_NUM_ALIGN_BITS;
num_bits = LZMA_NUM_ALIGN_BITS;
}
i = 1;
mi = 1;
while (num_bits--) {
if (rc_get_bit(&rc, prob + mi, &mi))
rep0 |= i;
i <<= 1;
}
} else
rep0 = pos_slot;
if (++rep0 == 0)
break;
}
len += LZMA_MATCH_MIN_LEN;
do {
pos = buffer_pos - rep0;
while (pos >= header.dict_size)
pos += header.dict_size;
previous_byte = buffer[pos];
buffer[buffer_pos++] = previous_byte;
if (buffer_pos == header.dict_size) {
buffer_pos = 0;
global_pos += header.dict_size;
write(dst_fd, buffer, header.dict_size);
}
len--;
} while (len != 0 && buffer_pos < header.dst_size);
}
}
write(dst_fd, buffer, buffer_pos);
rc_free(&rc);
return 0;
}
/* vi:set ts=4: */

View File

@ -50,6 +50,10 @@ extern char filter_accept_list_reassign(archive_handle_t *archive_handle)
return(EXIT_SUCCESS);
}
#endif
if (ENABLE_FEATURE_DEB_TAR_LZMA && !strcmp(name_ptr, ".lzma")) {
archive_handle->action_data_subarchive = get_header_tar_lzma;
return(EXIT_SUCCESS);
}
}
return(EXIT_FAILURE);
}

View File

@ -0,0 +1,23 @@
/*
* Small lzma deflate implementation.
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
* Licensed under GPL v2, see file LICENSE in this tarball for details.
*/
#include "unarchive.h"
char get_header_tar_lzma(archive_handle_t * archive_handle)
{
/* Can't lseek over pipes */
archive_handle->seek = seek_by_char;
archive_handle->src_fd = open_transformer(archive_handle->src_fd, unlzma);
archive_handle->offset = 0;
while (get_header_tar(archive_handle) == EXIT_SUCCESS);
/* Can only do one file at a time */
return EXIT_FAILURE;
}
/* vi:set ts=4: */

View File

@ -0,0 +1,158 @@
/*
* Small range coder implementation for lzma.
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
* Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
* Copyright (c) 1999-2005 Igor Pavlov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include "libbb.h"
#ifndef always_inline
# if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >0)
# define always_inline __attribute__((always_inline)) inline
# else
# define always_inline inline
# endif
#endif
#ifdef CONFIG_FEATURE_LZMA_FAST
# define speed_inline always_inline
#else
# define speed_inline
#endif
typedef struct {
int fd;
uint8_t *ptr;
uint8_t *buffer;
uint8_t *buffer_end;
int buffer_size;
uint32_t code;
uint32_t range;
uint32_t bound;
} rc_t;
#define RC_TOP_BITS 24
#define RC_MOVE_BITS 5
#define RC_MODEL_TOTAL_BITS 11
static speed_inline void rc_read(rc_t * rc)
{
rc->buffer_size = read(rc->fd, rc->buffer, rc->buffer_size);
if (rc->buffer_size <= 0)
bb_error_msg_and_die("unexpected EOF");
rc->ptr = rc->buffer;
rc->buffer_end = rc->buffer + rc->buffer_size;
}
static always_inline void rc_init(rc_t * rc, int fd, int buffer_size)
{
int i;
rc->fd = fd;
rc->buffer = malloc(buffer_size);
rc->buffer_size = buffer_size;
rc->buffer_end = rc->buffer + rc->buffer_size;
rc->ptr = rc->buffer_end;
rc->code = 0;
rc->range = 0xFFFFFFFF;
for (i = 0; i < 5; i++) {
if (rc->ptr >= rc->buffer_end)
rc_read(rc);
rc->code = (rc->code << 8) | *rc->ptr++;
}
}
static always_inline void rc_free(rc_t * rc)
{
if (ENABLE_FEATURE_CLEAN_UP)
free(rc->buffer);
}
static always_inline void rc_normalize(rc_t * rc)
{
if (rc->range < (1 << RC_TOP_BITS)) {
if (rc->ptr >= rc->buffer_end)
rc_read(rc);
rc->range <<= 8;
rc->code = (rc->code << 8) | *rc->ptr++;
}
}
static speed_inline int rc_is_bit_0(rc_t * rc, uint16_t * p)
{
rc_normalize(rc);
rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
return rc->code < rc->bound;
}
static speed_inline void rc_update_bit_0(rc_t * rc, uint16_t * p)
{
rc->range = rc->bound;
*p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
}
static speed_inline void rc_update_bit_1(rc_t * rc, uint16_t * p)
{
rc->range -= rc->bound;
rc->code -= rc->bound;
*p -= *p >> RC_MOVE_BITS;
}
static speed_inline int rc_get_bit(rc_t * rc, uint16_t * p, int *symbol)
{
if (rc_is_bit_0(rc, p)) {
rc_update_bit_0(rc, p);
*symbol *= 2;
return 0;
} else {
rc_update_bit_1(rc, p);
*symbol = *symbol * 2 + 1;
return 1;
}
}
static always_inline int rc_direct_bit(rc_t * rc)
{
rc_normalize(rc);
rc->range >>= 1;
if (rc->code >= rc->range) {
rc->code -= rc->range;
return 1;
}
return 0;
}
static speed_inline void
rc_bit_tree_decode(rc_t * rc, uint16_t * p, int num_levels, int *symbol)
{
int i = num_levels;
*symbol = 1;
while (i--)
rc_get_bit(rc, p + *symbol, symbol);
*symbol -= 1 << num_levels;
}
/* vi:set ts=4: */

View File

@ -615,14 +615,23 @@ static char get_header_tar_Z(archive_handle_t *archive_handle)
# define TAR_OPT_AFTER_BZIP2 TAR_OPT_AFTER_CREATE
#endif
#define TAR_OPT_INCLUDE_FROM (1 << (TAR_OPT_AFTER_BZIP2))
#define TAR_OPT_EXCLUDE_FROM (1 << (TAR_OPT_AFTER_BZIP2 + 1))
#define TAR_OPT_LZMA (1 << (TAR_OPT_AFTER_BZIP2))
#ifdef CONFIG_FEATURE_TAR_LZMA
# define TAR_OPT_STR_LZMA "a"
# define TAR_OPT_AFTER_LZMA TAR_OPT_AFTER_BZIP2 + 1
#else
# define TAR_OPT_STR_LZMA ""
# define TAR_OPT_AFTER_LZMA TAR_OPT_AFTER_BZIP2
#endif
#define TAR_OPT_INCLUDE_FROM (1 << (TAR_OPT_AFTER_LZMA))
#define TAR_OPT_EXCLUDE_FROM (1 << (TAR_OPT_AFTER_LZMA + 1))
#ifdef CONFIG_FEATURE_TAR_FROM
# define TAR_OPT_STR_FROM "T:X:"
# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_BZIP2 + 2
# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_LZMA + 2
#else
# define TAR_OPT_STR_FROM ""
# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_BZIP2
# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_LZMA
#endif
#define TAR_OPT_GZIP (1 << (TAR_OPT_AFTER_FROM))
@ -651,6 +660,7 @@ static char get_header_tar_Z(archive_handle_t *archive_handle)
static const char tar_options[]="txC:f:Opvk" \
TAR_OPT_STR_CREATE \
TAR_OPT_STR_BZIP2 \
TAR_OPT_STR_LZMA \
TAR_OPT_STR_FROM \
TAR_OPT_STR_GZIP \
TAR_OPT_STR_COMPRESS \
@ -675,6 +685,9 @@ static const struct option tar_long_options[] = {
# ifdef CONFIG_FEATURE_TAR_BZIP2
{ "bzip2", 0, NULL, 'j' },
# endif
# ifdef CONFIG_FEATURE_TAR_LZMA
{ "lzma", 0, NULL, 'a' },
# endif
# ifdef CONFIG_FEATURE_TAR_FROM
{ "files-from", 1, NULL, 'T' },
{ "exclude-from", 1, NULL, 'X' },
@ -757,6 +770,9 @@ int tar_main(int argc, char **argv)
if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2))
get_header_ptr = get_header_tar_bz2;
if (ENABLE_FEATURE_TAR_LZMA && (opt & TAR_OPT_LZMA))
get_header_ptr = get_header_tar_lzma;
if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS))
get_header_ptr = get_header_tar_Z;

65
archival/unlzma.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Small lzma deflate implementation.
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
* Based on bunzip.c from busybox
*
* Licensed under GPL v2, see file LICENSE in this tarball for details.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "busybox.h"
#include "unarchive.h"
#define UNLZMA_OPT_STDOUT 1
int unlzma_main(int argc, char **argv)
{
char *filename;
unsigned long opt;
int status, src_fd, dst_fd;
opt = bb_getopt_ulflags(argc, argv, "c");
/* Set input filename and number */
filename = argv[optind];
if ((filename) && (filename[0] != '-') && (filename[1] != '\0')) {
/* Open input file */
src_fd = bb_xopen(filename, O_RDONLY);
} else {
src_fd = STDIN_FILENO;
filename = 0;
}
/* if called as lzmacat force the stdout flag */
if ((opt & UNLZMA_OPT_STDOUT) || bb_applet_name[4] == 'c')
filename = 0;
if (filename) {
char *extension = filename + strlen(filename) - 5;
if (strcmp(extension, ".lzma") != 0) {
bb_error_msg_and_die("Invalid extension");
}
*extension = 0;
dst_fd = bb_xopen(filename, O_WRONLY | O_CREAT);
} else
dst_fd = STDOUT_FILENO;
status = unlzma(src_fd, dst_fd);
if (filename) {
if (!status)
filename[strlen(filename)] = '.';
if (unlink(filename) < 0) {
bb_error_msg_and_die("Couldn't remove %s", filename);
}
}
return status;
}
/* vi:set ts=4: */

View File

@ -408,6 +408,9 @@
#ifdef CONFIG_LSMOD
APPLET(lsmod, lsmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_UNLZMA
APPLET(lzmacat, unlzma_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_MAKEDEVS
APPLET(makedevs, makedevs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
#endif
@ -712,6 +715,9 @@
#ifdef CONFIG_UNIX2DOS
APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_UNLZMA
APPLET(unlzma, unlzma_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif
#ifdef CONFIG_UNZIP
APPLET(unzip, unzip_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
#endif

View File

@ -87,6 +87,7 @@ extern char get_header_ar(archive_handle_t *archive_handle);
extern char get_header_cpio(archive_handle_t *archive_handle);
extern char get_header_tar(archive_handle_t *archive_handle);
extern char get_header_tar_bz2(archive_handle_t *archive_handle);
extern char get_header_tar_lzma(archive_handle_t *archive_handle);
extern char get_header_tar_gz(archive_handle_t *archive_handle);
extern void seek_by_jump(const archive_handle_t *archive_handle, const unsigned int amount);
@ -103,6 +104,7 @@ extern void inflate_init(unsigned int bufsize);
extern void inflate_cleanup(void);
extern int inflate_unzip(int in, int out);
extern int inflate_gunzip(int in, int out);
extern int unlzma(int src_fd, int dst_fd);
extern int open_transformer(int src_fd, int (*transformer)(int src_fd, int dst_fd));

View File

@ -102,6 +102,19 @@
#define bzcat_full_usage \
"Uncompress to stdout."
#define unlzma_trivial_usage \
"[OPTION]... [FILE]"
#define unlzma_full_usage \
"Uncompress FILE (or standard input if FILE is '-' or omitted).\n\n" \
"Options:\n" \
"\t-c\tWrite output to standard output\n" \
"\t-f\tForce"
#define lzmacat_trivial_usage \
"FILE"
#define lzmacat_full_usage \
"Uncompress to stdout."
#define cal_trivial_usage \
"[-jy] [[month] year]"
#define cal_full_usage \
@ -2964,6 +2977,11 @@
#else
# define USAGE_TAR_BZIP2(a)
#endif
#ifdef CONFIG_FEATURE_TAR_LZMA
# define USAGE_TAR_LZMA(a) a
#else
# define USAGE_TAR_LZMA(a)
#endif
#ifdef CONFIG_FEATURE_TAR_COMPRESS
# define USAGE_TAR_COMPRESS(a) a
#else
@ -2971,7 +2989,7 @@
#endif
#define tar_trivial_usage \
"-[" USAGE_TAR_CREATE("c") USAGE_TAR_GZIP("z") USAGE_TAR_BZIP2("j") USAGE_TAR_COMPRESS("Z") "xtvO] " \
"-[" USAGE_TAR_CREATE("c") USAGE_TAR_GZIP("z") USAGE_TAR_BZIP2("j") USAGE_TAR_LZMA("a") USAGE_TAR_COMPRESS("Z") "xtvO] " \
USAGE_TAR_EXCLUDE("[-X FILE]") \
"[-f TARFILE] [-C DIR] [FILE(s)] ..."
#define tar_full_usage \
@ -2983,6 +3001,7 @@
"\nArchive format selection:\n" \
USAGE_TAR_GZIP("\tz\t\tFilter the archive through gzip\n") \
USAGE_TAR_BZIP2("\tj\t\tFilter the archive through bzip2\n") \
USAGE_TAR_LZMA("\ta\t\tFilter the archive through lzma\n") \
USAGE_TAR_COMPRESS("\tZ\t\tFilter the archive through compress\n") \
"\nFile selection:\n" \
"\tf\t\tname of TARFILE or \"-\" for stdin\n" \