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