00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "file.h"
00033 #include "magic.h"
00034 #include <stdlib.h>
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 #include <string.h>
00039 #include <assert.h>
00040 #include <ctype.h>
00041 #include <fcntl.h>
00042 #include <sys/stat.h>
00043 #include <sys/param.h>
00044 #ifdef QUICK
00045 #include <sys/mman.h>
00046 #endif
00047
00048 #ifndef lint
00049 FILE_RCSID("@(#)$File: apprentice.c,v 1.104 2007/01/19 19:54:39 christos Exp $")
00050 #endif
00051
00052 #define EATAB {while (isascii((unsigned char) *l) && \
00053 isspace((unsigned char) *l)) ++l;}
00054 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
00055 tolower((unsigned char) (l)) : (l))
00056
00057
00058
00059
00060 #if defined(__osf__) && defined(__DECC)
00061 #ifdef MAP_FAILED
00062 #undef MAP_FAILED
00063 #endif
00064 #endif
00065
00066 #ifndef MAP_FAILED
00067 #define MAP_FAILED (void *) -1
00068 #endif
00069
00070 #ifndef MAP_FILE
00071 #define MAP_FILE 0
00072 #endif
00073
00074 #ifndef MAXPATHLEN
00075 #define MAXPATHLEN 1024
00076 #endif
00077
00078 struct magic_entry {
00079 struct magic *mp;
00080 uint32_t cont_count;
00081 uint32_t max_count;
00082 };
00083
00084
00085 int file_formats[FILE_NAMES_SIZE];
00086
00087 const size_t file_nformats = FILE_NAMES_SIZE;
00088
00089 const char *file_names[FILE_NAMES_SIZE];
00090
00091 const size_t file_nnames = FILE_NAMES_SIZE;
00092
00093
00094 private size_t maxmagic = 0;
00095
00096 private size_t magicsize = sizeof(struct magic);
00097
00098 private int getvalue(struct magic_set *ms, struct magic *m, const char **p,
00099 int action)
00100
00101 ;
00102 private int hextoint(int c)
00103 ;
00104
00105 private const char * getstr(struct magic_set *ms, const char *s, char *p,
00106 int plen, int *slen, int action)
00107
00108 ;
00109 private int parse(struct magic_set *ms, struct magic_entry **mentryp,
00110 uint32_t *nmentryp, const char *line, size_t lineno, int action)
00111
00112 ;
00113 private void eatsize(const char **p)
00114 ;
00115 private int apprentice_1(struct magic_set *ms, const char *fn, int action,
00116 struct mlist *mlist)
00117
00118 ;
00119 private size_t apprentice_magic_strength(const struct magic *m)
00120
00121 ;
00122 private int apprentice_sort(const void *a, const void *b)
00123
00124 ;
00125 private int apprentice_file(struct magic_set *ms, struct magic **magicp,
00126 uint32_t *nmagicp, const char *fn, int action)
00127
00128 ;
00129 private void byteswap(struct magic *magic, uint32_t nmagic)
00130 ;
00131 private void bs1(struct magic *m)
00132 ;
00133 private uint16_t swap2(uint16_t sv)
00134 ;
00135 private uint32_t swap4(uint32_t sv)
00136 ;
00137 private uint64_t swap8(uint64_t sv)
00138 ;
00139 private char * mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
00140 ;
00141 private int apprentice_map(struct magic_set *ms, struct magic **magicp,
00142 uint32_t *nmagicp, const char *fn)
00143
00144 ;
00145 private int apprentice_compile(struct magic_set *ms, struct magic **magicp,
00146 uint32_t *nmagicp, const char *fn)
00147
00148 ;
00149 private int check_format_type(const char *ptr, int type)
00150 ;
00151 private int check_format(struct magic_set *ms, struct magic *m)
00152 ;
00153
00154 #ifdef COMPILE_ONLY
00155
00156 int main(int, char *[]);
00157
00158 int
00159 main(int argc, char *argv[])
00160 {
00161 int ret;
00162 struct magic_set *ms;
00163 char *progname;
00164
00165 if ((progname = strrchr(argv[0], '/')) != NULL)
00166 progname++;
00167 else
00168 progname = argv[0];
00169
00170 if (argc != 2) {
00171 (void)fprintf(stderr, "Usage: %s file\n", progname);
00172 return 1;
00173 }
00174
00175 if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
00176 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
00177 return 1;
00178 }
00179 ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
00180 if (ret == 1)
00181 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
00182 magic_close(ms);
00183 return ret;
00184 }
00185 #endif
00186
00187
00188 static const struct type_tbl_s {
00189
00190 const char *name;
00191 const size_t len;
00192 const int type;
00193 const int format;
00194 } type_tbl[] = {
00195 # define XX(s) s, (sizeof(s) - 1)
00196 # define XX_NULL NULL, 0
00197 { XX("byte"), FILE_BYTE, FILE_FMT_NUM },
00198 { XX("short"), FILE_SHORT, FILE_FMT_NUM },
00199 { XX("default"), FILE_DEFAULT, FILE_FMT_STR },
00200 { XX("long"), FILE_LONG, FILE_FMT_NUM },
00201 { XX("string"), FILE_STRING, FILE_FMT_STR },
00202 { XX("date"), FILE_DATE, FILE_FMT_STR },
00203 { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM },
00204 { XX("belong"), FILE_BELONG, FILE_FMT_NUM },
00205 { XX("bedate"), FILE_BEDATE, FILE_FMT_STR },
00206 { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM },
00207 { XX("lelong"), FILE_LELONG, FILE_FMT_NUM },
00208 { XX("ledate"), FILE_LEDATE, FILE_FMT_STR },
00209 { XX("pstring"), FILE_PSTRING, FILE_FMT_STR },
00210 { XX("ldate"), FILE_LDATE, FILE_FMT_STR },
00211 { XX("beldate"), FILE_BELDATE, FILE_FMT_STR },
00212 { XX("leldate"), FILE_LELDATE, FILE_FMT_STR },
00213 { XX("regex"), FILE_REGEX, FILE_FMT_STR },
00214 { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR },
00215 { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR },
00216 { XX("search"), FILE_SEARCH, FILE_FMT_STR },
00217 { XX("medate"), FILE_MEDATE, FILE_FMT_STR },
00218 { XX("meldate"), FILE_MELDATE, FILE_FMT_STR },
00219 { XX("melong"), FILE_MELONG, FILE_FMT_NUM },
00220 { XX("quad"), FILE_QUAD, FILE_FMT_QUAD },
00221 { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD },
00222 { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD },
00223 { XX("qdate"), FILE_QDATE, FILE_FMT_STR },
00224 { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR },
00225 { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR },
00226 { XX("qldate"), FILE_QLDATE, FILE_FMT_STR },
00227 { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR },
00228 { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR },
00229 { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
00230 # undef XX
00231 # undef XX_NULL
00232 };
00233
00234 private int
00235 get_type(const char *l, const char **t)
00236
00237 {
00238 const struct type_tbl_s *p;
00239
00240 for (p = type_tbl; p->name; p++) {
00241 if (strncmp(l, p->name, p->len) == 0) {
00242 if (t)
00243 *t = l + p->len;
00244 break;
00245 }
00246 }
00247 return p->type;
00248 }
00249
00250 private void
00251 init_file_tables(void)
00252
00253
00254 {
00255 static int done = 0;
00256 const struct type_tbl_s *p;
00257
00258 if (done)
00259 return;
00260 done++;
00261
00262
00263 for (p = type_tbl; p->name; p++) {
00264 assert(p->type < FILE_NAMES_SIZE);
00265 file_names[p->type] = p->name;
00266 file_formats[p->type] = p->format;
00267 }
00268
00269 }
00270
00271
00272
00273
00274 private int
00275 apprentice_1(struct magic_set *ms, const char *fn, int action,
00276 struct mlist *mlist)
00277 {
00278 struct magic *magic = NULL;
00279 uint32_t nmagic = 0;
00280 struct mlist *ml;
00281 int rv = -1;
00282 int mapped;
00283
00284 if (magicsize != FILE_MAGICSIZE) {
00285 file_error(ms, 0, "magic element size %lu != %lu",
00286 (unsigned long)sizeof(*magic),
00287 (unsigned long)FILE_MAGICSIZE);
00288 return -1;
00289 }
00290
00291 if (action == FILE_COMPILE) {
00292 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
00293 if (rv != 0)
00294 return -1;
00295 rv = apprentice_compile(ms, &magic, &nmagic, fn);
00296 free(magic);
00297 return rv;
00298 }
00299 #ifndef COMPILE_ONLY
00300 if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
00301 if (ms->flags & MAGIC_CHECK)
00302 file_magwarn(ms, "using regular magic file `%s'", fn);
00303 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
00304 if (rv != 0)
00305 return -1;
00306 mapped = 0;
00307 }
00308
00309 mapped = rv;
00310
00311 if (magic == NULL || nmagic == 0) {
00312 file_delmagic(magic, mapped, nmagic);
00313 return -1;
00314 }
00315
00316 if ((ml = malloc(sizeof(*ml))) == NULL) {
00317 file_delmagic(magic, mapped, nmagic);
00318 file_oomem(ms, sizeof(*ml));
00319 return -1;
00320 }
00321
00322 ml->magic = magic;
00323 ml->nmagic = nmagic;
00324 ml->mapped = mapped;
00325
00326 mlist->prev->next = ml;
00327 ml->prev = mlist->prev;
00328 ml->next = mlist;
00329 mlist->prev = ml;
00330
00331 return 0;
00332 #endif
00333 }
00334
00335 protected void
00336 file_delmagic(struct magic *p, int type, size_t entries)
00337 {
00338 if (p == NULL)
00339 return;
00340 switch (type) {
00341 case 2:
00342 p--;
00343 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
00344 break;
00345 case 1:
00346 p--;
00347
00348 case 0:
00349 free(p);
00350 break;
00351 default:
00352 abort();
00353 }
00354 }
00355
00356
00357
00358 protected struct mlist *
00359 file_apprentice(struct magic_set *ms, const char *fn, int action)
00360 {
00361 char *p, *mfn, *afn = NULL;
00362 int file_err, errs = -1;
00363 struct mlist *mlist;
00364 static const char mime[] = ".mime";
00365
00366 init_file_tables();
00367
00368 if (fn == NULL)
00369 fn = getenv("MAGIC");
00370 if (fn == NULL)
00371 fn = MAGIC;
00372
00373 if ((fn = mfn = strdup(fn)) == NULL) {
00374 file_oomem(ms, strlen(fn));
00375 return NULL;
00376 }
00377
00378 if ((mlist = malloc(sizeof(*mlist))) == NULL) {
00379 free(mfn);
00380 file_oomem(ms, sizeof(*mlist));
00381 return NULL;
00382 }
00383 mlist->next = mlist->prev = mlist;
00384
00385 while (fn) {
00386 p = strchr(fn, PATHSEP);
00387 if (p)
00388 *p++ = '\0';
00389 if (*fn == '\0')
00390 break;
00391 if (ms->flags & MAGIC_MIME) {
00392 size_t len = strlen(fn) + sizeof(mime);
00393 if ((afn = malloc(len)) == NULL) {
00394 free(mfn);
00395 free(mlist);
00396 file_oomem(ms, len);
00397 return NULL;
00398 }
00399 (void)strcpy(afn, fn);
00400 (void)strcat(afn, mime);
00401 fn = afn;
00402 }
00403 file_err = apprentice_1(ms, fn, action, mlist);
00404 if (file_err > errs)
00405 errs = file_err;
00406 if (afn) {
00407 free(afn);
00408 afn = NULL;
00409 }
00410 fn = p;
00411 }
00412 if (errs == -1) {
00413 free(mfn);
00414 free(mlist);
00415 mlist = NULL;
00416 file_error(ms, 0, "could not find any magic files!");
00417 return NULL;
00418 }
00419 free(mfn);
00420 return mlist;
00421 }
00422
00423
00424
00425
00426 private size_t
00427 apprentice_magic_strength(const struct magic *m)
00428 {
00429 #define MULT 10
00430 size_t val = 2 * MULT;
00431
00432 switch (m->type) {
00433 case FILE_DEFAULT:
00434 return 0;
00435
00436 case FILE_BYTE:
00437 val += 1 * MULT;
00438 break;
00439
00440 case FILE_SHORT:
00441 case FILE_LESHORT:
00442 case FILE_BESHORT:
00443 val += 2 * MULT;
00444 break;
00445
00446 case FILE_LONG:
00447 case FILE_LELONG:
00448 case FILE_BELONG:
00449 case FILE_MELONG:
00450 val += 4 * MULT;
00451 break;
00452
00453 case FILE_PSTRING:
00454 case FILE_STRING:
00455 val += m->vallen * MULT;
00456 break;
00457
00458 case FILE_BESTRING16:
00459 case FILE_LESTRING16:
00460 val += m->vallen * MULT / 2;
00461 break;
00462
00463 case FILE_SEARCH:
00464 case FILE_REGEX:
00465 val += m->vallen;
00466 break;
00467
00468 case FILE_DATE:
00469 case FILE_LEDATE:
00470 case FILE_BEDATE:
00471 case FILE_MEDATE:
00472 case FILE_LDATE:
00473 case FILE_LELDATE:
00474 case FILE_BELDATE:
00475 case FILE_MELDATE:
00476 val += 4 * MULT;
00477 break;
00478
00479 case FILE_QUAD:
00480 case FILE_BEQUAD:
00481 case FILE_LEQUAD:
00482 case FILE_QDATE:
00483 case FILE_LEQDATE:
00484 case FILE_BEQDATE:
00485 case FILE_QLDATE:
00486 case FILE_LEQLDATE:
00487 case FILE_BEQLDATE:
00488 val += 8 * MULT;
00489 break;
00490
00491 default:
00492 val = 0;
00493 (void)fprintf(stderr, "Bad type %d\n", m->type);
00494 abort();
00495 }
00496
00497 switch (m->reln) {
00498 case 'x':
00499 val = 0;
00500 break;
00501
00502 case '!':
00503 case '=':
00504 val += MULT;
00505 break;
00506
00507 case '>':
00508 case '<':
00509 val -= 2 * MULT;
00510 break;
00511
00512 case '^':
00513 case '&':
00514 val -= MULT;
00515 break;
00516
00517 default:
00518 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
00519 abort();
00520 }
00521
00522 if (val == 0)
00523 val = 1;
00524
00525 return val;
00526 }
00527
00528
00529
00530
00531 private int
00532 apprentice_sort(const void *a, const void *b)
00533 {
00534 const struct magic_entry *ma = a;
00535 const struct magic_entry *mb = b;
00536 size_t sa = apprentice_magic_strength(ma->mp);
00537 size_t sb = apprentice_magic_strength(mb->mp);
00538 if (sa == sb)
00539 return 0;
00540 else if (sa > sb)
00541 return -1;
00542 else
00543 return 1;
00544 }
00545
00546
00547
00548
00549
00550 private int
00551 apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
00552 const char *fn, int action)
00553 {
00554 private const char hdr[] =
00555 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
00556 FILE *f;
00557 char line[BUFSIZ+1];
00558 int errs = 0;
00559 struct magic_entry *marray;
00560 uint32_t marraycount, i, mentrycount = 0;
00561 size_t lineno = 0;
00562
00563 ms->flags |= MAGIC_CHECK;
00564
00565 f = fopen(ms->file = fn, "r");
00566 if (f == NULL) {
00567 if (errno != ENOENT)
00568 file_error(ms, errno, "cannot read magic file `%s'",
00569 fn);
00570 return -1;
00571 }
00572
00573 maxmagic = MAXMAGIS;
00574 if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
00575 (void)fclose(f);
00576 file_oomem(ms, maxmagic * sizeof(*marray));
00577 return -1;
00578 }
00579 marraycount = 0;
00580
00581
00582 if (action == FILE_CHECK)
00583 (void)fprintf(stderr, "%s\n", hdr);
00584
00585
00586 for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) {
00587 size_t len;
00588 len = strlen(line);
00589 if (len == 0)
00590 continue;
00591 if (line[len - 1] == '\n') {
00592 lineno++;
00593 line[len - 1] = '\0';
00594 }
00595 if (line[0] == '\0')
00596 continue;
00597 if (line[0] == '#')
00598 continue;
00599 if (parse(ms, &marray, &marraycount, line, lineno, action) != 0)
00600 errs++;
00601 }
00602
00603 (void)fclose(f);
00604 if (errs)
00605 goto out;
00606
00607 #ifndef NOORDER
00608 qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
00609
00610
00611
00612 for (i = 0; i < marraycount; i++) {
00613 if (marray[i].mp->cont_level == 0 &&
00614 marray[i].mp->type == FILE_DEFAULT) {
00615 while (++i < marraycount)
00616 if (marray[i].mp->cont_level == 0)
00617 break;
00618 if (i != marraycount) {
00619 ms->line = marray[i].mp->lineno;
00620 file_magwarn(ms,
00621 "level 0 \"default\" did not sort last");
00622 }
00623 break;
00624 }
00625 }
00626 #endif
00627
00628 for (i = 0; i < marraycount; i++)
00629 mentrycount += marray[i].cont_count;
00630
00631 if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
00632 file_oomem(ms, sizeof(**magicp) * mentrycount);
00633 errs++;
00634 goto out;
00635 }
00636
00637 mentrycount = 0;
00638 for (i = 0; i < marraycount; i++) {
00639 (void)memcpy(*magicp + mentrycount, marray[i].mp,
00640 marray[i].cont_count * sizeof(**magicp));
00641 mentrycount += marray[i].cont_count;
00642 }
00643 out:
00644 for (i = 0; i < marraycount; i++)
00645 free(marray[i].mp);
00646 free(marray);
00647 if (errs) {
00648 *magicp = NULL;
00649 *nmagicp = 0;
00650 return errs;
00651 } else {
00652 *nmagicp = mentrycount;
00653 return 0;
00654 }
00655
00656 }
00657
00658
00659
00660
00661 protected uint64_t
00662 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
00663 {
00664 if (!(m->flag & UNSIGNED)) {
00665 switch(m->type) {
00666
00667
00668
00669
00670
00671 case FILE_BYTE:
00672 v = (char) v;
00673 break;
00674 case FILE_SHORT:
00675 case FILE_BESHORT:
00676 case FILE_LESHORT:
00677 v = (short) v;
00678 break;
00679 case FILE_DATE:
00680 case FILE_BEDATE:
00681 case FILE_LEDATE:
00682 case FILE_MEDATE:
00683 case FILE_LDATE:
00684 case FILE_BELDATE:
00685 case FILE_LELDATE:
00686 case FILE_MELDATE:
00687 case FILE_LONG:
00688 case FILE_BELONG:
00689 case FILE_LELONG:
00690 case FILE_MELONG:
00691 v = (int32_t) v;
00692 break;
00693 case FILE_QUAD:
00694 case FILE_BEQUAD:
00695 case FILE_LEQUAD:
00696 case FILE_QDATE:
00697 case FILE_QLDATE:
00698 case FILE_BEQDATE:
00699 case FILE_BEQLDATE:
00700 case FILE_LEQDATE:
00701 case FILE_LEQLDATE:
00702 v = (int64_t) v;
00703 break;
00704 case FILE_STRING:
00705 case FILE_PSTRING:
00706 case FILE_BESTRING16:
00707 case FILE_LESTRING16:
00708 case FILE_REGEX:
00709 case FILE_SEARCH:
00710 case FILE_DEFAULT:
00711 break;
00712 default:
00713 if (ms->flags & MAGIC_CHECK)
00714 file_magwarn(ms, "cannot happen: m->type=%d\n",
00715 m->type);
00716 return ~0U;
00717 }
00718 }
00719 return v;
00720 }
00721
00722 private int
00723 string_modifier_check(struct magic_set *ms, struct magic const *m)
00724
00725
00726 {
00727 if ((ms->flags & MAGIC_CHECK) == 0)
00728 return 0;
00729
00730 switch (m->type) {
00731 case FILE_BESTRING16:
00732 case FILE_LESTRING16:
00733 if (m->str_flags != 0) {
00734 file_magwarn(ms, "no modifiers allowed for 16-bit strings\n");
00735 return -1;
00736 }
00737 break;
00738 case FILE_STRING:
00739 case FILE_PSTRING:
00740 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
00741 file_magwarn(ms, "'/%c' only allowed on regex and search\n",
00742 CHAR_REGEX_OFFSET_START);
00743 return -1;
00744 }
00745 break;
00746 case FILE_SEARCH:
00747 break;
00748 case FILE_REGEX:
00749 if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
00750 file_magwarn(ms, "'/%c' not allowed on regex\n",
00751 CHAR_COMPACT_BLANK);
00752 return -1;
00753 }
00754 if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
00755 file_magwarn(ms, "'/%c' not allowed on regex\n",
00756 CHAR_COMPACT_OPTIONAL_BLANK);
00757 return -1;
00758 }
00759 break;
00760 default:
00761 file_magwarn(ms, "coding error: m->type=%d\n",
00762 m->type);
00763 return -1;
00764 }
00765 return 0;
00766 }
00767
00768 private int
00769 get_op(char c)
00770
00771 {
00772 switch (c) {
00773 case '&':
00774 return FILE_OPAND;
00775 case '|':
00776 return FILE_OPOR;
00777 case '^':
00778 return FILE_OPXOR;
00779 case '+':
00780 return FILE_OPADD;
00781 case '-':
00782 return FILE_OPMINUS;
00783 case '*':
00784 return FILE_OPMULTIPLY;
00785 case '/':
00786 return FILE_OPDIVIDE;
00787 case '%':
00788 return FILE_OPMODULO;
00789 default:
00790 return -1;
00791 }
00792 }
00793
00794 #ifdef ENABLE_CONDITIONALS
00795 private int
00796 get_cond(const char *l, const char **t)
00797
00798 {
00799
00800 static struct cond_tbl_s {
00801
00802 const char *name;
00803 const size_t len;
00804 const int cond;
00805 } cond_tbl[] = {
00806 { "if", 2, COND_IF },
00807 { "elif", 4, COND_ELIF },
00808 { "else", 4, COND_ELSE },
00809 { NULL, 0, COND_NONE },
00810 };
00811 struct cond_tbl_s *p;
00812
00813 for (p = cond_tbl; p->name; p++) {
00814 if (strncmp(l, p->name, p->len) == 0 &&
00815 isspace((unsigned char)l[p->len])) {
00816 if (t)
00817 *t = l + p->len;
00818 break;
00819 }
00820 }
00821 return p->cond;
00822 }
00823
00824 private int
00825 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
00826
00827
00828 {
00829 int last_cond;
00830 last_cond = ms->c.li[cont_level].last_cond;
00831
00832 switch (cond) {
00833 case COND_IF:
00834 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
00835 if (ms->flags & MAGIC_CHECK)
00836 file_magwarn(ms, "syntax error: `if'");
00837 return -1;
00838 }
00839 last_cond = COND_IF;
00840 break;
00841
00842 case COND_ELIF:
00843 if (last_cond != COND_IF && last_cond != COND_ELIF) {
00844 if (ms->flags & MAGIC_CHECK)
00845 file_magwarn(ms, "syntax error: `elif'");
00846 return -1;
00847 }
00848 last_cond = COND_ELIF;
00849 break;
00850
00851 case COND_ELSE:
00852 if (last_cond != COND_IF && last_cond != COND_ELIF) {
00853 if (ms->flags & MAGIC_CHECK)
00854 file_magwarn(ms, "syntax error: `else'");
00855 return -1;
00856 }
00857 last_cond = COND_NONE;
00858 break;
00859
00860 case COND_NONE:
00861 last_cond = COND_NONE;
00862 break;
00863 }
00864
00865 ms->c.li[cont_level].last_cond = last_cond;
00866 return 0;
00867 }
00868 #endif
00869
00870
00871
00872
00873 private int
00874 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
00875 const char *line, size_t lineno, int action)
00876 {
00877 #ifdef ENABLE_CONDITIONALS
00878 static uint32_t last_cont_level = 0;
00879 #endif
00880 size_t i;
00881 struct magic_entry *me;
00882 struct magic *m;
00883 const char *l = line;
00884 char *t;
00885 int op;
00886 uint32_t cont_level;
00887
00888 cont_level = 0;
00889
00890 while (*l == '>') {
00891 ++l;
00892 cont_level++;
00893 }
00894 #ifdef ENABLE_CONDITIONALS
00895 if (cont_level == 0 || cont_level > last_cont_level)
00896 if (file_check_mem(ms, cont_level) == -1)
00897 return -1;
00898 last_cont_level = cont_level;
00899 #endif
00900
00901 #define ALLOC_CHUNK (size_t)10
00902 #define ALLOC_INCR (size_t)200
00903
00904 if (cont_level != 0) {
00905 if (*nmentryp == 0) {
00906 file_error(ms, 0, "No current entry for continuation");
00907 return -1;
00908 }
00909 me = &(*mentryp)[*nmentryp - 1];
00910 if (me->cont_count == me->max_count) {
00911 struct magic *nm;
00912 size_t cnt = me->max_count + ALLOC_CHUNK;
00913 if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
00914 file_oomem(ms, sizeof(*nm) * cnt);
00915 return -1;
00916 }
00917 me->mp = m = nm;
00918 me->max_count = cnt;
00919 }
00920 m = &me->mp[me->cont_count++];
00921 (void)memset(m, 0, sizeof(*m));
00922 m->cont_level = cont_level;
00923 } else {
00924 if (*nmentryp == maxmagic) {
00925 struct magic_entry *mp;
00926
00927 maxmagic += ALLOC_INCR;
00928 if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
00929 NULL) {
00930 file_oomem(ms, sizeof(*mp) * maxmagic);
00931 return -1;
00932 }
00933 (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
00934 ALLOC_INCR);
00935 *mentryp = mp;
00936 }
00937 me = &(*mentryp)[*nmentryp];
00938 if (me->mp == NULL) {
00939 if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
00940 file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
00941 return -1;
00942 }
00943 me->mp = m;
00944 me->max_count = ALLOC_CHUNK;
00945 } else
00946 m = me->mp;
00947 (void)memset(m, 0, sizeof(*m));
00948 m->cont_level = 0;
00949 me->cont_count = 1;
00950 }
00951 m->lineno = lineno;
00952
00953 if (*l == '&') {
00954 ++l;
00955 m->flag |= OFFADD;
00956 }
00957 if (*l == '(') {
00958 ++l;
00959 m->flag |= INDIR;
00960 if (m->flag & OFFADD)
00961 m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
00962
00963 if (*l == '&') {
00964 ++l;
00965 m->flag |= OFFADD;
00966 }
00967 }
00968
00969 if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
00970 if (ms->flags & MAGIC_CHECK)
00971 file_magwarn(ms, "relative offset at level 0");
00972
00973
00974 m->offset = (uint32_t)strtoul(l, &t, 0);
00975 if (l == t)
00976 if (ms->flags & MAGIC_CHECK)
00977 file_magwarn(ms, "offset `%s' invalid", l);
00978 l = t;
00979
00980 if (m->flag & INDIR) {
00981 m->in_type = FILE_LONG;
00982 m->in_offset = 0;
00983
00984
00985
00986 if (*l == '.') {
00987 l++;
00988 switch (*l) {
00989 case 'l':
00990 m->in_type = FILE_LELONG;
00991 break;
00992 case 'L':
00993 m->in_type = FILE_BELONG;
00994 break;
00995 case 'm':
00996 m->in_type = FILE_MELONG;
00997 break;
00998 case 'h':
00999 case 's':
01000 m->in_type = FILE_LESHORT;
01001 break;
01002 case 'H':
01003 case 'S':
01004 m->in_type = FILE_BESHORT;
01005 break;
01006 case 'c':
01007 case 'b':
01008 case 'C':
01009 case 'B':
01010 m->in_type = FILE_BYTE;
01011 break;
01012 default:
01013 if (ms->flags & MAGIC_CHECK)
01014 file_magwarn(ms,
01015 "indirect offset type `%c' invalid",
01016 *l);
01017 break;
01018 }
01019 l++;
01020 }
01021
01022 m->in_op = 0;
01023 if (*l == '~') {
01024 m->in_op |= FILE_OPINVERSE;
01025 l++;
01026 }
01027 if ((op = get_op(*l)) != -1) {
01028 m->in_op |= op;
01029 l++;
01030 }
01031 if (*l == '(') {
01032 m->in_op |= FILE_OPINDIRECT;
01033 l++;
01034 }
01035 if (isdigit((unsigned char)*l) || *l == '-') {
01036 m->in_offset = (int32_t)strtol(l, &t, 0);
01037 if (l == t)
01038 if (ms->flags & MAGIC_CHECK)
01039 file_magwarn(ms,
01040 "in_offset `%s' invalid", l);
01041 l = t;
01042 }
01043 if (*l++ != ')' ||
01044 ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
01045 if (ms->flags & MAGIC_CHECK)
01046 file_magwarn(ms,
01047 "missing ')' in indirect offset");
01048 }
01049 EATAB;
01050
01051 #ifdef ENABLE_CONDITIONALS
01052 m->cond = get_cond(l, &l);
01053 if (check_cond(ms, m->cond, cont_level) == -1)
01054 return -1;
01055
01056 EATAB;
01057 #endif
01058
01059 if (*l == 'u') {
01060 ++l;
01061 m->flag |= UNSIGNED;
01062 }
01063
01064 m->type = get_type(l, &l);
01065 if (m->type == FILE_INVALID) {
01066 if (ms->flags & MAGIC_CHECK)
01067 file_magwarn(ms, "type `%s' invalid", l);
01068 return -1;
01069 }
01070
01071
01072
01073
01074 m->mask_op = 0;
01075 if (*l == '~') {
01076 if (!IS_STRING(m->type))
01077 m->mask_op |= FILE_OPINVERSE;
01078 else if (ms->flags & MAGIC_CHECK)
01079 file_magwarn(ms, "'~' invalid for string types");
01080 ++l;
01081 }
01082 m->str_count = 0;
01083 m->str_flags = 0;
01084 m->num_mask = 0;
01085 if ((op = get_op(*l)) != -1) {
01086 if (!IS_STRING(m->type)) {
01087 uint64_t val;
01088 ++l;
01089 m->mask_op |= op;
01090 val = (uint64_t)strtoull(l, &t, 0);
01091 l = t;
01092 m->num_mask = file_signextend(ms, m, val);
01093 eatsize(&l);
01094 }
01095 else if (op == FILE_OPDIVIDE) {
01096 int have_count = 0;
01097 while (!isspace((unsigned char)*++l)) {
01098 switch (*l) {
01099
01100 case '0': case '1': case '2':
01101 case '3': case '4': case '5':
01102 case '6': case '7': case '8':
01103 case '9': {
01104 if (have_count && ms->flags & MAGIC_CHECK)
01105 file_magwarn(ms,
01106 "multiple counts");
01107 have_count = 1;
01108 m->str_count = strtoul(l, &t, 0);
01109 l = t - 1;
01110 break;
01111 }
01112 case CHAR_COMPACT_BLANK:
01113 m->str_flags |= STRING_COMPACT_BLANK;
01114 break;
01115 case CHAR_COMPACT_OPTIONAL_BLANK:
01116 m->str_flags |=
01117 STRING_COMPACT_OPTIONAL_BLANK;
01118 break;
01119 case CHAR_IGNORE_LOWERCASE:
01120 m->str_flags |= STRING_IGNORE_LOWERCASE;
01121 break;
01122 case CHAR_IGNORE_UPPERCASE:
01123 m->str_flags |= STRING_IGNORE_UPPERCASE;
01124 break;
01125 case CHAR_REGEX_OFFSET_START:
01126 m->str_flags |= REGEX_OFFSET_START;
01127 break;
01128 default:
01129 if (ms->flags & MAGIC_CHECK)
01130 file_magwarn(ms,
01131 "string extension `%c' invalid",
01132 *l);
01133 return -1;
01134 }
01135
01136 if (l[1] == '/' && !isspace((unsigned char)l[2]))
01137 l++;
01138 }
01139 if (string_modifier_check(ms, m) == -1)
01140 return -1;
01141 }
01142 else {
01143 if (ms->flags & MAGIC_CHECK)
01144 file_magwarn(ms, "invalid string op: %c", *t);
01145 return -1;
01146 }
01147 }
01148
01149
01150
01151
01152 EATAB;
01153
01154 switch (*l) {
01155 case '>':
01156 case '<':
01157
01158 case '&':
01159 case '^':
01160 case '=':
01161 m->reln = *l;
01162 ++l;
01163 if (*l == '=') {
01164
01165 ++l;
01166 }
01167 break;
01168 case '!':
01169 m->reln = *l;
01170 ++l;
01171 break;
01172 default:
01173 m->reln = '=';
01174 if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
01175 isspace((unsigned char)l[1])) || !l[1])) {
01176 m->reln = *l;
01177 ++l;
01178 }
01179 break;
01180 }
01181
01182
01183
01184 if (m->reln != 'x' && getvalue(ms, m, &l, action))
01185 return -1;
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196 EATAB;
01197 if (l[0] == '\b') {
01198 ++l;
01199 m->nospflag = 1;
01200 } else if ((l[0] == '\\') && (l[1] == 'b')) {
01201 ++l;
01202 ++l;
01203 m->nospflag = 1;
01204 } else
01205 m->nospflag = 0;
01206 for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
01207 continue;
01208 if (i == sizeof(m->desc)) {
01209 m->desc[sizeof(m->desc) - 1] = '\0';
01210 if (ms->flags & MAGIC_CHECK)
01211 file_magwarn(ms, "description `%s' truncated", m->desc);
01212 }
01213
01214
01215
01216
01217
01218 if (ms->flags & MAGIC_CHECK) {
01219 if (check_format(ms, m) == -1)
01220 return -1;
01221 }
01222 #ifndef COMPILE_ONLY
01223 if (action == FILE_CHECK) {
01224 file_mdump(m);
01225 }
01226 #endif
01227 if (m->cont_level == 0)
01228 ++(*nmentryp);
01229 return 0;
01230 }
01231
01232 private int
01233 check_format_type(const char *ptr, int type)
01234 {
01235 int quad = 0;
01236 if (*ptr == '\0') {
01237
01238 return -1;
01239 }
01240
01241 switch (type) {
01242 case FILE_FMT_QUAD:
01243 quad = 1;
01244
01245 case FILE_FMT_NUM:
01246 if (*ptr == '-')
01247 ptr++;
01248 if (*ptr == '.')
01249 ptr++;
01250 while (isdigit((unsigned char)*ptr)) ptr++;
01251 if (*ptr == '.')
01252 ptr++;
01253 while (isdigit((unsigned char)*ptr)) ptr++;
01254 if (quad) {
01255 if (*ptr++ != 'l')
01256 return -1;
01257 if (*ptr++ != 'l')
01258 return -1;
01259 }
01260
01261 switch (*ptr++) {
01262 case 'l':
01263 switch (*ptr++) {
01264 case 'i':
01265 case 'd':
01266 case 'u':
01267 case 'x':
01268 case 'X':
01269 return 0;
01270 default:
01271 return -1;
01272 }
01273
01274 case 'h':
01275 switch (*ptr++) {
01276 case 'h':
01277 switch (*ptr++) {
01278 case 'i':
01279 case 'd':
01280 case 'u':
01281 case 'x':
01282 case 'X':
01283 return 0;
01284 default:
01285 return -1;
01286 }
01287 case 'd':
01288 return 0;
01289 default:
01290 return -1;
01291 }
01292
01293 case 'i':
01294 case 'c':
01295 case 'd':
01296 case 'u':
01297 case 'x':
01298 case 'X':
01299 return 0;
01300
01301 default:
01302 return -1;
01303 }
01304
01305 case FILE_FMT_STR:
01306 if (*ptr == '-')
01307 ptr++;
01308 while (isdigit((unsigned char )*ptr))
01309 ptr++;
01310 if (*ptr == '.') {
01311 ptr++;
01312 while (isdigit((unsigned char )*ptr))
01313 ptr++;
01314 }
01315
01316 switch (*ptr++) {
01317 case 's':
01318 return 0;
01319 default:
01320 return -1;
01321 }
01322
01323 default:
01324
01325 abort();
01326 }
01327
01328 return -1;
01329 }
01330
01331
01332
01333
01334
01335 private int
01336 check_format(struct magic_set *ms, struct magic *m)
01337 {
01338 char *ptr;
01339
01340 for (ptr = m->desc; *ptr; ptr++)
01341 if (*ptr == '%')
01342 break;
01343 if (*ptr == '\0') {
01344
01345 return 1;
01346 }
01347
01348 assert(file_nformats == file_nnames);
01349
01350 if (m->type >= file_nformats) {
01351 file_error(ms, 0, "Internal error inconsistency between "
01352 "m->type and format strings");
01353 return -1;
01354 }
01355 if (file_formats[m->type] == FILE_FMT_NONE) {
01356 file_error(ms, 0, "No format string for `%s' with description "
01357 "`%s'", m->desc, file_names[m->type]);
01358 return -1;
01359 }
01360
01361 ptr++;
01362 if (check_format_type(ptr, file_formats[m->type]) == -1) {
01363
01364
01365
01366
01367 file_error(ms, 0, "Printf format `%c' is not valid for type "
01368 " `%s' in description `%s'", *ptr,
01369 file_names[m->type], m->desc);
01370 return -1;
01371 }
01372
01373 for (; *ptr; ptr++) {
01374 if (*ptr == '%') {
01375 file_error(ms, 0,
01376 "Too many format strings (should have at most one) "
01377 "for `%s' with description `%s'",
01378 file_names[m->type], m->desc);
01379 return -1;
01380 }
01381 }
01382 return 0;
01383 }
01384
01385
01386
01387
01388
01389
01390 private int
01391 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
01392 {
01393 int slen;
01394
01395 switch (m->type) {
01396 case FILE_BESTRING16:
01397 case FILE_LESTRING16:
01398 case FILE_STRING:
01399 case FILE_PSTRING:
01400 case FILE_REGEX:
01401 case FILE_SEARCH:
01402 *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
01403 if (*p == NULL) {
01404 if (ms->flags & MAGIC_CHECK)
01405 file_magwarn(ms, "cannot get string from `%s'",
01406 m->value.s);
01407 return -1;
01408 }
01409 m->vallen = slen;
01410 return 0;
01411 default:
01412 if (m->reln != 'x') {
01413 char *ep;
01414 m->value.q = file_signextend(ms, m,
01415 (uint64_t)strtoull(*p, &ep, 0));
01416 *p = ep;
01417 eatsize(p);
01418 }
01419 return 0;
01420 }
01421 }
01422
01423
01424
01425
01426
01427
01428
01429 private const char *
01430 getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
01431 {
01432 const char *origs = s;
01433 char *origp = p;
01434 char *pmax = p + plen - 1;
01435 int c;
01436 int val;
01437
01438 while ((c = *s++) != '\0') {
01439 if (isspace((unsigned char) c))
01440 break;
01441 if (p >= pmax) {
01442 file_error(ms, 0, "string too long: `%s'", origs);
01443 return NULL;
01444 }
01445 if(c == '\\') {
01446 switch(c = *s++) {
01447
01448 case '\0':
01449 if (action == FILE_COMPILE)
01450 file_magwarn(ms, "incomplete escape");
01451 goto out;
01452
01453 case '\t':
01454 if (action == FILE_COMPILE) {
01455 file_magwarn(ms,
01456 "escaped tab found, use \\t instead");
01457 action++;
01458 }
01459
01460 default:
01461 if (action == FILE_COMPILE) {
01462 if (isprint((unsigned char)c))
01463 file_magwarn(ms,
01464 "no need to escape `%c'", c);
01465 else
01466 file_magwarn(ms,
01467 "unknown escape sequence: \\%03o", c);
01468 }
01469
01470
01471 case ' ':
01472 #if 0
01473
01474
01475
01476
01477 case '\'':
01478 case '"':
01479 case '?':
01480 #endif
01481
01482 case '>':
01483 case '<':
01484 case '&':
01485 case '^':
01486 case '=':
01487 case '!':
01488
01489 case '\\':
01490 *p++ = (char) c;
01491 break;
01492
01493 case 'a':
01494 *p++ = '\a';
01495 break;
01496
01497 case 'b':
01498 *p++ = '\b';
01499 break;
01500
01501 case 'f':
01502 *p++ = '\f';
01503 break;
01504
01505 case 'n':
01506 *p++ = '\n';
01507 break;
01508
01509 case 'r':
01510 *p++ = '\r';
01511 break;
01512
01513 case 't':
01514 *p++ = '\t';
01515 break;
01516
01517 case 'v':
01518 *p++ = '\v';
01519 break;
01520
01521
01522 case '0':
01523 case '1':
01524 case '2':
01525 case '3':
01526 case '4':
01527 case '5':
01528 case '6':
01529 case '7':
01530 val = c - '0';
01531 c = *s++;
01532 if(c >= '0' && c <= '7') {
01533 val = (val<<3) | (c - '0');
01534 c = *s++;
01535 if(c >= '0' && c <= '7')
01536 val = (val<<3) | (c-'0');
01537 else
01538 --s;
01539 }
01540 else
01541 --s;
01542 *p++ = (char)val;
01543 break;
01544
01545
01546 case 'x':
01547 val = 'x';
01548 c = hextoint(*s++);
01549 if (c >= 0) {
01550 val = c;
01551 c = hextoint(*s++);
01552 if (c >= 0)
01553 val = (val << 4) + c;
01554 else
01555 --s;
01556 } else
01557 --s;
01558 *p++ = (char)val;
01559 break;
01560 }
01561 } else
01562 *p++ = (char)c;
01563 }
01564 out:
01565 *p = '\0';
01566 *slen = p - origp;
01567 return s;
01568 }
01569
01570
01571
01572 private int
01573 hextoint(int c)
01574 {
01575 if (!isascii((unsigned char) c))
01576 return -1;
01577 if (isdigit((unsigned char) c))
01578 return c - '0';
01579 if ((c >= 'a')&&(c <= 'f'))
01580 return c + 10 - 'a';
01581 if (( c>= 'A')&&(c <= 'F'))
01582 return c + 10 - 'A';
01583 return -1;
01584 }
01585
01586
01587
01588
01589
01590 protected void
01591 file_showstr(FILE *fp, const char *s, size_t len)
01592 {
01593 char c;
01594
01595 for (;;) {
01596 c = *s++;
01597 if (len == ~0U) {
01598 if (c == '\0')
01599 break;
01600 }
01601 else {
01602 if (len-- == 0)
01603 break;
01604 }
01605 if(c >= 040 && c <= 0176)
01606 (void) fputc(c, fp);
01607 else {
01608 (void) fputc('\\', fp);
01609 switch (c) {
01610 case '\a':
01611 (void) fputc('a', fp);
01612 break;
01613
01614 case '\b':
01615 (void) fputc('b', fp);
01616 break;
01617
01618 case '\f':
01619 (void) fputc('f', fp);
01620 break;
01621
01622 case '\n':
01623 (void) fputc('n', fp);
01624 break;
01625
01626 case '\r':
01627 (void) fputc('r', fp);
01628 break;
01629
01630 case '\t':
01631 (void) fputc('t', fp);
01632 break;
01633
01634 case '\v':
01635 (void) fputc('v', fp);
01636 break;
01637
01638 default:
01639 (void) fprintf(fp, "%.3o", c & 0377);
01640 break;
01641 }
01642 }
01643 }
01644 }
01645
01646
01647
01648
01649 private void
01650 eatsize(const char **p)
01651 {
01652 const char *l = *p;
01653
01654 if (LOWCASE(*l) == 'u')
01655 l++;
01656
01657 switch (LOWCASE(*l)) {
01658 case 'l':
01659 case 's':
01660 case 'h':
01661 case 'b':
01662 case 'c':
01663 l++;
01664
01665 default:
01666 break;
01667 }
01668
01669 *p = l;
01670 }
01671
01672
01673
01674
01675 private int
01676 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
01677 const char *fn)
01678 {
01679 int fd;
01680 struct stat st;
01681 uint32_t *ptr;
01682 uint32_t version;
01683 int needsbyteswap;
01684 char buf[MAXPATHLEN];
01685 char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
01686 void *mm = NULL;
01687
01688 if (dbname == NULL)
01689 return -1;
01690
01691 if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
01692 return -1;
01693
01694 if (fstat(fd, &st) == -1) {
01695 file_error(ms, errno, "cannot stat `%s'", dbname);
01696 goto error;
01697 }
01698 if (st.st_size < 16) {
01699 file_error(ms, 0, "file `%s' is too small", dbname);
01700 goto error;
01701 }
01702
01703 #ifdef QUICK
01704 if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
01705 MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
01706 file_error(ms, errno, "cannot map `%s'", dbname);
01707 goto error;
01708 }
01709 #define RET 2
01710 #else
01711 if ((mm = malloc((size_t)st.st_size)) == NULL) {
01712 file_oomem(ms, (size_t)st.st_size);
01713 goto error;
01714 }
01715 if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
01716 file_badread(ms);
01717 goto error;
01718 }
01719 #define RET 1
01720 #endif
01721 *magicp = mm;
01722 (void)close(fd);
01723 fd = -1;
01724 ptr = (uint32_t *)(void *)*magicp;
01725 if (*ptr != MAGICNO) {
01726 if (swap4(*ptr) != MAGICNO) {
01727 file_error(ms, 0, "bad magic in `%s'");
01728 goto error;
01729 }
01730 needsbyteswap = 1;
01731 } else
01732 needsbyteswap = 0;
01733 if (needsbyteswap)
01734 version = swap4(ptr[1]);
01735 else
01736 version = ptr[1];
01737 if (version != VERSIONNO) {
01738 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
01739 version, VERSIONNO, dbname);
01740 goto error;
01741 }
01742 *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
01743 (*magicp)++;
01744 if (needsbyteswap)
01745 byteswap(*magicp, *nmagicp);
01746 return RET;
01747
01748 error:
01749 if (fd != -1)
01750 (void)close(fd);
01751 if (mm) {
01752 #ifdef QUICK
01753 (void)munmap((void *)mm, (size_t)st.st_size);
01754 #else
01755 free(mm);
01756 #endif
01757 } else {
01758 *magicp = NULL;
01759 *nmagicp = 0;
01760 }
01761 return -1;
01762 }
01763
01764
01765 private const uint32_t ar[] = {
01766 MAGICNO, VERSIONNO
01767 };
01768
01769
01770
01771 private int
01772 apprentice_compile(struct magic_set *ms, struct magic **magicp,
01773 uint32_t *nmagicp, const char *fn)
01774 {
01775 int fd;
01776 char buf[MAXPATHLEN];
01777 char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
01778
01779 if (dbname == NULL)
01780 return -1;
01781
01782 if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
01783 file_error(ms, errno, "cannot open `%s'", dbname);
01784 return -1;
01785 }
01786
01787 if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
01788 file_error(ms, errno, "error writing `%s'", dbname);
01789 return -1;
01790 }
01791
01792 if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
01793 != sizeof(struct magic)) {
01794 file_error(ms, errno, "error seeking `%s'", dbname);
01795 return -1;
01796 }
01797
01798 if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
01799 != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
01800 file_error(ms, errno, "error writing `%s'", dbname);
01801 return -1;
01802 }
01803
01804 (void)close(fd);
01805 return 0;
01806 }
01807
01808
01809 private const char ext[] = ".mgc";
01810
01811
01812
01813 private char *
01814 mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
01815 {
01816 if (strip) {
01817 const char *p;
01818 if ((p = strrchr(fn, '/')) != NULL)
01819 fn = ++p;
01820 }
01821
01822 (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
01823 return buf;
01824 }
01825
01826
01827
01828
01829 private void
01830 byteswap(struct magic *magic, uint32_t nmagic)
01831 {
01832 uint32_t i;
01833 for (i = 0; i < nmagic; i++)
01834 bs1(&magic[i]);
01835 }
01836
01837
01838
01839
01840 private uint16_t
01841 swap2(uint16_t sv)
01842 {
01843 uint16_t rv;
01844 uint8_t *s = (uint8_t *)(void *)&sv;
01845 uint8_t *d = (uint8_t *)(void *)&rv;
01846 d[0] = s[1];
01847 d[1] = s[0];
01848 return rv;
01849 }
01850
01851
01852
01853
01854 private uint32_t
01855 swap4(uint32_t sv)
01856 {
01857 uint32_t rv;
01858 uint8_t *s = (uint8_t *)(void *)&sv;
01859 uint8_t *d = (uint8_t *)(void *)&rv;
01860 d[0] = s[3];
01861 d[1] = s[2];
01862 d[2] = s[1];
01863 d[3] = s[0];
01864 return rv;
01865 }
01866
01867
01868
01869
01870 private uint64_t
01871 swap8(uint64_t sv)
01872 {
01873 uint32_t rv;
01874 uint8_t *s = (uint8_t *)(void *)&sv;
01875 uint8_t *d = (uint8_t *)(void *)&rv;
01876 d[0] = s[3];
01877 d[1] = s[2];
01878 d[2] = s[1];
01879 d[3] = s[0];
01880 d[4] = s[7];
01881 d[5] = s[6];
01882 d[6] = s[5];
01883 d[7] = s[4];
01884 return rv;
01885 }
01886
01887
01888
01889
01890 private void
01891 bs1(struct magic *m)
01892 {
01893 m->cont_level = swap2(m->cont_level);
01894 m->offset = swap4((uint32_t)m->offset);
01895 m->in_offset = swap4((uint32_t)m->in_offset);
01896 m->lineno = swap4((uint32_t)m->lineno);
01897 if (IS_STRING(m->type)) {
01898 m->str_count = swap4(m->str_count);
01899 m->str_flags = swap4(m->str_flags);
01900 }
01901 else {
01902 m->value.q = swap8(m->value.q);
01903 m->num_mask = swap8(m->num_mask);
01904 }
01905 }