aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-02-04 17:04:17 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-02-04 17:16:20 +0100
commitb621d4ed5e07cdc17fee79011c21c62cd995ae2b (patch)
treed4221240dc55eb9b672b37df6d822086cb30792c
parent89b367941e12b1163afa517eeddca1b5ecd2a054 (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>
-rw-r--r--include/tar/format.h25
-rw-r--r--lib/tar/src/read_sparse_map_old.c101
2 files changed, 53 insertions, 73 deletions
diff --git a/include/tar/format.h b/include/tar/format.h
index c3e372d..9f60ef3 100644
--- a/include/tar/format.h
+++ b/include/tar/format.h
@@ -10,6 +10,17 @@
#include "sqfs/predef.h"
typedef struct {
+ char offset[12];
+ char numbytes[12];
+} gnu_old_sparse_t;
+
+typedef struct {
+ gnu_old_sparse_t sparse[21];
+ char isextended;
+ char padding[7];
+} gnu_old_sparse_record_t;
+
+typedef struct {
char name[100];
char mode[8];
char uid[8];
@@ -37,10 +48,7 @@ typedef struct {
char offset[12];
char deprecated[4];
char unused;
- struct {
- char offset[12];
- char numbytes[12];
- } sparse[4];
+ gnu_old_sparse_t sparse[4];
char isextended;
char realsize[12];
char padding[17];
@@ -48,15 +56,6 @@ typedef struct {
} tail;
} tar_header_t;
-typedef struct {
- struct {
- char offset[12];
- char numbytes[12];
- } sparse[21];
- char isextended;
- char padding[7];
-} gnu_sparse_t;
-
#define TAR_TYPE_FILE '0'
#define TAR_TYPE_LINK '1'
#define TAR_TYPE_SLINK '2'
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;