From: Greg Beaver Date: Mon, 25 Feb 2008 04:23:36 +0000 (+0000) Subject: implement Phar::mount() for directories, add test X-Git-Tag: RELEASE_2_0_0a1~337 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ec7f89fe794a4bf7ad2dcb8b67f52b9b28def878;p=php implement Phar::mount() for directories, add test # opendir not yet implemented for mounted directories --- diff --git a/ext/phar/phar.c b/ext/phar/phar.c index d4c746e5d0..14c28208ce 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -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; diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 4f49241b07..836e85b189 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -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 index 0000000000..fcb5e223ad --- /dev/null +++ b/ext/phar/tests/mounteddir.phpt @@ -0,0 +1,44 @@ +--TEST-- +Phar: mounted manifest directory test +--SKIPIF-- + +--INI-- +phar.readonly=0 +--FILE-- +'; +$a->setStub(''); +file_put_contents(dirname(__FILE__) . '/testit/extfile2.php', ''); +include dirname(__FILE__) . '/testit/extfile.php'; +include $fname; +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +string(%d) "%sextfile.php" +string(%d) "phar://%sextfile.php" +string(%d) "phar://%sextfile2.php" +===DONE=== \ No newline at end of file diff --git a/ext/phar/util.c b/ext/phar/util.c index 50c3371f46..77c0b59080 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -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;