unzip applet by Laurence Anderson
----------------------------------------------------------------------
This commit is contained in:
		| @@ -34,6 +34,7 @@ obj-$(CONFIG_GUNZIP)		+= gunzip.o | ||||
| obj-$(CONFIG_GZIP)		+= gzip.o | ||||
| obj-$(CONFIG_RPM2CPIO)		+= rpm2cpio.o | ||||
| obj-$(CONFIG_TAR)		+= tar.o | ||||
| obj-$(CONFIG_UNZIP)		+= unzip.o | ||||
|  | ||||
|  | ||||
| # Hand off to toplevel Rules.mak | ||||
|   | ||||
| @@ -20,4 +20,5 @@ if [ "$CONFIG_TAR" = "y" ] ; then | ||||
|     bool '  Enable -X and --exclude options (exclude files)'	CONFIG_FEATURE_TAR_EXCLUDE | ||||
|     bool '  Enable -z option (currently only for extracting)'	CONFIG_FEATURE_TAR_GZIP | ||||
| fi | ||||
| bool 'unzip'	    CONFIG_UNZIP | ||||
| endmenu | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
| { | ||||
|   | ||||
							
								
								
									
										110
									
								
								archival/libunarchive/get_header_zip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								archival/libunarchive/get_header_zip.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #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); | ||||
| } | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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) | ||||
| { | ||||
|   | ||||
							
								
								
									
										94
									
								
								archival/unzip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								archival/unzip.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * Mini unzip implementation 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 <fcntl.h> | ||||
| #include <getopt.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include "unarchive.h" | ||||
| #include "busybox.h" | ||||
|  | ||||
| extern int unzip_main(int argc, char **argv) | ||||
| { | ||||
| 	FILE *src_stream; | ||||
| 	int extract_function = extract_all_to_fs | extract_create_leading_dirs; | ||||
| 	char **extract_names = NULL; | ||||
| 	char **exclude_names = NULL; | ||||
| 	int opt = 0; | ||||
| 	int num_of_entries = 0; | ||||
| 	int exclude = 0; | ||||
| 	char *outdir = "./"; | ||||
| 	FILE *msgout = stdout; | ||||
|  | ||||
| 	while ((opt = getopt(argc, argv, "lnopqxd:")) != -1) { | ||||
| 		switch (opt) { | ||||
| 			case 'l': | ||||
| 				extract_function |= extract_verbose_list; | ||||
| 				extract_function ^= extract_all_to_fs; | ||||
| 				break; | ||||
| 			case 'n': | ||||
| 				break; | ||||
| 			case 'o': | ||||
| 				extract_function |= extract_unconditional; | ||||
| 				break; | ||||
| 			case 'p': | ||||
| 				extract_function |= extract_to_stdout; | ||||
| 				extract_function ^= extract_all_to_fs; | ||||
| 				/* FALLTHROUGH */ | ||||
| 			case 'q': | ||||
| 				msgout = xfopen("/dev/null", "w"); | ||||
| 				break; | ||||
| 			case 'd': | ||||
| 				outdir = xstrdup(optarg); | ||||
| 				strcat(outdir, "/"); | ||||
| 				break; | ||||
| 			case 'x': | ||||
| 				exclude = 1; | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (optind == argc) { | ||||
| 		show_usage(); | ||||
| 	} | ||||
|  | ||||
| 	if (*argv[optind] == '-') src_stream = stdin; | ||||
| 	else src_stream = xfopen(argv[optind++], "r"); | ||||
|  | ||||
| 	while (optind < argc) { | ||||
| 		if (exclude) { | ||||
| 			exclude_names = xrealloc(exclude_names, sizeof(char *) * (num_of_entries + 2)); | ||||
| 			exclude_names[num_of_entries] = xstrdup(argv[optind]); | ||||
| 		} else { | ||||
| 			extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); | ||||
| 			extract_names[num_of_entries] = xstrdup(argv[optind]); | ||||
| 		} | ||||
| 		num_of_entries++; | ||||
| 		if (exclude) exclude_names[num_of_entries] = NULL; | ||||
| 		else extract_names[num_of_entries] = NULL; | ||||
| 		optind++; | ||||
| 	} | ||||
|  | ||||
| 	unarchive(src_stream, msgout, &get_header_zip, extract_function, outdir, extract_names, exclude_names); | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
| @@ -470,6 +470,9 @@ | ||||
| #ifdef CONFIG_UNIX2DOS | ||||
| 	APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN) | ||||
| #endif | ||||
| #ifdef CONFIG_UNZIP | ||||
| 	APPLET(unzip, unzip_main, _BB_DIR_USR_BIN) | ||||
| #endif | ||||
| #ifdef CONFIG_UPDATE | ||||
| 	APPLET(update, update_main, _BB_DIR_SBIN) | ||||
| #endif | ||||
|   | ||||
| @@ -215,6 +215,7 @@ extern long arith (const char *startbuf, int *errcode); | ||||
| int read_package_field(const char *package_buffer, char **field_name, char **field_value); | ||||
| char *fgets_str(FILE *file, const char *terminating_string); | ||||
|  | ||||
| extern int inflate(FILE *in, FILE *out); | ||||
| extern int unzip(FILE *l_in_file, FILE *l_out_file); | ||||
| extern void gz_close(int gunzip_pid); | ||||
| extern FILE *gz_open(FILE *compressed_file, int *pid); | ||||
|   | ||||
| @@ -26,11 +26,13 @@ typedef struct file_headers_s { | ||||
| 	mode_t mode; | ||||
| 	time_t mtime; | ||||
| 	dev_t device; | ||||
| 	int (*extract_func)(FILE *, FILE *); | ||||
| } file_header_t; | ||||
|  | ||||
| file_header_t *get_header_ar(FILE *in_file); | ||||
| file_header_t *get_header_cpio(FILE *src_stream); | ||||
| file_header_t *get_header_tar(FILE *tar_stream); | ||||
| file_header_t *get_header_zip(FILE *zip_stream); | ||||
|  | ||||
| void seek_sub_file(FILE *src_stream, const int count); | ||||
|  | ||||
|   | ||||
| @@ -1851,6 +1851,19 @@ | ||||
| 	"\t-u\toutput will be in UNIX format\n" \ | ||||
| 	"\t-d\toutput will be in DOS format" | ||||
|  | ||||
| #define unzip_trivial_usage \ | ||||
| 	"[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]" | ||||
| #define unzip_full_usage \ | ||||
| 	"Extracts files from ZIP archives\n" \ | ||||
| 	"Options:\n" \ | ||||
| 	"\t-l\tlist archive contents (short form)\n" \ | ||||
| 	"\t-n\tnever overwrite existing files (default)\n" \ | ||||
| 	"\t-o\toverwrite files without prompting\n" \ | ||||
| 	"\t-p\tsend output to stdout\n" \ | ||||
| 	"\t-q\tbe quiet\n" \ | ||||
| 	"\t-x\texclude these files\n" \ | ||||
| 	"\t-d\textract files into this directory" | ||||
|  | ||||
| #define update_trivial_usage \ | ||||
| 	"[options]" | ||||
| #define update_full_usage \ | ||||
|   | ||||
| @@ -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) | ||||
| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user