root/Zend/zend_stream.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_stream_stdio_reader
  2. zend_stream_stdio_closer
  3. zend_stream_stdio_fsizer
  4. zend_stream_unmap
  5. zend_stream_mmap_closer
  6. zend_stream_is_mmap
  7. zend_stream_fsize
  8. zend_stream_open
  9. zend_stream_getc
  10. zend_stream_read
  11. zend_stream_fixup
  12. zend_file_handle_dtor
  13. zend_compare_file_handles

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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$ */
  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 } /* }}} */

/* [<][>][^][v][top][bottom][index][help] */