struct zip * _zip_open(const char *fn, FILE *fp, int flags, int aflags, int *zep) { struct zip *za; struct zip_cdir *cdir; int i; off_t len; if (fseeko(fp, 0, SEEK_END) < 0) { *zep = ZIP_ER_SEEK; return NULL; } len = ftello(fp); /* treat empty files as empty archives */ if (len == 0) { if ((za=_zip_allocate_new(fn, zep)) == NULL) fclose(fp); else za->zp = fp; return za; } cdir = _zip_find_central_dir(fp, flags, zep, len); if (cdir == NULL) { fclose(fp); return NULL; } if ((za=_zip_allocate_new(fn, zep)) == NULL) { _zip_cdir_free(cdir); fclose(fp); return NULL; } za->cdir = cdir; za->zp = fp; if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) * cdir->nentry)) == NULL) { set_error(zep, NULL, ZIP_ER_MEMORY); _zip_free(za); return NULL; } for (i=0; i<cdir->nentry; i++) _zip_entry_new(za); _zip_check_torrentzip(za); za->ch_flags = za->flags; return za; }
static struct zip * _zip_allocate_new(const char *fn, int *zep) { struct zip *za; struct zip_error error; if ((za=_zip_new(&error)) == NULL) { set_error(zep, &error, 0); return NULL; } za->zn = strdup(fn); if (!za->zn) { _zip_free(za); set_error(zep, NULL, ZIP_ER_MEMORY); return NULL; } return za; }
ZIP_EXTERN struct zip * zip_open(const char *fn, int flags, int *zep) { FILE *fp; struct zip *za; struct zip_cdir *cdir; int i; off_t len; switch (_zip_file_exists(fn, flags, zep)) { case -1: return NULL; case 0: return _zip_allocate_new(fn, zep); default: break; } if ((fp=fopen(fn, "rb")) == NULL) { set_error(zep, NULL, ZIP_ER_OPEN); return NULL; } fseeko(fp, 0, SEEK_END); len = ftello(fp); /* treat empty files as empty archives */ if (len == 0) { if ((za=_zip_allocate_new(fn, zep)) == NULL) fclose(fp); else za->zp = fp; return za; } cdir = _zip_find_central_dir(fp, flags, zep, len); if (cdir == NULL) { fclose(fp); return NULL; } if ((za=_zip_allocate_new(fn, zep)) == NULL) { _zip_cdir_free(cdir); fclose(fp); return NULL; } za->cdir = cdir; za->zp = fp; if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) * cdir->nentry)) == NULL) { set_error(zep, NULL, ZIP_ER_MEMORY); _zip_free(za); return NULL; } for (i=0; i<cdir->nentry; i++) _zip_entry_new(za); _zip_check_torrentzip(za); za->ch_flags = za->flags; return za; }
ZIP_EXTERN int zip_close(struct zip *za) { int survivors; int i, j, error; char *temp; FILE *out; mode_t mask; struct zip_cdir *cd; struct zip_dirent de; struct filelist *filelist; int reopen_on_error; int new_torrentzip; reopen_on_error = 0; if (za == NULL) return -1; if (!_zip_changed(za, &survivors)) { _zip_free(za); return 0; } /* don't create zip files with no entries */ if (survivors == 0) { if (za->zn && za->zp) { if (remove(za->zn) != 0) { _zip_error_set(&za->error, ZIP_ER_REMOVE, errno); return -1; } } _zip_free(za); return 0; } if ((filelist=(struct 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 = (char*)_zip_memdup((void*)(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); free(filelist); return -1; } } if ((temp=_zip_create_temp_output(za, &out)) == NULL) { _zip_cdir_free(cd); free(filelist); return -1; } /* 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) continue; filelist[j].idx = i; filelist[j].name = zip_get_name(za, i, 0); j++; } survivors = j; if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) qsort(filelist, survivors, sizeof(filelist[0]), _zip_torrentzip_cmp); new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1 && zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0); error = 0; for (j=0; j<survivors; j++) { i = filelist[j].idx; /* create new local directory entry */ if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { _zip_dirent_init(&de); if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) _zip_dirent_torrent_normalize(&de); /* use it as central directory entry */ memcpy(cd->entry+j, &de, sizeof(cd->entry[j])); /* set/update file name */ if (za->entry[i].ch_filename == NULL) { if (za->entry[i].state == ZIP_ST_ADDED) { de.filename = strdup("-"); de.filename_len = 1; cd->entry[j].filename = "-"; cd->entry[j].filename_len = 1; } else { de.filename = strdup(za->cdir->entry[i].filename); de.filename_len = strlen(de.filename); cd->entry[j].filename = za->cdir->entry[i].filename; cd->entry[j].filename_len = de.filename_len; } } } 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; } } if (za->entry[i].ch_filename) { free(de.filename); if ((de.filename=strdup(za->entry[i].ch_filename)) == NULL) { error = 1; break; } de.filename_len = strlen(de.filename); cd->entry[j].filename = za->entry[i].ch_filename; cd->entry[j].filename_len = de.filename_len; } if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 && za->entry[i].ch_comment_len != -1) { /* as the rest of cd entries, its malloc/free is done by za */ cd->entry[j].comment = za->entry[i].ch_comment; cd->entry[j].comment_len = za->entry[i].ch_comment_len; } cd->entry[j].offset = (unsigned int)ftello(out); if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { struct zip_source *zs; zs = NULL; if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) == NULL) { error = 1; break; } } if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { error = 1; break; } cd->entry[j].last_mod = de.last_mod; cd->entry[j].comp_method = de.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) { 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) { error = 1; break; } } _zip_dirent_finalize(&de); } 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); return -1; } if (fclose(out) != 0) { _zip_error_set(&za->error, ZIP_ER_CLOSE, errno); remove(temp); free(temp); return -1; } if (za->zp) { fclose(za->zp); za->zp = NULL; reopen_on_error = 1; } if (_zip_rename(temp, za->zn) != 0) { _zip_error_set(&za->error, ZIP_ER_RENAME, errno); remove(temp); free(temp); if (reopen_on_error) { /* ignore errors, since we're already in an error case */ za->zp = fopen(za->zn, "rb"); } return -1; } #ifndef _MSC_VER mask = umask(0); umask(mask); chmod(za->zn, 0666&~mask); #endif _zip_free(za); free(temp); return 0; }
int zip_close(struct zip *za) { int changed, survivors; int i, j, tfd, error; char *temp; FILE *tfp; mode_t mask; struct zip_cdir *cd; struct zip_dirent de; changed = survivors = 0; for (i=0; i<za->nentry; i++) { if (za->entry[i].state != ZIP_ST_UNCHANGED) changed = 1; if (za->entry[i].state != ZIP_ST_DELETED) survivors++; } if (!changed) { _zip_free(za); return 0; } /* don't create zip files with no entries */ if (survivors == 0) { if (za->zn) { if (remove(za->zn) != 0) { _zip_error_set(&za->error, ZIP_ER_REMOVE, errno); return -1; } } _zip_free(za); return 0; } if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL) return -1; if ((temp=malloc(strlen(za->zn)+8)) == NULL) { _zip_error_set(&za->error, ZIP_ER_MEMORY, 0); _zip_cdir_free(cd); return -1; } sprintf(temp, "%s.XXXXXX", za->zn); if ((tfd=mkstemp(temp)) == -1) { _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); _zip_cdir_free(cd); free(temp); return -1; } if ((tfp=fdopen(tfd, "r+b")) == NULL) { _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno); _zip_cdir_free(cd); close(tfd); remove(temp); free(temp); return -1; } error = 0; for (i=j=0; i<za->nentry; i++) { if (za->entry[i].state == ZIP_ST_DELETED) continue; if (ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { _zip_dirent_init(&de); memcpy(cd->entry+j, &de, sizeof(cd->entry[i])); if (za->entry[i].ch_filename == NULL) { if (za->entry[i].state == ZIP_ST_REPLACED) { de.filename = strdup(za->cdir->entry[i].filename); de.filename_len = strlen(de.filename); cd->entry[j].filename = za->cdir->entry[i].filename; cd->entry[j].filename_len = de.filename_len; } else { de.filename = strdup("-"); de.filename_len = 1; cd->entry[j].filename = "-"; cd->entry[j].filename_len = de.filename_len; } } } else { if (fseek(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, 0, 1, &za->error) != 0) { error = 1; break; } memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[i])); } if (za->entry[i].ch_filename) { free(de.filename); de.filename = strdup(za->entry[i].ch_filename); de.filename_len = strlen(de.filename); cd->entry[j].filename = za->entry[i].ch_filename; cd->entry[j].filename_len = de.filename_len; } cd->entry[j].offset = ftell(tfp); if (ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { if (add_data(za, i, &de, tfp) < 0) { error = -1; break; } cd->entry[j].last_mod = de.last_mod; cd->entry[j].comp_method = de.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, tfp, 1, &za->error) < 0) { error = 1; break; } /* we just read the local dirent, file is at correct position */ if (copy_data(za->zp, de.comp_size, tfp, &za->error) < 0) { error = 1; break; } } j++; _zip_dirent_finalize(&de); } if (!error) { if (_zip_cdir_write(cd, tfp, &za->error) < 0) error = 1; } /* pointers in cd are owned by za */ cd->nentry = 0; _zip_cdir_free(cd); if (error) { _zip_dirent_finalize(&de); fclose(tfp); remove(temp); free(temp); return -1; } if (fclose(tfp) != 0) { _zip_error_set(&za->error, ZIP_ER_CLOSE, errno); remove(temp); free(temp); return -1; } if (rename(temp, za->zn) != 0) { _zip_error_set(&za->error, ZIP_ER_RENAME, errno); remove(temp); free(temp); return -1; } if (za->zp) { fclose(za->zp); za->zp = NULL; } mask = umask(0); umask(mask); chmod(za->zn, 0666&~mask); _zip_free(za); return 0; }
ZIP_EXTERN struct zip * zip_open(const char *fn, int flags, int *zep) { FILE *fp; struct zip *za; struct zip_cdir *cdir; int i; off_t len; switch (_zip_file_exists(fn, flags, zep)) { case -1: return NULL; case 0: return _zip_allocate_new(fn, zep); default: break; } if ((fp=fopen(fn, "rb")) == NULL) { set_error(zep, NULL, ZIP_ER_OPEN); return NULL; } __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "FILE OPENED"); fseeko(fp, 0, SEEK_END); len = ftello(fp); /* treat empty files as empty archives */ if (len == 0) { if ((za=_zip_allocate_new(fn, zep)) == NULL) fclose(fp); else za->zp = fp; return za; } __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "SCANNING"); cdir = _zip_find_central_dir(fp, flags, zep, len); if (cdir == NULL) { fclose(fp); return NULL; } __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "DIR FOUND"); if ((za=_zip_allocate_new(fn, zep)) == NULL) { _zip_cdir_free(cdir); fclose(fp); return NULL; } za->cdir = cdir; za->zp = fp; __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "ALLOCING ENTRIES"); if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry)) * cdir->nentry)) == NULL) { set_error(zep, NULL, ZIP_ER_MEMORY); _zip_free(za); return NULL; } za->nentry_alloc = cdir->nentry; __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "FILLING ENTRIES"); for (i=0; i<cdir->nentry; i++) _zip_entry_new2(za); __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "CHECK TORRENTZIP"); _zip_check_torrentzip(za); za->ch_flags = za->flags; __android_log_print(ANDROID_LOG_VERBOSE, "ZIP", "DONE"); return za; }