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$");
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 ACL_TYPE_EXTENDED
129 #elif HAVE_FREEBSD_NFS4_ACL
130 #define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4
133 static int setup_acls(struct archive_read_disk *,
134 struct archive_entry *, int *fd);
135 static int setup_mac_metadata(struct archive_read_disk *,
136 struct archive_entry *, int *fd);
137 static int setup_xattrs(struct archive_read_disk *,
138 struct archive_entry *, int *fd);
139 static int setup_sparse(struct archive_read_disk *,
140 struct archive_entry *, int *fd);
141 #if defined(HAVE_LINUX_FIEMAP_H)
142 static int setup_sparse_fiemap(struct archive_read_disk *,
143 struct archive_entry *, int *fd);
147 archive_read_disk_entry_from_file(struct archive *_a,
148 struct archive_entry *entry,
150 const struct stat *st)
152 struct archive_read_disk *a = (struct archive_read_disk *)_a;
153 const char *path, *name;
158 archive_clear_error(_a);
159 path = archive_entry_sourcepath(entry);
161 path = archive_entry_pathname(entry);
163 if (a->tree == NULL) {
167 if (fstat(fd, &s) != 0) {
168 archive_set_error(&a->archive, errno,
170 return (ARCHIVE_FAILED);
175 if (!a->follow_symlinks) {
176 if (lstat(path, &s) != 0) {
177 archive_set_error(&a->archive, errno,
178 "Can't lstat %s", path);
179 return (ARCHIVE_FAILED);
183 if (stat(path, &s) != 0) {
184 archive_set_error(&a->archive, errno,
185 "Can't stat %s", path);
186 return (ARCHIVE_FAILED);
190 archive_entry_copy_stat(entry, st);
193 /* Lookup uname/gname */
194 name = archive_read_disk_uname(_a, archive_entry_uid(entry));
196 archive_entry_copy_uname(entry, name);
197 name = archive_read_disk_gname(_a, archive_entry_gid(entry));
199 archive_entry_copy_gname(entry, name);
201 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
202 /* On FreeBSD, we get flags for free with the stat. */
203 /* TODO: Does this belong in copy_stat()? */
204 if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)
205 archive_entry_set_fflags(entry, st->st_flags, 0);
208 #if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
209 (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
210 /* Linux requires an extra ioctl to pull the flags. Although
211 * this is an extra step, it has a nice side-effect: We get an
212 * open file descriptor which we can use in the subsequent lookups. */
213 if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&
214 (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
217 fd = a->open_on_current_dir(a->tree, path,
218 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
220 fd = open(path, O_RDONLY | O_NONBLOCK |
222 __archive_ensure_cloexec_flag(fd);
227 #if defined(FS_IOC_GETFLAGS)
233 if (r == 0 && stflags != 0)
234 archive_entry_set_fflags(entry, stflags, 0);
239 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
240 if (S_ISLNK(st->st_mode)) {
241 size_t linkbuffer_len = st->st_size + 1;
245 linkbuffer = malloc(linkbuffer_len);
246 if (linkbuffer == NULL) {
247 archive_set_error(&a->archive, ENOMEM,
248 "Couldn't read link data");
249 return (ARCHIVE_FAILED);
251 if (a->tree != NULL) {
252 #ifdef HAVE_READLINKAT
253 lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
254 path, linkbuffer, linkbuffer_len);
256 if (a->tree_enter_working_dir(a->tree) != 0) {
257 archive_set_error(&a->archive, errno,
258 "Couldn't read link data");
260 return (ARCHIVE_FAILED);
262 lnklen = readlink(path, linkbuffer, linkbuffer_len);
263 #endif /* HAVE_READLINKAT */
265 lnklen = readlink(path, linkbuffer, linkbuffer_len);
267 archive_set_error(&a->archive, errno,
268 "Couldn't read link data");
270 return (ARCHIVE_FAILED);
272 linkbuffer[lnklen] = 0;
273 archive_entry_set_symlink(entry, linkbuffer);
276 #endif /* HAVE_READLINK || HAVE_READLINKAT */
279 if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
280 r = setup_acls(a, entry, &fd);
281 if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
282 r1 = setup_xattrs(a, entry, &fd);
286 if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
287 r1 = setup_mac_metadata(a, entry, &fd);
291 r1 = setup_sparse(a, entry, &fd);
295 /* If we opened the file earlier in this function, close it. */
296 if (initial_fd != fd)
301 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
303 * The Mac OS "copyfile()" API copies the extended metadata for a
304 * file into a separate file in AppleDouble format (see RFC 1740).
306 * Mac OS tar and cpio implementations store this extended
307 * metadata as a separate entry just before the regular entry
308 * with a "._" prefix added to the filename.
310 * Note that this is currently done unconditionally; the tar program has
311 * an option to discard this information before the archive is written.
313 * TODO: If there's a failure, report it and return ARCHIVE_WARN.
316 setup_mac_metadata(struct archive_read_disk *a,
317 struct archive_entry *entry, int *fd)
320 int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
321 struct stat copyfile_stat;
322 int ret = ARCHIVE_OK;
325 const char *name, *tempdir;
326 struct archive_string tempfile;
328 (void)fd; /* UNUSED */
329 name = archive_entry_sourcepath(entry);
331 name = archive_entry_pathname(entry);
332 else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) {
333 archive_set_error(&a->archive, errno,
334 "Can't change dir to read extended attributes");
335 return (ARCHIVE_FAILED);
338 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
339 "Can't open file to read extended attributes: No name");
340 return (ARCHIVE_WARN);
343 /* Short-circuit if there's nothing to do. */
344 have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
345 if (have_attrs == -1) {
346 archive_set_error(&a->archive, errno,
347 "Could not check extended attributes");
348 return (ARCHIVE_WARN);
354 if (issetugid() == 0)
355 tempdir = getenv("TMPDIR");
358 archive_string_init(&tempfile);
359 archive_strcpy(&tempfile, tempdir);
360 archive_strcat(&tempfile, "tar.md.XXXXXX");
361 tempfd = mkstemp(tempfile.s);
363 archive_set_error(&a->archive, errno,
364 "Could not open extended attribute file");
368 __archive_ensure_cloexec_flag(tempfd);
370 /* XXX I wish copyfile() could pack directly to a memory
371 * buffer; that would avoid the temp file here. For that
372 * matter, it would be nice if fcopyfile() actually worked,
373 * that would reduce the many open/close races here. */
374 if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
375 archive_set_error(&a->archive, errno,
376 "Could not pack extended attributes");
380 if (fstat(tempfd, ©file_stat)) {
381 archive_set_error(&a->archive, errno,
382 "Could not check size of extended attributes");
386 buff = malloc(copyfile_stat.st_size);
388 archive_set_error(&a->archive, errno,
389 "Could not allocate memory for extended attributes");
393 if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
394 archive_set_error(&a->archive, errno,
395 "Could not read extended attributes into memory");
399 archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
406 archive_string_free(&tempfile);
414 * Stub implementation for non-Mac systems.
417 setup_mac_metadata(struct archive_read_disk *a,
418 struct archive_entry *entry, int *fd)
420 (void)a; /* UNUSED */
421 (void)entry; /* UNUSED */
422 (void)fd; /* UNUSED */
428 static int translate_guid(struct archive *, acl_entry_t,
429 int *, int *, const char **);
431 static void add_trivial_nfs4_acl(struct archive_entry *);
436 sun_acl_is_trivial(void *, int, mode_t, int, int, int *);
439 sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
447 size = sizeof(aclent_t);
449 #if HAVE_SUN_NFS4_ACL
450 else if (cmd == ACE_GETACL) {
451 cntcmd = ACE_GETACLCNT;
452 size = sizeof(ace_t);
464 while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
466 cnt = acl(path, cntcmd, 0, NULL);
468 cnt = facl(fd, cntcmd, 0, NULL);
472 aclp = malloc(cnt * size);
474 aclp = realloc(NULL, cnt * size);
477 cnt = acl(path, cmd, cnt, aclp);
479 cnt = facl(fd, cmd, cnt, aclp);
493 #endif /* HAVE_SUN_ACL */
495 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
496 static int translate_acl(struct archive_read_disk *a,
497 struct archive_entry *entry,
504 int archive_entry_acl_type);
507 setup_acls(struct archive_read_disk *a,
508 struct archive_entry *entry, int *fd)
521 #if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP
524 /* For default ACLs on Linux we need reachable accpath */
525 if (*fd < 0 || S_ISDIR(archive_entry_mode(entry)))
528 accpath = archive_entry_sourcepath(entry);
529 if (accpath == NULL || (a->tree != NULL &&
530 a->tree_enter_working_dir(a->tree) != 0))
531 accpath = archive_entry_pathname(entry);
532 if (accpath == NULL) {
533 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
534 "Couldn't determine file path to read ACLs");
535 return (ARCHIVE_WARN);
537 if (a->tree != NULL &&
538 #if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP
541 (a->follow_symlinks ||
542 archive_entry_filetype(entry) != AE_IFLNK)) {
543 *fd = a->open_on_current_dir(a->tree,
544 accpath, O_RDONLY | O_NONBLOCK);
548 archive_entry_acl_clear(entry);
557 /* Try NFSv4 ACL first. */
560 aclp = sunacl_get(ACE_GETACL, &aclcnt, *fd, NULL);
561 #elif HAVE_ACL_GET_FD_NP
562 acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
564 acl = acl_get_fd(*fd);
566 #if HAVE_ACL_GET_LINK_NP
567 else if (!a->follow_symlinks)
568 acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
570 else if ((!a->follow_symlinks)
571 && (archive_entry_filetype(entry) == AE_IFLNK))
572 /* We can't get the ACL of a symlink, so we assume it can't
579 #endif /* !HAVE_ACL_GET_LINK_NP */
582 /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
583 aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath);
585 acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
589 /* Ignore "trivial" ACLs that just mirror the file mode. */
591 if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt,
592 archive_entry_mode(entry), 1, S_ISDIR(archive_entry_mode(entry)),
593 &r) == 0 && r == 1) {
598 #elif HAVE_ACL_IS_TRIVIAL_NP
599 if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
612 r = translate_acl(a, entry,
618 ARCHIVE_ENTRY_ACL_TYPE_NFS4);
627 if (r != ARCHIVE_OK) {
628 archive_set_error(&a->archive, errno,
629 "Couldn't translate NFSv4 ACLs");
633 * Because Mac OS doesn't support owner@, group@ and everyone@
634 * ACLs we need to add NFSv4 ACLs mirroring the file mode to
635 * the archive entry. Otherwise extraction on non-Mac platforms
636 * would lead to an invalid file mode.
638 if ((archive_entry_acl_types(entry) &
639 ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
640 add_trivial_nfs4_acl(entry);
644 #endif /* HAVE_NFS4_ACL */
646 #if HAVE_POSIX_ACL || HAVE_SUN_ACL
647 /* This code path is skipped on MacOS */
649 /* Retrieve access ACL from file. */
652 aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL);
654 acl = acl_get_fd(*fd);
656 #if HAVE_ACL_GET_LINK_NP
657 else if (!a->follow_symlinks)
658 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
660 else if ((!a->follow_symlinks)
661 && (archive_entry_filetype(entry) == AE_IFLNK))
662 /* We can't get the ACL of a symlink, so we assume it can't
669 #endif /* !HAVE_ACL_GET_LINK_NP */
672 aclp = sunacl_get(GETACL, &aclcnt, 0, accpath);
674 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
678 /* Ignore "trivial" ACLs that just mirror the file mode. */
680 if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt,
681 archive_entry_mode(entry), 0, S_ISDIR(archive_entry_mode(entry)),
682 &r) == 0 && r == 1) {
686 #elif HAVE_ACL_IS_TRIVIAL_NP
687 if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
699 r = translate_acl(a, entry,
705 ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
714 if (r != ARCHIVE_OK) {
715 archive_set_error(&a->archive, errno,
716 "Couldn't translate access ACLs");
722 /* Only directories can have default ACLs. */
723 if (S_ISDIR(archive_entry_mode(entry))) {
724 #if HAVE_ACL_GET_FD_NP
726 acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
729 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
731 r = translate_acl(a, entry, acl,
732 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
734 if (r != ARCHIVE_OK) {
735 archive_set_error(&a->archive, errno,
736 "Couldn't translate default ACLs");
741 #endif /* !HAVE_SUN_ACL */
742 #endif /* HAVE_POSIX_ACL || HAVE_SUN_ACL */
747 * Translate system ACL permissions into libarchive internal structure
749 static const struct {
750 const int archive_perm;
751 const int platform_perm;
753 #if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */
754 {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
755 {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
756 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
757 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
758 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
759 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
760 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
761 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
762 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
763 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
764 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
765 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
766 {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
767 {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
768 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
769 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
770 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
771 #elif HAVE_DARWIN_ACL /* MacOS ACL permissions */
772 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
773 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
774 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
775 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
776 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
777 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
778 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
779 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
780 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
781 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
782 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
783 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
784 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
785 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
786 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
787 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
788 #if HAVE_DECL_ACL_SYNCHRONIZE
789 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
791 #else /* POSIX.1e ACL permissions */
792 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
793 {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
794 {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
795 #if HAVE_FREEBSD_NFS4_ACL /* FreeBSD NFSv4 ACL permissions */
796 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
797 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
798 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
799 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
800 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
801 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
802 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
803 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
804 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
805 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
806 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
807 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
808 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
809 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
810 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
811 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
813 #endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
818 * Translate system NFSv4 inheritance flags into libarchive internal structure
820 static const struct {
821 const int archive_inherit;
822 const int platform_inherit;
823 } acl_inherit_map[] = {
824 #if HAVE_SUN_NFS4_ACL /* Solaris ACL inheritance flags */
825 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
826 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
827 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
828 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
829 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
830 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
831 #ifdef ACE_INHERITED_ACE
832 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
834 #elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */
835 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
836 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
837 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
838 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
839 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
840 #else /* FreeBSD NFSv4 ACL inheritance flags */
841 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
842 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
843 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
844 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
845 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
846 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
847 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
848 #endif /* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
850 #endif /* HAVE_NFS4_ACL */
853 static int translate_guid(struct archive *a, acl_entry_t acl_entry,
854 int *ae_id, int *ae_tag, const char **ae_name)
862 q = acl_get_qualifier(acl_entry);
865 r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
870 if (idtype == ID_TYPE_UID) {
871 *ae_tag = ARCHIVE_ENTRY_ACL_USER;
877 *ae_id = pwd->pw_uid;
878 *ae_name = archive_read_disk_uname(a, *ae_id);
880 } else if (idtype == ID_TYPE_GID) {
881 *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
887 *ae_id = grp->gr_gid;
888 *ae_name = archive_read_disk_gname(a, *ae_id);
898 * Add trivial NFSv4 ACL entries from mode
901 add_trivial_nfs4_acl(struct archive_entry *entry)
905 const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
906 const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
907 ARCHIVE_ENTRY_ACL_APPEND_DATA;
908 const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
909 const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
910 ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
911 ARCHIVE_ENTRY_ACL_READ_ACL |
912 ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
913 const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
914 ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
915 ARCHIVE_ENTRY_ACL_WRITE_ACL |
916 ARCHIVE_ENTRY_ACL_WRITE_OWNER;
923 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
924 {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
925 {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
926 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
927 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
928 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
931 mode = archive_entry_mode(entry);
933 /* Permissions for everyone@ */
935 tacl_entry[5].permset |= rperm;
937 tacl_entry[5].permset |= wperm;
939 tacl_entry[5].permset |= eperm;
941 /* Permissions for group@ */
943 tacl_entry[4].permset |= rperm;
944 else if (mode & 0004)
945 tacl_entry[2].permset |= rperm;
947 tacl_entry[4].permset |= wperm;
948 else if (mode & 0002)
949 tacl_entry[2].permset |= wperm;
951 tacl_entry[4].permset |= eperm;
952 else if (mode & 0001)
953 tacl_entry[2].permset |= eperm;
955 /* Permissions for owner@ */
957 tacl_entry[3].permset |= rperm;
958 if (!(mode & 0040) && (mode & 0004))
959 tacl_entry[0].permset |= rperm;
960 } else if ((mode & 0040) || (mode & 0004))
961 tacl_entry[1].permset |= rperm;
963 tacl_entry[3].permset |= wperm;
964 if (!(mode & 0020) && (mode & 0002))
965 tacl_entry[0].permset |= wperm;
966 } else if ((mode & 0020) || (mode & 0002))
967 tacl_entry[1].permset |= wperm;
969 tacl_entry[3].permset |= eperm;
970 if (!(mode & 0010) && (mode & 0001))
971 tacl_entry[0].permset |= eperm;
972 } else if ((mode & 0010) || (mode & 0001))
973 tacl_entry[1].permset |= eperm;
975 for (i = 0; i < 6; i++) {
976 if (tacl_entry[i].permset != 0) {
977 archive_entry_acl_add_entry(entry,
978 tacl_entry[i].type, tacl_entry[i].permset,
979 tacl_entry[i].tag, -1, NULL);
987 * Check if acl is trivial
988 * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
991 sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4,
992 int is_dir, int *trivialp)
995 #if HAVE_SUN_NFS4_ACL
996 const uint32_t rperm = ACE_READ_DATA;
997 const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
998 const uint32_t eperm = ACE_EXECUTE;
999 const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
1000 ACE_READ_ACL | ACE_SYNCHRONIZE;
1001 const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
1002 ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
1008 if (aclp == NULL || trivialp == NULL)
1014 * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
1015 * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
1024 #if HAVE_SUN_NFS4_ACL
1026 * Continue with checking NFSv4 ACLs
1028 * Create list of trivial ace's to be compared
1031 /* owner@ allow pre */
1032 tace[0].a_flags = ACE_OWNER;
1033 tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1034 tace[0].a_access_mask = 0;
1037 tace[1].a_flags = ACE_OWNER;
1038 tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
1039 tace[1].a_access_mask = 0;
1042 tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
1043 tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
1044 tace[2].a_access_mask = 0;
1047 tace[3].a_flags = ACE_OWNER;
1048 tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1049 tace[3].a_access_mask = ownset;
1052 tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
1053 tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1054 tace[4].a_access_mask = pubset;
1056 /* everyone@ allow */
1057 tace[5].a_flags = ACE_EVERYONE;
1058 tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1059 tace[5].a_access_mask = pubset;
1061 /* Permissions for everyone@ */
1063 tace[5].a_access_mask |= rperm;
1065 tace[5].a_access_mask |= wperm;
1067 tace[5].a_access_mask |= eperm;
1069 /* Permissions for group@ */
1071 tace[4].a_access_mask |= rperm;
1072 else if (mode & 0004)
1073 tace[2].a_access_mask |= rperm;
1075 tace[4].a_access_mask |= wperm;
1076 else if (mode & 0002)
1077 tace[2].a_access_mask |= wperm;
1079 tace[4].a_access_mask |= eperm;
1080 else if (mode & 0001)
1081 tace[2].a_access_mask |= eperm;
1083 /* Permissions for owner@ */
1085 tace[3].a_access_mask |= rperm;
1086 if (!(mode & 0040) && (mode & 0004))
1087 tace[0].a_access_mask |= rperm;
1088 } else if ((mode & 0040) || (mode & 0004))
1089 tace[1].a_access_mask |= rperm;
1091 tace[3].a_access_mask |= wperm;
1092 if (!(mode & 0020) && (mode & 0002))
1093 tace[0].a_access_mask |= wperm;
1094 } else if ((mode & 0020) || (mode & 0002))
1095 tace[1].a_access_mask |= wperm;
1097 tace[3].a_access_mask |= eperm;
1098 if (!(mode & 0010) && (mode & 0001))
1099 tace[0].a_access_mask |= eperm;
1100 } else if ((mode & 0010) || (mode & 0001))
1101 tace[1].a_access_mask |= eperm;
1103 /* Check if the acl count matches */
1105 for (i = 0; i < 3; i++) {
1106 if (tace[i].a_access_mask != 0)
1113 for (i = 0; i < 6; i++) {
1114 if (tace[i].a_access_mask != 0) {
1115 ace = &((ace_t *)aclp)[p];
1117 * Illumos added ACE_DELETE_CHILD to write perms for
1118 * directories. We have to check against that, too.
1120 if (ace->a_flags != tace[i].a_flags ||
1121 ace->a_type != tace[i].a_type ||
1122 (ace->a_access_mask != tace[i].a_access_mask &&
1123 (!is_dir || (tace[i].a_access_mask & wperm) == 0 ||
1124 ace->a_access_mask !=
1125 (tace[i].a_access_mask | ACE_DELETE_CHILD))))
1132 #else /* !HAVE_SUN_NFS4_ACL */
1133 (void)aclp; /* UNUSED */
1134 #endif /* !HAVE_SUN_NFS4_ACL */
1137 #endif /* HAVE_SUN_ACL */
1141 * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
1144 translate_acl(struct archive_read_disk *a,
1145 struct archive_entry *entry, void *aclp, int aclcnt,
1146 int default_entry_acl_type)
1149 int ae_id, ae_tag, ae_perm;
1151 const char *ae_name;
1153 #if HAVE_SUN_NFS4_ACL
1158 return (ARCHIVE_OK);
1160 for (e = 0; e < aclcnt; e++) {
1165 #if HAVE_SUN_NFS4_ACL
1166 if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1167 ace = &((ace_t *)aclp)[e];
1170 switch(ace->a_type) {
1171 case ACE_ACCESS_ALLOWED_ACE_TYPE:
1172 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1174 case ACE_ACCESS_DENIED_ACE_TYPE:
1175 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1177 case ACE_SYSTEM_AUDIT_ACE_TYPE:
1178 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1180 case ACE_SYSTEM_ALARM_ACE_TYPE:
1181 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1184 /* Unknown entry type, skip */
1188 if ((ace->a_flags & ACE_OWNER) != 0)
1189 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1190 else if ((ace->a_flags & ACE_GROUP) != 0)
1191 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1192 else if ((ace->a_flags & ACE_EVERYONE) != 0)
1193 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1194 else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
1195 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1196 ae_name = archive_read_disk_gname(&a->archive,
1199 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1200 ae_name = archive_read_disk_uname(&a->archive,
1204 for (i = 0; i < (int)(sizeof(acl_inherit_map) /
1205 sizeof(acl_inherit_map[0])); ++i) {
1207 acl_inherit_map[i].platform_inherit) != 0)
1209 acl_inherit_map[i].archive_inherit;
1212 for (i = 0; i < (int)(sizeof(acl_perm_map) /
1213 sizeof(acl_perm_map[0])); ++i) {
1214 if ((ace->a_access_mask &
1215 acl_perm_map[i].platform_perm) != 0)
1217 acl_perm_map[i].archive_perm;
1220 #endif /* HAVE_SUN_NFS4_ACL */
1221 if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
1222 aclent = &((aclent_t *)aclp)[e];
1223 if ((aclent->a_type & ACL_DEFAULT) != 0)
1224 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
1226 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1227 ae_id = aclent->a_id;
1229 switch(aclent->a_type) {
1232 ae_name = archive_read_disk_uname(&a->archive,
1234 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1238 ae_name = archive_read_disk_gname(&a->archive,
1240 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1244 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1248 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1252 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1256 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1259 /* Unknown tag type, skip */
1263 if ((aclent->a_perm & 1) != 0)
1264 ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
1265 if ((aclent->a_perm & 2) != 0)
1266 ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
1267 if ((aclent->a_perm & 4) != 0)
1268 ae_perm |= ARCHIVE_ENTRY_ACL_READ;
1270 return (ARCHIVE_WARN);
1272 archive_entry_acl_add_entry(entry, entry_acl_type,
1273 ae_perm, ae_tag, ae_id, ae_name);
1275 return (ARCHIVE_OK);
1277 #else /* !HAVE_SUN_ACL */
1279 * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
1280 * MacOS (NFSv4 only) ACLs into libarchive internal structure
1283 translate_acl(struct archive_read_disk *a,
1284 struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
1287 #if HAVE_FREEBSD_NFS4_ACL
1288 acl_entry_type_t acl_type;
1291 #if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
1292 acl_flagset_t acl_flagset;
1294 acl_entry_t acl_entry;
1295 acl_permset_t acl_permset;
1296 int i, entry_acl_type;
1297 int r, s, ae_id, ae_tag, ae_perm;
1298 #if !HAVE_DARWIN_ACL
1301 const char *ae_name;
1303 #if HAVE_FREEBSD_NFS4_ACL
1304 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
1305 // Make sure the "brand" on this ACL is consistent
1306 // with the default_entry_acl_type bits provided.
1307 if (acl_get_brand_np(acl, &brand) != 0) {
1308 archive_set_error(&a->archive, errno,
1309 "Failed to read ACL brand");
1310 return (ARCHIVE_WARN);
1313 case ACL_BRAND_POSIX:
1314 switch (default_entry_acl_type) {
1315 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
1316 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
1319 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1320 "Invalid ACL entry type for POSIX.1e ACL");
1321 return (ARCHIVE_WARN);
1324 case ACL_BRAND_NFS4:
1325 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1326 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1327 "Invalid ACL entry type for NFSv4 ACL");
1328 return (ARCHIVE_WARN);
1332 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1333 "Unknown ACL brand");
1334 return (ARCHIVE_WARN);
1338 s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
1340 archive_set_error(&a->archive, errno,
1341 "Failed to get first ACL entry");
1342 return (ARCHIVE_WARN);
1347 #else /* FreeBSD, Linux */
1355 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
1356 archive_set_error(&a->archive, errno,
1357 "Failed to get ACL tag type");
1358 return (ARCHIVE_WARN);
1361 #if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
1363 q = acl_get_qualifier(acl_entry);
1365 ae_id = (int)*(uid_t *)q;
1367 ae_name = archive_read_disk_uname(&a->archive,
1370 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1373 q = acl_get_qualifier(acl_entry);
1375 ae_id = (int)*(gid_t *)q;
1377 ae_name = archive_read_disk_gname(&a->archive,
1380 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1383 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1386 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1389 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1392 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1394 #if HAVE_FREEBSD_NFS4_ACL
1396 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1399 #else /* HAVE_DARWIN_ACL */
1400 case ACL_EXTENDED_ALLOW:
1401 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1402 r = translate_guid(&a->archive, acl_entry, &ae_id,
1405 case ACL_EXTENDED_DENY:
1406 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1407 r = translate_guid(&a->archive, acl_entry, &ae_id,
1410 #endif /* HAVE_DARWIN_ACL */
1412 /* Skip types that libarchive can't support. */
1413 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1418 /* Skip if translate_guid() above failed */
1420 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1425 #if !HAVE_DARWIN_ACL
1426 // XXX acl_type maps to allow/deny/audit/YYYY bits
1427 entry_acl_type = default_entry_acl_type;
1429 #if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
1430 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1431 #if HAVE_FREEBSD_NFS4_ACL
1433 * acl_get_entry_type_np() fails with non-NFSv4 ACLs
1435 if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
1436 archive_set_error(&a->archive, errno, "Failed "
1437 "to get ACL type from a NFSv4 ACL entry");
1438 return (ARCHIVE_WARN);
1441 case ACL_ENTRY_TYPE_ALLOW:
1442 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1444 case ACL_ENTRY_TYPE_DENY:
1445 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1447 case ACL_ENTRY_TYPE_AUDIT:
1448 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
1450 case ACL_ENTRY_TYPE_ALARM:
1451 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1454 archive_set_error(&a->archive, errno,
1455 "Invalid NFSv4 ACL entry type");
1456 return (ARCHIVE_WARN);
1458 #endif /* HAVE_FREEBSD_NFS4_ACL */
1461 * Libarchive stores "flag" (NFSv4 inheritance bits)
1462 * in the ae_perm bitmap.
1464 * acl_get_flagset_np() fails with non-NFSv4 ACLs
1466 if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
1467 archive_set_error(&a->archive, errno,
1468 "Failed to get flagset from a NFSv4 ACL entry");
1469 return (ARCHIVE_WARN);
1471 for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
1472 r = acl_get_flag_np(acl_flagset,
1473 acl_inherit_map[i].platform_inherit);
1475 archive_set_error(&a->archive, errno,
1476 "Failed to check flag in a NFSv4 "
1478 return (ARCHIVE_WARN);
1480 ae_perm |= acl_inherit_map[i].archive_inherit;
1483 #endif /* HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL */
1485 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
1486 archive_set_error(&a->archive, errno,
1487 "Failed to get ACL permission set");
1488 return (ARCHIVE_WARN);
1490 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
1492 * acl_get_perm() is spelled differently on different
1493 * platforms; see above.
1495 r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
1497 archive_set_error(&a->archive, errno,
1498 "Failed to check permission in an ACL permission set");
1499 return (ARCHIVE_WARN);
1501 ae_perm |= acl_perm_map[i].archive_perm;
1504 #if HAVE_DARWIN_ACL && !HAVE_DECL_ACL_SYNCHRONIZE
1505 /* On Mac OS X without ACL_SYNCHRONIZE assume it is set */
1506 ae_perm |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
1509 archive_entry_acl_add_entry(entry, entry_acl_type,
1513 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1514 #if !HAVE_DARWIN_ACL
1516 archive_set_error(&a->archive, errno,
1517 "Failed to get next ACL entry");
1518 return (ARCHIVE_WARN);
1522 return (ARCHIVE_OK);
1524 #endif /* !HAVE_SUN_ACL */
1525 #else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1527 setup_acls(struct archive_read_disk *a,
1528 struct archive_entry *entry, int *fd)
1530 (void)a; /* UNUSED */
1531 (void)entry; /* UNUSED */
1532 (void)fd; /* UNUSED */
1533 return (ARCHIVE_OK);
1535 #endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1537 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
1538 HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
1539 (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
1542 * Linux and AIX extended attribute support.
1544 * TODO: By using a stack-allocated buffer for the first
1545 * call to getxattr(), we might be able to avoid the second
1546 * call entirely. We only need the second call if the
1547 * stack-allocated buffer is too small. But a modest buffer
1548 * of 1024 bytes or so will often be big enough. Same applies
1554 setup_xattr(struct archive_read_disk *a,
1555 struct archive_entry *entry, const char *name, int fd, const char *accpath)
1562 size = fgetxattr(fd, name, NULL, 0);
1563 else if (!a->follow_symlinks)
1564 size = lgetxattr(accpath, name, NULL, 0);
1566 size = getxattr(accpath, name, NULL, 0);
1569 size = fgetea(fd, name, NULL, 0);
1570 else if (!a->follow_symlinks)
1571 size = lgetea(accpath, name, NULL, 0);
1573 size = getea(accpath, name, NULL, 0);
1577 archive_set_error(&a->archive, errno,
1578 "Couldn't query extended attribute");
1579 return (ARCHIVE_WARN);
1582 if (size > 0 && (value = malloc(size)) == NULL) {
1583 archive_set_error(&a->archive, errno, "Out of memory");
1584 return (ARCHIVE_FATAL);
1589 size = fgetxattr(fd, name, value, size);
1590 else if (!a->follow_symlinks)
1591 size = lgetxattr(accpath, name, value, size);
1593 size = getxattr(accpath, name, value, size);
1596 size = fgetea(fd, name, value, size);
1597 else if (!a->follow_symlinks)
1598 size = lgetea(accpath, name, value, size);
1600 size = getea(accpath, name, value, size);
1604 archive_set_error(&a->archive, errno,
1605 "Couldn't read extended attribute");
1606 return (ARCHIVE_WARN);
1609 archive_entry_xattr_add_entry(entry, name, value, size);
1612 return (ARCHIVE_OK);
1616 setup_xattrs(struct archive_read_disk *a,
1617 struct archive_entry *entry, int *fd)
1626 path = archive_entry_sourcepath(entry);
1627 if (path == NULL || (a->tree != NULL &&
1628 a->tree_enter_working_dir(a->tree) != 0))
1629 path = archive_entry_pathname(entry);
1631 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1632 "Couldn't determine file path to read "
1633 "extended attributes");
1634 return (ARCHIVE_WARN);
1636 if (a->tree != NULL && (a->follow_symlinks ||
1637 archive_entry_filetype(entry) != AE_IFLNK)) {
1638 *fd = a->open_on_current_dir(a->tree,
1639 path, O_RDONLY | O_NONBLOCK);
1645 list_size = flistxattr(*fd, NULL, 0);
1646 else if (!a->follow_symlinks)
1647 list_size = llistxattr(path, NULL, 0);
1649 list_size = listxattr(path, NULL, 0);
1652 list_size = flistea(*fd, NULL, 0);
1653 else if (!a->follow_symlinks)
1654 list_size = llistea(path, NULL, 0);
1656 list_size = listea(path, NULL, 0);
1659 if (list_size == -1) {
1660 if (errno == ENOTSUP || errno == ENOSYS)
1661 return (ARCHIVE_OK);
1662 archive_set_error(&a->archive, errno,
1663 "Couldn't list extended attributes");
1664 return (ARCHIVE_WARN);
1668 return (ARCHIVE_OK);
1670 if ((list = malloc(list_size)) == NULL) {
1671 archive_set_error(&a->archive, errno, "Out of memory");
1672 return (ARCHIVE_FATAL);
1677 list_size = flistxattr(*fd, list, list_size);
1678 else if (!a->follow_symlinks)
1679 list_size = llistxattr(path, list, list_size);
1681 list_size = listxattr(path, list, list_size);
1684 list_size = flistea(*fd, list, list_size);
1685 else if (!a->follow_symlinks)
1686 list_size = llistea(path, list, list_size);
1688 list_size = listea(path, list, list_size);
1691 if (list_size == -1) {
1692 archive_set_error(&a->archive, errno,
1693 "Couldn't retrieve extended attributes");
1695 return (ARCHIVE_WARN);
1698 for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
1699 if (strncmp(p, "system.", 7) == 0 ||
1700 strncmp(p, "xfsroot.", 8) == 0)
1702 setup_xattr(a, entry, p, *fd, path);
1706 return (ARCHIVE_OK);
1709 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
1710 HAVE_DECL_EXTATTR_NAMESPACE_USER
1713 * FreeBSD extattr interface.
1716 /* TODO: Implement this. Follow the Linux model above, but
1717 * with FreeBSD-specific system calls, of course. Be careful
1718 * to not include the system extattrs that hold ACLs; we handle
1722 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1723 int namespace, const char *name, const char *fullname, int fd,
1727 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1728 int namespace, const char *name, const char *fullname, int fd,
1729 const char *accpath)
1735 size = extattr_get_fd(fd, namespace, name, NULL, 0);
1736 else if (!a->follow_symlinks)
1737 size = extattr_get_link(accpath, namespace, name, NULL, 0);
1739 size = extattr_get_file(accpath, namespace, name, NULL, 0);
1742 archive_set_error(&a->archive, errno,
1743 "Couldn't query extended attribute");
1744 return (ARCHIVE_WARN);
1747 if (size > 0 && (value = malloc(size)) == NULL) {
1748 archive_set_error(&a->archive, errno, "Out of memory");
1749 return (ARCHIVE_FATAL);
1753 size = extattr_get_fd(fd, namespace, name, value, size);
1754 else if (!a->follow_symlinks)
1755 size = extattr_get_link(accpath, namespace, name, value, size);
1757 size = extattr_get_file(accpath, namespace, name, value, size);
1761 archive_set_error(&a->archive, errno,
1762 "Couldn't read extended attribute");
1763 return (ARCHIVE_WARN);
1766 archive_entry_xattr_add_entry(entry, fullname, value, size);
1769 return (ARCHIVE_OK);
1773 setup_xattrs(struct archive_read_disk *a,
1774 struct archive_entry *entry, int *fd)
1780 int namespace = EXTATTR_NAMESPACE_USER;
1785 path = archive_entry_sourcepath(entry);
1786 if (path == NULL || (a->tree != NULL &&
1787 a->tree_enter_working_dir(a->tree) != 0))
1788 path = archive_entry_pathname(entry);
1790 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1791 "Couldn't determine file path to read "
1792 "extended attributes");
1793 return (ARCHIVE_WARN);
1795 if (a->tree != NULL && (a->follow_symlinks ||
1796 archive_entry_filetype(entry) != AE_IFLNK)) {
1797 *fd = a->open_on_current_dir(a->tree,
1798 path, O_RDONLY | O_NONBLOCK);
1803 list_size = extattr_list_fd(*fd, namespace, NULL, 0);
1804 else if (!a->follow_symlinks)
1805 list_size = extattr_list_link(path, namespace, NULL, 0);
1807 list_size = extattr_list_file(path, namespace, NULL, 0);
1809 if (list_size == -1 && errno == EOPNOTSUPP)
1810 return (ARCHIVE_OK);
1811 if (list_size == -1) {
1812 archive_set_error(&a->archive, errno,
1813 "Couldn't list extended attributes");
1814 return (ARCHIVE_WARN);
1818 return (ARCHIVE_OK);
1820 if ((list = malloc(list_size)) == NULL) {
1821 archive_set_error(&a->archive, errno, "Out of memory");
1822 return (ARCHIVE_FATAL);
1826 list_size = extattr_list_fd(*fd, namespace, list, list_size);
1827 else if (!a->follow_symlinks)
1828 list_size = extattr_list_link(path, namespace, list, list_size);
1830 list_size = extattr_list_file(path, namespace, list, list_size);
1832 if (list_size == -1) {
1833 archive_set_error(&a->archive, errno,
1834 "Couldn't retrieve extended attributes");
1836 return (ARCHIVE_WARN);
1840 while ((p - list) < list_size) {
1841 size_t len = 255 & (int)*p;
1844 strcpy(buff, "user.");
1845 name = buff + strlen(buff);
1846 memcpy(name, p + 1, len);
1848 setup_xattr(a, entry, namespace, name, buff, *fd, path);
1853 return (ARCHIVE_OK);
1859 * Generic (stub) extended attribute support.
1862 setup_xattrs(struct archive_read_disk *a,
1863 struct archive_entry *entry, int *fd)
1865 (void)a; /* UNUSED */
1866 (void)entry; /* UNUSED */
1867 (void)fd; /* UNUSED */
1868 return (ARCHIVE_OK);
1873 #if defined(HAVE_LINUX_FIEMAP_H)
1876 * Linux FIEMAP sparse interface.
1878 * The FIEMAP ioctl returns an "extent" for each physical allocation
1879 * on disk. We need to process those to generate a more compact list
1880 * of logical file blocks. We also need to be very careful to use
1881 * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
1882 * does not report allocations for newly-written data that hasn't
1883 * been synced to disk.
1885 * It's important to return a minimal sparse file list because we want
1886 * to not trigger sparse file extensions if we don't have to, since
1887 * not all readers support them.
1891 setup_sparse_fiemap(struct archive_read_disk *a,
1892 struct archive_entry *entry, int *fd)
1896 struct fiemap_extent *fe;
1898 int count, do_fiemap, iters;
1899 int exit_sts = ARCHIVE_OK;
1901 if (archive_entry_filetype(entry) != AE_IFREG
1902 || archive_entry_size(entry) <= 0
1903 || archive_entry_hardlink(entry) != NULL)
1904 return (ARCHIVE_OK);
1909 path = archive_entry_sourcepath(entry);
1911 path = archive_entry_pathname(entry);
1912 if (a->tree != NULL)
1913 *fd = a->open_on_current_dir(a->tree, path,
1914 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1916 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1918 archive_set_error(&a->archive, errno,
1919 "Can't open `%s'", path);
1920 return (ARCHIVE_FAILED);
1922 __archive_ensure_cloexec_flag(*fd);
1925 /* Initialize buffer to avoid the error valgrind complains about. */
1926 memset(buff, 0, sizeof(buff));
1927 count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
1928 fm = (struct fiemap *)buff;
1930 fm->fm_length = ~0ULL;;
1931 fm->fm_flags = FIEMAP_FLAG_SYNC;
1932 fm->fm_extent_count = count;
1934 size = archive_entry_size(entry);
1935 for (iters = 0; ; ++iters) {
1938 r = ioctl(*fd, FS_IOC_FIEMAP, fm);
1940 /* When something error happens, it is better we
1941 * should return ARCHIVE_OK because an earlier
1942 * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
1943 goto exit_setup_sparse_fiemap;
1945 if (fm->fm_mapped_extents == 0) {
1947 /* Fully sparse file; insert a zero-length "data" entry */
1948 archive_entry_sparse_add_entry(entry, 0, 0);
1952 fe = fm->fm_extents;
1953 for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
1954 if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
1955 /* The fe_length of the last block does not
1956 * adjust itself to its size files. */
1957 int64_t length = fe->fe_length;
1958 if (fe->fe_logical + length > (uint64_t)size)
1959 length -= fe->fe_logical + length - size;
1960 if (fe->fe_logical == 0 && length == size) {
1961 /* This is not sparse. */
1966 archive_entry_sparse_add_entry(entry,
1967 fe->fe_logical, length);
1969 if (fe->fe_flags & FIEMAP_EXTENT_LAST)
1973 fe = fm->fm_extents + fm->fm_mapped_extents -1;
1974 fm->fm_start = fe->fe_logical + fe->fe_length;
1978 exit_setup_sparse_fiemap:
1982 #if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1984 setup_sparse(struct archive_read_disk *a,
1985 struct archive_entry *entry, int *fd)
1987 return setup_sparse_fiemap(a, entry, fd);
1990 #endif /* defined(HAVE_LINUX_FIEMAP_H) */
1992 #if defined(SEEK_HOLE) && defined(SEEK_DATA)
1995 * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
1999 setup_sparse(struct archive_read_disk *a,
2000 struct archive_entry *entry, int *fd)
2005 int exit_sts = ARCHIVE_OK;
2006 int check_fully_sparse = 0;
2008 if (archive_entry_filetype(entry) != AE_IFREG
2009 || archive_entry_size(entry) <= 0
2010 || archive_entry_hardlink(entry) != NULL)
2011 return (ARCHIVE_OK);
2013 /* Does filesystem support the reporting of hole ? */
2014 if (*fd < 0 && a->tree != NULL) {
2017 path = archive_entry_sourcepath(entry);
2019 path = archive_entry_pathname(entry);
2020 *fd = a->open_on_current_dir(a->tree, path,
2021 O_RDONLY | O_NONBLOCK);
2023 archive_set_error(&a->archive, errno,
2024 "Can't open `%s'", path);
2025 return (ARCHIVE_FAILED);
2030 #ifdef _PC_MIN_HOLE_SIZE
2031 if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
2032 return (ARCHIVE_OK);
2034 initial_off = lseek(*fd, 0, SEEK_CUR);
2035 if (initial_off != 0)
2036 lseek(*fd, 0, SEEK_SET);
2040 path = archive_entry_sourcepath(entry);
2042 path = archive_entry_pathname(entry);
2044 #ifdef _PC_MIN_HOLE_SIZE
2045 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
2046 return (ARCHIVE_OK);
2048 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
2050 archive_set_error(&a->archive, errno,
2051 "Can't open `%s'", path);
2052 return (ARCHIVE_FAILED);
2054 __archive_ensure_cloexec_flag(*fd);
2058 #ifndef _PC_MIN_HOLE_SIZE
2059 /* Check if the underlying filesystem supports seek hole */
2060 off_s = lseek(*fd, 0, SEEK_HOLE);
2062 #if defined(HAVE_LINUX_FIEMAP_H)
2063 return setup_sparse_fiemap(a, entry, fd);
2065 goto exit_setup_sparse;
2068 lseek(*fd, 0, SEEK_SET);
2072 size = archive_entry_size(entry);
2073 while (off_s < size) {
2074 off_s = lseek(*fd, off_s, SEEK_DATA);
2075 if (off_s == (off_t)-1) {
2076 if (errno == ENXIO) {
2078 if (archive_entry_sparse_count(entry) == 0) {
2079 /* Potentially a fully-sparse file. */
2080 check_fully_sparse = 1;
2084 archive_set_error(&a->archive, errno,
2085 "lseek(SEEK_HOLE) failed");
2086 exit_sts = ARCHIVE_FAILED;
2087 goto exit_setup_sparse;
2089 off_e = lseek(*fd, off_s, SEEK_HOLE);
2090 if (off_e == (off_t)-1) {
2091 if (errno == ENXIO) {
2092 off_e = lseek(*fd, 0, SEEK_END);
2093 if (off_e != (off_t)-1)
2094 break;/* no more data */
2096 archive_set_error(&a->archive, errno,
2097 "lseek(SEEK_DATA) failed");
2098 exit_sts = ARCHIVE_FAILED;
2099 goto exit_setup_sparse;
2101 if (off_s == 0 && off_e == size)
2102 break;/* This is not sparse. */
2103 archive_entry_sparse_add_entry(entry, off_s,
2108 if (check_fully_sparse) {
2109 if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
2110 lseek(*fd, 0, SEEK_END) == size) {
2111 /* Fully sparse file; insert a zero-length "data" entry */
2112 archive_entry_sparse_add_entry(entry, 0, 0);
2116 lseek(*fd, initial_off, SEEK_SET);
2120 #elif !defined(HAVE_LINUX_FIEMAP_H)
2123 * Generic (stub) sparse support.
2126 setup_sparse(struct archive_read_disk *a,
2127 struct archive_entry *entry, int *fd)
2129 (void)a; /* UNUSED */
2130 (void)entry; /* UNUSED */
2131 (void)fd; /* UNUSED */
2132 return (ARCHIVE_OK);
2137 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */