Annotation of src/usr.bin/file/magic.c, Revision 1.6
1.6 ! chl 1: /* $OpenBSD: magic.c,v 1.5 2008/05/08 01:40:56 chl 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: *
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: #include "file.h"
30: #include "magic.h"
31:
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <unistd.h>
35: #include <string.h>
36: #include <sys/types.h>
37: #include <sys/param.h> /* for MAXPATHLEN */
38: #include <sys/stat.h>
39: #ifdef QUICK
40: #include <sys/mman.h>
41: #endif
1.5 chl 42: #include <limits.h> /* for PIPE_BUF */
1.1 tedu 43:
1.5 chl 44: #if defined(HAVE_UTIMES)
45: # include <sys/time.h>
46: #elif defined(HAVE_UTIME)
1.1 tedu 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: #endif
53:
54: #ifdef HAVE_UNISTD_H
55: #include <unistd.h> /* for read() */
56: #endif
57:
58: #ifdef HAVE_LOCALE_H
59: #include <locale.h>
60: #endif
61:
62: #include <netinet/in.h> /* for byte swapping */
63:
64: #include "patchlevel.h"
65:
66: #ifndef lint
1.6 ! chl 67: FILE_RCSID("@(#)$Id: magic.c,v 1.5 2008/05/08 01:40:56 chl Exp $")
1.1 tedu 68: #endif /* lint */
69:
1.6 ! chl 70: #ifndef PIPE_BUF
! 71: /* Get the PIPE_BUF from pathconf */
! 72: #ifdef _PC_PIPE_BUF
! 73: #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
! 74: #else
! 75: #define PIPE_BUF 512
! 76: #endif
! 77: #endif
! 78:
1.1 tedu 79: #ifdef __EMX__
80: private char *apptypeName = NULL;
81: protected int file_os2_apptype(struct magic_set *ms, const char *fn,
82: const void *buf, size_t nb);
83: #endif /* __EMX__ */
84:
85: private void free_mlist(struct mlist *);
86: private void close_and_restore(const struct magic_set *, const char *, int,
87: const struct stat *);
1.5 chl 88: private int info_from_stat(struct magic_set *, mode_t);
1.6 ! chl 89: #ifndef COMPILE_ONLY
! 90: private const char *file_or_fd(struct magic_set *, const char *, int);
! 91: #endif
1.5 chl 92:
93: #ifndef STDIN_FILENO
94: #define STDIN_FILENO 0
95: #endif
1.1 tedu 96:
97: public struct magic_set *
98: magic_open(int flags)
99: {
100: struct magic_set *ms;
101:
1.5 chl 102: if ((ms = calloc((size_t)1, sizeof(struct magic_set))) == NULL)
1.1 tedu 103: return NULL;
104:
105: if (magic_setflags(ms, flags) == -1) {
106: errno = EINVAL;
1.6 ! chl 107: goto free;
1.1 tedu 108: }
109:
1.6 ! chl 110: ms->o.buf = ms->o.pbuf = NULL;
1.5 chl 111:
112: ms->c.li = malloc((ms->c.len = 10) * sizeof(*ms->c.li));
113: if (ms->c.li == NULL)
1.6 ! chl 114: goto free;
1.5 chl 115:
1.1 tedu 116: ms->haderr = 0;
117: ms->error = -1;
118: ms->mlist = NULL;
1.5 chl 119: ms->file = "unknown";
120: ms->line = 0;
1.1 tedu 121: return ms;
1.6 ! chl 122: free:
1.5 chl 123: free(ms);
124: return NULL;
1.1 tedu 125: }
126:
127: private void
128: free_mlist(struct mlist *mlist)
129: {
130: struct mlist *ml;
131:
132: if (mlist == NULL)
133: return;
134:
135: for (ml = mlist->next; ml != mlist;) {
136: struct mlist *next = ml->next;
137: struct magic *mg = ml->magic;
138: file_delmagic(mg, ml->mapped, ml->nmagic);
139: free(ml);
140: ml = next;
141: }
142: free(ml);
143: }
144:
1.5 chl 145: private int
146: info_from_stat(struct magic_set *ms, mode_t md)
147: {
148: /* We cannot open it, but we were able to stat it. */
149: if (md & 0222)
150: if (file_printf(ms, "writable, ") == -1)
151: return -1;
152: if (md & 0111)
153: if (file_printf(ms, "executable, ") == -1)
154: return -1;
155: if (S_ISREG(md))
156: if (file_printf(ms, "regular file, ") == -1)
157: return -1;
158: if (file_printf(ms, "no read permission") == -1)
159: return -1;
160: return 0;
161: }
162:
1.1 tedu 163: public void
1.5 chl 164: magic_close(struct magic_set *ms)
1.1 tedu 165: {
166: free_mlist(ms->mlist);
1.5 chl 167: free(ms->o.pbuf);
1.1 tedu 168: free(ms->o.buf);
1.5 chl 169: free(ms->c.li);
1.1 tedu 170: free(ms);
171: }
172:
173: /*
174: * load a magic file
175: */
176: public int
177: magic_load(struct magic_set *ms, const char *magicfile)
178: {
179: struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
180: if (ml) {
181: free_mlist(ms->mlist);
182: ms->mlist = ml;
183: return 0;
184: }
185: return -1;
186: }
187:
188: public int
189: magic_compile(struct magic_set *ms, const char *magicfile)
190: {
191: struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
192: free_mlist(ml);
193: return ml ? 0 : -1;
194: }
195:
196: public int
197: magic_check(struct magic_set *ms, const char *magicfile)
198: {
199: struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
200: free_mlist(ml);
201: return ml ? 0 : -1;
202: }
203:
204: private void
205: close_and_restore(const struct magic_set *ms, const char *name, int fd,
206: const struct stat *sb)
207: {
1.5 chl 208: if (fd == STDIN_FILENO)
209: return;
1.1 tedu 210: (void) close(fd);
1.5 chl 211:
212: if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
1.1 tedu 213: /*
214: * Try to restore access, modification times if read it.
215: * This is really *bad* because it will modify the status
216: * time of the file... And of course this will affect
217: * backup programs
218: */
219: #ifdef HAVE_UTIMES
220: struct timeval utsbuf[2];
1.6 ! chl 221: (void)memset(utsbuf, 0, sizeof(utsbuf));
1.1 tedu 222: utsbuf[0].tv_sec = sb->st_atime;
223: utsbuf[1].tv_sec = sb->st_mtime;
224:
225: (void) utimes(name, utsbuf); /* don't care if loses */
226: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
227: struct utimbuf utbuf;
228:
1.6 ! chl 229: (void)memset(utbuf, 0, sizeof(utbuf));
1.1 tedu 230: utbuf.actime = sb->st_atime;
231: utbuf.modtime = sb->st_mtime;
232: (void) utime(name, &utbuf); /* don't care if loses */
233: #endif
234: }
235: }
236:
1.5 chl 237: #ifndef COMPILE_ONLY
1.6 ! chl 238:
! 239: /*
! 240: * find type of descriptor
! 241: */
! 242: public const char *
! 243: magic_descriptor(struct magic_set *ms, int fd)
! 244: {
! 245: return file_or_fd(ms, NULL, fd);
! 246: }
! 247:
1.1 tedu 248: /*
249: * find type of named file
250: */
251: public const char *
252: magic_file(struct magic_set *ms, const char *inname)
253: {
1.6 ! chl 254: return file_or_fd(ms, inname, STDIN_FILENO);
! 255: }
! 256:
! 257: private const char *
! 258: file_or_fd(struct magic_set *ms, const char *inname, int fd)
! 259: {
1.5 chl 260: int rv = -1;
261: unsigned char *buf;
1.1 tedu 262: struct stat sb;
263: ssize_t nbytes = 0; /* number of bytes read from a datafile */
1.5 chl 264: int ispipe = 0;
265:
266: /*
267: * one extra for terminating '\0', and
268: * some overlapping space for matches near EOF
269: */
270: #define SLOP (1 + sizeof(union VALUETYPE))
271: if ((buf = malloc(HOWMANY + SLOP)) == NULL)
272: return NULL;
1.1 tedu 273:
274: if (file_reset(ms) == -1)
1.5 chl 275: goto done;
1.1 tedu 276:
277: switch (file_fsmagic(ms, inname, &sb)) {
1.5 chl 278: case -1: /* error */
279: goto done;
280: case 0: /* nothing found */
1.1 tedu 281: break;
1.5 chl 282: default: /* matched it and printed type */
283: rv = 0;
284: goto done;
1.1 tedu 285: }
286:
1.5 chl 287: if (inname == NULL) {
288: if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
289: ispipe = 1;
290: } else {
291: int flags = O_RDONLY|O_BINARY;
292:
293: if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
294: flags |= O_NONBLOCK;
295: ispipe = 1;
296: }
297:
298: errno = 0;
299: if ((fd = open(inname, flags)) < 0) {
300: #ifdef __CYGWIN__
1.6 ! chl 301: /* FIXME: Do this with EXEEXT from autotools */
! 302: char *tmp = alloca(strlen(inname) + 5);
! 303: (void)strcat(strcpy(tmp, inname), ".exe");
! 304: if ((fd = open(tmp, flags)) < 0) {
1.5 chl 305: #endif
1.6 ! chl 306: fprintf(stderr, "couldn't open file\n");
! 307: if (info_from_stat(ms, sb.st_mode) == -1)
! 308: goto done;
! 309: rv = 0;
! 310: goto done;
1.5 chl 311: #ifdef __CYGWIN__
1.6 ! chl 312: }
1.5 chl 313: #endif
314: }
315: #ifdef O_NONBLOCK
316: if ((flags = fcntl(fd, F_GETFL)) != -1) {
317: flags &= ~O_NONBLOCK;
318: (void)fcntl(fd, F_SETFL, flags);
319: }
1.1 tedu 320: #endif
321: }
322:
323: /*
324: * try looking at the first HOWMANY bytes
325: */
1.5 chl 326: if (ispipe) {
327: ssize_t r = 0;
328:
329: while ((r = sread(fd, (void *)&buf[nbytes],
330: (size_t)(HOWMANY - nbytes), 1)) > 0) {
331: nbytes += r;
332: if (r < PIPE_BUF) break;
333: }
334:
335: if (nbytes == 0) {
336: /* We can not read it, but we were able to stat it. */
337: if (info_from_stat(ms, sb.st_mode) == -1)
338: goto done;
339: rv = 0;
340: goto done;
341: }
342:
343: } else {
344: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
345: file_error(ms, errno, "cannot read `%s'", inname);
346: goto done;
347: }
1.1 tedu 348: }
349:
1.6 ! chl 350: (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
! 351: if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
! 352: goto done;
1.5 chl 353: rv = 0;
1.1 tedu 354: done:
1.5 chl 355: free(buf);
1.1 tedu 356: close_and_restore(ms, inname, fd, &sb);
1.5 chl 357: return rv == 0 ? file_getbuffer(ms) : NULL;
1.1 tedu 358: }
359:
360:
361: public const char *
362: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
363: {
364: if (file_reset(ms) == -1)
365: return NULL;
366: /*
367: * The main work is done here!
368: * We have the file name and/or the data buffer to be identified.
369: */
1.5 chl 370: if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
1.1 tedu 371: return NULL;
372: }
373: return file_getbuffer(ms);
374: }
1.5 chl 375: #endif
1.1 tedu 376:
377: public const char *
378: magic_error(struct magic_set *ms)
379: {
380: return ms->haderr ? ms->o.buf : NULL;
381: }
382:
383: public int
384: magic_errno(struct magic_set *ms)
385: {
386: return ms->haderr ? ms->error : 0;
387: }
388:
389: public int
390: magic_setflags(struct magic_set *ms, int flags)
391: {
392: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
393: if (flags & MAGIC_PRESERVE_ATIME)
394: return -1;
395: #endif
396: ms->flags = flags;
397: return 0;
398: }