1 : /* $Id: zip_stream.c 287104 2009-08-11 17:19:35Z pajoye $ */
2 : #ifdef HAVE_CONFIG_H
3 : # include "config.h"
4 : #endif
5 : #include "php.h"
6 : #if HAVE_ZIP
7 : #ifdef ZEND_ENGINE_2
8 :
9 : #include "lib/zip.h"
10 :
11 : #include "php_streams.h"
12 : #include "ext/standard/file.h"
13 : #include "ext/standard/php_string.h"
14 : #include "fopen_wrappers.h"
15 : #include "php_zip.h"
16 :
17 : #include "ext/standard/url.h"
18 :
19 : struct php_zip_stream_data_t {
20 : struct zip *za;
21 : struct zip_file *zf;
22 : size_t cursor;
23 : php_stream *stream;
24 : };
25 :
26 : #define STREAM_DATA_FROM_STREAM() \
27 : struct php_zip_stream_data_t *self = (struct php_zip_stream_data_t *) stream->abstract;
28 :
29 :
30 : /* {{{ php_zip_ops_read */
31 : static size_t php_zip_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
32 111 : {
33 111 : int n = 0;
34 111 : STREAM_DATA_FROM_STREAM();
35 :
36 111 : if (self->za && self->zf) {
37 111 : n = (size_t)zip_fread(self->zf, buf, (int)count);
38 111 : if (n < 0) {
39 : int ze, se;
40 1 : zip_file_error_get(self->zf, &ze, &se);
41 1 : stream->eof = 1;
42 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zip stream error: %s", zip_file_strerror(self->zf));
43 1 : return 0;
44 : }
45 113 : if (n == 0 || n < count) {
46 3 : stream->eof = 1;
47 : } else {
48 107 : self->cursor += n;
49 : }
50 : }
51 110 : return n<1 ? 0 : n;
52 : }
53 : /* }}} */
54 :
55 : /* {{{ php_zip_ops_write */
56 : static size_t php_zip_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
57 0 : {
58 0 : if (!stream) {
59 0 : return 0;
60 : }
61 :
62 0 : return count;
63 : }
64 : /* }}} */
65 :
66 : /* {{{ php_zip_ops_close */
67 : static int php_zip_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
68 3 : {
69 3 : STREAM_DATA_FROM_STREAM();
70 3 : if (close_handle) {
71 3 : if (self->zf) {
72 3 : zip_fclose(self->zf);
73 3 : self->zf = NULL;
74 : }
75 3 : if (self->za) {
76 3 : zip_close(self->za);
77 3 : self->za = NULL;
78 : }
79 : }
80 3 : efree(self);
81 3 : stream->abstract = NULL;
82 3 : return EOF;
83 : }
84 : /* }}} */
85 :
86 : /* {{{ php_zip_ops_flush */
87 : static int php_zip_ops_flush(php_stream *stream TSRMLS_DC)
88 3 : {
89 3 : if (!stream) {
90 0 : return 0;
91 : }
92 :
93 3 : return 0;
94 : }
95 : /* }}} */
96 :
97 : php_stream_ops php_stream_zipio_ops = {
98 : php_zip_ops_write, php_zip_ops_read,
99 : php_zip_ops_close, php_zip_ops_flush,
100 : "zip",
101 : NULL, /* seek */
102 : NULL, /* cast */
103 : NULL, /* stat */
104 : NULL /* set_option */
105 : };
106 :
107 : /* {{{ php_stream_zip_open */
108 : php_stream *php_stream_zip_open(char *filename, char *path, char *mode STREAMS_DC TSRMLS_DC)
109 2 : {
110 2 : struct zip_file *zf = NULL;
111 2 : int err = 0;
112 :
113 2 : php_stream *stream = NULL;
114 : struct php_zip_stream_data_t *self;
115 : struct zip *stream_za;
116 :
117 2 : if (strncmp(mode,"r", strlen("r")) != 0) {
118 0 : return NULL;
119 : }
120 :
121 2 : if (filename) {
122 2 : if (OPENBASEDIR_CHECKPATH(filename)) {
123 0 : return NULL;
124 : }
125 :
126 : /* duplicate to make the stream za independent (esp. for MSHUTDOWN) */
127 2 : stream_za = zip_open(filename, ZIP_CREATE, &err);
128 2 : if (!stream_za) {
129 0 : return NULL;
130 : }
131 :
132 2 : zf = zip_fopen(stream_za, path, 0);
133 2 : if (zf) {
134 2 : self = emalloc(sizeof(*self));
135 :
136 2 : self->za = stream_za;
137 2 : self->zf = zf;
138 2 : self->stream = NULL;
139 2 : self->cursor = 0;
140 2 : stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
141 : } else {
142 0 : zip_close(stream_za);
143 : }
144 : }
145 :
146 2 : if (!stream) {
147 0 : return NULL;
148 : } else {
149 2 : return stream;
150 : }
151 :
152 : }
153 : /* }}} */
154 :
155 : /* {{{ php_stream_zip_opener */
156 : php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
157 : char *path,
158 : char *mode,
159 : int options,
160 : char **opened_path,
161 : php_stream_context *context STREAMS_DC TSRMLS_DC)
162 1 : {
163 : int path_len;
164 :
165 : char *file_basename;
166 : size_t file_basename_len;
167 : char file_dirname[MAXPATHLEN];
168 :
169 : struct zip *za;
170 1 : struct zip_file *zf = NULL;
171 : char *fragment;
172 : int fragment_len;
173 : int err;
174 :
175 1 : php_stream *stream = NULL;
176 : struct php_zip_stream_data_t *self;
177 :
178 1 : fragment = strchr(path, '#');
179 1 : if (!fragment) {
180 0 : return NULL;
181 : }
182 :
183 1 : if (strncasecmp("zip://", path, 6) == 0) {
184 1 : path += 6;
185 : }
186 :
187 1 : fragment_len = strlen(fragment);
188 :
189 1 : if (fragment_len < 1) {
190 0 : return NULL;
191 : }
192 1 : path_len = strlen(path);
193 1 : if (path_len >= MAXPATHLEN || mode[0] != 'r') {
194 0 : return NULL;
195 : }
196 :
197 1 : memcpy(file_dirname, path, path_len - fragment_len);
198 1 : file_dirname[path_len - fragment_len] = '\0';
199 :
200 1 : php_basename(path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC);
201 1 : fragment++;
202 :
203 1 : if (OPENBASEDIR_CHECKPATH(file_dirname)) {
204 0 : efree(file_basename);
205 0 : return NULL;
206 : }
207 :
208 1 : za = zip_open(file_dirname, ZIP_CREATE, &err);
209 1 : if (za) {
210 1 : zf = zip_fopen(za, fragment, 0);
211 1 : if (zf) {
212 1 : self = emalloc(sizeof(*self));
213 :
214 1 : self->za = za;
215 1 : self->zf = zf;
216 1 : self->stream = NULL;
217 1 : self->cursor = 0;
218 1 : stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
219 :
220 1 : if (opened_path) {
221 0 : *opened_path = estrdup(path);
222 : }
223 : } else {
224 0 : zip_close(za);
225 : }
226 : }
227 :
228 1 : efree(file_basename);
229 :
230 1 : if (!stream) {
231 0 : return NULL;
232 : } else {
233 1 : return stream;
234 : }
235 : }
236 : /* }}} */
237 :
238 : static php_stream_wrapper_ops zip_stream_wops = {
239 : php_stream_zip_opener,
240 : NULL, /* close */
241 : NULL, /* fstat */
242 : NULL, /* stat */
243 : NULL, /* opendir */
244 : "zip wrapper",
245 : NULL, /* unlink */
246 : NULL, /* rename */
247 : NULL, /* mkdir */
248 : NULL /* rmdir */
249 : };
250 :
251 : php_stream_wrapper php_stream_zip_wrapper = {
252 : &zip_stream_wops,
253 : NULL,
254 : 0 /* is_url */
255 : };
256 : #endif /* ZEND_ENGINE_2 */
257 : #endif /* HAVE_ZIP */
|