aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2002-01-02 13:52:26 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2002-01-02 13:52:26 +0000
commit87ac7028e01cdc4f504ea558a6ae3d086ed1bf2b (patch)
tree4f406c877f88a013c4e1dc650ac312640a95cb00
parent438803311b67c6337ea97476e97336e027ef9a3a (diff)
downloadbusybox-w32-87ac7028e01cdc4f504ea558a6ae3d086ed1bf2b.tar.gz
busybox-w32-87ac7028e01cdc4f504ea558a6ae3d086ed1bf2b.tar.bz2
busybox-w32-87ac7028e01cdc4f504ea558a6ae3d086ed1bf2b.zip
unzip applet by Laurence Anderson
----------------------------------------------------------------------
-rw-r--r--archival/Makefile1
-rw-r--r--archival/config.in1
-rw-r--r--archival/libunarchive/Makefile8
-rw-r--r--archival/libunarchive/decompress_unzip.c48
-rw-r--r--archival/libunarchive/get_header_zip.c110
-rw-r--r--archival/libunarchive/unarchive.c3
-rw-r--r--archival/libunarchive/unzip.c48
-rw-r--r--archival/unzip.c94
-rw-r--r--include/applets.h3
-rw-r--r--include/libbb.h1
-rw-r--r--include/unarchive.h2
-rw-r--r--include/usage.h13
-rw-r--r--libbb/unzip.c48
13 files changed, 302 insertions, 78 deletions
diff --git a/archival/Makefile b/archival/Makefile
index 8787589ff..35ba02f3b 100644
--- a/archival/Makefile
+++ b/archival/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_GUNZIP) += gunzip.o
34obj-$(CONFIG_GZIP) += gzip.o 34obj-$(CONFIG_GZIP) += gzip.o
35obj-$(CONFIG_RPM2CPIO) += rpm2cpio.o 35obj-$(CONFIG_RPM2CPIO) += rpm2cpio.o
36obj-$(CONFIG_TAR) += tar.o 36obj-$(CONFIG_TAR) += tar.o
37obj-$(CONFIG_UNZIP) += unzip.o
37 38
38 39
39# Hand off to toplevel Rules.mak 40# Hand off to toplevel Rules.mak
diff --git a/archival/config.in b/archival/config.in
index 76a192e13..7b5644f01 100644
--- a/archival/config.in
+++ b/archival/config.in
@@ -20,4 +20,5 @@ if [ "$CONFIG_TAR" = "y" ] ; then
20 bool ' Enable -X and --exclude options (exclude files)' CONFIG_FEATURE_TAR_EXCLUDE 20 bool ' Enable -X and --exclude options (exclude files)' CONFIG_FEATURE_TAR_EXCLUDE
21 bool ' Enable -z option (currently only for extracting)' CONFIG_FEATURE_TAR_GZIP 21 bool ' Enable -z option (currently only for extracting)' CONFIG_FEATURE_TAR_GZIP
22fi 22fi
23bool 'unzip' CONFIG_UNZIP
23endmenu 24endmenu
diff --git a/archival/libunarchive/Makefile b/archival/libunarchive/Makefile
index 0c7219dcd..a8409a432 100644
--- a/archival/libunarchive/Makefile
+++ b/archival/libunarchive/Makefile
@@ -20,7 +20,7 @@
20TOPDIR :=../.. 20TOPDIR :=../..
21L_TARGET := libunarchive.a 21L_TARGET := libunarchive.a
22 22
23obj-y := unarchive.o seek_sub_file.o 23obj-y := unarchive.o seek_sub_file.o
24obj-n := 24obj-n :=
25obj- := 25obj- :=
26 26
@@ -41,13 +41,17 @@ ifeq ($(CONFIG_CPIO),y)
41endif 41endif
42 42
43ifeq ($(CONFIG_RPM2CPIO),y) 43ifeq ($(CONFIG_RPM2CPIO),y)
44 obj-y += get_header_cpio.o 44 obj-y += get_header_cpio.o
45endif 45endif
46 46
47ifeq ($(CONFIG_TAR),y) 47ifeq ($(CONFIG_TAR),y)
48 obj-y += get_header_tar.o 48 obj-y += get_header_tar.o
49endif 49endif
50 50
51ifeq ($(CONFIG_UNZIP),y)
52 obj-y += get_header_zip.o
53endif
54
51 55
52# Hand off to toplevel Rules.mak 56# Hand off to toplevel Rules.mak
53include $(TOPDIR)/Rules.mak 57include $(TOPDIR)/Rules.mak
diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c
index 6c28d181d..8075fd717 100644
--- a/archival/libunarchive/decompress_unzip.c
+++ b/archival/libunarchive/decompress_unzip.c
@@ -80,7 +80,7 @@ static const int ERROR = 1;
80 80
81/* 81/*
82 * window size--must be a power of two, and 82 * window size--must be a power of two, and
83 * at least 32K for zip's deflate method 83 * at least 32K for zip's deflate method
84 */ 84 */
85static const int WSIZE = 0x8000; 85static const int WSIZE = 0x8000;
86 86
@@ -846,7 +846,7 @@ static int inflate_block(int *e)
846 * 846 *
847 * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr 847 * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
848 */ 848 */
849static int inflate(void) 849extern int inflate(FILE *in, FILE *out)
850{ 850{
851 int e; /* last block flag */ 851 int e; /* last block flag */
852 int r; /* result code */ 852 int r; /* result code */
@@ -857,6 +857,13 @@ static int inflate(void)
857 bk = 0; 857 bk = 0;
858 bb = 0; 858 bb = 0;
859 859
860 in_file = in;
861 out_file = out;
862
863 /* Allocate all global buffers (for DYN_ALLOC option) */
864 window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
865 bytes_out = 0L;
866
860 /* Create the crc table */ 867 /* Create the crc table */
861 make_crc_table(); 868 make_crc_table();
862 869
@@ -881,13 +888,15 @@ static int inflate(void)
881 888
882 /* flush out window */ 889 /* flush out window */
883 flush_window(); 890 flush_window();
891 free(window);
892 free(crc_table);
884 893
885 /* return success */ 894 /* return success */
886 return 0; 895 return 0;
887} 896}
888 897
889/* =========================================================================== 898/* ===========================================================================
890 * Unzip in to out. This routine works on both gzip and pkzip files. 899 * Unzip in to out. This routine works on gzip files only.
891 * 900 *
892 * IN assertions: the buffer inbuf contains already the beginning of 901 * IN assertions: the buffer inbuf contains already the beginning of
893 * the compressed data, from offsets inptr to insize-1 included. 902 * 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)
901 typedef void (*sig_type) (int); 910 typedef void (*sig_type) (int);
902 unsigned short i; 911 unsigned short i;
903 912
904 in_file = l_in_file;
905 out_file = l_out_file;
906
907 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 913 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
908 (void) signal(SIGINT, (sig_type) abort_gzip); 914 (void) signal(SIGINT, (sig_type) abort_gzip);
909 } 915 }
@@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
918 } 924 }
919#endif 925#endif
920 926
921 /* Allocate all global buffers (for DYN_ALLOC option) */
922 window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
923 outcnt = 0;
924 bytes_out = 0L;
925
926 /* Magic header for gzip files, 1F 8B = \037\213 */ 927 /* Magic header for gzip files, 1F 8B = \037\213 */
927 if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { 928 if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) {
928 error_msg("Invalid gzip magic"); 929 error_msg("Invalid gzip magic");
929 return EXIT_FAILURE; 930 return EXIT_FAILURE;
930 } 931 }
931 932
932 /* Check the compression method */ 933 /* Check the compression method */
933 if (fgetc(in_file) != 8) { 934 if (fgetc(l_in_file) != 8) {
934 error_msg("Unknown compression method"); 935 error_msg("Unknown compression method");
935 return(-1); 936 return(-1);
936 } 937 }
937 938
938 flags = (unsigned char) fgetc(in_file); 939 flags = (unsigned char) fgetc(l_in_file);
939 940
940 /* Ignore time stamp(4), extra flags(1), OS type(1) */ 941 /* Ignore time stamp(4), extra flags(1), OS type(1) */
941 for (i = 0; i < 6; i++) { 942 for (i = 0; i < 6; i++) {
942 fgetc(in_file); 943 fgetc(l_in_file);
943 } 944 }
944 945
945 if (flags & 0x04) { 946 if (flags & 0x04) {
946 /* bit 2 set: extra field present */ 947 /* bit 2 set: extra field present */
947 const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8); 948 const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8);
948 949
949 for (i = 0; i < extra; i++) { 950 for (i = 0; i < extra; i++) {
950 fgetc(in_file); 951 fgetc(l_in_file);
951 } 952 }
952 } 953 }
953 954
954 /* Discard original name if any */ 955 /* Discard original name if any */
955 if (flags & 0x08) { 956 if (flags & 0x08) {
956 /* bit 3 set: original file name present */ 957 /* bit 3 set: original file name present */
957 while (fgetc(in_file) != 0); /* null */ 958 while (fgetc(l_in_file) != 0); /* null */
958 } 959 }
959 960
960 /* Discard file comment if any */ 961 /* Discard file comment if any */
961 if (flags & 0x10) { 962 if (flags & 0x10) {
962 /* bit 4 set: file comment present */ 963 /* bit 4 set: file comment present */
963 while (fgetc(in_file) != 0); /* null */ 964 while (fgetc(l_in_file) != 0); /* null */
964 } 965 }
965 966
966 /* Decompress */ 967 /* Decompress */
967 if (inflate() != 0) { 968 if (inflate(l_in_file, l_out_file) != 0) {
968 error_msg("invalid compressed data--format violated"); 969 error_msg("invalid compressed data--format violated");
969 } 970 }
970 971
@@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
972 * crc32 (see algorithm.doc) 973 * crc32 (see algorithm.doc)
973 * uncompressed input size modulo 2^32 974 * uncompressed input size modulo 2^32
974 */ 975 */
975 fread(buf, 1, 8, in_file); 976 fread(buf, 1, 8, l_in_file);
976 977
977 /* Validate decompression - crc */ 978 /* Validate decompression - crc */
978 if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { 979 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)
983 error_msg("invalid compressed data--length error"); 984 error_msg("invalid compressed data--length error");
984 } 985 }
985 986
986 free(window);
987 free(crc_table);
988
989 return 0; 987 return 0;
990} 988}
991 989
992/* 990/*
993 * This needs access to global variables wondow and crc_table, so its not in its own file. 991 * This needs access to global variables window and crc_table, so its not in its own file.
994 */ 992 */
995extern void gz_close(int gunzip_pid) 993extern void gz_close(int gunzip_pid)
996{ 994{
diff --git a/archival/libunarchive/get_header_zip.c b/archival/libunarchive/get_header_zip.c
new file mode 100644
index 000000000..84f2a54f2
--- /dev/null
+++ b/archival/libunarchive/get_header_zip.c
@@ -0,0 +1,110 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * get_header_zip for busybox
4 *
5 * Copyright (C) 2001 by Laurence Anderson
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include "unarchive.h"
26#include "libbb.h"
27
28#define ZIP_FILEHEADER_MAGIC 0x04034b50
29#define ZIP_CDS_MAGIC 0x02014b50
30#define ZIP_CDS_END_MAGIC 0x06054b50
31#define ZIP_DD_MAGIC 0x8074b50
32
33file_header_t *get_header_zip(FILE *zip_stream)
34{
35 struct {
36 short version __attribute__ ((packed));
37 short flags __attribute__ ((packed));
38 short method __attribute__ ((packed));
39 short modtime __attribute__ ((packed));
40 short moddate __attribute__ ((packed));
41 int crc32 __attribute__ ((packed));
42 int cmpsize __attribute__ ((packed));
43 int ucmpsize __attribute__ ((packed));
44 short filename_len __attribute__ ((packed));
45 short extra_len __attribute__ ((packed));
46 } zip_header;
47 file_header_t *zip_entry = NULL;
48 int magic;
49 static int dd_ahead = 0; // If this is true, the we didn't know how long the last extraced file was
50
51 fread (&magic, 4, 1, zip_stream);
52 archive_offset += 4;
53
54 if (feof(zip_stream)) return(NULL);
55checkmagic:
56 switch (magic) {
57 case ZIP_FILEHEADER_MAGIC:
58 zip_entry = xcalloc(1, sizeof(file_header_t));
59 fread (&zip_header, sizeof(zip_header), 1, zip_stream);
60 archive_offset += sizeof(zip_header);
61 if (!(zip_header.method == 8 || zip_header.method == 0)) { printf("Unsupported compression method %d\n", zip_header.method); return(NULL); }
62 zip_entry->name = calloc(zip_header.filename_len + 1, sizeof(char));
63 fread (zip_entry->name, sizeof(char), zip_header.filename_len, zip_stream);
64 archive_offset += zip_header.filename_len;
65 seek_sub_file(zip_stream, zip_header.extra_len);
66 zip_entry->size = zip_header.cmpsize;
67 if (zip_header.method == 8) zip_entry->extract_func = &inflate;
68 zip_entry->mode = S_IFREG | 0777;
69 // Time/Date?
70 if (*(zip_entry->name + strlen(zip_entry->name) - 1) == '/') { // Files that end in a / are directories
71 zip_entry->mode ^= S_IFREG;
72 zip_entry->mode |= S_IFDIR;
73 *(zip_entry->name + strlen(zip_entry->name) - 1) = '\0'; // Remove trailing / so unarchive doesn't get confused
74 }
75 //printf("cmpsize: %d, ucmpsize: %d, method: %d\n", zip_header.cmpsize, zip_header.ucmpsize, zip_header.method);
76 if (zip_header.flags & 0x8) { // crc32, and sizes are in the data description _after_ the file
77 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
78 if (zip_header.ucmpsize != 0) dd_ahead = 2; // Humm... we would otherwise skip this twice - not good!
79 }
80 break;
81 case ZIP_CDS_MAGIC: /* FALLTHRU */
82 case ZIP_CDS_END_MAGIC:
83 return(NULL);
84 break;
85 case ZIP_DD_MAGIC: {
86 int cmpsize;
87 seek_sub_file(zip_stream, 4); // Skip crc32
88 fread(&cmpsize, 4, 1, zip_stream);
89 archive_offset += 4;
90 if (dd_ahead == 1) archive_offset += cmpsize;
91 seek_sub_file(zip_stream, 4); // Skip uncompressed size
92 dd_ahead = 0;
93 return (get_header_zip(zip_stream));
94 break; }
95 default:
96 if (!dd_ahead) error_msg("Invalid magic (%#x): Trying to skip junk", magic);
97 dd_ahead = 0;
98 while (!feof(zip_stream)) {
99 int tmpmagic;
100 tmpmagic = fgetc(zip_stream);
101 archive_offset++;
102 magic = ((magic >> 8) & 0x00ffffff) | ((tmpmagic << 24) & 0xff000000);
103 if (magic == ZIP_FILEHEADER_MAGIC || magic == ZIP_CDS_MAGIC || magic == ZIP_CDS_END_MAGIC) goto checkmagic;
104 }
105 error_msg("End of archive reached: Bad archive");
106 return(NULL);
107 }
108 //if (archive_offset != ftell(zip_stream)) printf("Archive offset out of sync (%d,%d)\n", (int) archive_offset, (int) ftell(zip_stream));
109 return(zip_entry);
110}
diff --git a/archival/libunarchive/unarchive.c b/archival/libunarchive/unarchive.c
index ff9b5876f..41be963ef 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
120 return NULL; 120 return NULL;
121 } 121 }
122 archive_offset += file_entry->size; 122 archive_offset += file_entry->size;
123 copy_file_chunk(src_stream, dst_stream, file_entry->size); 123 if (file_entry->extract_func) file_entry->extract_func(src_stream, dst_stream);
124 else copy_file_chunk(src_stream, dst_stream, file_entry->size);
124 fclose(dst_stream); 125 fclose(dst_stream);
125 } 126 }
126 break; 127 break;
diff --git a/archival/libunarchive/unzip.c b/archival/libunarchive/unzip.c
index 6c28d181d..8075fd717 100644
--- a/archival/libunarchive/unzip.c
+++ b/archival/libunarchive/unzip.c
@@ -80,7 +80,7 @@ static const int ERROR = 1;
80 80
81/* 81/*
82 * window size--must be a power of two, and 82 * window size--must be a power of two, and
83 * at least 32K for zip's deflate method 83 * at least 32K for zip's deflate method
84 */ 84 */
85static const int WSIZE = 0x8000; 85static const int WSIZE = 0x8000;
86 86
@@ -846,7 +846,7 @@ static int inflate_block(int *e)
846 * 846 *
847 * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr 847 * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
848 */ 848 */
849static int inflate(void) 849extern int inflate(FILE *in, FILE *out)
850{ 850{
851 int e; /* last block flag */ 851 int e; /* last block flag */
852 int r; /* result code */ 852 int r; /* result code */
@@ -857,6 +857,13 @@ static int inflate(void)
857 bk = 0; 857 bk = 0;
858 bb = 0; 858 bb = 0;
859 859
860 in_file = in;
861 out_file = out;
862
863 /* Allocate all global buffers (for DYN_ALLOC option) */
864 window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
865 bytes_out = 0L;
866
860 /* Create the crc table */ 867 /* Create the crc table */
861 make_crc_table(); 868 make_crc_table();
862 869
@@ -881,13 +888,15 @@ static int inflate(void)
881 888
882 /* flush out window */ 889 /* flush out window */
883 flush_window(); 890 flush_window();
891 free(window);
892 free(crc_table);
884 893
885 /* return success */ 894 /* return success */
886 return 0; 895 return 0;
887} 896}
888 897
889/* =========================================================================== 898/* ===========================================================================
890 * Unzip in to out. This routine works on both gzip and pkzip files. 899 * Unzip in to out. This routine works on gzip files only.
891 * 900 *
892 * IN assertions: the buffer inbuf contains already the beginning of 901 * IN assertions: the buffer inbuf contains already the beginning of
893 * the compressed data, from offsets inptr to insize-1 included. 902 * 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)
901 typedef void (*sig_type) (int); 910 typedef void (*sig_type) (int);
902 unsigned short i; 911 unsigned short i;
903 912
904 in_file = l_in_file;
905 out_file = l_out_file;
906
907 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 913 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
908 (void) signal(SIGINT, (sig_type) abort_gzip); 914 (void) signal(SIGINT, (sig_type) abort_gzip);
909 } 915 }
@@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
918 } 924 }
919#endif 925#endif
920 926
921 /* Allocate all global buffers (for DYN_ALLOC option) */
922 window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
923 outcnt = 0;
924 bytes_out = 0L;
925
926 /* Magic header for gzip files, 1F 8B = \037\213 */ 927 /* Magic header for gzip files, 1F 8B = \037\213 */
927 if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { 928 if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) {
928 error_msg("Invalid gzip magic"); 929 error_msg("Invalid gzip magic");
929 return EXIT_FAILURE; 930 return EXIT_FAILURE;
930 } 931 }
931 932
932 /* Check the compression method */ 933 /* Check the compression method */
933 if (fgetc(in_file) != 8) { 934 if (fgetc(l_in_file) != 8) {
934 error_msg("Unknown compression method"); 935 error_msg("Unknown compression method");
935 return(-1); 936 return(-1);
936 } 937 }
937 938
938 flags = (unsigned char) fgetc(in_file); 939 flags = (unsigned char) fgetc(l_in_file);
939 940
940 /* Ignore time stamp(4), extra flags(1), OS type(1) */ 941 /* Ignore time stamp(4), extra flags(1), OS type(1) */
941 for (i = 0; i < 6; i++) { 942 for (i = 0; i < 6; i++) {
942 fgetc(in_file); 943 fgetc(l_in_file);
943 } 944 }
944 945
945 if (flags & 0x04) { 946 if (flags & 0x04) {
946 /* bit 2 set: extra field present */ 947 /* bit 2 set: extra field present */
947 const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8); 948 const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8);
948 949
949 for (i = 0; i < extra; i++) { 950 for (i = 0; i < extra; i++) {
950 fgetc(in_file); 951 fgetc(l_in_file);
951 } 952 }
952 } 953 }
953 954
954 /* Discard original name if any */ 955 /* Discard original name if any */
955 if (flags & 0x08) { 956 if (flags & 0x08) {
956 /* bit 3 set: original file name present */ 957 /* bit 3 set: original file name present */
957 while (fgetc(in_file) != 0); /* null */ 958 while (fgetc(l_in_file) != 0); /* null */
958 } 959 }
959 960
960 /* Discard file comment if any */ 961 /* Discard file comment if any */
961 if (flags & 0x10) { 962 if (flags & 0x10) {
962 /* bit 4 set: file comment present */ 963 /* bit 4 set: file comment present */
963 while (fgetc(in_file) != 0); /* null */ 964 while (fgetc(l_in_file) != 0); /* null */
964 } 965 }
965 966
966 /* Decompress */ 967 /* Decompress */
967 if (inflate() != 0) { 968 if (inflate(l_in_file, l_out_file) != 0) {
968 error_msg("invalid compressed data--format violated"); 969 error_msg("invalid compressed data--format violated");
969 } 970 }
970 971
@@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
972 * crc32 (see algorithm.doc) 973 * crc32 (see algorithm.doc)
973 * uncompressed input size modulo 2^32 974 * uncompressed input size modulo 2^32
974 */ 975 */
975 fread(buf, 1, 8, in_file); 976 fread(buf, 1, 8, l_in_file);
976 977
977 /* Validate decompression - crc */ 978 /* Validate decompression - crc */
978 if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { 979 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)
983 error_msg("invalid compressed data--length error"); 984 error_msg("invalid compressed data--length error");
984 } 985 }
985 986
986 free(window);
987 free(crc_table);
988
989 return 0; 987 return 0;
990} 988}
991 989
992/* 990/*
993 * This needs access to global variables wondow and crc_table, so its not in its own file. 991 * This needs access to global variables window and crc_table, so its not in its own file.
994 */ 992 */
995extern void gz_close(int gunzip_pid) 993extern void gz_close(int gunzip_pid)
996{ 994{
diff --git a/archival/unzip.c b/archival/unzip.c
new file mode 100644
index 000000000..ae0d7c1dc
--- /dev/null
+++ b/archival/unzip.c
@@ -0,0 +1,94 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini unzip implementation for busybox
4 *
5 * Copyright (C) 2001 by Laurence Anderson
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <fcntl.h>
24#include <getopt.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include "unarchive.h"
29#include "busybox.h"
30
31extern int unzip_main(int argc, char **argv)
32{
33 FILE *src_stream;
34 int extract_function = extract_all_to_fs | extract_create_leading_dirs;
35 char **extract_names = NULL;
36 char **exclude_names = NULL;
37 int opt = 0;
38 int num_of_entries = 0;
39 int exclude = 0;
40 char *outdir = "./";
41 FILE *msgout = stdout;
42
43 while ((opt = getopt(argc, argv, "lnopqxd:")) != -1) {
44 switch (opt) {
45 case 'l':
46 extract_function |= extract_verbose_list;
47 extract_function ^= extract_all_to_fs;
48 break;
49 case 'n':
50 break;
51 case 'o':
52 extract_function |= extract_unconditional;
53 break;
54 case 'p':
55 extract_function |= extract_to_stdout;
56 extract_function ^= extract_all_to_fs;
57 /* FALLTHROUGH */
58 case 'q':
59 msgout = xfopen("/dev/null", "w");
60 break;
61 case 'd':
62 outdir = xstrdup(optarg);
63 strcat(outdir, "/");
64 break;
65 case 'x':
66 exclude = 1;
67 break;
68 }
69 }
70
71 if (optind == argc) {
72 show_usage();
73 }
74
75 if (*argv[optind] == '-') src_stream = stdin;
76 else src_stream = xfopen(argv[optind++], "r");
77
78 while (optind < argc) {
79 if (exclude) {
80 exclude_names = xrealloc(exclude_names, sizeof(char *) * (num_of_entries + 2));
81 exclude_names[num_of_entries] = xstrdup(argv[optind]);
82 } else {
83 extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2));
84 extract_names[num_of_entries] = xstrdup(argv[optind]);
85 }
86 num_of_entries++;
87 if (exclude) exclude_names[num_of_entries] = NULL;
88 else extract_names[num_of_entries] = NULL;
89 optind++;
90 }
91
92 unarchive(src_stream, msgout, &get_header_zip, extract_function, outdir, extract_names, exclude_names);
93 return EXIT_SUCCESS;
94}
diff --git a/include/applets.h b/include/applets.h
index ba0a9aaa9..0d310bdc3 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -470,6 +470,9 @@
470#ifdef CONFIG_UNIX2DOS 470#ifdef CONFIG_UNIX2DOS
471 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN) 471 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN)
472#endif 472#endif
473#ifdef CONFIG_UNZIP
474 APPLET(unzip, unzip_main, _BB_DIR_USR_BIN)
475#endif
473#ifdef CONFIG_UPDATE 476#ifdef CONFIG_UPDATE
474 APPLET(update, update_main, _BB_DIR_SBIN) 477 APPLET(update, update_main, _BB_DIR_SBIN)
475#endif 478#endif
diff --git a/include/libbb.h b/include/libbb.h
index fccdf5fdf..8dadfd958 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -215,6 +215,7 @@ extern long arith (const char *startbuf, int *errcode);
215int read_package_field(const char *package_buffer, char **field_name, char **field_value); 215int read_package_field(const char *package_buffer, char **field_name, char **field_value);
216char *fgets_str(FILE *file, const char *terminating_string); 216char *fgets_str(FILE *file, const char *terminating_string);
217 217
218extern int inflate(FILE *in, FILE *out);
218extern int unzip(FILE *l_in_file, FILE *l_out_file); 219extern int unzip(FILE *l_in_file, FILE *l_out_file);
219extern void gz_close(int gunzip_pid); 220extern void gz_close(int gunzip_pid);
220extern FILE *gz_open(FILE *compressed_file, int *pid); 221extern FILE *gz_open(FILE *compressed_file, int *pid);
diff --git a/include/unarchive.h b/include/unarchive.h
index be49f3d01..eada1c337 100644
--- a/include/unarchive.h
+++ b/include/unarchive.h
@@ -26,11 +26,13 @@ typedef struct file_headers_s {
26 mode_t mode; 26 mode_t mode;
27 time_t mtime; 27 time_t mtime;
28 dev_t device; 28 dev_t device;
29 int (*extract_func)(FILE *, FILE *);
29} file_header_t; 30} file_header_t;
30 31
31file_header_t *get_header_ar(FILE *in_file); 32file_header_t *get_header_ar(FILE *in_file);
32file_header_t *get_header_cpio(FILE *src_stream); 33file_header_t *get_header_cpio(FILE *src_stream);
33file_header_t *get_header_tar(FILE *tar_stream); 34file_header_t *get_header_tar(FILE *tar_stream);
35file_header_t *get_header_zip(FILE *zip_stream);
34 36
35void seek_sub_file(FILE *src_stream, const int count); 37void seek_sub_file(FILE *src_stream, const int count);
36 38
diff --git a/include/usage.h b/include/usage.h
index 20e2448fd..cd3af9c55 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1851,6 +1851,19 @@
1851 "\t-u\toutput will be in UNIX format\n" \ 1851 "\t-u\toutput will be in UNIX format\n" \
1852 "\t-d\toutput will be in DOS format" 1852 "\t-d\toutput will be in DOS format"
1853 1853
1854#define unzip_trivial_usage \
1855 "[-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir]"
1856#define unzip_full_usage \
1857 "Extracts files from ZIP archives\n" \
1858 "Options:\n" \
1859 "\t-l\tlist archive contents (short form)\n" \
1860 "\t-n\tnever overwrite existing files (default)\n" \
1861 "\t-o\toverwrite files without prompting\n" \
1862 "\t-p\tsend output to stdout\n" \
1863 "\t-q\tbe quiet\n" \
1864 "\t-x\texclude these files\n" \
1865 "\t-d\textract files into this directory"
1866
1854#define update_trivial_usage \ 1867#define update_trivial_usage \
1855 "[options]" 1868 "[options]"
1856#define update_full_usage \ 1869#define update_full_usage \
diff --git a/libbb/unzip.c b/libbb/unzip.c
index 6c28d181d..8075fd717 100644
--- a/libbb/unzip.c
+++ b/libbb/unzip.c
@@ -80,7 +80,7 @@ static const int ERROR = 1;
80 80
81/* 81/*
82 * window size--must be a power of two, and 82 * window size--must be a power of two, and
83 * at least 32K for zip's deflate method 83 * at least 32K for zip's deflate method
84 */ 84 */
85static const int WSIZE = 0x8000; 85static const int WSIZE = 0x8000;
86 86
@@ -846,7 +846,7 @@ static int inflate_block(int *e)
846 * 846 *
847 * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr 847 * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr
848 */ 848 */
849static int inflate(void) 849extern int inflate(FILE *in, FILE *out)
850{ 850{
851 int e; /* last block flag */ 851 int e; /* last block flag */
852 int r; /* result code */ 852 int r; /* result code */
@@ -857,6 +857,13 @@ static int inflate(void)
857 bk = 0; 857 bk = 0;
858 bb = 0; 858 bb = 0;
859 859
860 in_file = in;
861 out_file = out;
862
863 /* Allocate all global buffers (for DYN_ALLOC option) */
864 window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
865 bytes_out = 0L;
866
860 /* Create the crc table */ 867 /* Create the crc table */
861 make_crc_table(); 868 make_crc_table();
862 869
@@ -881,13 +888,15 @@ static int inflate(void)
881 888
882 /* flush out window */ 889 /* flush out window */
883 flush_window(); 890 flush_window();
891 free(window);
892 free(crc_table);
884 893
885 /* return success */ 894 /* return success */
886 return 0; 895 return 0;
887} 896}
888 897
889/* =========================================================================== 898/* ===========================================================================
890 * Unzip in to out. This routine works on both gzip and pkzip files. 899 * Unzip in to out. This routine works on gzip files only.
891 * 900 *
892 * IN assertions: the buffer inbuf contains already the beginning of 901 * IN assertions: the buffer inbuf contains already the beginning of
893 * the compressed data, from offsets inptr to insize-1 included. 902 * 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)
901 typedef void (*sig_type) (int); 910 typedef void (*sig_type) (int);
902 unsigned short i; 911 unsigned short i;
903 912
904 in_file = l_in_file;
905 out_file = l_out_file;
906
907 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 913 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
908 (void) signal(SIGINT, (sig_type) abort_gzip); 914 (void) signal(SIGINT, (sig_type) abort_gzip);
909 } 915 }
@@ -918,53 +924,48 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
918 } 924 }
919#endif 925#endif
920 926
921 /* Allocate all global buffers (for DYN_ALLOC option) */
922 window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char)));
923 outcnt = 0;
924 bytes_out = 0L;
925
926 /* Magic header for gzip files, 1F 8B = \037\213 */ 927 /* Magic header for gzip files, 1F 8B = \037\213 */
927 if ((fgetc(in_file) != 0x1F) || (fgetc(in_file) != 0x8b)) { 928 if ((fgetc(l_in_file) != 0x1F) || (fgetc(l_in_file) != 0x8b)) {
928 error_msg("Invalid gzip magic"); 929 error_msg("Invalid gzip magic");
929 return EXIT_FAILURE; 930 return EXIT_FAILURE;
930 } 931 }
931 932
932 /* Check the compression method */ 933 /* Check the compression method */
933 if (fgetc(in_file) != 8) { 934 if (fgetc(l_in_file) != 8) {
934 error_msg("Unknown compression method"); 935 error_msg("Unknown compression method");
935 return(-1); 936 return(-1);
936 } 937 }
937 938
938 flags = (unsigned char) fgetc(in_file); 939 flags = (unsigned char) fgetc(l_in_file);
939 940
940 /* Ignore time stamp(4), extra flags(1), OS type(1) */ 941 /* Ignore time stamp(4), extra flags(1), OS type(1) */
941 for (i = 0; i < 6; i++) { 942 for (i = 0; i < 6; i++) {
942 fgetc(in_file); 943 fgetc(l_in_file);
943 } 944 }
944 945
945 if (flags & 0x04) { 946 if (flags & 0x04) {
946 /* bit 2 set: extra field present */ 947 /* bit 2 set: extra field present */
947 const unsigned short extra = fgetc(in_file) + (fgetc(in_file) << 8); 948 const unsigned short extra = fgetc(l_in_file) + (fgetc(l_in_file) << 8);
948 949
949 for (i = 0; i < extra; i++) { 950 for (i = 0; i < extra; i++) {
950 fgetc(in_file); 951 fgetc(l_in_file);
951 } 952 }
952 } 953 }
953 954
954 /* Discard original name if any */ 955 /* Discard original name if any */
955 if (flags & 0x08) { 956 if (flags & 0x08) {
956 /* bit 3 set: original file name present */ 957 /* bit 3 set: original file name present */
957 while (fgetc(in_file) != 0); /* null */ 958 while (fgetc(l_in_file) != 0); /* null */
958 } 959 }
959 960
960 /* Discard file comment if any */ 961 /* Discard file comment if any */
961 if (flags & 0x10) { 962 if (flags & 0x10) {
962 /* bit 4 set: file comment present */ 963 /* bit 4 set: file comment present */
963 while (fgetc(in_file) != 0); /* null */ 964 while (fgetc(l_in_file) != 0); /* null */
964 } 965 }
965 966
966 /* Decompress */ 967 /* Decompress */
967 if (inflate() != 0) { 968 if (inflate(l_in_file, l_out_file) != 0) {
968 error_msg("invalid compressed data--format violated"); 969 error_msg("invalid compressed data--format violated");
969 } 970 }
970 971
@@ -972,7 +973,7 @@ extern int unzip(FILE *l_in_file, FILE *l_out_file)
972 * crc32 (see algorithm.doc) 973 * crc32 (see algorithm.doc)
973 * uncompressed input size modulo 2^32 974 * uncompressed input size modulo 2^32
974 */ 975 */
975 fread(buf, 1, 8, in_file); 976 fread(buf, 1, 8, l_in_file);
976 977
977 /* Validate decompression - crc */ 978 /* Validate decompression - crc */
978 if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { 979 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)
983 error_msg("invalid compressed data--length error"); 984 error_msg("invalid compressed data--length error");
984 } 985 }
985 986
986 free(window);
987 free(crc_table);
988
989 return 0; 987 return 0;
990} 988}
991 989
992/* 990/*
993 * This needs access to global variables wondow and crc_table, so its not in its own file. 991 * This needs access to global variables window and crc_table, so its not in its own file.
994 */ 992 */
995extern void gz_close(int gunzip_pid) 993extern void gz_close(int gunzip_pid)
996{ 994{