blob: be536a3d7e715f41ef0e1aacd30842092844dc7e [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 }
Thiago Jung Bauermannb4059f62015-05-03 18:40:12 +0200188 if (ENABLE_FEATURE_SEAMLESS_Z
189 && magic.b16[0] == COMPRESS_MAGIC
190 ) {
191 xstate->xformer = unpack_Z_stream;
192 USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";)
193 goto found_magic;
194 }
Denys Vlasenko59655072012-03-06 16:23:50 +0100195 if (ENABLE_FEATURE_SEAMLESS_BZ2
196 && magic.b16[0] == BZIP2_MAGIC
197 ) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100198 xstate->xformer = unpack_bz2_stream;
199 USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
Denys Vlasenko59655072012-03-06 16:23:50 +0100200 goto found_magic;
201 }
202 if (ENABLE_FEATURE_SEAMLESS_XZ
203 && magic.b16[0] == XZ_MAGIC1
204 ) {
205 offset = -6;
206 xread(fd, magic.b32, sizeof(magic.b32[0]));
207 if (magic.b32[0] == XZ_MAGIC2) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100208 xstate->xformer = unpack_xz_stream;
209 USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
Denys Vlasenko59655072012-03-06 16:23:50 +0100210 goto found_magic;
211 }
212 }
213
214 /* No known magic seen */
Denys Vlasenko640ce3d2014-02-02 02:06:38 +0100215 if (fail_if_not_compressed)
Denys Vlasenko59655072012-03-06 16:23:50 +0100216 bb_error_msg_and_die("no gzip"
217 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
218 IF_FEATURE_SEAMLESS_XZ("/xz")
219 " magic");
Denys Vlasenko59655072012-03-06 16:23:50 +0100220
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100221 /* Some callers expect this function to "consume" fd
222 * even if data is not compressed. In this case,
223 * we return a state with trivial transformer.
224 */
225// USE_FOR_MMU(xstate->xformer = copy_stream;)
226// USE_FOR_NOMMU(xstate->xformer_prog = "cat";)
227 /* fall through to seeking bck over bytes we read earlier */
228
229 USE_FOR_NOMMU(found_magic:)
230 /* NOMMU version of fork_transformer execs
Denys Vlasenko59655072012-03-06 16:23:50 +0100231 * an external unzipper that wants
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100232 * file position at the start of the file.
233 */
Denys Vlasenko59655072012-03-06 16:23:50 +0100234 xlseek(fd, offset, SEEK_CUR);
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100235
236 USE_FOR_MMU(found_magic:)
237 /* In MMU case, if magic was found, seeking back is not necessary */
238
239 return xstate;
240}
241
242/* Used by e.g. rpm which gives us a fd without filename,
243 * thus we can't guess the format from filename's extension.
244 */
245int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
246{
247 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
248
249 if (!xstate || !xstate->xformer) {
250 free(xstate);
251 return 1;
252 }
253
254# if BB_MMU
255 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
256# else
257 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
Denys Vlasenko59655072012-03-06 16:23:50 +0100258# endif
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100259 free(xstate);
Denys Vlasenko8a6a2f92012-03-06 16:27:48 +0100260 return 0;
Denys Vlasenko59655072012-03-06 16:23:50 +0100261}
Denys Vlasenko59655072012-03-06 16:23:50 +0100262
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100263static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed)
Denys Vlasenko59655072012-03-06 16:23:50 +0100264{
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100265 transformer_state_t *xstate;
Denys Vlasenko59655072012-03-06 16:23:50 +0100266 int fd;
267
268 fd = open(fname, O_RDONLY);
269 if (fd < 0)
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100270 return NULL;
Denys Vlasenko59655072012-03-06 16:23:50 +0100271
Denys Vlasenko7c47b562014-01-10 14:06:57 +0100272 if (ENABLE_FEATURE_SEAMLESS_LZMA) {
273 /* .lzma has no header/signature, can only detect it by extension */
274 char *sfx = strrchr(fname, '.');
275 if (sfx && strcmp(sfx+1, "lzma") == 0) {
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100276 xstate = xzalloc(sizeof(*xstate));
277 xstate->src_fd = fd;
278 xstate->xformer = unpack_lzma_stream;
279 USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";)
280 return xstate;
Denys Vlasenko59655072012-03-06 16:23:50 +0100281 }
282 }
283
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100284 xstate = setup_transformer_on_fd(fd, fail_if_not_compressed);
285
286 return xstate;
287}
288
289int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
290{
291 int fd;
292 transformer_state_t *xstate;
293
294 xstate = open_transformer(fname, fail_if_not_compressed);
295 if (!xstate)
296 return -1;
297
298 fd = xstate->src_fd;
299 if (xstate->xformer) {
300# if BB_MMU
301 fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer);
302# else
303 fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog);
304# endif
305 }
306 /* else: the file is not compressed */
307
308 free(xstate);
Denys Vlasenko59655072012-03-06 16:23:50 +0100309 return fd;
Denys Vlasenko59655072012-03-06 16:23:50 +0100310}
311
312void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
313{
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100314# if 1
315 transformer_state_t *xstate;
316 char *image;
317
318 xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0);
319 if (!xstate) /* file open error */
320 return NULL;
321
322 image = NULL;
323 if (xstate->xformer) {
324 /* In-memory decompression */
325 xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095);
326 xstate->xformer(xstate);
327 if (xstate->mem_output_buf) {
328 image = xstate->mem_output_buf;
329 if (maxsz_p)
330 *maxsz_p = xstate->mem_output_size;
331 }
332 } else {
333 /* File is not compressed */
334 image = xmalloc_read(xstate->src_fd, maxsz_p);
335 }
336
337 if (!image)
338 bb_perror_msg("read error from '%s'", fname);
339 close(xstate->src_fd);
340 free(xstate);
341 return image;
342# else
343 /* This version forks a subprocess - much more expensive */
Denys Vlasenko59655072012-03-06 16:23:50 +0100344 int fd;
345 char *image;
346
Denys Vlasenko640ce3d2014-02-02 02:06:38 +0100347 fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0);
Denys Vlasenko59655072012-03-06 16:23:50 +0100348 if (fd < 0)
349 return NULL;
350
351 image = xmalloc_read(fd, maxsz_p);
352 if (!image)
353 bb_perror_msg("read error from '%s'", fname);
354 close(fd);
Denys Vlasenko59655072012-03-06 16:23:50 +0100355 return image;
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100356# endif
Denys Vlasenko59655072012-03-06 16:23:50 +0100357}
Denys Vlasenkob4c11c12014-12-07 00:44:00 +0100358
359#endif /* SEAMLESS_COMPRESSION */