Mercurial > code
comparison modules/zip/libzip/lib/zip_dirent.c @ 527:8f8c32f102f1
Zip: resurrection
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 01 Jun 2016 17:36:52 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
526:b26d8be94adb | 527:8f8c32f102f1 |
---|---|
1 /* | |
2 zip_dirent.c -- read directory entry (local or central), clean dirent | |
3 Copyright (C) 1999-2016 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 <stdio.h> | |
36 #include <stdlib.h> | |
37 #include <string.h> | |
38 #include <sys/types.h> | |
39 #include <sys/stat.h> | |
40 | |
41 #include "zipint.h" | |
42 | |
43 static time_t _zip_d2u_time(zip_uint16_t, zip_uint16_t); | |
44 static zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str); | |
45 static zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *); | |
46 | |
47 | |
48 void | |
49 _zip_cdir_free(zip_cdir_t *cd) | |
50 { | |
51 zip_uint64_t i; | |
52 | |
53 if (!cd) | |
54 return; | |
55 | |
56 for (i=0; i<cd->nentry; i++) | |
57 _zip_entry_finalize(cd->entry+i); | |
58 free(cd->entry); | |
59 _zip_string_free(cd->comment); | |
60 free(cd); | |
61 } | |
62 | |
63 | |
64 zip_cdir_t * | |
65 _zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) | |
66 { | |
67 zip_cdir_t *cd; | |
68 zip_uint64_t i; | |
69 | |
70 if ((cd=(zip_cdir_t *)malloc(sizeof(*cd))) == NULL) { | |
71 zip_error_set(error, ZIP_ER_MEMORY, 0); | |
72 return NULL; | |
73 } | |
74 | |
75 if (nentry == 0) | |
76 cd->entry = NULL; | |
77 else if ((nentry > SIZE_MAX/sizeof(*(cd->entry))) || (cd->entry=(zip_entry_t *)malloc(sizeof(*(cd->entry))*(size_t)nentry)) == NULL) { | |
78 zip_error_set(error, ZIP_ER_MEMORY, 0); | |
79 free(cd); | |
80 return NULL; | |
81 } | |
82 | |
83 for (i=0; i<nentry; i++) | |
84 _zip_entry_init(cd->entry+i); | |
85 | |
86 cd->nentry = cd->nentry_alloc = nentry; | |
87 cd->size = cd->offset = 0; | |
88 cd->comment = NULL; | |
89 | |
90 return cd; | |
91 } | |
92 | |
93 | |
94 zip_int64_t | |
95 _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) | |
96 { | |
97 zip_uint64_t offset, size; | |
98 zip_string_t *comment; | |
99 zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN]; | |
100 zip_buffer_t *buffer; | |
101 zip_int64_t off; | |
102 zip_uint64_t i; | |
103 bool is_zip64; | |
104 int ret; | |
105 | |
106 if ((off = zip_source_tell_write(za->src)) < 0) { | |
107 _zip_error_set_from_source(&za->error, za->src); | |
108 return -1; | |
109 } | |
110 offset = (zip_uint64_t)off; | |
111 | |
112 is_zip64 = false; | |
113 | |
114 for (i=0; i<survivors; i++) { | |
115 zip_entry_t *entry = za->entry+filelist[i].idx; | |
116 | |
117 if ((ret=_zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL)) < 0) | |
118 return -1; | |
119 if (ret) | |
120 is_zip64 = true; | |
121 } | |
122 | |
123 if ((off = zip_source_tell_write(za->src)) < 0) { | |
124 _zip_error_set_from_source(&za->error, za->src); | |
125 return -1; | |
126 } | |
127 size = (zip_uint64_t)off - offset; | |
128 | |
129 if (offset > ZIP_UINT32_MAX || survivors > ZIP_UINT16_MAX) | |
130 is_zip64 = true; | |
131 | |
132 | |
133 if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { | |
134 zip_error_set(&za->error, ZIP_ER_MEMORY, 0); | |
135 return -1; | |
136 } | |
137 | |
138 if (is_zip64) { | |
139 _zip_buffer_put(buffer, EOCD64_MAGIC, 4); | |
140 _zip_buffer_put_64(buffer, EOCD64LEN-12); | |
141 _zip_buffer_put_16(buffer, 45); | |
142 _zip_buffer_put_16(buffer, 45); | |
143 _zip_buffer_put_32(buffer, 0); | |
144 _zip_buffer_put_32(buffer, 0); | |
145 _zip_buffer_put_64(buffer, survivors); | |
146 _zip_buffer_put_64(buffer, survivors); | |
147 _zip_buffer_put_64(buffer, size); | |
148 _zip_buffer_put_64(buffer, offset); | |
149 _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4); | |
150 _zip_buffer_put_32(buffer, 0); | |
151 _zip_buffer_put_64(buffer, offset+size); | |
152 _zip_buffer_put_32(buffer, 1); | |
153 } | |
154 | |
155 _zip_buffer_put(buffer, EOCD_MAGIC, 4); | |
156 _zip_buffer_put_32(buffer, 0); | |
157 _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); | |
158 _zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors)); | |
159 _zip_buffer_put_32(buffer, size >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)size); | |
160 _zip_buffer_put_32(buffer, offset >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)offset); | |
161 | |
162 comment = za->comment_changed ? za->comment_changes : za->comment_orig; | |
163 | |
164 _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0)); | |
165 | |
166 if (!_zip_buffer_ok(buffer)) { | |
167 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
168 _zip_buffer_free(buffer); | |
169 return -1; | |
170 } | |
171 | |
172 if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) { | |
173 _zip_buffer_free(buffer); | |
174 return -1; | |
175 } | |
176 | |
177 _zip_buffer_free(buffer); | |
178 | |
179 if (comment) { | |
180 if (_zip_write(za, comment->raw, comment->length) < 0) { | |
181 return -1; | |
182 } | |
183 } | |
184 | |
185 return (zip_int64_t)size; | |
186 } | |
187 | |
188 | |
189 zip_dirent_t * | |
190 _zip_dirent_clone(const zip_dirent_t *sde) | |
191 { | |
192 zip_dirent_t *tde; | |
193 | |
194 if ((tde=(zip_dirent_t *)malloc(sizeof(*tde))) == NULL) | |
195 return NULL; | |
196 | |
197 if (sde) | |
198 memcpy(tde, sde, sizeof(*sde)); | |
199 else | |
200 _zip_dirent_init(tde); | |
201 | |
202 tde->changed = 0; | |
203 tde->cloned = 1; | |
204 | |
205 return tde; | |
206 } | |
207 | |
208 | |
209 void | |
210 _zip_dirent_finalize(zip_dirent_t *zde) | |
211 { | |
212 if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) { | |
213 _zip_string_free(zde->filename); | |
214 zde->filename = NULL; | |
215 } | |
216 if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) { | |
217 _zip_ef_free(zde->extra_fields); | |
218 zde->extra_fields = NULL; | |
219 } | |
220 if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) { | |
221 _zip_string_free(zde->comment); | |
222 zde->comment = NULL; | |
223 } | |
224 } | |
225 | |
226 | |
227 void | |
228 _zip_dirent_free(zip_dirent_t *zde) | |
229 { | |
230 if (zde == NULL) | |
231 return; | |
232 | |
233 _zip_dirent_finalize(zde); | |
234 free(zde); | |
235 } | |
236 | |
237 | |
238 void | |
239 _zip_dirent_init(zip_dirent_t *de) | |
240 { | |
241 de->changed = 0; | |
242 de->local_extra_fields_read = 0; | |
243 de->cloned = 0; | |
244 | |
245 de->version_madeby = 20 | (ZIP_OPSYS_DEFAULT << 8); | |
246 de->version_needed = 20; /* 2.0 */ | |
247 de->bitflags = 0; | |
248 de->comp_method = ZIP_CM_DEFAULT; | |
249 de->last_mod = 0; | |
250 de->crc = 0; | |
251 de->comp_size = 0; | |
252 de->uncomp_size = 0; | |
253 de->filename = NULL; | |
254 de->extra_fields = NULL; | |
255 de->comment = NULL; | |
256 de->disk_number = 0; | |
257 de->int_attrib = 0; | |
258 de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT; | |
259 de->offset = 0; | |
260 } | |
261 | |
262 | |
263 bool | |
264 _zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) | |
265 { | |
266 if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX | |
267 || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX)) | |
268 return true; | |
269 | |
270 return false; | |
271 } | |
272 | |
273 | |
274 zip_dirent_t * | |
275 _zip_dirent_new(void) | |
276 { | |
277 zip_dirent_t *de; | |
278 | |
279 if ((de=(zip_dirent_t *)malloc(sizeof(*de))) == NULL) | |
280 return NULL; | |
281 | |
282 _zip_dirent_init(de); | |
283 return de; | |
284 } | |
285 | |
286 | |
287 /* _zip_dirent_read(zde, fp, bufp, left, localp, error): | |
288 Fills the zip directory entry zde. | |
289 | |
290 If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed. | |
291 | |
292 If local is true, it reads a local header instead of a central directory entry. | |
293 | |
294 Returns size of dirent read if successful. On error, error is filled in and -1 is returned. | |
295 */ | |
296 | |
297 zip_int64_t | |
298 _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error) | |
299 { | |
300 zip_uint8_t buf[CDENTRYSIZE]; | |
301 zip_uint16_t dostime, dosdate; | |
302 zip_uint32_t size, variable_size; | |
303 zip_uint16_t filename_len, comment_len, ef_len; | |
304 | |
305 bool from_buffer = (buffer != NULL); | |
306 | |
307 size = local ? LENTRYSIZE : CDENTRYSIZE; | |
308 | |
309 if (buffer) { | |
310 if (_zip_buffer_left(buffer) < size) { | |
311 zip_error_set(error, ZIP_ER_NOZIP, 0); | |
312 return -1; | |
313 } | |
314 } | |
315 else { | |
316 if ((buffer = _zip_buffer_new_from_source(src, size, buf, error)) == NULL) { | |
317 return -1; | |
318 } | |
319 } | |
320 | |
321 if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) { | |
322 zip_error_set(error, ZIP_ER_NOZIP, 0); | |
323 if (!from_buffer) { | |
324 _zip_buffer_free(buffer); | |
325 } | |
326 return -1; | |
327 } | |
328 | |
329 /* convert buffercontents to zip_dirent */ | |
330 | |
331 _zip_dirent_init(zde); | |
332 if (!local) | |
333 zde->version_madeby = _zip_buffer_get_16(buffer); | |
334 else | |
335 zde->version_madeby = 0; | |
336 zde->version_needed = _zip_buffer_get_16(buffer); | |
337 zde->bitflags = _zip_buffer_get_16(buffer); | |
338 zde->comp_method = _zip_buffer_get_16(buffer); | |
339 | |
340 /* convert to time_t */ | |
341 dostime = _zip_buffer_get_16(buffer); | |
342 dosdate = _zip_buffer_get_16(buffer); | |
343 zde->last_mod = _zip_d2u_time(dostime, dosdate); | |
344 | |
345 zde->crc = _zip_buffer_get_32(buffer); | |
346 zde->comp_size = _zip_buffer_get_32(buffer); | |
347 zde->uncomp_size = _zip_buffer_get_32(buffer); | |
348 | |
349 filename_len = _zip_buffer_get_16(buffer); | |
350 ef_len = _zip_buffer_get_16(buffer); | |
351 | |
352 if (local) { | |
353 comment_len = 0; | |
354 zde->disk_number = 0; | |
355 zde->int_attrib = 0; | |
356 zde->ext_attrib = 0; | |
357 zde->offset = 0; | |
358 } else { | |
359 comment_len = _zip_buffer_get_16(buffer); | |
360 zde->disk_number = _zip_buffer_get_16(buffer); | |
361 zde->int_attrib = _zip_buffer_get_16(buffer); | |
362 zde->ext_attrib = _zip_buffer_get_32(buffer); | |
363 zde->offset = _zip_buffer_get_32(buffer); | |
364 } | |
365 | |
366 if (!_zip_buffer_ok(buffer)) { | |
367 zip_error_set(error, ZIP_ER_INTERNAL, 0); | |
368 if (!from_buffer) { | |
369 _zip_buffer_free(buffer); | |
370 } | |
371 return -1; | |
372 } | |
373 | |
374 zde->filename = NULL; | |
375 zde->extra_fields = NULL; | |
376 zde->comment = NULL; | |
377 | |
378 variable_size = (zip_uint32_t)filename_len+(zip_uint32_t)ef_len+(zip_uint32_t)comment_len; | |
379 | |
380 if (from_buffer) { | |
381 if (_zip_buffer_left(buffer) < variable_size) { | |
382 zip_error_set(error, ZIP_ER_INCONS, 0); | |
383 return -1; | |
384 } | |
385 } | |
386 else { | |
387 _zip_buffer_free(buffer); | |
388 | |
389 if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) { | |
390 return -1; | |
391 } | |
392 } | |
393 | |
394 if (filename_len) { | |
395 zde->filename = _zip_read_string(buffer, src, filename_len, 1, error); | |
396 if (!zde->filename) { | |
397 if (zip_error_code_zip(error) == ZIP_ER_EOF) { | |
398 zip_error_set(error, ZIP_ER_INCONS, 0); | |
399 } | |
400 if (!from_buffer) { | |
401 _zip_buffer_free(buffer); | |
402 } | |
403 return -1; | |
404 } | |
405 | |
406 if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { | |
407 if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { | |
408 zip_error_set(error, ZIP_ER_INCONS, 0); | |
409 if (!from_buffer) { | |
410 _zip_buffer_free(buffer); | |
411 } | |
412 return -1; | |
413 } | |
414 } | |
415 } | |
416 | |
417 if (ef_len) { | |
418 zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error); | |
419 | |
420 if (ef == NULL) { | |
421 if (!from_buffer) { | |
422 _zip_buffer_free(buffer); | |
423 } | |
424 return -1; | |
425 } | |
426 if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) { | |
427 free(ef); | |
428 if (!from_buffer) { | |
429 _zip_buffer_free(buffer); | |
430 } | |
431 return -1; | |
432 } | |
433 free(ef); | |
434 if (local) | |
435 zde->local_extra_fields_read = 1; | |
436 } | |
437 | |
438 if (comment_len) { | |
439 zde->comment = _zip_read_string(buffer, src, comment_len, 0, error); | |
440 if (!zde->comment) { | |
441 if (!from_buffer) { | |
442 _zip_buffer_free(buffer); | |
443 } | |
444 return -1; | |
445 } | |
446 if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { | |
447 if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { | |
448 zip_error_set(error, ZIP_ER_INCONS, 0); | |
449 if (!from_buffer) { | |
450 _zip_buffer_free(buffer); | |
451 } | |
452 return -1; | |
453 } | |
454 } | |
455 } | |
456 | |
457 zde->filename = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename); | |
458 zde->comment = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment); | |
459 | |
460 /* Zip64 */ | |
461 | |
462 if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) { | |
463 zip_uint16_t got_len; | |
464 zip_buffer_t *ef_buffer; | |
465 const zip_uint8_t *ef = _zip_ef_get_by_id(zde->extra_fields, &got_len, ZIP_EF_ZIP64, 0, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error); | |
466 /* TODO: if got_len == 0 && !ZIP64_EOCD: no error, 0xffffffff is valid value */ | |
467 if (ef == NULL) { | |
468 if (!from_buffer) { | |
469 _zip_buffer_free(buffer); | |
470 } | |
471 return -1; | |
472 } | |
473 | |
474 if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) { | |
475 zip_error_set(error, ZIP_ER_MEMORY, 0); | |
476 if (!from_buffer) { | |
477 _zip_buffer_free(buffer); | |
478 } | |
479 return -1; | |
480 } | |
481 | |
482 if (zde->uncomp_size == ZIP_UINT32_MAX) | |
483 zde->uncomp_size = _zip_buffer_get_64(ef_buffer); | |
484 else if (local) { | |
485 /* From appnote.txt: This entry in the Local header MUST | |
486 include BOTH original and compressed file size fields. */ | |
487 (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */ | |
488 } | |
489 if (zde->comp_size == ZIP_UINT32_MAX) | |
490 zde->comp_size = _zip_buffer_get_64(ef_buffer); | |
491 if (!local) { | |
492 if (zde->offset == ZIP_UINT32_MAX) | |
493 zde->offset = _zip_buffer_get_64(ef_buffer); | |
494 if (zde->disk_number == ZIP_UINT16_MAX) | |
495 zde->disk_number = _zip_buffer_get_32(buffer); | |
496 } | |
497 | |
498 if (!_zip_buffer_eof(ef_buffer)) { | |
499 zip_error_set(error, ZIP_ER_INCONS, 0); | |
500 _zip_buffer_free(ef_buffer); | |
501 if (!from_buffer) { | |
502 _zip_buffer_free(buffer); | |
503 } | |
504 return -1; | |
505 } | |
506 _zip_buffer_free(ef_buffer); | |
507 } | |
508 | |
509 if (!_zip_buffer_ok(buffer)) { | |
510 zip_error_set(error, ZIP_ER_INTERNAL, 0); | |
511 if (!from_buffer) { | |
512 _zip_buffer_free(buffer); | |
513 } | |
514 return -1; | |
515 } | |
516 if (!from_buffer) { | |
517 _zip_buffer_free(buffer); | |
518 } | |
519 | |
520 /* zip_source_seek / zip_source_tell don't support values > ZIP_INT64_MAX */ | |
521 if (zde->offset > ZIP_INT64_MAX) { | |
522 zip_error_set(error, ZIP_ER_SEEK, EFBIG); | |
523 return -1; | |
524 } | |
525 | |
526 zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields); | |
527 | |
528 return (zip_int64_t)(size + variable_size); | |
529 } | |
530 | |
531 | |
532 static zip_string_t * | |
533 _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str) | |
534 { | |
535 zip_uint16_t ef_len; | |
536 zip_uint32_t ef_crc; | |
537 zip_buffer_t *buffer; | |
538 | |
539 const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL); | |
540 | |
541 if (ef == NULL || ef_len < 5 || ef[0] != 1) { | |
542 return str; | |
543 } | |
544 | |
545 if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { | |
546 return str; | |
547 } | |
548 | |
549 _zip_buffer_get_8(buffer); | |
550 ef_crc = _zip_buffer_get_32(buffer); | |
551 | |
552 if (_zip_string_crc32(str) == ef_crc) { | |
553 zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer); | |
554 zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL); | |
555 | |
556 if (ef_str != NULL) { | |
557 _zip_string_free(str); | |
558 str = ef_str; | |
559 } | |
560 } | |
561 | |
562 _zip_buffer_free(buffer); | |
563 | |
564 return str; | |
565 } | |
566 | |
567 | |
568 zip_int32_t | |
569 _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) | |
570 { | |
571 zip_int32_t size; | |
572 bool local = (flags & ZIP_EF_LOCAL) != 0; | |
573 int i; | |
574 zip_uint8_t b[6]; | |
575 zip_buffer_t *buffer; | |
576 | |
577 size = local ? LENTRYSIZE : CDENTRYSIZE; | |
578 | |
579 if (zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) { | |
580 _zip_error_set_from_source(error, src); | |
581 return -1; | |
582 } | |
583 | |
584 if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) { | |
585 return -1; | |
586 } | |
587 | |
588 for (i=0; i<(local ? 2 : 3); i++) { | |
589 size += _zip_buffer_get_16(buffer); | |
590 } | |
591 | |
592 if (!_zip_buffer_eof(buffer)) { | |
593 zip_error_set(error, ZIP_ER_INTERNAL, 0); | |
594 _zip_buffer_free(buffer); | |
595 return -1; | |
596 } | |
597 | |
598 _zip_buffer_free(buffer); | |
599 return size; | |
600 } | |
601 | |
602 | |
603 /* _zip_dirent_write | |
604 Writes zip directory entry. | |
605 | |
606 If flags & ZIP_EF_LOCAL, it writes a local header instead of a central | |
607 directory entry. If flags & ZIP_EF_FORCE_ZIP64, a ZIP64 extra field is written, even if not needed. | |
608 | |
609 Returns 0 if successful, 1 if successful and wrote ZIP64 extra field. On error, error is filled in and -1 is | |
610 returned. | |
611 */ | |
612 | |
613 int | |
614 _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) | |
615 { | |
616 zip_uint16_t dostime, dosdate; | |
617 zip_encoding_type_t com_enc, name_enc; | |
618 zip_extra_field_t *ef; | |
619 zip_extra_field_t *ef64; | |
620 zip_uint32_t ef_total_size; | |
621 bool is_zip64; | |
622 bool is_really_zip64; | |
623 zip_uint8_t buf[CDENTRYSIZE]; | |
624 zip_buffer_t *buffer; | |
625 | |
626 ef = NULL; | |
627 | |
628 name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); | |
629 com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); | |
630 | |
631 if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || | |
632 (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) || | |
633 (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN)) | |
634 de->bitflags |= ZIP_GPBF_ENCODING_UTF_8; | |
635 else { | |
636 de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8; | |
637 if (name_enc == ZIP_ENCODING_UTF8_KNOWN) { | |
638 ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error); | |
639 if (ef == NULL) | |
640 return -1; | |
641 } | |
642 if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN){ | |
643 zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error); | |
644 if (ef2 == NULL) { | |
645 _zip_ef_free(ef); | |
646 return -1; | |
647 } | |
648 ef2->next = ef; | |
649 ef = ef2; | |
650 } | |
651 } | |
652 | |
653 is_really_zip64 = _zip_dirent_needs_zip64(de, flags); | |
654 is_zip64 = (flags & (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64) || is_really_zip64; | |
655 | |
656 if (is_zip64) { | |
657 zip_uint8_t ef_zip64[EFZIP64SIZE]; | |
658 zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64)); | |
659 if (ef_buffer == NULL) { | |
660 zip_error_set(&za->error, ZIP_ER_MEMORY, 0); | |
661 _zip_ef_free(ef); | |
662 return -1; | |
663 } | |
664 | |
665 if (flags & ZIP_FL_LOCAL) { | |
666 if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) { | |
667 _zip_buffer_put_64(ef_buffer, de->uncomp_size); | |
668 _zip_buffer_put_64(ef_buffer, de->comp_size); | |
669 } | |
670 } | |
671 else { | |
672 if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) { | |
673 if (de->uncomp_size >= ZIP_UINT32_MAX) { | |
674 _zip_buffer_put_64(ef_buffer, de->uncomp_size); | |
675 } | |
676 if (de->comp_size >= ZIP_UINT32_MAX) { | |
677 _zip_buffer_put_64(ef_buffer, de->comp_size); | |
678 } | |
679 if (de->offset >= ZIP_UINT32_MAX) { | |
680 _zip_buffer_put_64(ef_buffer, de->offset); | |
681 } | |
682 } | |
683 } | |
684 | |
685 if (!_zip_buffer_ok(ef_buffer)) { | |
686 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
687 _zip_buffer_free(ef_buffer); | |
688 _zip_ef_free(ef); | |
689 return -1; | |
690 } | |
691 | |
692 ef64 = _zip_ef_new(ZIP_EF_ZIP64, (zip_uint16_t)(_zip_buffer_offset(ef_buffer)), ef_zip64, ZIP_EF_BOTH); | |
693 _zip_buffer_free(ef_buffer); | |
694 ef64->next = ef; | |
695 ef = ef64; | |
696 } | |
697 | |
698 if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { | |
699 zip_error_set(&za->error, ZIP_ER_MEMORY, 0); | |
700 _zip_ef_free(ef); | |
701 return -1; | |
702 } | |
703 | |
704 _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4); | |
705 | |
706 if ((flags & ZIP_FL_LOCAL) == 0) { | |
707 _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby)); | |
708 } | |
709 _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed)); | |
710 _zip_buffer_put_16(buffer, de->bitflags&0xfff9); /* clear compression method specific flags */ | |
711 _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method); | |
712 | |
713 _zip_u2d_time(de->last_mod, &dostime, &dosdate); | |
714 _zip_buffer_put_16(buffer, dostime); | |
715 _zip_buffer_put_16(buffer, dosdate); | |
716 | |
717 _zip_buffer_put_32(buffer, de->crc); | |
718 | |
719 if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) { | |
720 /* In local headers, if a ZIP64 EF is written, it MUST contain | |
721 * both compressed and uncompressed sizes (even if one of the | |
722 * two is smaller than 0xFFFFFFFF); on the other hand, those | |
723 * may only appear when the corresponding standard entry is | |
724 * 0xFFFFFFFF. (appnote.txt 4.5.3) */ | |
725 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); | |
726 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); | |
727 } | |
728 else { | |
729 if (de->comp_size < ZIP_UINT32_MAX) { | |
730 _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); | |
731 } | |
732 else { | |
733 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); | |
734 } | |
735 if (de->uncomp_size < ZIP_UINT32_MAX) { | |
736 _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); | |
737 } | |
738 else { | |
739 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); | |
740 } | |
741 } | |
742 | |
743 _zip_buffer_put_16(buffer, _zip_string_length(de->filename)); | |
744 /* TODO: check for overflow */ | |
745 ef_total_size = (zip_uint32_t)_zip_ef_size(de->extra_fields, flags) + (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH); | |
746 _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size); | |
747 | |
748 if ((flags & ZIP_FL_LOCAL) == 0) { | |
749 _zip_buffer_put_16(buffer, _zip_string_length(de->comment)); | |
750 _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number); | |
751 _zip_buffer_put_16(buffer, de->int_attrib); | |
752 _zip_buffer_put_32(buffer, de->ext_attrib); | |
753 if (de->offset < ZIP_UINT32_MAX) | |
754 _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset); | |
755 else | |
756 _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); | |
757 } | |
758 | |
759 if (!_zip_buffer_ok(buffer)) { | |
760 zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); | |
761 _zip_buffer_free(buffer); | |
762 _zip_ef_free(ef); | |
763 return -1; | |
764 } | |
765 | |
766 if (_zip_write(za, buf, _zip_buffer_offset(buffer)) < 0) { | |
767 _zip_buffer_free(buffer); | |
768 _zip_ef_free(ef); | |
769 return -1; | |
770 } | |
771 | |
772 _zip_buffer_free(buffer); | |
773 | |
774 if (de->filename) { | |
775 if (_zip_string_write(za, de->filename) < 0) { | |
776 _zip_ef_free(ef); | |
777 return -1; | |
778 } | |
779 } | |
780 | |
781 if (ef) { | |
782 if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) { | |
783 _zip_ef_free(ef); | |
784 return -1; | |
785 } | |
786 } | |
787 _zip_ef_free(ef); | |
788 if (de->extra_fields) { | |
789 if (_zip_ef_write(za, de->extra_fields, flags) < 0) { | |
790 return -1; | |
791 } | |
792 } | |
793 | |
794 if ((flags & ZIP_FL_LOCAL) == 0) { | |
795 if (de->comment) { | |
796 if (_zip_string_write(za, de->comment) < 0) { | |
797 return -1; | |
798 } | |
799 } | |
800 } | |
801 | |
802 | |
803 return is_zip64; | |
804 } | |
805 | |
806 | |
807 static time_t | |
808 _zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) | |
809 { | |
810 struct tm tm; | |
811 | |
812 memset(&tm, 0, sizeof(tm)); | |
813 | |
814 /* let mktime decide if DST is in effect */ | |
815 tm.tm_isdst = -1; | |
816 | |
817 tm.tm_year = ((ddate>>9)&127) + 1980 - 1900; | |
818 tm.tm_mon = ((ddate>>5)&15) - 1; | |
819 tm.tm_mday = ddate&31; | |
820 | |
821 tm.tm_hour = (dtime>>11)&31; | |
822 tm.tm_min = (dtime>>5)&63; | |
823 tm.tm_sec = (dtime<<1)&62; | |
824 | |
825 return mktime(&tm); | |
826 } | |
827 | |
828 | |
829 static zip_extra_field_t * | |
830 _zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) | |
831 { | |
832 const zip_uint8_t *raw; | |
833 zip_uint32_t len; | |
834 zip_buffer_t *buffer; | |
835 zip_extra_field_t *ef; | |
836 | |
837 if ((raw=_zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) { | |
838 /* error already set */ | |
839 return NULL; | |
840 } | |
841 | |
842 if (len+5 > ZIP_UINT16_MAX) { | |
843 zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */ | |
844 return NULL; | |
845 } | |
846 | |
847 if ((buffer = _zip_buffer_new(NULL, len+5)) == NULL) { | |
848 zip_error_set(error, ZIP_ER_MEMORY, 0); | |
849 return NULL; | |
850 } | |
851 | |
852 _zip_buffer_put_8(buffer, 1); | |
853 _zip_buffer_put_32(buffer, _zip_string_crc32(str)); | |
854 _zip_buffer_put(buffer, raw, len); | |
855 | |
856 if (!_zip_buffer_ok(buffer)) { | |
857 zip_error_set(error, ZIP_ER_INTERNAL, 0); | |
858 _zip_buffer_free(buffer); | |
859 return NULL; | |
860 } | |
861 | |
862 ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH); | |
863 _zip_buffer_free(buffer); | |
864 | |
865 return ef; | |
866 } | |
867 | |
868 | |
869 zip_dirent_t * | |
870 _zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) | |
871 { | |
872 if (error == NULL) | |
873 error = &za->error; | |
874 | |
875 if (idx >= za->nentry) { | |
876 zip_error_set(error, ZIP_ER_INVAL, 0); | |
877 return NULL; | |
878 } | |
879 | |
880 if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) { | |
881 if (za->entry[idx].orig == NULL) { | |
882 zip_error_set(error, ZIP_ER_INVAL, 0); | |
883 return NULL; | |
884 } | |
885 if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) { | |
886 zip_error_set(error, ZIP_ER_DELETED, 0); | |
887 return NULL; | |
888 } | |
889 return za->entry[idx].orig; | |
890 } | |
891 else | |
892 return za->entry[idx].changes; | |
893 } | |
894 | |
895 | |
896 | |
897 | |
898 void | |
899 _zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) | |
900 { | |
901 struct tm *tm; | |
902 | |
903 tm = localtime(&intime); | |
904 if (tm->tm_year < 80) { | |
905 tm->tm_year = 80; | |
906 } | |
907 | |
908 *ddate = (zip_uint16_t)(((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday); | |
909 *dtime = (zip_uint16_t)(((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1)); | |
910 | |
911 return; | |
912 } |