Annotation of src/usr.bin/file/magic.c, Revision 1.2.12.1
1.2.12.1! ckuethe 1: /* $OpenBSD: magic.c,v 1.3 2007/07/09 16:39:48 dim Exp $ */
1.1 tedu 2: /*
3: * Copyright (c) Christos Zoulas 2003.
4: * All Rights Reserved.
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. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28: * SUCH DAMAGE.
29: */
30:
31: #include "file.h"
32: #include "magic.h"
33:
34: #include <stdio.h>
35: #include <stdlib.h>
36: #include <unistd.h>
37: #include <string.h>
38: #include <sys/types.h>
39: #include <sys/param.h> /* for MAXPATHLEN */
40: #include <sys/stat.h>
41: #include <fcntl.h> /* for open() */
42: #ifdef QUICK
43: #include <sys/mman.h>
44: #endif
45:
46: #if defined(HAVE_UTIME)
47: # if defined(HAVE_SYS_UTIME_H)
48: # include <sys/utime.h>
49: # elif defined(HAVE_UTIME_H)
50: # include <utime.h>
51: # endif
52: #elif defined(HAVE_UTIMES)
53: # include <sys/time.h>
54: #endif
55:
56: #ifdef HAVE_UNISTD_H
57: #include <unistd.h> /* for read() */
58: #endif
59:
60: #ifdef HAVE_LOCALE_H
61: #include <locale.h>
62: #endif
63:
64: #include <netinet/in.h> /* for byte swapping */
65:
66: #include "patchlevel.h"
67:
68: #ifndef lint
1.2.12.1! ckuethe 69: FILE_RCSID("@(#)$Id: magic.c,v 1.3 2007/07/09 16:39:48 dim Exp $")
1.1 tedu 70: #endif /* lint */
71:
72: #ifdef __EMX__
73: private char *apptypeName = NULL;
74: protected int file_os2_apptype(struct magic_set *ms, const char *fn,
75: const void *buf, size_t nb);
76: #endif /* __EMX__ */
77:
78: private void free_mlist(struct mlist *);
79: private void close_and_restore(const struct magic_set *, const char *, int,
80: const struct stat *);
81:
82: public struct magic_set *
83: magic_open(int flags)
84: {
85: struct magic_set *ms;
86:
87: if ((ms = malloc(sizeof(struct magic_set))) == NULL)
88: return NULL;
89:
90: if (magic_setflags(ms, flags) == -1) {
91: free(ms);
92: errno = EINVAL;
93: return NULL;
94: }
95:
1.2.12.1! ckuethe 96: ms->o.ptr = ms->o.buf = malloc(ms->o.left = ms->o.size = 1024);
1.1 tedu 97: if (ms->o.buf == NULL) {
98: free(ms);
99: return NULL;
100: }
101: ms->o.pbuf = malloc(ms->o.psize = 1024);
102: if (ms->o.pbuf == NULL) {
103: free(ms->o.buf);
104: free(ms);
105: return NULL;
106: }
107: ms->c.off = malloc((ms->c.len = 10) * sizeof(*ms->c.off));
108: if (ms->c.off == NULL) {
109: free(ms->o.pbuf);
110: free(ms->o.buf);
111: free(ms);
112: return NULL;
113: }
114: ms->haderr = 0;
115: ms->error = -1;
116: ms->mlist = NULL;
117: return ms;
118: }
119:
120: private void
121: free_mlist(struct mlist *mlist)
122: {
123: struct mlist *ml;
124:
125: if (mlist == NULL)
126: return;
127:
128: for (ml = mlist->next; ml != mlist;) {
129: struct mlist *next = ml->next;
130: struct magic *mg = ml->magic;
131: file_delmagic(mg, ml->mapped, ml->nmagic);
132: free(ml);
133: ml = next;
134: }
135: free(ml);
136: }
137:
138: public void
139: magic_close(ms)
140: struct magic_set *ms;
141: {
142: free_mlist(ms->mlist);
143: free(ms->o.buf);
144: free(ms->c.off);
145: free(ms);
146: }
147:
148: /*
149: * load a magic file
150: */
151: public int
152: magic_load(struct magic_set *ms, const char *magicfile)
153: {
154: struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
155: if (ml) {
156: free_mlist(ms->mlist);
157: ms->mlist = ml;
158: return 0;
159: }
160: return -1;
161: }
162:
163: public int
164: magic_compile(struct magic_set *ms, const char *magicfile)
165: {
166: struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
167: free_mlist(ml);
168: return ml ? 0 : -1;
169: }
170:
171: public int
172: magic_check(struct magic_set *ms, const char *magicfile)
173: {
174: struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
175: free_mlist(ml);
176: return ml ? 0 : -1;
177: }
178:
179: private void
180: close_and_restore(const struct magic_set *ms, const char *name, int fd,
181: const struct stat *sb)
182: {
183: (void) close(fd);
184: if (fd != STDIN_FILENO && (ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
185: /*
186: * Try to restore access, modification times if read it.
187: * This is really *bad* because it will modify the status
188: * time of the file... And of course this will affect
189: * backup programs
190: */
191: #ifdef HAVE_UTIMES
192: struct timeval utsbuf[2];
193: utsbuf[0].tv_sec = sb->st_atime;
194: utsbuf[1].tv_sec = sb->st_mtime;
195:
196: (void) utimes(name, utsbuf); /* don't care if loses */
197: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
198: struct utimbuf utbuf;
199:
200: utbuf.actime = sb->st_atime;
201: utbuf.modtime = sb->st_mtime;
202: (void) utime(name, &utbuf); /* don't care if loses */
203: #endif
204: }
205: }
206:
207: /*
208: * find type of named file
209: */
210: public const char *
211: magic_file(struct magic_set *ms, const char *inname)
212: {
213: int fd = 0;
214: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
215: struct stat sb;
216: ssize_t nbytes = 0; /* number of bytes read from a datafile */
217:
218: if (file_reset(ms) == -1)
219: return NULL;
220:
221: switch (file_fsmagic(ms, inname, &sb)) {
222: case -1:
223: return NULL;
224: case 0:
225: break;
226: default:
227: return file_getbuffer(ms);
228: }
229:
230: #ifndef STDIN_FILENO
231: #define STDIN_FILENO 0
232: #endif
233: if (inname == NULL)
234: fd = STDIN_FILENO;
235: else if ((fd = open(inname, O_RDONLY)) < 0) {
236: /* We cannot open it, but we were able to stat it. */
237: if (sb.st_mode & 0222)
238: if (file_printf(ms, "writable, ") == -1)
239: return NULL;
240: if (sb.st_mode & 0111)
241: if (file_printf(ms, "executable, ") == -1)
242: return NULL;
243: if (S_ISREG(sb.st_mode))
244: if (file_printf(ms, "regular file, ") == -1)
245: return NULL;
246: if (file_printf(ms, "no read permission") == -1)
247: return NULL;
248: return file_getbuffer(ms);
249: }
250:
251: /*
252: * try looking at the first HOWMANY bytes
253: */
254: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
255: file_error(ms, errno, "cannot read `%s'", inname);
256: goto done;
257: }
258:
259: if (nbytes == 0) {
260: if (file_printf(ms, (ms->flags & MAGIC_MIME) ?
261: "application/x-empty" : "empty") == -1)
262: goto done;
263: goto gotit;
264: } else if (nbytes == 1) {
265: if (file_printf(ms, "very short file (no magic)") == -1)
266: goto done;
267: goto gotit;
268: } else {
269: buf[nbytes] = '\0'; /* null-terminate it */
270: #ifdef __EMX__
271: switch (file_os2_apptype(ms, inname, buf, nbytes)) {
272: case -1:
273: goto done;
274: case 0:
275: break;
276: default:
277: goto gotit;
278: }
279: #endif
280: if (file_buffer(ms, buf, (size_t)nbytes) == -1)
281: goto done;
282: #ifdef BUILTIN_ELF
283: if (nbytes > 5) {
284: /*
285: * We matched something in the file, so this *might*
286: * be an ELF file, and the file is at least 5 bytes
287: * long, so if it's an ELF file it has at least one
288: * byte past the ELF magic number - try extracting
289: * information from the ELF headers that cannot easily
290: * be extracted with rules in the magic file.
291: */
292: file_tryelf(ms, fd, buf, (size_t)nbytes);
293: }
294: #endif
295: }
296: gotit:
297: close_and_restore(ms, inname, fd, &sb);
298: return file_getbuffer(ms);
299: done:
300: close_and_restore(ms, inname, fd, &sb);
301: return NULL;
302: }
303:
304:
305: public const char *
306: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
307: {
308: if (file_reset(ms) == -1)
309: return NULL;
310: /*
311: * The main work is done here!
312: * We have the file name and/or the data buffer to be identified.
313: */
314: if (file_buffer(ms, buf, nb) == -1) {
315: return NULL;
316: }
317: return file_getbuffer(ms);
318: }
319:
320: public const char *
321: magic_error(struct magic_set *ms)
322: {
323: return ms->haderr ? ms->o.buf : NULL;
324: }
325:
326: public int
327: magic_errno(struct magic_set *ms)
328: {
329: return ms->haderr ? ms->error : 0;
330: }
331:
332: public int
333: magic_setflags(struct magic_set *ms, int flags)
334: {
335: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
336: if (flags & MAGIC_PRESERVE_ATIME)
337: return -1;
338: #endif
339: ms->flags = flags;
340: return 0;
341: }