aboutsummaryrefslogtreecommitdiff
path: root/lib/sqfs
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-12 13:48:38 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-12 15:45:00 +0200
commit1b35319762cd83982dacbe96eccf07fd00d7858a (patch)
tree9e5c99d59f096dd4c152aa8d28a8ed4cd76726f1 /lib/sqfs
parent3038bf18d12b9d97d13b4846fed301c054cd793f (diff)
Add generic support for reading files without fragments
This commit extends the special case handling for sparse files to generically support reading files that don't have a fragment but instead have a trunkated final block. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs')
-rw-r--r--lib/sqfs/data_reader.c50
-rw-r--r--lib/sqfs/read_inode.c23
-rw-r--r--lib/sqfs/tree_node_from_inode.c11
3 files changed, 56 insertions, 28 deletions
diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c
index f8c80af..ec85412 100644
--- a/lib/sqfs/data_reader.c
+++ b/lib/sqfs/data_reader.c
@@ -62,13 +62,21 @@ void data_reader_destroy(data_reader_t *data)
int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
bool allow_sparse)
{
- size_t i, count, fragsz;
+ size_t i, count, fragsz, unpackedsz;
+ uint64_t filesz = 0;
bool compressed;
uint32_t bs;
ssize_t ret;
void *ptr;
count = fi->size / data->block_size;
+ fragsz = fi->size % data->block_size;
+
+ if (fragsz != 0 && (fi->fragment == 0xFFFFFFFF ||
+ fi->fragment_offset == 0xFFFFFFFF)) {
+ fragsz = 0;
+ ++count;
+ }
if (count > 0) {
if (lseek(data->sqfsfd, fi->startblock, SEEK_SET) == (off_t)-1)
@@ -83,8 +91,16 @@ int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
if (bs > data->block_size)
goto fail_bs;
+ if ((fi->size - filesz) < (uint64_t)data->block_size) {
+ unpackedsz = fi->size - filesz;
+ } else {
+ unpackedsz = data->block_size;
+ }
+
+ filesz += unpackedsz;
+
if (bs == 0 && allow_sparse) {
- if (ftruncate(outfd, i * data->block_size))
+ if (ftruncate(outfd, filesz))
goto fail_sparse;
if (lseek(outfd, 0, SEEK_END) == (off_t)-1)
goto fail_sparse;
@@ -92,8 +108,7 @@ int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
}
if (bs == 0) {
- bs = data->block_size;
- memset(data->buffer, 0, bs);
+ memset(data->buffer, 0, unpackedsz);
compressed = false;
} else {
ret = read_retry(data->sqfsfd, data->buffer, bs);
@@ -118,7 +133,7 @@ int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
ptr = data->buffer;
}
- ret = write_retry(outfd, ptr, bs);
+ ret = write_retry(outfd, ptr, unpackedsz);
if (ret < 0)
goto fail_wr;
@@ -127,27 +142,14 @@ int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd,
}
}
- fragsz = fi->size % data->block_size;
-
if (fragsz > 0) {
- if (fi->fragment == 0xFFFFFFFF ||
- fi->fragment_offset == 0xFFFFFFFF) {
- if (allow_sparse) {
- if (ftruncate(outfd, fragsz))
- goto fail_sparse;
- return 0;
- }
-
- memset(data->buffer, 0, fragsz);
- } else {
- if (data->frag == NULL)
- goto fail_frag;
+ if (data->frag == NULL)
+ goto fail_frag;
- if (frag_reader_read(data->frag, fi->fragment,
- fi->fragment_offset, data->buffer,
- fragsz)) {
- return -1;
- }
+ if (frag_reader_read(data->frag, fi->fragment,
+ fi->fragment_offset, data->buffer,
+ fragsz)) {
+ return -1;
}
ret = write_retry(outfd, data->buffer, fragsz);
diff --git a/lib/sqfs/read_inode.c b/lib/sqfs/read_inode.c
index 565cb5a..8230138 100644
--- a/lib/sqfs/read_inode.c
+++ b/lib/sqfs/read_inode.c
@@ -50,13 +50,26 @@ static int set_mode(sqfs_inode_t *inode)
return 0;
}
+static uint64_t get_block_count(uint64_t size, uint64_t block_size,
+ uint32_t frag_index, uint32_t frag_offset)
+{
+ uint64_t count = size / block_size;
+
+ if ((size % block_size) != 0 &&
+ (frag_index == 0xFFFFFFFF || frag_offset == 0xFFFFFFFF)) {
+ ++count;
+ }
+
+ return count;
+}
+
static sqfs_inode_generic_t *read_inode_file(meta_reader_t *ir,
sqfs_inode_t *base,
size_t block_size)
{
sqfs_inode_generic_t *out;
sqfs_inode_file_t file;
- size_t i, count;
+ uint64_t i, count;
if (meta_reader_read(ir, &file, sizeof(file)))
return NULL;
@@ -66,7 +79,8 @@ static sqfs_inode_generic_t *read_inode_file(meta_reader_t *ir,
SWAB32(file.fragment_offset);
SWAB32(file.file_size);
- count = file.file_size / block_size;
+ count = get_block_count(file.file_size, block_size,
+ file.fragment_index, file.fragment_offset);
out = calloc(1, sizeof(*out) + count * sizeof(uint32_t));
if (out == NULL) {
@@ -95,7 +109,7 @@ static sqfs_inode_generic_t *read_inode_file_ext(meta_reader_t *ir,
{
sqfs_inode_file_ext_t file;
sqfs_inode_generic_t *out;
- size_t i, count;
+ uint64_t i, count;
if (meta_reader_read(ir, &file, sizeof(file)))
return NULL;
@@ -108,7 +122,8 @@ static sqfs_inode_generic_t *read_inode_file_ext(meta_reader_t *ir,
SWAB32(file.fragment_offset);
SWAB32(file.xattr_idx);
- count = file.file_size / block_size;
+ count = get_block_count(file.file_size, block_size,
+ file.fragment_idx, file.fragment_offset);
out = calloc(1, sizeof(*out) + count * sizeof(uint32_t));
if (out == NULL) {
diff --git a/lib/sqfs/tree_node_from_inode.c b/lib/sqfs/tree_node_from_inode.c
index 9c96701..0d46eed 100644
--- a/lib/sqfs/tree_node_from_inode.c
+++ b/lib/sqfs/tree_node_from_inode.c
@@ -19,10 +19,14 @@ static size_t compute_size(sqfs_inode_generic_t *inode, const char *name,
case SQFS_INODE_FILE:
size += sizeof(file_info_t);
block_count = inode->data.file.file_size / block_size;
+ if ((inode->data.file.file_size % block_size) != 0)
+ ++block_count;
break;
case SQFS_INODE_EXT_FILE:
size += sizeof(file_info_t);
block_count = inode->data.file_ext.file_size / block_size;
+ if ((inode->data.file_ext.file_size % block_size) != 0)
+ ++block_count;
break;
case SQFS_INODE_SLINK:
case SQFS_INODE_EXT_SLINK:
@@ -40,6 +44,13 @@ static void copy_block_sizes(sqfs_inode_generic_t *inode, tree_node_t *out,
{
size_t block_count = out->data.file->size / block_size;
+ if ((out->data.file->size % block_size) != 0) {
+ if (out->data.file->fragment == 0xFFFFFFFF ||
+ out->data.file->fragment_offset == 0xFFFFFFFF) {
+ ++block_count;
+ }
+ }
+
out->name += block_count * sizeof(uint32_t);
if (block_count) {