diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-04-17 23:20:35 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-04-17 23:31:32 +0200 | 
| commit | 1fe3f86230a970b3974f16a6bc2e819fdaf55b58 (patch) | |
| tree | 7f9f097840a68e0e6605059c9ebb2f8ee2d3fbfd /lib | |
| parent | 15250710c63a2c3d230304e46a03532f787759fb (diff) | |
Cleanup: split read_header.c in libtar.a
Simply moving the pax header decoding to a separate file and splitting
out the common helper functions should be a good start.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/tar/Makemodule.am | 2 | ||||
| -rw-r--r-- | lib/tar/internal.h | 5 | ||||
| -rw-r--r-- | lib/tar/pax_header.c | 183 | ||||
| -rw-r--r-- | lib/tar/read_header.c | 197 | ||||
| -rw-r--r-- | lib/tar/read_retry.c | 27 | 
5 files changed, 213 insertions, 201 deletions
| diff --git a/lib/tar/Makemodule.am b/lib/tar/Makemodule.am index abc0209..a47b07a 100644 --- a/lib/tar/Makemodule.am +++ b/lib/tar/Makemodule.am @@ -3,7 +3,7 @@ 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/write_retry.c +libtar_a_SOURCES += lib/tar/write_retry.c lib/tar/pax_header.c  libtar_a_CFLAGS = $(AM_CFLAGS)  libtar_a_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/lib/tar/internal.h b/lib/tar/internal.h index 0220f05..755d4eb 100644 --- a/lib/tar/internal.h +++ b/lib/tar/internal.h @@ -65,4 +65,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); + +int read_pax_header(FILE *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 new file mode 100644 index 0000000..4eeabf5 --- /dev/null +++ b/lib/tar/pax_header.c @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * pax_header.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "config.h" + +#include "internal.h" + +static tar_xattr_t *mkxattr(const char *key, size_t keylen, +			    const char *value, size_t valuelen) +{ +	tar_xattr_t *xattr; + +	xattr = calloc(1, sizeof(*xattr) + keylen + 1 + valuelen + 1); +	if (xattr == NULL) +		return NULL; + +	xattr->key = xattr->data; +	xattr->value = (sqfs_u8 *)xattr->data + keylen + 1; +	xattr->value_len = valuelen; +	memcpy(xattr->key, key, keylen); +	memcpy(xattr->value, value, valuelen); +	return xattr; +} + +int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax, +		    tar_header_decoded_t *out) +{ +	char *buffer, *line, *key, *ptr, *value, *end; +	sparse_map_t *sparse_last = NULL, *sparse; +	sqfs_u64 field, offset = 0, num_bytes = 0; +	tar_xattr_t *xattr; +	long len; + +	buffer = record_to_memory(fp, entsize); +	if (buffer == NULL) +		return -1; + +	end = buffer + entsize; + +	for (line = buffer; line < end; line += len) { +		len = strtol(line, &ptr, 10); +		if (ptr == line || !isspace(*ptr) || len <= 0) +			goto fail_malformed; + +		if (len > (end - line)) +			goto fail_ov; + +		line[len - 1] = '\0'; + +		while (ptr < end && isspace(*ptr)) +			++ptr; + +		if (ptr >= end || (ptr - line) >= len) +			goto fail_malformed; + +		if (!strncmp(ptr, "uid=", 4)) { +			if (pax_read_decimal(ptr + 4, &field)) +				goto fail; +			out->sb.st_uid = field; +			*set_by_pax |= PAX_UID; +		} else if (!strncmp(ptr, "gid=", 4)) { +			if (pax_read_decimal(ptr + 4, &field)) +				goto fail; +			out->sb.st_gid = field; +			*set_by_pax |= PAX_GID; +		} else if (!strncmp(ptr, "path=", 5)) { +			free(out->name); +			out->name = strdup(ptr + 5); +			if (out->name == NULL) +				goto fail_errno; +			*set_by_pax |= PAX_NAME; +		} else if (!strncmp(ptr, "size=", 5)) { +			if (pax_read_decimal(ptr + 5, &out->record_size)) +				goto fail; +			*set_by_pax |= PAX_SIZE; +		} else if (!strncmp(ptr, "linkpath=", 9)) { +			free(out->link_target); +			out->link_target = strdup(ptr + 9); +			if (out->link_target == NULL) +				goto fail_errno; +			*set_by_pax |= PAX_SLINK_TARGET; +		} else if (!strncmp(ptr, "mtime=", 6)) { +			if (ptr[6] == '-') { +				if (pax_read_decimal(ptr + 7, &field)) +					goto fail; +				out->mtime = -((sqfs_s64)field); +			} else { +				if (pax_read_decimal(ptr + 6, &field)) +					goto fail; +				out->mtime = field; +			} +			*set_by_pax |= PAX_MTIME; +		} else if (!strncmp(ptr, "GNU.sparse.name=", 16)) { +			free(out->name); +			out->name = strdup(ptr + 16); +			if (out->name == NULL) +				goto fail_errno; +			*set_by_pax |= PAX_NAME; +		} else if (!strncmp(ptr, "GNU.sparse.map=", 15)) { +			free_sparse_list(out->sparse); +			sparse_last = NULL; + +			out->sparse = read_sparse_map(ptr + 15); +			if (out->sparse == NULL) +				goto fail; +		} else if (!strncmp(ptr, "GNU.sparse.size=", 16)) { +			if (pax_read_decimal(ptr + 16, &out->actual_size)) +				goto fail; +			*set_by_pax |= PAX_SPARSE_SIZE; +		} else if (!strncmp(ptr, "GNU.sparse.offset=", 18)) { +			if (pax_read_decimal(ptr + 18, &offset)) +				goto fail; +		} else if (!strncmp(ptr, "GNU.sparse.numbytes=", 20)) { +			if (pax_read_decimal(ptr + 20, &num_bytes)) +				goto fail; +			sparse = calloc(1, sizeof(*sparse)); +			if (sparse == NULL) +				goto fail_errno; +			sparse->offset = offset; +			sparse->count = num_bytes; +			if (sparse_last == NULL) { +				free_sparse_list(out->sparse); +				out->sparse = sparse_last = sparse; +			} else { +				sparse_last->next = sparse; +				sparse_last = sparse; +			} +		} else if (!strncmp(ptr, "SCHILY.xattr.", 13)) { +			key = ptr + 13; + +			ptr = strrchr(key, '='); +			if (ptr == NULL || ptr == key) +				continue; + +			value = ptr + 1; + +			xattr = mkxattr(key, ptr - key, +					value, len - (value - line) - 1); +			if (xattr == NULL) +				goto fail_errno; + +			xattr->next = out->xattr; +			out->xattr = xattr; +		} else if (!strncmp(ptr, "LIBARCHIVE.xattr.", 17)) { +			key = ptr + 17; + +			ptr = strrchr(key, '='); +			if (ptr == NULL || ptr == key) +				continue; + +			value = ptr + 1; + +			xattr = mkxattr(key, ptr - key, value, strlen(value)); +			if (xattr == NULL) +				goto fail_errno; + +			urldecode(xattr->key); +			xattr->value_len = base64_decode(xattr->value, value, +							 xattr->value_len); + +			xattr->next = out->xattr; +			out->xattr = xattr; +		} +	} + +	free(buffer); +	return 0; +fail_malformed: +	fputs("Found a malformed PAX header.\n", stderr); +	goto fail; +fail_ov: +	fputs("Numeric overflow in PAX header.\n", stderr); +	goto fail; +fail_errno: +	perror("reading pax header"); +	goto fail; +fail: +	free(buffer); +	return -1; +} diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c index de6b0de..0591879 100644 --- a/lib/tar/read_header.c +++ b/lib/tar/read_header.c @@ -35,203 +35,6 @@ static int check_version(const tar_header_t *hdr)  	return ETV_UNKNOWN;  } -static 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; -} - -static tar_xattr_t *mkxattr(const char *key, size_t keylen, -			    const char *value, size_t valuelen) -{ -	tar_xattr_t *xattr; - -	xattr = calloc(1, sizeof(*xattr) + keylen + 1 + valuelen + 1); -	if (xattr == NULL) -		return NULL; - -	xattr->key = xattr->data; -	xattr->value = (sqfs_u8 *)xattr->data + keylen + 1; -	xattr->value_len = valuelen; -	memcpy(xattr->key, key, keylen); -	memcpy(xattr->value, value, valuelen); -	return xattr; -} - -static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax, -			   tar_header_decoded_t *out) -{ -	char *buffer, *line, *key, *ptr, *value, *end; -	sparse_map_t *sparse_last = NULL, *sparse; -	sqfs_u64 field, offset = 0, num_bytes = 0; -	tar_xattr_t *xattr; -	long len; - -	buffer = record_to_memory(fp, entsize); -	if (buffer == NULL) -		return -1; - -	end = buffer + entsize; - -	for (line = buffer; line < end; line += len) { -		len = strtol(line, &ptr, 10); -		if (ptr == line || !isspace(*ptr) || len <= 0) -			goto fail_malformed; - -		if (len > (end - line)) -			goto fail_ov; - -		line[len - 1] = '\0'; - -		while (ptr < end && isspace(*ptr)) -			++ptr; - -		if (ptr >= end || (ptr - line) >= len) -			goto fail_malformed; - -		if (!strncmp(ptr, "uid=", 4)) { -			if (pax_read_decimal(ptr + 4, &field)) -				goto fail; -			out->sb.st_uid = field; -			*set_by_pax |= PAX_UID; -		} else if (!strncmp(ptr, "gid=", 4)) { -			if (pax_read_decimal(ptr + 4, &field)) -				goto fail; -			out->sb.st_gid = field; -			*set_by_pax |= PAX_GID; -		} else if (!strncmp(ptr, "path=", 5)) { -			free(out->name); -			out->name = strdup(ptr + 5); -			if (out->name == NULL) -				goto fail_errno; -			*set_by_pax |= PAX_NAME; -		} else if (!strncmp(ptr, "size=", 5)) { -			if (pax_read_decimal(ptr + 5, &out->record_size)) -				goto fail; -			*set_by_pax |= PAX_SIZE; -		} else if (!strncmp(ptr, "linkpath=", 9)) { -			free(out->link_target); -			out->link_target = strdup(ptr + 9); -			if (out->link_target == NULL) -				goto fail_errno; -			*set_by_pax |= PAX_SLINK_TARGET; -		} else if (!strncmp(ptr, "mtime=", 6)) { -			if (ptr[6] == '-') { -				if (pax_read_decimal(ptr + 7, &field)) -					goto fail; -				out->mtime = -((sqfs_s64)field); -			} else { -				if (pax_read_decimal(ptr + 6, &field)) -					goto fail; -				out->mtime = field; -			} -			*set_by_pax |= PAX_MTIME; -		} else if (!strncmp(ptr, "GNU.sparse.name=", 16)) { -			free(out->name); -			out->name = strdup(ptr + 16); -			if (out->name == NULL) -				goto fail_errno; -			*set_by_pax |= PAX_NAME; -		} else if (!strncmp(ptr, "GNU.sparse.map=", 15)) { -			free_sparse_list(out->sparse); -			sparse_last = NULL; - -			out->sparse = read_sparse_map(ptr + 15); -			if (out->sparse == NULL) -				goto fail; -		} else if (!strncmp(ptr, "GNU.sparse.size=", 16)) { -			if (pax_read_decimal(ptr + 16, &out->actual_size)) -				goto fail; -			*set_by_pax |= PAX_SPARSE_SIZE; -		} else if (!strncmp(ptr, "GNU.sparse.offset=", 18)) { -			if (pax_read_decimal(ptr + 18, &offset)) -				goto fail; -		} else if (!strncmp(ptr, "GNU.sparse.numbytes=", 20)) { -			if (pax_read_decimal(ptr + 20, &num_bytes)) -				goto fail; -			sparse = calloc(1, sizeof(*sparse)); -			if (sparse == NULL) -				goto fail_errno; -			sparse->offset = offset; -			sparse->count = num_bytes; -			if (sparse_last == NULL) { -				free_sparse_list(out->sparse); -				out->sparse = sparse_last = sparse; -			} else { -				sparse_last->next = sparse; -				sparse_last = sparse; -			} -		} else if (!strncmp(ptr, "SCHILY.xattr.", 13)) { -			key = ptr + 13; - -			ptr = strrchr(key, '='); -			if (ptr == NULL || ptr == key) -				continue; - -			value = ptr + 1; - -			xattr = mkxattr(key, ptr - key, -					value, len - (value - line) - 1); -			if (xattr == NULL) -				goto fail_errno; - -			xattr->next = out->xattr; -			out->xattr = xattr; -		} else if (!strncmp(ptr, "LIBARCHIVE.xattr.", 17)) { -			key = ptr + 17; - -			ptr = strrchr(key, '='); -			if (ptr == NULL || ptr == key) -				continue; - -			value = ptr + 1; - -			xattr = mkxattr(key, ptr - key, value, strlen(value)); -			if (xattr == NULL) -				goto fail_errno; - -			urldecode(xattr->key); -			xattr->value_len = base64_decode(xattr->value, value, -							 xattr->value_len); - -			xattr->next = out->xattr; -			out->xattr = xattr; -		} -	} - -	free(buffer); -	return 0; -fail_malformed: -	fputs("Found a malformed PAX header.\n", stderr); -	goto fail; -fail_ov: -	fputs("Numeric overflow in PAX header.\n", stderr); -	goto fail; -fail_errno: -	perror("reading pax header"); -	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, int version)  { diff --git a/lib/tar/read_retry.c b/lib/tar/read_retry.c index c76e5e5..2a2f82c 100644 --- a/lib/tar/read_retry.c +++ b/lib/tar/read_retry.c @@ -6,10 +6,8 @@   */  #include "config.h" -#include <errno.h> -#include <stdio.h> -  #include "tar.h" +#include "internal.h"  int read_retry(const char *errstr, FILE *fp, void *buffer, size_t size)  { @@ -34,3 +32,26 @@ int read_retry(const char *errstr, FILE *fp, void *buffer, size_t size)  	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; +} | 
