From bda6cdf5897e5ebed7279aca3ea3387bddcb19b0 Mon Sep 17 00:00:00 2001 From: obrien Date: Mon, 9 Aug 2004 08:45:41 +0000 Subject: Virgin import of Christos Zoulas's FILE 4.10. *- file is now broken into a library containing and processing the magic and a consumer binary. --- contrib/file/apprentice.c | 774 ++++++++++++++++++++++++++-------------------- 1 file changed, 440 insertions(+), 334 deletions(-) (limited to 'contrib/file/apprentice.c') diff --git a/contrib/file/apprentice.c b/contrib/file/apprentice.c index 575bad6..531c791 100644 --- a/contrib/file/apprentice.c +++ b/contrib/file/apprentice.c @@ -1,31 +1,41 @@ /* + * Copyright (c) Ian F. Darwin 1986-1995. + * Software written by Ian F. Darwin and others; + * maintained 1995-present by Christos Zoulas and others. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ian F. Darwin and others. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* * apprentice - make one pass through /etc/magic, learning its secrets. - * - * 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 "file.h" +#include "magic.h" #include #ifdef HAVE_UNISTD_H #include @@ -33,12 +43,14 @@ #include #include #include +#include +#include #ifdef QUICK #include #endif #ifndef lint -FILE_RCSID("@(#)$Id: apprentice.c,v 1.50 2003/02/27 20:47:46 christos Exp $") +FILE_RCSID("@(#)$Id: apprentice.c,v 1.78 2004/07/24 20:38:56 christos Exp $") #endif /* lint */ #define EATAB {while (isascii((unsigned char) *l) && \ @@ -63,36 +75,33 @@ FILE_RCSID("@(#)$Id: apprentice.c,v 1.50 2003/02/27 20:47:46 christos Exp $") #define MAP_FILE 0 #endif -#ifdef __EMX__ - char PATHSEP=';'; -#else - char PATHSEP=':'; +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 #endif - -static int getvalue(struct magic *, char **); -static int hextoint(int); -static char *getstr(char *, char *, int, int *); -static int parse(struct magic **, uint32_t *, char *, int); -static void eatsize(char **); -static int apprentice_1(const char *, int); -static int apprentice_file(struct magic **, uint32_t *, const char *, int); -static void byteswap(struct magic *, uint32_t); -static void bs1(struct magic *); -static uint16_t swap2(uint16_t); -static uint32_t swap4(uint32_t); -static char *mkdbname(const char *); -static int apprentice_map(struct magic **, uint32_t *, const char *, int); -static int apprentice_compile(struct magic **, uint32_t *, const char *, int); - -static int maxmagic = 0; - -struct mlist mlist; +private int getvalue(struct magic_set *ms, struct magic *, char **); +private int hextoint(int); +private char *getstr(struct magic_set *, char *, char *, int, int *); +private int parse(struct magic_set *, struct magic **, uint32_t *, char *, int); +private void eatsize(char **); +private int apprentice_1(struct magic_set *, const char *, int, struct mlist *); +private int apprentice_file(struct magic_set *, struct magic **, uint32_t *, + const char *, int); +private void byteswap(struct magic *, uint32_t); +private void bs1(struct magic *); +private uint16_t swap2(uint16_t); +private uint32_t swap4(uint32_t); +private char *mkdbname(const char *, char *, size_t); +private int apprentice_map(struct magic_set *, struct magic **, uint32_t *, + const char *); +private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *, + const char *); +private int check_format(struct magic *); + +private size_t maxmagic = 0; +private size_t magicsize = sizeof(struct magic); #ifdef COMPILE_ONLY -const char *magicfile; -char *progname; -int lineno; int main(int, char *[]); @@ -100,6 +109,8 @@ int main(int argc, char *argv[]) { int ret; + struct magic_set *ms; + char *progname; if ((progname = strrchr(argv[0], '/')) != NULL) progname++; @@ -107,12 +118,19 @@ main(int argc, char *argv[]) progname = argv[0]; if (argc != 2) { - (void)fprintf(stderr, "usage: %s file\n", progname); - exit(1); + (void)fprintf(stderr, "Usage: %s file\n", progname); + return 1; } - magicfile = argv[1]; - exit(apprentice(magicfile, COMPILE)); + if ((ms = magic_open(MAGIC_CHECK)) == NULL) { + (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); + return 1; + } + ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0; + if (ret == 1) + (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms)); + magic_close(ms); + return ret; } #endif /* COMPILE_ONLY */ @@ -120,140 +138,200 @@ main(int argc, char *argv[]) /* * Handle one file. */ -static int -apprentice_1(const char *fn, int action) +private int +apprentice_1(struct magic_set *ms, const char *fn, int action, + struct mlist *mlist) { struct magic *magic = NULL; uint32_t nmagic = 0; struct mlist *ml; int rv = -1; + int mapped; - if (action == COMPILE) { - rv = apprentice_file(&magic, &nmagic, fn, action); - if (rv == 0) - return apprentice_compile(&magic, &nmagic, fn, action); - else - return rv; + if (magicsize != FILE_MAGICSIZE) { + file_error(ms, 0, "magic element size %lu != %lu", + (unsigned long)sizeof(*magic), + (unsigned long)FILE_MAGICSIZE); + return -1; } -#ifndef COMPILE_ONLY - if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0) - (void)fprintf(stderr, "%s: Using regular magic file `%s'\n", - progname, fn); - - if (rv != 0) - rv = apprentice_file(&magic, &nmagic, fn, action); - - if (rv != 0) + + if (action == FILE_COMPILE) { + rv = apprentice_file(ms, &magic, &nmagic, fn, action); + if (rv != 0) + return -1; + rv = apprentice_compile(ms, &magic, &nmagic, fn); + free(magic); return rv; - - if ((ml = malloc(sizeof(*ml))) == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - if (action == CHECK) + } +#ifndef COMPILE_ONLY + if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) { + if (ms->flags & MAGIC_CHECK) + file_magwarn("using regular magic file `%s'", fn); + rv = apprentice_file(ms, &magic, &nmagic, fn, action); + if (rv != 0) return -1; + mapped = 0; } - if (magic == NULL || nmagic == 0) + if (rv == -1) return rv; + mapped = rv; + + if (magic == NULL || nmagic == 0) { + file_delmagic(magic, mapped, nmagic); + return -1; + } + + if ((ml = malloc(sizeof(*ml))) == NULL) { + file_delmagic(magic, mapped, nmagic); + file_oomem(ms); + return -1; + } ml->magic = magic; ml->nmagic = nmagic; + ml->mapped = mapped; - mlist.prev->next = ml; - ml->prev = mlist.prev; - ml->next = &mlist; - mlist.prev = ml; + mlist->prev->next = ml; + ml->prev = mlist->prev; + ml->next = mlist; + mlist->prev = ml; - return rv; + return 0; #endif /* COMPILE_ONLY */ } +protected void +file_delmagic(struct magic *p, int type, size_t entries) +{ + if (p == NULL) + return; + switch (type) { + case 2: + p--; + (void)munmap((void *)p, sizeof(*p) * (entries + 1)); + break; + case 1: + p--; + /*FALLTHROUGH*/ + case 0: + free(p); + break; + default: + abort(); + } +} + /* const char *fn: list of magic files */ -int -apprentice(const char *fn, int action) +protected struct mlist * +file_apprentice(struct magic_set *ms, const char *fn, int action) { - char *p, *mfn; + char *p, *mfn, *afn = NULL; int file_err, errs = -1; + struct mlist *mlist; - mlist.next = mlist.prev = &mlist; - mfn = malloc(strlen(fn)+1); - if (mfn == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - if (action == CHECK) - return -1; - else - exit(1); + if (fn == NULL) + fn = getenv("MAGIC"); + if (fn == NULL) + fn = MAGIC; + + if ((fn = mfn = strdup(fn)) == NULL) { + file_oomem(ms); + return NULL; } - fn = strcpy(mfn, fn); - + + if ((mlist = malloc(sizeof(*mlist))) == NULL) { + free(mfn); + file_oomem(ms); + return NULL; + } + mlist->next = mlist->prev = mlist; + while (fn) { p = strchr(fn, PATHSEP); if (p) *p++ = '\0'; - file_err = apprentice_1(fn, action); + if (*fn == '\0') + break; + if (ms->flags & MAGIC_MIME) { + if ((afn = malloc(strlen(fn) + 5 + 1)) == NULL) { + free(mfn); + free(mlist); + file_oomem(ms); + return NULL; + } + (void)strcpy(afn, fn); + (void)strcat(afn, ".mime"); + fn = afn; + } + file_err = apprentice_1(ms, fn, action, mlist); if (file_err > errs) errs = file_err; + if (afn) { + free(afn); + afn = NULL; + } fn = p; } - if (errs == -1) - (void) fprintf(stderr, "%s: couldn't find any magic files!\n", - progname); - if (action == CHECK && errs) - exit(1); - + if (errs == -1) { + free(mfn); + free(mlist); + mlist = NULL; + file_error(ms, 0, "could not find any magic files!"); + return NULL; + } free(mfn); - return errs; + return mlist; } /* * parse from a file * const char *fn: name of magic file */ -static int -apprentice_file(struct magic **magicp, uint32_t *nmagicp, const char *fn, - int action) +private int +apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, + const char *fn, int action) { - static const char hdr[] = + private const char hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; FILE *f; char line[BUFSIZ+1]; + int lineno; int errs = 0; f = fopen(fn, "r"); if (f == NULL) { if (errno != ENOENT) - (void) fprintf(stderr, - "%s: can't read magic file %s (%s)\n", - progname, fn, strerror(errno)); + file_error(ms, errno, "cannot read magic file `%s'", + fn); return -1; } maxmagic = MAXMAGIS; *magicp = (struct magic *) calloc(maxmagic, sizeof(struct magic)); if (*magicp == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - if (action == CHECK) - return -1; + (void)fclose(f); + file_oomem(ms); + return -1; } - /* parse it */ - if (action == CHECK) /* print silly verbose header for USG compat. */ - (void) printf("%s\n", hdr); + /* print silly verbose header for USG compat. */ + if (action == FILE_CHECK) + (void)fprintf(stderr, "%s\n", hdr); - for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) { + /* parse it */ + for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++) { if (line[0]=='#') /* comment, do not parse */ continue; if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */ continue; line[strlen(line)-1] = '\0'; /* delete newline */ - if (parse(magicp, nmagicp, line, action) != 0) + if (parse(ms, magicp, nmagicp, line, action) != 0) errs = 1; } - (void) fclose(f); + (void)fclose(f); if (errs) { free(*magicp); *magicp = NULL; @@ -265,8 +343,8 @@ apprentice_file(struct magic **magicp, uint32_t *nmagicp, const char *fn, /* * extend the sign bit if the comparison is to be signed */ -uint32_t -signextend(struct magic *m, uint32_t v) +protected uint32_t +file_signextend(struct magic_set *ms, struct magic *m, uint32_t v) { if (!(m->flag & UNSIGNED)) switch(m->type) { @@ -275,34 +353,35 @@ signextend(struct magic *m, uint32_t v) * vital. When later compared with the data, * the sign extension must have happened. */ - case BYTE: + case FILE_BYTE: v = (char) v; break; - case SHORT: - case BESHORT: - case LESHORT: + case FILE_SHORT: + case FILE_BESHORT: + case FILE_LESHORT: v = (short) v; break; - case DATE: - case BEDATE: - case LEDATE: - case LDATE: - case BELDATE: - case LELDATE: - case LONG: - case BELONG: - case LELONG: + case FILE_DATE: + case FILE_BEDATE: + case FILE_LEDATE: + case FILE_LDATE: + case FILE_BELDATE: + case FILE_LELDATE: + case FILE_LONG: + case FILE_BELONG: + case FILE_LELONG: v = (int32_t) v; break; - case STRING: - case PSTRING: + case FILE_STRING: + case FILE_PSTRING: break; - case REGEX: + case FILE_REGEX: break; default: - magwarn("can't happen: m->type=%d\n", - m->type); - return -1; + if (ms->flags & MAGIC_CHECK) + file_magwarn("cannot happen: m->type=%d\n", + m->type); + return ~0U; } return v; } @@ -310,26 +389,25 @@ signextend(struct magic *m, uint32_t v) /* * parse one line from magic file, put into magic[index++] if valid */ -static int -parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) +private int +parse(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, char *l, + int action) { int i = 0; struct magic *m; char *t; + private const char *fops = FILE_OPS; + uint32_t val; #define ALLOC_INCR 200 if (*nmagicp + 1 >= maxmagic){ maxmagic += ALLOC_INCR; if ((m = (struct magic *) realloc(*magicp, sizeof(struct magic) * maxmagic)) == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", - progname, strerror(errno)); + file_oomem(ms); if (*magicp) free(*magicp); - if (action == CHECK) - return -1; - else - exit(1); + return -1; } *magicp = m; memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic) @@ -354,13 +432,14 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) } /* get offset, then skip over it */ - m->offset = (int) strtoul(l,&t,0); + m->offset = (uint32_t)strtoul(l, &t, 0); if (l == t) - magwarn("offset %s invalid", l); + if (ms->flags & MAGIC_CHECK) + file_magwarn("offset %s invalid", l); l = t; if (m->flag & INDIR) { - m->in_type = LONG; + m->in_type = FILE_LONG; m->in_offset = 0; /* * read [.lbs][+-]nnnnn) @@ -369,75 +448,79 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) l++; switch (*l) { case 'l': - m->in_type = LELONG; + m->in_type = FILE_LELONG; break; case 'L': - m->in_type = BELONG; + m->in_type = FILE_BELONG; break; case 'h': case 's': - m->in_type = LESHORT; + m->in_type = FILE_LESHORT; break; case 'H': case 'S': - m->in_type = BESHORT; + m->in_type = FILE_BESHORT; break; case 'c': case 'b': case 'C': case 'B': - m->in_type = BYTE; + m->in_type = FILE_BYTE; break; default: - magwarn("indirect offset type %c invalid", *l); + if (ms->flags & MAGIC_CHECK) + file_magwarn( + "indirect offset type %c invalid", + *l); break; } l++; } if (*l == '~') { - m->in_op = OPINVERSE; + m->in_op = FILE_OPINVERSE; l++; } switch (*l) { case '&': - m->in_op |= OPAND; + m->in_op |= FILE_OPAND; l++; break; case '|': - m->in_op |= OPOR; + m->in_op |= FILE_OPOR; l++; break; case '^': - m->in_op |= OPXOR; + m->in_op |= FILE_OPXOR; l++; break; case '+': - m->in_op |= OPADD; + m->in_op |= FILE_OPADD; l++; break; case '-': - m->in_op |= OPMINUS; + m->in_op |= FILE_OPMINUS; l++; break; case '*': - m->in_op |= OPMULTIPLY; + m->in_op |= FILE_OPMULTIPLY; l++; break; case '/': - m->in_op |= OPDIVIDE; + m->in_op |= FILE_OPDIVIDE; l++; break; case '%': - m->in_op |= OPMODULO; + m->in_op |= FILE_OPMODULO; l++; break; } if (isdigit((unsigned char)*l)) - m->in_offset = strtoul(l, &t, 0); + m->in_offset = (uint32_t)strtoul(l, &t, 0); else t = l; if (*t++ != ')') - magwarn("missing ')' in indirect offset"); + if (ms->flags & MAGIC_CHECK) + file_magwarn("missing ')' in indirect offset"); l = t; } @@ -470,119 +553,80 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) /* get type, skip it */ if (strncmp(l, "char", NBYTE)==0) { /* HP/UX compat */ - m->type = BYTE; + m->type = FILE_BYTE; l += NBYTE; } else if (strncmp(l, "byte", NBYTE)==0) { - m->type = BYTE; + m->type = FILE_BYTE; l += NBYTE; } else if (strncmp(l, "short", NSHORT)==0) { - m->type = SHORT; + m->type = FILE_SHORT; l += NSHORT; } else if (strncmp(l, "long", NLONG)==0) { - m->type = LONG; + m->type = FILE_LONG; l += NLONG; } else if (strncmp(l, "string", NSTRING)==0) { - m->type = STRING; + m->type = FILE_STRING; l += NSTRING; } else if (strncmp(l, "date", NDATE)==0) { - m->type = DATE; + m->type = FILE_DATE; l += NDATE; } else if (strncmp(l, "beshort", NBESHORT)==0) { - m->type = BESHORT; + m->type = FILE_BESHORT; l += NBESHORT; } else if (strncmp(l, "belong", NBELONG)==0) { - m->type = BELONG; + m->type = FILE_BELONG; l += NBELONG; } else if (strncmp(l, "bedate", NBEDATE)==0) { - m->type = BEDATE; + m->type = FILE_BEDATE; l += NBEDATE; } else if (strncmp(l, "leshort", NLESHORT)==0) { - m->type = LESHORT; + m->type = FILE_LESHORT; l += NLESHORT; } else if (strncmp(l, "lelong", NLELONG)==0) { - m->type = LELONG; + m->type = FILE_LELONG; l += NLELONG; } else if (strncmp(l, "ledate", NLEDATE)==0) { - m->type = LEDATE; + m->type = FILE_LEDATE; l += NLEDATE; } else if (strncmp(l, "pstring", NPSTRING)==0) { - m->type = PSTRING; + m->type = FILE_PSTRING; l += NPSTRING; } else if (strncmp(l, "ldate", NLDATE)==0) { - m->type = LDATE; + m->type = FILE_LDATE; l += NLDATE; } else if (strncmp(l, "beldate", NBELDATE)==0) { - m->type = BELDATE; + m->type = FILE_BELDATE; l += NBELDATE; } else if (strncmp(l, "leldate", NLELDATE)==0) { - m->type = LELDATE; + m->type = FILE_LELDATE; l += NLELDATE; } else if (strncmp(l, "regex", NREGEX)==0) { - m->type = REGEX; + m->type = FILE_REGEX; l += sizeof("regex"); } else { - magwarn("type %s invalid", l); + if (ms->flags & MAGIC_CHECK) + file_magwarn("type %s invalid", l); return -1; } /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */ if (*l == '~') { - if (STRING != m->type && PSTRING != m->type) - m->mask_op = OPINVERSE; + if (FILE_STRING != m->type && FILE_PSTRING != m->type) + m->mask_op = FILE_OPINVERSE; ++l; } - switch (*l) { - case '&': - m->mask_op |= OPAND; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '|': - m->mask_op |= OPOR; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '^': - m->mask_op |= OPXOR; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '+': - m->mask_op |= OPADD; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '-': - m->mask_op |= OPMINUS; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '*': - m->mask_op |= OPMULTIPLY; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '%': - m->mask_op |= OPMODULO; - ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); - eatsize(&l); - break; - case '/': - if (STRING != m->type && PSTRING != m->type) { - m->mask_op |= OPDIVIDE; + if ((t = strchr(fops, *l)) != NULL) { + uint32_t op = (uint32_t)(t - fops); + if (op != FILE_OPDIVIDE || + (FILE_STRING != m->type && FILE_PSTRING != m->type)) { ++l; - m->mask = signextend(m, strtoul(l, &l, 0)); + m->mask_op |= op; + val = (uint32_t)strtoul(l, &l, 0); + m->mask = file_signextend(ms, m, val); eatsize(&l); } else { m->mask = 0L; - while (!isspace(*++l)) { + while (!isspace((unsigned char)*++l)) { switch (*l) { case CHAR_IGNORE_LOWERCASE: m->mask |= STRING_IGNORE_LOWERCASE; @@ -595,16 +639,19 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) STRING_COMPACT_OPTIONAL_BLANK; break; default: - magwarn("string extension %c invalid", - *l); + if (ms->flags & MAGIC_CHECK) + file_magwarn( + "string extension %c invalid", + *l); return -1; } } } - break; } - /* We used to set mask to all 1's here, instead let's just not do anything - if mask = 0 (unless you have a better idea) */ + /* + * We used to set mask to all 1's here, instead let's just not do + * anything if mask = 0 (unless you have a better idea) + */ EATAB; switch (*l) { @@ -622,12 +669,12 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) } break; case '!': - if (m->type != STRING && m->type != PSTRING) { + if (m->type != FILE_STRING && m->type != FILE_PSTRING) { m->reln = *l; ++l; break; } - /* FALL THROUGH */ + /*FALLTHROUGH*/ default: if (*l == 'x' && isascii((unsigned char)l[1]) && isspace((unsigned char)l[1])) { @@ -640,7 +687,7 @@ parse(struct magic **magicp, uint32_t *nmagicp, char *l, int action) } EATAB; - if (getvalue(m, &l)) + if (getvalue(ms, m, &l)) return -1; /* * TODO finish this macro and start using it! @@ -662,37 +709,104 @@ GetDesc: m->nospflag = 1; } else m->nospflag = 0; - while ((m->desc[i++] = *l++) != '\0' && idesc[i++] = *l++) != '\0' && i < MAXDESC) /* NULLBODY */; + if (ms->flags & MAGIC_CHECK) { + if (!check_format(m)) + return -1; + } #ifndef COMPILE_ONLY - if (action == CHECK) { - mdump(m); + if (action == FILE_CHECK) { + file_mdump(m); } #endif ++(*nmagicp); /* make room for next */ return 0; } +/* + * Check that the optional printf format in description matches + * the type of the magic. + */ +private int +check_format(struct magic *m) +{ + static const char *formats[] = { FILE_FORMAT_STRING }; + static const char *names[] = { FILE_FORMAT_NAME }; + char *ptr; + + for (ptr = m->desc; *ptr; ptr++) + if (*ptr == '%') + break; + if (*ptr == '\0') { + /* No format string; ok */ + return 1; + } + if (m->type >= sizeof(formats)/sizeof(formats[0])) { + file_magwarn("Internal error inconsistency between m->type" + " and format strings"); + return 0; + } + if (formats[m->type] == NULL) { + file_magwarn("No format string for `%s' with description `%s'", + m->desc, names[m->type]); + return 0; + } + for (; *ptr; ptr++) { + if (*ptr == 'l' || *ptr == 'h') { + /* XXX: we should really fix this one day */ + continue; + } + if (islower((unsigned char)*ptr) || *ptr == 'X') + break; + } + if (*ptr == '\0') { + /* Missing format string; bad */ + file_magwarn("Invalid format `%s' for type `%s'", + m->desc, names[m->type]); + return 0; + } + if (strchr(formats[m->type], *ptr) == NULL) { + file_magwarn("Printf format `%c' is not valid for type `%s'" + " in description `%s'", + *ptr, names[m->type], m->desc); + return 0; + } + return 1; +} + /* * Read a numeric value from a pointer, into the value union of a magic * pointer, according to the magic type. Update the string pointer to point * just after the number read. Return 0 for success, non-zero for failure. */ -static int -getvalue(struct magic *m, char **p) +private int +getvalue(struct magic_set *ms, struct magic *m, char **p) { int slen; - if (m->type == STRING || m->type == PSTRING || m->type == REGEX) { - *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen); + switch (m->type) { + case FILE_STRING: + case FILE_PSTRING: + case FILE_REGEX: + *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen); + if (*p == NULL) { + if (ms->flags & MAGIC_CHECK) + file_magwarn("cannot get string from `%s'", + m->value.s); + return -1; + } m->vallen = slen; - } else + return 0; + default: if (m->reln != 'x') { - m->value.l = signextend(m, strtoul(*p, p, 0)); + m->value.l = file_signextend(ms, m, + (uint32_t)strtoul(*p, p, 0)); eatsize(p); } - return 0; + return 0; + } } /* @@ -701,8 +815,8 @@ getvalue(struct magic *m, char **p) * Copy the converted version to "p", returning its length in *slen. * Return updated scan pointer as function result. */ -static char * -getstr(char *s, char *p, int plen, int *slen) +private char * +getstr(struct magic_set *ms, char *s, char *p, int plen, int *slen) { char *origs = s, *origp = p; char *pmax = p + plen - 1; @@ -713,8 +827,8 @@ getstr(char *s, char *p, int plen, int *slen) if (isspace((unsigned char) c)) break; if (p >= pmax) { - fprintf(stderr, "String too long: %s\n", origs); - break; + file_error(ms, 0, "string too long: `%s'", origs); + return NULL; } if(c == '\\') { switch(c = *s++) { @@ -801,7 +915,7 @@ out: /* Single hex char to int; -1 if not a hex char. */ -static int +private int hextoint(int c) { if (!isascii((unsigned char) c)) @@ -819,14 +933,14 @@ hextoint(int c) /* * Print a string containing C character escapes. */ -void -showstr(FILE *fp, const char *s, int len) +protected void +file_showstr(FILE *fp, const char *s, size_t len) { char c; for (;;) { c = *s++; - if (len == -1) { + if (len == ~0U) { if (c == '\0') break; } @@ -875,7 +989,7 @@ showstr(FILE *fp, const char *s, int len) /* * eatsize(): Eat the size spec from a number [eg. 10UL] */ -static void +private void eatsize(char **p) { char *l = *p; @@ -901,17 +1015,18 @@ eatsize(char **p) /* * handle a compiled file. */ -static int -apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, - int action) +private int +apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, + const char *fn) { int fd; struct stat st; uint32_t *ptr; uint32_t version; int needsbyteswap; - char *dbname = mkdbname(fn); - void *mm; + char buf[MAXPATHLEN]; + char *dbname = mkdbname(fn, buf, sizeof(buf)); + void *mm = NULL; if (dbname == NULL) return -1; @@ -920,38 +1035,39 @@ apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, return -1; if (fstat(fd, &st) == -1) { - (void)fprintf(stderr, "%s: Cannot stat `%s' (%s)\n", - progname, dbname, strerror(errno)); + file_error(ms, errno, "cannot stat `%s'", dbname); + goto error; + } + if (st.st_size < 16) { + file_error(ms, 0, "file `%s' is too small", dbname); goto error; } #ifdef QUICK if ((mm = 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)); + file_error(ms, errno, "cannot map `%s'", dbname); goto error; } +#define RET 2 #else if ((mm = malloc((size_t)st.st_size)) == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); + file_oomem(ms); goto error; } if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) { - (void) fprintf(stderr, "%s: Read failed (%s).\n", progname, - strerror(errno)); + file_badread(ms); goto error; } +#define RET 1 #endif *magicp = mm; (void)close(fd); fd = -1; - ptr = (uint32_t *) *magicp; + ptr = (uint32_t *)(void *)*magicp; if (*ptr != MAGICNO) { if (swap4(*ptr) != MAGICNO) { - (void)fprintf(stderr, "%s: Bad magic in `%s'\n", - progname, dbname); + file_error(ms, 0, "bad magic in `%s'"); goto error; } needsbyteswap = 1; @@ -962,23 +1078,22 @@ apprentice_map(struct magic **magicp, uint32_t *nmagicp, const char *fn, else version = ptr[1]; if (version != VERSIONNO) { - (void)fprintf(stderr, - "%s: version mismatch (%d != %d) in `%s'\n", - progname, version, VERSIONNO, dbname); + file_error(ms, 0, "version mismatch (%d != %d) in `%s'", + version, VERSIONNO, dbname); goto error; } - *nmagicp = (st.st_size / sizeof(struct magic)) - 1; + *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1; (*magicp)++; if (needsbyteswap) byteswap(*magicp, *nmagicp); - return 0; + return RET; error: if (fd != -1) (void)close(fd); if (mm) { #ifdef QUICK - (void)munmap(mm, (size_t)st.st_size); + (void)munmap((void *)mm, (size_t)st.st_size); #else free(mm); #endif @@ -989,44 +1104,42 @@ error: return -1; } +private const uint32_t ar[] = { + MAGICNO, VERSIONNO +}; /* * handle an mmaped file. */ -static int -apprentice_compile(struct magic **magicp, uint32_t *nmagicp, const char *fn, - int action) +private int +apprentice_compile(struct magic_set *ms, struct magic **magicp, + uint32_t *nmagicp, const char *fn) { int fd; - char *dbname = mkdbname(fn); - static const uint32_t ar[] = { - MAGICNO, VERSIONNO - }; + char buf[MAXPATHLEN]; + char *dbname = mkdbname(fn, buf, sizeof(buf)); if (dbname == NULL) return -1; 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)); + file_error(ms, errno, "cannot open `%s'", dbname); return -1; } - if (write(fd, ar, sizeof(ar)) != sizeof(ar)) { - (void)fprintf(stderr, "%s: error writing `%s' (%s)\n", - progname, dbname, strerror(errno)); + if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) { + file_error(ms, errno, "error writing `%s'", dbname); 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)); + if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET) + != sizeof(struct magic)) { + file_error(ms, errno, "error seeking `%s'", dbname); 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)); + if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) + != (ssize_t)(sizeof(struct magic) * *nmagicp)) { + file_error(ms, errno, "error writing `%s'", dbname); return -1; } @@ -1034,33 +1147,26 @@ apprentice_compile(struct magic **magicp, uint32_t *nmagicp, const char *fn, return 0; } +private const char ext[] = ".mgc"; /* * make a dbname */ -char * -mkdbname(const char *fn) +private char * +mkdbname(const char *fn, char *buf, size_t bufsiz) { - 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); - if (buf == NULL) { - (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname, - strerror(errno)); - return NULL; - } - (void)strcpy(buf, fn); - (void)strcat(buf, ext); +#ifdef notdef + const char *p; + if ((p = strrchr(fn, '/')) != NULL) + fn = ++p; +#endif + (void)snprintf(buf, bufsiz, "%s%s", fn, ext); return buf; } /* * Byteswap an mmap'ed file if needed */ -static void +private void byteswap(struct magic *magic, uint32_t nmagic) { uint32_t i; @@ -1071,12 +1177,12 @@ byteswap(struct magic *magic, uint32_t nmagic) /* * swap a short */ -static uint16_t +private uint16_t swap2(uint16_t sv) { uint16_t rv; - uint8_t *s = (uint8_t *) &sv; - uint8_t *d = (uint8_t *) &rv; + uint8_t *s = (uint8_t *)(void *)&sv; + uint8_t *d = (uint8_t *)(void *)&rv; d[0] = s[1]; d[1] = s[0]; return rv; @@ -1085,12 +1191,12 @@ swap2(uint16_t sv) /* * swap an int */ -static uint32_t +private uint32_t swap4(uint32_t sv) { uint32_t rv; - uint8_t *s = (uint8_t *) &sv; - uint8_t *d = (uint8_t *) &rv; + uint8_t *s = (uint8_t *)(void *)&sv; + uint8_t *d = (uint8_t *)(void *)&rv; d[0] = s[3]; d[1] = s[2]; d[2] = s[1]; @@ -1101,13 +1207,13 @@ swap4(uint32_t sv) /* * byteswap a single magic entry */ -static -void bs1(struct magic *m) +private void +bs1(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->offset = swap4((uint32_t)m->offset); + m->in_offset = swap4((uint32_t)m->in_offset); + if (m->type != FILE_STRING) m->value.l = swap4(m->value.l); m->mask = swap4(m->mask); } -- cgit v1.1