Commit Diff


commit - 80f4afe898106e3eae350da9d42ecaf3a7d19124
commit + 962916a2f679f34e4029f33cb57807adb4be3340
blob - 9285ed5f1b90a4c3e4017658c8f83fb2dd3e8f2b
blob + 0f06cc08df37f0ffd05fa037b55dfe84e59a9d8f
--- lib/got_lib_zbuf.h
+++ lib/got_lib_zbuf.h
@@ -31,6 +31,9 @@ const struct got_error *got_inflate_init(struct got_zs
     size_t);
 const struct got_error *got_inflate_read(struct got_zstream_buf *, FILE *,
     size_t *);
+const struct got_error *got_inflate_read_fd(struct got_zstream_buf *, int,
+    size_t *);
 void got_inflate_end(struct got_zstream_buf *);
 const struct got_error *got_inflate_to_mem(uint8_t **, size_t *, FILE *);
 const struct got_error *got_inflate_to_file(size_t *, FILE *, FILE *);
+const struct got_error *got_inflate_to_fd(size_t *, int, int);
blob - 2b3120f98279f1802f0187c4a387f17ba660f9fe
blob + dcb2c9d4de8e4f38a93330772725e647ab5c2dc2
--- lib/zbuf.c
+++ lib/zbuf.c
@@ -105,6 +105,45 @@ got_inflate_read(struct got_zstream_buf *zb, FILE *f, 
 	return NULL;
 }
 
+const struct got_error *
+got_inflate_read_fd(struct got_zstream_buf *zb, int fd, size_t *outlenp)
+{
+	size_t last_total_out = zb->z.total_out;
+	z_stream *z = &zb->z;
+	int ret = Z_ERRNO;
+
+	z->next_out = zb->outbuf;
+	z->avail_out = zb->outlen;
+
+	*outlenp = 0;
+	do {
+		if (z->avail_in == 0) {
+			ssize_t n = read(fd, zb->inbuf, zb->inlen);
+			if (n < 0)
+				return got_error_from_errno();
+			else if (n == 0) {
+				/* EOF */
+				ret = Z_STREAM_END;
+				break;
+			}
+			z->next_in = zb->inbuf;
+			z->avail_in = n;
+		}
+		ret = inflate(z, Z_SYNC_FLUSH);
+	} while (ret == Z_OK && z->avail_out > 0);
+
+	if (ret == Z_OK) {
+		zb->flags |= GOT_ZSTREAM_F_HAVE_MORE;
+	} else {
+		if (ret != Z_STREAM_END)
+			return got_error(GOT_ERR_DECOMPRESSION);
+		zb->flags &= ~GOT_ZSTREAM_F_HAVE_MORE;
+	}
+
+	*outlenp = z->total_out - last_total_out;
+	return NULL;
+}
+
 void
 got_inflate_end(struct got_zstream_buf *zb)
 {
@@ -158,6 +197,43 @@ done:
 }
 
 const struct got_error *
+got_inflate_to_fd(size_t *outlen, int infd, int outfd)
+{
+	const struct got_error *err = NULL;
+	size_t avail;
+	struct got_zstream_buf zb;
+
+	err = got_inflate_init(&zb, NULL, GOT_ZSTREAM_BUFSIZE);
+	if (err)
+		goto done;
+
+	*outlen = 0;
+
+	do {
+		err = got_inflate_read_fd(&zb, infd, &avail);
+		if (err)
+			return err;
+		if (avail > 0) {
+			ssize_t n;
+			n = write(outfd, zb.outbuf, avail);
+			if (n != avail) {
+				err = got_error_from_errno();
+				goto done;
+			}
+			*outlen += avail;
+		}
+	} while (zb.flags & GOT_ZSTREAM_F_HAVE_MORE);
+
+done:
+	if (err == NULL) {
+		if (lseek(outfd, SEEK_SET, 0) == -1)
+			err = got_error_from_errno();
+	}
+	got_inflate_end(&zb);
+	return err;
+}
+
+const struct got_error *
 got_inflate_to_file(size_t *outlen, FILE *infile, FILE *outfile)
 {
 	const struct got_error *err;