From 897a625cacdd9201f9f2531f5ce97c4ab5e5d90a Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Fri, 25 Sep 2020 18:25:33 +0200 Subject: libfstream: Rework unix sparse file writing Instead of immediately seeking forward, record the sparse bytes "written" and then do the seek the next time we write data, or do an ftruncate if we do a sync. Signed-off-by: David Oberhollenzer --- lib/fstream/unix/ostream.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/fstream/unix/ostream.c b/lib/fstream/unix/ostream.c index dac675f..84a5725 100644 --- a/lib/fstream/unix/ostream.c +++ b/lib/fstream/unix/ostream.c @@ -10,6 +10,9 @@ typedef struct { ostream_t base; char *path; int fd; + + off_t sparse_count; + off_t size; } file_ostream_t; static int file_append(ostream_t *strm, const void *data, size_t size) @@ -17,6 +20,16 @@ static int file_append(ostream_t *strm, const void *data, size_t size) file_ostream_t *file = (file_ostream_t *)strm; ssize_t ret; + if (size == 0) + return 0; + + if (file->sparse_count > 0) { + if (lseek(file->fd, file->sparse_count, SEEK_CUR) == (off_t)-1) + goto fail_errno; + + file->sparse_count = 0; + } + while (size > 0) { ret = write(file->fd, data, size); @@ -29,27 +42,26 @@ static int file_append(ostream_t *strm, const void *data, size_t size) if (ret < 0) { if (errno == EINTR) continue; - - perror(file->path); - return -1; + goto fail_errno; } + file->size += ret; size -= ret; data = (const char *)data + ret; } return 0; +fail_errno: + perror(file->path); + return -1; } static int file_append_sparse(ostream_t *strm, size_t size) { file_ostream_t *file = (file_ostream_t *)strm; - if (lseek(file->fd, size, SEEK_CUR) == (off_t)-1) { - perror(file->path); - return -1; - } - + file->sparse_count += size; + file->size += size; return 0; } @@ -57,12 +69,18 @@ static int file_flush(ostream_t *strm) { file_ostream_t *file = (file_ostream_t *)strm; - if (fsync(file->fd) != 0) { - perror(file->path); - return -1; + if (file->sparse_count > 0) { + if (ftruncate(file->fd, file->size) != 0) + goto fail; } + if (fsync(file->fd) != 0) + goto fail; + return 0; +fail: + perror(file->path); + return -1; } static void file_destroy(sqfs_object_t *obj) -- cgit v1.2.3