From: Steph Fox Date: Fri, 25 Apr 2008 21:37:41 +0000 (+0000) Subject: - implemented Phar::buildFromDirectory X-Git-Tag: RELEASE_2_0_0b1~204 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9bf8d7429e5de07deb37b58c3ce8dfadde0c9718;p=php - implemented Phar::buildFromDirectory @Greg: There are two (identical) recurring memleaks I can't seem to kill, both marked FIXME. Would you please take a look? [DOC] $phar->buildFromDirectory(dirname[, regex]). Return value is an array pairing each file in the archive index with the original path on the filesystem. --- diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index c34dd7f8da..a37403cb86 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1382,7 +1382,11 @@ static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ goto phar_spl_fileinfo; case SPL_FS_INFO: case SPL_FS_FILE: - return ZEND_HASH_APPLY_KEEP; + /* FIXME: memleak here */ + fname = expand_filepath(intern->file_name, NULL TSRMLS_CC); + fname_len = strlen(fname); + is_splfileinfo = 1; + goto phar_spl_fileinfo; } } /* fall-through */ @@ -1396,6 +1400,9 @@ static int phar_build(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ phar_spl_fileinfo: if (base_len) { + /* FIXME: memleak here */ + base = expand_filepath(base, NULL TSRMLS_CC); + base_len = strlen(base); if (strstr(fname, base)) { str_key_len = fname_len - base_len; if (str_key_len <= 0) { @@ -1489,6 +1496,101 @@ after_open_fp: } /* }}} */ +/* {{{ proto array Phar::buildFromDirectory(string directory[, string regex]) + * Construct a phar archive from an existing directory, recursively. + * Optional second parameter is a regular expression for filtering directory contents. + * + * Return value is an array mapping phar index to actual files added. + */ +PHP_METHOD(Phar, buildFromDirectory) +{ + char *dir, *regex, *error; + int dir_len, regex_len; + zend_bool apply_reg = 0; + zval arg, arg2, *iter, *iteriter, *regexiter = NULL; + struct { + phar_archive_object *p; + zend_class_entry *c; + char *b; + uint l; + zval *ret; + } pass; + + PHAR_ARCHIVE_OBJECT(); + + if (PHAR_G(readonly) && !phar_obj->arc.archive->is_data) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write to archive - write operations restricted by INI setting"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &dir, &dir_len, ®ex, ®ex_len) == FAILURE) { + RETURN_FALSE; + } + + MAKE_STD_ZVAL(iter); + + if (SUCCESS != object_init_ex(iter, spl_ce_RecursiveDirectoryIterator)) { + zval_dtor(iter); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + INIT_PZVAL(&arg); + ZVAL_STRINGL(&arg, dir, dir_len, 0); + + zend_call_method_with_1_params(&iter, spl_ce_RecursiveDirectoryIterator, + &spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg); + + MAKE_STD_ZVAL(iteriter); + + if (SUCCESS != object_init_ex(iteriter, spl_ce_RecursiveIteratorIterator)) { + zval_dtor(iteriter); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate directory iterator for %s", phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator, + &spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, iter); + + zval_ptr_dtor(&iter); + + if (regex_len > 0) { + apply_reg = 1; + MAKE_STD_ZVAL(regexiter); + + if (SUCCESS != object_init_ex(regexiter, spl_ce_RegexIterator)) { + zval_dtor(regexiter); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to instantiate regex iterator for %s", phar_obj->arc.archive->fname); + RETURN_FALSE; + } + + INIT_PZVAL(&arg2); + ZVAL_STRINGL(&arg2, regex, regex_len, 0); + + zend_call_method_with_2_params(®exiter, spl_ce_RegexIterator, + &spl_ce_RegexIterator->constructor, "__construct", NULL, iteriter, &arg2); + } + + array_init(return_value); + + pass.c = apply_reg ? Z_OBJCE_P(regexiter) : Z_OBJCE_P(iteriter); + pass.p = phar_obj; + pass.b = dir; + pass.l = dir_len; + pass.ret = return_value; + + if (SUCCESS == spl_iterator_apply((apply_reg ? regexiter : iteriter), (spl_iterator_apply_func_t) phar_build, (void *) &pass TSRMLS_CC)) { + zval_ptr_dtor(&iteriter); + if (apply_reg) zval_ptr_dtor(®exiter); + phar_flush(phar_obj->arc.archive, 0, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } + } +} + /* {{{ proto array Phar::buildFromIterator(Iterator iter[, string base_directory]) * Construct a phar archive from an iterator. The iterator must return a series of strings * that are full paths to files that should be added to the phar. The iterator key should @@ -3963,6 +4065,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_delete, 0, 0, 1) ZEND_ARG_INFO(0, entry) ZEND_END_ARG_INFO(); +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_fromdir, 0, 0, 1) + ZEND_ARG_INFO(0, dir_path) + ZEND_ARG_INFO(0, regex) +ZEND_END_ARG_INFO(); + static ZEND_BEGIN_ARG_INFO_EX(arginfo_phar_offsetExists, 0, 0, 1) ZEND_ARG_INFO(0, entry) @@ -4022,6 +4130,7 @@ zend_function_entry php_archive_methods[] = { PHP_ME(Phar, addEmptyDir, arginfo_phar_emptydir, ZEND_ACC_PUBLIC) PHP_ME(Phar, addFile, arginfo_phar_addfile, ZEND_ACC_PUBLIC) PHP_ME(Phar, addFromString, arginfo_phar_fromstring, ZEND_ACC_PUBLIC) + PHP_ME(Phar, buildFromDirectory, arginfo_phar_fromdir, ZEND_ACC_PUBLIC) PHP_ME(Phar, buildFromIterator, arginfo_phar_build, ZEND_ACC_PUBLIC) PHP_ME(Phar, compressFiles, arginfo_phar_comp, ZEND_ACC_PUBLIC) PHP_ME(Phar, decompressFiles, NULL, ZEND_ACC_PUBLIC) diff --git a/ext/phar/util.c b/ext/phar/util.c index 82321a1c0b..f25a27c85a 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -594,7 +594,13 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char phar_entry_info *entry, etemp; phar_entry_data *ret; const char *pcr_error; - char is_dir = (path_len > 0 && path != NULL) ? path[path_len - 1] == '/' : 0; + char is_dir; + +#ifdef PHP_WIN32 + phar_unixify_path_separators(path, path_len); +#endif + + is_dir = (path_len > 0 && path != NULL) ? path[path_len - 1] == '/' : 0; if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { return NULL; @@ -1080,7 +1086,13 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in { const char *pcr_error; phar_entry_info *entry; - char is_dir = path_len && (path[path_len - 1] == '/'); + char is_dir; + +#ifdef PHP_WIN32 + phar_unixify_path_separators(path, path_len); +#endif + + is_dir = path_len && (path[path_len - 1] == '/'); if (error) { *error = NULL;