]> granicus.if.org Git - php/commitdiff
add rename support
authorGreg Beaver <cellog@php.net>
Sun, 28 Jan 2007 22:43:38 +0000 (22:43 +0000)
committerGreg Beaver <cellog@php.net>
Sun, 28 Jan 2007 22:43:38 +0000 (22:43 +0000)
ext/phar/TODO
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/tests/rename.phpt [new file with mode: 0644]

index 79eaa633111a3aad68630e3b824b7d8d1ca660e3..bc71b8877de915821f6979e42bdf2d2931215da7 100644 (file)
@@ -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
 
index e56ec88013a5a006d05bbfc6e2e501313f64c5ca..a1de40f86fc20f33a217921297468e579790af39 100644 (file)
@@ -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
  */
index e5d5c4620ece6cae3db2ad441ff746c4ea60638a..43fb5a4111744b37975c5cc0381d3fa5f2c4d63d 100755 (executable)
@@ -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 (file)
index 0000000..6d3cc2c
--- /dev/null
@@ -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
\ No newline at end of file