/* ArchiveReader::close {{{
 *
*/
ZEND_METHOD(ArchiveReader, close) 
{
	zval *this = getThis();
	int resourse_id;
    zend_error_handling error_handling;
	
    zend_replace_error_handling(EH_THROW, ce_ArchiveException, &error_handling TSRMLS_CC);

	if ((resourse_id = _archive_get_rsrc_id(this TSRMLS_CC))) {
		add_property_resource(this, "fd", 0);
		zend_list_delete(resourse_id);
        zend_restore_error_handling(&error_handling TSRMLS_CC);
		RETURN_TRUE;
	}
	
	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to close archive file descriptor");
    zend_restore_error_handling(&error_handling TSRMLS_CC);
}
/* ArchiveWriter::finish {{{
 *
*/
ZEND_METHOD(ArchiveWriter, finish)
{
	zval *this = getThis();
	int resource_id;
	HashPosition pos;
	archive_file_t *arch;
	archive_entry_t **entry;
	int result, error_num;
	const char *error_string;
	mode_t mode;
	php_stream *stream;
	zend_error_handling error_handling;

	zend_replace_error_handling(EH_THROW, ce_ArchiveException, &error_handling TSRMLS_CC);

	if (!_archive_get_fd(this, &arch TSRMLS_CC)) {
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		return;
	}

	if (zend_hash_sort(arch->entries, zend_qsort, _archive_pathname_compare, 0 TSRMLS_CC) == FAILURE) {
		RETURN_FALSE;
	}

	zend_hash_internal_pointer_reset_ex(arch->entries, &pos);
	while (zend_hash_get_current_data_ex(arch->entries, (void **)&entry, &pos) == SUCCESS) {

		mode = archive_entry_mode((*entry)->entry);

		if (S_ISREG(mode) && archive_entry_size((*entry)->entry) > 0) {
			if ((stream = php_stream_open_wrapper_ex((*entry)->filename, "r", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, NULL))) {
				char buf[PHP_ARCHIVE_BUF_LEN];
				int header_written=0;
				int read_bytes;

				while ((read_bytes = php_stream_read(stream, buf, PHP_ARCHIVE_BUF_LEN))) {
					if (!header_written) {
						/* write header only after the first successful read */
						result = archive_write_header(arch->arch, (*entry)->entry);
						if (result == ARCHIVE_FATAL) {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write entry header for file %s: fatal error", (*entry)->filename);
							zend_restore_error_handling(&error_handling TSRMLS_CC);
							return;
						}
						header_written = 1;
					}
					result = archive_write_data(arch->arch, buf, read_bytes);

					if (result <= 0) {
						error_num = archive_errno(arch->arch);
						error_string = archive_error_string(arch->arch);

						if (error_num && error_string) {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write file %s to archive: error #%d, %s", (*entry)->filename, error_num, error_string);
						}
						else {
							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write file %s: unknown error %d", (*entry)->filename, result);
						}
						php_stream_close(stream);
						zend_restore_error_handling(&error_handling TSRMLS_CC);
						return;
					}
				}
				php_stream_close(stream);
			}
		}
		else {
			result = archive_write_header(arch->arch, (*entry)->entry);
			if (result == ARCHIVE_FATAL) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write entry header for file %s: fatal error", (*entry)->filename);
				zend_restore_error_handling(&error_handling TSRMLS_CC);
				return;
			}
		}
		zend_hash_move_forward_ex(arch->entries, &pos);
	}

	if ((resource_id = _archive_get_rsrc_id(this TSRMLS_CC))) {
		add_property_resource(this, "fd", 0);
		zend_list_delete(resource_id);
		zend_restore_error_handling(&error_handling TSRMLS_CC);
		RETURN_TRUE;
	}

	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to finish writing of archive file");
	zend_restore_error_handling(&error_handling TSRMLS_CC);
}