Annotation of embedaddon/php/ext/fileinfo/libmagic/magic.c, revision 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>