summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-13 15:47:35 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-13 15:49:00 +0100
commit262fc48eb9e246ddb7315f5a14e7f6f58ca987c1 (patch)
treedc3e342ead34d15db452804d445d6621afe64a5e
parent7ab411dbd2cb066652f5f51a1bc6cc793b7cafad (diff)
Better support for reading/writing non-ASCII xattr values from/to tar
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/tar.h3
-rw-r--r--lib/tar/base64.c39
-rw-r--r--lib/tar/internal.h2
-rw-r--r--lib/tar/read_header.c9
-rw-r--r--lib/tar/write_header.c9
-rw-r--r--tar/sqfs2tar.c3
-rw-r--r--tar/tar2sqfs.c2
-rw-r--r--tests/tar_xattr_bsd.c3
-rw-r--r--tests/tar_xattr_schily.c3
9 files changed, 50 insertions, 23 deletions
diff --git a/include/tar.h b/include/tar.h
index c496095..22563c4 100644
--- a/include/tar.h
+++ b/include/tar.h
@@ -71,7 +71,8 @@ typedef struct {
typedef struct tar_xattr_t {
struct tar_xattr_t *next;
char *key;
- char *value;
+ sqfs_u8 *value;
+ size_t value_len;
char data[];
} tar_xattr_t;
diff --git a/lib/tar/base64.c b/lib/tar/base64.c
index 0ccf3c4..f88444a 100644
--- a/lib/tar/base64.c
+++ b/lib/tar/base64.c
@@ -23,18 +23,37 @@ static sqfs_u8 convert(char in)
return 0;
}
-void base64_decode(sqfs_u8 *out, const char *in)
+size_t base64_decode(sqfs_u8 *out, const char *in, size_t len)
{
- char temp[4];
+ sqfs_u8 *start = out;
- while (*in != '\0' && *in != '=') {
- temp[0] = *in == '\0' ? 0 : convert(*(in++));
- temp[1] = *in == '\0' ? 0 : convert(*(in++));
- temp[2] = *in == '\0' ? 0 : convert(*(in++));
- temp[3] = *in == '\0' ? 0 : convert(*(in++));
+ while (len > 0) {
+ unsigned int diff = 0, value = 0;
- *(out++) = ((temp[0] << 2) & 0xFC) | ((temp[1] >> 4) & 0x03);
- *(out++) = ((temp[1] << 4) & 0xF0) | ((temp[2] >> 2) & 0x0F);
- *(out++) = ((temp[2] << 6) & 0xC0) | ( temp[3] & 0x3F);
+ while (diff < 4 && len > 0) {
+ if (*in == '=' || *in == '_' || *in == '\0') {
+ len = 0;
+ } else {
+ value = (value << 6) | convert(*(in++));
+ --len;
+ ++diff;
+ }
+ }
+
+ if (diff < 2)
+ break;
+
+ value <<= 6 * (4 - diff);
+
+ switch (diff) {
+ case 4: out[2] = value & 0xff; /* fall-through */
+ case 3: out[1] = (value >> 8) & 0xff; /* fall-through */
+ default: out[0] = (value >> 16) & 0xff;
+ }
+
+ out += (diff * 3) / 4;
}
+
+ *out = '\0';
+ return out - start;
}
diff --git a/lib/tar/internal.h b/lib/tar/internal.h
index 055637a..0220f05 100644
--- a/lib/tar/internal.h
+++ b/lib/tar/internal.h
@@ -61,7 +61,7 @@ void free_sparse_list(sparse_map_t *sparse);
void free_xattr_list(tar_xattr_t *list);
-void base64_decode(sqfs_u8 *out, const char *in);
+size_t base64_decode(sqfs_u8 *out, const char *in, size_t len);
void urldecode(char *str);
diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c
index 845afc3..20e7a9f 100644
--- a/lib/tar/read_header.c
+++ b/lib/tar/read_header.c
@@ -68,7 +68,8 @@ static tar_xattr_t *mkxattr(const char *key, size_t keylen,
return NULL;
xattr->key = xattr->data;
- xattr->value = xattr->data + keylen + 1;
+ xattr->value = (sqfs_u8 *)xattr->data + keylen + 1;
+ xattr->value_len = valuelen;
memcpy(xattr->key, key, keylen);
memcpy(xattr->value, value, valuelen);
return xattr;
@@ -201,7 +202,8 @@ static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax,
value = ptr + 1;
- xattr = mkxattr(key, ptr - key, value, strlen(value));
+ xattr = mkxattr(key, ptr - key,
+ value, len - (value - line) - 1);
if (xattr == NULL)
goto fail_errno;
@@ -221,7 +223,8 @@ static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax,
goto fail_errno;
urldecode(xattr->key);
- base64_decode((sqfs_u8 *)xattr->value, value);
+ xattr->value_len = base64_decode(xattr->value, value,
+ xattr->value_len);
xattr->next = out->xattr;
out->xattr = xattr;
diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c
index c235014..acce280 100644
--- a/lib/tar/write_header.c
+++ b/lib/tar/write_header.c
@@ -133,7 +133,7 @@ static int write_schily_xattr(FILE *fp, const struct stat *orig,
struct stat sb;
for (it = xattr; it != NULL; it = it->next) {
- len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2;
+ len = strlen(prefix) + strlen(it->key) + it->value_len + 2;
total_size += num_digits(len) + 1 + len;
}
@@ -146,11 +146,12 @@ static int write_schily_xattr(FILE *fp, const struct stat *orig,
return -1;
for (it = xattr; it != NULL; it = it->next) {
- len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2;
+ len = strlen(prefix) + strlen(it->key) + it->value_len + 2;
len += num_digits(len) + 1;
- fprintf(fp, PRI_SZ " %s%s=%s\n", len,
- prefix, it->key, it->value);
+ fprintf(fp, PRI_SZ " %s%s=", len, prefix, it->key);
+ fwrite(it->value, 1, it->value_len, fp);
+ fputc('\n', fp);
}
return padd_file(fp, total_size);
diff --git a/tar/sqfs2tar.c b/tar/sqfs2tar.c
index 6767b95..58fb611 100644
--- a/tar/sqfs2tar.c
+++ b/tar/sqfs2tar.c
@@ -267,9 +267,10 @@ static int get_xattrs(const char *name, const sqfs_inode_generic_t *inode,
ent->key = ent->data;
strcpy(ent->key, (const char *)key->key);
- ent->value = ent->key + strlen(ent->key) + 1;
+ ent->value = (sqfs_u8 *)ent->key + strlen(ent->key) + 1;
memcpy(ent->value, value->value, value->size + 1);
+ ent->value_len = value->size;
ent->next = list;
list = ent;
diff --git a/tar/tar2sqfs.c b/tar/tar2sqfs.c
index 5d40fc5..6be682f 100644
--- a/tar/tar2sqfs.c
+++ b/tar/tar2sqfs.c
@@ -334,7 +334,7 @@ static int copy_xattr(tree_node_t *node, const tar_header_decoded_t *hdr)
}
ret = sqfs_xattr_writer_add(sqfs.xwr, xattr->key, xattr->value,
- strlen(xattr->value));
+ xattr->value_len);
if (ret) {
sqfs_perror(hdr->name, "storing xattr key-value pair",
ret);
diff --git a/tests/tar_xattr_bsd.c b/tests/tar_xattr_bsd.c
index dcaba1e..0741511 100644
--- a/tests/tar_xattr_bsd.c
+++ b/tests/tar_xattr_bsd.c
@@ -54,7 +54,8 @@ int main(void)
assert(hdr.xattr != NULL);
assert(strcmp(hdr.xattr->key, "user.mime_type") == 0);
- assert(strcmp(hdr.xattr->value, "text/plain") == 0);
+ assert(strcmp((const char *)hdr.xattr->value, "text/plain") == 0);
+ assert(hdr.xattr->value_len == 10);
assert(hdr.xattr->next == NULL);
clear_header(&hdr);
diff --git a/tests/tar_xattr_schily.c b/tests/tar_xattr_schily.c
index 6cc31f5..f562b43 100644
--- a/tests/tar_xattr_schily.c
+++ b/tests/tar_xattr_schily.c
@@ -54,7 +54,8 @@ int main(void)
assert(hdr.xattr != NULL);
assert(strcmp(hdr.xattr->key, "user.mime_type") == 0);
- assert(strcmp(hdr.xattr->value, "text/plain") == 0);
+ assert(strcmp((const char *)hdr.xattr->value, "text/plain") == 0);
+ assert(hdr.xattr->value_len == 10);
assert(hdr.xattr->next == NULL);
clear_header(&hdr);