Back to index

php5  5.3.10
Defines | Functions
cast.c File Reference
#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"

Go to the source code of this file.

Defines

#define _GNU_SOURCE

Functions

void php_stream_mode_sanitize_fdopen_fopencookie (php_stream *stream, char *result)
PHPAPI int _php_stream_cast (php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC)
PHPAPI FILE * _php_stream_open_wrapper_as_file (char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
PHPAPI int _php_stream_make_seekable (php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC)

Define Documentation

#define _GNU_SOURCE

Definition at line 21 of file cast.c.


Function Documentation

PHPAPI int _php_stream_cast ( php_stream *  stream,
int  castas,
void **  ret,
int show_err  TSRMLS_DC 
)

Definition at line 192 of file cast.c.

{
       int flags = castas & PHP_STREAM_CAST_MASK;
       castas &= ~PHP_STREAM_CAST_MASK;

       /* synchronize our buffer (if possible) */
       if (ret && castas != PHP_STREAM_AS_FD_FOR_SELECT) {
              php_stream_flush(stream);
              if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
                     off_t dummy;

                     stream->ops->seek(stream, stream->position, SEEK_SET, &dummy TSRMLS_CC);
                     stream->readpos = stream->writepos = 0;
              }
       }

       /* filtered streams can only be cast as stdio, and only when fopencookie is present */

       if (castas == PHP_STREAM_AS_STDIO) {
              if (stream->stdiocast) {
                     if (ret) {
                            *(FILE**)ret = stream->stdiocast;
                     }
                     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) &&
                     stream->ops->cast &&
                     !php_stream_is_filtered(stream) &&
                     stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS
              ) {
                     goto exit_success;
              }

#if HAVE_FOPENCOOKIE
              /* if just checking, say yes we can be a FILE*, but don't actually create it yet */
              if (ret == NULL) {
                     goto exit_success;
              }

              {
                     char fixed_mode[5];
                     php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode);
                     *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS);
              }

              if (*ret != NULL) {
                     off_t pos;

                     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);
                     if (pos > 0) {
                            fseek(*ret, pos, SEEK_SET);
                     }

                     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

              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) {
                     php_stream *newstream;

                     newstream = php_stream_fopen_tmpfile();
                     if (newstream) {
                            size_t retcopy = php_stream_copy_to_stream_ex(stream, newstream, PHP_STREAM_COPY_ALL, NULL);

                            if (retcopy != SUCCESS) {
                                   php_stream_close(newstream);
                            } else {
                                   int retcast = php_stream_cast(newstream, castas | flags, (void **)ret, show_err);

                                   if (retcast == SUCCESS) {
                                          rewind(*(FILE**)ret);
                                   }

                                   /* do some specialized cleanup */
                                   if ((flags & PHP_STREAM_CAST_RELEASE)) {
                                          php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED);
                                   }

                                   /* TODO: we probably should be setting .stdiocast and .fclose_stdiocast or
                                    * we may be leaking the FILE*. Needs investigation, though. */
                                   return retcast;
                            }
                     }
              }
       }

       if (php_stream_is_filtered(stream)) {
              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 */
              static const char *cast_names[4] = {
                     "STDIO FILE*",
                     "File Descriptor",
                     "Socket Descriptor",
                     "select()able descriptor"
              };

              php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot represent a stream of type %s as a %s", stream->ops->label, cast_names[castas]);
       }

       return FAILURE;

exit_success:

       if ((stream->writepos - stream->readpos) > 0 &&
              stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE &&
              (flags & PHP_STREAM_CAST_INTERNAL) == 0
       ) {
              /* 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 */

              php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld bytes of buffered data lost during stream conversion!", (long)(stream->writepos - stream->readpos));
       }

       if (castas == PHP_STREAM_AS_STDIO && ret) {
              stream->stdiocast = *(FILE**)ret;
       }

       if (flags & PHP_STREAM_CAST_RELEASE) {
              php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED);
       }

       return SUCCESS;

}

Here is the call graph for this function:

PHPAPI int _php_stream_make_seekable ( php_stream *  origstream,
php_stream **  newstream,
int flags STREAMS_DC  TSRMLS_DC 
)

Definition at line 369 of file cast.c.

{
       if (newstream == NULL) {
              return PHP_STREAM_FAILED;
       }
       *newstream = NULL;

       if (((flags & PHP_STREAM_FORCE_CONVERSION) == 0) && origstream->ops->seek != NULL) {
              *newstream = origstream;
              return PHP_STREAM_UNCHANGED;
       }

       /* Use a tmpfile and copy the old streams contents into it */

       if (flags & PHP_STREAM_PREFER_STDIO) {
              *newstream = php_stream_fopen_tmpfile();
       } else {
              *newstream = php_stream_temp_new();
       }

       if (*newstream == NULL) {
              return PHP_STREAM_FAILED;
       }

#if ZEND_DEBUG
       (*newstream)->open_filename = origstream->open_filename;
       (*newstream)->open_lineno = origstream->open_lineno;
#endif

       if (php_stream_copy_to_stream_ex(origstream, *newstream, PHP_STREAM_COPY_ALL, NULL) != SUCCESS) {
              php_stream_close(*newstream);
              *newstream = NULL;
              return PHP_STREAM_CRITICAL;
       }

       php_stream_close(origstream);
       php_stream_seek(*newstream, 0, SEEK_SET);

       return PHP_STREAM_RELEASED;
}
PHPAPI FILE* _php_stream_open_wrapper_as_file ( char *  path,
char *  mode,
int  options,
char **opened_path STREAMS_DC  TSRMLS_DC 
)

Definition at line 346 of file cast.c.

{
       FILE *fp = NULL;
       php_stream *stream = NULL;

       stream = php_stream_open_wrapper_rel(path, mode, options|STREAM_WILL_CAST, opened_path);

       if (stream == NULL) {
              return NULL;
       }

       if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE, (void**)&fp, REPORT_ERRORS) == FAILURE) {
              php_stream_close(stream);
              if (opened_path && *opened_path) {
                     efree(*opened_path);
              }
              return NULL;
       }
       return fp;
}
void php_stream_mode_sanitize_fdopen_fopencookie ( php_stream *  stream,
char *  result 
)

Definition at line 149 of file cast.c.

{
       /* 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';
}

Here is the caller graph for this function: