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>