]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/file/src/apprentice.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / contrib / file / src / apprentice.c
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
35 FILE_RCSID("@(#)$File: apprentice.c,v 1.238 2015/09/12 18:10:42 christos Exp $")
36 #endif  /* lint */
37
38 #include "magic.h"
39 #include <stdlib.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #ifdef HAVE_STDDEF_H
44 #include <stddef.h>
45 #endif
46 #include <string.h>
47 #include <assert.h>
48 #include <ctype.h>
49 #include <fcntl.h>
50 #ifdef QUICK
51 #include <sys/mman.h>
52 #endif
53 #include <dirent.h>
54 #if defined(HAVE_LIMITS_H)
55 #include <limits.h>
56 #endif
57
58 #ifndef SSIZE_MAX
59 #define MAXMAGIC_SIZE        ((ssize_t)0x7fffffff)
60 #else
61 #define MAXMAGIC_SIZE        SSIZE_MAX
62 #endif
63
64 #define EATAB {while (isascii((unsigned char) *l) && \
65                       isspace((unsigned char) *l))  ++l;}
66 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
67                         tolower((unsigned char) (l)) : (l))
68 /*
69  * Work around a bug in headers on Digital Unix.
70  * At least confirmed for: OSF1 V4.0 878
71  */
72 #if defined(__osf__) && defined(__DECC)
73 #ifdef MAP_FAILED
74 #undef MAP_FAILED
75 #endif
76 #endif
77
78 #ifndef MAP_FAILED
79 #define MAP_FAILED (void *) -1
80 #endif
81
82 #ifndef MAP_FILE
83 #define MAP_FILE 0
84 #endif
85
86 #define ALLOC_CHUNK     (size_t)10
87 #define ALLOC_INCR      (size_t)200
88
89 #define MAP_TYPE_MMAP   0
90 #define MAP_TYPE_MALLOC 1
91 #define MAP_TYPE_USER   2
92
93 struct magic_entry {
94         struct magic *mp;       
95         uint32_t cont_count;
96         uint32_t max_count;
97 };
98
99 struct magic_entry_set {
100         struct magic_entry *me;
101         uint32_t count;
102         uint32_t max;
103 };
104
105 struct magic_map {
106         void *p;
107         size_t len;
108         int type;
109         struct magic *magic[MAGIC_SETS];
110         uint32_t nmagic[MAGIC_SETS];
111 };
112
113 int file_formats[FILE_NAMES_SIZE];
114 const size_t file_nformats = FILE_NAMES_SIZE;
115 const char *file_names[FILE_NAMES_SIZE];
116 const size_t file_nnames = FILE_NAMES_SIZE;
117
118 private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
119 private int hextoint(int);
120 private const char *getstr(struct magic_set *, struct magic *, const char *,
121     int);
122 private int parse(struct magic_set *, struct magic_entry *, const char *,
123     size_t, int);
124 private void eatsize(const char **);
125 private int apprentice_1(struct magic_set *, const char *, int);
126 private size_t apprentice_magic_strength(const struct magic *);
127 private int apprentice_sort(const void *, const void *);
128 private void apprentice_list(struct mlist *, int );
129 private struct magic_map *apprentice_load(struct magic_set *, 
130     const char *, int);
131 private struct mlist *mlist_alloc(void);
132 private void mlist_free(struct mlist *);
133 private void byteswap(struct magic *, uint32_t);
134 private void bs1(struct magic *);
135 private uint16_t swap2(uint16_t);
136 private uint32_t swap4(uint32_t);
137 private uint64_t swap8(uint64_t);
138 private char *mkdbname(struct magic_set *, const char *, int);
139 private struct magic_map *apprentice_buf(struct magic_set *, struct magic *,
140     size_t);
141 private struct magic_map *apprentice_map(struct magic_set *, const char *);
142 private int check_buffer(struct magic_set *, struct magic_map *, const char *);
143 private void apprentice_unmap(struct magic_map *);
144 private int apprentice_compile(struct magic_set *, struct magic_map *,
145     const char *);
146 private int check_format_type(const char *, int);
147 private int check_format(struct magic_set *, struct magic *);
148 private int get_op(char);
149 private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
150 private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
151 private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
152 private int parse_ext(struct magic_set *, struct magic_entry *, const char *);
153
154
155 private size_t magicsize = sizeof(struct magic);
156
157 private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
158
159 private struct {
160         const char *name;
161         size_t len;
162         int (*fun)(struct magic_set *, struct magic_entry *, const char *);
163 } bang[] = {
164 #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
165         DECLARE_FIELD(mime),
166         DECLARE_FIELD(apple),
167         DECLARE_FIELD(ext),
168         DECLARE_FIELD(strength),
169 #undef  DECLARE_FIELD
170         { NULL, 0, NULL }
171 };
172
173 #ifdef COMPILE_ONLY
174
175 int main(int, char *[]);
176
177 int
178 main(int argc, char *argv[])
179 {
180         int ret;
181         struct magic_set *ms;
182         char *progname;
183
184         if ((progname = strrchr(argv[0], '/')) != NULL)
185                 progname++;
186         else
187                 progname = argv[0];
188
189         if (argc != 2) {
190                 (void)fprintf(stderr, "Usage: %s file\n", progname);
191                 return 1;
192         }
193
194         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
195                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
196                 return 1;
197         }
198         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
199         if (ret == 1)
200                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
201         magic_close(ms);
202         return ret;
203 }
204 #endif /* COMPILE_ONLY */
205
206 struct type_tbl_s {
207         const char name[16];
208         const size_t len;
209         const int type;
210         const int format;
211 };
212
213 /*
214  * XXX - the actual Single UNIX Specification says that "long" means "long",
215  * as in the C data type, but we treat it as meaning "4-byte integer".
216  * Given that the OS X version of file 5.04 did the same, I guess that passes
217  * the actual test; having "long" be dependent on how big a "long" is on
218  * the machine running "file" is silly.
219  */
220 static const struct type_tbl_s type_tbl[] = {
221 # define XX(s)          s, (sizeof(s) - 1)
222 # define XX_NULL        "", 0
223         { XX("invalid"),        FILE_INVALID,           FILE_FMT_NONE },
224         { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
225         { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
226         { XX("default"),        FILE_DEFAULT,           FILE_FMT_NONE },
227         { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
228         { XX("string"),         FILE_STRING,            FILE_FMT_STR },
229         { XX("date"),           FILE_DATE,              FILE_FMT_STR },
230         { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
231         { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
232         { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
233         { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
234         { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
235         { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
236         { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
237         { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
238         { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
239         { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
240         { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
241         { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
242         { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
243         { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
244         { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
245         { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
246         { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
247         { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
248         { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
249         { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
250         { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
251         { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
252         { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
253         { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
254         { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
255         { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
256         { XX("float"),          FILE_FLOAT,             FILE_FMT_FLOAT },
257         { XX("befloat"),        FILE_BEFLOAT,           FILE_FMT_FLOAT },
258         { XX("lefloat"),        FILE_LEFLOAT,           FILE_FMT_FLOAT },
259         { XX("double"),         FILE_DOUBLE,            FILE_FMT_DOUBLE },
260         { XX("bedouble"),       FILE_BEDOUBLE,          FILE_FMT_DOUBLE },
261         { XX("ledouble"),       FILE_LEDOUBLE,          FILE_FMT_DOUBLE },
262         { XX("leid3"),          FILE_LEID3,             FILE_FMT_NUM },
263         { XX("beid3"),          FILE_BEID3,             FILE_FMT_NUM },
264         { XX("indirect"),       FILE_INDIRECT,          FILE_FMT_NUM },
265         { XX("qwdate"),         FILE_QWDATE,            FILE_FMT_STR },
266         { XX("leqwdate"),       FILE_LEQWDATE,          FILE_FMT_STR },
267         { XX("beqwdate"),       FILE_BEQWDATE,          FILE_FMT_STR },
268         { XX("name"),           FILE_NAME,              FILE_FMT_NONE },
269         { XX("use"),            FILE_USE,               FILE_FMT_NONE },
270         { XX("clear"),          FILE_CLEAR,             FILE_FMT_NONE },
271         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
272 };
273
274 /*
275  * These are not types, and cannot be preceded by "u" to make them
276  * unsigned.
277  */
278 static const struct type_tbl_s special_tbl[] = {
279         { XX("name"),           FILE_NAME,              FILE_FMT_STR },
280         { XX("use"),            FILE_USE,               FILE_FMT_STR },
281         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
282 };
283 # undef XX
284 # undef XX_NULL
285
286 private int
287 get_type(const struct type_tbl_s *tbl, const char *l, const char **t)
288 {
289         const struct type_tbl_s *p;
290
291         for (p = tbl; p->len; p++) {
292                 if (strncmp(l, p->name, p->len) == 0) {
293                         if (t)
294                                 *t = l + p->len;
295                         break;
296                 }
297         }
298         return p->type;
299 }
300
301 private int
302 get_standard_integer_type(const char *l, const char **t)
303 {
304         int type;
305
306         if (isalpha((unsigned char)l[1])) {
307                 switch (l[1]) {
308                 case 'C':
309                         /* "dC" and "uC" */
310                         type = FILE_BYTE;
311                         break;
312                 case 'S':
313                         /* "dS" and "uS" */
314                         type = FILE_SHORT;
315                         break;
316                 case 'I':
317                 case 'L':
318                         /*
319                          * "dI", "dL", "uI", and "uL".
320                          *
321                          * XXX - the actual Single UNIX Specification says
322                          * that "L" means "long", as in the C data type,
323                          * but we treat it as meaning "4-byte integer".
324                          * Given that the OS X version of file 5.04 did
325                          * the same, I guess that passes the actual SUS
326                          * validation suite; having "dL" be dependent on
327                          * how big a "long" is on the machine running
328                          * "file" is silly.
329                          */
330                         type = FILE_LONG;
331                         break;
332                 case 'Q':
333                         /* "dQ" and "uQ" */
334                         type = FILE_QUAD;
335                         break;
336                 default:
337                         /* "d{anything else}", "u{anything else}" */
338                         return FILE_INVALID;
339                 }
340                 l += 2;
341         } else if (isdigit((unsigned char)l[1])) {
342                 /*
343                  * "d{num}" and "u{num}"; we only support {num} values
344                  * of 1, 2, 4, and 8 - the Single UNIX Specification
345                  * doesn't say anything about whether arbitrary
346                  * values should be supported, but both the Solaris 10
347                  * and OS X Mountain Lion versions of file passed the
348                  * Single UNIX Specification validation suite, and
349                  * neither of them support values bigger than 8 or
350                  * non-power-of-2 values.
351                  */
352                 if (isdigit((unsigned char)l[2])) {
353                         /* Multi-digit, so > 9 */
354                         return FILE_INVALID;
355                 }
356                 switch (l[1]) {
357                 case '1':
358                         type = FILE_BYTE;
359                         break;
360                 case '2':
361                         type = FILE_SHORT;
362                         break;
363                 case '4':
364                         type = FILE_LONG;
365                         break;
366                 case '8':
367                         type = FILE_QUAD;
368                         break;
369                 default:
370                         /* XXX - what about 3, 5, 6, or 7? */
371                         return FILE_INVALID;
372                 }
373                 l += 2;
374         } else {
375                 /*
376                  * "d" or "u" by itself.
377                  */
378                 type = FILE_LONG;
379                 ++l;
380         }
381         if (t)
382                 *t = l;
383         return type;
384 }
385
386 private void
387 init_file_tables(void)
388 {
389         static int done = 0;
390         const struct type_tbl_s *p;
391
392         if (done)
393                 return;
394         done++;
395
396         for (p = type_tbl; p->len; p++) {
397                 assert(p->type < FILE_NAMES_SIZE);
398                 file_names[p->type] = p->name;
399                 file_formats[p->type] = p->format;
400         }
401         assert(p - type_tbl == FILE_NAMES_SIZE);
402 }
403
404 private int
405 add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx)
406 {
407         struct mlist *ml;
408
409         mlp->map = idx == 0 ? map : NULL;
410         if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL)
411                 return -1;
412
413         ml->map = NULL;
414         ml->magic = map->magic[idx];
415         ml->nmagic = map->nmagic[idx];
416
417         mlp->prev->next = ml;
418         ml->prev = mlp->prev;
419         ml->next = mlp;
420         mlp->prev = ml;
421         return 0;
422 }
423
424 /*
425  * Handle one file or directory.
426  */
427 private int
428 apprentice_1(struct magic_set *ms, const char *fn, int action)
429 {
430         struct magic_map *map;
431 #ifndef COMPILE_ONLY
432         struct mlist *ml;
433         size_t i;
434 #endif
435
436         if (magicsize != FILE_MAGICSIZE) {
437                 file_error(ms, 0, "magic element size %lu != %lu",
438                     (unsigned long)sizeof(*map->magic[0]),
439                     (unsigned long)FILE_MAGICSIZE);
440                 return -1;
441         }
442
443         if (action == FILE_COMPILE) {
444                 map = apprentice_load(ms, fn, action);
445                 if (map == NULL)
446                         return -1;
447                 return apprentice_compile(ms, map, fn);
448         }
449
450 #ifndef COMPILE_ONLY
451         map = apprentice_map(ms, fn);
452         if (map == NULL) {
453                 if (ms->flags & MAGIC_CHECK)
454                         file_magwarn(ms, "using regular magic file `%s'", fn);
455                 map = apprentice_load(ms, fn, action);
456                 if (map == NULL)
457                         return -1;
458         }
459
460         for (i = 0; i < MAGIC_SETS; i++) {
461                 if (add_mlist(ms->mlist[i], map, i) == -1) {
462                         file_oomem(ms, sizeof(*ml));
463                         goto fail;
464                 }
465         }
466
467         if (action == FILE_LIST) {
468                 for (i = 0; i < MAGIC_SETS; i++) {
469                         printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n",
470                             i);
471                         apprentice_list(ms->mlist[i], BINTEST);
472                         printf("Text patterns:\n");
473                         apprentice_list(ms->mlist[i], TEXTTEST);
474                 }
475         }
476         return 0;
477 fail:
478         for (i = 0; i < MAGIC_SETS; i++) {
479                 mlist_free(ms->mlist[i]);
480                 ms->mlist[i] = NULL;
481         }
482         return -1;
483 #else
484         return 0;
485 #endif /* COMPILE_ONLY */
486 }
487
488 protected void
489 file_ms_free(struct magic_set *ms)
490 {
491         size_t i;
492         if (ms == NULL)
493                 return;
494         for (i = 0; i < MAGIC_SETS; i++)
495                 mlist_free(ms->mlist[i]);
496         free(ms->o.pbuf);
497         free(ms->o.buf);
498         free(ms->c.li);
499         free(ms);
500 }
501
502 protected struct magic_set *
503 file_ms_alloc(int flags)
504 {
505         struct magic_set *ms;
506         size_t i, len;
507
508         if ((ms = CAST(struct magic_set *, calloc((size_t)1,
509             sizeof(struct magic_set)))) == NULL)
510                 return NULL;
511
512         if (magic_setflags(ms, flags) == -1) {
513                 errno = EINVAL;
514                 goto free;
515         }
516
517         ms->o.buf = ms->o.pbuf = NULL;
518         len = (ms->c.len = 10) * sizeof(*ms->c.li);
519
520         if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL)
521                 goto free;
522
523         ms->event_flags = 0;
524         ms->error = -1;
525         for (i = 0; i < MAGIC_SETS; i++)
526                 ms->mlist[i] = NULL;
527         ms->file = "unknown";
528         ms->line = 0;
529         ms->indir_max = FILE_INDIR_MAX;
530         ms->name_max = FILE_NAME_MAX;
531         ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
532         ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
533         ms->elf_notes_max = FILE_ELF_NOTES_MAX;
534         ms->regex_max = FILE_REGEX_MAX;
535         return ms;
536 free:
537         free(ms);
538         return NULL;
539 }
540
541 private void
542 apprentice_unmap(struct magic_map *map)
543 {
544         size_t i;
545         if (map == NULL)
546                 return;
547
548         switch (map->type) {
549 #ifdef QUICK
550         case MAP_TYPE_MMAP:
551                 if (map->p)
552                         (void)munmap(map->p, map->len);
553                 break;
554 #endif
555         case MAP_TYPE_MALLOC:
556                 free(map->p);
557                 for (i = 0; i < MAGIC_SETS; i++)
558                         free(map->magic[i]);
559                 break;
560         case MAP_TYPE_USER:
561                 break;
562         default:
563                 abort();
564         }
565         free(map);
566 }
567
568 private struct mlist *
569 mlist_alloc(void)
570 {
571         struct mlist *mlist;
572         if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) {
573                 return NULL;
574         }
575         mlist->next = mlist->prev = mlist;
576         return mlist;
577 }
578
579 private void
580 mlist_free(struct mlist *mlist)
581 {
582         struct mlist *ml, *next;
583
584         if (mlist == NULL)
585                 return;
586
587         ml = mlist->next;
588         for (ml = mlist->next; (next = ml->next) != NULL; ml = next) {
589                 if (ml->map)
590                         apprentice_unmap(ml->map);
591                 free(ml);
592                 if (ml == mlist)
593                         break;
594         }
595 }
596
597 #ifndef COMPILE_ONLY
598 /* void **bufs: an array of compiled magic files */
599 protected int
600 buffer_apprentice(struct magic_set *ms, struct magic **bufs,
601     size_t *sizes, size_t nbufs)
602 {
603         size_t i, j;
604         struct mlist *ml;
605         struct magic_map *map;
606
607         if (nbufs == 0)
608                 return -1;
609
610         if (ms->mlist[0] != NULL)
611                 file_reset(ms);
612
613         init_file_tables();
614
615         for (i = 0; i < MAGIC_SETS; i++) {
616                 mlist_free(ms->mlist[i]);
617                 if ((ms->mlist[i] = mlist_alloc()) == NULL) {
618                         file_oomem(ms, sizeof(*ms->mlist[i]));
619                         goto fail;
620                 }
621         }
622
623         for (i = 0; i < nbufs; i++) {
624                 map = apprentice_buf(ms, bufs[i], sizes[i]);
625                 if (map == NULL)
626                         goto fail;
627
628                 for (j = 0; j < MAGIC_SETS; j++) {
629                         if (add_mlist(ms->mlist[j], map, j) == -1) {
630                                 file_oomem(ms, sizeof(*ml));
631                                 goto fail;
632                         }
633                 }
634         }
635
636         return 0;
637 fail:
638         for (i = 0; i < MAGIC_SETS; i++) {
639                 mlist_free(ms->mlist[i]);
640                 ms->mlist[i] = NULL;
641         }
642         return -1;
643 }
644 #endif
645
646 /* const char *fn: list of magic files and directories */
647 protected int
648 file_apprentice(struct magic_set *ms, const char *fn, int action)
649 {
650         char *p, *mfn;
651         int file_err, errs = -1;
652         size_t i;
653
654         if (ms->mlist[0] != NULL)
655                 file_reset(ms);
656
657         if ((fn = magic_getpath(fn, action)) == NULL)
658                 return -1;
659
660         init_file_tables();
661
662         if ((mfn = strdup(fn)) == NULL) {
663                 file_oomem(ms, strlen(fn));
664                 return -1;
665         }
666
667         for (i = 0; i < MAGIC_SETS; i++) {
668                 mlist_free(ms->mlist[i]);
669                 if ((ms->mlist[i] = mlist_alloc()) == NULL) {
670                         file_oomem(ms, sizeof(*ms->mlist[i]));
671                         while (i-- > 0) {
672                                 mlist_free(ms->mlist[i]);
673                                 ms->mlist[i] = NULL;
674                         }
675                         free(mfn);
676                         return -1;
677                 }
678         }
679         fn = mfn;
680
681         while (fn) {
682                 p = strchr(fn, PATHSEP);
683                 if (p)
684                         *p++ = '\0';
685                 if (*fn == '\0')
686                         break;
687                 file_err = apprentice_1(ms, fn, action);
688                 errs = MAX(errs, file_err);
689                 fn = p;
690         }
691
692         free(mfn);
693
694         if (errs == -1) {
695                 for (i = 0; i < MAGIC_SETS; i++) {
696                         mlist_free(ms->mlist[i]);
697                         ms->mlist[i] = NULL;
698                 }
699                 file_error(ms, 0, "could not find any valid magic files!");
700                 return -1;
701         }
702
703 #if 0
704         /*
705          * Always leave the database loaded
706          */
707         if (action == FILE_LOAD)
708                 return 0;
709
710         for (i = 0; i < MAGIC_SETS; i++) {
711                 mlist_free(ms->mlist[i]);
712                 ms->mlist[i] = NULL;
713         }
714 #endif
715
716         switch (action) {
717         case FILE_LOAD:
718         case FILE_COMPILE:
719         case FILE_CHECK:
720         case FILE_LIST:
721                 return 0;
722         default:
723                 file_error(ms, 0, "Invalid action %d", action);
724                 return -1;
725         }
726 }
727
728 /*
729  * Compute the real length of a magic expression, for the purposes
730  * of determining how "strong" a magic expression is (approximating
731  * how specific its matches are):
732  *      - magic characters count 0 unless escaped.
733  *      - [] expressions count 1
734  *      - {} expressions count 0
735  *      - regular characters or escaped magic characters count 1
736  *      - 0 length expressions count as one
737  */
738 private size_t
739 nonmagic(const char *str)
740 {
741         const char *p;
742         size_t rv = 0;
743
744         for (p = str; *p; p++)
745                 switch (*p) {
746                 case '\\':      /* Escaped anything counts 1 */
747                         if (!*++p)
748                                 p--;
749                         rv++;
750                         continue;
751                 case '?':       /* Magic characters count 0 */
752                 case '*':
753                 case '.':
754                 case '+':
755                 case '^':
756                 case '$':
757                         continue;
758                 case '[':       /* Bracketed expressions count 1 the ']' */
759                         while (*p && *p != ']')
760                                 p++;
761                         p--;
762                         continue;
763                 case '{':       /* Braced expressions count 0 */
764                         while (*p && *p != '}')
765                                 p++;
766                         if (!*p)
767                                 p--;
768                         continue;
769                 default:        /* Anything else counts 1 */
770                         rv++;
771                         continue;
772                 }
773
774         return rv == 0 ? 1 : rv;        /* Return at least 1 */
775 }
776
777 /*
778  * Get weight of this magic entry, for sorting purposes.
779  */
780 private size_t
781 apprentice_magic_strength(const struct magic *m)
782 {
783 #define MULT 10
784         size_t v, val = 2 * MULT;       /* baseline strength */
785
786         switch (m->type) {
787         case FILE_DEFAULT:      /* make sure this sorts last */
788                 if (m->factor_op != FILE_FACTOR_OP_NONE)
789                         abort();
790                 return 0;
791
792         case FILE_BYTE:
793                 val += 1 * MULT;
794                 break;
795
796         case FILE_SHORT:
797         case FILE_LESHORT:
798         case FILE_BESHORT:
799                 val += 2 * MULT;
800                 break;
801
802         case FILE_LONG:
803         case FILE_LELONG:
804         case FILE_BELONG:
805         case FILE_MELONG:
806                 val += 4 * MULT;
807                 break;
808
809         case FILE_PSTRING:
810         case FILE_STRING:
811                 val += m->vallen * MULT;
812                 break;
813
814         case FILE_BESTRING16:
815         case FILE_LESTRING16:
816                 val += m->vallen * MULT / 2;
817                 break;
818
819         case FILE_SEARCH:
820                 val += m->vallen * MAX(MULT / m->vallen, 1);
821                 break;
822
823         case FILE_REGEX:
824                 v = nonmagic(m->value.s);
825                 val += v * MAX(MULT / v, 1);
826                 break;
827
828         case FILE_DATE:
829         case FILE_LEDATE:
830         case FILE_BEDATE:
831         case FILE_MEDATE:
832         case FILE_LDATE:
833         case FILE_LELDATE:
834         case FILE_BELDATE:
835         case FILE_MELDATE:
836         case FILE_FLOAT:
837         case FILE_BEFLOAT:
838         case FILE_LEFLOAT:
839                 val += 4 * MULT;
840                 break;
841
842         case FILE_QUAD:
843         case FILE_BEQUAD:
844         case FILE_LEQUAD:
845         case FILE_QDATE:
846         case FILE_LEQDATE:
847         case FILE_BEQDATE:
848         case FILE_QLDATE:
849         case FILE_LEQLDATE:
850         case FILE_BEQLDATE:
851         case FILE_QWDATE:
852         case FILE_LEQWDATE:
853         case FILE_BEQWDATE:
854         case FILE_DOUBLE:
855         case FILE_BEDOUBLE:
856         case FILE_LEDOUBLE:
857                 val += 8 * MULT;
858                 break;
859
860         case FILE_INDIRECT:
861         case FILE_NAME:
862         case FILE_USE:
863                 break;
864
865         default:
866                 (void)fprintf(stderr, "Bad type %d\n", m->type);
867                 abort();
868         }
869
870         switch (m->reln) {
871         case 'x':       /* matches anything penalize */
872         case '!':       /* matches almost anything penalize */
873                 val = 0;
874                 break;
875
876         case '=':       /* Exact match, prefer */
877                 val += MULT;
878                 break;
879
880         case '>':
881         case '<':       /* comparison match reduce strength */
882                 val -= 2 * MULT;
883                 break;
884
885         case '^':
886         case '&':       /* masking bits, we could count them too */
887                 val -= MULT;
888                 break;
889
890         default:
891                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
892                 abort();
893         }
894
895         if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
896                 val = 1;
897
898         switch (m->factor_op) {
899         case FILE_FACTOR_OP_NONE:
900                 break;
901         case FILE_FACTOR_OP_PLUS:
902                 val += m->factor;
903                 break;
904         case FILE_FACTOR_OP_MINUS:
905                 val -= m->factor;
906                 break;
907         case FILE_FACTOR_OP_TIMES:
908                 val *= m->factor;
909                 break;
910         case FILE_FACTOR_OP_DIV:
911                 val /= m->factor;
912                 break;
913         default:
914                 abort();
915         }
916
917         /*
918          * Magic entries with no description get a bonus because they depend
919          * on subsequent magic entries to print something.
920          */
921         if (m->desc[0] == '\0')
922                 val++;
923         return val;
924 }
925
926 /*  
927  * Sort callback for sorting entries by "strength" (basically length)
928  */
929 private int
930 apprentice_sort(const void *a, const void *b)
931 {
932         const struct magic_entry *ma = CAST(const struct magic_entry *, a);
933         const struct magic_entry *mb = CAST(const struct magic_entry *, b);
934         size_t sa = apprentice_magic_strength(ma->mp);
935         size_t sb = apprentice_magic_strength(mb->mp);
936         if (sa == sb)
937                 return 0;
938         else if (sa > sb)
939                 return -1;
940         else
941                 return 1;
942 }
943
944 /*  
945  * Shows sorted patterns list in the order which is used for the matching
946  */
947 private void
948 apprentice_list(struct mlist *mlist, int mode)
949 {
950         uint32_t magindex = 0;
951         struct mlist *ml;
952         for (ml = mlist->next; ml != mlist; ml = ml->next) {
953                 for (magindex = 0; magindex < ml->nmagic; magindex++) {
954                         struct magic *m = &ml->magic[magindex];
955                         if ((m->flag & mode) != mode) {
956                                 /* Skip sub-tests */
957                                 while (magindex + 1 < ml->nmagic &&
958                                        ml->magic[magindex + 1].cont_level != 0)
959                                         ++magindex;
960                                 continue; /* Skip to next top-level test*/
961                         }
962
963                         /*
964                          * Try to iterate over the tree until we find item with
965                          * description/mimetype.
966                          */
967                         while (magindex + 1 < ml->nmagic &&
968                                ml->magic[magindex + 1].cont_level != 0 &&
969                                *ml->magic[magindex].desc == '\0' &&
970                                *ml->magic[magindex].mimetype == '\0')
971                                 magindex++;
972
973                         printf("Strength = %3" SIZE_T_FORMAT "u@%u: %s [%s]\n",
974                             apprentice_magic_strength(m),
975                             ml->magic[magindex].lineno,
976                             ml->magic[magindex].desc,
977                             ml->magic[magindex].mimetype);
978                 }
979         }
980 }
981
982 private void
983 set_test_type(struct magic *mstart, struct magic *m)
984 {
985         switch (m->type) {
986         case FILE_BYTE:
987         case FILE_SHORT:
988         case FILE_LONG:
989         case FILE_DATE:
990         case FILE_BESHORT:
991         case FILE_BELONG:
992         case FILE_BEDATE:
993         case FILE_LESHORT:
994         case FILE_LELONG:
995         case FILE_LEDATE:
996         case FILE_LDATE:
997         case FILE_BELDATE:
998         case FILE_LELDATE:
999         case FILE_MEDATE:
1000         case FILE_MELDATE:
1001         case FILE_MELONG:
1002         case FILE_QUAD:
1003         case FILE_LEQUAD:
1004         case FILE_BEQUAD:
1005         case FILE_QDATE:
1006         case FILE_LEQDATE:
1007         case FILE_BEQDATE:
1008         case FILE_QLDATE:
1009         case FILE_LEQLDATE:
1010         case FILE_BEQLDATE:
1011         case FILE_QWDATE:
1012         case FILE_LEQWDATE:
1013         case FILE_BEQWDATE:
1014         case FILE_FLOAT:
1015         case FILE_BEFLOAT:
1016         case FILE_LEFLOAT:
1017         case FILE_DOUBLE:
1018         case FILE_BEDOUBLE:
1019         case FILE_LEDOUBLE:
1020                 mstart->flag |= BINTEST;
1021                 break;
1022         case FILE_STRING:
1023         case FILE_PSTRING:
1024         case FILE_BESTRING16:
1025         case FILE_LESTRING16:
1026                 /* Allow text overrides */
1027                 if (mstart->str_flags & STRING_TEXTTEST)
1028                         mstart->flag |= TEXTTEST;
1029                 else
1030                         mstart->flag |= BINTEST;
1031                 break;
1032         case FILE_REGEX:
1033         case FILE_SEARCH:
1034                 /* Check for override */
1035                 if (mstart->str_flags & STRING_BINTEST)
1036                         mstart->flag |= BINTEST;
1037                 if (mstart->str_flags & STRING_TEXTTEST)
1038                         mstart->flag |= TEXTTEST;
1039                     
1040                 if (mstart->flag & (TEXTTEST|BINTEST))
1041                         break;
1042
1043                 /* binary test if pattern is not text */
1044                 if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
1045                     NULL) <= 0)
1046                         mstart->flag |= BINTEST;
1047                 else
1048                         mstart->flag |= TEXTTEST;
1049                 break;
1050         case FILE_DEFAULT:
1051                 /* can't deduce anything; we shouldn't see this at the
1052                    top level anyway */
1053                 break;
1054         case FILE_INVALID:
1055         default:
1056                 /* invalid search type, but no need to complain here */
1057                 break;
1058         }
1059 }
1060
1061 private int
1062 addentry(struct magic_set *ms, struct magic_entry *me,
1063    struct magic_entry_set *mset)
1064 {
1065         size_t i = me->mp->type == FILE_NAME ? 1 : 0;
1066         if (mset[i].count == mset[i].max) {
1067                 struct magic_entry *mp;
1068
1069                 mset[i].max += ALLOC_INCR;
1070                 if ((mp = CAST(struct magic_entry *,
1071                     realloc(mset[i].me, sizeof(*mp) * mset[i].max))) ==
1072                     NULL) {
1073                         file_oomem(ms, sizeof(*mp) * mset[i].max);
1074                         return -1;
1075                 }
1076                 (void)memset(&mp[mset[i].count], 0, sizeof(*mp) *
1077                     ALLOC_INCR);
1078                 mset[i].me = mp;
1079         }
1080         mset[i].me[mset[i].count++] = *me;
1081         memset(me, 0, sizeof(*me));
1082         return 0;
1083 }
1084
1085 /*
1086  * Load and parse one file.
1087  */
1088 private void
1089 load_1(struct magic_set *ms, int action, const char *fn, int *errs,
1090    struct magic_entry_set *mset)
1091 {
1092         size_t lineno = 0, llen = 0;
1093         char *line = NULL;
1094         ssize_t len;
1095         struct magic_entry me;
1096
1097         FILE *f = fopen(ms->file = fn, "r");
1098         if (f == NULL) {
1099                 if (errno != ENOENT)
1100                         file_error(ms, errno, "cannot read magic file `%s'",
1101                                    fn);
1102                 (*errs)++;
1103                 return;
1104         }
1105
1106         memset(&me, 0, sizeof(me));
1107         /* read and parse this file */
1108         for (ms->line = 1; (len = getline(&line, &llen, f)) != -1;
1109             ms->line++) {
1110                 if (len == 0) /* null line, garbage, etc */
1111                         continue;
1112                 if (line[len - 1] == '\n') {
1113                         lineno++;
1114                         line[len - 1] = '\0'; /* delete newline */
1115                 }
1116                 switch (line[0]) {
1117                 case '\0':      /* empty, do not parse */
1118                 case '#':       /* comment, do not parse */
1119                         continue;
1120                 case '!':
1121                         if (line[1] == ':') {
1122                                 size_t i;
1123
1124                                 for (i = 0; bang[i].name != NULL; i++) {
1125                                         if ((size_t)(len - 2) > bang[i].len &&
1126                                             memcmp(bang[i].name, line + 2,
1127                                             bang[i].len) == 0)
1128                                                 break;
1129                                 }
1130                                 if (bang[i].name == NULL) {
1131                                         file_error(ms, 0,
1132                                             "Unknown !: entry `%s'", line);
1133                                         (*errs)++;
1134                                         continue;
1135                                 }
1136                                 if (me.mp == NULL) {
1137                                         file_error(ms, 0,
1138                                             "No current entry for :!%s type",
1139                                                 bang[i].name);
1140                                         (*errs)++;
1141                                         continue;
1142                                 }
1143                                 if ((*bang[i].fun)(ms, &me,
1144                                     line + bang[i].len + 2) != 0) {
1145                                         (*errs)++;
1146                                         continue;
1147                                 }
1148                                 continue;
1149                         }
1150                         /*FALLTHROUGH*/
1151                 default:
1152                 again:
1153                         switch (parse(ms, &me, line, lineno, action)) {
1154                         case 0:
1155                                 continue;
1156                         case 1:
1157                                 (void)addentry(ms, &me, mset);
1158                                 goto again;
1159                         default:
1160                                 (*errs)++;
1161                                 break;
1162                         }
1163                 }
1164         }
1165         if (me.mp)
1166                 (void)addentry(ms, &me, mset);
1167         free(line);
1168         (void)fclose(f);
1169 }
1170
1171 /*
1172  * parse a file or directory of files
1173  * const char *fn: name of magic file or directory
1174  */
1175 private int
1176 cmpstrp(const void *p1, const void *p2)
1177 {
1178         return strcmp(*(char *const *)p1, *(char *const *)p2);
1179 }
1180
1181
1182 private uint32_t
1183 set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme,
1184     uint32_t starttest)
1185 {
1186         static const char text[] = "text";
1187         static const char binary[] = "binary";
1188         static const size_t len = sizeof(text);
1189
1190         uint32_t i = starttest;
1191
1192         do {
1193                 set_test_type(me[starttest].mp, me[i].mp);
1194                 if ((ms->flags & MAGIC_DEBUG) == 0)
1195                         continue;
1196                 (void)fprintf(stderr, "%s%s%s: %s\n",
1197                     me[i].mp->mimetype,
1198                     me[i].mp->mimetype[0] == '\0' ? "" : "; ",
1199                     me[i].mp->desc[0] ? me[i].mp->desc : "(no description)",
1200                     me[i].mp->flag & BINTEST ? binary : text);
1201                 if (me[i].mp->flag & BINTEST) {
1202                         char *p = strstr(me[i].mp->desc, text);
1203                         if (p && (p == me[i].mp->desc ||
1204                             isspace((unsigned char)p[-1])) &&
1205                             (p + len - me[i].mp->desc == MAXstring
1206                             || (p[len] == '\0' ||
1207                             isspace((unsigned char)p[len]))))
1208                                 (void)fprintf(stderr, "*** Possible "
1209                                     "binary test for text type\n");
1210                 }
1211         } while (++i < nme && me[i].mp->cont_level != 0);
1212         return i;
1213 }
1214
1215 private void
1216 set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme)
1217 {
1218         uint32_t i;
1219         for (i = 0; i < nme; i++) {
1220                 if (me[i].mp->cont_level == 0 &&
1221                     me[i].mp->type == FILE_DEFAULT) {
1222                         while (++i < nme)
1223                                 if (me[i].mp->cont_level == 0)
1224                                         break;
1225                         if (i != nme) {
1226                                 /* XXX - Ugh! */
1227                                 ms->line = me[i].mp->lineno;
1228                                 file_magwarn(ms,
1229                                     "level 0 \"default\" did not sort last");
1230                         }
1231                         return;                                     
1232                 }
1233         }
1234 }
1235
1236 private int
1237 coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme,
1238     struct magic **ma, uint32_t *nma)
1239 {
1240         uint32_t i, mentrycount = 0;
1241         size_t slen;
1242
1243         for (i = 0; i < nme; i++)
1244                 mentrycount += me[i].cont_count;
1245
1246         slen = sizeof(**ma) * mentrycount;
1247         if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) {
1248                 file_oomem(ms, slen);
1249                 return -1;
1250         }
1251
1252         mentrycount = 0;
1253         for (i = 0; i < nme; i++) {
1254                 (void)memcpy(*ma + mentrycount, me[i].mp,
1255                     me[i].cont_count * sizeof(**ma));
1256                 mentrycount += me[i].cont_count;
1257         }
1258         *nma = mentrycount;
1259         return 0;
1260 }
1261
1262 private void
1263 magic_entry_free(struct magic_entry *me, uint32_t nme)
1264 {
1265         uint32_t i;
1266         if (me == NULL)
1267                 return;
1268         for (i = 0; i < nme; i++)
1269                 free(me[i].mp);
1270         free(me);
1271 }
1272
1273 private struct magic_map *
1274 apprentice_load(struct magic_set *ms, const char *fn, int action)
1275 {
1276         int errs = 0;
1277         uint32_t i, j;
1278         size_t files = 0, maxfiles = 0;
1279         char **filearr = NULL, *mfn;
1280         struct stat st;
1281         struct magic_map *map;
1282         struct magic_entry_set mset[MAGIC_SETS];
1283         DIR *dir;
1284         struct dirent *d;
1285
1286         memset(mset, 0, sizeof(mset));
1287         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
1288
1289
1290         if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL)
1291         {
1292                 file_oomem(ms, sizeof(*map));
1293                 return NULL;
1294         }
1295         map->type = MAP_TYPE_MALLOC;
1296
1297         /* print silly verbose header for USG compat. */
1298         if (action == FILE_CHECK)
1299                 (void)fprintf(stderr, "%s\n", usg_hdr);
1300
1301         /* load directory or file */
1302         if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
1303                 dir = opendir(fn);
1304                 if (!dir) {
1305                         errs++;
1306                         goto out;
1307                 }
1308                 while ((d = readdir(dir)) != NULL) {
1309                         if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) {
1310                                 file_oomem(ms,
1311                                     strlen(fn) + strlen(d->d_name) + 2);
1312                                 errs++;
1313                                 closedir(dir);
1314                                 goto out;
1315                         }
1316                         if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) {
1317                                 free(mfn);
1318                                 continue;
1319                         }
1320                         if (files >= maxfiles) {
1321                                 size_t mlen;
1322                                 maxfiles = (maxfiles + 1) * 2;
1323                                 mlen = maxfiles * sizeof(*filearr);
1324                                 if ((filearr = CAST(char **,
1325                                     realloc(filearr, mlen))) == NULL) {
1326                                         file_oomem(ms, mlen);
1327                                         free(mfn);
1328                                         closedir(dir);
1329                                         errs++;
1330                                         goto out;
1331                                 }
1332                         }
1333                         filearr[files++] = mfn;
1334                 }
1335                 closedir(dir);
1336                 qsort(filearr, files, sizeof(*filearr), cmpstrp);
1337                 for (i = 0; i < files; i++) {
1338                         load_1(ms, action, filearr[i], &errs, mset);
1339                         free(filearr[i]);
1340                 }
1341                 free(filearr);
1342         } else
1343                 load_1(ms, action, fn, &errs, mset);
1344         if (errs)
1345                 goto out;
1346
1347         for (j = 0; j < MAGIC_SETS; j++) {
1348                 /* Set types of tests */
1349                 for (i = 0; i < mset[j].count; ) {
1350                         if (mset[j].me[i].mp->cont_level != 0) {
1351                                 i++;
1352                                 continue;
1353                         }
1354                         i = set_text_binary(ms, mset[j].me, mset[j].count, i);
1355                 }
1356                 if (mset[j].me)
1357                         qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me),
1358                             apprentice_sort);
1359
1360                 /*
1361                  * Make sure that any level 0 "default" line is last
1362                  * (if one exists).
1363                  */
1364                 set_last_default(ms, mset[j].me, mset[j].count);
1365
1366                 /* coalesce per file arrays into a single one */
1367                 if (coalesce_entries(ms, mset[j].me, mset[j].count,
1368                     &map->magic[j], &map->nmagic[j]) == -1) {
1369                         errs++;
1370                         goto out;
1371                 }
1372         }
1373
1374 out:
1375         for (j = 0; j < MAGIC_SETS; j++)
1376                 magic_entry_free(mset[j].me, mset[j].count);
1377
1378         if (errs) {
1379                 apprentice_unmap(map);
1380                 return NULL;
1381         }
1382         return map;
1383 }
1384
1385 /*
1386  * extend the sign bit if the comparison is to be signed
1387  */
1388 protected uint64_t
1389 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
1390 {
1391         if (!(m->flag & UNSIGNED)) {
1392                 switch(m->type) {
1393                 /*
1394                  * Do not remove the casts below.  They are
1395                  * vital.  When later compared with the data,
1396                  * the sign extension must have happened.
1397                  */
1398                 case FILE_BYTE:
1399                         v = (signed char) v;
1400                         break;
1401                 case FILE_SHORT:
1402                 case FILE_BESHORT:
1403                 case FILE_LESHORT:
1404                         v = (short) v;
1405                         break;
1406                 case FILE_DATE:
1407                 case FILE_BEDATE:
1408                 case FILE_LEDATE:
1409                 case FILE_MEDATE:
1410                 case FILE_LDATE:
1411                 case FILE_BELDATE:
1412                 case FILE_LELDATE:
1413                 case FILE_MELDATE:
1414                 case FILE_LONG:
1415                 case FILE_BELONG:
1416                 case FILE_LELONG:
1417                 case FILE_MELONG:
1418                 case FILE_FLOAT:
1419                 case FILE_BEFLOAT:
1420                 case FILE_LEFLOAT:
1421                         v = (int32_t) v;
1422                         break;
1423                 case FILE_QUAD:
1424                 case FILE_BEQUAD:
1425                 case FILE_LEQUAD:
1426                 case FILE_QDATE:
1427                 case FILE_QLDATE:
1428                 case FILE_QWDATE:
1429                 case FILE_BEQDATE:
1430                 case FILE_BEQLDATE:
1431                 case FILE_BEQWDATE:
1432                 case FILE_LEQDATE:
1433                 case FILE_LEQLDATE:
1434                 case FILE_LEQWDATE:
1435                 case FILE_DOUBLE:
1436                 case FILE_BEDOUBLE:
1437                 case FILE_LEDOUBLE:
1438                         v = (int64_t) v;
1439                         break;
1440                 case FILE_STRING:
1441                 case FILE_PSTRING:
1442                 case FILE_BESTRING16:
1443                 case FILE_LESTRING16:
1444                 case FILE_REGEX:
1445                 case FILE_SEARCH:
1446                 case FILE_DEFAULT:
1447                 case FILE_INDIRECT:
1448                 case FILE_NAME:
1449                 case FILE_USE:
1450                 case FILE_CLEAR:
1451                         break;
1452                 default:
1453                         if (ms->flags & MAGIC_CHECK)
1454                             file_magwarn(ms, "cannot happen: m->type=%d\n",
1455                                     m->type);
1456                         return ~0U;
1457                 }
1458         }
1459         return v;
1460 }
1461
1462 private int
1463 string_modifier_check(struct magic_set *ms, struct magic *m)
1464 {
1465         if ((ms->flags & MAGIC_CHECK) == 0)
1466                 return 0;
1467
1468         if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) &&
1469             (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) {
1470                 file_magwarn(ms,
1471                     "'/BHhLl' modifiers are only allowed for pascal strings\n");
1472                 return -1;
1473         }
1474         switch (m->type) {
1475         case FILE_BESTRING16:
1476         case FILE_LESTRING16:
1477                 if (m->str_flags != 0) {
1478                         file_magwarn(ms,
1479                             "no modifiers allowed for 16-bit strings\n");
1480                         return -1;
1481                 }
1482                 break;
1483         case FILE_STRING:
1484         case FILE_PSTRING:
1485                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
1486                         file_magwarn(ms,
1487                             "'/%c' only allowed on regex and search\n",
1488                             CHAR_REGEX_OFFSET_START);
1489                         return -1;
1490                 }
1491                 break;
1492         case FILE_SEARCH:
1493                 if (m->str_range == 0) {
1494                         file_magwarn(ms,
1495                             "missing range; defaulting to %d\n",
1496                             STRING_DEFAULT_RANGE);
1497                         m->str_range = STRING_DEFAULT_RANGE;
1498                         return -1;
1499                 }
1500                 break;
1501         case FILE_REGEX:
1502                 if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) {
1503                         file_magwarn(ms, "'/%c' not allowed on regex\n",
1504                             CHAR_COMPACT_WHITESPACE);
1505                         return -1;
1506                 }
1507                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) {
1508                         file_magwarn(ms, "'/%c' not allowed on regex\n",
1509                             CHAR_COMPACT_OPTIONAL_WHITESPACE);
1510                         return -1;
1511                 }
1512                 break;
1513         default:
1514                 file_magwarn(ms, "coding error: m->type=%d\n",
1515                     m->type);
1516                 return -1;
1517         }
1518         return 0;
1519 }
1520
1521 private int
1522 get_op(char c)
1523 {
1524         switch (c) {
1525         case '&':
1526                 return FILE_OPAND;
1527         case '|':
1528                 return FILE_OPOR;
1529         case '^':
1530                 return FILE_OPXOR;
1531         case '+':
1532                 return FILE_OPADD;
1533         case '-':
1534                 return FILE_OPMINUS;
1535         case '*':
1536                 return FILE_OPMULTIPLY;
1537         case '/':
1538                 return FILE_OPDIVIDE;
1539         case '%':
1540                 return FILE_OPMODULO;
1541         default:
1542                 return -1;
1543         }
1544 }
1545
1546 #ifdef ENABLE_CONDITIONALS
1547 private int
1548 get_cond(const char *l, const char **t)
1549 {
1550         static const struct cond_tbl_s {
1551                 char name[8];
1552                 size_t len;
1553                 int cond;
1554         } cond_tbl[] = {
1555                 { "if",         2,      COND_IF },
1556                 { "elif",       4,      COND_ELIF },
1557                 { "else",       4,      COND_ELSE },
1558                 { "",           0,      COND_NONE },
1559         };
1560         const struct cond_tbl_s *p;
1561
1562         for (p = cond_tbl; p->len; p++) {
1563                 if (strncmp(l, p->name, p->len) == 0 &&
1564                     isspace((unsigned char)l[p->len])) {
1565                         if (t)
1566                                 *t = l + p->len;
1567                         break;
1568                 }
1569         }
1570         return p->cond;
1571 }
1572
1573 private int
1574 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
1575 {
1576         int last_cond;
1577         last_cond = ms->c.li[cont_level].last_cond;
1578
1579         switch (cond) {
1580         case COND_IF:
1581                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
1582                         if (ms->flags & MAGIC_CHECK)
1583                                 file_magwarn(ms, "syntax error: `if'");
1584                         return -1;
1585                 }
1586                 last_cond = COND_IF;
1587                 break;
1588
1589         case COND_ELIF:
1590                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1591                         if (ms->flags & MAGIC_CHECK)
1592                                 file_magwarn(ms, "syntax error: `elif'");
1593                         return -1;
1594                 }
1595                 last_cond = COND_ELIF;
1596                 break;
1597
1598         case COND_ELSE:
1599                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1600                         if (ms->flags & MAGIC_CHECK)
1601                                 file_magwarn(ms, "syntax error: `else'");
1602                         return -1;
1603                 }
1604                 last_cond = COND_NONE;
1605                 break;
1606
1607         case COND_NONE:
1608                 last_cond = COND_NONE;
1609                 break;
1610         }
1611
1612         ms->c.li[cont_level].last_cond = last_cond;
1613         return 0;
1614 }
1615 #endif /* ENABLE_CONDITIONALS */
1616
1617 private int
1618 parse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp)
1619 {
1620         const char *l = *lp;
1621
1622         while (!isspace((unsigned char)*++l))
1623                 switch (*l) {
1624                 case CHAR_INDIRECT_RELATIVE:
1625                         m->str_flags |= INDIRECT_RELATIVE;
1626                         break;
1627                 default:
1628                         if (ms->flags & MAGIC_CHECK)
1629                                 file_magwarn(ms, "indirect modifier `%c' "
1630                                         "invalid", *l);
1631                         *lp = l;
1632                         return -1;
1633                 }
1634         *lp = l;
1635         return 0;
1636 }
1637
1638 private void
1639 parse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp,
1640     int op)
1641 {
1642         const char *l = *lp;
1643         char *t;
1644         uint64_t val;
1645
1646         ++l;
1647         m->mask_op |= op;
1648         val = (uint64_t)strtoull(l, &t, 0);
1649         l = t;
1650         m->num_mask = file_signextend(ms, m, val);
1651         eatsize(&l);
1652         *lp = l;
1653 }
1654
1655 private int
1656 parse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp)
1657 {
1658         const char *l = *lp;
1659         char *t;
1660         int have_range = 0;
1661
1662         while (!isspace((unsigned char)*++l)) {
1663                 switch (*l) {
1664                 case '0':  case '1':  case '2':
1665                 case '3':  case '4':  case '5':
1666                 case '6':  case '7':  case '8':
1667                 case '9':
1668                         if (have_range && (ms->flags & MAGIC_CHECK))
1669                                 file_magwarn(ms, "multiple ranges");
1670                         have_range = 1;
1671                         m->str_range = CAST(uint32_t, strtoul(l, &t, 0));
1672                         if (m->str_range == 0)
1673                                 file_magwarn(ms, "zero range");
1674                         l = t - 1;
1675                         break;
1676                 case CHAR_COMPACT_WHITESPACE:
1677                         m->str_flags |= STRING_COMPACT_WHITESPACE;
1678                         break;
1679                 case CHAR_COMPACT_OPTIONAL_WHITESPACE:
1680                         m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE;
1681                         break;
1682                 case CHAR_IGNORE_LOWERCASE:
1683                         m->str_flags |= STRING_IGNORE_LOWERCASE;
1684                         break;
1685                 case CHAR_IGNORE_UPPERCASE:
1686                         m->str_flags |= STRING_IGNORE_UPPERCASE;
1687                         break;
1688                 case CHAR_REGEX_OFFSET_START:
1689                         m->str_flags |= REGEX_OFFSET_START;
1690                         break;
1691                 case CHAR_BINTEST:
1692                         m->str_flags |= STRING_BINTEST;
1693                         break;
1694                 case CHAR_TEXTTEST:
1695                         m->str_flags |= STRING_TEXTTEST;
1696                         break;
1697                 case CHAR_TRIM:
1698                         m->str_flags |= STRING_TRIM;
1699                         break;
1700                 case CHAR_PSTRING_1_LE:
1701 #define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a)
1702                         if (m->type != FILE_PSTRING)
1703                                 goto bad;
1704                         SET_LENGTH(PSTRING_1_LE);
1705                         break;
1706                 case CHAR_PSTRING_2_BE:
1707                         if (m->type != FILE_PSTRING)
1708                                 goto bad;
1709                         SET_LENGTH(PSTRING_2_BE);
1710                         break;
1711                 case CHAR_PSTRING_2_LE:
1712                         if (m->type != FILE_PSTRING)
1713                                 goto bad;
1714                         SET_LENGTH(PSTRING_2_LE);
1715                         break;
1716                 case CHAR_PSTRING_4_BE:
1717                         if (m->type != FILE_PSTRING)
1718                                 goto bad;
1719                         SET_LENGTH(PSTRING_4_BE);
1720                         break;
1721                 case CHAR_PSTRING_4_LE:
1722                         switch (m->type) {
1723                         case FILE_PSTRING:
1724                         case FILE_REGEX:
1725                                 break;
1726                         default:
1727                                 goto bad;
1728                         }
1729                         SET_LENGTH(PSTRING_4_LE);
1730                         break;
1731                 case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF:
1732                         if (m->type != FILE_PSTRING)
1733                                 goto bad;
1734                         m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF;
1735                         break;
1736                 default:
1737                 bad:
1738                         if (ms->flags & MAGIC_CHECK)
1739                                 file_magwarn(ms, "string modifier `%c' "
1740                                         "invalid", *l);
1741                         goto out;
1742                 }
1743                 /* allow multiple '/' for readability */
1744                 if (l[1] == '/' && !isspace((unsigned char)l[2]))
1745                         l++;
1746         }
1747         if (string_modifier_check(ms, m) == -1)
1748                 goto out;
1749         *lp = l;
1750         return 0;
1751 out:
1752         *lp = l;
1753         return -1;
1754 }
1755
1756 /*
1757  * parse one line from magic file, put into magic[index++] if valid
1758  */
1759 private int
1760 parse(struct magic_set *ms, struct magic_entry *me, const char *line,
1761     size_t lineno, int action)
1762 {
1763 #ifdef ENABLE_CONDITIONALS
1764         static uint32_t last_cont_level = 0;
1765 #endif
1766         size_t i;
1767         struct magic *m;
1768         const char *l = line;
1769         char *t;
1770         int op;
1771         uint32_t cont_level;
1772         int32_t diff;
1773
1774         cont_level = 0;
1775
1776         /*
1777          * Parse the offset.
1778          */
1779         while (*l == '>') {
1780                 ++l;            /* step over */
1781                 cont_level++; 
1782         }
1783 #ifdef ENABLE_CONDITIONALS
1784         if (cont_level == 0 || cont_level > last_cont_level)
1785                 if (file_check_mem(ms, cont_level) == -1)
1786                         return -1;
1787         last_cont_level = cont_level;
1788 #endif
1789         if (cont_level != 0) {
1790                 if (me->mp == NULL) {
1791                         file_magerror(ms, "No current entry for continuation");
1792                         return -1;
1793                 }
1794                 if (me->cont_count == 0) {
1795                         file_magerror(ms, "Continuations present with 0 count");
1796                         return -1;
1797                 }
1798                 m = &me->mp[me->cont_count - 1];
1799                 diff = (int32_t)cont_level - (int32_t)m->cont_level;
1800                 if (diff > 1)
1801                         file_magwarn(ms, "New continuation level %u is more "
1802                             "than one larger than current level %u", cont_level,
1803                             m->cont_level);
1804                 if (me->cont_count == me->max_count) {
1805                         struct magic *nm;
1806                         size_t cnt = me->max_count + ALLOC_CHUNK;
1807                         if ((nm = CAST(struct magic *, realloc(me->mp,
1808                             sizeof(*nm) * cnt))) == NULL) {
1809                                 file_oomem(ms, sizeof(*nm) * cnt);
1810                                 return -1;
1811                         }
1812                         me->mp = m = nm;
1813                         me->max_count = CAST(uint32_t, cnt);
1814                 }
1815                 m = &me->mp[me->cont_count++];
1816                 (void)memset(m, 0, sizeof(*m));
1817                 m->cont_level = cont_level;
1818         } else {
1819                 static const size_t len = sizeof(*m) * ALLOC_CHUNK;
1820                 if (me->mp != NULL)
1821                         return 1;
1822                 if ((m = CAST(struct magic *, malloc(len))) == NULL) {
1823                         file_oomem(ms, len);
1824                         return -1;
1825                 }
1826                 me->mp = m;
1827                 me->max_count = ALLOC_CHUNK;
1828                 (void)memset(m, 0, sizeof(*m));
1829                 m->factor_op = FILE_FACTOR_OP_NONE;
1830                 m->cont_level = 0;
1831                 me->cont_count = 1;
1832         }
1833         m->lineno = CAST(uint32_t, lineno);
1834
1835         if (*l == '&') {  /* m->cont_level == 0 checked below. */
1836                 ++l;            /* step over */
1837                 m->flag |= OFFADD;
1838         }
1839         if (*l == '(') {
1840                 ++l;            /* step over */
1841                 m->flag |= INDIR;
1842                 if (m->flag & OFFADD)
1843                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1844
1845                 if (*l == '&') {  /* m->cont_level == 0 checked below */
1846                         ++l;            /* step over */
1847                         m->flag |= OFFADD;
1848                 }
1849         }
1850         /* Indirect offsets are not valid at level 0. */
1851         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) {
1852                 if (ms->flags & MAGIC_CHECK)
1853                         file_magwarn(ms, "relative offset at level 0");
1854                 return -1;
1855         }
1856
1857         /* get offset, then skip over it */
1858         m->offset = (uint32_t)strtoul(l, &t, 0);
1859         if (l == t) {
1860                 if (ms->flags & MAGIC_CHECK)
1861                         file_magwarn(ms, "offset `%s' invalid", l);
1862                 return -1;
1863         }
1864         l = t;
1865
1866         if (m->flag & INDIR) {
1867                 m->in_type = FILE_LONG;
1868                 m->in_offset = 0;
1869                 /*
1870                  * read [.lbs][+-]nnnnn)
1871                  */
1872                 if (*l == '.') {
1873                         l++;
1874                         switch (*l) {
1875                         case 'l':
1876                                 m->in_type = FILE_LELONG;
1877                                 break;
1878                         case 'L':
1879                                 m->in_type = FILE_BELONG;
1880                                 break;
1881                         case 'm':
1882                                 m->in_type = FILE_MELONG;
1883                                 break;
1884                         case 'h':
1885                         case 's':
1886                                 m->in_type = FILE_LESHORT;
1887                                 break;
1888                         case 'H':
1889                         case 'S':
1890                                 m->in_type = FILE_BESHORT;
1891                                 break;
1892                         case 'c':
1893                         case 'b':
1894                         case 'C':
1895                         case 'B':
1896                                 m->in_type = FILE_BYTE;
1897                                 break;
1898                         case 'e':
1899                         case 'f':
1900                         case 'g':
1901                                 m->in_type = FILE_LEDOUBLE;
1902                                 break;
1903                         case 'E':
1904                         case 'F':
1905                         case 'G':
1906                                 m->in_type = FILE_BEDOUBLE;
1907                                 break;
1908                         case 'i':
1909                                 m->in_type = FILE_LEID3;
1910                                 break;
1911                         case 'I':
1912                                 m->in_type = FILE_BEID3;
1913                                 break;
1914                         default:
1915                                 if (ms->flags & MAGIC_CHECK)
1916                                         file_magwarn(ms,
1917                                             "indirect offset type `%c' invalid",
1918                                             *l);
1919                                 return -1;
1920                         }
1921                         l++;
1922                 }
1923
1924                 m->in_op = 0;
1925                 if (*l == '~') {
1926                         m->in_op |= FILE_OPINVERSE;
1927                         l++;
1928                 }
1929                 if ((op = get_op(*l)) != -1) {
1930                         m->in_op |= op;
1931                         l++;
1932                 }
1933                 if (*l == '(') {
1934                         m->in_op |= FILE_OPINDIRECT;
1935                         l++;
1936                 }
1937                 if (isdigit((unsigned char)*l) || *l == '-') {
1938                         m->in_offset = (int32_t)strtol(l, &t, 0);
1939                         if (l == t) {
1940                                 if (ms->flags & MAGIC_CHECK)
1941                                         file_magwarn(ms,
1942                                             "in_offset `%s' invalid", l);
1943                                 return -1;
1944                         }
1945                         l = t;
1946                 }
1947                 if (*l++ != ')' || 
1948                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) {
1949                         if (ms->flags & MAGIC_CHECK)
1950                                 file_magwarn(ms,
1951                                     "missing ')' in indirect offset");
1952                         return -1;
1953                 }
1954         }
1955         EATAB;
1956
1957 #ifdef ENABLE_CONDITIONALS
1958         m->cond = get_cond(l, &l);
1959         if (check_cond(ms, m->cond, cont_level) == -1)
1960                 return -1;
1961
1962         EATAB;
1963 #endif
1964
1965         /*
1966          * Parse the type.
1967          */
1968         if (*l == 'u') {
1969                 /*
1970                  * Try it as a keyword type prefixed by "u"; match what
1971                  * follows the "u".  If that fails, try it as an SUS
1972                  * integer type. 
1973                  */
1974                 m->type = get_type(type_tbl, l + 1, &l);
1975                 if (m->type == FILE_INVALID) {
1976                         /*
1977                          * Not a keyword type; parse it as an SUS type,
1978                          * 'u' possibly followed by a number or C/S/L.
1979                          */
1980                         m->type = get_standard_integer_type(l, &l);
1981                 }
1982                 /* It's unsigned. */
1983                 if (m->type != FILE_INVALID)
1984                         m->flag |= UNSIGNED;
1985         } else {
1986                 /*
1987                  * Try it as a keyword type.  If that fails, try it as
1988                  * an SUS integer type if it begins with "d" or as an
1989                  * SUS string type if it begins with "s".  In any case,
1990                  * it's not unsigned.
1991                  */
1992                 m->type = get_type(type_tbl, l, &l);
1993                 if (m->type == FILE_INVALID) {
1994                         /*
1995                          * Not a keyword type; parse it as an SUS type,
1996                          * either 'd' possibly followed by a number or
1997                          * C/S/L, or just 's'.
1998                          */
1999                         if (*l == 'd')
2000                                 m->type = get_standard_integer_type(l, &l);
2001                         else if (*l == 's' && !isalpha((unsigned char)l[1])) {
2002                                 m->type = FILE_STRING;
2003                                 ++l;
2004                         }
2005                 }
2006         }
2007
2008         if (m->type == FILE_INVALID) {
2009                 /* Not found - try it as a special keyword. */
2010                 m->type = get_type(special_tbl, l, &l);
2011         }
2012                         
2013         if (m->type == FILE_INVALID) {
2014                 if (ms->flags & MAGIC_CHECK)
2015                         file_magwarn(ms, "type `%s' invalid", l);
2016                 return -1;
2017         }
2018
2019         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
2020         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
2021
2022         m->mask_op = 0;
2023         if (*l == '~') {
2024                 if (!IS_STRING(m->type))
2025                         m->mask_op |= FILE_OPINVERSE;
2026                 else if (ms->flags & MAGIC_CHECK)
2027                         file_magwarn(ms, "'~' invalid for string types");
2028                 ++l;
2029         }
2030         m->str_range = 0;
2031         m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0;
2032         if ((op = get_op(*l)) != -1) {
2033                 if (IS_STRING(m->type)) {
2034                         int r;
2035
2036                         if (op != FILE_OPDIVIDE) {
2037                                 if (ms->flags & MAGIC_CHECK)
2038                                         file_magwarn(ms,
2039                                             "invalid string/indirect op: "
2040                                             "`%c'", *t);
2041                                 return -1;
2042                         }
2043
2044                         if (m->type == FILE_INDIRECT)
2045                                 r = parse_indirect_modifier(ms, m, &l);
2046                         else
2047                                 r = parse_string_modifier(ms, m, &l);
2048                         if (r == -1)
2049                                 return -1;
2050                 } else
2051                         parse_op_modifier(ms, m, &l, op);
2052         }
2053
2054         /*
2055          * We used to set mask to all 1's here, instead let's just not do
2056          * anything if mask = 0 (unless you have a better idea)
2057          */
2058         EATAB;
2059   
2060         switch (*l) {
2061         case '>':
2062         case '<':
2063                 m->reln = *l;
2064                 ++l;
2065                 if (*l == '=') {
2066                         if (ms->flags & MAGIC_CHECK) {
2067                                 file_magwarn(ms, "%c= not supported",
2068                                     m->reln);
2069                                 return -1;
2070                         }
2071                    ++l;
2072                 }
2073                 break;
2074         /* Old-style anding: "0 byte &0x80 dynamically linked" */
2075         case '&':
2076         case '^':
2077         case '=':
2078                 m->reln = *l;
2079                 ++l;
2080                 if (*l == '=') {
2081                    /* HP compat: ignore &= etc. */
2082                    ++l;
2083                 }
2084                 break;
2085         case '!':
2086                 m->reln = *l;
2087                 ++l;
2088                 break;
2089         default:
2090                 m->reln = '=';  /* the default relation */
2091                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
2092                     isspace((unsigned char)l[1])) || !l[1])) {
2093                         m->reln = *l;
2094                         ++l;
2095                 }
2096                 break;
2097         }
2098         /*
2099          * Grab the value part, except for an 'x' reln.
2100          */
2101         if (m->reln != 'x' && getvalue(ms, m, &l, action))
2102                 return -1;
2103
2104         /*
2105          * TODO finish this macro and start using it!
2106          * #define offsetcheck {if (offset > HOWMANY-1) 
2107          *      magwarn("offset too big"); }
2108          */
2109
2110         /*
2111          * Now get last part - the description
2112          */
2113         EATAB;
2114         if (l[0] == '\b') {
2115                 ++l;
2116                 m->flag |= NOSPACE;
2117         } else if ((l[0] == '\\') && (l[1] == 'b')) {
2118                 ++l;
2119                 ++l;
2120                 m->flag |= NOSPACE;
2121         }
2122         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
2123                 continue;
2124         if (i == sizeof(m->desc)) {
2125                 m->desc[sizeof(m->desc) - 1] = '\0';
2126                 if (ms->flags & MAGIC_CHECK)
2127                         file_magwarn(ms, "description `%s' truncated", m->desc);
2128         }
2129
2130         /*
2131          * We only do this check while compiling, or if any of the magic
2132          * files were not compiled.
2133          */
2134         if (ms->flags & MAGIC_CHECK) {
2135                 if (check_format(ms, m) == -1)
2136                         return -1;
2137         }
2138 #ifndef COMPILE_ONLY
2139         if (action == FILE_CHECK) {
2140                 file_mdump(m);
2141         }
2142 #endif
2143         m->mimetype[0] = '\0';          /* initialise MIME type to none */
2144         return 0;
2145 }
2146
2147 /*
2148  * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
2149  * if valid
2150  */
2151 private int
2152 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
2153 {
2154         const char *l = line;
2155         char *el;
2156         unsigned long factor;
2157         struct magic *m = &me->mp[0];
2158
2159         if (m->factor_op != FILE_FACTOR_OP_NONE) {
2160                 file_magwarn(ms,
2161                     "Current entry already has a strength type: %c %d",
2162                     m->factor_op, m->factor);
2163                 return -1;
2164         }
2165         if (m->type == FILE_NAME) {
2166                 file_magwarn(ms, "%s: Strength setting is not supported in "
2167                     "\"name\" magic entries", m->value.s);
2168                 return -1;
2169         }
2170         EATAB;
2171         switch (*l) {
2172         case FILE_FACTOR_OP_NONE:
2173         case FILE_FACTOR_OP_PLUS:
2174         case FILE_FACTOR_OP_MINUS:
2175         case FILE_FACTOR_OP_TIMES:
2176         case FILE_FACTOR_OP_DIV:
2177                 m->factor_op = *l++;
2178                 break;
2179         default:
2180                 file_magwarn(ms, "Unknown factor op `%c'", *l);
2181                 return -1;
2182         }
2183         EATAB;
2184         factor = strtoul(l, &el, 0);
2185         if (factor > 255) {
2186                 file_magwarn(ms, "Too large factor `%lu'", factor);
2187                 goto out;
2188         }
2189         if (*el && !isspace((unsigned char)*el)) {
2190                 file_magwarn(ms, "Bad factor `%s'", l);
2191                 goto out;
2192         }
2193         m->factor = (uint8_t)factor;
2194         if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
2195                 file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
2196                     m->factor_op, m->factor);
2197                 goto out;
2198         }
2199         return 0;
2200 out:
2201         m->factor_op = FILE_FACTOR_OP_NONE;
2202         m->factor = 0;
2203         return -1;
2204 }
2205
2206 private int
2207 goodchar(unsigned char x, const char *extra)
2208 {
2209         return (isascii(x) && isalnum(x)) || strchr(extra, x);
2210 }
2211
2212 private int
2213 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line,
2214     off_t off, size_t len, const char *name, const char *extra, int nt)
2215 {
2216         size_t i;
2217         const char *l = line;
2218         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
2219         char *buf = CAST(char *, CAST(void *, m)) + off;
2220
2221         if (buf[0] != '\0') {
2222                 len = nt ? strlen(buf) : len;
2223                 file_magwarn(ms, "Current entry already has a %s type "
2224                     "`%.*s', new type `%s'", name, (int)len, buf, l);
2225                 return -1;
2226         }       
2227
2228         if (*m->desc == '\0') {
2229                 file_magwarn(ms, "Current entry does not yet have a "
2230                     "description for adding a %s type", name);
2231                 return -1;
2232         }
2233
2234         EATAB;
2235         for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++)
2236                 continue;
2237
2238         if (i == len && *l) {
2239                 if (nt)
2240                         buf[len - 1] = '\0';
2241                 if (ms->flags & MAGIC_CHECK)
2242                         file_magwarn(ms, "%s type `%s' truncated %"
2243                             SIZE_T_FORMAT "u", name, line, i);
2244         } else {
2245                 if (!isspace((unsigned char)*l) && !goodchar(*l, extra))
2246                         file_magwarn(ms, "%s type `%s' has bad char '%c'",
2247                             name, line, *l);
2248                 if (nt)
2249                         buf[i] = '\0';
2250         }
2251
2252         if (i > 0)
2253                 return 0;
2254
2255         file_magerror(ms, "Bad magic entry '%s'", line);
2256         return -1;
2257 }
2258
2259 /*
2260  * Parse an Apple CREATOR/TYPE annotation from magic file and put it into
2261  * magic[index - 1]
2262  */
2263 private int
2264 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
2265 {
2266         struct magic *m = &me->mp[0];
2267
2268         return parse_extra(ms, me, line,
2269             CAST(off_t, offsetof(struct magic, apple)),
2270             sizeof(m->apple), "APPLE", "!+-./", 0);
2271 }
2272
2273 /*
2274  * Parse a comma-separated list of extensions
2275  */
2276 private int
2277 parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line)
2278 {
2279         struct magic *m = &me->mp[0];
2280
2281         return parse_extra(ms, me, line,
2282             CAST(off_t, offsetof(struct magic, ext)),
2283             sizeof(m->ext), "EXTENSION", ",!+-/", 0);
2284 }
2285
2286 /*
2287  * parse a MIME annotation line from magic file, put into magic[index - 1]
2288  * if valid
2289  */
2290 private int
2291 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
2292 {
2293         struct magic *m = &me->mp[0];
2294
2295         return parse_extra(ms, me, line,
2296             CAST(off_t, offsetof(struct magic, mimetype)),
2297             sizeof(m->mimetype), "MIME", "+-/.", 1);
2298 }
2299
2300 private int
2301 check_format_type(const char *ptr, int type)
2302 {
2303         int quad = 0, h;
2304         if (*ptr == '\0') {
2305                 /* Missing format string; bad */
2306                 return -1;
2307         }
2308
2309         switch (file_formats[type]) {
2310         case FILE_FMT_QUAD:
2311                 quad = 1;
2312                 /*FALLTHROUGH*/
2313         case FILE_FMT_NUM:
2314                 if (quad == 0) {
2315                         switch (type) {
2316                         case FILE_BYTE:
2317                                 h = 2;
2318                                 break;
2319                         case FILE_SHORT:
2320                         case FILE_BESHORT:
2321                         case FILE_LESHORT:
2322                                 h = 1;
2323                                 break;
2324                         case FILE_LONG:
2325                         case FILE_BELONG:
2326                         case FILE_LELONG:
2327                         case FILE_MELONG:
2328                         case FILE_LEID3:
2329                         case FILE_BEID3:
2330                         case FILE_INDIRECT:
2331                                 h = 0;
2332                                 break;
2333                         default:
2334                                 abort();
2335                         }
2336                 } else
2337                         h = 0;
2338                 if (*ptr == '-')
2339                         ptr++;
2340                 if (*ptr == '.')
2341                         ptr++;
2342                 while (isdigit((unsigned char)*ptr)) ptr++;
2343                 if (*ptr == '.')
2344                         ptr++;
2345                 while (isdigit((unsigned char)*ptr)) ptr++;
2346                 if (quad) {
2347                         if (*ptr++ != 'l')
2348                                 return -1;
2349                         if (*ptr++ != 'l')
2350                                 return -1;
2351                 }
2352         
2353                 switch (*ptr++) {
2354 #ifdef STRICT_FORMAT    /* "long" formats are int formats for us */
2355                 /* so don't accept the 'l' modifier */
2356                 case 'l':
2357                         switch (*ptr++) {
2358                         case 'i':
2359                         case 'd':
2360                         case 'u':
2361                         case 'o':
2362                         case 'x':
2363                         case 'X':
2364                                 return h != 0 ? -1 : 0;
2365                         default:
2366                                 return -1;
2367                         }
2368                 
2369                 /*
2370                  * Don't accept h and hh modifiers. They make writing
2371                  * magic entries more complicated, for very little benefit
2372                  */
2373                 case 'h':
2374                         if (h-- <= 0)
2375                                 return -1;
2376                         switch (*ptr++) {
2377                         case 'h':
2378                                 if (h-- <= 0)
2379                                         return -1;
2380                                 switch (*ptr++) {
2381                                 case 'i':
2382                                 case 'd':
2383                                 case 'u':
2384                                 case 'o':
2385                                 case 'x':
2386                                 case 'X':
2387                                         return 0;
2388                                 default:
2389                                         return -1;
2390                                 }
2391                         case 'i':
2392                         case 'd':
2393                         case 'u':
2394                         case 'o':
2395                         case 'x':
2396                         case 'X':
2397                                 return h != 0 ? -1 : 0;
2398                         default:
2399                                 return -1;
2400                         }
2401 #endif
2402                 case 'c':
2403                         return h != 2 ? -1 : 0;
2404                 case 'i':
2405                 case 'd':
2406                 case 'u':
2407                 case 'o':
2408                 case 'x':
2409                 case 'X':
2410 #ifdef STRICT_FORMAT
2411                         return h != 0 ? -1 : 0;
2412 #else
2413                         return 0;
2414 #endif
2415                 default:
2416                         return -1;
2417                 }
2418                 
2419         case FILE_FMT_FLOAT:
2420         case FILE_FMT_DOUBLE:
2421                 if (*ptr == '-')
2422                         ptr++;
2423                 if (*ptr == '.')
2424                         ptr++;
2425                 while (isdigit((unsigned char)*ptr)) ptr++;
2426                 if (*ptr == '.')
2427                         ptr++;
2428                 while (isdigit((unsigned char)*ptr)) ptr++;
2429         
2430                 switch (*ptr++) {
2431                 case 'e':
2432                 case 'E':
2433                 case 'f':
2434                 case 'F':
2435                 case 'g':
2436                 case 'G':
2437                         return 0;
2438                         
2439                 default:
2440                         return -1;
2441                 }
2442                 
2443
2444         case FILE_FMT_STR:
2445                 if (*ptr == '-')
2446                         ptr++;
2447                 while (isdigit((unsigned char )*ptr))
2448                         ptr++;
2449                 if (*ptr == '.') {
2450                         ptr++;
2451                         while (isdigit((unsigned char )*ptr))
2452                                 ptr++;
2453                 }
2454                 
2455                 switch (*ptr++) {
2456                 case 's':
2457                         return 0;
2458                 default:
2459                         return -1;
2460                 }
2461                 
2462         default:
2463                 /* internal error */
2464                 abort();
2465         }
2466         /*NOTREACHED*/
2467         return -1;
2468 }
2469         
2470 /*
2471  * Check that the optional printf format in description matches
2472  * the type of the magic.
2473  */
2474 private int
2475 check_format(struct magic_set *ms, struct magic *m)
2476 {
2477         char *ptr;
2478
2479         for (ptr = m->desc; *ptr; ptr++)
2480                 if (*ptr == '%')
2481                         break;
2482         if (*ptr == '\0') {
2483                 /* No format string; ok */
2484                 return 1;
2485         }
2486
2487         assert(file_nformats == file_nnames);
2488
2489         if (m->type >= file_nformats) {
2490                 file_magwarn(ms, "Internal error inconsistency between "
2491                     "m->type and format strings");              
2492                 return -1;
2493         }
2494         if (file_formats[m->type] == FILE_FMT_NONE) {
2495                 file_magwarn(ms, "No format string for `%s' with description "
2496                     "`%s'", m->desc, file_names[m->type]);
2497                 return -1;
2498         }
2499
2500         ptr++;
2501         if (check_format_type(ptr, m->type) == -1) {
2502                 /*
2503                  * TODO: this error message is unhelpful if the format
2504                  * string is not one character long
2505                  */
2506                 file_magwarn(ms, "Printf format `%c' is not valid for type "
2507                     "`%s' in description `%s'", *ptr ? *ptr : '?',
2508                     file_names[m->type], m->desc);
2509                 return -1;
2510         }
2511         
2512         for (; *ptr; ptr++) {
2513                 if (*ptr == '%') {
2514                         file_magwarn(ms,
2515                             "Too many format strings (should have at most one) "
2516                             "for `%s' with description `%s'",
2517                             file_names[m->type], m->desc);
2518                         return -1;
2519                 }
2520         }
2521         return 0;
2522 }
2523
2524 /* 
2525  * Read a numeric value from a pointer, into the value union of a magic 
2526  * pointer, according to the magic type.  Update the string pointer to point 
2527  * just after the number read.  Return 0 for success, non-zero for failure.
2528  */
2529 private int
2530 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
2531 {
2532         switch (m->type) {
2533         case FILE_BESTRING16:
2534         case FILE_LESTRING16:
2535         case FILE_STRING:
2536         case FILE_PSTRING:
2537         case FILE_REGEX:
2538         case FILE_SEARCH:
2539         case FILE_NAME:
2540         case FILE_USE:
2541                 *p = getstr(ms, m, *p, action == FILE_COMPILE);
2542                 if (*p == NULL) {
2543                         if (ms->flags & MAGIC_CHECK)
2544                                 file_magwarn(ms, "cannot get string from `%s'",
2545                                     m->value.s);
2546                         return -1;
2547                 }
2548                 if (m->type == FILE_REGEX) {
2549                         file_regex_t rx;
2550                         int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED);
2551                         if (rc) {
2552                                 if (ms->flags & MAGIC_CHECK)
2553                                         file_regerror(&rx, rc, ms);
2554                         }
2555                         file_regfree(&rx);
2556                         return rc ? -1 : 0;
2557                 }
2558                 return 0;
2559         case FILE_FLOAT:
2560         case FILE_BEFLOAT:
2561         case FILE_LEFLOAT:
2562                 if (m->reln != 'x') {
2563                         char *ep;
2564                         errno = 0;
2565 #ifdef HAVE_STRTOF
2566                         m->value.f = strtof(*p, &ep);
2567 #else
2568                         m->value.f = (float)strtod(*p, &ep);
2569 #endif
2570                         if (errno == 0)
2571                                 *p = ep;
2572                 }
2573                 return 0;
2574         case FILE_DOUBLE:
2575         case FILE_BEDOUBLE:
2576         case FILE_LEDOUBLE:
2577                 if (m->reln != 'x') {
2578                         char *ep;
2579                         errno = 0;
2580                         m->value.d = strtod(*p, &ep);
2581                         if (errno == 0)
2582                                 *p = ep;
2583                 }
2584                 return 0;
2585         default:
2586                 if (m->reln != 'x') {
2587                         char *ep;
2588                         errno = 0;
2589                         m->value.q = file_signextend(ms, m,
2590                             (uint64_t)strtoull(*p, &ep, 0));
2591                         if (errno == 0) {
2592                                 *p = ep;
2593                                 eatsize(p);
2594                         }
2595                 }
2596                 return 0;
2597         }
2598 }
2599
2600 /*
2601  * Convert a string containing C character escapes.  Stop at an unescaped
2602  * space or tab.
2603  * Copy the converted version to "m->value.s", and the length in m->vallen.
2604  * Return updated scan pointer as function result. Warn if set.
2605  */
2606 private const char *
2607 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
2608 {
2609         const char *origs = s;
2610         char    *p = m->value.s;
2611         size_t  plen = sizeof(m->value.s);
2612         char    *origp = p;
2613         char    *pmax = p + plen - 1;
2614         int     c;
2615         int     val;
2616
2617         while ((c = *s++) != '\0') {
2618                 if (isspace((unsigned char) c))
2619                         break;
2620                 if (p >= pmax) {
2621                         file_error(ms, 0, "string too long: `%s'", origs);
2622                         return NULL;
2623                 }
2624                 if (c == '\\') {
2625                         switch(c = *s++) {
2626
2627                         case '\0':
2628                                 if (warn)
2629                                         file_magwarn(ms, "incomplete escape");
2630                                 s--;
2631                                 goto out;
2632
2633                         case '\t':
2634                                 if (warn) {
2635                                         file_magwarn(ms,
2636                                             "escaped tab found, use \\t instead");
2637                                         warn = 0;       /* already did */
2638                                 }
2639                                 /*FALLTHROUGH*/
2640                         default:
2641                                 if (warn) {
2642                                         if (isprint((unsigned char)c)) {
2643                                                 /* Allow escaping of 
2644                                                  * ``relations'' */
2645                                                 if (strchr("<>&^=!", c) == NULL
2646                                                     && (m->type != FILE_REGEX ||
2647                                                     strchr("[]().*?^$|{}", c)
2648                                                     == NULL)) {
2649                                                         file_magwarn(ms, "no "
2650                                                             "need to escape "
2651                                                             "`%c'", c);
2652                                                 }
2653                                         } else {
2654                                                 file_magwarn(ms,
2655                                                     "unknown escape sequence: "
2656                                                     "\\%03o", c);
2657                                         }
2658                                 }
2659                                 /*FALLTHROUGH*/
2660                         /* space, perhaps force people to use \040? */
2661                         case ' ':
2662 #if 0
2663                         /*
2664                          * Other things people escape, but shouldn't need to,
2665                          * so we disallow them
2666                          */
2667                         case '\'':
2668                         case '"':
2669                         case '?':
2670 #endif
2671                         /* Relations */
2672                         case '>':
2673                         case '<':
2674                         case '&':
2675                         case '^':
2676                         case '=':
2677                         case '!':
2678                         /* and baskslash itself */
2679                         case '\\':
2680                                 *p++ = (char) c;
2681                                 break;
2682
2683                         case 'a':
2684                                 *p++ = '\a';
2685                                 break;
2686
2687                         case 'b':
2688                                 *p++ = '\b';
2689                                 break;
2690
2691                         case 'f':
2692                                 *p++ = '\f';
2693                                 break;
2694
2695                         case 'n':
2696                                 *p++ = '\n';
2697                                 break;
2698
2699                         case 'r':
2700                                 *p++ = '\r';
2701                                 break;
2702
2703                         case 't':
2704                                 *p++ = '\t';
2705                                 break;
2706
2707                         case 'v':
2708                                 *p++ = '\v';
2709                                 break;
2710
2711                         /* \ and up to 3 octal digits */
2712                         case '0':
2713                         case '1':
2714                         case '2':
2715                         case '3':
2716                         case '4':
2717                         case '5':
2718                         case '6':
2719                         case '7':
2720                                 val = c - '0';
2721                                 c = *s++;  /* try for 2 */
2722                                 if (c >= '0' && c <= '7') {
2723                                         val = (val << 3) | (c - '0');
2724                                         c = *s++;  /* try for 3 */
2725                                         if (c >= '0' && c <= '7')
2726                                                 val = (val << 3) | (c-'0');
2727                                         else
2728                                                 --s;
2729                                 }
2730                                 else
2731                                         --s;
2732                                 *p++ = (char)val;
2733                                 break;
2734
2735                         /* \x and up to 2 hex digits */
2736                         case 'x':
2737                                 val = 'x';      /* Default if no digits */
2738                                 c = hextoint(*s++);     /* Get next char */
2739                                 if (c >= 0) {
2740                                         val = c;
2741                                         c = hextoint(*s++);
2742                                         if (c >= 0)
2743                                                 val = (val << 4) + c;
2744                                         else
2745                                                 --s;
2746                                 } else
2747                                         --s;
2748                                 *p++ = (char)val;
2749                                 break;
2750                         }
2751                 } else
2752                         *p++ = (char)c;
2753         }
2754         --s;
2755 out:
2756         *p = '\0';
2757         m->vallen = CAST(unsigned char, (p - origp));
2758         if (m->type == FILE_PSTRING)
2759                 m->vallen += (unsigned char)file_pstring_length_size(m);
2760         return s;
2761 }
2762
2763
2764 /* Single hex char to int; -1 if not a hex char. */
2765 private int
2766 hextoint(int c)
2767 {
2768         if (!isascii((unsigned char) c))
2769                 return -1;
2770         if (isdigit((unsigned char) c))
2771                 return c - '0';
2772         if ((c >= 'a') && (c <= 'f'))
2773                 return c + 10 - 'a';
2774         if (( c>= 'A') && (c <= 'F'))
2775                 return c + 10 - 'A';
2776         return -1;
2777 }
2778
2779
2780 /*
2781  * Print a string containing C character escapes.
2782  */
2783 protected void
2784 file_showstr(FILE *fp, const char *s, size_t len)
2785 {
2786         char    c;
2787
2788         for (;;) {
2789                 if (len == ~0U) {
2790                         c = *s++;
2791                         if (c == '\0')
2792                                 break;
2793                 }
2794                 else  {
2795                         if (len-- == 0)
2796                                 break;
2797                         c = *s++;
2798                 }
2799                 if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
2800                         (void) fputc(c, fp);
2801                 else {
2802                         (void) fputc('\\', fp);
2803                         switch (c) {
2804                         case '\a':
2805                                 (void) fputc('a', fp);
2806                                 break;
2807
2808                         case '\b':
2809                                 (void) fputc('b', fp);
2810                                 break;
2811
2812                         case '\f':
2813                                 (void) fputc('f', fp);
2814                                 break;
2815
2816                         case '\n':
2817                                 (void) fputc('n', fp);
2818                                 break;
2819
2820                         case '\r':
2821                                 (void) fputc('r', fp);
2822                                 break;
2823
2824                         case '\t':
2825                                 (void) fputc('t', fp);
2826                                 break;
2827
2828                         case '\v':
2829                                 (void) fputc('v', fp);
2830                                 break;
2831
2832                         default:
2833                                 (void) fprintf(fp, "%.3o", c & 0377);
2834                                 break;
2835                         }
2836                 }
2837         }
2838 }
2839
2840 /*
2841  * eatsize(): Eat the size spec from a number [eg. 10UL]
2842  */
2843 private void
2844 eatsize(const char **p)
2845 {
2846         const char *l = *p;
2847
2848         if (LOWCASE(*l) == 'u') 
2849                 l++;
2850
2851         switch (LOWCASE(*l)) {
2852         case 'l':    /* long */
2853         case 's':    /* short */
2854         case 'h':    /* short */
2855         case 'b':    /* char/byte */
2856         case 'c':    /* char/byte */
2857                 l++;
2858                 /*FALLTHROUGH*/
2859         default:
2860                 break;
2861         }
2862
2863         *p = l;
2864 }
2865
2866 /*
2867  * handle a buffer containing a compiled file.
2868  */
2869 private struct magic_map *
2870 apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len)
2871 {
2872         struct magic_map *map;
2873
2874         if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
2875                 file_oomem(ms, sizeof(*map));
2876                 return NULL;
2877         }
2878         map->len = len;
2879         map->p = buf;
2880         map->type = MAP_TYPE_USER;
2881         if (check_buffer(ms, map, "buffer") != 0) {
2882                 apprentice_unmap(map);
2883                 return NULL;
2884         }
2885         return map;
2886 }
2887
2888 /*
2889  * handle a compiled file.
2890  */
2891
2892 private struct magic_map *
2893 apprentice_map(struct magic_set *ms, const char *fn)
2894 {
2895         int fd;
2896         struct stat st;
2897         char *dbname = NULL;
2898         struct magic_map *map;
2899
2900         fd = -1;
2901         if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
2902                 file_oomem(ms, sizeof(*map));
2903                 goto error;
2904         }
2905
2906         dbname = mkdbname(ms, fn, 0);
2907         if (dbname == NULL)
2908                 goto error;
2909
2910         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
2911                 goto error;
2912
2913         if (fstat(fd, &st) == -1) {
2914                 file_error(ms, errno, "cannot stat `%s'", dbname);
2915                 goto error;
2916         }
2917         if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) {
2918                 file_error(ms, 0, "file `%s' is too %s", dbname,
2919                     st.st_size < 8 ? "small" : "large");
2920                 goto error;
2921         }
2922
2923         map->len = (size_t)st.st_size;
2924 #ifdef QUICK
2925         if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
2926             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
2927                 file_error(ms, errno, "cannot map `%s'", dbname);
2928                 goto error;
2929         }
2930         map->type = MAP_TYPE_MMAP;
2931 #else
2932         if ((map->p = CAST(void *, malloc(map->len))) == NULL) {
2933                 file_oomem(ms, map->len);
2934                 goto error;
2935         }
2936         if (read(fd, map->p, map->len) != (ssize_t)map->len) {
2937                 file_badread(ms);
2938                 goto error;
2939         }
2940         map->type = MAP_TYPE_MALLOC;
2941 #define RET     1
2942 #endif
2943         (void)close(fd);
2944         fd = -1;
2945
2946         if (check_buffer(ms, map, dbname) != 0)
2947                 goto error;
2948
2949         free(dbname);
2950         return map;
2951
2952 error:
2953         if (fd != -1)
2954                 (void)close(fd);
2955         apprentice_unmap(map);
2956         free(dbname);
2957         return NULL;
2958 }
2959
2960 private int
2961 check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname)
2962 {
2963         uint32_t *ptr;
2964         uint32_t entries, nentries;
2965         uint32_t version;
2966         int i, needsbyteswap;
2967
2968         ptr = CAST(uint32_t *, map->p);
2969         if (*ptr != MAGICNO) {
2970                 if (swap4(*ptr) != MAGICNO) {
2971                         file_error(ms, 0, "bad magic in `%s'", dbname);
2972                         return -1;
2973                 }
2974                 needsbyteswap = 1;
2975         } else
2976                 needsbyteswap = 0;
2977         if (needsbyteswap)
2978                 version = swap4(ptr[1]);
2979         else
2980                 version = ptr[1];
2981         if (version != VERSIONNO) {
2982                 file_error(ms, 0, "File %s supports only version %d magic "
2983                     "files. `%s' is version %d", VERSION,
2984                     VERSIONNO, dbname, version);
2985                 return -1;
2986         }
2987         entries = (uint32_t)(map->len / sizeof(struct magic));
2988         if ((entries * sizeof(struct magic)) != map->len) {
2989                 file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not "
2990                     "a multiple of %" SIZE_T_FORMAT "u",
2991                     dbname, map->len, sizeof(struct magic));
2992                 return -1;
2993         }
2994         map->magic[0] = CAST(struct magic *, map->p) + 1;
2995         nentries = 0;
2996         for (i = 0; i < MAGIC_SETS; i++) {
2997                 if (needsbyteswap)
2998                         map->nmagic[i] = swap4(ptr[i + 2]);
2999                 else
3000                         map->nmagic[i] = ptr[i + 2];
3001                 if (i != MAGIC_SETS - 1)
3002                         map->magic[i + 1] = map->magic[i] + map->nmagic[i];
3003                 nentries += map->nmagic[i];
3004         }
3005         if (entries != nentries + 1) {
3006                 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u",
3007                     dbname, entries, nentries + 1);
3008                 return -1;
3009         }
3010         if (needsbyteswap)
3011                 for (i = 0; i < MAGIC_SETS; i++)
3012                         byteswap(map->magic[i], map->nmagic[i]);
3013         return 0;
3014 }
3015
3016 /*
3017  * handle an mmaped file.
3018  */
3019 private int
3020 apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn)
3021 {
3022         static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS;
3023         static const size_t m = sizeof(**map->magic);
3024         int fd = -1;
3025         size_t len;
3026         char *dbname;
3027         int rv = -1;
3028         uint32_t i;
3029         union {
3030                 struct magic m;
3031                 uint32_t h[2 + MAGIC_SETS];
3032         } hdr;
3033
3034         dbname = mkdbname(ms, fn, 1);
3035
3036         if (dbname == NULL) 
3037                 goto out;
3038
3039         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 
3040         {
3041                 file_error(ms, errno, "cannot open `%s'", dbname);
3042                 goto out;
3043         }
3044         memset(&hdr, 0, sizeof(hdr));
3045         hdr.h[0] = MAGICNO;
3046         hdr.h[1] = VERSIONNO;
3047         memcpy(hdr.h + 2, map->nmagic, nm);
3048
3049         if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) {
3050                 file_error(ms, errno, "error writing `%s'", dbname);
3051                 goto out;
3052         }
3053
3054         for (i = 0; i < MAGIC_SETS; i++) {
3055                 len = m * map->nmagic[i];
3056                 if (write(fd, map->magic[i], len) != (ssize_t)len) {
3057                         file_error(ms, errno, "error writing `%s'", dbname);
3058                         goto out;
3059                 }
3060         }
3061
3062         if (fd != -1)
3063                 (void)close(fd);
3064         rv = 0;
3065 out:
3066         free(dbname);
3067         return rv;
3068 }
3069
3070 private const char ext[] = ".mgc";
3071 /*
3072  * make a dbname
3073  */
3074 private char *
3075 mkdbname(struct magic_set *ms, const char *fn, int strip)
3076 {
3077         const char *p, *q;
3078         char *buf;
3079
3080         if (strip) {
3081                 if ((p = strrchr(fn, '/')) != NULL)
3082                         fn = ++p;
3083         }
3084
3085         for (q = fn; *q; q++)
3086                 continue;
3087         /* Look for .mgc */
3088         for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
3089                 if (*p != *q)
3090                         break;
3091
3092         /* Did not find .mgc, restore q */
3093         if (p >= ext)
3094                 while (*q)
3095                         q++;
3096
3097         q++;
3098         /* Compatibility with old code that looked in .mime */
3099         if (ms->flags & MAGIC_MIME) {
3100                 if (asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext) < 0)
3101                         return NULL;
3102                 if (access(buf, R_OK) != -1) {
3103                         ms->flags &= MAGIC_MIME_TYPE;
3104                         return buf;
3105                 }
3106                 free(buf);
3107         }
3108         if (asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext) < 0)
3109                 return NULL;
3110
3111         /* Compatibility with old code that looked in .mime */
3112         if (strstr(p, ".mime") != NULL)
3113                 ms->flags &= MAGIC_MIME_TYPE;
3114         return buf;
3115 }
3116
3117 /*
3118  * Byteswap an mmap'ed file if needed
3119  */
3120 private void
3121 byteswap(struct magic *magic, uint32_t nmagic)
3122 {
3123         uint32_t i;
3124         for (i = 0; i < nmagic; i++)
3125                 bs1(&magic[i]);
3126 }
3127
3128 /*
3129  * swap a short
3130  */
3131 private uint16_t
3132 swap2(uint16_t sv)
3133 {
3134         uint16_t rv;
3135         uint8_t *s = (uint8_t *)(void *)&sv; 
3136         uint8_t *d = (uint8_t *)(void *)&rv; 
3137         d[0] = s[1];
3138         d[1] = s[0];
3139         return rv;
3140 }
3141
3142 /*
3143  * swap an int
3144  */
3145 private uint32_t
3146 swap4(uint32_t sv)
3147 {
3148         uint32_t rv;
3149         uint8_t *s = (uint8_t *)(void *)&sv; 
3150         uint8_t *d = (uint8_t *)(void *)&rv; 
3151         d[0] = s[3];
3152         d[1] = s[2];
3153         d[2] = s[1];
3154         d[3] = s[0];
3155         return rv;
3156 }
3157
3158 /*
3159  * swap a quad
3160  */
3161 private uint64_t
3162 swap8(uint64_t sv)
3163 {
3164         uint64_t rv;
3165         uint8_t *s = (uint8_t *)(void *)&sv; 
3166         uint8_t *d = (uint8_t *)(void *)&rv; 
3167 #if 0
3168         d[0] = s[3];
3169         d[1] = s[2];
3170         d[2] = s[1];
3171         d[3] = s[0];
3172         d[4] = s[7];
3173         d[5] = s[6];
3174         d[6] = s[5];
3175         d[7] = s[4];
3176 #else
3177         d[0] = s[7];
3178         d[1] = s[6];
3179         d[2] = s[5];
3180         d[3] = s[4];
3181         d[4] = s[3];
3182         d[5] = s[2];
3183         d[6] = s[1];
3184         d[7] = s[0];
3185 #endif
3186         return rv;
3187 }
3188
3189 /*
3190  * byteswap a single magic entry
3191  */
3192 private void
3193 bs1(struct magic *m)
3194 {
3195         m->cont_level = swap2(m->cont_level);
3196         m->offset = swap4((uint32_t)m->offset);
3197         m->in_offset = swap4((uint32_t)m->in_offset);
3198         m->lineno = swap4((uint32_t)m->lineno);
3199         if (IS_STRING(m->type)) {
3200                 m->str_range = swap4(m->str_range);
3201                 m->str_flags = swap4(m->str_flags);
3202         }
3203         else {
3204                 m->value.q = swap8(m->value.q);
3205                 m->num_mask = swap8(m->num_mask);
3206         }
3207 }
3208
3209 protected size_t 
3210 file_pstring_length_size(const struct magic *m)
3211 {
3212         switch (m->str_flags & PSTRING_LEN) {
3213         case PSTRING_1_LE:
3214                 return 1;
3215         case PSTRING_2_LE:
3216         case PSTRING_2_BE:
3217                 return 2;
3218         case PSTRING_4_LE:
3219         case PSTRING_4_BE:
3220                 return 4;
3221         default:
3222                 abort();        /* Impossible */
3223                 return 1;
3224         }
3225 }
3226 protected size_t
3227 file_pstring_get_length(const struct magic *m, const char *ss)
3228 {
3229         size_t len = 0;
3230         const unsigned char *s = (const unsigned char *)ss;
3231
3232         switch (m->str_flags & PSTRING_LEN) {
3233         case PSTRING_1_LE:
3234                 len = *s;
3235                 break;
3236         case PSTRING_2_LE:
3237                 len = (s[1] << 8) | s[0];
3238                 break;
3239         case PSTRING_2_BE:
3240                 len = (s[0] << 8) | s[1];
3241                 break;
3242         case PSTRING_4_LE:
3243                 len = (s[3] << 24) | (s[2] << 16) | (s[1] << 8) | s[0];
3244                 break;
3245         case PSTRING_4_BE:
3246                 len = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
3247                 break;
3248         default:
3249                 abort();        /* Impossible */
3250         }
3251
3252         if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF)
3253                 len -= file_pstring_length_size(m);
3254
3255         return len;
3256 }
3257
3258 protected int
3259 file_magicfind(struct magic_set *ms, const char *name, struct mlist *v)
3260 {
3261         uint32_t i, j;
3262         struct mlist *mlist, *ml;
3263
3264         mlist = ms->mlist[1];
3265
3266         for (ml = mlist->next; ml != mlist; ml = ml->next) {
3267                 struct magic *ma = ml->magic;
3268                 uint32_t nma = ml->nmagic;
3269                 for (i = 0; i < nma; i++) {
3270                         if (ma[i].type != FILE_NAME)
3271                                 continue;
3272                         if (strcmp(ma[i].value.s, name) == 0) {
3273                                 v->magic = &ma[i];
3274                                 for (j = i + 1; j < nma; j++)
3275                                     if (ma[j].cont_level == 0)
3276                                             break;
3277                                 v->nmagic = j - i;
3278                                 return 0;
3279                         }
3280                 }
3281         }
3282         return -1;
3283 }