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 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 (st->st_flags != 0)
207 archive_entry_set_fflags(entry, st->st_flags, 0);
210 #if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
211 /* Linux requires an extra ioctl to pull the flags. Although
212 * this is an extra step, it has a nice side-effect: We get an
213 * open file descriptor which we can use in the subsequent lookups. */
214 if ((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);
226 r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
227 if (r == 0 && stflags != 0)
228 archive_entry_set_fflags(entry, stflags, 0);
233 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
234 if (S_ISLNK(st->st_mode)) {
235 size_t linkbuffer_len = st->st_size + 1;
239 linkbuffer = malloc(linkbuffer_len);
240 if (linkbuffer == NULL) {
241 archive_set_error(&a->archive, ENOMEM,
242 "Couldn't read link data");
243 return (ARCHIVE_FAILED);
245 if (a->tree != NULL) {
246 #ifdef HAVE_READLINKAT
247 lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
248 path, linkbuffer, linkbuffer_len);
250 if (a->tree_enter_working_dir(a->tree) != 0) {
251 archive_set_error(&a->archive, errno,
252 "Couldn't read link data");
254 return (ARCHIVE_FAILED);
256 lnklen = readlink(path, linkbuffer, linkbuffer_len);
257 #endif /* HAVE_READLINKAT */
259 lnklen = readlink(path, linkbuffer, linkbuffer_len);
261 archive_set_error(&a->archive, errno,
262 "Couldn't read link data");
264 return (ARCHIVE_FAILED);
266 linkbuffer[lnklen] = 0;
267 archive_entry_set_symlink(entry, linkbuffer);
270 #endif /* HAVE_READLINK || HAVE_READLINKAT */
272 r = setup_acls(a, entry, &fd);
273 if (!a->suppress_xattr) {
274 r1 = setup_xattrs(a, entry, &fd);
278 if (a->enable_copyfile) {
279 r1 = setup_mac_metadata(a, entry, &fd);
283 r1 = setup_sparse(a, entry, &fd);
287 /* If we opened the file earlier in this function, close it. */
288 if (initial_fd != fd)
293 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
295 * The Mac OS "copyfile()" API copies the extended metadata for a
296 * file into a separate file in AppleDouble format (see RFC 1740).
298 * Mac OS tar and cpio implementations store this extended
299 * metadata as a separate entry just before the regular entry
300 * with a "._" prefix added to the filename.
302 * Note that this is currently done unconditionally; the tar program has
303 * an option to discard this information before the archive is written.
305 * TODO: If there's a failure, report it and return ARCHIVE_WARN.
308 setup_mac_metadata(struct archive_read_disk *a,
309 struct archive_entry *entry, int *fd)
312 int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
313 struct stat copyfile_stat;
314 int ret = ARCHIVE_OK;
317 const char *name, *tempdir;
318 struct archive_string tempfile;
320 (void)fd; /* UNUSED */
321 name = archive_entry_sourcepath(entry);
323 name = archive_entry_pathname(entry);
325 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
326 "Can't open file to read extended attributes: No name");
327 return (ARCHIVE_WARN);
330 if (a->tree != NULL) {
331 if (a->tree_enter_working_dir(a->tree) != 0) {
332 archive_set_error(&a->archive, errno,
333 "Couldn't change dir");
334 return (ARCHIVE_FAILED);
338 /* Short-circuit if there's nothing to do. */
339 have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
340 if (have_attrs == -1) {
341 archive_set_error(&a->archive, errno,
342 "Could not check extended attributes");
343 return (ARCHIVE_WARN);
349 if (issetugid() == 0)
350 tempdir = getenv("TMPDIR");
353 archive_string_init(&tempfile);
354 archive_strcpy(&tempfile, tempdir);
355 archive_strcat(&tempfile, "tar.md.XXXXXX");
356 tempfd = mkstemp(tempfile.s);
358 archive_set_error(&a->archive, errno,
359 "Could not open extended attribute file");
363 __archive_ensure_cloexec_flag(tempfd);
365 /* XXX I wish copyfile() could pack directly to a memory
366 * buffer; that would avoid the temp file here. For that
367 * matter, it would be nice if fcopyfile() actually worked,
368 * that would reduce the many open/close races here. */
369 if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
370 archive_set_error(&a->archive, errno,
371 "Could not pack extended attributes");
375 if (fstat(tempfd, ©file_stat)) {
376 archive_set_error(&a->archive, errno,
377 "Could not check size of extended attributes");
381 buff = malloc(copyfile_stat.st_size);
383 archive_set_error(&a->archive, errno,
384 "Could not allocate memory for extended attributes");
388 if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
389 archive_set_error(&a->archive, errno,
390 "Could not read extended attributes into memory");
394 archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
401 archive_string_free(&tempfile);
409 * Stub implementation for non-Mac systems.
412 setup_mac_metadata(struct archive_read_disk *a,
413 struct archive_entry *entry, int *fd)
415 (void)a; /* UNUSED */
416 (void)entry; /* UNUSED */
417 (void)fd; /* UNUSED */
423 static int translate_guid(struct archive *, acl_entry_t,
424 int *, int *, const char **);
426 static void add_trivial_nfs4_acl(struct archive_entry *);
431 sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
434 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
435 static int translate_acl(struct archive_read_disk *a,
436 struct archive_entry *entry,
442 int archive_entry_acl_type);
445 setup_acls(struct archive_read_disk *a,
446 struct archive_entry *entry, int *fd)
456 accpath = archive_entry_sourcepath(entry);
458 accpath = archive_entry_pathname(entry);
460 if (*fd < 0 && a->tree != NULL) {
461 if (a->follow_symlinks ||
462 archive_entry_filetype(entry) != AE_IFLNK)
463 *fd = a->open_on_current_dir(a->tree,
464 accpath, O_RDONLY | O_NONBLOCK);
466 if (a->tree_enter_working_dir(a->tree) != 0) {
467 archive_set_error(&a->archive, errno,
468 "Couldn't access %s", accpath);
469 return (ARCHIVE_FAILED);
474 archive_entry_acl_clear(entry);
479 /* Try NFSv4 ACL first. */
482 /* Solaris reads both POSIX.1e and NFSv4 ACL here */
483 facl_get(*fd, 0, &acl);
484 #elif HAVE_ACL_GET_FD_NP
485 acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
487 acl = acl_get_fd(*fd);
489 #if HAVE_ACL_GET_LINK_NP
490 else if (!a->follow_symlinks)
491 acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
493 else if ((!a->follow_symlinks)
494 && (archive_entry_filetype(entry) == AE_IFLNK))
495 /* We can't get the ACL of a symlink, so we assume it can't
501 /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
502 acl_get(accpath, 0, &acl);
504 acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
508 #if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL
509 /* Ignore "trivial" ACLs that just mirror the file mode. */
512 if (sun_acl_is_trivial(acl, archive_entry_mode(entry),
514 #elif HAVE_ACL_IS_TRIVIAL_NP
515 if (acl_is_trivial_np(acl, &r) == 0 && r == 1)
521 * Simultaneous NFSv4 and POSIX.1e ACLs for the same
522 * entry are not allowed, so we should return here
527 #endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */
529 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
531 if (r != ARCHIVE_OK) {
532 archive_set_error(&a->archive, errno,
534 "Couldn't translate ACLs: %s", accpath);
536 "Couldn't translate NFSv4 ACLs: %s", accpath);
541 * Because Mac OS doesn't support owner@, group@ and everyone@
542 * ACLs we need to add NFSv4 ACLs mirroring the file mode to
543 * the archive entry. Otherwise extraction on non-Mac platforms
544 * would lead to an invalid file mode.
546 if (archive_entry_acl_count(entry,
547 ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0)
548 add_trivial_nfs4_acl(entry);
552 #endif /* HAVE_NFS4_ACL */
555 /* This code path is skipped on MacOS and Solaris */
557 /* Retrieve access ACL from file. */
559 acl = acl_get_fd(*fd);
560 #if HAVE_ACL_GET_LINK_NP
561 else if (!a->follow_symlinks)
562 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
564 else if ((!a->follow_symlinks)
565 && (archive_entry_filetype(entry) == AE_IFLNK))
566 /* We can't get the ACL of a symlink, so we assume it can't
571 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
573 #if HAVE_ACL_IS_TRIVIAL_NP
574 /* Ignore "trivial" ACLs that just mirror the file mode. */
575 if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
584 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
587 if (r != ARCHIVE_OK) {
588 archive_set_error(&a->archive, errno,
589 "Couldn't translate access ACLs: %s", accpath);
594 /* Only directories can have default ACLs. */
595 if (S_ISDIR(archive_entry_mode(entry))) {
596 #if HAVE_ACL_GET_FD_NP
598 acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
601 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
603 r = translate_acl(a, entry, acl,
604 ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
606 if (r != ARCHIVE_OK) {
607 archive_set_error(&a->archive, errno,
608 "Couldn't translate default ACLs: %s",
614 #endif /* HAVE_POSIX_ACL */
619 * Translate system ACL permissions into libarchive internal structure
621 static const struct {
622 const int archive_perm;
623 const int platform_perm;
625 #if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */
626 {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
627 {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
628 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
629 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
630 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
631 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
632 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
633 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
634 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
635 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
636 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
637 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
638 {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
639 {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
640 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
641 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
642 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
643 #elif HAVE_DARWIN_ACL /* MacOS ACL permissions */
644 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
645 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
646 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
647 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
648 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
649 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
650 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
651 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
652 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
653 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
654 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
655 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
656 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
657 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
658 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
659 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
660 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
661 #else /* POSIX.1e ACL permissions */
662 {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
663 {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
664 {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
665 #if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */
666 {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
667 {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
668 {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
669 {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
670 {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
671 {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
672 {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
673 {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
674 {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
675 {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
676 {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
677 {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
678 {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
679 {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
680 {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
681 {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
683 #endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
688 * Translate system NFSv4 inheritance flags into libarchive internal structure
690 static const struct {
691 const int archive_inherit;
692 const int platform_inherit;
693 } acl_inherit_map[] = {
694 #if HAVE_SUN_ACL /* Solaris ACL inheritance flags */
695 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
696 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
697 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
698 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
699 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
700 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
701 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
702 #elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */
703 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
704 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
705 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
706 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
707 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
708 #else /* FreeBSD NFSv4 ACL inheritance flags */
709 {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
710 {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
711 {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
712 {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
713 {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
714 {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
715 {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
716 #endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
718 #endif /* HAVE_NFS4_ACL */
721 static int translate_guid(struct archive *a, acl_entry_t acl_entry,
722 int *ae_id, int *ae_tag, const char **ae_name)
730 q = acl_get_qualifier(acl_entry);
733 r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
738 if (idtype == ID_TYPE_UID) {
739 *ae_tag = ARCHIVE_ENTRY_ACL_USER;
745 *ae_id = pwd->pw_uid;
746 *ae_name = archive_read_disk_uname(a, *ae_id);
748 } else if (idtype == ID_TYPE_GID) {
749 *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
755 *ae_id = grp->gr_gid;
756 *ae_name = archive_read_disk_gname(a, *ae_id);
766 * Add trivial NFSv4 ACL entries from mode
769 add_trivial_nfs4_acl(struct archive_entry *entry)
773 const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
774 const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
775 ARCHIVE_ENTRY_ACL_APPEND_DATA;
776 const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
777 const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
778 ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
779 ARCHIVE_ENTRY_ACL_READ_ACL |
780 ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
781 const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
782 ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
783 ARCHIVE_ENTRY_ACL_WRITE_ACL |
784 ARCHIVE_ENTRY_ACL_WRITE_OWNER;
791 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
792 {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
793 {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
794 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
795 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
796 {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
799 mode = archive_entry_mode(entry);
801 /* Permissions for everyone@ */
803 tacl_entry[5].permset |= rperm;
805 tacl_entry[5].permset |= wperm;
807 tacl_entry[5].permset |= eperm;
809 /* Permissions for group@ */
811 tacl_entry[4].permset |= rperm;
812 else if (mode & 0004)
813 tacl_entry[2].permset |= rperm;
815 tacl_entry[4].permset |= wperm;
816 else if (mode & 0002)
817 tacl_entry[2].permset |= wperm;
819 tacl_entry[4].permset |= eperm;
820 else if (mode & 0001)
821 tacl_entry[2].permset |= eperm;
823 /* Permissions for owner@ */
825 tacl_entry[3].permset |= rperm;
826 if (!(mode & 0040) && (mode & 0004))
827 tacl_entry[0].permset |= rperm;
828 } else if ((mode & 0040) || (mode & 0004))
829 tacl_entry[1].permset |= rperm;
831 tacl_entry[3].permset |= wperm;
832 if (!(mode & 0020) && (mode & 0002))
833 tacl_entry[0].permset |= wperm;
834 } else if ((mode & 0020) || (mode & 0002))
835 tacl_entry[1].permset |= wperm;
837 tacl_entry[3].permset |= eperm;
838 if (!(mode & 0010) && (mode & 0001))
839 tacl_entry[0].permset |= eperm;
840 } else if ((mode & 0010) || (mode & 0001))
841 tacl_entry[1].permset |= eperm;
843 for (i = 0; i < 6; i++) {
844 if (tacl_entry[i].permset != 0) {
845 archive_entry_acl_add_entry(entry,
846 tacl_entry[i].type, tacl_entry[i].permset,
847 tacl_entry[i].tag, -1, NULL);
855 * Check if acl is trivial
856 * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
859 sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
862 const uint32_t rperm = ACE_READ_DATA;
863 const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
864 const uint32_t eperm = ACE_EXECUTE;
865 const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
866 ACE_READ_ACL | ACE_SYNCHRONIZE;
867 const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
868 ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
873 if (acl == NULL || trivialp == NULL)
878 /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */
879 if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0)
883 * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
884 * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
887 if (acl->acl_type == ACLENT_T) {
888 if (acl->acl_cnt == 4)
893 if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
897 * Continue with checking NFSv4 ACLs
899 * Create list of trivial ace's to be compared
902 /* owner@ allow pre */
903 tace[0].a_flags = ACE_OWNER;
904 tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
905 tace[0].a_access_mask = 0;
908 tace[1].a_flags = ACE_OWNER;
909 tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
910 tace[1].a_access_mask = 0;
913 tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
914 tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
915 tace[2].a_access_mask = 0;
918 tace[3].a_flags = ACE_OWNER;
919 tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
920 tace[3].a_access_mask = ownset;
923 tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
924 tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
925 tace[4].a_access_mask = pubset;
927 /* everyone@ allow */
928 tace[5].a_flags = ACE_EVERYONE;
929 tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
930 tace[5].a_access_mask = pubset;
932 /* Permissions for everyone@ */
934 tace[5].a_access_mask |= rperm;
936 tace[5].a_access_mask |= wperm;
938 tace[5].a_access_mask |= eperm;
940 /* Permissions for group@ */
942 tace[4].a_access_mask |= rperm;
943 else if (mode & 0004)
944 tace[2].a_access_mask |= rperm;
946 tace[4].a_access_mask |= wperm;
947 else if (mode & 0002)
948 tace[2].a_access_mask |= wperm;
950 tace[4].a_access_mask |= eperm;
951 else if (mode & 0001)
952 tace[2].a_access_mask |= eperm;
954 /* Permissions for owner@ */
956 tace[3].a_access_mask |= rperm;
957 if (!(mode & 0040) && (mode & 0004))
958 tace[0].a_access_mask |= rperm;
959 } else if ((mode & 0040) || (mode & 0004))
960 tace[1].a_access_mask |= rperm;
962 tace[3].a_access_mask |= wperm;
963 if (!(mode & 0020) && (mode & 0002))
964 tace[0].a_access_mask |= wperm;
965 } else if ((mode & 0020) || (mode & 0002))
966 tace[1].a_access_mask |= wperm;
968 tace[3].a_access_mask |= eperm;
969 if (!(mode & 0010) && (mode & 0001))
970 tace[0].a_access_mask |= eperm;
971 } else if ((mode & 0010) || (mode & 0001))
972 tace[1].a_access_mask |= eperm;
974 /* Check if the acl count matches */
976 for (i = 0; i < 3; i++) {
977 if (tace[i].a_access_mask != 0)
980 if (acl->acl_cnt != p)
984 for (i = 0; i < 6; i++) {
985 if (tace[i].a_access_mask != 0) {
986 ace = &((ace_t *)acl->acl_aclp)[p];
988 * Illumos added ACE_DELETE_CHILD to write perms for
989 * directories. We have to check against that, too.
991 if (ace->a_flags != tace[i].a_flags ||
992 ace->a_type != tace[i].a_type ||
993 (ace->a_access_mask != tace[i].a_access_mask &&
994 ((acl->acl_flags & ACL_IS_DIR) == 0 ||
995 (tace[i].a_access_mask & wperm) == 0 ||
996 ace->a_access_mask !=
997 (tace[i].a_access_mask | ACE_DELETE_CHILD))))
1006 #endif /* HAVE_SUN_ACL */
1010 * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
1013 translate_acl(struct archive_read_disk *a,
1014 struct archive_entry *entry, acl_t *acl, int default_entry_acl_type)
1017 int ae_id, ae_tag, ae_perm;
1019 const char *ae_name;
1023 (void)default_entry_acl_type;
1025 if (acl->acl_cnt <= 0)
1026 return (ARCHIVE_OK);
1028 for (e = 0; e < acl->acl_cnt; e++) {
1033 if (acl->acl_type == ACE_T) {
1034 ace = &((ace_t *)acl->acl_aclp)[e];
1037 switch(ace->a_type) {
1038 case ACE_ACCESS_ALLOWED_ACE_TYPE:
1039 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1041 case ACE_ACCESS_DENIED_ACE_TYPE:
1042 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1044 case ACE_SYSTEM_AUDIT_ACE_TYPE:
1045 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1047 case ACE_SYSTEM_ALARM_ACE_TYPE:
1048 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1051 /* Unknown entry type, skip */
1055 if ((ace->a_flags & ACE_OWNER) != 0)
1056 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1057 else if ((ace->a_flags & ACE_GROUP) != 0)
1058 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1059 else if ((ace->a_flags & ACE_EVERYONE) != 0)
1060 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1061 else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
1062 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1063 ae_name = archive_read_disk_gname(&a->archive,
1066 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1067 ae_name = archive_read_disk_uname(&a->archive,
1071 for (i = 0; i < (int)(sizeof(acl_inherit_map) /
1072 sizeof(acl_inherit_map[0])); ++i) {
1074 acl_inherit_map[i].platform_inherit) != 0)
1076 acl_inherit_map[i].archive_inherit;
1079 for (i = 0; i < (int)(sizeof(acl_perm_map) /
1080 sizeof(acl_perm_map[0])); ++i) {
1081 if ((ace->a_access_mask &
1082 acl_perm_map[i].platform_perm) != 0)
1084 acl_perm_map[i].archive_perm;
1087 aclent = &((aclent_t *)acl->acl_aclp)[e];
1088 if ((aclent->a_type & ACL_DEFAULT) != 0)
1089 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
1091 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1092 ae_id = aclent->a_id;
1094 switch(aclent->a_type) {
1097 ae_name = archive_read_disk_uname(&a->archive,
1099 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1103 ae_name = archive_read_disk_gname(&a->archive,
1105 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1109 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1113 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1117 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1121 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1124 /* Unknown tag type, skip */
1128 if ((aclent->a_perm & 1) != 0)
1129 ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
1130 if ((aclent->a_perm & 2) != 0)
1131 ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
1132 if ((aclent->a_perm & 4) != 0)
1133 ae_perm |= ARCHIVE_ENTRY_ACL_READ;
1134 } /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */
1136 archive_entry_acl_add_entry(entry, entry_acl_type,
1137 ae_perm, ae_tag, ae_id, ae_name);
1139 return (ARCHIVE_OK);
1141 #else /* !HAVE_SUN_ACL */
1143 * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
1144 * MacOS (NFSv4 only) ACLs into libarchive internal structure
1147 translate_acl(struct archive_read_disk *a,
1148 struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
1151 #if HAVE_ACL_TYPE_NFS4
1152 acl_entry_type_t acl_type;
1155 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
1156 acl_flagset_t acl_flagset;
1158 acl_entry_t acl_entry;
1159 acl_permset_t acl_permset;
1160 int i, entry_acl_type;
1161 int r, s, ae_id, ae_tag, ae_perm;
1162 #if !HAVE_DARWIN_ACL
1165 const char *ae_name;
1167 #if HAVE_ACL_TYPE_NFS4
1168 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
1169 // Make sure the "brand" on this ACL is consistent
1170 // with the default_entry_acl_type bits provided.
1171 if (acl_get_brand_np(acl, &brand) != 0) {
1172 archive_set_error(&a->archive, errno,
1173 "Failed to read ACL brand");
1174 return (ARCHIVE_WARN);
1177 case ACL_BRAND_POSIX:
1178 switch (default_entry_acl_type) {
1179 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
1180 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
1183 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1184 "Invalid ACL entry type for POSIX.1e ACL");
1185 return (ARCHIVE_WARN);
1188 case ACL_BRAND_NFS4:
1189 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1190 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1191 "Invalid ACL entry type for NFSv4 ACL");
1192 return (ARCHIVE_WARN);
1196 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1197 "Unknown ACL brand");
1198 return (ARCHIVE_WARN);
1202 s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
1204 archive_set_error(&a->archive, errno,
1205 "Failed to get first ACL entry");
1206 return (ARCHIVE_WARN);
1211 #else /* FreeBSD, Linux */
1219 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
1220 archive_set_error(&a->archive, errno,
1221 "Failed to get ACL tag type");
1222 return (ARCHIVE_WARN);
1225 #if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
1227 q = acl_get_qualifier(acl_entry);
1229 ae_id = (int)*(uid_t *)q;
1231 ae_name = archive_read_disk_uname(&a->archive,
1234 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1237 q = acl_get_qualifier(acl_entry);
1239 ae_id = (int)*(gid_t *)q;
1241 ae_name = archive_read_disk_gname(&a->archive,
1244 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1247 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1250 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1253 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1256 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1258 #if HAVE_ACL_TYPE_NFS4
1260 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1263 #else /* HAVE_DARWIN_ACL */
1264 case ACL_EXTENDED_ALLOW:
1265 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1266 r = translate_guid(&a->archive, acl_entry, &ae_id,
1269 case ACL_EXTENDED_DENY:
1270 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1271 r = translate_guid(&a->archive, acl_entry, &ae_id,
1274 #endif /* HAVE_DARWIN_ACL */
1276 /* Skip types that libarchive can't support. */
1277 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1282 /* Skip if translate_guid() above failed */
1284 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1289 #if !HAVE_DARWIN_ACL
1290 // XXX acl_type maps to allow/deny/audit/YYYY bits
1291 entry_acl_type = default_entry_acl_type;
1293 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
1294 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1295 #if HAVE_ACL_TYPE_NFS4
1297 * acl_get_entry_type_np() fails with non-NFSv4 ACLs
1299 if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
1300 archive_set_error(&a->archive, errno, "Failed "
1301 "to get ACL type from a NFSv4 ACL entry");
1302 return (ARCHIVE_WARN);
1305 case ACL_ENTRY_TYPE_ALLOW:
1306 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1308 case ACL_ENTRY_TYPE_DENY:
1309 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1311 case ACL_ENTRY_TYPE_AUDIT:
1312 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
1314 case ACL_ENTRY_TYPE_ALARM:
1315 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1318 archive_set_error(&a->archive, errno,
1319 "Invalid NFSv4 ACL entry type");
1320 return (ARCHIVE_WARN);
1322 #endif /* HAVE_ACL_TYPE_NFS4 */
1325 * Libarchive stores "flag" (NFSv4 inheritance bits)
1326 * in the ae_perm bitmap.
1328 * acl_get_flagset_np() fails with non-NFSv4 ACLs
1330 if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
1331 archive_set_error(&a->archive, errno,
1332 "Failed to get flagset from a NFSv4 ACL entry");
1333 return (ARCHIVE_WARN);
1335 for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
1336 r = acl_get_flag_np(acl_flagset,
1337 acl_inherit_map[i].platform_inherit);
1339 archive_set_error(&a->archive, errno,
1340 "Failed to check flag in a NFSv4 "
1342 return (ARCHIVE_WARN);
1344 ae_perm |= acl_inherit_map[i].archive_inherit;
1347 #endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
1349 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
1350 archive_set_error(&a->archive, errno,
1351 "Failed to get ACL permission set");
1352 return (ARCHIVE_WARN);
1354 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
1356 * acl_get_perm() is spelled differently on different
1357 * platforms; see above.
1359 r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
1361 archive_set_error(&a->archive, errno,
1362 "Failed to check permission in an ACL permission set");
1363 return (ARCHIVE_WARN);
1365 ae_perm |= acl_perm_map[i].archive_perm;
1368 archive_entry_acl_add_entry(entry, entry_acl_type,
1372 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1373 #if !HAVE_DARWIN_ACL
1375 archive_set_error(&a->archive, errno,
1376 "Failed to get next ACL entry");
1377 return (ARCHIVE_WARN);
1381 return (ARCHIVE_OK);
1383 #endif /* !HAVE_SUN_ACL */
1384 #else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1386 setup_acls(struct archive_read_disk *a,
1387 struct archive_entry *entry, int *fd)
1389 (void)a; /* UNUSED */
1390 (void)entry; /* UNUSED */
1391 (void)fd; /* UNUSED */
1392 return (ARCHIVE_OK);
1394 #endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1396 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
1397 HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
1398 (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
1401 * Linux and AIX extended attribute support.
1403 * TODO: By using a stack-allocated buffer for the first
1404 * call to getxattr(), we might be able to avoid the second
1405 * call entirely. We only need the second call if the
1406 * stack-allocated buffer is too small. But a modest buffer
1407 * of 1024 bytes or so will often be big enough. Same applies
1413 setup_xattr(struct archive_read_disk *a,
1414 struct archive_entry *entry, const char *name, int fd)
1418 const char *accpath;
1420 accpath = archive_entry_sourcepath(entry);
1421 if (accpath == NULL)
1422 accpath = archive_entry_pathname(entry);
1426 size = fgetxattr(fd, name, NULL, 0);
1427 else if (!a->follow_symlinks)
1428 size = lgetxattr(accpath, name, NULL, 0);
1430 size = getxattr(accpath, name, NULL, 0);
1433 size = fgetea(fd, name, NULL, 0);
1434 else if (!a->follow_symlinks)
1435 size = lgetea(accpath, name, NULL, 0);
1437 size = getea(accpath, name, NULL, 0);
1441 archive_set_error(&a->archive, errno,
1442 "Couldn't query extended attribute");
1443 return (ARCHIVE_WARN);
1446 if (size > 0 && (value = malloc(size)) == NULL) {
1447 archive_set_error(&a->archive, errno, "Out of memory");
1448 return (ARCHIVE_FATAL);
1453 size = fgetxattr(fd, name, value, size);
1454 else if (!a->follow_symlinks)
1455 size = lgetxattr(accpath, name, value, size);
1457 size = getxattr(accpath, name, value, size);
1460 size = fgetea(fd, name, value, size);
1461 else if (!a->follow_symlinks)
1462 size = lgetea(accpath, name, value, size);
1464 size = getea(accpath, name, value, size);
1468 archive_set_error(&a->archive, errno,
1469 "Couldn't read extended attribute");
1470 return (ARCHIVE_WARN);
1473 archive_entry_xattr_add_entry(entry, name, value, size);
1476 return (ARCHIVE_OK);
1480 setup_xattrs(struct archive_read_disk *a,
1481 struct archive_entry *entry, int *fd)
1487 path = archive_entry_sourcepath(entry);
1489 path = archive_entry_pathname(entry);
1491 if (*fd < 0 && a->tree != NULL) {
1492 if (a->follow_symlinks ||
1493 archive_entry_filetype(entry) != AE_IFLNK)
1494 *fd = a->open_on_current_dir(a->tree, path,
1495 O_RDONLY | O_NONBLOCK);
1497 if (a->tree_enter_working_dir(a->tree) != 0) {
1498 archive_set_error(&a->archive, errno,
1499 "Couldn't access %s", path);
1500 return (ARCHIVE_FAILED);
1507 list_size = flistxattr(*fd, NULL, 0);
1508 else if (!a->follow_symlinks)
1509 list_size = llistxattr(path, NULL, 0);
1511 list_size = listxattr(path, NULL, 0);
1514 list_size = flistea(*fd, NULL, 0);
1515 else if (!a->follow_symlinks)
1516 list_size = llistea(path, NULL, 0);
1518 list_size = listea(path, NULL, 0);
1521 if (list_size == -1) {
1522 if (errno == ENOTSUP || errno == ENOSYS)
1523 return (ARCHIVE_OK);
1524 archive_set_error(&a->archive, errno,
1525 "Couldn't list extended attributes");
1526 return (ARCHIVE_WARN);
1530 return (ARCHIVE_OK);
1532 if ((list = malloc(list_size)) == NULL) {
1533 archive_set_error(&a->archive, errno, "Out of memory");
1534 return (ARCHIVE_FATAL);
1539 list_size = flistxattr(*fd, list, list_size);
1540 else if (!a->follow_symlinks)
1541 list_size = llistxattr(path, list, list_size);
1543 list_size = listxattr(path, list, list_size);
1546 list_size = flistea(*fd, list, list_size);
1547 else if (!a->follow_symlinks)
1548 list_size = llistea(path, list, list_size);
1550 list_size = listea(path, list, list_size);
1553 if (list_size == -1) {
1554 archive_set_error(&a->archive, errno,
1555 "Couldn't retrieve extended attributes");
1557 return (ARCHIVE_WARN);
1560 for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
1561 if (strncmp(p, "system.", 7) == 0 ||
1562 strncmp(p, "xfsroot.", 8) == 0)
1564 setup_xattr(a, entry, p, *fd);
1568 return (ARCHIVE_OK);
1571 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
1572 HAVE_DECL_EXTATTR_NAMESPACE_USER
1575 * FreeBSD extattr interface.
1578 /* TODO: Implement this. Follow the Linux model above, but
1579 * with FreeBSD-specific system calls, of course. Be careful
1580 * to not include the system extattrs that hold ACLs; we handle
1584 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1585 int namespace, const char *name, const char *fullname, int fd);
1588 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1589 int namespace, const char *name, const char *fullname, int fd)
1593 const char *accpath;
1595 accpath = archive_entry_sourcepath(entry);
1596 if (accpath == NULL)
1597 accpath = archive_entry_pathname(entry);
1600 size = extattr_get_fd(fd, namespace, name, NULL, 0);
1601 else if (!a->follow_symlinks)
1602 size = extattr_get_link(accpath, namespace, name, NULL, 0);
1604 size = extattr_get_file(accpath, namespace, name, NULL, 0);
1607 archive_set_error(&a->archive, errno,
1608 "Couldn't query extended attribute");
1609 return (ARCHIVE_WARN);
1612 if (size > 0 && (value = malloc(size)) == NULL) {
1613 archive_set_error(&a->archive, errno, "Out of memory");
1614 return (ARCHIVE_FATAL);
1618 size = extattr_get_fd(fd, namespace, name, value, size);
1619 else if (!a->follow_symlinks)
1620 size = extattr_get_link(accpath, namespace, name, value, size);
1622 size = extattr_get_file(accpath, namespace, name, value, size);
1626 archive_set_error(&a->archive, errno,
1627 "Couldn't read extended attribute");
1628 return (ARCHIVE_WARN);
1631 archive_entry_xattr_add_entry(entry, fullname, value, size);
1634 return (ARCHIVE_OK);
1638 setup_xattrs(struct archive_read_disk *a,
1639 struct archive_entry *entry, int *fd)
1645 int namespace = EXTATTR_NAMESPACE_USER;
1647 path = archive_entry_sourcepath(entry);
1649 path = archive_entry_pathname(entry);
1651 if (*fd < 0 && a->tree != NULL) {
1652 if (a->follow_symlinks ||
1653 archive_entry_filetype(entry) != AE_IFLNK)
1654 *fd = a->open_on_current_dir(a->tree, path,
1655 O_RDONLY | O_NONBLOCK);
1657 if (a->tree_enter_working_dir(a->tree) != 0) {
1658 archive_set_error(&a->archive, errno,
1659 "Couldn't access %s", path);
1660 return (ARCHIVE_FAILED);
1666 list_size = extattr_list_fd(*fd, namespace, NULL, 0);
1667 else if (!a->follow_symlinks)
1668 list_size = extattr_list_link(path, namespace, NULL, 0);
1670 list_size = extattr_list_file(path, namespace, NULL, 0);
1672 if (list_size == -1 && errno == EOPNOTSUPP)
1673 return (ARCHIVE_OK);
1674 if (list_size == -1) {
1675 archive_set_error(&a->archive, errno,
1676 "Couldn't list extended attributes");
1677 return (ARCHIVE_WARN);
1681 return (ARCHIVE_OK);
1683 if ((list = malloc(list_size)) == NULL) {
1684 archive_set_error(&a->archive, errno, "Out of memory");
1685 return (ARCHIVE_FATAL);
1689 list_size = extattr_list_fd(*fd, namespace, list, list_size);
1690 else if (!a->follow_symlinks)
1691 list_size = extattr_list_link(path, namespace, list, list_size);
1693 list_size = extattr_list_file(path, namespace, list, list_size);
1695 if (list_size == -1) {
1696 archive_set_error(&a->archive, errno,
1697 "Couldn't retrieve extended attributes");
1699 return (ARCHIVE_WARN);
1703 while ((p - list) < list_size) {
1704 size_t len = 255 & (int)*p;
1707 strcpy(buff, "user.");
1708 name = buff + strlen(buff);
1709 memcpy(name, p + 1, len);
1711 setup_xattr(a, entry, namespace, name, buff, *fd);
1716 return (ARCHIVE_OK);
1722 * Generic (stub) extended attribute support.
1725 setup_xattrs(struct archive_read_disk *a,
1726 struct archive_entry *entry, int *fd)
1728 (void)a; /* UNUSED */
1729 (void)entry; /* UNUSED */
1730 (void)fd; /* UNUSED */
1731 return (ARCHIVE_OK);
1736 #if defined(HAVE_LINUX_FIEMAP_H)
1739 * Linux FIEMAP sparse interface.
1741 * The FIEMAP ioctl returns an "extent" for each physical allocation
1742 * on disk. We need to process those to generate a more compact list
1743 * of logical file blocks. We also need to be very careful to use
1744 * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
1745 * does not report allocations for newly-written data that hasn't
1746 * been synced to disk.
1748 * It's important to return a minimal sparse file list because we want
1749 * to not trigger sparse file extensions if we don't have to, since
1750 * not all readers support them.
1754 setup_sparse_fiemap(struct archive_read_disk *a,
1755 struct archive_entry *entry, int *fd)
1759 struct fiemap_extent *fe;
1761 int count, do_fiemap, iters;
1762 int exit_sts = ARCHIVE_OK;
1764 if (archive_entry_filetype(entry) != AE_IFREG
1765 || archive_entry_size(entry) <= 0
1766 || archive_entry_hardlink(entry) != NULL)
1767 return (ARCHIVE_OK);
1772 path = archive_entry_sourcepath(entry);
1774 path = archive_entry_pathname(entry);
1775 if (a->tree != NULL)
1776 *fd = a->open_on_current_dir(a->tree, path,
1777 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1779 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1781 archive_set_error(&a->archive, errno,
1782 "Can't open `%s'", path);
1783 return (ARCHIVE_FAILED);
1785 __archive_ensure_cloexec_flag(*fd);
1788 /* Initialize buffer to avoid the error valgrind complains about. */
1789 memset(buff, 0, sizeof(buff));
1790 count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
1791 fm = (struct fiemap *)buff;
1793 fm->fm_length = ~0ULL;;
1794 fm->fm_flags = FIEMAP_FLAG_SYNC;
1795 fm->fm_extent_count = count;
1797 size = archive_entry_size(entry);
1798 for (iters = 0; ; ++iters) {
1801 r = ioctl(*fd, FS_IOC_FIEMAP, fm);
1803 /* When something error happens, it is better we
1804 * should return ARCHIVE_OK because an earlier
1805 * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
1806 goto exit_setup_sparse_fiemap;
1808 if (fm->fm_mapped_extents == 0) {
1810 /* Fully sparse file; insert a zero-length "data" entry */
1811 archive_entry_sparse_add_entry(entry, 0, 0);
1815 fe = fm->fm_extents;
1816 for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
1817 if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
1818 /* The fe_length of the last block does not
1819 * adjust itself to its size files. */
1820 int64_t length = fe->fe_length;
1821 if (fe->fe_logical + length > (uint64_t)size)
1822 length -= fe->fe_logical + length - size;
1823 if (fe->fe_logical == 0 && length == size) {
1824 /* This is not sparse. */
1829 archive_entry_sparse_add_entry(entry,
1830 fe->fe_logical, length);
1832 if (fe->fe_flags & FIEMAP_EXTENT_LAST)
1836 fe = fm->fm_extents + fm->fm_mapped_extents -1;
1837 fm->fm_start = fe->fe_logical + fe->fe_length;
1841 exit_setup_sparse_fiemap:
1845 #if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1847 setup_sparse(struct archive_read_disk *a,
1848 struct archive_entry *entry, int *fd)
1850 return setup_sparse_fiemap(a, entry, fd);
1853 #endif /* defined(HAVE_LINUX_FIEMAP_H) */
1855 #if defined(SEEK_HOLE) && defined(SEEK_DATA)
1858 * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
1862 setup_sparse(struct archive_read_disk *a,
1863 struct archive_entry *entry, int *fd)
1868 int exit_sts = ARCHIVE_OK;
1869 int check_fully_sparse = 0;
1871 if (archive_entry_filetype(entry) != AE_IFREG
1872 || archive_entry_size(entry) <= 0
1873 || archive_entry_hardlink(entry) != NULL)
1874 return (ARCHIVE_OK);
1876 /* Does filesystem support the reporting of hole ? */
1877 if (*fd < 0 && a->tree != NULL) {
1880 path = archive_entry_sourcepath(entry);
1882 path = archive_entry_pathname(entry);
1883 *fd = a->open_on_current_dir(a->tree, path,
1884 O_RDONLY | O_NONBLOCK);
1886 archive_set_error(&a->archive, errno,
1887 "Can't open `%s'", path);
1888 return (ARCHIVE_FAILED);
1893 #ifdef _PC_MIN_HOLE_SIZE
1894 if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
1895 return (ARCHIVE_OK);
1897 initial_off = lseek(*fd, 0, SEEK_CUR);
1898 if (initial_off != 0)
1899 lseek(*fd, 0, SEEK_SET);
1903 path = archive_entry_sourcepath(entry);
1905 path = archive_entry_pathname(entry);
1907 #ifdef _PC_MIN_HOLE_SIZE
1908 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
1909 return (ARCHIVE_OK);
1911 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1913 archive_set_error(&a->archive, errno,
1914 "Can't open `%s'", path);
1915 return (ARCHIVE_FAILED);
1917 __archive_ensure_cloexec_flag(*fd);
1921 #ifndef _PC_MIN_HOLE_SIZE
1922 /* Check if the underlying filesystem supports seek hole */
1923 off_s = lseek(*fd, 0, SEEK_HOLE);
1925 #if defined(HAVE_LINUX_FIEMAP_H)
1926 return setup_sparse_fiemap(a, entry, fd);
1928 goto exit_setup_sparse;
1931 lseek(*fd, 0, SEEK_SET);
1935 size = archive_entry_size(entry);
1936 while (off_s < size) {
1937 off_s = lseek(*fd, off_s, SEEK_DATA);
1938 if (off_s == (off_t)-1) {
1939 if (errno == ENXIO) {
1941 if (archive_entry_sparse_count(entry) == 0) {
1942 /* Potentially a fully-sparse file. */
1943 check_fully_sparse = 1;
1947 archive_set_error(&a->archive, errno,
1948 "lseek(SEEK_HOLE) failed");
1949 exit_sts = ARCHIVE_FAILED;
1950 goto exit_setup_sparse;
1952 off_e = lseek(*fd, off_s, SEEK_HOLE);
1953 if (off_e == (off_t)-1) {
1954 if (errno == ENXIO) {
1955 off_e = lseek(*fd, 0, SEEK_END);
1956 if (off_e != (off_t)-1)
1957 break;/* no more data */
1959 archive_set_error(&a->archive, errno,
1960 "lseek(SEEK_DATA) failed");
1961 exit_sts = ARCHIVE_FAILED;
1962 goto exit_setup_sparse;
1964 if (off_s == 0 && off_e == size)
1965 break;/* This is not sparse. */
1966 archive_entry_sparse_add_entry(entry, off_s,
1971 if (check_fully_sparse) {
1972 if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
1973 lseek(*fd, 0, SEEK_END) == size) {
1974 /* Fully sparse file; insert a zero-length "data" entry */
1975 archive_entry_sparse_add_entry(entry, 0, 0);
1979 lseek(*fd, initial_off, SEEK_SET);
1983 #elif !defined(HAVE_LINUX_FIEMAP_H)
1986 * Generic (stub) sparse support.
1989 setup_sparse(struct archive_read_disk *a,
1990 struct archive_entry *entry, int *fd)
1992 (void)a; /* UNUSED */
1993 (void)entry; /* UNUSED */
1994 (void)fd; /* UNUSED */
1995 return (ARCHIVE_OK);
2000 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */