4
|
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 |
|
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 |
|
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 * |
|
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 * |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |