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_close.c
Views: 1401
/*1zip_close.c -- close zip archive and update changes2Copyright (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 "zipint.h"3536#include <stdio.h>37#include <stdlib.h>38#ifdef _WIN3239#include <fcntl.h>40#include <io.h>41#endif424344static int add_data(zip_t *, zip_source_t *, zip_dirent_t *, zip_uint32_t);45static int copy_data(zip_t *, zip_uint64_t);46static int copy_source(zip_t *, zip_source_t *, zip_int64_t);47static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);48static int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64);4950ZIP_EXTERN int51zip_close(zip_t *za) {52zip_uint64_t i, j, survivors, unchanged_offset;53zip_int64_t off;54int error;55zip_filelist_t *filelist;56int changed;5758if (za == NULL)59return -1;6061changed = _zip_changed(za, &survivors);6263/* don't create zip files with no entries */64if (survivors == 0) {65if ((za->open_flags & ZIP_TRUNCATE) || changed) {66if (zip_source_remove(za->src) < 0) {67if (!((zip_error_code_zip(zip_source_error(za->src)) == ZIP_ER_REMOVE) && (zip_error_code_system(zip_source_error(za->src)) == ENOENT))) {68_zip_error_set_from_source(&za->error, za->src);69return -1;70}71}72}73zip_discard(za);74return 0;75}7677if (!changed) {78zip_discard(za);79return 0;80}8182if (survivors > za->nentry) {83zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);84return -1;85}8687if ((filelist = (zip_filelist_t *)malloc(sizeof(filelist[0]) * (size_t)survivors)) == NULL)88return -1;8990unchanged_offset = ZIP_UINT64_MAX;91/* create list of files with index into original archive */92for (i = j = 0; i < za->nentry; i++) {93if (za->entry[i].orig != NULL && ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {94unchanged_offset = ZIP_MIN(unchanged_offset, za->entry[i].orig->offset);95}96if (za->entry[i].deleted) {97continue;98}99100if (j >= survivors) {101free(filelist);102zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);103return -1;104}105106filelist[j].idx = i;107j++;108}109if (j < survivors) {110free(filelist);111zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);112return -1;113}114115if ((zip_source_supports(za->src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING)) == 0) {116unchanged_offset = 0;117}118else {119if (unchanged_offset == ZIP_UINT64_MAX) {120/* we're keeping all file data, find the end of the last one */121zip_uint64_t last_index = ZIP_UINT64_MAX;122unchanged_offset = 0;123124for (i = 0; i < za->nentry; i++) {125if (za->entry[i].orig != NULL) {126if (za->entry[i].orig->offset >= unchanged_offset) {127unchanged_offset = za->entry[i].orig->offset;128last_index = i;129}130}131}132if (last_index != ZIP_UINT64_MAX) {133if ((unchanged_offset = _zip_file_get_end(za, last_index, &za->error)) == 0) {134free(filelist);135return -1;136}137}138}139if (unchanged_offset > 0) {140if (zip_source_begin_write_cloning(za->src, unchanged_offset) < 0) {141/* cloning not supported, need to copy everything */142unchanged_offset = 0;143}144}145}146if (unchanged_offset == 0) {147if (zip_source_begin_write(za->src) < 0) {148_zip_error_set_from_source(&za->error, za->src);149free(filelist);150return -1;151}152}153154if (_zip_progress_start(za->progress) != 0) {155zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);156zip_source_rollback_write(za->src);157free(filelist);158return -1;159}160error = 0;161for (j = 0; j < survivors; j++) {162int new_data;163zip_entry_t *entry;164zip_dirent_t *de;165166if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) {167zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);168error = 1;169break;170}171172i = filelist[j].idx;173entry = za->entry + i;174175if (entry->orig != NULL && entry->orig->offset < unchanged_offset) {176/* already implicitly copied by cloning */177continue;178}179180new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD) || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_ENCRYPTION_METHOD));181182/* create new local directory entry */183if (entry->changes == NULL) {184if ((entry->changes = _zip_dirent_clone(entry->orig)) == NULL) {185zip_error_set(&za->error, ZIP_ER_MEMORY, 0);186error = 1;187break;188}189}190de = entry->changes;191192if (_zip_read_local_ef(za, i) < 0) {193error = 1;194break;195}196197if ((off = zip_source_tell_write(za->src)) < 0) {198_zip_error_set_from_source(&za->error, za->src);199error = 1;200break;201}202de->offset = (zip_uint64_t)off;203204if (new_data) {205zip_source_t *zs;206207zs = NULL;208if (!ZIP_ENTRY_DATA_CHANGED(entry)) {209if ((zs = _zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, 0, NULL)) == NULL) {210error = 1;211break;212}213}214215/* add_data writes dirent */216if (add_data(za, zs ? zs : entry->source, de, entry->changes ? entry->changes->changed : 0) < 0) {217error = 1;218if (zs)219zip_source_free(zs);220break;221}222if (zs)223zip_source_free(zs);224}225else {226zip_uint64_t offset;227228if (de->encryption_method != ZIP_EM_TRAD_PKWARE) {229/* when copying data, all sizes are known -> no data descriptor needed */230/* except for PKWare encryption, where removing the data descriptor breaks password validation */231de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;232}233if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {234error = 1;235break;236}237if ((offset = _zip_file_get_offset(za, i, &za->error)) == 0) {238error = 1;239break;240}241if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {242_zip_error_set_from_source(&za->error, za->src);243error = 1;244break;245}246if (copy_data(za, de->comp_size) < 0) {247error = 1;248break;249}250251if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {252if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) {253error = 1;254break;255}256}257}258}259260if (!error) {261if (write_cdir(za, filelist, survivors) < 0)262error = 1;263}264265free(filelist);266267if (!error) {268if (zip_source_commit_write(za->src) != 0) {269_zip_error_set_from_source(&za->error, za->src);270error = 1;271}272_zip_progress_end(za->progress);273}274275if (error) {276zip_source_rollback_write(za->src);277return -1;278}279280zip_discard(za);281282return 0;283}284285286static int287add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) {288zip_int64_t offstart, offdata, offend, data_length;289zip_stat_t st;290zip_file_attributes_t attributes;291zip_source_t *src_final, *src_tmp;292int ret;293int is_zip64;294zip_flags_t flags;295bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;296297if (zip_source_stat(src, &st) < 0) {298_zip_error_set_from_source(&za->error, src);299return -1;300}301302if ((st.valid & ZIP_STAT_COMP_METHOD) == 0) {303st.valid |= ZIP_STAT_COMP_METHOD;304st.comp_method = ZIP_CM_STORE;305}306307if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)308de->comp_method = st.comp_method;309else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {310st.valid |= ZIP_STAT_COMP_SIZE;311st.comp_size = st.size;312}313else {314/* we'll recompress */315st.valid &= ~ZIP_STAT_COMP_SIZE;316}317318if ((st.valid & ZIP_STAT_ENCRYPTION_METHOD) == 0) {319st.valid |= ZIP_STAT_ENCRYPTION_METHOD;320st.encryption_method = ZIP_EM_NONE;321}322323flags = ZIP_EF_LOCAL;324325if ((st.valid & ZIP_STAT_SIZE) == 0) {326flags |= ZIP_FL_FORCE_ZIP64;327data_length = -1;328}329else {330de->uncomp_size = st.size;331/* this is technically incorrect (copy_source counts compressed data), but it's the best we have */332data_length = (zip_int64_t)st.size;333334if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {335zip_uint64_t max_size;336337switch (ZIP_CM_ACTUAL(de->comp_method)) {338case ZIP_CM_BZIP2:339/* computed by looking at increase of 10 random files of size 1MB when340* compressed with bzip2, rounded up: 1.006 */341max_size = 4269351188u;342break;343344case ZIP_CM_DEFLATE:345/* max deflate size increase: size + ceil(size/16k)*5+6 */346max_size = 4293656963u;347break;348349case ZIP_CM_STORE:350max_size = 0xffffffffu;351break;352353default:354max_size = 0;355}356357if (st.size > max_size) {358flags |= ZIP_FL_FORCE_ZIP64;359}360}361else362de->comp_size = st.comp_size;363}364365if ((offstart = zip_source_tell_write(za->src)) < 0) {366_zip_error_set_from_source(&za->error, za->src);367return -1;368}369370/* as long as we don't support non-seekable output, clear data descriptor bit */371de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;372if ((is_zip64 = _zip_dirent_write(za, de, flags)) < 0) {373return -1;374}375376needs_recompress = st.comp_method != ZIP_CM_ACTUAL(de->comp_method);377needs_decompress = needs_recompress && (st.comp_method != ZIP_CM_STORE);378needs_crc = (st.comp_method == ZIP_CM_STORE) || needs_decompress;379needs_compress = needs_recompress && (de->comp_method != ZIP_CM_STORE);380381needs_reencrypt = needs_recompress || (de->changed & ZIP_DIRENT_PASSWORD) || (de->encryption_method != st.encryption_method);382needs_decrypt = needs_reencrypt && (st.encryption_method != ZIP_EM_NONE);383needs_encrypt = needs_reencrypt && (de->encryption_method != ZIP_EM_NONE);384385src_final = src;386zip_source_keep(src_final);387388if (needs_decrypt) {389zip_encryption_implementation impl;390391if ((impl = _zip_get_encryption_implementation(st.encryption_method, ZIP_CODEC_DECODE)) == NULL) {392zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);393zip_source_free(src_final);394return -1;395}396if ((src_tmp = impl(za, src_final, st.encryption_method, ZIP_CODEC_DECODE, za->default_password)) == NULL) {397/* error set by impl */398zip_source_free(src_final);399return -1;400}401402zip_source_free(src_final);403src_final = src_tmp;404}405406if (needs_decompress) {407if ((src_tmp = zip_source_decompress(za, src_final, st.comp_method)) == NULL) {408zip_source_free(src_final);409return -1;410}411412zip_source_free(src_final);413src_final = src_tmp;414}415416if (needs_crc) {417if ((src_tmp = zip_source_crc(za, src_final, 0)) == NULL) {418zip_source_free(src_final);419return -1;420}421422zip_source_free(src_final);423src_final = src_tmp;424}425426if (needs_compress) {427if ((src_tmp = zip_source_compress(za, src_final, de->comp_method, de->compression_level)) == NULL) {428zip_source_free(src_final);429return -1;430}431432zip_source_free(src_final);433src_final = src_tmp;434}435436437if (needs_encrypt) {438zip_encryption_implementation impl;439const char *password = NULL;440441if (de->password) {442password = de->password;443}444else if (za->default_password) {445password = za->default_password;446}447448if ((impl = _zip_get_encryption_implementation(de->encryption_method, ZIP_CODEC_ENCODE)) == NULL) {449zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);450zip_source_free(src_final);451return -1;452}453if ((src_tmp = impl(za, src_final, de->encryption_method, ZIP_CODEC_ENCODE, password)) == NULL) {454/* error set by impl */455zip_source_free(src_final);456return -1;457}458if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {459de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;460}461462zip_source_free(src_final);463src_final = src_tmp;464}465466467if ((offdata = zip_source_tell_write(za->src)) < 0) {468_zip_error_set_from_source(&za->error, za->src);469return -1;470}471472ret = copy_source(za, src_final, data_length);473474if (zip_source_stat(src_final, &st) < 0) {475_zip_error_set_from_source(&za->error, src_final);476ret = -1;477}478479if (zip_source_get_file_attributes(src_final, &attributes) != 0) {480_zip_error_set_from_source(&za->error, src_final);481ret = -1;482}483484zip_source_free(src_final);485486if (ret < 0) {487return -1;488}489490if ((offend = zip_source_tell_write(za->src)) < 0) {491_zip_error_set_from_source(&za->error, za->src);492return -1;493}494495if (zip_source_seek_write(za->src, offstart, SEEK_SET) < 0) {496_zip_error_set_from_source(&za->error, za->src);497return -1;498}499500if ((st.valid & (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) != (ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE)) {501zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);502return -1;503}504505if ((de->changed & ZIP_DIRENT_LAST_MOD) == 0) {506if (st.valid & ZIP_STAT_MTIME)507de->last_mod = st.mtime;508else509time(&de->last_mod);510}511de->comp_method = st.comp_method;512de->crc = st.crc;513de->uncomp_size = st.size;514de->comp_size = (zip_uint64_t)(offend - offdata);515_zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed);516517if ((ret = _zip_dirent_write(za, de, flags)) < 0)518return -1;519520if (is_zip64 != ret) {521/* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */522zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);523return -1;524}525526if (zip_source_seek_write(za->src, offend, SEEK_SET) < 0) {527_zip_error_set_from_source(&za->error, za->src);528return -1;529}530531if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {532if (write_data_descriptor(za, de, is_zip64) < 0) {533return -1;534}535}536537return 0;538}539540541static int542copy_data(zip_t *za, zip_uint64_t len) {543DEFINE_BYTE_ARRAY(buf, BUFSIZE);544size_t n;545double total = (double)len;546547if (!byte_array_init(buf, BUFSIZE)) {548zip_error_set(&za->error, ZIP_ER_MEMORY, 0);549return -1;550}551552while (len > 0) {553n = len > BUFSIZE ? BUFSIZE : len;554if (_zip_read(za->src, buf, n, &za->error) < 0) {555byte_array_fini(buf);556return -1;557}558559if (_zip_write(za, buf, n) < 0) {560byte_array_fini(buf);561return -1;562}563564len -= n;565566if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) {567zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);568return -1;569}570}571572byte_array_fini(buf);573return 0;574}575576577static int578copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {579DEFINE_BYTE_ARRAY(buf, BUFSIZE);580zip_int64_t n, current;581int ret;582583if (zip_source_open(src) < 0) {584_zip_error_set_from_source(&za->error, src);585return -1;586}587588if (!byte_array_init(buf, BUFSIZE)) {589zip_error_set(&za->error, ZIP_ER_MEMORY, 0);590return -1;591}592593ret = 0;594current = 0;595while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {596if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {597ret = -1;598break;599}600if (n == BUFSIZE && za->progress && data_length > 0) {601current += n;602if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) {603zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);604ret = -1;605break;606}607}608}609610if (n < 0) {611_zip_error_set_from_source(&za->error, src);612ret = -1;613}614615byte_array_fini(buf);616617zip_source_close(src);618619return ret;620}621622static int623write_cdir(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors) {624zip_int64_t cd_start, end, size;625626if ((cd_start = zip_source_tell_write(za->src)) < 0) {627return -1;628}629630if ((size = _zip_cdir_write(za, filelist, survivors)) < 0) {631return -1;632}633634if ((end = zip_source_tell_write(za->src)) < 0) {635return -1;636}637638return 0;639}640641642int643_zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {644int changed;645zip_uint64_t i, survivors;646647changed = 0;648survivors = 0;649650if (za->comment_changed || za->ch_flags != za->flags) {651changed = 1;652}653654for (i = 0; i < za->nentry; i++) {655if (ZIP_ENTRY_HAS_CHANGES(&za->entry[i])) {656changed = 1;657}658if (!za->entry[i].deleted) {659survivors++;660}661}662663if (survivorsp) {664*survivorsp = survivors;665}666667return changed;668}669670static int671write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {672zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);673int ret = 0;674675if (buffer == NULL) {676zip_error_set(&za->error, ZIP_ER_MEMORY, 0);677return -1;678}679680_zip_buffer_put(buffer, DATADES_MAGIC, 4);681_zip_buffer_put_32(buffer, de->crc);682if (is_zip64) {683_zip_buffer_put_64(buffer, de->comp_size);684_zip_buffer_put_64(buffer, de->uncomp_size);685}686else {687_zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);688_zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);689}690691if (!_zip_buffer_ok(buffer)) {692zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);693ret = -1;694}695else {696ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));697}698699_zip_buffer_free(buffer);700701return ret;702}703704705