From 2539cbc74c4f2cca2f39f99b2d679bb4e329b53d Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Thu, 28 Mar 2002 00:49:00 +0000 Subject: [PATCH] Phase 3 of OO wrapper cleanup # What was phase 2? --- ext/standard/file.c | 41 ++++++++----------- ext/standard/ftp_fopen_wrapper.c | 13 ++++++ ext/standard/http_fopen_wrapper.c | 14 ++++++- ext/standard/php_fopen_wrapper.c | 2 + ext/zlib/zlib_fopen_wrapper.c | 3 +- main/memory_streams.c | 6 ++- main/network.c | 9 +++- main/php_streams.h | 23 ++++++++++- main/streams.c | 68 +++++++++++++++++++++++++++---- main/user_streams.c | 5 ++- 10 files changed, 144 insertions(+), 40 deletions(-) diff --git a/ext/standard/file.c b/ext/standard/file.c index 4d3e952406e..fcd50a3cbd8 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1529,9 +1529,8 @@ PHP_NAMED_FUNCTION(php_if_fstat) 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"}; @@ -1540,41 +1539,37 @@ PHP_NAMED_FUNCTION(php_if_fstat) 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 diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 70bf9e68ae6..e7f6eef638e 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -77,8 +77,21 @@ static int php_get_ftp_result(php_stream *stream TSRMLS_DC) 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 }; diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 2f566bd1b3b..c96f43ddff2 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -70,7 +70,6 @@ #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; @@ -309,8 +308,21 @@ out: 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 }; diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index 842df5fceee..e7f07a9e9bd 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -57,6 +57,8 @@ php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, char *path, ch static php_stream_wrapper_ops php_stdio_wops = { php_stream_url_wrap_php, + NULL, + NULL, NULL }; diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index c6e60e36388..c345241aa66 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -88,8 +88,9 @@ static int php_gziop_flush(php_stream *stream TSRMLS_DC) 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) diff --git a/main/memory_streams.c b/main/memory_streams.c index 65d4956b040..fdd074903f5 100644 --- a/main/memory_streams.c +++ b/main/memory_streams.c @@ -232,10 +232,11 @@ static int php_stream_memory_cast(php_stream *stream, int castas, void **ret TSR 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 }; @@ -448,10 +449,11 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret TSRML 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 }; diff --git a/main/network.c b/main/network.c index be15ae26771..7ed301a654a 100644 --- a/main/network.c +++ b/main/network.c @@ -768,6 +768,12 @@ static int php_sockop_flush(php_stream *stream TSRMLS_DC) 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; @@ -869,9 +875,10 @@ static char *php_sockop_gets(php_stream *stream, char *buf, size_t maxlen TSRMLS 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 }; diff --git a/main/php_streams.h b/main/php_streams.h index c8e05fd091d..2243f07de41 100755 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -22,6 +22,8 @@ #ifdef HAVE_SYS_TIME_H #include #endif +#include +#include /* See README.STREAMS in php4 root dir for more info about this stuff */ @@ -88,23 +90,37 @@ 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 { @@ -199,6 +215,9 @@ PHPAPI char *_php_stream_gets(php_stream *stream, char *buf, size_t maxlen TSRML 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 diff --git a/main/streams.c b/main/streams.c index 8f366af0d5d..52431cd1daf 100755 --- a/main/streams.c +++ b/main/streams.c @@ -43,6 +43,8 @@ #include "build-defs.h" #endif +#define STREAM_DEBUG 0 + /* {{{ some macros to help track leaks */ #if ZEND_DEBUG #define emalloc_rel_orig(size) \ @@ -76,6 +78,10 @@ PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract, int pe 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; @@ -90,6 +96,10 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* { 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; @@ -112,8 +122,6 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* 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; @@ -126,7 +134,7 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* 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; } @@ -204,6 +212,26 @@ PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC) 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) { @@ -367,20 +395,29 @@ PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen 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; } } @@ -388,7 +425,7 @@ PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen } #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))) { @@ -687,11 +724,25 @@ static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) } } +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 }; /* }}} */ @@ -850,7 +901,6 @@ static ssize_t stream_cookie_reader(void *cookie, char *buffer, size_t size) { ssize_t ret; TSRMLS_FETCH(); - ret = php_stream_read(((php_stream *)cookie), buffer, size); return ret; } diff --git a/main/user_streams.c b/main/user_streams.c index 53bb3863ccc..fe81d7c10f2 100644 --- a/main/user_streams.c +++ b/main/user_streams.c @@ -33,6 +33,8 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filena static php_stream_wrapper_ops user_stream_wops = { user_wrapper_opener, + NULL, + NULL, NULL }; @@ -504,9 +506,10 @@ static char *php_userstreamop_gets(php_stream *stream, char *buf, size_t size TS 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 */ };