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