]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/file/magic.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / file / magic.c
1 /*
2  * Copyright (c) Christos Zoulas 2003.
3  * All Rights Reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice immediately at the beginning of the file, without modification,
10  *    this list of conditions, and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *  
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include "file.h"
29 #include "magic.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/param.h>  /* for MAXPATHLEN */
37 #include <sys/stat.h>
38 #ifdef QUICK
39 #include <sys/mman.h>
40 #endif
41 #include <limits.h>     /* for PIPE_BUF */
42
43 #if defined(HAVE_UTIMES)
44 # include <sys/time.h>
45 #elif defined(HAVE_UTIME)
46 # if defined(HAVE_SYS_UTIME_H)
47 #  include <sys/utime.h>
48 # elif defined(HAVE_UTIME_H)
49 #  include <utime.h>
50 # endif
51 #endif
52
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>     /* for read() */
55 #endif
56
57 #ifdef HAVE_LOCALE_H
58 #include <locale.h>
59 #endif
60
61 #include <netinet/in.h>         /* for byte swapping */
62
63 #include "patchlevel.h"
64
65 #ifndef lint
66 FILE_RCSID("@(#)$File: magic.c,v 1.45 2007/12/27 16:35:59 christos Exp $")
67 #endif  /* lint */
68
69 #ifdef __EMX__
70 private char *apptypeName = NULL;
71 protected int file_os2_apptype(struct magic_set *ms, const char *fn,
72     const void *buf, size_t nb);
73 #endif /* __EMX__ */
74
75 private void free_mlist(struct mlist *);
76 private void close_and_restore(const struct magic_set *, const char *, int,
77     const struct stat *);
78 private int info_from_stat(struct magic_set *, mode_t);
79 #ifndef COMPILE_ONLY
80 private const char *file_or_fd(struct magic_set *, const char *, int);
81 #endif
82
83 #ifndef STDIN_FILENO
84 #define STDIN_FILENO    0
85 #endif
86
87 public struct magic_set *
88 magic_open(int flags)
89 {
90         struct magic_set *ms;
91
92         if ((ms = calloc((size_t)1, sizeof(struct magic_set))) == NULL)
93                 return NULL;
94
95         if (magic_setflags(ms, flags) == -1) {
96                 errno = EINVAL;
97                 goto free1;
98         }
99
100         ms->o.ptr = ms->o.buf = malloc(ms->o.left = ms->o.size = 1024);
101         if (ms->o.buf == NULL)
102                 goto free1;
103
104         ms->o.pbuf = malloc(ms->o.psize = 1024);
105         if (ms->o.pbuf == NULL)
106                 goto free2;
107
108         ms->c.li = malloc((ms->c.len = 10) * sizeof(*ms->c.li));
109         if (ms->c.li == NULL)
110                 goto free3;
111         
112         ms->haderr = 0;
113         ms->error = -1;
114         ms->mlist = NULL;
115         ms->file = "unknown";
116         ms->line = 0;
117         return ms;
118 free3:
119         free(ms->o.pbuf);
120 free2:
121         free(ms->o.buf);
122 free1:
123         free(ms);
124         return NULL;
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
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
163 public void
164 magic_close(struct magic_set *ms)
165 {
166         free_mlist(ms->mlist);
167         free(ms->o.pbuf);
168         free(ms->o.buf);
169         free(ms->c.li);
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 {
208         if (fd == STDIN_FILENO)
209                 return;
210         (void) close(fd);
211
212         if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
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];
221                 memset(utsbuf, 0, sizeof(struct timeval) * 2);
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
229                 memset(&utbuf, 0, sizeof(struct utimbuf));
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
237 #ifndef COMPILE_ONLY
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
248 /*
249  * find type of named file
250  */
251 public const char *
252 magic_file(struct magic_set *ms, const char *inname)
253 {
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 {
260         int     rv = -1;
261         unsigned char *buf;
262         struct stat     sb;
263         ssize_t nbytes = 0;     /* number of bytes read from a datafile */
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;
273
274         if (file_reset(ms) == -1)
275                 goto done;
276
277         switch (file_fsmagic(ms, inname, &sb)) {
278         case -1:                /* error */
279                 goto done;
280         case 0:                 /* nothing found */
281                 break;
282         default:                /* matched it and printed type */
283                 rv = 0;
284                 goto done;
285         }
286
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__
301                         char *tmp = alloca(strlen(inname) + 5);
302                         (void)strcat(strcpy(tmp, inname), ".exe");
303                         if ((fd = open(tmp, flags)) < 0) {
304 #endif
305                                 if (info_from_stat(ms, sb.st_mode) == -1)
306                                         goto done;
307                                 rv = 0;
308                                 goto done;
309 #ifdef __CYGWIN__
310                         }
311 #endif
312                 }
313 #ifdef O_NONBLOCK
314                 if ((flags = fcntl(fd, F_GETFL)) != -1) {
315                         flags &= ~O_NONBLOCK;
316                         (void)fcntl(fd, F_SETFL, flags);
317                 }
318 #endif
319         }
320
321         /*
322          * try looking at the first HOWMANY bytes
323          */
324         if (ispipe) {
325                 ssize_t r = 0;
326
327                 while ((r = sread(fd, (void *)&buf[nbytes],
328                     (size_t)(HOWMANY - nbytes), 1)) > 0) {
329                         nbytes += r;
330                         if (r < PIPE_BUF) break;
331                 }
332
333                 if (nbytes == 0) {
334                         /* We can not read it, but we were able to stat it. */
335                         if (info_from_stat(ms, sb.st_mode) == -1)
336                                 goto done;
337                         rv = 0;
338                         goto done;
339                 }
340
341         } else {
342                 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
343                         file_error(ms, errno, "cannot read `%s'", inname);
344                         goto done;
345                 }
346         }
347
348         (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
349         if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
350                 goto done;
351         rv = 0;
352 done:
353         free(buf);
354         close_and_restore(ms, inname, fd, &sb);
355         return rv == 0 ? file_getbuffer(ms) : NULL;
356 }
357
358
359 public const char *
360 magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
361 {
362         if (file_reset(ms) == -1)
363                 return NULL;
364         /*
365          * The main work is done here!
366          * We have the file name and/or the data buffer to be identified. 
367          */
368         if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
369                 return NULL;
370         }
371         return file_getbuffer(ms);
372 }
373 #endif
374
375 public const char *
376 magic_error(struct magic_set *ms)
377 {
378         return ms->haderr ? ms->o.buf : NULL;
379 }
380
381 public int
382 magic_errno(struct magic_set *ms)
383 {
384         return ms->haderr ? ms->error : 0;
385 }
386
387 public int
388 magic_setflags(struct magic_set *ms, int flags)
389 {
390 #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
391         if (flags & MAGIC_PRESERVE_ATIME)
392                 return -1;
393 #endif
394         ms->flags = flags;
395         return 0;
396 }