Return to zip_stream.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / zip |
1.1.1.2 ! misho 1: /* $Id$ */
1.1 misho 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: {
33: ssize_t n = 0;
34: STREAM_DATA_FROM_STREAM();
35:
36: if (self->za && self->zf) {
37: n = zip_fread(self->zf, buf, count);
38: if (n < 0) {
39: int ze, se;
40: zip_file_error_get(self->zf, &ze, &se);
41: stream->eof = 1;
42: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zip stream error: %s", zip_file_strerror(self->zf));
43: return 0;
44: }
45: /* cast count to signed value to avoid possibly negative n
46: * being cast to unsigned value */
47: if (n == 0 || n < (ssize_t)count) {
48: stream->eof = 1;
49: } else {
50: self->cursor += n;
51: }
52: }
53: return (n < 1 ? 0 : (size_t)n);
54: }
55: /* }}} */
56:
57: /* {{{ php_zip_ops_write */
58: static size_t php_zip_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
59: {
60: if (!stream) {
61: return 0;
62: }
63:
64: return count;
65: }
66: /* }}} */
67:
68: /* {{{ php_zip_ops_close */
69: static int php_zip_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
70: {
71: STREAM_DATA_FROM_STREAM();
72: if (close_handle) {
73: if (self->zf) {
74: zip_fclose(self->zf);
75: self->zf = NULL;
76: }
77:
78: if (self->za) {
79: zip_close(self->za);
80: self->za = NULL;
81: }
82: }
83: efree(self);
84: stream->abstract = NULL;
85: return EOF;
86: }
87: /* }}} */
88:
89: /* {{{ php_zip_ops_flush */
90: static int php_zip_ops_flush(php_stream *stream TSRMLS_DC)
91: {
92: if (!stream) {
93: return 0;
94: }
95:
96: return 0;
97: }
98: /* }}} */
99:
100: static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
101: {
102: struct zip_stat sb;
103: const char *path = stream->orig_path;
104: int path_len = strlen(stream->orig_path);
105: char *file_basename;
106: size_t file_basename_len;
107: char file_dirname[MAXPATHLEN];
108: struct zip *za;
109: char *fragment;
110: int fragment_len;
111: int err;
112:
113: fragment = strchr(path, '#');
114: if (!fragment) {
115: return -1;
116: }
117:
118:
119: if (strncasecmp("zip://", path, 6) == 0) {
120: path += 6;
121: }
122:
123: fragment_len = strlen(fragment);
124:
125: if (fragment_len < 1) {
126: return -1;
127: }
128: path_len = strlen(path);
129: if (path_len >= MAXPATHLEN) {
130: return -1;
131: }
132:
133: memcpy(file_dirname, path, path_len - fragment_len);
134: file_dirname[path_len - fragment_len] = '\0';
135:
136: php_basename((char *)path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC);
137: fragment++;
138:
139: if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) {
140: efree(file_basename);
141: return -1;
142: }
143:
144: za = zip_open(file_dirname, ZIP_CREATE, &err);
145: if (za) {
146: memset(ssb, 0, sizeof(php_stream_statbuf));
147: if (zip_stat(za, fragment, ZIP_FL_NOCASE, &sb) != 0) {
148: efree(file_basename);
149: return -1;
150: }
151: zip_close(za);
152:
153: if (path[path_len-1] != '/') {
154: ssb->sb.st_size = sb.size;
155: ssb->sb.st_mode |= S_IFREG; /* regular file */
156: } else {
157: ssb->sb.st_size = 0;
158: ssb->sb.st_mode |= S_IFDIR; /* regular directory */
159: }
160:
161: ssb->sb.st_mtime = sb.mtime;
162: ssb->sb.st_atime = sb.mtime;
163: ssb->sb.st_ctime = sb.mtime;
164: ssb->sb.st_nlink = 1;
165: ssb->sb.st_rdev = -1;
166: #ifndef PHP_WIN32
167: ssb->sb.st_blksize = -1;
168: ssb->sb.st_blocks = -1;
169: #endif
170: ssb->sb.st_ino = -1;
171: }
172: efree(file_basename);
173: return 0;
174: }
175: /* }}} */
176:
177: php_stream_ops php_stream_zipio_ops = {
178: php_zip_ops_write, php_zip_ops_read,
179: php_zip_ops_close, php_zip_ops_flush,
180: "zip",
181: NULL, /* seek */
182: NULL, /* cast */
183: php_zip_ops_stat, /* stat */
184: NULL /* set_option */
185: };
186:
187: /* {{{ php_stream_zip_open */
188: php_stream *php_stream_zip_open(char *filename, char *path, char *mode STREAMS_DC TSRMLS_DC)
189: {
190: struct zip_file *zf = NULL;
191: int err = 0;
192:
193: php_stream *stream = NULL;
194: struct php_zip_stream_data_t *self;
195: struct zip *stream_za;
196:
197: if (strncmp(mode,"r", strlen("r")) != 0) {
198: return NULL;
199: }
200:
201: if (filename) {
202: if (ZIP_OPENBASEDIR_CHECKPATH(filename)) {
203: return NULL;
204: }
205:
206: /* duplicate to make the stream za independent (esp. for MSHUTDOWN) */
207: stream_za = zip_open(filename, ZIP_CREATE, &err);
208: if (!stream_za) {
209: return NULL;
210: }
211:
212: zf = zip_fopen(stream_za, path, 0);
213: if (zf) {
214: self = emalloc(sizeof(*self));
215:
216: self->za = stream_za;
217: self->zf = zf;
218: self->stream = NULL;
219: self->cursor = 0;
220: stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
221: stream->orig_path = estrdup(path);
222: } else {
223: zip_close(stream_za);
224: }
225: }
226:
227: if (!stream) {
228: return NULL;
229: } else {
230: return stream;
231: }
232:
233: }
234: /* }}} */
235:
236: /* {{{ php_stream_zip_opener */
237: php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
238: char *path,
239: char *mode,
240: int options,
241: char **opened_path,
242: php_stream_context *context STREAMS_DC TSRMLS_DC)
243: {
244: int path_len;
245:
246: char *file_basename;
247: size_t file_basename_len;
248: char file_dirname[MAXPATHLEN];
249:
250: struct zip *za;
251: struct zip_file *zf = NULL;
252: char *fragment;
253: int fragment_len;
254: int err;
255:
256: php_stream *stream = NULL;
257: struct php_zip_stream_data_t *self;
258:
259: fragment = strchr(path, '#');
260: if (!fragment) {
261: return NULL;
262: }
263:
264: if (strncasecmp("zip://", path, 6) == 0) {
265: path += 6;
266: }
267:
268: fragment_len = strlen(fragment);
269:
270: if (fragment_len < 1) {
271: return NULL;
272: }
273: path_len = strlen(path);
274: if (path_len >= MAXPATHLEN || mode[0] != 'r') {
275: return NULL;
276: }
277:
278: memcpy(file_dirname, path, path_len - fragment_len);
279: file_dirname[path_len - fragment_len] = '\0';
280:
281: php_basename(path, path_len - fragment_len, NULL, 0, &file_basename, &file_basename_len TSRMLS_CC);
282: fragment++;
283:
284: if (ZIP_OPENBASEDIR_CHECKPATH(file_dirname)) {
285: efree(file_basename);
286: return NULL;
287: }
288:
289: za = zip_open(file_dirname, ZIP_CREATE, &err);
290: if (za) {
291: zf = zip_fopen(za, fragment, 0);
292: if (zf) {
293: self = emalloc(sizeof(*self));
294:
295: self->za = za;
296: self->zf = zf;
297: self->stream = NULL;
298: self->cursor = 0;
299: stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
300:
301: if (opened_path) {
302: *opened_path = estrdup(path);
303: }
304: } else {
305: zip_close(za);
306: }
307: }
308:
309: efree(file_basename);
310:
311: if (!stream) {
312: return NULL;
313: } else {
314: return stream;
315: }
316: }
317: /* }}} */
318:
319: static php_stream_wrapper_ops zip_stream_wops = {
320: php_stream_zip_opener,
321: NULL, /* close */
322: NULL, /* fstat */
323: NULL, /* stat */
324: NULL, /* opendir */
325: "zip wrapper",
326: NULL, /* unlink */
327: NULL, /* rename */
328: NULL, /* mkdir */
329: NULL /* rmdir */
330: };
331:
332: php_stream_wrapper php_stream_zip_wrapper = {
333: &zip_stream_wops,
334: NULL,
335: 0 /* is_url */
336: };
337: #endif /* ZEND_ENGINE_2 */
338: #endif /* HAVE_ZIP */