Deleted Added
full compact
apprentice.c (133359) apprentice.c (139368)
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.
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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Ian F. Darwin and others.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33/*
34 * apprentice - make one pass through /etc/magic, learning its secrets.
35 */
36
37#include "file.h"
38#include "magic.h"
39#include <stdlib.h>
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43#include <string.h>
44#include <ctype.h>
45#include <fcntl.h>
46#include <sys/stat.h>
47#include <sys/param.h>
48#ifdef QUICK
49#include <sys/mman.h>
50#endif
51
52#ifndef lint
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/*
29 * apprentice - make one pass through /etc/magic, learning its secrets.
30 */
31
32#include "file.h"
33#include "magic.h"
34#include <stdlib.h>
35#ifdef HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38#include <string.h>
39#include <ctype.h>
40#include <fcntl.h>
41#include <sys/stat.h>
42#include <sys/param.h>
43#ifdef QUICK
44#include <sys/mman.h>
45#endif
46
47#ifndef lint
53FILE_RCSID("@(#)$Id: apprentice.c,v 1.78 2004/07/24 20:38:56 christos Exp $")
48FILE_RCSID("@(#)$Id: apprentice.c,v 1.82 2004/11/24 18:56:04 christos Exp $")
54#endif /* lint */
55
56#define EATAB {while (isascii((unsigned char) *l) && \
57 isspace((unsigned char) *l)) ++l;}
58#define LOWCASE(l) (isupper((unsigned char) (l)) ? \
59 tolower((unsigned char) (l)) : (l))
60/*
61 * Work around a bug in headers on Digital Unix.
62 * At least confirmed for: OSF1 V4.0 878
63 */
64#if defined(__osf__) && defined(__DECC)
65#ifdef MAP_FAILED
66#undef MAP_FAILED
67#endif
68#endif
69
70#ifndef MAP_FAILED
71#define MAP_FAILED (void *) -1
72#endif
73
74#ifndef MAP_FILE
75#define MAP_FILE 0
76#endif
77
78#ifndef MAXPATHLEN
79#define MAXPATHLEN 1024
80#endif
81
49#endif /* lint */
50
51#define EATAB {while (isascii((unsigned char) *l) && \
52 isspace((unsigned char) *l)) ++l;}
53#define LOWCASE(l) (isupper((unsigned char) (l)) ? \
54 tolower((unsigned char) (l)) : (l))
55/*
56 * Work around a bug in headers on Digital Unix.
57 * At least confirmed for: OSF1 V4.0 878
58 */
59#if defined(__osf__) && defined(__DECC)
60#ifdef MAP_FAILED
61#undef MAP_FAILED
62#endif
63#endif
64
65#ifndef MAP_FAILED
66#define MAP_FAILED (void *) -1
67#endif
68
69#ifndef MAP_FILE
70#define MAP_FILE 0
71#endif
72
73#ifndef MAXPATHLEN
74#define MAXPATHLEN 1024
75#endif
76
77#define IS_STRING(t) ((t) == FILE_STRING || (t) == FILE_PSTRING || \
78 (t) == FILE_BESTRING16 || (t) == FILE_LESTRING16)
79
82private int getvalue(struct magic_set *ms, struct magic *, char **);
83private int hextoint(int);
84private char *getstr(struct magic_set *, char *, char *, int, int *);
85private int parse(struct magic_set *, struct magic **, uint32_t *, char *, int);
86private void eatsize(char **);
87private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
88private int apprentice_file(struct magic_set *, struct magic **, uint32_t *,
89 const char *, int);
90private void byteswap(struct magic *, uint32_t);
91private void bs1(struct magic *);
92private uint16_t swap2(uint16_t);
93private uint32_t swap4(uint32_t);
80private int getvalue(struct magic_set *ms, struct magic *, char **);
81private int hextoint(int);
82private char *getstr(struct magic_set *, char *, char *, int, int *);
83private int parse(struct magic_set *, struct magic **, uint32_t *, char *, int);
84private void eatsize(char **);
85private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
86private int apprentice_file(struct magic_set *, struct magic **, uint32_t *,
87 const char *, int);
88private void byteswap(struct magic *, uint32_t);
89private void bs1(struct magic *);
90private uint16_t swap2(uint16_t);
91private uint32_t swap4(uint32_t);
94private char *mkdbname(const char *, char *, size_t);
92private char *mkdbname(const char *, char *, size_t, int);
95private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
96 const char *);
97private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
98 const char *);
93private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
94 const char *);
95private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
96 const char *);
99private int check_format(struct magic *);
97private int check_format(struct magic_set *, struct magic *);
100
101private size_t maxmagic = 0;
102private size_t magicsize = sizeof(struct magic);
103
104#ifdef COMPILE_ONLY
105
106int main(int, char *[]);
107
108int
109main(int argc, char *argv[])
110{
111 int ret;
112 struct magic_set *ms;
113 char *progname;
114
115 if ((progname = strrchr(argv[0], '/')) != NULL)
116 progname++;
117 else
118 progname = argv[0];
119
120 if (argc != 2) {
121 (void)fprintf(stderr, "Usage: %s file\n", progname);
122 return 1;
123 }
124
125 if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
126 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
127 return 1;
128 }
129 ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
130 if (ret == 1)
131 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
132 magic_close(ms);
133 return ret;
134}
135#endif /* COMPILE_ONLY */
136
137
138/*
139 * Handle one file.
140 */
141private int
142apprentice_1(struct magic_set *ms, const char *fn, int action,
143 struct mlist *mlist)
144{
145 struct magic *magic = NULL;
146 uint32_t nmagic = 0;
147 struct mlist *ml;
148 int rv = -1;
149 int mapped;
150
151 if (magicsize != FILE_MAGICSIZE) {
152 file_error(ms, 0, "magic element size %lu != %lu",
153 (unsigned long)sizeof(*magic),
154 (unsigned long)FILE_MAGICSIZE);
155 return -1;
156 }
157
158 if (action == FILE_COMPILE) {
159 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
160 if (rv != 0)
161 return -1;
162 rv = apprentice_compile(ms, &magic, &nmagic, fn);
163 free(magic);
164 return rv;
165 }
166#ifndef COMPILE_ONLY
167 if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
168 if (ms->flags & MAGIC_CHECK)
98
99private size_t maxmagic = 0;
100private size_t magicsize = sizeof(struct magic);
101
102#ifdef COMPILE_ONLY
103
104int main(int, char *[]);
105
106int
107main(int argc, char *argv[])
108{
109 int ret;
110 struct magic_set *ms;
111 char *progname;
112
113 if ((progname = strrchr(argv[0], '/')) != NULL)
114 progname++;
115 else
116 progname = argv[0];
117
118 if (argc != 2) {
119 (void)fprintf(stderr, "Usage: %s file\n", progname);
120 return 1;
121 }
122
123 if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
124 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
125 return 1;
126 }
127 ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
128 if (ret == 1)
129 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
130 magic_close(ms);
131 return ret;
132}
133#endif /* COMPILE_ONLY */
134
135
136/*
137 * Handle one file.
138 */
139private int
140apprentice_1(struct magic_set *ms, const char *fn, int action,
141 struct mlist *mlist)
142{
143 struct magic *magic = NULL;
144 uint32_t nmagic = 0;
145 struct mlist *ml;
146 int rv = -1;
147 int mapped;
148
149 if (magicsize != FILE_MAGICSIZE) {
150 file_error(ms, 0, "magic element size %lu != %lu",
151 (unsigned long)sizeof(*magic),
152 (unsigned long)FILE_MAGICSIZE);
153 return -1;
154 }
155
156 if (action == FILE_COMPILE) {
157 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
158 if (rv != 0)
159 return -1;
160 rv = apprentice_compile(ms, &magic, &nmagic, fn);
161 free(magic);
162 return rv;
163 }
164#ifndef COMPILE_ONLY
165 if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
166 if (ms->flags & MAGIC_CHECK)
169 file_magwarn("using regular magic file `%s'", fn);
167 file_magwarn(ms, "using regular magic file `%s'", fn);
170 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
171 if (rv != 0)
172 return -1;
173 mapped = 0;
174 }
175
176 if (rv == -1)
177 return rv;
178 mapped = rv;
179
180 if (magic == NULL || nmagic == 0) {
181 file_delmagic(magic, mapped, nmagic);
182 return -1;
183 }
184
185 if ((ml = malloc(sizeof(*ml))) == NULL) {
186 file_delmagic(magic, mapped, nmagic);
187 file_oomem(ms);
188 return -1;
189 }
190
191 ml->magic = magic;
192 ml->nmagic = nmagic;
193 ml->mapped = mapped;
194
195 mlist->prev->next = ml;
196 ml->prev = mlist->prev;
197 ml->next = mlist;
198 mlist->prev = ml;
199
200 return 0;
201#endif /* COMPILE_ONLY */
202}
203
204protected void
205file_delmagic(struct magic *p, int type, size_t entries)
206{
207 if (p == NULL)
208 return;
209 switch (type) {
210 case 2:
211 p--;
212 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
213 break;
214 case 1:
215 p--;
216 /*FALLTHROUGH*/
217 case 0:
218 free(p);
219 break;
220 default:
221 abort();
222 }
223}
224
225
226/* const char *fn: list of magic files */
227protected struct mlist *
228file_apprentice(struct magic_set *ms, const char *fn, int action)
229{
230 char *p, *mfn, *afn = NULL;
231 int file_err, errs = -1;
232 struct mlist *mlist;
233
234 if (fn == NULL)
235 fn = getenv("MAGIC");
236 if (fn == NULL)
237 fn = MAGIC;
238
239 if ((fn = mfn = strdup(fn)) == NULL) {
240 file_oomem(ms);
241 return NULL;
242 }
243
244 if ((mlist = malloc(sizeof(*mlist))) == NULL) {
245 free(mfn);
246 file_oomem(ms);
247 return NULL;
248 }
249 mlist->next = mlist->prev = mlist;
250
251 while (fn) {
252 p = strchr(fn, PATHSEP);
253 if (p)
254 *p++ = '\0';
255 if (*fn == '\0')
256 break;
257 if (ms->flags & MAGIC_MIME) {
258 if ((afn = malloc(strlen(fn) + 5 + 1)) == NULL) {
259 free(mfn);
260 free(mlist);
261 file_oomem(ms);
262 return NULL;
263 }
264 (void)strcpy(afn, fn);
265 (void)strcat(afn, ".mime");
266 fn = afn;
267 }
268 file_err = apprentice_1(ms, fn, action, mlist);
269 if (file_err > errs)
270 errs = file_err;
271 if (afn) {
272 free(afn);
273 afn = NULL;
274 }
275 fn = p;
276 }
277 if (errs == -1) {
278 free(mfn);
279 free(mlist);
280 mlist = NULL;
281 file_error(ms, 0, "could not find any magic files!");
282 return NULL;
283 }
284 free(mfn);
285 return mlist;
286}
287
288/*
289 * parse from a file
290 * const char *fn: name of magic file
291 */
292private int
293apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
294 const char *fn, int action)
295{
296 private const char hdr[] =
297 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
298 FILE *f;
299 char line[BUFSIZ+1];
168 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
169 if (rv != 0)
170 return -1;
171 mapped = 0;
172 }
173
174 if (rv == -1)
175 return rv;
176 mapped = rv;
177
178 if (magic == NULL || nmagic == 0) {
179 file_delmagic(magic, mapped, nmagic);
180 return -1;
181 }
182
183 if ((ml = malloc(sizeof(*ml))) == NULL) {
184 file_delmagic(magic, mapped, nmagic);
185 file_oomem(ms);
186 return -1;
187 }
188
189 ml->magic = magic;
190 ml->nmagic = nmagic;
191 ml->mapped = mapped;
192
193 mlist->prev->next = ml;
194 ml->prev = mlist->prev;
195 ml->next = mlist;
196 mlist->prev = ml;
197
198 return 0;
199#endif /* COMPILE_ONLY */
200}
201
202protected void
203file_delmagic(struct magic *p, int type, size_t entries)
204{
205 if (p == NULL)
206 return;
207 switch (type) {
208 case 2:
209 p--;
210 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
211 break;
212 case 1:
213 p--;
214 /*FALLTHROUGH*/
215 case 0:
216 free(p);
217 break;
218 default:
219 abort();
220 }
221}
222
223
224/* const char *fn: list of magic files */
225protected struct mlist *
226file_apprentice(struct magic_set *ms, const char *fn, int action)
227{
228 char *p, *mfn, *afn = NULL;
229 int file_err, errs = -1;
230 struct mlist *mlist;
231
232 if (fn == NULL)
233 fn = getenv("MAGIC");
234 if (fn == NULL)
235 fn = MAGIC;
236
237 if ((fn = mfn = strdup(fn)) == NULL) {
238 file_oomem(ms);
239 return NULL;
240 }
241
242 if ((mlist = malloc(sizeof(*mlist))) == NULL) {
243 free(mfn);
244 file_oomem(ms);
245 return NULL;
246 }
247 mlist->next = mlist->prev = mlist;
248
249 while (fn) {
250 p = strchr(fn, PATHSEP);
251 if (p)
252 *p++ = '\0';
253 if (*fn == '\0')
254 break;
255 if (ms->flags & MAGIC_MIME) {
256 if ((afn = malloc(strlen(fn) + 5 + 1)) == NULL) {
257 free(mfn);
258 free(mlist);
259 file_oomem(ms);
260 return NULL;
261 }
262 (void)strcpy(afn, fn);
263 (void)strcat(afn, ".mime");
264 fn = afn;
265 }
266 file_err = apprentice_1(ms, fn, action, mlist);
267 if (file_err > errs)
268 errs = file_err;
269 if (afn) {
270 free(afn);
271 afn = NULL;
272 }
273 fn = p;
274 }
275 if (errs == -1) {
276 free(mfn);
277 free(mlist);
278 mlist = NULL;
279 file_error(ms, 0, "could not find any magic files!");
280 return NULL;
281 }
282 free(mfn);
283 return mlist;
284}
285
286/*
287 * parse from a file
288 * const char *fn: name of magic file
289 */
290private int
291apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
292 const char *fn, int action)
293{
294 private const char hdr[] =
295 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
296 FILE *f;
297 char line[BUFSIZ+1];
300 int lineno;
301 int errs = 0;
302
298 int errs = 0;
299
303 f = fopen(fn, "r");
300 f = fopen(ms->file = fn, "r");
304 if (f == NULL) {
305 if (errno != ENOENT)
306 file_error(ms, errno, "cannot read magic file `%s'",
307 fn);
308 return -1;
309 }
310
311 maxmagic = MAXMAGIS;
312 *magicp = (struct magic *) calloc(maxmagic, sizeof(struct magic));
313 if (*magicp == NULL) {
314 (void)fclose(f);
315 file_oomem(ms);
316 return -1;
317 }
318
319 /* print silly verbose header for USG compat. */
320 if (action == FILE_CHECK)
321 (void)fprintf(stderr, "%s\n", hdr);
322
323 /* parse it */
301 if (f == NULL) {
302 if (errno != ENOENT)
303 file_error(ms, errno, "cannot read magic file `%s'",
304 fn);
305 return -1;
306 }
307
308 maxmagic = MAXMAGIS;
309 *magicp = (struct magic *) calloc(maxmagic, sizeof(struct magic));
310 if (*magicp == NULL) {
311 (void)fclose(f);
312 file_oomem(ms);
313 return -1;
314 }
315
316 /* print silly verbose header for USG compat. */
317 if (action == FILE_CHECK)
318 (void)fprintf(stderr, "%s\n", hdr);
319
320 /* parse it */
324 for (lineno = 1; fgets(line, BUFSIZ, f) != NULL; lineno++) {
321 for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) {
322 size_t len;
325 if (line[0]=='#') /* comment, do not parse */
326 continue;
323 if (line[0]=='#') /* comment, do not parse */
324 continue;
327 if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
325 len = strlen(line);
326 if (len < 2) /* null line, garbage, etc */
328 continue;
327 continue;
329 line[strlen(line)-1] = '\0'; /* delete newline */
328 line[len - 1] = '\0'; /* delete newline */
330 if (parse(ms, magicp, nmagicp, line, action) != 0)
331 errs = 1;
332 }
333
334 (void)fclose(f);
335 if (errs) {
336 free(*magicp);
337 *magicp = NULL;
338 *nmagicp = 0;
339 }
340 return errs;
341}
342
343/*
344 * extend the sign bit if the comparison is to be signed
345 */
346protected uint32_t
347file_signextend(struct magic_set *ms, struct magic *m, uint32_t v)
348{
349 if (!(m->flag & UNSIGNED))
350 switch(m->type) {
351 /*
352 * Do not remove the casts below. They are
353 * vital. When later compared with the data,
354 * the sign extension must have happened.
355 */
356 case FILE_BYTE:
357 v = (char) v;
358 break;
359 case FILE_SHORT:
360 case FILE_BESHORT:
361 case FILE_LESHORT:
362 v = (short) v;
363 break;
364 case FILE_DATE:
365 case FILE_BEDATE:
366 case FILE_LEDATE:
367 case FILE_LDATE:
368 case FILE_BELDATE:
369 case FILE_LELDATE:
370 case FILE_LONG:
371 case FILE_BELONG:
372 case FILE_LELONG:
373 v = (int32_t) v;
374 break;
375 case FILE_STRING:
376 case FILE_PSTRING:
329 if (parse(ms, magicp, nmagicp, line, action) != 0)
330 errs = 1;
331 }
332
333 (void)fclose(f);
334 if (errs) {
335 free(*magicp);
336 *magicp = NULL;
337 *nmagicp = 0;
338 }
339 return errs;
340}
341
342/*
343 * extend the sign bit if the comparison is to be signed
344 */
345protected uint32_t
346file_signextend(struct magic_set *ms, struct magic *m, uint32_t v)
347{
348 if (!(m->flag & UNSIGNED))
349 switch(m->type) {
350 /*
351 * Do not remove the casts below. They are
352 * vital. When later compared with the data,
353 * the sign extension must have happened.
354 */
355 case FILE_BYTE:
356 v = (char) v;
357 break;
358 case FILE_SHORT:
359 case FILE_BESHORT:
360 case FILE_LESHORT:
361 v = (short) v;
362 break;
363 case FILE_DATE:
364 case FILE_BEDATE:
365 case FILE_LEDATE:
366 case FILE_LDATE:
367 case FILE_BELDATE:
368 case FILE_LELDATE:
369 case FILE_LONG:
370 case FILE_BELONG:
371 case FILE_LELONG:
372 v = (int32_t) v;
373 break;
374 case FILE_STRING:
375 case FILE_PSTRING:
376 case FILE_BESTRING16:
377 case FILE_LESTRING16:
377 break;
378 case FILE_REGEX:
379 break;
380 default:
381 if (ms->flags & MAGIC_CHECK)
378 break;
379 case FILE_REGEX:
380 break;
381 default:
382 if (ms->flags & MAGIC_CHECK)
382 file_magwarn("cannot happen: m->type=%d\n",
383 file_magwarn(ms, "cannot happen: m->type=%d\n",
383 m->type);
384 return ~0U;
385 }
386 return v;
387}
388
389/*
390 * parse one line from magic file, put into magic[index++] if valid
391 */
392private int
393parse(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, char *l,
394 int action)
395{
396 int i = 0;
397 struct magic *m;
398 char *t;
399 private const char *fops = FILE_OPS;
400 uint32_t val;
401
402#define ALLOC_INCR 200
403 if (*nmagicp + 1 >= maxmagic){
404 maxmagic += ALLOC_INCR;
405 if ((m = (struct magic *) realloc(*magicp,
406 sizeof(struct magic) * maxmagic)) == NULL) {
407 file_oomem(ms);
408 if (*magicp)
409 free(*magicp);
410 return -1;
411 }
412 *magicp = m;
413 memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic)
414 * ALLOC_INCR);
415 }
416 m = &(*magicp)[*nmagicp];
417 m->flag = 0;
418 m->cont_level = 0;
419
420 while (*l == '>') {
421 ++l; /* step over */
422 m->cont_level++;
423 }
424
425 if (m->cont_level != 0 && *l == '(') {
426 ++l; /* step over */
427 m->flag |= INDIR;
428 }
429 if (m->cont_level != 0 && *l == '&') {
430 ++l; /* step over */
431 m->flag |= OFFADD;
432 }
433
434 /* get offset, then skip over it */
435 m->offset = (uint32_t)strtoul(l, &t, 0);
436 if (l == t)
437 if (ms->flags & MAGIC_CHECK)
384 m->type);
385 return ~0U;
386 }
387 return v;
388}
389
390/*
391 * parse one line from magic file, put into magic[index++] if valid
392 */
393private int
394parse(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp, char *l,
395 int action)
396{
397 int i = 0;
398 struct magic *m;
399 char *t;
400 private const char *fops = FILE_OPS;
401 uint32_t val;
402
403#define ALLOC_INCR 200
404 if (*nmagicp + 1 >= maxmagic){
405 maxmagic += ALLOC_INCR;
406 if ((m = (struct magic *) realloc(*magicp,
407 sizeof(struct magic) * maxmagic)) == NULL) {
408 file_oomem(ms);
409 if (*magicp)
410 free(*magicp);
411 return -1;
412 }
413 *magicp = m;
414 memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic)
415 * ALLOC_INCR);
416 }
417 m = &(*magicp)[*nmagicp];
418 m->flag = 0;
419 m->cont_level = 0;
420
421 while (*l == '>') {
422 ++l; /* step over */
423 m->cont_level++;
424 }
425
426 if (m->cont_level != 0 && *l == '(') {
427 ++l; /* step over */
428 m->flag |= INDIR;
429 }
430 if (m->cont_level != 0 && *l == '&') {
431 ++l; /* step over */
432 m->flag |= OFFADD;
433 }
434
435 /* get offset, then skip over it */
436 m->offset = (uint32_t)strtoul(l, &t, 0);
437 if (l == t)
438 if (ms->flags & MAGIC_CHECK)
438 file_magwarn("offset %s invalid", l);
439 file_magwarn(ms, "offset `%s' invalid", l);
439 l = t;
440
441 if (m->flag & INDIR) {
442 m->in_type = FILE_LONG;
443 m->in_offset = 0;
444 /*
445 * read [.lbs][+-]nnnnn)
446 */
447 if (*l == '.') {
448 l++;
449 switch (*l) {
450 case 'l':
451 m->in_type = FILE_LELONG;
452 break;
453 case 'L':
454 m->in_type = FILE_BELONG;
455 break;
456 case 'h':
457 case 's':
458 m->in_type = FILE_LESHORT;
459 break;
460 case 'H':
461 case 'S':
462 m->in_type = FILE_BESHORT;
463 break;
464 case 'c':
465 case 'b':
466 case 'C':
467 case 'B':
468 m->in_type = FILE_BYTE;
469 break;
470 default:
471 if (ms->flags & MAGIC_CHECK)
440 l = t;
441
442 if (m->flag & INDIR) {
443 m->in_type = FILE_LONG;
444 m->in_offset = 0;
445 /*
446 * read [.lbs][+-]nnnnn)
447 */
448 if (*l == '.') {
449 l++;
450 switch (*l) {
451 case 'l':
452 m->in_type = FILE_LELONG;
453 break;
454 case 'L':
455 m->in_type = FILE_BELONG;
456 break;
457 case 'h':
458 case 's':
459 m->in_type = FILE_LESHORT;
460 break;
461 case 'H':
462 case 'S':
463 m->in_type = FILE_BESHORT;
464 break;
465 case 'c':
466 case 'b':
467 case 'C':
468 case 'B':
469 m->in_type = FILE_BYTE;
470 break;
471 default:
472 if (ms->flags & MAGIC_CHECK)
472 file_magwarn(
473 "indirect offset type %c invalid",
473 file_magwarn(ms,
474 "indirect offset type `%c' invalid",
474 *l);
475 break;
476 }
477 l++;
478 }
479 if (*l == '~') {
480 m->in_op = FILE_OPINVERSE;
481 l++;
482 }
483 switch (*l) {
484 case '&':
485 m->in_op |= FILE_OPAND;
486 l++;
487 break;
488 case '|':
489 m->in_op |= FILE_OPOR;
490 l++;
491 break;
492 case '^':
493 m->in_op |= FILE_OPXOR;
494 l++;
495 break;
496 case '+':
497 m->in_op |= FILE_OPADD;
498 l++;
499 break;
500 case '-':
501 m->in_op |= FILE_OPMINUS;
502 l++;
503 break;
504 case '*':
505 m->in_op |= FILE_OPMULTIPLY;
506 l++;
507 break;
508 case '/':
509 m->in_op |= FILE_OPDIVIDE;
510 l++;
511 break;
512 case '%':
513 m->in_op |= FILE_OPMODULO;
514 l++;
515 break;
516 }
517 if (isdigit((unsigned char)*l))
518 m->in_offset = (uint32_t)strtoul(l, &t, 0);
519 else
520 t = l;
521 if (*t++ != ')')
522 if (ms->flags & MAGIC_CHECK)
475 *l);
476 break;
477 }
478 l++;
479 }
480 if (*l == '~') {
481 m->in_op = FILE_OPINVERSE;
482 l++;
483 }
484 switch (*l) {
485 case '&':
486 m->in_op |= FILE_OPAND;
487 l++;
488 break;
489 case '|':
490 m->in_op |= FILE_OPOR;
491 l++;
492 break;
493 case '^':
494 m->in_op |= FILE_OPXOR;
495 l++;
496 break;
497 case '+':
498 m->in_op |= FILE_OPADD;
499 l++;
500 break;
501 case '-':
502 m->in_op |= FILE_OPMINUS;
503 l++;
504 break;
505 case '*':
506 m->in_op |= FILE_OPMULTIPLY;
507 l++;
508 break;
509 case '/':
510 m->in_op |= FILE_OPDIVIDE;
511 l++;
512 break;
513 case '%':
514 m->in_op |= FILE_OPMODULO;
515 l++;
516 break;
517 }
518 if (isdigit((unsigned char)*l))
519 m->in_offset = (uint32_t)strtoul(l, &t, 0);
520 else
521 t = l;
522 if (*t++ != ')')
523 if (ms->flags & MAGIC_CHECK)
523 file_magwarn("missing ')' in indirect offset");
524 file_magwarn(ms,
525 "missing ')' in indirect offset");
524 l = t;
525 }
526
527
528 while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
529 ++l;
530 EATAB;
531
532#define NBYTE 4
533#define NSHORT 5
534#define NLONG 4
535#define NSTRING 6
536#define NDATE 4
537#define NBESHORT 7
538#define NBELONG 6
539#define NBEDATE 6
540#define NLESHORT 7
541#define NLELONG 6
542#define NLEDATE 6
543#define NPSTRING 7
544#define NLDATE 5
545#define NBELDATE 7
546#define NLELDATE 7
547#define NREGEX 5
526 l = t;
527 }
528
529
530 while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
531 ++l;
532 EATAB;
533
534#define NBYTE 4
535#define NSHORT 5
536#define NLONG 4
537#define NSTRING 6
538#define NDATE 4
539#define NBESHORT 7
540#define NBELONG 6
541#define NBEDATE 6
542#define NLESHORT 7
543#define NLELONG 6
544#define NLEDATE 6
545#define NPSTRING 7
546#define NLDATE 5
547#define NBELDATE 7
548#define NLELDATE 7
549#define NREGEX 5
550#define NBESTRING16 10
551#define NLESTRING16 10
548
549 if (*l == 'u') {
550 ++l;
551 m->flag |= UNSIGNED;
552 }
553
554 /* get type, skip it */
555 if (strncmp(l, "char", NBYTE)==0) { /* HP/UX compat */
556 m->type = FILE_BYTE;
557 l += NBYTE;
558 } else if (strncmp(l, "byte", NBYTE)==0) {
559 m->type = FILE_BYTE;
560 l += NBYTE;
561 } else if (strncmp(l, "short", NSHORT)==0) {
562 m->type = FILE_SHORT;
563 l += NSHORT;
564 } else if (strncmp(l, "long", NLONG)==0) {
565 m->type = FILE_LONG;
566 l += NLONG;
567 } else if (strncmp(l, "string", NSTRING)==0) {
568 m->type = FILE_STRING;
569 l += NSTRING;
570 } else if (strncmp(l, "date", NDATE)==0) {
571 m->type = FILE_DATE;
572 l += NDATE;
573 } else if (strncmp(l, "beshort", NBESHORT)==0) {
574 m->type = FILE_BESHORT;
575 l += NBESHORT;
576 } else if (strncmp(l, "belong", NBELONG)==0) {
577 m->type = FILE_BELONG;
578 l += NBELONG;
579 } else if (strncmp(l, "bedate", NBEDATE)==0) {
580 m->type = FILE_BEDATE;
581 l += NBEDATE;
582 } else if (strncmp(l, "leshort", NLESHORT)==0) {
583 m->type = FILE_LESHORT;
584 l += NLESHORT;
585 } else if (strncmp(l, "lelong", NLELONG)==0) {
586 m->type = FILE_LELONG;
587 l += NLELONG;
588 } else if (strncmp(l, "ledate", NLEDATE)==0) {
589 m->type = FILE_LEDATE;
590 l += NLEDATE;
591 } else if (strncmp(l, "pstring", NPSTRING)==0) {
592 m->type = FILE_PSTRING;
593 l += NPSTRING;
594 } else if (strncmp(l, "ldate", NLDATE)==0) {
595 m->type = FILE_LDATE;
596 l += NLDATE;
597 } else if (strncmp(l, "beldate", NBELDATE)==0) {
598 m->type = FILE_BELDATE;
599 l += NBELDATE;
600 } else if (strncmp(l, "leldate", NLELDATE)==0) {
601 m->type = FILE_LELDATE;
602 l += NLELDATE;
603 } else if (strncmp(l, "regex", NREGEX)==0) {
604 m->type = FILE_REGEX;
552
553 if (*l == 'u') {
554 ++l;
555 m->flag |= UNSIGNED;
556 }
557
558 /* get type, skip it */
559 if (strncmp(l, "char", NBYTE)==0) { /* HP/UX compat */
560 m->type = FILE_BYTE;
561 l += NBYTE;
562 } else if (strncmp(l, "byte", NBYTE)==0) {
563 m->type = FILE_BYTE;
564 l += NBYTE;
565 } else if (strncmp(l, "short", NSHORT)==0) {
566 m->type = FILE_SHORT;
567 l += NSHORT;
568 } else if (strncmp(l, "long", NLONG)==0) {
569 m->type = FILE_LONG;
570 l += NLONG;
571 } else if (strncmp(l, "string", NSTRING)==0) {
572 m->type = FILE_STRING;
573 l += NSTRING;
574 } else if (strncmp(l, "date", NDATE)==0) {
575 m->type = FILE_DATE;
576 l += NDATE;
577 } else if (strncmp(l, "beshort", NBESHORT)==0) {
578 m->type = FILE_BESHORT;
579 l += NBESHORT;
580 } else if (strncmp(l, "belong", NBELONG)==0) {
581 m->type = FILE_BELONG;
582 l += NBELONG;
583 } else if (strncmp(l, "bedate", NBEDATE)==0) {
584 m->type = FILE_BEDATE;
585 l += NBEDATE;
586 } else if (strncmp(l, "leshort", NLESHORT)==0) {
587 m->type = FILE_LESHORT;
588 l += NLESHORT;
589 } else if (strncmp(l, "lelong", NLELONG)==0) {
590 m->type = FILE_LELONG;
591 l += NLELONG;
592 } else if (strncmp(l, "ledate", NLEDATE)==0) {
593 m->type = FILE_LEDATE;
594 l += NLEDATE;
595 } else if (strncmp(l, "pstring", NPSTRING)==0) {
596 m->type = FILE_PSTRING;
597 l += NPSTRING;
598 } else if (strncmp(l, "ldate", NLDATE)==0) {
599 m->type = FILE_LDATE;
600 l += NLDATE;
601 } else if (strncmp(l, "beldate", NBELDATE)==0) {
602 m->type = FILE_BELDATE;
603 l += NBELDATE;
604 } else if (strncmp(l, "leldate", NLELDATE)==0) {
605 m->type = FILE_LELDATE;
606 l += NLELDATE;
607 } else if (strncmp(l, "regex", NREGEX)==0) {
608 m->type = FILE_REGEX;
605 l += sizeof("regex");
609 l += NREGEX;
610 } else if (strncmp(l, "bestring16", NBESTRING16)==0) {
611 m->type = FILE_BESTRING16;
612 l += NBESTRING16;
613 } else if (strncmp(l, "lestring16", NLESTRING16)==0) {
614 m->type = FILE_LESTRING16;
615 l += NLESTRING16;
606 } else {
607 if (ms->flags & MAGIC_CHECK)
616 } else {
617 if (ms->flags & MAGIC_CHECK)
608 file_magwarn("type %s invalid", l);
618 file_magwarn(ms, "type `%s' invalid", l);
609 return -1;
610 }
611 /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
612 /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
613 if (*l == '~') {
619 return -1;
620 }
621 /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
622 /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
623 if (*l == '~') {
614 if (FILE_STRING != m->type && FILE_PSTRING != m->type)
624 if (!IS_STRING(m->type))
615 m->mask_op = FILE_OPINVERSE;
616 ++l;
617 }
618 if ((t = strchr(fops, *l)) != NULL) {
619 uint32_t op = (uint32_t)(t - fops);
625 m->mask_op = FILE_OPINVERSE;
626 ++l;
627 }
628 if ((t = strchr(fops, *l)) != NULL) {
629 uint32_t op = (uint32_t)(t - fops);
620 if (op != FILE_OPDIVIDE ||
621 (FILE_STRING != m->type && FILE_PSTRING != m->type)) {
630 if (op != FILE_OPDIVIDE || !IS_STRING(m->type)) {
622 ++l;
623 m->mask_op |= op;
624 val = (uint32_t)strtoul(l, &l, 0);
625 m->mask = file_signextend(ms, m, val);
626 eatsize(&l);
627 } else {
628 m->mask = 0L;
629 while (!isspace((unsigned char)*++l)) {
630 switch (*l) {
631 case CHAR_IGNORE_LOWERCASE:
632 m->mask |= STRING_IGNORE_LOWERCASE;
633 break;
634 case CHAR_COMPACT_BLANK:
635 m->mask |= STRING_COMPACT_BLANK;
636 break;
637 case CHAR_COMPACT_OPTIONAL_BLANK:
638 m->mask |=
639 STRING_COMPACT_OPTIONAL_BLANK;
640 break;
641 default:
642 if (ms->flags & MAGIC_CHECK)
631 ++l;
632 m->mask_op |= op;
633 val = (uint32_t)strtoul(l, &l, 0);
634 m->mask = file_signextend(ms, m, val);
635 eatsize(&l);
636 } else {
637 m->mask = 0L;
638 while (!isspace((unsigned char)*++l)) {
639 switch (*l) {
640 case CHAR_IGNORE_LOWERCASE:
641 m->mask |= STRING_IGNORE_LOWERCASE;
642 break;
643 case CHAR_COMPACT_BLANK:
644 m->mask |= STRING_COMPACT_BLANK;
645 break;
646 case CHAR_COMPACT_OPTIONAL_BLANK:
647 m->mask |=
648 STRING_COMPACT_OPTIONAL_BLANK;
649 break;
650 default:
651 if (ms->flags & MAGIC_CHECK)
643 file_magwarn(
644 "string extension %c invalid",
652 file_magwarn(ms,
653 "string extension `%c' invalid",
645 *l);
646 return -1;
647 }
648 }
649 }
650 }
651 /*
652 * We used to set mask to all 1's here, instead let's just not do
653 * anything if mask = 0 (unless you have a better idea)
654 */
655 EATAB;
656
657 switch (*l) {
658 case '>':
659 case '<':
660 /* Old-style anding: "0 byte &0x80 dynamically linked" */
661 case '&':
662 case '^':
663 case '=':
664 m->reln = *l;
665 ++l;
666 if (*l == '=') {
667 /* HP compat: ignore &= etc. */
668 ++l;
669 }
670 break;
671 case '!':
654 *l);
655 return -1;
656 }
657 }
658 }
659 }
660 /*
661 * We used to set mask to all 1's here, instead let's just not do
662 * anything if mask = 0 (unless you have a better idea)
663 */
664 EATAB;
665
666 switch (*l) {
667 case '>':
668 case '<':
669 /* Old-style anding: "0 byte &0x80 dynamically linked" */
670 case '&':
671 case '^':
672 case '=':
673 m->reln = *l;
674 ++l;
675 if (*l == '=') {
676 /* HP compat: ignore &= etc. */
677 ++l;
678 }
679 break;
680 case '!':
672 if (m->type != FILE_STRING && m->type != FILE_PSTRING) {
681 if (!IS_STRING(m->type)) {
673 m->reln = *l;
674 ++l;
675 break;
676 }
677 /*FALLTHROUGH*/
678 default:
679 if (*l == 'x' && isascii((unsigned char)l[1]) &&
680 isspace((unsigned char)l[1])) {
681 m->reln = *l;
682 ++l;
683 goto GetDesc; /* Bill The Cat */
684 }
685 m->reln = '=';
686 break;
687 }
688 EATAB;
689
690 if (getvalue(ms, m, &l))
691 return -1;
692 /*
693 * TODO finish this macro and start using it!
694 * #define offsetcheck {if (offset > HOWMANY-1)
695 * magwarn("offset too big"); }
696 */
697
698 /*
699 * now get last part - the description
700 */
701GetDesc:
702 EATAB;
703 if (l[0] == '\b') {
704 ++l;
705 m->nospflag = 1;
706 } else if ((l[0] == '\\') && (l[1] == 'b')) {
707 ++l;
708 ++l;
709 m->nospflag = 1;
710 } else
711 m->nospflag = 0;
712 while ((m->desc[i++] = *l++) != '\0' && i < MAXDESC)
713 /* NULLBODY */;
714
715 if (ms->flags & MAGIC_CHECK) {
682 m->reln = *l;
683 ++l;
684 break;
685 }
686 /*FALLTHROUGH*/
687 default:
688 if (*l == 'x' && isascii((unsigned char)l[1]) &&
689 isspace((unsigned char)l[1])) {
690 m->reln = *l;
691 ++l;
692 goto GetDesc; /* Bill The Cat */
693 }
694 m->reln = '=';
695 break;
696 }
697 EATAB;
698
699 if (getvalue(ms, m, &l))
700 return -1;
701 /*
702 * TODO finish this macro and start using it!
703 * #define offsetcheck {if (offset > HOWMANY-1)
704 * magwarn("offset too big"); }
705 */
706
707 /*
708 * now get last part - the description
709 */
710GetDesc:
711 EATAB;
712 if (l[0] == '\b') {
713 ++l;
714 m->nospflag = 1;
715 } else if ((l[0] == '\\') && (l[1] == 'b')) {
716 ++l;
717 ++l;
718 m->nospflag = 1;
719 } else
720 m->nospflag = 0;
721 while ((m->desc[i++] = *l++) != '\0' && i < MAXDESC)
722 /* NULLBODY */;
723
724 if (ms->flags & MAGIC_CHECK) {
716 if (!check_format(m))
725 if (!check_format(ms, m))
717 return -1;
718 }
719#ifndef COMPILE_ONLY
720 if (action == FILE_CHECK) {
721 file_mdump(m);
722 }
723#endif
724 ++(*nmagicp); /* make room for next */
725 return 0;
726}
727
728/*
729 * Check that the optional printf format in description matches
730 * the type of the magic.
731 */
732private int
726 return -1;
727 }
728#ifndef COMPILE_ONLY
729 if (action == FILE_CHECK) {
730 file_mdump(m);
731 }
732#endif
733 ++(*nmagicp); /* make room for next */
734 return 0;
735}
736
737/*
738 * Check that the optional printf format in description matches
739 * the type of the magic.
740 */
741private int
733check_format(struct magic *m)
742check_format(struct magic_set *ms, struct magic *m)
734{
735 static const char *formats[] = { FILE_FORMAT_STRING };
736 static const char *names[] = { FILE_FORMAT_NAME };
737 char *ptr;
738
739 for (ptr = m->desc; *ptr; ptr++)
740 if (*ptr == '%')
741 break;
742 if (*ptr == '\0') {
743 /* No format string; ok */
744 return 1;
745 }
746 if (m->type >= sizeof(formats)/sizeof(formats[0])) {
743{
744 static const char *formats[] = { FILE_FORMAT_STRING };
745 static const char *names[] = { FILE_FORMAT_NAME };
746 char *ptr;
747
748 for (ptr = m->desc; *ptr; ptr++)
749 if (*ptr == '%')
750 break;
751 if (*ptr == '\0') {
752 /* No format string; ok */
753 return 1;
754 }
755 if (m->type >= sizeof(formats)/sizeof(formats[0])) {
747 file_magwarn("Internal error inconsistency between m->type"
756 file_magwarn(ms, "Internal error inconsistency between m->type"
748 " and format strings");
749 return 0;
750 }
751 if (formats[m->type] == NULL) {
757 " and format strings");
758 return 0;
759 }
760 if (formats[m->type] == NULL) {
752 file_magwarn("No format string for `%s' with description `%s'",
753 m->desc, names[m->type]);
761 file_magwarn(ms, "No format string for `%s' with description "
762 "`%s'", m->desc, names[m->type]);
754 return 0;
755 }
756 for (; *ptr; ptr++) {
757 if (*ptr == 'l' || *ptr == 'h') {
758 /* XXX: we should really fix this one day */
759 continue;
760 }
761 if (islower((unsigned char)*ptr) || *ptr == 'X')
762 break;
763 }
764 if (*ptr == '\0') {
765 /* Missing format string; bad */
763 return 0;
764 }
765 for (; *ptr; ptr++) {
766 if (*ptr == 'l' || *ptr == 'h') {
767 /* XXX: we should really fix this one day */
768 continue;
769 }
770 if (islower((unsigned char)*ptr) || *ptr == 'X')
771 break;
772 }
773 if (*ptr == '\0') {
774 /* Missing format string; bad */
766 file_magwarn("Invalid format `%s' for type `%s'",
775 file_magwarn(ms, "Invalid format `%s' for type `%s'",
767 m->desc, names[m->type]);
768 return 0;
769 }
770 if (strchr(formats[m->type], *ptr) == NULL) {
776 m->desc, names[m->type]);
777 return 0;
778 }
779 if (strchr(formats[m->type], *ptr) == NULL) {
771 file_magwarn("Printf format `%c' is not valid for type `%s'"
780 file_magwarn(ms, "Printf format `%c' is not valid for type `%s'"
772 " in description `%s'",
773 *ptr, names[m->type], m->desc);
774 return 0;
775 }
776 return 1;
777}
778
779/*
780 * Read a numeric value from a pointer, into the value union of a magic
781 * pointer, according to the magic type. Update the string pointer to point
782 * just after the number read. Return 0 for success, non-zero for failure.
783 */
784private int
785getvalue(struct magic_set *ms, struct magic *m, char **p)
786{
787 int slen;
788
789 switch (m->type) {
781 " in description `%s'",
782 *ptr, names[m->type], m->desc);
783 return 0;
784 }
785 return 1;
786}
787
788/*
789 * Read a numeric value from a pointer, into the value union of a magic
790 * pointer, according to the magic type. Update the string pointer to point
791 * just after the number read. Return 0 for success, non-zero for failure.
792 */
793private int
794getvalue(struct magic_set *ms, struct magic *m, char **p)
795{
796 int slen;
797
798 switch (m->type) {
799 case FILE_BESTRING16:
800 case FILE_LESTRING16:
790 case FILE_STRING:
791 case FILE_PSTRING:
792 case FILE_REGEX:
793 *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen);
794 if (*p == NULL) {
795 if (ms->flags & MAGIC_CHECK)
801 case FILE_STRING:
802 case FILE_PSTRING:
803 case FILE_REGEX:
804 *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen);
805 if (*p == NULL) {
806 if (ms->flags & MAGIC_CHECK)
796 file_magwarn("cannot get string from `%s'",
807 file_magwarn(ms, "cannot get string from `%s'",
797 m->value.s);
798 return -1;
799 }
800 m->vallen = slen;
801 return 0;
802 default:
803 if (m->reln != 'x') {
804 m->value.l = file_signextend(ms, m,
805 (uint32_t)strtoul(*p, p, 0));
806 eatsize(p);
807 }
808 return 0;
809 }
810}
811
812/*
813 * Convert a string containing C character escapes. Stop at an unescaped
814 * space or tab.
815 * Copy the converted version to "p", returning its length in *slen.
816 * Return updated scan pointer as function result.
817 */
818private char *
819getstr(struct magic_set *ms, char *s, char *p, int plen, int *slen)
820{
821 char *origs = s, *origp = p;
822 char *pmax = p + plen - 1;
823 int c;
824 int val;
825
826 while ((c = *s++) != '\0') {
827 if (isspace((unsigned char) c))
828 break;
829 if (p >= pmax) {
830 file_error(ms, 0, "string too long: `%s'", origs);
831 return NULL;
832 }
833 if(c == '\\') {
834 switch(c = *s++) {
835
836 case '\0':
837 goto out;
838
839 default:
840 *p++ = (char) c;
841 break;
842
843 case 'n':
844 *p++ = '\n';
845 break;
846
847 case 'r':
848 *p++ = '\r';
849 break;
850
851 case 'b':
852 *p++ = '\b';
853 break;
854
855 case 't':
856 *p++ = '\t';
857 break;
858
859 case 'f':
860 *p++ = '\f';
861 break;
862
863 case 'v':
864 *p++ = '\v';
865 break;
866
867 /* \ and up to 3 octal digits */
868 case '0':
869 case '1':
870 case '2':
871 case '3':
872 case '4':
873 case '5':
874 case '6':
875 case '7':
876 val = c - '0';
877 c = *s++; /* try for 2 */
878 if(c >= '0' && c <= '7') {
879 val = (val<<3) | (c - '0');
880 c = *s++; /* try for 3 */
881 if(c >= '0' && c <= '7')
882 val = (val<<3) | (c-'0');
883 else
884 --s;
885 }
886 else
887 --s;
888 *p++ = (char)val;
889 break;
890
891 /* \x and up to 2 hex digits */
892 case 'x':
893 val = 'x'; /* Default if no digits */
894 c = hextoint(*s++); /* Get next char */
895 if (c >= 0) {
896 val = c;
897 c = hextoint(*s++);
898 if (c >= 0)
899 val = (val << 4) + c;
900 else
901 --s;
902 } else
903 --s;
904 *p++ = (char)val;
905 break;
906 }
907 } else
908 *p++ = (char)c;
909 }
910out:
911 *p = '\0';
912 *slen = p - origp;
913 return s;
914}
915
916
917/* Single hex char to int; -1 if not a hex char. */
918private int
919hextoint(int c)
920{
921 if (!isascii((unsigned char) c))
922 return -1;
923 if (isdigit((unsigned char) c))
924 return c - '0';
925 if ((c >= 'a')&&(c <= 'f'))
926 return c + 10 - 'a';
927 if (( c>= 'A')&&(c <= 'F'))
928 return c + 10 - 'A';
929 return -1;
930}
931
932
933/*
934 * Print a string containing C character escapes.
935 */
936protected void
937file_showstr(FILE *fp, const char *s, size_t len)
938{
939 char c;
940
941 for (;;) {
942 c = *s++;
943 if (len == ~0U) {
944 if (c == '\0')
945 break;
946 }
947 else {
948 if (len-- == 0)
949 break;
950 }
951 if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
952 (void) fputc(c, fp);
953 else {
954 (void) fputc('\\', fp);
955 switch (c) {
956
957 case '\n':
958 (void) fputc('n', fp);
959 break;
960
961 case '\r':
962 (void) fputc('r', fp);
963 break;
964
965 case '\b':
966 (void) fputc('b', fp);
967 break;
968
969 case '\t':
970 (void) fputc('t', fp);
971 break;
972
973 case '\f':
974 (void) fputc('f', fp);
975 break;
976
977 case '\v':
978 (void) fputc('v', fp);
979 break;
980
981 default:
982 (void) fprintf(fp, "%.3o", c & 0377);
983 break;
984 }
985 }
986 }
987}
988
989/*
990 * eatsize(): Eat the size spec from a number [eg. 10UL]
991 */
992private void
993eatsize(char **p)
994{
995 char *l = *p;
996
997 if (LOWCASE(*l) == 'u')
998 l++;
999
1000 switch (LOWCASE(*l)) {
1001 case 'l': /* long */
1002 case 's': /* short */
1003 case 'h': /* short */
1004 case 'b': /* char/byte */
1005 case 'c': /* char/byte */
1006 l++;
1007 /*FALLTHROUGH*/
1008 default:
1009 break;
1010 }
1011
1012 *p = l;
1013}
1014
1015/*
1016 * handle a compiled file.
1017 */
1018private int
1019apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1020 const char *fn)
1021{
1022 int fd;
1023 struct stat st;
1024 uint32_t *ptr;
1025 uint32_t version;
1026 int needsbyteswap;
1027 char buf[MAXPATHLEN];
808 m->value.s);
809 return -1;
810 }
811 m->vallen = slen;
812 return 0;
813 default:
814 if (m->reln != 'x') {
815 m->value.l = file_signextend(ms, m,
816 (uint32_t)strtoul(*p, p, 0));
817 eatsize(p);
818 }
819 return 0;
820 }
821}
822
823/*
824 * Convert a string containing C character escapes. Stop at an unescaped
825 * space or tab.
826 * Copy the converted version to "p", returning its length in *slen.
827 * Return updated scan pointer as function result.
828 */
829private char *
830getstr(struct magic_set *ms, char *s, char *p, int plen, int *slen)
831{
832 char *origs = s, *origp = p;
833 char *pmax = p + plen - 1;
834 int c;
835 int val;
836
837 while ((c = *s++) != '\0') {
838 if (isspace((unsigned char) c))
839 break;
840 if (p >= pmax) {
841 file_error(ms, 0, "string too long: `%s'", origs);
842 return NULL;
843 }
844 if(c == '\\') {
845 switch(c = *s++) {
846
847 case '\0':
848 goto out;
849
850 default:
851 *p++ = (char) c;
852 break;
853
854 case 'n':
855 *p++ = '\n';
856 break;
857
858 case 'r':
859 *p++ = '\r';
860 break;
861
862 case 'b':
863 *p++ = '\b';
864 break;
865
866 case 't':
867 *p++ = '\t';
868 break;
869
870 case 'f':
871 *p++ = '\f';
872 break;
873
874 case 'v':
875 *p++ = '\v';
876 break;
877
878 /* \ and up to 3 octal digits */
879 case '0':
880 case '1':
881 case '2':
882 case '3':
883 case '4':
884 case '5':
885 case '6':
886 case '7':
887 val = c - '0';
888 c = *s++; /* try for 2 */
889 if(c >= '0' && c <= '7') {
890 val = (val<<3) | (c - '0');
891 c = *s++; /* try for 3 */
892 if(c >= '0' && c <= '7')
893 val = (val<<3) | (c-'0');
894 else
895 --s;
896 }
897 else
898 --s;
899 *p++ = (char)val;
900 break;
901
902 /* \x and up to 2 hex digits */
903 case 'x':
904 val = 'x'; /* Default if no digits */
905 c = hextoint(*s++); /* Get next char */
906 if (c >= 0) {
907 val = c;
908 c = hextoint(*s++);
909 if (c >= 0)
910 val = (val << 4) + c;
911 else
912 --s;
913 } else
914 --s;
915 *p++ = (char)val;
916 break;
917 }
918 } else
919 *p++ = (char)c;
920 }
921out:
922 *p = '\0';
923 *slen = p - origp;
924 return s;
925}
926
927
928/* Single hex char to int; -1 if not a hex char. */
929private int
930hextoint(int c)
931{
932 if (!isascii((unsigned char) c))
933 return -1;
934 if (isdigit((unsigned char) c))
935 return c - '0';
936 if ((c >= 'a')&&(c <= 'f'))
937 return c + 10 - 'a';
938 if (( c>= 'A')&&(c <= 'F'))
939 return c + 10 - 'A';
940 return -1;
941}
942
943
944/*
945 * Print a string containing C character escapes.
946 */
947protected void
948file_showstr(FILE *fp, const char *s, size_t len)
949{
950 char c;
951
952 for (;;) {
953 c = *s++;
954 if (len == ~0U) {
955 if (c == '\0')
956 break;
957 }
958 else {
959 if (len-- == 0)
960 break;
961 }
962 if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
963 (void) fputc(c, fp);
964 else {
965 (void) fputc('\\', fp);
966 switch (c) {
967
968 case '\n':
969 (void) fputc('n', fp);
970 break;
971
972 case '\r':
973 (void) fputc('r', fp);
974 break;
975
976 case '\b':
977 (void) fputc('b', fp);
978 break;
979
980 case '\t':
981 (void) fputc('t', fp);
982 break;
983
984 case '\f':
985 (void) fputc('f', fp);
986 break;
987
988 case '\v':
989 (void) fputc('v', fp);
990 break;
991
992 default:
993 (void) fprintf(fp, "%.3o", c & 0377);
994 break;
995 }
996 }
997 }
998}
999
1000/*
1001 * eatsize(): Eat the size spec from a number [eg. 10UL]
1002 */
1003private void
1004eatsize(char **p)
1005{
1006 char *l = *p;
1007
1008 if (LOWCASE(*l) == 'u')
1009 l++;
1010
1011 switch (LOWCASE(*l)) {
1012 case 'l': /* long */
1013 case 's': /* short */
1014 case 'h': /* short */
1015 case 'b': /* char/byte */
1016 case 'c': /* char/byte */
1017 l++;
1018 /*FALLTHROUGH*/
1019 default:
1020 break;
1021 }
1022
1023 *p = l;
1024}
1025
1026/*
1027 * handle a compiled file.
1028 */
1029private int
1030apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1031 const char *fn)
1032{
1033 int fd;
1034 struct stat st;
1035 uint32_t *ptr;
1036 uint32_t version;
1037 int needsbyteswap;
1038 char buf[MAXPATHLEN];
1028 char *dbname = mkdbname(fn, buf, sizeof(buf));
1039 char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
1029 void *mm = NULL;
1030
1031 if (dbname == NULL)
1032 return -1;
1033
1034 if ((fd = open(dbname, O_RDONLY)) == -1)
1035 return -1;
1036
1037 if (fstat(fd, &st) == -1) {
1038 file_error(ms, errno, "cannot stat `%s'", dbname);
1039 goto error;
1040 }
1041 if (st.st_size < 16) {
1042 file_error(ms, 0, "file `%s' is too small", dbname);
1043 goto error;
1044 }
1045
1046#ifdef QUICK
1047 if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
1048 MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
1049 file_error(ms, errno, "cannot map `%s'", dbname);
1050 goto error;
1051 }
1052#define RET 2
1053#else
1054 if ((mm = malloc((size_t)st.st_size)) == NULL) {
1055 file_oomem(ms);
1056 goto error;
1057 }
1058 if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
1059 file_badread(ms);
1060 goto error;
1061 }
1062#define RET 1
1063#endif
1064 *magicp = mm;
1065 (void)close(fd);
1066 fd = -1;
1067 ptr = (uint32_t *)(void *)*magicp;
1068 if (*ptr != MAGICNO) {
1069 if (swap4(*ptr) != MAGICNO) {
1070 file_error(ms, 0, "bad magic in `%s'");
1071 goto error;
1072 }
1073 needsbyteswap = 1;
1074 } else
1075 needsbyteswap = 0;
1076 if (needsbyteswap)
1077 version = swap4(ptr[1]);
1078 else
1079 version = ptr[1];
1080 if (version != VERSIONNO) {
1081 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
1082 version, VERSIONNO, dbname);
1083 goto error;
1084 }
1085 *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
1086 (*magicp)++;
1087 if (needsbyteswap)
1088 byteswap(*magicp, *nmagicp);
1089 return RET;
1090
1091error:
1092 if (fd != -1)
1093 (void)close(fd);
1094 if (mm) {
1095#ifdef QUICK
1096 (void)munmap((void *)mm, (size_t)st.st_size);
1097#else
1098 free(mm);
1099#endif
1100 } else {
1101 *magicp = NULL;
1102 *nmagicp = 0;
1103 }
1104 return -1;
1105}
1106
1107private const uint32_t ar[] = {
1108 MAGICNO, VERSIONNO
1109};
1110/*
1111 * handle an mmaped file.
1112 */
1113private int
1114apprentice_compile(struct magic_set *ms, struct magic **magicp,
1115 uint32_t *nmagicp, const char *fn)
1116{
1117 int fd;
1118 char buf[MAXPATHLEN];
1040 void *mm = NULL;
1041
1042 if (dbname == NULL)
1043 return -1;
1044
1045 if ((fd = open(dbname, O_RDONLY)) == -1)
1046 return -1;
1047
1048 if (fstat(fd, &st) == -1) {
1049 file_error(ms, errno, "cannot stat `%s'", dbname);
1050 goto error;
1051 }
1052 if (st.st_size < 16) {
1053 file_error(ms, 0, "file `%s' is too small", dbname);
1054 goto error;
1055 }
1056
1057#ifdef QUICK
1058 if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
1059 MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
1060 file_error(ms, errno, "cannot map `%s'", dbname);
1061 goto error;
1062 }
1063#define RET 2
1064#else
1065 if ((mm = malloc((size_t)st.st_size)) == NULL) {
1066 file_oomem(ms);
1067 goto error;
1068 }
1069 if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
1070 file_badread(ms);
1071 goto error;
1072 }
1073#define RET 1
1074#endif
1075 *magicp = mm;
1076 (void)close(fd);
1077 fd = -1;
1078 ptr = (uint32_t *)(void *)*magicp;
1079 if (*ptr != MAGICNO) {
1080 if (swap4(*ptr) != MAGICNO) {
1081 file_error(ms, 0, "bad magic in `%s'");
1082 goto error;
1083 }
1084 needsbyteswap = 1;
1085 } else
1086 needsbyteswap = 0;
1087 if (needsbyteswap)
1088 version = swap4(ptr[1]);
1089 else
1090 version = ptr[1];
1091 if (version != VERSIONNO) {
1092 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
1093 version, VERSIONNO, dbname);
1094 goto error;
1095 }
1096 *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
1097 (*magicp)++;
1098 if (needsbyteswap)
1099 byteswap(*magicp, *nmagicp);
1100 return RET;
1101
1102error:
1103 if (fd != -1)
1104 (void)close(fd);
1105 if (mm) {
1106#ifdef QUICK
1107 (void)munmap((void *)mm, (size_t)st.st_size);
1108#else
1109 free(mm);
1110#endif
1111 } else {
1112 *magicp = NULL;
1113 *nmagicp = 0;
1114 }
1115 return -1;
1116}
1117
1118private const uint32_t ar[] = {
1119 MAGICNO, VERSIONNO
1120};
1121/*
1122 * handle an mmaped file.
1123 */
1124private int
1125apprentice_compile(struct magic_set *ms, struct magic **magicp,
1126 uint32_t *nmagicp, const char *fn)
1127{
1128 int fd;
1129 char buf[MAXPATHLEN];
1119 char *dbname = mkdbname(fn, buf, sizeof(buf));
1130 char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
1120
1121 if (dbname == NULL)
1122 return -1;
1123
1124 if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
1125 file_error(ms, errno, "cannot open `%s'", dbname);
1126 return -1;
1127 }
1128
1129 if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
1130 file_error(ms, errno, "error writing `%s'", dbname);
1131 return -1;
1132 }
1133
1134 if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
1135 != sizeof(struct magic)) {
1136 file_error(ms, errno, "error seeking `%s'", dbname);
1137 return -1;
1138 }
1139
1140 if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
1141 != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
1142 file_error(ms, errno, "error writing `%s'", dbname);
1143 return -1;
1144 }
1145
1146 (void)close(fd);
1147 return 0;
1148}
1149
1150private const char ext[] = ".mgc";
1151/*
1152 * make a dbname
1153 */
1154private char *
1131
1132 if (dbname == NULL)
1133 return -1;
1134
1135 if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
1136 file_error(ms, errno, "cannot open `%s'", dbname);
1137 return -1;
1138 }
1139
1140 if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
1141 file_error(ms, errno, "error writing `%s'", dbname);
1142 return -1;
1143 }
1144
1145 if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
1146 != sizeof(struct magic)) {
1147 file_error(ms, errno, "error seeking `%s'", dbname);
1148 return -1;
1149 }
1150
1151 if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
1152 != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
1153 file_error(ms, errno, "error writing `%s'", dbname);
1154 return -1;
1155 }
1156
1157 (void)close(fd);
1158 return 0;
1159}
1160
1161private const char ext[] = ".mgc";
1162/*
1163 * make a dbname
1164 */
1165private char *
1155mkdbname(const char *fn, char *buf, size_t bufsiz)
1166mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
1156{
1167{
1157#ifdef notdef
1158 const char *p;
1159 if ((p = strrchr(fn, '/')) != NULL)
1160 fn = ++p;
1161#endif
1168 if (strip) {
1169 const char *p;
1170 if ((p = strrchr(fn, '/')) != NULL)
1171 fn = ++p;
1172 }
1173
1162 (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
1163 return buf;
1164}
1165
1166/*
1167 * Byteswap an mmap'ed file if needed
1168 */
1169private void
1170byteswap(struct magic *magic, uint32_t nmagic)
1171{
1172 uint32_t i;
1173 for (i = 0; i < nmagic; i++)
1174 bs1(&magic[i]);
1175}
1176
1177/*
1178 * swap a short
1179 */
1180private uint16_t
1181swap2(uint16_t sv)
1182{
1183 uint16_t rv;
1184 uint8_t *s = (uint8_t *)(void *)&sv;
1185 uint8_t *d = (uint8_t *)(void *)&rv;
1186 d[0] = s[1];
1187 d[1] = s[0];
1188 return rv;
1189}
1190
1191/*
1192 * swap an int
1193 */
1194private uint32_t
1195swap4(uint32_t sv)
1196{
1197 uint32_t rv;
1198 uint8_t *s = (uint8_t *)(void *)&sv;
1199 uint8_t *d = (uint8_t *)(void *)&rv;
1200 d[0] = s[3];
1201 d[1] = s[2];
1202 d[2] = s[1];
1203 d[3] = s[0];
1204 return rv;
1205}
1206
1207/*
1208 * byteswap a single magic entry
1209 */
1210private void
1211bs1(struct magic *m)
1212{
1213 m->cont_level = swap2(m->cont_level);
1214 m->offset = swap4((uint32_t)m->offset);
1215 m->in_offset = swap4((uint32_t)m->in_offset);
1174 (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
1175 return buf;
1176}
1177
1178/*
1179 * Byteswap an mmap'ed file if needed
1180 */
1181private void
1182byteswap(struct magic *magic, uint32_t nmagic)
1183{
1184 uint32_t i;
1185 for (i = 0; i < nmagic; i++)
1186 bs1(&magic[i]);
1187}
1188
1189/*
1190 * swap a short
1191 */
1192private uint16_t
1193swap2(uint16_t sv)
1194{
1195 uint16_t rv;
1196 uint8_t *s = (uint8_t *)(void *)&sv;
1197 uint8_t *d = (uint8_t *)(void *)&rv;
1198 d[0] = s[1];
1199 d[1] = s[0];
1200 return rv;
1201}
1202
1203/*
1204 * swap an int
1205 */
1206private uint32_t
1207swap4(uint32_t sv)
1208{
1209 uint32_t rv;
1210 uint8_t *s = (uint8_t *)(void *)&sv;
1211 uint8_t *d = (uint8_t *)(void *)&rv;
1212 d[0] = s[3];
1213 d[1] = s[2];
1214 d[2] = s[1];
1215 d[3] = s[0];
1216 return rv;
1217}
1218
1219/*
1220 * byteswap a single magic entry
1221 */
1222private void
1223bs1(struct magic *m)
1224{
1225 m->cont_level = swap2(m->cont_level);
1226 m->offset = swap4((uint32_t)m->offset);
1227 m->in_offset = swap4((uint32_t)m->in_offset);
1216 if (m->type != FILE_STRING)
1228 if (IS_STRING(m->type))
1217 m->value.l = swap4(m->value.l);
1218 m->mask = swap4(m->mask);
1219}
1229 m->value.l = swap4(m->value.l);
1230 m->mask = swap4(m->mask);
1231}