Coverage Report

Created: 2026-08-25 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzip/lib/zip_extra_field.c
Line
Count
Source
1
/*
2
  zip_extra_field.c -- manipulate extra fields
3
  Copyright (C) 2012-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 <stdlib.h>
35
#include <string.h>
36
37
#include "zipint.h"
38
39
40
0
zip_extra_field_t *_zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error) {
41
0
    zip_extra_field_t *head, *prev, *def;
42
43
0
    head = prev = NULL;
44
45
0
    while (ef) {
46
0
        if ((def = _zip_ef_new(ef->id, ef->size, ef->data)) == NULL) {
47
0
            zip_error_set(error, ZIP_ER_MEMORY, 0);
48
0
            _zip_ef_free(head);
49
0
            return NULL;
50
0
        }
51
52
0
        if (head == NULL) {
53
0
            head = def;
54
0
        }
55
0
        if (prev) {
56
0
            prev->next = def;
57
0
        }
58
0
        prev = def;
59
60
0
        ef = ef->next;
61
0
    }
62
63
0
    return head;
64
0
}
65
66
67
0
zip_extra_field_t *_zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx) {
68
0
    zip_extra_field_t *head, *prev;
69
0
    int i;
70
71
0
    i = 0;
72
0
    head = ef;
73
0
    prev = NULL;
74
0
    for (; ef; ef = (prev ? prev->next : head)) {
75
0
        if ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL)) {
76
0
            if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {
77
0
                if (prev) {
78
0
                    prev->next = ef->next;
79
0
                }
80
0
                else {
81
0
                    head = ef->next;
82
0
                }
83
0
                ef->next = NULL;
84
0
                _zip_ef_free(ef);
85
86
0
                if (id_idx == ZIP_EXTRA_FIELD_ALL) {
87
0
                    continue;
88
0
                }
89
0
            }
90
91
0
            i++;
92
0
            if (i > id_idx) {
93
0
                break;
94
0
            }
95
0
        }
96
0
        prev = ef;
97
0
    }
98
99
0
    return head;
100
0
}
101
102
103
63.0k
void _zip_ef_free(zip_extra_field_t *ef) {
104
63.0k
    zip_extra_field_t *ef2;
105
106
68.0k
    while (ef) {
107
4.96k
        ef2 = ef->next;
108
4.96k
        free(ef->data);
109
4.96k
        free(ef);
110
4.96k
        ef = ef2;
111
4.96k
    }
112
63.0k
}
113
114
122k
zip_extra_field_t *_zip_ef_find(zip_extra_field_t *ef_head, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_extra_field_t **prev) {
115
122k
    zip_extra_field_t *ef;
116
122k
    zip_uint16_t i;
117
118
122k
    i = 0;
119
131k
    for (ef = ef_head; ef; ef = ef->next) {
120
9.07k
        if (ef->id == ef_id) {
121
244
            if (i == ef_idx) {
122
244
                return ef;
123
244
            }
124
0
            i++;
125
0
        }
126
8.83k
        if (prev) {
127
0
            *prev = ef;
128
0
        }
129
8.83k
    }
130
131
122k
    return NULL;
132
122k
}
133
134
135
122k
const zip_uint8_t *_zip_ef_get_by_id(const zip_extra_field_t *ef_head, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags) {
136
122k
    static const zip_uint8_t empty[1] = {'\0'};
137
138
122k
    zip_extra_field_t *ef = _zip_ef_find((zip_extra_field_t *)ef_head, id, id_idx, NULL);
139
140
122k
    if (ef) {
141
244
        if (lenp) {
142
244
            *lenp = ef->size;
143
244
        }
144
244
        if (ef->size > 0) {
145
175
            return ef->data;
146
175
        }
147
69
        else {
148
69
            return empty;
149
69
        }
150
244
    }
151
152
122k
    return NULL;
153
122k
}
154
155
4.96k
zip_extra_field_t *_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data) {
156
4.96k
    zip_extra_field_t *ef;
157
158
4.96k
    if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL) {
159
0
        return NULL;
160
0
    }
161
162
4.96k
    ef->next = NULL;
163
4.96k
    ef->id = id;
164
4.96k
    ef->size = size;
165
4.96k
    if (size > 0) {
166
2.89k
        if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
167
0
            free(ef);
168
0
            return NULL;
169
0
        }
170
2.89k
    }
171
2.06k
    else {
172
2.06k
        ef->data = NULL;
173
2.06k
    }
174
175
4.96k
    return ef;
176
4.96k
}
177
178
179
1.83k
bool _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_extra_field_t **ef_head_p, zip_error_t *error) {
180
1.83k
    zip_buffer_t *buffer;
181
1.83k
    zip_extra_field_t *ef, *ef2, *ef_head;
182
183
1.83k
    if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) {
184
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
185
0
        return false;
186
0
    }
187
188
1.83k
    ef_head = ef = NULL;
189
190
6.80k
    while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) {
191
5.10k
        zip_uint16_t fid, flen;
192
5.10k
        zip_uint8_t *ef_data;
193
194
5.10k
        fid = _zip_buffer_get_16(buffer);
195
5.10k
        flen = _zip_buffer_get_16(buffer);
196
5.10k
        ef_data = _zip_buffer_get(buffer, flen);
197
198
5.10k
        if (ef_data == NULL) {
199
140
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH);
200
140
            _zip_buffer_free(buffer);
201
140
            _zip_ef_free(ef_head);
202
140
            return false;
203
140
        }
204
205
4.96k
        if ((ef2 = _zip_ef_new(fid, flen, ef_data)) == NULL) {
206
0
            zip_error_set(error, ZIP_ER_MEMORY, 0);
207
0
            _zip_buffer_free(buffer);
208
0
            _zip_ef_free(ef_head);
209
0
            return false;
210
0
        }
211
212
4.96k
        if (ef_head) {
213
3.24k
            ef->next = ef2;
214
3.24k
            ef = ef2;
215
3.24k
        }
216
1.72k
        else {
217
1.72k
            ef_head = ef = ef2;
218
1.72k
        }
219
4.96k
    }
220
221
1.69k
    if (!_zip_buffer_eof(buffer)) {
222
        /* Android APK files align stored file data with padding in extra fields; ignore. */
223
        /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */
224
        /* buffer is at most 64k long, so this can't overflow. */
225
361
        size_t glen = _zip_buffer_left(buffer);
226
361
        zip_uint8_t *garbage;
227
361
        garbage = _zip_buffer_get(buffer, glen);
228
361
        if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", (size_t)glen) != 0) {
229
71
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE);
230
71
            _zip_buffer_free(buffer);
231
71
            _zip_ef_free(ef_head);
232
71
            return false;
233
71
        }
234
361
    }
235
236
1.62k
    _zip_buffer_free(buffer);
237
238
1.62k
    if (ef_head_p) {
239
1.62k
        *ef_head_p = ef_head;
240
1.62k
    }
241
0
    else {
242
0
        _zip_ef_free(ef_head);
243
0
    }
244
245
1.62k
    return true;
246
1.69k
}
247
248
249
30.3k
zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *ef) {
250
30.3k
    zip_extra_field_t *ef_head;
251
30.3k
    zip_extra_field_t *prev, *next;
252
253
30.3k
    ef_head = ef;
254
30.3k
    prev = NULL;
255
256
33.8k
    while (ef) {
257
3.53k
        if (ZIP_EF_IS_INTERNAL(ef->id)) {
258
113
            next = ef->next;
259
113
            if (ef_head == ef) {
260
36
                ef_head = next;
261
36
            }
262
113
            ef->next = NULL;
263
113
            _zip_ef_free(ef);
264
113
            if (prev) {
265
77
                prev->next = next;
266
77
            }
267
113
            ef = next;
268
113
        }
269
3.42k
        else {
270
3.42k
            prev = ef;
271
3.42k
            ef = ef->next;
272
3.42k
        }
273
3.53k
    }
274
275
30.3k
    return ef_head;
276
30.3k
}
277
278
279
/**
280
 * Calculate the size of the extra fields in bytes.
281
 *
282
 * @param ef the extra fields
283
 * @param flags which extra fields to include (ZIP_EF_LOCAL, ZIP_EF_CENTRAL, or both)
284
 * @return the size of the extra fields in bytes, or -1 if the size exceeds ZIP_UINT16_MAX.
285
 */
286
0
zip_int32_t _zip_ef_size(const zip_extra_field_t *ef) {
287
0
    zip_uint32_t size;
288
289
0
    size = 0;
290
0
    for (; ef; ef = ef->next) {
291
0
        size = (zip_uint32_t)(size + 4 + ef->size);
292
0
        if (size > ZIP_UINT16_MAX) {
293
0
            return -1;
294
0
        }
295
0
    }
296
297
0
    return (zip_int32_t)size;
298
0
}
299
300
301
0
int _zip_ef_write(zip_t *za, const zip_extra_field_t *ef) {
302
0
    zip_uint8_t b[4];
303
0
    zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b));
304
305
0
    if (buffer == NULL) {
306
0
        return -1;
307
0
    }
308
309
0
    for (; ef; ef = ef->next) {
310
0
        _zip_buffer_set_offset(buffer, 0);
311
0
        _zip_buffer_put_16(buffer, ef->id);
312
0
        _zip_buffer_put_16(buffer, ef->size);
313
0
        if (!_zip_buffer_ok(buffer)) {
314
0
            zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
315
0
            _zip_buffer_free(buffer);
316
0
            return -1;
317
0
        }
318
0
        if (_zip_write(za, b, 4) < 0) {
319
0
            _zip_buffer_free(buffer);
320
0
            return -1;
321
0
        }
322
0
        if (ef->size > 0) {
323
0
            if (_zip_write(za, ef->data, ef->size) < 0) {
324
0
                _zip_buffer_free(buffer);
325
0
                return -1;
326
0
            }
327
0
        }
328
0
    }
329
330
0
    _zip_buffer_free(buffer);
331
0
    return 0;
332
0
}
333
334
335
0
int _zip_read_local_ef(zip_t *za, zip_uint64_t idx) {
336
0
    zip_entry_t *e;
337
0
    unsigned char b[4];
338
0
    zip_buffer_t *buffer;
339
0
    zip_uint16_t fname_len, ef_len;
340
341
0
    if (idx >= za->nentry) {
342
0
        zip_error_set(&za->error, ZIP_ER_INVAL, 0);
343
0
        return -1;
344
0
    }
345
346
0
    e = za->entry + idx;
347
348
0
    if (e->orig == NULL || e->orig->local_extra_fields_read) {
349
0
        return 0;
350
0
    }
351
352
0
    if (e->orig->offset + 26 > ZIP_INT64_MAX) {
353
0
        zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG);
354
0
        return -1;
355
0
    }
356
357
0
    if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) {
358
0
        zip_error_set_from_source(&za->error, za->src);
359
0
        return -1;
360
0
    }
361
362
0
    if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) {
363
0
        return -1;
364
0
    }
365
366
0
    fname_len = _zip_buffer_get_16(buffer);
367
0
    ef_len = _zip_buffer_get_16(buffer);
368
369
0
    if (!_zip_buffer_eof(buffer)) {
370
0
        _zip_buffer_free(buffer);
371
0
        zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
372
0
        return -1;
373
0
    }
374
375
0
    _zip_buffer_free(buffer);
376
377
0
    if (ef_len > 0) {
378
0
        zip_extra_field_t *ef;
379
0
        zip_uint8_t *ef_raw;
380
381
0
        if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) {
382
0
            zip_error_set(&za->error, ZIP_ER_SEEK, errno);
383
0
            return -1;
384
0
        }
385
386
0
        ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error);
387
388
0
        if (ef_raw == NULL) {
389
0
            return -1;
390
0
        }
391
392
0
        if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) {
393
0
            free(ef_raw);
394
0
            return -1;
395
0
        }
396
0
        free(ef_raw);
397
398
0
        if (ef) {
399
0
            ef = _zip_ef_remove_internal(ef);
400
0
            e->orig->extra_fields.local = ef;
401
0
        }
402
0
    }
403
404
0
    e->orig->local_extra_fields_read = 1;
405
406
0
    if (e->changes && e->changes->local_extra_fields_read == 0) {
407
0
        e->changes->extra_fields = e->orig->extra_fields;
408
0
        e->changes->local_extra_fields_read = 1;
409
0
    }
410
411
0
    return 0;
412
0
}
413
414
0
void _zip_extrafields_delete_by_id(zip_extra_fields_t *fields, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags) {
415
0
    if (flags & ZIP_EF_LOCAL) {
416
0
        fields->local = _zip_ef_delete_by_id(fields->local, ef_id, ef_idx);
417
0
    }
418
0
    if (flags & ZIP_EF_CENTRAL) {
419
0
        fields->central = _zip_ef_delete_by_id(fields->central, ef_id, ef_idx);
420
0
    }
421
0
}
422
423
61.7k
const zip_uint8_t *_zip_extra_fields_get_by_id(const zip_extra_fields_t *extra_fields, zip_uint16_t *lenp, zip_uint16_t extra_field_id, zip_uint16_t extra_field_index, zip_flags_t flags, zip_error_t *error) {
424
61.7k
    const zip_uint8_t *data;
425
426
61.7k
    if (flags & ZIP_EF_LOCAL) {
427
61.1k
        data = _zip_ef_get_by_id(extra_fields->local, lenp, extra_field_id, extra_field_index, flags);
428
61.1k
        if (data) {
429
0
            return data;
430
0
        }
431
61.1k
    }
432
433
61.7k
    if (flags & ZIP_EF_CENTRAL) {
434
61.7k
        data = _zip_ef_get_by_id(extra_fields->central, lenp, extra_field_id, extra_field_index, flags);
435
61.7k
        if (data) {
436
244
            return data;
437
244
        }
438
61.7k
    }
439
440
61.4k
    zip_error_set(error, ZIP_ER_NOENT, 0);
441
61.4k
    return NULL;
442
61.7k
}
443
444
0
zip_int16_t _zip_ef_count(const zip_extra_field_t *ef, zip_int32_t id) {
445
0
    zip_int16_t n;
446
447
0
    n = 0;
448
0
    for (; ef; ef = ef->next) {
449
0
        if (id < 0 || ef->id == id) {
450
0
            n++;
451
0
        }
452
0
    }
453
454
0
    return n;
455
0
}
456
457
0
zip_int16_t _zip_extra_fields_count(const zip_extra_fields_t *extra_fields, zip_int32_t id, zip_flags_t flags) {
458
0
    zip_int16_t n;
459
460
0
    n = 0;
461
0
    if (flags & ZIP_EF_LOCAL) {
462
0
        n += _zip_ef_count(extra_fields->local, id);
463
0
    }
464
0
    if (flags & ZIP_EF_CENTRAL) {
465
0
        n += _zip_ef_count(extra_fields->central, id);
466
0
    }
467
468
0
    return n;
469
0
}
470
471
472
0
zip_extra_field_t *_zip_ef_set(zip_extra_field_t *ef_head, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_error_t *error) {
473
0
    zip_extra_field_t *ef_prev = NULL;
474
0
    zip_extra_field_t *ef_new, *ef;
475
0
    zip_int32_t new_len;
476
477
0
    ef = _zip_ef_find(ef_head, ef_id, ef_idx, &ef_prev);
478
479
0
    if (ef == NULL && ef_idx != ZIP_EXTRA_FIELD_NEW) {
480
0
        zip_error_set(error, ZIP_ER_INVAL, 0);
481
0
        return NULL;
482
0
    }
483
484
0
    new_len = _zip_ef_size(ef_head);
485
    /* This should not happen, but we want to assume lengths are >= 0 later. */
486
0
    if (new_len < 0) {
487
0
        zip_error_set(error, ZIP_ER_EF_TOO_LARGE, 0);
488
0
        return NULL;
489
0
    }
490
491
0
    if (ef != NULL) {
492
0
        new_len -= ef->size + 4;
493
0
    }
494
0
    new_len += len + 4;
495
496
0
    if (new_len > ZIP_UINT16_MAX) {
497
0
        zip_error_set(error, ZIP_ER_EF_TOO_LARGE, 0);
498
0
        return NULL;
499
0
    }
500
501
0
    if ((ef_new = _zip_ef_new(ef_id, len, data)) == NULL) {
502
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
503
0
        return NULL;
504
0
    }
505
506
0
    if (ef != NULL) {
507
0
        ef_new->next = ef->next;
508
0
        ef->next = NULL;
509
0
        _zip_ef_free(ef);
510
0
    }
511
0
    else if (ef_prev) {
512
0
        ef_new->next = ef_prev->next;
513
0
    }
514
515
0
    if (ef_prev) {
516
0
        ef_prev->next = ef_new;
517
0
    }
518
0
    else {
519
0
        ef_head = ef_new;
520
0
    }
521
522
0
    return ef_head;
523
0
}
524
525
0
bool _zip_extra_fields_set(zip_extra_fields_t *extra_fields, zip_flags_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_error_t *error) {
526
0
    zip_extra_field_t *ef;
527
528
0
    if (flags & ZIP_EF_LOCAL) {
529
0
        ef = _zip_ef_set(extra_fields->local, ef_id, ef_idx, data, len, error);
530
0
        if (ef == NULL) {
531
0
            return false;
532
0
        }
533
0
        extra_fields->local = ef;
534
0
    }
535
0
    if (flags & ZIP_EF_CENTRAL) {
536
0
        ef = _zip_ef_set(extra_fields->central, ef_id, ef_idx, data, len, error);
537
0
        if (ef == NULL) {
538
0
            return false;
539
0
        }
540
0
        extra_fields->central = ef;
541
0
    }
542
543
0
    return true;
544
0
}
545
546
0
bool _zip_extra_fields_clone(zip_extra_fields_t *extra_fields, zip_error_t *error) {
547
0
    if (extra_fields->local) {
548
0
        if ((extra_fields->local = _zip_ef_clone(extra_fields->local, error)) == NULL) {
549
            /* Clear central so we don't refer to the original. */
550
0
            extra_fields->central = NULL;
551
0
            return false;
552
0
        }
553
0
    }
554
0
    if (extra_fields->central) {
555
0
        if ((extra_fields->central = _zip_ef_clone(extra_fields->central, error)) == NULL) {
556
0
            return false;
557
0
        }
558
0
    }
559
560
0
    return true;
561
0
}
562
563
564
31.3k
void _zip_extra_fields_fini(zip_extra_fields_t *extra_fields) {
565
31.3k
    _zip_ef_free(extra_fields->local);
566
31.3k
    extra_fields->local = NULL;
567
31.3k
    _zip_ef_free(extra_fields->central);
568
31.3k
    extra_fields->central = NULL;
569
31.3k
}
570
571
93.4k
void _zip_extra_fields_init(zip_extra_fields_t *extra_fields) {
572
93.4k
    extra_fields->local = NULL;
573
93.4k
    extra_fields->central = NULL;
574
93.4k
}
575
576
577
0
void _zip_extra_fields_delete_by_id(zip_extra_fields_t *extra_fields, zip_uint16_t extra_field_id, zip_uint16_t extra_field_index, zip_flags_t flags) {
578
0
    if (flags & ZIP_EF_LOCAL) {
579
0
        extra_fields->local = _zip_ef_delete_by_id(extra_fields->local, extra_field_id, extra_field_index);
580
0
    }
581
0
    if (flags & ZIP_EF_CENTRAL) {
582
0
        extra_fields->central = _zip_ef_delete_by_id(extra_fields->central, extra_field_id, extra_field_index);
583
0
    }
584
0
}