xref: /PHP-5.3/ext/zip/lib/zip_open.c (revision d3780f1f)
1 /*
2   zip_open.c -- open zip archive by name
3   Copyright (C) 1999-2011 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 *, off_t, unsigned char *, unsigned char *,
56 				 int, int, struct zip_error *);
57 
58 
59 
60 ZIP_EXTERN(struct zip *)
zip_open(const char * fn,int flags,int * zep)61 zip_open(const char *fn, int flags, int *zep)
62 {
63     FILE *fp;
64 
65     if (flags & ZIP_OVERWRITE) {
66 	return _zip_allocate_new(fn, zep);
67     }
68 
69     switch (_zip_file_exists(fn, flags, zep)) {
70     case -1:
71 			if (!(flags & ZIP_OVERWRITE)) {
72 				return NULL;
73 			}
74     case 0:
75 	return _zip_allocate_new(fn, zep);
76     default:
77 	break;
78     }
79 
80     if ((fp=fopen(fn, "rb")) == NULL) {
81 	set_error(zep, NULL, ZIP_ER_OPEN);
82 	return NULL;
83     }
84 
85     return _zip_open(fn, fp, flags, 0, zep);
86 }
87 
88 
89 
90 struct zip *
_zip_open(const char * fn,FILE * fp,int flags,int aflags,int * zep)91 _zip_open(const char *fn, FILE *fp, int flags, int aflags, int *zep)
92 {
93     struct zip *za;
94     struct zip_cdir *cdir;
95     int i;
96     off_t len;
97 
98     if (fseeko(fp, 0, SEEK_END) < 0) {
99 	*zep = ZIP_ER_SEEK;
100 	return NULL;
101     }
102     len = ftello(fp);
103 
104     /* treat empty files as empty archives */
105     if (len == 0) {
106 	if ((za=_zip_allocate_new(fn, zep)) == NULL)
107 	    fclose(fp);
108 	else
109 	    za->zp = fp;
110 	return za;
111     }
112 
113     cdir = _zip_find_central_dir(fp, flags, zep, len);
114     if (cdir == NULL) {
115 	fclose(fp);
116 	return NULL;
117     }
118 
119     if ((za=_zip_allocate_new(fn, zep)) == NULL) {
120 	_zip_cdir_free(cdir);
121 	fclose(fp);
122 	return NULL;
123     }
124 
125     za->cdir = cdir;
126     za->zp = fp;
127 
128     if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
129 					      * cdir->nentry)) == NULL) {
130 	set_error(zep, NULL, ZIP_ER_MEMORY);
131 	_zip_free(za);
132 	return NULL;
133     }
134     for (i=0; i<cdir->nentry; i++)
135 	_zip_entry_new(za);
136 
137     _zip_check_torrentzip(za);
138     za->ch_flags = za->flags;
139 
140     return za;
141 }
142 
143 
144 
145 static void
set_error(int * zep,struct zip_error * err,int ze)146 set_error(int *zep, struct zip_error *err, int ze)
147 {
148     int se;
149 
150     if (err) {
151 	_zip_error_get(err, &ze, &se);
152 	if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
153 	    errno = se;
154     }
155 
156     if (zep)
157 	*zep = ze;
158 }
159 
160 
161 
162 /* _zip_readcdir:
163    tries to find a valid end-of-central-directory at the beginning of
164    buf, and then the corresponding central directory entries.
165    Returns a struct zip_cdir which contains the central directory
166    entries, or NULL if unsuccessful. */
167 
168 static struct zip_cdir *
_zip_readcdir(FILE * fp,off_t buf_offset,unsigned char * buf,unsigned char * eocd,int buflen,int flags,struct zip_error * error)169 _zip_readcdir(FILE *fp, off_t buf_offset, unsigned char *buf, unsigned char *eocd, int buflen,
170 	      int flags, struct zip_error *error)
171 {
172     struct zip_cdir *cd;
173     unsigned char *cdp, **bufp;
174     int i, comlen, nentry;
175     zip_uint32_t left;
176 
177     comlen = buf + buflen - eocd - EOCDLEN;
178     if (comlen < 0) {
179 	/* not enough bytes left for comment */
180 	_zip_error_set(error, ZIP_ER_NOZIP, 0);
181 	return NULL;
182     }
183 
184     /* check for end-of-central-dir magic */
185     if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
186 	_zip_error_set(error, ZIP_ER_NOZIP, 0);
187 	return NULL;
188     }
189 
190     if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
191 	_zip_error_set(error, ZIP_ER_MULTIDISK, 0);
192 	return NULL;
193     }
194 
195     cdp = eocd + 8;
196     /* number of cdir-entries on this disk */
197     i = _zip_read2(&cdp);
198     /* number of cdir-entries */
199     nentry = _zip_read2(&cdp);
200 
201     if ((cd=_zip_cdir_new(nentry, error)) == NULL)
202 	return NULL;
203 
204     cd->size = _zip_read4(&cdp);
205     cd->offset = _zip_read4(&cdp);
206     cd->comment = NULL;
207     cd->comment_len = _zip_read2(&cdp);
208 
209     if (((zip_uint64_t)cd->offset)+cd->size > buf_offset + (eocd-buf)) {
210 	/* cdir spans past EOCD record */
211 	_zip_error_set(error, ZIP_ER_INCONS, 0);
212 	cd->nentry = 0;
213 	_zip_cdir_free(cd);
214 	return NULL;
215     }
216 
217     if ((comlen < cd->comment_len) || (cd->nentry != i)) {
218 	_zip_error_set(error, ZIP_ER_NOZIP, 0);
219 	cd->nentry = 0;
220 	_zip_cdir_free(cd);
221 	return NULL;
222     }
223     if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) {
224 	_zip_error_set(error, ZIP_ER_INCONS, 0);
225 	cd->nentry = 0;
226 	_zip_cdir_free(cd);
227 	return NULL;
228     }
229 
230     if (cd->comment_len) {
231 	if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN,
232 					     cd->comment_len, error))
233 	    == NULL) {
234 	    cd->nentry = 0;
235 	    _zip_cdir_free(cd);
236 	    return NULL;
237 	}
238     }
239 
240     if (cd->offset >= buf_offset) {
241 	/* if buffer already read in, use it */
242 	cdp = buf + (cd->offset - buf_offset);
243 	bufp = &cdp;
244     }
245     else {
246 	/* go to start of cdir and read it entry by entry */
247 	bufp = NULL;
248 	clearerr(fp);
249 	fseeko(fp, cd->offset, SEEK_SET);
250 	/* possible consistency check: cd->offset =
251 	   len-(cd->size+cd->comment_len+EOCDLEN) ? */
252 	if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) {
253 	    /* seek error or offset of cdir wrong */
254 	    if (ferror(fp))
255 		_zip_error_set(error, ZIP_ER_SEEK, errno);
256 	    else
257 		_zip_error_set(error, ZIP_ER_NOZIP, 0);
258 	    cd->nentry = 0;
259 	    _zip_cdir_free(cd);
260 	    return NULL;
261 	}
262     }
263 
264     left = cd->size;
265     i=0;
266     while (i<cd->nentry && left > 0) {
267 	if ((_zip_dirent_read(cd->entry+i, fp, bufp, &left, 0, error)) < 0) {
268 	    cd->nentry = i;
269 	    _zip_cdir_free(cd);
270 	    return NULL;
271 	}
272 	i++;
273 
274 	if (i == cd->nentry && left > 0) {
275 	    /* Infozip extension for more than 64k entries:
276 	       nentries wraps around, size indicates correct EOCD */
277 	    if (_zip_cdir_grow(cd, cd->nentry+ZIP_UINT16_MAX, error) < 0) {
278 		cd->nentry = i;
279 		_zip_cdir_free(cd);
280 		return NULL;
281 	    }
282 	}
283     }
284 
285     cd->nentry = i;
286 
287     return cd;
288 }
289 
290 
291 
292 /* _zip_checkcons:
293    Checks the consistency of the central directory by comparing central
294    directory entries with local headers and checking for plausible
295    file and header offsets. Returns -1 if not plausible, else the
296    difference between the lowest and the highest fileposition reached */
297 
298 static int
_zip_checkcons(FILE * fp,struct zip_cdir * cd,struct zip_error * error)299 _zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
300 {
301     int i;
302     unsigned int min, max, j;
303     struct zip_dirent temp;
304 
305     if (cd->nentry) {
306 	max = cd->entry[0].offset;
307 	min = cd->entry[0].offset;
308     }
309     else
310 	min = max = 0;
311 
312     for (i=0; i<cd->nentry; i++) {
313 	if (cd->entry[i].offset < min)
314 	    min = cd->entry[i].offset;
315 	if (min > cd->offset) {
316 	    _zip_error_set(error, ZIP_ER_NOZIP, 0);
317 	    return -1;
318 	}
319 
320 	j = cd->entry[i].offset + cd->entry[i].comp_size
321 	    + cd->entry[i].filename_len + LENTRYSIZE;
322 	if (j > max)
323 	    max = j;
324 	if (max > cd->offset) {
325 	    _zip_error_set(error, ZIP_ER_NOZIP, 0);
326 	    return -1;
327 	}
328 
329 	if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) {
330 	    _zip_error_set(error, ZIP_ER_SEEK, 0);
331 	    return -1;
332 	}
333 
334 	if (_zip_dirent_read(&temp, fp, NULL, NULL, 1, error) == -1)
335 	    return -1;
336 
337 	if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) {
338 	    _zip_error_set(error, ZIP_ER_INCONS, 0);
339 	    _zip_dirent_finalize(&temp);
340 	    return -1;
341 	}
342 	_zip_dirent_finalize(&temp);
343     }
344 
345     return max - min;
346 }
347 
348 
349 
350 /* _zip_check_torrentzip:
351    check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
352 
353 static void
_zip_check_torrentzip(struct zip * za)354 _zip_check_torrentzip(struct zip *za)
355 {
356     uLong crc_got, crc_should;
357     char buf[8+1];
358     char *end;
359 
360     if (za->zp == NULL || za->cdir == NULL)
361 	return;
362 
363     if (za->cdir->comment_len != TORRENT_SIG_LEN+8
364 	|| strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
365 	return;
366 
367     memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8);
368     buf[8] = '\0';
369     errno = 0;
370     crc_should = strtoul(buf, &end, 16);
371     if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
372 	return;
373 
374     if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size,
375 			   &crc_got, NULL) < 0)
376 	return;
377 
378     if (crc_got == crc_should)
379 	za->flags |= ZIP_AFL_TORRENT;
380 }
381 
382 
383 
384 
385 /* _zip_headercomp:
386    compares two headers h1 and h2; if they are local headers, set
387    local1p or local2p respectively to 1, else 0. Return 0 if they
388    are identical, -1 if not. */
389 
390 static int
_zip_headercomp(struct zip_dirent * h1,int local1p,struct zip_dirent * h2,int local2p)391 _zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
392 	   int local2p)
393 {
394     if ((h1->version_needed != h2->version_needed)
395 #if 0
396 	/* some zip-files have different values in local
397 	   and global headers for the bitflags */
398 	|| (h1->bitflags != h2->bitflags)
399 #endif
400 	|| (h1->comp_method != h2->comp_method)
401 	|| (h1->last_mod != h2->last_mod)
402 	|| (h1->filename_len != h2->filename_len)
403 	|| !h1->filename || !h2->filename
404 	|| strcmp(h1->filename, h2->filename))
405 	return -1;
406 
407     /* check that CRC and sizes are zero if data descriptor is used */
408     if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p
409 	&& (h1->crc != 0
410 	    || h1->comp_size != 0
411 	    || h1->uncomp_size != 0))
412 	return -1;
413     if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p
414 	&& (h2->crc != 0
415 	    || h2->comp_size != 0
416 	    || h2->uncomp_size != 0))
417 	return -1;
418 
419     /* check that CRC and sizes are equal if no data descriptor is used */
420     if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0)
421 	&& ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) {
422 	if ((h1->crc != h2->crc)
423 	    || (h1->comp_size != h2->comp_size)
424 	    || (h1->uncomp_size != h2->uncomp_size))
425 	    return -1;
426     }
427 
428     if ((local1p == local2p)
429 	&& ((h1->extrafield_len != h2->extrafield_len)
430 	    || (h1->extrafield_len && h2->extrafield
431 		&& memcmp(h1->extrafield, h2->extrafield,
432 			  h1->extrafield_len))))
433 	return -1;
434 
435     /* if either is local, nothing more to check */
436     if (local1p || local2p)
437 	return 0;
438 
439     if ((h1->version_madeby != h2->version_madeby)
440 	|| (h1->disk_number != h2->disk_number)
441 	|| (h1->int_attrib != h2->int_attrib)
442 	|| (h1->ext_attrib != h2->ext_attrib)
443 	|| (h1->offset != h2->offset)
444 	|| (h1->comment_len != h2->comment_len)
445 	|| (h1->comment_len && h2->comment
446 	    && memcmp(h1->comment, h2->comment, h1->comment_len)))
447 	return -1;
448 
449     return 0;
450 }
451 
452 
453 
454 static struct zip *
_zip_allocate_new(const char * fn,int * zep)455 _zip_allocate_new(const char *fn, int *zep)
456 {
457     struct zip *za;
458     struct zip_error error;
459 
460     if ((za=_zip_new(&error)) == NULL) {
461 	set_error(zep, &error, 0);
462 	return NULL;
463     }
464 
465     if (fn == NULL)
466 	za->zn = NULL;
467     else {
468 	za->zn = strdup(fn);
469 	if (!za->zn) {
470 	    _zip_free(za);
471 	    set_error(zep, NULL, ZIP_ER_MEMORY);
472 	    return NULL;
473 	}
474     }
475     return za;
476 }
477 
478 
479 
480 static int
_zip_file_exists(const char * fn,int flags,int * zep)481 _zip_file_exists(const char *fn, int flags, int *zep)
482 {
483     struct stat st;
484 
485     if (fn == NULL) {
486 	set_error(zep, NULL, ZIP_ER_INVAL);
487 	return -1;
488     }
489 
490     if (stat(fn, &st) != 0) {
491 	if (flags & ZIP_CREATE || flags & ZIP_OVERWRITE)
492 	    return 0;
493 	else {
494 	    set_error(zep, NULL, ZIP_ER_OPEN);
495 	    return -1;
496 	}
497     }
498     else if ((flags & ZIP_EXCL)) {
499 	set_error(zep, NULL, ZIP_ER_EXISTS);
500 	return -1;
501     }
502     /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
503        just like open() */
504 
505     return 1;
506 }
507 
508 
509 
510 static struct zip_cdir *
_zip_find_central_dir(FILE * fp,int flags,int * zep,off_t len)511 _zip_find_central_dir(FILE *fp, int flags, int *zep, off_t len)
512 {
513     struct zip_cdir *cdir, *cdirnew;
514     unsigned char *buf, *match;
515     off_t buf_offset;
516     int a, best, buflen, i;
517     struct zip_error zerr;
518 
519     i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
520     if (i == -1 && errno != EFBIG) {
521 	/* seek before start of file on my machine */
522 	set_error(zep, NULL, ZIP_ER_SEEK);
523 	return NULL;
524     }
525     buf_offset = ftello(fp);
526 
527     /* 64k is too much for stack */
528     if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) {
529 	set_error(zep, NULL, ZIP_ER_MEMORY);
530 	return NULL;
531     }
532 
533     clearerr(fp);
534     buflen = fread(buf, 1, CDBUFSIZE, fp);
535 
536     if (ferror(fp)) {
537 	set_error(zep, NULL, ZIP_ER_READ);
538 	free(buf);
539 	return NULL;
540     }
541 
542     best = -1;
543     cdir = NULL;
544     match = buf;
545     _zip_error_set(&zerr, ZIP_ER_NOZIP, 0);
546 
547     while ((match=_zip_memmem(match, buflen-(match-buf)-18,
548 			      (const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
549 	/* found match -- check, if good */
550 	/* to avoid finding the same match all over again */
551 	match++;
552 	if ((cdirnew=_zip_readcdir(fp, buf_offset, buf, match-1, buflen, flags,
553 				   &zerr)) == NULL)
554 	    continue;
555 
556 	if (cdir) {
557 	    if (best <= 0)
558 		best = _zip_checkcons(fp, cdir, &zerr);
559 	    a = _zip_checkcons(fp, cdirnew, &zerr);
560 	    if (best < a) {
561 		_zip_cdir_free(cdir);
562 		cdir = cdirnew;
563 		best = a;
564 	    }
565 	    else
566 		_zip_cdir_free(cdirnew);
567 	}
568 	else {
569 	    cdir = cdirnew;
570 	    if (flags & ZIP_CHECKCONS)
571 		best = _zip_checkcons(fp, cdir, &zerr);
572 	    else
573 		best = 0;
574 	}
575 	cdirnew = NULL;
576     }
577 
578     free(buf);
579 
580     if (best < 0) {
581 	set_error(zep, &zerr, 0);
582 	_zip_cdir_free(cdir);
583 	return NULL;
584     }
585 
586     return cdir;
587 }
588 
589 
590 
591 static unsigned char *
_zip_memmem(const unsigned char * big,int biglen,const unsigned char * little,int littlelen)592 _zip_memmem(const unsigned char *big, int biglen, const unsigned char *little,
593        int littlelen)
594 {
595     const unsigned char *p;
596 
597     if ((biglen < littlelen) || (littlelen == 0))
598 	return NULL;
599     p = big-1;
600     while ((p=(const unsigned char *)
601 	        memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1)))
602 	   != NULL) {
603 	if (memcmp(p+1, little+1, littlelen-1)==0)
604 	    return (unsigned char *)p;
605     }
606 
607     return NULL;
608 }
609