From 395e92b66e35ccbd2f07a4857d6da588ec9f51f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Sat, 17 Jul 2021 19:17:46 +0300
Subject: [PATCH] io: formalize apk_ostream_write() always writing full data

---
 src/apk_io.h     |  7 +++----
 src/database.c   | 18 +++++++++---------
 src/io.c         | 45 ++++++++++++++++++---------------------------
 src/io_archive.c |  8 ++++----
 src/io_gunzip.c  | 20 ++++++++------------
 src/package.c    |  8 ++++----
 6 files changed, 46 insertions(+), 60 deletions(-)

diff --git a/src/apk_io.h b/src/apk_io.h
index 13ab4a92..d03369ea 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -141,7 +141,7 @@ struct apk_istream *apk_istream_tee(struct apk_istream *from, struct apk_ostream
 
 struct apk_ostream_ops {
 	void (*set_meta)(struct apk_ostream *os, struct apk_file_meta *meta);
-	ssize_t (*write)(struct apk_ostream *os, const void *buf, size_t size);
+	int (*write)(struct apk_ostream *os, const void *buf, size_t size);
 	int (*close)(struct apk_ostream *os);
 };
 
@@ -153,12 +153,11 @@ struct apk_ostream {
 struct apk_ostream *apk_ostream_counter(off_t *);
 struct apk_ostream *apk_ostream_to_fd(int fd);
 struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
-size_t apk_ostream_write_string(struct apk_ostream *os, const char *string);
+ssize_t apk_ostream_write_string(struct apk_ostream *os, const char *string);
 void apk_ostream_copy_meta(struct apk_ostream *os, struct apk_istream *is);
 static inline int apk_ostream_error(struct apk_ostream *os) { return os->rc; }
 static inline int apk_ostream_cancel(struct apk_ostream *os, int rc) { if (!os->rc) os->rc = rc; return rc; }
-static inline ssize_t apk_ostream_write(struct apk_ostream *os, const void *buf, size_t size)
-{
+static inline int apk_ostream_write(struct apk_ostream *os, const void *buf, size_t size) {
 	return os->ops->write(os, buf, size);
 }
 static inline int apk_ostream_close(struct apk_ostream *os)
diff --git a/src/database.c b/src/database.c
index ef050479..b009f748 100644
--- a/src/database.c
+++ b/src/database.c
@@ -986,15 +986,16 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
 					apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
 				}
 
-				if (apk_ostream_write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
-					return -EIO;
+				r = apk_ostream_write(os, buf, bbuf.ptr - buf);
+				if (r < 0) return r;
 				bbuf = APK_BLOB_BUF(buf);
 			}
-			if (apk_ostream_write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
-				return -EIO;
+			r = apk_ostream_write(os, buf, bbuf.ptr - buf);
+			if (r < 0) return r;
 			bbuf = APK_BLOB_BUF(buf);
 		}
-		apk_ostream_write(os, "\n", 1);
+		r = apk_ostream_write(os, "\n", 1);
+		if (r < 0) return r;
 	}
 
 	return 0;
@@ -1194,11 +1195,10 @@ static int write_index_entry(apk_hash_item item, void *ctx)
 		return 0;
 
 	r = apk_pkg_write_index_entry(pkg, iwctx->os);
-	if (r < 0)
-		return r;
+	if (r < 0) return r;
 
-	if (apk_ostream_write(iwctx->os, "\n", 1) != 1)
-		return apk_ostream_cancel(iwctx->os, -EIO);
+	r = apk_ostream_write(iwctx->os, "\n", 1);
+	if (r < 0) return r;
 
 	iwctx->count++;
 	return 0;
diff --git a/src/io.c b/src/io.c
index 1f53d3a7..bb5c5662 100644
--- a/src/io.c
+++ b/src/io.c
@@ -314,13 +314,10 @@ static void tee_get_meta(struct apk_istream *is, struct apk_file_meta *meta)
 	apk_istream_get_meta(tee->inner_is, meta);
 }
 
-static ssize_t __tee_write(struct apk_tee_istream *tee, void *ptr, size_t size)
+static int __tee_write(struct apk_tee_istream *tee, void *ptr, size_t size)
 {
-	ssize_t w = apk_ostream_write(tee->to, ptr, size);
-	if (size != w) {
-		if (w < 0) return w;
-		return -ENOSPC;
-	}
+	int r = apk_ostream_write(tee->to, ptr, size);
+	if (r < 0) return r;
 	tee->size += size;
 	if (tee->cb) tee->cb(tee->cb_ctx, tee->size);
 	return size;
@@ -828,11 +825,8 @@ static ssize_t fdo_flush(struct apk_fd_ostream *fos)
 
 	if (fos->os.rc < 0) return fos->os.rc;
 	if (fos->bytes == 0) return 0;
-
-	if ((r = apk_write_fully(fos->fd, fos->buffer, fos->bytes)) != fos->bytes) {
-		apk_ostream_cancel(&fos->os, r < 0 ? r : -ENOSPC);
-		return r;
-	}
+	if ((r = apk_write_fully(fos->fd, fos->buffer, fos->bytes)) != fos->bytes)
+		return apk_ostream_cancel(&fos->os, r < 0 ? r : -ENOSPC);
 
 	fos->bytes = 0;
 	return 0;
@@ -849,7 +843,7 @@ static void fdo_set_meta(struct apk_ostream *os, struct apk_file_meta *meta)
 	futimens(fos->fd, times);
 }
 
-static ssize_t fdo_write(struct apk_ostream *os, const void *ptr, size_t size)
+static int fdo_write(struct apk_ostream *os, const void *ptr, size_t size)
 {
 	struct apk_fd_ostream *fos = container_of(os, struct apk_fd_ostream, os);
 	ssize_t r;
@@ -868,7 +862,7 @@ static ssize_t fdo_write(struct apk_ostream *os, const void *ptr, size_t size)
 	memcpy(&fos->buffer[fos->bytes], ptr, size);
 	fos->bytes += size;
 
-	return size;
+	return 0;
 }
 
 static int fdo_close(struct apk_ostream *os)
@@ -877,12 +871,10 @@ static int fdo_close(struct apk_ostream *os)
 	int rc;
 
 	fdo_flush(fos);
-	rc = fos->os.rc;
-
-	if (fos->fd > STDERR_FILENO &&
-	    close(fos->fd) < 0)
-		rc = -errno;
+	if (fos->fd > STDERR_FILENO && close(fos->fd) < 0)
+		apk_ostream_cancel(os, -errno);
 
+	rc = fos->os.rc;
 	if (fos->file) {
 		char tmpname[PATH_MAX];
 
@@ -895,7 +887,6 @@ static int fdo_close(struct apk_ostream *os)
 			unlinkat(fos->atfd, tmpname, 0);
 		}
 	}
-
 	free(fos);
 
 	return rc;
@@ -954,20 +945,20 @@ struct apk_counter_ostream {
 	off_t *counter;
 };
 
-static ssize_t co_write(struct apk_ostream *os, const void *ptr, size_t size)
+static int co_write(struct apk_ostream *os, const void *ptr, size_t size)
 {
 	struct apk_counter_ostream *cos = container_of(os, struct apk_counter_ostream, os);
-
 	*cos->counter += size;
-	return size;
+	return 0;
 }
 
 static int co_close(struct apk_ostream *os)
 {
 	struct apk_counter_ostream *cos = container_of(os, struct apk_counter_ostream, os);
+	int rc = os->rc;
 
 	free(cos);
-	return 0;
+	return rc;
 }
 
 static const struct apk_ostream_ops counter_ostream_ops = {
@@ -991,14 +982,14 @@ struct apk_ostream *apk_ostream_counter(off_t *counter)
 	return &cos->os;
 }
 
-size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
+ssize_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
 {
 	size_t len;
+	ssize_t r;
 
 	len = strlen(string);
-	if (apk_ostream_write(os, string, len) != len)
-		return -1;
-
+	r = apk_ostream_write(os, string, len);
+	if (r < 0) return r;
 	return len;
 }
 
diff --git a/src/io_archive.c b/src/io_archive.c
index 984af094..1164d7c2 100644
--- a/src/io_archive.c
+++ b/src/io_archive.c
@@ -302,15 +302,15 @@ int apk_tar_write_entry(struct apk_ostream *os, const struct apk_file_info *ae,
 	        put_octal(buf.chksum, sizeof(buf.chksum)-1, chksum);
 	}
 
-	if (apk_ostream_write(os, &buf, sizeof(buf)) != sizeof(buf))
+	if (apk_ostream_write(os, &buf, sizeof(buf)) < 0)
 		return -1;
 
 	if (ae == NULL) {
 		/* End-of-archive is two empty headers */
-		if (apk_ostream_write(os, &buf, sizeof(buf)) != sizeof(buf))
+		if (apk_ostream_write(os, &buf, sizeof(buf)) < 0)
 			return -1;
 	} else if (data != NULL) {
-		if (apk_ostream_write(os, data, ae->size) != ae->size)
+		if (apk_ostream_write(os, data, ae->size) < 0)
 			return -1;
 		if (apk_tar_write_padding(os, ae) != 0)
 			return -1;
@@ -326,7 +326,7 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae
 
 	pad = 512 - (ae->size & 511);
 	if (pad != 512 &&
-	    apk_ostream_write(os, padding, pad) != pad)
+	    apk_ostream_write(os, padding, pad) < 0)
 		return -1;
 
 	return 0;
diff --git a/src/io_gunzip.c b/src/io_gunzip.c
index 96c66d2b..4ad0b6c9 100644
--- a/src/io_gunzip.c
+++ b/src/io_gunzip.c
@@ -176,7 +176,7 @@ struct apk_gzip_ostream {
 	z_stream zs;
 };
 
-static ssize_t gzo_write(struct apk_ostream *os, const void *ptr, size_t size)
+static int gzo_write(struct apk_ostream *os, const void *ptr, size_t size)
 {
 	struct apk_gzip_ostream *gos = container_of(os, struct apk_gzip_ostream, os);
 	unsigned char buffer[1024];
@@ -189,16 +189,15 @@ static ssize_t gzo_write(struct apk_ostream *os, const void *ptr, size_t size)
 		gos->zs.next_out = buffer;
 		r = deflate(&gos->zs, Z_NO_FLUSH);
 		if (r == Z_STREAM_ERROR)
-			return -EIO;
+			return apk_ostream_cancel(gos->output, -EIO);
 		have = sizeof(buffer) - gos->zs.avail_out;
 		if (have != 0) {
 			r = apk_ostream_write(gos->output, buffer, have);
-			if (r != have)
-				return -EIO;
+			if (r < 0) return r;
 		}
 	}
 
-	return size;
+	return 0;
 }
 
 static int gzo_close(struct apk_ostream *os)
@@ -206,24 +205,21 @@ static int gzo_close(struct apk_ostream *os)
 	struct apk_gzip_ostream *gos = container_of(os, struct apk_gzip_ostream, os);
 	unsigned char buffer[1024];
 	size_t have;
-	int r, rc = 0;
+	int r, rc = os->rc;
 
 	do {
 		gos->zs.avail_out = sizeof(buffer);
 		gos->zs.next_out = buffer;
 		r = deflate(&gos->zs, Z_FINISH);
 		have = sizeof(buffer) - gos->zs.avail_out;
-		if (apk_ostream_write(gos->output, buffer, have) != have)
-			rc = -EIO;
+		if (apk_ostream_write(gos->output, buffer, have) < 0)
+			break;
 	} while (r == Z_OK);
 	r = apk_ostream_close(gos->output);
-	if (r != 0)
-		rc = r;
-
 	deflateEnd(&gos->zs);
 	free(gos);
 
-	return rc;
+	return rc ?: r;
 }
 
 static const struct apk_ostream_ops gzip_ostream_ops = {
diff --git a/src/package.c b/src/package.c
index 542edfd8..dee15eb1 100644
--- a/src/package.c
+++ b/src/package.c
@@ -439,7 +439,7 @@ int apk_deps_write(struct apk_database *db, struct apk_dependency_array *deps, s
 
 		blob = apk_blob_pushed(APK_BLOB_BUF(tmp), blob);
 		if (APK_BLOB_IS_NULL(blob) || 
-		    apk_ostream_write(os, blob.ptr, blob.len) != blob.len)
+		    apk_ostream_write(os, blob.ptr, blob.len) < 0)
 			return -1;
 
 		n += blob.len;
@@ -1086,9 +1086,9 @@ static int write_depends(struct apk_ostream *os, const char *field,
 	int r;
 
 	if (deps->num == 0) return 0;
-	if (apk_ostream_write(os, field, 2) != 2) return -1;
+	if (apk_ostream_write(os, field, 2) < 0) return -1;
 	if ((r = apk_deps_write(NULL, deps, os, APK_BLOB_PTR_LEN(" ", 1))) < 0) return r;
-	if (apk_ostream_write(os, "\n", 1) != 1) return -1;
+	if (apk_ostream_write(os, "\n", 1) < 0) return -1;
 	return 0;
 }
 
@@ -1144,7 +1144,7 @@ int apk_pkg_write_index_entry(struct apk_package *info,
 		return apk_ostream_cancel(os, -ENOBUFS);
 
 	bbuf = apk_blob_pushed(APK_BLOB_BUF(buf), bbuf);
-	if (apk_ostream_write(os, bbuf.ptr, bbuf.len) != bbuf.len ||
+	if (apk_ostream_write(os, bbuf.ptr, bbuf.len) ||
 	    write_depends(os, "D:", info->depends) ||
 	    write_depends(os, "p:", info->provides) ||
 	    write_depends(os, "i:", info->install_if))
-- 
GitLab