summaryrefslogtreecommitdiff
path: root/lib/sqfs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqfs')
-rw-r--r--lib/sqfs/data_reader.c136
-rw-r--r--lib/sqfs/frag_reader.c134
2 files changed, 98 insertions, 172 deletions
diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c
index 196da32..0e2e7ac 100644
--- a/lib/sqfs/data_reader.c
+++ b/lib/sqfs/data_reader.c
@@ -2,7 +2,7 @@
#include "config.h"
#include "data_reader.h"
-#include "frag_reader.h"
+#include "highlevel.h"
#include "util.h"
#include <stdlib.h>
@@ -11,53 +11,72 @@
#include <stdio.h>
struct data_reader_t {
+ sqfs_fragment_t *frag;
+ size_t num_fragments;
+ size_t current_frag_index;
+ size_t frag_used;
+
compressor_t *cmp;
size_t block_size;
- frag_reader_t *frag;
int sqfsfd;
void *buffer;
void *scratch;
+ void *frag_block;
};
data_reader_t *data_reader_create(int fd, sqfs_super_t *super,
compressor_t *cmp)
{
- data_reader_t *data = calloc(1, sizeof(*data) + 2 * super->block_size);
+ data_reader_t *data = calloc(1, sizeof(*data) + 3 * super->block_size);
+ size_t i, size;
if (data == NULL) {
perror("creating data reader");
return data;
}
- if (super->fragment_entry_count > 0 &&
- !(super->flags & SQFS_FLAG_NO_FRAGMENTS)) {
- if (super->fragment_table_start >= super->bytes_used) {
- fputs("Fragment table start is past end of file\n",
- stderr);
- free(data);
- return NULL;
- }
-
- data->frag = frag_reader_create(super, fd, cmp);
- if (data->frag == NULL) {
- free(data);
- return NULL;
- }
- }
-
+ data->num_fragments = super->fragment_entry_count;
+ data->current_frag_index = super->fragment_entry_count;
data->buffer = (char *)data + sizeof(*data);
data->scratch = (char *)data->buffer + super->block_size;
+ data->frag_block = (char *)data->scratch + super->block_size;
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 0;
+ }
+
+ if (super->fragment_table_start >= super->bytes_used) {
+ fputs("Fragment table start is past end of file\n", stderr);
+ free(data);
+ return NULL;
+ }
+
+ size = sizeof(data->frag[0]) * data->num_fragments;
+
+ data->frag = sqfs_read_table(fd, cmp, size,
+ 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)
{
- if (data->frag != NULL)
- frag_reader_destroy(data->frag);
+ free(data->frag);
free(data);
}
@@ -134,6 +153,52 @@ fail_bs:
return -1;
}
+static int precache_fragment_block(data_reader_t *data, size_t idx)
+{
+ bool compressed;
+ size_t size;
+ 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;
+ }
+
+ compressed = (data->frag[idx].size & (1 << 24)) == 0;
+ size = data->frag[idx].size & ((1 << 24) - 1);
+
+ if (size > data->block_size) {
+ fputs("found fragment block larger than block size\n", stderr);
+ return -1;
+ }
+
+ if (read_data_at("reading fragments", data->frag[idx].start_offset,
+ data->sqfsfd, data->buffer, size)) {
+ return -1;
+ }
+
+ if (compressed) {
+ ret = data->cmp->do_block(data->cmp, data->buffer, size,
+ data->frag_block, data->block_size);
+
+ if (ret <= 0) {
+ fputs("extracting fragment block failed\n", stderr);
+ return -1;
+ }
+
+ size = ret;
+ } else {
+ memcpy(data->frag_block, data->buffer, size);
+ }
+
+ data->current_frag_index = idx;
+ data->frag_used = size;
+ return 0;
+}
+
int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
bool allow_sparse)
{
@@ -150,29 +215,24 @@ int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
return -1;
if (fragsz > 0) {
- if (data->frag == NULL)
- goto fail_frag;
-
- if (frag_reader_read(data->frag, fi->fragment,
- fi->fragment_offset, data->buffer,
- fragsz)) {
+ if (precache_fragment_block(data, fi->fragment))
return -1;
- }
- if (write_data("writing uncompressed fragment",
- outfd, data->buffer, fragsz)) {
+ 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_frag:
- fputs("file not a multiple of block size but no fragments available\n",
- stderr);
+fail_range:
+ fputs("attempted to read past fragment block limits\n", stderr);
return -1;
}
-
-const frag_reader_t *data_reader_get_fragment_reader(const data_reader_t *data)
-{
- return data->frag;
-}
diff --git a/lib/sqfs/frag_reader.c b/lib/sqfs/frag_reader.c
deleted file mode 100644
index 0436a17..0000000
--- a/lib/sqfs/frag_reader.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-#include "config.h"
-
-#include "frag_reader.h"
-#include "highlevel.h"
-#include "util.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-struct frag_reader_t {
- sqfs_fragment_t *tbl;
- size_t num_fragments;
-
- int fd;
- compressor_t *cmp;
- size_t block_size;
- size_t used;
- size_t current_index;
- uint8_t buffer[];
-};
-
-static int precache_block(frag_reader_t *f, size_t i)
-{
- bool compressed;
- size_t size;
- ssize_t ret;
-
- if (i == f->current_index)
- return 0;
-
- compressed = (f->tbl[i].size & (1 << 24)) == 0;
- size = f->tbl[i].size & ((1 << 24) - 1);
-
- if (size > f->block_size) {
- fputs("found fragment block larger than block size\n", stderr);
- return -1;
- }
-
- if (read_data_at("reading fragment", f->tbl[i].start_offset,
- f->fd, f->buffer, size)) {
- return -1;
- }
-
- if (compressed) {
- ret = f->cmp->do_block(f->cmp, f->buffer, size,
- f->buffer + f->block_size, f->block_size);
-
- if (ret <= 0) {
- fputs("extracting fragment failed\n", stderr);
- return -1;
- }
-
- size = ret;
- memmove(f->buffer, f->buffer + f->block_size, ret);
- }
-
- f->current_index = i;
- f->used = size;
- return 0;
-}
-
-
-frag_reader_t *frag_reader_create(sqfs_super_t *super, int fd,
- compressor_t *cmp)
-{
- frag_reader_t *f = NULL;
- size_t i;
-
- f = calloc(1, sizeof(*f) + super->block_size * 2);
- if (f == NULL) {
- perror("creating fragment table");
- return NULL;
- }
-
- f->block_size = super->block_size;
- f->num_fragments = super->fragment_entry_count;
- f->current_index = f->num_fragments;
- f->cmp = cmp;
- f->fd = fd;
-
- f->tbl = sqfs_read_table(fd, cmp, sizeof(f->tbl[0]) * f->num_fragments,
- super->fragment_table_start);
- if (f->tbl == NULL) {
- free(f);
- return NULL;
- }
-
- for (i = 0; i < f->num_fragments; ++i) {
- f->tbl[i].start_offset = le64toh(f->tbl[i].start_offset);
- f->tbl[i].size = le32toh(f->tbl[i].size);
- }
-
- return f;
-}
-
-void frag_reader_destroy(frag_reader_t *f)
-{
- free(f->tbl);
- free(f);
-}
-
-int frag_reader_read(frag_reader_t *f, size_t index, size_t offset,
- void *buffer, size_t size)
-{
- if (precache_block(f, index))
- return -1;
-
- if (offset >= f->used)
- goto fail_range;
-
- if (size == 0)
- return 0;
-
- if ((offset + size - 1) >= f->used)
- goto fail_range;
-
- memcpy(buffer, f->buffer + offset, size);
- return 0;
-fail_range:
- fputs("attempted to read past fragment block limits\n", stderr);
- return -1;
-}
-
-const sqfs_fragment_t *frag_reader_get_table(const frag_reader_t *f)
-{
- return f->tbl;
-}
-
-size_t frag_reader_get_fragment_count(const frag_reader_t *f)
-{
- return f->num_fragments;
-}