diff options
Diffstat (limited to 'contrib/file/src/compress.c')
-rw-r--r-- | contrib/file/src/compress.c | 589 |
1 files changed, 191 insertions, 398 deletions
diff --git a/contrib/file/src/compress.c b/contrib/file/src/compress.c index ad86431..539031e 100644 --- a/contrib/file/src/compress.c +++ b/contrib/file/src/compress.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.93 2016/03/31 17:51:12 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.80 2015/06/03 18:21:24 christos Exp $") #endif #include "magic.h" @@ -45,8 +45,6 @@ FILE_RCSID("@(#)$File: compress.c,v 1.93 2016/03/31 17:51:12 christos Exp $") #endif #include <string.h> #include <errno.h> -#include <ctype.h> -#include <stdarg.h> #ifdef HAVE_SIGNAL_H #include <signal.h> # ifndef HAVE_SIG_T @@ -65,119 +63,43 @@ typedef void (*sig_t)(int); #if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) #define BUILTIN_DECOMPRESS #include <zlib.h> -#define ZLIBSUPPORT #endif -#ifdef DEBUG -int tty = -1; -#define DPRINTF(...) do { \ - if (tty == -1) \ - tty = open("/dev/tty", O_RDWR); \ - if (tty == -1) \ - abort(); \ - dprintf(tty, __VA_ARGS__); \ -} while (/*CONSTCOND*/0) -#else -#define DPRINTF(...) -#endif - -#ifdef ZLIBSUPPORT -/* - * The following python code is not really used because ZLIBSUPPORT is only - * defined if we have a built-in zlib, and the built-in zlib handles that. - */ -static const char zlibcode[] = - "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))"; - -static const char *zlib_args[] = { "python", "-c", zlibcode, NULL }; - -static int -zlibcmp(const unsigned char *buf) -{ - unsigned short x = 1; - unsigned char *s = (unsigned char *)&x; - - if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0) - return 0; - if (s[0] != 1) /* endianness test */ - x = buf[0] | (buf[1] << 8); - else - x = buf[1] | (buf[0] << 8); - if (x % 31) - return 0; - return 1; -} -#endif - -#define gzip_flags "-cd" -#define lrzip_flags "-do" -#define lzip_flags gzip_flags - -static const char *gzip_args[] = { - "gzip", gzip_flags, NULL -}; -static const char *uncompress_args[] = { - "uncompress", "-c", NULL -}; -static const char *bzip2_args[] = { - "bzip2", "-cd", NULL -}; -static const char *lzip_args[] = { - "lzip", lzip_flags, NULL -}; -static const char *xz_args[] = { - "xz", "-cd", NULL -}; -static const char *lrzip_args[] = { - "lrzip", lrzip_flags, NULL -}; -static const char *lz4_args[] = { - "lz4", "-cd", NULL -}; private const struct { - const void *magic; + const char magic[8]; size_t maglen; - const char **argv; + const char *argv[3]; + int silent; } compr[] = { - { "\037\235", 2, gzip_args }, /* compressed */ + { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */ /* Uncompress can get stuck; so use gzip first if we have it * Idea from Damien Clark, thanks! */ - { "\037\235", 2, uncompress_args }, /* compressed */ - { "\037\213", 2, gzip_args }, /* gzipped */ - { "\037\236", 2, gzip_args }, /* frozen */ - { "\037\240", 2, gzip_args }, /* SCO LZH */ + { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */ + { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */ + { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */ + { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */ /* the standard pack utilities do not accept standard input */ - { "\037\036", 2, gzip_args }, /* packed */ - { "PK\3\4", 4, gzip_args }, /* pkzipped, */ - /* ...only first file examined */ - { "BZh", 3, bzip2_args }, /* bzip2-ed */ - { "LZIP", 4, lzip_args }, /* lzip-ed */ - { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */ - { "LRZI", 4, lrzip_args }, /* LRZIP */ - { "\004\"M\030",4, lz4_args }, /* LZ4 */ -#ifdef ZLIBSUPPORT - { zlibcmp, 0, zlib_args }, /* zlib */ -#endif + { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */ + { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 }, /* pkzipped, */ + /* ...only first file examined */ + { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */ + { "LZIP", 4, { "lzip", "-cdq", NULL }, 1 }, + { "\3757zXZ\0",6,{ "xz", "-cd", NULL }, 1 }, /* XZ Utils */ + { "LRZI", 4, { "lrzip", "-dqo-", NULL }, 1 }, /* LRZIP */ + { "\004\"M\030", 4, { "lz4", "-cd", NULL }, 1 }, /* LZ4 */ }; -#define OKDATA 0 -#define NODATA 1 -#define ERRDATA 2 +#define NODATA ((size_t)~0) private ssize_t swrite(int, const void *, size_t); #if HAVE_FORK private size_t ncompr = sizeof(compr) / sizeof(compr[0]); -private int uncompressbuf(int, size_t, size_t, const unsigned char *, - unsigned char **, size_t *); +private size_t uncompressbuf(struct magic_set *, int, size_t, + const unsigned char *, unsigned char **, size_t); #ifdef BUILTIN_DECOMPRESS -private int uncompresszlib(const unsigned char *, unsigned char **, size_t, - size_t *, int); -private int uncompressgzipped(const unsigned char *, unsigned char **, size_t, - size_t *); +private size_t uncompressgzipped(struct magic_set *, const unsigned char *, + unsigned char **, size_t); #endif -static int makeerror(unsigned char **, size_t *, const char *, ...) - __attribute__((__format__(__printf__, 3, 4))); -private const char *methodname(size_t); protected int file_zmagic(struct magic_set *ms, int fd, const char *name, @@ -185,8 +107,6 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, { unsigned char *newbuf = NULL; size_t i, nsz; - char *rbuf; - file_pushbuf_t *pb; int rv = 0; int mime = ms->flags & MAGIC_MIME; #ifdef HAVE_SIGNAL_H @@ -200,72 +120,37 @@ file_zmagic(struct magic_set *ms, int fd, const char *name, osigpipe = signal(SIGPIPE, SIG_IGN); #endif for (i = 0; i < ncompr; i++) { - int zm; if (nbytes < compr[i].maglen) continue; -#ifdef ZLIBSUPPORT - if (compr[i].maglen == 0) - zm = (CAST(int (*)(const unsigned char *), - CCAST(void *, compr[i].magic)))(buf); - else -#endif - zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0; - - if (!zm) - continue; - nsz = nbytes; - rv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz); - DPRINTF("uncompressbuf = %d, %s, %zu\n", rv, (char *)newbuf, - nsz); - switch (rv) { - case OKDATA: - case ERRDATA: - + if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 && + (nsz = uncompressbuf(ms, fd, i, buf, &newbuf, + nbytes)) != NODATA) { ms->flags &= ~MAGIC_COMPRESS; - if (rv == ERRDATA) - rv = file_printf(ms, "%s ERROR: %s", - methodname(i), newbuf); - else - rv = file_buffer(ms, -1, name, newbuf, nsz); - if (rv == -1) + rv = -1; + if (file_buffer(ms, -1, name, newbuf, nsz) == -1) goto error; - DPRINTF("rv = %d\n", rv); - if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0) - goto out; - if (mime != MAGIC_MIME && mime != 0) - goto out; - if ((file_printf(ms, - mime ? " compressed-encoding=" : " (")) == -1) - goto error; - if ((pb = file_push_buffer(ms)) == NULL) - goto error; - if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) - goto error; - if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { - if (file_printf(ms, "%s", rbuf) == -1) { - free(rbuf); + + if ((ms->flags & MAGIC_COMPRESS_TRANSP) == 0 && + (mime == MAGIC_MIME || mime == 0)) { + if (file_printf(ms, mime ? + " compressed-encoding=" : " (") == -1) + goto error; + if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) + goto error; + if (!mime && file_printf(ms, ")") == -1) goto error; - } - free(rbuf); } - if (!mime && file_printf(ms, ")") == -1) - goto error; - goto out; - case NODATA: - goto out; - default: - abort(); + + rv = 1; + break; } } -out: - rv = 1; error: #ifdef HAVE_SIGNAL_H (void)signal(SIGPIPE, osigpipe); #endif free(newbuf); ms->flags |= MAGIC_COMPRESS; - DPRINTF("Zmagic returns %d\n", rv); return rv; } #endif @@ -437,314 +322,222 @@ file_pipe2file(struct magic_set *ms, int fd, const void *startbuf, #define FNAME (1 << 3) #define FCOMMENT (1 << 4) - -private int -uncompressgzipped(const unsigned char *old, unsigned char **newch, - size_t bytes_max, size_t *n) +private size_t +uncompressgzipped(struct magic_set *ms, const unsigned char *old, + unsigned char **newch, size_t n) { unsigned char flg = old[3]; size_t data_start = 10; + z_stream z; + int rc; if (flg & FEXTRA) { - if (data_start + 1 >= *n) - goto err; + if (data_start+1 >= n) + return 0; data_start += 2 + old[data_start] + old[data_start + 1] * 256; } if (flg & FNAME) { - while(data_start < *n && old[data_start]) + while(data_start < n && old[data_start]) data_start++; data_start++; } - if (flg & FCOMMENT) { - while(data_start < *n && old[data_start]) + if(flg & FCOMMENT) { + while(data_start < n && old[data_start]) data_start++; data_start++; } - if (flg & FHCRC) + if(flg & FHCRC) data_start += 2; - if (data_start >= *n) - goto err; - - *n -= data_start; - old += data_start; - return uncompresszlib(old, newch, bytes_max, n, 0); -err: - return makeerror(newch, n, "File too short"); -} - -private int -uncompresszlib(const unsigned char *old, unsigned char **newch, - size_t bytes_max, size_t *n, int zlib) -{ - int rc; - z_stream z; - - if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) - return makeerror(newch, n, "No buffer, %s", strerror(errno)); - - z.next_in = CCAST(Bytef *, old); - z.avail_in = CAST(uint32_t, *n); + if (data_start >= n) + return 0; + if ((*newch = CAST(unsigned char *, malloc(HOWMANY + 1))) == NULL) { + return 0; + } + + /* XXX: const castaway, via strchr */ + z.next_in = (Bytef *)strchr((const char *)old + data_start, + old[data_start]); + z.avail_in = CAST(uint32_t, (n - data_start)); z.next_out = *newch; - z.avail_out = bytes_max; + z.avail_out = HOWMANY; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; /* LINTED bug in header macro */ - rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15); - if (rc != Z_OK) - goto err; + rc = inflateInit2(&z, -15); + if (rc != Z_OK) { + file_error(ms, 0, "zlib: %s", z.msg); + return 0; + } rc = inflate(&z, Z_SYNC_FLUSH); - if (rc != Z_OK && rc != Z_STREAM_END) - goto err; + if (rc != Z_OK && rc != Z_STREAM_END) { + file_error(ms, 0, "zlib: %s", z.msg); + return 0; + } - *n = (size_t)z.total_out; - rc = inflateEnd(&z); - if (rc != Z_OK) - goto err; + n = (size_t)z.total_out; + (void)inflateEnd(&z); /* let's keep the nul-terminate tradition */ - (*newch)[*n] = '\0'; - - return OKDATA; -err: - strlcpy((char *)*newch, z.msg, bytes_max); - *n = strlen((char *)*newch); - return ERRDATA; -} -#endif - -static int -makeerror(unsigned char **buf, size_t *len, const char *fmt, ...) -{ - char *msg; - va_list ap; - int rv; - - va_start(ap, fmt); - rv = vasprintf(&msg, fmt, ap); - va_end(ap); - if (rv < 0) { - *buf = NULL; - *len = 0; - return NODATA; - } - *buf = (unsigned char *)msg; - *len = strlen(msg); - return ERRDATA; -} - -static void -closefd(int *fd, size_t i) -{ - if (fd[i] == -1) - return; - (void) close(fd[i]); - fd[i] = -1; -} - -static void -closep(int *fd) -{ - size_t i; - for (i = 0; i < 2; i++) - closefd(fd, i); -} - -static void -copydesc(int i, int *fd) -{ - int j = fd[i == STDIN_FILENO ? 0 : 1]; - if (j == i) - return; - if (dup2(j, i) == -1) { - DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno)); - exit(1); - } - closep(fd); -} - -static void -writechild(int fdp[3][2], const void *old, size_t n) -{ - int status; - - closefd(fdp[STDIN_FILENO], 0); - /* - * fork again, to avoid blocking because both - * pipes filled - */ - switch (fork()) { - case 0: /* child */ - closefd(fdp[STDOUT_FILENO], 0); - if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) { - DPRINTF("Write failed (%s)\n", strerror(errno)); - exit(1); - } - exit(0); - /*NOTREACHED*/ - - case -1: - DPRINTF("Fork failed (%s)\n", strerror(errno)); - exit(1); - /*NOTREACHED*/ + (*newch)[n] = '\0'; - default: /* parent */ - if (wait(&status) == -1) { - DPRINTF("Wait failed (%s)\n", strerror(errno)); - exit(1); - } - DPRINTF("Grandchild wait return %#x\n", status); - } - closefd(fdp[STDIN_FILENO], 1); -} - -static ssize_t -filter_error(unsigned char *ubuf, ssize_t n) -{ - char *p; - char *buf; - - ubuf[n] = '\0'; - buf = (char *)ubuf; - while (isspace((unsigned char)*buf)) - buf++; - DPRINTF("Filter error[[[%s]]]\n", buf); - if ((p = strchr((char *)buf, '\n')) != NULL) - *p = '\0'; - if ((p = strchr((char *)buf, ';')) != NULL) - *p = '\0'; - if ((p = strrchr((char *)buf, ':')) != NULL) { - ++p; - while (isspace((unsigned char)*p)) - p++; - n = strlen(p); - memmove(ubuf, p, n + 1); - } - DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf); - if (islower(*ubuf)) - *ubuf = toupper(*ubuf); return n; } - -private const char * -methodname(size_t method) -{ -#ifdef BUILTIN_DECOMPRESS - /* FIXME: This doesn't cope with bzip2 */ - if (method == 2 || compr[method].maglen == 0) - return "zlib"; #endif - return compr[method].argv[0]; -} -private int -uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old, - unsigned char **newch, size_t* n) +private size_t +uncompressbuf(struct magic_set *ms, int fd, size_t method, + const unsigned char *old, unsigned char **newch, size_t n) { - int fdp[3][2]; - int status, rv; - size_t i; + int fdin[2], fdout[2]; + int status; ssize_t r; #ifdef BUILTIN_DECOMPRESS /* FIXME: This doesn't cope with bzip2 */ if (method == 2) - return uncompressgzipped(old, newch, bytes_max, n); - if (compr[method].maglen == 0) - return uncompresszlib(old, newch, bytes_max, n, 1); + return uncompressgzipped(ms, old, newch, n); #endif (void)fflush(stdout); (void)fflush(stderr); - for (i = 0; i < __arraycount(fdp); i++) - fdp[i][0] = fdp[i][1] = -1; - - if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) || - pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) { - closep(fdp[STDIN_FILENO]); - closep(fdp[STDOUT_FILENO]); - return makeerror(newch, n, "Cannot create pipe, %s", - strerror(errno)); + if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) { + file_error(ms, errno, "cannot create pipe"); + return NODATA; } switch (fork()) { case 0: /* child */ + (void) close(0); if (fd != -1) { - fdp[STDIN_FILENO][0] = fd; - (void) lseek(fd, (off_t)0, SEEK_SET); + if (dup(fd) == -1) + _exit(1); + (void) lseek(0, (off_t)0, SEEK_SET); + } else { + if (dup(fdin[0]) == -1) + _exit(1); + (void) close(fdin[0]); + (void) close(fdin[1]); } - - for (i = 0; i < __arraycount(fdp); i++) - copydesc(i, fdp[i]); + + (void) close(1); + if (dup(fdout[1]) == -1) + _exit(1); + (void) close(fdout[0]); + (void) close(fdout[1]); +#ifndef DEBUG + if (compr[method].silent) + (void)close(2); +#endif (void)execvp(compr[method].argv[0], (char *const *)(intptr_t)compr[method].argv); - dprintf(STDERR_FILENO, "exec `%s' failed, %s", +#ifdef DEBUG + (void)fprintf(stderr, "exec `%s' failed (%s)\n", compr[method].argv[0], strerror(errno)); +#endif exit(1); /*NOTREACHED*/ case -1: - return makeerror(newch, n, "Cannot fork, %s", - strerror(errno)); + file_error(ms, errno, "could not fork"); + return NODATA; default: /* parent */ - for (i = 1; i < __arraycount(fdp); i++) - closefd(fdp[i], 1); + (void) close(fdout[1]); + if (fd == -1) { + (void) close(fdin[0]); + /* + * fork again, to avoid blocking because both + * pipes filled + */ + switch (fork()) { + case 0: /* child */ + (void)close(fdout[0]); + if (swrite(fdin[1], old, n) != (ssize_t)n) { +#ifdef DEBUG + (void)fprintf(stderr, + "Write failed (%s)\n", + strerror(errno)); +#endif + exit(1); + } + exit(0); + /*NOTREACHED*/ + + case -1: +#ifdef DEBUG + (void)fprintf(stderr, "Fork failed (%s)\n", + strerror(errno)); +#endif + exit(1); + /*NOTREACHED*/ - /* Write the buffer data to the child, if we don't have fd */ - if (fd == -1) - writechild(fdp, old, *n); + default: /* parent */ + if (wait(&status) == -1) { +#ifdef DEBUG + (void)fprintf(stderr, + "Wait failed (%s)\n", + strerror(errno)); +#endif + exit(1); + } + exit(WIFEXITED(status) ? + WEXITSTATUS(status) : 1); + /*NOTREACHED*/ + } + (void) close(fdin[1]); + fdin[1] = -1; + } - *newch = CAST(unsigned char *, malloc(bytes_max + 1)); - if (*newch == NULL) { - rv = makeerror(newch, n, "No buffer, %s", + if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) { +#ifdef DEBUG + (void)fprintf(stderr, "Malloc failed (%s)\n", strerror(errno)); +#endif + n = NODATA; goto err; } - rv = OKDATA; - if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0) - break; - DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0], - r != -1 ? strerror(errno) : "no data"); - - rv = ERRDATA; - if (r == 0 && - (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0) - { - r = filter_error(*newch, r); - break; + if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) { +#ifdef DEBUG + (void)fprintf(stderr, "Read failed (%s)\n", + strerror(errno)); +#endif + free(*newch); + n = NODATA; + *newch = NULL; + goto err; + } else { + n = r; } - free(*newch); - if (r == 0) - rv = makeerror(newch, n, "Read failed, %s", + /* NUL terminate, as every buffer is handled here. */ + (*newch)[n] = '\0'; +err: + if (fdin[1] != -1) + (void) close(fdin[1]); + (void) close(fdout[0]); + if (wait(&status) == -1) { +#ifdef DEBUG + (void)fprintf(stderr, "Wait failed (%s)\n", strerror(errno)); - else - rv = makeerror(newch, n, "No data"); - goto err; - } +#endif + n = NODATA; + } else if (!WIFEXITED(status)) { +#ifdef DEBUG + (void)fprintf(stderr, "Child not exited (0x%x)\n", + status); +#endif + } else if (WEXITSTATUS(status) != 0) { +#ifdef DEBUG + (void)fprintf(stderr, "Child exited (0x%d)\n", + WEXITSTATUS(status)); +#endif + } - *n = r; - /* NUL terminate, as every buffer is handled here. */ - (*newch)[*n] = '\0'; -err: - closefd(fdp[STDIN_FILENO], 1); - closefd(fdp[STDOUT_FILENO], 0); - closefd(fdp[STDERR_FILENO], 0); - if (wait(&status) == -1) { - free(*newch); - rv = makeerror(newch, n, "Wait failed, %s", strerror(errno)); - DPRINTF("Child wait return %#x\n", status); - } else if (!WIFEXITED(status)) { - DPRINTF("Child not exited (0x%x)\n", status); - } else if (WEXITSTATUS(status) != 0) { - DPRINTF("Child exited (0x%d)\n", WEXITSTATUS(status)); + (void) close(fdin[0]); + + return n; } - - closefd(fdp[STDIN_FILENO], 0); - DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv); - - return rv; } #endif |