Annotation of embedaddon/php/Zend/zend_stream.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | Zend Engine                                                          |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 2.00 of the Zend license,     |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.zend.com/license/2_00.txt.                                |
        !            11:    | If you did not receive a copy of the Zend license and are unable to  |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@zend.com so we can mail you a copy immediately.              |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Authors: Wez Furlong <wez@thebrainroom.com>                          |
        !            16:    |          Scott MacVicar <scottmac@php.net>                           |
        !            17:    |          Nuno Lopes <nlopess@php.net>                                |
        !            18:    |          Marcus Boerger <helly@php.net>                              |
        !            19:    +----------------------------------------------------------------------+
        !            20: */
        !            21: 
        !            22: /* $Id: zend_stream.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            23: 
        !            24: 
        !            25: #include "zend.h"
        !            26: #include "zend_compile.h"
        !            27: 
        !            28: #include <sys/types.h>
        !            29: #include <sys/stat.h>
        !            30: #if HAVE_MMAP
        !            31: # if HAVE_UNISTD_H
        !            32: #  include <unistd.h>
        !            33: #  if defined(_SC_PAGESIZE)
        !            34: #    define REAL_PAGE_SIZE sysconf(_SC_PAGESIZE);
        !            35: #  elif defined(_SC_PAGE_SIZE)
        !            36: #    define REAL_PAGE_SIZE sysconf(_SC_PAGE_SIZE);
        !            37: #  endif
        !            38: # endif
        !            39: # if HAVE_SYS_MMAN_H
        !            40: #  include <sys/mman.h>
        !            41: # endif
        !            42: # ifndef REAL_PAGE_SIZE
        !            43: #  ifdef PAGE_SIZE
        !            44: #   define REAL_PAGE_SIZE PAGE_SIZE
        !            45: #  else
        !            46: #   define REAL_PAGE_SIZE 4096
        !            47: #  endif
        !            48: # endif
        !            49: #endif
        !            50: 
        !            51: ZEND_DLIMPORT int isatty(int fd);
        !            52: 
        !            53: static size_t zend_stream_stdio_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
        !            54: {
        !            55:        return fread(buf, 1, len, (FILE*)handle);
        !            56: } /* }}} */
        !            57: 
        !            58: static void zend_stream_stdio_closer(void *handle TSRMLS_DC) /* {{{ */
        !            59: {
        !            60:        if (handle && (FILE*)handle != stdin) {
        !            61:                fclose((FILE*)handle);
        !            62:        }
        !            63: } /* }}} */
        !            64: 
        !            65: static size_t zend_stream_stdio_fsizer(void *handle TSRMLS_DC) /* {{{ */
        !            66: {
        !            67:        struct stat buf;
        !            68:        if (handle && fstat(fileno((FILE*)handle), &buf) == 0) {
        !            69: #ifdef S_ISREG
        !            70:                if (!S_ISREG(buf.st_mode)) {
        !            71:                        return 0;
        !            72:                }
        !            73: #endif
        !            74:                return buf.st_size;
        !            75:        }
        !            76:        return 0;
        !            77: } /* }}} */
        !            78: 
        !            79: static void zend_stream_unmap(zend_stream *stream TSRMLS_DC) { /* {{{ */
        !            80: #if HAVE_MMAP
        !            81:        if (stream->mmap.map) {
        !            82:                munmap(stream->mmap.map, stream->mmap.len);
        !            83:        } else
        !            84: #endif
        !            85:        if (stream->mmap.buf) {
        !            86:                efree(stream->mmap.buf);
        !            87:        }
        !            88:        stream->mmap.len = 0;
        !            89:        stream->mmap.pos = 0;
        !            90:        stream->mmap.map = 0;
        !            91:        stream->mmap.buf = 0;
        !            92:        stream->handle   = stream->mmap.old_handle;
        !            93: } /* }}} */
        !            94: 
        !            95: static void zend_stream_mmap_closer(zend_stream *stream TSRMLS_DC) /* {{{ */
        !            96: {
        !            97:        zend_stream_unmap(stream TSRMLS_CC);
        !            98:        if (stream->mmap.old_closer && stream->handle) {
        !            99:                stream->mmap.old_closer(stream->handle TSRMLS_CC);
        !           100:        }
        !           101: } /* }}} */
        !           102: 
        !           103: static inline int zend_stream_is_mmap(zend_file_handle *file_handle) { /* {{{ */
        !           104:        return file_handle->type == ZEND_HANDLE_MAPPED;
        !           105: } /* }}} */
        !           106: 
        !           107: static size_t zend_stream_fsize(zend_file_handle *file_handle TSRMLS_DC) /* {{{ */
        !           108: {
        !           109:        struct stat buf;
        !           110: 
        !           111:        if (zend_stream_is_mmap(file_handle)) {
        !           112:                return file_handle->handle.stream.mmap.len;
        !           113:        }
        !           114:        if (file_handle->type == ZEND_HANDLE_STREAM || file_handle->type == ZEND_HANDLE_MAPPED) {
        !           115:                return file_handle->handle.stream.fsizer(file_handle->handle.stream.handle TSRMLS_CC);
        !           116:        }
        !           117:        if (file_handle->handle.fp && fstat(fileno(file_handle->handle.fp), &buf) == 0) {
        !           118: #ifdef S_ISREG
        !           119:                if (!S_ISREG(buf.st_mode)) {
        !           120:                        return 0;
        !           121:                }
        !           122: #endif
        !           123:                return buf.st_size;
        !           124:        }
        !           125: 
        !           126:        return -1;
        !           127: } /* }}} */
        !           128: 
        !           129: ZEND_API int zend_stream_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */
        !           130: {
        !           131:        if (zend_stream_open_function) {
        !           132:                return zend_stream_open_function(filename, handle TSRMLS_CC);
        !           133:        }
        !           134:        handle->type = ZEND_HANDLE_FP;
        !           135:        handle->opened_path = NULL;
        !           136:        handle->handle.fp = zend_fopen(filename, &handle->opened_path TSRMLS_CC);
        !           137:        handle->filename = (char *)filename;
        !           138:        handle->free_filename = 0;
        !           139:        memset(&handle->handle.stream.mmap, 0, sizeof(zend_mmap));
        !           140:        
        !           141:        return (handle->handle.fp) ? SUCCESS : FAILURE;
        !           142: } /* }}} */
        !           143: 
        !           144: static int zend_stream_getc(zend_file_handle *file_handle TSRMLS_DC) /* {{{ */
        !           145: {
        !           146:        char buf;
        !           147: 
        !           148:        if (file_handle->handle.stream.reader(file_handle->handle.stream.handle, &buf, sizeof(buf) TSRMLS_CC)) {
        !           149:                return (int)buf;
        !           150:        }
        !           151:        return EOF;
        !           152: } /* }}} */
        !           153: 
        !           154: static size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
        !           155: {
        !           156:        if (!zend_stream_is_mmap(file_handle) && file_handle->handle.stream.isatty) {
        !           157:                int c = '*';
        !           158:                size_t n;
        !           159: 
        !           160: #ifdef NETWARE
        !           161:                /*
        !           162:                        c != 4 check is there as fread of a character in NetWare LibC gives 4 upon ^D character.
        !           163:                        Ascii value 4 is actually EOT character which is not defined anywhere in the LibC
        !           164:                        or else we can use instead of hardcoded 4.
        !           165:                */
        !           166:                for (n = 0; n < len && (c = zend_stream_getc(file_handle TSRMLS_CC)) != EOF && c != 4 && c != '\n'; ++n) {
        !           167: #else
        !           168:                for (n = 0; n < len && (c = zend_stream_getc(file_handle TSRMLS_CC)) != EOF && c != '\n'; ++n)  {
        !           169: #endif
        !           170:                        buf[n] = (char)c;
        !           171:                }
        !           172:                if (c == '\n') {
        !           173:                        buf[n++] = (char)c; 
        !           174:                }
        !           175: 
        !           176:                return n;
        !           177:        }
        !           178:        return file_handle->handle.stream.reader(file_handle->handle.stream.handle, buf, len TSRMLS_CC);
        !           179: } /* }}} */
        !           180: 
        !           181: ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len TSRMLS_DC) /* {{{ */
        !           182: {
        !           183:        size_t size;
        !           184:        zend_stream_type old_type;
        !           185: 
        !           186:        if (file_handle->type == ZEND_HANDLE_FILENAME) {
        !           187:                if (zend_stream_open(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) {
        !           188:                        return FAILURE;
        !           189:                }
        !           190:        }
        !           191: 
        !           192:        switch (file_handle->type) {            
        !           193:                case ZEND_HANDLE_FD:
        !           194:                        file_handle->type = ZEND_HANDLE_FP;
        !           195:                        file_handle->handle.fp = fdopen(file_handle->handle.fd, "rb");
        !           196:                        /* no break; */                 
        !           197:                case ZEND_HANDLE_FP:
        !           198:                        if (!file_handle->handle.fp) {
        !           199:                                return FAILURE;
        !           200:                        }
        !           201:                        memset(&file_handle->handle.stream.mmap, 0, sizeof(zend_mmap));
        !           202:                        file_handle->handle.stream.isatty     = isatty(fileno((FILE *)file_handle->handle.stream.handle)) ? 1 : 0;
        !           203:                        file_handle->handle.stream.reader     = (zend_stream_reader_t)zend_stream_stdio_reader;
        !           204:                        file_handle->handle.stream.closer     = (zend_stream_closer_t)zend_stream_stdio_closer;
        !           205:                        file_handle->handle.stream.fsizer     = (zend_stream_fsizer_t)zend_stream_stdio_fsizer;
        !           206:                        memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
        !           207:                        /* no break; */                 
        !           208:                case ZEND_HANDLE_STREAM:
        !           209:                        /* nothing to do */
        !           210:                        break;
        !           211:                
        !           212:                case ZEND_HANDLE_MAPPED:
        !           213:                        file_handle->handle.stream.mmap.pos = 0;
        !           214:                        *buf = file_handle->handle.stream.mmap.buf;
        !           215:                        *len = file_handle->handle.stream.mmap.len;
        !           216:                        return SUCCESS;
        !           217:                        
        !           218:                default:
        !           219:                        return FAILURE;
        !           220:        }
        !           221: 
        !           222:        size = zend_stream_fsize(file_handle TSRMLS_CC);
        !           223:        if (size == (size_t)-1) {
        !           224:                return FAILURE;
        !           225:        }
        !           226: 
        !           227:        old_type = file_handle->type;
        !           228:        file_handle->type = ZEND_HANDLE_STREAM;  /* we might still be _FP but we need fsize() work */
        !           229: 
        !           230:        if (old_type == ZEND_HANDLE_FP && !file_handle->handle.stream.isatty && size) {
        !           231: #if HAVE_MMAP
        !           232:                size_t page_size = REAL_PAGE_SIZE;
        !           233: 
        !           234:                if (file_handle->handle.fp &&
        !           235:                    size != 0 &&
        !           236:                    ((size - 1) % page_size) <= page_size - ZEND_MMAP_AHEAD) {
        !           237:                        /*  *buf[size] is zeroed automatically by the kernel */
        !           238:                        *buf = mmap(0, size + ZEND_MMAP_AHEAD, PROT_READ, MAP_PRIVATE, fileno(file_handle->handle.fp), 0);
        !           239:                        if (*buf != MAP_FAILED) {
        !           240:                                long offset = ftell(file_handle->handle.fp);
        !           241:                                file_handle->handle.stream.mmap.map = *buf;
        !           242: 
        !           243:                                if (offset != -1) {
        !           244:                                        *buf += offset;
        !           245:                                        size -= offset;
        !           246:                                }
        !           247:                                file_handle->handle.stream.mmap.buf = *buf;
        !           248:                                file_handle->handle.stream.mmap.len = size;
        !           249: 
        !           250:                                goto return_mapped;
        !           251:                        }
        !           252:                }
        !           253: #endif
        !           254:                file_handle->handle.stream.mmap.map = 0;
        !           255:                file_handle->handle.stream.mmap.buf = *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD);
        !           256:                file_handle->handle.stream.mmap.len = zend_stream_read(file_handle, *buf, size TSRMLS_CC);
        !           257:        } else {
        !           258:                size_t read, remain = 4*1024;
        !           259:                *buf = emalloc(remain);
        !           260:                size = 0;
        !           261: 
        !           262:                while ((read = zend_stream_read(file_handle, *buf + size, remain TSRMLS_CC)) > 0) {
        !           263:                        size   += read;
        !           264:                        remain -= read;
        !           265: 
        !           266:                        if (remain == 0) {
        !           267:                                *buf   = safe_erealloc(*buf, size, 2, 0);
        !           268:                                remain = size;
        !           269:                        }
        !           270:                }
        !           271:                file_handle->handle.stream.mmap.map = 0;
        !           272:                file_handle->handle.stream.mmap.len = size;
        !           273:                if (size && remain < ZEND_MMAP_AHEAD) {
        !           274:                        *buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD);
        !           275:                }
        !           276:                file_handle->handle.stream.mmap.buf = *buf;
        !           277:        }
        !           278: 
        !           279:        if (file_handle->handle.stream.mmap.len == 0) {
        !           280:                *buf = erealloc(*buf, ZEND_MMAP_AHEAD);
        !           281:                file_handle->handle.stream.mmap.buf = *buf;
        !           282:        }
        !           283: 
        !           284:        if (ZEND_MMAP_AHEAD) {
        !           285:                memset(file_handle->handle.stream.mmap.buf + file_handle->handle.stream.mmap.len, 0, ZEND_MMAP_AHEAD);
        !           286:        }
        !           287: 
        !           288: #if HAVE_MMAP
        !           289: return_mapped:
        !           290: #endif
        !           291:        file_handle->type = ZEND_HANDLE_MAPPED;
        !           292:        file_handle->handle.stream.mmap.pos        = 0;
        !           293:        file_handle->handle.stream.mmap.old_handle = file_handle->handle.stream.handle;
        !           294:        file_handle->handle.stream.mmap.old_closer = file_handle->handle.stream.closer;
        !           295:        file_handle->handle.stream.handle          = &file_handle->handle.stream;
        !           296:        file_handle->handle.stream.closer          = (zend_stream_closer_t)zend_stream_mmap_closer;
        !           297: 
        !           298:        *buf = file_handle->handle.stream.mmap.buf;
        !           299:        *len = file_handle->handle.stream.mmap.len;
        !           300: 
        !           301:        return SUCCESS;
        !           302: } /* }}} */
        !           303: 
        !           304: ZEND_API void zend_file_handle_dtor(zend_file_handle *fh TSRMLS_DC) /* {{{ */
        !           305: {
        !           306:        switch (fh->type) {
        !           307:                case ZEND_HANDLE_FD:
        !           308:                        /* nothing to do */
        !           309:                        break;
        !           310:                case ZEND_HANDLE_FP:
        !           311:                        fclose(fh->handle.fp);
        !           312:                        break;
        !           313:                case ZEND_HANDLE_STREAM:
        !           314:                case ZEND_HANDLE_MAPPED:
        !           315:                        if (fh->handle.stream.closer && fh->handle.stream.handle) {
        !           316:                                fh->handle.stream.closer(fh->handle.stream.handle TSRMLS_CC);
        !           317:                        }
        !           318:                        fh->handle.stream.handle = NULL;
        !           319:                        break;
        !           320:                case ZEND_HANDLE_FILENAME:
        !           321:                        /* We're only supposed to get here when destructing the used_files hash,
        !           322:                         * which doesn't really contain open files, but references to their names/paths
        !           323:                         */
        !           324:                        break;
        !           325:        }
        !           326:        if (fh->opened_path) {
        !           327:                efree(fh->opened_path);
        !           328:                fh->opened_path = NULL;
        !           329:        }
        !           330:        if (fh->free_filename && fh->filename) {
        !           331:                efree(fh->filename);
        !           332:                fh->filename = NULL;
        !           333:        }
        !           334: }
        !           335: /* }}} */
        !           336: 
        !           337: ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2) /* {{{ */
        !           338: {
        !           339:        if (fh1->type != fh2->type) {
        !           340:                return 0;
        !           341:        }
        !           342:        switch (fh1->type) {
        !           343:                case ZEND_HANDLE_FD:
        !           344:                        return fh1->handle.fd == fh2->handle.fd;
        !           345:                case ZEND_HANDLE_FP:
        !           346:                        return fh1->handle.fp == fh2->handle.fp;
        !           347:                case ZEND_HANDLE_STREAM:
        !           348:                        return fh1->handle.stream.handle == fh2->handle.stream.handle;
        !           349:                case ZEND_HANDLE_MAPPED:
        !           350:                        return (fh1->handle.stream.handle == &fh1->handle.stream &&
        !           351:                                fh2->handle.stream.handle == &fh2->handle.stream &&
        !           352:                                fh1->handle.stream.mmap.old_handle == fh2->handle.stream.mmap.old_handle)
        !           353:                                || fh1->handle.stream.handle == fh2->handle.stream.handle;
        !           354:                default:
        !           355:                        return 0;
        !           356:        }
        !           357:        return 0;
        !           358: } /* }}} */

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