summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_write_disk.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2009-03-06 04:55:51 +0000
committerkientzle <kientzle@FreeBSD.org>2009-03-06 04:55:51 +0000
commit0e3959e0048adeb8162dda94e7d22719dc53d19d (patch)
treee7f6ccf2c08974aeaad7391510b0ad147506d8f5 /lib/libarchive/archive_write_disk.c
parent409cc977f6064716e39b1fec8562cb8aaab07e48 (diff)
downloadFreeBSD-src-0e3959e0048adeb8162dda94e7d22719dc53d19d.zip
FreeBSD-src-0e3959e0048adeb8162dda94e7d22719dc53d19d.tar.gz
Merge r416 from libarchive.googlecode.com:
Restoring POSIX.1e Extended Attributes on FreeBSD, part 1 This implements the basic ability to restore extended attributes on FreeBSD, including a test suite.
Diffstat (limited to 'lib/libarchive/archive_write_disk.c')
-rw-r--r--lib/libarchive/archive_write_disk.c99
1 files changed, 93 insertions, 6 deletions
diff --git a/lib/libarchive/archive_write_disk.c b/lib/libarchive/archive_write_disk.c
index a9417f4..b684150 100644
--- a/lib/libarchive/archive_write_disk.c
+++ b/lib/libarchive/archive_write_disk.c
@@ -33,6 +33,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_ACL_H
#include <sys/acl.h>
#endif
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
#ifdef HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#endif
@@ -411,6 +414,8 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
a->todo |= TODO_TIMES;
if (a->flags & ARCHIVE_EXTRACT_ACL)
a->todo |= TODO_ACLS;
+ if (a->flags & ARCHIVE_EXTRACT_XATTR)
+ a->todo |= TODO_XATTR;
if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
a->todo |= TODO_FFLAGS;
if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
@@ -425,6 +430,17 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
ret = restore_entry(a);
+ /*
+ * On the GNU tar mailing list, some people working with new
+ * Linux filesystems observed that system xattrs used as
+ * layout hints need to be restored before the file contents
+ * are written, so this can't be done at file close.
+ */
+ if (a->todo & TODO_XATTR) {
+ int r2 = set_xattrs(a);
+ if (r2 < ret) ret = r2;
+ }
+
#ifdef HAVE_FCHDIR
/* If we changed directory above, restore it here. */
if (a->restore_pwd >= 0) {
@@ -720,14 +736,18 @@ _archive_write_finish_entry(struct archive *_a)
int r2 = set_acls(a);
if (r2 < ret) ret = r2;
}
- if (a->todo & TODO_XATTR) {
- int r2 = set_xattrs(a);
- if (r2 < ret) ret = r2;
- }
+ /*
+ * Some flags prevent file modification; they must be restored after
+ * file contents are written.
+ */
if (a->todo & TODO_FFLAGS) {
int r2 = set_fflags(a);
if (r2 < ret) ret = r2;
}
+ /*
+ * Time has to be restored after all other metadata;
+ * otherwise atime will get changed.
+ */
if (a->todo & TODO_TIMES) {
int r2 = set_times(a);
if (r2 < ret) ret = r2;
@@ -1012,7 +1032,8 @@ restore_entry(struct archive_write_disk *a)
if (en) {
/* Everything failed; give up here. */
- archive_set_error(&a->archive, en, "Can't create '%s'", a->name);
+ archive_set_error(&a->archive, en, "Can't create '%s'",
+ a->name);
return (ARCHIVE_FAILED);
}
@@ -1657,7 +1678,8 @@ create_dir(struct archive_write_disk *a, char *path)
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
return (ARCHIVE_OK);
- archive_set_error(&a->archive, errno, "Failed to create dir '%s'", path);
+ archive_set_error(&a->archive, errno, "Failed to create dir '%s'",
+ path);
return (ARCHIVE_FAILED);
}
@@ -2326,6 +2348,71 @@ set_xattrs(struct archive_write_disk *a)
}
return (ret);
}
+#elif HAVE_EXTATTR_SET_FILE
+/*
+ * Restore extended attributes - FreeBSD implementation
+ */
+static int
+set_xattrs(struct archive_write_disk *a)
+{
+ struct archive_entry *entry = a->entry;
+ static int warning_done = 0;
+ int ret = ARCHIVE_OK;
+ int i = archive_entry_xattr_reset(entry);
+
+ while (i--) {
+ const char *name;
+ const void *value;
+ size_t size;
+ archive_entry_xattr_next(entry, &name, &value, &size);
+ if (name != NULL) {
+ int e;
+ int namespace;
+
+ if (strncmp(name, "user.", 5) == 0) {
+ /* "user." attributes go to user namespace */
+ name += 5;
+ namespace = EXTATTR_NAMESPACE_USER;
+ } else {
+ /* Warn about other extended attributes. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Can't restore extended attribute ``%s''",
+ name);
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ errno = 0;
+#if HAVE_EXTATTR_SET_FD
+ if (a->fd >= 0)
+ e = extattr_set_fd(a->fd, namespace, name, value, size);
+ else
+#endif
+ /* TODO: should we use extattr_set_link() instead? */
+ {
+ e = extattr_set_file(archive_entry_pathname(entry),
+ namespace, name, value, size);
+ }
+ if (e != (int)size) {
+ if (errno == ENOTSUP) {
+ if (!warning_done) {
+ warning_done = 1;
+ archive_set_error(&a->archive, errno,
+ "Cannot restore extended "
+ "attributes on this file "
+ "system");
+ }
+ } else {
+ archive_set_error(&a->archive, errno,
+ "Failed to set extended attribute");
+ }
+
+ ret = ARCHIVE_WARN;
+ }
+ }
+ }
+ return (ret);
+}
#else
/*
* Restore extended attributes - stub implementation for unsupported systems
OpenPOWER on IntegriCloud