diff options
Diffstat (limited to 'Zend/zend_stream.c')
-rw-r--r-- | Zend/zend_stream.c | 333 |
1 files changed, 263 insertions, 70 deletions
diff --git a/Zend/zend_stream.c b/Zend/zend_stream.c index 19cd9bb26..ff8a5d25b 100644 --- a/Zend/zend_stream.c +++ b/Zend/zend_stream.c @@ -5,7 +5,7 @@ | Copyright (c) 1998-2009 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | + | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.zend.com/license/2_00.txt. | | If you did not receive a copy of the Zend license and are unable to | @@ -13,94 +13,132 @@ | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Wez Furlong <wez@thebrainroom.com> | + | Scott MacVicar <scottmac@php.net> | + | Nuno Lopes <nlopess@php.net> | + | Marcus Boerger <helly@php.net> | +----------------------------------------------------------------------+ */ -/* $Id: zend_stream.c,v 1.13.2.1.2.3 2008/12/31 11:17:33 sebastian Exp $ */ +/* $Id: zend_stream.c,v 1.13.2.1.2.1.2.10 2009/01/28 23:18:49 nlopess Exp $ */ #include "zend.h" #include "zend_compile.h" +#include <sys/types.h> +#include <sys/stat.h> +#if HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif + ZEND_DLIMPORT int isatty(int fd); -static size_t zend_stream_stdio_reader(void *handle, char *buf, size_t len TSRMLS_DC) +static size_t zend_stream_stdio_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */ { return fread(buf, 1, len, (FILE*)handle); -} +} /* }}} */ -static void zend_stream_stdio_closer(void *handle TSRMLS_DC) +static void zend_stream_stdio_closer(void *handle TSRMLS_DC) /* {{{ */ { - if ((FILE*)handle != stdin) + if (handle && (FILE*)handle != stdin) { fclose((FILE*)handle); -} + } +} /* }}} */ -static long zend_stream_stdio_fteller(void *handle TSRMLS_DC) +static size_t zend_stream_stdio_fsizer(void *handle TSRMLS_DC) /* {{{ */ { - return ftell((FILE*) handle); -} + struct stat buf; + if (handle && fstat(fileno((FILE*)handle), &buf) == 0) { +#ifdef S_ISREG + if (!S_ISREG(buf.st_mode)) { + return 0; + } +#endif + return buf.st_size; + } + return 0; +} /* }}} */ + +static void zend_stream_unmap(zend_stream *stream TSRMLS_DC) { /* {{{ */ +#if HAVE_MMAP + if (stream->mmap.map) { + munmap(stream->mmap.map, stream->mmap.len); + } else +#endif + if (stream->mmap.buf) { + efree(stream->mmap.buf); + } + stream->mmap.len = 0; + stream->mmap.pos = 0; + stream->mmap.map = 0; + stream->mmap.buf = 0; + stream->handle = stream->mmap.old_handle; +} /* }}} */ + +static void zend_stream_mmap_closer(zend_stream *stream TSRMLS_DC) /* {{{ */ +{ + zend_stream_unmap(stream TSRMLS_CC); + if (stream->mmap.old_closer && stream->handle) { + stream->mmap.old_closer(stream->handle TSRMLS_CC); + } +} /* }}} */ +static inline int zend_stream_is_mmap(zend_file_handle *file_handle) { /* {{{ */ + return file_handle->type == ZEND_HANDLE_MAPPED; +} /* }}} */ -ZEND_API int zend_stream_open(const char *filename, zend_file_handle *handle TSRMLS_DC) +static size_t zend_stream_fsize(zend_file_handle *file_handle TSRMLS_DC) /* {{{ */ +{ + struct stat buf; + + if (zend_stream_is_mmap(file_handle)) { + return file_handle->handle.stream.mmap.len; + } + if (file_handle->type == ZEND_HANDLE_STREAM || file_handle->type == ZEND_HANDLE_MAPPED) { + return file_handle->handle.stream.fsizer(file_handle->handle.stream.handle TSRMLS_CC); + } + if (file_handle->handle.fp && fstat(fileno(file_handle->handle.fp), &buf) == 0) { +#ifdef S_ISREG + if (!S_ISREG(buf.st_mode)) { + return 0; + } +#endif + return buf.st_size; + } + + return -1; +} /* }}} */ + +ZEND_API int zend_stream_open(const char *filename, zend_file_handle *handle TSRMLS_DC) /* {{{ */ { if (zend_stream_open_function) { return zend_stream_open_function(filename, handle TSRMLS_CC); } handle->type = ZEND_HANDLE_FP; handle->opened_path = NULL; - handle->handle.fp = zend_fopen(filename, &handle->opened_path); + handle->handle.fp = zend_fopen(filename, &handle->opened_path TSRMLS_CC); handle->filename = (char *)filename; handle->free_filename = 0; + memset(&handle->handle.stream.mmap, 0, sizeof(zend_mmap)); return (handle->handle.fp) ? SUCCESS : FAILURE; -} +} /* }}} */ -ZEND_API int zend_stream_fixup(zend_file_handle *file_handle TSRMLS_DC) +static int zend_stream_getc(zend_file_handle *file_handle TSRMLS_DC) /* {{{ */ { - switch (file_handle->type) { - case ZEND_HANDLE_FILENAME: - if (FAILURE == zend_stream_open(file_handle->filename, file_handle TSRMLS_CC)) { - return FAILURE; - } - break; - - case ZEND_HANDLE_FD: - file_handle->handle.fp = fdopen(file_handle->handle.fd, "rb"); - file_handle->type = ZEND_HANDLE_FP; - break; - - case ZEND_HANDLE_FP: - file_handle->handle.fp = file_handle->handle.fp; - break; - - case ZEND_HANDLE_STREAM: - /* nothing to do */ - return SUCCESS; - - default: - return FAILURE; - } - if (file_handle->type == ZEND_HANDLE_FP) { - if (!file_handle->handle.fp) { - return FAILURE; - } - - /* make compatible with stream */ - file_handle->handle.stream.handle = file_handle->handle.fp; - file_handle->handle.stream.reader = zend_stream_stdio_reader; - file_handle->handle.stream.closer = zend_stream_stdio_closer; - file_handle->handle.stream.fteller = zend_stream_stdio_fteller; + char buf; - file_handle->handle.stream.interactive = isatty(fileno((FILE *)file_handle->handle.stream.handle)); + if (file_handle->handle.stream.reader(file_handle->handle.stream.handle, &buf, sizeof(buf) TSRMLS_CC)) { + return (int)buf; } - return SUCCESS; -} + return EOF; +} /* }}} */ -ZEND_API size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC) +static size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC) /* {{{ */ { - if (file_handle->handle.stream.interactive) { + if (!zend_stream_is_mmap(file_handle) && file_handle->handle.stream.isatty) { int c = '*'; - size_t n; + size_t n; #ifdef NETWARE /* @@ -108,35 +146,190 @@ ZEND_API size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_ Ascii value 4 is actually EOT character which is not defined anywhere in the LibC or else we can use instead of hardcoded 4. */ - for ( n = 0; n < len && (c = zend_stream_getc( file_handle TSRMLS_CC)) != EOF && c != 4 && c != '\n'; ++n ) + for (n = 0; n < len && (c = zend_stream_getc(file_handle TSRMLS_CC)) != EOF && c != 4 && c != '\n'; ++n) { #else - for ( n = 0; n < len && (c = zend_stream_getc( file_handle TSRMLS_CC)) != EOF && c != '\n'; ++n ) + for (n = 0; n < len && (c = zend_stream_getc(file_handle TSRMLS_CC)) != EOF && c != '\n'; ++n) { #endif - buf[n] = (char) c; - if ( c == '\n' ) - buf[n++] = (char) c; + buf[n] = (char)c; + } + if (c == '\n') { + buf[n++] = (char)c; + } return n; } return file_handle->handle.stream.reader(file_handle->handle.stream.handle, buf, len TSRMLS_CC); -} +} /* }}} */ -ZEND_API int zend_stream_getc(zend_file_handle *file_handle TSRMLS_DC) +ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len TSRMLS_DC) /* {{{ */ { - char buf; + size_t size; + zend_stream_type old_type; - if (file_handle->handle.stream.reader(file_handle->handle.stream.handle, &buf, sizeof(buf) TSRMLS_CC)) { - return (int)buf; + if (file_handle->type == ZEND_HANDLE_FILENAME) { + if (zend_stream_open(file_handle->filename, file_handle TSRMLS_CC) == FAILURE) { + return FAILURE; + } } - return EOF; -} -ZEND_API int zend_stream_ferror(zend_file_handle *file_handle TSRMLS_DC) + switch (file_handle->type) { + case ZEND_HANDLE_FD: + file_handle->type = ZEND_HANDLE_FP; + file_handle->handle.fp = fdopen(file_handle->handle.fd, "rb"); + /* no break; */ + case ZEND_HANDLE_FP: + if (!file_handle->handle.fp) { + return FAILURE; + } + memset(&file_handle->handle.stream.mmap, 0, sizeof(zend_mmap)); + file_handle->handle.stream.isatty = isatty(fileno((FILE *)file_handle->handle.stream.handle)) ? 1 : 0; + file_handle->handle.stream.reader = (zend_stream_reader_t)zend_stream_stdio_reader; + file_handle->handle.stream.closer = (zend_stream_closer_t)zend_stream_stdio_closer; + file_handle->handle.stream.fsizer = (zend_stream_fsizer_t)zend_stream_stdio_fsizer; + memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap)); + /* no break; */ + case ZEND_HANDLE_STREAM: + /* nothing to do */ + break; + + case ZEND_HANDLE_MAPPED: + file_handle->handle.stream.mmap.pos = 0; + *buf = file_handle->handle.stream.mmap.buf; + *len = file_handle->handle.stream.mmap.len; + return SUCCESS; + + default: + return FAILURE; + } + + size = zend_stream_fsize(file_handle TSRMLS_CC); + if (size == (size_t)-1) { + return FAILURE; + } + + old_type = file_handle->type; + file_handle->type = ZEND_HANDLE_STREAM; /* we might still be _FP but we need fsize() work */ + + if (old_type == ZEND_HANDLE_FP && !file_handle->handle.stream.isatty && size) { +#if HAVE_MMAP + if (file_handle->handle.fp) { + /* *buf[size] is zeroed automatically by the kernel */ + *buf = mmap(0, size + ZEND_MMAP_AHEAD, PROT_READ, MAP_PRIVATE, fileno(file_handle->handle.fp), 0); + if (*buf != MAP_FAILED) { + long offset = ftell(file_handle->handle.fp); + file_handle->handle.stream.mmap.map = *buf; + + if (offset != -1) { + *buf += offset; + size -= offset; + } + file_handle->handle.stream.mmap.buf = *buf; + file_handle->handle.stream.mmap.len = size; + + goto return_mapped; + } + } +#endif + file_handle->handle.stream.mmap.map = 0; + file_handle->handle.stream.mmap.buf = *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD); + file_handle->handle.stream.mmap.len = zend_stream_read(file_handle, *buf, size TSRMLS_CC); + } else { + size_t read, remain = 4*1024; + *buf = emalloc(remain); + size = 0; + + while ((read = zend_stream_read(file_handle, *buf + size, remain TSRMLS_CC)) > 0) { + size += read; + remain -= read; + + if (remain == 0) { + *buf = safe_erealloc(*buf, size, 2, 0); + remain = size; + } + } + file_handle->handle.stream.mmap.map = 0; + file_handle->handle.stream.mmap.len = size; + if (size && remain < ZEND_MMAP_AHEAD) { + *buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD); + } + file_handle->handle.stream.mmap.buf = *buf; + } + + if (file_handle->handle.stream.mmap.len == 0) { + *buf = erealloc(*buf, ZEND_MMAP_AHEAD); + file_handle->handle.stream.mmap.buf = *buf; + } + + if (ZEND_MMAP_AHEAD) { + memset(file_handle->handle.stream.mmap.buf + file_handle->handle.stream.mmap.len, 0, ZEND_MMAP_AHEAD); + } + +return_mapped: + file_handle->type = ZEND_HANDLE_MAPPED; + file_handle->handle.stream.mmap.pos = 0; + file_handle->handle.stream.mmap.old_handle = file_handle->handle.stream.handle; + file_handle->handle.stream.mmap.old_closer = file_handle->handle.stream.closer; + file_handle->handle.stream.handle = &file_handle->handle.stream; + file_handle->handle.stream.closer = (zend_stream_closer_t)zend_stream_mmap_closer; + + *buf = file_handle->handle.stream.mmap.buf; + *len = file_handle->handle.stream.mmap.len; + + return SUCCESS; +} /* }}} */ + +ZEND_API void zend_file_handle_dtor(zend_file_handle *fh TSRMLS_DC) /* {{{ */ { - return 0; + switch (fh->type) { + case ZEND_HANDLE_FD: + /* nothing to do */ + break; + case ZEND_HANDLE_FP: + fclose(fh->handle.fp); + break; + case ZEND_HANDLE_STREAM: + case ZEND_HANDLE_MAPPED: + if (fh->handle.stream.closer && fh->handle.stream.handle) { + fh->handle.stream.closer(fh->handle.stream.handle TSRMLS_CC); + } + fh->handle.stream.handle = NULL; + break; + case ZEND_HANDLE_FILENAME: + /* We're only supposed to get here when destructing the used_files hash, + * which doesn't really contain open files, but references to their names/paths + */ + break; + } + if (fh->opened_path) { + efree(fh->opened_path); + fh->opened_path = NULL; + } + if (fh->free_filename && fh->filename) { + efree(fh->filename); + fh->filename = NULL; + } } +/* }}} */ -ZEND_API long zend_stream_ftell(zend_file_handle *file_handle TSRMLS_DC) +ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2) /* {{{ */ { - return file_handle->handle.stream.fteller(file_handle->handle.stream.handle TSRMLS_CC); -} + if (fh1->type != fh2->type) { + return 0; + } + switch (fh1->type) { + case ZEND_HANDLE_FD: + return fh1->handle.fd == fh2->handle.fd; + case ZEND_HANDLE_FP: + return fh1->handle.fp == fh2->handle.fp; + case ZEND_HANDLE_STREAM: + return fh1->handle.stream.handle == fh2->handle.stream.handle; + case ZEND_HANDLE_MAPPED: + return (fh1->handle.stream.handle == &fh1->handle.stream && + fh2->handle.stream.handle == &fh2->handle.stream && + fh1->handle.stream.mmap.old_handle == fh2->handle.stream.mmap.old_handle) + || fh1->handle.stream.handle == fh2->handle.stream.handle; + default: + return 0; + } + return 0; +} /* }}} */ |