From 87ac7028e01cdc4f504ea558a6ae3d086ed1bf2b Mon Sep 17 00:00:00 2001 From: Glenn L McGrath Date: Wed, 2 Jan 2002 13:52:26 +0000 Subject: unzip applet by Laurence Anderson ---------------------------------------------------------------------- --- archival/libunarchive/Makefile | 8 ++- archival/libunarchive/decompress_unzip.c | 48 +++++++------- archival/libunarchive/get_header_zip.c | 110 +++++++++++++++++++++++++++++++ archival/libunarchive/unarchive.c | 3 +- archival/libunarchive/unzip.c | 48 +++++++------- 5 files changed, 164 insertions(+), 53 deletions(-) create mode 100644 archival/libunarchive/get_header_zip.c (limited to 'archival/libunarchive') diff --git a/archival/libunarchive/Makefile b/archival/libunarchive/Makefile index 0c7219d..a8409a4 100644 --- a/archival/libunarchive/Makefile +++ b/archival/libunarchive/Makefile @@ -20,7 +20,7 @@ TOPDIR :=../.. L_TARGET := libunarchive.a -obj-y := unarchive.o seek_sub_file.o +obj-y := unarchive.o seek_sub_file.o obj-n := obj- := @@ -41,13 +41,17 @@ ifeq ($(CONFIG_CPIO),y) endif ifeq ($(CONFIG_RPM2CPIO),y) - obj-y += get_header_cpio.o + obj-y += get_header_cpio.o endif ifeq ($(CONFIG_TAR),y) obj-y += get_header_tar.o endif +ifeq ($(CONFIG_UNZIP),y) + obj-y += get_header_zip.o +endif + # Hand off to toplevel Rules.mak include $(TOPDIR)/Rules.mak diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c index 6c28d18..8075fd7 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libunarchive/decompress_unzip.c @@ -80,7 +80,7 @@ static const int ERROR = 1; /* * window size--must be a power of two, and - * at least 32K for zip's deflate method + * at least 32K for zip's deflate method */ static const int WSIZE = 0x8000; @@ -846,7 +846,7 @@ static int inflate_block(int *e) * * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr */ -static int inflate(void) +extern int inflate(FILE *in, FILE *out) { int e; /* last block flag */ int r; /* result code */ @@ -857,6 +857,13 @@ static int inflate(void) 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; + /* Create the crc table */ make_crc_table(); @@ -881,13 +888,15 @@ static int inflate(void) /* flush out window */ flush_window(); + free(window); + free(crc_table); /* return success */ return 0; } /* =========================================================================== - * Unzip in to out. This routine works on both gzip and pkzip files. + * 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. @@ -901,9 +910,6 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) typedef void (*sig_type) (int); unsigned short i; - in_file = l_in_file; - out_file = l_out_file; - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, (sig_type) abort_gzip); } @@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) } #endif - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); - outcnt = 0; - bytes_out = 0L; - /* Magic header for gzip files, 1F 8B = \037\213 */ - if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { + if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) { error_msg("Invalid gzip magic"); return EXIT_FAILURE; } /* Check the compression method */ - if (fgetc(in_file) != 8) { + if (fgetc(l_in_file) != 8) { error_msg("Unknown compression method"); return(-1); } - flags = (unsigned char) fgetc(in_file); + flags = (unsigned char) fgetc(l_in_file); /* Ignore time stamp(4), extra flags(1), OS type(1) */ for (i = 0; i < 6; i++) { - fgetc(in_file); + fgetc(l_in_file); } if (flags & 0x04) { /* bit 2 set: extra field present */ - const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8); + const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8); for (i = 0; i < extra; i++) { - fgetc(in_file); + fgetc(l_in_file); } } /* Discard original name if any */ if (flags & 0x08) { /* bit 3 set: original file name present */ - while (fgetc(in_file) != 0); /* null */ + while (fgetc(l_in_file) != 0); /* null */ } /* Discard file comment if any */ if (flags & 0x10) { /* bit 4 set: file comment present */ - while (fgetc(in_file) != 0); /* null */ + while (fgetc(l_in_file) != 0); /* null */ } /* Decompress */ - if (inflate() != 0) { + if (inflate(l_in_file, l_out_file) != 0) { error_msg("invalid compressed data--format violated"); } @@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) * crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 */ - fread(buf, 1, 8, in_file); + 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)) { @@ -983,14 +984,11 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) error_msg("invalid compressed data--length error"); } - free(window); - free(crc_table); - return 0; } /* - * This needs access to global variables wondow and crc_table, so its not in its own file. + * This needs access to global variables window and crc_table, so its not in its own file. */ extern void gz_close(int gunzip_pid) { diff --git a/archival/libunarchive/get_header_zip.c b/archival/libunarchive/get_header_zip.c new file mode 100644 index 0000000..84f2a54 --- /dev/null +++ b/archival/libunarchive/get_header_zip.c @@ -0,0 +1,110 @@ +/* vi: set sw=4 ts=4: */ +/* + * get_header_zip for busybox + * + * Copyright (C) 2001 by Laurence Anderson + * + * 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 +#include +#include +#include "unarchive.h" +#include "libbb.h" + +#define ZIP_FILEHEADER_MAGIC 0x04034b50 +#define ZIP_CDS_MAGIC 0x02014b50 +#define ZIP_CDS_END_MAGIC 0x06054b50 +#define ZIP_DD_MAGIC 0x8074b50 + +file_header_t *get_header_zip(FILE *zip_stream) +{ + struct { + short version __attribute__ ((packed)); + short flags __attribute__ ((packed)); + short method __attribute__ ((packed)); + short modtime __attribute__ ((packed)); + short moddate __attribute__ ((packed)); + int crc32 __attribute__ ((packed)); + int cmpsize __attribute__ ((packed)); + int ucmpsize __attribute__ ((packed)); + short filename_len __attribute__ ((packed)); + short extra_len __attribute__ ((packed)); + } zip_header; + file_header_t *zip_entry = NULL; + int magic; + static int dd_ahead = 0; // If this is true, the we didn't know how long the last extraced file was + + fread (&magic, 4, 1, zip_stream); + archive_offset += 4; + + if (feof(zip_stream)) return(NULL); +checkmagic: + switch (magic) { + case ZIP_FILEHEADER_MAGIC: + zip_entry = xcalloc(1, sizeof(file_header_t)); + fread (&zip_header, sizeof(zip_header), 1, zip_stream); + archive_offset += sizeof(zip_header); + if (!(zip_header.method == 8 || zip_header.method == 0)) { printf("Unsupported compression method %d\n", zip_header.method); return(NULL); } + zip_entry->name = calloc(zip_header.filename_len + 1, sizeof(char)); + fread (zip_entry->name, sizeof(char), zip_header.filename_len, zip_stream); + archive_offset += zip_header.filename_len; + seek_sub_file(zip_stream, zip_header.extra_len); + zip_entry->size = zip_header.cmpsize; + if (zip_header.method == 8) zip_entry->extract_func = &inflate; + zip_entry->mode = S_IFREG | 0777; + // Time/Date? + if (*(zip_entry->name + strlen(zip_entry->name) - 1) == '/') { // Files that end in a / are directories + zip_entry->mode ^= S_IFREG; + zip_entry->mode |= S_IFDIR; + *(zip_entry->name + strlen(zip_entry->name) - 1) = '\0'; // Remove trailing / so unarchive doesn't get confused + } + //printf("cmpsize: %d, ucmpsize: %d, method: %d\n", zip_header.cmpsize, zip_header.ucmpsize, zip_header.method); + if (zip_header.flags & 0x8) { // crc32, and sizes are in the data description _after_ the file + if (zip_header.cmpsize == 0) dd_ahead = 1; // As we don't know how long this file it is difficult to skip! but it is compressed, so normally its ok + if (zip_header.ucmpsize != 0) dd_ahead = 2; // Humm... we would otherwise skip this twice - not good! + } + break; + case ZIP_CDS_MAGIC: /* FALLTHRU */ + case ZIP_CDS_END_MAGIC: + return(NULL); + break; + case ZIP_DD_MAGIC: { + int cmpsize; + seek_sub_file(zip_stream, 4); // Skip crc32 + fread(&cmpsize, 4, 1, zip_stream); + archive_offset += 4; + if (dd_ahead == 1) archive_offset += cmpsize; + seek_sub_file(zip_stream, 4); // Skip uncompressed size + dd_ahead = 0; + return (get_header_zip(zip_stream)); + break; } + default: + if (!dd_ahead) error_msg("Invalid magic (%#x): Trying to skip junk", magic); + dd_ahead = 0; + while (!feof(zip_stream)) { + int tmpmagic; + tmpmagic = fgetc(zip_stream); + archive_offset++; + magic = ((magic >> 8) & 0x00ffffff) | ((tmpmagic << 24) & 0xff000000); + if (magic == ZIP_FILEHEADER_MAGIC || magic == ZIP_CDS_MAGIC || magic == ZIP_CDS_END_MAGIC) goto checkmagic; + } + error_msg("End of archive reached: Bad archive"); + return(NULL); + } + //if (archive_offset != ftell(zip_stream)) printf("Archive offset out of sync (%d,%d)\n", (int) archive_offset, (int) ftell(zip_stream)); + return(zip_entry); +} diff --git a/archival/libunarchive/unarchive.c b/archival/libunarchive/unarchive.c index ff9b587..41be963 100644 --- a/archival/libunarchive/unarchive.c +++ b/archival/libunarchive/unarchive.c @@ -120,7 +120,8 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f return NULL; } archive_offset += file_entry->size; - copy_file_chunk(src_stream, dst_stream, file_entry->size); + if (file_entry->extract_func) file_entry->extract_func(src_stream, dst_stream); + else copy_file_chunk(src_stream, dst_stream, file_entry->size); fclose(dst_stream); } break; diff --git a/archival/libunarchive/unzip.c b/archival/libunarchive/unzip.c index 6c28d18..8075fd7 100644 --- a/archival/libunarchive/unzip.c +++ b/archival/libunarchive/unzip.c @@ -80,7 +80,7 @@ static const int ERROR = 1; /* * window size--must be a power of two, and - * at least 32K for zip's deflate method + * at least 32K for zip's deflate method */ static const int WSIZE = 0x8000; @@ -846,7 +846,7 @@ static int inflate_block(int *e) * * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr */ -static int inflate(void) +extern int inflate(FILE *in, FILE *out) { int e; /* last block flag */ int r; /* result code */ @@ -857,6 +857,13 @@ static int inflate(void) 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; + /* Create the crc table */ make_crc_table(); @@ -881,13 +888,15 @@ static int inflate(void) /* flush out window */ flush_window(); + free(window); + free(crc_table); /* return success */ return 0; } /* =========================================================================== - * Unzip in to out. This routine works on both gzip and pkzip files. + * 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. @@ -901,9 +910,6 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) typedef void (*sig_type) (int); unsigned short i; - in_file = l_in_file; - out_file = l_out_file; - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { (void) signal(SIGINT, (sig_type) abort_gzip); } @@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) } #endif - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); - outcnt = 0; - bytes_out = 0L; - /* Magic header for gzip files, 1F 8B = \037\213 */ - if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { + if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) { error_msg("Invalid gzip magic"); return EXIT_FAILURE; } /* Check the compression method */ - if (fgetc(in_file) != 8) { + if (fgetc(l_in_file) != 8) { error_msg("Unknown compression method"); return(-1); } - flags = (unsigned char) fgetc(in_file); + flags = (unsigned char) fgetc(l_in_file); /* Ignore time stamp(4), extra flags(1), OS type(1) */ for (i = 0; i < 6; i++) { - fgetc(in_file); + fgetc(l_in_file); } if (flags & 0x04) { /* bit 2 set: extra field present */ - const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8); + const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8); for (i = 0; i < extra; i++) { - fgetc(in_file); + fgetc(l_in_file); } } /* Discard original name if any */ if (flags & 0x08) { /* bit 3 set: original file name present */ - while (fgetc(in_file) != 0); /* null */ + while (fgetc(l_in_file) != 0); /* null */ } /* Discard file comment if any */ if (flags & 0x10) { /* bit 4 set: file comment present */ - while (fgetc(in_file) != 0); /* null */ + while (fgetc(l_in_file) != 0); /* null */ } /* Decompress */ - if (inflate() != 0) { + if (inflate(l_in_file, l_out_file) != 0) { error_msg("invalid compressed data--format violated"); } @@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) * crc32 (see algorithm.doc) * uncompressed input size modulo 2^32 */ - fread(buf, 1, 8, in_file); + 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)) { @@ -983,14 +984,11 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file) error_msg("invalid compressed data--length error"); } - free(window); - free(crc_table); - return 0; } /* - * This needs access to global variables wondow and crc_table, so its not in its own file. + * This needs access to global variables window and crc_table, so its not in its own file. */ extern void gz_close(int gunzip_pid) { -- cgit v1.1