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 #include "zend_stream.h"
  28 
  29 #if HAVE_MMAP
  30 # if HAVE_UNISTD_H
  31 #  include <unistd.h>
  32 #  if defined(_SC_PAGESIZE)
  33 #    define REAL_PAGE_SIZE sysconf(_SC_PAGESIZE);
  34 #  elif defined(_SC_PAGE_SIZE)
  35 #    define REAL_PAGE_SIZE sysconf(_SC_PAGE_SIZE);
  36 #  endif
  37 # endif
  38 # if HAVE_SYS_MMAN_H
  39 #  include <sys/mman.h>
  40 # endif
  41 # ifndef REAL_PAGE_SIZE
  42 #  ifdef PAGE_SIZE
  43 #   define REAL_PAGE_SIZE PAGE_SIZE
  44 #  else
  45 #   define REAL_PAGE_SIZE 4096
  46 #  endif
  47 # endif
  48 #endif
  49 
  50 ZEND_DLIMPORT int isatty(int fd);
  51 
  52 static size_t zend_stream_stdio_reader(void *handle, char *buf, size_t len) /* {{{ */
  53 {
  54         return fread(buf, 1, len, (FILE*)handle);
  55 } /* }}} */
  56 
  57 static void zend_stream_stdio_closer(void *handle) /* {{{ */
  58 {
  59         if (handle && (FILE*)handle != stdin) {
  60                 fclose((FILE*)handle);
  61         }
  62 } /* }}} */
  63 
  64 static size_t zend_stream_stdio_fsizer(void *handle) /* {{{ */
  65 {
  66         zend_stat_t buf;
  67         if (handle && zend_fstat(fileno((FILE*)handle), &buf) == 0) {
  68 #ifdef S_ISREG
  69                 if (!S_ISREG(buf.st_mode)) {
  70                         return 0;
  71                 }
  72 #endif
  73                 return buf.st_size;
  74         }
  75         return 0;
  76 } /* }}} */
  77 
  78 static void zend_stream_unmap(zend_stream *stream) { /* {{{ */
  79 #if HAVE_MMAP
  80         if (stream->mmap.map) {
  81                 munmap(stream->mmap.map, stream->mmap.len + ZEND_MMAP_AHEAD);
  82         } else
  83 #endif
  84         if (stream->mmap.buf) {
  85                 efree(stream->mmap.buf);
  86         }
  87         stream->mmap.len = 0;
  88         stream->mmap.pos = 0;
  89         stream->mmap.map = 0;
  90         stream->mmap.buf = 0;
  91         stream->handle   = stream->mmap.old_handle;
  92 } /* }}} */
  93 
  94 static void zend_stream_mmap_closer(zend_stream *stream) /* {{{ */
  95 {
  96         zend_stream_unmap(stream);
  97         if (stream->mmap.old_closer && stream->handle) {
  98                 stream->mmap.old_closer(stream->handle);
  99         }
 100 } /* }}} */
 101 
 102 static inline int zend_stream_is_mmap(zend_file_handle *file_handle) { /* {{{ */
 103         return file_handle->type == ZEND_HANDLE_MAPPED;
 104 } /* }}} */
 105 
 106 static size_t zend_stream_fsize(zend_file_handle *file_handle) /* {{{ */
 107 {
 108         zend_stat_t buf;
 109 
 110         if (zend_stream_is_mmap(file_handle)) {
 111                 return file_handle->handle.stream.mmap.len;
 112         }
 113         if (file_handle->type == ZEND_HANDLE_STREAM || file_handle->type == ZEND_HANDLE_MAPPED) {
 114                 return file_handle->handle.stream.fsizer(file_handle->handle.stream.handle);
 115         }
 116         if (file_handle->handle.fp && zend_fstat(fileno(file_handle->handle.fp), &buf) == 0) {
 117 #ifdef S_ISREG
 118                 if (!S_ISREG(buf.st_mode)) {
 119                         return 0;
 120                 }
 121 #endif
 122                 return buf.st_size;
 123         }
 124 
 125         return -1;
 126 } /* }}} */
 127 
 128 ZEND_API int zend_stream_open(const char *filename, zend_file_handle *handle) /* {{{ */
 129 {
 130         if (zend_stream_open_function) {
 131                 return zend_stream_open_function(filename, handle);
 132         }
 133         handle->type = ZEND_HANDLE_FP;
 134         handle->opened_path = NULL;
 135         handle->handle.fp = zend_fopen(filename, &handle->opened_path);
 136         handle->filename = filename;
 137         handle->free_filename = 0;
 138         memset(&handle->handle.stream.mmap, 0, sizeof(zend_mmap));
 139 
 140         return (handle->handle.fp) ? SUCCESS : FAILURE;
 141 } /* }}} */
 142 
 143 static int zend_stream_getc(zend_file_handle *file_handle) /* {{{ */
 144 {
 145         char buf;
 146 
 147         if (file_handle->handle.stream.reader(file_handle->handle.stream.handle, &buf, sizeof(buf))) {
 148                 return (int)buf;
 149         }
 150         return EOF;
 151 } /* }}} */
 152 
 153 static size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len) /* {{{ */
 154 {
 155         if (!zend_stream_is_mmap(file_handle) && file_handle->handle.stream.isatty) {
 156                 int c = '*';
 157                 size_t n;
 158 
 159 #ifdef NETWARE
 160                 /*
 161                         c != 4 check is there as fread of a character in NetWare LibC gives 4 upon ^D character.
 162                         Ascii value 4 is actually EOT character which is not defined anywhere in the LibC
 163                         or else we can use instead of hardcoded 4.
 164                 */
 165                 for (n = 0; n < len && (c = zend_stream_getc(file_handle)) != EOF && c != 4 && c != '\n'; ++n) {
 166 #else
 167                 for (n = 0; n < len && (c = zend_stream_getc(file_handle)) != EOF && c != '\n'; ++n)  {
 168 #endif
 169                         buf[n] = (char)c;
 170                 }
 171                 if (c == '\n') {
 172                         buf[n++] = (char)c;
 173                 }
 174 
 175                 return n;
 176         }
 177         return file_handle->handle.stream.reader(file_handle->handle.stream.handle, buf, len);
 178 } /* }}} */
 179 
 180 ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */
 181 {
 182         size_t size;
 183         zend_stream_type old_type;
 184 
 185         if (file_handle->type == ZEND_HANDLE_FILENAME) {
 186                 if (zend_stream_open(file_handle->filename, file_handle) == FAILURE) {
 187                         return FAILURE;
 188                 }
 189         }
 190 
 191         switch (file_handle->type) {
 192                 case ZEND_HANDLE_FD:
 193                         file_handle->type = ZEND_HANDLE_FP;
 194                         file_handle->handle.fp = fdopen(file_handle->handle.fd, "rb");
 195                         /* no break; */
 196                 case ZEND_HANDLE_FP:
 197                         if (!file_handle->handle.fp) {
 198                                 return FAILURE;
 199                         }
 200                         memset(&file_handle->handle.stream.mmap, 0, sizeof(zend_mmap));
 201                         file_handle->handle.stream.isatty     = isatty(fileno((FILE *)file_handle->handle.stream.handle)) ? 1 : 0;
 202                         file_handle->handle.stream.reader     = (zend_stream_reader_t)zend_stream_stdio_reader;
 203                         file_handle->handle.stream.closer     = (zend_stream_closer_t)zend_stream_stdio_closer;
 204                         file_handle->handle.stream.fsizer     = (zend_stream_fsizer_t)zend_stream_stdio_fsizer;
 205                         memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
 206                         /* no break; */
 207                 case ZEND_HANDLE_STREAM:
 208                         /* nothing to do */
 209                         break;
 210 
 211                 case ZEND_HANDLE_MAPPED:
 212                         file_handle->handle.stream.mmap.pos = 0;
 213                         *buf = file_handle->handle.stream.mmap.buf;
 214                         *len = file_handle->handle.stream.mmap.len;
 215                         return SUCCESS;
 216 
 217                 default:
 218                         return FAILURE;
 219         }
 220 
 221         size = zend_stream_fsize(file_handle);
 222         if (size == (size_t)-1) {
 223                 return FAILURE;
 224         }
 225 
 226         old_type = file_handle->type;
 227         file_handle->type = ZEND_HANDLE_STREAM;  /* we might still be _FP but we need fsize() work */
 228 
 229         if (old_type == ZEND_HANDLE_FP && !file_handle->handle.stream.isatty && size) {
 230 #if HAVE_MMAP
 231                 size_t page_size = REAL_PAGE_SIZE;
 232 
 233                 if (file_handle->handle.fp &&
 234                     size != 0 &&
 235                     ((size - 1) % page_size) <= page_size - ZEND_MMAP_AHEAD) {
 236                         /*  *buf[size] is zeroed automatically by the kernel */
 237                         *buf = mmap(0, size + ZEND_MMAP_AHEAD, PROT_READ, MAP_PRIVATE, fileno(file_handle->handle.fp), 0);
 238                         if (*buf != MAP_FAILED) {
 239                                 zend_long offset = ftell(file_handle->handle.fp);
 240                                 file_handle->handle.stream.mmap.map = *buf;
 241 
 242                                 if (offset != -1) {
 243                                         *buf += offset;
 244                                         size -= offset;
 245                                 }
 246                                 file_handle->handle.stream.mmap.buf = *buf;
 247                                 file_handle->handle.stream.mmap.len = size;
 248 
 249                                 goto return_mapped;
 250                         }
 251                 }
 252 #endif
 253                 file_handle->handle.stream.mmap.map = 0;
 254                 file_handle->handle.stream.mmap.buf = *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD);
 255                 file_handle->handle.stream.mmap.len = zend_stream_read(file_handle, *buf, size);
 256         } else {
 257                 size_t read, remain = 4*1024;
 258                 *buf = emalloc(remain);
 259                 size = 0;
 260 
 261                 while ((read = zend_stream_read(file_handle, *buf + size, remain)) > 0) {
 262                         size   += read;
 263                         remain -= read;
 264 
 265                         if (remain == 0) {
 266                                 *buf   = safe_erealloc(*buf, size, 2, 0);
 267                                 remain = size;
 268                         }
 269                 }
 270                 file_handle->handle.stream.mmap.map = 0;
 271                 file_handle->handle.stream.mmap.len = size;
 272                 if (size && remain < ZEND_MMAP_AHEAD) {
 273                         *buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD);
 274                 }
 275                 file_handle->handle.stream.mmap.buf = *buf;
 276         }
 277 
 278         if (file_handle->handle.stream.mmap.len == 0) {
 279                 *buf = erealloc(*buf, ZEND_MMAP_AHEAD);
 280                 file_handle->handle.stream.mmap.buf = *buf;
 281         }
 282 
 283         if (ZEND_MMAP_AHEAD) {
 284                 memset(file_handle->handle.stream.mmap.buf + file_handle->handle.stream.mmap.len, 0, ZEND_MMAP_AHEAD);
 285         }
 286 #if HAVE_MMAP
 287 return_mapped:
 288 #endif
 289         file_handle->type = ZEND_HANDLE_MAPPED;
 290         file_handle->handle.stream.mmap.pos        = 0;
 291         file_handle->handle.stream.mmap.old_handle = file_handle->handle.stream.handle;
 292         file_handle->handle.stream.mmap.old_closer = file_handle->handle.stream.closer;
 293         file_handle->handle.stream.handle          = &file_handle->handle.stream;
 294         file_handle->handle.stream.closer          = (zend_stream_closer_t)zend_stream_mmap_closer;
 295 
 296         *buf = file_handle->handle.stream.mmap.buf;
 297         *len = file_handle->handle.stream.mmap.len;
 298 
 299         return SUCCESS;
 300 } /* }}} */
 301 
 302 ZEND_API void zend_file_handle_dtor(zend_file_handle *fh) /* {{{ */
 303 {
 304         switch (fh->type) {
 305                 case ZEND_HANDLE_FD:
 306                         /* nothing to do */
 307                         break;
 308                 case ZEND_HANDLE_FP:
 309                         fclose(fh->handle.fp);
 310                         break;
 311                 case ZEND_HANDLE_STREAM:
 312                 case ZEND_HANDLE_MAPPED:
 313                         if (fh->handle.stream.closer && fh->handle.stream.handle) {
 314                                 fh->handle.stream.closer(fh->handle.stream.handle);
 315                         }
 316                         fh->handle.stream.handle = NULL;
 317                         break;
 318                 case ZEND_HANDLE_FILENAME:
 319                         /* We're only supposed to get here when destructing the used_files hash,
 320                          * which doesn't really contain open files, but references to their names/paths
 321                          */
 322                         break;
 323         }
 324         if (fh->opened_path) {
 325                 zend_string_release(fh->opened_path);
 326                 fh->opened_path = NULL;
 327         }
 328         if (fh->free_filename && fh->filename) {
 329                 efree((char*)fh->filename);
 330                 fh->filename = NULL;
 331         }
 332 }
 333 /* }}} */
 334 
 335 ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2) /* {{{ */
 336 {
 337         if (fh1->type != fh2->type) {
 338                 return 0;
 339         }
 340         switch (fh1->type) {
 341                 case ZEND_HANDLE_FD:
 342                         return fh1->handle.fd == fh2->handle.fd;
 343                 case ZEND_HANDLE_FP:
 344                         return fh1->handle.fp == fh2->handle.fp;
 345                 case ZEND_HANDLE_STREAM:
 346                         return fh1->handle.stream.handle == fh2->handle.stream.handle;
 347                 case ZEND_HANDLE_MAPPED:
 348                         return (fh1->handle.stream.handle == &fh1->handle.stream &&
 349                                 fh2->handle.stream.handle == &fh2->handle.stream &&
 350                                 fh1->handle.stream.mmap.old_handle == fh2->handle.stream.mmap.old_handle)
 351                                 || fh1->handle.stream.handle == fh2->handle.stream.handle;
 352                 default:
 353                         return 0;
 354         }
 355         return 0;
 356 } /* }}} */

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