Annotation of embedaddon/php/ext/fileinfo/libmagic/magic.c, revision 1.1.1.1
1.1 misho 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:
30: #ifndef lint
31: FILE_RCSID("@(#)$File: magic.c,v 1.62 2009/03/20 21:25:41 christos Exp $")
32: #endif /* lint */
33:
34: #include "magic.h"
35:
36: #include <stdlib.h>
37: #ifdef PHP_WIN32
38: #include "win32/unistd.h"
39: #else
40: #include <unistd.h>
41: #endif
42: #include <string.h>
43: #ifdef PHP_WIN32
44: # include "config.w32.h"
45: #else
46: # include "php_config.h"
47: #endif
48:
49: #include <limits.h> /* for PIPE_BUF */
50:
51: #if defined(HAVE_UTIMES)
52: # include <sys/time.h>
53: #elif defined(HAVE_UTIME)
54: # if defined(HAVE_SYS_UTIME_H)
55: # include <sys/utime.h>
56: # elif defined(HAVE_UTIME_H)
57: # include <utime.h>
58: # endif
59: #endif
60:
61: #ifdef HAVE_UNISTD_H
62: #include <unistd.h> /* for read() */
63: #endif
64:
65: #ifndef PHP_WIN32
66: # include <netinet/in.h> /* for byte swapping */
67: #endif
68:
69: #include "patchlevel.h"
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 PHP_WIN32
81: # undef S_IFLNK
82: # undef S_IFIFO
83: #endif
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 *);
88: private int unreadable_info(struct magic_set *, mode_t, const char *);
89: private const char *file_or_stream(struct magic_set *, const char *, php_stream *);
90:
91: #ifndef STDIN_FILENO
92: #define STDIN_FILENO 0
93: #endif
94:
95: public struct magic_set *
96: magic_open(int flags)
97: {
98: struct magic_set *ms;
99:
100: ms = ecalloc((size_t)1, sizeof(struct magic_set));
101:
102: if (magic_setflags(ms, flags) == -1) {
103: errno = EINVAL;
104: goto free;
105: }
106:
107: ms->o.buf = ms->o.pbuf = NULL;
108:
109: ms->c.li = emalloc((ms->c.len = 10) * sizeof(*ms->c.li));
110:
111: ms->event_flags = 0;
112: ms->error = -1;
113: ms->mlist = NULL;
114: ms->file = "unknown";
115: ms->line = 0;
116: return ms;
117: free:
118: efree(ms);
119: return NULL;
120: }
121:
122: private void
123: free_mlist(struct mlist *mlist)
124: {
125: struct mlist *ml;
126:
127: if (mlist == NULL)
128: return;
129:
130: for (ml = mlist->next; ml != mlist;) {
131: struct mlist *next = ml->next;
132: struct magic *mg = ml->magic;
133: file_delmagic(mg, ml->mapped, ml->nmagic);
134: efree(ml);
135: ml = next;
136: }
137: efree(ml);
138: }
139:
140: private int
141: unreadable_info(struct magic_set *ms, mode_t md, const char *file)
142: {
143: /* We cannot open it, but we were able to stat it. */
144: if (access(file, W_OK) == 0)
145: if (file_printf(ms, "writable, ") == -1)
146: return -1;
147: if (access(file, X_OK) == 0)
148: if (file_printf(ms, "executable, ") == -1)
149: return -1;
150: if (S_ISREG(md))
151: if (file_printf(ms, "regular file, ") == -1)
152: return -1;
153: if (file_printf(ms, "no read permission") == -1)
154: return -1;
155: return 0;
156: }
157:
158: public void
159: magic_close(struct magic_set *ms)
160: {
161: if (ms->mlist) {
162: free_mlist(ms->mlist);
163: }
164: if (ms->o.pbuf) {
165: efree(ms->o.pbuf);
166: }
167: if (ms->o.buf) {
168: efree(ms->o.buf);
169: }
170: if (ms->c.li) {
171: efree(ms->c.li);
172: }
173: efree(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: private void
200: close_and_restore(const struct magic_set *ms, const char *name, int fd,
201: const struct stat *sb)
202: {
203:
204: if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
205: /*
206: * Try to restore access, modification times if read it.
207: * This is really *bad* because it will modify the status
208: * time of the file... And of course this will affect
209: * backup programs
210: */
211: #ifdef HAVE_UTIMES
212: struct timeval utsbuf[2];
213: (void)memset(utsbuf, 0, sizeof(utsbuf));
214: utsbuf[0].tv_sec = sb->st_atime;
215: utsbuf[1].tv_sec = sb->st_mtime;
216:
217: (void) utimes(name, utsbuf); /* don't care if loses */
218: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
219: struct utimbuf utbuf;
220:
221: (void)memset(&utbuf, 0, sizeof(utbuf));
222: utbuf.actime = sb->st_atime;
223: utbuf.modtime = sb->st_mtime;
224: (void) utime(name, &utbuf); /* don't care if loses */
225: #endif
226: }
227: }
228:
229:
230: /*
231: * find type of descriptor
232: */
233: public const char *
234: magic_descriptor(struct magic_set *ms, int fd)
235: {
236: return file_or_stream(ms, NULL, NULL);
237: }
238:
239: /*
240: * find type of named file
241: */
242: public const char *
243: magic_file(struct magic_set *ms, const char *inname)
244: {
245: return file_or_stream(ms, inname, NULL);
246: }
247:
248: public const char *
249: magic_stream(struct magic_set *ms, php_stream *stream)
250: {
251: return file_or_stream(ms, NULL, stream);
252: }
253:
254: private const char *
255: file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream)
256: {
257: int rv = -1;
258: unsigned char *buf;
259: struct stat sb;
260: ssize_t nbytes = 0; /* number of bytes read from a datafile */
261: int no_in_stream = 0;
262: TSRMLS_FETCH();
263:
264: if (!inname && !stream) {
265: return NULL;
266: }
267:
268: /*
269: * one extra for terminating '\0', and
270: * some overlapping space for matches near EOF
271: */
272: #define SLOP (1 + sizeof(union VALUETYPE))
273: buf = emalloc(HOWMANY + SLOP);
274:
275: if (file_reset(ms) == -1) {
276: goto done;
277: }
278:
279: switch (file_fsmagic(ms, inname, &sb, stream)) {
280: case -1: /* error */
281: goto done;
282: case 0: /* nothing found */
283: break;
284: default: /* matched it and printed type */
285: rv = 0;
286: goto done;
287: }
288:
289: errno = 0;
290:
291: if (!stream && inname) {
292: no_in_stream = 1;
293: #if PHP_API_VERSION < 20100412
294: stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
295: #else
296: stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL);
297: #endif
298: }
299:
300: if (!stream) {
301: if (unreadable_info(ms, sb.st_mode, inname) == -1)
302: goto done;
303: rv = 0;
304: goto done;
305: }
306:
307: #ifdef O_NONBLOCK
308: /* we should be already be in non blocking mode for network socket */
309: #endif
310:
311: /*
312: * try looking at the first HOWMANY bytes
313: */
314: if ((nbytes = php_stream_read(stream, (char *)buf, HOWMANY)) < 0) {
315: file_error(ms, errno, "cannot read `%s'", inname);
316: goto done;
317: }
318:
319: (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
320: if (file_buffer(ms, stream, inname, buf, (size_t)nbytes) == -1)
321: goto done;
322: rv = 0;
323: done:
324: efree(buf);
325:
326: if (no_in_stream && stream) {
327: php_stream_close(stream);
328: }
329:
330: close_and_restore(ms, inname, 0, &sb);
331: return rv == 0 ? file_getbuffer(ms) : NULL;
332: }
333:
334: public const char *
335: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
336: {
337: if (file_reset(ms) == -1)
338: return NULL;
339: /*
340: * The main work is done here!
341: * We have the file name and/or the data buffer to be identified.
342: */
343: if (file_buffer(ms, NULL, NULL, buf, nb) == -1) {
344: return NULL;
345: }
346: return file_getbuffer(ms);
347: }
348:
349: public const char *
350: magic_error(struct magic_set *ms)
351: {
352: return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
353: }
354:
355: public int
356: magic_errno(struct magic_set *ms)
357: {
358: return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
359: }
360:
361: public int
362: magic_setflags(struct magic_set *ms, int flags)
363: {
364: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
365: if (flags & MAGIC_PRESERVE_ATIME)
366: return -1;
367: #endif
368: ms->flags = flags;
369: return 0;
370: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>