CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/ext/libzip/zip_dirent.c
Views: 1401
/*1zip_dirent.c -- read directory entry (local or central), clean dirent2Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner34This file is part of libzip, a library to manipulate ZIP archives.5The authors can be contacted at <[email protected]>67Redistribution and use in source and binary forms, with or without8modification, are permitted provided that the following conditions9are met:101. Redistributions of source code must retain the above copyright11notice, this list of conditions and the following disclaimer.122. Redistributions in binary form must reproduce the above copyright13notice, this list of conditions and the following disclaimer in14the documentation and/or other materials provided with the15distribution.163. The names of the authors may not be used to endorse or promote17products derived from this software without specific prior18written permission.1920THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS21OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED22WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY24DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE26GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS27INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER28IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR29OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.31*/323334#include <stdio.h>35#include <stdlib.h>36#include <string.h>37#include <sys/types.h>38#include <time.h>3940#include "zipint.h"4142static zip_string_t *_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str);43static zip_extra_field_t *_zip_ef_utf8(zip_uint16_t, zip_string_t *, zip_error_t *);44static bool _zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error);454647void48_zip_cdir_free(zip_cdir_t *cd) {49zip_uint64_t i;5051if (!cd)52return;5354for (i = 0; i < cd->nentry; i++)55_zip_entry_finalize(cd->entry + i);56free(cd->entry);57_zip_string_free(cd->comment);58free(cd);59}606162zip_cdir_t *63_zip_cdir_new(zip_uint64_t nentry, zip_error_t *error) {64zip_cdir_t *cd;6566if ((cd = (zip_cdir_t *)malloc(sizeof(*cd))) == NULL) {67zip_error_set(error, ZIP_ER_MEMORY, 0);68return NULL;69}7071cd->entry = NULL;72cd->nentry = cd->nentry_alloc = 0;73cd->size = cd->offset = 0;74cd->comment = NULL;75cd->is_zip64 = false;7677if (!_zip_cdir_grow(cd, nentry, error)) {78_zip_cdir_free(cd);79return NULL;80}8182return cd;83}848586bool87_zip_cdir_grow(zip_cdir_t *cd, zip_uint64_t additional_entries, zip_error_t *error) {88zip_uint64_t i, new_alloc;89zip_entry_t *new_entry;9091if (additional_entries == 0) {92return true;93}9495new_alloc = cd->nentry_alloc + additional_entries;9697if (new_alloc < additional_entries || new_alloc > SIZE_MAX / sizeof(*(cd->entry))) {98zip_error_set(error, ZIP_ER_MEMORY, 0);99return false;100}101102if ((new_entry = (zip_entry_t *)realloc(cd->entry, sizeof(*(cd->entry)) * (size_t)new_alloc)) == NULL) {103zip_error_set(error, ZIP_ER_MEMORY, 0);104return false;105}106107cd->entry = new_entry;108109for (i = cd->nentry; i < new_alloc; i++) {110_zip_entry_init(cd->entry + i);111}112113cd->nentry = cd->nentry_alloc = new_alloc;114115return true;116}117118119zip_int64_t120_zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {121zip_uint64_t offset, size;122zip_string_t *comment;123zip_uint8_t buf[EOCDLEN + EOCD64LEN + EOCD64LOCLEN];124zip_buffer_t *buffer;125zip_int64_t off;126zip_uint64_t i;127bool is_zip64;128int ret;129130if ((off = zip_source_tell_write(za->src)) < 0) {131_zip_error_set_from_source(&za->error, za->src);132return -1;133}134offset = (zip_uint64_t)off;135136is_zip64 = false;137138for (i = 0; i < survivors; i++) {139zip_entry_t *entry = za->entry + filelist[i].idx;140141if ((ret = _zip_dirent_write(za, entry->changes ? entry->changes : entry->orig, ZIP_FL_CENTRAL)) < 0)142return -1;143if (ret)144is_zip64 = true;145}146147if ((off = zip_source_tell_write(za->src)) < 0) {148_zip_error_set_from_source(&za->error, za->src);149return -1;150}151size = (zip_uint64_t)off - offset;152153if (offset > ZIP_UINT32_MAX || survivors > ZIP_UINT16_MAX)154is_zip64 = true;155156157if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {158zip_error_set(&za->error, ZIP_ER_MEMORY, 0);159return -1;160}161162if (is_zip64) {163_zip_buffer_put(buffer, EOCD64_MAGIC, 4);164_zip_buffer_put_64(buffer, EOCD64LEN - 12);165_zip_buffer_put_16(buffer, 45);166_zip_buffer_put_16(buffer, 45);167_zip_buffer_put_32(buffer, 0);168_zip_buffer_put_32(buffer, 0);169_zip_buffer_put_64(buffer, survivors);170_zip_buffer_put_64(buffer, survivors);171_zip_buffer_put_64(buffer, size);172_zip_buffer_put_64(buffer, offset);173_zip_buffer_put(buffer, EOCD64LOC_MAGIC, 4);174_zip_buffer_put_32(buffer, 0);175_zip_buffer_put_64(buffer, offset + size);176_zip_buffer_put_32(buffer, 1);177}178179_zip_buffer_put(buffer, EOCD_MAGIC, 4);180_zip_buffer_put_32(buffer, 0);181_zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors));182_zip_buffer_put_16(buffer, (zip_uint16_t)(survivors >= ZIP_UINT16_MAX ? ZIP_UINT16_MAX : survivors));183_zip_buffer_put_32(buffer, size >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)size);184_zip_buffer_put_32(buffer, offset >= ZIP_UINT32_MAX ? ZIP_UINT32_MAX : (zip_uint32_t)offset);185186comment = za->comment_changed ? za->comment_changes : za->comment_orig;187188_zip_buffer_put_16(buffer, (zip_uint16_t)(comment ? comment->length : 0));189190if (!_zip_buffer_ok(buffer)) {191zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);192_zip_buffer_free(buffer);193return -1;194}195196if (_zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer)) < 0) {197_zip_buffer_free(buffer);198return -1;199}200201_zip_buffer_free(buffer);202203if (comment) {204if (_zip_write(za, comment->raw, comment->length) < 0) {205return -1;206}207}208209return (zip_int64_t)size;210}211212213zip_dirent_t *214_zip_dirent_clone(const zip_dirent_t *sde) {215zip_dirent_t *tde;216217if ((tde = (zip_dirent_t *)malloc(sizeof(*tde))) == NULL)218return NULL;219220if (sde)221memcpy(tde, sde, sizeof(*sde));222else223_zip_dirent_init(tde);224225tde->changed = 0;226tde->cloned = 1;227228return tde;229}230231232void233_zip_dirent_finalize(zip_dirent_t *zde) {234if (!zde->cloned || zde->changed & ZIP_DIRENT_FILENAME) {235_zip_string_free(zde->filename);236zde->filename = NULL;237}238if (!zde->cloned || zde->changed & ZIP_DIRENT_EXTRA_FIELD) {239_zip_ef_free(zde->extra_fields);240zde->extra_fields = NULL;241}242if (!zde->cloned || zde->changed & ZIP_DIRENT_COMMENT) {243_zip_string_free(zde->comment);244zde->comment = NULL;245}246if (!zde->cloned || zde->changed & ZIP_DIRENT_PASSWORD) {247if (zde->password) {248_zip_crypto_clear(zde->password, strlen(zde->password));249}250free(zde->password);251zde->password = NULL;252}253}254255256void257_zip_dirent_free(zip_dirent_t *zde) {258if (zde == NULL)259return;260261_zip_dirent_finalize(zde);262free(zde);263}264265266void267_zip_dirent_init(zip_dirent_t *de) {268de->changed = 0;269de->local_extra_fields_read = 0;270de->cloned = 0;271272de->crc_valid = true;273de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8);274de->version_needed = 10; /* 1.0 */275de->bitflags = 0;276de->comp_method = ZIP_CM_DEFAULT;277de->last_mod = 0;278de->crc = 0;279de->comp_size = 0;280de->uncomp_size = 0;281de->filename = NULL;282de->extra_fields = NULL;283de->comment = NULL;284de->disk_number = 0;285de->int_attrib = 0;286de->ext_attrib = ZIP_EXT_ATTRIB_DEFAULT;287de->offset = 0;288de->compression_level = 0;289de->encryption_method = ZIP_EM_NONE;290de->password = NULL;291}292293294bool295_zip_dirent_needs_zip64(const zip_dirent_t *de, zip_flags_t flags) {296if (de->uncomp_size >= ZIP_UINT32_MAX || de->comp_size >= ZIP_UINT32_MAX || ((flags & ZIP_FL_CENTRAL) && de->offset >= ZIP_UINT32_MAX))297return true;298299return false;300}301302303zip_dirent_t *304_zip_dirent_new(void) {305zip_dirent_t *de;306307if ((de = (zip_dirent_t *)malloc(sizeof(*de))) == NULL)308return NULL;309310_zip_dirent_init(de);311return de;312}313314315/* _zip_dirent_read(zde, fp, bufp, left, localp, error):316Fills the zip directory entry zde.317318If buffer is non-NULL, data is taken from there; otherwise data is read from fp as needed.319320If local is true, it reads a local header instead of a central directory entry.321322Returns size of dirent read if successful. On error, error is filled in and -1 is returned.323*/324325zip_int64_t326_zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, bool local, zip_error_t *error) {327zip_uint8_t buf[CDENTRYSIZE];328zip_uint16_t dostime, dosdate;329zip_uint32_t size, variable_size;330zip_uint16_t filename_len, comment_len, ef_len;331332bool from_buffer = (buffer != NULL);333334size = local ? LENTRYSIZE : CDENTRYSIZE;335336if (buffer) {337if (_zip_buffer_left(buffer) < size) {338zip_error_set(error, ZIP_ER_NOZIP, 0);339return -1;340}341}342else {343if ((buffer = _zip_buffer_new_from_source(src, size, buf, error)) == NULL) {344return -1;345}346}347348if (memcmp(_zip_buffer_get(buffer, 4), (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {349zip_error_set(error, ZIP_ER_NOZIP, 0);350if (!from_buffer) {351_zip_buffer_free(buffer);352}353return -1;354}355356/* convert buffercontents to zip_dirent */357358_zip_dirent_init(zde);359if (!local)360zde->version_madeby = _zip_buffer_get_16(buffer);361else362zde->version_madeby = 0;363zde->version_needed = _zip_buffer_get_16(buffer);364zde->bitflags = _zip_buffer_get_16(buffer);365zde->comp_method = _zip_buffer_get_16(buffer);366367/* convert to time_t */368dostime = _zip_buffer_get_16(buffer);369dosdate = _zip_buffer_get_16(buffer);370zde->last_mod = _zip_d2u_time(dostime, dosdate);371372zde->crc = _zip_buffer_get_32(buffer);373zde->comp_size = _zip_buffer_get_32(buffer);374zde->uncomp_size = _zip_buffer_get_32(buffer);375376filename_len = _zip_buffer_get_16(buffer);377ef_len = _zip_buffer_get_16(buffer);378379if (local) {380comment_len = 0;381zde->disk_number = 0;382zde->int_attrib = 0;383zde->ext_attrib = 0;384zde->offset = 0;385}386else {387comment_len = _zip_buffer_get_16(buffer);388zde->disk_number = _zip_buffer_get_16(buffer);389zde->int_attrib = _zip_buffer_get_16(buffer);390zde->ext_attrib = _zip_buffer_get_32(buffer);391zde->offset = _zip_buffer_get_32(buffer);392}393394if (!_zip_buffer_ok(buffer)) {395zip_error_set(error, ZIP_ER_INTERNAL, 0);396if (!from_buffer) {397_zip_buffer_free(buffer);398}399return -1;400}401402if (zde->bitflags & ZIP_GPBF_ENCRYPTED) {403if (zde->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) {404/* TODO */405zde->encryption_method = ZIP_EM_UNKNOWN;406}407else {408zde->encryption_method = ZIP_EM_TRAD_PKWARE;409}410}411else {412zde->encryption_method = ZIP_EM_NONE;413}414415zde->filename = NULL;416zde->extra_fields = NULL;417zde->comment = NULL;418419variable_size = (zip_uint32_t)filename_len + (zip_uint32_t)ef_len + (zip_uint32_t)comment_len;420421if (from_buffer) {422if (_zip_buffer_left(buffer) < variable_size) {423zip_error_set(error, ZIP_ER_INCONS, 0);424return -1;425}426}427else {428_zip_buffer_free(buffer);429430if ((buffer = _zip_buffer_new_from_source(src, variable_size, NULL, error)) == NULL) {431return -1;432}433}434435if (filename_len) {436zde->filename = _zip_read_string(buffer, src, filename_len, 1, error);437if (!zde->filename) {438if (zip_error_code_zip(error) == ZIP_ER_EOF) {439zip_error_set(error, ZIP_ER_INCONS, 0);440}441if (!from_buffer) {442_zip_buffer_free(buffer);443}444return -1;445}446447if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) {448if (_zip_guess_encoding(zde->filename, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) {449zip_error_set(error, ZIP_ER_INCONS, 0);450if (!from_buffer) {451_zip_buffer_free(buffer);452}453return -1;454}455}456}457458if (ef_len) {459zip_uint8_t *ef = _zip_read_data(buffer, src, ef_len, 0, error);460461if (ef == NULL) {462if (!from_buffer) {463_zip_buffer_free(buffer);464}465return -1;466}467if (!_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, &zde->extra_fields, error)) {468free(ef);469if (!from_buffer) {470_zip_buffer_free(buffer);471}472return -1;473}474free(ef);475if (local)476zde->local_extra_fields_read = 1;477}478479if (comment_len) {480zde->comment = _zip_read_string(buffer, src, comment_len, 0, error);481if (!zde->comment) {482if (!from_buffer) {483_zip_buffer_free(buffer);484}485return -1;486}487if (zde->bitflags & ZIP_GPBF_ENCODING_UTF_8) {488if (_zip_guess_encoding(zde->comment, ZIP_ENCODING_UTF8_KNOWN) == ZIP_ENCODING_ERROR) {489zip_error_set(error, ZIP_ER_INCONS, 0);490if (!from_buffer) {491_zip_buffer_free(buffer);492}493return -1;494}495}496}497498zde->filename = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_NAME, zde->filename);499zde->comment = _zip_dirent_process_ef_utf_8(zde, ZIP_EF_UTF_8_COMMENT, zde->comment);500501/* Zip64 */502503if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) {504zip_uint16_t got_len;505zip_buffer_t *ef_buffer;506const 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);507/* TODO: if got_len == 0 && !ZIP64_EOCD: no error, 0xffffffff is valid value */508if (ef == NULL) {509if (!from_buffer) {510_zip_buffer_free(buffer);511}512return -1;513}514515if ((ef_buffer = _zip_buffer_new((zip_uint8_t *)ef, got_len)) == NULL) {516zip_error_set(error, ZIP_ER_MEMORY, 0);517if (!from_buffer) {518_zip_buffer_free(buffer);519}520return -1;521}522523if (zde->uncomp_size == ZIP_UINT32_MAX) {524zde->uncomp_size = _zip_buffer_get_64(ef_buffer);525}526else if (local) {527/* From appnote.txt: This entry in the Local header MUST528include BOTH original and compressed file size fields. */529(void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */530}531if (zde->comp_size == ZIP_UINT32_MAX) {532zde->comp_size = _zip_buffer_get_64(ef_buffer);533}534if (!local) {535if (zde->offset == ZIP_UINT32_MAX) {536zde->offset = _zip_buffer_get_64(ef_buffer);537}538if (zde->disk_number == ZIP_UINT16_MAX) {539zde->disk_number = _zip_buffer_get_32(ef_buffer);540}541}542543if (!_zip_buffer_eof(ef_buffer)) {544/* accept additional fields if values match */545bool ok = true;546switch (got_len) {547case 28:548_zip_buffer_set_offset(ef_buffer, 24);549if (zde->disk_number != _zip_buffer_get_32(ef_buffer)) {550ok = false;551}552/* fallthrough */553case 24:554_zip_buffer_set_offset(ef_buffer, 0);555if ((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))) {556ok = false;557}558break;559560default:561ok = false;562}563if (!ok) {564zip_error_set(error, ZIP_ER_INCONS, 0);565_zip_buffer_free(ef_buffer);566if (!from_buffer) {567_zip_buffer_free(buffer);568}569return -1;570}571}572_zip_buffer_free(ef_buffer);573}574575if (!_zip_buffer_ok(buffer)) {576zip_error_set(error, ZIP_ER_INTERNAL, 0);577if (!from_buffer) {578_zip_buffer_free(buffer);579}580return -1;581}582if (!from_buffer) {583_zip_buffer_free(buffer);584}585586/* zip_source_seek / zip_source_tell don't support values > ZIP_INT64_MAX */587if (zde->offset > ZIP_INT64_MAX) {588zip_error_set(error, ZIP_ER_SEEK, EFBIG);589return -1;590}591592if (!_zip_dirent_process_winzip_aes(zde, error)) {593return -1;594}595596zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields);597598return (zip_int64_t)size + (zip_int64_t)variable_size;599}600601602static zip_string_t *603_zip_dirent_process_ef_utf_8(const zip_dirent_t *de, zip_uint16_t id, zip_string_t *str) {604zip_uint16_t ef_len;605zip_uint32_t ef_crc;606zip_buffer_t *buffer;607608const zip_uint8_t *ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, id, 0, ZIP_EF_BOTH, NULL);609610if (ef == NULL || ef_len < 5 || ef[0] != 1) {611return str;612}613614if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) {615return str;616}617618_zip_buffer_get_8(buffer);619ef_crc = _zip_buffer_get_32(buffer);620621if (_zip_string_crc32(str) == ef_crc) {622zip_uint16_t len = (zip_uint16_t)_zip_buffer_left(buffer);623zip_string_t *ef_str = _zip_string_new(_zip_buffer_get(buffer, len), len, ZIP_FL_ENC_UTF_8, NULL);624625if (ef_str != NULL) {626_zip_string_free(str);627str = ef_str;628}629}630631_zip_buffer_free(buffer);632633return str;634}635636637static bool638_zip_dirent_process_winzip_aes(zip_dirent_t *de, zip_error_t *error) {639zip_uint16_t ef_len;640zip_buffer_t *buffer;641const zip_uint8_t *ef;642bool crc_valid;643zip_uint16_t enc_method;644645646if (de->comp_method != ZIP_CM_WINZIP_AES) {647return true;648}649650ef = _zip_ef_get_by_id(de->extra_fields, &ef_len, ZIP_EF_WINZIP_AES, 0, ZIP_EF_BOTH, NULL);651652if (ef == NULL || ef_len < 7) {653zip_error_set(error, ZIP_ER_INCONS, 0);654return false;655}656657if ((buffer = _zip_buffer_new((zip_uint8_t *)ef, ef_len)) == NULL) {658zip_error_set(error, ZIP_ER_INTERNAL, 0);659return false;660}661662/* version */663664crc_valid = true;665switch (_zip_buffer_get_16(buffer)) {666case 1:667break;668669case 2:670if (de->uncomp_size < 20 /* TODO: constant */) {671crc_valid = false;672}673break;674675default:676zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);677_zip_buffer_free(buffer);678return false;679}680681/* vendor */682if (memcmp(_zip_buffer_get(buffer, 2), "AE", 2) != 0) {683zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);684_zip_buffer_free(buffer);685return false;686}687688/* mode */689switch (_zip_buffer_get_8(buffer)) {690case 1:691enc_method = ZIP_EM_AES_128;692break;693case 2:694enc_method = ZIP_EM_AES_192;695break;696case 3:697enc_method = ZIP_EM_AES_256;698break;699default:700zip_error_set(error, ZIP_ER_ENCRNOTSUPP, 0);701_zip_buffer_free(buffer);702return false;703}704705if (ef_len != 7) {706zip_error_set(error, ZIP_ER_INCONS, 0);707_zip_buffer_free(buffer);708return false;709}710711de->crc_valid = crc_valid;712de->encryption_method = enc_method;713de->comp_method = _zip_buffer_get_16(buffer);714715_zip_buffer_free(buffer);716return true;717}718719720zip_int32_t721_zip_dirent_size(zip_source_t *src, zip_uint16_t flags, zip_error_t *error) {722zip_int32_t size;723bool local = (flags & ZIP_EF_LOCAL) != 0;724int i;725zip_uint8_t b[6];726zip_buffer_t *buffer;727728size = local ? LENTRYSIZE : CDENTRYSIZE;729730if (zip_source_seek(src, local ? 26 : 28, SEEK_CUR) < 0) {731_zip_error_set_from_source(error, src);732return -1;733}734735if ((buffer = _zip_buffer_new_from_source(src, local ? 4 : 6, b, error)) == NULL) {736return -1;737}738739for (i = 0; i < (local ? 2 : 3); i++) {740size += _zip_buffer_get_16(buffer);741}742743if (!_zip_buffer_eof(buffer)) {744zip_error_set(error, ZIP_ER_INTERNAL, 0);745_zip_buffer_free(buffer);746return -1;747}748749_zip_buffer_free(buffer);750return size;751}752753754/* _zip_dirent_write755Writes zip directory entry.756757If flags & ZIP_EF_LOCAL, it writes a local header instead of a central758directory entry. If flags & ZIP_EF_FORCE_ZIP64, a ZIP64 extra field is written, even if not needed.759760Returns 0 if successful, 1 if successful and wrote ZIP64 extra field. On error, error is filled in and -1 is761returned.762*/763764int765_zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) {766zip_uint16_t dostime, dosdate;767zip_encoding_type_t com_enc, name_enc;768zip_extra_field_t *ef;769zip_extra_field_t *ef64;770zip_uint32_t ef_total_size;771bool is_zip64;772bool is_really_zip64;773bool is_winzip_aes;774zip_uint8_t buf[CDENTRYSIZE];775zip_buffer_t *buffer;776777ef = NULL;778779name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN);780com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN);781782if ((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))783de->bitflags |= ZIP_GPBF_ENCODING_UTF_8;784else {785de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCODING_UTF_8;786if (name_enc == ZIP_ENCODING_UTF8_KNOWN) {787ef = _zip_ef_utf8(ZIP_EF_UTF_8_NAME, de->filename, &za->error);788if (ef == NULL)789return -1;790}791if ((flags & ZIP_FL_LOCAL) == 0 && com_enc == ZIP_ENCODING_UTF8_KNOWN) {792zip_extra_field_t *ef2 = _zip_ef_utf8(ZIP_EF_UTF_8_COMMENT, de->comment, &za->error);793if (ef2 == NULL) {794_zip_ef_free(ef);795return -1;796}797ef2->next = ef;798ef = ef2;799}800}801802if (de->encryption_method == ZIP_EM_NONE) {803de->bitflags &= (zip_uint16_t)~ZIP_GPBF_ENCRYPTED;804}805else {806de->bitflags |= (zip_uint16_t)ZIP_GPBF_ENCRYPTED;807}808809is_really_zip64 = _zip_dirent_needs_zip64(de, flags);810is_zip64 = (flags & (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL | ZIP_FL_FORCE_ZIP64) || is_really_zip64;811is_winzip_aes = de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256;812813if (is_zip64) {814zip_uint8_t ef_zip64[EFZIP64SIZE];815zip_buffer_t *ef_buffer = _zip_buffer_new(ef_zip64, sizeof(ef_zip64));816if (ef_buffer == NULL) {817zip_error_set(&za->error, ZIP_ER_MEMORY, 0);818_zip_ef_free(ef);819return -1;820}821822if (flags & ZIP_FL_LOCAL) {823if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX) {824_zip_buffer_put_64(ef_buffer, de->uncomp_size);825_zip_buffer_put_64(ef_buffer, de->comp_size);826}827}828else {829if ((flags & ZIP_FL_FORCE_ZIP64) || de->comp_size > ZIP_UINT32_MAX || de->uncomp_size > ZIP_UINT32_MAX || de->offset > ZIP_UINT32_MAX) {830if (de->uncomp_size >= ZIP_UINT32_MAX) {831_zip_buffer_put_64(ef_buffer, de->uncomp_size);832}833if (de->comp_size >= ZIP_UINT32_MAX) {834_zip_buffer_put_64(ef_buffer, de->comp_size);835}836if (de->offset >= ZIP_UINT32_MAX) {837_zip_buffer_put_64(ef_buffer, de->offset);838}839}840}841842if (!_zip_buffer_ok(ef_buffer)) {843zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);844_zip_buffer_free(ef_buffer);845_zip_ef_free(ef);846return -1;847}848849ef64 = _zip_ef_new(ZIP_EF_ZIP64, (zip_uint16_t)(_zip_buffer_offset(ef_buffer)), ef_zip64, ZIP_EF_BOTH);850_zip_buffer_free(ef_buffer);851ef64->next = ef;852ef = ef64;853}854855if (is_winzip_aes) {856zip_uint8_t data[EF_WINZIP_AES_SIZE];857zip_buffer_t *ef_buffer = _zip_buffer_new(data, sizeof(data));858zip_extra_field_t *ef_winzip;859860if (ef_buffer == NULL) {861zip_error_set(&za->error, ZIP_ER_MEMORY, 0);862_zip_ef_free(ef);863return -1;864}865866_zip_buffer_put_16(ef_buffer, 2);867_zip_buffer_put(ef_buffer, "AE", 2);868_zip_buffer_put_8(ef_buffer, (zip_uint8_t)(de->encryption_method & 0xff));869_zip_buffer_put_16(ef_buffer, (zip_uint16_t)de->comp_method);870871if (!_zip_buffer_ok(ef_buffer)) {872zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);873_zip_buffer_free(ef_buffer);874_zip_ef_free(ef);875return -1;876}877878ef_winzip = _zip_ef_new(ZIP_EF_WINZIP_AES, EF_WINZIP_AES_SIZE, data, ZIP_EF_BOTH);879_zip_buffer_free(ef_buffer);880ef_winzip->next = ef;881ef = ef_winzip;882}883884if ((buffer = _zip_buffer_new(buf, sizeof(buf))) == NULL) {885zip_error_set(&za->error, ZIP_ER_MEMORY, 0);886_zip_ef_free(ef);887return -1;888}889890_zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4);891892if ((flags & ZIP_FL_LOCAL) == 0) {893_zip_buffer_put_16(buffer, de->version_madeby);894}895_zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed));896_zip_buffer_put_16(buffer, de->bitflags);897if (is_winzip_aes) {898_zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES);899}900else {901_zip_buffer_put_16(buffer, (zip_uint16_t)de->comp_method);902}903904_zip_u2d_time(de->last_mod, &dostime, &dosdate);905_zip_buffer_put_16(buffer, dostime);906_zip_buffer_put_16(buffer, dosdate);907908if (is_winzip_aes && de->uncomp_size < 20) {909_zip_buffer_put_32(buffer, 0);910}911else {912_zip_buffer_put_32(buffer, de->crc);913}914915if (((flags & ZIP_FL_LOCAL) == ZIP_FL_LOCAL) && ((de->comp_size >= ZIP_UINT32_MAX) || (de->uncomp_size >= ZIP_UINT32_MAX))) {916/* In local headers, if a ZIP64 EF is written, it MUST contain917* both compressed and uncompressed sizes (even if one of the918* two is smaller than 0xFFFFFFFF); on the other hand, those919* may only appear when the corresponding standard entry is920* 0xFFFFFFFF. (appnote.txt 4.5.3) */921_zip_buffer_put_32(buffer, ZIP_UINT32_MAX);922_zip_buffer_put_32(buffer, ZIP_UINT32_MAX);923}924else {925if (de->comp_size < ZIP_UINT32_MAX) {926_zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);927}928else {929_zip_buffer_put_32(buffer, ZIP_UINT32_MAX);930}931if (de->uncomp_size < ZIP_UINT32_MAX) {932_zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);933}934else {935_zip_buffer_put_32(buffer, ZIP_UINT32_MAX);936}937}938939_zip_buffer_put_16(buffer, _zip_string_length(de->filename));940/* TODO: check for overflow */941ef_total_size = (zip_uint32_t)_zip_ef_size(de->extra_fields, flags) + (zip_uint32_t)_zip_ef_size(ef, ZIP_EF_BOTH);942_zip_buffer_put_16(buffer, (zip_uint16_t)ef_total_size);943944if ((flags & ZIP_FL_LOCAL) == 0) {945_zip_buffer_put_16(buffer, _zip_string_length(de->comment));946_zip_buffer_put_16(buffer, (zip_uint16_t)de->disk_number);947_zip_buffer_put_16(buffer, de->int_attrib);948_zip_buffer_put_32(buffer, de->ext_attrib);949if (de->offset < ZIP_UINT32_MAX)950_zip_buffer_put_32(buffer, (zip_uint32_t)de->offset);951else952_zip_buffer_put_32(buffer, ZIP_UINT32_MAX);953}954955if (!_zip_buffer_ok(buffer)) {956zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);957_zip_buffer_free(buffer);958_zip_ef_free(ef);959return -1;960}961962if (_zip_write(za, buf, _zip_buffer_offset(buffer)) < 0) {963_zip_buffer_free(buffer);964_zip_ef_free(ef);965return -1;966}967968_zip_buffer_free(buffer);969970if (de->filename) {971if (_zip_string_write(za, de->filename) < 0) {972_zip_ef_free(ef);973return -1;974}975}976977if (ef) {978if (_zip_ef_write(za, ef, ZIP_EF_BOTH) < 0) {979_zip_ef_free(ef);980return -1;981}982}983_zip_ef_free(ef);984if (de->extra_fields) {985if (_zip_ef_write(za, de->extra_fields, flags) < 0) {986return -1;987}988}989990if ((flags & ZIP_FL_LOCAL) == 0) {991if (de->comment) {992if (_zip_string_write(za, de->comment) < 0) {993return -1;994}995}996}997998999return is_zip64;1000}100110021003time_t1004_zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) {1005struct tm tm;10061007memset(&tm, 0, sizeof(tm));10081009/* let mktime decide if DST is in effect */1010tm.tm_isdst = -1;10111012tm.tm_year = ((ddate >> 9) & 127) + 1980 - 1900;1013tm.tm_mon = ((ddate >> 5) & 15) - 1;1014tm.tm_mday = ddate & 31;10151016tm.tm_hour = (dtime >> 11) & 31;1017tm.tm_min = (dtime >> 5) & 63;1018tm.tm_sec = (dtime << 1) & 62;10191020return mktime(&tm);1021}102210231024static zip_extra_field_t *1025_zip_ef_utf8(zip_uint16_t id, zip_string_t *str, zip_error_t *error) {1026const zip_uint8_t *raw;1027zip_uint32_t len;1028zip_buffer_t *buffer;1029zip_extra_field_t *ef;10301031if ((raw = _zip_string_get(str, &len, ZIP_FL_ENC_RAW, NULL)) == NULL) {1032/* error already set */1033return NULL;1034}10351036if (len + 5 > ZIP_UINT16_MAX) {1037zip_error_set(error, ZIP_ER_INVAL, 0); /* TODO: better error code? */1038return NULL;1039}10401041if ((buffer = _zip_buffer_new(NULL, len + 5)) == NULL) {1042zip_error_set(error, ZIP_ER_MEMORY, 0);1043return NULL;1044}10451046_zip_buffer_put_8(buffer, 1);1047_zip_buffer_put_32(buffer, _zip_string_crc32(str));1048_zip_buffer_put(buffer, raw, len);10491050if (!_zip_buffer_ok(buffer)) {1051zip_error_set(error, ZIP_ER_INTERNAL, 0);1052_zip_buffer_free(buffer);1053return NULL;1054}10551056ef = _zip_ef_new(id, (zip_uint16_t)(_zip_buffer_offset(buffer)), _zip_buffer_data(buffer), ZIP_EF_BOTH);1057_zip_buffer_free(buffer);10581059return ef;1060}106110621063zip_dirent_t *1064_zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *error) {1065if (error == NULL)1066error = &za->error;10671068if (idx >= za->nentry) {1069zip_error_set(error, ZIP_ER_INVAL, 0);1070return NULL;1071}10721073if ((flags & ZIP_FL_UNCHANGED) || za->entry[idx].changes == NULL) {1074if (za->entry[idx].orig == NULL) {1075zip_error_set(error, ZIP_ER_INVAL, 0);1076return NULL;1077}1078if (za->entry[idx].deleted && (flags & ZIP_FL_UNCHANGED) == 0) {1079zip_error_set(error, ZIP_ER_DELETED, 0);1080return NULL;1081}1082return za->entry[idx].orig;1083}1084else1085return za->entry[idx].changes;1086}108710881089void1090_zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) {1091struct tm *tpm;10921093#ifdef HAVE_LOCALTIME_R1094struct tm tm;1095tpm = localtime_r(&intime, &tm);1096#else1097tpm = localtime(&intime);1098#endif1099if (tpm == NULL) {1100/* if localtime() fails, return an arbitrary date (1980-01-01 00:00:00) */1101*ddate = (1 << 5) + 1;1102*dtime = 0;1103return;1104}1105if (tpm->tm_year < 80) {1106tpm->tm_year = 80;1107}11081109*ddate = (zip_uint16_t)(((tpm->tm_year + 1900 - 1980) << 9) + ((tpm->tm_mon + 1) << 5) + tpm->tm_mday);1110*dtime = (zip_uint16_t)(((tpm->tm_hour) << 11) + ((tpm->tm_min) << 5) + ((tpm->tm_sec) >> 1));11111112return;1113}111411151116void1117_zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64, zip_uint32_t changed) {1118zip_uint16_t length;11191120if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {1121zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;1122de->bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask);1123}1124if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) {1125de->int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0);1126}1127/* manually set attributes are preferred over attributes provided by source */1128if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) {1129de->ext_attrib = attributes->external_file_attributes;1130}11311132if (de->comp_method == ZIP_CM_LZMA) {1133de->version_needed = 63;1134}1135else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) {1136de->version_needed = 51;1137}1138else if (de->comp_method == ZIP_CM_BZIP2) {1139de->version_needed = 46;1140}1141else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) {1142de->version_needed = 45;1143}1144else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) {1145de->version_needed = 20;1146}1147else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') {1148de->version_needed = 20;1149}1150else {1151de->version_needed = 10;1152}11531154if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {1155de->version_needed = ZIP_MAX(de->version_needed, attributes->version_needed);1156}11571158de->version_madeby = 63 | (de->version_madeby & 0xff00);1159if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) {1160de->version_madeby = (de->version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8);1161}1162}116311641165