From: Greg Beaver Date: Mon, 29 Jan 2007 06:02:19 +0000 (+0000) Subject: throw exceptions from Phar object, and errors from stream wrapper X-Git-Tag: RELEASE_1_0_0RC1~77 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c7a5d062f5fbb883192aa1ac555f640bfaf5d7b9;p=php throw exceptions from Phar object, and errors from stream wrapper # we need to account for uncaught exceptions in shutdown, 2 tests leak because of this --- diff --git a/ext/phar/TODO b/ext/phar/TODO index 3939b9b49e..098fa5f9ed 100644 --- a/ext/phar/TODO +++ b/ext/phar/TODO @@ -23,8 +23,8 @@ Version 1.0.0 to Phar class [Greg] X add PharFileInfo::setMetaData($metadata) [Marcus] X add PharFileInfo::getMetaData() [Marcus] - * always throw exceptions from the Phar object, and E_RECOVERABLE_ERROR from - streams interface + X always throw exceptions from the Phar object, and E_RECOVERABLE_ERROR from + streams interface [Greg] X Phar archive metadata Phar::setMetaData($metadata) Phar::getMetaData() [Greg] X support rename() in stream wrapper [Greg] diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 9733534dd7..c523f0eee7 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -192,32 +192,40 @@ static void destroy_phar_manifest(void *pDest) /* {{{ */ * Looks up a phar archive in the filename map, connecting it to the alias * (if any) or returns null */ -static phar_archive_data * phar_get_archive(char *fname, int fname_len, char *alias, int alias_len TSRMLS_DC) /* {{{ */ +static int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */ { phar_archive_data *fd, **fd_ptr; + if (error) { + *error = NULL; + } if (alias && alias_len) { if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) { if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname); - return NULL; + if (error) { + spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname); + } + return FAILURE; } - return *fd_ptr; + *archive = *fd_ptr; + return SUCCESS; } } if (fname && fname_len) { if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) { + *archive = *fd_ptr; fd = *fd_ptr; if (alias && alias_len) { zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL); } - return fd; + return SUCCESS; } if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fname, fname_len, (void**)&fd_ptr)) { - return *fd_ptr; + *archive = *fd_ptr; + return SUCCESS; } } - return NULL; + return FAILURE; } /* }}} */ @@ -283,97 +291,98 @@ static int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len } return FAILURE; } - if ((phar = phar_get_archive(fname, fname_len, NULL, 0 TSRMLS_CC)) != NULL) { - if ((entry = phar_get_entry_info(phar, path, path_len TSRMLS_CC)) != NULL) { - if (entry->is_modified && !for_write) { - if (error) { - spprintf(error, 0, "phar error: file \"%s\" cannot opened for reading, writable file pointers are open", fname); + if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { + return FAILURE; + } + if ((entry = phar_get_entry_info(phar, path, path_len TSRMLS_CC)) == NULL) { + if (for_create && !PHAR_G(readonly)) { + return SUCCESS; + } + return FAILURE; + } + if (entry->is_modified && !for_write) { + if (error) { + spprintf(error, 0, "phar error: file \"%s\" cannot opened for reading, writable file pointers are open", fname); + } + return FAILURE; + } + if (entry->fp_refcount && for_write) { + if (error) { + spprintf(error, 0, "phar error: file \"%s\" cannot opened for writing, readable file pointers are open", fname); + } + return FAILURE; + } + if (entry->is_deleted) { + if (!for_create) { + return FAILURE; + } + entry->is_deleted = 0; + } + *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); + (*ret)->position = 0; + (*ret)->phar = phar; + (*ret)->internal_file = entry; + if (entry->fp) { + /* make a copy */ + if (for_trunc) { +#if PHP_VERSION_ID < 50202 + if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) { + if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) { + php_stream *inner = *(php_stream**)entry->fp->abstract; + php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract; + memfp->fpos = 0; + memfp->fsize = 0; + } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) { + php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0); + } else { + efree(*ret); + *ret = NULL; + if (error) { + spprintf(error, 0, "phar error: file \"%s\" cannot opened for writing, no truncate support", fname); + } + return FAILURE; } - return FAILURE; - } - if (entry->fp_refcount && for_write) { + } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) { + php_stream_truncate_set_size(entry->fp, 0); + } else { + efree(*ret); + *ret = NULL; if (error) { - spprintf(error, 0, "phar error: file \"%s\" cannot opened for writing, readable file pointers are open", fname); + spprintf(error, 0, "phar error: file \"%s\" cannot opened for writing, no truncate support", fname); } return FAILURE; } - if (entry->is_deleted) { - if (!for_create) { - return FAILURE; - } - entry->is_deleted = 0; - } - *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data)); - (*ret)->position = 0; - (*ret)->phar = phar; - (*ret)->internal_file = entry; - if (entry->fp) { - /* make a copy */ - if (for_trunc) { -#if PHP_VERSION_ID < 50202 - if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) { - if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) { - php_stream *inner = *(php_stream**)entry->fp->abstract; - php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract; - memfp->fpos = 0; - memfp->fsize = 0; - } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) { - php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0); - } else { - efree(*ret); - *ret = NULL; - if (error) { - spprintf(error, 0, "phar error: file \"%s\" cannot opened for writing, no truncate support", fname); - } - return FAILURE; - } - } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) { - php_stream_truncate_set_size(entry->fp, 0); - } else { - efree(*ret); - *ret = NULL; - if (error) { - spprintf(error, 0, "phar error: file \"%s\" cannot opened for writing, no truncate support", fname); - } - return FAILURE; - } #else - php_stream_truncate_set_size(entry->fp, 0); + php_stream_truncate_set_size(entry->fp, 0); #endif - entry->is_modified = 1; - phar->is_modified = 1; - /* reset file size */ - entry->uncompressed_filesize = 0; - entry->compressed_filesize = 0; - entry->crc32 = 0; - } else if (for_append) { - php_stream_seek(entry->fp, 0, SEEK_END); - } - (*ret)->fp = entry->fp; - } else { - (*ret)->fp = 0; - if (for_write) { - /* open a new temp file for writing */ - entry->fp = php_stream_fopen_tmpfile(); - (*ret)->fp = entry->fp; - entry->is_modified = 1; - phar->is_modified = 1; - /* reset file size */ - entry->uncompressed_filesize = 0; - entry->compressed_filesize = 0; - entry->crc32 = 0; - entry->flags = PHAR_ENT_PERM_DEF_FILE; - } - } - entry->fp_refcount++; - entry->phar->refcount++; - return SUCCESS; - } - if (for_create && !PHAR_G(readonly)) { - return SUCCESS; - } - } - return FAILURE; + entry->is_modified = 1; + phar->is_modified = 1; + /* reset file size */ + entry->uncompressed_filesize = 0; + entry->compressed_filesize = 0; + entry->crc32 = 0; + } else if (for_append) { + php_stream_seek(entry->fp, 0, SEEK_END); + } + (*ret)->fp = entry->fp; + } else { + (*ret)->fp = 0; + if (for_write) { + /* open a new temp file for writing */ + entry->fp = php_stream_fopen_tmpfile(); + (*ret)->fp = entry->fp; + entry->is_modified = 1; + phar->is_modified = 1; + /* reset file size */ + entry->uncompressed_filesize = 0; + entry->compressed_filesize = 0; + entry->crc32 = 0; + entry->flags = PHAR_ENT_PERM_DEF_FILE; + } + } + entry->fp_refcount++; + entry->phar->refcount++; + return SUCCESS; } /* }}} */ @@ -395,10 +404,10 @@ int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */ /** * Removes an entry, either by actually removingit or by marking it. */ -void phar_entry_remove(phar_entry_data *idata TSRMLS_DC) /* {{{ */ +void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */ { if (!idata->phar->donotflush) { - phar_flush(idata->internal_file->phar, 0, 0 TSRMLS_CC); + phar_flush(idata->internal_file->phar, 0, 0, error TSRMLS_CC); } if (idata->internal_file->fp_refcount < 2) { if (idata->fp && idata->fp != idata->internal_file->fp) { @@ -423,7 +432,7 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char phar_entry_info *entry, etemp; phar_entry_data *ret; - if ((phar = phar_get_archive(fname, fname_len, NULL, 0 TSRMLS_CC)) == NULL) { + if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) { return NULL; } @@ -464,7 +473,9 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char #define MAPPHAR_ALLOC_FAIL(msg) \ php_stream_close(fp);\ - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, msg, fname);\ + if (error) {\ + spprintf(error, 0, msg, fname);\ + }\ return FAILURE; #define MAPPHAR_FAIL(msg) \ @@ -500,11 +511,11 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char /** * Open an already loaded phar */ -static int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC) /* {{{ */ +static int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ { phar_archive_data *phar; - if ((phar = phar_get_archive(fname, fname_len, alias, alias_len TSRMLS_CC)) != NULL + if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC) && fname_len == phar->fname_len && !strncmp(fname, phar->fname, fname_len) ) { @@ -517,7 +528,11 @@ static int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_l *pphar = NULL; } if (phar && alias && (options & REPORT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, phar->fname, fname); + if (error) { + if (*error) { + spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, phar->fname, fname); + } + } } return FAILURE; } @@ -566,7 +581,7 @@ static int phar_parse_metadata(php_stream *fp, char **buffer, char *endbuffer, z * This is used by phar_open_filename to process the manifest, but can be called * directly. */ -int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar TSRMLS_DC) /* {{{ */ +int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ { char b32[4], *buffer, *endbuffer, *savebuf; phar_archive_data *mydata = NULL; @@ -580,6 +595,9 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int if (pphar) { *pphar = NULL; } + if (error) { + *error = NULL; + } /* check for ?>\n and increment accordingly */ if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) { @@ -644,7 +662,9 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) { efree(savebuf); php_stream_close(fp); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F); + if (error) { + spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F); + } return FAILURE; } @@ -666,7 +686,9 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int || memcmp(sig_buf+4, "GBMB", 4)) { efree(savebuf); php_stream_close(fp); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } return FAILURE; } PHAR_GET_32(sig_ptr, sig_flags); @@ -697,7 +719,9 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int || memcmp(digest, saved, sizeof(digest))) { efree(savebuf); php_stream_close(fp); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } return FAILURE; } @@ -736,7 +760,9 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int || memcmp(digest, saved, sizeof(digest))) { efree(savebuf); php_stream_close(fp); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } return FAILURE; } @@ -752,13 +778,17 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int default: efree(savebuf); php_stream_close(fp); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + if (error) { + spprintf(error, 0, "phar \"%s\" has a broken signature", fname); + } return FAILURE; } } else if (PHAR_G(require_hash)) { efree(savebuf); php_stream_close(fp); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" does not have a signature", fname); + if (error) { + spprintf(error, 0, "phar \"%s\" does not have a signature", fname); + } return FAILURE; } else { sig_flags = 0; @@ -784,7 +814,9 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int if (signature) { efree(signature); } - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias); + if (error) { + spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias); + } return FAILURE; } alias_len = tmp_len; @@ -914,7 +946,7 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int /** * Create or open a phar for writing */ -int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC) /* {{{ */ +int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ { phar_archive_data *mydata; int register_alias; @@ -923,8 +955,11 @@ int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int al if (!pphar) { pphar = &mydata; } + if (error) { + *error = NULL; + } - if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar TSRMLS_CC) == SUCCESS) { + if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar, 0 TSRMLS_CC) == SUCCESS) { if (!PHAR_G(readonly)) { (*pphar)->is_writeable = 1; } @@ -943,7 +978,7 @@ int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int al fp = php_stream_open_wrapper(fname, PHAR_G(readonly)?"rb":"r+b", IGNORE_URL|STREAM_MUST_SEEK|0, NULL); - if (fp && phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar TSRMLS_CC) == SUCCESS) { + if (fp && phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, 0 TSRMLS_CC) == SUCCESS) { if (!PHAR_G(readonly)) { (*pphar)->is_writeable = 1; } @@ -952,7 +987,9 @@ int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int al if (PHAR_G(readonly)) { if (options & REPORT_ERRORS) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "creating archive \"%s\" disabled by INI setting", fname); + if (*error) { + spprintf(error, 0, "creating archive \"%s\" disabled by INI setting", fname); + } } return FAILURE; } @@ -997,12 +1034,18 @@ int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int al * that the manifest is proper, then pass it to phar_open_file(). SUCCESS * or FAILURE is returned and pphar is set to a pointer to the phar's manifest */ -int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC) /* {{{ */ +int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ { php_stream *fp; + + if (error) { + *error = NULL; + } - if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar TSRMLS_CC) == SUCCESS) { + if (phar_open_loaded(fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC) == SUCCESS) { return SUCCESS; + } else if (*error) { + return FAILURE; } #if PHP_MAJOR_VERSION < 6 @@ -1019,12 +1062,14 @@ int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, i if (!fp) { if (options & REPORT_ERRORS) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to open phar for reading \"%s\"", fname); + if (error) { + spprintf(error, 0, "unable to open phar for reading \"%s\"", fname); + } } return FAILURE; } - return phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar TSRMLS_CC); + return phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC); } /* }}}*/ @@ -1033,7 +1078,7 @@ int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, i * that the manifest is proper, then pass it to phar_open_file(). SUCCESS * or FAILURE is returned and pphar is set to a pointer to the phar's manifest */ -static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC) /* {{{ */ +static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */ { const char token[] = "__HALT_COMPILER();"; char *pos, buffer[1024 + sizeof(token)]; @@ -1044,6 +1089,9 @@ static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, /* Maybe it's better to compile the file instead of just searching, */ /* but we only want the offset. So we want a .re scanner to find it. */ + if (error) { + *error = NULL; + } if (-1 == php_stream_rewind(fp)) { MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"") } @@ -1057,7 +1105,7 @@ static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, } if ((pos = strstr(buffer, token)) != NULL) { halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */ - return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar TSRMLS_CC); + return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, error TSRMLS_CC); } halt_offset += readsize; @@ -1128,7 +1176,7 @@ int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_le static php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC) /* {{{ */ { php_url *resource; - char *arch, *entry; + char *arch, *entry, *error; int arch_len, entry_len; if (!strncasecmp(filename, "phar://", 7)) { @@ -1165,14 +1213,22 @@ static php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char php_url_free(resource); return NULL; } - if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, options, NULL TSRMLS_CC) == FAILURE) + if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } php_url_free(resource); return NULL; } } else { - if (phar_open_filename(resource->host, arch_len, NULL, 0, options, NULL TSRMLS_CC) == FAILURE) + if (phar_open_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } php_url_free(resource); return NULL; } @@ -1188,7 +1244,7 @@ static php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char * Invoked when a user calls Phar::mapPhar() from within an executing .phar * to set up its manifest directly */ -int phar_open_compiled_file(char *alias, int alias_len TSRMLS_DC) /* {{{ */ +int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */ { char *fname; long halt_offset; @@ -1196,23 +1252,30 @@ int phar_open_compiled_file(char *alias, int alias_len TSRMLS_DC) /* {{{ */ php_stream *fp; int fname_len; + if (error) { + *error = NULL; + } fname = zend_get_executed_filename(TSRMLS_C); fname_len = strlen(fname); - if (alias && phar_open_loaded(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL TSRMLS_CC) == SUCCESS) { + if (alias && phar_open_loaded(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) { return SUCCESS; } if (!strcmp(fname, "[no active file]")) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "cannot initialize a phar outside of PHP execution"); + if (error) { + spprintf(error, 0, "cannot initialize a phar outside of PHP execution"); + } return FAILURE; } MAKE_STD_ZVAL(halt_constant); if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) { FREE_ZVAL(halt_constant); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "__HALT_COMPILER(); must be declared in a phar"); + if (error) { + spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar"); + } return FAILURE; } halt_offset = Z_LVAL(*halt_constant); @@ -1221,11 +1284,13 @@ int phar_open_compiled_file(char *alias, int alias_len TSRMLS_DC) /* {{{ */ fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); if (!fp) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to open phar for reading \"%s\"", fname); + if (error) { + spprintf(error, 0, "unable to open phar for reading \"%s\"", fname); + } return FAILURE; } - return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, NULL TSRMLS_CC); + return phar_open_file(fp, fname, fname_len, alias, alias_len, halt_offset, NULL, error TSRMLS_CC); } /* }}} */ @@ -1703,7 +1768,7 @@ static size_t phar_stream_write(php_stream *stream, const char *buf, size_t coun php_stream_seek(data->fp, data->position, SEEK_SET); if (count != php_stream_write(data->fp, buf, count)) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar error: Could not write %d characters to \"%s\" in phar \"%s\"", (int) count, data->internal_file->filename, data->phar->fname); + php_stream_wrapper_log_error(stream->wrapper, stream->flags TSRMLS_CC, "phar error: Could not write %d characters to \"%s\" in phar \"%s\"", (int) count, data->internal_file->filename, data->phar->fname); return -1; } data->position = php_stream_tell(data->fp); @@ -1769,7 +1834,7 @@ static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */ * user_stub contains either a string, or a resource pointer, if len is a negative length. * user_stub and len should be both 0 if the default or existing stub should be used */ -int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) /* {{{ */ +int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC) /* {{{ */ { static const char newstub[] = "fp && !archive->is_brandnew) { oldfile = archive->fp; closeoldfile = 0; @@ -1808,7 +1876,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to read resource to copy stub to new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", archive->fname); + } return EOF; } if (len == -1) { @@ -1822,7 +1892,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to copy stub from resource to new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to copy stub from resource to new phar \"%s\"", archive->fname); + } return EOF; } archive->halt_offset = offset; @@ -1832,7 +1904,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to create stub from string in new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", archive->fname); + } return EOF; } archive->halt_offset = len; @@ -1844,7 +1918,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to copy stub of old phar to new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", archive->fname); + } return EOF; } } else { @@ -1855,7 +1931,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to create stub in new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to create stub in new phar \"%s\"", archive->fname); + } return EOF; } } @@ -1928,9 +2006,13 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) } php_stream_close(newfile); if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, archive->fname); + } } else { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, archive->fname); + } } efree(buf); return EOF; @@ -1946,7 +2028,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) read = php_stream_read(file, buf, 8192); if (read) { if (read != php_stream_write(entry->cfp, buf, read)) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write to file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to write to file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname); + } efree(buf); php_stream_filter_remove(filter, 1 TSRMLS_CC); php_stream_close(entry->cfp); @@ -2000,7 +2084,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) } php_stream_close(newfile); archive->alias_len = restore_alias_len; - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest header of new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", archive->fname); + } return EOF; } @@ -2017,7 +2103,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) } php_stream_close(newfile); archive->alias_len = restore_alias_len; - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest meta-data of new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", archive->fname); + } return EOF; } } else { @@ -2028,7 +2116,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) } php_stream_close(newfile); archive->alias_len = restore_alias_len; - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write manifest header of new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", archive->fname); + } return EOF; } } @@ -2055,7 +2145,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname); + } return EOF; } /* set the manifest meta-data: @@ -2087,7 +2179,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, archive->fname); + } return EOF; } smart_str_free(&metadata_str); @@ -2116,7 +2210,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, archive->fname); + } return EOF; } file = oldfile; @@ -2131,7 +2227,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) php_stream_close(oldfile); } php_stream_close(newfile); - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, archive->fname); + if (error) { + spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, archive->fname); + } return EOF; } entry->is_modified = 0; @@ -2226,7 +2324,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) archive->fp = php_stream_open_wrapper(archive->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); if (!archive->fp) { archive->fp = newfile; - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to open new phar \"%s\" for writing", archive->fname); + if (error) { + spprintf(error, 0, "unable to open new phar \"%s\" for writing", archive->fname); + } return EOF; } php_stream_copy_to_stream(newfile, archive->fp, PHP_STREAM_COPY_ALL); @@ -2235,7 +2335,9 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) } if (-1 == php_stream_seek(archive->fp, archive->halt_offset, SEEK_SET)) { - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", archive->fname); + if (error) { + spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", archive->fname); + } return EOF; } @@ -2248,8 +2350,15 @@ int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC) */ static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */ { + char *error; + int ret; if (stream->mode[0] == 'w' || (stream->mode[0] == 'r' && stream->mode[1] == '+')) { - return phar_flush(((phar_entry_data *)stream->abstract)->internal_file->phar, 0, 0 TSRMLS_CC); + ret = phar_flush(((phar_entry_data *)stream->abstract)->internal_file->phar, 0, 0, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, error); + efree(error); + } + return ret; } else { return EOF; } @@ -2375,7 +2484,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */ { php_url *resource = NULL; - char *internal_file, *key; + char *internal_file, *key, *error; uint keylen; ulong unused; phar_archive_data *phar; @@ -2402,38 +2511,47 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags, internal_file = resource->path + 1; /* strip leading "/" */ /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */ - if ((phar = phar_get_archive(resource->host, strlen(resource->host), NULL, 0 TSRMLS_CC)) != NULL) { - if (*internal_file == '\0') { - /* root directory requested */ - phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC); - php_url_free(resource); - return 0; - } - if (!phar->manifest.arBuckets) { - php_url_free(resource); - return 0; + if (FAILURE == phar_get_archive(&phar, resource->host, strlen(resource->host), NULL, 0, &error TSRMLS_CC)) { + php_url_free(resource); + if (error) { + php_stream_wrapper_log_error(wrapper, flags TSRMLS_CC, error); + efree(error); } - /* search through the manifest of files, and if we have an exact match, it's a file */ - if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry)) { - phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC); - } else { - /* search for directory (partial match of a file) */ - zend_hash_internal_pointer_reset(&phar->manifest); - while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { - if (HASH_KEY_NON_EXISTANT != - zend_hash_get_current_key_ex( - &phar->manifest, &key, &keylen, &unused, 0, NULL)) { - if (0 == memcmp(internal_file, key, strlen(internal_file))) { - /* directory found, all dirs have the same stat */ - if (key[strlen(internal_file)] == '/') { - phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC); - break; - } + return 0; + } + if (error) { + efree(error); + } + if (*internal_file == '\0') { + /* root directory requested */ + phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC); + php_url_free(resource); + return 0; + } + if (!phar->manifest.arBuckets) { + php_url_free(resource); + return 0; + } + /* search through the manifest of files, and if we have an exact match, it's a file */ + if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry)) { + phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC); + } else { + /* search for directory (partial match of a file) */ + zend_hash_internal_pointer_reset(&phar->manifest); + while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { + if (HASH_KEY_NON_EXISTANT != + zend_hash_get_current_key_ex( + &phar->manifest, &key, &keylen, &unused, 0, NULL)) { + if (0 == memcmp(internal_file, key, strlen(internal_file))) { + /* directory found, all dirs have the same stat */ + if (key[strlen(internal_file)] == '/') { + phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC); + break; } } - if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { - break; - } + } + if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { + break; } } } @@ -2646,7 +2764,11 @@ static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int optio } php_url_free(resource); efree(internal_file); - phar_entry_remove(idata TSRMLS_CC); + phar_entry_remove(idata, &error TSRMLS_CC); + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); + } return SUCCESS; } /* }}} */ @@ -2805,7 +2927,7 @@ static php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path { php_url *resource = NULL; php_stream *ret; - char *internal_file, *key; + char *internal_file, *key, *error; uint keylen; ulong unused; phar_archive_data *phar; @@ -2836,40 +2958,49 @@ static php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, char *path } internal_file = resource->path + 1; /* strip leading "/" */ - if ((phar = phar_get_archive(resource->host, strlen(resource->host), NULL, 0 TSRMLS_CC)) != NULL) { - if (*internal_file == '\0') { - /* root directory requested */ - internal_file = estrndup(internal_file - 1, 1); - ret = phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); - php_url_free(resource); - return ret; - } - if (!phar->manifest.arBuckets) { - php_url_free(resource); - return NULL; + if (FAILURE == phar_get_archive(&phar, resource->host, strlen(resource->host), NULL, 0, &error TSRMLS_CC)) { + if (error) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + efree(error); } - if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry)) { - php_url_free(resource); - return NULL; - } else { - /* search for directory */ - zend_hash_internal_pointer_reset(&phar->manifest); - while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { - if (HASH_KEY_NON_EXISTANT != - zend_hash_get_current_key_ex( - &phar->manifest, &key, &keylen, &unused, 0, NULL)) { - if (0 == memcmp(key, internal_file, strlen(internal_file))) { - /* directory found */ - internal_file = estrndup(internal_file, - strlen(internal_file)); - php_url_free(resource); - return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); - } - } - if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { - break; + php_url_free(resource); + return NULL; + } + if (error) { + efree(error); + } + if (*internal_file == '\0') { + /* root directory requested */ + internal_file = estrndup(internal_file - 1, 1); + ret = phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); + php_url_free(resource); + return ret; + } + if (!phar->manifest.arBuckets) { + php_url_free(resource); + return NULL; + } + if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, strlen(internal_file), (void**)&entry)) { + php_url_free(resource); + return NULL; + } else { + /* search for directory */ + zend_hash_internal_pointer_reset(&phar->manifest); + while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) { + if (HASH_KEY_NON_EXISTANT != + zend_hash_get_current_key_ex( + &phar->manifest, &key, &keylen, &unused, 0, NULL)) { + if (0 == memcmp(key, internal_file, strlen(internal_file))) { + /* directory found */ + internal_file = estrndup(internal_file, + strlen(internal_file)); + php_url_free(resource); + return phar_make_dirstream(internal_file, &phar->manifest TSRMLS_CC); } } + if (SUCCESS != zend_hash_move_forward(&phar->manifest)) { + break; + } } } diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 5130edb103..5392438ab7 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -214,13 +214,13 @@ BEGIN_EXTERN_C() void phar_object_init(TSRMLS_D); -int phar_open_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC); -int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC); -int phar_open_compiled_file(char *alias, int alias_len TSRMLS_DC); +int phar_open_filename(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_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); +int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC); #ifdef PHAR_MAIN -static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar TSRMLS_DC); +static int phar_open_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); static php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC); @@ -253,7 +253,7 @@ int phar_entry_delref(phar_entry_data *idata TSRMLS_DC); phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len TSRMLS_DC); phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char **error TSRMLS_DC); -int phar_flush(phar_archive_data *archive, char *user_stub, long len TSRMLS_DC); +int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC); int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len TSRMLS_DC); END_EXTERN_C() diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 45f8f7dba6..e32f6daec8 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -22,6 +22,7 @@ #include "phar_internal.h" static zend_class_entry *phar_ce_archive; +static zend_class_entry *phar_ce_PharException; #if HAVE_SPL static zend_class_entry *phar_ce_entry; @@ -31,26 +32,34 @@ static zend_class_entry *phar_ce_entry; * Reads the currently executed file (a phar) and registers its manifest */ PHP_METHOD(Phar, mapPhar) { - char * alias = NULL; + char *alias = NULL, *error; int alias_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &alias, &alias_len) == FAILURE) { return; } - RETURN_BOOL(phar_open_compiled_file(alias, alias_len TSRMLS_CC) == SUCCESS); + RETVAL_BOOL(phar_open_compiled_file(alias, alias_len, &error TSRMLS_CC) == SUCCESS); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } } /* }}} */ /* {{{ proto mixed Phar::loadPhar(string filename [, string alias]) * Loads any phar archive with an alias */ PHP_METHOD(Phar, loadPhar) { - char *fname, *alias = NULL; + char *fname, *alias = NULL, *error; int fname_len, alias_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &fname, &fname_len, &alias, &alias_len) == FAILURE) { return; } - RETURN_BOOL(phar_open_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL TSRMLS_CC) == SUCCESS); + RETVAL_BOOL(phar_open_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, &error TSRMLS_CC) == SUCCESS); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } } /* }}} */ /* {{{ proto string apiVersion() @@ -117,7 +126,7 @@ PHP_METHOD(Phar, __construct) #if !HAVE_SPL zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Cannot instantiate Phar object without SPL extension"); #else - char *fname, *alias = NULL; + char *fname, *alias = NULL, *error; int fname_len, alias_len = 0; long flags = 0; phar_archive_object *phar_obj; @@ -135,9 +144,15 @@ PHP_METHOD(Phar, __construct) return; } - if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, &phar_data TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, - "Cannot open phar file '%s' with alias '%s'", fname, alias); + if (phar_open_or_create_filename(fname, fname_len, alias, alias_len, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) { + if (error) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot open phar file '%s' with alias '%s': %s", fname, alias, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot open phar file '%s' with alias '%s'", fname, alias); + } return; } @@ -215,6 +230,7 @@ PHP_METHOD(Phar, begin) */ PHP_METHOD(Phar, commit) { + char *error; PHAR_ARCHIVE_OBJECT(); if (PHAR_G(readonly)) { @@ -224,7 +240,11 @@ PHP_METHOD(Phar, commit) phar_obj->arc.archive->donotflush = 0; - phar_flush(phar_obj->arc.archive, 0, 0 TSRMLS_CC); + phar_flush(phar_obj->arc.archive, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } } /* }}} */ @@ -234,7 +254,7 @@ PHP_METHOD(Phar, commit) PHP_METHOD(Phar, setStub) { zval *zstub; - char *stub; + char *stub, *error; int stub_len; long len = -1; php_stream *stream; @@ -252,14 +272,22 @@ PHP_METHOD(Phar, setStub) } else { len = -1; } - phar_flush(phar_obj->arc.archive, (char *) &zstub, len TSRMLS_CC); + phar_flush(phar_obj->arc.archive, (char *) &zstub, len, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } RETURN_TRUE; } else { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Cannot change stub, unable to read from input stream"); } } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stub, &stub_len) == SUCCESS) { - phar_flush(phar_obj->arc.archive, stub, stub_len TSRMLS_CC); + phar_flush(phar_obj->arc.archive, stub, stub_len, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } RETURN_TRUE; } @@ -358,23 +386,30 @@ static int pharobj_cancompress(HashTable *manifest TSRMLS_DC) /* {{{ */ */ PHP_METHOD(Phar, compressAllFilesGZ) { +#if HAVE_ZLIB + char *error; +#endif PHAR_ARCHIVE_OBJECT(); if (PHAR_G(readonly)) { - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Phar is readonly, cannot change compression"); } #if HAVE_ZLIB if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) { - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot compress all files as Gzip, some are compressed as bzip2 and cannot be uncompressed"); } pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_GZ TSRMLS_CC); phar_obj->arc.archive->is_modified = 1; - phar_flush(phar_obj->arc.archive, 0, 0 TSRMLS_CC); + phar_flush(phar_obj->arc.archive, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } #else - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot compress with Gzip compression, zlib extension is not enabled"); #endif } @@ -385,23 +420,30 @@ PHP_METHOD(Phar, compressAllFilesGZ) */ PHP_METHOD(Phar, compressAllFilesBZIP2) { +#if HAVE_BZ2 + char *error; +#endif PHAR_ARCHIVE_OBJECT(); if (PHAR_G(readonly)) { - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Phar is readonly, cannot change compression"); } #if HAVE_BZ2 if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) { - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot compress all files as Bzip2, some are compressed as gzip and cannot be uncompressed"); } pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_BZ2 TSRMLS_CC); phar_obj->arc.archive->is_modified = 1; - phar_flush(phar_obj->arc.archive, 0, 0 TSRMLS_CC); + phar_flush(phar_obj->arc.archive, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } #else - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot compress with Bzip2 compression, bz2 extension is not enabled"); #endif } @@ -412,20 +454,25 @@ PHP_METHOD(Phar, compressAllFilesBZIP2) */ PHP_METHOD(Phar, uncompressAllFiles) { + char *error; PHAR_ARCHIVE_OBJECT(); if (PHAR_G(readonly)) { - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Phar is readonly, cannot change compression"); } if (!pharobj_cancompress(&phar_obj->arc.archive->manifest TSRMLS_CC)) { - zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "Cannot uncompress all files, some are compressed as bzip2 or gzip and cannot be uncompressed"); } pharobj_set_compression(&phar_obj->arc.archive->manifest, PHAR_ENT_COMPRESSED_NONE TSRMLS_CC); phar_obj->arc.archive->is_modified = 1; - phar_flush(phar_obj->arc.archive, 0, 0 TSRMLS_CC); + phar_flush(phar_obj->arc.archive, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } } /* }}} */ @@ -536,8 +583,12 @@ PHP_METHOD(Phar, offsetSet) zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Entry %s could not be written to", fname); } } - phar_flush(phar_obj->arc.archive, 0, 0 TSRMLS_CC); + phar_flush(phar_obj->arc.archive, 0, 0, &error TSRMLS_CC); phar_entry_delref(data TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } } } /* }}} */ @@ -547,7 +598,7 @@ PHP_METHOD(Phar, offsetSet) */ PHP_METHOD(Phar, offsetUnset) { - char *fname; + char *fname, *error; int fname_len; phar_entry_info *entry; PHAR_ARCHIVE_OBJECT(); @@ -570,7 +621,11 @@ PHP_METHOD(Phar, offsetUnset) entry->is_modified = 0; entry->is_deleted = 1; /* we need to "flush" the stream to save the newly deleted file on disk */ - phar_flush(phar_obj->arc.archive, 0, 0 TSRMLS_CC); + phar_flush(phar_obj->arc.archive, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } RETURN_TRUE; } } else { @@ -663,7 +718,7 @@ PHP_METHOD(Phar, setMetadata) */ PHP_METHOD(PharFileInfo, __construct) { - char *fname, *arch, *entry; + char *fname, *arch, *entry, *error; int fname_len, arch_len, entry_len; phar_entry_object *entry_obj; phar_entry_info *entry_info; @@ -689,11 +744,17 @@ PHP_METHOD(PharFileInfo, __construct) return; } - if (phar_open_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data TSRMLS_CC) == FAILURE) { + if (phar_open_filename(arch, arch_len, NULL, 0, REPORT_ERRORS, &phar_data, &error TSRMLS_CC) == FAILURE) { efree(arch); efree(entry); - zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, - "Cannot open phar file '%s'", fname); + if (error) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot open phar file '%s': %s", fname, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot open phar file '%s'", fname); + } return; } @@ -849,6 +910,7 @@ PHP_METHOD(PharFileInfo, setMetadata) PHP_METHOD(PharFileInfo, setCompressedGZ) { #if HAVE_ZLIB + char *error; PHAR_ENTRY_OBJECT(); if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_GZ) { @@ -868,7 +930,11 @@ PHP_METHOD(PharFileInfo, setCompressedGZ) entry_obj->ent.entry->phar->is_modified = 1; entry_obj->ent.entry->is_modified = 1; - phar_flush(entry_obj->ent.entry->phar, 0, 0 TSRMLS_CC); + phar_flush(entry_obj->ent.entry->phar, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } RETURN_TRUE; #else zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, @@ -883,6 +949,7 @@ PHP_METHOD(PharFileInfo, setCompressedGZ) PHP_METHOD(PharFileInfo, setCompressedBZIP2) { #if HAVE_BZ2 + char *error; PHAR_ENTRY_OBJECT(); if (entry_obj->ent.entry->flags & PHAR_ENT_COMPRESSED_BZ2) { @@ -902,7 +969,11 @@ PHP_METHOD(PharFileInfo, setCompressedBZIP2) entry_obj->ent.entry->phar->is_modified = 1; entry_obj->ent.entry->is_modified = 1; - phar_flush(entry_obj->ent.entry->phar, 0, 0 TSRMLS_CC); + phar_flush(entry_obj->ent.entry->phar, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } RETURN_TRUE; #else zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, @@ -916,7 +987,7 @@ PHP_METHOD(PharFileInfo, setCompressedBZIP2) */ PHP_METHOD(PharFileInfo, setUncompressed) { - char *fname; + char *fname, *error; int fname_len; PHAR_ENTRY_OBJECT(); @@ -953,7 +1024,11 @@ PHP_METHOD(PharFileInfo, setUncompressed) entry_obj->ent.entry->phar->is_modified = 1; entry_obj->ent.entry->is_modified = 1; - phar_flush(entry_obj->ent.entry->phar, 0, 0 TSRMLS_CC); + phar_flush(entry_obj->ent.entry->phar, 0, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + } RETURN_TRUE; } /* }}} */ @@ -1060,6 +1135,10 @@ zend_function_entry php_entry_methods[] = { {NULL, NULL, NULL} }; #endif + +zend_function_entry phar_exception_methods[] = { + {NULL, NULL, NULL} +}; /* }}} */ #define REGISTER_PHAR_CLASS_CONST_LONG(class_name, const_name, value) \ @@ -1069,6 +1148,9 @@ void phar_object_init(TSRMLS_D) /* {{{ */ { zend_class_entry ce; + INIT_CLASS_ENTRY(ce, "PharException", phar_exception_methods); + phar_ce_PharException = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); + #if HAVE_SPL INIT_CLASS_ENTRY(ce, "Phar", php_archive_methods); phar_ce_archive = zend_register_internal_class_ex(&ce, spl_ce_RecursiveDirectoryIterator, NULL TSRMLS_CC); diff --git a/ext/phar/tests/002.phpt b/ext/phar/tests/002.phpt index a070314a5d..5ee15f19c3 100644 --- a/ext/phar/tests/002.phpt +++ b/ext/phar/tests/002.phpt @@ -4,12 +4,16 @@ Phar::mapPhar truncated manifest/improper params --FILE-- getMessage(); +} __HALT_COMPILER(); ?> --EXPECTF-- Warning: Phar::mapPhar() expects at most 1 parameter, 2 given in %s002.php on line %d @@ -17,5 +21,4 @@ Warning: Phar::mapPhar() expects at most 1 parameter, 2 given in %s002.php on li Warning: Phar::mapPhar() expects at most 1 parameter, 2 given in %s002.php on line %d Warning: Phar::mapPhar() expects at most 1 parameter, 3 given in %s002.php on line %d - -%satal error: Phar::mapPhar(): internal corruption of phar "%s" (truncated manifest) in %s on line %d +internal corruption of phar "%s002.php" (truncated manifest) \ No newline at end of file diff --git a/ext/phar/tests/004.phpt b/ext/phar/tests/004.phpt index b7e02de1ab..17190a9ec2 100644 --- a/ext/phar/tests/004.phpt +++ b/ext/phar/tests/004.phpt @@ -4,7 +4,11 @@ Phar::mapPhar no __HALT_COMPILER(); --FILE-- getMessage(); +} ?> --EXPECTF-- -%satal error: Phar::mapPhar(): __HALT_COMPILER(); must be declared in a phar in %s on line %d +__HALT_COMPILER(); must be declared in a phar diff --git a/ext/phar/tests/005.phpt b/ext/phar/tests/005.phpt index 460df3baec..69d289d56e 100644 --- a/ext/phar/tests/005.phpt +++ b/ext/phar/tests/005.phpt @@ -4,7 +4,11 @@ Phar::mapPhar truncated manifest (none) --FILE-- getMessage(); +} __HALT_COMPILER(); ?>() --EXPECTF-- -%satal error: Phar::mapPhar(): internal corruption of phar "%s" (truncated manifest) in %s on line %d +internal corruption of phar "%s" (truncated manifest) diff --git a/ext/phar/tests/006.phpt b/ext/phar/tests/006.phpt index 89535f7045..0c207cfd68 100644 --- a/ext/phar/tests/006.phpt +++ b/ext/phar/tests/006.phpt @@ -4,7 +4,11 @@ Phar::mapPhar truncated manifest (manifest length truncated) --FILE-- getMessage(); +} __HALT_COMPILER(); ?> --EXPECTF-- -%satal error: Phar::mapPhar(): internal corruption of phar "%s" (truncated manifest) in %s on line %d +internal corruption of phar "%s" (truncated manifest) diff --git a/ext/phar/tests/007.phpt b/ext/phar/tests/007.phpt index 1da7a85de5..1519f4fe40 100644 --- a/ext/phar/tests/007.phpt +++ b/ext/phar/tests/007.phpt @@ -4,7 +4,11 @@ Phar::mapPhar manifest too big --FILE-- getMessage(); +} __HALT_COMPILER(); ?>~~~~ --EXPECTF-- -%satal error: Phar::mapPhar(): manifest cannot be larger than 1 MB in phar "%s" in %s on line %d +manifest cannot be larger than 1 MB in phar "%s" diff --git a/ext/phar/tests/008.phpt b/ext/phar/tests/008.phpt index ae1837a83d..689544b8b9 100644 --- a/ext/phar/tests/008.phpt +++ b/ext/phar/tests/008.phpt @@ -9,9 +9,13 @@ Phar::mapPhar('hio'); __HALT_COMPILER(); ?>"; $file .= pack('V', 500) . 'notenough'; file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); +try { include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +} catch (Exception $e) { +echo $e->getMessage(); +} ?> --CLEAN-- --EXPECTF-- -%satal error: Phar::mapPhar(): internal corruption of phar "%s" (truncated manifest) in %s on line %d +internal corruption of phar "%s" (truncated manifest) diff --git a/ext/phar/tests/009.phpt b/ext/phar/tests/009.phpt index 6a5bb73187..6a480c3852 100644 --- a/ext/phar/tests/009.phpt +++ b/ext/phar/tests/009.phpt @@ -11,9 +11,13 @@ Phar::mapPhar('hio'); __HALT_COMPILER(); ?>"; $file .= pack('VVnVVV', 500, 500, 0x1000, 0x00000000, 0, 0) . str_repeat('A', 500); file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); +try { include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; +} catch (Exception $e) { +echo $e->getMessage(); +} ?> --CLEAN-- --EXPECTF-- -%satal error: Phar::mapPhar(): internal corruption of phar "%s009.phar.php" (too many manifest entries for size of manifest) in %s on line %d +internal corruption of phar "%s009.phar.php" (too many manifest entries for size of manifest) diff --git a/ext/phar/tests/010.phpt b/ext/phar/tests/010.phpt index e07c85743b..3dcf495d9a 100644 --- a/ext/phar/tests/010.phpt +++ b/ext/phar/tests/010.phpt @@ -16,10 +16,14 @@ $manifest = pack('V', 1) . 'a' . pack('VVVVVV', 0, time(), 0, crc32(''), 0x00000 $file .= pack('VVnVV', strlen($manifest), 1, 0x1000, 0x00000000, 3) . 'hio' . pack('V', 0) . $manifest; file_put_contents(dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php', $file); +try { include dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php'; echo file_get_contents('phar://hio/a'); +} catch (Exception $e) { +echo $e->getMessage(); +} ?> --CLEAN-- --EXPECTF-- -%satal error: Phar::mapPhar(): internal corruption of phar "%s" (too many manifest entries for size of manifest) in %s on line %d +internal corruption of phar "%s" (too many manifest entries for size of manifest) diff --git a/ext/phar/tests/011.phpt b/ext/phar/tests/011.phpt index 3b0cde1d19..ac85477841 100644 --- a/ext/phar/tests/011.phpt +++ b/ext/phar/tests/011.phpt @@ -17,11 +17,14 @@ __HALT_COMPILER(); ?>"; $files = array(); $files['a'] = array('cont'=>'a','ulen'=>1,'clen'=>2);; include 'phar_test.inc'; - +try { include $fname; echo file_get_contents('phar://hio/a'); +} catch (Exception $e) { +echo $e->getMessage(); +} ?> --CLEAN-- --EXPECTF-- -%satal error: Phar::mapPhar(): internal corruption of phar "%s" (compressed and uncompressed size does not match for uncompressed entry) in %s on line %d +internal corruption of phar "%s" (compressed and uncompressed size does not match for uncompressed entry) diff --git a/ext/phar/tests/029.phpt b/ext/phar/tests/029.phpt index 155a9760b1..46d8722506 100755 --- a/ext/phar/tests/029.phpt +++ b/ext/phar/tests/029.phpt @@ -25,7 +25,11 @@ file_put_contents($fname2, $file); var_dump(Phar::loadPhar($fname1, 'hio')); var_dump(Phar::loadPhar($fname1, 'copy')); +try { var_dump(Phar::loadPhar($fname2, 'copy')); +} catch (Exception $e) { +echo $e->getMessage(); +} ?> ===DONE=== @@ -38,4 +42,4 @@ unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.2.phar.php bool(true) bool(true) -%satal error: Phar::loadPhar(): alias "copy" is already used for archive "%s029.1.phar.php" cannot be overloaded with "%s029.2.phar.php" in %s029.php on line %d +alias "copy" is already used for archive "%s029.1.phar.php" cannot be overloaded with "%s029.2.phar.php"===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/032.phpt b/ext/phar/tests/032.phpt index f8b8b97368..f7d11c6d64 100755 --- a/ext/phar/tests/032.phpt +++ b/ext/phar/tests/032.phpt @@ -11,7 +11,11 @@ $pharconfig = 0; require_once 'phar_oo_test.inc'; +try { Phar::loadPhar($fname); +} catch (Exception $e) { +echo $e->getMessage(); +} ?> ===DONE=== @@ -22,4 +26,4 @@ __halt_compiler(); ?> --EXPECTF-- -Catchable fatal error: Phar::loadPhar(): phar "%sphar_oo_test.phar.php" does not have a signature in %s032.php on line %d +phar "%sphar_oo_test.phar.php" does not have a signature===DONE=== \ No newline at end of file