summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/phar/dirstream.c116
-rw-r--r--ext/phar/phar.c2
-rwxr-xr-xext/phar/phar_internal.h1
-rw-r--r--ext/phar/stream.c94
-rw-r--r--ext/phar/tests/rename_dir.phpt2
-rwxr-xr-xext/phar/tests/rename_dir_and_mount.phpt65
-rw-r--r--ext/phar/tests/rmdir.phpt9
-rw-r--r--ext/phar/tests/tar/rename_dir.phpt2
-rw-r--r--ext/phar/tests/tar/rmdir.phpt9
-rw-r--r--ext/phar/tests/zip/rename_dir.phpt2
-rw-r--r--ext/phar/tests/zip/rmdir.phpt9
-rw-r--r--ext/phar/util.c49
12 files changed, 264 insertions, 96 deletions
diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
index 6c2bd7231c..4635e67fa3 100644
--- a/ext/phar/dirstream.c
+++ b/ext/phar/dirstream.c
@@ -415,7 +415,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
/* pre-readonly check, we need to know if this is a data phar */
if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
- return FAILURE;
+ return 0;
}
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar = NULL;
@@ -424,24 +424,24 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
efree(entry2);
if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
- return FAILURE;
+ return 0;
}
if ((resource = phar_parse_url(wrapper, url_from, "w", options TSRMLS_CC)) == NULL) {
- return FAILURE;
+ return 0;
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if (!resource->scheme || !resource->host || !resource->path) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url_from);
- return FAILURE;
+ return 0;
}
if (strcasecmp("phar", resource->scheme)) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url_from);
- return FAILURE;
+ return 0;
}
host_len = strlen(resource->host);
@@ -450,7 +450,7 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
efree(error);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1 TSRMLS_CC))) {
@@ -461,31 +461,31 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
}
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", resource->path+1, resource->host);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
efree(error);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1 TSRMLS_CC))) {
/* entry exists as a file */
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
efree(error);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", unable to make cached phar writeable", resource->path+1, resource->host);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
memset((void *) &entry, 0, sizeof(phar_entry_info));
@@ -511,17 +511,17 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname);
efree(error);
efree(entry.filename);
- return FAILURE;
+ return 0;
}
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
zend_hash_del(&phar->manifest, entry.filename, entry.filename_len);
efree(error);
- return FAILURE;
+ return 0;
}
phar_add_virtual_dirs(phar, entry.filename, entry.filename_len TSRMLS_CC);
- return SUCCESS;
+ return 1;
}
/* }}} */
@@ -536,11 +536,16 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
int arch_len, entry_len;
php_url *resource = NULL;
uint host_len;
+ int key_type;
+ char *key;
+ uint key_len;
+ ulong unused;
+ uint path_len;
/* pre-readonly check, we need to know if this is a data phar */
if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2 TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
- return FAILURE;
+ return 0;
}
if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
phar = NULL;
@@ -549,24 +554,24 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
efree(entry2);
if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
- return FAILURE;
+ return 0;
}
if ((resource = phar_parse_url(wrapper, url, "w", options TSRMLS_CC)) == NULL) {
- return FAILURE;
+ return 0;
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if (!resource->scheme || !resource->host || !resource->path) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
- return FAILURE;
+ return 0;
}
if (strcasecmp("phar", resource->scheme)) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
- return FAILURE;
+ return 0;
}
host_len = strlen(resource->host);
@@ -575,10 +580,12 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
efree(error);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
- if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path) - 1, 2, &error, 1 TSRMLS_CC))) {
+ path_len = strlen(resource->path+1);
+
+ if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, path_len, 2, &error, 1 TSRMLS_CC))) {
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
efree(error);
@@ -586,27 +593,70 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", resource->path+1, resource->host);
}
php_url_free(resource);
- return FAILURE;
+ return 0;
}
/* now for the easy part */
if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", unable to make cached phar writeable", resource->path+1, resource->host);
php_url_free(resource);
- return FAILURE;
+ return 0;
}
- entry->is_deleted = 1;
- entry->is_modified = 1;
- phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
- if (error) {
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
- php_url_free(resource);
- efree(error);
- return FAILURE;
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL));
+ zend_hash_move_forward(&phar->manifest)) {
+
+ if (!entry->is_deleted &&
+ key_len > path_len &&
+ memcmp(key, resource->path+1, path_len) == 0 &&
+ IS_SLASH(key[path_len])) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
+ if (entry->is_temp_dir) {
+ efree(entry->filename);
+ efree(entry);
+ }
+ php_url_free(resource);
+ return 0;
+ }
}
- phar_delete_virtual_dirs(phar, resource->path + 1, strlen(resource->path) - 1 TSRMLS_CC);
+
+ for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
+ HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL));
+ zend_hash_move_forward(&phar->virtual_dirs)) {
+
+ if (!entry->is_deleted &&
+ key_len > path_len &&
+ memcmp(key, resource->path+1, path_len) == 0 &&
+ IS_SLASH(key[path_len])) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
+ if (entry->is_temp_dir) {
+ efree(entry->filename);
+ efree(entry);
+ }
+ php_url_free(resource);
+ return 0;
+ }
+ }
+
+ if (entry->is_temp_dir) {
+ zend_hash_del(&phar->virtual_dirs, resource->path+1, path_len);
+ efree(entry->filename);
+ efree(entry);
+ } else {
+ entry->is_deleted = 1;
+ entry->is_modified = 1;
+ phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
+
+ if (error) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
+ php_url_free(resource);
+ efree(error);
+ return 0;
+ }
+ }
+
php_url_free(resource);
- return SUCCESS;
+ return 1;
}
/* }}} */
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index ac370af532..9fe9e05189 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -431,13 +431,11 @@ void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */
if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
php_stream_close(idata->fp);
}
- phar_delete_virtual_dirs(idata->phar, idata->internal_file->filename, idata->internal_file->filename_len TSRMLS_CC);
zend_hash_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
idata->phar->refcount--;
efree(idata);
} else {
idata->internal_file->is_deleted = 1;
- phar_delete_virtual_dirs(idata->phar, idata->internal_file->filename, idata->internal_file->filename_len TSRMLS_CC);
phar_entry_delref(idata TSRMLS_CC);
}
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index e2e415eeab..12a3a5a32c 100755
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -582,7 +582,6 @@ char *phar_decompress_filter(phar_entry_info * entry, int return_unknown);
char *phar_compress_filter(phar_entry_info * entry, int return_unknown);
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC);
-void phar_delete_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC);
int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC);
char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC);
char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC);
diff --git a/ext/phar/stream.c b/ext/phar/stream.c
index f70af7143e..fe863fd1a5 100644
--- a/ext/phar/stream.c
+++ b/ext/phar/stream.c
@@ -620,14 +620,16 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
char *str_key;
ulong unused;
uint keylen;
+ HashPosition pos;
- zend_hash_internal_pointer_reset(&phar->mounted_dirs);
- while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
- if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
+ zend_hash_internal_pointer_reset_ex(&phar->mounted_dirs, &pos);
+ while (FAILURE != zend_hash_has_more_elements_ex(&phar->mounted_dirs, &pos)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, &pos)) {
break;
}
PHAR_STR(key, str_key);
if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
+ zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
continue;
} else {
char *test;
@@ -644,6 +646,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
efree(test);
+ zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
continue;
}
/* mount the file/directory just in time */
@@ -752,6 +755,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
phar_archive_data *phar, *pfrom, *pto;
phar_entry_info *entry;
uint host_len;
+ int is_dir = 0;
+ int is_modified = 0;
error = NULL;
@@ -872,21 +877,96 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
return 0;
}
+ is_modified = 1;
entry->is_modified = 1;
entry->filename_len = strlen(entry->filename);
+ is_dir = entry->is_dir;
+ } else {
+ is_dir = zend_hash_exists(&(phar->virtual_dirs), resource_from->path+1, strlen(resource_from->path)-1);
+ }
+
+ /* Rename directory. Update all nested paths */
+ if (is_dir) {
+ int key_type;
+ char *key, *new_key;
+ uint key_len, new_key_len;
+ ulong unused;
+ uint from_len = strlen(resource_from->path+1);
+ uint to_len = strlen(resource_to->path+1);
+
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
+ HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)) &&
+ SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry);
+ zend_hash_move_forward(&phar->manifest)) {
+
+ if (!entry->is_deleted &&
+ key_len > from_len &&
+ memcmp(key, resource_from->path+1, from_len) == 0 &&
+ IS_SLASH(key[from_len])) {
+
+ new_key_len = key_len + to_len - from_len;
+ new_key = emalloc(new_key_len+1);
+ memcpy(new_key, resource_to->path + 1, to_len);
+ memcpy(new_key + to_len, key + from_len, key_len - from_len);
+ new_key[new_key_len] = 0;
+ is_modified = 1;
+ entry->is_modified = 1;
+ efree(entry->filename);
+ entry->filename = new_key;
+ entry->filename_len = new_key_len;
+ zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL);
+ }
+ }
+
+ for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
+ HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL));
+ zend_hash_move_forward(&phar->virtual_dirs)) {
+
+ if (key_len >= from_len &&
+ memcmp(key, resource_from->path+1, from_len) == 0 &&
+ (key_len == from_len || IS_SLASH(key[from_len]))) {
+
+ new_key_len = key_len + to_len - from_len;
+ new_key = emalloc(new_key_len+1);
+ memcpy(new_key, resource_to->path + 1, to_len);
+ memcpy(new_key + to_len, key + from_len, key_len - from_len);
+ new_key[new_key_len] = 0;
+ zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, NULL);
+ efree(new_key);
+ }
+ }
+
+ for (zend_hash_internal_pointer_reset(&phar->mounted_dirs);
+ HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &key_len, &unused, 0, NULL)) &&
+ SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry);
+ zend_hash_move_forward(&phar->mounted_dirs)) {
+
+ if (key_len >= from_len &&
+ memcmp(key, resource_from->path+1, from_len) == 0 &&
+ (key_len == from_len || IS_SLASH(key[from_len]))) {
+
+ new_key_len = key_len + to_len - from_len;
+ new_key = emalloc(new_key_len+1);
+ memcpy(new_key, resource_to->path + 1, to_len);
+ memcpy(new_key + to_len, key + from_len, key_len - from_len);
+ new_key[new_key_len] = 0;
+ zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, NULL);
+ efree(new_key);
+ }
+ }
+ }
+
+ if (is_modified) {
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
if (error) {
php_url_free(resource_from);
php_url_free(resource_to);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
efree(error);
- zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
return 0;
}
-
- phar_add_virtual_dirs(phar, resource_to->path+1, strlen(resource_to->path)-1 TSRMLS_CC);
- phar_delete_virtual_dirs(phar, resource_from->path+1, strlen(resource_from->path)-1 TSRMLS_CC);
}
+
php_url_free(resource_from);
php_url_free(resource_to);
return 1;
diff --git a/ext/phar/tests/rename_dir.phpt b/ext/phar/tests/rename_dir.phpt
index 308d2e3058..0645a817d6 100644
--- a/ext/phar/tests/rename_dir.phpt
+++ b/ext/phar/tests/rename_dir.phpt
@@ -29,4 +29,4 @@ echo file_get_contents($pname . '/a/x') . "\n";
a
a
-Warning: file_get_contents(phar://%srename.phar.php/a/x): 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
+Warning: file_get_contents(phar://%srename_dir.phar.php/a/x): failed to open stream: phar error: "a/x" is not a file in phar "%srename_dir.phar.php" in %srename_dir.php on line %d
diff --git a/ext/phar/tests/rename_dir_and_mount.phpt b/ext/phar/tests/rename_dir_and_mount.phpt
new file mode 100755
index 0000000000..b74f47b91d
--- /dev/null
+++ b/ext/phar/tests/rename_dir_and_mount.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Phar: rename_dir and mount test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("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/x'] = 'a';
+$files['a/b/x'] = 'a';
+include 'files/phar_test.inc';
+include $fname;
+
+Phar::mount("$pname/a/c", dirname(__FILE__));
+
+var_dump(file_exists($pname . '/a'));
+var_dump(file_exists($pname . '/a/x'));
+var_dump(file_exists($pname . '/a/b'));
+var_dump(file_exists($pname . '/a/b/x'));
+var_dump(file_exists($pname . '/a/c'));
+var_dump(file_exists($pname . '/a/c/'.basename(__FILE__)));
+rename($pname . '/a', $pname . '/b');
+clearstatcache();
+var_dump(file_exists($pname . '/a'));
+var_dump(file_exists($pname . '/a/x'));
+var_dump(file_exists($pname . '/a/b'));
+var_dump(file_exists($pname . '/a/b/x'));
+var_dump(file_exists($pname . '/a/c'));
+var_dump(file_exists($pname . '/a/c/'.basename(__FILE__)));
+var_dump(file_exists($pname . '/b'));
+var_dump(file_exists($pname . '/b/x'));
+var_dump(file_exists($pname . '/b/b'));
+var_dump(file_exists($pname . '/b/b/x'));
+var_dump(file_exists($pname . '/b/c'));
+var_dump(file_exists($pname . '/b/c/'.basename(__FILE__)));
+?>
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/phar/tests/rmdir.phpt b/ext/phar/tests/rmdir.phpt
index f3d07362d6..ef061bf7c2 100644
--- a/ext/phar/tests/rmdir.phpt
+++ b/ext/phar/tests/rmdir.phpt
@@ -19,12 +19,17 @@ include 'files/phar_test.inc';
include $fname;
echo file_get_contents($pname . '/a/x') . "\n";
-rmdir($pname . '/a');
+var_dump(rmdir($pname . '/a'));
echo file_get_contents($pname . '/a/x') . "\n";
+unlink($pname . '/a/x');
+var_dump(rmdir($pname . '/a'));
?>
--CLEAN--
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
--EXPECTF--
a
-Warning: file_get_contents(phar://%srename.phar.php/a/x): 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
+Warning: rmdir(): phar error: Directory not empty in %srmdir.php on line 14
+bool(false)
+a
+bool(true)
diff --git a/ext/phar/tests/tar/rename_dir.phpt b/ext/phar/tests/tar/rename_dir.phpt
index 4f94ef43b4..0b9578945a 100644
--- a/ext/phar/tests/tar/rename_dir.phpt
+++ b/ext/phar/tests/tar/rename_dir.phpt
@@ -39,4 +39,4 @@ echo file_get_contents($alias . '/a/x') . "\n";
a
a
-Warning: file_get_contents(phar://%srename.phar.tar/a/x): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.tar" in %srename.php on line %d
+Warning: file_get_contents(phar://%srename_dir.phar.tar/a/x): failed to open stream: phar error: "a/x" is not a file in phar "%srename_dir.phar.tar" in %srename_dir.php on line %d
diff --git a/ext/phar/tests/tar/rmdir.phpt b/ext/phar/tests/tar/rmdir.phpt
index 972dea8c32..d08e521614 100644
--- a/ext/phar/tests/tar/rmdir.phpt
+++ b/ext/phar/tests/tar/rmdir.phpt
@@ -29,12 +29,17 @@ $tar->close();
include $fname;
echo file_get_contents($alias . '/a/x') . "\n";
-rmdir($alias . '/a');
+var_dump(rmdir($alias . '/a'));
echo file_get_contents($alias . '/a/x') . "\n";
+unlink($alias . '/a/x');
+var_dump(rmdir($alias . '/a'));
?>
--CLEAN--
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.tar'); ?>
--EXPECTF--
a
-Warning: file_get_contents(phar://%srename.phar.tar/a/x): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.tar" in %srename.php on line %d
+Warning: rmdir(): phar error: Directory not empty in %srmdir.php on line 24
+bool(false)
+a
+bool(true)
diff --git a/ext/phar/tests/zip/rename_dir.phpt b/ext/phar/tests/zip/rename_dir.phpt
index d88eb9b0ef..bb03c7fd66 100644
--- a/ext/phar/tests/zip/rename_dir.phpt
+++ b/ext/phar/tests/zip/rename_dir.phpt
@@ -31,4 +31,4 @@ echo file_get_contents($alias . '/a/x') . "\n";
a
a
-Warning: file_get_contents(phar://%srename.phar.zip/a/x): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.zip" in %srename.php on line %d \ No newline at end of file
+Warning: file_get_contents(phar://%srename_dir.phar.zip/a/x): failed to open stream: phar error: "a/x" is not a file in phar "%srename_dir.phar.zip" in %srename_dir.php on line %d \ No newline at end of file
diff --git a/ext/phar/tests/zip/rmdir.phpt b/ext/phar/tests/zip/rmdir.phpt
index c0c2cbffe5..149f0e8d6b 100644
--- a/ext/phar/tests/zip/rmdir.phpt
+++ b/ext/phar/tests/zip/rmdir.phpt
@@ -21,12 +21,17 @@ $phar->stopBuffering();
include $fname;
echo file_get_contents($alias . '/a/x') . "\n";
-rmdir($alias . '/a');
+var_dump(rmdir($alias . '/a'));
echo file_get_contents($alias . '/a/x') . "\n";
+unlink($alias . '/a/x');
+var_dump(rmdir($alias . '/a'));
?>
--CLEAN--
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.zip'); ?>
--EXPECTF--
a
-Warning: file_get_contents(phar://%srename.phar.zip/a/x): failed to open stream: phar error: "a" is not a file in phar "%srename.phar.zip" in %srename.php on line %d \ No newline at end of file
+Warning: rmdir(): phar error: Directory not empty in %srmdir.php on line 16
+bool(false)
+a
+bool(true)
diff --git a/ext/phar/util.c b/ext/phar/util.c
index 88913fbce7..74cebdfc28 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -1950,53 +1950,14 @@ int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signat
}
/* }}} */
-/**
- * add an empty element with a char * key to a hash table, avoiding duplicates
- *
- * This is used to get a unique listing of virtual directories within a phar,
- * for iterating over opendir()ed phar directories.
- */
-static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength) /* {{{ */
-{
- char **dummy;
-
- if (SUCCESS == zend_hash_find(ht, arKey, nKeyLength, (void **)&dummy)) {
- (*dummy)++;
- return SUCCESS;
- } else {
- char *dummy = (char*)1;
-
- return zend_hash_add(ht, arKey, nKeyLength, (char *) &dummy, sizeof(void *), NULL);
- }
-}
-/* }}} */
-
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
{
- char *s = filename;
-
- /* we use filename_len - 1 to avoid adding a virtual dir for empty directory entries */
- for (; s - filename < filename_len - 1; s++) {
- if (*s == '/') {
- phar_add_empty(&phar->virtual_dirs, filename, s - filename);
- }
- }
-}
-/* }}} */
+ char *s;
-void phar_delete_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
-{
- char *s = filename;
- char **dummy;
-
- /* we use filename_len - 1 to avoid adding a virtual dir for empty directory entries */
- for (; s - filename < filename_len - 1; s++) {
- if (*s == '/') {
- if (SUCCESS == zend_hash_find(&phar->virtual_dirs, filename, s - filename, (void **)&dummy)) {
- if (!--(*dummy)) {
- zend_hash_del(&phar->virtual_dirs, filename, s - filename);
- }
- }
+ while ((s = zend_memrchr(filename, '/', filename_len))) {
+ filename_len = s - filename;
+ if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
+ break;
}
}
}