summaryrefslogtreecommitdiffstats
path: root/usr.bin/tar/write.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tar/write.c')
-rw-r--r--usr.bin/tar/write.c137
1 files changed, 125 insertions, 12 deletions
diff --git a/usr.bin/tar/write.c b/usr.bin/tar/write.c
index 8ce18a7..3f08eb0 100644
--- a/usr.bin/tar/write.c
+++ b/usr.bin/tar/write.c
@@ -32,8 +32,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_POSIX_ACL
#include <sys/acl.h>
#endif
-#include <archive.h>
-#include <archive_entry.h>
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
@@ -119,6 +120,8 @@ static int new_enough(struct bsdtar *, const char *path,
const struct stat *);
static void setup_acls(struct bsdtar *, struct archive_entry *,
const char *path);
+static void setup_xattrs(struct bsdtar *, struct archive_entry *,
+ const char *path);
static void test_for_append(struct bsdtar *);
static void write_archive(struct archive *, struct bsdtar *);
static void write_entry(struct bsdtar *, struct archive *,
@@ -444,10 +447,11 @@ archive_names_from_file_helper(struct bsdtar *bsdtar, const char *line)
}
/*
- * Copy from specified archive to current archive.
- * Returns non-zero on fatal error (i.e., output errors). Errors
- * reading the input archive set bsdtar->return_value, but this
- * function will still return zero.
+ * Copy from specified archive to current archive. Returns non-zero
+ * for write errors (which force us to terminate the entire archiving
+ * operation). If there are errors reading the input archive, we set
+ * bsdtar->return_value but return zero, so the overall archiving
+ * operation will complete and return non-zero.
*/
static int
append_archive(struct bsdtar *bsdtar, struct archive *a, const char *filename)
@@ -509,7 +513,8 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, const char *filename)
bsdtar->return_value = 1;
}
- return (0); /* TODO: Return non-zero on error */
+ /* Note: If we got here, we saw no write errors, so return success. */
+ return (0);
}
/*
@@ -741,6 +746,7 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st,
archive_entry_copy_stat(entry, st);
setup_acls(bsdtar, entry, accpath);
+ setup_xattrs(bsdtar, entry, accpath);
/*
* If it's a regular file (and non-zero in size) make sure we
@@ -991,11 +997,11 @@ lookup_hardlink(struct bsdtar *bsdtar, struct archive_entry *entry,
}
#ifdef HAVE_POSIX_ACL
-void setup_acl(struct bsdtar *bsdtar,
+static void setup_acl(struct bsdtar *bsdtar,
struct archive_entry *entry, const char *accpath,
int acl_type, int archive_entry_acl_type);
-void
+static void
setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry,
const char *accpath)
{
@@ -1009,7 +1015,7 @@ setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry,
ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
}
-void
+static void
setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry,
const char *accpath, int acl_type, int archive_entry_acl_type)
{
@@ -1073,7 +1079,7 @@ setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry,
}
}
#else
-void
+static void
setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry,
const char *accpath)
{
@@ -1083,13 +1089,120 @@ setup_acls(struct bsdtar *bsdtar, struct archive_entry *entry,
}
#endif
+#if HAVE_LISTXATTR && HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR
+
+static void
+setup_xattr(struct bsdtar *bsdtar, struct archive_entry *entry,
+ const char *accpath, const char *name)
+{
+ size_t size;
+ void *value = NULL;
+ char symlink_mode = bsdtar->symlink_mode;
+
+ if (symlink_mode == 'H')
+ size = getxattr(accpath, name, NULL, 0);
+ else
+ size = lgetxattr(accpath, name, NULL, 0);
+
+ if (size == -1) {
+ bsdtar_warnc(bsdtar, errno, "Couldn't get extended attribute");
+ return;
+ }
+
+ if (size > 0 && (value = malloc(size)) == NULL) {
+ bsdtar_errc(bsdtar, 1, errno, "Out of memory");
+ return;
+ }
+
+ if (symlink_mode == 'H')
+ size = getxattr(accpath, name, value, size);
+ else
+ size = lgetxattr(accpath, name, value, size);
+
+ if (size == -1) {
+ bsdtar_warnc(bsdtar, errno, "Couldn't get extended attribute");
+ return;
+ }
+
+ archive_entry_xattr_add_entry(entry, name, value, size);
+
+ free(value);
+}
+
+/*
+ * Linux extended attribute support
+ */
+static void
+setup_xattrs(struct bsdtar *bsdtar, struct archive_entry *entry,
+ const char *accpath)
+{
+ char *list, *p;
+ size_t list_size;
+ char symlink_mode = bsdtar->symlink_mode;
+
+ if (symlink_mode == 'H')
+ list_size = listxattr(accpath, NULL, 0);
+ else
+ list_size = llistxattr(accpath, NULL, 0);
+
+ if (list_size == -1) {
+ bsdtar_warnc(bsdtar, errno,
+ "Couldn't list extended attributes");
+ return;
+ } else if (list_size == 0)
+ return;
+
+ if ((list = malloc(list_size)) == NULL) {
+ bsdtar_errc(bsdtar, 1, errno, "Out of memory");
+ return;
+ }
+
+ if (symlink_mode == 'H')
+ list_size = listxattr(accpath, list, list_size);
+ else
+ list_size = llistxattr(accpath, list, list_size);
+
+ if (list_size == -1) {
+ bsdtar_warnc(bsdtar, errno,
+ "Couldn't list extended attributes");
+ free(list);
+ return;
+ }
+
+ for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
+ if (strncmp(p, "system.", 7) == 0 ||
+ strncmp(p, "xfsroot.", 8) == 0)
+ continue;
+
+ setup_xattr(bsdtar, entry, accpath, p);
+ }
+
+ free(list);
+}
+
+#else
+
+/*
+ * Generic (stub) extended attribute support.
+ */
+static void
+setup_xattrs(struct bsdtar *bsdtar, struct archive_entry *entry,
+ const char *accpath)
+{
+ (void)bsdtar; /* UNUSED */
+ (void)entry; /* UNUSED */
+ (void)accpath; /* UNUSED */
+}
+
+#endif
+
static void
free_cache(struct name_cache *cache)
{
size_t i;
if (cache != NULL) {
- for(i = 0; i < cache->size; i++) {
+ for (i = 0; i < cache->size; i++) {
if (cache->cache[i].name != NULL &&
cache->cache[i].name != NO_NAME)
free((void *)(uintptr_t)cache->cache[i].name);
OpenPOWER on IntegriCloud