version 1.1.1.1, 2012/02/21 23:48:05
|
version 1.1.1.2, 2013/07/22 01:32:11
|
Line 1
|
Line 1
|
/* |
/* |
zip_close.c -- close zip archive and update changes |
zip_close.c -- close zip archive and update changes |
Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner | Copyright (C) 1999-2011 Dieter Baron and Thomas Klausner |
|
|
This file is part of libzip, a library to manipulate ZIP archives. |
This file is part of libzip, a library to manipulate ZIP archives. |
The authors can be contacted at <libzip@nih.at> |
The authors can be contacted at <libzip@nih.at> |
Line 33
|
Line 33
|
|
|
|
|
|
|
|
#include "zipint.h" |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <errno.h> |
#include <errno.h> |
|
#ifdef HAVE_UNISTD_H |
|
#include <unistd.h> |
|
#endif |
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
|
#ifdef PHP_WIN32 |
|
#include <io.h> |
|
#include <fcntl.h> |
|
#endif |
|
|
#include "zipint.h" |
|
|
|
static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, |
static int add_data(struct zip *, struct zip_source *, struct zip_dirent *, |
FILE *); |
FILE *); |
static int add_data_comp(zip_source_callback, void *, struct zip_stat *, |
|
FILE *, struct zip_error *); |
|
static int add_data_uncomp(struct zip *, zip_source_callback, void *, |
|
struct zip_stat *, FILE *); |
|
static void ch_set_error(struct zip_error *, zip_source_callback, void *); |
|
static int copy_data(FILE *, off_t, FILE *, struct zip_error *); |
static int copy_data(FILE *, off_t, FILE *, struct zip_error *); |
|
static int copy_source(struct zip *, struct zip_source *, FILE *); |
static int write_cdir(struct zip *, struct zip_cdir *, FILE *); |
static int write_cdir(struct zip *, struct zip_cdir *, FILE *); |
static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); |
static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *); |
static int _zip_changed(struct zip *, int *); |
|
static char *_zip_create_temp_output(struct zip *, FILE **); |
static char *_zip_create_temp_output(struct zip *, FILE **); |
static int _zip_torrentzip_cmp(const void *, const void *); |
static int _zip_torrentzip_cmp(const void *, const void *); |
|
|
Line 72 zip_close(struct zip *za)
|
Line 74 zip_close(struct zip *za)
|
int i, j, error; |
int i, j, error; |
char *temp; |
char *temp; |
FILE *out; |
FILE *out; |
|
#ifndef PHP_WIN32 |
mode_t mask; |
mode_t mask; |
|
#endif |
struct zip_cdir *cd; |
struct zip_cdir *cd; |
struct zip_dirent de; |
struct zip_dirent de; |
struct filelist *filelist; |
struct filelist *filelist; |
Line 99 zip_close(struct zip *za)
|
Line 103 zip_close(struct zip *za)
|
} |
} |
_zip_free(za); |
_zip_free(za); |
return 0; |
return 0; |
} | } |
|
|
if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) |
if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors)) |
== NULL) |
== NULL) |
Line 126 zip_close(struct zip *za)
|
Line 130 zip_close(struct zip *za)
|
cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; |
cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN; |
} |
} |
else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { |
else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) { |
if (_zip_cdir_set_comment(cd, za) == -1) { | if (_zip_cdir_set_comment(cd, za) == -1) { |
_zip_cdir_free(cd); | _zip_cdir_free(cd); |
free(filelist); |
free(filelist); |
return -1; | return -1; |
| } |
} |
} |
} |
|
|
|
if ((temp=_zip_create_temp_output(za, &out)) == NULL) { |
if ((temp=_zip_create_temp_output(za, &out)) == NULL) { |
_zip_cdir_free(cd); |
_zip_cdir_free(cd); |
Line 160 zip_close(struct zip *za)
|
Line 164 zip_close(struct zip *za)
|
for (j=0; j<survivors; j++) { |
for (j=0; j<survivors; j++) { |
i = filelist[j].idx; |
i = filelist[j].idx; |
|
|
|
_zip_dirent_init(&de); |
|
|
/* create new local directory entry */ |
/* create new local directory entry */ |
if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { |
if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) { |
_zip_dirent_init(&de); |
|
|
|
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) |
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) |
_zip_dirent_torrent_normalize(&de); |
_zip_dirent_torrent_normalize(&de); |
Line 188 zip_close(struct zip *za)
|
Line 193 zip_close(struct zip *za)
|
} |
} |
else { |
else { |
/* copy existing directory entries */ |
/* copy existing directory entries */ |
if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) { | if ((NULL == za->zp) || (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0)) { |
_zip_error_set(&za->error, ZIP_ER_SEEK, errno); |
_zip_error_set(&za->error, ZIP_ER_SEEK, errno); |
error = 1; |
error = 1; |
break; |
break; |
Line 198 zip_close(struct zip *za)
|
Line 203 zip_close(struct zip *za)
|
error = 1; |
error = 1; |
break; |
break; |
} |
} |
memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); | memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j])); |
| |
if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { |
if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) { |
de.crc = za->cdir->entry[i].crc; |
de.crc = za->cdir->entry[i].crc; |
de.comp_size = za->cdir->entry[i].comp_size; |
de.comp_size = za->cdir->entry[i].comp_size; |
Line 220 zip_close(struct zip *za)
|
Line 224 zip_close(struct zip *za)
|
cd->entry[j].filename_len = de.filename_len; |
cd->entry[j].filename_len = de.filename_len; |
} |
} |
|
|
|
if (za->entry[i].ch_extra_len != -1) { |
|
free(de.extrafield); |
|
if ((de.extrafield=malloc(za->entry[i].ch_extra_len)) == NULL) { |
|
error = 1; |
|
break; |
|
} |
|
memcpy(de.extrafield, za->entry[i].ch_extra, za->entry[i].ch_extra_len); |
|
de.extrafield_len = za->entry[i].ch_extra_len; |
|
/* as the rest of cd entries, its malloc/free is done by za */ |
|
/* TODO unsure if this should also be set in the CD -- |
|
* not done for now |
|
cd->entry[j].extrafield = za->entry[i].ch_extra; |
|
cd->entry[j].extrafield_len = za->entry[i].ch_extra_len; |
|
*/ |
|
} |
|
|
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 |
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0 |
&& za->entry[i].ch_comment_len != -1) { |
&& za->entry[i].ch_comment_len != -1) { |
/* as the rest of cd entries, its malloc/free is done by za */ |
/* as the rest of cd entries, its malloc/free is done by za */ |
Line 234 zip_close(struct zip *za)
|
Line 254 zip_close(struct zip *za)
|
|
|
zs = NULL; |
zs = NULL; |
if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { |
if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) { |
if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) == NULL) { | if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1)) |
error = 1; | == NULL) { |
break; | error = 1; |
} | break; |
| } |
} |
} |
|
|
if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { |
if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) { |
error = 1; |
error = 1; |
|
if (zs) |
|
zip_source_free(zs); |
break; |
break; |
} |
} |
|
if (zs) |
|
zip_source_free(zs); |
|
|
cd->entry[j].last_mod = de.last_mod; |
cd->entry[j].last_mod = de.last_mod; |
cd->entry[j].comp_method = de.comp_method; |
cd->entry[j].comp_method = de.comp_method; |
cd->entry[j].comp_size = de.comp_size; |
cd->entry[j].comp_size = de.comp_size; |
Line 291 zip_close(struct zip *za)
|
Line 317 zip_close(struct zip *za)
|
free(temp); |
free(temp); |
return -1; |
return -1; |
} |
} |
| |
if (za->zp) { | if (za->zp) { |
fclose(za->zp); | fclose(za->zp); |
za->zp = NULL; | za->zp = NULL; |
reopen_on_error = 1; | reopen_on_error = 1; |
} |
} |
if (_zip_rename(temp, za->zn) != 0) { |
if (_zip_rename(temp, za->zn) != 0) { |
_zip_error_set(&za->error, ZIP_ER_RENAME, errno); | _zip_error_set(&za->error, ZIP_ER_RENAME, errno); |
remove(temp); | remove(temp); |
free(temp); | free(temp); |
if (reopen_on_error) { | if (reopen_on_error) { |
/* ignore errors, since we're already in an error case */ | /* ignore errors, since we're already in an error case */ |
za->zp = fopen(za->zn, "rb"); | za->zp = fopen(za->zn, "rb"); |
} | |
return -1; | |
} |
} |
|
return -1; |
|
} |
|
#ifndef PHP_WIN32 |
mask = umask(0); |
mask = umask(0); |
umask(mask); |
umask(mask); |
chmod(za->zn, 0666&~mask); |
chmod(za->zn, 0666&~mask); |
if (za->ch_comment) | #endif |
free(za->ch_comment); | |
|
|
_zip_free(za); |
_zip_free(za); |
free(temp); |
free(temp); |
Line 322 zip_close(struct zip *za)
|
Line 348 zip_close(struct zip *za)
|
|
|
|
|
static int |
static int |
add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft) | add_data(struct zip *za, struct zip_source *src, struct zip_dirent *de, |
| FILE *ft) |
{ |
{ |
off_t offstart, offend; | off_t offstart, offdata, offend; |
zip_source_callback cb; | |
void *ud; | |
struct zip_stat st; |
struct zip_stat st; |
| struct zip_source *s2; |
cb = zs->f; | zip_compression_implementation comp_impl; |
ud = zs->ud; | int ret; |
| |
if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) { | if (zip_source_stat(src, &st) < 0) { |
ch_set_error(&za->error, cb, ud); | _zip_error_set_from_source(&za->error, src); |
return -1; |
return -1; |
} |
} |
|
|
if (cb(ud, NULL, 0, ZIP_SOURCE_OPEN) < 0) { |
|
ch_set_error(&za->error, cb, ud); |
|
return -1; |
|
} |
|
|
|
offstart = ftello(ft); |
offstart = ftello(ft); |
|
|
if (_zip_dirent_write(de, ft, 1, &za->error) < 0) |
if (_zip_dirent_write(de, ft, 1, &za->error) < 0) |
return -1; |
return -1; |
|
|
if (st.comp_method != ZIP_CM_STORE) { | if ((s2=zip_source_crc(za, src, 0)) == NULL) { |
if (add_data_comp(cb, ud, &st, ft, &za->error) < 0) | zip_source_pop(s2); |
return -1; | return -1; |
} |
} |
else { | |
if (add_data_uncomp(za, cb, ud, &st, ft) < 0) | /* XXX: deflate 0-byte files for torrentzip? */ |
| if (((st.valid & ZIP_STAT_COMP_METHOD) == 0 |
| || st.comp_method == ZIP_CM_STORE) |
| && ((st.valid & ZIP_STAT_SIZE) == 0 || st.size != 0)) { |
| comp_impl = NULL; |
| if ((comp_impl=zip_get_compression_implementation(ZIP_CM_DEFLATE)) |
| == NULL) { |
| _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0); |
| zip_source_pop(s2); |
return -1; |
return -1; |
|
} |
|
if ((s2=comp_impl(za, s2, ZIP_CM_DEFLATE, ZIP_CODEC_ENCODE)) |
|
== NULL) { |
|
/* XXX: set error? */ |
|
zip_source_pop(s2); |
|
return -1; |
|
} |
} |
} |
|
else |
|
s2 = src; |
|
|
if (cb(ud, NULL, 0, ZIP_SOURCE_CLOSE) < 0) { | offdata = ftello(ft); |
ch_set_error(&za->error, cb, ud); | |
return -1; | ret = copy_source(za, s2, ft); |
| |
| if (zip_source_stat(s2, &st) < 0) |
| ret = -1; |
| |
| while (s2 != src) { |
| if ((s2=zip_source_pop(s2)) == NULL) { |
| /* XXX: set erorr */ |
| ret = -1; |
| break; |
| } |
} |
} |
|
|
|
if (ret < 0) |
|
return -1; |
|
|
offend = ftello(ft); |
offend = ftello(ft); |
|
|
if (fseeko(ft, offstart, SEEK_SET) < 0) { |
if (fseeko(ft, offstart, SEEK_SET) < 0) { |
Line 368 add_data(struct zip *za, struct zip_source *zs, struct
|
Line 418 add_data(struct zip *za, struct zip_source *zs, struct
|
return -1; |
return -1; |
} |
} |
|
|
|
|
de->last_mod = st.mtime; |
de->last_mod = st.mtime; |
de->comp_method = st.comp_method; |
de->comp_method = st.comp_method; |
de->crc = st.crc; |
de->crc = st.crc; |
de->uncomp_size = st.size; |
de->uncomp_size = st.size; |
de->comp_size = st.comp_size; | de->comp_size = offend - offdata; |
|
|
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) |
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) |
_zip_dirent_torrent_normalize(de); |
_zip_dirent_torrent_normalize(de); |
|
|
if (_zip_dirent_write(de, ft, 1, &za->error) < 0) |
if (_zip_dirent_write(de, ft, 1, &za->error) < 0) |
return -1; |
return -1; |
| |
if (fseeko(ft, offend, SEEK_SET) < 0) { |
if (fseeko(ft, offend, SEEK_SET) < 0) { |
_zip_error_set(&za->error, ZIP_ER_SEEK, errno); |
_zip_error_set(&za->error, ZIP_ER_SEEK, errno); |
return -1; |
return -1; |
Line 392 add_data(struct zip *za, struct zip_source *zs, struct
|
Line 441 add_data(struct zip *za, struct zip_source *zs, struct
|
|
|
|
|
static int |
static int |
add_data_comp(zip_source_callback cb, void *ud, struct zip_stat *st,FILE *ft, |
|
struct zip_error *error) |
|
{ |
|
char buf[BUFSIZE]; |
|
ssize_t n; |
|
|
|
st->comp_size = 0; |
|
while ((n=cb(ud, buf, sizeof(buf), ZIP_SOURCE_READ)) > 0) { |
|
if (fwrite(buf, 1, n, ft) != (size_t)n) { |
|
_zip_error_set(error, ZIP_ER_WRITE, errno); |
|
return -1; |
|
} |
|
|
|
st->comp_size += n; |
|
} |
|
if (n < 0) { |
|
ch_set_error(error, cb, ud); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
static int |
|
add_data_uncomp(struct zip *za, zip_source_callback cb, void *ud, |
|
struct zip_stat *st, FILE *ft) |
|
{ |
|
char b1[BUFSIZE], b2[BUFSIZE]; |
|
int end, flush, ret; |
|
ssize_t n; |
|
size_t n2; |
|
z_stream zstr; |
|
int mem_level; |
|
|
|
st->comp_method = ZIP_CM_DEFLATE; |
|
st->comp_size = st->size = 0; |
|
st->crc = crc32(0, NULL, 0); |
|
|
|
zstr.zalloc = Z_NULL; |
|
zstr.zfree = Z_NULL; |
|
zstr.opaque = NULL; |
|
zstr.avail_in = 0; |
|
zstr.avail_out = 0; |
|
|
|
if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) |
|
mem_level = TORRENT_MEM_LEVEL; |
|
else |
|
mem_level = MAX_MEM_LEVEL; |
|
|
|
/* -MAX_WBITS: undocumented feature of zlib to _not_ write a zlib header */ |
|
deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, mem_level, |
|
Z_DEFAULT_STRATEGY); |
|
|
|
zstr.next_out = (Bytef *)b2; |
|
zstr.avail_out = sizeof(b2); |
|
zstr.next_in = NULL; |
|
zstr.avail_in = 0; |
|
|
|
flush = 0; |
|
end = 0; |
|
while (!end) { |
|
if (zstr.avail_in == 0 && !flush) { |
|
if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) { |
|
ch_set_error(&za->error, cb, ud); |
|
deflateEnd(&zstr); |
|
return -1; |
|
} |
|
if (n > 0) { |
|
zstr.avail_in = n; |
|
zstr.next_in = (Bytef *)b1; |
|
st->size += n; |
|
st->crc = crc32(st->crc, (Bytef *)b1, n); |
|
} |
|
else |
|
flush = Z_FINISH; |
|
} |
|
|
|
ret = deflate(&zstr, flush); |
|
if (ret != Z_OK && ret != Z_STREAM_END) { |
|
_zip_error_set(&za->error, ZIP_ER_ZLIB, ret); |
|
return -1; |
|
} |
|
|
|
if (zstr.avail_out != sizeof(b2)) { |
|
n2 = sizeof(b2) - zstr.avail_out; |
|
|
|
if (fwrite(b2, 1, n2, ft) != n2) { |
|
_zip_error_set(&za->error, ZIP_ER_WRITE, errno); |
|
return -1; |
|
} |
|
|
|
zstr.next_out = (Bytef *)b2; |
|
zstr.avail_out = sizeof(b2); |
|
st->comp_size += n2; |
|
} |
|
|
|
if (ret == Z_STREAM_END) { |
|
deflateEnd(&zstr); |
|
end = 1; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
static void |
|
ch_set_error(struct zip_error *error, zip_source_callback cb, void *ud) |
|
{ |
|
int e[2]; |
|
|
|
if ((cb(ud, e, sizeof(e), ZIP_SOURCE_ERROR)) < (ssize_t)sizeof(e)) { |
|
error->zip_err = ZIP_ER_INTERNAL; |
|
error->sys_err = 0; |
|
} |
|
else { |
|
error->zip_err = e[0]; |
|
error->sys_err = e[1]; |
|
} |
|
} |
|
|
|
|
|
|
|
static int |
|
copy_data(FILE *fs, off_t len, FILE *ft, struct zip_error *error) |
copy_data(FILE *fs, off_t len, FILE *ft, struct zip_error *error) |
{ |
{ |
char buf[BUFSIZE]; |
char buf[BUFSIZE]; |
Line 552 copy_data(FILE *fs, off_t len, FILE *ft, struct zip_er
|
Line 474 copy_data(FILE *fs, off_t len, FILE *ft, struct zip_er
|
|
|
|
|
static int |
static int |
|
copy_source(struct zip *za, struct zip_source *src, FILE *ft) |
|
{ |
|
char buf[BUFSIZE]; |
|
zip_int64_t n; |
|
int ret; |
|
|
|
if (zip_source_open(src) < 0) { |
|
_zip_error_set_from_source(&za->error, src); |
|
return -1; |
|
} |
|
|
|
ret = 0; |
|
while ((n=zip_source_read(src, buf, sizeof(buf))) > 0) { |
|
if (fwrite(buf, 1, n, ft) != (size_t)n) { |
|
_zip_error_set(&za->error, ZIP_ER_WRITE, errno); |
|
ret = -1; |
|
break; |
|
} |
|
} |
|
|
|
if (n < 0) { |
|
if (ret == 0) |
|
_zip_error_set_from_source(&za->error, src); |
|
ret = -1; |
|
} |
|
|
|
zip_source_close(src); |
|
|
|
return ret; |
|
} |
|
|
|
|
|
|
|
static int |
write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) |
write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out) |
{ |
{ |
off_t offset; |
off_t offset; |
Line 613 _zip_cdir_set_comment(struct zip_cdir *dest, struct zi
|
Line 569 _zip_cdir_set_comment(struct zip_cdir *dest, struct zi
|
|
|
|
|
|
|
static int | int |
_zip_changed(struct zip *za, int *survivorsp) |
_zip_changed(struct zip *za, int *survivorsp) |
{ |
{ |
int changed, i, survivors; |
int changed, i, survivors; |
Line 626 _zip_changed(struct zip *za, int *survivorsp)
|
Line 582 _zip_changed(struct zip *za, int *survivorsp)
|
|
|
for (i=0; i<za->nentry; i++) { |
for (i=0; i<za->nentry; i++) { |
if ((za->entry[i].state != ZIP_ST_UNCHANGED) |
if ((za->entry[i].state != ZIP_ST_UNCHANGED) |
|
|| (za->entry[i].ch_extra_len != -1) |
|| (za->entry[i].ch_comment_len != -1)) |
|| (za->entry[i].ch_comment_len != -1)) |
changed = 1; |
changed = 1; |
if (za->entry[i].state != ZIP_ST_DELETED) |
if (za->entry[i].state != ZIP_ST_DELETED) |
survivors++; |
survivors++; |
} |
} |
|
|
*survivorsp = survivors; | if (survivorsp) |
| *survivorsp = survivors; |
|
|
return changed; |
return changed; |
} |
} |
Line 668 _zip_create_temp_output(struct zip *za, FILE **outp)
|
Line 626 _zip_create_temp_output(struct zip *za, FILE **outp)
|
return NULL; |
return NULL; |
} |
} |
#ifdef PHP_WIN32 |
#ifdef PHP_WIN32 |
|
/* |
|
According to Pierre Joye, Windows in some environments per |
|
default creates text files, so force binary mode. |
|
*/ |
_setmode(_fileno(tfp), _O_BINARY ); |
_setmode(_fileno(tfp), _O_BINARY ); |
#endif |
#endif |
|
|