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

LCOV - code coverage report
Current view: top level - main/streams - memory.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 269 342 78.7 %
Date: 2022-01-23 Functions: 20 23 87.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2018 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             :    | Author: Marcus Boerger <helly@php.net>                               |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : #define _GNU_SOURCE
      22             : #include "php.h"
      23             : #include "ext/standard/base64.h"
      24             : 
      25             : PHPAPI size_t php_url_decode(char *str, size_t len);
      26             : 
      27             : /* Memory streams use a dynamic memory buffer to emulate a stream.
      28             :  * You can use php_stream_memory_open to create a readonly stream
      29             :  * from an existing memory buffer.
      30             :  */
      31             : 
      32             : /* Temp streams are streams that uses memory streams as long their
      33             :  * size is less than a given memory amount. When a write operation
      34             :  * exceeds that limit the content is written to a temporary file.
      35             :  */
      36             : 
      37             : /* {{{ ------- MEMORY stream implementation -------*/
      38             : 
      39             : typedef struct {
      40             :         char        *data;
      41             :         size_t      fpos;
      42             :         size_t      fsize;
      43             :         size_t      smax;
      44             :         int                     mode;
      45             : } php_stream_memory_data;
      46             : 
      47             : 
      48             : /* {{{ */
      49        3407 : static size_t php_stream_memory_write(php_stream *stream, const char *buf, size_t count)
      50             : {
      51        3407 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
      52             :         assert(ms != NULL);
      53             : 
      54        3407 :         if (ms->mode & TEMP_STREAM_READONLY) {
      55           2 :                 return 0;
      56             :         }
      57        3405 :         if (ms->fpos + count > ms->fsize) {
      58             :                 char *tmp;
      59             : 
      60        3366 :                 if (!ms->data) {
      61         160 :                         tmp = emalloc(ms->fpos + count);
      62             :                 } else {
      63        3206 :                         tmp = erealloc(ms->data, ms->fpos + count);
      64             :                 }
      65        3366 :                 if (!tmp) {
      66           0 :                         count = ms->fsize - ms->fpos + 1;
      67             :                 } else {
      68        3366 :                         ms->data = tmp;
      69        3366 :                         ms->fsize = ms->fpos + count;
      70             :                 }
      71             :         }
      72        3405 :         if (!ms->data)
      73           0 :                 count = 0;
      74        3405 :         if (count) {
      75             :                 assert(buf!= NULL);
      76        3405 :                 memcpy(ms->data+ms->fpos, (char*)buf, count);
      77        3405 :                 ms->fpos += count;
      78             :         }
      79        3405 :         return count;
      80             : }
      81             : /* }}} */
      82             : 
      83             : 
      84             : /* {{{ */
      85         834 : static size_t php_stream_memory_read(php_stream *stream, char *buf, size_t count)
      86             : {
      87         834 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
      88             :         assert(ms != NULL);
      89             : 
      90         834 :         if (ms->fpos == ms->fsize) {
      91         125 :                 stream->eof = 1;
      92         125 :                 count = 0;
      93             :         } else {
      94         709 :                 if (ms->fpos + count >= ms->fsize) {
      95         187 :                         count = ms->fsize - ms->fpos;
      96             :                 }
      97         709 :                 if (count) {
      98             :                         assert(ms->data!= NULL);
      99             :                         assert(buf!= NULL);
     100         709 :                         memcpy(buf, ms->data+ms->fpos, count);
     101         709 :                         ms->fpos += count;
     102             :                 }
     103             :         }
     104         834 :         return count;
     105             : }
     106             : /* }}} */
     107             : 
     108             : 
     109             : /* {{{ */
     110         246 : static int php_stream_memory_close(php_stream *stream, int close_handle)
     111             : {
     112         246 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
     113             :         assert(ms != NULL);
     114             : 
     115         246 :         if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) {
     116         161 :                 efree(ms->data);
     117             :         }
     118         246 :         efree(ms);
     119         246 :         return 0;
     120             : }
     121             : /* }}} */
     122             : 
     123             : 
     124             : /* {{{ */
     125         178 : static int php_stream_memory_flush(php_stream *stream)
     126             : {
     127             :         /* nothing to do here */
     128         178 :         return 0;
     129             : }
     130             : /* }}} */
     131             : 
     132             : 
     133             : /* {{{ */
     134         321 : static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
     135             : {
     136         321 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
     137             :         assert(ms != NULL);
     138             : 
     139         321 :         switch(whence) {
     140           8 :                 case SEEK_CUR:
     141           8 :                         if (offset < 0) {
     142           0 :                                 if (ms->fpos < (size_t)(-offset)) {
     143           0 :                                         ms->fpos = 0;
     144           0 :                                         *newoffs = -1;
     145           0 :                                         return -1;
     146             :                                 } else {
     147           0 :                                         ms->fpos = ms->fpos + offset;
     148           0 :                                         *newoffs = ms->fpos;
     149           0 :                                         stream->eof = 0;
     150           0 :                                         return 0;
     151             :                                 }
     152             :                         } else {
     153           8 :                                 if (ms->fpos + (size_t)(offset) > ms->fsize) {
     154           0 :                                         ms->fpos = ms->fsize;
     155           0 :                                         *newoffs = -1;
     156           0 :                                         return -1;
     157             :                                 } else {
     158           8 :                                         ms->fpos = ms->fpos + offset;
     159           8 :                                         *newoffs = ms->fpos;
     160           8 :                                         stream->eof = 0;
     161           8 :                                         return 0;
     162             :                                 }
     163             :                         }
     164         303 :                 case SEEK_SET:
     165         303 :                         if (ms->fsize < (size_t)(offset)) {
     166           2 :                                 ms->fpos = ms->fsize;
     167           2 :                                 *newoffs = -1;
     168           2 :                                 return -1;
     169             :                         } else {
     170         301 :                                 ms->fpos = offset;
     171         301 :                                 *newoffs = ms->fpos;
     172         301 :                                 stream->eof = 0;
     173         301 :                                 return 0;
     174             :                         }
     175          10 :                 case SEEK_END:
     176          10 :                         if (offset > 0) {
     177           1 :                                 ms->fpos = ms->fsize;
     178           1 :                                 *newoffs = -1;
     179           1 :                                 return -1;
     180           9 :                         } else if (ms->fsize < (size_t)(-offset)) {
     181           0 :                                 ms->fpos = 0;
     182           0 :                                 *newoffs = -1;
     183           0 :                                 return -1;
     184             :                         } else {
     185           9 :                                 ms->fpos = ms->fsize + offset;
     186           9 :                                 *newoffs = ms->fpos;
     187           9 :                                 stream->eof = 0;
     188           9 :                                 return 0;
     189             :                         }
     190           0 :                 default:
     191           0 :                         *newoffs = ms->fpos;
     192           0 :                         return -1;
     193             :         }
     194             : }
     195             : /* }}} */
     196             : 
     197             : /* {{{ */
     198           0 : static int php_stream_memory_cast(php_stream *stream, int castas, void **ret)
     199             : {
     200           0 :         return FAILURE;
     201             : }
     202             : /* }}} */
     203             : 
     204         116 : static int php_stream_memory_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */
     205             : {
     206         116 :         time_t timestamp = 0;
     207         116 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
     208             :         assert(ms != NULL);
     209             : 
     210         116 :         memset(ssb, 0, sizeof(php_stream_statbuf));
     211             :         /* read-only across the board */
     212             : 
     213         116 :         ssb->sb.st_mode = ms->mode & TEMP_STREAM_READONLY ? 0444 : 0666;
     214             : 
     215         116 :         ssb->sb.st_size = ms->fsize;
     216         116 :         ssb->sb.st_mode |= S_IFREG; /* regular file */
     217             : 
     218             : #ifdef NETWARE
     219             :         ssb->sb.st_mtime.tv_sec = timestamp;
     220             :         ssb->sb.st_atime.tv_sec = timestamp;
     221             :         ssb->sb.st_ctime.tv_sec = timestamp;
     222             : #else
     223         116 :         ssb->sb.st_mtime = timestamp;
     224         116 :         ssb->sb.st_atime = timestamp;
     225         116 :         ssb->sb.st_ctime = timestamp;
     226             : #endif
     227             : 
     228         116 :         ssb->sb.st_nlink = 1;
     229         116 :         ssb->sb.st_rdev = -1;
     230             :         /* this is only for APC, so use /dev/null device - no chance of conflict there! */
     231         116 :         ssb->sb.st_dev = 0xC;
     232             :         /* generate unique inode number for alias/filename, so no phars will conflict */
     233         116 :         ssb->sb.st_ino = 0;
     234             : 
     235             : #ifndef PHP_WIN32
     236         116 :         ssb->sb.st_blksize = -1;
     237             : #endif
     238             : 
     239             : #if !defined(PHP_WIN32) && !defined(__BEOS__)
     240         116 :         ssb->sb.st_blocks = -1;
     241             : #endif
     242             : 
     243         116 :         return 0;
     244             : }
     245             : /* }}} */
     246             : 
     247          72 : static int php_stream_memory_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */
     248             : {
     249          72 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
     250             :         size_t newsize;
     251             : 
     252          72 :         switch(option) {
     253           1 :                 case PHP_STREAM_OPTION_TRUNCATE_API:
     254           1 :                         switch (value) {
     255           0 :                                 case PHP_STREAM_TRUNCATE_SUPPORTED:
     256           0 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     257             : 
     258           1 :                                 case PHP_STREAM_TRUNCATE_SET_SIZE:
     259           1 :                                         if (ms->mode & TEMP_STREAM_READONLY) {
     260           0 :                                                 return PHP_STREAM_OPTION_RETURN_ERR;
     261             :                                         }
     262           1 :                                         newsize = *(size_t*)ptrparam;
     263           1 :                                         if (newsize <= ms->fsize) {
     264           1 :                                                 if (newsize < ms->fpos) {
     265           1 :                                                         ms->fpos = newsize;
     266             :                                                 }
     267             :                                         } else {
     268           0 :                                                 ms->data = erealloc(ms->data, newsize);
     269           0 :                                                 memset(ms->data+ms->fsize, 0, newsize - ms->fsize);
     270           0 :                                                 ms->fsize = newsize;
     271             :                                         }
     272           1 :                                         ms->fsize = newsize;
     273           1 :                                         return PHP_STREAM_OPTION_RETURN_OK;
     274             :                         }
     275             :                 default:
     276          71 :                         return PHP_STREAM_OPTION_RETURN_NOTIMPL;
     277             :         }
     278             : }
     279             : /* }}} */
     280             : 
     281             : PHPAPI php_stream_ops   php_stream_memory_ops = {
     282             :         php_stream_memory_write, php_stream_memory_read,
     283             :         php_stream_memory_close, php_stream_memory_flush,
     284             :         "MEMORY",
     285             :         php_stream_memory_seek,
     286             :         php_stream_memory_cast,
     287             :         php_stream_memory_stat,
     288             :         php_stream_memory_set_option
     289             : };
     290             : 
     291             : 
     292             : /* {{{ */
     293         246 : PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC)
     294             : {
     295             :         php_stream_memory_data *self;
     296             :         php_stream *stream;
     297             : 
     298         246 :         self = emalloc(sizeof(*self));
     299         246 :         self->data = NULL;
     300         246 :         self->fpos = 0;
     301         246 :         self->fsize = 0;
     302         246 :         self->smax = ~0u;
     303         246 :         self->mode = mode;
     304             : 
     305         246 :         stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
     306         246 :         stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
     307         246 :         return stream;
     308             : }
     309             : /* }}} */
     310             : 
     311             : 
     312             : /* {{{ */
     313           6 : PHPAPI php_stream *_php_stream_memory_open(int mode, char *buf, size_t length STREAMS_DC)
     314             : {
     315             :         php_stream *stream;
     316             :         php_stream_memory_data *ms;
     317             : 
     318           6 :         if ((stream = php_stream_memory_create_rel(mode)) != NULL) {
     319           6 :                 ms = (php_stream_memory_data*)stream->abstract;
     320             : 
     321           6 :                 if (mode == TEMP_STREAM_READONLY || mode == TEMP_STREAM_TAKE_BUFFER) {
     322             :                         /* use the buffer directly */
     323           6 :                         ms->data = buf;
     324           6 :                         ms->fsize = length;
     325             :                 } else {
     326           0 :                         if (length) {
     327             :                                 assert(buf != NULL);
     328           0 :                                 php_stream_write(stream, buf, length);
     329             :                         }
     330             :                 }
     331             :         }
     332           6 :         return stream;
     333             : }
     334             : /* }}} */
     335             : 
     336             : 
     337             : /* {{{ */
     338        2312 : PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC)
     339             : {
     340        2312 :         php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
     341             : 
     342             :         assert(ms != NULL);
     343             :         assert(length != 0);
     344             : 
     345        2312 :         *length = ms->fsize;
     346        2312 :         return ms->data;
     347             : }
     348             : /* }}} */
     349             : 
     350             : /* }}} */
     351             : 
     352             : /* {{{ ------- TEMP stream implementation -------*/
     353             : 
     354             : typedef struct {
     355             :         php_stream  *innerstream;
     356             :         size_t      smax;
     357             :         int                     mode;
     358             :         zval        meta;
     359             :         char*           tmpdir;
     360             : } php_stream_temp_data;
     361             : 
     362             : 
     363             : /* {{{ */
     364        5264 : static size_t php_stream_temp_write(php_stream *stream, const char *buf, size_t count)
     365             : {
     366        5264 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     367             :         assert(ts != NULL);
     368             : 
     369        5264 :         if (!ts->innerstream) {
     370           0 :                 return -1;
     371             :         }
     372        5264 :         if (php_stream_is(ts->innerstream, PHP_STREAM_IS_MEMORY)) {
     373             :                 size_t memsize;
     374        2312 :                 char *membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
     375             : 
     376        2312 :                 if (memsize + count >= ts->smax) {
     377           2 :                         php_stream *file = php_stream_fopen_temporary_file(ts->tmpdir, "php", NULL);
     378           2 :                         if (file == NULL) {
     379           1 :                                 php_error_docref(NULL, E_WARNING, "Unable to create temporary file, Check permissions in temporary files directory.");
     380           1 :                                 return 0;
     381             :                         }
     382           1 :                         php_stream_write(file, membuf, memsize);
     383           1 :                         php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
     384           1 :                         ts->innerstream = file;
     385           1 :                         php_stream_encloses(stream, ts->innerstream);
     386             :                 }
     387             :         }
     388        5263 :         return php_stream_write(ts->innerstream, buf, count);
     389             : }
     390             : /* }}} */
     391             : 
     392             : 
     393             : /* {{{ */
     394         260 : static size_t php_stream_temp_read(php_stream *stream, char *buf, size_t count)
     395             : {
     396         260 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     397             :         size_t got;
     398             : 
     399             :         assert(ts != NULL);
     400             : 
     401         260 :         if (!ts->innerstream) {
     402           0 :                 return -1;
     403             :         }
     404             : 
     405         260 :         got = php_stream_read(ts->innerstream, buf, count);
     406             : 
     407         260 :         stream->eof = ts->innerstream->eof;
     408             : 
     409         260 :         return got;
     410             : }
     411             : /* }}} */
     412             : 
     413             : 
     414             : /* {{{ */
     415         192 : static int php_stream_temp_close(php_stream *stream, int close_handle)
     416             : {
     417         192 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     418             :         int ret;
     419             : 
     420             :         assert(ts != NULL);
     421             : 
     422         192 :         if (ts->innerstream) {
     423         192 :                 ret = php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE));
     424             :         } else {
     425           0 :                 ret = 0;
     426             :         }
     427             : 
     428         192 :         zval_ptr_dtor(&ts->meta);
     429             : 
     430         192 :         if (ts->tmpdir) {
     431           0 :                 efree(ts->tmpdir);
     432             :         }
     433             : 
     434         192 :         efree(ts);
     435             : 
     436         192 :         return ret;
     437             : }
     438             : /* }}} */
     439             : 
     440             : 
     441             : /* {{{ */
     442          76 : static int php_stream_temp_flush(php_stream *stream)
     443             : {
     444          76 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     445             :         assert(ts != NULL);
     446             : 
     447          76 :         return ts->innerstream ? php_stream_flush(ts->innerstream) : -1;
     448             : }
     449             : /* }}} */
     450             : 
     451             : 
     452             : /* {{{ */
     453         255 : static int php_stream_temp_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
     454             : {
     455         255 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     456             :         int ret;
     457             : 
     458             :         assert(ts != NULL);
     459             : 
     460         255 :         if (!ts->innerstream) {
     461           0 :                 *newoffs = -1;
     462           0 :                 return -1;
     463             :         }
     464         255 :         ret = php_stream_seek(ts->innerstream, offset, whence);
     465         255 :         *newoffs = php_stream_tell(ts->innerstream);
     466         255 :         stream->eof = ts->innerstream->eof;
     467             : 
     468         255 :         return ret;
     469             : }
     470             : /* }}} */
     471             : 
     472             : /* {{{ */
     473           0 : static int php_stream_temp_cast(php_stream *stream, int castas, void **ret)
     474             : {
     475           0 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     476             :         php_stream *file;
     477             :         size_t memsize;
     478             :         char *membuf;
     479             :         zend_off_t pos;
     480             : 
     481             :         assert(ts != NULL);
     482             : 
     483           0 :         if (!ts->innerstream) {
     484           0 :                 return FAILURE;
     485             :         }
     486           0 :         if (php_stream_is(ts->innerstream, PHP_STREAM_IS_STDIO)) {
     487           0 :                 return php_stream_cast(ts->innerstream, castas, ret, 0);
     488             :         }
     489             : 
     490             :         /* we are still using a memory based backing. If they are if we can be
     491             :          * a FILE*, say yes because we can perform the conversion.
     492             :          * If they actually want to perform the conversion, we need to switch
     493             :          * the memory stream to a tmpfile stream */
     494             : 
     495           0 :         if (ret == NULL && castas == PHP_STREAM_AS_STDIO) {
     496           0 :                 return SUCCESS;
     497             :         }
     498             : 
     499             :         /* say "no" to other stream forms */
     500           0 :         if (ret == NULL) {
     501           0 :                 return FAILURE;
     502             :         }
     503             : 
     504           0 :         file = php_stream_fopen_tmpfile();
     505           0 :         if (file == NULL) {
     506           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create temporary file.");
     507           0 :                 return FAILURE;
     508             :         }
     509             : 
     510             :         /* perform the conversion and then pass the request on to the innerstream */
     511           0 :         membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
     512           0 :         php_stream_write(file, membuf, memsize);
     513           0 :         pos = php_stream_tell(ts->innerstream);
     514             : 
     515           0 :         php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
     516           0 :         ts->innerstream = file;
     517           0 :         php_stream_encloses(stream, ts->innerstream);
     518           0 :         php_stream_seek(ts->innerstream, pos, SEEK_SET);
     519             : 
     520           0 :         return php_stream_cast(ts->innerstream, castas, ret, 1);
     521             : }
     522             : /* }}} */
     523             : 
     524          86 : static int php_stream_temp_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */
     525             : {
     526          86 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     527             : 
     528          86 :         if (!ts || !ts->innerstream) {
     529           0 :                 return -1;
     530             :         }
     531          86 :         return php_stream_stat(ts->innerstream, ssb);
     532             : }
     533             : /* }}} */
     534             : 
     535          78 : static int php_stream_temp_set_option(php_stream *stream, int option, int value, void *ptrparam) /* {{{ */
     536             : {
     537          78 :         php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
     538             : 
     539          78 :         switch(option) {
     540           7 :                 case PHP_STREAM_OPTION_META_DATA_API:
     541          14 :                         if (Z_TYPE(ts->meta) != IS_UNDEF) {
     542           7 :                                 zend_hash_copy(Z_ARRVAL_P((zval*)ptrparam), Z_ARRVAL(ts->meta), zval_add_ref);
     543             :                         }
     544           7 :                         return PHP_STREAM_OPTION_RETURN_OK;
     545          71 :                 default:
     546          71 :                         if (ts->innerstream) {
     547          71 :                                 return php_stream_set_option(ts->innerstream, option, value, ptrparam);
     548             :                         }
     549           0 :                         return PHP_STREAM_OPTION_RETURN_NOTIMPL;
     550             :         }
     551             : }
     552             : /* }}} */
     553             : 
     554             : PHPAPI php_stream_ops   php_stream_temp_ops = {
     555             :         php_stream_temp_write, php_stream_temp_read,
     556             :         php_stream_temp_close, php_stream_temp_flush,
     557             :         "TEMP",
     558             :         php_stream_temp_seek,
     559             :         php_stream_temp_cast,
     560             :         php_stream_temp_stat,
     561             :         php_stream_temp_set_option
     562             : };
     563             : 
     564             : /* }}} */
     565             : 
     566             : /* {{{ _php_stream_temp_create_ex */
     567         192 : PHPAPI php_stream *_php_stream_temp_create_ex(int mode, size_t max_memory_usage, const char *tmpdir STREAMS_DC)
     568             : {
     569             :         php_stream_temp_data *self;
     570             :         php_stream *stream;
     571             : 
     572         192 :         self = ecalloc(1, sizeof(*self));
     573         192 :         self->smax = max_memory_usage;
     574         192 :         self->mode = mode;
     575         192 :         ZVAL_UNDEF(&self->meta);
     576         192 :         if (tmpdir) {
     577           0 :                 self->tmpdir = estrdup(tmpdir);
     578             :         }
     579         192 :         stream = php_stream_alloc_rel(&php_stream_temp_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
     580         192 :         stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
     581         192 :         self->innerstream = php_stream_memory_create_rel(mode);
     582         192 :         php_stream_encloses(stream, self->innerstream);
     583             : 
     584         192 :         return stream;
     585             : }
     586             : /* }}} */
     587             : 
     588             : /* {{{ _php_stream_temp_create */
     589         148 : PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC)
     590             : {
     591         148 :         return php_stream_temp_create_ex(mode, max_memory_usage, NULL);
     592             : }
     593             : /* }}} */
     594             : 
     595             : /* {{{ _php_stream_temp_open */
     596           0 : PHPAPI php_stream *_php_stream_temp_open(int mode, size_t max_memory_usage, char *buf, size_t length STREAMS_DC)
     597             : {
     598             :         php_stream *stream;
     599             :         php_stream_temp_data *ts;
     600             :         zend_off_t newoffs;
     601             : 
     602           0 :         if ((stream = php_stream_temp_create_rel(mode, max_memory_usage)) != NULL) {
     603           0 :                 if (length) {
     604             :                         assert(buf != NULL);
     605           0 :                         php_stream_temp_write(stream, buf, length);
     606           0 :                         php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs);
     607             :                 }
     608           0 :                 ts = (php_stream_temp_data*)stream->abstract;
     609             :                 assert(ts != NULL);
     610           0 :                 ts->mode = mode;
     611             :         }
     612           0 :         return stream;
     613             : }
     614             : /* }}} */
     615             : 
     616             : PHPAPI php_stream_ops php_stream_rfc2397_ops = {
     617             :         php_stream_temp_write, php_stream_temp_read,
     618             :         php_stream_temp_close, php_stream_temp_flush,
     619             :         "RFC2397",
     620             :         php_stream_temp_seek,
     621             :         php_stream_temp_cast,
     622             :         php_stream_temp_stat,
     623             :         php_stream_temp_set_option
     624             : };
     625             : 
     626          71 : static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, const char *path,
     627             :                                                                                                 const char *mode, int options, zend_string **opened_path,
     628             :                                                                                                 php_stream_context *context STREAMS_DC) /* {{{ */
     629             : {
     630             :         php_stream *stream;
     631             :         php_stream_temp_data *ts;
     632             :         char *comma, *semi, *sep, *key;
     633             :         size_t mlen, dlen, plen, vlen;
     634             :         zend_off_t newoffs;
     635             :         zval meta;
     636          71 :         int base64 = 0, ilen;
     637          71 :         zend_string *base64_comma = NULL;
     638             : 
     639          71 :         ZVAL_NULL(&meta);
     640          71 :         if (memcmp(path, "data:", 5)) {
     641           0 :                 return NULL;
     642             :         }
     643             : 
     644          71 :         path += 5;
     645          71 :         dlen = strlen(path);
     646             : 
     647          71 :         if (dlen >= 2 && path[0] == '/' && path[1] == '/') {
     648          49 :                 dlen -= 2;
     649          49 :                 path += 2;
     650             :         }
     651             : 
     652          71 :         if ((comma = memchr(path, ',', dlen)) == NULL) {
     653           3 :                 php_stream_wrapper_log_error(wrapper, options, "rfc2397: no comma in URL");
     654           3 :                 return NULL;
     655             :         }
     656             : 
     657          68 :         if (comma != path) {
     658             :                 /* meta info */
     659          54 :                 mlen = comma - path;
     660          54 :                 dlen -= mlen;
     661          54 :                 semi = memchr(path, ';', mlen);
     662          54 :                 sep = memchr(path, '/', mlen);
     663             : 
     664          54 :                 if (!semi && !sep) {
     665           2 :                         php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal media type");
     666           2 :                         return NULL;
     667             :                 }
     668             : 
     669          52 :                 array_init(&meta);
     670          52 :                 if (!semi) { /* there is only a mime type */
     671          26 :                         add_assoc_stringl(&meta, "mediatype", (char *) path, mlen);
     672          26 :                         mlen = 0;
     673          26 :                 } else if (sep && sep < semi) { /* there is a mime type */
     674          19 :                         plen = semi - path;
     675          19 :                         add_assoc_stringl(&meta, "mediatype", (char *) path, plen);
     676          19 :                         mlen -= plen;
     677          19 :                         path += plen;
     678           7 :                 } else if (semi != path || mlen != sizeof(";base64")-1 || memcmp(path, ";base64", sizeof(";base64")-1)) { /* must be error since parameters are only allowed after mediatype */
     679           2 :                         zval_ptr_dtor(&meta);
     680           2 :                         php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal media type");
     681           2 :                         return NULL;
     682             :                 }
     683             :                 /* get parameters and potentially ';base64' */
     684         113 :                 while(semi && (semi == path)) {
     685          30 :                         path++;
     686          30 :                         mlen--;
     687          30 :                         sep = memchr(path, '=', mlen);
     688          30 :                         semi = memchr(path, ';', mlen);
     689          30 :                         if (!sep || (semi && semi < sep)) { /* must be ';base64' or failure */
     690          17 :                                 if (mlen != sizeof("base64")-1 || memcmp(path, "base64", sizeof("base64")-1)) {
     691             :                                         /* must be error since parameters are only allowed after mediatype and we have no '=' sign */
     692           2 :                                         zval_ptr_dtor(&meta);
     693           2 :                                         php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal parameter");
     694           2 :                                         return NULL;
     695             :                                 }
     696          15 :                                 base64 = 1;
     697          15 :                                 mlen -= sizeof("base64") - 1;
     698          15 :                                 path += sizeof("base64") - 1;
     699          15 :                                 break;
     700             :                         }
     701             :                         /* found parameter ... the heart of cs ppl lies in +1/-1 or was it +2 this time? */
     702          13 :                         plen = sep - path;
     703          13 :                         vlen = (semi ? (size_t)(semi - sep) : (mlen - plen)) - 1 /* '=' */;
     704          13 :                         key = estrndup(path, plen);
     705          13 :                         if (plen != sizeof("mediatype")-1 || memcmp(key, "mediatype", sizeof("mediatype")-1)) {
     706          12 :                                 add_assoc_stringl_ex(&meta, key, plen, sep + 1, vlen);
     707             :                         }
     708          13 :                         efree(key);
     709          13 :                         plen += vlen + 1;
     710          13 :                         mlen -= plen;
     711          13 :                         path += plen;
     712             :                 }
     713          48 :                 if (mlen) {
     714           0 :                         zval_ptr_dtor(&meta);
     715           0 :                         php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal URL");
     716           0 :                         return NULL;
     717             :                 }
     718             :         } else {
     719          14 :                 array_init(&meta);
     720             :         }
     721          62 :         add_assoc_bool(&meta, "base64", base64);
     722             : 
     723             :         /* skip ',' */
     724          62 :         comma++;
     725          62 :         dlen--;
     726             : 
     727          62 :         if (base64) {
     728          15 :                 base64_comma = php_base64_decode_ex((const unsigned char *)comma, dlen, 1);
     729          15 :                 if (!base64_comma) {
     730           2 :                         zval_ptr_dtor(&meta);
     731           2 :                         php_stream_wrapper_log_error(wrapper, options, "rfc2397: unable to decode");
     732           2 :                         return NULL;
     733             :                 }
     734          13 :                 comma = ZSTR_VAL(base64_comma);
     735          13 :                 ilen = (int)ZSTR_LEN(base64_comma);
     736             :         } else {
     737          47 :                 comma = estrndup(comma, dlen);
     738          47 :                 dlen = php_url_decode(comma, dlen);
     739          47 :                 ilen = (int)dlen;
     740             :         }
     741             : 
     742          60 :         if ((stream = php_stream_temp_create_rel(0, ~0u)) != NULL) {
     743             :                 /* store data */
     744          60 :                 php_stream_temp_write(stream, comma, ilen);
     745          60 :                 php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs);
     746             :                 /* set special stream stuff (enforce exact mode) */
     747          60 :                 vlen = strlen(mode);
     748          60 :                 if (vlen >= sizeof(stream->mode)) {
     749           0 :                         vlen = sizeof(stream->mode) - 1;
     750             :                 }
     751          60 :                 memcpy(stream->mode, mode, vlen);
     752          60 :                 stream->mode[vlen] = '\0';
     753          60 :                 stream->ops = &php_stream_rfc2397_ops;
     754          60 :                 ts = (php_stream_temp_data*)stream->abstract;
     755             :                 assert(ts != NULL);
     756          60 :                 ts->mode = mode && mode[0] == 'r' && mode[1] != '+' ? TEMP_STREAM_READONLY : 0;
     757          60 :                 ZVAL_COPY_VALUE(&ts->meta, &meta);
     758             :         }
     759          60 :         if (base64_comma) {
     760             :                 zend_string_free(base64_comma);
     761             :         } else {
     762          47 :                 efree(comma);
     763             :         }
     764             : 
     765          60 :         return stream;
     766             : }
     767             : 
     768             : PHPAPI php_stream_wrapper_ops php_stream_rfc2397_wops = {
     769             :         php_stream_url_wrap_rfc2397,
     770             :         NULL, /* close */
     771             :         NULL, /* fstat */
     772             :         NULL, /* stat */
     773             :         NULL, /* opendir */
     774             :         "RFC2397",
     775             :         NULL, /* unlink */
     776             :         NULL, /* rename */
     777             :         NULL, /* mkdir */
     778             :         NULL, /* rmdir */
     779             :         NULL, /* stream_metadata */
     780             : };
     781             : 
     782             : PHPAPI php_stream_wrapper php_stream_rfc2397_wrapper =  {
     783             :         &php_stream_rfc2397_wops,
     784             :         NULL,
     785             :         1, /* is_url */
     786             : };
     787             : 
     788             : /*
     789             :  * Local variables:
     790             :  * tab-width: 4
     791             :  * c-basic-offset: 4
     792             :  * End:
     793             :  * vim600: noet sw=4 ts=4 fdm=marker
     794             :  * vim<600: noet sw=4 ts=4
     795             :  */

Generated by: LCOV version 1.10

Generated at Mon, 24 Jan 2022 01:16:37 +0000 (5 days ago)

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