summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Beaver <cellog@php.net>2008-04-21 06:17:51 +0000
committerGreg Beaver <cellog@php.net>2008-04-21 06:17:51 +0000
commit3d858f4aa9b0eb47ad015b4d13b447baa836cf6f (patch)
treed2049285a4422ff39c2f88e8aa443abefe98aee6
parent7fe0ed87fb6be3e971d2bb1e9b7803bc77ad0536 (diff)
downloadphp-git-3d858f4aa9b0eb47ad015b4d13b447baa836cf6f.tar.gz
implement symbolic link support within a tar-based phar archive
this also resulted in a major fix for mounted directories, which were recycling the 'link' field which could cause stupid conflicts with actual links, so move that to new 'tmp' field.
-rw-r--r--ext/phar/dirstream.c2
-rw-r--r--ext/phar/phar.c22
-rwxr-xr-xext/phar/phar_internal.h8
-rwxr-xr-xext/phar/phar_object.c37
-rw-r--r--ext/phar/stream.c6
-rw-r--r--ext/phar/tar.c34
-rw-r--r--ext/phar/tests/tar/files/corrupt_tarmaker.php.inc22
-rw-r--r--ext/phar/tests/tar/links.phpt11
-rw-r--r--ext/phar/util.c160
-rw-r--r--ext/phar/zip.c14
10 files changed, 224 insertions, 92 deletions
diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
index 7bc3a80bc3..1d372829fd 100644
--- a/ext/phar/dirstream.c
+++ b/ext/phar/dirstream.c
@@ -364,7 +364,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path, char
/*if (entry->is_mounted) {
external directory, TODO: construct an internal dirstream based on this actual dir's dirstream
php_url_free(resource);
- return php_stream_opendir(entry->link, options, context);
+ return php_stream_opendir(entry->tmp, options, context);
}*/
internal_file = estrdup(internal_file);
php_url_free(resource);
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index b429b3aab7..7b5e3e3229 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -330,6 +330,10 @@ void destroy_phar_manifest_entry(void *pDest) /* {{{ */
efree(entry->link);
entry->link = 0;
}
+ if (entry->tmp) {
+ efree(entry->tmp);
+ entry->tmp = 0;
+ }
}
/* }}} */
@@ -1781,7 +1785,9 @@ char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC) /* {{{ */
{
const char *ext_str;
+#ifdef PHP_WIN32
char *save;
+#endif
int ext_len, free_filename = 0;
if (!strncasecmp(filename, "phar://", 7)) {
@@ -1800,7 +1806,11 @@ int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_le
if (ext_len != -1) {
if (!ext_str) {
/* no / detected, restore arch for error message */
+#ifdef PHP_WIN32
*arch = save;
+#else
+ *arch = filename;
+#endif
}
if (free_filename) {
efree(filename);
@@ -2246,7 +2256,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
if ((oldfile && !entry->is_modified) || entry->is_dir) {
continue;
}
- if (!phar_get_efp(entry TSRMLS_CC)) {
+ if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
/* re-open internal file pointer just-in-time */
newentry = phar_open_jit(phar, entry, oldfile, error, 0 TSRMLS_CC);
if (!newentry) {
@@ -2257,8 +2267,8 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
}
entry = newentry;
}
- file = phar_get_efp(entry TSRMLS_CC);
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
+ file = phar_get_efp(entry, 0 TSRMLS_CC);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
@@ -2313,7 +2323,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
return EOF;
}
php_stream_flush(file);
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
@@ -2507,8 +2517,8 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
file = entry->cfp;
php_stream_rewind(file);
} else {
- file = phar_get_efp(entry TSRMLS_CC);
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
+ file = phar_get_efp(entry, 0 TSRMLS_CC);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
if (closeoldfile) {
php_stream_close(oldfile);
}
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index b6f6bf49d6..aab5b3fd02 100755
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -244,6 +244,7 @@ typedef struct _phar_entry_info {
/* this flag is used for mounted entries (external files mapped to location
inside a phar */
int is_mounted:1;
+ char *tmp;
/* used when iterating */
int is_temp_dir:1;
phar_archive_data *phar;
@@ -404,10 +405,11 @@ phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry,
char **error, int for_write TSRMLS_DC);
int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSRMLS_DC);
void destroy_phar_manifest_entry(void *pDest);
-int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position TSRMLS_DC);
-php_stream *phar_get_efp(phar_entry_info *entry TSRMLS_DC);
+int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC);
+php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC);
int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC);
-int phar_open_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC);
+int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC);
+phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC);
int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC);
int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC);
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c
index a1b01a4a17..d486a2888b 100755
--- a/ext/phar/phar_object.c
+++ b/ext/phar/phar_object.c
@@ -237,7 +237,7 @@ static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, ch
}
/* prepare to output */
- if (!phar_get_efp(phar->internal_file TSRMLS_CC)) {
+ if (!phar_get_efp(phar->internal_file, 1 TSRMLS_CC)) {
char *error;
if (!phar_open_jit(phar->phar, phar->internal_file, phar->phar->fp, &error, 0 TSRMLS_CC)) {
if (error) {
@@ -246,10 +246,10 @@ static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, ch
}
return -1;
}
- phar->fp = phar_get_efp(phar->internal_file TSRMLS_CC);
+ phar->fp = phar_get_efp(phar->internal_file, 1 TSRMLS_CC);
phar->zero = phar->internal_file->offset;
}
- phar_seek_efp(phar->internal_file, 0, SEEK_SET, 0 TSRMLS_CC);
+ phar_seek_efp(phar->internal_file, 0, SEEK_SET, 0, 1 TSRMLS_CC);
do {
got = php_stream_read(phar->fp, buf, MIN(8192, phar->internal_file->uncompressed_filesize - phar->position));
PHPWRITE(buf, got);
@@ -1580,8 +1580,9 @@ static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS
{
char *error;
off_t offset;
+ phar_entry_info *link;
- if (FAILURE == phar_open_entry_fp(entry, &error TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, &error, 1 TSRMLS_CC)) {
if (error) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error);
@@ -1593,9 +1594,13 @@ static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS
return FAILURE;
}
/* copy old contents in entirety */
- phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC);
+ phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
offset = php_stream_tell(fp);
- if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry TSRMLS_CC), fp, entry->uncompressed_filesize)) {
+ link = phar_get_link_source(entry TSRMLS_CC);
+ if (!link) {
+ link = entry;
+ }
+ if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) {
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC,
"Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename);
return FAILURE;
@@ -3642,6 +3647,7 @@ PHP_METHOD(PharFileInfo, getContent)
{
char *error;
php_stream *fp;
+ phar_entry_info *link;
PHAR_ENTRY_OBJECT();
if (entry_obj->ent.entry->is_dir) {
@@ -3649,20 +3655,27 @@ PHP_METHOD(PharFileInfo, getContent)
"Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\" is a directory", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
return;
}
- if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error TSRMLS_CC)) {
+ link = phar_get_link_source(entry_obj->ent.entry TSRMLS_CC);
+ if (!link) {
+ link = entry_obj->ent.entry;
+ }
+ if (SUCCESS != phar_open_entry_fp(link, &error, 0 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar error: Cannot retrieve contents, \"%s\" in phar \"%s\": %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
efree(error);
return;
}
- if (!(fp = phar_get_efp(entry_obj->ent.entry TSRMLS_CC))) {
+ if (!(fp = phar_get_efp(link, 0 TSRMLS_CC))) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar error: Cannot retrieve contents of \"%s\" in phar \"%s\"", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname);
return;
}
- phar_seek_efp(entry_obj->ent.entry, 0, SEEK_SET, 0 TSRMLS_CC);
+ phar_seek_efp(link, 0, SEEK_SET, 0, 0 TSRMLS_CC);
Z_TYPE_P(return_value) = IS_STRING;
- Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), entry_obj->ent.entry->uncompressed_filesize, 0);
+ Z_STRLEN_P(return_value) = php_stream_copy_to_mem(fp, &(Z_STRVAL_P(return_value)), link->uncompressed_filesize, 0);
+ if (!Z_STRVAL_P(return_value)) {
+ Z_STRVAL_P(return_value) = estrndup("", 0);
+ }
}
/* }}} */
@@ -3713,7 +3726,7 @@ PHP_METHOD(PharFileInfo, compress)
return;
}
/* decompress this file indirectly */
- if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error TSRMLS_CC)) {
+ if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar error: Cannot decompress bzip2-compressed file \"%s\" in phar \"%s\" in order to compress with gzip: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
efree(error);
@@ -3741,7 +3754,7 @@ PHP_METHOD(PharFileInfo, compress)
return;
}
/* decompress this file indirectly */
- if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error TSRMLS_CC)) {
+ if (SUCCESS != phar_open_entry_fp(entry_obj->ent.entry, &error, 1 TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC,
"Phar error: Cannot decompress gzip-compressed file \"%s\" in phar \"%s\" in order to compress with bzip2: %s", entry_obj->ent.entry->filename, entry_obj->ent.entry->phar->fname, error);
efree(error);
diff --git a/ext/phar/stream.c b/ext/phar/stream.c
index d8341b7830..ac879d3cd8 100644
--- a/ext/phar/stream.c
+++ b/ext/phar/stream.c
@@ -618,10 +618,10 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
if (SUCCESS != zend_hash_find(&phar->manifest, key, keylen, (void **) &entry)) {
goto free_resource;
}
- if (!entry->link || !entry->is_mounted) {
+ if (!entry->tmp || !entry->is_mounted) {
goto free_resource;
}
- test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->link, internal_file + keylen);
+ test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
efree(test);
continue;
@@ -844,7 +844,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
entry->is_deleted = 1;
entry->fp = NULL;
entry->metadata = 0;
- entry->link = NULL;
+ entry->link = 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 ca13e5ba1b..b4cb09d05c 100644
--- a/ext/phar/tar.c
+++ b/ext/phar/tar.c
@@ -260,7 +260,7 @@ int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, i
if (entry.tar_type == TAR_LINK) {
if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
if (error) {
- spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file", fname);
+ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
}
efree(entry.filename);
php_stream_close(fp);
@@ -436,25 +436,27 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
pos = php_stream_tell(fp->new); /* save start of file within tar */
/* write contents */
- if (FAILURE == phar_open_entry_fp(entry, fp->error TSRMLS_CC)) {
- return ZEND_HASH_APPLY_STOP;
- }
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
- if (fp->error) {
- spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written, seek failed", entry->phar->fname, entry->filename);
+ if (entry->uncompressed_filesize) {
+ if (FAILURE == phar_open_entry_fp(entry, fp->error, 0 TSRMLS_CC)) {
+ return ZEND_HASH_APPLY_STOP;
}
- return ZEND_HASH_APPLY_STOP;
- }
- if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry TSRMLS_CC), fp->new, entry->uncompressed_filesize)) {
- if (fp->error) {
- spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename);
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written, seek failed", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
}
- return ZEND_HASH_APPLY_STOP;
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), fp->new, entry->uncompressed_filesize)) {
+ if (fp->error) {
+ spprintf(fp->error, 4096, "tar-based phar \"%s\" cannot be created, contents of file \"%s\" could not be written", entry->phar->fname, entry->filename);
+ }
+ return ZEND_HASH_APPLY_STOP;
+ }
+
+ memset(padding, 0, 512);
+ php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
}
- memset(padding, 0, 512);
- php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
-
entry->is_modified = 0;
if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
if (!entry->fp_refcount) {
diff --git a/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc b/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc
index d8b8bc20ac..b0eba6cc69 100644
--- a/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc
+++ b/ext/phar/tests/tar/files/corrupt_tarmaker.php.inc
@@ -56,16 +56,20 @@ class corrupt_tarmaker
}
$link = null;
- if ($stat['mode'] & 0x4000) {
- $type = 5; // Directory
- } else if ($stat['mode'] & 0x8000) {
- $type = 0; // Regular
- } else if ($stat['mode'] & 0xA000 && $corrupt = 'symlink') {
+ if ($stat['mode'] & 0xA000 && $corrupt === 'symlink') {
$type = 2; // Symbolic Link
- $link = 'file1.txt';
+ $link = $fileOrStream;
+ $stat['size'] = 0;
+ $fileOrStream = '';
} else if ($stat['mode'] & 0xA000) {
$type = 1; // Link
- $link = 'file1.txt';
+ $link = $fileOrStream;
+ $stat['size'] = 0;
+ $fileOrStream = '';
+ } else if ($stat['mode'] & 0x4000) {
+ $type = 5; // Directory
+ } else if ($stat['mode'] & 0x8000) {
+ $type = 0; // Regular
} else {
$type = 9; // Unknown
}
@@ -108,7 +112,7 @@ class corrupt_tarmaker
$checksum = 256; // 8 * ord(' ');
$checksum += array_reduce($checkheader, '_pear2tarchecksum');
- if ($corrupt == 'checksum') $checksum++;
+ if ($corrupt === 'checksum') $checksum++;
$checksum = pack('a8', sprintf('%6s ', decoct($checksum)));
fwrite($this->tmp, $block . $checksum . $blockend, 512);
@@ -119,7 +123,7 @@ class corrupt_tarmaker
}
} else {
fwrite($this->tmp, $fileOrStream);
- if (strlen($fileOrStream) % 512) {
+ if (strlen($fileOrStream) && !isset($link) && strlen($fileOrStream) % 512) {
fwrite($this->tmp, str_repeat("\0", 512 - strlen($fileOrStream) % 512));
}
}
diff --git a/ext/phar/tests/tar/links.phpt b/ext/phar/tests/tar/links.phpt
index 2e0fdcbf65..e67efab5ad 100644
--- a/ext/phar/tests/tar/links.phpt
+++ b/ext/phar/tests/tar/links.phpt
@@ -18,8 +18,11 @@ var_dump($p['testit/file']->getContent());
<?php
unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.tar');
?>
---EXPECTF--
-string(2) "hi"
-string(2) "hi"
-string(2) "hi"
+--EXPECT--
+string(3) "hi
+"
+string(3) "hi
+"
+string(3) "hi
+"
===DONE===
diff --git a/ext/phar/util.c b/ext/phar/util.c
index 1099464fce..ba10c960ea 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -25,9 +25,61 @@
extern php_stream_wrapper php_stream_phar_wrapper;
#endif
+/* for links to relative location, prepend cwd of the entry */
+static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC)
+{
+ char *tmp, *ret, *p;
+ if (!entry->link) {
+ return NULL;
+ }
+ if (entry->link[0] == '/') {
+ return entry->link;
+ }
+ tmp = estrndup(entry->filename, entry->filename_len);
+ p = strrchr(tmp, '/');
+ if (p) {
+ *p = '\0';
+ spprintf(&ret, 0, "%s/%s", tmp, entry->link);
+ efree(tmp);
+ return ret;
+ }
+ efree(ret);
+ return entry->link;
+}
+
+phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC)
+{
+ phar_entry_info *link_entry;
+ char *link = phar_get_link_location(entry);
+
+ if (!entry->link) {
+ return entry;
+ }
+
+ if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
+ SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
+ if (link != entry->link) {
+ efree(link);
+ }
+ return phar_get_link_source(link_entry TSRMLS_CC);
+ } else {
+ if (link != entry->link) {
+ efree(link);
+ }
+ return NULL;
+ }
+}
+
/* retrieve a phar_entry_info's current file pointer for reading contents */
-php_stream *phar_get_efp(phar_entry_info *entry TSRMLS_DC)
+php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC)
{
+ if (follow_links && entry->link) {
+ phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
+
+ if (link_entry && link_entry != entry) {
+ return phar_get_efp(link_entry, 1 TSRMLS_CC);
+ }
+ }
if (entry->fp_type == PHAR_FP) {
if (!entry->phar->fp) {
/* re-open just in time for cases where our refcount reached 0 on the phar archive */
@@ -41,17 +93,24 @@ php_stream *phar_get_efp(phar_entry_info *entry TSRMLS_DC)
} else {
/* temporary manifest entry */
if (!entry->fp) {
- entry->fp = php_stream_open_wrapper(entry->link, "rb", STREAM_MUST_SEEK|0, NULL);
+ entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
}
return entry->fp;
}
}
-int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position TSRMLS_DC)
+int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC)
{
- php_stream *fp = phar_get_efp(entry TSRMLS_CC);
+ php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
off_t temp;
+ if (follow_links) {
+ phar_entry_info *t;
+ t = phar_get_link_source(entry TSRMLS_CC);
+ if (t) {
+ entry = t;
+ }
+ }
if (entry->is_dir) {
return 0;
}
@@ -94,26 +153,26 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
#endif
entry.filename_len = path_len;
if (strstr(filename, "phar://")) {
- entry.link = estrndup(filename, filename_len);
+ entry.tmp = estrndup(filename, filename_len);
} else {
- entry.link = expand_filepath(filename, NULL TSRMLS_CC);
- if (!entry.link) {
- entry.link = estrndup(filename, filename_len);
+ entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
+ if (!entry.tmp) {
+ entry.tmp = estrndup(filename, filename_len);
}
}
#if PHP_MAJOR_VERSION < 6
- if (PG(safe_mode) && !strstr(filename, "phar://") && (!php_checkuid(entry.link, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
- efree(entry.link);
+ if (PG(safe_mode) && !strstr(filename, "phar://") && (!php_checkuid(entry.tmp, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
#endif
- filename_len = strlen(entry.link);
- filename = entry.link;
+ filename_len = strlen(entry.tmp);
+ filename = entry.tmp;
/* only check openbasedir for files, not for phar streams */
if (!strstr(filename, "phar://") && php_check_open_basedir(filename TSRMLS_CC)) {
- efree(entry.link);
+ efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
@@ -122,7 +181,7 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
entry.fp_type = PHAR_TMP;
if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
- efree(entry.link);
+ efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
@@ -130,7 +189,7 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
entry.is_dir = 1;
if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
/* directory already mounted */
- efree(entry.link);
+ efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
@@ -142,7 +201,7 @@ int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len,
if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
return SUCCESS;
}
- efree(entry.link);
+ efree(entry.tmp);
efree(entry.filename);
return FAILURE;
}
@@ -487,9 +546,14 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
return FAILURE;
}
} else if (for_append) {
- phar_seek_efp(entry, 0, SEEK_END, 0 TSRMLS_CC);
+ phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
}
} else {
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = NULL;
+ entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
+ }
if (for_write) {
if (for_trunc) {
if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
@@ -501,7 +565,7 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
}
}
} else {
- if (FAILURE == phar_open_entry_fp(entry, error TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
return FAILURE;
}
}
@@ -513,7 +577,7 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
(*ret)->internal_file = entry;
(*ret)->is_zip = entry->is_zip;
(*ret)->is_tar = entry->is_tar;
- (*ret)->fp = phar_get_efp(entry TSRMLS_CC);
+ (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
(*ret)->zero = entry->offset;
++(entry->fp_refcount);
++(entry->phar->refcount);
@@ -637,16 +701,27 @@ int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC)
/* copy file data from an existing to a new phar_entry_info that is not in the manifest */
int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC)
{
- if (FAILURE == phar_open_entry_fp(source, error TSRMLS_CC)) {
+ phar_entry_info *link;
+
+ if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
return FAILURE;
}
+ if (dest->link) {
+ efree(dest->link);
+ dest->link = NULL;
+ dest->tar_type = (dest->tar_type ? TAR_FILE : 0);
+ }
dest->fp_type = PHAR_MOD;
dest->offset = 0;
dest->is_modified = 1;
dest->fp = php_stream_fopen_tmpfile();
- phar_seek_efp(source, 0, SEEK_SET, 0 TSRMLS_CC);
- if (source->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(source TSRMLS_CC), dest->fp, source->uncompressed_filesize)) {
+ phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ link = phar_get_link_source(source TSRMLS_CC);
+ if (!link) {
+ link = source;
+ }
+ if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize)) {
php_stream_close(dest->fp);
dest->fp_type = PHAR_FP;
if (error) {
@@ -659,16 +734,23 @@ int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **er
/* open and decompress a compressed phar entry
*/
-int phar_open_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC)
+int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC)
{
php_stream_filter *filter;
phar_archive_data *phar = entry->phar;
char *filtername;
off_t loc;
+ if (follow_links && entry->link) {
+ phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
+
+ if (link_entry && link_entry != entry) {
+ return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
+ }
+ }
if (entry->fp_type == PHAR_TMP) {
if (!entry->fp) {
- entry->fp = php_stream_open_wrapper(entry->link, "rb", STREAM_MUST_SEEK|0, NULL);
+ entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
}
return SUCCESS;
}
@@ -786,6 +868,11 @@ int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry,
*error = NULL;
}
/* open a new temp file for writing */
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = NULL;
+ entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
+ }
entry->fp = php_stream_fopen_tmpfile();
if (!entry->fp) {
if (error) {
@@ -810,8 +897,9 @@ int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry,
int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC)
{
php_stream *fp;
+ phar_entry_info *link;
- if (FAILURE == phar_open_entry_fp(entry, error TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
return FAILURE;
}
@@ -820,14 +908,24 @@ int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC)
}
fp = php_stream_fopen_tmpfile();
- phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC);
- if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry TSRMLS_CC), fp, entry->uncompressed_filesize)) {
+ phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ link = phar_get_link_source(entry TSRMLS_CC);
+ if (!link) {
+ link = entry;
+ }
+ if (link->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize)) {
if (error) {
spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
}
return FAILURE;
}
+ if (entry->link) {
+ efree(entry->link);
+ entry->link = NULL;
+ entry->tar_type = (entry->tar_type ? TAR_FILE : 0);
+ }
+
entry->offset = 0;
entry->fp = fp;
entry->fp_type = PHAR_MOD;
@@ -845,10 +943,10 @@ phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry,
*error = NULL;
}
/* seek to start of internal file and read it */
- if (FAILURE == phar_open_entry_fp(entry, error TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
return NULL;
}
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
return NULL;
}
@@ -1050,13 +1148,13 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in
}
return NULL;
}
- if (!entry->link || !entry->is_mounted) {
+ if (!entry->tmp || !entry->is_mounted) {
if (error) {
spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", key);
}
return NULL;
}
- test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->link, path + keylen);
+ test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
if (SUCCESS != php_stream_stat_path(test, &ssb)) {
efree(test);
return NULL;
diff --git a/ext/phar/zip.c b/ext/phar/zip.c
index cd35b874fa..886cb20c5d 100644
--- a/ext/phar/zip.c
+++ b/ext/phar/zip.c
@@ -539,15 +539,15 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
}
goto continue_dir;
}
- if (FAILURE == phar_open_entry_fp(entry, p->error TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP;
}
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP;
}
- efp = phar_get_efp(entry TSRMLS_CC);
+ efp = phar_get_efp(entry, 0 TSRMLS_CC);
newcrc32 = ~0;
for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
@@ -580,7 +580,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
return ZEND_HASH_APPLY_STOP;
}
php_stream_flush(efp);
- if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC)) {
+ if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP;
}
@@ -676,11 +676,11 @@ continue_dir:
php_stream_close(entry->cfp);
entry->cfp = NULL;
} else {
- if (FAILURE == phar_open_entry_fp(entry, p->error TSRMLS_CC)) {
+ if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
return ZEND_HASH_APPLY_STOP;
}
- phar_seek_efp(entry, 0, SEEK_SET, 0 TSRMLS_CC);
- if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry TSRMLS_CC), p->filefp, entry->uncompressed_filesize)) {
+ phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC);
+ if (entry->uncompressed_filesize != php_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize)) {
spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
return ZEND_HASH_APPLY_STOP;
}