zip_source_open: Only keep files open while we read from them.
Otherwise, applications might easly run out of file descriptors.

--HG--
branch : HEAD
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index 2189eb6..5373934 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -1,6 +1,6 @@
 /*
   zip_source_filep.c -- create data source from 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>
@@ -42,6 +42,7 @@
 #include "zipint.h"
 
 struct read_file {
+    char *fname;	/* name of file to copy from */
     FILE *f;		/* file to copy from */
     off_t off;		/* start offset of */
     off_t len;		/* lengt of data to copy */
@@ -57,9 +58,6 @@
 ZIP_EXTERN struct zip_source *
 zip_source_filep(struct zip *za, FILE *file, off_t start, off_t len)
 {
-    struct read_file *f;
-    struct zip_source *zs;
-
     if (za == NULL)
 	return NULL;
 
@@ -68,11 +66,36 @@
 	return NULL;
     }
 
+    return _zip_source_file_or_p(za, NULL, file, start, len);
+}
+
+
+
+struct zip_source *
+_zip_source_file_or_p(struct zip *za, const char *fname, FILE *file,
+		      off_t start, off_t len)
+{
+    struct read_file *f;
+    struct zip_source *zs;
+
+    if (file == NULL && fname == NULL) {
+	_zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+	return NULL;
+    }
+
     if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
 	_zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
 	return NULL;
     }
 
+    f->fname = NULL;
+    if (fname) {
+	if ((f->fname=strdup(fname)) == NULL) {
+	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+	    free(f);
+	    return NULL;
+	}
+    }
     f->f = file;
     f->off = start;
     f->len = (len ? len : -1);
@@ -99,6 +122,14 @@
 
     switch (cmd) {
     case ZIP_SOURCE_OPEN:
+	if (z->fname) {
+	    if ((z->f=fopen(z->fname, "rb")) == NULL) {
+		z->e[0] = ZIP_ER_OPEN;
+		z->e[1] = errno;
+		return -1;
+	    }
+	}
+
 	if (fseeko(z->f, z->off, SEEK_SET) < 0) {
 	    z->e[0] = ZIP_ER_SEEK;
 	    z->e[1] = errno;
@@ -125,17 +156,27 @@
 	return i;
 	
     case ZIP_SOURCE_CLOSE:
+	if (z->fname) {
+	    fclose(z->f);
+	    z->f = NULL;
+	}
 	return 0;
 
     case ZIP_SOURCE_STAT:
         {
 	    struct zip_stat *st;
 	    struct stat fst;
+	    int err;
 	    
 	    if (len < sizeof(*st))
 		return -1;
 
-	    if (fstat(fileno(z->f), &fst) != 0) {
+	    if (z->f)
+		err = fstat(fileno(z->f), &fst);
+	    else
+		err = stat(z->fname, &fst);
+
+	    if (err != 0) {
 		z->e[0] = ZIP_ER_READ; /* best match */
 		z->e[1] = errno;
 		return -1;
@@ -161,7 +202,9 @@
 	return sizeof(int)*2;
 
     case ZIP_SOURCE_FREE:
-	fclose(z->f);
+	free(z->fname);
+	if (z->f)
+	    fclose(z->f);
 	free(z);
 	return 0;