Update to file-4.19.
[dragonfly.git] / contrib / file-4 / 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 #include "magic.h"
34 #include <stdlib.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <string.h>
39 #include <assert.h>
40 #include <ctype.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <sys/param.h>
44 #ifdef QUICK
45 #include <sys/mman.h>
46 #endif
47
48 #ifndef lint
49 FILE_RCSID("@(#)$Id: apprentice.c,v 1.100 2006/12/11 21:48:49 christos Exp $")
50 #endif  /* lint */
51
52 #define EATAB {while (isascii((unsigned char) *l) && \
53                       isspace((unsigned char) *l))  ++l;}
54 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
55                         tolower((unsigned char) (l)) : (l))
56 /*
57  * Work around a bug in headers on Digital Unix.
58  * At least confirmed for: OSF1 V4.0 878
59  */
60 #if defined(__osf__) && defined(__DECC)
61 #ifdef MAP_FAILED
62 #undef MAP_FAILED
63 #endif
64 #endif
65
66 #ifndef MAP_FAILED
67 #define MAP_FAILED (void *) -1
68 #endif
69
70 #ifndef MAP_FILE
71 #define MAP_FILE 0
72 #endif
73
74 #ifndef MAXPATHLEN
75 #define MAXPATHLEN      1024
76 #endif
77
78 #define IS_PLAINSTRING(t) ((t) == FILE_STRING || (t) == FILE_PSTRING || \
79     (t) == FILE_BESTRING16 || (t) == FILE_LESTRING16)
80     
81 #define IS_STRING(t) (IS_PLAINSTRING(t) || (t) == FILE_REGEX || \
82     (t) == FILE_SEARCH)
83
84 struct magic_entry {
85         struct magic *mp;       
86         uint32_t cont_count;
87         uint32_t max_count;
88 };
89
90 const int file_formats[] = { FILE_FORMAT_STRING };
91 const size_t file_nformats = sizeof(file_formats) / sizeof(file_formats[0]);
92 const char *file_names[] = { FILE_FORMAT_NAME };
93 const size_t file_nnames = sizeof(file_names) / sizeof(file_names[0]);
94
95 private int getvalue(struct magic_set *ms, struct magic *, const char **);
96 private int hextoint(int);
97 private const char *getstr(struct magic_set *, const char *, char *, int,
98     int *);
99 private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
100     const char *, size_t, int);
101 private void eatsize(const char **);
102 private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
103 private size_t apprentice_magic_strength(const struct magic *);
104 private int apprentice_sort(const void *, const void *);
105 private int apprentice_file(struct magic_set *, struct magic **, uint32_t *,
106     const char *, int);
107 private void byteswap(struct magic *, uint32_t);
108 private void bs1(struct magic *);
109 private uint16_t swap2(uint16_t);
110 private uint32_t swap4(uint32_t);
111 private uint64_t swap8(uint64_t);
112 private char *mkdbname(const char *, char *, size_t, int);
113 private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
114     const char *);
115 private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
116     const char *);
117 private int check_format_type(const char *, int);
118 private int check_format(struct magic_set *, struct magic *);
119
120 private size_t maxmagic = 0;
121 private size_t magicsize = sizeof(struct magic);
122
123
124 #ifdef COMPILE_ONLY
125
126 int main(int, char *[]);
127
128 int
129 main(int argc, char *argv[])
130 {
131         int ret;
132         struct magic_set *ms;
133         char *progname;
134
135         if ((progname = strrchr(argv[0], '/')) != NULL)
136                 progname++;
137         else
138                 progname = argv[0];
139
140         if (argc != 2) {
141                 (void)fprintf(stderr, "Usage: %s file\n", progname);
142                 return 1;
143         }
144
145         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
146                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
147                 return 1;
148         }
149         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
150         if (ret == 1)
151                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
152         magic_close(ms);
153         return ret;
154 }
155 #endif /* COMPILE_ONLY */
156
157
158 /*
159  * Handle one file.
160  */
161 private int
162 apprentice_1(struct magic_set *ms, const char *fn, int action,
163     struct mlist *mlist)
164 {
165         struct magic *magic = NULL;
166         uint32_t nmagic = 0;
167         struct mlist *ml;
168         int rv = -1;
169         int mapped;
170
171         if (magicsize != FILE_MAGICSIZE) {
172                 file_error(ms, 0, "magic element size %lu != %lu",
173                     (unsigned long)sizeof(*magic),
174                     (unsigned long)FILE_MAGICSIZE);
175                 return -1;
176         }
177
178         if (action == FILE_COMPILE) {
179                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
180                 if (rv != 0)
181                         return -1;
182                 rv = apprentice_compile(ms, &magic, &nmagic, fn);
183                 free(magic);
184                 return rv;
185         }
186
187 #ifndef COMPILE_ONLY
188         if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
189                 if (ms->flags & MAGIC_CHECK)
190                         file_magwarn(ms, "using regular magic file `%s'", fn);
191                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
192                 if (rv != 0)
193                         return -1;
194                 mapped = 0;
195         }
196
197         mapped = rv;
198              
199         if (magic == NULL || nmagic == 0) {
200                 file_delmagic(magic, mapped, nmagic);
201                 return -1;
202         }
203
204         if ((ml = malloc(sizeof(*ml))) == NULL) {
205                 file_delmagic(magic, mapped, nmagic);
206                 file_oomem(ms, sizeof(*ml));
207                 return -1;
208         }
209
210         ml->magic = magic;
211         ml->nmagic = nmagic;
212         ml->mapped = mapped;
213
214         mlist->prev->next = ml;
215         ml->prev = mlist->prev;
216         ml->next = mlist;
217         mlist->prev = ml;
218
219         return 0;
220 #endif /* COMPILE_ONLY */
221 }
222
223 protected void
224 file_delmagic(struct magic *p, int type, size_t entries)
225 {
226         if (p == NULL)
227                 return;
228         switch (type) {
229         case 2:
230                 p--;
231                 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
232                 break;
233         case 1:
234                 p--;
235                 /*FALLTHROUGH*/
236         case 0:
237                 free(p);
238                 break;
239         default:
240                 abort();
241         }
242 }
243
244
245 /* const char *fn: list of magic files */
246 protected struct mlist *
247 file_apprentice(struct magic_set *ms, const char *fn, int action)
248 {
249         char *p, *mfn, *afn = NULL;
250         int file_err, errs = -1;
251         struct mlist *mlist;
252         static const char mime[] = ".mime";
253
254         if (fn == NULL)
255                 fn = getenv("MAGIC");
256         if (fn == NULL)
257                 fn = MAGIC;
258
259         if ((fn = mfn = strdup(fn)) == NULL) {
260                 file_oomem(ms, strlen(fn));
261                 return NULL;
262         }
263
264         if ((mlist = malloc(sizeof(*mlist))) == NULL) {
265                 free(mfn);
266                 file_oomem(ms, sizeof(*mlist));
267                 return NULL;
268         }
269         mlist->next = mlist->prev = mlist;
270
271         while (fn) {
272                 p = strchr(fn, PATHSEP);
273                 if (p)
274                         *p++ = '\0';
275                 if (*fn == '\0')
276                         break;
277                 if (ms->flags & MAGIC_MIME) {
278                         size_t len = strlen(fn) + sizeof(mime);
279                         if ((afn = malloc(len)) == NULL) {
280                                 free(mfn);
281                                 free(mlist);
282                                 file_oomem(ms, len);
283                                 return NULL;
284                         }
285                         (void)strcpy(afn, fn);
286                         (void)strcat(afn, mime);
287                         fn = afn;
288                 }
289                 file_err = apprentice_1(ms, fn, action, mlist);
290                 if (file_err > errs)
291                         errs = file_err;
292                 if (afn) {
293                         free(afn);
294                         afn = NULL;
295                 }
296                 fn = p;
297         }
298         if (errs == -1) {
299                 free(mfn);
300                 free(mlist);
301                 mlist = NULL;
302                 file_error(ms, 0, "could not find any magic files!");
303                 return NULL;
304         }
305         free(mfn);
306         return mlist;
307 }
308
309 /*
310  * Get weight of this magic entry, for sorting purposes.
311  */
312 private size_t
313 apprentice_magic_strength(const struct magic *m)
314 {
315 #define MULT 10
316         size_t val = 2 * MULT;  /* baseline strength */
317
318         switch (m->type) {
319         case FILE_BYTE:
320                 val += 1 * MULT;
321                 break;
322
323         case FILE_SHORT:
324         case FILE_LESHORT:
325         case FILE_BESHORT:
326                 val += 2 * MULT;
327                 break;
328
329         case FILE_LONG:
330         case FILE_LELONG:
331         case FILE_BELONG:
332         case FILE_MELONG:
333                 val += 4 * MULT;
334                 break;
335
336         case FILE_PSTRING:
337         case FILE_STRING:
338                 val += m->vallen * MULT;
339                 break;
340
341         case FILE_BESTRING16:
342         case FILE_LESTRING16:
343                 val += m->vallen * MULT / 2;
344                 break;
345
346         case FILE_SEARCH:
347         case FILE_REGEX:
348                 val += m->vallen;
349                 break;
350
351         case FILE_DATE:
352         case FILE_LEDATE:
353         case FILE_BEDATE:
354         case FILE_MEDATE:
355         case FILE_LDATE:
356         case FILE_LELDATE:
357         case FILE_BELDATE:
358         case FILE_MELDATE:
359                 val += 4 * MULT;
360                 break;
361
362         case FILE_QUAD:
363         case FILE_BEQUAD:
364         case FILE_LEQUAD:
365         case FILE_QDATE:
366         case FILE_LEQDATE:
367         case FILE_BEQDATE:
368         case FILE_QLDATE:
369         case FILE_LEQLDATE:
370         case FILE_BEQLDATE:
371                 val += 8 * MULT;
372                 break;
373
374         default:
375                 val = 0;
376                 (void)fprintf(stderr, "Bad type %d\n", m->type);
377                 abort();
378         }
379
380         switch (m->reln) {
381         case 'x':       /* matches anything penalize */
382                 val = 0;
383                 break;
384
385         case '!':
386         case '=':       /* Exact match, prefer */
387                 val += MULT;
388                 break;
389
390         case '>':
391         case '<':       /* comparison match reduce strength */
392                 val -= 2 * MULT;
393                 break;
394
395         case '^':
396         case '&':       /* masking bits, we could count them too */
397                 val -= MULT;
398                 break;
399
400         default:
401                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
402                 abort();
403         }
404         return val;
405 }
406
407 /*  
408  * Sort callback for sorting entries by "strength" (basically length)
409  */
410 private int
411 apprentice_sort(const void *a, const void *b)
412 {
413         const struct magic_entry *ma = a;
414         const struct magic_entry *mb = b;
415         size_t sa = apprentice_magic_strength(ma->mp);
416         size_t sb = apprentice_magic_strength(mb->mp);
417         if (sa == sb)
418                 return 0;
419         else if (sa > sb)
420                 return -1;
421         else
422                 return 1;
423 }
424
425 /*
426  * parse from a file
427  * const char *fn: name of magic file
428  */
429 private int
430 apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
431     const char *fn, int action)
432 {
433         private const char hdr[] =
434                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
435         FILE *f;
436         char line[BUFSIZ+1];
437         int errs = 0;
438         struct magic_entry *marray;
439         uint32_t marraycount, i, mentrycount = 0;
440         size_t lineno = 0;
441
442         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
443
444         f = fopen(ms->file = fn, "r");
445         if (f == NULL) {
446                 if (errno != ENOENT)
447                         file_error(ms, errno, "cannot read magic file `%s'",
448                             fn);
449                 return -1;
450         }
451
452         maxmagic = MAXMAGIS;
453         if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
454                 (void)fclose(f);
455                 file_oomem(ms, maxmagic * sizeof(*marray));
456                 return -1;
457         }
458         marraycount = 0;
459
460         /* print silly verbose header for USG compat. */
461         if (action == FILE_CHECK)
462                 (void)fprintf(stderr, "%s\n", hdr);
463
464         /* read and parse this file */
465         for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) {
466                 size_t len;
467                 len = strlen(line);
468                 if (len == 0) /* null line, garbage, etc */
469                         continue;
470                 if (line[len - 1] == '\n') {
471                         lineno++;
472                         line[len - 1] = '\0'; /* delete newline */
473                 }
474                 if (line[0] == '\0')    /* empty, do not parse */
475                         continue;
476                 if (line[0] == '#')     /* comment, do not parse */
477                         continue;
478                 if (parse(ms, &marray, &marraycount, line, lineno, action) != 0)
479                         errs++;
480         }
481
482         (void)fclose(f);
483         if (errs)
484                 goto out;
485
486 #ifndef NOORDER
487         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
488 #endif
489
490         for (i = 0; i < marraycount; i++)
491                 mentrycount += marray[i].cont_count;
492
493         if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
494                 file_oomem(ms, sizeof(**magicp) * mentrycount);
495                 errs++;
496                 goto out;
497         }
498
499         mentrycount = 0;
500         for (i = 0; i < marraycount; i++) {
501                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
502                     marray[i].cont_count * sizeof(**magicp));
503                 mentrycount += marray[i].cont_count;
504         }
505 out:
506         for (i = 0; i < marraycount; i++)
507                 free(marray[i].mp);
508         free(marray);
509         if (errs) {
510                 *magicp = NULL;
511                 *nmagicp = 0;
512                 return errs;
513         } else {
514                 *nmagicp = mentrycount;
515                 return 0;
516         }
517
518 }
519
520 /*
521  * extend the sign bit if the comparison is to be signed
522  */
523 protected uint64_t
524 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
525 {
526         if (!(m->flag & UNSIGNED))
527                 switch(m->type) {
528                 /*
529                  * Do not remove the casts below.  They are
530                  * vital.  When later compared with the data,
531                  * the sign extension must have happened.
532                  */
533                 case FILE_BYTE:
534                         v = (char) v;
535                         break;
536                 case FILE_SHORT:
537                 case FILE_BESHORT:
538                 case FILE_LESHORT:
539                         v = (short) v;
540                         break;
541                 case FILE_DATE:
542                 case FILE_BEDATE:
543                 case FILE_LEDATE:
544                 case FILE_MEDATE:
545                 case FILE_LDATE:
546                 case FILE_BELDATE:
547                 case FILE_LELDATE:
548                 case FILE_MELDATE:
549                 case FILE_LONG:
550                 case FILE_BELONG:
551                 case FILE_LELONG:
552                 case FILE_MELONG:
553                         v = (int32_t) v;
554                         break;
555                 case FILE_QUAD:
556                 case FILE_BEQUAD:
557                 case FILE_LEQUAD:
558                 case FILE_QDATE:
559                 case FILE_QLDATE:
560                 case FILE_BEQDATE:
561                 case FILE_BEQLDATE:
562                 case FILE_LEQDATE:
563                 case FILE_LEQLDATE:
564                         v = (int64_t) v;
565                         break;
566                 case FILE_STRING:
567                 case FILE_PSTRING:
568                 case FILE_BESTRING16:
569                 case FILE_LESTRING16:
570                 case FILE_REGEX:
571                 case FILE_SEARCH:
572                         break;
573                 default:
574                         if (ms->flags & MAGIC_CHECK)
575                             file_magwarn(ms, "cannot happen: m->type=%d\n",
576                                     m->type);
577                         return ~0U;
578                 }
579         return v;
580 }
581
582 /*
583  * parse one line from magic file, put into magic[index++] if valid
584  */
585 private int
586 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
587     const char *line, size_t lineno, int action)
588 {
589         size_t i;
590         struct magic_entry *me;
591         struct magic *m;
592         const char *l = line;
593         char *t;
594         private const char *fops = FILE_OPS;
595         uint64_t val;
596         uint32_t cont_level;
597
598         cont_level = 0;
599
600         while (*l == '>') {
601                 ++l;            /* step over */
602                 cont_level++; 
603         }
604
605 #define ALLOC_CHUNK     (size_t)10
606 #define ALLOC_INCR      (size_t)200
607
608         if (cont_level != 0) {
609                 if (*nmentryp == 0) {
610                         file_error(ms, 0, "No current entry for continuation");
611                         return -1;
612                 }
613                 me = &(*mentryp)[*nmentryp - 1];
614                 if (me->cont_count == me->max_count) {
615                         struct magic *nm;
616                         size_t cnt = me->max_count + ALLOC_CHUNK;
617                         if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
618                                 file_oomem(ms, sizeof(*nm) * cnt);
619                                 return -1;
620                         }
621                         me->mp = m = nm;
622                         me->max_count = cnt;
623                 }
624                 m = &me->mp[me->cont_count++];
625                 memset(m, 0, sizeof(*m));
626                 m->cont_level = cont_level;
627         } else {
628                 if (*nmentryp == maxmagic) {
629                         struct magic_entry *mp;
630
631                         maxmagic += ALLOC_INCR;
632                         if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
633                             NULL) {
634                                 file_oomem(ms, sizeof(*mp) * maxmagic);
635                                 return -1;
636                         }
637                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
638                             ALLOC_INCR);
639                         *mentryp = mp;
640                 }
641                 me = &(*mentryp)[*nmentryp];
642                 if (me->mp == NULL) {
643                         if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
644                                 file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
645                                 return -1;
646                         }
647                         me->mp = m;
648                         me->max_count = ALLOC_CHUNK;
649                 } else
650                         m = me->mp;
651                 memset(m, 0, sizeof(*m));
652                 m->cont_level = 0;
653                 me->cont_count = 1;
654         }
655         m->lineno = lineno;
656
657         if (m->cont_level != 0 && *l == '&') {
658                 ++l;            /* step over */
659                 m->flag |= OFFADD;
660         }
661         if (m->cont_level != 0 && *l == '(') {
662                 ++l;            /* step over */
663                 m->flag |= INDIR;
664                 if (m->flag & OFFADD)
665                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
666         }
667         if (m->cont_level != 0 && *l == '&') {
668                 ++l;            /* step over */
669                 m->flag |= OFFADD;
670         }
671
672         /* get offset, then skip over it */
673         m->offset = (uint32_t)strtoul(l, &t, 0);
674         if (l == t)
675                 if (ms->flags & MAGIC_CHECK)
676                         file_magwarn(ms, "offset `%s' invalid", l);
677         l = t;
678
679         if (m->flag & INDIR) {
680                 m->in_type = FILE_LONG;
681                 m->in_offset = 0;
682                 /*
683                  * read [.lbs][+-]nnnnn)
684                  */
685                 if (*l == '.') {
686                         l++;
687                         switch (*l) {
688                         case 'l':
689                                 m->in_type = FILE_LELONG;
690                                 break;
691                         case 'L':
692                                 m->in_type = FILE_BELONG;
693                                 break;
694                         case 'm':
695                                 m->in_type = FILE_MELONG;
696                                 break;
697                         case 'h':
698                         case 's':
699                                 m->in_type = FILE_LESHORT;
700                                 break;
701                         case 'H':
702                         case 'S':
703                                 m->in_type = FILE_BESHORT;
704                                 break;
705                         case 'c':
706                         case 'b':
707                         case 'C':
708                         case 'B':
709                                 m->in_type = FILE_BYTE;
710                                 break;
711                         default:
712                                 if (ms->flags & MAGIC_CHECK)
713                                         file_magwarn(ms,
714                                             "indirect offset type `%c' invalid",
715                                             *l);
716                                 break;
717                         }
718                         l++;
719                 }
720                 if (*l == '~') {
721                         m->in_op |= FILE_OPINVERSE;
722                         l++;
723                 }
724                 switch (*l) {
725                 case '&':
726                         m->in_op |= FILE_OPAND;
727                         l++;
728                         break;
729                 case '|':
730                         m->in_op |= FILE_OPOR;
731                         l++;
732                         break;
733                 case '^':
734                         m->in_op |= FILE_OPXOR;
735                         l++;
736                         break;
737                 case '+':
738                         m->in_op |= FILE_OPADD;
739                         l++;
740                         break;
741                 case '-':
742                         m->in_op |= FILE_OPMINUS;
743                         l++;
744                         break;
745                 case '*':
746                         m->in_op |= FILE_OPMULTIPLY;
747                         l++;
748                         break;
749                 case '/':
750                         m->in_op |= FILE_OPDIVIDE;
751                         l++;
752                         break;
753                 case '%':
754                         m->in_op |= FILE_OPMODULO;
755                         l++;
756                         break;
757                 }
758                 if (*l == '(') {
759                         m->in_op |= FILE_OPINDIRECT;
760                         l++;
761                 }
762                 if (isdigit((unsigned char)*l) || *l == '-') {
763                         m->in_offset = (int32_t)strtol(l, &t, 0);
764                         l = t;
765                 }
766                 if (*l++ != ')' || 
767                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
768                         if (ms->flags & MAGIC_CHECK)
769                                 file_magwarn(ms,
770                                     "missing ')' in indirect offset");
771         }
772
773
774         while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
775                 ++l;
776         EATAB;
777
778         if (*l == 'u') {
779                 ++l;
780                 m->flag |= UNSIGNED;
781         }
782
783         /* get type, skip it */
784         for (i = 0; i < file_nnames; i++) {
785                 size_t len = strlen(file_names[i]);
786                 if (strncmp(l, file_names[i], len) == 0) {
787                         m->type = i;
788                         l+= len;
789                         break;
790                 }
791         }
792         if (i == file_nnames) {
793                 if (ms->flags & MAGIC_CHECK)
794                         file_magwarn(ms, "type `%s' invalid", l);
795                 return -1;
796         }
797         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
798         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
799         if (*l == '~') {
800                 if (!IS_STRING(m->type))
801                         m->mask_op |= FILE_OPINVERSE;
802                 ++l;
803         }
804         if ((t = strchr(fops,  *l)) != NULL) {
805                 uint32_t op = (uint32_t)(t - fops);
806                 if (op != FILE_OPDIVIDE || !IS_PLAINSTRING(m->type)) {
807                         ++l;
808                         m->mask_op |= op;
809                         val = (uint64_t)strtoull(l, &t, 0);
810                         l = t;
811                         m->mask = file_signextend(ms, m, val);
812                         eatsize(&l);
813                 } else {
814                         m->mask = 0L;
815                         while (!isspace((unsigned char)*++l)) {
816                                 switch (*l) {
817                                 case CHAR_IGNORE_LOWERCASE:
818                                         m->mask |= STRING_IGNORE_LOWERCASE;
819                                         break;
820                                 case CHAR_COMPACT_BLANK:
821                                         m->mask |= STRING_COMPACT_BLANK;
822                                         break;
823                                 case CHAR_COMPACT_OPTIONAL_BLANK:
824                                         m->mask |=
825                                             STRING_COMPACT_OPTIONAL_BLANK;
826                                         break;
827                                 default:
828                                         if (ms->flags & MAGIC_CHECK)
829                                                 file_magwarn(ms,
830                                                 "string extension `%c' invalid",
831                                                 *l);
832                                         return -1;
833                                 }
834                         }
835                         ++l;
836                 }
837         }
838         /*
839          * We used to set mask to all 1's here, instead let's just not do
840          * anything if mask = 0 (unless you have a better idea)
841          */
842         EATAB;
843   
844         switch (*l) {
845         case '>':
846         case '<':
847         /* Old-style anding: "0 byte &0x80 dynamically linked" */
848         case '&':
849         case '^':
850         case '=':
851                 m->reln = *l;
852                 ++l;
853                 if (*l == '=') {
854                    /* HP compat: ignore &= etc. */
855                    ++l;
856                 }
857                 break;
858         case '!':
859                 m->reln = *l;
860                 ++l;
861                 break;
862         default:
863                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
864                     isspace((unsigned char)l[1])) || !l[1])) {
865                         m->reln = *l;
866                         ++l;
867                         goto GetDesc;   /* Bill The Cat */
868                 }
869                 m->reln = '=';
870                 break;
871         }
872         EATAB;
873   
874         if (getvalue(ms, m, &l))
875                 return -1;
876         /*
877          * TODO finish this macro and start using it!
878          * #define offsetcheck {if (offset > HOWMANY-1) 
879          *      magwarn("offset too big"); }
880          */
881
882         /*
883          * now get last part - the description
884          */
885 GetDesc:
886         EATAB;
887         if (l[0] == '\b') {
888                 ++l;
889                 m->nospflag = 1;
890         } else if ((l[0] == '\\') && (l[1] == 'b')) {
891                 ++l;
892                 ++l;
893                 m->nospflag = 1;
894         } else
895                 m->nospflag = 0;
896         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
897                 continue;
898         if (i == sizeof(m->desc)) {
899                 m->desc[sizeof(m->desc) - 1] = '\0';
900                 if (ms->flags & MAGIC_CHECK)
901                         file_magwarn(ms, "description `%s' truncated", m->desc);
902         }
903
904         /*
905          * We only do this check while compiling, or if any of the magic
906          * files were not compiled.
907          */
908         if (ms->flags & MAGIC_CHECK) {
909                 if (check_format(ms, m) == -1)
910                         return -1;
911         }
912 #ifndef COMPILE_ONLY
913         if (action == FILE_CHECK) {
914                 file_mdump(m);
915         }
916 #endif
917         if (m->cont_level == 0)
918                 ++(*nmentryp);          /* make room for next */
919         return 0;
920 }
921
922 private int
923 check_format_type(const char *ptr, int type)
924 {
925         int quad = 0;
926         if (*ptr == '\0') {
927                 /* Missing format string; bad */
928                 return -1;
929         }
930
931         switch (type) {
932         case FILE_FMT_QUAD:
933                 quad = 1;
934                 /*FALLTHROUGH*/
935         case FILE_FMT_NUM:
936                 if (*ptr == '-')
937                         ptr++;
938                 if (*ptr == '.')
939                         ptr++;
940                 while (isdigit((unsigned char)*ptr)) ptr++;
941                 if (*ptr == '.')
942                         ptr++;
943                 while (isdigit((unsigned char)*ptr)) ptr++;
944                 if (quad) {
945                         if (*ptr++ != 'l')
946                                 return -1;
947                         if (*ptr++ != 'l')
948                                 return -1;
949                 }
950         
951                 switch (*ptr++) {
952                 case 'l':
953                         switch (*ptr++) {
954                         case 'i':
955                         case 'd':
956                         case 'u':
957                         case 'x':
958                         case 'X':
959                                 return 0;
960                         default:
961                                 return -1;
962                         }
963                 
964                 case 'h':
965                         switch (*ptr++) {
966                         case 'h':
967                                 switch (*ptr++) {
968                                 case 'i':
969                                 case 'd':
970                                 case 'u':
971                                 case 'x':
972                                 case 'X':
973                                         return 0;
974                                 default:
975                                         return -1;
976                                 }
977                         case 'd':
978                                 return 0;
979                         default:
980                                 return -1;
981                         }
982
983                 case 'i':
984                 case 'c':
985                 case 'd':
986                 case 'u':
987                 case 'x':
988                 case 'X':
989                         return 0;
990                         
991                 default:
992                         return -1;
993                 }
994                 
995         case FILE_FMT_STR:
996                 if (*ptr == '-')
997                         ptr++;
998                 while (isdigit((unsigned char )*ptr))
999                         ptr++;
1000                 if (*ptr == '.') {
1001                         ptr++;
1002                         while (isdigit((unsigned char )*ptr))
1003                                 ptr++;
1004                 }
1005                 
1006                 switch (*ptr++) {
1007                 case 's':
1008                         return 0;
1009                 default:
1010                         return -1;
1011                 }
1012                 
1013         default:
1014                 /* internal error */
1015                 abort();
1016         }
1017         /*NOTREACHED*/
1018         return -1;
1019 }
1020         
1021 /*
1022  * Check that the optional printf format in description matches
1023  * the type of the magic.
1024  */
1025 private int
1026 check_format(struct magic_set *ms, struct magic *m)
1027 {
1028         char *ptr;
1029
1030         for (ptr = m->desc; *ptr; ptr++)
1031                 if (*ptr == '%')
1032                         break;
1033         if (*ptr == '\0') {
1034                 /* No format string; ok */
1035                 return 1;
1036         }
1037
1038         assert(file_nformats == file_nnames);
1039
1040         if (m->type >= file_nformats) {
1041                 file_error(ms, 0, "Internal error inconsistency between "
1042                     "m->type and format strings");              
1043                 return -1;
1044         }
1045         if (file_formats[m->type] == FILE_FMT_NONE) {
1046                 file_error(ms, 0, "No format string for `%s' with description "
1047                     "`%s'", m->desc, file_names[m->type]);
1048                 return -1;
1049         }
1050
1051         ptr++;
1052         if (check_format_type(ptr, file_formats[m->type]) == -1) {
1053                 /*
1054                  * TODO: this error message is unhelpful if the format
1055                  * string is not one character long
1056                  */
1057                 file_error(ms, 0, "Printf format `%c' is not valid for type "
1058                     " `%s' in description `%s'", *ptr,
1059                     file_names[m->type], m->desc);
1060                 return -1;
1061         }
1062         
1063         for (; *ptr; ptr++) {
1064                 if (*ptr == '%') {
1065                         file_error(ms, 0,
1066                             "Too many format strings (should have at most one) "
1067                             "for `%s' with description `%s'",
1068                             file_names[m->type], m->desc);
1069                         return -1;
1070                 }
1071         }
1072         return 0;
1073 }
1074
1075 /* 
1076  * Read a numeric value from a pointer, into the value union of a magic 
1077  * pointer, according to the magic type.  Update the string pointer to point 
1078  * just after the number read.  Return 0 for success, non-zero for failure.
1079  */
1080 private int
1081 getvalue(struct magic_set *ms, struct magic *m, const char **p)
1082 {
1083         int slen;
1084
1085         switch (m->type) {
1086         case FILE_BESTRING16:
1087         case FILE_LESTRING16:
1088         case FILE_STRING:
1089         case FILE_PSTRING:
1090         case FILE_REGEX:
1091         case FILE_SEARCH:
1092                 *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen);
1093                 if (*p == NULL) {
1094                         if (ms->flags & MAGIC_CHECK)
1095                                 file_magwarn(ms, "cannot get string from `%s'",
1096                                     m->value.s);
1097                         return -1;
1098                 }
1099                 m->vallen = slen;
1100                 return 0;
1101         default:
1102                 if (m->reln != 'x') {
1103                         char *ep;
1104                         m->value.q = file_signextend(ms, m,
1105                             (uint64_t)strtoull(*p, &ep, 0));
1106                         *p = ep;
1107                         eatsize(p);
1108                 }
1109                 return 0;
1110         }
1111 }
1112
1113 /*
1114  * Convert a string containing C character escapes.  Stop at an unescaped
1115  * space or tab.
1116  * Copy the converted version to "p", returning its length in *slen.
1117  * Return updated scan pointer as function result.
1118  */
1119 private const char *
1120 getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen)
1121 {
1122         const char *origs = s;
1123         char    *origp = p;
1124         char    *pmax = p + plen - 1;
1125         int     c;
1126         int     val;
1127
1128         while ((c = *s++) != '\0') {
1129                 if (isspace((unsigned char) c))
1130                         break;
1131                 if (p >= pmax) {
1132                         file_error(ms, 0, "string too long: `%s'", origs);
1133                         return NULL;
1134                 }
1135                 if(c == '\\') {
1136                         switch(c = *s++) {
1137
1138                         case '\0':
1139                                 goto out;
1140
1141                         default:
1142                                 *p++ = (char) c;
1143                                 break;
1144
1145                         case 'n':
1146                                 *p++ = '\n';
1147                                 break;
1148
1149                         case 'r':
1150                                 *p++ = '\r';
1151                                 break;
1152
1153                         case 'b':
1154                                 *p++ = '\b';
1155                                 break;
1156
1157                         case 't':
1158                                 *p++ = '\t';
1159                                 break;
1160
1161                         case 'f':
1162                                 *p++ = '\f';
1163                                 break;
1164
1165                         case 'v':
1166                                 *p++ = '\v';
1167                                 break;
1168
1169                         /* \ and up to 3 octal digits */
1170                         case '0':
1171                         case '1':
1172                         case '2':
1173                         case '3':
1174                         case '4':
1175                         case '5':
1176                         case '6':
1177                         case '7':
1178                                 val = c - '0';
1179                                 c = *s++;  /* try for 2 */
1180                                 if(c >= '0' && c <= '7') {
1181                                         val = (val<<3) | (c - '0');
1182                                         c = *s++;  /* try for 3 */
1183                                         if(c >= '0' && c <= '7')
1184                                                 val = (val<<3) | (c-'0');
1185                                         else
1186                                                 --s;
1187                                 }
1188                                 else
1189                                         --s;
1190                                 *p++ = (char)val;
1191                                 break;
1192
1193                         /* \x and up to 2 hex digits */
1194                         case 'x':
1195                                 val = 'x';      /* Default if no digits */
1196                                 c = hextoint(*s++);     /* Get next char */
1197                                 if (c >= 0) {
1198                                         val = c;
1199                                         c = hextoint(*s++);
1200                                         if (c >= 0)
1201                                                 val = (val << 4) + c;
1202                                         else
1203                                                 --s;
1204                                 } else
1205                                         --s;
1206                                 *p++ = (char)val;
1207                                 break;
1208                         }
1209                 } else
1210                         *p++ = (char)c;
1211         }
1212 out:
1213         *p = '\0';
1214         *slen = p - origp;
1215         return s;
1216 }
1217
1218
1219 /* Single hex char to int; -1 if not a hex char. */
1220 private int
1221 hextoint(int c)
1222 {
1223         if (!isascii((unsigned char) c))
1224                 return -1;
1225         if (isdigit((unsigned char) c))
1226                 return c - '0';
1227         if ((c >= 'a')&&(c <= 'f'))
1228                 return c + 10 - 'a';
1229         if (( c>= 'A')&&(c <= 'F'))
1230                 return c + 10 - 'A';
1231         return -1;
1232 }
1233
1234
1235 /*
1236  * Print a string containing C character escapes.
1237  */
1238 protected void
1239 file_showstr(FILE *fp, const char *s, size_t len)
1240 {
1241         char    c;
1242
1243         for (;;) {
1244                 c = *s++;
1245                 if (len == ~0U) {
1246                         if (c == '\0')
1247                                 break;
1248                 }
1249                 else  {
1250                         if (len-- == 0)
1251                                 break;
1252                 }
1253                 if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
1254                         (void) fputc(c, fp);
1255                 else {
1256                         (void) fputc('\\', fp);
1257                         switch (c) {
1258                         
1259                         case '\n':
1260                                 (void) fputc('n', fp);
1261                                 break;
1262
1263                         case '\r':
1264                                 (void) fputc('r', fp);
1265                                 break;
1266
1267                         case '\b':
1268                                 (void) fputc('b', fp);
1269                                 break;
1270
1271                         case '\t':
1272                                 (void) fputc('t', fp);
1273                                 break;
1274
1275                         case '\f':
1276                                 (void) fputc('f', fp);
1277                                 break;
1278
1279                         case '\v':
1280                                 (void) fputc('v', fp);
1281                                 break;
1282
1283                         default:
1284                                 (void) fprintf(fp, "%.3o", c & 0377);
1285                                 break;
1286                         }
1287                 }
1288         }
1289 }
1290
1291 /*
1292  * eatsize(): Eat the size spec from a number [eg. 10UL]
1293  */
1294 private void
1295 eatsize(const char **p)
1296 {
1297         const char *l = *p;
1298
1299         if (LOWCASE(*l) == 'u') 
1300                 l++;
1301
1302         switch (LOWCASE(*l)) {
1303         case 'l':    /* long */
1304         case 's':    /* short */
1305         case 'h':    /* short */
1306         case 'b':    /* char/byte */
1307         case 'c':    /* char/byte */
1308                 l++;
1309                 /*FALLTHROUGH*/
1310         default:
1311                 break;
1312         }
1313
1314         *p = l;
1315 }
1316
1317 /*
1318  * handle a compiled file.
1319  */
1320 private int
1321 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1322     const char *fn)
1323 {
1324         int fd;
1325         struct stat st;
1326         uint32_t *ptr;
1327         uint32_t version;
1328         int needsbyteswap;
1329         char buf[MAXPATHLEN];
1330         char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
1331         void *mm = NULL;
1332
1333         if (dbname == NULL)
1334                 return -1;
1335
1336         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
1337                 return -1;
1338
1339         if (fstat(fd, &st) == -1) {
1340                 file_error(ms, errno, "cannot stat `%s'", dbname);
1341                 goto error;
1342         }
1343         if (st.st_size < 16) {
1344                 file_error(ms, 0, "file `%s' is too small", dbname);
1345                 goto error;
1346         }
1347
1348 #ifdef QUICK
1349         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
1350             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
1351                 file_error(ms, errno, "cannot map `%s'", dbname);
1352                 goto error;
1353         }
1354 #define RET     2
1355 #else
1356         if ((mm = malloc((size_t)st.st_size)) == NULL) {
1357                 file_oomem(ms, (size_t)st.st_size);
1358                 goto error;
1359         }
1360         if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
1361                 file_badread(ms);
1362                 goto error;
1363         }
1364 #define RET     1
1365 #endif
1366         *magicp = mm;
1367         (void)close(fd);
1368         fd = -1;
1369         ptr = (uint32_t *)(void *)*magicp;
1370         if (*ptr != MAGICNO) {
1371                 if (swap4(*ptr) != MAGICNO) {
1372                         file_error(ms, 0, "bad magic in `%s'");
1373                         goto error;
1374                 }
1375                 needsbyteswap = 1;
1376         } else
1377                 needsbyteswap = 0;
1378         if (needsbyteswap)
1379                 version = swap4(ptr[1]);
1380         else
1381                 version = ptr[1];
1382         if (version != VERSIONNO) {
1383                 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
1384                     version, VERSIONNO, dbname);
1385                 goto error;
1386         }
1387         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
1388         (*magicp)++;
1389         if (needsbyteswap)
1390                 byteswap(*magicp, *nmagicp);
1391         return RET;
1392
1393 error:
1394         if (fd != -1)
1395                 (void)close(fd);
1396         if (mm) {
1397 #ifdef QUICK
1398                 (void)munmap((void *)mm, (size_t)st.st_size);
1399 #else
1400                 free(mm);
1401 #endif
1402         } else {
1403                 *magicp = NULL;
1404                 *nmagicp = 0;
1405         }
1406         return -1;
1407 }
1408
1409 private const uint32_t ar[] = {
1410     MAGICNO, VERSIONNO
1411 };
1412 /*
1413  * handle an mmaped file.
1414  */
1415 private int
1416 apprentice_compile(struct magic_set *ms, struct magic **magicp,
1417     uint32_t *nmagicp, const char *fn)
1418 {
1419         int fd;
1420         char buf[MAXPATHLEN];
1421         char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
1422
1423         if (dbname == NULL) 
1424                 return -1;
1425
1426         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
1427                 file_error(ms, errno, "cannot open `%s'", dbname);
1428                 return -1;
1429         }
1430
1431         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
1432                 file_error(ms, errno, "error writing `%s'", dbname);
1433                 return -1;
1434         }
1435
1436         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
1437             != sizeof(struct magic)) {
1438                 file_error(ms, errno, "error seeking `%s'", dbname);
1439                 return -1;
1440         }
1441
1442         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
1443             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
1444                 file_error(ms, errno, "error writing `%s'", dbname);
1445                 return -1;
1446         }
1447
1448         (void)close(fd);
1449         return 0;
1450 }
1451
1452 private const char ext[] = ".mgc";
1453 /*
1454  * make a dbname
1455  */
1456 private char *
1457 mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
1458 {
1459         if (strip) {
1460                 const char *p;
1461                 if ((p = strrchr(fn, '/')) != NULL)
1462                         fn = ++p;
1463         }
1464
1465         (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
1466         return buf;
1467 }
1468
1469 /*
1470  * Byteswap an mmap'ed file if needed
1471  */
1472 private void
1473 byteswap(struct magic *magic, uint32_t nmagic)
1474 {
1475         uint32_t i;
1476         for (i = 0; i < nmagic; i++)
1477                 bs1(&magic[i]);
1478 }
1479
1480 /*
1481  * swap a short
1482  */
1483 private uint16_t
1484 swap2(uint16_t sv)
1485 {
1486         uint16_t rv;
1487         uint8_t *s = (uint8_t *)(void *)&sv; 
1488         uint8_t *d = (uint8_t *)(void *)&rv; 
1489         d[0] = s[1];
1490         d[1] = s[0];
1491         return rv;
1492 }
1493
1494 /*
1495  * swap an int
1496  */
1497 private uint32_t
1498 swap4(uint32_t sv)
1499 {
1500         uint32_t rv;
1501         uint8_t *s = (uint8_t *)(void *)&sv; 
1502         uint8_t *d = (uint8_t *)(void *)&rv; 
1503         d[0] = s[3];
1504         d[1] = s[2];
1505         d[2] = s[1];
1506         d[3] = s[0];
1507         return rv;
1508 }
1509
1510 /*
1511  * swap a quad
1512  */
1513 private uint64_t
1514 swap8(uint64_t sv)
1515 {
1516         uint32_t rv;
1517         uint8_t *s = (uint8_t *)(void *)&sv; 
1518         uint8_t *d = (uint8_t *)(void *)&rv; 
1519         d[0] = s[3];
1520         d[1] = s[2];
1521         d[2] = s[1];
1522         d[3] = s[0];
1523         d[4] = s[7];
1524         d[5] = s[6];
1525         d[6] = s[5];
1526         d[7] = s[4];
1527         return rv;
1528 }
1529
1530 /*
1531  * byteswap a single magic entry
1532  */
1533 private void
1534 bs1(struct magic *m)
1535 {
1536         m->cont_level = swap2(m->cont_level);
1537         m->offset = swap4((uint32_t)m->offset);
1538         m->in_offset = swap4((uint32_t)m->in_offset);
1539         if (!IS_STRING(m->type))
1540                 m->value.q = swap8(m->value.q);
1541         m->mask = swap8(m->mask);
1542 }