diff options
author | nobody <nobody@localhost> | 2004-10-13 09:42:10 +0000 |
---|---|---|
committer | nobody <nobody@localhost> | 2004-10-13 09:42:10 +0000 |
commit | 8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373 (patch) | |
tree | 1826706cd4fd009fcd14f4f8021005ec8ec0fa59 /busybox/archival | |
download | busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.tar.gz busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.tar.bz2 busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.zip |
This commit was manufactured by cvs2svn to create tag 'busybox_1_00'.
Diffstat (limited to 'busybox/archival')
46 files changed, 10404 insertions, 0 deletions
diff --git a/busybox/archival/Config.in b/busybox/archival/Config.in new file mode 100644 index 000000000..db358db08 --- /dev/null +++ b/busybox/archival/Config.in | |||
@@ -0,0 +1,258 @@ | |||
1 | # | ||
2 | # For a description of the syntax of this configuration file, | ||
3 | # see scripts/kbuild/config-language.txt. | ||
4 | # | ||
5 | |||
6 | menu "Archival Utilities" | ||
7 | |||
8 | config CONFIG_AR | ||
9 | bool "ar" | ||
10 | default n | ||
11 | help | ||
12 | ar is an archival utility program used to create, modify, and | ||
13 | extract contents from archives. An archive is a single file holding | ||
14 | a collection of other files in a structure that makes it possible to | ||
15 | retrieve the original individual files (called archive members). | ||
16 | The original files' contents, mode (permissions), timestamp, owner, | ||
17 | and group are preserved in the archive, and can be restored on | ||
18 | extraction. | ||
19 | |||
20 | The stored filename is limited to 15 characters. (for more information | ||
21 | see long filename support). | ||
22 | ar has 60 bytes of overheads for every stored file. | ||
23 | |||
24 | This implementation of ar can extract archives, it cannot create or | ||
25 | modify them. | ||
26 | On an x86 system, the ar applet adds about 1K. | ||
27 | |||
28 | Unless you have a specific application which requires ar, you should | ||
29 | probably say N here. | ||
30 | |||
31 | config CONFIG_FEATURE_AR_LONG_FILENAMES | ||
32 | bool " Enable support for long filenames (not need for debs)" | ||
33 | default n | ||
34 | depends on CONFIG_AR | ||
35 | help | ||
36 | By default the ar format can only store the first 15 characters of the | ||
37 | filename, this option removes that limitation. | ||
38 | It supports the GNU ar long filename method which moves multiple long | ||
39 | filenames into a the data section of a new ar entry. | ||
40 | |||
41 | config CONFIG_BUNZIP2 | ||
42 | bool "bunzip2" | ||
43 | default n | ||
44 | help | ||
45 | bunzip2 is a compression utility using the Burrows-Wheeler block | ||
46 | sorting text compression algorithm, and Huffman coding. Compression | ||
47 | is generally considerably better than that achieved by more | ||
48 | conventional LZ77/LZ78-based compressors, and approaches the | ||
49 | performance of the PPM family of statistical compressors. | ||
50 | |||
51 | The BusyBox bunzip2 applet is limited to de-compression only. | ||
52 | On an x86 system, this applet adds about 11K. | ||
53 | |||
54 | Unless you have a specific application which requires bunzip2, you | ||
55 | should probably say N here. | ||
56 | |||
57 | config CONFIG_CPIO | ||
58 | bool "cpio" | ||
59 | default n | ||
60 | help | ||
61 | cpio is an archival utility program used to create, modify, and extract | ||
62 | contents from archives. | ||
63 | cpio has 110 bytes of overheads for every stored file. | ||
64 | |||
65 | This implementation of cpio can extract cpio archives created in the | ||
66 | "newc" or "crc" format, it cannot create or modify them. | ||
67 | |||
68 | Unless you have a specific application which requires cpio, you should | ||
69 | probably say N here. | ||
70 | |||
71 | config CONFIG_DPKG | ||
72 | bool "dpkg" | ||
73 | default n | ||
74 | help | ||
75 | dpkg is a medium-level tool to install, build, remove and manage Debian packages. | ||
76 | |||
77 | This implementation of dpkg has a number of limitations, you should use the | ||
78 | official dpkg if possible. | ||
79 | |||
80 | config CONFIG_DPKG_DEB | ||
81 | bool "dpkg_deb" | ||
82 | default n | ||
83 | help | ||
84 | dpkg-deb packs, unpacks and provides information about Debian archives. | ||
85 | |||
86 | This implementation of dpkg-deb cannot pack archives. | ||
87 | |||
88 | Unless you have a specific application which requires dpkg-deb, you should | ||
89 | probably say N here. | ||
90 | |||
91 | config CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY | ||
92 | bool " extract only (-x)" | ||
93 | default n | ||
94 | depends on CONFIG_DPKG_DEB | ||
95 | help | ||
96 | This reduces dpkg-deb to the equivalent of "ar -p <deb> data.tar.gz | tar -zx". | ||
97 | However it saves space as none of the extra dpkg-deb, ar or tar options are | ||
98 | needed, they are linked to internally. | ||
99 | |||
100 | config CONFIG_GUNZIP | ||
101 | bool "gunzip" | ||
102 | default n | ||
103 | help | ||
104 | gunzip is used to decompress archives created by gzip. | ||
105 | You can use the `-t' option to test the integrity of | ||
106 | an archive, without decompressing it. | ||
107 | |||
108 | config CONFIG_FEATURE_GUNZIP_UNCOMPRESS | ||
109 | bool " Uncompress support" | ||
110 | default n | ||
111 | depends on CONFIG_GUNZIP | ||
112 | help | ||
113 | Enable if you want gunzip to have the ability to decompress | ||
114 | archives created by the program compress (not much | ||
115 | used anymore). | ||
116 | |||
117 | config CONFIG_GZIP | ||
118 | bool "gzip" | ||
119 | default n | ||
120 | help | ||
121 | gzip is used to compress files. | ||
122 | It's probably the most widely used UNIX compression program. | ||
123 | |||
124 | config CONFIG_RPM2CPIO | ||
125 | bool "rpm2cpio" | ||
126 | default n | ||
127 | help | ||
128 | Converts an RPM file into a CPIO archive. | ||
129 | |||
130 | config CONFIG_RPM | ||
131 | bool "rpm" | ||
132 | default n | ||
133 | help | ||
134 | Mini RPM applet - queries and extracts | ||
135 | |||
136 | config CONFIG_TAR | ||
137 | bool "tar" | ||
138 | default n | ||
139 | help | ||
140 | tar is an archiving program. It's commonly used with gzip to | ||
141 | create compressed archives. It's probably the most widely used | ||
142 | UNIX archive program. | ||
143 | |||
144 | config CONFIG_FEATURE_TAR_CREATE | ||
145 | bool " Enable archive creation" | ||
146 | default y | ||
147 | depends on CONFIG_TAR | ||
148 | help | ||
149 | If you enable this option you'll be able to create | ||
150 | tar archives using the `-c' option. | ||
151 | |||
152 | config CONFIG_FEATURE_TAR_BZIP2 | ||
153 | bool " Enable -j option to handle .tar.bz2 files" | ||
154 | default n | ||
155 | depends on CONFIG_TAR | ||
156 | help | ||
157 | If you enable this option you'll be able to extract | ||
158 | archives compressed with bzip2. | ||
159 | |||
160 | config CONFIG_FEATURE_TAR_FROM | ||
161 | bool " Enable -X (exclude from) and -T (include from) options)" | ||
162 | default n | ||
163 | depends on CONFIG_TAR | ||
164 | help | ||
165 | If you enable this option you'll be able to specify | ||
166 | a list of files to include or exclude from an archive. | ||
167 | |||
168 | config CONFIG_FEATURE_TAR_GZIP | ||
169 | bool " Enable -z option" | ||
170 | default y | ||
171 | depends on CONFIG_TAR | ||
172 | help | ||
173 | If you enable this option tar will be able to call gzip, | ||
174 | when creating or extracting tar gziped archives. | ||
175 | |||
176 | config CONFIG_FEATURE_TAR_COMPRESS | ||
177 | bool " Enable -Z option" | ||
178 | default n | ||
179 | depends on CONFIG_TAR | ||
180 | help | ||
181 | If you enable this option tar will be able to call uncompress, | ||
182 | when extracting .tar.Z archives. | ||
183 | |||
184 | config CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY | ||
185 | bool " Enable support for old tar header format" | ||
186 | default N | ||
187 | depends on CONFIG_TAR | ||
188 | help | ||
189 | This option is required to unpack archives created in | ||
190 | the old GNU format; help to kill this old format by | ||
191 | repacking your ancient archives with the new format. | ||
192 | |||
193 | config CONFIG_FEATURE_TAR_GNU_EXTENSIONS | ||
194 | bool " Enable support for some GNU tar extensions" | ||
195 | default y | ||
196 | depends on CONFIG_TAR | ||
197 | help | ||
198 | With this option busybox supports GNU long filenames and | ||
199 | linknames. | ||
200 | |||
201 | config CONFIG_FEATURE_TAR_LONG_OPTIONS | ||
202 | bool " Enable long options" | ||
203 | default n | ||
204 | depends on CONFIG_TAR | ||
205 | help | ||
206 | Enable use of long options, increases size by about 400 Bytes | ||
207 | |||
208 | config CONFIG_UNCOMPRESS | ||
209 | bool "uncompress" | ||
210 | default n | ||
211 | help | ||
212 | uncompress is used to decompress archives created by compress. | ||
213 | Not much used anymore, replaced by gzip/gunzip. | ||
214 | |||
215 | config CONFIG_UNZIP | ||
216 | bool "unzip" | ||
217 | default n | ||
218 | help | ||
219 | unzip will list or extract files from a ZIP archive, | ||
220 | commonly found on DOS/WIN systems. The default behavior | ||
221 | (with no options) is to extract the archive into the | ||
222 | current directory. Use the `-d' option to extract to a | ||
223 | directory of your choice. | ||
224 | |||
225 | comment "Common options for cpio and tar" | ||
226 | depends on CONFIG_CPIO || CONFIG_TAR | ||
227 | |||
228 | config CONFIG_FEATURE_UNARCHIVE_TAPE | ||
229 | bool " Enable tape drive support" | ||
230 | default n | ||
231 | depends on CONFIG_CPIO || CONFIG_TAR | ||
232 | help | ||
233 | I don't think this is needed anymore. | ||
234 | |||
235 | comment "Common options for dpkg and dpkg_deb" | ||
236 | depends on CONFIG_DPKG || CONFIG_DPKG_DEB | ||
237 | |||
238 | config CONFIG_FEATURE_DEB_TAR_GZ | ||
239 | bool " gzip debian packages (normal)" | ||
240 | default y if CONFIG_DPKG || CONFIG_DPKG_DEB | ||
241 | depends on CONFIG_DPKG || CONFIG_DPKG_DEB | ||
242 | help | ||
243 | This is the default compression method inside the debian ar file. | ||
244 | |||
245 | If you want compatibility with standard .deb's you should say yes here. | ||
246 | |||
247 | config CONFIG_FEATURE_DEB_TAR_BZ2 | ||
248 | bool " bzip2 debian packages" | ||
249 | default n | ||
250 | depends on CONFIG_DPKG || CONFIG_DPKG_DEB | ||
251 | help | ||
252 | This allows dpkg and dpkg-deb to extract deb's that are compressed internally | ||
253 | with bzip2 instead of gzip. | ||
254 | |||
255 | You only want this if you are creating your own custom debian packages that | ||
256 | use an internal control.tar.bz2 or data.tar.bz2. | ||
257 | |||
258 | endmenu | ||
diff --git a/busybox/archival/Makefile b/busybox/archival/Makefile new file mode 100644 index 000000000..a96daa4df --- /dev/null +++ b/busybox/archival/Makefile | |||
@@ -0,0 +1,32 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | # | ||
19 | |||
20 | top_srcdir=.. | ||
21 | top_builddir=.. | ||
22 | ARCHIVAL_DIR:=./ | ||
23 | srcdir=$(top_srcdir)/archival | ||
24 | include $(top_builddir)/Rules.mak | ||
25 | include $(top_builddir)/.config | ||
26 | include $(srcdir)/Makefile.in | ||
27 | all: $(libraries-y) | ||
28 | -include $(top_builddir)/.depend | ||
29 | |||
30 | clean: | ||
31 | rm -f *.o *.a $(AR_TARGET) | ||
32 | |||
diff --git a/busybox/archival/Makefile.in b/busybox/archival/Makefile.in new file mode 100644 index 000000000..76ab6cd08 --- /dev/null +++ b/busybox/archival/Makefile.in | |||
@@ -0,0 +1,48 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | # | ||
19 | |||
20 | ARCHIVAL_AR:=archival.a | ||
21 | ifndef $(ARCHIVAL_DIR) | ||
22 | ARCHIVAL_DIR:=$(top_builddir)/archival/ | ||
23 | endif | ||
24 | srcdir=$(top_srcdir)/archival | ||
25 | |||
26 | ARCHIVAL-y:= | ||
27 | ARCHIVAL-$(CONFIG_APT_GET) += | ||
28 | ARCHIVAL-$(CONFIG_AR) += ar.o | ||
29 | ARCHIVAL-$(CONFIG_BUNZIP2) += bunzip2.o | ||
30 | ARCHIVAL-$(CONFIG_CPIO) += cpio.o | ||
31 | ARCHIVAL-$(CONFIG_DPKG) += dpkg.o | ||
32 | ARCHIVAL-$(CONFIG_DPKG_DEB) += dpkg_deb.o | ||
33 | ARCHIVAL-$(CONFIG_GUNZIP) += gunzip.o | ||
34 | ARCHIVAL-$(CONFIG_GZIP) += gzip.o | ||
35 | ARCHIVAL-$(CONFIG_RPM2CPIO) += rpm2cpio.o | ||
36 | ARCHIVAL-$(CONFIG_RPM) += rpm.o | ||
37 | ARCHIVAL-$(CONFIG_TAR) += tar.o | ||
38 | ARCHIVAL-$(CONFIG_UNCOMPRESS) += uncompress.o | ||
39 | ARCHIVAL-$(CONFIG_UNZIP) += unzip.o | ||
40 | |||
41 | libraries-y+=$(ARCHIVAL_DIR)$(ARCHIVAL_AR) | ||
42 | |||
43 | $(ARCHIVAL_DIR)$(ARCHIVAL_AR): $(patsubst %,$(ARCHIVAL_DIR)%, $(ARCHIVAL-y)) | ||
44 | $(AR) -ro $@ $(patsubst %,$(ARCHIVAL_DIR)%, $(ARCHIVAL-y)) | ||
45 | |||
46 | $(ARCHIVAL_DIR)%.o: $(srcdir)/%.c | ||
47 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< | ||
48 | |||
diff --git a/busybox/archival/ar.c b/busybox/archival/ar.c new file mode 100644 index 000000000..44c5db035 --- /dev/null +++ b/busybox/archival/ar.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini ar implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2000 by Glenn McGrath | ||
6 | * Written by Glenn McGrath <bug1@iinet.net.au> 1 June 2000 | ||
7 | * | ||
8 | * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * There is no single standard to adhere to so ar may not portable | ||
25 | * between different systems | ||
26 | * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html | ||
27 | */ | ||
28 | |||
29 | #include <fcntl.h> | ||
30 | #include <getopt.h> | ||
31 | #include <stdio.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <time.h> | ||
35 | #include <utime.h> | ||
36 | #include <unistd.h> | ||
37 | |||
38 | #include "unarchive.h" | ||
39 | #include "busybox.h" | ||
40 | |||
41 | static void header_verbose_list_ar(const file_header_t *file_header) | ||
42 | { | ||
43 | const char *mode = bb_mode_string(file_header->mode); | ||
44 | char *mtime; | ||
45 | |||
46 | mtime = ctime(&file_header->mtime); | ||
47 | mtime[16] = ' '; | ||
48 | memmove(&mtime[17], &mtime[20], 4); | ||
49 | mtime[21] = '\0'; | ||
50 | printf("%s %d/%d%7d %s %s\n", &mode[1], file_header->uid, file_header->gid, (int) file_header->size, &mtime[4], file_header->name); | ||
51 | } | ||
52 | |||
53 | #define AR_CTX_PRINT 0x01 | ||
54 | #define AR_CTX_LIST 0x02 | ||
55 | #define AR_CTX_EXTRACT 0x04 | ||
56 | #define AR_OPT_PRESERVE_DATE 0x08 | ||
57 | #define AR_OPT_VERBOSE 0x10 | ||
58 | #define AR_OPT_CREATE 0x20 | ||
59 | |||
60 | extern int ar_main(int argc, char **argv) | ||
61 | { | ||
62 | archive_handle_t *archive_handle; | ||
63 | unsigned long opt; | ||
64 | char magic[8]; | ||
65 | |||
66 | archive_handle = init_handle(); | ||
67 | |||
68 | bb_opt_complementaly = "p~tx:t~px:x~pt"; | ||
69 | opt = bb_getopt_ulflags(argc, argv, "ptxovc"); | ||
70 | |||
71 | if ((opt & 0x80000000UL) || (optind == argc)) { | ||
72 | bb_show_usage(); | ||
73 | } | ||
74 | |||
75 | if (opt & AR_CTX_PRINT) { | ||
76 | archive_handle->action_data = data_extract_to_stdout; | ||
77 | } | ||
78 | if (opt & AR_CTX_LIST) { | ||
79 | archive_handle->action_header = header_list; | ||
80 | } | ||
81 | if (opt & AR_CTX_EXTRACT) { | ||
82 | archive_handle->action_data = data_extract_all; | ||
83 | } | ||
84 | if (opt & AR_OPT_PRESERVE_DATE) { | ||
85 | archive_handle->flags |= ARCHIVE_PRESERVE_DATE; | ||
86 | } | ||
87 | if (opt & AR_OPT_VERBOSE) { | ||
88 | archive_handle->action_header = header_verbose_list_ar; | ||
89 | } | ||
90 | if (opt & AR_OPT_CREATE) { | ||
91 | bb_error_msg_and_die("Archive creation not supported. Install binutils 'ar'."); | ||
92 | } | ||
93 | |||
94 | archive_handle->src_fd = bb_xopen(argv[optind++], O_RDONLY); | ||
95 | |||
96 | while (optind < argc) { | ||
97 | archive_handle->filter = filter_accept_list; | ||
98 | archive_handle->accept = llist_add_to(archive_handle->accept, argv[optind++]); | ||
99 | } | ||
100 | |||
101 | archive_xread_all(archive_handle, magic, 7); | ||
102 | if (strncmp(magic, "!<arch>", 7) != 0) { | ||
103 | bb_error_msg_and_die("Invalid ar magic"); | ||
104 | } | ||
105 | archive_handle->offset += 7; | ||
106 | |||
107 | while (get_header_ar(archive_handle) == EXIT_SUCCESS); | ||
108 | |||
109 | return EXIT_SUCCESS; | ||
110 | } | ||
diff --git a/busybox/archival/bunzip2.c b/busybox/archival/bunzip2.c new file mode 100644 index 000000000..bedd38c22 --- /dev/null +++ b/busybox/archival/bunzip2.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Modified for busybox by Glenn McGrath <bug1@iinet.net.au> | ||
3 | * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <fcntl.h> | ||
21 | #include <getopt.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <unistd.h> | ||
26 | |||
27 | #include "busybox.h" | ||
28 | #include "unarchive.h" | ||
29 | |||
30 | #define BUNZIP2_OPT_STDOUT 1 | ||
31 | #define BUNZIP2_OPT_FORCE 2 | ||
32 | |||
33 | int bunzip2_main(int argc, char **argv) | ||
34 | { | ||
35 | char *compressed_name; | ||
36 | /* Note: Ignore the warning about save_name being used uninitialized. | ||
37 | * That is not the case, but gcc has trouble working that out... */ | ||
38 | char *save_name; | ||
39 | unsigned long opt; | ||
40 | int status; | ||
41 | int src_fd; | ||
42 | int dst_fd; | ||
43 | |||
44 | opt = bb_getopt_ulflags(argc, argv, "cf"); | ||
45 | |||
46 | /* if called as bzcat force the stdout flag */ | ||
47 | if (bb_applet_name[2] == 'c') { | ||
48 | opt |= BUNZIP2_OPT_STDOUT; | ||
49 | } | ||
50 | |||
51 | /* Set input filename and number */ | ||
52 | compressed_name = argv[optind]; | ||
53 | if ((compressed_name) && (compressed_name[0] != '-') && (compressed_name[1] != '\0')) { | ||
54 | /* Open input file */ | ||
55 | src_fd = bb_xopen(compressed_name, O_RDONLY); | ||
56 | } else { | ||
57 | src_fd = STDIN_FILENO; | ||
58 | opt |= BUNZIP2_OPT_STDOUT; | ||
59 | } | ||
60 | |||
61 | /* Check that the input is sane. */ | ||
62 | if (isatty(src_fd) && (opt & BUNZIP2_OPT_FORCE) == 0) { | ||
63 | bb_error_msg_and_die("compressed data not read from terminal. Use -f to force it."); | ||
64 | } | ||
65 | |||
66 | if (opt & BUNZIP2_OPT_STDOUT) { | ||
67 | dst_fd = STDOUT_FILENO; | ||
68 | } else { | ||
69 | int len = strlen(compressed_name) - 4; | ||
70 | if (strcmp(compressed_name + len, ".bz2") != 0) { | ||
71 | bb_error_msg_and_die("Invalid extension"); | ||
72 | } | ||
73 | save_name = bb_xstrndup(compressed_name, len); | ||
74 | dst_fd = bb_xopen(save_name, O_WRONLY | O_CREAT); | ||
75 | } | ||
76 | |||
77 | status = uncompressStream(src_fd, dst_fd); | ||
78 | if(!(opt & BUNZIP2_OPT_STDOUT)) { | ||
79 | char *delete_name; | ||
80 | if (status) { | ||
81 | delete_name = save_name; | ||
82 | } else { | ||
83 | delete_name = compressed_name; | ||
84 | } | ||
85 | if (unlink(delete_name) < 0) { | ||
86 | bb_error_msg_and_die("Couldn't remove %s", delete_name); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | return status; | ||
91 | } | ||
diff --git a/busybox/archival/cpio.c b/busybox/archival/cpio.c new file mode 100644 index 000000000..0fbe7b8e5 --- /dev/null +++ b/busybox/archival/cpio.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini cpio implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2001 by Glenn McGrath | ||
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 | * Limitations: | ||
22 | * Doesn't check CRC's | ||
23 | * Only supports new ASCII and CRC formats | ||
24 | * | ||
25 | */ | ||
26 | #include <fcntl.h> | ||
27 | #include <getopt.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include <unistd.h> | ||
31 | #include "unarchive.h" | ||
32 | #include "busybox.h" | ||
33 | |||
34 | #define CPIO_OPT_EXTRACT 0x01 | ||
35 | #define CPIO_OPT_TEST 0x02 | ||
36 | #define CPIO_OPT_UNCONDITIONAL 0x04 | ||
37 | #define CPIO_OPT_VERBOSE 0x08 | ||
38 | #define CPIO_OPT_FILE 0x10 | ||
39 | #define CPIO_OPT_CREATE_LEADING_DIR 0x20 | ||
40 | #define CPIO_OPT_PRESERVE_MTIME 0x40 | ||
41 | |||
42 | extern int cpio_main(int argc, char **argv) | ||
43 | { | ||
44 | archive_handle_t *archive_handle; | ||
45 | char *cpio_filename = NULL; | ||
46 | unsigned long opt; | ||
47 | |||
48 | /* Initialise */ | ||
49 | archive_handle = init_handle(); | ||
50 | archive_handle->src_fd = STDIN_FILENO; | ||
51 | archive_handle->seek = seek_by_char; | ||
52 | archive_handle->flags = ARCHIVE_EXTRACT_NEWER | ARCHIVE_PRESERVE_DATE; | ||
53 | |||
54 | opt = bb_getopt_ulflags(argc, argv, "ituvF:dm", &cpio_filename); | ||
55 | |||
56 | /* One of either extract or test options must be given */ | ||
57 | if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { | ||
58 | bb_show_usage(); | ||
59 | } | ||
60 | |||
61 | if (opt & CPIO_OPT_TEST) { | ||
62 | /* if both extract and test option are given, ignore extract option */ | ||
63 | if (opt & CPIO_OPT_EXTRACT) { | ||
64 | opt &= ~CPIO_OPT_EXTRACT; | ||
65 | } | ||
66 | archive_handle->action_header = header_list; | ||
67 | } | ||
68 | if (opt & CPIO_OPT_EXTRACT) { | ||
69 | archive_handle->action_data = data_extract_all; | ||
70 | } | ||
71 | if (opt & CPIO_OPT_UNCONDITIONAL) { | ||
72 | archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; | ||
73 | archive_handle->flags &= ~ARCHIVE_EXTRACT_NEWER; | ||
74 | } | ||
75 | if (opt & CPIO_OPT_VERBOSE) { | ||
76 | if (archive_handle->action_header == header_list) { | ||
77 | archive_handle->action_header = header_verbose_list; | ||
78 | } else { | ||
79 | archive_handle->action_header = header_list; | ||
80 | } | ||
81 | } | ||
82 | if (cpio_filename) { /* CPIO_OPT_FILE */ | ||
83 | archive_handle->src_fd = bb_xopen(cpio_filename, O_RDONLY); | ||
84 | archive_handle->seek = seek_by_jump; | ||
85 | } | ||
86 | if (opt & CPIO_OPT_CREATE_LEADING_DIR) { | ||
87 | archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS; | ||
88 | } | ||
89 | |||
90 | while (optind < argc) { | ||
91 | archive_handle->filter = filter_accept_list; | ||
92 | archive_handle->accept = llist_add_to(archive_handle->accept, argv[optind]); | ||
93 | optind++; | ||
94 | } | ||
95 | |||
96 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS); | ||
97 | |||
98 | return(EXIT_SUCCESS); | ||
99 | } | ||
diff --git a/busybox/archival/dpkg.c b/busybox/archival/dpkg.c new file mode 100644 index 000000000..c096518a2 --- /dev/null +++ b/busybox/archival/dpkg.c | |||
@@ -0,0 +1,1833 @@ | |||
1 | /* | ||
2 | * Mini dpkg implementation for busybox. | ||
3 | * This is not meant as a replacement for dpkg | ||
4 | * | ||
5 | * Written By Glenn McGrath with the help of others | ||
6 | * Copyright (C) 2001 by Glenn McGrath | ||
7 | * | ||
8 | * Started life as a busybox implementation of udpkg | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU Library General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * Known difference between busybox dpkg and the official dpkg that i don't | ||
27 | * consider important, its worth keeping a note of differences anyway, just to | ||
28 | * make it easier to maintain. | ||
29 | * - The first value for the Confflile: field isnt placed on a new line. | ||
30 | * - When installing a package the Status: field is placed at the end of the | ||
31 | * section, rather than just after the Package: field. | ||
32 | * | ||
33 | * Bugs that need to be fixed | ||
34 | * - (unknown, please let me know when you find any) | ||
35 | * | ||
36 | */ | ||
37 | |||
38 | #include <fcntl.h> | ||
39 | #include <getopt.h> | ||
40 | #include <stdlib.h> | ||
41 | #include <string.h> | ||
42 | #include <unistd.h> | ||
43 | #include "unarchive.h" | ||
44 | #include "busybox.h" | ||
45 | |||
46 | /* NOTE: If you vary HASH_PRIME sizes be aware, | ||
47 | * 1) Tweaking these will have a big effect on how much memory this program uses. | ||
48 | * 2) For computational efficiency these hash tables should be at least 20% | ||
49 | * larger than the maximum number of elements stored in it. | ||
50 | * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking | ||
51 | * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt | ||
52 | * 4) If you go bigger than 15 bits you may get into trouble (untested) as its | ||
53 | * sometimes cast to an unsigned int, if you go to 16 bit you will overlap | ||
54 | * int's and chaos is assured, 16381 is the max prime for 14 bit field | ||
55 | */ | ||
56 | |||
57 | /* NAME_HASH_PRIME, Stores package names and versions, | ||
58 | * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME, | ||
59 | * as there a lot of duplicate version numbers */ | ||
60 | #define NAME_HASH_PRIME 16381 | ||
61 | char *name_hashtable[NAME_HASH_PRIME + 1]; | ||
62 | |||
63 | /* PACKAGE_HASH_PRIME, Maximum number of unique packages, | ||
64 | * It must not be smaller than STATUS_HASH_PRIME, | ||
65 | * Currently only packages from status_hashtable are stored in here, but in | ||
66 | * future this may be used to store packages not only from a status file, | ||
67 | * but an available_hashtable, and even multiple packages files. | ||
68 | * Package can be stored more than once if they have different versions. | ||
69 | * e.g. The same package may have different versions in the status file | ||
70 | * and available file */ | ||
71 | #define PACKAGE_HASH_PRIME 10007 | ||
72 | typedef struct edge_s { | ||
73 | unsigned int operator:3; | ||
74 | unsigned int type:4; | ||
75 | unsigned int name:14; | ||
76 | unsigned int version:14; | ||
77 | } edge_t; | ||
78 | |||
79 | typedef struct common_node_s { | ||
80 | unsigned int name:14; | ||
81 | unsigned int version:14; | ||
82 | unsigned int num_of_edges:14; | ||
83 | edge_t **edge; | ||
84 | } common_node_t; | ||
85 | common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; | ||
86 | |||
87 | /* Currently it doesnt store packages that have state-status of not-installed | ||
88 | * So it only really has to be the size of the maximum number of packages | ||
89 | * likely to be installed at any one time, so there is a bit of leeway here */ | ||
90 | #define STATUS_HASH_PRIME 8191 | ||
91 | typedef struct status_node_s { | ||
92 | unsigned int package:14; /* has to fit PACKAGE_HASH_PRIME */ | ||
93 | unsigned int status:14; /* has to fit STATUS_HASH_PRIME */ | ||
94 | } status_node_t; | ||
95 | status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; | ||
96 | |||
97 | /* Even numbers are for 'extras', like ored dependencies or null */ | ||
98 | enum edge_type_e { | ||
99 | EDGE_NULL = 0, | ||
100 | EDGE_PRE_DEPENDS = 1, | ||
101 | EDGE_OR_PRE_DEPENDS = 2, | ||
102 | EDGE_DEPENDS = 3, | ||
103 | EDGE_OR_DEPENDS = 4, | ||
104 | EDGE_REPLACES = 5, | ||
105 | EDGE_PROVIDES = 7, | ||
106 | EDGE_CONFLICTS = 9, | ||
107 | EDGE_SUGGESTS = 11, | ||
108 | EDGE_RECOMMENDS = 13, | ||
109 | EDGE_ENHANCES = 15 | ||
110 | }; | ||
111 | enum operator_e { | ||
112 | VER_NULL = 0, | ||
113 | VER_EQUAL = 1, | ||
114 | VER_LESS = 2, | ||
115 | VER_LESS_EQUAL = 3, | ||
116 | VER_MORE = 4, | ||
117 | VER_MORE_EQUAL = 5, | ||
118 | VER_ANY = 6 | ||
119 | }; | ||
120 | |||
121 | enum dpkg_opt_e { | ||
122 | dpkg_opt_purge = 1, | ||
123 | dpkg_opt_remove = 2, | ||
124 | dpkg_opt_unpack = 4, | ||
125 | dpkg_opt_configure = 8, | ||
126 | dpkg_opt_install = 16, | ||
127 | dpkg_opt_package_name = 32, | ||
128 | dpkg_opt_filename = 64, | ||
129 | dpkg_opt_list_installed = 128, | ||
130 | dpkg_opt_force_ignore_depends = 256 | ||
131 | }; | ||
132 | |||
133 | typedef struct deb_file_s { | ||
134 | char *control_file; | ||
135 | char *filename; | ||
136 | unsigned int package:14; | ||
137 | } deb_file_t; | ||
138 | |||
139 | |||
140 | void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime) | ||
141 | { | ||
142 | unsigned long int hash_num = key[0]; | ||
143 | int len = strlen(key); | ||
144 | int i; | ||
145 | |||
146 | /* Maybe i should have uses a "proper" hashing algorithm here instead | ||
147 | * of making one up myself, seems to be working ok though. */ | ||
148 | for(i = 1; i < len; i++) { | ||
149 | /* shifts the ascii based value and adds it to previous value | ||
150 | * shift amount is mod 24 because long int is 32 bit and data | ||
151 | * to be shifted is 8, don't want to shift data to where it has | ||
152 | * no effect*/ | ||
153 | hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); | ||
154 | } | ||
155 | *start = (unsigned int) hash_num % hash_prime; | ||
156 | *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1)); | ||
157 | } | ||
158 | |||
159 | /* this adds the key to the hash table */ | ||
160 | int search_name_hashtable(const char *key) | ||
161 | { | ||
162 | unsigned int probe_address = 0; | ||
163 | unsigned int probe_decrement = 0; | ||
164 | // char *temp; | ||
165 | |||
166 | make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); | ||
167 | while(name_hashtable[probe_address] != NULL) { | ||
168 | if (strcmp(name_hashtable[probe_address], key) == 0) { | ||
169 | return(probe_address); | ||
170 | } else { | ||
171 | probe_address -= probe_decrement; | ||
172 | if ((int)probe_address < 0) { | ||
173 | probe_address += NAME_HASH_PRIME; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | name_hashtable[probe_address] = bb_xstrdup(key); | ||
178 | return(probe_address); | ||
179 | } | ||
180 | |||
181 | /* this DOESNT add the key to the hashtable | ||
182 | * TODO make it consistent with search_name_hashtable | ||
183 | */ | ||
184 | unsigned int search_status_hashtable(const char *key) | ||
185 | { | ||
186 | unsigned int probe_address = 0; | ||
187 | unsigned int probe_decrement = 0; | ||
188 | |||
189 | make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); | ||
190 | while(status_hashtable[probe_address] != NULL) { | ||
191 | if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) { | ||
192 | break; | ||
193 | } else { | ||
194 | probe_address -= probe_decrement; | ||
195 | if ((int)probe_address < 0) { | ||
196 | probe_address += STATUS_HASH_PRIME; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | return(probe_address); | ||
201 | } | ||
202 | |||
203 | /* Need to rethink version comparison, maybe the official dpkg has something i can use ? */ | ||
204 | int version_compare_part(const char *version1, const char *version2) | ||
205 | { | ||
206 | int upstream_len1 = 0; | ||
207 | int upstream_len2 = 0; | ||
208 | char *name1_char; | ||
209 | char *name2_char; | ||
210 | int len1 = 0; | ||
211 | int len2 = 0; | ||
212 | int tmp_int; | ||
213 | int ver_num1; | ||
214 | int ver_num2; | ||
215 | int ret; | ||
216 | |||
217 | if (version1 == NULL) { | ||
218 | version1 = bb_xstrdup(""); | ||
219 | } | ||
220 | if (version2 == NULL) { | ||
221 | version2 = bb_xstrdup(""); | ||
222 | } | ||
223 | upstream_len1 = strlen(version1); | ||
224 | upstream_len2 = strlen(version2); | ||
225 | |||
226 | while ((len1 < upstream_len1) || (len2 < upstream_len2)) { | ||
227 | /* Compare non-digit section */ | ||
228 | tmp_int = strcspn(&version1[len1], "0123456789"); | ||
229 | name1_char = bb_xstrndup(&version1[len1], tmp_int); | ||
230 | len1 += tmp_int; | ||
231 | tmp_int = strcspn(&version2[len2], "0123456789"); | ||
232 | name2_char = bb_xstrndup(&version2[len2], tmp_int); | ||
233 | len2 += tmp_int; | ||
234 | tmp_int = strcmp(name1_char, name2_char); | ||
235 | free(name1_char); | ||
236 | free(name2_char); | ||
237 | if (tmp_int != 0) { | ||
238 | ret = tmp_int; | ||
239 | goto cleanup_version_compare_part; | ||
240 | } | ||
241 | |||
242 | /* Compare digits */ | ||
243 | tmp_int = strspn(&version1[len1], "0123456789"); | ||
244 | name1_char = bb_xstrndup(&version1[len1], tmp_int); | ||
245 | len1 += tmp_int; | ||
246 | tmp_int = strspn(&version2[len2], "0123456789"); | ||
247 | name2_char = bb_xstrndup(&version2[len2], tmp_int); | ||
248 | len2 += tmp_int; | ||
249 | ver_num1 = atoi(name1_char); | ||
250 | ver_num2 = atoi(name2_char); | ||
251 | free(name1_char); | ||
252 | free(name2_char); | ||
253 | if (ver_num1 < ver_num2) { | ||
254 | ret = -1; | ||
255 | goto cleanup_version_compare_part; | ||
256 | } | ||
257 | else if (ver_num1 > ver_num2) { | ||
258 | ret = 1; | ||
259 | goto cleanup_version_compare_part; | ||
260 | } | ||
261 | } | ||
262 | ret = 0; | ||
263 | cleanup_version_compare_part: | ||
264 | return(ret); | ||
265 | } | ||
266 | |||
267 | /* if ver1 < ver2 return -1, | ||
268 | * if ver1 = ver2 return 0, | ||
269 | * if ver1 > ver2 return 1, | ||
270 | */ | ||
271 | int version_compare(const unsigned int ver1, const unsigned int ver2) | ||
272 | { | ||
273 | char *ch_ver1 = name_hashtable[ver1]; | ||
274 | char *ch_ver2 = name_hashtable[ver2]; | ||
275 | |||
276 | char epoch1, epoch2; | ||
277 | char *deb_ver1, *deb_ver2; | ||
278 | char *ver1_ptr, *ver2_ptr; | ||
279 | char *upstream_ver1; | ||
280 | char *upstream_ver2; | ||
281 | int result; | ||
282 | |||
283 | /* Compare epoch */ | ||
284 | if (ch_ver1[1] == ':') { | ||
285 | epoch1 = ch_ver1[0]; | ||
286 | ver1_ptr = strchr(ch_ver1, ':') + 1; | ||
287 | } else { | ||
288 | epoch1 = '0'; | ||
289 | ver1_ptr = ch_ver1; | ||
290 | } | ||
291 | if (ch_ver2[1] == ':') { | ||
292 | epoch2 = ch_ver2[0]; | ||
293 | ver2_ptr = strchr(ch_ver2, ':') + 1; | ||
294 | } else { | ||
295 | epoch2 = '0'; | ||
296 | ver2_ptr = ch_ver2; | ||
297 | } | ||
298 | if (epoch1 < epoch2) { | ||
299 | return(-1); | ||
300 | } | ||
301 | else if (epoch1 > epoch2) { | ||
302 | return(1); | ||
303 | } | ||
304 | |||
305 | /* Compare upstream version */ | ||
306 | upstream_ver1 = bb_xstrdup(ver1_ptr); | ||
307 | upstream_ver2 = bb_xstrdup(ver2_ptr); | ||
308 | |||
309 | /* Chop off debian version, and store for later use */ | ||
310 | deb_ver1 = strrchr(upstream_ver1, '-'); | ||
311 | deb_ver2 = strrchr(upstream_ver2, '-'); | ||
312 | if (deb_ver1) { | ||
313 | deb_ver1[0] = '\0'; | ||
314 | deb_ver1++; | ||
315 | } | ||
316 | if (deb_ver2) { | ||
317 | deb_ver2[0] = '\0'; | ||
318 | deb_ver2++; | ||
319 | } | ||
320 | result = version_compare_part(upstream_ver1, upstream_ver2); | ||
321 | |||
322 | free(upstream_ver1); | ||
323 | free(upstream_ver2); | ||
324 | |||
325 | if (result != 0) { | ||
326 | return(result); | ||
327 | } | ||
328 | |||
329 | /* Compare debian versions */ | ||
330 | return(version_compare_part(deb_ver1, deb_ver2)); | ||
331 | } | ||
332 | |||
333 | int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator) | ||
334 | { | ||
335 | const int version_result = version_compare(version1, version2); | ||
336 | switch(operator) { | ||
337 | case (VER_ANY): | ||
338 | return(TRUE); | ||
339 | case (VER_EQUAL): | ||
340 | if (version_result == 0) { | ||
341 | return(TRUE); | ||
342 | } | ||
343 | break; | ||
344 | case (VER_LESS): | ||
345 | if (version_result < 0) { | ||
346 | return(TRUE); | ||
347 | } | ||
348 | break; | ||
349 | case (VER_LESS_EQUAL): | ||
350 | if (version_result <= 0) { | ||
351 | return(TRUE); | ||
352 | } | ||
353 | break; | ||
354 | case (VER_MORE): | ||
355 | if (version_result > 0) { | ||
356 | return(TRUE); | ||
357 | } | ||
358 | break; | ||
359 | case (VER_MORE_EQUAL): | ||
360 | if (version_result >= 0) { | ||
361 | return(TRUE); | ||
362 | } | ||
363 | break; | ||
364 | } | ||
365 | return(FALSE); | ||
366 | } | ||
367 | |||
368 | |||
369 | int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator) | ||
370 | { | ||
371 | unsigned int probe_address = 0; | ||
372 | unsigned int probe_decrement = 0; | ||
373 | |||
374 | make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); | ||
375 | while(package_hashtable[probe_address] != NULL) { | ||
376 | if (package_hashtable[probe_address]->name == name) { | ||
377 | if (operator == VER_ANY) { | ||
378 | return(probe_address); | ||
379 | } | ||
380 | if (test_version(package_hashtable[probe_address]->version, version, operator)) { | ||
381 | return(probe_address); | ||
382 | } | ||
383 | } | ||
384 | probe_address -= probe_decrement; | ||
385 | if ((int)probe_address < 0) { | ||
386 | probe_address += PACKAGE_HASH_PRIME; | ||
387 | } | ||
388 | } | ||
389 | return(probe_address); | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * This function searches through the entire package_hashtable looking | ||
394 | * for a package which provides "needle". It returns the index into | ||
395 | * the package_hashtable for the providing package. | ||
396 | * | ||
397 | * needle is the index into name_hashtable of the package we are | ||
398 | * looking for. | ||
399 | * | ||
400 | * start_at is the index in the package_hashtable to start looking | ||
401 | * at. If start_at is -1 then start at the beginning. This is to allow | ||
402 | * for repeated searches since more than one package might provide | ||
403 | * needle. | ||
404 | * | ||
405 | * FIXME: I don't think this is very efficient, but I thought I'd keep | ||
406 | * it simple for now until it proves to be a problem. | ||
407 | */ | ||
408 | int search_for_provides(int needle, int start_at) { | ||
409 | int i, j; | ||
410 | common_node_t *p; | ||
411 | for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) { | ||
412 | p = package_hashtable[i]; | ||
413 | if ( p == NULL ) continue; | ||
414 | for(j = 0; j < p->num_of_edges; j++) | ||
415 | if ( p->edge[j]->type == EDGE_PROVIDES && p->edge[j]->name == needle ) | ||
416 | return i; | ||
417 | } | ||
418 | return -1; | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * Add an edge to a node | ||
423 | */ | ||
424 | void add_edge_to_node(common_node_t *node, edge_t *edge) | ||
425 | { | ||
426 | node->num_of_edges++; | ||
427 | node->edge = xrealloc(node->edge, sizeof(edge_t) * (node->num_of_edges + 1)); | ||
428 | node->edge[node->num_of_edges - 1] = edge; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Create one new node and one new edge for every dependency. | ||
433 | * | ||
434 | * Dependencies which contain multiple alternatives are represented as | ||
435 | * an EDGE_OR_PRE_DEPENDS or EDGE_OR_DEPENDS node, followed by a | ||
436 | * number of EDGE_PRE_DEPENDS or EDGE_DEPENDS nodes. The name field of | ||
437 | * the OR edge contains the full dependency string while the version | ||
438 | * field contains the number of EDGE nodes which follow as part of | ||
439 | * this alternative. | ||
440 | */ | ||
441 | void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type) | ||
442 | { | ||
443 | char *line = bb_xstrdup(whole_line); | ||
444 | char *line2; | ||
445 | char *line_ptr1 = NULL; | ||
446 | char *line_ptr2 = NULL; | ||
447 | char *field; | ||
448 | char *field2; | ||
449 | char *version; | ||
450 | edge_t *edge; | ||
451 | edge_t *or_edge; | ||
452 | int offset_ch; | ||
453 | |||
454 | field = strtok_r(line, ",", &line_ptr1); | ||
455 | do { | ||
456 | /* skip leading spaces */ | ||
457 | field += strspn(field, " "); | ||
458 | line2 = bb_xstrdup(field); | ||
459 | field2 = strtok_r(line2, "|", &line_ptr2); | ||
460 | if ( (edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS) && | ||
461 | (strcmp(field, field2) != 0)) { | ||
462 | or_edge = (edge_t *)xmalloc(sizeof(edge_t)); | ||
463 | or_edge->type = edge_type + 1; | ||
464 | } else { | ||
465 | or_edge = NULL; | ||
466 | } | ||
467 | |||
468 | if ( or_edge ) { | ||
469 | or_edge->name = search_name_hashtable(field); | ||
470 | or_edge->version = 0; // tracks the number of altenatives | ||
471 | |||
472 | add_edge_to_node(parent_node, or_edge); | ||
473 | } | ||
474 | |||
475 | do { | ||
476 | edge = (edge_t *) xmalloc(sizeof(edge_t)); | ||
477 | edge->type = edge_type; | ||
478 | |||
479 | /* Skip any extra leading spaces */ | ||
480 | field2 += strspn(field2, " "); | ||
481 | |||
482 | /* Get dependency version info */ | ||
483 | version = strchr(field2, '('); | ||
484 | if (version == NULL) { | ||
485 | edge->operator = VER_ANY; | ||
486 | /* Get the versions hash number, adding it if the number isnt already in there */ | ||
487 | edge->version = search_name_hashtable("ANY"); | ||
488 | } else { | ||
489 | /* Skip leading ' ' or '(' */ | ||
490 | version += strspn(field2, " "); | ||
491 | version += strspn(version, "("); | ||
492 | /* Calculate length of any operator characters */ | ||
493 | offset_ch = strspn(version, "<=>"); | ||
494 | /* Determine operator */ | ||
495 | if (offset_ch > 0) { | ||
496 | if (strncmp(version, "=", offset_ch) == 0) { | ||
497 | edge->operator = VER_EQUAL; | ||
498 | } | ||
499 | else if (strncmp(version, "<<", offset_ch) == 0) { | ||
500 | edge->operator = VER_LESS; | ||
501 | } | ||
502 | else if (strncmp(version, "<=", offset_ch) == 0) { | ||
503 | edge->operator = VER_LESS_EQUAL; | ||
504 | } | ||
505 | else if (strncmp(version, ">>", offset_ch) == 0) { | ||
506 | edge->operator = VER_MORE; | ||
507 | } | ||
508 | else if (strncmp(version, ">=", offset_ch) == 0) { | ||
509 | edge->operator = VER_MORE_EQUAL; | ||
510 | } else { | ||
511 | bb_error_msg_and_die("Illegal operator\n"); | ||
512 | } | ||
513 | } | ||
514 | /* skip to start of version numbers */ | ||
515 | version += offset_ch; | ||
516 | version += strspn(version, " "); | ||
517 | |||
518 | /* Truncate version at trailing ' ' or ')' */ | ||
519 | version[strcspn(version, " )")] = '\0'; | ||
520 | /* Get the versions hash number, adding it if the number isnt already in there */ | ||
521 | edge->version = search_name_hashtable(version); | ||
522 | } | ||
523 | |||
524 | /* Get the dependency name */ | ||
525 | field2[strcspn(field2, " (")] = '\0'; | ||
526 | edge->name = search_name_hashtable(field2); | ||
527 | |||
528 | if ( or_edge ) | ||
529 | or_edge->version++; | ||
530 | |||
531 | add_edge_to_node(parent_node, edge); | ||
532 | } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL); | ||
533 | free(line2); | ||
534 | } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL); | ||
535 | free(line); | ||
536 | |||
537 | return; | ||
538 | } | ||
539 | |||
540 | void free_package(common_node_t *node) | ||
541 | { | ||
542 | unsigned short i; | ||
543 | if (node) { | ||
544 | for (i = 0; i < node->num_of_edges; i++) { | ||
545 | free(node->edge[i]); | ||
546 | } | ||
547 | if ( node->edge ) | ||
548 | free(node->edge); | ||
549 | free(node); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | unsigned int fill_package_struct(char *control_buffer) | ||
554 | { | ||
555 | common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t)); | ||
556 | const char *field_names[] = { "Package", "Version", "Pre-Depends", "Depends", | ||
557 | "Replaces", "Provides", "Conflicts", "Suggests", "Recommends", "Enhances", 0}; | ||
558 | char *field_name; | ||
559 | char *field_value; | ||
560 | int field_start = 0; | ||
561 | int num = -1; | ||
562 | int buffer_length = strlen(control_buffer); | ||
563 | |||
564 | new_node->version = search_name_hashtable("unknown"); | ||
565 | while (field_start < buffer_length) { | ||
566 | unsigned short field_num; | ||
567 | |||
568 | field_start += read_package_field(&control_buffer[field_start], | ||
569 | &field_name, &field_value); | ||
570 | |||
571 | if (field_name == NULL) { | ||
572 | goto fill_package_struct_cleanup; /* Oh no, the dreaded goto statement ! */ | ||
573 | } | ||
574 | |||
575 | field_num = compare_string_array(field_names, field_name); | ||
576 | switch(field_num) { | ||
577 | case 0: /* Package */ | ||
578 | new_node->name = search_name_hashtable(field_value); | ||
579 | break; | ||
580 | case 1: /* Version */ | ||
581 | new_node->version = search_name_hashtable(field_value); | ||
582 | break; | ||
583 | case 2: /* Pre-Depends */ | ||
584 | add_split_dependencies(new_node, field_value, EDGE_PRE_DEPENDS); | ||
585 | break; | ||
586 | case 3: /* Depends */ | ||
587 | add_split_dependencies(new_node, field_value, EDGE_DEPENDS); | ||
588 | break; | ||
589 | case 4: /* Replaces */ | ||
590 | add_split_dependencies(new_node, field_value, EDGE_REPLACES); | ||
591 | break; | ||
592 | case 5: /* Provides */ | ||
593 | add_split_dependencies(new_node, field_value, EDGE_PROVIDES); | ||
594 | break; | ||
595 | case 6: /* Conflicts */ | ||
596 | add_split_dependencies(new_node, field_value, EDGE_CONFLICTS); | ||
597 | break; | ||
598 | case 7: /* Suggests */ | ||
599 | add_split_dependencies(new_node, field_value, EDGE_SUGGESTS); | ||
600 | break; | ||
601 | case 8: /* Recommends */ | ||
602 | add_split_dependencies(new_node, field_value, EDGE_RECOMMENDS); | ||
603 | break; | ||
604 | case 9: /* Enhances */ | ||
605 | add_split_dependencies(new_node, field_value, EDGE_ENHANCES); | ||
606 | break; | ||
607 | } | ||
608 | fill_package_struct_cleanup: | ||
609 | free(field_name); | ||
610 | free(field_value); | ||
611 | } | ||
612 | |||
613 | if (new_node->version == search_name_hashtable("unknown")) { | ||
614 | free_package(new_node); | ||
615 | return(-1); | ||
616 | } | ||
617 | num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); | ||
618 | if (package_hashtable[num] == NULL) { | ||
619 | package_hashtable[num] = new_node; | ||
620 | } else { | ||
621 | free_package(new_node); | ||
622 | } | ||
623 | return(num); | ||
624 | } | ||
625 | |||
626 | /* if num = 1, it returns the want status, 2 returns flag, 3 returns status */ | ||
627 | unsigned int get_status(const unsigned int status_node, const int num) | ||
628 | { | ||
629 | char *status_string = name_hashtable[status_hashtable[status_node]->status]; | ||
630 | char *state_sub_string; | ||
631 | unsigned int state_sub_num; | ||
632 | int len; | ||
633 | int i; | ||
634 | |||
635 | /* set tmp_string to point to the start of the word number */ | ||
636 | for (i = 1; i < num; i++) { | ||
637 | /* skip past a word */ | ||
638 | status_string += strcspn(status_string, " "); | ||
639 | /* skip past the separating spaces */ | ||
640 | status_string += strspn(status_string, " "); | ||
641 | } | ||
642 | len = strcspn(status_string, " \n\0"); | ||
643 | state_sub_string = bb_xstrndup(status_string, len); | ||
644 | state_sub_num = search_name_hashtable(state_sub_string); | ||
645 | free(state_sub_string); | ||
646 | return(state_sub_num); | ||
647 | } | ||
648 | |||
649 | void set_status(const unsigned int status_node_num, const char *new_value, const int position) | ||
650 | { | ||
651 | const unsigned int new_value_len = strlen(new_value); | ||
652 | const unsigned int new_value_num = search_name_hashtable(new_value); | ||
653 | unsigned int want = get_status(status_node_num, 1); | ||
654 | unsigned int flag = get_status(status_node_num, 2); | ||
655 | unsigned int status = get_status(status_node_num, 3); | ||
656 | int want_len = strlen(name_hashtable[want]); | ||
657 | int flag_len = strlen(name_hashtable[flag]); | ||
658 | int status_len = strlen(name_hashtable[status]); | ||
659 | char *new_status; | ||
660 | |||
661 | switch (position) { | ||
662 | case (1): | ||
663 | want = new_value_num; | ||
664 | want_len = new_value_len; | ||
665 | break; | ||
666 | case (2): | ||
667 | flag = new_value_num; | ||
668 | flag_len = new_value_len; | ||
669 | break; | ||
670 | case (3): | ||
671 | status = new_value_num; | ||
672 | status_len = new_value_len; | ||
673 | break; | ||
674 | default: | ||
675 | bb_error_msg_and_die("DEBUG ONLY: this shouldnt happen"); | ||
676 | } | ||
677 | |||
678 | new_status = (char *) xmalloc(want_len + flag_len + status_len + 3); | ||
679 | sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); | ||
680 | status_hashtable[status_node_num]->status = search_name_hashtable(new_status); | ||
681 | free(new_status); | ||
682 | return; | ||
683 | } | ||
684 | |||
685 | const char *describe_status(int status_num) { | ||
686 | int status_want, status_state ; | ||
687 | if ( status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0 ) | ||
688 | return "is not installed or flagged to be installed\n"; | ||
689 | |||
690 | status_want = get_status(status_num, 1); | ||
691 | status_state = get_status(status_num, 3); | ||
692 | |||
693 | if ( status_state == search_name_hashtable("installed") ) { | ||
694 | if ( status_want == search_name_hashtable("install") ) | ||
695 | return "is installed"; | ||
696 | if ( status_want == search_name_hashtable("deinstall") ) | ||
697 | return "is marked to be removed"; | ||
698 | if ( status_want == search_name_hashtable("purge") ) | ||
699 | return "is marked to be purged"; | ||
700 | } | ||
701 | if ( status_want == search_name_hashtable("unknown") ) | ||
702 | return "is in an indeterminate state"; | ||
703 | if ( status_want == search_name_hashtable("install") ) | ||
704 | return "is marked to be installed"; | ||
705 | |||
706 | return "is not installed or flagged to be installed"; | ||
707 | } | ||
708 | |||
709 | |||
710 | void index_status_file(const char *filename) | ||
711 | { | ||
712 | FILE *status_file; | ||
713 | char *control_buffer; | ||
714 | char *status_line; | ||
715 | status_node_t *status_node = NULL; | ||
716 | unsigned int status_num; | ||
717 | |||
718 | status_file = bb_xfopen(filename, "r"); | ||
719 | while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) { | ||
720 | const unsigned int package_num = fill_package_struct(control_buffer); | ||
721 | if (package_num != -1) { | ||
722 | status_node = xmalloc(sizeof(status_node_t)); | ||
723 | /* fill_package_struct doesnt handle the status field */ | ||
724 | status_line = strstr(control_buffer, "Status:"); | ||
725 | if (status_line != NULL) { | ||
726 | status_line += 7; | ||
727 | status_line += strspn(status_line, " \n\t"); | ||
728 | status_line = bb_xstrndup(status_line, strcspn(status_line, "\n\0")); | ||
729 | status_node->status = search_name_hashtable(status_line); | ||
730 | free(status_line); | ||
731 | } | ||
732 | status_node->package = package_num; | ||
733 | status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]); | ||
734 | status_hashtable[status_num] = status_node; | ||
735 | } | ||
736 | free(control_buffer); | ||
737 | } | ||
738 | fclose(status_file); | ||
739 | return; | ||
740 | } | ||
741 | |||
742 | #if 0 /* this code is no longer used */ | ||
743 | char *get_depends_field(common_node_t *package, const int depends_type) | ||
744 | { | ||
745 | char *depends = NULL; | ||
746 | char *old_sep = (char *)xcalloc(1, 3); | ||
747 | char *new_sep = (char *)xcalloc(1, 3); | ||
748 | int line_size = 0; | ||
749 | int depends_size; | ||
750 | |||
751 | int i; | ||
752 | |||
753 | for (i = 0; i < package->num_of_edges; i++) { | ||
754 | if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) || | ||
755 | (package->edge[i]->type == EDGE_OR_DEPENDS)) { | ||
756 | } | ||
757 | |||
758 | if ((package->edge[i]->type == depends_type) || | ||
759 | (package->edge[i]->type == depends_type + 1)) { | ||
760 | /* Check if its the first time through */ | ||
761 | |||
762 | depends_size = 8 + strlen(name_hashtable[package->edge[i]->name]) | ||
763 | + strlen(name_hashtable[package->edge[i]->version]); | ||
764 | line_size += depends_size; | ||
765 | depends = (char *) xrealloc(depends, line_size + 1); | ||
766 | |||
767 | /* Check to see if this dependency is the type we are looking for | ||
768 | * +1 to check for 'extra' types, e.g. ored dependecies */ | ||
769 | strcpy(old_sep, new_sep); | ||
770 | if (package->edge[i]->type == depends_type) { | ||
771 | strcpy(new_sep, ", "); | ||
772 | } | ||
773 | else if (package->edge[i]->type == depends_type + 1) { | ||
774 | strcpy(new_sep, "| "); | ||
775 | } | ||
776 | |||
777 | if (depends_size == line_size) { | ||
778 | strcpy(depends, ""); | ||
779 | } else { | ||
780 | if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) { | ||
781 | strcat(depends, " | "); | ||
782 | } else { | ||
783 | strcat(depends, ", "); | ||
784 | } | ||
785 | } | ||
786 | |||
787 | strcat(depends, name_hashtable[package->edge[i]->name]); | ||
788 | if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) { | ||
789 | if (package->edge[i]->operator == VER_EQUAL) { | ||
790 | strcat(depends, " (= "); | ||
791 | } | ||
792 | else if (package->edge[i]->operator == VER_LESS) { | ||
793 | strcat(depends, " (<< "); | ||
794 | } | ||
795 | else if (package->edge[i]->operator == VER_LESS_EQUAL) { | ||
796 | strcat(depends, " (<= "); | ||
797 | } | ||
798 | else if (package->edge[i]->operator == VER_MORE) { | ||
799 | strcat(depends, " (>> "); | ||
800 | } | ||
801 | else if (package->edge[i]->operator == VER_MORE_EQUAL) { | ||
802 | strcat(depends, " (>= "); | ||
803 | } else { | ||
804 | strcat(depends, " ("); | ||
805 | } | ||
806 | strcat(depends, name_hashtable[package->edge[i]->version]); | ||
807 | strcat(depends, ")"); | ||
808 | } | ||
809 | } | ||
810 | } | ||
811 | return(depends); | ||
812 | } | ||
813 | #endif | ||
814 | |||
815 | void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) | ||
816 | { | ||
817 | char *name; | ||
818 | char *value; | ||
819 | int start = 0; | ||
820 | while (1) { | ||
821 | start += read_package_field(&control_buffer[start], &name, &value); | ||
822 | if (name == NULL) { | ||
823 | break; | ||
824 | } | ||
825 | if (strcmp(name, "Status") != 0) { | ||
826 | fprintf(new_status_file, "%s: %s\n", name, value); | ||
827 | } | ||
828 | } | ||
829 | return; | ||
830 | } | ||
831 | |||
832 | /* This could do with a cleanup */ | ||
833 | void write_status_file(deb_file_t **deb_file) | ||
834 | { | ||
835 | FILE *old_status_file = bb_xfopen("/var/lib/dpkg/status", "r"); | ||
836 | FILE *new_status_file = bb_xfopen("/var/lib/dpkg/status.udeb", "w"); | ||
837 | char *package_name; | ||
838 | char *status_from_file; | ||
839 | char *control_buffer = NULL; | ||
840 | char *tmp_string; | ||
841 | int status_num; | ||
842 | int field_start = 0; | ||
843 | int write_flag; | ||
844 | int i = 0; | ||
845 | |||
846 | /* Update previously known packages */ | ||
847 | while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) { | ||
848 | if ((tmp_string = strstr(control_buffer, "Package:")) == NULL) { | ||
849 | continue; | ||
850 | } | ||
851 | |||
852 | tmp_string += 8; | ||
853 | tmp_string += strspn(tmp_string, " \n\t"); | ||
854 | package_name = bb_xstrndup(tmp_string, strcspn(tmp_string, "\n\0")); | ||
855 | write_flag = FALSE; | ||
856 | tmp_string = strstr(control_buffer, "Status:"); | ||
857 | if (tmp_string != NULL) { | ||
858 | /* Seperate the status value from the control buffer */ | ||
859 | tmp_string += 7; | ||
860 | tmp_string += strspn(tmp_string, " \n\t"); | ||
861 | status_from_file = bb_xstrndup(tmp_string, strcspn(tmp_string, "\n")); | ||
862 | } else { | ||
863 | status_from_file = NULL; | ||
864 | } | ||
865 | |||
866 | /* Find this package in the status hashtable */ | ||
867 | status_num = search_status_hashtable(package_name); | ||
868 | if (status_hashtable[status_num] != NULL) { | ||
869 | const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status]; | ||
870 | if (strcmp(status_from_file, status_from_hashtable) != 0) { | ||
871 | /* New status isnt exactly the same as old status */ | ||
872 | const int state_status = get_status(status_num, 3); | ||
873 | if ((strcmp("installed", name_hashtable[state_status]) == 0) || | ||
874 | (strcmp("unpacked", name_hashtable[state_status]) == 0)) { | ||
875 | /* We need to add the control file from the package */ | ||
876 | i = 0; | ||
877 | while(deb_file[i] != NULL) { | ||
878 | if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) { | ||
879 | /* Write a status file entry with a modified status */ | ||
880 | /* remove trailing \n's */ | ||
881 | write_buffer_no_status(new_status_file, deb_file[i]->control_file); | ||
882 | set_status(status_num, "ok", 2); | ||
883 | fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); | ||
884 | write_flag = TRUE; | ||
885 | break; | ||
886 | } | ||
887 | i++; | ||
888 | } | ||
889 | /* This is temperary, debugging only */ | ||
890 | if (deb_file[i] == NULL) { | ||
891 | bb_error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name); | ||
892 | } | ||
893 | } | ||
894 | else if (strcmp("not-installed", name_hashtable[state_status]) == 0) { | ||
895 | /* Only write the Package, Status, Priority and Section lines */ | ||
896 | fprintf(new_status_file, "Package: %s\n", package_name); | ||
897 | fprintf(new_status_file, "Status: %s\n", status_from_hashtable); | ||
898 | |||
899 | while (1) { | ||
900 | char *field_name; | ||
901 | char *field_value; | ||
902 | field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); | ||
903 | if (field_name == NULL) { | ||
904 | break; | ||
905 | } | ||
906 | if ((strcmp(field_name, "Priority") == 0) || | ||
907 | (strcmp(field_name, "Section") == 0)) { | ||
908 | fprintf(new_status_file, "%s: %s\n", field_name, field_value); | ||
909 | } | ||
910 | } | ||
911 | write_flag = TRUE; | ||
912 | fputs("\n", new_status_file); | ||
913 | } | ||
914 | else if (strcmp("config-files", name_hashtable[state_status]) == 0) { | ||
915 | /* only change the status line */ | ||
916 | while (1) { | ||
917 | char *field_name; | ||
918 | char *field_value; | ||
919 | field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); | ||
920 | if (field_name == NULL) { | ||
921 | break; | ||
922 | } | ||
923 | /* Setup start point for next field */ | ||
924 | if (strcmp(field_name, "Status") == 0) { | ||
925 | fprintf(new_status_file, "Status: %s\n", status_from_hashtable); | ||
926 | } else { | ||
927 | fprintf(new_status_file, "%s: %s\n", field_name, field_value); | ||
928 | } | ||
929 | } | ||
930 | write_flag = TRUE; | ||
931 | fputs("\n", new_status_file); | ||
932 | } | ||
933 | } | ||
934 | } | ||
935 | /* If the package from the status file wasnt handle above, do it now*/ | ||
936 | if (! write_flag) { | ||
937 | fprintf(new_status_file, "%s\n\n", control_buffer); | ||
938 | } | ||
939 | |||
940 | free(status_from_file); | ||
941 | free(package_name); | ||
942 | free(control_buffer); | ||
943 | } | ||
944 | |||
945 | /* Write any new packages */ | ||
946 | for(i = 0; deb_file[i] != NULL; i++) { | ||
947 | status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]); | ||
948 | if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) { | ||
949 | write_buffer_no_status(new_status_file, deb_file[i]->control_file); | ||
950 | set_status(status_num, "ok", 2); | ||
951 | fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); | ||
952 | } | ||
953 | } | ||
954 | fclose(old_status_file); | ||
955 | fclose(new_status_file); | ||
956 | |||
957 | |||
958 | /* Create a separate backfile to dpkg */ | ||
959 | if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { | ||
960 | struct stat stat_buf; | ||
961 | if (stat("/var/lib/dpkg/status", &stat_buf) == 0) { | ||
962 | bb_error_msg_and_die("Couldnt create backup status file"); | ||
963 | } | ||
964 | /* Its ok if renaming the status file fails because status | ||
965 | * file doesnt exist, maybe we are starting from scratch */ | ||
966 | bb_error_msg("No status file found, creating new one"); | ||
967 | } | ||
968 | |||
969 | if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) { | ||
970 | bb_error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file"); | ||
971 | } | ||
972 | } | ||
973 | |||
974 | /* This function returns TRUE if the given package can satisfy a | ||
975 | * dependency of type depend_type. | ||
976 | * | ||
977 | * A pre-depends is satisfied only if a package is already installed, | ||
978 | * which a regular depends can be satisfied by a package which we want | ||
979 | * to install. | ||
980 | */ | ||
981 | int package_satisfies_dependency(int package, int depend_type) | ||
982 | { | ||
983 | int status_num = search_status_hashtable(name_hashtable[package_hashtable[package]->name]); | ||
984 | |||
985 | /* status could be unknown if package is a pure virtual | ||
986 | * provides which cannot satisfy any dependency by itself. | ||
987 | */ | ||
988 | if ( status_hashtable[status_num] == NULL ) | ||
989 | return 0; | ||
990 | |||
991 | switch (depend_type) { | ||
992 | case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed"); | ||
993 | case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install"); | ||
994 | } | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count) | ||
999 | { | ||
1000 | int *conflicts = NULL; | ||
1001 | int conflicts_num = 0; | ||
1002 | int i = deb_start; | ||
1003 | int j; | ||
1004 | |||
1005 | /* Check for conflicts | ||
1006 | * TODO: TEST if conflicts with other packages to be installed | ||
1007 | * | ||
1008 | * Add install packages and the packages they provide | ||
1009 | * to the list of files to check conflicts for | ||
1010 | */ | ||
1011 | |||
1012 | /* Create array of package numbers to check against | ||
1013 | * installed package for conflicts*/ | ||
1014 | while (deb_file[i] != NULL) { | ||
1015 | const unsigned int package_num = deb_file[i]->package; | ||
1016 | conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); | ||
1017 | conflicts[conflicts_num] = package_num; | ||
1018 | conflicts_num++; | ||
1019 | /* add provides to conflicts list */ | ||
1020 | for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { | ||
1021 | if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { | ||
1022 | const int conflicts_package_num = search_package_hashtable( | ||
1023 | package_hashtable[package_num]->edge[j]->name, | ||
1024 | package_hashtable[package_num]->edge[j]->version, | ||
1025 | package_hashtable[package_num]->edge[j]->operator); | ||
1026 | if (package_hashtable[conflicts_package_num] == NULL) { | ||
1027 | /* create a new package */ | ||
1028 | common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t)); | ||
1029 | new_node->name = package_hashtable[package_num]->edge[j]->name; | ||
1030 | new_node->version = package_hashtable[package_num]->edge[j]->version; | ||
1031 | new_node->num_of_edges = 0; | ||
1032 | new_node->edge = NULL; | ||
1033 | package_hashtable[conflicts_package_num] = new_node; | ||
1034 | } | ||
1035 | conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); | ||
1036 | conflicts[conflicts_num] = conflicts_package_num; | ||
1037 | conflicts_num++; | ||
1038 | } | ||
1039 | } | ||
1040 | i++; | ||
1041 | } | ||
1042 | |||
1043 | /* Check conflicts */ | ||
1044 | i = 0; | ||
1045 | while (deb_file[i] != NULL) { | ||
1046 | const common_node_t *package_node = package_hashtable[deb_file[i]->package]; | ||
1047 | int status_num = 0; | ||
1048 | status_num = search_status_hashtable(name_hashtable[package_node->name]); | ||
1049 | |||
1050 | if (get_status(status_num, 3) == search_name_hashtable("installed")) { | ||
1051 | i++; | ||
1052 | continue; | ||
1053 | } | ||
1054 | |||
1055 | for (j = 0; j < package_node->num_of_edges; j++) { | ||
1056 | const edge_t *package_edge = package_node->edge[j]; | ||
1057 | |||
1058 | if (package_edge->type == EDGE_CONFLICTS) { | ||
1059 | const unsigned int package_num = | ||
1060 | search_package_hashtable(package_edge->name, | ||
1061 | package_edge->version, | ||
1062 | package_edge->operator); | ||
1063 | int result = 0; | ||
1064 | if (package_hashtable[package_num] != NULL) { | ||
1065 | status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); | ||
1066 | |||
1067 | if (get_status(status_num, 1) == search_name_hashtable("install")) { | ||
1068 | result = test_version(package_hashtable[deb_file[i]->package]->version, | ||
1069 | package_edge->version, package_edge->operator); | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | if (result) { | ||
1074 | bb_error_msg_and_die("Package %s conflicts with %s", | ||
1075 | name_hashtable[package_node->name], | ||
1076 | name_hashtable[package_edge->name]); | ||
1077 | } | ||
1078 | } | ||
1079 | } | ||
1080 | i++; | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | /* Check dependendcies */ | ||
1085 | for (i = 0; i < PACKAGE_HASH_PRIME; i++) { | ||
1086 | int status_num = 0; | ||
1087 | int number_of_alternatives = 0; | ||
1088 | const edge_t * root_of_alternatives = NULL; | ||
1089 | const common_node_t *package_node = package_hashtable[i]; | ||
1090 | |||
1091 | /* If the package node does not exist then this | ||
1092 | * package is a virtual one. In which case there are | ||
1093 | * no dependencies to check. | ||
1094 | */ | ||
1095 | if ( package_node == NULL ) continue; | ||
1096 | |||
1097 | status_num = search_status_hashtable(name_hashtable[package_node->name]); | ||
1098 | |||
1099 | /* If there is no status then this package is a | ||
1100 | * virtual one provided by something else. In which | ||
1101 | * case there are no dependencies to check. | ||
1102 | */ | ||
1103 | if ( status_hashtable[status_num] == NULL ) continue; | ||
1104 | |||
1105 | /* If we don't want this package installed then we may | ||
1106 | * as well ignore it's dependencies. | ||
1107 | */ | ||
1108 | if (get_status(status_num, 1) != search_name_hashtable("install")) { | ||
1109 | continue; | ||
1110 | } | ||
1111 | |||
1112 | #if 0 | ||
1113 | /* This might be needed so we don't complain about | ||
1114 | * things which are broken but unrelated to the | ||
1115 | * packages that are currently being installed | ||
1116 | */ | ||
1117 | if (state_status == search_name_hashtable("installed")) | ||
1118 | continue; | ||
1119 | #endif | ||
1120 | |||
1121 | /* This code is tested only for EDGE_DEPENDS, since I | ||
1122 | * have no suitable pre-depends available. There is no | ||
1123 | * reason that it shouldn't work though :-) | ||
1124 | */ | ||
1125 | for (j = 0; j < package_node->num_of_edges; j++) { | ||
1126 | const edge_t *package_edge = package_node->edge[j]; | ||
1127 | unsigned int package_num; | ||
1128 | |||
1129 | if ( package_edge->type == EDGE_OR_PRE_DEPENDS || | ||
1130 | package_edge->type == EDGE_OR_DEPENDS ) { /* start an EDGE_OR_ list */ | ||
1131 | number_of_alternatives = package_edge->version; | ||
1132 | root_of_alternatives = package_edge; | ||
1133 | continue; | ||
1134 | } else if ( number_of_alternatives == 0 ) { /* not in the middle of an EDGE_OR_ list */ | ||
1135 | number_of_alternatives = 1; | ||
1136 | root_of_alternatives = NULL; | ||
1137 | } | ||
1138 | |||
1139 | package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator); | ||
1140 | |||
1141 | if (package_edge->type == EDGE_PRE_DEPENDS || | ||
1142 | package_edge->type == EDGE_DEPENDS ) { | ||
1143 | int result=1; | ||
1144 | status_num = 0; | ||
1145 | |||
1146 | /* If we are inside an alternative then check | ||
1147 | * this edge is the right type. | ||
1148 | * | ||
1149 | * EDGE_DEPENDS == OR_DEPENDS -1 | ||
1150 | * EDGE_PRE_DEPENDS == OR_PRE_DEPENDS -1 | ||
1151 | */ | ||
1152 | if ( root_of_alternatives && package_edge->type != root_of_alternatives->type - 1) | ||
1153 | bb_error_msg_and_die("Fatal error. Package dependencies corrupt: %d != %d - 1 \n", | ||
1154 | package_edge->type, root_of_alternatives->type); | ||
1155 | |||
1156 | if (package_hashtable[package_num] != NULL) | ||
1157 | result = !package_satisfies_dependency(package_num, package_edge->type); | ||
1158 | |||
1159 | if (result) { /* check for other package which provide what we are looking for */ | ||
1160 | int provider = -1; | ||
1161 | |||
1162 | while ( (provider = search_for_provides(package_edge->name, provider) ) > -1 ) { | ||
1163 | if ( package_hashtable[provider] == NULL ) { | ||
1164 | printf("Have a provider but no package information for it\n"); | ||
1165 | continue; | ||
1166 | } | ||
1167 | result = !package_satisfies_dependency(provider, package_edge->type); | ||
1168 | |||
1169 | if ( result == 0 ) | ||
1170 | break; | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | /* It must be already installed, or to be installed */ | ||
1175 | number_of_alternatives--; | ||
1176 | if (result && number_of_alternatives == 0) { | ||
1177 | if ( root_of_alternatives ) | ||
1178 | bb_error_msg_and_die( | ||
1179 | "Package %s %sdepends on %s, " | ||
1180 | "which cannot be satisfied", | ||
1181 | name_hashtable[package_node->name], | ||
1182 | package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", | ||
1183 | name_hashtable[root_of_alternatives->name]); | ||
1184 | else | ||
1185 | bb_error_msg_and_die( | ||
1186 | "Package %s %sdepends on %s, which %s\n", | ||
1187 | name_hashtable[package_node->name], | ||
1188 | package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", | ||
1189 | name_hashtable[package_edge->name], | ||
1190 | describe_status(status_num)); | ||
1191 | } else if ( result == 0 && number_of_alternatives ) { | ||
1192 | /* we've found a package which | ||
1193 | * satisfies the dependency, | ||
1194 | * so skip over the rest of | ||
1195 | * the alternatives. | ||
1196 | */ | ||
1197 | j += number_of_alternatives; | ||
1198 | number_of_alternatives = 0; | ||
1199 | } | ||
1200 | } | ||
1201 | } | ||
1202 | } | ||
1203 | free(conflicts); | ||
1204 | return(TRUE); | ||
1205 | } | ||
1206 | |||
1207 | char **create_list(const char *filename) | ||
1208 | { | ||
1209 | FILE *list_stream; | ||
1210 | char **file_list = NULL; | ||
1211 | char *line = NULL; | ||
1212 | int count = 0; | ||
1213 | |||
1214 | /* don't use [xw]fopen here, handle error ourself */ | ||
1215 | list_stream = fopen(filename, "r"); | ||
1216 | if (list_stream == NULL) { | ||
1217 | return(NULL); | ||
1218 | } | ||
1219 | |||
1220 | while ((line = bb_get_chomped_line_from_file(list_stream)) != NULL) { | ||
1221 | file_list = xrealloc(file_list, sizeof(char *) * (count + 2)); | ||
1222 | file_list[count] = line; | ||
1223 | count++; | ||
1224 | } | ||
1225 | fclose(list_stream); | ||
1226 | |||
1227 | if (count == 0) { | ||
1228 | return(NULL); | ||
1229 | } else { | ||
1230 | file_list[count] = NULL; | ||
1231 | return(file_list); | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | /* maybe i should try and hook this into remove_file.c somehow */ | ||
1236 | int remove_file_array(char **remove_names, char **exclude_names) | ||
1237 | { | ||
1238 | struct stat path_stat; | ||
1239 | int match_flag; | ||
1240 | int remove_flag = FALSE; | ||
1241 | int i,j; | ||
1242 | |||
1243 | if (remove_names == NULL) { | ||
1244 | return(FALSE); | ||
1245 | } | ||
1246 | for (i = 0; remove_names[i] != NULL; i++) { | ||
1247 | match_flag = FALSE; | ||
1248 | if (exclude_names != NULL) { | ||
1249 | for (j = 0; exclude_names[j] != 0; j++) { | ||
1250 | if (strcmp(remove_names[i], exclude_names[j]) == 0) { | ||
1251 | match_flag = TRUE; | ||
1252 | break; | ||
1253 | } | ||
1254 | } | ||
1255 | } | ||
1256 | if (!match_flag) { | ||
1257 | if (lstat(remove_names[i], &path_stat) < 0) { | ||
1258 | continue; | ||
1259 | } | ||
1260 | if (S_ISDIR(path_stat.st_mode)) { | ||
1261 | if (rmdir(remove_names[i]) != -1) { | ||
1262 | remove_flag = TRUE; | ||
1263 | } | ||
1264 | } else { | ||
1265 | if (unlink(remove_names[i]) != -1) { | ||
1266 | remove_flag = TRUE; | ||
1267 | } | ||
1268 | } | ||
1269 | } | ||
1270 | } | ||
1271 | return(remove_flag); | ||
1272 | } | ||
1273 | |||
1274 | int run_package_script(const char *package_name, const char *script_type) | ||
1275 | { | ||
1276 | struct stat path_stat; | ||
1277 | char *script_path; | ||
1278 | int result; | ||
1279 | |||
1280 | script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21); | ||
1281 | sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type); | ||
1282 | |||
1283 | /* If the file doesnt exist is isnt a fatal */ | ||
1284 | if (lstat(script_path, &path_stat) < 0) { | ||
1285 | result = EXIT_SUCCESS; | ||
1286 | } else { | ||
1287 | result = system(script_path); | ||
1288 | } | ||
1289 | free(script_path); | ||
1290 | return(result); | ||
1291 | } | ||
1292 | |||
1293 | const char *all_control_files[] = {"preinst", "postinst", "prerm", "postrm", | ||
1294 | "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL }; | ||
1295 | |||
1296 | char **all_control_list(const char *package_name) | ||
1297 | { | ||
1298 | unsigned short i = 0; | ||
1299 | char **remove_files; | ||
1300 | |||
1301 | /* Create a list of all /var/lib/dpkg/info/<package> files */ | ||
1302 | remove_files = malloc(sizeof(all_control_files)); | ||
1303 | while (all_control_files[i]) { | ||
1304 | remove_files[i] = xmalloc(strlen(package_name) + strlen(all_control_files[i]) + 21); | ||
1305 | sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_control_files[i]); | ||
1306 | i++; | ||
1307 | } | ||
1308 | remove_files[sizeof(all_control_files)/sizeof(char*) - 1] = NULL; | ||
1309 | |||
1310 | return(remove_files); | ||
1311 | } | ||
1312 | |||
1313 | void free_array(char **array) | ||
1314 | { | ||
1315 | |||
1316 | if (array) { | ||
1317 | unsigned short i = 0; | ||
1318 | while (array[i]) { | ||
1319 | free(array[i]); | ||
1320 | i++; | ||
1321 | } | ||
1322 | free(array); | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | /* This function lists information on the installed packages. It loops through | ||
1327 | * the status_hashtable to retrieve the info. This results in smaller code than | ||
1328 | * scanning the status file. The resulting list, however, is unsorted. | ||
1329 | */ | ||
1330 | void list_packages(void) | ||
1331 | { | ||
1332 | int i; | ||
1333 | |||
1334 | printf(" Name Version\n"); | ||
1335 | printf("+++-==============-==============\n"); | ||
1336 | |||
1337 | /* go through status hash, dereference package hash and finally strings */ | ||
1338 | for (i=0; i<STATUS_HASH_PRIME+1; i++) { | ||
1339 | |||
1340 | if (status_hashtable[i]) { | ||
1341 | const char *stat_str; /* status string */ | ||
1342 | const char *name_str; /* package name */ | ||
1343 | const char *vers_str; /* version */ | ||
1344 | char s1, s2; /* status abbreviations */ | ||
1345 | int spccnt; /* space count */ | ||
1346 | int j; | ||
1347 | |||
1348 | stat_str = name_hashtable[status_hashtable[i]->status]; | ||
1349 | name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; | ||
1350 | vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; | ||
1351 | |||
1352 | /* get abbreviation for status field 1 */ | ||
1353 | s1 = stat_str[0] == 'i' ? 'i' : 'r'; | ||
1354 | |||
1355 | /* get abbreviation for status field 2 */ | ||
1356 | for (j=0, spccnt=0; stat_str[j] && spccnt<2; j++) { | ||
1357 | if (stat_str[j] == ' ') spccnt++; | ||
1358 | } | ||
1359 | s2 = stat_str[j]; | ||
1360 | |||
1361 | /* print out the line formatted like Debian dpkg */ | ||
1362 | printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str); | ||
1363 | } | ||
1364 | } | ||
1365 | } | ||
1366 | |||
1367 | void remove_package(const unsigned int package_num, int noisy) | ||
1368 | { | ||
1369 | const char *package_name = name_hashtable[package_hashtable[package_num]->name]; | ||
1370 | const char *package_version = name_hashtable[package_hashtable[package_num]->version]; | ||
1371 | const unsigned int status_num = search_status_hashtable(package_name); | ||
1372 | const int package_name_length = strlen(package_name); | ||
1373 | char **remove_files; | ||
1374 | char **exclude_files; | ||
1375 | char list_name[package_name_length + 25]; | ||
1376 | char conffile_name[package_name_length + 30]; | ||
1377 | int return_value; | ||
1378 | |||
1379 | if ( noisy ) | ||
1380 | printf("Removing %s (%s) ...\n", package_name, package_version); | ||
1381 | |||
1382 | /* run prerm script */ | ||
1383 | return_value = run_package_script(package_name, "prerm"); | ||
1384 | if (return_value == -1) { | ||
1385 | bb_error_msg_and_die("script failed, prerm failure"); | ||
1386 | } | ||
1387 | |||
1388 | /* Create a list of files to remove, and a separate list of those to keep */ | ||
1389 | sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); | ||
1390 | remove_files = create_list(list_name); | ||
1391 | |||
1392 | sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name); | ||
1393 | exclude_files = create_list(conffile_name); | ||
1394 | |||
1395 | /* Some directories cant be removed straight away, so do multiple passes */ | ||
1396 | while (remove_file_array(remove_files, exclude_files)); | ||
1397 | free_array(exclude_files); | ||
1398 | free_array(remove_files); | ||
1399 | |||
1400 | /* Create a list of files in /var/lib/dpkg/info/<package>.* to keep */ | ||
1401 | exclude_files = xmalloc(sizeof(char*) * 3); | ||
1402 | exclude_files[0] = bb_xstrdup(conffile_name); | ||
1403 | exclude_files[1] = xmalloc(package_name_length + 27); | ||
1404 | sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name); | ||
1405 | exclude_files[2] = NULL; | ||
1406 | |||
1407 | /* Create a list of all /var/lib/dpkg/info/<package> files */ | ||
1408 | remove_files = all_control_list(package_name); | ||
1409 | |||
1410 | remove_file_array(remove_files, exclude_files); | ||
1411 | free_array(remove_files); | ||
1412 | free_array(exclude_files); | ||
1413 | |||
1414 | /* rename <package>.conffile to <package>.list */ | ||
1415 | rename(conffile_name, list_name); | ||
1416 | |||
1417 | /* Change package status */ | ||
1418 | set_status(status_num, "config-files", 3); | ||
1419 | } | ||
1420 | |||
1421 | void purge_package(const unsigned int package_num) | ||
1422 | { | ||
1423 | const char *package_name = name_hashtable[package_hashtable[package_num]->name]; | ||
1424 | const char *package_version = name_hashtable[package_hashtable[package_num]->version]; | ||
1425 | const unsigned int status_num = search_status_hashtable(package_name); | ||
1426 | char **remove_files; | ||
1427 | char **exclude_files; | ||
1428 | char list_name[strlen(package_name) + 25]; | ||
1429 | |||
1430 | printf("Purging %s (%s) ...\n", package_name, package_version); | ||
1431 | |||
1432 | /* run prerm script */ | ||
1433 | if (run_package_script(package_name, "prerm") != 0) { | ||
1434 | bb_error_msg_and_die("script failed, prerm failure"); | ||
1435 | } | ||
1436 | |||
1437 | /* Create a list of files to remove */ | ||
1438 | sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); | ||
1439 | remove_files = create_list(list_name); | ||
1440 | |||
1441 | exclude_files = xmalloc(sizeof(char*)); | ||
1442 | exclude_files[0] = NULL; | ||
1443 | |||
1444 | /* Some directories cant be removed straight away, so do multiple passes */ | ||
1445 | while (remove_file_array(remove_files, exclude_files)); | ||
1446 | free_array(remove_files); | ||
1447 | |||
1448 | /* Create a list of all /var/lib/dpkg/info/<package> files */ | ||
1449 | remove_files = all_control_list(package_name); | ||
1450 | remove_file_array(remove_files, exclude_files); | ||
1451 | free_array(remove_files); | ||
1452 | free(exclude_files); | ||
1453 | |||
1454 | /* run postrm script */ | ||
1455 | if (run_package_script(package_name, "postrm") == -1) { | ||
1456 | bb_error_msg_and_die("postrm fialure.. set status to what?"); | ||
1457 | } | ||
1458 | |||
1459 | /* Change package status */ | ||
1460 | set_status(status_num, "not-installed", 3); | ||
1461 | } | ||
1462 | |||
1463 | static archive_handle_t *init_archive_deb_ar(const char *filename) | ||
1464 | { | ||
1465 | archive_handle_t *ar_handle; | ||
1466 | |||
1467 | /* Setup an ar archive handle that refers to the gzip sub archive */ | ||
1468 | ar_handle = init_handle(); | ||
1469 | ar_handle->filter = filter_accept_list_reassign; | ||
1470 | ar_handle->src_fd = bb_xopen(filename, O_RDONLY); | ||
1471 | |||
1472 | return(ar_handle); | ||
1473 | } | ||
1474 | |||
1475 | static void init_archive_deb_control(archive_handle_t *ar_handle) | ||
1476 | { | ||
1477 | archive_handle_t *tar_handle; | ||
1478 | |||
1479 | /* Setup the tar archive handle */ | ||
1480 | tar_handle = init_handle(); | ||
1481 | tar_handle->src_fd = ar_handle->src_fd; | ||
1482 | |||
1483 | /* We don't care about data.tar.* or debian-binary, just control.tar.* */ | ||
1484 | #ifdef CONFIG_FEATURE_DEB_TAR_GZ | ||
1485 | ar_handle->accept = llist_add_to(NULL, "control.tar.gz"); | ||
1486 | #endif | ||
1487 | #ifdef CONFIG_FEATURE_DEB_TAR_BZ2 | ||
1488 | ar_handle->accept = llist_add_to(ar_handle->accept, "control.tar.bz2"); | ||
1489 | #endif | ||
1490 | |||
1491 | /* Assign the tar handle as a subarchive of the ar handle */ | ||
1492 | ar_handle->sub_archive = tar_handle; | ||
1493 | |||
1494 | return; | ||
1495 | } | ||
1496 | |||
1497 | static void init_archive_deb_data(archive_handle_t *ar_handle) | ||
1498 | { | ||
1499 | archive_handle_t *tar_handle; | ||
1500 | |||
1501 | /* Setup the tar archive handle */ | ||
1502 | tar_handle = init_handle(); | ||
1503 | tar_handle->src_fd = ar_handle->src_fd; | ||
1504 | |||
1505 | /* We don't care about control.tar.* or debian-binary, just data.tar.* */ | ||
1506 | #ifdef CONFIG_FEATURE_DEB_TAR_GZ | ||
1507 | ar_handle->accept = llist_add_to(NULL, "data.tar.gz"); | ||
1508 | #endif | ||
1509 | #ifdef CONFIG_FEATURE_DEB_TAR_BZ2 | ||
1510 | ar_handle->accept = llist_add_to(ar_handle->accept, "data.tar.bz2"); | ||
1511 | #endif | ||
1512 | |||
1513 | /* Assign the tar handle as a subarchive of the ar handle */ | ||
1514 | ar_handle->sub_archive = tar_handle; | ||
1515 | |||
1516 | return; | ||
1517 | } | ||
1518 | |||
1519 | static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) | ||
1520 | { | ||
1521 | ar_handle->sub_archive->action_data = data_extract_to_buffer; | ||
1522 | ar_handle->sub_archive->accept = myaccept; | ||
1523 | |||
1524 | unpack_ar_archive(ar_handle); | ||
1525 | close(ar_handle->src_fd); | ||
1526 | |||
1527 | return(ar_handle->sub_archive->buffer); | ||
1528 | } | ||
1529 | |||
1530 | static void data_extract_all_prefix(archive_handle_t *archive_handle) | ||
1531 | { | ||
1532 | char *name_ptr = archive_handle->file_header->name; | ||
1533 | |||
1534 | name_ptr += strspn(name_ptr, "./"); | ||
1535 | if (name_ptr[0] != '\0') { | ||
1536 | archive_handle->file_header->name = xmalloc(strlen(archive_handle->buffer) + 2 + strlen(name_ptr)); | ||
1537 | strcpy(archive_handle->file_header->name, archive_handle->buffer); | ||
1538 | strcat(archive_handle->file_header->name, name_ptr); | ||
1539 | data_extract_all(archive_handle); | ||
1540 | } | ||
1541 | return; | ||
1542 | } | ||
1543 | |||
1544 | static void unpack_package(deb_file_t *deb_file) | ||
1545 | { | ||
1546 | const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; | ||
1547 | const unsigned int status_num = search_status_hashtable(package_name); | ||
1548 | const unsigned int status_package_num = status_hashtable[status_num]->package; | ||
1549 | char *info_prefix; | ||
1550 | archive_handle_t *archive_handle; | ||
1551 | FILE *out_stream; | ||
1552 | llist_t *accept_list = NULL; | ||
1553 | int i = 0; | ||
1554 | |||
1555 | /* If existing version, remove it first */ | ||
1556 | if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { | ||
1557 | /* Package is already installed, remove old version first */ | ||
1558 | printf("Preparing to replace %s %s (using %s) ...\n", package_name, | ||
1559 | name_hashtable[package_hashtable[status_package_num]->version], | ||
1560 | deb_file->filename); | ||
1561 | remove_package(status_package_num, 0); | ||
1562 | } else { | ||
1563 | printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename); | ||
1564 | } | ||
1565 | |||
1566 | /* Extract control.tar.gz to /var/lib/dpkg/info/<package>.filename */ | ||
1567 | info_prefix = (char *) xmalloc(strlen(package_name) + 20 + 4 + 2); | ||
1568 | sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name); | ||
1569 | archive_handle = init_archive_deb_ar(deb_file->filename); | ||
1570 | init_archive_deb_control(archive_handle); | ||
1571 | |||
1572 | while(all_control_files[i]) { | ||
1573 | char *c = (char *) xmalloc(3 + bb_strlen(all_control_files[i])); | ||
1574 | sprintf(c, "./%s", all_control_files[i]); | ||
1575 | accept_list= llist_add_to(accept_list, c); | ||
1576 | i++; | ||
1577 | } | ||
1578 | archive_handle->sub_archive->accept = accept_list; | ||
1579 | archive_handle->sub_archive->filter = filter_accept_list; | ||
1580 | archive_handle->sub_archive->action_data = data_extract_all_prefix; | ||
1581 | archive_handle->sub_archive->buffer = info_prefix; | ||
1582 | archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; | ||
1583 | unpack_ar_archive(archive_handle); | ||
1584 | |||
1585 | /* Run the preinst prior to extracting */ | ||
1586 | if (run_package_script(package_name, "preinst") != 0) { | ||
1587 | /* when preinst returns exit code != 0 then quit installation process */ | ||
1588 | bb_error_msg_and_die("subprocess pre-installation script returned error."); | ||
1589 | } | ||
1590 | |||
1591 | /* Extract data.tar.gz to the root directory */ | ||
1592 | archive_handle = init_archive_deb_ar(deb_file->filename); | ||
1593 | init_archive_deb_data(archive_handle); | ||
1594 | archive_handle->sub_archive->action_data = data_extract_all_prefix; | ||
1595 | archive_handle->sub_archive->buffer = "/"; | ||
1596 | archive_handle->sub_archive->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; | ||
1597 | unpack_ar_archive(archive_handle); | ||
1598 | |||
1599 | /* Create the list file */ | ||
1600 | strcat(info_prefix, "list"); | ||
1601 | out_stream = bb_xfopen(info_prefix, "w"); | ||
1602 | while (archive_handle->sub_archive->passed) { | ||
1603 | /* the leading . has been stripped by data_extract_all_prefix already */ | ||
1604 | fputs(archive_handle->sub_archive->passed->data, out_stream); | ||
1605 | fputc('\n', out_stream); | ||
1606 | archive_handle->sub_archive->passed = archive_handle->sub_archive->passed->link; | ||
1607 | } | ||
1608 | fclose(out_stream); | ||
1609 | |||
1610 | /* change status */ | ||
1611 | set_status(status_num, "install", 1); | ||
1612 | set_status(status_num, "unpacked", 3); | ||
1613 | |||
1614 | free(info_prefix); | ||
1615 | } | ||
1616 | |||
1617 | void configure_package(deb_file_t *deb_file) | ||
1618 | { | ||
1619 | const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; | ||
1620 | const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version]; | ||
1621 | const int status_num = search_status_hashtable(package_name); | ||
1622 | |||
1623 | printf("Setting up %s (%s) ...\n", package_name, package_version); | ||
1624 | |||
1625 | /* Run the postinst script */ | ||
1626 | if (run_package_script(package_name, "postinst") != 0) { | ||
1627 | /* TODO: handle failure gracefully */ | ||
1628 | bb_error_msg_and_die("postrm failure.. set status to what?"); | ||
1629 | } | ||
1630 | /* Change status to reflect success */ | ||
1631 | set_status(status_num, "install", 1); | ||
1632 | set_status(status_num, "installed", 3); | ||
1633 | } | ||
1634 | |||
1635 | int dpkg_main(int argc, char **argv) | ||
1636 | { | ||
1637 | deb_file_t **deb_file = NULL; | ||
1638 | status_node_t *status_node; | ||
1639 | int opt; | ||
1640 | int package_num; | ||
1641 | int dpkg_opt = 0; | ||
1642 | int deb_count = 0; | ||
1643 | int state_status; | ||
1644 | int status_num; | ||
1645 | int i; | ||
1646 | |||
1647 | while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) { | ||
1648 | switch (opt) { | ||
1649 | case 'C': // equivalent to --configure in official dpkg | ||
1650 | dpkg_opt |= dpkg_opt_configure; | ||
1651 | dpkg_opt |= dpkg_opt_package_name; | ||
1652 | break; | ||
1653 | case 'F': // equivalent to --force in official dpkg | ||
1654 | if (strcmp(optarg, "depends") == 0) { | ||
1655 | dpkg_opt |= dpkg_opt_force_ignore_depends; | ||
1656 | } | ||
1657 | break; | ||
1658 | case 'i': | ||
1659 | dpkg_opt |= dpkg_opt_install; | ||
1660 | dpkg_opt |= dpkg_opt_filename; | ||
1661 | break; | ||
1662 | case 'l': | ||
1663 | dpkg_opt |= dpkg_opt_list_installed; | ||
1664 | break; | ||
1665 | case 'P': | ||
1666 | dpkg_opt |= dpkg_opt_purge; | ||
1667 | dpkg_opt |= dpkg_opt_package_name; | ||
1668 | break; | ||
1669 | case 'r': | ||
1670 | dpkg_opt |= dpkg_opt_remove; | ||
1671 | dpkg_opt |= dpkg_opt_package_name; | ||
1672 | break; | ||
1673 | case 'u': /* Equivalent to --unpack in official dpkg */ | ||
1674 | dpkg_opt |= dpkg_opt_unpack; | ||
1675 | dpkg_opt |= dpkg_opt_filename; | ||
1676 | break; | ||
1677 | default: | ||
1678 | bb_show_usage(); | ||
1679 | } | ||
1680 | } | ||
1681 | /* check for non-otion argument if expected */ | ||
1682 | if ((dpkg_opt == 0) || ((argc == optind) && !(dpkg_opt && dpkg_opt_list_installed))) { | ||
1683 | bb_show_usage(); | ||
1684 | } | ||
1685 | |||
1686 | /* puts("(Reading database ... xxxxx files and directories installed.)"); */ | ||
1687 | index_status_file("/var/lib/dpkg/status"); | ||
1688 | |||
1689 | /* if the list action was given print the installed packages and exit */ | ||
1690 | if (dpkg_opt & dpkg_opt_list_installed) { | ||
1691 | list_packages(); | ||
1692 | return(EXIT_SUCCESS); | ||
1693 | } | ||
1694 | |||
1695 | /* Read arguments and store relevant info in structs */ | ||
1696 | while (optind < argc) { | ||
1697 | /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ | ||
1698 | deb_file = xrealloc(deb_file, sizeof(deb_file_t *) * (deb_count + 2)); | ||
1699 | deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t)); | ||
1700 | if (dpkg_opt & dpkg_opt_filename) { | ||
1701 | archive_handle_t *archive_handle; | ||
1702 | llist_t *control_list = NULL; | ||
1703 | |||
1704 | /* Extract the control file */ | ||
1705 | control_list = llist_add_to(NULL, "./control"); | ||
1706 | archive_handle = init_archive_deb_ar(argv[optind]); | ||
1707 | init_archive_deb_control(archive_handle); | ||
1708 | deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); | ||
1709 | if (deb_file[deb_count]->control_file == NULL) { | ||
1710 | bb_error_msg_and_die("Couldnt extract control file"); | ||
1711 | } | ||
1712 | deb_file[deb_count]->filename = bb_xstrdup(argv[optind]); | ||
1713 | package_num = fill_package_struct(deb_file[deb_count]->control_file); | ||
1714 | |||
1715 | if (package_num == -1) { | ||
1716 | bb_error_msg("Invalid control file in %s", argv[optind]); | ||
1717 | continue; | ||
1718 | } | ||
1719 | deb_file[deb_count]->package = (unsigned int) package_num; | ||
1720 | |||
1721 | /* Add the package to the status hashtable */ | ||
1722 | if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) { | ||
1723 | /* Try and find a currently installed version of this package */ | ||
1724 | status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); | ||
1725 | /* If no previous entry was found initialise a new entry */ | ||
1726 | if ((status_hashtable[status_num] == NULL) || | ||
1727 | (status_hashtable[status_num]->status == 0)) { | ||
1728 | status_node = (status_node_t *) xmalloc(sizeof(status_node_t)); | ||
1729 | status_node->package = deb_file[deb_count]->package; | ||
1730 | /* reinstreq isnt changed to "ok" until the package control info | ||
1731 | * is written to the status file*/ | ||
1732 | status_node->status = search_name_hashtable("install reinstreq not-installed"); | ||
1733 | status_hashtable[status_num] = status_node; | ||
1734 | } else { | ||
1735 | set_status(status_num, "install", 1); | ||
1736 | set_status(status_num, "reinstreq", 2); | ||
1737 | } | ||
1738 | } | ||
1739 | } | ||
1740 | else if (dpkg_opt & dpkg_opt_package_name) { | ||
1741 | deb_file[deb_count]->filename = NULL; | ||
1742 | deb_file[deb_count]->control_file = NULL; | ||
1743 | deb_file[deb_count]->package = search_package_hashtable( | ||
1744 | search_name_hashtable(argv[optind]), | ||
1745 | search_name_hashtable("ANY"), VER_ANY); | ||
1746 | if (package_hashtable[deb_file[deb_count]->package] == NULL) { | ||
1747 | bb_error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]); | ||
1748 | } | ||
1749 | package_num = deb_file[deb_count]->package; | ||
1750 | status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); | ||
1751 | state_status = get_status(status_num, 3); | ||
1752 | |||
1753 | /* check package status is "installed" */ | ||
1754 | if (dpkg_opt & dpkg_opt_remove) { | ||
1755 | if ((strcmp(name_hashtable[state_status], "not-installed") == 0) || | ||
1756 | (strcmp(name_hashtable[state_status], "config-files") == 0)) { | ||
1757 | bb_error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[package_num]->name]); | ||
1758 | } | ||
1759 | set_status(status_num, "deinstall", 1); | ||
1760 | } | ||
1761 | else if (dpkg_opt & dpkg_opt_purge) { | ||
1762 | /* if package status is "conf-files" then its ok */ | ||
1763 | if (strcmp(name_hashtable[state_status], "not-installed") == 0) { | ||
1764 | bb_error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[package_num]->name]); | ||
1765 | } | ||
1766 | set_status(status_num, "purge", 1); | ||
1767 | } | ||
1768 | } | ||
1769 | deb_count++; | ||
1770 | optind++; | ||
1771 | } | ||
1772 | deb_file[deb_count] = NULL; | ||
1773 | |||
1774 | /* Check that the deb file arguments are installable */ | ||
1775 | if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) { | ||
1776 | if (!check_deps(deb_file, 0, deb_count)) { | ||
1777 | bb_error_msg_and_die("Dependency check failed"); | ||
1778 | } | ||
1779 | } | ||
1780 | |||
1781 | /* TODO: install or remove packages in the correct dependency order */ | ||
1782 | for (i = 0; i < deb_count; i++) { | ||
1783 | /* Remove or purge packages */ | ||
1784 | if (dpkg_opt & dpkg_opt_remove) { | ||
1785 | remove_package(deb_file[i]->package, 1); | ||
1786 | } | ||
1787 | else if (dpkg_opt & dpkg_opt_purge) { | ||
1788 | purge_package(deb_file[i]->package); | ||
1789 | } | ||
1790 | else if (dpkg_opt & dpkg_opt_unpack) { | ||
1791 | unpack_package(deb_file[i]); | ||
1792 | } | ||
1793 | else if (dpkg_opt & dpkg_opt_install) { | ||
1794 | unpack_package(deb_file[i]); | ||
1795 | /* package is configured in second pass below */ | ||
1796 | } | ||
1797 | else if (dpkg_opt & dpkg_opt_configure) { | ||
1798 | configure_package(deb_file[i]); | ||
1799 | } | ||
1800 | } | ||
1801 | /* configure installed packages */ | ||
1802 | if (dpkg_opt & dpkg_opt_install) { | ||
1803 | for (i = 0; i < deb_count; i++) | ||
1804 | configure_package(deb_file[i]); | ||
1805 | } | ||
1806 | |||
1807 | write_status_file(deb_file); | ||
1808 | |||
1809 | for (i = 0; i < deb_count; i++) { | ||
1810 | free(deb_file[i]->control_file); | ||
1811 | free(deb_file[i]->filename); | ||
1812 | free(deb_file[i]); | ||
1813 | } | ||
1814 | |||
1815 | free(deb_file); | ||
1816 | |||
1817 | for (i = 0; i < NAME_HASH_PRIME; i++) { | ||
1818 | free(name_hashtable[i]); | ||
1819 | } | ||
1820 | |||
1821 | for (i = 0; i < PACKAGE_HASH_PRIME; i++) { | ||
1822 | if (package_hashtable[i] != NULL) { | ||
1823 | free_package(package_hashtable[i]); | ||
1824 | } | ||
1825 | } | ||
1826 | |||
1827 | for (i = 0; i < STATUS_HASH_PRIME; i++) { | ||
1828 | free(status_hashtable[i]); | ||
1829 | } | ||
1830 | |||
1831 | return(EXIT_SUCCESS); | ||
1832 | } | ||
1833 | |||
diff --git a/busybox/archival/dpkg_deb.c b/busybox/archival/dpkg_deb.c new file mode 100644 index 000000000..5aa9881d5 --- /dev/null +++ b/busybox/archival/dpkg_deb.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | * | ||
16 | */ | ||
17 | #include <fcntl.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <unistd.h> | ||
21 | #include <getopt.h> | ||
22 | |||
23 | #include "unarchive.h" | ||
24 | #include "busybox.h" | ||
25 | |||
26 | #define DPKG_DEB_OPT_CONTENTS 1 | ||
27 | #define DPKG_DEB_OPT_CONTROL 2 | ||
28 | #define DPKG_DEB_OPT_FIELD 4 | ||
29 | #define DPKG_DEB_OPT_EXTRACT 8 | ||
30 | #define DPKG_DEB_OPT_EXTRACT_VERBOSE 16 | ||
31 | |||
32 | extern int dpkg_deb_main(int argc, char **argv) | ||
33 | { | ||
34 | archive_handle_t *ar_archive; | ||
35 | archive_handle_t *tar_archive; | ||
36 | llist_t *control_tar_llist = NULL; | ||
37 | unsigned long opt; | ||
38 | char *extract_dir = NULL; | ||
39 | short argcount = 1; | ||
40 | |||
41 | /* Setup the tar archive handle */ | ||
42 | tar_archive = init_handle(); | ||
43 | |||
44 | /* Setup an ar archive handle that refers to the gzip sub archive */ | ||
45 | ar_archive = init_handle(); | ||
46 | ar_archive->sub_archive = tar_archive; | ||
47 | ar_archive->filter = filter_accept_list_reassign; | ||
48 | |||
49 | #ifdef CONFIG_FEATURE_DEB_TAR_GZ | ||
50 | ar_archive->accept = llist_add_to(NULL, "data.tar.gz"); | ||
51 | control_tar_llist = llist_add_to(NULL, "control.tar.gz"); | ||
52 | #endif | ||
53 | |||
54 | #ifdef CONFIG_FEATURE_DEB_TAR_BZ2 | ||
55 | ar_archive->accept = llist_add_to(ar_archive->accept, "data.tar.bz2"); | ||
56 | control_tar_llist = llist_add_to(control_tar_llist, "control.tar.bz2"); | ||
57 | #endif | ||
58 | |||
59 | bb_opt_complementaly = "c~efXx:e~cfXx:f~ceXx:X~cefx:x~cefX"; | ||
60 | opt = bb_getopt_ulflags(argc, argv, "cefXx"); | ||
61 | |||
62 | if (opt & DPKG_DEB_OPT_CONTENTS) { | ||
63 | tar_archive->action_header = header_verbose_list; | ||
64 | } | ||
65 | if (opt & DPKG_DEB_OPT_CONTROL) { | ||
66 | ar_archive->accept = control_tar_llist; | ||
67 | tar_archive->action_data = data_extract_all; | ||
68 | if (optind + 1 == argc) { | ||
69 | extract_dir = "./DEBIAN"; | ||
70 | } else { | ||
71 | argcount++; | ||
72 | } | ||
73 | } | ||
74 | if (opt & DPKG_DEB_OPT_FIELD) { | ||
75 | /* Print the entire control file | ||
76 | * it should accept a second argument which specifies a | ||
77 | * specific field to print */ | ||
78 | ar_archive->accept = control_tar_llist; | ||
79 | tar_archive->accept = llist_add_to(NULL, "./control");; | ||
80 | tar_archive->filter = filter_accept_list; | ||
81 | tar_archive->action_data = data_extract_to_stdout; | ||
82 | } | ||
83 | if (opt & DPKG_DEB_OPT_EXTRACT) { | ||
84 | tar_archive->action_header = header_list; | ||
85 | } | ||
86 | if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) { | ||
87 | tar_archive->action_data = data_extract_all; | ||
88 | argcount = 2; | ||
89 | } | ||
90 | |||
91 | if ((optind + argcount != argc) || (opt & 0x80000000UL)) { | ||
92 | bb_show_usage(); | ||
93 | } | ||
94 | |||
95 | tar_archive->src_fd = ar_archive->src_fd = bb_xopen(argv[optind++], O_RDONLY); | ||
96 | |||
97 | /* Workout where to extract the files */ | ||
98 | /* 2nd argument is a dir name */ | ||
99 | if (argv[optind]) { | ||
100 | extract_dir = argv[optind]; | ||
101 | } | ||
102 | if (extract_dir) { | ||
103 | mkdir(extract_dir, 0777); | ||
104 | chdir(extract_dir); | ||
105 | } | ||
106 | unpack_ar_archive(ar_archive); | ||
107 | |||
108 | /* Cleanup */ | ||
109 | close (ar_archive->src_fd); | ||
110 | |||
111 | return(EXIT_SUCCESS); | ||
112 | } | ||
diff --git a/busybox/archival/gunzip.c b/busybox/archival/gunzip.c new file mode 100644 index 000000000..beb7bd12e --- /dev/null +++ b/busybox/archival/gunzip.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Gzip implementation for busybox | ||
4 | * | ||
5 | * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. | ||
6 | * | ||
7 | * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de> | ||
8 | * based on gzip sources | ||
9 | * | ||
10 | * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as | ||
11 | * well as stdin/stdout, and to generally behave itself wrt command line | ||
12 | * handling. | ||
13 | * | ||
14 | * General cleanup to better adhere to the style guide and make use of standard | ||
15 | * busybox functions by Glenn McGrath <bug1@iinet.net.au> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
25 | * General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
30 | * | ||
31 | * | ||
32 | * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface | ||
33 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
34 | * The unzip code was written and put in the public domain by Mark Adler. | ||
35 | * Portions of the lzw code are derived from the public domain 'compress' | ||
36 | * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, | ||
37 | * Ken Turkowski, Dave Mack and Peter Jannesen. | ||
38 | * | ||
39 | * See the license_msg below and the file COPYING for the software license. | ||
40 | * See the file algorithm.doc for the compression algorithms and file formats. | ||
41 | */ | ||
42 | |||
43 | #if 0 | ||
44 | static char *license_msg[] = { | ||
45 | " Copyright (C) 1992-1993 Jean-loup Gailly", | ||
46 | " This program is free software; you can redistribute it and/or modify", | ||
47 | " it under the terms of the GNU General Public License as published by", | ||
48 | " the Free Software Foundation; either version 2, or (at your option)", | ||
49 | " any later version.", | ||
50 | "", | ||
51 | " This program is distributed in the hope that it will be useful,", | ||
52 | " but WITHOUT ANY WARRANTY; without even the implied warranty of", | ||
53 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", | ||
54 | " GNU General Public License for more details.", | ||
55 | "", | ||
56 | " You should have received a copy of the GNU General Public License", | ||
57 | " along with this program; if not, write to the Free Software", | ||
58 | " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.", | ||
59 | 0 | ||
60 | }; | ||
61 | #endif | ||
62 | |||
63 | #include <stdlib.h> | ||
64 | #include <string.h> | ||
65 | #include <unistd.h> | ||
66 | #include <getopt.h> | ||
67 | #include <sys/types.h> | ||
68 | #include <sys/stat.h> | ||
69 | #include <fcntl.h> | ||
70 | |||
71 | #include "busybox.h" | ||
72 | #include "unarchive.h" | ||
73 | |||
74 | #define GUNZIP_OPT_STDOUT 1 | ||
75 | #define GUNZIP_OPT_FORCE 2 | ||
76 | #define GUNZIP_OPT_TEST 4 | ||
77 | #define GUNZIP_OPT_DECOMPRESS 8 | ||
78 | |||
79 | extern int gunzip_main(int argc, char **argv) | ||
80 | { | ||
81 | char status = EXIT_SUCCESS; | ||
82 | unsigned long opt; | ||
83 | |||
84 | opt = bb_getopt_ulflags(argc, argv, "cftd"); | ||
85 | /* if called as zcat */ | ||
86 | if (strcmp(bb_applet_name, "zcat") == 0) { | ||
87 | opt |= GUNZIP_OPT_STDOUT; | ||
88 | } | ||
89 | |||
90 | do { | ||
91 | struct stat stat_buf; | ||
92 | const char *old_path = argv[optind]; | ||
93 | const char *delete_path = NULL; | ||
94 | char *new_path = NULL; | ||
95 | int src_fd; | ||
96 | int dst_fd; | ||
97 | |||
98 | optind++; | ||
99 | |||
100 | if (old_path == NULL || strcmp(old_path, "-") == 0) { | ||
101 | src_fd = STDIN_FILENO; | ||
102 | opt |= GUNZIP_OPT_STDOUT; | ||
103 | } else { | ||
104 | src_fd = bb_xopen(old_path, O_RDONLY); | ||
105 | |||
106 | /* Get the time stamp on the input file. */ | ||
107 | if (stat(old_path, &stat_buf) < 0) { | ||
108 | bb_error_msg_and_die("Couldn't stat file %s", old_path); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | /* Check that the input is sane. */ | ||
113 | if (isatty(src_fd) && ((opt & GUNZIP_OPT_FORCE) == 0)) { | ||
114 | bb_error_msg_and_die | ||
115 | ("compressed data not read from terminal. Use -f to force it."); | ||
116 | } | ||
117 | |||
118 | /* Set output filename and number */ | ||
119 | if (opt & GUNZIP_OPT_TEST) { | ||
120 | dst_fd = bb_xopen("/dev/null", O_WRONLY); /* why does test use filenum 2 ? */ | ||
121 | } else if (opt & GUNZIP_OPT_STDOUT) { | ||
122 | dst_fd = STDOUT_FILENO; | ||
123 | } else { | ||
124 | char *extension; | ||
125 | |||
126 | new_path = bb_xstrdup(old_path); | ||
127 | |||
128 | extension = strrchr(new_path, '.'); | ||
129 | #ifdef CONFIG_FEATURE_GUNZIP_UNCOMPRESS | ||
130 | if (extension && (strcmp(extension, ".Z") == 0)) { | ||
131 | *extension = '\0'; | ||
132 | } else | ||
133 | #endif | ||
134 | if (extension && (strcmp(extension, ".gz") == 0)) { | ||
135 | *extension = '\0'; | ||
136 | } else if (extension && (strcmp(extension, ".tgz") == 0)) { | ||
137 | extension[2] = 'a'; | ||
138 | extension[3] = 'r'; | ||
139 | } else { | ||
140 | bb_error_msg_and_die("Invalid extension"); | ||
141 | } | ||
142 | |||
143 | /* Open output file */ | ||
144 | dst_fd = bb_xopen(new_path, O_WRONLY | O_CREAT); | ||
145 | |||
146 | /* Set permissions on the file */ | ||
147 | chmod(new_path, stat_buf.st_mode); | ||
148 | |||
149 | /* If unzip succeeds remove the old file */ | ||
150 | delete_path = old_path; | ||
151 | } | ||
152 | |||
153 | /* do the decompression, and cleanup */ | ||
154 | if (bb_xread_char(src_fd) == 0x1f) { | ||
155 | unsigned char magic2; | ||
156 | |||
157 | magic2 = bb_xread_char(src_fd); | ||
158 | #ifdef CONFIG_FEATURE_GUNZIP_UNCOMPRESS | ||
159 | if (magic2 == 0x9d) { | ||
160 | status = uncompress(src_fd, dst_fd); | ||
161 | } else | ||
162 | #endif | ||
163 | if (magic2 == 0x8b) { | ||
164 | check_header_gzip(src_fd); | ||
165 | status = inflate_gunzip(src_fd, dst_fd); | ||
166 | if (status != 0) { | ||
167 | bb_error_msg_and_die("Error inflating"); | ||
168 | } | ||
169 | } else { | ||
170 | bb_error_msg_and_die("Invalid magic"); | ||
171 | } | ||
172 | } else { | ||
173 | bb_error_msg_and_die("Invalid magic"); | ||
174 | } | ||
175 | |||
176 | if ((status != EXIT_SUCCESS) && (new_path)) { | ||
177 | /* Unzip failed, remove new path instead of old path */ | ||
178 | delete_path = new_path; | ||
179 | } | ||
180 | |||
181 | if (dst_fd != STDOUT_FILENO) { | ||
182 | close(dst_fd); | ||
183 | } | ||
184 | if (src_fd != STDIN_FILENO) { | ||
185 | close(src_fd); | ||
186 | } | ||
187 | |||
188 | /* delete_path will be NULL if in test mode or from stdin */ | ||
189 | if (delete_path && (unlink(delete_path) == -1)) { | ||
190 | bb_error_msg_and_die("Couldn't remove %s", delete_path); | ||
191 | } | ||
192 | |||
193 | free(new_path); | ||
194 | |||
195 | } while (optind < argc); | ||
196 | |||
197 | return status; | ||
198 | } | ||
diff --git a/busybox/archival/gzip.c b/busybox/archival/gzip.c new file mode 100644 index 000000000..d494aa30e --- /dev/null +++ b/busybox/archival/gzip.c | |||
@@ -0,0 +1,2548 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Gzip implementation for busybox | ||
4 | * | ||
5 | * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly. | ||
6 | * | ||
7 | * Originally adjusted for busybox by Charles P. Wright <cpw@unix.asb.com> | ||
8 | * "this is a stripped down version of gzip I put into busybox, it does | ||
9 | * only standard in to standard out with -9 compression. It also requires | ||
10 | * the zcat module for some important functions." | ||
11 | * | ||
12 | * Adjusted further by Erik Andersen <andersen@codepoet.org> to support | ||
13 | * files as well as stdin/stdout, and to generally behave itself wrt | ||
14 | * command line handling. | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
24 | * General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | /* These defines are very important for BusyBox. Without these, | ||
33 | * huge chunks of ram are pre-allocated making the BusyBox bss | ||
34 | * size Freaking Huge(tm), which is a bad thing.*/ | ||
35 | #define SMALL_MEM | ||
36 | #define DYN_ALLOC | ||
37 | |||
38 | #include <stdlib.h> | ||
39 | #include <stdio.h> | ||
40 | #include <string.h> | ||
41 | #include <unistd.h> | ||
42 | #include <errno.h> | ||
43 | #include <sys/types.h> | ||
44 | #include <signal.h> | ||
45 | #include <utime.h> | ||
46 | #include <ctype.h> | ||
47 | #include <sys/types.h> | ||
48 | #include <unistd.h> | ||
49 | #include <dirent.h> | ||
50 | #include <fcntl.h> | ||
51 | #include <time.h> | ||
52 | #include "busybox.h" | ||
53 | |||
54 | #define memzero(s, n) memset ((void *)(s), 0, (n)) | ||
55 | |||
56 | #ifndef RETSIGTYPE | ||
57 | # define RETSIGTYPE void | ||
58 | #endif | ||
59 | |||
60 | typedef unsigned char uch; | ||
61 | typedef unsigned short ush; | ||
62 | typedef unsigned long ulg; | ||
63 | |||
64 | /* Return codes from gzip */ | ||
65 | #define OK 0 | ||
66 | #define ERROR 1 | ||
67 | #define WARNING 2 | ||
68 | |||
69 | /* Compression methods (see algorithm.doc) */ | ||
70 | /* Only STORED and DEFLATED are supported by this BusyBox module */ | ||
71 | #define STORED 0 | ||
72 | /* methods 4 to 7 reserved */ | ||
73 | #define DEFLATED 8 | ||
74 | |||
75 | /* To save memory for 16 bit systems, some arrays are overlaid between | ||
76 | * the various modules: | ||
77 | * deflate: prev+head window d_buf l_buf outbuf | ||
78 | * unlzw: tab_prefix tab_suffix stack inbuf outbuf | ||
79 | * For compression, input is done in window[]. For decompression, output | ||
80 | * is done in window except for unlzw. | ||
81 | */ | ||
82 | |||
83 | #ifndef INBUFSIZ | ||
84 | # ifdef SMALL_MEM | ||
85 | # define INBUFSIZ 0x2000 /* input buffer size */ | ||
86 | # else | ||
87 | # define INBUFSIZ 0x8000 /* input buffer size */ | ||
88 | # endif | ||
89 | #endif | ||
90 | #define INBUF_EXTRA 64 /* required by unlzw() */ | ||
91 | |||
92 | #ifndef OUTBUFSIZ | ||
93 | # ifdef SMALL_MEM | ||
94 | # define OUTBUFSIZ 8192 /* output buffer size */ | ||
95 | # else | ||
96 | # define OUTBUFSIZ 16384 /* output buffer size */ | ||
97 | # endif | ||
98 | #endif | ||
99 | #define OUTBUF_EXTRA 2048 /* required by unlzw() */ | ||
100 | |||
101 | #ifndef DIST_BUFSIZE | ||
102 | # ifdef SMALL_MEM | ||
103 | # define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */ | ||
104 | # else | ||
105 | # define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ | ||
106 | # endif | ||
107 | #endif | ||
108 | |||
109 | #ifdef DYN_ALLOC | ||
110 | # define DECLARE(type, array, size) static type * array | ||
111 | # define ALLOC(type, array, size) { \ | ||
112 | array = (type*)xcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ | ||
113 | } | ||
114 | # define FREE(array) {free(array), array=NULL;} | ||
115 | #else | ||
116 | # define DECLARE(type, array, size) static type array[size] | ||
117 | # define ALLOC(type, array, size) | ||
118 | # define FREE(array) | ||
119 | #endif | ||
120 | |||
121 | #define tab_suffix window | ||
122 | #define tab_prefix prev /* hash link (see deflate.c) */ | ||
123 | #define head (prev+WSIZE) /* hash head (see deflate.c) */ | ||
124 | |||
125 | static long bytes_in; /* number of input bytes */ | ||
126 | |||
127 | #define isize bytes_in | ||
128 | /* for compatibility with old zip sources (to be cleaned) */ | ||
129 | |||
130 | typedef int file_t; /* Do not use stdio */ | ||
131 | |||
132 | #define NO_FILE (-1) /* in memory compression */ | ||
133 | |||
134 | |||
135 | #define PACK_MAGIC "\037\036" /* Magic header for packed files */ | ||
136 | #define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ | ||
137 | #define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ | ||
138 | #define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files */ | ||
139 | #define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */ | ||
140 | |||
141 | /* gzip flag byte */ | ||
142 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ | ||
143 | #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ | ||
144 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ | ||
145 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ | ||
146 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | ||
147 | #define RESERVED 0xC0 /* bit 6,7: reserved */ | ||
148 | |||
149 | /* internal file attribute */ | ||
150 | #define UNKNOWN 0xffff | ||
151 | #define BINARY 0 | ||
152 | #define ASCII 1 | ||
153 | |||
154 | #ifndef WSIZE | ||
155 | # define WSIZE 0x8000 /* window size--must be a power of two, and */ | ||
156 | #endif /* at least 32K for zip's deflate method */ | ||
157 | |||
158 | #define MIN_MATCH 3 | ||
159 | #define MAX_MATCH 258 | ||
160 | /* The minimum and maximum match lengths */ | ||
161 | |||
162 | #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) | ||
163 | /* Minimum amount of lookahead, except at the end of the input file. | ||
164 | * See deflate.c for comments about the MIN_MATCH+1. | ||
165 | */ | ||
166 | |||
167 | #define MAX_DIST (WSIZE-MIN_LOOKAHEAD) | ||
168 | /* In order to simplify the code, particularly on 16 bit machines, match | ||
169 | * distances are limited to MAX_DIST instead of WSIZE. | ||
170 | */ | ||
171 | |||
172 | /* put_byte is used for the compressed output */ | ||
173 | #define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ | ||
174 | flush_outbuf();} | ||
175 | |||
176 | |||
177 | /* Output a 32 bit value to the bit stream, lsb first */ | ||
178 | #if 0 | ||
179 | #define put_long(n) { \ | ||
180 | put_short((n) & 0xffff); \ | ||
181 | put_short(((ulg)(n)) >> 16); \ | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | #define seekable() 0 /* force sequential output */ | ||
186 | #define translate_eol 0 /* no option -a yet */ | ||
187 | |||
188 | /* Diagnostic functions */ | ||
189 | #ifdef DEBUG | ||
190 | # define Assert(cond,msg) {if(!(cond)) bb_error_msg(msg);} | ||
191 | # define Trace(x) fprintf x | ||
192 | # define Tracev(x) {if (verbose) fprintf x ;} | ||
193 | # define Tracevv(x) {if (verbose>1) fprintf x ;} | ||
194 | # define Tracec(c,x) {if (verbose && (c)) fprintf x ;} | ||
195 | # define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} | ||
196 | #else | ||
197 | # define Assert(cond,msg) | ||
198 | # define Trace(x) | ||
199 | # define Tracev(x) | ||
200 | # define Tracevv(x) | ||
201 | # define Tracec(c,x) | ||
202 | # define Tracecv(c,x) | ||
203 | #endif | ||
204 | |||
205 | #define WARN(msg) {if (!quiet) fprintf msg ; \ | ||
206 | if (exit_code == OK) exit_code = WARNING;} | ||
207 | |||
208 | #ifndef MAX_PATH_LEN | ||
209 | # define MAX_PATH_LEN 1024 /* max pathname length */ | ||
210 | #endif | ||
211 | |||
212 | |||
213 | /* from zip.c: */ | ||
214 | static int zip(int in, int out); | ||
215 | static int file_read(char *buf, unsigned size); | ||
216 | |||
217 | /* from gzip.c */ | ||
218 | static RETSIGTYPE abort_gzip(void); | ||
219 | |||
220 | /* from deflate.c */ | ||
221 | static void lm_init(ush * flags); | ||
222 | static ulg deflate(void); | ||
223 | |||
224 | /* from trees.c */ | ||
225 | static void ct_init(ush * attr, int *methodp); | ||
226 | static int ct_tally(int dist, int lc); | ||
227 | static ulg flush_block(char *buf, ulg stored_len, int eof); | ||
228 | |||
229 | /* from bits.c */ | ||
230 | static void bi_init(file_t zipfile); | ||
231 | static void send_bits(int value, int length); | ||
232 | static unsigned bi_reverse(unsigned value, int length); | ||
233 | static void bi_windup(void); | ||
234 | static void copy_block(char *buf, unsigned len, int header); | ||
235 | static int (*read_buf) (char *buf, unsigned size); | ||
236 | |||
237 | /* from util.c: */ | ||
238 | static void flush_outbuf(void); | ||
239 | |||
240 | /* lzw.h -- define the lzw functions. | ||
241 | * Copyright (C) 1992-1993 Jean-loup Gailly. | ||
242 | * This is free software; you can redistribute it and/or modify it under the | ||
243 | * terms of the GNU General Public License, see the file COPYING. | ||
244 | */ | ||
245 | |||
246 | #if !defined(OF) && defined(lint) | ||
247 | # include "gzip.h" | ||
248 | #endif | ||
249 | |||
250 | #ifndef BITS | ||
251 | # define BITS 16 | ||
252 | #endif | ||
253 | #define INIT_BITS 9 /* Initial number of bits per code */ | ||
254 | |||
255 | #define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ | ||
256 | /* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. | ||
257 | * It's a pity that old uncompress does not check bit 0x20. That makes | ||
258 | * extension of the format actually undesirable because old compress | ||
259 | * would just crash on the new format instead of giving a meaningful | ||
260 | * error message. It does check the number of bits, but it's more | ||
261 | * helpful to say "unsupported format, get a new version" than | ||
262 | * "can only handle 16 bits". | ||
263 | */ | ||
264 | |||
265 | /* tailor.h -- target dependent definitions | ||
266 | * Copyright (C) 1992-1993 Jean-loup Gailly. | ||
267 | * This is free software; you can redistribute it and/or modify it under the | ||
268 | * terms of the GNU General Public License, see the file COPYING. | ||
269 | */ | ||
270 | |||
271 | /* The target dependent definitions should be defined here only. | ||
272 | * The target dependent functions should be defined in tailor.c. | ||
273 | */ | ||
274 | |||
275 | |||
276 | /* Common defaults */ | ||
277 | |||
278 | #ifndef OS_CODE | ||
279 | # define OS_CODE 0x03 /* assume Unix */ | ||
280 | #endif | ||
281 | |||
282 | #ifndef PATH_SEP | ||
283 | # define PATH_SEP '/' | ||
284 | #endif | ||
285 | |||
286 | #ifndef OPTIONS_VAR | ||
287 | # define OPTIONS_VAR "GZIP" | ||
288 | #endif | ||
289 | |||
290 | #ifndef Z_SUFFIX | ||
291 | # define Z_SUFFIX ".gz" | ||
292 | #endif | ||
293 | |||
294 | #ifdef MAX_EXT_CHARS | ||
295 | # define MAX_SUFFIX MAX_EXT_CHARS | ||
296 | #else | ||
297 | # define MAX_SUFFIX 30 | ||
298 | #endif | ||
299 | |||
300 | /* global buffers */ | ||
301 | |||
302 | DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA); | ||
303 | DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); | ||
304 | DECLARE(ush, d_buf, DIST_BUFSIZE); | ||
305 | DECLARE(uch, window, 2L * WSIZE); | ||
306 | DECLARE(ush, tab_prefix, 1L << BITS); | ||
307 | |||
308 | static int foreground; /* set if program run in foreground */ | ||
309 | static int method = DEFLATED; /* compression method */ | ||
310 | static int exit_code = OK; /* program exit code */ | ||
311 | static int part_nb; /* number of parts in .gz file */ | ||
312 | static long time_stamp; /* original time stamp (modification time) */ | ||
313 | static long ifile_size; /* input file size, -1 for devices (debug only) */ | ||
314 | static char z_suffix[MAX_SUFFIX + 1]; /* default suffix (can be set with --suffix) */ | ||
315 | static int z_len; /* strlen(z_suffix) */ | ||
316 | |||
317 | static int ifd; /* input file descriptor */ | ||
318 | static int ofd; /* output file descriptor */ | ||
319 | static unsigned insize; /* valid bytes in inbuf */ | ||
320 | static unsigned outcnt; /* bytes in output buffer */ | ||
321 | |||
322 | |||
323 | /* Output a 16 bit value, lsb first */ | ||
324 | static void put_short(ush w) | ||
325 | { | ||
326 | if (outcnt < OUTBUFSIZ - 2) { | ||
327 | outbuf[outcnt++] = (uch) ((w) & 0xff); | ||
328 | outbuf[outcnt++] = (uch) ((ush) (w) >> 8); | ||
329 | } else { | ||
330 | put_byte((uch) ((w) & 0xff)); | ||
331 | put_byte((uch) ((ush) (w) >> 8)); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | /* ======================================================================== | ||
336 | * Signal and error handler. | ||
337 | */ | ||
338 | static void abort_gzip() | ||
339 | { | ||
340 | exit(ERROR); | ||
341 | } | ||
342 | |||
343 | /* =========================================================================== | ||
344 | * Clear input and output buffers | ||
345 | */ | ||
346 | static void clear_bufs(void) | ||
347 | { | ||
348 | outcnt = 0; | ||
349 | insize = 0; | ||
350 | bytes_in = 0L; | ||
351 | } | ||
352 | |||
353 | static void write_bb_error_msg(void) | ||
354 | { | ||
355 | fputc('\n', stderr); | ||
356 | bb_perror_nomsg(); | ||
357 | abort_gzip(); | ||
358 | } | ||
359 | |||
360 | /* =========================================================================== | ||
361 | * Does the same as write(), but also handles partial pipe writes and checks | ||
362 | * for error return. | ||
363 | */ | ||
364 | static void write_buf(int fd, void *buf, unsigned cnt) | ||
365 | { | ||
366 | unsigned n; | ||
367 | |||
368 | while ((n = write(fd, buf, cnt)) != cnt) { | ||
369 | if (n == (unsigned) (-1)) { | ||
370 | write_bb_error_msg(); | ||
371 | } | ||
372 | cnt -= n; | ||
373 | buf = (void *) ((char *) buf + n); | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* =========================================================================== | ||
378 | * Run a set of bytes through the crc shift register. If s is a NULL | ||
379 | * pointer, then initialize the crc shift register contents instead. | ||
380 | * Return the current crc in either case. | ||
381 | */ | ||
382 | static ulg updcrc(uch * s, unsigned n) | ||
383 | { | ||
384 | static ulg crc = (ulg) 0xffffffffL; /* shift register contents */ | ||
385 | register ulg c; /* temporary variable */ | ||
386 | static unsigned long crc_32_tab[256]; | ||
387 | |||
388 | if (crc_32_tab[1] == 0x00000000L) { | ||
389 | unsigned long csr; /* crc shift register */ | ||
390 | const unsigned long e = 0xedb88320L; /* polynomial exclusive-or pattern */ | ||
391 | int i; /* counter for all possible eight bit values */ | ||
392 | int k; /* byte being shifted into crc apparatus */ | ||
393 | |||
394 | /* Compute table of CRC's. */ | ||
395 | for (i = 1; i < 256; i++) { | ||
396 | csr = i; | ||
397 | /* The idea to initialize the register with the byte instead of | ||
398 | * zero was stolen from Haruhiko Okumura's ar002 | ||
399 | */ | ||
400 | for (k = 8; k; k--) | ||
401 | csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1; | ||
402 | crc_32_tab[i] = csr; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | if (s == NULL) { | ||
407 | c = 0xffffffffL; | ||
408 | } else { | ||
409 | c = crc; | ||
410 | if (n) | ||
411 | do { | ||
412 | c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8); | ||
413 | } while (--n); | ||
414 | } | ||
415 | crc = c; | ||
416 | return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ | ||
417 | } | ||
418 | |||
419 | /* bits.c -- output variable-length bit strings | ||
420 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
421 | * This is free software; you can redistribute it and/or modify it under the | ||
422 | * terms of the GNU General Public License, see the file COPYING. | ||
423 | */ | ||
424 | |||
425 | |||
426 | /* | ||
427 | * PURPOSE | ||
428 | * | ||
429 | * Output variable-length bit strings. Compression can be done | ||
430 | * to a file or to memory. (The latter is not supported in this version.) | ||
431 | * | ||
432 | * DISCUSSION | ||
433 | * | ||
434 | * The PKZIP "deflate" file format interprets compressed file data | ||
435 | * as a sequence of bits. Multi-bit strings in the file may cross | ||
436 | * byte boundaries without restriction. | ||
437 | * | ||
438 | * The first bit of each byte is the low-order bit. | ||
439 | * | ||
440 | * The routines in this file allow a variable-length bit value to | ||
441 | * be output right-to-left (useful for literal values). For | ||
442 | * left-to-right output (useful for code strings from the tree routines), | ||
443 | * the bits must have been reversed first with bi_reverse(). | ||
444 | * | ||
445 | * For in-memory compression, the compressed bit stream goes directly | ||
446 | * into the requested output buffer. The input data is read in blocks | ||
447 | * by the mem_read() function. The buffer is limited to 64K on 16 bit | ||
448 | * machines. | ||
449 | * | ||
450 | * INTERFACE | ||
451 | * | ||
452 | * void bi_init (FILE *zipfile) | ||
453 | * Initialize the bit string routines. | ||
454 | * | ||
455 | * void send_bits (int value, int length) | ||
456 | * Write out a bit string, taking the source bits right to | ||
457 | * left. | ||
458 | * | ||
459 | * int bi_reverse (int value, int length) | ||
460 | * Reverse the bits of a bit string, taking the source bits left to | ||
461 | * right and emitting them right to left. | ||
462 | * | ||
463 | * void bi_windup (void) | ||
464 | * Write out any remaining bits in an incomplete byte. | ||
465 | * | ||
466 | * void copy_block(char *buf, unsigned len, int header) | ||
467 | * Copy a stored block to the zip file, storing first the length and | ||
468 | * its one's complement if requested. | ||
469 | * | ||
470 | */ | ||
471 | |||
472 | /* =========================================================================== | ||
473 | * Local data used by the "bit string" routines. | ||
474 | */ | ||
475 | |||
476 | static file_t zfile; /* output gzip file */ | ||
477 | |||
478 | static unsigned short bi_buf; | ||
479 | |||
480 | /* Output buffer. bits are inserted starting at the bottom (least significant | ||
481 | * bits). | ||
482 | */ | ||
483 | |||
484 | #define Buf_size (8 * 2*sizeof(char)) | ||
485 | /* Number of bits used within bi_buf. (bi_buf might be implemented on | ||
486 | * more than 16 bits on some systems.) | ||
487 | */ | ||
488 | |||
489 | static int bi_valid; | ||
490 | |||
491 | /* Current input function. Set to mem_read for in-memory compression */ | ||
492 | |||
493 | #ifdef DEBUG | ||
494 | ulg bits_sent; /* bit length of the compressed data */ | ||
495 | #endif | ||
496 | |||
497 | /* =========================================================================== | ||
498 | * Initialize the bit string routines. | ||
499 | */ | ||
500 | static void bi_init(file_t zipfile) | ||
501 | { | ||
502 | zfile = zipfile; | ||
503 | bi_buf = 0; | ||
504 | bi_valid = 0; | ||
505 | #ifdef DEBUG | ||
506 | bits_sent = 0L; | ||
507 | #endif | ||
508 | |||
509 | /* Set the defaults for file compression. They are set by memcompress | ||
510 | * for in-memory compression. | ||
511 | */ | ||
512 | if (zfile != NO_FILE) { | ||
513 | read_buf = file_read; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* =========================================================================== | ||
518 | * Send a value on a given number of bits. | ||
519 | * IN assertion: length <= 16 and value fits in length bits. | ||
520 | */ | ||
521 | static void send_bits(int value, int length) | ||
522 | { | ||
523 | #ifdef DEBUG | ||
524 | Tracev((stderr, " l %2d v %4x ", length, value)); | ||
525 | Assert(length > 0 && length <= 15, "invalid length"); | ||
526 | bits_sent += (ulg) length; | ||
527 | #endif | ||
528 | /* If not enough room in bi_buf, use (valid) bits from bi_buf and | ||
529 | * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) | ||
530 | * unused bits in value. | ||
531 | */ | ||
532 | if (bi_valid > (int) Buf_size - length) { | ||
533 | bi_buf |= (value << bi_valid); | ||
534 | put_short(bi_buf); | ||
535 | bi_buf = (ush) value >> (Buf_size - bi_valid); | ||
536 | bi_valid += length - Buf_size; | ||
537 | } else { | ||
538 | bi_buf |= value << bi_valid; | ||
539 | bi_valid += length; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | /* =========================================================================== | ||
544 | * Reverse the first len bits of a code, using straightforward code (a faster | ||
545 | * method would use a table) | ||
546 | * IN assertion: 1 <= len <= 15 | ||
547 | */ | ||
548 | static unsigned bi_reverse(unsigned code, int len) | ||
549 | { | ||
550 | register unsigned res = 0; | ||
551 | |||
552 | do { | ||
553 | res |= code & 1; | ||
554 | code >>= 1, res <<= 1; | ||
555 | } while (--len > 0); | ||
556 | return res >> 1; | ||
557 | } | ||
558 | |||
559 | /* =========================================================================== | ||
560 | * Write out any remaining bits in an incomplete byte. | ||
561 | */ | ||
562 | static void bi_windup() | ||
563 | { | ||
564 | if (bi_valid > 8) { | ||
565 | put_short(bi_buf); | ||
566 | } else if (bi_valid > 0) { | ||
567 | put_byte(bi_buf); | ||
568 | } | ||
569 | bi_buf = 0; | ||
570 | bi_valid = 0; | ||
571 | #ifdef DEBUG | ||
572 | bits_sent = (bits_sent + 7) & ~7; | ||
573 | #endif | ||
574 | } | ||
575 | |||
576 | /* =========================================================================== | ||
577 | * Copy a stored block to the zip file, storing first the length and its | ||
578 | * one's complement if requested. | ||
579 | */ | ||
580 | static void copy_block(char *buf, unsigned len, int header) | ||
581 | { | ||
582 | bi_windup(); /* align on byte boundary */ | ||
583 | |||
584 | if (header) { | ||
585 | put_short((ush) len); | ||
586 | put_short((ush) ~ len); | ||
587 | #ifdef DEBUG | ||
588 | bits_sent += 2 * 16; | ||
589 | #endif | ||
590 | } | ||
591 | #ifdef DEBUG | ||
592 | bits_sent += (ulg) len << 3; | ||
593 | #endif | ||
594 | while (len--) { | ||
595 | put_byte(*buf++); | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /* deflate.c -- compress data using the deflation algorithm | ||
600 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
601 | * This is free software; you can redistribute it and/or modify it under the | ||
602 | * terms of the GNU General Public License, see the file COPYING. | ||
603 | */ | ||
604 | |||
605 | /* | ||
606 | * PURPOSE | ||
607 | * | ||
608 | * Identify new text as repetitions of old text within a fixed- | ||
609 | * length sliding window trailing behind the new text. | ||
610 | * | ||
611 | * DISCUSSION | ||
612 | * | ||
613 | * The "deflation" process depends on being able to identify portions | ||
614 | * of the input text which are identical to earlier input (within a | ||
615 | * sliding window trailing behind the input currently being processed). | ||
616 | * | ||
617 | * The most straightforward technique turns out to be the fastest for | ||
618 | * most input files: try all possible matches and select the longest. | ||
619 | * The key feature of this algorithm is that insertions into the string | ||
620 | * dictionary are very simple and thus fast, and deletions are avoided | ||
621 | * completely. Insertions are performed at each input character, whereas | ||
622 | * string matches are performed only when the previous match ends. So it | ||
623 | * is preferable to spend more time in matches to allow very fast string | ||
624 | * insertions and avoid deletions. The matching algorithm for small | ||
625 | * strings is inspired from that of Rabin & Karp. A brute force approach | ||
626 | * is used to find longer strings when a small match has been found. | ||
627 | * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze | ||
628 | * (by Leonid Broukhis). | ||
629 | * A previous version of this file used a more sophisticated algorithm | ||
630 | * (by Fiala and Greene) which is guaranteed to run in linear amortized | ||
631 | * time, but has a larger average cost, uses more memory and is patented. | ||
632 | * However the F&G algorithm may be faster for some highly redundant | ||
633 | * files if the parameter max_chain_length (described below) is too large. | ||
634 | * | ||
635 | * ACKNOWLEDGMENTS | ||
636 | * | ||
637 | * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and | ||
638 | * I found it in 'freeze' written by Leonid Broukhis. | ||
639 | * Thanks to many info-zippers for bug reports and testing. | ||
640 | * | ||
641 | * REFERENCES | ||
642 | * | ||
643 | * APPNOTE.TXT documentation file in PKZIP 1.93a distribution. | ||
644 | * | ||
645 | * A description of the Rabin and Karp algorithm is given in the book | ||
646 | * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. | ||
647 | * | ||
648 | * Fiala,E.R., and Greene,D.H. | ||
649 | * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 | ||
650 | * | ||
651 | * INTERFACE | ||
652 | * | ||
653 | * void lm_init (int pack_level, ush *flags) | ||
654 | * Initialize the "longest match" routines for a new file | ||
655 | * | ||
656 | * ulg deflate (void) | ||
657 | * Processes a new input file and return its compressed length. Sets | ||
658 | * the compressed length, crc, deflate flags and internal file | ||
659 | * attributes. | ||
660 | */ | ||
661 | |||
662 | |||
663 | /* =========================================================================== | ||
664 | * Configuration parameters | ||
665 | */ | ||
666 | |||
667 | /* Compile with MEDIUM_MEM to reduce the memory requirements or | ||
668 | * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the | ||
669 | * entire input file can be held in memory (not possible on 16 bit systems). | ||
670 | * Warning: defining these symbols affects HASH_BITS (see below) and thus | ||
671 | * affects the compression ratio. The compressed output | ||
672 | * is still correct, and might even be smaller in some cases. | ||
673 | */ | ||
674 | |||
675 | #ifdef SMALL_MEM | ||
676 | # define HASH_BITS 13 /* Number of bits used to hash strings */ | ||
677 | #endif | ||
678 | #ifdef MEDIUM_MEM | ||
679 | # define HASH_BITS 14 | ||
680 | #endif | ||
681 | #ifndef HASH_BITS | ||
682 | # define HASH_BITS 15 | ||
683 | /* For portability to 16 bit machines, do not use values above 15. */ | ||
684 | #endif | ||
685 | |||
686 | /* To save space (see unlzw.c), we overlay prev+head with tab_prefix and | ||
687 | * window with tab_suffix. Check that we can do this: | ||
688 | */ | ||
689 | #if (WSIZE<<1) > (1<<BITS) | ||
690 | # error cannot overlay window with tab_suffix and prev with tab_prefix0 | ||
691 | #endif | ||
692 | #if HASH_BITS > BITS-1 | ||
693 | # error cannot overlay head with tab_prefix1 | ||
694 | #endif | ||
695 | #define HASH_SIZE (unsigned)(1<<HASH_BITS) | ||
696 | #define HASH_MASK (HASH_SIZE-1) | ||
697 | #define WMASK (WSIZE-1) | ||
698 | /* HASH_SIZE and WSIZE must be powers of two */ | ||
699 | #define NIL 0 | ||
700 | /* Tail of hash chains */ | ||
701 | #define FAST 4 | ||
702 | #define SLOW 2 | ||
703 | /* speed options for the general purpose bit flag */ | ||
704 | #ifndef TOO_FAR | ||
705 | # define TOO_FAR 4096 | ||
706 | #endif | ||
707 | /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ | ||
708 | /* =========================================================================== | ||
709 | * Local data used by the "longest match" routines. | ||
710 | */ | ||
711 | typedef ush Pos; | ||
712 | typedef unsigned IPos; | ||
713 | |||
714 | /* A Pos is an index in the character window. We use short instead of int to | ||
715 | * save space in the various tables. IPos is used only for parameter passing. | ||
716 | */ | ||
717 | |||
718 | /* DECLARE(uch, window, 2L*WSIZE); */ | ||
719 | /* Sliding window. Input bytes are read into the second half of the window, | ||
720 | * and move to the first half later to keep a dictionary of at least WSIZE | ||
721 | * bytes. With this organization, matches are limited to a distance of | ||
722 | * WSIZE-MAX_MATCH bytes, but this ensures that IO is always | ||
723 | * performed with a length multiple of the block size. Also, it limits | ||
724 | * the window size to 64K, which is quite useful on MSDOS. | ||
725 | * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would | ||
726 | * be less efficient). | ||
727 | */ | ||
728 | |||
729 | /* DECLARE(Pos, prev, WSIZE); */ | ||
730 | /* Link to older string with same hash index. To limit the size of this | ||
731 | * array to 64K, this link is maintained only for the last 32K strings. | ||
732 | * An index in this array is thus a window index modulo 32K. | ||
733 | */ | ||
734 | |||
735 | /* DECLARE(Pos, head, 1<<HASH_BITS); */ | ||
736 | /* Heads of the hash chains or NIL. */ | ||
737 | |||
738 | static const ulg window_size = (ulg) 2 * WSIZE; | ||
739 | |||
740 | /* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the | ||
741 | * input file length plus MIN_LOOKAHEAD. | ||
742 | */ | ||
743 | |||
744 | static long block_start; | ||
745 | |||
746 | /* window position at the beginning of the current output block. Gets | ||
747 | * negative when the window is moved backwards. | ||
748 | */ | ||
749 | |||
750 | static unsigned ins_h; /* hash index of string to be inserted */ | ||
751 | |||
752 | #define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH) | ||
753 | /* Number of bits by which ins_h and del_h must be shifted at each | ||
754 | * input step. It must be such that after MIN_MATCH steps, the oldest | ||
755 | * byte no longer takes part in the hash key, that is: | ||
756 | * H_SHIFT * MIN_MATCH >= HASH_BITS | ||
757 | */ | ||
758 | |||
759 | static unsigned int prev_length; | ||
760 | |||
761 | /* Length of the best match at previous step. Matches not greater than this | ||
762 | * are discarded. This is used in the lazy match evaluation. | ||
763 | */ | ||
764 | |||
765 | static unsigned strstart; /* start of string to insert */ | ||
766 | static unsigned match_start; /* start of matching string */ | ||
767 | static int eofile; /* flag set at end of input file */ | ||
768 | static unsigned lookahead; /* number of valid bytes ahead in window */ | ||
769 | |||
770 | static const unsigned max_chain_length = 4096; | ||
771 | |||
772 | /* To speed up deflation, hash chains are never searched beyond this length. | ||
773 | * A higher limit improves compression ratio but degrades the speed. | ||
774 | */ | ||
775 | |||
776 | static const unsigned int max_lazy_match = 258; | ||
777 | |||
778 | /* Attempt to find a better match only when the current match is strictly | ||
779 | * smaller than this value. This mechanism is used only for compression | ||
780 | * levels >= 4. | ||
781 | */ | ||
782 | #define max_insert_length max_lazy_match | ||
783 | /* Insert new strings in the hash table only if the match length | ||
784 | * is not greater than this length. This saves time but degrades compression. | ||
785 | * max_insert_length is used only for compression levels <= 3. | ||
786 | */ | ||
787 | |||
788 | static const unsigned good_match = 32; | ||
789 | |||
790 | /* Use a faster search when the previous match is longer than this */ | ||
791 | |||
792 | |||
793 | /* Values for max_lazy_match, good_match and max_chain_length, depending on | ||
794 | * the desired pack level (0..9). The values given below have been tuned to | ||
795 | * exclude worst case performance for pathological files. Better values may be | ||
796 | * found for specific files. | ||
797 | */ | ||
798 | |||
799 | static const int nice_match = 258; /* Stop searching when current match exceeds this */ | ||
800 | |||
801 | /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 | ||
802 | * For deflate_fast() (levels <= 3) good is ignored and lazy has a different | ||
803 | * meaning. | ||
804 | */ | ||
805 | |||
806 | #define EQUAL 0 | ||
807 | /* result of memcmp for equal strings */ | ||
808 | |||
809 | /* =========================================================================== | ||
810 | * Prototypes for local functions. | ||
811 | */ | ||
812 | static void fill_window(void); | ||
813 | |||
814 | static int longest_match(IPos cur_match); | ||
815 | |||
816 | #ifdef DEBUG | ||
817 | static void check_match(IPos start, IPos match, int length); | ||
818 | #endif | ||
819 | |||
820 | /* =========================================================================== | ||
821 | * Update a hash value with the given input byte | ||
822 | * IN assertion: all calls to to UPDATE_HASH are made with consecutive | ||
823 | * input characters, so that a running hash key can be computed from the | ||
824 | * previous key instead of complete recalculation each time. | ||
825 | */ | ||
826 | #define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK) | ||
827 | |||
828 | /* =========================================================================== | ||
829 | * Insert string s in the dictionary and set match_head to the previous head | ||
830 | * of the hash chain (the most recent string with same hash key). Return | ||
831 | * the previous length of the hash chain. | ||
832 | * IN assertion: all calls to to INSERT_STRING are made with consecutive | ||
833 | * input characters and the first MIN_MATCH bytes of s are valid | ||
834 | * (except for the last MIN_MATCH-1 bytes of the input file). | ||
835 | */ | ||
836 | #define INSERT_STRING(s, match_head) \ | ||
837 | (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \ | ||
838 | prev[(s) & WMASK] = match_head = head[ins_h], \ | ||
839 | head[ins_h] = (s)) | ||
840 | |||
841 | /* =========================================================================== | ||
842 | * Initialize the "longest match" routines for a new file | ||
843 | */ | ||
844 | static void lm_init(ush * flags) | ||
845 | { | ||
846 | register unsigned j; | ||
847 | |||
848 | /* Initialize the hash table. */ | ||
849 | memzero((char *) head, HASH_SIZE * sizeof(*head)); | ||
850 | /* prev will be initialized on the fly */ | ||
851 | |||
852 | *flags |= SLOW; | ||
853 | /* ??? reduce max_chain_length for binary files */ | ||
854 | |||
855 | strstart = 0; | ||
856 | block_start = 0L; | ||
857 | |||
858 | lookahead = read_buf((char *) window, | ||
859 | sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE); | ||
860 | |||
861 | if (lookahead == 0 || lookahead == (unsigned) EOF) { | ||
862 | eofile = 1, lookahead = 0; | ||
863 | return; | ||
864 | } | ||
865 | eofile = 0; | ||
866 | /* Make sure that we always have enough lookahead. This is important | ||
867 | * if input comes from a device such as a tty. | ||
868 | */ | ||
869 | while (lookahead < MIN_LOOKAHEAD && !eofile) | ||
870 | fill_window(); | ||
871 | |||
872 | ins_h = 0; | ||
873 | for (j = 0; j < MIN_MATCH - 1; j++) | ||
874 | UPDATE_HASH(ins_h, window[j]); | ||
875 | /* If lookahead < MIN_MATCH, ins_h is garbage, but this is | ||
876 | * not important since only literal bytes will be emitted. | ||
877 | */ | ||
878 | } | ||
879 | |||
880 | /* =========================================================================== | ||
881 | * Set match_start to the longest match starting at the given string and | ||
882 | * return its length. Matches shorter or equal to prev_length are discarded, | ||
883 | * in which case the result is equal to prev_length and match_start is | ||
884 | * garbage. | ||
885 | * IN assertions: cur_match is the head of the hash chain for the current | ||
886 | * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 | ||
887 | */ | ||
888 | |||
889 | /* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or | ||
890 | * match.s. The code is functionally equivalent, so you can use the C version | ||
891 | * if desired. | ||
892 | */ | ||
893 | static int longest_match(IPos cur_match) | ||
894 | { | ||
895 | unsigned chain_length = max_chain_length; /* max hash chain length */ | ||
896 | register uch *scan = window + strstart; /* current string */ | ||
897 | register uch *match; /* matched string */ | ||
898 | register int len; /* length of current match */ | ||
899 | int best_len = prev_length; /* best match length so far */ | ||
900 | IPos limit = | ||
901 | strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL; | ||
902 | /* Stop when cur_match becomes <= limit. To simplify the code, | ||
903 | * we prevent matches with the string of window index 0. | ||
904 | */ | ||
905 | |||
906 | /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. | ||
907 | * It is easy to get rid of this optimization if necessary. | ||
908 | */ | ||
909 | #if HASH_BITS < 8 || MAX_MATCH != 258 | ||
910 | # error Code too clever | ||
911 | #endif | ||
912 | register uch *strend = window + strstart + MAX_MATCH; | ||
913 | register uch scan_end1 = scan[best_len - 1]; | ||
914 | register uch scan_end = scan[best_len]; | ||
915 | |||
916 | /* Do not waste too much time if we already have a good match: */ | ||
917 | if (prev_length >= good_match) { | ||
918 | chain_length >>= 2; | ||
919 | } | ||
920 | Assert(strstart <= window_size - MIN_LOOKAHEAD, "insufficient lookahead"); | ||
921 | |||
922 | do { | ||
923 | Assert(cur_match < strstart, "no future"); | ||
924 | match = window + cur_match; | ||
925 | |||
926 | /* Skip to next match if the match length cannot increase | ||
927 | * or if the match length is less than 2: | ||
928 | */ | ||
929 | if (match[best_len] != scan_end || | ||
930 | match[best_len - 1] != scan_end1 || | ||
931 | *match != *scan || *++match != scan[1]) | ||
932 | continue; | ||
933 | |||
934 | /* The check at best_len-1 can be removed because it will be made | ||
935 | * again later. (This heuristic is not always a win.) | ||
936 | * It is not necessary to compare scan[2] and match[2] since they | ||
937 | * are always equal when the other bytes match, given that | ||
938 | * the hash keys are equal and that HASH_BITS >= 8. | ||
939 | */ | ||
940 | scan += 2, match++; | ||
941 | |||
942 | /* We check for insufficient lookahead only every 8th comparison; | ||
943 | * the 256th check will be made at strstart+258. | ||
944 | */ | ||
945 | do { | ||
946 | } while (*++scan == *++match && *++scan == *++match && | ||
947 | *++scan == *++match && *++scan == *++match && | ||
948 | *++scan == *++match && *++scan == *++match && | ||
949 | *++scan == *++match && *++scan == *++match && scan < strend); | ||
950 | |||
951 | len = MAX_MATCH - (int) (strend - scan); | ||
952 | scan = strend - MAX_MATCH; | ||
953 | |||
954 | if (len > best_len) { | ||
955 | match_start = cur_match; | ||
956 | best_len = len; | ||
957 | if (len >= nice_match) | ||
958 | break; | ||
959 | scan_end1 = scan[best_len - 1]; | ||
960 | scan_end = scan[best_len]; | ||
961 | } | ||
962 | } while ((cur_match = prev[cur_match & WMASK]) > limit | ||
963 | && --chain_length != 0); | ||
964 | |||
965 | return best_len; | ||
966 | } | ||
967 | |||
968 | #ifdef DEBUG | ||
969 | /* =========================================================================== | ||
970 | * Check that the match at match_start is indeed a match. | ||
971 | */ | ||
972 | static void check_match(IPos start, IPos match, int length) | ||
973 | { | ||
974 | /* check that the match is indeed a match */ | ||
975 | if (memcmp((char *) window + match, | ||
976 | (char *) window + start, length) != EQUAL) { | ||
977 | bb_error_msg(" start %d, match %d, length %d", start, match, length); | ||
978 | bb_error_msg("invalid match"); | ||
979 | } | ||
980 | if (verbose > 1) { | ||
981 | bb_error_msg("\\[%d,%d]", start - match, length); | ||
982 | do { | ||
983 | putc(window[start++], stderr); | ||
984 | } while (--length != 0); | ||
985 | } | ||
986 | } | ||
987 | #else | ||
988 | # define check_match(start, match, length) | ||
989 | #endif | ||
990 | |||
991 | /* =========================================================================== | ||
992 | * Fill the window when the lookahead becomes insufficient. | ||
993 | * Updates strstart and lookahead, and sets eofile if end of input file. | ||
994 | * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 | ||
995 | * OUT assertions: at least one byte has been read, or eofile is set; | ||
996 | * file reads are performed for at least two bytes (required for the | ||
997 | * translate_eol option). | ||
998 | */ | ||
999 | static void fill_window() | ||
1000 | { | ||
1001 | register unsigned n, m; | ||
1002 | unsigned more = | ||
1003 | (unsigned) (window_size - (ulg) lookahead - (ulg) strstart); | ||
1004 | /* Amount of free space at the end of the window. */ | ||
1005 | |||
1006 | /* If the window is almost full and there is insufficient lookahead, | ||
1007 | * move the upper half to the lower one to make room in the upper half. | ||
1008 | */ | ||
1009 | if (more == (unsigned) EOF) { | ||
1010 | /* Very unlikely, but possible on 16 bit machine if strstart == 0 | ||
1011 | * and lookahead == 1 (input done one byte at time) | ||
1012 | */ | ||
1013 | more--; | ||
1014 | } else if (strstart >= WSIZE + MAX_DIST) { | ||
1015 | /* By the IN assertion, the window is not empty so we can't confuse | ||
1016 | * more == 0 with more == 64K on a 16 bit machine. | ||
1017 | */ | ||
1018 | Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM"); | ||
1019 | |||
1020 | memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE); | ||
1021 | match_start -= WSIZE; | ||
1022 | strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ | ||
1023 | |||
1024 | block_start -= (long) WSIZE; | ||
1025 | |||
1026 | for (n = 0; n < HASH_SIZE; n++) { | ||
1027 | m = head[n]; | ||
1028 | head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); | ||
1029 | } | ||
1030 | for (n = 0; n < WSIZE; n++) { | ||
1031 | m = prev[n]; | ||
1032 | prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); | ||
1033 | /* If n is not on any hash chain, prev[n] is garbage but | ||
1034 | * its value will never be used. | ||
1035 | */ | ||
1036 | } | ||
1037 | more += WSIZE; | ||
1038 | } | ||
1039 | /* At this point, more >= 2 */ | ||
1040 | if (!eofile) { | ||
1041 | n = read_buf((char *) window + strstart + lookahead, more); | ||
1042 | if (n == 0 || n == (unsigned) EOF) { | ||
1043 | eofile = 1; | ||
1044 | } else { | ||
1045 | lookahead += n; | ||
1046 | } | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | /* =========================================================================== | ||
1051 | * Flush the current block, with given end-of-file flag. | ||
1052 | * IN assertion: strstart is set to the end of the current match. | ||
1053 | */ | ||
1054 | #define FLUSH_BLOCK(eof) \ | ||
1055 | flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \ | ||
1056 | (char*)NULL, (long)strstart - block_start, (eof)) | ||
1057 | |||
1058 | /* =========================================================================== | ||
1059 | * Same as above, but achieves better compression. We use a lazy | ||
1060 | * evaluation for matches: a match is finally adopted only if there is | ||
1061 | * no better match at the next window position. | ||
1062 | */ | ||
1063 | static ulg deflate() | ||
1064 | { | ||
1065 | IPos hash_head; /* head of hash chain */ | ||
1066 | IPos prev_match; /* previous match */ | ||
1067 | int flush; /* set if current block must be flushed */ | ||
1068 | int match_available = 0; /* set if previous match exists */ | ||
1069 | register unsigned match_length = MIN_MATCH - 1; /* length of best match */ | ||
1070 | |||
1071 | /* Process the input block. */ | ||
1072 | while (lookahead != 0) { | ||
1073 | /* Insert the string window[strstart .. strstart+2] in the | ||
1074 | * dictionary, and set hash_head to the head of the hash chain: | ||
1075 | */ | ||
1076 | INSERT_STRING(strstart, hash_head); | ||
1077 | |||
1078 | /* Find the longest match, discarding those <= prev_length. | ||
1079 | */ | ||
1080 | prev_length = match_length, prev_match = match_start; | ||
1081 | match_length = MIN_MATCH - 1; | ||
1082 | |||
1083 | if (hash_head != NIL && prev_length < max_lazy_match && | ||
1084 | strstart - hash_head <= MAX_DIST) { | ||
1085 | /* To simplify the code, we prevent matches with the string | ||
1086 | * of window index 0 (in particular we have to avoid a match | ||
1087 | * of the string with itself at the start of the input file). | ||
1088 | */ | ||
1089 | match_length = longest_match(hash_head); | ||
1090 | /* longest_match() sets match_start */ | ||
1091 | if (match_length > lookahead) | ||
1092 | match_length = lookahead; | ||
1093 | |||
1094 | /* Ignore a length 3 match if it is too distant: */ | ||
1095 | if (match_length == MIN_MATCH && strstart - match_start > TOO_FAR) { | ||
1096 | /* If prev_match is also MIN_MATCH, match_start is garbage | ||
1097 | * but we will ignore the current match anyway. | ||
1098 | */ | ||
1099 | match_length--; | ||
1100 | } | ||
1101 | } | ||
1102 | /* If there was a match at the previous step and the current | ||
1103 | * match is not better, output the previous match: | ||
1104 | */ | ||
1105 | if (prev_length >= MIN_MATCH && match_length <= prev_length) { | ||
1106 | |||
1107 | check_match(strstart - 1, prev_match, prev_length); | ||
1108 | |||
1109 | flush = | ||
1110 | ct_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); | ||
1111 | |||
1112 | /* Insert in hash table all strings up to the end of the match. | ||
1113 | * strstart-1 and strstart are already inserted. | ||
1114 | */ | ||
1115 | lookahead -= prev_length - 1; | ||
1116 | prev_length -= 2; | ||
1117 | do { | ||
1118 | strstart++; | ||
1119 | INSERT_STRING(strstart, hash_head); | ||
1120 | /* strstart never exceeds WSIZE-MAX_MATCH, so there are | ||
1121 | * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH | ||
1122 | * these bytes are garbage, but it does not matter since the | ||
1123 | * next lookahead bytes will always be emitted as literals. | ||
1124 | */ | ||
1125 | } while (--prev_length != 0); | ||
1126 | match_available = 0; | ||
1127 | match_length = MIN_MATCH - 1; | ||
1128 | strstart++; | ||
1129 | if (flush) | ||
1130 | FLUSH_BLOCK(0), block_start = strstart; | ||
1131 | |||
1132 | } else if (match_available) { | ||
1133 | /* If there was no match at the previous position, output a | ||
1134 | * single literal. If there was a match but the current match | ||
1135 | * is longer, truncate the previous match to a single literal. | ||
1136 | */ | ||
1137 | Tracevv((stderr, "%c", window[strstart - 1])); | ||
1138 | if (ct_tally(0, window[strstart - 1])) { | ||
1139 | FLUSH_BLOCK(0), block_start = strstart; | ||
1140 | } | ||
1141 | strstart++; | ||
1142 | lookahead--; | ||
1143 | } else { | ||
1144 | /* There is no previous match to compare with, wait for | ||
1145 | * the next step to decide. | ||
1146 | */ | ||
1147 | match_available = 1; | ||
1148 | strstart++; | ||
1149 | lookahead--; | ||
1150 | } | ||
1151 | Assert(strstart <= isize && lookahead <= isize, "a bit too far"); | ||
1152 | |||
1153 | /* Make sure that we always have enough lookahead, except | ||
1154 | * at the end of the input file. We need MAX_MATCH bytes | ||
1155 | * for the next match, plus MIN_MATCH bytes to insert the | ||
1156 | * string following the next match. | ||
1157 | */ | ||
1158 | while (lookahead < MIN_LOOKAHEAD && !eofile) | ||
1159 | fill_window(); | ||
1160 | } | ||
1161 | if (match_available) | ||
1162 | ct_tally(0, window[strstart - 1]); | ||
1163 | |||
1164 | return FLUSH_BLOCK(1); /* eof */ | ||
1165 | } | ||
1166 | |||
1167 | /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface | ||
1168 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
1169 | * The unzip code was written and put in the public domain by Mark Adler. | ||
1170 | * Portions of the lzw code are derived from the public domain 'compress' | ||
1171 | * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, | ||
1172 | * Ken Turkowski, Dave Mack and Peter Jannesen. | ||
1173 | * | ||
1174 | * See the license_msg below and the file COPYING for the software license. | ||
1175 | * See the file algorithm.doc for the compression algorithms and file formats. | ||
1176 | */ | ||
1177 | |||
1178 | /* Compress files with zip algorithm and 'compress' interface. | ||
1179 | * See usage() and help() functions below for all options. | ||
1180 | * Outputs: | ||
1181 | * file.gz: compressed file with same mode, owner, and utimes | ||
1182 | * or stdout with -c option or if stdin used as input. | ||
1183 | * If the output file name had to be truncated, the original name is kept | ||
1184 | * in the compressed file. | ||
1185 | */ | ||
1186 | |||
1187 | /* configuration */ | ||
1188 | |||
1189 | typedef struct dirent dir_type; | ||
1190 | |||
1191 | typedef RETSIGTYPE(*sig_type) (int); | ||
1192 | |||
1193 | /* ======================================================================== */ | ||
1194 | int gzip_main(int argc, char **argv) | ||
1195 | { | ||
1196 | int result; | ||
1197 | int inFileNum; | ||
1198 | int outFileNum; | ||
1199 | struct stat statBuf; | ||
1200 | char *delFileName; | ||
1201 | int tostdout = 0; | ||
1202 | int force = 0; | ||
1203 | int opt; | ||
1204 | |||
1205 | while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) { | ||
1206 | switch (opt) { | ||
1207 | case 'c': | ||
1208 | tostdout = 1; | ||
1209 | break; | ||
1210 | case 'f': | ||
1211 | force = 1; | ||
1212 | break; | ||
1213 | /* Ignore 1-9 (compression level) options */ | ||
1214 | case '1': | ||
1215 | case '2': | ||
1216 | case '3': | ||
1217 | case '4': | ||
1218 | case '5': | ||
1219 | case '6': | ||
1220 | case '7': | ||
1221 | case '8': | ||
1222 | case '9': | ||
1223 | break; | ||
1224 | case 'q': | ||
1225 | break; | ||
1226 | #ifdef CONFIG_GUNZIP | ||
1227 | case 'd': | ||
1228 | optind = 1; | ||
1229 | return gunzip_main(argc, argv); | ||
1230 | #endif | ||
1231 | default: | ||
1232 | bb_show_usage(); | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1236 | foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; | ||
1237 | if (foreground) { | ||
1238 | (void) signal(SIGINT, (sig_type) abort_gzip); | ||
1239 | } | ||
1240 | #ifdef SIGTERM | ||
1241 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { | ||
1242 | (void) signal(SIGTERM, (sig_type) abort_gzip); | ||
1243 | } | ||
1244 | #endif | ||
1245 | #ifdef SIGHUP | ||
1246 | if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { | ||
1247 | (void) signal(SIGHUP, (sig_type) abort_gzip); | ||
1248 | } | ||
1249 | #endif | ||
1250 | |||
1251 | strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1); | ||
1252 | z_len = strlen(z_suffix); | ||
1253 | |||
1254 | /* Allocate all global buffers (for DYN_ALLOC option) */ | ||
1255 | ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA); | ||
1256 | ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); | ||
1257 | ALLOC(ush, d_buf, DIST_BUFSIZE); | ||
1258 | ALLOC(uch, window, 2L * WSIZE); | ||
1259 | ALLOC(ush, tab_prefix, 1L << BITS); | ||
1260 | |||
1261 | clear_bufs(); | ||
1262 | part_nb = 0; | ||
1263 | |||
1264 | if (optind == argc) { | ||
1265 | time_stamp = 0; | ||
1266 | ifile_size = -1L; | ||
1267 | zip(STDIN_FILENO, STDOUT_FILENO); | ||
1268 | } else { | ||
1269 | int i; | ||
1270 | |||
1271 | for (i = optind; i < argc; i++) { | ||
1272 | char *path = NULL; | ||
1273 | |||
1274 | if (strcmp(argv[i], "-") == 0) { | ||
1275 | time_stamp = 0; | ||
1276 | ifile_size = -1L; | ||
1277 | inFileNum = STDIN_FILENO; | ||
1278 | outFileNum = STDOUT_FILENO; | ||
1279 | } else { | ||
1280 | inFileNum = open(argv[i], O_RDONLY); | ||
1281 | if (inFileNum < 0 || fstat(inFileNum, &statBuf) < 0) | ||
1282 | bb_perror_msg_and_die("%s", argv[i]); | ||
1283 | time_stamp = statBuf.st_ctime; | ||
1284 | ifile_size = statBuf.st_size; | ||
1285 | |||
1286 | if (!tostdout) { | ||
1287 | path = xmalloc(strlen(argv[i]) + 4); | ||
1288 | strcpy(path, argv[i]); | ||
1289 | strcat(path, ".gz"); | ||
1290 | |||
1291 | /* Open output file */ | ||
1292 | #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) | ||
1293 | outFileNum = | ||
1294 | open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); | ||
1295 | #else | ||
1296 | outFileNum = open(path, O_RDWR | O_CREAT | O_EXCL); | ||
1297 | #endif | ||
1298 | if (outFileNum < 0) { | ||
1299 | bb_perror_msg("%s", path); | ||
1300 | free(path); | ||
1301 | continue; | ||
1302 | } | ||
1303 | |||
1304 | /* Set permissions on the file */ | ||
1305 | fchmod(outFileNum, statBuf.st_mode); | ||
1306 | } else | ||
1307 | outFileNum = STDOUT_FILENO; | ||
1308 | } | ||
1309 | |||
1310 | if (path == NULL && isatty(outFileNum) && force == 0) { | ||
1311 | bb_error_msg | ||
1312 | ("compressed data not written to a terminal. Use -f to force compression."); | ||
1313 | free(path); | ||
1314 | continue; | ||
1315 | } | ||
1316 | |||
1317 | result = zip(inFileNum, outFileNum); | ||
1318 | |||
1319 | if (path != NULL) { | ||
1320 | close(inFileNum); | ||
1321 | close(outFileNum); | ||
1322 | |||
1323 | /* Delete the original file */ | ||
1324 | if (result == OK) | ||
1325 | delFileName = argv[i]; | ||
1326 | else | ||
1327 | delFileName = path; | ||
1328 | |||
1329 | if (unlink(delFileName) < 0) | ||
1330 | bb_perror_msg("%s", delFileName); | ||
1331 | } | ||
1332 | |||
1333 | free(path); | ||
1334 | } | ||
1335 | } | ||
1336 | |||
1337 | return (exit_code); | ||
1338 | } | ||
1339 | |||
1340 | /* trees.c -- output deflated data using Huffman coding | ||
1341 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
1342 | * This is free software; you can redistribute it and/or modify it under the | ||
1343 | * terms of the GNU General Public License, see the file COPYING. | ||
1344 | */ | ||
1345 | |||
1346 | /* | ||
1347 | * PURPOSE | ||
1348 | * | ||
1349 | * Encode various sets of source values using variable-length | ||
1350 | * binary code trees. | ||
1351 | * | ||
1352 | * DISCUSSION | ||
1353 | * | ||
1354 | * The PKZIP "deflation" process uses several Huffman trees. The more | ||
1355 | * common source values are represented by shorter bit sequences. | ||
1356 | * | ||
1357 | * Each code tree is stored in the ZIP file in a compressed form | ||
1358 | * which is itself a Huffman encoding of the lengths of | ||
1359 | * all the code strings (in ascending order by source values). | ||
1360 | * The actual code strings are reconstructed from the lengths in | ||
1361 | * the UNZIP process, as described in the "application note" | ||
1362 | * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program. | ||
1363 | * | ||
1364 | * REFERENCES | ||
1365 | * | ||
1366 | * Lynch, Thomas J. | ||
1367 | * Data Compression: Techniques and Applications, pp. 53-55. | ||
1368 | * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7. | ||
1369 | * | ||
1370 | * Storer, James A. | ||
1371 | * Data Compression: Methods and Theory, pp. 49-50. | ||
1372 | * Computer Science Press, 1988. ISBN 0-7167-8156-5. | ||
1373 | * | ||
1374 | * Sedgewick, R. | ||
1375 | * Algorithms, p290. | ||
1376 | * Addison-Wesley, 1983. ISBN 0-201-06672-6. | ||
1377 | * | ||
1378 | * INTERFACE | ||
1379 | * | ||
1380 | * void ct_init (ush *attr, int *methodp) | ||
1381 | * Allocate the match buffer, initialize the various tables and save | ||
1382 | * the location of the internal file attribute (ascii/binary) and | ||
1383 | * method (DEFLATE/STORE) | ||
1384 | * | ||
1385 | * void ct_tally (int dist, int lc); | ||
1386 | * Save the match info and tally the frequency counts. | ||
1387 | * | ||
1388 | * long flush_block (char *buf, ulg stored_len, int eof) | ||
1389 | * Determine the best encoding for the current block: dynamic trees, | ||
1390 | * static trees or store, and output the encoded block to the zip | ||
1391 | * file. Returns the total compressed length for the file so far. | ||
1392 | * | ||
1393 | */ | ||
1394 | |||
1395 | /* =========================================================================== | ||
1396 | * Constants | ||
1397 | */ | ||
1398 | |||
1399 | #define MAX_BITS 15 | ||
1400 | /* All codes must not exceed MAX_BITS bits */ | ||
1401 | |||
1402 | #define MAX_BL_BITS 7 | ||
1403 | /* Bit length codes must not exceed MAX_BL_BITS bits */ | ||
1404 | |||
1405 | #define LENGTH_CODES 29 | ||
1406 | /* number of length codes, not counting the special END_BLOCK code */ | ||
1407 | |||
1408 | #define LITERALS 256 | ||
1409 | /* number of literal bytes 0..255 */ | ||
1410 | |||
1411 | #define END_BLOCK 256 | ||
1412 | /* end of block literal code */ | ||
1413 | |||
1414 | #define L_CODES (LITERALS+1+LENGTH_CODES) | ||
1415 | /* number of Literal or Length codes, including the END_BLOCK code */ | ||
1416 | |||
1417 | #define D_CODES 30 | ||
1418 | /* number of distance codes */ | ||
1419 | |||
1420 | #define BL_CODES 19 | ||
1421 | /* number of codes used to transfer the bit lengths */ | ||
1422 | |||
1423 | typedef uch extra_bits_t; | ||
1424 | |||
1425 | /* extra bits for each length code */ | ||
1426 | static const extra_bits_t extra_lbits[LENGTH_CODES] | ||
1427 | = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, | ||
1428 | 4, 4, 5, 5, 5, 5, 0 | ||
1429 | }; | ||
1430 | |||
1431 | /* extra bits for each distance code */ | ||
1432 | static const extra_bits_t extra_dbits[D_CODES] | ||
1433 | = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, | ||
1434 | 10, 10, 11, 11, 12, 12, 13, 13 | ||
1435 | }; | ||
1436 | |||
1437 | /* extra bits for each bit length code */ | ||
1438 | static const extra_bits_t extra_blbits[BL_CODES] | ||
1439 | = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; | ||
1440 | |||
1441 | #define STORED_BLOCK 0 | ||
1442 | #define STATIC_TREES 1 | ||
1443 | #define DYN_TREES 2 | ||
1444 | /* The three kinds of block type */ | ||
1445 | |||
1446 | #ifndef LIT_BUFSIZE | ||
1447 | # ifdef SMALL_MEM | ||
1448 | # define LIT_BUFSIZE 0x2000 | ||
1449 | # else | ||
1450 | # ifdef MEDIUM_MEM | ||
1451 | # define LIT_BUFSIZE 0x4000 | ||
1452 | # else | ||
1453 | # define LIT_BUFSIZE 0x8000 | ||
1454 | # endif | ||
1455 | # endif | ||
1456 | #endif | ||
1457 | #ifndef DIST_BUFSIZE | ||
1458 | # define DIST_BUFSIZE LIT_BUFSIZE | ||
1459 | #endif | ||
1460 | /* Sizes of match buffers for literals/lengths and distances. There are | ||
1461 | * 4 reasons for limiting LIT_BUFSIZE to 64K: | ||
1462 | * - frequencies can be kept in 16 bit counters | ||
1463 | * - if compression is not successful for the first block, all input data is | ||
1464 | * still in the window so we can still emit a stored block even when input | ||
1465 | * comes from standard input. (This can also be done for all blocks if | ||
1466 | * LIT_BUFSIZE is not greater than 32K.) | ||
1467 | * - if compression is not successful for a file smaller than 64K, we can | ||
1468 | * even emit a stored file instead of a stored block (saving 5 bytes). | ||
1469 | * - creating new Huffman trees less frequently may not provide fast | ||
1470 | * adaptation to changes in the input data statistics. (Take for | ||
1471 | * example a binary file with poorly compressible code followed by | ||
1472 | * a highly compressible string table.) Smaller buffer sizes give | ||
1473 | * fast adaptation but have of course the overhead of transmitting trees | ||
1474 | * more frequently. | ||
1475 | * - I can't count above 4 | ||
1476 | * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save | ||
1477 | * memory at the expense of compression). Some optimizations would be possible | ||
1478 | * if we rely on DIST_BUFSIZE == LIT_BUFSIZE. | ||
1479 | */ | ||
1480 | #if LIT_BUFSIZE > INBUFSIZ | ||
1481 | #error cannot overlay l_buf and inbuf | ||
1482 | #endif | ||
1483 | #define REP_3_6 16 | ||
1484 | /* repeat previous bit length 3-6 times (2 bits of repeat count) */ | ||
1485 | #define REPZ_3_10 17 | ||
1486 | /* repeat a zero length 3-10 times (3 bits of repeat count) */ | ||
1487 | #define REPZ_11_138 18 | ||
1488 | /* repeat a zero length 11-138 times (7 bits of repeat count) */ | ||
1489 | |||
1490 | /* =========================================================================== | ||
1491 | * Local data | ||
1492 | */ | ||
1493 | |||
1494 | /* Data structure describing a single value and its code string. */ | ||
1495 | typedef struct ct_data { | ||
1496 | union { | ||
1497 | ush freq; /* frequency count */ | ||
1498 | ush code; /* bit string */ | ||
1499 | } fc; | ||
1500 | union { | ||
1501 | ush dad; /* father node in Huffman tree */ | ||
1502 | ush len; /* length of bit string */ | ||
1503 | } dl; | ||
1504 | } ct_data; | ||
1505 | |||
1506 | #define Freq fc.freq | ||
1507 | #define Code fc.code | ||
1508 | #define Dad dl.dad | ||
1509 | #define Len dl.len | ||
1510 | |||
1511 | #define HEAP_SIZE (2*L_CODES+1) | ||
1512 | /* maximum heap size */ | ||
1513 | |||
1514 | static ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */ | ||
1515 | static ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */ | ||
1516 | |||
1517 | static ct_data static_ltree[L_CODES + 2]; | ||
1518 | |||
1519 | /* The static literal tree. Since the bit lengths are imposed, there is no | ||
1520 | * need for the L_CODES extra codes used during heap construction. However | ||
1521 | * The codes 286 and 287 are needed to build a canonical tree (see ct_init | ||
1522 | * below). | ||
1523 | */ | ||
1524 | |||
1525 | static ct_data static_dtree[D_CODES]; | ||
1526 | |||
1527 | /* The static distance tree. (Actually a trivial tree since all codes use | ||
1528 | * 5 bits.) | ||
1529 | */ | ||
1530 | |||
1531 | static ct_data bl_tree[2 * BL_CODES + 1]; | ||
1532 | |||
1533 | /* Huffman tree for the bit lengths */ | ||
1534 | |||
1535 | typedef struct tree_desc { | ||
1536 | ct_data *dyn_tree; /* the dynamic tree */ | ||
1537 | ct_data *static_tree; /* corresponding static tree or NULL */ | ||
1538 | const extra_bits_t *extra_bits; /* extra bits for each code or NULL */ | ||
1539 | int extra_base; /* base index for extra_bits */ | ||
1540 | int elems; /* max number of elements in the tree */ | ||
1541 | int max_length; /* max bit length for the codes */ | ||
1542 | int max_code; /* largest code with non zero frequency */ | ||
1543 | } tree_desc; | ||
1544 | |||
1545 | static tree_desc l_desc = | ||
1546 | { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, | ||
1547 | MAX_BITS, 0 | ||
1548 | }; | ||
1549 | |||
1550 | static tree_desc d_desc = | ||
1551 | { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 }; | ||
1552 | |||
1553 | static tree_desc bl_desc = | ||
1554 | { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, | ||
1555 | 0 | ||
1556 | }; | ||
1557 | |||
1558 | |||
1559 | static ush bl_count[MAX_BITS + 1]; | ||
1560 | |||
1561 | /* number of codes at each bit length for an optimal tree */ | ||
1562 | |||
1563 | static const uch bl_order[BL_CODES] | ||
1564 | = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; | ||
1565 | |||
1566 | /* The lengths of the bit length codes are sent in order of decreasing | ||
1567 | * probability, to avoid transmitting the lengths for unused bit length codes. | ||
1568 | */ | ||
1569 | |||
1570 | static int heap[2 * L_CODES + 1]; /* heap used to build the Huffman trees */ | ||
1571 | static int heap_len; /* number of elements in the heap */ | ||
1572 | static int heap_max; /* element of largest frequency */ | ||
1573 | |||
1574 | /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. | ||
1575 | * The same heap array is used to build all trees. | ||
1576 | */ | ||
1577 | |||
1578 | static uch depth[2 * L_CODES + 1]; | ||
1579 | |||
1580 | /* Depth of each subtree used as tie breaker for trees of equal frequency */ | ||
1581 | |||
1582 | static uch length_code[MAX_MATCH - MIN_MATCH + 1]; | ||
1583 | |||
1584 | /* length code for each normalized match length (0 == MIN_MATCH) */ | ||
1585 | |||
1586 | static uch dist_code[512]; | ||
1587 | |||
1588 | /* distance codes. The first 256 values correspond to the distances | ||
1589 | * 3 .. 258, the last 256 values correspond to the top 8 bits of | ||
1590 | * the 15 bit distances. | ||
1591 | */ | ||
1592 | |||
1593 | static int base_length[LENGTH_CODES]; | ||
1594 | |||
1595 | /* First normalized length for each code (0 = MIN_MATCH) */ | ||
1596 | |||
1597 | static int base_dist[D_CODES]; | ||
1598 | |||
1599 | /* First normalized distance for each code (0 = distance of 1) */ | ||
1600 | |||
1601 | #define l_buf inbuf | ||
1602 | /* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */ | ||
1603 | |||
1604 | /* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */ | ||
1605 | |||
1606 | static uch flag_buf[(LIT_BUFSIZE / 8)]; | ||
1607 | |||
1608 | /* flag_buf is a bit array distinguishing literals from lengths in | ||
1609 | * l_buf, thus indicating the presence or absence of a distance. | ||
1610 | */ | ||
1611 | |||
1612 | static unsigned last_lit; /* running index in l_buf */ | ||
1613 | static unsigned last_dist; /* running index in d_buf */ | ||
1614 | static unsigned last_flags; /* running index in flag_buf */ | ||
1615 | static uch flags; /* current flags not yet saved in flag_buf */ | ||
1616 | static uch flag_bit; /* current bit used in flags */ | ||
1617 | |||
1618 | /* bits are filled in flags starting at bit 0 (least significant). | ||
1619 | * Note: these flags are overkill in the current code since we don't | ||
1620 | * take advantage of DIST_BUFSIZE == LIT_BUFSIZE. | ||
1621 | */ | ||
1622 | |||
1623 | static ulg opt_len; /* bit length of current block with optimal trees */ | ||
1624 | static ulg static_len; /* bit length of current block with static trees */ | ||
1625 | |||
1626 | static ulg compressed_len; /* total bit length of compressed file */ | ||
1627 | |||
1628 | |||
1629 | static ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */ | ||
1630 | static int *file_method; /* pointer to DEFLATE or STORE */ | ||
1631 | |||
1632 | /* =========================================================================== | ||
1633 | * Local (static) routines in this file. | ||
1634 | */ | ||
1635 | |||
1636 | static void init_block(void); | ||
1637 | static void pqdownheap(ct_data * tree, int k); | ||
1638 | static void gen_bitlen(tree_desc * desc); | ||
1639 | static void gen_codes(ct_data * tree, int max_code); | ||
1640 | static void build_tree(tree_desc * desc); | ||
1641 | static void scan_tree(ct_data * tree, int max_code); | ||
1642 | static void send_tree(ct_data * tree, int max_code); | ||
1643 | static int build_bl_tree(void); | ||
1644 | static void send_all_trees(int lcodes, int dcodes, int blcodes); | ||
1645 | static void compress_block(ct_data * ltree, ct_data * dtree); | ||
1646 | static void set_file_type(void); | ||
1647 | |||
1648 | |||
1649 | #ifndef DEBUG | ||
1650 | # define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len) | ||
1651 | /* Send a code of the given tree. c and tree must not have side effects */ | ||
1652 | |||
1653 | #else /* DEBUG */ | ||
1654 | # define send_code(c, tree) \ | ||
1655 | { if (verbose>1) bb_error_msg("\ncd %3d ",(c)); \ | ||
1656 | send_bits(tree[c].Code, tree[c].Len); } | ||
1657 | #endif | ||
1658 | |||
1659 | #define d_code(dist) \ | ||
1660 | ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) | ||
1661 | /* Mapping from a distance to a distance code. dist is the distance - 1 and | ||
1662 | * must not have side effects. dist_code[256] and dist_code[257] are never | ||
1663 | * used. | ||
1664 | */ | ||
1665 | |||
1666 | /* the arguments must not have side effects */ | ||
1667 | |||
1668 | /* =========================================================================== | ||
1669 | * Allocate the match buffer, initialize the various tables and save the | ||
1670 | * location of the internal file attribute (ascii/binary) and method | ||
1671 | * (DEFLATE/STORE). | ||
1672 | */ | ||
1673 | static void ct_init(ush * attr, int *methodp) | ||
1674 | { | ||
1675 | int n; /* iterates over tree elements */ | ||
1676 | int bits; /* bit counter */ | ||
1677 | int length; /* length value */ | ||
1678 | int code; /* code value */ | ||
1679 | int dist; /* distance index */ | ||
1680 | |||
1681 | file_type = attr; | ||
1682 | file_method = methodp; | ||
1683 | compressed_len = 0L; | ||
1684 | |||
1685 | if (static_dtree[0].Len != 0) | ||
1686 | return; /* ct_init already called */ | ||
1687 | |||
1688 | /* Initialize the mapping length (0..255) -> length code (0..28) */ | ||
1689 | length = 0; | ||
1690 | for (code = 0; code < LENGTH_CODES - 1; code++) { | ||
1691 | base_length[code] = length; | ||
1692 | for (n = 0; n < (1 << extra_lbits[code]); n++) { | ||
1693 | length_code[length++] = (uch) code; | ||
1694 | } | ||
1695 | } | ||
1696 | Assert(length == 256, "ct_init: length != 256"); | ||
1697 | /* Note that the length 255 (match length 258) can be represented | ||
1698 | * in two different ways: code 284 + 5 bits or code 285, so we | ||
1699 | * overwrite length_code[255] to use the best encoding: | ||
1700 | */ | ||
1701 | length_code[length - 1] = (uch) code; | ||
1702 | |||
1703 | /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ | ||
1704 | dist = 0; | ||
1705 | for (code = 0; code < 16; code++) { | ||
1706 | base_dist[code] = dist; | ||
1707 | for (n = 0; n < (1 << extra_dbits[code]); n++) { | ||
1708 | dist_code[dist++] = (uch) code; | ||
1709 | } | ||
1710 | } | ||
1711 | Assert(dist == 256, "ct_init: dist != 256"); | ||
1712 | dist >>= 7; /* from now on, all distances are divided by 128 */ | ||
1713 | for (; code < D_CODES; code++) { | ||
1714 | base_dist[code] = dist << 7; | ||
1715 | for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { | ||
1716 | dist_code[256 + dist++] = (uch) code; | ||
1717 | } | ||
1718 | } | ||
1719 | Assert(dist == 256, "ct_init: 256+dist != 512"); | ||
1720 | |||
1721 | /* Construct the codes of the static literal tree */ | ||
1722 | for (bits = 0; bits <= MAX_BITS; bits++) | ||
1723 | bl_count[bits] = 0; | ||
1724 | n = 0; | ||
1725 | while (n <= 143) | ||
1726 | static_ltree[n++].Len = 8, bl_count[8]++; | ||
1727 | while (n <= 255) | ||
1728 | static_ltree[n++].Len = 9, bl_count[9]++; | ||
1729 | while (n <= 279) | ||
1730 | static_ltree[n++].Len = 7, bl_count[7]++; | ||
1731 | while (n <= 287) | ||
1732 | static_ltree[n++].Len = 8, bl_count[8]++; | ||
1733 | /* Codes 286 and 287 do not exist, but we must include them in the | ||
1734 | * tree construction to get a canonical Huffman tree (longest code | ||
1735 | * all ones) | ||
1736 | */ | ||
1737 | gen_codes((ct_data *) static_ltree, L_CODES + 1); | ||
1738 | |||
1739 | /* The static distance tree is trivial: */ | ||
1740 | for (n = 0; n < D_CODES; n++) { | ||
1741 | static_dtree[n].Len = 5; | ||
1742 | static_dtree[n].Code = bi_reverse(n, 5); | ||
1743 | } | ||
1744 | |||
1745 | /* Initialize the first block of the first file: */ | ||
1746 | init_block(); | ||
1747 | } | ||
1748 | |||
1749 | /* =========================================================================== | ||
1750 | * Initialize a new block. | ||
1751 | */ | ||
1752 | static void init_block() | ||
1753 | { | ||
1754 | int n; /* iterates over tree elements */ | ||
1755 | |||
1756 | /* Initialize the trees. */ | ||
1757 | for (n = 0; n < L_CODES; n++) | ||
1758 | dyn_ltree[n].Freq = 0; | ||
1759 | for (n = 0; n < D_CODES; n++) | ||
1760 | dyn_dtree[n].Freq = 0; | ||
1761 | for (n = 0; n < BL_CODES; n++) | ||
1762 | bl_tree[n].Freq = 0; | ||
1763 | |||
1764 | dyn_ltree[END_BLOCK].Freq = 1; | ||
1765 | opt_len = static_len = 0L; | ||
1766 | last_lit = last_dist = last_flags = 0; | ||
1767 | flags = 0; | ||
1768 | flag_bit = 1; | ||
1769 | } | ||
1770 | |||
1771 | #define SMALLEST 1 | ||
1772 | /* Index within the heap array of least frequent node in the Huffman tree */ | ||
1773 | |||
1774 | |||
1775 | /* =========================================================================== | ||
1776 | * Remove the smallest element from the heap and recreate the heap with | ||
1777 | * one less element. Updates heap and heap_len. | ||
1778 | */ | ||
1779 | #define pqremove(tree, top) \ | ||
1780 | {\ | ||
1781 | top = heap[SMALLEST]; \ | ||
1782 | heap[SMALLEST] = heap[heap_len--]; \ | ||
1783 | pqdownheap(tree, SMALLEST); \ | ||
1784 | } | ||
1785 | |||
1786 | /* =========================================================================== | ||
1787 | * Compares to subtrees, using the tree depth as tie breaker when | ||
1788 | * the subtrees have equal frequency. This minimizes the worst case length. | ||
1789 | */ | ||
1790 | #define smaller(tree, n, m) \ | ||
1791 | (tree[n].Freq < tree[m].Freq || \ | ||
1792 | (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) | ||
1793 | |||
1794 | /* =========================================================================== | ||
1795 | * Restore the heap property by moving down the tree starting at node k, | ||
1796 | * exchanging a node with the smallest of its two sons if necessary, stopping | ||
1797 | * when the heap property is re-established (each father smaller than its | ||
1798 | * two sons). | ||
1799 | */ | ||
1800 | static void pqdownheap(ct_data * tree, int k) | ||
1801 | { | ||
1802 | int v = heap[k]; | ||
1803 | int j = k << 1; /* left son of k */ | ||
1804 | |||
1805 | while (j <= heap_len) { | ||
1806 | /* Set j to the smallest of the two sons: */ | ||
1807 | if (j < heap_len && smaller(tree, heap[j + 1], heap[j])) | ||
1808 | j++; | ||
1809 | |||
1810 | /* Exit if v is smaller than both sons */ | ||
1811 | if (smaller(tree, v, heap[j])) | ||
1812 | break; | ||
1813 | |||
1814 | /* Exchange v with the smallest son */ | ||
1815 | heap[k] = heap[j]; | ||
1816 | k = j; | ||
1817 | |||
1818 | /* And continue down the tree, setting j to the left son of k */ | ||
1819 | j <<= 1; | ||
1820 | } | ||
1821 | heap[k] = v; | ||
1822 | } | ||
1823 | |||
1824 | /* =========================================================================== | ||
1825 | * Compute the optimal bit lengths for a tree and update the total bit length | ||
1826 | * for the current block. | ||
1827 | * IN assertion: the fields freq and dad are set, heap[heap_max] and | ||
1828 | * above are the tree nodes sorted by increasing frequency. | ||
1829 | * OUT assertions: the field len is set to the optimal bit length, the | ||
1830 | * array bl_count contains the frequencies for each bit length. | ||
1831 | * The length opt_len is updated; static_len is also updated if stree is | ||
1832 | * not null. | ||
1833 | */ | ||
1834 | static void gen_bitlen(tree_desc * desc) | ||
1835 | { | ||
1836 | ct_data *tree = desc->dyn_tree; | ||
1837 | const extra_bits_t *extra = desc->extra_bits; | ||
1838 | int base = desc->extra_base; | ||
1839 | int max_code = desc->max_code; | ||
1840 | int max_length = desc->max_length; | ||
1841 | ct_data *stree = desc->static_tree; | ||
1842 | int h; /* heap index */ | ||
1843 | int n, m; /* iterate over the tree elements */ | ||
1844 | int bits; /* bit length */ | ||
1845 | int xbits; /* extra bits */ | ||
1846 | ush f; /* frequency */ | ||
1847 | int overflow = 0; /* number of elements with bit length too large */ | ||
1848 | |||
1849 | for (bits = 0; bits <= MAX_BITS; bits++) | ||
1850 | bl_count[bits] = 0; | ||
1851 | |||
1852 | /* In a first pass, compute the optimal bit lengths (which may | ||
1853 | * overflow in the case of the bit length tree). | ||
1854 | */ | ||
1855 | tree[heap[heap_max]].Len = 0; /* root of the heap */ | ||
1856 | |||
1857 | for (h = heap_max + 1; h < HEAP_SIZE; h++) { | ||
1858 | n = heap[h]; | ||
1859 | bits = tree[tree[n].Dad].Len + 1; | ||
1860 | if (bits > max_length) | ||
1861 | bits = max_length, overflow++; | ||
1862 | tree[n].Len = (ush) bits; | ||
1863 | /* We overwrite tree[n].Dad which is no longer needed */ | ||
1864 | |||
1865 | if (n > max_code) | ||
1866 | continue; /* not a leaf node */ | ||
1867 | |||
1868 | bl_count[bits]++; | ||
1869 | xbits = 0; | ||
1870 | if (n >= base) | ||
1871 | xbits = extra[n - base]; | ||
1872 | f = tree[n].Freq; | ||
1873 | opt_len += (ulg) f *(bits + xbits); | ||
1874 | |||
1875 | if (stree) | ||
1876 | static_len += (ulg) f *(stree[n].Len + xbits); | ||
1877 | } | ||
1878 | if (overflow == 0) | ||
1879 | return; | ||
1880 | |||
1881 | Trace((stderr, "\nbit length overflow\n")); | ||
1882 | /* This happens for example on obj2 and pic of the Calgary corpus */ | ||
1883 | |||
1884 | /* Find the first bit length which could increase: */ | ||
1885 | do { | ||
1886 | bits = max_length - 1; | ||
1887 | while (bl_count[bits] == 0) | ||
1888 | bits--; | ||
1889 | bl_count[bits]--; /* move one leaf down the tree */ | ||
1890 | bl_count[bits + 1] += 2; /* move one overflow item as its brother */ | ||
1891 | bl_count[max_length]--; | ||
1892 | /* The brother of the overflow item also moves one step up, | ||
1893 | * but this does not affect bl_count[max_length] | ||
1894 | */ | ||
1895 | overflow -= 2; | ||
1896 | } while (overflow > 0); | ||
1897 | |||
1898 | /* Now recompute all bit lengths, scanning in increasing frequency. | ||
1899 | * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all | ||
1900 | * lengths instead of fixing only the wrong ones. This idea is taken | ||
1901 | * from 'ar' written by Haruhiko Okumura.) | ||
1902 | */ | ||
1903 | for (bits = max_length; bits != 0; bits--) { | ||
1904 | n = bl_count[bits]; | ||
1905 | while (n != 0) { | ||
1906 | m = heap[--h]; | ||
1907 | if (m > max_code) | ||
1908 | continue; | ||
1909 | if (tree[m].Len != (unsigned) bits) { | ||
1910 | Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, | ||
1911 | bits)); | ||
1912 | opt_len += | ||
1913 | ((long) bits - (long) tree[m].Len) * (long) tree[m].Freq; | ||
1914 | tree[m].Len = (ush) bits; | ||
1915 | } | ||
1916 | n--; | ||
1917 | } | ||
1918 | } | ||
1919 | } | ||
1920 | |||
1921 | /* =========================================================================== | ||
1922 | * Generate the codes for a given tree and bit counts (which need not be | ||
1923 | * optimal). | ||
1924 | * IN assertion: the array bl_count contains the bit length statistics for | ||
1925 | * the given tree and the field len is set for all tree elements. | ||
1926 | * OUT assertion: the field code is set for all tree elements of non | ||
1927 | * zero code length. | ||
1928 | */ | ||
1929 | static void gen_codes(ct_data * tree, int max_code) | ||
1930 | { | ||
1931 | ush next_code[MAX_BITS + 1]; /* next code value for each bit length */ | ||
1932 | ush code = 0; /* running code value */ | ||
1933 | int bits; /* bit index */ | ||
1934 | int n; /* code index */ | ||
1935 | |||
1936 | /* The distribution counts are first used to generate the code values | ||
1937 | * without bit reversal. | ||
1938 | */ | ||
1939 | for (bits = 1; bits <= MAX_BITS; bits++) { | ||
1940 | next_code[bits] = code = (code + bl_count[bits - 1]) << 1; | ||
1941 | } | ||
1942 | /* Check that the bit counts in bl_count are consistent. The last code | ||
1943 | * must be all ones. | ||
1944 | */ | ||
1945 | Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, | ||
1946 | "inconsistent bit counts"); | ||
1947 | Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); | ||
1948 | |||
1949 | for (n = 0; n <= max_code; n++) { | ||
1950 | int len = tree[n].Len; | ||
1951 | |||
1952 | if (len == 0) | ||
1953 | continue; | ||
1954 | /* Now reverse the bits */ | ||
1955 | tree[n].Code = bi_reverse(next_code[len]++, len); | ||
1956 | |||
1957 | Tracec(tree != static_ltree, | ||
1958 | (stderr, "\nn %3d %c l %2d c %4x (%x) ", n, | ||
1959 | (isgraph(n) ? n : ' '), len, tree[n].Code, | ||
1960 | next_code[len] - 1)); | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | /* =========================================================================== | ||
1965 | * Construct one Huffman tree and assigns the code bit strings and lengths. | ||
1966 | * Update the total bit length for the current block. | ||
1967 | * IN assertion: the field freq is set for all tree elements. | ||
1968 | * OUT assertions: the fields len and code are set to the optimal bit length | ||
1969 | * and corresponding code. The length opt_len is updated; static_len is | ||
1970 | * also updated if stree is not null. The field max_code is set. | ||
1971 | */ | ||
1972 | static void build_tree(tree_desc * desc) | ||
1973 | { | ||
1974 | ct_data *tree = desc->dyn_tree; | ||
1975 | ct_data *stree = desc->static_tree; | ||
1976 | int elems = desc->elems; | ||
1977 | int n, m; /* iterate over heap elements */ | ||
1978 | int max_code = -1; /* largest code with non zero frequency */ | ||
1979 | int node = elems; /* next internal node of the tree */ | ||
1980 | |||
1981 | /* Construct the initial heap, with least frequent element in | ||
1982 | * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. | ||
1983 | * heap[0] is not used. | ||
1984 | */ | ||
1985 | heap_len = 0, heap_max = HEAP_SIZE; | ||
1986 | |||
1987 | for (n = 0; n < elems; n++) { | ||
1988 | if (tree[n].Freq != 0) { | ||
1989 | heap[++heap_len] = max_code = n; | ||
1990 | depth[n] = 0; | ||
1991 | } else { | ||
1992 | tree[n].Len = 0; | ||
1993 | } | ||
1994 | } | ||
1995 | |||
1996 | /* The pkzip format requires that at least one distance code exists, | ||
1997 | * and that at least one bit should be sent even if there is only one | ||
1998 | * possible code. So to avoid special checks later on we force at least | ||
1999 | * two codes of non zero frequency. | ||
2000 | */ | ||
2001 | while (heap_len < 2) { | ||
2002 | int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0); | ||
2003 | |||
2004 | tree[new].Freq = 1; | ||
2005 | depth[new] = 0; | ||
2006 | opt_len--; | ||
2007 | if (stree) | ||
2008 | static_len -= stree[new].Len; | ||
2009 | /* new is 0 or 1 so it does not have extra bits */ | ||
2010 | } | ||
2011 | desc->max_code = max_code; | ||
2012 | |||
2013 | /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, | ||
2014 | * establish sub-heaps of increasing lengths: | ||
2015 | */ | ||
2016 | for (n = heap_len / 2; n >= 1; n--) | ||
2017 | pqdownheap(tree, n); | ||
2018 | |||
2019 | /* Construct the Huffman tree by repeatedly combining the least two | ||
2020 | * frequent nodes. | ||
2021 | */ | ||
2022 | do { | ||
2023 | pqremove(tree, n); /* n = node of least frequency */ | ||
2024 | m = heap[SMALLEST]; /* m = node of next least frequency */ | ||
2025 | |||
2026 | heap[--heap_max] = n; /* keep the nodes sorted by frequency */ | ||
2027 | heap[--heap_max] = m; | ||
2028 | |||
2029 | /* Create a new node father of n and m */ | ||
2030 | tree[node].Freq = tree[n].Freq + tree[m].Freq; | ||
2031 | depth[node] = (uch) (MAX(depth[n], depth[m]) + 1); | ||
2032 | tree[n].Dad = tree[m].Dad = (ush) node; | ||
2033 | #ifdef DUMP_BL_TREE | ||
2034 | if (tree == bl_tree) { | ||
2035 | bb_error_msg("\nnode %d(%d), sons %d(%d) %d(%d)", | ||
2036 | node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); | ||
2037 | } | ||
2038 | #endif | ||
2039 | /* and insert the new node in the heap */ | ||
2040 | heap[SMALLEST] = node++; | ||
2041 | pqdownheap(tree, SMALLEST); | ||
2042 | |||
2043 | } while (heap_len >= 2); | ||
2044 | |||
2045 | heap[--heap_max] = heap[SMALLEST]; | ||
2046 | |||
2047 | /* At this point, the fields freq and dad are set. We can now | ||
2048 | * generate the bit lengths. | ||
2049 | */ | ||
2050 | gen_bitlen((tree_desc *) desc); | ||
2051 | |||
2052 | /* The field len is now set, we can generate the bit codes */ | ||
2053 | gen_codes((ct_data *) tree, max_code); | ||
2054 | } | ||
2055 | |||
2056 | /* =========================================================================== | ||
2057 | * Scan a literal or distance tree to determine the frequencies of the codes | ||
2058 | * in the bit length tree. Updates opt_len to take into account the repeat | ||
2059 | * counts. (The contribution of the bit length codes will be added later | ||
2060 | * during the construction of bl_tree.) | ||
2061 | */ | ||
2062 | static void scan_tree(ct_data * tree, int max_code) | ||
2063 | { | ||
2064 | int n; /* iterates over all tree elements */ | ||
2065 | int prevlen = -1; /* last emitted length */ | ||
2066 | int curlen; /* length of current code */ | ||
2067 | int nextlen = tree[0].Len; /* length of next code */ | ||
2068 | int count = 0; /* repeat count of the current code */ | ||
2069 | int max_count = 7; /* max repeat count */ | ||
2070 | int min_count = 4; /* min repeat count */ | ||
2071 | |||
2072 | if (nextlen == 0) | ||
2073 | max_count = 138, min_count = 3; | ||
2074 | tree[max_code + 1].Len = (ush) 0xffff; /* guard */ | ||
2075 | |||
2076 | for (n = 0; n <= max_code; n++) { | ||
2077 | curlen = nextlen; | ||
2078 | nextlen = tree[n + 1].Len; | ||
2079 | if (++count < max_count && curlen == nextlen) { | ||
2080 | continue; | ||
2081 | } else if (count < min_count) { | ||
2082 | bl_tree[curlen].Freq += count; | ||
2083 | } else if (curlen != 0) { | ||
2084 | if (curlen != prevlen) | ||
2085 | bl_tree[curlen].Freq++; | ||
2086 | bl_tree[REP_3_6].Freq++; | ||
2087 | } else if (count <= 10) { | ||
2088 | bl_tree[REPZ_3_10].Freq++; | ||
2089 | } else { | ||
2090 | bl_tree[REPZ_11_138].Freq++; | ||
2091 | } | ||
2092 | count = 0; | ||
2093 | prevlen = curlen; | ||
2094 | if (nextlen == 0) { | ||
2095 | max_count = 138, min_count = 3; | ||
2096 | } else if (curlen == nextlen) { | ||
2097 | max_count = 6, min_count = 3; | ||
2098 | } else { | ||
2099 | max_count = 7, min_count = 4; | ||
2100 | } | ||
2101 | } | ||
2102 | } | ||
2103 | |||
2104 | /* =========================================================================== | ||
2105 | * Send a literal or distance tree in compressed form, using the codes in | ||
2106 | * bl_tree. | ||
2107 | */ | ||
2108 | static void send_tree(ct_data * tree, int max_code) | ||
2109 | { | ||
2110 | int n; /* iterates over all tree elements */ | ||
2111 | int prevlen = -1; /* last emitted length */ | ||
2112 | int curlen; /* length of current code */ | ||
2113 | int nextlen = tree[0].Len; /* length of next code */ | ||
2114 | int count = 0; /* repeat count of the current code */ | ||
2115 | int max_count = 7; /* max repeat count */ | ||
2116 | int min_count = 4; /* min repeat count */ | ||
2117 | |||
2118 | /* tree[max_code+1].Len = -1; *//* guard already set */ | ||
2119 | if (nextlen == 0) | ||
2120 | max_count = 138, min_count = 3; | ||
2121 | |||
2122 | for (n = 0; n <= max_code; n++) { | ||
2123 | curlen = nextlen; | ||
2124 | nextlen = tree[n + 1].Len; | ||
2125 | if (++count < max_count && curlen == nextlen) { | ||
2126 | continue; | ||
2127 | } else if (count < min_count) { | ||
2128 | do { | ||
2129 | send_code(curlen, bl_tree); | ||
2130 | } while (--count != 0); | ||
2131 | |||
2132 | } else if (curlen != 0) { | ||
2133 | if (curlen != prevlen) { | ||
2134 | send_code(curlen, bl_tree); | ||
2135 | count--; | ||
2136 | } | ||
2137 | Assert(count >= 3 && count <= 6, " 3_6?"); | ||
2138 | send_code(REP_3_6, bl_tree); | ||
2139 | send_bits(count - 3, 2); | ||
2140 | |||
2141 | } else if (count <= 10) { | ||
2142 | send_code(REPZ_3_10, bl_tree); | ||
2143 | send_bits(count - 3, 3); | ||
2144 | |||
2145 | } else { | ||
2146 | send_code(REPZ_11_138, bl_tree); | ||
2147 | send_bits(count - 11, 7); | ||
2148 | } | ||
2149 | count = 0; | ||
2150 | prevlen = curlen; | ||
2151 | if (nextlen == 0) { | ||
2152 | max_count = 138, min_count = 3; | ||
2153 | } else if (curlen == nextlen) { | ||
2154 | max_count = 6, min_count = 3; | ||
2155 | } else { | ||
2156 | max_count = 7, min_count = 4; | ||
2157 | } | ||
2158 | } | ||
2159 | } | ||
2160 | |||
2161 | /* =========================================================================== | ||
2162 | * Construct the Huffman tree for the bit lengths and return the index in | ||
2163 | * bl_order of the last bit length code to send. | ||
2164 | */ | ||
2165 | static const int build_bl_tree() | ||
2166 | { | ||
2167 | int max_blindex; /* index of last bit length code of non zero freq */ | ||
2168 | |||
2169 | /* Determine the bit length frequencies for literal and distance trees */ | ||
2170 | scan_tree((ct_data *) dyn_ltree, l_desc.max_code); | ||
2171 | scan_tree((ct_data *) dyn_dtree, d_desc.max_code); | ||
2172 | |||
2173 | /* Build the bit length tree: */ | ||
2174 | build_tree((tree_desc *) (&bl_desc)); | ||
2175 | /* opt_len now includes the length of the tree representations, except | ||
2176 | * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. | ||
2177 | */ | ||
2178 | |||
2179 | /* Determine the number of bit length codes to send. The pkzip format | ||
2180 | * requires that at least 4 bit length codes be sent. (appnote.txt says | ||
2181 | * 3 but the actual value used is 4.) | ||
2182 | */ | ||
2183 | for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { | ||
2184 | if (bl_tree[bl_order[max_blindex]].Len != 0) | ||
2185 | break; | ||
2186 | } | ||
2187 | /* Update opt_len to include the bit length tree and counts */ | ||
2188 | opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; | ||
2189 | Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len)); | ||
2190 | |||
2191 | return max_blindex; | ||
2192 | } | ||
2193 | |||
2194 | /* =========================================================================== | ||
2195 | * Send the header for a block using dynamic Huffman trees: the counts, the | ||
2196 | * lengths of the bit length codes, the literal tree and the distance tree. | ||
2197 | * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. | ||
2198 | */ | ||
2199 | static void send_all_trees(int lcodes, int dcodes, int blcodes) | ||
2200 | { | ||
2201 | int rank; /* index in bl_order */ | ||
2202 | |||
2203 | Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); | ||
2204 | Assert(lcodes <= L_CODES && dcodes <= D_CODES | ||
2205 | && blcodes <= BL_CODES, "too many codes"); | ||
2206 | Tracev((stderr, "\nbl counts: ")); | ||
2207 | send_bits(lcodes - 257, 5); /* not +255 as stated in appnote.txt */ | ||
2208 | send_bits(dcodes - 1, 5); | ||
2209 | send_bits(blcodes - 4, 4); /* not -3 as stated in appnote.txt */ | ||
2210 | for (rank = 0; rank < blcodes; rank++) { | ||
2211 | Tracev((stderr, "\nbl code %2d ", bl_order[rank])); | ||
2212 | send_bits(bl_tree[bl_order[rank]].Len, 3); | ||
2213 | } | ||
2214 | Tracev((stderr, "\nbl tree: sent %ld", bits_sent)); | ||
2215 | |||
2216 | send_tree((ct_data *) dyn_ltree, lcodes - 1); /* send the literal tree */ | ||
2217 | Tracev((stderr, "\nlit tree: sent %ld", bits_sent)); | ||
2218 | |||
2219 | send_tree((ct_data *) dyn_dtree, dcodes - 1); /* send the distance tree */ | ||
2220 | Tracev((stderr, "\ndist tree: sent %ld", bits_sent)); | ||
2221 | } | ||
2222 | |||
2223 | /* =========================================================================== | ||
2224 | * Determine the best encoding for the current block: dynamic trees, static | ||
2225 | * trees or store, and output the encoded block to the zip file. This function | ||
2226 | * returns the total compressed length for the file so far. | ||
2227 | */ | ||
2228 | static ulg flush_block(char *buf, ulg stored_len, int eof) | ||
2229 | { | ||
2230 | ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ | ||
2231 | int max_blindex; /* index of last bit length code of non zero freq */ | ||
2232 | |||
2233 | flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */ | ||
2234 | |||
2235 | /* Check if the file is ascii or binary */ | ||
2236 | if (*file_type == (ush) UNKNOWN) | ||
2237 | set_file_type(); | ||
2238 | |||
2239 | /* Construct the literal and distance trees */ | ||
2240 | build_tree((tree_desc *) (&l_desc)); | ||
2241 | Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len)); | ||
2242 | |||
2243 | build_tree((tree_desc *) (&d_desc)); | ||
2244 | Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len)); | ||
2245 | /* At this point, opt_len and static_len are the total bit lengths of | ||
2246 | * the compressed block data, excluding the tree representations. | ||
2247 | */ | ||
2248 | |||
2249 | /* Build the bit length tree for the above two trees, and get the index | ||
2250 | * in bl_order of the last bit length code to send. | ||
2251 | */ | ||
2252 | max_blindex = build_bl_tree(); | ||
2253 | |||
2254 | /* Determine the best encoding. Compute first the block length in bytes */ | ||
2255 | opt_lenb = (opt_len + 3 + 7) >> 3; | ||
2256 | static_lenb = (static_len + 3 + 7) >> 3; | ||
2257 | |||
2258 | Trace((stderr, | ||
2259 | "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", | ||
2260 | opt_lenb, opt_len, static_lenb, static_len, stored_len, | ||
2261 | last_lit, last_dist)); | ||
2262 | |||
2263 | if (static_lenb <= opt_lenb) | ||
2264 | opt_lenb = static_lenb; | ||
2265 | |||
2266 | /* If compression failed and this is the first and last block, | ||
2267 | * and if the zip file can be seeked (to rewrite the local header), | ||
2268 | * the whole file is transformed into a stored file: | ||
2269 | */ | ||
2270 | if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) { | ||
2271 | /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ | ||
2272 | if (buf == (char *) 0) | ||
2273 | bb_error_msg("block vanished"); | ||
2274 | |||
2275 | copy_block(buf, (unsigned) stored_len, 0); /* without header */ | ||
2276 | compressed_len = stored_len << 3; | ||
2277 | *file_method = STORED; | ||
2278 | |||
2279 | } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) { | ||
2280 | /* 4: two words for the lengths */ | ||
2281 | /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. | ||
2282 | * Otherwise we can't have processed more than WSIZE input bytes since | ||
2283 | * the last block flush, because compression would have been | ||
2284 | * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to | ||
2285 | * transform a block into a stored block. | ||
2286 | */ | ||
2287 | send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */ | ||
2288 | compressed_len = (compressed_len + 3 + 7) & ~7L; | ||
2289 | compressed_len += (stored_len + 4) << 3; | ||
2290 | |||
2291 | copy_block(buf, (unsigned) stored_len, 1); /* with header */ | ||
2292 | |||
2293 | } else if (static_lenb == opt_lenb) { | ||
2294 | send_bits((STATIC_TREES << 1) + eof, 3); | ||
2295 | compress_block((ct_data *) static_ltree, (ct_data *) static_dtree); | ||
2296 | compressed_len += 3 + static_len; | ||
2297 | } else { | ||
2298 | send_bits((DYN_TREES << 1) + eof, 3); | ||
2299 | send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, | ||
2300 | max_blindex + 1); | ||
2301 | compress_block((ct_data *) dyn_ltree, (ct_data *) dyn_dtree); | ||
2302 | compressed_len += 3 + opt_len; | ||
2303 | } | ||
2304 | Assert(compressed_len == bits_sent, "bad compressed size"); | ||
2305 | init_block(); | ||
2306 | |||
2307 | if (eof) { | ||
2308 | bi_windup(); | ||
2309 | compressed_len += 7; /* align on byte boundary */ | ||
2310 | } | ||
2311 | Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3, | ||
2312 | compressed_len - 7 * eof)); | ||
2313 | |||
2314 | return compressed_len >> 3; | ||
2315 | } | ||
2316 | |||
2317 | /* =========================================================================== | ||
2318 | * Save the match info and tally the frequency counts. Return true if | ||
2319 | * the current block must be flushed. | ||
2320 | */ | ||
2321 | static int ct_tally(int dist, int lc) | ||
2322 | { | ||
2323 | l_buf[last_lit++] = (uch) lc; | ||
2324 | if (dist == 0) { | ||
2325 | /* lc is the unmatched char */ | ||
2326 | dyn_ltree[lc].Freq++; | ||
2327 | } else { | ||
2328 | /* Here, lc is the match length - MIN_MATCH */ | ||
2329 | dist--; /* dist = match distance - 1 */ | ||
2330 | Assert((ush) dist < (ush) MAX_DIST && | ||
2331 | (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) && | ||
2332 | (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match"); | ||
2333 | |||
2334 | dyn_ltree[length_code[lc] + LITERALS + 1].Freq++; | ||
2335 | dyn_dtree[d_code(dist)].Freq++; | ||
2336 | |||
2337 | d_buf[last_dist++] = (ush) dist; | ||
2338 | flags |= flag_bit; | ||
2339 | } | ||
2340 | flag_bit <<= 1; | ||
2341 | |||
2342 | /* Output the flags if they fill a byte: */ | ||
2343 | if ((last_lit & 7) == 0) { | ||
2344 | flag_buf[last_flags++] = flags; | ||
2345 | flags = 0, flag_bit = 1; | ||
2346 | } | ||
2347 | /* Try to guess if it is profitable to stop the current block here */ | ||
2348 | if ((last_lit & 0xfff) == 0) { | ||
2349 | /* Compute an upper bound for the compressed length */ | ||
2350 | ulg out_length = (ulg) last_lit * 8L; | ||
2351 | ulg in_length = (ulg) strstart - block_start; | ||
2352 | int dcode; | ||
2353 | |||
2354 | for (dcode = 0; dcode < D_CODES; dcode++) { | ||
2355 | out_length += | ||
2356 | (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]); | ||
2357 | } | ||
2358 | out_length >>= 3; | ||
2359 | Trace((stderr, | ||
2360 | "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", | ||
2361 | last_lit, last_dist, in_length, out_length, | ||
2362 | 100L - out_length * 100L / in_length)); | ||
2363 | if (last_dist < last_lit / 2 && out_length < in_length / 2) | ||
2364 | return 1; | ||
2365 | } | ||
2366 | return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE); | ||
2367 | /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K | ||
2368 | * on 16 bit machines and because stored blocks are restricted to | ||
2369 | * 64K-1 bytes. | ||
2370 | */ | ||
2371 | } | ||
2372 | |||
2373 | /* =========================================================================== | ||
2374 | * Send the block data compressed using the given Huffman trees | ||
2375 | */ | ||
2376 | static void compress_block(ct_data * ltree, ct_data * dtree) | ||
2377 | { | ||
2378 | unsigned dist; /* distance of matched string */ | ||
2379 | int lc; /* match length or unmatched char (if dist == 0) */ | ||
2380 | unsigned lx = 0; /* running index in l_buf */ | ||
2381 | unsigned dx = 0; /* running index in d_buf */ | ||
2382 | unsigned fx = 0; /* running index in flag_buf */ | ||
2383 | uch flag = 0; /* current flags */ | ||
2384 | unsigned code; /* the code to send */ | ||
2385 | int extra; /* number of extra bits to send */ | ||
2386 | |||
2387 | if (last_lit != 0) | ||
2388 | do { | ||
2389 | if ((lx & 7) == 0) | ||
2390 | flag = flag_buf[fx++]; | ||
2391 | lc = l_buf[lx++]; | ||
2392 | if ((flag & 1) == 0) { | ||
2393 | send_code(lc, ltree); /* send a literal byte */ | ||
2394 | Tracecv(isgraph(lc), (stderr, " '%c' ", lc)); | ||
2395 | } else { | ||
2396 | /* Here, lc is the match length - MIN_MATCH */ | ||
2397 | code = length_code[lc]; | ||
2398 | send_code(code + LITERALS + 1, ltree); /* send the length code */ | ||
2399 | extra = extra_lbits[code]; | ||
2400 | if (extra != 0) { | ||
2401 | lc -= base_length[code]; | ||
2402 | send_bits(lc, extra); /* send the extra length bits */ | ||
2403 | } | ||
2404 | dist = d_buf[dx++]; | ||
2405 | /* Here, dist is the match distance - 1 */ | ||
2406 | code = d_code(dist); | ||
2407 | Assert(code < D_CODES, "bad d_code"); | ||
2408 | |||
2409 | send_code(code, dtree); /* send the distance code */ | ||
2410 | extra = extra_dbits[code]; | ||
2411 | if (extra != 0) { | ||
2412 | dist -= base_dist[code]; | ||
2413 | send_bits(dist, extra); /* send the extra distance bits */ | ||
2414 | } | ||
2415 | } /* literal or match pair ? */ | ||
2416 | flag >>= 1; | ||
2417 | } while (lx < last_lit); | ||
2418 | |||
2419 | send_code(END_BLOCK, ltree); | ||
2420 | } | ||
2421 | |||
2422 | /* =========================================================================== | ||
2423 | * Set the file type to ASCII or BINARY, using a crude approximation: | ||
2424 | * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. | ||
2425 | * IN assertion: the fields freq of dyn_ltree are set and the total of all | ||
2426 | * frequencies does not exceed 64K (to fit in an int on 16 bit machines). | ||
2427 | */ | ||
2428 | static void set_file_type() | ||
2429 | { | ||
2430 | int n = 0; | ||
2431 | unsigned ascii_freq = 0; | ||
2432 | unsigned bin_freq = 0; | ||
2433 | |||
2434 | while (n < 7) | ||
2435 | bin_freq += dyn_ltree[n++].Freq; | ||
2436 | while (n < 128) | ||
2437 | ascii_freq += dyn_ltree[n++].Freq; | ||
2438 | while (n < LITERALS) | ||
2439 | bin_freq += dyn_ltree[n++].Freq; | ||
2440 | *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; | ||
2441 | if (*file_type == BINARY && translate_eol) { | ||
2442 | bb_error_msg("-l used on binary file"); | ||
2443 | } | ||
2444 | } | ||
2445 | |||
2446 | /* zip.c -- compress files to the gzip or pkzip format | ||
2447 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
2448 | * This is free software; you can redistribute it and/or modify it under the | ||
2449 | * terms of the GNU General Public License, see the file COPYING. | ||
2450 | */ | ||
2451 | |||
2452 | |||
2453 | static ulg crc; /* crc on uncompressed file data */ | ||
2454 | static long header_bytes; /* number of bytes in gzip header */ | ||
2455 | |||
2456 | static void put_long(ulg n) | ||
2457 | { | ||
2458 | put_short((n) & 0xffff); | ||
2459 | put_short(((ulg) (n)) >> 16); | ||
2460 | } | ||
2461 | |||
2462 | /* put_header_byte is used for the compressed output | ||
2463 | * - for the initial 4 bytes that can't overflow the buffer. | ||
2464 | */ | ||
2465 | #define put_header_byte(c) {outbuf[outcnt++]=(uch)(c);} | ||
2466 | |||
2467 | /* =========================================================================== | ||
2468 | * Deflate in to out. | ||
2469 | * IN assertions: the input and output buffers are cleared. | ||
2470 | * The variables time_stamp and save_orig_name are initialized. | ||
2471 | */ | ||
2472 | static int zip(int in, int out) | ||
2473 | { | ||
2474 | uch my_flags = 0; /* general purpose bit flags */ | ||
2475 | ush attr = 0; /* ascii/binary flag */ | ||
2476 | ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ | ||
2477 | |||
2478 | ifd = in; | ||
2479 | ofd = out; | ||
2480 | outcnt = 0; | ||
2481 | |||
2482 | /* Write the header to the gzip file. See algorithm.doc for the format */ | ||
2483 | |||
2484 | |||
2485 | method = DEFLATED; | ||
2486 | put_header_byte(GZIP_MAGIC[0]); /* magic header */ | ||
2487 | put_header_byte(GZIP_MAGIC[1]); | ||
2488 | put_header_byte(DEFLATED); /* compression method */ | ||
2489 | |||
2490 | put_header_byte(my_flags); /* general flags */ | ||
2491 | put_long(time_stamp); | ||
2492 | |||
2493 | /* Write deflated file to zip file */ | ||
2494 | crc = updcrc(0, 0); | ||
2495 | |||
2496 | bi_init(out); | ||
2497 | ct_init(&attr, &method); | ||
2498 | lm_init(&deflate_flags); | ||
2499 | |||
2500 | put_byte((uch) deflate_flags); /* extra flags */ | ||
2501 | put_byte(OS_CODE); /* OS identifier */ | ||
2502 | |||
2503 | header_bytes = (long) outcnt; | ||
2504 | |||
2505 | (void) deflate(); | ||
2506 | |||
2507 | /* Write the crc and uncompressed size */ | ||
2508 | put_long(crc); | ||
2509 | put_long(isize); | ||
2510 | header_bytes += 2 * sizeof(long); | ||
2511 | |||
2512 | flush_outbuf(); | ||
2513 | return OK; | ||
2514 | } | ||
2515 | |||
2516 | |||
2517 | /* =========================================================================== | ||
2518 | * Read a new buffer from the current input file, perform end-of-line | ||
2519 | * translation, and update the crc and input file size. | ||
2520 | * IN assertion: size >= 2 (for end-of-line translation) | ||
2521 | */ | ||
2522 | static int file_read(char *buf, unsigned size) | ||
2523 | { | ||
2524 | unsigned len; | ||
2525 | |||
2526 | Assert(insize == 0, "inbuf not empty"); | ||
2527 | |||
2528 | len = read(ifd, buf, size); | ||
2529 | if (len == (unsigned) (-1) || len == 0) | ||
2530 | return (int) len; | ||
2531 | |||
2532 | crc = updcrc((uch *) buf, len); | ||
2533 | isize += (ulg) len; | ||
2534 | return (int) len; | ||
2535 | } | ||
2536 | |||
2537 | /* =========================================================================== | ||
2538 | * Write the output buffer outbuf[0..outcnt-1] and update bytes_out. | ||
2539 | * (used for the compressed data only) | ||
2540 | */ | ||
2541 | static void flush_outbuf() | ||
2542 | { | ||
2543 | if (outcnt == 0) | ||
2544 | return; | ||
2545 | |||
2546 | write_buf(ofd, (char *) outbuf, outcnt); | ||
2547 | outcnt = 0; | ||
2548 | } | ||
diff --git a/busybox/archival/libunarchive/Makefile b/busybox/archival/libunarchive/Makefile new file mode 100644 index 000000000..e985fa49f --- /dev/null +++ b/busybox/archival/libunarchive/Makefile | |||
@@ -0,0 +1,32 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | # | ||
19 | |||
20 | top_srcdir=../.. | ||
21 | top_builddir=../.. | ||
22 | srcdir=$(top_srcdir)/archival/libunarchive | ||
23 | LIBUNARCHIVE_DIR:=./ | ||
24 | include $(top_builddir)/Rules.mak | ||
25 | include $(top_builddir)/.config | ||
26 | include $(srcdir)/Makefile.in | ||
27 | all: $(libraries-y) | ||
28 | -include $(top_builddir)/.depend | ||
29 | |||
30 | clean: | ||
31 | rm -f *.o *.a $(AR_TARGET) | ||
32 | |||
diff --git a/busybox/archival/libunarchive/Makefile.in b/busybox/archival/libunarchive/Makefile.in new file mode 100644 index 000000000..809b0e10e --- /dev/null +++ b/busybox/archival/libunarchive/Makefile.in | |||
@@ -0,0 +1,84 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | # | ||
19 | |||
20 | LIBUNARCHIVE_AR:=libunarchive.a | ||
21 | ifndef $(LIBUNARCHIVE_DIR) | ||
22 | LIBUNARCHIVE_DIR:=$(top_builddir)/archival/libunarchive/ | ||
23 | endif | ||
24 | srcdir=$(top_srcdir)/archvial/libunarchive | ||
25 | |||
26 | LIBUNARCHIVE-y:= \ | ||
27 | \ | ||
28 | data_skip.o \ | ||
29 | data_extract_all.o \ | ||
30 | data_extract_to_stdout.o \ | ||
31 | data_extract_to_buffer.o \ | ||
32 | \ | ||
33 | filter_accept_all.o \ | ||
34 | filter_accept_list.o \ | ||
35 | filter_accept_reject_list.o \ | ||
36 | \ | ||
37 | header_skip.o \ | ||
38 | header_list.o \ | ||
39 | header_verbose_list.o \ | ||
40 | \ | ||
41 | archive_xread_all.o \ | ||
42 | archive_xread_all_eof.o \ | ||
43 | \ | ||
44 | seek_by_char.o \ | ||
45 | seek_by_jump.o \ | ||
46 | \ | ||
47 | data_align.o \ | ||
48 | find_list_entry.o \ | ||
49 | open_transformer.o \ | ||
50 | init_handle.o | ||
51 | |||
52 | GUNZIP_FILES:= check_header_gzip.o decompress_unzip.o | ||
53 | DPKG_FILES:= \ | ||
54 | get_header_ar.o \ | ||
55 | unpack_ar_archive.o \ | ||
56 | get_header_tar.o \ | ||
57 | filter_accept_list_reassign.o | ||
58 | |||
59 | LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o | ||
60 | LIBUNARCHIVE-$(CONFIG_BUNZIP2) += decompress_bunzip2.o | ||
61 | LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o | ||
62 | LIBUNARCHIVE-$(CONFIG_DPKG) += $(DPKG_FILES) | ||
63 | LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) | ||
64 | LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o | ||
65 | LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o | ||
66 | LIBUNARCHIVE-$(CONFIG_GUNZIP) += $(GUNZIP_FILES) | ||
67 | LIBUNARCHIVE-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o | ||
68 | LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o | ||
69 | LIBUNARCHIVE-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o | ||
70 | LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o | ||
71 | LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o | ||
72 | LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_GZIP) += $(GUNZIP_FILES) get_header_tar_gz.o | ||
73 | LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o | ||
74 | LIBUNARCHIVE-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o | ||
75 | LIBUNARCHIVE-$(CONFIG_UNZIP) += $(GUNZIP_FILES) | ||
76 | |||
77 | libraries-y+=$(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR) | ||
78 | |||
79 | $(LIBUNARCHIVE_DIR)$(LIBUNARCHIVE_AR): $(patsubst %,$(LIBUNARCHIVE_DIR)%, $(LIBUNARCHIVE-y)) | ||
80 | $(AR) -ro $@ $(patsubst %,$(LIBUNARCHIVE_DIR)%, $(LIBUNARCHIVE-y)) | ||
81 | |||
82 | $(LIBUNARCHIVA_DIR)%.o: $(srcdir)/%.c | ||
83 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< | ||
84 | |||
diff --git a/busybox/archival/libunarchive/archive_xread_all.c b/busybox/archival/libunarchive/archive_xread_all.c new file mode 100644 index 000000000..ba9ade2d5 --- /dev/null +++ b/busybox/archival/libunarchive/archive_xread_all.c | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include "unarchive.h" | ||
21 | #include "libbb.h" | ||
22 | |||
23 | extern void archive_xread_all(const archive_handle_t *archive_handle, void *buf, const size_t count) | ||
24 | { | ||
25 | ssize_t size; | ||
26 | |||
27 | size = bb_full_read(archive_handle->src_fd, buf, count); | ||
28 | if (size != count) { | ||
29 | bb_error_msg_and_die("Short read"); | ||
30 | } | ||
31 | return; | ||
32 | } | ||
diff --git a/busybox/archival/libunarchive/archive_xread_all_eof.c b/busybox/archival/libunarchive/archive_xread_all_eof.c new file mode 100644 index 000000000..8084e3524 --- /dev/null +++ b/busybox/archival/libunarchive/archive_xread_all_eof.c | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include "unarchive.h" | ||
21 | #include "libbb.h" | ||
22 | |||
23 | extern ssize_t archive_xread_all_eof(archive_handle_t *archive_handle, unsigned char *buf, size_t count) | ||
24 | { | ||
25 | ssize_t size; | ||
26 | |||
27 | size = bb_full_read(archive_handle->src_fd, buf, count); | ||
28 | if ((size != 0) && (size != count)) { | ||
29 | bb_perror_msg_and_die("Short read, read %d of %d", size, count); | ||
30 | } | ||
31 | return(size); | ||
32 | } | ||
diff --git a/busybox/archival/libunarchive/check_header_gzip.c b/busybox/archival/libunarchive/check_header_gzip.c new file mode 100644 index 000000000..13832c240 --- /dev/null +++ b/busybox/archival/libunarchive/check_header_gzip.c | |||
@@ -0,0 +1,57 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <unistd.h> | ||
3 | #include "libbb.h" | ||
4 | |||
5 | extern void check_header_gzip(int src_fd) | ||
6 | { | ||
7 | union { | ||
8 | unsigned char raw[8]; | ||
9 | struct { | ||
10 | unsigned char method; | ||
11 | unsigned char flags; | ||
12 | unsigned int mtime; | ||
13 | unsigned char xtra_flags; | ||
14 | unsigned char os_flags; | ||
15 | } formated; | ||
16 | } header; | ||
17 | |||
18 | bb_xread_all(src_fd, header.raw, 8); | ||
19 | |||
20 | /* Check the compression method */ | ||
21 | if (header.formated.method != 8) { | ||
22 | bb_error_msg_and_die("Unknown compression method %d", | ||
23 | header.formated.method); | ||
24 | } | ||
25 | |||
26 | if (header.formated.flags & 0x04) { | ||
27 | /* bit 2 set: extra field present */ | ||
28 | unsigned char extra_short; | ||
29 | |||
30 | extra_short = bb_xread_char(src_fd) + (bb_xread_char(src_fd) << 8); | ||
31 | while (extra_short > 0) { | ||
32 | /* Ignore extra field */ | ||
33 | bb_xread_char(src_fd); | ||
34 | extra_short--; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | /* Discard original name if any */ | ||
39 | if (header.formated.flags & 0x08) { | ||
40 | /* bit 3 set: original file name present */ | ||
41 | while(bb_xread_char(src_fd) != 0); | ||
42 | } | ||
43 | |||
44 | /* Discard file comment if any */ | ||
45 | if (header.formated.flags & 0x10) { | ||
46 | /* bit 4 set: file comment present */ | ||
47 | while(bb_xread_char(src_fd) != 0); | ||
48 | } | ||
49 | |||
50 | /* Read the header checksum */ | ||
51 | if (header.formated.flags & 0x02) { | ||
52 | bb_xread_char(src_fd); | ||
53 | bb_xread_char(src_fd); | ||
54 | } | ||
55 | |||
56 | return; | ||
57 | } | ||
diff --git a/busybox/archival/libunarchive/data_align.c b/busybox/archival/libunarchive/data_align.c new file mode 100644 index 000000000..1d433957d --- /dev/null +++ b/busybox/archival/libunarchive/data_align.c | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | |||
19 | #include <errno.h> | ||
20 | #include <unistd.h> | ||
21 | |||
22 | #include "libbb.h" | ||
23 | #include "unarchive.h" | ||
24 | |||
25 | extern void data_align(archive_handle_t *archive_handle, const unsigned short boundary) | ||
26 | { | ||
27 | const unsigned short skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary; | ||
28 | |||
29 | archive_handle->seek(archive_handle, skip_amount); | ||
30 | archive_handle->offset += skip_amount; | ||
31 | |||
32 | return; | ||
33 | } | ||
diff --git a/busybox/archival/libunarchive/data_extract_all.c b/busybox/archival/libunarchive/data_extract_all.c new file mode 100644 index 000000000..d10d665f6 --- /dev/null +++ b/busybox/archival/libunarchive/data_extract_all.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | |||
19 | #include <errno.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <utime.h> | ||
24 | #include <unistd.h> | ||
25 | #include <stdlib.h> | ||
26 | |||
27 | #include "libbb.h" | ||
28 | #include "unarchive.h" | ||
29 | |||
30 | extern void data_extract_all(archive_handle_t *archive_handle) | ||
31 | { | ||
32 | file_header_t *file_header = archive_handle->file_header; | ||
33 | int dst_fd; | ||
34 | int res; | ||
35 | |||
36 | if (archive_handle->flags & ARCHIVE_CREATE_LEADING_DIRS) { | ||
37 | char *name = bb_xstrdup(file_header->name); | ||
38 | bb_make_directory (dirname(name), -1, FILEUTILS_RECUR); | ||
39 | free(name); | ||
40 | } | ||
41 | |||
42 | /* Check if the file already exists */ | ||
43 | if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { | ||
44 | /* Remove the existing entry if it exists */ | ||
45 | if (((file_header->mode & S_IFMT) != S_IFDIR) && (unlink(file_header->name) == -1) && (errno != ENOENT)) { | ||
46 | bb_perror_msg_and_die("Couldnt remove old file"); | ||
47 | } | ||
48 | } | ||
49 | else if (archive_handle->flags & ARCHIVE_EXTRACT_NEWER) { | ||
50 | /* Remove the existing entry if its older than the extracted entry */ | ||
51 | struct stat statbuf; | ||
52 | if (lstat(file_header->name, &statbuf) == -1) { | ||
53 | if (errno != ENOENT) { | ||
54 | bb_perror_msg_and_die("Couldnt stat old file"); | ||
55 | } | ||
56 | } | ||
57 | else if (statbuf.st_mtime <= file_header->mtime) { | ||
58 | if (!(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { | ||
59 | bb_error_msg("%s not created: newer or same age file exists", file_header->name); | ||
60 | } | ||
61 | data_skip(archive_handle); | ||
62 | return; | ||
63 | } | ||
64 | else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { | ||
65 | bb_perror_msg_and_die("Couldnt remove old file %s", file_header->name); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | /* Handle hard links separately | ||
70 | * We identified hard links as regular files of size 0 with a symlink */ | ||
71 | if (S_ISREG(file_header->mode) && (file_header->link_name) && (file_header->size == 0)) { | ||
72 | /* hard link */ | ||
73 | res = link(file_header->link_name, file_header->name); | ||
74 | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { | ||
75 | bb_perror_msg("Couldnt create hard link"); | ||
76 | } | ||
77 | } else { | ||
78 | /* Create the filesystem entry */ | ||
79 | switch(file_header->mode & S_IFMT) { | ||
80 | case S_IFREG: { | ||
81 | /* Regular file */ | ||
82 | dst_fd = bb_xopen(file_header->name, O_WRONLY | O_CREAT | O_EXCL); | ||
83 | bb_copyfd_size(archive_handle->src_fd, dst_fd, file_header->size); | ||
84 | close(dst_fd); | ||
85 | break; | ||
86 | } | ||
87 | case S_IFDIR: | ||
88 | res = mkdir(file_header->name, file_header->mode); | ||
89 | if ((errno != EISDIR) && (res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { | ||
90 | bb_perror_msg("extract_archive: %s", file_header->name); | ||
91 | } | ||
92 | break; | ||
93 | case S_IFLNK: | ||
94 | /* Symlink */ | ||
95 | res = symlink(file_header->link_name, file_header->name); | ||
96 | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { | ||
97 | bb_perror_msg("Cannot create symlink from %s to '%s'", file_header->name, file_header->link_name); | ||
98 | } | ||
99 | break; | ||
100 | case S_IFSOCK: | ||
101 | case S_IFBLK: | ||
102 | case S_IFCHR: | ||
103 | case S_IFIFO: | ||
104 | res = mknod(file_header->name, file_header->mode, file_header->device); | ||
105 | if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) { | ||
106 | bb_perror_msg("Cannot create node %s", file_header->name); | ||
107 | } | ||
108 | break; | ||
109 | default: | ||
110 | bb_error_msg_and_die("Unrecognised file type"); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | lchown(file_header->name, file_header->uid, file_header->gid); | ||
115 | if ((file_header->mode & S_IFMT) != S_IFLNK) { | ||
116 | chmod(file_header->name, file_header->mode); | ||
117 | } | ||
118 | |||
119 | if (archive_handle->flags & ARCHIVE_PRESERVE_DATE) { | ||
120 | struct utimbuf t; | ||
121 | t.actime = t.modtime = file_header->mtime; | ||
122 | utime(file_header->name, &t); | ||
123 | } | ||
124 | } | ||
diff --git a/busybox/archival/libunarchive/data_extract_to_buffer.c b/busybox/archival/libunarchive/data_extract_to_buffer.c new file mode 100644 index 000000000..db5521bcb --- /dev/null +++ b/busybox/archival/libunarchive/data_extract_to_buffer.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include "libbb.h" | ||
18 | #include "unarchive.h" | ||
19 | |||
20 | extern void data_extract_to_buffer(archive_handle_t *archive_handle) | ||
21 | { | ||
22 | const unsigned int size = archive_handle->file_header->size; | ||
23 | |||
24 | archive_handle->buffer = xmalloc(size + 1); | ||
25 | |||
26 | archive_xread_all(archive_handle, archive_handle->buffer, size); | ||
27 | archive_handle->buffer[size] = '\0'; | ||
28 | } | ||
diff --git a/busybox/archival/libunarchive/data_extract_to_stdout.c b/busybox/archival/libunarchive/data_extract_to_stdout.c new file mode 100644 index 000000000..df2bca6ef --- /dev/null +++ b/busybox/archival/libunarchive/data_extract_to_stdout.c | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include "unarchive.h" | ||
18 | #include <unistd.h> | ||
19 | |||
20 | extern void data_extract_to_stdout(archive_handle_t *archive_handle) | ||
21 | { | ||
22 | bb_copyfd_size(archive_handle->src_fd, STDOUT_FILENO, archive_handle->file_header->size); | ||
23 | } | ||
diff --git a/busybox/archival/libunarchive/data_skip.c b/busybox/archival/libunarchive/data_skip.c new file mode 100644 index 000000000..b82c9065b --- /dev/null +++ b/busybox/archival/libunarchive/data_skip.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | #include <errno.h> | ||
19 | #include <unistd.h> | ||
20 | #include <stdlib.h> | ||
21 | #include "unarchive.h" | ||
22 | #include "libbb.h" | ||
23 | |||
24 | extern void data_skip(archive_handle_t *archive_handle) | ||
25 | { | ||
26 | archive_handle->seek(archive_handle, archive_handle->file_header->size); | ||
27 | } | ||
diff --git a/busybox/archival/libunarchive/decompress_bunzip2.c b/busybox/archival/libunarchive/decompress_bunzip2.c new file mode 100644 index 000000000..259a47776 --- /dev/null +++ b/busybox/archival/libunarchive/decompress_bunzip2.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). | ||
3 | |||
4 | Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), | ||
5 | which also acknowledges contributions by Mike Burrows, David Wheeler, | ||
6 | Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, | ||
7 | Robert Sedgewick, and Jon L. Bentley. | ||
8 | |||
9 | This code is licensed under the LGPLv2: | ||
10 | LGPL (http://www.gnu.org/copyleft/lgpl.html | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org). | ||
15 | |||
16 | More efficient reading of Huffman codes, a streamlined read_bunzip() | ||
17 | function, and various other tweaks. In (limited) tests, approximately | ||
18 | 20% faster than bzcat on x86 and about 10% faster on arm. | ||
19 | |||
20 | Note that about 2/3 of the time is spent in read_unzip() reversing | ||
21 | the Burrows-Wheeler transformation. Much of that time is delay | ||
22 | resulting from cache misses. | ||
23 | |||
24 | I would ask that anyone benefiting from this work, especially those | ||
25 | using it in commercial products, consider making a donation to my local | ||
26 | non-profit hospice organization in the name of the woman I loved, who | ||
27 | passed away Feb. 12, 2003. | ||
28 | |||
29 | In memory of Toni W. Hagan | ||
30 | |||
31 | Hospice of Acadiana, Inc. | ||
32 | 2600 Johnston St., Suite 200 | ||
33 | Lafayette, LA 70503-3240 | ||
34 | |||
35 | Phone (337) 232-1234 or 1-800-738-2226 | ||
36 | Fax (337) 232-1297 | ||
37 | |||
38 | http://www.hospiceacadiana.com/ | ||
39 | |||
40 | Manuel | ||
41 | */ | ||
42 | |||
43 | #include <setjmp.h> | ||
44 | #include <stdio.h> | ||
45 | #include <stdlib.h> | ||
46 | #include <string.h> | ||
47 | #include <unistd.h> | ||
48 | #include <limits.h> | ||
49 | |||
50 | #include "libbb.h" | ||
51 | |||
52 | /* Constants for Huffman coding */ | ||
53 | #define MAX_GROUPS 6 | ||
54 | #define GROUP_SIZE 50 /* 64 would have been more efficient */ | ||
55 | #define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */ | ||
56 | #define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */ | ||
57 | #define SYMBOL_RUNA 0 | ||
58 | #define SYMBOL_RUNB 1 | ||
59 | |||
60 | /* Status return values */ | ||
61 | #define RETVAL_OK 0 | ||
62 | #define RETVAL_LAST_BLOCK (-1) | ||
63 | #define RETVAL_NOT_BZIP_DATA (-2) | ||
64 | #define RETVAL_UNEXPECTED_INPUT_EOF (-3) | ||
65 | #define RETVAL_UNEXPECTED_OUTPUT_EOF (-4) | ||
66 | #define RETVAL_DATA_ERROR (-5) | ||
67 | #define RETVAL_OUT_OF_MEMORY (-6) | ||
68 | #define RETVAL_OBSOLETE_INPUT (-7) | ||
69 | |||
70 | /* Other housekeeping constants */ | ||
71 | #define IOBUF_SIZE 4096 | ||
72 | |||
73 | /* This is what we know about each Huffman coding group */ | ||
74 | struct group_data { | ||
75 | /* We have an extra slot at the end of limit[] for a sentinal value. */ | ||
76 | int limit[MAX_HUFCODE_BITS+1],base[MAX_HUFCODE_BITS],permute[MAX_SYMBOLS]; | ||
77 | int minLen, maxLen; | ||
78 | }; | ||
79 | |||
80 | /* Structure holding all the housekeeping data, including IO buffers and | ||
81 | memory that persists between calls to bunzip */ | ||
82 | typedef struct { | ||
83 | /* State for interrupting output loop */ | ||
84 | int writeCopies,writePos,writeRunCountdown,writeCount,writeCurrent; | ||
85 | /* I/O tracking data (file handles, buffers, positions, etc.) */ | ||
86 | int in_fd,out_fd,inbufCount,inbufPos /*,outbufPos*/; | ||
87 | unsigned char *inbuf /*,*outbuf*/; | ||
88 | unsigned int inbufBitCount, inbufBits; | ||
89 | /* The CRC values stored in the block header and calculated from the data */ | ||
90 | unsigned int crc32Table[256],headerCRC, totalCRC, writeCRC; | ||
91 | /* Intermediate buffer and its size (in bytes) */ | ||
92 | unsigned int *dbuf, dbufSize; | ||
93 | /* These things are a bit too big to go on the stack */ | ||
94 | unsigned char selectors[32768]; /* nSelectors=15 bits */ | ||
95 | struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ | ||
96 | /* For I/O error handling */ | ||
97 | jmp_buf jmpbuf; | ||
98 | } bunzip_data; | ||
99 | |||
100 | /* Return the next nnn bits of input. All reads from the compressed input | ||
101 | are done through this function. All reads are big endian */ | ||
102 | static unsigned int get_bits(bunzip_data *bd, char bits_wanted) | ||
103 | { | ||
104 | unsigned int bits=0; | ||
105 | |||
106 | /* If we need to get more data from the byte buffer, do so. (Loop getting | ||
107 | one byte at a time to enforce endianness and avoid unaligned access.) */ | ||
108 | while (bd->inbufBitCount<bits_wanted) { | ||
109 | /* If we need to read more data from file into byte buffer, do so */ | ||
110 | if(bd->inbufPos==bd->inbufCount) { | ||
111 | if((bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE)) <= 0) | ||
112 | longjmp(bd->jmpbuf,RETVAL_UNEXPECTED_INPUT_EOF); | ||
113 | bd->inbufPos=0; | ||
114 | } | ||
115 | /* Avoid 32-bit overflow (dump bit buffer to top of output) */ | ||
116 | if(bd->inbufBitCount>=24) { | ||
117 | bits=bd->inbufBits&((1<<bd->inbufBitCount)-1); | ||
118 | bits_wanted-=bd->inbufBitCount; | ||
119 | bits<<=bits_wanted; | ||
120 | bd->inbufBitCount=0; | ||
121 | } | ||
122 | /* Grab next 8 bits of input from buffer. */ | ||
123 | bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++]; | ||
124 | bd->inbufBitCount+=8; | ||
125 | } | ||
126 | /* Calculate result */ | ||
127 | bd->inbufBitCount-=bits_wanted; | ||
128 | bits|=(bd->inbufBits>>bd->inbufBitCount)&((1<<bits_wanted)-1); | ||
129 | |||
130 | return bits; | ||
131 | } | ||
132 | |||
133 | /* Unpacks the next block and sets up for the inverse burrows-wheeler step. */ | ||
134 | |||
135 | static int get_next_block(bunzip_data *bd) | ||
136 | { | ||
137 | /* Note: Ignore the warning about hufGroup, base and limit being used uninitialized. | ||
138 | * They will be initialized on the fist pass of the loop. */ | ||
139 | struct group_data *hufGroup; | ||
140 | int dbufCount,nextSym,dbufSize,groupCount,*base,*limit,selector, | ||
141 | i,j,k,t,runPos,symCount,symTotal,nSelectors,byteCount[256]; | ||
142 | unsigned char uc, symToByte[256], mtfSymbol[256], *selectors; | ||
143 | unsigned int *dbuf,origPtr; | ||
144 | |||
145 | dbuf=bd->dbuf; | ||
146 | dbufSize=bd->dbufSize; | ||
147 | selectors=bd->selectors; | ||
148 | /* Reset longjmp I/O error handling */ | ||
149 | i=setjmp(bd->jmpbuf); | ||
150 | if(i) return i; | ||
151 | /* Read in header signature and CRC, then validate signature. | ||
152 | (last block signature means CRC is for whole file, return now) */ | ||
153 | i = get_bits(bd,24); | ||
154 | j = get_bits(bd,24); | ||
155 | bd->headerCRC=get_bits(bd,32); | ||
156 | if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK; | ||
157 | if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA; | ||
158 | /* We can add support for blockRandomised if anybody complains. There was | ||
159 | some code for this in busybox 1.0.0-pre3, but nobody ever noticed that | ||
160 | it didn't actually work. */ | ||
161 | if(get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT; | ||
162 | if((origPtr=get_bits(bd,24)) > dbufSize) return RETVAL_DATA_ERROR; | ||
163 | /* mapping table: if some byte values are never used (encoding things | ||
164 | like ascii text), the compression code removes the gaps to have fewer | ||
165 | symbols to deal with, and writes a sparse bitfield indicating which | ||
166 | values were present. We make a translation table to convert the symbols | ||
167 | back to the corresponding bytes. */ | ||
168 | t=get_bits(bd, 16); | ||
169 | symTotal=0; | ||
170 | for (i=0;i<16;i++) { | ||
171 | if(t&(1<<(15-i))) { | ||
172 | k=get_bits(bd,16); | ||
173 | for(j=0;j<16;j++) | ||
174 | if(k&(1<<(15-j))) symToByte[symTotal++]=(16*i)+j; | ||
175 | } | ||
176 | } | ||
177 | /* How many different Huffman coding groups does this block use? */ | ||
178 | groupCount=get_bits(bd,3); | ||
179 | if (groupCount<2 || groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR; | ||
180 | /* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding | ||
181 | group. Read in the group selector list, which is stored as MTF encoded | ||
182 | bit runs. (MTF=Move To Front, as each value is used it's moved to the | ||
183 | start of the list.) */ | ||
184 | if(!(nSelectors=get_bits(bd, 15))) return RETVAL_DATA_ERROR; | ||
185 | for(i=0; i<groupCount; i++) mtfSymbol[i] = i; | ||
186 | for(i=0; i<nSelectors; i++) { | ||
187 | /* Get next value */ | ||
188 | for(j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR; | ||
189 | /* Decode MTF to get the next selector */ | ||
190 | uc = mtfSymbol[j]; | ||
191 | for(;j;j--) mtfSymbol[j] = mtfSymbol[j-1]; | ||
192 | mtfSymbol[0]=selectors[i]=uc; | ||
193 | } | ||
194 | /* Read the Huffman coding tables for each group, which code for symTotal | ||
195 | literal symbols, plus two run symbols (RUNA, RUNB) */ | ||
196 | symCount=symTotal+2; | ||
197 | for (j=0; j<groupCount; j++) { | ||
198 | unsigned char length[MAX_SYMBOLS],temp[MAX_HUFCODE_BITS+1]; | ||
199 | int minLen, maxLen, pp; | ||
200 | /* Read Huffman code lengths for each symbol. They're stored in | ||
201 | a way similar to mtf; record a starting value for the first symbol, | ||
202 | and an offset from the previous value for everys symbol after that. | ||
203 | (Subtracting 1 before the loop and then adding it back at the end is | ||
204 | an optimization that makes the test inside the loop simpler: symbol | ||
205 | length 0 becomes negative, so an unsigned inequality catches it.) */ | ||
206 | t=get_bits(bd, 5)-1; | ||
207 | for (i = 0; i < symCount; i++) { | ||
208 | for(;;) { | ||
209 | if (((unsigned)t) > (MAX_HUFCODE_BITS-1)) | ||
210 | return RETVAL_DATA_ERROR; | ||
211 | /* If first bit is 0, stop. Else second bit indicates whether | ||
212 | to increment or decrement the value. Optimization: grab 2 | ||
213 | bits and unget the second if the first was 0. */ | ||
214 | k = get_bits(bd,2); | ||
215 | if (k < 2) { | ||
216 | bd->inbufBitCount++; | ||
217 | break; | ||
218 | } | ||
219 | /* Add one if second bit 1, else subtract 1. Avoids if/else */ | ||
220 | t+=(((k+1)&2)-1); | ||
221 | } | ||
222 | /* Correct for the initial -1, to get the final symbol length */ | ||
223 | length[i]=t+1; | ||
224 | } | ||
225 | /* Find largest and smallest lengths in this group */ | ||
226 | minLen=maxLen=length[0]; | ||
227 | for(i = 1; i < symCount; i++) { | ||
228 | if(length[i] > maxLen) maxLen = length[i]; | ||
229 | else if(length[i] < minLen) minLen = length[i]; | ||
230 | } | ||
231 | /* Calculate permute[], base[], and limit[] tables from length[]. | ||
232 | * | ||
233 | * permute[] is the lookup table for converting Huffman coded symbols | ||
234 | * into decoded symbols. base[] is the amount to subtract from the | ||
235 | * value of a Huffman symbol of a given length when using permute[]. | ||
236 | * | ||
237 | * limit[] indicates the largest numerical value a symbol with a given | ||
238 | * number of bits can have. This is how the Huffman codes can vary in | ||
239 | * length: each code with a value>limit[length] needs another bit. | ||
240 | */ | ||
241 | hufGroup=bd->groups+j; | ||
242 | hufGroup->minLen = minLen; | ||
243 | hufGroup->maxLen = maxLen; | ||
244 | /* Note that minLen can't be smaller than 1, so we adjust the base | ||
245 | and limit array pointers so we're not always wasting the first | ||
246 | entry. We do this again when using them (during symbol decoding).*/ | ||
247 | base=hufGroup->base-1; | ||
248 | limit=hufGroup->limit-1; | ||
249 | /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ | ||
250 | pp=0; | ||
251 | for(i=minLen;i<=maxLen;i++) { | ||
252 | temp[i]=limit[i]=0; | ||
253 | for(t=0;t<symCount;t++) | ||
254 | if(length[t]==i) hufGroup->permute[pp++] = t; | ||
255 | } | ||
256 | /* Count symbols coded for at each bit length */ | ||
257 | for (i=0;i<symCount;i++) temp[length[i]]++; | ||
258 | /* Calculate limit[] (the largest symbol-coding value at each bit | ||
259 | * length, which is (previous limit<<1)+symbols at this level), and | ||
260 | * base[] (number of symbols to ignore at each bit length, which is | ||
261 | * limit minus the cumulative count of symbols coded for already). */ | ||
262 | pp=t=0; | ||
263 | for (i=minLen; i<maxLen; i++) { | ||
264 | pp+=temp[i]; | ||
265 | /* We read the largest possible symbol size and then unget bits | ||
266 | after determining how many we need, and those extra bits could | ||
267 | be set to anything. (They're noise from future symbols.) At | ||
268 | each level we're really only interested in the first few bits, | ||
269 | so here we set all the trailing to-be-ignored bits to 1 so they | ||
270 | don't affect the value>limit[length] comparison. */ | ||
271 | limit[i]= (pp << (maxLen - i)) - 1; | ||
272 | pp<<=1; | ||
273 | base[i+1]=pp-(t+=temp[i]); | ||
274 | } | ||
275 | limit[maxLen+1] = INT_MAX; /* Sentinal value for reading next sym. */ | ||
276 | limit[maxLen]=pp+temp[maxLen]-1; | ||
277 | base[minLen]=0; | ||
278 | } | ||
279 | /* We've finished reading and digesting the block header. Now read this | ||
280 | block's Huffman coded symbols from the file and undo the Huffman coding | ||
281 | and run length encoding, saving the result into dbuf[dbufCount++]=uc */ | ||
282 | |||
283 | /* Initialize symbol occurrence counters and symbol Move To Front table */ | ||
284 | for(i=0;i<256;i++) { | ||
285 | byteCount[i] = 0; | ||
286 | mtfSymbol[i]=(unsigned char)i; | ||
287 | } | ||
288 | /* Loop through compressed symbols. */ | ||
289 | runPos=dbufCount=symCount=selector=0; | ||
290 | for(;;) { | ||
291 | /* Determine which Huffman coding group to use. */ | ||
292 | if(!(symCount--)) { | ||
293 | symCount=GROUP_SIZE-1; | ||
294 | if(selector>=nSelectors) return RETVAL_DATA_ERROR; | ||
295 | hufGroup=bd->groups+selectors[selector++]; | ||
296 | base=hufGroup->base-1; | ||
297 | limit=hufGroup->limit-1; | ||
298 | } | ||
299 | /* Read next Huffman-coded symbol. */ | ||
300 | /* Note: It is far cheaper to read maxLen bits and back up than it is | ||
301 | to read minLen bits and then an additional bit at a time, testing | ||
302 | as we go. Because there is a trailing last block (with file CRC), | ||
303 | there is no danger of the overread causing an unexpected EOF for a | ||
304 | valid compressed file. As a further optimization, we do the read | ||
305 | inline (falling back to a call to get_bits if the buffer runs | ||
306 | dry). The following (up to got_huff_bits:) is equivalent to | ||
307 | j=get_bits(bd,hufGroup->maxLen); | ||
308 | */ | ||
309 | while (bd->inbufBitCount<hufGroup->maxLen) { | ||
310 | if(bd->inbufPos==bd->inbufCount) { | ||
311 | j = get_bits(bd,hufGroup->maxLen); | ||
312 | goto got_huff_bits; | ||
313 | } | ||
314 | bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++]; | ||
315 | bd->inbufBitCount+=8; | ||
316 | }; | ||
317 | bd->inbufBitCount-=hufGroup->maxLen; | ||
318 | j = (bd->inbufBits>>bd->inbufBitCount)&((1<<hufGroup->maxLen)-1); | ||
319 | got_huff_bits: | ||
320 | /* Figure how how many bits are in next symbol and unget extras */ | ||
321 | i=hufGroup->minLen; | ||
322 | while(j>limit[i]) ++i; | ||
323 | bd->inbufBitCount += (hufGroup->maxLen - i); | ||
324 | /* Huffman decode value to get nextSym (with bounds checking) */ | ||
325 | if ((i > hufGroup->maxLen) | ||
326 | || (((unsigned)(j=(j>>(hufGroup->maxLen-i))-base[i])) | ||
327 | >= MAX_SYMBOLS)) | ||
328 | return RETVAL_DATA_ERROR; | ||
329 | nextSym = hufGroup->permute[j]; | ||
330 | /* We have now decoded the symbol, which indicates either a new literal | ||
331 | byte, or a repeated run of the most recent literal byte. First, | ||
332 | check if nextSym indicates a repeated run, and if so loop collecting | ||
333 | how many times to repeat the last literal. */ | ||
334 | if (((unsigned)nextSym) <= SYMBOL_RUNB) { /* RUNA or RUNB */ | ||
335 | /* If this is the start of a new run, zero out counter */ | ||
336 | if(!runPos) { | ||
337 | runPos = 1; | ||
338 | t = 0; | ||
339 | } | ||
340 | /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at | ||
341 | each bit position, add 1 or 2 instead. For example, | ||
342 | 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. | ||
343 | You can make any bit pattern that way using 1 less symbol than | ||
344 | the basic or 0/1 method (except all bits 0, which would use no | ||
345 | symbols, but a run of length 0 doesn't mean anything in this | ||
346 | context). Thus space is saved. */ | ||
347 | t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ | ||
348 | runPos <<= 1; | ||
349 | continue; | ||
350 | } | ||
351 | /* When we hit the first non-run symbol after a run, we now know | ||
352 | how many times to repeat the last literal, so append that many | ||
353 | copies to our buffer of decoded symbols (dbuf) now. (The last | ||
354 | literal used is the one at the head of the mtfSymbol array.) */ | ||
355 | if(runPos) { | ||
356 | runPos=0; | ||
357 | if(dbufCount+t>=dbufSize) return RETVAL_DATA_ERROR; | ||
358 | |||
359 | uc = symToByte[mtfSymbol[0]]; | ||
360 | byteCount[uc] += t; | ||
361 | while(t--) dbuf[dbufCount++]=uc; | ||
362 | } | ||
363 | /* Is this the terminating symbol? */ | ||
364 | if(nextSym>symTotal) break; | ||
365 | /* At this point, nextSym indicates a new literal character. Subtract | ||
366 | one to get the position in the MTF array at which this literal is | ||
367 | currently to be found. (Note that the result can't be -1 or 0, | ||
368 | because 0 and 1 are RUNA and RUNB. But another instance of the | ||
369 | first symbol in the mtf array, position 0, would have been handled | ||
370 | as part of a run above. Therefore 1 unused mtf position minus | ||
371 | 2 non-literal nextSym values equals -1.) */ | ||
372 | if(dbufCount>=dbufSize) return RETVAL_DATA_ERROR; | ||
373 | i = nextSym - 1; | ||
374 | uc = mtfSymbol[i]; | ||
375 | /* Adjust the MTF array. Since we typically expect to move only a | ||
376 | * small number of symbols, and are bound by 256 in any case, using | ||
377 | * memmove here would typically be bigger and slower due to function | ||
378 | * call overhead and other assorted setup costs. */ | ||
379 | do { | ||
380 | mtfSymbol[i] = mtfSymbol[i-1]; | ||
381 | } while (--i); | ||
382 | mtfSymbol[0] = uc; | ||
383 | uc=symToByte[uc]; | ||
384 | /* We have our literal byte. Save it into dbuf. */ | ||
385 | byteCount[uc]++; | ||
386 | dbuf[dbufCount++] = (unsigned int)uc; | ||
387 | } | ||
388 | /* At this point, we've read all the Huffman-coded symbols (and repeated | ||
389 | runs) for this block from the input stream, and decoded them into the | ||
390 | intermediate buffer. There are dbufCount many decoded bytes in dbuf[]. | ||
391 | Now undo the Burrows-Wheeler transform on dbuf. | ||
392 | See http://dogma.net/markn/articles/bwt/bwt.htm | ||
393 | */ | ||
394 | /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ | ||
395 | j=0; | ||
396 | for(i=0;i<256;i++) { | ||
397 | k=j+byteCount[i]; | ||
398 | byteCount[i] = j; | ||
399 | j=k; | ||
400 | } | ||
401 | /* Figure out what order dbuf would be in if we sorted it. */ | ||
402 | for (i=0;i<dbufCount;i++) { | ||
403 | uc=(unsigned char)(dbuf[i] & 0xff); | ||
404 | dbuf[byteCount[uc]] |= (i << 8); | ||
405 | byteCount[uc]++; | ||
406 | } | ||
407 | /* Decode first byte by hand to initialize "previous" byte. Note that it | ||
408 | doesn't get output, and if the first three characters are identical | ||
409 | it doesn't qualify as a run (hence writeRunCountdown=5). */ | ||
410 | if(dbufCount) { | ||
411 | if(origPtr>=dbufCount) return RETVAL_DATA_ERROR; | ||
412 | bd->writePos=dbuf[origPtr]; | ||
413 | bd->writeCurrent=(unsigned char)(bd->writePos&0xff); | ||
414 | bd->writePos>>=8; | ||
415 | bd->writeRunCountdown=5; | ||
416 | } | ||
417 | bd->writeCount=dbufCount; | ||
418 | |||
419 | return RETVAL_OK; | ||
420 | } | ||
421 | |||
422 | /* Undo burrows-wheeler transform on intermediate buffer to produce output. | ||
423 | If start_bunzip was initialized with out_fd=-1, then up to len bytes of | ||
424 | data are written to outbuf. Return value is number of bytes written or | ||
425 | error (all errors are negative numbers). If out_fd!=-1, outbuf and len | ||
426 | are ignored, data is written to out_fd and return is RETVAL_OK or error. | ||
427 | */ | ||
428 | |||
429 | static int read_bunzip(bunzip_data *bd, char *outbuf, int len) | ||
430 | { | ||
431 | const unsigned int *dbuf; | ||
432 | int pos,current,previous,gotcount; | ||
433 | |||
434 | /* If last read was short due to end of file, return last block now */ | ||
435 | if(bd->writeCount<0) return bd->writeCount; | ||
436 | |||
437 | gotcount = 0; | ||
438 | dbuf=bd->dbuf; | ||
439 | pos=bd->writePos; | ||
440 | current=bd->writeCurrent; | ||
441 | |||
442 | /* We will always have pending decoded data to write into the output | ||
443 | buffer unless this is the very first call (in which case we haven't | ||
444 | Huffman-decoded a block into the intermediate buffer yet). */ | ||
445 | |||
446 | if (bd->writeCopies) { | ||
447 | /* Inside the loop, writeCopies means extra copies (beyond 1) */ | ||
448 | --bd->writeCopies; | ||
449 | /* Loop outputting bytes */ | ||
450 | for(;;) { | ||
451 | /* If the output buffer is full, snapshot state and return */ | ||
452 | if(gotcount >= len) { | ||
453 | bd->writePos=pos; | ||
454 | bd->writeCurrent=current; | ||
455 | bd->writeCopies++; | ||
456 | return len; | ||
457 | } | ||
458 | /* Write next byte into output buffer, updating CRC */ | ||
459 | outbuf[gotcount++] = current; | ||
460 | bd->writeCRC=(((bd->writeCRC)<<8) | ||
461 | ^bd->crc32Table[((bd->writeCRC)>>24)^current]); | ||
462 | /* Loop now if we're outputting multiple copies of this byte */ | ||
463 | if (bd->writeCopies) { | ||
464 | --bd->writeCopies; | ||
465 | continue; | ||
466 | } | ||
467 | decode_next_byte: | ||
468 | if (!bd->writeCount--) break; | ||
469 | /* Follow sequence vector to undo Burrows-Wheeler transform */ | ||
470 | previous=current; | ||
471 | pos=dbuf[pos]; | ||
472 | current=pos&0xff; | ||
473 | pos>>=8; | ||
474 | /* After 3 consecutive copies of the same byte, the 4th is a repeat | ||
475 | count. We count down from 4 instead | ||
476 | * of counting up because testing for non-zero is faster */ | ||
477 | if(--bd->writeRunCountdown) { | ||
478 | if(current!=previous) bd->writeRunCountdown=4; | ||
479 | } else { | ||
480 | /* We have a repeated run, this byte indicates the count */ | ||
481 | bd->writeCopies=current; | ||
482 | current=previous; | ||
483 | bd->writeRunCountdown=5; | ||
484 | /* Sometimes there are just 3 bytes (run length 0) */ | ||
485 | if(!bd->writeCopies) goto decode_next_byte; | ||
486 | /* Subtract the 1 copy we'd output anyway to get extras */ | ||
487 | --bd->writeCopies; | ||
488 | } | ||
489 | } | ||
490 | /* Decompression of this block completed successfully */ | ||
491 | bd->writeCRC=~bd->writeCRC; | ||
492 | bd->totalCRC=((bd->totalCRC<<1) | (bd->totalCRC>>31)) ^ bd->writeCRC; | ||
493 | /* If this block had a CRC error, force file level CRC error. */ | ||
494 | if(bd->writeCRC!=bd->headerCRC) { | ||
495 | bd->totalCRC=bd->headerCRC+1; | ||
496 | return RETVAL_LAST_BLOCK; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | /* Refill the intermediate buffer by Huffman-decoding next block of input */ | ||
501 | /* (previous is just a convenient unused temp variable here) */ | ||
502 | previous=get_next_block(bd); | ||
503 | if(previous) { | ||
504 | bd->writeCount=previous; | ||
505 | return (previous!=RETVAL_LAST_BLOCK) ? previous : gotcount; | ||
506 | } | ||
507 | bd->writeCRC=0xffffffffUL; | ||
508 | pos=bd->writePos; | ||
509 | current=bd->writeCurrent; | ||
510 | goto decode_next_byte; | ||
511 | } | ||
512 | |||
513 | /* Allocate the structure, read file header. If in_fd==-1, inbuf must contain | ||
514 | a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are | ||
515 | ignored, and data is read from file handle into temporary buffer. */ | ||
516 | static int start_bunzip(bunzip_data **bdp, int in_fd, char *inbuf, int len) | ||
517 | { | ||
518 | bunzip_data *bd; | ||
519 | unsigned int i,j,c; | ||
520 | const unsigned int BZh0=(((unsigned int)'B')<<24)+(((unsigned int)'Z')<<16) | ||
521 | +(((unsigned int)'h')<<8)+(unsigned int)'0'; | ||
522 | |||
523 | /* Figure out how much data to allocate */ | ||
524 | i=sizeof(bunzip_data); | ||
525 | if(in_fd!=-1) i+=IOBUF_SIZE; | ||
526 | /* Allocate bunzip_data. Most fields initialize to zero. */ | ||
527 | bd=*bdp=xmalloc(i); | ||
528 | memset(bd,0,sizeof(bunzip_data)); | ||
529 | /* Setup input buffer */ | ||
530 | if(-1==(bd->in_fd=in_fd)) { | ||
531 | bd->inbuf=inbuf; | ||
532 | bd->inbufCount=len; | ||
533 | } else bd->inbuf=(unsigned char *)(bd+1); | ||
534 | /* Init the CRC32 table (big endian) */ | ||
535 | for(i=0;i<256;i++) { | ||
536 | c=i<<24; | ||
537 | for(j=8;j;j--) | ||
538 | c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); | ||
539 | bd->crc32Table[i]=c; | ||
540 | } | ||
541 | /* Setup for I/O error handling via longjmp */ | ||
542 | i=setjmp(bd->jmpbuf); | ||
543 | if(i) return i; | ||
544 | |||
545 | /* Ensure that file starts with "BZh['1'-'9']." */ | ||
546 | i = get_bits(bd,32); | ||
547 | if (((unsigned int)(i-BZh0-1)) >= 9) return RETVAL_NOT_BZIP_DATA; | ||
548 | |||
549 | /* Fourth byte (ascii '1'-'9'), indicates block size in units of 100k of | ||
550 | uncompressed data. Allocate intermediate buffer for block. */ | ||
551 | bd->dbufSize=100000*(i-BZh0); | ||
552 | |||
553 | bd->dbuf=xmalloc(bd->dbufSize * sizeof(int)); | ||
554 | return RETVAL_OK; | ||
555 | } | ||
556 | |||
557 | /* Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, | ||
558 | not end of file.) */ | ||
559 | extern int uncompressStream(int src_fd, int dst_fd) | ||
560 | { | ||
561 | char *outbuf; | ||
562 | bunzip_data *bd; | ||
563 | int i; | ||
564 | |||
565 | outbuf=xmalloc(IOBUF_SIZE); | ||
566 | if(!(i=start_bunzip(&bd,src_fd,0,0))) { | ||
567 | for(;;) { | ||
568 | if((i=read_bunzip(bd,outbuf,IOBUF_SIZE)) <= 0) break; | ||
569 | if(i!=write(dst_fd,outbuf,i)) { | ||
570 | i=RETVAL_UNEXPECTED_OUTPUT_EOF; | ||
571 | break; | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | /* Check CRC and release memory */ | ||
576 | if(i==RETVAL_LAST_BLOCK) { | ||
577 | if (bd->headerCRC!=bd->totalCRC) { | ||
578 | bb_error_msg("Data integrity error when decompressing."); | ||
579 | } else { | ||
580 | i=RETVAL_OK; | ||
581 | } | ||
582 | } | ||
583 | else if (i==RETVAL_UNEXPECTED_OUTPUT_EOF) { | ||
584 | bb_error_msg("Compressed file ends unexpectedly"); | ||
585 | } else { | ||
586 | bb_error_msg("Decompression failed"); | ||
587 | } | ||
588 | if(bd->dbuf) free(bd->dbuf); | ||
589 | free(bd); | ||
590 | free(outbuf); | ||
591 | |||
592 | return i; | ||
593 | } | ||
594 | |||
595 | #ifdef TESTING | ||
596 | |||
597 | static char * const bunzip_errors[]={NULL,"Bad file checksum","Not bzip data", | ||
598 | "Unexpected input EOF","Unexpected output EOF","Data error", | ||
599 | "Out of memory","Obsolete (pre 0.9.5) bzip format not supported."}; | ||
600 | |||
601 | /* Dumb little test thing, decompress stdin to stdout */ | ||
602 | int main(int argc, char *argv[]) | ||
603 | { | ||
604 | int i=uncompressStream(0,1); | ||
605 | char c; | ||
606 | |||
607 | if(i) fprintf(stderr,"%s\n", bunzip_errors[-i]); | ||
608 | else if(read(0,&c,1)) fprintf(stderr,"Trailing garbage ignored\n"); | ||
609 | return -i; | ||
610 | } | ||
611 | #endif | ||
diff --git a/busybox/archival/libunarchive/decompress_uncompress.c b/busybox/archival/libunarchive/decompress_uncompress.c new file mode 100644 index 000000000..e39872cbe --- /dev/null +++ b/busybox/archival/libunarchive/decompress_uncompress.c | |||
@@ -0,0 +1,293 @@ | |||
1 | #include "config.h" | ||
2 | #include "libbb.h" | ||
3 | |||
4 | /* uncompress for busybox -- (c) 2002 Robert Griebl | ||
5 | * | ||
6 | * based on the original compress42.c source | ||
7 | * (see disclaimer below) | ||
8 | */ | ||
9 | |||
10 | |||
11 | /* (N)compress42.c - File compression ala IEEE Computer, Mar 1992. | ||
12 | * | ||
13 | * Authors: | ||
14 | * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) | ||
15 | * Jim McKie (decvax!mcvax!jim) | ||
16 | * Steve Davies (decvax!vax135!petsd!peora!srd) | ||
17 | * Ken Turkowski (decvax!decwrl!turtlevax!ken) | ||
18 | * James A. Woods (decvax!ihnp4!ames!jaw) | ||
19 | * Joe Orost (decvax!vax135!petsd!joe) | ||
20 | * Dave Mack (csu@alembic.acs.com) | ||
21 | * Peter Jannesen, Network Communication Systems | ||
22 | * (peter@ncs.nl) | ||
23 | * | ||
24 | * marc@suse.de : a small security fix for a buffer overflow | ||
25 | * | ||
26 | * [... History snipped ...] | ||
27 | * | ||
28 | */ | ||
29 | #include <stdio.h> | ||
30 | #include <string.h> | ||
31 | #include <unistd.h> | ||
32 | |||
33 | /* Default input buffer size */ | ||
34 | #define IBUFSIZ 2048 | ||
35 | |||
36 | /* Default output buffer size */ | ||
37 | #define OBUFSIZ 2048 | ||
38 | |||
39 | /* Defines for third byte of header */ | ||
40 | #define MAGIC_1 (char_type)'\037' /* First byte of compressed file */ | ||
41 | #define MAGIC_2 (char_type)'\235' /* Second byte of compressed file */ | ||
42 | #define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ | ||
43 | /* Masks 0x20 and 0x40 are free. */ | ||
44 | /* I think 0x20 should mean that there is */ | ||
45 | /* a fourth header byte (for expansion). */ | ||
46 | #define BLOCK_MODE 0x80 /* Block compresssion if table is full and */ | ||
47 | /* compression rate is dropping flush tables */ | ||
48 | /* the next two codes should not be changed lightly, as they must not */ | ||
49 | /* lie within the contiguous general code space. */ | ||
50 | #define FIRST 257 /* first free entry */ | ||
51 | #define CLEAR 256 /* table clear output code */ | ||
52 | |||
53 | #define INIT_BITS 9 /* initial number of bits/code */ | ||
54 | |||
55 | |||
56 | /* machine variants which require cc -Dmachine: pdp11, z8000, DOS */ | ||
57 | #define FAST | ||
58 | |||
59 | #define HBITS 17 /* 50% occupancy */ | ||
60 | #define HSIZE (1<<HBITS) | ||
61 | #define HMASK (HSIZE-1) | ||
62 | #define HPRIME 9941 | ||
63 | #define BITS 16 | ||
64 | #undef MAXSEG_64K | ||
65 | #define MAXCODE(n) (1L << (n)) | ||
66 | |||
67 | /* Block compress mode -C compatible with 2.0 */ | ||
68 | int block_mode = BLOCK_MODE; | ||
69 | |||
70 | /* user settable max # bits/code */ | ||
71 | int maxbits = BITS; | ||
72 | |||
73 | /* Exitcode of compress (-1 no file compressed) */ | ||
74 | int exit_code = -1; | ||
75 | |||
76 | /* Input buffer */ | ||
77 | unsigned char inbuf[IBUFSIZ + 64]; | ||
78 | |||
79 | /* Output buffer */ | ||
80 | unsigned char outbuf[OBUFSIZ + 2048]; | ||
81 | |||
82 | |||
83 | long int htab[HSIZE]; | ||
84 | unsigned short codetab[HSIZE]; | ||
85 | |||
86 | #define htabof(i) htab[i] | ||
87 | #define codetabof(i) codetab[i] | ||
88 | #define tab_prefixof(i) codetabof(i) | ||
89 | #define tab_suffixof(i) ((unsigned char *)(htab))[i] | ||
90 | #define de_stack ((unsigned char *)&(htab[HSIZE-1])) | ||
91 | #define clear_htab() memset(htab, -1, sizeof(htab)) | ||
92 | #define clear_tab_prefixof() memset(codetab, 0, 256); | ||
93 | |||
94 | |||
95 | /* | ||
96 | * Decompress stdin to stdout. This routine adapts to the codes in the | ||
97 | * file building the "string" table on-the-fly; requiring no table to | ||
98 | * be stored in the compressed file. The tables used herein are shared | ||
99 | * with those of the compress() routine. See the definitions above. | ||
100 | */ | ||
101 | |||
102 | extern int uncompress(int fd_in, int fd_out) | ||
103 | { | ||
104 | unsigned char *stackp; | ||
105 | long int code; | ||
106 | int finchar; | ||
107 | long int oldcode; | ||
108 | long int incode; | ||
109 | int inbits; | ||
110 | int posbits; | ||
111 | int outpos; | ||
112 | int insize; | ||
113 | int bitmask; | ||
114 | long int free_ent; | ||
115 | long int maxcode; | ||
116 | long int maxmaxcode; | ||
117 | int n_bits; | ||
118 | int rsize = 0; | ||
119 | |||
120 | insize = 0; | ||
121 | |||
122 | inbuf[0] = bb_xread_char(fd_in); | ||
123 | |||
124 | maxbits = inbuf[0] & BIT_MASK; | ||
125 | block_mode = inbuf[0] & BLOCK_MODE; | ||
126 | maxmaxcode = MAXCODE(maxbits); | ||
127 | |||
128 | if (maxbits > BITS) { | ||
129 | bb_error_msg("compressed with %d bits, can only handle %d bits", maxbits, | ||
130 | BITS); | ||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | maxcode = MAXCODE(n_bits = INIT_BITS) - 1; | ||
135 | bitmask = (1 << n_bits) - 1; | ||
136 | oldcode = -1; | ||
137 | finchar = 0; | ||
138 | outpos = 0; | ||
139 | posbits = 0 << 3; | ||
140 | |||
141 | free_ent = ((block_mode) ? FIRST : 256); | ||
142 | |||
143 | /* As above, initialize the first 256 entries in the table. */ | ||
144 | clear_tab_prefixof(); | ||
145 | |||
146 | for (code = 255; code >= 0; --code) { | ||
147 | tab_suffixof(code) = (unsigned char) code; | ||
148 | } | ||
149 | |||
150 | do { | ||
151 | resetbuf:; | ||
152 | { | ||
153 | int i; | ||
154 | int e; | ||
155 | int o; | ||
156 | |||
157 | e = insize - (o = (posbits >> 3)); | ||
158 | |||
159 | for (i = 0; i < e; ++i) | ||
160 | inbuf[i] = inbuf[i + o]; | ||
161 | |||
162 | insize = e; | ||
163 | posbits = 0; | ||
164 | } | ||
165 | |||
166 | if (insize < (int) sizeof(inbuf) - IBUFSIZ) { | ||
167 | rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); | ||
168 | insize += rsize; | ||
169 | } | ||
170 | |||
171 | inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : | ||
172 | (insize << 3) - (n_bits - 1)); | ||
173 | |||
174 | while (inbits > posbits) { | ||
175 | if (free_ent > maxcode) { | ||
176 | posbits = | ||
177 | ((posbits - 1) + | ||
178 | ((n_bits << 3) - | ||
179 | (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); | ||
180 | ++n_bits; | ||
181 | if (n_bits == maxbits) { | ||
182 | maxcode = maxmaxcode; | ||
183 | } else { | ||
184 | maxcode = MAXCODE(n_bits) - 1; | ||
185 | } | ||
186 | bitmask = (1 << n_bits) - 1; | ||
187 | goto resetbuf; | ||
188 | } | ||
189 | { | ||
190 | unsigned char *p = &inbuf[posbits >> 3]; | ||
191 | |||
192 | code = | ||
193 | ((((long) (p[0])) | ((long) (p[1]) << 8) | | ||
194 | ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; | ||
195 | } | ||
196 | posbits += n_bits; | ||
197 | |||
198 | |||
199 | if (oldcode == -1) { | ||
200 | outbuf[outpos++] = (unsigned char) (finchar = | ||
201 | (int) (oldcode = code)); | ||
202 | continue; | ||
203 | } | ||
204 | |||
205 | if (code == CLEAR && block_mode) { | ||
206 | clear_tab_prefixof(); | ||
207 | free_ent = FIRST - 1; | ||
208 | posbits = | ||
209 | ((posbits - 1) + | ||
210 | ((n_bits << 3) - | ||
211 | (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); | ||
212 | maxcode = MAXCODE(n_bits = INIT_BITS) - 1; | ||
213 | bitmask = (1 << n_bits) - 1; | ||
214 | goto resetbuf; | ||
215 | } | ||
216 | |||
217 | incode = code; | ||
218 | stackp = de_stack; | ||
219 | |||
220 | /* Special case for KwKwK string. */ | ||
221 | if (code >= free_ent) { | ||
222 | if (code > free_ent) { | ||
223 | unsigned char *p; | ||
224 | |||
225 | posbits -= n_bits; | ||
226 | p = &inbuf[posbits >> 3]; | ||
227 | |||
228 | bb_error_msg | ||
229 | ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)", | ||
230 | insize, posbits, p[-1], p[0], p[1], p[2], p[3], | ||
231 | (posbits & 07)); | ||
232 | bb_error_msg("uncompress: corrupt input"); | ||
233 | return -1; | ||
234 | } | ||
235 | |||
236 | *--stackp = (unsigned char) finchar; | ||
237 | code = oldcode; | ||
238 | } | ||
239 | |||
240 | /* Generate output characters in reverse order */ | ||
241 | while ((long int) code >= (long int) 256) { | ||
242 | *--stackp = tab_suffixof(code); | ||
243 | code = tab_prefixof(code); | ||
244 | } | ||
245 | |||
246 | *--stackp = (unsigned char) (finchar = tab_suffixof(code)); | ||
247 | |||
248 | /* And put them out in forward order */ | ||
249 | { | ||
250 | int i; | ||
251 | |||
252 | if (outpos + (i = (de_stack - stackp)) >= OBUFSIZ) { | ||
253 | do { | ||
254 | if (i > OBUFSIZ - outpos) { | ||
255 | i = OBUFSIZ - outpos; | ||
256 | } | ||
257 | |||
258 | if (i > 0) { | ||
259 | memcpy(outbuf + outpos, stackp, i); | ||
260 | outpos += i; | ||
261 | } | ||
262 | |||
263 | if (outpos >= OBUFSIZ) { | ||
264 | write(fd_out, outbuf, outpos); | ||
265 | outpos = 0; | ||
266 | } | ||
267 | stackp += i; | ||
268 | } while ((i = (de_stack - stackp)) > 0); | ||
269 | } else { | ||
270 | memcpy(outbuf + outpos, stackp, i); | ||
271 | outpos += i; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* Generate the new entry. */ | ||
276 | if ((code = free_ent) < maxmaxcode) { | ||
277 | tab_prefixof(code) = (unsigned short) oldcode; | ||
278 | tab_suffixof(code) = (unsigned char) finchar; | ||
279 | free_ent = code + 1; | ||
280 | } | ||
281 | |||
282 | /* Remember previous code. */ | ||
283 | oldcode = incode; | ||
284 | } | ||
285 | |||
286 | } while (rsize > 0); | ||
287 | |||
288 | if (outpos > 0) { | ||
289 | write(fd_out, outbuf, outpos); | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
diff --git a/busybox/archival/libunarchive/decompress_unzip.c b/busybox/archival/libunarchive/decompress_unzip.c new file mode 100644 index 000000000..e8cf54bff --- /dev/null +++ b/busybox/archival/libunarchive/decompress_unzip.c | |||
@@ -0,0 +1,982 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * gunzip implementation for busybox | ||
4 | * | ||
5 | * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. | ||
6 | * | ||
7 | * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de> | ||
8 | * based on gzip sources | ||
9 | * | ||
10 | * Adjusted further by Erik Andersen <andersen@codepoet.org> to support | ||
11 | * files as well as stdin/stdout, and to generally behave itself wrt | ||
12 | * command line handling. | ||
13 | * | ||
14 | * General cleanup to better adhere to the style guide and make use of standard | ||
15 | * busybox functions by Glenn McGrath <bug1@iinet.net.au> | ||
16 | * | ||
17 | * read_gz interface + associated hacking by Laurence Anderson | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
27 | * General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | * | ||
33 | * | ||
34 | * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface | ||
35 | * Copyright (C) 1992-1993 Jean-loup Gailly | ||
36 | * The unzip code was written and put in the public domain by Mark Adler. | ||
37 | * Portions of the lzw code are derived from the public domain 'compress' | ||
38 | * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, | ||
39 | * Ken Turkowski, Dave Mack and Peter Jannesen. | ||
40 | * | ||
41 | * See the license_msg below and the file COPYING for the software license. | ||
42 | * See the file algorithm.doc for the compression algorithms and file formats. | ||
43 | */ | ||
44 | |||
45 | #if 0 | ||
46 | static char *license_msg[] = { | ||
47 | " Copyright (C) 1992-1993 Jean-loup Gailly", | ||
48 | " This program is free software; you can redistribute it and/or modify", | ||
49 | " it under the terms of the GNU General Public License as published by", | ||
50 | " the Free Software Foundation; either version 2, or (at your option)", | ||
51 | " any later version.", | ||
52 | "", | ||
53 | " This program is distributed in the hope that it will be useful,", | ||
54 | " but WITHOUT ANY WARRANTY; without even the implied warranty of", | ||
55 | " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", | ||
56 | " GNU General Public License for more details.", | ||
57 | "", | ||
58 | " You should have received a copy of the GNU General Public License", | ||
59 | " along with this program; if not, write to the Free Software", | ||
60 | " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.", | ||
61 | 0 | ||
62 | }; | ||
63 | #endif | ||
64 | |||
65 | #include <sys/types.h> | ||
66 | #include <sys/wait.h> | ||
67 | #include <signal.h> | ||
68 | #include <stdlib.h> | ||
69 | #include <string.h> | ||
70 | #include <unistd.h> | ||
71 | #include <fcntl.h> | ||
72 | #include "config.h" | ||
73 | #include "busybox.h" | ||
74 | #include "unarchive.h" | ||
75 | |||
76 | typedef struct huft_s { | ||
77 | unsigned char e; /* number of extra bits or operation */ | ||
78 | unsigned char b; /* number of bits in this code or subcode */ | ||
79 | union { | ||
80 | unsigned short n; /* literal, length base, or distance base */ | ||
81 | struct huft_s *t; /* pointer to next level of table */ | ||
82 | } v; | ||
83 | } huft_t; | ||
84 | |||
85 | static int gunzip_src_fd; | ||
86 | unsigned int gunzip_bytes_out; /* number of output bytes */ | ||
87 | static unsigned int gunzip_outbuf_count; /* bytes in output buffer */ | ||
88 | |||
89 | /* gunzip_window size--must be a power of two, and | ||
90 | * at least 32K for zip's deflate method */ | ||
91 | static const int gunzip_wsize = 0x8000; | ||
92 | static unsigned char *gunzip_window; | ||
93 | |||
94 | static unsigned int *gunzip_crc_table; | ||
95 | unsigned int gunzip_crc; | ||
96 | |||
97 | /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ | ||
98 | #define BMAX 16 /* maximum bit length of any code (16 for explode) */ | ||
99 | #define N_MAX 288 /* maximum number of codes in any set */ | ||
100 | |||
101 | /* bitbuffer */ | ||
102 | static unsigned int gunzip_bb; /* bit buffer */ | ||
103 | static unsigned char gunzip_bk; /* bits in bit buffer */ | ||
104 | |||
105 | /* These control the size of the bytebuffer */ | ||
106 | static unsigned int bytebuffer_max = 0x8000; | ||
107 | static unsigned char *bytebuffer = NULL; | ||
108 | static unsigned int bytebuffer_offset = 0; | ||
109 | static unsigned int bytebuffer_size = 0; | ||
110 | |||
111 | static const unsigned short mask_bits[] = { | ||
112 | 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, | ||
113 | 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | ||
114 | }; | ||
115 | |||
116 | /* Copy lengths for literal codes 257..285 */ | ||
117 | static const unsigned short cplens[] = { | ||
118 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, | ||
119 | 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 | ||
120 | }; | ||
121 | |||
122 | /* note: see note #13 above about the 258 in this list. */ | ||
123 | /* Extra bits for literal codes 257..285 */ | ||
124 | static const unsigned char cplext[] = { | ||
125 | 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, | ||
126 | 5, 5, 5, 0, 99, 99 | ||
127 | }; /* 99==invalid */ | ||
128 | |||
129 | /* Copy offsets for distance codes 0..29 */ | ||
130 | static const unsigned short cpdist[] = { | ||
131 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, | ||
132 | 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 | ||
133 | }; | ||
134 | |||
135 | /* Extra bits for distance codes */ | ||
136 | static const unsigned char cpdext[] = { | ||
137 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, | ||
138 | 11, 11, 12, 12, 13, 13 | ||
139 | }; | ||
140 | |||
141 | /* Tables for deflate from PKZIP's appnote.txt. */ | ||
142 | /* Order of the bit length code lengths */ | ||
143 | static const unsigned char border[] = { | ||
144 | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 | ||
145 | }; | ||
146 | |||
147 | static unsigned int fill_bitbuffer(unsigned int bitbuffer, unsigned int *current, const unsigned int required) | ||
148 | { | ||
149 | while (*current < required) { | ||
150 | if (bytebuffer_offset >= bytebuffer_size) { | ||
151 | /* Leave the first 4 bytes empty so we can always unwind the bitbuffer | ||
152 | * to the front of the bytebuffer, leave 4 bytes free at end of tail | ||
153 | * so we can easily top up buffer in check_trailer_gzip() */ | ||
154 | bytebuffer_size = 4 + bb_xread(gunzip_src_fd, &bytebuffer[4], bytebuffer_max - 8); | ||
155 | bytebuffer_offset = 4; | ||
156 | } | ||
157 | bitbuffer |= ((unsigned int) bytebuffer[bytebuffer_offset]) << *current; | ||
158 | bytebuffer_offset++; | ||
159 | *current += 8; | ||
160 | } | ||
161 | return(bitbuffer); | ||
162 | } | ||
163 | |||
164 | static void make_gunzip_crc_table(void) | ||
165 | { | ||
166 | const unsigned int poly = 0xedb88320; /* polynomial exclusive-or pattern */ | ||
167 | unsigned short i; /* counter for all possible eight bit values */ | ||
168 | |||
169 | /* initial shift register value */ | ||
170 | gunzip_crc = 0xffffffffL; | ||
171 | gunzip_crc_table = (unsigned int *) malloc(256 * sizeof(unsigned int)); | ||
172 | |||
173 | /* Compute and print table of CRC's, five per line */ | ||
174 | for (i = 0; i < 256; i++) { | ||
175 | unsigned int table_entry; /* crc shift register */ | ||
176 | unsigned char k; /* byte being shifted into crc apparatus */ | ||
177 | |||
178 | table_entry = i; | ||
179 | /* The idea to initialize the register with the byte instead of | ||
180 | * zero was stolen from Haruhiko Okumura's ar002 | ||
181 | */ | ||
182 | for (k = 8; k; k--) { | ||
183 | if (table_entry & 1) { | ||
184 | table_entry = (table_entry >> 1) ^ poly; | ||
185 | } else { | ||
186 | table_entry >>= 1; | ||
187 | } | ||
188 | } | ||
189 | gunzip_crc_table[i] = table_entry; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * Free the malloc'ed tables built by huft_build(), which makes a linked | ||
195 | * list of the tables it made, with the links in a dummy first entry of | ||
196 | * each table. | ||
197 | * t: table to free | ||
198 | */ | ||
199 | static int huft_free(huft_t * t) | ||
200 | { | ||
201 | huft_t *p; | ||
202 | huft_t *q; | ||
203 | |||
204 | /* Go through linked list, freeing from the malloced (t[-1]) address. */ | ||
205 | p = t; | ||
206 | while (p != (huft_t *) NULL) { | ||
207 | q = (--p)->v.t; | ||
208 | free((char *) p); | ||
209 | p = q; | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* Given a list of code lengths and a maximum table size, make a set of | ||
215 | * tables to decode that set of codes. Return zero on success, one if | ||
216 | * the given code set is incomplete (the tables are still built in this | ||
217 | * case), two if the input is invalid (all zero length codes or an | ||
218 | * oversubscribed set of lengths), and three if not enough memory. | ||
219 | * | ||
220 | * b: code lengths in bits (all assumed <= BMAX) | ||
221 | * n: number of codes (assumed <= N_MAX) | ||
222 | * s: number of simple-valued codes (0..s-1) | ||
223 | * d: list of base values for non-simple codes | ||
224 | * e: list of extra bits for non-simple codes | ||
225 | * t: result: starting table | ||
226 | * m: maximum lookup bits, returns actual | ||
227 | */ | ||
228 | static int huft_build(unsigned int *b, const unsigned int n, | ||
229 | const unsigned int s, const unsigned short *d, | ||
230 | const unsigned char *e, huft_t ** t, int *m) | ||
231 | { | ||
232 | unsigned a; /* counter for codes of length k */ | ||
233 | unsigned c[BMAX + 1]; /* bit length count table */ | ||
234 | unsigned f; /* i repeats in table every f entries */ | ||
235 | int g; /* maximum code length */ | ||
236 | int h; /* table level */ | ||
237 | register unsigned i; /* counter, current code */ | ||
238 | register unsigned j; /* counter */ | ||
239 | register int k; /* number of bits in current code */ | ||
240 | int l; /* bits per table (returned in m) */ | ||
241 | register unsigned *p; /* pointer into c[], b[], or v[] */ | ||
242 | register huft_t *q; /* points to current table */ | ||
243 | huft_t r; /* table entry for structure assignment */ | ||
244 | huft_t *u[BMAX]; /* table stack */ | ||
245 | unsigned v[N_MAX]; /* values in order of bit length */ | ||
246 | register int w; /* bits before this table == (l * h) */ | ||
247 | unsigned x[BMAX + 1]; /* bit offsets, then code stack */ | ||
248 | unsigned *xp; /* pointer into x */ | ||
249 | int y; /* number of dummy codes added */ | ||
250 | unsigned z; /* number of entries in current table */ | ||
251 | |||
252 | /* Generate counts for each bit length */ | ||
253 | memset((void *) (c), 0, sizeof(c)); | ||
254 | p = b; | ||
255 | i = n; | ||
256 | do { | ||
257 | c[*p]++; /* assume all entries <= BMAX */ | ||
258 | p++; /* Can't combine with above line (Solaris bug) */ | ||
259 | } while (--i); | ||
260 | if (c[0] == n) { /* null input--all zero length codes */ | ||
261 | *t = (huft_t *) NULL; | ||
262 | *m = 0; | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /* Find minimum and maximum length, bound *m by those */ | ||
267 | l = *m; | ||
268 | for (j = 1; j <= BMAX; j++) { | ||
269 | if (c[j]) { | ||
270 | break; | ||
271 | } | ||
272 | } | ||
273 | k = j; /* minimum code length */ | ||
274 | if ((unsigned) l < j) { | ||
275 | l = j; | ||
276 | } | ||
277 | for (i = BMAX; i; i--) { | ||
278 | if (c[i]) { | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | g = i; /* maximum code length */ | ||
283 | if ((unsigned) l > i) { | ||
284 | l = i; | ||
285 | } | ||
286 | *m = l; | ||
287 | |||
288 | /* Adjust last length count to fill out codes, if needed */ | ||
289 | for (y = 1 << j; j < i; j++, y <<= 1) { | ||
290 | if ((y -= c[j]) < 0) { | ||
291 | return 2; /* bad input: more codes than bits */ | ||
292 | } | ||
293 | } | ||
294 | if ((y -= c[i]) < 0) { | ||
295 | return 2; | ||
296 | } | ||
297 | c[i] += y; | ||
298 | |||
299 | /* Generate starting offsets into the value table for each length */ | ||
300 | x[1] = j = 0; | ||
301 | p = c + 1; | ||
302 | xp = x + 2; | ||
303 | while (--i) { /* note that i == g from above */ | ||
304 | *xp++ = (j += *p++); | ||
305 | } | ||
306 | |||
307 | /* Make a table of values in order of bit lengths */ | ||
308 | p = b; | ||
309 | i = 0; | ||
310 | do { | ||
311 | if ((j = *p++) != 0) { | ||
312 | v[x[j]++] = i; | ||
313 | } | ||
314 | } while (++i < n); | ||
315 | |||
316 | /* Generate the Huffman codes and for each, make the table entries */ | ||
317 | x[0] = i = 0; /* first Huffman code is zero */ | ||
318 | p = v; /* grab values in bit order */ | ||
319 | h = -1; /* no tables yet--level -1 */ | ||
320 | w = -l; /* bits decoded == (l * h) */ | ||
321 | u[0] = (huft_t *) NULL; /* just to keep compilers happy */ | ||
322 | q = (huft_t *) NULL; /* ditto */ | ||
323 | z = 0; /* ditto */ | ||
324 | |||
325 | /* go through the bit lengths (k already is bits in shortest code) */ | ||
326 | for (; k <= g; k++) { | ||
327 | a = c[k]; | ||
328 | while (a--) { | ||
329 | /* here i is the Huffman code of length k bits for value *p */ | ||
330 | /* make tables up to required level */ | ||
331 | while (k > w + l) { | ||
332 | h++; | ||
333 | w += l; /* previous table always l bits */ | ||
334 | |||
335 | /* compute minimum size table less than or equal to l bits */ | ||
336 | z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ | ||
337 | if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ | ||
338 | f -= a + 1; /* deduct codes from patterns left */ | ||
339 | xp = c + k; | ||
340 | while (++j < z) { /* try smaller tables up to z bits */ | ||
341 | if ((f <<= 1) <= *++xp) { | ||
342 | break; /* enough codes to use up j bits */ | ||
343 | } | ||
344 | f -= *xp; /* else deduct codes from patterns */ | ||
345 | } | ||
346 | } | ||
347 | z = 1 << j; /* table entries for j-bit table */ | ||
348 | |||
349 | /* allocate and link in new table */ | ||
350 | q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t)); | ||
351 | |||
352 | *t = q + 1; /* link to list for huft_free() */ | ||
353 | *(t = &(q->v.t)) = NULL; | ||
354 | u[h] = ++q; /* table starts after link */ | ||
355 | |||
356 | /* connect to last table, if there is one */ | ||
357 | if (h) { | ||
358 | x[h] = i; /* save pattern for backing up */ | ||
359 | r.b = (unsigned char) l; /* bits to dump before this table */ | ||
360 | r.e = (unsigned char) (16 + j); /* bits in this table */ | ||
361 | r.v.t = q; /* pointer to this table */ | ||
362 | j = i >> (w - l); /* (get around Turbo C bug) */ | ||
363 | u[h - 1][j] = r; /* connect to last table */ | ||
364 | } | ||
365 | } | ||
366 | |||
367 | /* set up table entry in r */ | ||
368 | r.b = (unsigned char) (k - w); | ||
369 | if (p >= v + n) { | ||
370 | r.e = 99; /* out of values--invalid code */ | ||
371 | } else if (*p < s) { | ||
372 | r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ | ||
373 | r.v.n = (unsigned short) (*p); /* simple code is just the value */ | ||
374 | p++; /* one compiler does not like *p++ */ | ||
375 | } else { | ||
376 | r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ | ||
377 | r.v.n = d[*p++ - s]; | ||
378 | } | ||
379 | |||
380 | /* fill code-like entries with r */ | ||
381 | f = 1 << (k - w); | ||
382 | for (j = i >> w; j < z; j += f) { | ||
383 | q[j] = r; | ||
384 | } | ||
385 | |||
386 | /* backwards increment the k-bit code i */ | ||
387 | for (j = 1 << (k - 1); i & j; j >>= 1) { | ||
388 | i ^= j; | ||
389 | } | ||
390 | i ^= j; | ||
391 | |||
392 | /* backup over finished tables */ | ||
393 | while ((i & ((1 << w) - 1)) != x[h]) { | ||
394 | h--; /* don't need to update q */ | ||
395 | w -= l; | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | /* Return true (1) if we were given an incomplete table */ | ||
400 | return y != 0 && g != 1; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * inflate (decompress) the codes in a deflated (compressed) block. | ||
405 | * Return an error code or zero if it all goes ok. | ||
406 | * | ||
407 | * tl, td: literal/length and distance decoder tables | ||
408 | * bl, bd: number of bits decoded by tl[] and td[] | ||
409 | */ | ||
410 | static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned int my_bl, const unsigned int my_bd, int setup) | ||
411 | { | ||
412 | static unsigned int e; /* table entry flag/number of extra bits */ | ||
413 | static unsigned int n, d; /* length and index for copy */ | ||
414 | static unsigned int w; /* current gunzip_window position */ | ||
415 | static huft_t *t; /* pointer to table entry */ | ||
416 | static unsigned int ml, md; /* masks for bl and bd bits */ | ||
417 | static unsigned int b; /* bit buffer */ | ||
418 | static unsigned int k; /* number of bits in bit buffer */ | ||
419 | static huft_t *tl, *td; | ||
420 | static unsigned int bl, bd; | ||
421 | static int resumeCopy = 0; | ||
422 | |||
423 | if (setup) { // 1st time we are called, copy in variables | ||
424 | tl = my_tl; | ||
425 | td = my_td; | ||
426 | bl = my_bl; | ||
427 | bd = my_bd; | ||
428 | /* make local copies of globals */ | ||
429 | b = gunzip_bb; /* initialize bit buffer */ | ||
430 | k = gunzip_bk; | ||
431 | w = gunzip_outbuf_count; /* initialize gunzip_window position */ | ||
432 | |||
433 | /* inflate the coded data */ | ||
434 | ml = mask_bits[bl]; /* precompute masks for speed */ | ||
435 | md = mask_bits[bd]; | ||
436 | return 0; // Don't actually do anything the first time | ||
437 | } | ||
438 | |||
439 | if (resumeCopy) goto do_copy; | ||
440 | |||
441 | while (1) { /* do until end of block */ | ||
442 | b = fill_bitbuffer(b, &k, bl); | ||
443 | if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) | ||
444 | do { | ||
445 | if (e == 99) { | ||
446 | bb_error_msg_and_die("inflate_codes error 1");; | ||
447 | } | ||
448 | b >>= t->b; | ||
449 | k -= t->b; | ||
450 | e -= 16; | ||
451 | b = fill_bitbuffer(b, &k, e); | ||
452 | } while ((e = | ||
453 | (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | ||
454 | b >>= t->b; | ||
455 | k -= t->b; | ||
456 | if (e == 16) { /* then it's a literal */ | ||
457 | gunzip_window[w++] = (unsigned char) t->v.n; | ||
458 | if (w == gunzip_wsize) { | ||
459 | gunzip_outbuf_count = (w); | ||
460 | //flush_gunzip_window(); | ||
461 | w = 0; | ||
462 | return 1; // We have a block to read | ||
463 | } | ||
464 | } else { /* it's an EOB or a length */ | ||
465 | |||
466 | /* exit if end of block */ | ||
467 | if (e == 15) { | ||
468 | break; | ||
469 | } | ||
470 | |||
471 | /* get length of block to copy */ | ||
472 | b = fill_bitbuffer(b, &k, e); | ||
473 | n = t->v.n + ((unsigned) b & mask_bits[e]); | ||
474 | b >>= e; | ||
475 | k -= e; | ||
476 | |||
477 | /* decode distance of block to copy */ | ||
478 | b = fill_bitbuffer(b, &k, bd); | ||
479 | if ((e = (t = td + ((unsigned) b & md))->e) > 16) | ||
480 | do { | ||
481 | if (e == 99) | ||
482 | bb_error_msg_and_die("inflate_codes error 2");; | ||
483 | b >>= t->b; | ||
484 | k -= t->b; | ||
485 | e -= 16; | ||
486 | b = fill_bitbuffer(b, &k, e); | ||
487 | } while ((e = | ||
488 | (t = | ||
489 | t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); | ||
490 | b >>= t->b; | ||
491 | k -= t->b; | ||
492 | b = fill_bitbuffer(b, &k, e); | ||
493 | d = w - t->v.n - ((unsigned) b & mask_bits[e]); | ||
494 | b >>= e; | ||
495 | k -= e; | ||
496 | |||
497 | /* do the copy */ | ||
498 | do_copy: do { | ||
499 | n -= (e = | ||
500 | (e = | ||
501 | gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); | ||
502 | /* copy to new buffer to prevent possible overwrite */ | ||
503 | if (w - d >= e) { /* (this test assumes unsigned comparison) */ | ||
504 | memcpy(gunzip_window + w, gunzip_window + d, e); | ||
505 | w += e; | ||
506 | d += e; | ||
507 | } else { | ||
508 | /* do it slow to avoid memcpy() overlap */ | ||
509 | /* !NOMEMCPY */ | ||
510 | do { | ||
511 | gunzip_window[w++] = gunzip_window[d++]; | ||
512 | } while (--e); | ||
513 | } | ||
514 | if (w == gunzip_wsize) { | ||
515 | gunzip_outbuf_count = (w); | ||
516 | if (n) resumeCopy = 1; | ||
517 | else resumeCopy = 0; | ||
518 | //flush_gunzip_window(); | ||
519 | w = 0; | ||
520 | return 1; | ||
521 | } | ||
522 | } while (n); | ||
523 | resumeCopy = 0; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | /* restore the globals from the locals */ | ||
528 | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ | ||
529 | gunzip_bb = b; /* restore global bit buffer */ | ||
530 | gunzip_bk = k; | ||
531 | |||
532 | /* normally just after call to inflate_codes, but save code by putting it here */ | ||
533 | /* free the decoding tables, return */ | ||
534 | huft_free(tl); | ||
535 | huft_free(td); | ||
536 | |||
537 | /* done */ | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int inflate_stored(int my_n, int my_b_stored, int my_k_stored, int setup) | ||
542 | { | ||
543 | static int n, b_stored, k_stored, w; | ||
544 | if (setup) { | ||
545 | n = my_n; | ||
546 | b_stored = my_b_stored; | ||
547 | k_stored = my_k_stored; | ||
548 | w = gunzip_outbuf_count; /* initialize gunzip_window position */ | ||
549 | return 0; // Don't do anything first time | ||
550 | } | ||
551 | |||
552 | /* read and output the compressed data */ | ||
553 | while (n--) { | ||
554 | b_stored = fill_bitbuffer(b_stored, &k_stored, 8); | ||
555 | gunzip_window[w++] = (unsigned char) b_stored; | ||
556 | if (w == (unsigned int) gunzip_wsize) { | ||
557 | gunzip_outbuf_count = (w); | ||
558 | //flush_gunzip_window(); | ||
559 | w = 0; | ||
560 | b_stored >>= 8; | ||
561 | k_stored -= 8; | ||
562 | return 1; // We have a block | ||
563 | } | ||
564 | b_stored >>= 8; | ||
565 | k_stored -= 8; | ||
566 | } | ||
567 | |||
568 | /* restore the globals from the locals */ | ||
569 | gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ | ||
570 | gunzip_bb = b_stored; /* restore global bit buffer */ | ||
571 | gunzip_bk = k_stored; | ||
572 | return 0; // Finished | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * decompress an inflated block | ||
577 | * e: last block flag | ||
578 | * | ||
579 | * GLOBAL VARIABLES: bb, kk, | ||
580 | */ | ||
581 | // Return values: -1 = inflate_stored, -2 = inflate_codes | ||
582 | static int inflate_block(int *e) | ||
583 | { | ||
584 | unsigned t; /* block type */ | ||
585 | register unsigned int b; /* bit buffer */ | ||
586 | unsigned int k; /* number of bits in bit buffer */ | ||
587 | |||
588 | /* make local bit buffer */ | ||
589 | |||
590 | b = gunzip_bb; | ||
591 | k = gunzip_bk; | ||
592 | |||
593 | /* read in last block bit */ | ||
594 | b = fill_bitbuffer(b, &k, 1); | ||
595 | *e = (int) b & 1; | ||
596 | b >>= 1; | ||
597 | k -= 1; | ||
598 | |||
599 | /* read in block type */ | ||
600 | b = fill_bitbuffer(b, &k, 2); | ||
601 | t = (unsigned) b & 3; | ||
602 | b >>= 2; | ||
603 | k -= 2; | ||
604 | |||
605 | /* restore the global bit buffer */ | ||
606 | gunzip_bb = b; | ||
607 | gunzip_bk = k; | ||
608 | |||
609 | /* inflate that block type */ | ||
610 | switch (t) { | ||
611 | case 0: /* Inflate stored */ | ||
612 | { | ||
613 | unsigned int n; /* number of bytes in block */ | ||
614 | unsigned int b_stored; /* bit buffer */ | ||
615 | unsigned int k_stored; /* number of bits in bit buffer */ | ||
616 | |||
617 | /* make local copies of globals */ | ||
618 | b_stored = gunzip_bb; /* initialize bit buffer */ | ||
619 | k_stored = gunzip_bk; | ||
620 | |||
621 | /* go to byte boundary */ | ||
622 | n = k_stored & 7; | ||
623 | b_stored >>= n; | ||
624 | k_stored -= n; | ||
625 | |||
626 | /* get the length and its complement */ | ||
627 | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); | ||
628 | n = ((unsigned) b_stored & 0xffff); | ||
629 | b_stored >>= 16; | ||
630 | k_stored -= 16; | ||
631 | |||
632 | b_stored = fill_bitbuffer(b_stored, &k_stored, 16); | ||
633 | if (n != (unsigned) ((~b_stored) & 0xffff)) { | ||
634 | return 1; /* error in compressed data */ | ||
635 | } | ||
636 | b_stored >>= 16; | ||
637 | k_stored -= 16; | ||
638 | |||
639 | inflate_stored(n, b_stored, k_stored, 1); // Setup inflate_stored | ||
640 | return -1; | ||
641 | } | ||
642 | case 1: /* Inflate fixed | ||
643 | * decompress an inflated type 1 (fixed Huffman codes) block. We should | ||
644 | * either replace this with a custom decoder, or at least precompute the | ||
645 | * Huffman tables. | ||
646 | */ | ||
647 | { | ||
648 | int i; /* temporary variable */ | ||
649 | huft_t *tl; /* literal/length code table */ | ||
650 | huft_t *td; /* distance code table */ | ||
651 | unsigned int bl; /* lookup bits for tl */ | ||
652 | unsigned int bd; /* lookup bits for td */ | ||
653 | unsigned int l[288]; /* length list for huft_build */ | ||
654 | |||
655 | /* set up literal table */ | ||
656 | for (i = 0; i < 144; i++) { | ||
657 | l[i] = 8; | ||
658 | } | ||
659 | for (; i < 256; i++) { | ||
660 | l[i] = 9; | ||
661 | } | ||
662 | for (; i < 280; i++) { | ||
663 | l[i] = 7; | ||
664 | } | ||
665 | for (; i < 288; i++) { /* make a complete, but wrong code set */ | ||
666 | l[i] = 8; | ||
667 | } | ||
668 | bl = 7; | ||
669 | if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { | ||
670 | return i; | ||
671 | } | ||
672 | |||
673 | /* set up distance table */ | ||
674 | for (i = 0; i < 30; i++) { /* make an incomplete code set */ | ||
675 | l[i] = 5; | ||
676 | } | ||
677 | bd = 5; | ||
678 | if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { | ||
679 | huft_free(tl); | ||
680 | return i; | ||
681 | } | ||
682 | |||
683 | /* decompress until an end-of-block code */ | ||
684 | inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes | ||
685 | |||
686 | /* huft_free code moved into inflate_codes */ | ||
687 | |||
688 | return -2; | ||
689 | } | ||
690 | case 2: /* Inflate dynamic */ | ||
691 | { | ||
692 | const int dbits = 6; /* bits in base distance lookup table */ | ||
693 | const int lbits = 9; /* bits in base literal/length lookup table */ | ||
694 | |||
695 | huft_t *tl; /* literal/length code table */ | ||
696 | huft_t *td; /* distance code table */ | ||
697 | unsigned int i; /* temporary variables */ | ||
698 | unsigned int j; | ||
699 | unsigned int l; /* last length */ | ||
700 | unsigned int m; /* mask for bit lengths table */ | ||
701 | unsigned int n; /* number of lengths to get */ | ||
702 | unsigned int bl; /* lookup bits for tl */ | ||
703 | unsigned int bd; /* lookup bits for td */ | ||
704 | unsigned int nb; /* number of bit length codes */ | ||
705 | unsigned int nl; /* number of literal/length codes */ | ||
706 | unsigned int nd; /* number of distance codes */ | ||
707 | |||
708 | unsigned int ll[286 + 30]; /* literal/length and distance code lengths */ | ||
709 | unsigned int b_dynamic; /* bit buffer */ | ||
710 | unsigned int k_dynamic; /* number of bits in bit buffer */ | ||
711 | |||
712 | /* make local bit buffer */ | ||
713 | b_dynamic = gunzip_bb; | ||
714 | k_dynamic = gunzip_bk; | ||
715 | |||
716 | /* read in table lengths */ | ||
717 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); | ||
718 | nl = 257 + ((unsigned int) b_dynamic & 0x1f); /* number of literal/length codes */ | ||
719 | |||
720 | b_dynamic >>= 5; | ||
721 | k_dynamic -= 5; | ||
722 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 5); | ||
723 | nd = 1 + ((unsigned int) b_dynamic & 0x1f); /* number of distance codes */ | ||
724 | |||
725 | b_dynamic >>= 5; | ||
726 | k_dynamic -= 5; | ||
727 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 4); | ||
728 | nb = 4 + ((unsigned int) b_dynamic & 0xf); /* number of bit length codes */ | ||
729 | |||
730 | b_dynamic >>= 4; | ||
731 | k_dynamic -= 4; | ||
732 | if (nl > 286 || nd > 30) { | ||
733 | return 1; /* bad lengths */ | ||
734 | } | ||
735 | |||
736 | /* read in bit-length-code lengths */ | ||
737 | for (j = 0; j < nb; j++) { | ||
738 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); | ||
739 | ll[border[j]] = (unsigned int) b_dynamic & 7; | ||
740 | b_dynamic >>= 3; | ||
741 | k_dynamic -= 3; | ||
742 | } | ||
743 | for (; j < 19; j++) { | ||
744 | ll[border[j]] = 0; | ||
745 | } | ||
746 | |||
747 | /* build decoding table for trees--single level, 7 bit lookup */ | ||
748 | bl = 7; | ||
749 | i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl); | ||
750 | if (i != 0) { | ||
751 | if (i == 1) { | ||
752 | huft_free(tl); | ||
753 | } | ||
754 | return i; /* incomplete code set */ | ||
755 | } | ||
756 | |||
757 | /* read in literal and distance code lengths */ | ||
758 | n = nl + nd; | ||
759 | m = mask_bits[bl]; | ||
760 | i = l = 0; | ||
761 | while ((unsigned int) i < n) { | ||
762 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, (unsigned int)bl); | ||
763 | j = (td = tl + ((unsigned int) b_dynamic & m))->b; | ||
764 | b_dynamic >>= j; | ||
765 | k_dynamic -= j; | ||
766 | j = td->v.n; | ||
767 | if (j < 16) { /* length of code in bits (0..15) */ | ||
768 | ll[i++] = l = j; /* save last length in l */ | ||
769 | } else if (j == 16) { /* repeat last length 3 to 6 times */ | ||
770 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 2); | ||
771 | j = 3 + ((unsigned int) b_dynamic & 3); | ||
772 | b_dynamic >>= 2; | ||
773 | k_dynamic -= 2; | ||
774 | if ((unsigned int) i + j > n) { | ||
775 | return 1; | ||
776 | } | ||
777 | while (j--) { | ||
778 | ll[i++] = l; | ||
779 | } | ||
780 | } else if (j == 17) { /* 3 to 10 zero length codes */ | ||
781 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 3); | ||
782 | j = 3 + ((unsigned int) b_dynamic & 7); | ||
783 | b_dynamic >>= 3; | ||
784 | k_dynamic -= 3; | ||
785 | if ((unsigned int) i + j > n) { | ||
786 | return 1; | ||
787 | } | ||
788 | while (j--) { | ||
789 | ll[i++] = 0; | ||
790 | } | ||
791 | l = 0; | ||
792 | } else { /* j == 18: 11 to 138 zero length codes */ | ||
793 | b_dynamic = fill_bitbuffer(b_dynamic, &k_dynamic, 7); | ||
794 | j = 11 + ((unsigned int) b_dynamic & 0x7f); | ||
795 | b_dynamic >>= 7; | ||
796 | k_dynamic -= 7; | ||
797 | if ((unsigned int) i + j > n) { | ||
798 | return 1; | ||
799 | } | ||
800 | while (j--) { | ||
801 | ll[i++] = 0; | ||
802 | } | ||
803 | l = 0; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | /* free decoding table for trees */ | ||
808 | huft_free(tl); | ||
809 | |||
810 | /* restore the global bit buffer */ | ||
811 | gunzip_bb = b_dynamic; | ||
812 | gunzip_bk = k_dynamic; | ||
813 | |||
814 | /* build the decoding tables for literal/length and distance codes */ | ||
815 | bl = lbits; | ||
816 | |||
817 | if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { | ||
818 | if (i == 1) { | ||
819 | bb_error_msg_and_die("Incomplete literal tree"); | ||
820 | huft_free(tl); | ||
821 | } | ||
822 | return i; /* incomplete code set */ | ||
823 | } | ||
824 | |||
825 | bd = dbits; | ||
826 | if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { | ||
827 | if (i == 1) { | ||
828 | bb_error_msg_and_die("incomplete distance tree"); | ||
829 | huft_free(td); | ||
830 | } | ||
831 | huft_free(tl); | ||
832 | return i; /* incomplete code set */ | ||
833 | } | ||
834 | |||
835 | /* decompress until an end-of-block code */ | ||
836 | inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes | ||
837 | |||
838 | /* huft_free code moved into inflate_codes */ | ||
839 | |||
840 | return -2; | ||
841 | } | ||
842 | default: | ||
843 | /* bad block type */ | ||
844 | bb_error_msg_and_die("bad block type %d\n", t); | ||
845 | } | ||
846 | } | ||
847 | |||
848 | static void calculate_gunzip_crc(void) | ||
849 | { | ||
850 | int n; | ||
851 | for (n = 0; n < gunzip_outbuf_count; n++) { | ||
852 | gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); | ||
853 | } | ||
854 | gunzip_bytes_out += gunzip_outbuf_count; | ||
855 | } | ||
856 | |||
857 | static int inflate_get_next_window(void) | ||
858 | { | ||
859 | static int method = -1; // Method == -1 for stored, -2 for codes | ||
860 | static int e = 0; | ||
861 | static int needAnotherBlock = 1; | ||
862 | |||
863 | gunzip_outbuf_count = 0; | ||
864 | |||
865 | while(1) { | ||
866 | int ret; | ||
867 | |||
868 | if (needAnotherBlock) { | ||
869 | if(e) { | ||
870 | calculate_gunzip_crc(); | ||
871 | e = 0; | ||
872 | needAnotherBlock = 1; | ||
873 | return 0; | ||
874 | } // Last block | ||
875 | method = inflate_block(&e); | ||
876 | needAnotherBlock = 0; | ||
877 | } | ||
878 | |||
879 | switch (method) { | ||
880 | case -1: ret = inflate_stored(0,0,0,0); | ||
881 | break; | ||
882 | case -2: ret = inflate_codes(0,0,0,0,0); | ||
883 | break; | ||
884 | default: bb_error_msg_and_die("inflate error %d", method); | ||
885 | } | ||
886 | |||
887 | if (ret == 1) { | ||
888 | calculate_gunzip_crc(); | ||
889 | return 1; // More data left | ||
890 | } else needAnotherBlock = 1; // End of that block | ||
891 | } | ||
892 | /* Doesnt get here */ | ||
893 | } | ||
894 | |||
895 | /* Initialise bytebuffer, be careful not to overfill the buffer */ | ||
896 | extern void inflate_init(unsigned int bufsize) | ||
897 | { | ||
898 | /* Set the bytebuffer size, default is same as gunzip_wsize */ | ||
899 | bytebuffer_max = bufsize + 8; | ||
900 | bytebuffer_offset = 4; | ||
901 | bytebuffer_size = 0; | ||
902 | } | ||
903 | |||
904 | extern int inflate_unzip(int in, int out) | ||
905 | { | ||
906 | ssize_t nwrote; | ||
907 | typedef void (*sig_type) (int); | ||
908 | |||
909 | /* Allocate all global buffers (for DYN_ALLOC option) */ | ||
910 | gunzip_window = xmalloc(gunzip_wsize); | ||
911 | gunzip_outbuf_count = 0; | ||
912 | gunzip_bytes_out = 0; | ||
913 | gunzip_src_fd = in; | ||
914 | |||
915 | /* initialize gunzip_window, bit buffer */ | ||
916 | gunzip_bk = 0; | ||
917 | gunzip_bb = 0; | ||
918 | |||
919 | /* Create the crc table */ | ||
920 | make_gunzip_crc_table(); | ||
921 | |||
922 | /* Allocate space for buffer */ | ||
923 | bytebuffer = xmalloc(bytebuffer_max); | ||
924 | |||
925 | while(1) { | ||
926 | int ret = inflate_get_next_window(); | ||
927 | nwrote = bb_full_write(out, gunzip_window, gunzip_outbuf_count); | ||
928 | if (nwrote == -1) { | ||
929 | bb_perror_msg("write"); | ||
930 | return -1; | ||
931 | } | ||
932 | if (ret == 0) break; | ||
933 | } | ||
934 | |||
935 | /* Cleanup */ | ||
936 | free(gunzip_window); | ||
937 | free(gunzip_crc_table); | ||
938 | |||
939 | /* Store unused bytes in a global buffer so calling applets can access it */ | ||
940 | if (gunzip_bk >= 8) { | ||
941 | /* Undo too much lookahead. The next read will be byte aligned | ||
942 | * so we can discard unused bits in the last meaningful byte. */ | ||
943 | bytebuffer_offset--; | ||
944 | bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; | ||
945 | gunzip_bb >>= 8; | ||
946 | gunzip_bk -= 8; | ||
947 | } | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | extern int inflate_gunzip(int in, int out) | ||
952 | { | ||
953 | unsigned int stored_crc = 0; | ||
954 | unsigned char count; | ||
955 | |||
956 | inflate_unzip(in, out); | ||
957 | |||
958 | /* top up the input buffer with the rest of the trailer */ | ||
959 | count = bytebuffer_size - bytebuffer_offset; | ||
960 | if (count < 8) { | ||
961 | bb_xread_all(in, &bytebuffer[bytebuffer_size], 8 - count); | ||
962 | bytebuffer_size += 8 - count; | ||
963 | } | ||
964 | for (count = 0; count != 4; count++) { | ||
965 | stored_crc |= (bytebuffer[bytebuffer_offset] << (count * 8)); | ||
966 | bytebuffer_offset++; | ||
967 | } | ||
968 | |||
969 | /* Validate decompression - crc */ | ||
970 | if (stored_crc != (gunzip_crc ^ 0xffffffffL)) { | ||
971 | bb_error_msg("crc error"); | ||
972 | } | ||
973 | |||
974 | /* Validate decompression - size */ | ||
975 | if (gunzip_bytes_out != | ||
976 | (bytebuffer[bytebuffer_offset] | (bytebuffer[bytebuffer_offset+1] << 8) | | ||
977 | (bytebuffer[bytebuffer_offset+2] << 16) | (bytebuffer[bytebuffer_offset+3] << 24))) { | ||
978 | bb_error_msg("Incorrect length"); | ||
979 | } | ||
980 | |||
981 | return 0; | ||
982 | } | ||
diff --git a/busybox/archival/libunarchive/filter_accept_all.c b/busybox/archival/libunarchive/filter_accept_all.c new file mode 100644 index 000000000..baf9e4b71 --- /dev/null +++ b/busybox/archival/libunarchive/filter_accept_all.c | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 by Glenn McGrath | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include <fnmatch.h> | ||
20 | #include <stdlib.h> | ||
21 | |||
22 | #include "unarchive.h" | ||
23 | |||
24 | /* Accept any non-null name, its not really a filter at all */ | ||
25 | extern char filter_accept_all(archive_handle_t *archive_handle) | ||
26 | { | ||
27 | if (archive_handle->file_header->name) { | ||
28 | return(EXIT_SUCCESS); | ||
29 | } else { | ||
30 | return(EXIT_FAILURE); | ||
31 | } | ||
32 | } | ||
diff --git a/busybox/archival/libunarchive/filter_accept_list.c b/busybox/archival/libunarchive/filter_accept_list.c new file mode 100644 index 000000000..e1c4827bf --- /dev/null +++ b/busybox/archival/libunarchive/filter_accept_list.c | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 by Glenn McGrath | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include <fnmatch.h> | ||
20 | #include <stdlib.h> | ||
21 | |||
22 | #include "unarchive.h" | ||
23 | |||
24 | /* | ||
25 | * Accept names that are in the accept list, ignoring reject list. | ||
26 | */ | ||
27 | extern char filter_accept_list(archive_handle_t *archive_handle) | ||
28 | { | ||
29 | if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) { | ||
30 | return(EXIT_SUCCESS); | ||
31 | } else { | ||
32 | return(EXIT_FAILURE); | ||
33 | } | ||
34 | } | ||
diff --git a/busybox/archival/libunarchive/filter_accept_list_reassign.c b/busybox/archival/libunarchive/filter_accept_list_reassign.c new file mode 100644 index 000000000..d0436549b --- /dev/null +++ b/busybox/archival/libunarchive/filter_accept_list_reassign.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 by Glenn McGrath | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include <stdlib.h> | ||
20 | #include <string.h> | ||
21 | #include <unistd.h> | ||
22 | |||
23 | #include "libbb.h" | ||
24 | #include "unarchive.h" | ||
25 | |||
26 | /* | ||
27 | * Reassign the subarchive metadata parser based on the filename extension | ||
28 | * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz | ||
29 | * or if its a .tar.bz2 make archive_handle->sub_archive handle that | ||
30 | */ | ||
31 | extern char filter_accept_list_reassign(archive_handle_t *archive_handle) | ||
32 | { | ||
33 | /* Check the file entry is in the accept list */ | ||
34 | if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) { | ||
35 | const char *name_ptr; | ||
36 | |||
37 | /* Extract the last 2 extensions */ | ||
38 | name_ptr = strrchr(archive_handle->file_header->name, '.'); | ||
39 | |||
40 | /* Modify the subarchive handler based on the extension */ | ||
41 | #ifdef CONFIG_FEATURE_DEB_TAR_GZ | ||
42 | if (strcmp(name_ptr, ".gz") == 0) { | ||
43 | archive_handle->action_data_subarchive = get_header_tar_gz; | ||
44 | return(EXIT_SUCCESS); | ||
45 | } | ||
46 | #endif | ||
47 | #ifdef CONFIG_FEATURE_DEB_TAR_BZ2 | ||
48 | if (strcmp(name_ptr, ".bz2") == 0) { | ||
49 | archive_handle->action_data_subarchive = get_header_tar_bz2; | ||
50 | return(EXIT_SUCCESS); | ||
51 | } | ||
52 | #endif | ||
53 | } | ||
54 | return(EXIT_FAILURE); | ||
55 | } | ||
diff --git a/busybox/archival/libunarchive/filter_accept_reject_list.c b/busybox/archival/libunarchive/filter_accept_reject_list.c new file mode 100644 index 000000000..657f7a0bd --- /dev/null +++ b/busybox/archival/libunarchive/filter_accept_reject_list.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 by Glenn McGrath | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include <fnmatch.h> | ||
20 | #include <stdlib.h> | ||
21 | |||
22 | #include "unarchive.h" | ||
23 | |||
24 | /* | ||
25 | * Accept names that are in the accept list and not in the reject list | ||
26 | */ | ||
27 | extern char filter_accept_reject_list(archive_handle_t *archive_handle) | ||
28 | { | ||
29 | const char *key = archive_handle->file_header->name; | ||
30 | const llist_t *accept_entry = find_list_entry(archive_handle->accept, key); | ||
31 | const llist_t *reject_entry = find_list_entry(archive_handle->reject, key); | ||
32 | |||
33 | /* If the key is in a reject list fail */ | ||
34 | if (reject_entry) { | ||
35 | return(EXIT_FAILURE); | ||
36 | } | ||
37 | |||
38 | /* Fail if an accept list was specified and the key wasnt in there */ | ||
39 | if (archive_handle->accept && (accept_entry == NULL)) { | ||
40 | return(EXIT_FAILURE); | ||
41 | } | ||
42 | |||
43 | /* Accepted */ | ||
44 | return(EXIT_SUCCESS); | ||
45 | } | ||
diff --git a/busybox/archival/libunarchive/find_list_entry.c b/busybox/archival/libunarchive/find_list_entry.c new file mode 100644 index 000000000..7ed9e332f --- /dev/null +++ b/busybox/archival/libunarchive/find_list_entry.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <fnmatch.h> | ||
18 | #include <stdlib.h> | ||
19 | #include "unarchive.h" | ||
20 | |||
21 | extern const llist_t *find_list_entry(const llist_t *list, const char *filename) | ||
22 | { | ||
23 | while (list) { | ||
24 | if (fnmatch(list->data, filename, 0) == 0) { | ||
25 | return(list); | ||
26 | } | ||
27 | list = list->link; | ||
28 | } | ||
29 | return(NULL); | ||
30 | } | ||
diff --git a/busybox/archival/libunarchive/get_header_ar.c b/busybox/archival/libunarchive/get_header_ar.c new file mode 100644 index 000000000..ebb6f8cbe --- /dev/null +++ b/busybox/archival/libunarchive/get_header_ar.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <unistd.h> | ||
21 | #include "unarchive.h" | ||
22 | #include "libbb.h" | ||
23 | |||
24 | extern char get_header_ar(archive_handle_t *archive_handle) | ||
25 | { | ||
26 | file_header_t *typed = archive_handle->file_header; | ||
27 | union { | ||
28 | char raw[60]; | ||
29 | struct { | ||
30 | char name[16]; | ||
31 | char date[12]; | ||
32 | char uid[6]; | ||
33 | char gid[6]; | ||
34 | char mode[8]; | ||
35 | char size[10]; | ||
36 | char magic[2]; | ||
37 | } formated; | ||
38 | } ar; | ||
39 | #ifdef CONFIG_FEATURE_AR_LONG_FILENAMES | ||
40 | static char *ar_long_names; | ||
41 | static unsigned int ar_long_name_size; | ||
42 | #endif | ||
43 | |||
44 | /* dont use bb_xread as we want to handle the error ourself */ | ||
45 | if (read(archive_handle->src_fd, ar.raw, 60) != 60) { | ||
46 | /* End Of File */ | ||
47 | return(EXIT_FAILURE); | ||
48 | } | ||
49 | |||
50 | /* ar header starts on an even byte (2 byte aligned) | ||
51 | * '\n' is used for padding | ||
52 | */ | ||
53 | if (ar.raw[0] == '\n') { | ||
54 | /* fix up the header, we started reading 1 byte too early */ | ||
55 | memmove(ar.raw, &ar.raw[1], 59); | ||
56 | ar.raw[59] = bb_xread_char(archive_handle->src_fd); | ||
57 | archive_handle->offset++; | ||
58 | } | ||
59 | archive_handle->offset += 60; | ||
60 | |||
61 | /* align the headers based on the header magic */ | ||
62 | if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { | ||
63 | bb_error_msg_and_die("Invalid ar header"); | ||
64 | } | ||
65 | |||
66 | typed->mode = strtol(ar.formated.mode, NULL, 8); | ||
67 | typed->mtime = atoi(ar.formated.date); | ||
68 | typed->uid = atoi(ar.formated.uid); | ||
69 | typed->gid = atoi(ar.formated.gid); | ||
70 | typed->size = atoi(ar.formated.size); | ||
71 | |||
72 | /* long filenames have '/' as the first character */ | ||
73 | if (ar.formated.name[0] == '/') { | ||
74 | #ifdef CONFIG_FEATURE_AR_LONG_FILENAMES | ||
75 | if (ar.formated.name[1] == '/') { | ||
76 | /* If the second char is a '/' then this entries data section | ||
77 | * stores long filename for multiple entries, they are stored | ||
78 | * in static variable long_names for use in future entries */ | ||
79 | ar_long_name_size = typed->size; | ||
80 | ar_long_names = xmalloc(ar_long_name_size); | ||
81 | bb_xread_all(archive_handle->src_fd, ar_long_names, ar_long_name_size); | ||
82 | archive_handle->offset += ar_long_name_size; | ||
83 | /* This ar entries data section only contained filenames for other records | ||
84 | * they are stored in the static ar_long_names for future reference */ | ||
85 | return (get_header_ar(archive_handle)); /* Return next header */ | ||
86 | } else if (ar.formated.name[1] == ' ') { | ||
87 | /* This is the index of symbols in the file for compilers */ | ||
88 | data_skip(archive_handle); | ||
89 | archive_handle->offset += typed->size; | ||
90 | return (get_header_ar(archive_handle)); /* Return next header */ | ||
91 | } else { | ||
92 | /* The number after the '/' indicates the offset in the ar data section | ||
93 | (saved in variable long_name) that conatains the real filename */ | ||
94 | const unsigned int long_offset = atoi(&ar.formated.name[1]); | ||
95 | if (long_offset >= ar_long_name_size) { | ||
96 | bb_error_msg_and_die("Cant resolve long filename"); | ||
97 | } | ||
98 | typed->name = bb_xstrdup(ar_long_names + long_offset); | ||
99 | } | ||
100 | #else | ||
101 | bb_error_msg_and_die("long filenames not supported"); | ||
102 | #endif | ||
103 | } else { | ||
104 | /* short filenames */ | ||
105 | typed->name = bb_xstrndup(ar.formated.name, 16); | ||
106 | } | ||
107 | |||
108 | typed->name[strcspn(typed->name, " /")] = '\0'; | ||
109 | |||
110 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { | ||
111 | archive_handle->action_header(typed); | ||
112 | if (archive_handle->sub_archive) { | ||
113 | while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS); | ||
114 | } else { | ||
115 | archive_handle->action_data(archive_handle); | ||
116 | } | ||
117 | } else { | ||
118 | data_skip(archive_handle); | ||
119 | } | ||
120 | |||
121 | archive_handle->offset += typed->size; | ||
122 | /* Set the file pointer to the correct spot, we may have been reading a compressed file */ | ||
123 | lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET); | ||
124 | |||
125 | return(EXIT_SUCCESS); | ||
126 | } | ||
diff --git a/busybox/archival/libunarchive/get_header_cpio.c b/busybox/archival/libunarchive/get_header_cpio.c new file mode 100644 index 000000000..11925c4e3 --- /dev/null +++ b/busybox/archival/libunarchive/get_header_cpio.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <unistd.h> | ||
21 | #include <sys/sysmacros.h> /* major() and minor() */ | ||
22 | #include "unarchive.h" | ||
23 | #include "libbb.h" | ||
24 | |||
25 | typedef struct hardlinks_s { | ||
26 | file_header_t *entry; | ||
27 | int inode; | ||
28 | struct hardlinks_s *next; | ||
29 | } hardlinks_t; | ||
30 | |||
31 | extern char get_header_cpio(archive_handle_t *archive_handle) | ||
32 | { | ||
33 | static hardlinks_t *saved_hardlinks = NULL; | ||
34 | static unsigned short pending_hardlinks = 0; | ||
35 | file_header_t *file_header = archive_handle->file_header; | ||
36 | char cpio_header[110]; | ||
37 | int namesize; | ||
38 | char dummy[16]; | ||
39 | int major, minor, nlink, inode; | ||
40 | |||
41 | if (pending_hardlinks) { /* Deal with any pending hardlinks */ | ||
42 | hardlinks_t *tmp; | ||
43 | hardlinks_t *oldtmp; | ||
44 | |||
45 | tmp = saved_hardlinks; | ||
46 | oldtmp = NULL; | ||
47 | |||
48 | while (tmp) { | ||
49 | bb_error_msg_and_die("need to fix this\n"); | ||
50 | if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */ | ||
51 | file_header = tmp->entry; | ||
52 | if (oldtmp) { | ||
53 | oldtmp->next = tmp->next; /* Remove item from linked list */ | ||
54 | } else { | ||
55 | saved_hardlinks = tmp->next; | ||
56 | } | ||
57 | free(tmp); | ||
58 | continue; | ||
59 | } | ||
60 | oldtmp = tmp; | ||
61 | tmp = tmp->next; | ||
62 | } | ||
63 | pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */ | ||
64 | } | ||
65 | |||
66 | /* There can be padding before archive header */ | ||
67 | data_align(archive_handle, 4); | ||
68 | |||
69 | if (archive_xread_all_eof(archive_handle, cpio_header, 110) == 0) { | ||
70 | return(EXIT_FAILURE); | ||
71 | } | ||
72 | archive_handle->offset += 110; | ||
73 | |||
74 | if ((strncmp(&cpio_header[0], "07070", 5) != 0) || ((cpio_header[5] != '1') && (cpio_header[5] != '2'))) { | ||
75 | bb_error_msg_and_die("Unsupported cpio format, use newc or crc"); | ||
76 | } | ||
77 | |||
78 | { | ||
79 | unsigned long tmpsize; | ||
80 | sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", | ||
81 | dummy, &inode, (unsigned int*)&file_header->mode, | ||
82 | (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid, | ||
83 | &nlink, &file_header->mtime, &tmpsize, | ||
84 | dummy, &major, &minor, &namesize, dummy); | ||
85 | file_header->size = tmpsize; | ||
86 | } | ||
87 | |||
88 | file_header->name = (char *) xmalloc(namesize + 1); | ||
89 | archive_xread_all(archive_handle, file_header->name, namesize); /* Read in filename */ | ||
90 | file_header->name[namesize] = '\0'; | ||
91 | archive_handle->offset += namesize; | ||
92 | |||
93 | /* Update offset amount and skip padding before file contents */ | ||
94 | data_align(archive_handle, 4); | ||
95 | |||
96 | if (strcmp(file_header->name, "TRAILER!!!") == 0) { | ||
97 | printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */ | ||
98 | if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ | ||
99 | hardlinks_t *tmp = saved_hardlinks; | ||
100 | hardlinks_t *oldtmp = NULL; | ||
101 | while (tmp) { | ||
102 | bb_error_msg("%s not created: cannot resolve hardlink", tmp->entry->name); | ||
103 | oldtmp = tmp; | ||
104 | tmp = tmp->next; | ||
105 | free (oldtmp->entry->name); | ||
106 | free (oldtmp->entry); | ||
107 | free (oldtmp); | ||
108 | } | ||
109 | saved_hardlinks = NULL; | ||
110 | pending_hardlinks = 0; | ||
111 | } | ||
112 | return(EXIT_FAILURE); | ||
113 | } | ||
114 | |||
115 | if (S_ISLNK(file_header->mode)) { | ||
116 | file_header->link_name = (char *) xmalloc(file_header->size + 1); | ||
117 | archive_xread_all(archive_handle, file_header->link_name, file_header->size); | ||
118 | file_header->link_name[file_header->size] = '\0'; | ||
119 | archive_handle->offset += file_header->size; | ||
120 | file_header->size = 0; /* Stop possible seeks in future */ | ||
121 | } else { | ||
122 | file_header->link_name = NULL; | ||
123 | } | ||
124 | if (nlink > 1 && !S_ISDIR(file_header->mode)) { | ||
125 | if (file_header->size == 0) { /* Put file on a linked list for later */ | ||
126 | hardlinks_t *new = xmalloc(sizeof(hardlinks_t)); | ||
127 | new->next = saved_hardlinks; | ||
128 | new->inode = inode; | ||
129 | new->entry = file_header; | ||
130 | saved_hardlinks = new; | ||
131 | return(EXIT_SUCCESS); // Skip this one | ||
132 | } else { /* Found the file with data in */ | ||
133 | hardlinks_t *tmp = saved_hardlinks; | ||
134 | pending_hardlinks = 1; | ||
135 | while (tmp) { | ||
136 | if (tmp->inode == inode) { | ||
137 | tmp->entry->link_name = bb_xstrdup(file_header->name); | ||
138 | nlink--; | ||
139 | } | ||
140 | tmp = tmp->next; | ||
141 | } | ||
142 | if (nlink > 1) { | ||
143 | bb_error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?"); | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | file_header->device = makedev(major, minor); | ||
148 | |||
149 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { | ||
150 | archive_handle->action_data(archive_handle); | ||
151 | archive_handle->action_header(archive_handle->file_header); | ||
152 | } else { | ||
153 | data_skip(archive_handle); | ||
154 | } | ||
155 | |||
156 | archive_handle->offset += file_header->size; | ||
157 | |||
158 | free(file_header->link_name); | ||
159 | |||
160 | return (EXIT_SUCCESS); | ||
161 | } | ||
diff --git a/busybox/archival/libunarchive/get_header_tar.c b/busybox/archival/libunarchive/get_header_tar.c new file mode 100644 index 000000000..1ad9ac5e5 --- /dev/null +++ b/busybox/archival/libunarchive/get_header_tar.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | * | ||
16 | * FIXME: | ||
17 | * In privileged mode if uname and gname map to a uid and gid then use the | ||
18 | * mapped value instead of the uid/gid values in tar header | ||
19 | * | ||
20 | * References: | ||
21 | * GNU tar and star man pages, | ||
22 | * Opengroup's ustar interchange format, | ||
23 | * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html | ||
24 | */ | ||
25 | |||
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | #include "unarchive.h" | ||
30 | #include "libbb.h" | ||
31 | |||
32 | #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS | ||
33 | static char *longname = NULL; | ||
34 | static char *linkname = NULL; | ||
35 | #endif | ||
36 | |||
37 | extern char get_header_tar(archive_handle_t *archive_handle) | ||
38 | { | ||
39 | file_header_t *file_header = archive_handle->file_header; | ||
40 | union { | ||
41 | /* ustar header, Posix 1003.1 */ | ||
42 | unsigned char raw[512]; | ||
43 | struct { | ||
44 | char name[100]; /* 0-99 */ | ||
45 | char mode[8]; /* 100-107 */ | ||
46 | char uid[8]; /* 108-115 */ | ||
47 | char gid[8]; /* 116-123 */ | ||
48 | char size[12]; /* 124-135 */ | ||
49 | char mtime[12]; /* 136-147 */ | ||
50 | char chksum[8]; /* 148-155 */ | ||
51 | char typeflag; /* 156-156 */ | ||
52 | char linkname[100]; /* 157-256 */ | ||
53 | char magic[6]; /* 257-262 */ | ||
54 | char version[2]; /* 263-264 */ | ||
55 | char uname[32]; /* 265-296 */ | ||
56 | char gname[32]; /* 297-328 */ | ||
57 | char devmajor[8]; /* 329-336 */ | ||
58 | char devminor[8]; /* 337-344 */ | ||
59 | char prefix[155]; /* 345-499 */ | ||
60 | char padding[12]; /* 500-512 */ | ||
61 | } formated; | ||
62 | } tar; | ||
63 | long sum = 0; | ||
64 | long i; | ||
65 | |||
66 | /* Align header */ | ||
67 | data_align(archive_handle, 512); | ||
68 | |||
69 | if (bb_full_read(archive_handle->src_fd, tar.raw, 512) != 512) { | ||
70 | /* Assume end of file */ | ||
71 | return(EXIT_FAILURE); | ||
72 | } | ||
73 | archive_handle->offset += 512; | ||
74 | |||
75 | /* If there is no filename its an empty header */ | ||
76 | if (tar.formated.name[0] == 0) { | ||
77 | return(EXIT_SUCCESS); | ||
78 | } | ||
79 | |||
80 | /* Check header has valid magic, "ustar" is for the proper tar | ||
81 | * 0's are for the old tar format | ||
82 | */ | ||
83 | if (strncmp(tar.formated.magic, "ustar", 5) != 0) { | ||
84 | #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY | ||
85 | if (strncmp(tar.formated.magic, "\0\0\0\0\0", 5) != 0) | ||
86 | #endif | ||
87 | bb_error_msg_and_die("Invalid tar magic"); | ||
88 | } | ||
89 | /* Do checksum on headers */ | ||
90 | for (i = 0; i < 148 ; i++) { | ||
91 | sum += tar.raw[i]; | ||
92 | } | ||
93 | sum += ' ' * 8; | ||
94 | for (i = 156; i < 512 ; i++) { | ||
95 | sum += tar.raw[i]; | ||
96 | } | ||
97 | if (sum != strtol(tar.formated.chksum, NULL, 8)) { | ||
98 | bb_error_msg("Invalid tar header checksum"); | ||
99 | return(EXIT_FAILURE); | ||
100 | } | ||
101 | |||
102 | #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS | ||
103 | if (longname) { | ||
104 | file_header->name = longname; | ||
105 | longname = NULL; | ||
106 | } | ||
107 | else if (linkname) { | ||
108 | file_header->name = linkname; | ||
109 | linkname = NULL; | ||
110 | } else | ||
111 | #endif | ||
112 | if (tar.formated.prefix[0] == 0) { | ||
113 | file_header->name = strdup(tar.formated.name); | ||
114 | } else { | ||
115 | file_header->name = concat_path_file(tar.formated.prefix, tar.formated.name); | ||
116 | } | ||
117 | |||
118 | file_header->uid = strtol(tar.formated.uid, NULL, 8); | ||
119 | file_header->gid = strtol(tar.formated.gid, NULL, 8); | ||
120 | file_header->size = strtol(tar.formated.size, NULL, 8); | ||
121 | file_header->mtime = strtol(tar.formated.mtime, NULL, 8); | ||
122 | file_header->link_name = (tar.formated.linkname[0] != '\0') ? | ||
123 | bb_xstrdup(tar.formated.linkname) : NULL; | ||
124 | file_header->device = makedev(strtol(tar.formated.devmajor, NULL, 8), | ||
125 | strtol(tar.formated.devminor, NULL, 8)); | ||
126 | |||
127 | /* Set bits 0-11 of the files mode */ | ||
128 | file_header->mode = 07777 & strtol(tar.formated.mode, NULL, 8); | ||
129 | |||
130 | /* Set bits 12-15 of the files mode */ | ||
131 | switch (tar.formated.typeflag) { | ||
132 | /* busybox identifies hard links as being regular files with 0 size and a link name */ | ||
133 | case '1': | ||
134 | file_header->mode |= S_IFREG; | ||
135 | break; | ||
136 | case 'x': | ||
137 | case 'g': | ||
138 | bb_error_msg_and_die("pax is not tar"); | ||
139 | break; | ||
140 | case '7': | ||
141 | /* Reserved for high performance files, treat as normal file */ | ||
142 | case 0: | ||
143 | case '0': | ||
144 | #ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATABILITY | ||
145 | if (last_char_is(file_header->name, '/')) { | ||
146 | file_header->mode |= S_IFDIR; | ||
147 | } else | ||
148 | #endif | ||
149 | file_header->mode |= S_IFREG; | ||
150 | break; | ||
151 | case '2': | ||
152 | file_header->mode |= S_IFLNK; | ||
153 | break; | ||
154 | case '3': | ||
155 | file_header->mode |= S_IFCHR; | ||
156 | break; | ||
157 | case '4': | ||
158 | file_header->mode |= S_IFBLK; | ||
159 | break; | ||
160 | case '5': | ||
161 | file_header->mode |= S_IFDIR; | ||
162 | break; | ||
163 | case '6': | ||
164 | file_header->mode |= S_IFIFO; | ||
165 | break; | ||
166 | #ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS | ||
167 | case 'L': { | ||
168 | longname = xmalloc(file_header->size + 1); | ||
169 | archive_xread_all(archive_handle, longname, file_header->size); | ||
170 | longname[file_header->size] = '\0'; | ||
171 | archive_handle->offset += file_header->size; | ||
172 | |||
173 | return(get_header_tar(archive_handle)); | ||
174 | } | ||
175 | case 'K': { | ||
176 | linkname = xmalloc(file_header->size + 1); | ||
177 | archive_xread_all(archive_handle, linkname, file_header->size); | ||
178 | linkname[file_header->size] = '\0'; | ||
179 | archive_handle->offset += file_header->size; | ||
180 | |||
181 | file_header->name = linkname; | ||
182 | return(get_header_tar(archive_handle)); | ||
183 | } | ||
184 | case 'D': /* GNU dump dir */ | ||
185 | case 'M': /* Continuation of multi volume archive*/ | ||
186 | case 'N': /* Old GNU for names > 100 characters */ | ||
187 | case 'S': /* Sparse file */ | ||
188 | case 'V': /* Volume header */ | ||
189 | bb_error_msg("Ignoring GNU extension type %c", tar.formated.typeflag); | ||
190 | #endif | ||
191 | default: | ||
192 | bb_error_msg("Unknown typeflag: 0x%x", tar.formated.typeflag); | ||
193 | } | ||
194 | { /* Strip trailing '/' in directories */ | ||
195 | /* Must be done after mode is set as '/' is used to check if its a directory */ | ||
196 | char *tmp = last_char_is(file_header->name, '/'); | ||
197 | if (tmp) { | ||
198 | *tmp = '\0'; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { | ||
203 | archive_handle->action_header(archive_handle->file_header); | ||
204 | archive_handle->flags |= ARCHIVE_EXTRACT_QUIET; | ||
205 | archive_handle->action_data(archive_handle); | ||
206 | archive_handle->passed = llist_add_to(archive_handle->passed, file_header->name); | ||
207 | } else { | ||
208 | data_skip(archive_handle); | ||
209 | } | ||
210 | archive_handle->offset += file_header->size; | ||
211 | |||
212 | free(file_header->link_name); | ||
213 | |||
214 | return(EXIT_SUCCESS); | ||
215 | } | ||
diff --git a/busybox/archival/libunarchive/get_header_tar_bz2.c b/busybox/archival/libunarchive/get_header_tar_bz2.c new file mode 100644 index 000000000..d49d6b96a --- /dev/null +++ b/busybox/archival/libunarchive/get_header_tar_bz2.c | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | #include <sys/wait.h> | ||
19 | #include <signal.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <unistd.h> | ||
24 | #include "libbb.h" | ||
25 | #include "unarchive.h" | ||
26 | |||
27 | extern char get_header_tar_bz2(archive_handle_t *archive_handle) | ||
28 | { | ||
29 | /* Cant lseek over pipe's */ | ||
30 | archive_handle->seek = seek_by_char; | ||
31 | |||
32 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompressStream); | ||
33 | archive_handle->offset = 0; | ||
34 | while (get_header_tar(archive_handle) == EXIT_SUCCESS); | ||
35 | |||
36 | /* Can only do one file at a time */ | ||
37 | return(EXIT_FAILURE); | ||
38 | } | ||
diff --git a/busybox/archival/libunarchive/get_header_tar_gz.c b/busybox/archival/libunarchive/get_header_tar_gz.c new file mode 100644 index 000000000..9c708a951 --- /dev/null +++ b/busybox/archival/libunarchive/get_header_tar_gz.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdlib.h> | ||
18 | |||
19 | #include "libbb.h" | ||
20 | #include "unarchive.h" | ||
21 | |||
22 | extern char get_header_tar_gz(archive_handle_t *archive_handle) | ||
23 | { | ||
24 | unsigned char magic[2]; | ||
25 | |||
26 | /* Cant lseek over pipe's */ | ||
27 | archive_handle->seek = seek_by_char; | ||
28 | |||
29 | archive_xread_all(archive_handle, &magic, 2); | ||
30 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { | ||
31 | bb_error_msg_and_die("Invalid gzip magic"); | ||
32 | } | ||
33 | |||
34 | check_header_gzip(archive_handle->src_fd); | ||
35 | |||
36 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, inflate_gunzip); | ||
37 | archive_handle->offset = 0; | ||
38 | while (get_header_tar(archive_handle) == EXIT_SUCCESS); | ||
39 | |||
40 | /* Can only do one file at a time */ | ||
41 | return(EXIT_FAILURE); | ||
42 | } | ||
diff --git a/busybox/archival/libunarchive/header_list.c b/busybox/archival/libunarchive/header_list.c new file mode 100644 index 000000000..5849a762e --- /dev/null +++ b/busybox/archival/libunarchive/header_list.c | |||
@@ -0,0 +1,7 @@ | |||
1 | #include <stdio.h> | ||
2 | #include "unarchive.h" | ||
3 | |||
4 | extern void header_list(const file_header_t *file_header) | ||
5 | { | ||
6 | puts(file_header->name); | ||
7 | } | ||
diff --git a/busybox/archival/libunarchive/header_skip.c b/busybox/archival/libunarchive/header_skip.c new file mode 100644 index 000000000..4430178f8 --- /dev/null +++ b/busybox/archival/libunarchive/header_skip.c | |||
@@ -0,0 +1,7 @@ | |||
1 | #include <stdio.h> | ||
2 | #include "unarchive.h" | ||
3 | |||
4 | extern void header_skip(const file_header_t *file_header) | ||
5 | { | ||
6 | return; | ||
7 | } | ||
diff --git a/busybox/archival/libunarchive/header_verbose_list.c b/busybox/archival/libunarchive/header_verbose_list.c new file mode 100644 index 000000000..6739dd393 --- /dev/null +++ b/busybox/archival/libunarchive/header_verbose_list.c | |||
@@ -0,0 +1,29 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <time.h> | ||
4 | #include "libbb.h" | ||
5 | #include "unarchive.h" | ||
6 | |||
7 | extern void header_verbose_list(const file_header_t *file_header) | ||
8 | { | ||
9 | struct tm *mtime = localtime(&file_header->mtime); | ||
10 | |||
11 | printf("%s %d/%d%10u %4u-%02u-%02u %02u:%02u:%02u %s", | ||
12 | bb_mode_string(file_header->mode), | ||
13 | file_header->uid, | ||
14 | file_header->gid, | ||
15 | (unsigned int) file_header->size, | ||
16 | 1900 + mtime->tm_year, | ||
17 | 1 + mtime->tm_mon, | ||
18 | mtime->tm_mday, | ||
19 | mtime->tm_hour, | ||
20 | mtime->tm_min, | ||
21 | mtime->tm_sec, | ||
22 | file_header->name); | ||
23 | |||
24 | if (file_header->link_name) { | ||
25 | printf(" -> %s", file_header->link_name); | ||
26 | } | ||
27 | /* putchar isnt used anywhere else i dont think */ | ||
28 | puts(""); | ||
29 | } | ||
diff --git a/busybox/archival/libunarchive/init_handle.c b/busybox/archival/libunarchive/init_handle.c new file mode 100644 index 000000000..3cee84f67 --- /dev/null +++ b/busybox/archival/libunarchive/init_handle.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <unistd.h> | ||
18 | #include <string.h> | ||
19 | #include "libbb.h" | ||
20 | #include "unarchive.h" | ||
21 | |||
22 | archive_handle_t *init_handle(void) | ||
23 | { | ||
24 | archive_handle_t *archive_handle; | ||
25 | |||
26 | /* Initialise default values */ | ||
27 | archive_handle = xmalloc(sizeof(archive_handle_t)); | ||
28 | memset(archive_handle, 0, sizeof(archive_handle_t)); | ||
29 | archive_handle->file_header = xmalloc(sizeof(file_header_t)); | ||
30 | archive_handle->action_header = header_skip; | ||
31 | archive_handle->action_data = data_skip; | ||
32 | archive_handle->filter = filter_accept_all; | ||
33 | archive_handle->seek = seek_by_jump; | ||
34 | |||
35 | return(archive_handle); | ||
36 | } | ||
diff --git a/busybox/archival/libunarchive/open_transformer.c b/busybox/archival/libunarchive/open_transformer.c new file mode 100644 index 000000000..fb149fc0b --- /dev/null +++ b/busybox/archival/libunarchive/open_transformer.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdlib.h> | ||
18 | #include <unistd.h> | ||
19 | |||
20 | #include "libbb.h" | ||
21 | |||
22 | /* transformer(), more than meets the eye */ | ||
23 | extern int open_transformer(int src_fd, int (*transformer)(int src_fd, int dst_fd)) | ||
24 | { | ||
25 | int fd_pipe[2]; | ||
26 | int pid; | ||
27 | |||
28 | if (pipe(fd_pipe) != 0) { | ||
29 | bb_perror_msg_and_die("Can't create pipe"); | ||
30 | } | ||
31 | |||
32 | pid = fork(); | ||
33 | if (pid == -1) { | ||
34 | bb_perror_msg_and_die("Fork failed"); | ||
35 | } | ||
36 | |||
37 | if (pid == 0) { | ||
38 | /* child process */ | ||
39 | close(fd_pipe[0]); /* We don't wan't to read from the parent */ | ||
40 | transformer(src_fd, fd_pipe[1]); | ||
41 | close(fd_pipe[1]); /* Send EOF */ | ||
42 | close(src_fd); | ||
43 | exit(0); | ||
44 | /* notreached */ | ||
45 | } | ||
46 | |||
47 | /* parent process */ | ||
48 | close(fd_pipe[1]); /* Don't want to write to the child */ | ||
49 | |||
50 | return(fd_pipe[0]); | ||
51 | } | ||
diff --git a/busybox/archival/libunarchive/seek_by_char.c b/busybox/archival/libunarchive/seek_by_char.c new file mode 100644 index 000000000..a50d566f5 --- /dev/null +++ b/busybox/archival/libunarchive/seek_by_char.c | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <stdlib.h> | ||
18 | |||
19 | #include "unarchive.h" | ||
20 | #include "busybox.h" | ||
21 | |||
22 | /* If we are reading through a pipe(), or from stdin then we cant lseek, | ||
23 | * we must read and discard the data to skip over it. | ||
24 | * | ||
25 | * TODO: rename to seek_by_read | ||
26 | */ | ||
27 | extern void seek_by_char(const archive_handle_t *archive_handle, const unsigned int jump_size) | ||
28 | { | ||
29 | if (jump_size) { | ||
30 | bb_copyfd_size(archive_handle->src_fd, -1, jump_size); | ||
31 | } | ||
32 | } | ||
diff --git a/busybox/archival/libunarchive/seek_by_jump.c b/busybox/archival/libunarchive/seek_by_jump.c new file mode 100644 index 000000000..578870d9b --- /dev/null +++ b/busybox/archival/libunarchive/seek_by_jump.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | #include <errno.h> | ||
19 | #include <unistd.h> | ||
20 | #include <stdlib.h> | ||
21 | |||
22 | #include "libbb.h" | ||
23 | #include "unarchive.h" | ||
24 | |||
25 | extern void seek_by_jump(const archive_handle_t *archive_handle, const unsigned int amount) | ||
26 | { | ||
27 | if (lseek(archive_handle->src_fd, (off_t) amount, SEEK_CUR) == (off_t) -1) { | ||
28 | #ifdef CONFIG_FEATURE_UNARCHIVE_TAPE | ||
29 | if (errno == ESPIPE) { | ||
30 | seek_by_char(archive_handle, amount); | ||
31 | } else | ||
32 | #endif | ||
33 | bb_perror_msg_and_die("Seek failure"); | ||
34 | } | ||
35 | } | ||
diff --git a/busybox/archival/libunarchive/unpack_ar_archive.c b/busybox/archival/libunarchive/unpack_ar_archive.c new file mode 100644 index 000000000..e8f113bcf --- /dev/null +++ b/busybox/archival/libunarchive/unpack_ar_archive.c | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU Library General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
15 | */ | ||
16 | #include <fcntl.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <getopt.h> | ||
20 | #include "unarchive.h" | ||
21 | #include "busybox.h" | ||
22 | |||
23 | extern void unpack_ar_archive(archive_handle_t *ar_archive) | ||
24 | { | ||
25 | char magic[7]; | ||
26 | |||
27 | archive_xread_all(ar_archive, magic, 7); | ||
28 | if (strncmp(magic, "!<arch>", 7) != 0) { | ||
29 | bb_error_msg_and_die("Invalid ar magic"); | ||
30 | } | ||
31 | ar_archive->offset += 7; | ||
32 | |||
33 | while (get_header_ar(ar_archive) == EXIT_SUCCESS); | ||
34 | } | ||
diff --git a/busybox/archival/rpm.c b/busybox/archival/rpm.c new file mode 100644 index 000000000..30cdc93fb --- /dev/null +++ b/busybox/archival/rpm.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini rpm applet for busybox | ||
4 | * | ||
5 | * Copyright (C) 2001,2002 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 <unistd.h> | ||
24 | #include <signal.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <netinet/in.h> /* For ntohl & htonl function */ | ||
28 | #include <string.h> /* For strncmp */ | ||
29 | #include <sys/mman.h> /* For mmap */ | ||
30 | #include <time.h> /* For ctime */ | ||
31 | |||
32 | #include "busybox.h" | ||
33 | #include "unarchive.h" | ||
34 | |||
35 | #define RPM_HEADER_MAGIC "\216\255\350" | ||
36 | #define RPM_CHAR_TYPE 1 | ||
37 | #define RPM_INT8_TYPE 2 | ||
38 | #define RPM_INT16_TYPE 3 | ||
39 | #define RPM_INT32_TYPE 4 | ||
40 | /* #define RPM_INT64_TYPE 5 ---- These aren't supported (yet) */ | ||
41 | #define RPM_STRING_TYPE 6 | ||
42 | #define RPM_BIN_TYPE 7 | ||
43 | #define RPM_STRING_ARRAY_TYPE 8 | ||
44 | #define RPM_I18NSTRING_TYPE 9 | ||
45 | |||
46 | #define RPMTAG_NAME 1000 | ||
47 | #define RPMTAG_VERSION 1001 | ||
48 | #define RPMTAG_RELEASE 1002 | ||
49 | #define RPMTAG_SUMMARY 1004 | ||
50 | #define RPMTAG_DESCRIPTION 1005 | ||
51 | #define RPMTAG_BUILDTIME 1006 | ||
52 | #define RPMTAG_BUILDHOST 1007 | ||
53 | #define RPMTAG_SIZE 1009 | ||
54 | #define RPMTAG_VENDOR 1011 | ||
55 | #define RPMTAG_LICENSE 1014 | ||
56 | #define RPMTAG_PACKAGER 1015 | ||
57 | #define RPMTAG_GROUP 1016 | ||
58 | #define RPMTAG_URL 1020 | ||
59 | #define RPMTAG_PREIN 1023 | ||
60 | #define RPMTAG_POSTIN 1024 | ||
61 | #define RPMTAG_FILEFLAGS 1037 | ||
62 | #define RPMTAG_FILEUSERNAME 1039 | ||
63 | #define RPMTAG_FILEGROUPNAME 1040 | ||
64 | #define RPMTAG_SOURCERPM 1044 | ||
65 | #define RPMTAG_PREINPROG 1085 | ||
66 | #define RPMTAG_POSTINPROG 1086 | ||
67 | #define RPMTAG_PREFIXS 1098 | ||
68 | #define RPMTAG_DIRINDEXES 1116 | ||
69 | #define RPMTAG_BASENAMES 1117 | ||
70 | #define RPMTAG_DIRNAMES 1118 | ||
71 | #define RPMFILE_CONFIG (1 << 0) | ||
72 | #define RPMFILE_DOC (1 << 1) | ||
73 | |||
74 | enum rpm_functions_e { | ||
75 | rpm_query = 1, | ||
76 | rpm_install = 2, | ||
77 | rpm_query_info = 4, | ||
78 | rpm_query_package = 8, | ||
79 | rpm_query_list = 16, | ||
80 | rpm_query_list_doc = 32, | ||
81 | rpm_query_list_config = 64 | ||
82 | }; | ||
83 | |||
84 | typedef struct { | ||
85 | uint32_t tag; /* 4 byte tag */ | ||
86 | uint32_t type; /* 4 byte type */ | ||
87 | uint32_t offset; /* 4 byte offset */ | ||
88 | uint32_t count; /* 4 byte count */ | ||
89 | } rpm_index; | ||
90 | |||
91 | static void *map; | ||
92 | static rpm_index **mytags; | ||
93 | static int tagcount; | ||
94 | |||
95 | void extract_cpio_gz(int fd); | ||
96 | rpm_index **rpm_gettags(int fd, int *num_tags); | ||
97 | int bsearch_rpmtag(const void *key, const void *item); | ||
98 | char *rpm_getstring(int tag, int itemindex); | ||
99 | int rpm_getint(int tag, int itemindex); | ||
100 | int rpm_getcount(int tag); | ||
101 | void exec_script(int progtag, int datatag, char *prefix); | ||
102 | void fileaction_dobackup(char *filename, int fileref); | ||
103 | void fileaction_setowngrp(char *filename, int fileref); | ||
104 | void fileaction_list(char *filename, int itemno); | ||
105 | void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)); | ||
106 | |||
107 | int rpm_main(int argc, char **argv) | ||
108 | { | ||
109 | int opt = 0, func = 0, rpm_fd, offset; | ||
110 | |||
111 | while ((opt = getopt(argc, argv, "iqpldc")) != -1) { | ||
112 | switch (opt) { | ||
113 | case 'i': // First arg: Install mode, with q: Information | ||
114 | if (!func) func |= rpm_install; | ||
115 | else func |= rpm_query_info; | ||
116 | break; | ||
117 | case 'q': // First arg: Query mode | ||
118 | if (!func) func |= rpm_query; | ||
119 | else bb_show_usage(); | ||
120 | break; | ||
121 | case 'p': // Query a package | ||
122 | func |= rpm_query_package; | ||
123 | break; | ||
124 | case 'l': // List files in a package | ||
125 | func |= rpm_query_list; | ||
126 | break; | ||
127 | case 'd': // List doc files in a package (implies list) | ||
128 | func |= rpm_query_list; | ||
129 | func |= rpm_query_list_doc; | ||
130 | break; | ||
131 | case 'c': // List config files in a package (implies list) | ||
132 | func |= rpm_query_list; | ||
133 | func |= rpm_query_list_config; | ||
134 | break; | ||
135 | default: | ||
136 | bb_show_usage(); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | if (optind == argc) bb_show_usage(); | ||
141 | while (optind < argc) { | ||
142 | rpm_fd = bb_xopen(argv[optind], O_RDONLY); | ||
143 | mytags = rpm_gettags(rpm_fd, (int *) &tagcount); | ||
144 | offset = lseek(rpm_fd, 0, SEEK_CUR); | ||
145 | if (!mytags) { printf("Error reading rpm header\n"); exit(-1); } | ||
146 | map = mmap(0, offset > getpagesize() ? (offset + offset % getpagesize()) : getpagesize(), PROT_READ, MAP_SHARED, rpm_fd, 0); // Mimimum is one page | ||
147 | if (func & rpm_install) { | ||
148 | loop_through_files(RPMTAG_BASENAMES, fileaction_dobackup); /* Backup any config files */ | ||
149 | extract_cpio_gz(rpm_fd); // Extact the archive | ||
150 | loop_through_files(RPMTAG_BASENAMES, fileaction_setowngrp); /* Set the correct file uid/gid's */ | ||
151 | } else if (func & rpm_query && func & rpm_query_package) { | ||
152 | if (!((func & rpm_query_info) || (func & rpm_query_list))) { // If just a straight query, just give package name | ||
153 | printf("%s-%s-%s\n", rpm_getstring(RPMTAG_NAME, 0), rpm_getstring(RPMTAG_VERSION, 0), rpm_getstring(RPMTAG_RELEASE, 0)); | ||
154 | } | ||
155 | if (func & rpm_query_info) { | ||
156 | /* Do the nice printout */ | ||
157 | time_t bdate_time; | ||
158 | struct tm *bdate; | ||
159 | char bdatestring[50]; | ||
160 | printf("Name : %-29sRelocations: %s\n", rpm_getstring(RPMTAG_NAME, 0), rpm_getstring(RPMTAG_PREFIXS, 0) ? rpm_getstring(RPMTAG_PREFIXS, 0) : "(not relocateable)"); | ||
161 | printf("Version : %-34sVendor: %s\n", rpm_getstring(RPMTAG_VERSION, 0), rpm_getstring(RPMTAG_VENDOR, 0) ? rpm_getstring(RPMTAG_VENDOR, 0) : "(none)"); | ||
162 | bdate_time = rpm_getint(RPMTAG_BUILDTIME, 0); | ||
163 | bdate = localtime((time_t *) &bdate_time); | ||
164 | strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate); | ||
165 | printf("Release : %-30sBuild Date: %s\n", rpm_getstring(RPMTAG_RELEASE, 0), bdatestring); | ||
166 | printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstring(RPMTAG_BUILDHOST, 0)); | ||
167 | printf("Group : %-30sSource RPM: %s\n", rpm_getstring(RPMTAG_GROUP, 0), rpm_getstring(RPMTAG_SOURCERPM, 0)); | ||
168 | printf("Size : %-33dLicense: %s\n", rpm_getint(RPMTAG_SIZE, 0), rpm_getstring(RPMTAG_LICENSE, 0)); | ||
169 | printf("URL : %s\n", rpm_getstring(RPMTAG_URL, 0)); | ||
170 | printf("Summary : %s\n", rpm_getstring(RPMTAG_SUMMARY, 0)); | ||
171 | printf("Description :\n%s\n", rpm_getstring(RPMTAG_DESCRIPTION, 0)); | ||
172 | } | ||
173 | if (func & rpm_query_list) { | ||
174 | int count, it, flags; | ||
175 | count = rpm_getcount(RPMTAG_BASENAMES); | ||
176 | for (it = 0; it < count; it++) { | ||
177 | flags = rpm_getint(RPMTAG_FILEFLAGS, it); | ||
178 | switch ((func & rpm_query_list_doc) + (func & rpm_query_list_config)) | ||
179 | { | ||
180 | case rpm_query_list_doc: if (!(flags & RPMFILE_DOC)) continue; break; | ||
181 | case rpm_query_list_config: if (!(flags & RPMFILE_CONFIG)) continue; break; | ||
182 | case rpm_query_list_doc + rpm_query_list_config: if (!((flags & RPMFILE_CONFIG) || (flags & RPMFILE_DOC))) continue; break; | ||
183 | } | ||
184 | printf("%s%s\n", rpm_getstring(RPMTAG_DIRNAMES, rpm_getint(RPMTAG_DIRINDEXES, it)), rpm_getstring(RPMTAG_BASENAMES, it)); | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | optind++; | ||
189 | free (mytags); | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | void extract_cpio_gz(int fd) { | ||
195 | archive_handle_t *archive_handle; | ||
196 | unsigned char magic[2]; | ||
197 | |||
198 | /* Initialise */ | ||
199 | archive_handle = init_handle(); | ||
200 | archive_handle->seek = seek_by_char; | ||
201 | //archive_handle->action_header = header_list; | ||
202 | archive_handle->action_data = data_extract_all; | ||
203 | archive_handle->flags |= ARCHIVE_PRESERVE_DATE; | ||
204 | archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS; | ||
205 | archive_handle->src_fd = fd; | ||
206 | archive_handle->offset = 0; | ||
207 | |||
208 | bb_xread_all(archive_handle->src_fd, &magic, 2); | ||
209 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { | ||
210 | bb_error_msg_and_die("Invalid gzip magic"); | ||
211 | } | ||
212 | check_header_gzip(archive_handle->src_fd); | ||
213 | chdir("/"); // Install RPM's to root | ||
214 | |||
215 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, inflate_gunzip); | ||
216 | archive_handle->offset = 0; | ||
217 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS); | ||
218 | } | ||
219 | |||
220 | |||
221 | rpm_index **rpm_gettags(int fd, int *num_tags) | ||
222 | { | ||
223 | rpm_index **tags = calloc(200, sizeof(struct rpmtag *)); /* We should never need mode than 200, and realloc later */ | ||
224 | int pass, tagindex = 0; | ||
225 | lseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ | ||
226 | |||
227 | for (pass = 0; pass < 2; pass++) { /* 1st pass is the signature headers, 2nd is the main stuff */ | ||
228 | struct { | ||
229 | char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ | ||
230 | uint8_t version; /* 1 byte version number */ | ||
231 | uint32_t reserved; /* 4 bytes reserved */ | ||
232 | uint32_t entries; /* Number of entries in header (4 bytes) */ | ||
233 | uint32_t size; /* Size of store (4 bytes) */ | ||
234 | } header; | ||
235 | rpm_index *tmpindex; | ||
236 | int storepos; | ||
237 | |||
238 | read(fd, &header, sizeof(header)); | ||
239 | if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) return NULL; /* Invalid magic */ | ||
240 | if (header.version != 1) return NULL; /* This program only supports v1 headers */ | ||
241 | header.size = ntohl(header.size); | ||
242 | header.entries = ntohl(header.entries); | ||
243 | storepos = lseek(fd,0,SEEK_CUR) + header.entries * 16; | ||
244 | |||
245 | while (header.entries--) { | ||
246 | tmpindex = tags[tagindex++] = malloc(sizeof(rpm_index)); | ||
247 | read(fd, tmpindex, sizeof(rpm_index)); | ||
248 | tmpindex->tag = ntohl(tmpindex->tag); tmpindex->type = ntohl(tmpindex->type); tmpindex->count = ntohl(tmpindex->count); | ||
249 | tmpindex->offset = storepos + ntohl(tmpindex->offset); | ||
250 | if (pass==0) tmpindex->tag -= 743; | ||
251 | } | ||
252 | lseek(fd, header.size, SEEK_CUR); /* Seek past store */ | ||
253 | if (pass==0) lseek(fd, (8 - (lseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR); /* Skip padding to 8 byte boundary after reading signature headers */ | ||
254 | } | ||
255 | tags = realloc(tags, tagindex * sizeof(struct rpmtag *)); /* realloc tags to save space */ | ||
256 | *num_tags = tagindex; | ||
257 | return tags; /* All done, leave the file at the start of the gzipped cpio archive */ | ||
258 | } | ||
259 | |||
260 | int bsearch_rpmtag(const void *key, const void *item) | ||
261 | { | ||
262 | rpm_index **tmp = (rpm_index **) item; | ||
263 | return ((int) key - tmp[0]->tag); | ||
264 | } | ||
265 | |||
266 | int rpm_getcount(int tag) | ||
267 | { | ||
268 | rpm_index **found; | ||
269 | found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | ||
270 | if (!found) return 0; | ||
271 | else return found[0]->count; | ||
272 | } | ||
273 | |||
274 | char *rpm_getstring(int tag, int itemindex) | ||
275 | { | ||
276 | rpm_index **found; | ||
277 | found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | ||
278 | if (!found || itemindex >= found[0]->count) return NULL; | ||
279 | if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) { | ||
280 | int n; | ||
281 | char *tmpstr = (char *) (map + found[0]->offset); | ||
282 | for (n=0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; | ||
283 | return tmpstr; | ||
284 | } else return NULL; | ||
285 | } | ||
286 | |||
287 | int rpm_getint(int tag, int itemindex) | ||
288 | { | ||
289 | rpm_index **found; | ||
290 | int n, *tmpint; | ||
291 | found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); | ||
292 | if (!found || itemindex >= found[0]->count) return -1; | ||
293 | tmpint = (int *) (map + found[0]->offset); | ||
294 | if (found[0]->type == RPM_INT32_TYPE) { | ||
295 | for (n=0; n<itemindex; n++) tmpint = (int *) ((void *) tmpint + 4); | ||
296 | return ntohl(*tmpint); | ||
297 | } else if (found[0]->type == RPM_INT16_TYPE) { | ||
298 | for (n=0; n<itemindex; n++) tmpint = (int *) ((void *) tmpint + 2); | ||
299 | return ntohs(*tmpint); | ||
300 | } else if (found[0]->type == RPM_INT8_TYPE) { | ||
301 | for (n=0; n<itemindex; n++) tmpint = (int *) ((void *) tmpint + 1); | ||
302 | return ntohs(*tmpint); | ||
303 | } else return -1; | ||
304 | } | ||
305 | |||
306 | void fileaction_dobackup(char *filename, int fileref) | ||
307 | { | ||
308 | struct stat oldfile; | ||
309 | int stat_res; | ||
310 | char *newname; | ||
311 | if (rpm_getint(RPMTAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) { /* Only need to backup config files */ | ||
312 | stat_res = lstat (filename, &oldfile); | ||
313 | if (stat_res == 0 && S_ISREG(oldfile.st_mode)) { /* File already exists - really should check MD5's etc to see if different */ | ||
314 | newname = bb_xstrdup(filename); | ||
315 | newname = strcat(newname, ".rpmorig"); | ||
316 | copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS); | ||
317 | remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE); | ||
318 | free(newname); | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | |||
323 | void fileaction_setowngrp(char *filename, int fileref) | ||
324 | { | ||
325 | int uid, gid; | ||
326 | uid = my_getpwnam(rpm_getstring(RPMTAG_FILEUSERNAME, fileref)); | ||
327 | gid = my_getgrnam(rpm_getstring(RPMTAG_FILEGROUPNAME, fileref)); | ||
328 | chown (filename, uid, gid); | ||
329 | } | ||
330 | |||
331 | void fileaction_list(char *filename, int fileref) | ||
332 | { | ||
333 | printf("%s\n", filename); | ||
334 | } | ||
335 | |||
336 | void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)) | ||
337 | { | ||
338 | int count = 0; | ||
339 | char *filename, *tmp_dirname, *tmp_basename; | ||
340 | while (rpm_getstring(filetag, count)) { | ||
341 | tmp_dirname = rpm_getstring(RPMTAG_DIRNAMES, rpm_getint(RPMTAG_DIRINDEXES, count)); /* 1st put on the directory */ | ||
342 | tmp_basename = rpm_getstring(RPMTAG_BASENAMES, count); | ||
343 | filename = xmalloc(strlen(tmp_basename) + strlen(tmp_dirname) + 1); | ||
344 | strcpy(filename, tmp_dirname); /* First the directory name */ | ||
345 | strcat(filename, tmp_basename); /* then the filename */ | ||
346 | fileaction(filename, count++); | ||
347 | free(filename); | ||
348 | } | ||
349 | } | ||
diff --git a/busybox/archival/rpm2cpio.c b/busybox/archival/rpm2cpio.c new file mode 100644 index 000000000..5314e5300 --- /dev/null +++ b/busybox/archival/rpm2cpio.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini rpm2cpio 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 | #include <sys/types.h> | ||
22 | #include <netinet/in.h> /* For ntohl & htonl function */ | ||
23 | #include <fcntl.h> | ||
24 | #include <unistd.h> | ||
25 | #include <string.h> | ||
26 | #include "busybox.h" | ||
27 | #include "unarchive.h" | ||
28 | |||
29 | #define RPM_MAGIC "\355\253\356\333" | ||
30 | #define RPM_HEADER_MAGIC "\216\255\350" | ||
31 | |||
32 | struct rpm_lead { | ||
33 | unsigned char magic[4]; | ||
34 | uint8_t major, minor; | ||
35 | uint16_t type; | ||
36 | uint16_t archnum; | ||
37 | char name[66]; | ||
38 | uint16_t osnum; | ||
39 | uint16_t signature_type; | ||
40 | char reserved[16]; | ||
41 | }; | ||
42 | |||
43 | struct rpm_header { | ||
44 | char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ | ||
45 | uint8_t version; /* 1 byte version number */ | ||
46 | uint32_t reserved; /* 4 bytes reserved */ | ||
47 | uint32_t entries; /* Number of entries in header (4 bytes) */ | ||
48 | uint32_t size; /* Size of store (4 bytes) */ | ||
49 | }; | ||
50 | |||
51 | void skip_header(int rpm_fd) | ||
52 | { | ||
53 | struct rpm_header header; | ||
54 | |||
55 | bb_xread_all(rpm_fd, &header, sizeof(struct rpm_header)); | ||
56 | if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) { | ||
57 | bb_error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */ | ||
58 | } | ||
59 | if (header.version != 1) { | ||
60 | bb_error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ | ||
61 | } | ||
62 | header.entries = ntohl(header.entries); | ||
63 | header.size = ntohl(header.size); | ||
64 | lseek (rpm_fd, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ | ||
65 | lseek (rpm_fd, header.size, SEEK_CUR); /* Seek past store */ | ||
66 | } | ||
67 | |||
68 | /* No getopt required */ | ||
69 | extern int rpm2cpio_main(int argc, char **argv) | ||
70 | { | ||
71 | struct rpm_lead lead; | ||
72 | int rpm_fd; | ||
73 | unsigned char magic[2]; | ||
74 | |||
75 | if (argc == 1) { | ||
76 | rpm_fd = STDIN_FILENO; | ||
77 | } else { | ||
78 | rpm_fd = bb_xopen(argv[1], O_RDONLY); | ||
79 | } | ||
80 | |||
81 | bb_xread_all(rpm_fd, &lead, sizeof(struct rpm_lead)); | ||
82 | if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) { | ||
83 | bb_error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */ | ||
84 | } | ||
85 | |||
86 | /* Skip the signature header */ | ||
87 | skip_header(rpm_fd); | ||
88 | lseek(rpm_fd, (8 - (lseek(rpm_fd, 0, SEEK_CUR) % 8)) % 8, SEEK_CUR); | ||
89 | |||
90 | /* Skip the main header */ | ||
91 | skip_header(rpm_fd); | ||
92 | |||
93 | bb_xread_all(rpm_fd, &magic, 2); | ||
94 | if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { | ||
95 | bb_error_msg_and_die("Invalid gzip magic"); | ||
96 | } | ||
97 | |||
98 | check_header_gzip(rpm_fd); | ||
99 | if (inflate_gunzip(rpm_fd, STDOUT_FILENO) != 0) { | ||
100 | bb_error_msg("Error inflating"); | ||
101 | } | ||
102 | |||
103 | close(rpm_fd); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
diff --git a/busybox/archival/tar.c b/busybox/archival/tar.c new file mode 100644 index 000000000..950e21dd3 --- /dev/null +++ b/busybox/archival/tar.c | |||
@@ -0,0 +1,891 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini tar implementation for busybox | ||
4 | * | ||
5 | * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg | ||
6 | * Glenn McGrath <bug1@iinet.net.au> | ||
7 | * | ||
8 | * Note, that as of BusyBox-0.43, tar has been completely rewritten from the | ||
9 | * ground up. It still has remnants of the old code lying about, but it is | ||
10 | * very different now (i.e., cleaner, less global variables, etc.) | ||
11 | * | ||
12 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
13 | * | ||
14 | * Based in part in the tar implementation in sash | ||
15 | * Copyright (c) 1999 by David I. Bell | ||
16 | * Permission is granted to use, distribute, or modify this source, | ||
17 | * provided that this copyright notice remains intact. | ||
18 | * Permission to distribute sash derived code under the GPL has been granted. | ||
19 | * | ||
20 | * Based in part on the tar implementation from busybox-0.28 | ||
21 | * Copyright (C) 1995 Bruce Perens | ||
22 | * This is free software under the GNU General Public License. | ||
23 | * | ||
24 | * This program is free software; you can redistribute it and/or modify | ||
25 | * it under the terms of the GNU General Public License as published by | ||
26 | * the Free Software Foundation; either version 2 of the License, or | ||
27 | * (at your option) any later version. | ||
28 | * | ||
29 | * This program is distributed in the hope that it will be useful, | ||
30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
32 | * General Public License for more details. | ||
33 | * | ||
34 | * You should have received a copy of the GNU General Public License | ||
35 | * along with this program; if not, write to the Free Software | ||
36 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
37 | * | ||
38 | */ | ||
39 | |||
40 | #include <fcntl.h> | ||
41 | #include <getopt.h> | ||
42 | #include <search.h> | ||
43 | #include <stdio.h> | ||
44 | #include <stdlib.h> | ||
45 | #include <unistd.h> | ||
46 | #include <fnmatch.h> | ||
47 | #include <string.h> | ||
48 | #include <errno.h> | ||
49 | #include <signal.h> | ||
50 | #include <sys/wait.h> | ||
51 | #include <sys/socket.h> | ||
52 | #include <sys/sysmacros.h> /* major() and minor() */ | ||
53 | #include "unarchive.h" | ||
54 | #include "busybox.h" | ||
55 | |||
56 | #ifdef CONFIG_FEATURE_TAR_CREATE | ||
57 | |||
58 | /* Tar file constants */ | ||
59 | # define TAR_MAGIC "ustar" /* ustar and a null */ | ||
60 | # define TAR_VERSION " " /* Be compatable with GNU tar format */ | ||
61 | |||
62 | static const int TAR_BLOCK_SIZE = 512; | ||
63 | static const int TAR_MAGIC_LEN = 6; | ||
64 | static const int TAR_VERSION_LEN = 2; | ||
65 | |||
66 | /* POSIX tar Header Block, from POSIX 1003.1-1990 */ | ||
67 | enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */ | ||
68 | struct TarHeader { /* byte offset */ | ||
69 | char name[NAME_SIZE]; /* 0-99 */ | ||
70 | char mode[8]; /* 100-107 */ | ||
71 | char uid[8]; /* 108-115 */ | ||
72 | char gid[8]; /* 116-123 */ | ||
73 | char size[12]; /* 124-135 */ | ||
74 | char mtime[12]; /* 136-147 */ | ||
75 | char chksum[8]; /* 148-155 */ | ||
76 | char typeflag; /* 156-156 */ | ||
77 | char linkname[NAME_SIZE]; /* 157-256 */ | ||
78 | char magic[6]; /* 257-262 */ | ||
79 | char version[2]; /* 263-264 */ | ||
80 | char uname[32]; /* 265-296 */ | ||
81 | char gname[32]; /* 297-328 */ | ||
82 | char devmajor[8]; /* 329-336 */ | ||
83 | char devminor[8]; /* 337-344 */ | ||
84 | char prefix[155]; /* 345-499 */ | ||
85 | char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */ | ||
86 | }; | ||
87 | typedef struct TarHeader TarHeader; | ||
88 | |||
89 | /* | ||
90 | ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are | ||
91 | ** the only functions that deal with the HardLinkInfo structure. | ||
92 | ** Even these functions use the xxxHardLinkInfo() functions. | ||
93 | */ | ||
94 | typedef struct HardLinkInfo HardLinkInfo; | ||
95 | struct HardLinkInfo { | ||
96 | HardLinkInfo *next; /* Next entry in list */ | ||
97 | dev_t dev; /* Device number */ | ||
98 | ino_t ino; /* Inode number */ | ||
99 | short linkCount; /* (Hard) Link Count */ | ||
100 | char name[1]; /* Start of filename (must be last) */ | ||
101 | }; | ||
102 | |||
103 | /* Some info to be carried along when creating a new tarball */ | ||
104 | struct TarBallInfo { | ||
105 | char *fileName; /* File name of the tarball */ | ||
106 | int tarFd; /* Open-for-write file descriptor | ||
107 | for the tarball */ | ||
108 | struct stat statBuf; /* Stat info for the tarball, letting | ||
109 | us know the inode and device that the | ||
110 | tarball lives, so we can avoid trying | ||
111 | to include the tarball into itself */ | ||
112 | int verboseFlag; /* Whether to print extra stuff or not */ | ||
113 | const llist_t *excludeList; /* List of files to not include */ | ||
114 | HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ | ||
115 | HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ | ||
116 | }; | ||
117 | typedef struct TarBallInfo TarBallInfo; | ||
118 | |||
119 | /* A nice enum with all the possible tar file content types */ | ||
120 | enum TarFileType { | ||
121 | REGTYPE = '0', /* regular file */ | ||
122 | REGTYPE0 = '\0', /* regular file (ancient bug compat) */ | ||
123 | LNKTYPE = '1', /* hard link */ | ||
124 | SYMTYPE = '2', /* symbolic link */ | ||
125 | CHRTYPE = '3', /* character special */ | ||
126 | BLKTYPE = '4', /* block special */ | ||
127 | DIRTYPE = '5', /* directory */ | ||
128 | FIFOTYPE = '6', /* FIFO special */ | ||
129 | CONTTYPE = '7', /* reserved */ | ||
130 | GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ | ||
131 | GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ | ||
132 | }; | ||
133 | typedef enum TarFileType TarFileType; | ||
134 | |||
135 | /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ | ||
136 | static inline void addHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr, | ||
137 | struct stat *statbuf, | ||
138 | const char *name) | ||
139 | { | ||
140 | /* Note: hlInfoHeadPtr can never be NULL! */ | ||
141 | HardLinkInfo *hlInfo; | ||
142 | |||
143 | hlInfo = (HardLinkInfo *) xmalloc(sizeof(HardLinkInfo) + strlen(name)); | ||
144 | hlInfo->next = *hlInfoHeadPtr; | ||
145 | *hlInfoHeadPtr = hlInfo; | ||
146 | hlInfo->dev = statbuf->st_dev; | ||
147 | hlInfo->ino = statbuf->st_ino; | ||
148 | hlInfo->linkCount = statbuf->st_nlink; | ||
149 | strcpy(hlInfo->name, name); | ||
150 | } | ||
151 | |||
152 | static void freeHardLinkInfo(HardLinkInfo ** hlInfoHeadPtr) | ||
153 | { | ||
154 | HardLinkInfo *hlInfo = NULL; | ||
155 | HardLinkInfo *hlInfoNext = NULL; | ||
156 | |||
157 | if (hlInfoHeadPtr) { | ||
158 | hlInfo = *hlInfoHeadPtr; | ||
159 | while (hlInfo) { | ||
160 | hlInfoNext = hlInfo->next; | ||
161 | free(hlInfo); | ||
162 | hlInfo = hlInfoNext; | ||
163 | } | ||
164 | *hlInfoHeadPtr = NULL; | ||
165 | } | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | /* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ | ||
170 | static inline HardLinkInfo *findHardLinkInfo(HardLinkInfo * hlInfo, struct stat *statbuf) | ||
171 | { | ||
172 | while (hlInfo) { | ||
173 | if ((statbuf->st_ino == hlInfo->ino) && (statbuf->st_dev == hlInfo->dev)) | ||
174 | break; | ||
175 | hlInfo = hlInfo->next; | ||
176 | } | ||
177 | return (hlInfo); | ||
178 | } | ||
179 | |||
180 | /* Put an octal string into the specified buffer. | ||
181 | * The number is zero and space padded and possibly null padded. | ||
182 | * Returns TRUE if successful. */ | ||
183 | static int putOctal(char *cp, int len, long value) | ||
184 | { | ||
185 | int tempLength; | ||
186 | char tempBuffer[32]; | ||
187 | char *tempString = tempBuffer; | ||
188 | |||
189 | /* Create a string of the specified length with an initial space, | ||
190 | * leading zeroes and the octal number, and a trailing null. */ | ||
191 | sprintf(tempString, "%0*lo", len - 1, value); | ||
192 | |||
193 | /* If the string is too large, suppress the leading space. */ | ||
194 | tempLength = strlen(tempString) + 1; | ||
195 | if (tempLength > len) { | ||
196 | tempLength--; | ||
197 | tempString++; | ||
198 | } | ||
199 | |||
200 | /* If the string is still too large, suppress the trailing null. */ | ||
201 | if (tempLength > len) | ||
202 | tempLength--; | ||
203 | |||
204 | /* If the string is still too large, fail. */ | ||
205 | if (tempLength > len) | ||
206 | return FALSE; | ||
207 | |||
208 | /* Copy the string to the field. */ | ||
209 | memcpy(cp, tempString, len); | ||
210 | |||
211 | return TRUE; | ||
212 | } | ||
213 | |||
214 | /* Write out a tar header for the specified file/directory/whatever */ | ||
215 | static inline int writeTarHeader(struct TarBallInfo *tbInfo, | ||
216 | const char *header_name, | ||
217 | const char *real_name, struct stat *statbuf) | ||
218 | { | ||
219 | long chksum = 0; | ||
220 | struct TarHeader header; | ||
221 | const unsigned char *cp = (const unsigned char *) &header; | ||
222 | ssize_t size = sizeof(struct TarHeader); | ||
223 | |||
224 | memset(&header, 0, size); | ||
225 | |||
226 | strncpy(header.name, header_name, sizeof(header.name)); | ||
227 | |||
228 | putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); | ||
229 | putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); | ||
230 | putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); | ||
231 | putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ | ||
232 | putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); | ||
233 | strncpy(header.magic, TAR_MAGIC TAR_VERSION, | ||
234 | TAR_MAGIC_LEN + TAR_VERSION_LEN); | ||
235 | |||
236 | /* Enter the user and group names (default to root if it fails) */ | ||
237 | if (my_getpwuid(header.uname, statbuf->st_uid, sizeof(header.uname)) == NULL) | ||
238 | strcpy(header.uname, "root"); | ||
239 | if (my_getgrgid(header.gname, statbuf->st_gid, sizeof(header.gname)) == NULL) | ||
240 | strcpy(header.gname, "root"); | ||
241 | |||
242 | if (tbInfo->hlInfo) { | ||
243 | /* This is a hard link */ | ||
244 | header.typeflag = LNKTYPE; | ||
245 | strncpy(header.linkname, tbInfo->hlInfo->name, | ||
246 | sizeof(header.linkname)); | ||
247 | } else if (S_ISLNK(statbuf->st_mode)) { | ||
248 | char *lpath = xreadlink(real_name); | ||
249 | |||
250 | if (!lpath) /* Already printed err msg inside xreadlink() */ | ||
251 | return (FALSE); | ||
252 | header.typeflag = SYMTYPE; | ||
253 | strncpy(header.linkname, lpath, sizeof(header.linkname)); | ||
254 | free(lpath); | ||
255 | } else if (S_ISDIR(statbuf->st_mode)) { | ||
256 | header.typeflag = DIRTYPE; | ||
257 | strncat(header.name, "/", sizeof(header.name)); | ||
258 | } else if (S_ISCHR(statbuf->st_mode)) { | ||
259 | header.typeflag = CHRTYPE; | ||
260 | putOctal(header.devmajor, sizeof(header.devmajor), | ||
261 | major(statbuf->st_rdev)); | ||
262 | putOctal(header.devminor, sizeof(header.devminor), | ||
263 | minor(statbuf->st_rdev)); | ||
264 | } else if (S_ISBLK(statbuf->st_mode)) { | ||
265 | header.typeflag = BLKTYPE; | ||
266 | putOctal(header.devmajor, sizeof(header.devmajor), | ||
267 | major(statbuf->st_rdev)); | ||
268 | putOctal(header.devminor, sizeof(header.devminor), | ||
269 | minor(statbuf->st_rdev)); | ||
270 | } else if (S_ISFIFO(statbuf->st_mode)) { | ||
271 | header.typeflag = FIFOTYPE; | ||
272 | } else if (S_ISREG(statbuf->st_mode)) { | ||
273 | header.typeflag = REGTYPE; | ||
274 | putOctal(header.size, sizeof(header.size), statbuf->st_size); | ||
275 | } else { | ||
276 | bb_error_msg("%s: Unknown file type", real_name); | ||
277 | return (FALSE); | ||
278 | } | ||
279 | |||
280 | /* Calculate and store the checksum (i.e., the sum of all of the bytes of | ||
281 | * the header). The checksum field must be filled with blanks for the | ||
282 | * calculation. The checksum field is formatted differently from the | ||
283 | * other fields: it has [6] digits, a null, then a space -- rather than | ||
284 | * digits, followed by a null like the other fields... */ | ||
285 | memset(header.chksum, ' ', sizeof(header.chksum)); | ||
286 | cp = (const unsigned char *) &header; | ||
287 | while (size-- > 0) | ||
288 | chksum += *cp++; | ||
289 | putOctal(header.chksum, 7, chksum); | ||
290 | |||
291 | /* Now write the header out to disk */ | ||
292 | if ((size = | ||
293 | bb_full_write(tbInfo->tarFd, (char *) &header, | ||
294 | sizeof(struct TarHeader))) < 0) { | ||
295 | bb_error_msg(bb_msg_io_error, real_name); | ||
296 | return (FALSE); | ||
297 | } | ||
298 | /* Pad the header up to the tar block size */ | ||
299 | for (; size < TAR_BLOCK_SIZE; size++) { | ||
300 | write(tbInfo->tarFd, "\0", 1); | ||
301 | } | ||
302 | /* Now do the verbose thing (or not) */ | ||
303 | |||
304 | if (tbInfo->verboseFlag) { | ||
305 | FILE *vbFd = stdout; | ||
306 | |||
307 | if (tbInfo->tarFd == STDOUT_FILENO) /* If the archive goes to stdout, verbose to stderr */ | ||
308 | vbFd = stderr; | ||
309 | |||
310 | fprintf(vbFd, "%s\n", header.name); | ||
311 | } | ||
312 | |||
313 | return (TRUE); | ||
314 | } | ||
315 | |||
316 | # ifdef CONFIG_FEATURE_TAR_FROM | ||
317 | static inline int exclude_file(const llist_t *excluded_files, const char *file) | ||
318 | { | ||
319 | while (excluded_files) { | ||
320 | if (excluded_files->data[0] == '/') { | ||
321 | if (fnmatch(excluded_files->data, file, | ||
322 | FNM_PATHNAME | FNM_LEADING_DIR) == 0) | ||
323 | return 1; | ||
324 | } else { | ||
325 | const char *p; | ||
326 | |||
327 | for (p = file; p[0] != '\0'; p++) { | ||
328 | if ((p == file || p[-1] == '/') && p[0] != '/' && | ||
329 | fnmatch(excluded_files->data, p, | ||
330 | FNM_PATHNAME | FNM_LEADING_DIR) == 0) | ||
331 | return 1; | ||
332 | } | ||
333 | } | ||
334 | excluded_files = excluded_files->link; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | # endif | ||
340 | |||
341 | static int writeFileToTarball(const char *fileName, struct stat *statbuf, | ||
342 | void *userData) | ||
343 | { | ||
344 | struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData; | ||
345 | const char *header_name; | ||
346 | |||
347 | /* | ||
348 | ** Check to see if we are dealing with a hard link. | ||
349 | ** If so - | ||
350 | ** Treat the first occurance of a given dev/inode as a file while | ||
351 | ** treating any additional occurances as hard links. This is done | ||
352 | ** by adding the file information to the HardLinkInfo linked list. | ||
353 | */ | ||
354 | tbInfo->hlInfo = NULL; | ||
355 | if (statbuf->st_nlink > 1) { | ||
356 | tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf); | ||
357 | if (tbInfo->hlInfo == NULL) | ||
358 | addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, fileName); | ||
359 | } | ||
360 | |||
361 | /* It is against the rules to archive a socket */ | ||
362 | if (S_ISSOCK(statbuf->st_mode)) { | ||
363 | bb_error_msg("%s: socket ignored", fileName); | ||
364 | return (TRUE); | ||
365 | } | ||
366 | |||
367 | /* It is a bad idea to store the archive we are in the process of creating, | ||
368 | * so check the device and inode to be sure that this particular file isn't | ||
369 | * the new tarball */ | ||
370 | if (tbInfo->statBuf.st_dev == statbuf->st_dev && | ||
371 | tbInfo->statBuf.st_ino == statbuf->st_ino) { | ||
372 | bb_error_msg("%s: file is the archive; skipping", fileName); | ||
373 | return (TRUE); | ||
374 | } | ||
375 | |||
376 | header_name = fileName; | ||
377 | while (header_name[0] == '/') { | ||
378 | static int alreadyWarned = FALSE; | ||
379 | |||
380 | if (alreadyWarned == FALSE) { | ||
381 | bb_error_msg("Removing leading '/' from member names"); | ||
382 | alreadyWarned = TRUE; | ||
383 | } | ||
384 | header_name++; | ||
385 | } | ||
386 | |||
387 | if (strlen(fileName) >= NAME_SIZE) { | ||
388 | bb_error_msg(bb_msg_name_longer_than_foo, NAME_SIZE); | ||
389 | return (TRUE); | ||
390 | } | ||
391 | |||
392 | if (header_name[0] == '\0') | ||
393 | return TRUE; | ||
394 | |||
395 | # ifdef CONFIG_FEATURE_TAR_FROM | ||
396 | if (exclude_file(tbInfo->excludeList, header_name)) { | ||
397 | return SKIP; | ||
398 | } | ||
399 | # endif /* CONFIG_FEATURE_TAR_FROM */ | ||
400 | |||
401 | if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) { | ||
402 | return (FALSE); | ||
403 | } | ||
404 | |||
405 | /* Now, if the file is a regular file, copy it out to the tarball */ | ||
406 | if ((tbInfo->hlInfo == NULL) | ||
407 | && (S_ISREG(statbuf->st_mode))) { | ||
408 | int inputFileFd; | ||
409 | ssize_t readSize = 0; | ||
410 | |||
411 | /* open the file we want to archive, and make sure all is well */ | ||
412 | if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { | ||
413 | bb_perror_msg("%s: Cannot open", fileName); | ||
414 | return (FALSE); | ||
415 | } | ||
416 | |||
417 | /* write the file to the archive */ | ||
418 | readSize = bb_copyfd_eof(inputFileFd, tbInfo->tarFd); | ||
419 | |||
420 | /* Pad the file up to the tar block size */ | ||
421 | for (; (readSize % TAR_BLOCK_SIZE) != 0; readSize++) { | ||
422 | write(tbInfo->tarFd, "\0", 1); | ||
423 | } | ||
424 | close(inputFileFd); | ||
425 | } | ||
426 | |||
427 | return (TRUE); | ||
428 | } | ||
429 | |||
430 | static inline int writeTarFile(const int tar_fd, const int verboseFlag, | ||
431 | const unsigned long dereferenceFlag, const llist_t *include, | ||
432 | const llist_t *exclude, const int gzip) | ||
433 | { | ||
434 | #ifdef CONFIG_FEATURE_TAR_GZIP | ||
435 | int gzipDataPipe[2] = { -1, -1 }; | ||
436 | int gzipStatusPipe[2] = { -1, -1 }; | ||
437 | pid_t gzipPid = 0; | ||
438 | volatile int vfork_exec_errno = 0; | ||
439 | #endif | ||
440 | |||
441 | int errorFlag = FALSE; | ||
442 | ssize_t size; | ||
443 | struct TarBallInfo tbInfo; | ||
444 | |||
445 | tbInfo.hlInfoHead = NULL; | ||
446 | |||
447 | fchmod(tar_fd, 0644); | ||
448 | tbInfo.tarFd = tar_fd; | ||
449 | tbInfo.verboseFlag = verboseFlag; | ||
450 | |||
451 | /* Store the stat info for the tarball's file, so | ||
452 | * can avoid including the tarball into itself.... */ | ||
453 | if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) | ||
454 | bb_perror_msg_and_die("Couldnt stat tar file"); | ||
455 | |||
456 | #ifdef CONFIG_FEATURE_TAR_GZIP | ||
457 | if (gzip) { | ||
458 | if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) { | ||
459 | bb_perror_msg_and_die("Failed to create gzip pipe"); | ||
460 | } | ||
461 | |||
462 | signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ | ||
463 | |||
464 | # if __GNUC__ | ||
465 | /* Avoid vfork clobbering */ | ||
466 | (void) &include; | ||
467 | (void) &errorFlag; | ||
468 | # endif | ||
469 | |||
470 | gzipPid = vfork(); | ||
471 | |||
472 | if (gzipPid == 0) { | ||
473 | dup2(gzipDataPipe[0], 0); | ||
474 | close(gzipDataPipe[1]); | ||
475 | |||
476 | if (tbInfo.tarFd != 1) | ||
477 | dup2(tbInfo.tarFd, 1); | ||
478 | |||
479 | close(gzipStatusPipe[0]); | ||
480 | fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ | ||
481 | |||
482 | execl("/bin/gzip", "gzip", "-f", 0); | ||
483 | vfork_exec_errno = errno; | ||
484 | |||
485 | close(gzipStatusPipe[1]); | ||
486 | exit(-1); | ||
487 | } else if (gzipPid > 0) { | ||
488 | close(gzipDataPipe[0]); | ||
489 | close(gzipStatusPipe[1]); | ||
490 | |||
491 | while (1) { | ||
492 | char buf; | ||
493 | |||
494 | int n = bb_full_read(gzipStatusPipe[0], &buf, 1); | ||
495 | |||
496 | if (n == 0 && vfork_exec_errno != 0) { | ||
497 | errno = vfork_exec_errno; | ||
498 | bb_perror_msg_and_die("Could not exec gzip process"); | ||
499 | } else if ((n < 0) && (errno == EAGAIN || errno == EINTR)) | ||
500 | continue; /* try it again */ | ||
501 | break; | ||
502 | } | ||
503 | close(gzipStatusPipe[0]); | ||
504 | |||
505 | tbInfo.tarFd = gzipDataPipe[1]; | ||
506 | } else { | ||
507 | bb_perror_msg_and_die("Failed to vfork gzip process"); | ||
508 | } | ||
509 | } | ||
510 | #endif | ||
511 | |||
512 | tbInfo.excludeList = exclude; | ||
513 | |||
514 | /* Read the directory/files and iterate over them one at a time */ | ||
515 | while (include) { | ||
516 | if (!recursive_action(include->data, TRUE, dereferenceFlag, FALSE, | ||
517 | writeFileToTarball, writeFileToTarball, | ||
518 | (void *) &tbInfo)) { | ||
519 | errorFlag = TRUE; | ||
520 | } | ||
521 | include = include->link; | ||
522 | } | ||
523 | /* Write two empty blocks to the end of the archive */ | ||
524 | for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) { | ||
525 | write(tbInfo.tarFd, "\0", 1); | ||
526 | } | ||
527 | |||
528 | /* To be pedantically correct, we would check if the tarball | ||
529 | * is smaller than 20 tar blocks, and pad it if it was smaller, | ||
530 | * but that isn't necessary for GNU tar interoperability, and | ||
531 | * so is considered a waste of space */ | ||
532 | |||
533 | /* Hang up the tools, close up shop, head home */ | ||
534 | close(tbInfo.tarFd); | ||
535 | if (errorFlag) | ||
536 | bb_error_msg("Error exit delayed from previous errors"); | ||
537 | |||
538 | freeHardLinkInfo(&tbInfo.hlInfoHead); | ||
539 | |||
540 | #ifdef CONFIG_FEATURE_TAR_GZIP | ||
541 | if (gzip && gzipPid) { | ||
542 | if (waitpid(gzipPid, NULL, 0) == -1) | ||
543 | printf("Couldnt wait ?"); | ||
544 | } | ||
545 | #endif | ||
546 | |||
547 | return !errorFlag; | ||
548 | } | ||
549 | #endif /* tar_create */ | ||
550 | |||
551 | #ifdef CONFIG_FEATURE_TAR_FROM | ||
552 | static llist_t *append_file_list_to_list(llist_t *list) | ||
553 | { | ||
554 | FILE *src_stream; | ||
555 | llist_t *cur = list; | ||
556 | llist_t *tmp; | ||
557 | char *line; | ||
558 | llist_t *newlist = NULL; | ||
559 | |||
560 | while(cur) { | ||
561 | src_stream = bb_xfopen(cur->data, "r"); | ||
562 | tmp = cur; | ||
563 | cur = cur->link; | ||
564 | free(tmp); | ||
565 | while((line = bb_get_chomped_line_from_file(src_stream)) != NULL) { | ||
566 | newlist = llist_add_to(newlist, line); | ||
567 | } | ||
568 | fclose(src_stream); | ||
569 | } | ||
570 | return newlist; | ||
571 | } | ||
572 | #endif | ||
573 | |||
574 | #ifdef CONFIG_FEATURE_TAR_COMPRESS | ||
575 | static char get_header_tar_Z(archive_handle_t *archive_handle) | ||
576 | { | ||
577 | /* Cant lseek over pipe's */ | ||
578 | archive_handle->seek = seek_by_char; | ||
579 | |||
580 | /* do the decompression, and cleanup */ | ||
581 | if ((bb_xread_char(archive_handle->src_fd) != 0x1f) || (bb_xread_char(archive_handle->src_fd) != 0x9d)) { | ||
582 | bb_error_msg_and_die("Invalid magic"); | ||
583 | } | ||
584 | |||
585 | archive_handle->src_fd = open_transformer(archive_handle->src_fd, uncompress); | ||
586 | archive_handle->offset = 0; | ||
587 | while (get_header_tar(archive_handle) == EXIT_SUCCESS); | ||
588 | |||
589 | /* Can only do one file at a time */ | ||
590 | return(EXIT_FAILURE); | ||
591 | } | ||
592 | #endif | ||
593 | |||
594 | #define CTX_TEST (1 << 0) | ||
595 | #define CTX_EXTRACT (1 << 1) | ||
596 | #define TAR_OPT_BASEDIR (1 << 2) | ||
597 | #define TAR_OPT_TARNAME (1 << 3) | ||
598 | #define TAR_OPT_2STDOUT (1 << 4) | ||
599 | #define TAR_OPT_P (1 << 5) | ||
600 | #define TAR_OPT_VERBOSE (1 << 6) | ||
601 | #define TAR_OPT_KEEP_OLD (1 << 7) | ||
602 | |||
603 | #ifdef CONFIG_FEATURE_TAR_CREATE | ||
604 | # define CTX_CREATE (1 << 8) | ||
605 | # define TAR_OPT_DEREFERNCE (1 << 9) | ||
606 | # define TAR_OPT_STR_CREATE "ch" | ||
607 | # define TAR_OPT_FLAG_CREATE 2 | ||
608 | #else | ||
609 | //# define CTX_CREATE 0 | ||
610 | # define TAR_OPT_STR_CREATE "" | ||
611 | # define TAR_OPT_FLAG_CREATE 0 | ||
612 | #endif | ||
613 | |||
614 | #ifdef CONFIG_FEATURE_TAR_BZIP2 | ||
615 | # define TAR_OPT_BZIP2 (1 << (8 + TAR_OPT_FLAG_CREATE)) | ||
616 | # define TAR_OPT_STR_BZIP2 "j" | ||
617 | # define TAR_OPT_FLAG_BZIP2 1 | ||
618 | #else | ||
619 | # define TAR_OPT_STR_BZIP2 "" | ||
620 | # define TAR_OPT_FLAG_BZIP2 0 | ||
621 | #endif | ||
622 | |||
623 | #ifdef CONFIG_FEATURE_TAR_FROM | ||
624 | # define TAR_OPT_INCLUDE_FROM (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2)) | ||
625 | # define TAR_OPT_EXCLUDE_FROM (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + 1)) | ||
626 | # define TAR_OPT_STR_FROM "T:X:" | ||
627 | # define TAR_OPT_FLAG_FROM 2 | ||
628 | #else | ||
629 | # define TAR_OPT_STR_FROM "" | ||
630 | # define TAR_OPT_FLAG_FROM 0 | ||
631 | #endif | ||
632 | |||
633 | #ifdef CONFIG_FEATURE_TAR_GZIP | ||
634 | # define TAR_OPT_GZIP (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + TAR_OPT_FLAG_FROM)) | ||
635 | # define TAR_OPT_STR_GZIP "z" | ||
636 | # define TAR_OPT_FLAG_GZIP 1 | ||
637 | #else | ||
638 | # define TAR_OPT_STR_GZIP "" | ||
639 | # define TAR_OPT_FLAG_GZIP 0 | ||
640 | #endif | ||
641 | |||
642 | #ifdef CONFIG_FEATURE_TAR_COMPRESS | ||
643 | # define TAR_OPT_UNCOMPRESS (1 << (8 + TAR_OPT_FLAG_CREATE + TAR_OPT_FLAG_BZIP2 + TAR_OPT_FLAG_FROM + TAR_OPT_FLAG_GZIP)) | ||
644 | # define TAR_OPT_STR_COMPRESS "Z" | ||
645 | #else | ||
646 | # define TAR_OPT_STR_COMPRESS "" | ||
647 | #endif | ||
648 | |||
649 | static const char tar_options[]="txC:f:Opvk" \ | ||
650 | TAR_OPT_STR_CREATE \ | ||
651 | TAR_OPT_STR_BZIP2 \ | ||
652 | TAR_OPT_STR_FROM \ | ||
653 | TAR_OPT_STR_GZIP \ | ||
654 | TAR_OPT_STR_COMPRESS; | ||
655 | |||
656 | #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS | ||
657 | static const struct option tar_long_options[] = { | ||
658 | { "list", 0, NULL, 't' }, | ||
659 | { "extract", 0, NULL, 'x' }, | ||
660 | { "directory", 1, NULL, 'C' }, | ||
661 | { "file", 1, NULL, 'f' }, | ||
662 | { "to-stdout", 0, NULL, 'O' }, | ||
663 | { "same-permissions", 0, NULL, 'p' }, | ||
664 | { "verbose", 0, NULL, 'v' }, | ||
665 | { "keep-old", 0, NULL, 'k' }, | ||
666 | # ifdef CONFIG_FEATURE_TAR_CREATE | ||
667 | { "create", 0, NULL, 'c' }, | ||
668 | { "dereference", 0, NULL, 'h' }, | ||
669 | # endif | ||
670 | # ifdef CONFIG_FEATURE_TAR_BZIP2 | ||
671 | { "bzip2", 0, NULL, 'j' }, | ||
672 | # endif | ||
673 | # ifdef CONFIG_FEATURE_TAR_FROM | ||
674 | { "files-from", 1, NULL, 'T' }, | ||
675 | { "exclude-from", 1, NULL, 'X' }, | ||
676 | # endif | ||
677 | # ifdef CONFIG_FEATURE_TAR_GZIP | ||
678 | { "gzip", 0, NULL, 'z' }, | ||
679 | # endif | ||
680 | # ifdef CONFIG_FEATURE_TAR_COMPRESS | ||
681 | { "compress", 0, NULL, 'Z' }, | ||
682 | # endif | ||
683 | { 0, 0, 0, 0 } | ||
684 | }; | ||
685 | #endif | ||
686 | |||
687 | int tar_main(int argc, char **argv) | ||
688 | { | ||
689 | char (*get_header_ptr)(archive_handle_t *) = get_header_tar; | ||
690 | archive_handle_t *tar_handle; | ||
691 | char *base_dir = NULL; | ||
692 | const char *tar_filename = "-"; | ||
693 | unsigned long opt; | ||
694 | unsigned long ctx_flag = 0; | ||
695 | |||
696 | if (argc < 2) { | ||
697 | bb_show_usage(); | ||
698 | } | ||
699 | |||
700 | /* Prepend '-' to the first argument if required */ | ||
701 | if (argv[1][0] != '-') { | ||
702 | char *tmp; | ||
703 | |||
704 | bb_xasprintf(&tmp, "-%s", argv[1]); | ||
705 | argv[1] = tmp; | ||
706 | } | ||
707 | |||
708 | /* Initialise default values */ | ||
709 | tar_handle = init_handle(); | ||
710 | tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL; | ||
711 | |||
712 | bb_opt_complementaly = "c~tx:t~cx:x~ct:X*:T*"; | ||
713 | #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS | ||
714 | bb_applet_long_options = tar_long_options; | ||
715 | #endif | ||
716 | |||
717 | opt = bb_getopt_ulflags(argc, argv, tar_options, | ||
718 | &base_dir, /* Change to dir <optarg> */ | ||
719 | &tar_filename /* archive filename */ | ||
720 | #ifdef CONFIG_FEATURE_TAR_FROM | ||
721 | , &(tar_handle->accept), | ||
722 | &(tar_handle->reject) | ||
723 | #endif | ||
724 | ); | ||
725 | |||
726 | /* Check one and only one context option was given */ | ||
727 | if(opt & 0x80000000UL) { | ||
728 | bb_show_usage(); | ||
729 | } | ||
730 | #ifdef CONFIG_FEATURE_TAR_CREATE | ||
731 | ctx_flag = opt & (CTX_CREATE | CTX_TEST | CTX_EXTRACT); | ||
732 | #else | ||
733 | ctx_flag = opt & (CTX_TEST | CTX_EXTRACT); | ||
734 | #endif | ||
735 | if (ctx_flag == 0) { | ||
736 | bb_show_usage(); | ||
737 | } | ||
738 | if(ctx_flag & CTX_TEST) { | ||
739 | if ((tar_handle->action_header == header_list) || | ||
740 | (tar_handle->action_header == header_verbose_list)) { | ||
741 | tar_handle->action_header = header_verbose_list; | ||
742 | } else { | ||
743 | tar_handle->action_header = header_list; | ||
744 | } | ||
745 | } | ||
746 | if(ctx_flag & CTX_EXTRACT) { | ||
747 | if (tar_handle->action_data != data_extract_to_stdout) | ||
748 | tar_handle->action_data = data_extract_all; | ||
749 | } | ||
750 | if(opt & TAR_OPT_2STDOUT) { | ||
751 | /* To stdout */ | ||
752 | tar_handle->action_data = data_extract_to_stdout; | ||
753 | } | ||
754 | if(opt & TAR_OPT_VERBOSE) { | ||
755 | if ((tar_handle->action_header == header_list) || | ||
756 | (tar_handle->action_header == header_verbose_list)) | ||
757 | { | ||
758 | tar_handle->action_header = header_verbose_list; | ||
759 | } else { | ||
760 | tar_handle->action_header = header_list; | ||
761 | } | ||
762 | } | ||
763 | if (opt & TAR_OPT_KEEP_OLD) { | ||
764 | tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL; | ||
765 | } | ||
766 | |||
767 | #ifdef CONFIG_FEATURE_TAR_GZIP | ||
768 | if(opt & TAR_OPT_GZIP) { | ||
769 | get_header_ptr = get_header_tar_gz; | ||
770 | } | ||
771 | #endif | ||
772 | #ifdef CONFIG_FEATURE_TAR_BZIP2 | ||
773 | if(opt & TAR_OPT_BZIP2) { | ||
774 | get_header_ptr = get_header_tar_bz2; | ||
775 | } | ||
776 | #endif | ||
777 | #ifdef CONFIG_FEATURE_TAR_COMPRESS | ||
778 | if(opt & TAR_OPT_UNCOMPRESS) { | ||
779 | get_header_ptr = get_header_tar_Z; | ||
780 | } | ||
781 | #endif | ||
782 | #ifdef CONFIG_FEATURE_TAR_FROM | ||
783 | if(opt & TAR_OPT_EXCLUDE_FROM) { | ||
784 | tar_handle->reject = append_file_list_to_list(tar_handle->reject); | ||
785 | } | ||
786 | if(opt & TAR_OPT_INCLUDE_FROM) { | ||
787 | tar_handle->accept = append_file_list_to_list(tar_handle->accept); | ||
788 | } | ||
789 | #endif | ||
790 | |||
791 | /* Check if we are reading from stdin */ | ||
792 | if ((argv[optind]) && (*argv[optind] == '-')) { | ||
793 | /* Default is to read from stdin, so just skip to next arg */ | ||
794 | optind++; | ||
795 | } | ||
796 | |||
797 | /* Setup an array of filenames to work with */ | ||
798 | /* TODO: This is the same as in ar, separate function ? */ | ||
799 | while (optind < argc) { | ||
800 | char *filename_ptr = last_char_is(argv[optind], '/'); | ||
801 | if (filename_ptr) { | ||
802 | *filename_ptr = '\0'; | ||
803 | } | ||
804 | tar_handle->accept = llist_add_to(tar_handle->accept, argv[optind]); | ||
805 | optind++; | ||
806 | } | ||
807 | |||
808 | if ((tar_handle->accept) || (tar_handle->reject)) { | ||
809 | tar_handle->filter = filter_accept_reject_list; | ||
810 | } | ||
811 | |||
812 | /* Open the tar file */ | ||
813 | { | ||
814 | FILE *tar_stream; | ||
815 | int flags; | ||
816 | |||
817 | #ifdef CONFIG_FEATURE_TAR_CREATE | ||
818 | if (opt & CTX_CREATE) { | ||
819 | /* Make sure there is at least one file to tar up. */ | ||
820 | if (tar_handle->accept == NULL) { | ||
821 | bb_error_msg_and_die("Cowardly refusing to create an empty archive"); | ||
822 | } | ||
823 | tar_stream = stdout; | ||
824 | flags = O_WRONLY | O_CREAT | O_EXCL; | ||
825 | unlink(tar_filename); | ||
826 | } else | ||
827 | #endif | ||
828 | { | ||
829 | tar_stream = stdin; | ||
830 | flags = O_RDONLY; | ||
831 | } | ||
832 | |||
833 | if ((tar_filename[0] == '-') && (tar_filename[1] == '\0')) { | ||
834 | tar_handle->src_fd = fileno(tar_stream); | ||
835 | tar_handle->seek = seek_by_char; | ||
836 | } else { | ||
837 | tar_handle->src_fd = bb_xopen(tar_filename, flags); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | if ((base_dir) && (chdir(base_dir))) { | ||
842 | bb_perror_msg_and_die("Couldnt chdir to %s", base_dir); | ||
843 | } | ||
844 | |||
845 | #ifdef CONFIG_FEATURE_TAR_CREATE | ||
846 | /* create an archive */ | ||
847 | if (opt & CTX_CREATE) { | ||
848 | int verboseFlag = FALSE; | ||
849 | int gzipFlag = FALSE; | ||
850 | |||
851 | # ifdef CONFIG_FEATURE_TAR_GZIP | ||
852 | if (get_header_ptr == get_header_tar_gz) { | ||
853 | gzipFlag = TRUE; | ||
854 | } | ||
855 | # endif /* CONFIG_FEATURE_TAR_GZIP */ | ||
856 | # ifdef CONFIG_FEATURE_TAR_BZIP2 | ||
857 | if (get_header_ptr == get_header_tar_bz2) { | ||
858 | bb_error_msg_and_die("Creating bzip2 compressed archives is not currently supported."); | ||
859 | } | ||
860 | # endif /* CONFIG_FEATURE_TAR_BZIP2 */ | ||
861 | |||
862 | if ((tar_handle->action_header == header_list) || | ||
863 | (tar_handle->action_header == header_verbose_list)) { | ||
864 | verboseFlag = TRUE; | ||
865 | } | ||
866 | writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERNCE, tar_handle->accept, | ||
867 | tar_handle->reject, gzipFlag); | ||
868 | } else | ||
869 | #endif /* CONFIG_FEATURE_TAR_CREATE */ | ||
870 | { | ||
871 | while (get_header_ptr(tar_handle) == EXIT_SUCCESS); | ||
872 | |||
873 | /* Ckeck that every file that should have been extracted was */ | ||
874 | while (tar_handle->accept) { | ||
875 | if (find_list_entry(tar_handle->reject, tar_handle->accept->data) == NULL) { | ||
876 | if (find_list_entry(tar_handle->passed, tar_handle->accept->data) == NULL) { | ||
877 | bb_error_msg_and_die("%s: Not found in archive\n", tar_handle->accept->data); | ||
878 | } | ||
879 | } | ||
880 | tar_handle->accept = tar_handle->accept->link; | ||
881 | } | ||
882 | } | ||
883 | |||
884 | #ifdef CONFIG_FEATURE_CLEAN_UP | ||
885 | if (tar_handle->src_fd != STDIN_FILENO) { | ||
886 | close(tar_handle->src_fd); | ||
887 | } | ||
888 | #endif /* CONFIG_FEATURE_CLEAN_UP */ | ||
889 | |||
890 | return(EXIT_SUCCESS); | ||
891 | } | ||
diff --git a/busybox/archival/uncompress.c b/busybox/archival/uncompress.c new file mode 100644 index 000000000..48b4e2cad --- /dev/null +++ b/busybox/archival/uncompress.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Uncompress applet for busybox (c) 2002 Glenn McGrath | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <unistd.h> | ||
23 | #include <getopt.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <fcntl.h> | ||
27 | |||
28 | #include "libbb.h" | ||
29 | #include "unarchive.h" | ||
30 | |||
31 | #define GUNZIP_TO_STDOUT 1 | ||
32 | #define GUNZIP_FORCE 2 | ||
33 | |||
34 | extern int uncompress_main(int argc, char **argv) | ||
35 | { | ||
36 | int status = EXIT_SUCCESS; | ||
37 | unsigned long flags; | ||
38 | |||
39 | flags = bb_getopt_ulflags(argc, argv, "cf"); | ||
40 | |||
41 | while (optind < argc) { | ||
42 | const char *compressed_file = argv[optind++]; | ||
43 | const char *delete_path = NULL; | ||
44 | char *uncompressed_file = NULL; | ||
45 | int src_fd; | ||
46 | int dst_fd; | ||
47 | |||
48 | if (strcmp(compressed_file, "-") == 0) { | ||
49 | src_fd = STDIN_FILENO; | ||
50 | flags |= GUNZIP_TO_STDOUT; | ||
51 | } else { | ||
52 | src_fd = bb_xopen(compressed_file, O_RDONLY); | ||
53 | } | ||
54 | |||
55 | /* Check that the input is sane. */ | ||
56 | if (isatty(src_fd) && ((flags & GUNZIP_FORCE) == 0)) { | ||
57 | bb_error_msg_and_die | ||
58 | ("compressed data not read from terminal. Use -f to force it."); | ||
59 | } | ||
60 | |||
61 | /* Set output filename and number */ | ||
62 | if (flags & GUNZIP_TO_STDOUT) { | ||
63 | dst_fd = STDOUT_FILENO; | ||
64 | } else { | ||
65 | struct stat stat_buf; | ||
66 | char *extension; | ||
67 | |||
68 | uncompressed_file = bb_xstrdup(compressed_file); | ||
69 | |||
70 | extension = strrchr(uncompressed_file, '.'); | ||
71 | if (!extension || (strcmp(extension, ".Z") != 0)) { | ||
72 | bb_error_msg_and_die("Invalid extension"); | ||
73 | } | ||
74 | *extension = '\0'; | ||
75 | |||
76 | /* Open output file */ | ||
77 | dst_fd = bb_xopen(uncompressed_file, O_WRONLY | O_CREAT); | ||
78 | |||
79 | /* Set permissions on the file */ | ||
80 | stat(compressed_file, &stat_buf); | ||
81 | chmod(uncompressed_file, stat_buf.st_mode); | ||
82 | |||
83 | /* If unzip succeeds remove the old file */ | ||
84 | delete_path = compressed_file; | ||
85 | } | ||
86 | |||
87 | /* do the decompression, and cleanup */ | ||
88 | if ((bb_xread_char(src_fd) != 0x1f) || (bb_xread_char(src_fd) != 0x9d)) { | ||
89 | bb_error_msg_and_die("Invalid magic"); | ||
90 | } | ||
91 | |||
92 | status = uncompress(src_fd, dst_fd); | ||
93 | |||
94 | if ((status != EXIT_SUCCESS) && (uncompressed_file)) { | ||
95 | /* Unzip failed, remove the uncomressed file instead of compressed file */ | ||
96 | delete_path = uncompressed_file; | ||
97 | } | ||
98 | |||
99 | if (dst_fd != STDOUT_FILENO) { | ||
100 | close(dst_fd); | ||
101 | } | ||
102 | if (src_fd != STDIN_FILENO) { | ||
103 | close(src_fd); | ||
104 | } | ||
105 | |||
106 | /* delete_path will be NULL if in test mode or from stdin */ | ||
107 | if (delete_path && (unlink(delete_path) == -1)) { | ||
108 | bb_error_msg_and_die("Couldn't remove %s", delete_path); | ||
109 | } | ||
110 | |||
111 | free(uncompressed_file); | ||
112 | } | ||
113 | |||
114 | return status; | ||
115 | } | ||
diff --git a/busybox/archival/unzip.c b/busybox/archival/unzip.c new file mode 100644 index 000000000..eea2f5438 --- /dev/null +++ b/busybox/archival/unzip.c | |||
@@ -0,0 +1,247 @@ | |||
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 | /* For reference see | ||
24 | * http://www.pkware.com/products/enterprise/white_papers/appnote.txt | ||
25 | * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip | ||
26 | */ | ||
27 | |||
28 | /* TODO Endian issues, exclude, should we accept input from stdin ? */ | ||
29 | |||
30 | #include <fcntl.h> | ||
31 | #include <getopt.h> | ||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <unistd.h> | ||
35 | #include "unarchive.h" | ||
36 | #include "busybox.h" | ||
37 | |||
38 | #define ZIP_FILEHEADER_MAGIC 0x04034b50 | ||
39 | #define ZIP_CDS_MAGIC 0x02014b50 | ||
40 | #define ZIP_CDS_END_MAGIC 0x06054b50 | ||
41 | #define ZIP_DD_MAGIC 0x08074b50 | ||
42 | |||
43 | extern unsigned int gunzip_crc; | ||
44 | extern unsigned int gunzip_bytes_out; | ||
45 | |||
46 | static void header_list_unzip(const file_header_t *file_header) | ||
47 | { | ||
48 | printf(" inflating: %s\n", file_header->name); | ||
49 | } | ||
50 | |||
51 | static void header_verbose_list_unzip(const file_header_t *file_header) | ||
52 | { | ||
53 | unsigned int dostime = (unsigned int) file_header->mtime; | ||
54 | |||
55 | /* can printf arguments cut of the decade component ? */ | ||
56 | unsigned short year = 1980 + ((dostime & 0xfe000000) >> 25); | ||
57 | while (year >= 100) { | ||
58 | year -= 100; | ||
59 | } | ||
60 | |||
61 | printf("%9u %02u-%02u-%02u %02u:%02u %s\n", | ||
62 | (unsigned int) file_header->size, | ||
63 | (dostime & 0x01e00000) >> 21, | ||
64 | (dostime & 0x001f0000) >> 16, | ||
65 | year, | ||
66 | (dostime & 0x0000f800) >> 11, | ||
67 | (dostime & 0x000007e0) >> 5, | ||
68 | file_header->name); | ||
69 | } | ||
70 | |||
71 | extern int unzip_main(int argc, char **argv) | ||
72 | { | ||
73 | union { | ||
74 | unsigned char raw[26]; | ||
75 | struct { | ||
76 | unsigned short version; /* 0-1 */ | ||
77 | unsigned short flags; /* 2-3 */ | ||
78 | unsigned short method; /* 4-5 */ | ||
79 | unsigned short modtime; /* 6-7 */ | ||
80 | unsigned short moddate; /* 8-9 */ | ||
81 | unsigned int crc32 __attribute__ ((packed)); /* 10-13 */ | ||
82 | unsigned int cmpsize __attribute__ ((packed));; /* 14-17 */ | ||
83 | unsigned int ucmpsize __attribute__ ((packed));; /* 18-21 */ | ||
84 | unsigned short filename_len; /* 22-23 */ | ||
85 | unsigned short extra_len; /* 24-25 */ | ||
86 | } formated __attribute__ ((packed)); | ||
87 | } zip_header; | ||
88 | |||
89 | archive_handle_t *archive_handle; | ||
90 | unsigned int total_size = 0; | ||
91 | unsigned int total_entries = 0; | ||
92 | char *base_dir = NULL; | ||
93 | int opt = 0; | ||
94 | |||
95 | /* Initialise */ | ||
96 | archive_handle = init_handle(); | ||
97 | archive_handle->action_data = NULL; | ||
98 | archive_handle->action_header = header_list_unzip; | ||
99 | |||
100 | while ((opt = getopt(argc, argv, "lnopqd:")) != -1) { | ||
101 | switch (opt) { | ||
102 | case 'l': /* list */ | ||
103 | archive_handle->action_header = header_verbose_list_unzip; | ||
104 | archive_handle->action_data = data_skip; | ||
105 | break; | ||
106 | case 'n': /* never overwright existing files */ | ||
107 | break; | ||
108 | case 'o': | ||
109 | archive_handle->flags = ARCHIVE_EXTRACT_UNCONDITIONAL; | ||
110 | break; | ||
111 | case 'p': /* extract files to stdout */ | ||
112 | archive_handle->action_data = data_extract_to_stdout; | ||
113 | break; | ||
114 | case 'q': /* Extract files quietly */ | ||
115 | archive_handle->action_header = header_skip; | ||
116 | break; | ||
117 | case 'd': /* Extract files to specified base directory*/ | ||
118 | base_dir = optarg; | ||
119 | break; | ||
120 | #if 0 | ||
121 | case 'x': /* Exclude the specified files */ | ||
122 | archive_handle->filter = filter_accept_reject_list; | ||
123 | break; | ||
124 | #endif | ||
125 | default: | ||
126 | bb_show_usage(); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if (argc == optind) { | ||
131 | bb_show_usage(); | ||
132 | } | ||
133 | |||
134 | printf("Archive: %s\n", argv[optind]); | ||
135 | if (archive_handle->action_header == header_verbose_list_unzip) { | ||
136 | printf(" Length Date Time Name\n"); | ||
137 | printf(" -------- ---- ---- ----\n"); | ||
138 | } | ||
139 | |||
140 | if (*argv[optind] == '-') { | ||
141 | archive_handle->src_fd = STDIN_FILENO; | ||
142 | archive_handle->seek = seek_by_char; | ||
143 | } else { | ||
144 | archive_handle->src_fd = bb_xopen(argv[optind++], O_RDONLY); | ||
145 | } | ||
146 | |||
147 | if ((base_dir) && (chdir(base_dir))) { | ||
148 | bb_perror_msg_and_die("Couldnt chdir"); | ||
149 | } | ||
150 | |||
151 | while (optind < argc) { | ||
152 | archive_handle->filter = filter_accept_list; | ||
153 | archive_handle->accept = llist_add_to(archive_handle->accept, argv[optind]); | ||
154 | optind++; | ||
155 | } | ||
156 | |||
157 | while (1) { | ||
158 | unsigned int magic; | ||
159 | int dst_fd; | ||
160 | |||
161 | /* TODO Endian issues */ | ||
162 | archive_xread_all(archive_handle, &magic, 4); | ||
163 | archive_handle->offset += 4; | ||
164 | |||
165 | if (magic == ZIP_CDS_MAGIC) { | ||
166 | break; | ||
167 | } | ||
168 | else if (magic != ZIP_FILEHEADER_MAGIC) { | ||
169 | bb_error_msg_and_die("Invlaide zip magic"); | ||
170 | } | ||
171 | |||
172 | /* Read the file header */ | ||
173 | archive_xread_all(archive_handle, zip_header.raw, 26); | ||
174 | archive_handle->offset += 26; | ||
175 | archive_handle->file_header->mode = S_IFREG | 0777; | ||
176 | |||
177 | if (zip_header.formated.method != 8) { | ||
178 | bb_error_msg_and_die("Unsupported compression method %d\n", zip_header.formated.method); | ||
179 | } | ||
180 | |||
181 | /* Read filename */ | ||
182 | archive_handle->file_header->name = xmalloc(zip_header.formated.filename_len + 1); | ||
183 | archive_xread_all(archive_handle, archive_handle->file_header->name, zip_header.formated.filename_len); | ||
184 | archive_handle->offset += zip_header.formated.filename_len; | ||
185 | archive_handle->file_header->name[zip_header.formated.filename_len] = '\0'; | ||
186 | |||
187 | /* Skip extra header bits */ | ||
188 | archive_handle->file_header->size = zip_header.formated.extra_len; | ||
189 | data_skip(archive_handle); | ||
190 | archive_handle->offset += zip_header.formated.extra_len; | ||
191 | |||
192 | /* Handle directories */ | ||
193 | archive_handle->file_header->mode = S_IFREG | 0777; | ||
194 | if (last_char_is(archive_handle->file_header->name, '/')) { | ||
195 | archive_handle->file_header->mode ^= S_IFREG; | ||
196 | archive_handle->file_header->mode |= S_IFDIR; | ||
197 | } | ||
198 | |||
199 | /* Data section */ | ||
200 | archive_handle->file_header->size = zip_header.formated.cmpsize; | ||
201 | if (archive_handle->action_data) { | ||
202 | archive_handle->action_data(archive_handle); | ||
203 | } else { | ||
204 | dst_fd = bb_xopen(archive_handle->file_header->name, O_WRONLY | O_CREAT); | ||
205 | inflate_init(zip_header.formated.cmpsize); | ||
206 | inflate_unzip(archive_handle->src_fd, dst_fd); | ||
207 | close(dst_fd); | ||
208 | chmod(archive_handle->file_header->name, archive_handle->file_header->mode); | ||
209 | |||
210 | /* Validate decompression - crc */ | ||
211 | if (zip_header.formated.crc32 != (gunzip_crc ^ 0xffffffffL)) { | ||
212 | bb_error_msg("Invalid compressed data--crc error"); | ||
213 | } | ||
214 | |||
215 | /* Validate decompression - size */ | ||
216 | if (gunzip_bytes_out != zip_header.formated.ucmpsize) { | ||
217 | bb_error_msg("Invalid compressed data--length error"); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | /* local file descriptor section */ | ||
222 | archive_handle->offset += zip_header.formated.cmpsize; | ||
223 | /* This ISNT unix time */ | ||
224 | archive_handle->file_header->mtime = zip_header.formated.modtime | (zip_header.formated.moddate << 16); | ||
225 | archive_handle->file_header->size = zip_header.formated.ucmpsize; | ||
226 | total_size += archive_handle->file_header->size; | ||
227 | total_entries++; | ||
228 | |||
229 | archive_handle->action_header(archive_handle->file_header); | ||
230 | |||
231 | /* Data descriptor section */ | ||
232 | if (zip_header.formated.flags & 4) { | ||
233 | /* skip over duplicate crc, compressed size and uncompressed size */ | ||
234 | unsigned char data_description[12]; | ||
235 | archive_xread_all(archive_handle, data_description, 12); | ||
236 | archive_handle->offset += 12; | ||
237 | } | ||
238 | } | ||
239 | /* Central directory section */ | ||
240 | |||
241 | if (archive_handle->action_header == header_verbose_list_unzip) { | ||
242 | printf(" -------- -------\n"); | ||
243 | printf("%9d %d files\n", total_size, total_entries); | ||
244 | } | ||
245 | |||
246 | return(EXIT_SUCCESS); | ||
247 | } | ||