From: Dmitry Stogov Date: Sun, 20 Jul 2008 14:42:34 +0000 (+0000) Subject: Fixed directory reanming/deletion X-Git-Tag: php-5.3.0alpha1~265 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=68537af530b380d203fbd4bc388ce4c7bc779db6;p=php Fixed directory reanming/deletion --- 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-- + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +"; + +$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-- + +--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-- --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-- --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-- --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; } } }