diff options
Diffstat (limited to 'lib/sqfs/data_reader.c')
-rw-r--r-- | lib/sqfs/data_reader.c | 314 |
1 files changed, 0 insertions, 314 deletions
diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c deleted file mode 100644 index 4ad6266..0000000 --- a/lib/sqfs/data_reader.c +++ /dev/null @@ -1,314 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * data_reader.c - * - * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> - */ -#include "config.h" - -#include "data_reader.h" -#include "highlevel.h" -#include "util.h" - -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> - -struct data_reader_t { - sqfs_fragment_t *frag; - size_t num_fragments; - size_t current_frag_index; - size_t frag_used; - - off_t current_block; - - compressor_t *cmp; - size_t block_size; - int sqfsfd; - - void *block; - void *scratch; - void *frag_block; -}; - -static ssize_t read_block(data_reader_t *data, off_t offset, uint32_t size, - void *dst) -{ - bool compressed = SQFS_IS_BLOCK_COMPRESSED(size); - void *ptr = compressed ? data->scratch : dst; - ssize_t ret; - - size = SQFS_ON_DISK_BLOCK_SIZE(size); - - if (size > data->block_size) - goto fail_bs; - - if (read_data_at("reading block", offset, data->sqfsfd, ptr, size)) - return -1; - - if (compressed) { - ret = data->cmp->do_block(data->cmp, data->scratch, size, - dst, data->block_size); - if (ret <= 0) { - fputs("extracting block failed\n", stderr); - return -1; - } - size = ret; - } - - return size; -fail_bs: - fputs("found compressed block larger than block size\n", stderr); - return -1; -} - -static int precache_data_block(data_reader_t *data, off_t location, - uint32_t size) -{ - ssize_t ret; - - if (data->current_block == location) - return 0; - - ret = read_block(data, location, size, data->block); - if (ret < 0) - return -1; - - if ((size_t)ret < data->block_size) - memset((char *)data->block + ret, 0, data->block_size - ret); - - data->current_block = location; - return 0; -} - -static int precache_fragment_block(data_reader_t *data, size_t idx) -{ - ssize_t ret; - - if (idx == data->current_frag_index) - return 0; - - if (idx >= data->num_fragments) { - fputs("fragment index out of bounds\n", stderr); - return -1; - } - - ret = read_block(data, data->frag[idx].start_offset, - data->frag[idx].size, data->frag_block); - if (ret < 0) - return -1; - - data->current_frag_index = idx; - data->frag_used = ret; - return 0; -} - -data_reader_t *data_reader_create(int fd, sqfs_super_t *super, - compressor_t *cmp) -{ - data_reader_t *data = alloc_flex(sizeof(*data), super->block_size, 3); - size_t i, size; - - if (data == NULL) { - perror("creating data reader"); - return data; - } - - data->num_fragments = super->fragment_entry_count; - data->current_frag_index = super->fragment_entry_count; - data->block = (char *)data + sizeof(*data); - data->scratch = (char *)data->block + super->block_size; - data->frag_block = (char *)data->scratch + super->block_size; - data->current_block = -1; - data->sqfsfd = fd; - data->block_size = super->block_size; - data->cmp = cmp; - - if (super->fragment_entry_count == 0 || - (super->flags & SQFS_FLAG_NO_FRAGMENTS) != 0) { - return data; - } - - if (super->fragment_table_start >= super->bytes_used) { - fputs("Fragment table start is past end of file\n", stderr); - free(data); - return NULL; - } - - if (SZ_MUL_OV(sizeof(data->frag[0]), data->num_fragments, &size)) { - fputs("Too many fragments: overflow\n", stderr); - free(data); - return NULL; - } - - data->frag = sqfs_read_table(fd, cmp, size, - super->fragment_table_start, - super->directory_table_start, - super->fragment_table_start); - if (data->frag == NULL) { - free(data); - return NULL; - } - - for (i = 0; i < data->num_fragments; ++i) { - data->frag[i].size = le32toh(data->frag[i].size); - data->frag[i].start_offset = - le64toh(data->frag[i].start_offset); - } - - return data; -} - -void data_reader_destroy(data_reader_t *data) -{ - free(data->frag); - free(data); -} - -int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd, - bool allow_sparse) -{ - uint64_t filesz = fi->size; - size_t fragsz = fi->size % data->block_size; - size_t count = fi->size / data->block_size; - off_t off = fi->startblock; - size_t i, diff; - - if (fragsz != 0 && !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) { - fragsz = 0; - ++count; - } - - if (allow_sparse && ftruncate(outfd, filesz)) - goto fail_sparse; - - for (i = 0; i < count; ++i) { - diff = filesz > data->block_size ? data->block_size : filesz; - filesz -= diff; - - if (SQFS_IS_SPARSE_BLOCK(fi->blocks[i].size)) { - if (allow_sparse) { - if (lseek(outfd, diff, SEEK_CUR) == (off_t)-1) - goto fail_sparse; - continue; - } - memset(data->block, 0, diff); - } else { - if (precache_data_block(data, off, fi->blocks[i].size)) - return -1; - off += SQFS_ON_DISK_BLOCK_SIZE(fi->blocks[i].size); - } - - if (write_data("writing uncompressed block", - outfd, data->block, diff)) { - return -1; - } - } - - if (fragsz > 0) { - if (precache_fragment_block(data, fi->fragment)) - return -1; - - if (fi->fragment_offset >= data->frag_used) - goto fail_range; - - if ((fi->fragment_offset + fragsz - 1) >= data->frag_used) - goto fail_range; - - if (write_data("writing uncompressed fragment", outfd, - (char *)data->frag_block + fi->fragment_offset, - fragsz)) { - return -1; - } - } - - return 0; -fail_range: - fputs("attempted to read past fragment block limits\n", stderr); - return -1; -fail_sparse: - perror("creating sparse output file"); - return -1; -} - -ssize_t data_reader_read(data_reader_t *data, file_info_t *fi, - uint64_t offset, void *buffer, size_t size) -{ - size_t i, diff, fragsz, count, total = 0; - off_t off; - char *ptr; - - /* work out block count and fragment size */ - fragsz = fi->size % data->block_size; - count = fi->size / data->block_size; - - if (fragsz != 0 && !(fi->flags & FILE_FLAG_HAS_FRAGMENT)) { - fragsz = 0; - ++count; - } - - /* work out block index and on-disk location */ - off = fi->startblock; - i = 0; - - while (offset > data->block_size && i < count) { - off += SQFS_ON_DISK_BLOCK_SIZE(fi->blocks[i++].size); - offset -= data->block_size; - } - - /* copy data from blocks */ - while (i < count && size > 0) { - diff = data->block_size - offset; - if (size < diff) - size = diff; - - if (SQFS_IS_SPARSE_BLOCK(fi->blocks[i].size)) { - memset(buffer, 0, diff); - } else { - if (precache_data_block(data, off, fi->blocks[i].size)) - return -1; - - memcpy(buffer, (char *)data->block + offset, diff); - off += SQFS_ON_DISK_BLOCK_SIZE(fi->blocks[i].size); - } - - ++i; - offset = 0; - size -= diff; - total += diff; - buffer = (char *)buffer + diff; - } - - /* copy from fragment */ - if (i == count && size > 0 && fragsz > 0) { - if (precache_fragment_block(data, fi->fragment)) - return -1; - - if (fi->fragment_offset >= data->frag_used) - goto fail_range; - - if ((fi->fragment_offset + fragsz - 1) >= data->frag_used) - goto fail_range; - - ptr = (char *)data->frag_block + fi->fragment_offset; - ptr += offset; - - if (offset >= fragsz) { - offset = 0; - size = 0; - } - - if (offset + size > fragsz) - size = fragsz - offset; - - if (size > 0) { - memcpy(buffer, ptr + offset, size); - total += size; - } - } - return total; -fail_range: - fputs("attempted to read past fragment block limits\n", stderr); - return -1; -} |