blob: ab6aa3afc5379b189f9fbd7ebb086c20150164ad [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath5699b852003-11-15 23:19:05 +00002/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02003 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath5699b852003-11-15 23:19:05 +00004 */
5
Glenn L McGrath5699b852003-11-15 23:19:05 +00006#include "libbb.h"
Denys Vlasenkod184a722011-09-22 12:45:14 +02007#include "bb_archive.h"
Bernhard Reutner-Fischercfb53df2006-04-02 21:50:01 +00008
Denys Vlasenkoe7800f32014-12-07 00:42:49 +01009void FAST_FUNC init_transformer_state(transformer_state_t *xstate)
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010010{
Denys Vlasenkoe7800f32014-12-07 00:42:49 +010011 memset(xstate, 0, sizeof(*xstate));
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010012}
Denys Vlasenko59655072012-03-06 16:23:50 +010013
Denys Vlasenkob4c11c12014-12-07 00:44:00 +010014int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16)
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010015{
Denys Vlasenkob4c11c12014-12-07 00:44:00 +010016 if (xstate->check_signature) {
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010017 uint16_t magic2;
Denys Vlasenkob4c11c12014-12-07 00:44:00 +010018 if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) {
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010019 bb_error_msg("invalid magic");
20#if 0 /* possible future extension */
Denys Vlasenkoe7800f32014-12-07 00:42:49 +010021 if (xstate->check_signature > 1)
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010022 xfunc_die();
Denys Vlasenko59655072012-03-06 16:23:50 +010023#endif
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +010024 return -1;
25 }
26 }
27 return 0;
28}
Denys Vlasenko59655072012-03-06 16:23:50 +010029
Denys Vlasenkob4c11c12014-12-07 00:44:00 +010030ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
31{
32 ssize_t nwrote;
33
34 if (xstate->mem_output_size_max != 0) {
35 size_t pos = xstate->mem_output_size;
36 size_t size;
37
38 size = (xstate->mem_output_size += bufsize);
39 if (size > xstate->mem_output_size_max) {
40 free(xstate->mem_output_buf);
41 xstate->mem_output_buf = NULL;
42 bb_perror_msg("buffer %u too small", (unsigned)xstate->mem_output_size_max);
43 nwrote = -1;
44 goto ret;
45 }
Denys Vlasenkocfcd2392014-12-07 00:49:55 +010046 xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size + 1);
Denys Vlasenkob4c11c12014-12-07 00:44:00 +010047 memcpy(xstate->mem_output_buf + pos, buf, bufsize);
Denys Vlasenkocfcd2392014-12-07 00:49:55 +010048 xstate->mem_output_buf[size] = '\0';
Denys Vlasenkob4c11c12014-12-07 00:44:00 +010049 nwrote = bufsize;
50 } else {
51 nwrote = full_write(xstate->dst_fd, buf, bufsize);
52 if (nwrote != (ssize_t)bufsize) {
53 bb_perror_msg("write");
54 nwrote = -1;
55 goto ret;
56 }
57 }
58 ret:
59 return nwrote;
60}
61
62ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize)
63{
64 ssize_t nwrote = transformer_write(xstate, buf, bufsize);
65 if (nwrote != (ssize_t)bufsize) {
66 xfunc_die();
67 }
68 return nwrote;
69}
70
Denys Vlasenkofaac1d32012-03-06 16:33:42 +010071void check_errors_in_children(int signo)
72{
73 int status;
74
75 if (!signo) {
76 /* block waiting for any child */
77 if (wait(&status) < 0)
Denys Vlasenko577235d2013-02-28 16:38:25 +010078//FIXME: check EINTR?
Denys Vlasenkofaac1d32012-03-06 16:33:42 +010079 return; /* probably there are no children */
80 goto check_status;
81 }
82
83 /* Wait for any child without blocking */
84 for (;;) {
85 if (wait_any_nohang(&status) < 0)
Denys Vlasenko577235d2013-02-28 16:38:25 +010086//FIXME: check EINTR?
Denys Vlasenkofaac1d32012-03-06 16:33:42 +010087 /* wait failed?! I'm confused... */
88 return;
89 check_status:
Denys Vlasenko577235d2013-02-28 16:38:25 +010090 /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/
91 /* On Linux, the above can be checked simply as: */
92 if (status == 0)
Denys Vlasenkofaac1d32012-03-06 16:33:42 +010093 /* this child exited with 0 */
94 continue;
Denys Vlasenko577235d2013-02-28 16:38:25 +010095 /* Cannot happen:
96 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???;
97 */
Denys Vlasenkofaac1d32012-03-06 16:33:42 +010098 bb_got_signal = 1;
99 }
100}
101
Glenn L McGrath5699b852003-11-15 23:19:05 +0000102/* transformer(), more than meets the eye */
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100103#if BB_MMU
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100104void FAST_FUNC fork_transformer(int fd,
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100105 int check_signature,
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100106 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate)
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100107)
108#else
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100109void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100110#endif
Glenn L McGrath5699b852003-11-15 23:19:05 +0000111{
Denis Vlasenko37188322008-02-16 13:20:56 +0000112 struct fd_pair fd_pipe;
Glenn L McGrath5699b852003-11-15 23:19:05 +0000113 int pid;
114
Denis Vlasenko37188322008-02-16 13:20:56 +0000115 xpiped_pair(fd_pipe);
Pascal Bellard926031b2010-07-04 15:32:38 +0200116 pid = BB_MMU ? xfork() : xvfork();
Glenn L McGrath5699b852003-11-15 23:19:05 +0000117 if (pid == 0) {
Pascal Bellard926031b2010-07-04 15:32:38 +0200118 /* Child */
Denis Vlasenkob6052722008-07-10 17:43:01 +0000119 close(fd_pipe.rd); /* we don't want to read from the parent */
Denis Vlasenkoea620772006-10-14 02:23:43 +0000120 // FIXME: error check?
Denis Vlasenko211f7f82007-09-05 11:48:32 +0000121#if BB_MMU
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100122 {
Denys Vlasenkoebfa9b52013-11-19 14:44:04 +0100123 IF_DESKTOP(long long) int r;
Denys Vlasenkoe7800f32014-12-07 00:42:49 +0100124 transformer_state_t xstate;
125 init_transformer_state(&xstate);
126 xstate.check_signature = check_signature;
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100127 xstate.src_fd = fd;
128 xstate.dst_fd = fd_pipe.wr;
129 r = transformer(&xstate);
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100130 if (ENABLE_FEATURE_CLEAN_UP) {
131 close(fd_pipe.wr); /* send EOF */
132 close(fd);
133 }
134 /* must be _exit! bug was actually seen here */
Denys Vlasenkoebfa9b52013-11-19 14:44:04 +0100135 _exit(/*error if:*/ r < 0);
Denis Vlasenko7e0fbf92007-09-04 19:33:22 +0000136 }
Denis Vlasenko211f7f82007-09-05 11:48:32 +0000137#else
Denis Vlasenko059c9172007-11-12 02:13:12 +0000138 {
139 char *argv[4];
Denis Vlasenkob6052722008-07-10 17:43:01 +0000140 xmove_fd(fd, 0);
Denis Vlasenko37188322008-02-16 13:20:56 +0000141 xmove_fd(fd_pipe.wr, 1);
Denis Vlasenko059c9172007-11-12 02:13:12 +0000142 argv[0] = (char*)transform_prog;
143 argv[1] = (char*)"-cf";
144 argv[2] = (char*)"-";
145 argv[3] = NULL;
146 BB_EXECVP(transform_prog, argv);
Denis Vlasenkof9d4fc32009-04-21 20:40:51 +0000147 bb_perror_msg_and_die("can't execute '%s'", transform_prog);
Denis Vlasenko059c9172007-11-12 02:13:12 +0000148 }
Denis Vlasenko211f7f82007-09-05 11:48:32 +0000149#endif
Denis Vlasenkoea620772006-10-14 02:23:43 +0000150 /* notreached */
Glenn L McGrath5699b852003-11-15 23:19:05 +0000151 }
Glenn L McGrath20872be2003-11-18 21:31:19 +0000152
Glenn L McGrath5699b852003-11-15 23:19:05 +0000153 /* parent process */
Denis Vlasenkob6052722008-07-10 17:43:01 +0000154 close(fd_pipe.wr); /* don't want to write to the child */
155 xmove_fd(fd_pipe.rd, fd);
Glenn L McGrath5699b852003-11-15 23:19:05 +0000156}
Denys Vlasenko59655072012-03-06 16:23:50 +0100157
158
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100159#if SEAMLESS_COMPRESSION
160
Denys Vlasenko59655072012-03-06 16:23:50 +0100161/* Used by e.g. rpm which gives us a fd without filename,
162 * thus we can't guess the format from filename's extension.
163 */
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100164static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed)
Denys Vlasenko59655072012-03-06 16:23:50 +0100165{
Denys Vlasenko59655072012-03-06 16:23:50 +0100166 union {
167 uint8_t b[4];
168 uint16_t b16[2];
169 uint32_t b32[1];
170 } magic;
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100171 int offset;
172 transformer_state_t *xstate;
173
174 offset = -2;
175 xstate = xzalloc(sizeof(*xstate));
176 xstate->src_fd = fd;
Denys Vlasenko59655072012-03-06 16:23:50 +0100177
178 /* .gz and .bz2 both have 2-byte signature, and their
179 * unpack_XXX_stream wants this header skipped. */
180 xread(fd, magic.b16, sizeof(magic.b16[0]));
181 if (ENABLE_FEATURE_SEAMLESS_GZ
182 && magic.b16[0] == GZIP_MAGIC
183 ) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100184 xstate->xformer = unpack_gz_stream;
185 USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";)
Denys Vlasenko59655072012-03-06 16:23:50 +0100186 goto found_magic;
187 }
188 if (ENABLE_FEATURE_SEAMLESS_BZ2
189 && magic.b16[0] == BZIP2_MAGIC
190 ) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100191 xstate->xformer = unpack_bz2_stream;
192 USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
Denys Vlasenko59655072012-03-06 16:23:50 +0100193 goto found_magic;
194 }
195 if (ENABLE_FEATURE_SEAMLESS_XZ
196 && magic.b16[0] == XZ_MAGIC1
197 ) {
198 offset = -6;
199 xread(fd, magic.b32, sizeof(magic.b32[0]));
200 if (magic.b32[0] == XZ_MAGIC2) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100201 xstate->xformer = unpack_xz_stream;
202 USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
Denys Vlasenko59655072012-03-06 16:23:50 +0100203 goto found_magic;
204 }
205 }
206
207 /* No known magic seen */
Denys Vlasenko640ce3d2014-02-02 02:06:38 +0100208 if (fail_if_not_compressed)
Denys Vlasenko59655072012-03-06 16:23:50 +0100209 bb_error_msg_and_die("no gzip"
210 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
211 IF_FEATURE_SEAMLESS_XZ("/xz")
212 " magic");
Denys Vlasenko59655072012-03-06 16:23:50 +0100213
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100214 /* Some callers expect this function to "consume" fd
215 * even if data is not compressed. In this case,
216 * we return a state with trivial transformer.
217 */
218// USE_FOR_MMU(xstate->xformer = copy_stream;)
219// USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
220 /* fall through to seeking bck over bytes we read earlier */
221
222 USE_FOR_NOMMU(found_magic:)
223 /* NOMMU version of fork_transformer execs
Denys Vlasenko59655072012-03-06 16:23:50 +0100224 * an external unzipper that wants
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100225 * file position at the start of the file.
226 */
Denys Vlasenko59655072012-03-06 16:23:50 +0100227 xlseek(fd, offset, SEEK_CUR);
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100228
229 USE_FOR_MMU(found_magic:)
230 /* In MMU case, if magic was found, seeking back is not necessary */
231
232 return xstate;
233}
234
235/* Used by e.g. rpm which gives us a fd without filename,
236 * thus we can't guess the format from filename's extension.
237 */
238int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
239{
240 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
241
242 if (!xstate || !xstate->xformer) {
243 free(xstate);
244 return 1;
245 }
246
247# if BB_MMU
248 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
249# else
250 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
Denys Vlasenko59655072012-03-06 16:23:50 +0100251# endif
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100252 free(xstate);
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100253 return 0;
Denys Vlasenko59655072012-03-06 16:23:50 +0100254}
Denys Vlasenko59655072012-03-06 16:23:50 +0100255
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100256static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed)
Denys Vlasenko59655072012-03-06 16:23:50 +0100257{
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100258 transformer_state_t *xstate;
Denys Vlasenko59655072012-03-06 16:23:50 +0100259 int fd;
260
261 fd = open(fname, O_RDONLY);
262 if (fd < 0)
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100263 return NULL;
Denys Vlasenko59655072012-03-06 16:23:50 +0100264
Denys Vlasenko7c47b562014-01-10 14:06:57 +0100265 if (ENABLE_FEATURE_SEAMLESS_LZMA) {
266 /* .lzma has no header/signature, can only detect it by extension */
267 char *sfx = strrchr(fname, '.');
268 if (sfx && strcmp(sfx+1, "lzma") == 0) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100269 xstate = xzalloc(sizeof(*xstate));
270 xstate->src_fd = fd;
271 xstate->xformer = unpack_lzma_stream;
272 USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
273 return xstate;
Denys Vlasenko59655072012-03-06 16:23:50 +0100274 }
275 }
276
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100277 xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
278
279 return xstate;
280}
281
282int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
283{
284 int fd;
285 transformer_state_t *xstate;
286
287 xstate = open_transformer(fname, fail_if_not_compressed);
288 if (!xstate)
289 return -1;
290
291 fd = xstate->src_fd;
292 if (xstate->xformer) {
293# if BB_MMU
294 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
295# else
296 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
297# endif
298 }
299 /* else: the file is not compressed */
300
301 free(xstate);
Denys Vlasenko59655072012-03-06 16:23:50 +0100302 return fd;
Denys Vlasenko59655072012-03-06 16:23:50 +0100303}
304
305void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
306{
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100307# if 1
308 transformer_state_t *xstate;
309 char *image;
310
311 xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0);
312 if (!xstate) /* file open error */
313 return NULL;
314
315 image = NULL;
316 if (xstate->xformer) {
317 /* In-memory decompression */
318 xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095);
319 xstate->xformer(xstate);
320 if (xstate->mem_output_buf) {
321 image = xstate->mem_output_buf;
322 if (maxsz_p)
323 *maxsz_p = xstate->mem_output_size;
324 }
325 } else {
326 /* File is not compressed */
327 image = xmalloc_read(xstate->src_fd, maxsz_p);
328 }
329
330 if (!image)
331 bb_perror_msg("read error from '%s'", fname);
332 close(xstate->src_fd);
333 free(xstate);
334 return image;
335# else
336 /* This version forks a subprocess - much more expensive */
Denys Vlasenko59655072012-03-06 16:23:50 +0100337 int fd;
338 char *image;
339
Denys Vlasenko640ce3d2014-02-02 02:06:38 +0100340 fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0);
Denys Vlasenko59655072012-03-06 16:23:50 +0100341 if (fd < 0)
342 return NULL;
343
344 image = xmalloc_read(fd, maxsz_p);
345 if (!image)
346 bb_perror_msg("read error from '%s'", fname);
347 close(fd);
Denys Vlasenko59655072012-03-06 16:23:50 +0100348 return image;
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100349# endif
Denys Vlasenko59655072012-03-06 16:23:50 +0100350}
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100351
352#endif /* SEAMLESS_COMPRESSION */