zval *stat_dev, *stat_ino, *stat_mode, *stat_nlink, *stat_uid, *stat_gid, *stat_rdev,
*stat_size, *stat_atime, *stat_mtime, *stat_ctime, *stat_blksize, *stat_blocks;
int type;
- void *what;
- struct stat stat_sb;
- int fd;
+ php_stream *stream;
+ php_stream_statbuf stat_ssb;
char *stat_sb_names[13]={"dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
"size", "atime", "mtime", "ctime", "blksize", "blocks"};
WRONG_PARAM_COUNT;
}
- what = zend_fetch_resource(fp TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream);
- ZEND_VERIFY_RESOURCE(what);
+ stream = (php_stream *) zend_fetch_resource(fp TSRMLS_CC,-1, "File-Handle", &type, 1, le_stream);
+ ZEND_VERIFY_RESOURCE(stream);
- if (FAILURE == php_stream_cast((php_stream*)what, PHP_STREAM_AS_FD, (void*)&fd, 1)) {
- RETURN_FALSE;
- }
-
- if (fstat(fd, &stat_sb)) {
+ if (php_stream_stat(stream, &stat_ssb)) {
RETURN_FALSE;
}
array_init(return_value);
- MAKE_LONG_ZVAL_INCREF(stat_dev, stat_sb.st_dev);
- MAKE_LONG_ZVAL_INCREF(stat_ino, stat_sb.st_ino);
- MAKE_LONG_ZVAL_INCREF(stat_mode, stat_sb.st_mode);
- MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_sb.st_nlink);
- MAKE_LONG_ZVAL_INCREF(stat_uid, stat_sb.st_uid);
- MAKE_LONG_ZVAL_INCREF(stat_gid, stat_sb.st_gid);
+ MAKE_LONG_ZVAL_INCREF(stat_dev, stat_ssb.sb.st_dev);
+ MAKE_LONG_ZVAL_INCREF(stat_ino, stat_ssb.sb.st_ino);
+ MAKE_LONG_ZVAL_INCREF(stat_mode, stat_ssb.sb.st_mode);
+ MAKE_LONG_ZVAL_INCREF(stat_nlink, stat_ssb.sb.st_nlink);
+ MAKE_LONG_ZVAL_INCREF(stat_uid, stat_ssb.sb.st_uid);
+ MAKE_LONG_ZVAL_INCREF(stat_gid, stat_ssb.sb.st_gid);
#ifdef HAVE_ST_RDEV
- MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_sb.st_rdev);
+ MAKE_LONG_ZVAL_INCREF(stat_rdev, stat_ssb.sb.st_rdev);
#else
MAKE_LONG_ZVAL_INCREF(stat_rdev, -1);
#endif
- MAKE_LONG_ZVAL_INCREF(stat_size, stat_sb.st_size);
- MAKE_LONG_ZVAL_INCREF(stat_atime, stat_sb.st_atime);
- MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_sb.st_mtime);
- MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_sb.st_ctime);
+ MAKE_LONG_ZVAL_INCREF(stat_size, stat_ssb.sb.st_size);
+ MAKE_LONG_ZVAL_INCREF(stat_atime, stat_ssb.sb.st_atime);
+ MAKE_LONG_ZVAL_INCREF(stat_mtime, stat_ssb.sb.st_mtime);
+ MAKE_LONG_ZVAL_INCREF(stat_ctime, stat_ssb.sb.st_ctime);
#ifdef HAVE_ST_BLKSIZE
- MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_sb.st_blksize);
+ MAKE_LONG_ZVAL_INCREF(stat_blksize, stat_ssb.sb.st_blksize);
#else
MAKE_LONG_ZVAL_INCREF(stat_blksize,-1);
#endif
#ifdef HAVE_ST_BLOCKS
- MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_sb.st_blocks);
+ MAKE_LONG_ZVAL_INCREF(stat_blocks, stat_ssb.sb.st_blocks);
#else
MAKE_LONG_ZVAL_INCREF(stat_blocks,-1);
#endif
return strtol(tmp_line, NULL, 10);
}
+static int php_stream_ftp_stream_stat(php_stream_wrapper *wrapper,
+ php_stream *stream,
+ php_stream_statbuf *ssb
+ TSRMLS_DC)
+{
+ /* For now, we return with a failure code to prevent the underlying
+ * file's details from being used instead. */
+ return -1;
+}
+
+
static php_stream_wrapper_ops ftp_stream_wops = {
php_stream_url_wrap_ftp,
+ NULL,
+ php_stream_ftp_stream_stat,
NULL
};
#define HTTP_HEADER_BLOCK_SIZE 1024
-
php_stream *php_stream_url_wrap_http(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
{
php_stream *stream = NULL;
return stream;
}
+static int php_stream_http_stream_stat(php_stream_wrapper *wrapper,
+ php_stream *stream,
+ php_stream_statbuf *ssb
+ TSRMLS_DC)
+{
+ /* one day, we could fill in the details based on Date: and Content-Length:
+ * headers. For now, we return with a failure code to prevent the underlying
+ * file's details from being used instead. */
+ return -1;
+}
+
static php_stream_wrapper_ops http_stream_wops = {
php_stream_url_wrap_http,
+ NULL,
+ php_stream_http_stream_stat,
NULL
};
static php_stream_wrapper_ops php_stdio_wops = {
php_stream_url_wrap_php,
+ NULL,
+ NULL,
NULL
};
php_stream_ops php_stream_gzio_ops = {
php_gziop_write, php_gziop_read,
php_gziop_close, php_gziop_flush,
+ "ZLIB",
php_gziop_seek, php_gziop_gets,
- NULL, "ZLIB"
+ NULL, NULL
};
php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
php_stream_ops php_stream_memory_ops = {
php_stream_memory_write, php_stream_memory_read,
php_stream_memory_close, php_stream_memory_flush,
+ "MEMORY",
php_stream_memory_seek,
php_stream_memory_gets,
php_stream_memory_cast,
- "MEMORY"
+ NULL
};
php_stream_ops php_stream_temp_ops = {
php_stream_temp_write, php_stream_temp_read,
php_stream_temp_close, php_stream_temp_flush,
+ "TEMP",
php_stream_temp_seek,
php_stream_temp_gets,
php_stream_temp_cast,
- "TEMP"
+ NULL
};
return fsync(sock->socket);
}
+static int php_sockop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+ return fstat(sock->socket, &ssb->sb);
+}
+
static int php_sockop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
{
php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
php_stream_ops php_stream_socket_ops = {
php_sockop_write, php_sockop_read,
php_sockop_close, php_sockop_flush,
+ "socket",
NULL, php_sockop_gets,
php_sockop_cast,
- "socket"
+ php_sockop_stat
};
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
+#include <sys/types.h>
+#include <sys/stat.h>
/* See README.STREAMS in php4 root dir for more info about this stuff */
typedef struct _php_stream php_stream;
typedef struct _php_stream_wrapper php_stream_wrapper;
+typedef struct _php_stream_statbuf {
+ struct stat sb; /* regular info */
+ /* extended info to go here some day */
+} php_stream_statbuf;
+
typedef struct _php_stream_ops {
/* stdio like functions - these are mandatory! */
size_t (*write)(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
size_t (*read)(php_stream *stream, char *buf, size_t count TSRMLS_DC);
int (*close)(php_stream *stream, int close_handle TSRMLS_DC);
int (*flush)(php_stream *stream TSRMLS_DC);
+
+ const char *label; /* label for this ops structure */
+
/* these are optional */
int (*seek)(php_stream *stream, off_t offset, int whence TSRMLS_DC);
char *(*gets)(php_stream *stream, char *buf, size_t size TSRMLS_DC);
int (*cast)(php_stream *stream, int castas, void **ret TSRMLS_DC);
- const char *label; /* label for this ops structure */
+ int (*stat)(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
} php_stream_ops;
typedef struct _php_stream_wrapper_ops {
+ /* open/create a wrapped stream */
php_stream *(*opener)(php_stream_wrapper *wrapper, char *filename, char *mode,
int options, char **opened_path STREAMS_DC TSRMLS_DC);
- php_stream *(*closer)(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC);
+ /* close/destroy a wrapped stream */
+ int (*closer)(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC);
+ /* stat a wrapped stream */
+ int (*stream_stat)(php_stream_wrapper *wrapper, php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
+ /* stat a URL */
+ int (*url_stat)(php_stream_wrapper *wrapper, php_stream_statbuf *ssb TSRMLS_DC);
} php_stream_wrapper_ops;
struct _php_stream_wrapper {
PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC);
#define php_stream_puts(stream, buf) _php_stream_puts((stream), (buf) TSRMLS_CC)
+PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
+#define php_stream_stat(stream, ssb) _php_stream_stat((stream), (ssb) TSRMLS_CC)
+
/* copy up to maxlen bytes from src to dest. If maxlen is PHP_STREAM_COPY_ALL, copy until eof(src).
* Uses mmap if the src is a plain file and at offset 0 */
#define PHP_STREAM_COPY_ALL -1
#include "build-defs.h"
#endif
+#define STREAM_DEBUG 0
+
/* {{{ some macros to help track leaks */
#if ZEND_DEBUG
#define emalloc_rel_orig(size) \
memset(ret, 0, sizeof(php_stream));
+#if STREAM_DEBUG
+fprintf(stderr, "stream_alloc: %s:%p\n", ops->label, ret);
+#endif
+
ret->ops = ops;
ret->abstract = abstract;
ret->is_persistent = persistent;
{
int ret = 1;
+#if STREAM_DEBUG
+fprintf(stderr, "stream_free: %s:%p in_free=%d opts=%08x\n", stream->ops->label, stream, stream->in_free, close_options);
+#endif
+
if (stream->in_free)
return 1;
return fclose(stream->stdiocast);
}
- php_stream_flush(stream);
-
ret = stream->ops->close(stream, close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 0 : 1 TSRMLS_CC);
stream->abstract = NULL;
if (close_options & PHP_STREAM_FREE_RELEASE_STREAM) {
- if (stream->wrapper && stream->wrapper->wops->closer) {
+ if (stream->wrapper && stream->wrapper->wops && stream->wrapper->wops->closer) {
stream->wrapper->wops->closer(stream->wrapper, stream TSRMLS_CC);
stream->wrapper = NULL;
}
return 0;
}
+PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ memset(ssb, 0, sizeof(*ssb));
+
+ /* if the stream was wrapped, allow the wrapper to stat it */
+ if (stream->wrapper && stream->wrapper->wops->stream_stat != NULL) {
+ return stream->wrapper->wops->stream_stat(stream->wrapper, stream, ssb TSRMLS_CC);
+ }
+
+ /* if the stream doesn't directly support stat-ing, return with failure.
+ * We could try and emulate this by casting to a FD and fstat-ing it,
+ * but since the fd might not represent the actual underlying content
+ * this would give bogus results. */
+ if (stream->ops->stat == NULL) {
+ return -1;
+ }
+
+ return stream->ops->stat(stream, ssb TSRMLS_CC);
+}
+
PHPAPI char *_php_stream_gets(php_stream *stream, char *buf, size_t maxlen TSRMLS_DC)
{
if (fstat(srcfd, &sbuf) == 0) {
void *srcfile;
+#if STREAM_DEBUG
+ fprintf(stderr, "mmap attempt: maxlen=%d filesize=%d\n", maxlen, sbuf.st_size);
+#endif
+
if (maxlen > sbuf.st_size || maxlen == 0)
maxlen = sbuf.st_size;
-
+#if STREAM_DEBUG
+ fprintf(stderr, "mmap attempt: will map maxlen=%d\n", maxlen);
+#endif
+
srcfile = mmap(NULL, maxlen, PROT_READ, MAP_SHARED, srcfd, 0);
if (srcfile != (void*)MAP_FAILED) {
- *buf = pemalloc_rel_orig(persistent, maxlen);
+ *buf = pemalloc_rel_orig(maxlen + 1, persistent);
if (*buf) {
memcpy(*buf, srcfile, maxlen);
+ (*buf)[maxlen] = '\0';
ret = maxlen;
}
munmap(srcfile, maxlen);
+
return ret;
}
}
}
#endif
- ptr = *buf = pemalloc_rel_orig(persistent, step);
+ ptr = *buf = pemalloc_rel_orig(step, persistent);
max_len = step;
while((ret = php_stream_read(src, ptr, max_len - len))) {
}
}
+static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
+{
+ int fd;
+ php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract;
+
+ assert(data != NULL);
+
+ fd = fileno(data->file);
+
+ return fstat(fd, &ssb->sb);
+}
+
php_stream_ops php_stream_stdio_ops = {
php_stdiop_write, php_stdiop_read,
- php_stdiop_close, php_stdiop_flush, php_stdiop_seek,
+ php_stdiop_close, php_stdiop_flush,
+ "STDIO",
+ php_stdiop_seek,
php_stdiop_gets, php_stdiop_cast,
- "STDIO"
+ php_stdiop_stat
};
/* }}} */
{
ssize_t ret;
TSRMLS_FETCH();
-
ret = php_stream_read(((php_stream *)cookie), buffer, size);
return ret;
}
static php_stream_wrapper_ops user_stream_wops = {
user_wrapper_opener,
+ NULL,
+ NULL,
NULL
};
php_stream_ops php_stream_userspace_ops = {
php_userstreamop_write, php_userstreamop_read,
php_userstreamop_close, php_userstreamop_flush,
+ "user-space",
php_userstreamop_seek, php_userstreamop_gets,
NULL, /* cast */
- "user-space"
+ NULL /* stat */
};