diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c index c486fd41abfd..64cace889922 100644 --- a/ext/phar/dirstream.c +++ b/ext/phar/dirstream.c @@ -345,21 +345,21 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mo { phar_entry_info entry, *e; phar_archive_data *phar = NULL; - char *error, *arch; - size_t arch_len; + char *error; php_url *resource = NULL; /* pre-readonly check, we need to know if this is a data phar */ - if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, NULL, 2, 2)) { + zend_string *arch = phar_split_fname(url_from, strlen(url_from), NULL, 2, 2); + if (!arch) { php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", no phar archive specified", url_from); return 0; } - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { + if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { phar = NULL; } - efree(arch); + zend_string_release_ex(arch, false); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", write operations disabled", url_from); @@ -471,21 +471,21 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options { phar_entry_info *entry; phar_archive_data *phar = NULL; - char *error, *arch; - size_t arch_len; + char *error; php_url *resource = NULL; /* pre-readonly check, we need to know if this is a data phar */ - if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, NULL, 2, 2)) { + zend_string *arch = phar_split_fname(url, strlen(url), NULL, 2, 2); + if (!arch) { php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url); return 0; } - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { + if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { phar = NULL; } - efree(arch); + zend_string_release_ex(arch, false); if (PHAR_G(readonly) && (!phar || !phar->is_data)) { php_stream_wrapper_log_error(wrapper, options, "phar error: cannot rmdir directory \"%s\", write operations disabled", url); diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index 0e7d2df0db61..20ce0e8d7258 100644 --- a/ext/phar/func_interceptors.c +++ b/ext/phar/func_interceptors.c @@ -38,8 +38,6 @@ PHP_FUNCTION(phar_opendir) /* {{{ */ } if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { - char *arch; - size_t arch_len; zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is @@ -48,7 +46,8 @@ PHP_FUNCTION(phar_opendir) /* {{{ */ goto skip_phar; } - if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) { + zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); + if (arch) { php_stream_context *context = NULL; php_stream *stream; char *name; @@ -58,12 +57,12 @@ PHP_FUNCTION(phar_opendir) /* {{{ */ zend_string *entry = phar_fix_filepath(filename, filename_len, true); if (ZSTR_VAL(entry)[0] == '/') { - spprintf(&name, 4096, "phar://%s%s", arch, ZSTR_VAL(entry)); + spprintf(&name, 4096, "phar://%s%s", ZSTR_VAL(arch), ZSTR_VAL(entry)); } else { - spprintf(&name, 4096, "phar://%s/%s", arch, ZSTR_VAL(entry)); + spprintf(&name, 4096, "phar://%s/%s", ZSTR_VAL(arch), ZSTR_VAL(entry)); } zend_string_release_ex(entry, false); - efree(arch); + zend_string_release_ex(arch, false); if (zcontext) { context = php_stream_context_from_zval(zcontext, 0); } @@ -84,8 +83,6 @@ PHP_FUNCTION(phar_opendir) /* {{{ */ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool using_include_path) { - char *arch; - size_t arch_len; zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is @@ -94,15 +91,16 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool return NULL; } - if (FAILURE == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) { + zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); + if (!arch) { return NULL; } /* fopen within phar, if :// is not in the url, then prepend phar:/// */ /* retrieving a file defaults to within the current directory, so use this if possible */ phar_archive_data *phar; - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); + if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { + zend_string_release_ex(arch, false); return NULL; } @@ -110,7 +108,7 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool if (using_include_path) { if (!(name = phar_find_in_include_path(filename, NULL))) { /* this file is not in the phar, use the original path */ - efree(arch); + zend_string_release_ex(arch, false); return NULL; } } else { @@ -124,24 +122,24 @@ static zend_string* phar_get_name_for_relative_paths(zend_string *filename, bool /* this file is not in the phar, use the original path */ if (!is_in_phar) { zend_string_release_ex(entry, false); - efree(arch); + zend_string_release_ex(arch, false); return NULL; } /* auto-convert to phar:// */ if (ZSTR_VAL(entry)[0] == '/') { - ZEND_ASSERT(strlen("phar://") + arch_len + ZSTR_LEN(entry) < 4096); + ZEND_ASSERT(strlen("phar://") + ZSTR_LEN(arch) + ZSTR_LEN(entry) < 4096); name = zend_string_concat3( "phar://", strlen("phar://"), - arch, arch_len, + ZSTR_VAL(arch), ZSTR_LEN(arch), ZSTR_VAL(entry), ZSTR_LEN(entry) ); } else { - name = strpprintf(4096, "phar://%s/%s", arch, ZSTR_VAL(entry)); + name = strpprintf(4096, "phar://%s/%s", ZSTR_VAL(arch), ZSTR_VAL(entry)); } zend_string_release_ex(entry, false); } - efree(arch); + zend_string_release_ex(arch, false); return name; } @@ -492,12 +490,12 @@ static void phar_file_stat(const char *filename, size_t filename_length, int typ phar = PHAR_G(last_phar); goto splitted; } - char *arch; - size_t arch_len; - if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) { + + zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); + if (arch) { /* fopen within phar, if :// is not in the url, then prepend phar:/// */ - zend_result has_archive = phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL); - efree(arch); + zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + zend_string_release_ex(arch, false); if (FAILURE == has_archive) { goto skip_phar; } @@ -721,8 +719,6 @@ PHP_FUNCTION(phar_is_file) /* {{{ */ goto skip_phar; } if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { - char *arch; - size_t arch_len; zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is @@ -731,12 +727,15 @@ PHP_FUNCTION(phar_is_file) /* {{{ */ goto skip_phar; } - if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) { + zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); + if (arch) { phar_archive_data *phar; /* fopen within phar, if :// is not in the url, then prepend phar:/// */ /* retrieving a file within the current directory, so use this if possible */ - if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { + zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + zend_string_release_ex(arch, false); + if (has_archive == SUCCESS) { phar_entry_info *etemp; zend_string *entry = phar_fix_filepath(filename, filename_len, true); @@ -747,12 +746,10 @@ PHP_FUNCTION(phar_is_file) /* {{{ */ } zend_string_release_ex(entry, false); if (etemp) { - efree(arch); RETURN_BOOL(!etemp->is_dir); } /* this file is not in the current directory, use the original path */ } - efree(arch); RETURN_FALSE; } } @@ -779,8 +776,6 @@ PHP_FUNCTION(phar_is_link) /* {{{ */ goto skip_phar; } if (!IS_ABSOLUTE_PATH(filename, filename_len) && !strstr(filename, "://")) { - char *arch; - size_t arch_len; zend_string *fname = zend_get_executed_filename_ex(); /* we are checking for existence of a file within the relative path. Chances are good that this is @@ -789,12 +784,15 @@ PHP_FUNCTION(phar_is_link) /* {{{ */ goto skip_phar; } - if (SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0)) { + zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); + if (arch) { phar_archive_data *phar; /* fopen within phar, if :// is not in the url, then prepend phar:/// */ /* retrieving a file within the current directory, so use this if possible */ - if (SUCCESS == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { + zend_result has_archive = phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL); + zend_string_release_ex(arch, false); + if (has_archive == SUCCESS) { phar_entry_info *etemp; zend_string *entry = phar_fix_filepath(filename, filename_len, true); @@ -805,11 +803,9 @@ PHP_FUNCTION(phar_is_link) /* {{{ */ } zend_string_release_ex(entry, false); if (etemp) { - efree(arch); RETURN_BOOL(etemp->link); } } - efree(arch); RETURN_FALSE; } } diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 5fb6c864be74..3008316f6274 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2164,7 +2164,7 @@ zend_string* phar_fix_filepath(const char *path, size_t path_length, bool use_cw * * This is used by phar_parse_url() */ -zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, zend_string **entry, int executable, int for_create) /* {{{ */ +zend_string* phar_split_fname_ex(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create, const char **error) /* {{{ */ { const char *ext_str; #ifdef PHP_WIN32 @@ -2172,8 +2172,11 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a #endif size_t ext_len; + if (error) { + *error = NULL; + } if (zend_char_has_nul_byte(filename, filename_len)) { - return FAILURE; + return NULL; } if (!strncasecmp(filename, "phar://", 7)) { @@ -2191,12 +2194,12 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a #endif if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, false) == FAILURE) { if (ext_len != -1) { - if (!ext_str) { + if (!ext_str && error) { /* no / detected, restore arch for error message */ #ifdef PHP_WIN32 - *arch = save; + *error = save; #else - *arch = (char*)filename; + *error = filename; #endif } @@ -2205,19 +2208,19 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a efree((char *)filename); } #endif - return FAILURE; + return NULL; } ext_len = 0; /* no extension detected - instead we are dealing with an alias */ } - *arch_len = ext_str - filename + ext_len; - *arch = estrndup(filename, *arch_len); + size_t arch_len = ext_str - filename + ext_len; + zend_string *arch = zend_string_init(filename, arch_len, false); if (entry) { if (ext_str[ext_len]) { - size_t computed_entry_len = filename_len - *arch_len; + size_t computed_entry_len = filename_len - arch_len; /* We don't need to unixify the path on Windows, * as ext_str is derived from filename that was already unixify */ *entry = phar_fix_filepath(ext_str+ext_len, computed_entry_len, false); @@ -2232,10 +2235,14 @@ zend_result phar_split_fname(const char *filename, size_t filename_len, char **a } #endif - return SUCCESS; + return arch; } /* }}} */ +zend_string* phar_split_fname(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create) { + return phar_split_fname_ex(filename, filename_len, entry, executable, for_create, NULL); +} + /** * Invoked when a user calls Phar::mapPhar() from within an executing .phar * to set up its manifest directly diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index a60c5ed5d432..34f221f43e0e 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -474,7 +474,8 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, co ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error); ZEND_ATTRIBUTE_NONNULL int phar_flush(phar_archive_data *archive, char **error); zend_result phar_detect_phar_fname_ext(const char *filename, size_t filename_len, const char **ext_str, size_t *ext_len, int executable, int for_create, bool is_complete); -zend_result phar_split_fname(const char *filename, size_t filename_len, char **arch, size_t *arch_len, zend_string **entry, int executable, int for_create); +zend_string* phar_split_fname_ex(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create, const char **error); +zend_string* phar_split_fname(const char *filename, size_t filename_len, zend_string **entry, int executable, int for_create); typedef enum { pcr_use_query, diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index f97240010d48..07058eefc461 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -403,33 +403,27 @@ static void phar_postprocess_ru_web(char *fname, size_t fname_len, char *entry, */ PHP_METHOD(Phar, running) { - zend_string *fname; - char *arch; - size_t arch_len; bool retphar = true; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &retphar) == FAILURE) { RETURN_THROWS(); } - fname = zend_get_executed_filename_ex(); + const zend_string *fname = zend_get_executed_filename_ex(); if (!fname) { RETURN_EMPTY_STRING(); } - if ( - zend_string_starts_with_literal_ci(fname, "phar://") - && SUCCESS == phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 2, 0) - ) { - if (retphar) { - RETVAL_STRINGL(ZSTR_VAL(fname), arch_len + 7); - efree(arch); - return; - } else { - // TODO: avoid reallocation ??? - RETVAL_STRINGL(arch, arch_len); - efree(arch); - return; + if (zend_string_starts_with_literal_ci(fname, "phar://")) { + zend_string *arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 2, 0); + if (arch) { + if (retphar) { + RETVAL_STRINGL(ZSTR_VAL(fname), ZSTR_LEN(arch) + 7); + zend_string_release_ex(arch, false); + return; + } else { + RETURN_STR(arch); + } } } @@ -444,8 +438,8 @@ PHP_METHOD(Phar, running) */ PHP_METHOD(Phar, mount) { - char *fname, *arch = NULL, *path, *actual; - size_t fname_len, arch_len; + char *fname, *path, *actual; + size_t fname_len; size_t path_len, actual_len; phar_archive_data *pphar; #ifdef PHP_WIN32 @@ -477,31 +471,29 @@ PHP_METHOD(Phar, mount) #endif zend_string *entry = NULL; - if (fname_len > 7 && !memcmp(fname, "phar://", 7) && SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, NULL, 2, 0)) { + zend_string *arch = NULL; + if (fname_len > 7 && !memcmp(fname, "phar://", 7) && (arch = phar_split_fname(fname, fname_len, NULL, 2, 0))) { if (path_len > 7 && !memcmp(path, "phar://", 7)) { zend_throw_exception_ex(phar_ce_PharException, 0, "Can only mount internal paths within a phar archive, use a relative path instead of \"%s\"", path); - efree(arch); + zend_string_release_ex(arch, false); goto finish; } carry_on2: - if (NULL == (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len))) { - if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len))) { + if (NULL == (pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), arch))) { + if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_find_ptr(&cached_phars, arch))) { if (SUCCESS == phar_copy_on_write(&pphar)) { goto carry_on; } } - zend_throw_exception_ex(phar_ce_PharException, 0, "%s is not a phar archive, cannot mount", arch); - - if (arch) { - efree(arch); - } + zend_throw_exception_ex(phar_ce_PharException, 0, "%s is not a phar archive, cannot mount", ZSTR_VAL(arch)); + zend_string_release_ex(arch, false); goto finish; } carry_on: if (SUCCESS != phar_mount_entry(pphar, actual, actual_len, path, path_len)) { - zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, arch); + zend_throw_exception_ex(phar_ce_PharException, 0, "Mounting of %s to %s within phar %s failed", path, actual, ZSTR_VAL(arch)); } if (entry && path == ZSTR_VAL(entry)) { @@ -509,7 +501,7 @@ PHP_METHOD(Phar, mount) } if (arch) { - efree(arch); + zend_string_release_ex(arch, false); } goto finish; @@ -521,7 +513,7 @@ PHP_METHOD(Phar, mount) } goto carry_on; - } else if (SUCCESS == phar_split_fname(path, path_len, &arch, &arch_len, &entry, 2, 0)) { + } else if ((arch = phar_split_fname(path, path_len, &entry, 2, 0))) { path = ZSTR_VAL(entry); path_len = ZSTR_LEN(entry); goto carry_on2; @@ -1077,9 +1069,8 @@ static const spl_other_handler phar_spl_foreign_handler = { */ PHP_METHOD(Phar, __construct) { - char *fname, *alias = NULL, *error, *arch = NULL, *save_fname; + char *fname, *alias = NULL, *error, *save_fname; size_t fname_len, alias_len = 0; - size_t arch_len; bool is_data; zend_long flags = SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS; zend_long format = 0; @@ -1108,27 +1099,19 @@ PHP_METHOD(Phar, __construct) save_fname = fname; zend_string *entry = NULL; - if (SUCCESS == phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, !is_data, 2)) { + /* phar_split_fname() will unixify the path */ + zend_string *arch = phar_split_fname(fname, fname_len, &entry, !is_data, 2); + if (arch) { /* use arch (the basename for the archive) for fname instead of fname */ /* this allows support for RecursiveDirectoryIterator of subdirectories */ -#ifdef PHP_WIN32 - phar_unixify_path_separators(arch, arch_len); -#endif - fname = arch; - fname_len = arch_len; -#ifdef PHP_WIN32 - } else { - arch = estrndup(fname, fname_len); - arch_len = fname_len; - fname = arch; - phar_unixify_path_separators(arch, arch_len); -#endif + fname = ZSTR_VAL(arch); + fname_len = ZSTR_LEN(arch); } if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, is_data, REPORT_ERRORS, &phar_data, &error) == FAILURE) { - if (fname == arch && fname != save_fname) { - efree(arch); + if (arch && fname == ZSTR_VAL(arch) && fname != save_fname) { + zend_string_release_ex(arch, false); fname = save_fname; } @@ -1153,8 +1136,8 @@ PHP_METHOD(Phar, __construct) phar_data->is_tar = false; } - if (fname == arch) { - efree(arch); + if (arch && fname == ZSTR_VAL(arch)) { + zend_string_release_ex(arch, false); fname = save_fname; } @@ -1260,9 +1243,8 @@ PHP_METHOD(Phar, getSupportedCompression) /* {{{ Completely remove a phar archive from memory and disk */ PHP_METHOD(Phar, unlinkArchive) { - char *fname, *error, *arch; + char *fname, *error; size_t fname_len; - size_t arch_len; phar_archive_data *phar; if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &fname, &fname_len) == FAILURE) { @@ -1284,19 +1266,17 @@ PHP_METHOD(Phar, unlinkArchive) RETURN_THROWS(); } - zend_string *zend_file_name = zend_get_executed_filename_ex(); - - if ( - zend_file_name - && zend_string_starts_with_literal_ci(zend_file_name, "phar://") - && SUCCESS == phar_split_fname(ZSTR_VAL(zend_file_name), ZSTR_LEN(zend_file_name), &arch, &arch_len, NULL, 2, 0) - ) { - if (arch_len == fname_len && !memcmp(arch, fname, arch_len)) { - zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" cannot be unlinked from within itself", fname); - efree(arch); - RETURN_THROWS(); + const zend_string *zend_file_name = zend_get_executed_filename_ex(); + if (zend_file_name && zend_string_starts_with_literal_ci(zend_file_name, "phar://")) { + zend_string *arch = phar_split_fname(ZSTR_VAL(zend_file_name), ZSTR_LEN(zend_file_name), NULL, 2, 0); + if (arch) { + if (ZSTR_LEN(arch) == fname_len && !memcmp(ZSTR_VAL(arch), fname, ZSTR_LEN(arch))) { + zend_string_release_ex(arch, false); + zend_throw_exception_ex(phar_ce_PharException, 0, "phar archive \"%s\" cannot be unlinked from within itself", fname); + RETURN_THROWS(); + } + zend_string_release_ex(arch, false); } - efree(arch); } if (phar->is_persistent) { @@ -4395,9 +4375,8 @@ PHP_METHOD(Phar, extractTo) /* {{{ Construct a Phar entry object */ PHP_METHOD(PharFileInfo, __construct) { - char *fname, *arch, *error; + char *fname, *error; size_t fname_len; - size_t arch_len; phar_entry_object *entry_obj; phar_archive_data *phar_data; zval arg1; @@ -4413,15 +4392,22 @@ PHP_METHOD(PharFileInfo, __construct) RETURN_THROWS(); } + if (fname_len < 7 || memcmp(fname, "phar://", 7)) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0, + "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname); + RETURN_THROWS(); + } + zend_string *entry = NULL; - if (fname_len < 7 || memcmp(fname, "phar://", 7) || phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, 2, 0) == FAILURE) { + zend_string *arch = phar_split_fname(fname, fname_len, &entry, 2, 0); + if (!arch) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "'%s' is not a valid phar archive URL (must have at least phar://filename.phar)", fname); RETURN_THROWS(); } - if (phar_open_from_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error) == FAILURE) { - efree(arch); + if (phar_open_from_filename(ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, REPORT_ERRORS, &phar_data, &error) == FAILURE) { + zend_string_release_ex(arch, false); efree(entry); if (error) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, @@ -4437,14 +4423,15 @@ PHP_METHOD(PharFileInfo, __construct) phar_entry_info *entry_info = phar_get_entry_info_dir(phar_data, ZSTR_VAL(entry), ZSTR_LEN(entry), 1, &error, true); if (UNEXPECTED(!entry_info)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, - "Cannot access phar file entry '%s' in archive '%s'%s%s", ZSTR_VAL(entry), arch, error ? ", " : "", error ? error : ""); + "Cannot access phar file entry '%s' in archive '%s'%s%s", + ZSTR_VAL(entry), ZSTR_VAL(arch), error ? ", " : "", error ? error : ""); zend_string_release_ex(entry, false); - efree(arch); + zend_string_release_ex(arch, false); RETURN_THROWS(); } zend_string_release_ex(entry, false); - efree(arch); + zend_string_release_ex(arch, false); entry_obj->entry = entry_info; if (!entry_info->is_persistent && !entry_info->is_temp_dir) { diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 4b49703b4abe..455f403b597b 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -58,8 +58,7 @@ const php_stream_wrapper php_stream_phar_wrapper = { php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options) /* {{{ */ { php_url *resource; - char *arch = NULL, *error; - size_t arch_len; + char *error; if (strncasecmp(filename, "phar://", 7)) { return NULL; @@ -70,12 +69,14 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } return NULL; } + zend_string *entry = NULL; - if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, 2, (mode[0] == 'w' ? 2 : 0)) == FAILURE) { + const char *arch_error = NULL; + zend_string *arch = phar_split_fname_ex(filename, strlen(filename), &entry, 2, (mode[0] == 'w' ? 2 : 0), &arch_error); + if (!arch) { if (!(options & PHP_STREAM_URL_STAT_QUIET)) { - if (arch && !entry) { - php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch); - arch = NULL; + if (arch_error && !entry) { + php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", filename, arch_error); } else { php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url or non-existent phar \"%s\"", filename); } @@ -84,8 +85,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const } resource = ecalloc(1, sizeof(php_url)); resource->scheme = ZSTR_INIT_LITERAL("phar", 0); - resource->host = zend_string_init(arch, arch_len, 0); - efree(arch); + resource->host = arch; resource->path = entry; #ifdef MBO_0 diff --git a/ext/phar/util.c b/ext/phar/util.c index 8af0c488f5ca..43ed4dd24824 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -41,9 +41,9 @@ static zend_result phar_call_openssl_signverify(bool is_sign, php_stream *fp, ze static char *phar_get_link_location(phar_entry_info *entry) /* {{{ */ { char *p, *ret = NULL; - if (!entry->link) { - return NULL; - } + + ZEND_ASSERT(entry->link); + if (entry->link[0] == '/') { return estrdup(entry->link + 1); } @@ -266,8 +266,8 @@ zend_result phar_mount_entry(phar_archive_data *phar, const char *filename, size zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data **pphar) /* {{{ */ { zend_string *ret; - char *path, *arch; - size_t arch_len; + char *path; + zend_string *arch; phar_archive_data *phar; if (pphar) { @@ -294,19 +294,22 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data && ZSTR_LEN(fname) - length_phar_protocol >= PHAR_G(last_phar_name_len) && !memcmp(ZSTR_VAL(fname) + length_phar_protocol, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)) ) { - arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len)); - arch_len = PHAR_G(last_phar_name_len); + arch = zend_string_init(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len), false); phar = PHAR_G(last_phar); goto splitted; } - if (!is_file_a_phar_wrapper || SUCCESS != phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), &arch, &arch_len, NULL, 1, 0)) { + if (!is_file_a_phar_wrapper) { + return NULL; + } + arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 1, 0); + if (!arch) { return NULL; } if (*ZSTR_VAL(filename) == '.') { - if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) { - efree(arch); + if (FAILURE == phar_get_archive(&phar, ZSTR_VAL(arch), ZSTR_LEN(arch), NULL, 0, NULL)) { + zend_string_release_ex(arch, false); return NULL; } splitted: @@ -319,42 +322,43 @@ zend_string *phar_find_in_include_path(zend_string *filename, phar_archive_data if (zend_hash_str_exists(&(phar->manifest), ZSTR_VAL(test) + 1, ZSTR_LEN(test) - 1)) { ret = zend_string_concat3( "phar://", strlen("phar://"), - arch, arch_len, + ZSTR_VAL(arch), ZSTR_LEN(arch), ZSTR_VAL(test), ZSTR_LEN(test) ); zend_string_release_ex(test, false); - efree(arch); + zend_string_release_ex(arch, false); return ret; } } else { if (zend_hash_exists(&(phar->manifest), test)) { - ret = strpprintf(0, "phar://%s/%s", arch, ZSTR_VAL(test)); + ret = strpprintf(0, "phar://%s/%s", ZSTR_VAL(arch), ZSTR_VAL(test)); zend_string_release_ex(test, false); - efree(arch); + zend_string_release_ex(arch, false); return ret; } } zend_string_release_ex(test, false); } - spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path)); - efree(arch); + spprintf(&path, MAXPATHLEN + 1 + strlen(PG(include_path)), "phar://%s/%s%c%s", ZSTR_VAL(arch), PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path)); + zend_string_release_ex(arch, false); ret = php_resolve_path(ZSTR_VAL(filename), ZSTR_LEN(filename), path); efree(path); if (ret && zend_string_starts_with_literal_ci(ret, "phar://")) { /* found phar:// */ - if (SUCCESS != phar_split_fname(ZSTR_VAL(ret), ZSTR_LEN(ret), &arch, &arch_len, NULL, 1, 0)) { + arch = phar_split_fname(ZSTR_VAL(fname), ZSTR_LEN(fname), NULL, 1, 0); + if (!arch) { return ret; } - *pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), arch, arch_len); + *pphar = zend_hash_find_ptr(&(PHAR_G(phar_fname_map)), arch); if (!*pphar && PHAR_G(manifest_cached)) { - *pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len); + *pphar = zend_hash_find_ptr(&cached_phars, arch); } - efree(arch); + zend_string_release_ex(arch, false); } return ret;