Annotation of embedaddon/php/ext/zip/lib/zip_open.c, revision 1.1.1.1
1.1 misho 1: /*
2: zip_open.c -- open zip archive
3: Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
4:
5: This file is part of libzip, a library to manipulate ZIP archives.
6: The authors can be contacted at <libzip@nih.at>
7:
8: Redistribution and use in source and binary forms, with or without
9: modification, are permitted provided that the following conditions
10: are met:
11: 1. Redistributions of source code must retain the above copyright
12: notice, this list of conditions and the following disclaimer.
13: 2. Redistributions in binary form must reproduce the above copyright
14: notice, this list of conditions and the following disclaimer in
15: the documentation and/or other materials provided with the
16: distribution.
17: 3. The names of the authors may not be used to endorse or promote
18: products derived from this software without specific prior
19: written permission.
20:
21: THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22: OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25: DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27: GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28: INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29: IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31: IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34:
35:
36: #include <sys/stat.h>
37: #include <errno.h>
38: #include <limits.h>
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
42:
43: #include "zipint.h"
44:
45: static void set_error(int *, struct zip_error *, int);
46: static struct zip *_zip_allocate_new(const char *, int *);
47: static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
48: static void _zip_check_torrentzip(struct zip *);
49: static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, off_t);
50: static int _zip_file_exists(const char *, int, int *);
51: static int _zip_headercomp(struct zip_dirent *, int,
52: struct zip_dirent *, int);
53: static unsigned char *_zip_memmem(const unsigned char *, int,
54: const unsigned char *, int);
55: static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *,
56: int, int, struct zip_error *);
57:
58:
59:
60: ZIP_EXTERN(struct zip *)
61: zip_open(const char *fn, int flags, int *zep)
62: {
63: FILE *fp;
64: struct zip *za;
65: struct zip_cdir *cdir;
66: int i;
67: off_t len;
68:
69: if (flags & ZIP_OVERWRITE) {
70: return _zip_allocate_new(fn, zep);
71: }
72:
73: switch (_zip_file_exists(fn, flags, zep)) {
74: case -1:
75: if (!(flags & ZIP_OVERWRITE)) {
76: return NULL;
77: }
78:
79: case 0:
80: return _zip_allocate_new(fn, zep);
81:
82: default:
83: break;
84: }
85:
86: if ((fp=fopen(fn, "rb")) == NULL) {
87: set_error(zep, NULL, ZIP_ER_OPEN);
88: return NULL;
89: }
90:
91: fseeko(fp, 0, SEEK_END);
92: len = ftello(fp);
93:
94: /* treat empty files as empty archives */
95: if (len == 0) {
96: if ((za=_zip_allocate_new(fn, zep)) == NULL)
97: fclose(fp);
98: else
99: za->zp = fp;
100: return za;
101: }
102:
103: cdir = _zip_find_central_dir(fp, flags, zep, len);
104: if (cdir == NULL) {
105: fclose(fp);
106: return NULL;
107: }
108:
109: if ((za=_zip_allocate_new(fn, zep)) == NULL) {
110: _zip_cdir_free(cdir);
111: fclose(fp);
112: return NULL;
113: }
114:
115: za->cdir = cdir;
116: za->zp = fp;
117:
118: if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
119: * cdir->nentry)) == NULL) {
120: set_error(zep, NULL, ZIP_ER_MEMORY);
121: _zip_free(za);
122: return NULL;
123: }
124: for (i=0; i<cdir->nentry; i++)
125: _zip_entry_new(za);
126:
127: _zip_check_torrentzip(za);
128: za->ch_flags = za->flags;
129:
130: return za;
131: }
132:
133:
134:
135: static void
136: set_error(int *zep, struct zip_error *err, int ze)
137: {
138: int se;
139:
140: if (err) {
141: _zip_error_get(err, &ze, &se);
142: if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
143: errno = se;
144: }
145:
146: if (zep)
147: *zep = ze;
148: }
149:
150:
151:
152: /* _zip_readcdir:
153: tries to find a valid end-of-central-directory at the beginning of
154: buf, and then the corresponding central directory entries.
155: Returns a struct zip_cdir which contains the central directory
156: entries, or NULL if unsuccessful. */
157:
158: static struct zip_cdir *
159: _zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen,
160: int flags, struct zip_error *error)
161: {
162: struct zip_cdir *cd;
163: unsigned char *cdp, **bufp;
164: int i, comlen, nentry;
165: unsigned int left;
166:
167: comlen = buf + buflen - eocd - EOCDLEN;
168: if (comlen < 0) {
169: /* not enough bytes left for comment */
170: _zip_error_set(error, ZIP_ER_NOZIP, 0);
171: return NULL;
172: }
173:
174: /* check for end-of-central-dir magic */
175: if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
176: _zip_error_set(error, ZIP_ER_NOZIP, 0);
177: return NULL;
178: }
179:
180: if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
181: _zip_error_set(error, ZIP_ER_MULTIDISK, 0);
182: return NULL;
183: }
184:
185: cdp = eocd + 8;
186: /* number of cdir-entries on this disk */
187: i = _zip_read2(&cdp);
188: /* number of cdir-entries */
189: nentry = _zip_read2(&cdp);
190:
191: if ((cd=_zip_cdir_new(nentry, error)) == NULL)
192: return NULL;
193:
194: cd->size = _zip_read4(&cdp);
195: cd->offset = _zip_read4(&cdp);
196: cd->comment = NULL;
197: cd->comment_len = _zip_read2(&cdp);
198:
199: if ((comlen < cd->comment_len) || (cd->nentry != i)) {
200: _zip_error_set(error, ZIP_ER_NOZIP, 0);
201: free(cd);
202: return NULL;
203: }
204: if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) {
205: _zip_error_set(error, ZIP_ER_INCONS, 0);
206: free(cd);
207: return NULL;
208: }
209:
210: if (cd->comment_len) {
211: if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN,
212: cd->comment_len, error))
213: == NULL) {
214: free(cd);
215: return NULL;
216: }
217: }
218:
219: if (cd->size < (unsigned int)(eocd-buf)) {
220: /* if buffer already read in, use it */
221: cdp = eocd - cd->size;
222: bufp = &cdp;
223: }
224: else {
225: /* go to start of cdir and read it entry by entry */
226: bufp = NULL;
227: clearerr(fp);
228: fseeko(fp, cd->offset, SEEK_SET);
229: /* possible consistency check: cd->offset =
230: len-(cd->size+cd->comment_len+EOCDLEN) ? */
231: if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) {
232: /* seek error or offset of cdir wrong */
233: if (ferror(fp))
234: _zip_error_set(error, ZIP_ER_SEEK, errno);
235: else
236: _zip_error_set(error, ZIP_ER_NOZIP, 0);
237: free(cd);
238: return NULL;
239: }
240: }
241:
242: left = cd->size;
243: i=0;
244: do {
245: if (i == cd->nentry && left > 0) {
246: /* Infozip extension for more than 64k entries:
247: nentries wraps around, size indicates correct EOCD */
248: _zip_cdir_grow(cd, cd->nentry+0x10000, error);
249: }
250:
251: if ((_zip_dirent_read(cd->entry+i, fp, bufp, &left, 0, error)) < 0) {
252: cd->nentry = i;
253: _zip_cdir_free(cd);
254: return NULL;
255: }
256: i++;
257:
258: } while (i<cd->nentry);
259:
260: return cd;
261: }
262:
263:
264:
265: /* _zip_checkcons:
266: Checks the consistency of the central directory by comparing central
267: directory entries with local headers and checking for plausible
268: file and header offsets. Returns -1 if not plausible, else the
269: difference between the lowest and the highest fileposition reached */
270:
271: static int
272: _zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
273: {
274: int i;
275: unsigned int min, max, j;
276: struct zip_dirent temp;
277:
278: if (cd->nentry) {
279: max = cd->entry[0].offset;
280: min = cd->entry[0].offset;
281: }
282: else
283: min = max = 0;
284:
285: for (i=0; i<cd->nentry; i++) {
286: if (cd->entry[i].offset < min)
287: min = cd->entry[i].offset;
288: if (min > cd->offset) {
289: _zip_error_set(error, ZIP_ER_NOZIP, 0);
290: return -1;
291: }
292:
293: j = cd->entry[i].offset + cd->entry[i].comp_size
294: + cd->entry[i].filename_len + LENTRYSIZE;
295: if (j > max)
296: max = j;
297: if (max > cd->offset) {
298: _zip_error_set(error, ZIP_ER_NOZIP, 0);
299: return -1;
300: }
301:
302: if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) {
303: _zip_error_set(error, ZIP_ER_SEEK, 0);
304: return -1;
305: }
306:
307: if (_zip_dirent_read(&temp, fp, NULL, NULL, 1, error) == -1)
308: return -1;
309:
310: if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) {
311: _zip_error_set(error, ZIP_ER_INCONS, 0);
312: _zip_dirent_finalize(&temp);
313: return -1;
314: }
315: _zip_dirent_finalize(&temp);
316: }
317:
318: return max - min;
319: }
320:
321:
322:
323: /* _zip_check_torrentzip:
324: check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
325:
326: static void
327: _zip_check_torrentzip(struct zip *za)
328: {
329: uLong crc_got, crc_should;
330: char buf[8+1];
331: char *end;
332:
333: if (za->zp == NULL || za->cdir == NULL)
334: return;
335:
336: if (za->cdir->comment_len != TORRENT_SIG_LEN+8
337: || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
338: return;
339:
340: memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8);
341: buf[8] = '\0';
342: errno = 0;
343: crc_should = strtoul(buf, &end, 16);
344: if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
345: return;
346:
347: if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size,
348: &crc_got, NULL) < 0)
349: return;
350:
351: if (crc_got == crc_should)
352: za->flags |= ZIP_AFL_TORRENT;
353: }
354:
355:
356:
357:
358: /* _zip_headercomp:
359: compares two headers h1 and h2; if they are local headers, set
360: local1p or local2p respectively to 1, else 0. Return 0 if they
361: are identical, -1 if not. */
362:
363: static int
364: _zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
365: int local2p)
366: {
367: if ((h1->version_needed != h2->version_needed)
368: #if 0
369: /* some zip-files have different values in local
370: and global headers for the bitflags */
371: || (h1->bitflags != h2->bitflags)
372: #endif
373: || (h1->comp_method != h2->comp_method)
374: || (h1->last_mod != h2->last_mod)
375: || (h1->filename_len != h2->filename_len)
376: || !h1->filename || !h2->filename
377: || strcmp(h1->filename, h2->filename))
378: return -1;
379:
380: /* check that CRC and sizes are zero if data descriptor is used */
381: if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p
382: && (h1->crc != 0
383: || h1->comp_size != 0
384: || h1->uncomp_size != 0))
385: return -1;
386: if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p
387: && (h2->crc != 0
388: || h2->comp_size != 0
389: || h2->uncomp_size != 0))
390: return -1;
391:
392: /* check that CRC and sizes are equal if no data descriptor is used */
393: if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0)
394: && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) {
395: if ((h1->crc != h2->crc)
396: || (h1->comp_size != h2->comp_size)
397: || (h1->uncomp_size != h2->uncomp_size))
398: return -1;
399: }
400:
401: if ((local1p == local2p)
402: && ((h1->extrafield_len != h2->extrafield_len)
403: || (h1->extrafield_len && h2->extrafield
404: && memcmp(h1->extrafield, h2->extrafield,
405: h1->extrafield_len))))
406: return -1;
407:
408: /* if either is local, nothing more to check */
409: if (local1p || local2p)
410: return 0;
411:
412: if ((h1->version_madeby != h2->version_madeby)
413: || (h1->disk_number != h2->disk_number)
414: || (h1->int_attrib != h2->int_attrib)
415: || (h1->ext_attrib != h2->ext_attrib)
416: || (h1->offset != h2->offset)
417: || (h1->comment_len != h2->comment_len)
418: || (h1->comment_len && h2->comment
419: && memcmp(h1->comment, h2->comment, h1->comment_len)))
420: return -1;
421:
422: return 0;
423: }
424:
425:
426:
427: static struct zip *
428: _zip_allocate_new(const char *fn, int *zep)
429: {
430: struct zip *za;
431: struct zip_error error;
432:
433: if ((za=_zip_new(&error)) == NULL) {
434: set_error(zep, &error, 0);
435: return NULL;
436: }
437:
438: za->zn = strdup(fn);
439: if (!za->zn) {
440: _zip_free(za);
441: set_error(zep, NULL, ZIP_ER_MEMORY);
442: return NULL;
443: }
444: return za;
445: }
446:
447:
448:
449: static int
450: _zip_file_exists(const char *fn, int flags, int *zep)
451: {
452: struct stat st;
453:
454: if (fn == NULL) {
455: set_error(zep, NULL, ZIP_ER_INVAL);
456: return -1;
457: }
458:
459: if (stat(fn, &st) != 0) {
460: if (flags & ZIP_CREATE || flags & ZIP_OVERWRITE)
461: return 0;
462: else {
463: set_error(zep, NULL, ZIP_ER_OPEN);
464: return -1;
465: }
466: }
467: else if ((flags & ZIP_EXCL)) {
468: set_error(zep, NULL, ZIP_ER_EXISTS);
469: return -1;
470: }
471: /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
472: just like open() */
473:
474: return 1;
475: }
476:
477:
478:
479: static struct zip_cdir *
480: _zip_find_central_dir(FILE *fp, int flags, int *zep, off_t len)
481: {
482: struct zip_cdir *cdir, *cdirnew;
483: unsigned char *buf, *match;
484: int a, best, buflen, i;
485: struct zip_error zerr;
486:
487: i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
488: if (i == -1 && errno != EFBIG) {
489: /* seek before start of file on my machine */
490: set_error(zep, NULL, ZIP_ER_SEEK);
491: return NULL;
492: }
493:
494: /* 64k is too much for stack */
495: if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) {
496: set_error(zep, NULL, ZIP_ER_MEMORY);
497: return NULL;
498: }
499:
500: clearerr(fp);
501: buflen = fread(buf, 1, CDBUFSIZE, fp);
502:
503: if (ferror(fp)) {
504: set_error(zep, NULL, ZIP_ER_READ);
505: free(buf);
506: return NULL;
507: }
508:
509: best = -1;
510: cdir = NULL;
511: match = buf;
512: _zip_error_set(&zerr, ZIP_ER_NOZIP, 0);
513:
514: while ((match=_zip_memmem(match, buflen-(match-buf)-18,
515: (const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
516: /* found match -- check, if good */
517: /* to avoid finding the same match all over again */
518: match++;
519: if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags,
520: &zerr)) == NULL)
521: continue;
522:
523: if (cdir) {
524: if (best <= 0)
525: best = _zip_checkcons(fp, cdir, &zerr);
526: a = _zip_checkcons(fp, cdirnew, &zerr);
527: if (best < a) {
528: _zip_cdir_free(cdir);
529: cdir = cdirnew;
530: best = a;
531: }
532: else
533: _zip_cdir_free(cdirnew);
534: }
535: else {
536: cdir = cdirnew;
537: if (flags & ZIP_CHECKCONS)
538: best = _zip_checkcons(fp, cdir, &zerr);
539: else
540: best = 0;
541: }
542: cdirnew = NULL;
543: }
544:
545: free(buf);
546:
547: if (best < 0) {
548: set_error(zep, &zerr, 0);
549: _zip_cdir_free(cdir);
550: return NULL;
551: }
552:
553: return cdir;
554: }
555:
556:
557:
558: static unsigned char *
559: _zip_memmem(const unsigned char *big, int biglen, const unsigned char *little,
560: int littlelen)
561: {
562: const unsigned char *p;
563:
564: if ((biglen < littlelen) || (littlelen == 0))
565: return NULL;
566: p = big-1;
567: while ((p=(const unsigned char *)
568: memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1)))
569: != NULL) {
570: if (memcmp(p+1, little+1, littlelen-1)==0)
571: return (unsigned char *)p;
572: }
573:
574: return NULL;
575: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>