PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_3/main/streams - streams.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 964
Code covered: 84.8 % Executed lines: 817
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Wez Furlong <wez@thebrainroom.com>                          |
      16                 :    | Borrowed code from:                                                  |
      17                 :    |          Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
      18                 :    |          Jim Winstead <jimw@php.net>                                 |
      19                 :    +----------------------------------------------------------------------+
      20                 :  */
      21                 : 
      22                 : /* $Id: streams.c 290803 2009-11-16 10:36:27Z felipe $ */
      23                 : 
      24                 : #define _GNU_SOURCE
      25                 : #include "php.h"
      26                 : #include "php_globals.h"
      27                 : #include "php_network.h"
      28                 : #include "php_open_temporary_file.h"
      29                 : #include "ext/standard/file.h"
      30                 : #include "ext/standard/basic_functions.h" /* for BG(mmap_file) (not strictly required) */
      31                 : #include "ext/standard/php_string.h" /* for php_memnstr, used by php_stream_get_record() */
      32                 : #include <stddef.h>
      33                 : #include <fcntl.h>
      34                 : #include "php_streams_int.h"
      35                 : 
      36                 : /* {{{ resource and registration code */
      37                 : /* Global wrapper hash, copied to FG(stream_wrappers) on registration of volatile wrapper */
      38                 : static HashTable url_stream_wrappers_hash;
      39                 : static int le_stream = FAILURE; /* true global */
      40                 : static int le_pstream = FAILURE; /* true global */
      41                 : static int le_stream_filter = FAILURE; /* true global */
      42                 : 
      43                 : PHPAPI int php_file_le_stream(void)
      44         9462853 : {
      45         9462853 :         return le_stream;
      46                 : }
      47                 : 
      48                 : PHPAPI int php_file_le_pstream(void)
      49         9400839 : {
      50         9400839 :         return le_pstream;
      51                 : }
      52                 : 
      53                 : PHPAPI int php_file_le_stream_filter(void)
      54              86 : {
      55              86 :         return le_stream_filter;
      56                 : }
      57                 : 
      58                 : PHPAPI HashTable *_php_stream_get_url_stream_wrappers_hash(TSRMLS_D)
      59              31 : {
      60              31 :         return (FG(stream_wrappers) ? FG(stream_wrappers) : &url_stream_wrappers_hash);
      61                 : }
      62                 : 
      63                 : PHPAPI HashTable *php_stream_get_url_stream_wrappers_hash_global(void)
      64               1 : {
      65               1 :         return &url_stream_wrappers_hash;
      66                 : }
      67                 : 
      68                 : static int _php_stream_release_context(zend_rsrc_list_entry *le, void *pContext TSRMLS_DC)
      69               0 : {
      70               0 :         if (le->ptr == pContext) {
      71               0 :                 return --le->refcount == 0;
      72                 :         }
      73               0 :         return 0;
      74                 : }
      75                 : 
      76                 : static int forget_persistent_resource_id_numbers(zend_rsrc_list_entry *rsrc TSRMLS_DC)
      77             328 : {
      78                 :         php_stream *stream;
      79                 : 
      80             328 :         if (Z_TYPE_P(rsrc) != le_pstream) {
      81             322 :                 return 0;
      82                 :         }
      83                 : 
      84               6 :         stream = (php_stream*)rsrc->ptr;
      85                 : 
      86                 : #if STREAM_DEBUG
      87                 : fprintf(stderr, "forget_persistent: %s:%p\n", stream->ops->label, stream);
      88                 : #endif
      89                 : 
      90               6 :         stream->rsrc_id = FAILURE;
      91                 : 
      92               6 :         if (stream->context) {
      93               0 :                 zend_hash_apply_with_argument(&EG(regular_list),
      94                 :                                 (apply_func_arg_t) _php_stream_release_context,
      95                 :                                 stream->context TSRMLS_CC);
      96               0 :                 stream->context = NULL;
      97                 :         }
      98                 :         
      99               6 :         return 0;
     100                 : }
     101                 : 
     102                 : PHP_RSHUTDOWN_FUNCTION(streams)
     103           17651 : {
     104           17651 :         zend_hash_apply(&EG(persistent_list), (apply_func_t)forget_persistent_resource_id_numbers TSRMLS_CC);
     105           17651 :         return SUCCESS;
     106                 : }
     107                 : 
     108                 : PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC)
     109            1006 : {
     110                 :         zend_rsrc_list_entry *le;
     111                 : 
     112            1006 :         if (zend_hash_find(&EG(persistent_list), (char*)persistent_id, strlen(persistent_id)+1, (void*) &le) == SUCCESS) {
     113               0 :                 if (Z_TYPE_P(le) == le_pstream) {
     114               0 :                         if (stream) {
     115               0 :                                 *stream = (php_stream*)le->ptr;
     116               0 :                                 le->refcount++;
     117               0 :                                 (*stream)->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, *stream, le_pstream);
     118                 :                         }
     119               0 :                         return PHP_STREAM_PERSISTENT_SUCCESS;
     120                 :                 }
     121               0 :                 return PHP_STREAM_PERSISTENT_FAILURE;
     122                 :         }
     123            1006 :         return PHP_STREAM_PERSISTENT_NOT_EXIST;
     124                 : }
     125                 : 
     126                 : /* }}} */
     127                 : 
     128                 : /* {{{ wrapper error reporting */
     129                 : void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC)
     130             440 : {
     131             440 :         char *tmp = estrdup(path);
     132                 :         char *msg;
     133             440 :         int free_msg = 0;
     134                 : 
     135             440 :         if (wrapper) {
     136             420 :                 if (wrapper->err_count > 0) {
     137                 :                         int i;
     138                 :                         size_t l;
     139                 :                         int brlen;
     140                 :                         char *br;
     141                 : 
     142              86 :                         if (PG(html_errors)) {
     143               0 :                                 brlen = 7;
     144               0 :                                 br = "<br />\n";
     145                 :                         } else {
     146              86 :                                 brlen = 1;
     147              86 :                                 br = "\n";
     148                 :                         }
     149                 : 
     150             178 :                         for (i = 0, l = 0; i < wrapper->err_count; i++) {
     151              92 :                                 l += strlen(wrapper->err_stack[i]);
     152              92 :                                 if (i < wrapper->err_count - 1) {
     153               6 :                                         l += brlen;
     154                 :                                 }
     155                 :                         }
     156              86 :                         msg = emalloc(l + 1);
     157              86 :                         msg[0] = '\0';
     158             178 :                         for (i = 0; i < wrapper->err_count; i++) {
     159              92 :                                 strcat(msg, wrapper->err_stack[i]);
     160              92 :                                 if (i < wrapper->err_count - 1) { 
     161               6 :                                         strcat(msg, br);
     162                 :                                 }
     163                 :                         }
     164                 : 
     165              86 :                         free_msg = 1;
     166                 :                 } else {
     167             334 :                         if (wrapper == &php_plain_files_wrapper) {
     168             333 :                                 msg = strerror(errno);
     169                 :                         } else {
     170               1 :                                 msg = "operation failed";
     171                 :                         }
     172                 :                 }
     173                 :         } else {
     174              20 :                 msg = "no suitable wrapper could be found";
     175                 :         }
     176                 : 
     177             440 :         php_strip_url_passwd(tmp);
     178             440 :         php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "%s: %s", caption, msg);
     179             440 :         efree(tmp);
     180             440 :         if (free_msg) {
     181              86 :                 efree(msg);
     182                 :         }
     183             440 : }
     184                 : 
     185                 : void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
     186          116899 : {
     187          116899 :         if (wrapper) {
     188                 :                 /* tidy up the error stack */
     189                 :                 int i;
     190                 : 
     191          116971 :                 for (i = 0; i < wrapper->err_count; i++) {
     192              92 :                         efree(wrapper->err_stack[i]);
     193                 :                 }
     194          116879 :                 if (wrapper->err_stack) {
     195              86 :                         efree(wrapper->err_stack);
     196                 :                 }
     197          116879 :                 wrapper->err_stack = NULL;
     198          116879 :                 wrapper->err_count = 0;
     199                 :         }
     200          116899 : }
     201                 : 
     202                 : PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...)
     203             126 : {
     204                 :         va_list args;
     205             126 :         char *buffer = NULL;
     206                 : 
     207             126 :         va_start(args, fmt);
     208             126 :         vspprintf(&buffer, 0, fmt, args);
     209             126 :         va_end(args);
     210                 : 
     211             160 :         if (options & REPORT_ERRORS || wrapper == NULL) {
     212              34 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", buffer);
     213              34 :                 efree(buffer);
     214                 :         } else {
     215                 :                 /* append to stack */
     216              92 :                 wrapper->err_stack = erealloc(wrapper->err_stack, (wrapper->err_count + 1) * sizeof(char *));
     217              92 :                 if (wrapper->err_stack) {
     218              92 :                         wrapper->err_stack[wrapper->err_count++] = buffer;
     219                 :                 }
     220                 :         }
     221             126 : }
     222                 : 
     223                 : 
     224                 : /* }}} */
     225                 : 
     226                 : /* allocate a new stream for a particular ops */
     227                 : PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract, const char *persistent_id, const char *mode STREAMS_DC TSRMLS_DC) /* {{{ */
     228          193754 : {
     229                 :         php_stream *ret;
     230                 : 
     231          193754 :         ret = (php_stream*) pemalloc_rel_orig(sizeof(php_stream), persistent_id ? 1 : 0);
     232                 : 
     233          193754 :         memset(ret, 0, sizeof(php_stream));
     234                 : 
     235          193754 :         ret->readfilters.stream = ret;
     236          193754 :         ret->writefilters.stream = ret;
     237                 : 
     238                 : #if STREAM_DEBUG
     239                 : fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persistent_id);
     240                 : #endif
     241                 : 
     242          193754 :         ret->ops = ops;
     243          193754 :         ret->abstract = abstract;
     244          193754 :         ret->is_persistent = persistent_id ? 1 : 0;
     245          193754 :         ret->chunk_size = FG(def_chunk_size);
     246                 : 
     247                 : #if ZEND_DEBUG
     248                 :         ret->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename;
     249                 :         ret->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno;
     250                 : #endif
     251                 : 
     252          193754 :         if (FG(auto_detect_line_endings)) {
     253               0 :                 ret->flags |= PHP_STREAM_FLAG_DETECT_EOL;
     254                 :         }
     255                 : 
     256          193754 :         if (persistent_id) {
     257                 :                 zend_rsrc_list_entry le;
     258                 : 
     259            1006 :                 Z_TYPE(le) = le_pstream;
     260            1006 :                 le.ptr = ret;
     261            1006 :                 le.refcount = 0;
     262                 : 
     263            1006 :                 if (FAILURE == zend_hash_update(&EG(persistent_list), (char *)persistent_id,
     264                 :                                         strlen(persistent_id) + 1,
     265                 :                                         (void *)&le, sizeof(le), NULL)) {
     266                 :                         
     267               0 :                         pefree(ret, 1);
     268               0 :                         return NULL;
     269                 :                 }
     270                 :         }
     271                 : 
     272          193754 :         ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, persistent_id ? le_pstream : le_stream);
     273          193754 :         strlcpy(ret->mode, mode, sizeof(ret->mode));
     274                 : 
     275          193754 :         return ret;
     276                 : }
     277                 : /* }}} */
     278                 : 
     279                 : static int _php_stream_free_persistent(zend_rsrc_list_entry *le, void *pStream TSRMLS_DC)
     280              36 : {
     281              36 :         return le->ptr == pStream;
     282                 : }
     283                 : 
     284                 : PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */
     285          257834 : {
     286          257834 :         int ret = 1;
     287          257834 :         int remove_rsrc = 1;
     288          257834 :         int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
     289          257834 :         int release_cast = 1;
     290          257834 :         php_stream_context *context = stream->context;
     291                 : 
     292          257834 :         if (stream->flags & PHP_STREAM_FLAG_NO_CLOSE) {
     293               0 :                 preserve_handle = 1;
     294                 :         }
     295                 : 
     296                 : #if STREAM_DEBUG
     297                 : fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->label, stream, stream->orig_path, stream->in_free, close_options);
     298                 : #endif
     299                 : 
     300                 :         /* recursion protection */
     301          257834 :         if (stream->in_free) {
     302           63947 :                 return 1;
     303                 :         }
     304                 : 
     305          193887 :         stream->in_free++;
     306                 : 
     307                 :         /* if we are releasing the stream only (and preserving the underlying handle),
     308                 :          * we need to do things a little differently.
     309                 :          * We are only ever called like this when the stream is cast to a FILE*
     310                 :          * for include (or other similar) purposes.
     311                 :          * */
     312          193887 :         if (preserve_handle) {
     313               0 :                 if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
     314                 :                         /* If the stream was fopencookied, we must NOT touch anything
     315                 :                          * here, as the cookied stream relies on it all.
     316                 :                          * Instead, mark the stream as OK to auto-clean */
     317                 :                         php_stream_auto_cleanup(stream);
     318               0 :                         stream->in_free--;
     319               0 :                         return 0;
     320                 :                 }
     321                 :                 /* otherwise, make sure that we don't close the FILE* from a cast */
     322               0 :                 release_cast = 0;
     323                 :         }
     324                 : 
     325                 : #if STREAM_DEBUG
     326                 : fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remove_rsrc=%d\n",
     327                 :                 stream->ops->label, stream, stream->orig_path, preserve_handle, release_cast, remove_rsrc);
     328                 : #endif
     329                 : 
     330                 :         /* make sure everything is saved */
     331          193887 :         _php_stream_flush(stream, 1 TSRMLS_CC);
     332                 :                 
     333                 :         /* If not called from the resource dtor, remove the stream from the resource list. */
     334          193887 :         if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0 && remove_rsrc) {
     335           63015 :                 zend_list_delete(stream->rsrc_id);
     336                 :         }
     337                 : 
     338                 :         /* Remove stream from any context link list */
     339          193887 :         if (stream->context && stream->context->links) {
     340               0 :                 php_stream_context_del_link(stream->context, stream);
     341                 :         }
     342                 : 
     343          193887 :         if (close_options & PHP_STREAM_FREE_CALL_DTOR) {
     344          193887 :                 if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
     345                 :                         /* calling fclose on an fopencookied stream will ultimately
     346                 :                                 call this very same function.  If we were called via fclose,
     347                 :                                 the cookie_closer unsets the fclose_stdiocast flags, so
     348                 :                                 we can be sure that we only reach here when PHP code calls
     349                 :                                 php_stream_free.
     350                 :                                 Lets let the cookie code clean it all up.
     351                 :                          */
     352               0 :                         stream->in_free = 0;
     353               0 :                         return fclose(stream->stdiocast);
     354                 :                 }
     355                 : 
     356          193887 :                 ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC);
     357          193885 :                 stream->abstract = NULL;
     358                 : 
     359                 :                 /* tidy up any FILE* that might have been fdopened */
     360          193885 :                 if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FDOPEN && stream->stdiocast) {
     361               0 :                         fclose(stream->stdiocast);
     362               0 :                         stream->stdiocast = NULL;
     363               0 :                         stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE;
     364                 :                 }
     365                 :         }
     366                 : 
     367          193885 :         if (close_options & PHP_STREAM_FREE_RELEASE_STREAM) {
     368          387829 :                 while (stream->readfilters.head) {
     369              59 :                         php_stream_filter_remove(stream->readfilters.head, 1 TSRMLS_CC);
     370                 :                 }
     371          387815 :                 while (stream->writefilters.head) {
     372              45 :                         php_stream_filter_remove(stream->writefilters.head, 1 TSRMLS_CC);
     373                 :                 }
     374                 : 
     375          193885 :                 if (stream->wrapper && stream->wrapper->wops && stream->wrapper->wops->stream_closer) {
     376               0 :                         stream->wrapper->wops->stream_closer(stream->wrapper, stream TSRMLS_CC);
     377               0 :                         stream->wrapper = NULL;
     378                 :                 }
     379                 : 
     380          193885 :                 if (stream->wrapperdata) {
     381              65 :                         zval_ptr_dtor(&stream->wrapperdata);
     382              65 :                         stream->wrapperdata = NULL;
     383                 :                 }
     384                 : 
     385          193885 :                 if (stream->readbuf) {
     386           43748 :                         pefree(stream->readbuf, stream->is_persistent);
     387           43748 :                         stream->readbuf = NULL;
     388                 :                 }
     389                 : 
     390          193885 :                 if (stream->is_persistent && (close_options & PHP_STREAM_FREE_PERSISTENT)) {
     391                 :                         /* we don't work with *stream but need its value for comparison */
     392            1008 :                         zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) _php_stream_free_persistent, stream TSRMLS_CC);
     393                 :                 }
     394                 : #if ZEND_DEBUG
     395                 :                 if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && (stream->__exposed == 0) && (EG(error_reporting) & E_WARNING)) {
     396                 :                         /* it leaked: Lets deliberately NOT pefree it so that the memory manager shows it
     397                 :                          * as leaked; it will log a warning, but lets help it out and display what kind
     398                 :                          * of stream it was. */
     399                 :                         char *leakinfo;
     400                 :                         spprintf(&leakinfo, 0, __FILE__ "(%d) : Stream of type '%s' %p (path:%s) was not closed\n", __LINE__, stream->ops->label, stream, stream->orig_path);
     401                 : 
     402                 :                         if (stream->orig_path) {
     403                 :                                 pefree(stream->orig_path, stream->is_persistent);
     404                 :                                 stream->orig_path = NULL;
     405                 :                         }
     406                 :                         
     407                 : # if defined(PHP_WIN32)
     408                 :                         OutputDebugString(leakinfo);
     409                 : # else
     410                 :                         fprintf(stderr, "%s", leakinfo);
     411                 : # endif
     412                 :                         efree(leakinfo);
     413                 :                 } else {
     414                 :                         if (stream->orig_path) {
     415                 :                                 pefree(stream->orig_path, stream->is_persistent);
     416                 :                                 stream->orig_path = NULL;
     417                 :                         }
     418                 : 
     419                 :                         pefree(stream, stream->is_persistent);
     420                 :                 }
     421                 : #else
     422          193885 :                 if (stream->orig_path) {
     423          135275 :                         pefree(stream->orig_path, stream->is_persistent);
     424          135275 :                         stream->orig_path = NULL;
     425                 :                 }
     426                 : 
     427          193885 :                 pefree(stream, stream->is_persistent);
     428                 : #endif
     429                 :         }
     430                 : 
     431          193885 :         if (context) {
     432             194 :                 zend_list_delete(context->rsrc_id);
     433                 :         }
     434                 : 
     435          193885 :         return ret;
     436                 : }
     437                 : /* }}} */
     438                 : 
     439                 : /* {{{ generic stream operations */
     440                 : 
     441                 : static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC)
     442          838234 : {
     443                 :         /* allocate/fill the buffer */
     444                 : 
     445          838234 :         if (stream->readfilters.head) {
     446                 :                 char *chunk_buf;
     447              69 :                 int err_flag = 0;
     448              69 :                 php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
     449              69 :                 php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out, *brig_swap;
     450                 : 
     451                 :                 /* Invalidate the existing cache, otherwise reads can fail, see note in
     452                 :                    main/streams/filter.c::_php_stream_filter_append */
     453              69 :                 stream->writepos = stream->readpos = 0;
     454                 : 
     455                 :                 /* allocate a buffer for reading chunks */
     456              69 :                 chunk_buf = emalloc(stream->chunk_size);
     457                 : 
     458             185 :                 while (!stream->eof && !err_flag && (stream->writepos - stream->readpos < (off_t)size)) {
     459              62 :                         size_t justread = 0;
     460                 :                         int flags;
     461                 :                         php_stream_bucket *bucket;
     462              62 :                         php_stream_filter_status_t status = PSFS_ERR_FATAL;
     463                 :                         php_stream_filter *filter;
     464                 : 
     465                 :                         /* read a chunk into a bucket */
     466              62 :                         justread = stream->ops->read(stream, chunk_buf, stream->chunk_size TSRMLS_CC);
     467             109 :                         if (justread && justread != (size_t)-1) {
     468              47 :                                 bucket = php_stream_bucket_new(stream, chunk_buf, justread, 0, 0 TSRMLS_CC);
     469                 : 
     470                 :                                 /* after this call, bucket is owned by the brigade */
     471              47 :                                 php_stream_bucket_append(brig_inp, bucket TSRMLS_CC);
     472                 : 
     473              47 :                                 flags = PSFS_FLAG_NORMAL;
     474                 :                         } else {
     475              15 :                                 flags = stream->eof ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC;
     476                 :                         }
     477                 :                 
     478                 :                         /* wind the handle... */
     479             113 :                         for (filter = stream->readfilters.head; filter; filter = filter->next) {
     480              68 :                                 status = filter->fops->filter(stream, filter, brig_inp, brig_outp, NULL, flags TSRMLS_CC);
     481                 : 
     482              68 :                                 if (status != PSFS_PASS_ON) {
     483              17 :                                         break;
     484                 :                                 }
     485                 :                                 
     486                 :                                 /* brig_out becomes brig_in.
     487                 :                                  * brig_in will always be empty here, as the filter MUST attach any un-consumed buckets
     488                 :                                  * to its own brigade */
     489              51 :                                 brig_swap = brig_inp;
     490              51 :                                 brig_inp = brig_outp;
     491              51 :                                 brig_outp = brig_swap;
     492              51 :                                 memset(brig_outp, 0, sizeof(*brig_outp));
     493                 :                         }
     494                 :                         
     495              62 :                         switch (status) {
     496                 :                                 case PSFS_PASS_ON:
     497                 :                                         /* we get here when the last filter in the chain has data to pass on.
     498                 :                                          * in this situation, we are passing the brig_in brigade into the
     499                 :                                          * stream read buffer */
     500             123 :                                         while (brig_inp->head) {
     501              33 :                                                 bucket = brig_inp->head;
     502                 :                                                 /* grow buffer to hold this bucket
     503                 :                                                  * TODO: this can fail for persistent streams */
     504              33 :                                                 if (stream->readbuflen - stream->writepos < bucket->buflen) {
     505              24 :                                                         stream->readbuflen += bucket->buflen;
     506              24 :                                                         stream->readbuf = perealloc(stream->readbuf, stream->readbuflen,
     507                 :                                                                         stream->is_persistent);
     508                 :                                                 }
     509              33 :                                                 memcpy(stream->readbuf + stream->writepos, bucket->buf, bucket->buflen);
     510              33 :                                                 stream->writepos += bucket->buflen;
     511                 : 
     512              33 :                                                 php_stream_bucket_unlink(bucket TSRMLS_CC);
     513              33 :                                                 php_stream_bucket_delref(bucket TSRMLS_CC);
     514                 :                                         }
     515              45 :                                         break;
     516                 : 
     517                 :                                 case PSFS_FEED_ME:
     518                 :                                         /* when a filter needs feeding, there is no brig_out to deal with.
     519                 :                                          * we simply continue the loop; if the caller needs more data,
     520                 :                                          * we will read again, otherwise out job is done here */
     521               2 :                                         if (justread == 0) {
     522                 :                                                 /* there is no data */
     523               2 :                                                 err_flag = 1;
     524               2 :                                                 break;
     525                 :                                         }
     526               0 :                                         continue;
     527                 : 
     528                 :                                 case PSFS_ERR_FATAL:
     529                 :                                         /* some fatal error. Theoretically, the stream is borked, so all
     530                 :                                          * further reads should fail. */
     531              15 :                                         err_flag = 1;
     532                 :                                         break;
     533                 :                         }
     534                 : 
     535              62 :                         if (justread == 0 || justread == (size_t)-1) {
     536                 :                                 break;
     537                 :                         }
     538                 :                 }
     539                 : 
     540              69 :                 efree(chunk_buf);
     541                 : 
     542                 :         } else {
     543                 :                 /* is there enough data in the buffer ? */
     544          838165 :                 if (stream->writepos - stream->readpos < (off_t)size) {
     545          838163 :                         size_t justread = 0;
     546                 : 
     547                 :                         /* reduce buffer memory consumption if possible, to avoid a realloc */
     548          838163 :                         if (stream->readbuf && stream->readbuflen - stream->writepos < stream->chunk_size) {
     549          773005 :                                 memmove(stream->readbuf, stream->readbuf + stream->readpos, stream->readbuflen - stream->readpos);
     550          773005 :                                 stream->writepos -= stream->readpos;
     551          773005 :                                 stream->readpos = 0;
     552                 :                         }
     553                 : 
     554                 :                         /* grow the buffer if required
     555                 :                          * TODO: this can fail for persistent streams */
     556          838163 :                         if (stream->readbuflen - stream->writepos < stream->chunk_size) {
     557           43743 :                                 stream->readbuflen += stream->chunk_size;
     558           43743 :                                 stream->readbuf = perealloc(stream->readbuf, stream->readbuflen,
     559                 :                                                 stream->is_persistent);
     560                 :                         }
     561                 : 
     562          838163 :                         justread = stream->ops->read(stream, stream->readbuf + stream->writepos,
     563                 :                                         stream->readbuflen - stream->writepos
     564                 :                                         TSRMLS_CC);
     565                 : 
     566          838163 :                         if (justread != (size_t)-1) {
     567          837861 :                                 stream->writepos += justread;
     568                 :                         }
     569                 :                 }
     570                 :         }
     571          838234 : }
     572                 : 
     573                 : PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC)
     574         1648238 : {
     575         1648238 :         size_t toread = 0, didread = 0;
     576                 : 
     577         3391467 :         while (size > 0) {
     578                 : 
     579                 :                 /* take from the read buffer first.
     580                 :                  * It is possible that a buffered stream was switched to non-buffered, so we
     581                 :                  * drain the remainder of the buffer before using the "raw" read mode for
     582                 :                  * the excess */
     583         1652296 :                 if (stream->writepos > stream->readpos) {
     584                 : 
     585          797330 :                         toread = stream->writepos - stream->readpos;
     586          797330 :                         if (toread > size) {
     587          751230 :                                 toread = size;
     588                 :                         }
     589                 : 
     590          797330 :                         memcpy(buf, stream->readbuf + stream->readpos, toread);
     591          797330 :                         stream->readpos += toread;
     592          797330 :                         size -= toread;
     593          797330 :                         buf += toread;
     594          797330 :                         didread += toread;
     595                 :                 }
     596                 : 
     597                 :                 /* ignore eof here; the underlying state might have changed */
     598         1652296 :                 if (size == 0) {
     599          791094 :                         break;
     600                 :                 }
     601                 : 
     602          930131 :                 if (!stream->readfilters.head && (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1)) {
     603           68929 :                         toread = stream->ops->read(stream, buf, size TSRMLS_CC);
     604                 :                 } else {
     605          792273 :                         php_stream_fill_read_buffer(stream, size TSRMLS_CC);
     606                 : 
     607          792273 :                         toread = stream->writepos - stream->readpos;
     608          792273 :                         if (toread > size) {
     609           55841 :                                 toread = size;
     610                 :                         }
     611                 : 
     612          792273 :                         if (toread > 0) {
     613          757976 :                                 memcpy(buf, stream->readbuf + stream->readpos, toread);
     614          757976 :                                 stream->readpos += toread;
     615                 :                         }
     616                 :                 }
     617          861202 :                 if (toread > 0) {
     618          823463 :                         didread += toread;
     619          823463 :                         buf += toread;
     620          823463 :                         size -= toread;
     621                 :                 } else {
     622                 :                         /* EOF, or temporary end of data (for non-blocking mode). */
     623           37739 :                         break;
     624                 :                 }
     625                 : 
     626                 :                 /* just break anyway, to avoid greedy read */
     627          823463 :                 if (stream->wrapper != &php_plain_files_wrapper) {
     628          728472 :                         break;
     629                 :                 }
     630                 :         }
     631                 : 
     632         1648238 :         if (didread > 0) {
     633         1617681 :                 stream->position += didread;
     634                 :         }
     635                 : 
     636         1648238 :         return didread;
     637                 : }
     638                 : 
     639                 : PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC)
     640         1076130 : {
     641                 :         /* if there is data in the buffer, it's not EOF */
     642         1076130 :         if (stream->writepos - stream->readpos > 0) {
     643         1034939 :                 return 0;
     644                 :         }
     645                 : 
     646                 :         /* use the configured timeout when checking eof */
     647           41191 :         if (!stream->eof && PHP_STREAM_OPTION_RETURN_ERR ==
     648                 :                         php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS,
     649                 :                         0, NULL)) {
     650               4 :                 stream->eof = 1;
     651                 :         }
     652                 : 
     653           41191 :         return stream->eof;
     654                 : }
     655                 : 
     656                 : PHPAPI int _php_stream_putc(php_stream *stream, int c TSRMLS_DC)
     657              49 : {
     658              49 :         unsigned char buf = c;
     659                 : 
     660              49 :         if (php_stream_write(stream, &buf, 1) > 0) {
     661              49 :                 return 1;
     662                 :         }
     663               0 :         return EOF;
     664                 : }
     665                 : 
     666                 : PHPAPI int _php_stream_getc(php_stream *stream TSRMLS_DC)
     667          533762 : {
     668                 :         char buf;
     669                 : 
     670          533762 :         if (php_stream_read(stream, &buf, 1) > 0) {
     671          533733 :                 return buf & 0xff;
     672                 :         }
     673              29 :         return EOF;
     674                 : }
     675                 : 
     676                 : PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC)
     677               0 : {
     678                 :         int len;
     679               0 :         char newline[2] = "\n"; /* is this OK for Win? */
     680               0 :         len = strlen(buf);
     681                 : 
     682               0 :         if (len > 0 && php_stream_write(stream, buf, len) && php_stream_write(stream, newline, 1)) {
     683               0 :                 return 1;
     684                 :         }
     685               0 :         return 0;
     686                 : }
     687                 : 
     688                 : PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
     689           33410 : {
     690           33410 :         memset(ssb, 0, sizeof(*ssb));
     691                 : 
     692                 :         /* if the stream was wrapped, allow the wrapper to stat it */
     693           33410 :         if (stream->wrapper && stream->wrapper->wops->stream_stat != NULL) {
     694               0 :                 return stream->wrapper->wops->stream_stat(stream->wrapper, stream, ssb TSRMLS_CC);
     695                 :         }
     696                 : 
     697                 :         /* if the stream doesn't directly support stat-ing, return with failure.
     698                 :          * We could try and emulate this by casting to a FD and fstat-ing it,
     699                 :          * but since the fd might not represent the actual underlying content
     700                 :          * this would give bogus results. */
     701           33410 :         if (stream->ops->stat == NULL) {
     702              12 :                 return -1;
     703                 :         }
     704                 : 
     705           33398 :         return (stream->ops->stat)(stream, ssb TSRMLS_CC);
     706                 : }
     707                 : 
     708                 : PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC)
     709         1383687 : {
     710                 :         size_t avail;
     711         1383687 :         char *cr, *lf, *eol = NULL;
     712                 :         char *readptr;
     713                 : 
     714         1383687 :         if (!buf) {
     715         1383546 :                 readptr = stream->readbuf + stream->readpos;
     716         1383546 :                 avail = stream->writepos - stream->readpos;
     717                 :         } else {
     718             141 :                 readptr = buf;
     719             141 :                 avail = buf_len;
     720                 :         }       
     721                 : 
     722                 :         /* Look for EOL */
     723         1383687 :         if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) {
     724               0 :                 cr = memchr(readptr, '\r', avail);
     725               0 :                 lf = memchr(readptr, '\n', avail);
     726                 : 
     727               0 :                 if (cr && lf != cr + 1 && !(lf && lf < cr)) {
     728                 :                         /* mac */
     729               0 :                         stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL;
     730               0 :                         stream->flags |= PHP_STREAM_FLAG_EOL_MAC;
     731               0 :                         eol = cr;
     732               0 :                 } else if ((cr && lf && cr == lf - 1) || (lf)) {
     733                 :                         /* dos or unix endings */
     734               0 :                         stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL;
     735               0 :                         eol = lf;
     736                 :                 }
     737         1383687 :         } else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) {
     738               0 :                 eol = memchr(readptr, '\r', avail);
     739                 :         } else {
     740                 :                 /* unix (and dos) line endings */
     741         1383687 :                 eol = memchr(readptr, '\n', avail);
     742                 :         }
     743                 : 
     744         1383687 :         return eol;
     745                 : }
     746                 : 
     747                 : /* If buf == NULL, the buffer will be allocated automatically and will be of an
     748                 :  * appropriate length to hold the line, regardless of the line length, memory
     749                 :  * permitting */
     750                 : PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen,
     751                 :                 size_t *returned_len TSRMLS_DC)
     752         1378121 : {
     753         1378121 :         size_t avail = 0;
     754         1378121 :         size_t current_buf_size = 0;
     755         1378121 :         size_t total_copied = 0;
     756         1378121 :         int grow_mode = 0;
     757         1378121 :         char *bufstart = buf;
     758                 : 
     759         1378121 :         if (buf == NULL) {
     760         1051933 :                 grow_mode = 1;
     761          326188 :         } else if (maxlen == 0) {
     762               0 :                 return NULL;
     763                 :         }
     764                 : 
     765                 :         /*
     766                 :          * If the underlying stream operations block when no new data is readable,
     767                 :          * we need to take extra precautions.
     768                 :          *
     769                 :          * If there is buffered data available, we check for a EOL. If it exists,
     770                 :          * we pass the data immediately back to the caller. This saves a call
     771                 :          * to the read implementation and will not block where blocking
     772                 :          * is not necessary at all.
     773                 :          *
     774                 :          * If the stream buffer contains more data than the caller requested,
     775                 :          * we can also avoid that costly step and simply return that data.
     776                 :          */
     777                 : 
     778                 :         for (;;) {
     779         1429785 :                 avail = stream->writepos - stream->readpos;
     780                 : 
     781         1429785 :                 if (avail > 0) {
     782         1383546 :                         size_t cpysz = 0;
     783                 :                         char *readptr;
     784                 :                         char *eol;
     785         1383546 :                         int done = 0;
     786                 : 
     787         1383546 :                         readptr = stream->readbuf + stream->readpos;
     788         1383546 :                         eol = php_stream_locate_eol(stream, NULL, 0 TSRMLS_CC);
     789                 : 
     790         1383546 :                         if (eol) {
     791         1364724 :                                 cpysz = eol - readptr + 1;
     792         1364724 :                                 done = 1;
     793                 :                         } else {
     794           18822 :                                 cpysz = avail;
     795                 :                         }
     796                 : 
     797         1383546 :                         if (grow_mode) {
     798                 :                                 /* allow room for a NUL. If this realloc is really a realloc
     799                 :                                  * (ie: second time around), we get an extra byte. In most
     800                 :                                  * cases, with the default chunk size of 8K, we will only
     801                 :                                  * incur that overhead once.  When people have lines longer
     802                 :                                  * than 8K, we waste 1 byte per additional 8K or so.
     803                 :                                  * That seems acceptable to me, to avoid making this code
     804                 :                                  * hard to follow */
     805         1041765 :                                 bufstart = erealloc(bufstart, current_buf_size + cpysz + 1);
     806         1041765 :                                 current_buf_size += cpysz + 1;
     807         1041765 :                                 buf = bufstart + total_copied;
     808                 :                         } else {
     809          341781 :                                 if (cpysz >= maxlen - 1) {
     810             590 :                                         cpysz = maxlen - 1;
     811             590 :                                         done = 1;
     812                 :                                 }
     813                 :                         }
     814                 : 
     815         1383546 :                         memcpy(buf, readptr, cpysz);
     816                 : 
     817         1383546 :                         stream->position += cpysz;
     818         1383546 :                         stream->readpos += cpysz;
     819         1383546 :                         buf += cpysz;
     820         1383546 :                         maxlen -= cpysz;
     821         1383546 :                         total_copied += cpysz;
     822                 : 
     823         1383546 :                         if (done) {
     824         1364817 :                                 break;
     825                 :                         }
     826           46239 :                 } else if (stream->eof) {
     827             310 :                         break;
     828                 :                 } else {
     829                 :                         /* XXX: Should be fine to always read chunk_size */
     830                 :                         size_t toread;
     831                 :                         
     832           45929 :                         if (grow_mode) {
     833           25502 :                                 toread = stream->chunk_size;
     834                 :                         } else {
     835           20427 :                                 toread = maxlen - 1;
     836           20427 :                                 if (toread > stream->chunk_size) {
     837               0 :                                         toread = stream->chunk_size;
     838                 :                                 }
     839                 :                         }
     840                 : 
     841           45929 :                         php_stream_fill_read_buffer(stream, toread TSRMLS_CC);
     842                 : 
     843           45929 :                         if (stream->writepos - stream->readpos == 0) {
     844           12994 :                                 break;
     845                 :                         }
     846                 :                 }
     847           51664 :         }
     848                 : 
     849         1378121 :         if (total_copied == 0) {
     850                 :                 if (grow_mode) {
     851                 :                         assert(bufstart == NULL);
     852                 :                 }
     853           11307 :                 return NULL;
     854                 :         }
     855                 : 
     856         1366814 :         buf[0] = '\0';
     857         1366814 :         if (returned_len) {
     858         1365338 :                 *returned_len = total_copied;
     859                 :         }
     860                 : 
     861         1366814 :         return bufstart;
     862                 : }
     863                 : 
     864                 : PHPAPI char *php_stream_get_record(php_stream *stream, size_t maxlen, size_t *returned_len, char *delim, size_t delim_len TSRMLS_DC)
     865              37 : {
     866                 :         char *e, *buf;
     867                 :         size_t toread, len;
     868              37 :         int skip = 0;
     869                 : 
     870              37 :         len = stream->writepos - stream->readpos;
     871                 : 
     872              82 :         while (len < maxlen) {
     873                 : 
     874                 :                 size_t just_read;
     875              32 :                 toread = MIN(maxlen - len, stream->chunk_size);
     876                 : 
     877              32 :                 php_stream_fill_read_buffer(stream, len + toread TSRMLS_CC);
     878                 : 
     879              32 :                 just_read = (stream->writepos - stream->readpos) - len;
     880              32 :                 len += just_read;
     881                 : 
     882              32 :                 if (just_read < toread) {
     883              24 :                         break;
     884                 :                 }
     885                 :         }
     886                 : 
     887              37 :         if (delim_len == 0 || !delim) {
     888               0 :                 toread = maxlen;
     889                 :         } else {
     890                 :                 size_t seek_len;
     891                 : 
     892              37 :                 seek_len = stream->writepos - stream->readpos;
     893              37 :                 if (seek_len > maxlen) {
     894              11 :                         seek_len = maxlen;
     895                 :                 }
     896                 : 
     897              37 :                 if (delim_len == 1) {
     898              12 :                         e = memchr(stream->readbuf + stream->readpos, *delim, seek_len);
     899                 :                 } else {
     900              25 :                         e = php_memnstr(stream->readbuf + stream->readpos, delim, delim_len, (stream->readbuf + stream->readpos + seek_len));
     901                 :                 }
     902                 : 
     903              37 :                 if (!e) {
     904              14 :                         if (seek_len < maxlen && !stream->eof) {
     905               6 :                                 return NULL;
     906                 :                         }
     907               8 :                         toread = maxlen;
     908                 :                 } else {
     909              23 :                         toread = e - (char *) stream->readbuf - stream->readpos;
     910              23 :                         skip = 1;
     911                 :                 }
     912                 :         }
     913                 : 
     914              31 :         if (toread > maxlen && maxlen > 0) {
     915               0 :                 toread = maxlen;
     916                 :         }
     917                 : 
     918              31 :         buf = emalloc(toread + 1);
     919              31 :         *returned_len = php_stream_read(stream, buf, toread);
     920                 : 
     921                 :         if (*returned_len >= 0) {
     922              31 :                 if (skip) {
     923              23 :                         stream->readpos += delim_len;
     924              23 :                         stream->position += delim_len;
     925                 :                 }
     926              31 :                 buf[*returned_len] = '\0';
     927              31 :                 return buf;
     928                 :         } else {
     929                 :                 efree(buf);
     930                 :                 return NULL;
     931                 :         }
     932                 : }
     933                 : 
     934                 : /* Writes a buffer directly to a stream, using multiple of the chunk size */
     935                 : static size_t _php_stream_write_buffer(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
     936          203960 : {
     937          203960 :         size_t didwrite = 0, towrite, justwrote;
     938                 : 
     939                 :         /* if we have a seekable stream we need to ensure that data is written at the
     940                 :          * current stream->position. This means invalidating the read buffer and then
     941                 :          * performing a low-level seek */
     942          203960 :         if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && stream->readpos != stream->writepos) {
     943               1 :                 stream->readpos = stream->writepos = 0;
     944                 : 
     945               1 :                 stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC);
     946                 :         }
     947                 : 
     948                 :  
     949          612451 :         while (count > 0) {
     950          204604 :                 towrite = count;
     951          204604 :                 if (towrite > stream->chunk_size)
     952             640 :                         towrite = stream->chunk_size;
     953                 : 
     954          204604 :                 justwrote = stream->ops->write(stream, buf, towrite TSRMLS_CC);
     955                 : 
     956                 :                 /* convert justwrote to an integer, since normally it is unsigned */
     957          204604 :                 if ((int)justwrote > 0) {
     958          204531 :                         buf += justwrote;
     959          204531 :                         count -= justwrote;
     960          204531 :                         didwrite += justwrote;
     961                 :                         
     962                 :                         /* Only screw with the buffer if we can seek, otherwise we lose data
     963                 :                          * buffered from fifos and sockets */
     964          204531 :                         if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
     965          174194 :                                 stream->position += justwrote;
     966                 :                         }
     967                 :                 } else {
     968              73 :                         break;
     969                 :                 }
     970                 :         }
     971          203960 :         return didwrite;
     972                 : 
     973                 : }
     974                 : 
     975                 : /* push some data through the write filter chain.
     976                 :  * buf may be NULL, if flags are set to indicate a flush.
     977                 :  * This may trigger a real write to the stream.
     978                 :  * Returns the number of bytes consumed from buf by the first filter in the chain.
     979                 :  * */
     980                 : static size_t _php_stream_write_filtered(php_stream *stream, const char *buf, size_t count, int flags TSRMLS_DC)
     981             265 : {
     982             265 :         size_t consumed = 0;
     983                 :         php_stream_bucket *bucket;
     984             265 :         php_stream_bucket_brigade brig_in = { NULL, NULL }, brig_out = { NULL, NULL };
     985             265 :         php_stream_bucket_brigade *brig_inp = &brig_in, *brig_outp = &brig_out, *brig_swap;
     986             265 :         php_stream_filter_status_t status = PSFS_ERR_FATAL;
     987                 :         php_stream_filter *filter;
     988                 : 
     989             265 :         if (buf) {
     990             150 :                 bucket = php_stream_bucket_new(stream, (char *)buf, count, 0, 0 TSRMLS_CC);
     991             150 :                 php_stream_bucket_append(&brig_in, bucket TSRMLS_CC);
     992                 :         }
     993                 : 
     994             387 :         for (filter = stream->writefilters.head; filter; filter = filter->next) {
     995                 :                 /* for our return value, we are interested in the number of bytes consumed from
     996                 :                  * the first filter in the chain */
     997             276 :                 status = filter->fops->filter(stream, filter, brig_inp, brig_outp,
     998                 :                                 filter == stream->writefilters.head ? &consumed : NULL, flags TSRMLS_CC);
     999                 : 
    1000             276 :                 if (status != PSFS_PASS_ON) {
    1001             154 :                         break;
    1002                 :                 }
    1003                 :                 /* brig_out becomes brig_in.
    1004                 :                  * brig_in will always be empty here, as the filter MUST attach any un-consumed buckets
    1005                 :                  * to its own brigade */
    1006             122 :                 brig_swap = brig_inp;
    1007             122 :                 brig_inp = brig_outp;
    1008             122 :                 brig_outp = brig_swap;
    1009             122 :                 memset(brig_outp, 0, sizeof(*brig_outp));
    1010                 :         }
    1011                 : 
    1012             265 :         switch (status) {
    1013                 :                 case PSFS_PASS_ON:
    1014                 :                         /* filter chain generated some output; push it through to the
    1015                 :                          * underlying stream */
    1016             482 :                         while (brig_inp->head) {
    1017             260 :                                 bucket = brig_inp->head;
    1018             260 :                                 _php_stream_write_buffer(stream, bucket->buf, bucket->buflen TSRMLS_CC);
    1019                 :                                 /* Potential error situation - eg: no space on device. Perhaps we should keep this brigade
    1020                 :                                  * hanging around and try to write it later.
    1021                 :                                  * At the moment, we just drop it on the floor
    1022                 :                                  * */
    1023                 : 
    1024             260 :                                 php_stream_bucket_unlink(bucket TSRMLS_CC);
    1025             260 :                                 php_stream_bucket_delref(bucket TSRMLS_CC);
    1026                 :                         }
    1027                 :                         break;
    1028                 :                 case PSFS_FEED_ME:
    1029                 :                         /* need more data before we can push data through to the stream */
    1030                 :                         break;
    1031                 : 
    1032                 :                 case PSFS_ERR_FATAL:
    1033                 :                         /* some fatal error.  Theoretically, the stream is borked, so all
    1034                 :                          * further writes should fail. */
    1035                 :                         break;
    1036                 :         }
    1037                 : 
    1038             265 :         return consumed;
    1039                 : }
    1040                 : 
    1041                 : PHPAPI int _php_stream_flush(php_stream *stream, int closing TSRMLS_DC)
    1042          194926 : {
    1043          194926 :         int ret = 0;
    1044                 : 
    1045          194926 :         if (stream->writefilters.head) {
    1046             115 :                 _php_stream_write_filtered(stream, NULL, 0, closing ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC  TSRMLS_CC);
    1047                 :         }
    1048                 : 
    1049          194926 :         if (stream->ops->flush) {
    1050          191738 :                 ret = stream->ops->flush(stream TSRMLS_CC);
    1051                 :         }
    1052                 : 
    1053          194926 :         return ret;
    1054                 : }
    1055                 : 
    1056                 : PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
    1057          211821 : {
    1058          211821 :         if (buf == NULL || count == 0 || stream->ops->write == NULL) {
    1059            7971 :                 return 0;
    1060                 :         }
    1061                 : 
    1062          203850 :         if (stream->writefilters.head) {
    1063             150 :                 return _php_stream_write_filtered(stream, buf, count, PSFS_FLAG_NORMAL TSRMLS_CC);
    1064                 :         } else {
    1065          203700 :                 return _php_stream_write_buffer(stream, buf, count TSRMLS_CC);
    1066                 :         }
    1067                 : }
    1068                 : 
    1069                 : PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...)
    1070             134 : {
    1071                 :         size_t count;
    1072                 :         char *buf;
    1073                 :         va_list ap;
    1074                 : 
    1075             134 :         va_start(ap, fmt);
    1076             134 :         count = vspprintf(&buf, 0, fmt, ap);
    1077             134 :         va_end(ap);
    1078                 : 
    1079             134 :         if (!buf) {
    1080               0 :                 return 0; /* error condition */
    1081                 :         }
    1082                 : 
    1083             134 :         count = php_stream_write(stream, buf, count);
    1084             134 :         efree(buf);
    1085                 : 
    1086             134 :         return count;
    1087                 : }
    1088                 : 
    1089                 : PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC)
    1090           61985 : {
    1091           61985 :         return stream->position;
    1092                 : }
    1093                 : 
    1094                 : PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)
    1095           72778 : {
    1096                 :         /* handle the case where we are in the buffer */
    1097           72778 :         if ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) == 0) {
    1098           72104 :                 switch(whence) {
    1099                 :                         case SEEK_CUR:
    1100           17987 :                                 if (offset > 0 && offset < stream->writepos - stream->readpos) {
    1101             436 :                                         stream->readpos += offset;
    1102             436 :                                         stream->position += offset;
    1103             436 :                                         stream->eof = 0;
    1104             436 :                                         return 0;
    1105                 :                                 }
    1106           17551 :                                 break;
    1107                 :                         case SEEK_SET:
    1108           51898 :                                 if (offset > stream->position &&
    1109                 :                                                 offset < stream->position + stream->writepos - stream->readpos) {
    1110             811 :                                         stream->readpos += offset - stream->position;
    1111             811 :                                         stream->position = offset;
    1112             811 :                                         stream->eof = 0;
    1113             811 :                                         return 0;
    1114                 :                                 }
    1115                 :                                 break;
    1116                 :                 }
    1117                 :         }
    1118                 : 
    1119                 : 
    1120           71531 :         if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
    1121                 :                 int ret;
    1122                 :                 
    1123           71529 :                 if (stream->writefilters.head) {
    1124               1 :                         _php_stream_flush(stream, 0 TSRMLS_CC);
    1125                 :                 }
    1126                 :                 
    1127           71529 :                 switch(whence) {
    1128                 :                         case SEEK_CUR:
    1129           17559 :                                 offset = stream->position + offset;
    1130           17559 :                                 whence = SEEK_SET;
    1131                 :                                 break;
    1132                 :                 }
    1133           71529 :                 ret = stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC);
    1134                 : 
    1135           71529 :                 if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0) {
    1136           71529 :                         if (ret == 0) {
    1137           71321 :                                 stream->eof = 0;
    1138                 :                         }
    1139                 : 
    1140                 :                         /* invalidate the buffer contents */
    1141           71529 :                         stream->readpos = stream->writepos = 0;
    1142                 : 
    1143           71529 :                         return ret;
    1144                 :                 }
    1145                 :                 /* else the stream has decided that it can't support seeking after all;
    1146                 :                  * fall through to attempt emulation */
    1147                 :         }
    1148                 : 
    1149                 :         /* emulate forward moving seeks with reads */
    1150               2 :         if (whence == SEEK_CUR && offset > 0) {
    1151                 :                 char tmp[1024];
    1152               0 :                 while(offset >= sizeof(tmp)) {
    1153               0 :                         if (php_stream_read(stream, tmp, sizeof(tmp)) == 0) {
    1154               0 :                                 return -1;
    1155                 :                         }
    1156               0 :                         offset -= sizeof(tmp);
    1157                 :                 }
    1158               0 :                 if (offset && (php_stream_read(stream, tmp, offset) == 0)) {
    1159               0 :                         return -1;
    1160                 :                 }
    1161               0 :                 stream->eof = 0;
    1162               0 :                 return 0;
    1163                 :         }
    1164                 : 
    1165               2 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream does not support seeking");
    1166                 : 
    1167               2 :         return -1;
    1168                 : }
    1169                 : 
    1170                 : PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
    1171          108400 : {
    1172          108400 :         int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;
    1173                 : 
    1174          108400 :         if (stream->ops->set_option) {
    1175          107703 :                 ret = stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC);
    1176                 :         }
    1177                 : 
    1178          108400 :         if (ret == PHP_STREAM_OPTION_RETURN_NOTIMPL) {
    1179           28679 :                 switch(option) {
    1180                 :                         case PHP_STREAM_OPTION_SET_CHUNK_SIZE:
    1181               0 :                                 ret = stream->chunk_size;
    1182               0 :                                 stream->chunk_size = value;
    1183               0 :                                 return ret;
    1184                 : 
    1185                 :                         case PHP_STREAM_OPTION_READ_BUFFER:
    1186                 :                                 /* try to match the buffer mode as best we can */
    1187               0 :                                 if (value == PHP_STREAM_BUFFER_NONE) {
    1188               0 :                                         stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
    1189                 :                                 } else {
    1190               0 :                                         stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER;
    1191                 :                                 }
    1192               0 :                                 ret = PHP_STREAM_OPTION_RETURN_OK;
    1193                 :                                 break;
    1194                 :                                 
    1195                 :                         default:
    1196                 :                                 ;
    1197                 :                 }
    1198                 :         }
    1199                 : 
    1200          108400 :         return ret;
    1201                 : }
    1202                 : 
    1203                 : PHPAPI int _php_stream_truncate_set_size(php_stream *stream, size_t newsize TSRMLS_DC)
    1204             398 : {
    1205             398 :         return php_stream_set_option(stream, PHP_STREAM_OPTION_TRUNCATE_API, PHP_STREAM_TRUNCATE_SET_SIZE, &newsize);
    1206                 : }
    1207                 : 
    1208                 : PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC)
    1209             539 : {
    1210             539 :         size_t bcount = 0;
    1211                 :         char buf[8192];
    1212                 :         int b;
    1213                 : 
    1214             539 :         if (php_stream_mmap_possible(stream)) {
    1215                 :                 char *p;
    1216                 :                 size_t mapped;
    1217                 : 
    1218             478 :                 p = php_stream_mmap_range(stream, php_stream_tell(stream), PHP_STREAM_MMAP_ALL, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
    1219                 : 
    1220             478 :                 if (p) {
    1221             372 :                         PHPWRITE(p, mapped);
    1222                 : 
    1223             372 :                         php_stream_mmap_unmap_ex(stream, mapped);
    1224                 : 
    1225             372 :                         return mapped;
    1226                 :                 }
    1227                 :         }
    1228                 : 
    1229             412 :         while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) {
    1230              78 :                 PHPWRITE(buf, b);
    1231              78 :                 bcount += b;
    1232                 :         }
    1233                 : 
    1234             167 :         return bcount;
    1235                 : }
    1236                 : 
    1237                 : 
    1238                 : PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent STREAMS_DC TSRMLS_DC)
    1239            2633 : {
    1240            2633 :         size_t ret = 0;
    1241                 :         char *ptr;
    1242            2633 :         size_t len = 0, max_len;
    1243            2633 :         int step = CHUNK_SIZE;
    1244            2633 :         int min_room = CHUNK_SIZE / 4;
    1245                 :         php_stream_statbuf ssbuf;
    1246                 : 
    1247            2633 :         if (maxlen == 0) { 
    1248              10 :                 return 0;
    1249                 :         }
    1250                 : 
    1251            2623 :         if (maxlen == PHP_STREAM_COPY_ALL) {
    1252            2550 :                 maxlen = 0;
    1253                 :         }
    1254                 : 
    1255            2623 :         if (maxlen > 0) {
    1256              73 :                 ptr = *buf = pemalloc_rel_orig(maxlen + 1, persistent);
    1257             218 :                 while ((len < maxlen) && !php_stream_eof(src)) {
    1258              72 :                         ret = php_stream_read(src, ptr, maxlen - len);
    1259              72 :                         len += ret;
    1260              72 :                         ptr += ret;
    1261                 :                 }
    1262              73 :                 *ptr = '\0';
    1263              73 :                 return len;
    1264                 :         }
    1265                 : 
    1266                 :         /* avoid many reallocs by allocating a good sized chunk to begin with, if
    1267                 :          * we can.  Note that the stream may be filtered, in which case the stat
    1268                 :          * result may be inaccurate, as the filter may inflate or deflate the
    1269                 :          * number of bytes that we can read.  In order to avoid an upsize followed
    1270                 :          * by a downsize of the buffer, overestimate by the step size (which is
    1271                 :          * 2K).  */
    1272            4573 :         if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) {
    1273            2023 :                 max_len = ssbuf.sb.st_size + step;
    1274                 :         } else {
    1275             527 :                 max_len = step;
    1276                 :         }
    1277                 : 
    1278            2550 :         ptr = *buf = pemalloc_rel_orig(max_len, persistent);
    1279                 : 
    1280            8608 :         while((ret = php_stream_read(src, ptr, max_len - len))) {
    1281            3508 :                 len += ret;
    1282            3508 :                 if (len + min_room >= max_len) {
    1283              14 :                         *buf = perealloc_rel_orig(*buf, max_len + step, persistent);
    1284              14 :                         max_len += step;
    1285              14 :                         ptr = *buf + len;
    1286                 :                 } else {
    1287            3494 :                         ptr += ret;
    1288                 :                 }
    1289                 :         }
    1290            2550 :         if (len) {
    1291            2137 :                 *buf = perealloc_rel_orig(*buf, len + 1, persistent);
    1292            2137 :                 (*buf)[len] = '\0';
    1293                 :         } else {
    1294             413 :                 pefree(*buf, persistent);
    1295             413 :                 *buf = NULL;
    1296                 :         }
    1297            2550 :         return len;
    1298                 : }
    1299                 : 
    1300                 : /* Returns SUCCESS/FAILURE and sets *len to the number of bytes moved */
    1301                 : PHPAPI size_t _php_stream_copy_to_stream_ex(php_stream *src, php_stream *dest, size_t maxlen, size_t *len STREAMS_DC TSRMLS_DC)
    1302           26738 : {
    1303                 :         char buf[CHUNK_SIZE];
    1304                 :         size_t readchunk;
    1305           26738 :         size_t haveread = 0;
    1306                 :         size_t didread;
    1307                 :         size_t dummy;
    1308                 :         php_stream_statbuf ssbuf;
    1309                 : 
    1310           26738 :         if (!len) {
    1311            7223 :                 len = &dummy;
    1312                 :         }
    1313                 : 
    1314           26738 :         if (maxlen == 0) {
    1315            4125 :                 *len = 0;
    1316            4125 :                 return SUCCESS;
    1317                 :         }
    1318                 : 
    1319           22613 :         if (maxlen == PHP_STREAM_COPY_ALL) {
    1320           12355 :                 maxlen = 0;
    1321                 :         }
    1322                 : 
    1323           22613 :         if (php_stream_stat(src, &ssbuf) == 0) {
    1324           22611 :                 if (ssbuf.sb.st_size == 0
    1325                 : #ifdef S_ISREG
    1326                 :                         && S_ISREG(ssbuf.sb.st_mode)
    1327                 : #endif
    1328                 :                 ) {
    1329            4122 :                         *len = 0;
    1330            4122 :                         return SUCCESS;
    1331                 :                 }
    1332                 :         }
    1333                 : 
    1334           18491 :         if (php_stream_mmap_possible(src)) {
    1335                 :                 char *p;
    1336                 :                 size_t mapped;
    1337                 : 
    1338           18467 :                 p = php_stream_mmap_range(src, php_stream_tell(src), maxlen, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped);
    1339                 : 
    1340           18467 :                 if (p) {
    1341           13924 :                         mapped = php_stream_write(dest, p, mapped);
    1342                 : 
    1343           13924 :                         php_stream_mmap_unmap_ex(src, mapped);
    1344                 : 
    1345           13924 :                         *len = mapped;
    1346                 :                         
    1347                 :                         /* we've got at least 1 byte to read. 
    1348                 :                          * less than 1 is an error */
    1349                 : 
    1350           13924 :                         if (mapped > 0) {
    1351           13924 :                                 return SUCCESS;
    1352                 :                         }
    1353               0 :                         return FAILURE;
    1354                 :                 }
    1355                 :         }
    1356                 : 
    1357                 :         while(1) {
    1358            4599 :                 readchunk = sizeof(buf);
    1359                 : 
    1360            4599 :                 if (maxlen && (maxlen - haveread) < readchunk) {
    1361            4558 :                         readchunk = maxlen - haveread;
    1362                 :                 }
    1363                 : 
    1364            4599 :                 didread = php_stream_read(src, buf, readchunk);
    1365                 : 
    1366            4599 :                 if (didread) {
    1367                 :                         /* extra paranoid */
    1368                 :                         size_t didwrite, towrite;
    1369                 :                         char *writeptr;
    1370                 : 
    1371            4589 :                         towrite = didread;
    1372            4589 :                         writeptr = buf;
    1373            4589 :                         haveread += didread;
    1374                 : 
    1375           13767 :                         while(towrite) {
    1376            4589 :                                 didwrite = php_stream_write(dest, writeptr, towrite);
    1377            4589 :                                 if (didwrite == 0) {
    1378               0 :                                         *len = haveread - (didread - towrite);
    1379               0 :                                         return FAILURE;
    1380                 :                                 }
    1381                 : 
    1382            4589 :                                 towrite -= didwrite;
    1383            4589 :                                 writeptr += didwrite;
    1384                 :                         }
    1385                 :                 } else {
    1386              10 :                         break;
    1387                 :                 }
    1388                 : 
    1389            4589 :                 if (maxlen - haveread == 0) {
    1390            4557 :                         break;
    1391                 :                 }
    1392              32 :         }
    1393                 : 
    1394            4567 :         *len = haveread;
    1395                 : 
    1396                 :         /* we've got at least 1 byte to read. 
    1397                 :          * less than 1 is an error */
    1398                 : 
    1399            4567 :         if (haveread > 0) {
    1400            4565 :                 return SUCCESS;
    1401                 :         }
    1402               2 :         return FAILURE;
    1403                 : }
    1404                 : 
    1405                 : /* Returns the number of bytes moved.
    1406                 :  * Returns 1 when source len is 0. 
    1407                 :  * Deprecated in favor of php_stream_copy_to_stream_ex() */
    1408                 : ZEND_ATTRIBUTE_DEPRECATED
    1409                 : PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen STREAMS_DC TSRMLS_DC)
    1410              24 : {
    1411                 :         size_t len;
    1412              24 :         int ret = _php_stream_copy_to_stream_ex(src, dest, maxlen, &len STREAMS_REL_CC TSRMLS_CC);
    1413              24 :         if (ret == SUCCESS && len == 0 && maxlen != 0) {
    1414               0 :                 return 1;
    1415                 :         }
    1416              24 :         return len;
    1417                 : }
    1418                 : /* }}} */
    1419                 : 
    1420                 : /* {{{ wrapper init and registration */
    1421                 : 
    1422                 : static void stream_resource_regular_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
    1423          192820 : {
    1424          192820 :         php_stream *stream = (php_stream*)rsrc->ptr;
    1425                 :         /* set the return value for pclose */
    1426          192820 :         FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
    1427          192819 : }
    1428                 : 
    1429                 : static void stream_resource_persistent_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
    1430            1006 : {
    1431            1006 :         php_stream *stream = (php_stream*)rsrc->ptr;
    1432            1006 :         FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
    1433            1006 : }
    1434                 : 
    1435                 : void php_shutdown_stream_hashes(TSRMLS_D)
    1436           17651 : {
    1437           17651 :         if (FG(stream_wrappers)) {
    1438              26 :                 zend_hash_destroy(FG(stream_wrappers));
    1439              26 :                 efree(FG(stream_wrappers));
    1440              26 :                 FG(stream_wrappers) = NULL;
    1441                 :         }
    1442                 : 
    1443           17651 :         if (FG(stream_filters)) {
    1444               9 :                 zend_hash_destroy(FG(stream_filters));
    1445               9 :                 efree(FG(stream_filters));
    1446               9 :                 FG(stream_filters) = NULL;
    1447                 :         }
    1448           17651 : }
    1449                 : 
    1450                 : int php_init_stream_wrappers(int module_number TSRMLS_DC)
    1451           17633 : {
    1452           17633 :         le_stream = zend_register_list_destructors_ex(stream_resource_regular_dtor, NULL, "stream", module_number);
    1453           17633 :         le_pstream = zend_register_list_destructors_ex(NULL, stream_resource_persistent_dtor, "persistent stream", module_number);
    1454                 : 
    1455                 :         /* Filters are cleaned up by the streams they're attached to */
    1456           17633 :         le_stream_filter = zend_register_list_destructors_ex(NULL, NULL, "stream filter", module_number);
    1457                 : 
    1458           17633 :         return (
    1459                 :                         zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1) == SUCCESS
    1460                 :                         && 
    1461                 :                         zend_hash_init(php_get_stream_filters_hash_global(), 0, NULL, NULL, 1) == SUCCESS
    1462                 :                         &&
    1463                 :                         zend_hash_init(php_stream_xport_get_hash(), 0, NULL, NULL, 1) == SUCCESS
    1464                 :                         &&
    1465                 :                         php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
    1466                 :                         &&
    1467                 :                         php_stream_xport_register("udp", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
    1468                 : #if defined(AF_UNIX) && !(defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE))
    1469                 :                         &&
    1470                 :                         php_stream_xport_register("unix", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
    1471                 :                         &&
    1472                 :                         php_stream_xport_register("udg", php_stream_generic_socket_factory TSRMLS_CC) == SUCCESS
    1473                 : #endif
    1474                 :                 ) ? SUCCESS : FAILURE;
    1475                 : }
    1476                 : 
    1477                 : int php_shutdown_stream_wrappers(int module_number TSRMLS_DC)
    1478           17665 : {
    1479           17665 :         zend_hash_destroy(&url_stream_wrappers_hash);
    1480           17665 :         zend_hash_destroy(php_get_stream_filters_hash_global());
    1481           17665 :         zend_hash_destroy(php_stream_xport_get_hash());
    1482           17665 :         return SUCCESS;
    1483                 : }
    1484                 : 
    1485                 : /* Validate protocol scheme names during registration
    1486                 :  * Must conform to /^[a-zA-Z0-9+.-]+$/
    1487                 :  */
    1488                 : static inline int php_stream_wrapper_scheme_validate(char *protocol, int protocol_len)
    1489          317427 : {
    1490                 :         int i;
    1491                 : 
    1492         1939848 :         for(i = 0; i < protocol_len; i++) {
    1493         1622421 :                 if (!isalnum((int)protocol[i]) &&
    1494                 :                         protocol[i] != '+' &&
    1495                 :                         protocol[i] != '-' &&
    1496                 :                         protocol[i] != '.') {
    1497               0 :                         return FAILURE;
    1498                 :                 }
    1499                 :         }
    1500                 : 
    1501          317427 :         return SUCCESS;
    1502                 : }
    1503                 : 
    1504                 : /* API for registering GLOBAL wrappers */
    1505                 : PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC)
    1506          317394 : {
    1507          317394 :         int protocol_len = strlen(protocol);
    1508                 : 
    1509          317394 :         if (php_stream_wrapper_scheme_validate(protocol, protocol_len) == FAILURE) {
    1510               0 :                 return FAILURE;
    1511                 :         }
    1512                 : 
    1513          317394 :         return zend_hash_add(&url_stream_wrappers_hash, protocol, protocol_len + 1, &wrapper, sizeof(wrapper), NULL);
    1514                 : }
    1515                 : 
    1516                 : PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC)
    1517          335379 : {
    1518          335379 :         return zend_hash_del(&url_stream_wrappers_hash, protocol, strlen(protocol) + 1);
    1519                 : }
    1520                 : 
    1521                 : static void clone_wrapper_hash(TSRMLS_D)
    1522              26 : {
    1523                 :         php_stream_wrapper *tmp;
    1524                 : 
    1525              26 :         ALLOC_HASHTABLE(FG(stream_wrappers));
    1526              26 :         zend_hash_init(FG(stream_wrappers), zend_hash_num_elements(&url_stream_wrappers_hash), NULL, NULL, 1);
    1527              26 :         zend_hash_copy(FG(stream_wrappers), &url_stream_wrappers_hash, NULL, &tmp, sizeof(tmp));
    1528              26 : }
    1529                 : 
    1530                 : /* API for registering VOLATILE wrappers */
    1531                 : PHPAPI int php_register_url_stream_wrapper_volatile(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC)
    1532              33 : {
    1533              33 :         int protocol_len = strlen(protocol);
    1534                 : 
    1535              33 :         if (php_stream_wrapper_scheme_validate(protocol, protocol_len) == FAILURE) {
    1536               0 :                 return FAILURE;
    1537                 :         }
    1538                 : 
    1539              33 :         if (!FG(stream_wrappers)) {
    1540              25 :                 clone_wrapper_hash(TSRMLS_C);
    1541                 :         }
    1542                 : 
    1543              33 :         return zend_hash_add(FG(stream_wrappers), protocol, protocol_len + 1, &wrapper, sizeof(wrapper), NULL);
    1544                 : }
    1545                 : 
    1546                 : PHPAPI int php_unregister_url_stream_wrapper_volatile(char *protocol TSRMLS_DC)
    1547               2 : {
    1548               2 :         if (!FG(stream_wrappers)) {
    1549               1 :                 clone_wrapper_hash(TSRMLS_C);
    1550                 :         }
    1551                 : 
    1552               2 :         return zend_hash_del(FG(stream_wrappers), protocol, strlen(protocol) + 1);
    1553                 : }
    1554                 : /* }}} */
    1555                 : 
    1556                 : /* {{{ php_stream_locate_url_wrapper */
    1557                 : PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC)
    1558          474385 : {
    1559          474385 :         HashTable *wrapper_hash = (FG(stream_wrappers) ? FG(stream_wrappers) : &url_stream_wrappers_hash);
    1560          474385 :         php_stream_wrapper **wrapperpp = NULL;
    1561          474385 :         const char *p, *protocol = NULL;
    1562          474385 :         int n = 0;
    1563                 : 
    1564          474385 :         if (path_for_open) {
    1565          301080 :                 *path_for_open = (char*)path;
    1566                 :         }
    1567                 : 
    1568          474385 :         if (options & IGNORE_URL) {
    1569            5682 :                 return (options & STREAM_LOCATE_WRAPPERS_ONLY) ? NULL : &php_plain_files_wrapper;
    1570                 :         }
    1571                 : 
    1572          675779 :         for (p = path; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
    1573          207076 :                 n++;
    1574                 :         }
    1575                 : 
    1576          523012 :         if ((*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || (n == 4 && !memcmp("data:", path, 5)))) {
    1577           54309 :                 protocol = path;
    1578          414394 :         } else if (n == 5 && strncasecmp(path, "zlib:", 5) == 0) {
    1579                 :                 /* BC with older php scripts and zlib wrapper */
    1580               0 :                 protocol = "compress.zlib";
    1581               0 :                 n = 13;
    1582               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Use of \"zlib:\" wrapper is deprecated; please use \"compress.zlib://\" instead");
    1583                 :         }
    1584                 : 
    1585          468703 :         if (protocol) {
    1586           54309 :                 char *tmp = estrndup(protocol, n);
    1587           54309 :                 if (FAILURE == zend_hash_find(wrapper_hash, (char*)tmp, n + 1, (void**)&wrapperpp)) {
    1588               3 :                         php_strtolower(tmp, n);
    1589               3 :                         if (FAILURE == zend_hash_find(wrapper_hash, (char*)tmp, n + 1, (void**)&wrapperpp)) {
    1590                 :                                 char wrapper_name[32];
    1591                 : 
    1592               2 :                                 if (n >= sizeof(wrapper_name)) {
    1593               0 :                                         n = sizeof(wrapper_name) - 1;
    1594                 :                                 }
    1595               2 :                                 PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
    1596                 : 
    1597               2 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find the wrapper \"%s\" - did you forget to enable it when you configured PHP?", wrapper_name);
    1598                 : 
    1599               2 :                                 wrapperpp = NULL;
    1600               2 :                                 protocol = NULL;
    1601                 :                         }
    1602                 :                 }
    1603           54309 :                 efree(tmp);
    1604                 :         }
    1605                 :         /* TODO: curl based streams probably support file:// properly */
    1606          468703 :         if (!protocol || !strncasecmp(protocol, "file", n))   {
    1607                 :                 /* fall back on regular file access */
    1608          414441 :                 php_stream_wrapper *plain_files_wrapper = &php_plain_files_wrapper;
    1609                 : 
    1610          414441 :                 if (protocol) {
    1611              45 :                         int localhost = 0;
    1612                 : 
    1613              45 :                         if (!strncasecmp(path, "file://localhost/", 17)) {
    1614               0 :                                 localhost = 1;
    1615                 :                         }
    1616                 : 
    1617                 : #ifdef PHP_WIN32
    1618                 :                         if (localhost == 0 && path[n+3] != '\0' && path[n+3] != '/' && path[n+4] != ':')        {
    1619                 : #else
    1620              45 :                         if (localhost == 0 && path[n+3] != '\0' && path[n+3] != '/') {
    1621                 : #endif
    1622              18 :                                 if (options & REPORT_ERRORS) {
    1623              12 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "remote host file access not supported, %s", path);
    1624                 :                                 }
    1625              18 :                                 return NULL;
    1626                 :                         }
    1627                 : 
    1628              27 :                         if (path_for_open) {
    1629                 :                                 /* skip past protocol and :/, but handle windows correctly */
    1630              26 :                                 *path_for_open = (char*)path + n + 1;
    1631              26 :                                 if (localhost == 1) {
    1632               0 :                                         (*path_for_open) += 11;
    1633                 :                                 }
    1634              79 :                                 while (*(++*path_for_open)=='/');
    1635                 : #ifdef PHP_WIN32
    1636                 :                                 if (*(*path_for_open + 1) != ':')
    1637                 : #endif
    1638              26 :                                         (*path_for_open)--;
    1639                 :                         }
    1640                 :                 }
    1641                 : 
    1642          414423 :                 if (options & STREAM_LOCATE_WRAPPERS_ONLY) {
    1643             584 :                         return NULL;
    1644                 :                 }
    1645                 : 
    1646          413839 :                 if (FG(stream_wrappers)) {
    1647                 :                 /* The file:// wrapper may have been disabled/overridden */
    1648                 : 
    1649              11 :                         if (wrapperpp) {
    1650                 :                                 /* It was found so go ahead and provide it */
    1651               1 :                                 return *wrapperpp;
    1652                 :                         }
    1653                 : 
    1654                 :                         /* Check again, the original check might have not known the protocol name */
    1655              10 :                         if (zend_hash_find(wrapper_hash, "file", sizeof("file"), (void**)&wrapperpp) == SUCCESS) {
    1656               9 :                                 return *wrapperpp;
    1657                 :                         }
    1658                 : 
    1659               1 :                         if (options & REPORT_ERRORS) {
    1660               1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "file:// wrapper is disabled in the server configuration");
    1661                 :                         }
    1662               1 :                         return NULL;
    1663                 :                 }
    1664                 :                 
    1665          413828 :                 return plain_files_wrapper;
    1666                 :         }
    1667                 : 
    1668           54262 :         if (wrapperpp && (*wrapperpp)->is_url &&         
    1669                 :         (options & STREAM_DISABLE_URL_PROTECTION) == 0 &&
    1670                 :             (!PG(allow_url_fopen) || 
    1671                 :              (((options & STREAM_OPEN_FOR_INCLUDE) ||
    1672                 :                PG(in_user_include)) && !PG(allow_url_include)))) {
    1673              10 :                 if (options & REPORT_ERRORS) {
    1674                 :                         /* protocol[n] probably isn't '\0' */
    1675               7 :                         char *protocol_dup = estrndup(protocol, n);
    1676               7 :                         if (!PG(allow_url_fopen)) {
    1677               4 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// wrapper is disabled in the server configuration by allow_url_fopen=0", protocol_dup);
    1678                 :                         } else {
    1679               3 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// wrapper is disabled in the server configuration by allow_url_include=0", protocol_dup);
    1680                 :                         }
    1681               7 :                         efree(protocol_dup);
    1682                 :                 }
    1683              10 :                 return NULL;
    1684                 :         }
    1685                 : 
    1686           54252 :         return *wrapperpp;
    1687                 : }
    1688                 : /* }}} */
    1689                 : 
    1690                 : /* {{{ _php_stream_mkdir
    1691                 :  */
    1692                 : PHPAPI int _php_stream_mkdir(char *path, int mode, int options, php_stream_context *context TSRMLS_DC)
    1693            1675 : {
    1694            1675 :         php_stream_wrapper *wrapper = NULL;
    1695                 : 
    1696            1675 :         wrapper = php_stream_locate_url_wrapper(path, NULL, ENFORCE_SAFE_MODE TSRMLS_CC);
    1697            1675 :         if (!wrapper || !wrapper->wops || !wrapper->wops->stream_mkdir) {
    1698               1 :                 return 0;
    1699                 :         }
    1700                 : 
    1701            1674 :         return wrapper->wops->stream_mkdir(wrapper, path, mode, options, context TSRMLS_CC);
    1702                 : }
    1703                 : /* }}} */
    1704                 : 
    1705                 : /* {{{ _php_stream_rmdir
    1706                 :  */
    1707                 : PHPAPI int _php_stream_rmdir(char *path, int options, php_stream_context *context TSRMLS_DC)
    1708            1693 : {
    1709            1693 :         php_stream_wrapper *wrapper = NULL;
    1710                 : 
    1711            1693 :         wrapper = php_stream_locate_url_wrapper(path, NULL, ENFORCE_SAFE_MODE TSRMLS_CC);
    1712            1693 :         if (!wrapper || !wrapper->wops || !wrapper->wops->stream_rmdir) {
    1713               1 :                 return 0;
    1714                 :         }
    1715                 : 
    1716            1692 :         return wrapper->wops->stream_rmdir(wrapper, path, options, context TSRMLS_CC);
    1717                 : }
    1718                 : /* }}} */
    1719                 : 
    1720                 : /* {{{ _php_stream_stat_path */
    1721                 : PHPAPI int _php_stream_stat_path(char *path, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
    1722           87621 : {
    1723           87621 :         php_stream_wrapper *wrapper = NULL;
    1724           87621 :         char *path_to_open = path;
    1725                 :         int ret;
    1726                 : 
    1727                 :         /* Try to hit the cache first */
    1728           87621 :         if (flags & PHP_STREAM_URL_STAT_LINK) {
    1729            3194 :                 if (BG(CurrentLStatFile) && strcmp(path, BG(CurrentLStatFile)) == 0) {
    1730               8 :                         memcpy(ssb, &BG(lssb), sizeof(php_stream_statbuf));
    1731               8 :                         return 0;
    1732                 :                 }
    1733                 :         } else {
    1734           84427 :                 if (BG(CurrentStatFile) && strcmp(path, BG(CurrentStatFile)) == 0) {
    1735            4969 :                         memcpy(ssb, &BG(ssb), sizeof(php_stream_statbuf));
    1736            4969 :                         return 0;
    1737                 :                 }
    1738                 :         }
    1739                 : 
    1740           82644 :         wrapper = php_stream_locate_url_wrapper(path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
    1741           82644 :         if (wrapper && wrapper->wops->url_stat) {
    1742           82631 :                 ret = wrapper->wops->url_stat(wrapper, path_to_open, flags, ssb, context TSRMLS_CC);
    1743           82631 :                 if (ret == 0) {
    1744                 :                         /* Drop into cache */
    1745           81496 :                         if (flags & PHP_STREAM_URL_STAT_LINK) {
    1746            3161 :                                 if (BG(CurrentLStatFile)) {
    1747            3085 :                                         efree(BG(CurrentLStatFile));
    1748                 :                                 }
    1749            3161 :                                 BG(CurrentLStatFile) = estrdup(path);
    1750            3161 :                                 memcpy(&BG(lssb), ssb, sizeof(php_stream_statbuf));
    1751                 :                         } else {
    1752           78335 :                                 if (BG(CurrentStatFile)) {
    1753           59001 :                                         efree(BG(CurrentStatFile));
    1754                 :                                 }
    1755           78335 :                                 BG(CurrentStatFile) = estrdup(path);
    1756           78335 :                                 memcpy(&BG(ssb), ssb, sizeof(php_stream_statbuf));
    1757                 :                         }
    1758                 :                 }
    1759           82631 :                 return ret;
    1760                 :         }
    1761              13 :         return -1;
    1762                 : }
    1763                 : /* }}} */
    1764                 : 
    1765                 : /* {{{ php_stream_opendir */
    1766                 : PHPAPI php_stream *_php_stream_opendir(char *path, int options,
    1767                 :                 php_stream_context *context STREAMS_DC TSRMLS_DC)
    1768            3749 : {
    1769            3749 :         php_stream *stream = NULL;
    1770            3749 :         php_stream_wrapper *wrapper = NULL;
    1771                 :         char *path_to_open;
    1772                 : 
    1773            3749 :         if (!path || !*path) {
    1774              16 :                 return NULL;
    1775                 :         }
    1776                 : 
    1777            3733 :         path_to_open = path;
    1778                 : 
    1779            3733 :         wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC);
    1780                 : 
    1781            7463 :         if (wrapper && wrapper->wops->dir_opener) {
    1782            3730 :                 stream = wrapper->wops->dir_opener(wrapper,
    1783                 :                                 path_to_open, "r", options ^ REPORT_ERRORS, NULL,
    1784                 :                                 context STREAMS_REL_CC TSRMLS_CC);
    1785                 : 
    1786            3730 :                 if (stream) {
    1787            3638 :                         stream->wrapper = wrapper;
    1788            3638 :                         stream->flags |= PHP_STREAM_FLAG_NO_BUFFER | PHP_STREAM_FLAG_IS_DIR;
    1789                 :                 }
    1790               3 :         } else if (wrapper) {
    1791               3 :                 php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC, "not implemented");
    1792                 :         }
    1793            3733 :         if (stream == NULL && (options & REPORT_ERRORS)) {
    1794              95 :                 php_stream_display_wrapper_errors(wrapper, path, "failed to open dir" TSRMLS_CC);
    1795                 :         }
    1796            3733 :         php_stream_tidy_wrapper_error_log(wrapper TSRMLS_CC);
    1797                 : 
    1798            3733 :         return stream;
    1799                 : }
    1800                 : /* }}} */
    1801                 : 
    1802                 : /* {{{ _php_stream_readdir */
    1803                 : PHPAPI php_stream_dirent *_php_stream_readdir(php_stream *dirstream, php_stream_dirent *ent TSRMLS_DC)
    1804           68217 : {
    1805                 : 
    1806           68217 :         if (sizeof(php_stream_dirent) == php_stream_read(dirstream, (char*)ent, sizeof(php_stream_dirent))) {
    1807           64916 :                 return ent;
    1808                 :         }
    1809                 : 
    1810            3301 :         return NULL;
    1811                 : }
    1812                 : /* }}} */
    1813                 : 
    1814                 : /* {{{ php_stream_open_wrapper_ex */
    1815                 : PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options,
    1816                 :                 char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
    1817          122182 : {
    1818          122182 :         php_stream *stream = NULL;
    1819          122182 :         php_stream_wrapper *wrapper = NULL;
    1820                 :         char *path_to_open;
    1821          122182 :         int persistent = options & STREAM_OPEN_PERSISTENT;
    1822          122182 :         char *resolved_path = NULL;
    1823          122182 :         char *copy_of_path = NULL;
    1824                 : 
    1825                 :         
    1826          122182 :         if (opened_path) {
    1827           11874 :                 *opened_path = NULL;
    1828                 :         }
    1829                 : 
    1830          122182 :         if (!path || !*path) {
    1831              69 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filename cannot be empty");
    1832              69 :                 return NULL;
    1833                 :         }
    1834                 : 
    1835          122113 :         if (options & USE_PATH) {
    1836            8132 :                 resolved_path = zend_resolve_path(path, strlen(path) TSRMLS_CC);
    1837            8132 :                 if (resolved_path) {
    1838            7772 :                         path = resolved_path;
    1839                 :                         /* we've found this file, don't re-check include_path or run realpath */
    1840            7772 :                         options |= STREAM_ASSUME_REALPATH;
    1841            7772 :                         options &= ~USE_PATH;
    1842                 :                 }
    1843                 :         }
    1844                 : 
    1845          122113 :         path_to_open = path;
    1846                 : 
    1847          122113 :         wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC);
    1848          122113 :         if (options & STREAM_USE_URL && (!wrapper || !wrapper->is_url)) {
    1849               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function may only be used against URLs");
    1850               0 :                 if (resolved_path) {
    1851               0 :                         efree(resolved_path);
    1852                 :                 }
    1853               0 :                 return NULL;
    1854                 :         }
    1855                 : 
    1856          122113 :         if (wrapper) {
    1857          122093 :                 if (!wrapper->wops->stream_opener) {
    1858               0 :                         php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC,
    1859                 :                                         "wrapper does not support stream open");
    1860                 :                 } else {
    1861          122093 :                         stream = wrapper->wops->stream_opener(wrapper,
    1862                 :                                 path_to_open, mode, options ^ REPORT_ERRORS,
    1863                 :                                 opened_path, context STREAMS_REL_CC TSRMLS_CC);
    1864                 :                 }
    1865                 : 
    1866                 :                 /* if the caller asked for a persistent stream but the wrapper did not
    1867                 :                  * return one, force an error here */
    1868          122092 :                 if (stream && (options & STREAM_OPEN_PERSISTENT) && !stream->is_persistent) {
    1869               0 :                         php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC,
    1870                 :                                         "wrapper does not support persistent streams");
    1871               0 :                         php_stream_close(stream);
    1872               0 :                         stream = NULL;
    1873                 :                 }
    1874                 :                 
    1875          122092 :                 if (stream) {
    1876          121349 :                         stream->wrapper = wrapper;
    1877                 :                 }
    1878                 :         }
    1879                 : 
    1880          122112 :         if (stream) {
    1881          121349 :                 if (opened_path && !*opened_path && resolved_path) {
    1882               2 :                         *opened_path = resolved_path;
    1883               2 :                         resolved_path = NULL;
    1884                 :                 }
    1885          121349 :                 if (stream->orig_path) {
    1886               1 :                         pefree(stream->orig_path, persistent);
    1887                 :                 }
    1888          121349 :                 copy_of_path = pestrdup(path, persistent);
    1889          121349 :                 stream->orig_path = copy_of_path;
    1890                 : #if ZEND_DEBUG
    1891                 :                 stream->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename;
    1892                 :                 stream->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno;
    1893                 : #endif
    1894                 :         }
    1895                 : 
    1896          122112 :         if (stream != NULL && (options & STREAM_MUST_SEEK)) {
    1897                 :                 php_stream *newstream;
    1898                 : 
    1899            8946 :                 switch(php_stream_make_seekable_rel(stream, &newstream,
    1900                 :                                         (options & STREAM_WILL_CAST)
    1901                 :                                                 ? PHP_STREAM_PREFER_STDIO : PHP_STREAM_NO_PREFERENCE)) {
    1902                 :                         case PHP_STREAM_UNCHANGED:
    1903            8946 :                                 if (resolved_path) {
    1904              42 :                                         efree(resolved_path);
    1905                 :                                 }
    1906            8946 :                                 return stream;
    1907                 :                         case PHP_STREAM_RELEASED:
    1908               0 :                                 if (newstream->orig_path) {
    1909               0 :                                         pefree(newstream->orig_path, persistent);
    1910                 :                                 }
    1911               0 :                                 newstream->orig_path = pestrdup(path, persistent);
    1912               0 :                                 if (resolved_path) {
    1913               0 :                                         efree(resolved_path);
    1914                 :                                 }
    1915               0 :                                 return newstream;
    1916                 :                         default:
    1917               0 :                                 php_stream_close(stream);
    1918               0 :                                 stream = NULL;
    1919               0 :                                 if (options & REPORT_ERRORS) {
    1920               0 :                                         char *tmp = estrdup(path);
    1921               0 :                                         php_strip_url_passwd(tmp);
    1922               0 :                                         php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "could not make seekable - %s",
    1923                 :                                                         tmp);
    1924               0 :                                         efree(tmp);
    1925                 : 
    1926               0 :                                         options ^= REPORT_ERRORS;
    1927                 :                                 }
    1928                 :                 }
    1929                 :         }
    1930                 : 
    1931          113166 :         if (stream && stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) {
    1932            1367 :                 off_t newpos = 0;
    1933                 : 
    1934                 :                 /* if opened for append, we need to revise our idea of the initial file position */
    1935            1367 :                 if (0 == stream->ops->seek(stream, 0, SEEK_CUR, &newpos TSRMLS_CC)) {
    1936            1367 :                         stream->position = newpos;
    1937                 :                 }
    1938                 :         }
    1939                 : 
    1940          113166 :         if (stream == NULL && (options & REPORT_ERRORS)) {
    1941             345 :                 php_stream_display_wrapper_errors(wrapper, path, "failed to open stream" TSRMLS_CC);
    1942             345 :                 if (opened_path && *opened_path) {
    1943               0 :                         efree(*opened_path);
    1944               0 :                         *opened_path = NULL;
    1945                 :                 }
    1946                 :         }
    1947          113166 :         php_stream_tidy_wrapper_error_log(wrapper TSRMLS_CC);
    1948                 : #if ZEND_DEBUG
    1949                 :         if (stream == NULL && copy_of_path != NULL) {
    1950                 :                 pefree(copy_of_path, persistent);
    1951                 :         }
    1952                 : #endif
    1953          113166 :         if (resolved_path) {
    1954            7728 :                 efree(resolved_path);
    1955                 :         }
    1956          113166 :         return stream;
    1957                 : }
    1958                 : /* }}} */
    1959                 : 
    1960                 : /* {{{ context API */
    1961                 : PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context)
    1962            1829 : {
    1963            1829 :         php_stream_context *oldcontext = stream->context;
    1964                 :         TSRMLS_FETCH();
    1965                 : 
    1966            1829 :         stream->context = context;
    1967                 : 
    1968            1829 :         if (context) {
    1969             125 :                 zend_list_addref(context->rsrc_id);
    1970                 :         }
    1971            1829 :         if (oldcontext) {
    1972               0 :                 zend_list_delete(oldcontext->rsrc_id);
    1973                 :         }
    1974                 : 
    1975            1829 :         return oldcontext;
    1976                 : }
    1977                 : 
    1978                 : PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity,
    1979                 :                 char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC)
    1980               0 : {
    1981               0 :         if (context && context->notifier)
    1982               0 :                 context->notifier->func(context, notifycode, severity, xmsg, xcode, bytes_sofar, bytes_max, ptr TSRMLS_CC);
    1983               0 : }
    1984                 : 
    1985                 : PHPAPI void php_stream_context_free(php_stream_context *context)
    1986            3545 : {
    1987            3545 :         if (context->options) {
    1988               0 :                 zval_ptr_dtor(&context->options);
    1989               0 :                 context->options = NULL;
    1990                 :         }
    1991            3545 :         if (context->notifier) {
    1992               1 :                 php_stream_notification_free(context->notifier);
    1993               1 :                 context->notifier = NULL;
    1994                 :         }
    1995            3545 :         if (context->links) {
    1996               0 :                 zval_ptr_dtor(&context->links);
    1997               0 :                 context->links = NULL;
    1998                 :         }
    1999            3545 :         efree(context);
    2000            3545 : }
    2001                 : 
    2002                 : PHPAPI php_stream_context *php_stream_context_alloc(void)
    2003            3519 : {
    2004                 :         php_stream_context *context;
    2005                 : 
    2006            3519 :         context = ecalloc(1, sizeof(php_stream_context));
    2007            3519 :         context->notifier = NULL;
    2008            3519 :         MAKE_STD_ZVAL(context->options);
    2009            3519 :         array_init(context->options);
    2010                 : 
    2011            3519 :         context->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, context, php_le_stream_context());
    2012            3519 :         return context;
    2013                 : }
    2014                 : 
    2015                 : PHPAPI php_stream_notifier *php_stream_notification_alloc(void)
    2016               2 : {
    2017               2 :         return ecalloc(1, sizeof(php_stream_notifier));
    2018                 : }
    2019                 : 
    2020                 : PHPAPI void php_stream_notification_free(php_stream_notifier *notifier)
    2021               2 : {
    2022               2 :         if (notifier->dtor) {
    2023               2 :                 notifier->dtor(notifier);
    2024                 :         }
    2025               2 :         efree(notifier);
    2026               2 : }
    2027                 : 
    2028                 : PHPAPI int php_stream_context_get_option(php_stream_context *context,
    2029                 :                 const char *wrappername, const char *optionname, zval ***optionvalue)
    2030             926 : {
    2031                 :         zval **wrapperhash;
    2032                 : 
    2033             926 :         if (FAILURE == zend_hash_find(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&wrapperhash)) {
    2034             796 :                 return FAILURE;
    2035                 :         }
    2036             130 :         return zend_hash_find(Z_ARRVAL_PP(wrapperhash), (char*)optionname, strlen(optionname)+1, (void**)optionvalue);
    2037                 : }
    2038                 : 
    2039                 : PHPAPI int php_stream_context_set_option(php_stream_context *context,
    2040                 :                 const char *wrappername, const char *optionname, zval *optionvalue)
    2041            1481 : {
    2042                 :         zval **wrapperhash;
    2043                 :         zval *category, *copied_val;
    2044                 : 
    2045            1481 :         ALLOC_INIT_ZVAL(copied_val);
    2046            1481 :         *copied_val = *optionvalue;
    2047            1481 :         zval_copy_ctor(copied_val);
    2048            1481 :         INIT_PZVAL(copied_val);
    2049                 : 
    2050            1481 :         if (FAILURE == zend_hash_find(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&wrapperhash)) {
    2051             744 :                 MAKE_STD_ZVAL(category);
    2052             744 :                 array_init(category);
    2053             744 :                 if (FAILURE == zend_hash_update(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&category, sizeof(zval *), NULL)) {
    2054               0 :                         return FAILURE;
    2055                 :                 }
    2056                 : 
    2057             744 :                 wrapperhash = &category;
    2058                 :         }
    2059            1481 :         return zend_hash_update(Z_ARRVAL_PP(wrapperhash), (char*)optionname, strlen(optionname)+1, (void**)&copied_val, sizeof(zval *), NULL);
    2060                 : }
    2061                 : 
    2062                 : PHPAPI int php_stream_context_get_link(php_stream_context *context,
    2063                 :         const char *hostent, php_stream **stream)
    2064               0 : {
    2065                 :         php_stream **pstream;
    2066                 : 
    2067               0 :         if (!stream || !hostent || !context || !(context->links)) {
    2068               0 :                 return FAILURE;
    2069                 :         }
    2070               0 :         if (SUCCESS == zend_hash_find(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1, (void**)&pstream)) {
    2071               0 :                 *stream = *pstream;
    2072               0 :                 return SUCCESS;
    2073                 :         }
    2074               0 :         return FAILURE;
    2075                 : }
    2076                 : 
    2077                 : PHPAPI int php_stream_context_set_link(php_stream_context *context,
    2078                 :         const char *hostent, php_stream *stream)
    2079               0 : {
    2080               0 :         if (!context) {
    2081               0 :                 return FAILURE;
    2082                 :         }
    2083               0 :         if (!context->links) {
    2084               0 :                 ALLOC_INIT_ZVAL(context->links);
    2085               0 :                 array_init(context->links);
    2086                 :         }
    2087               0 :         if (!stream) {
    2088                 :                 /* Delete any entry for <hostent> */
    2089               0 :                 return zend_hash_del(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1);
    2090                 :         }
    2091               0 :         return zend_hash_update(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1, (void**)&stream, sizeof(php_stream *), NULL);
    2092                 : }
    2093                 : 
    2094                 : PHPAPI int php_stream_context_del_link(php_stream_context *context,
    2095                 :         php_stream *stream)
    2096               0 : {
    2097                 :         php_stream **pstream;
    2098                 :         char *hostent;
    2099               0 :         int ret = SUCCESS;
    2100                 : 
    2101               0 :         if (!context || !context->links || !stream) {
    2102               0 :                 return FAILURE;
    2103                 :         }
    2104                 : 
    2105               0 :         for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(context->links));
    2106               0 :                 SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(context->links), (void**)&pstream);
    2107               0 :                 zend_hash_move_forward(Z_ARRVAL_P(context->links))) {
    2108               0 :                 if (*pstream == stream) {
    2109               0 :                         if (SUCCESS == zend_hash_get_current_key(Z_ARRVAL_P(context->links), &hostent, NULL, 0)) {
    2110               0 :                                 if (FAILURE == zend_hash_del(Z_ARRVAL_P(context->links), (char*)hostent, strlen(hostent)+1)) {
    2111               0 :                                         ret = FAILURE;
    2112                 :                                 }
    2113                 :                         } else {
    2114               0 :                                 ret = FAILURE;
    2115                 :                         }
    2116                 :                 }
    2117                 :         }
    2118                 : 
    2119               0 :         return ret;
    2120                 : }
    2121                 : /* }}} */
    2122                 : 
    2123                 : /* {{{ php_stream_dirent_alphasort
    2124                 :  */
    2125                 : PHPAPI int php_stream_dirent_alphasort(const char **a, const char **b)
    2126             124 : {
    2127             124 :         return strcoll(*a, *b);
    2128                 : }
    2129                 : /* }}} */
    2130                 : 
    2131                 : /* {{{ php_stream_dirent_alphasortr
    2132                 :  */
    2133                 : PHPAPI int php_stream_dirent_alphasortr(const char **a, const char **b)
    2134              24 : {
    2135              24 :         return strcoll(*b, *a);
    2136                 : }
    2137                 : /* }}} */
    2138                 : 
    2139                 : /* {{{ php_stream_scandir
    2140                 :  */
    2141                 : PHPAPI int _php_stream_scandir(char *dirname, char **namelist[], int flags, php_stream_context *context,
    2142                 :                           int (*compare) (const char **a, const char **b) TSRMLS_DC)
    2143              76 : {
    2144                 :         php_stream *stream;
    2145                 :         php_stream_dirent sdp;
    2146              76 :         char **vector = NULL;
    2147              76 :         int vector_size = 0;
    2148              76 :         int nfiles = 0;
    2149                 : 
    2150              76 :         if (!namelist) {
    2151               0 :                 return FAILURE;
    2152                 :         }
    2153                 : 
    2154              76 :         stream = php_stream_opendir(dirname, ENFORCE_SAFE_MODE | REPORT_ERRORS, context);
    2155              76 :         if (!stream) {
    2156              31 :                 return FAILURE;
    2157                 :         }
    2158                 : 
    2159             229 :         while (php_stream_readdir(stream, &sdp)) {
    2160             139 :                 if (nfiles == vector_size) {
    2161              46 :                         if (vector_size == 0) {
    2162              45 :                                 vector_size = 10;
    2163                 :                         } else {
    2164               1 :                                 vector_size *= 2;
    2165                 :                         }
    2166              46 :                         vector = (char **) erealloc(vector, vector_size * sizeof(char *));
    2167                 :                 }
    2168                 : 
    2169             139 :                 vector[nfiles] = estrdup(sdp.d_name);
    2170                 : 
    2171             139 :                 nfiles++;
    2172                 :         }
    2173              45 :         php_stream_closedir(stream);
    2174                 : 
    2175              45 :         *namelist = vector;
    2176                 : 
    2177              45 :         if (compare) {
    2178              45 :                 qsort(*namelist, nfiles, sizeof(char *), (int(*)(const void *, const void *))compare);
    2179                 :         }
    2180              45 :         return nfiles;
    2181                 : }
    2182                 : /* }}} */
    2183                 : 
    2184                 : /*
    2185                 :  * Local variables:
    2186                 :  * tab-width: 4
    2187                 :  * c-basic-offset: 4
    2188                 :  * End:
    2189                 :  * vim600: noet sw=4 ts=4 fdm=marker
    2190                 :  * vim<600: noet sw=4 ts=4
    2191                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:17 +0000 (3 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.