Merge from vendor branch FILE:
[dragonfly.git] / contrib / file-4 / src / 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("@(#)$Id: magic.c,v 1.35 2006/10/31 19:37:17 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
80 #ifndef STDIN_FILENO
81 #define STDIN_FILENO    0
82 #endif
83
84 public struct magic_set *
85 magic_open(int flags)
86 {
87         struct magic_set *ms;
88
89         if ((ms = malloc(sizeof(struct magic_set))) == NULL)
90                 return NULL;
91
92         if (magic_setflags(ms, flags) == -1) {
93                 errno = EINVAL;
94                 goto free1;
95         }
96
97         ms->o.ptr = ms->o.buf = malloc(ms->o.size = 1024);
98         if (ms->o.buf == NULL)
99                 goto free1;
100
101         ms->o.pbuf = malloc(ms->o.psize = 1024);
102         if (ms->o.pbuf == NULL)
103                 goto free2;
104
105         ms->c.off = malloc((ms->c.len = 10) * sizeof(*ms->c.off));
106         if (ms->c.off == NULL)
107                 goto free3;
108         
109         ms->o.len = 0;
110         ms->haderr = 0;
111         ms->error = -1;
112         ms->mlist = NULL;
113         return ms;
114 free3:
115         free(ms->o.pbuf);
116 free2:
117         free(ms->o.buf);
118 free1:
119         free(ms);
120         return NULL;
121 }
122
123 private void
124 free_mlist(struct mlist *mlist)
125 {
126         struct mlist *ml;
127
128         if (mlist == NULL)
129                 return;
130
131         for (ml = mlist->next; ml != mlist;) {
132                 struct mlist *next = ml->next;
133                 struct magic *mg = ml->magic;
134                 file_delmagic(mg, ml->mapped, ml->nmagic);
135                 free(ml);
136                 ml = next;
137         }
138         free(ml);
139 }
140
141 private int
142 info_from_stat(struct magic_set *ms, mode_t md)
143 {
144         /* We cannot open it, but we were able to stat it. */
145         if (md & 0222)
146                 if (file_printf(ms, "writable, ") == -1)
147                         return -1;
148         if (md & 0111)
149                 if (file_printf(ms, "executable, ") == -1)
150                         return -1;
151         if (S_ISREG(md))
152                 if (file_printf(ms, "regular file, ") == -1)
153                         return -1;
154         if (file_printf(ms, "no read permission") == -1)
155                 return -1;
156         return 0;
157 }
158
159 public void
160 magic_close(struct magic_set *ms)
161 {
162         free_mlist(ms->mlist);
163         free(ms->o.pbuf);
164         free(ms->o.buf);
165         free(ms->c.off);
166         free(ms);
167 }
168
169 /*
170  * load a magic file
171  */
172 public int
173 magic_load(struct magic_set *ms, const char *magicfile)
174 {
175         struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
176         if (ml) {
177                 free_mlist(ms->mlist);
178                 ms->mlist = ml;
179                 return 0;
180         }
181         return -1;
182 }
183
184 public int
185 magic_compile(struct magic_set *ms, const char *magicfile)
186 {
187         struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
188         free_mlist(ml);
189         return ml ? 0 : -1;
190 }
191
192 public int
193 magic_check(struct magic_set *ms, const char *magicfile)
194 {
195         struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
196         free_mlist(ml);
197         return ml ? 0 : -1;
198 }
199
200 private void
201 close_and_restore(const struct magic_set *ms, const char *name, int fd,
202     const struct stat *sb)
203 {
204         if (fd == STDIN_FILENO)
205                 return;
206         (void) close(fd);
207
208         if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
209                 /*
210                  * Try to restore access, modification times if read it.
211                  * This is really *bad* because it will modify the status
212                  * time of the file... And of course this will affect
213                  * backup programs
214                  */
215 #ifdef HAVE_UTIMES
216                 struct timeval  utsbuf[2];
217                 utsbuf[0].tv_sec = sb->st_atime;
218                 utsbuf[1].tv_sec = sb->st_mtime;
219
220                 (void) utimes(name, utsbuf); /* don't care if loses */
221 #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
222                 struct utimbuf  utbuf;
223
224                 utbuf.actime = sb->st_atime;
225                 utbuf.modtime = sb->st_mtime;
226                 (void) utime(name, &utbuf); /* don't care if loses */
227 #endif
228         }
229 }
230
231 #ifndef COMPILE_ONLY
232 /*
233  * find type of named file
234  */
235 public const char *
236 magic_file(struct magic_set *ms, const char *inname)
237 {
238         int     fd = 0;
239         int     rv = -1;
240         unsigned char *buf;
241         struct stat     sb;
242         ssize_t nbytes = 0;     /* number of bytes read from a datafile */
243         int     ispipe = 0;
244
245         /*
246          * one extra for terminating '\0', and
247          * some overlapping space for matches near EOF
248          */
249 #define SLOP (1 + sizeof(union VALUETYPE))
250         if ((buf = malloc(HOWMANY + SLOP)) == NULL)
251                 return NULL;
252
253         if (file_reset(ms) == -1)
254                 goto done;
255
256         switch (file_fsmagic(ms, inname, &sb)) {
257         case -1:                /* error */
258                 goto done;
259         case 0:                 /* nothing found */
260                 break;
261         default:                /* matched it and printed type */
262                 rv = 0;
263                 goto done;
264         }
265
266         if (inname == NULL) {
267                 fd = STDIN_FILENO;
268                 if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
269                         ispipe = 1;
270         } else {
271                 int flags = O_RDONLY|O_BINARY;
272
273                 if (stat(inname, &sb) == 0 && S_ISFIFO(sb.st_mode)) {
274                         flags |= O_NONBLOCK;
275                         ispipe = 1;
276                 }
277
278                 errno = 0;
279                 if ((fd = open(inname, flags)) < 0) {
280 #ifdef __CYGWIN__
281                     char *tmp = alloca(strlen(inname) + 5);
282                     (void)strcat(strcpy(tmp, inname), ".exe");
283                     if ((fd = open(tmp, flags)) < 0) {
284 #endif
285                         if (info_from_stat(ms, sb.st_mode) == -1)
286                             goto done;
287                         rv = 0;
288                         goto done;
289 #ifdef __CYGWIN__
290                     }
291 #endif
292                 }
293 #ifdef O_NONBLOCK
294                 if ((flags = fcntl(fd, F_GETFL)) != -1) {
295                         flags &= ~O_NONBLOCK;
296                         (void)fcntl(fd, F_SETFL, flags);
297                 }
298 #endif
299         }
300
301         /*
302          * try looking at the first HOWMANY bytes
303          */
304         if (ispipe) {
305                 ssize_t r = 0;
306
307                 while ((r = sread(fd, (void *)&buf[nbytes],
308                     (size_t)(HOWMANY - nbytes))) > 0) {
309                         nbytes += r;
310                         if (r < PIPE_BUF) break;
311                 }
312
313                 if (nbytes == 0) {
314                         /* We can not read it, but we were able to stat it. */
315                         if (info_from_stat(ms, sb.st_mode) == -1)
316                                 goto done;
317                         rv = 0;
318                         goto done;
319                 }
320
321         } else {
322                 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
323                         file_error(ms, errno, "cannot read `%s'", inname);
324                         goto done;
325                 }
326         }
327
328         if (nbytes == 0) {
329                 if (file_printf(ms, (ms->flags & MAGIC_MIME) ?
330                     "application/x-empty" : "empty") == -1)
331                         goto done;
332         } else if (nbytes == 1) {
333                 if (file_printf(ms, "very short file (no magic)") == -1)
334                         goto done;
335         } else {
336                 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
337 #ifdef __EMX__
338                 switch (file_os2_apptype(ms, inname, buf, nbytes)) {
339                 case -1:
340                         goto done;
341                 case 0:
342                         break;
343                 default:
344                         rv = 0;
345                         goto done;
346                 }
347 #endif
348                 if (file_buffer(ms, fd, buf, (size_t)nbytes) == -1)
349                         goto done;
350 #ifdef BUILTIN_ELF
351                 if (nbytes > 5) {
352                         /*
353                          * We matched something in the file, so this *might*
354                          * be an ELF file, and the file is at least 5 bytes
355                          * long, so if it's an ELF file it has at least one
356                          * byte past the ELF magic number - try extracting
357                          * information from the ELF headers that cannot easily
358                          * be extracted with rules in the magic file.
359                          */
360                         file_tryelf(ms, fd, buf, (size_t)nbytes);
361                 }
362 #endif
363         }
364         rv = 0;
365 done:
366         free(buf);
367         close_and_restore(ms, inname, fd, &sb);
368         return rv == 0 ? file_getbuffer(ms) : NULL;
369 }
370
371
372 public const char *
373 magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
374 {
375         if (file_reset(ms) == -1)
376                 return NULL;
377         /*
378          * The main work is done here!
379          * We have the file name and/or the data buffer to be identified. 
380          */
381         if (file_buffer(ms, -1, buf, nb) == -1) {
382                 return NULL;
383         }
384         return file_getbuffer(ms);
385 }
386 #endif
387
388 public const char *
389 magic_error(struct magic_set *ms)
390 {
391         return ms->haderr ? ms->o.buf : NULL;
392 }
393
394 public int
395 magic_errno(struct magic_set *ms)
396 {
397         return ms->haderr ? ms->error : 0;
398 }
399
400 public int
401 magic_setflags(struct magic_set *ms, int flags)
402 {
403 #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
404         if (flags & MAGIC_PRESERVE_ATIME)
405                 return -1;
406 #endif
407         ms->flags = flags;
408         return 0;
409 }