Commit b33fee51fb7 for php.net
commit b33fee51fb7ab5b919faf71507c45e86cf2bd978
Author: Gina Peter Banyard <girgias@php.net>
Date: Sat Apr 18 16:27:22 2026 +0100
ext/phar: refactor phar_entry_info.link field (#21790)
- 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
diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c
index 20ce0e8d725..ae52e7189bd 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 3008316f627..5829d32e615 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 34f221f43e0..db2856309fc 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 07058eefc46..0af02748407 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 455f403b597..f929aef4fb9 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 ef356bfc7a2..844f613983f 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 43ed4dd2482..bbfcde8d868 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) {