diff options
Diffstat (limited to 'lib/tar/src/read_sparse_map_old.c')
-rw-r--r-- | lib/tar/src/read_sparse_map_old.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/lib/tar/src/read_sparse_map_old.c b/lib/tar/src/read_sparse_map_old.c new file mode 100644 index 0000000..3dd3300 --- /dev/null +++ b/lib/tar/src/read_sparse_map_old.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * read_sparse_map_old.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "config.h" +#include "internal.h" + +#include <ctype.h> +#include <stdlib.h> + +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, ret; + + for (i = 0; i < 4; ++i) { + if (!isdigit(hdr->tail.gnu.sparse[i].offset[0])) + break; + if (!isdigit(hdr->tail.gnu.sparse[i].numbytes[0])) + break; + + if (read_octal(hdr->tail.gnu.sparse[i].offset, + sizeof(hdr->tail.gnu.sparse[i].offset), &off)) + goto fail; + if (read_octal(hdr->tail.gnu.sparse[i].numbytes, + sizeof(hdr->tail.gnu.sparse[i].numbytes), &sz)) + goto fail; + + node = calloc(1, sizeof(*node)); + if (node == NULL) + goto fail_errno; + + node->offset = off; + node->count = sz; + + if (list == NULL) { + list = end = node; + } else { + end->next = node; + end = node; + } + } + + if (hdr->tail.gnu.isextended == 0) + return list; + + do { + 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; + } + + for (i = 0; i < 21; ++i) { + if (!isdigit(sph.sparse[i].offset[0])) + break; + if (!isdigit(sph.sparse[i].numbytes[0])) + break; + + if (read_octal(sph.sparse[i].offset, + sizeof(sph.sparse[i].offset), &off)) + goto fail; + if (read_octal(sph.sparse[i].numbytes, + sizeof(sph.sparse[i].numbytes), &sz)) + goto fail; + + node = calloc(1, sizeof(*node)); + if (node == NULL) + goto fail_errno; + + node->offset = off; + node->count = sz; + + if (list == NULL) { + list = end = node; + } else { + end->next = node; + end = node; + } + } + } while (sph.isextended != 0); + + return list; +fail_errno: + perror("parsing GNU sparse header"); + goto fail; +fail: + free_sparse_list(list); + return NULL; +} |