2003-02-16 22:19:28 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-09-19 16:33:14 +00:00
| PHP Version 7 |
2003-02-16 22:19:28 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-01-03 03:08:10 +00:00
| Copyright ( c ) 1997 - 2014 The PHP Group |
2003-02-16 22:19:28 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 12:51:34 +00:00
| This source file is subject to version 3.01 of the PHP license , |
2003-02-16 22:19:28 +00:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-10 20:04:29 +00:00
| available through the world - wide - web at the following url : |
2006-01-01 12:51:34 +00:00
| http : //www.php.net/license/3_01.txt |
2003-02-16 22:19:28 +00:00
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2003-02-19 08:40:19 +00:00
| Authors : Wez Furlong < wez @ thebrainroom . com > |
2003-02-16 22:19:28 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
/* $Id$ */
# define _GNU_SOURCE
# include "php.h"
# include "php_globals.h"
# include "php_network.h"
# include "php_open_temporary_file.h"
# include "ext/standard/file.h"
# include <stddef.h>
# include <fcntl.h>
# include "php_streams_int.h"
/* Under BSD, emulate fopencookie using funopen */
2010-01-19 13:44:08 +00:00
# if defined(HAVE_FUNOPEN) && !defined(HAVE_FOPENCOOKIE)
2013-06-14 14:51:54 +00:00
/* NetBSD 6.0+ uses off_t instead of fpos_t in funopen */
2013-07-08 17:25:03 +00:00
# if defined(__NetBSD__) && (__NetBSD_Version__ >= 600000000)
2013-06-14 14:51:54 +00:00
# define PHP_FPOS_T off_t
# else
# define PHP_FPOS_T fpos_t
# endif
2003-02-16 22:19:28 +00:00
typedef struct {
int ( * reader ) ( void * , char * , int ) ;
int ( * writer ) ( void * , const char * , int ) ;
2013-06-14 14:51:54 +00:00
PHP_FPOS_T ( * seeker ) ( void * , PHP_FPOS_T , int ) ;
2003-02-16 22:19:28 +00:00
int ( * closer ) ( void * ) ;
} COOKIE_IO_FUNCTIONS_T ;
FILE * fopencookie ( void * cookie , const char * mode , COOKIE_IO_FUNCTIONS_T * funcs )
{
return funopen ( cookie , funcs - > reader , funcs - > writer , funcs - > seeker , funcs - > closer ) ;
}
# define HAVE_FOPENCOOKIE 1
2010-01-19 13:44:08 +00:00
# define PHP_EMULATE_FOPENCOOKIE 1
2003-02-16 22:19:28 +00:00
# define PHP_STREAM_COOKIE_FUNCTIONS &stream_cookie_functions
2010-01-19 13:44:08 +00:00
# elif defined(HAVE_FOPENCOOKIE)
2003-02-16 22:19:28 +00:00
# define PHP_STREAM_COOKIE_FUNCTIONS stream_cookie_functions
# endif
/* {{{ STDIO with fopencookie */
2010-01-19 13:44:08 +00:00
# if defined(PHP_EMULATE_FOPENCOOKIE)
2003-02-16 22:19:28 +00:00
/* use our fopencookie emulation */
static int stream_cookie_reader ( void * cookie , char * buffer , int size )
{
int ret ;
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
ret = php_stream_read ( ( php_stream * ) cookie , buffer , size ) ;
return ret ;
}
static int stream_cookie_writer ( void * cookie , const char * buffer , int size )
{
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2003-02-16 22:19:28 +00:00
return php_stream_write ( ( php_stream * ) cookie , ( char * ) buffer , size ) ;
}
2014-08-16 09:16:11 +00:00
static PHP_FPOS_T stream_cookie_seeker ( void * cookie , zend_off_t position , int whence )
2003-02-16 22:19:28 +00:00
{
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2013-06-14 14:51:54 +00:00
return ( PHP_FPOS_T ) php_stream_seek ( ( php_stream * ) cookie , position , whence ) ;
2003-02-16 22:19:28 +00:00
}
static int stream_cookie_closer ( void * cookie )
{
php_stream * stream = ( php_stream * ) cookie ;
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2003-02-16 22:19:28 +00:00
/* prevent recursion */
stream - > fclose_stdiocast = PHP_STREAM_FCLOSE_NONE ;
return php_stream_close ( stream ) ;
}
2010-01-19 13:44:08 +00:00
# elif defined(HAVE_FOPENCOOKIE)
2003-02-16 22:19:28 +00:00
static ssize_t stream_cookie_reader ( void * cookie , char * buffer , size_t size )
{
ssize_t ret ;
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
ret = php_stream_read ( ( ( php_stream * ) cookie ) , buffer , size ) ;
return ret ;
}
static ssize_t stream_cookie_writer ( void * cookie , const char * buffer , size_t size )
{
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2003-02-16 22:19:28 +00:00
return php_stream_write ( ( ( php_stream * ) cookie ) , ( char * ) buffer , size ) ;
}
2010-01-19 13:44:08 +00:00
# ifdef COOKIE_SEEKER_USES_OFF64_T
2003-02-16 22:19:28 +00:00
static int stream_cookie_seeker ( void * cookie , __off64_t * position , int whence )
{
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2014-08-16 09:16:11 +00:00
* position = php_stream_seek ( ( php_stream * ) cookie , ( zend_off_t ) * position , whence ) ;
2003-02-16 22:19:28 +00:00
2010-01-19 12:03:07 +00:00
if ( * position = = - 1 ) {
2003-02-16 22:19:28 +00:00
return - 1 ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
return 0 ;
}
2010-01-19 13:44:08 +00:00
# else
2014-08-16 09:16:11 +00:00
static int stream_cookie_seeker ( void * cookie , zend_off_t position , int whence )
2003-02-16 22:19:28 +00:00
{
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2003-02-16 22:19:28 +00:00
return php_stream_seek ( ( php_stream * ) cookie , position , whence ) ;
}
2010-01-19 13:44:08 +00:00
# endif
2003-02-16 22:19:28 +00:00
static int stream_cookie_closer ( void * cookie )
{
php_stream * stream = ( php_stream * ) cookie ;
2014-10-15 07:37:55 +00:00
TSRMLS_FETCH ( ) ;
2003-02-16 22:19:28 +00:00
/* prevent recursion */
stream - > fclose_stdiocast = PHP_STREAM_FCLOSE_NONE ;
return php_stream_close ( stream ) ;
}
2010-01-19 13:44:08 +00:00
# endif /* elif defined(HAVE_FOPENCOOKIE) */
2003-02-16 22:19:28 +00:00
# if HAVE_FOPENCOOKIE
static COOKIE_IO_FUNCTIONS_T stream_cookie_functions =
{
stream_cookie_reader , stream_cookie_writer ,
stream_cookie_seeker , stream_cookie_closer
} ;
# else
/* TODO: use socketpair() to emulate fopencookie, as suggested by Hartmut ? */
# endif
/* }}} */
2010-11-05 18:53:48 +00:00
/* {{{ php_stream_mode_sanitize_fdopen_fopencookie
2010-11-05 01:29:08 +00:00
* Result should have at least size 5 , e . g . to write wbx + \ 0 */
2010-11-05 18:53:48 +00:00
void php_stream_mode_sanitize_fdopen_fopencookie ( php_stream * stream , char * result )
2010-11-05 01:29:08 +00:00
{
/* replace modes not supported by fdopen and fopencookie, but supported
* by PHP ' s fread ( ) , so that their calls won ' t fail */
const char * cur_mode = stream - > mode ;
int has_plus = 0 ,
has_bin = 0 ,
i ,
res_curs = 0 ;
if ( cur_mode [ 0 ] = = ' r ' | | cur_mode [ 0 ] = = ' w ' | | cur_mode [ 0 ] = = ' a ' ) {
result [ res_curs + + ] = cur_mode [ 0 ] ;
} else {
/* assume cur_mode[0] is 'c' or 'x'; substitute by 'w', which should not
* truncate anything in fdopen / fopencookie */
result [ res_curs + + ] = ' w ' ;
/* x is allowed (at least by glibc & compat), but not as the 1st mode
* as in PHP and in any case is ( at best ) ignored by fdopen and fopencookie */
}
/* assume current mode has at most length 4 (e.g. wbn+) */
for ( i = 1 ; i < 4 & & cur_mode [ i ] ! = ' \0 ' ; i + + ) {
if ( cur_mode [ i ] = = ' b ' ) {
has_bin = 1 ;
} else if ( cur_mode [ i ] = = ' + ' ) {
has_plus = 1 ;
}
/* ignore 'n', 't' or other stuff */
}
if ( has_bin ) {
result [ res_curs + + ] = ' b ' ;
}
if ( has_plus ) {
result [ res_curs + + ] = ' + ' ;
}
result [ res_curs ] = ' \0 ' ;
}
/* }}} */
2003-02-16 22:19:28 +00:00
/* {{{ php_stream_cast */
PHPAPI int _php_stream_cast ( php_stream * stream , int castas , void * * ret , int show_err TSRMLS_DC )
{
int flags = castas & PHP_STREAM_CAST_MASK ;
castas & = ~ PHP_STREAM_CAST_MASK ;
/* synchronize our buffer (if possible) */
2003-06-28 11:24:47 +00:00
if ( ret & & castas ! = PHP_STREAM_AS_FD_FOR_SELECT ) {
2003-02-16 22:19:28 +00:00
php_stream_flush ( stream ) ;
if ( stream - > ops - > seek & & ( stream - > flags & PHP_STREAM_FLAG_NO_SEEK ) = = 0 ) {
2014-08-16 09:16:11 +00:00
zend_off_t dummy ;
2003-02-16 22:19:28 +00:00
stream - > ops - > seek ( stream , stream - > position , SEEK_SET , & dummy TSRMLS_CC ) ;
stream - > readpos = stream - > writepos = 0 ;
}
}
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
/* filtered streams can only be cast as stdio, and only when fopencookie is present */
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
if ( castas = = PHP_STREAM_AS_STDIO ) {
if ( stream - > stdiocast ) {
if ( ret ) {
2003-03-15 13:29:56 +00:00
* ( FILE * * ) ret = stream - > stdiocast ;
2003-02-16 22:19:28 +00:00
}
goto exit_success ;
}
/* if the stream is a stdio stream let's give it a chance to respond
* first , to avoid doubling up the layers of stdio with an fopencookie */
if ( php_stream_is ( stream , PHP_STREAM_IS_STDIO ) & &
2010-01-19 12:03:07 +00:00
stream - > ops - > cast & &
! php_stream_is_filtered ( stream ) & &
stream - > ops - > cast ( stream , castas , ret TSRMLS_CC ) = = SUCCESS
) {
2003-02-16 22:19:28 +00:00
goto exit_success ;
}
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
# if HAVE_FOPENCOOKIE
/* if just checking, say yes we can be a FILE*, but don't actually create it yet */
2010-01-19 12:03:07 +00:00
if ( ret = = NULL ) {
2003-02-16 22:19:28 +00:00
goto exit_success ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
2010-11-05 01:29:08 +00:00
{
char fixed_mode [ 5 ] ;
2010-11-05 18:53:48 +00:00
php_stream_mode_sanitize_fdopen_fopencookie ( stream , fixed_mode ) ;
2010-11-05 01:29:08 +00:00
* ( FILE * * ) ret = fopencookie ( stream , fixed_mode , PHP_STREAM_COOKIE_FUNCTIONS ) ;
}
2003-02-16 22:19:28 +00:00
if ( * ret ! = NULL ) {
2014-08-16 09:16:11 +00:00
zend_off_t pos ;
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
stream - > fclose_stdiocast = PHP_STREAM_FCLOSE_FOPENCOOKIE ;
/* If the stream position is not at the start, we need to force
* the stdio layer to believe it ' s real location . */
pos = php_stream_tell ( stream ) ;
2010-01-19 12:03:07 +00:00
if ( pos > 0 ) {
2014-08-16 09:16:11 +00:00
zend_fseek ( * ret , pos , SEEK_SET ) ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
goto exit_success ;
}
/* must be either:
a ) programmer error
b ) no memory
- > lets bail
*/
php_error_docref ( NULL TSRMLS_CC , E_ERROR , " fopencookie failed " ) ;
return FAILURE ;
# endif
2003-02-24 21:40:23 +00:00
if ( ! php_stream_is_filtered ( stream ) & & stream - > ops - > cast & & stream - > ops - > cast ( stream , castas , NULL TSRMLS_CC ) = = SUCCESS ) {
if ( FAILURE = = stream - > ops - > cast ( stream , castas , ret TSRMLS_CC ) ) {
return FAILURE ;
}
goto exit_success ;
} else if ( flags & PHP_STREAM_CAST_TRY_HARD ) {
2003-02-16 22:19:28 +00:00
php_stream * newstream ;
newstream = php_stream_fopen_tmpfile ( ) ;
if ( newstream ) {
2011-09-04 22:36:33 +00:00
int retcopy = php_stream_copy_to_stream_ex ( stream , newstream , PHP_STREAM_COPY_ALL , NULL ) ;
2003-02-16 22:19:28 +00:00
2011-09-04 22:36:33 +00:00
if ( retcopy ! = SUCCESS ) {
2003-02-16 22:19:28 +00:00
php_stream_close ( newstream ) ;
} else {
2011-09-04 22:36:33 +00:00
int retcast = php_stream_cast ( newstream , castas | flags , ( void * * ) ret , show_err ) ;
2003-02-16 22:19:28 +00:00
2011-09-04 22:36:33 +00:00
if ( retcast = = SUCCESS ) {
rewind ( * ( FILE * * ) ret ) ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
/* do some specialized cleanup */
if ( ( flags & PHP_STREAM_CAST_RELEASE ) ) {
php_stream_free ( stream , PHP_STREAM_FREE_CLOSE_CASTED ) ;
}
2011-09-04 22:36:33 +00:00
/* TODO: we probably should be setting .stdiocast and .fclose_stdiocast or
* we may be leaking the FILE * . Needs investigation , though . */
return retcast ;
2003-02-16 22:19:28 +00:00
}
}
}
}
2003-02-18 01:22:21 +00:00
if ( php_stream_is_filtered ( stream ) ) {
2003-02-16 22:19:28 +00:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot cast a filtered stream on this system " ) ;
return FAILURE ;
} else if ( stream - > ops - > cast & & stream - > ops - > cast ( stream , castas , ret TSRMLS_CC ) = = SUCCESS ) {
goto exit_success ;
}
if ( show_err ) {
/* these names depend on the values of the PHP_STREAM_AS_XXX defines in php_streams.h */
2003-06-28 11:24:47 +00:00
static const char * cast_names [ 4 ] = {
2010-01-19 12:03:07 +00:00
" STDIO FILE* " ,
" File Descriptor " ,
" Socket Descriptor " ,
" select()able descriptor "
2003-02-16 22:19:28 +00:00
} ;
2010-01-19 12:03:07 +00:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " cannot represent a stream of type %s as a %s " , stream - > ops - > label , cast_names [ castas ] ) ;
2003-02-16 22:19:28 +00:00
}
return FAILURE ;
exit_success :
if ( ( stream - > writepos - stream - > readpos ) > 0 & &
2010-01-19 12:03:07 +00:00
stream - > fclose_stdiocast ! = PHP_STREAM_FCLOSE_FOPENCOOKIE & &
( flags & PHP_STREAM_CAST_INTERNAL ) = = 0
) {
2003-02-16 22:19:28 +00:00
/* the data we have buffered will be lost to the third party library that
* will be accessing the stream . Emit a warning so that the end - user will
* know that they should try something else */
2010-01-19 12:03:07 +00:00
2014-08-25 18:22:49 +00:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , ZEND_LONG_FMT " bytes of buffered data lost during stream conversion! " , ( zend_long ) ( stream - > writepos - stream - > readpos ) ) ;
2003-02-16 22:19:28 +00:00
}
2010-01-19 12:03:07 +00:00
if ( castas = = PHP_STREAM_AS_STDIO & & ret ) {
2003-03-15 13:29:56 +00:00
stream - > stdiocast = * ( FILE * * ) ret ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
if ( flags & PHP_STREAM_CAST_RELEASE ) {
php_stream_free ( stream , PHP_STREAM_FREE_CLOSE_CASTED ) ;
}
return SUCCESS ;
}
/* }}} */
/* {{{ php_stream_open_wrapper_as_file */
PHPAPI FILE * _php_stream_open_wrapper_as_file ( char * path , char * mode , int options , char * * opened_path STREAMS_DC TSRMLS_DC )
{
FILE * fp = NULL ;
php_stream * stream = NULL ;
stream = php_stream_open_wrapper_rel ( path , mode , options | STREAM_WILL_CAST , opened_path ) ;
2010-01-19 12:03:07 +00:00
if ( stream = = NULL ) {
2003-02-16 22:19:28 +00:00
return NULL ;
2010-01-19 12:03:07 +00:00
}
if ( php_stream_cast ( stream , PHP_STREAM_AS_STDIO | PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE , ( void * * ) & fp , REPORT_ERRORS ) = = FAILURE ) {
2003-02-16 22:19:28 +00:00
php_stream_close ( stream ) ;
2010-01-19 12:03:07 +00:00
if ( opened_path & & * opened_path ) {
2003-02-16 22:19:28 +00:00
efree ( * opened_path ) ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
return NULL ;
}
return fp ;
}
/* }}} */
/* {{{ php_stream_make_seekable */
PHPAPI int _php_stream_make_seekable ( php_stream * origstream , php_stream * * newstream , int flags STREAMS_DC TSRMLS_DC )
{
2011-01-20 06:32:59 +00:00
if ( newstream = = NULL ) {
return PHP_STREAM_FAILED ;
}
2003-02-16 22:19:28 +00:00
* newstream = NULL ;
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
if ( ( ( flags & PHP_STREAM_FORCE_CONVERSION ) = = 0 ) & & origstream - > ops - > seek ! = NULL ) {
* newstream = origstream ;
return PHP_STREAM_UNCHANGED ;
}
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
/* Use a tmpfile and copy the old streams contents into it */
2010-01-19 12:03:07 +00:00
if ( flags & PHP_STREAM_PREFER_STDIO ) {
2003-02-16 22:19:28 +00:00
* newstream = php_stream_fopen_tmpfile ( ) ;
2010-01-19 12:03:07 +00:00
} else {
2003-02-16 22:19:28 +00:00
* newstream = php_stream_temp_new ( ) ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
2010-01-19 12:03:07 +00:00
if ( * newstream = = NULL ) {
2003-02-16 22:19:28 +00:00
return PHP_STREAM_FAILED ;
2010-01-19 12:03:07 +00:00
}
2003-02-16 22:19:28 +00:00
2007-11-06 11:02:36 +00:00
# if ZEND_DEBUG
( * newstream ) - > open_filename = origstream - > open_filename ;
( * newstream ) - > open_lineno = origstream - > open_lineno ;
# endif
2009-04-19 17:10:35 +00:00
if ( php_stream_copy_to_stream_ex ( origstream , * newstream , PHP_STREAM_COPY_ALL , NULL ) ! = SUCCESS ) {
2003-02-16 22:19:28 +00:00
php_stream_close ( * newstream ) ;
* newstream = NULL ;
return PHP_STREAM_CRITICAL ;
}
php_stream_close ( origstream ) ;
php_stream_seek ( * newstream , 0 , SEEK_SET ) ;
2010-01-19 12:03:07 +00:00
2003-02-16 22:19:28 +00:00
return PHP_STREAM_RELEASED ;
}
/* }}} */
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
* vim600 : noet sw = 4 ts = 4 fdm = marker
* vim < 600 : noet sw = 4 ts = 4
*/