Upgrade to file-4.18.
[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 #include <fcntl.h>      /* for open() */
39 #ifdef QUICK
40 #include <sys/mman.h>
41 #endif
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.28 2005/06/25 15:52:14 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
79 public struct magic_set *
80 magic_open(int flags)
81 {
82         struct magic_set *ms;
83
84         if ((ms = malloc(sizeof(struct magic_set))) == NULL)
85                 return NULL;
86
87         if (magic_setflags(ms, flags) == -1) {
88                 errno = EINVAL;
89                 goto free1;
90         }
91
92         ms->o.ptr = ms->o.buf = malloc(ms->o.size = 1024);
93         if (ms->o.buf == NULL)
94                 goto free1;
95
96         ms->o.pbuf = malloc(ms->o.psize = 1024);
97         if (ms->o.pbuf == NULL)
98                 goto free2;
99
100         ms->c.off = malloc((ms->c.len = 10) * sizeof(*ms->c.off));
101         if (ms->c.off == NULL)
102                 goto free3;
103         
104         ms->o.len = 0;
105         ms->haderr = 0;
106         ms->error = -1;
107         ms->mlist = NULL;
108         return ms;
109 free3:
110         free(ms->o.pbuf);
111 free2:
112         free(ms->o.buf);
113 free1:
114         free(ms);
115         return NULL;
116 }
117
118 private void
119 free_mlist(struct mlist *mlist)
120 {
121         struct mlist *ml;
122
123         if (mlist == NULL)
124                 return;
125
126         for (ml = mlist->next; ml != mlist;) {
127                 struct mlist *next = ml->next;
128                 struct magic *mg = ml->magic;
129                 file_delmagic(mg, ml->mapped, ml->nmagic);
130                 free(ml);
131                 ml = next;
132         }
133         free(ml);
134 }
135
136 public void
137 magic_close(ms)
138     struct magic_set *ms;
139 {
140         free_mlist(ms->mlist);
141         free(ms->o.pbuf);
142         free(ms->o.buf);
143         free(ms->c.off);
144         free(ms);
145 }
146
147 /*
148  * load a magic file
149  */
150 public int
151 magic_load(struct magic_set *ms, const char *magicfile)
152 {
153         struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
154         if (ml) {
155                 free_mlist(ms->mlist);
156                 ms->mlist = ml;
157                 return 0;
158         }
159         return -1;
160 }
161
162 public int
163 magic_compile(struct magic_set *ms, const char *magicfile)
164 {
165         struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
166         free_mlist(ml);
167         return ml ? 0 : -1;
168 }
169
170 public int
171 magic_check(struct magic_set *ms, const char *magicfile)
172 {
173         struct mlist *ml = file_apprentice(ms, magicfile, FILE_CHECK);
174         free_mlist(ml);
175         return ml ? 0 : -1;
176 }
177
178 private void
179 close_and_restore(const struct magic_set *ms, const char *name, int fd,
180     const struct stat *sb)
181 {
182         (void) close(fd);
183         if (fd != STDIN_FILENO && (ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
184                 /*
185                  * Try to restore access, modification times if read it.
186                  * This is really *bad* because it will modify the status
187                  * time of the file... And of course this will affect
188                  * backup programs
189                  */
190 #ifdef HAVE_UTIMES
191                 struct timeval  utsbuf[2];
192                 utsbuf[0].tv_sec = sb->st_atime;
193                 utsbuf[1].tv_sec = sb->st_mtime;
194
195                 (void) utimes(name, utsbuf); /* don't care if loses */
196 #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
197                 struct utimbuf  utbuf;
198
199                 utbuf.actime = sb->st_atime;
200                 utbuf.modtime = sb->st_mtime;
201                 (void) utime(name, &utbuf); /* don't care if loses */
202 #endif
203         }
204 }
205
206 #ifndef COMPILE_ONLY
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         int     rv = -1;
215         unsigned char *buf;
216         struct stat     sb;
217         ssize_t nbytes = 0;     /* number of bytes read from a datafile */
218
219         /*
220          * one extra for terminating '\0', and
221          * some overlapping space for matches near EOF
222          */
223 #define SLOP (1 + sizeof(union VALUETYPE))
224         if ((buf = malloc(HOWMANY + SLOP)) == NULL)
225                 return NULL;
226
227         if (file_reset(ms) == -1)
228                 goto done;
229
230         switch (file_fsmagic(ms, inname, &sb)) {
231         case -1:
232                 goto done;
233         case 0:
234                 break;
235         default:
236                 rv = 0;
237                 goto done;
238         }
239
240 #ifndef STDIN_FILENO
241 #define STDIN_FILENO    0
242 #endif
243         if (inname == NULL)
244                 fd = STDIN_FILENO;
245         else if ((fd = open(inname, O_RDONLY)) < 0) {
246                 /* We cannot open it, but we were able to stat it. */
247                 if (sb.st_mode & 0222)
248                         if (file_printf(ms, "writable, ") == -1)
249                                 goto done;
250                 if (sb.st_mode & 0111)
251                         if (file_printf(ms, "executable, ") == -1)
252                                 goto done;
253                 if (S_ISREG(sb.st_mode))
254                         if (file_printf(ms, "regular file, ") == -1)
255                                 goto done;
256                 if (file_printf(ms, "no read permission") == -1)
257                         goto done;
258                 rv = 0;
259                 goto done;
260         }
261
262         /*
263          * try looking at the first HOWMANY bytes
264          */
265         if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
266                 file_error(ms, errno, "cannot read `%s'", inname);
267                 goto done;
268         }
269
270         if (nbytes == 0) {
271                 if (file_printf(ms, (ms->flags & MAGIC_MIME) ?
272                     "application/x-empty" : "empty") == -1)
273                         goto done;
274         } else if (nbytes == 1) {
275                 if (file_printf(ms, "very short file (no magic)") == -1)
276                         goto done;
277         } else {
278                 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
279 #ifdef __EMX__
280                 switch (file_os2_apptype(ms, inname, buf, nbytes)) {
281                 case -1:
282                         goto done;
283                 case 0:
284                         break;
285                 default:
286                         rv = 0;
287                         goto done;
288                 }
289 #endif
290                 if (file_buffer(ms, fd, buf, (size_t)nbytes) == -1)
291                         goto done;
292 #ifdef BUILTIN_ELF
293                 if (nbytes > 5) {
294                         /*
295                          * We matched something in the file, so this *might*
296                          * be an ELF file, and the file is at least 5 bytes
297                          * long, so if it's an ELF file it has at least one
298                          * byte past the ELF magic number - try extracting
299                          * information from the ELF headers that cannot easily
300                          * be extracted with rules in the magic file.
301                          */
302                         file_tryelf(ms, fd, buf, (size_t)nbytes);
303                 }
304 #endif
305         }
306         rv = 0;
307 done:
308         free(buf);
309         close_and_restore(ms, inname, fd, &sb);
310         return rv == 0 ? file_getbuffer(ms) : NULL;
311 }
312
313
314 public const char *
315 magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
316 {
317         if (file_reset(ms) == -1)
318                 return NULL;
319         /*
320          * The main work is done here!
321          * We have the file name and/or the data buffer to be identified. 
322          */
323         if (file_buffer(ms, -1, buf, nb) == -1) {
324                 return NULL;
325         }
326         return file_getbuffer(ms);
327 }
328 #endif
329
330 public const char *
331 magic_error(struct magic_set *ms)
332 {
333         return ms->haderr ? ms->o.buf : NULL;
334 }
335
336 public int
337 magic_errno(struct magic_set *ms)
338 {
339         return ms->haderr ? ms->error : 0;
340 }
341
342 public int
343 magic_setflags(struct magic_set *ms, int flags)
344 {
345 #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
346         if (flags & MAGIC_PRESERVE_ATIME)
347                 return -1;
348 #endif
349         ms->flags = flags;
350         return 0;
351 }