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