diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-09-19 16:02:33 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-09-20 03:18:47 +0200 |
commit | 04518e8940014d4528fbdc5474705cfcf98b44f2 (patch) | |
tree | 50341e52ea146230744d3e1d75574c9e035124c4 /lib | |
parent | 03965d76aed3bad803b62bf9a683f0feaa1ae360 (diff) |
Add data reader function to dump contents by inode
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sqfshelper/data_reader.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/lib/sqfshelper/data_reader.c b/lib/sqfshelper/data_reader.c index 42a351f..0c982d7 100644 --- a/lib/sqfshelper/data_reader.c +++ b/lib/sqfshelper/data_reader.c @@ -172,6 +172,81 @@ void data_reader_destroy(data_reader_t *data) free(data); } +int data_reader_dump(data_reader_t *data, const sqfs_inode_generic_t *inode, + int outfd, bool allow_sparse) +{ + uint32_t frag_idx, frag_off; + uint64_t filesz; + size_t i, diff; + off_t off; + + if (inode->base.type == SQFS_INODE_FILE) { + filesz = inode->data.file.file_size; + off = inode->data.file.blocks_start; + frag_idx = inode->data.file.fragment_index; + frag_off = inode->data.file.fragment_offset; + } else if (inode->base.type == SQFS_INODE_EXT_FILE) { + filesz = inode->data.file_ext.file_size; + off = inode->data.file_ext.blocks_start; + frag_idx = inode->data.file_ext.fragment_idx; + frag_off = inode->data.file_ext.fragment_offset; + } else { + return -1; + } + + if (allow_sparse && ftruncate(outfd, filesz)) + goto fail_sparse; + + for (i = 0; i < inode->num_file_blocks; ++i) { + diff = filesz > data->block_size ? data->block_size : filesz; + filesz -= diff; + + if (SQFS_IS_SPARSE_BLOCK(inode->block_sizes[i])) { + 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, + inode->block_sizes[i])) + return -1; + off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i]); + } + + if (write_data("writing uncompressed block", + outfd, data->block, diff)) { + return -1; + } + } + + if (filesz > 0 && frag_off != 0xFFFFFFFF) { + if (precache_fragment_block(data, frag_idx)) + return -1; + + if (frag_off >= data->frag_used) + goto fail_range; + + if ((frag_off + filesz - 1) >= data->frag_used) + goto fail_range; + + if (write_data("writing uncompressed fragment", outfd, + (char *)data->frag_block + frag_off, + filesz)) { + 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; +} + int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd, bool allow_sparse) { |