Annotation of embedaddon/php/ext/fileinfo/libmagic/apprentice.c, revision 1.1.1.1
1.1 misho 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 "php.h"
33:
34: #include "file.h"
35:
36: #ifndef lint
37: FILE_RCSID("@(#)$File: apprentice.c,v 1.151 2009/03/18 15:19:23 christos Exp $")
38: #endif /* lint */
39:
40: #include "magic.h"
41: #include "patchlevel.h"
42: #include <stdlib.h>
43:
44: #if defined(__hpux) && !defined(HAVE_STRTOULL)
45: #if SIZEOF_LONG == 8
46: # define strtoull strtoul
47: #else
48: # define strtoull __strtoull
49: #endif
50: #endif
51:
52: #ifdef PHP_WIN32
53: #include "win32/unistd.h"
54: #if _MSC_VER <= 1300
55: # include "win32/php_strtoi64.h"
56: #endif
57: #define strtoull _strtoui64
58: #else
59: #include <unistd.h>
60: #endif
61:
62: #include <string.h>
63: #include <assert.h>
64: #include <ctype.h>
65: #include <fcntl.h>
66: #ifndef PHP_WIN32
67: #include <dirent.h>
68: #endif
69:
70: #define EATAB {while (isascii((unsigned char) *l) && \
71: isspace((unsigned char) *l)) ++l;}
72: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
73: tolower((unsigned char) (l)) : (l))
74: /*
75: * Work around a bug in headers on Digital Unix.
76: * At least confirmed for: OSF1 V4.0 878
77: */
78: #if defined(__osf__) && defined(__DECC)
79: #ifdef MAP_FAILED
80: #undef MAP_FAILED
81: #endif
82: #endif
83:
84: #ifndef MAP_FAILED
85: #define MAP_FAILED (void *) -1
86: #endif
87:
88: #ifndef MAP_FILE
89: #define MAP_FILE 0
90: #endif
91:
92: #ifndef MAXPATHLEN
93: #define MAXPATHLEN 1024
94: #endif
95:
96: struct magic_entry {
97: struct magic *mp;
98: uint32_t cont_count;
99: uint32_t max_count;
100: };
101:
102: int file_formats[FILE_NAMES_SIZE];
103: const size_t file_nformats = FILE_NAMES_SIZE;
104: const char *file_names[FILE_NAMES_SIZE];
105: const size_t file_nnames = FILE_NAMES_SIZE;
106:
107: private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
108: private int hextoint(int);
109: private const char *getstr(struct magic_set *, struct magic *, const char *,
110: int);
111: private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
112: const char *, size_t, int);
113: private void eatsize(const char **);
114: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
115: private size_t apprentice_magic_strength(const struct magic *);
116: private int apprentice_sort(const void *, const void *);
117: private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
118: const char *, int);
119: private void byteswap(struct magic *, uint32_t);
120: private void bs1(struct magic *);
121: private uint16_t swap2(uint16_t);
122: private uint32_t swap4(uint32_t);
123: private uint64_t swap8(uint64_t);
124: private char *mkdbname(struct magic_set *, const char *, int);
125: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
126: const char *);
127: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
128: const char *);
129: private int check_format_type(const char *, int);
130: private int check_format(struct magic_set *, struct magic *);
131: private int get_op(char);
132: private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
133: private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
134: private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
135:
136: private size_t maxmagic = 0;
137: private size_t magicsize = sizeof(struct magic);
138:
139: private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
140: private struct {
141: const char *name;
142: size_t len;
143: int (*fun)(struct magic_set *, struct magic_entry *, const char *);
144: } bang[] = {
145: #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
146: DECLARE_FIELD(mime),
147: DECLARE_FIELD(apple),
148: DECLARE_FIELD(strength),
149: #undef DECLARE_FIELD
150: { NULL, 0, NULL }
151: };
152:
153: #include "../data_file.c"
154:
155: static const struct type_tbl_s {
156: const char name[16];
157: const size_t len;
158: const int type;
159: const int format;
160: } type_tbl[] = {
161: # define XX(s) s, (sizeof(s) - 1)
162: # define XX_NULL "", 0
163: { XX("byte"), FILE_BYTE, FILE_FMT_NUM },
164: { XX("short"), FILE_SHORT, FILE_FMT_NUM },
165: { XX("default"), FILE_DEFAULT, FILE_FMT_STR },
166: { XX("long"), FILE_LONG, FILE_FMT_NUM },
167: { XX("string"), FILE_STRING, FILE_FMT_STR },
168: { XX("date"), FILE_DATE, FILE_FMT_STR },
169: { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM },
170: { XX("belong"), FILE_BELONG, FILE_FMT_NUM },
171: { XX("bedate"), FILE_BEDATE, FILE_FMT_STR },
172: { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM },
173: { XX("lelong"), FILE_LELONG, FILE_FMT_NUM },
174: { XX("ledate"), FILE_LEDATE, FILE_FMT_STR },
175: { XX("pstring"), FILE_PSTRING, FILE_FMT_STR },
176: { XX("ldate"), FILE_LDATE, FILE_FMT_STR },
177: { XX("beldate"), FILE_BELDATE, FILE_FMT_STR },
178: { XX("leldate"), FILE_LELDATE, FILE_FMT_STR },
179: { XX("regex"), FILE_REGEX, FILE_FMT_STR },
180: { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR },
181: { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR },
182: { XX("search"), FILE_SEARCH, FILE_FMT_STR },
183: { XX("medate"), FILE_MEDATE, FILE_FMT_STR },
184: { XX("meldate"), FILE_MELDATE, FILE_FMT_STR },
185: { XX("melong"), FILE_MELONG, FILE_FMT_NUM },
186: { XX("quad"), FILE_QUAD, FILE_FMT_QUAD },
187: { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD },
188: { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD },
189: { XX("qdate"), FILE_QDATE, FILE_FMT_STR },
190: { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR },
191: { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR },
192: { XX("qldate"), FILE_QLDATE, FILE_FMT_STR },
193: { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR },
194: { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR },
195: { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT },
196: { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT },
197: { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT },
198: { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE },
199: { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE },
200: { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE },
201: { XX("leid3"), FILE_LEID3, FILE_FMT_NUM },
202: { XX("beid3"), FILE_BEID3, FILE_FMT_NUM },
203: { XX("indirect"), FILE_INDIRECT, FILE_FMT_NONE },
204: { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
205: # undef XX
206: # undef XX_NULL
207: };
208:
209: #ifndef S_ISDIR
210: #define S_ISDIR(mode) ((mode) & _S_IFDIR)
211: #endif
212:
213: private int
214: get_type(const char *l, const char **t)
215: {
216: const struct type_tbl_s *p;
217:
218: for (p = type_tbl; p->len; p++) {
219: if (strncmp(l, p->name, p->len) == 0) {
220: if (t)
221: *t = l + p->len;
222: break;
223: }
224: }
225: return p->type;
226: }
227:
228: private void
229: init_file_tables(void)
230: {
231: static int done = 0;
232: const struct type_tbl_s *p;
233:
234: if (done)
235: return;
236: done++;
237:
238: for (p = type_tbl; p->len; p++) {
239: assert(p->type < FILE_NAMES_SIZE);
240: file_names[p->type] = p->name;
241: file_formats[p->type] = p->format;
242: }
243: }
244:
245: /*
246: * Handle one file or directory.
247: */
248: private int
249: apprentice_1(struct magic_set *ms, const char *fn, int action,
250: struct mlist *mlist)
251: {
252: struct magic *magic = NULL;
253: uint32_t nmagic = 0;
254: struct mlist *ml;
255: int rv = -1;
256: int mapped;
257:
258: if (magicsize != FILE_MAGICSIZE) {
259: file_error(ms, 0, "magic element size %lu != %lu",
260: (unsigned long)sizeof(*magic),
261: (unsigned long)FILE_MAGICSIZE);
262: return -1;
263: }
264:
265: if (action == FILE_COMPILE) {
266: rv = apprentice_load(ms, &magic, &nmagic, fn, action);
267: if (rv != 0)
268: return -1;
269: rv = apprentice_compile(ms, &magic, &nmagic, fn);
270: efree(magic);
271: return rv;
272: }
273:
274: if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
275: if (fn) {
276: if (ms->flags & MAGIC_CHECK)
277: file_magwarn(ms, "using regular magic file `%s'", fn);
278: rv = apprentice_load(ms, &magic, &nmagic, fn, action);
279: }
280:
281: if (rv != 0)
282: return -1;
283: }
284:
285: mapped = rv;
286:
287: if (magic == NULL) {
288: file_delmagic(magic, mapped, nmagic);
289: return -1;
290: }
291:
292: ml = emalloc(sizeof(*ml));
293:
294: ml->magic = magic;
295: ml->nmagic = nmagic;
296: ml->mapped = mapped;
297:
298: mlist->prev->next = ml;
299: ml->prev = mlist->prev;
300: ml->next = mlist;
301: mlist->prev = ml;
302:
303: return 0;
304: }
305:
306: protected void
307: file_delmagic(struct magic *p, int type, size_t entries)
308: {
309: if (p == NULL)
310: return;
311: switch (type) {
312: case 3:
313: /* Do nothing, it's part of the code segment */
314: break;
315:
316: case 1:
317: p--;
318: /*FALLTHROUGH*/
319:
320: case 0:
321: efree(p);
322: break;
323:
324: default:
325: abort();
326: }
327: }
328:
329: /* const char *fn: list of magic files and directories */
330: protected struct mlist *
331: file_apprentice(struct magic_set *ms, const char *fn, int action)
332: {
333: char *p, *mfn;
334: int file_err, errs = -1;
335: struct mlist *mlist;
336:
337: init_file_tables();
338:
339: if (fn == NULL)
340: fn = getenv("MAGIC");
341: if (fn == NULL) {
342: mlist = emalloc(sizeof(*mlist));
343: mlist->next = mlist->prev = mlist;
344: apprentice_1(ms, fn, action, mlist);
345: return mlist;
346: }
347:
348: mfn = estrdup(fn);
349: fn = mfn;
350:
351: mlist = emalloc(sizeof(*mlist));
352: mlist->next = mlist->prev = mlist;
353:
354: while (fn) {
355: p = strchr(fn, PATHSEP);
356: if (p)
357: *p++ = '\0';
358: if (*fn == '\0')
359: break;
360: file_err = apprentice_1(ms, fn, action, mlist);
361: errs = MAX(errs, file_err);
362: fn = p;
363: }
364: if (errs == -1) {
365: efree(mfn);
366: efree(mlist);
367: mlist = NULL;
368: file_error(ms, 0, "could not find any magic files!");
369: return NULL;
370: }
371: efree(mfn);
372: return mlist;
373: }
374:
375: /*
376: * Get weight of this magic entry, for sorting purposes.
377: */
378: private size_t
379: apprentice_magic_strength(const struct magic *m)
380: {
381: #define MULT 10
382: size_t val = 2 * MULT; /* baseline strength */
383:
384: switch (m->type) {
385: case FILE_DEFAULT: /* make sure this sorts last */
386: if (m->factor_op != FILE_FACTOR_OP_NONE)
387: abort();
388: return 0;
389:
390: case FILE_BYTE:
391: val += 1 * MULT;
392: break;
393:
394: case FILE_SHORT:
395: case FILE_LESHORT:
396: case FILE_BESHORT:
397: val += 2 * MULT;
398: break;
399:
400: case FILE_LONG:
401: case FILE_LELONG:
402: case FILE_BELONG:
403: case FILE_MELONG:
404: val += 4 * MULT;
405: break;
406:
407: case FILE_PSTRING:
408: case FILE_STRING:
409: val += m->vallen * MULT;
410: break;
411:
412: case FILE_BESTRING16:
413: case FILE_LESTRING16:
414: val += m->vallen * MULT / 2;
415: break;
416:
417: case FILE_SEARCH:
418: case FILE_REGEX:
419: val += m->vallen * MAX(MULT / m->vallen, 1);
420: break;
421:
422: case FILE_DATE:
423: case FILE_LEDATE:
424: case FILE_BEDATE:
425: case FILE_MEDATE:
426: case FILE_LDATE:
427: case FILE_LELDATE:
428: case FILE_BELDATE:
429: case FILE_MELDATE:
430: case FILE_FLOAT:
431: case FILE_BEFLOAT:
432: case FILE_LEFLOAT:
433: val += 4 * MULT;
434: break;
435:
436: case FILE_QUAD:
437: case FILE_BEQUAD:
438: case FILE_LEQUAD:
439: case FILE_QDATE:
440: case FILE_LEQDATE:
441: case FILE_BEQDATE:
442: case FILE_QLDATE:
443: case FILE_LEQLDATE:
444: case FILE_BEQLDATE:
445: case FILE_DOUBLE:
446: case FILE_BEDOUBLE:
447: case FILE_LEDOUBLE:
448: val += 8 * MULT;
449: break;
450:
451: default:
452: val = 0;
453: (void)fprintf(stderr, "Bad type %d\n", m->type);
454: abort();
455: }
456:
457: switch (m->reln) {
458: case 'x': /* matches anything penalize */
459: case '!': /* matches almost anything penalize */
460: val = 0;
461: break;
462:
463: case '=': /* Exact match, prefer */
464: val += MULT;
465: break;
466:
467: case '>':
468: case '<': /* comparison match reduce strength */
469: val -= 2 * MULT;
470: break;
471:
472: case '^':
473: case '&': /* masking bits, we could count them too */
474: val -= MULT;
475: break;
476:
477: default:
478: (void)fprintf(stderr, "Bad relation %c\n", m->reln);
479: abort();
480: }
481:
482: if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */
483: val = 1;
484:
485: switch (m->factor_op) {
486: case FILE_FACTOR_OP_NONE:
487: break;
488: case FILE_FACTOR_OP_PLUS:
489: val += m->factor;
490: break;
491: case FILE_FACTOR_OP_MINUS:
492: val -= m->factor;
493: break;
494: case FILE_FACTOR_OP_TIMES:
495: val *= m->factor;
496: break;
497: case FILE_FACTOR_OP_DIV:
498: val /= m->factor;
499: break;
500: default:
501: abort();
502: }
503:
504:
505: /*
506: * Magic entries with no description get a bonus because they depend
507: * on subsequent magic entries to print something.
508: */
509: if (m->desc[0] == '\0')
510: val++;
511: return val;
512: }
513:
514: /*
515: * Sort callback for sorting entries by "strength" (basically length)
516: */
517: private int
518: apprentice_sort(const void *a, const void *b)
519: {
520: const struct magic_entry *ma = a;
521: const struct magic_entry *mb = b;
522: size_t sa = apprentice_magic_strength(ma->mp);
523: size_t sb = apprentice_magic_strength(mb->mp);
524: if (sa == sb)
525: return 0;
526: else if (sa > sb)
527: return -1;
528: else
529: return 1;
530: }
531:
532: private void
533: set_test_type(struct magic *mstart, struct magic *m)
534: {
535: switch (m->type) {
536: case FILE_BYTE:
537: case FILE_SHORT:
538: case FILE_LONG:
539: case FILE_DATE:
540: case FILE_BESHORT:
541: case FILE_BELONG:
542: case FILE_BEDATE:
543: case FILE_LESHORT:
544: case FILE_LELONG:
545: case FILE_LEDATE:
546: case FILE_LDATE:
547: case FILE_BELDATE:
548: case FILE_LELDATE:
549: case FILE_MEDATE:
550: case FILE_MELDATE:
551: case FILE_MELONG:
552: case FILE_QUAD:
553: case FILE_LEQUAD:
554: case FILE_BEQUAD:
555: case FILE_QDATE:
556: case FILE_LEQDATE:
557: case FILE_BEQDATE:
558: case FILE_QLDATE:
559: case FILE_LEQLDATE:
560: case FILE_BEQLDATE:
561: case FILE_FLOAT:
562: case FILE_BEFLOAT:
563: case FILE_LEFLOAT:
564: case FILE_DOUBLE:
565: case FILE_BEDOUBLE:
566: case FILE_LEDOUBLE:
567: case FILE_STRING:
568: case FILE_PSTRING:
569: case FILE_BESTRING16:
570: case FILE_LESTRING16:
571: /* binary test, set flag */
572: mstart->flag |= BINTEST;
573: break;
574: case FILE_REGEX:
575: case FILE_SEARCH:
576: /* binary test if pattern is not text */
577: if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
578: NULL) <= 0)
579: mstart->flag |= BINTEST;
580: break;
581: case FILE_DEFAULT:
582: /* can't deduce anything; we shouldn't see this at the
583: top level anyway */
584: break;
585: case FILE_INVALID:
586: default:
587: /* invalid search type, but no need to complain here */
588: break;
589: }
590: }
591:
592: /*
593: * Load and parse one file.
594: */
595: private void
596: load_1(struct magic_set *ms, int action, const char *fn, int *errs,
597: struct magic_entry **marray, uint32_t *marraycount)
598: {
599: char buffer[BUFSIZ + 1];
600: char *line;
601: size_t line_len;
602: size_t lineno = 0;
603:
604: php_stream *stream;
605:
606: TSRMLS_FETCH();
607:
608: #if PHP_API_VERSION < 20100412
609: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
610: #else
611: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL);
612: #endif
613:
614: if (stream == NULL) {
615: if (errno != ENOENT)
616: file_error(ms, errno, "cannot read magic file `%s'",
617: fn);
618: (*errs)++;
619: } else {
620:
621: /* read and parse this file */
622: #if (PHP_MAJOR_VERSION < 6)
623: for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &line_len)) != NULL; ms->line++) {
624: #else
625: for (ms->line = 1; (line = php_stream_get_line(stream, ZSTR(buffer), BUFSIZ, &line_len)) != NULL; ms->line++) {
626: #endif
627: if (line_len == 0) /* null line, garbage, etc */
628: continue;
629:
630: if (line[line_len - 1] == '\n') {
631: lineno++;
632: line[line_len - 1] = '\0'; /* delete newline */
633: }
634: if (line[0] == '\0') /* empty, do not parse */
635: continue;
636: if (line[0] == '#') /* comment, do not parse */
637: continue;
638:
639: if (line[0] == '!' && line[1] == ':') {
640: size_t i;
641:
642: for (i = 0; bang[i].name != NULL; i++) {
643: if (line_len - 2 > bang[i].len &&
644: memcmp(bang[i].name, line + 2,
645: bang[i].len) == 0)
646: break;
647: }
648: if (bang[i].name == NULL) {
649: file_error(ms, 0,
650: "Unknown !: entry `%s'", line);
651: (*errs)++;
652: continue;
653: }
654: if (*marraycount == 0) {
655: file_error(ms, 0,
656: "No current entry for :!%s type",
657: bang[i].name);
658: (*errs)++;
659: continue;
660: }
661: if ((*bang[i].fun)(ms,
662: &(*marray)[*marraycount - 1],
663: line + bang[i].len + 2) != 0) {
664: (*errs)++;
665: continue;
666: }
667: continue;
668: }
669: if (parse(ms, marray, marraycount, line, lineno, action) != 0)
670: (*errs)++;
671: }
672:
673: php_stream_close(stream);
674: }
675: }
676:
677: /*
678: * parse a file or directory of files
679: * const char *fn: name of magic file or directory
680: */
681: private int
682: apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
683: const char *fn, int action)
684: {
685: int errs = 0;
686: struct magic_entry *marray;
687: uint32_t marraycount, i, mentrycount = 0, starttest;
688: char subfn[MAXPATHLEN];
689: struct stat st;
690: DIR *dir;
691: struct dirent *d;
692:
693: ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */
694:
695: maxmagic = MAXMAGIS;
696: marray = ecalloc(maxmagic, sizeof(*marray));
697: marraycount = 0;
698:
699: /* print silly verbose header for USG compat. */
700: if (action == FILE_CHECK)
701: (void)fprintf(stderr, "%s\n", usg_hdr);
702:
703: /* load directory or file */
704: /* FIXME: Read file names and sort them to prevent
705: non-determinism. See Debian bug #488562. */
706: if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
707: dir = opendir(fn);
708: if (dir) {
709: while ((d = readdir(dir)) != NULL) {
710: snprintf(subfn, sizeof(subfn), "%s/%s",
711: fn, d->d_name);
712: if (stat(subfn, &st) == 0 &&
713: S_ISREG(st.st_mode)) {
714: load_1(ms, action, subfn, &errs,
715: &marray, &marraycount);
716: }
717: }
718: closedir(dir);
719: } else
720: errs++;
721: } else
722: load_1(ms, action, fn, &errs, &marray, &marraycount);
723: if (errs)
724: goto out;
725:
726: /* Set types of tests */
727: for (i = 0; i < marraycount; ) {
728: if (marray[i].mp->cont_level != 0) {
729: i++;
730: continue;
731: }
732:
733: starttest = i;
734: do {
735: static const char text[] = "text";
736: static const char binary[] = "binary";
737: static const size_t len = sizeof(text);
738: set_test_type(marray[starttest].mp, marray[i].mp);
739: if ((ms->flags & MAGIC_DEBUG) == 0)
740: continue;
741: (void)fprintf(stderr, "%s%s%s: %s\n",
742: marray[i].mp->mimetype,
743: marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
744: marray[i].mp->desc[0] ? marray[i].mp->desc :
745: "(no description)",
746: marray[i].mp->flag & BINTEST ? binary : text);
747: if (marray[i].mp->flag & BINTEST) {
748: char *p = strstr(marray[i].mp->desc, text);
749: if (p && (p == marray[i].mp->desc ||
750: isspace((unsigned char)p[-1])) &&
751: (p + len - marray[i].mp->desc ==
752: MAXstring || (p[len] == '\0' ||
753: isspace((unsigned char)p[len]))))
754: (void)fprintf(stderr, "*** Possible "
755: "binary test for text type\n");
756: }
757: } while (++i < marraycount && marray[i].mp->cont_level != 0);
758: }
759:
760: qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
761:
762: /*
763: * Make sure that any level 0 "default" line is last (if one exists).
764: */
765: for (i = 0; i < marraycount; i++) {
766: if (marray[i].mp->cont_level == 0 &&
767: marray[i].mp->type == FILE_DEFAULT) {
768: while (++i < marraycount)
769: if (marray[i].mp->cont_level == 0)
770: break;
771: if (i != marraycount) {
772: ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
773: file_magwarn(ms,
774: "level 0 \"default\" did not sort last");
775: }
776: break;
777: }
778: }
779:
780: for (i = 0; i < marraycount; i++)
781: mentrycount += marray[i].cont_count;
782:
783: *magicp = emalloc(sizeof(**magicp) * mentrycount);
784:
785: mentrycount = 0;
786: for (i = 0; i < marraycount; i++) {
787: (void)memcpy(*magicp + mentrycount, marray[i].mp,
788: marray[i].cont_count * sizeof(**magicp));
789: mentrycount += marray[i].cont_count;
790: }
791: out:
792: for (i = 0; i < marraycount; i++)
793: efree(marray[i].mp);
794: efree(marray);
795: if (errs) {
796: *magicp = NULL;
797: *nmagicp = 0;
798: return errs;
799: } else {
800: *nmagicp = mentrycount;
801: return 0;
802: }
803:
804: }
805:
806: /*
807: * extend the sign bit if the comparison is to be signed
808: */
809: protected uint64_t
810: file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
811: {
812: if (!(m->flag & UNSIGNED)) {
813: switch(m->type) {
814: /*
815: * Do not remove the casts below. They are
816: * vital. When later compared with the data,
817: * the sign extension must have happened.
818: */
819: case FILE_BYTE:
820: v = (char) v;
821: break;
822: case FILE_SHORT:
823: case FILE_BESHORT:
824: case FILE_LESHORT:
825: v = (short) v;
826: break;
827: case FILE_DATE:
828: case FILE_BEDATE:
829: case FILE_LEDATE:
830: case FILE_MEDATE:
831: case FILE_LDATE:
832: case FILE_BELDATE:
833: case FILE_LELDATE:
834: case FILE_MELDATE:
835: case FILE_LONG:
836: case FILE_BELONG:
837: case FILE_LELONG:
838: case FILE_MELONG:
839: case FILE_FLOAT:
840: case FILE_BEFLOAT:
841: case FILE_LEFLOAT:
842: v = (int32_t) v;
843: break;
844: case FILE_QUAD:
845: case FILE_BEQUAD:
846: case FILE_LEQUAD:
847: case FILE_QDATE:
848: case FILE_QLDATE:
849: case FILE_BEQDATE:
850: case FILE_BEQLDATE:
851: case FILE_LEQDATE:
852: case FILE_LEQLDATE:
853: case FILE_DOUBLE:
854: case FILE_BEDOUBLE:
855: case FILE_LEDOUBLE:
856: v = (int64_t) v;
857: break;
858: case FILE_STRING:
859: case FILE_PSTRING:
860: case FILE_BESTRING16:
861: case FILE_LESTRING16:
862: case FILE_REGEX:
863: case FILE_SEARCH:
864: case FILE_DEFAULT:
865: case FILE_INDIRECT:
866: break;
867: default:
868: if (ms->flags & MAGIC_CHECK)
869: file_magwarn(ms, "cannot happen: m->type=%d\n",
870: m->type);
871: return ~0U;
872: }
873: }
874: return v;
875: }
876:
877: private int
878: string_modifier_check(struct magic_set *ms, struct magic *m)
879: {
880: if ((ms->flags & MAGIC_CHECK) == 0)
881: return 0;
882:
883: switch (m->type) {
884: case FILE_BESTRING16:
885: case FILE_LESTRING16:
886: if (m->str_flags != 0) {
887: file_magwarn(ms,
888: "no modifiers allowed for 16-bit strings\n");
889: return -1;
890: }
891: break;
892: case FILE_STRING:
893: case FILE_PSTRING:
894: if ((m->str_flags & REGEX_OFFSET_START) != 0) {
895: file_magwarn(ms,
896: "'/%c' only allowed on regex and search\n",
897: CHAR_REGEX_OFFSET_START);
898: return -1;
899: }
900: break;
901: case FILE_SEARCH:
902: if (m->str_range == 0) {
903: file_magwarn(ms,
904: "missing range; defaulting to %d\n",
905: STRING_DEFAULT_RANGE);
906: m->str_range = STRING_DEFAULT_RANGE;
907: return -1;
908: }
909: break;
910: case FILE_REGEX:
911: if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
912: file_magwarn(ms, "'/%c' not allowed on regex\n",
913: CHAR_COMPACT_BLANK);
914: return -1;
915: }
916: if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
917: file_magwarn(ms, "'/%c' not allowed on regex\n",
918: CHAR_COMPACT_OPTIONAL_BLANK);
919: return -1;
920: }
921: break;
922: default:
923: file_magwarn(ms, "coding error: m->type=%d\n",
924: m->type);
925: return -1;
926: }
927: return 0;
928: }
929:
930: private int
931: get_op(char c)
932: {
933: switch (c) {
934: case '&':
935: return FILE_OPAND;
936: case '|':
937: return FILE_OPOR;
938: case '^':
939: return FILE_OPXOR;
940: case '+':
941: return FILE_OPADD;
942: case '-':
943: return FILE_OPMINUS;
944: case '*':
945: return FILE_OPMULTIPLY;
946: case '/':
947: return FILE_OPDIVIDE;
948: case '%':
949: return FILE_OPMODULO;
950: default:
951: return -1;
952: }
953: }
954:
955: #ifdef ENABLE_CONDITIONALS
956: private int
957: get_cond(const char *l, const char **t)
958: {
959: static const struct cond_tbl_s {
960: char name[8];
961: size_t len;
962: int cond;
963: } cond_tbl[] = {
964: { "if", 2, COND_IF },
965: { "elif", 4, COND_ELIF },
966: { "else", 4, COND_ELSE },
967: { "", 0, COND_NONE },
968: };
969: const struct cond_tbl_s *p;
970:
971: for (p = cond_tbl; p->len; p++) {
972: if (strncmp(l, p->name, p->len) == 0 &&
973: isspace((unsigned char)l[p->len])) {
974: if (t)
975: *t = l + p->len;
976: break;
977: }
978: }
979: return p->cond;
980: }
981:
982: private int
983: check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
984: {
985: int last_cond;
986: last_cond = ms->c.li[cont_level].last_cond;
987:
988: switch (cond) {
989: case COND_IF:
990: if (last_cond != COND_NONE && last_cond != COND_ELIF) {
991: if (ms->flags & MAGIC_CHECK)
992: file_magwarn(ms, "syntax error: `if'");
993: return -1;
994: }
995: last_cond = COND_IF;
996: break;
997:
998: case COND_ELIF:
999: if (last_cond != COND_IF && last_cond != COND_ELIF) {
1000: if (ms->flags & MAGIC_CHECK)
1001: file_magwarn(ms, "syntax error: `elif'");
1002: return -1;
1003: }
1004: last_cond = COND_ELIF;
1005: break;
1006:
1007: case COND_ELSE:
1008: if (last_cond != COND_IF && last_cond != COND_ELIF) {
1009: if (ms->flags & MAGIC_CHECK)
1010: file_magwarn(ms, "syntax error: `else'");
1011: return -1;
1012: }
1013: last_cond = COND_NONE;
1014: break;
1015:
1016: case COND_NONE:
1017: last_cond = COND_NONE;
1018: break;
1019: }
1020:
1021: ms->c.li[cont_level].last_cond = last_cond;
1022: return 0;
1023: }
1024: #endif /* ENABLE_CONDITIONALS */
1025:
1026: /*
1027: * parse one line from magic file, put into magic[index++] if valid
1028: */
1029: private int
1030: parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
1031: const char *line, size_t lineno, int action)
1032: {
1033: #ifdef ENABLE_CONDITIONALS
1034: static uint32_t last_cont_level = 0;
1035: #endif
1036: size_t i;
1037: struct magic_entry *me;
1038: struct magic *m;
1039: const char *l = line;
1040: char *t;
1041: int op;
1042: uint32_t cont_level;
1043:
1044: cont_level = 0;
1045:
1046: while (*l == '>') {
1047: ++l; /* step over */
1048: cont_level++;
1049: }
1050: #ifdef ENABLE_CONDITIONALS
1051: if (cont_level == 0 || cont_level > last_cont_level)
1052: if (file_check_mem(ms, cont_level) == -1)
1053: return -1;
1054: last_cont_level = cont_level;
1055: #endif
1056:
1057: #define ALLOC_CHUNK (size_t)10
1058: #define ALLOC_INCR (size_t)200
1059:
1060: if (cont_level != 0) {
1061: if (*nmentryp == 0) {
1062: file_error(ms, 0, "No current entry for continuation");
1063: return -1;
1064: }
1065: me = &(*mentryp)[*nmentryp - 1];
1066: if (me->cont_count == me->max_count) {
1067: struct magic *nm;
1068: size_t cnt = me->max_count + ALLOC_CHUNK;
1069: nm = erealloc(me->mp, sizeof(*nm) * cnt);
1070: me->mp = m = nm;
1071: me->max_count = cnt;
1072: }
1073: m = &me->mp[me->cont_count++];
1074: (void)memset(m, 0, sizeof(*m));
1075: m->cont_level = cont_level;
1076: } else {
1077: if (*nmentryp == maxmagic) {
1078: struct magic_entry *mp;
1079:
1080: maxmagic += ALLOC_INCR;
1081: mp = erealloc(*mentryp, sizeof(*mp) * maxmagic);
1082: (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * ALLOC_INCR);
1083: *mentryp = mp;
1084: }
1085: me = &(*mentryp)[*nmentryp];
1086: if (me->mp == NULL) {
1087: m = safe_emalloc(sizeof(*m), ALLOC_CHUNK, 0);
1088: me->mp = m;
1089: me->max_count = ALLOC_CHUNK;
1090: } else
1091: m = me->mp;
1092: (void)memset(m, 0, sizeof(*m));
1093: m->factor_op = FILE_FACTOR_OP_NONE;
1094: m->cont_level = 0;
1095: me->cont_count = 1;
1096: }
1097: m->lineno = lineno;
1098:
1099: if (*l == '&') { /* m->cont_level == 0 checked below. */
1100: ++l; /* step over */
1101: m->flag |= OFFADD;
1102: }
1103: if (*l == '(') {
1104: ++l; /* step over */
1105: m->flag |= INDIR;
1106: if (m->flag & OFFADD)
1107: m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1108:
1109: if (*l == '&') { /* m->cont_level == 0 checked below */
1110: ++l; /* step over */
1111: m->flag |= OFFADD;
1112: }
1113: }
1114: /* Indirect offsets are not valid at level 0. */
1115: if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
1116: if (ms->flags & MAGIC_CHECK)
1117: file_magwarn(ms, "relative offset at level 0");
1118:
1119: /* get offset, then skip over it */
1120: m->offset = (uint32_t)strtoul(l, &t, 0);
1121: if (l == t)
1122: if (ms->flags & MAGIC_CHECK)
1123: file_magwarn(ms, "offset `%s' invalid", l);
1124: l = t;
1125:
1126: if (m->flag & INDIR) {
1127: m->in_type = FILE_LONG;
1128: m->in_offset = 0;
1129: /*
1130: * read [.lbs][+-]nnnnn)
1131: */
1132: if (*l == '.') {
1133: l++;
1134: switch (*l) {
1135: case 'l':
1136: m->in_type = FILE_LELONG;
1137: break;
1138: case 'L':
1139: m->in_type = FILE_BELONG;
1140: break;
1141: case 'm':
1142: m->in_type = FILE_MELONG;
1143: break;
1144: case 'h':
1145: case 's':
1146: m->in_type = FILE_LESHORT;
1147: break;
1148: case 'H':
1149: case 'S':
1150: m->in_type = FILE_BESHORT;
1151: break;
1152: case 'c':
1153: case 'b':
1154: case 'C':
1155: case 'B':
1156: m->in_type = FILE_BYTE;
1157: break;
1158: case 'e':
1159: case 'f':
1160: case 'g':
1161: m->in_type = FILE_LEDOUBLE;
1162: break;
1163: case 'E':
1164: case 'F':
1165: case 'G':
1166: m->in_type = FILE_BEDOUBLE;
1167: break;
1168: case 'i':
1169: m->in_type = FILE_LEID3;
1170: break;
1171: case 'I':
1172: m->in_type = FILE_BEID3;
1173: break;
1174: default:
1175: if (ms->flags & MAGIC_CHECK)
1176: file_magwarn(ms,
1177: "indirect offset type `%c' invalid",
1178: *l);
1179: break;
1180: }
1181: l++;
1182: }
1183:
1184: m->in_op = 0;
1185: if (*l == '~') {
1186: m->in_op |= FILE_OPINVERSE;
1187: l++;
1188: }
1189: if ((op = get_op(*l)) != -1) {
1190: m->in_op |= op;
1191: l++;
1192: }
1193: if (*l == '(') {
1194: m->in_op |= FILE_OPINDIRECT;
1195: l++;
1196: }
1197: if (isdigit((unsigned char)*l) || *l == '-') {
1198: m->in_offset = (int32_t)strtol(l, &t, 0);
1199: if (l == t)
1200: if (ms->flags & MAGIC_CHECK)
1201: file_magwarn(ms,
1202: "in_offset `%s' invalid", l);
1203: l = t;
1204: }
1205: if (*l++ != ')' ||
1206: ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1207: if (ms->flags & MAGIC_CHECK)
1208: file_magwarn(ms,
1209: "missing ')' in indirect offset");
1210: }
1211: EATAB;
1212:
1213: #ifdef ENABLE_CONDITIONALS
1214: m->cond = get_cond(l, &l);
1215: if (check_cond(ms, m->cond, cont_level) == -1)
1216: return -1;
1217:
1218: EATAB;
1219: #endif
1220:
1221: if (*l == 'u') {
1222: ++l;
1223: m->flag |= UNSIGNED;
1224: }
1225:
1226: m->type = get_type(l, &l);
1227: if (m->type == FILE_INVALID) {
1228: if (ms->flags & MAGIC_CHECK)
1229: file_magwarn(ms, "type `%s' invalid", l);
1230: return -1;
1231: }
1232:
1233: /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1234: /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1235:
1236: m->mask_op = 0;
1237: if (*l == '~') {
1238: if (!IS_LIBMAGIC_STRING(m->type))
1239: m->mask_op |= FILE_OPINVERSE;
1240: else if (ms->flags & MAGIC_CHECK)
1241: file_magwarn(ms, "'~' invalid for string types");
1242: ++l;
1243: }
1244: m->str_range = 0;
1245: m->str_flags = 0;
1246: m->num_mask = 0;
1247: if ((op = get_op(*l)) != -1) {
1248: if (!IS_LIBMAGIC_STRING(m->type)) {
1249: uint64_t val;
1250: ++l;
1251: m->mask_op |= op;
1252: val = (uint64_t)strtoull(l, &t, 0);
1253: l = t;
1254: m->num_mask = file_signextend(ms, m, val);
1255: eatsize(&l);
1256: }
1257: else if (op == FILE_OPDIVIDE) {
1258: int have_range = 0;
1259: while (!isspace((unsigned char)*++l)) {
1260: switch (*l) {
1261: case '0': case '1': case '2':
1262: case '3': case '4': case '5':
1263: case '6': case '7': case '8':
1264: case '9':
1265: if (have_range &&
1266: (ms->flags & MAGIC_CHECK))
1267: file_magwarn(ms,
1268: "multiple ranges");
1269: have_range = 1;
1270: m->str_range = strtoul(l, &t, 0);
1271: if (m->str_range == 0)
1272: file_magwarn(ms,
1273: "zero range");
1274: l = t - 1;
1275: break;
1276: case CHAR_COMPACT_BLANK:
1277: m->str_flags |= STRING_COMPACT_BLANK;
1278: break;
1279: case CHAR_COMPACT_OPTIONAL_BLANK:
1280: m->str_flags |=
1281: STRING_COMPACT_OPTIONAL_BLANK;
1282: break;
1283: case CHAR_IGNORE_LOWERCASE:
1284: m->str_flags |= STRING_IGNORE_LOWERCASE;
1285: break;
1286: case CHAR_IGNORE_UPPERCASE:
1287: m->str_flags |= STRING_IGNORE_UPPERCASE;
1288: break;
1289: case CHAR_REGEX_OFFSET_START:
1290: m->str_flags |= REGEX_OFFSET_START;
1291: break;
1292: default:
1293: if (ms->flags & MAGIC_CHECK)
1294: file_magwarn(ms,
1295: "string extension `%c' invalid",
1296: *l);
1297: return -1;
1298: }
1299: /* allow multiple '/' for readability */
1300: if (l[1] == '/' &&
1301: !isspace((unsigned char)l[2]))
1302: l++;
1303: }
1304: if (string_modifier_check(ms, m) == -1)
1305: return -1;
1306: }
1307: else {
1308: if (ms->flags & MAGIC_CHECK)
1309: file_magwarn(ms, "invalid string op: %c", *t);
1310: return -1;
1311: }
1312: }
1313: /*
1314: * We used to set mask to all 1's here, instead let's just not do
1315: * anything if mask = 0 (unless you have a better idea)
1316: */
1317: EATAB;
1318:
1319: switch (*l) {
1320: case '>':
1321: case '<':
1322: m->reln = *l;
1323: ++l;
1324: if (*l == '=') {
1325: if (ms->flags & MAGIC_CHECK) {
1326: file_magwarn(ms, "%c= not supported",
1327: m->reln);
1328: return -1;
1329: }
1330: ++l;
1331: }
1332: break;
1333: /* Old-style anding: "0 byte &0x80 dynamically linked" */
1334: case '&':
1335: case '^':
1336: case '=':
1337: m->reln = *l;
1338: ++l;
1339: if (*l == '=') {
1340: /* HP compat: ignore &= etc. */
1341: ++l;
1342: }
1343: break;
1344: case '!':
1345: m->reln = *l;
1346: ++l;
1347: break;
1348: default:
1349: m->reln = '='; /* the default relation */
1350: if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
1351: isspace((unsigned char)l[1])) || !l[1])) {
1352: m->reln = *l;
1353: ++l;
1354: }
1355: break;
1356: }
1357: /*
1358: * Grab the value part, except for an 'x' reln.
1359: */
1360: if (m->reln != 'x' && getvalue(ms, m, &l, action))
1361: return -1;
1362:
1363: /*
1364: * TODO finish this macro and start using it!
1365: * #define offsetcheck {if (offset > HOWMANY-1)
1366: * magwarn("offset too big"); }
1367: */
1368:
1369: /*
1370: * Now get last part - the description
1371: */
1372: EATAB;
1373: if (l[0] == '\b') {
1374: ++l;
1375: m->flag |= NOSPACE;
1376: } else if ((l[0] == '\\') && (l[1] == 'b')) {
1377: ++l;
1378: ++l;
1379: m->flag |= NOSPACE;
1380: }
1381: for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
1382: continue;
1383: if (i == sizeof(m->desc)) {
1384: m->desc[sizeof(m->desc) - 1] = '\0';
1385: if (ms->flags & MAGIC_CHECK)
1386: file_magwarn(ms, "description `%s' truncated", m->desc);
1387: }
1388:
1389: /*
1390: * We only do this check while compiling, or if any of the magic
1391: * files were not compiled.
1392: */
1393: if (ms->flags & MAGIC_CHECK) {
1394: if (check_format(ms, m) == -1)
1395: return -1;
1396: }
1397: m->mimetype[0] = '\0'; /* initialise MIME type to none */
1398: if (m->cont_level == 0)
1399: ++(*nmentryp); /* make room for next */
1400: return 0;
1401: }
1402:
1403: /*
1404: * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
1405: * if valid
1406: */
1407: private int
1408: parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
1409: {
1410: const char *l = line;
1411: char *el;
1412: unsigned long factor;
1413: struct magic *m = &me->mp[0];
1414:
1415: if (m->factor_op != FILE_FACTOR_OP_NONE) {
1416: file_magwarn(ms,
1417: "Current entry already has a strength type: %c %d",
1418: m->factor_op, m->factor);
1419: return -1;
1420: }
1421: EATAB;
1422: switch (*l) {
1423: case FILE_FACTOR_OP_NONE:
1424: case FILE_FACTOR_OP_PLUS:
1425: case FILE_FACTOR_OP_MINUS:
1426: case FILE_FACTOR_OP_TIMES:
1427: case FILE_FACTOR_OP_DIV:
1428: m->factor_op = *l++;
1429: break;
1430: default:
1431: file_magwarn(ms, "Unknown factor op `%c'", *l);
1432: return -1;
1433: }
1434: EATAB;
1435: factor = strtoul(l, &el, 0);
1436: if (factor > 255) {
1437: file_magwarn(ms, "Too large factor `%lu'", factor);
1438: goto out;
1439: }
1440: if (*el && !isspace((unsigned char)*el)) {
1441: file_magwarn(ms, "Bad factor `%s'", l);
1442: goto out;
1443: }
1444: m->factor = (uint8_t)factor;
1445: if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
1446: file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
1447: m->factor_op, m->factor);
1448: goto out;
1449: }
1450: return 0;
1451: out:
1452: m->factor_op = FILE_FACTOR_OP_NONE;
1453: m->factor = 0;
1454: return -1;
1455: }
1456:
1457: /*
1458: * Parse an Apple CREATOR/TYPE annotation from magic file and put it into magic[index - 1]
1459: */
1460: private int
1461: parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
1462: {
1463: size_t i;
1464: const char *l = line;
1465: struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1466:
1467: if (m->apple[0] != '\0') {
1468: file_magwarn(ms, "Current entry already has a APPLE type `%.8s',"
1469: " new type `%s'", m->mimetype, l);
1470: return -1;
1471: }
1472:
1473: EATAB;
1474: for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1475: || strchr("-+/.", *l)) && i < sizeof(m->apple); m->apple[i++] = *l++)
1476: continue;
1477: if (i == sizeof(m->apple) && *l) {
1478: if (ms->flags & MAGIC_CHECK)
1479: file_magwarn(ms, "APPLE type `%s' truncated %zu",
1480: line, i);
1481: }
1482:
1483: if (i > 0)
1484: return 0;
1485: else
1486: return -1;
1487: }
1488:
1489: /*
1490: * parse a MIME annotation line from magic file, put into magic[index - 1]
1491: * if valid
1492: */
1493: private int
1494: parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
1495: {
1496: size_t i;
1497: const char *l = line;
1498: struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1499:
1500: if (m->mimetype[0] != '\0') {
1501: file_magwarn(ms, "Current entry already has a MIME type `%s',"
1502: " new type `%s'", m->mimetype, l);
1503: return -1;
1504: }
1505:
1506: EATAB;
1507: for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1508: || strchr("-+/.", *l)) && i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
1509: continue;
1510: if (i == sizeof(m->mimetype)) {
1511: m->desc[sizeof(m->mimetype) - 1] = '\0';
1512: if (ms->flags & MAGIC_CHECK)
1513: file_magwarn(ms, "MIME type `%s' truncated %zu",
1514: m->mimetype, i);
1515: } else
1516: m->mimetype[i] = '\0';
1517:
1518: if (i > 0)
1519: return 0;
1520: else
1521: return -1;
1522: }
1523:
1524: private int
1525: check_format_type(const char *ptr, int type)
1526: {
1527: int quad = 0;
1528: if (*ptr == '\0') {
1529: /* Missing format string; bad */
1530: return -1;
1531: }
1532:
1533: switch (type) {
1534: case FILE_FMT_QUAD:
1535: quad = 1;
1536: /*FALLTHROUGH*/
1537: case FILE_FMT_NUM:
1538: if (*ptr == '-')
1539: ptr++;
1540: if (*ptr == '.')
1541: ptr++;
1542: while (isdigit((unsigned char)*ptr)) ptr++;
1543: if (*ptr == '.')
1544: ptr++;
1545: while (isdigit((unsigned char)*ptr)) ptr++;
1546: if (quad) {
1547: if (*ptr++ != 'l')
1548: return -1;
1549: if (*ptr++ != 'l')
1550: return -1;
1551: }
1552:
1553: switch (*ptr++) {
1554: case 'l':
1555: switch (*ptr++) {
1556: case 'i':
1557: case 'd':
1558: case 'u':
1559: case 'x':
1560: case 'X':
1561: return 0;
1562: default:
1563: return -1;
1564: }
1565:
1566: case 'h':
1567: switch (*ptr++) {
1568: case 'h':
1569: switch (*ptr++) {
1570: case 'i':
1571: case 'd':
1572: case 'u':
1573: case 'x':
1574: case 'X':
1575: return 0;
1576: default:
1577: return -1;
1578: }
1579: case 'd':
1580: return 0;
1581: default:
1582: return -1;
1583: }
1584:
1585: case 'i':
1586: case 'c':
1587: case 'd':
1588: case 'u':
1589: case 'x':
1590: case 'X':
1591: return 0;
1592:
1593: default:
1594: return -1;
1595: }
1596:
1597: case FILE_FMT_FLOAT:
1598: case FILE_FMT_DOUBLE:
1599: if (*ptr == '-')
1600: ptr++;
1601: if (*ptr == '.')
1602: ptr++;
1603: while (isdigit((unsigned char)*ptr)) ptr++;
1604: if (*ptr == '.')
1605: ptr++;
1606: while (isdigit((unsigned char)*ptr)) ptr++;
1607:
1608: switch (*ptr++) {
1609: case 'e':
1610: case 'E':
1611: case 'f':
1612: case 'F':
1613: case 'g':
1614: case 'G':
1615: return 0;
1616:
1617: default:
1618: return -1;
1619: }
1620:
1621:
1622: case FILE_FMT_STR:
1623: if (*ptr == '-')
1624: ptr++;
1625: while (isdigit((unsigned char )*ptr))
1626: ptr++;
1627: if (*ptr == '.') {
1628: ptr++;
1629: while (isdigit((unsigned char )*ptr))
1630: ptr++;
1631: }
1632:
1633: switch (*ptr++) {
1634: case 's':
1635: return 0;
1636: default:
1637: return -1;
1638: }
1639:
1640: default:
1641: /* internal error */
1642: abort();
1643: }
1644: /*NOTREACHED*/
1645: return -1;
1646: }
1647:
1648: /*
1649: * Check that the optional printf format in description matches
1650: * the type of the magic.
1651: */
1652: private int
1653: check_format(struct magic_set *ms, struct magic *m)
1654: {
1655: char *ptr;
1656:
1657: for (ptr = m->desc; *ptr; ptr++)
1658: if (*ptr == '%')
1659: break;
1660: if (*ptr == '\0') {
1661: /* No format string; ok */
1662: return 1;
1663: }
1664:
1665: assert(file_nformats == file_nnames);
1666:
1667: if (m->type >= file_nformats) {
1668: file_magwarn(ms, "Internal error inconsistency between "
1669: "m->type and format strings");
1670: return -1;
1671: }
1672: if (file_formats[m->type] == FILE_FMT_NONE) {
1673: file_magwarn(ms, "No format string for `%s' with description "
1674: "`%s'", m->desc, file_names[m->type]);
1675: return -1;
1676: }
1677:
1678: ptr++;
1679: if (check_format_type(ptr, file_formats[m->type]) == -1) {
1680: /*
1681: * TODO: this error message is unhelpful if the format
1682: * string is not one character long
1683: */
1684: file_magwarn(ms, "Printf format `%c' is not valid for type "
1685: "`%s' in description `%s'", *ptr ? *ptr : '?',
1686: file_names[m->type], m->desc);
1687: return -1;
1688: }
1689:
1690: for (; *ptr; ptr++) {
1691: if (*ptr == '%') {
1692: file_magwarn(ms,
1693: "Too many format strings (should have at most one) "
1694: "for `%s' with description `%s'",
1695: file_names[m->type], m->desc);
1696: return -1;
1697: }
1698: }
1699: return 0;
1700: }
1701:
1702: /*
1703: * Read a numeric value from a pointer, into the value union of a magic
1704: * pointer, according to the magic type. Update the string pointer to point
1705: * just after the number read. Return 0 for success, non-zero for failure.
1706: */
1707: private int
1708: getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1709: {
1710: switch (m->type) {
1711: case FILE_BESTRING16:
1712: case FILE_LESTRING16:
1713: case FILE_STRING:
1714: case FILE_PSTRING:
1715: case FILE_REGEX:
1716: case FILE_SEARCH:
1717: *p = getstr(ms, m, *p, action == FILE_COMPILE);
1718: if (*p == NULL) {
1719: if (ms->flags & MAGIC_CHECK)
1720: file_magwarn(ms, "cannot get string from `%s'",
1721: m->value.s);
1722: return -1;
1723: }
1724: return 0;
1725: case FILE_FLOAT:
1726: case FILE_BEFLOAT:
1727: case FILE_LEFLOAT:
1728: if (m->reln != 'x') {
1729: char *ep;
1730: #ifdef HAVE_STRTOF
1731: m->value.f = strtof(*p, &ep);
1732: #else
1733: m->value.f = (float)strtod(*p, &ep);
1734: #endif
1735: *p = ep;
1736: }
1737: return 0;
1738: case FILE_DOUBLE:
1739: case FILE_BEDOUBLE:
1740: case FILE_LEDOUBLE:
1741: if (m->reln != 'x') {
1742: char *ep;
1743: m->value.d = strtod(*p, &ep);
1744: *p = ep;
1745: }
1746: return 0;
1747: default:
1748: if (m->reln != 'x') {
1749: char *ep;
1750: m->value.q = file_signextend(ms, m,
1751: (uint64_t)strtoull(*p, &ep, 0));
1752: *p = ep;
1753: eatsize(p);
1754: }
1755: return 0;
1756: }
1757: }
1758:
1759: /*
1760: * Convert a string containing C character escapes. Stop at an unescaped
1761: * space or tab.
1762: * Copy the converted version to "m->value.s", and the length in m->vallen.
1763: * Return updated scan pointer as function result. Warn if set.
1764: */
1765: private const char *
1766: getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
1767: {
1768: const char *origs = s;
1769: char *p = m->value.s;
1770: size_t plen = sizeof(m->value.s);
1771: char *origp = p;
1772: char *pmax = p + plen - 1;
1773: int c;
1774: int val;
1775:
1776: while ((c = *s++) != '\0') {
1777: if (isspace((unsigned char) c))
1778: break;
1779: if (p >= pmax) {
1780: file_error(ms, 0, "string too long: `%s'", origs);
1781: return NULL;
1782: }
1783: if (c == '\\') {
1784: switch(c = *s++) {
1785:
1786: case '\0':
1787: if (warn)
1788: file_magwarn(ms, "incomplete escape");
1789: goto out;
1790:
1791: case '\t':
1792: if (warn) {
1793: file_magwarn(ms,
1794: "escaped tab found, use \\t instead");
1795: warn = 0; /* already did */
1796: }
1797: /*FALLTHROUGH*/
1798: default:
1799: if (warn) {
1800: if (isprint((unsigned char)c)) {
1801: /* Allow escaping of
1802: * ``relations'' */
1803: if (strchr("<>&^=!", c)
1804: == NULL) {
1805: file_magwarn(ms, "no "
1806: "need to escape "
1807: "`%c'", c);
1808: }
1809: } else {
1810: file_magwarn(ms,
1811: "unknown escape sequence: "
1812: "\\%03o", c);
1813: }
1814: }
1815: /*FALLTHROUGH*/
1816: /* space, perhaps force people to use \040? */
1817: case ' ':
1818: #if 0
1819: /*
1820: * Other things people escape, but shouldn't need to,
1821: * so we disallow them
1822: */
1823: case '\'':
1824: case '"':
1825: case '?':
1826: #endif
1827: /* Relations */
1828: case '>':
1829: case '<':
1830: case '&':
1831: case '^':
1832: case '=':
1833: case '!':
1834: /* and baskslash itself */
1835: case '\\':
1836: *p++ = (char) c;
1837: break;
1838:
1839: case 'a':
1840: *p++ = '\a';
1841: break;
1842:
1843: case 'b':
1844: *p++ = '\b';
1845: break;
1846:
1847: case 'f':
1848: *p++ = '\f';
1849: break;
1850:
1851: case 'n':
1852: *p++ = '\n';
1853: break;
1854:
1855: case 'r':
1856: *p++ = '\r';
1857: break;
1858:
1859: case 't':
1860: *p++ = '\t';
1861: break;
1862:
1863: case 'v':
1864: *p++ = '\v';
1865: break;
1866:
1867: /* \ and up to 3 octal digits */
1868: case '0':
1869: case '1':
1870: case '2':
1871: case '3':
1872: case '4':
1873: case '5':
1874: case '6':
1875: case '7':
1876: val = c - '0';
1877: c = *s++; /* try for 2 */
1878: if (c >= '0' && c <= '7') {
1879: val = (val << 3) | (c - '0');
1880: c = *s++; /* try for 3 */
1881: if (c >= '0' && c <= '7')
1882: val = (val << 3) | (c-'0');
1883: else
1884: --s;
1885: }
1886: else
1887: --s;
1888: *p++ = (char)val;
1889: break;
1890:
1891: /* \x and up to 2 hex digits */
1892: case 'x':
1893: val = 'x'; /* Default if no digits */
1894: c = hextoint(*s++); /* Get next char */
1895: if (c >= 0) {
1896: val = c;
1897: c = hextoint(*s++);
1898: if (c >= 0)
1899: val = (val << 4) + c;
1900: else
1901: --s;
1902: } else
1903: --s;
1904: *p++ = (char)val;
1905: break;
1906: }
1907: } else
1908: *p++ = (char)c;
1909: }
1910: out:
1911: *p = '\0';
1912: m->vallen = p - origp;
1913: if (m->type == FILE_PSTRING)
1914: m->vallen++;
1915: return s;
1916: }
1917:
1918:
1919: /* Single hex char to int; -1 if not a hex char. */
1920: private int
1921: hextoint(int c)
1922: {
1923: if (!isascii((unsigned char) c))
1924: return -1;
1925: if (isdigit((unsigned char) c))
1926: return c - '0';
1927: if ((c >= 'a') && (c <= 'f'))
1928: return c + 10 - 'a';
1929: if (( c>= 'A') && (c <= 'F'))
1930: return c + 10 - 'A';
1931: return -1;
1932: }
1933:
1934:
1935: /*
1936: * Print a string containing C character escapes.
1937: */
1938: protected void
1939: file_showstr(FILE *fp, const char *s, size_t len)
1940: {
1941: char c;
1942:
1943: for (;;) {
1944: c = *s++;
1945: if (len == ~0U) {
1946: if (c == '\0')
1947: break;
1948: }
1949: else {
1950: if (len-- == 0)
1951: break;
1952: }
1953: if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
1954: (void) fputc(c, fp);
1955: else {
1956: (void) fputc('\\', fp);
1957: switch (c) {
1958: case '\a':
1959: (void) fputc('a', fp);
1960: break;
1961:
1962: case '\b':
1963: (void) fputc('b', fp);
1964: break;
1965:
1966: case '\f':
1967: (void) fputc('f', fp);
1968: break;
1969:
1970: case '\n':
1971: (void) fputc('n', fp);
1972: break;
1973:
1974: case '\r':
1975: (void) fputc('r', fp);
1976: break;
1977:
1978: case '\t':
1979: (void) fputc('t', fp);
1980: break;
1981:
1982: case '\v':
1983: (void) fputc('v', fp);
1984: break;
1985:
1986: default:
1987: (void) fprintf(fp, "%.3o", c & 0377);
1988: break;
1989: }
1990: }
1991: }
1992: }
1993:
1994: /*
1995: * eatsize(): Eat the size spec from a number [eg. 10UL]
1996: */
1997: private void
1998: eatsize(const char **p)
1999: {
2000: const char *l = *p;
2001:
2002: if (LOWCASE(*l) == 'u')
2003: l++;
2004:
2005: switch (LOWCASE(*l)) {
2006: case 'l': /* long */
2007: case 's': /* short */
2008: case 'h': /* short */
2009: case 'b': /* char/byte */
2010: case 'c': /* char/byte */
2011: l++;
2012: /*FALLTHROUGH*/
2013: default:
2014: break;
2015: }
2016:
2017: *p = l;
2018: }
2019:
2020: /*
2021: * handle a compiled file.
2022: * return -1 = error
2023: * return 1 = memory structure you can free
2024: * return 3 = bundled library from PHP
2025: */
2026: private int
2027: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
2028: const char *fn)
2029: {
2030: uint32_t *ptr;
2031: uint32_t version;
2032: int needsbyteswap;
2033: char *dbname = NULL;
2034: void *mm = NULL;
2035: int ret = 0;
2036: php_stream *stream = NULL;
2037: php_stream_statbuf st;
2038:
2039:
2040: TSRMLS_FETCH();
2041:
2042: if (fn == NULL) {
2043: mm = (void *)&php_magic_database;
2044: ret = 3;
2045: goto internal_loaded;
2046: }
2047:
2048: dbname = mkdbname(ms, fn, 0);
2049: if (dbname == NULL)
2050: goto error2;
2051:
2052: #if PHP_API_VERSION < 20100412
2053: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
2054: #else
2055: stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL);
2056: #endif
2057:
2058: if (!stream) {
2059: goto error2;
2060: }
2061:
2062: if (php_stream_stat(stream, &st) < 0) {
2063: file_error(ms, errno, "cannot stat `%s'", dbname);
2064: goto error1;
2065: }
2066:
2067: if (st.sb.st_size < 8) {
2068: file_error(ms, 0, "file `%s' is too small", dbname);
2069: goto error1;
2070: }
2071:
2072: mm = emalloc((size_t)st.sb.st_size);
2073: ret = 1;
2074: if (php_stream_read(stream, mm, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) {
2075: file_badread(ms);
2076: goto error1;
2077: }
2078:
2079: php_stream_close(stream);
2080: stream = NULL;
2081:
2082: internal_loaded:
2083: *magicp = mm;
2084: ptr = (uint32_t *)(void *)*magicp;
2085: if (*ptr != MAGICNO) {
2086: if (swap4(*ptr) != MAGICNO) {
2087: file_error(ms, 0, "bad magic in `%s'", dbname);
2088: goto error1;
2089: }
2090: needsbyteswap = 1;
2091: } else {
2092: needsbyteswap = 0;
2093: }
2094:
2095: if (needsbyteswap)
2096: version = swap4(ptr[1]);
2097: else
2098: version = ptr[1];
2099:
2100: if (version != VERSIONNO) {
2101: file_error(ms, 0, "File %d.%d supports only version %d magic "
2102: "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
2103: VERSIONNO, dbname, version);
2104: goto error1;
2105: }
2106:
2107: /* php_magic_database is a const, performing writes will segfault. This is for big-endian
2108: machines only, PPC and Sparc specifically. Consider static variable or MINIT in
2109: future. */
2110: if (needsbyteswap && fn == NULL) {
2111: mm = emalloc(sizeof(php_magic_database));
2112: mm = memcpy(mm, php_magic_database, sizeof(php_magic_database));
2113: *magicp = mm;
2114: ret = 1;
2115: }
2116:
2117: if (fn == NULL) {
2118: *nmagicp = (sizeof(php_magic_database) / sizeof(struct magic));
2119: } else {
2120: *nmagicp = (uint32_t)(st.sb.st_size / sizeof(struct magic));
2121: }
2122: if (*nmagicp > 0) {
2123: (*nmagicp)--;
2124: }
2125: (*magicp)++;
2126: if (needsbyteswap) {
2127: byteswap(*magicp, *nmagicp);
2128: }
2129:
2130: if (dbname) {
2131: efree(dbname);
2132: }
2133: return ret;
2134:
2135: error1:
2136: if (stream) {
2137: php_stream_close(stream);
2138: }
2139:
2140: if (mm && ret == 1) {
2141: efree(mm);
2142: } else {
2143: *magicp = NULL;
2144: *nmagicp = 0;
2145: }
2146: error2:
2147: if (dbname) {
2148: efree(dbname);
2149: }
2150: return -1;
2151: }
2152:
2153: private const uint32_t ar[] = {
2154: MAGICNO, VERSIONNO
2155: };
2156: /*
2157: * handle an mmaped file.
2158: */
2159: private int
2160: apprentice_compile(struct magic_set *ms, struct magic **magicp,
2161: uint32_t *nmagicp, const char *fn)
2162: {
2163: char *dbname;
2164: int rv = -1;
2165: php_stream *stream;
2166:
2167: TSRMLS_FETCH();
2168:
2169: dbname = mkdbname(ms, fn, 0);
2170:
2171: if (dbname == NULL) {
2172: goto out;
2173: }
2174:
2175: /* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */
2176: #if PHP_API_VERSION < 20100412
2177: stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
2178: #else
2179: stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL);
2180: #endif
2181:
2182: if (!stream) {
2183: file_error(ms, errno, "cannot open `%s'", dbname);
2184: goto out;
2185: }
2186:
2187: if (php_stream_write(stream, (char *)ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
2188: file_error(ms, errno, "error writing `%s'", dbname);
2189: goto out;
2190: }
2191:
2192: if (php_stream_seek(stream,(off_t)sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
2193: file_error(ms, errno, "error seeking `%s'", dbname);
2194: goto out;
2195: }
2196:
2197: if (php_stream_write(stream, (char *)*magicp, (sizeof(struct magic) * *nmagicp) != (ssize_t)(sizeof(struct magic) * *nmagicp))) {
2198: file_error(ms, errno, "error writing `%s'", dbname);
2199: goto out;
2200: }
2201:
2202: php_stream_close(stream);
2203:
2204: rv = 0;
2205: out:
2206: efree(dbname);
2207: return rv;
2208: }
2209:
2210: private const char ext[] = ".mgc";
2211: /*
2212: * make a dbname
2213: */
2214: private char *
2215: mkdbname(struct magic_set *ms, const char *fn, int strip)
2216: {
2217: const char *p, *q;
2218: char *buf;
2219: TSRMLS_FETCH();
2220:
2221: if (strip) {
2222: if ((p = strrchr(fn, '/')) != NULL)
2223: fn = ++p;
2224: }
2225:
2226: for (q = fn; *q; q++)
2227: continue;
2228: /* Look for .mgc */
2229: for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
2230: if (*p != *q)
2231: break;
2232:
2233: /* Did not find .mgc, restore q */
2234: if (p >= ext)
2235: while (*q)
2236: q++;
2237:
2238: q++;
2239: /* Compatibility with old code that looked in .mime */
2240: if (ms->flags & MAGIC_MIME) {
2241: spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", (int)(q - fn), fn, ext);
2242: if (VCWD_ACCESS(buf, R_OK) != -1) {
2243: ms->flags &= MAGIC_MIME_TYPE;
2244: return buf;
2245: }
2246: efree(buf);
2247: }
2248: spprintf(&buf, MAXPATHLEN, "%.*s%s", (int)(q - fn), fn, ext);
2249:
2250: /* Compatibility with old code that looked in .mime */
2251: if (strstr(p, ".mime") != NULL)
2252: ms->flags &= MAGIC_MIME_TYPE;
2253: return buf;
2254: }
2255:
2256: /*
2257: * Byteswap an mmap'ed file if needed
2258: */
2259: private void
2260: byteswap(struct magic *magic, uint32_t nmagic)
2261: {
2262: uint32_t i;
2263: for (i = 0; i < nmagic; i++)
2264: bs1(&magic[i]);
2265: }
2266:
2267: /*
2268: * swap a short
2269: */
2270: private uint16_t
2271: swap2(uint16_t sv)
2272: {
2273: uint16_t rv;
2274: uint8_t *s = (uint8_t *)(void *)&sv;
2275: uint8_t *d = (uint8_t *)(void *)&rv;
2276: d[0] = s[1];
2277: d[1] = s[0];
2278: return rv;
2279: }
2280:
2281: /*
2282: * swap an int
2283: */
2284: private uint32_t
2285: swap4(uint32_t sv)
2286: {
2287: uint32_t rv;
2288: uint8_t *s = (uint8_t *)(void *)&sv;
2289: uint8_t *d = (uint8_t *)(void *)&rv;
2290: d[0] = s[3];
2291: d[1] = s[2];
2292: d[2] = s[1];
2293: d[3] = s[0];
2294: return rv;
2295: }
2296:
2297: /*
2298: * swap a quad
2299: */
2300: private uint64_t
2301: swap8(uint64_t sv)
2302: {
2303: uint64_t rv;
2304: uint8_t *s = (uint8_t *)(void *)&sv;
2305: uint8_t *d = (uint8_t *)(void *)&rv;
2306: #if 0
2307: d[0] = s[3];
2308: d[1] = s[2];
2309: d[2] = s[1];
2310: d[3] = s[0];
2311: d[4] = s[7];
2312: d[5] = s[6];
2313: d[6] = s[5];
2314: d[7] = s[4];
2315: #else
2316: d[0] = s[7];
2317: d[1] = s[6];
2318: d[2] = s[5];
2319: d[3] = s[4];
2320: d[4] = s[3];
2321: d[5] = s[2];
2322: d[6] = s[1];
2323: d[7] = s[0];
2324: #endif
2325: return rv;
2326: }
2327:
2328: /*
2329: * byteswap a single magic entry
2330: */
2331: private void
2332: bs1(struct magic *m)
2333: {
2334: m->cont_level = swap2(m->cont_level);
2335: m->offset = swap4((uint32_t)m->offset);
2336: m->in_offset = swap4((uint32_t)m->in_offset);
2337: m->lineno = swap4((uint32_t)m->lineno);
2338: if (IS_LIBMAGIC_STRING(m->type)) {
2339: m->str_range = swap4(m->str_range);
2340: m->str_flags = swap4(m->str_flags);
2341: }
2342: else {
2343: m->value.q = swap8(m->value.q);
2344: m->num_mask = swap8(m->num_mask);
2345: }
2346: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>