Annotation of embedaddon/php/ext/fileinfo/libmagic/magic.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>