Coverage Report

Created: 2026-10-14 06:52

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
59.7k
void _zip_ef_free(zip_extra_field_t *ef) {
104
59.7k
    zip_extra_field_t *ef2;
105
106
64.7k
    while (ef) {
107
4.99k
        ef2 = ef->next;
108
4.99k
        free(ef->data);
109
4.99k
        free(ef);
110
4.99k
        ef = ef2;
111
4.99k
    }
112
59.7k
}
113
114
115k
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
115k
    zip_extra_field_t *ef;
116
115k
    zip_uint16_t i;
117
118
115k
    i = 0;
119
125k
    for (ef = ef_head; ef; ef = ef->next) {
120
9.59k
        if (ef->id == ef_id) {
121
322
            if (i == ef_idx) {
122
322
                return ef;
123
322
            }
124
0
            i++;
125
0
        }
126
9.27k
        if (prev) {
127
0
            *prev = ef;
128
0
        }
129
9.27k
    }
130
131
115k
    return NULL;
132
115k
}
133
134
135
115k
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
115k
    static const zip_uint8_t empty[1] = {'\0'};
137
138
115k
    zip_extra_field_t *ef = _zip_ef_find((zip_extra_field_t *)ef_head, id, id_idx, NULL);
139
140
115k
    if (ef) {
141
322
        if (lenp) {
142
322
            *lenp = ef->size;
143
322
        }
144
322
        if (ef->size > 0) {
145
137
            return ef->data;
146
137
        }
147
185
        else {
148
185
            return empty;
149
185
        }
150
322
    }
151
152
115k
    return NULL;
153
115k
}
154
155
4.99k
zip_extra_field_t *_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data) {
156
4.99k
    zip_extra_field_t *ef;
157
158
4.99k
    if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL) {
159
0
        return NULL;
160
0
    }
161
162
4.99k
    ef->next = NULL;
163
4.99k
    ef->id = id;
164
4.99k
    ef->size = size;
165
4.99k
    if (size > 0) {
166
2.41k
        if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
167
0
            free(ef);
168
0
            return NULL;
169
0
        }
170
2.41k
    }
171
2.58k
    else {
172
2.58k
        ef->data = NULL;
173
2.58k
    }
174
175
4.99k
    return ef;
176
4.99k
}
177
178
179
1.67k
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.67k
    zip_buffer_t *buffer;
181
1.67k
    zip_extra_field_t *ef, *ef2, *ef_head;
182
183
1.67k
    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.67k
    ef_head = ef = NULL;
189
190
6.66k
    while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) {
191
5.12k
        zip_uint16_t fid, flen;
192
5.12k
        zip_uint8_t *ef_data;
193
194
5.12k
        fid = _zip_buffer_get_16(buffer);
195
5.12k
        flen = _zip_buffer_get_16(buffer);
196
5.12k
        ef_data = _zip_buffer_get(buffer, flen);
197
198
5.12k
        if (ef_data == NULL) {
199
127
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH);
200
127
            _zip_buffer_free(buffer);
201
127
            _zip_ef_free(ef_head);
202
127
            return false;
203
127
        }
204
205
4.99k
        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.99k
        if (ef_head) {
213
3.40k
            ef->next = ef2;
214
3.40k
            ef = ef2;
215
3.40k
        }
216
1.58k
        else {
217
1.58k
            ef_head = ef = ef2;
218
1.58k
        }
219
4.99k
    }
220
221
1.54k
    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
422
        size_t glen = _zip_buffer_left(buffer);
226
422
        zip_uint8_t *garbage;
227
422
        garbage = _zip_buffer_get(buffer, glen);
228
422
        if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", (size_t)glen) != 0) {
229
66
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE);
230
66
            _zip_buffer_free(buffer);
231
66
            _zip_ef_free(ef_head);
232
66
            return false;
233
66
        }
234
422
    }
235
236
1.48k
    _zip_buffer_free(buffer);
237
238
1.48k
    if (ef_head_p) {
239
1.48k
        *ef_head_p = ef_head;
240
1.48k
    }
241
0
    else {
242
0
        _zip_ef_free(ef_head);
243
0
    }
244
245
1.48k
    return true;
246
1.54k
}
247
248
249
28.6k
zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *ef) {
250
28.6k
    zip_extra_field_t *ef_head;
251
28.6k
    zip_extra_field_t *prev, *next;
252
253
28.6k
    ef_head = ef;
254
28.6k
    prev = NULL;
255
256
32.4k
    while (ef) {
257
3.81k
        if (ZIP_EF_IS_INTERNAL(ef->id)) {
258
158
            next = ef->next;
259
158
            if (ef_head == ef) {
260
41
                ef_head = next;
261
41
            }
262
158
            ef->next = NULL;
263
158
            _zip_ef_free(ef);
264
158
            if (prev) {
265
117
                prev->next = next;
266
117
            }
267
158
            ef = next;
268
158
        }
269
3.65k
        else {
270
3.65k
            prev = ef;
271
3.65k
            ef = ef->next;
272
3.65k
        }
273
3.81k
    }
274
275
28.6k
    return ef_head;
276
28.6k
}
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
58.1k
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
58.1k
    const zip_uint8_t *data;
425
426
58.1k
    if (flags & ZIP_EF_LOCAL) {
427
57.7k
        data = _zip_ef_get_by_id(extra_fields->local, lenp, extra_field_id, extra_field_index, flags);
428
57.7k
        if (data) {
429
0
            return data;
430
0
        }
431
57.7k
    }
432
433
58.1k
    if (flags & ZIP_EF_CENTRAL) {
434
58.1k
        data = _zip_ef_get_by_id(extra_fields->central, lenp, extra_field_id, extra_field_index, flags);
435
58.1k
        if (data) {
436
322
            return data;
437
322
        }
438
58.1k
    }
439
440
57.8k
    zip_error_set(error, ZIP_ER_NOENT, 0);
441
57.8k
    return NULL;
442
58.1k
}
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
    /* If we are updating an existing field with its current data pointer, just update the size.
502
       This also ensures that data remains valid, which is needed if we set both local and central extra fields. */
503
0
    if (ef && ef->data == data) {
504
        /* Since ef->data can be user supplied, we don't know its allocation size, so a bigger len may be fine. */
505
0
        ef->size = len;
506
0
        return ef_head;
507
0
    }
508
509
    /* Otherwise, create a new extra field. */
510
0
    if ((ef_new = _zip_ef_new(ef_id, len, data)) == NULL) {
511
0
        zip_error_set(error, ZIP_ER_MEMORY, 0);
512
0
        return NULL;
513
0
    }
514
515
0
    if (ef != NULL) {
516
0
        ef_new->next = ef->next;
517
0
        ef->next = NULL;
518
0
        _zip_ef_free(ef);
519
0
    }
520
0
    else if (ef_prev) {
521
0
        ef_new->next = ef_prev->next;
522
0
    }
523
524
0
    if (ef_prev) {
525
0
        ef_prev->next = ef_new;
526
0
    }
527
0
    else {
528
0
        ef_head = ef_new;
529
0
    }
530
531
0
    return ef_head;
532
0
}
533
534
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) {
535
0
    zip_extra_field_t *ef;
536
537
0
    if (flags & ZIP_EF_LOCAL) {
538
0
        ef = _zip_ef_set(extra_fields->local, ef_id, ef_idx, data, len, error);
539
0
        if (ef == NULL) {
540
0
            return false;
541
0
        }
542
0
        extra_fields->local = ef;
543
0
    }
544
0
    if (flags & ZIP_EF_CENTRAL) {
545
0
        ef = _zip_ef_set(extra_fields->central, ef_id, ef_idx, data, len, error);
546
0
        if (ef == NULL) {
547
0
            return false;
548
0
        }
549
0
        extra_fields->central = ef;
550
0
    }
551
552
0
    return true;
553
0
}
554
555
0
bool _zip_extra_fields_clone(zip_extra_fields_t *extra_fields, zip_error_t *error) {
556
0
    if (extra_fields->local) {
557
0
        if ((extra_fields->local = _zip_ef_clone(extra_fields->local, error)) == NULL) {
558
            /* Clear central so we don't refer to the original. */
559
0
            extra_fields->central = NULL;
560
0
            return false;
561
0
        }
562
0
    }
563
0
    if (extra_fields->central) {
564
0
        if ((extra_fields->central = _zip_ef_clone(extra_fields->central, error)) == NULL) {
565
0
            return false;
566
0
        }
567
0
    }
568
569
0
    return true;
570
0
}
571
572
573
29.7k
void _zip_extra_fields_fini(zip_extra_fields_t *extra_fields) {
574
29.7k
    _zip_ef_free(extra_fields->local);
575
29.7k
    extra_fields->local = NULL;
576
29.7k
    _zip_ef_free(extra_fields->central);
577
29.7k
    extra_fields->central = NULL;
578
29.7k
}
579
580
88.4k
void _zip_extra_fields_init(zip_extra_fields_t *extra_fields) {
581
88.4k
    extra_fields->local = NULL;
582
88.4k
    extra_fields->central = NULL;
583
88.4k
}
584
585
586
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) {
587
0
    if (flags & ZIP_EF_LOCAL) {
588
0
        extra_fields->local = _zip_ef_delete_by_id(extra_fields->local, extra_field_id, extra_field_index);
589
0
    }
590
0
    if (flags & ZIP_EF_CENTRAL) {
591
0
        extra_fields->central = _zip_ef_delete_by_id(extra_fields->central, extra_field_id, extra_field_index);
592
0
    }
593
0
}