From: Greg Beaver Date: Sun, 21 Jan 2007 06:30:55 +0000 (+0000) Subject: implement reading meta-data from phars. writing is not yet supported X-Git-Tag: RELEASE_1_0_0RC1~180 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5bbd10296c7ac8affd0690df97ccb5d2f26e1aaa;p=php implement reading meta-data from phars. writing is not yet supported --- diff --git a/ext/phar/TODO b/ext/phar/TODO index e1e7f6bb6c..517fee55dd 100644 --- a/ext/phar/TODO +++ b/ext/phar/TODO @@ -4,8 +4,9 @@ Version 1.0.0 X implement ini handler for phar.readonly and phar.require_hash that allows enabling it on PHP_INI_ALL if it is disabled in the system, but does not allow disabling it if it is enabled in the system [Greg] - * implement metadata in manifest as [type32][len16][metadata...] where 0 type is - used to finish metadata for this file + X implement reading in metadata in manifest as [type32][len16][metadata...] where 0 type is + used to finish metadata for this file [Greg] + * implement writing out of metadata to new manifest * if SPL is disabled, disable the Phar class * implement in-phar locking, so that a file that is opened for reading can't have a handle opened for writing diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 6d8eabc246..9c991b312e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -76,9 +76,10 @@ #define PHAR_METADATA_FINISHED 0x00000000 -/* #define PHAR_METADATA_WHATEVER 0x000000001 - We don't need anything yet, so put this here - in order to remember how it works */ +/* basic meta-data types */ +#define PHAR_METADATA_STRING 0x00000001 +#define PHAR_METADATA_INT 0x00000002 +#define PHAR_METADATA_BOOL 0x00000003 /* flags byte for each file adheres to these bitmasks. All unused values are reserved */ @@ -191,6 +192,7 @@ typedef struct _phar_entry_info { php_uint32 crc32; php_uint32 flags; /* remainder */ + zval *metadata; php_uint32 filename_len; char *filename; long offset_within_phar; @@ -391,6 +393,10 @@ static void destroy_phar_manifest(void *pDest) /* {{{ */ if (entry->temp_file) { php_stream_close(entry->temp_file); } + if (entry->metadata) { + zval_dtor(entry->metadata); + entry->metadata = 0; + } efree(entry->filename); } /* }}} */ @@ -591,15 +597,22 @@ PHP_METHOD(Phar, canWrite) #ifdef WORDS_BIGENDIAN # define PHAR_GET_32(buffer, var) \ - var = ((unsigned char)buffer[3]) << 24 \ - + ((unsigned char)buffer[2]) << 16 \ - + ((unsigned char)buffer[1]) << 8 \ - + ((unsigned char)buffer[0]); \ - buffer += 4 + var = ((unsigned char)(buffer)[3]) << 24 \ + + ((unsigned char)(buffer)[2]) << 16 \ + + ((unsigned char)(buffer)[1]) << 8 \ + + ((unsigned char)(buffer)[0]); \ + (buffer) += 4 +# define PHAR_GET_16(buffer, var) \ + var = ((unsigned char)(buffer)[1]) << 8 \ + + ((unsigned char)(buffer)[0]); \ + (buffer) += 2 #else # define PHAR_GET_32(buffer, var) \ var = *(php_uint32*)(buffer); \ buffer += 4 +# define PHAR_GET_16(buffer, var) \ + var = *(php_uint16*)(buffer); \ + buffer += 2 #endif /** @@ -628,6 +641,50 @@ static int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_l } /* }}}*/ +/** + * Parse out metadata from the manifest for a single file + * + * Meta-data is in this format: + * [type32][len16][data...] + * + * where type32 is a 32-bit type indicator, len16 is a 16-bit length indicator, + * and data is the actual meta-data. + */ +static int phar_parse_metadata(php_stream *fp, char **buffer, char *endbuffer, zval *metadata TSRMLS_DC) /* {{{ */ +{ + zval *dataarray, *found; + php_uint32 datatype; + php_uint16 len; + char *data; + do { + /* for each meta-data, add an array index to the metadata array + if the index already exists, convert to a sub-array */ + PHAR_GET_32(*buffer, datatype); + PHAR_GET_16(*buffer, len); + data = (char *) emalloc(len); + if (len != php_stream_read(fp, data, (size_t) len) TSRMLS_CC) { + return FAILURE; + } + if (SUCCESS == zend_hash_index_find(metadata->value.ht, datatype, (void**)&found)) { + if (Z_TYPE_P(found) == IS_ARRAY) { + add_next_index_stringl(dataarray, data, len, 0); + } else { + MAKE_STD_ZVAL(dataarray); + array_init(dataarray); + add_next_index_zval(dataarray, found); + add_next_index_stringl(dataarray, data, len, 0); + } + } else { + MAKE_STD_ZVAL(dataarray); + add_index_stringl(metadata, datatype, data, len, 0); + } + + } while (*(php_uint32 *) *buffer && *buffer < endbuffer); + *buffer += 4; + return SUCCESS; +} +/* }}}*/ + /** * Does not check for a previously opened phar in the cache. * @@ -912,6 +969,13 @@ static int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alia PHAR_GET_32(buffer, entry.compressed_filesize); PHAR_GET_32(buffer, entry.crc32); PHAR_GET_32(buffer, entry.flags); + if (*(php_uint32 *) buffer) { + MAKE_STD_ZVAL(entry.metadata); + array_init(entry.metadata); + phar_parse_metadata(fp, &buffer, endbuffer, entry.metadata TSRMLS_CC); + } else { + buffer += 4; + } entry.offset_within_phar = offset; offset += entry.compressed_filesize; switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) { @@ -1518,7 +1582,7 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat /* Unfortunately we cannot check the read position of fp after getting */ /* uncompressed data because the new stream posiition is being changed */ /* by the number of bytes read throughthe filter not by the raw number */ - /* bytes being consumed on the stream. Therefor use a consumed filter. */ + /* bytes being consumed on the stream. Therefore use a consumed filter. */ consumed = php_stream_filter_create("consumed", NULL, php_stream_is_persistent(fp) TSRMLS_CC); php_stream_filter_append(&fp->readfilters, consumed); php_stream_filter_append(&fp->readfilters, filter); @@ -1781,7 +1845,7 @@ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ phar_entry_info *entry; int alias_len, fname_len, halt_offset, restore_alias_len, global_flags = 0; char *fname, *alias; - char manifest[18], entry_buffer[20]; + char manifest[18], entry_buffer[24]; off_t manifest_ftell; long offset; php_uint32 copy, loc, new_manifest_count; @@ -1971,6 +2035,7 @@ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ 4: compressed filesize 4: crc32 4: flags + 4+: metadata TODO: copy the actual metadata, 0 for now */ copy = time(NULL); phar_set_32(entry_buffer, entry->uncompressed_filesize); @@ -1978,6 +2043,8 @@ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ phar_set_32(entry_buffer+8, entry->compressed_filesize); phar_set_32(entry_buffer+12, entry->crc32); phar_set_32(entry_buffer+16, entry->flags); + copy = 0; + phar_set_32(entry_buffer+20, 0); if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))) { if (oldfile) { php_stream_close(oldfile); diff --git a/ext/phar/tests/010.phpt b/ext/phar/tests/010.phpt index 008bdc8fee..dd905edada 100644 --- a/ext/phar/tests/010.phpt +++ b/ext/phar/tests/010.phpt @@ -12,7 +12,7 @@ __HALT_COMPILER(); ?>"; // this fails because the manifest length does not include the other 10 byte manifest data -$manifest = pack('V', 1) . 'a' . pack('VVVVV', 0, time(), 0, crc32(''), 0x00000000); +$manifest = pack('V', 1) . 'a' . pack('VVVVVV', 0, time(), 0, crc32(''), 0x00000000, 0); $file .= pack('VVnVV', strlen($manifest), 1, 0x0900, 0x00000000, 3) . 'hio' . $manifest; file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); diff --git a/ext/phar/tests/011.phpt b/ext/phar/tests/011.phpt index 1ff2a32f97..009d51d4e7 100644 --- a/ext/phar/tests/011.phpt +++ b/ext/phar/tests/011.phpt @@ -17,7 +17,7 @@ $files['a'] = 'a'; $manifest = ''; foreach($files as $name => $cont) { $len = strlen($cont); - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', $len, time(), $len+1, crc32($cont), 0x00000000); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', $len, time(), $len+1, crc32($cont), 0x00000000, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00000000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/013.phpt b/ext/phar/tests/013.phpt index 3327e53db9..808d37462a 100644 --- a/ext/phar/tests/013.phpt +++ b/ext/phar/tests/013.phpt @@ -18,7 +18,7 @@ $files['a'] = 'a'; $manifest = ''; foreach($files as $name => $cont) { $len = strlen($cont)+1; - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', $len, time(), $len, crc32($cont), 0x00000000); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', $len, time(), $len, crc32($cont), 0x00000000, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00000000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/014.phpt b/ext/phar/tests/014.phpt index ea27faaf7e..2117eaaff9 100644 --- a/ext/phar/tests/014.phpt +++ b/ext/phar/tests/014.phpt @@ -16,7 +16,7 @@ $files['a'] = 'a'; $manifest = ''; foreach($files as $name => $cont) { $len = strlen($cont); - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', $len, time(), $len, crc32($cont.'X'), 0x00000000); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', $len, time(), $len, crc32($cont.'X'), 0x00000000, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00000000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/015.phpt b/ext/phar/tests/015.phpt index 240537bcf8..4d5477c557 100644 --- a/ext/phar/tests/015.phpt +++ b/ext/phar/tests/015.phpt @@ -16,7 +16,7 @@ $files['a'] = 'a'; $manifest = ''; foreach($files as $name => $cont) { $len = strlen($cont); - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', $len, time(), 3, crc32($cont), 0x00001000); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', $len, time(), 3, crc32($cont), 0x00001000, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00001000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/015b.phpt b/ext/phar/tests/015b.phpt index 1cccdd613c..1909da6a82 100755 --- a/ext/phar/tests/015b.phpt +++ b/ext/phar/tests/015b.phpt @@ -15,7 +15,7 @@ $files = array(); $files['a'] = array('Hello World', pack('H*', '425a6839314159265359d872012f00000157800010400000400080060490002000220686d420c988c769e8281f8bb9229c28486c39009780')); $manifest = ''; foreach($files as $name => $cont) { - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', strlen($cont[0]), time(), strlen($cont[1]), crc32($cont[0]), 0x00002000); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', strlen($cont[0]), time(), strlen($cont[1]), crc32($cont[0]), 0x00002000, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00002000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/016.phpt b/ext/phar/tests/016.phpt index e4d944104d..929e21a1f3 100644 --- a/ext/phar/tests/016.phpt +++ b/ext/phar/tests/016.phpt @@ -22,7 +22,7 @@ foreach($files as $name => $cont) { $ulen = strlen($cont[0]); $clen = strlen($cont[1]); $manifest .= pack('V', strlen($name)) . $name - . pack('VVVVV', $ulen, time(), $clen, crc32($cont[0]), $cont[2]); + . pack('VVVVVV', $ulen, time(), $clen, crc32($cont[0]), $cont[2], 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00001000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/016b.phpt b/ext/phar/tests/016b.phpt index a58c8bbfd6..ae5ec5fded 100755 --- a/ext/phar/tests/016b.phpt +++ b/ext/phar/tests/016b.phpt @@ -17,7 +17,7 @@ $files['a'] = 'a'; $manifest = ''; foreach($files as $name => $cont) { $len = strlen($cont); - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', $len, time(), 1, crc32($cont), 0x00001000); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', $len, time(), 1, crc32($cont), 0x00001000, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00001000, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/017.phpt b/ext/phar/tests/017.phpt index 197649d451..b3332bb6dc 100644 --- a/ext/phar/tests/017.phpt +++ b/ext/phar/tests/017.phpt @@ -16,7 +16,7 @@ $files['a'] = 'abc'; $manifest = ''; foreach($files as $name => $cont) { $len = strlen($cont); - $manifest .= pack('V', strlen($name)) . $name . pack('VVVVV', $len, time(), $len, crc32($cont), 0x00000001); + $manifest .= pack('V', strlen($name)) . $name . pack('VVVVVV', $len, time(), $len, crc32($cont), 0x00000001, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00000001, strlen($alias)) . $alias . $manifest; diff --git a/ext/phar/tests/phar_test.inc b/ext/phar/tests/phar_test.inc index 6f85bfd418..9f887dceb5 100755 --- a/ext/phar/tests/phar_test.inc +++ b/ext/phar/tests/phar_test.inc @@ -8,7 +8,7 @@ foreach($files as $name => $cont) $clen = $ulen; $time = isset($ftime) ? $ftime : @mktime(12, 0, 0, 3, 1, 2006); $manifest .= pack('V', strlen($name)) . $name; - $manifest .= pack('VVVVV', $ulen, $time, $clen, crc32($cont), 0x000001B6); + $manifest .= pack('VVVVVV', $ulen, $time, $clen, crc32($cont), 0x000001B6, 0); } $alias = 'hio'; $manifest = pack('VnVV', count($files), 0x0900, 0x00000000, strlen($alias)) . $alias . $manifest;