ZIP_EXTERN int zip_file_rename(struct zip *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { const char *old_name; int old_is_dir, new_is_dir; if (idx >= za->nentry || (name != NULL && strlen(name) > ZIP_UINT16_MAX)) { _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 ((old_name=zip_get_name(za, idx, 0)) == NULL) return -1; new_is_dir = (name != NULL && name[strlen(name)-1] == '/'); old_is_dir = (old_name[strlen(old_name)-1] == '/'); if (new_is_dir != old_is_dir) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } return _zip_set_name(za, idx, name, flags); }
zip_set_archive_comment(struct zip *za, const char *comment, int len) { char *tmpcom; if (len < 0 || len > MAXCOMLEN || (len > 0 && comment == 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 ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL) return -1; } else tmpcom = NULL; free(za->ch_comment); za->ch_comment = tmpcom; za->ch_comment_len = len; return 0; }
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) { struct zip_dirent *de; if ((flags & ZIP_EF_BOTH) == 0) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (((flags & ZIP_EF_BOTH) == ZIP_EF_BOTH) && (ef_idx != ZIP_EXTRA_FIELD_ALL)) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } 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; }
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; }
ZIP_EXTERN int zip_set_archive_flag(struct zip *za, unsigned int flag, int value) { unsigned int new_flags; if (value) new_flags = za->ch_flags | flag; else new_flags = za->ch_flags & ~flag; if (new_flags == za->ch_flags) return 0; if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if ((flag & ZIP_AFL_RDONLY) && value && (za->ch_flags & ZIP_AFL_RDONLY) == 0) { if (_zip_changed(za, NULL)) { _zip_error_set(&za->error, ZIP_ER_CHANGED, 0); return -1; } } za->ch_flags = new_flags; return 0; }
zip_int64_t _zip_replace(struct zip *za, zip_uint64_t idx, const char *name, struct zip_source *source) { zip_uint64_t za_nentry_prev; if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } za_nentry_prev = za->nentry; if (idx == ZIP_UINT64_MAX) { if (_zip_entry_new(za) == NULL) return -1; idx = za->nentry - 1; za->entry[idx].changes.valid |= ZIP_DIRENT_COMP_METHOD; za->entry[idx].changes.comp_method = ZIP_CM_DEFLATE; /* XXX: default */ } if (name && _zip_set_name(za, idx, name) != 0) { za->nentry = za_nentry_prev; return -1; } /* does not change any name related data, so we can do it here; * needed for a double add of the same file name */ _zip_unchange_data(za->entry+idx); za->entry[idx].state = ((za->cdir == NULL || idx >= (zip_uint64_t)za->cdir->nentry) ? ZIP_ST_ADDED : ZIP_ST_REPLACED); za->entry[idx].source = source; return idx; }
zip_int64_t _zip_file_replace(struct zip *za, zip_uint64_t idx, const char *name, struct zip_source *source, zip_flags_t flags) { zip_uint64_t za_nentry_prev; if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } za_nentry_prev = za->nentry; if (idx == ZIP_UINT64_MAX) { zip_int64_t i = -1; if (flags & ZIP_FL_OVERWRITE) i = _zip_name_locate(za, name, flags, NULL); if (i == -1) { /* create and use new entry, used by zip_add */ if ((i=_zip_add_entry(za)) < 0) return -1; } idx = (zip_uint64_t)i; } if (name && _zip_set_name(za, idx, name, flags) != 0) { if (za->nentry != za_nentry_prev) { _zip_entry_finalize(za->entry+idx); za->nentry = za_nentry_prev; } return -1; } /* does not change any name related data, so we can do it here; * 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) { 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].source = source; return (zip_int64_t)idx; }
ZIP_EXTERN int zip_set_file_compression(struct zip *za, zip_uint64_t idx, zip_int32_t method, zip_uint32_t flags) { struct zip_entry *e; zip_int32_t old_method; if (idx >= za->nentry) { _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 (method != ZIP_CM_DEFAULT && method != ZIP_CM_STORE && method != ZIP_CM_DEFLATE) { _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); return -1; } e = za->entry+idx; //zip_int32_t old_method = (e->orig == NULL ? ZIP_CM_DEFAULT : e->orig->comp_method); old_method = (e->orig == NULL ? ZIP_CM_DEFAULT : e->orig->comp_method); /* XXX: revisit this when flags are supported, since they may require a recompression */ if (method == old_method) { 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) { 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; } return 0; }
ZIP_EXTERN zip_int64_t zip_dir_add(struct zip *za, const char *name, zip_flags_t flags) { size_t len; zip_int64_t idx; char *s; struct zip_source *source; if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (name == NULL) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } s = NULL; len = strlen(name); if (name[len-1] != '/') { if ((s=(char *)malloc(len+2)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } strcpy(s, name); s[len] = '/'; s[len+1] = '\0'; } if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) { free(s); return -1; } idx = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags); free(s); if (idx < 0) zip_source_free(source); else { if (zip_file_set_external_attributes(za, (zip_uint64_t)idx, 0, ZIP_OPSYS_DEFAULT, ZIP_EXT_ATTRIB_DEFAULT_DIR) < 0) { zip_delete(za, (zip_uint64_t)idx); return -1; } } return idx; }
int zip_file_set_external_attributes(struct zip *za, zip_uint64_t idx, zip_flags_t flags, zip_uint8_t opsys, zip_uint32_t attributes) { struct zip_entry *e; int changed; zip_uint8_t unchanged_opsys; zip_uint32_t unchanged_attributes; 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; } e = za->entry+idx; unchanged_opsys = e->orig ? e->orig->version_madeby>>8 : ZIP_OPSYS_DEFAULT; unchanged_attributes = e->orig ? e->orig->ext_attrib : ZIP_EXT_ATTRIB_DEFAULT; changed = (opsys != unchanged_opsys || attributes != unchanged_attributes); if (changed) { 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->version_madeby = (opsys << 8) | (e->changes->version_madeby & 0xff); e->changes->ext_attrib = attributes; e->changes->changed |= ZIP_DIRENT_ATTRIBUTES; } else if (e->changes) { e->changes->changed &= ~ZIP_DIRENT_ATTRIBUTES; if (e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } else { e->changes->version_madeby = (unchanged_opsys << 8) | (e->changes->version_madeby & 0xff); e->changes->ext_attrib = unchanged_attributes; } } return 0; }
ZIP_EXTERN zip_int64_t zip_dir_add(struct zip *za, const char *name, zip_flags_t flags) { size_t len; zip_int64_t ret; char *s; struct zip_source *source; if (ZIP_IS_RDONLY(za)) { _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); return -1; } if (name == NULL) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } s = NULL; len = strlen(name); if (name[len-1] != '/') { if ((s=(char *)malloc(len+2)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); return -1; } strcpy(s, name); s[len] = '/'; s[len+1] = '\0'; } if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) { free(s); return -1; } ret = _zip_file_replace(za, ZIP_UINT64_MAX, s ? s : name, source, flags); free(s); if (ret < 0) zip_source_free(source); return ret; }
ZIP_EXTERN int zip_set_archive_comment(struct zip *za, const char *comment, zip_uint16_t len) { 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)) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (len > 0) { if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, ZIP_FL_ENC_GUESS, &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 cstr = NULL; _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; }
zip_delete(struct zip *za, zip_uint64_t idx) { if (idx >= za->nentry) { _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; } /* allow duplicate file names, because the file will * be removed directly afterwards */ if (_zip_unchange(za, idx, 1) != 0) return -1; za->entry[idx].state = ZIP_ST_DELETED; return 0; }
ZIP_EXTERN int zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags) { zip_entry_t *e; int changed; 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; } e = za->entry+idx; changed = e->orig == NULL || mtime != e->orig->last_mod; if (changed) { 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->last_mod = mtime; e->changes->changed |= ZIP_DIRENT_LAST_MOD; } else { if (e->changes) { e->changes->changed &= ~ZIP_DIRENT_LAST_MOD; if (e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } } } return 0; }
int _zip_set_name(zip_t *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { zip_entry_t *e; zip_string_t *str; bool same_as_orig; zip_int64_t i; const zip_uint8_t *old_name, *new_name; zip_string_t *old_str; if (idx >= za->nentry) { 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 (name && name[0] != '\0') { /* TODO: check for string too long */ if ((str=_zip_string_new((const zip_uint8_t *)name, (zip_uint16_t)strlen(name), flags, &za->error)) == NULL) return -1; if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(str, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) str->encoding = ZIP_ENCODING_UTF8_KNOWN; } else str = NULL; /* TODO: encoding flags needed for CP437? */ if ((i=_zip_name_locate(za, name, 0, NULL)) >= 0 && (zip_uint64_t)i != idx) { _zip_string_free(str); zip_error_set(&za->error, ZIP_ER_EXISTS, 0); return -1; } /* no effective name change */ if (i>=0 && (zip_uint64_t)i == idx) { _zip_string_free(str); return 0; } e = za->entry+idx; if (e->orig) same_as_orig = _zip_string_equal(e->orig->filename, str); else same_as_orig = false; if (!same_as_orig && e->changes == NULL) { if ((e->changes=_zip_dirent_clone(e->orig)) == NULL) { zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_string_free(str); return -1; } } if ((new_name = _zip_string_get(same_as_orig ? e->orig->filename : str, NULL, 0, &za->error)) == NULL) { _zip_string_free(str); return -1; } if (e->changes) { old_str = e->changes->filename; } else if (e->orig) { old_str = e->orig->filename; } else { old_str = NULL; } if (old_str) { if ((old_name = _zip_string_get(old_str, NULL, 0, &za->error)) == NULL) { _zip_string_free(str); return -1; } } else { old_name = NULL; } if (_zip_hash_add(za->names, new_name, idx, 0, &za->error) == false) { _zip_string_free(str); return -1; } if (old_name) { _zip_hash_delete(za->names, old_name, NULL); } if (same_as_orig) { if (e->changes) { if (e->changes->changed & ZIP_DIRENT_FILENAME) { _zip_string_free(e->changes->filename); e->changes->changed &= ~ZIP_DIRENT_FILENAME; if (e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } else { /* TODO: what if not cloned? can that happen? */ e->changes->filename = e->orig->filename; } } } _zip_string_free(str); } else { if (e->changes->changed & ZIP_DIRENT_FILENAME) { _zip_string_free(e->changes->filename); } e->changes->changed |= ZIP_DIRENT_FILENAME; e->changes->filename = str; } return 0; }
ZIP_EXTERN int zip_file_set_comment(struct zip *za, zip_uint64_t idx, const char *comment, zip_uint16_t len, zip_flags_t flags) { struct zip_entry *e; struct zip_string *cstr; struct zip_dirent *de; int changed; 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 (len > 0 && comment == NULL) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } if (len > 0) { if ((cstr=_zip_string_new((const zip_uint8_t *)comment, len, flags, &za->error)) == NULL) return -1; if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(cstr, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) cstr->encoding = ZIP_ENCODING_UTF8_KNOWN; } else cstr = NULL; e = za->entry+idx; 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) { 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); if (e->changes && e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } } return 0; }
int _zip_set_name(struct zip *za, zip_uint64_t idx, const char *name, zip_flags_t flags) { struct zip_entry *e; struct zip_string *str; int changed; zip_int64_t i; if (idx >= za->nentry) { _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 (name && strlen(name) > 0) { /* XXX: check for string too long */ if ((str=_zip_string_new((const zip_uint8_t *)name, (zip_uint16_t)strlen(name), flags, &za->error)) == NULL) return -1; if ((flags & ZIP_FL_ENCODING_ALL) == ZIP_FL_ENC_GUESS && _zip_guess_encoding(str, ZIP_ENCODING_UNKNOWN) == ZIP_ENCODING_UTF8_GUESSED) str->encoding = ZIP_ENCODING_UTF8_KNOWN; } else str = NULL; /* XXX: encoding flags needed for CP437? */ if ((i=_zip_name_locate(za, name, 0, NULL)) >= 0 && (zip_uint64_t)i != idx) { _zip_string_free(str); _zip_error_set(&za->error, ZIP_ER_EXISTS, 0); return -1; } /* no effective name change */ if (i>=0 && (zip_uint64_t)i == idx) { _zip_string_free(str); return 0; } 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) changed = !_zip_string_equal(e->orig->filename, str); else changed = 1; if (changed) { 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); if (e->changes && e->changes->changed == 0) { _zip_dirent_free(e->changes); e->changes = NULL; } } return 0; }
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) { struct zip_dirent *de; zip_uint16_t ls, cs; struct zip_extra_field *ef, *ef_prev, *ef_new; int i, found, new_len; if ((flags & ZIP_EF_BOTH) == 0) { _zip_error_set(&za->error, ZIP_ER_INVAL, 0); return -1; } 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_EF_IS_INTERNAL(ef_id)) { _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; ef = de->extra_fields; ef_prev = NULL; i = 0; found = 0; for (; ef; ef=ef->next) { if (ef->id == ef_id && (ef->flags & 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 (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; new_len = ls > cs ? ls : cs; if (found) new_len -= ef->size + 4; new_len += len + 4; if (new_len > ZIP_UINT16_MAX) { _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) { if ((ef->flags & ZIP_EF_BOTH) == (flags & ZIP_EF_BOTH)) { 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 { ef->flags &= ~(flags & ZIP_EF_BOTH); ef_new->next = ef->next; ef->next = ef_new; } } else if (ef_prev) { ef_new->next = ef_prev->next; ef_prev->next = ef_new; } else de->extra_fields = ef_new; return 0; }