static int write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) { off_t offset; uLong crc; char buf[TORRENT_CRC_LEN+1]; if (_zip_cdir_write(cd, out, &za->error) < 0) return -1; 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) return -1; #ifndef _WIN32 snprintf(buf, sizeof(buf), "%08lX", (long)crc); #else _snprintf(buf, sizeof(buf), "%08lX", (long)crc); #endif if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { _zip_error_set(&za->error, ZIP_ER_WRITE, errno); return -1; } return 0; }
static int write_cdir(struct zip *za, const struct zip_filelist *filelist, zip_uint64_t survivors, FILE *out) { off_t cd_start, end; zip_int64_t size; uLong crc; char buf[TORRENT_CRC_LEN+1]; 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 */ if (_zip_filerange_crc(out, cd_start, size, &crc, &za->error) < 0) return -1; snprintf(buf, sizeof(buf), "%08lX", (long)crc); if (fseeko(out, end-TORRENT_CRC_LEN, SEEK_SET) < 0) { _zip_error_set(&za->error, ZIP_ER_SEEK, errno); return -1; } if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) { _zip_error_set(&za->error, ZIP_ER_WRITE, errno); return -1; } 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; }