Annotation of embedaddon/php/Zend/zend_stream.c, revision 1.1.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>