diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-02-04 17:04:17 +0100 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-02-04 17:16:20 +0100 |
commit | b621d4ed5e07cdc17fee79011c21c62cd995ae2b (patch) | |
tree | d4221240dc55eb9b672b37df6d822086cb30792c /lib | |
parent | 89b367941e12b1163afa517eeddca1b5ecd2a054 (diff) |
libtar: simplfy parsing of old GNU sparse format
There was some code duplication for extracting the sparse entry
fields from the start record and the subsequent extended record.
This commit introduces a data structure for both and unifies
the parsing code paths.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/tar/src/read_sparse_map_old.c | 101 |
1 files changed, 41 insertions, 60 deletions
diff --git a/lib/tar/src/read_sparse_map_old.c b/lib/tar/src/read_sparse_map_old.c index 3dd3300..8f193d4 100644 --- a/lib/tar/src/read_sparse_map_old.c +++ b/lib/tar/src/read_sparse_map_old.c @@ -10,42 +10,52 @@ #include <ctype.h> #include <stdlib.h> -sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr) +static int parse(const gnu_old_sparse_t *in, size_t count, + sparse_map_t **head, sparse_map_t **tail) { - sparse_map_t *list = NULL, *end = NULL, *node; - gnu_sparse_t sph; + sparse_map_t *node; 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; + while (count--) { + if (!isdigit(in->offset[0]) || !isdigit(in->numbytes[0])) + return 1; + if (read_number(in->offset, sizeof(in->offset), &off)) + return -1; + if (read_number(in->numbytes, sizeof(in->numbytes), &sz)) + return -1; + ++in; node = calloc(1, sizeof(*node)); - if (node == NULL) - goto fail_errno; + if (node == NULL) { + perror("parsing GNU sparse header"); + return -1; + } node->offset = off; node->count = sz; - if (list == NULL) { - list = end = node; + if ((*head) == NULL) { + (*head) = (*tail) = node; } else { - end->next = node; - end = node; + (*tail)->next = node; + (*tail) = node; } } - if (hdr->tail.gnu.isextended == 0) + return 0; +} + +sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr) +{ + sparse_map_t *list = NULL, *end = NULL; + gnu_old_sparse_record_t sph; + int ret; + + ret = parse(hdr->tail.gnu.sparse, 4, &list, &end); + if (ret < 0) + goto fail; + + if (ret > 0 || hdr->tail.gnu.isextended == 0) return list; do { @@ -53,46 +63,17 @@ sparse_map_t *read_gnu_old_sparse(istream_t *fp, tar_header_t *hdr) 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; + if ((size_t)ret < sizeof(sph)) + goto fail_eof; - 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); + ret = parse(sph.sparse, 21, &list, &end); + if (ret < 0) + goto fail; + } while (ret == 0 && sph.isextended != 0); return list; -fail_errno: - perror("parsing GNU sparse header"); - goto fail; +fail_eof: + fputs("reading GNU sparse header: unexpected end-of-file\n", stderr); fail: free_sparse_list(list); return NULL; |