Invalidate zip_source_zip when underlying zip archive is closed.
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index 48f1878..674301c 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -50,10 +50,13 @@
     zip_int64_t len;	/* length of data to copy */
     zip_int64_t remain;	/* bytes remaining to be copied */
     int e[2];		/* error codes */
+    int source_closed;  /* set if source archive is closed */
+    struct zip *source_archive;  /* zip archive we're reading from, NULL if not from archive */
 };
 
-static zip_int64_t read_file(void *state, void *data, zip_uint64_t len,
-		     enum zip_source_cmd cmd);
+static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, enum zip_source_cmd cmd);
+static void _zip_deregister_source(struct zip *za, void *ud);
+static int _zip_register_source(struct zip *za, struct zip_source *src);
 
 
 ZIP_EXTERN struct zip_source *
@@ -102,6 +105,8 @@
     f->off = start;
     f->len = (len ? len : -1);
     f->closep = f->fname ? 1 : closep;
+    f->source_closed = 0;
+    f->source_archive = NULL;
     if (st)
 	memcpy(&f->st, st, sizeof(f->st));
     else
@@ -116,6 +121,31 @@
 }
 
 
+int
+_zip_source_filep_set_source_archive(struct zip_source *src, struct zip *za)
+{
+    struct read_file *z = (struct read_file *)src->ud;
+
+    z->source_archive = za;
+    return _zip_register_source(za, src);
+}
+
+
+/* called by zip_discard to avoid operating on file from closed archive */
+void
+_zip_source_filep_invalidate(struct zip_source *src)
+{
+    struct read_file *z = (struct read_file *)src->ud;
+
+    z->source_closed = 1;
+    z->f = NULL;
+    if (z->e[0] == ZIP_ER_OK) {
+	z->e[0] = ZIP_ER_ZIPCLOSED;
+	z->e[1] = 0;
+    }
+}
+
+
 static zip_int64_t
 read_file(void *state, void *data, zip_uint64_t len, enum zip_source_cmd cmd)
 {
@@ -129,6 +159,9 @@
 
     switch (cmd) {
     case ZIP_SOURCE_OPEN:
+	if (z->source_closed)
+	    return -1;
+
 	if (z->fname) {
 	    if ((z->f=fopen(z->fname, "rb")) == NULL) {
 		z->e[0] = ZIP_ER_OPEN;
@@ -148,6 +181,9 @@
 	return 0;
 	
     case ZIP_SOURCE_READ:
+	if (z->source_closed)
+	    return -1;
+
 	if (z->remain != -1)
 	    n = len > (zip_uint64_t)z->remain ? (zip_uint64_t)z->remain : len;
 	else
@@ -179,6 +215,9 @@
 	return (zip_int64_t)i;
 	
     case ZIP_SOURCE_CLOSE:
+	if (z->source_closed)
+	    return -1;
+
 	if (z->fname) {
 	    fclose(z->f);
 	    z->f = NULL;
@@ -186,6 +225,9 @@
 	return 0;
 
     case ZIP_SOURCE_STAT:
+	if (z->source_closed)
+	    return -1;
+
         {
 	    if (len < sizeof(z->st))
 		return -1;
@@ -233,6 +275,9 @@
 	return sizeof(int)*2;
 
     case ZIP_SOURCE_FREE:
+	if (z->source_archive && !z->source_closed) {
+	    _zip_deregister_source(z->source_archive, state);
+	}
 	free(z->fname);
 	if (z->closep && z->f)
 	    fclose(z->f);
@@ -245,3 +290,41 @@
 
     return -1;
 }
+
+
+static void
+_zip_deregister_source(struct zip *za, void *ud)
+{
+    int i;
+
+    for (i=0; i<za->nsource; i++) {
+	if (za->source[i]->ud == ud) {
+	    za->source[i] = za->source[za->nsource-1];
+	    za->nsource--;
+	    break;
+	}
+    }
+}
+
+
+static int
+_zip_register_source(struct zip *za, struct zip_source *src)
+{
+    struct zip_source **source;
+
+    if (za->nsource+1 >= za->nsource_alloc) {
+	unsigned int n;
+	n = za->nsource_alloc + 10;
+	source = (struct zip_source **)realloc(za->source, n*sizeof(struct zip_source *));
+	if (source == NULL) {
+	    _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+	    return -1;
+	}
+	za->nsource_alloc = n;
+	za->source = source;
+    }
+
+    za->source[za->nsource++] = src;
+
+    return 0;
+}