#include <stdio.h>
struct cookiedata {
- fpos_t pos;
+ __off64_t pos;
};
-size_t reader(void *cookie, char *buffer, size_t size)
+__ssize_t reader(void *cookie, char *buffer, size_t size)
{ return size; }
-size_t writer(void *cookie, const char *buffer, size_t size)
+__ssize_t writer(void *cookie, const char *buffer, size_t size)
{ return size; }
int closer(void *cookie)
{ return 0; }
-int seeker(void *cookie, fpos_t *position, int whence)
+int seeker(void *cookie, __off64_t *position, int whence)
{ ((struct cookiedata*)cookie)->pos = *position; return 0; }
cookie_io_functions_t funcs = {reader, writer, seeker, closer};
struct cookiedata g = { 0 };
FILE *fp = fopencookie(&g, "r", funcs);
- if (fp && fseek(fp, 69, SEEK_SET) == 0 && g.pos == 69)
+ if (fp && fseek(fp, 8192, SEEK_SET) == 0 && g.pos == 8192)
exit(0);
exit(1);
}
],
- [ cookie_io_functions_use_fpos_t=yes ],
+ [ cookie_io_functions_use_off64_t=yes ],
[ ] )
else
if test "$have_fopen_cookie" = "yes" ; then
AC_DEFINE(HAVE_FOPENCOOKIE, 1, [ ])
AC_DEFINE_UNQUOTED(COOKIE_IO_FUNCTIONS_T, $cookie_io_functions_t, [ ])
- if test "$cookie_io_functions_use_fpos_t" = "yes" ; then
- AC_DEFINE(COOKIE_SEEKER_USES_FPOS_T, 1, [ ])
+ if test "$cookie_io_functions_use_off64_t" = "yes" ; then
+ AC_DEFINE(COOKIE_SEEKER_USES_OFF64_T, 1, [ ])
fi
fi
+----------------------------------------------------------------------+
*/
+/* $Id$ */
+
#ifndef PHP_STREAMS_H
#define PHP_STREAMS_H
#define PHP_STREAM_FREE_PRESERVE_HANDLE 4 /* tell ops->close to not close it's underlying handle */
#define PHP_STREAM_FREE_RSRC_DTOR 8 /* called from the resource list dtor */
#define PHP_STREAM_FREE_CLOSE (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)
+#define PHP_STREAM_FREE_CLOSE_CASTED (PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_PRESERVE_HANDLE)
PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC);
#define php_stream_free(stream, close_options) _php_stream_free((stream), (close_options) TSRMLS_CC)
#define php_stream_close(stream) _php_stream_free((stream), PHP_STREAM_FREE_CLOSE TSRMLS_CC)
/* cast as a socketd */
#define PHP_STREAM_AS_SOCKETD 2
-/* try really, really hard to make sure the cast happens (socketpair) */
+/* try really, really hard to make sure the cast happens (avoid using this flag if possible) */
#define PHP_STREAM_CAST_TRY_HARD 0x80000000
#define PHP_STREAM_CAST_RELEASE 0x40000000 /* stream becomes invalid on success */
#define PHP_STREAM_CAST_INTERNAL 0x20000000 /* stream cast for internal use */
/* this flag is only used by include/require functions */
#define STREAM_OPEN_FOR_INCLUDE 128
-#ifdef PHP_WIN32
-# define IGNORE_URL_WIN STREAM_MUST_SEEK
-#else
-# define IGNORE_URL_WIN 0
-#endif
+/* Antique - no longer has meaning */
+#define IGNORE_URL_WIN 0
int php_init_stream_wrappers(int module_number TSRMLS_DC);
int php_shutdown_stream_wrappers(int module_number TSRMLS_DC);
#define PHP_STREAM_CRITICAL 3 /* an error occurred; origstream is in an unknown state; you should close origstream */
#define PHP_STREAM_NO_PREFERENCE 0
#define PHP_STREAM_PREFER_STDIO 1
+#define PHP_STREAM_FORCE_CONVERSION 2
/* DO NOT call this on streams that are referenced by resources! */
PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC);
#define php_stream_make_seekable(origstream, newstream, flags) _php_stream_make_seekable((origstream), (newstream), (flags) STREAMS_CC TSRMLS_CC)
#endif
#define STREAM_DEBUG 0
-
#define STREAM_WRAPPER_PLAIN_FILES ((php_stream_wrapper*)-1)
/* {{{ some macros to help track leaks */
PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */
{
int ret = 1;
+ int remove_rsrc = 1;
+ int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0;
+ int release_cast = 1;
#if STREAM_DEBUG
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);
#endif
+ /* recursion protection */
if (stream->in_free)
return 1;
stream->in_free++;
- _php_stream_flush(stream, 1 TSRMLS_CC);
+ /* if we are releasing the stream only (and preserving the underlying handle),
+ * we need to do things a little differently.
+ * We are only ever called like this when the stream is cast to a FILE*
+ * for include (or other similar) purposes.
+ * */
+ if (preserve_handle) {
+ if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
+ /* If the stream was fopencookied, we must NOT touch anything
+ * here, as the cookied stream relies on it all.
+ * Instead, mark the stream as OK to auto-clean */
+ php_stream_auto_cleanup(stream);
+ stream->in_free--;
+ return 0;
+ }
+ /* otherwise, make sure that we don't close the FILE* from a cast */
+ release_cast = 0;
+ }
+
+#if STREAM_DEBUG
+fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remove_rsrc=%d\n",
+ stream->ops->label, stream, stream->__orig_path, preserve_handle, release_cast, remove_rsrc);
+#endif
- if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0) {
- /* Remove entry from the resource list */
+ /* make sure everything is saved */
+ _php_stream_flush(stream, 1 TSRMLS_CC);
+
+ /* If not called from the resource dtor, remove the stream
+ * from the resource list.
+ * */
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0 && remove_rsrc) {
zend_list_delete(stream->rsrc_id);
}
+
if (close_options & PHP_STREAM_FREE_CALL_DTOR) {
- if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
+ if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
/* calling fclose on an fopencookied stream will ultimately
call this very same function. If we were called via fclose,
the cookie_closer unsets the fclose_stdiocast flags, so
return fclose(stream->stdiocast);
}
- ret = stream->ops->close(stream, close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 0 : 1 TSRMLS_CC);
+ ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC);
stream->abstract = NULL;
/* tidy up any FILE* that might have been fdopened */
- if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FDOPEN && stream->stdiocast) {
+ if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FDOPEN && stream->stdiocast) {
fclose(stream->stdiocast);
stream->stdiocast = NULL;
+ stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE;
}
}
int fd; /* underlying file descriptor */
int is_process_pipe; /* use pclose instead of fclose */
int is_pipe; /* don't try and seek */
+ char *temp_file_name; /* if non-null, this is the path to a temporary file that
+ * is to be deleted when the stream is closed */
#if HAVE_FLUSHIO
char last_op;
#endif
PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC)
{
- FILE *fp;
- php_stream *stream;
+ char *opened_path = NULL;
+ FILE *fp = php_open_temporary_file(NULL, "php", &opened_path TSRMLS_CC);
- fp = tmpfile();
- if (fp == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "tmpfile(): %s", strerror(errno));
- return NULL;
- }
- stream = php_stream_fopen_from_file_rel(fp, "r+");
- if (stream == NULL) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "tmpfile(): %s", strerror(errno));
+ if (fp) {
+ php_stream *stream = php_stream_fopen_from_file_rel(fp, "r+b");
+ if (stream) {
+ php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
+
+ self->temp_file_name = opened_path;
+ return stream;
+ }
fclose(fp);
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream");
+
return NULL;
}
- return stream;
+ return NULL;
}
self->file = file;
self->is_pipe = 0;
self->is_process_pipe = 0;
-
+ self->temp_file_name = NULL;
self->fd = fileno(file);
#ifdef S_ISFIFO
self->is_pipe = 1;
self->is_process_pipe = 1;
self->fd = fileno(file);
+ self->temp_file_name = NULL;
return php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode);
}
assert(data != NULL);
if (close_handle) {
- if (data->is_process_pipe) {
- ret = pclose(data->file);
- } else {
- ret = fclose(data->file);
+ if (data->file) {
+ if (data->is_process_pipe) {
+ ret = pclose(data->file);
+ } else {
+ ret = fclose(data->file);
+ }
+ }
+ if (data->temp_file_name) {
+ unlink(data->temp_file_name);
+ efree(data->temp_file_name);
}
} else {
ret = 0;
+ data->file = NULL;
}
/* STDIO streams are never persistent! */
return ret;
}
- err:
+err:
fclose(fp);
}
efree(realpath);
return php_stream_write(((php_stream *)cookie), (char *)buffer, size);
}
-#ifdef COOKIE_SEEKER_USES_FPOS_T
-static int stream_cookie_seeker(void *cookie, fpos_t *position, int whence)
+#ifdef COOKIE_SEEKER_USES_OFF64_T
+static int stream_cookie_seeker(void *cookie, __off64_t *position, int whence)
{
TSRMLS_FETCH();
- *position = php_stream_seek((php_stream *)cookie, *position, whence);
+ *position = php_stream_seek((php_stream *)cookie, (off_t)*position, whence);
if (*position == -1)
return -1;
return FAILURE;
#endif
+ if (flags & PHP_STREAM_CAST_TRY_HARD) {
+ php_stream *newstream;
+
+ newstream = php_stream_fopen_tmpfile();
+ if (newstream) {
+ size_t copied = php_stream_copy_to_stream(stream, newstream, PHP_STREAM_COPY_ALL);
+
+ if (copied == 0) {
+ php_stream_close(newstream);
+ } else {
+ int retcode = php_stream_cast(newstream, castas | flags, ret, show_err);
+
+ if (retcode == SUCCESS)
+ rewind((FILE*)*ret);
+
+ /* do some specialized cleanup */
+ if ((flags & PHP_STREAM_CAST_RELEASE)) {
+ php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED);
+ }
+
+ return retcode;
+ }
+ }
+ }
}
if (stream->filterhead) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot cast a filtered stream on this system");
return FAILURE;
- }
-
- if (stream->ops->cast && stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS)
+ } 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 */
stream->stdiocast = *ret;
if (flags & PHP_STREAM_CAST_RELEASE) {
- /* Something other than php_stream_close will be closing
- * the underlying handle, so we should free the stream handle/data
- * here now. The stream may not be freed immediately (in the case
- * of fopencookie), but the caller should still not touch their
- * original stream pointer in any case. */
- if (stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE) {
- /* ask the implementation to release resources other than
- * the underlying handle */
- php_stream_free(stream, PHP_STREAM_FREE_PRESERVE_HANDLE | PHP_STREAM_FREE_CLOSE);
- }
+ php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED);
}
return SUCCESS;
if (stream == NULL)
return NULL;
+
+#ifdef PHP_WIN32
+ /* Avoid possible strange problems when working with socket based streams */
+ if ((options & STREAM_OPEN_FOR_INCLUDE) && php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
+ char buf[CHUNK_SIZE];
+
+ fp = php_open_temporary_file(NULL, "php", NULL TSRMLS_CC);
+ if (fp) {
+ while (!php_stream_eof(stream)) {
+ size_t didread = php_stream_read(stream, buf, sizeof(buf));
+ if (didread > 0) {
+ fwrite(buf, 1, didread, fp);
+ } else {
+ break;
+ }
+ }
+ php_stream_close(stream);
+ rewind(fp);
+ return fp;
+ }
+ }
+#endif
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE,
(void**)&fp, REPORT_ERRORS) == FAILURE)
*newstream = NULL;
- if (origstream->ops->seek != NULL) {
+ if (((flags & PHP_STREAM_FORCE_CONVERSION) == 0) && origstream->ops->seek != NULL) {
*newstream = origstream;
return PHP_STREAM_UNCHANGED;
}