2 * Copyright (c) 2003-2009 Tim Kientzle
3 * Copyright (c) 2010-2012 Michihiro NAKAJIMA
4 * Copyright (c) 2016 Martin Matuska
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "archive_platform.h"
29 __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 201084 2009-12-28 02:14:09Z kientzle $");
31 /* This is the tree-walking code for POSIX systems. */
32 #if !defined(_WIN32) || defined(__CYGWIN__)
34 #ifdef HAVE_SYS_TYPES_H
35 /* Mac OSX requires sys/types.h before sys/acl.h. */
36 #include <sys/types.h>
41 #ifdef HAVE_DARWIN_ACL
42 #include <membership.h>
46 #ifdef HAVE_SYS_EXTATTR_H
47 #include <sys/extattr.h>
49 #ifdef HAVE_SYS_IOCTL_H
50 #include <sys/ioctl.h>
52 #ifdef HAVE_SYS_PARAM_H
53 #include <sys/param.h>
55 #ifdef HAVE_SYS_STAT_H
58 #if defined(HAVE_SYS_XATTR_H)
59 #include <sys/xattr.h>
60 #elif defined(HAVE_ATTR_XATTR_H)
61 #include <attr/xattr.h>
66 #ifdef HAVE_ACL_LIBACL_H
67 #include <acl/libacl.h>
69 #ifdef HAVE_COPYFILE_H
81 #ifdef HAVE_LINUX_TYPES_H
82 #include <linux/types.h>
84 #ifdef HAVE_LINUX_FIEMAP_H
85 #include <linux/fiemap.h>
87 #ifdef HAVE_LINUX_FS_H
91 * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
92 * As the include guards don't agree, the order of include is important.
94 #ifdef HAVE_LINUX_EXT2_FS_H
95 #include <linux/ext2_fs.h> /* for Linux file flags */
97 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
98 #include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */
108 #include "archive_entry.h"
109 #include "archive_private.h"
110 #include "archive_read_disk_private.h"
117 * Linux and FreeBSD plug this obvious hole in POSIX.1e in
120 #if HAVE_ACL_GET_PERM
121 #define ACL_GET_PERM acl_get_perm
122 #elif HAVE_ACL_GET_PERM_NP
123 #define ACL_GET_PERM acl_get_perm_np
126 /* NFSv4 platform ACL type */
128 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T
129 #elif HAVE_DARWIN_ACL
130 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
131 #elif HAVE_ACL_TYPE_NFS4
132 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4
135 static int setup_acls(struct archive_read_disk *,
136 struct archive_entry *, int *fd);
137 static int setup_mac_metadata(struct archive_read_disk *,
138 struct archive_entry *, int *fd);
139 static int setup_xattrs(struct archive_read_disk *,
140 struct archive_entry *, int *fd);
141 static int setup_sparse(struct archive_read_disk *,
142 struct archive_entry *, int *fd);
143 #if defined(HAVE_LINUX_FIEMAP_H)
144 static int setup_sparse_fiemap(struct archive_read_disk *,
145 struct archive_entry *, int *fd);
149 archive_read_disk_entry_from_file(struct archive *_a,
150 struct archive_entry *entry,
152 const struct stat *st)
154 struct archive_read_disk *a = (struct archive_read_disk *)_a;
155 const char *path, *name;
160 archive_clear_error(_a);
161 path = archive_entry_sourcepath(entry);
163 path = archive_entry_pathname(entry);
165 if (a->tree == NULL) {
169 if (fstat(fd, &s) != 0) {
170 archive_set_error(&a->archive, errno,
172 return (ARCHIVE_FAILED);
177 if (!a->follow_symlinks) {
178 if (lstat(path, &s) != 0) {
179 archive_set_error(&a->archive, errno,
180 "Can't lstat %s", path);
181 return (ARCHIVE_FAILED);
185 if (stat(path, &s) != 0) {
186 archive_set_error(&a->archive, errno,
187 "Can't stat %s", path);
188 return (ARCHIVE_FAILED);
192 archive_entry_copy_stat(entry, st);
195 /* Lookup uname/gname */
196 name = archive_read_disk_uname(_a, archive_entry_uid(entry));
198 archive_entry_copy_uname(entry, name);
199 name = archive_read_disk_gname(_a, archive_entry_gid(entry));
201 archive_entry_copy_gname(entry, name);
203 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
204 /* On FreeBSD, we get flags for free with the stat. */
205 /* TODO: Does this belong in copy_stat()? */
206 if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)
207 archive_entry_set_fflags(entry, st->st_flags, 0);
210 #if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
211 (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
212 /* Linux requires an extra ioctl to pull the flags. Although
213 * this is an extra step, it has a nice side-effect: We get an
214 * open file descriptor which we can use in the subsequent lookups. */
215 if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&
216 (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
219 fd = a->open_on_current_dir(a->tree, path,
220 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
222 fd = open(path, O_RDONLY | O_NONBLOCK |
224 __archive_ensure_cloexec_flag(fd);
229 #if defined(FS_IOC_GETFLAGS)
235 if (r == 0 && stflags != 0)
236 archive_entry_set_fflags(entry, stflags, 0);
241 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
242 if (S_ISLNK(st->st_mode)) {
243 size_t linkbuffer_len = st->st_size + 1;
247 linkbuffer = malloc(linkbuffer_len);
248 if (linkbuffer == NULL) {
249 archive_set_error(&a->archive, ENOMEM,
250 "Couldn't read link data");
251 return (ARCHIVE_FAILED);
253 if (a->tree != NULL) {
254 #ifdef HAVE_READLINKAT
255 lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
256 path, linkbuffer, linkbuffer_len);
258 if (a->tree_enter_working_dir(a->tree) != 0) {
259 archive_set_error(&a->archive, errno,
260 "Couldn't read link data");
262 return (ARCHIVE_FAILED);
264 lnklen = readlink(path, linkbuffer, linkbuffer_len);
265 #endif /* HAVE_READLINKAT */
267 lnklen = readlink(path, linkbuffer, linkbuffer_len);
269 archive_set_error(&a->archive, errno,
270 "Couldn't read link data");
272 return (ARCHIVE_FAILED);
274 linkbuffer[lnklen] = 0;
275 archive_entry_set_symlink(entry, linkbuffer);
278 #endif /* HAVE_READLINK || HAVE_READLINKAT */
281 if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
282 r = setup_acls(a, entry, &fd);
283 if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
284 r1 = setup_xattrs(a, entry, &fd);
288 if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
289 r1 = setup_mac_metadata(a, entry, &fd);
293 r1 = setup_sparse(a, entry, &fd);
297 /* If we opened the file earlier in this function, close it. */
298 if (initial_fd != fd)
303 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
305 * The Mac OS "copyfile()" API copies the extended metadata for a
306 * file into a separate file in AppleDouble format (see RFC 1740).
308 * Mac OS tar and cpio implementations store this extended
309 * metadata as a separate entry just before the regular entry
310 * with a "._" prefix added to the filename.
312 * Note that this is currently done unconditionally; the tar program has
313 * an option to discard this information before the archive is written.
315 * TODO: If there's a failure, report it and return ARCHIVE_WARN.
318 setup_mac_metadata(struct archive_read_disk *a,
319 struct archive_entry *entry, int *fd)
322 int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
323 struct stat copyfile_stat;
324 int ret = ARCHIVE_OK;
327 const char *name, *tempdir;
328 struct archive_string tempfile;
330 (void)fd; /* UNUSED */
331 name = archive_entry_sourcepath(entry);
333 name = archive_entry_pathname(entry);
334 else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) {
335 archive_set_error(&a->archive, errno,
336 "Can't change dir to read extended attributes");
337 return (ARCHIVE_FAILED);
340 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
341 "Can't open file to read extended attributes: No name");
342 return (ARCHIVE_WARN);
345 /* Short-circuit if there's nothing to do. */
346 have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
347 if (have_attrs == -1) {
348 archive_set_error(&a->archive, errno,
349 "Could not check extended attributes");
350 return (ARCHIVE_WARN);
356 if (issetugid() == 0)
357 tempdir = getenv("TMPDIR");
360 archive_string_init(&tempfile);
361 archive_strcpy(&tempfile, tempdir);
362 archive_strcat(&tempfile, "tar.md.XXXXXX");
363 tempfd = mkstemp(tempfile.s);
365 archive_set_error(&a->archive, errno,
366 "Could not open extended attribute file");
370 __archive_ensure_cloexec_flag(tempfd);
372 /* XXX I wish copyfile() could pack directly to a memory
373 * buffer; that would avoid the temp file here. For that
374 * matter, it would be nice if fcopyfile() actually worked,
375 * that would reduce the many open/close races here. */
376 if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
377 archive_set_error(&a->archive, errno,
378 "Could not pack extended attributes");
382 if (fstat(tempfd, ©file_stat)) {
383 archive_set_error(&a->archive, errno,
384 "Could not check size of extended attributes");
388 buff = malloc(copyfile_stat.st_size);
390 archive_set_error(&a->archive, errno,
391 "Could not allocate memory for extended attributes");
395 if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
396 archive_set_error(&a->archive, errno,
397 "Could not read extended attributes into memory");
401 archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
408 archive_string_free(&tempfile);
416 * Stub implementation for non-Mac systems.
419 setup_mac_metadata(struct archive_read_disk *a,
420 struct archive_entry *entry, int *fd)
422 (void)a; /* UNUSED */
423 (void)entry; /* UNUSED */
424 (void)fd; /* UNUSED */
430 static int translate_guid(struct archive *, acl_entry_t,
431 int *, int *, const char **);
433 static void add_trivial_nfs4_acl(struct archive_entry *);
438 sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
441 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
442 static int translate_acl(struct archive_read_disk *a,
443 struct archive_entry *entry,
449 int archive_entry_acl_type);
452 setup_acls(struct archive_read_disk *a,
453 struct archive_entry *entry, int *fd)
465 #if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP
468 /* For default ACLs on Linux we need reachable accpath */
469 if (*fd < 0 || S_ISDIR(archive_entry_mode(entry)))
472 accpath = archive_entry_sourcepath(entry);
473 if (accpath == NULL || (a->tree != NULL &&
474 a->tree_enter_working_dir(a->tree) != 0))
475 accpath = archive_entry_pathname(entry);
476 if (accpath == NULL) {
477 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
478 "Couldn't determine file path to read ACLs");
479 return (ARCHIVE_WARN);
481 if (a->tree != NULL &&
482 #if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP
485 (a->follow_symlinks ||
486 archive_entry_filetype(entry) != AE_IFLNK)) {
487 *fd = a->open_on_current_dir(a->tree,
488 accpath, O_RDONLY | O_NONBLOCK);
492 archive_entry_acl_clear(entry);
497 /* Try NFSv4 ACL first. */
500 /* Solaris reads both POSIX.1e and NFSv4 ACL here */
501 facl_get(*fd, 0, &acl);
502 #elif HAVE_ACL_GET_FD_NP
503 acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
505 acl = acl_get_fd(*fd);
507 #if HAVE_ACL_GET_LINK_NP
508 else if (!a->follow_symlinks)
509 acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
511 else if ((!a->follow_symlinks)
512 && (archive_entry_filetype(entry) == AE_IFLNK))
513 /* We can't get the ACL of a symlink, so we assume it can't
519 /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
520 acl_get(accpath, 0, &acl);
522 acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
526 #if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL
527 /* Ignore "trivial" ACLs that just mirror the file mode. */
530 if (sun_acl_is_trivial(acl, archive_entry_mode(entry),
532 #elif HAVE_ACL_IS_TRIVIAL_NP
533 if (acl_is_trivial_np(acl, &r) == 0 && r == 1)
539 * Simultaneous NFSv4 and POSIX.1e ACLs for the same
540 * entry are not allowed, so we should return here
545 #endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */
547 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
549 if (r != ARCHIVE_OK) {
550 archive_set_error(&a->archive, errno,
551 "Couldn't translate "
559 * Because Mac OS doesn't support owner@, group@ and everyone@
560 * ACLs we need to add NFSv4 ACLs mirroring the file mode to
561 * the archive entry. Otherwise extraction on non-Mac platforms
562 * would lead to an invalid file mode.
564 if ((archive_entry_acl_types(entry) &
565 ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
566 add_trivial_nfs4_acl(entry);
570 #endif /* HAVE_NFS4_ACL */
573 /* This code path is skipped on MacOS and Solaris */
575 /* Retrieve access ACL from file. */
577 acl = acl_get_fd(*fd);
578 #if HAVE_ACL_GET_LINK_NP
579 else if (!a->follow_symlinks)
580 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
582 else if ((!a->follow_symlinks)
583 && (archive_entry_filetype(entry) == AE_IFLNK))
584 /* We can't get the ACL of a symlink, so we assume it can't
589 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
591 #if HAVE_ACL_IS_TRIVIAL_NP
592 /* Ignore "trivial" ACLs that just mirror the file mode. */
593 if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
602 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
605 if (r != ARCHIVE_OK) {
606 archive_set_error(&a->archive, errno,
607 "Couldn't translate access ACLs");
612 /* Only directories can have default ACLs. */
613 if (S_ISDIR(archive_entry_mode(entry))) {
614 #if HAVE_ACL_GET_FD_NP
616 acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
619 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
621 r = translate_acl(a, entry, acl,
622 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
624 if (r != ARCHIVE_OK) {
625 archive_set_error(&a->archive, errno,
626 "Couldn't translate default ACLs");
631 #endif /* HAVE_POSIX_ACL */
636 * Translate system ACL permissions into libarchive internal structure
638 static const struct {
639 const int archive_perm;
640 const int platform_perm;
642 #if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */
643 {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
644 {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
645 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
646 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
647 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
648 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
649 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
650 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
651 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
652 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
653 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
654 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
655 {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
656 {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
657 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
658 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
659 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
660 #elif HAVE_DARWIN_ACL /* MacOS ACL permissions */
661 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
662 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
663 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
664 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
665 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
666 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
667 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
668 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
669 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
670 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
671 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
672 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
673 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
674 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
675 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
676 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
677 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
678 #else /* POSIX.1e ACL permissions */
679 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
680 {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
681 {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
682 #if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */
683 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
684 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
685 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
686 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
687 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
688 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
689 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
690 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
691 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
692 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
693 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
694 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
695 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
696 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
697 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
698 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
700 #endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
705 * Translate system NFSv4 inheritance flags into libarchive internal structure
707 static const struct {
708 const int archive_inherit;
709 const int platform_inherit;
710 } acl_inherit_map[] = {
711 #if HAVE_SUN_ACL /* Solaris ACL inheritance flags */
712 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
713 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
714 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
715 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
716 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
717 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
718 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
719 #elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */
720 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
721 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
722 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
723 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
724 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
725 #else /* FreeBSD NFSv4 ACL inheritance flags */
726 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
727 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
728 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
729 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
730 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
731 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
732 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
733 #endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
735 #endif /* HAVE_NFS4_ACL */
738 static int translate_guid(struct archive *a, acl_entry_t acl_entry,
739 int *ae_id, int *ae_tag, const char **ae_name)
747 q = acl_get_qualifier(acl_entry);
750 r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
755 if (idtype == ID_TYPE_UID) {
756 *ae_tag = ARCHIVE_ENTRY_ACL_USER;
762 *ae_id = pwd->pw_uid;
763 *ae_name = archive_read_disk_uname(a, *ae_id);
765 } else if (idtype == ID_TYPE_GID) {
766 *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
772 *ae_id = grp->gr_gid;
773 *ae_name = archive_read_disk_gname(a, *ae_id);
783 * Add trivial NFSv4 ACL entries from mode
786 add_trivial_nfs4_acl(struct archive_entry *entry)
790 const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
791 const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
792 ARCHIVE_ENTRY_ACL_APPEND_DATA;
793 const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
794 const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
795 ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
796 ARCHIVE_ENTRY_ACL_READ_ACL |
797 ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
798 const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
799 ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
800 ARCHIVE_ENTRY_ACL_WRITE_ACL |
801 ARCHIVE_ENTRY_ACL_WRITE_OWNER;
808 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
809 {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
810 {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
811 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
812 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
813 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
816 mode = archive_entry_mode(entry);
818 /* Permissions for everyone@ */
820 tacl_entry[5].permset |= rperm;
822 tacl_entry[5].permset |= wperm;
824 tacl_entry[5].permset |= eperm;
826 /* Permissions for group@ */
828 tacl_entry[4].permset |= rperm;
829 else if (mode & 0004)
830 tacl_entry[2].permset |= rperm;
832 tacl_entry[4].permset |= wperm;
833 else if (mode & 0002)
834 tacl_entry[2].permset |= wperm;
836 tacl_entry[4].permset |= eperm;
837 else if (mode & 0001)
838 tacl_entry[2].permset |= eperm;
840 /* Permissions for owner@ */
842 tacl_entry[3].permset |= rperm;
843 if (!(mode & 0040) && (mode & 0004))
844 tacl_entry[0].permset |= rperm;
845 } else if ((mode & 0040) || (mode & 0004))
846 tacl_entry[1].permset |= rperm;
848 tacl_entry[3].permset |= wperm;
849 if (!(mode & 0020) && (mode & 0002))
850 tacl_entry[0].permset |= wperm;
851 } else if ((mode & 0020) || (mode & 0002))
852 tacl_entry[1].permset |= wperm;
854 tacl_entry[3].permset |= eperm;
855 if (!(mode & 0010) && (mode & 0001))
856 tacl_entry[0].permset |= eperm;
857 } else if ((mode & 0010) || (mode & 0001))
858 tacl_entry[1].permset |= eperm;
860 for (i = 0; i < 6; i++) {
861 if (tacl_entry[i].permset != 0) {
862 archive_entry_acl_add_entry(entry,
863 tacl_entry[i].type, tacl_entry[i].permset,
864 tacl_entry[i].tag, -1, NULL);
872 * Check if acl is trivial
873 * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
876 sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
879 const uint32_t rperm = ACE_READ_DATA;
880 const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
881 const uint32_t eperm = ACE_EXECUTE;
882 const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
883 ACE_READ_ACL | ACE_SYNCHRONIZE;
884 const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
885 ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
890 if (acl == NULL || trivialp == NULL)
895 /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */
896 if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0)
900 * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
901 * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
904 if (acl->acl_type == ACLENT_T) {
905 if (acl->acl_cnt == 4)
910 if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
914 * Continue with checking NFSv4 ACLs
916 * Create list of trivial ace's to be compared
919 /* owner@ allow pre */
920 tace[0].a_flags = ACE_OWNER;
921 tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
922 tace[0].a_access_mask = 0;
925 tace[1].a_flags = ACE_OWNER;
926 tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
927 tace[1].a_access_mask = 0;
930 tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
931 tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
932 tace[2].a_access_mask = 0;
935 tace[3].a_flags = ACE_OWNER;
936 tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
937 tace[3].a_access_mask = ownset;
940 tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
941 tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
942 tace[4].a_access_mask = pubset;
944 /* everyone@ allow */
945 tace[5].a_flags = ACE_EVERYONE;
946 tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
947 tace[5].a_access_mask = pubset;
949 /* Permissions for everyone@ */
951 tace[5].a_access_mask |= rperm;
953 tace[5].a_access_mask |= wperm;
955 tace[5].a_access_mask |= eperm;
957 /* Permissions for group@ */
959 tace[4].a_access_mask |= rperm;
960 else if (mode & 0004)
961 tace[2].a_access_mask |= rperm;
963 tace[4].a_access_mask |= wperm;
964 else if (mode & 0002)
965 tace[2].a_access_mask |= wperm;
967 tace[4].a_access_mask |= eperm;
968 else if (mode & 0001)
969 tace[2].a_access_mask |= eperm;
971 /* Permissions for owner@ */
973 tace[3].a_access_mask |= rperm;
974 if (!(mode & 0040) && (mode & 0004))
975 tace[0].a_access_mask |= rperm;
976 } else if ((mode & 0040) || (mode & 0004))
977 tace[1].a_access_mask |= rperm;
979 tace[3].a_access_mask |= wperm;
980 if (!(mode & 0020) && (mode & 0002))
981 tace[0].a_access_mask |= wperm;
982 } else if ((mode & 0020) || (mode & 0002))
983 tace[1].a_access_mask |= wperm;
985 tace[3].a_access_mask |= eperm;
986 if (!(mode & 0010) && (mode & 0001))
987 tace[0].a_access_mask |= eperm;
988 } else if ((mode & 0010) || (mode & 0001))
989 tace[1].a_access_mask |= eperm;
991 /* Check if the acl count matches */
993 for (i = 0; i < 3; i++) {
994 if (tace[i].a_access_mask != 0)
997 if (acl->acl_cnt != p)
1001 for (i = 0; i < 6; i++) {
1002 if (tace[i].a_access_mask != 0) {
1003 ace = &((ace_t *)acl->acl_aclp)[p];
1005 * Illumos added ACE_DELETE_CHILD to write perms for
1006 * directories. We have to check against that, too.
1008 if (ace->a_flags != tace[i].a_flags ||
1009 ace->a_type != tace[i].a_type ||
1010 (ace->a_access_mask != tace[i].a_access_mask &&
1011 ((acl->acl_flags & ACL_IS_DIR) == 0 ||
1012 (tace[i].a_access_mask & wperm) == 0 ||
1013 ace->a_access_mask !=
1014 (tace[i].a_access_mask | ACE_DELETE_CHILD))))
1023 #endif /* HAVE_SUN_ACL */
1027 * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
1030 translate_acl(struct archive_read_disk *a,
1031 struct archive_entry *entry, acl_t *acl, int default_entry_acl_type)
1034 int ae_id, ae_tag, ae_perm;
1036 const char *ae_name;
1040 (void)default_entry_acl_type;
1042 if (acl->acl_cnt <= 0)
1043 return (ARCHIVE_OK);
1045 for (e = 0; e < acl->acl_cnt; e++) {
1050 if (acl->acl_type == ACE_T) {
1051 ace = &((ace_t *)acl->acl_aclp)[e];
1054 switch(ace->a_type) {
1055 case ACE_ACCESS_ALLOWED_ACE_TYPE:
1056 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1058 case ACE_ACCESS_DENIED_ACE_TYPE:
1059 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1061 case ACE_SYSTEM_AUDIT_ACE_TYPE:
1062 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1064 case ACE_SYSTEM_ALARM_ACE_TYPE:
1065 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1068 /* Unknown entry type, skip */
1072 if ((ace->a_flags & ACE_OWNER) != 0)
1073 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1074 else if ((ace->a_flags & ACE_GROUP) != 0)
1075 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1076 else if ((ace->a_flags & ACE_EVERYONE) != 0)
1077 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1078 else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
1079 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1080 ae_name = archive_read_disk_gname(&a->archive,
1083 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1084 ae_name = archive_read_disk_uname(&a->archive,
1088 for (i = 0; i < (int)(sizeof(acl_inherit_map) /
1089 sizeof(acl_inherit_map[0])); ++i) {
1091 acl_inherit_map[i].platform_inherit) != 0)
1093 acl_inherit_map[i].archive_inherit;
1096 for (i = 0; i < (int)(sizeof(acl_perm_map) /
1097 sizeof(acl_perm_map[0])); ++i) {
1098 if ((ace->a_access_mask &
1099 acl_perm_map[i].platform_perm) != 0)
1101 acl_perm_map[i].archive_perm;
1104 aclent = &((aclent_t *)acl->acl_aclp)[e];
1105 if ((aclent->a_type & ACL_DEFAULT) != 0)
1106 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
1108 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1109 ae_id = aclent->a_id;
1111 switch(aclent->a_type) {
1114 ae_name = archive_read_disk_uname(&a->archive,
1116 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1120 ae_name = archive_read_disk_gname(&a->archive,
1122 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1126 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1130 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1134 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1138 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1141 /* Unknown tag type, skip */
1145 if ((aclent->a_perm & 1) != 0)
1146 ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
1147 if ((aclent->a_perm & 2) != 0)
1148 ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
1149 if ((aclent->a_perm & 4) != 0)
1150 ae_perm |= ARCHIVE_ENTRY_ACL_READ;
1151 } /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */
1153 archive_entry_acl_add_entry(entry, entry_acl_type,
1154 ae_perm, ae_tag, ae_id, ae_name);
1156 return (ARCHIVE_OK);
1158 #else /* !HAVE_SUN_ACL */
1160 * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
1161 * MacOS (NFSv4 only) ACLs into libarchive internal structure
1164 translate_acl(struct archive_read_disk *a,
1165 struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
1168 #if HAVE_ACL_TYPE_NFS4
1169 acl_entry_type_t acl_type;
1172 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
1173 acl_flagset_t acl_flagset;
1175 acl_entry_t acl_entry;
1176 acl_permset_t acl_permset;
1177 int i, entry_acl_type;
1178 int r, s, ae_id, ae_tag, ae_perm;
1179 #if !HAVE_DARWIN_ACL
1182 const char *ae_name;
1184 #if HAVE_ACL_TYPE_NFS4
1185 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
1186 // Make sure the "brand" on this ACL is consistent
1187 // with the default_entry_acl_type bits provided.
1188 if (acl_get_brand_np(acl, &brand) != 0) {
1189 archive_set_error(&a->archive, errno,
1190 "Failed to read ACL brand");
1191 return (ARCHIVE_WARN);
1194 case ACL_BRAND_POSIX:
1195 switch (default_entry_acl_type) {
1196 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
1197 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
1200 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1201 "Invalid ACL entry type for POSIX.1e ACL");
1202 return (ARCHIVE_WARN);
1205 case ACL_BRAND_NFS4:
1206 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1207 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1208 "Invalid ACL entry type for NFSv4 ACL");
1209 return (ARCHIVE_WARN);
1213 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1214 "Unknown ACL brand");
1215 return (ARCHIVE_WARN);
1219 s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
1221 archive_set_error(&a->archive, errno,
1222 "Failed to get first ACL entry");
1223 return (ARCHIVE_WARN);
1228 #else /* FreeBSD, Linux */
1236 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
1237 archive_set_error(&a->archive, errno,
1238 "Failed to get ACL tag type");
1239 return (ARCHIVE_WARN);
1242 #if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
1244 q = acl_get_qualifier(acl_entry);
1246 ae_id = (int)*(uid_t *)q;
1248 ae_name = archive_read_disk_uname(&a->archive,
1251 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1254 q = acl_get_qualifier(acl_entry);
1256 ae_id = (int)*(gid_t *)q;
1258 ae_name = archive_read_disk_gname(&a->archive,
1261 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1264 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1267 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1270 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1273 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1275 #if HAVE_ACL_TYPE_NFS4
1277 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1280 #else /* HAVE_DARWIN_ACL */
1281 case ACL_EXTENDED_ALLOW:
1282 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1283 r = translate_guid(&a->archive, acl_entry, &ae_id,
1286 case ACL_EXTENDED_DENY:
1287 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1288 r = translate_guid(&a->archive, acl_entry, &ae_id,
1291 #endif /* HAVE_DARWIN_ACL */
1293 /* Skip types that libarchive can't support. */
1294 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1299 /* Skip if translate_guid() above failed */
1301 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1306 #if !HAVE_DARWIN_ACL
1307 // XXX acl_type maps to allow/deny/audit/YYYY bits
1308 entry_acl_type = default_entry_acl_type;
1310 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
1311 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1312 #if HAVE_ACL_TYPE_NFS4
1314 * acl_get_entry_type_np() fails with non-NFSv4 ACLs
1316 if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
1317 archive_set_error(&a->archive, errno, "Failed "
1318 "to get ACL type from a NFSv4 ACL entry");
1319 return (ARCHIVE_WARN);
1322 case ACL_ENTRY_TYPE_ALLOW:
1323 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1325 case ACL_ENTRY_TYPE_DENY:
1326 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1328 case ACL_ENTRY_TYPE_AUDIT:
1329 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
1331 case ACL_ENTRY_TYPE_ALARM:
1332 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1335 archive_set_error(&a->archive, errno,
1336 "Invalid NFSv4 ACL entry type");
1337 return (ARCHIVE_WARN);
1339 #endif /* HAVE_ACL_TYPE_NFS4 */
1342 * Libarchive stores "flag" (NFSv4 inheritance bits)
1343 * in the ae_perm bitmap.
1345 * acl_get_flagset_np() fails with non-NFSv4 ACLs
1347 if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
1348 archive_set_error(&a->archive, errno,
1349 "Failed to get flagset from a NFSv4 ACL entry");
1350 return (ARCHIVE_WARN);
1352 for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
1353 r = acl_get_flag_np(acl_flagset,
1354 acl_inherit_map[i].platform_inherit);
1356 archive_set_error(&a->archive, errno,
1357 "Failed to check flag in a NFSv4 "
1359 return (ARCHIVE_WARN);
1361 ae_perm |= acl_inherit_map[i].archive_inherit;
1364 #endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
1366 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
1367 archive_set_error(&a->archive, errno,
1368 "Failed to get ACL permission set");
1369 return (ARCHIVE_WARN);
1371 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
1373 * acl_get_perm() is spelled differently on different
1374 * platforms; see above.
1376 r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
1378 archive_set_error(&a->archive, errno,
1379 "Failed to check permission in an ACL permission set");
1380 return (ARCHIVE_WARN);
1382 ae_perm |= acl_perm_map[i].archive_perm;
1385 archive_entry_acl_add_entry(entry, entry_acl_type,
1389 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1390 #if !HAVE_DARWIN_ACL
1392 archive_set_error(&a->archive, errno,
1393 "Failed to get next ACL entry");
1394 return (ARCHIVE_WARN);
1398 return (ARCHIVE_OK);
1400 #endif /* !HAVE_SUN_ACL */
1401 #else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1403 setup_acls(struct archive_read_disk *a,
1404 struct archive_entry *entry, int *fd)
1406 (void)a; /* UNUSED */
1407 (void)entry; /* UNUSED */
1408 (void)fd; /* UNUSED */
1409 return (ARCHIVE_OK);
1411 #endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1413 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
1414 HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
1415 (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
1418 * Linux and AIX extended attribute support.
1420 * TODO: By using a stack-allocated buffer for the first
1421 * call to getxattr(), we might be able to avoid the second
1422 * call entirely. We only need the second call if the
1423 * stack-allocated buffer is too small. But a modest buffer
1424 * of 1024 bytes or so will often be big enough. Same applies
1430 setup_xattr(struct archive_read_disk *a,
1431 struct archive_entry *entry, const char *name, int fd, const char *accpath)
1438 size = fgetxattr(fd, name, NULL, 0);
1439 else if (!a->follow_symlinks)
1440 size = lgetxattr(accpath, name, NULL, 0);
1442 size = getxattr(accpath, name, NULL, 0);
1445 size = fgetea(fd, name, NULL, 0);
1446 else if (!a->follow_symlinks)
1447 size = lgetea(accpath, name, NULL, 0);
1449 size = getea(accpath, name, NULL, 0);
1453 archive_set_error(&a->archive, errno,
1454 "Couldn't query extended attribute");
1455 return (ARCHIVE_WARN);
1458 if (size > 0 && (value = malloc(size)) == NULL) {
1459 archive_set_error(&a->archive, errno, "Out of memory");
1460 return (ARCHIVE_FATAL);
1465 size = fgetxattr(fd, name, value, size);
1466 else if (!a->follow_symlinks)
1467 size = lgetxattr(accpath, name, value, size);
1469 size = getxattr(accpath, name, value, size);
1472 size = fgetea(fd, name, value, size);
1473 else if (!a->follow_symlinks)
1474 size = lgetea(accpath, name, value, size);
1476 size = getea(accpath, name, value, size);
1480 archive_set_error(&a->archive, errno,
1481 "Couldn't read extended attribute");
1482 return (ARCHIVE_WARN);
1485 archive_entry_xattr_add_entry(entry, name, value, size);
1488 return (ARCHIVE_OK);
1492 setup_xattrs(struct archive_read_disk *a,
1493 struct archive_entry *entry, int *fd)
1502 path = archive_entry_sourcepath(entry);
1503 if (path == NULL || (a->tree != NULL &&
1504 a->tree_enter_working_dir(a->tree) != 0))
1505 path = archive_entry_pathname(entry);
1507 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1508 "Couldn't determine file path to read "
1509 "extended attributes");
1510 return (ARCHIVE_WARN);
1512 if (a->tree != NULL && (a->follow_symlinks ||
1513 archive_entry_filetype(entry) != AE_IFLNK)) {
1514 *fd = a->open_on_current_dir(a->tree,
1515 path, O_RDONLY | O_NONBLOCK);
1521 list_size = flistxattr(*fd, NULL, 0);
1522 else if (!a->follow_symlinks)
1523 list_size = llistxattr(path, NULL, 0);
1525 list_size = listxattr(path, NULL, 0);
1528 list_size = flistea(*fd, NULL, 0);
1529 else if (!a->follow_symlinks)
1530 list_size = llistea(path, NULL, 0);
1532 list_size = listea(path, NULL, 0);
1535 if (list_size == -1) {
1536 if (errno == ENOTSUP || errno == ENOSYS)
1537 return (ARCHIVE_OK);
1538 archive_set_error(&a->archive, errno,
1539 "Couldn't list extended attributes");
1540 return (ARCHIVE_WARN);
1544 return (ARCHIVE_OK);
1546 if ((list = malloc(list_size)) == NULL) {
1547 archive_set_error(&a->archive, errno, "Out of memory");
1548 return (ARCHIVE_FATAL);
1553 list_size = flistxattr(*fd, list, list_size);
1554 else if (!a->follow_symlinks)
1555 list_size = llistxattr(path, list, list_size);
1557 list_size = listxattr(path, list, list_size);
1560 list_size = flistea(*fd, list, list_size);
1561 else if (!a->follow_symlinks)
1562 list_size = llistea(path, list, list_size);
1564 list_size = listea(path, list, list_size);
1567 if (list_size == -1) {
1568 archive_set_error(&a->archive, errno,
1569 "Couldn't retrieve extended attributes");
1571 return (ARCHIVE_WARN);
1574 for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
1575 if (strncmp(p, "system.", 7) == 0 ||
1576 strncmp(p, "xfsroot.", 8) == 0)
1578 setup_xattr(a, entry, p, *fd, path);
1582 return (ARCHIVE_OK);
1585 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
1586 HAVE_DECL_EXTATTR_NAMESPACE_USER
1589 * FreeBSD extattr interface.
1592 /* TODO: Implement this. Follow the Linux model above, but
1593 * with FreeBSD-specific system calls, of course. Be careful
1594 * to not include the system extattrs that hold ACLs; we handle
1598 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1599 int namespace, const char *name, const char *fullname, int fd,
1603 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1604 int namespace, const char *name, const char *fullname, int fd,
1605 const char *accpath)
1611 size = extattr_get_fd(fd, namespace, name, NULL, 0);
1612 else if (!a->follow_symlinks)
1613 size = extattr_get_link(accpath, namespace, name, NULL, 0);
1615 size = extattr_get_file(accpath, namespace, name, NULL, 0);
1618 archive_set_error(&a->archive, errno,
1619 "Couldn't query extended attribute");
1620 return (ARCHIVE_WARN);
1623 if (size > 0 && (value = malloc(size)) == NULL) {
1624 archive_set_error(&a->archive, errno, "Out of memory");
1625 return (ARCHIVE_FATAL);
1629 size = extattr_get_fd(fd, namespace, name, value, size);
1630 else if (!a->follow_symlinks)
1631 size = extattr_get_link(accpath, namespace, name, value, size);
1633 size = extattr_get_file(accpath, namespace, name, value, size);
1637 archive_set_error(&a->archive, errno,
1638 "Couldn't read extended attribute");
1639 return (ARCHIVE_WARN);
1642 archive_entry_xattr_add_entry(entry, fullname, value, size);
1645 return (ARCHIVE_OK);
1649 setup_xattrs(struct archive_read_disk *a,
1650 struct archive_entry *entry, int *fd)
1656 int namespace = EXTATTR_NAMESPACE_USER;
1661 path = archive_entry_sourcepath(entry);
1662 if (path == NULL || (a->tree != NULL &&
1663 a->tree_enter_working_dir(a->tree) != 0))
1664 path = archive_entry_pathname(entry);
1666 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1667 "Couldn't determine file path to read "
1668 "extended attributes");
1669 return (ARCHIVE_WARN);
1671 if (a->tree != NULL && (a->follow_symlinks ||
1672 archive_entry_filetype(entry) != AE_IFLNK)) {
1673 *fd = a->open_on_current_dir(a->tree,
1674 path, O_RDONLY | O_NONBLOCK);
1679 list_size = extattr_list_fd(*fd, namespace, NULL, 0);
1680 else if (!a->follow_symlinks)
1681 list_size = extattr_list_link(path, namespace, NULL, 0);
1683 list_size = extattr_list_file(path, namespace, NULL, 0);
1685 if (list_size == -1 && errno == EOPNOTSUPP)
1686 return (ARCHIVE_OK);
1687 if (list_size == -1) {
1688 archive_set_error(&a->archive, errno,
1689 "Couldn't list extended attributes");
1690 return (ARCHIVE_WARN);
1694 return (ARCHIVE_OK);
1696 if ((list = malloc(list_size)) == NULL) {
1697 archive_set_error(&a->archive, errno, "Out of memory");
1698 return (ARCHIVE_FATAL);
1702 list_size = extattr_list_fd(*fd, namespace, list, list_size);
1703 else if (!a->follow_symlinks)
1704 list_size = extattr_list_link(path, namespace, list, list_size);
1706 list_size = extattr_list_file(path, namespace, list, list_size);
1708 if (list_size == -1) {
1709 archive_set_error(&a->archive, errno,
1710 "Couldn't retrieve extended attributes");
1712 return (ARCHIVE_WARN);
1716 while ((p - list) < list_size) {
1717 size_t len = 255 & (int)*p;
1720 strcpy(buff, "user.");
1721 name = buff + strlen(buff);
1722 memcpy(name, p + 1, len);
1724 setup_xattr(a, entry, namespace, name, buff, *fd, path);
1729 return (ARCHIVE_OK);
1735 * Generic (stub) extended attribute support.
1738 setup_xattrs(struct archive_read_disk *a,
1739 struct archive_entry *entry, int *fd)
1741 (void)a; /* UNUSED */
1742 (void)entry; /* UNUSED */
1743 (void)fd; /* UNUSED */
1744 return (ARCHIVE_OK);
1749 #if defined(HAVE_LINUX_FIEMAP_H)
1752 * Linux FIEMAP sparse interface.
1754 * The FIEMAP ioctl returns an "extent" for each physical allocation
1755 * on disk. We need to process those to generate a more compact list
1756 * of logical file blocks. We also need to be very careful to use
1757 * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
1758 * does not report allocations for newly-written data that hasn't
1759 * been synced to disk.
1761 * It's important to return a minimal sparse file list because we want
1762 * to not trigger sparse file extensions if we don't have to, since
1763 * not all readers support them.
1767 setup_sparse_fiemap(struct archive_read_disk *a,
1768 struct archive_entry *entry, int *fd)
1772 struct fiemap_extent *fe;
1774 int count, do_fiemap, iters;
1775 int exit_sts = ARCHIVE_OK;
1777 if (archive_entry_filetype(entry) != AE_IFREG
1778 || archive_entry_size(entry) <= 0
1779 || archive_entry_hardlink(entry) != NULL)
1780 return (ARCHIVE_OK);
1785 path = archive_entry_sourcepath(entry);
1787 path = archive_entry_pathname(entry);
1788 if (a->tree != NULL)
1789 *fd = a->open_on_current_dir(a->tree, path,
1790 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1792 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1794 archive_set_error(&a->archive, errno,
1795 "Can't open `%s'", path);
1796 return (ARCHIVE_FAILED);
1798 __archive_ensure_cloexec_flag(*fd);
1801 /* Initialize buffer to avoid the error valgrind complains about. */
1802 memset(buff, 0, sizeof(buff));
1803 count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
1804 fm = (struct fiemap *)buff;
1806 fm->fm_length = ~0ULL;;
1807 fm->fm_flags = FIEMAP_FLAG_SYNC;
1808 fm->fm_extent_count = count;
1810 size = archive_entry_size(entry);
1811 for (iters = 0; ; ++iters) {
1814 r = ioctl(*fd, FS_IOC_FIEMAP, fm);
1816 /* When something error happens, it is better we
1817 * should return ARCHIVE_OK because an earlier
1818 * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
1819 goto exit_setup_sparse_fiemap;
1821 if (fm->fm_mapped_extents == 0) {
1823 /* Fully sparse file; insert a zero-length "data" entry */
1824 archive_entry_sparse_add_entry(entry, 0, 0);
1828 fe = fm->fm_extents;
1829 for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
1830 if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
1831 /* The fe_length of the last block does not
1832 * adjust itself to its size files. */
1833 int64_t length = fe->fe_length;
1834 if (fe->fe_logical + length > (uint64_t)size)
1835 length -= fe->fe_logical + length - size;
1836 if (fe->fe_logical == 0 && length == size) {
1837 /* This is not sparse. */
1842 archive_entry_sparse_add_entry(entry,
1843 fe->fe_logical, length);
1845 if (fe->fe_flags & FIEMAP_EXTENT_LAST)
1849 fe = fm->fm_extents + fm->fm_mapped_extents -1;
1850 fm->fm_start = fe->fe_logical + fe->fe_length;
1854 exit_setup_sparse_fiemap:
1858 #if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1860 setup_sparse(struct archive_read_disk *a,
1861 struct archive_entry *entry, int *fd)
1863 return setup_sparse_fiemap(a, entry, fd);
1866 #endif /* defined(HAVE_LINUX_FIEMAP_H) */
1868 #if defined(SEEK_HOLE) && defined(SEEK_DATA)
1871 * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
1875 setup_sparse(struct archive_read_disk *a,
1876 struct archive_entry *entry, int *fd)
1881 int exit_sts = ARCHIVE_OK;
1882 int check_fully_sparse = 0;
1884 if (archive_entry_filetype(entry) != AE_IFREG
1885 || archive_entry_size(entry) <= 0
1886 || archive_entry_hardlink(entry) != NULL)
1887 return (ARCHIVE_OK);
1889 /* Does filesystem support the reporting of hole ? */
1890 if (*fd < 0 && a->tree != NULL) {
1893 path = archive_entry_sourcepath(entry);
1895 path = archive_entry_pathname(entry);
1896 *fd = a->open_on_current_dir(a->tree, path,
1897 O_RDONLY | O_NONBLOCK);
1899 archive_set_error(&a->archive, errno,
1900 "Can't open `%s'", path);
1901 return (ARCHIVE_FAILED);
1906 #ifdef _PC_MIN_HOLE_SIZE
1907 if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
1908 return (ARCHIVE_OK);
1910 initial_off = lseek(*fd, 0, SEEK_CUR);
1911 if (initial_off != 0)
1912 lseek(*fd, 0, SEEK_SET);
1916 path = archive_entry_sourcepath(entry);
1918 path = archive_entry_pathname(entry);
1920 #ifdef _PC_MIN_HOLE_SIZE
1921 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
1922 return (ARCHIVE_OK);
1924 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1926 archive_set_error(&a->archive, errno,
1927 "Can't open `%s'", path);
1928 return (ARCHIVE_FAILED);
1930 __archive_ensure_cloexec_flag(*fd);
1934 #ifndef _PC_MIN_HOLE_SIZE
1935 /* Check if the underlying filesystem supports seek hole */
1936 off_s = lseek(*fd, 0, SEEK_HOLE);
1938 #if defined(HAVE_LINUX_FIEMAP_H)
1939 return setup_sparse_fiemap(a, entry, fd);
1941 goto exit_setup_sparse;
1944 lseek(*fd, 0, SEEK_SET);
1948 size = archive_entry_size(entry);
1949 while (off_s < size) {
1950 off_s = lseek(*fd, off_s, SEEK_DATA);
1951 if (off_s == (off_t)-1) {
1952 if (errno == ENXIO) {
1954 if (archive_entry_sparse_count(entry) == 0) {
1955 /* Potentially a fully-sparse file. */
1956 check_fully_sparse = 1;
1960 archive_set_error(&a->archive, errno,
1961 "lseek(SEEK_HOLE) failed");
1962 exit_sts = ARCHIVE_FAILED;
1963 goto exit_setup_sparse;
1965 off_e = lseek(*fd, off_s, SEEK_HOLE);
1966 if (off_e == (off_t)-1) {
1967 if (errno == ENXIO) {
1968 off_e = lseek(*fd, 0, SEEK_END);
1969 if (off_e != (off_t)-1)
1970 break;/* no more data */
1972 archive_set_error(&a->archive, errno,
1973 "lseek(SEEK_DATA) failed");
1974 exit_sts = ARCHIVE_FAILED;
1975 goto exit_setup_sparse;
1977 if (off_s == 0 && off_e == size)
1978 break;/* This is not sparse. */
1979 archive_entry_sparse_add_entry(entry, off_s,
1984 if (check_fully_sparse) {
1985 if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
1986 lseek(*fd, 0, SEEK_END) == size) {
1987 /* Fully sparse file; insert a zero-length "data" entry */
1988 archive_entry_sparse_add_entry(entry, 0, 0);
1992 lseek(*fd, initial_off, SEEK_SET);
1996 #elif !defined(HAVE_LINUX_FIEMAP_H)
1999 * Generic (stub) sparse support.
2002 setup_sparse(struct archive_read_disk *a,
2003 struct archive_entry *entry, int *fd)
2005 (void)a; /* UNUSED */
2006 (void)entry; /* UNUSED */
2007 (void)fd; /* UNUSED */
2008 return (ARCHIVE_OK);
2013 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */