#define PHAR_ENT_COMPRESSED_GZ 0x01
#define PHAR_ENT_COMPRESSED_BZ2 0x02
+/* an entry has been marked as deleted from a writeable phar */
+#define PHAR_ENT_DELETED 0x10
+/* an entry has been modified, and should be saved */
+#define PHAR_ENT_MODIFIED 0x20
+
ZEND_BEGIN_MODULE_GLOBALS(phar)
HashTable phar_fname_map;
char flags;
zend_bool crc_checked;
php_stream *fp;
+ php_stream *temp_file;
} phar_entry_info;
/* information about a phar file (the archive itself) */
int alias_len;
char version[12];
size_t internal_file_start;
+ size_t halt_offset;
zend_bool has_compressed_files;
HashTable manifest;
php_uint32 min_timestamp;
static int phar_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC);
static size_t phar_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
+static size_t phar_dirwrite(php_stream *stream, const char *buf, size_t count TSRMLS_DC);
static int phar_flush(php_stream *stream TSRMLS_DC);
+static int phar_dirflush(php_stream *stream TSRMLS_DC);
static int phar_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC);
static int phar_stream_stat(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
}
/* }}} */
+/**
+ * Create a new dummy file slot within a writeable phar for a newly created file
+ */
+static phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ phar_entry_info *entry, etemp;
+ phar_entry_data *ret;
+ if ((phar = phar_get_archive(fname, fname_len, NULL, 0 TSRMLS_CC)) == NULL) {
+ return NULL;
+ }
+ if (NULL == (ret = phar_get_entry_data(fname, fname_len, path, path_len TSRMLS_CC))) {
+ /* create an entry, this is a new file */
+ if ((entry = phar_get_entry_info(phar, path, path_len TSRMLS_CC)) != NULL) {
+ ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
+ entry = (phar_entry_info *) emalloc(sizeof(phar_entry_info));
+ etemp.filename_len = path_len;
+ etemp.filename = estrndup(path, path_len);
+ etemp.uncompressed_filesize = 0;
+ etemp.compressed_filesize = 0;
+ etemp.timestamp = time(0);
+ etemp.offset_within_phar = -1;
+ etemp.crc32 = 0;
+ etemp.crc_checked = TRUE;
+ etemp.fp = NULL;
+ etemp.temp_file = 0;
+ memcpy((void *) entry, (void *) &etemp, sizeof(phar_entry_info));
+ zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)entry, sizeof(phar_entry_info), NULL);
+ }
+ }
+ ret->phar = phar;
+ ret->internal_file = entry;
+ if (entry->fp) {
+ /* transfer ownership */
+ ret->fp = entry->fp;
+ php_stream_seek(ret->fp, 0, SEEK_SET);
+ entry->fp = 0;
+ } else {
+ ret->fp = 0;
+ }
+ if (ret->internal_file->temp_file == 0) {
+ /* create atemporary stream for our new file */
+ ret->internal_file->temp_file = php_stream_fopen_tmpfile();
+ ret->internal_file->flags |= PHAR_ENT_MODIFIED;
+ }
+ return ret;
+}
+/* }}} */
+
/* {{{ proto string apiVersion()
* Returns the api version */
PHP_METHOD(Phar, apiVersion)
+ ((unsigned char)buffer[2]) << 16 \
+ ((unsigned char)buffer[1]) << 8 \
+ ((unsigned char)buffer[0]); \
- buffer += 4get_entry_data
+ buffer += 4
#else
# define PHAR_GET_32(buffer, var) \
var = *(php_uint32*)(buffer); \
*
* This is used by phar_open_filename to process the manifest, but can be called
* directly.
+ *
+ * If reload is TRUE, this will overwrite the existing entry (essentially reload the information)
*/
-static 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) /* {{{ */
+static int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, zend_bool reload TSRMLS_DC) /* {{{ */
{
char b32[4], *buffer, *endbuffer, *savebuf;
phar_archive_data *mydata;
int compressed = 0;
int register_alias;
- if (pphar) {
+ if (!reload && pphar) {
*pphar = NULL;
}
if ((mydata = phar_get_archive(fname, fname_len, alias, alias_len TSRMLS_CC)) != NULL) {
- /* Overloading or reloading an archive would only be possible if we */
- /* refcount everything to be sure no stream for any file in the */
- /* archive is open. */
- if (fname_len != mydata->fname_len || strncmp(fname, mydata->fname, fname_len)) {
- php_stream_close(fp);
- php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, mydata->fname, fname);
- return FAILURE;
+ if (reload) {
+ /* start over */
+ zend_hash_destroy(&mydata->manifest);
} else {
- if (pphar) {
- *pphar = mydata;
- }
- php_stream_close(fp);
- return SUCCESS;
+ /* Overloading or reloading an archive would only be possible if we */
+ /* refcount everything to be sure no stream for any file in the */
+ /* archive is open. */
+ if (fname_len != mydata->fname_len || strncmp(fname, mydata->fname, fname_len)) {
+ php_stream_close(fp);
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, mydata->fname, fname);
+ return FAILURE;
+ } else {
+ if (pphar) {
+ *pphar = mydata;
+ }
+ php_stream_close(fp);
+ return SUCCESS;
+ }
}
}
mydata->alias_len = alias ? alias_len : fname_len;
snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_tag >> 12, (manifest_tag >> 8) & 0xF, (manifest_tag >> 4) & 0xF);
mydata->internal_file_start = halt_offset + manifest_len + 4;
+ mydata->halt_offset = halt_offset;
mydata->has_compressed_files = compressed;
mydata->fp = fp;
mydata->refcount = 0;
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void*)&mydata, sizeof(phar_archive_data), NULL);
if (register_alias) {
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
}
efree(savebuf);
- if (pphar) {
+ if (!reload && pphar) {
*pphar = mydata;
}
}
/* }}} */
+/**
+ * Create or open a phar for writing
+ */
+static int phar_create_or_open_filename(char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar TSRMLS_CC) /* {{{ */
+{
+ phar_archive_data *mydata;
+ int register_alias;
+ php_stream *fp;
+ phar_archive_data *phar;
+
+ if (pphar) {
+ *pphar = NULL;
+ }
+
+ if ((phar = phar_get_archive(fname, fname_len, alias, alias_len TSRMLS_CC)) != NULL) {
+ if (fname_len != phar->fname_len || strncmp(fname, phar->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, phar->fname, fname);
+ return FAILURE;
+ } else {
+ if (pphar) {
+ *pphar = phar;
+ }
+ return SUCCESS;
+ }
+ }
+ /* set up our manifest */
+ mydata = emalloc(sizeof(phar_archive_data));
+ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
+ zend_get_hash_value, destroy_phar_manifest, 0);
+ mydata->min_timestamp = 0;
+ mydata->max_timestamp = 0;
+ mydata->fname = estrndup(fname, fname_len);
+ mydata->fname_len = fname_len;
+ mydata->alias = alias ? estrndup(alias, alias_len) : mydata->fname;
+ mydata->alias_len = alias ? alias_len : fname_len;
+ snprintf(mydata->version, sizeof(mydata->version), "%s", PHAR_VERSION_STR);
+ mydata->internal_file_start = -1;
+ mydata->halt_offset = 0;
+ mydata->has_compressed_files = 0;
+ mydata->fp = fp;
+ mydata->refcount = 0;
+ if (!alias_len || !alias) {
+ /* if we neither have an explicit nor an implicit alias, we use the filename */
+ alias = NULL;
+ alias_len = 0;
+ register_alias = 0;
+ } else {
+ register_alias = 1;
+ }
+ zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void*)&mydata, sizeof(phar_archive_data), NULL);
+ if (register_alias) {
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
+ }
+ return SUCCESS;
+}
+
/**
* Scan a phar file for the required __HALT_COMPILER(); ?> token and verify
* that the manifest is proper, then pass it to phar_open_file(). SUCCESS
}
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, FALSE TSRMLS_CC);
}
halt_offset += readsize;
/* fprintf(stderr, "Fragment: %s\n", resource->fragment);*/
}
#endif
- if (phar_open_filename(resource->host, arch_len, NULL, 0, NULL TSRMLS_CC) == FAILURE)
- {
- php_url_free(resource);
- return NULL;
- }
-
+ if (strcmp(mode, "wb") == 0 || strcmp(mode, "w") == 0) {
+ if (phar_create_or_open_filename(resource->host, arch_len, NULL, 0, NULL TSRMLS_CC) == FAILURE)
+ {
+ php_url_free(resource);
+ return NULL;
+ }
+ } else {
+ if (phar_open_filename(resource->host, arch_len, NULL, 0, NULL TSRMLS_CC) == FAILURE)
+ {
+ php_url_free(resource);
+ return NULL;
+ }
+ }
return resource;
}
return FAILURE;
}
- return phar_open_file(fp, fname, strlen(fname), alias, alias_len, halt_offset, NULL TSRMLS_CC);
+ return phar_open_file(fp, fname, strlen(fname), alias, alias_len, halt_offset, NULL, FALSE TSRMLS_CC);
}
/* }}} */
} /* }}} */
static php_stream_ops phar_ops = {
- phar_write, /* write (does nothing) */
+ phar_write, /* write */
phar_read, /* read */
phar_close, /* close */
- phar_flush, /* flush (does nothing) */
+ phar_flush, /* flush */
"phar stream",
phar_seek, /* seek */
NULL, /* cast */
};
static php_stream_ops phar_dir_ops = {
- phar_write, /* write (does nothing) */
+ phar_dirwrite, /* write (does nothing) */
phar_readdir, /* read */
phar_closedir, /* close */
- phar_flush, /* flush (does nothing) */
+ phar_dirflush, /* flush (does nothing) */
"phar stream",
phar_seekdir, /* seek */
NULL, /* cast */
/* strip leading "/" */
internal_file = estrdup(resource->path + 1);
- if (NULL == (idata = phar_get_entry_data(resource->host, strlen(resource->host), internal_file, strlen(internal_file) TSRMLS_CC))) {
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host);
- efree(internal_file);
- php_url_free(resource);
- return NULL;
+ if (strcmp(mode, "wb") == 0 || strcmp(mode, "w") == 0) {
+ if (NULL == (idata = phar_get_or_create_entry_data(resource->host, strlen(resource->host), internal_file, strlen(internal_file) TSRMLS_CC))) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
+ efree(internal_file);
+ php_url_free(resource);
+ return NULL;
+ }
+ } else {
+ if (NULL == (idata = phar_get_entry_data(resource->host, strlen(resource->host), internal_file, strlen(internal_file) TSRMLS_CC))) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host);
+ efree(internal_file);
+ php_url_free(resource);
+ return NULL;
+ }
}
php_url_free(resource);
* Used for writing to a phar file
*/
static size_t phar_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *data = (phar_entry_data *) stream->abstract;
+
+ if (data->internal_file->temp_file == 0) {
+ /* create a new temporary stream for our new file */
+ data->internal_file->temp_file = php_stream_fopen_tmpfile();
+ }
+ if (count != php_stream_write(data->internal_file->temp_file, buf, count)) {
+ php_stream_close(data->internal_file->temp_file);
+ 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);
+ return -1;
+ }
+ data->internal_file->flags |= PHAR_ENT_MODIFIED;
+ return 0;
+}
+/* }}} */
+
+/**
+ * Dummy: Used for writing to a phar directory (i.e. not used)
+ */
+static size_t phar_dirwrite(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
{
return 0;
}
/* }}} */
+#ifdef WORDS_BIGENDIAN
+# define PHAR_SET_32(buffer, var) \
+ *((buffer) + 3) = (unsigned char) (((var) << 24) & 0xFF); \
+ *((buffer) + 2) = (unsigned char) (((var) << 16) & 0xFF); \
+ *((buffer) + 1) = (unsigned char) (((var) << 8) & 0xFF); \
+ *(buffer) = (unsigned char) ((var) & 0xFF);
+# define PHAR_SET_16(buffer, var) \
+ *((buffer) + 1) = (unsigned char) (((var) << 8) & 0xFF); \
+ *(buffer) = (unsigned char) ((var) & 0xFF);
+#else
+# define PHAR_SET_32(buffer, var) \
+ *(php_uint32 *)buffer = *(php_uint32*)(var);
+# define PHAR_SET_16(buffer, var) \
+ *(php_uint16 *)buffer = *(php_uint16*)(var);
+#endif
+
/**
* Used to save work done on a writeable phar
*/
static int phar_flush(php_stream *stream TSRMLS_DC) /* {{{ */
+{
+ phar_entry_data *data = (phar_entry_data *)stream->abstract;
+ phar_entry_info *entry;
+ char *buffer;
+ char *manifest;
+ off_t manifest_ftell, bufsize, file_ftell;
+ php_uint32 copy, loc, newcrc32;
+ php_stream *file, *newfile, *compressedfile;
+ php_stream_filter *filter;
+
+ if (stream->mode != "w" && stream->mode != "wb") {
+ return EOF;
+ }
+ newfile = php_stream_fopen_tmpfile();
+ filter = 0;
+
+ if (data->phar->halt_offset) {
+ if (data->phar->halt_offset != php_stream_copy_to_stream(newfile, data->fp, data->phar->halt_offset))
+ {
+
+ }
+ }
+ manifest_ftell = php_stream_tell(data->fp);
+ buffer = (char *) emalloc(300);
+ bufsize = 300;
+ /* 4: manifest length, 4: manifest entry count, 2: phar version,
+ 4: alias length, the rest is the alias itself
+ */
+ manifest = (char *) emalloc(14 + data->phar->alias_len);
+ /* use dummy value until we know the actual length */
+ copy = 0;
+ PHAR_SET_32(manifest, copy); /* manifest length */
+ manifest += 4;
+ PHAR_SET_32(manifest, data->phar->manifest.nNumOfElements);
+ manifest += 4;
+ copy = PHAR_API_VERSION;
+ PHAR_SET_16(manifest, copy);
+ manifest += 2;
+ PHAR_SET_32(manifest, data->phar->alias_len);
+ manifest -= 10;
+ memcpy(manifest + 14, data->phar->alias, data->phar->alias_len);
+
+ /* write the manifest header */
+ php_stream_write(newfile, manifest, 14 + data->phar->alias_len);
+
+ for (zend_hash_internal_pointer_reset(&data->phar->manifest);
+ zend_hash_has_more_elements(&data->phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&data->phar->manifest)) {
+ if (zend_hash_get_current_data(&data->phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (entry->flags & PHAR_ENT_DELETED) {
+ /* remove this from the new phar */
+ continue;
+ }
+ PHAR_SET_32(buffer, entry->filename_len);
+ memcpy(buffer + 4, entry->filename, entry->filename_len);
+ if (4 + entry->filename_len != php_stream_write(newfile, buffer, 4 + entry->filename_len)) {
+
+ }
+ if (entry->flags & PHAR_ENT_MODIFIED) {
+ if (!entry->temp_file) {
+ /* nothing to do here */
+ continue;
+ }
+ } else {
+ /* set the manifest meta-data:
+ 4: uncompressed filesize
+ 4: creation timestamp
+ 4: compressed filesize
+ 4: crc32
+ 1: flags (compression or not)
+ */
+ copy = time(NULL);
+ PHAR_SET_32(buffer, entry->uncompressed_filesize);
+ buffer += 4;
+ PHAR_SET_32(buffer, copy);
+ buffer += 4;
+ PHAR_SET_32(buffer, entry->compressed_filesize);
+ buffer += 4;
+ PHAR_SET_32(buffer, entry->crc32);
+ buffer[4] = (char) entry->flags;
+ buffer -= 11;
+ php_stream_write(newfile, buffer, 17);
+ }
+ }
+ /* write the actual manifest size */
+ file_ftell = php_stream_tell(newfile);
+ copy = file_ftell - manifest_ftell;
+ PHAR_SET_32(manifest, copy);
+ php_stream_seek(newfile, manifest_ftell, SEEK_SET);
+ /* write the manifest header */
+ php_stream_write(newfile, manifest, 2);
+ php_stream_seek(newfile, file_ftell, SEEK_SET);
+
+ compressedfile = php_stream_fopen_tmpfile();
+ /* now copy the actual file data to the new phar */
+ for (zend_hash_internal_pointer_reset(&data->phar->manifest);
+ zend_hash_has_more_elements(&data->phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&data->phar->manifest)) {
+ if (zend_hash_get_current_data(&data->phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (entry->flags & PHAR_ENT_DELETED) {
+ /* remove this from the new phar */
+ continue;
+ }
+ if (entry->flags & PHAR_ENT_MODIFIED) {
+ if (!entry->temp_file) {
+ /* nothing to do here */
+ continue;
+ }
+ php_stream_rewind(entry->temp_file);
+ file = entry->temp_file;
+ } else {
+ php_stream_seek(data->fp, entry->offset_within_phar, SEEK_SET);
+ file = data->fp;
+ copy = entry->uncompressed_filesize;
+ }
+ if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
+ filter = php_stream_filter_create("zlib.deflate", NULL, 0 TSRMLS_CC);
+ if (!filter) {
+
+ }
+ php_stream_filter_append(&file->readfilters, filter);
+ if (bufsize < entry->uncompressed_filesize) {
+ buffer = (char *) erealloc((void *)buffer, entry->uncompressed_filesize);
+ }
+ copy = php_stream_read(file, buffer, entry->uncompressed_filesize);
+ entry->compressed_filesize = copy;
+ newcrc32 = 0;
+ for (loc = 0;loc < copy; loc++) {
+ CRC32(newcrc32, *(buffer + loc));
+ }
+ php_stream_filter_remove(filter, 1);
+ php_stream_rewind(compressedfile);
+ php_stream_write(compressedfile, buffer, copy);
+ file = compressedfile;
+ entry->crc32 = newcrc32;
+ } else if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
+ filter = php_stream_filter_create("zlib.deflate", NULL, 0 TSRMLS_CC);
+ if (!filter) {
+
+ }
+ php_stream_filter_append(&file->readfilters, filter);
+ if (bufsize < entry->uncompressed_filesize) {
+ buffer = (char *) erealloc((void *)buffer, entry->uncompressed_filesize);
+ }
+ copy = php_stream_read(data->fp, buffer, entry->uncompressed_filesize);
+ entry->compressed_filesize = copy;
+ newcrc32 = 0;
+ for (loc = 0;loc < copy; loc++) {
+ CRC32(newcrc32, *(buffer + loc));
+ }
+ php_stream_filter_remove(filter, 1);
+ php_stream_rewind(compressedfile);
+ php_stream_write(compressedfile, buffer, copy);
+ file = compressedfile;
+ entry->crc32 = newcrc32;
+ }
+ if (copy != php_stream_copy_to_stream(newfile, file, copy)) {
+
+ }
+ /* close the temporary file, no longer needed */
+ if (entry->flags & PHAR_ENT_MODIFIED) {
+ if (entry->temp_file) {
+ php_stream_close(entry->temp_file);
+ entry->temp_file = 0;
+ entry->flags &= ~PHAR_ENT_MODIFIED;
+ }
+ }
+ }
+ php_stream_close(compressedfile);
+ /* now that we know the actual file sizes and CRC32s, re-write the manifest */
+ php_stream_seek(newfile, data->phar->halt_offset + 14 + data->phar->alias_len, SEEK_SET);
+ for (zend_hash_internal_pointer_reset(&data->phar->manifest);
+ zend_hash_has_more_elements(&data->phar->manifest) == SUCCESS;
+ zend_hash_move_forward(&data->phar->manifest)) {
+ if (zend_hash_get_current_data(&data->phar->manifest, (void **)&entry) == FAILURE) {
+ continue;
+ }
+ if (entry->flags & PHAR_ENT_DELETED) {
+ /* already removed from the new phar */
+ continue;
+ }
+ /* skip already written filename */
+ php_stream_seek(newfile, 4 + entry->filename_len, SEEK_CUR);
+ /* set the actual manifest meta-data:
+ 4: uncompressed filesize
+ 4: creation timestamp
+ 4: compressed filesize
+ 4: crc32
+ 1: flags (compression or not)
+ */
+ copy = time(NULL);
+ PHAR_SET_32(buffer, entry->uncompressed_filesize);
+ buffer += 4;
+ PHAR_SET_32(buffer, copy);
+ buffer += 4;
+ PHAR_SET_32(buffer, entry->compressed_filesize);
+ buffer += 4;
+ PHAR_SET_32(buffer, entry->crc32);
+ buffer[4] = (char) entry->flags;
+ buffer -= 11;
+ php_stream_write(newfile, buffer, 17);
+ }
+ /* finally, close the temp file, rename the original phar,
+ move the temp to the old phar, unlink the old phar, and reload it into memory
+ */
+ php_stream_rewind(newfile);
+ VCWD_UNLINK(data->phar->fname);
+ file = php_stream_open_wrapper(data->phar->fname, "wb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+ if (!file) {
+
+ }
+ php_stream_copy_to_stream(newfile, file, PHP_STREAM_COPY_ALL);
+ php_stream_close(newfile);
+ php_stream_close(file);
+ efree(buffer);
+ efree(manifest);
+ file = 0;
+
+#if PHP_MAJOR_VERSION < 6
+ if (PG(safe_mode) && (!php_checkuid(data->phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
+ return FAILURE;
+ }
+#endif
+
+ if (php_check_open_basedir(data->phar->fname TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ file = php_stream_open_wrapper(data->phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
+
+ if (!file) {
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "unable to open phar for reading \"%s\"", data->phar->fname);
+ return FAILURE;
+ }
+
+ if (-1 == php_stream_seek(file, data->phar->halt_offset, SEEK_SET)) {
+
+ }
+
+ phar_open_file(file, data->phar->fname, data->phar->fname_len, data->phar->alias, data->phar->alias_len, data->phar->halt_offset, &data->phar, TRUE TSRMLS_CC);
+ return EOF;
+}
+/* }}} */
+
+/**
+ * Dummy: Used for flushing writes to a phar directory (i.e. not used)
+ */
+static int phar_dirflush(php_stream *stream TSRMLS_DC) /* {{{ */
{
return EOF;
}