📄 apprentice.c
字号:
/* * 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. * * 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. */#include "file.h"#include "magic.h"#include <stdlib.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <string.h>#include <assert.h>#include <ctype.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/param.h>#ifdef QUICK#include <sys/mman.h>#endif#ifndef lintFILE_RCSID("@(#)$File: apprentice.c,v 1.105 2007/05/16 20:51:40 christos Exp $")#endif /* lint */#define EATAB {while (isascii((unsigned char) *l) && \ isspace((unsigned char) *l)) ++l;}#define LOWCASE(l) (isupper((unsigned char) (l)) ? \ tolower((unsigned char) (l)) : (l))/* * Work around a bug in headers on Digital Unix. * At least confirmed for: OSF1 V4.0 878 */#if defined(__osf__) && defined(__DECC)#ifdef MAP_FAILED#undef MAP_FAILED#endif#endif#ifndef MAP_FAILED#define MAP_FAILED (void *) -1#endif#ifndef MAP_FILE#define MAP_FILE 0#endif#ifndef MAXPATHLEN#define MAXPATHLEN 1024#endifstruct magic_entry { struct magic *mp; uint32_t cont_count; uint32_t max_count;};int file_formats[FILE_NAMES_SIZE];const size_t file_nformats = FILE_NAMES_SIZE;const char *file_names[FILE_NAMES_SIZE];const size_t file_nnames = FILE_NAMES_SIZE;private int getvalue(struct magic_set *ms, struct magic *, const char **, int);private int hextoint(int);private const char *getstr(struct magic_set *, const char *, char *, int, int *, int);private int parse(struct magic_set *, struct magic_entry **, uint32_t *, const char *, size_t, int);private void eatsize(const char **);private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);private size_t apprentice_magic_strength(const struct magic *);private int apprentice_sort(const void *, const void *);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 uint64_t swap8(uint64_t);private char *mkdbname(const char *, char *, size_t, int);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_type(const char *, int);private int check_format(struct magic_set *, struct magic *);private size_t maxmagic = 0;private size_t magicsize = sizeof(struct magic);#ifdef COMPILE_ONLYint main(int, char *[]);intmain(int argc, char *argv[]){ int ret; struct magic_set *ms; char *progname; if ((progname = strrchr(argv[0], '/')) != NULL) progname++; else progname = argv[0]; if (argc != 2) { (void)fprintf(stderr, "Usage: %s file\n", progname); return 1; } 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 */static const struct type_tbl_s { const char *name; const size_t len; const int type; const int format;} type_tbl[] = {# define XX(s) s, (sizeof(s) - 1)# define XX_NULL NULL, 0 { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, { XX("short"), FILE_SHORT, FILE_FMT_NUM }, { XX("default"), FILE_DEFAULT, FILE_FMT_STR }, { XX("long"), FILE_LONG, FILE_FMT_NUM }, { XX("string"), FILE_STRING, FILE_FMT_STR }, { XX("date"), FILE_DATE, FILE_FMT_STR }, { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM }, { XX("belong"), FILE_BELONG, FILE_FMT_NUM }, { XX("bedate"), FILE_BEDATE, FILE_FMT_STR }, { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM }, { XX("lelong"), FILE_LELONG, FILE_FMT_NUM }, { XX("ledate"), FILE_LEDATE, FILE_FMT_STR }, { XX("pstring"), FILE_PSTRING, FILE_FMT_STR }, { XX("ldate"), FILE_LDATE, FILE_FMT_STR }, { XX("beldate"), FILE_BELDATE, FILE_FMT_STR }, { XX("leldate"), FILE_LELDATE, FILE_FMT_STR }, { XX("regex"), FILE_REGEX, FILE_FMT_STR }, { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR }, { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR }, { XX("search"), FILE_SEARCH, FILE_FMT_STR }, { XX("medate"), FILE_MEDATE, FILE_FMT_STR }, { XX("meldate"), FILE_MELDATE, FILE_FMT_STR }, { XX("melong"), FILE_MELONG, FILE_FMT_NUM }, { XX("quad"), FILE_QUAD, FILE_FMT_QUAD }, { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD }, { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD }, { XX("qdate"), FILE_QDATE, FILE_FMT_STR }, { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR }, { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR }, { XX("qldate"), FILE_QLDATE, FILE_FMT_STR }, { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR }, { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR }, { XX_NULL, FILE_INVALID, FILE_FMT_NONE },# undef XX# undef XX_NULL};private intget_type(const char *l, const char **t){ const struct type_tbl_s *p; for (p = type_tbl; p->name; p++) { if (strncmp(l, p->name, p->len) == 0) { if (t) *t = l + p->len; break; } } return p->type;}private voidinit_file_tables(void){ static int done = 0; const struct type_tbl_s *p; if (done) return; done++; for (p = type_tbl; p->name; p++) { assert(p->type < FILE_NAMES_SIZE); file_names[p->type] = p->name; file_formats[p->type] = p->format; }}/* * Handle one file. */private intapprentice_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 (magicsize != FILE_MAGICSIZE) { file_error(ms, 0, "magic element size %lu != %lu", (unsigned long)sizeof(*magic), (unsigned long)FILE_MAGICSIZE); return -1; } 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; }#ifndef COMPILE_ONLY if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "using regular magic file `%s'", fn); rv = apprentice_file(ms, &magic, &nmagic, fn, action); if (rv != 0) return -1; mapped = 0; } 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, 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; return 0;#endif /* COMPILE_ONLY */}protected voidfile_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 */protected struct mlist *file_apprentice(struct magic_set *ms, const char *fn, int action){ char *p, *mfn, *afn = NULL; int file_err, errs = -1; struct mlist *mlist; static const char mime[] = ".mime"; init_file_tables(); if (fn == NULL) fn = getenv("MAGIC"); if (fn == NULL) fn = MAGIC; if ((mfn = strdup(fn)) == NULL) { file_oomem(ms, strlen(fn)); return NULL; } fn = mfn; if ((mlist = malloc(sizeof(*mlist))) == NULL) { free(mfn); file_oomem(ms, sizeof(*mlist)); return NULL; } mlist->next = mlist->prev = mlist; while (fn) { p = strchr(fn, PATHSEP); if (p) *p++ = '\0'; if (*fn == '\0') break; if (ms->flags & MAGIC_MIME) { size_t len = strlen(fn) + sizeof(mime); if ((afn = malloc(len)) == NULL) { free(mfn); free(mlist); file_oomem(ms, len); 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) { free(mfn); free(mlist); mlist = NULL; file_error(ms, 0, "could not find any magic files!"); return NULL; } free(mfn); return mlist;}/* * Get weight of this magic entry, for sorting purposes. */private size_tapprentice_magic_strength(const struct magic *m){#define MULT 10 size_t val = 2 * MULT; /* baseline strength */ switch (m->type) { case FILE_DEFAULT: /* make sure this sorts last */ return 0; case FILE_BYTE: val += 1 * MULT; break; case FILE_SHORT: case FILE_LESHORT: case FILE_BESHORT: val += 2 * MULT; break; case FILE_LONG: case FILE_LELONG: case FILE_BELONG: case FILE_MELONG: val += 4 * MULT; break; case FILE_PSTRING: case FILE_STRING: val += m->vallen * MULT; break; case FILE_BESTRING16: case FILE_LESTRING16: val += m->vallen * MULT / 2; break; case FILE_SEARCH: case FILE_REGEX: val += m->vallen; break; case FILE_DATE: case FILE_LEDATE: case FILE_BEDATE: case FILE_MEDATE: case FILE_LDATE: case FILE_LELDATE: case FILE_BELDATE: case FILE_MELDATE: val += 4 * MULT; break; case FILE_QUAD: case FILE_BEQUAD: case FILE_LEQUAD: case FILE_QDATE: case FILE_LEQDATE: case FILE_BEQDATE: case FILE_QLDATE: case FILE_LEQLDATE: case FILE_BEQLDATE: val += 8 * MULT; break; default: val = 0; (void)fprintf(stderr, "Bad type %d\n", m->type); abort(); } switch (m->reln) { case 'x': /* matches anything penalize */ val = 0; break; case '!': case '=': /* Exact match, prefer */ val += MULT; break; case '>': case '<': /* comparison match reduce strength */ val -= 2 * MULT; break; case '^': case '&': /* masking bits, we could count them too */ val -= MULT; break; default: (void)fprintf(stderr, "Bad relation %c\n", m->reln); abort(); } if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */ val = 1; return val;}/* * Sort callback for sorting entries by "strength" (basically length) */private intapprentice_sort(const void *a, const void *b){ const struct magic_entry *ma = a; const struct magic_entry *mb = b; size_t sa = apprentice_magic_strength(ma->mp); size_t sb = apprentice_magic_strength(mb->mp); if (sa == sb) return 0; else if (sa > sb) return -1; else return 1;}/* * parse from a file * const char *fn: name of magic file */private intapprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, const char *fn, int action){ private const char hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; FILE *f; char line[BUFSIZ+1]; int errs = 0; struct magic_entry *marray; uint32_t marraycount, i, mentrycount = 0; size_t lineno = 0; ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ f = fopen(ms->file = fn, "r"); if (f == NULL) { if (errno != ENOENT) file_error(ms, errno, "cannot read magic file `%s'", fn); return -1; } maxmagic = MAXMAGIS; if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) { (void)fclose(f); 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", hdr); /* read and parse this file */ for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) { size_t len; len = strlen(line); if (len == 0) /* null line, garbage, etc */ continue; if (line[len - 1] == '\n') { lineno++; line[len - 1] = '\0'; /* delete newline */ } if (line[0] == '\0') /* empty, do not parse */ continue; if (line[0] == '#') /* comment, do not parse */ continue; if (parse(ms, &marray, &marraycount, line, lineno, action) != 0) errs++; } (void)fclose(f); if (errs) goto out;#ifndef NOORDER 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) { ms->line = marray[i].mp->lineno; /* XXX - Ugh! */ file_magwarn(ms, "level 0 \"default\" did not sort last"); } break; } }#endif for (i = 0; i < marraycount; i++) mentrycount += marray[i].cont_count; if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) { file_oomem(ms, sizeof(**magicp) * mentrycount); 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); if (errs) { *magicp = NULL; *nmagicp = 0; return errs; } else { *nmagicp = mentrycount; return 0; }}/* * extend the sign bit if the comparison is to be signed */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -