summaryrefslogtreecommitdiff
path: root/lib/sqfshelper/io_stdin.c
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-09-25 17:47:19 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-09-25 17:47:19 +0200
commit3511b1fa7c6f71c579e161951e945904e552e1d9 (patch)
tree55fa94e5daef7bcc8e4b650f27d05af49fd1b02d /lib/sqfshelper/io_stdin.c
parent4d79f55f4a626a3cfd8bd18673aa29b48b16e137 (diff)
Remove condensed sparse file handling from libsquashfs
This only exists for tar2sqfs. Move the sparse file map to libtar and add the ability to do this into the stind sqfs_file_t abstraction, so it acts like a normal file but internally stitches the data together from the sparse implementation. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfshelper/io_stdin.c')
-rw-r--r--lib/sqfshelper/io_stdin.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/lib/sqfshelper/io_stdin.c b/lib/sqfshelper/io_stdin.c
index 6cb45d4..8568f5e 100644
--- a/lib/sqfshelper/io_stdin.c
+++ b/lib/sqfshelper/io_stdin.c
@@ -11,12 +11,14 @@
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <errno.h>
typedef struct {
sqfs_file_t base;
+ const sparse_map_t *map;
uint64_t offset;
uint64_t size;
} sqfs_file_stdin_t;
@@ -78,6 +80,60 @@ static int stdin_read_at(sqfs_file_t *base, uint64_t offset,
return 0;
}
+static int stdin_read_condensed(sqfs_file_t *base, uint64_t offset,
+ void *buffer, size_t size)
+{
+ sqfs_file_stdin_t *file = (sqfs_file_stdin_t *)base;
+ uint64_t poffset = 0, src_start;
+ size_t dst_start, diff, count;
+ const sparse_map_t *it;
+ int err;
+
+ memset(buffer, 0, size);
+
+ for (it = file->map; it != NULL; it = it->next) {
+ if (it->offset + it->count <= offset) {
+ poffset += it->count;
+ continue;
+ }
+
+ if (it->offset >= offset + size) {
+ poffset += it->count;
+ continue;
+ }
+
+ count = size;
+
+ if (offset + count >= it->offset + it->count)
+ count = it->offset + it->count - offset;
+
+ if (it->offset < offset) {
+ diff = offset - it->offset;
+
+ src_start = poffset + diff;
+ dst_start = 0;
+ count -= diff;
+ } else if (it->offset > offset) {
+ diff = it->offset - offset;
+
+ src_start = poffset;
+ dst_start = diff;
+ } else {
+ src_start = poffset;
+ dst_start = 0;
+ }
+
+ err = stdin_read_at(base, src_start,
+ (char *)buffer + dst_start, count);
+ if (err)
+ return err;
+
+ poffset += it->count;
+ }
+
+ return 0;
+}
+
static int stdin_write_at(sqfs_file_t *base, uint64_t offset,
const void *buffer, size_t size)
{
@@ -96,7 +152,7 @@ static int stdin_truncate(sqfs_file_t *base, uint64_t size)
return SQFS_ERROR_IO;
}
-sqfs_file_t *sqfs_get_stdin_file(uint64_t size)
+sqfs_file_t *sqfs_get_stdin_file(const sparse_map_t *map, uint64_t size)
{
sqfs_file_stdin_t *file = calloc(1, sizeof(*file));
sqfs_file_t *base = (sqfs_file_t *)file;
@@ -105,10 +161,17 @@ sqfs_file_t *sqfs_get_stdin_file(uint64_t size)
return NULL;
file->size = size;
+ file->map = map;
+
base->destroy = stdin_destroy;
- base->read_at = stdin_read_at;
base->write_at = stdin_write_at;
base->get_size = stdin_get_size;
base->truncate = stdin_truncate;
+
+ if (map == NULL) {
+ base->read_at = stdin_read_at;
+ } else {
+ base->read_at = stdin_read_condensed;
+ }
return base;
}