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>