xref: /PHP-7.3/ext/zip/lib/zip_dirent.c (revision dac6c639)
1 /*
2   zip_dirent.c -- read directory entry (local or central), clean dirent
3   Copyright (c) 1999-2017 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
_zip_cdir_free(zip_cdir_t * cd)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 *
_zip_cdir_new(zip_uint64_t nentry,zip_error_t * error)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
_zip_cdir_write(zip_t * za,const zip_filelist_t * filelist,zip_uint64_t survivors)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 *
_zip_dirent_clone(const zip_dirent_t * sde)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
_zip_dirent_finalize(zip_dirent_t * zde)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
_zip_dirent_free(zip_dirent_t * zde)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
_zip_dirent_init(zip_dirent_t * de)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
_zip_dirent_needs_zip64(const zip_dirent_t * de,zip_flags_t flags)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 *
_zip_dirent_new(void)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
_zip_dirent_read(zip_dirent_t * zde,zip_source_t * src,zip_buffer_t * buffer,bool local,zip_error_t * error)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 *
_zip_dirent_process_ef_utf_8(const zip_dirent_t * de,zip_uint16_t id,zip_string_t * str)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
_zip_dirent_size(zip_source_t * src,zip_uint16_t flags,zip_error_t * error)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
_zip_dirent_write(zip_t * za,zip_dirent_t * de,zip_flags_t flags)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
_zip_d2u_time(zip_uint16_t dtime,zip_uint16_t ddate)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 *
_zip_ef_utf8(zip_uint16_t id,zip_string_t * str,zip_error_t * error)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 *
_zip_get_dirent(zip_t * za,zip_uint64_t idx,zip_flags_t flags,zip_error_t * error)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
_zip_u2d_time(time_t intime,zip_uint16_t * dtime,zip_uint16_t * ddate)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 }
913