File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / Zend / zend_stream.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:04:04 2014 UTC (10 years, 4 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | Zend Engine                                                          |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1998-2014 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,v 1.1.1.4 2014/06/15 20:04:04 misho Exp $ */
   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 + ZEND_MMAP_AHEAD);
   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 = 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: #if HAVE_MMAP
  288: return_mapped:
  289: #endif
  290: 	file_handle->type = ZEND_HANDLE_MAPPED;
  291: 	file_handle->handle.stream.mmap.pos        = 0;
  292: 	file_handle->handle.stream.mmap.old_handle = file_handle->handle.stream.handle;
  293: 	file_handle->handle.stream.mmap.old_closer = file_handle->handle.stream.closer;
  294: 	file_handle->handle.stream.handle          = &file_handle->handle.stream;
  295: 	file_handle->handle.stream.closer          = (zend_stream_closer_t)zend_stream_mmap_closer;
  296: 
  297: 	*buf = file_handle->handle.stream.mmap.buf;
  298: 	*len = file_handle->handle.stream.mmap.len;
  299: 
  300: 	return SUCCESS;
  301: } /* }}} */
  302: 
  303: ZEND_API void zend_file_handle_dtor(zend_file_handle *fh TSRMLS_DC) /* {{{ */
  304: {
  305: 	switch (fh->type) {
  306: 		case ZEND_HANDLE_FD:
  307: 			/* nothing to do */
  308: 			break;
  309: 		case ZEND_HANDLE_FP:
  310: 			fclose(fh->handle.fp);
  311: 			break;
  312: 		case ZEND_HANDLE_STREAM:
  313: 		case ZEND_HANDLE_MAPPED:
  314: 			if (fh->handle.stream.closer && fh->handle.stream.handle) {
  315: 				fh->handle.stream.closer(fh->handle.stream.handle TSRMLS_CC);
  316: 			}
  317: 			fh->handle.stream.handle = NULL;
  318: 			break;
  319: 		case ZEND_HANDLE_FILENAME:
  320: 			/* We're only supposed to get here when destructing the used_files hash,
  321: 			 * which doesn't really contain open files, but references to their names/paths
  322: 			 */
  323: 			break;
  324: 	}
  325: 	if (fh->opened_path) {
  326: 		efree(fh->opened_path);
  327: 		fh->opened_path = NULL;
  328: 	}
  329: 	if (fh->free_filename && fh->filename) {
  330: 		efree((char*)fh->filename);
  331: 		fh->filename = NULL;
  332: 	}
  333: }
  334: /* }}} */
  335: 
  336: ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2) /* {{{ */
  337: {
  338: 	if (fh1->type != fh2->type) {
  339: 		return 0;
  340: 	}
  341: 	switch (fh1->type) {
  342: 		case ZEND_HANDLE_FD:
  343: 			return fh1->handle.fd == fh2->handle.fd;
  344: 		case ZEND_HANDLE_FP:
  345: 			return fh1->handle.fp == fh2->handle.fp;
  346: 		case ZEND_HANDLE_STREAM:
  347: 			return fh1->handle.stream.handle == fh2->handle.stream.handle;
  348: 		case ZEND_HANDLE_MAPPED:
  349: 			return (fh1->handle.stream.handle == &fh1->handle.stream &&
  350: 			        fh2->handle.stream.handle == &fh2->handle.stream &&
  351: 			        fh1->handle.stream.mmap.old_handle == fh2->handle.stream.mmap.old_handle)
  352: 				|| fh1->handle.stream.handle == fh2->handle.stream.handle;
  353: 		default:
  354: 			return 0;
  355: 	}
  356: 	return 0;
  357: } /* }}} */

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