fix stat of directory in tar/zip

improve phar recognition of tar/zip-based phars in phar_compile_file
fix segfault in Phar::webPhar() with invalid redirect
add Phar->isTar()/isZip()/isPhar() to determine internal file format
fix creation of tar-based phars from filename in some circumstances
fix read of corrupted file contents from a tar if the tar had been opened readonly and then modified
ensure directories are marked with is_dir in tar file format entries
copy fp_refcount logic into phar_tar_flush() from phar_flush()
fix segfault when flushing a tar with a new stub/alias
This commit is contained in:
Greg Beaver 2008-01-07 05:41:09 +00:00
parent ff1c8b2beb
commit 8a46146f37
3 changed files with 91 additions and 37 deletions

View file

@ -4027,6 +4027,20 @@ static void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stre
ssb->sb.st_mtime = data->timestamp; ssb->sb.st_mtime = data->timestamp;
ssb->sb.st_atime = data->timestamp; ssb->sb.st_atime = data->timestamp;
ssb->sb.st_ctime = data->timestamp; ssb->sb.st_ctime = data->timestamp;
#endif
} else if (!is_dir && data->is_dir && (data->is_tar || data->is_zip)) {
ssb->sb.st_size = 0;
ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
ssb->sb.st_mode |= S_IFDIR; /* regular directory */
/* timestamp is just the timestamp when this was added to the phar */
#ifdef NETWARE
ssb->sb.st_mtime.tv_sec = data->timestamp;
ssb->sb.st_atime.tv_sec = data->timestamp;
ssb->sb.st_ctime.tv_sec = data->timestamp;
#else
ssb->sb.st_mtime = data->timestamp;
ssb->sb.st_atime = data->timestamp;
ssb->sb.st_ctime = data->timestamp;
#endif #endif
} else { } else {
ssb->sb.st_size = 0; ssb->sb.st_size = 0;
@ -4719,14 +4733,16 @@ static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type
char *fname = NULL; char *fname = NULL;
int fname_len, failed; int fname_len, failed;
zend_op_array *(*save)(zend_file_handle *file_handle, int type TSRMLS_DC); zend_op_array *(*save)(zend_file_handle *file_handle, int type TSRMLS_DC);
phar_archive_data *phar;
save = zend_compile_file; /* restore current handler or we cause trouble */ save = zend_compile_file; /* restore current handler or we cause trouble */
zend_compile_file = phar_orig_compile_file; zend_compile_file = phar_orig_compile_file;
fname = zend_get_executed_filename(TSRMLS_C); fname = zend_get_executed_filename(TSRMLS_C);
fname_len = strlen(fname); fname_len = strlen(fname);
if (fname_len == sizeof("[no active file]")-1 && !strncmp(fname, "[no active file]", fname_len)) { if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, ":\\")) {
if (strstr(file_handle->filename, ".phar.zip") && !strstr(file_handle->filename, ":\\")) { if (SUCCESS == phar_open_filename(file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
if (phar->is_zip || phar->is_tar) {
/* zip-based phar */ /* zip-based phar */
spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php"); spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
file_handle->type = ZEND_HANDLE_FILENAME; file_handle->type = ZEND_HANDLE_FILENAME;
@ -4737,16 +4753,6 @@ static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type
} }
goto skip_phar; goto skip_phar;
} }
if (strstr(file_handle->filename, ".phar.tar") && !strstr(file_handle->filename, ":\\")) {
/* tar-based phar */
spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
file_handle->type = ZEND_HANDLE_FILENAME;
file_handle->free_filename = 1;
file_handle->filename = name;
if (file_handle->opened_path) {
efree(file_handle->opened_path);
}
goto skip_phar;
} }
} }
if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {

View file

@ -382,7 +382,7 @@ PHP_METHOD(Phar, webPhar)
if (strstr(fname, "://")) { if (strstr(fname, "://")) {
char *arch, *entry; char *arch, *entry;
int arch_len, entry_len; int arch_len, entry_len;
phar_archive_data *phar; phar_archive_data *mphar;
/* running within a zip-based phar, acquire the actual name */ /* running within a zip-based phar, acquire the actual name */
if (SUCCESS != phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) { if (SUCCESS != phar_split_fname(fname, fname_len, &arch, &arch_len, &entry, &entry_len TSRMLS_CC)) {
@ -395,10 +395,10 @@ PHP_METHOD(Phar, webPhar)
entry = fname; entry = fname;
fname = arch; fname = arch;
fname_len = arch_len; fname_len = arch_len;
if (SUCCESS == phar_open_loaded(fname, fname_len, alias, alias_len, 0, &phar, 0 TSRMLS_CC) && phar && (phar->is_zip || phar->is_tar)) { if (SUCCESS == phar_open_loaded(fname, fname_len, alias, alias_len, 0, &mphar, 0 TSRMLS_CC) && mphar && (phar->is_zip || phar->is_tar)) {
efree(arch); efree(arch);
fname = phar->fname; fname = mphar->fname;
fname_len = phar->fname_len; fname_len = mphar->fname_len;
} else { } else {
efree(arch); efree(arch);
fname = entry; fname = entry;
@ -476,7 +476,6 @@ PHP_METHOD(Phar, webPhar)
/* check for "rewrite" urls */ /* check for "rewrite" urls */
if (SUCCESS == zend_hash_find(Z_ARRVAL_P(rewrites), entry, entry_len+1, (void **) &fd_ptr)) { if (SUCCESS == zend_hash_find(Z_ARRVAL_P(rewrites), entry, entry_len+1, (void **) &fd_ptr)) {
if (IS_STRING != Z_TYPE_PP(fd_ptr)) { if (IS_STRING != Z_TYPE_PP(fd_ptr)) {
phar_entry_delref(phar TSRMLS_CC);
#ifdef PHP_WIN32 #ifdef PHP_WIN32
efree(fname); efree(fname);
#endif #endif
@ -1218,6 +1217,39 @@ PHP_METHOD(Phar, count)
} }
/* }}} */ /* }}} */
/* {{{ proto bool Phar::isTar()
* Returns true if the phar archive is based on the tar file format
*/
PHP_METHOD(Phar, isTar)
{
PHAR_ARCHIVE_OBJECT();
RETURN_BOOL(phar_obj->arc.archive->is_tar);
}
/* }}} */
/* {{{ proto bool Phar::isZip()
* Returns true if the phar archive is based on the Zip file format
*/
PHP_METHOD(Phar, isZip)
{
PHAR_ARCHIVE_OBJECT();
RETURN_BOOL(phar_obj->arc.archive->is_zip);
}
/* }}} */
/* {{{ proto bool Phar::isPhar()
* Returns true if the phar archive is based on the phar file format
*/
PHP_METHOD(Phar, isPhar)
{
PHAR_ARCHIVE_OBJECT();
RETURN_BOOL(!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip);
}
/* }}} */
/* {{{ proto bool Phar::delete(string file) /* {{{ proto bool Phar::delete(string file)
* Delete a file from within the Phar * Delete a file from within the Phar
*/ */
@ -2217,8 +2249,8 @@ PHP_METHOD(PharFileInfo, __destruct)
{ {
PHAR_ENTRY_OBJECT(); PHAR_ENTRY_OBJECT();
if (entry_obj->ent.entry->is_dir) { if (entry_obj->ent.entry->is_dir&& !entry_obj->ent.entry->is_zip && !entry_obj->ent.entry->is_tar) {
if (!entry_obj->ent.entry->is_zip && !entry_obj->ent.entry->is_tar && entry_obj->ent.entry->filename) { if (entry_obj->ent.entry->filename) {
efree(entry_obj->ent.entry->filename); efree(entry_obj->ent.entry->filename);
entry_obj->ent.entry->filename = NULL; entry_obj->ent.entry->filename = NULL;
} }
@ -2323,7 +2355,7 @@ PHP_METHOD(PharFileInfo, chmod)
long perms; long perms;
PHAR_ENTRY_OBJECT(); PHAR_ENTRY_OBJECT();
if (entry_obj->ent.entry->is_dir) { if (entry_obj->ent.entry->is_dir && (!entry_obj->ent.entry->is_tar && !entry_obj->ent.entry->is_zip)) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, \
"Phar entry is a directory, cannot chmod"); \ "Phar entry is a directory, cannot chmod"); \
} }
@ -2728,6 +2760,9 @@ zend_function_entry php_archive_methods[] = {
PHP_ME(Phar, offsetUnset, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC) PHP_ME(Phar, offsetUnset, arginfo_phar_offsetExists, ZEND_ACC_PUBLIC)
PHP_ME(Phar, uncompressAllFiles, NULL, ZEND_ACC_PUBLIC) PHP_ME(Phar, uncompressAllFiles, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Phar, buildFromIterator, arginfo_phar_build, ZEND_ACC_PUBLIC) PHP_ME(Phar, buildFromIterator, arginfo_phar_build, ZEND_ACC_PUBLIC)
PHP_ME(Phar, isTar, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Phar, isZip, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Phar, isPhar, NULL, ZEND_ACC_PUBLIC)
#endif #endif
/* static member functions */ /* static member functions */
PHP_ME(Phar, apiVersion, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) PHP_ME(Phar, apiVersion, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL)

View file

@ -125,18 +125,20 @@ int phar_is_tar(char *buf)
int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
{ {
phar_archive_data *phar; phar_archive_data *phar;
int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, options, &phar, error TSRMLS_CC);
if (pphar) {
*pphar = phar;
}
if (FAILURE == ret) { if (FAILURE == ret) {
return FAILURE; return FAILURE;
} }
if ((*pphar)->is_tar) { if (phar->is_tar) {
return ret; return ret;
} }
phar = *pphar;
if (phar->is_brandnew) { if (phar->is_brandnew) {
phar->is_tar = 1; phar->is_tar = 1;
phar->internal_file_start = 0;
return SUCCESS; return SUCCESS;
} }
@ -231,6 +233,9 @@ int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, i
if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) { if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry.flags)) {
entry.tar_type = TAR_DIR; entry.tar_type = TAR_DIR;
} }
if (entry.tar_type == TAR_DIR) {
entry.is_dir = 1;
}
entry.link = NULL; entry.link = NULL;
if (entry.tar_type == TAR_LINK) { if (entry.tar_type == TAR_LINK) {
@ -366,7 +371,11 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
if (entry->fp) { if (entry->fp) {
/* new file */ /* new file */
file = entry->fp; file = entry->fp;
if (file == entry->phar->fp) {
php_stream_seek(file, entry->offset_within_phar, SEEK_SET);
} else {
php_stream_seek(file, 0, SEEK_SET); php_stream_seek(file, 0, SEEK_SET);
}
} else { } else {
file = fp->old; file = fp->old;
php_stream_seek(file, entry->offset_within_phar, SEEK_SET); php_stream_seek(file, entry->offset_within_phar, SEEK_SET);
@ -381,10 +390,13 @@ int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC)
memset(padding, 0, 512); memset(padding, 0, 512);
php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize); php_stream_write(fp->new, padding, ((entry->uncompressed_filesize +511)&~511) - entry->uncompressed_filesize);
if (entry->fp) { entry->is_modified = 0;
if (entry->fp && entry->fp_refcount == 0) {
if (entry->fp != entry->phar->fp) {
php_stream_close(entry->fp); php_stream_close(entry->fp);
entry->fp = NULL; entry->fp = NULL;
} }
}
/* note new location within tar */ /* note new location within tar */
entry->offset_within_phar = pos; entry->offset_within_phar = pos;
@ -405,6 +417,7 @@ int phar_tar_flush(phar_archive_data *archive, char *user_stub, long len, char *
entry.is_modified = 1; entry.is_modified = 1;
entry.is_tar = 1; entry.is_tar = 1;
entry.tar_type = '0'; entry.tar_type = '0';
entry.phar = archive;
/* set alias */ /* set alias */
if (archive->is_explicit_alias) { if (archive->is_explicit_alias) {
entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1); entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);