mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
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.
This commit is contained in:
parent
17fcda1a0b
commit
ce077a6fd8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=189431
|
@ -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
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/* FreeBSD 5.0 and later have ACL support. */
|
||||
/* FreeBSD 5.0 and later have ACL and extattr support. */
|
||||
#if __FreeBSD__ > 4
|
||||
#define HAVE_ACL_CREATE_ENTRY 1
|
||||
#define HAVE_ACL_GET_PERM_NP 1
|
||||
|
@ -101,7 +101,6 @@
|
|||
#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
|
||||
#define HAVE_STRUCT_STAT_ST_FLAGS 1
|
||||
#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
|
||||
#define HAVE_SYS_ACL_H 1
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
|
|
@ -21,6 +21,7 @@ TESTS= \
|
|||
test_empty_write.c \
|
||||
test_entry.c \
|
||||
test_entry_strmode.c \
|
||||
test_extattr_freebsd.c \
|
||||
test_fuzz.c \
|
||||
test_link_resolver.c \
|
||||
test_pax_filename_encoding.c \
|
||||
|
|
154
lib/libarchive/test/test_extattr_freebsd.c
Normal file
154
lib/libarchive/test/test_extattr_freebsd.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*-
|
||||
* Copyright (c) 2003-2009 Tim Kientzle
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "test.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#if defined(__FreeBSD__) && __FreeBSD__ > 4
|
||||
#include <sys/extattr.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Verify extended attribute restore-to-disk. This test is FreeBSD-specific.
|
||||
*/
|
||||
|
||||
DEFINE_TEST(test_extattr_freebsd)
|
||||
{
|
||||
#if !defined(__FreeBSD__)
|
||||
skipping("FreeBSD-specific extattr restore test");
|
||||
#elif __FreeBSD__ < 5
|
||||
skipping("extattr restore supported only on FreeBSD 5.0 and later");
|
||||
#else
|
||||
char buff[64];
|
||||
struct stat st;
|
||||
struct archive *a;
|
||||
struct archive_entry *ae;
|
||||
int n, fd;
|
||||
int extattr_privilege_bug = 0;
|
||||
|
||||
/*
|
||||
* First, do a quick manual set/read of an extended attribute
|
||||
* to verify that the local filesystem does support it. If it
|
||||
* doesn't, we'll simply skip the remaining tests.
|
||||
*/
|
||||
/* Create a test file and try to set an ACL on it. */
|
||||
fd = open("pretest", O_RDWR | O_CREAT, 0777);
|
||||
failure("Could not create test file?!");
|
||||
if (!assert(fd >= 0))
|
||||
return;
|
||||
|
||||
errno = 0;
|
||||
n = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, "testattr", "1234", 4);
|
||||
if (n != 4 && errno == EOPNOTSUPP) {
|
||||
close(fd);
|
||||
skipping("extattr tests require that extattr support be enabled on the filesystem");
|
||||
return;
|
||||
}
|
||||
failure("extattr_set_fd(): errno=%d (%s)", errno, strerror(errno));
|
||||
assertEqualInt(4, n);
|
||||
close(fd);
|
||||
|
||||
/*
|
||||
* Repeat the above, but with file permissions set to 0000.
|
||||
* This should work (extattr_set_fd() should follow fd
|
||||
* permissions, not file permissions), but is known broken on
|
||||
* some versions of FreeBSD.
|
||||
*/
|
||||
fd = open("pretest2", O_RDWR | O_CREAT, 00000);
|
||||
failure("Could not create test file?!");
|
||||
if (!assert(fd >= 0))
|
||||
return;
|
||||
|
||||
n = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, "testattr", "1234", 4);
|
||||
if (n != 4) {
|
||||
skipping("Restoring xattr to an unwritable file (broken in some versions of FreeBSD");
|
||||
extattr_privilege_bug = 1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* Create a write-to-disk object. */
|
||||
assert(NULL != (a = archive_write_disk_new()));
|
||||
archive_write_disk_set_options(a,
|
||||
ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_XATTR);
|
||||
|
||||
/* Populate an archive entry with an extended attribute. */
|
||||
ae = archive_entry_new();
|
||||
assert(ae != NULL);
|
||||
archive_entry_set_pathname(ae, "test0");
|
||||
archive_entry_set_mtime(ae, 123456, 7890);
|
||||
archive_entry_set_size(ae, 0);
|
||||
archive_entry_set_mode(ae, 0755);
|
||||
archive_entry_xattr_add_entry(ae, "user.foo", "12345", 5);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
|
||||
archive_entry_free(ae);
|
||||
|
||||
/* Another entry; similar but with mode = 0. */
|
||||
ae = archive_entry_new();
|
||||
assert(ae != NULL);
|
||||
archive_entry_set_pathname(ae, "test1");
|
||||
archive_entry_set_mtime(ae, 12345678, 7890);
|
||||
archive_entry_set_size(ae, 0);
|
||||
archive_entry_set_mode(ae, 0);
|
||||
archive_entry_xattr_add_entry(ae, "user.bar", "123456", 6);
|
||||
if (extattr_privilege_bug)
|
||||
/* If the bug is here, write_header will return warning. */
|
||||
assertEqualIntA(a, ARCHIVE_WARN,
|
||||
archive_write_header(a, ae));
|
||||
else
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_write_header(a, ae));
|
||||
archive_entry_free(ae);
|
||||
|
||||
/* Close the archive. */
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_write_finish(a));
|
||||
|
||||
/* Verify the data on disk. */
|
||||
assertEqualInt(0, stat("test0", &st));
|
||||
assertEqualInt(st.st_mtime, 123456);
|
||||
/* Verify extattr */
|
||||
n = extattr_get_file("test0", EXTATTR_NAMESPACE_USER,
|
||||
"foo", buff, sizeof(buff));
|
||||
if (assertEqualInt(n, 5)) {
|
||||
buff[n] = '\0';
|
||||
assertEqualString(buff, "12345");
|
||||
}
|
||||
|
||||
/* Verify the data on disk. */
|
||||
assertEqualInt(0, stat("test1", &st));
|
||||
assertEqualInt(st.st_mtime, 12345678);
|
||||
/* Verify extattr */
|
||||
n = extattr_get_file("test1", EXTATTR_NAMESPACE_USER,
|
||||
"bar", buff, sizeof(buff));
|
||||
if (extattr_privilege_bug) {
|
||||
/* If we have the bug, the extattr won't have been written. */
|
||||
assertEqualInt(n, -1);
|
||||
} else {
|
||||
if (assertEqualInt(n, 6)) {
|
||||
buff[n] = '\0';
|
||||
assertEqualString(buff, "123456");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
Loading…
Reference in a new issue