From ab9eef21a57c23567505e8fbceb8e5ea76306ce1 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Wed, 7 Mar 2007 22:02:23 +0000 Subject: [PATCH] bunzip2/gunzip/uncompress/unlzma: merge into common code - fix few corner cases, reduce size by 450 bytes. Update testsuite. --- archival/Kbuild | 8 +- archival/bbunzip.c | 346 ++++++++++++++++++++++ archival/bunzip2.c | 67 ----- archival/gunzip.c | 163 ---------- archival/libunarchive/check_header_gzip.c | 11 +- archival/libunarchive/get_header_tar_gz.c | 2 +- archival/rpm.c | 2 +- archival/rpm2cpio.c | 2 +- archival/uncompress.c | 95 ------ archival/unlzma.c | 65 ---- include/unarchive.h | 2 +- testsuite/bunzip2.tests | 84 ++++++ testsuite/bzcat.tests | 49 +++ testsuite/gunzip.tests | 3 + 14 files changed, 494 insertions(+), 405 deletions(-) create mode 100644 archival/bbunzip.c delete mode 100644 archival/bunzip2.c delete mode 100644 archival/gunzip.c delete mode 100644 archival/uncompress.c delete mode 100644 archival/unlzma.c create mode 100755 testsuite/bunzip2.tests create mode 100755 testsuite/bzcat.tests create mode 100755 testsuite/gunzip.tests 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 + * Added support output to stdout by Thomas Lundquist + * + * 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 + * based on gzip sources + * + * Adjusted further by Erik Andersen 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 + * + * 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 + * + * 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 - * Added support output to stdout by Thomas Lundquist - * - * 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 - * based on gzip sources - * - * Adjusted further by Erik Andersen 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 - * - * 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 -#include -#include "libbb.h" -#include "unarchive.h" /* for external decl of check_header_gzip */ -void check_header_gzip(int src_fd) +#include "libbb.h" +#include "unarchive.h" /* for external decl of check_header_gzip_or_die */ + +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 - * - * 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