Clean up misc. todos.
- Implement missing extra field functions
- add flag for zip_file_add that overwrites any existing entry with same name
- set "version needed"/"version made by" correctly (zip64)
- zip_replace: set compression method to default unless user-set
- reset compression specific bits in bitflags when (re)compressing
- rename zip_get_{compression,encryption}_implementation to _zip_*
diff --git a/TODO b/TODO
index db730d8..9af4980 100644
--- a/TODO
+++ b/TODO
@@ -9,7 +9,6 @@
API Issues
==========
-! clean up first version of extra field support
* compression/crypt implementations: how to set error code on failure
* compression/crypt error messages a la ZIP_ER_ZLIB (no detailed info passing)
* check arguments for every entry point into libzip
@@ -17,7 +16,6 @@
Features
========
-! Implement missing extra field functions
! Document extra field functions
! Document API changes
. _set_name allows NULL (document)
@@ -26,9 +24,10 @@
. document ZIP_DISABLE_DEPRECATED (libzip man page)
. renames of zip_add, zip_rename, zip_replace, zip_add_dir, zip_{set,get}_file_comment
. NULL is now allowed for file names (zip_add, zip_add_dir, zip_rename)
-! add flag for zip_file_add that overwrites any existing entry with same name
+! document ZIP_FL_OVERWRITE (flag for zip_file_add that overwrites any existing entry with same name)
* do not compress if storing is smaller
+! test extra fields api
* I/O methods
* support streaming output (creating new archive to e.g. stdout)
* add functions to:
@@ -55,10 +54,7 @@
Bugs
====
-! set "version needed"/"version made by" correctly (zip64)
! check inconsistent file test case result
-! zip_replace: set compression method to default unless user-set
-! reset compression specific bits in bitflags when (re)compressing
* split zip archive torrentzip state from user requested torrentzip state
* check for limits imposed by format (central dir size, file size, extra fields, ...)
* _zip_u2d_time: handle localtime(3) failure
@@ -72,7 +68,6 @@
Cleanup
=======
-! rename zip_get_{compression,encryption}_implementation to _zip_*
* get rid of zip_get_{compression,encryption}_implementation
* use zip_*int*_t internally
* completely get rid of off_t
diff --git a/lib/zip.h b/lib/zip.h
index c04c9ed..cf3edb2 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -80,6 +80,7 @@
/* 1024 reserved for internal use */
#define ZIP_FL_ENC_UTF_8 2048 /* string is UTF-8 encoded */
#define ZIP_FL_ENC_CP437 4096 /* string is CP437 encoded */
+#define ZIP_FL_OVERWRITE 8192 /* zip_file_add: if file with name exists, overwrite (replace) it */
/* archive global flags flags */
diff --git a/lib/zip_close.c b/lib/zip_close.c
index 1ac9153..098a9c2 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -282,7 +282,7 @@
st.comp_method = ZIP_CM_STORE;
}
- if (de->comp_method == ZIP_CM_DEFAULT && st.comp_method != ZIP_CM_STORE)
+ if (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != ZIP_CM_STORE)
de->comp_method = st.comp_method;
else if (de->comp_method == ZIP_CM_STORE && (st.valid & ZIP_STAT_SIZE)) {
st.valid |= ZIP_STAT_COMP_SIZE;
@@ -302,8 +302,8 @@
de->uncomp_size = st.size;
if ((st.valid & ZIP_STAT_COMP_SIZE) == 0) {
- if ((((de->comp_method == ZIP_CM_DEFLATE || de->comp_method == ZIP_CM_DEFAULT) && st.size > MAX_DEFLATE_SIZE_32)
- || de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && de->comp_method != ZIP_CM_DEFAULT))
+ if ((((de->comp_method == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(de->comp_method)) && st.size > MAX_DEFLATE_SIZE_32)
+ || de->comp_method != ZIP_CM_STORE && de->comp_method != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(de->comp_method)))
flags |= ZIP_FL_FORCE_ZIP64;
}
else
@@ -317,12 +317,12 @@
return -1;
- if (st.comp_method == ZIP_CM_STORE || (de->comp_method != ZIP_CM_DEFAULT && st.comp_method != de->comp_method)) {
+ if (st.comp_method == ZIP_CM_STORE || (ZIP_CM_IS_DEFAULT(de->comp_method) && st.comp_method != de->comp_method)) {
struct zip_source *s_store, *s_crc;
zip_compression_implementation comp_impl;
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 -1;
}
@@ -342,7 +342,7 @@
/* XXX: deflate 0-byte files for torrentzip? */
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) {
+ 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)
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index 77cf4a3..2457c96 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -249,7 +249,7 @@
de->changed = 0;
de->local_extra_fields_read = 0;
- de->version_madeby = 0;
+ de->version_madeby = 20;
de->version_needed = 20; /* 2.0 */
de->bitflags = 0;
de->comp_method = ZIP_CM_DEFAULT;
@@ -627,6 +627,7 @@
struct zip_extra_field *ef;
zip_uint8_t ef_zip64[24], *ef_zip64_p;
int is_zip64;
+ int is_really_zip64;
ef = NULL;
@@ -684,10 +685,15 @@
is_zip64 = 1;
}
+ if ((flags & (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64)) == (ZIP_FL_LOCAL|ZIP_FL_FORCE_ZIP64))
+ is_really_zip64 = _zip_dirent_needs_zip64(de, flags);
+ else
+ is_really_zip64 = is_zip64;
+
if ((flags & ZIP_FL_LOCAL) == 0)
- _zip_write2(de->version_madeby, fp);
- _zip_write2(de->version_needed, fp); /* XXX: at least 4.5 if zip64 */
- _zip_write2(de->bitflags, fp);
+ _zip_write2(is_really_zip64 ? 45 : de->version_madeby, fp);
+ _zip_write2(is_really_zip64 ? 45 : de->version_needed, fp);
+ _zip_write2(de->bitflags&0xfff9, fp); /* clear compression method specific flags */
_zip_write2(de->comp_method, fp);
_zip_u2d_time(de->last_mod, &dostime, &dosdate);
diff --git a/lib/zip_extra_field_api.c b/lib/zip_extra_field_api.c
index 1c45dd9..bbb0f75 100644
--- a/lib/zip_extra_field_api.c
+++ b/lib/zip_extra_field_api.c
@@ -40,8 +40,13 @@
ZIP_EXTERN int
zip_file_extra_field_delete(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_idx, zip_flags_t flags)
{
- /* XXX */
- return -1;
+ struct zip_dirent *de;
+
+ if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
+ return -1;
+
+ de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags);
+ return 0;
}
@@ -49,8 +54,13 @@
ZIP_EXTERN int
zip_file_extra_field_delete_by_id(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, zip_flags_t flags)
{
- /* XXX */
- return -1;
+ struct zip_dirent *de;
+
+ if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
+ return -1;
+
+ de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags);
+ return 0;
}
@@ -177,9 +187,73 @@
ZIP_EXTERN int
zip_file_extra_field_set(struct zip *za, zip_uint64_t idx, zip_uint16_t ef_id, zip_uint16_t ef_idx, const zip_uint8_t *data, zip_uint16_t len, zip_flags_t flags)
{
- /* XXX: ZIP_ER_INVAL if ef_id == ZIP_EF_ZIP64 */
- /* XXX: size of ef + new <= ZIP_UINT16_MAX */
+ struct zip_dirent *de;
+ zip_uint16_t ls, cs;
+ struct zip_extra_field *ef, *ef_prev, *ef_new;
+ int i, found;
- /* XXX */
- return -1;
+ if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL)
+ return -1;
+
+ if (ef_id == ZIP_EF_ZIP64 || ef_id == ZIP_EF_UTF_8_NAME || ef_id == ZIP_EF_UTF_8_COMMENT) {
+ _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+ return -1;
+ }
+
+ if (flags & ZIP_EF_LOCAL)
+ ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL);
+ else
+ ls = 0;
+ if (flags & ZIP_EF_CENTRAL)
+ cs = _zip_ef_size(de->extra_fields, ZIP_EF_CENTRAL);
+ else
+ cs = 0;
+
+ if (((zip_uint32_t)(ls > cs ? ls : cs)) + len + 4 > ZIP_UINT16_MAX) {
+ _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+ return -1;
+ }
+
+ ef = de->extra_fields;
+ ef_prev = NULL;
+ found = 0;
+
+ for (; ef; ef=ef->next) {
+ if (ef->id == ef_id && (ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) {
+ if (i == ef_idx) {
+ found = 1;
+ break;
+ }
+ i++;
+ }
+ ef_prev = ef;
+ }
+
+ if (i < ef_idx && ef_idx != ZIP_EXTRA_FIELD_NEW) {
+ _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+ return -1;
+ }
+
+ if ((ef_new=_zip_ef_new(ef_id, len, data, flags)) == NULL) {
+ _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+ return -1;
+ }
+
+ if (found) {
+ ef_new->next = ef->next;
+ ef->next = NULL;
+ _zip_ef_free(ef);
+ if (ef_prev)
+ ef_prev->next = ef_new;
+ else
+ de->extra_fields = ef_new;
+ }
+ else if (ef) {
+ ef_new->next = ef->next;
+ ef->next = ef_new;
+ }
+ else
+ de->extra_fields = ef_new;
+
+ return 0;
}
diff --git a/lib/zip_file_replace.c b/lib/zip_file_replace.c
index 14da8ad..b23a646 100644
--- a/lib/zip_file_replace.c
+++ b/lib/zip_file_replace.c
@@ -67,11 +67,16 @@
za_nentry_prev = za->nentry;
if (idx == ZIP_UINT64_MAX) {
- zip_int64_t i;
+ zip_int64_t i = -1;
- /* create and use new entry, used by zip_add */
- if ((i=_zip_add_entry(za)) < 0)
- return -1;
+ if (flags & ZIP_FL_OVERWRITE)
+ i = zip_name_locate(za, name, flags);
+
+ if (i == -1) {
+ /* create and use new entry, used by zip_add */
+ if ((i=_zip_add_entry(za)) < 0)
+ return -1;
+ }
idx = i;
}
@@ -87,6 +92,14 @@
* needed for a double add of the same file name */
_zip_unchange_data(za->entry+idx);
+ if (za->entry[idx].orig != NULL && (za->entry[idx].changes == NULL || (za->entry[idx].changes->changed & ZIP_DIRENT_COMP_METHOD) == 0)) {
+ if (za->entry[idx].changes == NULL)
+ za->entry[idx].changes = _zip_dirent_clone(za->entry[idx].orig);
+
+ za->entry[idx].changes->comp_method = ZIP_CM_REPLACED_DEFAULT;
+ za->entry[idx].changes->changed |= ZIP_DIRENT_COMP_METHOD;
+ }
+
za->entry[idx].source = source;
return idx;
diff --git a/lib/zip_get_compression_implementation.c b/lib/zip_get_compression_implementation.c
index 82128f3..aa4a160 100644
--- a/lib/zip_get_compression_implementation.c
+++ b/lib/zip_get_compression_implementation.c
@@ -37,10 +37,10 @@
-ZIP_EXTERN zip_compression_implementation
-zip_get_compression_implementation(zip_int32_t cm)
+zip_compression_implementation
+_zip_get_compression_implementation(zip_int32_t cm)
{
- if (cm == ZIP_CM_DEFLATE || cm == ZIP_CM_DEFAULT)
+ if (cm == ZIP_CM_DEFLATE || ZIP_CM_IS_DEFAULT(cm))
return zip_source_deflate;
return NULL;
}
diff --git a/lib/zip_get_encryption_implementation.c b/lib/zip_get_encryption_implementation.c
index d83698c..7dcb992 100644
--- a/lib/zip_get_encryption_implementation.c
+++ b/lib/zip_get_encryption_implementation.c
@@ -37,8 +37,8 @@
-ZIP_EXTERN zip_encryption_implementation
-zip_get_encryption_implementation(zip_uint16_t em)
+zip_encryption_implementation
+_zip_get_encryption_implementation(zip_uint16_t em)
{
if (em == ZIP_EM_TRAD_PKWARE)
return zip_source_pkware;
diff --git a/lib/zip_set_file_compression.c b/lib/zip_set_file_compression.c
index 51a74a2..bbcaa65 100644
--- a/lib/zip_set_file_compression.c
+++ b/lib/zip_set_file_compression.c
@@ -60,20 +60,22 @@
e = za->entry+idx;
- if (method != (e->orig ? e->orig->comp_method : ZIP_CM_DEFAULT)) {
+ if (method == ZIP_CM_DEFAULT && e->orig == NULL) {
+ if (e->changes) {
+ e->changes->changed &= ~ZIP_DIRENT_COMP_METHOD;
+ if (e->changes->changed == 0) {
+ _zip_dirent_free(e->changes);
+ e->changes = NULL;
+ }
+ }
+ }
+ else {
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_source_deflate.c b/lib/zip_source_deflate.c
index e651400..5c26740 100644
--- a/lib/zip_source_deflate.c
+++ b/lib/zip_source_deflate.c
@@ -67,7 +67,7 @@
struct deflate *ctx;
struct zip_source *s2;
- if (src == NULL || (cm != ZIP_CM_DEFLATE && cm != ZIP_CM_DEFAULT)) {
+ if (src == NULL || (cm != ZIP_CM_DEFLATE && !ZIP_CM_IS_DEFAULT(cm))) {
_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
return NULL;
}
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c
index d3aa339..44e41ab 100644
--- a/lib/zip_source_zip_new.c
+++ b/lib/zip_source_zip_new.c
@@ -91,7 +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;
}
@@ -100,7 +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;
}
diff --git a/lib/zip_unchange_data.c b/lib/zip_unchange_data.c
index 105ea3a..fa25feb 100644
--- a/lib/zip_unchange_data.c
+++ b/lib/zip_unchange_data.c
@@ -43,6 +43,14 @@
ze->source = NULL;
}
+ if (ze->changes != NULL && (ze->changes->changed & ZIP_DIRENT_COMP_METHOD) && ze->changes->comp_method == ZIP_CM_REPLACED_DEFAULT) {
+ ze->changes->changed &= ~ZIP_DIRENT_COMP_METHOD;
+ if (ze->changes->changed == 0) {
+ _zip_dirent_free(ze->changes);
+ ze->changes = NULL;
+ }
+ }
+
ze->deleted = 0;
}
diff --git a/lib/zipint.h b/lib/zipint.h
index 44c5baf..d7737af 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -118,6 +118,10 @@
#define CDBUFSIZE (MAXCOMLEN+EOCDLEN+EOCD64LOCLEN)
#define BUFSIZE 8192
+#define ZIP_CM_REPLACED_DEFAULT (-2)
+
+#define ZIP_CM_IS_DEFAULT(x) ((x) == ZIP_CM_DEFAULT || (x) == ZIP_CM_REPLACED_DEFAULT)
+
#define ZIP_EF_UTF_8_COMMENT 0x6375
#define ZIP_EF_UTF_8_NAME 0x7075
#define ZIP_EF_ZIP64 0x0001
@@ -135,8 +139,8 @@
zip_uint16_t, int,
const char *);
-zip_compression_implementation zip_get_compression_implementation(zip_int32_t);
-zip_encryption_implementation zip_get_encryption_implementation(zip_uint16_t);
+zip_compression_implementation _zip_get_compression_implementation(zip_int32_t);
+zip_encryption_implementation _zip_get_encryption_implementation(zip_uint16_t);