#include <string.h>
#include <ctype.h>
#include <errno.h>
+#ifdef QUICK
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#endif
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$Id: apprentice.c,v 1.33 2000/08/05 17:36:47 christos Exp $")
+FILE_RCSID("@(#)$Id: apprentice.c,v 1.34 2001/03/11 20:29:16 christos Exp $")
#endif /* lint */
#define EATAB {while (isascii((unsigned char) *l) && \
static int getvalue __P((struct magic *, char **));
static int hextoint __P((int));
static char *getstr __P((char *, char *, int, int *));
-static int parse __P((char *, int *, int));
+static int parse __P((struct magic **, uint32 *, char *, int));
static void eatsize __P((char **));
+static int apprentice_1 __P((const char *, int));
+static int apprentice_file __P((struct magic **, uint32 *,
+ const char *, int));
+#ifdef QUICK
+static void byteswap __P((struct magic *, uint32));
+static void bs1 __P((struct magic *));
+static uint16 swap2 __P((uint16));
+static uint32 swap4 __P((uint32));
+static char * mkdbname __P((const char *));
+static int apprentice_map __P((struct magic **, uint32 *,
+ const char *, int));
+static int apprentice_compile __P((struct magic **, uint32 *,
+ const char *, int));
+#endif
static int maxmagic = 0;
-static int apprentice_1 __P((const char *, int));
+struct mlist mlist;
+
+
+/*
+ * Handle one file.
+ */
+static int
+apprentice_1(fn, action)
+ const char *fn;
+ int action;
+{
+ struct magic *magic = NULL;
+ uint32 nmagic = 0;
+ struct mlist *ml;
+ int rv = -1;
+
+#ifdef QUICK
+ if (action == COMPILE) {
+ rv = apprentice_file(&magic, &nmagic, fn, action);
+ if (rv == 0)
+ return apprentice_compile(&magic, &nmagic, fn, action);
+ else
+ return rv;
+ }
+ if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0)
+ (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
+ progname, fn);
+#endif
+
+ if (rv != 0)
+ rv = apprentice_file(&magic, &nmagic, fn, action);
+
+ if (rv != 0)
+ return rv;
+
+ if ((ml = malloc(sizeof(*ml))) == NULL) {
+ (void) fprintf(stderr, "%s: Out of memory.\n", progname);
+ if (action == CHECK)
+ return -1;
+ }
+
+ if (magic == NULL || nmagic == 0)
+ return rv;
+
+ ml->magic = magic;
+ ml->nmagic = nmagic;
+
+ mlist.prev->next = ml;
+ ml->prev = mlist.prev;
+ ml->next = &mlist;
+ mlist.prev = ml;
+
+ return rv;
+}
+
int
-apprentice(fn, check)
+apprentice(fn, action)
const char *fn; /* list of magic files */
- int check; /* non-zero? checking-only run. */
+ int action;
{
char *p, *mfn;
int file_err, errs = -1;
- maxmagic = MAXMAGIS;
- magic = (struct magic *) calloc(sizeof(struct magic), maxmagic);
+ mlist.next = mlist.prev = &mlist;
mfn = malloc(strlen(fn)+1);
- if (magic == NULL || mfn == NULL) {
+ if (mfn == NULL) {
(void) fprintf(stderr, "%s: Out of memory.\n", progname);
- if (check)
+ if (action == CHECK)
return -1;
else
exit(1);
p = strchr(fn, PATHSEP);
if (p)
*p++ = '\0';
- file_err = apprentice_1(fn, check);
+ file_err = apprentice_1(fn, action);
if (file_err > errs)
errs = file_err;
fn = p;
}
if (errs == -1)
(void) fprintf(stderr, "%s: couldn't find any magic files!\n",
- progname);
- if (!check && errs)
+ progname);
+ if (action == CHECK && errs)
exit(1);
free(mfn);
return errs;
}
+/*
+ * parse from a file
+ */
static int
-apprentice_1(fn, check)
+apprentice_file(magicp, nmagicp, fn, action)
+ struct magic **magicp;
+ uint32 *nmagicp;
const char *fn; /* name of magic file */
- int check; /* non-zero? checking-only run. */
+ int action;
{
static const char hdr[] =
"cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
int errs = 0;
f = fopen(fn, "r");
- if (f==NULL) {
+ if (f == NULL) {
if (errno != ENOENT)
(void) fprintf(stderr,
"%s: can't read magic file %s (%s)\n",
return -1;
}
+ maxmagic = MAXMAGIS;
+ *magicp = (struct magic *) calloc(sizeof(struct magic), maxmagic);
+ if (*magicp == NULL) {
+ (void) fprintf(stderr, "%s: Out of memory.\n", progname);
+ if (action == CHECK)
+ return -1;
+ }
+
/* parse it */
- if (check) /* print silly verbose header for USG compat. */
+ if (action == CHECK) /* print silly verbose header for USG compat. */
(void) printf("%s\n", hdr);
for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
continue;
line[strlen(line)-1] = '\0'; /* delete newline */
- if (parse(line, &nmagic, check) != 0)
+ if (parse(magicp, nmagicp, line, action) != 0)
errs = 1;
}
(void) fclose(f);
+ if (errs) {
+ free(*magicp);
+ *magicp = NULL;
+ *nmagicp = 0;
+ }
return errs;
}
* parse one line from magic file, put into magic[index++] if valid
*/
static int
-parse(l, ndx, check)
+parse(magicp, nmagicp, l, action)
+ struct magic **magicp;
+ uint32 *nmagicp;
char *l;
- int *ndx, check;
+ int action;
{
- int i = 0, nd = *ndx;
+ int i = 0;
struct magic *m;
char *t, *s;
#define ALLOC_INCR 200
- if (nd+1 >= maxmagic){
+ if (*nmagicp + 1 >= maxmagic){
maxmagic += ALLOC_INCR;
- if ((m = (struct magic *) realloc(magic, sizeof(struct magic) *
- maxmagic)) == NULL) {
+ if ((m = (struct magic *) realloc(*magicp,
+ sizeof(struct magic) * maxmagic)) == NULL) {
(void) fprintf(stderr, "%s: Out of memory.\n",
progname);
- if (magic)
- free(magic);
- if (check)
+ if (*magicp)
+ free(*magicp);
+ if (action == CHECK)
return -1;
else
exit(1);
}
- magic = m;
- memset(&magic[*ndx], 0, sizeof(struct magic) * ALLOC_INCR);
+ *magicp = m;
+ memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic)
+ * ALLOC_INCR);
}
- m = &magic[*ndx];
+ m = &(*magicp)[*nmagicp];
m->flag = 0;
m->cont_level = 0;
l = t;
if (m->flag & INDIR) {
- m->in.type = LONG;
- m->in.offset = 0;
+ m->in_type = LONG;
+ m->in_offset = 0;
/*
* read [.lbs][+-]nnnnn)
*/
l++;
switch (*l) {
case 'l':
- m->in.type = LELONG;
+ m->in_type = LELONG;
break;
case 'L':
- m->in.type = BELONG;
+ m->in_type = BELONG;
break;
case 'h':
case 's':
- m->in.type = LESHORT;
+ m->in_type = LESHORT;
break;
case 'H':
case 'S':
- m->in.type = BESHORT;
+ m->in_type = BESHORT;
break;
case 'c':
case 'b':
case 'C':
case 'B':
- m->in.type = BYTE;
+ m->in_type = BYTE;
break;
default:
magwarn("indirect offset type %c invalid", *l);
s = l;
if (*l == '+' || *l == '-') l++;
if (isdigit((unsigned char)*l)) {
- m->in.offset = strtoul(l, &t, 0);
- if (*s == '-') m->in.offset = - m->in.offset;
+ m->in_offset = strtoul(l, &t, 0);
+ if (*s == '-') m->in_offset = - m->in_offset;
}
else
t = l;
while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
/* NULLBODY */;
- if (check) {
+ if (action == CHECK) {
mdump(m);
}
- ++(*ndx); /* make room for next */
+ ++(*nmagicp); /* make room for next */
return 0;
}
*p = l;
}
+
+#ifdef QUICK
+/*
+ * handle an mmaped file.
+ */
+static int
+apprentice_map(magicp, nmagicp, fn, action)
+ struct magic **magicp;
+ uint32 *nmagicp;
+ const char *fn;
+ int action;
+{
+ int fd;
+ struct stat st;
+ uint32 *ptr;
+ uint32 version;
+ int needsbyteswap;
+ char *dbname = mkdbname(fn);
+
+ if ((fd = open(dbname, O_RDONLY)) == -1)
+ return -1;
+
+ if (fstat(fd, &st) == -1) {
+ (void)fprintf(stderr, "%s: Cannot stat `%s' (%s)\n",
+ progname, dbname, strerror(errno));
+ goto error;
+ }
+
+ if ((*magicp = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
+ (void)fprintf(stderr, "%s: Cannot map `%s' (%s)\n",
+ progname, dbname, strerror(errno));
+ goto error;
+ }
+ (void)close(fd);
+ ptr = (uint32 *) *magicp;
+ if (*ptr != MAGICNO) {
+ if (swap4(*ptr) != MAGICNO) {
+ (void)fprintf(stderr, "%s: Bad magic in `%s'\n",
+ progname, dbname);
+ goto error;
+ }
+ needsbyteswap = 1;
+ } else
+ needsbyteswap = 0;
+ if (needsbyteswap)
+ version = swap4(ptr[1]);
+ else
+ version = ptr[1];
+ if (version != VERSIONNO) {
+ (void)fprintf(stderr,
+ "%s: version mismatch (%d != %d) in `%s'\n",
+ progname, version, VERSION, dbname);
+ goto error;
+ }
+ *nmagicp = (st.st_size / sizeof(struct magic)) - 1;
+ (*magicp)++;
+ if (needsbyteswap)
+ byteswap(*magicp, *nmagicp);
+ return 0;
+
+error:
+ if (fd != -1)
+ (void)close(fd);
+ if (*magicp)
+ (void)munmap(*magicp, (size_t)st.st_size);
+ else {
+ *magicp = NULL;
+ *nmagicp = 0;
+ }
+ return -1;
+}
+
+/*
+ * handle an mmaped file.
+ */
+static int
+apprentice_compile(magicp, nmagicp, fn, action)
+ struct magic **magicp;
+ uint32 *nmagicp;
+ const char *fn;
+ int action;
+{
+ int fd;
+ char *dbname = mkdbname(fn);
+ static const uint32 ar[] = {
+ MAGICNO, VERSIONNO
+ };
+
+ if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
+ (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n",
+ progname, dbname, strerror(errno));
+ return -1;
+ }
+
+ if (write(fd, ar, sizeof(ar)) != sizeof(ar)) {
+ (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
+ progname, dbname, strerror(errno));
+ return -1;
+ }
+
+ if (lseek(fd, sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
+ (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
+ progname, dbname, strerror(errno));
+ return -1;
+ }
+
+ if (write(fd, *magicp, sizeof(struct magic) * *nmagicp)
+ != sizeof(struct magic) * *nmagicp) {
+ (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
+ progname, dbname, strerror(errno));
+ return -1;
+ }
+
+ (void)close(fd);
+ return 0;
+}
+
+/*
+ * make a dbname
+ */
+char *
+mkdbname(fn)
+ const char *fn;
+{
+ static const char ext[] = ".mgc";
+ static char *buf = NULL;
+ size_t len = strlen(fn) + sizeof(ext) + 1;
+ if (buf == NULL)
+ buf = malloc(len);
+ else
+ buf = realloc(buf, len);
+ (void)strcpy(buf, fn);
+ (void)strcat(buf, ext);
+ return buf;
+}
+
+/*
+ * Byteswap an mmap'ed file if needed
+ */
+static void
+byteswap(magic, nmagic)
+ struct magic *magic;
+ uint32 nmagic;
+{
+ uint32 i;
+ for (i = 0; i < nmagic; i++)
+ bs1(&magic[i]);
+}
+
+/*
+ * swap a short
+ */
+static uint16
+swap2(sv)
+ uint16 sv;
+{
+ uint16 rv;
+ uint8 *s = (uint8 *) &sv;
+ uint8 *d = (uint8 *) &rv;
+ d[0] = s[1];
+ d[1] = s[0];
+ return rv;
+}
+
+/*
+ * swap an int
+ */
+static uint32
+swap4(sv)
+ uint32 sv;
+{
+ uint32 rv;
+ uint8 *s = (uint8 *) &sv;
+ uint8 *d = (uint8 *) &rv;
+ d[0] = s[3];
+ d[1] = s[2];
+ d[2] = s[1];
+ d[3] = s[0];
+ return rv;
+}
+
+/*
+ * byteswap a single magic entry
+ */
+static
+void bs1(m)
+ struct magic *m;
+{
+ m->cont_level = swap2(m->cont_level);
+ m->offset = swap4(m->offset);
+ m->in_offset = swap4(m->in_offset);
+ if (m->type != STRING)
+ m->value.l = swap4(m->value.l);
+ m->mask = swap4(m->mask);
+}
+#endif
/*
* file.h - definitions for file(1) program
- * @(#)$Id: file.h,v 1.34 2000/11/13 00:30:49 christos Exp $
+ * @(#)$Id: file.h,v 1.35 2001/03/11 20:29:16 christos Exp $
*
* Copyright (c) Ian F. Darwin, 1987.
* Written by Ian F. Darwin.
typedef int int32;
typedef unsigned int uint32;
+typedef short int16;
+typedef unsigned short uint16;
+typedef char int8;
+typedef unsigned char uint8;
#ifndef HOWMANY
# define HOWMANY 16384 /* how much of the file to look at */
#define MAXDESC 50 /* max leng of text description */
#define MAXstring 32 /* max leng of "string" types */
+#define MAGICNO 0xF11E041C
+#define VERSIONNO 1
+
+#define CHECK 1
+#define COMPILE 2
+
struct magic {
- short flag;
+ uint16 cont_level;/* level of ">" */
+ uint8 nospflag; /* supress space character */
+ uint8 flag;
#define INDIR 1 /* if '>(...)' appears, */
#define UNSIGNED 2 /* comparison is unsigned */
#define ADD 4 /* if '>&' appears, */
- short cont_level; /* level of ">" */
- struct {
- unsigned char type; /* byte short long */
- int32 offset; /* offset from indirection */
- } in;
- int32 offset; /* offset to magic number */
- unsigned char reln; /* relation (0=eq, '>'=gt, etc) */
- unsigned char type; /* int, short, long or string. */
- char vallen; /* length of string value, if any */
+ uint8 reln; /* relation (0=eq, '>'=gt, etc) */
+ uint8 vallen; /* length of string value, if any */
+ uint8 type; /* int, short, long or string. */
+ uint8 in_type; /* type of indirrection */
#define BYTE 1
#define SHORT 2
#define LONG 4
#define LESHORT 10
#define LELONG 11
#define LEDATE 12
+ int32 offset; /* offset to magic number */
+ int32 in_offset; /* offset from indirection */
union VALUETYPE {
unsigned char b;
unsigned short h;
uint32 l;
char s[MAXstring];
unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */
- unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */
+ unsigned char hl[4]; /* 4 bytes of a fixed-endian "long" */
} value; /* either number or string */
uint32 mask; /* mask before comparison with value */
- char nospflag; /* supress space character */
char desc[MAXDESC]; /* description */
};
#define CHAR_COMPACT_OPTIONAL_BLANK 'b'
+/* list of magic entries */
+struct mlist {
+ struct magic *magic; /* array of magic entries */
+ uint32 nmagic; /* number of entries in array */
+ struct mlist *next, *prev;
+};
+
#include <stdio.h> /* Include that here, to make sure __P gets defined */
#include <errno.h>
extern const char *magicfile; /* name of the magic file */
extern int lineno; /* current line number in magic file */
-extern struct magic *magic; /* array of magic entries */
-extern int nmagic; /* number of valid magic[]s */
-
+extern struct mlist mlist; /* list of arrays of magic entries */
extern int debug; /* enable debugging? */
extern int zflag; /* process compressed files? */
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$Id: softmagic.c,v 1.42 2000/08/05 17:36:49 christos Exp $")
+FILE_RCSID("@(#)$Id: softmagic.c,v 1.43 2001/03/11 20:29:16 christos Exp $")
#endif /* lint */
-static int match __P((unsigned char *, int));
+static int match __P((struct magic *, uint32, unsigned char *, int));
static int mget __P((union VALUETYPE *,
unsigned char *, struct magic *, int));
static int mcheck __P((union VALUETYPE *, struct magic *));
unsigned char *buf;
int nbytes;
{
- if (match(buf, nbytes))
- return 1;
+ struct mlist *ml;
+
+ for (ml = mlist.next; ml != &mlist; ml = ml->next)
+ if (match(ml->magic, ml->nmagic, buf, nbytes))
+ return 1;
return 0;
}
* so that higher-level continuations are processed.
*/
static int
-match(s, nbytes)
+match(magic, nmagic, s, nbytes)
+ struct magic *magic;
+ uint32 nmagic;
unsigned char *s;
int nbytes;
{
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 */
+ struct mlist *ml;
if (tmpoff == NULL)
if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
}
if (magic[magindex].flag & ADD) {
oldoff=magic[magindex].offset;
- magic[magindex].offset += tmpoff[cont_level-1];
+ magic[magindex].offset +=
+ tmpoff[cont_level-1];
}
if (mget(&p, s, &magic[magindex], nbytes) &&
mcheck(&p, &magic[magindex])) {
(void) putchar(' ');
need_separator = 0;
}
- tmpoff[cont_level] = mprint(&p, &magic[magindex]);
+ tmpoff[cont_level] =
+ mprint(&p, &magic[magindex]);
if (magic[magindex].desc[0])
need_separator = 1;
if (m->flag & INDIR) {
- switch (m->in.type) {
+ switch (m->in_type) {
case BYTE:
- offset = p->b + m->in.offset;
+ offset = p->b + m->in_offset;
break;
case BESHORT:
offset = (short)((p->hs[0]<<8)|(p->hs[1]))+
- m->in.offset;
+ m->in_offset;
break;
case LESHORT:
offset = (short)((p->hs[1]<<8)|(p->hs[0]))+
- m->in.offset;
+ m->in_offset;
break;
case SHORT:
- offset = p->h + m->in.offset;
+ 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;
+ 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;
+ m->in_offset;
break;
case LONG:
- offset = p->l + m->in.offset;
+ offset = p->l + m->in_offset;
break;
}