Coverage Report

Created: 2026-09-14 07:37

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
0
void _zip_ef_free(zip_extra_field_t *ef) {
104
0
    zip_extra_field_t *ef2;
105
106
0
    while (ef) {
107
0
        ef2 = ef->next;
108
0
        free(ef->data);
109
0
        free(ef);
110
0
        ef = ef2;
111
0
    }
112
0
}
113
114
0
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
0
    zip_extra_field_t *ef;
116
0
    zip_uint16_t i;
117
118
0
    i = 0;
119
0
    for (ef = ef_head; ef; ef = ef->next) {
120
0
        if (ef->id == ef_id) {
121
0
            if (i == ef_idx) {
122
0
                return ef;
123
0
            }
124
0
            i++;
125
0
        }
126
0
        if (prev) {
127
0
            *prev = ef;
128
0
        }
129
0
    }
130
131
0
    return NULL;
132
0
}
133
134
135
0
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
0
    static const zip_uint8_t empty[1] = {'\0'};
137
138
0
    zip_extra_field_t *ef = _zip_ef_find((zip_extra_field_t *)ef_head, id, id_idx, NULL);
139
140
0
    if (ef) {
141
0
        if (lenp) {
142
0
            *lenp = ef->size;
143
0
        }
144
0
        if (ef->size > 0) {
145
0
            return ef->data;
146
0
        }
147
0
        else {
148
0
            return empty;
149
0
        }
150
0
    }
151
152
0
    return NULL;
153
0
}
154
155
0
zip_extra_field_t *_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data) {
156
0
    zip_extra_field_t *ef;
157
158
0
    if ((ef = (zip_extra_field_t *)malloc(sizeof(*ef))) == NULL) {
159
0
        return NULL;
160
0
    }
161
162
0
    ef->next = NULL;
163
0
    ef->id = id;
164
0
    ef->size = size;
165
0
    if (size > 0) {
166
0
        if ((ef->data = (zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
167
0
            free(ef);
168
0
            return NULL;
169
0
        }
170
0
    }
171
0
    else {
172
0
        ef->data = NULL;
173
0
    }
174
175
0
    return ef;
176
0
}
177
178
179
0
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
0
    zip_buffer_t *buffer;
181
0
    zip_extra_field_t *ef, *ef2, *ef_head;
182
183
0
    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
0
    ef_head = ef = NULL;
189
190
0
    while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) {
191
0
        zip_uint16_t fid, flen;
192
0
        zip_uint8_t *ef_data;
193
194
0
        fid = _zip_buffer_get_16(buffer);
195
0
        flen = _zip_buffer_get_16(buffer);
196
0
        ef_data = _zip_buffer_get(buffer, flen);
197
198
0
        if (ef_data == NULL) {
199
0
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_EF_LENGTH);
200
0
            _zip_buffer_free(buffer);
201
0
            _zip_ef_free(ef_head);
202
0
            return false;
203
0
        }
204
205
0
        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
0
        if (ef_head) {
213
0
            ef->next = ef2;
214
0
            ef = ef2;
215
0
        }
216
0
        else {
217
0
            ef_head = ef = ef2;
218
0
        }
219
0
    }
220
221
0
    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
0
        size_t glen = _zip_buffer_left(buffer);
226
0
        zip_uint8_t *garbage;
227
0
        garbage = _zip_buffer_get(buffer, glen);
228
0
        if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", (size_t)glen) != 0) {
229
0
            zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_EF_TRAILING_GARBAGE);
230
0
            _zip_buffer_free(buffer);
231
0
            _zip_ef_free(ef_head);
232
0
            return false;
233
0
        }
234
0
    }
235
236
0
    _zip_buffer_free(buffer);
237
238
0
    if (ef_head_p) {
239
0
        *ef_head_p = ef_head;
240
0
    }
241
0
    else {
242
0
        _zip_ef_free(ef_head);
243
0
    }
244
245
0
    return true;
246
0
}
247
248
249
0
zip_extra_field_t *_zip_ef_remove_internal(zip_extra_field_t *ef) {
250
0
    zip_extra_field_t *ef_head;
251
0
    zip_extra_field_t *prev, *next;
252
253
0
    ef_head = ef;
254
0
    prev = NULL;
255
256
0
    while (ef) {
257
0
        if (ZIP_EF_IS_INTERNAL(ef->id)) {
258
0
            next = ef->next;
259
0
            if (ef_head == ef) {
260
0
                ef_head = next;
261
0
            }
262
0
            ef->next = NULL;
263
0
            _zip_ef_free(ef);
264
0
            if (prev) {
265
0
                prev->next = next;
266
0
            }
267
0
            ef = next;
268
0
        }
269
0
        else {
270
0
            prev = ef;
271
0
            ef = ef->next;
272
0
        }
273
0
    }
274
275
0
    return ef_head;
276
0
}
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
0
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
0
    const zip_uint8_t *data;
425
426
0
    if (flags & ZIP_EF_LOCAL) {
427
0
        data = _zip_ef_get_by_id(extra_fields->local, lenp, extra_field_id, extra_field_index, flags);
428
0
        if (data) {
429
0
            return data;
430
0
        }
431
0
    }
432
433
0
    if (flags & ZIP_EF_CENTRAL) {
434
0
        data = _zip_ef_get_by_id(extra_fields->central, lenp, extra_field_id, extra_field_index, flags);
435
0
        if (data) {
436
0
            return data;
437
0
        }
438
0
    }
439
440
0
    zip_error_set(error, ZIP_ER_NOENT, 0);
441
0
    return NULL;
442
0
}
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
0
void _zip_extra_fields_fini(zip_extra_fields_t *extra_fields) {
565
0
    _zip_ef_free(extra_fields->local);
566
0
    extra_fields->local = NULL;
567
0
    _zip_ef_free(extra_fields->central);
568
0
    extra_fields->central = NULL;
569
0
}
570
571
0
void _zip_extra_fields_init(zip_extra_fields_t *extra_fields) {
572
0
    extra_fields->local = NULL;
573
0
    extra_fields->central = NULL;
574
0
}
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
}