xref: /netbsd-src/external/gpl2/mkhybrid/dist/libfile/softmagic.c (revision 7804f23efd64308ff6bfc74397b5a25728376f71)
1 /* @(#)softmagic.c	1.12 09/07/11 joerg */
2 #ifndef lint
3 static	const char sccsid[] =
4 	"@(#)softmagic.c	1.12 09/07/11 joerg";
5 #endif
6 /*
7 **	find file types by using a modified "magic" file
8 **
9 **	based on file v3.22 by Ian F. Darwin (see below)
10 **
11 **	Modified for mkhybrid James Pearson 19/5/98
12 */
13 
14 /*
15  * softmagic - interpret variable magic from /etc/magic
16  *
17  * Copyright (c) Ian F. Darwin, 1987.
18  * Written by Ian F. Darwin.
19  *
20  * This software is not subject to any export provision of the United States
21  * Department of Commerce, and may be exported to any country or planet.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice immediately at the beginning of the file, without modification,
28  *    this list of conditions, and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above copyright
30  *    notice, this list of conditions and the following disclaimer in the
31  *    documentation and/or other materials provided with the distribution.
32  *
33  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
37  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  */
45 
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 
50 #include "file.h"
51 
52 #ifndef	lint
53 static const char moduleid[] =
54 	"@(#)Id: softmagic.c,v 1.34 1997/01/15 19:28:35 christos Exp";
55 #endif	/* lint */
56 
57 #ifdef DEBUG
58 int	debug = 1; 	/* debugging 				*/
59 #else
60 #define	debug	0 	/* debugging 				*/
61 #endif /* DEBUG */
62 
63 static char *match	(unsigned char *, int);
64 static int mget		(union VALUETYPE *,
65 			     unsigned char *, struct magic *, int);
66 /* QNX has a mcheck() prototyp in a public include file */
67 static int magcheck	(union VALUETYPE *, struct magic *);
68 #ifdef	__used__
69 static void mdebug	(Int32_t, char *, int);
70 #endif
71 static int mconvert	(union VALUETYPE *, struct magic *);
72 
73 /*
74  * softmagic - lookup one file in database
75  * (already read from /etc/magic by apprentice.c).
76  * Passed the name and FILE * of one file to be typed.
77  */
78 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
79 char *
softmagic(unsigned char * buf,int nbytes)80 softmagic(unsigned char *buf, int nbytes)
81 {
82 	return (match(buf, nbytes));
83 }
84 
85 /*
86  * Go through the whole list, stopping if you find a match.  Process all
87  * the continuations of that match before returning.
88  *
89  * We support multi-level continuations:
90  *
91  *	At any time when processing a successful top-level match, there is a
92  *	current continuation level; it represents the level of the last
93  *	successfully matched continuation.
94  *
95  *	Continuations above that level are skipped as, if we see one, it
96  *	means that the continuation that controls them - i.e, the
97  *	lower-level continuation preceding them - failed to match.
98  *
99  *	Continuations below that level are processed as, if we see one,
100  *	it means we've finished processing or skipping higher-level
101  *	continuations under the control of a successful or unsuccessful
102  *	lower-level continuation, and are now seeing the next lower-level
103  *	continuation and should process it.  The current continuation
104  *	level reverts to the level of the one we're seeing.
105  *
106  *	Continuations at the current level are processed as, if we see
107  *	one, there's no lower-level continuation that may have failed.
108  *
109  *	If a continuation matches, we bump the current continuation level
110  *	so that higher-level continuations are processed.
111  */
112 static char *
match(unsigned char * s,int nbytes)113 match(unsigned char *s, int nbytes)
114 {
115 	int magindex = 0;
116 	union VALUETYPE p;
117 
118 	for (magindex = 0; magindex < __f_nmagic; magindex++) {
119 		/* if main entry matches, print it... */
120 		if (!mget(&p, s, &__f_magic[magindex], nbytes) ||
121 		    !magcheck(&p, &__f_magic[magindex])) {
122 			    /*
123 			     * main entry didn't match,
124 			     * flush its continuations
125 			     */
126 			    while (magindex < __f_nmagic &&
127 			    	   __f_magic[magindex + 1].cont_level != 0)
128 			    	   magindex++;
129 			    continue;
130 		}
131 
132 		return (__f_magic[magindex].desc);
133 	}
134 	return 0;			/* no match at all */
135 }
136 
137 
138 /*
139  * Convert the byte order of the data we are looking at
140  */
141 static int
mconvert(union VALUETYPE * p,struct magic * m)142 mconvert(union VALUETYPE *p, struct magic *m)
143 {
144 	switch (m->type) {
145 	case BYTE:
146 	case SHORT:
147 	case LONG:
148 	case DATE:
149 		return 1;
150 	case STRING:
151 		{
152 			char *ptr;
153 
154 			/* Null terminate and eat the return */
155 			p->s[sizeof(p->s) - 1] = '\0';
156 			if ((ptr = strchr(p->s, '\n')) != NULL)
157 				*ptr = '\0';
158 			return 1;
159 		}
160 	case BESHORT:
161 		p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
162 		return 1;
163 	case BELONG:
164 	case BEDATE:
165 		p->l = (Int32_t)
166 		    ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
167 		return 1;
168 	case LESHORT:
169 		p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
170 		return 1;
171 	case LELONG:
172 	case LEDATE:
173 		p->l = (Int32_t)
174 		    ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
175 		return 1;
176 	default:
177 		return 0;
178 	}
179 }
180 
181 #ifdef	__used__
182 static void
mdebug(Int32_t offset,char * str,int len)183 mdebug(Int32_t offset, char *str, int len)
184 {
185 	(void) fprintf(stderr, "mget @%d: ", offset);
186 	showstr(stderr, (char *) str, len);
187 	(void) fputc('\n', stderr);
188 	(void) fputc('\n', stderr);
189 }
190 #endif
191 
192 static int
mget(union VALUETYPE * p,unsigned char * s,struct magic * m,int nbytes)193 mget(union VALUETYPE* p, unsigned char *s, struct magic *m, int nbytes)
194 {
195 	Int32_t offset = m->offset;
196 
197 	if (offset + sizeof(union VALUETYPE) <= nbytes)
198 		memcpy(p, s + offset, sizeof(union VALUETYPE));
199 	else {
200 		/*
201 		 * the usefulness of padding with zeroes eludes me, it
202 		 * might even cause problems
203 		 */
204 		Int32_t have = nbytes - offset;
205 		memset(p, 0, sizeof(union VALUETYPE));
206 		if (have > 0)
207 			memcpy(p, s + offset, have);
208 	}
209 
210 	if (!mconvert(p, m))
211 		return 0;
212 
213 	if (m->flag & INDIR) {
214 
215 		switch (m->in.type) {
216 		case BYTE:
217 			offset = p->b + m->in.offset;
218 			break;
219 		case SHORT:
220 			offset = p->h + m->in.offset;
221 			break;
222 		case LONG:
223 			offset = p->l + m->in.offset;
224 			break;
225 		}
226 
227 		if (offset + sizeof(union VALUETYPE) > nbytes)
228 			return 0;
229 
230 		memcpy(p, s + offset, sizeof(union VALUETYPE));
231 
232 		if (!mconvert(p, m))
233 			return 0;
234 	}
235 	return 1;
236 }
237 
238 static int
magcheck(union VALUETYPE * p,struct magic * m)239 magcheck(union VALUETYPE* p, struct magic *m)
240 {
241 	register UInt32_t l = m->value.l;
242 	register UInt32_t v;
243 	int matched;
244 
245 	if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
246 		fprintf(stderr, "BOINK");
247 		return 1;
248 	}
249 
250 
251 	switch (m->type) {
252 	case BYTE:
253 		v = p->b;
254 		break;
255 
256 	case SHORT:
257 	case BESHORT:
258 	case LESHORT:
259 		v = p->h;
260 		break;
261 
262 	case LONG:
263 	case BELONG:
264 	case LELONG:
265 	case DATE:
266 	case BEDATE:
267 	case LEDATE:
268 		v = p->l;
269 		break;
270 
271 	case STRING:
272 		l = 0;
273 		/* What we want here is:
274 		 * v = strncmp(m->value.s, p->s, m->vallen);
275 		 * but ignoring any nulls.  bcmp doesn't give -/+/0
276 		 * and isn't universally available anyway.
277 		 */
278 		v = 0;
279 		{
280 			register unsigned char *a = (unsigned char*)m->value.s;
281 			register unsigned char *b = (unsigned char*)p->s;
282 			register int len = m->vallen;
283 
284 			while (--len >= 0)
285 				if ((v = *b++ - *a++) != '\0')
286 					break;
287 		}
288 		break;
289 	default:
290 		return 0;/*NOTREACHED*/
291 	}
292 
293 	v = signextend(m, v) & m->mask;
294 
295 	switch (m->reln) {
296 	case 'x':
297 		if (debug)
298 			(void) fprintf(stderr, "%u == *any* = 1\n", v);
299 		matched = 1;
300 		break;
301 
302 	case '!':
303 		matched = v != l;
304 		if (debug)
305 			(void) fprintf(stderr, "%u != %u = %d\n",
306 				       v, l, matched);
307 		break;
308 
309 	case '=':
310 		matched = v == l;
311 		if (debug)
312 			(void) fprintf(stderr, "%u == %u = %d\n",
313 				       v, l, matched);
314 		break;
315 
316 	case '>':
317 		if (m->flag & UNSIGNED) {
318 			matched = v > l;
319 			if (debug)
320 				(void) fprintf(stderr, "%u > %u = %d\n",
321 					       v, l, matched);
322 		}
323 		else {
324 			matched = (Int32_t) v > (Int32_t) l;
325 			if (debug)
326 				(void) fprintf(stderr, "%d > %d = %d\n",
327 					    (Int32_t)v, (Int32_t)l, matched);
328 		}
329 		break;
330 
331 	case '<':
332 		if (m->flag & UNSIGNED) {
333 			matched = v < l;
334 			if (debug)
335 				(void) fprintf(stderr, "%u < %u = %d\n",
336 					       v, l, matched);
337 		}
338 		else {
339 			matched = (Int32_t) v < (Int32_t) l;
340 			if (debug)
341 				(void) fprintf(stderr, "%d < %d = %d\n",
342 					    (Int32_t)v, (Int32_t)l, matched);
343 		}
344 		break;
345 
346 	case '&':
347 		matched = (v & l) == l;
348 		if (debug)
349 			(void) fprintf(stderr, "((%x & %x) == %x) = %d\n",
350 				       v, l, l, matched);
351 		break;
352 
353 	case '^':
354 		matched = (v & l) != l;
355 		if (debug)
356 			(void) fprintf(stderr, "((%x & %x) != %x) = %d\n",
357 				       v, l, l, matched);
358 		break;
359 
360 	default:
361 		matched = 0;
362 		break;/*NOTREACHED*/
363 	}
364 
365 	return matched;
366 }
367