]> granicus.if.org Git - php/commitdiff
initial tar support - a few kinks to work on in phar creation, but read works
authorGreg Beaver <cellog@php.net>
Thu, 3 Jan 2008 04:45:00 +0000 (04:45 +0000)
committerGreg Beaver <cellog@php.net>
Thu, 3 Jan 2008 04:45:00 +0000 (04:45 +0000)
ext/phar/config.m4
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/phar_object.c

index 5de8145b071b0cc396636cc8b60157776f752f5a..2e262516aba561ec559c4e3869e06a0c43e4fa3e 100644 (file)
@@ -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)
index 43e66b54c6f1506256f06659f0a9071e9988c9d4..e54ba6d21384c3ea93d2b3c2b5e0c6459909cc25 100644 (file)
@@ -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");
index a39d7e93d58f837fc7388fc6c26fe24d3e2fe38e..a9ee9591924fb967b76edf3d2d768cd9ab4232dc 100755 (executable)
@@ -25,6 +25,7 @@
 
 #include <time.h>
 #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);
index 8f5be1c79e6d07029016ae7222438ec11867cd56..d6594b79d38e2dbf3026c36ea8beb16e713e5727 100755 (executable)
@@ -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");