summaryrefslogtreecommitdiffstats
path: root/contrib/file/softmagic.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/file/softmagic.c')
-rw-r--r--contrib/file/softmagic.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/contrib/file/softmagic.c b/contrib/file/softmagic.c
new file mode 100644
index 0000000..2fb4c4a
--- /dev/null
+++ b/contrib/file/softmagic.c
@@ -0,0 +1,569 @@
+/*
+ * softmagic - interpret variable magic from /etc/magic
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or of the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of this
+ * software, no matter how awful, even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$Id: softmagic.c,v 1.42 2000/08/05 17:36:49 christos Exp $")
+#endif /* lint */
+
+static int match __P((unsigned char *, int));
+static int mget __P((union VALUETYPE *,
+ unsigned char *, struct magic *, int));
+static int mcheck __P((union VALUETYPE *, struct magic *));
+static int32 mprint __P((union VALUETYPE *, struct magic *));
+static void mdebug __P((int32, char *, int));
+static int mconvert __P((union VALUETYPE *, struct magic *));
+
+/*
+ * softmagic - lookup one file in database
+ * (already read from /etc/magic by apprentice.c).
+ * Passed the name and FILE * of one file to be typed.
+ */
+/*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
+int
+softmagic(buf, nbytes)
+ unsigned char *buf;
+ int nbytes;
+{
+ if (match(buf, nbytes))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Go through the whole list, stopping if you find a match. Process all
+ * the continuations of that match before returning.
+ *
+ * We support multi-level continuations:
+ *
+ * At any time when processing a successful top-level match, there is a
+ * current continuation level; it represents the level of the last
+ * successfully matched continuation.
+ *
+ * Continuations above that level are skipped as, if we see one, it
+ * means that the continuation that controls them - i.e, the
+ * lower-level continuation preceding them - failed to match.
+ *
+ * Continuations below that level are processed as, if we see one,
+ * it means we've finished processing or skipping higher-level
+ * continuations under the control of a successful or unsuccessful
+ * lower-level continuation, and are now seeing the next lower-level
+ * continuation and should process it. The current continuation
+ * level reverts to the level of the one we're seeing.
+ *
+ * Continuations at the current level are processed as, if we see
+ * one, there's no lower-level continuation that may have failed.
+ *
+ * If a continuation matches, we bump the current continuation level
+ * so that higher-level continuations are processed.
+ */
+static int
+match(s, nbytes)
+ unsigned char *s;
+ int nbytes;
+{
+ int magindex = 0;
+ int cont_level = 0;
+ int need_separator = 0;
+ union VALUETYPE p;
+ static int32 *tmpoff = NULL;
+ static size_t tmplen = 0;
+ int32 oldoff = 0;
+ int returnval = 0; /* if a match is found it is set to 1*/
+ extern int kflag;
+ int firstline = 1; /* a flag to print X\n X\n- X */
+
+ if (tmpoff == NULL)
+ if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
+ error("out of memory\n");
+
+ for (magindex = 0; magindex < nmagic; magindex++) {
+ /* if main entry matches, print it... */
+ if (!mget(&p, s, &magic[magindex], nbytes) ||
+ !mcheck(&p, &magic[magindex])) {
+ /*
+ * main entry didn't match,
+ * flush its continuations
+ */
+ while (magindex < nmagic &&
+ magic[magindex + 1].cont_level != 0)
+ magindex++;
+ continue;
+ }
+
+ if (! firstline) { /* we found another match */
+ /* put a newline and '-' to do some simple formatting*/
+ printf("\n- ");
+ }
+
+ tmpoff[cont_level] = mprint(&p, &magic[magindex]);
+ /*
+ * If we printed something, we'll need to print
+ * a blank before we print something else.
+ */
+ if (magic[magindex].desc[0])
+ need_separator = 1;
+ /* and any continuations that match */
+ if (++cont_level >= tmplen)
+ if ((tmpoff = (int32 *) realloc(tmpoff,
+ tmplen += 20)) == NULL)
+ error("out of memory\n");
+ while (magic[magindex+1].cont_level != 0 &&
+ ++magindex < nmagic) {
+ if (cont_level >= magic[magindex].cont_level) {
+ if (cont_level > magic[magindex].cont_level) {
+ /*
+ * We're at the end of the level
+ * "cont_level" continuations.
+ */
+ cont_level = magic[magindex].cont_level;
+ }
+ if (magic[magindex].flag & ADD) {
+ oldoff=magic[magindex].offset;
+ magic[magindex].offset += tmpoff[cont_level-1];
+ }
+ if (mget(&p, s, &magic[magindex], nbytes) &&
+ mcheck(&p, &magic[magindex])) {
+ /*
+ * This continuation matched.
+ * Print its message, with
+ * a blank before it if
+ * the previous item printed
+ * and this item isn't empty.
+ */
+ /* space if previous printed */
+ if (need_separator
+ && (magic[magindex].nospflag == 0)
+ && (magic[magindex].desc[0] != '\0')
+ ) {
+ (void) putchar(' ');
+ need_separator = 0;
+ }
+ tmpoff[cont_level] = mprint(&p, &magic[magindex]);
+ if (magic[magindex].desc[0])
+ need_separator = 1;
+
+ /*
+ * If we see any continuations
+ * at a higher level,
+ * process them.
+ */
+ if (++cont_level >= tmplen)
+ if ((tmpoff =
+ (int32 *) realloc(tmpoff,
+ tmplen += 20)) == NULL)
+ error("out of memory\n");
+ }
+ if (magic[magindex].flag & ADD) {
+ magic[magindex].offset = oldoff;
+ }
+ }
+ }
+ firstline = 0;
+ returnval = 1;
+ if (!kflag) {
+ return 1; /* don't keep searching */
+ }
+ }
+ return returnval; /* This is hit if -k is set or there is no match */
+}
+
+static int32
+mprint(p, m)
+ union VALUETYPE *p;
+ struct magic *m;
+{
+ char *pp, *rt;
+ uint32 v;
+ time_t curtime;
+ int32 t=0 ;
+
+
+ switch (m->type) {
+ case BYTE:
+ v = p->b;
+ v = signextend(m, v) & m->mask;
+ (void) printf(m->desc, (unsigned char) v);
+ t = m->offset + sizeof(char);
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = p->h;
+ v = signextend(m, v) & m->mask;
+ (void) printf(m->desc, (unsigned short) v);
+ t = m->offset + sizeof(short);
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ v = p->l;
+ v = signextend(m, v) & m->mask;
+ (void) printf(m->desc, (uint32) v);
+ t = m->offset + sizeof(int32);
+ break;
+
+ case STRING:
+ if (m->reln == '=') {
+ (void) printf(m->desc, m->value.s);
+ t = m->offset + strlen(m->value.s);
+ }
+ else {
+ if (*m->value.s == '\0') {
+ char *cp = strchr(p->s,'\n');
+ if (cp)
+ *cp = '\0';
+ }
+ (void) printf(m->desc, p->s);
+ t = m->offset + strlen(p->s);
+ }
+ break;
+
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ curtime = p->l;
+ pp = ctime(&curtime);
+ if ((rt = strchr(pp, '\n')) != NULL)
+ *rt = '\0';
+ (void) printf(m->desc, pp);
+ t = m->offset + sizeof(time_t);
+ break;
+
+ default:
+ error("invalid m->type (%d) in mprint().\n", m->type);
+ /*NOTREACHED*/
+ }
+ return(t);
+}
+
+/*
+ * Convert the byte order of the data we are looking at
+ */
+static int
+mconvert(p, m)
+ union VALUETYPE *p;
+ struct magic *m;
+{
+ switch (m->type) {
+ case BYTE:
+ case SHORT:
+ case LONG:
+ case DATE:
+ return 1;
+ case STRING:
+ {
+ char *ptr;
+
+ /* Null terminate and eat the return */
+ p->s[sizeof(p->s) - 1] = '\0';
+ if ((ptr = strchr(p->s, '\n')) != NULL)
+ *ptr = '\0';
+ return 1;
+ }
+ case BESHORT:
+ p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
+ return 1;
+ case BELONG:
+ case BEDATE:
+ p->l = (int32)
+ ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
+ return 1;
+ case LESHORT:
+ p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
+ return 1;
+ case LELONG:
+ case LEDATE:
+ p->l = (int32)
+ ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
+ return 1;
+ default:
+ error("invalid type %d in mconvert().\n", m->type);
+ return 0;
+ }
+}
+
+
+static void
+mdebug(offset, str, len)
+ int32 offset;
+ char *str;
+ int len;
+{
+ (void) fprintf(stderr, "mget @%d: ", offset);
+ showstr(stderr, (char *) str, len);
+ (void) fputc('\n', stderr);
+ (void) fputc('\n', stderr);
+}
+
+static int
+mget(p, s, m, nbytes)
+ union VALUETYPE* p;
+ unsigned char *s;
+ struct magic *m;
+ int nbytes;
+{
+ int32 offset = m->offset;
+
+ if (offset + sizeof(union VALUETYPE) <= nbytes)
+ memcpy(p, s + offset, sizeof(union VALUETYPE));
+ else {
+ /*
+ * the usefulness of padding with zeroes eludes me, it
+ * might even cause problems
+ */
+ int32 have = nbytes - offset;
+ memset(p, 0, sizeof(union VALUETYPE));
+ if (have > 0)
+ memcpy(p, s + offset, have);
+ }
+
+
+ if (debug) {
+ mdebug(offset, (char *) p, sizeof(union VALUETYPE));
+ mdump(m);
+ }
+
+ if (m->flag & INDIR) {
+
+ switch (m->in.type) {
+ case BYTE:
+ offset = p->b + m->in.offset;
+ break;
+ case BESHORT:
+ offset = (short)((p->hs[0]<<8)|(p->hs[1]))+
+ m->in.offset;
+ break;
+ case LESHORT:
+ offset = (short)((p->hs[1]<<8)|(p->hs[0]))+
+ m->in.offset;
+ break;
+ case SHORT:
+ offset = p->h + m->in.offset;
+ break;
+ case BELONG:
+ offset = (int32)((p->hl[0]<<24)|(p->hl[1]<<16)|
+ (p->hl[2]<<8)|(p->hl[3]))+
+ m->in.offset;
+ break;
+ case LELONG:
+ offset = (int32)((p->hl[3]<<24)|(p->hl[2]<<16)|
+ (p->hl[1]<<8)|(p->hl[0]))+
+ m->in.offset;
+ break;
+ case LONG:
+ offset = p->l + m->in.offset;
+ break;
+ }
+
+ if (offset + sizeof(union VALUETYPE) > nbytes)
+ return 0;
+
+ memcpy(p, s + offset, sizeof(union VALUETYPE));
+
+ if (debug) {
+ mdebug(offset, (char *) p, sizeof(union VALUETYPE));
+ mdump(m);
+ }
+ }
+ if (!mconvert(p, m))
+ return 0;
+ return 1;
+}
+
+static int
+mcheck(p, m)
+ union VALUETYPE* p;
+ struct magic *m;
+{
+ uint32 l = m->value.l;
+ uint32 v;
+ int matched;
+
+ if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
+ fprintf(stderr, "BOINK");
+ return 1;
+ }
+
+
+ switch (m->type) {
+ case BYTE:
+ v = p->b;
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = p->h;
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ v = p->l;
+ break;
+
+ case STRING: {
+ /*
+ * What we want here is:
+ * v = strncmp(m->value.s, p->s, m->vallen);
+ * but ignoring any nulls. bcmp doesn't give -/+/0
+ * and isn't universally available anyway.
+ */
+ unsigned char *a = (unsigned char*)m->value.s;
+ unsigned char *b = (unsigned char*)p->s;
+ int len = m->vallen;
+ l = 0;
+ v = 0;
+ if (0L == m->mask) { /* normal string: do it fast */
+ while (--len >= 0)
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ } else { /* combine the others */
+ while (--len >= 0) {
+ if ((m->mask & STRING_IGNORE_LOWERCASE) &&
+ islower(*a)) {
+ if ((v = tolower(*b++) - *a++) != '\0')
+ break;
+ } else if ((m->mask & STRING_COMPACT_BLANK) &&
+ isspace(*a)) {
+ a++;
+ if (isspace(*b++)) {
+ while (isspace(*b))
+ b++;
+ } else {
+ v = 1;
+ break;
+ }
+ } else if (isspace(*a) &&
+ (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
+ a++;
+ while (isspace(*b))
+ b++;
+ } else {
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ error("invalid type %d in mcheck().\n", m->type);
+ return 0;/*NOTREACHED*/
+ }
+
+ if(m->type != STRING)
+ v = signextend(m, v) & m->mask;
+
+ switch (m->reln) {
+ case 'x':
+ if (debug)
+ (void) fprintf(stderr, "%u == *any* = 1\n", v);
+ matched = 1;
+ break;
+
+ case '!':
+ matched = v != l;
+ if (debug)
+ (void) fprintf(stderr, "%u != %u = %d\n",
+ v, l, matched);
+ break;
+
+ case '=':
+ matched = v == l;
+ if (debug)
+ (void) fprintf(stderr, "%u == %u = %d\n",
+ v, l, matched);
+ break;
+
+ case '>':
+ if (m->flag & UNSIGNED) {
+ matched = v > l;
+ if (debug)
+ (void) fprintf(stderr, "%u > %u = %d\n",
+ v, l, matched);
+ }
+ else {
+ matched = (int32) v > (int32) l;
+ if (debug)
+ (void) fprintf(stderr, "%d > %d = %d\n",
+ v, l, matched);
+ }
+ break;
+
+ case '<':
+ if (m->flag & UNSIGNED) {
+ matched = v < l;
+ if (debug)
+ (void) fprintf(stderr, "%u < %u = %d\n",
+ v, l, matched);
+ }
+ else {
+ matched = (int32) v < (int32) l;
+ if (debug)
+ (void) fprintf(stderr, "%d < %d = %d\n",
+ v, l, matched);
+ }
+ break;
+
+ case '&':
+ matched = (v & l) == l;
+ if (debug)
+ (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
+ v, l, l, matched);
+ break;
+
+ case '^':
+ matched = (v & l) != l;
+ if (debug)
+ (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
+ v, l, l, matched);
+ break;
+
+ default:
+ matched = 0;
+ error("mcheck: can't happen: invalid relation %d.\n", m->reln);
+ break;/*NOTREACHED*/
+ }
+
+ return matched;
+}
OpenPOWER on IntegriCloud