summaryrefslogtreecommitdiffstats
path: root/lib/libarchive
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2005-05-21 19:45:56 +0000
committerkientzle <kientzle@FreeBSD.org>2005-05-21 19:45:56 +0000
commit3c03499e5b87c381757115bd28ead50404867bb6 (patch)
tree204b4462e048dc1ac7dd860da0d069286d7ae4c6 /lib/libarchive
parentd665dce5d09b64996b824cbcbb8180e845cc6364 (diff)
downloadFreeBSD-src-3c03499e5b87c381757115bd28ead50404867bb6.zip
FreeBSD-src-3c03499e5b87c381757115bd28ead50404867bb6.tar.gz
Start to address the race issue between restoring a file's contents
and restoring the metadata. In particular, the metadata-restore functions now all accept a file descriptor and a pathname. If the file descriptor is set and the platform supports the appropriate syscall, restore the metadata through the file descriptor. Otherwise, restore it through the pathname. This is complicated by varying syscall support (FreeBSD has an fchmod(2) but no fchflags(2), for example) and because non-file entries don't have an fd to use in restoring attributes (for example, mknod(2) doesn't return a file handle). MFC after: 14 days
Diffstat (limited to 'lib/libarchive')
-rw-r--r--lib/libarchive/Makefile2
-rw-r--r--lib/libarchive/archive_platform.h13
-rw-r--r--lib/libarchive/archive_read_extract.c289
-rw-r--r--lib/libarchive/configure.ac.in5
4 files changed, 204 insertions, 105 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index ecfea60..dbe9dad 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -7,7 +7,7 @@
LIB= archive
-VERSION= 1.02.019
+VERSION= 1.02.023
ARCHIVE_API_FEATURE= 2
ARCHIVE_API_VERSION= 1
SHLIB_MAJOR= ${ARCHIVE_API_VERSION}
diff --git a/lib/libarchive/archive_platform.h b/lib/libarchive/archive_platform.h
index 770d808..4140df2 100644
--- a/lib/libarchive/archive_platform.h
+++ b/lib/libarchive/archive_platform.h
@@ -46,6 +46,8 @@
#if __FreeBSD__ > 4
#define HAVE_ACL_CREATE_ENTRY 1
#define HAVE_ACL_INIT 1
+#define HAVE_ACL_SET_FD 1
+#define HAVE_ACL_SET_FD_NP 1
#define HAVE_ACL_SET_FILE 1
#endif
#define HAVE_BZLIB_H 1
@@ -55,7 +57,10 @@
#define HAVE_EILSEQ 1
#define HAVE_ERRNO_H 1
#define HAVE_FCHDIR 1
+#define HAVE_FCHMOD 1
+#define HAVE_FCHOWN 1
#define HAVE_FCNTL_H 1
+#define HAVE_FUTIMES 1
#define HAVE_INTTYPES_H 1
#define HAVE_LCHMOD 1
#define HAVE_LCHOWN 1
@@ -123,6 +128,14 @@
#define HAVE_POSIX_ACL 1
#endif
+/*
+ * If we can't restore metadata using a file descriptor, then
+ * for compatibility's sake, close files before trying to restore metadata.
+ */
+#if defined(HAVE_FCHMOD) || defined(HAVE_FUTIMES) || defined(HAVE_ACL_SET_FD) || defined(HAVE_ACL_SET_FD_NP) || defined(HAVE_FCHOWN)
+#define CAN_RESTORE_METADATA_FD
+#endif
+
/* Set up defaults for internal error codes. */
#ifndef ARCHIVE_ERRNO_FILE_FORMAT
#if HAVE_EFTYPE
diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c
index 20fb1dd..4a8f1d2 100644
--- a/lib/libarchive/archive_read_extract.c
+++ b/lib/libarchive/archive_read_extract.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2003-2004 Tim Kientzle
+ * Copyright (c) 2003-2005 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,9 +94,6 @@ struct extract {
* Cached stat data from disk for the current entry.
* If this is valid, pst points to st. Otherwise,
* pst is null.
- *
- * TODO: Have all of the stat calls use this cached data
- * if possible.
*/
struct stat st;
struct stat *pst;
@@ -130,19 +127,20 @@ static int create_dir_mutable(struct archive *, char *, int flags);
static int create_dir_recursive(struct archive *, char *, int flags);
static int create_parent_dir(struct archive *, const char *, int flags);
static int create_parent_dir_mutable(struct archive *, char *, int flags);
-static int restore_metadata(struct archive *, struct archive_entry *,
- int flags);
+static int restore_metadata(struct archive *, int fd,
+ struct archive_entry *, int flags);
#ifdef HAVE_POSIX_ACL
-static int set_acl(struct archive *, struct archive_entry *,
+static int set_acl(struct archive *, int fd, struct archive_entry *,
acl_type_t, int archive_entry_acl_type, const char *tn);
#endif
-static int set_acls(struct archive *, struct archive_entry *);
-static int set_fflags(struct archive *, const char *name, mode_t mode,
+static int set_acls(struct archive *, int fd, struct archive_entry *);
+static int set_fflags(struct archive *, int fd, const char *name, mode_t,
unsigned long fflags_set, unsigned long fflags_clear);
-static int set_ownership(struct archive *, struct archive_entry *, int);
-static int set_perm(struct archive *, struct archive_entry *, int mode,
+static int set_ownership(struct archive *, int fd, struct archive_entry *,
int flags);
-static int set_time(struct archive *, struct archive_entry *, int);
+static int set_perm(struct archive *, int fd, struct archive_entry *,
+ int mode, int flags);
+static int set_time(struct archive *, int fd, struct archive_entry *, int);
static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
@@ -183,6 +181,8 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
restore_pwd = -1;
original_filename = NULL;
+ /* The following is not possible without fchdir. <sigh> */
+#ifdef HAVE_FCHDIR
/*
* If pathname is longer than PATH_MAX, record starting directory
* and chdir to a suitable intermediate dir.
@@ -190,13 +190,19 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
if (strlen(archive_entry_pathname(entry)) > PATH_MAX) {
char *intdir, *tail;
+ restore_pwd = open(".", O_RDONLY);
+ if (restore_pwd < 0) {
+ archive_set_error(a, errno,
+ "Unable to restore long pathname");
+ return (ARCHIVE_WARN);
+ }
+
/*
* Yes, the copy here is necessary because we edit
* the pathname in-place to create intermediate dirnames.
*/
original_filename = strdup(archive_entry_pathname(entry));
- restore_pwd = open(".", O_RDONLY);
/*
* "intdir" points to the initial dir section we're going
* to remove, "tail" points to the remainder of the path.
@@ -230,6 +236,7 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
}
archive_entry_set_pathname(entry, tail);
}
+#endif
if (stat(archive_entry_pathname(entry), &extract->st) == 0)
extract->pst = &extract->st;
@@ -269,6 +276,7 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
cleanup:
+#ifdef HAVE_FCHDIR
/* If we changed directory above, restore it here. */
if (restore_pwd >= 0 && original_filename != NULL) {
fchdir(restore_pwd);
@@ -276,6 +284,7 @@ cleanup:
archive_entry_copy_pathname(entry, original_filename);
free(original_filename);
}
+#endif
return (ret);
}
@@ -287,7 +296,7 @@ cleanup:
* dir, so we restore the dir 0700 first, then correct the
* mode at the end.
* * Similarly, the act of restoring a file touches the directory
- * and changes the timestamp on the dir, so we have to touch-up the
+ * and changes the timestamp on the dir, so we have to touch-up dir
* timestamps at the end as well.
* * Some file flags can interfere with the restore by, for example,
* preventing the creation of hardlinks to those files.
@@ -316,7 +325,7 @@ archive_extract_cleanup(struct archive *a)
p = sort_dir_list(extract->fixup_list);
while (p != NULL) {
- extract->pst = NULL; /* Mark stat buff as out-of-date. */
+ extract->pst = NULL; /* Mark stat cache as out-of-date. */
if (p->fixup & FIXUP_TIMES) {
struct timeval times[2];
times[1].tv_sec = p->mtime;
@@ -329,7 +338,7 @@ archive_extract_cleanup(struct archive *a)
chmod(p->name, p->mode);
if (p->fixup & FIXUP_FFLAGS)
- set_fflags(a, p->name, p->mode, p->fflags_set, 0);
+ set_fflags(a, -1, p->name, p->mode, p->fflags_set, 0);
next = p->next;
free(p->name);
@@ -482,9 +491,9 @@ extract_file(struct archive *a, struct archive_entry *entry, int flags)
return (ARCHIVE_WARN);
}
r = archive_read_data_into_fd(a, fd);
- close(fd);
extract->pst = NULL; /* Cached stat data no longer valid. */
- r2 = restore_metadata(a, entry, flags);
+ r2 = restore_metadata(a, fd, entry, flags);
+ close(fd);
return (err_combine(r, r2));
}
@@ -503,28 +512,40 @@ extract_dir(struct archive *a, struct archive_entry *entry, int flags)
archive_entry_pathname(entry));
path = extract->create_parent_dir.s;
+ if (*path == '\0') {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Invalid empty pathname");
+ return (ARCHIVE_WARN);
+ }
+
/* Deal with any troublesome trailing path elements. */
+ /* TODO: Someday, generalize this to remove '//' or '/./' from
+ * the middle of paths. But, it should not compress '..' from
+ * the middle of paths. It's a feature that restoring
+ * "a/../b" creates both 'a' and 'b' directories. */
for (;;) {
- if (*path == '\0')
- return (ARCHIVE_OK);
- /* Locate last element; trim trailing '/'. */
+ /* Locate last element. */
p = strrchr(path, '/');
- if (p != NULL) {
- if (p[1] == '\0') {
- *p = '\0';
- continue;
- }
+ if (p != NULL)
p++;
- } else
+ else
p = path;
- /* Trim trailing '.'. */
- if (p[0] == '.' && p[1] == '\0') {
+ /* Trim trailing '/' unless that's the entire path. */
+ if (p[0] == '\0' && p - 1 > path) {
+ p[-1] = '\0';
+ continue;
+ }
+ /* Trim trailing '.' unless that's the entire path. */
+ if (p > path && p[0] == '.' && p[1] == '\0') {
p[0] = '\0';
continue;
}
/* Just exit on trailing '..'. */
- if (p[0] == '.' && p[1] == '.' && p[2] == '\0')
- return (ARCHIVE_OK);
+ if (p[0] == '.' && p[1] == '.' && p[2] == '\0') {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Can't restore directory '..'");
+ return (ARCHIVE_WARN);
+ }
break;
}
@@ -570,7 +591,7 @@ success:
}
/* For now, set the mode to SECURE_DIR_MODE. */
archive_entry_set_mode(entry, SECURE_DIR_MODE);
- return (restore_metadata(a, entry, flags));
+ return (restore_metadata(a, -1, entry, flags));
}
@@ -762,7 +783,7 @@ extract_hard_link(struct archive *a, struct archive_entry *entry, int flags)
}
/* Set ownership, time, permission information. */
- r = restore_metadata(a, entry, flags);
+ r = restore_metadata(a, -1, entry, flags);
return (r);
}
@@ -798,7 +819,7 @@ extract_symlink(struct archive *a, struct archive_entry *entry, int flags)
return (ARCHIVE_WARN);
}
- r = restore_metadata(a, entry, flags);
+ r = restore_metadata(a, -1, entry, flags);
return (r);
}
@@ -830,7 +851,7 @@ extract_device(struct archive *a, struct archive_entry *entry,
return (ARCHIVE_WARN);
}
- r = restore_metadata(a, entry, flags);
+ r = restore_metadata(a, -1, entry, flags);
return (r);
}
@@ -879,24 +900,25 @@ extract_fifo(struct archive *a, struct archive_entry *entry, int flags)
return (ARCHIVE_WARN);
}
- r = restore_metadata(a, entry, flags);
+ r = restore_metadata(a, -1, entry, flags);
return (r);
}
static int
-restore_metadata(struct archive *a, struct archive_entry *entry, int flags)
+restore_metadata(struct archive *a, int fd, struct archive_entry *entry, int flags)
{
int r, r2;
- r = set_ownership(a, entry, flags);
- r2 = set_time(a, entry, flags);
+ r = set_ownership(a, fd, entry, flags);
+ r2 = set_time(a, fd, entry, flags);
r = err_combine(r, r2);
- r2 = set_perm(a, entry, archive_entry_mode(entry), flags);
+ r2 = set_perm(a, fd, entry, archive_entry_mode(entry), flags);
return (err_combine(r, r2));
}
static int
-set_ownership(struct archive *a, struct archive_entry *entry, int flags)
+set_ownership(struct archive *a, int fd,
+ struct archive_entry *entry, int flags)
{
uid_t uid;
gid_t gid;
@@ -914,6 +936,11 @@ set_ownership(struct archive *a, struct archive_entry *entry, int flags)
if (a->user_uid != 0 && a->user_uid != uid)
return (ARCHIVE_OK);
+#ifdef HAVE_FCHOWN
+ if (fd >= 0 && fchown(fd, uid, gid) == 0)
+ return (ARCHIVE_OK);
+#endif
+
#ifdef HAVE_LCHOWN
if (lchown(archive_entry_pathname(entry), uid, gid))
#else
@@ -930,7 +957,7 @@ set_ownership(struct archive *a, struct archive_entry *entry, int flags)
}
static int
-set_time(struct archive *a, struct archive_entry *entry, int flags)
+set_time(struct archive *a, int fd, struct archive_entry *entry, int flags)
{
const struct stat *st;
struct timeval times[2];
@@ -950,6 +977,11 @@ set_time(struct archive *a, struct archive_entry *entry, int flags)
times[0].tv_sec = st->st_atime;
times[0].tv_usec = ARCHIVE_STAT_ATIME_NANOS(st) / 1000;
+#ifdef HAVE_FUTIMES
+ if (fd >= 0 && futimes(fd, times) == 0)
+ return (ARCHIVE_OK);
+#endif
+
#ifdef HAVE_LUTIMES
if (lutimes(archive_entry_pathname(entry), times) != 0) {
#else
@@ -973,7 +1005,8 @@ set_time(struct archive *a, struct archive_entry *entry, int flags)
}
static int
-set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
+set_perm(struct archive *a, int fd, struct archive_entry *entry,
+ int mode, int flags)
{
struct extract *extract;
struct fixup_entry *le;
@@ -990,11 +1023,20 @@ set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
name = archive_entry_pathname(entry);
if (mode & (S_ISUID | S_ISGID)) {
- if (extract->pst == NULL && stat(name, &extract->st) != 0) {
- archive_set_error(a, errno, "Can't check ownership");
+ if (extract->pst != NULL) {
+ /* Already have stat() data available. */
+#ifdef HAVE_FSTAT
+ } else if (fd >= 0 && fstat(fd, &extract->st) == 0) {
+ extract->pst = &extract->st;
+#endif
+ } else if (stat(name, &extract->st) == 0) {
+ extract->pst = &extract->st;
+ } else {
+ archive_set_error(a, errno,
+ "Couldn't stat file");
return (ARCHIVE_WARN);
}
- extract->pst = &extract->st;
+
/*
* TODO: Use the uid/gid looked up in set_ownership
* above rather than the uid/gid stored in the entry.
@@ -1011,6 +1053,10 @@ set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
* the way.
*/
if (!S_ISLNK(archive_entry_mode(entry))) {
+#ifdef HAVE_FCHMOD
+ if (fd >= 0 && fchmod(fd, mode) == 0)
+ return (ARCHIVE_OK);
+#endif
if (chmod(name, mode) != 0) {
archive_set_error(a, errno, "Can't set permissions");
return (ARCHIVE_WARN);
@@ -1030,7 +1076,7 @@ set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
}
if (flags & ARCHIVE_EXTRACT_ACL) {
- r = set_acls(a, entry);
+ r = set_acls(a, fd, entry);
if (r != ARCHIVE_OK)
return (r);
}
@@ -1086,7 +1132,7 @@ set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
if ((le->fixup & FIXUP_MODE) == 0)
le->mode = mode;
} else {
- r = set_fflags(a, archive_entry_pathname(entry),
+ r = set_fflags(a, fd, archive_entry_pathname(entry),
mode, set, clear);
if (r != ARCHIVE_OK)
return (r);
@@ -1095,24 +1141,18 @@ set_perm(struct archive *a, struct archive_entry *entry, int mode, int flags)
return (ARCHIVE_OK);
}
+
+#if defined(HAVE_CHFLAGS) && !defined(__linux)
static int
-set_fflags(struct archive *a, const char *name, mode_t mode,
+set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
unsigned long set, unsigned long clear)
{
struct extract *extract;
- int ret;
-#ifdef linux
- int fd;
- int err;
- unsigned long newflags, oldflags;
-#endif
extract = a->extract;
- ret = ARCHIVE_OK;
if (set == 0 && clear == 0)
- return (ret);
+ return (ARCHIVE_OK);
-#ifdef HAVE_CHFLAGS
(void)mode; /* UNUSED */
/*
* XXX Is the stat here really necessary? Or can I just use
@@ -1120,65 +1160,99 @@ set_fflags(struct archive *a, const char *name, mode_t mode,
* about the correct approach if we're overwriting an existing
* file that already has flags on it. XXX
*/
- if (stat(name, &extract->st) == 0) {
- extract->st.st_flags &= ~clear;
- extract->st.st_flags |= set;
- if (chflags(name, extract->st.st_flags) != 0) {
- archive_set_error(a, errno,
- "Failed to set file flags");
- ret = ARCHIVE_WARN;
- }
+ if (extract->pst != NULL) {
+ /* Already have stat() data available. */
+ } else if (fd >= 0 && fstat(fd, &extract->st) == 0)
+ extract->pst = &extract->st;
+ else if (stat(name, &extract->st) == 0)
extract->pst = &extract->st;
+ else {
+ archive_set_error(a, errno,
+ "Couldn't stat file");
+ return (ARCHIVE_WARN);
}
-#else
-#ifdef linux
- /* Linux has flags too, but no chflags syscall */
+
+ extract->st.st_flags &= ~clear;
+ extract->st.st_flags |= set;
+ if (chflags(name, extract->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+
+ archive_set_error(a, errno,
+ "Failed to set file flags");
+ return (ARCHIVE_WARN);
+}
+#endif /* HAVE_CHFLAGS */
+
+#ifdef __linux
+/* Linux has flags too, but uses ioctl() instead of chflags(). */
+static int
+set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
+ unsigned long set, unsigned long clear)
+{
+ struct extract *extract;
+ int ret;
+ int myfd = fd;
+ int err;
+ unsigned long newflags, oldflags;
+
+ extract = a->extract;
+ ret = ARCHIVE_OK;
+ if (set == 0 && clear == 0)
+ return (ret);
+ /* Only regular files and dirs can have flags. */
+ if (!S_ISREG(mode) && !S_ISDIR(mode))
+ return (ret);
+
+ /* If we weren't given an fd, open it ourselves. */
+ if (myfd < 0)
+ myfd = open(name, O_RDONLY|O_NONBLOCK);
+ if (myfd < 0)
+ return (ret);
+
/*
* Linux has no define for the flags that are only settable
* by the root user...
*/
#define SF_MASK (EXT2_IMMUTABLE_FL|EXT2_APPEND_FL)
-
/*
* XXX As above, this would be way simpler if we didn't have
* to read the current flags from disk. XXX
*/
- if ((S_ISREG(mode) || S_ISDIR(mode)) &&
- ((fd = open(name, O_RDONLY|O_NONBLOCK)) >= 0)) {
- err = 1;
- if (fd >= 0 && (ioctl(fd, EXT2_IOC_GETFLAGS, &oldflags) >= 0)) {
- newflags = (oldflags & ~clear) | set;
- if (ioctl(fd, EXT2_IOC_SETFLAGS, &newflags) >= 0) {
- err = 0;
- } else if (errno == EPERM) {
- if (ioctl(fd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
- newflags &= ~SF_MASK;
- oldflags &= SF_MASK;
- newflags |= oldflags;
- if (ioctl(fd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
- err = 0;
- }
- }
- }
- close(fd);
- if (err) {
- archive_set_error(a, errno,
- "Failed to set file flags");
- ret = ARCHIVE_WARN;
- }
+ /* Try setting the flags as given. */
+ if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags = (oldflags & ~clear) | set;
+ if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ goto cleanup;
+ if (errno != EPERM)
+ goto fail;
}
-#endif /* linux */
-#endif /* HAVE_CHFLAGS */
-
+ /* If we couldn't set all the flags, try again with a subset. */
+ if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags &= ~SF_MASK;
+ oldflags &= SF_MASK;
+ newflags |= oldflags;
+ if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ goto cleanup;
+ }
+ /* We couldn't set the flags, so report the failure. */
+fail:
+ archive_set_error(a, errno,
+ "Failed to set file flags");
+ ret = ARCHIVE_WARN;
+cleanup:
+ if (fd < 0)
+ close(myfd);
return (ret);
}
+#endif /* __linux */
#ifndef HAVE_POSIX_ACL
/* Default empty function body to satisfy mainline code. */
static int
-set_acls(struct archive *a, struct archive_entry *entry)
+set_acls(struct archive *a, int fd, struct archive_entry *entry)
{
(void)a;
+ (void)fd;
(void)entry;
return (ARCHIVE_OK);
@@ -1190,23 +1264,23 @@ set_acls(struct archive *a, struct archive_entry *entry)
* XXX TODO: What about ACL types other than ACCESS and DEFAULT?
*/
static int
-set_acls(struct archive *a, struct archive_entry *entry)
+set_acls(struct archive *a, int fd, struct archive_entry *entry)
{
int ret;
- ret = set_acl(a, entry, ACL_TYPE_ACCESS,
+ ret = set_acl(a, fd, entry, ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
if (ret != ARCHIVE_OK)
return (ret);
- ret = set_acl(a, entry, ACL_TYPE_DEFAULT,
+ ret = set_acl(a, fd, entry, ACL_TYPE_DEFAULT,
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
return (ret);
}
static int
-set_acl(struct archive *a, struct archive_entry *entry, acl_type_t acl_type,
- int ae_requested_type, const char *typename)
+set_acl(struct archive *a, int fd, struct archive_entry *entry,
+ acl_type_t acl_type, int ae_requested_type, const char *typename)
{
acl_t acl;
acl_entry_t acl_entry;
@@ -1268,6 +1342,17 @@ set_acl(struct archive *a, struct archive_entry *entry, acl_type_t acl_type,
name = archive_entry_pathname(entry);
+ /* Try restoring the ACL through 'fd' if we can. */
+#if HAVE_ACL_SET_FD
+ if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
+ ret = ARCHIVE_OK;
+ else
+#endif
+#if HAVE_ACL_SET_FD_NP
+ if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
+ ret = ARCHIVE_OK;
+ else
+#endif
if (acl_set_file(name, acl_type, acl) != 0) {
archive_set_error(a, errno, "Failed to set %s acl", typename);
ret = ARCHIVE_WARN;
diff --git a/lib/libarchive/configure.ac.in b/lib/libarchive/configure.ac.in
index 537b577..09d8ed3 100644
--- a/lib/libarchive/configure.ac.in
+++ b/lib/libarchive/configure.ac.in
@@ -72,8 +72,9 @@ AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_STAT
AC_FUNC_STRERROR_R
-AC_CHECK_FUNCS([acl_create_entry acl_init acl_set_file])
-AC_CHECK_FUNCS([chflags fchdir lchmod lchown lutimes memmove])
+AC_CHECK_FUNCS([acl_create_entry acl_init acl_set_fd acl_set_fd_np acl_set_file])
+AC_CHECK_FUNCS([chflags fchdir fchmod fchown futimes])
+AC_CHECK_FUNCS([lchmod lchown lutimes memmove])
AC_CHECK_FUNCS([memset mkdir mkfifo strchr strdup strerror strrchr])
# Additional requirements
OpenPOWER on IntegriCloud