From: Greg Beaver Date: Thu, 3 Jan 2008 04:45:00 +0000 (+0000) Subject: initial tar support - a few kinks to work on in phar creation, but read works X-Git-Tag: RELEASE_2_0_0a1~1055 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8ee4266b3fae9ef42e9d62a22ebc1569044235ed;p=php initial tar support - a few kinks to work on in phar creation, but read works --- diff --git a/ext/phar/config.m4 b/ext/phar/config.m4 index 5de8145b07..2e262516ab 100644 --- a/ext/phar/config.m4 +++ b/ext/phar/config.m4 @@ -32,7 +32,7 @@ if test "$PHP_PHAR" != "no"; then else AC_MSG_RESULT([no]) fi - PHP_NEW_EXTENSION(phar, phar.c phar_object.c phar_path_check.c $PHP_PHAR_SOURCES, $ext_shared) + PHP_NEW_EXTENSION(phar, tar.c phar.c phar_object.c phar_path_check.c $PHP_PHAR_SOURCES, $ext_shared) PHP_ADD_BUILD_DIR($ext_builddir/lib, 1) PHP_SUBST(PHAR_SHARED_LIBADD) PHP_ADD_EXTENSION_DEP(phar, zlib, true) diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 43e66b54c6..e54ba6d213 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -298,7 +298,7 @@ static void destroy_phar_data(void *pDest) /* {{{ */ /** * destructor for the manifest hash, frees each file's entry */ -static void destroy_phar_manifest(void *pDest) /* {{{ */ +void destroy_phar_manifest(void *pDest) /* {{{ */ { phar_entry_info *entry = (phar_entry_info *)pDest; TSRMLS_FETCH(); @@ -328,6 +328,10 @@ static void destroy_phar_manifest(void *pDest) /* {{{ */ entry->zip = 0; } #endif + if (entry->linkname) { + efree(entry->linkname); + entry->linkname = 0; + } } /* }}} */ @@ -493,7 +497,7 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info)); entry->is_dir = 1; /* this next line tells PharFileInfo->__destruct() to efree the filename */ - entry->is_zip = 0; + entry->is_zip = entry->is_tar = 0; entry->filename = (char *) estrndup(path, path_len + 1); entry->filename_len = path_len; return entry; @@ -624,6 +628,7 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char (*ret)->for_write = for_write; (*ret)->internal_file = entry; (*ret)->is_zip = entry->is_zip; + (*ret)->is_tar = entry->is_tar; if (entry->fp) { /* make a copy */ if (for_trunc) { @@ -1646,9 +1651,6 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int } /* }}} */ -/* forward declaration */ -static int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); - /** * Create or open a phar for writing */ @@ -1734,7 +1736,7 @@ int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int al } if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar, 0 TSRMLS_CC) == SUCCESS) { - if (!PHAR_G(readonly)) { + if (pphar && !PHAR_G(readonly)) { (*pphar)->is_writeable = 1; } return SUCCESS; @@ -1745,11 +1747,15 @@ int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int al /* assume zip-based phar */ return phar_open_or_create_zip(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); } + if (ext_len >= sizeof(".phar.tar")-1 && !memcmp((void *) ext_str, (void *) ".phar.tar", sizeof(".phar.tar")-1)) { + /* assume tar-based phar */ + return phar_open_or_create_tar(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); + } } return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); } -static int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ +int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ { phar_archive_data *mydata; char *my_realpath; @@ -1920,6 +1926,11 @@ static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, php_stream_close(fp); return phar_open_zipfile(fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC); } + if (got > 512) { + if (phar_is_tar(pos)) { + return phar_open_tarfile(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); + } + } } if ((pos = strstr(buffer, token)) != NULL) { halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */ @@ -1940,6 +1951,8 @@ int phar_detect_phar_fname_ext(const char *filename, int check_length, char **ex char *pos_p = strstr(filename, ".phar.php"); char *pos_zi = strstr(filename, ".phar.zip"); char *pos_zi2 = strstr(filename, ".phar.zip.php"); + char *pos_t = strstr(filename, ".phar.tar"); + char *pos_t2 = strstr(filename, ".phar.tar.php"); char *pos_z = strstr(filename, ".phar.gz"); char *pos_b = strstr(filename, ".phar.bz2"); @@ -1961,6 +1974,12 @@ int phar_detect_phar_fname_ext(const char *filename, int check_length, char **ex } else if (pos_zi) { *ext_str = pos_zi; *ext_len = 9; + } else if (pos_t2) { + *ext_str = pos_t2; + *ext_len = 13; + } else if (pos_t) { + *ext_str = pos_t; + *ext_len = 9; } else if ((pos_p = strstr(filename, ".phar")) != NULL) { *ext_str = pos_p; *ext_len = 5; @@ -2292,7 +2311,7 @@ int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC) entry = fname; fname = arch; fname_len = arch_len; - if (SUCCESS == phar_open_loaded(fname, fname_len, alias, alias_len, 0, &phar, 0 TSRMLS_CC) && phar && phar->is_zip) { + if (SUCCESS == phar_open_loaded(fname, fname_len, alias, alias_len, 0, &phar, 0 TSRMLS_CC) && phar && (phar->is_zip || phar->is_tar)) { efree(arch); return SUCCESS; } @@ -3317,6 +3336,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **err return phar_zip_flush(archive, user_stub, len, error TSRMLS_CC); } #endif + if (archive->is_tar) { + return phar_tar_flush(archive, user_stub, len, error TSRMLS_CC); + } if (archive->fp && !archive->is_brandnew) { oldfile = archive->fp; closeoldfile = 0; @@ -4688,6 +4710,17 @@ static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type } goto skip_phar; } + if (strstr(file_handle->filename, ".phar.tar") && !strstr(file_handle->filename, ":\\")) { + /* zip-based phar */ + spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php"); + file_handle->type = ZEND_HANDLE_FILENAME; + file_handle->free_filename = 1; + file_handle->filename = name; + if (file_handle->opened_path) { + efree(file_handle->opened_path); + } + goto skip_phar; + } if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { char *arch, *entry; int arch_len, entry_len; @@ -4860,6 +4893,8 @@ PHP_MINFO_FUNCTION(phar) /* {{{ */ php_info_print_table_row(2, "CVS revision", "$Revision$"); php_info_print_table_row(2, "Phar-based phar archives", "enabled"); + php_info_print_table_row(2, "Tar-based phar archives", + "enabled"); #if HAVE_PHAR_ZIP php_info_print_table_row(2, "ZIP-based phar archives", "enabled"); diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index a39d7e93d5..a9ee959192 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -25,6 +25,7 @@ #include #include "php.h" +#include "tar.h" #include "php_ini.h" #include "zend_constants.h" #include "zend_execute.h" @@ -184,6 +185,10 @@ typedef struct _phar_entry_info { int is_dir:1; phar_archive_data *phar; smart_str metadata_str; + /* tar-based phar file stuff */ + int is_tar:1; + char *link; /* symbolic link to another file */ + char tar_type; /* zip-based phar file stuff */ int is_zip:1; #if HAVE_PHAR_ZIP @@ -219,6 +224,8 @@ struct _phar_archive_data { int donotflush:1; /* zip-based phar variables */ int is_zip:1; + /* tar-based phar variables */ + int is_tar:1; #if HAVE_PHAR_ZIP struct zip *zip; #endif @@ -245,6 +252,7 @@ typedef struct _phar_entry_data { off_t zero; int for_write:1; int is_zip:1; + int is_tar:1; phar_entry_info *internal_file; } phar_entry_data; @@ -283,10 +291,18 @@ void phar_object_init(TSRMLS_D); int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); +int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC); 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_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); +void destroy_phar_manifest(void *pDest); +/* tar functions */ +int phar_is_tar(char *buf); +int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); +int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC); +int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); +int phar_tar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC); #ifdef PHAR_MAIN static void phar_fopen(INTERNAL_FUNCTION_PARAMETERS); diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 8f5be1c79e..d6594b79d3 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -295,7 +295,7 @@ PHP_METHOD(Phar, webPhar) entry = fname; fname = arch; fname_len = arch_len; - if (SUCCESS == phar_open_loaded(fname, fname_len, alias, alias_len, 0, &phar, 0 TSRMLS_CC) && phar && phar->is_zip) { + if (SUCCESS == phar_open_loaded(fname, fname_len, alias, alias_len, 0, &phar, 0 TSRMLS_CC) && phar && (phar->is_zip || phar->is_tar)) { efree(arch); fname = phar->fname; fname_len = phar->fname_len; @@ -1269,7 +1269,11 @@ PHP_METHOD(Phar, setSignatureAlgorithm) if (PHAR_G(readonly)) { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, - "Cannot change stub, phar is read-only"); + "Cannot set signature algorithm, phar is read-only"); + } + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot set signature algorithm, not possible with tar-based phar archives"); } if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &algo) != SUCCESS) { @@ -1417,6 +1421,10 @@ PHP_METHOD(Phar, compressAllFilesGZ) #endif PHAR_ARCHIVE_OBJECT(); + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress all files as Gzip, not possible with tar-based phar archives"); + } if (PHAR_G(readonly)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Phar is readonly, cannot change compression"); @@ -1455,6 +1463,15 @@ PHP_METHOD(Phar, compressAllFilesBZIP2) #endif PHAR_ARCHIVE_OBJECT(); + if (phar_obj->arc.archive->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress all files as Bzip2, not possible with tar-based phar archives"); + } + if (phar_obj->arc.archive->is_zip) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress all files as Bzip2, not possible with zip-based phar archives"); + } + if (PHAR_G(readonly)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Phar is readonly, cannot change compression"); @@ -1585,6 +1602,9 @@ PHP_METHOD(Phar, copy) newentry.fp = fp; newentry.filename = estrndup(newfile, newfile_len); newentry.filename_len = newfile_len; + if (oldentry->is_tar) { + newentry.tar_type = oldentry->tar_type; + } phar_obj->arc.archive->is_modified = 1; zend_hash_add(&phar_obj->arc.archive->manifest, newfile, newfile_len, (void*)&newentry, sizeof(phar_entry_info), NULL); @@ -1798,6 +1818,29 @@ PHP_METHOD(Phar, getStub) RETURN_STRINGL(buf, len, 0); } #endif + if (phar_obj->arc.archive->is_tar) { + phar_entry_info *stub; + + if (SUCCESS == zend_hash_find(&(phar_obj->arc.archive->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) { + if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew) { + fp = phar_obj->arc.archive->fp; + } else { + fp = php_stream_open_wrapper(phar_obj->arc.archive->fname, "rb", 0, NULL); + } + + if (!fp) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, + "Unable to read stub"); + return; + } + + php_stream_seek(fp, stub->offset_within_phar, SEEK_SET); + len = stub->uncompressed_filesize; + goto carry_on; + } else { + RETURN_STRINGL("", 0, 0); + } + } len = phar_obj->arc.archive->halt_offset; if (phar_obj->arc.archive->fp && !phar_obj->arc.archive->is_brandnew) { @@ -1812,8 +1855,9 @@ PHP_METHOD(Phar, getStub) return; } - buf = safe_emalloc(len, 1, 1); php_stream_rewind(fp); +carry_on: + buf = safe_emalloc(len, 1, 1); if (len != php_stream_read(fp, buf, len)) { if (fp != phar_obj->arc.archive->fp) { php_stream_close(fp); @@ -1865,6 +1909,10 @@ PHP_METHOD(Phar, setMetadata) zval *metadata; PHAR_ARCHIVE_OBJECT(); + 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"); + } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &metadata) == FAILURE) { return; } @@ -1993,7 +2041,7 @@ PHP_METHOD(PharFileInfo, __destruct) PHAR_ENTRY_OBJECT(); if (entry_obj->ent.entry->is_dir) { - if (!entry_obj->ent.entry->is_zip && entry_obj->ent.entry->filename) { + if (!entry_obj->ent.entry->is_zip && !entry_obj->ent.entry->is_tar && entry_obj->ent.entry->filename) { efree(entry_obj->ent.entry->filename); entry_obj->ent.entry->filename = NULL; } @@ -2167,6 +2215,10 @@ PHP_METHOD(PharFileInfo, setMetadata) zval *metadata; PHAR_ENTRY_OBJECT(); + 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"); + } if (entry_obj->ent.entry->is_dir) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ "Phar entry is a directory, cannot set metadata"); \ @@ -2230,6 +2282,10 @@ PHP_METHOD(PharFileInfo, setCompressedGZ) char *error; PHAR_ENTRY_OBJECT(); + if (entry_obj->ent.entry->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with Gzip compression, not possible with tar-based phar archives"); + } if (entry_obj->ent.entry->is_dir) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ "Phar entry is a directory, cannot set compression"); \ @@ -2282,6 +2338,10 @@ PHP_METHOD(PharFileInfo, setCompressedBZIP2) zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot compress with Bzip2 compression, not possible with zip-based phar archives"); } + if (entry_obj->ent.entry->is_tar) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot compress with Bzip2 compression, not possible with tar-based phar archives"); + } if (!phar_has_bz2) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Cannot compress with Bzip2 compression, bz2 extension is not enabled");