aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archival/Kbuild8
-rw-r--r--archival/bbunzip.c346
-rw-r--r--archival/bunzip2.c67
-rw-r--r--archival/gunzip.c163
-rw-r--r--archival/libunarchive/check_header_gzip.c9
-rw-r--r--archival/libunarchive/get_header_tar_gz.c2
-rw-r--r--archival/rpm.c2
-rw-r--r--archival/rpm2cpio.c2
-rw-r--r--archival/uncompress.c95
-rw-r--r--archival/unlzma.c65
-rw-r--r--include/unarchive.h2
-rwxr-xr-xtestsuite/bunzip2.tests84
-rwxr-xr-xtestsuite/bzcat.tests49
-rwxr-xr-xtestsuite/gunzip.tests3
14 files changed, 493 insertions, 404 deletions
diff --git a/archival/Kbuild b/archival/Kbuild
index f85e0c2a7..50b90fa93 100644
--- a/archival/Kbuild
+++ b/archival/Kbuild
@@ -8,15 +8,15 @@ libs-y += libunarchive/
lib-y:=
lib-$(CONFIG_AR) += ar.o
-lib-$(CONFIG_BUNZIP2) += bunzip2.o
-lib-$(CONFIG_UNLZMA) += unlzma.o
+lib-$(CONFIG_BUNZIP2) += bbunzip.o ### bunzip2.o
+lib-$(CONFIG_UNLZMA) += bbunzip.o ### unlzma.o
lib-$(CONFIG_CPIO) += cpio.o
lib-$(CONFIG_DPKG) += dpkg.o
lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o
-lib-$(CONFIG_GUNZIP) += gunzip.o
+lib-$(CONFIG_GUNZIP) += bbunzip.o ### gunzip.o
lib-$(CONFIG_GZIP) += gzip.o
lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
lib-$(CONFIG_RPM) += rpm.o
lib-$(CONFIG_TAR) += tar.o
-lib-$(CONFIG_UNCOMPRESS) += uncompress.o
+lib-$(CONFIG_UNCOMPRESS) += bbunzip.o ### uncompress.o
lib-$(CONFIG_UNZIP) += unzip.o
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
new file mode 100644
index 000000000..7ec8f4f0a
--- /dev/null
+++ b/archival/bbunzip.c
@@ -0,0 +1,346 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Modified for busybox by Glenn McGrath <bug1@iinet.net.au>
+ * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "busybox.h"
+#include "unarchive.h"
+
+enum {
+ OPT_STDOUT = 1,
+ OPT_FORCE = 2,
+/* gunzip only: */
+ OPT_TEST = 4,
+ OPT_DECOMPRESS = 8,
+ OPT_VERBOSE = 0x10,
+};
+
+static
+int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
+{
+ int fd = open(filename, flags, mode);
+ if (fd < 0) {
+ bb_perror_msg("%s", filename);
+ return 1;
+ }
+ if (fd != to_fd) {
+ if (dup2(fd, to_fd) < 0)
+ bb_perror_msg_and_die("cannot dup");
+ close(fd);
+ }
+ return 0;
+}
+
+static
+int unpack(char **argv,
+ char* (*make_new_name)(char *filename),
+ USE_DESKTOP(long long) int (*unpacker)(void)
+)
+{
+ struct stat stat_buf;
+ USE_DESKTOP(long long) int status;
+ char *filename;
+ /* NB: new_name is *possibly* malloc'ed! */
+ smallint exitcode = 0;
+
+ do {
+ char *new_name = NULL;
+
+ filename = *argv; /* can be NULL - 'streaming' bunzip2 */
+ if (filename && LONE_DASH(filename))
+ filename = NULL;
+
+ /* Open src */
+ if (filename) {
+ if (stat(filename, &stat_buf) != 0) {
+ bb_perror_msg("%s", filename);
+ err:
+ exitcode = 1;
+ goto free_name;
+ }
+ if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
+ goto err;
+ }
+
+ /* Special cases: test, stdout */
+ if (option_mask32 & (OPT_STDOUT|OPT_TEST)) {
+ if (option_mask32 & OPT_TEST)
+ if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
+ goto err;
+ filename = NULL;
+ }
+
+ /* Open dst unless -c, "-" or called as bzcat */
+ if (filename) {
+ new_name = make_new_name(filename);
+ if (!new_name) {
+ bb_error_msg("%s: unknown suffix - ignored", filename);
+ goto err;
+ }
+ /* O_EXCL: "real" bunzip2 doesn't overwrite files too */
+ /* TODO: "real" gunzip goes not bail out, but goes
+ * to next file */
+ if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
+ stat_buf.st_mode))
+ goto err;
+ }
+
+ /* Check that the input is sane. */
+ if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) {
+ bb_error_msg_and_die("compressed data not read from terminal, "
+ "use -f to force it");
+ }
+
+ status = unpacker();
+ if (status < 0)
+ exitcode = 1;
+
+ if (filename) {
+ char *del = new_name;
+ if (status >= 0) {
+ /* TODO: restore user/group/times here? */
+ /* delete _old_ file */
+ del = filename;
+ /* Restore extension (unless tgz -> tar case) */
+ if (new_name == filename)
+ filename[strlen(filename)] = '.';
+ }
+ if (unlink(del) < 0)
+ bb_perror_msg_and_die("cannot remove %s", del);
+#if 0 /* Currently buggy - wrong name: "a.gz: 261% - replaced with a.gz" */
+ /* Extreme bloat for gunzip compat */
+ if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) {
+ fprintf(stderr, "%s: %u%% - replaced with %s\n",
+ filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name);
+ }
+#endif
+ free_name:
+ if (new_name != filename)
+ free(new_name);
+ }
+ } while (*argv && *++argv);
+
+ return exitcode;
+}
+
+#if ENABLE_BUNZIP2
+
+static
+char* make_new_name_bunzip2(char *filename)
+{
+ char *extension = strrchr(filename, '.');
+ if (!extension || strcmp(extension, ".bz2") != 0) {
+ /* Mimic GNU gunzip ("real" bunzip2 tries to */
+ /* unpack file anyway, to file.out) */
+ return NULL;
+ }
+ *extension = '\0';
+ return filename;
+}
+
+static
+USE_DESKTOP(long long) int unpack_bunzip2(void)
+{
+ return uncompressStream(STDIN_FILENO, STDOUT_FILENO);
+}
+
+int bunzip2_main(int argc, char **argv);
+int bunzip2_main(int argc, char **argv)
+{
+ getopt32(argc, argv, "cf");
+ argv += optind;
+ if (applet_name[2] == 'c')
+ option_mask32 |= OPT_STDOUT;
+
+ return unpack(argv, make_new_name_bunzip2, unpack_bunzip2);
+}
+
+#endif
+
+
+/*
+ * Gzip implementation for busybox
+ *
+ * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
+ *
+ * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
+ * based on gzip sources
+ *
+ * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
+ * well as stdin/stdout, and to generally behave itself wrt command line
+ * handling.
+ *
+ * General cleanup to better adhere to the style guide and make use of standard
+ * busybox functions by Glenn McGrath <bug1@iinet.net.au>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+#if ENABLE_GUNZIP
+
+static
+char* make_new_name_gunzip(char *filename)
+{
+ char *extension = strrchr(filename, '.');
+
+ if (!extension)
+ return NULL;
+
+ if (strcmp(extension, ".gz") == 0
+#ifdef CONFIG_FEATURE_GUNZIP_UNCOMPRESS
+ || strcmp(extension, ".Z") == 0
+#endif
+ ) {
+ *extension = '\0';
+ } else if(strcmp(extension, ".tgz") == 0) {
+ filename = xstrdup(filename);
+ extension = strrchr(filename, '.');
+ extension[2] = 'a';
+ extension[3] = 'r';
+ } else {
+ return NULL;
+ }
+ return filename;
+}
+
+static
+USE_DESKTOP(long long) int unpack_gunzip(void)
+{
+ USE_DESKTOP(long long) int status = -1;
+
+ /* do the decompression, and cleanup */
+ if (xread_char(STDIN_FILENO) == 0x1f) {
+ unsigned char magic2;
+
+ magic2 = xread_char(STDIN_FILENO);
+ if (ENABLE_FEATURE_GUNZIP_UNCOMPRESS && magic2 == 0x9d) {
+ status = uncompress(STDIN_FILENO, STDOUT_FILENO);
+ } else if (magic2 == 0x8b) {
+ check_header_gzip_or_die(STDIN_FILENO);
+ status = inflate_gunzip(STDIN_FILENO, STDOUT_FILENO);
+ } else {
+ goto bad_magic;
+ }
+ if (status < 0) {
+ bb_error_msg("error inflating");
+ }
+ } else {
+ bad_magic:
+ bb_error_msg("invalid magic");
+ /* status is still == -1 */
+ }
+ return status;
+}
+
+int gunzip_main(int argc, char **argv);
+int gunzip_main(int argc, char **argv)
+{
+ getopt32(argc, argv, "cftdv");
+ argv += optind;
+ /* if called as zcat */
+ if (applet_name[1] == 'c')
+ option_mask32 |= OPT_STDOUT;
+
+ return unpack(argv, make_new_name_gunzip, unpack_gunzip);
+}
+
+#endif
+
+
+/*
+ * 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.
+ */
+
+#if ENABLE_UNLZMA
+
+static
+char* make_new_name_unlzma(char *filename)
+{
+ char *extension = strrchr(filename, '.');
+ if (!extension || strcmp(extension, ".lzma") != 0)
+ return NULL;
+ *extension = '\0';
+ return filename;
+}
+
+static
+USE_DESKTOP(long long) int unpack_unlzma(void)
+{
+ return unlzma(STDIN_FILENO, STDOUT_FILENO);
+}
+
+int unlzma_main(int argc, char **argv);
+int unlzma_main(int argc, char **argv)
+{
+ getopt32(argc, argv, "c");
+ argv += optind;
+ /* lzmacat? */
+ if (applet_name[4] == 'c')
+ option_mask32 |= OPT_STDOUT;
+
+ return unpack(argv, make_new_name_unlzma, unpack_unlzma);
+}
+
+#endif
+
+
+/* vi: set sw=4 ts=4: */
+/*
+ * Uncompress applet for busybox (c) 2002 Glenn McGrath
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#if ENABLE_UNCOMPRESS
+
+static
+char* make_new_name_uncompress(char *filename)
+{
+ char *extension = strrchr(filename, '.');
+ if (!extension || strcmp(extension, ".Z") != 0)
+ return NULL;
+ *extension = '\0';
+ return filename;
+}
+
+static
+USE_DESKTOP(long long) int unpack_uncompress(void)
+{
+ USE_DESKTOP(long long) int status = -1;
+
+ if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
+ bb_error_msg("invalid magic");
+ } else {
+ status = uncompress(STDIN_FILENO, STDOUT_FILENO);
+ }
+ return status;
+}
+
+int uncompress_main(int argc, char **argv);
+int uncompress_main(int argc, char **argv)
+{
+ getopt32(argc, argv, "cf");
+ argv += optind;
+
+ return unpack(argv, make_new_name_uncompress, unpack_uncompress);
+}
+
+#endif
diff --git a/archival/bunzip2.c b/archival/bunzip2.c
deleted file mode 100644
index 1deac7b53..000000000
--- a/archival/bunzip2.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Modified for busybox by Glenn McGrath <bug1@iinet.net.au>
- * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
- *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
- */
-
-#include "busybox.h"
-#include "unarchive.h"
-
-#define BUNZIP2_OPT_STDOUT 1
-#define BUNZIP2_OPT_FORCE 2
-
-int bunzip2_main(int argc, char **argv);
-int bunzip2_main(int argc, char **argv)
-{
- USE_DESKTOP(long long) int status;
- char *filename;
- unsigned opt;
- int src_fd, dst_fd;
-
- opt = getopt32(argc, argv, "cf");
-
- /* Set input filename and number */
- filename = argv[optind];
- if (filename && NOT_LONE_DASH(filename)) {
- /* Open input file */
- src_fd = xopen(filename, O_RDONLY);
- } else {
- src_fd = STDIN_FILENO;
- filename = 0;
- }
-
- /* if called as bzcat force the stdout flag */
- if ((opt & BUNZIP2_OPT_STDOUT) || applet_name[2] == 'c')
- filename = 0;
-
- /* Check that the input is sane. */
- if (isatty(src_fd) && (opt & BUNZIP2_OPT_FORCE) == 0) {
- bb_error_msg_and_die("compressed data not read from terminal, "
- "use -f to force it");
- }
-
- if (filename) {
- struct stat stat_buf;
- /* extension = filename+strlen(filename)-4 is buggy:
- * strlen may be less than 4 */
- char *extension = strrchr(filename, '.');
- if (!extension || strcmp(extension, ".bz2") != 0) {
- bb_error_msg_and_die("invalid extension");
- }
- xstat(filename, &stat_buf);
- *extension = '\0';
- dst_fd = xopen3(filename, O_WRONLY | O_CREAT | O_TRUNC,
- stat_buf.st_mode);
- } else dst_fd = STDOUT_FILENO;
- status = uncompressStream(src_fd, dst_fd);
- if (filename) {
- if (status >= 0) filename[strlen(filename)] = '.';
- if (unlink(filename) < 0) {
- bb_error_msg_and_die("cannot remove %s", filename);
- }
- }
-
- return status;
-}
diff --git a/archival/gunzip.c b/archival/gunzip.c
deleted file mode 100644
index 3d99fe506..000000000
--- a/archival/gunzip.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Gzip implementation for busybox
- *
- * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
- *
- * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
- * based on gzip sources
- *
- * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
- * well as stdin/stdout, and to generally behave itself wrt command line
- * handling.
- *
- * General cleanup to better adhere to the style guide and make use of standard
- * busybox functions by Glenn McGrath <bug1@iinet.net.au>
- *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
- *
- * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-#include "busybox.h"
-#include "unarchive.h"
-
-#define GUNZIP_OPT_STDOUT 1
-#define GUNZIP_OPT_FORCE 2
-#define GUNZIP_OPT_TEST 4
-#define GUNZIP_OPT_DECOMPRESS 8
-#define GUNZIP_OPT_VERBOSE 0x10
-
-int gunzip_main(int argc, char **argv);
-int gunzip_main(int argc, char **argv)
-{
- USE_DESKTOP(long long) int status;
- int exitcode = 0;
- unsigned opt;
-
- opt = getopt32(argc, argv, "cftdv");
- /* if called as zcat */
- if (strcmp(applet_name, "zcat") == 0) {
- opt |= GUNZIP_OPT_STDOUT;
- }
-
- do {
- struct stat stat_buf;
- char *old_path = argv[optind];
- char *delete_path = NULL;
- char *new_path = NULL;
- int src_fd;
- int dst_fd;
-
- optind++;
-
- if (old_path == NULL || LONE_DASH(old_path)) {
- src_fd = STDIN_FILENO;
- opt |= GUNZIP_OPT_STDOUT;
- USE_DESKTOP(opt &= ~GUNZIP_OPT_VERBOSE;)
- optind = argc; /* we don't handle "gunzip - a.gz b.gz" */
- } else {
- src_fd = xopen(old_path, O_RDONLY);
- /* Get the time stamp on the input file. */
- fstat(src_fd, &stat_buf);
- }
-
- /* Check that the input is sane. */
- if (isatty(src_fd) && !(opt & GUNZIP_OPT_FORCE)) {
- bb_error_msg_and_die
- ("compressed data not read from terminal, use -f to force it");
- }
-
- /* Set output filename and number */
- if (opt & GUNZIP_OPT_TEST) {
- dst_fd = xopen(bb_dev_null, O_WRONLY); /* why does test use filenum 2 ? */
- } else if (opt & GUNZIP_OPT_STDOUT) {
- dst_fd = STDOUT_FILENO;
- } else {
- char *extension;
-
- new_path = xstrdup(old_path);
-
- extension = strrchr(new_path, '.');
-#ifdef CONFIG_FEATURE_GUNZIP_UNCOMPRESS
- if (extension && (strcmp(extension, ".Z") == 0)) {
- *extension = '\0';
- } else
-#endif
- if (extension && (strcmp(extension, ".gz") == 0)) {
- *extension = '\0';
- } else if (extension && (strcmp(extension, ".tgz") == 0)) {
- extension[2] = 'a';
- extension[3] = 'r';
- } else {
- // FIXME: should we die or just skip to next?
- bb_error_msg_and_die("invalid extension");
- }
-
- /* Open output file (with correct permissions) */
- dst_fd = xopen3(new_path, O_WRONLY | O_CREAT | O_TRUNC,
- stat_buf.st_mode);
-
- /* If unzip succeeds remove the old file */
- delete_path = old_path;
- }
-
- status = -1;
- /* do the decompression, and cleanup */
- if (xread_char(src_fd) == 0x1f) {
- unsigned char magic2;
-
- magic2 = xread_char(src_fd);
- if (ENABLE_FEATURE_GUNZIP_UNCOMPRESS && magic2 == 0x9d) {
- status = uncompress(src_fd, dst_fd);
- } else if (magic2 == 0x8b) {
- check_header_gzip(src_fd); // FIXME: xfunc? _or_die?
- status = inflate_gunzip(src_fd, dst_fd);
- } else {
- bb_error_msg("invalid magic");
- exitcode = 1;
- }
- if (status < 0) {
- bb_error_msg("error inflating");
- exitcode = 1;
- }
- else if (ENABLE_DESKTOP && (opt & GUNZIP_OPT_VERBOSE)) {
- fprintf(stderr, "%s: %u%% - replaced with %s\n",
- old_path, (unsigned)(stat_buf.st_size*100 / (status+1)), new_path);
- }
- } else {
- bb_error_msg("invalid magic");
- exitcode = 1;
- }
- if (status < 0 && new_path) {
- /* Unzip failed, remove new path instead of old path */
- delete_path = new_path;
- }
-
- if (dst_fd != STDOUT_FILENO) {
- close(dst_fd);
- }
- if (src_fd != STDIN_FILENO) {
- close(src_fd);
- }
-
- /* delete_path will be NULL if in test mode or from stdin */
- if (delete_path && (unlink(delete_path) == -1)) {
- bb_error_msg("cannot remove %s", delete_path);
- exitcode = 1;
- }
-
- free(new_path);
-
- } while (optind < argc);
-
- return exitcode;
-}
diff --git a/archival/libunarchive/check_header_gzip.c b/archival/libunarchive/check_header_gzip.c
index 0cfa94454..09cd6a94e 100644
--- a/archival/libunarchive/check_header_gzip.c
+++ b/archival/libunarchive/check_header_gzip.c
@@ -2,12 +2,11 @@
/*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdlib.h>
-#include <unistd.h>
+
#include "libbb.h"
-#include "unarchive.h" /* for external decl of check_header_gzip */
+#include "unarchive.h" /* for external decl of check_header_gzip_or_die */
-void check_header_gzip(int src_fd)
+void check_header_gzip_or_die(int src_fd)
{
union {
unsigned char raw[8];
@@ -57,6 +56,4 @@ void check_header_gzip(int src_fd)
xread_char(src_fd);
xread_char(src_fd);
}
-
- return;
}
diff --git a/archival/libunarchive/get_header_tar_gz.c b/archival/libunarchive/get_header_tar_gz.c
index 41c02e16a..1f07e4e64 100644
--- a/archival/libunarchive/get_header_tar_gz.c
+++ b/archival/libunarchive/get_header_tar_gz.c
@@ -20,7 +20,7 @@ char get_header_tar_gz(archive_handle_t *archive_handle)
bb_error_msg_and_die("invalid gzip magic");
}
- check_header_gzip(archive_handle->src_fd);
+ check_header_gzip_or_die(archive_handle->src_fd);
archive_handle->src_fd = open_transformer(archive_handle->src_fd, inflate_gunzip);
archive_handle->offset = 0;
diff --git a/archival/rpm.c b/archival/rpm.c
index 9ab12df2d..a48dda3bc 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -203,7 +203,7 @@ static void extract_cpio_gz(int fd) {
if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
bb_error_msg_and_die("invalid gzip magic");
}
- check_header_gzip(archive_handle->src_fd);
+ check_header_gzip_or_die(archive_handle->src_fd);
xchdir("/"); /* Install RPM's to root */
archive_handle->src_fd = open_transformer(archive_handle->src_fd, inflate_gunzip);
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index 7a2e64b86..307d1a0f6 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -79,7 +79,7 @@ int rpm2cpio_main(int argc, char **argv)
bb_error_msg_and_die("invalid gzip magic");
}
- check_header_gzip(rpm_fd);
+ check_header_gzip_or_die(rpm_fd);
if (inflate_gunzip(rpm_fd, STDOUT_FILENO) < 0) {
bb_error_msg("error inflating");
}
diff --git a/archival/uncompress.c b/archival/uncompress.c
deleted file mode 100644
index b16c353ec..000000000
--- a/archival/uncompress.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Uncompress applet for busybox (c) 2002 Glenn McGrath
- *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
- */
-
-#include "busybox.h"
-#include "unarchive.h"
-
-#define GUNZIP_TO_STDOUT 1
-#define GUNZIP_FORCE 2
-
-int uncompress_main(int argc, char **argv);
-int uncompress_main(int argc, char **argv)
-{
- int status = EXIT_SUCCESS;
- unsigned long flags;
-
- flags = getopt32(argc, argv, "cf");
-
- while (optind < argc) {
- char *compressed_file = argv[optind++];
- char *delete_path = NULL;
- char *uncompressed_file = NULL;
- int src_fd;
- int dst_fd;
-
- if (LONE_DASH(compressed_file)) {
- src_fd = STDIN_FILENO;
- flags |= GUNZIP_TO_STDOUT;
- } else {
- src_fd = xopen(compressed_file, O_RDONLY);
- }
-
- /* Check that the input is sane. */
- if (isatty(src_fd) && ((flags & GUNZIP_FORCE) == 0)) {
- bb_error_msg_and_die
- ("compressed data not read from terminal. Use -f to force it.");
- }
-
- /* Set output filename and number */
- if (flags & GUNZIP_TO_STDOUT) {
- dst_fd = STDOUT_FILENO;
- } else {
- struct stat stat_buf;
- char *extension;
-
- uncompressed_file = xstrdup(compressed_file);
-
- extension = strrchr(uncompressed_file, '.');
- if (!extension || (strcmp(extension, ".Z") != 0)) {
- bb_error_msg_and_die("invalid extension");
- }
- *extension = '\0';
-
- /* Open output file */
- xstat(compressed_file, &stat_buf);
- dst_fd = xopen3(uncompressed_file,
- O_WRONLY | O_CREAT | O_TRUNC,
- stat_buf.st_mode);
-
- /* If unzip succeeds remove the old file */
- delete_path = compressed_file;
- }
-
- /* do the decompression, and cleanup */
- if ((xread_char(src_fd) != 0x1f) || (xread_char(src_fd) != 0x9d)) {
- bb_error_msg_and_die("invalid magic");
- }
-
- status = uncompress(src_fd, dst_fd);
-
- if ((status != EXIT_SUCCESS) && (uncompressed_file)) {
- /* Unzip failed, remove the uncomressed file instead of compressed file */
- delete_path = uncompressed_file;
- }
-
- if (dst_fd != STDOUT_FILENO) {
- close(dst_fd);
- }
- if (src_fd != STDIN_FILENO) {
- close(src_fd);
- }
-
- /* delete_path will be NULL if in test mode or from stdin */
- if (delete_path && (unlink(delete_path) == -1)) {
- bb_error_msg_and_die("cannot remove %s", delete_path);
- }
-
- free(uncompressed_file);
- }
-
- return status;
-}
diff --git a/archival/unlzma.c b/archival/unlzma.c
deleted file mode 100644
index 24632c4a7..000000000
--- a/archival/unlzma.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * 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.
- */
-
-/* Why our g[un]zip/bunzip2 are so ugly compared to this beauty? */
-
-#include "busybox.h"
-#include "unarchive.h"
-
-#define UNLZMA_OPT_STDOUT 1
-
-int unlzma_main(int argc, char **argv);
-int unlzma_main(int argc, char **argv)
-{
- USE_DESKTOP(long long) int status;
- char *filename;
- unsigned opt;
- int src_fd, dst_fd;
-
- opt = getopt32(argc, argv, "c");
-
- /* Set input filename and number */
- filename = argv[optind];
- if (filename && NOT_LONE_DASH(filename)) {
- /* Open input file */
- src_fd = xopen(filename, O_RDONLY);
- } else {
- src_fd = STDIN_FILENO;
- filename = 0;
- }
-
- /* if called as lzmacat force the stdout flag */
- if ((opt & UNLZMA_OPT_STDOUT) || applet_name[4] == 'c')
- filename = 0;
-
- if (filename) {
- struct stat stat_buf;
- /* bug: char *extension = filename + strlen(filename) - 5; */
- char *extension = strrchr(filename, '.');
- if (!extension || strcmp(extension, ".lzma") != 0) {
- bb_error_msg_and_die("invalid extension");
- }
- xstat(filename, &stat_buf);
- *extension = '\0';
- dst_fd = xopen3(filename, O_WRONLY | O_CREAT | O_TRUNC,
- stat_buf.st_mode);
- } else
- dst_fd = STDOUT_FILENO;
- status = unlzma(src_fd, dst_fd);
- if (filename) {
- if (status >= 0) /* if success delete src, else delete dst */
- filename[strlen(filename)] = '.';
- if (unlink(filename) < 0) {
- bb_error_msg_and_die("cannot remove %s", filename);
- }
- }
-
- return (status < 0);
-}
diff --git a/include/unarchive.h b/include/unarchive.h
index 5e87d088e..36b56a925 100644
--- a/include/unarchive.h
+++ b/include/unarchive.h
@@ -83,7 +83,7 @@ extern void header_skip(const file_header_t *file_header);
extern void header_list(const file_header_t *file_header);
extern void header_verbose_list(const file_header_t *file_header);
-extern void check_header_gzip(int src_fd);
+extern void check_header_gzip_or_die(int src_fd);
extern char get_header_ar(archive_handle_t *archive_handle);
extern char get_header_cpio(archive_handle_t *archive_handle);
diff --git a/testsuite/bunzip2.tests b/testsuite/bunzip2.tests
new file mode 100755
index 000000000..83c365d75
--- /dev/null
+++ b/testsuite/bunzip2.tests
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+if test "${0##*/}" = "gunzip.tests"; then
+ unpack=gunzip
+ ext=gz
+elif test "${0##*/}" = "bunzip2.tests"; then
+ unpack=bunzip2
+ ext=bz2
+else
+ echo "WTF? argv0='$0'"
+ exit 1
+fi
+
+bb="busybox "
+
+unset LC_ALL
+unset LC_MESSAGES
+unset LANG
+unset LANGUAGE
+
+hello_gz() {
+ # Gzipped "HELLO\n"
+ #_________________________ vvv vvv vvv vvv - mtime
+ echo -ne "\x1f\x8b\x08\x00\x85\x1d\xef\x45\x02\x03\xf3\x70\xf5\xf1\xf1\xe7"
+ echo -ne "\x02\x00\x6e\xd7\xac\xfd\x06\x00\x00\x00"
+}
+
+hello_bz2() {
+ # Bzipped "HELLO\n"
+ echo -ne "\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\x5b\xb8\xe8\xa3\x00\x00"
+ echo -ne "\x01\x44\x00\x00\x10\x02\x44\xa0\x00\x30\xcd\x00\xc3\x46\x29\x97"
+ echo -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3"
+}
+
+prep() {
+ rm -f t*
+ hello_$ext >t1.$ext
+ hello_$ext >t2.$ext
+}
+
+check() {
+ eval $2 >t_actual 2>&1
+ if echo -ne "$expected" | cmp - t_actual; then
+ echo "$1: PASS"
+ else
+ echo "$1: FAIL"
+ fi
+}
+
+mkdir testdir 2>/dev/null
+(
+cd testdir || { echo "cannot cd testdir!"; exit 1; }
+
+expected="$unpack: z: No such file or directory
+1
+HELLO
+"
+prep; check "$unpack: doesnt exist" "${bb}$unpack z t1.$ext; echo \$?; cat t1"
+
+
+expected="$unpack: t.zz: unknown suffix - ignored
+1
+HELLO
+"
+prep; >t.zz; check "$unpack: unknown suffix" "${bb}$unpack t.zz t1.$ext; echo \$?; cat t1"
+
+
+# In this case file "t1" exists, and we skip t1.gz and unpack t2.gz
+expected="$unpack: t1: File exists
+1
+HELLO
+"
+prep; >t1; check "$unpack: already exists" "${bb}$unpack t1.$ext t2.$ext; echo \$?; cat t1 t2"
+
+
+# From old testsuite
+expected="HELLO\n0\n"
+prep; check "$unpack: stream unpack" "cat t1.$ext | ${bb}$unpack; echo $?"
+
+expected="ok\n"
+prep; check "$unpack: delete src" "${bb}$unpack t2.$ext; test ! -f t2.$ext && echo ok"
+
+)
+rm -rf testdir \ No newline at end of file
diff --git a/testsuite/bzcat.tests b/testsuite/bzcat.tests
new file mode 100755
index 000000000..16fa3c248
--- /dev/null
+++ b/testsuite/bzcat.tests
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+ext=bz2
+
+bb="busybox "
+
+unset LC_ALL
+unset LC_MESSAGES
+unset LANG
+unset LANGUAGE
+
+hello_gz() {
+ # Gzipped "HELLO\n"
+ #_________________________ vvv vvv vvv vvv - mtime
+ echo -ne "\x1f\x8b\x08\x00\x85\x1d\xef\x45\x02\x03\xf3\x70\xf5\xf1\xf1\xe7"
+ echo -ne "\x02\x00\x6e\xd7\xac\xfd\x06\x00\x00\x00"
+}
+
+hello_bz2() {
+ # Bzipped "HELLO\n"
+ echo -ne "\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\x5b\xb8\xe8\xa3\x00\x00"
+ echo -ne "\x01\x44\x00\x00\x10\x02\x44\xa0\x00\x30\xcd\x00\xc3\x46\x29\x97"
+ echo -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3"
+}
+
+prep() {
+ rm -f t*
+ hello_$ext >t1.$ext
+ hello_$ext >t2.$ext
+}
+
+check() {
+ eval $2 >t_actual 2>&1
+ if echo -ne "$expected" | cmp - t_actual; then
+ echo "$1: PASS"
+ else
+ echo "$1: FAIL"
+ fi
+}
+
+mkdir testdir 2>/dev/null
+(
+cd testdir || { echo "cannot cd testdir!"; exit 1; }
+
+expected="HELLO\nok\n"
+prep; check "bzcat: dont delete src" "${bb}bzcat t2.bz2; test -f t2.bz2 && echo ok"
+
+)
+rm -rf testdir
diff --git a/testsuite/gunzip.tests b/testsuite/gunzip.tests
new file mode 100755
index 000000000..d7810044f
--- /dev/null
+++ b/testsuite/gunzip.tests
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+. bunzip2.tests