mirror of
https://github.com/php/php-src.git
synced 2024-09-22 10:27:25 +00:00
add rename support
This commit is contained in:
parent
0bc1b90ec3
commit
744ec410ec
@ -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
|
||||
|
||||
|
152
ext/phar/phar.c
152
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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
|
32
ext/phar/tests/rename.phpt
Normal file
32
ext/phar/tests/rename.phpt
Normal file
@ -0,0 +1,32 @@
|
||||
--TEST--
|
||||
Phar: rename test
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("phar")) print "skip"; ?>
|
||||
--INI--
|
||||
phar.readonly=0
|
||||
phar.require_hash=0
|
||||
--FILE--
|
||||
<?php
|
||||
$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
|
||||
$pname = 'phar://' . $fname;
|
||||
$file = "<?php
|
||||
Phar::mapPhar('hio');
|
||||
__HALT_COMPILER(); ?>";
|
||||
|
||||
$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--
|
||||
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
|
||||
--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
|
Loading…
Reference in New Issue
Block a user