xref: /PHP-5.6/ext/zip/lib/zip_extra_field.c (revision 0579e827)
1 /*
2   zip_extra_field.c -- manipulate extra fields
3   Copyright (C) 2012-2015 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 <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 
34 
35 
36 #include "zipint.h"
37 
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 
43 
44 struct zip_extra_field *
_zip_ef_clone(const struct zip_extra_field * ef,struct zip_error * error)45 _zip_ef_clone(const struct zip_extra_field *ef, struct zip_error *error)
46 {
47     struct zip_extra_field *head, *prev, *def;
48 
49     head = prev = NULL;
50 
51     while (ef) {
52         if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) {
53             _zip_error_set(error, ZIP_ER_MEMORY, 0);
54             _zip_ef_free(head);
55             return NULL;
56         }
57 
58         if (head == NULL)
59             head = def;
60         if (prev)
61             prev->next = def;
62         prev = def;
63 
64 	ef = ef->next;
65     }
66 
67     return head;
68 }
69 
70 
71 struct zip_extra_field *
_zip_ef_delete_by_id(struct zip_extra_field * ef,zip_uint16_t id,zip_uint16_t id_idx,zip_flags_t flags)72 _zip_ef_delete_by_id(struct zip_extra_field *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags)
73 {
74     struct zip_extra_field *head, *prev;
75     int i;
76 
77     i = 0;
78     head = ef;
79     prev = NULL;
80     for (; ef; ef=(prev ? prev->next : head)) {
81 	if ((ef->flags & flags & ZIP_EF_BOTH) && ((ef->id == id) || (id == ZIP_EXTRA_FIELD_ALL))) {
82 	    if (id_idx == ZIP_EXTRA_FIELD_ALL || i == id_idx) {
83 		ef->flags &= ~(flags & ZIP_EF_BOTH);
84 		if ((ef->flags & ZIP_EF_BOTH) == 0) {
85 		    if (prev)
86 			prev->next = ef->next;
87 		    else
88 			head = ef->next;
89 		    ef->next = NULL;
90 		    _zip_ef_free(ef);
91 
92 		    if (id_idx == ZIP_EXTRA_FIELD_ALL)
93 			continue;
94 		}
95 	    }
96 
97 	    i++;
98 	    if (i > id_idx)
99 		break;
100 	}
101 	prev = ef;
102     }
103 
104     return head;
105 }
106 
107 
108 
109 
110 void
_zip_ef_free(struct zip_extra_field * ef)111 _zip_ef_free(struct zip_extra_field *ef)
112 {
113     struct zip_extra_field *ef2;
114 
115     while (ef) {
116 	ef2 = ef->next;
117 	free(ef->data);
118 	free(ef);
119 	ef = ef2;
120     }
121 }
122 
123 
124 
125 const zip_uint8_t *
_zip_ef_get_by_id(const struct zip_extra_field * ef,zip_uint16_t * lenp,zip_uint16_t id,zip_uint16_t id_idx,zip_flags_t flags,struct zip_error * error)126 _zip_ef_get_by_id(const struct zip_extra_field *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags, struct zip_error *error)
127 {
128     static const zip_uint8_t empty[1] = { '\0' };
129 
130     int i;
131 
132     i = 0;
133     for (; ef; ef=ef->next) {
134 	if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) {
135 	    if (i < id_idx) {
136 		i++;
137 		continue;
138 	    }
139 
140 	    if (lenp)
141 		*lenp = ef->size;
142 	    if (ef->size > 0)
143 		return ef->data;
144 	    else
145 		return empty;
146 	}
147     }
148 
149     _zip_error_set(error, ZIP_ER_NOENT, 0);
150     return NULL;
151 }
152 
153 
154 
155 struct zip_extra_field *
_zip_ef_merge(struct zip_extra_field * to,struct zip_extra_field * from)156 _zip_ef_merge(struct zip_extra_field *to, struct zip_extra_field *from)
157 {
158     struct zip_extra_field *ef2, *tt, *tail;
159     int duplicate;
160 
161     if (to == NULL)
162 	return from;
163 
164     for (tail=to; tail->next; tail=tail->next)
165 	;
166 
167     for (; from; from=ef2) {
168 	ef2 = from->next;
169 
170 	duplicate = 0;
171 	for (tt=to; tt; tt=tt->next) {
172 	    if (tt->id == from->id && tt->size == from->size && memcmp(tt->data, from->data, tt->size) == 0) {
173 		tt->flags |= (from->flags & ZIP_EF_BOTH);
174 		duplicate = 1;
175 		break;
176 	    }
177 	}
178 
179 	from->next = NULL;
180 	if (duplicate)
181 	    _zip_ef_free(from);
182 	else
183 	    tail = tail->next = from;
184     }
185 
186     return to;
187 }
188 
189 
190 
191 struct zip_extra_field *
_zip_ef_new(zip_uint16_t id,zip_uint16_t size,const zip_uint8_t * data,zip_flags_t flags)192 _zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_flags_t flags)
193 {
194     struct zip_extra_field *ef;
195 
196     if ((ef=(struct zip_extra_field *)malloc(sizeof(*ef))) == NULL)
197 	return NULL;
198 
199     ef->next = NULL;
200     ef->flags = flags;
201     ef->id = id;
202     ef->size = size;
203     if (size > 0) {
204 	if ((ef->data=(zip_uint8_t *)_zip_memdup(data, size, NULL)) == NULL) {
205 	    free(ef);
206 	    return NULL;
207 	}
208     }
209     else
210 	ef->data = NULL;
211 
212     return ef;
213 }
214 
215 
216 
217 struct zip_extra_field *
_zip_ef_parse(const zip_uint8_t * data,zip_uint16_t len,zip_flags_t flags,struct zip_error * error)218 _zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags, struct zip_error *error)
219 {
220     struct zip_extra_field *ef, *ef2, *ef_head;
221     const zip_uint8_t *p;
222     zip_uint16_t fid, flen;
223 
224     ef_head = NULL;
225     for (p=data; p<data+len; p+=flen) {
226 	if (p+4 > data+len) {
227 	    _zip_error_set(error, ZIP_ER_INCONS, 0);
228 	    _zip_ef_free(ef_head);
229 	    return NULL;
230 	}
231 
232 	fid = _zip_read2(&p);
233 	flen = _zip_read2(&p);
234 
235 	if (p+flen > data+len) {
236 	    _zip_error_set(error, ZIP_ER_INCONS, 0);
237 	    _zip_ef_free(ef_head);
238 	    return NULL;
239 	}
240 
241 	if ((ef2=_zip_ef_new(fid, flen, p, flags)) == NULL) {
242 	    _zip_error_set(error, ZIP_ER_MEMORY, 0);
243 	    _zip_ef_free(ef_head);
244 	    return NULL;
245 	}
246 
247 	if (ef_head) {
248 	    ef->next = ef2;
249 	    ef = ef2;
250 	}
251 	else
252 	    ef_head = ef = ef2;
253     }
254 
255     return ef_head;
256 }
257 
258 
259 
260 struct zip_extra_field *
_zip_ef_remove_internal(struct zip_extra_field * ef)261 _zip_ef_remove_internal(struct zip_extra_field *ef)
262 {
263     struct zip_extra_field *ef_head;
264     struct zip_extra_field *prev, *next;
265 
266     ef_head = ef;
267     prev = NULL;
268 
269     while (ef) {
270         if (ZIP_EF_IS_INTERNAL(ef->id)) {
271             next = ef->next;
272             if (ef_head == ef)
273                 ef_head = next;
274             ef->next = NULL;
275             _zip_ef_free(ef);
276             if (prev)
277                 prev->next = next;
278             ef = next;
279         }
280         else {
281             prev = ef;
282             ef = ef->next;
283         }
284     }
285 
286     return ef_head;
287 }
288 
289 
290 zip_uint16_t
_zip_ef_size(const struct zip_extra_field * ef,zip_flags_t flags)291 _zip_ef_size(const struct zip_extra_field *ef, zip_flags_t flags)
292 {
293     zip_uint16_t size;
294 
295     size = 0;
296     for (; ef; ef=ef->next) {
297 	if (ef->flags & flags & ZIP_EF_BOTH)
298 	    size += 4+ef->size;
299     }
300 
301     return size;
302 }
303 
304 
305 
306 void
_zip_ef_write(const struct zip_extra_field * ef,zip_flags_t flags,FILE * f)307 _zip_ef_write(const struct zip_extra_field *ef, zip_flags_t flags, FILE *f)
308 {
309     for (; ef; ef=ef->next) {
310 	if (ef->flags & flags & ZIP_EF_BOTH) {
311 	    _zip_write2(ef->id, f);
312 	    _zip_write2(ef->size, f);
313 	    if (ef->size > 0)
314 		fwrite(ef->data, ef->size, 1, f);
315 	}
316     }
317 }
318 
319 
320 
321 int
_zip_read_local_ef(struct zip * za,zip_uint64_t idx)322 _zip_read_local_ef(struct zip *za, zip_uint64_t idx)
323 {
324     struct zip_entry *e;
325     unsigned char b[4];
326     const unsigned char *p;
327     zip_uint16_t fname_len, ef_len;
328 
329     if (idx >= za->nentry) {
330 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
331 	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 
339 
340     if (fseeko(za->zp, (off_t)(e->orig->offset + 26), SEEK_SET) < 0) {
341 	_zip_error_set(&za->error, ZIP_ER_SEEK, errno);
342 	return -1;
343     }
344 
345     if (fread(b, sizeof(b), 1, za->zp) != 1) {
346 	_zip_error_set(&za->error, ZIP_ER_READ, errno);
347 	return -1;
348     }
349 
350     p = b;
351     fname_len = _zip_read2(&p);
352     ef_len = _zip_read2(&p);
353 
354     if (ef_len > 0) {
355 	struct zip_extra_field *ef;
356 	zip_uint8_t *ef_raw;
357 
358 	if (fseek(za->zp, fname_len, SEEK_CUR) < 0) {
359 	    _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
360 	    return -1;
361 	}
362 
363 	ef_raw = _zip_read_data(NULL, za->zp, ef_len, 0, &za->error);
364 
365 	if (ef_raw == NULL)
366 	    return -1;
367 
368 	if ((ef=_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &za->error)) == NULL) {
369 	    free(ef_raw);
370 	    return -1;
371 	}
372 	free(ef_raw);
373 
374         ef = _zip_ef_remove_internal(ef);
375 	e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef);
376     }
377 
378     e->orig->local_extra_fields_read = 1;
379 
380     if (e->changes && e->changes->local_extra_fields_read == 0) {
381 	e->changes->extra_fields = e->orig->extra_fields;
382 	e->changes->local_extra_fields_read = 1;
383     }
384 
385     return 0;
386 }
387