Improve internal data structures. New extra field API (read only). Added paranoid mode to zipcmp (compare more meta data). Keep up-to-date metadata for changed entries, avoid parallel arrays. XXX: Modifying extra fields API functions are stubs. Old API removed.
diff --git a/TODO b/TODO index 75ce36d..2d977c8 100644 --- a/TODO +++ b/TODO
@@ -62,6 +62,7 @@ Bugs ==== +* split zip archive torrentzip state from user requested torrentzip state * check for limits imposed by format (central dir size, file size, ...) * set "version of encoding software" to proper value (2.0?) * _zip_checkcons return value can overflow
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 441fba3..b8ad48f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt
@@ -55,12 +55,12 @@ SET(LIBZIP_SOURCES zip_add.c zip_add_dir.c + zip_add_entry.c zip_close.c zip_delete.c zip_dirent.c zip_discard.c - zip_entry_free.c - zip_entry_new.c + zip_entry.c zip_err_str.c zip_error.c zip_error_clear.c @@ -68,6 +68,8 @@ zip_error_get_sys_type.c zip_error_strerror.c zip_error_to_str.c + zip_extra_field.c + zip_extra_field_api.c zip_fclose.c zip_fdopen.c zip_file_error_clear.c @@ -84,9 +86,7 @@ zip_get_archive_flag.c zip_get_compression_implementation.c zip_get_encryption_implementation.c - zip_get_extra_field_by_id.c zip_get_file_comment.c - zip_get_file_extra.c zip_get_name.c zip_get_num_entries.c zip_get_num_files.c @@ -101,7 +101,6 @@ zip_set_default_password.c zip_set_file_comment.c zip_set_file_compression.c - zip_set_file_extra.c zip_set_name.c zip_source_buffer.c zip_source_close.c @@ -125,6 +124,7 @@ zip_stat_index.c zip_stat_init.c zip_strerror.c + zip_string.c zip_unchange.c zip_unchange_all.c zip_unchange_archive.c
diff --git a/lib/Makefile.am b/lib/Makefile.am index 00394ce..de5c718 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am
@@ -12,12 +12,12 @@ libzip_la_SOURCES=\ zip_add.c \ zip_add_dir.c \ + zip_add_entry.c \ zip_close.c \ zip_delete.c \ zip_dirent.c \ zip_discard.c \ - zip_entry_free.c \ - zip_entry_new.c \ + zip_entry.c \ zip_err_str.c \ zip_error.c \ zip_error_clear.c \ @@ -25,6 +25,8 @@ zip_error_get_sys_type.c \ zip_error_strerror.c \ zip_error_to_str.c \ + zip_extra_field.c \ + zip_extra_field_api.c \ zip_fclose.c \ zip_fdopen.c \ zip_file_error_clear.c \ @@ -41,9 +43,7 @@ zip_get_archive_flag.c \ zip_get_compression_implementation.c \ zip_get_encryption_implementation.c \ - zip_get_extra_field_by_id.c \ zip_get_file_comment.c \ - zip_get_file_extra.c \ zip_get_num_entries.c \ zip_get_num_files.c \ zip_get_name.c \ @@ -58,7 +58,7 @@ zip_set_default_password.c \ zip_set_file_comment.c \ zip_set_file_compression.c \ - zip_set_file_extra.c \ + zip_set_name.c \ zip_source_buffer.c \ zip_source_close.c \ zip_source_crc.c \ @@ -77,11 +77,11 @@ zip_source_window.c \ zip_source_zip.c \ zip_source_zip_new.c \ - zip_set_name.c \ zip_stat.c \ zip_stat_index.c \ zip_stat_init.c \ zip_strerror.c \ + zip_string.c \ zip_unchange.c \ zip_unchange_all.c \ zip_unchange_archive.c \
diff --git a/lib/zip.h b/lib/zip.h index 10e2f36..2edec7b 100644 --- a/lib/zip.h +++ b/lib/zip.h
@@ -71,11 +71,12 @@ #define ZIP_FL_COMPRESSED 4 /* read compressed data */ #define ZIP_FL_UNCHANGED 8 /* use original data, ignoring changes */ #define ZIP_FL_RECOMPRESS 16 /* force recompression of data */ -#define ZIP_FL_ENCRYPTED 32 /* read encrypted data - (implies ZIP_FL_COMPRESSED) */ +#define ZIP_FL_ENCRYPTED 32 /* read encrypted data (implies ZIP_FL_COMPRESSED) */ #define ZIP_FL_NAME_GUESS 0 /* guess name encoding (is default) */ #define ZIP_FL_NAME_RAW 64 /* get unmodified name */ #define ZIP_FL_NAME_STRICT 128 /* follow specification strictly */ +#define ZIP_FL_LOCAL 256 /* in local header */ +#define ZIP_FL_CENTRAL 512 /* in central directory */ /* archive global flags flags */ @@ -83,6 +84,10 @@ #define ZIP_AFL_RDONLY 2 /* read only -- cannot be cleared */ +/* create a new extra field */ + +#define ZIP_EXTRA_FIELD_NEW ZIP_UINT16_MAX + /* flags for compression and encryption sources */ #define ZIP_CODEC_DECODE 0 /* decompress/decrypt (encode flag not set) */ @@ -218,6 +223,8 @@ ZIP_EXTERN int zip_close(struct zip *); ZIP_EXTERN void zip_discard(struct zip *); ZIP_EXTERN int zip_delete(struct zip *, zip_uint64_t); +ZIP_EXTERN int zip_delete_file_extra_field(struct zip *, zip_uint64_t, zip_uint32_t, zip_uint16_t); +ZIP_EXTERN int zip_delete_file_extra_field_by_id(struct zip *, zip_uint64_t, zip_uint32_t, zip_uint16_t, zip_uint16_t); ZIP_EXTERN void zip_error_clear(struct zip *); ZIP_EXTERN void zip_error_get(struct zip *, int *, int *); ZIP_EXTERN int zip_error_get_sys_type(int); @@ -239,8 +246,10 @@ ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int); ZIP_EXTERN const char *zip_get_file_comment(struct zip *, zip_uint64_t, int *, int); -ZIP_EXTERN const char *zip_get_file_extra(struct zip *, zip_uint64_t, - int *, int); +ZIP_EXTERN const zip_uint8_t *zip_get_file_extra_field(struct zip *, zip_uint64_t, zip_uint32_t, zip_uint16_t, zip_uint16_t *, zip_uint16_t *); +ZIP_EXTERN const zip_uint8_t *zip_get_file_extra_field_by_id(struct zip *, zip_uint64_t, zip_uint32_t, zip_uint16_t, zip_uint16_t, zip_uint16_t *); +ZIP_EXTERN zip_int16_t zip_get_file_num_extra_fields(struct zip *, zip_uint64_t, zip_uint32_t); +ZIP_EXTERN zip_int16_t zip_get_file_num_extra_fields_by_id(struct zip *, zip_uint64_t, zip_uint32_t, zip_uint16_t); ZIP_EXTERN const char *zip_get_name(struct zip *, zip_uint64_t, int); ZIP_EXTERN zip_uint64_t zip_get_num_entries(struct zip *, int); ZIP_EXTERN int zip_get_num_files(struct zip *); /* deprecated, use zip_get_num_entries instead */ @@ -255,8 +264,7 @@ const char *, int); ZIP_EXTERN int zip_set_file_compression(struct zip *, zip_uint64_t, zip_int32_t, zip_uint32_t); -ZIP_EXTERN int zip_set_file_extra(struct zip *, zip_uint64_t, - const char *, int); +ZIP_EXTERN int zip_set_file_extra_field(struct zip *, zip_uint64_t, zip_uint32_t, zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_uint16_t); ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *, zip_uint64_t, int); ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *,
diff --git a/lib/zip_add.c b/lib/zip_add.c index 6a310a8..3c22ddc 100644 --- a/lib/zip_add.c +++ b/lib/zip_add.c
@@ -34,7 +34,6 @@ #include "zipint.h" - /*
diff --git a/lib/zip_entry_free.c b/lib/zip_add_entry.c similarity index 69% copy from lib/zip_entry_free.c copy to lib/zip_add_entry.c index f801855..f3ba576 100644 --- a/lib/zip_entry_free.c +++ b/lib/zip_add_entry.c
@@ -1,6 +1,6 @@ /* - zip_entry_free.c -- free struct zip_entry - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + zip_add_entry.c -- create and init struct zip_entry + Copyright (C) 1999-2012 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> @@ -39,16 +39,28 @@ -void -_zip_entry_free(struct zip_entry *ze) -{ - if (ze->changes.valid & ZIP_DIRENT_FILENAME) - free(ze->changes.filename); - if (ze->changes.valid & ZIP_DIRENT_EXTRAFIELD) - free(ze->changes.extrafield); - if (ze->changes.valid & ZIP_DIRENT_COMMENT) - free(ze->changes.comment); - ze->changes.valid = 0; +/* NOTE: Signed due to -1 on error. See zip_add.c for more details. */ - _zip_unchange_data(ze); +zip_int64_t +_zip_add_entry(struct zip *za) +{ + zip_uint64_t idx; + + if (za->nentry+1 >= za->nentry_alloc) { + struct zip_entry *rentries; + zip_uint64_t nalloc = za->nentry_alloc + 16; + rentries = (struct zip_entry *)realloc(za->entry, sizeof(struct zip_entry) * nalloc); + if (!rentries) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + za->entry = rentries; + za->nentry_alloc = nalloc; + } + + idx = za->nentry++; + + _zip_entry_init(za->entry+idx); + + return idx; }
diff --git a/lib/zip_close.c b/lib/zip_close.c index 123f919..00aa7da 100644 --- a/lib/zip_close.c +++ b/lib/zip_close.c
@@ -49,24 +49,18 @@ #include <fcntl.h> #endif + + static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, FILE *); static int copy_data(FILE *, off_t, FILE *, struct zip_error *); static int copy_source(struct zip *, struct zip_source *, FILE *); -static int write_cdir(struct zip *, struct zip_cdir *, FILE *); -static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); +static int write_cdir(struct zip *, const struct zip_filelist *, int, FILE *); static char *_zip_create_temp_output(struct zip *, FILE **); static int _zip_torrentzip_cmp(const void *, const void *); -struct filelist { - int idx; - const char *name; -}; - - - ZIP_EXTERN int zip_close(struct zip *za) { @@ -77,15 +71,14 @@ #ifndef _WIN32 mode_t mask; #endif - struct zip_cdir *cd; - struct zip_dirent de; - struct filelist *filelist; + struct zip_filelist *filelist; int reopen_on_error; int new_torrentzip; enum zip_encoding_type com_enc, enc; - int changed; + int changed, is_zip64; reopen_on_error = 0; + is_zip64 = 0; /* for wiz */ if (za == NULL) return -1; @@ -109,40 +102,21 @@ return 0; } - if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) + if ((filelist=(struct zip_filelist *)malloc(sizeof(filelist[0])*survivors)) == NULL) return -1; - if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL) { - free(filelist); - return -1; - } - - for (i=0; i<survivors; i++) - _zip_dirent_init(&cd->entry[i]); - /* archive comment is special for torrentzip */ if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) { - cd->comment = _zip_memdup(TORRENT_SIG "XXXXXXXX", - TORRENT_SIG_LEN + TORRENT_CRC_LEN, - &za->error); - if (cd->comment == NULL) { - _zip_cdir_free(cd); - free(filelist); - return -1; - } - cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; - } - else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { - if (_zip_cdir_set_comment(cd, za) == -1) { - _zip_cdir_free(cd); + /* XXX: use internal function when zip_set_archive_comment clears TORRENT flag */ + if (zip_set_archive_comment(za, TORRENT_SIG "XXXXXXXX", TORRENT_SIG_LEN + TORRENT_CRC_LEN) < 0) { free(filelist); return -1; } } + /* XXX: if no longer torrentzip and archive comment not changed by user, delete it */ if ((temp=_zip_create_temp_output(za, &out)) == NULL) { - _zip_cdir_free(cd); free(filelist); return -1; } @@ -150,7 +124,7 @@ /* create list of files with index into original archive */ for (i=j=0; i<za->nentry; i++) { - if (za->entry[i].state == ZIP_ST_DELETED) + if (za->entry[i].deleted) continue; filelist[j].idx = i; @@ -167,119 +141,55 @@ error = 0; for (j=0; j<survivors; j++) { int new_data; + struct zip_entry *entry; + struct zip_dirent *de; i = filelist[j].idx; + entry = za->entry+i; - new_data = (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip || (za->entry[i].changes.valid & ZIP_DIRENT_COMP_METHOD)); + new_data = (ZIP_ENTRY_DATA_CHANGED(entry) || new_torrentzip || ZIP_ENTRY_CHANGED(entry, ZIP_DIRENT_COMP_METHOD)); /* create new local directory entry */ - if (new_data) { - _zip_dirent_init(&de); - - if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) - _zip_dirent_torrent_normalize(&de); - - if (za->entry[i].changes.valid & ZIP_DIRENT_COMP_METHOD) { - de.settable.comp_method = za->entry[i].changes.comp_method; - de.settable.valid |= ZIP_DIRENT_COMP_METHOD; - } - - /* use it as central directory entry */ - memcpy(cd->entry+j, &de, sizeof(cd->entry[j])); - - /* set/update file name */ - if ((za->entry[i].changes.valid & ZIP_DIRENT_FILENAME) == 0) { - de.settable.filename = strdup(za->cdir->entry[i].settable.filename); - cd->entry[j].settable.filename = za->cdir->entry[i].settable.filename; - de.settable.valid |= ZIP_DIRENT_FILENAME; - cd->entry[j].settable.valid |= ZIP_DIRENT_FILENAME; + if (entry->changes == NULL) { + if ((entry->changes=_zip_dirent_clone(entry->orig)) == NULL) { + /* XXX: error */ } } - else { - /* copy existing directory entries */ - if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) { - _zip_error_set(&za->error, ZIP_ER_SEEK, errno); - error = 1; - break; - } - if (_zip_dirent_read(&de, za->zp, NULL, NULL, 1, - &za->error) != 0) { - error = 1; - break; - } - memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); - if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { - de.crc = za->cdir->entry[i].crc; - de.comp_size = za->cdir->entry[i].comp_size; - de.uncomp_size = za->cdir->entry[i].uncomp_size; - de.bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; - cd->entry[j].bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR; - } + de = entry->changes; + + if (_zip_read_local_ef(za, i) < 0) { + error = 1; + break; } - if (za->entry[i].changes.valid & ZIP_DIRENT_FILENAME) { - free(de.settable.filename); - if ((de.settable.filename=strdup(za->entry[i].changes.filename)) == NULL) { - error = 1; - break; - } - cd->entry[j].settable.filename = za->entry[i].changes.filename; - } - - if (za->entry[i].changes.valid & ZIP_DIRENT_EXTRAFIELD) { - free(de.settable.extrafield); - if (za->entry[i].changes.extrafield_len > 0) { - if ((de.settable.extrafield=malloc(za->entry[i].changes.extrafield_len)) == NULL) { - error = 1; - break; - } - memcpy(de.settable.extrafield, za->entry[i].changes.extrafield, za->entry[i].changes.extrafield_len); - } - else - de.settable.extrafield = NULL; - de.settable.extrafield_len = za->entry[i].changes.extrafield_len; - /* as the rest of cd entries, its malloc/free is done by za */ - /* TODO unsure if this should also be set in the CD -- - * not done for now - cd->entry[j].settable.extrafield = za->entry[i].changes.extrafield; - cd->entry[j].settable.extrafield_len = za->entry[i].changes.extrafield_len; - */ - } - - if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 - && za->entry[i].changes.valid & ZIP_DIRENT_COMMENT) { - /* as the rest of cd entries, its malloc/free is done by za */ - cd->entry[j].settable.comment = za->entry[i].changes.comment; - cd->entry[j].settable.comment_len = za->entry[i].changes.comment_len; - } + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) + _zip_dirent_torrent_normalize(entry->changes); /* set general purpose bit flag for file name/comment encoding */ - enc = _zip_guess_encoding(de.settable.filename, - strlen(de.settable.filename)); - com_enc = _zip_guess_encoding(cd->entry[j].settable.comment, - cd->entry[j].settable.comment_len); - if ((enc == ZIP_ENCODING_UTF8 && com_enc == ZIP_ENCODING_ASCII) || - (enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8 ) || - (enc == ZIP_ENCODING_UTF8 && com_enc == ZIP_ENCODING_UTF8 )) - de.bitflags |= ZIP_GPBF_ENCODING_UTF_8; + enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); + com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); + if ((enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_ASCII) || + (enc == ZIP_ENCODING_ASCII && com_enc == ZIP_ENCODING_UTF8_KNOWN ) || + (enc == ZIP_ENCODING_UTF8_KNOWN && com_enc == ZIP_ENCODING_UTF8_KNOWN )) + de->bitflags |= ZIP_GPBF_ENCODING_UTF_8; else - de.bitflags &= ~ZIP_GPBF_ENCODING_UTF_8; - cd->entry[j].bitflags = de.bitflags; + de->bitflags &= ~ZIP_GPBF_ENCODING_UTF_8; - cd->entry[j].offset = ftello(out); + de->offset = ftello(out); if (new_data) { struct zip_source *zs; zs = NULL; - if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { + if (!ZIP_ENTRY_DATA_CHANGED(entry)) { if ((zs=_zip_source_zip_new(za, za, i, ZIP_FL_UNCHANGED, 0, -1, NULL)) == NULL) { error = 1; break; } } - if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { + /* add_data writes dirent */ + if (add_data(za, zs ? zs : entry->source, de, out) < 0) { error = 1; if (zs) zip_source_free(zs); @@ -287,42 +197,28 @@ } if (zs) zip_source_free(zs); - - cd->entry[j].last_mod = de.last_mod; - cd->entry[j].settable.comp_method = de.settable.comp_method; - cd->entry[j].comp_size = de.comp_size; - cd->entry[j].uncomp_size = de.uncomp_size; - cd->entry[j].crc = de.crc; } else { - if (_zip_dirent_write(&de, out, 1, &za->error) < 0) { + if (_zip_dirent_write(de, out, 1, &za->error) < 0) { error = 1; break; } /* we just read the local dirent, file is at correct position */ - if (copy_data(za->zp, cd->entry[j].comp_size, out, - &za->error) < 0) { + if (copy_data(za->zp, de->comp_size, out, &za->error) < 0) { error = 1; break; } } + } - _zip_dirent_finalize(&de); + if (!error) { + if (write_cdir(za, filelist, survivors, out) < 0) + error = 1; } free(filelist); - if (!error) { - if (write_cdir(za, cd, out) < 0) - error = 1; - } - - /* pointers in cd entries are owned by za */ - cd->nentry = 0; - _zip_cdir_free(cd); - if (error) { - _zip_dirent_finalize(&de); fclose(out); remove(temp); free(temp); @@ -366,8 +262,7 @@ static int -add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, - FILE *ft) +add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, FILE *ft) { off_t offstart, offdata, offend; struct zip_stat st; @@ -389,12 +284,12 @@ st.comp_method = ZIP_CM_STORE; } - if ((de->settable.valid & ZIP_DIRENT_COMP_METHOD) == 0 || de->settable.comp_method == ZIP_CM_DEFAULT) { - de->settable.valid |= ZIP_DIRENT_COMP_METHOD; - de->settable.comp_method = ZIP_CM_DEFLATE; + if (de->comp_method == ZIP_CM_DEFAULT) { + /* XXX: set changed? */ + de->comp_method = ZIP_CM_DEFLATE; } - if (st.comp_method != de->settable.comp_method) { + if (st.comp_method != de->comp_method || st.comp_method == ZIP_CM_STORE) { struct zip_source *s_store, *s_crc; zip_compression_implementation comp_impl; @@ -418,15 +313,15 @@ } /* XXX: deflate 0-byte files for torrentzip? */ - if (de->settable.comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { - if ((comp_impl=zip_get_compression_implementation(de->settable.comp_method)) == NULL) { + if (de->comp_method != ZIP_CM_STORE && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { + if ((comp_impl=zip_get_compression_implementation(de->comp_method)) == NULL) { _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); zip_source_pop(s_crc); if (s_store != src) zip_source_pop(s_store); return -1; } - if ((s2=comp_impl(za, s_crc, de->settable.comp_method, ZIP_CODEC_ENCODE)) == NULL) { + if ((s2=comp_impl(za, s_crc, de->comp_method, ZIP_CODEC_ENCODE)) == NULL) { zip_source_pop(s_crc); if (s_store != src) zip_source_pop(s_store); @@ -465,7 +360,7 @@ } de->last_mod = st.mtime; - de->settable.comp_method = st.comp_method; + de->comp_method = st.comp_method; de->crc = st.crc; de->uncomp_size = st.size; de->comp_size = offend - offdata; @@ -554,29 +449,32 @@ static int -write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) +write_cdir(struct zip *za, const struct zip_filelist *filelist, int survivors, FILE *out) { - off_t offset; + off_t cd_start, end; + zip_int64_t size; uLong crc; char buf[TORRENT_CRC_LEN+1]; - if (_zip_cdir_write(cd, out, &za->error) < 0) + cd_start = ftello(out); + + if ((size=_zip_cdir_write(za, filelist, survivors, out)) < 0) return -1; + end = ftello(out); + if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0) return 0; /* fix up torrentzip comment */ - offset = ftello(out); - - if (_zip_filerange_crc(out, cd->offset, cd->size, &crc, &za->error) < 0) + if (_zip_filerange_crc(out, cd_start, size, &crc, &za->error) < 0) return -1; snprintf(buf, sizeof(buf), "%08lX", (long)crc); - if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) { + if (fseeko(out, end-TORRENT_CRC_LEN, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } @@ -591,35 +489,6 @@ -static int -_zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src) -{ - if (src->ch_comment_len != -1) { - dest->comment_len = src->ch_comment_len; - if (src->ch_comment_len == 0) - dest->comment = NULL; - else { - dest->comment = _zip_memdup(src->ch_comment, - src->ch_comment_len, &src->error); - if (dest->comment == NULL) - return -1; - } - } - else { - if (src->cdir && src->cdir->comment_len > 0) { - dest->comment = _zip_memdup(src->cdir->comment, - src->cdir->comment_len, &src->error); - if (dest->comment == NULL) - return -1; - dest->comment_len = src->cdir->comment_len; - } - } - - return 0; -} - - - int _zip_changed(struct zip *za, int *survivorsp) { @@ -627,14 +496,13 @@ changed = survivors = 0; - if (za->ch_comment_len != -1 - || za->ch_flags != za->flags) + if (za->comment_changed || za->ch_flags != za->flags) changed = 1; for (i=0; i<za->nentry; i++) { - if (za->entry[i].state != ZIP_ST_UNCHANGED || za->entry[i].changes.valid != 0) + if (za->entry[i].deleted || za->entry[i].source || (za->entry[i].changes && za->entry[i].changes->changed != 0)) changed = 1; - if (za->entry[i].state != ZIP_ST_DELETED) + if (!za->entry[i].deleted) survivors++; } @@ -691,6 +559,6 @@ static int _zip_torrentzip_cmp(const void *a, const void *b) { - return strcasecmp(((const struct filelist *)a)->name, - ((const struct filelist *)b)->name); + return strcasecmp(((const struct zip_filelist *)a)->name, + ((const struct zip_filelist *)b)->name); }
diff --git a/lib/zip_delete.c b/lib/zip_delete.c index 8178ebb..cb76936 100644 --- a/lib/zip_delete.c +++ b/lib/zip_delete.c
@@ -55,7 +55,7 @@ if (_zip_unchange(za, idx, 1) != 0) return -1; - za->entry[idx].state = ZIP_ST_DELETED; + za->entry[idx].deleted = 1; return 0; }
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c index 89926f4..0e025a0 100644 --- a/lib/zip_dirent.c +++ b/lib/zip_dirent.c
@@ -43,10 +43,7 @@ #include "zipint.h" static time_t _zip_d2u_time(int, int); -static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *); -static char *_zip_readstr(const unsigned char **, int, int, struct zip_error *); -static void _zip_write2(unsigned short, FILE *); -static void _zip_write4(unsigned int, FILE *); +static struct zip_string *_zip_read_string(const unsigned char **, FILE *, int, int, struct zip_error *); @@ -59,10 +56,9 @@ return; for (i=0; i<cd->nentry; i++) - _zip_dirent_finalize(cd->entry+i); - free(cd->comment); - free(cd->comment_converted); + _zip_entry_finalize(cd->entry+i); free(cd->entry); + _zip_string_free(cd->comment); free(cd); } @@ -71,23 +67,27 @@ int _zip_cdir_grow(struct zip_cdir *cd, int nentry, struct zip_error *error) { - struct zip_dirent *entry; + struct zip_entry *entry; + int i; - if (nentry < cd->nentry) { + if (nentry < cd->nentry_alloc) { _zip_error_set(error, ZIP_ER_INTERNAL, 0); return -1; } - if (nentry == cd->nentry) + if (nentry == cd->nentry_alloc) return 0; - if ((entry=((struct zip_dirent *) + if ((entry=((struct zip_entry *) realloc(cd->entry, sizeof(*(cd->entry))*nentry))) == NULL) { _zip_error_set(error, ZIP_ER_MEMORY, 0); return -1; } + + for (i=cd->nentry_alloc; i<nentry; i++) + _zip_entry_init(entry+i); - cd->nentry = nentry; + cd->nentry_alloc = nentry; cd->entry = entry; return 0; @@ -99,6 +99,7 @@ _zip_cdir_new(int nentry, struct zip_error *error) { struct zip_cdir *cd; + int i; if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) { _zip_error_set(error, ZIP_ER_MEMORY, 0); @@ -107,57 +108,84 @@ if (nentry == 0) cd->entry = NULL; - else if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry)) - == NULL) { + else if ((cd->entry=(struct zip_entry *)malloc(sizeof(*(cd->entry))*nentry)) == NULL) { _zip_error_set(error, ZIP_ER_MEMORY, 0); free(cd); return NULL; } - /* entries must be initialized by caller */ + for (i=0; i<nentry; i++) + _zip_entry_init(cd->entry+i); - cd->nentry = nentry; + cd->nentry = cd->nentry_alloc = nentry; cd->size = cd->offset = 0; cd->comment = NULL; - cd->comment_len = 0; - cd->comment_type = ZIP_ENCODING_UNKNOWN; - cd->comment_converted = NULL; return cd; } -int -_zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error) +zip_int64_t +_zip_cdir_write(struct zip *za, const struct zip_filelist *filelist, int survivors, FILE *fp) { + zip_uint64_t offset, size; + struct zip_string *comment; int i; - cd->offset = ftello(fp); + offset = ftello(fp); - for (i=0; i<cd->nentry; i++) { - if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0) + for (i=0; i<survivors; i++) { + struct zip_entry *entry = za->entry+filelist[i].idx; + + if (_zip_dirent_write(entry->changes ? entry->changes : entry->orig, fp, 0, &za->error) != 0) return -1; } - cd->size = ftello(fp) - cd->offset; + size = ftello(fp) - offset; + /* EOCD64 */ + /* clearerr(fp); */ fwrite(EOCD_MAGIC, 1, 4, fp); _zip_write4(0, fp); - _zip_write2((unsigned short)cd->nentry, fp); - _zip_write2((unsigned short)cd->nentry, fp); - _zip_write4(cd->size, fp); - _zip_write4(cd->offset, fp); - _zip_write2(cd->comment_len, fp); - fwrite(cd->comment, 1, cd->comment_len, fp); + _zip_write2((unsigned short)survivors, fp); + _zip_write2((unsigned short)survivors, fp); + _zip_write4(size, fp); + _zip_write4(offset, fp); + + comment = za->comment_changed ? za->comment_changes : za->comment_orig; + + _zip_write2(comment ? comment->length : 0, fp); + if (comment) + fwrite(comment->raw, 1, comment->length, fp); if (ferror(fp)) { - _zip_error_set(error, ZIP_ER_WRITE, errno); + _zip_error_set(&za->error, ZIP_ER_WRITE, errno); return -1; } - return 0; + return size; +} + + + +struct zip_dirent * +_zip_dirent_clone(const struct zip_dirent *sde) +{ + struct zip_dirent *tde; + + if ((tde=malloc(sizeof(*tde))) == NULL) + return NULL; + + if (sde) + memcpy(tde, sde, sizeof(*sde)); + else + _zip_dirent_init(tde); + + tde->changed = 0; + + return tde; } @@ -165,16 +193,24 @@ void _zip_dirent_finalize(struct zip_dirent *zde) { - free(zde->filename_converted); - zde->filename_converted = NULL; - free(zde->comment_converted); - zde->comment_converted = NULL; - free(zde->settable.filename); - zde->settable.filename = NULL; - free(zde->settable.extrafield); - zde->settable.extrafield = NULL; - free(zde->settable.comment); - zde->settable.comment = NULL; + if (zde->changed & ZIP_DIRENT_FILENAME) + _zip_string_free(zde->filename); + if (zde->changed & ZIP_DIRENT_EXTRA_FIELD) + _zip_ef_free(zde->extra_fields); + if (zde->changed & ZIP_DIRENT_COMMENT) + _zip_string_free(zde->comment); +} + + + +void +_zip_dirent_free(struct zip_dirent *zde) +{ + if (zde == NULL) + return; + + _zip_dirent_finalize(zde); + free(zde); } @@ -182,28 +218,38 @@ void _zip_dirent_init(struct zip_dirent *de) { - de->settable.valid = 0; - de->settable.comp_method = 0; - de->settable.filename = NULL; - de->settable.extrafield = NULL; - de->settable.extrafield_len = 0; - de->settable.comment = NULL; - de->settable.comment_len = 0; + de->changed = 0; + de->local_extra_fields_read = 0; + de->version_madeby = 0; de->version_needed = 20; /* 2.0 */ de->bitflags = 0; + de->comp_method = ZIP_CM_DEFAULT; de->last_mod = 0; de->crc = 0; de->comp_size = 0; de->uncomp_size = 0; + de->filename = NULL; + de->extra_fields = NULL; + de->comment = NULL; de->disk_number = 0; de->int_attrib = 0; de->ext_attrib = 0; de->offset = 0; - de->fn_type = ZIP_ENCODING_UNKNOWN; - de->filename_converted = NULL; - de->fc_type = ZIP_ENCODING_UNKNOWN; - de->comment_converted = NULL; +} + + + +struct zip_dirent * +_zip_dirent_new(void) +{ + struct zip_dirent *de; + + if ((de=malloc(sizeof(*de))) == NULL) + return NULL; + + _zip_dirent_init(de); + return de; } @@ -235,7 +281,7 @@ const unsigned char *cur; unsigned short dostime, dosdate; zip_uint32_t size; - zip_uint16_t filename_len; + zip_uint32_t filename_len, ef_len, comment_len; if (local) size = LENTRYSIZE; @@ -276,8 +322,7 @@ zde->version_madeby = 0; zde->version_needed = _zip_read2(&cur); zde->bitflags = _zip_read2(&cur); - zde->settable.comp_method = _zip_read2(&cur); - zde->settable.valid |= ZIP_DIRENT_COMP_METHOD; + zde->comp_method = _zip_read2(&cur); /* convert to time_t */ dostime = _zip_read2(&cur); @@ -289,99 +334,84 @@ zde->uncomp_size = _zip_read4(&cur); filename_len = _zip_read2(&cur); - zde->settable.extrafield_len = _zip_read2(&cur); + ef_len = _zip_read2(&cur); if (local) { - zde->settable.comment_len = 0; + comment_len = 0; zde->disk_number = 0; zde->int_attrib = 0; zde->ext_attrib = 0; zde->offset = 0; } else { - zde->settable.comment_len = _zip_read2(&cur); + comment_len = _zip_read2(&cur); zde->disk_number = _zip_read2(&cur); zde->int_attrib = _zip_read2(&cur); zde->ext_attrib = _zip_read4(&cur); zde->offset = _zip_read4(&cur); } - zde->settable.filename = NULL; - zde->settable.extrafield = NULL; - zde->settable.comment = NULL; + zde->filename = NULL; + zde->extra_fields = NULL; + zde->comment = NULL; - size += filename_len+zde->settable.extrafield_len+zde->settable.comment_len; + size += filename_len+ef_len+comment_len; if (leftp && (*leftp < size)) { _zip_error_set(error, ZIP_ER_NOZIP, 0); return -1; } - if (bufp) { - if (filename_len) { - zde->settable.filename = _zip_readstr(&cur, filename_len, 1, error); - if (!zde->settable.filename) - return -1; - } - - if (zde->settable.extrafield_len) { - zde->settable.extrafield = _zip_readstr(&cur, zde->settable.extrafield_len, 0, - error); - if (!zde->settable.extrafield) - return -1; - } - - if (zde->settable.comment_len) { - zde->settable.comment = _zip_readstr(&cur, zde->settable.comment_len, 0, error); - if (!zde->settable.comment) - return -1; - } - } - else { - if (filename_len) { - zde->settable.filename = _zip_readfpstr(fp, filename_len, 1, error); - if (!zde->settable.filename) - return -1; - } - - if (zde->settable.extrafield_len) { - zde->settable.extrafield = _zip_readfpstr(fp, zde->settable.extrafield_len, 0, - error); - if (!zde->settable.extrafield) - return -1; - } - - if (zde->settable.comment_len) { - zde->settable.comment = _zip_readfpstr(fp, zde->settable.comment_len, 0, error); - if (!zde->settable.comment) - return -1; - } - } - - if (filename_len == 0) { - if ((zde->settable.filename=strdup("")) == NULL) + if (filename_len) { + zde->filename = _zip_read_string(bufp ? &cur : NULL, fp, filename_len, 1, error); + if (!zde->filename) return -1; - } - if (strlen(zde->settable.filename) != filename_len) - return -1; - zde->settable.valid |= ZIP_DIRENT_FILENAME; - if (zde->settable.comment_len) - zde->settable.valid |= ZIP_DIRENT_COMMENT; - if (zde->settable.extrafield_len) - zde->settable.valid |= ZIP_DIRENT_EXTRAFIELD; + 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); + return -1; + } + } + } + + if (ef_len) { + zip_uint8_t *ef = _zip_read_data(bufp ? &cur : NULL, fp, ef_len, 0, error); + + if (ef == NULL) + return -1; + if ((zde->extra_fields=_zip_ef_parse(ef, ef_len, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error)) == NULL) { + free(ef); + return -1; + } + free(ef); + if (local) + zde->local_extra_fields_read = 1; + } + + if (comment_len) { + zde->comment = _zip_read_string(bufp ? &cur : NULL, fp, comment_len, 0, error); + if (!zde->comment) + 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); + return -1; + } + } + } /* Zip64 */ if (zde->uncomp_size == ZIP_UINT32_MAX || zde->comp_size == ZIP_UINT32_MAX || zde->offset == ZIP_UINT32_MAX) { zip_uint16_t ef_len, needed_len; - const zip_uint8_t *ef = _zip_extract_extra_field_by_id(error, ZIP_EF_ZIP64, 0, - (zip_uint8_t *)zde->settable.extrafield, zde->settable.extrafield_len, &ef_len); - + const zip_uint8_t *ef = _zip_ef_get_by_id(zde->extra_fields, &ef_len, ZIP_EF_ZIP64, 0, local ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, error); + /* XXX: if ef_len == 0 && !ZIP64_EOCD: no error, 0xffffffff is valid value */ if (ef == NULL) return -1; - /* XXX: if ef_len == 0 && !ZIP64_EOCD: no error, 0xffffffff is valid value */ + if (local) needed_len = 16; else @@ -417,6 +447,37 @@ +zip_int32_t +_zip_dirent_size(FILE *f, zip_uint16_t flags, struct zip_error *error) +{ + zip_int32_t size; + int local = (flags & ZIP_EF_LOCAL); + int i; + unsigned char b[6]; + const unsigned char *p; + + size = local ? LENTRYSIZE : CDENTRYSIZE; + + if (fseek(f, local ? 26 : 28, SEEK_CUR) < 0) { + _zip_error_set(error, ZIP_ER_SEEK, errno); + return -1; + } + + if (fread(b, (local ? 4 : 6), 1, f) != 1) { + _zip_error_set(error, ZIP_ER_READ, errno); + return -1; + } + + p = b; + for (i=0; i<(local ? 2 : 3); i++) { + size += _zip_read2(&p); + } + + return size; +} + + + /* _zip_dirent_torrent_normalize(de); Set values suitable for torrentzip. */ @@ -456,22 +517,17 @@ de->version_madeby = 0; de->version_needed = 20; /* 2.0 */ de->bitflags = 2; /* maximum compression */ - de->settable.comp_method = ZIP_CM_DEFLATE; - de->settable.valid |= ZIP_DIRENT_COMP_METHOD; + de->comp_method = ZIP_CM_DEFLATE; de->last_mod = last_mod; de->disk_number = 0; de->int_attrib = 0; de->ext_attrib = 0; - de->offset = 0; - free(de->settable.extrafield); - de->settable.extrafield = NULL; - de->settable.extrafield_len = 0; - free(de->settable.comment); - de->settable.comment = NULL; - de->settable.comment_len = 0; - de->settable.valid &= ~(ZIP_DIRENT_COMMENT|ZIP_DIRENT_EXTRAFIELD); + _zip_ef_free(de->extra_fields); + de->extra_fields = NULL; + _zip_string_free(de->comment); + de->comment = NULL; } @@ -491,9 +547,6 @@ struct zip_error *error) { unsigned short dostime, dosdate; - zip_uint16_t filename_len; - - filename_len = strlen(zde->settable.filename); fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp); @@ -501,7 +554,7 @@ _zip_write2(zde->version_madeby, fp); _zip_write2(zde->version_needed, fp); _zip_write2(zde->bitflags, fp); - _zip_write2(zde->settable.comp_method, fp); + _zip_write2(zde->comp_method, fp); _zip_u2d_time(zde->last_mod, &dostime, &dosdate); _zip_write2(dostime, fp); @@ -511,26 +564,26 @@ _zip_write4(zde->comp_size, fp); _zip_write4(zde->uncomp_size, fp); - _zip_write2(filename_len, fp); - _zip_write2(zde->settable.extrafield_len, fp); + _zip_write2(_zip_string_length(zde->filename), fp); + _zip_write2(_zip_ef_size(zde->extra_fields, localp ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL), fp); if (!localp) { - _zip_write2(zde->settable.comment_len, fp); + _zip_write2(_zip_string_length(zde->comment), fp); _zip_write2(zde->disk_number, fp); _zip_write2(zde->int_attrib, fp); _zip_write4(zde->ext_attrib, fp); _zip_write4(zde->offset, fp); } - if (filename_len > 0) - fwrite(zde->settable.filename, 1, filename_len, fp); + if (zde->filename) + _zip_string_write(zde->filename, fp); - if (zde->settable.extrafield_len) - fwrite(zde->settable.extrafield, 1, zde->settable.extrafield_len, fp); + if (zde->extra_fields) + _zip_ef_write(zde->extra_fields, localp ? ZIP_EF_LOCAL : ZIP_EF_CENTRAL, fp); if (!localp) { - if (zde->settable.comment_len) - fwrite(zde->settable.comment, 1, zde->settable.comment_len, fp); + if (zde->comment) + _zip_string_write(zde->comment, fp); } if (ferror(fp)) { @@ -566,6 +619,34 @@ +struct zip_dirent * +_zip_get_dirent(struct zip *za, zip_uint64_t idx, int flags, struct zip_error *error) +{ + if (error == NULL) + error = &za->error; + + if (idx >= za->nentry) { + _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; + } + else + return za->entry[idx].changes; +} + + + zip_uint16_t _zip_read2(const unsigned char **a) { @@ -607,55 +688,31 @@ -static char * -_zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error) +zip_uint8_t * +_zip_read_data(const unsigned char **buf, FILE *fp, int len, int nulp, struct zip_error *error) { - char *r, *o; + zip_uint8_t *r, *o; if (len == 0 && nulp == 0) return NULL; - r = (char *)malloc(nulp ? len+1 : len); + r = (zip_uint8_t *)malloc(nulp ? len+1 : len); if (!r) { _zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } - if (fread(r, 1, len, fp)<len) { - free(r); - _zip_error_set(error, ZIP_ER_READ, errno); - return NULL; + if (buf) { + memcpy(r, *buf, len); + *buf += len; } - - if (nulp) { - /* replace any in-string NUL characters with spaces */ - r[len] = 0; - for (o=r; o<r+len; o++) - if (*o == '\0') - *o = ' '; + else { + if (fread(r, 1, len, fp)<len) { + free(r); + _zip_error_set(error, ZIP_ER_READ, errno); + return NULL; + } } - - return r; -} - - - -static char * -_zip_readstr(const unsigned char **buf, int len, int nulp, struct zip_error *error) -{ - char *r, *o; - - if (len == 0 && nulp == 0) - return NULL; - - r = (char *)malloc(nulp ? len+1 : len); - if (!r) { - _zip_error_set(error, ZIP_ER_MEMORY, 0); - return NULL; - } - - memcpy(r, *buf, len); - *buf += len; if (nulp) { /* replace any in-string NUL characters with spaces */ @@ -670,8 +727,21 @@ -static void -_zip_write2(unsigned short i, FILE *fp) +static struct zip_string * +_zip_read_string(const unsigned char **buf, FILE *fp, int len, int nulp, struct zip_error *error) +{ + zip_uint8_t *raw; + + if ((raw=_zip_read_data(buf, fp, len, nulp, error)) == NULL) + return NULL; + + return _zip_string_new(raw, len, error); +} + + + +void +_zip_write2(zip_uint16_t i, FILE *fp) { putc(i&0xff, fp); putc((i>>8)&0xff, fp); @@ -681,8 +751,8 @@ -static void -_zip_write4(unsigned int i, FILE *fp) +void +_zip_write4(zip_uint32_t i, FILE *fp) { putc(i&0xff, fp); putc((i>>8)&0xff, fp);
diff --git a/lib/zip_discard.c b/lib/zip_discard.c index 16cc3d8..29aa25e 100644 --- a/lib/zip_discard.c +++ b/lib/zip_discard.c
@@ -58,13 +58,12 @@ fclose(za->zp); free(za->default_password); - _zip_cdir_free(za->cdir); - free(za->ch_comment); + _zip_string_free(za->comment_orig); + _zip_string_free(za->comment_changes); if (za->entry) { - for (i=0; i<za->nentry; i++) { - _zip_entry_free(za->entry+i); - } + for (i=0; i<za->nentry; i++) + _zip_entry_finalize(za->entry+i); free(za->entry); }
diff --git a/lib/zip_entry_free.c b/lib/zip_entry.c similarity index 77% rename from lib/zip_entry_free.c rename to lib/zip_entry.c index f801855..58663e8 100644 --- a/lib/zip_entry_free.c +++ b/lib/zip_entry.c
@@ -1,6 +1,6 @@ /* - zip_entry_free.c -- free struct zip_entry - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + zip_entry.c -- struct zip_entry helper functions + Copyright (C) 1999-2012 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> @@ -33,22 +33,23 @@ -#include <stdlib.h> - #include "zipint.h" +void +_zip_entry_finalize(struct zip_entry *e) +{ + _zip_unchange_data(e); + _zip_dirent_free(e->orig); + _zip_dirent_free(e->changes); +} + void -_zip_entry_free(struct zip_entry *ze) +_zip_entry_init(struct zip_entry *e) { - if (ze->changes.valid & ZIP_DIRENT_FILENAME) - free(ze->changes.filename); - if (ze->changes.valid & ZIP_DIRENT_EXTRAFIELD) - free(ze->changes.extrafield); - if (ze->changes.valid & ZIP_DIRENT_COMMENT) - free(ze->changes.comment); - ze->changes.valid = 0; - - _zip_unchange_data(ze); + e->orig = NULL; + e->changes = NULL; + e->source = NULL; + e->deleted = 0; }
diff --git a/lib/zip_entry_new.c b/lib/zip_entry_new.c deleted file mode 100644 index b8ab272..0000000 --- a/lib/zip_entry_new.c +++ /dev/null
@@ -1,75 +0,0 @@ -/* - zip_entry_new.c -- create and init struct zip_entry - Copyright (C) 1999-2012 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> - - 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 <stdlib.h> - -#include "zipint.h" - - - -struct zip_entry * -_zip_entry_new(struct zip *za) -{ - struct zip_entry *ze; - if (!za) { - ze = (struct zip_entry *)malloc(sizeof(struct zip_entry)); - if (!ze) - return NULL; - } - else { - if (za->nentry+1 >= za->nentry_alloc) { - struct zip_entry *rentries; - za->nentry_alloc += 16; - rentries = (struct zip_entry *)realloc(za->entry, - sizeof(struct zip_entry) - * za->nentry_alloc); - if (!rentries) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - return NULL; - } - za->entry = rentries; - } - ze = za->entry+za->nentry; - } - - ze->state = ZIP_ST_UNCHANGED; - ze->source = NULL; - ze->changes.valid = 0; - - if (za) - za->nentry++; - - return ze; -}
diff --git a/lib/zip_extra_field.c b/lib/zip_extra_field.c new file mode 100644 index 0000000..1c5a414 --- /dev/null +++ b/lib/zip_extra_field.c
@@ -0,0 +1,290 @@ +/* + zip_extra_field.c -- manipulate extra fields + Copyright (C) 2012 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> + + 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 <errno.h> +#include <stdlib.h> +#include <string.h> + + + +void +_zip_ef_free(struct zip_extra_field *ef) +{ + struct zip_extra_field *ef2; + + while (ef) { + ef2 = ef->next; + free(ef->data); + free(ef); + ef = ef2; + } +} + + + +const zip_uint8_t * +_zip_ef_get_by_id(struct zip_extra_field *ef, zip_uint16_t *lenp, zip_uint16_t id, zip_uint16_t id_idx, zip_uint16_t flags, struct zip_error *error) +{ + static const zip_uint8_t empty[1]; + + int i; + + i = 0; + for (; ef; ef=ef->next) { + if (ef->id == id && (ef->flags & flags & ZIP_EF_BOTH)) { + if (i < id_idx) { + i++; + continue; + } + + if (lenp) + *lenp = ef->size; + if (ef->size > 0) + return ef->data; + else + return empty; + } + } + + _zip_error_set(error, ZIP_ER_NOENT, 0); + return NULL; +} + + + +struct zip_extra_field * +_zip_ef_merge(struct zip_extra_field *to, struct zip_extra_field *from) +{ + struct zip_extra_field *ef2, *tt, *tail; + int duplicate; + + if (to == NULL) + return from; + + for (tail=to; tail->next; tail=tail->next) + ; + + for (; from; from=ef2) { + ef2 = from->next; + + duplicate = 0; + for (tt=to; tt; tt=tt->next) { + if (tt->id == from->id && tt->size == from->size && memcmp(tt->data, from->data, tt->size) == 0) { + tt->flags |= (from->flags & ZIP_EF_BOTH); + duplicate = 1; + break; + } + } + + from->next = NULL; + if (duplicate) + _zip_ef_free(from); + else + tail = tail->next = from; + } + + return to; +} + + + +struct zip_extra_field * +_zip_ef_new(zip_uint16_t id, zip_uint16_t size, const zip_uint8_t *data, zip_uint16_t flags) +{ + struct zip_extra_field *ef; + + if ((ef=malloc(sizeof(*ef))) == NULL) + return NULL; + + ef->next = NULL; + ef->flags = flags; + ef->id = id; + ef->size = size; + if (size > 0) { + if ((ef->data=_zip_memdup(data, size, NULL)) == NULL) { + free(ef); + return NULL; + } + } + else + ef->data = NULL; + + return ef; +} + + + +struct zip_extra_field * +_zip_ef_parse(const zip_uint8_t *data, zip_uint16_t len, zip_uint16_t flags, struct zip_error *error) +{ + struct zip_extra_field *ef, *ef2, *ef_head; + int i; + const zip_uint8_t *p; + zip_uint16_t fid, flen; + + ef_head = NULL; + i = 0; + for (p=data; p<data+len; p+=flen+4) { + if (p+4 > data+len) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + _zip_ef_free(ef_head); + return NULL; + } + + fid = p[0]+(p[1]<<8); + flen = p[2]+(p[3]<<8); + + if (p+flen+4 > data+len) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + _zip_ef_free(ef_head); + return NULL; + } + + if ((ef2=_zip_ef_new(fid, flen, p+4, flags)) == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + _zip_ef_free(ef_head); + return NULL; + } + + if (ef_head) { + ef->next = ef2; + ef = ef2; + } + else + ef_head = ef = ef2; + } + + return ef_head; +} + + + +zip_uint16_t +_zip_ef_size(struct zip_extra_field *ef, zip_uint16_t flags) +{ + zip_uint16_t size; + + size = 0; + for (; ef; ef=ef->next) { + if (ef->flags & flags & ZIP_EF_BOTH) + size += 4+ef->size; + } + + return size; +} + + + +void +_zip_ef_write(struct zip_extra_field *ef, zip_uint16_t flags, FILE *f) +{ + for (; ef; ef=ef->next) { + if (ef->flags & flags & ZIP_EF_BOTH) { + _zip_write2(ef->id, f); + _zip_write2(ef->size, f); + if (ef->size > 0) + fwrite(ef->data, ef->size, 1, f); + } + } +} + + + +int +_zip_read_local_ef(struct zip *za, int idx) +{ + struct zip_entry *e; + unsigned char b[4]; + const unsigned char *p; + zip_uint16_t fname_len, ef_len; + zip_uint8_t *ef_raw; + struct zip_extra_field *ef; + + if (idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + e = za->entry+idx; + + if (e->orig == NULL || e->orig->local_extra_fields_read) + return 0; + + + if (fseek(za->zp, e->orig->offset + 26, SEEK_SET) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + if (fread(b, sizeof(b), 1, za->zp) != 1) { + _zip_error_set(&za->error, ZIP_ER_READ, errno); + return -1; + } + + p = b; + fname_len = _zip_read2(&p); + ef_len = _zip_read2(&p); + + if (ef_len > 0) { + if (fseek(za->zp, fname_len, SEEK_CUR) < 0) { + _zip_error_set(&za->error, ZIP_ER_SEEK, errno); + return -1; + } + + ef_raw = _zip_read_data(NULL, za->zp, ef_len, 0, &za->error); + + if (ef_raw == NULL) + return -1; + + if ((ef=_zip_ef_parse(ef_raw, ef_len, ZIP_EF_LOCAL, &za->error)) == NULL) { + free(ef_raw); + return -1; + } + free(ef_raw); + + e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef); + } + + e->orig->local_extra_fields_read = 1; + + if (e->changes && e->changes->local_extra_fields_read == 0) { + e->changes->extra_fields = e->orig->extra_fields; + e->changes->local_extra_fields_read = 1; + } + + return 0; +}
diff --git a/lib/zip_extra_field_api.c b/lib/zip_extra_field_api.c new file mode 100644 index 0000000..4aafa2e --- /dev/null +++ b/lib/zip_extra_field_api.c
@@ -0,0 +1,182 @@ +/* + zip_extra_field_api.c -- public extra fields API functions + Copyright (C) 2012 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> + + 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" + + + +ZIP_EXTERN int +zip_delete_file_extra_field(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_idx) +{ + /* XXX */ + return -1; +} + + + +ZIP_EXTERN int +zip_delete_file_extra_field_by_id(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx) +{ + /* XXX */ + return -1; +} + + + +ZIP_EXTERN const zip_uint8_t * +zip_get_file_extra_field(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_idx, zip_uint16_t *idp, zip_uint16_t *lenp) +{ + static const zip_uint8_t empty[1]; + + struct zip_dirent *de; + struct zip_extra_field *ef; + int i; + + if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return NULL; + + if ((flags & ZIP_EF_BOTH) == 0) + flags = ZIP_EF_BOTH; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return NULL; + + i = 0; + for (ef=de->extra_fields; ef; ef=ef->next) { + if (ef->flags & flags & ZIP_EF_BOTH) { + if (i < ef_idx) { + i++; + continue; + } + + if (idp) + *idp = ef->id; + if (lenp) + *lenp = ef->size; + if (ef->size > 0) + return ef->data; + else + return empty; + } + } + + _zip_error_set(&za->error, ZIP_ER_NOENT, 0); + return NULL; + +} + + + +ZIP_EXTERN const zip_uint8_t * +zip_get_file_extra_field_by_id(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_uint16_t *lenp) +{ + struct zip_dirent *de; + + if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return NULL; + + if ((flags & ZIP_EF_BOTH) == 0) + flags = ZIP_EF_BOTH; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return NULL; + + return _zip_ef_get_by_id(de->extra_fields, lenp, ef_id, ef_idx, flags, &za->error); +} + + + +ZIP_EXTERN zip_int16_t +zip_get_file_num_extra_fields(struct zip *za, zip_uint64_t idx, zip_uint32_t flags) +{ + struct zip_dirent *de; + struct zip_extra_field *ef; + zip_uint16_t n; + + if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return -1; + + if ((flags & ZIP_EF_BOTH) == 0) + flags = ZIP_EF_BOTH; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return -1; + + n = 0; + for (ef=de->extra_fields; ef; ef=ef->next) + if (ef->flags & flags & ZIP_EF_BOTH) + n++; + + return n; +} + + + +ZIP_EXTERN zip_int16_t +zip_get_file_num_extra_fields_by_id(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id) +{ + struct zip_dirent *de; + struct zip_extra_field *ef; + zip_uint16_t n; + + if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + return -1; + + if ((flags & ZIP_EF_BOTH) == 0) + flags = ZIP_EF_BOTH; + + if (flags & ZIP_FL_LOCAL) + if (_zip_read_local_ef(za, idx) < 0) + return -1; + + n = 0; + for (ef=de->extra_fields; ef; ef=ef->next) + if (ef->id == ef_id && (ef->flags & flags & ZIP_EF_BOTH)) + n++; + + return n; +} + + + +ZIP_EXTERN int +zip_set_file_extra_field(struct zip *za, zip_uint64_t idx, zip_uint32_t flags, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len) +{ + /* XXX */ + return -1; +}
diff --git a/lib/zip_file_get_offset.c b/lib/zip_file_get_offset.c index 9f161a4..644613f 100644 --- a/lib/zip_file_get_offset.c +++ b/lib/zip_file_get_offset.c
@@ -51,24 +51,21 @@ */ zip_uint64_t -_zip_file_get_offset(struct zip *za, int idx, struct zip_error *ze) +_zip_file_get_offset(struct zip *za, int idx, struct zip_error *error) { - struct zip_dirent de; - unsigned int offset; + zip_uint64_t offset; + zip_int32_t size; - offset = za->cdir->entry[idx].offset; + offset = za->entry[idx].orig->offset; if (fseeko(za->zp, offset, SEEK_SET) != 0) { - _zip_error_set(ze, ZIP_ER_SEEK, errno); + _zip_error_set(error, ZIP_ER_SEEK, errno); return 0; } - if (_zip_dirent_read(&de, za->zp, NULL, NULL, 1, ze) != 0) + /* XXX: cache? */ + if ((size=_zip_dirent_size(za->zp, ZIP_EF_LOCAL, error)) < 0) return 0; - offset += LENTRYSIZE + strlen(de.settable.filename) + de.settable.extrafield_len; - - _zip_dirent_finalize(&de); - - return offset; + return offset + size; }
diff --git a/lib/zip_get_archive_comment.c b/lib/zip_get_archive_comment.c index 730062d..ccada19 100644 --- a/lib/zip_get_archive_comment.c +++ b/lib/zip_get_archive_comment.c
@@ -42,42 +42,20 @@ ZIP_EXTERN const char * zip_get_archive_comment(struct zip *za, int *lenp, int flags) { - const char *ret; - if ((flags & ZIP_FL_UNCHANGED) - || (za->ch_comment_len == -1)) { - if (za->cdir) { - if (lenp != NULL) - *lenp = za->cdir->comment_len; - ret = za->cdir->comment; - - if (flags & ZIP_FL_NAME_RAW) - return ret; + struct zip_string *comment; + zip_uint32_t len; + const zip_uint8_t *str; - /* start guessing */ - if (za->cdir->comment_type == ZIP_ENCODING_UNKNOWN) - za->cdir->comment_type = _zip_guess_encoding(ret, za->cdir->comment_len); + if ((flags & ZIP_FL_UNCHANGED) || (za->comment_changes == NULL)) + comment = za->comment_orig; + else + comment = za->comment_changes; - if (((flags & ZIP_FL_NAME_STRICT) && (za->cdir->comment_type != ZIP_ENCODING_ASCII)) - || (za->cdir->comment_type == ZIP_ENCODING_CP437)) { - if (za->cdir->comment_converted == NULL) - za->cdir->comment_converted = _zip_cp437_to_utf8(ret, za->cdir->comment_len, - &za->cdir->comment_converted_len, &za->error); - ret = za->cdir->comment_converted; - if (lenp != NULL) - *lenp = za->cdir->comment_converted_len; - } + if ((str=_zip_string_get(comment, &len, flags, &za->error)) == NULL) + return NULL; - return ret; - } - else { - if (lenp != NULL) - *lenp = -1; - return NULL; - } - } + if (lenp) + *lenp = len; - /* already UTF-8, no conversion needed */ - if (lenp != NULL) - *lenp = za->ch_comment_len; - return za->ch_comment; + return (const char *)str; }
diff --git a/lib/zip_get_extra_field_by_id.c b/lib/zip_get_extra_field_by_id.c deleted file mode 100644 index 588a337..0000000 --- a/lib/zip_get_extra_field_by_id.c +++ /dev/null
@@ -1,102 +0,0 @@ -/* - zip_get_extra_field_by_id.c -- get extrafield by ID - Copyright (C) 2012 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> - - 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" - - - -const zip_uint8_t * -zip_get_extra_field_by_id(struct zip *za, int idx, int flags, - zip_uint16_t id, int id_index, zip_uint16_t *lenp) -{ - static zip_uint8_t empty[1]; - - const zip_uint8_t *ef; - int len; - - len = 17; - ef = (const zip_uint8_t *)zip_get_file_extra(za, idx, &len, flags); - - if (ef == NULL) { - if (len == 17) - return NULL; - if (lenp) - *lenp = 0; - return empty; - } - - return _zip_extract_extra_field_by_id(&za->error, id, id_index, ef, len, lenp); -} - - -const zip_uint8_t * -_zip_extract_extra_field_by_id(struct zip_error *errorp, zip_uint16_t id, int id_index, - const zip_uint8_t *ef, zip_uint16_t ef_len, zip_uint16_t *lenp) -{ - int i; - const zip_uint8_t *p; - zip_uint16_t fid, flen; - - i = 0; - for (p=ef; p<ef+ef_len; p+=flen+4) { - if (p+4 > ef+ef_len) { - _zip_error_set(errorp, ZIP_ER_INCONS, 0); - return NULL; - } - - fid = p[0]+(p[1]<<8); - flen = p[2]+(p[3]<<8); - - if (p+flen+4 > ef+ef_len) { - _zip_error_set(errorp, ZIP_ER_INCONS, 0); - return NULL; - } - - if (fid == id) { - if (i < id_index) { - i++; - continue; - } - - if (lenp) - *lenp = flen; - return p+4; - } - } - - _zip_error_set(errorp, ZIP_ER_NOENT, 0); - return NULL; -} -
diff --git a/lib/zip_get_file_comment.c b/lib/zip_get_file_comment.c index ee71609..a7a586a 100644 --- a/lib/zip_get_file_comment.c +++ b/lib/zip_get_file_comment.c
@@ -33,8 +33,6 @@ -#include <string.h> - #include "zipint.h" @@ -42,53 +40,18 @@ ZIP_EXTERN const char * zip_get_file_comment(struct zip *za, zip_uint64_t idx, int *lenp, int flags) { - const char *ret; + struct zip_dirent *de; + zip_uint32_t len; + const zip_uint8_t *str; - if (idx >= za->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + if ((de=_zip_get_dirent(za, idx, flags, NULL)) == NULL) return NULL; - } - if ((flags & ZIP_FL_UNCHANGED) || (za->entry[idx].changes.valid & ZIP_DIRENT_COMMENT) == 0) { - if (za->cdir == NULL) { - _zip_error_set(&za->error, ZIP_ER_NOENT, 0); - return NULL; - } - if (idx >= za->cdir->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return NULL; - } - - if (lenp != NULL) - *lenp = za->cdir->entry[idx].settable.comment_len; - ret = za->cdir->entry[idx].settable.comment; + if ((str=_zip_string_get(de->comment, &len, flags, &za->error)) == NULL) + return NULL; - if (flags & ZIP_FL_NAME_RAW) - return ret; + if (lenp) + *lenp = len; - /* file comment already is UTF-8? */ - if (za->cdir->entry[idx].bitflags & ZIP_GPBF_ENCODING_UTF_8) - return ret; - - /* undeclared, start guessing */ - if (za->cdir->entry[idx].fc_type == ZIP_ENCODING_UNKNOWN) - za->cdir->entry[idx].fc_type = _zip_guess_encoding(ret, za->cdir->entry[idx].settable.comment_len); - - if (((flags & ZIP_FL_NAME_STRICT) && (za->cdir->entry[idx].fc_type != ZIP_ENCODING_ASCII)) - || (za->cdir->entry[idx].fc_type == ZIP_ENCODING_CP437)) { - if (za->cdir->entry[idx].comment_converted == NULL) - za->cdir->entry[idx].comment_converted = _zip_cp437_to_utf8(ret, za->cdir->entry[idx].settable.comment_len, - &za->cdir->entry[idx].comment_converted_len, &za->error); - ret = za->cdir->entry[idx].comment_converted; - if (lenp != NULL) - *lenp = za->cdir->entry[idx].comment_converted_len; - } - - return ret; - } - - /* already UTF-8, no conversion necessary */ - if (lenp != NULL) - *lenp = za->entry[idx].changes.comment_len; - return za->entry[idx].changes.comment; + return (const char *)str; }
diff --git a/lib/zip_get_file_extra.c b/lib/zip_get_file_extra.c deleted file mode 100644 index cb3d2b5..0000000 --- a/lib/zip_get_file_extra.c +++ /dev/null
@@ -1,62 +0,0 @@ -/* - zip_get_file_extra.c -- get file extra field - Copyright (C) 2006-2010 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> - - 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" - - - -ZIP_EXTERN const char * -zip_get_file_extra(struct zip *za, zip_uint64_t idx, int *lenp, int flags) -{ - if (idx >= za->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return NULL; - } - - if ((flags & ZIP_FL_UNCHANGED) || (za->entry[idx].changes.valid & ZIP_DIRENT_EXTRAFIELD) == 0) { - if (idx >= za->cdir->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return NULL; - } - - if (lenp != NULL) - *lenp = za->cdir->entry[idx].settable.extrafield_len; - return za->cdir->entry[idx].settable.extrafield; - } - - if (lenp != NULL) - *lenp = za->entry[idx].changes.extrafield_len; - return za->entry[idx].changes.extrafield; -}
diff --git a/lib/zip_get_name.c b/lib/zip_get_name.c index 7c3f7b9..baa383d 100644 --- a/lib/zip_get_name.c +++ b/lib/zip_get_name.c
@@ -51,48 +51,14 @@ _zip_get_name(struct zip *za, zip_uint64_t idx, int flags, struct zip_error *error) { - enum zip_encoding_type enc; - const char *ret; + struct zip_dirent *de; + const zip_uint8_t *str; - ret = NULL; - if (idx >= za->nentry) { - _zip_error_set(error, ZIP_ER_INVAL, 0); + if ((de=_zip_get_dirent(za, idx, flags, NULL)) == NULL) return NULL; - } - if ((flags & ZIP_FL_UNCHANGED) == 0) { - if (za->entry[idx].state == ZIP_ST_DELETED) { - _zip_error_set(error, ZIP_ER_DELETED, 0); - return NULL; - } - if (za->entry[idx].changes.valid & ZIP_DIRENT_FILENAME) - return za->entry[idx].changes.filename; /* must be UTF-8 */ - } - - /* XXX: read Infozip UTF-8 Extension 0x7075 file name? */ - if (za->cdir == NULL || idx >= za->cdir->nentry) { - _zip_error_set(error, ZIP_ER_INVAL, 0); + if ((str=_zip_string_get(de->filename, NULL, flags, &za->error)) == NULL) return NULL; - } - ret = za->cdir->entry[idx].settable.filename; - if (flags & ZIP_FL_NAME_RAW) - return ret; - - /* file name already is UTF-8? */ - if (za->cdir->entry[idx].bitflags & ZIP_GPBF_ENCODING_UTF_8) - return ret; - - /* undeclared, start guessing */ - if (za->cdir->entry[idx].fn_type == ZIP_ENCODING_UNKNOWN) - za->cdir->entry[idx].fn_type = _zip_guess_encoding(ret, strlen(ret)); - - if (((flags & ZIP_FL_NAME_STRICT) && (za->cdir->entry[idx].fn_type != ZIP_ENCODING_ASCII)) - || (za->cdir->entry[idx].fn_type == ZIP_ENCODING_CP437)) { - if (za->cdir->entry[idx].filename_converted == NULL) - za->cdir->entry[idx].filename_converted = _zip_cp437_to_utf8(ret, strlen(ret), NULL, error); - ret = za->cdir->entry[idx].filename_converted; - } - - return ret; + return (const char *)str; }
diff --git a/lib/zip_get_num_entries.c b/lib/zip_get_num_entries.c index 83293e9..3fbafd2 100644 --- a/lib/zip_get_num_entries.c +++ b/lib/zip_get_num_entries.c
@@ -40,13 +40,16 @@ ZIP_EXTERN zip_uint64_t zip_get_num_entries(struct zip *za, int flags) { + zip_uint64_t n; + if (za == NULL) return -1; if (flags & ZIP_FL_UNCHANGED) { - if (za->cdir == NULL) - return 0; - return za->cdir->nentry; + n = za->nentry; + while (n>0 && za->entry[n-1].orig == NULL) + --n; + return n; } return za->nentry; }
diff --git a/lib/zip_name_locate.c b/lib/zip_name_locate.c index 44e3c85..a5b1db2 100644 --- a/lib/zip_name_locate.c +++ b/lib/zip_name_locate.c
@@ -53,7 +53,7 @@ { int (*cmp)(const char *, const char *); const char *fn, *p; - int i, n; + zip_uint64_t i; if (za == NULL) return -1; @@ -63,15 +63,9 @@ return -1; } - if ((flags & ZIP_FL_UNCHANGED) && za->cdir == NULL) { - _zip_error_set(error, ZIP_ER_NOENT, 0); - return -1; - } - cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp; - n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry; - for (i=0; i<n; i++) { + for (i=0; i<za->nentry; i++) { fn = _zip_get_name(za, i, flags, error); /* newly added (partially filled) entry or error */
diff --git a/lib/zip_new.c b/lib/zip_new.c index 7ce1237..62e1420 100644 --- a/lib/zip_new.c +++ b/lib/zip_new.c
@@ -1,6 +1,6 @@ /* zip_new.c -- create and init struct zip - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2012 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> @@ -56,16 +56,16 @@ za->zn = NULL; za->zp = NULL; + za->open_flags = 0; _zip_error_init(&za->error); - za->cdir = NULL; - za->ch_comment = NULL; - za->ch_comment_len = -1; + za->flags = za->ch_flags = 0; + za->default_password = NULL; + za->comment_orig = za->comment_changes = NULL; + za->comment_changed = 0; za->nentry = za->nentry_alloc = 0; za->entry = NULL; za->nfile = za->nfile_alloc = 0; za->file = NULL; - za->flags = za->ch_flags = 0; - za->default_password = NULL; return za; }
diff --git a/lib/zip_open.c b/lib/zip_open.c index 3901ea5..dac8677 100644 --- a/lib/zip_open.c +++ b/lib/zip_open.c
@@ -45,11 +45,10 @@ static void set_error(int *, struct zip_error *, int); static struct zip *_zip_allocate_new(const char *, int, int *); static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *); -static void _zip_check_torrentzip(struct zip *); +static void _zip_check_torrentzip(struct zip *, const struct zip_cdir *); static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, off_t); static int _zip_file_exists(const char *, int, int *); -static int _zip_headercomp(struct zip_dirent *, int, - struct zip_dirent *, int); +static int _zip_headercomp(struct zip_dirent *, struct zip_dirent *); static unsigned char *_zip_memmem(const unsigned char *, int, const unsigned char *, int); static struct zip_cdir *_zip_readcdir(FILE *, off_t, unsigned char *, unsigned char *, @@ -100,7 +99,6 @@ { struct zip *za; struct zip_cdir *cdir; - int i; off_t len; if (fseeko(fp, 0, SEEK_END) < 0) { @@ -130,23 +128,19 @@ return NULL; } - za->cdir = cdir; + za->entry = cdir->entry; + za->nentry = cdir->nentry; + za->nentry_alloc = cdir->nentry_alloc; + za->comment_orig = cdir->comment; + za->zp = fp; - if (cdir->nentry == 0) - za->entry = NULL; - else if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) - * cdir->nentry)) == NULL) { - set_error(zep, NULL, ZIP_ER_MEMORY); - zip_discard(za); - return NULL; - } - for (i=0; i<cdir->nentry; i++) - _zip_entry_new(za); + _zip_check_torrentzip(za, cdir); - _zip_check_torrentzip(za); za->ch_flags = za->flags; + free(cdir); + return za; } @@ -182,12 +176,12 @@ struct zip_cdir *cd; const unsigned char *cdp; const unsigned char **bufp; - zip_int32_t comlen; + zip_int32_t tail_len, comment_len; int i; zip_uint32_t left; - comlen = buf + buflen - eocd - EOCDLEN; - if (comlen < 0) { + tail_len = buf + buflen - eocd - EOCDLEN; + if (tail_len < 0) { /* not enough bytes left for comment */ _zip_error_set(error, ZIP_ER_NOZIP, 0); return NULL; @@ -204,7 +198,7 @@ return NULL; } - if (eocd-buf < EOCD64LOCLEN && memcmp(eocd-EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) + if (eocd-EOCD64LOCLEN >= buf && memcmp(eocd-EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) cd = _zip_read_eocd64(fp, eocd-EOCD64LOCLEN, buf, buf_offset, buflen, flags, error); else cd = _zip_read_eocd(eocd, buf, buf_offset, buflen, flags, error); @@ -213,35 +207,28 @@ return NULL; cdp = eocd + 20; - cd->comment = NULL; - cd->comment_len = _zip_read2(&cdp); + comment_len = _zip_read2(&cdp); if (((zip_uint64_t)cd->offset)+cd->size > buf_offset + (eocd-buf)) { /* cdir spans past EOCD record */ _zip_error_set(error, ZIP_ER_INCONS, 0); - cd->nentry = 0; _zip_cdir_free(cd); return NULL; } - if (comlen < cd->comment_len) { + if (tail_len < comment_len) { _zip_error_set(error, ZIP_ER_NOZIP, 0); - cd->nentry = 0; _zip_cdir_free(cd); return NULL; } - if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) { + if ((flags & ZIP_CHECKCONS) && tail_len != comment_len) { _zip_error_set(error, ZIP_ER_INCONS, 0); - cd->nentry = 0; _zip_cdir_free(cd); return NULL; } - if (cd->comment_len) { - if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN, - cd->comment_len, error)) - == NULL) { - cd->nentry = 0; + if (comment_len) { + if ((cd->comment=_zip_string_new(eocd+EOCDLEN, comment_len, error)) == NULL) { _zip_cdir_free(cd); return NULL; } @@ -265,7 +252,6 @@ _zip_error_set(error, ZIP_ER_SEEK, errno); else _zip_error_set(error, ZIP_ER_NOZIP, 0); - cd->nentry = 0; _zip_cdir_free(cd); return NULL; } @@ -274,8 +260,8 @@ left = cd->size; i=0; while (i<cd->nentry && left > 0) { - if ((_zip_dirent_read(cd->entry+i, fp, bufp, &left, 0, error)) < 0) { - cd->nentry = i; + if ((cd->entry[i].orig=_zip_dirent_new()) == NULL + || (_zip_dirent_read(cd->entry[i].orig, fp, bufp, &left, 0, error)) < 0) { _zip_cdir_free(cd); return NULL; } @@ -285,7 +271,6 @@ /* Infozip extension for more than 64k entries: nentries wraps around, size indicates correct EOCD */ if (_zip_cdir_grow(cd, cd->nentry+ZIP_UINT16_MAX, error) < 0) { - cd->nentry = i; _zip_cdir_free(cd); return NULL; } @@ -312,22 +297,22 @@ struct zip_dirent temp; if (cd->nentry) { - max = cd->entry[0].offset; - min = cd->entry[0].offset; + max = cd->entry[0].orig->offset; + min = cd->entry[0].orig->offset; } else min = max = 0; for (i=0; i<cd->nentry; i++) { - if (cd->entry[i].offset < min) - min = cd->entry[i].offset; + if (cd->entry[i].orig->offset < min) + min = cd->entry[i].orig->offset; if (min > cd->offset) { _zip_error_set(error, ZIP_ER_NOZIP, 0); return -1; } - j = cd->entry[i].offset + cd->entry[i].comp_size - + strlen(cd->entry[i].settable.filename) + LENTRYSIZE; + j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size + + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE; if (j > max) max = j; if (max > cd->offset) { @@ -335,7 +320,7 @@ return -1; } - if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) { + if (fseeko(fp, cd->entry[i].orig->offset, SEEK_SET) != 0) { _zip_error_set(error, ZIP_ER_SEEK, errno); return -1; } @@ -343,11 +328,16 @@ if (_zip_dirent_read(&temp, fp, NULL, NULL, 1, error) == -1) return -1; - if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) { + if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) { _zip_error_set(error, ZIP_ER_INCONS, 0); _zip_dirent_finalize(&temp); return -1; } + + cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields); + cd->entry[i].orig->local_extra_fields_read = 1; + temp.extra_fields = NULL; + _zip_dirent_finalize(&temp); } @@ -360,28 +350,27 @@ check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */ static void -_zip_check_torrentzip(struct zip *za) +_zip_check_torrentzip(struct zip *za, const struct zip_cdir *cdir) { uLong crc_got, crc_should; char buf[8+1]; char *end; - if (za->zp == NULL || za->cdir == NULL) + if (za->zp == NULL || cdir == NULL) return; - if (za->cdir->comment_len != TORRENT_SIG_LEN+8 - || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0) + if (_zip_string_length(cdir->comment) != TORRENT_SIG_LEN+8 + || strncmp((const char *)cdir->comment->raw, TORRENT_SIG, TORRENT_SIG_LEN) != 0) return; - memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8); + memcpy(buf, cdir->comment->raw+TORRENT_SIG_LEN, 8); buf[8] = '\0'; errno = 0; crc_should = strtoul(buf, &end, 16); if ((crc_should == UINT_MAX && errno != 0) || (end && *end)) return; - if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size, - &crc_got, NULL) < 0) + if (_zip_filerange_crc(za->zp, cdir->offset, cdir->size, &crc_got, NULL) < 0) return; if (crc_got == crc_should) @@ -392,66 +381,32 @@ /* _zip_headercomp: - compares two headers h1 and h2; if they are local headers, set - local1p or local2p respectively to 1, else 0. Return 0 if they - are identical, -1 if not. */ + compares a central directory entry and a local file header + Return 0 if they are consistent, -1 if not. */ static int -_zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2, - int local2p) +_zip_headercomp(struct zip_dirent *central, struct zip_dirent *local) { - if ((h1->version_needed != h2->version_needed) + if ((central->version_needed != local->version_needed) #if 0 /* some zip-files have different values in local and global headers for the bitflags */ - || (h1->bitflags != h2->bitflags) + || (central->bitflags != local->bitflags) #endif - || (h1->settable.comp_method != h2->settable.comp_method) - || (h1->last_mod != h2->last_mod) - || strcmp(h1->settable.filename, h2->settable.filename)) + || (central->comp_method != local->comp_method) + || (central->last_mod != local->last_mod) + || !_zip_string_equal(central->filename, local->filename)) return -1; - /* check that CRC and sizes are zero if data descriptor is used */ - if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p - && (h1->crc != 0 - || h1->comp_size != 0 - || h1->uncomp_size != 0)) - return -1; - if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p - && (h2->crc != 0 - || h2->comp_size != 0 - || h2->uncomp_size != 0)) - return -1; - - /* check that CRC and sizes are equal if no data descriptor is used */ - if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0) - && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) { - if ((h1->crc != h2->crc) - || (h1->comp_size != h2->comp_size) - || (h1->uncomp_size != h2->uncomp_size)) + + if ((central->crc != local->crc) || (central->comp_size != local->comp_size) + || (central->uncomp_size != local->uncomp_size)) { + /* InfoZip stores valid values in local header even when data descriptor is used. + This is in violation of the appnote. */ + if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 + || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0)) return -1; } - - if ((local1p == local2p) - && ((h1->settable.extrafield_len != h2->settable.extrafield_len) - || (h1->settable.extrafield_len && h2->settable.extrafield - && memcmp(h1->settable.extrafield, h2->settable.extrafield, - h1->settable.extrafield_len)))) - return -1; - - /* if either is local, nothing more to check */ - if (local1p || local2p) - return 0; - - if ((h1->version_madeby != h2->version_madeby) - || (h1->disk_number != h2->disk_number) - || (h1->int_attrib != h2->int_attrib) - || (h1->ext_attrib != h2->ext_attrib) - || (h1->offset != h2->offset) - || (h1->settable.comment_len != h2->settable.comment_len) - || (h1->settable.comment_len && h2->settable.comment - && memcmp(h1->settable.comment, h2->settable.comment, h1->settable.comment_len))) - return -1; return 0; } @@ -672,6 +627,11 @@ cdp = eocd64loc+8; eocd_offset = _zip_read8(&cdp); + if (eocd_offset+EOCD64LEN > buf_offset+(eocd64loc-buf)) { + _zip_error_set(error, ZIP_ER_INCONS, 0); + return NULL; + } + if (eocd_offset >= buf_offset) cdp = buf+(eocd_offset-buf_offset); else { @@ -692,14 +652,14 @@ } if (memcmp(cdp, EOCD64_MAGIC, 4) != 0) { - _zip_error_set(error, ZIP_ER_NOZIP, 0); + _zip_error_set(error, ZIP_ER_INCONS, 0); return NULL; } cdp += 4; size = _zip_read8(&cdp); - if ((flags & ZIP_CHECKCONS) && size+eocd_offset != buf_offset+(eocd64loc-buf)) { + if ((flags & ZIP_CHECKCONS) && size+eocd_offset+12 != buf_offset+(eocd64loc-buf)) { _zip_error_set(error, ZIP_ER_INCONS, 0); return NULL; }
diff --git a/lib/zip_replace.c b/lib/zip_replace.c index 53524e6..0d39306 100644 --- a/lib/zip_replace.c +++ b/lib/zip_replace.c
@@ -68,17 +68,19 @@ za_nentry_prev = za->nentry; if (idx == ZIP_UINT64_MAX) { - /* create and use new entry, used by zip_add */ - if (_zip_entry_new(za) == NULL) - return -1; + zip_int64_t i; - idx = za->nentry - 1; - za->entry[idx].changes.valid |= ZIP_DIRENT_COMP_METHOD; - za->entry[idx].changes.comp_method = ZIP_CM_DEFLATE; /* XXX: default */ + /* create and use new entry, used by zip_add */ + if ((i=_zip_add_entry(za)) < 0) + return -1; + idx = i; } if (name && _zip_set_name(za, idx, name) != 0) { - za->nentry = za_nentry_prev; + if (za->nentry != za_nentry_prev) { + _zip_entry_finalize(za->entry+idx); + za->nentry = za_nentry_prev; + } return -1; } @@ -86,8 +88,6 @@ * needed for a double add of the same file name */ _zip_unchange_data(za->entry+idx); - za->entry[idx].state = ((za->cdir == NULL || idx >= za->cdir->nentry) - ? ZIP_ST_ADDED : ZIP_ST_REPLACED); za->entry[idx].source = source; return idx;
diff --git a/lib/zip_set_archive_comment.c b/lib/zip_set_archive_comment.c index bbb9a73..f71bea7 100644 --- a/lib/zip_set_archive_comment.c +++ b/lib/zip_set_archive_comment.c
@@ -42,7 +42,12 @@ ZIP_EXTERN int zip_set_archive_comment(struct zip *za, const char *comment, int len) { - char *tmpcom; + struct zip_string *cstr; + + if (ZIP_IS_RDONLY(za)) { + _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } if (len < 0 || len > MAXCOMLEN || (len > 0 && comment == NULL)) { @@ -50,26 +55,31 @@ return -1; } - if (ZIP_IS_RDONLY(za)) { - _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); - return -1; - } - - if (_zip_guess_encoding(comment, len) == ZIP_ENCODING_CP437) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return -1; - } - if (len > 0) { - if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) + if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, &za->error)) == NULL) return -1; + + if (_zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_CP437) { + _zip_string_free(cstr); + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } } else - tmpcom = NULL; + cstr = NULL; - free(za->ch_comment); - za->ch_comment = tmpcom; - za->ch_comment_len = len; + _zip_string_free(za->comment_changes); + za->comment_changes = NULL; + + if (((za->comment_orig && _zip_string_equal(za->comment_orig, cstr)) + || (za->comment_orig == NULL && cstr == NULL))) { + _zip_string_free(cstr); + za->comment_changed = 0; + } + else { + za->comment_changes = cstr; + za->comment_changed = 1; + } return 0; }
diff --git a/lib/zip_set_file_comment.c b/lib/zip_set_file_comment.c index bccad10..0621ad2 100644 --- a/lib/zip_set_file_comment.c +++ b/lib/zip_set_file_comment.c
@@ -44,48 +44,74 @@ zip_set_file_comment(struct zip *za, zip_uint64_t idx, const char *comment, int len) { - char *tmpcom; - const char *name; - enum zip_encoding_type com_enc, enc; + struct zip_entry *e; + struct zip_string *cstr; + struct zip_dirent *de; + enum zip_encoding_type com_enc, name_enc; + int changed; - if (idx >= za->nentry - || len < 0 || len > MAXCOMLEN - || (len > 0 && comment == NULL)) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + if ((de=_zip_get_dirent(za, idx, 0, NULL)) == NULL) return -1; - } if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } - if ((com_enc=_zip_guess_encoding(comment, len)) == ZIP_ENCODING_CP437) { + if (len < 0 || len > MAXCOMLEN + || (len > 0 && comment == NULL)) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } - if ((name=zip_get_name(za, idx, ZIP_FL_NAME_RAW)) == NULL) - return -1; - enc = _zip_guess_encoding(name, strlen(name)); + if (len > 0) { + if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, &za->error)) == NULL) + return -1; - if (enc == ZIP_ENCODING_CP437 && com_enc == ZIP_ENCODING_UTF8) { + if ((com_enc=_zip_guess_encoding(cstr, ZIP_ENCODING_UTF8_KNOWN)) == ZIP_ENCODING_ERROR) { + _zip_string_free(cstr); + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + } + else { + cstr = NULL; + com_enc = ZIP_ENCODING_ASCII; + } + + name_enc = _zip_guess_encoding(de->filename, ZIP_ENCODING_UNKNOWN); + + if (name_enc == ZIP_ENCODING_CP437 && com_enc == ZIP_ENCODING_UTF8_KNOWN) { _zip_error_set(&za->error, ZIP_ER_ENCMISMATCH, 0); return -1; } - if (len > 0) { - if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) - return -1; - } - else - tmpcom = NULL; + e = za->entry+idx; - if (za->entry[idx].changes.valid & ZIP_DIRENT_COMMENT) - free(za->entry[idx].changes.comment); - za->entry[idx].changes.comment = tmpcom; - za->entry[idx].changes.comment_len = len; - za->entry[idx].changes.valid |= ZIP_DIRENT_COMMENT; - + if (e->changes) { + _zip_string_free(e->changes->comment); + e->changes->comment = NULL; + e->changes->changed &= ~ZIP_DIRENT_COMMENT; + } + + if (e->orig && e->orig->comment) + changed = !_zip_string_equal(e->orig->comment, cstr); + else + changed = (cstr != NULL); + + if (changed) { + if (e->changes == NULL) + e->changes = _zip_dirent_clone(e->orig); + e->changes->comment = cstr; + e->changes->changed |= ZIP_DIRENT_COMMENT; + } + else { + _zip_string_free(cstr); + if (e->changes && e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + } + return 0; }
diff --git a/lib/zip_set_file_compression.c b/lib/zip_set_file_compression.c index 25cb5a0..51a74a2 100644 --- a/lib/zip_set_file_compression.c +++ b/lib/zip_set_file_compression.c
@@ -41,32 +41,38 @@ zip_set_file_compression(struct zip *za, zip_uint64_t idx, zip_int32_t method, zip_uint32_t flags) { + struct zip_entry *e; + if (idx >= za->nentry) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } - if (method != ZIP_CM_DEFAULT && method != ZIP_CM_STORE && method != ZIP_CM_DEFLATE) { - _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); - return -1; - } - if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } - /* XXX: needs support for better of deflate/store - * update man page when fixing this */ - if (method == ZIP_CM_DEFAULT) - method = ZIP_CM_DEFLATE; + if (method != ZIP_CM_DEFAULT && method != ZIP_CM_STORE && method != ZIP_CM_DEFLATE) { + _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); + return -1; + } - if (za->cdir != NULL && idx < za->cdir->nentry && - method == za->cdir->entry[idx].settable.comp_method) - za->entry[idx].changes.valid &= ~ZIP_DIRENT_COMP_METHOD; - else { - za->entry[idx].changes.valid |= ZIP_DIRENT_COMP_METHOD; - za->entry[idx].changes.comp_method = method; + e = za->entry+idx; + + if (method != (e->orig ? e->orig->comp_method : ZIP_CM_DEFAULT)) { + if (e->changes == NULL) + e->changes = _zip_dirent_clone(e->orig); + + e->changes->comp_method = method; + e->changes->changed |= ZIP_DIRENT_COMP_METHOD; + } + else if (e->changes) { + e->changes->changed &= ~ZIP_DIRENT_COMP_METHOD; + if (e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } } return 0;
diff --git a/lib/zip_set_file_extra.c b/lib/zip_set_file_extra.c deleted file mode 100644 index 1a85bff..0000000 --- a/lib/zip_set_file_extra.c +++ /dev/null
@@ -1,74 +0,0 @@ -/* - zip_set_file_extra.c -- set extra field for file in archive - Copyright (C) 2006-2010 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> - - 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 <stdlib.h> - -#include "zipint.h" - - - -ZIP_EXTERN int -zip_set_file_extra(struct zip *za, zip_uint64_t idx, - const char *extra, int len) -{ - char *tmpext; - - if (idx >= za->nentry - || len < 0 || len > MAXEXTLEN - || (len > 0 && extra == NULL)) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return -1; - } - - if (ZIP_IS_RDONLY(za)) { - _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); - return -1; - } - - if (len > 0) { - if ((tmpext=(char *)_zip_memdup(extra, len, &za->error)) == NULL) - return -1; - } - else - tmpext = NULL; - - if (za->entry[idx].changes.valid & ZIP_DIRENT_EXTRAFIELD) - free(za->entry[idx].changes.extrafield); - za->entry[idx].changes.extrafield = tmpext; - za->entry[idx].changes.extrafield_len = len; - za->entry[idx].changes.valid |= ZIP_DIRENT_EXTRAFIELD; - - return 0; -}
diff --git a/lib/zip_set_name.c b/lib/zip_set_name.c index 7b43131..70a01d9 100644 --- a/lib/zip_set_name.c +++ b/lib/zip_set_name.c
@@ -43,53 +43,90 @@ int _zip_set_name(struct zip *za, zip_uint64_t idx, const char *name) { - char *s; - const char *com; - int comlen; - zip_int64_t i; - enum zip_encoding_type enc, com_enc; - - if (idx >= za->nentry || name == NULL) { + struct zip_entry *e; + struct zip_string *str; + struct zip_dirent *de; + enum zip_encoding_type com_enc, name_enc; + int changed; + int i; + + if (idx >= za->nentry) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } - if ((enc=_zip_guess_encoding(name, strlen(name))) == ZIP_ENCODING_CP437) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + if (ZIP_IS_RDONLY(za)) { + _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } + if (name && strlen(name) > 0) { + if ((str=_zip_string_new((const zip_uint8_t *)name, strlen(name), &za->error)) == NULL) + return -1; + + if ((name_enc=_zip_guess_encoding(str, ZIP_ENCODING_UTF8_KNOWN)) == ZIP_ENCODING_ERROR) { + _zip_string_free(str); + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + } + else { + str = NULL; + name_enc = ZIP_ENCODING_ASCII; + } + if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) { + _zip_string_free(str); _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); return -1; } /* no effective name change */ - if (i == idx) + if (i == idx) { + _zip_string_free(str); return 0; + } - com = zip_get_file_comment(za, idx, &comlen, ZIP_FL_NAME_RAW); - if (com == NULL) - com_enc = ZIP_ENCODING_ASCII; + de = _zip_get_dirent(za, idx, 0, NULL); + + if (de) + com_enc = _zip_guess_encoding(de->comment, ZIP_ENCODING_UNKNOWN); else - com_enc = _zip_guess_encoding(com, comlen); - if (com_enc == ZIP_ENCODING_CP437 && enc == ZIP_ENCODING_UTF8) { + com_enc = ZIP_ENCODING_ASCII; + + if (com_enc == ZIP_ENCODING_CP437 && name_enc == ZIP_ENCODING_UTF8_KNOWN) { + _zip_string_free(str); _zip_error_set(&za->error, ZIP_ER_ENCMISMATCH, 0); return -1; } - if ((s=strdup(name)) == NULL) { - _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); - return -1; - } - - if (za->entry[idx].state == ZIP_ST_UNCHANGED) - za->entry[idx].state = ZIP_ST_RENAMED; - if (za->entry[idx].changes.valid & ZIP_DIRENT_FILENAME) - free(za->entry[idx].changes.filename); - za->entry[idx].changes.filename = s; - za->entry[idx].changes.valid |= ZIP_DIRENT_FILENAME; + e = za->entry+idx; + + if (e->changes) { + _zip_string_free(e->changes->filename); + e->changes->filename = NULL; + e->changes->changed &= ~ZIP_DIRENT_FILENAME; + } + + if (e->orig && e->orig->filename) + changed = !_zip_string_equal(e->orig->filename, str); + else + changed = (str != NULL); + + if (changed) { + if (e->changes == NULL) + e->changes = _zip_dirent_clone(e->orig); + e->changes->filename = str; + e->changes->changed |= ZIP_DIRENT_FILENAME; + } + else { + _zip_string_free(str); + if (e->changes && e->changes->changed == 0) { + _zip_dirent_free(e->changes); + e->changes = NULL; + } + } return 0; }
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c index b5364a1..d3aa339 100644 --- a/lib/zip_source_zip_new.c +++ b/lib/zip_source_zip_new.c
@@ -58,13 +58,13 @@ } if ((flags & ZIP_FL_UNCHANGED) == 0 - && (ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx) || srcza->entry[srcidx].state == ZIP_ST_DELETED)) { + && (ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx) || srcza->entry[srcidx].deleted)) { _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); return NULL; } - if (srcza->cdir == NULL || srcidx >= srcza->cdir->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + if (zip_stat_index(srcza, srcidx, flags|ZIP_FL_UNCHANGED, &st) < 0) { + _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); return NULL; } @@ -76,11 +76,6 @@ return NULL; } - if (zip_stat_index(srcza, srcidx, flags, &st) < 0) { - _zip_error_set(&za->error, ZIP_ER_INTERNAL, 0); - return NULL; - } - if (len == -1) len = 0; @@ -96,8 +91,7 @@ _zip_error_set(&za->error, ZIP_ER_NOPASSWD, 0); return NULL; } - if ((enc_impl=zip_get_encryption_implementation( - st.encryption_method)) == NULL) { + if ((enc_impl=zip_get_encryption_implementation(st.encryption_method)) == NULL) { _zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0); return NULL; } @@ -106,8 +100,7 @@ comp_impl = NULL; if ((flags & ZIP_FL_COMPRESSED) == 0) { if (st.comp_method != ZIP_CM_STORE) { - if ((comp_impl=zip_get_compression_implementation( - st.comp_method)) == NULL) { + if ((comp_impl=zip_get_compression_implementation(st.comp_method)) == NULL) { _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return NULL; } @@ -123,9 +116,15 @@ } else { if (start+len > 0 && enc_impl == NULL && comp_impl == NULL) { - if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset+start, - len ? len : st.size-start, - 0, &st)) == NULL) + struct zip_stat st2; + + st2.size = len ? len : st.size-start; + st2.comp_size = st2.size; + st2.comp_method = ZIP_CM_STORE; + st2.mtime = st.mtime; + st2.valid = ZIP_STAT_SIZE|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_MTIME; + + if ((src=_zip_source_file_or_p(za, NULL, srcza->zp, offset+start, st2.size, 0, &st2)) == NULL) return NULL; } else { @@ -151,7 +150,7 @@ src = s2; } if (((flags & ZIP_FL_COMPRESSED) == 0 || st.comp_method == ZIP_CM_STORE) - && (len == 0 || start+len == st.comp_size)) { + && (len == 0 || len == st.comp_size)) { /* when reading the whole file, check for crc errors */ if ((s2=zip_source_crc(za, src, 1)) == NULL) { zip_source_free(src);
diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c index 771c686..4427958 100644 --- a/lib/zip_stat_index.c +++ b/lib/zip_stat_index.c
@@ -42,11 +42,10 @@ struct zip_stat *st) { const char *name; - - if (index >= za->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + struct zip_dirent *de; + + if ((de=_zip_get_dirent(za, index, flags, NULL)) == NULL) return -1; - } if ((name=zip_get_name(za, index, flags)) == NULL) return -1; @@ -60,23 +59,15 @@ } } else { - if (za->cdir == NULL || index >= za->cdir->nentry) { - _zip_error_set(&za->error, ZIP_ER_INVAL, 0); - return -1; - } - zip_stat_init(st); - st->crc = za->cdir->entry[index].crc; - st->size = za->cdir->entry[index].uncomp_size; - st->mtime = za->cdir->entry[index].last_mod; - st->comp_size = za->cdir->entry[index].comp_size; - if ((flags & ZIP_FL_UNCHANGED) == 0 && (za->entry[index].changes.valid & ZIP_DIRENT_COMP_METHOD)) - st->comp_method = za->entry[index].changes.comp_method; - else - st->comp_method = za->cdir->entry[index].settable.comp_method; - if (za->cdir->entry[index].bitflags & ZIP_GPBF_ENCRYPTED) { - if (za->cdir->entry[index].bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { + st->crc = de->crc; + st->size = de->uncomp_size; + st->mtime = de->last_mod; + st->comp_size = de->comp_size; + st->comp_method = de->comp_method; + if (de->bitflags & ZIP_GPBF_ENCRYPTED) { + if (de->bitflags & ZIP_GPBF_STRONG_ENCRYPTION) { /* XXX */ st->encryption_method = ZIP_EM_UNKNOWN; }
diff --git a/lib/zip_string.c b/lib/zip_string.c new file mode 100644 index 0000000..b837ea8 --- /dev/null +++ b/lib/zip_string.c
@@ -0,0 +1,157 @@ +/* + zip_string.c -- string handling (with encoding) + Copyright (C) 2012 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> + + 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 <stdlib.h> +#include <string.h> + +#include "zipint.h" + + + +int +_zip_string_equal(const struct zip_string *a, const struct zip_string *b) +{ + if (a == NULL || b == NULL) + return a == b; + + if (a->length != b->length) + return 0; + + /* XXX: encoding */ + + return (memcmp(a->raw, b->raw, a->length) == 0); +} + + + +void +_zip_string_free(struct zip_string *s) +{ + if (s == NULL) + return; + + free(s->raw); + free(s->converted); + free(s); +} + + + +const zip_uint8_t * +_zip_string_get(struct zip_string *string, zip_uint32_t *lenp, int flags, struct zip_error *error) +{ + static const zip_uint8_t empty[1] = ""; + + if (string == NULL) { + if (lenp) + *lenp = 0; + return empty; + } + + if ((flags & ZIP_FL_NAME_RAW) == 0) { + /* start guessing */ + if (string->encoding == ZIP_ENCODING_UNKNOWN) + _zip_guess_encoding(string, ZIP_ENCODING_UNKNOWN); + + if (((flags & ZIP_FL_NAME_STRICT) + && string->encoding != ZIP_ENCODING_ASCII && string->encoding != ZIP_ENCODING_UTF8_KNOWN) + || (string->encoding == ZIP_ENCODING_CP437)) { + if (string->converted == NULL) { + if ((string->converted=_zip_cp437_to_utf8(string->raw, string->length, + &string->converted_length, error)) == NULL) + return NULL; + } + if (lenp) + *lenp = string->converted_length; + return string->converted; + } + } + + if (lenp) + *lenp = string->length; + return string->raw; +} + + + +zip_uint16_t +_zip_string_length(const struct zip_string *s) +{ + if (s == NULL) + return 0; + + return s->length; +} + + + +struct zip_string * +_zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, struct zip_error *error) +{ + struct zip_string *s; + + if (length == 0) + return NULL; + + if ((s=malloc(sizeof(*s))) == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + return NULL; + } + + if ((s->raw=malloc(length+1)) == NULL) { + free(s); + return NULL; + } + + memcpy(s->raw, raw, length); + s->raw[length] = '\0'; + s->length = length; + s->encoding = ZIP_ENCODING_UNKNOWN; + s->converted = NULL; + s->converted_length = 0; + + return s; +} + + + +void +_zip_string_write(const struct zip_string *s, FILE *f) +{ + if (s == NULL) + return; + + fwrite(s->raw, s->length, 1, f); +}
diff --git a/lib/zip_unchange.c b/lib/zip_unchange.c index 61adf50..7026063 100644 --- a/lib/zip_unchange.c +++ b/lib/zip_unchange.c
@@ -57,25 +57,16 @@ return -1; } - if (za->entry[idx].changes.valid & ZIP_DIRENT_FILENAME) { - if (!allow_duplicates) { - i = _zip_name_locate(za, - _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL), - 0, NULL); - if (i != -1 && i != idx) { - _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); - return -1; - } + if (!allow_duplicates && za->entry[idx].changes && (za->entry[idx].changes->changed & ZIP_DIRENT_FILENAME)) { + i = _zip_name_locate(za, _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL), 0, NULL); + if (i != -1 && i != idx) { + _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); + return -1; } - - free(za->entry[idx].changes.filename); } - if (za->entry[idx].changes.valid & ZIP_DIRENT_EXTRAFIELD) - free(za->entry[idx].changes.extrafield); - if (za->entry[idx].changes.valid & ZIP_DIRENT_COMMENT) - free(za->entry[idx].changes.comment); - za->entry[idx].changes.valid = 0; + _zip_dirent_free(za->entry[idx].changes); + za->entry[idx].changes = NULL; _zip_unchange_data(za->entry+idx);
diff --git a/lib/zip_unchange_archive.c b/lib/zip_unchange_archive.c index 8f9c024..e24ee21 100644 --- a/lib/zip_unchange_archive.c +++ b/lib/zip_unchange_archive.c
@@ -42,10 +42,12 @@ ZIP_EXTERN int zip_unchange_archive(struct zip *za) { - free(za->ch_comment); - za->ch_comment = NULL; - za->ch_comment_len = -1; - + if (za->comment_changed) { + _zip_string_free(za->comment_changes); + za->comment_changes = NULL; + za->comment_changed = 0; + } + za->ch_flags = za->flags; return 0;
diff --git a/lib/zip_unchange_data.c b/lib/zip_unchange_data.c index fab51de..105ea3a 100644 --- a/lib/zip_unchange_data.c +++ b/lib/zip_unchange_data.c
@@ -1,6 +1,6 @@ /* zip_unchange_data.c -- undo helper function - Copyright (C) 1999, 2004 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2012 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> @@ -33,8 +33,6 @@ -#include <stdlib.h> - #include "zipint.h" void @@ -44,7 +42,7 @@ zip_source_free(ze->source); ze->source = NULL; } - - ze->state = (ze->changes.valid & ZIP_DIRENT_FILENAME) ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED; + + ze->deleted = 0; }
diff --git a/lib/zip_utf-8.c b/lib/zip_utf-8.c index d184b17..4b8e4b1 100644 --- a/lib/zip_utf-8.c +++ b/lib/zip_utf-8.c
@@ -118,39 +118,65 @@ enum zip_encoding_type -_zip_guess_encoding(const char * const _name, zip_uint32_t len) +_zip_guess_encoding(struct zip_string *str, enum zip_encoding_type expected_encoding) { - zip_uint8_t *name = (zip_uint8_t *)_name; + enum zip_encoding_type enc; + const zip_uint8_t *name; zip_uint32_t i; - int ret; int j, ulen; - ret = ZIP_ENCODING_ASCII; - for (i=0; i<len; i++) { - if ((name[i] > 31 && name[i] < 128) || name[i] == '\r' || name[i] == '\n' || name[i] == '\t') - continue; + if (str == NULL) + return ZIP_ENCODING_ASCII; - ret = ZIP_ENCODING_UTF8; - if ((name[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH) - ulen = 1; - else if ((name[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH) - ulen = 2; - else if ((name[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH) - ulen = 3; - else - return ZIP_ENCODING_CP437; + name = str->raw; - if (i + ulen >= len) - return ZIP_ENCODING_CP437; + if (str->encoding != ZIP_ENCODING_UNKNOWN) + enc = str->encoding; + else { + enc = ZIP_ENCODING_ASCII; + for (i=0; i<str->length; i++) { + if ((name[i] > 31 && name[i] < 128) || name[i] == '\r' || name[i] == '\n' || name[i] == '\t') + continue; - for (j=1; j<=ulen; j++) { - if ((name[i+j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH) - return ZIP_ENCODING_CP437; + enc = ZIP_ENCODING_UTF8_GUESSED; + if ((name[i] & UTF_8_LEN_2_MASK) == UTF_8_LEN_2_MATCH) + ulen = 1; + else if ((name[i] & UTF_8_LEN_3_MASK) == UTF_8_LEN_3_MATCH) + ulen = 2; + else if ((name[i] & UTF_8_LEN_4_MASK) == UTF_8_LEN_4_MATCH) + ulen = 3; + else { + enc = ZIP_ENCODING_CP437; + break; + } + + if (i + ulen >= str->length) { + enc = ZIP_ENCODING_CP437; + break; + } + + for (j=1; j<=ulen; j++) { + if ((name[i+j] & UTF_8_CONTINUE_MASK) != UTF_8_CONTINUE_MATCH) { + enc = ZIP_ENCODING_CP437; + goto done; + } + } + i += ulen; } - i += ulen; } - return ret; +done: + str->encoding = enc; + + if (expected_encoding != ZIP_ENCODING_UNKNOWN) { + if (expected_encoding == ZIP_ENCODING_UTF8_KNOWN && enc == ZIP_ENCODING_UTF8_GUESSED) + str->encoding = enc = ZIP_ENCODING_UTF8_KNOWN; + + if (expected_encoding != enc && enc != ZIP_ENCODING_ASCII) + return ZIP_ENCODING_ERROR; + } + + return enc; } @@ -196,8 +222,8 @@ -char * -_zip_cp437_to_utf8(const char * const _cp437buf, zip_uint32_t len, +zip_uint8_t * +_zip_cp437_to_utf8(const zip_uint8_t * const _cp437buf, zip_uint32_t len, zip_uint32_t *utf8_lenp, struct zip_error *error) { zip_uint8_t *cp437buf = (zip_uint8_t *)_cp437buf; @@ -227,5 +253,5 @@ utf8buf[buflen-1] = 0; if (utf8_lenp) *utf8_lenp = buflen-1; - return (char *)utf8buf; + return utf8buf; }
diff --git a/lib/zipint.h b/lib/zipint.h index c2cdf3b..a03fe7c 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -180,11 +180,6 @@ -/* state of change of a file in zip archive */ - -enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED, - ZIP_ST_ADDED, ZIP_ST_RENAMED }; - /* error source for layered sources */ enum zip_les { ZIP_LES_NONE, ZIP_LES_UPPER, ZIP_LES_LOWER, ZIP_LES_INVAL }; @@ -196,12 +191,21 @@ #define ZIP_GPBF_STRONG_ENCRYPTION 0x0040 /* uses strong encryption */ #define ZIP_GPBF_ENCODING_UTF_8 0x0800 /* file name encoding is UTF-8 */ + +/* extra fields */ +#define ZIP_EF_LOCAL ZIP_FL_LOCAL /* include in local header */ +#define ZIP_EF_CENTRAL ZIP_FL_CENTRAL /* include in central directory */ +#define ZIP_EF_BOTH (ZIP_EF_LOCAL|ZIP_EF_CENTRAL) /* include in both */ + + /* encoding type */ enum zip_encoding_type { - ZIP_ENCODING_UNKNOWN, /* not yet analyzed */ - ZIP_ENCODING_ASCII, /* plain ASCII */ - ZIP_ENCODING_UTF8, /* possibly UTF-8 */ - ZIP_ENCODING_CP437 /* Code Page 437 */ + ZIP_ENCODING_UNKNOWN, /* not yet analyzed */ + ZIP_ENCODING_ASCII, /* plain ASCII */ + ZIP_ENCODING_UTF8_KNOWN, /* is UTF-8 */ + ZIP_ENCODING_UTF8_GUESSED, /* possibly UTF-8 */ + ZIP_ENCODING_CP437, /* Code Page 437 */ + ZIP_ENCODING_ERROR /* should be UTF-8 but isn't */ }; /* error information */ @@ -215,26 +219,27 @@ /* zip archive, part of API */ struct zip { - char *zn; /* file name */ - FILE *zp; /* file */ - unsigned int open_flags; /* flags passed to zip_open */ - struct zip_error error; /* error information */ + char *zn; /* file name */ + FILE *zp; /* file */ + unsigned int open_flags; /* flags passed to zip_open */ + struct zip_error error; /* error information */ - unsigned int flags; /* archive global flags */ - unsigned int ch_flags; /* changed archive global flags */ + unsigned int flags; /* archive global flags */ + unsigned int ch_flags; /* changed archive global flags */ - char *default_password; /* password used when no other supplied */ + char *default_password; /* password used when no other supplied */ - struct zip_cdir *cdir; /* central directory */ - char *ch_comment; /* changed archive comment */ - zip_int32_t ch_comment_len; /* length of changed zip archive - * comment, -1 if unchanged */ - zip_uint64_t nentry; /* number of entries */ - zip_uint64_t nentry_alloc; /* number of entries allocated */ - struct zip_entry *entry; /* entries */ - unsigned int nfile; /* number of opened files within archive */ - unsigned int nfile_alloc; /* number of files allocated */ - struct zip_file **file; /* opened files within archive */ + struct zip_string *comment_orig; /* archive comment */ + struct zip_string *comment_changes; /* changed archive comment */ + int comment_changed; /* whether archive comment was changed */ + + zip_uint64_t nentry; /* number of entries */ + zip_uint64_t nentry_alloc; /* number of entries allocated */ + struct zip_entry *entry; /* entries */ + + unsigned int nfile; /* number of opened files within archive */ + unsigned int nfile_alloc; /* number of files allocated */ + struct zip_file **file; /* opened files within archive */ }; /* file in zip archive, part of API */ @@ -251,59 +256,48 @@ #define ZIP_DIRENT_COMP_METHOD 0x0001 #define ZIP_DIRENT_FILENAME 0x0002 #define ZIP_DIRENT_COMMENT 0x0004 -#define ZIP_DIRENT_EXTRAFIELD 0x0008 +#define ZIP_DIRENT_EXTRA_FIELD 0x0008 #define ZIP_DIRENT_ALL 0xffff -struct zip_dirent_settable { - zip_uint32_t valid; - zip_int32_t comp_method; /* (cl) compression method used (uint16 and ZIP_CM_DEFAULT (-1)) */ - char *filename; /* (cl) file name (NUL-terminated) */ - char *comment; /* (c) file comment */ - zip_uint16_t comment_len; /* (c) length of file comment */ - char *extrafield; /* (l) extra field local header */ - zip_uint16_t extrafield_len; /* (l) length of extra field from local header*/ -#if 0 - char *cdir_extrafield; /* (c) extra field from cdir */ - zip_uint16_t cdir_extrafield_len; /* (c) length of extra field from cdir*/ - struct zip_extrafield *extra_parsed; /* parsed extra fields */ - zip_uint16_t nextra_parsed; /* number of parsed extra fields */ - zip_uint16_t nextra_parsed_alloc; /* number of parsed extra fields allocated */ -#endif -}; - struct zip_dirent { - zip_uint16_t version_madeby; /* (c) version of creator */ - zip_uint16_t version_needed; /* (cl) version needed to extract */ - zip_uint16_t bitflags; /* (cl) general purpose bit flag */ - time_t last_mod; /* (cl) time of last modification */ - zip_uint32_t crc; /* (cl) CRC-32 of uncompressed data */ - zip_uint64_t comp_size; /* (cl) size of compressed data */ - zip_uint64_t uncomp_size; /* (cl) size of uncompressed data */ - zip_uint32_t disk_number; /* (c) disk number start */ - zip_uint16_t int_attrib; /* (c) internal file attributes */ - zip_uint32_t ext_attrib; /* (c) external file attributes */ - zip_uint64_t offset; /* (c) offset of local header */ - enum zip_encoding_type fn_type; /* file name encoding (autorecognition) */ - char *filename_converted; /* file name (autoconverted) */ - enum zip_encoding_type fc_type; /* file comment encoding (autorecognition) */ - char *comment_converted; /* file comment (autoconverted) */ - zip_uint32_t comment_converted_len; /* file comment length (autoconverted) */ - struct zip_dirent_settable settable; + zip_uint32_t changed; + int local_extra_fields_read; /* whether we already read in local header extra fields */ + + zip_uint16_t version_madeby; /* (c) version of creator */ + zip_uint16_t version_needed; /* (cl) version needed to extract */ + zip_uint16_t bitflags; /* (cl) general purpose bit flag */ + zip_int32_t comp_method; /* (cl) compression method used (uint16 and ZIP_CM_DEFAULT (-1)) */ + time_t last_mod; /* (cl) time of last modification */ + zip_uint32_t crc; /* (cl) CRC-32 of uncompressed data */ + zip_uint64_t comp_size; /* (cl) size of compressed data */ + zip_uint64_t uncomp_size; /* (cl) size of uncompressed data */ + struct zip_string *filename; /* (cl) file name (NUL-terminated) */ + struct zip_extra_field *extra_fields; /* (cl) extra fields, parsed */ + struct zip_string *comment; /* (c) file comment */ + zip_uint32_t disk_number; /* (c) disk number start */ + zip_uint16_t int_attrib; /* (c) internal file attributes */ + zip_uint32_t ext_attrib; /* (c) external file attributes */ + zip_uint64_t offset; /* (c) offset of local header */ }; /* zip archive central directory */ struct zip_cdir { - struct zip_dirent *entry; /* directory entries */ + struct zip_entry *entry; /* directory entries */ unsigned int nentry; /* number of entries */ + unsigned int nentry_alloc; /* number of entries allocated */ - zip_uint64_t size; /* size of central direcotry */ + zip_uint64_t size; /* size of central directory */ zip_uint64_t offset; /* offset of central directory in file */ - char *comment; /* zip archive comment */ - zip_uint16_t comment_len; /* length of zip archive comment */ - enum zip_encoding_type comment_type; /* archive comment encoding (autorecognition) */ - char *comment_converted; /* archive comment (autoconverted) */ - zip_uint32_t comment_converted_len; /* archive comment length (autoconverted) */ + struct zip_string *comment; /* zip archive comment */ +}; + +struct zip_extra_field { + struct zip_extra_field *next; + zip_uint16_t flags; /* in local/central header */ + zip_uint16_t id; /* header id */ + zip_uint16_t size; /* data size */ + zip_uint8_t *data; }; @@ -322,9 +316,31 @@ /* entry in zip archive directory */ struct zip_entry { - enum zip_state state; + struct zip_dirent *orig; + struct zip_dirent *changes; struct zip_source *source; - struct zip_dirent_settable changes; + int deleted; +}; + + + +/* file or archive comment, or filename */ + +struct zip_string { + zip_uint8_t *raw; /* raw string */ + zip_uint16_t length; /* length of raw string */ + unsigned short encoding; /* autorecognized encoding */ + zip_uint8_t *converted; /* autoconverted string */ + zip_uint32_t converted_length; /* length of converted */ +}; + + + +/* which files to write, and in which order (name is for torrentzip sorting) */ + +struct zip_filelist { + int idx; + const char *name; }; @@ -335,30 +351,43 @@ -#define ZIP_ENTRY_DATA_CHANGED(x) \ - ((x)->state == ZIP_ST_REPLACED \ - || (x)->state == ZIP_ST_ADDED) +#define ZIP_ENTRY_CHANGED(e, f) ((e)->changes && ((e)->changes->changed & (f))) + +#define ZIP_ENTRY_DATA_CHANGED(x) ((x)->source != NULL) #define ZIP_IS_RDONLY(za) ((za)->ch_flags & ZIP_AFL_RDONLY) +zip_int64_t _zip_add_entry(struct zip *); + int _zip_cdir_compute_crc(struct zip *, uLong *); void _zip_cdir_free(struct zip_cdir *); int _zip_cdir_grow(struct zip_cdir *, int, struct zip_error *); struct zip_cdir *_zip_cdir_new(int, struct zip_error *); -int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *); +zip_int64_t _zip_cdir_write(struct zip *, const struct zip_filelist *, int, FILE *); +struct zip_dirent *_zip_dirent_clone(const struct zip_dirent *); +void _zip_dirent_free(struct zip_dirent *); void _zip_dirent_finalize(struct zip_dirent *); void _zip_dirent_init(struct zip_dirent *); +struct zip_dirent *_zip_dirent_new(void); int _zip_dirent_read(struct zip_dirent *, FILE *, const unsigned char **, zip_uint32_t *, int, struct zip_error *); +zip_int32_t _zip_dirent_size(FILE *, zip_uint16_t, struct zip_error *); void _zip_dirent_torrent_normalize(struct zip_dirent *); int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *); -void _zip_entry_free(struct zip_entry *); -void _zip_entry_init(struct zip *, int); -struct zip_entry *_zip_entry_new(struct zip *); +void _zip_ef_free(struct zip_extra_field *); +const zip_uint8_t *_zip_ef_get_by_id(struct zip_extra_field *, zip_uint16_t *, zip_uint16_t, zip_uint16_t, zip_uint16_t, struct zip_error *); +struct zip_extra_field *_zip_ef_merge(struct zip_extra_field *, struct zip_extra_field *); +struct zip_extra_field *_zip_ef_new(zip_uint16_t, zip_uint16_t, const zip_uint8_t *, zip_uint16_t); +struct zip_extra_field *_zip_ef_parse(const zip_uint8_t *, zip_uint16_t, zip_uint16_t, struct zip_error *); +zip_uint16_t _zip_ef_size(struct zip_extra_field *, zip_uint16_t); +void _zip_ef_write(struct zip_extra_field *, zip_uint16_t, FILE *); + +void _zip_entry_finalize(struct zip_entry *); +void _zip_entry_init(struct zip_entry *); void _zip_error_clear(struct zip_error *); void _zip_error_copy(struct zip_error *, struct zip_error *); @@ -376,12 +405,16 @@ int _zip_filerange_crc(FILE *, off_t, off_t, uLong *, struct zip_error *); -enum zip_encoding_type _zip_guess_encoding(const char * const, zip_uint32_t); -char *_zip_cp437_to_utf8(const char * const, zip_uint32_t, +struct zip_dirent *_zip_get_dirent(struct zip *, zip_uint64_t, int, struct zip_error *); + +enum zip_encoding_type _zip_guess_encoding(struct zip_string *, enum zip_encoding_type); +zip_uint8_t *_zip_cp437_to_utf8(const zip_uint8_t * const, zip_uint32_t, zip_uint32_t *, struct zip_error *error); struct zip *_zip_open(const char *, FILE *, int, int, int *); +int _zip_read_local_ef(struct zip *, int); + struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, zip_uint64_t, zip_int64_t, int, const struct zip_stat *); @@ -389,6 +422,13 @@ struct zip_source *_zip_source_zip_new(struct zip *, struct zip *, zip_uint64_t, int, zip_uint64_t, zip_int64_t, const char *); +int _zip_string_equal(const struct zip_string *, const struct zip_string *); +void _zip_string_free(struct zip_string *); +const zip_uint8_t *_zip_string_get(struct zip_string *, zip_uint32_t *, int, struct zip_error *); +zip_uint16_t _zip_string_length(const struct zip_string *); +struct zip_string *_zip_string_new(const zip_uint8_t *, zip_uint16_t, struct zip_error *); +void _zip_string_write(const struct zip_string *, FILE *); + int _zip_changed(struct zip *, int *); const char *_zip_get_name(struct zip *, zip_uint64_t, int, struct zip_error *); int _zip_local_header_read(struct zip *, int); @@ -398,6 +438,7 @@ zip_uint16_t _zip_read2(const unsigned char **); zip_uint32_t _zip_read4(const unsigned char **); zip_uint64_t _zip_read8(const unsigned char **); +zip_uint8_t *_zip_read_data(const unsigned char **, FILE *, int, int, struct zip_error *); zip_int64_t _zip_replace(struct zip *, zip_uint64_t, const char *, struct zip_source *); int _zip_set_name(struct zip *, zip_uint64_t, const char *); @@ -405,4 +446,8 @@ int _zip_unchange(struct zip *, zip_uint64_t, int); void _zip_unchange_data(struct zip_entry *); +void _zip_write2(zip_uint16_t, FILE *); +void _zip_write4(zip_uint32_t, FILE *); + + #endif /* zipint.h */
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt index 53d114b..31d6c9b 100644 --- a/man/CMakeLists.txt +++ b/man/CMakeLists.txt
@@ -19,7 +19,6 @@ zip_get_archive_comment.mdoc zip_get_archive_flag.mdoc zip_get_file_comment.mdoc - zip_get_file_extra.mdoc zip_get_name.mdoc zip_get_num_entries.mdoc zip_get_num_files.mdoc @@ -31,7 +30,6 @@ zip_set_default_password.mdoc zip_set_file_comment.mdoc zip_set_file_compression.mdoc - zip_set_file_extra.mdoc zip_source_buffer.mdoc zip_source_file.mdoc zip_source_filep.mdoc
diff --git a/man/Makefile.am b/man/Makefile.am index 9e83698..71671eb 100644 --- a/man/Makefile.am +++ b/man/Makefile.am
@@ -26,7 +26,6 @@ zip_get_archive_comment.mdoc \ zip_get_archive_flag.mdoc \ zip_get_file_comment.mdoc \ - zip_get_file_extra.mdoc \ zip_get_name.mdoc \ zip_get_num_entries.mdoc \ zip_get_num_files.mdoc \ @@ -38,7 +37,6 @@ zip_set_default_password.mdoc \ zip_set_file_comment.mdoc \ zip_set_file_compression.mdoc \ - zip_set_file_extra.mdoc \ zip_source_buffer.mdoc \ zip_source_file.mdoc \ zip_source_filep.mdoc \
diff --git a/man/zip_get_file_extra.man b/man/zip_get_file_extra.man deleted file mode 100644 index b767b47..0000000 --- a/man/zip_get_file_extra.man +++ /dev/null
@@ -1,90 +0,0 @@ -.\" zip_get_file_extra.mdoc \-- get extra field for file in zip -.\" Copyright (C) 2006-2011 Dieter Baron and Thomas Klausner -.\" -.\" This file is part of libzip, a library to manipulate ZIP files. -.\" The authors can be contacted at <libzip@nih.at> -.\" -.\" 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. -.\" -.TH ZIP_GET_FILE_EXTRA 3 "February 13, 2011" NiH -.SH "NAME" -zip_get_file_extra \- get extra field for file in zip -.SH "LIBRARY" -libzip (-lzip) -.SH "SYNOPSIS" -#include <zip.h> -.PP -const char * -zip_get_file_extra(struct zip *archive, zip_uint64_t index); \ -"int *lenp" "int flags" -.SH "DESCRIPTION" -The -zip_get_file_extra -function returns the extra field for the file at position -\fBindex\fR -in the zip archive. -This pointer should not be modified or -free(3) -Ap d. -If -\fBlenp\fR -is not -\fBNULL,\fR -the integer to which it points will be set to the length of the -extra. -If -\fBflags\fR -is set to -\fBZIP_FL_UNCHANGED,\fR -the original unchanged extra field is returned. -.SH "RETURN VALUES" -Upon successful completion, a pointer to the extra field is returned, -or -\fBNULL\fR -if there is no extra field. -In case of an error, -\fBNULL\fR -is returned and the error code in -\fBarchive\fR -is set to indicate the error. -.SH "ERRORS" -zip_get_file_extra -fails if: -.RS -.TP 4 -[ZIP_ER_INVAL] -\fBindex\fR -is not a valid file index in -\fBarchive.\fR -.RE -.SH "SEE ALSO" -libzip(3), -zip_set_file_extra(3) -.SH "AUTHORS" - -Dieter Baron <dillo@giga.or.at> -and -Thomas Klausner <tk@giga.or.at>
diff --git a/man/zip_get_file_extra.mdoc b/man/zip_get_file_extra.mdoc deleted file mode 100644 index bf6e49e..0000000 --- a/man/zip_get_file_extra.mdoc +++ /dev/null
@@ -1,90 +0,0 @@ -.\" zip_get_file_extra.mdoc -- get extra field for file in zip -.\" Copyright (C) 2006-2011 Dieter Baron and Thomas Klausner -.\" -.\" This file is part of libzip, a library to manipulate ZIP files. -.\" The authors can be contacted at <libzip@nih.at> -.\" -.\" 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. -.\" -.Dd February 13, 2011 -.Dt ZIP_GET_FILE_EXTRA 3 -.Os -.Sh NAME -.Nm zip_get_file_extra -.Nd get extra field for file in zip -.Sh LIBRARY -libzip (-lzip) -.Sh SYNOPSIS -.In zip.h -.Ft const char * -.Fn zip_get_file_extra "struct zip *archive" "zip_uint64_t index" \ -"int *lenp" "int flags" -.Sh DESCRIPTION -The -.Fn zip_get_file_extra -function returns the extra field for the file at position -.Ar index -in the zip archive. -This pointer should not be modified or -.Xr free 3 Ap d . -If -.Ar lenp -is not -.Dv NULL , -the integer to which it points will be set to the length of the -extra. -If -.Ar flags -is set to -.Dv ZIP_FL_UNCHANGED , -the original unchanged extra field is returned. -.Sh RETURN VALUES -Upon successful completion, a pointer to the extra field is returned, -or -.Dv NULL -if there is no extra field. -In case of an error, -.Dv NULL -is returned and the error code in -.Ar archive -is set to indicate the error. -.Sh ERRORS -.Fn zip_get_file_extra -fails if: -.Bl -tag -width Er -.It Bq Er ZIP_ER_INVAL -.Ar index -is not a valid file index in -.Ar archive . -.El -.Sh SEE ALSO -.Xr libzip 3 , -.Xr zip_set_file_extra 3 -.Sh AUTHORS -.An -nosplit -.An Dieter Baron Aq dillo@giga.or.at -and -.An Thomas Klausner Aq tk@giga.or.at
diff --git a/man/zip_set_file_extra.man b/man/zip_set_file_extra.man deleted file mode 100644 index 7298c1a..0000000 --- a/man/zip_set_file_extra.man +++ /dev/null
@@ -1,88 +0,0 @@ -.\" zip_set_file_extra.mdoc \-- set extra field for file in zip -.\" Copyright (C) 2006-2011 Dieter Baron and Thomas Klausner -.\" -.\" This file is part of libzip, a library to manipulate ZIP files. -.\" The authors can be contacted at <libzip@nih.at> -.\" -.\" 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. -.\" -.TH ZIP_SET_FILE_EXTRA 3 "February 13, 2011" NiH -.SH "NAME" -zip_set_file_extra \- set extra field for file in zip -.SH "LIBRARY" -libzip (-lzip) -.SH "SYNOPSIS" -#include <zip.h> -.PP -int -zip_set_file_extra(struct zip *archive, zip_uint64_t index); \ -"const char *extra" "int len" -.SH "DESCRIPTION" -The -zip_set_file_extra -function sets the extra field for the file at position -\fBindex\fR -in the zip archive to -\fBextra\fR -of length -\fBlen.\fR -If -\fBextra\fR -is -\fBNULL\fR -and -\fBlen\fR -is 0, the file extra field will be removed. -.SH "RETURN VALUES" -Upon successful completion 0 is returned. -Otherwise, \-1 is returned and the error information in -\fBarchive\fR -is set to indicate the error. -.SH "ERRORS" -zip_set_file_extra -fails if: -.RS -.TP 4 -[ZIP_ER_INVAL] -\fBindex\fR -is not a valid file index in -\fBarchive,\fR -or -\fBlen\fR -is less than 0 or longer than the maximum extra field length in a zip file -(65535). -.TP 4 -[ZIP_ER_MEMORY] -Required memory could not be allocated. -.RE -.SH "SEE ALSO" -libzip(3), -zip_get_file_extra(3) -.SH "AUTHORS" - -Dieter Baron <dillo@giga.or.at> -and -Thomas Klausner <tk@giga.or.at>
diff --git a/man/zip_set_file_extra.mdoc b/man/zip_set_file_extra.mdoc deleted file mode 100644 index d54a14c..0000000 --- a/man/zip_set_file_extra.mdoc +++ /dev/null
@@ -1,88 +0,0 @@ -.\" zip_set_file_extra.mdoc -- set extra field for file in zip -.\" Copyright (C) 2006-2011 Dieter Baron and Thomas Klausner -.\" -.\" This file is part of libzip, a library to manipulate ZIP files. -.\" The authors can be contacted at <libzip@nih.at> -.\" -.\" 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. -.\" -.Dd February 13, 2011 -.Dt ZIP_SET_FILE_EXTRA 3 -.Os -.Sh NAME -.Nm zip_set_file_extra -.Nd set extra field for file in zip -.Sh LIBRARY -libzip (-lzip) -.Sh SYNOPSIS -.In zip.h -.Ft int -.Fn zip_set_file_extra "struct zip *archive" "zip_uint64_t index" \ -"const char *extra" "int len" -.Sh DESCRIPTION -The -.Fn zip_set_file_extra -function sets the extra field for the file at position -.Ar index -in the zip archive to -.Ar extra -of length -.Ar len . -If -.Ar extra -is -.Dv NULL -and -.Ar len -is 0, the file extra field will be removed. -.Sh RETURN VALUES -Upon successful completion 0 is returned. -Otherwise, \-1 is returned and the error information in -.Ar archive -is set to indicate the error. -.Sh ERRORS -.Fn zip_set_file_extra -fails if: -.Bl -tag -width Er -.It Bq Er ZIP_ER_INVAL -.Ar index -is not a valid file index in -.Ar archive , -or -.Ar len -is less than 0 or longer than the maximum extra field length in a zip file -(65535). -.It Bq Er ZIP_ER_MEMORY -Required memory could not be allocated. -.El -.Sh SEE ALSO -.Xr libzip 3 , -.Xr zip_get_file_extra 3 -.Sh AUTHORS -.An -nosplit -.An Dieter Baron Aq dillo@giga.or.at -and -.An Thomas Klausner Aq tk@giga.or.at
diff --git a/regress/add_from_zip.test b/regress/add_from_zip.test index 0a20c2e..de89508 100644 --- a/regress/add_from_zip.test +++ b/regress/add_from_zip.test
@@ -3,4 +3,4 @@ return 0 args teststored.zip testfile.zip abac-repeat.txt file teststored.zip teststored.zip teststored.zip -file-new testfile.zip teststored.zip +file-new testfile.zip testdeflated.zip
diff --git a/regress/fopen_unchanged.c b/regress/fopen_unchanged.c index 2df665f..5b30e2b 100644 --- a/regress/fopen_unchanged.c +++ b/regress/fopen_unchanged.c
@@ -42,7 +42,6 @@ const char *teststr="This is a test.\n"; const char *file="teststring.txt"; -const char *prg; int main(int argc, char *argv[]) @@ -53,10 +52,8 @@ char buf[100]; int err; - prg = argv[0]; - if (argc != 2) { - fprintf(stderr, "usage: %s archive\n", prg); + fprintf(stderr, "usage: %s archive\n", argv[0]); return 1; } @@ -64,34 +61,28 @@ if ((za=zip_open(archive, ZIP_CREATE, &err)) == NULL) { zip_error_to_str(buf, sizeof(buf), err, errno); - fprintf(stderr, "%s: can't open zip archive `%s': %s\n", prg, - archive, buf); + fprintf(stderr, "can't open zip archive `%s': %s\n", archive, buf); return 1; } if ((zs=zip_source_buffer(za, teststr, strlen(teststr), 0)) == NULL) { - fprintf(stderr, "%s: can't create zip_source from buffer: %s\n", prg, - zip_strerror(za)); + fprintf(stderr, "can't create zip_source from buffer: %s\n", zip_strerror(za)); exit(1); } if (zip_add(za, file, zs) == -1) { zip_source_free(zs); - fprintf(stderr, "%s: can't add file `%s': %s\n", prg, - file, zip_strerror(za)); + fprintf(stderr, "can't add file `%s': %s\n", file, zip_strerror(za)); return 1; } if (zip_fopen(za, file, ZIP_FL_UNCHANGED) == NULL) { - /* expected error, don't pollute with prg */ - fprintf(stderr, "can't zip_fopen file `%s': %s\n", - file, zip_strerror(za)); + fprintf(stderr, "can't zip_fopen file `%s': %s\n", file, zip_strerror(za)); return 1; } if (zip_close(za) == -1) { - fprintf(stderr, "%s: can't close zip archive `%s': %s\n", prg, - archive, zip_strerror(za)); + fprintf(stderr, "can't close zip archive `%s': %s\n", archive, zip_strerror(za)); return 1; }
diff --git a/regress/get_comment.c b/regress/get_comment.c index 2446f5a..9d27de0 100644 --- a/regress/get_comment.c +++ b/regress/get_comment.c
@@ -1,6 +1,6 @@ /* comment.c -- test cases for file and archive comments - Copyright (C) 2006 Dieter Baron and Thomas Klausner + Copyright (C) 2006-2012 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> @@ -75,6 +75,8 @@ for (i=0; i<zip_get_num_files(za); i++) { if ((com=zip_get_file_comment(za, i, &len, 0)) == NULL) + printf("Error getting comment for `%s': %s\n", zip_get_name(za, i, 0), zip_strerror(za)); + else if (len == 0) printf("No comment for `%s'\n", zip_get_name(za, i, 0)); else printf("File comment for `%s': %.*s\n", zip_get_name(za, i, 0), len, com);
diff --git a/regress/name_locate.c b/regress/name_locate.c index eb997c5..03d3daa 100644 --- a/regress/name_locate.c +++ b/regress/name_locate.c
@@ -105,20 +105,21 @@ { int ze, se; char expected[80]; + int idx; - if (zip_name_locate(z, name, flags) < 0) { + if ((idx=zip_name_locate(z, name, flags)) < 0) { zip_error_get(z, &ze, &se); if (ze != zerr) { zip_error_to_str(expected, sizeof(expected), zerr, 0); - printf("%s: unexpected error while looking for `%s': " - "got `%s', expected `%s'\n", prg, name, - zip_strerror(z), expected); + printf("unexpected error while looking for `%s' with flags %x: got `%s', expected `%s'\n", + name, flags, zip_strerror(z), expected); return 1; } return 0; } + printf("unexpected success while looking for `%s' with flags %x: index %d\n", name, flags, idx); return 1; } @@ -129,8 +130,8 @@ { if (zip_name_locate(z, name, flags) < 0) { - printf("%s: unexpected error while looking for `%s': %s\n", - prg, name, zip_strerror(z)); + printf("unexpected error while looking for `%s' with flags %x: %s\n", + name, flags, zip_strerror(z)); return 1; }
diff --git a/regress/open_cons_extrabytes.test b/regress/open_cons_extrabytes.test index 8fdf2cc..e154541 100644 --- a/regress/open_cons_extrabytes.test +++ b/regress/open_cons_extrabytes.test
@@ -1,6 +1,6 @@ # zip_open: file has extra bytes at end of archive program tryopen -file testextrabytes.zip testextrabytes.zip testextrabytes.zip -args -c testextrabytes.zip +file testextrabytes.zzip testextrabytes.zip testextrabytes.zip +args -c testextrabytes.zzip return 1 -stdout opening `testextrabytes.zip' returned error 21 +stdout opening `testextrabytes.zzip' returned error 21
diff --git a/regress/open_extrabytes.test b/regress/open_extrabytes.test index e647373..80227ab 100644 --- a/regress/open_extrabytes.test +++ b/regress/open_extrabytes.test
@@ -1,6 +1,6 @@ # zip_open: file has extra bytes at end of archive program tryopen -file testextrabytes.zip testextrabytes.zip testextrabytes.zip -args testextrabytes.zip +file testextrabytes.zzip testextrabytes.zip testextrabytes.zip +args testextrabytes.zzip return 0 -stdout opening `testextrabytes.zip' succeeded, 1 entries +stdout opening `testextrabytes.zzip' succeeded, 1 entries
diff --git a/regress/runtest b/regress/runtest index 2d397e2..50e6cb7 100755 --- a/regress/runtest +++ b/regress/runtest
@@ -3,7 +3,7 @@ # from ckmame:runtest,v 1.22 2005/12/27 09:41:51 dillo Exp # # runtest -- run regression tests -# Copyright (C) 2002-2007 Dieter Baron and Thomas Klausner +# Copyright (C) 2002-2012 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> @@ -171,8 +171,7 @@ checkzip() { check_in_out_exists "$1" "$2" - # quiet CRC errors - ${ZIPCMP} -t ${ZIPCMP_FLAGS} "$1" "$2" 2>/dev/null + ${ZIPCMP} ${ZIPCMP_FLAGS} "$1" "$2" 2>/dev/null if [ $? -ne 0 ] then fail "$3" @@ -243,6 +242,7 @@ DIFF_FLAGS='-u' ZIPCMP_FLAGS='-v' fi +ZIPCMP_FLAGS="$ZIPCMP_FLAGS -p -t" # XXX: set up trap to cleanup
diff --git a/regress/stat_index.c b/regress/stat_index.c index 51db2d2..4f323c1 100644 --- a/regress/stat_index.c +++ b/regress/stat_index.c
@@ -34,7 +34,10 @@ #include <errno.h> +#include <stdlib.h> + #include <time.h> + #ifndef HAVE_GETOPT #include "getopt.h" #endif @@ -54,7 +57,6 @@ char buf[100]; struct zip *z; int c, flags, ze; - zip_uint64_t count; struct zip_stat sb; int index; @@ -120,11 +122,11 @@ if (sb.valid & ZIP_STAT_CRC) printf("crc: `%0x'\n", sb.crc); if (sb.valid & ZIP_STAT_COMP_METHOD) - printf("compression method: `%lld'\n", sb.comp_method); + printf("compression method: `%d'\n", sb.comp_method); if (sb.valid & ZIP_STAT_ENCRYPTION_METHOD) - printf("encryption method: `%lld'\n", sb.encryption_method); + printf("encryption method: `%d'\n", sb.encryption_method); if (sb.valid & ZIP_STAT_FLAGS) - printf("flags: `%lld'\n", sb.flags); + printf("flags: `%ld'\n", (long)sb.flags); printf("\n"); }
diff --git a/regress/test2.zip b/regress/test2.zip index ff5e351..89c90d0 100644 --- a/regress/test2.zip +++ b/regress/test2.zip Binary files differ
diff --git a/regress/testdeflated.zip b/regress/testdeflated.zip index c9ee5d2..7f6ab1c 100644 --- a/regress/testdeflated.zip +++ b/regress/testdeflated.zip Binary files differ
diff --git a/regress/testdir.zip b/regress/testdir.zip index 7e6e7b9..b1e13e1 100644 --- a/regress/testdir.zip +++ b/regress/testdir.zip Binary files differ
diff --git a/regress/testfile-UTF8.zip b/regress/testfile-UTF8.zip index abb3409..7279615 100644 --- a/regress/testfile-UTF8.zip +++ b/regress/testfile-UTF8.zip Binary files differ
diff --git a/regress/testfile.zip b/regress/testfile.zip index ad6afb3..2fa5ba0 100644 --- a/regress/testfile.zip +++ b/regress/testfile.zip Binary files differ
diff --git a/regress/teststored.zip b/regress/teststored.zip index 91cb1e6..138c6ad 100644 --- a/regress/teststored.zip +++ b/regress/teststored.zip Binary files differ
diff --git a/src/zipcmp.c b/src/zipcmp.c index 6e1d5d2..5b1d8ea 100644 --- a/src/zipcmp.c +++ b/src/zipcmp.c
@@ -51,10 +51,22 @@ #include "zip.h" #include "zipint.h" +struct ef { + const char *name; + zip_uint16_t flags; + zip_uint16_t id; + zip_uint16_t size; + const zip_uint8_t *data; +}; + struct entry { char *name; - unsigned int size; - unsigned int crc; + zip_uint64_t size; + zip_uint32_t crc; + zip_uint32_t comp_method; + zip_uint64_t comp_size; + struct ef *extra_fields; + int n_extra_fields; }; @@ -63,7 +75,7 @@ #define PROGRAM "zipmerge" -char *usage = "usage: %s [-hiqtVv] zip1 zip2\n"; +char *usage = "usage: %s [-hipqtVv] zip1 zip2\n"; char help_head[] = PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n"; @@ -72,6 +84,7 @@ -h display this help message\n\ -V display version number\n\ -i compare names ignoring case distinctions\n\ + -p compare as many details as possible\n\ -q be quiet\n\ -t test zip files\n\ -v be verbose (print differences, default)\n\ @@ -82,33 +95,40 @@ Copyright (C) 2012 Dieter Baron and Thomas Klausner\n\ " PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n"; -#define OPTIONS "hViqtv" +#define OPTIONS "hVipqtv" +static int ef_read(struct zip *za, int idx, struct entry *e); +static int ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2); +static int ef_order(const void *a, const void *b); +static void ef_print(const void *p); static int entry_cmp(const void *p1, const void *p2); +static int entry_paranoia_checks(char *const name[2], const void *p1, const void *p2); static void entry_print(const void *p); -static int compare_list(char * const name[], int verbose, - const void *l[], const int n[], int size, - int (*cmp)(const void *, const void *), - void print(const void *)); -static int compare_zip(char * const zn[], int verbose); +static int compare_list(char * const name[], + const void *l[], const int n[], int size, + int (*cmp)(const void *, const void *), + int (*checks)(char *const name[2], const void *, const void *), + void (*print)(const void *)); +static int compare_zip(char * const zn[]); static int test_file(struct zip *za, int idx, off_t size, unsigned int crc); -int ignore_case, test_files; +int ignore_case, test_files, paranoid, verbose; +int header_done; int main(int argc, char * const argv[]) { - int verbose; int c; prg = argv[0]; ignore_case = 0; test_files = 0; + paranoid = 0; verbose = 1; while ((c=getopt(argc, argv, OPTIONS)) != -1) { @@ -116,6 +136,9 @@ case 'i': ignore_case = 1; break; + case 'p': + paranoid = 1; + break; case 'q': verbose = 0; break; @@ -146,13 +169,13 @@ exit(2); } - exit((compare_zip(argv+optind, verbose) == 0) ? 0 : 1); + exit((compare_zip(argv+optind) == 0) ? 0 : 1); } static int -compare_zip(char * const zn[], int verbose) +compare_zip(char * const zn[]) { struct zip *za; struct zip_stat st; @@ -163,7 +186,7 @@ char errstr[1024]; for (i=0; i<2; i++) { - if ((za=zip_open(zn[i], 0, &err)) == NULL) { + if ((za=zip_open(zn[i], paranoid ? ZIP_CHECKCONS : 0, &err)) == NULL) { zip_error_to_str(errstr, sizeof(errstr), err, errno); fprintf(stderr, "%s: cannot open zip archive `%s': %s\n", prg, zn[i], errstr); @@ -187,6 +210,16 @@ e[i][j].crc = st.crc; if (test_files) test_file(za, j, st.size, st.crc); + if (paranoid) { + e[i][j].comp_method = st.comp_method; + e[i][j].comp_size = st.comp_size; + ef_read(za, j, e[i]+j); + } + else { + e[i][j].comp_method = 0; + e[i][j].comp_size = 0; + e[i][j].n_extra_fields = 0; + } } qsort(e[i], n[i], sizeof(e[i][0]), entry_cmp); } @@ -195,9 +228,8 @@ } - switch (compare_list(zn, verbose, - (void *)e, n, sizeof(e[i][0]), - entry_cmp, entry_print)) { + switch (compare_list(zn, (void *)e, n, sizeof(e[i][0]), + entry_cmp, paranoid ? entry_paranoia_checks : NULL, entry_print)) { case 0: exit(0); @@ -214,31 +246,38 @@ static int -compare_list(char * const name[2], int verbose, +compare_list(char * const name[2], const void *l[2], const int n[2], int size, int (*cmp)(const void *, const void *), - void print(const void *)) + int (*check)(char *const name[2], const void *, const void *), + void (*print)(const void *)) { int i[2], j, c; int diff; #define INC(k) (i[k]++, l[k]=((const char *)l[k])+size) -#define PRINT(k) do { \ - if (diff==0 && verbose) \ +#define PRINT(k) do { \ + if (header_done==0 && verbose) { \ printf("--- %s\n+++ %s\n", name[0], name[1]); \ - if (verbose) { \ - printf("%c ", (k)?'+':'-'); \ - print(l[k]); \ - } \ - diff = 1; \ + header_done = 1; \ + } \ + if (verbose) { \ + printf("%c ", (k)?'+':'-'); \ + print(l[k]); \ + } \ + diff = 1; \ } while (0) + header_done = 0; + i[0] = i[1] = 0; diff = 0; while (i[0]<n[0] && i[1]<n[1]) { c = cmp(l[0], l[1]); if (c == 0) { + if (check) + diff |= check(name, l[0], l[1]); INC(0); INC(1); } @@ -265,6 +304,90 @@ static int +ef_read(struct zip *za, int idx, struct entry *e) +{ + int n_local, n_central; + int i; + zip_uint16_t len; + + n_local = zip_get_file_num_extra_fields(za, idx, ZIP_FL_LOCAL); + n_central = zip_get_file_num_extra_fields(za, idx, ZIP_FL_CENTRAL); + e->n_extra_fields = n_local + n_central; + + if ((e->extra_fields=malloc(sizeof(e->extra_fields[0])*e->n_extra_fields)) == NULL) + return -1; + + for (i=0; i<n_local; i++) { + e->extra_fields[i].name = e->name; + if ((e->extra_fields[i].data=zip_get_file_extra_field(za, idx, ZIP_FL_LOCAL, i, &e->extra_fields[i].id, &e->extra_fields[i].size)) == NULL) + return -1; + e->extra_fields[i].flags = ZIP_FL_LOCAL; + } + for (; i<e->n_extra_fields; i++) { + e->extra_fields[i].name = e->name; + if ((e->extra_fields[i].data=zip_get_file_extra_field(za, idx, ZIP_FL_CENTRAL, i-n_local, &e->extra_fields[i].id, &e->extra_fields[i].size)) == NULL) + return -1; + e->extra_fields[i].flags = ZIP_FL_CENTRAL; + } + + qsort(e->extra_fields, e->n_extra_fields, sizeof(e->extra_fields[0]), ef_order); + + return 0; +} + + + +static int +ef_compare(char *const name[2], const struct entry *e1, const struct entry *e2) +{ + struct ef *ef[2]; + int n[2]; + + ef[0] = e1->extra_fields; + ef[1] = e2->extra_fields; + n[0] = e1->n_extra_fields; + n[1] = e2->n_extra_fields; + + return compare_list(name, (void *)ef, n, sizeof(struct ef), ef_order, NULL, ef_print); +} + + + + +static int +ef_order(const void *ap, const void *bp) { + const struct ef *a, *b; + + a = ap; + b = bp; + + if (a->flags != b->flags) + return a->flags - b->flags; + if (a->id != b->id) + return a->id - b->id; + if (a->size != b->size) + return a->size - b->size; + return memcmp(a->data, b->data, a->size); +} + + + +static void +ef_print(const void *p) +{ + const struct ef *ef = p; + int i; + + printf(" %s ", ef->name); + printf("%04x %c <", ef->id, ef->flags == ZIP_FL_LOCAL ? 'l' : 'c', ef->data); + for (i=0; i<ef->size; i++) + printf("%s%02x", i ? " " : "", ef->data[i]); + printf(">\n"); +} + + + +static int entry_cmp(const void *p1, const void *p2) { const struct entry *e1, *e2; @@ -285,6 +408,36 @@ +static int +entry_paranoia_checks(char *const name[2], const void *p1, const void *p2) { + const struct entry *e1, *e2; + + e1 = p1; + e2 = p2; + + if (ef_compare(name, e1, e2) != 0) + return 1; + + if (e1->comp_method != e2->comp_method || e1->comp_size != e2->comp_size) { + if (verbose) { + if (header_done==0) { + printf("--- %s\n+++ %s\n", name[0], name[1]); + header_done = 1; + } + printf("--- %s ", e1->name); + printf("method %d size %lu\n", e1->comp_method, (long unsigned)e1->comp_size); + printf("+++ %s ", e1->name); + printf("method %d size %lu\n", e2->comp_method, (long unsigned)e2->comp_size); + } + return 1; + } + + return 0; +} + + + + static void entry_print(const void *p) { @@ -292,7 +445,8 @@ e = p; - printf("%10u %08x %s\n", e->size, e->crc, e->name); + /* XXX PRId64 */ + printf("%10lu %08x %s\n", (unsigned long)e->size, e->crc, e->name); }