TorrentZip support.
- two new functions (zip_get_archive_flag, zip_set_archive_flag)
to manipulate archive-global flags, currently only wether an archive
is/should be torrentzipped.
- new flag to zip_source_zip (ZIP_FL_RECOMPRESS) to force recompression
- new program to torrentzip existing archive.
--HG--
branch : HEAD
diff --git a/.hgignore b/.hgignore
index 93a8fb3..d23e0d4 100644
--- a/.hgignore
+++ b/.hgignore
@@ -30,3 +30,4 @@
^regress/set_comment_revert$
^src/zipcmp$
^src/zipmerge$
+^src/ziptorrent$
diff --git a/NEWS b/NEWS
index ea25d58..f63f6ed 100644
--- a/NEWS
+++ b/NEWS
@@ -2,12 +2,15 @@
* on Windows, explictly set dllimport/dllexport
* remove erroneous references to GPL
+* add support for torrentzip
+* new functions: zip_get_archive_flag, zip_set_archive_flag
+* zip_source_zip: add flag to force recompression
0.8 [2007/06/06]
* fix for zip archives larger than 2GiB
* fix zip_error_strerror to include libzip error string
-* add support for streamed zip files
+* add support for reading streamed zip files
* new functions: zip_add_dir, zip_error_clear, zip_file_error_clear
* add basic support for building with CMake (incomplete)
diff --git a/TODO b/TODO
index e49d184..3270b90 100644
--- a/TODO
+++ b/TODO
@@ -5,12 +5,10 @@
- [doc] document that no empty archives will be created
- [bug] zip_close: on empty archive, don't try to delete non-existent file
- [bug] zip_merge: zip_close too early for source archives
-- [feature] torrentzip support
- . two flag members in struct zip (has, should)
- . zip_get_global_flag(zip, flag, unchanged?)
- . zip_set_global_flag(zip, flag, value)
- . if was TZ but shouldn't be, delete comment
- . if should be TZ, convert existing (if wasn't), normalize added
++ [doc] zip_source_zip ZIP_FL_RECOMPRESS
++ [doc] zip_get_archive_flag, zip_set_archive_flag
++ [doc] ziptorrent(1)
++ [test] ziptorrent support
+ [feature] Windows support:
. better mkstemp replacement function (no getpid; other problems?)
. snprintf replacement
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a55920c..5a6d095 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -25,6 +25,7 @@
zip_file_error_get.c \
zip_file_get_offset.c \
zip_file_strerror.c \
+ zip_filerange_crc.c \
zip_fopen.c \
zip_fopen_index.c \
zip_fread.c \
diff --git a/lib/zip.h b/lib/zip.h
index 014df7a..48431a3 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -65,6 +65,7 @@
#define ZIP_FL_NODIR 2 /* ignore directory component */
#define ZIP_FL_COMPRESSED 4 /* read compressed data */
#define ZIP_FL_UNCHANGED 8 /* use original data, ignoring changes */
+#define ZIP_FL_RECOMPRESS 16 /* force recompression of data */
/* archive global flags flags */
diff --git a/lib/zip_close.c b/lib/zip_close.c
index 326c26f..49462d8 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -42,16 +42,26 @@
#include "zipint.h"
-static int add_data(struct zip *, int, struct zip_dirent *, FILE *);
+static int add_data(struct zip *, struct zip_source *, struct zip_dirent *,
+ FILE *);
static int add_data_comp(zip_source_callback, void *, struct zip_stat *,
FILE *, struct zip_error *);
-static int add_data_uncomp(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 write_cdir(struct zip *, struct zip_cdir *, FILE *);
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 int _zip_torrentzip_cmp(const void *, const void *);
+
+
+
+struct filelist {
+ int idx;
+ const char *name;
+};
@@ -65,7 +75,9 @@
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;
@@ -88,16 +100,37 @@
_zip_free(za);
return 0;
}
-
- if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL)
+
+ 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]);
- if (_zip_cdir_set_comment(cd, za) == -1) {
- _zip_cdir_free(cd);
- return -1;
+ /* archive comment is special for torrentzip */
+ if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) {
+ cd->comment = _zip_memdup(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) {
@@ -105,29 +138,48 @@
return -1;
}
- error = 0;
+
+ /* 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++;
+ }
+ 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)) {
+ 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_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 {
+ if (za->entry[i].state == ZIP_ST_ADDED) {
de.filename = strdup("-");
de.filename_len = 1;
cd->entry[j].filename = "-";
+ }
+ 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;
}
}
@@ -163,7 +215,8 @@
cd->entry[j].filename_len = de.filename_len;
}
- if (za->entry[i].ch_comment_len != -1) {
+ 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;
@@ -171,8 +224,19 @@
cd->entry[j].offset = ftello(out);
- if (ZIP_ENTRY_DATA_CHANGED(za->entry+i)) {
- if (add_data(za, i, &de, out) < 0) {
+ 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;
}
@@ -195,16 +259,14 @@
}
}
- j++;
-
_zip_dirent_finalize(&de);
}
if (!error) {
- if (_zip_cdir_write(cd, out, &za->error) < 0)
+ if (write_cdir(za, cd, out) < 0)
error = 1;
}
-
+
/* pointers in cd entries are owned by za */
cd->nentry = 0;
_zip_cdir_free(cd);
@@ -252,15 +314,15 @@
static int
-add_data(struct zip *za, int idx, struct zip_dirent *de, FILE *ft)
+add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft)
{
off_t offstart, offend;
zip_source_callback cb;
void *ud;
struct zip_stat st;
- cb = za->entry[idx].source->f;
- ud = za->entry[idx].source->ud;
+ cb = zs->f;
+ ud = zs->ud;
if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) {
ch_set_error(&za->error, cb, ud);
@@ -282,7 +344,7 @@
return -1;
}
else {
- if (add_data_uncomp(cb, ud, &st, ft, &za->error) < 0)
+ if (add_data_uncomp(za, cb, ud, &st, ft) < 0)
return -1;
}
@@ -297,13 +359,17 @@
_zip_error_set(&za->error, ZIP_ER_SEEK, errno);
return -1;
}
+
- de->comp_method = st.comp_method;
de->last_mod = st.mtime;
+ de->comp_method = st.comp_method;
de->crc = st.crc;
de->uncomp_size = st.size;
de->comp_size = st.comp_size;
+ if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
+ _zip_dirent_torrent_normalize(de);
+
if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
return -1;
@@ -344,14 +410,15 @@
static int
-add_data_uncomp(zip_source_callback cb, void *ud, struct zip_stat *st,
- FILE *ft, struct zip_error *error)
+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;
@@ -363,8 +430,13 @@
zstr.avail_in = 0;
zstr.avail_out = 0;
- /* -15: undocumented feature of zlib to _not_ write a zlib header */
- deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 9,
+ 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;
@@ -376,7 +448,7 @@
while (!end) {
if (zstr.avail_in == 0 && !flush) {
if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) {
- ch_set_error(error, cb, ud);
+ ch_set_error(&za->error, cb, ud);
deflateEnd(&zstr);
return -1;
}
@@ -392,7 +464,7 @@
ret = deflate(&zstr, flush);
if (ret != Z_OK && ret != Z_STREAM_END) {
- _zip_error_set(error, ZIP_ER_ZLIB, ret);
+ _zip_error_set(&za->error, ZIP_ER_ZLIB, ret);
return -1;
}
@@ -400,7 +472,7 @@
n2 = sizeof(b2) - zstr.avail_out;
if (fwrite(b2, 1, n2, ft) != n2) {
- _zip_error_set(error, ZIP_ER_WRITE, errno);
+ _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
return -1;
}
@@ -471,6 +543,44 @@
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;
+
+ snprintf(buf, sizeof(buf), "%08lX", (long)crc);
+
+ 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
_zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src)
{
if (src->ch_comment_len != -1) {
@@ -501,7 +611,8 @@
changed = survivors = 0;
- if (za->ch_comment_len != -1)
+ if (za->ch_comment_len != -1
+ || za->ch_flags != za->flags)
changed = 1;
for (i=0; i<za->nentry; i++) {
@@ -550,3 +661,12 @@
*outp = tfp;
return temp;
}
+
+
+
+static int
+_zip_torrentzip_cmp(const void *a, const void *b)
+{
+ return strcasecmp(((const struct filelist *)a)->name,
+ ((const struct filelist *)b)->name);
+}
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
index 7b95359..5f39a8b 100644
--- a/lib/zip_dirent.c
+++ b/lib/zip_dirent.c
@@ -1,6 +1,6 @@
/*
zip_dirent.c -- read directory entry (local or central), clean dirent
- Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+ Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -318,6 +318,50 @@
+/* _zip_dirent_torrent_normalize(de);
+ Set values suitable for torrentzip.
+*/
+
+void
+_zip_dirent_torrent_normalize(struct zip_dirent *de)
+{
+ static struct tm torrenttime = {
+ 0, 32, 23, 24, 11, 96, 0, 0, -1, 0, "UTC"
+ };
+ static last_mod = 0;
+
+ if (last_mod == 0) {
+ time_t now;
+ struct tm *l;
+
+ time(&now);
+ l = localtime(&now);
+ torrenttime.tm_gmtoff = l->tm_gmtoff;
+ torrenttime.tm_zone = l->tm_zone;
+ last_mod = mktime(&torrenttime);
+ }
+
+ de->version_madeby = 0;
+ de->version_needed = 20; /* 2.0 */
+ de->bitflags = 2; /* maximum compression */
+ de->comp_method = ZIP_CM_DEFLATE;
+ de->last_mod = last_mod;
+
+ de->disk_number = 0;
+ de->int_attrib = 0;
+ de->ext_attrib = 0;
+ de->offset = 0;
+
+ free(de->extrafield);
+ de->extrafield = NULL;
+ de->extrafield_len = 0;
+ free(de->comment);
+ de->comment = NULL;
+ de->comment_len = 0;
+}
+
+
+
/* _zip_dirent_write(zde, fp, localp, error):
Writes zip directory entry zde to file fp.
diff --git a/lib/zip_filerange_crc.c b/lib/zip_filerange_crc.c
new file mode 100644
index 0000000..4d1ad56
--- /dev/null
+++ b/lib/zip_filerange_crc.c
@@ -0,0 +1,71 @@
+/*
+ zip_filerange_crc.c -- compute CRC32 for a range of a file
+ Copyright (C) 2008 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "zipint.h"
+
+
+
+
+int
+_zip_filerange_crc(FILE *fp, off_t start, off_t len, uLong *crcp,
+ struct zip_error *errp)
+{
+ Bytef buf[BUFSIZE];
+ size_t n;
+
+ *crcp = crc32(0L, Z_NULL, 0);
+
+ if (fseeko(fp, start, SEEK_SET) != 0) {
+ _zip_error_set(errp, ZIP_ER_SEEK, errno);
+ return -1;
+ }
+
+ while (len > 0) {
+ n = len > BUFSIZE ? BUFSIZE : len;
+ if ((n=fread(buf, 1, n, fp)) <= 0) {
+ _zip_error_set(errp, ZIP_ER_READ, errno);
+ return -1;
+ }
+
+ *crcp = crc32(*crcp, buf, n);
+
+ len-= n;
+ }
+
+ return 0;
+}
diff --git a/lib/zip_get_archive_flag.c b/lib/zip_get_archive_flag.c
new file mode 100644
index 0000000..4733d92
--- /dev/null
+++ b/lib/zip_get_archive_flag.c
@@ -0,0 +1,48 @@
+/*
+ zip_get_archive_flag.c -- get archive global flag
+ Copyright (C) 2008 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include "zipint.h"
+
+
+
+ZIP_EXTERN int
+zip_get_archive_flag(struct zip *za, int flag, int flags)
+{
+ int fl;
+
+ fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags;
+
+ return (fl & flag) ? 1 : 0;
+}
diff --git a/lib/zip_open.c b/lib/zip_open.c
index d3306c8..2d8fa90 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -311,8 +311,6 @@
{
uLong crc_got, crc_should;
char *end;
- Bytef buf[BUFSIZE];
- unsigned int n, remain;
if (za->zp == NULL || za->cdir == NULL)
return;
@@ -325,22 +323,10 @@
crc_should = strtoul(za->cdir->comment+TORRENT_SIG_LEN, &end, 16);
if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
return;
-
- crc_got = crc32(0L, Z_NULL, 0);
- if (fseek(za->zp, za->cdir->offset, SEEK_SET) != 0)
+ if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size,
+ &crc_got, NULL) < 0)
return;
- remain = za->cdir->size;
-
- while (remain > 0) {
- n = remain > BUFSIZE ? BUFSIZE : remain;
- if ((n=fread(buf, 1, n, za->zp)) <= 0)
- return;
-
- crc_got = crc32(crc_got, buf, n);
-
- remain -= n;
- }
if (crc_got == crc_should)
za->flags |= ZIP_AFL_TORRENT;
diff --git a/lib/zip_set_archive_flag.c b/lib/zip_set_archive_flag.c
new file mode 100644
index 0000000..720e1f3
--- /dev/null
+++ b/lib/zip_set_archive_flag.c
@@ -0,0 +1,49 @@
+/*
+ zip_get_archive_flag.c -- set archive global flag
+ Copyright (C) 2008 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include "zipint.h"
+
+
+
+ZIP_EXTERN int
+zip_set_archive_flag(struct zip *za, int flag, int value)
+{
+ if (value)
+ za->ch_flags |= flag;
+ else
+ za->ch_flags &= ~flag;
+
+ return 0;
+}
diff --git a/lib/zip_source_zip.c b/lib/zip_source_zip.c
index 0768027..3eef552 100644
--- a/lib/zip_source_zip.c
+++ b/lib/zip_source_zip.c
@@ -1,6 +1,6 @@
/*
zip_source_zip.c -- create data source from zip file
- Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner
+ Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -57,6 +57,8 @@
struct zip_source *zs;
struct read_zip *p;
+ /* XXX: ZIP_FL_RECOMPRESS */
+
if (za == NULL)
return NULL;
@@ -74,7 +76,7 @@
if (len == 0)
len = -1;
- if (start == 0 && len == -1)
+ if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0)
flags |= ZIP_FL_COMPRESSED;
else
flags &= ~ZIP_FL_COMPRESSED;
diff --git a/lib/zip_unchange_archive.c b/lib/zip_unchange_archive.c
index 6378e39..8f9c024 100644
--- a/lib/zip_unchange_archive.c
+++ b/lib/zip_unchange_archive.c
@@ -1,6 +1,6 @@
/*
zip_unchange_archive.c -- undo global changes to ZIP archive
- Copyright (C) 2006-2007 Dieter Baron and Thomas Klausner
+ Copyright (C) 2006-2008 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -46,5 +46,7 @@
za->ch_comment = NULL;
za->ch_comment_len = -1;
+ za->ch_flags = za->flags;
+
return 0;
}
diff --git a/lib/zipint.h b/lib/zipint.h
index 7107585..051be5f 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -72,6 +72,8 @@
#define DATADES_MAGIC "PK\7\8"
#define TORRENT_SIG "TORRENTZIPPED-"
#define TORRENT_SIG_LEN 14
+#define TORRENT_CRC_LEN 8
+#define TORRENT_MEM_LEVEL 8
#define CDENTRYSIZE 46u
#define LENTRYSIZE 30
#define MAXCOMLEN 65536
@@ -213,6 +215,7 @@
+int _zip_cdir_compute_crc(struct zip *, uLong *);
void _zip_cdir_free(struct zip_cdir *);
struct zip_cdir *_zip_cdir_new(int, struct zip_error *);
int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *);
@@ -221,6 +224,7 @@
void _zip_dirent_init(struct zip_dirent *);
int _zip_dirent_read(struct zip_dirent *, FILE *,
unsigned char **, unsigned int, int, struct zip_error *);
+void _zip_dirent_torrent_normalize(struct zip_dirent *);
int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *);
void _zip_entry_free(struct zip_entry *);
@@ -238,6 +242,8 @@
int _zip_file_fillbuf(void *, size_t, struct zip_file *);
unsigned int _zip_file_get_offset(struct zip *, int);
+int _zip_filerange_crc(FILE *, off_t, off_t, uLong *, struct zip_error *);
+
void _zip_free(struct zip *);
const char *_zip_get_name(struct zip *, int, int, struct zip_error *);
int _zip_local_header_read(struct zip *, int);
diff --git a/man/zip_source_zip.mdoc b/man/zip_source_zip.mdoc
index d3437a7..860c2c3 100644
--- a/man/zip_source_zip.mdoc
+++ b/man/zip_source_zip.mdoc
@@ -76,6 +76,7 @@
have been made to
.Ar srcarchive
after opening it.
+.\" XXX: document ZIP_FL_RECOMPRESS
.Sh RETURN VALUES
Upon successful completion, the created source is returned.
Otherwise,
diff --git a/man/zip_unchange_archive.mdoc b/man/zip_unchange_archive.mdoc
index 2b3137c..dc331b3 100644
--- a/man/zip_unchange_archive.mdoc
+++ b/man/zip_unchange_archive.mdoc
@@ -1,7 +1,7 @@
.\" $NiH: zip_unchange_all.mdoc,v 1.10 2005/06/09 21:14:54 wiz Exp $
.\"
.\" zip_unchange_archive.mdoc -- undo changes to all files in zip archive
-.\" Copyright (C) 2006 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2006-2008 Dieter Baron and Thomas Klausner
.\"
.\" This file is part of libzip, a library to manipulate ZIP archives.
.\" The authors can be contacted at <libzip@nih.at>
@@ -31,7 +31,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd April 23, 2006
+.Dd May 14, 2008
.Dt ZIP_UNCHANGE_ARCHIVE 3
.Os
.Sh NAME
@@ -46,7 +46,7 @@
.Sh DESCRIPTION
Revert all global changes to the archive
.Ar archive .
-For now, this only reverts archive comment changes.
+This reverts changes to the archive comment and global flags.
.Sh RETURN VALUES
Upon successful completion 0 is returned.
Otherwise, \-1 is returned and the error code in
diff --git a/src/Makefile.am b/src/Makefile.am
index 3235bde..2bd9a1b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,8 +1,10 @@
-bin_PROGRAMS=zipcmp zipmerge
+bin_PROGRAMS=zipcmp zipmerge ziptorrent
zipcmp_CPPFLAGS=-I${top_srcdir}/lib
zipcmp_LDADD=${top_builddir}/lib/libzip.la
zipmerge_CPPFLAGS=-I${top_srcdir}/lib
zipmerge_LDADD=${top_builddir}/lib/libzip.la
+ziptorrent_CPPFLAGS=-I${top_srcdir}/lib
+ziptorrent_LDADD=${top_builddir}/lib/libzip.la
EXTRA_DIST= CMakeLists.txt
diff --git a/src/ziptorrent.c b/src/ziptorrent.c
new file mode 100644
index 0000000..0ca7197
--- /dev/null
+++ b/src/ziptorrent.c
@@ -0,0 +1,143 @@
+/*
+ zipcmp.c -- compare zip files
+ Copyright (C) 2008 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include "config.h"
+#include "zip.h"
+
+
+
+const char *prg;
+
+#define PROGRAM "ziptorrent"
+
+char *usage = "usage: %s [-hV] zip [...]\n";
+
+char help_head[] =
+ PROGRAM " (" PACKAGE ") by Dieter Baron and Thomas Klausner\n\n";
+
+char help[] = "\n\
+ -h display this help message\n\
+ -V display version number\n\
+\n\
+Report bugs to <libzip@nih.at>.\n";
+
+char version_string[] = PROGRAM " (" PACKAGE " " VERSION ")\n\
+Copyright (C) 2008 Dieter Baron and Thomas Klausner\n\
+" PACKAGE " comes with ABSOLUTELY NO WARRANTY, to the extent permitted by law.\n";
+
+#define OPTIONS "hV"
+
+static int torrentzip(const char *);
+
+
+
+int
+main(int argc, char * const argv[])
+{
+ int err;
+ int c;
+
+ prg = argv[0];
+
+ while ((c=getopt(argc, argv, OPTIONS)) != -1) {
+ switch (c) {
+ case 'h':
+ fputs(help_head, stdout);
+ printf(usage, prg);
+ fputs(help, stdout);
+ exit(0);
+ case 'V':
+ fputs(version_string, stdout);
+ exit(0);
+
+ default:
+ fprintf(stderr, usage, prg);
+ exit(2);
+ }
+ }
+
+ if (argc == optind) {
+ fprintf(stderr, usage, prg);
+ exit(2);
+ }
+
+ err = 0;
+ while (optind < argc) {
+ err |= torrentzip(argv[optind++]);
+ }
+
+ return (err ? 1 : 0);
+}
+
+
+
+static int
+torrentzip(const char *fname)
+{
+ struct zip *za;
+ int err;
+ char errstr[1024];
+
+ if ((za=zip_open(fname, 0, &err)) == NULL) {
+ zip_error_to_str(errstr, sizeof(errstr), err, errno);
+ fprintf(stderr, "%s: cannot open zip archive `%s': %s\n",
+ prg, fname, errstr);
+ return -1;
+ }
+
+ if (zip_set_archive_flag(za, ZIP_AFL_TORRENT, 1) < 0) {
+ fprintf(stderr, "%s: cannot set torrentzip flag in `%s': %s\n",
+ prg, fname, zip_strerror(za));
+ zip_close(za);
+ return -1;
+ }
+
+ if (zip_close(za) < 0) {
+ fprintf(stderr, "%s: cannot torrentzip `%s': %s\n",
+ prg, fname, zip_strerror(za));
+ zip_unchange_all(za);
+ zip_close(za);
+ return -1;
+ }
+
+ return 0;
+}