summaryrefslogtreecommitdiff
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
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>
-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) {