diff options
Diffstat (limited to 'lib/tar/src/istream.c')
-rw-r--r-- | lib/tar/src/istream.c | 240 |
1 files changed, 0 insertions, 240 deletions
diff --git a/lib/tar/src/istream.c b/lib/tar/src/istream.c deleted file mode 100644 index 80519b1..0000000 --- a/lib/tar/src/istream.c +++ /dev/null @@ -1,240 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * istream.c - * - * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> - */ -#include "internal.h" - -#include <string.h> -#include <stdlib.h> - -typedef struct { - sqfs_u64 offset; - sqfs_u64 count; -} sparse_ent_t; - -typedef struct { - istream_t base; - - istream_t *parent; - - char *filename; - - sparse_ent_t *sparse; - size_t num_sparse; - - sqfs_u64 record_size; - sqfs_u64 file_size; - sqfs_u64 offset; - - size_t padding; - size_t last_chunk; - bool last_sparse; - - sqfs_u8 buffer[4096]; -} tar_istream_t; - -static bool is_sparse_region(tar_istream_t *tar, sqfs_u64 *count) -{ - size_t i; - - *count = tar->file_size - tar->offset; - if (tar->num_sparse == 0) - return false; - - for (i = 0; i < tar->num_sparse; ++i) { - if (tar->offset >= tar->sparse[i].offset) { - sqfs_u64 diff = tar->offset - tar->sparse[i].offset; - - if (diff < tar->sparse[i].count) { - *count = tar->sparse[i].count - diff; - return false; - } - } - } - - for (i = 0; i < tar->num_sparse; ++i) { - if (tar->offset < tar->sparse[i].offset) { - sqfs_u64 diff = tar->sparse[i].offset - tar->offset; - - if (diff < *count) - *count = diff; - } - } - - return true; -} - -static int precache(istream_t *strm) -{ - tar_istream_t *tar = (tar_istream_t *)strm; - sqfs_u64 diff, avail; - - tar->offset += tar->last_chunk; - - if (!tar->last_sparse) { - tar->parent->buffer_offset += tar->last_chunk; - tar->record_size -= tar->last_chunk; - } - - if (tar->offset >= tar->file_size) { - strm->eof = true; - strm->buffer_used = 0; - strm->buffer = tar->buffer; - if (tar->record_size > 0) - goto fail_rec_sz; - if (istream_skip(tar->parent, tar->padding)) - goto fail; - tar->padding = 0; - return 0; - } - - if (is_sparse_region(tar, &diff)) { - if (diff > sizeof(tar->buffer)) - diff = sizeof(tar->buffer); - - strm->buffer = tar->buffer; - strm->buffer_used = diff; - tar->last_chunk = diff; - tar->last_sparse = true; - - memset(tar->buffer, 0, diff); - } else { - if (diff > tar->record_size) - goto fail_rec_sz; - - avail = tar->parent->buffer_used - tar->parent->buffer_offset; - - if ((diff > avail) && - ((tar->parent->buffer_offset > 0) || avail == 0)) { - if (istream_precache(tar->parent)) - goto fail; - - if (tar->parent->buffer_used == 0 && tar->parent->eof) - goto fail_eof; - - avail = tar->parent->buffer_used; - } - - if (diff > avail) - diff = avail; - - strm->buffer = tar->parent->buffer + tar->parent->buffer_offset; - strm->buffer_used = diff; - tar->last_chunk = diff; - tar->last_sparse = false; - } - - return 0; -fail_rec_sz: - fprintf(stderr, - "%s: missmatch in tar record size vs file size for `%s`.\n", - istream_get_filename(tar->parent), istream_get_filename(strm)); - goto fail; -fail_eof: - fprintf(stderr, "%s: unexpected end-of-file while reading `%s`\n", - istream_get_filename(tar->parent), istream_get_filename(strm)); - goto fail; -fail: - tar->record_size = 0; - tar->padding = 0; - return -1; -} - -static const char *get_filename(istream_t *strm) -{ - return ((tar_istream_t *)strm)->filename; -} - -static void tar_istream_destroy(sqfs_object_t *obj) -{ - tar_istream_t *strm = (tar_istream_t *)obj; - - if (strm->record_size > 0) - istream_skip(strm->parent, strm->record_size); - - if (strm->padding > 0) - istream_skip(strm->parent, strm->padding); - - sqfs_drop(strm->parent); - free(strm->sparse); - free(strm->filename); - free(strm); -} - -istream_t *tar_record_istream_create(istream_t *parent, - const tar_header_decoded_t *hdr) -{ - tar_istream_t *strm; - sparse_map_t *it; - sqfs_u64 diff; - size_t idx; - - strm = calloc(1, sizeof(*strm)); - if (strm == NULL) - goto fail_oom; - - sqfs_object_init(strm, tar_istream_destroy, NULL); - - strm->filename = strdup(hdr->name); - if (strm->filename == NULL) - goto fail_oom; - - strm->num_sparse = 0; - for (it = hdr->sparse; it != NULL; it = it->next) - strm->num_sparse += 1; - - if (strm->num_sparse > 0) { - strm->sparse = alloc_array(sizeof(strm->sparse[0]), - strm->num_sparse); - if (strm->sparse == NULL) - goto fail_oom; - - idx = 0; - it = hdr->sparse; - while (it != NULL && idx < strm->num_sparse) { - strm->sparse[idx].offset = it->offset; - strm->sparse[idx].count = it->count; - ++idx; - it = it->next; - } - } - - for (idx = 1; idx < strm->num_sparse; ++idx) { - if (strm->sparse[idx].offset <= strm->sparse[idx - 1].offset) - goto fail_sparse; - - diff = strm->sparse[idx].offset - strm->sparse[idx - 1].offset; - - if (diff < strm->sparse[idx - 1].count) - goto fail_sparse; - } - - strm->padding = hdr->record_size % 512; - if (strm->padding > 0) - strm->padding = 512 - strm->padding; - - strm->record_size = hdr->record_size; - strm->file_size = hdr->actual_size; - strm->parent = sqfs_grab(parent); - - ((istream_t *)strm)->precache = precache; - ((istream_t *)strm)->get_filename = get_filename; - ((istream_t *)strm)->buffer = strm->buffer; - ((istream_t *)strm)->eof = false; - return (istream_t *)strm; -fail_sparse: - fprintf(stderr, "%s: sparse map is not ordered or overlapping!\n", - hdr->name); - goto fail; -fail_oom: - fputs("tar istream create: out-of-memory\n", stderr); - goto fail; -fail: - if (strm != NULL) { - free(strm->filename); - free(strm); - } - return NULL; -} |