summaryrefslogtreecommitdiffstats
path: root/usr.bin/file/compress.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/file/compress.c')
-rw-r--r--usr.bin/file/compress.c185
1 files changed, 134 insertions, 51 deletions
diff --git a/usr.bin/file/compress.c b/usr.bin/file/compress.c
index 1c70d56bb5b..a17a1d32861 100644
--- a/usr.bin/file/compress.c
+++ b/usr.bin/file/compress.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: compress.c,v 1.11 2004/05/19 02:32:35 tedu Exp $ */
+/* $OpenBSD: compress.c,v 1.12 2008/05/08 01:40:56 chl Exp $ */
/*
* Copyright (c) Ian F. Darwin 1986-1995.
* Software written by Ian F. Darwin and others;
@@ -43,19 +43,22 @@
#include <string.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/ioctl.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
-#undef HAVE_LIBZ
+#if defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
#ifdef HAVE_LIBZ
#include <zlib.h>
#endif
+
#ifndef lint
-FILE_RCSID("@(#)$Id: compress.c,v 1.11 2004/05/19 02:32:35 tedu Exp $")
+FILE_RCSID("@(#)$Id: compress.c,v 1.12 2008/05/08 01:40:56 chl Exp $")
#endif
-
private struct {
const char *magic;
size_t maglen;
@@ -71,23 +74,27 @@ private struct {
{ "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */
/* the standard pack utilities do not accept standard input */
{ "\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 */
};
-private int ncompr = sizeof(compr) / sizeof(compr[0]);
+private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
+
+#define NODATA ((size_t)~0)
private ssize_t swrite(int, const void *, size_t);
-private ssize_t sread(int, void *, size_t);
-private size_t uncompressbuf(struct magic_set *, 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 HAVE_LIBZ
private size_t uncompressgzipped(struct magic_set *, const unsigned char *,
unsigned char **, size_t);
#endif
protected int
-file_zmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
+file_zmagic(struct magic_set *ms, int fd, const char *name,
+ const unsigned char *buf, size_t nbytes)
{
unsigned char *newbuf = NULL;
size_t i, nsz;
@@ -100,14 +107,15 @@ file_zmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
if (nbytes < compr[i].maglen)
continue;
if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
- (nsz = uncompressbuf(ms, i, buf, &newbuf, nbytes)) != 0) {
+ (nsz = uncompressbuf(ms, fd, i, buf, &newbuf,
+ nbytes)) != NODATA) {
ms->flags &= ~MAGIC_COMPRESS;
rv = -1;
- if (file_buffer(ms, newbuf, nsz) == -1)
+ if (file_buffer(ms, -1, name, newbuf, nsz) == -1)
goto error;
if (file_printf(ms, " (") == -1)
goto error;
- if (file_buffer(ms, buf, nbytes) == -1)
+ if (file_buffer(ms, -1, NULL, buf, nbytes) == -1)
goto error;
if (file_printf(ms, ")") == -1)
goto error;
@@ -150,14 +158,55 @@ swrite(int fd, const void *buf, size_t n)
/*
* `safe' read for sockets and pipes.
*/
-private ssize_t
-sread(int fd, void *buf, size_t n)
+protected ssize_t
+sread(int fd, void *buf, size_t n, int canbepipe)
{
- int rv;
+ int rv, cnt;
+#ifdef FIONREAD
+ int t = 0;
+#endif
size_t rn = n;
+ if (fd == STDIN_FILENO)
+ goto nocheck;
+
+#ifdef FIONREAD
+ if ((canbepipe && (ioctl(fd, FIONREAD, &t) == -1)) || (t == 0)) {
+#ifdef FD_ZERO
+ for (cnt = 0;; cnt++) {
+ fd_set check;
+ struct timeval tout = {0, 100 * 1000};
+ int selrv;
+
+ FD_ZERO(&check);
+ FD_SET(fd, &check);
+
+ /*
+ * Avoid soft deadlock: do not read if there
+ * is nothing to read from sockets and pipes.
+ */
+ selrv = select(fd + 1, &check, NULL, NULL, &tout);
+ if (selrv == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ } else if (selrv == 0 && cnt >= 5) {
+ return 0;
+ } else
+ break;
+ }
+#endif
+ (void)ioctl(fd, FIONREAD, &t);
+ }
+
+ if (t > 0 && (size_t)t < n) {
+ n = t;
+ rn = n;
+ }
+#endif
+
+nocheck:
do
- switch (rv = read(fd, buf, n)) {
+ switch ((rv = read(fd, buf, n))) {
case -1:
if (errno == EINTR)
continue;
@@ -204,7 +253,7 @@ file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
r = 1;
else {
- while ((r = sread(fd, buf, sizeof(buf))) > 0)
+ while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
if (swrite(tfd, buf, (size_t)r) != r)
break;
}
@@ -300,82 +349,116 @@ uncompressgzipped(struct magic_set *ms, const unsigned char *old,
}
n = (size_t)z.total_out;
- inflateEnd(&z);
+ (void)inflateEnd(&z);
/* let's keep the nul-terminate tradition */
- (*newch)[n++] = '\0';
+ (*newch)[n] = '\0';
return n;
}
#endif
private size_t
-uncompressbuf(struct magic_set *ms, size_t method, const unsigned char *old,
- unsigned char **newch, size_t n)
+uncompressbuf(struct magic_set *ms, int fd, size_t method,
+ const unsigned char *old, unsigned char **newch, size_t n)
{
int fdin[2], fdout[2];
int r;
- /* The buffer is NUL terminated, and we don't need that. */
- n--;
-
#ifdef HAVE_LIBZ
if (method == 2)
return uncompressgzipped(ms, old, newch, n);
#endif
+ (void)fflush(stdout);
+ (void)fflush(stderr);
- if (pipe(fdin) == -1 || pipe(fdout) == -1) {
+ if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) {
file_error(ms, errno, "cannot create pipe");
- return 0;
+ return NODATA;
}
switch (fork()) {
case 0: /* child */
(void) close(0);
- (void) dup(fdin[0]);
- (void) close(fdin[0]);
- (void) close(fdin[1]);
+ if (fd != -1) {
+ (void) dup(fd);
+ (void) lseek(0, (off_t)0, SEEK_SET);
+ } else {
+ (void) dup(fdin[0]);
+ (void) close(fdin[0]);
+ (void) close(fdin[1]);
+ }
(void) close(1);
(void) dup(fdout[1]);
(void) close(fdout[0]);
(void) close(fdout[1]);
+#ifndef DEBUG
if (compr[method].silent)
- (void) close(2);
+ (void)close(2);
+#endif
- execvp(compr[method].argv[0],
- (char *const *)compr[method].argv);
+ (void)execvp(compr[method].argv[0],
+ (char *const *)(intptr_t)compr[method].argv);
+#ifdef DEBUG
+ (void)fprintf(stderr, "exec `%s' failed (%s)\n",
+ compr[method].argv[0], strerror(errno));
+#endif
exit(1);
/*NOTREACHED*/
case -1:
file_error(ms, errno, "could not fork");
- return 0;
+ return NODATA;
default: /* parent */
- (void) close(fdin[0]);
(void) close(fdout[1]);
- /* fork again, to avoid blocking because both pipes filled */
- switch (fork()) {
- case 0: /* child */
- (void)close(fdout[0]);
- if (swrite(fdin[1], old, n) != n)
+ 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);
- exit(0);
- /*NOTREACHED*/
+ /*NOTREACHED*/
- case -1:
- exit(1);
- /*NOTREACHED*/
-
- default: /* parent */
- break;
+ default: /* parent */
+ break;
+ }
+ (void) close(fdin[1]);
+ fdin[1] = -1;
}
- (void) close(fdin[1]);
- fdin[1] = -1;
+
if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) {
+#ifdef DEBUG
+ (void)fprintf(stderr, "Malloc failed (%s)\n",
+ strerror(errno));
+#endif
n = 0;
goto err;
}
- if ((r = sread(fdout[0], *newch, HOWMANY)) <= 0) {
+ if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) {
+#ifdef DEBUG
+ (void)fprintf(stderr, "Read failed (%s)\n",
+ strerror(errno));
+#endif
free(*newch);
n = 0;
newch[0] = '\0';
@@ -384,7 +467,7 @@ uncompressbuf(struct magic_set *ms, size_t method, const unsigned char *old,
n = r;
}
/* NUL terminate, as every buffer is handled here. */
- (*newch)[n++] = '\0';
+ (*newch)[n] = '\0';
err:
if (fdin[1] != -1)
(void) close(fdin[1]);