From: Greg Beaver Date: Sun, 28 Jan 2007 22:43:38 +0000 (+0000) Subject: add rename support X-Git-Tag: RELEASE_1_0_0RC1~81 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=744ec410ec4a58e358579ba1e341db3d5d1e108d;p=php add rename support --- diff --git a/ext/phar/TODO b/ext/phar/TODO index 79eaa63311..bc71b8877d 100644 --- a/ext/phar/TODO +++ b/ext/phar/TODO @@ -26,7 +26,7 @@ Version 1.0.0 * always throw exceptions from the Phar object, and E_RECOVERABLE_ERROR from streams interface * Phar archive metadata - * support rename() in stream wrapper + X support rename() in stream wrapper [Greg] Version 1.1.0 diff --git a/ext/phar/phar.c b/ext/phar/phar.c index e56ec88013..a1de40f86f 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1248,7 +1248,7 @@ static php_stream_wrapper_ops phar_stream_wops = { phar_wrapper_open_dir, /* opendir */ "phar", phar_wrapper_unlink, /* unlink */ - NULL, /* rename */ + phar_wrapper_rename, /* rename */ NULL, /* create directory */ NULL, /* remove directory */ }; @@ -2536,7 +2536,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio char *internal_file; char *error; phar_entry_data *idata; - + resource = php_url_parse(url); if (!resource && (resource = phar_open_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) { @@ -2561,7 +2561,7 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting"); return FAILURE; } - + /* need to copy to strip leading "/", will get touched again */ internal_file = estrdup(resource->path + 1); if (FAILURE == phar_get_entry_data(&idata, resource->host, strlen(resource->host), internal_file, strlen(internal_file), "r", &error TSRMLS_CC)) { @@ -2598,6 +2598,152 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio } /* }}} */ +static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */ +{ + php_url *resource_from, *resource_to; + char *from_file, *to_file; + char *error; + phar_entry_data *fromdata, *todata; + + if (PHAR_G(readonly)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting"); + return FAILURE; + } + + resource_from = php_url_parse(url_from); + resource_to = php_url_parse(url_from); + + if (!resource_from && (resource_from = phar_open_url(wrapper, url_from, "r+b", options TSRMLS_CC)) == NULL) { + return FAILURE; + } + + if (!resource_to && (resource_to = phar_open_url(wrapper, url_to, "wb", options TSRMLS_CC)) == NULL) { + php_url_free(resource_from); + return FAILURE; + } + + /* we must have at the very least phar://alias.phar/internalfile.php */ + if (!resource_from->scheme || !resource_from->host || !resource_from->path) { + php_url_free(resource_from); + php_url_free(resource_to); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from); + return FAILURE; + } + + if (!resource_to->scheme || !resource_to->host || !resource_to->path) { + php_url_free(resource_from); + php_url_free(resource_to); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_to); + return FAILURE; + } + + if (strcasecmp("phar", resource_from->scheme)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from); + return FAILURE; + } + + if (strcasecmp("phar", resource_to->scheme)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_to); + return FAILURE; + } + + if (strcmp(resource_from->host, resource_to->host)) { + php_url_free(resource_from); + php_url_free(resource_to); + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to); + return FAILURE; + } + + /* need to copy to strip leading "/", will get touched again */ + from_file = estrdup(resource_from->path + 1); + to_file = estrdup(resource_to->path + 1); + if (FAILURE == phar_get_entry_data(&fromdata, resource_from->host, strlen(resource_from->host), from_file, strlen(from_file), "r", &error TSRMLS_CC)) { + /* constraints of fp refcount were not met */ + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + return FAILURE; + } + if (error) { + efree(error); + } + if (!fromdata) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\", cannot rename", from_file, resource_from->host); + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + return FAILURE; + } + if (!(todata = phar_get_or_create_entry_data(resource_to->host, strlen(resource_to->host), to_file, strlen(to_file), "w", &error TSRMLS_CC))) { + /* constraints of fp refcount were not met */ + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + return FAILURE; + } + if (error) { + efree(error); + } + if (fromdata->internal_file->fp_refcount > 1) { + /* more than just our fp resource is open for this file */ + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot rename", from_file, resource_from->host); + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + phar_entry_delref(fromdata TSRMLS_CC); + phar_entry_delref(todata TSRMLS_CC); + return FAILURE; + } + if (todata->internal_file->fp_refcount > 1) { + /* more than just our fp resource is open for this file */ + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot rename", to_file, resource_to->host); + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + phar_entry_delref(fromdata TSRMLS_CC); + phar_entry_delref(todata TSRMLS_CC); + return FAILURE; + } + + php_stream_seek(fromdata->internal_file->fp, 0, SEEK_SET); + if (fromdata->internal_file->uncompressed_filesize != php_stream_copy_to_stream(fromdata->internal_file->fp, todata->internal_file->fp, PHP_STREAM_COPY_ALL)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: rename failed \"%s\" to \"%s\"", url_from, url_to); + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + phar_entry_delref(fromdata TSRMLS_CC); + phar_entry_delref(todata TSRMLS_CC); + return FAILURE; + } + phar_entry_delref(fromdata TSRMLS_CC); + phar_entry_delref(todata TSRMLS_CC); + efree(from_file); + efree(to_file); + php_url_free(resource_from); + php_url_free(resource_to); + phar_wrapper_unlink(wrapper, url_from, 0, 0 TSRMLS_CC); + return SUCCESS; +} +/* }}} */ + /** * Open a directory handle within a phar archive */ diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index e5d5c4620e..43fb5a4111 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -225,6 +225,7 @@ static php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char static php_stream* phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); static php_stream* phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); +static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC); static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC); static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC); diff --git a/ext/phar/tests/rename.phpt b/ext/phar/tests/rename.phpt new file mode 100644 index 0000000000..6d3cc2c137 --- /dev/null +++ b/ext/phar/tests/rename.phpt @@ -0,0 +1,32 @@ +--TEST-- +Phar: rename test +--SKIPIF-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +"; + +$files = array(); +$files['a'] = 'a'; +include 'phar_test.inc'; +include $fname; + +echo file_get_contents($pname . '/a') . "\n"; +rename($pname . '/a', $pname . '/b'); +echo file_get_contents($pname . '/b') . "\n"; +echo file_get_contents($pname . '/a') . "\n"; +?> +--CLEAN-- + +--EXPECTF-- +a +a + +Warning: file_get_contents(phar://%srename.phar.php/a): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.php" in %srename.php on line %d \ No newline at end of file