cellog Thu May 15 23:46:32 2008 UTC
Modified files:
/php-src/ext/phar phar_object.c tar.c
/php-src/ext/phar/tests badparameters.phpt
pharfileinfo_setmetadata.phpt
Log:
MFB: add full metadata support for tar-based archives and test
http://cvs.php.net/viewvc.cgi/php-src/ext/phar/phar_object.c?r1=1.269&r2=1.270&diff_format=u
Index: php-src/ext/phar/phar_object.c
diff -u php-src/ext/phar/phar_object.c:1.269
php-src/ext/phar/phar_object.c:1.270
--- php-src/ext/phar/phar_object.c:1.269 Thu May 15 16:09:21 2008
+++ php-src/ext/phar/phar_object.c Thu May 15 23:46:32 2008
@@ -17,7 +17,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: phar_object.c,v 1.269 2008/05/15 16:09:21 cellog Exp $ */
+/* $Id: phar_object.c,v 1.270 2008/05/15 23:46:32 cellog Exp $ */
#include "phar_internal.h"
#include "func_interceptors.h"
@@ -1999,6 +1999,7 @@
newentry.tmp = estrdup(newentry.tmp);
goto no_copy;
}
+ newentry.metadata_str.c = 0;
if (FAILURE == phar_copy_file_contents(&newentry, phar->fp
TSRMLS_CC)) {
zend_hash_destroy(&(phar->manifest));
php_stream_close(phar->fp);
@@ -3537,11 +3538,7 @@
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC, "Write operations disabled by INI setting");
return;
}
- if (phar_obj->arc.archive->is_tar) {
- zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC,
- "Cannot set metadata, not possible with tar-based phar
archives");
- return;
- }
+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) ==
FAILURE) {
return;
}
@@ -3553,6 +3550,7 @@
MAKE_STD_ZVAL(phar_obj->arc.archive->metadata);
ZVAL_ZVAL(phar_obj->arc.archive->metadata, metadata, 1, 0);
+ phar_obj->arc.archive->is_modified = 1;
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
if (error) {
@@ -3574,14 +3572,11 @@
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC, "Write operations disabled by INI setting");
return;
}
- if (phar_obj->arc.archive->is_tar) {
- zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC,
- "Cannot delete metadata, not possible with tar-based
phar archives");
- return;
- }
+
if (phar_obj->arc.archive->metadata) {
zval_ptr_dtor(&phar_obj->arc.archive->metadata);
phar_obj->arc.archive->metadata = NULL;
+ phar_obj->arc.archive->is_modified = 1;
phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC);
if (error) {
@@ -4117,11 +4112,6 @@
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC, "Write operations disabled by phar.readonly INI setting");
return;
}
- if (entry_obj->ent.entry->is_tar) {
- zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC,
- "Cannot set metadata, not possible with tar-based phar
archives");
- return;
- }
if (entry_obj->ent.entry->is_temp_dir) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC, \
"Phar entry is a temporary directory (not an actual
entry in the archive), cannot set metadata"); \
@@ -4139,6 +4129,8 @@
MAKE_STD_ZVAL(entry_obj->ent.entry->metadata);
ZVAL_ZVAL(entry_obj->ent.entry->metadata, metadata, 1, 0);
+ entry_obj->ent.entry->is_modified = 1;
+ entry_obj->ent.entry->phar->is_modified = 1;
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error TSRMLS_CC);
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC,
error);
@@ -4159,11 +4151,6 @@
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC, "Write operations disabled by phar.readonly INI setting");
return;
}
- if (entry_obj->ent.entry->is_tar) {
- zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC,
- "Cannot delete metadata, not possible with tar-based
phar archives");
- return;
- }
if (entry_obj->ent.entry->is_temp_dir) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0
TSRMLS_CC, \
"Phar entry is a temporary directory (not an actual
entry in the archive), cannot delete metadata"); \
@@ -4172,6 +4159,8 @@
if (entry_obj->ent.entry->metadata) {
zval_ptr_dtor(&entry_obj->ent.entry->metadata);
entry_obj->ent.entry->metadata = NULL;
+ entry_obj->ent.entry->is_modified = 1;
+ entry_obj->ent.entry->phar->is_modified = 1;
phar_flush(entry_obj->ent.entry->phar, 0, 0, 0, &error
TSRMLS_CC);
if (error) {
http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tar.c?r1=1.55&r2=1.56&diff_format=u
Index: php-src/ext/phar/tar.c
diff -u php-src/ext/phar/tar.c:1.55 php-src/ext/phar/tar.c:1.56
--- php-src/ext/phar/tar.c:1.55 Mon May 12 20:42:06 2008
+++ php-src/ext/phar/tar.c Thu May 15 23:46:32 2008
@@ -152,6 +152,40 @@
return FAILURE;
}
+int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
+{
+ char *metadata;
+ size_t save = php_stream_tell(fp), read;
+ phar_entry_info *mentry;
+
+ metadata = (char *) emalloc(entry->uncompressed_filesize + 1);
+
+ read = php_stream_read(fp, metadata, entry->uncompressed_filesize);
+ if (read != entry->uncompressed_filesize) {
+ efree(metadata);
+ php_stream_seek(fp, save, SEEK_SET);
+ return FAILURE;
+ }
+
+ if (phar_parse_metadata(&metadata, &entry->metadata,
entry->uncompressed_filesize TSRMLS_CC) == FAILURE) {
+ /* if not valid serialized data, it is a regular string */
+ efree(metadata);
+ php_stream_seek(fp, save, SEEK_SET);
+ return FAILURE;
+ }
+ if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 &&
!memcmp(entry->filename, ".phar/.metadata.bin",
sizeof(".phar/.metadata.bin")-1)) {
+ entry->phar->metadata = entry->metadata;
+ entry->metadata = NULL;
+ } else if (entry->filename_len >= sizeof(".phar/.metadata/") +
sizeof("/.metadata.bin") - 1 && SUCCESS ==
zend_hash_find(&(entry->phar->manifest), entry->filename +
sizeof(".phar/.metadata/") - 1, entry->filename_len - (sizeof("/.metadata.bin")
- 1 + sizeof(".phar/.metadata/") - 1), (void *)&mentry)) {
+ /* transfer this metadata to the entry it refers */
+ mentry->metadata = entry->metadata;
+ entry->metadata = NULL;
+ }
+ efree(metadata);
+ php_stream_seek(fp, save, SEEK_SET);
+ return SUCCESS;
+}
+
int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
int alias_len, int options, phar_archive_data** pphar, php_uint32 compression,
char **error TSRMLS_DC) /* {{{ */
{
char buf[512], *actual_alias = NULL, *p;
@@ -192,6 +226,8 @@
entry.is_crc_checked = 1;
entry.phar = myphar;
do {
+ phar_entry_info *newentry;
+
pos += sizeof(buf);
hdr = (tar_header*) buf;
sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum));
@@ -280,7 +316,21 @@
} else if (entry.tar_type == TAR_SYMLINK) {
entry.link = estrdup(hdr->linkname);
}
- zend_hash_add(&myphar->manifest, entry.filename,
entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
+ zend_hash_add(&myphar->manifest, entry.filename,
entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **)
&newentry);
+ if (entry.filename_len >= sizeof(".phar/.metadata")-1 &&
!memcmp(entry.filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) {
+ if (FAILURE == phar_tar_process_metadata(newentry, fp
TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error:
tar-based phar \"%s\" has invalid metadata in magic file \"%s\"", fname,
entry.filename);
+ }
+ php_stream_close(fp);
+ zend_hash_destroy(&myphar->manifest);
+ myphar->manifest.arBuckets = 0;
+ zend_hash_destroy(&myphar->mounted_dirs);
+ myphar->mounted_dirs.arBuckets = 0;
+ efree(myphar);
+ return FAILURE;
+ }
+ }
if (!actual_alias && entry.filename_len ==
sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt",
sizeof(".phar/alias.txt")-1)) {
size_t read;
/* found explicit alias */
@@ -567,6 +617,87 @@
return ZEND_HASH_APPLY_KEEP;
}
+int phar_tar_setmetadata(zval *metadata, phar_entry_info *entry, char **error,
php_stream *fp TSRMLS_DC)
+{
+ php_serialize_data_t metadata_hash;
+
+ if (entry->metadata_str.c) {
+ smart_str_free(&entry->metadata_str);
+ }
+ entry->metadata_str.c = 0;
+ entry->metadata_str.len = 0;
+ PHP_VAR_SERIALIZE_INIT(metadata_hash);
+ php_var_serialize(&entry->metadata_str, &metadata, &metadata_hash
TSRMLS_CC);
+ PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
+ entry->uncompressed_filesize = entry->compressed_filesize =
entry->metadata_str.len;
+ if (entry->fp && entry->fp_type == PHAR_MOD) {
+ php_stream_close(entry->fp);
+ }
+ entry->fp_type = PHAR_MOD;
+ entry->is_modified = 1;
+ entry->fp = php_stream_fopen_tmpfile();
+ entry->offset = entry->offset_abs = 0;
+ if (entry->metadata_str.len != php_stream_write(entry->fp,
entry->metadata_str.c, entry->metadata_str.len)) {
+ spprintf(error, 0, "phar tar error: unable to write metadata to
magic metadata file \"%s\"", entry->filename);
+ zend_hash_del(&(entry->phar->manifest), entry->filename,
entry->filename_len);
+ return ZEND_HASH_APPLY_STOP;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+int phar_tar_setupmetadata(void *pDest, void *argument TSRMLS_DC)
+{
+ int lookfor_len;
+ struct _phar_pass_tar_info *i = (struct _phar_pass_tar_info *)argument;
+ char *lookfor, **error = i->error;
+ php_stream *fp = i->old;
+ phar_entry_info *entry = (phar_entry_info *)pDest, *metadata, newentry
= {0};
+
+ if (entry->filename_len >= sizeof(".phar/.metadata") &&
!memcmp(entry->filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) {
+ if (entry->filename_len == sizeof(".phar/.metadata.bin")-1 &&
!memcmp(entry->filename, ".phar/.metadata.bin",
sizeof(".phar/.metadata.bin")-1)) {
+ return phar_tar_setmetadata(entry->phar->metadata,
entry, error, fp TSRMLS_CC);
+ }
+ /* search for the file this metadata entry references */
+ if (entry->filename_len >= sizeof(".phar/.metadata/") +
sizeof("/.metadata.bin") - 1 && !zend_hash_exists(&(entry->phar->manifest),
entry->filename + sizeof(".phar/.metadata/") - 1, entry->filename_len -
(sizeof("/.metadata.bin") - 1 + sizeof(".phar/.metadata/") - 1))) {
+ /* this is orphaned metadata, erase it */
+ return ZEND_HASH_APPLY_REMOVE;
+ }
+ /* we can keep this entry, the file that refers to it exists */
+ return ZEND_HASH_APPLY_KEEP;
+ }
+
+ if (!entry->is_modified) {
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ /* now we are dealing with regular files, so look for metadata */
+ lookfor_len = spprintf(&lookfor, 0, ".phar/.metadata/%s/.metadata.bin",
entry->filename);
+ if (!entry->metadata) {
+ zend_hash_del(&(entry->phar->manifest), lookfor, lookfor_len);
+ efree(lookfor);
+ return ZEND_HASH_APPLY_KEEP;
+ }
+ if (SUCCESS == zend_hash_find(&(entry->phar->manifest), lookfor,
lookfor_len, (void **)&metadata)) {
+ int ret;
+ ret = phar_tar_setmetadata(entry->metadata, metadata, error, fp
TSRMLS_CC);
+ efree(lookfor);
+ return ret;
+ }
+
+ newentry.filename = lookfor;
+ newentry.filename_len = lookfor_len;
+ newentry.phar = entry->phar;
+ newentry.tar_type = TAR_FILE;
+ newentry.is_tar = 1;
+
+ if (SUCCESS != zend_hash_add(&(entry->phar->manifest), lookfor,
lookfor_len, (void *)&newentry, sizeof(phar_entry_info), (void **)&metadata)) {
+ efree(lookfor);
+ spprintf(error, 0, "phar tar error: unable to add magic
metadata file to manifest for file \"%s\"", entry->filename);
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ return phar_tar_setmetadata(entry->metadata, metadata, error, fp
TSRMLS_CC);
+}
+
int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int
defaultstub, char **error TSRMLS_DC) /* {{{ */
{
phar_entry_info entry = {0};
@@ -739,6 +870,51 @@
pass.free_fp = 1;
pass.free_ufp = 1;
+ if (phar->metadata) {
+ phar_entry_info *mentry;
+ if (SUCCESS == zend_hash_find(&(phar->manifest),
".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1, (void **)&mentry)) {
+ if (ZEND_HASH_APPLY_KEEP !=
phar_tar_setmetadata(phar->metadata, mentry, error, oldfile TSRMLS_CC)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+ } else {
+ phar_entry_info newentry = {0};
+
+ newentry.filename = estrndup(".phar/.metadata.bin",
sizeof(".phar/.metadata.bin")-1);
+ newentry.filename_len = sizeof(".phar/.metadata.bin")-1;
+ newentry.phar = phar;
+ newentry.tar_type = TAR_FILE;
+ newentry.is_tar = 1;
+
+ if (SUCCESS != zend_hash_add(&(phar->manifest),
".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1, (void *)&newentry,
sizeof(phar_entry_info), (void **)&mentry)) {
+ spprintf(error, 0, "phar tar error: unable to
add magic metadata file to manifest for phar archive \"%s\"", phar->fname);
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+ if (ZEND_HASH_APPLY_KEEP !=
phar_tar_setmetadata(phar->metadata, mentry, error, oldfile TSRMLS_CC)) {
+ zend_hash_del(&(phar->manifest),
".phar/.metadata.bin", sizeof(".phar/.metadata.bin")-1);
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ return EOF;
+ }
+ }
+ }
+ zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t)
phar_tar_setupmetadata, (void *) &pass TSRMLS_CC);
+
+ if (error && *error) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+ /* on error in the hash iterator above, error is set */
+ php_stream_close(newfile);
+ return EOF;
+ }
+
zend_hash_apply_with_argument(&phar->manifest, (apply_func_arg_t)
phar_tar_writeheaders, (void *) &pass TSRMLS_CC);
/* add final zero blocks */
http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/badparameters.phpt?r1=1.3&r2=1.4&diff_format=u
Index: php-src/ext/phar/tests/badparameters.phpt
diff -u php-src/ext/phar/tests/badparameters.phpt:1.3
php-src/ext/phar/tests/badparameters.phpt:1.4
--- php-src/ext/phar/tests/badparameters.phpt:1.3 Tue Apr 29 12:06:53 2008
+++ php-src/ext/phar/tests/badparameters.phpt Thu May 15 23:46:32 2008
@@ -123,11 +123,6 @@
} catch (Exception $e) {
echo $e->getMessage() . "\n";
}
-try {
-$b->setMetadata('a');
-} catch (Exception $e) {
-echo $e->getMessage() . "\n";
-}
ini_set('phar.readonly', 0);
$a->setMetadata(1,2);
ini_set('phar.readonly', 1);
@@ -136,11 +131,6 @@
} catch (Exception $e) {
echo $e->getMessage() . "\n";
}
-try {
-$b->delMetadata();
-} catch (Exception $e) {
-echo $e->getMessage() . "\n";
-}
?>
===DONE===
--EXPECTF--
@@ -202,9 +192,7 @@
Warning: Phar::addFromString() expects exactly 2 parameters, 1 given in
%sbadparameters.php on line %d
Write operations disabled by INI setting
-Cannot set metadata, not possible with tar-based phar archives
Warning: Phar::setMetadata() expects exactly 1 parameter, 2 given in
%sbadparameters.php on line %d
Write operations disabled by INI setting
-Cannot delete metadata, not possible with tar-based phar archives
===DONE===
http://cvs.php.net/viewvc.cgi/php-src/ext/phar/tests/pharfileinfo_setmetadata.phpt?r1=1.1&r2=1.2&diff_format=u
Index: php-src/ext/phar/tests/pharfileinfo_setmetadata.phpt
diff -u php-src/ext/phar/tests/pharfileinfo_setmetadata.phpt:1.1
php-src/ext/phar/tests/pharfileinfo_setmetadata.phpt:1.2
--- php-src/ext/phar/tests/pharfileinfo_setmetadata.phpt:1.1 Fri Apr 25
16:05:04 2008
+++ php-src/ext/phar/tests/pharfileinfo_setmetadata.phpt Thu May 15
23:46:32 2008
@@ -16,16 +16,6 @@
$b = $phar['a/b'];
try {
-$tar['a/b']->setMetadata('hi');
-} catch (Exception $e) {
-echo $e->getMessage(), "\n";
-}
-try {
-$tar['a/b']->delMetadata();
-} catch (Exception $e) {
-echo $e->getMessage(), "\n";
-}
-try {
$phar['a']->setMetadata('hi');
} catch (Exception $e) {
echo $e->getMessage(), "\n";
@@ -54,8 +44,6 @@
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') .
'.phar'); ?>
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') .
'.tar'); ?>
--EXPECTF--
-Cannot set metadata, not possible with tar-based phar archives
-Cannot delete metadata, not possible with tar-based phar archives
Phar entry is a temporary directory (not an actual entry in the archive),
cannot set metadata
Phar entry is a temporary directory (not an actual entry in the archive),
cannot delete metadata
Write operations disabled by phar.readonly INI setting
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php