]> granicus.if.org Git - php/commitdiff
implement Phar::mount() for directories, add test
authorGreg Beaver <cellog@php.net>
Mon, 25 Feb 2008 04:23:36 +0000 (04:23 +0000)
committerGreg Beaver <cellog@php.net>
Mon, 25 Feb 2008 04:23:36 +0000 (04:23 +0000)
# opendir not yet implemented for mounted directories

ext/phar/phar.c
ext/phar/phar_object.c
ext/phar/tests/mounteddir.phpt [new file with mode: 0644]
ext/phar/util.c

index d4c746e5d097b170ba06914db3917a9c62684aec..14c28208cecce1edd5605a25da352fa3beb10a6d 100644 (file)
@@ -1064,6 +1064,8 @@ int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int a
        }
        zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
                zend_get_hash_value, destroy_phar_manifest_entry, 0);
+       zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
+               zend_get_hash_value, NULL, 0);
        mydata->fname_len = fname_len;
        mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
        mydata->alias_len = alias ? alias_len : fname_len;
index 4f49241b0701c95fc26aaf682959462efa270675..836e85b189934ce10c32dd999989f6cb30354b1e 100755 (executable)
@@ -414,6 +414,26 @@ static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, in
 }
 /* }}} */
 
+/* {{{ proto void Phar::getRunningPhar()
+ * return the name of the currently running phar archive
+ */
+PHP_METHOD(Phar, getRunningPhar)
+{
+       char *fname, *arch, *entry;
+       int fname_len, arch_len, entry_len;
+
+       fname = zend_get_executed_filename(TSRMLS_C);
+       fname_len = strlen(fname);
+
+       if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
+               efree(entry);
+               RETURN_STRINGL(arch, arch_len, 0);
+       }
+       efree(entry);
+       RETURN_STRING("", 0);
+}
+/* }}} */
+
 /* {{{ proto void Phar::mount(string pharpath, string externalfile)
  * mount an external file or path to a location within the phar.  This maps
  * an external file or directory to a location within the phar archive, allowing
@@ -424,6 +444,7 @@ PHP_METHOD(Phar, mount)
 {
        char *fname, *arch, *entry, *path, *actual;
        int fname_len, arch_len, entry_len, path_len, actual_len;
+       phar_archive_data **pphar;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &path, &path_len, &actual, &actual_len) == FAILURE) {
                return;
@@ -433,16 +454,23 @@ PHP_METHOD(Phar, mount)
        fname_len = strlen(fname);
 
        if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
-               phar_archive_data **pphar;
+               efree(entry);
                if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
-                       /* TODO: throw exception */
+                       zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "%s is not a phar archive, cannot mount", arch);
+                       efree(arch);
                        return;
                }
+carry_on:
                if (SUCCESS != phar_mount_entry(*pphar, actual, actual_len, path, path_len TSRMLS_CC)) {
-                       /* TODO: throw exception */
-                       return;
+                       zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Mounting of %s to %s within phar %s failed", path, actual, arch);
+                       efree(arch);
                }
+               efree(arch);
+               return;
+       } else if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **)&pphar)) {
+               goto carry_on;
        }
+       zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Phar::mount() can only be run from within a phar archive");
 }
 /* }}} */
 
@@ -3508,6 +3536,7 @@ zend_function_entry php_archive_methods[] = {
        PHP_ME(Phar, isValidPharFilename,   NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, loadPhar,              arginfo_phar_loadPhar,     ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, mapPhar,               arginfo_phar_mapPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
+       PHP_ME(Phar, getRunningPhar,        NULL,                      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, mount,                 arginfo_phar_mount,        ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, mungServer,            arginfo_phar_mungServer,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
        PHP_ME(Phar, webPhar,               arginfo_phar_webPhar,      ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)
diff --git a/ext/phar/tests/mounteddir.phpt b/ext/phar/tests/mounteddir.phpt
new file mode 100644 (file)
index 0000000..fcb5e22
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+Phar: mounted manifest directory test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.readonly=0
+--FILE--
+<?php
+$fname = dirname(__FILE__) . '/tempmanifest1.phar.php';
+$a = new Phar($fname);
+$a['index.php'] = '<?php
+set_include_path(".");
+Phar::mount("testit", dirname(Phar::getRunningPhar()) . "/testit");
+include "testit/extfile.php";
+include "testit/extfile2.php";
+?>';
+$a->setStub('<?php
+include "phar://" . __FILE__ . "/index.php";
+__HALT_COMPILER();');
+unset($a);
+mkdir(dirname(__FILE__) . '/testit');
+file_put_contents(dirname(__FILE__) . '/testit/extfile.php', '<?php
+var_dump(__FILE__);
+?>');
+file_put_contents(dirname(__FILE__) . '/testit/extfile2.php', '<?php
+var_dump(__FILE__);
+?>');
+include dirname(__FILE__) . '/testit/extfile.php';
+include $fname;
+?>
+===DONE===
+--CLEAN--
+<?php
+@unlink(dirname(__FILE__) . '/tempmanifest1.phar.php');
+@unlink(dirname(__FILE__) . '/testit/extfile.php');
+@unlink(dirname(__FILE__) . '/testit/extfile2.php');
+@rmdir(dirname(__FILE__) . '/testit');
+
+?>
+--EXPECTF--
+string(%d) "%sextfile.php"
+string(%d) "phar://%sextfile.php"
+string(%d) "phar://%sextfile2.php"
+===DONE===
\ No newline at end of file
index 50c3371f463ee90523d6f6190c2e1f7a9f79e781..77c0b590805d3d9b1c4e6d5fc67d0143cfd94bb8 100644 (file)
@@ -72,8 +72,8 @@ int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t positi
        return php_stream_seek(fp, temp, SEEK_SET);
 }
 
-void phar_rename_archive(phar_archive_data *phar, char *ext TSRMLS_DC) {
-
+void phar_rename_archive(phar_archive_data *phar, char *ext TSRMLS_DC)
+{
        char *oldname = NULL, *oldpath = NULL;
        char *basename = NULL, *basepath = NULL;
        char *newname = NULL, *newpath = NULL;
@@ -151,26 +151,39 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
                return FAILURE;
        }
 
+
+       entry.phar = phar;
+       entry.filename = estrndup(path, path_len);
+       entry.filename_len = path_len;
+       if (strstr(filename, "phar://")) {
+               entry.link = estrndup(filename, filename_len);
+       } else {
+               entry.link = expand_filepath(filename, NULL TSRMLS_CC);
+               if (!entry.link) {
+                       entry.link = estrndup(filename, filename_len);
+               }
+       }
 #if PHP_MAJOR_VERSION < 6
-       if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+       if (PG(safe_mode) && !strstr(filename, "phar://") && (!php_checkuid(entry.link, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+               efree(entry.link);
+               efree(entry.filename);
                return FAILURE;
        }
 #endif
 
+       filename_len = strlen(entry.link);
+       filename = entry.link;
        /* only check openbasedir for files, not for phar streams */
        if (!strstr(filename, "phar://") && php_check_open_basedir(filename TSRMLS_CC)) {
+               efree(entry.link);
+               efree(entry.filename);
                return FAILURE;
        }
-
-       entry.phar = phar;
-       entry.filename = estrndup(path, path_len);
-       entry.filename_len = path_len;
-       entry.link = estrndup(filename, filename_len);
        entry.is_mounted = 1;
        entry.is_crc_checked = 1;
        entry.fp_type = PHAR_TMP;
 
-       if (SUCCESS != php_stream_stat_path(entry.link, &ssb)) {
+       if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
                efree(entry.link);
                efree(entry.filename);
                return FAILURE;
@@ -185,8 +198,8 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
                }
        } else {
                entry.is_dir = 0;
+               entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
        }
-       entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
        entry.flags = ssb.sb.st_mode;
        if (SUCCESS == zend_hash_add(&phar->manifest, path, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
                return SUCCESS;
@@ -234,6 +247,15 @@ char *phar_find_in_include_path(char *file, char *entry, phar_archive_data *phar
                        efree(save);
                        return test;
                }
+               if (zend_hash_num_elements(&(phar->mounted_dirs))) {
+                       if (phar_get_entry_info_dir(phar, test + 1, try_len - 1, 0, NULL TSRMLS_CC)) {
+                               char *save = test;
+                               efree(pathbuf);
+                               test = estrndup(test + 1, try_len - 1);
+                               efree(save);
+                               return test;
+                       }
+               }
                efree(test);
 stream_skip:
                ptr = end;
@@ -875,8 +897,76 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in
                        return NULL;
                }
                return entry;
+       } else if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
+               char *key;
+               ulong unused;
+               uint keylen;
+
+               zend_hash_internal_pointer_reset(&phar->mounted_dirs);
+               while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
+                       if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
+                               break;
+                       }
+                       if (keylen >= path_len || strncmp(key, path, keylen)) {
+                               continue;
+                       } else {
+                               char *test;
+                               int test_len;
+                               phar_entry_info *entry;
+                               php_stream_statbuf ssb;
+
+                               if (SUCCESS != zend_hash_find(&phar->manifest, key, keylen, (void **) &entry)) {
+                                       if (error) {
+                                               spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", key);
+                                       }
+                                       return NULL;
+                               }
+                               if (!entry->link || !entry->is_mounted) {
+                                       if (error) {
+                                               spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", key);
+                                       }
+                                       return NULL;
+                               }
+                               test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->link, path + keylen);
+                               if (SUCCESS != php_stream_stat_path(test, &ssb)) {
+                                       efree(test);
+                                       return NULL;
+                               }
+                               if (ssb.sb.st_mode & S_IFDIR && !dir) {
+                                       efree(test);
+                                       if (error) {
+                                               spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
+                                       }
+                                       return NULL;
+                               }
+                               if (ssb.sb.st_mode & S_IFDIR && dir) {
+                                       efree(test);
+                                       /* user requested a directory, we must return one */
+                                       if (error) {
+                                               spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
+                                       }
+                                       return NULL;
+                               }
+                               /* mount the file just in time */
+                               if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
+                                       efree(test);
+                                       if (error) {
+                                               spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
+                                       }
+                                       return NULL;
+                               }
+                               efree(test);
+                               if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
+                                       if (error) {
+                                               spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
+                                       }
+                                       return NULL;
+                               }
+                               return entry;
+                       }
+               }
        }
-       if (dir == 1) {
+       if (dir) {
                /* try to find a directory */
                HashTable *manifest;
                char *key;