blob: 482703e32c5f4b56c5649c8d9db71ebd1045173a [file] [log] [blame]
Dieter Baron0e5eeab2012-04-24 18:47:12 +02001/*
2 zip_extra_field.c -- manipulate extra fields
Thomas Klausnerea8ba492014-09-23 16:54:47 +02003 Copyright (C) 2012-2014 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
35#include "zipint.h"
36
37#include <errno.h>
38#include <stdlib.h>
39#include <string.h>
40
Dieter Baron0e5eeab2012-04-24 18:47:12 +020041
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020042zip_extra_field_t *
43_zip_ef_clone(const zip_extra_field_t *ef, zip_error_t *error)
Dieter Baron6fad8b62012-10-12 15:18:04 +020044{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020045 zip_extra_field_t *head, *prev, *def;
Dieter Baron6fad8b62012-10-12 15:18:04 +020046
47 head = prev = NULL;
48
49 while (ef) {
50 if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020051 zip_error_set(error, ZIP_ER_MEMORY, 0);
Dieter Baron6fad8b62012-10-12 15:18:04 +020052 _zip_ef_free(head);
53 return NULL;
54 }
55
56 if (head == NULL)
57 head = def;
58 if (prev)
59 prev->next = def;
60 prev = def;
Thomas Klausner95d6fdf2013-02-20 11:47:10 +010061
62 ef = ef->next;
Dieter Baron6fad8b62012-10-12 15:18:04 +020063 }
64
65 return head;
66}
67
68
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020069zip_extra_field_t *
70_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 +020071{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020072 zip_extra_field_t *head, *prev;
Dieter Baron3efab992012-05-04 09:29:29 +020073 int i;
74
75 i = 0;
76 head = ef;
77 prev = NULL;
78 for (; ef; ef=(prev ? prev->next : head)) {
Thomas Klausner17bf6d32013-07-31 16:29:24 +020079 if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) {
Dieter Baron3efab992012-05-04 09:29:29 +020080 if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {
81 ef->flags &= ~(flags & ZIP_EF_BOTH);
82 if ((ef->flags & ZIP_EF_BOTH) == 0) {
83 if (prev)
84 prev->next = ef->next;
85 else
86 head = ef->next;
87 ef->next = NULL;
88 _zip_ef_free(ef);
89
90 if (id_idx == ZIP_EXTRA_FIELD_ALL)
91 continue;
92 }
93 }
94
95 i++;
96 if (i > id_idx)
97 break;
98 }
99 prev = ef;
100 }
101
102 return head;
103}
104
105
Dieter Baron3efab992012-05-04 09:29:29 +0200106
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200107void
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200108_zip_ef_free(zip_extra_field_t *ef)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200109{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200110 zip_extra_field_t *ef2;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200111
112 while (ef) {
113 ef2 = ef->next;
114 free(ef->data);
115 free(ef);
116 ef = ef2;
117 }
118}
119
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200120
121const zip_uint8_t *
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200122_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 +0200123{
Dieter Baron837f5ce2013-03-14 12:21:04 +0100124 static const zip_uint8_t empty[1] = { '\0' };
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200125
126 int i;
127
128 i = 0;
129 for (; ef; ef=ef->next) {
130 if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) {
131 if (i < id_idx) {
132 i++;
133 continue;
134 }
135
136 if (lenp)
137 *lenp = ef->size;
138 if (ef->size > 0)
139 return ef->data;
140 else
141 return empty;
142 }
143 }
144
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200145 zip_error_set(error, ZIP_ER_NOENT, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200146 return NULL;
147}
148
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200149
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200150zip_extra_field_t *
151_zip_ef_merge(zip_extra_field_t *to, zip_extra_field_t *from)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200152{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200153 zip_extra_field_t *ef2, *tt, *tail;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200154 int duplicate;
155
156 if (to == NULL)
157 return from;
158
159 for (tail=to; tail->next; tail=tail->next)
160 ;
161
162 for (; from; from=ef2) {
163 ef2 = from->next;
164
165 duplicate = 0;
166 for (tt=to; tt; tt=tt->next) {
167 if (tt->id == from->id && tt->size == from->size && memcmp(tt->data, from->data, tt->size) == 0) {
168 tt->flags |= (from->flags & ZIP_EF_BOTH);
169 duplicate = 1;
170 break;
171 }
172 }
173
174 from->next = NULL;
175 if (duplicate)
176 _zip_ef_free(from);
177 else
178 tail = tail->next = from;
179 }
180
181 return to;
182}
183
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200184
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200185zip_extra_field_t *
Dieter Baron3efab992012-05-04 09:29:29 +0200186_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 +0200187{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200188 zip_extra_field_t *ef;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200189
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200190 if ((ef=(zip_extra_field_t *)malloc(sizeof(*ef))) == NULL)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200191 return NULL;
192
193 ef->next = NULL;
194 ef->flags = flags;
195 ef->id = id;
196 ef->size = size;
197 if (size > 0) {
Thomas Klausner84c2c082013-03-17 22:20:14 +0100198 if ((ef->data=(zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200199 free(ef);
200 return NULL;
201 }
202 }
203 else
204 ef->data = NULL;
205
206 return ef;
207}
208
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200209
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200210zip_extra_field_t *
211_zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, zip_error_t *error)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200212{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200213 zip_extra_field_t *ef, *ef2, *ef_head;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200214 const zip_uint8_t *p;
215 zip_uint16_t fid, flen;
216
Thomas Klausnerd683c122014-03-10 16:13:59 +0100217 ef_head = ef = NULL;
Dieter Baronabc6fd72012-07-22 15:49:45 +0200218 for (p=data; p<data+len; p+=flen) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200219 if (p+4 > data+len) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200220 zip_error_set(error, ZIP_ER_INCONS, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200221 _zip_ef_free(ef_head);
222 return NULL;
223 }
224
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200225 fid = _zip_get_16(&p);
226 flen = _zip_get_16(&p);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200227
Dieter Baronabc6fd72012-07-22 15:49:45 +0200228 if (p+flen > data+len) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200229 zip_error_set(error, ZIP_ER_INCONS, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200230 _zip_ef_free(ef_head);
231 return NULL;
232 }
233
Dieter Baronabc6fd72012-07-22 15:49:45 +0200234 if ((ef2=_zip_ef_new(fid, flen, p, flags)) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200235 zip_error_set(error, ZIP_ER_MEMORY, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200236 _zip_ef_free(ef_head);
237 return NULL;
238 }
239
240 if (ef_head) {
241 ef->next = ef2;
242 ef = ef2;
243 }
244 else
245 ef_head = ef = ef2;
246 }
247
248 return ef_head;
249}
250
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200251
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200252zip_extra_field_t *
253_zip_ef_remove_internal(zip_extra_field_t *ef)
Dieter Baronc332cc72012-10-13 18:32:44 +0200254{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200255 zip_extra_field_t *ef_head;
256 zip_extra_field_t *prev, *next;
Dieter Baronc332cc72012-10-13 18:32:44 +0200257
Dieter Baron837f5ce2013-03-14 12:21:04 +0100258 ef_head = ef;
Dieter Baron7f433be2012-10-13 18:55:35 +0200259 prev = NULL;
Dieter Baronc332cc72012-10-13 18:32:44 +0200260
261 while (ef) {
262 if (ZIP_EF_IS_INTERNAL(ef->id)) {
263 next = ef->next;
264 if (ef_head == ef)
265 ef_head = next;
266 ef->next = NULL;
267 _zip_ef_free(ef);
268 if (prev)
269 prev->next = next;
270 ef = next;
271 }
272 else {
273 prev = ef;
274 ef = ef->next;
275 }
276 }
277
278 return ef_head;
279}
280
281
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200282zip_uint16_t
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200283_zip_ef_size(const zip_extra_field_t *ef, zip_flags_t flags)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200284{
285 zip_uint16_t size;
286
287 size = 0;
288 for (; ef; ef=ef->next) {
289 if (ef->flags & flags & ZIP_EF_BOTH)
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200290 size = (zip_uint16_t)(size+4+ef->size);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200291 }
292
293 return size;
294}
295
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200296
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200297int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200298_zip_ef_write(zip_t *za, const zip_extra_field_t *ef, zip_flags_t flags)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200299{
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200300 zip_uint8_t b[4], *p;
301
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200302 for (; ef; ef=ef->next) {
303 if (ef->flags & flags & ZIP_EF_BOTH) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200304 p = b;
305 _zip_put_16(&p, ef->id);
306 _zip_put_16(&p, ef->size);
307 if (_zip_write(za, b, 4) < 0) {
308 return -1;
309 }
310 if (ef->size > 0) {
311 if (_zip_write(za, ef->data, ef->size) < 0) {
312 return -1;
313 }
314 }
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200315 }
316 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200317 return 0;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200318}
319
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200320
321int
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200322_zip_read_local_ef(zip_t *za, zip_uint64_t idx)
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200323{
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200324 zip_entry_t *e;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200325 unsigned char b[4];
326 const unsigned char *p;
327 zip_uint16_t fname_len, ef_len;
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200328
329 if (idx >= za->nentry) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200330 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200331 return -1;
332 }
333
334 e = za->entry+idx;
335
336 if (e->orig == NULL || e->orig->local_extra_fields_read)
337 return 0;
338
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200339 if (e->orig->offset + 26 > ZIP_INT64_MAX) {
340 zip_error_set(&za->error, ZIP_ER_SEEK, EFBIG);
341 return -1;
342 }
Dieter Baronabc6fd72012-07-22 15:49:45 +0200343
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200344 if (zip_source_seek(za->src, (zip_int64_t)(e->orig->offset + 26), SEEK_SET) < 0) {
Thomas Klausnerd97f5442014-09-23 17:02:03 +0200345 _zip_error_set_from_source(&za->error, za->src);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200346 return -1;
347 }
348
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200349 if (_zip_read(za->src, b, sizeof(b), &za->error) < 0) {
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200350 return -1;
351 }
352
353 p = b;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200354 fname_len = _zip_get_16(&p);
355 ef_len = _zip_get_16(&p);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200356
357 if (ef_len > 0) {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200358 zip_extra_field_t *ef;
Thomas Klausner92447052013-03-20 00:34:05 +0100359 zip_uint8_t *ef_raw;
360
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200361 if (zip_source_seek(za->src, fname_len, SEEK_CUR) < 0) {
362 zip_error_set(&za->error, ZIP_ER_SEEK, errno);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200363 return -1;
364 }
365
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200366 ef_raw = _zip_read_data(NULL, za->src, ef_len, 0, &za->error);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200367
368 if (ef_raw == NULL)
369 return -1;
370
371 if ((ef=_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &za->error)) == NULL) {
372 free(ef_raw);
373 return -1;
374 }
375 free(ef_raw);
376
Dieter Baronc332cc72012-10-13 18:32:44 +0200377 ef = _zip_ef_remove_internal(ef);
Dieter Baron0e5eeab2012-04-24 18:47:12 +0200378 e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
379 }
380
381 e->orig->local_extra_fields_read = 1;
382
383 if (e->changes && e->changes->local_extra_fields_read == 0) {
384 e->changes->extra_fields = e->orig->extra_fields;
385 e->changes->local_extra_fields_read = 1;
386 }
387
388 return 0;
389}