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);