1/*
2 * Copyright (c) Ian F. Darwin 1986-1995.
3 * Software written by Ian F. Darwin and others;
4 * maintained 1995-present by Christos Zoulas and others.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice immediately at the beginning of the file, without modification,
11 *    this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/*
29 * apprentice - make one pass through /etc/magic, learning its secrets.
30 */
31
32#include "file.h"
33
34#ifndef	lint
35FILE_RCSID("@(#)$File: apprentice.c,v 1.158 2009/10/19 13:10:20 christos Exp $")
36#endif	/* lint */
37
38#include "magic.h"
39#include "patchlevel.h"
40#include <stdlib.h>
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44#include <string.h>
45#include <assert.h>
46#include <ctype.h>
47#include <fcntl.h>
48#ifdef QUICK
49#include <sys/mman.h>
50#endif
51#include <dirent.h>
52
53#define	EATAB {while (isascii((unsigned char) *l) && \
54		      isspace((unsigned char) *l))  ++l;}
55#define LOWCASE(l) (isupper((unsigned char) (l)) ? \
56			tolower((unsigned char) (l)) : (l))
57/*
58 * Work around a bug in headers on Digital Unix.
59 * At least confirmed for: OSF1 V4.0 878
60 */
61#if defined(__osf__) && defined(__DECC)
62#ifdef MAP_FAILED
63#undef MAP_FAILED
64#endif
65#endif
66
67#ifndef MAP_FAILED
68#define MAP_FAILED (void *) -1
69#endif
70
71#ifndef MAP_FILE
72#define MAP_FILE 0
73#endif
74
75#ifndef MAXPATHLEN
76#define MAXPATHLEN	1024
77#endif
78
79struct magic_entry {
80	struct magic *mp;
81	uint32_t cont_count;
82	uint32_t max_count;
83};
84
85int file_formats[FILE_NAMES_SIZE];
86const size_t file_nformats = FILE_NAMES_SIZE;
87const char *file_names[FILE_NAMES_SIZE];
88const size_t file_nnames = FILE_NAMES_SIZE;
89
90private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
91private int hextoint(int);
92private const char *getstr(struct magic_set *, struct magic *, const char *,
93    int);
94private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
95    const char *, size_t, int);
96private void eatsize(const char **);
97private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
98private size_t apprentice_magic_strength(const struct magic *);
99private int apprentice_sort(const void *, const void *);
100private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
101    const char *, int);
102private void byteswap(struct magic *, uint32_t);
103private void bs1(struct magic *);
104private uint16_t swap2(uint16_t);
105private uint32_t swap4(uint32_t);
106private uint64_t swap8(uint64_t);
107private char *mkdbname(struct magic_set *, const char *, int);
108private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
109    const char *);
110private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
111    const char *);
112private int check_format_type(const char *, int);
113private int check_format(struct magic_set *, struct magic *);
114private int get_op(char);
115private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
116private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
117private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
118
119
120private size_t maxmagic = 0;
121private size_t magicsize = sizeof(struct magic);
122
123private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
124
125private struct {
126	const char *name;
127	size_t len;
128	int (*fun)(struct magic_set *, struct magic_entry *, const char *);
129} bang[] = {
130#define	DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
131	DECLARE_FIELD(mime),
132	DECLARE_FIELD(apple),
133	DECLARE_FIELD(strength),
134#undef	DECLARE_FIELD
135	{ NULL, 0, NULL }
136};
137
138#ifdef COMPILE_ONLY
139
140int main(int, char *[]);
141
142int
143main(int argc, char *argv[])
144{
145	int ret;
146	struct magic_set *ms;
147	char *progname;
148
149	if ((progname = strrchr(argv[0], '/')) != NULL)
150		progname++;
151	else
152		progname = argv[0];
153
154	if (argc != 2) {
155		(void)fprintf(stderr, "Usage: %s file\n", progname);
156		return 1;
157	}
158
159	if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
160		(void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
161		return 1;
162	}
163	ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
164	if (ret == 1)
165		(void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
166	magic_close(ms);
167	return ret;
168}
169#endif /* COMPILE_ONLY */
170
171static const struct type_tbl_s {
172	const char name[16];
173	const size_t len;
174	const int type;
175	const int format;
176} type_tbl[] = {
177# define XX(s)		s, (sizeof(s) - 1)
178# define XX_NULL	"", 0
179	{ XX("byte"),		FILE_BYTE,		FILE_FMT_NUM },
180	{ XX("short"),		FILE_SHORT,		FILE_FMT_NUM },
181	{ XX("default"),	FILE_DEFAULT,		FILE_FMT_STR },
182	{ XX("long"),		FILE_LONG,		FILE_FMT_NUM },
183	{ XX("string"),		FILE_STRING,		FILE_FMT_STR },
184	{ XX("date"),		FILE_DATE,		FILE_FMT_STR },
185	{ XX("beshort"),	FILE_BESHORT,		FILE_FMT_NUM },
186	{ XX("belong"),		FILE_BELONG,		FILE_FMT_NUM },
187	{ XX("bedate"),		FILE_BEDATE,		FILE_FMT_STR },
188	{ XX("leshort"),	FILE_LESHORT,		FILE_FMT_NUM },
189	{ XX("lelong"),		FILE_LELONG,		FILE_FMT_NUM },
190	{ XX("ledate"),		FILE_LEDATE,		FILE_FMT_STR },
191	{ XX("pstring"),	FILE_PSTRING,		FILE_FMT_STR },
192	{ XX("ldate"),		FILE_LDATE,		FILE_FMT_STR },
193	{ XX("beldate"),	FILE_BELDATE,		FILE_FMT_STR },
194	{ XX("leldate"),	FILE_LELDATE,		FILE_FMT_STR },
195	{ XX("regex"),		FILE_REGEX,		FILE_FMT_STR },
196	{ XX("bestring16"),	FILE_BESTRING16,	FILE_FMT_STR },
197	{ XX("lestring16"),	FILE_LESTRING16,	FILE_FMT_STR },
198	{ XX("search"),		FILE_SEARCH,		FILE_FMT_STR },
199	{ XX("medate"),		FILE_MEDATE,		FILE_FMT_STR },
200	{ XX("meldate"),	FILE_MELDATE,		FILE_FMT_STR },
201	{ XX("melong"),		FILE_MELONG,		FILE_FMT_NUM },
202	{ XX("quad"),		FILE_QUAD,		FILE_FMT_QUAD },
203	{ XX("lequad"),		FILE_LEQUAD,		FILE_FMT_QUAD },
204	{ XX("bequad"),		FILE_BEQUAD,		FILE_FMT_QUAD },
205	{ XX("qdate"),		FILE_QDATE,		FILE_FMT_STR },
206	{ XX("leqdate"),	FILE_LEQDATE,		FILE_FMT_STR },
207	{ XX("beqdate"),	FILE_BEQDATE,		FILE_FMT_STR },
208	{ XX("qldate"),		FILE_QLDATE,		FILE_FMT_STR },
209	{ XX("leqldate"),	FILE_LEQLDATE,		FILE_FMT_STR },
210	{ XX("beqldate"),	FILE_BEQLDATE,		FILE_FMT_STR },
211	{ XX("float"),		FILE_FLOAT,		FILE_FMT_FLOAT },
212	{ XX("befloat"),	FILE_BEFLOAT,		FILE_FMT_FLOAT },
213	{ XX("lefloat"),	FILE_LEFLOAT,		FILE_FMT_FLOAT },
214	{ XX("double"),		FILE_DOUBLE,		FILE_FMT_DOUBLE },
215	{ XX("bedouble"),	FILE_BEDOUBLE,		FILE_FMT_DOUBLE },
216	{ XX("ledouble"),	FILE_LEDOUBLE,		FILE_FMT_DOUBLE },
217	{ XX("leid3"),		FILE_LEID3,		FILE_FMT_NUM },
218	{ XX("beid3"),		FILE_BEID3,		FILE_FMT_NUM },
219	{ XX("indirect"),	FILE_INDIRECT,		FILE_FMT_NONE },
220	{ XX_NULL,		FILE_INVALID,		FILE_FMT_NONE },
221# undef XX
222# undef XX_NULL
223};
224
225private int
226get_type(const char *l, const char **t)
227{
228	const struct type_tbl_s *p;
229
230	for (p = type_tbl; p->len; p++) {
231		if (strncmp(l, p->name, p->len) == 0) {
232			if (t)
233				*t = l + p->len;
234			break;
235		}
236	}
237	return p->type;
238}
239
240private void
241init_file_tables(void)
242{
243	static int done = 0;
244	const struct type_tbl_s *p;
245
246	if (done)
247		return;
248	done++;
249
250	for (p = type_tbl; p->len; p++) {
251		assert(p->type < FILE_NAMES_SIZE);
252		file_names[p->type] = p->name;
253		file_formats[p->type] = p->format;
254	}
255}
256
257/*
258 * Handle one file or directory.
259 */
260private int
261apprentice_1(struct magic_set *ms, const char *fn, int action,
262    struct mlist *mlist)
263{
264	struct magic *magic = NULL;
265	uint32_t nmagic = 0;
266	struct mlist *ml;
267	int rv = -1;
268	int mapped;
269
270	if (magicsize != FILE_MAGICSIZE) {
271		file_error(ms, 0, "magic element size %lu != %lu",
272		    (unsigned long)sizeof(*magic),
273		    (unsigned long)FILE_MAGICSIZE);
274		return -1;
275	}
276
277	if (action == FILE_COMPILE) {
278		rv = apprentice_load(ms, &magic, &nmagic, fn, action);
279		if (rv != 0)
280			return -1;
281		rv = apprentice_compile(ms, &magic, &nmagic, fn);
282		free(magic);
283		return rv;
284	}
285
286#ifndef COMPILE_ONLY
287	if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
288		if (ms->flags & MAGIC_CHECK)
289			file_magwarn(ms, "using regular magic file `%s'", fn);
290		rv = apprentice_load(ms, &magic, &nmagic, fn, action);
291		if (rv != 0)
292			return -1;
293	}
294
295	mapped = rv;
296
297	if (magic == NULL) {
298		file_delmagic(magic, mapped, nmagic);
299		return -1;
300	}
301
302	if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) {
303		file_delmagic(magic, mapped, nmagic);
304		file_oomem(ms, sizeof(*ml));
305		return -1;
306	}
307
308	ml->magic = magic;
309	ml->nmagic = nmagic;
310	ml->mapped = mapped;
311
312	mlist->prev->next = ml;
313	ml->prev = mlist->prev;
314	ml->next = mlist;
315	mlist->prev = ml;
316
317	return 0;
318#endif /* COMPILE_ONLY */
319}
320
321protected void
322file_delmagic(struct magic *p, int type, size_t entries)
323{
324	if (p == NULL)
325		return;
326	switch (type) {
327	case 2:
328#ifdef QUICK
329		p--;
330		(void)munmap((void *)p, sizeof(*p) * (entries + 1));
331		break;
332#else
333		(void)&entries;
334		abort();
335		/*NOTREACHED*/
336#endif
337	case 1:
338		p--;
339		/*FALLTHROUGH*/
340	case 0:
341		free(p);
342		break;
343	default:
344		abort();
345	}
346}
347
348/* const char *fn: list of magic files and directories */
349protected struct mlist *
350file_apprentice(struct magic_set *ms, const char *fn, int action)
351{
352	char *p, *mfn;
353	int file_err, errs = -1;
354	struct mlist *mlist;
355
356	if ((fn = magic_getpath(fn, action)) == NULL)
357		return NULL;
358
359	init_file_tables();
360
361	if ((mfn = strdup(fn)) == NULL) {
362		file_oomem(ms, strlen(fn));
363		return NULL;
364	}
365	fn = mfn;
366
367	if ((mlist = CAST(struct mlist *, malloc(sizeof(*mlist)))) == NULL) {
368		free(mfn);
369		file_oomem(ms, sizeof(*mlist));
370		return NULL;
371	}
372	mlist->next = mlist->prev = mlist;
373
374	while (fn) {
375		p = strchr(fn, PATHSEP);
376		if (p)
377			*p++ = '\0';
378		if (*fn == '\0')
379			break;
380		file_err = apprentice_1(ms, fn, action, mlist);
381		errs = MAX(errs, file_err);
382		fn = p;
383	}
384	if (errs == -1) {
385		free(mfn);
386		free(mlist);
387		mlist = NULL;
388		file_error(ms, 0, "could not find any magic files!");
389		return NULL;
390	}
391	free(mfn);
392	return mlist;
393}
394
395/*
396 * Get weight of this magic entry, for sorting purposes.
397 */
398private size_t
399apprentice_magic_strength(const struct magic *m)
400{
401#define MULT 10
402	size_t val = 2 * MULT;	/* baseline strength */
403
404	switch (m->type) {
405	case FILE_DEFAULT:	/* make sure this sorts last */
406		if (m->factor_op != FILE_FACTOR_OP_NONE)
407			abort();
408		return 0;
409
410	case FILE_BYTE:
411		val += 1 * MULT;
412		break;
413
414	case FILE_SHORT:
415	case FILE_LESHORT:
416	case FILE_BESHORT:
417		val += 2 * MULT;
418		break;
419
420	case FILE_LONG:
421	case FILE_LELONG:
422	case FILE_BELONG:
423	case FILE_MELONG:
424		val += 4 * MULT;
425		break;
426
427	case FILE_PSTRING:
428	case FILE_STRING:
429		val += m->vallen * MULT;
430		break;
431
432	case FILE_BESTRING16:
433	case FILE_LESTRING16:
434		val += m->vallen * MULT / 2;
435		break;
436
437	case FILE_SEARCH:
438	case FILE_REGEX:
439		val += m->vallen * MAX(MULT / m->vallen, 1);
440		break;
441
442	case FILE_DATE:
443	case FILE_LEDATE:
444	case FILE_BEDATE:
445	case FILE_MEDATE:
446	case FILE_LDATE:
447	case FILE_LELDATE:
448	case FILE_BELDATE:
449	case FILE_MELDATE:
450	case FILE_FLOAT:
451	case FILE_BEFLOAT:
452	case FILE_LEFLOAT:
453		val += 4 * MULT;
454		break;
455
456	case FILE_QUAD:
457	case FILE_BEQUAD:
458	case FILE_LEQUAD:
459	case FILE_QDATE:
460	case FILE_LEQDATE:
461	case FILE_BEQDATE:
462	case FILE_QLDATE:
463	case FILE_LEQLDATE:
464	case FILE_BEQLDATE:
465	case FILE_DOUBLE:
466	case FILE_BEDOUBLE:
467	case FILE_LEDOUBLE:
468		val += 8 * MULT;
469		break;
470
471	default:
472		val = 0;
473		(void)fprintf(stderr, "Bad type %d\n", m->type);
474		abort();
475	}
476
477	switch (m->reln) {
478	case 'x':	/* matches anything penalize */
479	case '!':       /* matches almost anything penalize */
480		val = 0;
481		break;
482
483	case '=':	/* Exact match, prefer */
484		val += MULT;
485		break;
486
487	case '>':
488	case '<':	/* comparison match reduce strength */
489		val -= 2 * MULT;
490		break;
491
492	case '^':
493	case '&':	/* masking bits, we could count them too */
494		val -= MULT;
495		break;
496
497	default:
498		(void)fprintf(stderr, "Bad relation %c\n", m->reln);
499		abort();
500	}
501
502	if (val == 0)	/* ensure we only return 0 for FILE_DEFAULT */
503		val = 1;
504
505	switch (m->factor_op) {
506	case FILE_FACTOR_OP_NONE:
507		break;
508	case FILE_FACTOR_OP_PLUS:
509		val += m->factor;
510		break;
511	case FILE_FACTOR_OP_MINUS:
512		val -= m->factor;
513		break;
514	case FILE_FACTOR_OP_TIMES:
515		val *= m->factor;
516		break;
517	case FILE_FACTOR_OP_DIV:
518		val /= m->factor;
519		break;
520	default:
521		abort();
522	}
523
524	/*
525	 * Magic entries with no description get a bonus because they depend
526	 * on subsequent magic entries to print something.
527	 */
528	if (m->desc[0] == '\0')
529		val++;
530	return val;
531}
532
533/*
534 * Sort callback for sorting entries by "strength" (basically length)
535 */
536private int
537apprentice_sort(const void *a, const void *b)
538{
539	const struct magic_entry *ma = CAST(const struct magic_entry *, a);
540	const struct magic_entry *mb = CAST(const struct magic_entry *, b);
541	size_t sa = apprentice_magic_strength(ma->mp);
542	size_t sb = apprentice_magic_strength(mb->mp);
543	if (sa == sb)
544		return 0;
545	else if (sa > sb)
546		return -1;
547	else
548		return 1;
549}
550
551private void
552set_test_type(struct magic *mstart, struct magic *m)
553{
554	switch (m->type) {
555	case FILE_BYTE:
556	case FILE_SHORT:
557	case FILE_LONG:
558	case FILE_DATE:
559	case FILE_BESHORT:
560	case FILE_BELONG:
561	case FILE_BEDATE:
562	case FILE_LESHORT:
563	case FILE_LELONG:
564	case FILE_LEDATE:
565	case FILE_LDATE:
566	case FILE_BELDATE:
567	case FILE_LELDATE:
568	case FILE_MEDATE:
569	case FILE_MELDATE:
570	case FILE_MELONG:
571	case FILE_QUAD:
572	case FILE_LEQUAD:
573	case FILE_BEQUAD:
574	case FILE_QDATE:
575	case FILE_LEQDATE:
576	case FILE_BEQDATE:
577	case FILE_QLDATE:
578	case FILE_LEQLDATE:
579	case FILE_BEQLDATE:
580	case FILE_FLOAT:
581	case FILE_BEFLOAT:
582	case FILE_LEFLOAT:
583	case FILE_DOUBLE:
584	case FILE_BEDOUBLE:
585	case FILE_LEDOUBLE:
586	case FILE_STRING:
587	case FILE_PSTRING:
588	case FILE_BESTRING16:
589	case FILE_LESTRING16:
590		/* binary test, set flag */
591		mstart->flag |= BINTEST;
592		break;
593	case FILE_REGEX:
594	case FILE_SEARCH:
595		/* Check for override */
596		if (mstart->str_flags & STRING_BINTEST)
597			mstart->flag |= BINTEST;
598		if (mstart->str_flags & STRING_TEXTTEST)
599			mstart->flag |= TEXTTEST;
600
601		if (mstart->flag & (TEXTTEST|BINTEST))
602			break;
603
604		/* binary test if pattern is not text */
605		if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
606		    NULL) <= 0)
607			mstart->flag |= BINTEST;
608		else
609			mstart->flag |= TEXTTEST;
610		break;
611	case FILE_DEFAULT:
612		/* can't deduce anything; we shouldn't see this at the
613		   top level anyway */
614		break;
615	case FILE_INVALID:
616	default:
617		/* invalid search type, but no need to complain here */
618		break;
619	}
620}
621
622/*
623 * Load and parse one file.
624 */
625private void
626load_1(struct magic_set *ms, int action, const char *fn, int *errs,
627   struct magic_entry **marray, uint32_t *marraycount)
628{
629	char line[BUFSIZ];
630	size_t lineno = 0;
631	FILE *f = fopen(ms->file = fn, "r");
632	if (f == NULL) {
633		if (errno != ENOENT)
634			file_error(ms, errno, "cannot read magic file `%s'",
635				   fn);
636		(*errs)++;
637	} else {
638		/* read and parse this file */
639		for (ms->line = 1;
640		    fgets(line, CAST(int, sizeof(line)), f) != NULL;
641		    ms->line++) {
642			size_t len;
643			len = strlen(line);
644			if (len == 0) /* null line, garbage, etc */
645				continue;
646			if (line[len - 1] == '\n') {
647				lineno++;
648				line[len - 1] = '\0'; /* delete newline */
649			}
650			if (line[0] == '\0')	/* empty, do not parse */
651				continue;
652			if (line[0] == '#')	/* comment, do not parse */
653				continue;
654			if (line[0] == '!' && line[1] == ':') {
655				size_t i;
656
657				for (i = 0; bang[i].name != NULL; i++) {
658					if (len - 2 > bang[i].len &&
659					    memcmp(bang[i].name, line + 2,
660					    bang[i].len) == 0)
661						break;
662				}
663				if (bang[i].name == NULL) {
664					file_error(ms, 0,
665					    "Unknown !: entry `%s'", line);
666					(*errs)++;
667					continue;
668				}
669				if (*marraycount == 0) {
670					file_error(ms, 0,
671					    "No current entry for :!%s type",
672						bang[i].name);
673					(*errs)++;
674					continue;
675				}
676				if ((*bang[i].fun)(ms,
677				    &(*marray)[*marraycount - 1],
678				    line + bang[i].len + 2) != 0) {
679					(*errs)++;
680					continue;
681				}
682				continue;
683			}
684			if (parse(ms, marray, marraycount, line, lineno,
685			    action) != 0)
686				(*errs)++;
687		}
688
689		(void)fclose(f);
690	}
691}
692
693/*
694 * parse a file or directory of files
695 * const char *fn: name of magic file or directory
696 */
697private int
698cmpstrp(const void *p1, const void *p2)
699{
700        return strcmp(*(char *const *)p1, *(char *const *)p2);
701}
702
703private int
704apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
705    const char *fn, int action)
706{
707	int errs = 0;
708	struct magic_entry *marray;
709	uint32_t marraycount, i, mentrycount = 0, starttest;
710	size_t slen, files = 0, maxfiles = 0;
711	char subfn[MAXPATHLEN], **filearr = NULL, *mfn;
712	struct stat st;
713	DIR *dir;
714	struct dirent *d;
715
716	ms->flags |= MAGIC_CHECK;	/* Enable checks for parsed files */
717
718        maxmagic = MAXMAGIS;
719	if ((marray = CAST(struct magic_entry *, calloc(maxmagic,
720	    sizeof(*marray)))) == NULL) {
721		file_oomem(ms, maxmagic * sizeof(*marray));
722		return -1;
723	}
724	marraycount = 0;
725
726	/* print silly verbose header for USG compat. */
727	if (action == FILE_CHECK)
728		(void)fprintf(stderr, "%s\n", usg_hdr);
729
730	/* load directory or file */
731	if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
732		dir = opendir(fn);
733		if (!dir) {
734			errs++;
735			goto out;
736		}
737		while ((d = readdir(dir)) != NULL) {
738			(void)snprintf(subfn, sizeof(subfn), "%s/%s",
739			    fn, d->d_name);
740			if (stat(subfn, &st) == -1 || !S_ISREG(st.st_mode))
741				continue;
742			if ((mfn = strdup(subfn)) == NULL) {
743				file_oomem(ms, strlen(subfn));
744				errs++;
745				goto out;
746			}
747			if (files >= maxfiles) {
748				size_t mlen;
749				maxfiles = (maxfiles + 1) * 2;
750				mlen = maxfiles * sizeof(*filearr);
751				if ((filearr = CAST(char **,
752				    realloc(filearr, mlen))) == NULL) {
753					file_oomem(ms, mlen);
754					errs++;
755					goto out;
756				}
757			}
758			filearr[files++] = mfn;
759		}
760		closedir(dir);
761		qsort(filearr, files, sizeof(*filearr), cmpstrp);
762		for (i = 0; i < files; i++) {
763			load_1(ms, action, filearr[i], &errs, &marray,
764			    &marraycount);
765			free(filearr[i]);
766		}
767		free(filearr);
768	} else
769		load_1(ms, action, fn, &errs, &marray, &marraycount);
770	if (errs)
771		goto out;
772
773	/* Set types of tests */
774	for (i = 0; i < marraycount; ) {
775		if (marray[i].mp->cont_level != 0) {
776			i++;
777			continue;
778		}
779
780		starttest = i;
781		do {
782			static const char text[] = "text";
783			static const char binary[] = "binary";
784			static const size_t len = sizeof(text);
785			set_test_type(marray[starttest].mp, marray[i].mp);
786			if ((ms->flags & MAGIC_DEBUG) == 0)
787				continue;
788			(void)fprintf(stderr, "%s%s%s: %s\n",
789			    marray[i].mp->mimetype,
790			    marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
791			    marray[i].mp->desc[0] ? marray[i].mp->desc :
792			    "(no description)",
793			    marray[i].mp->flag & BINTEST ? binary : text);
794			if (marray[i].mp->flag & BINTEST) {
795				char *p = strstr(marray[i].mp->desc, text);
796				if (p && (p == marray[i].mp->desc ||
797				    isspace((unsigned char)p[-1])) &&
798				    (p + len - marray[i].mp->desc ==
799				    MAXstring || (p[len] == '\0' ||
800				    isspace((unsigned char)p[len]))))
801					(void)fprintf(stderr, "*** Possible "
802					    "binary test for text type\n");
803			}
804		} while (++i < marraycount && marray[i].mp->cont_level != 0);
805	}
806
807	qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
808
809	/*
810	 * Make sure that any level 0 "default" line is last (if one exists).
811	 */
812	for (i = 0; i < marraycount; i++) {
813		if (marray[i].mp->cont_level == 0 &&
814		    marray[i].mp->type == FILE_DEFAULT) {
815			while (++i < marraycount)
816				if (marray[i].mp->cont_level == 0)
817					break;
818			if (i != marraycount) {
819				ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
820				file_magwarn(ms,
821				    "level 0 \"default\" did not sort last");
822			}
823			break;
824		}
825	}
826
827	for (i = 0; i < marraycount; i++)
828		mentrycount += marray[i].cont_count;
829
830	slen = sizeof(**magicp) * mentrycount;
831	if ((*magicp = CAST(struct magic *, malloc(slen))) == NULL) {
832		file_oomem(ms, slen);
833		errs++;
834		goto out;
835	}
836
837	mentrycount = 0;
838	for (i = 0; i < marraycount; i++) {
839		(void)memcpy(*magicp + mentrycount, marray[i].mp,
840		    marray[i].cont_count * sizeof(**magicp));
841		mentrycount += marray[i].cont_count;
842	}
843out:
844	for (i = 0; i < marraycount; i++)
845		free(marray[i].mp);
846	free(marray);
847	if (errs) {
848		*magicp = NULL;
849		*nmagicp = 0;
850		return errs;
851	} else {
852		*nmagicp = mentrycount;
853		return 0;
854	}
855
856}
857
858/*
859 * extend the sign bit if the comparison is to be signed
860 */
861protected uint64_t
862file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
863{
864	if (!(m->flag & UNSIGNED)) {
865		switch(m->type) {
866		/*
867		 * Do not remove the casts below.  They are
868		 * vital.  When later compared with the data,
869		 * the sign extension must have happened.
870		 */
871		case FILE_BYTE:
872			v = (char) v;
873			break;
874		case FILE_SHORT:
875		case FILE_BESHORT:
876		case FILE_LESHORT:
877			v = (short) v;
878			break;
879		case FILE_DATE:
880		case FILE_BEDATE:
881		case FILE_LEDATE:
882		case FILE_MEDATE:
883		case FILE_LDATE:
884		case FILE_BELDATE:
885		case FILE_LELDATE:
886		case FILE_MELDATE:
887		case FILE_LONG:
888		case FILE_BELONG:
889		case FILE_LELONG:
890		case FILE_MELONG:
891		case FILE_FLOAT:
892		case FILE_BEFLOAT:
893		case FILE_LEFLOAT:
894			v = (int32_t) v;
895			break;
896		case FILE_QUAD:
897		case FILE_BEQUAD:
898		case FILE_LEQUAD:
899		case FILE_QDATE:
900		case FILE_QLDATE:
901		case FILE_BEQDATE:
902		case FILE_BEQLDATE:
903		case FILE_LEQDATE:
904		case FILE_LEQLDATE:
905		case FILE_DOUBLE:
906		case FILE_BEDOUBLE:
907		case FILE_LEDOUBLE:
908			v = (int64_t) v;
909			break;
910		case FILE_STRING:
911		case FILE_PSTRING:
912		case FILE_BESTRING16:
913		case FILE_LESTRING16:
914		case FILE_REGEX:
915		case FILE_SEARCH:
916		case FILE_DEFAULT:
917		case FILE_INDIRECT:
918			break;
919		default:
920			if (ms->flags & MAGIC_CHECK)
921			    file_magwarn(ms, "cannot happen: m->type=%d\n",
922				    m->type);
923			return ~0U;
924		}
925	}
926	return v;
927}
928
929private int
930string_modifier_check(struct magic_set *ms, struct magic *m)
931{
932	if ((ms->flags & MAGIC_CHECK) == 0)
933		return 0;
934
935	switch (m->type) {
936	case FILE_BESTRING16:
937	case FILE_LESTRING16:
938		if (m->str_flags != 0) {
939			file_magwarn(ms,
940			    "no modifiers allowed for 16-bit strings\n");
941			return -1;
942		}
943		break;
944	case FILE_STRING:
945	case FILE_PSTRING:
946		if ((m->str_flags & REGEX_OFFSET_START) != 0) {
947			file_magwarn(ms,
948			    "'/%c' only allowed on regex and search\n",
949			    CHAR_REGEX_OFFSET_START);
950			return -1;
951		}
952		break;
953	case FILE_SEARCH:
954		if (m->str_range == 0) {
955			file_magwarn(ms,
956			    "missing range; defaulting to %d\n",
957                            STRING_DEFAULT_RANGE);
958			m->str_range = STRING_DEFAULT_RANGE;
959			return -1;
960		}
961		break;
962	case FILE_REGEX:
963		if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) {
964			file_magwarn(ms, "'/%c' not allowed on regex\n",
965			    CHAR_COMPACT_WHITESPACE);
966			return -1;
967		}
968		if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) {
969			file_magwarn(ms, "'/%c' not allowed on regex\n",
970			    CHAR_COMPACT_OPTIONAL_WHITESPACE);
971			return -1;
972		}
973		break;
974	default:
975		file_magwarn(ms, "coding error: m->type=%d\n",
976		    m->type);
977		return -1;
978	}
979	return 0;
980}
981
982private int
983get_op(char c)
984{
985	switch (c) {
986	case '&':
987		return FILE_OPAND;
988	case '|':
989		return FILE_OPOR;
990	case '^':
991		return FILE_OPXOR;
992	case '+':
993		return FILE_OPADD;
994	case '-':
995		return FILE_OPMINUS;
996	case '*':
997		return FILE_OPMULTIPLY;
998	case '/':
999		return FILE_OPDIVIDE;
1000	case '%':
1001		return FILE_OPMODULO;
1002	default:
1003		return -1;
1004	}
1005}
1006
1007#ifdef ENABLE_CONDITIONALS
1008private int
1009get_cond(const char *l, const char **t)
1010{
1011	static const struct cond_tbl_s {
1012		char name[8];
1013		size_t len;
1014		int cond;
1015	} cond_tbl[] = {
1016		{ "if",		2,	COND_IF },
1017		{ "elif",	4,	COND_ELIF },
1018		{ "else",	4,	COND_ELSE },
1019		{ "",		0,	COND_NONE },
1020	};
1021	const struct cond_tbl_s *p;
1022
1023	for (p = cond_tbl; p->len; p++) {
1024		if (strncmp(l, p->name, p->len) == 0 &&
1025		    isspace((unsigned char)l[p->len])) {
1026			if (t)
1027				*t = l + p->len;
1028			break;
1029		}
1030	}
1031	return p->cond;
1032}
1033
1034private int
1035check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
1036{
1037	int last_cond;
1038	last_cond = ms->c.li[cont_level].last_cond;
1039
1040	switch (cond) {
1041	case COND_IF:
1042		if (last_cond != COND_NONE && last_cond != COND_ELIF) {
1043			if (ms->flags & MAGIC_CHECK)
1044				file_magwarn(ms, "syntax error: `if'");
1045			return -1;
1046		}
1047		last_cond = COND_IF;
1048		break;
1049
1050	case COND_ELIF:
1051		if (last_cond != COND_IF && last_cond != COND_ELIF) {
1052			if (ms->flags & MAGIC_CHECK)
1053				file_magwarn(ms, "syntax error: `elif'");
1054			return -1;
1055		}
1056		last_cond = COND_ELIF;
1057		break;
1058
1059	case COND_ELSE:
1060		if (last_cond != COND_IF && last_cond != COND_ELIF) {
1061			if (ms->flags & MAGIC_CHECK)
1062				file_magwarn(ms, "syntax error: `else'");
1063			return -1;
1064		}
1065		last_cond = COND_NONE;
1066		break;
1067
1068	case COND_NONE:
1069		last_cond = COND_NONE;
1070		break;
1071	}
1072
1073	ms->c.li[cont_level].last_cond = last_cond;
1074	return 0;
1075}
1076#endif /* ENABLE_CONDITIONALS */
1077
1078/*
1079 * parse one line from magic file, put into magic[index++] if valid
1080 */
1081private int
1082parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
1083    const char *line, size_t lineno, int action)
1084{
1085#ifdef ENABLE_CONDITIONALS
1086	static uint32_t last_cont_level = 0;
1087#endif
1088	size_t i;
1089	struct magic_entry *me;
1090	struct magic *m;
1091	const char *l = line;
1092	char *t;
1093	int op;
1094	uint32_t cont_level;
1095
1096	cont_level = 0;
1097
1098	while (*l == '>') {
1099		++l;		/* step over */
1100		cont_level++;
1101	}
1102#ifdef ENABLE_CONDITIONALS
1103	if (cont_level == 0 || cont_level > last_cont_level)
1104		if (file_check_mem(ms, cont_level) == -1)
1105			return -1;
1106	last_cont_level = cont_level;
1107#endif
1108
1109#define ALLOC_CHUNK	(size_t)10
1110#define ALLOC_INCR	(size_t)200
1111
1112	if (cont_level != 0) {
1113		if (*nmentryp == 0) {
1114			file_error(ms, 0, "No current entry for continuation");
1115			return -1;
1116		}
1117		me = &(*mentryp)[*nmentryp - 1];
1118		if (me->cont_count == me->max_count) {
1119			struct magic *nm;
1120			size_t cnt = me->max_count + ALLOC_CHUNK;
1121			if ((nm = CAST(struct magic *, realloc(me->mp,
1122			    sizeof(*nm) * cnt))) == NULL) {
1123				file_oomem(ms, sizeof(*nm) * cnt);
1124				return -1;
1125			}
1126			me->mp = m = nm;
1127			me->max_count = CAST(uint32_t, cnt);
1128		}
1129		m = &me->mp[me->cont_count++];
1130		(void)memset(m, 0, sizeof(*m));
1131		m->cont_level = cont_level;
1132	} else {
1133		if (*nmentryp == maxmagic) {
1134			struct magic_entry *mp;
1135
1136			maxmagic += ALLOC_INCR;
1137			if ((mp = CAST(struct magic_entry *,
1138			    realloc(*mentryp, sizeof(*mp) * maxmagic))) ==
1139			    NULL) {
1140				file_oomem(ms, sizeof(*mp) * maxmagic);
1141				return -1;
1142			}
1143			(void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
1144			    ALLOC_INCR);
1145			*mentryp = mp;
1146		}
1147		me = &(*mentryp)[*nmentryp];
1148		if (me->mp == NULL) {
1149			size_t len = sizeof(*m) * ALLOC_CHUNK;
1150			if ((m = CAST(struct magic *, malloc(len))) == NULL) {
1151				file_oomem(ms, len);
1152				return -1;
1153			}
1154			me->mp = m;
1155			me->max_count = ALLOC_CHUNK;
1156		} else
1157			m = me->mp;
1158		(void)memset(m, 0, sizeof(*m));
1159		m->factor_op = FILE_FACTOR_OP_NONE;
1160		m->cont_level = 0;
1161		me->cont_count = 1;
1162	}
1163	m->lineno = CAST(uint32_t, lineno);
1164
1165	if (*l == '&') {  /* m->cont_level == 0 checked below. */
1166                ++l;            /* step over */
1167                m->flag |= OFFADD;
1168        }
1169	if (*l == '(') {
1170		++l;		/* step over */
1171		m->flag |= INDIR;
1172		if (m->flag & OFFADD)
1173			m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1174
1175		if (*l == '&') {  /* m->cont_level == 0 checked below */
1176			++l;            /* step over */
1177			m->flag |= OFFADD;
1178		}
1179	}
1180	/* Indirect offsets are not valid at level 0. */
1181	if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
1182		if (ms->flags & MAGIC_CHECK)
1183			file_magwarn(ms, "relative offset at level 0");
1184
1185	/* get offset, then skip over it */
1186	m->offset = (uint32_t)strtoul(l, &t, 0);
1187        if (l == t)
1188		if (ms->flags & MAGIC_CHECK)
1189			file_magwarn(ms, "offset `%s' invalid", l);
1190        l = t;
1191
1192	if (m->flag & INDIR) {
1193		m->in_type = FILE_LONG;
1194		m->in_offset = 0;
1195		/*
1196		 * read [.lbs][+-]nnnnn)
1197		 */
1198		if (*l == '.') {
1199			l++;
1200			switch (*l) {
1201			case 'l':
1202				m->in_type = FILE_LELONG;
1203				break;
1204			case 'L':
1205				m->in_type = FILE_BELONG;
1206				break;
1207			case 'm':
1208				m->in_type = FILE_MELONG;
1209				break;
1210			case 'h':
1211			case 's':
1212				m->in_type = FILE_LESHORT;
1213				break;
1214			case 'H':
1215			case 'S':
1216				m->in_type = FILE_BESHORT;
1217				break;
1218			case 'c':
1219			case 'b':
1220			case 'C':
1221			case 'B':
1222				m->in_type = FILE_BYTE;
1223				break;
1224			case 'e':
1225			case 'f':
1226			case 'g':
1227				m->in_type = FILE_LEDOUBLE;
1228				break;
1229			case 'E':
1230			case 'F':
1231			case 'G':
1232				m->in_type = FILE_BEDOUBLE;
1233				break;
1234			case 'i':
1235				m->in_type = FILE_LEID3;
1236				break;
1237			case 'I':
1238				m->in_type = FILE_BEID3;
1239				break;
1240			default:
1241				if (ms->flags & MAGIC_CHECK)
1242					file_magwarn(ms,
1243					    "indirect offset type `%c' invalid",
1244					    *l);
1245				break;
1246			}
1247			l++;
1248		}
1249
1250		m->in_op = 0;
1251		if (*l == '~') {
1252			m->in_op |= FILE_OPINVERSE;
1253			l++;
1254		}
1255		if ((op = get_op(*l)) != -1) {
1256			m->in_op |= op;
1257			l++;
1258		}
1259		if (*l == '(') {
1260			m->in_op |= FILE_OPINDIRECT;
1261			l++;
1262		}
1263		if (isdigit((unsigned char)*l) || *l == '-') {
1264			m->in_offset = (int32_t)strtol(l, &t, 0);
1265			if (l == t)
1266				if (ms->flags & MAGIC_CHECK)
1267					file_magwarn(ms,
1268					    "in_offset `%s' invalid", l);
1269			l = t;
1270		}
1271		if (*l++ != ')' ||
1272		    ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1273			if (ms->flags & MAGIC_CHECK)
1274				file_magwarn(ms,
1275				    "missing ')' in indirect offset");
1276	}
1277	EATAB;
1278
1279#ifdef ENABLE_CONDITIONALS
1280	m->cond = get_cond(l, &l);
1281	if (check_cond(ms, m->cond, cont_level) == -1)
1282		return -1;
1283
1284	EATAB;
1285#endif
1286
1287	switch (*l) {
1288	case 'd':
1289		if (!isalpha((unsigned char)l[1])) {
1290			m->type = FILE_LONG;
1291			++l;
1292		}
1293		if (isdigit((unsigned char)*l)) {
1294			switch (*l) {
1295			case '1':
1296				m->type = FILE_BYTE;
1297				++l;
1298				break;
1299			case '2':
1300				m->type = FILE_SHORT;
1301				++l;
1302				break;
1303			case '4':
1304				++l;
1305				break;
1306			}
1307		}
1308		break;
1309	case 's':
1310		if (!isalpha((unsigned char)l[1])) {
1311			m->type = FILE_STRING;
1312			++l;
1313		}
1314		break;
1315	case 'u':
1316		++l;
1317		m->flag |= UNSIGNED;
1318		if (!isalpha((unsigned char)*l)) {
1319			m->type = FILE_LONG;
1320		}
1321		if (isdigit((unsigned char)*l)) {
1322			switch (*l) {
1323			case '1':
1324				m->type = FILE_BYTE;
1325				++l;
1326				break;
1327			case '2':
1328				m->type = FILE_SHORT;
1329				++l;
1330				break;
1331			case '4':
1332				++l;
1333				break;
1334			}
1335		}
1336		break;
1337	}
1338
1339	if (!m->type) m->type = get_type(l, &l);
1340	if (m->type == FILE_INVALID) {
1341		if (ms->flags & MAGIC_CHECK)
1342			file_magwarn(ms, "type `%s' invalid", l);
1343		return -1;
1344	}
1345
1346	/* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1347	/* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1348
1349	m->mask_op = 0;
1350	if (*l == '~') {
1351		if (!IS_STRING(m->type))
1352			m->mask_op |= FILE_OPINVERSE;
1353		else if (ms->flags & MAGIC_CHECK)
1354			file_magwarn(ms, "'~' invalid for string types");
1355		++l;
1356	}
1357	m->str_range = 0;
1358	m->str_flags = 0;
1359	m->num_mask = 0;
1360	if ((op = get_op(*l)) != -1) {
1361		if (!IS_STRING(m->type)) {
1362			uint64_t val;
1363			++l;
1364			m->mask_op |= op;
1365			val = (uint64_t)strtoull(l, &t, 0);
1366			l = t;
1367			m->num_mask = file_signextend(ms, m, val);
1368			eatsize(&l);
1369		}
1370		else if (op == FILE_OPDIVIDE) {
1371			int have_range = 0;
1372			while (!isspace((unsigned char)*++l)) {
1373				switch (*l) {
1374				case '0':  case '1':  case '2':
1375				case '3':  case '4':  case '5':
1376				case '6':  case '7':  case '8':
1377				case '9':
1378					if (have_range &&
1379					    (ms->flags & MAGIC_CHECK))
1380						file_magwarn(ms,
1381						    "multiple ranges");
1382					have_range = 1;
1383					m->str_range = CAST(uint32_t,
1384					    strtoul(l, &t, 0));
1385					if (m->str_range == 0)
1386						file_magwarn(ms,
1387						    "zero range");
1388					l = t - 1;
1389					break;
1390				case CHAR_COMPACT_WHITESPACE:
1391					m->str_flags |= STRING_COMPACT_WHITESPACE;
1392					break;
1393				case CHAR_COMPACT_OPTIONAL_WHITESPACE:
1394					m->str_flags |=
1395					    STRING_COMPACT_OPTIONAL_WHITESPACE;
1396					break;
1397				case CHAR_IGNORE_LOWERCASE:
1398					m->str_flags |= STRING_IGNORE_LOWERCASE;
1399					break;
1400				case CHAR_IGNORE_UPPERCASE:
1401					m->str_flags |= STRING_IGNORE_UPPERCASE;
1402					break;
1403				case CHAR_REGEX_OFFSET_START:
1404					m->str_flags |= REGEX_OFFSET_START;
1405					break;
1406				case CHAR_BINTEST:
1407					m->str_flags |= STRING_BINTEST;
1408					break;
1409				case CHAR_TEXTTEST:
1410					m->str_flags |= STRING_TEXTTEST;
1411					break;
1412				default:
1413					if (ms->flags & MAGIC_CHECK)
1414						file_magwarn(ms,
1415						"string extension `%c' invalid",
1416						*l);
1417					return -1;
1418				}
1419				/* allow multiple '/' for readability */
1420				if (l[1] == '/' &&
1421				    !isspace((unsigned char)l[2]))
1422					l++;
1423			}
1424			if (string_modifier_check(ms, m) == -1)
1425				return -1;
1426		}
1427		else {
1428			if (ms->flags & MAGIC_CHECK)
1429				file_magwarn(ms, "invalid string op: %c", *t);
1430			return -1;
1431		}
1432	}
1433	/*
1434	 * We used to set mask to all 1's here, instead let's just not do
1435	 * anything if mask = 0 (unless you have a better idea)
1436	 */
1437	EATAB;
1438
1439	switch (*l) {
1440	case '>':
1441	case '<':
1442  		m->reln = *l;
1443  		++l;
1444		if (*l == '=') {
1445			if (ms->flags & MAGIC_CHECK) {
1446				file_magwarn(ms, "%c= not supported",
1447				    m->reln);
1448				return -1;
1449			}
1450		   ++l;
1451		}
1452		break;
1453	/* Old-style anding: "0 byte &0x80 dynamically linked" */
1454	case '&':
1455	case '^':
1456	case '=':
1457  		m->reln = *l;
1458  		++l;
1459		if (*l == '=') {
1460		   /* HP compat: ignore &= etc. */
1461		   ++l;
1462		}
1463		break;
1464	case '!':
1465		m->reln = *l;
1466		++l;
1467		break;
1468	default:
1469  		m->reln = '=';	/* the default relation */
1470		if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
1471		    isspace((unsigned char)l[1])) || !l[1])) {
1472			m->reln = *l;
1473			++l;
1474		}
1475		break;
1476	}
1477	/*
1478	 * Grab the value part, except for an 'x' reln.
1479	 */
1480	if (m->reln != 'x' && getvalue(ms, m, &l, action))
1481		return -1;
1482
1483	/*
1484	 * TODO finish this macro and start using it!
1485	 * #define offsetcheck {if (offset > HOWMANY-1)
1486	 *	magwarn("offset too big"); }
1487	 */
1488
1489	/*
1490	 * Now get last part - the description
1491	 */
1492	EATAB;
1493	if (l[0] == '\b') {
1494		++l;
1495		m->flag |= NOSPACE;
1496	} else if ((l[0] == '\\') && (l[1] == 'b')) {
1497		++l;
1498		++l;
1499		m->flag |= NOSPACE;
1500	}
1501	for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
1502		continue;
1503	if (i == sizeof(m->desc)) {
1504		m->desc[sizeof(m->desc) - 1] = '\0';
1505		if (ms->flags & MAGIC_CHECK)
1506			file_magwarn(ms, "description `%s' truncated", m->desc);
1507	}
1508
1509        /*
1510	 * We only do this check while compiling, or if any of the magic
1511	 * files were not compiled.
1512         */
1513        if (ms->flags & MAGIC_CHECK) {
1514		if (check_format(ms, m) == -1)
1515			return -1;
1516	}
1517#ifndef COMPILE_ONLY
1518	if (action == FILE_CHECK) {
1519		file_mdump(m);
1520	}
1521#endif
1522	m->mimetype[0] = '\0';		/* initialise MIME type to none */
1523	if (m->cont_level == 0)
1524		++(*nmentryp);		/* make room for next */
1525	return 0;
1526}
1527
1528/*
1529 * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
1530 * if valid
1531 */
1532private int
1533parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
1534{
1535	const char *l = line;
1536	char *el;
1537	unsigned long factor;
1538	struct magic *m = &me->mp[0];
1539
1540	if (m->factor_op != FILE_FACTOR_OP_NONE) {
1541		file_magwarn(ms,
1542		    "Current entry already has a strength type: %c %d",
1543		    m->factor_op, m->factor);
1544		return -1;
1545	}
1546	EATAB;
1547	switch (*l) {
1548	case FILE_FACTOR_OP_NONE:
1549	case FILE_FACTOR_OP_PLUS:
1550	case FILE_FACTOR_OP_MINUS:
1551	case FILE_FACTOR_OP_TIMES:
1552	case FILE_FACTOR_OP_DIV:
1553		m->factor_op = *l++;
1554		break;
1555	default:
1556		file_magwarn(ms, "Unknown factor op `%c'", *l);
1557		return -1;
1558	}
1559	EATAB;
1560	factor = strtoul(l, &el, 0);
1561	if (factor > 255) {
1562		file_magwarn(ms, "Too large factor `%lu'", factor);
1563		goto out;
1564	}
1565	if (*el && !isspace((unsigned char)*el)) {
1566		file_magwarn(ms, "Bad factor `%s'", l);
1567		goto out;
1568	}
1569	m->factor = (uint8_t)factor;
1570	if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
1571		file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
1572		    m->factor_op, m->factor);
1573		goto out;
1574	}
1575	return 0;
1576out:
1577	m->factor_op = FILE_FACTOR_OP_NONE;
1578	m->factor = 0;
1579	return -1;
1580}
1581
1582/*
1583 * Parse an Apple CREATOR/TYPE annotation from magic file and put it into magic[index - 1]
1584 */
1585private int
1586parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
1587{
1588	size_t i;
1589	const char *l = line;
1590	struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1591
1592	if (m->apple[0] != '\0') {
1593		file_magwarn(ms, "Current entry already has a APPLE type `%.8s',"
1594		    " new type `%s'", m->mimetype, l);
1595		return -1;
1596	}
1597
1598	EATAB;
1599	for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1600	     || strchr("-+/.", *l)) && i < sizeof(m->apple); m->apple[i++] = *l++)
1601		continue;
1602	if (i == sizeof(m->apple) && *l) {
1603		/* We don't need to NUL terminate here, printing handles it */
1604		if (ms->flags & MAGIC_CHECK)
1605			file_magwarn(ms, "APPLE type `%s' truncated %zu",
1606			    line, i);
1607	}
1608
1609	if (i > 0)
1610		return 0;
1611	else
1612		return -1;
1613}
1614
1615/*
1616 * parse a MIME annotation line from magic file, put into magic[index - 1]
1617 * if valid
1618 */
1619private int
1620parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
1621{
1622	size_t i;
1623	const char *l = line;
1624	struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1625
1626	if (m->mimetype[0] != '\0') {
1627		file_magwarn(ms, "Current entry already has a MIME type `%s',"
1628		    " new type `%s'", m->mimetype, l);
1629		return -1;
1630	}
1631
1632	EATAB;
1633	for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1634	     || strchr("-+/.", *l)) && i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
1635		continue;
1636	if (i == sizeof(m->mimetype)) {
1637		m->mimetype[sizeof(m->mimetype) - 1] = '\0';
1638		if (ms->flags & MAGIC_CHECK)
1639			file_magwarn(ms, "MIME type `%s' truncated %zu",
1640			    m->mimetype, i);
1641	} else
1642		m->mimetype[i] = '\0';
1643
1644	if (i > 0)
1645		return 0;
1646	else
1647		return -1;
1648}
1649
1650private int
1651check_format_type(const char *ptr, int type)
1652{
1653	int quad = 0;
1654	if (*ptr == '\0') {
1655		/* Missing format string; bad */
1656		return -1;
1657	}
1658
1659	switch (type) {
1660	case FILE_FMT_QUAD:
1661		quad = 1;
1662		/*FALLTHROUGH*/
1663	case FILE_FMT_NUM:
1664		if (*ptr == '-')
1665			ptr++;
1666		if (*ptr == '.')
1667			ptr++;
1668		while (isdigit((unsigned char)*ptr)) ptr++;
1669		if (*ptr == '.')
1670			ptr++;
1671		while (isdigit((unsigned char)*ptr)) ptr++;
1672		if (quad) {
1673			if (*ptr++ != 'l')
1674				return -1;
1675			if (*ptr++ != 'l')
1676				return -1;
1677		}
1678
1679		switch (*ptr++) {
1680		case 'l':
1681			switch (*ptr++) {
1682			case 'i':
1683			case 'd':
1684			case 'u':
1685			case 'x':
1686			case 'X':
1687				return 0;
1688			default:
1689				return -1;
1690			}
1691
1692		case 'h':
1693			switch (*ptr++) {
1694			case 'h':
1695				switch (*ptr++) {
1696				case 'i':
1697				case 'd':
1698				case 'u':
1699				case 'x':
1700				case 'X':
1701					return 0;
1702				default:
1703					return -1;
1704				}
1705			case 'd':
1706				return 0;
1707			default:
1708				return -1;
1709			}
1710
1711		case 'i':
1712		case 'c':
1713		case 'd':
1714		case 'u':
1715		case 'x':
1716		case 'X':
1717			return 0;
1718
1719		default:
1720			return -1;
1721		}
1722
1723	case FILE_FMT_FLOAT:
1724	case FILE_FMT_DOUBLE:
1725		if (*ptr == '-')
1726			ptr++;
1727		if (*ptr == '.')
1728			ptr++;
1729		while (isdigit((unsigned char)*ptr)) ptr++;
1730		if (*ptr == '.')
1731			ptr++;
1732		while (isdigit((unsigned char)*ptr)) ptr++;
1733
1734		switch (*ptr++) {
1735		case 'e':
1736		case 'E':
1737		case 'f':
1738		case 'F':
1739		case 'g':
1740		case 'G':
1741			return 0;
1742
1743		default:
1744			return -1;
1745		}
1746
1747
1748	case FILE_FMT_STR:
1749		if (*ptr == '-')
1750			ptr++;
1751		while (isdigit((unsigned char )*ptr))
1752			ptr++;
1753		if (*ptr == '.') {
1754			ptr++;
1755			while (isdigit((unsigned char )*ptr))
1756				ptr++;
1757		}
1758
1759		switch (*ptr++) {
1760		case 's':
1761			return 0;
1762		default:
1763			return -1;
1764		}
1765
1766	default:
1767		/* internal error */
1768		abort();
1769	}
1770	/*NOTREACHED*/
1771	return -1;
1772}
1773
1774/*
1775 * Check that the optional printf format in description matches
1776 * the type of the magic.
1777 */
1778private int
1779check_format(struct magic_set *ms, struct magic *m)
1780{
1781	char *ptr;
1782
1783	for (ptr = m->desc; *ptr; ptr++)
1784		if (*ptr == '%')
1785			break;
1786	if (*ptr == '\0') {
1787		/* No format string; ok */
1788		return 1;
1789	}
1790
1791	assert(file_nformats == file_nnames);
1792
1793	if (m->type >= file_nformats) {
1794		file_magwarn(ms, "Internal error inconsistency between "
1795		    "m->type and format strings");
1796		return -1;
1797	}
1798	if (file_formats[m->type] == FILE_FMT_NONE) {
1799		file_magwarn(ms, "No format string for `%s' with description "
1800		    "`%s'", m->desc, file_names[m->type]);
1801		return -1;
1802	}
1803
1804	ptr++;
1805	if (check_format_type(ptr, file_formats[m->type]) == -1) {
1806		/*
1807		 * TODO: this error message is unhelpful if the format
1808		 * string is not one character long
1809		 */
1810		file_magwarn(ms, "Printf format `%c' is not valid for type "
1811		    "`%s' in description `%s'", *ptr ? *ptr : '?',
1812		    file_names[m->type], m->desc);
1813		return -1;
1814	}
1815
1816	for (; *ptr; ptr++) {
1817		if (*ptr == '%') {
1818			file_magwarn(ms,
1819			    "Too many format strings (should have at most one) "
1820			    "for `%s' with description `%s'",
1821			    file_names[m->type], m->desc);
1822			return -1;
1823		}
1824	}
1825	return 0;
1826}
1827
1828/*
1829 * Read a numeric value from a pointer, into the value union of a magic
1830 * pointer, according to the magic type.  Update the string pointer to point
1831 * just after the number read.  Return 0 for success, non-zero for failure.
1832 */
1833private int
1834getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1835{
1836	switch (m->type) {
1837	case FILE_BESTRING16:
1838	case FILE_LESTRING16:
1839	case FILE_STRING:
1840	case FILE_PSTRING:
1841	case FILE_REGEX:
1842	case FILE_SEARCH:
1843		*p = getstr(ms, m, *p, action == FILE_COMPILE);
1844		if (*p == NULL) {
1845			if (ms->flags & MAGIC_CHECK)
1846				file_magwarn(ms, "cannot get string from `%s'",
1847				    m->value.s);
1848			return -1;
1849		}
1850		return 0;
1851	case FILE_FLOAT:
1852	case FILE_BEFLOAT:
1853	case FILE_LEFLOAT:
1854		if (m->reln != 'x') {
1855			char *ep;
1856#ifdef HAVE_STRTOF
1857			m->value.f = strtof(*p, &ep);
1858#else
1859			m->value.f = (float)strtod(*p, &ep);
1860#endif
1861			*p = ep;
1862		}
1863		return 0;
1864	case FILE_DOUBLE:
1865	case FILE_BEDOUBLE:
1866	case FILE_LEDOUBLE:
1867		if (m->reln != 'x') {
1868			char *ep;
1869			m->value.d = strtod(*p, &ep);
1870			*p = ep;
1871		}
1872		return 0;
1873	default:
1874		if (m->reln != 'x') {
1875			char *ep;
1876			m->value.q = file_signextend(ms, m,
1877			    (uint64_t)strtoull(*p, &ep, 0));
1878			*p = ep;
1879			eatsize(p);
1880		}
1881		return 0;
1882	}
1883}
1884
1885/*
1886 * Convert a string containing C character escapes.  Stop at an unescaped
1887 * space or tab.
1888 * Copy the converted version to "m->value.s", and the length in m->vallen.
1889 * Return updated scan pointer as function result. Warn if set.
1890 */
1891private const char *
1892getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
1893{
1894	const char *origs = s;
1895	char	*p = m->value.s;
1896	size_t  plen = sizeof(m->value.s);
1897	char 	*origp = p;
1898	char	*pmax = p + plen - 1;
1899	int	c;
1900	int	val;
1901
1902	while ((c = *s++) != '\0') {
1903		if (isspace((unsigned char) c))
1904			break;
1905		if (p >= pmax) {
1906			file_error(ms, 0, "string too long: `%s'", origs);
1907			return NULL;
1908		}
1909		if (c == '\\') {
1910			switch(c = *s++) {
1911
1912			case '\0':
1913				if (warn)
1914					file_magwarn(ms, "incomplete escape");
1915				goto out;
1916
1917			case '\t':
1918				if (warn) {
1919					file_magwarn(ms,
1920					    "escaped tab found, use \\t instead");
1921					warn = 0;	/* already did */
1922				}
1923				/*FALLTHROUGH*/
1924			default:
1925				if (warn) {
1926					if (isprint((unsigned char)c)) {
1927						/* Allow escaping of
1928						 * ``relations'' */
1929						if (strchr("<>&^=!", c)
1930						    == NULL) {
1931							file_magwarn(ms, "no "
1932							    "need to escape "
1933							    "`%c'", c);
1934						}
1935					} else {
1936						file_magwarn(ms,
1937						    "unknown escape sequence: "
1938						    "\\%03o", c);
1939					}
1940				}
1941				/*FALLTHROUGH*/
1942			/* space, perhaps force people to use \040? */
1943			case ' ':
1944#if 0
1945			/*
1946			 * Other things people escape, but shouldn't need to,
1947			 * so we disallow them
1948			 */
1949			case '\'':
1950			case '"':
1951			case '?':
1952#endif
1953			/* Relations */
1954			case '>':
1955			case '<':
1956			case '&':
1957			case '^':
1958			case '=':
1959			case '!':
1960			/* and baskslash itself */
1961			case '\\':
1962				*p++ = (char) c;
1963				break;
1964
1965			case 'a':
1966				*p++ = '\a';
1967				break;
1968
1969			case 'b':
1970				*p++ = '\b';
1971				break;
1972
1973			case 'f':
1974				*p++ = '\f';
1975				break;
1976
1977			case 'n':
1978				*p++ = '\n';
1979				break;
1980
1981			case 'r':
1982				*p++ = '\r';
1983				break;
1984
1985			case 't':
1986				*p++ = '\t';
1987				break;
1988
1989			case 'v':
1990				*p++ = '\v';
1991				break;
1992
1993			/* \ and up to 3 octal digits */
1994			case '0':
1995			case '1':
1996			case '2':
1997			case '3':
1998			case '4':
1999			case '5':
2000			case '6':
2001			case '7':
2002				val = c - '0';
2003				c = *s++;  /* try for 2 */
2004				if (c >= '0' && c <= '7') {
2005					val = (val << 3) | (c - '0');
2006					c = *s++;  /* try for 3 */
2007					if (c >= '0' && c <= '7')
2008						val = (val << 3) | (c-'0');
2009					else
2010						--s;
2011				}
2012				else
2013					--s;
2014				*p++ = (char)val;
2015				break;
2016
2017			/* \x and up to 2 hex digits */
2018			case 'x':
2019				val = 'x';	/* Default if no digits */
2020				c = hextoint(*s++);	/* Get next char */
2021				if (c >= 0) {
2022					val = c;
2023					c = hextoint(*s++);
2024					if (c >= 0)
2025						val = (val << 4) + c;
2026					else
2027						--s;
2028				} else
2029					--s;
2030				*p++ = (char)val;
2031				break;
2032			}
2033		} else
2034			*p++ = (char)c;
2035	}
2036out:
2037	*p = '\0';
2038	m->vallen = CAST(unsigned char, (p - origp));
2039	if (m->type == FILE_PSTRING)
2040		m->vallen++;
2041	return s;
2042}
2043
2044
2045/* Single hex char to int; -1 if not a hex char. */
2046private int
2047hextoint(int c)
2048{
2049	if (!isascii((unsigned char) c))
2050		return -1;
2051	if (isdigit((unsigned char) c))
2052		return c - '0';
2053	if ((c >= 'a') && (c <= 'f'))
2054		return c + 10 - 'a';
2055	if (( c>= 'A') && (c <= 'F'))
2056		return c + 10 - 'A';
2057	return -1;
2058}
2059
2060
2061/*
2062 * Print a string containing C character escapes.
2063 */
2064protected void
2065file_showstr(FILE *fp, const char *s, size_t len)
2066{
2067	char	c;
2068
2069	for (;;) {
2070		if (len == ~0U) {
2071			c = *s++;
2072			if (c == '\0')
2073				break;
2074		}
2075		else  {
2076			if (len-- == 0)
2077				break;
2078			c = *s++;
2079		}
2080		if (c >= 040 && c <= 0176)	/* TODO isprint && !iscntrl */
2081			(void) fputc(c, fp);
2082		else {
2083			(void) fputc('\\', fp);
2084			switch (c) {
2085			case '\a':
2086				(void) fputc('a', fp);
2087				break;
2088
2089			case '\b':
2090				(void) fputc('b', fp);
2091				break;
2092
2093			case '\f':
2094				(void) fputc('f', fp);
2095				break;
2096
2097			case '\n':
2098				(void) fputc('n', fp);
2099				break;
2100
2101			case '\r':
2102				(void) fputc('r', fp);
2103				break;
2104
2105			case '\t':
2106				(void) fputc('t', fp);
2107				break;
2108
2109			case '\v':
2110				(void) fputc('v', fp);
2111				break;
2112
2113			default:
2114				(void) fprintf(fp, "%.3o", c & 0377);
2115				break;
2116			}
2117		}
2118	}
2119}
2120
2121/*
2122 * eatsize(): Eat the size spec from a number [eg. 10UL]
2123 */
2124private void
2125eatsize(const char **p)
2126{
2127	const char *l = *p;
2128
2129	if (LOWCASE(*l) == 'u')
2130		l++;
2131
2132	switch (LOWCASE(*l)) {
2133	case 'l':    /* long */
2134	case 's':    /* short */
2135	case 'h':    /* short */
2136	case 'b':    /* char/byte */
2137	case 'c':    /* char/byte */
2138		l++;
2139		/*FALLTHROUGH*/
2140	default:
2141		break;
2142	}
2143
2144	*p = l;
2145}
2146
2147/*
2148 * handle a compiled file.
2149 */
2150private int
2151apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
2152    const char *fn)
2153{
2154	int fd;
2155	struct stat st;
2156	uint32_t *ptr;
2157	uint32_t version;
2158	int needsbyteswap;
2159	char *dbname = NULL;
2160	void *mm = NULL;
2161
2162	dbname = mkdbname(ms, fn, 0);
2163	if (dbname == NULL)
2164		goto error2;
2165
2166	if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
2167		goto error2;
2168
2169	if (fstat(fd, &st) == -1) {
2170		file_error(ms, errno, "cannot stat `%s'", dbname);
2171		goto error1;
2172	}
2173	if (st.st_size < 8) {
2174		file_error(ms, 0, "file `%s' is too small", dbname);
2175		goto error1;
2176	}
2177
2178#ifdef QUICK
2179	if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
2180	    MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
2181		file_error(ms, errno, "cannot map `%s'", dbname);
2182		goto error1;
2183	}
2184#define RET	2
2185#else
2186	if ((mm = CAST(void *, malloc((size_t)st.st_size))) == NULL) {
2187		file_oomem(ms, (size_t)st.st_size);
2188		goto error1;
2189	}
2190	if (read(fd, mm, (size_t)st.st_size) != (ssize_t)st.st_size) {
2191		file_badread(ms);
2192		goto error1;
2193	}
2194#define RET	1
2195#endif
2196	*magicp = CAST(struct magic *, mm);
2197	(void)close(fd);
2198	fd = -1;
2199	ptr = (uint32_t *)(void *)*magicp;
2200	if (*ptr != MAGICNO) {
2201		if (swap4(*ptr) != MAGICNO) {
2202			file_error(ms, 0, "bad magic in `%s'", dbname);
2203			goto error1;
2204		}
2205		needsbyteswap = 1;
2206	} else
2207		needsbyteswap = 0;
2208	if (needsbyteswap)
2209		version = swap4(ptr[1]);
2210	else
2211		version = ptr[1];
2212	if (version != VERSIONNO) {
2213		file_error(ms, 0, "File %d.%d supports only version %d magic "
2214		    "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
2215		    VERSIONNO, dbname, version);
2216		goto error1;
2217	}
2218	*nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
2219	if (*nmagicp > 0)
2220		(*nmagicp)--;
2221	(*magicp)++;
2222	if (needsbyteswap)
2223		byteswap(*magicp, *nmagicp);
2224	free(dbname);
2225	return RET;
2226
2227error1:
2228	if (fd != -1)
2229		(void)close(fd);
2230	if (mm) {
2231#ifdef QUICK
2232		(void)munmap((void *)mm, (size_t)st.st_size);
2233#else
2234		free(mm);
2235#endif
2236	} else {
2237		*magicp = NULL;
2238		*nmagicp = 0;
2239	}
2240error2:
2241	free(dbname);
2242	return -1;
2243}
2244
2245private const uint32_t ar[] = {
2246    MAGICNO, VERSIONNO
2247};
2248/*
2249 * handle an mmaped file.
2250 */
2251private int
2252apprentice_compile(struct magic_set *ms, struct magic **magicp,
2253    uint32_t *nmagicp, const char *fn)
2254{
2255	int fd;
2256	char *dbname;
2257	int rv = -1;
2258
2259	dbname = mkdbname(ms, fn, 1);
2260
2261	if (dbname == NULL)
2262		goto out;
2263
2264	if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
2265		file_error(ms, errno, "cannot open `%s'", dbname);
2266		goto out;
2267	}
2268
2269	if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
2270		file_error(ms, errno, "error writing `%s'", dbname);
2271		goto out;
2272	}
2273
2274	if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
2275	    != sizeof(struct magic)) {
2276		file_error(ms, errno, "error seeking `%s'", dbname);
2277		goto out;
2278	}
2279
2280	if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
2281	    != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
2282		file_error(ms, errno, "error writing `%s'", dbname);
2283		goto out;
2284	}
2285
2286	(void)close(fd);
2287	rv = 0;
2288out:
2289	free(dbname);
2290	return rv;
2291}
2292
2293private const char ext[] = ".mgc";
2294/*
2295 * make a dbname
2296 */
2297private char *
2298mkdbname(struct magic_set *ms, const char *fn, int strip)
2299{
2300	const char *p, *q;
2301	char *buf;
2302
2303	if (strip) {
2304		if ((p = strrchr(fn, '/')) != NULL)
2305			fn = ++p;
2306	}
2307
2308	for (q = fn; *q; q++)
2309		continue;
2310	/* Look for .mgc */
2311	for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
2312		if (*p != *q)
2313			break;
2314
2315	/* Did not find .mgc, restore q */
2316	if (p >= ext)
2317		while (*q)
2318			q++;
2319
2320	q++;
2321	/* Compatibility with old code that looked in .mime */
2322	if (ms->flags & MAGIC_MIME) {
2323		asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext);
2324		if (access(buf, R_OK) != -1) {
2325			ms->flags &= MAGIC_MIME_TYPE;
2326			return buf;
2327		}
2328		free(buf);
2329	}
2330	asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext);
2331
2332	/* Compatibility with old code that looked in .mime */
2333	if (strstr(p, ".mime") != NULL)
2334		ms->flags &= MAGIC_MIME_TYPE;
2335	return buf;
2336}
2337
2338/*
2339 * Byteswap an mmap'ed file if needed
2340 */
2341private void
2342byteswap(struct magic *magic, uint32_t nmagic)
2343{
2344	uint32_t i;
2345	for (i = 0; i < nmagic; i++)
2346		bs1(&magic[i]);
2347}
2348
2349/*
2350 * swap a short
2351 */
2352private uint16_t
2353swap2(uint16_t sv)
2354{
2355	uint16_t rv;
2356	uint8_t *s = (uint8_t *)(void *)&sv;
2357	uint8_t *d = (uint8_t *)(void *)&rv;
2358	d[0] = s[1];
2359	d[1] = s[0];
2360	return rv;
2361}
2362
2363/*
2364 * swap an int
2365 */
2366private uint32_t
2367swap4(uint32_t sv)
2368{
2369	uint32_t rv;
2370	uint8_t *s = (uint8_t *)(void *)&sv;
2371	uint8_t *d = (uint8_t *)(void *)&rv;
2372	d[0] = s[3];
2373	d[1] = s[2];
2374	d[2] = s[1];
2375	d[3] = s[0];
2376	return rv;
2377}
2378
2379/*
2380 * swap a quad
2381 */
2382private uint64_t
2383swap8(uint64_t sv)
2384{
2385	uint64_t rv;
2386	uint8_t *s = (uint8_t *)(void *)&sv;
2387	uint8_t *d = (uint8_t *)(void *)&rv;
2388#if 0
2389	d[0] = s[3];
2390	d[1] = s[2];
2391	d[2] = s[1];
2392	d[3] = s[0];
2393	d[4] = s[7];
2394	d[5] = s[6];
2395	d[6] = s[5];
2396	d[7] = s[4];
2397#else
2398	d[0] = s[7];
2399	d[1] = s[6];
2400	d[2] = s[5];
2401	d[3] = s[4];
2402	d[4] = s[3];
2403	d[5] = s[2];
2404	d[6] = s[1];
2405	d[7] = s[0];
2406#endif
2407	return rv;
2408}
2409
2410/*
2411 * byteswap a single magic entry
2412 */
2413private void
2414bs1(struct magic *m)
2415{
2416	m->cont_level = swap2(m->cont_level);
2417	m->offset = swap4((uint32_t)m->offset);
2418	m->in_offset = swap4((uint32_t)m->in_offset);
2419	m->lineno = swap4((uint32_t)m->lineno);
2420	if (IS_STRING(m->type)) {
2421		m->str_range = swap4(m->str_range);
2422		m->str_flags = swap4(m->str_flags);
2423	}
2424	else {
2425		m->value.q = swap8(m->value.q);
2426		m->num_mask = swap8(m->num_mask);
2427	}
2428}
2429