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