From 679dd21801923ec69fb08aa0f47ad97a8d928d08 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 17 Apr 2026 19:39:28 +0100 Subject: [PATCH] ext/phar: refactor phar_entry_info.link Rename field to symlink so that what this field represents is clear Convert it from a char* to a zend_string* Refactor the implementation of phar_get_link_location() to always return a "new" zend_string* Refactor the implementation of phar_get_link_source() to make it more legible --- ext/phar/func_interceptors.c | 6 +-- ext/phar/phar.c | 6 +-- ext/phar/phar_internal.h | 2 +- ext/phar/phar_object.c | 6 +-- ext/phar/stream.c | 7 ++-- ext/phar/tar.c | 14 +++---- ext/phar/util.c | 80 ++++++++++++++++++------------------ 7 files changed, 61 insertions(+), 60 deletions(-) diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c index 20ce0e8d7258..ae52e7189bd1 100644 --- a/ext/phar/func_interceptors.c +++ b/ext/phar/func_interceptors.c @@ -578,7 +578,7 @@ splitted:; if (!data->is_dir) { sb.st_size = data->uncompressed_filesize; sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; - if (data->link) { + if (data->symlink) { sb.st_mode |= S_IFREG|S_IFLNK; /* regular file */ } else { sb.st_mode |= S_IFREG; /* regular file */ @@ -591,7 +591,7 @@ splitted:; sb.st_size = 0; sb.st_mode = data->flags & PHAR_ENT_PERM_MASK; sb.st_mode |= S_IFDIR; /* regular directory */ - if (data->link) { + if (data->symlink) { sb.st_mode |= S_IFLNK; } /* timestamp is just the timestamp when this was added to the phar */ @@ -803,7 +803,7 @@ PHP_FUNCTION(phar_is_link) /* {{{ */ } zend_string_release_ex(entry, false); if (etemp) { - RETURN_BOOL(etemp->link); + RETURN_BOOL(etemp->symlink); } } RETURN_FALSE; diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 3008316f6274..5829d32e615e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -374,9 +374,9 @@ void destroy_phar_manifest_entry_int(phar_entry_info *entry) /* {{{ */ zend_string_release_ex(entry->filename, entry->is_persistent); - if (entry->link) { - pefree(entry->link, entry->is_persistent); - entry->link = 0; + if (entry->symlink) { + zend_string_release_ex(entry->symlink, entry->is_persistent); + entry->symlink = NULL; } if (entry->tmp) { diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 34f221f43e0e..db2856309fcb 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -217,7 +217,7 @@ typedef struct _phar_entry_info { unsigned int fileinfo_lock_count; char *tmp; phar_archive_data *phar; - char *link; /* symbolic link to another file */ + zend_string *symlink; char tar_type; /* position in the manifest */ uint32_t manifest_pos; diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 07058eefc461..0af02748407a 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1902,7 +1902,7 @@ static zend_result phar_copy_file_contents(phar_entry_info *entry, php_stream *f char *error; zend_off_t offset; - ZEND_ASSERT(!entry->link); + ZEND_ASSERT(!entry->symlink); if (FAILURE == phar_open_entry_fp(entry, &error, true)) { if (error) { @@ -2243,8 +2243,8 @@ static zend_object *phar_convert_to_other(phar_archive_data *source, int convert newentry = *entry; - if (newentry.link) { - newentry.link = estrdup(newentry.link); + if (newentry.symlink) { + zend_string_addref(newentry.symlink); goto no_copy; } diff --git a/ext/phar/stream.c b/ext/phar/stream.c index 455f403b597b..f929aef4fb98 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -368,7 +368,7 @@ static ssize_t phar_stream_read(php_stream *stream, char *buf, size_t count) /* ssize_t got; phar_entry_info *entry; - if (data->internal_file->link) { + if (data->internal_file->symlink) { entry = phar_get_link_source(data->internal_file); } else { entry = data->internal_file; @@ -400,7 +400,7 @@ static int phar_stream_seek(php_stream *stream, zend_off_t offset, int whence, z int res; zend_ulong temp; - if (data->internal_file->link) { + if (data->internal_file->symlink) { entry = phar_get_link_source(data->internal_file); } else { entry = data->internal_file; @@ -838,7 +838,8 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from entry->is_deleted = 1; entry->fp = NULL; ZVAL_UNDEF(&entry->metadata_tracker.val); - entry->link = entry->tmp = NULL; + entry->symlink = NULL; + entry->tmp = NULL; source = entry; /* add to the manifest, and then store the pointer to the new guy in entry diff --git a/ext/phar/tar.c b/ext/phar/tar.c index ef356bfc7a28..844f613983f7 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -492,8 +492,8 @@ zend_result phar_parse_tarfile(php_stream* fp, const char *fname, size_t fname_l entry.is_dir = 0; } - entry.link = NULL; - /* link field is null-terminated unless it has 100 non-null chars. + entry.symlink = NULL; + /* linkname field is null-terminated unless it has 100 non-null chars. * Thus we cannot use strlen. */ linkname_len = zend_strnlen(hdr->linkname, 100); if (entry.tar_type == TAR_LINK) { @@ -506,9 +506,9 @@ zend_result phar_parse_tarfile(php_stream* fp, const char *fname, size_t fname_l phar_destroy_phar_data(myphar); return FAILURE; } - entry.link = estrndup(hdr->linkname, linkname_len); + entry.symlink = zend_string_init(hdr->linkname, linkname_len, false); } else if (entry.tar_type == TAR_SYMLINK) { - entry.link = estrndup(hdr->linkname, linkname_len); + entry.symlink = zend_string_init(hdr->linkname, linkname_len, false); } phar_set_inode(&entry); @@ -779,10 +779,10 @@ static int phar_tar_writeheaders_int(phar_entry_info *entry, void *argument) /* /* calc checksum */ header.typeflag = entry->tar_type; - if (entry->link) { - if (strlcpy(header.linkname, entry->link, sizeof(header.linkname)) >= sizeof(header.linkname)) { + if (entry->symlink) { + if (strlcpy(header.linkname, ZSTR_VAL(entry->symlink), sizeof(header.linkname)) >= sizeof(header.linkname)) { if (fp->error) { - spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, link \"%s\" is too long for format", entry->phar->fname, entry->link); + spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, link \"%s\" is too long for format", entry->phar->fname, ZSTR_VAL(entry->symlink)); } return ZEND_HASH_APPLY_STOP; } diff --git a/ext/phar/util.c b/ext/phar/util.c index 43ed4dd24824..bbfcde8d868d 100644 --- a/ext/phar/util.c +++ b/ext/phar/util.c @@ -38,50 +38,50 @@ static zend_result phar_call_openssl_signverify(bool is_sign, php_stream *fp, ze #endif /* for links to relative location, prepend cwd of the entry */ -static char *phar_get_link_location(phar_entry_info *entry) /* {{{ */ +static zend_string *phar_get_link_location(phar_entry_info *entry) /* {{{ */ { - char *p, *ret = NULL; + ZEND_ASSERT(entry->symlink); - ZEND_ASSERT(entry->link); - - if (entry->link[0] == '/') { - return estrdup(entry->link + 1); + if (ZSTR_VAL(entry->symlink)[0] == '/') { + return zend_string_init(ZSTR_VAL(entry->symlink) + 1, ZSTR_LEN(entry->symlink) - 1, false); } - p = strrchr(ZSTR_VAL(entry->filename), '/'); + const char *p = strrchr(ZSTR_VAL(entry->filename), '/'); if (p) { /* Important: don't modify the original `p` data because it is a shared string. */ zend_string *new_name = zend_string_init(ZSTR_VAL(entry->filename), p - ZSTR_VAL(entry->filename), false); - spprintf(&ret, 0, "%s/%s", ZSTR_VAL(new_name), entry->link); + zend_string *location = zend_string_concat3( + ZSTR_VAL(new_name), ZSTR_LEN(new_name), + ZEND_STRL("/"), + ZSTR_VAL(entry->symlink), ZSTR_LEN(entry->symlink) + ); zend_string_release(entry->filename); entry->filename = new_name; - return ret; + return location; } - return entry->link; + return zend_string_copy(entry->symlink); } /* }}} */ phar_entry_info *phar_get_link_source(phar_entry_info *entry) /* {{{ */ { phar_entry_info *link_entry; - char *link; - if (!entry->link) { + if (!entry->symlink) { return entry; } - link = phar_get_link_location(entry); - if (NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), entry->link, strlen(entry->link))) || - NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), link, strlen(link)))) { - if (link != entry->link) { - efree(link); - } + link_entry = zend_hash_find_ptr(&(entry->phar->manifest), entry->symlink); + if (link_entry) { return phar_get_link_source(link_entry); - } else { - if (link != entry->link) { - efree(link); - } - return NULL; } + + zend_string *link = phar_get_link_location(entry); + link_entry = zend_hash_find_ptr(&(entry->phar->manifest), link); + zend_string_release(link); + if (link_entry) { + return phar_get_link_source(link_entry); + } + return NULL; } /* }}} */ @@ -96,7 +96,7 @@ static php_stream *phar_get_entrypufp(const phar_entry_info *entry) /* retrieve a phar_entry_info's current file pointer for reading contents */ php_stream *phar_get_efp(phar_entry_info *entry, bool follow_links) /* {{{ */ { - if (follow_links && entry->link) { + if (follow_links && entry->symlink) { phar_entry_info *link_entry = phar_get_link_source(entry); if (link_entry && link_entry != entry) { @@ -387,9 +387,9 @@ static ZEND_ATTRIBUTE_NONNULL zend_result phar_create_writeable_entry(phar_archi } /* open a new temp file for writing */ - if (entry->link) { - efree(entry->link); - entry->link = NULL; + if (entry->symlink) { + zend_string_release(entry->symlink); + entry->symlink = NULL; entry->tar_type = (entry->is_tar ? TAR_FILE : '\0'); } @@ -444,9 +444,9 @@ ZEND_ATTRIBUTE_NONNULL static zend_result phar_separate_entry_fp(phar_entry_info return FAILURE; } - if (entry->link) { - efree(entry->link); - entry->link = NULL; + if (entry->symlink) { + zend_string_release(entry->symlink); + entry->symlink = NULL; entry->tar_type = (entry->is_tar ? TAR_FILE : '\0'); } @@ -559,9 +559,9 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, co } } else { if (for_write) { - if (entry->link) { - efree(entry->link); - entry->link = NULL; + if (entry->symlink) { + zend_string_release(entry->symlink); + entry->symlink = NULL; entry->tar_type = (entry->is_tar ? TAR_FILE : '\0'); } @@ -586,7 +586,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_get_entry_data(phar_entry_data **ret, co (*ret)->phar = phar; (*ret)->internal_file = entry; (*ret)->fp = phar_get_efp(entry, true); - if (entry->link) { + if (entry->symlink) { phar_entry_info *link = phar_get_link_source(entry); if(!link) { efree(*ret); @@ -740,9 +740,9 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_copy_entry_fp(phar_entry_info *source, p return FAILURE; } - if (dest->link) { - efree(dest->link); - dest->link = NULL; + if (dest->symlink) { + zend_string_release(dest->symlink); + dest->symlink = NULL; dest->tar_type = (dest->is_tar ? TAR_FILE : '\0'); } @@ -807,7 +807,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_open_entry_fp(phar_entry_info *entry, ch php_stream *ufp; phar_entry_data dummy; - if (follow_links && entry->link) { + if (follow_links && entry->symlink) { phar_entry_info *link_entry = phar_get_link_source(entry); if (link_entry && link_entry != entry) { return phar_open_entry_fp(link_entry, error, true); @@ -1995,8 +1995,8 @@ static int phar_update_cached_entry(zval *data, void *argument) /* {{{ */ entry->phar = (phar_archive_data *)argument; - if (entry->link) { - entry->link = estrdup(entry->link); + if (entry->symlink) { + zend_string_addref(entry->symlink); } if (entry->tmp) {