Implement zip_fdopen and ZIP_AFL_RDONLY. This allows to open a zip archive from an already open file descriptor; archives opened this way are marked read-only. --HG-- branch : HEAD
diff --git a/lib/Makefile.am b/lib/Makefile.am index f52984c..b6d7b13 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am
@@ -25,6 +25,7 @@ zip_error_strerror.c \ zip_error_to_str.c \ zip_fclose.c \ + zip_fdopen.c \ zip_file_error_clear.c \ zip_file_error_get.c \ zip_file_get_offset.c \
diff --git a/lib/zip.h b/lib/zip.h index 0c9a7f6..03b5640 100644 --- a/lib/zip.h +++ b/lib/zip.h
@@ -68,10 +68,13 @@ #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 */ +#define ZIP_FL_ENCRYPTED 32 /* read encrypted data + (implies ZIP_FL_COMPRESSED) */ /* archive global flags flags */ #define ZIP_AFL_TORRENT 1 /* torrent zipped */ +#define ZIP_AFL_RDONLY 2 /* read only -- cannot be cleared */ /* libzip error codes */ @@ -100,6 +103,8 @@ #define ZIP_ER_REMOVE 22 /* S Can't remove file */ #define ZIP_ER_DELETED 23 /* N Entry has been deleted */ #define ZIP_ER_ENCRNOTSUPP 24 /* N Encryption method not supported */ +#define ZIP_ER_RDONLY 25 /* N Read-only archive */ +#define ZIP_ER_NOPASSWD 26 /* N No password provided */ /* type of system error value */ @@ -189,6 +194,7 @@ ZIP_EXTERN int zip_error_get_sys_type(int); ZIP_EXTERN int zip_error_to_str(char *, size_t, int, int); ZIP_EXTERN int zip_fclose(struct zip_file *); +ZIP_EXTERN struct zip *zip_fdopen(int, int, int *); ZIP_EXTERN void zip_file_error_clear(struct zip_file *); ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *); ZIP_EXTERN const char *zip_file_strerror(struct zip_file *);
diff --git a/lib/zip_add_dir.c b/lib/zip_add_dir.c index 493e28d..39c13ee 100644 --- a/lib/zip_add_dir.c +++ b/lib/zip_add_dir.c
@@ -1,6 +1,6 @@ /* zip_add_dir.c -- add directory - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -47,6 +47,11 @@ 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;
diff --git a/lib/zip_close.c b/lib/zip_close.c index f5dc3a6..baac888 100644 --- a/lib/zip_close.c +++ b/lib/zip_close.c
@@ -1,6 +1,6 @@ /* zip_close.c -- close zip archive and update changes - Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -52,7 +52,6 @@ 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 *); @@ -604,7 +603,7 @@ -static int +int _zip_changed(struct zip *za, int *survivorsp) { int changed, i, survivors; @@ -623,7 +622,8 @@ survivors++; } - *survivorsp = survivors; + if (survivorsp) + *survivorsp = survivors; return changed; }
diff --git a/lib/zip_delete.c b/lib/zip_delete.c index a0545e4..382b3fd 100644 --- a/lib/zip_delete.c +++ b/lib/zip_delete.c
@@ -1,6 +1,6 @@ /* zip_delete.c -- delete file from zip archive - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -45,6 +45,11 @@ 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)
diff --git a/lib/zip_fdopen.c b/lib/zip_fdopen.c new file mode 100644 index 0000000..09cdafd --- /dev/null +++ b/lib/zip_fdopen.c
@@ -0,0 +1,61 @@ +/* + zip_fdopen.c -- open read-only archive from file descriptor + Copyright (C) 2009 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 struct zip * +zip_fdopen(int fd_orig, int flags, int *zep) +{ + int fd; + FILE *fp; + + /* XXX: we dup here to avoid messing with the passed in fd. + We could not restore it to the original state in case of error. */ + + if ((fd=dup(fd_orig)) < 0) { + *zep = ZIP_ER_OPEN; + return NULL; + } + + if ((fp=fdopen(fd, "rb")) == NULL) { + close(fd); + *zep = ZIP_ER_OPEN; + return NULL; + } + + return _zip_open(NULL, fp, flags, ZIP_AFL_RDONLY, zep); +}
diff --git a/lib/zip_open.c b/lib/zip_open.c index c4199d3..f49aeba 100644 --- a/lib/zip_open.c +++ b/lib/zip_open.c
@@ -1,6 +1,6 @@ /* - zip_open.c -- open zip archive - Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + zip_open.c -- open zip archive by name + Copyright (C) 1999-2009 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> @@ -61,10 +61,6 @@ 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: @@ -80,7 +76,23 @@ return NULL; } - fseeko(fp, 0, SEEK_END); + return _zip_open(fn, fp, flags, 0, zep); +} + + + +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 */ @@ -417,12 +429,16 @@ 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; + + if (fn == NULL) + za->zn = NULL; + else { + za->zn = strdup(fn); + if (!za->zn) { + _zip_free(za); + set_error(zep, NULL, ZIP_ER_MEMORY); + return NULL; + } } return za; }
diff --git a/lib/zip_rename.c b/lib/zip_rename.c index 1d056bb..1609b5c 100644 --- a/lib/zip_rename.c +++ b/lib/zip_rename.c
@@ -1,6 +1,6 @@ /* zip_rename.c -- rename file in zip archive - Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -50,6 +50,11 @@ 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;
diff --git a/lib/zip_replace.c b/lib/zip_replace.c index 6cdb80c..baa0b8a 100644 --- a/lib/zip_replace.c +++ b/lib/zip_replace.c
@@ -1,6 +1,6 @@ /* zip_replace.c -- replace file via callback function - Copyright (C) 1999-2007 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -58,6 +58,11 @@ _zip_replace(struct zip *za, int idx, const char *name, struct zip_source *source) { + if (ZIP_IS_RDONLY(za)) { + _zip_error_set(&za->error, ZIP_ER_RDONLY, 0); + return -1; + } + if (idx == -1) { if (_zip_entry_new(za) == NULL) return -1;
diff --git a/lib/zip_set_archive_comment.c b/lib/zip_set_archive_comment.c index 343fa54..3bb85d1 100644 --- a/lib/zip_set_archive_comment.c +++ b/lib/zip_set_archive_comment.c
@@ -1,6 +1,6 @@ /* zip_set_archive_comment.c -- set archive comment - Copyright (C) 2006-2007 Dieter Baron and Thomas Klausner + Copyright (C) 2006-2009 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> @@ -50,6 +50,11 @@ 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;
diff --git a/lib/zip_set_archive_flag.c b/lib/zip_set_archive_flag.c index 720e1f3..dc3ef94 100644 --- a/lib/zip_set_archive_flag.c +++ b/lib/zip_set_archive_flag.c
@@ -1,6 +1,6 @@ /* zip_get_archive_flag.c -- set archive global flag - Copyright (C) 2008 Dieter Baron and Thomas Klausner + Copyright (C) 2008-2009 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> @@ -40,10 +40,30 @@ ZIP_EXTERN int zip_set_archive_flag(struct zip *za, int flag, int value) { + int new_flags; + if (value) - za->ch_flags |= flag; + new_flags = za->ch_flags | flag; else - za->ch_flags &= ~flag; + 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; }
diff --git a/lib/zip_set_file_comment.c b/lib/zip_set_file_comment.c index bc1938e..571e86c 100644 --- a/lib/zip_set_file_comment.c +++ b/lib/zip_set_file_comment.c
@@ -1,6 +1,6 @@ /* zip_set_file_comment.c -- set comment for file in archive - Copyright (C) 2006-2007 Dieter Baron and Thomas Klausner + Copyright (C) 2006-2009 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> @@ -51,6 +51,11 @@ 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;
diff --git a/lib/zipint.h b/lib/zipint.h index da08ed7..9f17dff 100644 --- a/lib/zipint.h +++ b/lib/zipint.h
@@ -3,7 +3,7 @@ /* zipint.h -- internal declarations. - Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2009 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> @@ -213,6 +213,8 @@ ((x)->state == ZIP_ST_REPLACED \ || (x)->state == ZIP_ST_ADDED) +#define ZIP_IS_RDONLY(za) ((za)->ch_flags & ZIP_AFL_RDONLY) + int _zip_cdir_compute_crc(struct zip *, uLong *); @@ -244,9 +246,12 @@ int _zip_filerange_crc(FILE *, off_t, off_t, uLong *, struct zip_error *); +struct zip *_zip_open(const char *, FILE *, int, int, int *); + struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *, zip_uint64_t, zip_int64_t); +int _zip_changed(struct zip *, int *); 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);