diff options
Diffstat (limited to 'archival/libunarchive')
23 files changed, 1277 insertions, 1026 deletions
diff --git a/archival/libunarchive/Makefile.in b/archival/libunarchive/Makefile.in index cd68be732..e2ac546ab 100644 --- a/archival/libunarchive/Makefile.in +++ b/archival/libunarchive/Makefile.in @@ -22,14 +22,41 @@ ifndef $(LIBUNARCHIVE_DIR) LIBUNARCHIVE_DIR:=$(TOPDIR)archival/libunarchive/ endif -LIBUNARCHIVE-y:=unarchive.o seek_sub_file.o -LIBUNARCHIVE-$(CONFIG_DPKG) += deb_extract.o get_header_ar.o get_header_tar.o -LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += deb_extract.o get_header_ar.o get_header_tar.o -LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o -LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o -LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += get_header_cpio.o -LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o -LIBUNARCHIVE-$(CONFIG_UNZIP) += get_header_zip.o +LIBUNARCHIVE-y:= \ +\ + data_skip.o \ + data_extract_all.o \ + data_extract_to_stdout.o \ +\ + filter_accept_all.o \ + filter_accept_list.o \ + filter_accept_reject_list.o \ +\ + get_header_ar.o \ + get_header_tar.o \ + get_header_tar_gz.o \ +\ + header_skip.o \ + header_list.o \ + header_verbose_list.o \ +\ + add_to_list.o \ + check_header_gzip.o \ + check_trailer_gzip.o \ + copy_file_chunk_fd.o \ + data_align.o \ + init_handle.o \ + seek_sub_file.o \ + unpack_ar_archive.o \ + +LIBUNARCHIVE-$(CONFIG_DPKG) += +LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += +LIBUNARCHIVE-$(CONFIG_AR) += +LIBUNARCHIVE-$(CONFIG_CPIO) += +LIBUNARCHIVE-$(CONFIG_GUNZIP) += +LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += +LIBUNARCHIVE-$(CONFIG_TAR) += +LIBUNARCHIVE-$(CONFIG_UNZIP) += libraries-y+=$(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR) diff --git a/archival/libunarchive/add_to_list.c b/archival/libunarchive/add_to_list.c new file mode 100644 index 000000000..052bca351 --- /dev/null +++ b/archival/libunarchive/add_to_list.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <string.h> +#include "unarchive.h" +#include "libbb.h" + +extern const llist_t *add_to_list(const llist_t *old_head, const char *new_item) +{ + llist_t *new_head; + + new_head = xmalloc(sizeof(llist_t)); + new_head->data = new_item; + new_head->link = old_head; + + return(new_head); +} diff --git a/archival/libunarchive/check_header_gzip.c b/archival/libunarchive/check_header_gzip.c new file mode 100644 index 000000000..508d30924 --- /dev/null +++ b/archival/libunarchive/check_header_gzip.c @@ -0,0 +1,75 @@ +#include <stdlib.h> +#include <unistd.h> +#include "libbb.h" + +extern void check_header_gzip(int src_fd) +{ + union { + unsigned char raw[10]; + struct { + unsigned char magic[2]; + unsigned char method; + unsigned char flags; + unsigned int mtime; + unsigned char xtra_flags; + unsigned char os_flags; + } formated; + } header; + + xread_all(src_fd, header.raw, 10); + + /* Magic header for gzip files, 1F 8B = \037\213 */ + if ((header.formated.magic[0] != 0x1F) + || (header.formated.magic[1] != 0x8b)) { + error_msg_and_die("Invalid gzip magic"); + } + + /* Check the compression method */ + if (header.formated.method != 8) { + error_msg_and_die("Unknown compression method %d", + header.formated.method); + } + + if (header.formated.flags & 0x04) { + /* bit 2 set: extra field present */ + unsigned char extra_short; + + extra_short = xread_char(src_fd); + extra_short += xread_char(src_fd) << 8; + while (extra_short > 0) { + /* Ignore extra field */ + xread_char(src_fd); + extra_short--; + } + } + + /* Discard original name if any */ + if (header.formated.flags & 0x08) { + /* bit 3 set: original file name present */ + char tmp; + + do { + read(src_fd, &tmp, 1); + } while (tmp != 0); + } + + /* Discard file comment if any */ + if (header.formated.flags & 0x10) { + /* bit 4 set: file comment present */ + char tmp; + + do { + read(src_fd, &tmp, 1); + } while (tmp != 0); + } + + /* Read the header checksum */ + if (header.formated.flags & 0x02) { + char tmp; + + read(src_fd, &tmp, 1); + read(src_fd, &tmp, 1); + } + + return; +} diff --git a/archival/libunarchive/check_trailer_gzip.c b/archival/libunarchive/check_trailer_gzip.c new file mode 100644 index 000000000..215e8293f --- /dev/null +++ b/archival/libunarchive/check_trailer_gzip.c @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: */ +/* + * busybox gunzip trailing header handler + * Copyright Glenn McGrath 2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "config.h" +#include "busybox.h" +#include "unarchive.h" + +extern unsigned int gunzip_crc; +extern unsigned int gunzip_bytes_out; +extern unsigned char *gunzip_in_buffer; +extern unsigned char gunzip_in_buffer_count; + +extern void check_trailer_gzip(int src_fd) +{ + + unsigned int stored_crc = 0; + unsigned char count; + + /* top up the input buffer with the rest of the trailer */ + xread_all(src_fd, &gunzip_in_buffer[gunzip_in_buffer_count], 8 - gunzip_in_buffer_count); + for (count = 0; count != 4; count++) { + stored_crc |= (gunzip_in_buffer[count] << (count * 8)); + } + + /* Validate decompression - crc */ + if (stored_crc != (gunzip_crc ^ 0xffffffffL)) { + error_msg("invalid compressed data--crc error"); + } + + /* Validate decompression - size */ + if (gunzip_bytes_out != + (gunzip_in_buffer[4] | (gunzip_in_buffer[5] << 8) | + (gunzip_in_buffer[6] << 16) | (gunzip_in_buffer[7] << 24))) { + error_msg("invalid compressed data--length error"); + } + +} diff --git a/archival/libunarchive/copy_file_chunk_fd.c b/archival/libunarchive/copy_file_chunk_fd.c new file mode 100644 index 000000000..fb513e6d5 --- /dev/null +++ b/archival/libunarchive/copy_file_chunk_fd.c @@ -0,0 +1,33 @@ +#include <unistd.h> +#include <sys/types.h> +#include "libbb.h" + +/* Copy CHUNKSIZE bytes (or untill EOF if chunksize == -1) + * from SRC_FILE to DST_FILE. */ +extern int copy_file_chunk_fd(int src_fd, int dst_fd, off_t chunksize) +{ + size_t nread, size; + char buffer[BUFSIZ]; + + while (chunksize != 0) { + if (chunksize > BUFSIZ) { + size = BUFSIZ; + } else { + size = chunksize; + } + nread = xread(src_fd, buffer, size); + if (nread == 0) { + return 1; + } + + if (write (dst_fd, buffer, nread) != nread) { + error_msg_and_die ("Short write"); + } + + if (chunksize != -1) { + chunksize -= nread; + } + } + + return 0; +} diff --git a/archival/libunarchive/data_align.c b/archival/libunarchive/data_align.c new file mode 100644 index 000000000..d6243bc19 --- /dev/null +++ b/archival/libunarchive/data_align.c @@ -0,0 +1,13 @@ +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#include "unarchive.h" +#include "libbb.h" + +extern const unsigned short data_align(const int src_fd, const unsigned int offset, const unsigned short align_to) +{ + const unsigned short skip_amount = (align_to - (offset % align_to)) % align_to; + seek_sub_file(src_fd, skip_amount); + + return(skip_amount); +} diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c new file mode 100644 index 000000000..20d99aa58 --- /dev/null +++ b/archival/libunarchive/data_extract_all.c @@ -0,0 +1,76 @@ +#include <sys/types.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <utime.h> +#include <unistd.h> +#include <stdlib.h> +#include "libbb.h" +#include "unarchive.h" + +extern void data_extract_all(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + int dst_fd; + int res; + + if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { + char *dir = dirname(strdup(file_header->name)); + make_directory (dir, 0777, FILEUTILS_RECUR); + free(dir); + } + + /* Create the file */ + switch(file_header->mode & S_IFMT) { + case S_IFREG: { +#ifdef CONFIG_CPIO + if (file_header->link_name) { + /* hard link */ + res = link(file_header->link_name, file_header->name); + if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { + perror_msg("Couldnt create hard link"); + } + } else +#endif + { + /* Regular file */ + dst_fd = xopen(file_header->name, O_WRONLY | O_CREAT); + copy_file_chunk_fd(archive_handle->src_fd, dst_fd, file_header->size); + close(dst_fd); + } + break; + } + case S_IFDIR: + res = mkdir(file_header->name, file_header->mode); + if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { + perror_msg("extract_archive: %s", file_header->name); + } + break; + case S_IFLNK: + /* Symlink */ + res = symlink(file_header->link_name, file_header->name); + if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { + perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name); + } + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + res = mknod(file_header->name, file_header->mode, file_header->device); + if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { + perror_msg("Cannot create node %s", file_header->name); + } + break; + } + + chmod(file_header->name, file_header->mode); + chown(file_header->name, file_header->uid, file_header->gid); + + if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { + struct utimbuf t; + t.actime = t.modtime = file_header->mtime; + utime(file_header->name, &t); + } +} diff --git a/archival/libunarchive/data_extract_to_stdout.c b/archival/libunarchive/data_extract_to_stdout.c new file mode 100644 index 000000000..00687b315 --- /dev/null +++ b/archival/libunarchive/data_extract_to_stdout.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <stdio.h> +#include "unarchive.h" + +extern void data_extract_to_stdout(archive_handle_t *archive_handle) +{ + copy_file_chunk_fd(archive_handle->src_fd, fileno(stdout), archive_handle->file_header->size); +} diff --git a/archival/libunarchive/data_skip.c b/archival/libunarchive/data_skip.c new file mode 100644 index 000000000..4e63d4304 --- /dev/null +++ b/archival/libunarchive/data_skip.c @@ -0,0 +1,27 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include "unarchive.h" +#include "libbb.h" + +extern void data_skip(archive_handle_t *archive_handle) +{ + seek_sub_file(archive_handle->src_fd, archive_handle->file_header->size); +} diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c index d84067068..20bf88f55 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libunarchive/decompress_unzip.c @@ -65,114 +65,126 @@ static char *license_msg[] = { #include <signal.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <fcntl.h> #include "config.h" -#include "libbb.h" +#include "busybox.h" +#include "unarchive.h" -#ifdef CONFIG_FEATURE_UNCOMPRESS -int uncompress(FILE * in, FILE * out); -#endif - -static FILE *in_file, *out_file; +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ + } v; +} huft_t; -/* these are freed by gz_close */ -static unsigned char *window; -static unsigned long *crc_table; +static int gunzip_src_fd; +static int gunzip_dst_fd; +unsigned int gunzip_bytes_out; /* number of output bytes */ +static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ -static unsigned long crc; /* shift register contents */ +/* This is used to sanify any unused bits from the bitbuffer + * so they arent skipped when reading trailers (trailing headers) */ +unsigned char gunzip_in_buffer_count; +unsigned char *gunzip_in_buffer; -/* Return codes from gzip */ -#define ERROR 1 +/* gunzip_window size--must be a power of two, and + * at least 32K for zip's deflate method */ +static const int gunzip_wsize = 0x8000; -/* - * window size--must be a power of two, and - * at least 32K for zip's deflate method - */ -#define WSIZE 0x8000 +static unsigned char *gunzip_window; +static unsigned int *gunzip_crc_table; +unsigned int gunzip_crc; /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ -static long bytes_out; /* number of output bytes */ -static unsigned long outcnt; /* bytes in output buffer */ - -static unsigned hufts; /* track memory usage */ -static unsigned long bb; /* bit buffer */ -static unsigned bk; /* bits in bit buffer */ - -typedef struct huft_s { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_s *t; /* pointer to next level of table */ - } v; -} huft_t; +static unsigned int gunzip_hufts; /* track memory usage */ +static unsigned int gunzip_bb; /* bit buffer */ +static unsigned char gunzip_bk; /* bits in bit buffer */ static const unsigned short mask_bits[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; -/* static int error_number = 0; */ -/* ======================================================================== - * Signal and error handler. - */ +/* Copy lengths for literal codes 257..285 */ +static const unsigned short cplens[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +}; + +/* note: see note #13 above about the 258 in this list. */ +/* Extra bits for literal codes 257..285 */ +static const unsigned char cplext[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, + 5, 5, 5, 0, 99, 99 +}; /* 99==invalid */ + +/* Copy offsets for distance codes 0..29 */ +static const unsigned short cpdist[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +}; + +/* Extra bits for distance codes */ +static const unsigned char cpdext[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 +}; + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* Order of the bit length code lengths */ +static const unsigned char border[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) +{ + while (*current < required) { + bitbuffer |= ((unsigned int) xread_char(gunzip_src_fd)) << *current; + *current += 8; + } + + return(bitbuffer); +} static void abort_gzip(void) { error_msg("gzip aborted\n"); - exit(ERROR); + exit(-1); } -static void make_crc_table(void) +static void make_gunzip_crc_table(void) { - const unsigned long poly = 0xedb88320; /* polynomial exclusive-or pattern */ + const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */ unsigned short i; /* counter for all possible eight bit values */ /* initial shift register value */ - crc = 0xffffffffL; - crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); + gunzip_crc = 0xffffffffL; + gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int)); /* Compute and print table of CRC's, five per line */ for (i = 0; i < 256; i++) { - unsigned long table_entry; /* crc shift register */ - char k; /* byte being shifted into crc apparatus */ + unsigned int table_entry; /* crc shift register */ + unsigned char k; /* byte being shifted into crc apparatus */ table_entry = i; /* The idea to initialize the register with the byte instead of * zero was stolen from Haruhiko Okumura's ar002 */ for (k = 8; k; k--) { - table_entry = - table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> - 1; - } - crc_table[i] = table_entry; + if (table_entry & 1) { + table_entry = (table_entry >> 1) ^ poly; + } else { + table_entry >>= 1; } -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void flush_window(void) -{ - int n; - - if (outcnt == 0) - return; - - for (n = 0; n < outcnt; n++) { - crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); } - - if (fwrite(window, 1, outcnt, out_file) != outcnt) { - error_msg_and_die("Couldnt write"); + gunzip_crc_table[i] = table_entry; } - bytes_out += (unsigned long) outcnt; - outcnt = 0; } /* @@ -183,7 +195,8 @@ static void flush_window(void) */ static int huft_free(huft_t * t) { - huft_t *p, *q; + huft_t *p; + huft_t *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; @@ -195,8 +208,6 @@ static int huft_free(huft_t * t) return 0; } -typedef unsigned char extra_bits_t; - /* Given a list of code lengths and a maximum table size, make a set of * tables to decode that set of codes. Return zero on success, one if * the given code set is incomplete (the tables are still built in this @@ -213,7 +224,7 @@ typedef unsigned char extra_bits_t; */ static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, const unsigned short *d, - const extra_bits_t * e, huft_t ** t, int *m) + const unsigned char *e, huft_t ** t, int *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -251,26 +262,35 @@ static int huft_build(unsigned int *b, const unsigned int n, /* Find minimum and maximum length, bound *m by those */ l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) + for (j = 1; j <= BMAX; j++) { + if (c[j]) { break; + } + } k = j; /* minimum code length */ - if ((unsigned) l < j) + if ((unsigned) l < j) { l = j; - for (i = BMAX; i; i--) - if (c[i]) + } + for (i = BMAX; i; i--) { + if (c[i]) { break; + } + } g = i; /* maximum code length */ - if ((unsigned) l > i) + if ((unsigned) l > i) { l = i; + } *m = l; /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) + for (y = 1 << j; j < i; j++, y <<= 1) { + if ((y -= c[j]) < 0) { return 2; /* bad input: more codes than bits */ - if ((y -= c[i]) < 0) + } + } + if ((y -= c[i]) < 0) { return 2; + } c[i] += y; /* Generate starting offsets into the value table for each length */ @@ -285,8 +305,9 @@ static int huft_build(unsigned int *b, const unsigned int n, p = b; i = 0; do { - if ((j = *p++) != 0) + if ((j = *p++) != 0) { v[x[j]++] = i; + } } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ @@ -314,8 +335,9 @@ static int huft_build(unsigned int *b, const unsigned int n, f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) { /* try smaller tables up to z bits */ - if ((f <<= 1) <= *++xp) + if ((f <<= 1) <= *++xp) { break; /* enough codes to use up j bits */ + } f -= *xp; /* else deduct codes from patterns */ } } @@ -324,7 +346,7 @@ static int huft_build(unsigned int *b, const unsigned int n, /* allocate and link in new table */ q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); - hufts += z + 1; /* track memory usage */ + gunzip_hufts += z + 1; /* track memory usage */ *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = NULL; u[h] = ++q; /* table starts after link */ @@ -342,9 +364,9 @@ static int huft_build(unsigned int *b, const unsigned int n, /* set up table entry in r */ r.b = (unsigned char) (k - w); - if (p >= v + n) + if (p >= v + n) { r.e = 99; /* out of values--invalid code */ - else if (*p < s) { + } else if (*p < s) { r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ r.v.n = (unsigned short) (*p); /* simple code is just the value */ p++; /* one compiler does not like *p++ */ @@ -355,12 +377,14 @@ static int huft_build(unsigned int *b, const unsigned int n, /* fill code-like entries with r */ f = 1 << (k - w); - for (j = i >> w; j < z; j += f) + for (j = i >> w; j < z; j += f) { q[j] = r; + } /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) + for (j = 1 << (k - 1); i & j; j >>= 1) { i ^= j; + } i ^= j; /* backup over finished tables */ @@ -374,6 +398,25 @@ static int huft_build(unsigned int *b, const unsigned int n, return y != 0 && g != 1; } +/* =========================================================================== + * Write the output gunzip_window gunzip_window[0..gunzip_outbuf_count-1] and update crc and gunzip_bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_gunzip_window(void) +{ + int n; + + for (n = 0; n < gunzip_outbuf_count; n++) { + gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); + } + + if (write(gunzip_dst_fd, gunzip_window, gunzip_outbuf_count) != gunzip_outbuf_count) { + error_msg_and_die("Couldnt write"); + } + gunzip_bytes_out += gunzip_outbuf_count; + gunzip_outbuf_count = 0; +} + /* * inflate (decompress) the codes in a deflated (compressed) block. * Return an error code or zero if it all goes ok. @@ -381,32 +424,26 @@ static int huft_build(unsigned int *b, const unsigned int n, * tl, td: literal/length and distance decoder tables * bl, bd: number of bits decoded by tl[] and td[] */ -static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) +static int inflate_codes(huft_t * tl, huft_t * td, const unsigned int bl, const unsigned int bd) { - register unsigned long e; /* table entry flag/number of extra bits */ - unsigned long n, d; /* length and index for copy */ - unsigned long w; /* current window position */ + unsigned int e; /* table entry flag/number of extra bits */ + unsigned int n, d; /* length and index for copy */ + unsigned int w; /* current gunzip_window position */ huft_t *t; /* pointer to table entry */ - unsigned ml, md; /* masks for bl and bd bits */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - register int input_char; + unsigned int ml, md; /* masks for bl and bd bits */ + unsigned int b; /* bit buffer */ + unsigned int k; /* number of bits in bit buffer */ /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = outcnt; /* initialize window position */ + b = gunzip_bb; /* initialize bit buffer */ + k = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ /* inflate the coded data */ ml = mask_bits[bl]; /* precompute masks for speed */ md = mask_bits[bd]; - for (;;) { /* do until end of block */ - while (k < (unsigned) bl) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + while (1) { /* do until end of block */ + b = fill_bitbuffer(b, &k, bl); if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) do { if (e == 99) { @@ -415,20 +452,16 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) b >>= t->b; k -= t->b; e -= 16; - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); b >>= t->b; k -= t->b; if (e == 16) { /* then it's a literal */ - window[w++] = (unsigned char) t->v.n; - if (w == WSIZE) { - outcnt = (w), flush_window(); + gunzip_window[w++] = (unsigned char) t->v.n; + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + flush_gunzip_window(); w = 0; } } else { /* it's an EOB or a length */ @@ -439,24 +472,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) } /* get length of block to copy */ - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); n = t->v.n + ((unsigned) b & mask_bits[e]); b >>= e; k -= e; /* decode distance of block to copy */ - while (k < (unsigned) bd) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } - + b = fill_bitbuffer(b, &k, bd); if ((e = (t = td + ((unsigned) b & md))->e) > 16) do { if (e == 99) @@ -464,23 +486,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) b >>= t->b; k -= t->b; e -= 16; - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); b >>= t->b; k -= t->b; - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); d = w - t->v.n - ((unsigned) b & mask_bits[e]); b >>= e; k -= e; @@ -489,60 +501,38 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) do { n -= (e = (e = - WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); -#if !defined(NOMEMCPY) && !defined(DEBUG) + gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); + /* copy to new buffer to prevent possible overwrite */ if (w - d >= e) { /* (this test assumes unsigned comparison) */ - memcpy(window + w, window + d, e); + memcpy(gunzip_window + w, gunzip_window + d, e); w += e; d += e; - } else /* do it slow to avoid memcpy() overlap */ -#endif /* !NOMEMCPY */ + } else { + /* do it slow to avoid memcpy() overlap */ + /* !NOMEMCPY */ do { - window[w++] = window[d++]; + gunzip_window[w++] = gunzip_window[d++]; } while (--e); - if (w == WSIZE) { - outcnt = (w), flush_window(); + } + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + flush_gunzip_window(); w = 0; } + } while (n); } } /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = b; /* restore global bit buffer */ + gunzip_bk = k; /* done */ return 0; } -static const unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 -}; - -/* note: see note #13 above about the 258 in this list. */ -static const extra_bits_t cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 -}; /* 99==invalid */ -static const unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 -}; -static const extra_bits_t cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 -}; - -/* Tables for deflate from PKZIP's appnote.txt. */ -static const extra_bits_t border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; - /* * decompress an inflated block * e: last block flag @@ -552,53 +542,43 @@ static const extra_bits_t border[] = { /* Order of the bit length code lengths * static int inflate_block(int *e) { unsigned t; /* block type */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - int input_char; + register unsigned int b; /* bit buffer */ + unsigned int k; /* number of bits in bit buffer */ /* make local bit buffer */ - b = bb; - k = bk; + + b = gunzip_bb; + k = gunzip_bk; /* read in last block bit */ - while (k < 1) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, 1); *e = (int) b & 1; b >>= 1; k -= 1; /* read in block type */ - while (k < 2) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, 2); t = (unsigned) b & 3; b >>= 2; k -= 2; /* restore the global bit buffer */ - bb = b; - bk = k; + gunzip_bb = b; + gunzip_bk = k; /* inflate that block type */ switch (t) { case 0: /* Inflate stored */ { - unsigned long n; /* number of bytes in block */ - unsigned long w; /* current window position */ - register unsigned long b_stored; /* bit buffer */ - register unsigned long k_stored; /* number of bits in bit buffer */ + unsigned int n; /* number of bytes in block */ + unsigned int w; /* current gunzip_window position */ + unsigned int b_stored; /* bit buffer */ + unsigned int k_stored; /* number of bits in bit buffer */ /* make local copies of globals */ - b_stored = bb; /* initialize bit buffer */ - k_stored = bk; - w = outcnt; /* initialize window position */ + b_stored = gunzip_bb; /* initialize bit buffer */ + k_stored = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ /* go to byte boundary */ n = k_stored & 7; @@ -606,21 +586,12 @@ static int inflate_block(int *e) k_stored -= n; /* get the length and its complement */ - while (k_stored < 16) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_stored |= ((unsigned long)input_char) << k_stored; - k_stored += 8; - } + b_stored = fill_bitbuffer(b_stored, &k_stored, 16); n = ((unsigned) b_stored & 0xffff); b_stored >>= 16; k_stored -= 16; - while (k_stored < 16) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_stored |= ((unsigned long)input_char) << k_stored; - k_stored += 8; - } + + b_stored = fill_bitbuffer(b_stored, &k_stored, 16); if (n != (unsigned) ((~b_stored) & 0xffff)) { return 1; /* error in compressed data */ } @@ -629,15 +600,11 @@ static int inflate_block(int *e) /* read and output the compressed data */ while (n--) { - while (k_stored < 8) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_stored |= ((unsigned long)input_char) << k_stored; - k_stored += 8; - } - window[w++] = (unsigned char) b_stored; - if (w == (unsigned long) WSIZE) { - outcnt = (w), flush_window(); + b_stored = fill_bitbuffer(b_stored, &k_stored, 8); + gunzip_window[w++] = (unsigned char) b_stored; + if (w == (unsigned int) gunzip_wsize) { + gunzip_outbuf_count = (w); + flush_gunzip_window(); w = 0; } b_stored >>= 8; @@ -645,9 +612,9 @@ static int inflate_block(int *e) } /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b_stored; /* restore global bit buffer */ - bk = k_stored; + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = b_stored; /* restore global bit buffer */ + gunzip_bk = k_stored; return 0; } case 1: /* Inflate fixed @@ -659,8 +626,8 @@ static int inflate_block(int *e) int i; /* temporary variable */ huft_t *tl; /* literal/length code table */ huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ + unsigned int bl; /* lookup bits for tl */ + unsigned int bd; /* lookup bits for td */ unsigned int l[288]; /* length list for huft_build */ /* set up literal table */ @@ -692,8 +659,9 @@ static int inflate_block(int *e) } /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) + if (inflate_codes(tl, td, bl, bd)) { return 1; + } /* free the decoding tables, return */ huft_free(tl); @@ -705,53 +673,41 @@ static int inflate_block(int *e) const int dbits = 6; /* bits in base distance lookup table */ const int lbits = 9; /* bits in base literal/length lookup table */ - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ huft_t *tl; /* literal/length code table */ huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - register unsigned long b_dynamic; /* bit buffer */ - register unsigned k_dynamic; /* number of bits in bit buffer */ + unsigned int i; /* temporary variables */ + unsigned int j; + unsigned int l; /* last length */ + unsigned int m; /* mask for bit lengths table */ + unsigned int n; /* number of lengths to get */ + unsigned int bl; /* lookup bits for tl */ + unsigned int bd; /* lookup bits for td */ + unsigned int nb; /* number of bit length codes */ + unsigned int nl; /* number of literal/length codes */ + unsigned int nd; /* number of distance codes */ + + unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned int b_dynamic; /* bit buffer */ + unsigned int k_dynamic; /* number of bits in bit buffer */ /* make local bit buffer */ - b_dynamic = bb; - k_dynamic = bk; + b_dynamic = gunzip_bb; + k_dynamic = gunzip_bk; /* read in table lengths */ - while (k_dynamic < 5) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); + nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic >>= 5; k_dynamic -= 5; - while (k_dynamic < 5) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); + nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic >>= 5; k_dynamic -= 5; - while (k_dynamic < 4) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); + nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic >>= 4; k_dynamic -= 4; if (nl > 286 || nd > 30) { @@ -760,13 +716,8 @@ static int inflate_block(int *e) /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { - while (k_dynamic < 3) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); + ll[border[j]] = (unsigned int) b_dynamic & 7; b_dynamic >>= 3; k_dynamic -= 3; } @@ -776,7 +727,8 @@ static int inflate_block(int *e) /* build decoding table for trees--single level, 7 bit lookup */ bl = 7; - if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { + i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl); + if (i != 0) { if (i == 1) { huft_free(tl); } @@ -787,46 +739,31 @@ static int inflate_block(int *e) n = nl + nd; m = mask_bits[bl]; i = l = 0; - while ((unsigned) i < n) { - while (k_dynamic < (unsigned) bl) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = (td = tl + ((unsigned) b_dynamic & m))->b; + while ((unsigned int) i < n) { + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); + j = (td = tl + ((unsigned int) b_dynamic & m))->b; b_dynamic >>= j; k_dynamic -= j; j = td->v.n; if (j < 16) { /* length of code in bits (0..15) */ ll[i++] = l = j; /* save last length in l */ } else if (j == 16) { /* repeat last length 3 to 6 times */ - while (k_dynamic < 2) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); + j = 3 + ((unsigned int) b_dynamic & 3); b_dynamic >>= 2; k_dynamic -= 2; - if ((unsigned) i + j > n) { + if ((unsigned int) i + j > n) { return 1; } while (j--) { ll[i++] = l; } } else if (j == 17) { /* 3 to 10 zero length codes */ - while (k_dynamic < 3) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); + j = 3 + ((unsigned int) b_dynamic & 7); b_dynamic >>= 3; k_dynamic -= 3; - if ((unsigned) i + j > n) { + if ((unsigned int) i + j > n) { return 1; } while (j--) { @@ -834,16 +771,11 @@ static int inflate_block(int *e) } l = 0; } else { /* j == 18: 11 to 138 zero length codes */ - while (k_dynamic < 7) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); + j = 11 + ((unsigned int) b_dynamic & 0x7f); b_dynamic >>= 7; k_dynamic -= 7; - if ((unsigned) i + j > n) { + if ((unsigned int) i + j > n) { return 1; } while (j--) { @@ -857,22 +789,24 @@ static int inflate_block(int *e) huft_free(tl); /* restore the global bit buffer */ - bb = b_dynamic; - bk = k_dynamic; + gunzip_bb = b_dynamic; + gunzip_bk = k_dynamic; /* build the decoding tables for literal/length and distance codes */ bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { if (i == 1) { - error_msg("Incomplete literal tree"); + error_msg_and_die("Incomplete literal tree"); huft_free(tl); } return i; /* incomplete code set */ } + bd = dbits; if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { if (i == 1) { - error_msg("incomplete distance tree"); + error_msg_and_die("incomplete distance tree"); huft_free(td); } huft_free(tl); @@ -880,8 +814,9 @@ static int inflate_block(int *e) } /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) + if (inflate_codes(tl, td, bl, bd)) { return 1; + } /* free the decoding tables, return */ huft_free(tl); @@ -890,6 +825,7 @@ static int inflate_block(int *e) } default: /* bad block type */ + error_msg("bad block type %d\n", t); return 2; } } @@ -897,72 +833,24 @@ static int inflate_block(int *e) /* * decompress an inflated entry * - * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr + * GLOBAL VARIABLES: gunzip_outbuf_count, bk, gunzip_bb, hufts, inptr */ -extern int inflate(FILE * in, FILE * out) +extern int inflate(int in, int out) { + typedef void (*sig_type) (int); int e; /* last block flag */ int r; /* result code */ unsigned h = 0; /* maximum struct huft's malloc'ed */ - /* initialize window, bit buffer */ - outcnt = 0; - bk = 0; - bb = 0; - - in_file = in; - out_file = out; - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t) (((2L * WSIZE) + 1L) * sizeof(unsigned char))); - bytes_out = 0L; + gunzip_window = xmalloc(0x8000); + gunzip_outbuf_count = 0; + gunzip_bytes_out = 0; - /* Create the crc table */ - make_crc_table(); + gunzip_src_fd = in; + gunzip_dst_fd = out; - /* decompress until the last block */ - do { - hufts = 0; - if ((r = inflate_block(&e)) != 0) { - return r; - } - if (hufts > h) { - h = hufts; - } - } while (!e); - - /* Undo too much lookahead. The next read will be byte aligned so we - * can discard unused bits in the last meaningful byte. - */ - while (bk >= 8) { - bk -= 8; - ungetc((bb << bk), in_file); - } - - /* flush out window */ - flush_window(); - free(window); - free(crc_table); - - /* return success */ - return 0; -} - -/* =========================================================================== - * Unzip in to out. This routine works on gzip files only. - * - * IN assertions: the buffer inbuf contains already the beginning of - * the compressed data, from offsets inptr to insize-1 included. - * The magic header has already been checked. The output buffer is cleared. - * in, out: input and output file descriptors - */ -extern int unzip(FILE * l_in_file, FILE * l_out_file) -{ - unsigned char buf[8]; /* extended local header */ - unsigned char flags; /* compression flags */ - typedef void (*sig_type) (int); - unsigned short i; - unsigned char magic[2]; + gunzip_in_buffer = malloc(8); if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, (sig_type) abort_gzip); @@ -973,97 +861,44 @@ extern int unzip(FILE * l_in_file, FILE * l_out_file) } #endif - magic[0] = fgetc(l_in_file); - magic[1] = fgetc(l_in_file); - -#ifdef CONFIG_FEATURE_UNCOMPRESS - /* Magic header for compress files, 1F 9d = \037\235 */ - if ((magic[0] == 0x1F) && (magic[1] == 0x9d)) { - return uncompress(l_in_file, l_out_file); - } -#endif - - /* Magic header for gzip files, 1F 8B = \037\213 */ - if ((magic[0] != 0x1F) || (magic[1] != 0x8b)) { - error_msg("Invalid gzip magic"); - return EXIT_FAILURE; - } - - /* Check the compression method */ - if (fgetc(l_in_file) != 8) /* also catches EOF */ { - error_msg("Unknown compression method"); - return (-1); - } - - flags = (unsigned char) fgetc(l_in_file); - - /* Ignore time stamp(4), extra flags(1), OS type(1) */ - for (i = 0; i < 6; i++) { - fgetc(l_in_file); - } + /* initialize gunzip_window, bit buffer */ + gunzip_bk = 0; + gunzip_bb = 0; - if (flags & 0x04) { - /* bit 2 set: extra field present */ - const unsigned short extra = - fgetc(l_in_file) + (fgetc(l_in_file) << 8); - if (feof(in_file)) return 1; - for (i = 0; i < extra; i++) { - fgetc(l_in_file); - } - } - - /* Discard original name if any */ - if (flags & 0x08) { - /* bit 3 set: original file name present */ - while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ - } + /* Create the crc table */ + make_gunzip_crc_table(); - /* Discard file comment if any */ - if (flags & 0x10) { - /* bit 4 set: file comment present */ - while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ + /* decompress until the last block */ + do { + gunzip_hufts = 0; + r = inflate_block(&e); + if (r != 0) { + error_msg_and_die("inflate error %d", r); + return r; } - - /* Decompress */ - if (inflate(l_in_file, l_out_file) != 0) { - error_msg("invalid compressed data--format violated"); + if (gunzip_hufts > h) { + h = gunzip_hufts; } + } while (!e); - /* Get the crc and original length - * crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - fread(buf, 1, 8, l_in_file); - - /* Validate decompression - crc */ - if ((unsigned int) ((buf[0] | (buf[1] << 8)) | - ((buf[2] | (buf[3] << 8)) << 16)) != - (crc ^ 0xffffffffL)) { - error_msg("invalid compressed data--crc error"); - } - /* Validate decompression - size */ - if (((buf[4] | (buf[5] << 8)) | ((buf[6] | (buf[7] << 8)) << 16)) != - (unsigned long) bytes_out) { - error_msg("invalid compressed data--length error"); + /* write any buffered uncompressed data */ + flush_gunzip_window(); + free(gunzip_window); + + /* Cleanup */ + free(gunzip_crc_table); + + /* Store unused bytes in a global buffer so calling applets can access it */ + gunzip_in_buffer_count = 0; + if (gunzip_bk >= 8) { + /* Undo too much lookahead. The next read will be byte aligned + * so we can discard unused bits in the last meaningful byte. */ + gunzip_in_buffer[gunzip_in_buffer_count] = gunzip_bb & 0xff; + gunzip_in_buffer_count++; + gunzip_bb >>= 8; + gunzip_bk -= 8; } + /* return success */ return 0; } - -/* - * This needs access to global variables window and crc_table, so its not in its own file. - */ -extern void gz_close(int gunzip_pid) -{ - if (kill(gunzip_pid, SIGTERM) == -1) { - error_msg_and_die - ("*** Couldnt kill old gunzip process *** aborting"); - } - - if (waitpid(gunzip_pid, NULL, 0) == -1) { - printf("Couldnt wait ?"); - } - - free(window); - free(crc_table); -} diff --git a/archival/libunarchive/filter_accept_all.c b/archival/libunarchive/filter_accept_all.c new file mode 100644 index 000000000..0471ccef0 --- /dev/null +++ b/archival/libunarchive/filter_accept_all.c @@ -0,0 +1,10 @@ +#include <fnmatch.h> +#include <stdlib.h> +#include "unarchive.h" +/* + * Accept names that are in the accept list + */ +extern char filter_accept_all(const llist_t *accept_list, const llist_t *reject_list, const char *key) +{ + return(EXIT_SUCCESS); +} diff --git a/archival/libunarchive/filter_accept_list.c b/archival/libunarchive/filter_accept_list.c new file mode 100644 index 000000000..06b1dd3dd --- /dev/null +++ b/archival/libunarchive/filter_accept_list.c @@ -0,0 +1,16 @@ +#include <fnmatch.h> +#include <stdlib.h> +#include "unarchive.h" +/* + * Accept names that are in the accept list + */ +extern char filter_accept_list(const llist_t *accept_list, const llist_t *reject_list, const char *key) +{ + while (accept_list) { + if (fnmatch(accept_list->data, key, 0) == 0) { + return(EXIT_SUCCESS); + } + accept_list = accept_list->link; + } + return(EXIT_FAILURE); +} diff --git a/archival/libunarchive/filter_accept_reject_list.c b/archival/libunarchive/filter_accept_reject_list.c new file mode 100644 index 000000000..c893dfcfc --- /dev/null +++ b/archival/libunarchive/filter_accept_reject_list.c @@ -0,0 +1,34 @@ +#include <fnmatch.h> +#include <stdlib.h> +#include "unarchive.h" + +static char check_list(const llist_t *list, const char *filename) +{ + if (list) { + while (list) { + if (fnmatch(list->data, filename, 0) == 0) { + return(EXIT_SUCCESS); + } + list = list->link; + } + } + return(EXIT_FAILURE); +} + +/* + * Accept names that are in the accept list + */ +extern char filter_accept_reject_list(const llist_t *accept_list, const llist_t *reject_list, const char *key) +{ + /* Fail if an accept list was specified and the key wasnt in there */ + if ((accept_list) && (check_list(accept_list, key) == EXIT_FAILURE)) { + return(EXIT_FAILURE); + } + + /* If the key is in a reject list fail */ + if (check_list(reject_list, key) == EXIT_FAILURE) { + return(EXIT_FAILURE); + } + + return(EXIT_SUCCESS); +} diff --git a/archival/libunarchive/get_header_ar.c b/archival/libunarchive/get_header_ar.c index f172fa7c9..b7f2cfbcd 100644 --- a/archival/libunarchive/get_header_ar.c +++ b/archival/libunarchive/get_header_ar.c @@ -17,12 +17,13 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include "unarchive.h" #include "libbb.h" -file_header_t *get_header_ar(FILE *src_stream) +extern char get_header_ar(archive_handle_t *archive_handle) { - file_header_t *typed; + file_header_t *typed = archive_handle->file_header; union { char raw[60]; struct { @@ -35,72 +36,87 @@ file_header_t *get_header_ar(FILE *src_stream) char magic[2]; } formated; } ar; +#ifdef CONFIG_FEATURE_AR_LONG_FILENAMES static char *ar_long_names; + static unsigned int ar_long_name_size; +#endif - if (fread(ar.raw, 1, 60, src_stream) != 60) { - return(NULL); - } - archive_offset += 60; - /* align the headers based on the header magic */ - if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { - /* some version of ar, have an extra '\n' after each data entry, - * this puts the next header out by 1 */ - if (ar.formated.magic[1] != '`') { - error_msg("Invalid magic"); - return(NULL); - } - /* read the next char out of what would be the data section, - * if its a '\n' then it is a valid header offset by 1*/ - archive_offset++; - if (fgetc(src_stream) != '\n') { - error_msg("Invalid magic"); - return(NULL); + /* dont use xread as we want to handle the error ourself */ + if (read(archive_handle->src_fd, ar.raw, 60) != 60) { + /* End Of File */ + return(EXIT_FAILURE); } + + /* Some ar entries have a trailing '\n' after the previous data entry */ + if (ar.raw[0] == '\n') { /* fix up the header, we started reading 1 byte too early */ - /* raw_header[60] wont be '\n' as it should, but it doesnt matter */ memmove(ar.raw, &ar.raw[1], 59); + ar.raw[59] = xread_char(archive_handle->src_fd); + archive_handle->offset++; } + archive_handle->offset += 60; - typed = (file_header_t *) xcalloc(1, sizeof(file_header_t)); + /* align the headers based on the header magic */ + if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { + error_msg_and_die("Invalid ar header"); + } + + typed->mode = strtol(ar.formated.mode, NULL, 8); + typed->mtime = atoi(ar.formated.date); + typed->uid = atoi(ar.formated.uid); + typed->gid = atoi(ar.formated.gid); + typed->size = atoi(ar.formated.size); - typed->size = (size_t) atoi(ar.formated.size); /* long filenames have '/' as the first character */ if (ar.formated.name[0] == '/') { +#ifdef CONFIG_FEATURE_AR_LONG_FILENAMES if (ar.formated.name[1] == '/') { /* If the second char is a '/' then this entries data section * stores long filename for multiple entries, they are stored * in static variable long_names for use in future entries */ - ar_long_names = (char *) xrealloc(ar_long_names, typed->size); - fread(ar_long_names, 1, typed->size, src_stream); - archive_offset += typed->size; + ar_long_name_size = typed->size; + ar_long_names = xmalloc(ar_long_name_size); + xread_all(archive_handle->src_fd, ar_long_names, ar_long_name_size); + archive_handle->offset += ar_long_name_size; /* This ar entries data section only contained filenames for other records * they are stored in the static ar_long_names for future reference */ - return (get_header_ar(src_stream)); /* Return next header */ + return (get_header_ar(archive_handle)); /* Return next header */ } else if (ar.formated.name[1] == ' ') { /* This is the index of symbols in the file for compilers */ - seek_sub_file(src_stream, typed->size); - return (get_header_ar(src_stream)); /* Return next header */ + data_skip(archive_handle); + return (get_header_ar(archive_handle)); /* Return next header */ } else { /* The number after the '/' indicates the offset in the ar data section (saved in variable long_name) that conatains the real filename */ - if (!ar_long_names) { - error_msg("Cannot resolve long file name"); - return (NULL); + const unsigned int long_offset = atoi(&ar.formated.name[1]); + if (long_offset >= ar_long_name_size) { + error_msg_and_die("Cant resolve long filename"); } - typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1])); + typed->name = xstrdup(ar_long_names + long_offset); } +#else + error_msg_and_die("long filenames not supported"); +#endif } else { /* short filenames */ typed->name = xstrndup(ar.formated.name, 16); } - typed->name[strcspn(typed->name, " /")]='\0'; - /* convert the rest of the now valid char header to its typed struct */ - parse_mode(ar.formated.mode, &typed->mode); - typed->mtime = atoi(ar.formated.date); - typed->uid = atoi(ar.formated.uid); - typed->gid = atoi(ar.formated.gid); + typed->name[strcspn(typed->name, " /")] = '\0'; + + if (archive_handle->filter(archive_handle->accept, archive_handle->reject, typed->name) == EXIT_SUCCESS) { + archive_handle->action_header(typed); + if (archive_handle->sub_archive) { + while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS); + } else { + archive_handle->action_data(archive_handle); + } + } else { + data_skip(archive_handle); + } + + archive_handle->offset += typed->size + 1; - return(typed); + return(EXIT_SUCCESS); } diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index e6747b72f..2c8fc0aa0 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c @@ -20,8 +20,9 @@ #include "unarchive.h" #include "libbb.h" -file_header_t *get_header_tar(FILE * tar_stream) +extern char get_header_tar(archive_handle_t *archive_handle) { + file_header_t *file_header = archive_handle->file_header; union { unsigned char raw[512]; struct { @@ -44,20 +45,22 @@ file_header_t *get_header_tar(FILE * tar_stream) char padding[12]; /* 500-512 */ } formated; } tar; - file_header_t *tar_entry = NULL; long sum = 0; long i; - if (archive_offset % 512 != 0) { - seek_sub_file(tar_stream, 512 - (archive_offset % 512)); + /* Align header */ + archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 512); + + if (xread_all_eof(archive_handle->src_fd, tar.raw, 512) == 0) { + /* End of file */ + return(EXIT_FAILURE); } + archive_handle->offset += 512; - if (fread(tar.raw, 1, 512, tar_stream) != 512) { - /* Unfortunatly its common for tar files to have all sorts of - * trailing garbage, fail silently */ - return (NULL); + /* If there is no filename its an empty header */ + if (tar.formated.name[0] == 0) { + return(EXIT_SUCCESS); } - archive_offset += 512; /* Check header has valid magic, "ustar" is for the proper tar * 0's are for the old tar format @@ -66,100 +69,102 @@ file_header_t *get_header_tar(FILE * tar_stream) #ifdef CONFIG_FEATURE_TAR_OLD_FORMAT if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) #endif - return (NULL); - } - - /* If there is no filename its an empty header, skip it */ - if (tar.formated.name[0] == 0) { - return (NULL); + error_msg_and_die("Invalid tar magic"); } /* Do checksum on headers */ - for (i = 0; i < 148; i++) { + for (i = 0; i < 148 ; i++) { sum += tar.raw[i]; } sum += ' ' * 8; - for (i = 156; i < 512; i++) { + for (i = 156; i < 512 ; i++) { sum += tar.raw[i]; } if (sum != strtol(tar.formated.chksum, NULL, 8)) { error_msg("Invalid tar header checksum"); - return (NULL); + return(EXIT_FAILURE); } /* convert to type'ed variables */ - tar_entry = xcalloc(1, sizeof(file_header_t)); if (tar.formated.prefix[0] == 0) { - tar_entry->name = xstrdup(tar.formated.name); + file_header->name = strdup(tar.formated.name); } else { - tar_entry->name = - concat_path_file(tar.formated.prefix, tar.formated.name); + file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name); } - - tar_entry->mode = strtol(tar.formated.mode, NULL, 8); - tar_entry->uid = strtol(tar.formated.uid, NULL, 8); - tar_entry->gid = strtol(tar.formated.gid, NULL, 8); - tar_entry->size = strtol(tar.formated.size, NULL, 8); - tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); - tar_entry->link_name = - strlen(tar.formated.linkname) ? xstrdup(tar.formated.linkname) : NULL; - tar_entry->device = - (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) + + file_header->mode = strtol(tar.formated.mode, NULL, 8); + file_header->uid = strtol(tar.formated.uid, NULL, 8); + file_header->gid = strtol(tar.formated.gid, NULL, 8); + file_header->size = strtol(tar.formated.size, NULL, 8); + file_header->mtime = strtol(tar.formated.mtime, NULL, 8); + file_header->link_name = (tar.formated.linkname[0] != '\0') ? + xstrdup(tar.formated.linkname) : NULL; + file_header->device = (dev_t) ((strtol(tar.formated.devmajor, NULL, 8) << 8) + strtol(tar.formated.devminor, NULL, 8)); #if defined CONFIG_FEATURE_TAR_OLD_FORMAT || defined CONFIG_FEATURE_GNUTAR_LONG_FILENAME + /* Fix mode, used by the old format */ switch (tar.formated.typeflag) { # ifdef CONFIG_FEATURE_TAR_OLD_FORMAT case 0: - tar_entry->mode |= S_IFREG; + file_header->mode |= S_IFREG; break; case 1: - error_msg("internal hard link not handled\n"); + error_msg("Internal hard link not supported"); break; case 2: - tar_entry->mode |= S_IFLNK; + file_header->mode |= S_IFLNK; break; case 3: - tar_entry->mode |= S_IFCHR; + file_header->mode |= S_IFCHR; break; case 4: - tar_entry->mode |= S_IFBLK; + file_header->mode |= S_IFBLK; break; case 5: - tar_entry->mode |= S_IFDIR; + file_header->mode |= S_IFDIR; break; case 6: - tar_entry->mode |= S_IFIFO; + file_header->mode |= S_IFIFO; break; # endif # ifdef CONFIG_FEATURE_GNUTAR_LONG_FILENAME case 'L': { char *longname; - longname = xmalloc(tar_entry->size + 1); - fread(longname, 1, tar_entry->size, tar_stream); - archive_offset += tar_entry->size; - longname[tar_entry->size] = '\0'; + longname = xmalloc(file_header->size + 1); + xread_all(archive_handle->src_fd, longname, file_header->size); + longname[file_header->size] = '\0'; + archive_handle->offset += file_header->size; - tar_entry = get_header_tar(tar_stream); - tar_entry->name = longname; + get_header_tar(archive_handle); + file_header->name = longname; break; } case 'K': { - char *longname; + char *linkname; - longname = xmalloc(tar_entry->size + 1); - fread(longname, 1, tar_entry->size, tar_stream); - archive_offset += tar_entry->size; - longname[tar_entry->size] = '\0'; + linkname = xmalloc(file_header->size + 1); + xread_all(archive_handle->src_fd, linkname, file_header->size); + linkname[file_header->size] = '\0'; + archive_handle->offset += file_header->size; - tar_entry = get_header_tar(tar_stream); - tar_entry->link_name = longname; + get_header_tar(archive_handle); + file_header->name = linkname; break; } # endif } #endif - return (tar_entry); + if (archive_handle->filter(archive_handle->accept, archive_handle->reject, archive_handle->file_header->name) == EXIT_SUCCESS) { + archive_handle->action_header(archive_handle->file_header); + archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; + archive_handle->action_data(archive_handle); + } else { + data_skip(archive_handle); + } + archive_handle->offset += file_header->size; + + return(EXIT_SUCCESS); } + diff --git a/archival/libunarchive/get_header_tar_gz.c b/archival/libunarchive/get_header_tar_gz.c new file mode 100644 index 000000000..c06beac9d --- /dev/null +++ b/archival/libunarchive/get_header_tar_gz.c @@ -0,0 +1,73 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <sys/types.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "libbb.h" +#include "unarchive.h" + +extern char get_header_tar_gz(archive_handle_t *archive_handle) +{ + int fd_pipe[2]; + int pid; + + check_header_gzip(archive_handle->src_fd); + + if (pipe(fd_pipe) != 0) { + error_msg_and_die("Can't create pipe\n"); + } + + pid = fork(); + if (pid == -1) { + error_msg_and_die("Fork failed\n"); + } + + if (pid == 0) { + /* child process */ + close(fd_pipe[0]); /* We don't wan't to read from the pipe */ + inflate(archive_handle->src_fd, fd_pipe[1]); + check_trailer_gzip(archive_handle->src_fd); + close(fd_pipe[1]); /* Send EOF */ + exit(0); + /* notreached */ + } + /* parent process */ + close(fd_pipe[1]); /* Don't want to write down the pipe */ + close(archive_handle->src_fd); + + archive_handle->src_fd = fd_pipe[0]; + + while (get_header_tar(archive_handle) == EXIT_SUCCESS); + + if (kill(pid, SIGTERM) == -1) { + error_msg_and_die("Couldnt kill gunzip process"); + } + + /* I dont think this is needed */ +#if 0 + if (waitpid(pid, NULL, 0) == -1) { + error_msg("Couldnt wait ?"); + } +#endif + + /* Can only do one file at a time */ + return(EXIT_FAILURE); +} + diff --git a/archival/libunarchive/header_list.c b/archival/libunarchive/header_list.c new file mode 100644 index 000000000..5849a762e --- /dev/null +++ b/archival/libunarchive/header_list.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include "unarchive.h" + +extern void header_list(const file_header_t *file_header) +{ + puts(file_header->name); +} diff --git a/archival/libunarchive/header_skip.c b/archival/libunarchive/header_skip.c new file mode 100644 index 000000000..4430178f8 --- /dev/null +++ b/archival/libunarchive/header_skip.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include "unarchive.h" + +extern void header_skip(const file_header_t *file_header) +{ + return; +} diff --git a/archival/libunarchive/header_verbose_list.c b/archival/libunarchive/header_verbose_list.c new file mode 100644 index 000000000..ff7b3bca2 --- /dev/null +++ b/archival/libunarchive/header_verbose_list.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "libbb.h" +#include "unarchive.h" + +extern void header_verbose_list(const file_header_t *file_header) +{ + struct tm *mtime = localtime(&file_header->mtime); + + printf("%s %d/%d%10u %4u-%02u-%02u %02u:%02u:%02u %s", + mode_string(file_header->mode), + file_header->uid, + file_header->gid, + (unsigned int) file_header->size, + 1900 + mtime->tm_year, + 1 + mtime->tm_mon, + mtime->tm_mday, + mtime->tm_hour, + mtime->tm_min, + mtime->tm_sec, + file_header->name); + + if (file_header->link_name) { + printf(" -> %s", file_header->link_name); + } + /* putchar isnt used anywhere else i dont think */ + puts(""); +} diff --git a/archival/libunarchive/init_handle.c b/archival/libunarchive/init_handle.c new file mode 100644 index 000000000..12d9e7183 --- /dev/null +++ b/archival/libunarchive/init_handle.c @@ -0,0 +1,18 @@ +#include <string.h> +#include "libbb.h" +#include "unarchive.h" + +archive_handle_t *init_handle(void) +{ + archive_handle_t *archive_handle; + + /* Initialise default values */ + archive_handle = xmalloc(sizeof(archive_handle_t)); + memset(archive_handle, 0, sizeof(archive_handle_t)); + archive_handle->file_header = xmalloc(sizeof(file_header_t)); + archive_handle->action_header = header_skip; + archive_handle->action_data = data_skip; + archive_handle->filter = filter_accept_all; + + return(archive_handle); +} diff --git a/archival/libunarchive/seek_sub_file.c b/archival/libunarchive/seek_sub_file.c index 7523a52ab..733bb36a9 100644 --- a/archival/libunarchive/seek_sub_file.c +++ b/archival/libunarchive/seek_sub_file.c @@ -14,23 +14,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <stdio.h> +#include <sys/types.h> #include <errno.h> -#include <stdlib.h> #include <unistd.h> +#include <stdlib.h> +#include "unarchive.h" +#include "libbb.h" -off_t archive_offset; - -void seek_sub_file(FILE *src_stream, const int count) +extern void seek_sub_file(const int src_fd, const unsigned int amount) { - /* Try to fseek as faster */ - archive_offset += count; - if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) { - int i; - for (i = 0; i < count; i++) { - fgetc(src_stream); + if ((lseek(src_fd, amount, SEEK_CUR) == -1) && (errno == ESPIPE)) { + unsigned int i; + for (i = 0; i < amount; i++) { + xread_char(src_fd); } } - return; } - diff --git a/archival/libunarchive/unpack_ar_archive.c b/archival/libunarchive/unpack_ar_archive.c new file mode 100644 index 000000000..923b8a068 --- /dev/null +++ b/archival/libunarchive/unpack_ar_archive.c @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include "unarchive.h" +#include "busybox.h" + +extern void unpack_ar_archive(archive_handle_t *ar_archive) +{ + char magic[7]; + + xread_all(ar_archive->src_fd, magic, 7); + if (strncmp(magic, "!<arch>", 7) != 0) { + error_msg_and_die("Invalid ar magic"); + } + ar_archive->offset += 7; + + while (get_header_ar(ar_archive) == EXIT_SUCCESS); +} diff --git a/archival/libunarchive/unzip.c b/archival/libunarchive/unzip.c index d84067068..20bf88f55 100644 --- a/archival/libunarchive/unzip.c +++ b/archival/libunarchive/unzip.c @@ -65,114 +65,126 @@ static char *license_msg[] = { #include <signal.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <fcntl.h> #include "config.h" -#include "libbb.h" +#include "busybox.h" +#include "unarchive.h" -#ifdef CONFIG_FEATURE_UNCOMPRESS -int uncompress(FILE * in, FILE * out); -#endif - -static FILE *in_file, *out_file; +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ + } v; +} huft_t; -/* these are freed by gz_close */ -static unsigned char *window; -static unsigned long *crc_table; +static int gunzip_src_fd; +static int gunzip_dst_fd; +unsigned int gunzip_bytes_out; /* number of output bytes */ +static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ -static unsigned long crc; /* shift register contents */ +/* This is used to sanify any unused bits from the bitbuffer + * so they arent skipped when reading trailers (trailing headers) */ +unsigned char gunzip_in_buffer_count; +unsigned char *gunzip_in_buffer; -/* Return codes from gzip */ -#define ERROR 1 +/* gunzip_window size--must be a power of two, and + * at least 32K for zip's deflate method */ +static const int gunzip_wsize = 0x8000; -/* - * window size--must be a power of two, and - * at least 32K for zip's deflate method - */ -#define WSIZE 0x8000 +static unsigned char *gunzip_window; +static unsigned int *gunzip_crc_table; +unsigned int gunzip_crc; /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ #define BMAX 16 /* maximum bit length of any code (16 for explode) */ #define N_MAX 288 /* maximum number of codes in any set */ -static long bytes_out; /* number of output bytes */ -static unsigned long outcnt; /* bytes in output buffer */ - -static unsigned hufts; /* track memory usage */ -static unsigned long bb; /* bit buffer */ -static unsigned bk; /* bits in bit buffer */ - -typedef struct huft_s { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_s *t; /* pointer to next level of table */ - } v; -} huft_t; +static unsigned int gunzip_hufts; /* track memory usage */ +static unsigned int gunzip_bb; /* bit buffer */ +static unsigned char gunzip_bk; /* bits in bit buffer */ static const unsigned short mask_bits[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; -/* static int error_number = 0; */ -/* ======================================================================== - * Signal and error handler. - */ +/* Copy lengths for literal codes 257..285 */ +static const unsigned short cplens[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +}; + +/* note: see note #13 above about the 258 in this list. */ +/* Extra bits for literal codes 257..285 */ +static const unsigned char cplext[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, + 5, 5, 5, 0, 99, 99 +}; /* 99==invalid */ + +/* Copy offsets for distance codes 0..29 */ +static const unsigned short cpdist[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +}; + +/* Extra bits for distance codes */ +static const unsigned char cpdext[] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13 +}; + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* Order of the bit length code lengths */ +static const unsigned char border[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) +{ + while (*current < required) { + bitbuffer |= ((unsigned int) xread_char(gunzip_src_fd)) << *current; + *current += 8; + } + + return(bitbuffer); +} static void abort_gzip(void) { error_msg("gzip aborted\n"); - exit(ERROR); + exit(-1); } -static void make_crc_table(void) +static void make_gunzip_crc_table(void) { - const unsigned long poly = 0xedb88320; /* polynomial exclusive-or pattern */ + const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */ unsigned short i; /* counter for all possible eight bit values */ /* initial shift register value */ - crc = 0xffffffffL; - crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); + gunzip_crc = 0xffffffffL; + gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int)); /* Compute and print table of CRC's, five per line */ for (i = 0; i < 256; i++) { - unsigned long table_entry; /* crc shift register */ - char k; /* byte being shifted into crc apparatus */ + unsigned int table_entry; /* crc shift register */ + unsigned char k; /* byte being shifted into crc apparatus */ table_entry = i; /* The idea to initialize the register with the byte instead of * zero was stolen from Haruhiko Okumura's ar002 */ for (k = 8; k; k--) { - table_entry = - table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> - 1; - } - crc_table[i] = table_entry; + if (table_entry & 1) { + table_entry = (table_entry >> 1) ^ poly; + } else { + table_entry >>= 1; } -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void flush_window(void) -{ - int n; - - if (outcnt == 0) - return; - - for (n = 0; n < outcnt; n++) { - crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); } - - if (fwrite(window, 1, outcnt, out_file) != outcnt) { - error_msg_and_die("Couldnt write"); + gunzip_crc_table[i] = table_entry; } - bytes_out += (unsigned long) outcnt; - outcnt = 0; } /* @@ -183,7 +195,8 @@ static void flush_window(void) */ static int huft_free(huft_t * t) { - huft_t *p, *q; + huft_t *p; + huft_t *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; @@ -195,8 +208,6 @@ static int huft_free(huft_t * t) return 0; } -typedef unsigned char extra_bits_t; - /* Given a list of code lengths and a maximum table size, make a set of * tables to decode that set of codes. Return zero on success, one if * the given code set is incomplete (the tables are still built in this @@ -213,7 +224,7 @@ typedef unsigned char extra_bits_t; */ static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, const unsigned short *d, - const extra_bits_t * e, huft_t ** t, int *m) + const unsigned char *e, huft_t ** t, int *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -251,26 +262,35 @@ static int huft_build(unsigned int *b, const unsigned int n, /* Find minimum and maximum length, bound *m by those */ l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) + for (j = 1; j <= BMAX; j++) { + if (c[j]) { break; + } + } k = j; /* minimum code length */ - if ((unsigned) l < j) + if ((unsigned) l < j) { l = j; - for (i = BMAX; i; i--) - if (c[i]) + } + for (i = BMAX; i; i--) { + if (c[i]) { break; + } + } g = i; /* maximum code length */ - if ((unsigned) l > i) + if ((unsigned) l > i) { l = i; + } *m = l; /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) + for (y = 1 << j; j < i; j++, y <<= 1) { + if ((y -= c[j]) < 0) { return 2; /* bad input: more codes than bits */ - if ((y -= c[i]) < 0) + } + } + if ((y -= c[i]) < 0) { return 2; + } c[i] += y; /* Generate starting offsets into the value table for each length */ @@ -285,8 +305,9 @@ static int huft_build(unsigned int *b, const unsigned int n, p = b; i = 0; do { - if ((j = *p++) != 0) + if ((j = *p++) != 0) { v[x[j]++] = i; + } } while (++i < n); /* Generate the Huffman codes and for each, make the table entries */ @@ -314,8 +335,9 @@ static int huft_build(unsigned int *b, const unsigned int n, f -= a + 1; /* deduct codes from patterns left */ xp = c + k; while (++j < z) { /* try smaller tables up to z bits */ - if ((f <<= 1) <= *++xp) + if ((f <<= 1) <= *++xp) { break; /* enough codes to use up j bits */ + } f -= *xp; /* else deduct codes from patterns */ } } @@ -324,7 +346,7 @@ static int huft_build(unsigned int *b, const unsigned int n, /* allocate and link in new table */ q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); - hufts += z + 1; /* track memory usage */ + gunzip_hufts += z + 1; /* track memory usage */ *t = q + 1; /* link to list for huft_free() */ *(t = &(q->v.t)) = NULL; u[h] = ++q; /* table starts after link */ @@ -342,9 +364,9 @@ static int huft_build(unsigned int *b, const unsigned int n, /* set up table entry in r */ r.b = (unsigned char) (k - w); - if (p >= v + n) + if (p >= v + n) { r.e = 99; /* out of values--invalid code */ - else if (*p < s) { + } else if (*p < s) { r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ r.v.n = (unsigned short) (*p); /* simple code is just the value */ p++; /* one compiler does not like *p++ */ @@ -355,12 +377,14 @@ static int huft_build(unsigned int *b, const unsigned int n, /* fill code-like entries with r */ f = 1 << (k - w); - for (j = i >> w; j < z; j += f) + for (j = i >> w; j < z; j += f) { q[j] = r; + } /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) + for (j = 1 << (k - 1); i & j; j >>= 1) { i ^= j; + } i ^= j; /* backup over finished tables */ @@ -374,6 +398,25 @@ static int huft_build(unsigned int *b, const unsigned int n, return y != 0 && g != 1; } +/* =========================================================================== + * Write the output gunzip_window gunzip_window[0..gunzip_outbuf_count-1] and update crc and gunzip_bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_gunzip_window(void) +{ + int n; + + for (n = 0; n < gunzip_outbuf_count; n++) { + gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); + } + + if (write(gunzip_dst_fd, gunzip_window, gunzip_outbuf_count) != gunzip_outbuf_count) { + error_msg_and_die("Couldnt write"); + } + gunzip_bytes_out += gunzip_outbuf_count; + gunzip_outbuf_count = 0; +} + /* * inflate (decompress) the codes in a deflated (compressed) block. * Return an error code or zero if it all goes ok. @@ -381,32 +424,26 @@ static int huft_build(unsigned int *b, const unsigned int n, * tl, td: literal/length and distance decoder tables * bl, bd: number of bits decoded by tl[] and td[] */ -static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) +static int inflate_codes(huft_t * tl, huft_t * td, const unsigned int bl, const unsigned int bd) { - register unsigned long e; /* table entry flag/number of extra bits */ - unsigned long n, d; /* length and index for copy */ - unsigned long w; /* current window position */ + unsigned int e; /* table entry flag/number of extra bits */ + unsigned int n, d; /* length and index for copy */ + unsigned int w; /* current gunzip_window position */ huft_t *t; /* pointer to table entry */ - unsigned ml, md; /* masks for bl and bd bits */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - register int input_char; + unsigned int ml, md; /* masks for bl and bd bits */ + unsigned int b; /* bit buffer */ + unsigned int k; /* number of bits in bit buffer */ /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = outcnt; /* initialize window position */ + b = gunzip_bb; /* initialize bit buffer */ + k = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ /* inflate the coded data */ ml = mask_bits[bl]; /* precompute masks for speed */ md = mask_bits[bd]; - for (;;) { /* do until end of block */ - while (k < (unsigned) bl) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + while (1) { /* do until end of block */ + b = fill_bitbuffer(b, &k, bl); if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) do { if (e == 99) { @@ -415,20 +452,16 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) b >>= t->b; k -= t->b; e -= 16; - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); b >>= t->b; k -= t->b; if (e == 16) { /* then it's a literal */ - window[w++] = (unsigned char) t->v.n; - if (w == WSIZE) { - outcnt = (w), flush_window(); + gunzip_window[w++] = (unsigned char) t->v.n; + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + flush_gunzip_window(); w = 0; } } else { /* it's an EOB or a length */ @@ -439,24 +472,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) } /* get length of block to copy */ - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); n = t->v.n + ((unsigned) b & mask_bits[e]); b >>= e; k -= e; /* decode distance of block to copy */ - while (k < (unsigned) bd) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } - + b = fill_bitbuffer(b, &k, bd); if ((e = (t = td + ((unsigned) b & md))->e) > 16) do { if (e == 99) @@ -464,23 +486,13 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) b >>= t->b; k -= t->b; e -= 16; - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); b >>= t->b; k -= t->b; - while (k < e) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, e); d = w - t->v.n - ((unsigned) b & mask_bits[e]); b >>= e; k -= e; @@ -489,60 +501,38 @@ static int inflate_codes(huft_t * tl, huft_t * td, int bl, int bd) do { n -= (e = (e = - WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); -#if !defined(NOMEMCPY) && !defined(DEBUG) + gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); + /* copy to new buffer to prevent possible overwrite */ if (w - d >= e) { /* (this test assumes unsigned comparison) */ - memcpy(window + w, window + d, e); + memcpy(gunzip_window + w, gunzip_window + d, e); w += e; d += e; - } else /* do it slow to avoid memcpy() overlap */ -#endif /* !NOMEMCPY */ + } else { + /* do it slow to avoid memcpy() overlap */ + /* !NOMEMCPY */ do { - window[w++] = window[d++]; + gunzip_window[w++] = gunzip_window[d++]; } while (--e); - if (w == WSIZE) { - outcnt = (w), flush_window(); + } + if (w == gunzip_wsize) { + gunzip_outbuf_count = (w); + flush_gunzip_window(); w = 0; } + } while (n); } } /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = b; /* restore global bit buffer */ + gunzip_bk = k; /* done */ return 0; } -static const unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 -}; - -/* note: see note #13 above about the 258 in this list. */ -static const extra_bits_t cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 -}; /* 99==invalid */ -static const unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 -}; -static const extra_bits_t cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 -}; - -/* Tables for deflate from PKZIP's appnote.txt. */ -static const extra_bits_t border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; - /* * decompress an inflated block * e: last block flag @@ -552,53 +542,43 @@ static const extra_bits_t border[] = { /* Order of the bit length code lengths * static int inflate_block(int *e) { unsigned t; /* block type */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - int input_char; + register unsigned int b; /* bit buffer */ + unsigned int k; /* number of bits in bit buffer */ /* make local bit buffer */ - b = bb; - k = bk; + + b = gunzip_bb; + k = gunzip_bk; /* read in last block bit */ - while (k < 1) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, 1); *e = (int) b & 1; b >>= 1; k -= 1; /* read in block type */ - while (k < 2) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b |= ((unsigned long)input_char) << k; - k += 8; - } + b = fill_bitbuffer(b, &k, 2); t = (unsigned) b & 3; b >>= 2; k -= 2; /* restore the global bit buffer */ - bb = b; - bk = k; + gunzip_bb = b; + gunzip_bk = k; /* inflate that block type */ switch (t) { case 0: /* Inflate stored */ { - unsigned long n; /* number of bytes in block */ - unsigned long w; /* current window position */ - register unsigned long b_stored; /* bit buffer */ - register unsigned long k_stored; /* number of bits in bit buffer */ + unsigned int n; /* number of bytes in block */ + unsigned int w; /* current gunzip_window position */ + unsigned int b_stored; /* bit buffer */ + unsigned int k_stored; /* number of bits in bit buffer */ /* make local copies of globals */ - b_stored = bb; /* initialize bit buffer */ - k_stored = bk; - w = outcnt; /* initialize window position */ + b_stored = gunzip_bb; /* initialize bit buffer */ + k_stored = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ /* go to byte boundary */ n = k_stored & 7; @@ -606,21 +586,12 @@ static int inflate_block(int *e) k_stored -= n; /* get the length and its complement */ - while (k_stored < 16) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_stored |= ((unsigned long)input_char) << k_stored; - k_stored += 8; - } + b_stored = fill_bitbuffer(b_stored, &k_stored, 16); n = ((unsigned) b_stored & 0xffff); b_stored >>= 16; k_stored -= 16; - while (k_stored < 16) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_stored |= ((unsigned long)input_char) << k_stored; - k_stored += 8; - } + + b_stored = fill_bitbuffer(b_stored, &k_stored, 16); if (n != (unsigned) ((~b_stored) & 0xffff)) { return 1; /* error in compressed data */ } @@ -629,15 +600,11 @@ static int inflate_block(int *e) /* read and output the compressed data */ while (n--) { - while (k_stored < 8) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_stored |= ((unsigned long)input_char) << k_stored; - k_stored += 8; - } - window[w++] = (unsigned char) b_stored; - if (w == (unsigned long) WSIZE) { - outcnt = (w), flush_window(); + b_stored = fill_bitbuffer(b_stored, &k_stored, 8); + gunzip_window[w++] = (unsigned char) b_stored; + if (w == (unsigned int) gunzip_wsize) { + gunzip_outbuf_count = (w); + flush_gunzip_window(); w = 0; } b_stored >>= 8; @@ -645,9 +612,9 @@ static int inflate_block(int *e) } /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b_stored; /* restore global bit buffer */ - bk = k_stored; + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = b_stored; /* restore global bit buffer */ + gunzip_bk = k_stored; return 0; } case 1: /* Inflate fixed @@ -659,8 +626,8 @@ static int inflate_block(int *e) int i; /* temporary variable */ huft_t *tl; /* literal/length code table */ huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ + unsigned int bl; /* lookup bits for tl */ + unsigned int bd; /* lookup bits for td */ unsigned int l[288]; /* length list for huft_build */ /* set up literal table */ @@ -692,8 +659,9 @@ static int inflate_block(int *e) } /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) + if (inflate_codes(tl, td, bl, bd)) { return 1; + } /* free the decoding tables, return */ huft_free(tl); @@ -705,53 +673,41 @@ static int inflate_block(int *e) const int dbits = 6; /* bits in base distance lookup table */ const int lbits = 9; /* bits in base literal/length lookup table */ - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ huft_t *tl; /* literal/length code table */ huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - register unsigned long b_dynamic; /* bit buffer */ - register unsigned k_dynamic; /* number of bits in bit buffer */ + unsigned int i; /* temporary variables */ + unsigned int j; + unsigned int l; /* last length */ + unsigned int m; /* mask for bit lengths table */ + unsigned int n; /* number of lengths to get */ + unsigned int bl; /* lookup bits for tl */ + unsigned int bd; /* lookup bits for td */ + unsigned int nb; /* number of bit length codes */ + unsigned int nl; /* number of literal/length codes */ + unsigned int nd; /* number of distance codes */ + + unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned int b_dynamic; /* bit buffer */ + unsigned int k_dynamic; /* number of bits in bit buffer */ /* make local bit buffer */ - b_dynamic = bb; - k_dynamic = bk; + b_dynamic = gunzip_bb; + k_dynamic = gunzip_bk; /* read in table lengths */ - while (k_dynamic < 5) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); + nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic >>= 5; k_dynamic -= 5; - while (k_dynamic < 5) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); + nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic >>= 5; k_dynamic -= 5; - while (k_dynamic < 4) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); + nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic >>= 4; k_dynamic -= 4; if (nl > 286 || nd > 30) { @@ -760,13 +716,8 @@ static int inflate_block(int *e) /* read in bit-length-code lengths */ for (j = 0; j < nb; j++) { - while (k_dynamic < 3) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); + ll[border[j]] = (unsigned int) b_dynamic & 7; b_dynamic >>= 3; k_dynamic -= 3; } @@ -776,7 +727,8 @@ static int inflate_block(int *e) /* build decoding table for trees--single level, 7 bit lookup */ bl = 7; - if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { + i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl); + if (i != 0) { if (i == 1) { huft_free(tl); } @@ -787,46 +739,31 @@ static int inflate_block(int *e) n = nl + nd; m = mask_bits[bl]; i = l = 0; - while ((unsigned) i < n) { - while (k_dynamic < (unsigned) bl) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = (td = tl + ((unsigned) b_dynamic & m))->b; + while ((unsigned int) i < n) { + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); + j = (td = tl + ((unsigned int) b_dynamic & m))->b; b_dynamic >>= j; k_dynamic -= j; j = td->v.n; if (j < 16) { /* length of code in bits (0..15) */ ll[i++] = l = j; /* save last length in l */ } else if (j == 16) { /* repeat last length 3 to 6 times */ - while (k_dynamic < 2) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); + j = 3 + ((unsigned int) b_dynamic & 3); b_dynamic >>= 2; k_dynamic -= 2; - if ((unsigned) i + j > n) { + if ((unsigned int) i + j > n) { return 1; } while (j--) { ll[i++] = l; } } else if (j == 17) { /* 3 to 10 zero length codes */ - while (k_dynamic < 3) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); + j = 3 + ((unsigned int) b_dynamic & 7); b_dynamic >>= 3; k_dynamic -= 3; - if ((unsigned) i + j > n) { + if ((unsigned int) i + j > n) { return 1; } while (j--) { @@ -834,16 +771,11 @@ static int inflate_block(int *e) } l = 0; } else { /* j == 18: 11 to 138 zero length codes */ - while (k_dynamic < 7) { - input_char = fgetc(in_file); - if (input_char == EOF) return 1; - b_dynamic |= ((unsigned long)input_char) << k_dynamic; - k_dynamic += 8; - } - j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); + j = 11 + ((unsigned int) b_dynamic & 0x7f); b_dynamic >>= 7; k_dynamic -= 7; - if ((unsigned) i + j > n) { + if ((unsigned int) i + j > n) { return 1; } while (j--) { @@ -857,22 +789,24 @@ static int inflate_block(int *e) huft_free(tl); /* restore the global bit buffer */ - bb = b_dynamic; - bk = k_dynamic; + gunzip_bb = b_dynamic; + gunzip_bk = k_dynamic; /* build the decoding tables for literal/length and distance codes */ bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { if (i == 1) { - error_msg("Incomplete literal tree"); + error_msg_and_die("Incomplete literal tree"); huft_free(tl); } return i; /* incomplete code set */ } + bd = dbits; if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { if (i == 1) { - error_msg("incomplete distance tree"); + error_msg_and_die("incomplete distance tree"); huft_free(td); } huft_free(tl); @@ -880,8 +814,9 @@ static int inflate_block(int *e) } /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) + if (inflate_codes(tl, td, bl, bd)) { return 1; + } /* free the decoding tables, return */ huft_free(tl); @@ -890,6 +825,7 @@ static int inflate_block(int *e) } default: /* bad block type */ + error_msg("bad block type %d\n", t); return 2; } } @@ -897,72 +833,24 @@ static int inflate_block(int *e) /* * decompress an inflated entry * - * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr + * GLOBAL VARIABLES: gunzip_outbuf_count, bk, gunzip_bb, hufts, inptr */ -extern int inflate(FILE * in, FILE * out) +extern int inflate(int in, int out) { + typedef void (*sig_type) (int); int e; /* last block flag */ int r; /* result code */ unsigned h = 0; /* maximum struct huft's malloc'ed */ - /* initialize window, bit buffer */ - outcnt = 0; - bk = 0; - bb = 0; - - in_file = in; - out_file = out; - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t) (((2L * WSIZE) + 1L) * sizeof(unsigned char))); - bytes_out = 0L; + gunzip_window = xmalloc(0x8000); + gunzip_outbuf_count = 0; + gunzip_bytes_out = 0; - /* Create the crc table */ - make_crc_table(); + gunzip_src_fd = in; + gunzip_dst_fd = out; - /* decompress until the last block */ - do { - hufts = 0; - if ((r = inflate_block(&e)) != 0) { - return r; - } - if (hufts > h) { - h = hufts; - } - } while (!e); - - /* Undo too much lookahead. The next read will be byte aligned so we - * can discard unused bits in the last meaningful byte. - */ - while (bk >= 8) { - bk -= 8; - ungetc((bb << bk), in_file); - } - - /* flush out window */ - flush_window(); - free(window); - free(crc_table); - - /* return success */ - return 0; -} - -/* =========================================================================== - * Unzip in to out. This routine works on gzip files only. - * - * IN assertions: the buffer inbuf contains already the beginning of - * the compressed data, from offsets inptr to insize-1 included. - * The magic header has already been checked. The output buffer is cleared. - * in, out: input and output file descriptors - */ -extern int unzip(FILE * l_in_file, FILE * l_out_file) -{ - unsigned char buf[8]; /* extended local header */ - unsigned char flags; /* compression flags */ - typedef void (*sig_type) (int); - unsigned short i; - unsigned char magic[2]; + gunzip_in_buffer = malloc(8); if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, (sig_type) abort_gzip); @@ -973,97 +861,44 @@ extern int unzip(FILE * l_in_file, FILE * l_out_file) } #endif - magic[0] = fgetc(l_in_file); - magic[1] = fgetc(l_in_file); - -#ifdef CONFIG_FEATURE_UNCOMPRESS - /* Magic header for compress files, 1F 9d = \037\235 */ - if ((magic[0] == 0x1F) && (magic[1] == 0x9d)) { - return uncompress(l_in_file, l_out_file); - } -#endif - - /* Magic header for gzip files, 1F 8B = \037\213 */ - if ((magic[0] != 0x1F) || (magic[1] != 0x8b)) { - error_msg("Invalid gzip magic"); - return EXIT_FAILURE; - } - - /* Check the compression method */ - if (fgetc(l_in_file) != 8) /* also catches EOF */ { - error_msg("Unknown compression method"); - return (-1); - } - - flags = (unsigned char) fgetc(l_in_file); - - /* Ignore time stamp(4), extra flags(1), OS type(1) */ - for (i = 0; i < 6; i++) { - fgetc(l_in_file); - } + /* initialize gunzip_window, bit buffer */ + gunzip_bk = 0; + gunzip_bb = 0; - if (flags & 0x04) { - /* bit 2 set: extra field present */ - const unsigned short extra = - fgetc(l_in_file) + (fgetc(l_in_file) << 8); - if (feof(in_file)) return 1; - for (i = 0; i < extra; i++) { - fgetc(l_in_file); - } - } - - /* Discard original name if any */ - if (flags & 0x08) { - /* bit 3 set: original file name present */ - while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ - } + /* Create the crc table */ + make_gunzip_crc_table(); - /* Discard file comment if any */ - if (flags & 0x10) { - /* bit 4 set: file comment present */ - while (fgetc(l_in_file) != 0 && !feof(l_in_file)); /* null */ + /* decompress until the last block */ + do { + gunzip_hufts = 0; + r = inflate_block(&e); + if (r != 0) { + error_msg_and_die("inflate error %d", r); + return r; } - - /* Decompress */ - if (inflate(l_in_file, l_out_file) != 0) { - error_msg("invalid compressed data--format violated"); + if (gunzip_hufts > h) { + h = gunzip_hufts; } + } while (!e); - /* Get the crc and original length - * crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - fread(buf, 1, 8, l_in_file); - - /* Validate decompression - crc */ - if ((unsigned int) ((buf[0] | (buf[1] << 8)) | - ((buf[2] | (buf[3] << 8)) << 16)) != - (crc ^ 0xffffffffL)) { - error_msg("invalid compressed data--crc error"); - } - /* Validate decompression - size */ - if (((buf[4] | (buf[5] << 8)) | ((buf[6] | (buf[7] << 8)) << 16)) != - (unsigned long) bytes_out) { - error_msg("invalid compressed data--length error"); + /* write any buffered uncompressed data */ + flush_gunzip_window(); + free(gunzip_window); + + /* Cleanup */ + free(gunzip_crc_table); + + /* Store unused bytes in a global buffer so calling applets can access it */ + gunzip_in_buffer_count = 0; + if (gunzip_bk >= 8) { + /* Undo too much lookahead. The next read will be byte aligned + * so we can discard unused bits in the last meaningful byte. */ + gunzip_in_buffer[gunzip_in_buffer_count] = gunzip_bb & 0xff; + gunzip_in_buffer_count++; + gunzip_bb >>= 8; + gunzip_bk -= 8; } + /* return success */ return 0; } - -/* - * This needs access to global variables window and crc_table, so its not in its own file. - */ -extern void gz_close(int gunzip_pid) -{ - if (kill(gunzip_pid, SIGTERM) == -1) { - error_msg_and_die - ("*** Couldnt kill old gunzip process *** aborting"); - } - - if (waitpid(gunzip_pid, NULL, 0) == -1) { - printf("Couldnt wait ?"); - } - - free(window); - free(crc_table); -} |