sfox Fri Apr 25 21:37:40 2008 UTC Modified files: /pecl/phar phar_object.c util.c Log: - 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. http://cvs.php.net/viewvc.cgi/pecl/phar/phar_object.c?r1=1.237&r2=1.238&diff_format=u Index: pecl/phar/phar_object.c diff -u pecl/phar/phar_object.c:1.237 pecl/phar/phar_object.c:1.238 --- pecl/phar/phar_object.c:1.237 Fri Apr 25 16:50:20 2008 +++ pecl/phar/phar_object.c Fri Apr 25 21:37:40 2008 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: phar_object.c,v 1.237 2008/04/25 16:50:20 cellog Exp $ */ +/* $Id: phar_object.c,v 1.238 2008/04/25 21:37:40 sfox Exp $ */ #include "phar_internal.h" #include "func_interceptors.h" @@ -1382,7 +1382,11 @@ 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 @@ 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 @@ } /* }}} */ +/* {{{ 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 @@ -3964,6 +4066,12 @@ 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) ZEND_END_ARG_INFO(); @@ -4022,6 +4130,7 @@ 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) http://cvs.php.net/viewvc.cgi/pecl/phar/util.c?r1=1.41&r2=1.42&diff_format=u Index: pecl/phar/util.c diff -u pecl/phar/util.c:1.41 pecl/phar/util.c:1.42 --- pecl/phar/util.c:1.41 Fri Apr 25 16:10:58 2008 +++ pecl/phar/util.c Fri Apr 25 21:37:40 2008 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: util.c,v 1.41 2008/04/25 16:10:58 cellog Exp $ */ +/* $Id: util.c,v 1.42 2008/04/25 21:37:40 sfox Exp $ */ #include "phar_internal.h" #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300 @@ -594,7 +594,13 @@ 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 @@ { 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;