diff --git a/ext/phar/phar.c b/ext/phar/phar.c index cea08479d68e..a4464444a02b 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -420,7 +420,7 @@ ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **err phar = idata->phar; - if (idata->internal_file->fp_refcount < 2) { + if (idata->internal_file->fp_refcount < 2 && idata->internal_file->fileinfo_lock_count == 0) { if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) { php_stream_close(idata->fp); } diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 144a3c1359f9..abdbb9a9816f 100644 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -216,6 +216,7 @@ typedef struct _phar_entry_info { php_stream *cfp; enum phar_fp_type fp_type; int fp_refcount; + unsigned int fileinfo_lock_count; char *tmp; phar_archive_data *phar; char *link; /* symbolic link to another file */ diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index cd00880a0bf0..17000ca3c0f1 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -4441,7 +4441,7 @@ PHP_METHOD(PharFileInfo, __construct) entry_obj->entry = entry_info; if (!entry_info->is_persistent && !entry_info->is_temp_dir) { - ++entry_info->fp_refcount; + ++entry_info->fileinfo_lock_count; /* The phar data must exist to keep the alias locked. */ ZEND_ASSERT(!phar_data->is_persistent); ++phar_data->refcount; @@ -4486,7 +4486,7 @@ PHP_METHOD(PharFileInfo, __destruct) efree(entry); entry_obj->entry = NULL; } else if (!entry->is_persistent) { - --entry->fp_refcount; + --entry->fileinfo_lock_count; /* The entry itself still lives in the manifest, * which will either be freed here if the file info was the last reference; or freed later. */ entry_obj->entry = NULL; diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 01ab3f2dd47f..91b6b04996d6 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -726,7 +726,7 @@ static int phar_tar_writeheaders_int(phar_entry_info *entry, void *argument) /* } if (entry->is_deleted) { - if (entry->fp_refcount <= 0) { + if (entry->fp_refcount <= 0 && entry->fileinfo_lock_count == 0) { return ZEND_HASH_APPLY_REMOVE; } else { /* we can't delete this in-memory until it is closed */ diff --git a/ext/phar/tests/SplFileInfo_openFile_write.phpt b/ext/phar/tests/SplFileInfo_openFile_write.phpt new file mode 100644 index 000000000000..f63baf5c7ad1 --- /dev/null +++ b/ext/phar/tests/SplFileInfo_openFile_write.phpt @@ -0,0 +1,31 @@ +--TEST-- +SplFileInfo::openFile() in write mode +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +--FILE-- +addFromString('test', 'contents'); +var_dump($phar['test']->openFile('w')); + +?> +--CLEAN-- + +--EXPECTF-- +object(SplFileObject)#%d (%d) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%stest" + ["fileName":"SplFileInfo":private]=> + string(4) "test" + ["openMode":"SplFileObject":private]=> + string(1) "w" + ["delimiter":"SplFileObject":private]=> + string(1) "," + ["enclosure":"SplFileObject":private]=> + string(1) """ +} diff --git a/ext/phar/tests/gh17808.phpt b/ext/phar/tests/gh17808.phpt index 03e54ff264bf..a5c13a5405e2 100644 --- a/ext/phar/tests/gh17808.phpt +++ b/ext/phar/tests/gh17808.phpt @@ -5,18 +5,26 @@ phar zlib --FILE-- getContent())); -unlink("$file"); +unlink($file); var_dump($file->getATime()); ?> +--CLEAN-- + --EXPECTF-- -string(%d) "phar://%spackage.xml" +object(PharFileInfo)#%d (%d) { + ["pathName":"SplFileInfo":private]=> + string(%d) "phar://%spackage.xml" + ["fileName":"SplFileInfo":private]=> + string(11) "package.xml" +} int(6747) - -Warning: unlink(): phar error: "package.xml" in phar %s, has open file pointers, cannot unlink in %s on line %d int(33188) diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 660cd0a98782..9e71a33ccf98 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -851,7 +851,7 @@ static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg) /* {{{ } if (entry->is_deleted) { - if (entry->fp_refcount <= 0) { + if (entry->fp_refcount <= 0 && entry->fileinfo_lock_count == 0) { return ZEND_HASH_APPLY_REMOVE; } else { /* we can't delete this in-memory until it is closed */