xref: /PHP-5.6/ext/zip/lib/zip_extra_field_api.c (revision 0579e827)
1 /*
2   zip_extra_field_api.c -- public extra fields API functions
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 
39 
40 ZIP_EXTERN int
zip_file_extra_field_delete(struct zip * za,zip_uint64_t idx,zip_uint16_t ef_idx,zip_flags_t flags)41 zip_file_extra_field_delete(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags)
42 {
43     struct zip_dirent *de;
44 
45     if ((flags & ZIP_EF_BOTH) == 0) {
46 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
47 	return -1;
48     }
49 
50     if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) {
51 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
52 	return -1;
53     }
54 
55     if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
56 	return -1;
57 
58     if (ZIP_IS_RDONLY(za)) {
59 	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
60 	return -1;
61     }
62 
63     if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)
64         return -1;
65 
66     de = za->entry[idx].changes;
67 
68     de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags);
69     return 0;
70 }
71 
72 
73 
74 ZIP_EXTERN int
zip_file_extra_field_delete_by_id(struct zip * za,zip_uint64_t idx,zip_uint16_t ef_id,zip_uint16_t ef_idx,zip_flags_t flags)75 zip_file_extra_field_delete_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags)
76 {
77     struct zip_dirent *de;
78 
79     if ((flags & ZIP_EF_BOTH) == 0) {
80 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
81 	return -1;
82     }
83 
84     if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) {
85 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
86 	return -1;
87     }
88 
89     if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
90 	return -1;
91 
92     if (ZIP_IS_RDONLY(za)) {
93 	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
94 	return -1;
95     }
96 
97     if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)
98         return -1;
99 
100     de = za->entry[idx].changes;
101 
102     de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags);
103     return 0;
104 }
105 
106 
107 
108 ZIP_EXTERN const zip_uint8_t *
zip_file_extra_field_get(struct zip * za,zip_uint64_t idx,zip_uint16_t ef_idx,zip_uint16_t * idp,zip_uint16_t * lenp,zip_flags_t flags)109 zip_file_extra_field_get(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp, zip_flags_t flags)
110 {
111     static const zip_uint8_t empty[1] = { '\0' };
112 
113     struct zip_dirent *de;
114     struct zip_extra_field *ef;
115     int i;
116 
117     if ((flags & ZIP_EF_BOTH) == 0) {
118 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
119 	return NULL;
120     }
121 
122     if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
123 	return NULL;
124 
125     if (flags & ZIP_FL_LOCAL)
126 	if (_zip_read_local_ef(za, idx) < 0)
127 	    return NULL;
128 
129     i = 0;
130     for (ef=de->extra_fields; ef; ef=ef->next) {
131 	if (ef->flags & flags & ZIP_EF_BOTH) {
132 	    if (i < ef_idx) {
133 		i++;
134 		continue;
135 	    }
136 
137 	    if (idp)
138 		*idp = ef->id;
139 	    if (lenp)
140 		*lenp = ef->size;
141 	    if (ef->size > 0)
142 		return ef->data;
143 	    else
144 		return empty;
145 	}
146     }
147 
148     _zip_error_set(&za->error, ZIP_ER_NOENT, 0);
149     return NULL;
150 
151 }
152 
153 
154 
155 ZIP_EXTERN const zip_uint8_t *
zip_file_extra_field_get_by_id(struct zip * za,zip_uint64_t idx,zip_uint16_t ef_id,zip_uint16_t ef_idx,zip_uint16_t * lenp,zip_flags_t flags)156 zip_file_extra_field_get_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp, zip_flags_t flags)
157 {
158     struct zip_dirent *de;
159 
160     if ((flags & ZIP_EF_BOTH) == 0) {
161 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
162 	return NULL;
163     }
164 
165     if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
166 	return NULL;
167 
168     if (flags & ZIP_FL_LOCAL)
169 	if (_zip_read_local_ef(za, idx) < 0)
170 	    return NULL;
171 
172     return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error);
173 }
174 
175 
176 
177 ZIP_EXTERN zip_int16_t
zip_file_extra_fields_count(struct zip * za,zip_uint64_t idx,zip_flags_t flags)178 zip_file_extra_fields_count(struct zip *za, zip_uint64_t idx, zip_flags_t flags)
179 {
180     struct zip_dirent *de;
181     struct zip_extra_field *ef;
182     zip_uint16_t n;
183 
184     if ((flags & ZIP_EF_BOTH) == 0) {
185 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
186 	return -1;
187     }
188 
189     if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
190 	return -1;
191 
192     if (flags & ZIP_FL_LOCAL)
193 	if (_zip_read_local_ef(za, idx) < 0)
194 	    return -1;
195 
196     n = 0;
197     for (ef=de->extra_fields; ef; ef=ef->next)
198 	if (ef->flags & flags & ZIP_EF_BOTH)
199 	    n++;
200 
201     return (zip_int16_t)n;
202 }
203 
204 
205 
206 ZIP_EXTERN zip_int16_t
zip_file_extra_fields_count_by_id(struct zip * za,zip_uint64_t idx,zip_uint16_t ef_id,zip_flags_t flags)207 zip_file_extra_fields_count_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_flags_t flags)
208 {
209     struct zip_dirent *de;
210     struct zip_extra_field *ef;
211     zip_uint16_t n;
212 
213     if ((flags & ZIP_EF_BOTH) == 0) {
214 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
215 	return -1;
216     }
217 
218     if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
219 	return -1;
220 
221     if (flags & ZIP_FL_LOCAL)
222 	if (_zip_read_local_ef(za, idx) < 0)
223 	    return -1;
224 
225     n = 0;
226     for (ef=de->extra_fields; ef; ef=ef->next)
227 	if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH))
228 	    n++;
229 
230     return (zip_int16_t)n;
231 }
232 
233 
234 
235 ZIP_EXTERN int
zip_file_extra_field_set(struct zip * za,zip_uint64_t idx,zip_uint16_t ef_id,zip_uint16_t ef_idx,const zip_uint8_t * data,zip_uint16_t len,zip_flags_t flags)236 zip_file_extra_field_set(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags)
237 {
238     struct zip_dirent *de;
239     zip_uint16_t ls, cs;
240     struct zip_extra_field *ef, *ef_prev, *ef_new;
241     int i, found, new_len;
242 
243     if ((flags & ZIP_EF_BOTH) == 0) {
244 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
245 	return -1;
246     }
247 
248     if (_zip_get_dirent(za, idx, 0, NULL) == NULL)
249 	return -1;
250 
251     if (ZIP_IS_RDONLY(za)) {
252 	_zip_error_set(&za->error, ZIP_ER_RDONLY, 0);
253 	return -1;
254     }
255 
256     if (ZIP_EF_IS_INTERNAL(ef_id)) {
257 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
258 	return -1;
259     }
260 
261     if (_zip_file_extra_field_prepare_for_change(za, idx) < 0)
262         return -1;
263 
264     de = za->entry[idx].changes;
265 
266     ef = de->extra_fields;
267     ef_prev = NULL;
268     i = 0;
269     found = 0;
270 
271     for (; ef; ef=ef->next) {
272 	if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) {
273 	    if (i == ef_idx) {
274 		found = 1;
275 		break;
276 	    }
277 	    i++;
278 	}
279 	ef_prev = ef;
280     }
281 
282     if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) {
283 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
284 	return -1;
285     }
286 
287     if (flags & ZIP_EF_LOCAL)
288 	ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL);
289     else
290 	ls = 0;
291     if (flags & ZIP_EF_CENTRAL)
292 	cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL);
293     else
294 	cs = 0;
295 
296     new_len = ls > cs ? ls : cs;
297     if (found)
298 	new_len -= ef->size + 4;
299     new_len += len + 4;
300 
301     if (new_len > ZIP_UINT16_MAX) {
302 	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
303 	return -1;
304     }
305 
306     if ((ef_new=_zip_ef_new(ef_id, len, data, flags)) == NULL) {
307 	_zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
308 	return -1;
309     }
310 
311     if (found) {
312 	if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) {
313 	    ef_new->next = ef->next;
314 	    ef->next = NULL;
315 	    _zip_ef_free(ef);
316 	    if (ef_prev)
317 		ef_prev->next = ef_new;
318 	    else
319 		de->extra_fields = ef_new;
320 	}
321 	else {
322 	    ef->flags &= ~(flags & ZIP_EF_BOTH);
323 	    ef_new->next = ef->next;
324 	    ef->next = ef_new;
325 	}
326     }
327     else if (ef_prev) {
328 	ef_new->next = ef_prev->next;
329 	ef_prev->next = ef_new;
330     }
331     else
332 	de->extra_fields = ef_new;
333 
334     return 0;
335 }
336 
337 
338 
339 int
_zip_file_extra_field_prepare_for_change(struct zip * za,zip_uint64_t idx)340 _zip_file_extra_field_prepare_for_change(struct zip *za, zip_uint64_t idx)
341 {
342     struct zip_entry *e;
343 
344     if (idx >= za->nentry) {
345         _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
346         return -1;
347     }
348 
349     e = za->entry+idx;
350 
351     if (e->changes && (e->changes->changed & ZIP_DIRENT_EXTRA_FIELD))
352         return 0;
353 
354     if (e->orig) {
355 	if (_zip_read_local_ef(za, idx) < 0)
356 	    return -1;
357     }
358 
359     if (e->changes == NULL) {
360         if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) {
361             _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
362             return -1;
363         }
364     }
365 
366     if (e->orig && e->orig->extra_fields) {
367 	if ((e->changes->extra_fields=_zip_ef_clone(e->orig->extra_fields, &za->error)) == NULL)
368 	    return -1;
369     }
370     e->changes->changed |= ZIP_DIRENT_EXTRA_FIELD;
371 
372     return 0;
373 }
374 
375