2023-08-24 02:30:24 +00:00
/*
zip_close . c - - close zip archive and update changes
2024-09-28 00:48:55 +00:00
Copyright ( C ) 1999 - 2024 Dieter Baron and Thomas Klausner
2023-08-24 02:30:24 +00:00
This file is part of libzip , a library to manipulate ZIP archives .
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
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in
the documentation and / or other materials provided with the
distribution .
3. The names of the authors may not be used to endorse or promote
products derived from this software without specific prior
written permission .
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ` ` AS IS ' ' AND ANY EXPRESS
OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER
IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR
OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "zipint.h"
# include <stdio.h>
# include <stdlib.h>
# ifdef _WIN32
# include <fcntl.h>
# include <io.h>
# endif
static int add_data ( zip_t * , zip_source_t * , zip_dirent_t * , zip_uint32_t ) ;
static int copy_data ( zip_t * , zip_uint64_t ) ;
2024-09-28 00:48:55 +00:00
static int copy_source ( zip_t * , zip_source_t * , zip_source_t * , zip_int64_t ) ;
2023-08-24 02:30:24 +00:00
static int torrentzip_compare_names ( const void * a , const void * b ) ;
static int write_cdir ( zip_t * , const zip_filelist_t * , zip_uint64_t ) ;
static int write_data_descriptor ( zip_t * za , const zip_dirent_t * dirent , int is_zip64 ) ;
ZIP_EXTERN int
zip_close ( zip_t * za ) {
zip_uint64_t i , j , survivors , unchanged_offset ;
zip_int64_t off ;
int error ;
zip_filelist_t * filelist ;
int changed ;
if ( za = = NULL )
return - 1 ;
changed = _zip_changed ( za , & survivors ) ;
if ( survivors = = 0 & & ! ( za - > ch_flags & ZIP_AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE ) ) {
/* don't create zip files with no entries */
if ( ( za - > open_flags & ZIP_TRUNCATE ) | | changed ) {
if ( zip_source_remove ( za - > src ) < 0 ) {
if ( ! ( ( zip_error_code_zip ( zip_source_error ( za - > src ) ) = = ZIP_ER_REMOVE ) & & ( zip_error_code_system ( zip_source_error ( za - > src ) ) = = ENOENT ) ) ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
return - 1 ;
}
}
}
zip_discard ( za ) ;
return 0 ;
}
/* Always write empty archive if we are told to keep it, otherwise it wouldn't be created if the file doesn't already exist. */
if ( ! changed & & survivors > 0 ) {
zip_discard ( za ) ;
return 0 ;
}
if ( survivors > za - > nentry ) {
zip_error_set ( & za - > error , ZIP_ER_INTERNAL , 0 ) ;
return - 1 ;
}
if ( ( filelist = ( zip_filelist_t * ) malloc ( sizeof ( filelist [ 0 ] ) * ( size_t ) survivors ) ) = = NULL )
return - 1 ;
unchanged_offset = ZIP_UINT64_MAX ;
/* create list of files with index into original archive */
for ( i = j = 0 ; i < za - > nentry ; i + + ) {
if ( za - > entry [ i ] . orig ! = NULL & & ZIP_ENTRY_HAS_CHANGES ( & za - > entry [ i ] ) ) {
unchanged_offset = ZIP_MIN ( unchanged_offset , za - > entry [ i ] . orig - > offset ) ;
}
if ( za - > entry [ i ] . deleted ) {
continue ;
}
if ( j > = survivors ) {
free ( filelist ) ;
zip_error_set ( & za - > error , ZIP_ER_INTERNAL , 0 ) ;
return - 1 ;
}
filelist [ j ] . idx = i ;
filelist [ j ] . name = zip_get_name ( za , i , 0 ) ;
j + + ;
}
if ( j < survivors ) {
free ( filelist ) ;
zip_error_set ( & za - > error , ZIP_ER_INTERNAL , 0 ) ;
return - 1 ;
}
if ( ZIP_WANT_TORRENTZIP ( za ) ) {
qsort ( filelist , ( size_t ) survivors , sizeof ( filelist [ 0 ] ) , torrentzip_compare_names ) ;
}
if ( ZIP_WANT_TORRENTZIP ( za ) | | ( zip_source_supports ( za - > src ) & ZIP_SOURCE_MAKE_COMMAND_BITMASK ( ZIP_SOURCE_BEGIN_WRITE_CLONING ) ) = = 0 ) {
unchanged_offset = 0 ;
}
else {
if ( unchanged_offset = = ZIP_UINT64_MAX ) {
/* we're keeping all file data, find the end of the last one */
zip_uint64_t last_index = ZIP_UINT64_MAX ;
unchanged_offset = 0 ;
for ( i = 0 ; i < za - > nentry ; i + + ) {
if ( za - > entry [ i ] . orig ! = NULL ) {
if ( za - > entry [ i ] . orig - > offset > = unchanged_offset ) {
unchanged_offset = za - > entry [ i ] . orig - > offset ;
last_index = i ;
}
}
}
if ( last_index ! = ZIP_UINT64_MAX ) {
if ( ( unchanged_offset = _zip_file_get_end ( za , last_index , & za - > error ) ) = = 0 ) {
free ( filelist ) ;
return - 1 ;
}
}
}
if ( unchanged_offset > 0 ) {
if ( zip_source_begin_write_cloning ( za - > src , unchanged_offset ) < 0 ) {
/* cloning not supported, need to copy everything */
unchanged_offset = 0 ;
}
}
}
if ( unchanged_offset = = 0 ) {
if ( zip_source_begin_write ( za - > src ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
free ( filelist ) ;
return - 1 ;
}
}
if ( _zip_progress_start ( za - > progress ) ! = 0 ) {
zip_error_set ( & za - > error , ZIP_ER_CANCELLED , 0 ) ;
zip_source_rollback_write ( za - > src ) ;
free ( filelist ) ;
return - 1 ;
}
error = 0 ;
for ( j = 0 ; j < survivors ; j + + ) {
int new_data ;
zip_entry_t * entry ;
zip_dirent_t * de ;
if ( _zip_progress_subrange ( za - > progress , ( double ) j / ( double ) survivors , ( double ) ( j + 1 ) / ( double ) survivors ) ! = 0 ) {
zip_error_set ( & za - > error , ZIP_ER_CANCELLED , 0 ) ;
error = 1 ;
break ;
}
i = filelist [ j ] . idx ;
entry = za - > entry + i ;
if ( entry - > orig ! = NULL & & entry - > orig - > offset < unchanged_offset ) {
/* already implicitly copied by cloning */
continue ;
}
new_data = ( ZIP_ENTRY_DATA_CHANGED ( entry ) | | ZIP_ENTRY_CHANGED ( entry , ZIP_DIRENT_COMP_METHOD ) | | ZIP_ENTRY_CHANGED ( entry , ZIP_DIRENT_ENCRYPTION_METHOD ) ) | | ( ZIP_WANT_TORRENTZIP ( za ) & & ! ZIP_IS_TORRENTZIP ( za ) ) ;
/* create new local directory entry */
if ( entry - > changes = = NULL ) {
if ( ( entry - > changes = _zip_dirent_clone ( entry - > orig ) ) = = NULL ) {
zip_error_set ( & za - > error , ZIP_ER_MEMORY , 0 ) ;
error = 1 ;
break ;
}
}
de = entry - > changes ;
if ( _zip_read_local_ef ( za , i ) < 0 ) {
error = 1 ;
break ;
}
if ( ZIP_WANT_TORRENTZIP ( za ) ) {
zip_dirent_torrentzip_normalize ( entry - > changes ) ;
}
if ( ( off = zip_source_tell_write ( za - > src ) ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
error = 1 ;
break ;
}
de - > offset = ( zip_uint64_t ) off ;
if ( new_data ) {
zip_source_t * zs ;
zs = NULL ;
if ( ! ZIP_ENTRY_DATA_CHANGED ( entry ) ) {
if ( ( zs = zip_source_zip_file_create ( za , i , ZIP_FL_UNCHANGED , 0 , - 1 , NULL , & za - > error ) ) = = NULL ) {
error = 1 ;
break ;
}
}
/* add_data writes dirent */
if ( add_data ( za , zs ? zs : entry - > source , de , entry - > changes ? entry - > changes - > changed : 0 ) < 0 ) {
error = 1 ;
if ( zs )
zip_source_free ( zs ) ;
break ;
}
if ( zs )
zip_source_free ( zs ) ;
}
else {
zip_uint64_t offset ;
if ( de - > encryption_method ! = ZIP_EM_TRAD_PKWARE ) {
/* when copying data, all sizes are known -> no data descriptor needed */
/* except for PKWare encryption, where removing the data descriptor breaks password validation */
de - > bitflags & = ( zip_uint16_t ) ~ ZIP_GPBF_DATA_DESCRIPTOR ;
}
if ( _zip_dirent_write ( za , de , ZIP_FL_LOCAL ) < 0 ) {
error = 1 ;
break ;
}
if ( ( offset = _zip_file_get_offset ( za , i , & za - > error ) ) = = 0 ) {
error = 1 ;
break ;
}
if ( zip_source_seek ( za - > src , ( zip_int64_t ) offset , SEEK_SET ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
error = 1 ;
break ;
}
if ( copy_data ( za , de - > comp_size ) < 0 ) {
error = 1 ;
break ;
}
if ( de - > bitflags & ZIP_GPBF_DATA_DESCRIPTOR ) {
if ( write_data_descriptor ( za , de , _zip_dirent_needs_zip64 ( de , 0 ) ) < 0 ) {
error = 1 ;
break ;
}
}
}
}
if ( ! error ) {
if ( write_cdir ( za , filelist , survivors ) < 0 )
error = 1 ;
}
free ( filelist ) ;
if ( ! error ) {
if ( zip_source_commit_write ( za - > src ) ! = 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
error = 1 ;
}
_zip_progress_end ( za - > progress ) ;
}
if ( error ) {
zip_source_rollback_write ( za - > src ) ;
return - 1 ;
}
zip_discard ( za ) ;
return 0 ;
}
static int
add_data ( zip_t * za , zip_source_t * src , zip_dirent_t * de , zip_uint32_t changed ) {
zip_int64_t offstart , offdata , offend , data_length ;
zip_stat_t st ;
zip_file_attributes_t attributes ;
zip_source_t * src_final , * src_tmp ;
int ret ;
int is_zip64 ;
zip_flags_t flags ;
bool needs_recompress , needs_decompress , needs_crc , needs_compress , needs_reencrypt , needs_decrypt , needs_encrypt ;
if ( zip_source_stat ( src , & st ) < 0 ) {
zip_error_set_from_source ( & za - > error , src ) ;
return - 1 ;
}
if ( ( st . valid & ZIP_STAT_COMP_METHOD ) = = 0 ) {
st . valid | = ZIP_STAT_COMP_METHOD ;
st . comp_method = ZIP_CM_STORE ;
}
if ( ZIP_CM_IS_DEFAULT ( de - > comp_method ) & & st . comp_method ! = ZIP_CM_STORE )
de - > comp_method = st . comp_method ;
else if ( de - > comp_method = = ZIP_CM_STORE & & ( st . valid & ZIP_STAT_SIZE ) ) {
st . valid | = ZIP_STAT_COMP_SIZE ;
st . comp_size = st . size ;
}
else {
/* we'll recompress */
st . valid & = ~ ZIP_STAT_COMP_SIZE ;
}
if ( ( st . valid & ZIP_STAT_ENCRYPTION_METHOD ) = = 0 ) {
st . valid | = ZIP_STAT_ENCRYPTION_METHOD ;
st . encryption_method = ZIP_EM_NONE ;
}
flags = ZIP_EF_LOCAL ;
if ( ( st . valid & ZIP_STAT_SIZE ) = = 0 ) {
/* TODO: not valid for torrentzip */
flags | = ZIP_FL_FORCE_ZIP64 ;
data_length = - 1 ;
}
else {
de - > uncomp_size = st . size ;
/* this is technically incorrect (copy_source counts compressed data), but it's the best we have */
data_length = ( zip_int64_t ) st . size ;
if ( ( st . valid & ZIP_STAT_COMP_SIZE ) = = 0 ) {
zip_uint64_t max_compressed_size ;
zip_uint16_t compression_method = ZIP_CM_ACTUAL ( de - > comp_method ) ;
if ( compression_method = = ZIP_CM_STORE ) {
max_compressed_size = st . size ;
}
else {
zip_compression_algorithm_t * algorithm = _zip_get_compression_algorithm ( compression_method , true ) ;
if ( algorithm = = NULL ) {
max_compressed_size = ZIP_UINT64_MAX ;
}
else {
max_compressed_size = algorithm - > maximum_compressed_size ( st . size ) ;
}
}
if ( max_compressed_size > 0xffffffffu ) {
/* TODO: not valid for torrentzip */
flags | = ZIP_FL_FORCE_ZIP64 ;
}
}
else {
de - > comp_size = st . comp_size ;
data_length = ( zip_int64_t ) st . comp_size ;
}
}
if ( ( offstart = zip_source_tell_write ( za - > src ) ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
return - 1 ;
}
/* as long as we don't support non-seekable output, clear data descriptor bit */
de - > bitflags & = ( zip_uint16_t ) ~ ZIP_GPBF_DATA_DESCRIPTOR ;
if ( ( is_zip64 = _zip_dirent_write ( za , de , flags ) ) < 0 ) {
return - 1 ;
}
needs_recompress = ZIP_WANT_TORRENTZIP ( za ) | | st . comp_method ! = ZIP_CM_ACTUAL ( de - > comp_method ) ;
needs_decompress = needs_recompress & & ( st . comp_method ! = ZIP_CM_STORE ) ;
/* in these cases we can compute the CRC ourselves, so we do */
needs_crc = ( st . comp_method = = ZIP_CM_STORE ) | | needs_decompress ;
needs_compress = needs_recompress & & ( de - > comp_method ! = ZIP_CM_STORE ) ;
needs_reencrypt = needs_recompress | | ( de - > changed & ZIP_DIRENT_PASSWORD ) | | ( de - > encryption_method ! = st . encryption_method ) ;
needs_decrypt = needs_reencrypt & & ( st . encryption_method ! = ZIP_EM_NONE ) ;
needs_encrypt = needs_reencrypt & & ( de - > encryption_method ! = ZIP_EM_NONE ) ;
src_final = src ;
zip_source_keep ( src_final ) ;
if ( ! needs_decrypt & & st . encryption_method = = ZIP_EM_TRAD_PKWARE & & ( de - > changed & ZIP_DIRENT_LAST_MOD ) ) {
/* PKWare encryption uses the last modification time for password verification, therefore we can't change it without re-encrypting. Ignoring the requested modification time change seems more sensible than failing to close the archive. */
de - > changed & = ~ ZIP_DIRENT_LAST_MOD ;
}
if ( needs_decrypt ) {
zip_encryption_implementation impl ;
if ( ( impl = _zip_get_encryption_implementation ( st . encryption_method , ZIP_CODEC_DECODE ) ) = = NULL ) {
zip_error_set ( & za - > error , ZIP_ER_ENCRNOTSUPP , 0 ) ;
zip_source_free ( src_final ) ;
return - 1 ;
}
if ( ( src_tmp = impl ( za , src_final , st . encryption_method , ZIP_CODEC_DECODE , za - > default_password ) ) = = NULL ) {
/* error set by impl */
zip_source_free ( src_final ) ;
return - 1 ;
}
src_final = src_tmp ;
}
if ( needs_decompress ) {
if ( ( src_tmp = zip_source_decompress ( za , src_final , st . comp_method ) ) = = NULL ) {
zip_source_free ( src_final ) ;
return - 1 ;
}
src_final = src_tmp ;
}
if ( needs_crc ) {
if ( ( src_tmp = zip_source_crc_create ( src_final , 0 , & za - > error ) ) = = NULL ) {
zip_source_free ( src_final ) ;
return - 1 ;
}
src_final = src_tmp ;
}
if ( needs_compress ) {
if ( ( src_tmp = zip_source_compress ( za , src_final , de - > comp_method , de - > compression_level ) ) = = NULL ) {
zip_source_free ( src_final ) ;
return - 1 ;
}
src_final = src_tmp ;
}
if ( needs_encrypt ) {
zip_encryption_implementation impl ;
const char * password = NULL ;
if ( de - > password ) {
password = de - > password ;
}
else if ( za - > default_password ) {
password = za - > default_password ;
}
if ( ( impl = _zip_get_encryption_implementation ( de - > encryption_method , ZIP_CODEC_ENCODE ) ) = = NULL ) {
zip_error_set ( & za - > error , ZIP_ER_ENCRNOTSUPP , 0 ) ;
zip_source_free ( src_final ) ;
return - 1 ;
}
if ( de - > encryption_method = = ZIP_EM_TRAD_PKWARE ) {
de - > bitflags | = ZIP_GPBF_DATA_DESCRIPTOR ;
/* PKWare encryption uses last_mod, make sure it gets the right value. */
if ( de - > changed & ZIP_DIRENT_LAST_MOD ) {
2024-09-28 00:48:55 +00:00
if ( ( src_tmp = _zip_source_window_new ( src_final , 0 , - 1 , NULL , 0 , NULL , & de - > last_mod , NULL , 0 , true , & za - > error ) ) = = NULL ) {
2023-08-24 02:30:24 +00:00
zip_source_free ( src_final ) ;
return - 1 ;
}
src_final = src_tmp ;
}
}
if ( ( src_tmp = impl ( za , src_final , de - > encryption_method , ZIP_CODEC_ENCODE , password ) ) = = NULL ) {
/* error set by impl */
zip_source_free ( src_final ) ;
return - 1 ;
}
src_final = src_tmp ;
}
if ( ( offdata = zip_source_tell_write ( za - > src ) ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
return - 1 ;
}
2024-09-28 00:48:55 +00:00
ret = copy_source ( za , src_final , src , data_length ) ;
2023-08-24 02:30:24 +00:00
if ( zip_source_stat ( src_final , & st ) < 0 ) {
zip_error_set_from_source ( & za - > error , src_final ) ;
ret = - 1 ;
}
if ( zip_source_get_file_attributes ( src_final , & attributes ) ! = 0 ) {
zip_error_set_from_source ( & za - > error , src_final ) ;
ret = - 1 ;
}
zip_source_free ( src_final ) ;
if ( ret < 0 ) {
return - 1 ;
}
if ( ( offend = zip_source_tell_write ( za - > src ) ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
return - 1 ;
}
if ( zip_source_seek_write ( za - > src , offstart , SEEK_SET ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
return - 1 ;
}
if ( ( st . valid & ( ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE ) ) ! = ( ZIP_STAT_COMP_METHOD | ZIP_STAT_CRC | ZIP_STAT_SIZE ) ) {
zip_error_set ( & za - > error , ZIP_ER_INTERNAL , 0 ) ;
return - 1 ;
}
if ( ( de - > changed & ZIP_DIRENT_LAST_MOD ) = = 0 ) {
2024-09-28 00:48:55 +00:00
int ret2 = zip_source_get_dos_time ( src , & de - > last_mod ) ;
if ( ret2 < 0 ) {
zip_error_set_from_source ( & za - > error , src ) ;
return - 1 ;
}
if ( ret2 = = 0 ) {
time_t mtime ;
if ( st . valid & ZIP_STAT_MTIME ) {
mtime = st . mtime ;
}
else {
time ( & mtime ) ;
}
if ( _zip_u2d_time ( mtime , & de - > last_mod , & za - > error ) < 0 ) {
return - 1 ;
}
}
2023-08-24 02:30:24 +00:00
}
de - > comp_method = st . comp_method ;
de - > crc = st . crc ;
de - > uncomp_size = st . size ;
de - > comp_size = ( zip_uint64_t ) ( offend - offdata ) ;
_zip_dirent_apply_attributes ( de , & attributes , ( flags & ZIP_FL_FORCE_ZIP64 ) ! = 0 , changed ) ;
if ( ZIP_WANT_TORRENTZIP ( za ) ) {
zip_dirent_torrentzip_normalize ( de ) ;
}
if ( ( ret = _zip_dirent_write ( za , de , flags ) ) < 0 )
return - 1 ;
if ( is_zip64 ! = ret ) {
/* Zip64 mismatch between preliminary file header written before data and final file header written afterwards */
zip_error_set ( & za - > error , ZIP_ER_INTERNAL , 0 ) ;
return - 1 ;
}
if ( zip_source_seek_write ( za - > src , offend , SEEK_SET ) < 0 ) {
zip_error_set_from_source ( & za - > error , za - > src ) ;
return - 1 ;
}
if ( de - > bitflags & ZIP_GPBF_DATA_DESCRIPTOR ) {
if ( write_data_descriptor ( za , de , is_zip64 ) < 0 ) {
return - 1 ;
}
}
return 0 ;
}
static int
copy_data ( zip_t * za , zip_uint64_t len ) {
DEFINE_BYTE_ARRAY ( buf , BUFSIZE ) ;
double total = ( double ) len ;
if ( ! byte_array_init ( buf , BUFSIZE ) ) {
zip_error_set ( & za - > error , ZIP_ER_MEMORY , 0 ) ;
return - 1 ;
}
while ( len > 0 ) {
zip_uint64_t n = ZIP_MIN ( len , BUFSIZE ) ;
if ( _zip_read ( za - > src , buf , n , & za - > error ) < 0 ) {
byte_array_fini ( buf ) ;
return - 1 ;
}
if ( _zip_write ( za , buf , n ) < 0 ) {
byte_array_fini ( buf ) ;
return - 1 ;
}
len - = n ;
if ( _zip_progress_update ( za - > progress , ( total - ( double ) len ) / total ) ! = 0 ) {
zip_error_set ( & za - > error , ZIP_ER_CANCELLED , 0 ) ;
return - 1 ;
}
}
byte_array_fini ( buf ) ;
return 0 ;
}
static int
2024-09-28 00:48:55 +00:00
copy_source ( zip_t * za , zip_source_t * src , zip_source_t * src_for_length , zip_int64_t data_length ) {
2023-08-24 02:30:24 +00:00
DEFINE_BYTE_ARRAY ( buf , BUFSIZE ) ;
zip_int64_t n , current ;
int ret ;
if ( zip_source_open ( src ) < 0 ) {
zip_error_set_from_source ( & za - > error , src ) ;
return - 1 ;
}
if ( ! byte_array_init ( buf , BUFSIZE ) ) {
zip_error_set ( & za - > error , ZIP_ER_MEMORY , 0 ) ;
return - 1 ;
}
ret = 0 ;
current = 0 ;
while ( ( n = zip_source_read ( src , buf , BUFSIZE ) ) > 0 ) {
if ( _zip_write ( za , buf , ( zip_uint64_t ) n ) < 0 ) {
ret = - 1 ;
break ;
}
if ( n = = BUFSIZE & & za - > progress & & data_length > 0 ) {
2024-09-28 00:48:55 +00:00
zip_int64_t t ;
t = zip_source_tell ( src_for_length ) ;
if ( t > = 0 ) {
current = t ;
} else {
current + = n ;
}
2023-08-24 02:30:24 +00:00
if ( _zip_progress_update ( za - > progress , ( double ) current / ( double ) data_length ) ! = 0 ) {
zip_error_set ( & za - > error , ZIP_ER_CANCELLED , 0 ) ;
ret = - 1 ;
break ;
}
}
}
if ( n < 0 ) {
zip_error_set_from_source ( & za - > error , src ) ;
ret = - 1 ;
}
byte_array_fini ( buf ) ;
zip_source_close ( src ) ;
return ret ;
}
static int
write_cdir ( zip_t * za , const zip_filelist_t * filelist , zip_uint64_t survivors ) {
if ( zip_source_tell_write ( za - > src ) < 0 ) {
return - 1 ;
}
if ( _zip_cdir_write ( za , filelist , survivors ) < 0 ) {
return - 1 ;
}
if ( zip_source_tell_write ( za - > src ) < 0 ) {
return - 1 ;
}
return 0 ;
}
int
_zip_changed ( const zip_t * za , zip_uint64_t * survivorsp ) {
int changed ;
zip_uint64_t i , survivors ;
changed = 0 ;
survivors = 0 ;
if ( za - > comment_changed | | ( ZIP_WANT_TORRENTZIP ( za ) & & ! ZIP_IS_TORRENTZIP ( za ) ) ) {
changed = 1 ;
}
for ( i = 0 ; i < za - > nentry ; i + + ) {
if ( ZIP_ENTRY_HAS_CHANGES ( & za - > entry [ i ] ) ) {
changed = 1 ;
}
if ( ! za - > entry [ i ] . deleted ) {
survivors + + ;
}
}
if ( survivorsp ) {
* survivorsp = survivors ;
}
return changed ;
}
static int
write_data_descriptor ( zip_t * za , const zip_dirent_t * de , int is_zip64 ) {
zip_buffer_t * buffer = _zip_buffer_new ( NULL , MAX_DATA_DESCRIPTOR_LENGTH ) ;
int ret = 0 ;
if ( buffer = = NULL ) {
zip_error_set ( & za - > error , ZIP_ER_MEMORY , 0 ) ;
return - 1 ;
}
_zip_buffer_put ( buffer , DATADES_MAGIC , 4 ) ;
_zip_buffer_put_32 ( buffer , de - > crc ) ;
if ( is_zip64 ) {
_zip_buffer_put_64 ( buffer , de - > comp_size ) ;
_zip_buffer_put_64 ( buffer , de - > uncomp_size ) ;
}
else {
_zip_buffer_put_32 ( buffer , ( zip_uint32_t ) de - > comp_size ) ;
_zip_buffer_put_32 ( buffer , ( zip_uint32_t ) de - > uncomp_size ) ;
}
if ( ! _zip_buffer_ok ( buffer ) ) {
zip_error_set ( & za - > error , ZIP_ER_INTERNAL , 0 ) ;
ret = - 1 ;
}
else {
ret = _zip_write ( za , _zip_buffer_data ( buffer ) , _zip_buffer_offset ( buffer ) ) ;
}
_zip_buffer_free ( buffer ) ;
return ret ;
}
static int torrentzip_compare_names ( const void * a , const void * b ) {
const char * aname = ( ( const zip_filelist_t * ) a ) - > name ;
const char * bname = ( ( const zip_filelist_t * ) b ) - > name ;
if ( aname = = NULL ) {
return ( bname ! = NULL ) * - 1 ;
}
else if ( bname = = NULL ) {
return 1 ;
}
return strcasecmp ( aname , bname ) ;
2024-09-28 00:48:55 +00:00
}