diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/apprentice.c | 645 | ||||
-rw-r--r-- | src/file.h | 20 | ||||
-rw-r--r-- | src/funcs.c | 4 | ||||
-rw-r--r-- | src/magic.c | 75 | ||||
-rw-r--r-- | src/print.c | 6 | ||||
-rw-r--r-- | src/softmagic.c | 63 |
6 files changed, 524 insertions, 289 deletions
diff --git a/src/apprentice.c b/src/apprentice.c index b7aab7bc..2b1608d9 100644 --- a/src/apprentice.c +++ b/src/apprentice.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: apprentice.c,v 1.176 2012/09/06 14:42:39 christos Exp $") +FILE_RCSID("@(#)$File: apprentice.c,v 1.177 2012/10/30 23:11:51 christos Exp $") #endif /* lint */ #include "magic.h" @@ -71,6 +71,9 @@ FILE_RCSID("@(#)$File: apprentice.c,v 1.176 2012/09/06 14:42:39 christos Exp $") #define MAP_FILE 0 #endif +#define ALLOC_CHUNK (size_t)10 +#define ALLOC_INCR (size_t)200 + struct magic_entry { struct magic *mp; uint32_t cont_count; @@ -86,15 +89,17 @@ private int getvalue(struct magic_set *ms, struct magic *, const char **, int); private int hextoint(int); private const char *getstr(struct magic_set *, struct magic *, const char *, int); -private int parse(struct magic_set *, struct magic_entry **, uint32_t *, - const char *, size_t, int); +private int parse(struct magic_set *, struct magic_entry *, const char *, + size_t, int); private void eatsize(const char **); -private int apprentice_1(struct magic_set *, const char *, int, struct mlist *); +private int apprentice_1(struct magic_set *, const char *, int); private size_t apprentice_magic_strength(const struct magic *); private int apprentice_sort(const void *, const void *); private void apprentice_list(struct mlist *, int ); private int apprentice_load(struct magic_set *, struct magic **, uint32_t *, const char *, int); +private struct mlist *mlist_alloc(void); +private void mlist_free(struct mlist *); private void byteswap(struct magic *, uint32_t); private void bs1(struct magic *); private uint16_t swap2(uint16_t); @@ -113,7 +118,7 @@ private int parse_strength(struct magic_set *, struct magic_entry *, const char private int parse_apple(struct magic_set *, struct magic_entry *, const char *); -private size_t maxmagic = 0; +private size_t maxmagic[MAGIC_SETS] = { 0 }; private size_t magicsize = sizeof(struct magic); private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; @@ -216,6 +221,8 @@ static const struct type_tbl_s { { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR }, { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR }, { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, + { XX("name"), FILE_NAME, FILE_FMT_STR }, + { XX("use"), FILE_USE, FILE_FMT_STR }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, # undef XX # undef XX_NULL @@ -253,71 +260,84 @@ init_file_tables(void) } } +private int +add_mlist(struct mlist *mlp, struct magic *magic, uint32_t nmagic, int mapped) +{ + struct mlist *ml; + + if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) + return -1; + + ml->magic = magic; + ml->nmagic = nmagic; + ml->mapped = mapped; + + mlp->prev->next = ml; + ml->prev = mlp->prev; + ml->next = mlp; + mlp->prev = ml; + return 0; +} + /* * Handle one file or directory. */ private int -apprentice_1(struct magic_set *ms, const char *fn, int action, - struct mlist *mlist) +apprentice_1(struct magic_set *ms, const char *fn, int action) { - struct magic *magic = NULL; - uint32_t nmagic = 0; + struct magic *magic[MAGIC_SETS] = { NULL }; + uint32_t nmagic[MAGIC_SETS] = { 0 }; struct mlist *ml; int rv = -1; int mapped; if (magicsize != FILE_MAGICSIZE) { file_error(ms, 0, "magic element size %lu != %lu", - (unsigned long)sizeof(*magic), + (unsigned long)sizeof(*magic[0]), (unsigned long)FILE_MAGICSIZE); return -1; } if (action == FILE_COMPILE) { - rv = apprentice_load(ms, &magic, &nmagic, fn, action); + rv = apprentice_load(ms, magic, nmagic, fn, action); if (rv != 0) return -1; - rv = apprentice_compile(ms, &magic, &nmagic, fn); - free(magic); + rv = apprentice_compile(ms, magic, nmagic, fn); return rv; } #ifndef COMPILE_ONLY - if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) { + if ((rv = apprentice_map(ms, magic, nmagic, fn)) < 0) { + if (rv == -2) + return -1; if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "using regular magic file `%s'", fn); - rv = apprentice_load(ms, &magic, &nmagic, fn, action); + rv = apprentice_load(ms, magic, nmagic, fn, action); if (rv != 0) return -1; } mapped = rv; - if (magic == NULL) { - file_delmagic(magic, mapped, nmagic); - return -1; - } - - if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) { - file_delmagic(magic, mapped, nmagic); - file_oomem(ms, sizeof(*ml)); - return -1; + for (size_t i = 0; i < MAGIC_SETS; i++) { + if (magic[i] == NULL) + continue; + if (add_mlist(ms->mlist[i], magic[i], nmagic[i], mapped) == -1) + { + i = i == 1 ? 0 : 1; + file_delmagic(magic[i], mapped, nmagic[i]); + file_oomem(ms, sizeof(*ml)); + 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; - if (action == FILE_LIST) { - printf("Binary patterns:\n"); - apprentice_list(mlist, BINTEST); - printf("Text patterns:\n"); - apprentice_list(mlist, TEXTTEST); + for (size_t i = 0; i < MAGIC_SETS; i++) { + printf("Set %zu:\nBinary patterns:\n", i); + apprentice_list(ms->mlist[i], BINTEST); + printf("Text patterns:\n"); + apprentice_list(ms->mlist[i], TEXTTEST); + } } return 0; @@ -325,6 +345,51 @@ apprentice_1(struct magic_set *ms, const char *fn, int action, } protected void +file_ms_free(struct magic_set *ms) +{ + if (ms == NULL) + return; + for (size_t i = 0; i < MAGIC_SETS; i++) + mlist_free(ms->mlist[i]); + free(ms->o.pbuf); + free(ms->o.buf); + free(ms->c.li); + free(ms); +} + +protected struct magic_set * +file_ms_alloc(int flags) { + struct magic_set *ms; + size_t len; + + if ((ms = CAST(struct magic_set *, calloc((size_t)1, + sizeof(struct magic_set)))) == NULL) + return NULL; + + if (magic_setflags(ms, flags) == -1) { + errno = EINVAL; + goto free; + } + + ms->o.buf = ms->o.pbuf = NULL; + len = (ms->c.len = 10) * sizeof(*ms->c.li); + + if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) + goto free; + + ms->event_flags = 0; + ms->error = -1; + for (size_t i = 0; i < MAGIC_SETS; i++) + ms->mlist[i] = NULL; + ms->file = "unknown"; + ms->line = 0; + return ms; +free: + free(ms); + return NULL; +} + +protected void file_delmagic(struct magic *p, int type, size_t entries) { if (p == NULL) @@ -351,31 +416,67 @@ file_delmagic(struct magic *p, int type, size_t entries) } } +private struct mlist * +mlist_alloc(void) +{ + struct mlist *mlist; + if ((mlist = CAST(struct mlist *, malloc(sizeof(*mlist)))) == NULL) { + return NULL; + } + mlist->next = mlist->prev = mlist; + return mlist; +} + +private void +mlist_free(struct mlist *mlist) +{ + struct mlist *ml; + + if (mlist == NULL) + return; + + for (ml = mlist->next; ml != mlist;) { + struct mlist *next = ml->next; + struct magic *mg = ml->magic; + file_delmagic(mg, ml->mapped, ml->nmagic); + free(ml); + ml = next; + } + free(ml); +} + /* const char *fn: list of magic files and directories */ -protected struct mlist * +protected int file_apprentice(struct magic_set *ms, const char *fn, int action) { char *p, *mfn; int file_err, errs = -1; - struct mlist *mlist; if ((fn = magic_getpath(fn, action)) == NULL) - return NULL; + return -1; init_file_tables(); if ((mfn = strdup(fn)) == NULL) { file_oomem(ms, strlen(fn)); - return NULL; + return -1; } - fn = mfn; - if ((mlist = CAST(struct mlist *, malloc(sizeof(*mlist)))) == NULL) { - free(mfn); - file_oomem(ms, sizeof(*mlist)); - return NULL; + for (size_t i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + if ((ms->mlist[i] = mlist_alloc()) == NULL) { + file_oomem(ms, sizeof(*ms->mlist[i])); + if (i != 0) { + --i; + do + mlist_free(ms->mlist[i]); + while (i != 0); + } + free(mfn); + return -1; + } } - mlist->next = mlist->prev = mlist; + fn = mfn; while (fn) { p = strchr(fn, PATHSEP); @@ -383,19 +484,39 @@ file_apprentice(struct magic_set *ms, const char *fn, int action) *p++ = '\0'; if (*fn == '\0') break; - file_err = apprentice_1(ms, fn, action, mlist); + file_err = apprentice_1(ms, fn, action); errs = MAX(errs, file_err); fn = p; } + + free(mfn); + if (errs == -1) { - free(mfn); - free(mlist); - mlist = NULL; + for (size_t i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } file_error(ms, 0, "could not find any magic files!"); - return NULL; + return -1; + } + + if (action == FILE_LOAD) + return 0; + + for (size_t i = 0; i < MAGIC_SETS; i++) { + mlist_free(ms->mlist[i]); + ms->mlist[i] = NULL; + } + + switch (action) { + case FILE_COMPILE: + case FILE_CHECK: + case FILE_LIST: + return 0; + default: + file_error(ms, 0, "Invalid action %d", action); + return -1; } - free(mfn); - return mlist; } /* @@ -478,6 +599,8 @@ apprentice_magic_strength(const struct magic *m) break; case FILE_INDIRECT: + case FILE_NAME: + case FILE_USE: break; default: @@ -676,16 +799,41 @@ set_test_type(struct magic *mstart, struct magic *m) } } +private int +addentry(struct magic_set *ms, struct magic_entry *me, + struct magic_entry **mentry, uint32_t *mentrycount) +{ + size_t i = me->mp->type == FILE_NAME ? 1 : 0; + if (mentrycount[i] == maxmagic[i]) { + struct magic_entry *mp; + + maxmagic[i] += ALLOC_INCR; + if ((mp = CAST(struct magic_entry *, + realloc(mentry[i], sizeof(*mp) * maxmagic[i]))) == + NULL) { + file_oomem(ms, sizeof(*mp) * maxmagic[i]); + return -1; + } + (void)memset(&mp[mentrycount[i]], 0, sizeof(*mp) * + ALLOC_INCR); + mentry[i] = mp; + } + mentry[i][mentrycount[i]++] = *me; + memset(me, 0, sizeof(*me)); + return 0; +} + /* * Load and parse one file. */ private void load_1(struct magic_set *ms, int action, const char *fn, int *errs, - struct magic_entry **marray, uint32_t *marraycount) + struct magic_entry **mentry, uint32_t *mentrycount) { size_t lineno = 0, llen = 0; char *line = NULL; ssize_t len; + struct magic_entry me; FILE *f = fopen(ms->file = fn, "r"); if (f == NULL) { @@ -696,6 +844,7 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, return; } + memset(&me, 0, sizeof(me)); /* read and parse this file */ for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; ms->line++) { @@ -725,15 +874,14 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, (*errs)++; continue; } - if (*marraycount == 0) { + if (me.mp == NULL) { file_error(ms, 0, "No current entry for :!%s type", bang[i].name); (*errs)++; continue; } - if ((*bang[i].fun)(ms, - &(*marray)[*marraycount - 1], + if ((*bang[i].fun)(ms, &me, line + bang[i].len + 2) != 0) { (*errs)++; continue; @@ -742,12 +890,21 @@ load_1(struct magic_set *ms, int action, const char *fn, int *errs, } /*FALLTHROUGH*/ default: - if (parse(ms, marray, marraycount, line, lineno, - action) != 0) + again: + switch (parse(ms, &me, line, lineno, action)) { + case 0: + continue; + case 1: + (void)addentry(ms, &me, mentry, mentrycount); + goto again; + default: (*errs)++; - break; + break; + } } } + if (me.mp) + (void)addentry(ms, &me, mentry, mentrycount); free(line); (void)fclose(f); } @@ -762,14 +919,107 @@ cmpstrp(const void *p1, const void *p2) return strcmp(*(char *const *)p1, *(char *const *)p2); } + +private uint32_t +set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme, + uint32_t starttest) +{ + static const char text[] = "text"; + static const char binary[] = "binary"; + static const size_t len = sizeof(text); + + uint32_t i = starttest; + + do { + set_test_type(me[starttest].mp, me[i].mp); + if ((ms->flags & MAGIC_DEBUG) == 0) + continue; + (void)fprintf(stderr, "%s%s%s: %s\n", + me[i].mp->mimetype, + me[i].mp->mimetype[0] == '\0' ? "" : "; ", + me[i].mp->desc[0] ? me[i].mp->desc : "(no description)", + me[i].mp->flag & BINTEST ? binary : text); + if (me[i].mp->flag & BINTEST) { + char *p = strstr(me[i].mp->desc, text); + if (p && (p == me[i].mp->desc || + isspace((unsigned char)p[-1])) && + (p + len - me[i].mp->desc == MAXstring + || (p[len] == '\0' || + isspace((unsigned char)p[len])))) + (void)fprintf(stderr, "*** Possible " + "binary test for text type\n"); + } + } while (++i < nme && me[i].mp->cont_level != 0); + return i; +} + +private void +set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme) +{ + uint32_t i; + for (i = 0; i < nme; i++) { + if (me[i].mp->cont_level == 0 && + me[i].mp->type == FILE_DEFAULT) { + while (++i < nme) + if (me[i].mp->cont_level == 0) + break; + if (i != nme) { + /* XXX - Ugh! */ + ms->line = me[i].mp->lineno; + file_magwarn(ms, + "level 0 \"default\" did not sort last"); + } + return; + } + } +} + +private int +coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme, + struct magic **ma, uint32_t *nma) +{ + uint32_t i, mentrycount; + size_t slen; + + for (i = 0; i < nme; i++) + mentrycount += me[i].cont_count; + + slen = sizeof(**ma) * mentrycount; + if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { + file_oomem(ms, slen); + return -1; + } + + mentrycount = 0; + for (i = 0; i < nme; i++) { + (void)memcpy(*ma + mentrycount, me[i].mp, + me[i].cont_count * sizeof(**ma)); + mentrycount += me[i].cont_count; + } + *nma = mentrycount; + return 0; +} + +private void +magic_entry_free(struct magic_entry *me, uint32_t nme) +{ + uint32_t i; + if (me == NULL) + return; + for (i = 0; i < nme; i++) + free(me[i].mp); + free(me); +} + private int apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, const char *fn, int action) { int errs = 0; - struct magic_entry *marray; - uint32_t marraycount, i, mentrycount = 0, starttest; - size_t slen, files = 0, maxfiles = 0; + struct magic_entry *mentry[MAGIC_SETS] = { NULL }; + uint32_t mentrycount[MAGIC_SETS] = { 0 }; + uint32_t i, j; + size_t files = 0, maxfiles = 0; char **filearr = NULL, *mfn; struct stat st; DIR *dir; @@ -777,14 +1027,6 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ - maxmagic = MAXMAGIS; - if ((marray = CAST(struct magic_entry *, calloc(maxmagic, - sizeof(*marray)))) == NULL) { - file_oomem(ms, maxmagic * sizeof(*marray)); - return -1; - } - marraycount = 0; - /* print silly verbose header for USG compat. */ if (action == FILE_CHECK) (void)fprintf(stderr, "%s\n", usg_hdr); @@ -826,100 +1068,58 @@ apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, closedir(dir); qsort(filearr, files, sizeof(*filearr), cmpstrp); for (i = 0; i < files; i++) { - load_1(ms, action, filearr[i], &errs, &marray, - &marraycount); + load_1(ms, action, filearr[i], &errs, mentry, + mentrycount); free(filearr[i]); } free(filearr); } else - load_1(ms, action, fn, &errs, &marray, &marraycount); + load_1(ms, action, fn, &errs, mentry, mentrycount); if (errs) goto out; - /* Set types of tests */ - for (i = 0; i < marraycount; ) { - if (marray[i].mp->cont_level != 0) { - i++; - continue; - } - - starttest = i; - do { - static const char text[] = "text"; - static const char binary[] = "binary"; - static const size_t len = sizeof(text); - set_test_type(marray[starttest].mp, marray[i].mp); - if ((ms->flags & MAGIC_DEBUG) == 0) + for (j = 0; j < MAGIC_SETS; j++) { +fprintf(stderr, "set %u %p %u\n", j, mentry[j], mentrycount[j]); + /* Set types of tests */ + for (i = 0; i < mentrycount[j]; ) { + if (mentry[j][i].mp->cont_level != 0) { + i++; continue; - (void)fprintf(stderr, "%s%s%s: %s\n", - marray[i].mp->mimetype, - marray[i].mp->mimetype[0] == '\0' ? "" : "; ", - marray[i].mp->desc[0] ? marray[i].mp->desc : - "(no description)", - marray[i].mp->flag & BINTEST ? binary : text); - if (marray[i].mp->flag & BINTEST) { - char *p = strstr(marray[i].mp->desc, text); - if (p && (p == marray[i].mp->desc || - isspace((unsigned char)p[-1])) && - (p + len - marray[i].mp->desc == - MAXstring || (p[len] == '\0' || - isspace((unsigned char)p[len])))) - (void)fprintf(stderr, "*** Possible " - "binary test for text type\n"); } - } while (++i < marraycount && marray[i].mp->cont_level != 0); - } - - qsort(marray, marraycount, sizeof(*marray), apprentice_sort); - - /* - * Make sure that any level 0 "default" line is last (if one exists). - */ - for (i = 0; i < marraycount; i++) { - if (marray[i].mp->cont_level == 0 && - marray[i].mp->type == FILE_DEFAULT) { - while (++i < marraycount) - if (marray[i].mp->cont_level == 0) - break; - if (i != marraycount) { - /* XXX - Ugh! */ - ms->line = marray[i].mp->lineno; - file_magwarn(ms, - "level 0 \"default\" did not sort last"); - } - break; + i = set_text_binary(ms, mentry[j], mentrycount[j], i); } - } + qsort(mentry[j], mentrycount[j], sizeof(*mentry[j]), + apprentice_sort); - for (i = 0; i < marraycount; i++) - mentrycount += marray[i].cont_count; + /* + * Make sure that any level 0 "default" line is last + * (if one exists). + */ + set_last_default(ms, mentry[j], mentrycount[j]); - slen = sizeof(**magicp) * mentrycount; - if ((*magicp = CAST(struct magic *, malloc(slen))) == NULL) { - file_oomem(ms, slen); - errs++; - goto out; + /* coallesce per file arrays into a single one */ + if (coalesce_entries(ms, mentry[j], mentrycount[j], + &magicp[j], &nmagicp[j]) == -1) { + errs++; + goto out; + } } - mentrycount = 0; - for (i = 0; i < marraycount; i++) { - (void)memcpy(*magicp + mentrycount, marray[i].mp, - marray[i].cont_count * sizeof(**magicp)); - mentrycount += marray[i].cont_count; - } out: - for (i = 0; i < marraycount; i++) - free(marray[i].mp); - free(marray); + for (j = 0; j < MAGIC_SETS; j++) + magic_entry_free(mentry[j], mentrycount[j]); + if (errs) { - *magicp = NULL; - *nmagicp = 0; + for (j = 0; j < MAGIC_SETS; j++) { + if (magicp[j]) { + free(magicp[j]); + magicp[j] = NULL; + } + nmagicp[j] = 0; + } return errs; - } else { - *nmagicp = mentrycount; - return 0; } - + return 0; } /* @@ -985,6 +1185,8 @@ file_signextend(struct magic_set *ms, struct magic *m, uint64_t v) case FILE_SEARCH: case FILE_DEFAULT: case FILE_INDIRECT: + case FILE_NAME: + case FILE_USE: break; default: if (ms->flags & MAGIC_CHECK) @@ -1154,14 +1356,13 @@ check_cond(struct magic_set *ms, int cond, uint32_t cont_level) * parse one line from magic file, put into magic[index++] if valid */ private int -parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, - const char *line, size_t lineno, int action) +parse(struct magic_set *ms, struct magic_entry *me, const char *line, + size_t lineno, int action) { #ifdef ENABLE_CONDITIONALS static uint32_t last_cont_level = 0; #endif size_t i; - struct magic_entry *me; struct magic *m; const char *l = line; char *t; @@ -1180,16 +1381,11 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, return -1; last_cont_level = cont_level; #endif - -#define ALLOC_CHUNK (size_t)10 -#define ALLOC_INCR (size_t)200 - if (cont_level != 0) { - if (*nmentryp == 0) { + if (me->mp == NULL) { file_error(ms, 0, "No current entry for continuation"); return -1; } - me = &(*mentryp)[*nmentryp - 1]; if (me->cont_count == me->max_count) { struct magic *nm; size_t cnt = me->max_count + ALLOC_CHUNK; @@ -1205,31 +1401,15 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, (void)memset(m, 0, sizeof(*m)); m->cont_level = cont_level; } else { - if (*nmentryp == maxmagic) { - struct magic_entry *mp; - - maxmagic += ALLOC_INCR; - if ((mp = CAST(struct magic_entry *, - realloc(*mentryp, sizeof(*mp) * maxmagic))) == - NULL) { - file_oomem(ms, sizeof(*mp) * maxmagic); - return -1; - } - (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * - ALLOC_INCR); - *mentryp = mp; + if (me->mp != NULL) + return 1; + size_t len = sizeof(*m) * ALLOC_CHUNK; + if ((m = CAST(struct magic *, malloc(len))) == NULL) { + file_oomem(ms, len); + return -1; } - me = &(*mentryp)[*nmentryp]; - if (me->mp == NULL) { - size_t len = sizeof(*m) * ALLOC_CHUNK; - if ((m = CAST(struct magic *, malloc(len))) == NULL) { - file_oomem(ms, len); - return -1; - } - me->mp = m; - me->max_count = ALLOC_CHUNK; - } else - m = me->mp; + me->mp = m; + me->max_count = ALLOC_CHUNK; (void)memset(m, 0, sizeof(*m)); m->factor_op = FILE_FACTOR_OP_NONE; m->cont_level = 0; @@ -1359,7 +1539,7 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, EATAB; #endif - if (*l == 'u') { + if (*l == 'u' && (l[1] != 's' || l[2] != 'e')) { ++l; m->flag |= UNSIGNED; } @@ -1582,8 +1762,6 @@ parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, } #endif m->mimetype[0] = '\0'; /* initialise MIME type to none */ - if (m->cont_level == 0) - ++(*nmentryp); /* make room for next */ return 0; } @@ -1905,6 +2083,8 @@ getvalue(struct magic_set *ms, struct magic *m, const char **p, int action) case FILE_PSTRING: case FILE_REGEX: case FILE_SEARCH: + case FILE_NAME: + case FILE_USE: *p = getstr(ms, m, *p, action == FILE_COMPILE); if (*p == NULL) { if (ms->flags & MAGIC_CHECK) @@ -2218,14 +2398,15 @@ private int apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, const char *fn) { - int fd; + int fd, ret; struct stat st; uint32_t *ptr; - uint32_t version; + uint32_t version, entries, nentries; int needsbyteswap; char *dbname = NULL; void *mm = NULL; + ret = -1; dbname = mkdbname(ms, fn, 0); if (dbname == NULL) goto error2; @@ -2260,10 +2441,9 @@ apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, } #define RET 1 #endif - *magicp = CAST(struct magic *, mm); (void)close(fd); fd = -1; - ptr = (uint32_t *)(void *)*magicp; + ptr = CAST(uint32_t *, mm); if (*ptr != MAGICNO) { if (swap4(*ptr) != MAGICNO) { file_error(ms, 0, "bad magic in `%s'", dbname); @@ -2276,18 +2456,39 @@ apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, version = swap4(ptr[1]); else version = ptr[1]; + ret = -2; if (version != VERSIONNO) { file_error(ms, 0, "File %s supports only version %d magic " "files. `%s' is version %d", VERSION, VERSIONNO, dbname, version); goto error1; } - *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)); - if (*nmagicp > 0) - (*nmagicp)--; - (*magicp)++; + entries = (uint32_t)(st.st_size / sizeof(struct magic)); + if ((off_t)(entries * sizeof(struct magic)) != st.st_size) { + file_error(ms, 0, "Size of `%s' %llu is not a multiple of %zu", + dbname, (unsigned long long)st.st_size, + sizeof(struct magic)); + goto error1; + } + magicp[0] = CAST(struct magic *, mm) + 1; + nentries = 0; + for (size_t i = 0; i < MAGIC_SETS; i++) { + if (needsbyteswap) + nmagicp[i] = swap4(ptr[i + 2]); + else + nmagicp[i] = ptr[i + 2]; + if (i != MAGIC_SETS - 1) + magicp[i + 1] = magicp[i] + nmagicp[i]; + nentries += nmagicp[i]; + } + if (entries != nentries + 1) { + file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", + dbname, entries, nentries + 1); + goto error1; + } if (needsbyteswap) - byteswap(*magicp, *nmagicp); + for (size_t i = 0; i < MAGIC_SETS; i++) + byteswap(magicp[i], nmagicp[i]); free(dbname); return RET; @@ -2301,12 +2502,14 @@ error1: free(mm); #endif } else { - *magicp = NULL; - *nmagicp = 0; + for (size_t i = 0; i < MAGIC_SETS; i++) { + magicp[i] = NULL; + nmagicp[i] = 0; + } } error2: free(dbname); - return -1; + return ret; } private const uint32_t ar[] = { @@ -2319,16 +2522,19 @@ private int apprentice_compile(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, const char *fn) { + static size_t nm = sizeof(*nmagicp) * MAGIC_SETS; int fd = -1; char *dbname; int rv = -1; + uint32_t i; dbname = mkdbname(ms, fn, 1); if (dbname == NULL) goto out; - if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) { + if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) + { file_error(ms, errno, "cannot open `%s'", dbname); goto out; } @@ -2338,16 +2544,25 @@ apprentice_compile(struct magic_set *ms, struct magic **magicp, goto out; } + if (write(fd, nmagicp, nm) != (ssize_t)nm) { + file_error(ms, errno, "error writing `%s'", dbname); + goto out; + } + + assert(nm + sizeof(ar) < sizeof(struct magic)); + if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) { file_error(ms, errno, "error seeking `%s'", dbname); goto out; } - if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) - != (ssize_t)(sizeof(struct magic) * *nmagicp)) { - file_error(ms, errno, "error writing `%s'", dbname); - goto out; + for (i = 0; i < MAGIC_SETS; i++) { + if (write(fd, magicp[i], (sizeof(struct magic) * nmagicp[i])) + != (ssize_t)(sizeof(struct magic) * nmagicp[i])) { + file_error(ms, errno, "error writing `%s'", dbname); + goto out; + } } if (fd != -1) @@ -2542,3 +2757,31 @@ file_pstring_get_length(const struct magic *m, const char *s) return len; } + +protected int +file_magicfind(struct magic_set *ms, const char *name, struct mlist *v) +{ + uint32_t i, j; + struct mlist *mlist, *ml; + + mlist = ms->mlist[1]; + + for (ml = mlist->next; ml != mlist; ml = ml->next) { + struct magic *ma = ml->magic; + uint32_t nma = ml->nmagic; + for (i = 0; i < nma; i++) { + if (ma[i].type != FILE_NAME) + continue; + fprintf(stderr, "i = %u %s\n", i, ma[i].value.s); + if (strcmp(ma[i].value.s, name) == 0) { + v->magic = &ma[i]; + for (j = i + 1; j < nma; j++) + if (ma[j].cont_level == 0) + break; + v->nmagic = j - i; + return 0; + } + } + } + return -1; +} @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.139 2012/09/06 14:42:39 christos Exp $ + * @(#)$File: file.h,v 1.140 2012/10/30 23:11:51 christos Exp $ */ #ifndef __file_h__ @@ -132,7 +132,7 @@ #define MAXstring 64 /* max leng of "string" types */ #define MAGICNO 0xF11E041C -#define VERSIONNO 8 +#define VERSIONNO 9 #define FILE_MAGICSIZE 232 #define FILE_LOAD 0 @@ -219,7 +219,9 @@ struct magic { #define FILE_QWDATE 42 #define FILE_LEQWDATE 43 #define FILE_BEQWDATE 44 -#define FILE_NAMES_SIZE 45/* size of array to contain all names */ +#define FILE_NAME 45 +#define FILE_USE 46 +#define FILE_NAMES_SIZE 47 /* size of array to contain all names */ #define IS_STRING(t) \ ((t) == FILE_STRING || \ @@ -228,6 +230,8 @@ struct magic { (t) == FILE_LESTRING16 || \ (t) == FILE_REGEX || \ (t) == FILE_SEARCH || \ + (t) == FILE_NAME || \ + (t) == FILE_USE || \ (t) == FILE_DEFAULT) #define FILE_FMT_NONE 0 @@ -365,8 +369,11 @@ struct level_info { int last_cond; /* used for error checking by parse() */ #endif }; + +#define MAGIC_SETS 2 + struct magic_set { - struct mlist *mlist; + struct mlist *mlist[MAGIC_SETS]; /* list of regular entries */ struct cont { size_t len; struct level_info *li; @@ -403,6 +410,8 @@ struct stat; #define FILE_T_LOCAL 1 #define FILE_T_WINDOWS 2 protected const char *file_fmttime(uint64_t, int, char *); +protected struct magic_set *file_ms_alloc(int); +protected void file_ms_free(struct magic_set *); protected int file_buffer(struct magic_set *, int, const char *, const void *, size_t); protected int file_fsmagic(struct magic_set *, const char *, struct stat *); @@ -431,7 +440,8 @@ protected int file_encoding(struct magic_set *, const unsigned char *, size_t, protected int file_is_tar(struct magic_set *, const unsigned char *, size_t); protected int file_softmagic(struct magic_set *, const unsigned char *, size_t, int, int); -protected struct mlist *file_apprentice(struct magic_set *, const char *, int); +protected int file_apprentice(struct magic_set *, const char *, int); +protected int file_magicfind(struct magic_set *, const char *, struct mlist *); protected uint64_t file_signextend(struct magic_set *, struct magic *, uint64_t); protected void file_delmagic(struct magic *, int type, size_t entries); diff --git a/src/funcs.c b/src/funcs.c index 0b2a3d0c..7fc0e5cb 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.60 2011/12/08 12:38:24 rrt Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.61 2012/10/30 23:11:51 christos Exp $") #endif /* lint */ #include "magic.h" @@ -301,7 +301,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((unu protected int file_reset(struct magic_set *ms) { - if (ms->mlist == NULL) { + if (ms->mlist[0] == NULL) { file_error(ms, 0, "no magic files loaded"); return -1; } diff --git a/src/magic.c b/src/magic.c index 0103cfce..2940afd1 100644 --- a/src/magic.c +++ b/src/magic.c @@ -33,7 +33,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: magic.c,v 1.75 2012/08/26 11:00:58 christos Exp $") +FILE_RCSID("@(#)$File: magic.c,v 1.76 2012/10/30 23:11:51 christos Exp $") #endif /* lint */ #include "magic.h" @@ -71,7 +71,6 @@ FILE_RCSID("@(#)$File: magic.c,v 1.75 2012/08/26 11:00:58 christos Exp $") #endif #endif -private void free_mlist(struct mlist *); private void close_and_restore(const struct magic_set *, const char *, int, const struct stat *); private int unreadable_info(struct magic_set *, mode_t, const char *); @@ -215,51 +214,7 @@ magic_getpath(const char *magicfile, int action) public struct magic_set * magic_open(int flags) { - struct magic_set *ms; - size_t len; - - if ((ms = CAST(struct magic_set *, calloc((size_t)1, - sizeof(struct magic_set)))) == NULL) - return NULL; - - if (magic_setflags(ms, flags) == -1) { - errno = EINVAL; - goto free; - } - - ms->o.buf = ms->o.pbuf = NULL; - len = (ms->c.len = 10) * sizeof(*ms->c.li); - - if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) - goto free; - - ms->event_flags = 0; - ms->error = -1; - ms->mlist = NULL; - ms->file = "unknown"; - ms->line = 0; - return ms; -free: - free(ms); - return NULL; -} - -private void -free_mlist(struct mlist *mlist) -{ - struct mlist *ml; - - if (mlist == NULL) - return; - - for (ml = mlist->next; ml != mlist;) { - struct mlist *next = ml->next; - struct magic *mg = ml->magic; - file_delmagic(mg, ml->mapped, ml->nmagic); - free(ml); - ml = next; - } - free(ml); + return file_ms_alloc(flags); } private int @@ -283,11 +238,7 @@ unreadable_info(struct magic_set *ms, mode_t md, const char *file) public void magic_close(struct magic_set *ms) { - free_mlist(ms->mlist); - free(ms->o.pbuf); - free(ms->o.buf); - free(ms->c.li); - free(ms); + file_ms_free(ms); } /* @@ -296,37 +247,25 @@ magic_close(struct magic_set *ms) public int magic_load(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD); - if (ml) { - free_mlist(ms->mlist); - ms->mlist = ml; - return 0; - } - return -1; + return file_apprentice(ms, magicfile, FILE_LOAD); } public int magic_compile(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE); - free_mlist(ml); - return ml ? 0 : -1; + return file_apprentice(ms, magicfile, FILE_COMPILE); } public int magic_check(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK); - free_mlist(ml); - return ml ? 0 : -1; + return file_apprentice(ms, magicfile, FILE_CHECK); } public int magic_list(struct magic_set *ms, const char *magicfile) { - struct mlist *ml = file_apprentice(ms, magicfile, FILE_LIST); - free_mlist(ml); - return ml ? 0 : -1; + return file_apprentice(ms, magicfile, FILE_LIST); } private void diff --git a/src/print.c b/src/print.c index 38377a3f..245bb983 100644 --- a/src/print.c +++ b/src/print.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: print.c,v 1.74 2012/05/15 17:14:36 christos Exp $") +FILE_RCSID("@(#)$File: print.c,v 1.75 2012/10/30 23:11:51 christos Exp $") #endif /* lint */ #include <string.h> @@ -195,6 +195,10 @@ file_mdump(struct magic *m) case FILE_DEFAULT: /* XXX - do anything here? */ break; + case FILE_USE: + case FILE_NAME: + (void) fprintf(stderr, "'%s'", m->value.s); + break; default: (void) fputs("*bad*", stderr); break; diff --git a/src/softmagic.c b/src/softmagic.c index 2f275c1e..eb7b8d16 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.152 2012/10/03 22:13:21 rrt Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.153 2012/10/30 23:11:52 christos Exp $") #endif /* lint */ #include "magic.h" @@ -43,9 +43,9 @@ FILE_RCSID("@(#)$File: softmagic.c,v 1.152 2012/10/03 22:13:21 rrt Exp $") private int match(struct magic_set *, struct magic *, uint32_t, - const unsigned char *, size_t, int, int); + const unsigned char *, size_t, size_t, int, int); private int mget(struct magic_set *, const unsigned char *, - struct magic *, size_t, unsigned int, int); + struct magic *, size_t, size_t, unsigned int, int, int); private int magiccheck(struct magic_set *, struct magic *); private int32_t mprint(struct magic_set *, struct magic *); private int32_t moffset(struct magic_set *, struct magic *); @@ -71,8 +71,8 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, { struct mlist *ml; int rv; - for (ml = ms->mlist->next; ml != ms->mlist; ml = ml->next) - if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, mode, + for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) + if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode, text)) != 0) return rv; @@ -108,7 +108,7 @@ file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes, */ private int match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, - const unsigned char *s, size_t nbytes, int mode, int text) + const unsigned char *s, size_t nbytes, size_t offset, int mode, int text) { uint32_t magindex = 0; unsigned int cont_level = 0; @@ -125,6 +125,7 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, int flush = 0; struct magic *m = &magic[magindex]; + if (m->type != FILE_NAME) if ((IS_STRING(m->type) && ((text && (m->str_flags & (STRING_BINTEST | STRING_TEXTTEST)) == STRING_BINTEST) || (!text && (m->str_flags & (STRING_TEXTTEST | STRING_BINTEST)) == STRING_TEXTTEST))) || @@ -140,9 +141,11 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, ms->offset = m->offset; ms->line = m->lineno; +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); /* if main entry matches, print it... */ - switch (mget(ms, s, m, nbytes, cont_level, text)) { + switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text)) { case -1: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); return -1; case 0: flush = m->reln != '!'; @@ -153,17 +156,21 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, switch (magiccheck(ms, m)) { case -1: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); return -1; case 0: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); flush++; break; default: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); flush = 0; break; } break; } if (flush) { +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); /* * main entry didn't match, * flush its continuations @@ -174,8 +181,10 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, continue; } - if ((e = handle_annotation(ms, m)) != 0) + if ((e = handle_annotation(ms, m)) != 0) { +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); return e; + } /* * If we are going to print something, we'll need to print * a blank before we print something else. @@ -191,12 +200,14 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, if (print && mprint(ms, m) == -1) return -1; +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); ms->c.li[cont_level].off = moffset(ms, m); /* and any continuations that match */ if (file_check_mem(ms, ++cont_level) == -1) return -1; +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); while (magic[magindex+1].cont_level != 0 && ++magindex < nmagic) { m = &magic[magindex]; @@ -224,15 +235,18 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, continue; } #endif - switch (mget(ms, s, m, nbytes, cont_level, text)) { + switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text)) { case -1: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); return -1; case 0: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); if (m->reln != '!') continue; flush = 1; break; default: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); if (m->type == FILE_INDIRECT) returnval = 1; flush = 0; @@ -241,13 +255,16 @@ match(struct magic_set *ms, struct magic *magic, uint32_t nmagic, switch (flush ? 1 : magiccheck(ms, m)) { case -1: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); return -1; case 0: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); #ifdef ENABLE_CONDITIONALS ms->c.li[cont_level].last_match = 0; #endif break; default: +fprintf(stderr, "%s, %d: %d, %s\n", __FILE__, __LINE__, m->type, m->desc); #ifdef ENABLE_CONDITIONALS ms->c.li[cont_level].last_match = 1; #endif @@ -601,6 +618,8 @@ mprint(struct magic_set *ms, struct magic *m) break; case FILE_INDIRECT: + case FILE_USE: + case FILE_NAME: t = ms->offset; break; @@ -921,6 +940,8 @@ mconvert(struct magic_set *ms, struct magic *m) case FILE_REGEX: case FILE_SEARCH: case FILE_DEFAULT: + case FILE_NAME: + case FILE_USE: return 1; default: file_magerror(ms, "invalid type %d in mconvert()", m->type); @@ -1049,16 +1070,17 @@ mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir, } private int -mget(struct magic_set *ms, const unsigned char *s, - struct magic *m, size_t nbytes, unsigned int cont_level, int text) +mget(struct magic_set *ms, const unsigned char *s, struct magic *m, + size_t nbytes, size_t o, unsigned int cont_level, int mode, int text) { uint32_t offset = ms->offset; uint32_t count = m->str_range; int rv; char *sbuf, *rbuf; union VALUETYPE *p = &ms->ms_value; + struct mlist ml; - if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1) + if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset + o, nbytes - o, count) == -1) return -1; if ((ms->flags & MAGIC_DEBUG) != 0) { @@ -1619,6 +1641,7 @@ mget(struct magic_set *ms, const unsigned char *s, return 0; sbuf = ms->o.buf; ms->o.buf = NULL; + ms->offset = 0; rv = file_softmagic(ms, s + offset, nbytes - offset, BINTEST, text); if ((ms->flags & MAGIC_DEBUG) != 0) @@ -1636,6 +1659,20 @@ mget(struct magic_set *ms, const unsigned char *s, ms->o.buf = sbuf; return rv; + case FILE_USE: + if (nbytes < offset) + return 0; + if (file_magicfind(ms, m->value.s, &ml) == -1) { + file_magerror(ms, "cannot find entry `%s'", m->value.s); + return -1; + } + return match(ms, ml.magic, ml.nmagic, s, nbytes, offset, + mode, text); + + case FILE_NAME: + if (file_printf(ms, m->desc) == -1) + return -1; + return 1; case FILE_DEFAULT: /* nothing to check */ default: break; @@ -1939,6 +1976,8 @@ magiccheck(struct magic_set *ms, struct magic *m) break; } case FILE_INDIRECT: + case FILE_USE: + case FILE_NAME: return 1; default: file_magerror(ms, "invalid type %d in magiccheck()", m->type); |