Annotation of embedaddon/php/ext/fileinfo/libmagic/magic.c, revision 1.1.1.2
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
1.1.1.2 ! misho 31: FILE_RCSID("@(#)$File: magic.c,v 1.74 2011/05/26 01:27:59 christos Exp $")
1.1 misho 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:
1.1.1.2 ! misho 49: #ifdef PHP_WIN32
! 50: #include <shlwapi.h>
! 51: #endif
! 52:
1.1 misho 53: #include <limits.h> /* for PIPE_BUF */
54:
55: #if defined(HAVE_UTIMES)
56: # include <sys/time.h>
57: #elif defined(HAVE_UTIME)
58: # if defined(HAVE_SYS_UTIME_H)
59: # include <sys/utime.h>
60: # elif defined(HAVE_UTIME_H)
61: # include <utime.h>
62: # endif
63: #endif
64:
65: #ifdef HAVE_UNISTD_H
66: #include <unistd.h> /* for read() */
67: #endif
68:
69: #ifndef PIPE_BUF
70: /* Get the PIPE_BUF from pathconf */
71: #ifdef _PC_PIPE_BUF
72: #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
73: #else
74: #define PIPE_BUF 512
75: #endif
76: #endif
77:
78: #ifdef PHP_WIN32
79: # undef S_IFLNK
80: # undef S_IFIFO
81: #endif
82:
83: private void free_mlist(struct mlist *);
84: private void close_and_restore(const struct magic_set *, const char *, int,
85: const struct stat *);
86: private int unreadable_info(struct magic_set *, mode_t, const char *);
1.1.1.2 ! misho 87: private const char* get_default_magic(void);
1.1 misho 88: private const char *file_or_stream(struct magic_set *, const char *, php_stream *);
89:
90: #ifndef STDIN_FILENO
91: #define STDIN_FILENO 0
92: #endif
93:
1.1.1.2 ! misho 94: /* XXX this functionality is excluded in php, enable it in apprentice.c:340 */
! 95: #if 0
! 96: private const char *
! 97: get_default_magic(void)
! 98: {
! 99: static const char hmagic[] = "/.magic/magic.mgc";
! 100: static char *default_magic;
! 101: char *home, *hmagicpath;
! 102:
! 103: #ifndef PHP_WIN32
! 104: struct stat st;
! 105:
! 106: if (default_magic) {
! 107: free(default_magic);
! 108: default_magic = NULL;
! 109: }
! 110: if ((home = getenv("HOME")) == NULL)
! 111: return MAGIC;
! 112:
! 113: if (asprintf(&hmagicpath, "%s/.magic", home) < 0)
! 114: return MAGIC;
! 115: if (stat(hmagicpath, &st) == -1)
! 116: goto out;
! 117: if (S_ISDIR(st.st_mode)) {
! 118: free(hmagicpath);
! 119: if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0)
! 120: return MAGIC;
! 121: if (access(hmagicpath, R_OK) == -1)
! 122: goto out;
! 123: }
! 124:
! 125: if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0)
! 126: goto out;
! 127: free(hmagicpath);
! 128: return default_magic;
! 129: out:
! 130: default_magic = NULL;
! 131: free(hmagicpath);
! 132: return MAGIC;
! 133: #else
! 134: char *hmagicp = hmagicpath;
! 135: char *tmppath = NULL;
! 136: LPTSTR dllpath;
! 137:
! 138: #define APPENDPATH() \
! 139: do { \
! 140: if (tmppath && access(tmppath, R_OK) != -1) { \
! 141: if (hmagicpath == NULL) \
! 142: hmagicpath = tmppath; \
! 143: else { \
! 144: if (asprintf(&hmagicp, "%s%c%s", hmagicpath, \
! 145: PATHSEP, tmppath) >= 0) { \
! 146: free(hmagicpath); \
! 147: hmagicpath = hmagicp; \
! 148: } \
! 149: free(tmppath); \
! 150: } \
! 151: tmppath = NULL; \
! 152: } \
! 153: } while (/*CONSTCOND*/0)
! 154:
! 155: if (default_magic) {
! 156: free(default_magic);
! 157: default_magic = NULL;
! 158: }
! 159:
! 160: /* First, try to get user-specific magic file */
! 161: if ((home = getenv("LOCALAPPDATA")) == NULL) {
! 162: if ((home = getenv("USERPROFILE")) != NULL)
! 163: if (asprintf(&tmppath,
! 164: "%s/Local Settings/Application Data%s", home,
! 165: hmagic) < 0)
! 166: tmppath = NULL;
! 167: } else {
! 168: if (asprintf(&tmppath, "%s%s", home, hmagic) < 0)
! 169: tmppath = NULL;
! 170: }
! 171:
! 172: APPENDPATH();
! 173:
! 174: /* Second, try to get a magic file from Common Files */
! 175: if ((home = getenv("COMMONPROGRAMFILES")) != NULL) {
! 176: if (asprintf(&tmppath, "%s%s", home, hmagic) >= 0)
! 177: APPENDPATH();
! 178: }
! 179:
! 180: /* Third, try to get magic file relative to dll location */
! 181: dllpath = malloc(sizeof(*dllpath) * (MAX_PATH + 1));
! 182: dllpath[MAX_PATH] = 0; /* just in case long path gets truncated and not null terminated */
! 183: if (GetModuleFileNameA(NULL, dllpath, MAX_PATH)){
! 184: PathRemoveFileSpecA(dllpath);
! 185: if (strlen(dllpath) > 3 &&
! 186: stricmp(&dllpath[strlen(dllpath) - 3], "bin") == 0) {
! 187: if (asprintf(&tmppath,
! 188: "%s/../share/misc/magic.mgc", dllpath) >= 0)
! 189: APPENDPATH();
! 190: } else {
! 191: if (asprintf(&tmppath,
! 192: "%s/share/misc/magic.mgc", dllpath) >= 0)
! 193: APPENDPATH();
! 194: else if (asprintf(&tmppath,
! 195: "%s/magic.mgc", dllpath) >= 0)
! 196: APPENDPATH();
! 197: }
! 198: }
! 199:
! 200: /* Don't put MAGIC constant - it likely points to a file within MSys
! 201: tree */
! 202: default_magic = hmagicpath;
! 203: return default_magic;
! 204: #endif
! 205: }
! 206:
! 207: public const char *
! 208: magic_getpath(const char *magicfile, int action)
! 209: {
! 210: if (magicfile != NULL)
! 211: return magicfile;
! 212:
! 213: magicfile = getenv("MAGIC");
! 214: if (magicfile != NULL)
! 215: return magicfile;
! 216:
! 217: return action == FILE_LOAD ? get_default_magic() : MAGIC;
! 218: }
! 219: #endif
! 220:
1.1 misho 221: public struct magic_set *
222: magic_open(int flags)
223: {
224: struct magic_set *ms;
225:
226: ms = ecalloc((size_t)1, sizeof(struct magic_set));
227:
228: if (magic_setflags(ms, flags) == -1) {
229: errno = EINVAL;
230: goto free;
231: }
232:
233: ms->o.buf = ms->o.pbuf = NULL;
234:
235: ms->c.li = emalloc((ms->c.len = 10) * sizeof(*ms->c.li));
236:
237: ms->event_flags = 0;
238: ms->error = -1;
239: ms->mlist = NULL;
240: ms->file = "unknown";
241: ms->line = 0;
242: return ms;
243: free:
244: efree(ms);
245: return NULL;
246: }
247:
248: private void
249: free_mlist(struct mlist *mlist)
250: {
251: struct mlist *ml;
252:
253: if (mlist == NULL)
254: return;
255:
256: for (ml = mlist->next; ml != mlist;) {
257: struct mlist *next = ml->next;
258: struct magic *mg = ml->magic;
259: file_delmagic(mg, ml->mapped, ml->nmagic);
260: efree(ml);
261: ml = next;
262: }
263: efree(ml);
264: }
265:
266: private int
267: unreadable_info(struct magic_set *ms, mode_t md, const char *file)
268: {
269: /* We cannot open it, but we were able to stat it. */
270: if (access(file, W_OK) == 0)
271: if (file_printf(ms, "writable, ") == -1)
272: return -1;
273: if (access(file, X_OK) == 0)
274: if (file_printf(ms, "executable, ") == -1)
275: return -1;
276: if (S_ISREG(md))
277: if (file_printf(ms, "regular file, ") == -1)
278: return -1;
279: if (file_printf(ms, "no read permission") == -1)
280: return -1;
281: return 0;
282: }
283:
284: public void
285: magic_close(struct magic_set *ms)
286: {
287: if (ms->mlist) {
288: free_mlist(ms->mlist);
289: }
290: if (ms->o.pbuf) {
291: efree(ms->o.pbuf);
292: }
293: if (ms->o.buf) {
294: efree(ms->o.buf);
295: }
296: if (ms->c.li) {
297: efree(ms->c.li);
298: }
299: efree(ms);
300: }
301:
302: /*
303: * load a magic file
304: */
305: public int
306: magic_load(struct magic_set *ms, const char *magicfile)
307: {
308: struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
309: if (ml) {
310: free_mlist(ms->mlist);
311: ms->mlist = ml;
312: return 0;
313: }
314: return -1;
315: }
316:
317: public int
318: magic_compile(struct magic_set *ms, const char *magicfile)
319: {
320: struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
321: free_mlist(ml);
322: return ml ? 0 : -1;
323: }
324:
1.1.1.2 ! misho 325:
! 326: public int
! 327: magic_list(struct magic_set *ms, const char *magicfile)
! 328: {
! 329: struct mlist *ml = file_apprentice(ms, magicfile, FILE_LIST);
! 330: free_mlist(ml);
! 331: return ml ? 0 : -1;
! 332: }
! 333:
1.1 misho 334: private void
335: close_and_restore(const struct magic_set *ms, const char *name, int fd,
336: const struct stat *sb)
337: {
338:
339: if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
340: /*
341: * Try to restore access, modification times if read it.
342: * This is really *bad* because it will modify the status
343: * time of the file... And of course this will affect
344: * backup programs
345: */
346: #ifdef HAVE_UTIMES
347: struct timeval utsbuf[2];
348: (void)memset(utsbuf, 0, sizeof(utsbuf));
349: utsbuf[0].tv_sec = sb->st_atime;
350: utsbuf[1].tv_sec = sb->st_mtime;
351:
352: (void) utimes(name, utsbuf); /* don't care if loses */
353: #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
354: struct utimbuf utbuf;
355:
356: (void)memset(&utbuf, 0, sizeof(utbuf));
357: utbuf.actime = sb->st_atime;
358: utbuf.modtime = sb->st_mtime;
359: (void) utime(name, &utbuf); /* don't care if loses */
360: #endif
361: }
362: }
363:
364:
365: /*
366: * find type of descriptor
367: */
368: public const char *
369: magic_descriptor(struct magic_set *ms, int fd)
370: {
371: return file_or_stream(ms, NULL, NULL);
372: }
373:
374: /*
375: * find type of named file
376: */
377: public const char *
378: magic_file(struct magic_set *ms, const char *inname)
379: {
380: return file_or_stream(ms, inname, NULL);
381: }
382:
383: public const char *
384: magic_stream(struct magic_set *ms, php_stream *stream)
385: {
386: return file_or_stream(ms, NULL, stream);
387: }
388:
389: private const char *
390: file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream)
391: {
392: int rv = -1;
393: unsigned char *buf;
394: struct stat sb;
395: ssize_t nbytes = 0; /* number of bytes read from a datafile */
396: int no_in_stream = 0;
397: TSRMLS_FETCH();
398:
399: if (!inname && !stream) {
400: return NULL;
401: }
402:
403: /*
404: * one extra for terminating '\0', and
405: * some overlapping space for matches near EOF
406: */
407: #define SLOP (1 + sizeof(union VALUETYPE))
408: buf = emalloc(HOWMANY + SLOP);
409:
1.1.1.2 ! misho 410: if (file_reset(ms) == -1)
1.1 misho 411: goto done;
412:
413: switch (file_fsmagic(ms, inname, &sb, stream)) {
1.1.1.2 ! misho 414: case -1: /* error */
! 415: goto done;
! 416: case 0: /* nothing found */
! 417: break;
! 418: default: /* matched it and printed type */
! 419: rv = 0;
! 420: goto done;
1.1 misho 421: }
422:
423: errno = 0;
424:
425: if (!stream && inname) {
426: no_in_stream = 1;
427: #if PHP_API_VERSION < 20100412
428: stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
429: #else
430: stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL);
431: #endif
432: }
433:
434: if (!stream) {
435: if (unreadable_info(ms, sb.st_mode, inname) == -1)
436: goto done;
437: rv = 0;
438: goto done;
439: }
440:
441: #ifdef O_NONBLOCK
442: /* we should be already be in non blocking mode for network socket */
443: #endif
444:
445: /*
446: * try looking at the first HOWMANY bytes
447: */
448: if ((nbytes = php_stream_read(stream, (char *)buf, HOWMANY)) < 0) {
449: file_error(ms, errno, "cannot read `%s'", inname);
450: goto done;
451: }
452:
453: (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
454: if (file_buffer(ms, stream, inname, buf, (size_t)nbytes) == -1)
455: goto done;
456: rv = 0;
457: done:
458: efree(buf);
459:
460: if (no_in_stream && stream) {
461: php_stream_close(stream);
462: }
463:
464: close_and_restore(ms, inname, 0, &sb);
465: return rv == 0 ? file_getbuffer(ms) : NULL;
466: }
467:
1.1.1.2 ! misho 468:
1.1 misho 469: public const char *
470: magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
471: {
472: if (file_reset(ms) == -1)
473: return NULL;
474: /*
475: * The main work is done here!
476: * We have the file name and/or the data buffer to be identified.
477: */
478: if (file_buffer(ms, NULL, NULL, buf, nb) == -1) {
479: return NULL;
480: }
481: return file_getbuffer(ms);
482: }
483:
484: public const char *
485: magic_error(struct magic_set *ms)
486: {
487: return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
488: }
489:
490: public int
491: magic_errno(struct magic_set *ms)
492: {
493: return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
494: }
495:
496: public int
497: magic_setflags(struct magic_set *ms, int flags)
498: {
499: #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
500: if (flags & MAGIC_PRESERVE_ATIME)
501: return -1;
502: #endif
503: ms->flags = flags;
504: return 0;
505: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>