fix *extremely* ancient problem where phar_wrapper_stat always returned success indicating the file existed
rename phar_destroy_manifest to phar_destroy_manifest_entry
/* now for the easy part */
entry->is_deleted = 1;
+ entry->is_modified = 1;
phar_flush(phar, 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);
+ php_url_free(resource);
efree(error);
return FAILURE;
}
+ php_url_free(resource);
return SUCCESS;
}
/* }}} */
/**
* destructor for the manifest hash, frees each file's entry
*/
-void destroy_phar_manifest(void *pDest) /* {{{ */
+void destroy_phar_manifest_entry(void *pDest) /* {{{ */
{
phar_entry_info *entry = (phar_entry_info *)pDest;
TSRMLS_FETCH();
/* set up our manifest */
zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
- zend_get_hash_value, destroy_phar_manifest, 0);
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
offset = 0;
for (manifest_index = 0; manifest_index < manifest_count; manifest_index++) {
if (buffer + 4 > endbuffer) {
*pphar = mydata;
}
zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
- zend_get_hash_value, destroy_phar_manifest, 0);
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
mydata->fname_len = fname_len;
mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
mydata->alias_len = alias ? alias_len : fname_len;
entry->metadata_str.len = 0;
}
- offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len;
+ /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
+ offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0);
/* compress and rehash as necessary */
if (oldfile && !entry->is_modified) {
/* remove this from the new phar */
continue;
}
- phar_set_32(entry_buffer, entry->filename_len);
+ if (entry->is_dir) {
+ /* add 1 for trailing slash */
+ phar_set_32(entry_buffer, entry->filename_len + 1);
+ } else {
+ phar_set_32(entry_buffer, entry->filename_len);
+ }
if (4 != php_stream_write(newfile, entry_buffer, 4)
|| entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)) {
if (closeoldfile) {
}
php_stream_close(newfile);
if (error) {
- spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname);
+ spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname);
}
return EOF;
}
phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp,
char **error, int for_write TSRMLS_DC);
int phar_parse_metadata(char **buffer, zval **metadata, int is_zip TSRMLS_DC);
-void destroy_phar_manifest(void *pDest);
+void destroy_phar_manifest_entry(void *pDest);
/* tar functions in tar.c */
int phar_is_tar(char *buf);
int retval;
if ((resource = phar_open_url(wrapper, url, "r", flags TSRMLS_CC)) == NULL) {
- return -1;
+ return FAILURE;
}
/* 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, flags TSRMLS_CC, "phar error: invalid url \"%s\"", url);
- return -1;
+ return FAILURE;
}
if (strcasecmp("phar", resource->scheme)) {
php_url_free(resource);
php_stream_wrapper_log_error(wrapper, flags TSRMLS_CC, "phar error: not a phar url \"%s\"", url);
- return -1;
+ return FAILURE;
}
host_len = strlen(resource->host);
spprintf(&internal_file, 0, "%s%s", plain_map, resource->path);
retval = php_stream_stat_path_ex(internal_file, flags, ssb, context);
if (retval == -1) {
- php_stream_wrapper_log_error(wrapper, 0/* TODO:options */ TSRMLS_CC, "phar error: file \"%s\" extracted from \"%s\" could not be opened", internal_file, resource->host);
+ php_stream_wrapper_log_error(wrapper, 0/* TODO:options */ TSRMLS_CC, "phar error: file \"%s\" extracted from \"%s\" could not be stated", internal_file, resource->host);
}
php_url_free(resource);
efree(internal_file);
php_stream_wrapper_log_error(wrapper, flags TSRMLS_CC, error);
efree(error);
}
- return 0;
+ return SUCCESS;
}
if (error) {
efree(error);
/* root directory requested */
phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
- return 0;
+ return SUCCESS;
}
if (!phar->manifest.arBuckets) {
php_url_free(resource);
- return 0;
+ return SUCCESS;
}
/* search through the manifest of files, and if we have an exact match, it's a file */
if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry)) {
phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
} else {
/* search for directory (partial match of a file) */
zend_hash_internal_pointer_reset(&phar->manifest);
/* directory found, all dirs have the same stat */
if (key[strlen(internal_file)] == '/') {
phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
- break;
+ php_url_free(resource);
+ return SUCCESS;
}
}
}
}
php_url_free(resource);
- return 0;
+ return FAILURE;
}
/* }}} */
myphar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data));
zend_hash_init(&myphar->manifest, sizeof(phar_entry_info),
- zend_get_hash_value, destroy_phar_manifest, 0);
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
myphar->is_tar = 1;
entry.is_tar = 1;
--TEST--
-Phar: mkdir test
+Phar: mkdir/rmdir test
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--INI--
<?php
$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
$pname = 'phar://' . $fname;
+$fname2 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.1.phar.php';
+$pname2 = 'phar://' . $fname2;
+$fname3 = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.2.phar.php';
+$pname3 = 'phar://' . $fname3;
$phar = new Phar($fname);
$phar['test/'] = '';
var_dump($phar['test']->isDir());
var_dump($phar['test/']->isDir());
+copy($fname, $fname2);
mkdir($pname . '/another/dir/');
var_dump($phar['another/dir']->isDir());
+rmdir($pname . '/another/dir/');
+copy($fname, $fname3);
+clearstatcache();
+var_dump(file_exists($pname . '/another/dir/'));
+var_dump(file_exists($pname2 . '/test/'));
+var_dump(file_exists($pname3 . '/another/dir/'));
?>
--CLEAN--
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.1.phar.php'); ?>
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php'); ?>
--EXPECT--
bool(true)
bool(true)
bool(true)
+bool(false)
+bool(true)
+bool(false)
}
/* set up our manifest */
zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
- zend_get_hash_value, destroy_phar_manifest, 0);
+ zend_get_hash_value, destroy_phar_manifest_entry, 0);
entry.phar = mydata;
entry.is_zip = 1;
/* prevent CRC checking */