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