Sophie

Sophie

distrib > Mandriva > 2010.2 > i586 > by-pkgid > 3360a71f40b196f13ed5026474f80f3c > files > 8

cyrus-imapd-2.3.15-10mdv2010.1.src.rpm

--- cyrus-imapd-2.3.15//lib/prot.c	2009-04-23 19:10:07.000000000 +0200
+++ cyrus-imapd-2.3.16//lib/prot.c	2009-11-05 01:19:19.000000000 +0100
@@ -39,7 +39,7 @@
  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Id: prot.c,v 1.97 2009/04/23 17:10:07 murch Exp $
+ * $Id: prot.c,v 1.98 2009/11/05 00:19:19 brong Exp $
  */
 
 #include <config.h>
@@ -287,14 +287,13 @@
     if (s->write) {
 	if (s->ptr != s->buf) {
 	    /* flush any pending output */
-	    if (prot_flush_internal(s,0) == EOF) zr = EOF;
+	    if (prot_flush_internal(s, 0) == EOF)
+	        goto error;
 	}
 
-	if (zr == Z_OK) {
-	    s->zlevel = Z_DEFAULT_COMPRESSION;
-	    zr = deflateInit2(zstrm, s->zlevel, Z_DEFLATED,
-			     -15, 8, Z_DEFAULT_STRATEGY);
-	}
+	s->zlevel = Z_DEFAULT_COMPRESSION;
+	zr = deflateInit2(zstrm, s->zlevel, Z_DEFLATED,
+		          -15, 8, Z_DEFAULT_STRATEGY);
     }
     else {
 	zstrm->next_in = Z_NULL;
@@ -302,10 +301,37 @@
 	zr = inflateInit2(zstrm, -15);
     }
 
-    if (zr != Z_OK) free(zstrm);
-    else s->zstrm = zstrm;
+    if (zr != Z_OK)
+	goto error;
+
+    /* RFC 1951 says:
+     * A simple counting argument shows that no lossless compression
+     * algorithm can compress every possible input data set.  For the
+     * format defined here, the worst case expansion is 5 bytes per 32K-
+     * byte block, i.e., a size increase of 0.015% for large data sets.
+     *
+     * We say: maxplain can never be bigger than PROT_BUFSIZE, which
+     * is currently 4096, so adding 5 bytes will do it!
+     * 
+     * Add another spare byte and we'll never totally fill the buffer,
+     * which saves a loop.
+     *
+     * NOTE: we do double check and handle buffer filling gracefully
+     * anyway, but starting with the right size is good.
+     */
+    s->zbuf_size = s->maxplain + 6;
+    s->zbuf = (unsigned char *) xmalloc(sizeof(unsigned char) * s->zbuf_size);
+    syslog(LOG_DEBUG, "created %scompress buffer of %u bytes",
+	   s->write ? "" : "de", s->zbuf_size);
+    s->zstrm = zstrm;
 
-    return zr;
+    return 0;
+
+error:
+    syslog(LOG_NOTICE, "failed to start %scompression",
+	   s->write ? "" : "de");
+    free(zstrm);
+    return EOF;
 }
 
 /* Table of incompressible file type signatures */
@@ -327,6 +353,9 @@
 {
     struct file_sig *sig = sig_tbl;
 
+    /* is it worth checking? */
+    if (n < ZLARGE_DIFF_CHUNK) return 0;
+
     while (sig->type) {
 	if (n >= sig->len && !memcmp(p, sig->sig, sig->len)) {
 	    syslog(LOG_DEBUG, "data is %s", sig->type);
@@ -515,6 +544,33 @@
     if (s->eof || s->error) return EOF;
 
     do {
+#ifdef HAVE_ZLIB
+	/* check if there's anything in the zlib buffer already */
+	if (s->zstrm && s->zstrm->avail_in) {
+	    /* Decompress the data */
+	    int zr = Z_OK;
+
+	    s->zstrm->next_out = s->zbuf;
+	    s->zstrm->avail_out = s->zbuf_size;
+	    zr = inflate(s->zstrm, Z_SYNC_FLUSH);
+	    if (!(zr == Z_OK || zr == Z_BUF_ERROR || zr == Z_STREAM_END)) {
+		/* Error decompressing */
+		syslog(LOG_ERR, "zlib inflate error: %d %s", zr, s->zstrm->msg);
+		s->error = xstrdup("Error decompressing data");
+		return EOF;
+	    }
+
+	    if (s->zstrm->avail_out < s->zbuf_size) {
+		/* inflated some data */
+		s->ptr = s->zbuf;
+		s->cnt = s->zbuf_size - s->zstrm->avail_out;
+
+		/* drop straight to logging and returning the first char */
+		break;
+	    }
+	}
+#endif
+
 	/* wait until get input */
 	haveinput = 0;
 
@@ -633,74 +689,42 @@
 	}
 
 #ifdef HAVE_ZLIB
-	if (s->zstrm && s->cnt > 0) {
-	    /* Decompress the data */
-	    int zr = Z_OK;
+	if (s->zstrm) {
+	    /* transfer the data we have to the input of 
+	     * the z_stream and loop to process it */
 
 	    s->zstrm->next_in = s->ptr;
 	    s->zstrm->avail_in = s->cnt;
-	    s->zstrm->next_out = s->zbuf;
-	    s->zstrm->avail_out = s->zbuf_size;
-
-	    syslog(LOG_DEBUG, "inflate(%d bytes)", s->cnt);
+	    s->cnt = 0;
+	}
+#endif /* HAVE_ZLIB */
+    } while (!s->cnt);
 
-	    do {
-		if (!s->zstrm->avail_out) {
-		    /* Need more space to decompress */
-		    syslog(LOG_DEBUG,
-			   "growing decompress buffer from %d to %d bytes",
-			   s->zbuf_size, s->zbuf_size + PROT_BUFSIZE);
-
-		    s->zbuf = (unsigned char *)
-			xrealloc(s->zbuf, s->zbuf_size + PROT_BUFSIZE);
-		    s->zstrm->next_out = s->zbuf + s->zbuf_size;
-		    s->zstrm->avail_out = PROT_BUFSIZE;
-		    s->zbuf_size += PROT_BUFSIZE;
-		}
+    if (s->logfd != -1) {
+	time_t newtime;
+	char timebuf[20];
 
-		zr = inflate(s->zstrm, Z_SYNC_FLUSH);
-	    } while (zr == Z_OK && !s->zstrm->avail_out);
+	time(&newtime);
+	snprintf(timebuf, sizeof(timebuf), "<%ld<", newtime);
+	write(s->logfd, timebuf, strlen(timebuf));
 
-	    if (zr != Z_OK || s->zstrm->avail_in) {
-		/* Error decompressing */
-		s->error = xstrdup("Error decompressing data");
-		return EOF;
+	left = s->cnt;
+	ptr = s->ptr;
+	do {
+	    n = write(s->logfd, ptr, left);
+	    if (n == -1 && (errno != EINTR)) {
+		break;
 	    }
 
-	    s->ptr = s->zbuf;
-	    s->cnt = s->zbuf_size - s->zstrm->avail_out;
-
-	    syslog(LOG_DEBUG, "   => decompressed to %d bytes", s->cnt);
-	}
-#endif /* HAVE_ZLIB */
-	
-	if (s->cnt > 0) {
-	    if (s->logfd != -1) {
-		time_t newtime;
-		char timebuf[20];
-
-		time(&newtime);
-		snprintf(timebuf, sizeof(timebuf), "<%ld<", newtime);
-		write(s->logfd, timebuf, strlen(timebuf));
-
-		left = s->cnt;
-		ptr = s->ptr;
-		do {
-		    n = write(s->logfd, ptr, left);
-		    if (n == -1 && errno != EINTR) {
-			break;
-		    }
-		    if (n > 0) {
-			ptr += n;
-			left -= n;
-		    }
-		} while (left);
+	    if (n > 0) {
+		ptr += n;
+		left -= n;
 	    }
+	} while (left);
+    }
 
-	    s->cnt--;		/* we return the first char */
-	    return *s->ptr++;
-	}
-    } while (1);
+    s->cnt--;		/* we return the first char */
+    return *s->ptr++;
 }
 
 /*
@@ -751,47 +775,44 @@
 #ifdef HAVE_ZLIB
     if (s->zstrm) {
 	/* Compress the data */
-	unsigned long def_size = deflateBound(s->zstrm, left);
-	int zflush = s->boundary ? Z_FULL_FLUSH : Z_SYNC_FLUSH;
 	int zr = Z_OK;
 
-	if (def_size > s->zbuf_size) {
-	    /* Make sure buffer is large enough to hold compressed data.
-	     * Oversize the buffer, so we (hopefully) eliminate
-	     * multiple small incremental reallocations.
-	     */
-	    syslog(LOG_DEBUG, "growing compress buffer from %u to %lu bytes",
-		   s->zbuf_size, def_size + PROT_BUFSIZE);
-
-	    s->zbuf_size = def_size + PROT_BUFSIZE;
-	    s->zbuf = (unsigned char *) xrealloc(s->zbuf, s->zbuf_size);
-	}
-
 	s->zstrm->next_in = ptr;
 	s->zstrm->avail_in = left;
 	s->zstrm->next_out = s->zbuf;
 	s->zstrm->avail_out = s->zbuf_size;
 
-	syslog(LOG_DEBUG, "deflate(%d bytes, level=%d, flush=%s)",
-	       left, s->zlevel,
-	       zflush == Z_FULL_FLUSH ? "FULL" : "SYNC");
-
-	if (s->boundary) {
-	    /* Set (new) compression level */
-	    zr = deflateParams(s->zstrm, s->zlevel, Z_DEFAULT_STRATEGY);
-	}
-	if (zr == Z_OK) zr = deflate(s->zstrm, zflush);
-
-	if (zr != Z_OK || s->zstrm->avail_in) {
-	    /* Error compressing */
-	    s->error = xstrdup("Error compressing data");
-	    return EOF;
-	}
+	do {
+	    /* should never be needed, but it's better to always check! */
+	    if (!s->zstrm->avail_out) {
+		syslog(LOG_DEBUG, "growing compress buffer from %u to %u bytes",
+		       s->zbuf_size, s->zbuf_size + PROT_BUFSIZE);
+
+		s->zbuf = (unsigned char *)
+		    xrealloc(s->zbuf, s->zbuf_size + PROT_BUFSIZE);
+		s->zstrm->next_out = s->zbuf + s->zbuf_size;
+		s->zstrm->avail_out = PROT_BUFSIZE;
+		s->zbuf_size += PROT_BUFSIZE;
+	    }
+
+	    zr = deflate(s->zstrm, Z_SYNC_FLUSH);
+	    if (!(zr == Z_OK || zr == Z_STREAM_END || zr == Z_BUF_ERROR)) {
+		/* something went wrong */
+		syslog(LOG_ERR, "zlib deflate error: %d %s", zr, s->zstrm->msg);
+		s->error = xstrdup("Error compressing data");
+		return EOF;
+	    }
+
+	    /* http://www.zlib.net/manual.html says:
+	     * If deflate returns with avail_out == 0, this function must be 
+	     * called again with the same value of the flush parameter and
+	     * more output space (updated avail_out), until the flush is 
+	     * complete (deflate returns with non-zero avail_out). 
+	     */
+	} while (!s->zstrm->avail_out);
 
 	ptr = s->zbuf;
 	left = s->zbuf_size - s->zstrm->avail_out;
-
-	syslog(LOG_DEBUG, "   => compressed to %d bytes", left);
     }
 #endif /* HAVE_ZLIB */
 
@@ -1059,24 +1080,26 @@
     if (s->boundary) {
 #ifdef HAVE_ZLIB
 	if (s->zstrm) {
-	    s->zlevel = Z_DEFAULT_COMPRESSION;
+	    int zr = Z_OK;
+	    int zlevel = Z_DEFAULT_COMPRESSION;
 
-	    if (len > ZLARGE_DIFF_CHUNK) {
-		/* Start of a large chunk of different data */
-		s->zflush = 1;
+	    if (is_incompressible(buf, len))
+		zlevel = Z_NO_COMPRESSION;
 
-		/* Check for incompressible data */
-		if (is_incompressible(buf, len)) s->zlevel = Z_NO_COMPRESSION;
-	    }
+	    if (zlevel != s->zlevel) {
+		s->zlevel = zlevel;
 
-	    if (s->zflush) {
-		/* Flush any pending output */
-		if (prot_flush_internal(s, 1) == EOF) return EOF;
-	    }
+		/* flush any pending data */
+		if (s->ptr != s->buf) {
+		    if (prot_flush_internal(s, 1) == EOF) return EOF;
+		}
 
-	    if (len <= ZLARGE_DIFF_CHUNK) {
-		/* End of large chunk */
-		s->zflush = 0;
+		/* Set new compression level */
+		zr = deflateParams(s->zstrm, s->zlevel, Z_DEFAULT_STRATEGY);
+		if (zr != Z_OK) {
+		    s->error = xstrdup("Error setting compression level");
+		    return EOF;
+		}
 	    }
 	}
 #endif /* HAVE_ZLIB */