Back to index

php5  5.3.10
magic.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Christos Zoulas 2003.
00003  * All Rights Reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice immediately at the beginning of the file, without modification,
00010  *    this list of conditions, and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00016  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
00019  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00021  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00022  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00023  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00024  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00025  * SUCH DAMAGE.
00026  */
00027 
00028 #include "file.h"
00029 
00030 #ifndef       lint
00031 FILE_RCSID("@(#)$File: magic.c,v 1.62 2009/03/20 21:25:41 christos Exp $")
00032 #endif /* lint */
00033 
00034 #include "magic.h"
00035 
00036 #include <stdlib.h>
00037 #ifdef PHP_WIN32
00038 #include "win32/unistd.h"
00039 #else
00040 #include <unistd.h>
00041 #endif
00042 #include <string.h>
00043 #ifdef PHP_WIN32
00044 # include "config.w32.h"
00045 #else
00046 # include "php_config.h"
00047 #endif
00048 
00049 #include <limits.h>  /* for PIPE_BUF */
00050 
00051 #if defined(HAVE_UTIMES)
00052 # include <sys/time.h>
00053 #elif defined(HAVE_UTIME)
00054 # if defined(HAVE_SYS_UTIME_H)
00055 #  include <sys/utime.h>
00056 # elif defined(HAVE_UTIME_H)
00057 #  include <utime.h>
00058 # endif
00059 #endif
00060 
00061 #ifdef HAVE_UNISTD_H
00062 #include <unistd.h>  /* for read() */
00063 #endif
00064 
00065 #ifndef PHP_WIN32
00066 # include <netinet/in.h>           /* for byte swapping */
00067 #endif
00068 
00069 #include "patchlevel.h"
00070 
00071 #ifndef PIPE_BUF
00072 /* Get the PIPE_BUF from pathconf */
00073 #ifdef _PC_PIPE_BUF
00074 #define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
00075 #else
00076 #define PIPE_BUF 512
00077 #endif
00078 #endif
00079 
00080 #ifdef PHP_WIN32
00081 # undef S_IFLNK
00082 # undef S_IFIFO
00083 #endif
00084 
00085 private void free_mlist(struct mlist *);
00086 private void close_and_restore(const struct magic_set *, const char *, int,
00087     const struct stat *);
00088 private int unreadable_info(struct magic_set *, mode_t, const char *);
00089 private const char *file_or_stream(struct magic_set *, const char *, php_stream *);
00090 
00091 #ifndef       STDIN_FILENO
00092 #define       STDIN_FILENO  0
00093 #endif
00094 
00095 public struct magic_set *
00096 magic_open(int flags)
00097 {
00098        struct magic_set *ms;
00099 
00100        ms = ecalloc((size_t)1, sizeof(struct magic_set));
00101 
00102        if (magic_setflags(ms, flags) == -1) {
00103               errno = EINVAL;
00104               goto free;
00105        }
00106 
00107        ms->o.buf = ms->o.pbuf = NULL;
00108 
00109        ms->c.li = emalloc((ms->c.len = 10) * sizeof(*ms->c.li));
00110        
00111        ms->event_flags = 0;
00112        ms->error = -1;
00113        ms->mlist = NULL;
00114        ms->file = "unknown";
00115        ms->line = 0;
00116        return ms;
00117 free:
00118        efree(ms);
00119        return NULL;
00120 }
00121 
00122 private void
00123 free_mlist(struct mlist *mlist)
00124 {
00125        struct mlist *ml;
00126 
00127        if (mlist == NULL)
00128               return;
00129 
00130        for (ml = mlist->next; ml != mlist;) {
00131               struct mlist *next = ml->next;
00132               struct magic *mg = ml->magic;
00133               file_delmagic(mg, ml->mapped, ml->nmagic);
00134               efree(ml);
00135               ml = next;
00136        }
00137        efree(ml);
00138 }
00139 
00140 private int
00141 unreadable_info(struct magic_set *ms, mode_t md, const char *file)
00142 {
00143        /* We cannot open it, but we were able to stat it. */
00144        if (access(file, W_OK) == 0)
00145               if (file_printf(ms, "writable, ") == -1)
00146                      return -1;
00147        if (access(file, X_OK) == 0)
00148               if (file_printf(ms, "executable, ") == -1)
00149                      return -1;
00150        if (S_ISREG(md))
00151               if (file_printf(ms, "regular file, ") == -1)
00152                      return -1;
00153        if (file_printf(ms, "no read permission") == -1)
00154               return -1;
00155        return 0;
00156 }
00157 
00158 public void
00159 magic_close(struct magic_set *ms)
00160 {
00161        if (ms->mlist) {
00162               free_mlist(ms->mlist);
00163        }
00164        if (ms->o.pbuf) {
00165               efree(ms->o.pbuf);
00166        }
00167        if (ms->o.buf) {
00168               efree(ms->o.buf);
00169        }
00170        if (ms->c.li) {
00171               efree(ms->c.li);
00172        }
00173        efree(ms);
00174 }
00175 
00176 /*
00177  * load a magic file
00178  */
00179 public int
00180 magic_load(struct magic_set *ms, const char *magicfile)
00181 {
00182        struct mlist *ml = file_apprentice(ms, magicfile, FILE_LOAD);
00183        if (ml) {
00184               free_mlist(ms->mlist);
00185               ms->mlist = ml;
00186               return 0;
00187        }
00188        return -1;
00189 }
00190 
00191 public int
00192 magic_compile(struct magic_set *ms, const char *magicfile)
00193 {
00194        struct mlist *ml = file_apprentice(ms, magicfile, FILE_COMPILE);
00195        free_mlist(ml);
00196        return ml ? 0 : -1;
00197 }
00198 
00199 private void
00200 close_and_restore(const struct magic_set *ms, const char *name, int fd,
00201     const struct stat *sb)
00202 {
00203 
00204        if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
00205               /*
00206                * Try to restore access, modification times if read it.
00207                * This is really *bad* because it will modify the status
00208                * time of the file... And of course this will affect
00209                * backup programs
00210                */
00211 #ifdef HAVE_UTIMES
00212               struct timeval  utsbuf[2];
00213               (void)memset(utsbuf, 0, sizeof(utsbuf));
00214               utsbuf[0].tv_sec = sb->st_atime;
00215               utsbuf[1].tv_sec = sb->st_mtime;
00216 
00217               (void) utimes(name, utsbuf); /* don't care if loses */
00218 #elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
00219               struct utimbuf  utbuf;
00220 
00221               (void)memset(&utbuf, 0, sizeof(utbuf));
00222               utbuf.actime = sb->st_atime;
00223               utbuf.modtime = sb->st_mtime;
00224               (void) utime(name, &utbuf); /* don't care if loses */
00225 #endif
00226        }
00227 }
00228 
00229 
00230 /*
00231  * find type of descriptor
00232  */
00233 public const char *
00234 magic_descriptor(struct magic_set *ms, int fd)
00235 {
00236        return file_or_stream(ms, NULL, NULL);
00237 }
00238 
00239 /*
00240  * find type of named file
00241  */
00242 public const char *
00243 magic_file(struct magic_set *ms, const char *inname)
00244 {
00245        return file_or_stream(ms, inname, NULL);
00246 }
00247 
00248 public const char *
00249 magic_stream(struct magic_set *ms, php_stream *stream)
00250 {
00251        return file_or_stream(ms, NULL, stream);
00252 }
00253 
00254 private const char *
00255 file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream)
00256 {
00257        int    rv = -1;
00258        unsigned char *buf;
00259        struct stat   sb;
00260        ssize_t nbytes = 0;  /* number of bytes read from a datafile */
00261        int no_in_stream = 0;
00262        TSRMLS_FETCH();
00263 
00264        if (!inname && !stream) {
00265               return NULL;
00266        }
00267 
00268        /*
00269         * one extra for terminating '\0', and
00270         * some overlapping space for matches near EOF
00271         */
00272 #define SLOP (1 + sizeof(union VALUETYPE))
00273        buf = emalloc(HOWMANY + SLOP);
00274 
00275        if (file_reset(ms) == -1) {
00276               goto done;
00277        }
00278 
00279        switch (file_fsmagic(ms, inname, &sb, stream)) {
00280               case -1:             /* error */
00281                      goto done;
00282               case 0:                     /* nothing found */
00283                      break;
00284               default:             /* matched it and printed type */
00285                      rv = 0;
00286                      goto done;
00287        }
00288 
00289        errno = 0;
00290 
00291        if (!stream && inname) {
00292               no_in_stream = 1;
00293 #if PHP_API_VERSION < 20100412
00294               stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
00295 #else
00296               stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL);
00297 #endif
00298        }
00299 
00300        if (!stream) {
00301               if (unreadable_info(ms, sb.st_mode, inname) == -1)
00302                      goto done;
00303               rv = 0;
00304               goto done;
00305        }
00306 
00307 #ifdef O_NONBLOCK
00308 /* we should be already be in non blocking mode for network socket */
00309 #endif
00310 
00311        /*
00312         * try looking at the first HOWMANY bytes
00313         */
00314        if ((nbytes = php_stream_read(stream, (char *)buf, HOWMANY)) < 0) {
00315               file_error(ms, errno, "cannot read `%s'", inname);
00316               goto done;
00317        }
00318 
00319        (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
00320        if (file_buffer(ms, stream, inname, buf, (size_t)nbytes) == -1)
00321               goto done;
00322        rv = 0;
00323 done:
00324        efree(buf);
00325 
00326        if (no_in_stream && stream) {
00327               php_stream_close(stream);
00328        }
00329 
00330        close_and_restore(ms, inname, 0, &sb);
00331        return rv == 0 ? file_getbuffer(ms) : NULL;
00332 }
00333 
00334 public const char *
00335 magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
00336 {
00337        if (file_reset(ms) == -1)
00338               return NULL;
00339        /*
00340         * The main work is done here!
00341         * We have the file name and/or the data buffer to be identified. 
00342         */
00343        if (file_buffer(ms, NULL, NULL, buf, nb) == -1) {
00344               return NULL;
00345        }
00346        return file_getbuffer(ms);
00347 }
00348 
00349 public const char *
00350 magic_error(struct magic_set *ms)
00351 {
00352        return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
00353 }
00354 
00355 public int
00356 magic_errno(struct magic_set *ms)
00357 {
00358        return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
00359 }
00360 
00361 public int
00362 magic_setflags(struct magic_set *ms, int flags)
00363 {
00364 #if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
00365        if (flags & MAGIC_PRESERVE_ATIME)
00366               return -1;
00367 #endif
00368        ms->flags = flags;
00369        return 0;
00370 }