diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-05-03 15:59:35 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-05-03 21:45:46 +0200 |
commit | 4dc4c6bf50155550c0b83e433fef8c7c19462853 (patch) | |
tree | c46dabc7c757fac27b506194ce4d236c244ac938 /unpack/extract_file.c | |
parent | 12c8196ad46808dc9d0e84b3a798509dcf1a41e7 (diff) |
unsquashfs: add file data extraction
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'unpack/extract_file.c')
-rw-r--r-- | unpack/extract_file.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/unpack/extract_file.c b/unpack/extract_file.c new file mode 100644 index 0000000..c18ace8 --- /dev/null +++ b/unpack/extract_file.c @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include "unsquashfs.h" + +int extract_file(file_info_t *fi, compressor_t *cmp, size_t block_size, + frag_reader_t *frag, int sqfsfd, int outfd) +{ + size_t i, count, fragsz; + bool compressed; + void *buffer; + uint32_t bs; + ssize_t ret; + + buffer = malloc(block_size); + if (buffer == NULL) { + perror("allocating scratch buffer"); + return -1; + } + + count = fi->size / block_size; + + if (count > 0) { + if (lseek(sqfsfd, fi->startblock, SEEK_SET) == (off_t)-1) + goto fail_seek; + + for (i = 0; i < count; ++i) { + bs = fi->blocksizes[i]; + + compressed = (bs & (1 << 24)) == 0; + bs &= (1 << 24) - 1; + + if (bs > block_size) + goto fail_bs; + + ret = read_retry(sqfsfd, buffer, bs); + if (ret < 0) + goto fail_rd; + + if ((size_t)ret < bs) + goto fail_trunc; + + if (compressed) { + ret = cmp->do_block(cmp, buffer, bs); + if (ret <= 0) + goto fail; + + bs = ret; + } + + ret = write_retry(outfd, buffer, bs); + if (ret < 0) + goto fail_wr; + + if ((size_t)ret < bs) + goto fail_wr_trunc; + } + } + + fragsz = fi->size % block_size; + + if (fragsz > 0) { + if (frag_reader_read(frag, fi->fragment, fi->fragment_offset, + buffer, fragsz)) { + goto fail; + } + + ret = write_retry(outfd, buffer, fragsz); + if (ret < 0) + goto fail_wr; + + if ((size_t)ret < fragsz) + goto fail_wr_trunc; + } + + free(buffer); + return 0; +fail_seek: + perror("seek on squashfs"); + goto fail; +fail_wr: + perror("writing uncompressed block"); + goto fail; +fail_wr_trunc: + fputs("writing uncompressed block: truncated write\n", stderr); + goto fail; +fail_rd: + perror("reading from squashfs"); + goto fail; +fail_trunc: + fputs("reading from squashfs: unexpected end of file\n", stderr); + goto fail; +fail_bs: + fputs("found compressed block larger than block size\n", stderr); + goto fail; +fail: + free(buffer); + return -1; +} |