From cccbd5aa139b8e0cac233f317cb3e7252daae0d9 Mon Sep 17 00:00:00 2001
From: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
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 <david.oberhollenzer@sigma-star.at>
---
 lib/tar/write_header.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

(limited to 'lib')

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;
 
-- 
cgit v1.2.3