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