diff options
Diffstat (limited to 'lib/sqfshelper')
-rw-r--r-- | lib/sqfshelper/data_reader.c | 155 |
1 files changed, 52 insertions, 103 deletions
diff --git a/lib/sqfshelper/data_reader.c b/lib/sqfshelper/data_reader.c index 0c982d7..0780da0 100644 --- a/lib/sqfshelper/data_reader.c +++ b/lib/sqfshelper/data_reader.c @@ -247,113 +247,64 @@ fail_sparse: return -1; } -int data_reader_dump_file(data_reader_t *data, file_info_t *fi, int outfd, - bool allow_sparse) -{ - uint64_t filesz = fi->size; - size_t fragsz = fi->size % data->block_size; - size_t count = fi->size / data->block_size; - off_t off = fi->startblock; - size_t i, diff; - - if (fragsz != 0 && (fi->fragment_offset >= data->block_size || - fi->fragment == 0xFFFFFFFF)) { - fragsz = 0; - ++count; - } - - if (allow_sparse && ftruncate(outfd, filesz)) - goto fail_sparse; - - for (i = 0; i < count; ++i) { - diff = filesz > data->block_size ? data->block_size : filesz; - filesz -= diff; - - if (SQFS_IS_SPARSE_BLOCK(fi->block_size[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, fi->block_size[i])) - return -1; - off += SQFS_ON_DISK_BLOCK_SIZE(fi->block_size[i]); - } - - if (write_data("writing uncompressed block", - outfd, data->block, diff)) { - return -1; - } - } - - if (fragsz > 0) { - if (precache_fragment_block(data, fi->fragment)) - return -1; - - 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_range: - fputs("attempted to read past fragment block limits\n", stderr); - return -1; -fail_sparse: - perror("creating sparse output file"); - return -1; -} - -ssize_t data_reader_read(data_reader_t *data, file_info_t *fi, +ssize_t data_reader_read(data_reader_t *data, + const sqfs_inode_generic_t *inode, uint64_t offset, void *buffer, size_t size) { - size_t i, diff, fragsz, count, total = 0; - off_t off; + uint32_t frag_idx, frag_off; + size_t i, diff, total = 0; + uint64_t off, filesz; char *ptr; - /* work out block count and fragment size */ - fragsz = fi->size % data->block_size; - count = fi->size / data->block_size; - - if (fragsz != 0 && (fi->fragment_offset >= data->block_size || - fi->fragment == 0xFFFFFFFF)) { - fragsz = 0; - ++count; + /* 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; } - /* work out block index and on-disk location */ - off = fi->startblock; + /* find location of the first block */ i = 0; - while (offset > data->block_size && i < count) { - off += SQFS_ON_DISK_BLOCK_SIZE(fi->block_size[i++]); + 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 < count && size > 0) { + while (i < inode->num_file_blocks && size > 0 && filesz > 0) { diff = data->block_size - offset; if (size < diff) - size = diff; + diff = size; - if (SQFS_IS_SPARSE_BLOCK(fi->block_size[i])) { + if (SQFS_IS_SPARSE_BLOCK(inode->block_sizes[i])) { memset(buffer, 0, diff); } else { - if (precache_data_block(data, off, fi->block_size[i])) + if (precache_data_block(data, off, + inode->block_sizes[i])) { return -1; + } memcpy(buffer, (char *)data->block + offset, diff); - off += SQFS_ON_DISK_BLOCK_SIZE(fi->block_size[i]); + off += SQFS_ON_DISK_BLOCK_SIZE(inode->block_sizes[i]); + } + + if (filesz >= data->block_size) { + filesz -= data->block_size; + } else { + filesz = 0; } ++i; @@ -364,32 +315,30 @@ ssize_t data_reader_read(data_reader_t *data, file_info_t *fi, } /* copy from fragment */ - if (i == count && size > 0 && fragsz > 0) { - if (precache_fragment_block(data, fi->fragment)) + if (i == inode->num_file_blocks && size > 0 && filesz > 0) { + if (precache_fragment_block(data, frag_idx)) return -1; - if (fi->fragment_offset >= data->frag_used) + if (frag_off >= data->frag_used) goto fail_range; - if ((fi->fragment_offset + fragsz - 1) >= data->frag_used) + if (frag_off + filesz > data->frag_used) goto fail_range; - ptr = (char *)data->frag_block + fi->fragment_offset; - ptr += offset; + if (offset >= filesz) + return total; - if (offset >= fragsz) { - offset = 0; - size = 0; - } + if (offset + size > filesz) + size = filesz - offset; - if (offset + size > fragsz) - size = fragsz - offset; + if (size == 0) + return total; - if (size > 0) { - memcpy(buffer, ptr + offset, size); - total += size; - } + ptr = (char *)data->frag_block + frag_off + offset; + memcpy(buffer, ptr, size); + total += size; } + return total; fail_range: fputs("attempted to read past fragment block limits\n", stderr); |