Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) Ian F. Darwin 1986-1995. |
3 | | * Software written by Ian F. Darwin and others; |
4 | | * maintained 1995-present by Christos Zoulas and others. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice immediately at the beginning of the file, without modification, |
11 | | * this list of conditions, and the following disclaimer. |
12 | | * 2. Redistributions in binary form must reproduce the above copyright |
13 | | * notice, this list of conditions and the following disclaimer in the |
14 | | * documentation and/or other materials provided with the distribution. |
15 | | * |
16 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
20 | | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | | * SUCH DAMAGE. |
27 | | */ |
28 | | /* |
29 | | * compress routines: |
30 | | * zmagic() - returns 0 if not recognized, uncompresses and prints |
31 | | * information if recognized |
32 | | * uncompress(method, old, n, newch) - uncompress old into new, |
33 | | * using method, return sizeof new |
34 | | */ |
35 | | #include "file.h" |
36 | | |
37 | | #ifndef lint |
38 | | FILE_RCSID("@(#)$File: compress.c,v 1.158 2024/11/10 16:52:27 christos Exp $") |
39 | | #endif |
40 | | |
41 | | #include "magic.h" |
42 | | #include <stdlib.h> |
43 | | #ifdef HAVE_UNISTD_H |
44 | | #include <unistd.h> |
45 | | #endif |
46 | | #ifdef HAVE_SPAWN_H |
47 | | #include <spawn.h> |
48 | | #endif |
49 | | #include <stdio.h> |
50 | | #include <string.h> |
51 | | #include <errno.h> |
52 | | #include <ctype.h> |
53 | | #include <stdarg.h> |
54 | | #include <signal.h> |
55 | | #ifndef HAVE_SIG_T |
56 | | typedef void (*sig_t)(int); |
57 | | #endif /* HAVE_SIG_T */ |
58 | | #ifdef HAVE_SYS_IOCTL_H |
59 | | #include <sys/ioctl.h> |
60 | | #endif |
61 | | #ifdef HAVE_SYS_WAIT_H |
62 | | #include <sys/wait.h> |
63 | | #endif |
64 | | #if defined(HAVE_SYS_TIME_H) |
65 | | #include <sys/time.h> |
66 | | #endif |
67 | | |
68 | | #if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT) |
69 | | #define BUILTIN_DECOMPRESS |
70 | | #include <zlib.h> |
71 | | #endif |
72 | | |
73 | | #if defined(HAVE_BZLIB_H) && defined(BZLIBSUPPORT) |
74 | | #define BUILTIN_BZLIB |
75 | | #include <bzlib.h> |
76 | | #endif |
77 | | |
78 | | #if defined(HAVE_LZMA_H) && defined(XZLIBSUPPORT) |
79 | | #define BUILTIN_XZLIB |
80 | | #include <lzma.h> |
81 | | #endif |
82 | | |
83 | | #if defined(HAVE_ZSTD_H) && defined(ZSTDLIBSUPPORT) |
84 | | #define BUILTIN_ZSTDLIB |
85 | | #include <zstd.h> |
86 | | #include <zstd_errors.h> |
87 | | #endif |
88 | | |
89 | | #if defined(HAVE_LZLIB_H) && defined(LZLIBSUPPORT) |
90 | | #define BUILTIN_LZLIB |
91 | | #include <lzlib.h> |
92 | | #endif |
93 | | |
94 | | #ifdef notyet |
95 | | #if defined(HAVE_LRZIP_H) && defined(LRZIPLIBSUPPORT) |
96 | | #define BUILTIN_LRZIP |
97 | | #include <Lrzip.h> |
98 | | #endif |
99 | | #endif |
100 | | |
101 | | #ifdef DEBUG |
102 | | int tty = -1; |
103 | | #define DPRINTF(...) do { \ |
104 | | if (tty == -1) \ |
105 | | tty = open("/dev/tty", O_RDWR); \ |
106 | | if (tty == -1) \ |
107 | | abort(); \ |
108 | | dprintf(tty, __VA_ARGS__); \ |
109 | | } while (/*CONSTCOND*/0) |
110 | | #else |
111 | | #define DPRINTF(...) |
112 | | #endif |
113 | | |
114 | | #ifdef ZLIBSUPPORT |
115 | | /* |
116 | | * The following python code is not really used because ZLIBSUPPORT is only |
117 | | * defined if we have a built-in zlib, and the built-in zlib handles that. |
118 | | * That is not true for android where we have zlib.h and not -lz. |
119 | | */ |
120 | | static const char zlibcode[] = |
121 | | "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; |
122 | | |
123 | | static const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; |
124 | | |
125 | | static int |
126 | | zlibcmp(const unsigned char *buf) |
127 | 19.9k | { |
128 | 19.9k | unsigned short x = 1; |
129 | 19.9k | unsigned char *s = CAST(unsigned char *, CAST(void *, &x)); |
130 | | |
131 | 19.9k | if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) |
132 | 19.7k | return 0; |
133 | 123 | if (s[0] != 1) /* endianness test */ |
134 | 0 | x = buf[0] | (buf[1] << 8); |
135 | 123 | else |
136 | 123 | x = buf[1] | (buf[0] << 8); |
137 | 123 | if (x % 31) |
138 | 69 | return 0; |
139 | 54 | return 1; |
140 | 123 | } |
141 | | #endif |
142 | | |
143 | | static int |
144 | | lzmacmp(const unsigned char *buf) |
145 | 13.7k | { |
146 | 13.7k | if (buf[0] != 0x5d || buf[1] || buf[2]) |
147 | 13.7k | return 0; |
148 | 13 | if (buf[12] && buf[12] != 0xff) |
149 | 7 | return 0; |
150 | 6 | return 1; |
151 | 13 | } |
152 | | |
153 | | #define gzip_flags "-cd" |
154 | | #define lzip_flags gzip_flags |
155 | | |
156 | | static const char *gzip_args[] = { |
157 | | "gzip", gzip_flags, NULL |
158 | | }; |
159 | | static const char *uncompress_args[] = { |
160 | | "uncompress", "-c", NULL |
161 | | }; |
162 | | static const char *bzip2_args[] = { |
163 | | "bzip2", "-cd", NULL |
164 | | }; |
165 | | static const char *lzip_args[] = { |
166 | | "lzip", lzip_flags, NULL |
167 | | }; |
168 | | static const char *xz_args[] = { |
169 | | "xz", "-cd", NULL |
170 | | }; |
171 | | static const char *lrzip_args[] = { |
172 | | "lrzip", "-qdf", "-", NULL |
173 | | }; |
174 | | static const char *lz4_args[] = { |
175 | | "lz4", "-cd", NULL |
176 | | }; |
177 | | static const char *zstd_args[] = { |
178 | | "zstd", "-cd", NULL |
179 | | }; |
180 | | |
181 | | #define do_zlib NULL |
182 | | #define do_bzlib NULL |
183 | | |
184 | | file_private const struct { |
185 | | union { |
186 | | const char *magic; |
187 | | int (*func)(const unsigned char *); |
188 | | } u; |
189 | | int maglen; |
190 | | const char **argv; |
191 | | void *unused; |
192 | | } compr[] = { |
193 | 50 | #define METH_FROZEN 2 |
194 | 20 | #define METH_BZIP 7 |
195 | 6 | #define METH_XZ 9 |
196 | | #define METH_LZIP 8 |
197 | | #define METH_LRZIP 10 |
198 | 8 | #define METH_ZSTD 12 |
199 | 18 | #define METH_LZMA 13 |
200 | 133 | #define METH_ZLIB 14 |
201 | | { { .magic = "\037\235" }, 2, gzip_args, NULL }, /* 0, compressed */ |
202 | | /* Uncompress can get stuck; so use gzip first if we have it |
203 | | * Idea from Damien Clark, thanks! */ |
204 | | { { .magic = "\037\235" }, 2, uncompress_args, NULL },/* 1, compressed */ |
205 | | { { .magic = "\037\213" }, 2, gzip_args, do_zlib },/* 2, gzipped */ |
206 | | { { .magic = "\037\236" }, 2, gzip_args, NULL }, /* 3, frozen */ |
207 | | { { .magic = "\037\240" }, 2, gzip_args, NULL }, /* 4, SCO LZH */ |
208 | | /* the standard pack utilities do not accept standard input */ |
209 | | { { .magic = "\037\036" }, 2, gzip_args, NULL }, /* 5, packed */ |
210 | | { { .magic = "PK\3\4" }, 4, gzip_args, NULL }, /* 6, pkziped */ |
211 | | /* ...only first file examined */ |
212 | | { { .magic = "BZh" }, 3, bzip2_args, do_bzlib },/* 7, bzip2-ed */ |
213 | | { { .magic = "LZIP" }, 4, lzip_args, NULL }, /* 8, lzip-ed */ |
214 | | { { .magic = "\3757zXZ\0" },6, xz_args, NULL }, /* 9, XZ Util */ |
215 | | { { .magic = "LRZI" }, 4, lrzip_args, NULL }, /* 10, LRZIP */ |
216 | | { { .magic = "\004\"M\030" },4, lz4_args, NULL }, /* 11, LZ4 */ |
217 | | { { .magic = "\x28\xB5\x2F\xFD" }, 4, zstd_args, NULL },/* 12, zstd */ |
218 | | { { .func = lzmacmp }, -13, xz_args, NULL }, /* 13, lzma */ |
219 | | #ifdef ZLIBSUPPORT |
220 | | { { .func = zlibcmp }, -2, zlib_args, NULL }, /* 14, zlib */ |
221 | | #endif |
222 | | }; |
223 | | |
224 | 12.6k | #define OKDATA 0 |
225 | 6.33k | #define NODATA 1 |
226 | 13.6k | #define ERRDATA 2 |
227 | | |
228 | | file_private ssize_t swrite(int, const void *, size_t); |
229 | | #if HAVE_FORK |
230 | | file_private size_t ncompr = __arraycount(compr); |
231 | | file_private int uncompressbuf(int, size_t, size_t, int, const unsigned char *, |
232 | | unsigned char **, size_t *); |
233 | | #ifdef BUILTIN_DECOMPRESS |
234 | | file_private int uncompresszlib(const unsigned char *, unsigned char **, size_t, |
235 | | size_t *, int); |
236 | | file_private int uncompressgzipped(const unsigned char *, unsigned char **, size_t, |
237 | | size_t *, int); |
238 | | #endif |
239 | | #ifdef BUILTIN_BZLIB |
240 | | file_private int uncompressbzlib(const unsigned char *, unsigned char **, size_t, |
241 | | size_t *, int); |
242 | | #endif |
243 | | #ifdef BUILTIN_XZLIB |
244 | | file_private int uncompressxzlib(const unsigned char *, unsigned char **, size_t, |
245 | | size_t *, int); |
246 | | #endif |
247 | | #ifdef BUILTIN_ZSTDLIB |
248 | | file_private int uncompresszstd(const unsigned char *, unsigned char **, size_t, |
249 | | size_t *, int); |
250 | | #endif |
251 | | #ifdef BUILTIN_LZLIB |
252 | | file_private int uncompresslzlib(const unsigned char *, unsigned char **, size_t, |
253 | | size_t *, int); |
254 | | #endif |
255 | | #ifdef BUILTIN_LRZIP |
256 | | file_private int uncompresslrzip(const unsigned char *, unsigned char **, size_t, |
257 | | size_t *, int); |
258 | | #endif |
259 | | |
260 | | |
261 | | static int makeerror(unsigned char **, size_t *, const char *, ...) |
262 | | __attribute__((__format__(__printf__, 3, 4))); |
263 | | file_private const char *methodname(size_t); |
264 | | |
265 | | file_private int |
266 | | format_decompression_error(struct magic_set *ms, size_t i, unsigned char *buf) |
267 | 472 | { |
268 | 472 | unsigned char *p; |
269 | 472 | int mime = ms->flags & MAGIC_MIME; |
270 | | |
271 | 472 | if (!mime) |
272 | 472 | return file_printf(ms, "ERROR:[%s: %s]", methodname(i), buf); |
273 | | |
274 | 0 | for (p = buf; *p; p++) |
275 | 0 | if (!isalnum(*p)) |
276 | 0 | *p = '-'; |
277 | |
|
278 | 0 | return file_printf(ms, "application/x-decompression-error-%s-%s", |
279 | 0 | methodname(i), buf); |
280 | 472 | } |
281 | | |
282 | | file_protected int |
283 | | file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name) |
284 | 32.3k | { |
285 | 32.3k | unsigned char *newbuf = NULL; |
286 | 32.3k | size_t i, nsz; |
287 | 32.3k | char *rbuf; |
288 | 32.3k | file_pushbuf_t *pb; |
289 | 32.3k | int urv, prv, rv = 0; |
290 | 32.3k | int mime = ms->flags & MAGIC_MIME; |
291 | 32.3k | int fd = b->fd; |
292 | 32.3k | const unsigned char *buf = CAST(const unsigned char *, b->fbuf); |
293 | 32.3k | size_t nbytes = b->flen; |
294 | 32.3k | int sa_saved = 0; |
295 | 32.3k | struct sigaction sig_act; |
296 | | |
297 | 32.3k | if ((ms->flags & MAGIC_COMPRESS) == 0) |
298 | 12.4k | return 0; |
299 | | |
300 | 318k | for (i = 0; i < ncompr; i++) { |
301 | 298k | int zm; |
302 | 298k | if (nbytes < CAST(size_t, abs(compr[i].maglen))) |
303 | 15.1k | continue; |
304 | 283k | if (compr[i].maglen < 0) { |
305 | 33.7k | zm = (*compr[i].u.func)(buf); |
306 | 249k | } else { |
307 | 249k | zm = memcmp(buf, compr[i].u.magic, |
308 | 249k | CAST(size_t, compr[i].maglen)) == 0; |
309 | 249k | } |
310 | | |
311 | 283k | if (!zm) |
312 | 276k | continue; |
313 | | |
314 | | /* Prevent SIGPIPE death if child dies unexpectedly */ |
315 | 6.59k | if (!sa_saved) { |
316 | | //We can use sig_act for both new and old, but |
317 | 5.83k | struct sigaction new_act; |
318 | 5.83k | memset(&new_act, 0, sizeof(new_act)); |
319 | 5.83k | new_act.sa_handler = SIG_IGN; |
320 | 5.83k | sa_saved = sigaction(SIGPIPE, &new_act, &sig_act) != -1; |
321 | 5.83k | } |
322 | | |
323 | 6.59k | nsz = nbytes; |
324 | 6.59k | free(newbuf); |
325 | 6.59k | urv = uncompressbuf(fd, ms->bytes_max, i, |
326 | 6.59k | (ms->flags & MAGIC_NO_COMPRESS_FORK), buf, &newbuf, &nsz); |
327 | 6.59k | DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv, |
328 | 6.59k | (char *)newbuf, nsz); |
329 | 6.59k | switch (urv) { |
330 | 6.12k | case OKDATA: |
331 | 6.59k | case ERRDATA: |
332 | 6.59k | ms->flags &= ~MAGIC_COMPRESS; |
333 | 6.59k | if (urv == ERRDATA) |
334 | 472 | prv = format_decompression_error(ms, i, newbuf); |
335 | 6.12k | else |
336 | 6.12k | prv = file_buffer(ms, -1, NULL, name, newbuf, |
337 | 6.12k | nsz); |
338 | 6.59k | if (prv == -1) |
339 | 0 | goto error; |
340 | 6.59k | rv = 1; |
341 | 6.59k | if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) |
342 | 0 | goto out; |
343 | 6.59k | if (mime != MAGIC_MIME && mime != 0) |
344 | 0 | goto out; |
345 | 6.59k | if ((file_printf(ms, |
346 | 6.59k | mime ? " compressed-encoding=" : " (")) == -1) |
347 | 0 | goto error; |
348 | 6.59k | if ((pb = file_push_buffer(ms)) == NULL) |
349 | 246 | goto error; |
350 | | /* |
351 | | * XXX: If file_buffer fails here, we overwrite |
352 | | * the compressed text. FIXME. |
353 | | */ |
354 | 6.35k | if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) |
355 | 0 | { |
356 | 0 | if (file_pop_buffer(ms, pb) != NULL) |
357 | 0 | abort(); |
358 | 0 | goto error; |
359 | 0 | } |
360 | 6.35k | if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { |
361 | 6.35k | if (file_printf(ms, "%s", rbuf) == -1) { |
362 | 15 | free(rbuf); |
363 | 15 | goto error; |
364 | 15 | } |
365 | 6.33k | free(rbuf); |
366 | 6.33k | } |
367 | 6.33k | if (!mime && file_printf(ms, ")") == -1) |
368 | 0 | goto error; |
369 | | /*FALLTHROUGH*/ |
370 | 6.33k | case NODATA: |
371 | 6.33k | break; |
372 | 0 | default: |
373 | 0 | abort(); |
374 | | /*NOTREACHED*/ |
375 | 261 | error: |
376 | 261 | rv = -1; |
377 | 261 | break; |
378 | 6.59k | } |
379 | 6.59k | } |
380 | 19.9k | out: |
381 | 19.9k | DPRINTF("rv = %d\n", rv); |
382 | | |
383 | 19.9k | if (sa_saved && sig_act.sa_handler != SIG_IGN) |
384 | 5.83k | (void)sigaction(SIGPIPE, &sig_act, NULL); |
385 | | |
386 | 19.9k | free(newbuf); |
387 | 19.9k | ms->flags |= MAGIC_COMPRESS; |
388 | 19.9k | DPRINTF("Zmagic returns %d\n", rv); |
389 | 19.9k | return rv; |
390 | 19.9k | } |
391 | | #endif |
392 | | /* |
393 | | * `safe' write for sockets and pipes. |
394 | | */ |
395 | | file_private ssize_t |
396 | | swrite(int fd, const void *buf, size_t n) |
397 | 0 | { |
398 | 0 | ssize_t rv; |
399 | 0 | size_t rn = n; |
400 | |
|
401 | 0 | do |
402 | 0 | switch (rv = write(fd, buf, n)) { |
403 | 0 | case -1: |
404 | 0 | if (errno == EINTR) |
405 | 0 | continue; |
406 | 0 | return -1; |
407 | 0 | default: |
408 | 0 | n -= rv; |
409 | 0 | buf = CAST(const char *, buf) + rv; |
410 | 0 | break; |
411 | 0 | } |
412 | 0 | while (n > 0); |
413 | 0 | return rn; |
414 | 0 | } |
415 | | |
416 | | |
417 | | /* |
418 | | * `safe' read for sockets and pipes. |
419 | | */ |
420 | | file_protected ssize_t |
421 | | sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__))) |
422 | 12.8k | { |
423 | 12.8k | ssize_t rv; |
424 | 12.8k | #if defined(FIONREAD) && !defined(__MINGW32__) |
425 | 12.8k | int t = 0; |
426 | 12.8k | #endif |
427 | 12.8k | size_t rn = n; |
428 | | |
429 | 12.8k | if (fd == STDIN_FILENO) |
430 | 0 | goto nocheck; |
431 | | |
432 | 12.8k | #if defined(FIONREAD) && !defined(__MINGW32__) |
433 | 12.8k | if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) { |
434 | 0 | #ifdef FD_ZERO |
435 | 0 | ssize_t cnt; |
436 | 0 | for (cnt = 0;; cnt++) { |
437 | 0 | fd_set check; |
438 | 0 | struct timeval tout = {0, 100 * 1000}; |
439 | 0 | int selrv; |
440 | |
|
441 | 0 | FD_ZERO(&check); |
442 | 0 | FD_SET(fd, &check); |
443 | | |
444 | | /* |
445 | | * Avoid soft deadlock: do not read if there |
446 | | * is nothing to read from sockets and pipes. |
447 | | */ |
448 | 0 | selrv = select(fd + 1, &check, NULL, NULL, &tout); |
449 | 0 | if (selrv == -1) { |
450 | 0 | if (errno == EINTR || errno == EAGAIN) |
451 | 0 | continue; |
452 | 0 | } else if (selrv == 0 && cnt >= 5) { |
453 | 0 | return 0; |
454 | 0 | } else |
455 | 0 | break; |
456 | 0 | } |
457 | 0 | #endif |
458 | 0 | (void)ioctl(fd, FIONREAD, &t); |
459 | 0 | } |
460 | | |
461 | 12.8k | if (t > 0 && CAST(size_t, t) < n) { |
462 | 0 | n = t; |
463 | 0 | rn = n; |
464 | 0 | } |
465 | 12.8k | #endif |
466 | | |
467 | 12.8k | nocheck: |
468 | 12.8k | do |
469 | 328k | switch ((rv = read(fd, buf, n))) { |
470 | 16 | case -1: |
471 | 16 | if (errno == EINTR) |
472 | 16 | continue; |
473 | 0 | return -1; |
474 | 12.7k | case 0: |
475 | 12.7k | return rn - n; |
476 | 316k | default: |
477 | 316k | n -= rv; |
478 | 316k | buf = CAST(char *, CCAST(void *, buf)) + rv; |
479 | 316k | break; |
480 | 328k | } |
481 | 316k | while (n > 0); |
482 | 119 | return rn; |
483 | 12.8k | } |
484 | | |
485 | | file_protected int |
486 | | file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, |
487 | | size_t nbytes) |
488 | 0 | { |
489 | 0 | char buf[4096]; |
490 | 0 | ssize_t r; |
491 | 0 | int tfd; |
492 | |
|
493 | | #ifdef WIN32 |
494 | | const char *t; |
495 | | buf[0] = '\0'; |
496 | | if ((t = getenv("TEMP")) != NULL) |
497 | | (void)strlcpy(buf, t, sizeof(buf)); |
498 | | else if ((t = getenv("TMP")) != NULL) |
499 | | (void)strlcpy(buf, t, sizeof(buf)); |
500 | | else if ((t = getenv("TMPDIR")) != NULL) |
501 | | (void)strlcpy(buf, t, sizeof(buf)); |
502 | | if (buf[0] != '\0') |
503 | | (void)strlcat(buf, "/", sizeof(buf)); |
504 | | (void)strlcat(buf, "file.XXXXXX", sizeof(buf)); |
505 | | #else |
506 | 0 | (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof(buf)); |
507 | 0 | #endif |
508 | | #ifndef HAVE_MKSTEMP |
509 | | { |
510 | | char *ptr = mktemp(buf); |
511 | | tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); |
512 | | r = errno; |
513 | | (void)unlink(ptr); |
514 | | errno = r; |
515 | | } |
516 | | #else |
517 | 0 | { |
518 | 0 | int te; |
519 | 0 | mode_t ou = umask(0); |
520 | 0 | tfd = mkstemp(buf); |
521 | 0 | (void)umask(ou); |
522 | 0 | te = errno; |
523 | 0 | (void)unlink(buf); |
524 | 0 | errno = te; |
525 | 0 | } |
526 | 0 | #endif |
527 | 0 | if (tfd == -1) { |
528 | 0 | file_error(ms, errno, |
529 | 0 | "cannot create temporary file for pipe copy"); |
530 | 0 | return -1; |
531 | 0 | } |
532 | | |
533 | 0 | if (swrite(tfd, startbuf, nbytes) != CAST(ssize_t, nbytes)) |
534 | 0 | r = 1; |
535 | 0 | else { |
536 | 0 | while ((r = sread(fd, buf, sizeof(buf), 1)) > 0) |
537 | 0 | if (swrite(tfd, buf, CAST(size_t, r)) != r) |
538 | 0 | break; |
539 | 0 | } |
540 | |
|
541 | 0 | switch (r) { |
542 | 0 | case -1: |
543 | 0 | file_error(ms, errno, "error copying from pipe to temp file"); |
544 | 0 | return -1; |
545 | 0 | case 0: |
546 | 0 | break; |
547 | 0 | default: |
548 | 0 | file_error(ms, errno, "error while writing to temp file"); |
549 | 0 | return -1; |
550 | 0 | } |
551 | | |
552 | | /* |
553 | | * We duplicate the file descriptor, because fclose on a |
554 | | * tmpfile will delete the file, but any open descriptors |
555 | | * can still access the phantom inode. |
556 | | */ |
557 | 0 | if ((fd = dup2(tfd, fd)) == -1) { |
558 | 0 | file_error(ms, errno, "could not dup descriptor for temp file"); |
559 | 0 | return -1; |
560 | 0 | } |
561 | 0 | (void)close(tfd); |
562 | 0 | if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) { |
563 | 0 | file_badseek(ms); |
564 | 0 | return -1; |
565 | 0 | } |
566 | 0 | return fd; |
567 | 0 | } |
568 | | #if HAVE_FORK |
569 | | #ifdef BUILTIN_DECOMPRESS |
570 | | |
571 | 0 | #define FHCRC (1 << 1) |
572 | 0 | #define FEXTRA (1 << 2) |
573 | 0 | #define FNAME (1 << 3) |
574 | 0 | #define FCOMMENT (1 << 4) |
575 | | |
576 | | |
577 | | file_private int |
578 | | uncompressgzipped(const unsigned char *old, unsigned char **newch, |
579 | | size_t bytes_max, size_t *n, int extra __attribute__((__unused__))) |
580 | 0 | { |
581 | 0 | unsigned char flg; |
582 | 0 | size_t data_start = 10; |
583 | |
|
584 | 0 | if (*n < 4) { |
585 | 0 | goto err; |
586 | 0 | } |
587 | | |
588 | 0 | flg = old[3]; |
589 | |
|
590 | 0 | if (flg & FEXTRA) { |
591 | 0 | if (data_start + 1 >= *n) |
592 | 0 | goto err; |
593 | 0 | data_start += 2 + old[data_start] + old[data_start + 1] * 256; |
594 | 0 | } |
595 | 0 | if (flg & FNAME) { |
596 | 0 | while(data_start < *n && old[data_start]) |
597 | 0 | data_start++; |
598 | 0 | data_start++; |
599 | 0 | } |
600 | 0 | if (flg & FCOMMENT) { |
601 | 0 | while(data_start < *n && old[data_start]) |
602 | 0 | data_start++; |
603 | 0 | data_start++; |
604 | 0 | } |
605 | 0 | if (flg & FHCRC) |
606 | 0 | data_start += 2; |
607 | |
|
608 | 0 | if (data_start >= *n) |
609 | 0 | goto err; |
610 | | |
611 | 0 | *n -= data_start; |
612 | 0 | old += data_start; |
613 | 0 | return uncompresszlib(old, newch, bytes_max, n, 0); |
614 | 0 | err: |
615 | 0 | return makeerror(newch, n, "File too short"); |
616 | 0 | } |
617 | | |
618 | | file_private int |
619 | | uncompresszlib(const unsigned char *old, unsigned char **newch, |
620 | | size_t bytes_max, size_t *n, int zlib) |
621 | 0 | { |
622 | 0 | int rc; |
623 | 0 | z_stream z; |
624 | |
|
625 | 0 | DPRINTF("builtin zlib decompression\n"); |
626 | 0 | z.next_in = CCAST(Bytef *, old); |
627 | 0 | z.avail_in = CAST(uint32_t, *n); |
628 | 0 | z.next_out = *newch; |
629 | 0 | z.avail_out = CAST(unsigned int, bytes_max); |
630 | 0 | z.zalloc = Z_NULL; |
631 | 0 | z.zfree = Z_NULL; |
632 | 0 | z.opaque = Z_NULL; |
633 | | |
634 | | /* LINTED bug in header macro */ |
635 | 0 | rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); |
636 | 0 | if (rc != Z_OK) |
637 | 0 | goto err; |
638 | | |
639 | 0 | rc = inflate(&z, Z_SYNC_FLUSH); |
640 | 0 | if (rc != Z_OK && rc != Z_STREAM_END) { |
641 | 0 | inflateEnd(&z); |
642 | 0 | goto err; |
643 | 0 | } |
644 | | |
645 | 0 | *n = CAST(size_t, z.total_out); |
646 | 0 | rc = inflateEnd(&z); |
647 | 0 | if (rc != Z_OK) |
648 | 0 | goto err; |
649 | | |
650 | | /* let's keep the nul-terminate tradition */ |
651 | 0 | (*newch)[*n] = '\0'; |
652 | |
|
653 | 0 | return OKDATA; |
654 | 0 | err: |
655 | 0 | return makeerror(newch, n, "%s", z.msg ? z.msg : zError(rc)); |
656 | 0 | } |
657 | | #endif |
658 | | |
659 | | #ifdef BUILTIN_BZLIB |
660 | | file_private int |
661 | | uncompressbzlib(const unsigned char *old, unsigned char **newch, |
662 | | size_t bytes_max, size_t *n, int extra __attribute__((__unused__))) |
663 | 0 | { |
664 | 0 | int rc; |
665 | 0 | bz_stream bz; |
666 | |
|
667 | 0 | DPRINTF("builtin bzlib decompression\n"); |
668 | 0 | memset(&bz, 0, sizeof(bz)); |
669 | 0 | rc = BZ2_bzDecompressInit(&bz, 0, 0); |
670 | 0 | if (rc != BZ_OK) |
671 | 0 | goto err; |
672 | | |
673 | 0 | bz.next_in = CCAST(char *, RCAST(const char *, old)); |
674 | 0 | bz.avail_in = CAST(uint32_t, *n); |
675 | 0 | bz.next_out = RCAST(char *, *newch); |
676 | 0 | bz.avail_out = CAST(unsigned int, bytes_max); |
677 | |
|
678 | 0 | rc = BZ2_bzDecompress(&bz); |
679 | 0 | if (rc != BZ_OK && rc != BZ_STREAM_END) { |
680 | 0 | BZ2_bzDecompressEnd(&bz); |
681 | 0 | goto err; |
682 | 0 | } |
683 | | |
684 | | /* Assume byte_max is within 32bit */ |
685 | | /* assert(bz.total_out_hi32 == 0); */ |
686 | 0 | *n = CAST(size_t, bz.total_out_lo32); |
687 | 0 | rc = BZ2_bzDecompressEnd(&bz); |
688 | 0 | if (rc != BZ_OK) |
689 | 0 | goto err; |
690 | | |
691 | | /* let's keep the nul-terminate tradition */ |
692 | 0 | (*newch)[*n] = '\0'; |
693 | |
|
694 | 0 | return OKDATA; |
695 | 0 | err: |
696 | 0 | return makeerror(newch, n, "bunzip error %d", rc); |
697 | 0 | } |
698 | | #endif |
699 | | |
700 | | #ifdef BUILTIN_XZLIB |
701 | | file_private int |
702 | | uncompressxzlib(const unsigned char *old, unsigned char **newch, |
703 | | size_t bytes_max, size_t *n, int extra __attribute__((__unused__))) |
704 | 0 | { |
705 | 0 | int rc; |
706 | 0 | lzma_stream xz; |
707 | |
|
708 | 0 | DPRINTF("builtin xzlib decompression\n"); |
709 | 0 | memset(&xz, 0, sizeof(xz)); |
710 | 0 | rc = lzma_auto_decoder(&xz, UINT64_MAX, 0); |
711 | 0 | if (rc != LZMA_OK) |
712 | 0 | goto err; |
713 | | |
714 | 0 | xz.next_in = CCAST(const uint8_t *, old); |
715 | 0 | xz.avail_in = CAST(uint32_t, *n); |
716 | 0 | xz.next_out = RCAST(uint8_t *, *newch); |
717 | 0 | xz.avail_out = CAST(unsigned int, bytes_max); |
718 | |
|
719 | 0 | rc = lzma_code(&xz, LZMA_RUN); |
720 | 0 | if (rc != LZMA_OK && rc != LZMA_STREAM_END) { |
721 | 0 | lzma_end(&xz); |
722 | 0 | goto err; |
723 | 0 | } |
724 | | |
725 | 0 | *n = CAST(size_t, xz.total_out); |
726 | |
|
727 | 0 | lzma_end(&xz); |
728 | | |
729 | | /* let's keep the nul-terminate tradition */ |
730 | 0 | (*newch)[*n] = '\0'; |
731 | |
|
732 | 0 | return OKDATA; |
733 | 0 | err: |
734 | 0 | return makeerror(newch, n, "unxz error %d", rc); |
735 | 0 | } |
736 | | #endif |
737 | | |
738 | | #ifdef BUILTIN_ZSTDLIB |
739 | | file_private int |
740 | | uncompresszstd(const unsigned char *old, unsigned char **newch, |
741 | | size_t bytes_max, size_t *n, int extra __attribute__((__unused__))) |
742 | 0 | { |
743 | 0 | size_t rc; |
744 | 0 | ZSTD_DStream *zstd; |
745 | 0 | ZSTD_inBuffer in; |
746 | 0 | ZSTD_outBuffer out; |
747 | |
|
748 | 0 | DPRINTF("builtin zstd decompression\n"); |
749 | 0 | if ((zstd = ZSTD_createDStream()) == NULL) { |
750 | 0 | return makeerror(newch, n, "No ZSTD decompression stream, %s", |
751 | 0 | strerror(errno)); |
752 | 0 | } |
753 | | |
754 | 0 | rc = ZSTD_DCtx_reset(zstd, ZSTD_reset_session_only); |
755 | 0 | if (ZSTD_isError(rc)) |
756 | 0 | goto err; |
757 | | |
758 | 0 | in.src = CCAST(const void *, old); |
759 | 0 | in.size = *n; |
760 | 0 | in.pos = 0; |
761 | 0 | out.dst = RCAST(void *, *newch); |
762 | 0 | out.size = bytes_max; |
763 | 0 | out.pos = 0; |
764 | |
|
765 | 0 | rc = ZSTD_decompressStream(zstd, &out, &in); |
766 | 0 | if (ZSTD_isError(rc)) |
767 | 0 | goto err; |
768 | | |
769 | 0 | *n = out.pos; |
770 | |
|
771 | 0 | ZSTD_freeDStream(zstd); |
772 | | |
773 | | /* let's keep the nul-terminate tradition */ |
774 | 0 | (*newch)[*n] = '\0'; |
775 | |
|
776 | 0 | return OKDATA; |
777 | 0 | err: |
778 | 0 | ZSTD_freeDStream(zstd); |
779 | 0 | return makeerror(newch, n, "zstd error %d", ZSTD_getErrorCode(rc)); |
780 | 0 | } |
781 | | #endif |
782 | | |
783 | | #ifdef BUILTIN_LZLIB |
784 | | file_private int |
785 | | uncompresslzlib(const unsigned char *old, unsigned char **newch, |
786 | | size_t bytes_max, size_t *n, int extra __attribute__((__unused__))) |
787 | | { |
788 | | enum LZ_Errno err; |
789 | | size_t old_remaining = *n; |
790 | | size_t new_remaining = bytes_max; |
791 | | size_t total_read = 0; |
792 | | unsigned char *bufp; |
793 | | struct LZ_Decoder *dec; |
794 | | |
795 | | bufp = *newch; |
796 | | |
797 | | DPRINTF("builtin lzlib decompression\n"); |
798 | | dec = LZ_decompress_open(); |
799 | | if (!dec) { |
800 | | return makeerror(newch, n, "unable to allocate LZ_Decoder"); |
801 | | } |
802 | | if (LZ_decompress_errno(dec) != LZ_ok) |
803 | | goto err; |
804 | | |
805 | | for (;;) { |
806 | | // LZ_decompress_read() stops at member boundaries, so we may |
807 | | // have more than one successful read after writing all data |
808 | | // we have. |
809 | | if (old_remaining > 0) { |
810 | | int wr = LZ_decompress_write(dec, old, old_remaining); |
811 | | if (wr < 0) |
812 | | goto err; |
813 | | old_remaining -= wr; |
814 | | old += wr; |
815 | | } |
816 | | |
817 | | int rd = LZ_decompress_read(dec, bufp, new_remaining); |
818 | | if (rd > 0) { |
819 | | new_remaining -= rd; |
820 | | bufp += rd; |
821 | | total_read += rd; |
822 | | } |
823 | | |
824 | | if (rd < 0 || LZ_decompress_errno(dec) != LZ_ok) |
825 | | goto err; |
826 | | if (new_remaining == 0) |
827 | | break; |
828 | | if (old_remaining == 0 && rd == 0) |
829 | | break; |
830 | | } |
831 | | |
832 | | LZ_decompress_close(dec); |
833 | | *n = total_read; |
834 | | |
835 | | /* let's keep the nul-terminate tradition */ |
836 | | *bufp = '\0'; |
837 | | |
838 | | return OKDATA; |
839 | | err: |
840 | | err = LZ_decompress_errno(dec); |
841 | | LZ_decompress_close(dec); |
842 | | return makeerror(newch, n, "lzlib error: %s", LZ_strerror(err)); |
843 | | } |
844 | | #endif |
845 | | |
846 | | #ifdef BUILTIN_LRZIP |
847 | | file_private int |
848 | | uncompresslrzip(const unsigned char *old, unsigned char **newch, |
849 | | size_t bytes_max, size_t *n, int extra __attribute__((__unused__))) |
850 | | { |
851 | | Lrzip *lr; |
852 | | FILE *in, *out; |
853 | | int res = OKDATA; |
854 | | |
855 | | DPRINTF("builtin rlzip decompression\n"); |
856 | | lr = lrzip_new(LRZIP_MODE_DECOMPRESS); |
857 | | if (lr == NULL) { |
858 | | res = makeerror(newch, n, "unable to create an lrzip decoder"); |
859 | | goto out0; |
860 | | } |
861 | | lrzip_config_env(lr); |
862 | | in = fmemopen(RCAST(void *, old), bytes_max, "r"); |
863 | | if (in == NULL) { |
864 | | res = makeerror(newch, n, "unable to construct input file"); |
865 | | goto out1; |
866 | | } |
867 | | if (!lrzip_file_add(lr, in)) { |
868 | | res = makeerror(newch, n, "unable to add input file"); |
869 | | goto out2; |
870 | | } |
871 | | *newch = calloc(*n = 2 * bytes_max, 1); |
872 | | if (*newch == NULL) { |
873 | | res = makeerror(newch, n, "unable to allocate output buffer"); |
874 | | goto out2; |
875 | | } |
876 | | out = fmemopen(*newch, *n, "w"); |
877 | | if (out == NULL) { |
878 | | free(*newch); |
879 | | res = makeerror(newch, n, "unable to allocate output file"); |
880 | | goto out2; |
881 | | } |
882 | | lrzip_outfile_set(lr, out); |
883 | | if (lrzip_run(lr)) { |
884 | | free(*newch); |
885 | | res = makeerror(newch, n, "unable to decompress file"); |
886 | | goto out3; |
887 | | } |
888 | | *n = (size_t)ftell(out); |
889 | | out3: |
890 | | fclose(out); |
891 | | out2: |
892 | | fclose(in); |
893 | | out1: |
894 | | lrzip_free(lr); |
895 | | out0: |
896 | | return res; |
897 | | } |
898 | | #endif |
899 | | |
900 | | static int |
901 | | makeerror(unsigned char **buf, size_t *len, const char *fmt, ...) |
902 | 122 | { |
903 | 122 | char *msg; |
904 | 122 | va_list ap; |
905 | 122 | int rv; |
906 | | |
907 | 122 | DPRINTF("Makeerror %s\n", fmt); |
908 | 122 | free(*buf); |
909 | 122 | va_start(ap, fmt); |
910 | 122 | rv = vasprintf(&msg, fmt, ap); |
911 | 122 | va_end(ap); |
912 | 122 | if (rv < 0) { |
913 | 0 | DPRINTF("Makeerror failed"); |
914 | 0 | *buf = NULL; |
915 | 0 | *len = 0; |
916 | 0 | return NODATA; |
917 | 0 | } |
918 | 122 | *buf = RCAST(unsigned char *, msg); |
919 | 122 | *len = strlen(msg); |
920 | 122 | return ERRDATA; |
921 | 122 | } |
922 | | |
923 | | static void |
924 | | closefd(int *fd, size_t i) |
925 | 46.6k | { |
926 | 46.6k | if (fd[i] == -1) |
927 | 13.1k | return; |
928 | 33.5k | (void) close(fd[i]); |
929 | 33.5k | fd[i] = -1; |
930 | 33.5k | } |
931 | | |
932 | | static void |
933 | | closep(int *fd) |
934 | 0 | { |
935 | 0 | size_t i; |
936 | 0 | for (i = 0; i < 2; i++) |
937 | 0 | closefd(fd, i); |
938 | 0 | } |
939 | | |
940 | | static void |
941 | | movedesc(void *v, int i, int fd) |
942 | 19.4k | { |
943 | 19.4k | if (fd == i) |
944 | 0 | return; /* "no dup was necessary" */ |
945 | 19.4k | #ifdef HAVE_POSIX_SPAWNP |
946 | 19.4k | posix_spawn_file_actions_t *fa = RCAST(posix_spawn_file_actions_t *, v); |
947 | 19.4k | posix_spawn_file_actions_adddup2(fa, fd, i); |
948 | 19.4k | posix_spawn_file_actions_addclose(fa, fd); |
949 | | #else |
950 | | if (dup2(fd, i) == -1) { |
951 | | DPRINTF("dup(%d, %d) failed (%s)\n", fd, i, strerror(errno)); |
952 | | exit(EXIT_FAILURE); |
953 | | } |
954 | | close(v ? fd : fd); |
955 | | #endif |
956 | 19.4k | } |
957 | | |
958 | | static void |
959 | | closedesc(void *v, int fd) |
960 | 16.7k | { |
961 | 16.7k | #ifdef HAVE_POSIX_SPAWNP |
962 | 16.7k | posix_spawn_file_actions_t *fa = RCAST(posix_spawn_file_actions_t *, v); |
963 | 16.7k | posix_spawn_file_actions_addclose(fa, fd); |
964 | | #else |
965 | | close(v ? fd : fd); |
966 | | #endif |
967 | 16.7k | } |
968 | | |
969 | | static void |
970 | | handledesc(void *v, int fd, int fdp[3][2]) |
971 | 6.49k | { |
972 | 6.49k | if (fd != -1) { |
973 | 2.70k | (void) lseek(fd, CAST(off_t, 0), SEEK_SET); |
974 | 2.70k | movedesc(v, STDIN_FILENO, fd); |
975 | 3.78k | } else { |
976 | 3.78k | movedesc(v, STDIN_FILENO, fdp[STDIN_FILENO][0]); |
977 | 3.78k | if (fdp[STDIN_FILENO][1] > 2) |
978 | 3.78k | closedesc(v, fdp[STDIN_FILENO][1]); |
979 | 3.78k | } |
980 | | |
981 | 6.49k | file_clear_closexec(STDIN_FILENO); |
982 | | |
983 | | ///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly |
984 | 6.49k | movedesc(v, STDOUT_FILENO, fdp[STDOUT_FILENO][1]); |
985 | 6.49k | if (fdp[STDOUT_FILENO][0] > 2) |
986 | 6.49k | closedesc(v, fdp[STDOUT_FILENO][0]); |
987 | | |
988 | 6.49k | file_clear_closexec(STDOUT_FILENO); |
989 | | |
990 | 6.49k | movedesc(v, STDERR_FILENO, fdp[STDERR_FILENO][1]); |
991 | 6.49k | if (fdp[STDERR_FILENO][0] > 2) |
992 | 6.49k | closedesc(v, fdp[STDERR_FILENO][0]); |
993 | | |
994 | 6.49k | file_clear_closexec(STDERR_FILENO); |
995 | 6.49k | } |
996 | | |
997 | | static pid_t |
998 | | writechild(int fd, const void *old, size_t n) |
999 | 3.78k | { |
1000 | 3.78k | pid_t pid; |
1001 | | |
1002 | | /* |
1003 | | * fork again, to avoid blocking because both |
1004 | | * pipes filled |
1005 | | */ |
1006 | 3.78k | pid = fork(); |
1007 | 3.78k | if (pid == -1) { |
1008 | 0 | DPRINTF("Fork failed (%s)\n", strerror(errno)); |
1009 | 0 | return -1; |
1010 | 0 | } |
1011 | 3.78k | if (pid == 0) { |
1012 | | /* child */ |
1013 | 0 | if (swrite(fd, old, n) != CAST(ssize_t, n)) { |
1014 | 0 | DPRINTF("Write failed (%s)\n", strerror(errno)); |
1015 | 0 | exit(EXIT_FAILURE); |
1016 | 0 | } |
1017 | 0 | exit(EXIT_SUCCESS); |
1018 | 0 | } |
1019 | | /* parent */ |
1020 | 3.78k | return pid; |
1021 | 3.78k | } |
1022 | | |
1023 | | static ssize_t |
1024 | | filter_error(unsigned char *ubuf, ssize_t n) |
1025 | 350 | { |
1026 | 350 | char *p; |
1027 | 350 | char *buf; |
1028 | | |
1029 | 350 | ubuf[n] = '\0'; |
1030 | 350 | buf = RCAST(char *, ubuf); |
1031 | 350 | while (isspace(CAST(unsigned char, *buf))) |
1032 | 81 | buf++; |
1033 | 350 | DPRINTF("Filter error[[[%s]]]\n", buf); |
1034 | 350 | if ((p = strchr(CAST(char *, buf), '\n')) != NULL) |
1035 | 17 | *p = '\0'; |
1036 | 350 | if ((p = strchr(CAST(char *, buf), ';')) != NULL) |
1037 | 0 | *p = '\0'; |
1038 | 350 | if ((p = strrchr(CAST(char *, buf), ':')) != NULL) { |
1039 | 31 | ++p; |
1040 | 31 | while (isspace(CAST(unsigned char, *p))) |
1041 | 27 | p++; |
1042 | 31 | n = strlen(p); |
1043 | 31 | memmove(ubuf, p, CAST(size_t, n + 1)); |
1044 | 31 | } |
1045 | 350 | DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); |
1046 | 350 | if (islower(*ubuf)) |
1047 | 23 | *ubuf = toupper(*ubuf); |
1048 | 350 | return n; |
1049 | 350 | } |
1050 | | |
1051 | | file_private const char * |
1052 | | methodname(size_t method) |
1053 | 472 | { |
1054 | 472 | switch (method) { |
1055 | 0 | #ifdef BUILTIN_DECOMPRESS |
1056 | 25 | case METH_FROZEN: |
1057 | 79 | case METH_ZLIB: |
1058 | 79 | return "zlib"; |
1059 | 0 | #endif |
1060 | 0 | #ifdef BUILTIN_BZLIB |
1061 | 10 | case METH_BZIP: |
1062 | 10 | return "bzlib"; |
1063 | 0 | #endif |
1064 | 0 | #ifdef BUILTIN_XZLIB |
1065 | 3 | case METH_XZ: |
1066 | 9 | case METH_LZMA: |
1067 | 9 | return "xzlib"; |
1068 | 0 | #endif |
1069 | 0 | #ifdef BUILTIN_ZSTDLIB |
1070 | 4 | case METH_ZSTD: |
1071 | 4 | return "zstd"; |
1072 | 0 | #endif |
1073 | | #ifdef BUILTIN_LZLIB |
1074 | | case METH_LZIP: |
1075 | | return "lzlib"; |
1076 | | #endif |
1077 | | #ifdef BUILTIN_LRZIP |
1078 | | case METH_LRZIP: |
1079 | | return "lrzip"; |
1080 | | #endif |
1081 | 370 | default: |
1082 | 370 | return compr[method].argv[0]; |
1083 | 472 | } |
1084 | 472 | } |
1085 | | |
1086 | | file_private int (* |
1087 | | getdecompressor(size_t method))(const unsigned char *, unsigned char **, size_t, |
1088 | | size_t *, int) |
1089 | 6.59k | { |
1090 | 6.59k | switch (method) { |
1091 | 0 | #ifdef BUILTIN_DECOMPRESS |
1092 | 25 | case METH_FROZEN: |
1093 | 25 | return uncompressgzipped; |
1094 | 54 | case METH_ZLIB: |
1095 | 54 | return uncompresszlib; |
1096 | 0 | #endif |
1097 | 0 | #ifdef BUILTIN_BZLIB |
1098 | 10 | case METH_BZIP: |
1099 | 10 | return uncompressbzlib; |
1100 | 0 | #endif |
1101 | 0 | #ifdef BUILTIN_XZLIB |
1102 | 3 | case METH_XZ: |
1103 | 9 | case METH_LZMA: |
1104 | 9 | return uncompressxzlib; |
1105 | 0 | #endif |
1106 | 0 | #ifdef BUILTIN_ZSTDLIB |
1107 | 4 | case METH_ZSTD: |
1108 | 4 | return uncompresszstd; |
1109 | 0 | #endif |
1110 | | #ifdef BUILTIN_LZLIB |
1111 | | case METH_LZIP: |
1112 | | return uncompresslzlib; |
1113 | | #endif |
1114 | | #ifdef BUILTIN_LRZIP |
1115 | | case METH_LRZIP: |
1116 | | return uncompresslrzip; |
1117 | | #endif |
1118 | 6.49k | default: |
1119 | 6.49k | return NULL; |
1120 | 6.59k | } |
1121 | 6.59k | } |
1122 | | |
1123 | | file_private int |
1124 | | uncompressbuf(int fd, size_t bytes_max, size_t method, int nofork, |
1125 | | const unsigned char *old, unsigned char **newch, size_t* n) |
1126 | 6.59k | { |
1127 | 6.59k | int fdp[3][2]; |
1128 | 6.59k | int status, rv, w; |
1129 | 6.59k | pid_t pid; |
1130 | 6.59k | pid_t writepid = -1; |
1131 | 6.59k | size_t i; |
1132 | 6.59k | ssize_t r, re; |
1133 | 6.59k | char *const *args; |
1134 | 6.59k | #ifdef HAVE_POSIX_SPAWNP |
1135 | 6.59k | posix_spawn_file_actions_t fa; |
1136 | 6.59k | #endif |
1137 | 6.59k | int (*decompress)(const unsigned char *, unsigned char **, |
1138 | 6.59k | size_t, size_t *, int) = getdecompressor(method); |
1139 | | |
1140 | 6.59k | *newch = CAST(unsigned char *, malloc(bytes_max + 1)); |
1141 | 6.59k | if (*newch == NULL) |
1142 | 0 | return makeerror(newch, n, "No buffer, %s", strerror(errno)); |
1143 | | |
1144 | 6.59k | if (decompress) { |
1145 | 102 | if (nofork) { |
1146 | 102 | return makeerror(newch, n, |
1147 | 102 | "Fork is required to uncompress, but disabled"); |
1148 | 102 | } |
1149 | 0 | return (*decompress)(old, newch, bytes_max, n, 1); |
1150 | 102 | } |
1151 | | |
1152 | 6.49k | (void)fflush(stdout); |
1153 | 6.49k | (void)fflush(stderr); |
1154 | | |
1155 | 25.9k | for (i = 0; i < __arraycount(fdp); i++) |
1156 | 19.4k | fdp[i][0] = fdp[i][1] = -1; |
1157 | | |
1158 | | /* |
1159 | | * There are multithreaded users who run magic_file() |
1160 | | * from dozens of threads. If two parallel magic_file() calls |
1161 | | * analyze two large compressed files, both will spawn |
1162 | | * an uncompressing child here, which writes out uncompressed data. |
1163 | | * We read some portion, then close the pipe, then waitpid() the child. |
1164 | | * If uncompressed data is larger, child should get EPIPE and exit. |
1165 | | * However, with *parallel* calls OTHER child may unintentionally |
1166 | | * inherit pipe fds, thus keeping pipe open and making writes in |
1167 | | * our child block instead of failing with EPIPE! |
1168 | | * (For the bug to occur, two threads must mutually inherit their pipes, |
1169 | | * and both must have large outputs. Thus it happens not that often). |
1170 | | * To avoid this, be sure to create pipes with O_CLOEXEC. |
1171 | | */ |
1172 | 6.49k | if ((fd == -1 && file_pipe_closexec(fdp[STDIN_FILENO]) == -1) || |
1173 | 6.49k | file_pipe_closexec(fdp[STDOUT_FILENO]) == -1 || |
1174 | 6.49k | file_pipe_closexec(fdp[STDERR_FILENO]) == -1) { |
1175 | 0 | closep(fdp[STDIN_FILENO]); |
1176 | 0 | closep(fdp[STDOUT_FILENO]); |
1177 | 0 | return makeerror(newch, n, "Cannot create pipe, %s", |
1178 | 0 | strerror(errno)); |
1179 | 0 | } |
1180 | | |
1181 | 6.49k | args = RCAST(char *const *, RCAST(intptr_t, compr[method].argv)); |
1182 | 6.49k | #ifdef HAVE_POSIX_SPAWNP |
1183 | 6.49k | posix_spawn_file_actions_init(&fa); |
1184 | | |
1185 | 6.49k | handledesc(&fa, fd, fdp); |
1186 | | |
1187 | 6.49k | DPRINTF("Executing %s\n", compr[method].argv[0]); |
1188 | 6.49k | status = posix_spawnp(&pid, compr[method].argv[0], &fa, NULL, |
1189 | 6.49k | args, NULL); |
1190 | | |
1191 | 6.49k | posix_spawn_file_actions_destroy(&fa); |
1192 | | |
1193 | 6.49k | if (status == -1) { |
1194 | 0 | return makeerror(newch, n, "Cannot posix_spawn `%s', %s", |
1195 | 0 | compr[method].argv[0], strerror(errno)); |
1196 | 0 | } |
1197 | | #else |
1198 | | /* For processes with large mapped virtual sizes, vfork |
1199 | | * may be _much_ faster (10-100 times) than fork. |
1200 | | */ |
1201 | | pid = vfork(); |
1202 | | if (pid == -1) { |
1203 | | return makeerror(newch, n, "Cannot vfork, %s", |
1204 | | strerror(errno)); |
1205 | | } |
1206 | | if (pid == 0) { |
1207 | | /* child */ |
1208 | | /* Note: we are after vfork, do not modify memory |
1209 | | * in a way which confuses parent. In particular, |
1210 | | * do not modify fdp[i][j]. |
1211 | | */ |
1212 | | handledesc(NULL, fd, fdp); |
1213 | | DPRINTF("Executing %s\n", compr[method].argv[0]); |
1214 | | |
1215 | | (void)execvp(compr[method].argv[0], args); |
1216 | | dprintf(STDERR_FILENO, "exec `%s' failed, %s", |
1217 | | compr[method].argv[0], strerror(errno)); |
1218 | | _exit(EXIT_FAILURE); /* _exit(), not exit(), because of vfork */ |
1219 | | } |
1220 | | #endif |
1221 | | /* parent */ |
1222 | | /* Close write sides of child stdout/err pipes */ |
1223 | 19.4k | for (i = 1; i < __arraycount(fdp); i++) |
1224 | 12.9k | closefd(fdp[i], 1); |
1225 | | /* Write the buffer data to child stdin, if we don't have fd */ |
1226 | 6.49k | if (fd == -1) { |
1227 | 3.78k | closefd(fdp[STDIN_FILENO], 0); |
1228 | 3.78k | writepid = writechild(fdp[STDIN_FILENO][1], old, *n); |
1229 | 3.78k | if (writepid == (pid_t)-1) { |
1230 | 0 | rv = makeerror(newch, n, "Write to child failed, %s", |
1231 | 0 | strerror(errno)); |
1232 | 0 | DPRINTF("Write to child failed\n"); |
1233 | 0 | goto err; |
1234 | 0 | } |
1235 | 3.78k | closefd(fdp[STDIN_FILENO], 1); |
1236 | 3.78k | } |
1237 | | |
1238 | 6.49k | rv = OKDATA; |
1239 | 6.49k | r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0); |
1240 | 6.49k | DPRINTF("read got %zd\n", r); |
1241 | 6.49k | if (r < 0) { |
1242 | 0 | rv = ERRDATA; |
1243 | 0 | DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], |
1244 | 0 | strerror(errno)); |
1245 | 0 | goto err; |
1246 | 0 | } |
1247 | 6.49k | if (CAST(size_t, r) == bytes_max) { |
1248 | | /* |
1249 | | * close fd so that the child exits with sigpipe and ignore |
1250 | | * errors, otherwise we risk the child blocking and never |
1251 | | * exiting. |
1252 | | */ |
1253 | 119 | DPRINTF("Closing stdout for bytes_max\n"); |
1254 | 119 | closefd(fdp[STDOUT_FILENO], 0); |
1255 | 119 | goto ok; |
1256 | 119 | } |
1257 | 6.37k | if ((re = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) { |
1258 | 350 | DPRINTF("Got stuff from stderr %s\n", *newch); |
1259 | 350 | rv = ERRDATA; |
1260 | 350 | r = filter_error(*newch, r); |
1261 | 350 | goto ok; |
1262 | 350 | } |
1263 | 6.02k | if (re == 0) |
1264 | 6.02k | goto ok; |
1265 | 0 | rv = makeerror(newch, n, "Read stderr failed, %s", |
1266 | 0 | strerror(errno)); |
1267 | 0 | goto err; |
1268 | 6.49k | ok: |
1269 | 6.49k | *n = r; |
1270 | | /* NUL terminate, as every buffer is handled here. */ |
1271 | 6.49k | (*newch)[*n] = '\0'; |
1272 | 6.49k | err: |
1273 | 6.49k | closefd(fdp[STDIN_FILENO], 1); |
1274 | 6.49k | closefd(fdp[STDOUT_FILENO], 0); |
1275 | 6.49k | closefd(fdp[STDERR_FILENO], 0); |
1276 | | |
1277 | 6.49k | w = waitpid(pid, &status, 0); |
1278 | 10.2k | wait_err: |
1279 | 10.2k | if (w == -1) { |
1280 | 20 | rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); |
1281 | 20 | DPRINTF("Child wait return %#x\n", status); |
1282 | 10.2k | } else if (!WIFEXITED(status)) { |
1283 | 0 | DPRINTF("Child not exited (%#x)\n", status); |
1284 | 10.2k | } else if (WEXITSTATUS(status) != 0) { |
1285 | 4.25k | DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status)); |
1286 | 4.25k | } |
1287 | 10.2k | if (writepid > 0) { |
1288 | | /* _After_ we know decompressor has exited, our input writer |
1289 | | * definitely will exit now (at worst, writing fails in it, |
1290 | | * since output fd is closed now on the reading size). |
1291 | | */ |
1292 | 3.78k | w = waitpid(writepid, &status, 0); |
1293 | 3.78k | writepid = -1; |
1294 | 3.78k | goto wait_err; |
1295 | 3.78k | } |
1296 | | |
1297 | 6.49k | closefd(fdp[STDIN_FILENO], 0); //why? it is already closed here! |
1298 | 6.49k | DPRINTF("Returning %p n=%" SIZE_T_FORMAT "u rv=%d\n", *newch, *n, rv); |
1299 | | |
1300 | 6.49k | return rv; |
1301 | 10.2k | } |
1302 | | #endif |