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