diff options
Diffstat (limited to 'lib/sqfshelper/io_stdin.c')
-rw-r--r-- | lib/sqfshelper/io_stdin.c | 67 |
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; } |