blob: 035047827ee33b87318229a714379657b1f1035f [file] [log] [blame]
Dieter Baron0e5eeab2012-04-24 18:47:12 +02001/*
2 zip_extra_field.c -- manipulate extra fields
Thomas Klausnera1415de2015-04-29 15:36:30 +02003 Copyright (C) 2012-2015 Dieter Baron and Thomas Klausner
Dieter Baron0e5eeab2012-04-24 18:47:12 +02004
5 This file is part of libzip, a library to manipulate ZIP archives.
6 The authors can be contacted at <libzip@nih.at>
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in
15 the documentation and/or other materials provided with the
16 distribution.
17 3. The names of the authors may not be used to endorse or promote
18 products derived from this software without specific prior
19 written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
Dieter Baron0e5eeab2012-04-24 18:47:12 +020034#include <stdlib.h>
35#include <string.h>
36
Thomas Klausner51180602015-08-21 13:36:26 +020037#include "zipint.h"
38
Dieter Baron0e5eeab2012-04-24 18:47:12 +020039
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020040zip_extra_field_t *
41_zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error)
Dieter Baron6fad8b62012-10-12 15:18:04 +020042{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020043 zip_extra_field_t *head, *prev, *def;
Dieter Baron6fad8b62012-10-12 15:18:04 +020044
45 head = prev = NULL;
46
47 while (ef) {
48 if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020049 zip_error_set(error, ZIP_ER_MEMORY, 0);
Dieter Baron6fad8b62012-10-12 15:18:04 +020050 _zip_ef_free(head);
51 return NULL;
52 }
53
54 if (head == NULL)
55 head = def;
56 if (prev)
57 prev->next = def;
58 prev = def;
Thomas Klausner95d6fdf2013-02-20 11:47:10 +010059
60 ef = ef->next;
Dieter Baron6fad8b62012-10-12 15:18:04 +020061 }
62
63 return head;
64}
65
66
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020067zip_extra_field_t *
68_zip_ef_delete_by_id(zip_extra_field_t *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags)
Dieter Baron3efab992012-05-04 09:29:29 +020069{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020070 zip_extra_field_t *head, *prev;
Dieter Baron3efab992012-05-04 09:29:29 +020071 int i;
72
73 i = 0;
74 head = ef;
75 prev = NULL;
76 for (; ef; ef=(prev ? prev->next : head)) {
Thomas Klausner17bf6d32013-07-31 16:29:24 +020077 if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) {
Dieter Baron3efab992012-05-04 09:29:29 +020078 if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {
79 ef->flags &= ~(flags & ZIP_EF_BOTH);
80 if ((ef->flags & ZIP_EF_BOTH) == 0) {
81 if (prev)
82 prev->next = ef->next;
83 else
84 head = ef->next;
85 ef->next = NULL;
86 _zip_ef_free(ef);
87
88 if (id_idx == ZIP_EXTRA_FIELD_ALL)
89 continue;
90 }
91 }
92
93 i++;
94 if (i > id_idx)
95 break;
96 }
97 prev = ef;
98 }
99
100 return head;
101}
102
103
Dieter Baron3efab992012-05-04 09:29:29 +0200104
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200105void
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200106_zip_ef_free(zip_extra_field_t *ef)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200107{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200108 zip_extra_field_t *ef2;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200109
110 while (ef) {
111 ef2 = ef->next;
112 free(ef->data);
113 free(ef);
114 ef = ef2;
115 }
116}
117
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200118
119const zip_uint8_t *
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200120_zip_ef_get_by_id(const zip_extra_field_t *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, zip_error_t *error)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200121{
Dieter Baron837f5ce2013-03-14 12:21:04 +0100122 static const zip_uint8_t empty[1] = { '\0' };
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200123
124 int i;
125
126 i = 0;
127 for (; ef; ef=ef->next) {
128 if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) {
129 if (i < id_idx) {
130 i++;
131 continue;
132 }
133
134 if (lenp)
135 *lenp = ef->size;
136 if (ef->size > 0)
137 return ef->data;
138 else
139 return empty;
140 }
141 }
142
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200143 zip_error_set(error, ZIP_ER_NOENT, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200144 return NULL;
145}
146
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200147
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200148zip_extra_field_t *
149_zip_ef_merge(zip_extra_field_t *to, zip_extra_field_t *from)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200150{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200151 zip_extra_field_t *ef2, *tt, *tail;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200152 int duplicate;
153
154 if (to == NULL)
155 return from;
156
157 for (tail=to; tail->next; tail=tail->next)
158 ;
159
160 for (; from; from=ef2) {
161 ef2 = from->next;
162
163 duplicate = 0;
164 for (tt=to; tt; tt=tt->next) {
165 if (tt->id == from->id && tt->size == from->size && memcmp(tt->data, from->data, tt->size) == 0) {
166 tt->flags |= (from->flags & ZIP_EF_BOTH);
167 duplicate = 1;
168 break;
169 }
170 }
171
172 from->next = NULL;
173 if (duplicate)
174 _zip_ef_free(from);
175 else
176 tail = tail->next = from;
177 }
178
179 return to;
180}
181
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200182
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200183zip_extra_field_t *
Dieter Baron3efab992012-05-04 09:29:29 +0200184_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200185{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200186 zip_extra_field_t *ef;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200187
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200188 if ((ef=(zip_extra_field_t *)malloc(sizeof(*ef))) == NULL)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200189 return NULL;
190
191 ef->next = NULL;
192 ef->flags = flags;
193 ef->id = id;
194 ef->size = size;
195 if (size > 0) {
Thomas Klausner84c2c082013-03-17 22:20:14 +0100196 if ((ef->data=(zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200197 free(ef);
198 return NULL;
199 }
200 }
201 else
202 ef->data = NULL;
203
204 return ef;
205}
206
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200207
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100208bool
209_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)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200210{
Dieter Baronee25b7d2014-10-11 18:30:13 +0200211 zip_buffer_t *buffer;
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200212 zip_extra_field_t *ef, *ef2, *ef_head;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200213
Dieter Baronee25b7d2014-10-11 18:30:13 +0200214 if ((buffer = _zip_buffer_new((zip_uint8_t *)data, len)) == NULL) {
215 zip_error_set(error, ZIP_ER_MEMORY, 0);
Thomas Klausner8b3895f2016-02-06 09:06:06 +0100216 return false;
Dieter Baronee25b7d2014-10-11 18:30:13 +0200217 }
218
Thomas Klausnerd683c122014-03-10 16:13:59 +0100219 ef_head = ef = NULL;
Dieter Baronee25b7d2014-10-11 18:30:13 +0200220
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100221 while (_zip_buffer_ok(buffer) && _zip_buffer_left(buffer) >= 4) {
Dieter Baronee25b7d2014-10-11 18:30:13 +0200222 zip_uint16_t fid, flen;
223 zip_uint8_t *ef_data;
224
225 fid = _zip_buffer_get_16(buffer);
226 flen = _zip_buffer_get_16(buffer);
227 ef_data = _zip_buffer_get(buffer, flen);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200228
Dieter Baronee25b7d2014-10-11 18:30:13 +0200229 if (ef_data == NULL) {
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100230 zip_error_set(error, ZIP_ER_INCONS, 0);
231 _zip_buffer_free(buffer);
232 _zip_ef_free(ef_head);
233 return false;
Dieter Baronee25b7d2014-10-11 18:30:13 +0200234 }
235
236 if ((ef2=_zip_ef_new(fid, flen, ef_data, flags)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200237 zip_error_set(error, ZIP_ER_MEMORY, 0);
Dieter Baronee25b7d2014-10-11 18:30:13 +0200238 _zip_buffer_free(buffer);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200239 _zip_ef_free(ef_head);
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100240 return false;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200241 }
242
243 if (ef_head) {
244 ef->next = ef2;
245 ef = ef2;
246 }
247 else
248 ef_head = ef = ef2;
249 }
250
Dieter Baronee25b7d2014-10-11 18:30:13 +0200251 if (!_zip_buffer_eof(buffer)) {
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100252 /* Android APK files align stored file data with padding in extra fields; ignore. */
253 /* see https://android.googlesource.com/platform/build/+/master/tools/zipalign/ZipAlign.cpp */
254 size_t glen = _zip_buffer_left(buffer);
255 zip_uint8_t *garbage;
Dieter Baron0ed64952016-01-21 10:23:44 +0100256 garbage = _zip_buffer_get(buffer, glen);
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100257 if (glen >= 4 || garbage == NULL || memcmp(garbage, "\0\0\0", glen) != 0) {
258 zip_error_set(error, ZIP_ER_INCONS, 0);
259 _zip_buffer_free(buffer);
260 _zip_ef_free(ef_head);
261 return false;
262 }
Dieter Baronee25b7d2014-10-11 18:30:13 +0200263 }
264
265 _zip_buffer_free(buffer);
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100266
267 if (ef_head_p) {
268 *ef_head_p = ef_head;
269 }
Dieter Baron42df64a2016-01-21 10:02:46 +0100270 else {
271 _zip_ef_free(ef_head);
272 }
Dieter Baronee25b7d2014-10-11 18:30:13 +0200273
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100274 return true;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200275}
276
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200277
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200278zip_extra_field_t *
279_zip_ef_remove_internal(zip_extra_field_t *ef)
Dieter Baronc332cc72012-10-13 18:32:44 +0200280{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200281 zip_extra_field_t *ef_head;
282 zip_extra_field_t *prev, *next;
Dieter Baronc332cc72012-10-13 18:32:44 +0200283
Dieter Baron837f5ce2013-03-14 12:21:04 +0100284 ef_head = ef;
Dieter Baron7f433be2012-10-13 18:55:35 +0200285 prev = NULL;
Dieter Baronc332cc72012-10-13 18:32:44 +0200286
287 while (ef) {
288 if (ZIP_EF_IS_INTERNAL(ef->id)) {
289 next = ef->next;
290 if (ef_head == ef)
291 ef_head = next;
292 ef->next = NULL;
293 _zip_ef_free(ef);
294 if (prev)
295 prev->next = next;
296 ef = next;
297 }
298 else {
299 prev = ef;
300 ef = ef->next;
301 }
302 }
303
304 return ef_head;
305}
306
307
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200308zip_uint16_t
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200309_zip_ef_size(const zip_extra_field_t *ef, zip_flags_t flags)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200310{
311 zip_uint16_t size;
312
313 size = 0;
314 for (; ef; ef=ef->next) {
315 if (ef->flags & flags & ZIP_EF_BOTH)
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200316 size = (zip_uint16_t)(size+4+ef->size);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200317 }
318
319 return size;
320}
321
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200322
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200323int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200324_zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200325{
Dieter Baronee25b7d2014-10-11 18:30:13 +0200326 zip_uint8_t b[4];
327 zip_buffer_t *buffer = _zip_buffer_new(b, sizeof(b));
Thomas Klausneraf5e63b2015-04-22 21:25:06 +0200328
329 if (buffer == NULL) {
330 return -1;
331 }
332
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200333 for (; ef; ef=ef->next) {
334 if (ef->flags & flags & ZIP_EF_BOTH) {
Dieter Baronee25b7d2014-10-11 18:30:13 +0200335 _zip_buffer_set_offset(buffer, 0);
336 _zip_buffer_put_16(buffer, ef->id);
337 _zip_buffer_put_16(buffer, ef->size);
338 if (!_zip_buffer_ok(buffer)) {
339 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
340 _zip_buffer_free(buffer);
341 return -1;
342 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200343 if (_zip_write(za, b, 4) < 0) {
Dieter Baronee25b7d2014-10-11 18:30:13 +0200344 _zip_buffer_free(buffer);
345 return -1;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200346 }
347 if (ef->size > 0) {
348 if (_zip_write(za, ef->data, ef->size) < 0) {
Dieter Baronee25b7d2014-10-11 18:30:13 +0200349 _zip_buffer_free(buffer);
350 return -1;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200351 }
352 }
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200353 }
354 }
Dieter Baronee25b7d2014-10-11 18:30:13 +0200355
356 _zip_buffer_free(buffer);
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200357 return 0;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200358}
359
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200360
361int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200362_zip_read_local_ef(zip_t *za, zip_uint64_t idx)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200363{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200364 zip_entry_t *e;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200365 unsigned char b[4];
Dieter Baronee25b7d2014-10-11 18:30:13 +0200366 zip_buffer_t *buffer;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200367 zip_uint16_t fname_len, ef_len;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200368
369 if (idx >= za->nentry) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200370 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200371 return -1;
372 }
373
374 e = za->entry+idx;
375
376 if (e->orig == NULL || e->orig->local_extra_fields_read)
377 return 0;
378
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200379 if (e->orig->offset + 26 > ZIP_INT64_MAX) {
380 zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG);
381 return -1;
382 }
Dieter Baronabc6fd72012-07-22 15:49:45 +0200383
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200384 if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) {
Thomas Klausnerd97f5442014-09-23 17:02:03 +0200385 _zip_error_set_from_source(&za->error, za->src);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200386 return -1;
387 }
Dieter Baronee25b7d2014-10-11 18:30:13 +0200388
389 if ((buffer = _zip_buffer_new_from_source(za->src, sizeof(b), b, &za->error)) == NULL) {
390 return -1;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200391 }
Dieter Baronee25b7d2014-10-11 18:30:13 +0200392
393 fname_len = _zip_buffer_get_16(buffer);
394 ef_len = _zip_buffer_get_16(buffer);
395
396 if (!_zip_buffer_eof(buffer)) {
397 _zip_buffer_free(buffer);
398 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
399 return -1;
400 }
401
402 _zip_buffer_free(buffer);
403
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200404 if (ef_len > 0) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200405 zip_extra_field_t *ef;
Thomas Klausner92447052013-03-20 00:34:05 +0100406 zip_uint8_t *ef_raw;
407
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200408 if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) {
409 zip_error_set(&za->error, ZIP_ER_SEEK, errno);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200410 return -1;
411 }
412
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200413 ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200414
415 if (ef_raw == NULL)
416 return -1;
417
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100418 if (!_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &ef, &za->error)) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200419 free(ef_raw);
420 return -1;
421 }
422 free(ef_raw);
Thomas Klausnerdc5ea3f2016-01-19 13:27:40 +0100423
424 if (ef) {
425 ef = _zip_ef_remove_internal(ef);
426 e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
427 }
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200428 }
429
430 e->orig->local_extra_fields_read = 1;
431
432 if (e->changes && e->changes->local_extra_fields_read == 0) {
433 e->changes->extra_fields = e->orig->extra_fields;
434 e->changes->local_extra_fields_read = 1;
435 }
436
437 return 0;
438}