From f757737060d4daebb24a32e90d912661428708a8 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 13 Sep 2020 13:37:42 +0200 Subject: Remodel libtar/tar2sqfs to read data from an istream_t Signed-off-by: David Oberhollenzer --- lib/common/Makemodule.am | 4 +- lib/common/io_stdin.c | 182 ------------------------------------------ lib/tar/Makemodule.am | 5 +- lib/tar/internal.h | 8 +- lib/tar/pax_header.c | 2 +- lib/tar/read_header.c | 24 +++++- lib/tar/read_retry.c | 57 ------------- lib/tar/read_sparse_map_new.c | 20 +++-- lib/tar/read_sparse_map_old.c | 14 +++- lib/tar/record_to_memory.c | 40 ++++++++++ lib/tar/skip.c | 44 ---------- 11 files changed, 94 insertions(+), 306 deletions(-) delete mode 100644 lib/common/io_stdin.c delete mode 100644 lib/tar/read_retry.c create mode 100644 lib/tar/record_to_memory.c delete mode 100644 lib/tar/skip.c (limited to 'lib') diff --git a/lib/common/Makemodule.am b/lib/common/Makemodule.am index df08894..e191e29 100644 --- a/lib/common/Makemodule.am +++ b/lib/common/Makemodule.am @@ -3,10 +3,10 @@ libcommon_a_SOURCES += lib/common/inode_stat.c lib/common/hardlink.c libcommon_a_SOURCES += lib/common/print_version.c lib/common/data_reader_dump.c libcommon_a_SOURCES += lib/common/compress.c lib/common/comp_opt.c libcommon_a_SOURCES += lib/common/data_writer.c include/common.h -libcommon_a_SOURCES += lib/common/get_path.c lib/common/io_stdin.c +libcommon_a_SOURCES += lib/common/get_path.c lib/common/data_writer_ostream.c libcommon_a_SOURCES += lib/common/writer.c lib/common/perror.c libcommon_a_SOURCES += lib/common/mkdir_p.c lib/common/parse_size.c -libcommon_a_SOURCES += lib/common/print_size.c lib/common/data_writer_ostream.c +libcommon_a_SOURCES += lib/common/print_size.c libcommon_a_CFLAGS = $(AM_CFLAGS) $(LZO_CFLAGS) if WITH_LZO diff --git a/lib/common/io_stdin.c b/lib/common/io_stdin.c deleted file mode 100644 index 4694989..0000000 --- a/lib/common/io_stdin.c +++ /dev/null @@ -1,182 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * io_stdin.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "common.h" - -#include -#include -#include - - -typedef struct { - sqfs_file_t base; - - const sparse_map_t *map; - sqfs_u64 offset; - sqfs_u64 real_size; - sqfs_u64 apparent_size; - FILE *fp; -} sqfs_file_stdinout_t; - - -static void stdinout_destroy(sqfs_object_t *base) -{ - free(base); -} - -static sqfs_u64 stdinout_get_size(const sqfs_file_t *base) -{ - return ((const sqfs_file_stdinout_t *)base)->apparent_size; -} - -static int stdinout_truncate(sqfs_file_t *base, sqfs_u64 size) -{ - (void)base; (void)size; - return SQFS_ERROR_IO; -} - -static int stdin_read_at(sqfs_file_t *base, sqfs_u64 offset, - void *buffer, size_t size) -{ - sqfs_file_stdinout_t *file = (sqfs_file_stdinout_t *)base; - size_t temp_size = 0; - sqfs_u8 *temp = NULL; - sqfs_u64 diff; - size_t ret; - - if (offset < file->offset) - return SQFS_ERROR_IO; - - if (offset > file->offset) { - temp_size = 1024; - temp = alloca(temp_size); - } - - if (offset >= file->real_size || (offset + size) > file->real_size) - return SQFS_ERROR_OUT_OF_BOUNDS; - - while (size > 0) { - if (ferror(file->fp)) - return SQFS_ERROR_IO; - - if (feof(file->fp)) - return SQFS_ERROR_OUT_OF_BOUNDS; - - if (offset > file->offset) { - diff = file->offset - offset; - diff = diff > (sqfs_u64)temp_size ? temp_size : diff; - - ret = fread(temp, 1, diff, file->fp); - } else { - ret = fread(buffer, 1, size, file->fp); - } - - if (offset <= file->offset) { - buffer = (char *)buffer + ret; - size -= ret; - offset += ret; - } - - file->offset += ret; - } - - return 0; -} - -static int stdin_read_condensed(sqfs_file_t *base, sqfs_u64 offset, - void *buffer, size_t size) -{ - sqfs_file_stdinout_t *file = (sqfs_file_stdinout_t *)base; - sqfs_u64 poffset = 0, src_start; - size_t dst_start, diff, count; - const sparse_map_t *it; - int err; - - memset(buffer, 0, size); - - for (it = file->map; it != NULL; it = it->next) { - if (it->offset + it->count <= offset) { - poffset += it->count; - continue; - } - - if (it->offset >= offset + size) { - poffset += it->count; - continue; - } - - count = size; - - if (offset + count >= it->offset + it->count) - count = it->offset + it->count - offset; - - if (it->offset < offset) { - diff = offset - it->offset; - - src_start = poffset + diff; - dst_start = 0; - count -= diff; - } else if (it->offset > offset) { - diff = it->offset - offset; - - src_start = poffset; - dst_start = diff; - } else { - src_start = poffset; - dst_start = 0; - } - - err = stdin_read_at(base, src_start, - (char *)buffer + dst_start, count); - if (err) - return err; - - poffset += it->count; - } - - return 0; -} - -static int stdin_write_at(sqfs_file_t *base, sqfs_u64 offset, - const void *buffer, size_t size) -{ - (void)base; (void)offset; (void)buffer; (void)size; - return SQFS_ERROR_IO; -} - -sqfs_file_t *sqfs_get_stdin_file(FILE *fp, const sparse_map_t *map, - sqfs_u64 size) -{ - sqfs_file_stdinout_t *file = calloc(1, sizeof(*file)); - sqfs_file_t *base = (sqfs_file_t *)file; - const sparse_map_t *it; - - if (file == NULL) - return NULL; - - file->apparent_size = size; - file->map = map; - file->fp = fp; - - if (map != NULL) { - for (it = map; it != NULL; it = it->next) - file->real_size += map->count; - } else { - file->real_size = size; - } - - ((sqfs_object_t *)base)->destroy = stdinout_destroy; - base->write_at = stdin_write_at; - base->get_size = stdinout_get_size; - base->truncate = stdinout_truncate; - - if (map == NULL) { - base->read_at = stdin_read_at; - } else { - base->read_at = stdin_read_condensed; - } - return base; -} diff --git a/lib/tar/Makemodule.am b/lib/tar/Makemodule.am index 7ba0454..414aca1 100644 --- a/lib/tar/Makemodule.am +++ b/lib/tar/Makemodule.am @@ -1,9 +1,10 @@ -libtar_a_SOURCES = lib/tar/read_header.c lib/tar/write_header.c lib/tar/skip.c +libtar_a_SOURCES = lib/tar/read_header.c lib/tar/write_header.c libtar_a_SOURCES += lib/tar/number.c lib/tar/checksum.c lib/tar/cleanup.c libtar_a_SOURCES += lib/tar/read_sparse_map.c lib/tar/read_sparse_map_old.c libtar_a_SOURCES += lib/tar/base64.c lib/tar/urldecode.c lib/tar/internal.h -libtar_a_SOURCES += lib/tar/padd_file.c lib/tar/read_retry.c include/tar.h +libtar_a_SOURCES += lib/tar/padd_file.c lib/tar/record_to_memory.c libtar_a_SOURCES += lib/tar/pax_header.c lib/tar/read_sparse_map_new.c +libtar_a_SOURCES += include/tar.h libtar_a_CFLAGS = $(AM_CFLAGS) libtar_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/lib/tar/internal.h b/lib/tar/internal.h index bea863d..b7c4c34 100644 --- a/lib/tar/internal.h +++ b/lib/tar/internal.h @@ -59,9 +59,9 @@ bool is_checksum_valid(const tar_header_t *hdr); sparse_map_t *read_sparse_map(const char *line); -sparse_map_t *read_gnu_old_sparse(FILE *fp, tar_header_t *hdr); +sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr); -sparse_map_t *read_gnu_new_sparse(FILE *fp, tar_header_decoded_t *out); +sparse_map_t *read_gnu_new_sparse(istream_t *fp, tar_header_decoded_t *out); void free_sparse_list(sparse_map_t *sparse); @@ -69,9 +69,9 @@ size_t base64_decode(sqfs_u8 *out, const char *in, size_t len); void urldecode(char *str); -char *record_to_memory(FILE *fp, sqfs_u64 size); +char *record_to_memory(istream_t *fp, size_t size); -int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax, +int read_pax_header(istream_t *fp, sqfs_u64 entsize, unsigned int *set_by_pax, tar_header_decoded_t *out); #endif /* INTERNAL_H */ diff --git a/lib/tar/pax_header.c b/lib/tar/pax_header.c index 448976d..a96a32f 100644 --- a/lib/tar/pax_header.c +++ b/lib/tar/pax_header.c @@ -25,7 +25,7 @@ static tar_xattr_t *mkxattr(const char *key, size_t keylen, return xattr; } -int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax, +int read_pax_header(istream_t *fp, sqfs_u64 entsize, unsigned int *set_by_pax, tar_header_decoded_t *out) { char *buffer, *line, *key, *ptr, *value, *end; diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c index 14752ea..b332514 100644 --- a/lib/tar/read_header.c +++ b/lib/tar/read_header.c @@ -170,20 +170,24 @@ static int decode_header(const tar_header_t *hdr, unsigned int set_by_pax, return 0; } -int read_header(FILE *fp, tar_header_decoded_t *out) +int read_header(istream_t *fp, tar_header_decoded_t *out) { unsigned int set_by_pax = 0; bool prev_was_zero = false; sqfs_u64 pax_size; tar_header_t hdr; - int version; + int version, ret; memset(out, 0, sizeof(*out)); for (;;) { - if (read_retry("reading tar header", fp, &hdr, sizeof(hdr))) + ret = istream_read(fp, &hdr, sizeof(hdr)); + if (ret < 0) goto fail; + if ((size_t)ret < sizeof(hdr)) + goto out_eof; + if (is_zero_block(&hdr)) { if (prev_was_zero) goto out_eof; @@ -294,3 +298,17 @@ fail: clear_header(out); return -1; } + +int skip_padding(istream_t *fp, sqfs_u64 size) +{ + size_t tail = size % 512; + + return tail ? istream_skip(fp, 512 - tail) : 0; +} + +int skip_entry(istream_t *fp, sqfs_u64 size) +{ + size_t tail = size % 512; + + return istream_skip(fp, tail ? (size + 512 - tail) : size); +} diff --git a/lib/tar/read_retry.c b/lib/tar/read_retry.c deleted file mode 100644 index 2a2f82c..0000000 --- a/lib/tar/read_retry.c +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * read_retry.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "config.h" - -#include "tar.h" -#include "internal.h" - -int read_retry(const char *errstr, FILE *fp, void *buffer, size_t size) -{ - size_t ret; - - while (size > 0) { - if (ferror(fp)) { - fprintf(stderr, "%s: error reading from file\n", - errstr); - return -1; - } - - if (feof(fp)) { - fprintf(stderr, "%s: short read\n", errstr); - return -1; - } - - ret = fread(buffer, 1, size, fp); - size -= ret; - buffer = (char *)buffer + ret; - } - - return 0; -} - -char *record_to_memory(FILE *fp, sqfs_u64 size) -{ - char *buffer = malloc(size + 1); - - if (buffer == NULL) - goto fail_errno; - - if (read_retry("reading tar record", fp, buffer, size)) - goto fail; - - if (skip_padding(fp, size)) - goto fail; - - buffer[size] = '\0'; - return buffer; -fail_errno: - perror("reading tar record"); - goto fail; -fail: - free(buffer); - return NULL; -} diff --git a/lib/tar/read_sparse_map_new.c b/lib/tar/read_sparse_map_new.c index f4f0f92..d9f6c6e 100644 --- a/lib/tar/read_sparse_map_new.c +++ b/lib/tar/read_sparse_map_new.c @@ -28,7 +28,7 @@ static int decode(const char *str, size_t len, size_t *out) return (*str == '\n') ? ((int)count + 1) : -1; } -sparse_map_t *read_gnu_new_sparse(FILE *fp, tar_header_decoded_t *out) +sparse_map_t *read_gnu_new_sparse(istream_t *fp, tar_header_decoded_t *out) { sparse_map_t *last = NULL, *list = NULL, *ent = NULL; size_t i, count, value; @@ -38,8 +38,12 @@ sparse_map_t *read_gnu_new_sparse(FILE *fp, tar_header_decoded_t *out) if (out->record_size < 512) goto fail_format; - if (read_retry("reading GNU sparse map", fp, buffer, 512)) - return NULL; + ret = istream_read(fp, buffer, 512); + if (ret < 0) + goto fail; + + if (ret < 512) + goto fail_format; diff = decode(buffer, 512, &count); if (diff <= 0) @@ -61,10 +65,12 @@ sparse_map_t *read_gnu_new_sparse(FILE *fp, tar_header_decoded_t *out) if (out->record_size < 512) goto fail_format; - if (read_retry("reading GNU sparse map", fp, - buffer + 512, 512)) { - return NULL; - } + ret = istream_read(fp, buffer + 512, 512); + if (ret < 0) + goto fail; + + if (ret < 512) + goto fail_format; ret = decode(buffer + diff, 1024 - diff, &value); if (ret <= 0) diff --git a/lib/tar/read_sparse_map_old.c b/lib/tar/read_sparse_map_old.c index 84e1f9e..cd7177d 100644 --- a/lib/tar/read_sparse_map_old.c +++ b/lib/tar/read_sparse_map_old.c @@ -8,12 +8,12 @@ #include "internal.h" -sparse_map_t *read_gnu_old_sparse(FILE *fp, tar_header_t *hdr) +sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr) { sparse_map_t *list = NULL, *end = NULL, *node; gnu_sparse_t sph; sqfs_u64 off, sz; - int i; + int i, ret; for (i = 0; i < 4; ++i) { if (!isdigit(hdr->tail.gnu.sparse[i].offset[0])) @@ -47,8 +47,14 @@ sparse_map_t *read_gnu_old_sparse(FILE *fp, tar_header_t *hdr) return list; do { - if (read_retry("reading GNU sparse header", - fp, &sph, sizeof(sph))) { + ret = istream_read(fp, &sph, sizeof(sph)); + if (ret < 0) + goto fail; + + if ((size_t)ret < sizeof(sph)) { + fputs("reading GNU sparse header: " + "unexpected end-of-file\n", + stderr); goto fail; } diff --git a/lib/tar/record_to_memory.c b/lib/tar/record_to_memory.c new file mode 100644 index 0000000..822608c --- /dev/null +++ b/lib/tar/record_to_memory.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * record_to_memory.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "config.h" + +#include "tar.h" +#include "internal.h" + +char *record_to_memory(istream_t *fp, size_t size) +{ + char *buffer = malloc(size + 1); + int ret; + + if (buffer == NULL) + goto fail_errno; + + ret = istream_read(fp, buffer, size); + if (ret < 0) + goto fail; + + if ((size_t)ret < size) { + fputs("Reading tar record: unexpected end-of-file.\n", stderr); + goto fail; + } + + if (skip_padding(fp, size)) + goto fail; + + buffer[size] = '\0'; + return buffer; +fail_errno: + perror("reading tar record"); + goto fail; +fail: + free(buffer); + return NULL; +} diff --git a/lib/tar/skip.c b/lib/tar/skip.c deleted file mode 100644 index 36cd470..0000000 --- a/lib/tar/skip.c +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * skip.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "config.h" - -#include "tar.h" - -#include - -static int skip_bytes(FILE *fp, sqfs_u64 size) -{ - unsigned char buffer[1024]; - size_t diff; - - while (size != 0) { - diff = sizeof(buffer); - if (diff > size) - diff = size; - - if (read_retry("reading tar record padding", fp, buffer, diff)) - return -1; - - size -= diff; - } - - return 0; -} - -int skip_padding(FILE *fp, sqfs_u64 size) -{ - size_t tail = size % 512; - - return tail ? skip_bytes(fp, 512 - tail) : 0; -} - -int skip_entry(FILE *fp, sqfs_u64 size) -{ - size_t tail = size % 512; - - return skip_bytes(fp, tail ? (size + 512 - tail) : size); -} -- cgit v1.2.3