Back to index

php5  5.3.10
zip_stream.c
Go to the documentation of this file.
00001 /* $Id: zip_stream.c 307917 2011-02-01 14:44:29Z cataphract $ */
00002 #ifdef HAVE_CONFIG_H
00003 #   include "config.h"
00004 #endif
00005 #include "php.h"
00006 #if HAVE_ZIP
00007 #ifdef ZEND_ENGINE_2
00008 
00009 #include "lib/zip.h"
00010 
00011 #include "php_streams.h"
00012 #include "ext/standard/file.h"
00013 #include "ext/standard/php_string.h"
00014 #include "fopen_wrappers.h"
00015 #include "php_zip.h"
00016 
00017 #include "ext/standard/url.h"
00018 
00019 struct php_zip_stream_data_t {
00020        struct zip *za;
00021        struct zip_file *zf;
00022        size_t cursor;
00023        php_stream *stream;
00024 };
00025 
00026 #define STREAM_DATA_FROM_STREAM() \
00027        struct php_zip_stream_data_t *self = (struct php_zip_stream_data_t *) stream->abstract;
00028 
00029 
00030 /* {{{ php_zip_ops_read */
00031 static size_t php_zip_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
00032 {
00033        ssize_t n = 0;
00034        STREAM_DATA_FROM_STREAM();
00035 
00036        if (self->za && self->zf) {
00037               n = zip_fread(self->zf, buf, count);
00038               if (n < 0) {
00039                      int ze, se;
00040                      zip_file_error_get(self->zf, &ze, &se);
00041                      stream->eof = 1;
00042                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zip stream error: %s", zip_file_strerror(self->zf));
00043                      return 0;
00044               }
00045               /* cast count to signed value to avoid possibly negative n
00046                * being cast to unsigned value */
00047               if (n == 0 || n < (ssize_t)count) {
00048                      stream->eof = 1;
00049               } else {
00050                      self->cursor += n;
00051               }
00052        }
00053        return (n < 1 ? 0 : (size_t)n);
00054 }
00055 /* }}} */
00056 
00057 /* {{{ php_zip_ops_write */
00058 static size_t php_zip_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
00059 {
00060        if (!stream) {
00061               return 0;
00062        }
00063 
00064        return count;
00065 }
00066 /* }}} */
00067 
00068 /* {{{ php_zip_ops_close */
00069 static int php_zip_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
00070 {
00071        STREAM_DATA_FROM_STREAM();
00072        if (close_handle) {
00073               if (self->zf) {
00074                      zip_fclose(self->zf);
00075                      self->zf = NULL;
00076               }
00077 
00078               if (self->za) {
00079                      zip_close(self->za);
00080                      self->za = NULL;
00081               }
00082        }
00083        efree(self);
00084        stream->abstract = NULL;
00085        return EOF;
00086 }
00087 /* }}} */
00088 
00089 /* {{{ php_zip_ops_flush */
00090 static int php_zip_ops_flush(php_stream *stream TSRMLS_DC)
00091 {
00092        if (!stream) {
00093               return 0;
00094        }
00095 
00096        return 0;
00097 }
00098 /* }}} */
00099 
00100 static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
00101 {
00102        struct zip_stat sb;
00103        const char *path = stream->orig_path;
00104        int path_len = strlen(stream->orig_path);
00105        char *file_basename;
00106        size_t file_basename_len;
00107        char file_dirname[MAXPATHLEN];
00108        struct zip *za;
00109        char *fragment;
00110        int fragment_len;
00111        int err;
00112 
00113        fragment = strchr(path, '#');
00114        if (!fragment) {
00115               return -1;
00116        }
00117 
00118 
00119        if (strncasecmp("zip://", path, 6) == 0) {
00120               path += 6;
00121        }
00122 
00123        fragment_len = strlen(fragment);
00124 
00125        if (fragment_len < 1) {
00126               return -1;
00127        }
00128        path_len = strlen(path);
00129        if (path_len >= MAXPATHLEN) {
00130               return -1;
00131        }
00132 
00133        memcpy(file_dirname, path, path_len - fragment_len);
00134        file_dirname[path_len - fragment_len] = '\0';
00135 
00136        php_basename((char *)path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC);
00137        fragment++;
00138 
00139        if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) {
00140               efree(file_basename);
00141               return -1;
00142        }
00143 
00144        za = zip_open(file_dirname, ZIP_CREATE, &err);
00145        if (za) {
00146               memset(ssb, 0, sizeof(php_stream_statbuf));
00147               if (zip_stat(za, fragment, ZIP_FL_NOCASE, &sb) != 0) {
00148                      efree(file_basename);
00149                      return -1;
00150               }
00151               zip_close(za);
00152 
00153               if (path[path_len-1] != '/') {
00154                      ssb->sb.st_size = sb.size;
00155                      ssb->sb.st_mode |= S_IFREG; /* regular file */
00156               } else {
00157                      ssb->sb.st_size = 0;
00158                      ssb->sb.st_mode |= S_IFDIR; /* regular directory */
00159               }
00160 
00161               ssb->sb.st_mtime = sb.mtime;
00162               ssb->sb.st_atime = sb.mtime;
00163               ssb->sb.st_ctime = sb.mtime;
00164               ssb->sb.st_nlink = 1;
00165               ssb->sb.st_rdev = -1;
00166 #ifndef PHP_WIN32
00167               ssb->sb.st_blksize = -1;
00168               ssb->sb.st_blocks = -1;
00169 #endif
00170               ssb->sb.st_ino = -1;
00171        }
00172        efree(file_basename);
00173        return 0;
00174 }
00175 /* }}} */
00176 
00177 php_stream_ops php_stream_zipio_ops = {
00178        php_zip_ops_write, php_zip_ops_read,
00179        php_zip_ops_close, php_zip_ops_flush,
00180        "zip",
00181        NULL, /* seek */
00182        NULL, /* cast */
00183        php_zip_ops_stat, /* stat */
00184        NULL  /* set_option */
00185 };
00186 
00187 /* {{{ php_stream_zip_open */
00188 php_stream *php_stream_zip_open(char *filename, char *path, char *mode STREAMS_DC TSRMLS_DC)
00189 {
00190        struct zip_file *zf = NULL;
00191        int err = 0;
00192 
00193        php_stream *stream = NULL;
00194        struct php_zip_stream_data_t *self;
00195        struct zip *stream_za;
00196 
00197        if (strncmp(mode,"r", strlen("r")) != 0) {
00198               return NULL;
00199        }
00200 
00201        if (filename) {
00202               if (ZIP_OPENBASEDIR_CHECKPATH(filename)) {
00203                      return NULL;
00204               }
00205 
00206               /* duplicate to make the stream za independent (esp. for MSHUTDOWN) */
00207               stream_za = zip_open(filename, ZIP_CREATE, &err);
00208               if (!stream_za) {
00209                      return NULL;
00210               }
00211 
00212               zf = zip_fopen(stream_za, path, 0);
00213               if (zf) {
00214                      self = emalloc(sizeof(*self));
00215 
00216                      self->za = stream_za;
00217                      self->zf = zf; 
00218                      self->stream = NULL;
00219                      self->cursor = 0;
00220                      stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
00221                      stream->orig_path = estrdup(path);
00222               } else {
00223                      zip_close(stream_za);
00224               }
00225        }
00226 
00227        if (!stream) {
00228               return NULL;
00229        } else {
00230               return stream;
00231        }
00232 
00233 }
00234 /* }}} */
00235 
00236 /* {{{ php_stream_zip_opener */
00237 php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
00238                                                                              char *path,
00239                                                                              char *mode,
00240                                                                              int options,
00241                                                                              char **opened_path,
00242                                                                              php_stream_context *context STREAMS_DC TSRMLS_DC)
00243 {
00244        int path_len;
00245 
00246        char *file_basename;
00247        size_t file_basename_len;
00248        char file_dirname[MAXPATHLEN];
00249 
00250        struct zip *za;
00251        struct zip_file *zf = NULL;
00252        char *fragment;
00253        int fragment_len;
00254        int err;
00255 
00256        php_stream *stream = NULL;
00257        struct php_zip_stream_data_t *self;
00258 
00259        fragment = strchr(path, '#');
00260        if (!fragment) {
00261               return NULL;
00262        }
00263 
00264        if (strncasecmp("zip://", path, 6) == 0) {
00265               path += 6;
00266        }
00267 
00268        fragment_len = strlen(fragment);
00269 
00270        if (fragment_len < 1) {
00271               return NULL;
00272        }
00273        path_len = strlen(path);
00274        if (path_len >= MAXPATHLEN || mode[0] != 'r') {
00275               return NULL;
00276        }
00277 
00278        memcpy(file_dirname, path, path_len - fragment_len);
00279        file_dirname[path_len - fragment_len] = '\0';
00280 
00281        php_basename(path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC);
00282        fragment++;
00283 
00284        if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) {
00285               efree(file_basename);
00286               return NULL;
00287        }
00288 
00289        za = zip_open(file_dirname, ZIP_CREATE, &err);
00290        if (za) {
00291               zf = zip_fopen(za, fragment, 0);
00292               if (zf) {
00293                      self = emalloc(sizeof(*self));
00294 
00295                      self->za = za;
00296                      self->zf = zf; 
00297                      self->stream = NULL;
00298                      self->cursor = 0;
00299                      stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
00300 
00301                      if (opened_path) {
00302                             *opened_path = estrdup(path);
00303                      }
00304               } else {
00305                      zip_close(za);
00306               }
00307        }
00308 
00309        efree(file_basename);
00310 
00311        if (!stream) {
00312               return NULL;
00313        } else {
00314               return stream;
00315        }
00316 }
00317 /* }}} */
00318 
00319 static php_stream_wrapper_ops zip_stream_wops = {
00320        php_stream_zip_opener,
00321        NULL,  /* close */
00322        NULL,  /* fstat */
00323        NULL,  /* stat */
00324        NULL,  /* opendir */
00325        "zip wrapper",
00326        NULL,  /* unlink */
00327        NULL,  /* rename */
00328        NULL,  /* mkdir */
00329        NULL   /* rmdir */
00330 };
00331 
00332 php_stream_wrapper php_stream_zip_wrapper = {
00333        &zip_stream_wops,
00334        NULL,
00335        0 /* is_url */
00336 };
00337 #endif /* ZEND_ENGINE_2 */
00338 #endif /* HAVE_ZIP */