Fix extra field modification functions (clone extra fields before modifying). Check return value of _zip_dirent_clone().
diff --git a/lib/zip_extra_field.c b/lib/zip_extra_field.c index 5ce002a..d4bc77f 100644 --- a/lib/zip_extra_field.c +++ b/lib/zip_extra_field.c
@@ -42,6 +42,31 @@ struct zip_extra_field * +_zip_ef_clone(struct zip_extra_field *ef, struct zip_error *error) +{ + struct zip_extra_field *head, *prev, *def; + + head = prev = NULL; + + while (ef) { + if ((def=_zip_ef_new(ef->id, ef->size, ef->data, ef->flags)) == NULL) { + _zip_error_set(error, ZIP_ER_MEMORY, 0); + _zip_ef_free(head); + return NULL; + } + + if (head == NULL) + head = def; + if (prev) + prev->next = def; + prev = def; + } + + return head; +} + + +struct zip_extra_field * _zip_ef_delete_by_id(struct zip_extra_field *ef, zip_uint16_t id, zip_uint16_t id_idx, zip_flags_t flags) { struct zip_extra_field *head, *prev; @@ -314,6 +339,7 @@ } free(ef_raw); + /* XXX: remove fields handled internally (Zip64, UTF-8) */ e->orig->extra_fields = _zip_ef_merge(e->orig->extra_fields, ef); }
diff --git a/lib/zip_extra_field_api.c b/lib/zip_extra_field_api.c index f0ca76c..0458c70 100644 --- a/lib/zip_extra_field_api.c +++ b/lib/zip_extra_field_api.c
@@ -42,9 +42,19 @@ { struct zip_dirent *de; - if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + if (_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 (_zip_file_extra_field_prepare_for_change(za, idx) < 0) + return -1; + + de = za->entry[idx].changes; + de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ZIP_EXTRA_FIELD_ALL, ef_idx, flags); return 0; } @@ -56,9 +66,19 @@ { struct zip_dirent *de; - if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + if (_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 (_zip_file_extra_field_prepare_for_change(za, idx) < 0) + return -1; + + de = za->entry[idx].changes; + de->extra_fields = _zip_ef_delete_by_id(de->extra_fields, ef_id, ef_idx, flags); return 0; } @@ -192,14 +212,24 @@ struct zip_extra_field *ef, *ef_prev, *ef_new; int i, found; - if ((de=_zip_get_dirent(za, idx, flags, &za->error)) == NULL) + if (_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 (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 (_zip_file_extra_field_prepare_for_change(za, idx) < 0) + return -1; + + de = za->entry[idx].changes; + if (flags & ZIP_EF_LOCAL) ls = _zip_ef_size(de->extra_fields, ZIP_EF_LOCAL); else @@ -258,3 +288,38 @@ return 0; } + + + +int +_zip_file_extra_field_prepare_for_change(struct zip *za, zip_uint64_t idx) +{ + struct zip_entry *e; + + if (idx >= za->nentry) { + _zip_error_set(&za->error, ZIP_ER_INVAL, 0); + return -1; + } + + e = za->entry+idx; + + if (e->changes && (e->changes->changed & ZIP_DIRENT_EXTRA_FIELD)) + return 0; + + if (_zip_read_local_ef(za, idx) < 0) + return -1; + + if (e->changes == NULL) { + if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + + if ((e->changes->extra_fields=_zip_ef_clone(e->changes->extra_fields, &za->error)) == 0) + return -1; + e->changes->changed |= ZIP_DIRENT_EXTRA_FIELD; + + return 0; +} +
diff --git a/lib/zip_file_replace.c b/lib/zip_file_replace.c index a73a261..cc1b72a 100644 --- a/lib/zip_file_replace.c +++ b/lib/zip_file_replace.c
@@ -93,11 +93,15 @@ _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); + if (za->entry[idx].changes == NULL) { + if ((za->entry[idx].changes=_zip_dirent_clone(za->entry[idx].orig)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } - za->entry[idx].changes->comp_method = ZIP_CM_REPLACED_DEFAULT; - za->entry[idx].changes->changed |= ZIP_DIRENT_COMP_METHOD; + za->entry[idx].changes->comp_method = ZIP_CM_REPLACED_DEFAULT; + za->entry[idx].changes->changed |= ZIP_DIRENT_COMP_METHOD; } za->entry[idx].source = source;
diff --git a/lib/zip_file_set_comment.c b/lib/zip_file_set_comment.c index 16955ac..143d03a 100644 --- a/lib/zip_file_set_comment.c +++ b/lib/zip_file_set_comment.c
@@ -85,10 +85,14 @@ 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; + if (e->changes == NULL) { + if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + e->changes->comment = cstr; + e->changes->changed |= ZIP_DIRENT_COMMENT; } else { _zip_string_free(cstr);
diff --git a/lib/zip_set_file_compression.c b/lib/zip_set_file_compression.c index bbcaa65..e62cf45 100644 --- a/lib/zip_set_file_compression.c +++ b/lib/zip_set_file_compression.c
@@ -70,11 +70,15 @@ } } else { - if (e->changes == NULL) - e->changes = _zip_dirent_clone(e->orig); + if (e->changes == NULL) { + if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } - e->changes->comp_method = method; - e->changes->changed |= ZIP_DIRENT_COMP_METHOD; + e->changes->comp_method = method; + e->changes->changed |= ZIP_DIRENT_COMP_METHOD; + } } return 0;
diff --git a/lib/zip_set_name.c b/lib/zip_set_name.c index 6a91cd7..dc62c74 100644 --- a/lib/zip_set_name.c +++ b/lib/zip_set_name.c
@@ -95,10 +95,14 @@ 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; + if (e->changes == NULL) { + if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { + _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); + return -1; + } + } + e->changes->filename = str; + e->changes->changed |= ZIP_DIRENT_FILENAME; } else { _zip_string_free(str);
diff --git a/lib/zipint.h b/lib/zipint.h index 7d5235f..84d377e 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -393,6 +393,7 @@ void _zip_dirent_torrent_normalize(struct zip_dirent *); int _zip_dirent_write(struct zip_dirent *, FILE *, zip_flags_t, struct zip_error *); +struct zip_extra_field *_zip_ef_clone(struct zip_extra_field *, struct zip_error *); struct zip_extra_field *_zip_ef_delete_by_id(struct zip_extra_field *, zip_uint16_t, zip_uint16_t, zip_flags_t); 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_flags_t, struct zip_error *); @@ -416,6 +417,7 @@ const zip_uint8_t *_zip_extract_extra_field_by_id(struct zip_error *, zip_uint16_t, int, const zip_uint8_t *, zip_uint16_t, zip_uint16_t *); +int _zip_file_extra_field_prepare_for_change(struct zip *, zip_uint64_t); int _zip_file_fillbuf(void *, size_t, struct zip_file *); zip_uint64_t _zip_file_get_offset(struct zip *, zip_uint64_t, struct zip_error *);