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