1284194Sdelphij/* 2284194Sdelphij * Copyright (c) Ian F. Darwin 1986-1995. 3284194Sdelphij * Software written by Ian F. Darwin and others; 4284194Sdelphij * maintained 1995-present by Christos Zoulas and others. 5284194Sdelphij * 6284194Sdelphij * Redistribution and use in source and binary forms, with or without 7284194Sdelphij * modification, are permitted provided that the following conditions 8284194Sdelphij * are met: 9284194Sdelphij * 1. Redistributions of source code must retain the above copyright 10284194Sdelphij * notice immediately at the beginning of the file, without modification, 11284194Sdelphij * this list of conditions, and the following disclaimer. 12284194Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 13284194Sdelphij * notice, this list of conditions and the following disclaimer in the 14284194Sdelphij * documentation and/or other materials provided with the distribution. 15284194Sdelphij * 16284194Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17284194Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18284194Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19284194Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20284194Sdelphij * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21284194Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22284194Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23284194Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24284194Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25284194Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26284194Sdelphij * SUCH DAMAGE. 27284194Sdelphij */ 28284194Sdelphij/* 29284194Sdelphij * apprentice - make one pass through /etc/magic, learning its secrets. 30284194Sdelphij */ 31284194Sdelphij 32284194Sdelphij#include "file.h" 33284194Sdelphij 34284194Sdelphij#ifndef lint 35284194SdelphijFILE_RCSID("@(#)$File: apprentice.c,v 1.229 2015/01/01 17:07:34 christos Exp $") 36284194Sdelphij#endif /* lint */ 37284194Sdelphij 38284194Sdelphij#include "magic.h" 39284194Sdelphij#include <stdlib.h> 40284194Sdelphij#ifdef HAVE_UNISTD_H 41284194Sdelphij#include <unistd.h> 42284194Sdelphij#endif 43284194Sdelphij#ifdef HAVE_STDDEF_H 44284194Sdelphij#include <stddef.h> 45284194Sdelphij#endif 46284194Sdelphij#include <string.h> 47284194Sdelphij#include <assert.h> 48284194Sdelphij#include <ctype.h> 49284194Sdelphij#include <fcntl.h> 50284194Sdelphij#ifdef QUICK 51284194Sdelphij#include <sys/mman.h> 52284194Sdelphij#endif 53284194Sdelphij#include <dirent.h> 54284194Sdelphij#if defined(HAVE_LIMITS_H) 55284194Sdelphij#include <limits.h> 56284194Sdelphij#endif 57284194Sdelphij 58284194Sdelphij#ifndef SSIZE_MAX 59284194Sdelphij#define MAXMAGIC_SIZE ((ssize_t)0x7fffffff) 60284194Sdelphij#else 61284194Sdelphij#define MAXMAGIC_SIZE SSIZE_MAX 62284194Sdelphij#endif 63284194Sdelphij 64284194Sdelphij#define EATAB {while (isascii((unsigned char) *l) && \ 65284194Sdelphij isspace((unsigned char) *l)) ++l;} 66284194Sdelphij#define LOWCASE(l) (isupper((unsigned char) (l)) ? \ 67284194Sdelphij tolower((unsigned char) (l)) : (l)) 68284194Sdelphij/* 69284194Sdelphij * Work around a bug in headers on Digital Unix. 70284194Sdelphij * At least confirmed for: OSF1 V4.0 878 71284194Sdelphij */ 72284194Sdelphij#if defined(__osf__) && defined(__DECC) 73284194Sdelphij#ifdef MAP_FAILED 74284194Sdelphij#undef MAP_FAILED 75284194Sdelphij#endif 76284194Sdelphij#endif 77284194Sdelphij 78284194Sdelphij#ifndef MAP_FAILED 79284194Sdelphij#define MAP_FAILED (void *) -1 80284194Sdelphij#endif 81284194Sdelphij 82284194Sdelphij#ifndef MAP_FILE 83284194Sdelphij#define MAP_FILE 0 84284194Sdelphij#endif 85284194Sdelphij 86284194Sdelphij#define ALLOC_CHUNK (size_t)10 87284194Sdelphij#define ALLOC_INCR (size_t)200 88284194Sdelphij 89284194Sdelphij#define MAP_TYPE_MMAP 0 90284194Sdelphij#define MAP_TYPE_MALLOC 1 91284194Sdelphij#define MAP_TYPE_USER 2 92284194Sdelphij 93284194Sdelphijstruct magic_entry { 94284194Sdelphij struct magic *mp; 95284194Sdelphij uint32_t cont_count; 96284194Sdelphij uint32_t max_count; 97284194Sdelphij}; 98284194Sdelphij 99284194Sdelphijstruct magic_entry_set { 100284194Sdelphij struct magic_entry *me; 101284194Sdelphij uint32_t count; 102284194Sdelphij uint32_t max; 103284194Sdelphij}; 104284194Sdelphij 105284194Sdelphijstruct magic_map { 106284194Sdelphij void *p; 107284194Sdelphij size_t len; 108284194Sdelphij int type; 109284194Sdelphij struct magic *magic[MAGIC_SETS]; 110284194Sdelphij uint32_t nmagic[MAGIC_SETS]; 111284194Sdelphij}; 112284194Sdelphij 113284194Sdelphijint file_formats[FILE_NAMES_SIZE]; 114284194Sdelphijconst size_t file_nformats = FILE_NAMES_SIZE; 115284194Sdelphijconst char *file_names[FILE_NAMES_SIZE]; 116284194Sdelphijconst size_t file_nnames = FILE_NAMES_SIZE; 117284194Sdelphij 118284194Sdelphijprivate int getvalue(struct magic_set *ms, struct magic *, const char **, int); 119284194Sdelphijprivate int hextoint(int); 120284194Sdelphijprivate const char *getstr(struct magic_set *, struct magic *, const char *, 121284194Sdelphij int); 122284194Sdelphijprivate int parse(struct magic_set *, struct magic_entry *, const char *, 123284194Sdelphij size_t, int); 124284194Sdelphijprivate void eatsize(const char **); 125284194Sdelphijprivate int apprentice_1(struct magic_set *, const char *, int); 126284194Sdelphijprivate size_t apprentice_magic_strength(const struct magic *); 127284194Sdelphijprivate int apprentice_sort(const void *, const void *); 128284194Sdelphijprivate void apprentice_list(struct mlist *, int ); 129284194Sdelphijprivate struct magic_map *apprentice_load(struct magic_set *, 130284194Sdelphij const char *, int); 131284194Sdelphijprivate struct mlist *mlist_alloc(void); 132284194Sdelphijprivate void mlist_free(struct mlist *); 133284194Sdelphijprivate void byteswap(struct magic *, uint32_t); 134284194Sdelphijprivate void bs1(struct magic *); 135284194Sdelphijprivate uint16_t swap2(uint16_t); 136284194Sdelphijprivate uint32_t swap4(uint32_t); 137284194Sdelphijprivate uint64_t swap8(uint64_t); 138284194Sdelphijprivate char *mkdbname(struct magic_set *, const char *, int); 139284194Sdelphijprivate struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 140284194Sdelphij size_t); 141284194Sdelphijprivate struct magic_map *apprentice_map(struct magic_set *, const char *); 142284194Sdelphijprivate int check_buffer(struct magic_set *, struct magic_map *, const char *); 143284194Sdelphijprivate void apprentice_unmap(struct magic_map *); 144284194Sdelphijprivate int apprentice_compile(struct magic_set *, struct magic_map *, 145284194Sdelphij const char *); 146284194Sdelphijprivate int check_format_type(const char *, int); 147284194Sdelphijprivate int check_format(struct magic_set *, struct magic *); 148284194Sdelphijprivate int get_op(char); 149284194Sdelphijprivate int parse_mime(struct magic_set *, struct magic_entry *, const char *); 150284194Sdelphijprivate int parse_strength(struct magic_set *, struct magic_entry *, const char *); 151284194Sdelphijprivate int parse_apple(struct magic_set *, struct magic_entry *, const char *); 152284194Sdelphij 153284194Sdelphij 154284194Sdelphijprivate size_t magicsize = sizeof(struct magic); 155284194Sdelphij 156284194Sdelphijprivate const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc"; 157284194Sdelphij 158284194Sdelphijprivate struct { 159284194Sdelphij const char *name; 160284194Sdelphij size_t len; 161284194Sdelphij int (*fun)(struct magic_set *, struct magic_entry *, const char *); 162284194Sdelphij} bang[] = { 163284194Sdelphij#define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name } 164284194Sdelphij DECLARE_FIELD(mime), 165284194Sdelphij DECLARE_FIELD(apple), 166284194Sdelphij DECLARE_FIELD(strength), 167284194Sdelphij#undef DECLARE_FIELD 168284194Sdelphij { NULL, 0, NULL } 169284194Sdelphij}; 170284194Sdelphij 171284194Sdelphij#ifdef COMPILE_ONLY 172284194Sdelphij 173284194Sdelphijint main(int, char *[]); 174284194Sdelphij 175284194Sdelphijint 176284194Sdelphijmain(int argc, char *argv[]) 177284194Sdelphij{ 178284194Sdelphij int ret; 179284194Sdelphij struct magic_set *ms; 180284194Sdelphij char *progname; 181284194Sdelphij 182284194Sdelphij if ((progname = strrchr(argv[0], '/')) != NULL) 183284194Sdelphij progname++; 184284194Sdelphij else 185284194Sdelphij progname = argv[0]; 186284194Sdelphij 187284194Sdelphij if (argc != 2) { 188284194Sdelphij (void)fprintf(stderr, "Usage: %s file\n", progname); 189284194Sdelphij return 1; 190284194Sdelphij } 191284194Sdelphij 192284194Sdelphij if ((ms = magic_open(MAGIC_CHECK)) == NULL) { 193284194Sdelphij (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); 194284194Sdelphij return 1; 195284194Sdelphij } 196284194Sdelphij ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0; 197284194Sdelphij if (ret == 1) 198284194Sdelphij (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms)); 199284194Sdelphij magic_close(ms); 200284194Sdelphij return ret; 201284194Sdelphij} 202284194Sdelphij#endif /* COMPILE_ONLY */ 203284194Sdelphij 204284194Sdelphijstruct type_tbl_s { 205284194Sdelphij const char name[16]; 206284194Sdelphij const size_t len; 207284194Sdelphij const int type; 208284194Sdelphij const int format; 209284194Sdelphij}; 210284194Sdelphij 211284194Sdelphij/* 212284194Sdelphij * XXX - the actual Single UNIX Specification says that "long" means "long", 213284194Sdelphij * as in the C data type, but we treat it as meaning "4-byte integer". 214284194Sdelphij * Given that the OS X version of file 5.04 did the same, I guess that passes 215284194Sdelphij * the actual test; having "long" be dependent on how big a "long" is on 216284194Sdelphij * the machine running "file" is silly. 217284194Sdelphij */ 218284194Sdelphijstatic const struct type_tbl_s type_tbl[] = { 219284194Sdelphij# define XX(s) s, (sizeof(s) - 1) 220284194Sdelphij# define XX_NULL "", 0 221284194Sdelphij { XX("invalid"), FILE_INVALID, FILE_FMT_NONE }, 222284194Sdelphij { XX("byte"), FILE_BYTE, FILE_FMT_NUM }, 223284194Sdelphij { XX("short"), FILE_SHORT, FILE_FMT_NUM }, 224284194Sdelphij { XX("default"), FILE_DEFAULT, FILE_FMT_NONE }, 225284194Sdelphij { XX("long"), FILE_LONG, FILE_FMT_NUM }, 226284194Sdelphij { XX("string"), FILE_STRING, FILE_FMT_STR }, 227284194Sdelphij { XX("date"), FILE_DATE, FILE_FMT_STR }, 228284194Sdelphij { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM }, 229284194Sdelphij { XX("belong"), FILE_BELONG, FILE_FMT_NUM }, 230284194Sdelphij { XX("bedate"), FILE_BEDATE, FILE_FMT_STR }, 231284194Sdelphij { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM }, 232284194Sdelphij { XX("lelong"), FILE_LELONG, FILE_FMT_NUM }, 233284194Sdelphij { XX("ledate"), FILE_LEDATE, FILE_FMT_STR }, 234284194Sdelphij { XX("pstring"), FILE_PSTRING, FILE_FMT_STR }, 235284194Sdelphij { XX("ldate"), FILE_LDATE, FILE_FMT_STR }, 236284194Sdelphij { XX("beldate"), FILE_BELDATE, FILE_FMT_STR }, 237284194Sdelphij { XX("leldate"), FILE_LELDATE, FILE_FMT_STR }, 238284194Sdelphij { XX("regex"), FILE_REGEX, FILE_FMT_STR }, 239284194Sdelphij { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR }, 240284194Sdelphij { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR }, 241284194Sdelphij { XX("search"), FILE_SEARCH, FILE_FMT_STR }, 242284194Sdelphij { XX("medate"), FILE_MEDATE, FILE_FMT_STR }, 243284194Sdelphij { XX("meldate"), FILE_MELDATE, FILE_FMT_STR }, 244284194Sdelphij { XX("melong"), FILE_MELONG, FILE_FMT_NUM }, 245284194Sdelphij { XX("quad"), FILE_QUAD, FILE_FMT_QUAD }, 246284194Sdelphij { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD }, 247284194Sdelphij { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD }, 248284194Sdelphij { XX("qdate"), FILE_QDATE, FILE_FMT_STR }, 249284194Sdelphij { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR }, 250284194Sdelphij { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR }, 251284194Sdelphij { XX("qldate"), FILE_QLDATE, FILE_FMT_STR }, 252284194Sdelphij { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR }, 253284194Sdelphij { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR }, 254284194Sdelphij { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT }, 255284194Sdelphij { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT }, 256284194Sdelphij { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT }, 257284194Sdelphij { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE }, 258284194Sdelphij { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE }, 259284194Sdelphij { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE }, 260284194Sdelphij { XX("leid3"), FILE_LEID3, FILE_FMT_NUM }, 261284194Sdelphij { XX("beid3"), FILE_BEID3, FILE_FMT_NUM }, 262284194Sdelphij { XX("indirect"), FILE_INDIRECT, FILE_FMT_NUM }, 263284194Sdelphij { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR }, 264284194Sdelphij { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR }, 265284194Sdelphij { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR }, 266284194Sdelphij { XX("name"), FILE_NAME, FILE_FMT_NONE }, 267284194Sdelphij { XX("use"), FILE_USE, FILE_FMT_NONE }, 268284194Sdelphij { XX("clear"), FILE_CLEAR, FILE_FMT_NONE }, 269284194Sdelphij { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 270284194Sdelphij}; 271284194Sdelphij 272284194Sdelphij/* 273284194Sdelphij * These are not types, and cannot be preceded by "u" to make them 274284194Sdelphij * unsigned. 275284194Sdelphij */ 276284194Sdelphijstatic const struct type_tbl_s special_tbl[] = { 277284194Sdelphij { XX("name"), FILE_NAME, FILE_FMT_STR }, 278284194Sdelphij { XX("use"), FILE_USE, FILE_FMT_STR }, 279284194Sdelphij { XX_NULL, FILE_INVALID, FILE_FMT_NONE }, 280284194Sdelphij}; 281284194Sdelphij# undef XX 282284194Sdelphij# undef XX_NULL 283284194Sdelphij 284284194Sdelphijprivate int 285284194Sdelphijget_type(const struct type_tbl_s *tbl, const char *l, const char **t) 286284194Sdelphij{ 287284194Sdelphij const struct type_tbl_s *p; 288284194Sdelphij 289284194Sdelphij for (p = tbl; p->len; p++) { 290284194Sdelphij if (strncmp(l, p->name, p->len) == 0) { 291284194Sdelphij if (t) 292284194Sdelphij *t = l + p->len; 293284194Sdelphij break; 294284194Sdelphij } 295284194Sdelphij } 296284194Sdelphij return p->type; 297284194Sdelphij} 298284194Sdelphij 299284194Sdelphijprivate int 300284194Sdelphijget_standard_integer_type(const char *l, const char **t) 301284194Sdelphij{ 302284194Sdelphij int type; 303284194Sdelphij 304284194Sdelphij if (isalpha((unsigned char)l[1])) { 305284194Sdelphij switch (l[1]) { 306284194Sdelphij case 'C': 307284194Sdelphij /* "dC" and "uC" */ 308284194Sdelphij type = FILE_BYTE; 309284194Sdelphij break; 310284194Sdelphij case 'S': 311284194Sdelphij /* "dS" and "uS" */ 312284194Sdelphij type = FILE_SHORT; 313284194Sdelphij break; 314284194Sdelphij case 'I': 315284194Sdelphij case 'L': 316284194Sdelphij /* 317284194Sdelphij * "dI", "dL", "uI", and "uL". 318284194Sdelphij * 319284194Sdelphij * XXX - the actual Single UNIX Specification says 320284194Sdelphij * that "L" means "long", as in the C data type, 321284194Sdelphij * but we treat it as meaning "4-byte integer". 322284194Sdelphij * Given that the OS X version of file 5.04 did 323284194Sdelphij * the same, I guess that passes the actual SUS 324284194Sdelphij * validation suite; having "dL" be dependent on 325284194Sdelphij * how big a "long" is on the machine running 326284194Sdelphij * "file" is silly. 327284194Sdelphij */ 328284194Sdelphij type = FILE_LONG; 329284194Sdelphij break; 330284194Sdelphij case 'Q': 331284194Sdelphij /* "dQ" and "uQ" */ 332284194Sdelphij type = FILE_QUAD; 333284194Sdelphij break; 334284194Sdelphij default: 335284194Sdelphij /* "d{anything else}", "u{anything else}" */ 336284194Sdelphij return FILE_INVALID; 337284194Sdelphij } 338284194Sdelphij l += 2; 339284194Sdelphij } else if (isdigit((unsigned char)l[1])) { 340284194Sdelphij /* 341284194Sdelphij * "d{num}" and "u{num}"; we only support {num} values 342284194Sdelphij * of 1, 2, 4, and 8 - the Single UNIX Specification 343284194Sdelphij * doesn't say anything about whether arbitrary 344284194Sdelphij * values should be supported, but both the Solaris 10 345284194Sdelphij * and OS X Mountain Lion versions of file passed the 346284194Sdelphij * Single UNIX Specification validation suite, and 347284194Sdelphij * neither of them support values bigger than 8 or 348284194Sdelphij * non-power-of-2 values. 349284194Sdelphij */ 350284194Sdelphij if (isdigit((unsigned char)l[2])) { 351284194Sdelphij /* Multi-digit, so > 9 */ 352284194Sdelphij return FILE_INVALID; 353284194Sdelphij } 354284194Sdelphij switch (l[1]) { 355284194Sdelphij case '1': 356284194Sdelphij type = FILE_BYTE; 357284194Sdelphij break; 358284194Sdelphij case '2': 359284194Sdelphij type = FILE_SHORT; 360284194Sdelphij break; 361284194Sdelphij case '4': 362284194Sdelphij type = FILE_LONG; 363284194Sdelphij break; 364284194Sdelphij case '8': 365284194Sdelphij type = FILE_QUAD; 366284194Sdelphij break; 367284194Sdelphij default: 368284194Sdelphij /* XXX - what about 3, 5, 6, or 7? */ 369284194Sdelphij return FILE_INVALID; 370284194Sdelphij } 371284194Sdelphij l += 2; 372284194Sdelphij } else { 373284194Sdelphij /* 374284194Sdelphij * "d" or "u" by itself. 375284194Sdelphij */ 376284194Sdelphij type = FILE_LONG; 377284194Sdelphij ++l; 378284194Sdelphij } 379284194Sdelphij if (t) 380284194Sdelphij *t = l; 381284194Sdelphij return type; 382284194Sdelphij} 383284194Sdelphij 384284194Sdelphijprivate void 385284194Sdelphijinit_file_tables(void) 386284194Sdelphij{ 387284194Sdelphij static int done = 0; 388284194Sdelphij const struct type_tbl_s *p; 389284194Sdelphij 390284194Sdelphij if (done) 391284194Sdelphij return; 392284194Sdelphij done++; 393284194Sdelphij 394284194Sdelphij for (p = type_tbl; p->len; p++) { 395284194Sdelphij assert(p->type < FILE_NAMES_SIZE); 396284194Sdelphij file_names[p->type] = p->name; 397284194Sdelphij file_formats[p->type] = p->format; 398284194Sdelphij } 399284194Sdelphij assert(p - type_tbl == FILE_NAMES_SIZE); 400284194Sdelphij} 401284194Sdelphij 402284194Sdelphijprivate int 403284194Sdelphijadd_mlist(struct mlist *mlp, struct magic_map *map, size_t idx) 404284194Sdelphij{ 405284194Sdelphij struct mlist *ml; 406284194Sdelphij 407284194Sdelphij mlp->map = idx == 0 ? map : NULL; 408284194Sdelphij if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 409284194Sdelphij return -1; 410284194Sdelphij 411284194Sdelphij ml->map = NULL; 412284194Sdelphij ml->magic = map->magic[idx]; 413284194Sdelphij ml->nmagic = map->nmagic[idx]; 414284194Sdelphij 415284194Sdelphij mlp->prev->next = ml; 416284194Sdelphij ml->prev = mlp->prev; 417284194Sdelphij ml->next = mlp; 418284194Sdelphij mlp->prev = ml; 419284194Sdelphij return 0; 420284194Sdelphij} 421284194Sdelphij 422284194Sdelphij/* 423284194Sdelphij * Handle one file or directory. 424284194Sdelphij */ 425284194Sdelphijprivate int 426284194Sdelphijapprentice_1(struct magic_set *ms, const char *fn, int action) 427284194Sdelphij{ 428284194Sdelphij struct magic_map *map; 429284194Sdelphij#ifndef COMPILE_ONLY 430284194Sdelphij struct mlist *ml; 431284194Sdelphij size_t i; 432284194Sdelphij#endif 433284194Sdelphij 434284194Sdelphij if (magicsize != FILE_MAGICSIZE) { 435284194Sdelphij file_error(ms, 0, "magic element size %lu != %lu", 436284194Sdelphij (unsigned long)sizeof(*map->magic[0]), 437284194Sdelphij (unsigned long)FILE_MAGICSIZE); 438284194Sdelphij return -1; 439284194Sdelphij } 440284194Sdelphij 441284194Sdelphij if (action == FILE_COMPILE) { 442284194Sdelphij map = apprentice_load(ms, fn, action); 443284194Sdelphij if (map == NULL) 444284194Sdelphij return -1; 445284194Sdelphij return apprentice_compile(ms, map, fn); 446284194Sdelphij } 447284194Sdelphij 448284194Sdelphij#ifndef COMPILE_ONLY 449284194Sdelphij map = apprentice_map(ms, fn); 450284194Sdelphij if (map == NULL) { 451284194Sdelphij if (ms->flags & MAGIC_CHECK) 452284194Sdelphij file_magwarn(ms, "using regular magic file `%s'", fn); 453284194Sdelphij map = apprentice_load(ms, fn, action); 454284194Sdelphij if (map == NULL) 455284194Sdelphij return -1; 456284194Sdelphij } 457284194Sdelphij 458284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 459284194Sdelphij if (add_mlist(ms->mlist[i], map, i) == -1) { 460284194Sdelphij file_oomem(ms, sizeof(*ml)); 461284194Sdelphij goto fail; 462284194Sdelphij } 463284194Sdelphij } 464284194Sdelphij 465284194Sdelphij if (action == FILE_LIST) { 466284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 467284194Sdelphij printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n", 468284194Sdelphij i); 469284194Sdelphij apprentice_list(ms->mlist[i], BINTEST); 470284194Sdelphij printf("Text patterns:\n"); 471284194Sdelphij apprentice_list(ms->mlist[i], TEXTTEST); 472284194Sdelphij } 473284194Sdelphij } 474284194Sdelphij return 0; 475284194Sdelphijfail: 476284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 477284194Sdelphij mlist_free(ms->mlist[i]); 478284194Sdelphij ms->mlist[i] = NULL; 479284194Sdelphij } 480284194Sdelphij return -1; 481284194Sdelphij#else 482284194Sdelphij return 0; 483284194Sdelphij#endif /* COMPILE_ONLY */ 484284194Sdelphij} 485284194Sdelphij 486284194Sdelphijprotected void 487284194Sdelphijfile_ms_free(struct magic_set *ms) 488284194Sdelphij{ 489284194Sdelphij size_t i; 490284194Sdelphij if (ms == NULL) 491284194Sdelphij return; 492284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) 493284194Sdelphij mlist_free(ms->mlist[i]); 494284194Sdelphij free(ms->o.pbuf); 495284194Sdelphij free(ms->o.buf); 496284194Sdelphij free(ms->c.li); 497284194Sdelphij free(ms); 498284194Sdelphij} 499284194Sdelphij 500284194Sdelphijprotected struct magic_set * 501284194Sdelphijfile_ms_alloc(int flags) 502284194Sdelphij{ 503284194Sdelphij struct magic_set *ms; 504284194Sdelphij size_t i, len; 505284194Sdelphij 506284194Sdelphij if ((ms = CAST(struct magic_set *, calloc((size_t)1, 507284194Sdelphij sizeof(struct magic_set)))) == NULL) 508284194Sdelphij return NULL; 509284194Sdelphij 510284194Sdelphij if (magic_setflags(ms, flags) == -1) { 511284194Sdelphij errno = EINVAL; 512284194Sdelphij goto free; 513284194Sdelphij } 514284194Sdelphij 515284194Sdelphij ms->o.buf = ms->o.pbuf = NULL; 516284194Sdelphij len = (ms->c.len = 10) * sizeof(*ms->c.li); 517284194Sdelphij 518284194Sdelphij if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 519284194Sdelphij goto free; 520284194Sdelphij 521284194Sdelphij ms->event_flags = 0; 522284194Sdelphij ms->error = -1; 523284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) 524284194Sdelphij ms->mlist[i] = NULL; 525284194Sdelphij ms->file = "unknown"; 526284194Sdelphij ms->line = 0; 527284194Sdelphij ms->indir_max = FILE_INDIR_MAX; 528284194Sdelphij ms->name_max = FILE_NAME_MAX; 529284194Sdelphij ms->elf_shnum_max = FILE_ELF_SHNUM_MAX; 530284194Sdelphij ms->elf_phnum_max = FILE_ELF_PHNUM_MAX; 531284194Sdelphij ms->elf_notes_max = FILE_ELF_NOTES_MAX; 532284194Sdelphij return ms; 533284194Sdelphijfree: 534284194Sdelphij free(ms); 535284194Sdelphij return NULL; 536284194Sdelphij} 537284194Sdelphij 538284194Sdelphijprivate void 539284194Sdelphijapprentice_unmap(struct magic_map *map) 540284194Sdelphij{ 541284194Sdelphij if (map == NULL) 542284194Sdelphij return; 543284194Sdelphij 544284194Sdelphij switch (map->type) { 545284194Sdelphij#ifdef QUICK 546284194Sdelphij case MAP_TYPE_MMAP: 547284194Sdelphij if (map->p) 548284194Sdelphij (void)munmap(map->p, map->len); 549284194Sdelphij break; 550284194Sdelphij#endif 551284194Sdelphij case MAP_TYPE_MALLOC: 552284194Sdelphij free(map->p); 553284194Sdelphij break; 554284194Sdelphij case MAP_TYPE_USER: 555284194Sdelphij break; 556284194Sdelphij default: 557284194Sdelphij abort(); 558284194Sdelphij } 559284194Sdelphij free(map); 560284194Sdelphij} 561284194Sdelphij 562284194Sdelphijprivate struct mlist * 563284194Sdelphijmlist_alloc(void) 564284194Sdelphij{ 565284194Sdelphij struct mlist *mlist; 566284194Sdelphij if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 567284194Sdelphij return NULL; 568284194Sdelphij } 569284194Sdelphij mlist->next = mlist->prev = mlist; 570284194Sdelphij return mlist; 571284194Sdelphij} 572284194Sdelphij 573284194Sdelphijprivate void 574284194Sdelphijmlist_free(struct mlist *mlist) 575284194Sdelphij{ 576284194Sdelphij struct mlist *ml, *next; 577284194Sdelphij 578284194Sdelphij if (mlist == NULL) 579284194Sdelphij return; 580284194Sdelphij 581284194Sdelphij ml = mlist->next; 582284194Sdelphij for (ml = mlist->next; (next = ml->next) != NULL; ml = next) { 583284194Sdelphij if (ml->map) 584284194Sdelphij apprentice_unmap(ml->map); 585284194Sdelphij free(ml); 586284194Sdelphij if (ml == mlist) 587284194Sdelphij break; 588284194Sdelphij } 589284194Sdelphij} 590284194Sdelphij 591284194Sdelphij#ifndef COMPILE_ONLY 592284194Sdelphij/* void **bufs: an array of compiled magic files */ 593284194Sdelphijprotected int 594284194Sdelphijbuffer_apprentice(struct magic_set *ms, struct magic **bufs, 595284194Sdelphij size_t *sizes, size_t nbufs) 596284194Sdelphij{ 597284194Sdelphij size_t i, j; 598284194Sdelphij struct mlist *ml; 599284194Sdelphij struct magic_map *map; 600284194Sdelphij 601284194Sdelphij if (nbufs == 0) 602284194Sdelphij return -1; 603284194Sdelphij 604284194Sdelphij if (ms->mlist[0] != NULL) 605284194Sdelphij file_reset(ms); 606284194Sdelphij 607284194Sdelphij init_file_tables(); 608284194Sdelphij 609284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 610284194Sdelphij mlist_free(ms->mlist[i]); 611284194Sdelphij if ((ms->mlist[i] = mlist_alloc()) == NULL) { 612284194Sdelphij file_oomem(ms, sizeof(*ms->mlist[i])); 613284194Sdelphij goto fail; 614284194Sdelphij } 615284194Sdelphij } 616284194Sdelphij 617284194Sdelphij for (i = 0; i < nbufs; i++) { 618284194Sdelphij map = apprentice_buf(ms, bufs[i], sizes[i]); 619284194Sdelphij if (map == NULL) 620284194Sdelphij goto fail; 621284194Sdelphij 622284194Sdelphij for (j = 0; j < MAGIC_SETS; j++) { 623284194Sdelphij if (add_mlist(ms->mlist[j], map, j) == -1) { 624284194Sdelphij file_oomem(ms, sizeof(*ml)); 625284194Sdelphij goto fail; 626284194Sdelphij } 627284194Sdelphij } 628284194Sdelphij } 629284194Sdelphij 630284194Sdelphij return 0; 631284194Sdelphijfail: 632284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 633284194Sdelphij mlist_free(ms->mlist[i]); 634284194Sdelphij ms->mlist[i] = NULL; 635284194Sdelphij } 636284194Sdelphij return -1; 637284194Sdelphij} 638284194Sdelphij#endif 639284194Sdelphij 640284194Sdelphij/* const char *fn: list of magic files and directories */ 641284194Sdelphijprotected int 642284194Sdelphijfile_apprentice(struct magic_set *ms, const char *fn, int action) 643284194Sdelphij{ 644284194Sdelphij char *p, *mfn; 645284194Sdelphij int file_err, errs = -1; 646284194Sdelphij size_t i; 647284194Sdelphij 648284194Sdelphij if (ms->mlist[0] != NULL) 649284194Sdelphij file_reset(ms); 650284194Sdelphij 651284194Sdelphij if ((fn = magic_getpath(fn, action)) == NULL) 652284194Sdelphij return -1; 653284194Sdelphij 654284194Sdelphij init_file_tables(); 655284194Sdelphij 656284194Sdelphij if ((mfn = strdup(fn)) == NULL) { 657284194Sdelphij file_oomem(ms, strlen(fn)); 658284194Sdelphij return -1; 659284194Sdelphij } 660284194Sdelphij 661284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 662284194Sdelphij mlist_free(ms->mlist[i]); 663284194Sdelphij if ((ms->mlist[i] = mlist_alloc()) == NULL) { 664284194Sdelphij file_oomem(ms, sizeof(*ms->mlist[i])); 665284194Sdelphij while (i-- > 0) { 666284194Sdelphij mlist_free(ms->mlist[i]); 667284194Sdelphij ms->mlist[i] = NULL; 668284194Sdelphij } 669284194Sdelphij free(mfn); 670284194Sdelphij return -1; 671284194Sdelphij } 672284194Sdelphij } 673284194Sdelphij fn = mfn; 674284194Sdelphij 675284194Sdelphij while (fn) { 676284194Sdelphij p = strchr(fn, PATHSEP); 677284194Sdelphij if (p) 678284194Sdelphij *p++ = '\0'; 679284194Sdelphij if (*fn == '\0') 680284194Sdelphij break; 681284194Sdelphij file_err = apprentice_1(ms, fn, action); 682284194Sdelphij errs = MAX(errs, file_err); 683284194Sdelphij fn = p; 684284194Sdelphij } 685284194Sdelphij 686284194Sdelphij free(mfn); 687284194Sdelphij 688284194Sdelphij if (errs == -1) { 689284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 690284194Sdelphij mlist_free(ms->mlist[i]); 691284194Sdelphij ms->mlist[i] = NULL; 692284194Sdelphij } 693284194Sdelphij file_error(ms, 0, "could not find any valid magic files!"); 694284194Sdelphij return -1; 695284194Sdelphij } 696284194Sdelphij 697284194Sdelphij#if 0 698284194Sdelphij /* 699284194Sdelphij * Always leave the database loaded 700284194Sdelphij */ 701284194Sdelphij if (action == FILE_LOAD) 702284194Sdelphij return 0; 703284194Sdelphij 704284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 705284194Sdelphij mlist_free(ms->mlist[i]); 706284194Sdelphij ms->mlist[i] = NULL; 707284194Sdelphij } 708284194Sdelphij#endif 709284194Sdelphij 710284194Sdelphij switch (action) { 711284194Sdelphij case FILE_LOAD: 712284194Sdelphij case FILE_COMPILE: 713284194Sdelphij case FILE_CHECK: 714284194Sdelphij case FILE_LIST: 715284194Sdelphij return 0; 716284194Sdelphij default: 717284194Sdelphij file_error(ms, 0, "Invalid action %d", action); 718284194Sdelphij return -1; 719284194Sdelphij } 720284194Sdelphij} 721284194Sdelphij 722284194Sdelphij/* 723284194Sdelphij * Compute the real length of a magic expression, for the purposes 724284194Sdelphij * of determining how "strong" a magic expression is (approximating 725284194Sdelphij * how specific its matches are): 726284194Sdelphij * - magic characters count 0 unless escaped. 727284194Sdelphij * - [] expressions count 1 728284194Sdelphij * - {} expressions count 0 729284194Sdelphij * - regular characters or escaped magic characters count 1 730284194Sdelphij * - 0 length expressions count as one 731284194Sdelphij */ 732284194Sdelphijprivate size_t 733284194Sdelphijnonmagic(const char *str) 734284194Sdelphij{ 735284194Sdelphij const char *p; 736284194Sdelphij size_t rv = 0; 737284194Sdelphij 738284194Sdelphij for (p = str; *p; p++) 739284194Sdelphij switch (*p) { 740284194Sdelphij case '\\': /* Escaped anything counts 1 */ 741284194Sdelphij if (!*++p) 742284194Sdelphij p--; 743284194Sdelphij rv++; 744284194Sdelphij continue; 745284194Sdelphij case '?': /* Magic characters count 0 */ 746284194Sdelphij case '*': 747284194Sdelphij case '.': 748284194Sdelphij case '+': 749284194Sdelphij case '^': 750284194Sdelphij case '$': 751284194Sdelphij continue; 752284194Sdelphij case '[': /* Bracketed expressions count 1 the ']' */ 753284194Sdelphij while (*p && *p != ']') 754284194Sdelphij p++; 755284194Sdelphij p--; 756284194Sdelphij continue; 757284194Sdelphij case '{': /* Braced expressions count 0 */ 758284194Sdelphij while (*p && *p != '}') 759284194Sdelphij p++; 760284194Sdelphij if (!*p) 761284194Sdelphij p--; 762284194Sdelphij continue; 763284194Sdelphij default: /* Anything else counts 1 */ 764284194Sdelphij rv++; 765284194Sdelphij continue; 766284194Sdelphij } 767284194Sdelphij 768284194Sdelphij return rv == 0 ? 1 : rv; /* Return at least 1 */ 769284194Sdelphij} 770284194Sdelphij 771284194Sdelphij/* 772284194Sdelphij * Get weight of this magic entry, for sorting purposes. 773284194Sdelphij */ 774284194Sdelphijprivate size_t 775284194Sdelphijapprentice_magic_strength(const struct magic *m) 776284194Sdelphij{ 777284194Sdelphij#define MULT 10 778284194Sdelphij size_t v, val = 2 * MULT; /* baseline strength */ 779284194Sdelphij 780284194Sdelphij switch (m->type) { 781284194Sdelphij case FILE_DEFAULT: /* make sure this sorts last */ 782284194Sdelphij if (m->factor_op != FILE_FACTOR_OP_NONE) 783284194Sdelphij abort(); 784284194Sdelphij return 0; 785284194Sdelphij 786284194Sdelphij case FILE_BYTE: 787284194Sdelphij val += 1 * MULT; 788284194Sdelphij break; 789284194Sdelphij 790284194Sdelphij case FILE_SHORT: 791284194Sdelphij case FILE_LESHORT: 792284194Sdelphij case FILE_BESHORT: 793284194Sdelphij val += 2 * MULT; 794284194Sdelphij break; 795284194Sdelphij 796284194Sdelphij case FILE_LONG: 797284194Sdelphij case FILE_LELONG: 798284194Sdelphij case FILE_BELONG: 799284194Sdelphij case FILE_MELONG: 800284194Sdelphij val += 4 * MULT; 801284194Sdelphij break; 802284194Sdelphij 803284194Sdelphij case FILE_PSTRING: 804284194Sdelphij case FILE_STRING: 805284194Sdelphij val += m->vallen * MULT; 806284194Sdelphij break; 807284194Sdelphij 808284194Sdelphij case FILE_BESTRING16: 809284194Sdelphij case FILE_LESTRING16: 810284194Sdelphij val += m->vallen * MULT / 2; 811284194Sdelphij break; 812284194Sdelphij 813284194Sdelphij case FILE_SEARCH: 814284194Sdelphij val += m->vallen * MAX(MULT / m->vallen, 1); 815284194Sdelphij break; 816284194Sdelphij 817284194Sdelphij case FILE_REGEX: 818284194Sdelphij v = nonmagic(m->value.s); 819284194Sdelphij val += v * MAX(MULT / v, 1); 820284194Sdelphij break; 821284194Sdelphij 822284194Sdelphij case FILE_DATE: 823284194Sdelphij case FILE_LEDATE: 824284194Sdelphij case FILE_BEDATE: 825284194Sdelphij case FILE_MEDATE: 826284194Sdelphij case FILE_LDATE: 827284194Sdelphij case FILE_LELDATE: 828284194Sdelphij case FILE_BELDATE: 829284194Sdelphij case FILE_MELDATE: 830284194Sdelphij case FILE_FLOAT: 831284194Sdelphij case FILE_BEFLOAT: 832284194Sdelphij case FILE_LEFLOAT: 833284194Sdelphij val += 4 * MULT; 834284194Sdelphij break; 835284194Sdelphij 836284194Sdelphij case FILE_QUAD: 837284194Sdelphij case FILE_BEQUAD: 838284194Sdelphij case FILE_LEQUAD: 839284194Sdelphij case FILE_QDATE: 840284194Sdelphij case FILE_LEQDATE: 841284194Sdelphij case FILE_BEQDATE: 842284194Sdelphij case FILE_QLDATE: 843284194Sdelphij case FILE_LEQLDATE: 844284194Sdelphij case FILE_BEQLDATE: 845284194Sdelphij case FILE_QWDATE: 846284194Sdelphij case FILE_LEQWDATE: 847284194Sdelphij case FILE_BEQWDATE: 848284194Sdelphij case FILE_DOUBLE: 849284194Sdelphij case FILE_BEDOUBLE: 850284194Sdelphij case FILE_LEDOUBLE: 851284194Sdelphij val += 8 * MULT; 852284194Sdelphij break; 853284194Sdelphij 854284194Sdelphij case FILE_INDIRECT: 855284194Sdelphij case FILE_NAME: 856284194Sdelphij case FILE_USE: 857284194Sdelphij break; 858284194Sdelphij 859284194Sdelphij default: 860284194Sdelphij (void)fprintf(stderr, "Bad type %d\n", m->type); 861284194Sdelphij abort(); 862284194Sdelphij } 863284194Sdelphij 864284194Sdelphij switch (m->reln) { 865284194Sdelphij case 'x': /* matches anything penalize */ 866284194Sdelphij case '!': /* matches almost anything penalize */ 867284194Sdelphij val = 0; 868284194Sdelphij break; 869284194Sdelphij 870284194Sdelphij case '=': /* Exact match, prefer */ 871284194Sdelphij val += MULT; 872284194Sdelphij break; 873284194Sdelphij 874284194Sdelphij case '>': 875284194Sdelphij case '<': /* comparison match reduce strength */ 876284194Sdelphij val -= 2 * MULT; 877284194Sdelphij break; 878284194Sdelphij 879284194Sdelphij case '^': 880284194Sdelphij case '&': /* masking bits, we could count them too */ 881284194Sdelphij val -= MULT; 882284194Sdelphij break; 883284194Sdelphij 884284194Sdelphij default: 885284194Sdelphij (void)fprintf(stderr, "Bad relation %c\n", m->reln); 886284194Sdelphij abort(); 887284194Sdelphij } 888284194Sdelphij 889284194Sdelphij if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */ 890284194Sdelphij val = 1; 891284194Sdelphij 892284194Sdelphij switch (m->factor_op) { 893284194Sdelphij case FILE_FACTOR_OP_NONE: 894284194Sdelphij break; 895284194Sdelphij case FILE_FACTOR_OP_PLUS: 896284194Sdelphij val += m->factor; 897284194Sdelphij break; 898284194Sdelphij case FILE_FACTOR_OP_MINUS: 899284194Sdelphij val -= m->factor; 900284194Sdelphij break; 901284194Sdelphij case FILE_FACTOR_OP_TIMES: 902284194Sdelphij val *= m->factor; 903284194Sdelphij break; 904284194Sdelphij case FILE_FACTOR_OP_DIV: 905284194Sdelphij val /= m->factor; 906284194Sdelphij break; 907284194Sdelphij default: 908284194Sdelphij abort(); 909284194Sdelphij } 910284194Sdelphij 911284194Sdelphij /* 912284194Sdelphij * Magic entries with no description get a bonus because they depend 913284194Sdelphij * on subsequent magic entries to print something. 914284194Sdelphij */ 915284194Sdelphij if (m->desc[0] == '\0') 916284194Sdelphij val++; 917284194Sdelphij return val; 918284194Sdelphij} 919284194Sdelphij 920284194Sdelphij/* 921284194Sdelphij * Sort callback for sorting entries by "strength" (basically length) 922284194Sdelphij */ 923284194Sdelphijprivate int 924284194Sdelphijapprentice_sort(const void *a, const void *b) 925284194Sdelphij{ 926284194Sdelphij const struct magic_entry *ma = CAST(const struct magic_entry *, a); 927284194Sdelphij const struct magic_entry *mb = CAST(const struct magic_entry *, b); 928284194Sdelphij size_t sa = apprentice_magic_strength(ma->mp); 929284194Sdelphij size_t sb = apprentice_magic_strength(mb->mp); 930284194Sdelphij if (sa == sb) 931284194Sdelphij return 0; 932284194Sdelphij else if (sa > sb) 933284194Sdelphij return -1; 934284194Sdelphij else 935284194Sdelphij return 1; 936284194Sdelphij} 937284194Sdelphij 938284194Sdelphij/* 939284194Sdelphij * Shows sorted patterns list in the order which is used for the matching 940284194Sdelphij */ 941284194Sdelphijprivate void 942284194Sdelphijapprentice_list(struct mlist *mlist, int mode) 943284194Sdelphij{ 944284194Sdelphij uint32_t magindex = 0; 945284194Sdelphij struct mlist *ml; 946284194Sdelphij for (ml = mlist->next; ml != mlist; ml = ml->next) { 947284194Sdelphij for (magindex = 0; magindex < ml->nmagic; magindex++) { 948284194Sdelphij struct magic *m = &ml->magic[magindex]; 949284194Sdelphij if ((m->flag & mode) != mode) { 950284194Sdelphij /* Skip sub-tests */ 951284194Sdelphij while (magindex + 1 < ml->nmagic && 952284194Sdelphij ml->magic[magindex + 1].cont_level != 0) 953284194Sdelphij ++magindex; 954284194Sdelphij continue; /* Skip to next top-level test*/ 955284194Sdelphij } 956284194Sdelphij 957284194Sdelphij /* 958284194Sdelphij * Try to iterate over the tree until we find item with 959284194Sdelphij * description/mimetype. 960284194Sdelphij */ 961284194Sdelphij while (magindex + 1 < ml->nmagic && 962284194Sdelphij ml->magic[magindex + 1].cont_level != 0 && 963284194Sdelphij *ml->magic[magindex].desc == '\0' && 964284194Sdelphij *ml->magic[magindex].mimetype == '\0') 965284194Sdelphij magindex++; 966284194Sdelphij 967284194Sdelphij printf("Strength = %3" SIZE_T_FORMAT "u : %s [%s]\n", 968284194Sdelphij apprentice_magic_strength(m), 969284194Sdelphij ml->magic[magindex].desc, 970284194Sdelphij ml->magic[magindex].mimetype); 971284194Sdelphij } 972284194Sdelphij } 973284194Sdelphij} 974284194Sdelphij 975284194Sdelphijprivate void 976284194Sdelphijset_test_type(struct magic *mstart, struct magic *m) 977284194Sdelphij{ 978284194Sdelphij switch (m->type) { 979284194Sdelphij case FILE_BYTE: 980284194Sdelphij case FILE_SHORT: 981284194Sdelphij case FILE_LONG: 982284194Sdelphij case FILE_DATE: 983284194Sdelphij case FILE_BESHORT: 984284194Sdelphij case FILE_BELONG: 985284194Sdelphij case FILE_BEDATE: 986284194Sdelphij case FILE_LESHORT: 987284194Sdelphij case FILE_LELONG: 988284194Sdelphij case FILE_LEDATE: 989284194Sdelphij case FILE_LDATE: 990284194Sdelphij case FILE_BELDATE: 991284194Sdelphij case FILE_LELDATE: 992284194Sdelphij case FILE_MEDATE: 993284194Sdelphij case FILE_MELDATE: 994284194Sdelphij case FILE_MELONG: 995284194Sdelphij case FILE_QUAD: 996284194Sdelphij case FILE_LEQUAD: 997284194Sdelphij case FILE_BEQUAD: 998284194Sdelphij case FILE_QDATE: 999284194Sdelphij case FILE_LEQDATE: 1000284194Sdelphij case FILE_BEQDATE: 1001284194Sdelphij case FILE_QLDATE: 1002284194Sdelphij case FILE_LEQLDATE: 1003284194Sdelphij case FILE_BEQLDATE: 1004284194Sdelphij case FILE_QWDATE: 1005284194Sdelphij case FILE_LEQWDATE: 1006284194Sdelphij case FILE_BEQWDATE: 1007284194Sdelphij case FILE_FLOAT: 1008284194Sdelphij case FILE_BEFLOAT: 1009284194Sdelphij case FILE_LEFLOAT: 1010284194Sdelphij case FILE_DOUBLE: 1011284194Sdelphij case FILE_BEDOUBLE: 1012284194Sdelphij case FILE_LEDOUBLE: 1013284194Sdelphij mstart->flag |= BINTEST; 1014284194Sdelphij break; 1015284194Sdelphij case FILE_STRING: 1016284194Sdelphij case FILE_PSTRING: 1017284194Sdelphij case FILE_BESTRING16: 1018284194Sdelphij case FILE_LESTRING16: 1019284194Sdelphij /* Allow text overrides */ 1020284194Sdelphij if (mstart->str_flags & STRING_TEXTTEST) 1021284194Sdelphij mstart->flag |= TEXTTEST; 1022284194Sdelphij else 1023284194Sdelphij mstart->flag |= BINTEST; 1024284194Sdelphij break; 1025284194Sdelphij case FILE_REGEX: 1026284194Sdelphij case FILE_SEARCH: 1027284194Sdelphij /* Check for override */ 1028284194Sdelphij if (mstart->str_flags & STRING_BINTEST) 1029284194Sdelphij mstart->flag |= BINTEST; 1030284194Sdelphij if (mstart->str_flags & STRING_TEXTTEST) 1031284194Sdelphij mstart->flag |= TEXTTEST; 1032284194Sdelphij 1033284194Sdelphij if (mstart->flag & (TEXTTEST|BINTEST)) 1034284194Sdelphij break; 1035284194Sdelphij 1036284194Sdelphij /* binary test if pattern is not text */ 1037284194Sdelphij if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL, 1038284194Sdelphij NULL) <= 0) 1039284194Sdelphij mstart->flag |= BINTEST; 1040284194Sdelphij else 1041284194Sdelphij mstart->flag |= TEXTTEST; 1042284194Sdelphij break; 1043284194Sdelphij case FILE_DEFAULT: 1044284194Sdelphij /* can't deduce anything; we shouldn't see this at the 1045284194Sdelphij top level anyway */ 1046284194Sdelphij break; 1047284194Sdelphij case FILE_INVALID: 1048284194Sdelphij default: 1049284194Sdelphij /* invalid search type, but no need to complain here */ 1050284194Sdelphij break; 1051284194Sdelphij } 1052284194Sdelphij} 1053284194Sdelphij 1054284194Sdelphijprivate int 1055284194Sdelphijaddentry(struct magic_set *ms, struct magic_entry *me, 1056284194Sdelphij struct magic_entry_set *mset) 1057284194Sdelphij{ 1058284194Sdelphij size_t i = me->mp->type == FILE_NAME ? 1 : 0; 1059284194Sdelphij if (mset[i].count == mset[i].max) { 1060284194Sdelphij struct magic_entry *mp; 1061284194Sdelphij 1062284194Sdelphij mset[i].max += ALLOC_INCR; 1063284194Sdelphij if ((mp = CAST(struct magic_entry *, 1064284194Sdelphij realloc(mset[i].me, sizeof(*mp) * mset[i].max))) == 1065284194Sdelphij NULL) { 1066284194Sdelphij file_oomem(ms, sizeof(*mp) * mset[i].max); 1067284194Sdelphij return -1; 1068284194Sdelphij } 1069284194Sdelphij (void)memset(&mp[mset[i].count], 0, sizeof(*mp) * 1070284194Sdelphij ALLOC_INCR); 1071284194Sdelphij mset[i].me = mp; 1072284194Sdelphij } 1073284194Sdelphij mset[i].me[mset[i].count++] = *me; 1074284194Sdelphij memset(me, 0, sizeof(*me)); 1075284194Sdelphij return 0; 1076284194Sdelphij} 1077284194Sdelphij 1078284194Sdelphij/* 1079284194Sdelphij * Load and parse one file. 1080284194Sdelphij */ 1081284194Sdelphijprivate void 1082284194Sdelphijload_1(struct magic_set *ms, int action, const char *fn, int *errs, 1083284194Sdelphij struct magic_entry_set *mset) 1084284194Sdelphij{ 1085284194Sdelphij size_t lineno = 0, llen = 0; 1086284194Sdelphij char *line = NULL; 1087284194Sdelphij ssize_t len; 1088284194Sdelphij struct magic_entry me; 1089284194Sdelphij 1090284194Sdelphij FILE *f = fopen(ms->file = fn, "r"); 1091284194Sdelphij if (f == NULL) { 1092284194Sdelphij if (errno != ENOENT) 1093284194Sdelphij file_error(ms, errno, "cannot read magic file `%s'", 1094284194Sdelphij fn); 1095284194Sdelphij (*errs)++; 1096284194Sdelphij return; 1097284194Sdelphij } 1098284194Sdelphij 1099284194Sdelphij memset(&me, 0, sizeof(me)); 1100284194Sdelphij /* read and parse this file */ 1101284194Sdelphij for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 1102284194Sdelphij ms->line++) { 1103284194Sdelphij if (len == 0) /* null line, garbage, etc */ 1104284194Sdelphij continue; 1105284194Sdelphij if (line[len - 1] == '\n') { 1106284194Sdelphij lineno++; 1107284194Sdelphij line[len - 1] = '\0'; /* delete newline */ 1108284194Sdelphij } 1109284194Sdelphij switch (line[0]) { 1110284194Sdelphij case '\0': /* empty, do not parse */ 1111284194Sdelphij case '#': /* comment, do not parse */ 1112284194Sdelphij continue; 1113284194Sdelphij case '!': 1114284194Sdelphij if (line[1] == ':') { 1115284194Sdelphij size_t i; 1116284194Sdelphij 1117284194Sdelphij for (i = 0; bang[i].name != NULL; i++) { 1118284194Sdelphij if ((size_t)(len - 2) > bang[i].len && 1119284194Sdelphij memcmp(bang[i].name, line + 2, 1120284194Sdelphij bang[i].len) == 0) 1121284194Sdelphij break; 1122284194Sdelphij } 1123284194Sdelphij if (bang[i].name == NULL) { 1124284194Sdelphij file_error(ms, 0, 1125284194Sdelphij "Unknown !: entry `%s'", line); 1126284194Sdelphij (*errs)++; 1127284194Sdelphij continue; 1128284194Sdelphij } 1129284194Sdelphij if (me.mp == NULL) { 1130284194Sdelphij file_error(ms, 0, 1131284194Sdelphij "No current entry for :!%s type", 1132284194Sdelphij bang[i].name); 1133284194Sdelphij (*errs)++; 1134284194Sdelphij continue; 1135284194Sdelphij } 1136284194Sdelphij if ((*bang[i].fun)(ms, &me, 1137284194Sdelphij line + bang[i].len + 2) != 0) { 1138284194Sdelphij (*errs)++; 1139284194Sdelphij continue; 1140284194Sdelphij } 1141284194Sdelphij continue; 1142284194Sdelphij } 1143284194Sdelphij /*FALLTHROUGH*/ 1144284194Sdelphij default: 1145284194Sdelphij again: 1146284194Sdelphij switch (parse(ms, &me, line, lineno, action)) { 1147284194Sdelphij case 0: 1148284194Sdelphij continue; 1149284194Sdelphij case 1: 1150284194Sdelphij (void)addentry(ms, &me, mset); 1151284194Sdelphij goto again; 1152284194Sdelphij default: 1153284194Sdelphij (*errs)++; 1154284194Sdelphij break; 1155284194Sdelphij } 1156284194Sdelphij } 1157284194Sdelphij } 1158284194Sdelphij if (me.mp) 1159284194Sdelphij (void)addentry(ms, &me, mset); 1160284194Sdelphij free(line); 1161284194Sdelphij (void)fclose(f); 1162284194Sdelphij} 1163284194Sdelphij 1164284194Sdelphij/* 1165284194Sdelphij * parse a file or directory of files 1166284194Sdelphij * const char *fn: name of magic file or directory 1167284194Sdelphij */ 1168284194Sdelphijprivate int 1169284194Sdelphijcmpstrp(const void *p1, const void *p2) 1170284194Sdelphij{ 1171284194Sdelphij return strcmp(*(char *const *)p1, *(char *const *)p2); 1172284194Sdelphij} 1173284194Sdelphij 1174284194Sdelphij 1175284194Sdelphijprivate uint32_t 1176284194Sdelphijset_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1177284194Sdelphij uint32_t starttest) 1178284194Sdelphij{ 1179284194Sdelphij static const char text[] = "text"; 1180284194Sdelphij static const char binary[] = "binary"; 1181284194Sdelphij static const size_t len = sizeof(text); 1182284194Sdelphij 1183284194Sdelphij uint32_t i = starttest; 1184284194Sdelphij 1185284194Sdelphij do { 1186284194Sdelphij set_test_type(me[starttest].mp, me[i].mp); 1187284194Sdelphij if ((ms->flags & MAGIC_DEBUG) == 0) 1188284194Sdelphij continue; 1189284194Sdelphij (void)fprintf(stderr, "%s%s%s: %s\n", 1190284194Sdelphij me[i].mp->mimetype, 1191284194Sdelphij me[i].mp->mimetype[0] == '\0' ? "" : "; ", 1192284194Sdelphij me[i].mp->desc[0] ? me[i].mp->desc : "(no description)", 1193284194Sdelphij me[i].mp->flag & BINTEST ? binary : text); 1194284194Sdelphij if (me[i].mp->flag & BINTEST) { 1195284194Sdelphij char *p = strstr(me[i].mp->desc, text); 1196284194Sdelphij if (p && (p == me[i].mp->desc || 1197284194Sdelphij isspace((unsigned char)p[-1])) && 1198284194Sdelphij (p + len - me[i].mp->desc == MAXstring 1199284194Sdelphij || (p[len] == '\0' || 1200284194Sdelphij isspace((unsigned char)p[len])))) 1201284194Sdelphij (void)fprintf(stderr, "*** Possible " 1202284194Sdelphij "binary test for text type\n"); 1203284194Sdelphij } 1204284194Sdelphij } while (++i < nme && me[i].mp->cont_level != 0); 1205284194Sdelphij return i; 1206284194Sdelphij} 1207284194Sdelphij 1208284194Sdelphijprivate void 1209284194Sdelphijset_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme) 1210284194Sdelphij{ 1211284194Sdelphij uint32_t i; 1212284194Sdelphij for (i = 0; i < nme; i++) { 1213284194Sdelphij if (me[i].mp->cont_level == 0 && 1214284194Sdelphij me[i].mp->type == FILE_DEFAULT) { 1215284194Sdelphij while (++i < nme) 1216284194Sdelphij if (me[i].mp->cont_level == 0) 1217284194Sdelphij break; 1218284194Sdelphij if (i != nme) { 1219284194Sdelphij /* XXX - Ugh! */ 1220284194Sdelphij ms->line = me[i].mp->lineno; 1221284194Sdelphij file_magwarn(ms, 1222284194Sdelphij "level 0 \"default\" did not sort last"); 1223284194Sdelphij } 1224284194Sdelphij return; 1225284194Sdelphij } 1226284194Sdelphij } 1227284194Sdelphij} 1228284194Sdelphij 1229284194Sdelphijprivate int 1230284194Sdelphijcoalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme, 1231284194Sdelphij struct magic **ma, uint32_t *nma) 1232284194Sdelphij{ 1233284194Sdelphij uint32_t i, mentrycount = 0; 1234284194Sdelphij size_t slen; 1235284194Sdelphij 1236284194Sdelphij for (i = 0; i < nme; i++) 1237284194Sdelphij mentrycount += me[i].cont_count; 1238284194Sdelphij 1239284194Sdelphij slen = sizeof(**ma) * mentrycount; 1240284194Sdelphij if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 1241284194Sdelphij file_oomem(ms, slen); 1242284194Sdelphij return -1; 1243284194Sdelphij } 1244284194Sdelphij 1245284194Sdelphij mentrycount = 0; 1246284194Sdelphij for (i = 0; i < nme; i++) { 1247284194Sdelphij (void)memcpy(*ma + mentrycount, me[i].mp, 1248284194Sdelphij me[i].cont_count * sizeof(**ma)); 1249284194Sdelphij mentrycount += me[i].cont_count; 1250284194Sdelphij } 1251284194Sdelphij *nma = mentrycount; 1252284194Sdelphij return 0; 1253284194Sdelphij} 1254284194Sdelphij 1255284194Sdelphijprivate void 1256284194Sdelphijmagic_entry_free(struct magic_entry *me, uint32_t nme) 1257284194Sdelphij{ 1258284194Sdelphij uint32_t i; 1259284194Sdelphij if (me == NULL) 1260284194Sdelphij return; 1261284194Sdelphij for (i = 0; i < nme; i++) 1262284194Sdelphij free(me[i].mp); 1263284194Sdelphij free(me); 1264284194Sdelphij} 1265284194Sdelphij 1266284194Sdelphijprivate struct magic_map * 1267284194Sdelphijapprentice_load(struct magic_set *ms, const char *fn, int action) 1268284194Sdelphij{ 1269284194Sdelphij int errs = 0; 1270284194Sdelphij uint32_t i, j; 1271284194Sdelphij size_t files = 0, maxfiles = 0; 1272284194Sdelphij char **filearr = NULL, *mfn; 1273284194Sdelphij struct stat st; 1274284194Sdelphij struct magic_map *map; 1275284194Sdelphij struct magic_entry_set mset[MAGIC_SETS]; 1276284194Sdelphij DIR *dir; 1277284194Sdelphij struct dirent *d; 1278284194Sdelphij 1279284194Sdelphij memset(mset, 0, sizeof(mset)); 1280284194Sdelphij ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 1281284194Sdelphij 1282284194Sdelphij 1283284194Sdelphij if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 1284284194Sdelphij { 1285284194Sdelphij file_oomem(ms, sizeof(*map)); 1286284194Sdelphij return NULL; 1287284194Sdelphij } 1288284194Sdelphij 1289284194Sdelphij /* print silly verbose header for USG compat. */ 1290284194Sdelphij if (action == FILE_CHECK) 1291284194Sdelphij (void)fprintf(stderr, "%s\n", usg_hdr); 1292284194Sdelphij 1293284194Sdelphij /* load directory or file */ 1294284194Sdelphij if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 1295284194Sdelphij dir = opendir(fn); 1296284194Sdelphij if (!dir) { 1297284194Sdelphij errs++; 1298284194Sdelphij goto out; 1299284194Sdelphij } 1300284194Sdelphij while ((d = readdir(dir)) != NULL) { 1301284194Sdelphij if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 1302284194Sdelphij file_oomem(ms, 1303284194Sdelphij strlen(fn) + strlen(d->d_name) + 2); 1304284194Sdelphij errs++; 1305284194Sdelphij closedir(dir); 1306284194Sdelphij goto out; 1307284194Sdelphij } 1308284194Sdelphij if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 1309284194Sdelphij free(mfn); 1310284194Sdelphij continue; 1311284194Sdelphij } 1312284194Sdelphij if (files >= maxfiles) { 1313284194Sdelphij size_t mlen; 1314284194Sdelphij maxfiles = (maxfiles + 1) * 2; 1315284194Sdelphij mlen = maxfiles * sizeof(*filearr); 1316284194Sdelphij if ((filearr = CAST(char **, 1317284194Sdelphij realloc(filearr, mlen))) == NULL) { 1318284194Sdelphij file_oomem(ms, mlen); 1319284194Sdelphij free(mfn); 1320284194Sdelphij closedir(dir); 1321284194Sdelphij errs++; 1322284194Sdelphij goto out; 1323284194Sdelphij } 1324284194Sdelphij } 1325284194Sdelphij filearr[files++] = mfn; 1326284194Sdelphij } 1327284194Sdelphij closedir(dir); 1328284194Sdelphij qsort(filearr, files, sizeof(*filearr), cmpstrp); 1329284194Sdelphij for (i = 0; i < files; i++) { 1330284194Sdelphij load_1(ms, action, filearr[i], &errs, mset); 1331284194Sdelphij free(filearr[i]); 1332284194Sdelphij } 1333284194Sdelphij free(filearr); 1334284194Sdelphij } else 1335284194Sdelphij load_1(ms, action, fn, &errs, mset); 1336284194Sdelphij if (errs) 1337284194Sdelphij goto out; 1338284194Sdelphij 1339284194Sdelphij for (j = 0; j < MAGIC_SETS; j++) { 1340284194Sdelphij /* Set types of tests */ 1341284194Sdelphij for (i = 0; i < mset[j].count; ) { 1342284194Sdelphij if (mset[j].me[i].mp->cont_level != 0) { 1343284194Sdelphij i++; 1344284194Sdelphij continue; 1345284194Sdelphij } 1346284194Sdelphij i = set_text_binary(ms, mset[j].me, mset[j].count, i); 1347284194Sdelphij } 1348284194Sdelphij qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me), 1349284194Sdelphij apprentice_sort); 1350284194Sdelphij 1351284194Sdelphij /* 1352284194Sdelphij * Make sure that any level 0 "default" line is last 1353284194Sdelphij * (if one exists). 1354284194Sdelphij */ 1355284194Sdelphij set_last_default(ms, mset[j].me, mset[j].count); 1356284194Sdelphij 1357284194Sdelphij /* coalesce per file arrays into a single one */ 1358284194Sdelphij if (coalesce_entries(ms, mset[j].me, mset[j].count, 1359284194Sdelphij &map->magic[j], &map->nmagic[j]) == -1) { 1360284194Sdelphij errs++; 1361284194Sdelphij goto out; 1362284194Sdelphij } 1363284194Sdelphij } 1364284194Sdelphij 1365284194Sdelphijout: 1366284194Sdelphij for (j = 0; j < MAGIC_SETS; j++) 1367284194Sdelphij magic_entry_free(mset[j].me, mset[j].count); 1368284194Sdelphij 1369284194Sdelphij if (errs) { 1370284194Sdelphij apprentice_unmap(map); 1371284194Sdelphij return NULL; 1372284194Sdelphij } 1373284194Sdelphij return map; 1374284194Sdelphij} 1375284194Sdelphij 1376284194Sdelphij/* 1377284194Sdelphij * extend the sign bit if the comparison is to be signed 1378284194Sdelphij */ 1379284194Sdelphijprotected uint64_t 1380284194Sdelphijfile_signextend(struct magic_set *ms, struct magic *m, uint64_t v) 1381284194Sdelphij{ 1382284194Sdelphij if (!(m->flag & UNSIGNED)) { 1383284194Sdelphij switch(m->type) { 1384284194Sdelphij /* 1385284194Sdelphij * Do not remove the casts below. They are 1386284194Sdelphij * vital. When later compared with the data, 1387284194Sdelphij * the sign extension must have happened. 1388284194Sdelphij */ 1389284194Sdelphij case FILE_BYTE: 1390284194Sdelphij v = (signed char) v; 1391284194Sdelphij break; 1392284194Sdelphij case FILE_SHORT: 1393284194Sdelphij case FILE_BESHORT: 1394284194Sdelphij case FILE_LESHORT: 1395284194Sdelphij v = (short) v; 1396284194Sdelphij break; 1397284194Sdelphij case FILE_DATE: 1398284194Sdelphij case FILE_BEDATE: 1399284194Sdelphij case FILE_LEDATE: 1400284194Sdelphij case FILE_MEDATE: 1401284194Sdelphij case FILE_LDATE: 1402284194Sdelphij case FILE_BELDATE: 1403284194Sdelphij case FILE_LELDATE: 1404284194Sdelphij case FILE_MELDATE: 1405284194Sdelphij case FILE_LONG: 1406284194Sdelphij case FILE_BELONG: 1407284194Sdelphij case FILE_LELONG: 1408284194Sdelphij case FILE_MELONG: 1409284194Sdelphij case FILE_FLOAT: 1410284194Sdelphij case FILE_BEFLOAT: 1411284194Sdelphij case FILE_LEFLOAT: 1412284194Sdelphij v = (int32_t) v; 1413284194Sdelphij break; 1414284194Sdelphij case FILE_QUAD: 1415284194Sdelphij case FILE_BEQUAD: 1416284194Sdelphij case FILE_LEQUAD: 1417284194Sdelphij case FILE_QDATE: 1418284194Sdelphij case FILE_QLDATE: 1419284194Sdelphij case FILE_QWDATE: 1420284194Sdelphij case FILE_BEQDATE: 1421284194Sdelphij case FILE_BEQLDATE: 1422284194Sdelphij case FILE_BEQWDATE: 1423284194Sdelphij case FILE_LEQDATE: 1424284194Sdelphij case FILE_LEQLDATE: 1425284194Sdelphij case FILE_LEQWDATE: 1426284194Sdelphij case FILE_DOUBLE: 1427284194Sdelphij case FILE_BEDOUBLE: 1428284194Sdelphij case FILE_LEDOUBLE: 1429284194Sdelphij v = (int64_t) v; 1430284194Sdelphij break; 1431284194Sdelphij case FILE_STRING: 1432284194Sdelphij case FILE_PSTRING: 1433284194Sdelphij case FILE_BESTRING16: 1434284194Sdelphij case FILE_LESTRING16: 1435284194Sdelphij case FILE_REGEX: 1436284194Sdelphij case FILE_SEARCH: 1437284194Sdelphij case FILE_DEFAULT: 1438284194Sdelphij case FILE_INDIRECT: 1439284194Sdelphij case FILE_NAME: 1440284194Sdelphij case FILE_USE: 1441284194Sdelphij case FILE_CLEAR: 1442284194Sdelphij break; 1443284194Sdelphij default: 1444284194Sdelphij if (ms->flags & MAGIC_CHECK) 1445284194Sdelphij file_magwarn(ms, "cannot happen: m->type=%d\n", 1446284194Sdelphij m->type); 1447284194Sdelphij return ~0U; 1448284194Sdelphij } 1449284194Sdelphij } 1450284194Sdelphij return v; 1451284194Sdelphij} 1452284194Sdelphij 1453284194Sdelphijprivate int 1454284194Sdelphijstring_modifier_check(struct magic_set *ms, struct magic *m) 1455284194Sdelphij{ 1456284194Sdelphij if ((ms->flags & MAGIC_CHECK) == 0) 1457284194Sdelphij return 0; 1458284194Sdelphij 1459284194Sdelphij if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) && 1460284194Sdelphij (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) { 1461284194Sdelphij file_magwarn(ms, 1462284194Sdelphij "'/BHhLl' modifiers are only allowed for pascal strings\n"); 1463284194Sdelphij return -1; 1464284194Sdelphij } 1465284194Sdelphij switch (m->type) { 1466284194Sdelphij case FILE_BESTRING16: 1467284194Sdelphij case FILE_LESTRING16: 1468284194Sdelphij if (m->str_flags != 0) { 1469284194Sdelphij file_magwarn(ms, 1470284194Sdelphij "no modifiers allowed for 16-bit strings\n"); 1471284194Sdelphij return -1; 1472284194Sdelphij } 1473284194Sdelphij break; 1474284194Sdelphij case FILE_STRING: 1475284194Sdelphij case FILE_PSTRING: 1476284194Sdelphij if ((m->str_flags & REGEX_OFFSET_START) != 0) { 1477284194Sdelphij file_magwarn(ms, 1478284194Sdelphij "'/%c' only allowed on regex and search\n", 1479284194Sdelphij CHAR_REGEX_OFFSET_START); 1480284194Sdelphij return -1; 1481284194Sdelphij } 1482284194Sdelphij break; 1483284194Sdelphij case FILE_SEARCH: 1484284194Sdelphij if (m->str_range == 0) { 1485284194Sdelphij file_magwarn(ms, 1486284194Sdelphij "missing range; defaulting to %d\n", 1487284194Sdelphij STRING_DEFAULT_RANGE); 1488284194Sdelphij m->str_range = STRING_DEFAULT_RANGE; 1489284194Sdelphij return -1; 1490284194Sdelphij } 1491284194Sdelphij break; 1492284194Sdelphij case FILE_REGEX: 1493284194Sdelphij if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) { 1494284194Sdelphij file_magwarn(ms, "'/%c' not allowed on regex\n", 1495284194Sdelphij CHAR_COMPACT_WHITESPACE); 1496284194Sdelphij return -1; 1497284194Sdelphij } 1498284194Sdelphij if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) { 1499284194Sdelphij file_magwarn(ms, "'/%c' not allowed on regex\n", 1500284194Sdelphij CHAR_COMPACT_OPTIONAL_WHITESPACE); 1501284194Sdelphij return -1; 1502284194Sdelphij } 1503284194Sdelphij break; 1504284194Sdelphij default: 1505284194Sdelphij file_magwarn(ms, "coding error: m->type=%d\n", 1506284194Sdelphij m->type); 1507284194Sdelphij return -1; 1508284194Sdelphij } 1509284194Sdelphij return 0; 1510284194Sdelphij} 1511284194Sdelphij 1512284194Sdelphijprivate int 1513284194Sdelphijget_op(char c) 1514284194Sdelphij{ 1515284194Sdelphij switch (c) { 1516284194Sdelphij case '&': 1517284194Sdelphij return FILE_OPAND; 1518284194Sdelphij case '|': 1519284194Sdelphij return FILE_OPOR; 1520284194Sdelphij case '^': 1521284194Sdelphij return FILE_OPXOR; 1522284194Sdelphij case '+': 1523284194Sdelphij return FILE_OPADD; 1524284194Sdelphij case '-': 1525284194Sdelphij return FILE_OPMINUS; 1526284194Sdelphij case '*': 1527284194Sdelphij return FILE_OPMULTIPLY; 1528284194Sdelphij case '/': 1529284194Sdelphij return FILE_OPDIVIDE; 1530284194Sdelphij case '%': 1531284194Sdelphij return FILE_OPMODULO; 1532284194Sdelphij default: 1533284194Sdelphij return -1; 1534284194Sdelphij } 1535284194Sdelphij} 1536284194Sdelphij 1537284194Sdelphij#ifdef ENABLE_CONDITIONALS 1538284194Sdelphijprivate int 1539284194Sdelphijget_cond(const char *l, const char **t) 1540284194Sdelphij{ 1541284194Sdelphij static const struct cond_tbl_s { 1542284194Sdelphij char name[8]; 1543284194Sdelphij size_t len; 1544284194Sdelphij int cond; 1545284194Sdelphij } cond_tbl[] = { 1546284194Sdelphij { "if", 2, COND_IF }, 1547284194Sdelphij { "elif", 4, COND_ELIF }, 1548284194Sdelphij { "else", 4, COND_ELSE }, 1549284194Sdelphij { "", 0, COND_NONE }, 1550284194Sdelphij }; 1551284194Sdelphij const struct cond_tbl_s *p; 1552284194Sdelphij 1553284194Sdelphij for (p = cond_tbl; p->len; p++) { 1554284194Sdelphij if (strncmp(l, p->name, p->len) == 0 && 1555284194Sdelphij isspace((unsigned char)l[p->len])) { 1556284194Sdelphij if (t) 1557284194Sdelphij *t = l + p->len; 1558284194Sdelphij break; 1559284194Sdelphij } 1560284194Sdelphij } 1561284194Sdelphij return p->cond; 1562284194Sdelphij} 1563284194Sdelphij 1564284194Sdelphijprivate int 1565284194Sdelphijcheck_cond(struct magic_set *ms, int cond, uint32_t cont_level) 1566284194Sdelphij{ 1567284194Sdelphij int last_cond; 1568284194Sdelphij last_cond = ms->c.li[cont_level].last_cond; 1569284194Sdelphij 1570284194Sdelphij switch (cond) { 1571284194Sdelphij case COND_IF: 1572284194Sdelphij if (last_cond != COND_NONE && last_cond != COND_ELIF) { 1573284194Sdelphij if (ms->flags & MAGIC_CHECK) 1574284194Sdelphij file_magwarn(ms, "syntax error: `if'"); 1575284194Sdelphij return -1; 1576284194Sdelphij } 1577284194Sdelphij last_cond = COND_IF; 1578284194Sdelphij break; 1579284194Sdelphij 1580284194Sdelphij case COND_ELIF: 1581284194Sdelphij if (last_cond != COND_IF && last_cond != COND_ELIF) { 1582284194Sdelphij if (ms->flags & MAGIC_CHECK) 1583284194Sdelphij file_magwarn(ms, "syntax error: `elif'"); 1584284194Sdelphij return -1; 1585284194Sdelphij } 1586284194Sdelphij last_cond = COND_ELIF; 1587284194Sdelphij break; 1588284194Sdelphij 1589284194Sdelphij case COND_ELSE: 1590284194Sdelphij if (last_cond != COND_IF && last_cond != COND_ELIF) { 1591284194Sdelphij if (ms->flags & MAGIC_CHECK) 1592284194Sdelphij file_magwarn(ms, "syntax error: `else'"); 1593284194Sdelphij return -1; 1594284194Sdelphij } 1595284194Sdelphij last_cond = COND_NONE; 1596284194Sdelphij break; 1597284194Sdelphij 1598284194Sdelphij case COND_NONE: 1599284194Sdelphij last_cond = COND_NONE; 1600284194Sdelphij break; 1601284194Sdelphij } 1602284194Sdelphij 1603284194Sdelphij ms->c.li[cont_level].last_cond = last_cond; 1604284194Sdelphij return 0; 1605284194Sdelphij} 1606284194Sdelphij#endif /* ENABLE_CONDITIONALS */ 1607284194Sdelphij 1608284194Sdelphijprivate int 1609284194Sdelphijparse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp) 1610284194Sdelphij{ 1611284194Sdelphij const char *l = *lp; 1612284194Sdelphij 1613284194Sdelphij while (!isspace((unsigned char)*++l)) 1614284194Sdelphij switch (*l) { 1615284194Sdelphij case CHAR_INDIRECT_RELATIVE: 1616284194Sdelphij m->str_flags |= INDIRECT_RELATIVE; 1617284194Sdelphij break; 1618284194Sdelphij default: 1619284194Sdelphij if (ms->flags & MAGIC_CHECK) 1620284194Sdelphij file_magwarn(ms, "indirect modifier `%c' " 1621284194Sdelphij "invalid", *l); 1622284194Sdelphij *lp = l; 1623284194Sdelphij return -1; 1624284194Sdelphij } 1625284194Sdelphij *lp = l; 1626284194Sdelphij return 0; 1627284194Sdelphij} 1628284194Sdelphij 1629284194Sdelphijprivate void 1630284194Sdelphijparse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp, 1631284194Sdelphij int op) 1632284194Sdelphij{ 1633284194Sdelphij const char *l = *lp; 1634284194Sdelphij char *t; 1635284194Sdelphij uint64_t val; 1636284194Sdelphij 1637284194Sdelphij ++l; 1638284194Sdelphij m->mask_op |= op; 1639284194Sdelphij val = (uint64_t)strtoull(l, &t, 0); 1640284194Sdelphij l = t; 1641284194Sdelphij m->num_mask = file_signextend(ms, m, val); 1642284194Sdelphij eatsize(&l); 1643284194Sdelphij *lp = l; 1644284194Sdelphij} 1645284194Sdelphij 1646284194Sdelphijprivate int 1647284194Sdelphijparse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp) 1648284194Sdelphij{ 1649284194Sdelphij const char *l = *lp; 1650284194Sdelphij char *t; 1651284194Sdelphij int have_range = 0; 1652284194Sdelphij 1653284194Sdelphij while (!isspace((unsigned char)*++l)) { 1654284194Sdelphij switch (*l) { 1655284194Sdelphij case '0': case '1': case '2': 1656284194Sdelphij case '3': case '4': case '5': 1657284194Sdelphij case '6': case '7': case '8': 1658284194Sdelphij case '9': 1659284194Sdelphij if (have_range && (ms->flags & MAGIC_CHECK)) 1660284194Sdelphij file_magwarn(ms, "multiple ranges"); 1661284194Sdelphij have_range = 1; 1662284194Sdelphij m->str_range = CAST(uint32_t, strtoul(l, &t, 0)); 1663284194Sdelphij if (m->str_range == 0) 1664284194Sdelphij file_magwarn(ms, "zero range"); 1665284194Sdelphij l = t - 1; 1666284194Sdelphij break; 1667284194Sdelphij case CHAR_COMPACT_WHITESPACE: 1668284194Sdelphij m->str_flags |= STRING_COMPACT_WHITESPACE; 1669284194Sdelphij break; 1670284194Sdelphij case CHAR_COMPACT_OPTIONAL_WHITESPACE: 1671284194Sdelphij m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE; 1672284194Sdelphij break; 1673284194Sdelphij case CHAR_IGNORE_LOWERCASE: 1674284194Sdelphij m->str_flags |= STRING_IGNORE_LOWERCASE; 1675284194Sdelphij break; 1676284194Sdelphij case CHAR_IGNORE_UPPERCASE: 1677284194Sdelphij m->str_flags |= STRING_IGNORE_UPPERCASE; 1678284194Sdelphij break; 1679284194Sdelphij case CHAR_REGEX_OFFSET_START: 1680284194Sdelphij m->str_flags |= REGEX_OFFSET_START; 1681284194Sdelphij break; 1682284194Sdelphij case CHAR_BINTEST: 1683284194Sdelphij m->str_flags |= STRING_BINTEST; 1684284194Sdelphij break; 1685284194Sdelphij case CHAR_TEXTTEST: 1686284194Sdelphij m->str_flags |= STRING_TEXTTEST; 1687284194Sdelphij break; 1688284194Sdelphij case CHAR_TRIM: 1689284194Sdelphij m->str_flags |= STRING_TRIM; 1690284194Sdelphij break; 1691284194Sdelphij case CHAR_PSTRING_1_LE: 1692284194Sdelphij#define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a) 1693284194Sdelphij if (m->type != FILE_PSTRING) 1694284194Sdelphij goto bad; 1695284194Sdelphij SET_LENGTH(PSTRING_1_LE); 1696284194Sdelphij break; 1697284194Sdelphij case CHAR_PSTRING_2_BE: 1698284194Sdelphij if (m->type != FILE_PSTRING) 1699284194Sdelphij goto bad; 1700284194Sdelphij SET_LENGTH(PSTRING_2_BE); 1701284194Sdelphij break; 1702284194Sdelphij case CHAR_PSTRING_2_LE: 1703284194Sdelphij if (m->type != FILE_PSTRING) 1704284194Sdelphij goto bad; 1705284194Sdelphij SET_LENGTH(PSTRING_2_LE); 1706284194Sdelphij break; 1707284194Sdelphij case CHAR_PSTRING_4_BE: 1708284194Sdelphij if (m->type != FILE_PSTRING) 1709284194Sdelphij goto bad; 1710284194Sdelphij SET_LENGTH(PSTRING_4_BE); 1711284194Sdelphij break; 1712284194Sdelphij case CHAR_PSTRING_4_LE: 1713284194Sdelphij switch (m->type) { 1714284194Sdelphij case FILE_PSTRING: 1715284194Sdelphij case FILE_REGEX: 1716284194Sdelphij break; 1717284194Sdelphij default: 1718284194Sdelphij goto bad; 1719284194Sdelphij } 1720284194Sdelphij SET_LENGTH(PSTRING_4_LE); 1721284194Sdelphij break; 1722284194Sdelphij case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF: 1723284194Sdelphij if (m->type != FILE_PSTRING) 1724284194Sdelphij goto bad; 1725284194Sdelphij m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF; 1726284194Sdelphij break; 1727284194Sdelphij default: 1728284194Sdelphij bad: 1729284194Sdelphij if (ms->flags & MAGIC_CHECK) 1730284194Sdelphij file_magwarn(ms, "string modifier `%c' " 1731284194Sdelphij "invalid", *l); 1732284194Sdelphij goto out; 1733284194Sdelphij } 1734284194Sdelphij /* allow multiple '/' for readability */ 1735284194Sdelphij if (l[1] == '/' && !isspace((unsigned char)l[2])) 1736284194Sdelphij l++; 1737284194Sdelphij } 1738284194Sdelphij if (string_modifier_check(ms, m) == -1) 1739284194Sdelphij goto out; 1740284194Sdelphij *lp = l; 1741284194Sdelphij return 0; 1742284194Sdelphijout: 1743284194Sdelphij *lp = l; 1744284194Sdelphij return -1; 1745284194Sdelphij} 1746284194Sdelphij 1747284194Sdelphij/* 1748284194Sdelphij * parse one line from magic file, put into magic[index++] if valid 1749284194Sdelphij */ 1750284194Sdelphijprivate int 1751284194Sdelphijparse(struct magic_set *ms, struct magic_entry *me, const char *line, 1752284194Sdelphij size_t lineno, int action) 1753284194Sdelphij{ 1754284194Sdelphij#ifdef ENABLE_CONDITIONALS 1755284194Sdelphij static uint32_t last_cont_level = 0; 1756284194Sdelphij#endif 1757284194Sdelphij size_t i; 1758284194Sdelphij struct magic *m; 1759284194Sdelphij const char *l = line; 1760284194Sdelphij char *t; 1761284194Sdelphij int op; 1762284194Sdelphij uint32_t cont_level; 1763284194Sdelphij int32_t diff; 1764284194Sdelphij 1765284194Sdelphij cont_level = 0; 1766284194Sdelphij 1767284194Sdelphij /* 1768284194Sdelphij * Parse the offset. 1769284194Sdelphij */ 1770284194Sdelphij while (*l == '>') { 1771284194Sdelphij ++l; /* step over */ 1772284194Sdelphij cont_level++; 1773284194Sdelphij } 1774284194Sdelphij#ifdef ENABLE_CONDITIONALS 1775284194Sdelphij if (cont_level == 0 || cont_level > last_cont_level) 1776284194Sdelphij if (file_check_mem(ms, cont_level) == -1) 1777284194Sdelphij return -1; 1778284194Sdelphij last_cont_level = cont_level; 1779284194Sdelphij#endif 1780284194Sdelphij if (cont_level != 0) { 1781284194Sdelphij if (me->mp == NULL) { 1782284194Sdelphij file_magerror(ms, "No current entry for continuation"); 1783284194Sdelphij return -1; 1784284194Sdelphij } 1785284194Sdelphij if (me->cont_count == 0) { 1786284194Sdelphij file_magerror(ms, "Continuations present with 0 count"); 1787284194Sdelphij return -1; 1788284194Sdelphij } 1789284194Sdelphij m = &me->mp[me->cont_count - 1]; 1790284194Sdelphij diff = (int32_t)cont_level - (int32_t)m->cont_level; 1791284194Sdelphij if (diff > 1) 1792284194Sdelphij file_magwarn(ms, "New continuation level %u is more " 1793284194Sdelphij "than one larger than current level %u", cont_level, 1794284194Sdelphij m->cont_level); 1795284194Sdelphij if (me->cont_count == me->max_count) { 1796284194Sdelphij struct magic *nm; 1797284194Sdelphij size_t cnt = me->max_count + ALLOC_CHUNK; 1798284194Sdelphij if ((nm = CAST(struct magic *, realloc(me->mp, 1799284194Sdelphij sizeof(*nm) * cnt))) == NULL) { 1800284194Sdelphij file_oomem(ms, sizeof(*nm) * cnt); 1801284194Sdelphij return -1; 1802284194Sdelphij } 1803284194Sdelphij me->mp = m = nm; 1804284194Sdelphij me->max_count = CAST(uint32_t, cnt); 1805284194Sdelphij } 1806284194Sdelphij m = &me->mp[me->cont_count++]; 1807284194Sdelphij (void)memset(m, 0, sizeof(*m)); 1808284194Sdelphij m->cont_level = cont_level; 1809284194Sdelphij } else { 1810284194Sdelphij static const size_t len = sizeof(*m) * ALLOC_CHUNK; 1811284194Sdelphij if (me->mp != NULL) 1812284194Sdelphij return 1; 1813284194Sdelphij if ((m = CAST(struct magic *, malloc(len))) == NULL) { 1814284194Sdelphij file_oomem(ms, len); 1815284194Sdelphij return -1; 1816284194Sdelphij } 1817284194Sdelphij me->mp = m; 1818284194Sdelphij me->max_count = ALLOC_CHUNK; 1819284194Sdelphij (void)memset(m, 0, sizeof(*m)); 1820284194Sdelphij m->factor_op = FILE_FACTOR_OP_NONE; 1821284194Sdelphij m->cont_level = 0; 1822284194Sdelphij me->cont_count = 1; 1823284194Sdelphij } 1824284194Sdelphij m->lineno = CAST(uint32_t, lineno); 1825284194Sdelphij 1826284194Sdelphij if (*l == '&') { /* m->cont_level == 0 checked below. */ 1827284194Sdelphij ++l; /* step over */ 1828284194Sdelphij m->flag |= OFFADD; 1829284194Sdelphij } 1830284194Sdelphij if (*l == '(') { 1831284194Sdelphij ++l; /* step over */ 1832284194Sdelphij m->flag |= INDIR; 1833284194Sdelphij if (m->flag & OFFADD) 1834284194Sdelphij m->flag = (m->flag & ~OFFADD) | INDIROFFADD; 1835284194Sdelphij 1836284194Sdelphij if (*l == '&') { /* m->cont_level == 0 checked below */ 1837284194Sdelphij ++l; /* step over */ 1838284194Sdelphij m->flag |= OFFADD; 1839284194Sdelphij } 1840284194Sdelphij } 1841284194Sdelphij /* Indirect offsets are not valid at level 0. */ 1842284194Sdelphij if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) 1843284194Sdelphij if (ms->flags & MAGIC_CHECK) 1844284194Sdelphij file_magwarn(ms, "relative offset at level 0"); 1845284194Sdelphij 1846284194Sdelphij /* get offset, then skip over it */ 1847284194Sdelphij m->offset = (uint32_t)strtoul(l, &t, 0); 1848284194Sdelphij if (l == t) 1849284194Sdelphij if (ms->flags & MAGIC_CHECK) 1850284194Sdelphij file_magwarn(ms, "offset `%s' invalid", l); 1851284194Sdelphij l = t; 1852284194Sdelphij 1853284194Sdelphij if (m->flag & INDIR) { 1854284194Sdelphij m->in_type = FILE_LONG; 1855284194Sdelphij m->in_offset = 0; 1856284194Sdelphij /* 1857284194Sdelphij * read [.lbs][+-]nnnnn) 1858284194Sdelphij */ 1859284194Sdelphij if (*l == '.') { 1860284194Sdelphij l++; 1861284194Sdelphij switch (*l) { 1862284194Sdelphij case 'l': 1863284194Sdelphij m->in_type = FILE_LELONG; 1864284194Sdelphij break; 1865284194Sdelphij case 'L': 1866284194Sdelphij m->in_type = FILE_BELONG; 1867284194Sdelphij break; 1868284194Sdelphij case 'm': 1869284194Sdelphij m->in_type = FILE_MELONG; 1870284194Sdelphij break; 1871284194Sdelphij case 'h': 1872284194Sdelphij case 's': 1873284194Sdelphij m->in_type = FILE_LESHORT; 1874284194Sdelphij break; 1875284194Sdelphij case 'H': 1876284194Sdelphij case 'S': 1877284194Sdelphij m->in_type = FILE_BESHORT; 1878284194Sdelphij break; 1879284194Sdelphij case 'c': 1880284194Sdelphij case 'b': 1881284194Sdelphij case 'C': 1882284194Sdelphij case 'B': 1883284194Sdelphij m->in_type = FILE_BYTE; 1884284194Sdelphij break; 1885284194Sdelphij case 'e': 1886284194Sdelphij case 'f': 1887284194Sdelphij case 'g': 1888284194Sdelphij m->in_type = FILE_LEDOUBLE; 1889284194Sdelphij break; 1890284194Sdelphij case 'E': 1891284194Sdelphij case 'F': 1892284194Sdelphij case 'G': 1893284194Sdelphij m->in_type = FILE_BEDOUBLE; 1894284194Sdelphij break; 1895284194Sdelphij case 'i': 1896284194Sdelphij m->in_type = FILE_LEID3; 1897284194Sdelphij break; 1898284194Sdelphij case 'I': 1899284194Sdelphij m->in_type = FILE_BEID3; 1900284194Sdelphij break; 1901284194Sdelphij default: 1902284194Sdelphij if (ms->flags & MAGIC_CHECK) 1903284194Sdelphij file_magwarn(ms, 1904284194Sdelphij "indirect offset type `%c' invalid", 1905284194Sdelphij *l); 1906284194Sdelphij break; 1907284194Sdelphij } 1908284194Sdelphij l++; 1909284194Sdelphij } 1910284194Sdelphij 1911284194Sdelphij m->in_op = 0; 1912284194Sdelphij if (*l == '~') { 1913284194Sdelphij m->in_op |= FILE_OPINVERSE; 1914284194Sdelphij l++; 1915284194Sdelphij } 1916284194Sdelphij if ((op = get_op(*l)) != -1) { 1917284194Sdelphij m->in_op |= op; 1918284194Sdelphij l++; 1919284194Sdelphij } 1920284194Sdelphij if (*l == '(') { 1921284194Sdelphij m->in_op |= FILE_OPINDIRECT; 1922284194Sdelphij l++; 1923284194Sdelphij } 1924284194Sdelphij if (isdigit((unsigned char)*l) || *l == '-') { 1925284194Sdelphij m->in_offset = (int32_t)strtol(l, &t, 0); 1926284194Sdelphij if (l == t) 1927284194Sdelphij if (ms->flags & MAGIC_CHECK) 1928284194Sdelphij file_magwarn(ms, 1929284194Sdelphij "in_offset `%s' invalid", l); 1930284194Sdelphij l = t; 1931284194Sdelphij } 1932284194Sdelphij if (*l++ != ')' || 1933284194Sdelphij ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) 1934284194Sdelphij if (ms->flags & MAGIC_CHECK) 1935284194Sdelphij file_magwarn(ms, 1936284194Sdelphij "missing ')' in indirect offset"); 1937284194Sdelphij } 1938284194Sdelphij EATAB; 1939284194Sdelphij 1940284194Sdelphij#ifdef ENABLE_CONDITIONALS 1941284194Sdelphij m->cond = get_cond(l, &l); 1942284194Sdelphij if (check_cond(ms, m->cond, cont_level) == -1) 1943284194Sdelphij return -1; 1944284194Sdelphij 1945284194Sdelphij EATAB; 1946284194Sdelphij#endif 1947284194Sdelphij 1948284194Sdelphij /* 1949284194Sdelphij * Parse the type. 1950284194Sdelphij */ 1951284194Sdelphij if (*l == 'u') { 1952284194Sdelphij /* 1953284194Sdelphij * Try it as a keyword type prefixed by "u"; match what 1954284194Sdelphij * follows the "u". If that fails, try it as an SUS 1955284194Sdelphij * integer type. 1956284194Sdelphij */ 1957284194Sdelphij m->type = get_type(type_tbl, l + 1, &l); 1958284194Sdelphij if (m->type == FILE_INVALID) { 1959284194Sdelphij /* 1960284194Sdelphij * Not a keyword type; parse it as an SUS type, 1961284194Sdelphij * 'u' possibly followed by a number or C/S/L. 1962284194Sdelphij */ 1963284194Sdelphij m->type = get_standard_integer_type(l, &l); 1964284194Sdelphij } 1965284194Sdelphij /* It's unsigned. */ 1966284194Sdelphij if (m->type != FILE_INVALID) 1967284194Sdelphij m->flag |= UNSIGNED; 1968284194Sdelphij } else { 1969284194Sdelphij /* 1970284194Sdelphij * Try it as a keyword type. If that fails, try it as 1971284194Sdelphij * an SUS integer type if it begins with "d" or as an 1972284194Sdelphij * SUS string type if it begins with "s". In any case, 1973284194Sdelphij * it's not unsigned. 1974284194Sdelphij */ 1975284194Sdelphij m->type = get_type(type_tbl, l, &l); 1976284194Sdelphij if (m->type == FILE_INVALID) { 1977284194Sdelphij /* 1978284194Sdelphij * Not a keyword type; parse it as an SUS type, 1979284194Sdelphij * either 'd' possibly followed by a number or 1980284194Sdelphij * C/S/L, or just 's'. 1981284194Sdelphij */ 1982284194Sdelphij if (*l == 'd') 1983284194Sdelphij m->type = get_standard_integer_type(l, &l); 1984284194Sdelphij else if (*l == 's' && !isalpha((unsigned char)l[1])) { 1985284194Sdelphij m->type = FILE_STRING; 1986284194Sdelphij ++l; 1987284194Sdelphij } 1988284194Sdelphij } 1989284194Sdelphij } 1990284194Sdelphij 1991284194Sdelphij if (m->type == FILE_INVALID) { 1992284194Sdelphij /* Not found - try it as a special keyword. */ 1993284194Sdelphij m->type = get_type(special_tbl, l, &l); 1994284194Sdelphij } 1995284194Sdelphij 1996284194Sdelphij if (m->type == FILE_INVALID) { 1997284194Sdelphij if (ms->flags & MAGIC_CHECK) 1998284194Sdelphij file_magwarn(ms, "type `%s' invalid", l); 1999284194Sdelphij return -1; 2000284194Sdelphij } 2001284194Sdelphij 2002284194Sdelphij /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ 2003284194Sdelphij /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */ 2004284194Sdelphij 2005284194Sdelphij m->mask_op = 0; 2006284194Sdelphij if (*l == '~') { 2007284194Sdelphij if (!IS_STRING(m->type)) 2008284194Sdelphij m->mask_op |= FILE_OPINVERSE; 2009284194Sdelphij else if (ms->flags & MAGIC_CHECK) 2010284194Sdelphij file_magwarn(ms, "'~' invalid for string types"); 2011284194Sdelphij ++l; 2012284194Sdelphij } 2013284194Sdelphij m->str_range = 0; 2014284194Sdelphij m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 2015284194Sdelphij if ((op = get_op(*l)) != -1) { 2016284194Sdelphij if (IS_STRING(m->type)) { 2017284194Sdelphij int r; 2018284194Sdelphij 2019284194Sdelphij if (op != FILE_OPDIVIDE) { 2020284194Sdelphij if (ms->flags & MAGIC_CHECK) 2021284194Sdelphij file_magwarn(ms, 2022284194Sdelphij "invalid string/indirect op: " 2023284194Sdelphij "`%c'", *t); 2024284194Sdelphij return -1; 2025284194Sdelphij } 2026284194Sdelphij 2027284194Sdelphij if (m->type == FILE_INDIRECT) 2028284194Sdelphij r = parse_indirect_modifier(ms, m, &l); 2029284194Sdelphij else 2030284194Sdelphij r = parse_string_modifier(ms, m, &l); 2031284194Sdelphij if (r == -1) 2032284194Sdelphij return -1; 2033284194Sdelphij } else 2034284194Sdelphij parse_op_modifier(ms, m, &l, op); 2035284194Sdelphij } 2036284194Sdelphij 2037284194Sdelphij /* 2038284194Sdelphij * We used to set mask to all 1's here, instead let's just not do 2039284194Sdelphij * anything if mask = 0 (unless you have a better idea) 2040284194Sdelphij */ 2041284194Sdelphij EATAB; 2042284194Sdelphij 2043284194Sdelphij switch (*l) { 2044284194Sdelphij case '>': 2045284194Sdelphij case '<': 2046284194Sdelphij m->reln = *l; 2047284194Sdelphij ++l; 2048284194Sdelphij if (*l == '=') { 2049284194Sdelphij if (ms->flags & MAGIC_CHECK) { 2050284194Sdelphij file_magwarn(ms, "%c= not supported", 2051284194Sdelphij m->reln); 2052284194Sdelphij return -1; 2053284194Sdelphij } 2054284194Sdelphij ++l; 2055284194Sdelphij } 2056284194Sdelphij break; 2057284194Sdelphij /* Old-style anding: "0 byte &0x80 dynamically linked" */ 2058284194Sdelphij case '&': 2059284194Sdelphij case '^': 2060284194Sdelphij case '=': 2061284194Sdelphij m->reln = *l; 2062284194Sdelphij ++l; 2063284194Sdelphij if (*l == '=') { 2064284194Sdelphij /* HP compat: ignore &= etc. */ 2065284194Sdelphij ++l; 2066284194Sdelphij } 2067284194Sdelphij break; 2068284194Sdelphij case '!': 2069284194Sdelphij m->reln = *l; 2070284194Sdelphij ++l; 2071284194Sdelphij break; 2072284194Sdelphij default: 2073284194Sdelphij m->reln = '='; /* the default relation */ 2074284194Sdelphij if (*l == 'x' && ((isascii((unsigned char)l[1]) && 2075284194Sdelphij isspace((unsigned char)l[1])) || !l[1])) { 2076284194Sdelphij m->reln = *l; 2077284194Sdelphij ++l; 2078284194Sdelphij } 2079284194Sdelphij break; 2080284194Sdelphij } 2081284194Sdelphij /* 2082284194Sdelphij * Grab the value part, except for an 'x' reln. 2083284194Sdelphij */ 2084284194Sdelphij if (m->reln != 'x' && getvalue(ms, m, &l, action)) 2085284194Sdelphij return -1; 2086284194Sdelphij 2087284194Sdelphij /* 2088284194Sdelphij * TODO finish this macro and start using it! 2089284194Sdelphij * #define offsetcheck {if (offset > HOWMANY-1) 2090284194Sdelphij * magwarn("offset too big"); } 2091284194Sdelphij */ 2092284194Sdelphij 2093284194Sdelphij /* 2094284194Sdelphij * Now get last part - the description 2095284194Sdelphij */ 2096284194Sdelphij EATAB; 2097284194Sdelphij if (l[0] == '\b') { 2098284194Sdelphij ++l; 2099284194Sdelphij m->flag |= NOSPACE; 2100284194Sdelphij } else if ((l[0] == '\\') && (l[1] == 'b')) { 2101284194Sdelphij ++l; 2102284194Sdelphij ++l; 2103284194Sdelphij m->flag |= NOSPACE; 2104284194Sdelphij } 2105284194Sdelphij for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); ) 2106284194Sdelphij continue; 2107284194Sdelphij if (i == sizeof(m->desc)) { 2108284194Sdelphij m->desc[sizeof(m->desc) - 1] = '\0'; 2109284194Sdelphij if (ms->flags & MAGIC_CHECK) 2110284194Sdelphij file_magwarn(ms, "description `%s' truncated", m->desc); 2111284194Sdelphij } 2112284194Sdelphij 2113284194Sdelphij /* 2114284194Sdelphij * We only do this check while compiling, or if any of the magic 2115284194Sdelphij * files were not compiled. 2116284194Sdelphij */ 2117284194Sdelphij if (ms->flags & MAGIC_CHECK) { 2118284194Sdelphij if (check_format(ms, m) == -1) 2119284194Sdelphij return -1; 2120284194Sdelphij } 2121284194Sdelphij#ifndef COMPILE_ONLY 2122284194Sdelphij if (action == FILE_CHECK) { 2123284194Sdelphij file_mdump(m); 2124284194Sdelphij } 2125284194Sdelphij#endif 2126284194Sdelphij m->mimetype[0] = '\0'; /* initialise MIME type to none */ 2127284194Sdelphij return 0; 2128284194Sdelphij} 2129284194Sdelphij 2130284194Sdelphij/* 2131284194Sdelphij * parse a STRENGTH annotation line from magic file, put into magic[index - 1] 2132284194Sdelphij * if valid 2133284194Sdelphij */ 2134284194Sdelphijprivate int 2135284194Sdelphijparse_strength(struct magic_set *ms, struct magic_entry *me, const char *line) 2136284194Sdelphij{ 2137284194Sdelphij const char *l = line; 2138284194Sdelphij char *el; 2139284194Sdelphij unsigned long factor; 2140284194Sdelphij struct magic *m = &me->mp[0]; 2141284194Sdelphij 2142284194Sdelphij if (m->factor_op != FILE_FACTOR_OP_NONE) { 2143284194Sdelphij file_magwarn(ms, 2144284194Sdelphij "Current entry already has a strength type: %c %d", 2145284194Sdelphij m->factor_op, m->factor); 2146284194Sdelphij return -1; 2147284194Sdelphij } 2148284194Sdelphij if (m->type == FILE_NAME) { 2149284194Sdelphij file_magwarn(ms, "%s: Strength setting is not supported in " 2150284194Sdelphij "\"name\" magic entries", m->value.s); 2151284194Sdelphij return -1; 2152284194Sdelphij } 2153284194Sdelphij EATAB; 2154284194Sdelphij switch (*l) { 2155284194Sdelphij case FILE_FACTOR_OP_NONE: 2156284194Sdelphij case FILE_FACTOR_OP_PLUS: 2157284194Sdelphij case FILE_FACTOR_OP_MINUS: 2158284194Sdelphij case FILE_FACTOR_OP_TIMES: 2159284194Sdelphij case FILE_FACTOR_OP_DIV: 2160284194Sdelphij m->factor_op = *l++; 2161284194Sdelphij break; 2162284194Sdelphij default: 2163284194Sdelphij file_magwarn(ms, "Unknown factor op `%c'", *l); 2164284194Sdelphij return -1; 2165284194Sdelphij } 2166284194Sdelphij EATAB; 2167284194Sdelphij factor = strtoul(l, &el, 0); 2168284194Sdelphij if (factor > 255) { 2169284194Sdelphij file_magwarn(ms, "Too large factor `%lu'", factor); 2170284194Sdelphij goto out; 2171284194Sdelphij } 2172284194Sdelphij if (*el && !isspace((unsigned char)*el)) { 2173284194Sdelphij file_magwarn(ms, "Bad factor `%s'", l); 2174284194Sdelphij goto out; 2175284194Sdelphij } 2176284194Sdelphij m->factor = (uint8_t)factor; 2177284194Sdelphij if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) { 2178284194Sdelphij file_magwarn(ms, "Cannot have factor op `%c' and factor %u", 2179284194Sdelphij m->factor_op, m->factor); 2180284194Sdelphij goto out; 2181284194Sdelphij } 2182284194Sdelphij return 0; 2183284194Sdelphijout: 2184284194Sdelphij m->factor_op = FILE_FACTOR_OP_NONE; 2185284194Sdelphij m->factor = 0; 2186284194Sdelphij return -1; 2187284194Sdelphij} 2188284194Sdelphij 2189284194Sdelphijprivate int 2190284194Sdelphijgoodchar(unsigned char x, const char *extra) 2191284194Sdelphij{ 2192284194Sdelphij return (isascii(x) && isalnum(x)) || strchr(extra, x); 2193284194Sdelphij} 2194284194Sdelphij 2195284194Sdelphijprivate int 2196284194Sdelphijparse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 2197284194Sdelphij off_t off, size_t len, const char *name, const char *extra, int nt) 2198284194Sdelphij{ 2199284194Sdelphij size_t i; 2200284194Sdelphij const char *l = line; 2201284194Sdelphij struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1]; 2202284194Sdelphij char *buf = (char *)m + off; 2203284194Sdelphij 2204284194Sdelphij if (buf[0] != '\0') { 2205284194Sdelphij len = nt ? strlen(buf) : len; 2206284194Sdelphij file_magwarn(ms, "Current entry already has a %s type " 2207284194Sdelphij "`%.*s', new type `%s'", name, (int)len, buf, l); 2208284194Sdelphij return -1; 2209284194Sdelphij } 2210284194Sdelphij 2211284194Sdelphij if (*m->desc == '\0') { 2212284194Sdelphij file_magwarn(ms, "Current entry does not yet have a " 2213284194Sdelphij "description for adding a %s type", name); 2214284194Sdelphij return -1; 2215284194Sdelphij } 2216284194Sdelphij 2217284194Sdelphij EATAB; 2218284194Sdelphij for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++) 2219284194Sdelphij continue; 2220284194Sdelphij 2221284194Sdelphij if (i == len && *l) { 2222284194Sdelphij if (nt) 2223284194Sdelphij buf[len - 1] = '\0'; 2224284194Sdelphij if (ms->flags & MAGIC_CHECK) 2225284194Sdelphij file_magwarn(ms, "%s type `%s' truncated %" 2226284194Sdelphij SIZE_T_FORMAT "u", name, line, i); 2227284194Sdelphij } else { 2228284194Sdelphij if (!isspace((unsigned char)*l) && !goodchar(*l, extra)) 2229284194Sdelphij file_magwarn(ms, "%s type `%s' has bad char '%c'", 2230284194Sdelphij name, line, *l); 2231284194Sdelphij if (nt) 2232284194Sdelphij buf[i] = '\0'; 2233284194Sdelphij } 2234284194Sdelphij 2235284194Sdelphij if (i > 0) 2236284194Sdelphij return 0; 2237284194Sdelphij 2238284194Sdelphij file_magerror(ms, "Bad magic entry '%s'", line); 2239284194Sdelphij return -1; 2240284194Sdelphij} 2241284194Sdelphij 2242284194Sdelphij/* 2243284194Sdelphij * Parse an Apple CREATOR/TYPE annotation from magic file and put it into 2244284194Sdelphij * magic[index - 1] 2245284194Sdelphij */ 2246284194Sdelphijprivate int 2247284194Sdelphijparse_apple(struct magic_set *ms, struct magic_entry *me, const char *line) 2248284194Sdelphij{ 2249284194Sdelphij struct magic *m = &me->mp[0]; 2250284194Sdelphij 2251284194Sdelphij return parse_extra(ms, me, line, offsetof(struct magic, apple), 2252284194Sdelphij sizeof(m->apple), "APPLE", "!+-./", 0); 2253284194Sdelphij} 2254284194Sdelphij 2255284194Sdelphij/* 2256284194Sdelphij * parse a MIME annotation line from magic file, put into magic[index - 1] 2257284194Sdelphij * if valid 2258284194Sdelphij */ 2259284194Sdelphijprivate int 2260284194Sdelphijparse_mime(struct magic_set *ms, struct magic_entry *me, const char *line) 2261284194Sdelphij{ 2262284194Sdelphij struct magic *m = &me->mp[0]; 2263284194Sdelphij 2264284194Sdelphij return parse_extra(ms, me, line, offsetof(struct magic, mimetype), 2265284194Sdelphij sizeof(m->mimetype), "MIME", "+-/.", 1); 2266284194Sdelphij} 2267284194Sdelphij 2268284194Sdelphijprivate int 2269284194Sdelphijcheck_format_type(const char *ptr, int type) 2270284194Sdelphij{ 2271284194Sdelphij int quad = 0, h; 2272284194Sdelphij if (*ptr == '\0') { 2273284194Sdelphij /* Missing format string; bad */ 2274284194Sdelphij return -1; 2275284194Sdelphij } 2276284194Sdelphij 2277284194Sdelphij switch (file_formats[type]) { 2278284194Sdelphij case FILE_FMT_QUAD: 2279284194Sdelphij quad = 1; 2280284194Sdelphij /*FALLTHROUGH*/ 2281284194Sdelphij case FILE_FMT_NUM: 2282284194Sdelphij if (quad == 0) { 2283284194Sdelphij switch (type) { 2284284194Sdelphij case FILE_BYTE: 2285284194Sdelphij h = 2; 2286284194Sdelphij break; 2287284194Sdelphij case FILE_SHORT: 2288284194Sdelphij case FILE_BESHORT: 2289284194Sdelphij case FILE_LESHORT: 2290284194Sdelphij h = 1; 2291284194Sdelphij break; 2292284194Sdelphij case FILE_LONG: 2293284194Sdelphij case FILE_BELONG: 2294284194Sdelphij case FILE_LELONG: 2295284194Sdelphij case FILE_MELONG: 2296284194Sdelphij case FILE_LEID3: 2297284194Sdelphij case FILE_BEID3: 2298284194Sdelphij case FILE_INDIRECT: 2299284194Sdelphij h = 0; 2300284194Sdelphij break; 2301284194Sdelphij default: 2302284194Sdelphij abort(); 2303284194Sdelphij } 2304284194Sdelphij } else 2305284194Sdelphij h = 0; 2306284194Sdelphij if (*ptr == '-') 2307284194Sdelphij ptr++; 2308284194Sdelphij if (*ptr == '.') 2309284194Sdelphij ptr++; 2310284194Sdelphij while (isdigit((unsigned char)*ptr)) ptr++; 2311284194Sdelphij if (*ptr == '.') 2312284194Sdelphij ptr++; 2313284194Sdelphij while (isdigit((unsigned char)*ptr)) ptr++; 2314284194Sdelphij if (quad) { 2315284194Sdelphij if (*ptr++ != 'l') 2316284194Sdelphij return -1; 2317284194Sdelphij if (*ptr++ != 'l') 2318284194Sdelphij return -1; 2319284194Sdelphij } 2320284194Sdelphij 2321284194Sdelphij switch (*ptr++) { 2322284194Sdelphij#ifdef STRICT_FORMAT /* "long" formats are int formats for us */ 2323284194Sdelphij /* so don't accept the 'l' modifier */ 2324284194Sdelphij case 'l': 2325284194Sdelphij switch (*ptr++) { 2326284194Sdelphij case 'i': 2327284194Sdelphij case 'd': 2328284194Sdelphij case 'u': 2329284194Sdelphij case 'o': 2330284194Sdelphij case 'x': 2331284194Sdelphij case 'X': 2332284194Sdelphij return h != 0 ? -1 : 0; 2333284194Sdelphij default: 2334284194Sdelphij return -1; 2335284194Sdelphij } 2336284194Sdelphij 2337284194Sdelphij /* 2338284194Sdelphij * Don't accept h and hh modifiers. They make writing 2339284194Sdelphij * magic entries more complicated, for very little benefit 2340284194Sdelphij */ 2341284194Sdelphij case 'h': 2342284194Sdelphij if (h-- <= 0) 2343284194Sdelphij return -1; 2344284194Sdelphij switch (*ptr++) { 2345284194Sdelphij case 'h': 2346284194Sdelphij if (h-- <= 0) 2347284194Sdelphij return -1; 2348284194Sdelphij switch (*ptr++) { 2349284194Sdelphij case 'i': 2350284194Sdelphij case 'd': 2351284194Sdelphij case 'u': 2352284194Sdelphij case 'o': 2353284194Sdelphij case 'x': 2354284194Sdelphij case 'X': 2355284194Sdelphij return 0; 2356284194Sdelphij default: 2357284194Sdelphij return -1; 2358284194Sdelphij } 2359284194Sdelphij case 'i': 2360284194Sdelphij case 'd': 2361284194Sdelphij case 'u': 2362284194Sdelphij case 'o': 2363284194Sdelphij case 'x': 2364284194Sdelphij case 'X': 2365284194Sdelphij return h != 0 ? -1 : 0; 2366284194Sdelphij default: 2367284194Sdelphij return -1; 2368284194Sdelphij } 2369284194Sdelphij#endif 2370284194Sdelphij case 'c': 2371284194Sdelphij return h != 2 ? -1 : 0; 2372284194Sdelphij case 'i': 2373284194Sdelphij case 'd': 2374284194Sdelphij case 'u': 2375284194Sdelphij case 'o': 2376284194Sdelphij case 'x': 2377284194Sdelphij case 'X': 2378284194Sdelphij#ifdef STRICT_FORMAT 2379284194Sdelphij return h != 0 ? -1 : 0; 2380284194Sdelphij#else 2381284194Sdelphij return 0; 2382284194Sdelphij#endif 2383284194Sdelphij default: 2384284194Sdelphij return -1; 2385284194Sdelphij } 2386284194Sdelphij 2387284194Sdelphij case FILE_FMT_FLOAT: 2388284194Sdelphij case FILE_FMT_DOUBLE: 2389284194Sdelphij if (*ptr == '-') 2390284194Sdelphij ptr++; 2391284194Sdelphij if (*ptr == '.') 2392284194Sdelphij ptr++; 2393284194Sdelphij while (isdigit((unsigned char)*ptr)) ptr++; 2394284194Sdelphij if (*ptr == '.') 2395284194Sdelphij ptr++; 2396284194Sdelphij while (isdigit((unsigned char)*ptr)) ptr++; 2397284194Sdelphij 2398284194Sdelphij switch (*ptr++) { 2399284194Sdelphij case 'e': 2400284194Sdelphij case 'E': 2401284194Sdelphij case 'f': 2402284194Sdelphij case 'F': 2403284194Sdelphij case 'g': 2404284194Sdelphij case 'G': 2405284194Sdelphij return 0; 2406284194Sdelphij 2407284194Sdelphij default: 2408284194Sdelphij return -1; 2409284194Sdelphij } 2410284194Sdelphij 2411284194Sdelphij 2412284194Sdelphij case FILE_FMT_STR: 2413284194Sdelphij if (*ptr == '-') 2414284194Sdelphij ptr++; 2415284194Sdelphij while (isdigit((unsigned char )*ptr)) 2416284194Sdelphij ptr++; 2417284194Sdelphij if (*ptr == '.') { 2418284194Sdelphij ptr++; 2419284194Sdelphij while (isdigit((unsigned char )*ptr)) 2420284194Sdelphij ptr++; 2421284194Sdelphij } 2422284194Sdelphij 2423284194Sdelphij switch (*ptr++) { 2424284194Sdelphij case 's': 2425284194Sdelphij return 0; 2426284194Sdelphij default: 2427284194Sdelphij return -1; 2428284194Sdelphij } 2429284194Sdelphij 2430284194Sdelphij default: 2431284194Sdelphij /* internal error */ 2432284194Sdelphij abort(); 2433284194Sdelphij } 2434284194Sdelphij /*NOTREACHED*/ 2435284194Sdelphij return -1; 2436284194Sdelphij} 2437284194Sdelphij 2438284194Sdelphij/* 2439284194Sdelphij * Check that the optional printf format in description matches 2440284194Sdelphij * the type of the magic. 2441284194Sdelphij */ 2442284194Sdelphijprivate int 2443284194Sdelphijcheck_format(struct magic_set *ms, struct magic *m) 2444284194Sdelphij{ 2445284194Sdelphij char *ptr; 2446284194Sdelphij 2447284194Sdelphij for (ptr = m->desc; *ptr; ptr++) 2448284194Sdelphij if (*ptr == '%') 2449284194Sdelphij break; 2450284194Sdelphij if (*ptr == '\0') { 2451284194Sdelphij /* No format string; ok */ 2452284194Sdelphij return 1; 2453284194Sdelphij } 2454284194Sdelphij 2455284194Sdelphij assert(file_nformats == file_nnames); 2456284194Sdelphij 2457284194Sdelphij if (m->type >= file_nformats) { 2458284194Sdelphij file_magwarn(ms, "Internal error inconsistency between " 2459284194Sdelphij "m->type and format strings"); 2460284194Sdelphij return -1; 2461284194Sdelphij } 2462284194Sdelphij if (file_formats[m->type] == FILE_FMT_NONE) { 2463284194Sdelphij file_magwarn(ms, "No format string for `%s' with description " 2464284194Sdelphij "`%s'", m->desc, file_names[m->type]); 2465284194Sdelphij return -1; 2466284194Sdelphij } 2467284194Sdelphij 2468284194Sdelphij ptr++; 2469284194Sdelphij if (check_format_type(ptr, m->type) == -1) { 2470284194Sdelphij /* 2471284194Sdelphij * TODO: this error message is unhelpful if the format 2472284194Sdelphij * string is not one character long 2473284194Sdelphij */ 2474284194Sdelphij file_magwarn(ms, "Printf format `%c' is not valid for type " 2475284194Sdelphij "`%s' in description `%s'", *ptr ? *ptr : '?', 2476284194Sdelphij file_names[m->type], m->desc); 2477284194Sdelphij return -1; 2478284194Sdelphij } 2479284194Sdelphij 2480284194Sdelphij for (; *ptr; ptr++) { 2481284194Sdelphij if (*ptr == '%') { 2482284194Sdelphij file_magwarn(ms, 2483284194Sdelphij "Too many format strings (should have at most one) " 2484284194Sdelphij "for `%s' with description `%s'", 2485284194Sdelphij file_names[m->type], m->desc); 2486284194Sdelphij return -1; 2487284194Sdelphij } 2488284194Sdelphij } 2489284194Sdelphij return 0; 2490284194Sdelphij} 2491284194Sdelphij 2492284194Sdelphij/* 2493284194Sdelphij * Read a numeric value from a pointer, into the value union of a magic 2494284194Sdelphij * pointer, according to the magic type. Update the string pointer to point 2495284194Sdelphij * just after the number read. Return 0 for success, non-zero for failure. 2496284194Sdelphij */ 2497284194Sdelphijprivate int 2498284194Sdelphijgetvalue(struct magic_set *ms, struct magic *m, const char **p, int action) 2499284194Sdelphij{ 2500284194Sdelphij switch (m->type) { 2501284194Sdelphij case FILE_BESTRING16: 2502284194Sdelphij case FILE_LESTRING16: 2503284194Sdelphij case FILE_STRING: 2504284194Sdelphij case FILE_PSTRING: 2505284194Sdelphij case FILE_REGEX: 2506284194Sdelphij case FILE_SEARCH: 2507284194Sdelphij case FILE_NAME: 2508284194Sdelphij case FILE_USE: 2509284194Sdelphij *p = getstr(ms, m, *p, action == FILE_COMPILE); 2510284194Sdelphij if (*p == NULL) { 2511284194Sdelphij if (ms->flags & MAGIC_CHECK) 2512284194Sdelphij file_magwarn(ms, "cannot get string from `%s'", 2513284194Sdelphij m->value.s); 2514284194Sdelphij return -1; 2515284194Sdelphij } 2516284194Sdelphij if (m->type == FILE_REGEX) { 2517284194Sdelphij file_regex_t rx; 2518284194Sdelphij int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED); 2519284194Sdelphij if (rc) { 2520284194Sdelphij if (ms->flags & MAGIC_CHECK) 2521284194Sdelphij file_regerror(&rx, rc, ms); 2522284194Sdelphij } 2523284194Sdelphij file_regfree(&rx); 2524284194Sdelphij return rc ? -1 : 0; 2525284194Sdelphij } 2526284194Sdelphij return 0; 2527284194Sdelphij case FILE_FLOAT: 2528284194Sdelphij case FILE_BEFLOAT: 2529284194Sdelphij case FILE_LEFLOAT: 2530284194Sdelphij if (m->reln != 'x') { 2531284194Sdelphij char *ep; 2532284194Sdelphij#ifdef HAVE_STRTOF 2533284194Sdelphij m->value.f = strtof(*p, &ep); 2534284194Sdelphij#else 2535284194Sdelphij m->value.f = (float)strtod(*p, &ep); 2536284194Sdelphij#endif 2537284194Sdelphij *p = ep; 2538284194Sdelphij } 2539284194Sdelphij return 0; 2540284194Sdelphij case FILE_DOUBLE: 2541284194Sdelphij case FILE_BEDOUBLE: 2542284194Sdelphij case FILE_LEDOUBLE: 2543284194Sdelphij if (m->reln != 'x') { 2544284194Sdelphij char *ep; 2545284194Sdelphij m->value.d = strtod(*p, &ep); 2546284194Sdelphij *p = ep; 2547284194Sdelphij } 2548284194Sdelphij return 0; 2549284194Sdelphij default: 2550284194Sdelphij if (m->reln != 'x') { 2551284194Sdelphij char *ep; 2552284194Sdelphij m->value.q = file_signextend(ms, m, 2553284194Sdelphij (uint64_t)strtoull(*p, &ep, 0)); 2554284194Sdelphij *p = ep; 2555284194Sdelphij eatsize(p); 2556284194Sdelphij } 2557284194Sdelphij return 0; 2558284194Sdelphij } 2559284194Sdelphij} 2560284194Sdelphij 2561284194Sdelphij/* 2562284194Sdelphij * Convert a string containing C character escapes. Stop at an unescaped 2563284194Sdelphij * space or tab. 2564284194Sdelphij * Copy the converted version to "m->value.s", and the length in m->vallen. 2565284194Sdelphij * Return updated scan pointer as function result. Warn if set. 2566284194Sdelphij */ 2567284194Sdelphijprivate const char * 2568284194Sdelphijgetstr(struct magic_set *ms, struct magic *m, const char *s, int warn) 2569284194Sdelphij{ 2570284194Sdelphij const char *origs = s; 2571284194Sdelphij char *p = m->value.s; 2572284194Sdelphij size_t plen = sizeof(m->value.s); 2573284194Sdelphij char *origp = p; 2574284194Sdelphij char *pmax = p + plen - 1; 2575284194Sdelphij int c; 2576284194Sdelphij int val; 2577284194Sdelphij 2578284194Sdelphij while ((c = *s++) != '\0') { 2579284194Sdelphij if (isspace((unsigned char) c)) 2580284194Sdelphij break; 2581284194Sdelphij if (p >= pmax) { 2582284194Sdelphij file_error(ms, 0, "string too long: `%s'", origs); 2583284194Sdelphij return NULL; 2584284194Sdelphij } 2585284194Sdelphij if (c == '\\') { 2586284194Sdelphij switch(c = *s++) { 2587284194Sdelphij 2588284194Sdelphij case '\0': 2589284194Sdelphij if (warn) 2590284194Sdelphij file_magwarn(ms, "incomplete escape"); 2591284194Sdelphij goto out; 2592284194Sdelphij 2593284194Sdelphij case '\t': 2594284194Sdelphij if (warn) { 2595284194Sdelphij file_magwarn(ms, 2596284194Sdelphij "escaped tab found, use \\t instead"); 2597284194Sdelphij warn = 0; /* already did */ 2598284194Sdelphij } 2599284194Sdelphij /*FALLTHROUGH*/ 2600284194Sdelphij default: 2601284194Sdelphij if (warn) { 2602284194Sdelphij if (isprint((unsigned char)c)) { 2603284194Sdelphij /* Allow escaping of 2604284194Sdelphij * ``relations'' */ 2605284194Sdelphij if (strchr("<>&^=!", c) == NULL 2606284194Sdelphij && (m->type != FILE_REGEX || 2607284194Sdelphij strchr("[]().*?^$|{}", c) 2608284194Sdelphij == NULL)) { 2609284194Sdelphij file_magwarn(ms, "no " 2610284194Sdelphij "need to escape " 2611284194Sdelphij "`%c'", c); 2612284194Sdelphij } 2613284194Sdelphij } else { 2614284194Sdelphij file_magwarn(ms, 2615284194Sdelphij "unknown escape sequence: " 2616284194Sdelphij "\\%03o", c); 2617284194Sdelphij } 2618284194Sdelphij } 2619284194Sdelphij /*FALLTHROUGH*/ 2620284194Sdelphij /* space, perhaps force people to use \040? */ 2621284194Sdelphij case ' ': 2622284194Sdelphij#if 0 2623284194Sdelphij /* 2624284194Sdelphij * Other things people escape, but shouldn't need to, 2625284194Sdelphij * so we disallow them 2626284194Sdelphij */ 2627284194Sdelphij case '\'': 2628284194Sdelphij case '"': 2629284194Sdelphij case '?': 2630284194Sdelphij#endif 2631284194Sdelphij /* Relations */ 2632284194Sdelphij case '>': 2633284194Sdelphij case '<': 2634284194Sdelphij case '&': 2635284194Sdelphij case '^': 2636284194Sdelphij case '=': 2637284194Sdelphij case '!': 2638284194Sdelphij /* and baskslash itself */ 2639284194Sdelphij case '\\': 2640284194Sdelphij *p++ = (char) c; 2641284194Sdelphij break; 2642284194Sdelphij 2643284194Sdelphij case 'a': 2644284194Sdelphij *p++ = '\a'; 2645284194Sdelphij break; 2646284194Sdelphij 2647284194Sdelphij case 'b': 2648284194Sdelphij *p++ = '\b'; 2649284194Sdelphij break; 2650284194Sdelphij 2651284194Sdelphij case 'f': 2652284194Sdelphij *p++ = '\f'; 2653284194Sdelphij break; 2654284194Sdelphij 2655284194Sdelphij case 'n': 2656284194Sdelphij *p++ = '\n'; 2657284194Sdelphij break; 2658284194Sdelphij 2659284194Sdelphij case 'r': 2660284194Sdelphij *p++ = '\r'; 2661284194Sdelphij break; 2662284194Sdelphij 2663284194Sdelphij case 't': 2664284194Sdelphij *p++ = '\t'; 2665284194Sdelphij break; 2666284194Sdelphij 2667284194Sdelphij case 'v': 2668284194Sdelphij *p++ = '\v'; 2669284194Sdelphij break; 2670284194Sdelphij 2671284194Sdelphij /* \ and up to 3 octal digits */ 2672284194Sdelphij case '0': 2673284194Sdelphij case '1': 2674284194Sdelphij case '2': 2675284194Sdelphij case '3': 2676284194Sdelphij case '4': 2677284194Sdelphij case '5': 2678284194Sdelphij case '6': 2679284194Sdelphij case '7': 2680284194Sdelphij val = c - '0'; 2681284194Sdelphij c = *s++; /* try for 2 */ 2682284194Sdelphij if (c >= '0' && c <= '7') { 2683284194Sdelphij val = (val << 3) | (c - '0'); 2684284194Sdelphij c = *s++; /* try for 3 */ 2685284194Sdelphij if (c >= '0' && c <= '7') 2686284194Sdelphij val = (val << 3) | (c-'0'); 2687284194Sdelphij else 2688284194Sdelphij --s; 2689284194Sdelphij } 2690284194Sdelphij else 2691284194Sdelphij --s; 2692284194Sdelphij *p++ = (char)val; 2693284194Sdelphij break; 2694284194Sdelphij 2695284194Sdelphij /* \x and up to 2 hex digits */ 2696284194Sdelphij case 'x': 2697284194Sdelphij val = 'x'; /* Default if no digits */ 2698284194Sdelphij c = hextoint(*s++); /* Get next char */ 2699284194Sdelphij if (c >= 0) { 2700284194Sdelphij val = c; 2701284194Sdelphij c = hextoint(*s++); 2702284194Sdelphij if (c >= 0) 2703284194Sdelphij val = (val << 4) + c; 2704284194Sdelphij else 2705284194Sdelphij --s; 2706284194Sdelphij } else 2707284194Sdelphij --s; 2708284194Sdelphij *p++ = (char)val; 2709284194Sdelphij break; 2710284194Sdelphij } 2711284194Sdelphij } else 2712284194Sdelphij *p++ = (char)c; 2713284194Sdelphij } 2714284194Sdelphijout: 2715284194Sdelphij *p = '\0'; 2716284194Sdelphij m->vallen = CAST(unsigned char, (p - origp)); 2717284194Sdelphij if (m->type == FILE_PSTRING) 2718284194Sdelphij m->vallen += (unsigned char)file_pstring_length_size(m); 2719284194Sdelphij return s; 2720284194Sdelphij} 2721284194Sdelphij 2722284194Sdelphij 2723284194Sdelphij/* Single hex char to int; -1 if not a hex char. */ 2724284194Sdelphijprivate int 2725284194Sdelphijhextoint(int c) 2726284194Sdelphij{ 2727284194Sdelphij if (!isascii((unsigned char) c)) 2728284194Sdelphij return -1; 2729284194Sdelphij if (isdigit((unsigned char) c)) 2730284194Sdelphij return c - '0'; 2731284194Sdelphij if ((c >= 'a') && (c <= 'f')) 2732284194Sdelphij return c + 10 - 'a'; 2733284194Sdelphij if (( c>= 'A') && (c <= 'F')) 2734284194Sdelphij return c + 10 - 'A'; 2735284194Sdelphij return -1; 2736284194Sdelphij} 2737284194Sdelphij 2738284194Sdelphij 2739284194Sdelphij/* 2740284194Sdelphij * Print a string containing C character escapes. 2741284194Sdelphij */ 2742284194Sdelphijprotected void 2743284194Sdelphijfile_showstr(FILE *fp, const char *s, size_t len) 2744284194Sdelphij{ 2745284194Sdelphij char c; 2746284194Sdelphij 2747284194Sdelphij for (;;) { 2748284194Sdelphij if (len == ~0U) { 2749284194Sdelphij c = *s++; 2750284194Sdelphij if (c == '\0') 2751284194Sdelphij break; 2752284194Sdelphij } 2753284194Sdelphij else { 2754284194Sdelphij if (len-- == 0) 2755284194Sdelphij break; 2756284194Sdelphij c = *s++; 2757284194Sdelphij } 2758284194Sdelphij if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */ 2759284194Sdelphij (void) fputc(c, fp); 2760284194Sdelphij else { 2761284194Sdelphij (void) fputc('\\', fp); 2762284194Sdelphij switch (c) { 2763284194Sdelphij case '\a': 2764284194Sdelphij (void) fputc('a', fp); 2765284194Sdelphij break; 2766284194Sdelphij 2767284194Sdelphij case '\b': 2768284194Sdelphij (void) fputc('b', fp); 2769284194Sdelphij break; 2770284194Sdelphij 2771284194Sdelphij case '\f': 2772284194Sdelphij (void) fputc('f', fp); 2773284194Sdelphij break; 2774284194Sdelphij 2775284194Sdelphij case '\n': 2776284194Sdelphij (void) fputc('n', fp); 2777284194Sdelphij break; 2778284194Sdelphij 2779284194Sdelphij case '\r': 2780284194Sdelphij (void) fputc('r', fp); 2781284194Sdelphij break; 2782284194Sdelphij 2783284194Sdelphij case '\t': 2784284194Sdelphij (void) fputc('t', fp); 2785284194Sdelphij break; 2786284194Sdelphij 2787284194Sdelphij case '\v': 2788284194Sdelphij (void) fputc('v', fp); 2789284194Sdelphij break; 2790284194Sdelphij 2791284194Sdelphij default: 2792284194Sdelphij (void) fprintf(fp, "%.3o", c & 0377); 2793284194Sdelphij break; 2794284194Sdelphij } 2795284194Sdelphij } 2796284194Sdelphij } 2797284194Sdelphij} 2798284194Sdelphij 2799284194Sdelphij/* 2800284194Sdelphij * eatsize(): Eat the size spec from a number [eg. 10UL] 2801284194Sdelphij */ 2802284194Sdelphijprivate void 2803284194Sdelphijeatsize(const char **p) 2804284194Sdelphij{ 2805284194Sdelphij const char *l = *p; 2806284194Sdelphij 2807284194Sdelphij if (LOWCASE(*l) == 'u') 2808284194Sdelphij l++; 2809284194Sdelphij 2810284194Sdelphij switch (LOWCASE(*l)) { 2811284194Sdelphij case 'l': /* long */ 2812284194Sdelphij case 's': /* short */ 2813284194Sdelphij case 'h': /* short */ 2814284194Sdelphij case 'b': /* char/byte */ 2815284194Sdelphij case 'c': /* char/byte */ 2816284194Sdelphij l++; 2817284194Sdelphij /*FALLTHROUGH*/ 2818284194Sdelphij default: 2819284194Sdelphij break; 2820284194Sdelphij } 2821284194Sdelphij 2822284194Sdelphij *p = l; 2823284194Sdelphij} 2824284194Sdelphij 2825284194Sdelphij/* 2826284194Sdelphij * handle a buffer containing a compiled file. 2827284194Sdelphij */ 2828284194Sdelphijprivate struct magic_map * 2829284194Sdelphijapprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 2830284194Sdelphij{ 2831284194Sdelphij struct magic_map *map; 2832284194Sdelphij 2833284194Sdelphij if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 2834284194Sdelphij file_oomem(ms, sizeof(*map)); 2835284194Sdelphij return NULL; 2836284194Sdelphij } 2837284194Sdelphij map->len = len; 2838284194Sdelphij map->p = buf; 2839284194Sdelphij map->type = MAP_TYPE_USER; 2840284194Sdelphij if (check_buffer(ms, map, "buffer") != 0) { 2841284194Sdelphij apprentice_unmap(map); 2842284194Sdelphij return NULL; 2843284194Sdelphij } 2844284194Sdelphij return map; 2845284194Sdelphij} 2846284194Sdelphij 2847284194Sdelphij/* 2848284194Sdelphij * handle a compiled file. 2849284194Sdelphij */ 2850284194Sdelphij 2851284194Sdelphijprivate struct magic_map * 2852284194Sdelphijapprentice_map(struct magic_set *ms, const char *fn) 2853284194Sdelphij{ 2854284194Sdelphij int fd; 2855284194Sdelphij struct stat st; 2856284194Sdelphij char *dbname = NULL; 2857284194Sdelphij struct magic_map *map; 2858284194Sdelphij 2859284194Sdelphij fd = -1; 2860284194Sdelphij if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 2861284194Sdelphij file_oomem(ms, sizeof(*map)); 2862284194Sdelphij goto error; 2863284194Sdelphij } 2864284194Sdelphij 2865284194Sdelphij dbname = mkdbname(ms, fn, 0); 2866284194Sdelphij if (dbname == NULL) 2867284194Sdelphij goto error; 2868284194Sdelphij 2869284194Sdelphij if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 2870284194Sdelphij goto error; 2871284194Sdelphij 2872284194Sdelphij if (fstat(fd, &st) == -1) { 2873284194Sdelphij file_error(ms, errno, "cannot stat `%s'", dbname); 2874284194Sdelphij goto error; 2875284194Sdelphij } 2876284194Sdelphij if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) { 2877284194Sdelphij file_error(ms, 0, "file `%s' is too %s", dbname, 2878284194Sdelphij st.st_size < 8 ? "small" : "large"); 2879284194Sdelphij goto error; 2880284194Sdelphij } 2881284194Sdelphij 2882284194Sdelphij map->len = (size_t)st.st_size; 2883284194Sdelphij#ifdef QUICK 2884284194Sdelphij if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE, 2885284194Sdelphij MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) { 2886284194Sdelphij file_error(ms, errno, "cannot map `%s'", dbname); 2887284194Sdelphij goto error; 2888284194Sdelphij } 2889284194Sdelphij map->type = MAP_TYPE_MMAP; 2890284194Sdelphij#else 2891284194Sdelphij if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 2892284194Sdelphij file_oomem(ms, map->len); 2893284194Sdelphij goto error; 2894284194Sdelphij } 2895284194Sdelphij if (read(fd, map->p, map->len) != (ssize_t)map->len) { 2896284194Sdelphij file_badread(ms); 2897284194Sdelphij goto error; 2898284194Sdelphij } 2899284194Sdelphij map->type = MAP_TYPE_MALLOC; 2900284194Sdelphij#define RET 1 2901284194Sdelphij#endif 2902284194Sdelphij (void)close(fd); 2903284194Sdelphij fd = -1; 2904284194Sdelphij 2905284194Sdelphij if (check_buffer(ms, map, dbname) != 0) 2906284194Sdelphij goto error; 2907284194Sdelphij 2908284194Sdelphij free(dbname); 2909284194Sdelphij return map; 2910284194Sdelphij 2911284194Sdelphijerror: 2912284194Sdelphij if (fd != -1) 2913284194Sdelphij (void)close(fd); 2914284194Sdelphij apprentice_unmap(map); 2915284194Sdelphij free(dbname); 2916284194Sdelphij return NULL; 2917284194Sdelphij} 2918284194Sdelphij 2919284194Sdelphijprivate int 2920284194Sdelphijcheck_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 2921284194Sdelphij{ 2922284194Sdelphij uint32_t *ptr; 2923284194Sdelphij uint32_t entries, nentries; 2924284194Sdelphij uint32_t version; 2925284194Sdelphij int i, needsbyteswap; 2926284194Sdelphij 2927284194Sdelphij ptr = CAST(uint32_t *, map->p); 2928284194Sdelphij if (*ptr != MAGICNO) { 2929284194Sdelphij if (swap4(*ptr) != MAGICNO) { 2930284194Sdelphij file_error(ms, 0, "bad magic in `%s'", dbname); 2931284194Sdelphij return -1; 2932284194Sdelphij } 2933284194Sdelphij needsbyteswap = 1; 2934284194Sdelphij } else 2935284194Sdelphij needsbyteswap = 0; 2936284194Sdelphij if (needsbyteswap) 2937284194Sdelphij version = swap4(ptr[1]); 2938284194Sdelphij else 2939284194Sdelphij version = ptr[1]; 2940284194Sdelphij if (version != VERSIONNO) { 2941284194Sdelphij file_error(ms, 0, "File %s supports only version %d magic " 2942284194Sdelphij "files. `%s' is version %d", VERSION, 2943284194Sdelphij VERSIONNO, dbname, version); 2944284194Sdelphij return -1; 2945284194Sdelphij } 2946284194Sdelphij entries = (uint32_t)(map->len / sizeof(struct magic)); 2947284194Sdelphij if ((entries * sizeof(struct magic)) != map->len) { 2948284194Sdelphij file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " 2949284194Sdelphij "a multiple of %" SIZE_T_FORMAT "u", 2950284194Sdelphij dbname, map->len, sizeof(struct magic)); 2951284194Sdelphij return -1; 2952284194Sdelphij } 2953284194Sdelphij map->magic[0] = CAST(struct magic *, map->p) + 1; 2954284194Sdelphij nentries = 0; 2955284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 2956284194Sdelphij if (needsbyteswap) 2957284194Sdelphij map->nmagic[i] = swap4(ptr[i + 2]); 2958284194Sdelphij else 2959284194Sdelphij map->nmagic[i] = ptr[i + 2]; 2960284194Sdelphij if (i != MAGIC_SETS - 1) 2961284194Sdelphij map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 2962284194Sdelphij nentries += map->nmagic[i]; 2963284194Sdelphij } 2964284194Sdelphij if (entries != nentries + 1) { 2965284194Sdelphij file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 2966284194Sdelphij dbname, entries, nentries + 1); 2967284194Sdelphij return -1; 2968284194Sdelphij } 2969284194Sdelphij if (needsbyteswap) 2970284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) 2971284194Sdelphij byteswap(map->magic[i], map->nmagic[i]); 2972284194Sdelphij return 0; 2973284194Sdelphij} 2974284194Sdelphij 2975284194Sdelphij/* 2976284194Sdelphij * handle an mmaped file. 2977284194Sdelphij */ 2978284194Sdelphijprivate int 2979284194Sdelphijapprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn) 2980284194Sdelphij{ 2981284194Sdelphij static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 2982284194Sdelphij static const size_t m = sizeof(**map->magic); 2983284194Sdelphij int fd = -1; 2984284194Sdelphij size_t len; 2985284194Sdelphij char *dbname; 2986284194Sdelphij int rv = -1; 2987284194Sdelphij uint32_t i; 2988284194Sdelphij union { 2989284194Sdelphij struct magic m; 2990284194Sdelphij uint32_t h[2 + MAGIC_SETS]; 2991284194Sdelphij } hdr; 2992284194Sdelphij 2993284194Sdelphij dbname = mkdbname(ms, fn, 1); 2994284194Sdelphij 2995284194Sdelphij if (dbname == NULL) 2996284194Sdelphij goto out; 2997284194Sdelphij 2998284194Sdelphij if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 2999284194Sdelphij { 3000284194Sdelphij file_error(ms, errno, "cannot open `%s'", dbname); 3001284194Sdelphij goto out; 3002284194Sdelphij } 3003284194Sdelphij memset(&hdr, 0, sizeof(hdr)); 3004284194Sdelphij hdr.h[0] = MAGICNO; 3005284194Sdelphij hdr.h[1] = VERSIONNO; 3006284194Sdelphij memcpy(hdr.h + 2, map->nmagic, nm); 3007284194Sdelphij 3008284194Sdelphij if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { 3009284194Sdelphij file_error(ms, errno, "error writing `%s'", dbname); 3010284194Sdelphij goto out; 3011284194Sdelphij } 3012284194Sdelphij 3013284194Sdelphij for (i = 0; i < MAGIC_SETS; i++) { 3014284194Sdelphij len = m * map->nmagic[i]; 3015284194Sdelphij if (write(fd, map->magic[i], len) != (ssize_t)len) { 3016284194Sdelphij file_error(ms, errno, "error writing `%s'", dbname); 3017284194Sdelphij goto out; 3018284194Sdelphij } 3019284194Sdelphij } 3020284194Sdelphij 3021284194Sdelphij if (fd != -1) 3022284194Sdelphij (void)close(fd); 3023284194Sdelphij rv = 0; 3024284194Sdelphijout: 3025284194Sdelphij free(dbname); 3026284194Sdelphij return rv; 3027284194Sdelphij} 3028284194Sdelphij 3029284194Sdelphijprivate const char ext[] = ".mgc"; 3030284194Sdelphij/* 3031284194Sdelphij * make a dbname 3032284194Sdelphij */ 3033284194Sdelphijprivate char * 3034284194Sdelphijmkdbname(struct magic_set *ms, const char *fn, int strip) 3035284194Sdelphij{ 3036284194Sdelphij const char *p, *q; 3037284194Sdelphij char *buf; 3038284194Sdelphij 3039284194Sdelphij if (strip) { 3040284194Sdelphij if ((p = strrchr(fn, '/')) != NULL) 3041284194Sdelphij fn = ++p; 3042284194Sdelphij } 3043284194Sdelphij 3044284194Sdelphij for (q = fn; *q; q++) 3045284194Sdelphij continue; 3046284194Sdelphij /* Look for .mgc */ 3047284194Sdelphij for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--) 3048284194Sdelphij if (*p != *q) 3049284194Sdelphij break; 3050284194Sdelphij 3051284194Sdelphij /* Did not find .mgc, restore q */ 3052284194Sdelphij if (p >= ext) 3053284194Sdelphij while (*q) 3054284194Sdelphij q++; 3055284194Sdelphij 3056284194Sdelphij q++; 3057284194Sdelphij /* Compatibility with old code that looked in .mime */ 3058284194Sdelphij if (ms->flags & MAGIC_MIME) { 3059284194Sdelphij if (asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext) < 0) 3060284194Sdelphij return NULL; 3061284194Sdelphij if (access(buf, R_OK) != -1) { 3062284194Sdelphij ms->flags &= MAGIC_MIME_TYPE; 3063284194Sdelphij return buf; 3064284194Sdelphij } 3065284194Sdelphij free(buf); 3066284194Sdelphij } 3067284194Sdelphij if (asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext) < 0) 3068284194Sdelphij return NULL; 3069284194Sdelphij 3070284194Sdelphij /* Compatibility with old code that looked in .mime */ 3071284194Sdelphij if (strstr(p, ".mime") != NULL) 3072284194Sdelphij ms->flags &= MAGIC_MIME_TYPE; 3073284194Sdelphij return buf; 3074284194Sdelphij} 3075284194Sdelphij 3076284194Sdelphij/* 3077284194Sdelphij * Byteswap an mmap'ed file if needed 3078284194Sdelphij */ 3079284194Sdelphijprivate void 3080284194Sdelphijbyteswap(struct magic *magic, uint32_t nmagic) 3081284194Sdelphij{ 3082284194Sdelphij uint32_t i; 3083284194Sdelphij for (i = 0; i < nmagic; i++) 3084284194Sdelphij bs1(&magic[i]); 3085284194Sdelphij} 3086284194Sdelphij 3087284194Sdelphij/* 3088284194Sdelphij * swap a short 3089284194Sdelphij */ 3090284194Sdelphijprivate uint16_t 3091284194Sdelphijswap2(uint16_t sv) 3092284194Sdelphij{ 3093284194Sdelphij uint16_t rv; 3094284194Sdelphij uint8_t *s = (uint8_t *)(void *)&sv; 3095284194Sdelphij uint8_t *d = (uint8_t *)(void *)&rv; 3096284194Sdelphij d[0] = s[1]; 3097284194Sdelphij d[1] = s[0]; 3098284194Sdelphij return rv; 3099284194Sdelphij} 3100284194Sdelphij 3101284194Sdelphij/* 3102284194Sdelphij * swap an int 3103284194Sdelphij */ 3104284194Sdelphijprivate uint32_t 3105284194Sdelphijswap4(uint32_t sv) 3106284194Sdelphij{ 3107284194Sdelphij uint32_t rv; 3108284194Sdelphij uint8_t *s = (uint8_t *)(void *)&sv; 3109284194Sdelphij uint8_t *d = (uint8_t *)(void *)&rv; 3110284194Sdelphij d[0] = s[3]; 3111284194Sdelphij d[1] = s[2]; 3112284194Sdelphij d[2] = s[1]; 3113284194Sdelphij d[3] = s[0]; 3114284194Sdelphij return rv; 3115284194Sdelphij} 3116284194Sdelphij 3117284194Sdelphij/* 3118284194Sdelphij * swap a quad 3119284194Sdelphij */ 3120284194Sdelphijprivate uint64_t 3121284194Sdelphijswap8(uint64_t sv) 3122284194Sdelphij{ 3123284194Sdelphij uint64_t rv; 3124284194Sdelphij uint8_t *s = (uint8_t *)(void *)&sv; 3125284194Sdelphij uint8_t *d = (uint8_t *)(void *)&rv; 3126284194Sdelphij#if 0 3127284194Sdelphij d[0] = s[3]; 3128284194Sdelphij d[1] = s[2]; 3129284194Sdelphij d[2] = s[1]; 3130284194Sdelphij d[3] = s[0]; 3131284194Sdelphij d[4] = s[7]; 3132284194Sdelphij d[5] = s[6]; 3133284194Sdelphij d[6] = s[5]; 3134284194Sdelphij d[7] = s[4]; 3135284194Sdelphij#else 3136284194Sdelphij d[0] = s[7]; 3137284194Sdelphij d[1] = s[6]; 3138284194Sdelphij d[2] = s[5]; 3139284194Sdelphij d[3] = s[4]; 3140284194Sdelphij d[4] = s[3]; 3141284194Sdelphij d[5] = s[2]; 3142284194Sdelphij d[6] = s[1]; 3143284194Sdelphij d[7] = s[0]; 3144284194Sdelphij#endif 3145284194Sdelphij return rv; 3146284194Sdelphij} 3147284194Sdelphij 3148284194Sdelphij/* 3149284194Sdelphij * byteswap a single magic entry 3150284194Sdelphij */ 3151284194Sdelphijprivate void 3152284194Sdelphijbs1(struct magic *m) 3153284194Sdelphij{ 3154284194Sdelphij m->cont_level = swap2(m->cont_level); 3155284194Sdelphij m->offset = swap4((uint32_t)m->offset); 3156284194Sdelphij m->in_offset = swap4((uint32_t)m->in_offset); 3157284194Sdelphij m->lineno = swap4((uint32_t)m->lineno); 3158284194Sdelphij if (IS_STRING(m->type)) { 3159284194Sdelphij m->str_range = swap4(m->str_range); 3160284194Sdelphij m->str_flags = swap4(m->str_flags); 3161284194Sdelphij } 3162284194Sdelphij else { 3163284194Sdelphij m->value.q = swap8(m->value.q); 3164284194Sdelphij m->num_mask = swap8(m->num_mask); 3165284194Sdelphij } 3166284194Sdelphij} 3167284194Sdelphij 3168284194Sdelphijprotected size_t 3169284194Sdelphijfile_pstring_length_size(const struct magic *m) 3170284194Sdelphij{ 3171284194Sdelphij switch (m->str_flags & PSTRING_LEN) { 3172284194Sdelphij case PSTRING_1_LE: 3173284194Sdelphij return 1; 3174284194Sdelphij case PSTRING_2_LE: 3175284194Sdelphij case PSTRING_2_BE: 3176284194Sdelphij return 2; 3177284194Sdelphij case PSTRING_4_LE: 3178284194Sdelphij case PSTRING_4_BE: 3179284194Sdelphij return 4; 3180284194Sdelphij default: 3181284194Sdelphij abort(); /* Impossible */ 3182284194Sdelphij return 1; 3183284194Sdelphij } 3184284194Sdelphij} 3185284194Sdelphijprotected size_t 3186284194Sdelphijfile_pstring_get_length(const struct magic *m, const char *s) 3187284194Sdelphij{ 3188284194Sdelphij size_t len = 0; 3189284194Sdelphij 3190284194Sdelphij switch (m->str_flags & PSTRING_LEN) { 3191284194Sdelphij case PSTRING_1_LE: 3192284194Sdelphij len = *s; 3193284194Sdelphij break; 3194284194Sdelphij case PSTRING_2_LE: 3195284194Sdelphij len = (s[1] << 8) | s[0]; 3196284194Sdelphij break; 3197284194Sdelphij case PSTRING_2_BE: 3198284194Sdelphij len = (s[0] << 8) | s[1]; 3199284194Sdelphij break; 3200284194Sdelphij case PSTRING_4_LE: 3201284194Sdelphij len = (s[3] << 24) | (s[2] << 16) | (s[1] << 8) | s[0]; 3202284194Sdelphij break; 3203284194Sdelphij case PSTRING_4_BE: 3204284194Sdelphij len = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; 3205284194Sdelphij break; 3206284194Sdelphij default: 3207284194Sdelphij abort(); /* Impossible */ 3208284194Sdelphij } 3209284194Sdelphij 3210284194Sdelphij if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) 3211284194Sdelphij len -= file_pstring_length_size(m); 3212284194Sdelphij 3213284194Sdelphij return len; 3214284194Sdelphij} 3215284194Sdelphij 3216284194Sdelphijprotected int 3217284194Sdelphijfile_magicfind(struct magic_set *ms, const char *name, struct mlist *v) 3218284194Sdelphij{ 3219284194Sdelphij uint32_t i, j; 3220284194Sdelphij struct mlist *mlist, *ml; 3221284194Sdelphij 3222284194Sdelphij mlist = ms->mlist[1]; 3223284194Sdelphij 3224284194Sdelphij for (ml = mlist->next; ml != mlist; ml = ml->next) { 3225284194Sdelphij struct magic *ma = ml->magic; 3226284194Sdelphij uint32_t nma = ml->nmagic; 3227284194Sdelphij for (i = 0; i < nma; i++) { 3228284194Sdelphij if (ma[i].type != FILE_NAME) 3229284194Sdelphij continue; 3230284194Sdelphij if (strcmp(ma[i].value.s, name) == 0) { 3231284194Sdelphij v->magic = &ma[i]; 3232284194Sdelphij for (j = i + 1; j < nma; j++) 3233284194Sdelphij if (ma[j].cont_level == 0) 3234284194Sdelphij break; 3235284194Sdelphij v->nmagic = j - i; 3236284194Sdelphij return 0; 3237284194Sdelphij } 3238284194Sdelphij } 3239284194Sdelphij } 3240284194Sdelphij return -1; 3241284194Sdelphij} 3242