root/ext/zip/zip_stream.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_zip_ops_read
  2. php_zip_ops_write
  3. php_zip_ops_close
  4. php_zip_ops_flush
  5. php_zip_ops_stat
  6. php_stream_zip_open
  7. php_stream_zip_opener

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt.                                 |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Author: Piere-Alain Joye <pierre@php.net>                            |
  16   +----------------------------------------------------------------------+
  17 */
  18 
  19 #ifdef HAVE_CONFIG_H
  20 #   include "config.h"
  21 #endif
  22 #include "php.h"
  23 #if HAVE_ZIP
  24 #if defined(ZEND_ENGINE_2) || defined(ZEND_ENGINE_3)
  25 
  26 #include "php_streams.h"
  27 #include "ext/standard/file.h"
  28 #include "ext/standard/php_string.h"
  29 #include "fopen_wrappers.h"
  30 #include "php_zip.h"
  31 
  32 #include "ext/standard/url.h"
  33 
  34 struct php_zip_stream_data_t {
  35         struct zip *za;
  36         struct zip_file *zf;
  37         size_t cursor;
  38         php_stream *stream;
  39 };
  40 
  41 #define STREAM_DATA_FROM_STREAM() \
  42         struct php_zip_stream_data_t *self = (struct php_zip_stream_data_t *) stream->abstract;
  43 
  44 
  45 /* {{{ php_zip_ops_read */
  46 static size_t php_zip_ops_read(php_stream *stream, char *buf, size_t count)
  47 {
  48         ssize_t n = 0;
  49         STREAM_DATA_FROM_STREAM();
  50 
  51         if (self->za && self->zf) {
  52                 n = zip_fread(self->zf, buf, count);
  53                 if (n < 0) {
  54 #if LIBZIP_VERSION_MAJOR < 1
  55                         int ze, se;
  56                         zip_file_error_get(self->zf, &ze, &se);
  57                         stream->eof = 1;
  58                         php_error_docref(NULL, E_WARNING, "Zip stream error: %s", zip_file_strerror(self->zf));
  59 #else
  60                         zip_error_t *err;
  61                         err = zip_file_get_error(self->zf);
  62                         stream->eof = 1;
  63                         php_error_docref(NULL, E_WARNING, "Zip stream error: %s", zip_error_strerror(err));
  64                         zip_error_fini(err);
  65 #endif
  66                         return 0;
  67                 }
  68                 /* cast count to signed value to avoid possibly negative n
  69                  * being cast to unsigned value */
  70                 if (n == 0 || n < (ssize_t)count) {
  71                         stream->eof = 1;
  72                 } else {
  73                         self->cursor += n;
  74                 }
  75         }
  76         return (n < 1 ? 0 : (size_t)n);
  77 }
  78 /* }}} */
  79 
  80 /* {{{ php_zip_ops_write */
  81 static size_t php_zip_ops_write(php_stream *stream, const char *buf, size_t count)
  82 {
  83         if (!stream) {
  84                 return 0;
  85         }
  86 
  87         return count;
  88 }
  89 /* }}} */
  90 
  91 /* {{{ php_zip_ops_close */
  92 static int php_zip_ops_close(php_stream *stream, int close_handle)
  93 {
  94         STREAM_DATA_FROM_STREAM();
  95         if (close_handle) {
  96                 if (self->zf) {
  97                         zip_fclose(self->zf);
  98                         self->zf = NULL;
  99                 }
 100 
 101                 if (self->za) {
 102                         zip_close(self->za);
 103                         self->za = NULL;
 104                 }
 105         }
 106         efree(self);
 107         stream->abstract = NULL;
 108         return EOF;
 109 }
 110 /* }}} */
 111 
 112 /* {{{ php_zip_ops_flush */
 113 static int php_zip_ops_flush(php_stream *stream)
 114 {
 115         if (!stream) {
 116                 return 0;
 117         }
 118 
 119         return 0;
 120 }
 121 /* }}} */
 122 
 123 static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */
 124 {
 125         struct zip_stat sb;
 126         const char *path = stream->orig_path;
 127         int path_len = strlen(stream->orig_path);
 128         char file_dirname[MAXPATHLEN];
 129         struct zip *za;
 130         char *fragment;
 131         int fragment_len;
 132         int err;
 133         zend_string *file_basename;
 134 
 135         fragment = strchr(path, '#');
 136         if (!fragment) {
 137                 return -1;
 138         }
 139 
 140 
 141         if (strncasecmp("zip://", path, 6) == 0) {
 142                 path += 6;
 143         }
 144 
 145         fragment_len = strlen(fragment);
 146 
 147         if (fragment_len < 1) {
 148                 return -1;
 149         }
 150         path_len = strlen(path);
 151         if (path_len >= MAXPATHLEN) {
 152                 return -1;
 153         }
 154 
 155         memcpy(file_dirname, path, path_len - fragment_len);
 156         file_dirname[path_len - fragment_len] = '\0';
 157 
 158         file_basename = php_basename((char *)path, path_len - fragment_len, NULL, 0);
 159         fragment++;
 160 
 161         if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) {
 162                 zend_string_release(file_basename);
 163                 return -1;
 164         }
 165 
 166         za = zip_open(file_dirname, ZIP_CREATE, &err);
 167         if (za) {
 168                 memset(ssb, 0, sizeof(php_stream_statbuf));
 169                 if (zip_stat(za, fragment, ZIP_FL_NOCASE, &sb) != 0) {
 170                         zip_close(za);
 171                         zend_string_release(file_basename);
 172                         return -1;
 173                 }
 174                 zip_close(za);
 175 
 176                 if (path[path_len-1] != '/') {
 177                         ssb->sb.st_size = sb.size;
 178                         ssb->sb.st_mode |= S_IFREG; /* regular file */
 179                 } else {
 180                         ssb->sb.st_size = 0;
 181                         ssb->sb.st_mode |= S_IFDIR; /* regular directory */
 182                 }
 183 
 184                 ssb->sb.st_mtime = sb.mtime;
 185                 ssb->sb.st_atime = sb.mtime;
 186                 ssb->sb.st_ctime = sb.mtime;
 187                 ssb->sb.st_nlink = 1;
 188                 ssb->sb.st_rdev = -1;
 189 #ifndef PHP_WIN32
 190                 ssb->sb.st_blksize = -1;
 191                 ssb->sb.st_blocks = -1;
 192 #endif
 193                 ssb->sb.st_ino = -1;
 194         }
 195         zend_string_release(file_basename);
 196         return 0;
 197 }
 198 /* }}} */
 199 
 200 php_stream_ops php_stream_zipio_ops = {
 201         php_zip_ops_write, php_zip_ops_read,
 202         php_zip_ops_close, php_zip_ops_flush,
 203         "zip",
 204         NULL, /* seek */
 205         NULL, /* cast */
 206         php_zip_ops_stat, /* stat */
 207         NULL  /* set_option */
 208 };
 209 
 210 /* {{{ php_stream_zip_open */
 211 php_stream *php_stream_zip_open(const char *filename, const char *path, const char *mode STREAMS_DC)
 212 {
 213         struct zip_file *zf = NULL;
 214         int err = 0;
 215 
 216         php_stream *stream = NULL;
 217         struct php_zip_stream_data_t *self;
 218         struct zip *stream_za;
 219 
 220         if (strncmp(mode,"r", strlen("r")) != 0) {
 221                 return NULL;
 222         }
 223 
 224         if (filename) {
 225                 if (ZIP_OPENBASEDIR_CHECKPATH(filename)) {
 226                         return NULL;
 227                 }
 228 
 229                 /* duplicate to make the stream za independent (esp. for MSHUTDOWN) */
 230                 stream_za = zip_open(filename, ZIP_CREATE, &err);
 231                 if (!stream_za) {
 232                         return NULL;
 233                 }
 234 
 235                 zf = zip_fopen(stream_za, path, 0);
 236                 if (zf) {
 237                         self = emalloc(sizeof(*self));
 238 
 239                         self->za = stream_za;
 240                         self->zf = zf;
 241                         self->stream = NULL;
 242                         self->cursor = 0;
 243                         stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
 244                         stream->orig_path = estrdup(path);
 245                 } else {
 246                         zip_close(stream_za);
 247                 }
 248         }
 249 
 250         if (!stream) {
 251                 return NULL;
 252         } else {
 253                 return stream;
 254         }
 255 
 256 }
 257 /* }}} */
 258 
 259 /* {{{ php_stream_zip_opener */
 260 php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
 261                                                                                         const char *path,
 262                                                                                         const char *mode,
 263                                                                                         int options,
 264                                                                                         zend_string **opened_path,
 265                                                                                         php_stream_context *context STREAMS_DC)
 266 {
 267         int path_len;
 268 
 269         zend_string *file_basename;
 270         char file_dirname[MAXPATHLEN];
 271 
 272         struct zip *za;
 273         struct zip_file *zf = NULL;
 274         char *fragment;
 275         int fragment_len;
 276         int err;
 277 
 278         php_stream *stream = NULL;
 279         struct php_zip_stream_data_t *self;
 280 
 281         fragment = strchr(path, '#');
 282         if (!fragment) {
 283                 return NULL;
 284         }
 285 
 286         if (strncasecmp("zip://", path, 6) == 0) {
 287                 path += 6;
 288         }
 289 
 290         fragment_len = strlen(fragment);
 291 
 292         if (fragment_len < 1) {
 293                 return NULL;
 294         }
 295         path_len = strlen(path);
 296         if (path_len >= MAXPATHLEN || mode[0] != 'r') {
 297                 return NULL;
 298         }
 299 
 300         memcpy(file_dirname, path, path_len - fragment_len);
 301         file_dirname[path_len - fragment_len] = '\0';
 302 
 303         file_basename = php_basename(path, path_len - fragment_len, NULL, 0);
 304         fragment++;
 305 
 306         if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) {
 307                 zend_string_release(file_basename);
 308                 return NULL;
 309         }
 310 
 311         za = zip_open(file_dirname, ZIP_CREATE, &err);
 312         if (za) {
 313                 zf = zip_fopen(za, fragment, 0);
 314                 if (zf) {
 315                         self = emalloc(sizeof(*self));
 316 
 317                         self->za = za;
 318                         self->zf = zf;
 319                         self->stream = NULL;
 320                         self->cursor = 0;
 321                         stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
 322 
 323                         if (opened_path) {
 324                                 *opened_path = zend_string_init(path, strlen(path), 0);
 325                         }
 326                 } else {
 327                         zip_close(za);
 328                 }
 329         }
 330 
 331         zend_string_release(file_basename);
 332 
 333         if (!stream) {
 334                 return NULL;
 335         } else {
 336                 return stream;
 337         }
 338 }
 339 /* }}} */
 340 
 341 static php_stream_wrapper_ops zip_stream_wops = {
 342         php_stream_zip_opener,
 343         NULL,   /* close */
 344         NULL,   /* fstat */
 345         NULL,   /* stat */
 346         NULL,   /* opendir */
 347         "zip wrapper",
 348         NULL,   /* unlink */
 349         NULL,   /* rename */
 350         NULL,   /* mkdir */
 351         NULL    /* rmdir */
 352 };
 353 
 354 php_stream_wrapper php_stream_zip_wrapper = {
 355         &zip_stream_wops,
 356         NULL,
 357         0 /* is_url */
 358 };
 359 #endif /* defined(ZEND_ENGINE_2) || defined(ZEND_ENGINE_3) */
 360 #endif /* HAVE_ZIP */

/* [<][>][^][v][top][bottom][index][help] */