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

Reply via email to