diff options
Diffstat (limited to 'src/Common/libzip/zip_dirent.c')
-rw-r--r-- | src/Common/libzip/zip_dirent.c | 836 |
1 files changed, 469 insertions, 367 deletions
diff --git a/src/Common/libzip/zip_dirent.c b/src/Common/libzip/zip_dirent.c index df38afd9..45a2a6a2 100644 --- a/src/Common/libzip/zip_dirent.c +++ b/src/Common/libzip/zip_dirent.c @@ -1,9 +1,9 @@ /* zip_dirent.c -- read directory entry (local or central), clean dirent - Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2021 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. - The authors can be contacted at <libzip@nih.at> + The authors can be contacted at <info@libzip.org> Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -36,27 +36,25 @@ #include <stdlib.h> #include <string.h> #include <sys/types.h> -#include <sys/stat.h> #include <time.h> +#include <zlib.h> #include "zipint.h" -static time_t _zip_d2u_time(zip_uint16_t, zip_uint16_t); static zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str); static zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *); static bool _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error); void -_zip_cdir_free(zip_cdir_t *cd) -{ +_zip_cdir_free(zip_cdir_t *cd) { zip_uint64_t i; if (!cd) - return; + return; - for (i=0; i<cd->nentry; i++) - _zip_entry_finalize(cd->entry+i); + for (i = 0; i < cd->nentry; i++) + _zip_entry_finalize(cd->entry + i); free(cd->entry); _zip_string_free(cd->comment); free(cd); @@ -64,13 +62,12 @@ _zip_cdir_free(zip_cdir_t *cd) zip_cdir_t * -_zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) -{ +_zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) { zip_cdir_t *cd; - if ((cd=(zip_cdir_t *)malloc(sizeof(*cd))) == NULL) { - zip_error_set(error, ZIP_ER_MEMORY, 0); - return NULL; + if ((cd = (zip_cdir_t *)malloc(sizeof(*cd))) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; } cd->entry = NULL; @@ -80,8 +77,8 @@ _zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) cd->is_zip64 = false; if (!_zip_cdir_grow(cd, nentry, error)) { - _zip_cdir_free(cd); - return NULL; + _zip_cdir_free(cd); + return NULL; } return cd; @@ -89,31 +86,30 @@ _zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) bool -_zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error) -{ +_zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error) { zip_uint64_t i, new_alloc; zip_entry_t *new_entry; if (additional_entries == 0) { - return true; + return true; } new_alloc = cd->nentry_alloc + additional_entries; - if (new_alloc < additional_entries || new_alloc > SIZE_MAX/sizeof(*(cd->entry))) { - zip_error_set(error, ZIP_ER_MEMORY, 0); - return false; + if (new_alloc < additional_entries || new_alloc > SIZE_MAX / sizeof(*(cd->entry))) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; } - if ((new_entry = (zip_entry_t *)realloc(cd->entry, sizeof(*(cd->entry))*(size_t)new_alloc)) == NULL) { - zip_error_set(error, ZIP_ER_MEMORY, 0); - return false; + if ((new_entry = (zip_entry_t *)realloc(cd->entry, sizeof(*(cd->entry)) * (size_t)new_alloc)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; } cd->entry = new_entry; for (i = cd->nentry; i < new_alloc; i++) { - _zip_entry_init(cd->entry+i); + _zip_entry_init(cd->entry + i); } cd->nentry = cd->nentry_alloc = new_alloc; @@ -123,8 +119,7 @@ _zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *err zip_int64_t -_zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) -{ +_zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) { zip_uint64_t offset, size; zip_string_t *comment; zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN]; @@ -133,33 +128,41 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor zip_uint64_t i; bool is_zip64; int ret; + zip_uint32_t cdir_crc; if ((off = zip_source_tell_write(za->src)) < 0) { - _zip_error_set_from_source(&za->error, za->src); + zip_error_set_from_source(&za->error, za->src); return -1; } offset = (zip_uint64_t)off; is_zip64 = false; - for (i=0; i<survivors; i++) { - zip_entry_t *entry = za->entry+filelist[i].idx; + if (ZIP_WANT_TORRENTZIP(za)) { + cdir_crc = (zip_uint32_t)crc32(0, NULL, 0); + za->write_crc = &cdir_crc; + } + + for (i = 0; i < survivors; i++) { + zip_entry_t *entry = za->entry + filelist[i].idx; - if ((ret=_zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL)) < 0) - return -1; - if (ret) - is_zip64 = true; + if ((ret = _zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL)) < 0) + return -1; + if (ret) + is_zip64 = true; } + za->write_crc = NULL; + if ((off = zip_source_tell_write(za->src)) < 0) { - _zip_error_set_from_source(&za->error, za->src); + zip_error_set_from_source(&za->error, za->src); return -1; } size = (zip_uint64_t)off - offset; - if (offset > ZIP_UINT32_MAX || survivors > ZIP_UINT16_MAX) - is_zip64 = true; - + if (offset > ZIP_UINT32_MAX || survivors > ZIP_UINT16_MAX) { + is_zip64 = true; + } if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); @@ -167,20 +170,20 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor } if (is_zip64) { - _zip_buffer_put(buffer, EOCD64_MAGIC, 4); - _zip_buffer_put_64(buffer, EOCD64LEN-12); - _zip_buffer_put_16(buffer, 45); - _zip_buffer_put_16(buffer, 45); - _zip_buffer_put_32(buffer, 0); - _zip_buffer_put_32(buffer, 0); - _zip_buffer_put_64(buffer, survivors); - _zip_buffer_put_64(buffer, survivors); - _zip_buffer_put_64(buffer, size); - _zip_buffer_put_64(buffer, offset); - _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4); - _zip_buffer_put_32(buffer, 0); - _zip_buffer_put_64(buffer, offset+size); - _zip_buffer_put_32(buffer, 1); + _zip_buffer_put(buffer, EOCD64_MAGIC, 4); + _zip_buffer_put_64(buffer, EOCD64LEN - 12); + _zip_buffer_put_16(buffer, 45); + _zip_buffer_put_16(buffer, 45); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_64(buffer, survivors); + _zip_buffer_put_64(buffer, survivors); + _zip_buffer_put_64(buffer, size); + _zip_buffer_put_64(buffer, offset); + _zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4); + _zip_buffer_put_32(buffer, 0); + _zip_buffer_put_64(buffer, offset + size); + _zip_buffer_put_32(buffer, 1); } _zip_buffer_put(buffer, EOCD_MAGIC, 4); @@ -192,7 +195,13 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor comment = za->comment_changed ? za->comment_changes : za->comment_orig; - _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0)); + if (ZIP_WANT_TORRENTZIP(za)) { + _zip_buffer_put_16(buffer, TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH); + } + else { + _zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0)); + } + if (!_zip_buffer_ok(buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); @@ -202,15 +211,23 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) { _zip_buffer_free(buffer); - return -1; + return -1; } _zip_buffer_free(buffer); - if (comment) { - if (_zip_write(za, comment->raw, comment->length) < 0) { - return -1; - } + if (ZIP_WANT_TORRENTZIP(za)) { + char torrentzip_comment[TORRENTZIP_SIGNATURE_LENGTH + TORRENTZIP_CRC_LENGTH + 1]; + snprintf(torrentzip_comment, sizeof(torrentzip_comment), TORRENTZIP_SIGNATURE "%08X", cdir_crc); + + if (_zip_write(za, torrentzip_comment, strlen(torrentzip_comment)) < 0) { + return -1; + } + } + else if (comment != NULL) { + if (_zip_write(za, comment->raw, comment->length) < 0) { + return -1; + } } return (zip_int64_t)size; @@ -218,17 +235,16 @@ _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivor zip_dirent_t * -_zip_dirent_clone(const zip_dirent_t *sde) -{ +_zip_dirent_clone(const zip_dirent_t *sde) { zip_dirent_t *tde; - if ((tde=(zip_dirent_t *)malloc(sizeof(*tde))) == NULL) - return NULL; + if ((tde = (zip_dirent_t *)malloc(sizeof(*tde))) == NULL) + return NULL; if (sde) - memcpy(tde, sde, sizeof(*sde)); + (void)memcpy_s(tde, sizeof(*tde), sde, sizeof(*sde)); else - _zip_dirent_init(tde); + _zip_dirent_init(tde); tde->changed = 0; tde->cloned = 1; @@ -238,35 +254,33 @@ _zip_dirent_clone(const zip_dirent_t *sde) void -_zip_dirent_finalize(zip_dirent_t *zde) -{ +_zip_dirent_finalize(zip_dirent_t *zde) { if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) { - _zip_string_free(zde->filename); - zde->filename = NULL; + _zip_string_free(zde->filename); + zde->filename = NULL; } if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) { - _zip_ef_free(zde->extra_fields); - zde->extra_fields = NULL; + _zip_ef_free(zde->extra_fields); + zde->extra_fields = NULL; } if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) { - _zip_string_free(zde->comment); - zde->comment = NULL; + _zip_string_free(zde->comment); + zde->comment = NULL; } if (!zde->cloned || zde->changed & ZIP_DIRENT_PASSWORD) { - if (zde->password) { - _zip_crypto_clear(zde->password, strlen(zde->password)); - } - free(zde->password); - zde->password = NULL; + if (zde->password) { + _zip_crypto_clear(zde->password, strlen(zde->password)); + } + free(zde->password); + zde->password = NULL; } } void -_zip_dirent_free(zip_dirent_t *zde) -{ +_zip_dirent_free(zip_dirent_t *zde) { if (zde == NULL) - return; + return; _zip_dirent_finalize(zde); free(zde); @@ -274,15 +288,14 @@ _zip_dirent_free(zip_dirent_t *zde) void -_zip_dirent_init(zip_dirent_t *de) -{ +_zip_dirent_init(zip_dirent_t *de) { de->changed = 0; de->local_extra_fields_read = 0; de->cloned = 0; de->crc_valid = true; - de->version_madeby = 20 | (ZIP_OPSYS_DEFAULT << 8); - de->version_needed = 20; /* 2.0 */ + de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8); + de->version_needed = 10; /* 1.0 */ de->bitflags = 0; de->comp_method = ZIP_CM_DEFAULT; de->last_mod = 0; @@ -296,29 +309,27 @@ _zip_dirent_init(zip_dirent_t *de) de->int_attrib = 0; de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT; de->offset = 0; + de->compression_level = 0; de->encryption_method = ZIP_EM_NONE; de->password = NULL; } bool -_zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) -{ - if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX - || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX)) - return true; +_zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) { + if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX)) + return true; return false; } zip_dirent_t * -_zip_dirent_new(void) -{ +_zip_dirent_new(void) { zip_dirent_t *de; - if ((de=(zip_dirent_t *)malloc(sizeof(*de))) == NULL) - return NULL; + if ((de = (zip_dirent_t *)malloc(sizeof(*de))) == NULL) + return NULL; _zip_dirent_init(de); return de; @@ -336,8 +347,7 @@ _zip_dirent_new(void) */ zip_int64_t -_zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error) -{ +_zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error) { zip_uint8_t buf[CDENTRYSIZE]; zip_uint16_t dostime, dosdate; zip_uint32_t size, variable_size; @@ -360,20 +370,20 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) { - zip_error_set(error, ZIP_ER_NOZIP, 0); + zip_error_set(error, ZIP_ER_NOZIP, 0); if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; + return -1; } /* convert buffercontents to zip_dirent */ _zip_dirent_init(zde); if (!local) - zde->version_madeby = _zip_buffer_get_16(buffer); + zde->version_madeby = _zip_buffer_get_16(buffer); else - zde->version_madeby = 0; + zde->version_madeby = 0; zde->version_needed = _zip_buffer_get_16(buffer); zde->bitflags = _zip_buffer_get_16(buffer); zde->comp_method = _zip_buffer_get_16(buffer); @@ -391,17 +401,18 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo ef_len = _zip_buffer_get_16(buffer); if (local) { - comment_len = 0; - zde->disk_number = 0; - zde->int_attrib = 0; - zde->ext_attrib = 0; - zde->offset = 0; - } else { - comment_len = _zip_buffer_get_16(buffer); - zde->disk_number = _zip_buffer_get_16(buffer); - zde->int_attrib = _zip_buffer_get_16(buffer); - zde->ext_attrib = _zip_buffer_get_32(buffer); - zde->offset = _zip_buffer_get_32(buffer); + comment_len = 0; + zde->disk_number = 0; + zde->int_attrib = 0; + zde->ext_attrib = 0; + zde->offset = 0; + } + else { + comment_len = _zip_buffer_get_16(buffer); + zde->disk_number = _zip_buffer_get_16(buffer); + zde->int_attrib = _zip_buffer_get_16(buffer); + zde->ext_attrib = _zip_buffer_get_32(buffer); + zde->offset = _zip_buffer_get_32(buffer); } if (!_zip_buffer_ok(buffer)) { @@ -413,27 +424,27 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } if (zde->bitflags & ZIP_GPBF_ENCRYPTED) { - if (zde->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { - /* TODO */ - zde->encryption_method = ZIP_EM_UNKNOWN; - } - else { - zde->encryption_method = ZIP_EM_TRAD_PKWARE; - } + if (zde->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { + /* TODO */ + zde->encryption_method = ZIP_EM_UNKNOWN; + } + else { + zde->encryption_method = ZIP_EM_TRAD_PKWARE; + } } else { - zde->encryption_method = ZIP_EM_NONE; + zde->encryption_method = ZIP_EM_NONE; } zde->filename = NULL; zde->extra_fields = NULL; zde->comment = NULL; - variable_size = (zip_uint32_t)filename_len+(zip_uint32_t)ef_len+(zip_uint32_t)comment_len; + variable_size = (zip_uint32_t)filename_len + (zip_uint32_t)ef_len + (zip_uint32_t)comment_len; if (from_buffer) { if (_zip_buffer_left(buffer) < variable_size) { - zip_error_set(error, ZIP_ER_INCONS, 0); + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW); return -1; } } @@ -446,66 +457,66 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo } if (filename_len) { - zde->filename = _zip_read_string(buffer, src, filename_len, 1, error); + zde->filename = _zip_read_string(buffer, src, filename_len, 1, error); if (!zde->filename) { if (zip_error_code_zip(error) == ZIP_ER_EOF) { - zip_error_set(error, ZIP_ER_INCONS, 0); + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_VARIABLE_SIZE_OVERFLOW); } if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; + return -1; } - if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { - if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { - zip_error_set(error, ZIP_ER_INCONS, 0); + if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { + if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_FILENAME); if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; - } - } + return -1; + } + } } if (ef_len) { - zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error); + zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error); if (ef == NULL) { if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; + return -1; } if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) { - free(ef); + free(ef); if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; - } - free(ef); - if (local) - zde->local_extra_fields_read = 1; + return -1; + } + free(ef); + if (local) + zde->local_extra_fields_read = 1; } if (comment_len) { - zde->comment = _zip_read_string(buffer, src, comment_len, 0, error); + zde->comment = _zip_read_string(buffer, src, comment_len, 0, error); if (!zde->comment) { if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; + return -1; } - if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { - if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { - zip_error_set(error, ZIP_ER_INCONS, 0); + if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) { + if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_UTF8_IN_COMMENT); if (!from_buffer) { _zip_buffer_free(buffer); } - return -1; - } - } + return -1; + } + } } zde->filename = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename); @@ -514,52 +525,19 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo /* Zip64 */ if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) { - zip_uint16_t got_len; - zip_buffer_t *ef_buffer; - 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); - /* TODO: if got_len == 0 && !ZIP64_EOCD: no error, 0xffffffff is valid value */ - if (ef == NULL) { - if (!from_buffer) { - _zip_buffer_free(buffer); - } - return -1; - } - - if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) { - zip_error_set(error, ZIP_ER_MEMORY, 0); - if (!from_buffer) { - _zip_buffer_free(buffer); - } - return -1; - } - - if (zde->uncomp_size == ZIP_UINT32_MAX) - zde->uncomp_size = _zip_buffer_get_64(ef_buffer); - else if (local) { - /* From appnote.txt: This entry in the Local header MUST - include BOTH original and compressed file size fields. */ - (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */ - } - if (zde->comp_size == ZIP_UINT32_MAX) - zde->comp_size = _zip_buffer_get_64(ef_buffer); - if (!local) { - if (zde->offset == ZIP_UINT32_MAX) - zde->offset = _zip_buffer_get_64(ef_buffer); - if (zde->disk_number == ZIP_UINT16_MAX) - zde->disk_number = _zip_buffer_get_32(buffer); - } - - if (!_zip_buffer_eof(ef_buffer)) { - zip_error_set(error, ZIP_ER_INCONS, 0); - _zip_buffer_free(ef_buffer); - if (!from_buffer) { - _zip_buffer_free(buffer); + zip_uint16_t got_len; + 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); + if (ef != NULL) { + if (!zip_dirent_process_ef_zip64(zde, ef, got_len, local, error)) { + if (!from_buffer) { + _zip_buffer_free(buffer); + } + return -1; } - return -1; } - _zip_buffer_free(ef_buffer); } + if (!_zip_buffer_ok(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); if (!from_buffer) { @@ -573,26 +551,81 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo /* zip_source_seek / zip_source_tell don't support values > ZIP_INT64_MAX */ if (zde->offset > ZIP_INT64_MAX) { - zip_error_set(error, ZIP_ER_SEEK, EFBIG); - return -1; + zip_error_set(error, ZIP_ER_SEEK, EFBIG); + return -1; } if (!_zip_dirent_process_winzip_aes(zde, error)) { - if (!from_buffer) { - _zip_buffer_free(buffer); - } - return -1; + return -1; } zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields); - return (zip_int64_t)(size + variable_size); + return (zip_int64_t)size + (zip_int64_t)variable_size; +} + +bool zip_dirent_process_ef_zip64(zip_dirent_t* zde, const zip_uint8_t* ef, zip_uint64_t got_len, bool local, zip_error_t* error) { + zip_buffer_t *ef_buffer; + + if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return false; + } + + if (zde->uncomp_size == ZIP_UINT32_MAX) { + zde->uncomp_size = _zip_buffer_get_64(ef_buffer); + } + else if (local) { + /* From appnote.txt: This entry in the Local header MUST + include BOTH original and compressed file size fields. */ + (void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */ + } + if (zde->comp_size == ZIP_UINT32_MAX) { + zde->comp_size = _zip_buffer_get_64(ef_buffer); + } + if (!local) { + if (zde->offset == ZIP_UINT32_MAX) { + zde->offset = _zip_buffer_get_64(ef_buffer); + } + if (zde->disk_number == ZIP_UINT16_MAX) { + zde->disk_number = _zip_buffer_get_32(ef_buffer); + } + } + + if (!_zip_buffer_eof(ef_buffer)) { + /* accept additional fields if values match */ + bool ok = true; + switch (got_len) { + case 28: + _zip_buffer_set_offset(ef_buffer, 24); + if (zde->disk_number != _zip_buffer_get_32(ef_buffer)) { + ok = false; + } + /* fallthrough */ + case 24: + _zip_buffer_set_offset(ef_buffer, 0); + if ((zde->uncomp_size != _zip_buffer_get_64(ef_buffer)) || (zde->comp_size != _zip_buffer_get_64(ef_buffer)) || (zde->offset != _zip_buffer_get_64(ef_buffer))) { + ok = false; + } + break; + + default: + ok = false; + } + if (!ok) { + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_ZIP64_EF); + _zip_buffer_free(ef_buffer); + return false; + } + } + _zip_buffer_free(ef_buffer); + + return true; } static zip_string_t * -_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str) -{ +_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str) { zip_uint16_t ef_len; zip_uint32_t ef_crc; zip_buffer_t *buffer; @@ -600,7 +633,7 @@ _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL); if (ef == NULL || ef_len < 5 || ef[0] != 1) { - return str; + return str; } if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { @@ -614,10 +647,10 @@ _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer); zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL); - if (ef_str != NULL) { - _zip_string_free(str); - str = ef_str; - } + if (ef_str != NULL) { + _zip_string_free(str); + str = ef_str; + } } _zip_buffer_free(buffer); @@ -627,8 +660,7 @@ _zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string static bool -_zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) -{ +_zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) { zip_uint16_t ef_len; zip_buffer_t *buffer; const zip_uint8_t *ef; @@ -637,18 +669,18 @@ _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) if (de->comp_method != ZIP_CM_WINZIP_AES) { - return true; + return true; } ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, ZIP_EF_WINZIP_AES, 0, ZIP_EF_BOTH, NULL); if (ef == NULL || ef_len < 7) { - zip_error_set(error, ZIP_ER_INCONS, 0); - return false; + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF); + return false; } if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) { - zip_error_set(error, ZIP_ER_INTERNAL, 0); + zip_error_set(error, ZIP_ER_INTERNAL, 0); return false; } @@ -656,49 +688,48 @@ _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) crc_valid = true; switch (_zip_buffer_get_16(buffer)) { - case 1: - break; - - case 2: - if (de->uncomp_size < 20 /* TODO: constant */) { - crc_valid = false; - } - break; - - default: - zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); - _zip_buffer_free(buffer); - return false; + case 1: + break; + + case 2: + crc_valid = false; + /* TODO: When checking consistency, check that crc is 0. */ + break; + + default: + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + _zip_buffer_free(buffer); + return false; } /* vendor */ if (memcmp(_zip_buffer_get(buffer, 2), "AE", 2) != 0) { - zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); - _zip_buffer_free(buffer); - return false; + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + _zip_buffer_free(buffer); + return false; } /* mode */ switch (_zip_buffer_get_8(buffer)) { case 1: - enc_method = ZIP_EM_AES_128; - break; + enc_method = ZIP_EM_AES_128; + break; case 2: - enc_method = ZIP_EM_AES_192; - break; + enc_method = ZIP_EM_AES_192; + break; case 3: - enc_method = ZIP_EM_AES_256; - break; + enc_method = ZIP_EM_AES_256; + break; default: - zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); - _zip_buffer_free(buffer); - return false; + zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0); + _zip_buffer_free(buffer); + return false; } if (ef_len != 7) { - zip_error_set(error, ZIP_ER_INCONS, 0); - _zip_buffer_free(buffer); - return false; + zip_error_set(error, ZIP_ER_INCONS, ZIP_ER_DETAIL_INVALID_WINZIPAES_EF); + _zip_buffer_free(buffer); + return false; } de->crc_valid = crc_valid; @@ -711,8 +742,7 @@ _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) zip_int32_t -_zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) -{ +_zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) { zip_int32_t size; bool local = (flags & ZIP_EF_LOCAL) != 0; int i; @@ -722,21 +752,21 @@ _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) size = local ? LENTRYSIZE : CDENTRYSIZE; if (zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) { - _zip_error_set_from_source(error, src); - return -1; + zip_error_set_from_source(error, src); + return -1; } if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) { - return -1; + return -1; } - for (i=0; i<(local ? 2 : 3); i++) { - size += _zip_buffer_get_16(buffer); + for (i = 0; i < (local ? 2 : 3); i++) { + size += _zip_buffer_get_16(buffer); } if (!_zip_buffer_eof(buffer)) { zip_error_set(error, ZIP_ER_INTERNAL, 0); - _zip_buffer_free(buffer); + _zip_buffer_free(buffer); return -1; } @@ -756,8 +786,7 @@ _zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) */ int -_zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) -{ +_zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) { zip_uint16_t dostime, dosdate; zip_encoding_type_t com_enc, name_enc; zip_extra_field_t *ef; @@ -774,37 +803,35 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); - if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || - (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) || - (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN)) - de->bitflags |= ZIP_GPBF_ENCODING_UTF_8; + if ((name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || (name_enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN) || (name_enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN)) + de->bitflags |= ZIP_GPBF_ENCODING_UTF_8; else { - de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8; - if (name_enc == ZIP_ENCODING_UTF8_KNOWN) { - ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error); - if (ef == NULL) - return -1; - } - if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN){ - zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error); - if (ef2 == NULL) { - _zip_ef_free(ef); - return -1; - } - ef2->next = ef; - ef = ef2; - } + de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8; + if (name_enc == ZIP_ENCODING_UTF8_KNOWN) { + ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error); + if (ef == NULL) + return -1; + } + if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN) { + zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error); + if (ef2 == NULL) { + _zip_ef_free(ef); + return -1; + } + ef2->next = ef; + ef = ef2; + } } if (de->encryption_method == ZIP_EM_NONE) { - de->bitflags &= ~ZIP_GPBF_ENCRYPTED; + de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCRYPTED; } else { - de->bitflags |= ZIP_GPBF_ENCRYPTED; + de->bitflags |= (zip_uint16_t)ZIP_GPBF_ENCRYPTED; } is_really_zip64 = _zip_dirent_needs_zip64(de, flags); - is_zip64 = (flags & (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64) || is_really_zip64; + is_zip64 = (flags & (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64) || is_really_zip64; is_winzip_aes = de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256; if (is_zip64) { @@ -812,7 +839,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64)); if (ef_buffer == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - _zip_ef_free(ef); + _zip_ef_free(ef); return -1; } @@ -839,7 +866,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) if (!_zip_buffer_ok(ef_buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(ef_buffer); - _zip_ef_free(ef); + _zip_ef_free(ef); return -1; } @@ -850,25 +877,25 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) } if (is_winzip_aes) { - zip_uint8_t data[EF_WINZIP_AES_SIZE]; + zip_uint8_t data[EF_WINZIP_AES_SIZE]; zip_buffer_t *ef_buffer = _zip_buffer_new(data, sizeof(data)); - zip_extra_field_t *ef_winzip; - + zip_extra_field_t *ef_winzip; + if (ef_buffer == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - _zip_ef_free(ef); + _zip_ef_free(ef); return -1; } - _zip_buffer_put_16(ef_buffer, 2); - _zip_buffer_put(ef_buffer, "AE", 2); - _zip_buffer_put_8(ef_buffer, (de->encryption_method & 0xff)); - _zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method); + _zip_buffer_put_16(ef_buffer, 2); + _zip_buffer_put(ef_buffer, "AE", 2); + _zip_buffer_put_8(ef_buffer, (zip_uint8_t)(de->encryption_method & 0xff)); + _zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method); if (!_zip_buffer_ok(ef_buffer)) { zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); _zip_buffer_free(ef_buffer); - _zip_ef_free(ef); + _zip_ef_free(ef); return -1; } @@ -887,66 +914,75 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) _zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4); if ((flags & ZIP_FL_LOCAL) == 0) { - _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby)); + _zip_buffer_put_16(buffer, de->version_madeby); } - _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed)); - _zip_buffer_put_16(buffer, de->bitflags&0xfff9); /* clear compression method specific flags */ + _zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed)); + _zip_buffer_put_16(buffer, de->bitflags); if (is_winzip_aes) { - _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES); + _zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES); } else { - _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method); + _zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method); } - _zip_u2d_time(de->last_mod, &dostime, &dosdate); + if (ZIP_WANT_TORRENTZIP(za)) { + dostime = 0xbc00; + dosdate = 0x2198; + } + else { + _zip_u2d_time(de->last_mod, &dostime, &dosdate); + } _zip_buffer_put_16(buffer, dostime); _zip_buffer_put_16(buffer, dosdate); - if (is_winzip_aes && de->uncomp_size < 20) { - _zip_buffer_put_32(buffer, 0); + if (is_winzip_aes && de->uncomp_size < 20) { + _zip_buffer_put_32(buffer, 0); } else { - _zip_buffer_put_32(buffer, de->crc); + _zip_buffer_put_32(buffer, de->crc); } if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) { - /* In local headers, if a ZIP64 EF is written, it MUST contain - * both compressed and uncompressed sizes (even if one of the - * two is smaller than 0xFFFFFFFF); on the other hand, those - * may only appear when the corresponding standard entry is - * 0xFFFFFFFF. (appnote.txt 4.5.3) */ - _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); - _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + /* In local headers, if a ZIP64 EF is written, it MUST contain + * both compressed and uncompressed sizes (even if one of the + * two is smaller than 0xFFFFFFFF); on the other hand, those + * may only appear when the corresponding standard entry is + * 0xFFFFFFFF. (appnote.txt 4.5.3) */ + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } else { if (de->comp_size < ZIP_UINT32_MAX) { - _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); + _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size); } else { - _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } if (de->uncomp_size < ZIP_UINT32_MAX) { - _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); + _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size); } else { - _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } } _zip_buffer_put_16(buffer, _zip_string_length(de->filename)); - /* TODO: check for overflow */ - ef_total_size = (zip_uint32_t)_zip_ef_size(de->extra_fields, flags) + (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH); + ef_total_size = (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH); + if (!ZIP_WANT_TORRENTZIP(za)) { + /* TODO: check for overflow */ + ef_total_size += (zip_uint32_t)_zip_ef_size(de->extra_fields, flags); + } _zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size); if ((flags & ZIP_FL_LOCAL) == 0) { - _zip_buffer_put_16(buffer, _zip_string_length(de->comment)); - _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number); - _zip_buffer_put_16(buffer, de->int_attrib); - _zip_buffer_put_32(buffer, de->ext_attrib); - if (de->offset < ZIP_UINT32_MAX) - _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset); - else - _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); + _zip_buffer_put_16(buffer, ZIP_WANT_TORRENTZIP(za) ? 0 : _zip_string_length(de->comment)); + _zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number); + _zip_buffer_put_16(buffer, de->int_attrib); + _zip_buffer_put_32(buffer, de->ext_attrib); + if (de->offset < ZIP_UINT32_MAX) + _zip_buffer_put_32(buffer, (zip_uint32_t)de->offset); + else + _zip_buffer_put_32(buffer, ZIP_UINT32_MAX); } if (!_zip_buffer_ok(buffer)) { @@ -965,31 +1001,31 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) _zip_buffer_free(buffer); if (de->filename) { - if (_zip_string_write(za, de->filename) < 0) { + if (_zip_string_write(za, de->filename) < 0) { _zip_ef_free(ef); - return -1; - } + return -1; + } } if (ef) { - if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) { + if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) { _zip_ef_free(ef); - return -1; - } + return -1; + } } _zip_ef_free(ef); - if (de->extra_fields) { - if (_zip_ef_write(za, de->extra_fields, flags) < 0) { - return -1; - } + if (de->extra_fields && !ZIP_WANT_TORRENTZIP(za)) { + if (_zip_ef_write(za, de->extra_fields, flags) < 0) { + return -1; + } } - if ((flags & ZIP_FL_LOCAL) == 0) { - if (de->comment) { - if (_zip_string_write(za, de->comment) < 0) { - return -1; - } - } + if ((flags & ZIP_FL_LOCAL) == 0 && !ZIP_WANT_TORRENTZIP(za)) { + if (de->comment) { + if (_zip_string_write(za, de->comment) < 0) { + return -1; + } + } } @@ -997,9 +1033,8 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) } -static time_t -_zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) -{ +time_t +_zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) { struct tm tm; memset(&tm, 0, sizeof(tm)); @@ -1007,39 +1042,38 @@ _zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) /* let mktime decide if DST is in effect */ tm.tm_isdst = -1; - tm.tm_year = ((ddate>>9)&127) + 1980 - 1900; - tm.tm_mon = ((ddate>>5)&15) - 1; - tm.tm_mday = ddate&31; + tm.tm_year = ((ddate >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((ddate >> 5) & 15) - 1; + tm.tm_mday = ddate & 31; - tm.tm_hour = (dtime>>11)&31; - tm.tm_min = (dtime>>5)&63; - tm.tm_sec = (dtime<<1)&62; + tm.tm_hour = (dtime >> 11) & 31; + tm.tm_min = (dtime >> 5) & 63; + tm.tm_sec = (dtime << 1) & 62; return mktime(&tm); } static zip_extra_field_t * -_zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) -{ +_zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) { const zip_uint8_t *raw; zip_uint32_t len; zip_buffer_t *buffer; zip_extra_field_t *ef; - if ((raw=_zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) { - /* error already set */ - return NULL; + if ((raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) { + /* error already set */ + return NULL; } - if (len+5 > ZIP_UINT16_MAX) { + if (len + 5 > ZIP_UINT16_MAX) { zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */ return NULL; } - if ((buffer = _zip_buffer_new(NULL, len+5)) == NULL) { - zip_error_set(error, ZIP_ER_MEMORY, 0); - return NULL; + if ((buffer = _zip_buffer_new(NULL, len + 5)) == NULL) { + zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; } _zip_buffer_put_8(buffer, 1); @@ -1060,46 +1094,114 @@ _zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) zip_dirent_t * -_zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) -{ +_zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) { if (error == NULL) - error = &za->error; + error = &za->error; if (idx >= za->nentry) { - zip_error_set(error, ZIP_ER_INVAL, 0); - return NULL; + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; } if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) { - if (za->entry[idx].orig == NULL) { - zip_error_set(error, ZIP_ER_INVAL, 0); - return NULL; - } - if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) { - zip_error_set(error, ZIP_ER_DELETED, 0); - return NULL; - } - return za->entry[idx].orig; + if (za->entry[idx].orig == NULL) { + zip_error_set(error, ZIP_ER_INVAL, 0); + return NULL; + } + if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) { + zip_error_set(error, ZIP_ER_DELETED, 0); + return NULL; + } + return za->entry[idx].orig; } else - return za->entry[idx].changes; + return za->entry[idx].changes; } +void +_zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) { + struct tm *tpm; + struct tm tm; + tpm = zip_localtime(&intime, &tm); + if (tpm == NULL) { + /* if localtime fails, return an arbitrary date (1980-01-01 00:00:00) */ + *ddate = (1 << 5) + 1; + *dtime = 0; + return; + } + if (tpm->tm_year < 80) { + tpm->tm_year = 80; + } + + *ddate = (zip_uint16_t)(((tpm->tm_year + 1900 - 1980) << 9) + ((tpm->tm_mon + 1) << 5) + tpm->tm_mday); + *dtime = (zip_uint16_t)(((tpm->tm_hour) << 11) + ((tpm->tm_min) << 5) + ((tpm->tm_sec) >> 1)); +} void -_zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) -{ - struct tm *tm; +_zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64, zip_uint32_t changed) { + zip_uint16_t length; + + if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) { + zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK; + de->bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask); + } + if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) { + de->int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0); + } + /* manually set attributes are preferred over attributes provided by source */ + if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) { + de->ext_attrib = attributes->external_file_attributes; + } - tm = localtime(&intime); - if (tm->tm_year < 80) { - tm->tm_year = 80; + if (de->comp_method == ZIP_CM_LZMA) { + de->version_needed = 63; } + else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) { + de->version_needed = 51; + } + else if (de->comp_method == ZIP_CM_BZIP2) { + de->version_needed = 46; + } + else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) { + de->version_needed = 45; + } + else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) { + de->version_needed = 20; + } + else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') { + de->version_needed = 20; + } + else { + de->version_needed = 10; + } + + if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) { + de->version_needed = ZIP_MAX(de->version_needed, attributes->version_needed); + } + + de->version_madeby = 63 | (de->version_madeby & 0xff00); + if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) { + de->version_madeby = (de->version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8); + } +} + + +/* _zip_dirent_torrent_normalize(de); + Set values suitable for torrentzip. +*/ + +void zip_dirent_torrentzip_normalize(zip_dirent_t *de) { + de->version_madeby = 0; + de->version_needed = 20; /* 2.0 */ + de->bitflags = 2; /* maximum compression */ + de->comp_method = ZIP_CM_DEFLATE; + de->compression_level = TORRENTZIP_COMPRESSION_FLAGS; + de->disk_number = 0; + de->int_attrib = 0; + de->ext_attrib = 0; - *ddate = (zip_uint16_t)(((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday); - *dtime = (zip_uint16_t)(((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1)); + /* last_mod, extra_fields, and comment are normalized in zip_dirent_write() directly */ - return; } |