summaryrefslogtreecommitdiff
path: root/src/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c39
1 files changed, 35 insertions, 4 deletions
diff --git a/src/io.c b/src/io.c
index 09b5212..81ed289 100644
--- a/src/io.c
+++ b/src/io.c
@@ -399,16 +399,16 @@ struct apk_istream *apk_istream_from_file_gz(const char *file)
struct apk_fd_ostream {
struct apk_ostream os;
int fd;
+ size_t bytes;
+ char buffer[1024];
};
-static size_t fdo_write(void *stream, const void *ptr, size_t size)
+static size_t safe_write(int fd, const void *ptr, size_t size)
{
- struct apk_fd_ostream *fos =
- container_of(stream, struct apk_fd_ostream, os);
size_t i = 0, r;
while (i < size) {
- r = write(fos->fd, ptr + i, size - i);
+ r = write(fd, ptr + i, size - i);
if (r < 0)
return r;
if (r == 0)
@@ -419,11 +419,42 @@ static size_t fdo_write(void *stream, const void *ptr, size_t size)
return i;
}
+static int fdo_flush(struct apk_fd_ostream *fos)
+{
+ if (fos->bytes == 0)
+ return 0;
+
+ if (safe_write(fos->fd, fos->buffer, fos->bytes) != fos->bytes)
+ return -1;
+
+ fos->bytes = 0;
+ return 0;
+}
+
+static size_t fdo_write(void *stream, const void *ptr, size_t size)
+{
+ struct apk_fd_ostream *fos =
+ container_of(stream, struct apk_fd_ostream, os);
+
+ if (size + fos->bytes >= sizeof(fos->buffer)) {
+ if (fdo_flush(fos))
+ return -1;
+ if (size >= sizeof(fos->buffer) / 2)
+ return safe_write(fos->fd, ptr, size);
+ }
+
+ memcpy(&fos->buffer[fos->bytes], ptr, size);
+ fos->bytes += size;
+
+ return size;
+}
+
static void fdo_close(void *stream)
{
struct apk_fd_ostream *fos =
container_of(stream, struct apk_fd_ostream, os);
+ fdo_flush(fos);
close(fos->fd);
free(fos);
}