From cccbd5aa139b8e0cac233f317cb3e7252daae0d9 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 1 Aug 2019 16:03:59 +0200 Subject: Add ability to write_tar_header to embedd extended attributes This commit patches the tar writer to generate a PAX header with SCHILY xattr key/value pairs if requested. The Schily format is used for two reasons: - It is simple - It is apparently more widely supported than the libarchive format Signed-off-by: David Oberhollenzer --- include/tar.h | 3 ++- lib/tar/write_header.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- tar/sqfs2tar.c | 2 +- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/include/tar.h b/include/tar.h index cb56ff0..44db5fe 100644 --- a/include/tar.h +++ b/include/tar.h @@ -113,7 +113,8 @@ typedef struct { headers need to be generated. */ int write_tar_header(int fd, const struct stat *sb, const char *name, - const char *slink_target, unsigned int counter); + const char *slink_target, const tar_xattr_t *xattr, + unsigned int counter); /* calcuate and skip the zero padding */ int skip_padding(int fd, uint64_t size); diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c index e4d4d38..d3a184a 100644 --- a/lib/tar/write_header.c +++ b/lib/tar/write_header.c @@ -112,13 +112,64 @@ static int write_gnu_header(int fd, const struct stat *orig, return padd_file(fd, payload_len, 512); } +static size_t num_digits(size_t num) +{ + size_t i = 1; + + while (num > 10) { + num /= 10; + ++i; + } + + return i; +} + +static int write_schily_xattr(int fd, const struct stat *orig, + const char *name, const tar_xattr_t *xattr) +{ + static const char *prefix = "SCHILY.xattr."; + size_t len, total_size = 0; + const tar_xattr_t *it; + struct stat sb; + + for (it = xattr; it != NULL; it = it->next) { + len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2; + + total_size += num_digits(len) + 1 + len; + } + + sb = *orig; + sb.st_mode = S_IFREG | 0644; + sb.st_size = total_size; + + if (write_header(fd, &sb, name, NULL, TAR_TYPE_PAX)) + return -1; + + for (it = xattr; it != NULL; it = it->next) { + len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2; + len += num_digits(len) + 1; + + dprintf(fd, "%zu %s%s=%s\n", len, prefix, it->key, it->value); + } + + return padd_file(fd, total_size, 512); +} + int write_tar_header(int fd, const struct stat *sb, const char *name, - const char *slink_target, unsigned int counter) + const char *slink_target, const tar_xattr_t *xattr, + unsigned int counter) { const char *reason; char buffer[64]; int type; + if (xattr != NULL) { + sprintf(buffer, "pax/xattr%u", counter); + + if (write_schily_xattr(fd, sb, buffer, xattr)) + return -1; + } + if (!S_ISLNK(sb->st_mode)) slink_target = NULL; diff --git a/tar/sqfs2tar.c b/tar/sqfs2tar.c index 13a2339..07be2b4 100644 --- a/tar/sqfs2tar.c +++ b/tar/sqfs2tar.c @@ -211,7 +211,7 @@ static int write_tree_dfs(fstree_t *fs, tree_node_t *n, data_reader_t *data) fstree_node_stat(fs, n, &sb); target = S_ISLNK(sb.st_mode) ? n->data.slink_target : NULL; - ret = write_tar_header(STDOUT_FILENO, &sb, name, target, + ret = write_tar_header(STDOUT_FILENO, &sb, name, target, NULL, record_counter++); if (ret > 0) { -- cgit v1.2.3