diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-05-01 16:11:16 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-05-02 12:40:06 +0200 |
commit | 6ba88daae14e64009619562209060532eb6eadbb (patch) | |
tree | 2c21d168a4561756c7ce7129b2769ec5342f9f23 | |
parent | 4da96898487f0f4aca1dfc7afc355aa90065308a (diff) |
Add meta data reader implementation
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r-- | include/meta_reader.h | 26 | ||||
-rw-r--r-- | lib/Makemodule.am | 3 | ||||
-rw-r--r-- | lib/sqfs/meta_reader.c | 123 |
3 files changed, 151 insertions, 1 deletions
diff --git a/include/meta_reader.h b/include/meta_reader.h new file mode 100644 index 0000000..4c03996 --- /dev/null +++ b/include/meta_reader.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#ifndef META_READER_H +#define META_READER_H + +#include "compress.h" +#include "squashfs.h" + +typedef struct { + uint64_t block_offset; + uint64_t next_block; + size_t offset; + int fd; + compressor_t *cmp; + uint8_t data[SQFS_META_BLOCK_SIZE]; +} meta_reader_t; + +meta_reader_t *meta_reader_create(int fd, compressor_t *cmp); + +void meta_reader_destroy(meta_reader_t *m); + +int meta_reader_seek(meta_reader_t *m, uint64_t block_start, + size_t offset); + +int meta_reader_read(meta_reader_t *m, void *data, size_t size); + +#endif /* META_READER_H */ diff --git a/lib/Makemodule.am b/lib/Makemodule.am index 026e3f1..5cadf58 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -11,7 +11,8 @@ libsquashfs_a_SOURCES = include/meta_writer.h include/squashfs.h libsquashfs_a_SOURCES += lib/sqfs/meta_writer.c lib/sqfs/super.c libsquashfs_a_SOURCES += lib/sqfs/id_table.c include/id_table.h libsquashfs_a_SOURCES += lib/sqfs/table.c include/table.h -libsquashfs_a_SOURCES += lib/sqfs/read_super.c +libsquashfs_a_SOURCES += lib/sqfs/read_super.c lib/sqfs/meta_reader.c +libsquashfs_a_SOURCES += include/meta_reader.h libutil_a_SOURCES = lib/util/canonicalize_name.c lib/util/write_retry.c libutil_a_SOURCES += lib/util/read_retry.c include/util.h diff --git a/lib/sqfs/meta_reader.c b/lib/sqfs/meta_reader.c new file mode 100644 index 0000000..8cd7c8f --- /dev/null +++ b/lib/sqfs/meta_reader.c @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include "meta_reader.h" +#include "util.h" + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +meta_reader_t *meta_reader_create(int fd, compressor_t *cmp) +{ + meta_reader_t *m = calloc(1, sizeof(*m)); + + if (m == NULL) { + perror("creating meta data reader"); + return NULL; + } + + m->fd = fd; + m->cmp = cmp; + return m; +} + +void meta_reader_destroy(meta_reader_t *m) +{ + free(m); +} + +int meta_reader_seek(meta_reader_t *m, uint64_t block_start, size_t offset) +{ + bool compressed; + uint16_t header; + ssize_t ret; + size_t size; + + if (offset >= sizeof(m->data)) { + fputs("Tried to seek past end of meta data block.\n", stderr); + return -1; + } + + if (block_start == m->block_offset) { + m->offset = offset; + return 0; + } + + if (lseek(m->fd, block_start, SEEK_SET) == (off_t)-1) { + perror("seek on image file"); + return -1; + } + + ret = read_retry(m->fd, &header, 2); + if (ret < 0) + goto fail_rd; + + if ((size_t)ret < 2) + goto fail_trunc; + + header = le16toh(header); + compressed = (header & 0x8000) == 0; + size = header & 0x7FFF; + + if (size > sizeof(m->data)) { + fputs("found meta data block larger than maximum size\n", + stderr); + return -1; + } + + m->block_offset = block_start; + m->offset = offset; + m->next_block = block_start + size + 2; + + memset(m->data, 0, sizeof(m->data)); + + ret = read_retry(m->fd, m->data, size); + if (ret < 0) + goto fail_rd; + + if ((size_t)ret < size) + goto fail_trunc; + + if (compressed) { + ret = m->cmp->do_block(m->cmp, m->data, size); + + if (ret <= 0) { + fputs("error uncompressing meta data block\n", stderr); + return -1; + } + } + + return 0; +fail_trunc: + fputs("reading meta data: unexpected end of file\n", stderr); + return -1; +fail_rd: + perror("reading meta data"); + return -1; +} + +int meta_reader_read(meta_reader_t *m, void *data, size_t size) +{ + size_t diff; + + while (size != 0) { + diff = sizeof(m->data) - m->offset; + + if (diff == 0) { + if (meta_reader_seek(m, m->next_block, 0)) + return -1; + diff = sizeof(m->data); + } + + if (diff > size) + diff = size; + + memcpy(data, m->data + m->offset, diff); + + m->offset += diff; + data = (char *)data + diff; + size -= diff; + } + + return 0; +} |