Coverage Report

Created: 2024-11-08 06:29

/src/libzip/lib/zip_open.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  zip_open.c -- open zip archive by name
3
  Copyright (C) 1999-2024 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 <info@libzip.org>
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
#include <limits.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
39
#include "zipint.h"
40
41
typedef enum {
42
    EXISTS_ERROR = -1,
43
    EXISTS_NOT = 0,
44
    EXISTS_OK
45
} exists_t;
46
typedef enum {
47
    CDIR_OK,
48
    CDIR_INVALID,
49
    CDIR_NOT_FOUND
50
51
} cdir_status_t;
52
53
static bool check_eocd(zip_cdir_t *cd, unsigned int flags, zip_error_t *error);
54
static bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_uint64_t buffer_offset, zip_source_t *src, const char* magic);
55
static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);
56
static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);
57
static void zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir);
58
static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);
59
static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error);
60
static int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *);
61
static bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_cdir_t **cdirp, zip_error_t *error);
62
static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error);
63
static cdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
64
static const unsigned char *find_eocd(zip_buffer_t *buffer, const unsigned char *last);
65
66
67
ZIP_EXTERN zip_t *
68
5.20k
zip_open(const char *fn, int _flags, int *zep) {
69
5.20k
    zip_t *za;
70
5.20k
    zip_source_t *src;
71
5.20k
    struct zip_error error;
72
73
5.20k
    zip_error_init(&error);
74
5.20k
    if ((src = zip_source_file_create(fn, 0, -1, &error)) == NULL) {
75
0
        _zip_set_open_error(zep, &error, 0);
76
0
        zip_error_fini(&error);
77
0
        return NULL;
78
0
    }
79
80
5.20k
    if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {
81
2.56k
        zip_source_free(src);
82
2.56k
        _zip_set_open_error(zep, &error, 0);
83
2.56k
        zip_error_fini(&error);
84
2.56k
        return NULL;
85
2.56k
    }
86
87
2.63k
    zip_error_fini(&error);
88
2.63k
    return za;
89
5.20k
}
90
91
92
ZIP_EXTERN zip_t *
93
9.89k
zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error) {
94
9.89k
    unsigned int flags;
95
9.89k
    zip_int64_t supported;
96
9.89k
    exists_t exists;
97
98
9.89k
    if (_flags < 0 || src == NULL) {
99
0
        zip_error_set(error, ZIP_ER_INVAL, 0);
100
0
        return NULL;
101
0
    }
102
9.89k
    flags = (unsigned int)_flags;
103
104
9.89k
    supported = zip_source_supports(src);
105
9.89k
    if ((supported & ZIP_SOURCE_SUPPORTS_SEEKABLE) != ZIP_SOURCE_SUPPORTS_SEEKABLE) {
106
0
        zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
107
0
        return NULL;
108
0
    }
109
9.89k
    if ((supported & ZIP_SOURCE_SUPPORTS_WRITABLE) != ZIP_SOURCE_SUPPORTS_WRITABLE) {
110
0
        flags |= ZIP_RDONLY;
111
0
    }
112
113
9.89k
    if ((flags & (ZIP_RDONLY | ZIP_TRUNCATE)) == (ZIP_RDONLY | ZIP_TRUNCATE)) {
114
0
        zip_error_set(error, ZIP_ER_RDONLY, 0);
115
0
        return NULL;
116
0
    }
117
118
9.89k
    exists = _zip_file_exists(src, error);
119
9.89k
    switch (exists) {
120
0
    case EXISTS_ERROR:
121
0
        return NULL;
122
123
925
    case EXISTS_NOT:
124
925
        if ((flags & ZIP_CREATE) == 0) {
125
0
            zip_error_set(error, ZIP_ER_NOENT, 0);
126
0
            return NULL;
127
0
        }
128
925
        return _zip_allocate_new(src, flags, error);
129
130
8.97k
    default: {
131
8.97k
        zip_t *za;
132
8.97k
        if (flags & ZIP_EXCL) {
133
0
            zip_error_set(error, ZIP_ER_EXISTS, 0);
134
0
            return NULL;
135
0
        }
136
8.97k
        if (zip_source_open(src) < 0) {
137
0
            zip_error_set_from_source(error, src);
138
0
            return NULL;
139
0
        }
140
141
8.97k
        if (flags & ZIP_TRUNCATE) {
142
0
            za = _zip_allocate_new(src, flags, error);
143
0
        }
144
8.97k
        else {
145
            /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */
146
8.97k
            za = _zip_open(src, flags, error);
147
8.97k
        }
148
149
8.97k
        if (za == NULL) {
150
5.15k
            zip_source_close(src);
151
5.15k
            return NULL;
152
5.15k
        }
153
3.81k
        return za;
154
8.97k
    }
155
9.89k
    }
156
9.89k
}
157
158
159
static bool
160
1.06k
_is_truncated_zip(zip_source_t *src) {
161
1.06k
    unsigned char data[4];
162
    /* check if the source is a truncated zip archive: true if yes, no
163
       if not or can't be determined */
164
1.06k
    if (zip_source_seek(src, 0, SEEK_SET) < 0) {
165
0
        return false;
166
0
    }
167
168
1.06k
    if (zip_source_read(src, data, 4) != 4) {
169
6
        return false;
170
6
    }
171
172
1.05k
    if (memcmp(data, LOCAL_MAGIC, 4) == 0) {
173
        /* file starts with a ZIP local header signature */
174
17
        return true;
175
17
    }
176
1.04k
    return false;
177
1.05k
}
178
179
180
zip_t *
181
8.97k
_zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) {
182
8.97k
    zip_t *za;
183
8.97k
    zip_cdir_t *cdir;
184
8.97k
    struct zip_stat st;
185
8.97k
    zip_uint64_t len, idx;
186
187
8.97k
    zip_stat_init(&st);
188
8.97k
    if (zip_source_stat(src, &st) < 0) {
189
0
        zip_error_set_from_source(error, src);
190
0
        return NULL;
191
0
    }
192
8.97k
    if ((st.valid & ZIP_STAT_SIZE) == 0) {
193
0
        zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);
194
0
        return NULL;
195
0
    }
196
8.97k
    len = st.size;
197
198
199
8.97k
    if ((za = _zip_allocate_new(src, flags, error)) == NULL) {
200
0
        return NULL;
201
0
    }
202
203
    /* treat empty files as empty archives */
204
8.97k
    if (len == 0 && zip_source_accept_empty(src)) {
205
0
        return za;
206
0
    }
207
208
8.97k
    if ((cdir = _zip_find_central_dir(za, len)) == NULL) {
209
5.15k
        _zip_error_copy(error, &za->error);
210
5.15k
        if (zip_error_code_zip(error) == ZIP_ER_NOZIP) {
211
            /* not a zip - find out if it's truncated */
212
1.06k
            if (_is_truncated_zip(src)) {
213
17
                zip_error_set(error, ZIP_ER_TRUNCATED_ZIP, 0);
214
17
            }
215
1.06k
        }
216
        /* keep src so discard does not get rid of it */
217
5.15k
        zip_source_keep(src);
218
5.15k
        zip_discard(za);
219
5.15k
        return NULL;
220
5.15k
    }
221
222
3.81k
    za->entry = cdir->entry;
223
3.81k
    za->nentry = cdir->nentry;
224
3.81k
    za->nentry_alloc = cdir->nentry_alloc;
225
226
3.81k
    zip_check_torrentzip(za, cdir);
227
228
3.81k
    if (ZIP_IS_TORRENTZIP(za)) {
229
        /* Torrentzip uses the archive comment to detect changes by tools that are not torrentzip aware. */
230
2
        _zip_string_free(cdir->comment);
231
2
    }
232
3.81k
    else {
233
3.81k
        za->comment_orig = cdir->comment;
234
3.81k
    }
235
236
3.81k
    free(cdir);
237
238
3.81k
    _zip_hash_reserve_capacity(za->names, za->nentry, &za->error);
239
240
44.2k
    for (idx = 0; idx < za->nentry; idx++) {
241
40.4k
        const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);
242
40.4k
        if (name == NULL) {
243
            /* keep src so discard does not get rid of it */
244
0
            zip_source_keep(src);
245
0
            zip_discard(za);
246
0
            return NULL;
247
0
        }
248
249
40.4k
        if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) {
250
28.7k
            if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) {
251
0
                _zip_error_copy(error, &za->error);
252
                /* keep src so discard does not get rid of it */
253
0
                zip_source_keep(src);
254
0
                zip_discard(za);
255
0
                return NULL;
256
0
            }
257
28.7k
        }
258
40.4k
    }
259
260
3.81k
    za->ch_flags = za->flags;
261
262
3.81k
    return za;
263
3.81k
}
264
265
266
void
267
2.56k
_zip_set_open_error(int *zep, const zip_error_t *err, int ze) {
268
2.56k
    if (err) {
269
2.56k
        ze = zip_error_code_zip(err);
270
2.56k
        switch (zip_error_system_type(err)) {
271
123
        case ZIP_ET_SYS:
272
1.69k
        case ZIP_ET_LIBZIP:
273
1.69k
            errno = zip_error_code_system(err);
274
1.69k
            break;
275
276
872
        default:
277
872
            break;
278
2.56k
        }
279
2.56k
    }
280
281
2.56k
    if (zep)
282
2.56k
        *zep = ze;
283
2.56k
}
284
285
286
/* _zip_readcdir:
287
   tries to find a valid end-of-central-directory at the beginning of
288
   buf, and then the corresponding central directory entries.
289
   Returns a struct zip_cdir which contains the central directory
290
   entries, or NULL if unsuccessful. */
291
292
79.4k
static bool _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_cdir_t **cdirp, zip_error_t *error) {
293
79.4k
    zip_cdir_t *cd;
294
79.4k
    zip_uint16_t comment_len;
295
79.4k
    zip_uint64_t i, left;
296
79.4k
    zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);
297
79.4k
    zip_buffer_t *cd_buffer;
298
79.4k
    bool eocd64_found = false;
299
300
79.4k
    *cdirp = NULL;
301
302
79.4k
    if ((cd = _zip_read_eocd(buffer, buf_offset, error)) == NULL) {
303
505
        return false;
304
505
    }
305
306
78.9k
    if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {
307
14.7k
        eocd64_found = true;
308
14.7k
        _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);
309
14.7k
        switch (_zip_read_eocd64(cd, za->src, buffer, buf_offset, za->flags, error)) {
310
350
        case CDIR_OK:
311
350
            break;
312
313
1.58k
        case CDIR_INVALID:
314
1.58k
            _zip_cdir_free(cd);
315
1.58k
            return true;
316
317
12.8k
        case CDIR_NOT_FOUND:
318
12.8k
            _zip_cdir_free(cd);
319
12.8k
            return false;
320
14.7k
        }
321
14.7k
    }
322
323
64.5k
    if ((cd->eocd_disk != 0 || cd->this_disk != 0) && !eocd64_found && cd->eocd_disk != cd->this_disk) {
324
        /* If the central directory doesn't start on this disk, we can't check that offset is valid. Check as much as we can instead. */
325
24.1k
        if (cd->this_disk < cd->eocd_disk) {
326
            /* Disks before the start of the central directory don't contain an EOCD. */
327
5.54k
            _zip_cdir_free(cd);
328
5.54k
            return false;
329
5.54k
        }
330
18.5k
        if (cd->size <= cd->eocd_offset) {
331
            /* The complete central directory would fit on this disk. */
332
5.02k
            _zip_cdir_free(cd);
333
5.02k
            return false;
334
5.02k
        }
335
18.5k
    }
336
337
54.0k
    if (!eocd64_found) {
338
53.6k
        if (cd->this_disk == 0 && cd->eocd_disk == 0 && cd->eocd_offset == 0 && cd->offset == 0 && cd->num_entries == 0) {
339
            /* An empty archive doesn't contain central directory entries. */
340
723
        }
341
52.9k
        else if (!check_magic(cd->offset, buffer, buf_offset, za->src, CENTRAL_MAGIC)) {
342
47.5k
            _zip_cdir_free(cd);
343
47.5k
            return false;
344
47.5k
        }
345
53.6k
    }
346
347
    /* We accept this EOCD as valid and won't search for an earlier one if it is unusable. */
348
349
6.50k
    if (!check_eocd(cd, za->flags, error)) {
350
219
        _zip_cdir_free(cd);
351
219
        return true;
352
219
    }
353
354
6.28k
    _zip_buffer_set_offset(buffer, eocd_offset + 20);
355
6.28k
    comment_len = _zip_buffer_get_16(buffer);
356
357
6.28k
    if (cd->offset + cd->size > buf_offset + eocd_offset) {
358
        /* cdir spans past EOCD record */
359
278
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_OVERLAPS_EOCD);
360
278
        _zip_cdir_free(cd);
361
278
        return true;
362
278
    }
363
364
6.00k
    if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
365
2.10k
        zip_uint64_t tail_len;
366
367
2.10k
        _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
368
2.10k
        tail_len = _zip_buffer_left(buffer);
369
370
2.10k
        if (tail_len != comment_len) {
371
1.71k
            if (za->open_flags & ZIP_CHECKCONS) {
372
0
                zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_COMMENT_LENGTH_INVALID);
373
0
                _zip_cdir_free(cd);
374
0
                return true;
375
0
            }
376
1.71k
            if (tail_len < comment_len) {
377
1.56k
                comment_len = tail_len;
378
1.56k
            }
379
1.71k
        }
380
381
2.10k
        if (comment_len) {
382
953
            if ((cd->comment = _zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
383
0
                _zip_cdir_free(cd);
384
0
                return true;
385
0
            }
386
953
        }
387
2.10k
    }
388
389
6.00k
    if (cd->offset >= buf_offset) {
390
5.75k
        zip_uint8_t *data;
391
        /* if buffer already read in, use it */
392
5.75k
        _zip_buffer_set_offset(buffer, cd->offset - buf_offset);
393
394
5.75k
        if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
395
0
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID);
396
0
            _zip_cdir_free(cd);
397
0
            return true;
398
0
        }
399
5.75k
        if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
400
0
            zip_error_set(error, ZIP_ER_MEMORY, 0);
401
0
            _zip_cdir_free(cd);
402
0
            return true;
403
0
        }
404
5.75k
    }
405
250
    else {
406
250
        cd_buffer = NULL;
407
408
250
        if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
409
0
            zip_error_set_from_source(error, za->src);
410
0
            _zip_cdir_free(cd);
411
0
            return true;
412
0
        }
413
414
        /* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */
415
250
        if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {
416
0
            zip_error_set(error, ZIP_ER_NOZIP, 0);
417
0
            _zip_cdir_free(cd);
418
0
            return true;
419
0
        }
420
250
    }
421
422
6.00k
    if (!_zip_cdir_grow(cd, cd->num_entries, error)) {
423
0
        _zip_cdir_free(cd);
424
0
        _zip_buffer_free(cd_buffer);
425
0
        return true;
426
0
    }
427
6.00k
    left = (zip_uint64_t)cd->size;
428
6.00k
    i = 0;
429
93.1k
    while (left > 0) {
430
89.0k
        bool grown = false;
431
89.0k
        zip_int64_t entry_size;
432
433
89.0k
        if (i == cd->nentry) {
434
            /* InfoZIP has a hack to avoid using Zip64: it stores nentries % 0x10000 */
435
            /* This hack isn't applicable if we're using Zip64, or if there is no central directory entry following. */
436
437
585
            if (cd->is_zip64 || left < CDENTRYSIZE) {
438
89
                break;
439
89
            }
440
441
496
            if (!_zip_cdir_grow(cd, 0x10000, error)) {
442
0
                _zip_cdir_free(cd);
443
0
                _zip_buffer_free(cd_buffer);
444
0
                return true;
445
0
            }
446
496
            grown = true;
447
496
        }
448
449
88.9k
        if ((cd->entry[i].orig = _zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, 0, za->open_flags & ZIP_CHECKCONS, error)) < 0) {
450
1.89k
            if (zip_error_code_zip(error) == ZIP_ER_INCONS) {
451
1.21k
                zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(zip_error_code_system(error), i));
452
1.21k
            }
453
686
            else if (grown && zip_error_code_zip(error) == ZIP_ER_NOZIP) {
454
93
                zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_CDIR_ENTRY_INVALID, i));
455
93
            }
456
1.89k
            _zip_cdir_free(cd);
457
1.89k
            _zip_buffer_free(cd_buffer);
458
1.89k
            return true;
459
1.89k
        }
460
87.0k
        i++;
461
87.0k
        left -= (zip_uint64_t)entry_size;
462
87.0k
    }
463
464
    /* If we didn't fill all we grew, cd->num_entries was wrong. */
465
4.11k
    if (i != cd->nentry || left > 0) {
466
291
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_WRONG_ENTRIES_COUNT);
467
291
        _zip_buffer_free(cd_buffer);
468
291
        _zip_cdir_free(cd);
469
291
        return true;
470
291
    }
471
472
3.81k
    if (za->open_flags & ZIP_CHECKCONS) {
473
0
        bool ok;
474
475
0
        if (cd_buffer) {
476
0
            ok = _zip_buffer_eof(cd_buffer);
477
0
        }
478
0
        else {
479
0
            zip_int64_t offset = zip_source_tell(za->src);
480
481
0
            if (offset < 0) {
482
0
                zip_error_set_from_source(error, za->src);
483
0
                _zip_cdir_free(cd);
484
0
                return true;
485
0
            }
486
0
            ok = ((zip_uint64_t)offset == cd->offset + cd->size);
487
0
        }
488
489
0
        if (!ok) {
490
0
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID);
491
0
            _zip_buffer_free(cd_buffer);
492
0
            _zip_cdir_free(cd);
493
0
            return true;
494
0
        }
495
0
    }
496
497
3.81k
    _zip_buffer_free(cd_buffer);
498
3.81k
    *cdirp = cd;
499
3.81k
    return true;
500
3.81k
}
501
502
503
67.6k
static bool check_magic(zip_uint64_t offset, zip_buffer_t *buffer, zip_uint64_t buffer_offset, zip_source_t *src, const char* magic) {
504
67.6k
    if (buffer_offset <= offset) {
505
60.0k
        zip_uint8_t* data;
506
60.0k
        if (_zip_buffer_set_offset(buffer, offset - buffer_offset) < 0 || (data = _zip_buffer_get(buffer, MAGIC_LEN)) == NULL) {
507
22.0k
            return false;
508
22.0k
        }
509
38.0k
        return memcmp(data, magic, MAGIC_LEN) == 0;
510
60.0k
    }
511
7.65k
    else {
512
7.65k
        zip_uint8_t data[MAGIC_LEN];
513
514
7.65k
        if (zip_source_seek(src, offset, SEEK_SET) < 0 || zip_source_read(src, data, MAGIC_LEN) != MAGIC_LEN) {
515
0
            return false;
516
0
        }
517
7.65k
        return memcmp(data, magic, MAGIC_LEN) == 0;
518
7.65k
    }
519
67.6k
}
520
521
522
/* _zip_checkcons:
523
   Checks the consistency of the central directory by comparing central
524
   directory entries with local headers and checking for plausible
525
   file and header offsets. Returns -1 if not plausible, else the
526
   difference between the lowest and the highest fileposition reached */
527
528
static zip_int64_t
529
0
_zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error) {
530
0
    zip_uint64_t i;
531
0
    zip_uint64_t min, max, j;
532
0
    struct zip_dirent temp;
533
0
    int detail;
534
535
0
    _zip_dirent_init(&temp);
536
0
    if (cd->nentry) {
537
0
        max = cd->entry[0].orig->offset;
538
0
        min = cd->entry[0].orig->offset;
539
0
    }
540
0
    else
541
0
        min = max = 0;
542
543
0
    for (i = 0; i < cd->nentry; i++) {
544
0
        if (cd->entry[i].orig->offset < min)
545
0
            min = cd->entry[i].orig->offset;
546
0
        if (min > (zip_uint64_t)cd->offset) {
547
0
            zip_error_set(error, ZIP_ER_NOZIP, 0);
548
0
            return -1;
549
0
        }
550
551
0
        j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
552
0
        if (j > max)
553
0
            max = j;
554
0
        if (max > (zip_uint64_t)cd->offset) {
555
0
            zip_error_set(error, ZIP_ER_NOZIP, 0);
556
0
            return -1;
557
0
        }
558
559
0
        if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {
560
0
            zip_error_set_from_source(error, za->src);
561
0
            return -1;
562
0
        }
563
564
0
        if (_zip_dirent_read(&temp, za->src, NULL, true, cd->entry[i].orig->comp_size, true, error) == -1) {
565
0
            if (zip_error_code_zip(error) == ZIP_ER_INCONS) {
566
0
                zip_error_set(error, ZIP_ER_INCONS, ADD_INDEX_TO_DETAIL(zip_error_code_system(error), i));
567
0
            }
568
0
            _zip_dirent_finalize(&temp);
569
0
            return -1;
570
0
        }
571
572
0
        if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
573
0
            zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(ZIP_ER_DETAIL_ENTRY_HEADER_MISMATCH, i));
574
0
            _zip_dirent_finalize(&temp);
575
0
            return -1;
576
0
        }
577
578
0
        cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
579
0
        cd->entry[i].orig->local_extra_fields_read = 1;
580
0
        temp.extra_fields = NULL;
581
582
0
        _zip_dirent_finalize(&temp);
583
584
0
        if ((detail = zip_dirent_check_consistency(cd->entry[i].orig)) != 0) {
585
0
            zip_error_set(error, ZIP_ER_INCONS, MAKE_DETAIL_WITH_INDEX(detail, i));
586
0
            return -1;
587
0
        }
588
0
    }
589
590
0
    return (max - min) < ZIP_INT64_MAX ? (zip_int64_t)(max - min) : ZIP_INT64_MAX;
591
0
}
592
593
594
/* _zip_headercomp:
595
   compares a central directory entry and a local file header
596
   Return 0 if they are consistent, -1 if not. */
597
598
static int
599
0
_zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local) {
600
0
    if ((central->version_needed < local->version_needed)
601
#if 0
602
  /* some zip-files have different values in local
603
     and global headers for the bitflags */
604
  || (central->bitflags != local->bitflags)
605
#endif
606
0
        || (central->comp_method != local->comp_method) || (central->last_mod.time != local->last_mod.time) || (central->last_mod.date != local->last_mod.date) || !_zip_string_equal(central->filename, local->filename))
607
0
        return -1;
608
609
0
    if ((central->crc != local->crc) || (central->comp_size != local->comp_size) || (central->uncomp_size != local->uncomp_size)) {
610
        /* InfoZip stores valid values in local header even when data descriptor is used.
611
           This is in violation of the appnote.
612
           macOS Archive sets the compressed size even when data descriptor is used ( but not the others),
613
           also in violation of the appnote.
614
        */
615
        /* if data descriptor is not used, the values must match */
616
0
        if ((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0) {
617
0
            return -1;
618
0
        }
619
        /* when using a data descriptor, the local header value must be zero or match */
620
0
        if ((local->crc != 0 && central->crc != local->crc) || (local->comp_size != 0 && central->comp_size != local->comp_size) || (local->uncomp_size != 0 && central->uncomp_size != local->uncomp_size)) {
621
0
            return -1;
622
0
        }
623
0
    }
624
625
0
    return 0;
626
0
}
627
628
629
static zip_t *
630
9.89k
_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error) {
631
9.89k
    zip_t *za;
632
633
9.89k
    if ((za = _zip_new(error)) == NULL) {
634
0
        return NULL;
635
0
    }
636
637
9.89k
    za->src = src;
638
9.89k
    za->open_flags = flags;
639
9.89k
    za->flags = 0;
640
9.89k
    za->ch_flags = 0;
641
9.89k
    za->write_crc = NULL;
642
643
9.89k
    if (flags & ZIP_RDONLY) {
644
0
        za->flags |= ZIP_AFL_RDONLY;
645
0
        za->ch_flags |= ZIP_AFL_RDONLY;
646
0
    }
647
648
9.89k
    return za;
649
9.89k
}
650
651
652
/*
653
 * tests for file existence
654
 */
655
static exists_t
656
9.89k
_zip_file_exists(zip_source_t *src, zip_error_t *error) {
657
9.89k
    struct zip_stat st;
658
659
9.89k
    zip_stat_init(&st);
660
9.89k
    if (zip_source_stat(src, &st) != 0) {
661
925
        zip_error_t *src_error = zip_source_error(src);
662
925
        if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) {
663
925
            return EXISTS_NOT;
664
925
        }
665
0
        _zip_error_copy(error, src_error);
666
0
        return EXISTS_ERROR;
667
925
    }
668
669
8.97k
    return EXISTS_OK;
670
9.89k
}
671
672
673
static zip_cdir_t *
674
8.97k
_zip_find_central_dir(zip_t *za, zip_uint64_t len) {
675
8.97k
    zip_cdir_t *cdir;
676
8.97k
    const zip_uint8_t *match;
677
8.97k
    zip_int64_t buf_offset;
678
8.97k
    zip_uint64_t buflen;
679
8.97k
    zip_error_t error;
680
8.97k
    zip_buffer_t *buffer;
681
682
8.97k
    if (len < EOCDLEN) {
683
94
        zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
684
94
        return NULL;
685
94
    }
686
687
8.88k
    buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);
688
8.88k
    if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {
689
0
        zip_error_t *src_error = zip_source_error(za->src);
690
0
        if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {
691
            /* seek before start of file on my machine */
692
0
            _zip_error_copy(&za->error, src_error);
693
0
            return NULL;
694
0
        }
695
0
    }
696
8.88k
    if ((buf_offset = zip_source_tell(za->src)) < 0) {
697
0
        zip_error_set_from_source(&za->error, za->src);
698
0
        return NULL;
699
0
    }
700
701
8.88k
    if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
702
0
        return NULL;
703
0
    }
704
705
8.88k
    cdir = NULL;
706
8.88k
    if (buflen >= CDBUFSIZE) {
707
        /* EOCD64 locator is before EOCD, so leave place for it */
708
336
        _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
709
336
    }
710
8.88k
    zip_error_set(&error, ZIP_ER_NOZIP, 0);
711
712
8.88k
    match = NULL;
713
80.2k
    while ((match = find_eocd(buffer, match)) != NULL) {
714
79.4k
        _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
715
79.4k
        if (_zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &cdir, &error)) {
716
8.08k
            if (cdir != NULL && (za->open_flags & ZIP_CHECKCONS) && _zip_checkcons(za, cdir, &error) < 0) {
717
0
                _zip_cdir_free(cdir);
718
0
                cdir = NULL;
719
0
            }
720
8.08k
            break;
721
8.08k
        }
722
79.4k
    }
723
724
8.88k
    _zip_buffer_free(buffer);
725
726
8.88k
    if (cdir == NULL) {
727
5.06k
        _zip_error_copy(&za->error, &error);
728
5.06k
    }
729
8.88k
    return cdir;
730
8.88k
}
731
732
733
static const unsigned char *
734
80.2k
find_eocd(zip_buffer_t *buffer, const unsigned char *last) {
735
80.2k
    const unsigned char *data = _zip_buffer_data(buffer);
736
80.2k
    const unsigned char *p;
737
738
80.2k
    if (last == NULL) {
739
8.88k
        last = data + _zip_buffer_size(buffer) - MAGIC_LEN;
740
8.88k
    }
741
71.3k
    else if (last == _zip_buffer_data(buffer)) {
742
422
        return NULL;
743
422
    }
744
70.9k
    else {
745
70.9k
        last -= 1;
746
70.9k
    }
747
748
7.39M
    for (p = last; p >= data; p -= 1) {
749
7.39M
        if (*p == EOCD_MAGIC[0]) {
750
242k
            if (memcmp(p, EOCD_MAGIC, MAGIC_LEN) == 0) {
751
79.4k
                return p;
752
79.4k
            }
753
242k
        }
754
7.39M
    }
755
756
369
    return NULL;
757
79.8k
}
758
759
760
static zip_cdir_t *
761
79.4k
_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error) {
762
79.4k
    zip_cdir_t *cd;
763
764
79.4k
    if (_zip_buffer_left(buffer) < EOCDLEN) {
765
505
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD_LENGTH_INVALID);
766
505
        return NULL;
767
505
    }
768
769
78.9k
    if ((cd = _zip_cdir_new(error)) == NULL) {
770
0
        return NULL;
771
0
    }
772
773
78.9k
    cd->eocd_offset = buf_offset + _zip_buffer_offset(buffer);
774
    /* This function is only called where EOCD magic was found, so no need to check that here. */
775
78.9k
    _zip_buffer_skip(buffer, MAGIC_LEN);
776
78.9k
    cd->is_zip64 = false;
777
78.9k
    cd->this_disk = _zip_buffer_get_16(buffer);
778
78.9k
    cd->eocd_disk = _zip_buffer_get_16(buffer);
779
780
    /* number of cdir-entries on this disk */
781
78.9k
    cd->disk_entries = _zip_buffer_get_16(buffer);
782
    /* number of cdir-entries */
783
78.9k
    cd->num_entries = _zip_buffer_get_16(buffer);
784
78.9k
    cd->size = _zip_buffer_get_32(buffer);
785
78.9k
    cd->offset = _zip_buffer_get_32(buffer);
786
787
78.9k
    return cd;
788
78.9k
}
789
790
static bool
791
6.50k
check_eocd(zip_cdir_t *cd, unsigned int flags, zip_error_t *error) {
792
6.50k
    if (cd->disk_entries != cd->num_entries || cd->this_disk != 0 || cd->eocd_disk != 0) {
793
219
        zip_error_set(error, ZIP_ER_MULTIDISK, 0);
794
219
        return false;
795
219
    }
796
797
6.28k
    if (cd->offset + cd->size < cd->offset) {
798
0
        zip_error_set(error, ZIP_ER_SEEK, EFBIG);
799
0
        return false;
800
0
    }
801
6.28k
    if ((flags & ZIP_CHECKCONS) && cd->offset + cd->size != cd->eocd_offset) {
802
0
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_LENGTH_INVALID);
803
0
        return false;
804
0
    }
805
806
6.28k
    return true;
807
6.28k
}
808
809
810
14.7k
cdir_status_t _zip_read_eocd64(zip_cdir_t *cdir, zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) {
811
14.7k
    zip_uint64_t offset;
812
14.7k
    zip_uint8_t eocd[EOCD64LEN];
813
14.7k
    zip_uint64_t eocd_offset;
814
14.7k
    zip_uint64_t size, nentry, i, eocdloc_offset;
815
14.7k
    bool free_buffer;
816
14.7k
    zip_uint32_t num_disks, eocd_disk, this_disk;
817
818
14.7k
    eocdloc_offset = _zip_buffer_offset(buffer);
819
820
14.7k
    _zip_buffer_get(buffer, 4); /* magic already verified */
821
822
14.7k
    eocd_disk = _zip_buffer_get_32(buffer);
823
14.7k
    eocd_offset = _zip_buffer_get_64(buffer);
824
14.7k
    num_disks = _zip_buffer_get_32(buffer);
825
826
14.7k
    if (!check_magic(eocd_offset, buffer, buf_offset, src, EOCD64_MAGIC)) {
827
12.8k
        return CDIR_NOT_FOUND;
828
12.8k
    }
829
830
1.93k
    if (num_disks != 1) {
831
110
        zip_error_set(error, ZIP_ER_MULTIDISK, 0);
832
110
        return CDIR_INVALID;
833
110
    }
834
835
    /* valid seek value for start of EOCD */
836
1.82k
    if (eocd_offset > ZIP_INT64_MAX) {
837
0
        zip_error_set(error, ZIP_ER_SEEK, EFBIG);
838
0
        return CDIR_INVALID;
839
0
    }
840
841
    /* does EOCD fit before EOCD locator? */
842
1.82k
    if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
843
75
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD);
844
75
        return CDIR_INVALID;
845
75
    }
846
847
    /* make sure current position of buffer is beginning of EOCD */
848
1.74k
    if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
849
1.71k
        _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
850
1.71k
        free_buffer = false;
851
1.71k
    }
852
37
    else {
853
37
        if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
854
0
            zip_error_set_from_source(error, src);
855
0
            return CDIR_INVALID;
856
0
        }
857
37
        if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
858
0
            return CDIR_INVALID;
859
0
        }
860
37
        free_buffer = true;
861
37
    }
862
863
1.74k
    if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
864
0
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_WRONG_MAGIC);
865
0
        if (free_buffer) {
866
0
            _zip_buffer_free(buffer);
867
0
        }
868
0
        return CDIR_INVALID;
869
0
    }
870
871
    /* size of EOCD */
872
1.74k
    size = _zip_buffer_get_64(buffer);
873
874
    /* is there a hole between EOCD and EOCD locator, or do they overlap? */
875
1.74k
    if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
876
0
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_OVERLAPS_EOCD);
877
0
        if (free_buffer) {
878
0
            _zip_buffer_free(buffer);
879
0
        }
880
0
        return CDIR_INVALID;
881
0
    }
882
883
1.74k
    _zip_buffer_get(buffer, 4); /* skip version made by/needed */
884
885
1.74k
    this_disk = _zip_buffer_get_32(buffer);
886
1.74k
    if (_zip_buffer_get_32(buffer) != eocd_disk) {
887
167
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_LOCATOR_MISMATCH);
888
167
        if (free_buffer) {
889
9
            _zip_buffer_free(buffer);
890
9
        }
891
167
        return CDIR_INVALID;
892
167
    }
893
894
1.58k
    i = _zip_buffer_get_64(buffer);
895
1.58k
    nentry = _zip_buffer_get_64(buffer);
896
897
1.58k
    if (nentry != i) {
898
160
        zip_error_set(error, ZIP_ER_MULTIDISK, 0);
899
160
        if (free_buffer) {
900
5
            _zip_buffer_free(buffer);
901
5
        }
902
160
        return CDIR_INVALID;
903
160
    }
904
905
1.42k
    size = _zip_buffer_get_64(buffer);
906
1.42k
    offset = _zip_buffer_get_64(buffer);
907
908
    /* did we read past the end of the buffer? */
909
1.42k
    if (!_zip_buffer_ok(buffer)) {
910
0
        zip_error_set(error, ZIP_ER_INTERNAL, 0);
911
0
        if (free_buffer) {
912
0
            _zip_buffer_free(buffer);
913
0
        }
914
0
        return CDIR_INVALID;
915
0
    }
916
917
1.42k
    if (free_buffer) {
918
23
        _zip_buffer_free(buffer);
919
23
    }
920
921
1.42k
    if (offset > ZIP_INT64_MAX || offset + size < offset) {
922
109
        zip_error_set(error, ZIP_ER_SEEK, EFBIG);
923
109
        return CDIR_INVALID;
924
109
    }
925
926
1.31k
    if (nentry > size / CDENTRYSIZE) {
927
153
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_CDIR_INVALID);
928
153
        return CDIR_INVALID;
929
153
    }
930
931
1.16k
    if ((cdir->size != 0xffffffff && cdir->size != size) || (cdir->offset != 0xffffffff && cdir->offset != offset) || (cdir->num_entries != 0xffff && cdir->num_entries != nentry) || (cdir->disk_entries != 0xffff && cdir->disk_entries != i) || (cdir->this_disk != 0xffff && cdir->this_disk != this_disk) || (cdir->eocd_disk != 0xffff && cdir->eocd_disk != eocd_disk)) {
932
810
        zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EOCD64_MISMATCH);
933
810
        return CDIR_INVALID;
934
810
    }
935
936
350
    cdir->is_zip64 = true;
937
350
    cdir->size = size;
938
350
    cdir->offset = offset;
939
350
    cdir->disk_entries = i;
940
350
    cdir->num_entries = nentry;
941
350
    cdir->this_disk = this_disk;
942
350
    cdir->eocd_disk = eocd_disk;
943
944
350
    return CDIR_OK;
945
1.16k
}
946
947
948
static int
949
1.31k
decode_hex(char c) {
950
1.31k
    if (c >= '0' && c <= '9') {
951
812
        return c - '0';
952
812
    }
953
500
    else if (c >= 'A' && c <= 'F') {
954
398
        return c - 'A' + 10;
955
398
    }
956
102
    else {
957
102
        return -1;
958
102
    }
959
1.31k
}
960
961
/* _zip_check_torrentzip:
962
   check whether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
963
964
static void
965
3.81k
zip_check_torrentzip(zip_t *za, const zip_cdir_t *cdir) {
966
3.81k
    zip_uint32_t crc_should;
967
3.81k
    char buf[8 + 1];
968
3.81k
    size_t i;
969
970
3.81k
    if (cdir == NULL) {
971
0
        return;
972
0
    }
973
974
3.81k
    if (_zip_string_length(cdir->comment) != TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH || strncmp((const char *)cdir->comment->raw, TORRENTZIP_SIGNATURE, TORRENTZIP_SIGNATURE_LENGTH) != 0)
975
3.62k
        return;
976
977
196
    memcpy(buf, cdir->comment->raw + TORRENTZIP_SIGNATURE_LENGTH, TORRENTZIP_CRC_LENGTH);
978
196
    buf[TORRENTZIP_CRC_LENGTH] = '\0';
979
196
    crc_should = 0;
980
785
    for (i = 0; i < TORRENTZIP_CRC_LENGTH; i += 2) {
981
656
        int low, high;
982
656
        high = decode_hex((buf[i]));
983
656
        low = decode_hex(buf[i + 1]);
984
656
        if (high < 0 || low < 0) {
985
67
            return;
986
67
        }
987
589
        crc_should = (crc_should << 8) + (high << 4) + low;
988
589
    }
989
990
129
    {
991
129
        zip_stat_t st;
992
129
        zip_source_t *src_window;
993
129
        zip_source_t *src_crc;
994
129
        zip_uint8_t buffer[512];
995
129
        zip_int64_t ret;
996
997
129
        zip_stat_init(&st);
998
129
        st.valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC;
999
129
        st.size = cdir->size;
1000
129
        st.crc = crc_should;
1001
129
        if ((src_window = _zip_source_window_new(za->src, cdir->offset, cdir->size, &st, 0, NULL, NULL, NULL, 0, false, NULL)) == NULL) {
1002
0
            return;
1003
0
        }
1004
129
        if ((src_crc = zip_source_crc_create(src_window, 1, NULL)) == NULL) {
1005
0
            zip_source_free(src_window);
1006
0
            return;
1007
0
        }
1008
129
        if (zip_source_open(src_crc) != 0) {
1009
0
            zip_source_free(src_crc);
1010
0
            return;
1011
0
        }
1012
179
        while ((ret = zip_source_read(src_crc, buffer, sizeof(buffer))) > 0) {
1013
50
        }
1014
129
        zip_source_free(src_crc);
1015
129
        if (ret < 0) {
1016
127
            return;
1017
127
        }
1018
129
    }
1019
1020
    /* TODO: if check consistency, check cdir entries for valid values */
1021
2
    za->flags |= ZIP_AFL_IS_TORRENTZIP;
1022
2
}