diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/zip/zip_stream.c | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/zip/zip_stream.c')
-rw-r--r-- | ext/zip/zip_stream.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c new file mode 100644 index 0000000..400edd6 --- /dev/null +++ b/ext/zip/zip_stream.c @@ -0,0 +1,338 @@ +/* $Id$ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "php.h" +#if HAVE_ZIP +#ifdef ZEND_ENGINE_2 + +#include "lib/zip.h" + +#include "php_streams.h" +#include "ext/standard/file.h" +#include "ext/standard/php_string.h" +#include "fopen_wrappers.h" +#include "php_zip.h" + +#include "ext/standard/url.h" + +struct php_zip_stream_data_t { + struct zip *za; + struct zip_file *zf; + size_t cursor; + php_stream *stream; +}; + +#define STREAM_DATA_FROM_STREAM() \ + struct php_zip_stream_data_t *self = (struct php_zip_stream_data_t *) stream->abstract; + + +/* {{{ php_zip_ops_read */ +static size_t php_zip_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) +{ + ssize_t n = 0; + STREAM_DATA_FROM_STREAM(); + + if (self->za && self->zf) { + n = zip_fread(self->zf, buf, count); + if (n < 0) { + int ze, se; + zip_file_error_get(self->zf, &ze, &se); + stream->eof = 1; + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zip stream error: %s", zip_file_strerror(self->zf)); + return 0; + } + /* cast count to signed value to avoid possibly negative n + * being cast to unsigned value */ + if (n == 0 || n < (ssize_t)count) { + stream->eof = 1; + } else { + self->cursor += n; + } + } + return (n < 1 ? 0 : (size_t)n); +} +/* }}} */ + +/* {{{ php_zip_ops_write */ +static size_t php_zip_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) +{ + if (!stream) { + return 0; + } + + return count; +} +/* }}} */ + +/* {{{ php_zip_ops_close */ +static int php_zip_ops_close(php_stream *stream, int close_handle TSRMLS_DC) +{ + STREAM_DATA_FROM_STREAM(); + if (close_handle) { + if (self->zf) { + zip_fclose(self->zf); + self->zf = NULL; + } + + if (self->za) { + zip_close(self->za); + self->za = NULL; + } + } + efree(self); + stream->abstract = NULL; + return EOF; +} +/* }}} */ + +/* {{{ php_zip_ops_flush */ +static int php_zip_ops_flush(php_stream *stream TSRMLS_DC) +{ + if (!stream) { + return 0; + } + + return 0; +} +/* }}} */ + +static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */ +{ + struct zip_stat sb; + const char *path = stream->orig_path; + int path_len = strlen(stream->orig_path); + char *file_basename; + size_t file_basename_len; + char file_dirname[MAXPATHLEN]; + struct zip *za; + char *fragment; + int fragment_len; + int err; + + fragment = strchr(path, '#'); + if (!fragment) { + return -1; + } + + + if (strncasecmp("zip://", path, 6) == 0) { + path += 6; + } + + fragment_len = strlen(fragment); + + if (fragment_len < 1) { + return -1; + } + path_len = strlen(path); + if (path_len >= MAXPATHLEN) { + return -1; + } + + memcpy(file_dirname, path, path_len - fragment_len); + file_dirname[path_len - fragment_len] = '\0'; + + php_basename((char *)path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC); + fragment++; + + if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) { + efree(file_basename); + return -1; + } + + za = zip_open(file_dirname, ZIP_CREATE, &err); + if (za) { + memset(ssb, 0, sizeof(php_stream_statbuf)); + if (zip_stat(za, fragment, ZIP_FL_NOCASE, &sb) != 0) { + efree(file_basename); + return -1; + } + zip_close(za); + + if (path[path_len-1] != '/') { + ssb->sb.st_size = sb.size; + ssb->sb.st_mode |= S_IFREG; /* regular file */ + } else { + ssb->sb.st_size = 0; + ssb->sb.st_mode |= S_IFDIR; /* regular directory */ + } + + ssb->sb.st_mtime = sb.mtime; + ssb->sb.st_atime = sb.mtime; + ssb->sb.st_ctime = sb.mtime; + ssb->sb.st_nlink = 1; + ssb->sb.st_rdev = -1; +#ifndef PHP_WIN32 + ssb->sb.st_blksize = -1; + ssb->sb.st_blocks = -1; +#endif + ssb->sb.st_ino = -1; + } + efree(file_basename); + return 0; +} +/* }}} */ + +php_stream_ops php_stream_zipio_ops = { + php_zip_ops_write, php_zip_ops_read, + php_zip_ops_close, php_zip_ops_flush, + "zip", + NULL, /* seek */ + NULL, /* cast */ + php_zip_ops_stat, /* stat */ + NULL /* set_option */ +}; + +/* {{{ php_stream_zip_open */ +php_stream *php_stream_zip_open(char *filename, char *path, char *mode STREAMS_DC TSRMLS_DC) +{ + struct zip_file *zf = NULL; + int err = 0; + + php_stream *stream = NULL; + struct php_zip_stream_data_t *self; + struct zip *stream_za; + + if (strncmp(mode,"r", strlen("r")) != 0) { + return NULL; + } + + if (filename) { + if (ZIP_OPENBASEDIR_CHECKPATH(filename)) { + return NULL; + } + + /* duplicate to make the stream za independent (esp. for MSHUTDOWN) */ + stream_za = zip_open(filename, ZIP_CREATE, &err); + if (!stream_za) { + return NULL; + } + + zf = zip_fopen(stream_za, path, 0); + if (zf) { + self = emalloc(sizeof(*self)); + + self->za = stream_za; + self->zf = zf; + self->stream = NULL; + self->cursor = 0; + stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode); + stream->orig_path = estrdup(path); + } else { + zip_close(stream_za); + } + } + + if (!stream) { + return NULL; + } else { + return stream; + } + +} +/* }}} */ + +/* {{{ php_stream_zip_opener */ +php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, + char *path, + char *mode, + int options, + char **opened_path, + php_stream_context *context STREAMS_DC TSRMLS_DC) +{ + int path_len; + + char *file_basename; + size_t file_basename_len; + char file_dirname[MAXPATHLEN]; + + struct zip *za; + struct zip_file *zf = NULL; + char *fragment; + int fragment_len; + int err; + + php_stream *stream = NULL; + struct php_zip_stream_data_t *self; + + fragment = strchr(path, '#'); + if (!fragment) { + return NULL; + } + + if (strncasecmp("zip://", path, 6) == 0) { + path += 6; + } + + fragment_len = strlen(fragment); + + if (fragment_len < 1) { + return NULL; + } + path_len = strlen(path); + if (path_len >= MAXPATHLEN || mode[0] != 'r') { + return NULL; + } + + memcpy(file_dirname, path, path_len - fragment_len); + file_dirname[path_len - fragment_len] = '\0'; + + php_basename(path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC); + fragment++; + + if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) { + efree(file_basename); + return NULL; + } + + za = zip_open(file_dirname, ZIP_CREATE, &err); + if (za) { + zf = zip_fopen(za, fragment, 0); + if (zf) { + self = emalloc(sizeof(*self)); + + self->za = za; + self->zf = zf; + self->stream = NULL; + self->cursor = 0; + stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode); + + if (opened_path) { + *opened_path = estrdup(path); + } + } else { + zip_close(za); + } + } + + efree(file_basename); + + if (!stream) { + return NULL; + } else { + return stream; + } +} +/* }}} */ + +static php_stream_wrapper_ops zip_stream_wops = { + php_stream_zip_opener, + NULL, /* close */ + NULL, /* fstat */ + NULL, /* stat */ + NULL, /* opendir */ + "zip wrapper", + NULL, /* unlink */ + NULL, /* rename */ + NULL, /* mkdir */ + NULL /* rmdir */ +}; + +php_stream_wrapper php_stream_zip_wrapper = { + &zip_stream_wops, + NULL, + 0 /* is_url */ +}; +#endif /* ZEND_ENGINE_2 */ +#endif /* HAVE_ZIP */ |