aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfshelper/data_reader.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqfshelper/data_reader.c')
-rw-r--r--lib/sqfshelper/data_reader.c374
1 files changed, 0 insertions, 374 deletions
diff --git a/lib/sqfshelper/data_reader.c b/lib/sqfshelper/data_reader.c
deleted file mode 100644
index bf808ba..0000000
--- a/lib/sqfshelper/data_reader.c
+++ /dev/null
@@ -1,374 +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 "sqfs/block_processor.h"
-#include "sqfs/error.h"
-
-#include "data_reader.h"
-#include "highlevel.h"
-#include "util.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-struct sqfs_data_reader_t {
- sqfs_fragment_t *frag;
- sqfs_compressor_t *cmp;
- sqfs_block_t *data_block;
- sqfs_block_t *frag_block;
-
- uint64_t current_block;
-
- sqfs_file_t *file;
-
- uint32_t num_fragments;
- uint32_t current_frag_index;
- uint32_t block_size;
-
- uint8_t scratch[];
-};
-
-static int get_block(sqfs_data_reader_t *data, uint64_t off, uint32_t size,
- size_t unpacked_size, sqfs_block_t **out)
-{
- sqfs_block_t *blk = alloc_flex(sizeof(*blk), 1, unpacked_size);
- size_t on_disk_size;
- ssize_t ret;
- int err;
-
- if (blk == NULL)
- return SQFS_ERROR_ALLOC;
-
- blk->size = unpacked_size;
-
- if (SQFS_IS_SPARSE_BLOCK(size)) {
- *out = blk;
- return 0;
- }
-
- on_disk_size = SQFS_ON_DISK_BLOCK_SIZE(size);
-
- if (on_disk_size > unpacked_size)
- return SQFS_ERROR_OVERFLOW;
-
- if (SQFS_IS_BLOCK_COMPRESSED(size)) {
- err = data->file->read_at(data->file, off,
- data->scratch, on_disk_size);
- if (err) {
- free(blk);
- return err;
- }
-
- ret = data->cmp->do_block(data->cmp, data->scratch,
- on_disk_size, blk->data, blk->size);
- if (ret <= 0)
- err = ret < 0 ? ret : SQFS_ERROR_OVERFLOW;
- } else {
- err = data->file->read_at(data->file, off,
- blk->data, on_disk_size);
- }
-
- if (err) {
- free(blk);
- return err;
- }
-
- *out = blk;
- return 0;
-}
-
-static int precache_data_block(sqfs_data_reader_t *data, uint64_t location,
- uint32_t size)
-{
- int ret;
-
- if (data->data_block != NULL && data->current_block == location)
- return 0;
-
- free(data->data_block);
-
- ret = get_block(data, location, size, data->block_size,
- &data->data_block);
-
- if (ret < 0) {
- data->data_block = NULL;
- return -1;
- }
-
- data->current_block = location;
- return 0;
-}
-
-static int precache_fragment_block(sqfs_data_reader_t *data, size_t idx)
-{
- int ret;
-
- if (data->frag_block != NULL && idx == data->current_frag_index)
- return 0;
-
- if (idx >= data->num_fragments) {
- fputs("fragment index out of bounds\n", stderr);
- return -1;
- }
-
- free(data->frag_block);
-
- ret = get_block(data, data->frag[idx].start_offset,
- data->frag[idx].size, data->block_size,
- &data->frag_block);
- if (ret < 0)
- return -1;
-
- data->current_frag_index = idx;
- return 0;
-}
-
-sqfs_data_reader_t *sqfs_data_reader_create(sqfs_file_t *file,
- size_t block_size,
- sqfs_compressor_t *cmp)
-{
- sqfs_data_reader_t *data = alloc_flex(sizeof(*data), 1, block_size);
-
- if (data != NULL) {
- data->file = file;
- data->block_size = block_size;
- data->cmp = cmp;
- }
-
- return data;
-}
-
-int sqfs_data_reader_load_fragment_table(sqfs_data_reader_t *data,
- const sqfs_super_t *super)
-{
- void *raw_frag;
- size_t size;
- uint32_t i;
- int ret;
-
- free(data->frag_block);
- free(data->frag);
-
- data->frag = NULL;
- data->frag_block = NULL;
- data->num_fragments = 0;
- data->current_frag_index = 0;
-
- if (super->fragment_entry_count == 0 ||
- (super->flags & SQFS_FLAG_NO_FRAGMENTS) != 0) {
- return 0;
- }
-
- if (super->fragment_table_start >= super->bytes_used)
- return SQFS_ERROR_OUT_OF_BOUNDS;
-
- if (SZ_MUL_OV(sizeof(data->frag[0]), super->fragment_entry_count,
- &size)) {
- return SQFS_ERROR_OVERFLOW;
- }
-
- ret = sqfs_read_table(data->file, data->cmp, size,
- super->fragment_table_start,
- super->directory_table_start,
- super->fragment_table_start, &raw_frag);
- if (ret)
- return ret;
-
- data->num_fragments = super->fragment_entry_count;
- data->current_frag_index = super->fragment_entry_count;
- data->frag = raw_frag;
-
- 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 0;
-}
-
-void sqfs_data_reader_destroy(sqfs_data_reader_t *data)
-{
- free(data->data_block);
- free(data->frag_block);
- free(data->frag);
- free(data);
-}
-
-int sqfs_data_reader_get_block(sqfs_data_reader_t *data,
- const sqfs_inode_generic_t *inode,
- size_t index, sqfs_block_t **out)
-{
- size_t i, unpacked_size;
- uint64_t off, filesz;
-
- if (inode->base.type == SQFS_INODE_FILE) {
- off = inode->data.file.blocks_start;
- filesz = inode->data.file.file_size;
- } else if (inode->base.type == SQFS_INODE_EXT_FILE) {
- off = inode->data.file_ext.blocks_start;
- filesz = inode->data.file_ext.file_size;
- } else {
- return SQFS_ERROR_NOT_FILE;
- }
-
- if (index >= inode->num_file_blocks)
- return SQFS_ERROR_OUT_OF_BOUNDS;
-
- for (i = 0; i < index; ++i) {
- off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i]);
- filesz -= data->block_size;
- }
-
- unpacked_size = filesz < data->block_size ? filesz : data->block_size;
-
- return get_block(data, off, inode->block_sizes[index],
- unpacked_size, out);
-}
-
-int sqfs_data_reader_get_fragment(sqfs_data_reader_t *data,
- const sqfs_inode_generic_t *inode,
- sqfs_block_t **out)
-{
- uint32_t frag_idx, frag_off, frag_sz;
- sqfs_block_t *blk;
- uint64_t filesz;
-
- if (inode->base.type == SQFS_INODE_EXT_FILE) {
- filesz = inode->data.file_ext.file_size;
- frag_idx = inode->data.file_ext.fragment_idx;
- frag_off = inode->data.file_ext.fragment_offset;
- } else if (inode->base.type == SQFS_INODE_FILE) {
- filesz = inode->data.file.file_size;
- frag_idx = inode->data.file.fragment_index;
- frag_off = inode->data.file.fragment_offset;
- } else {
- return -1;
- }
-
- if (inode->num_file_blocks * data->block_size >= filesz) {
- *out = NULL;
- return 0;
- }
-
- frag_sz = filesz % data->block_size;
-
- if (precache_fragment_block(data, frag_idx))
- return -1;
-
- if (frag_off + frag_sz > data->block_size)
- return -1;
-
- blk = alloc_flex(sizeof(*blk), 1, frag_sz);
- if (blk == NULL)
- return -1;
-
- blk->size = frag_sz;
- memcpy(blk->data, (char *)data->frag_block->data + frag_off, frag_sz);
-
- *out = blk;
- return 0;
-}
-
-ssize_t sqfs_data_reader_read(sqfs_data_reader_t *data,
- const sqfs_inode_generic_t *inode,
- uint64_t offset, void *buffer, size_t size)
-{
- uint32_t frag_idx, frag_off;
- size_t i, diff, total = 0;
- uint64_t off, filesz;
- char *ptr;
-
- /* work out file location and size */
- if (inode->base.type == SQFS_INODE_EXT_FILE) {
- off = inode->data.file_ext.blocks_start;
- filesz = inode->data.file_ext.file_size;
- frag_idx = inode->data.file_ext.fragment_idx;
- frag_off = inode->data.file_ext.fragment_offset;
- } else {
- off = inode->data.file.blocks_start;
- filesz = inode->data.file.file_size;
- frag_idx = inode->data.file.fragment_index;
- frag_off = inode->data.file.fragment_offset;
- }
-
- /* find location of the first block */
- i = 0;
-
- while (offset > data->block_size && i < inode->num_file_blocks) {
- off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i++]);
- offset -= data->block_size;
-
- if (filesz >= data->block_size) {
- filesz -= data->block_size;
- } else {
- filesz = 0;
- }
- }
-
- /* copy data from blocks */
- while (i < inode->num_file_blocks && size > 0 && filesz > 0) {
- diff = data->block_size - offset;
- if (size < diff)
- diff = size;
-
- if (SQFS_IS_SPARSE_BLOCK(inode->block_sizes[i])) {
- memset(buffer, 0, diff);
- } else {
- if (precache_data_block(data, off,
- inode->block_sizes[i])) {
- return -1;
- }
-
- memcpy(buffer, (char *)data->data_block->data + offset,
- diff);
- off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i]);
- }
-
- if (filesz >= data->block_size) {
- filesz -= data->block_size;
- } else {
- filesz = 0;
- }
-
- ++i;
- offset = 0;
- size -= diff;
- total += diff;
- buffer = (char *)buffer + diff;
- }
-
- /* copy from fragment */
- if (i == inode->num_file_blocks && size > 0 && filesz > 0) {
- if (precache_fragment_block(data, frag_idx))
- return -1;
-
- if (frag_off + filesz > data->block_size)
- goto fail_range;
-
- if (offset >= filesz)
- return total;
-
- if (offset + size > filesz)
- size = filesz - offset;
-
- if (size == 0)
- return total;
-
- ptr = (char *)data->frag_block->data + frag_off + offset;
- memcpy(buffer, ptr, size);
- total += size;
- }
-
- return total;
-fail_range:
- fputs("attempted to read past fragment block limits\n", stderr);
- return -1;
-}