]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
MFC r314571:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_read_disk_entry_from_file.c
1 /*-
2  * Copyright (c) 2003-2009 Tim Kientzle
3  * Copyright (c) 2010-2012 Michihiro NAKAJIMA
4  * Copyright (c) 2016 Martin Matuska
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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.
26  */
27
28 #include "archive_platform.h"
29 __FBSDID("$FreeBSD$");
30
31 /* This is the tree-walking code for POSIX systems. */
32 #if !defined(_WIN32) || defined(__CYGWIN__)
33
34 #ifdef HAVE_SYS_TYPES_H
35 /* Mac OSX requires sys/types.h before sys/acl.h. */
36 #include <sys/types.h>
37 #endif
38 #ifdef HAVE_SYS_ACL_H
39 #include <sys/acl.h>
40 #endif
41 #ifdef HAVE_DARWIN_ACL
42 #include <membership.h>
43 #include <grp.h>
44 #include <pwd.h>
45 #endif
46 #ifdef HAVE_SYS_EXTATTR_H
47 #include <sys/extattr.h>
48 #endif
49 #ifdef HAVE_SYS_IOCTL_H
50 #include <sys/ioctl.h>
51 #endif
52 #ifdef HAVE_SYS_PARAM_H
53 #include <sys/param.h>
54 #endif
55 #ifdef HAVE_SYS_STAT_H
56 #include <sys/stat.h>
57 #endif
58 #if defined(HAVE_SYS_XATTR_H)
59 #include <sys/xattr.h>
60 #elif defined(HAVE_ATTR_XATTR_H)
61 #include <attr/xattr.h>
62 #endif
63 #ifdef HAVE_SYS_EA_H
64 #include <sys/ea.h>
65 #endif
66 #ifdef HAVE_ACL_LIBACL_H
67 #include <acl/libacl.h>
68 #endif
69 #ifdef HAVE_COPYFILE_H
70 #include <copyfile.h>
71 #endif
72 #ifdef HAVE_ERRNO_H
73 #include <errno.h>
74 #endif
75 #ifdef HAVE_FCNTL_H
76 #include <fcntl.h>
77 #endif
78 #ifdef HAVE_LIMITS_H
79 #include <limits.h>
80 #endif
81 #ifdef HAVE_LINUX_TYPES_H
82 #include <linux/types.h>
83 #endif
84 #ifdef HAVE_LINUX_FIEMAP_H
85 #include <linux/fiemap.h>
86 #endif
87 #ifdef HAVE_LINUX_FS_H
88 #include <linux/fs.h>
89 #endif
90 /*
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.
93  */
94 #ifdef HAVE_LINUX_EXT2_FS_H
95 #include <linux/ext2_fs.h>      /* for Linux file flags */
96 #endif
97 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
98 #include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
99 #endif
100 #ifdef HAVE_PATHS_H
101 #include <paths.h>
102 #endif
103 #ifdef HAVE_UNISTD_H
104 #include <unistd.h>
105 #endif
106
107 #include "archive.h"
108 #include "archive_entry.h"
109 #include "archive_private.h"
110 #include "archive_read_disk_private.h"
111
112 #ifndef O_CLOEXEC
113 #define O_CLOEXEC       0
114 #endif
115
116 /*
117  * Linux and FreeBSD plug this obvious hole in POSIX.1e in
118  * different ways.
119  */
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
124 #endif
125
126 /* NFSv4 platform ACL type */
127 #if HAVE_DARWIN_ACL
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
131 #endif
132
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);
144 #endif
145
146 int
147 archive_read_disk_entry_from_file(struct archive *_a,
148     struct archive_entry *entry,
149     int fd,
150     const struct stat *st)
151 {
152         struct archive_read_disk *a = (struct archive_read_disk *)_a;
153         const char *path, *name;
154         struct stat s;
155         int initial_fd = fd;
156         int r, r1;
157
158         archive_clear_error(_a);
159         path = archive_entry_sourcepath(entry);
160         if (path == NULL)
161                 path = archive_entry_pathname(entry);
162
163         if (a->tree == NULL) {
164                 if (st == NULL) {
165 #if HAVE_FSTAT
166                         if (fd >= 0) {
167                                 if (fstat(fd, &s) != 0) {
168                                         archive_set_error(&a->archive, errno,
169                                             "Can't fstat");
170                                         return (ARCHIVE_FAILED);
171                                 }
172                         } else
173 #endif
174 #if HAVE_LSTAT
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);
180                                 }
181                         } else
182 #endif
183                         if (stat(path, &s) != 0) {
184                                 archive_set_error(&a->archive, errno,
185                                     "Can't stat %s", path);
186                                 return (ARCHIVE_FAILED);
187                         }
188                         st = &s;
189                 }
190                 archive_entry_copy_stat(entry, st);
191         }
192
193         /* Lookup uname/gname */
194         name = archive_read_disk_uname(_a, archive_entry_uid(entry));
195         if (name != NULL)
196                 archive_entry_copy_uname(entry, name);
197         name = archive_read_disk_gname(_a, archive_entry_gid(entry));
198         if (name != NULL)
199                 archive_entry_copy_gname(entry, name);
200
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);
206 #endif
207
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))) {
215                 if (fd < 0) {
216                         if (a->tree != NULL)
217                                 fd = a->open_on_current_dir(a->tree, path,
218                                         O_RDONLY | O_NONBLOCK | O_CLOEXEC);
219                         else
220                                 fd = open(path, O_RDONLY | O_NONBLOCK |
221                                                 O_CLOEXEC);
222                         __archive_ensure_cloexec_flag(fd);
223                 }
224                 if (fd >= 0) {
225                         int stflags;
226                         r = ioctl(fd,
227 #if defined(FS_IOC_GETFLAGS)
228                             FS_IOC_GETFLAGS,
229 #else
230                             EXT2_IOC_GETFLAGS,
231 #endif
232                             &stflags);
233                         if (r == 0 && stflags != 0)
234                                 archive_entry_set_fflags(entry, stflags, 0);
235                 }
236         }
237 #endif
238
239 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
240         if (S_ISLNK(st->st_mode)) {
241                 size_t linkbuffer_len = st->st_size + 1;
242                 char *linkbuffer;
243                 int lnklen;
244
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);
250                 }
251                 if (a->tree != NULL) {
252 #ifdef HAVE_READLINKAT
253                         lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
254                             path, linkbuffer, linkbuffer_len);
255 #else
256                         if (a->tree_enter_working_dir(a->tree) != 0) {
257                                 archive_set_error(&a->archive, errno,
258                                     "Couldn't read link data");
259                                 free(linkbuffer);
260                                 return (ARCHIVE_FAILED);
261                         }
262                         lnklen = readlink(path, linkbuffer, linkbuffer_len);
263 #endif /* HAVE_READLINKAT */
264                 } else
265                         lnklen = readlink(path, linkbuffer, linkbuffer_len);
266                 if (lnklen < 0) {
267                         archive_set_error(&a->archive, errno,
268                             "Couldn't read link data");
269                         free(linkbuffer);
270                         return (ARCHIVE_FAILED);
271                 }
272                 linkbuffer[lnklen] = 0;
273                 archive_entry_set_symlink(entry, linkbuffer);
274                 free(linkbuffer);
275         }
276 #endif /* HAVE_READLINK || HAVE_READLINKAT */
277
278         r = 0;
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);
283                 if (r1 < r)
284                         r = r1;
285         }
286         if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
287                 r1 = setup_mac_metadata(a, entry, &fd);
288                 if (r1 < r)
289                         r = r1;
290         }
291         r1 = setup_sparse(a, entry, &fd);
292         if (r1 < r)
293                 r = r1;
294
295         /* If we opened the file earlier in this function, close it. */
296         if (initial_fd != fd)
297                 close(fd);
298         return (r);
299 }
300
301 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
302 /*
303  * The Mac OS "copyfile()" API copies the extended metadata for a
304  * file into a separate file in AppleDouble format (see RFC 1740).
305  *
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.
309  *
310  * Note that this is currently done unconditionally; the tar program has
311  * an option to discard this information before the archive is written.
312  *
313  * TODO: If there's a failure, report it and return ARCHIVE_WARN.
314  */
315 static int
316 setup_mac_metadata(struct archive_read_disk *a,
317     struct archive_entry *entry, int *fd)
318 {
319         int tempfd = -1;
320         int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
321         struct stat copyfile_stat;
322         int ret = ARCHIVE_OK;
323         void *buff = NULL;
324         int have_attrs;
325         const char *name, *tempdir;
326         struct archive_string tempfile;
327
328         (void)fd; /* UNUSED */
329         name = archive_entry_sourcepath(entry);
330         if (name == NULL)
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);
336         }
337         if (name == NULL) {
338                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
339                     "Can't open file to read extended attributes: No name");
340                 return (ARCHIVE_WARN);
341         }
342
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);
349         }
350         if (have_attrs == 0)
351                 return (ARCHIVE_OK);
352
353         tempdir = NULL;
354         if (issetugid() == 0)
355                 tempdir = getenv("TMPDIR");
356         if (tempdir == NULL)
357                 tempdir = _PATH_TMP;
358         archive_string_init(&tempfile);
359         archive_strcpy(&tempfile, tempdir);
360         archive_strcat(&tempfile, "tar.md.XXXXXX");
361         tempfd = mkstemp(tempfile.s);
362         if (tempfd < 0) {
363                 archive_set_error(&a->archive, errno,
364                     "Could not open extended attribute file");
365                 ret = ARCHIVE_WARN;
366                 goto cleanup;
367         }
368         __archive_ensure_cloexec_flag(tempfd);
369
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");
377                 ret = ARCHIVE_WARN;
378                 goto cleanup;
379         }
380         if (fstat(tempfd, &copyfile_stat)) {
381                 archive_set_error(&a->archive, errno,
382                     "Could not check size of extended attributes");
383                 ret = ARCHIVE_WARN;
384                 goto cleanup;
385         }
386         buff = malloc(copyfile_stat.st_size);
387         if (buff == NULL) {
388                 archive_set_error(&a->archive, errno,
389                     "Could not allocate memory for extended attributes");
390                 ret = ARCHIVE_WARN;
391                 goto cleanup;
392         }
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");
396                 ret = ARCHIVE_WARN;
397                 goto cleanup;
398         }
399         archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
400
401 cleanup:
402         if (tempfd >= 0) {
403                 close(tempfd);
404                 unlink(tempfile.s);
405         }
406         archive_string_free(&tempfile);
407         free(buff);
408         return (ret);
409 }
410
411 #else
412
413 /*
414  * Stub implementation for non-Mac systems.
415  */
416 static int
417 setup_mac_metadata(struct archive_read_disk *a,
418     struct archive_entry *entry, int *fd)
419 {
420         (void)a; /* UNUSED */
421         (void)entry; /* UNUSED */
422         (void)fd; /* UNUSED */
423         return (ARCHIVE_OK);
424 }
425 #endif
426
427 #if HAVE_DARWIN_ACL
428 static int translate_guid(struct archive *, acl_entry_t,
429     int *, int *, const char **);
430
431 static void add_trivial_nfs4_acl(struct archive_entry *);
432 #endif
433
434 #if HAVE_SUN_ACL
435 static int
436 sun_acl_is_trivial(void *, int, mode_t, int, int, int *);
437
438 static void *
439 sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
440 {
441         int cnt, cntcmd;
442         size_t size;
443         void *aclp;
444
445         if (cmd == GETACL) {
446                 cntcmd = GETACLCNT;
447                 size = sizeof(aclent_t);
448         }
449 #if HAVE_SUN_NFS4_ACL
450         else if (cmd == ACE_GETACL) {
451                 cntcmd = ACE_GETACLCNT;
452                 size = sizeof(ace_t);
453         }
454 #endif
455         else {
456                 errno = EINVAL;
457                 *aclcnt = -1;
458                 return (NULL);
459         }
460
461         aclp = NULL;
462         cnt = -2;
463
464         while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
465                 if (path != NULL)
466                         cnt = acl(path, cntcmd, 0, NULL);
467                 else
468                         cnt = facl(fd, cntcmd, 0, NULL);
469
470                 if (cnt > 0) {
471                         if (aclp == NULL)
472                                 aclp = malloc(cnt * size);
473                         else
474                                 aclp = realloc(NULL, cnt * size);
475                         if (aclp != NULL) {
476                                 if (path != NULL)
477                                         cnt = acl(path, cmd, cnt, aclp);
478                                 else
479                                         cnt = facl(fd, cmd, cnt, aclp);
480                         }
481                 } else {
482                         if (aclp != NULL) {
483                                 free(aclp);
484                                 aclp = NULL;
485                         }
486                         break;
487                 }
488         }
489
490         *aclcnt = cnt;
491         return (aclp);
492 }
493 #endif  /* HAVE_SUN_ACL */
494
495 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
496 static int translate_acl(struct archive_read_disk *a,
497     struct archive_entry *entry,
498 #if HAVE_SUN_ACL
499     void *aclp,
500     int aclcnt,
501 #else
502     acl_t acl,
503 #endif
504     int archive_entry_acl_type);
505
506 static int
507 setup_acls(struct archive_read_disk *a,
508     struct archive_entry *entry, int *fd)
509 {
510         const char      *accpath;
511 #if HAVE_SUN_ACL
512         void            *aclp;
513         int             aclcnt;
514 #else
515         acl_t           acl;
516 #endif
517         int             r;
518
519         accpath = NULL;
520
521 #if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP
522         if (*fd < 0)
523 #else
524         /* For default ACLs on Linux we need reachable accpath */
525         if (*fd < 0 || S_ISDIR(archive_entry_mode(entry)))
526 #endif
527         {
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);
536                 }
537                 if (a->tree != NULL &&
538 #if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP
539                     *fd < 0 &&
540 #endif
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);
545                 }
546         }
547
548         archive_entry_acl_clear(entry);
549
550 #if HAVE_SUN_ACL
551         aclp = NULL;
552 #else
553         acl = NULL;
554 #endif
555
556 #if HAVE_NFS4_ACL
557         /* Try NFSv4 ACL first. */
558         if (*fd >= 0)
559 #if HAVE_SUN_ACL
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);
563 #else
564                 acl = acl_get_fd(*fd);
565 #endif
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);
569 #else
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
573                    have one. */
574 #if HAVE_SUN_ACL
575                 aclp = NULL;
576 #else
577                 acl = NULL;
578 #endif
579 #endif /* !HAVE_ACL_GET_LINK_NP */
580         else
581 #if HAVE_SUN_ACL
582                 /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
583                 aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath);
584 #else
585                 acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
586 #endif
587
588
589         /* Ignore "trivial" ACLs that just mirror the file mode. */
590 #if HAVE_SUN_ACL
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) {
594                 free(aclp);
595                 aclp = NULL;
596                 return (ARCHIVE_OK);
597         }
598 #elif HAVE_ACL_IS_TRIVIAL_NP
599         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
600                 acl_free(acl);
601                 acl = NULL;
602                 return (ARCHIVE_OK);
603         }
604 #endif
605
606 #if HAVE_SUN_ACL
607         if (aclp != NULL)
608 #else
609         if (acl != NULL)
610 #endif
611         {
612                 r = translate_acl(a, entry,
613 #if HAVE_SUN_ACL
614                     aclp, aclcnt,
615 #else
616                     acl,
617 #endif
618                     ARCHIVE_ENTRY_ACL_TYPE_NFS4);
619 #if HAVE_SUN_ACL
620                 free(aclp);
621                 aclp = NULL;
622 #else
623                 acl_free(acl);
624                 acl = NULL;
625 #endif
626
627                 if (r != ARCHIVE_OK) {
628                         archive_set_error(&a->archive, errno,
629                             "Couldn't translate NFSv4 ACLs");
630                 }
631 #if HAVE_DARWIN_ACL
632                 /*
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.
637                  */
638                 if ((archive_entry_acl_types(entry) &
639                     ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
640                         add_trivial_nfs4_acl(entry);
641 #endif
642                 return (r);
643         }
644 #endif  /* HAVE_NFS4_ACL */
645
646 #if HAVE_POSIX_ACL || HAVE_SUN_ACL
647         /* This code path is skipped on MacOS */
648
649         /* Retrieve access ACL from file. */
650         if (*fd >= 0)
651 #if HAVE_SUN_ACL
652                 aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL);
653 #else
654                 acl = acl_get_fd(*fd);
655 #endif
656 #if HAVE_ACL_GET_LINK_NP
657         else if (!a->follow_symlinks)
658                 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
659 #else
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
663                    have one. */
664 #if HAVE_SUN_ACL
665                 aclp = NULL;
666 #else
667                 acl = NULL;
668 #endif
669 #endif /* !HAVE_ACL_GET_LINK_NP */
670         else
671 #if HAVE_SUN_ACL
672                 aclp = sunacl_get(GETACL, &aclcnt, 0, accpath);
673 #else
674                 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
675 #endif
676
677
678         /* Ignore "trivial" ACLs that just mirror the file mode. */
679 #if HAVE_SUN_ACL
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) {
683                 free(aclp);
684                 aclp = NULL;
685         }
686 #elif HAVE_ACL_IS_TRIVIAL_NP
687         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
688                 acl_free(acl);
689                 acl = NULL;
690         }
691 #endif
692
693 #if HAVE_SUN_ACL
694         if (aclp != NULL)
695 #else
696         if (acl != NULL)
697 #endif
698         {
699                 r = translate_acl(a, entry,
700 #if HAVE_SUN_ACL
701                     aclp, aclcnt,
702 #else
703                     acl,
704 #endif
705                     ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
706 #if HAVE_SUN_ACL
707                 free(aclp);
708                 aclp = NULL;
709 #else
710                 acl_free(acl);
711                 acl = NULL;
712 #endif
713
714                 if (r != ARCHIVE_OK) {
715                         archive_set_error(&a->archive, errno,
716                             "Couldn't translate access ACLs");
717                         return (r);
718                 }
719         }
720
721 #if !HAVE_SUN_ACL
722         /* Only directories can have default ACLs. */
723         if (S_ISDIR(archive_entry_mode(entry))) {
724 #if HAVE_ACL_GET_FD_NP
725                 if (*fd >= 0)
726                         acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
727                 else
728 #endif
729                 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
730                 if (acl != NULL) {
731                         r = translate_acl(a, entry, acl,
732                             ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
733                         acl_free(acl);
734                         if (r != ARCHIVE_OK) {
735                                 archive_set_error(&a->archive, errno,
736                                     "Couldn't translate default ACLs");
737                                 return (r);
738                         }
739                 }
740         }
741 #endif  /* !HAVE_SUN_ACL */
742 #endif  /* HAVE_POSIX_ACL || HAVE_SUN_ACL */
743         return (ARCHIVE_OK);
744 }
745
746 /*
747  * Translate system ACL permissions into libarchive internal structure
748  */
749 static const struct {
750         const int archive_perm;
751         const int platform_perm;
752 } acl_perm_map[] = {
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}
790 #endif
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}
812 #endif
813 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
814 };
815
816 #if HAVE_NFS4_ACL
817 /*
818  * Translate system NFSv4 inheritance flags into libarchive internal structure
819  */
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}
833 #endif
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 */
849 };
850 #endif  /* HAVE_NFS4_ACL */
851
852 #if HAVE_DARWIN_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)
855 {
856         void *q;
857         uid_t ugid;
858         int r, idtype;
859         struct passwd *pwd;
860         struct group *grp;
861
862         q = acl_get_qualifier(acl_entry);
863         if (q == NULL)
864                 return (1);
865         r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
866         if (r != 0) {
867                 acl_free(q);
868                 return (1);
869         }
870         if (idtype == ID_TYPE_UID) {
871                 *ae_tag = ARCHIVE_ENTRY_ACL_USER;
872                 pwd = getpwuuid(q);
873                 if (pwd == NULL) {
874                         *ae_id = ugid;
875                         *ae_name = NULL;
876                 } else {
877                         *ae_id = pwd->pw_uid;
878                         *ae_name = archive_read_disk_uname(a, *ae_id);
879                 }
880         } else if (idtype == ID_TYPE_GID) {
881                 *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
882                 grp = getgruuid(q);
883                 if (grp == NULL) {
884                         *ae_id = ugid;
885                         *ae_name = NULL;
886                 } else {
887                         *ae_id = grp->gr_gid;
888                         *ae_name = archive_read_disk_gname(a, *ae_id);
889                 }
890         } else
891                 r = 1;
892
893         acl_free(q);
894         return (r);
895 }
896
897 /*
898  * Add trivial NFSv4 ACL entries from mode
899  */
900 static void
901 add_trivial_nfs4_acl(struct archive_entry *entry)
902 {
903         mode_t mode;
904         int i;
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;
917
918         struct {
919             const int type;
920             const int tag;
921             int permset;
922         } tacl_entry[] = {
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}
929         };
930
931         mode = archive_entry_mode(entry);
932
933         /* Permissions for everyone@ */
934         if (mode & 0004)
935                 tacl_entry[5].permset |= rperm;
936         if (mode & 0002)
937                 tacl_entry[5].permset |= wperm;
938         if (mode & 0001)
939                 tacl_entry[5].permset |= eperm;
940
941         /* Permissions for group@ */
942         if (mode & 0040)
943                 tacl_entry[4].permset |= rperm;
944         else if (mode & 0004)
945                 tacl_entry[2].permset |= rperm;
946         if (mode & 0020)
947                 tacl_entry[4].permset |= wperm;
948         else if (mode & 0002)
949                 tacl_entry[2].permset |= wperm;
950         if (mode & 0010)
951                 tacl_entry[4].permset |= eperm;
952         else if (mode & 0001)
953                 tacl_entry[2].permset |= eperm;
954
955         /* Permissions for owner@ */
956         if (mode & 0400) {
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;
962         if (mode & 0200) {
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;
968         if (mode & 0100) {
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;
974
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);
980                 }
981         }
982
983         return;
984 }
985 #elif HAVE_SUN_ACL
986 /*
987  * Check if acl is trivial
988  * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
989  */
990 static int
991 sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4,
992     int is_dir, int *trivialp)
993 {
994         int i, p;
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;
1003
1004         ace_t *ace;
1005         ace_t tace[6];
1006 #endif
1007
1008         if (aclp == NULL || trivialp == NULL)
1009                 return (-1);
1010
1011         *trivialp = 0;
1012
1013         /*
1014          * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
1015          * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
1016          * including mask.
1017          */
1018         if (!is_nfs4) {
1019                 if (aclcnt == 4)
1020                         *trivialp = 1;
1021                 return (0);
1022         }
1023
1024 #if HAVE_SUN_NFS4_ACL
1025         /*
1026          * Continue with checking NFSv4 ACLs
1027          *
1028          * Create list of trivial ace's to be compared
1029          */
1030
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;
1035
1036         /* owner@ deny */
1037         tace[1].a_flags = ACE_OWNER;
1038         tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
1039         tace[1].a_access_mask = 0;
1040
1041         /* group@ deny */
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;
1045
1046         /* owner@ allow */
1047         tace[3].a_flags = ACE_OWNER;
1048         tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
1049         tace[3].a_access_mask = ownset;
1050
1051         /* group@ allow */
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;
1055
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;
1060
1061         /* Permissions for everyone@ */
1062         if (mode & 0004)
1063                 tace[5].a_access_mask |= rperm;
1064         if (mode & 0002)
1065                 tace[5].a_access_mask |= wperm;
1066         if (mode & 0001)
1067                 tace[5].a_access_mask |= eperm;
1068
1069         /* Permissions for group@ */
1070         if (mode & 0040)
1071                 tace[4].a_access_mask |= rperm;
1072         else if (mode & 0004)
1073                 tace[2].a_access_mask |= rperm;
1074         if (mode & 0020)
1075                 tace[4].a_access_mask |= wperm;
1076         else if (mode & 0002)
1077                 tace[2].a_access_mask |= wperm;
1078         if (mode & 0010)
1079                 tace[4].a_access_mask |= eperm;
1080         else if (mode & 0001)
1081                 tace[2].a_access_mask |= eperm;
1082
1083         /* Permissions for owner@ */
1084         if (mode & 0400) {
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;
1090         if (mode & 0200) {
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;
1096         if (mode & 0100) {
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;
1102
1103         /* Check if the acl count matches */
1104         p = 3;
1105         for (i = 0; i < 3; i++) {
1106                 if (tace[i].a_access_mask != 0)
1107                         p++;
1108         }
1109         if (aclcnt != p)
1110                 return (0);
1111
1112         p = 0;
1113         for (i = 0; i < 6; i++) {
1114                 if (tace[i].a_access_mask != 0) {
1115                         ace = &((ace_t *)aclp)[p];
1116                         /*
1117                          * Illumos added ACE_DELETE_CHILD to write perms for
1118                          * directories. We have to check against that, too.
1119                          */
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))))
1126                                 return (0);
1127                         p++;
1128                 }
1129         }
1130
1131         *trivialp = 1;
1132 #else   /* !HAVE_SUN_NFS4_ACL */
1133         (void)aclp;     /* UNUSED */
1134 #endif  /* !HAVE_SUN_NFS4_ACL */
1135         return (0);
1136 }
1137 #endif  /* HAVE_SUN_ACL */
1138
1139 #if HAVE_SUN_ACL
1140 /*
1141  * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
1142  */
1143 static int
1144 translate_acl(struct archive_read_disk *a,
1145     struct archive_entry *entry, void *aclp, int aclcnt,
1146     int default_entry_acl_type)
1147 {
1148         int e, i;
1149         int ae_id, ae_tag, ae_perm;
1150         int entry_acl_type;
1151         const char *ae_name;
1152         aclent_t *aclent;
1153 #if HAVE_SUN_NFS4_ACL
1154         ace_t *ace;
1155 #endif
1156
1157         if (aclcnt <= 0)
1158                 return (ARCHIVE_OK);
1159
1160         for (e = 0; e < aclcnt; e++) {
1161                 ae_name = NULL;
1162                 ae_tag = 0;
1163                 ae_perm = 0;
1164
1165 #if HAVE_SUN_NFS4_ACL
1166                 if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1167                         ace = &((ace_t *)aclp)[e];
1168                         ae_id = ace->a_who;
1169
1170                         switch(ace->a_type) {
1171                         case ACE_ACCESS_ALLOWED_ACE_TYPE:
1172                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1173                                 break;
1174                         case ACE_ACCESS_DENIED_ACE_TYPE:
1175                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1176                                 break;
1177                         case ACE_SYSTEM_AUDIT_ACE_TYPE:
1178                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1179                                 break;
1180                         case ACE_SYSTEM_ALARM_ACE_TYPE:
1181                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1182                                 break;
1183                         default:
1184                                 /* Unknown entry type, skip */
1185                                 continue;
1186                         }
1187
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,
1197                                     ae_id);
1198                         } else {
1199                                 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1200                                 ae_name = archive_read_disk_uname(&a->archive,
1201                                     ae_id);
1202                         }
1203
1204                         for (i = 0; i < (int)(sizeof(acl_inherit_map) /
1205                             sizeof(acl_inherit_map[0])); ++i) {
1206                                 if ((ace->a_flags &
1207                                     acl_inherit_map[i].platform_inherit) != 0)
1208                                         ae_perm |=
1209                                             acl_inherit_map[i].archive_inherit;
1210                         }
1211
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)
1216                                         ae_perm |=
1217                                             acl_perm_map[i].archive_perm;
1218                         }
1219                 } else
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;
1225                         else
1226                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1227                         ae_id = aclent->a_id;
1228
1229                         switch(aclent->a_type) {
1230                         case DEF_USER:
1231                         case USER:
1232                                 ae_name = archive_read_disk_uname(&a->archive,
1233                                     ae_id);
1234                                 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1235                                 break;
1236                         case DEF_GROUP:
1237                         case GROUP:
1238                                 ae_name = archive_read_disk_gname(&a->archive,
1239                                     ae_id);
1240                                 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1241                                 break;
1242                         case DEF_CLASS_OBJ:
1243                         case CLASS_OBJ:
1244                                 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1245                                 break;
1246                         case DEF_USER_OBJ:
1247                         case USER_OBJ:
1248                                 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1249                                 break;
1250                         case DEF_GROUP_OBJ:
1251                         case GROUP_OBJ:
1252                                 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1253                                 break;
1254                         case DEF_OTHER_OBJ:
1255                         case OTHER_OBJ:
1256                                 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1257                                 break;
1258                         default:
1259                                 /* Unknown tag type, skip */
1260                                 continue;
1261                         }
1262
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;
1269                 } else
1270                         return (ARCHIVE_WARN);
1271
1272                 archive_entry_acl_add_entry(entry, entry_acl_type,
1273                     ae_perm, ae_tag, ae_id, ae_name);
1274         }
1275         return (ARCHIVE_OK);
1276 }
1277 #else   /* !HAVE_SUN_ACL */
1278 /*
1279  * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
1280  * MacOS (NFSv4 only) ACLs into libarchive internal structure
1281  */
1282 static int
1283 translate_acl(struct archive_read_disk *a,
1284     struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
1285 {
1286         acl_tag_t        acl_tag;
1287 #if HAVE_FREEBSD_NFS4_ACL
1288         acl_entry_type_t acl_type;
1289         int brand;
1290 #endif
1291 #if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
1292         acl_flagset_t    acl_flagset;
1293 #endif
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
1299         void            *q;
1300 #endif
1301         const char      *ae_name;
1302
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);
1311         }
1312         switch (brand) {
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:
1317                         break;
1318                 default:
1319                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1320                             "Invalid ACL entry type for POSIX.1e ACL");
1321                         return (ARCHIVE_WARN);
1322                 }
1323                 break;
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);
1329                 }
1330                 break;
1331         default:
1332                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1333                     "Unknown ACL brand");
1334                 return (ARCHIVE_WARN);
1335         }
1336 #endif
1337
1338         s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
1339         if (s == -1) {
1340                 archive_set_error(&a->archive, errno,
1341                     "Failed to get first ACL entry");
1342                 return (ARCHIVE_WARN);
1343         }
1344
1345 #if HAVE_DARWIN_ACL
1346         while (s == 0)
1347 #else   /* FreeBSD, Linux */
1348         while (s == 1)
1349 #endif
1350         {
1351                 ae_id = -1;
1352                 ae_name = NULL;
1353                 ae_perm = 0;
1354
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);
1359                 }
1360                 switch (acl_tag) {
1361 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
1362                 case ACL_USER:
1363                         q = acl_get_qualifier(acl_entry);
1364                         if (q != NULL) {
1365                                 ae_id = (int)*(uid_t *)q;
1366                                 acl_free(q);
1367                                 ae_name = archive_read_disk_uname(&a->archive,
1368                                     ae_id);
1369                         }
1370                         ae_tag = ARCHIVE_ENTRY_ACL_USER;
1371                         break;
1372                 case ACL_GROUP:
1373                         q = acl_get_qualifier(acl_entry);
1374                         if (q != NULL) {
1375                                 ae_id = (int)*(gid_t *)q;
1376                                 acl_free(q);
1377                                 ae_name = archive_read_disk_gname(&a->archive,
1378                                     ae_id);
1379                         }
1380                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1381                         break;
1382                 case ACL_MASK:
1383                         ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1384                         break;
1385                 case ACL_USER_OBJ:
1386                         ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1387                         break;
1388                 case ACL_GROUP_OBJ:
1389                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1390                         break;
1391                 case ACL_OTHER:
1392                         ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1393                         break;
1394 #if HAVE_FREEBSD_NFS4_ACL
1395                 case ACL_EVERYONE:
1396                         ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1397                         break;
1398 #endif
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,
1403                             &ae_tag, &ae_name);
1404                         break;
1405                 case ACL_EXTENDED_DENY:
1406                         entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1407                         r = translate_guid(&a->archive, acl_entry, &ae_id,
1408                             &ae_tag, &ae_name);
1409                         break;
1410 #endif  /* HAVE_DARWIN_ACL */
1411                 default:
1412                         /* Skip types that libarchive can't support. */
1413                         s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1414                         continue;
1415                 }
1416
1417 #if HAVE_DARWIN_ACL
1418                 /* Skip if translate_guid() above failed */
1419                 if (r != 0) {
1420                         s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1421                         continue;
1422                 }
1423 #endif
1424
1425 #if !HAVE_DARWIN_ACL
1426                 // XXX acl_type maps to allow/deny/audit/YYYY bits
1427                 entry_acl_type = default_entry_acl_type;
1428 #endif
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
1432                         /*
1433                          * acl_get_entry_type_np() fails with non-NFSv4 ACLs
1434                          */
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);
1439                         }
1440                         switch (acl_type) {
1441                         case ACL_ENTRY_TYPE_ALLOW:
1442                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1443                                 break;
1444                         case ACL_ENTRY_TYPE_DENY:
1445                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1446                                 break;
1447                         case ACL_ENTRY_TYPE_AUDIT:
1448                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
1449                                 break;
1450                         case ACL_ENTRY_TYPE_ALARM:
1451                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1452                                 break;
1453                         default:
1454                                 archive_set_error(&a->archive, errno,
1455                                     "Invalid NFSv4 ACL entry type");
1456                                 return (ARCHIVE_WARN);
1457                         }
1458 #endif  /* HAVE_FREEBSD_NFS4_ACL */
1459
1460                         /*
1461                          * Libarchive stores "flag" (NFSv4 inheritance bits)
1462                          * in the ae_perm bitmap.
1463                          *
1464                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
1465                          */
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);
1470                         }
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);
1474                                 if (r == -1) {
1475                                         archive_set_error(&a->archive, errno,
1476                                             "Failed to check flag in a NFSv4 "
1477                                             "ACL flagset");
1478                                         return (ARCHIVE_WARN);
1479                                 } else if (r)
1480                                         ae_perm |= acl_inherit_map[i].archive_inherit;
1481                         }
1482                 }
1483 #endif  /* HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL */
1484
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);
1489                 }
1490                 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
1491                         /*
1492                          * acl_get_perm() is spelled differently on different
1493                          * platforms; see above.
1494                          */
1495                         r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
1496                         if (r == -1) {
1497                                 archive_set_error(&a->archive, errno,
1498                                     "Failed to check permission in an ACL permission set");
1499                                 return (ARCHIVE_WARN);
1500                         } else if (r)
1501                                 ae_perm |= acl_perm_map[i].archive_perm;
1502                 }
1503
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;
1507 #endif
1508
1509                 archive_entry_acl_add_entry(entry, entry_acl_type,
1510                                             ae_perm, ae_tag,
1511                                             ae_id, ae_name);
1512
1513                 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1514 #if !HAVE_DARWIN_ACL
1515                 if (s == -1) {
1516                         archive_set_error(&a->archive, errno,
1517                             "Failed to get next ACL entry");
1518                         return (ARCHIVE_WARN);
1519                 }
1520 #endif
1521         }
1522         return (ARCHIVE_OK);
1523 }
1524 #endif  /* !HAVE_SUN_ACL */
1525 #else   /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1526 static int
1527 setup_acls(struct archive_read_disk *a,
1528     struct archive_entry *entry, int *fd)
1529 {
1530         (void)a;      /* UNUSED */
1531         (void)entry;  /* UNUSED */
1532         (void)fd;     /* UNUSED */
1533         return (ARCHIVE_OK);
1534 }
1535 #endif  /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1536
1537 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
1538     HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
1539     (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
1540
1541 /*
1542  * Linux and AIX extended attribute support.
1543  *
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
1549  * to listxattr().
1550  */
1551
1552
1553 static int
1554 setup_xattr(struct archive_read_disk *a,
1555     struct archive_entry *entry, const char *name, int fd, const char *accpath)
1556 {
1557         ssize_t size;
1558         void *value = NULL;
1559
1560 #if HAVE_FGETXATTR
1561         if (fd >= 0)
1562                 size = fgetxattr(fd, name, NULL, 0);
1563         else if (!a->follow_symlinks)
1564                 size = lgetxattr(accpath, name, NULL, 0);
1565         else
1566                 size = getxattr(accpath, name, NULL, 0);
1567 #elif HAVE_FGETEA
1568         if (fd >= 0)
1569                 size = fgetea(fd, name, NULL, 0);
1570         else if (!a->follow_symlinks)
1571                 size = lgetea(accpath, name, NULL, 0);
1572         else
1573                 size = getea(accpath, name, NULL, 0);
1574 #endif
1575
1576         if (size == -1) {
1577                 archive_set_error(&a->archive, errno,
1578                     "Couldn't query extended attribute");
1579                 return (ARCHIVE_WARN);
1580         }
1581
1582         if (size > 0 && (value = malloc(size)) == NULL) {
1583                 archive_set_error(&a->archive, errno, "Out of memory");
1584                 return (ARCHIVE_FATAL);
1585         }
1586
1587 #if HAVE_FGETXATTR
1588         if (fd >= 0)
1589                 size = fgetxattr(fd, name, value, size);
1590         else if (!a->follow_symlinks)
1591                 size = lgetxattr(accpath, name, value, size);
1592         else
1593                 size = getxattr(accpath, name, value, size);
1594 #elif HAVE_FGETEA
1595         if (fd >= 0)
1596                 size = fgetea(fd, name, value, size);
1597         else if (!a->follow_symlinks)
1598                 size = lgetea(accpath, name, value, size);
1599         else
1600                 size = getea(accpath, name, value, size);
1601 #endif
1602
1603         if (size == -1) {
1604                 archive_set_error(&a->archive, errno,
1605                     "Couldn't read extended attribute");
1606                 return (ARCHIVE_WARN);
1607         }
1608
1609         archive_entry_xattr_add_entry(entry, name, value, size);
1610
1611         free(value);
1612         return (ARCHIVE_OK);
1613 }
1614
1615 static int
1616 setup_xattrs(struct archive_read_disk *a,
1617     struct archive_entry *entry, int *fd)
1618 {
1619         char *list, *p;
1620         const char *path;
1621         ssize_t list_size;
1622
1623         path = NULL;
1624
1625         if (*fd < 0) {
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);
1630                 if (path == NULL) {
1631                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1632                             "Couldn't determine file path to read "
1633                             "extended attributes");
1634                         return (ARCHIVE_WARN);
1635                 }
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);
1640                 }
1641         }
1642
1643 #if HAVE_FLISTXATTR
1644         if (*fd >= 0)
1645                 list_size = flistxattr(*fd, NULL, 0);
1646         else if (!a->follow_symlinks)
1647                 list_size = llistxattr(path, NULL, 0);
1648         else
1649                 list_size = listxattr(path, NULL, 0);
1650 #elif HAVE_FLISTEA
1651         if (*fd >= 0)
1652                 list_size = flistea(*fd, NULL, 0);
1653         else if (!a->follow_symlinks)
1654                 list_size = llistea(path, NULL, 0);
1655         else
1656                 list_size = listea(path, NULL, 0);
1657 #endif
1658
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);
1665         }
1666
1667         if (list_size == 0)
1668                 return (ARCHIVE_OK);
1669
1670         if ((list = malloc(list_size)) == NULL) {
1671                 archive_set_error(&a->archive, errno, "Out of memory");
1672                 return (ARCHIVE_FATAL);
1673         }
1674
1675 #if HAVE_FLISTXATTR
1676         if (*fd >= 0)
1677                 list_size = flistxattr(*fd, list, list_size);
1678         else if (!a->follow_symlinks)
1679                 list_size = llistxattr(path, list, list_size);
1680         else
1681                 list_size = listxattr(path, list, list_size);
1682 #elif HAVE_FLISTEA
1683         if (*fd >= 0)
1684                 list_size = flistea(*fd, list, list_size);
1685         else if (!a->follow_symlinks)
1686                 list_size = llistea(path, list, list_size);
1687         else
1688                 list_size = listea(path, list, list_size);
1689 #endif
1690
1691         if (list_size == -1) {
1692                 archive_set_error(&a->archive, errno,
1693                         "Couldn't retrieve extended attributes");
1694                 free(list);
1695                 return (ARCHIVE_WARN);
1696         }
1697
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)
1701                         continue;
1702                 setup_xattr(a, entry, p, *fd, path);
1703         }
1704
1705         free(list);
1706         return (ARCHIVE_OK);
1707 }
1708
1709 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
1710     HAVE_DECL_EXTATTR_NAMESPACE_USER
1711
1712 /*
1713  * FreeBSD extattr interface.
1714  */
1715
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
1719  * those separately.
1720  */
1721 static int
1722 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1723     int namespace, const char *name, const char *fullname, int fd,
1724     const char *path);
1725
1726 static int
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)
1730 {
1731         ssize_t size;
1732         void *value = NULL;
1733
1734         if (fd >= 0)
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);
1738         else
1739                 size = extattr_get_file(accpath, namespace, name, NULL, 0);
1740
1741         if (size == -1) {
1742                 archive_set_error(&a->archive, errno,
1743                     "Couldn't query extended attribute");
1744                 return (ARCHIVE_WARN);
1745         }
1746
1747         if (size > 0 && (value = malloc(size)) == NULL) {
1748                 archive_set_error(&a->archive, errno, "Out of memory");
1749                 return (ARCHIVE_FATAL);
1750         }
1751
1752         if (fd >= 0)
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);
1756         else
1757                 size = extattr_get_file(accpath, namespace, name, value, size);
1758
1759         if (size == -1) {
1760                 free(value);
1761                 archive_set_error(&a->archive, errno,
1762                     "Couldn't read extended attribute");
1763                 return (ARCHIVE_WARN);
1764         }
1765
1766         archive_entry_xattr_add_entry(entry, fullname, value, size);
1767
1768         free(value);
1769         return (ARCHIVE_OK);
1770 }
1771
1772 static int
1773 setup_xattrs(struct archive_read_disk *a,
1774     struct archive_entry *entry, int *fd)
1775 {
1776         char buff[512];
1777         char *list, *p;
1778         ssize_t list_size;
1779         const char *path;
1780         int namespace = EXTATTR_NAMESPACE_USER;
1781
1782         path = NULL;
1783
1784         if (*fd < 0) {
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);
1789                 if (path == NULL) {
1790                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1791                             "Couldn't determine file path to read "
1792                             "extended attributes");
1793                         return (ARCHIVE_WARN);
1794                 }
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);
1799                 }
1800         }
1801
1802         if (*fd >= 0)
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);
1806         else
1807                 list_size = extattr_list_file(path, namespace, NULL, 0);
1808
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);
1815         }
1816
1817         if (list_size == 0)
1818                 return (ARCHIVE_OK);
1819
1820         if ((list = malloc(list_size)) == NULL) {
1821                 archive_set_error(&a->archive, errno, "Out of memory");
1822                 return (ARCHIVE_FATAL);
1823         }
1824
1825         if (*fd >= 0)
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);
1829         else
1830                 list_size = extattr_list_file(path, namespace, list, list_size);
1831
1832         if (list_size == -1) {
1833                 archive_set_error(&a->archive, errno,
1834                         "Couldn't retrieve extended attributes");
1835                 free(list);
1836                 return (ARCHIVE_WARN);
1837         }
1838
1839         p = list;
1840         while ((p - list) < list_size) {
1841                 size_t len = 255 & (int)*p;
1842                 char *name;
1843
1844                 strcpy(buff, "user.");
1845                 name = buff + strlen(buff);
1846                 memcpy(name, p + 1, len);
1847                 name[len] = '\0';
1848                 setup_xattr(a, entry, namespace, name, buff, *fd, path);
1849                 p += 1 + len;
1850         }
1851
1852         free(list);
1853         return (ARCHIVE_OK);
1854 }
1855
1856 #else
1857
1858 /*
1859  * Generic (stub) extended attribute support.
1860  */
1861 static int
1862 setup_xattrs(struct archive_read_disk *a,
1863     struct archive_entry *entry, int *fd)
1864 {
1865         (void)a;     /* UNUSED */
1866         (void)entry; /* UNUSED */
1867         (void)fd;    /* UNUSED */
1868         return (ARCHIVE_OK);
1869 }
1870
1871 #endif
1872
1873 #if defined(HAVE_LINUX_FIEMAP_H)
1874
1875 /*
1876  * Linux FIEMAP sparse interface.
1877  *
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.
1884  *
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.
1888  */
1889
1890 static int
1891 setup_sparse_fiemap(struct archive_read_disk *a,
1892     struct archive_entry *entry, int *fd)
1893 {
1894         char buff[4096];
1895         struct fiemap *fm;
1896         struct fiemap_extent *fe;
1897         int64_t size;
1898         int count, do_fiemap, iters;
1899         int exit_sts = ARCHIVE_OK;
1900
1901         if (archive_entry_filetype(entry) != AE_IFREG
1902             || archive_entry_size(entry) <= 0
1903             || archive_entry_hardlink(entry) != NULL)
1904                 return (ARCHIVE_OK);
1905
1906         if (*fd < 0) {
1907                 const char *path;
1908
1909                 path = archive_entry_sourcepath(entry);
1910                 if (path == NULL)
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);
1915                 else
1916                         *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1917                 if (*fd < 0) {
1918                         archive_set_error(&a->archive, errno,
1919                             "Can't open `%s'", path);
1920                         return (ARCHIVE_FAILED);
1921                 }
1922                 __archive_ensure_cloexec_flag(*fd);
1923         }
1924
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;
1929         fm->fm_start = 0;
1930         fm->fm_length = ~0ULL;;
1931         fm->fm_flags = FIEMAP_FLAG_SYNC;
1932         fm->fm_extent_count = count;
1933         do_fiemap = 1;
1934         size = archive_entry_size(entry);
1935         for (iters = 0; ; ++iters) {
1936                 int i, r;
1937
1938                 r = ioctl(*fd, FS_IOC_FIEMAP, fm); 
1939                 if (r < 0) {
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;
1944                 }
1945                 if (fm->fm_mapped_extents == 0) {
1946                         if (iters == 0) {
1947                                 /* Fully sparse file; insert a zero-length "data" entry */
1948                                 archive_entry_sparse_add_entry(entry, 0, 0);
1949                         }
1950                         break;
1951                 }
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. */
1962                                         do_fiemap = 0;
1963                                         break;
1964                                 }
1965                                 if (length > 0)
1966                                         archive_entry_sparse_add_entry(entry,
1967                                             fe->fe_logical, length);
1968                         }
1969                         if (fe->fe_flags & FIEMAP_EXTENT_LAST)
1970                                 do_fiemap = 0;
1971                 }
1972                 if (do_fiemap) {
1973                         fe = fm->fm_extents + fm->fm_mapped_extents -1;
1974                         fm->fm_start = fe->fe_logical + fe->fe_length;
1975                 } else
1976                         break;
1977         }
1978 exit_setup_sparse_fiemap:
1979         return (exit_sts);
1980 }
1981
1982 #if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1983 static int
1984 setup_sparse(struct archive_read_disk *a,
1985     struct archive_entry *entry, int *fd)
1986 {
1987         return setup_sparse_fiemap(a, entry, fd);
1988 }
1989 #endif
1990 #endif  /* defined(HAVE_LINUX_FIEMAP_H) */
1991
1992 #if defined(SEEK_HOLE) && defined(SEEK_DATA)
1993
1994 /*
1995  * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
1996  */
1997
1998 static int
1999 setup_sparse(struct archive_read_disk *a,
2000     struct archive_entry *entry, int *fd)
2001 {
2002         int64_t size;
2003         off_t initial_off;
2004         off_t off_s, off_e;
2005         int exit_sts = ARCHIVE_OK;
2006         int check_fully_sparse = 0;
2007
2008         if (archive_entry_filetype(entry) != AE_IFREG
2009             || archive_entry_size(entry) <= 0
2010             || archive_entry_hardlink(entry) != NULL)
2011                 return (ARCHIVE_OK);
2012
2013         /* Does filesystem support the reporting of hole ? */
2014         if (*fd < 0 && a->tree != NULL) {
2015                 const char *path;
2016
2017                 path = archive_entry_sourcepath(entry);
2018                 if (path == NULL)
2019                         path = archive_entry_pathname(entry);
2020                 *fd = a->open_on_current_dir(a->tree, path,
2021                                 O_RDONLY | O_NONBLOCK);
2022                 if (*fd < 0) {
2023                         archive_set_error(&a->archive, errno,
2024                             "Can't open `%s'", path);
2025                         return (ARCHIVE_FAILED);
2026                 }
2027         }
2028
2029         if (*fd >= 0) {
2030 #ifdef _PC_MIN_HOLE_SIZE
2031                 if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
2032                         return (ARCHIVE_OK);
2033 #endif
2034                 initial_off = lseek(*fd, 0, SEEK_CUR);
2035                 if (initial_off != 0)
2036                         lseek(*fd, 0, SEEK_SET);
2037         } else {
2038                 const char *path;
2039
2040                 path = archive_entry_sourcepath(entry);
2041                 if (path == NULL)
2042                         path = archive_entry_pathname(entry);
2043                         
2044 #ifdef _PC_MIN_HOLE_SIZE
2045                 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
2046                         return (ARCHIVE_OK);
2047 #endif
2048                 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
2049                 if (*fd < 0) {
2050                         archive_set_error(&a->archive, errno,
2051                             "Can't open `%s'", path);
2052                         return (ARCHIVE_FAILED);
2053                 }
2054                 __archive_ensure_cloexec_flag(*fd);
2055                 initial_off = 0;
2056         }
2057
2058 #ifndef _PC_MIN_HOLE_SIZE
2059         /* Check if the underlying filesystem supports seek hole */
2060         off_s = lseek(*fd, 0, SEEK_HOLE);
2061         if (off_s < 0)
2062 #if defined(HAVE_LINUX_FIEMAP_H)
2063                 return setup_sparse_fiemap(a, entry, fd);
2064 #else
2065                 goto exit_setup_sparse;
2066 #endif
2067         else if (off_s > 0)
2068                 lseek(*fd, 0, SEEK_SET);
2069 #endif
2070
2071         off_s = 0;
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) {
2077                                 /* no more hole */
2078                                 if (archive_entry_sparse_count(entry) == 0) {
2079                                         /* Potentially a fully-sparse file. */
2080                                         check_fully_sparse = 1;
2081                                 }
2082                                 break;
2083                         }
2084                         archive_set_error(&a->archive, errno,
2085                             "lseek(SEEK_HOLE) failed");
2086                         exit_sts = ARCHIVE_FAILED;
2087                         goto exit_setup_sparse;
2088                 }
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 */
2095                         }
2096                         archive_set_error(&a->archive, errno,
2097                             "lseek(SEEK_DATA) failed");
2098                         exit_sts = ARCHIVE_FAILED;
2099                         goto exit_setup_sparse;
2100                 }
2101                 if (off_s == 0 && off_e == size)
2102                         break;/* This is not sparse. */
2103                 archive_entry_sparse_add_entry(entry, off_s,
2104                         off_e - off_s);
2105                 off_s = off_e;
2106         }
2107
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);
2113                 }
2114         }
2115 exit_setup_sparse:
2116         lseek(*fd, initial_off, SEEK_SET);
2117         return (exit_sts);
2118 }
2119
2120 #elif !defined(HAVE_LINUX_FIEMAP_H)
2121
2122 /*
2123  * Generic (stub) sparse support.
2124  */
2125 static int
2126 setup_sparse(struct archive_read_disk *a,
2127     struct archive_entry *entry, int *fd)
2128 {
2129         (void)a;     /* UNUSED */
2130         (void)entry; /* UNUSED */
2131         (void)fd;    /* UNUSED */
2132         return (ARCHIVE_OK);
2133 }
2134
2135 #endif
2136
2137 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */
2138