summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-01 13:23:36 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-01 13:23:36 +0200
commit8aea2d1dc437b5b497170ef9c1b6854aee8f5dcf (patch)
tree0999ed4664c74cf90896d8b11f7f4a9dc06e8d48
parentf0d18050d832498c8e230c04084675455fef391f (diff)
cleanup: split tar code up, remove some duplications
This commit attempts to split some of the monolitic tar parsing code up into multiple functions in seperate files. Also, some code duplication (like reading a record into memory which was implemented twice) is removed. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/tar.h7
-rw-r--r--lib/Makemodule.am4
-rw-r--r--lib/tar/checksum.c26
-rw-r--r--lib/tar/cleanup.c21
-rw-r--r--lib/tar/internal.h55
-rw-r--r--lib/tar/number.c94
-rw-r--r--lib/tar/read_header.c366
-rw-r--r--lib/tar/read_sparse_map.c47
-rw-r--r--lib/tar/read_sparse_map_old.c89
-rw-r--r--lib/tar/write_header.c30
10 files changed, 374 insertions, 365 deletions
diff --git a/include/tar.h b/include/tar.h
index 513e5bc..ef4fdec 100644
--- a/include/tar.h
+++ b/include/tar.h
@@ -8,13 +8,6 @@
#include "util.h"
-typedef enum {
- ETV_UNKNOWN = 0,
- ETV_V7_UNIX,
- ETV_PRE_POSIX,
- ETV_POSIX,
-} E_TAR_VERSION;
-
typedef struct {
char name[100];
char mode[8];
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index a79b9c3..6418568 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -8,7 +8,9 @@ libfstree_a_CFLAGS = $(AM_CFLAGS)
libfstree_a_CPPFLAGS = $(AM_CPPFLAGS)
libtar_a_SOURCES = lib/tar/read_header.c lib/tar/write_header.c lib/tar/skip.c
-libtar_a_SOURCES += include/tar.h
+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/internal.h include/tar.h
libtar_a_CFLAGS = $(AM_CFLAGS)
libtar_a_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/lib/tar/checksum.c b/lib/tar/checksum.c
new file mode 100644
index 0000000..925f942
--- /dev/null
+++ b/lib/tar/checksum.c
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "internal.h"
+
+void update_checksum(tar_header_t *hdr)
+{
+ unsigned int chksum = 0;
+ size_t i;
+
+ memset(hdr->chksum, ' ', sizeof(hdr->chksum));
+
+ for (i = 0; i < sizeof(*hdr); ++i)
+ chksum += ((unsigned char *)hdr)[i];
+
+ write_octal(hdr->chksum, chksum, 6);
+ hdr->chksum[6] = '\0';
+ hdr->chksum[7] = ' ';
+}
+
+bool is_checksum_valid(const tar_header_t *hdr)
+{
+ tar_header_t copy;
+
+ memcpy(&copy, hdr, sizeof(*hdr));
+ update_checksum(&copy);
+ return memcmp(hdr, &copy, sizeof(*hdr)) == 0;
+}
diff --git a/lib/tar/cleanup.c b/lib/tar/cleanup.c
new file mode 100644
index 0000000..c4d1734
--- /dev/null
+++ b/lib/tar/cleanup.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "internal.h"
+
+void free_sparse_list(sparse_map_t *sparse)
+{
+ sparse_map_t *old;
+
+ while (sparse != NULL) {
+ old = sparse;
+ sparse = sparse->next;
+ free(old);
+ }
+}
+
+void clear_header(tar_header_decoded_t *hdr)
+{
+ free_sparse_list(hdr->sparse);
+ free(hdr->name);
+ free(hdr->link_target);
+ memset(hdr, 0, sizeof(*hdr));
+}
diff --git a/lib/tar/internal.h b/lib/tar/internal.h
new file mode 100644
index 0000000..6596987
--- /dev/null
+++ b/lib/tar/internal.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+#include "util.h"
+#include "tar.h"
+
+#include <sys/sysmacros.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+
+enum {
+ PAX_SIZE = 0x001,
+ PAX_UID = 0x002,
+ PAX_GID = 0x004,
+ PAX_DEV_MAJ = 0x008,
+ PAX_DEV_MIN = 0x010,
+ PAX_NAME = 0x020,
+ PAX_SLINK_TARGET = 0x040,
+ PAX_ATIME = 0x080,
+ PAX_MTIME = 0x100,
+ PAX_CTIME = 0x200,
+ PAX_SPARSE_SIZE = 0x400,
+};
+
+enum {
+ ETV_UNKNOWN = 0,
+ ETV_V7_UNIX,
+ ETV_PRE_POSIX,
+ ETV_POSIX,
+};
+
+int read_octal(const char *str, int digits, uint64_t *out);
+
+int read_binary(const char *str, int digits, uint64_t *out);
+
+int read_number(const char *str, int digits, uint64_t *out);
+
+void write_octal(char *dst, unsigned int value, int digits);
+
+int pax_read_decimal(const char *str, uint64_t *out);
+
+void update_checksum(tar_header_t *hdr);
+
+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(int fd, tar_header_t *hdr);
+
+void free_sparse_list(sparse_map_t *sparse);
+
+#endif /* INTERNAL_H */
diff --git a/lib/tar/number.c b/lib/tar/number.c
new file mode 100644
index 0000000..e85866d
--- /dev/null
+++ b/lib/tar/number.c
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "internal.h"
+
+int read_octal(const char *str, int digits, uint64_t *out)
+{
+ uint64_t result = 0;
+
+ while (digits > 0 && isspace(*str)) {
+ ++str;
+ --digits;
+ }
+
+ while (digits > 0 && *str >= '0' && *str <= '7') {
+ if (result > 0x1FFFFFFFFFFFFFFFUL) {
+ fputs("numeric overflow parsing tar header\n", stderr);
+ return -1;
+ }
+
+ result = (result << 3) | (*(str++) - '0');
+ --digits;
+ }
+
+ *out = result;
+ return 0;
+}
+
+int read_binary(const char *str, int digits, uint64_t *out)
+{
+ uint64_t x, ov, result = 0;
+ bool first = true;
+
+ while (digits > 0) {
+ x = *((const unsigned char *)str++);
+ --digits;
+
+ if (first) {
+ first = false;
+ if (x == 0xFF) {
+ result = 0xFFFFFFFFFFFFFFFFUL;
+ } else {
+ x &= 0x7F;
+ result = 0;
+ if (digits > 7 && x != 0)
+ goto fail_ov;
+ }
+ }
+
+ ov = (result >> 56) & 0xFF;
+
+ if (ov != 0 && ov != 0xFF)
+ goto fail_ov;
+
+ result = (result << 8) | x;
+ }
+
+ *out = result;
+ return 0;
+fail_ov:
+ fputs("numeric overflow parsing tar header\n", stderr);
+ return -1;
+}
+
+int read_number(const char *str, int digits, uint64_t *out)
+{
+ if (*((unsigned char *)str) & 0x80)
+ return read_binary(str, digits, out);
+
+ return read_octal(str, digits, out);
+}
+
+int pax_read_decimal(const char *str, uint64_t *out)
+{
+ uint64_t result = 0;
+
+ while (*str >= '0' && *str <= '9') {
+ if (result > 0xFFFFFFFFFFFFFFFFUL / 10) {
+ fputs("numeric overflow parsing pax header\n", stderr);
+ return -1;
+ }
+
+ result = (result * 10) + (*(str++) - '0');
+ }
+
+ *out = result;
+ return 0;
+}
+
+void write_octal(char *dst, unsigned int value, int digits)
+{
+ char temp[64];
+
+ sprintf(temp, "%0*o ", digits, value);
+ memcpy(dst, temp, strlen(temp));
+}
diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c
index de6f0cd..067b1df 100644
--- a/lib/tar/read_header.c
+++ b/lib/tar/read_header.c
@@ -1,104 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
-#include "util.h"
-#include "tar.h"
-
-#include <sys/sysmacros.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdio.h>
-
-enum {
- PAX_SIZE = 0x001,
- PAX_UID = 0x002,
- PAX_GID = 0x004,
- PAX_DEV_MAJ = 0x008,
- PAX_DEV_MIN = 0x010,
- PAX_NAME = 0x020,
- PAX_SLINK_TARGET = 0x040,
- PAX_ATIME = 0x080,
- PAX_MTIME = 0x100,
- PAX_CTIME = 0x200,
- PAX_SPARSE_SIZE = 0x400,
-};
-
-static void free_sparse_list(sparse_map_t *sparse)
-{
- sparse_map_t *old;
-
- while (sparse != NULL) {
- old = sparse;
- sparse = sparse->next;
- free(old);
- }
-}
-
-static int read_octal(const char *str, int digits, uint64_t *out)
-{
- uint64_t result = 0;
-
- while (digits > 0 && isspace(*str)) {
- ++str;
- --digits;
- }
-
- while (digits > 0 && *str >= '0' && *str <= '7') {
- if (result > 0x1FFFFFFFFFFFFFFFUL) {
- fputs("numeric overflow parsing tar header\n", stderr);
- return -1;
- }
-
- result = (result << 3) | (*(str++) - '0');
- --digits;
- }
-
- *out = result;
- return 0;
-}
-
-static int read_binary(const char *str, int digits, uint64_t *out)
-{
- uint64_t x, ov, result;
- bool first = true;
-
- while (digits > 0) {
- x = *((const unsigned char *)str++);
- --digits;
-
- if (first) {
- first = false;
- if (x == 0xFF) {
- result = 0xFFFFFFFFFFFFFFFFUL;
- } else {
- x &= 0x7F;
- result = 0;
- if (digits > 7 && x != 0)
- goto fail_ov;
- }
- }
-
- ov = (result >> 56) & 0xFF;
-
- if (ov != 0 && ov != 0xFF)
- goto fail_ov;
-
- result = (result << 8) | x;
- }
-
- *out = result;
- return 0;
-fail_ov:
- fputs("numeric overflow parsing tar header\n", stderr);
- return -1;
-}
-
-static int read_number(const char *str, int digits, uint64_t *out)
-{
- if (*((unsigned char *)str) & 0x80)
- return read_binary(str, digits, out);
-
- return read_octal(str, digits, out);
-}
+#include "internal.h"
static bool is_zero_block(const tar_header_t *hdr)
{
@@ -107,26 +8,7 @@ static bool is_zero_block(const tar_header_t *hdr)
return ptr[0] == '\0' && memcmp(ptr, ptr + 1, sizeof(*hdr) - 1) == 0;
}
-static bool is_checksum_valid(const tar_header_t *hdr)
-{
- unsigned int chksum = 0;
- tar_header_t copy;
- uint64_t ref;
- size_t i;
-
- if (read_octal(hdr->chksum, sizeof(hdr->chksum), &ref))
- return false;
-
- memcpy(&copy, hdr, sizeof(*hdr));
- memset(copy.chksum, ' ', sizeof(copy.chksum));
-
- for (i = 0; i < sizeof(copy); ++i)
- chksum += ((unsigned char *)&copy)[i];
-
- return chksum == ref;
-}
-
-static E_TAR_VERSION check_version(const tar_header_t *hdr)
+static int check_version(const tar_header_t *hdr)
{
char buffer[sizeof(hdr->magic) + sizeof(hdr->version)];
@@ -146,65 +28,35 @@ static E_TAR_VERSION check_version(const tar_header_t *hdr)
return ETV_UNKNOWN;
}
-static int pax_read_decimal(const char *str, uint64_t *out)
-{
- uint64_t result = 0;
-
- while (*str >= '0' && *str <= '9') {
- if (result > 0xFFFFFFFFFFFFFFFFUL / 10) {
- fputs("numeric overflow parsing pax header\n", stderr);
- return -1;
- }
-
- result = (result * 10) + (*(str++) - '0');
- }
-
- *out = result;
- return 0;
-}
-
-static sparse_map_t *read_sparse_map(const char *line)
+static char *record_to_memory(int fd, uint64_t size)
{
- sparse_map_t *last = NULL, *list = NULL, *ent = NULL;
-
- do {
- ent = calloc(1, sizeof(*ent));
- if (ent == NULL)
- goto fail_errno;
-
- if (pax_read_decimal(line, &ent->offset))
- goto fail_format;
-
- while (isdigit(*line))
- ++line;
-
- if (*(line++) != ',')
- goto fail_format;
+ char *buffer = malloc(size + 1);
+ ssize_t ret;
- if (pax_read_decimal(line, &ent->count))
- goto fail_format;
+ if (buffer == NULL)
+ goto fail_errno;
- while (isdigit(*line))
- ++line;
+ ret = read_retry(fd, buffer, size);
+ if (ret == 0)
+ goto fail_eof;
+ if (ret < 0)
+ goto fail_errno;
+ if ((uint64_t)ret < size)
+ goto fail_eof;
- if (last == NULL) {
- list = last = ent;
- } else {
- last->next = ent;
- last = ent;
- }
- } while (*(line++) == ',');
+ if (skip_padding(fd, size))
+ goto fail;
- return list;
+ buffer[size] = '\0';
+ return buffer;
fail_errno:
- perror("parsing GNU pax sparse file record");
+ perror("reading tar record");
goto fail;
-fail_format:
- fputs("malformed GNU pax sparse file record\n", stderr);
+fail_eof:
+ fputs("reading tar record: unexpected end of file\n", stderr);
goto fail;
fail:
- free_sparse_list(list);
- free(ent);
+ free(buffer);
return NULL;
}
@@ -214,23 +66,11 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,
sparse_map_t *sparse_last = NULL, *sparse;
uint64_t field, offset = 0, num_bytes = 0;
char *buffer, *line;
- ssize_t ret;
uint64_t i;
- buffer = malloc(entsize + 1);
+ buffer = record_to_memory(fd, entsize);
if (buffer == NULL)
- goto fail_errno;
-
- ret = read_retry(fd, buffer, entsize);
- if (ret < 0)
- goto fail_errno;
- if ((size_t)ret < entsize)
- goto fail_eof;
-
- if (skip_padding(fd, entsize))
- goto fail;
-
- buffer[entsize] = '\0';
+ return -1;
for (i = 0; i < entsize; ++i) {
while (i < entsize && isspace(buffer[i]))
@@ -251,12 +91,12 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,
if (!strncmp(line, "uid=", 4)) {
if (pax_read_decimal(line + 4, &field))
- return -1;
+ goto fail;
out->sb.st_uid = field;
*set_by_pax |= PAX_UID;
} else if (!strncmp(line, "gid=", 4)) {
if (pax_read_decimal(line + 4, &field))
- return -1;
+ goto fail;
out->sb.st_gid = field;
*set_by_pax |= PAX_GID;
} else if (!strncmp(line, "path=", 5)) {
@@ -267,7 +107,7 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,
*set_by_pax |= PAX_NAME;
} else if (!strncmp(line, "size=", 5)) {
if (pax_read_decimal(line + 5, &out->record_size))
- return -1;
+ goto fail;
*set_by_pax |= PAX_SIZE;
} else if (!strncmp(line, "linkpath=", 9)) {
free(out->link_target);
@@ -278,33 +118,33 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,
} else if (!strncmp(line, "atime=", 6)) {
if (line[6] == '-') {
if (pax_read_decimal(line + 7, &field))
- return -1;
+ goto fail;
out->sb.st_atime = -((int64_t)field);
} else {
if (pax_read_decimal(line + 6, &field))
- return -1;
+ goto fail;
out->sb.st_atime = field;
}
*set_by_pax |= PAX_ATIME;
} else if (!strncmp(line, "mtime=", 6)) {
if (line[6] == '-') {
if (pax_read_decimal(line + 7, &field))
- return -1;
+ goto fail;
out->sb.st_mtime = -((int64_t)field);
} else {
if (pax_read_decimal(line + 6, &field))
- return -1;
+ goto fail;
out->sb.st_mtime = field;
}
*set_by_pax |= PAX_MTIME;
} else if (!strncmp(line, "ctime=", 6)) {
if (line[6] == '-') {
if (pax_read_decimal(line + 7, &field))
- return -1;
+ goto fail;
out->sb.st_ctime = -((int64_t)field);
} else {
if (pax_read_decimal(line + 6, &field))
- return -1;
+ goto fail;
out->sb.st_ctime = field;
}
*set_by_pax |= PAX_CTIME;
@@ -323,14 +163,14 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,
goto fail;
} else if (!strncmp(line, "GNU.sparse.size=", 16)) {
if (pax_read_decimal(line + 16, &out->actual_size))
- return -1;
+ goto fail;
*set_by_pax |= PAX_SPARSE_SIZE;
} else if (!strncmp(line, "GNU.sparse.offset=", 18)) {
if (pax_read_decimal(line + 18, &offset))
- return -1;
+ goto fail;
} else if (!strncmp(line, "GNU.sparse.numbytes=", 20)) {
if (pax_read_decimal(line + 20, &num_bytes))
- return -1;
+ goto fail;
sparse = calloc(1, sizeof(*sparse));
if (sparse == NULL)
goto fail_errno;
@@ -351,16 +191,13 @@ static int read_pax_header(int fd, uint64_t entsize, unsigned int *set_by_pax,
fail_errno:
perror("reading pax header");
goto fail;
-fail_eof:
- fputs("reading pax header: unexpected end of file\n", stderr);
- goto fail;
fail:
free(buffer);
return -1;
}
static int decode_header(const tar_header_t *hdr, unsigned int set_by_pax,
- tar_header_decoded_t *out, E_TAR_VERSION version)
+ tar_header_decoded_t *out, int version)
{
uint64_t field;
size_t count;
@@ -520,132 +357,13 @@ static int decode_header(const tar_header_t *hdr, unsigned int set_by_pax,
return 0;
}
-static char *record_to_memory(int fd, uint64_t size)
-{
- char *buffer = malloc(size + 1);
- ssize_t ret;
-
- if (buffer == NULL)
- goto fail_errno;
-
- ret = read_retry(fd, buffer, size);
- if (ret == 0)
- goto fail_eof;
- if (ret < 0)
- goto fail_errno;
- if ((uint64_t)ret < size)
- goto fail_eof;
-
- if (skip_padding(fd, size))
- goto fail;
-
- return buffer;
-fail_errno:
- perror("reading tar record");
- goto fail;
-fail_eof:
- fputs("reading tar record: unexpected end of file\n", stderr);
- goto fail;
-fail:
- free(buffer);
- return NULL;
-}
-
-static sparse_map_t *read_gnu_old_sparse(int fd, tar_header_t *hdr)
-{
- sparse_map_t *list = NULL, *end = NULL, *node;
- gnu_sparse_t sph;
- uint64_t off, sz;
- ssize_t ret;
- int i;
-
- 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 = read_retry(fd, &sph, sizeof(sph));
- if (ret < 0)
- goto fail_errno;
- if ((size_t)ret < sizeof(sph))
- goto fail_eof;
-
- 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_eof:
- fputs("parsing GNU sparse header: unexpected end of file", stderr);
- goto fail;
-fail_errno:
- perror("parsing GNU sparse header");
- goto fail;
-fail:
- free_sparse_list(list);
- return NULL;
-}
-
int read_header(int fd, tar_header_decoded_t *out)
{
unsigned int set_by_pax = 0;
bool prev_was_zero = false;
- E_TAR_VERSION version;
uint64_t pax_size;
tar_header_t hdr;
- int ret;
+ int ret, version;
memset(out, 0, sizeof(*out));
@@ -744,11 +462,3 @@ fail:
clear_header(out);
return -1;
}
-
-void clear_header(tar_header_decoded_t *hdr)
-{
- free_sparse_list(hdr->sparse);
- free(hdr->name);
- free(hdr->link_target);
- memset(hdr, 0, sizeof(*hdr));
-}
diff --git a/lib/tar/read_sparse_map.c b/lib/tar/read_sparse_map.c
new file mode 100644
index 0000000..77876f5
--- /dev/null
+++ b/lib/tar/read_sparse_map.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "internal.h"
+
+sparse_map_t *read_sparse_map(const char *line)
+{
+ sparse_map_t *last = NULL, *list = NULL, *ent = NULL;
+
+ do {
+ ent = calloc(1, sizeof(*ent));
+ if (ent == NULL)
+ goto fail_errno;
+
+ if (pax_read_decimal(line, &ent->offset))
+ goto fail_format;
+
+ while (isdigit(*line))
+ ++line;
+
+ if (*(line++) != ',')
+ goto fail_format;
+
+ if (pax_read_decimal(line, &ent->count))
+ goto fail_format;
+
+ while (isdigit(*line))
+ ++line;
+
+ if (last == NULL) {
+ list = last = ent;
+ } else {
+ last->next = ent;
+ last = ent;
+ }
+ } while (*(line++) == ',');
+
+ return list;
+fail_errno:
+ perror("parsing GNU pax sparse file record");
+ goto fail;
+fail_format:
+ fputs("malformed GNU pax sparse file record\n", stderr);
+ goto fail;
+fail:
+ free_sparse_list(list);
+ free(ent);
+ return NULL;
+}
diff --git a/lib/tar/read_sparse_map_old.c b/lib/tar/read_sparse_map_old.c
new file mode 100644
index 0000000..c0b2d0d
--- /dev/null
+++ b/lib/tar/read_sparse_map_old.c
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "internal.h"
+
+sparse_map_t *read_gnu_old_sparse(int fd, tar_header_t *hdr)
+{
+ sparse_map_t *list = NULL, *end = NULL, *node;
+ gnu_sparse_t sph;
+ uint64_t off, sz;
+ ssize_t ret;
+ int i;
+
+ 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 = read_retry(fd, &sph, sizeof(sph));
+ if (ret < 0)
+ goto fail_errno;
+ if ((size_t)ret < sizeof(sph))
+ goto fail_eof;
+
+ 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_eof:
+ fputs("parsing GNU sparse header: unexpected end of file", stderr);
+ goto fail;
+fail_errno:
+ perror("parsing GNU sparse header");
+ goto fail;
+fail:
+ free_sparse_list(list);
+ return NULL;
+}
diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c
index 0670523..b84324b 100644
--- a/lib/tar/write_header.c
+++ b/lib/tar/write_header.c
@@ -1,22 +1,9 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
-#include "util.h"
-#include "tar.h"
-
-#include <sys/sysmacros.h>
-#include <string.h>
-#include <stdio.h>
+#include "internal.h"
static unsigned long pax_hdr_counter = 0;
static char buffer[4096];
-static void write_octal(char *dst, unsigned int value, int digits)
-{
- char temp[64];
-
- sprintf(temp, "%0*o ", digits, value);
- memcpy(dst, temp, strlen(temp));
-}
-
static int name_to_tar_header(tar_header_t *hdr, const char *path)
{
size_t len = strlen(path);
@@ -80,21 +67,6 @@ static void init_header(tar_header_t *hdr, const struct stat *sb,
sprintf(hdr->gname, "%u", sb->st_gid);
}
-static void update_checksum(tar_header_t *hdr)
-{
- unsigned int chksum = 0;
- size_t i;
-
- memset(hdr->chksum, ' ', sizeof(hdr->chksum));
-
- for (i = 0; i < sizeof(*hdr); ++i)
- chksum += ((unsigned char *)hdr)[i];
-
- write_octal(hdr->chksum, chksum, 6);
- hdr->chksum[6] = '\0';
- hdr->chksum[7] = ' ';
-}
-
static bool need_pax_header(const struct stat *sb, const char *name)
{
tar_header_t tmp;