file_cmds-60.tar.gz
[apple/file_cmds.git] / file / softmagic.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /* $OpenBSD: softmagic.c,v 1.3 1997/02/09 23:58:36 millert Exp $ */
25
26 /*
27 * softmagic - interpret variable magic from /etc/magic
28 *
29 * Copyright (c) Ian F. Darwin, 1987.
30 * Written by Ian F. Darwin.
31 *
32 * This software is not subject to any license of the American Telephone
33 * and Telegraph Company or of the Regents of the University of California.
34 *
35 * Permission is granted to anyone to use this software for any purpose on
36 * any computer system, and to alter it and redistribute it freely, subject
37 * to the following restrictions:
38 *
39 * 1. The author is not responsible for the consequences of use of this
40 * software, no matter how awful, even if they arise from flaws in it.
41 *
42 * 2. The origin of this software must not be misrepresented, either by
43 * explicit claim or by omission. Since few users ever read sources,
44 * credits must appear in the documentation.
45 *
46 * 3. Altered versions must be plainly marked as such, and must not be
47 * misrepresented as being the original software. Since few users
48 * ever read sources, credits must appear in the documentation.
49 *
50 * 4. This notice may not be removed or altered.
51 */
52
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <time.h>
57 #include <sys/types.h>
58
59 #include "file.h"
60
61 #ifndef lint
62 #if 0
63 static char *moduleid = "$OpenBSD: softmagic.c,v 1.3 1997/02/09 23:58:36 millert Exp $";
64 #endif
65 #endif /* lint */
66
67 static int match __P((unsigned char *, int));
68 static int mget __P((union VALUETYPE *,
69 unsigned char *, struct magic *, int));
70 static int mcheck __P((union VALUETYPE *, struct magic *));
71 static int32 mprint __P((union VALUETYPE *, struct magic *));
72 static void mdebug __P((int32, char *, int));
73 static int mconvert __P((union VALUETYPE *, struct magic *));
74
75 /*
76 * softmagic - lookup one file in database
77 * (already read from /etc/magic by apprentice.c).
78 * Passed the name and FILE * of one file to be typed.
79 */
80 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
81 int
82 softmagic(buf, nbytes)
83 unsigned char *buf;
84 int nbytes;
85 {
86 if (match(buf, nbytes))
87 return 1;
88
89 return 0;
90 }
91
92 /*
93 * Go through the whole list, stopping if you find a match. Process all
94 * the continuations of that match before returning.
95 *
96 * We support multi-level continuations:
97 *
98 * At any time when processing a successful top-level match, there is a
99 * current continuation level; it represents the level of the last
100 * successfully matched continuation.
101 *
102 * Continuations above that level are skipped as, if we see one, it
103 * means that the continuation that controls them - i.e, the
104 * lower-level continuation preceding them - failed to match.
105 *
106 * Continuations below that level are processed as, if we see one,
107 * it means we've finished processing or skipping higher-level
108 * continuations under the control of a successful or unsuccessful
109 * lower-level continuation, and are now seeing the next lower-level
110 * continuation and should process it. The current continuation
111 * level reverts to the level of the one we're seeing.
112 *
113 * Continuations at the current level are processed as, if we see
114 * one, there's no lower-level continuation that may have failed.
115 *
116 * If a continuation matches, we bump the current continuation level
117 * so that higher-level continuations are processed.
118 */
119 static int
120 match(s, nbytes)
121 unsigned char *s;
122 int nbytes;
123 {
124 int magindex = 0;
125 int cont_level = 0;
126 int need_separator = 0;
127 union VALUETYPE p;
128 static int32 *tmpoff = NULL;
129 static size_t tmplen = 0;
130 int32 oldoff = 0;
131
132 if (tmpoff == NULL)
133 if ((tmpoff = (int32 *) malloc(tmplen = 20)) == NULL)
134 error("out of memory\n");
135
136 for (magindex = 0; magindex < nmagic; magindex++) {
137 /* if main entry matches, print it... */
138 if (!mget(&p, s, &magic[magindex], nbytes) ||
139 !mcheck(&p, &magic[magindex])) {
140 /*
141 * main entry didn't match,
142 * flush its continuations
143 */
144 while (magindex < nmagic &&
145 magic[magindex + 1].cont_level != 0)
146 magindex++;
147 continue;
148 }
149
150 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
151 /*
152 * If we printed something, we'll need to print
153 * a blank before we print something else.
154 */
155 if (magic[magindex].desc[0])
156 need_separator = 1;
157 /* and any continuations that match */
158 if (++cont_level >= tmplen)
159 if ((tmpoff = (int32 *) realloc(tmpoff,
160 tmplen += 20)) == NULL)
161 error("out of memory\n");
162 while (magic[magindex+1].cont_level != 0 &&
163 ++magindex < nmagic) {
164 if (cont_level >= magic[magindex].cont_level) {
165 if (cont_level > magic[magindex].cont_level) {
166 /*
167 * We're at the end of the level
168 * "cont_level" continuations.
169 */
170 cont_level = magic[magindex].cont_level;
171 }
172 if (magic[magindex].flag & ADD) {
173 oldoff=magic[magindex].offset;
174 magic[magindex].offset += tmpoff[cont_level-1];
175 }
176 if (mget(&p, s, &magic[magindex], nbytes) &&
177 mcheck(&p, &magic[magindex])) {
178 /*
179 * This continuation matched.
180 * Print its message, with
181 * a blank before it if
182 * the previous item printed
183 * and this item isn't empty.
184 */
185 /* space if previous printed */
186 if (need_separator
187 && (magic[magindex].nospflag == 0)
188 && (magic[magindex].desc[0] != '\0')
189 ) {
190 (void) putchar(' ');
191 need_separator = 0;
192 }
193 tmpoff[cont_level] = mprint(&p, &magic[magindex]);
194 if (magic[magindex].desc[0])
195 need_separator = 1;
196
197 /*
198 * If we see any continuations
199 * at a higher level,
200 * process them.
201 */
202 if (++cont_level >= tmplen)
203 if ((tmpoff =
204 (int32 *) realloc(tmpoff,
205 tmplen += 20)) == NULL)
206 error("out of memory\n");
207 }
208 if (magic[magindex].flag & ADD) {
209 magic[magindex].offset = oldoff;
210 }
211 }
212 }
213 return 1; /* all through */
214 }
215 return 0; /* no match at all */
216 }
217
218 static int32
219 mprint(p, m)
220 union VALUETYPE *p;
221 struct magic *m;
222 {
223 char *pp, *rt;
224 uint32 v;
225 int32 t=0 ;
226
227
228 switch (m->type) {
229 case BYTE:
230 v = p->b;
231 v = signextend(m, v) & m->mask;
232 (void) printf(m->desc, (unsigned char) v);
233 t = m->offset + sizeof(char);
234 break;
235
236 case SHORT:
237 case BESHORT:
238 case LESHORT:
239 v = p->h;
240 v = signextend(m, v) & m->mask;
241 (void) printf(m->desc, (unsigned short) v);
242 t = m->offset + sizeof(short);
243 break;
244
245 case LONG:
246 case BELONG:
247 case LELONG:
248 v = p->l;
249 v = signextend(m, v) & m->mask;
250 (void) printf(m->desc, (uint32) v);
251 t = m->offset + sizeof(int32);
252 break;
253
254 case STRING:
255 if (m->reln == '=') {
256 (void) printf(m->desc, m->value.s);
257 t = m->offset + strlen(m->value.s);
258 }
259 else {
260 if (*m->value.s == '\0') {
261 char *cp = strchr(p->s,'\n');
262 if (cp)
263 *cp = '\0';
264 }
265 (void) printf(m->desc, p->s);
266 t = m->offset + strlen(p->s);
267 }
268 break;
269
270 case DATE:
271 case BEDATE:
272 case LEDATE:
273 pp = ctime((time_t*) &p->l);
274 if ((rt = strchr(pp, '\n')) != NULL)
275 *rt = '\0';
276 (void) printf(m->desc, pp);
277 t = m->offset + sizeof(time_t);
278 break;
279
280 default:
281 error("invalid m->type (%d) in mprint().\n", m->type);
282 /*NOTREACHED*/
283 }
284 return(t);
285 }
286
287 /*
288 * Convert the byte order of the data we are looking at
289 */
290 static int
291 mconvert(p, m)
292 union VALUETYPE *p;
293 struct magic *m;
294 {
295 switch (m->type) {
296 case BYTE:
297 case SHORT:
298 case LONG:
299 case DATE:
300 return 1;
301 case STRING:
302 {
303 char *ptr;
304
305 /* Null terminate and eat the return */
306 p->s[sizeof(p->s) - 1] = '\0';
307 if ((ptr = strchr(p->s, '\n')) != NULL)
308 *ptr = '\0';
309 return 1;
310 }
311 case BESHORT:
312 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
313 return 1;
314 case BELONG:
315 case BEDATE:
316 p->l = (int32)
317 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
318 return 1;
319 case LESHORT:
320 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
321 return 1;
322 case LELONG:
323 case LEDATE:
324 p->l = (int32)
325 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
326 return 1;
327 default:
328 error("invalid type %d in mconvert().\n", m->type);
329 return 0;
330 }
331 }
332
333
334 static void
335 mdebug(offset, str, len)
336 int32 offset;
337 char *str;
338 int len;
339 {
340 (void) fprintf(stderr, "mget @%d: ", offset);
341 showstr(stderr, (char *) str, len);
342 (void) fputc('\n', stderr);
343 (void) fputc('\n', stderr);
344 }
345
346 static int
347 mget(p, s, m, nbytes)
348 union VALUETYPE* p;
349 unsigned char *s;
350 struct magic *m;
351 int nbytes;
352 {
353 int32 offset = m->offset;
354
355 if (offset + sizeof(union VALUETYPE) <= nbytes)
356 memcpy(p, s + offset, sizeof(union VALUETYPE));
357 else {
358 /*
359 * the usefulness of padding with zeroes eludes me, it
360 * might even cause problems
361 */
362 int32 have = nbytes - offset;
363 memset(p, 0, sizeof(union VALUETYPE));
364 if (have > 0)
365 memcpy(p, s + offset, have);
366 }
367
368
369 if (debug) {
370 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
371 mdump(m);
372 }
373
374 if (!mconvert(p, m))
375 return 0;
376
377 if (m->flag & INDIR) {
378
379 switch (m->in.type) {
380 case BYTE:
381 offset = p->b + m->in.offset;
382 break;
383 case SHORT:
384 offset = p->h + m->in.offset;
385 break;
386 case LONG:
387 offset = p->l + m->in.offset;
388 break;
389 }
390
391 if (offset + sizeof(union VALUETYPE) > nbytes)
392 return 0;
393
394 memcpy(p, s + offset, sizeof(union VALUETYPE));
395
396 if (debug) {
397 mdebug(offset, (char *) p, sizeof(union VALUETYPE));
398 mdump(m);
399 }
400
401 if (!mconvert(p, m))
402 return 0;
403 }
404 return 1;
405 }
406
407 static int
408 mcheck(p, m)
409 union VALUETYPE* p;
410 struct magic *m;
411 {
412 register uint32 l = m->value.l;
413 register uint32 v;
414 int matched;
415
416 if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
417 fprintf(stderr, "BOINK");
418 return 1;
419 }
420
421
422 switch (m->type) {
423 case BYTE:
424 v = p->b;
425 break;
426
427 case SHORT:
428 case BESHORT:
429 case LESHORT:
430 v = p->h;
431 break;
432
433 case LONG:
434 case BELONG:
435 case LELONG:
436 case DATE:
437 case BEDATE:
438 case LEDATE:
439 v = p->l;
440 break;
441
442 case STRING:
443 l = 0;
444 /* What we want here is:
445 * v = strncmp(m->value.s, p->s, m->vallen);
446 * but ignoring any nulls. bcmp doesn't give -/+/0
447 * and isn't universally available anyway.
448 */
449 v = 0;
450 {
451 register unsigned char *a = (unsigned char*)m->value.s;
452 register unsigned char *b = (unsigned char*)p->s;
453 register int len = m->vallen;
454
455 while (--len >= 0)
456 if ((v = *b++ - *a++) != '\0')
457 break;
458 }
459 break;
460 default:
461 error("invalid type %d in mcheck().\n", m->type);
462 return 0;/*NOTREACHED*/
463 }
464
465 v = signextend(m, v) & m->mask;
466
467 switch (m->reln) {
468 case 'x':
469 if (debug)
470 (void) fprintf(stderr, "%u == *any* = 1\n", v);
471 matched = 1;
472 break;
473
474 case '!':
475 matched = v != l;
476 if (debug)
477 (void) fprintf(stderr, "%u != %u = %d\n",
478 v, l, matched);
479 break;
480
481 case '=':
482 matched = v == l;
483 if (debug)
484 (void) fprintf(stderr, "%u == %u = %d\n",
485 v, l, matched);
486 break;
487
488 case '>':
489 if (m->flag & UNSIGNED) {
490 matched = v > l;
491 if (debug)
492 (void) fprintf(stderr, "%u > %u = %d\n",
493 v, l, matched);
494 }
495 else {
496 matched = (int32) v > (int32) l;
497 if (debug)
498 (void) fprintf(stderr, "%d > %d = %d\n",
499 v, l, matched);
500 }
501 break;
502
503 case '<':
504 if (m->flag & UNSIGNED) {
505 matched = v < l;
506 if (debug)
507 (void) fprintf(stderr, "%u < %u = %d\n",
508 v, l, matched);
509 }
510 else {
511 matched = (int32) v < (int32) l;
512 if (debug)
513 (void) fprintf(stderr, "%d < %d = %d\n",
514 v, l, matched);
515 }
516 break;
517
518 case '&':
519 matched = (v & l) == l;
520 if (debug)
521 (void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
522 v, l, l, matched);
523 break;
524
525 case '^':
526 matched = (v & l) != l;
527 if (debug)
528 (void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
529 v, l, l, matched);
530 break;
531
532 default:
533 matched = 0;
534 error("mcheck: can't happen: invalid relation %d.\n", m->reln);
535 break;/*NOTREACHED*/
536 }
537
538 return matched;
539 }