Imported Upstream version 3.3.1
[platform/upstream/libarchive.git] / 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: head/lib/libarchive/archive_read_disk_entry_from_file.c 201084 2009-12-28 02:14:09Z kientzle $");
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_SUN_ACL
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
133 #endif
134
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);
146 #endif
147
148 int
149 archive_read_disk_entry_from_file(struct archive *_a,
150     struct archive_entry *entry,
151     int fd,
152     const struct stat *st)
153 {
154         struct archive_read_disk *a = (struct archive_read_disk *)_a;
155         const char *path, *name;
156         struct stat s;
157         int initial_fd = fd;
158         int r, r1;
159
160         archive_clear_error(_a);
161         path = archive_entry_sourcepath(entry);
162         if (path == NULL)
163                 path = archive_entry_pathname(entry);
164
165         if (a->tree == NULL) {
166                 if (st == NULL) {
167 #if HAVE_FSTAT
168                         if (fd >= 0) {
169                                 if (fstat(fd, &s) != 0) {
170                                         archive_set_error(&a->archive, errno,
171                                             "Can't fstat");
172                                         return (ARCHIVE_FAILED);
173                                 }
174                         } else
175 #endif
176 #if HAVE_LSTAT
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);
182                                 }
183                         } else
184 #endif
185                         if (stat(path, &s) != 0) {
186                                 archive_set_error(&a->archive, errno,
187                                     "Can't stat %s", path);
188                                 return (ARCHIVE_FAILED);
189                         }
190                         st = &s;
191                 }
192                 archive_entry_copy_stat(entry, st);
193         }
194
195         /* Lookup uname/gname */
196         name = archive_read_disk_uname(_a, archive_entry_uid(entry));
197         if (name != NULL)
198                 archive_entry_copy_uname(entry, name);
199         name = archive_read_disk_gname(_a, archive_entry_gid(entry));
200         if (name != NULL)
201                 archive_entry_copy_gname(entry, name);
202
203 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
204         /* On FreeBSD, we get flags for free with the stat. */
205         /* TODO: Does this belong in copy_stat()? */
206         if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)
207                 archive_entry_set_fflags(entry, st->st_flags, 0);
208 #endif
209
210 #if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
211     (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
212         /* Linux requires an extra ioctl to pull the flags.  Although
213          * this is an extra step, it has a nice side-effect: We get an
214          * open file descriptor which we can use in the subsequent lookups. */
215         if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&
216             (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
217                 if (fd < 0) {
218                         if (a->tree != NULL)
219                                 fd = a->open_on_current_dir(a->tree, path,
220                                         O_RDONLY | O_NONBLOCK | O_CLOEXEC);
221                         else
222                                 fd = open(path, O_RDONLY | O_NONBLOCK |
223                                                 O_CLOEXEC);
224                         __archive_ensure_cloexec_flag(fd);
225                 }
226                 if (fd >= 0) {
227                         int stflags;
228                         r = ioctl(fd,
229 #if defined(FS_IOC_GETFLAGS)
230                             FS_IOC_GETFLAGS,
231 #else
232                             EXT2_IOC_GETFLAGS,
233 #endif
234                             &stflags);
235                         if (r == 0 && stflags != 0)
236                                 archive_entry_set_fflags(entry, stflags, 0);
237                 }
238         }
239 #endif
240
241 #if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
242         if (S_ISLNK(st->st_mode)) {
243                 size_t linkbuffer_len = st->st_size + 1;
244                 char *linkbuffer;
245                 int lnklen;
246
247                 linkbuffer = malloc(linkbuffer_len);
248                 if (linkbuffer == NULL) {
249                         archive_set_error(&a->archive, ENOMEM,
250                             "Couldn't read link data");
251                         return (ARCHIVE_FAILED);
252                 }
253                 if (a->tree != NULL) {
254 #ifdef HAVE_READLINKAT
255                         lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
256                             path, linkbuffer, linkbuffer_len);
257 #else
258                         if (a->tree_enter_working_dir(a->tree) != 0) {
259                                 archive_set_error(&a->archive, errno,
260                                     "Couldn't read link data");
261                                 free(linkbuffer);
262                                 return (ARCHIVE_FAILED);
263                         }
264                         lnklen = readlink(path, linkbuffer, linkbuffer_len);
265 #endif /* HAVE_READLINKAT */
266                 } else
267                         lnklen = readlink(path, linkbuffer, linkbuffer_len);
268                 if (lnklen < 0) {
269                         archive_set_error(&a->archive, errno,
270                             "Couldn't read link data");
271                         free(linkbuffer);
272                         return (ARCHIVE_FAILED);
273                 }
274                 linkbuffer[lnklen] = 0;
275                 archive_entry_set_symlink(entry, linkbuffer);
276                 free(linkbuffer);
277         }
278 #endif /* HAVE_READLINK || HAVE_READLINKAT */
279
280         r = 0;
281         if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
282                 r = setup_acls(a, entry, &fd);
283         if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
284                 r1 = setup_xattrs(a, entry, &fd);
285                 if (r1 < r)
286                         r = r1;
287         }
288         if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
289                 r1 = setup_mac_metadata(a, entry, &fd);
290                 if (r1 < r)
291                         r = r1;
292         }
293         r1 = setup_sparse(a, entry, &fd);
294         if (r1 < r)
295                 r = r1;
296
297         /* If we opened the file earlier in this function, close it. */
298         if (initial_fd != fd)
299                 close(fd);
300         return (r);
301 }
302
303 #if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
304 /*
305  * The Mac OS "copyfile()" API copies the extended metadata for a
306  * file into a separate file in AppleDouble format (see RFC 1740).
307  *
308  * Mac OS tar and cpio implementations store this extended
309  * metadata as a separate entry just before the regular entry
310  * with a "._" prefix added to the filename.
311  *
312  * Note that this is currently done unconditionally; the tar program has
313  * an option to discard this information before the archive is written.
314  *
315  * TODO: If there's a failure, report it and return ARCHIVE_WARN.
316  */
317 static int
318 setup_mac_metadata(struct archive_read_disk *a,
319     struct archive_entry *entry, int *fd)
320 {
321         int tempfd = -1;
322         int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
323         struct stat copyfile_stat;
324         int ret = ARCHIVE_OK;
325         void *buff = NULL;
326         int have_attrs;
327         const char *name, *tempdir;
328         struct archive_string tempfile;
329
330         (void)fd; /* UNUSED */
331         name = archive_entry_sourcepath(entry);
332         if (name == NULL)
333                 name = archive_entry_pathname(entry);
334         else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) {
335                 archive_set_error(&a->archive, errno,
336                             "Can't change dir to read extended attributes");
337                         return (ARCHIVE_FAILED);
338         }
339         if (name == NULL) {
340                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
341                     "Can't open file to read extended attributes: No name");
342                 return (ARCHIVE_WARN);
343         }
344
345         /* Short-circuit if there's nothing to do. */
346         have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
347         if (have_attrs == -1) {
348                 archive_set_error(&a->archive, errno,
349                         "Could not check extended attributes");
350                 return (ARCHIVE_WARN);
351         }
352         if (have_attrs == 0)
353                 return (ARCHIVE_OK);
354
355         tempdir = NULL;
356         if (issetugid() == 0)
357                 tempdir = getenv("TMPDIR");
358         if (tempdir == NULL)
359                 tempdir = _PATH_TMP;
360         archive_string_init(&tempfile);
361         archive_strcpy(&tempfile, tempdir);
362         archive_strcat(&tempfile, "tar.md.XXXXXX");
363         tempfd = mkstemp(tempfile.s);
364         if (tempfd < 0) {
365                 archive_set_error(&a->archive, errno,
366                     "Could not open extended attribute file");
367                 ret = ARCHIVE_WARN;
368                 goto cleanup;
369         }
370         __archive_ensure_cloexec_flag(tempfd);
371
372         /* XXX I wish copyfile() could pack directly to a memory
373          * buffer; that would avoid the temp file here.  For that
374          * matter, it would be nice if fcopyfile() actually worked,
375          * that would reduce the many open/close races here. */
376         if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
377                 archive_set_error(&a->archive, errno,
378                     "Could not pack extended attributes");
379                 ret = ARCHIVE_WARN;
380                 goto cleanup;
381         }
382         if (fstat(tempfd, &copyfile_stat)) {
383                 archive_set_error(&a->archive, errno,
384                     "Could not check size of extended attributes");
385                 ret = ARCHIVE_WARN;
386                 goto cleanup;
387         }
388         buff = malloc(copyfile_stat.st_size);
389         if (buff == NULL) {
390                 archive_set_error(&a->archive, errno,
391                     "Could not allocate memory for extended attributes");
392                 ret = ARCHIVE_WARN;
393                 goto cleanup;
394         }
395         if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
396                 archive_set_error(&a->archive, errno,
397                     "Could not read extended attributes into memory");
398                 ret = ARCHIVE_WARN;
399                 goto cleanup;
400         }
401         archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
402
403 cleanup:
404         if (tempfd >= 0) {
405                 close(tempfd);
406                 unlink(tempfile.s);
407         }
408         archive_string_free(&tempfile);
409         free(buff);
410         return (ret);
411 }
412
413 #else
414
415 /*
416  * Stub implementation for non-Mac systems.
417  */
418 static int
419 setup_mac_metadata(struct archive_read_disk *a,
420     struct archive_entry *entry, int *fd)
421 {
422         (void)a; /* UNUSED */
423         (void)entry; /* UNUSED */
424         (void)fd; /* UNUSED */
425         return (ARCHIVE_OK);
426 }
427 #endif
428
429 #if HAVE_DARWIN_ACL
430 static int translate_guid(struct archive *, acl_entry_t,
431     int *, int *, const char **);
432
433 static void add_trivial_nfs4_acl(struct archive_entry *);
434 #endif
435
436 #if HAVE_SUN_ACL
437 static int
438 sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
439 #endif
440
441 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
442 static int translate_acl(struct archive_read_disk *a,
443     struct archive_entry *entry,
444 #if HAVE_SUN_ACL
445     acl_t *acl,
446 #else
447     acl_t acl,
448 #endif
449     int archive_entry_acl_type);
450
451 static int
452 setup_acls(struct archive_read_disk *a,
453     struct archive_entry *entry, int *fd)
454 {
455         const char      *accpath;
456 #if HAVE_SUN_ACL
457         acl_t           *acl;
458 #else
459         acl_t           acl;
460 #endif
461         int             r;
462
463         accpath = NULL;
464
465 #if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP
466         if (*fd < 0)
467 #else
468         /* For default ACLs on Linux we need reachable accpath */
469         if (*fd < 0 || S_ISDIR(archive_entry_mode(entry)))
470 #endif
471         {
472                 accpath = archive_entry_sourcepath(entry);
473                 if (accpath == NULL || (a->tree != NULL &&
474                     a->tree_enter_working_dir(a->tree) != 0))
475                         accpath = archive_entry_pathname(entry);
476                 if (accpath == NULL) {
477                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
478                             "Couldn't determine file path to read ACLs");
479                         return (ARCHIVE_WARN);
480                 }
481                 if (a->tree != NULL &&
482 #if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP
483                     *fd < 0 &&
484 #endif
485                     (a->follow_symlinks ||
486                     archive_entry_filetype(entry) != AE_IFLNK)) {
487                         *fd = a->open_on_current_dir(a->tree,
488                             accpath, O_RDONLY | O_NONBLOCK);
489                 }
490         }
491
492         archive_entry_acl_clear(entry);
493
494         acl = NULL;
495
496 #if HAVE_NFS4_ACL
497         /* Try NFSv4 ACL first. */
498         if (*fd >= 0)
499 #if HAVE_SUN_ACL
500                 /* Solaris reads both POSIX.1e and NFSv4 ACL here */
501                 facl_get(*fd, 0, &acl);
502 #elif HAVE_ACL_GET_FD_NP
503                 acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
504 #else
505                 acl = acl_get_fd(*fd);
506 #endif
507 #if HAVE_ACL_GET_LINK_NP
508         else if (!a->follow_symlinks)
509                 acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
510 #else
511         else if ((!a->follow_symlinks)
512             && (archive_entry_filetype(entry) == AE_IFLNK))
513                 /* We can't get the ACL of a symlink, so we assume it can't
514                    have one. */
515                 acl = NULL;
516 #endif
517         else
518 #if HAVE_SUN_ACL
519                 /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
520                 acl_get(accpath, 0, &acl);
521 #else
522                 acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
523 #endif
524
525
526 #if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL
527         /* Ignore "trivial" ACLs that just mirror the file mode. */
528         if (acl != NULL) {
529 #if HAVE_SUN_ACL
530                 if (sun_acl_is_trivial(acl, archive_entry_mode(entry),
531                     &r) == 0 && r == 1)
532 #elif HAVE_ACL_IS_TRIVIAL_NP
533                 if (acl_is_trivial_np(acl, &r) == 0 && r == 1)
534 #endif
535                 {
536                         acl_free(acl);
537                         acl = NULL;
538                         /*
539                          * Simultaneous NFSv4 and POSIX.1e ACLs for the same
540                          * entry are not allowed, so we should return here
541                          */
542                         return (ARCHIVE_OK);
543                 }
544         }
545 #endif  /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */
546         if (acl != NULL) {
547                 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
548                 acl_free(acl);
549                 if (r != ARCHIVE_OK) {
550                         archive_set_error(&a->archive, errno,
551                             "Couldn't translate "
552 #if !HAVE_SUN_ACL
553                             "NFSv4 "
554 #endif
555                             "ACLs");
556                 }
557 #if HAVE_DARWIN_ACL
558                 /*
559                  * Because Mac OS doesn't support owner@, group@ and everyone@
560                  * ACLs we need to add NFSv4 ACLs mirroring the file mode to
561                  * the archive entry. Otherwise extraction on non-Mac platforms
562                  * would lead to an invalid file mode.
563                  */
564                 if ((archive_entry_acl_types(entry) &
565                     ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
566                         add_trivial_nfs4_acl(entry);
567 #endif
568                 return (r);
569         }
570 #endif  /* HAVE_NFS4_ACL */
571
572 #if HAVE_POSIX_ACL
573         /* This code path is skipped on MacOS and Solaris */
574
575         /* Retrieve access ACL from file. */
576         if (*fd >= 0)
577                 acl = acl_get_fd(*fd);
578 #if HAVE_ACL_GET_LINK_NP
579         else if (!a->follow_symlinks)
580                 acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
581 #else
582         else if ((!a->follow_symlinks)
583             && (archive_entry_filetype(entry) == AE_IFLNK))
584                 /* We can't get the ACL of a symlink, so we assume it can't
585                    have one. */
586                 acl = NULL;
587 #endif
588         else
589                 acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
590
591 #if HAVE_ACL_IS_TRIVIAL_NP
592         /* Ignore "trivial" ACLs that just mirror the file mode. */
593         if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
594                 if (r) {
595                         acl_free(acl);
596                         acl = NULL;
597                 }
598         }
599 #endif
600
601         if (acl != NULL) {
602                 r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
603                 acl_free(acl);
604                 acl = NULL;
605                 if (r != ARCHIVE_OK) {
606                         archive_set_error(&a->archive, errno,
607                             "Couldn't translate access ACLs");
608                         return (r);
609                 }
610         }
611
612         /* Only directories can have default ACLs. */
613         if (S_ISDIR(archive_entry_mode(entry))) {
614 #if HAVE_ACL_GET_FD_NP
615                 if (*fd >= 0)
616                         acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
617                 else
618 #endif
619                 acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
620                 if (acl != NULL) {
621                         r = translate_acl(a, entry, acl,
622                             ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
623                         acl_free(acl);
624                         if (r != ARCHIVE_OK) {
625                                 archive_set_error(&a->archive, errno,
626                                     "Couldn't translate default ACLs");
627                                 return (r);
628                         }
629                 }
630         }
631 #endif  /* HAVE_POSIX_ACL */
632         return (ARCHIVE_OK);
633 }
634
635 /*
636  * Translate system ACL permissions into libarchive internal structure
637  */
638 static const struct {
639         const int archive_perm;
640         const int platform_perm;
641 } acl_perm_map[] = {
642 #if HAVE_SUN_ACL        /* Solaris NFSv4 ACL permissions */
643         {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
644         {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
645         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
646         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
647         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
648         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
649         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
650         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
651         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
652         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
653         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
654         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
655         {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
656         {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
657         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
658         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
659         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
660 #elif HAVE_DARWIN_ACL   /* MacOS ACL permissions */
661         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
662         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
663         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
664         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
665         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
666         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
667         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
668         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
669         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
670         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
671         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
672         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
673         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
674         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
675         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
676         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
677         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
678 #else   /* POSIX.1e ACL permissions */
679         {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
680         {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
681         {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
682 #if HAVE_ACL_TYPE_NFS4  /* FreeBSD NFSv4 ACL permissions */
683         {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
684         {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
685         {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
686         {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
687         {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
688         {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
689         {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
690         {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
691         {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
692         {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
693         {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
694         {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
695         {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
696         {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
697         {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
698         {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
699 #endif
700 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
701 };
702
703 #if HAVE_NFS4_ACL
704 /*
705  * Translate system NFSv4 inheritance flags into libarchive internal structure
706  */
707 static const struct {
708         const int archive_inherit;
709         const int platform_inherit;
710 } acl_inherit_map[] = {
711 #if HAVE_SUN_ACL        /* Solaris ACL inheritance flags */
712         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
713         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
714         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
715         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
716         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
717         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
718         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
719 #elif HAVE_DARWIN_ACL   /* MacOS NFSv4 inheritance flags */
720         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
721         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
722         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
723         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
724         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
725 #else   /* FreeBSD NFSv4 ACL inheritance flags */
726         {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
727         {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
728         {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
729         {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
730         {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
731         {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
732         {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
733 #endif  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
734 };
735 #endif  /* HAVE_NFS4_ACL */
736
737 #if HAVE_DARWIN_ACL
738 static int translate_guid(struct archive *a, acl_entry_t acl_entry,
739     int *ae_id, int *ae_tag, const char **ae_name)
740 {
741         void *q;
742         uid_t ugid;
743         int r, idtype;
744         struct passwd *pwd;
745         struct group *grp;
746
747         q = acl_get_qualifier(acl_entry);
748         if (q == NULL)
749                 return (1);
750         r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
751         if (r != 0) {
752                 acl_free(q);
753                 return (1);
754         }
755         if (idtype == ID_TYPE_UID) {
756                 *ae_tag = ARCHIVE_ENTRY_ACL_USER;
757                 pwd = getpwuuid(q);
758                 if (pwd == NULL) {
759                         *ae_id = ugid;
760                         *ae_name = NULL;
761                 } else {
762                         *ae_id = pwd->pw_uid;
763                         *ae_name = archive_read_disk_uname(a, *ae_id);
764                 }
765         } else if (idtype == ID_TYPE_GID) {
766                 *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
767                 grp = getgruuid(q);
768                 if (grp == NULL) {
769                         *ae_id = ugid;
770                         *ae_name = NULL;
771                 } else {
772                         *ae_id = grp->gr_gid;
773                         *ae_name = archive_read_disk_gname(a, *ae_id);
774                 }
775         } else
776                 r = 1;
777
778         acl_free(q);
779         return (r);
780 }
781
782 /*
783  * Add trivial NFSv4 ACL entries from mode
784  */
785 static void
786 add_trivial_nfs4_acl(struct archive_entry *entry)
787 {
788         mode_t mode;
789         int i;
790         const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
791         const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
792             ARCHIVE_ENTRY_ACL_APPEND_DATA;
793         const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
794         const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
795             ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
796             ARCHIVE_ENTRY_ACL_READ_ACL |
797             ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
798         const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
799             ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
800             ARCHIVE_ENTRY_ACL_WRITE_ACL |
801             ARCHIVE_ENTRY_ACL_WRITE_OWNER;
802
803         struct {
804             const int type;
805             const int tag;
806             int permset;
807         } tacl_entry[] = {
808             {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
809             {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
810             {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
811             {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
812             {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
813             {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
814         };
815
816         mode = archive_entry_mode(entry);
817
818         /* Permissions for everyone@ */
819         if (mode & 0004)
820                 tacl_entry[5].permset |= rperm;
821         if (mode & 0002)
822                 tacl_entry[5].permset |= wperm;
823         if (mode & 0001)
824                 tacl_entry[5].permset |= eperm;
825
826         /* Permissions for group@ */
827         if (mode & 0040)
828                 tacl_entry[4].permset |= rperm;
829         else if (mode & 0004)
830                 tacl_entry[2].permset |= rperm;
831         if (mode & 0020)
832                 tacl_entry[4].permset |= wperm;
833         else if (mode & 0002)
834                 tacl_entry[2].permset |= wperm;
835         if (mode & 0010)
836                 tacl_entry[4].permset |= eperm;
837         else if (mode & 0001)
838                 tacl_entry[2].permset |= eperm;
839
840         /* Permissions for owner@ */
841         if (mode & 0400) {
842                 tacl_entry[3].permset |= rperm;
843                 if (!(mode & 0040) && (mode & 0004))
844                         tacl_entry[0].permset |= rperm;
845         } else if ((mode & 0040) || (mode & 0004))
846                 tacl_entry[1].permset |= rperm;
847         if (mode & 0200) {
848                 tacl_entry[3].permset |= wperm;
849                 if (!(mode & 0020) && (mode & 0002))
850                         tacl_entry[0].permset |= wperm;
851         } else if ((mode & 0020) || (mode & 0002))
852                 tacl_entry[1].permset |= wperm;
853         if (mode & 0100) {
854                 tacl_entry[3].permset |= eperm;
855                 if (!(mode & 0010) && (mode & 0001))
856                         tacl_entry[0].permset |= eperm;
857         } else if ((mode & 0010) || (mode & 0001))
858                 tacl_entry[1].permset |= eperm;
859
860         for (i = 0; i < 6; i++) {
861                 if (tacl_entry[i].permset != 0) {
862                         archive_entry_acl_add_entry(entry,
863                             tacl_entry[i].type, tacl_entry[i].permset,
864                             tacl_entry[i].tag, -1, NULL);
865                 }
866         }
867
868         return;
869 }
870 #elif HAVE_SUN_ACL
871 /*
872  * Check if acl is trivial
873  * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
874  */
875 static int
876 sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
877 {
878         int i, p;
879         const uint32_t rperm = ACE_READ_DATA;
880         const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
881         const uint32_t eperm = ACE_EXECUTE;
882         const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
883             ACE_READ_ACL | ACE_SYNCHRONIZE;
884         const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
885             ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
886
887         ace_t *ace;
888         ace_t tace[6];
889
890         if (acl == NULL || trivialp == NULL)
891                 return (-1);
892
893         *trivialp = 0;
894
895         /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */
896         if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0)
897                 return (0);
898
899         /*
900          * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
901          * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
902          * including mask.
903          */
904         if (acl->acl_type == ACLENT_T) {
905                 if (acl->acl_cnt == 4)
906                         *trivialp = 1;
907                 return (0);
908         }
909
910         if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
911                 return (-1);
912
913         /*
914          * Continue with checking NFSv4 ACLs
915          *
916          * Create list of trivial ace's to be compared
917          */
918
919         /* owner@ allow pre */
920         tace[0].a_flags = ACE_OWNER;
921         tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
922         tace[0].a_access_mask = 0;
923
924         /* owner@ deny */
925         tace[1].a_flags = ACE_OWNER;
926         tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
927         tace[1].a_access_mask = 0;
928
929         /* group@ deny */
930         tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
931         tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
932         tace[2].a_access_mask = 0;
933
934         /* owner@ allow */
935         tace[3].a_flags = ACE_OWNER;
936         tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
937         tace[3].a_access_mask = ownset;
938
939         /* group@ allow */
940         tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
941         tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
942         tace[4].a_access_mask = pubset;
943
944         /* everyone@ allow */
945         tace[5].a_flags = ACE_EVERYONE;
946         tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
947         tace[5].a_access_mask = pubset;
948
949         /* Permissions for everyone@ */
950         if (mode & 0004)
951                 tace[5].a_access_mask |= rperm;
952         if (mode & 0002)
953                 tace[5].a_access_mask |= wperm;
954         if (mode & 0001)
955                 tace[5].a_access_mask |= eperm;
956
957         /* Permissions for group@ */
958         if (mode & 0040)
959                 tace[4].a_access_mask |= rperm;
960         else if (mode & 0004)
961                 tace[2].a_access_mask |= rperm;
962         if (mode & 0020)
963                 tace[4].a_access_mask |= wperm;
964         else if (mode & 0002)
965                 tace[2].a_access_mask |= wperm;
966         if (mode & 0010)
967                 tace[4].a_access_mask |= eperm;
968         else if (mode & 0001)
969                 tace[2].a_access_mask |= eperm;
970
971         /* Permissions for owner@ */
972         if (mode & 0400) {
973                 tace[3].a_access_mask |= rperm;
974                 if (!(mode & 0040) && (mode & 0004))
975                         tace[0].a_access_mask |= rperm;
976         } else if ((mode & 0040) || (mode & 0004))
977                 tace[1].a_access_mask |= rperm;
978         if (mode & 0200) {
979                 tace[3].a_access_mask |= wperm;
980                 if (!(mode & 0020) && (mode & 0002))
981                         tace[0].a_access_mask |= wperm;
982         } else if ((mode & 0020) || (mode & 0002))
983                 tace[1].a_access_mask |= wperm;
984         if (mode & 0100) {
985                 tace[3].a_access_mask |= eperm;
986                 if (!(mode & 0010) && (mode & 0001))
987                         tace[0].a_access_mask |= eperm;
988         } else if ((mode & 0010) || (mode & 0001))
989                 tace[1].a_access_mask |= eperm;
990
991         /* Check if the acl count matches */
992         p = 3;
993         for (i = 0; i < 3; i++) {
994                 if (tace[i].a_access_mask != 0)
995                         p++;
996         }
997         if (acl->acl_cnt != p)
998                 return (0);
999
1000         p = 0;
1001         for (i = 0; i < 6; i++) {
1002                 if (tace[i].a_access_mask != 0) {
1003                         ace = &((ace_t *)acl->acl_aclp)[p];
1004                         /*
1005                          * Illumos added ACE_DELETE_CHILD to write perms for
1006                          * directories. We have to check against that, too.
1007                          */
1008                         if (ace->a_flags != tace[i].a_flags ||
1009                             ace->a_type != tace[i].a_type ||
1010                             (ace->a_access_mask != tace[i].a_access_mask &&
1011                             ((acl->acl_flags & ACL_IS_DIR) == 0 ||
1012                             (tace[i].a_access_mask & wperm) == 0 ||
1013                             ace->a_access_mask !=
1014                             (tace[i].a_access_mask | ACE_DELETE_CHILD))))
1015                                 return (0);
1016                         p++;
1017                 }
1018         }
1019
1020         *trivialp = 1;
1021         return (0);
1022 }
1023 #endif  /* HAVE_SUN_ACL */
1024
1025 #if HAVE_SUN_ACL
1026 /*
1027  * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
1028  */
1029 static int
1030 translate_acl(struct archive_read_disk *a,
1031     struct archive_entry *entry, acl_t *acl, int default_entry_acl_type)
1032 {
1033         int e, i;
1034         int ae_id, ae_tag, ae_perm;
1035         int entry_acl_type;
1036         const char *ae_name;
1037         aclent_t *aclent;
1038         ace_t *ace;
1039
1040         (void)default_entry_acl_type;
1041
1042         if (acl->acl_cnt <= 0)
1043                 return (ARCHIVE_OK);
1044
1045         for (e = 0; e < acl->acl_cnt; e++) {
1046                 ae_name = NULL;
1047                 ae_tag = 0;
1048                 ae_perm = 0;
1049
1050                 if (acl->acl_type == ACE_T) {
1051                         ace = &((ace_t *)acl->acl_aclp)[e];
1052                         ae_id = ace->a_who;
1053
1054                         switch(ace->a_type) {
1055                         case ACE_ACCESS_ALLOWED_ACE_TYPE:
1056                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1057                                 break;
1058                         case ACE_ACCESS_DENIED_ACE_TYPE:
1059                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1060                                 break;
1061                         case ACE_SYSTEM_AUDIT_ACE_TYPE:
1062                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1063                                 break;
1064                         case ACE_SYSTEM_ALARM_ACE_TYPE:
1065                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1066                                 break;
1067                         default:
1068                                 /* Unknown entry type, skip */
1069                                 continue;
1070                         }
1071
1072                         if ((ace->a_flags & ACE_OWNER) != 0)
1073                                 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1074                         else if ((ace->a_flags & ACE_GROUP) != 0)
1075                                 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1076                         else if ((ace->a_flags & ACE_EVERYONE) != 0)
1077                                 ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1078                         else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
1079                                 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1080                                 ae_name = archive_read_disk_gname(&a->archive,
1081                                     ae_id);
1082                         } else {
1083                                 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1084                                 ae_name = archive_read_disk_uname(&a->archive,
1085                                     ae_id);
1086                         }
1087
1088                         for (i = 0; i < (int)(sizeof(acl_inherit_map) /
1089                             sizeof(acl_inherit_map[0])); ++i) {
1090                                 if ((ace->a_flags &
1091                                     acl_inherit_map[i].platform_inherit) != 0)
1092                                         ae_perm |=
1093                                             acl_inherit_map[i].archive_inherit;
1094                         }
1095
1096                         for (i = 0; i < (int)(sizeof(acl_perm_map) /
1097                             sizeof(acl_perm_map[0])); ++i) {
1098                                 if ((ace->a_access_mask &
1099                                     acl_perm_map[i].platform_perm) != 0)
1100                                         ae_perm |=
1101                                             acl_perm_map[i].archive_perm;
1102                         }
1103                 } else {
1104                         aclent = &((aclent_t *)acl->acl_aclp)[e];
1105                         if ((aclent->a_type & ACL_DEFAULT) != 0)
1106                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
1107                         else
1108                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
1109                         ae_id = aclent->a_id;
1110
1111                         switch(aclent->a_type) {
1112                         case DEF_USER:
1113                         case USER:
1114                                 ae_name = archive_read_disk_uname(&a->archive,
1115                                     ae_id);
1116                                 ae_tag = ARCHIVE_ENTRY_ACL_USER;
1117                                 break;
1118                         case DEF_GROUP:
1119                         case GROUP:
1120                                 ae_name = archive_read_disk_gname(&a->archive,
1121                                     ae_id);
1122                                 ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1123                                 break;
1124                         case DEF_CLASS_OBJ:
1125                         case CLASS_OBJ:
1126                                 ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1127                                 break;
1128                         case DEF_USER_OBJ:
1129                         case USER_OBJ:
1130                                 ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1131                                 break;
1132                         case DEF_GROUP_OBJ:
1133                         case GROUP_OBJ:
1134                                 ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1135                                 break;
1136                         case DEF_OTHER_OBJ:
1137                         case OTHER_OBJ:
1138                                 ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1139                                 break;
1140                         default:
1141                                 /* Unknown tag type, skip */
1142                                 continue;
1143                         }
1144
1145                         if ((aclent->a_perm & 1) != 0)
1146                                 ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
1147                         if ((aclent->a_perm & 2) != 0)
1148                                 ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
1149                         if ((aclent->a_perm & 4) != 0)
1150                                 ae_perm |= ARCHIVE_ENTRY_ACL_READ;
1151                 } /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */
1152
1153                 archive_entry_acl_add_entry(entry, entry_acl_type,
1154                     ae_perm, ae_tag, ae_id, ae_name);
1155         }
1156         return (ARCHIVE_OK);
1157 }
1158 #else   /* !HAVE_SUN_ACL */
1159 /*
1160  * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
1161  * MacOS (NFSv4 only) ACLs into libarchive internal structure
1162  */
1163 static int
1164 translate_acl(struct archive_read_disk *a,
1165     struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
1166 {
1167         acl_tag_t        acl_tag;
1168 #if HAVE_ACL_TYPE_NFS4
1169         acl_entry_type_t acl_type;
1170         int brand;
1171 #endif
1172 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
1173         acl_flagset_t    acl_flagset;
1174 #endif
1175         acl_entry_t      acl_entry;
1176         acl_permset_t    acl_permset;
1177         int              i, entry_acl_type;
1178         int              r, s, ae_id, ae_tag, ae_perm;
1179 #if !HAVE_DARWIN_ACL
1180         void            *q;
1181 #endif
1182         const char      *ae_name;
1183
1184 #if HAVE_ACL_TYPE_NFS4
1185         // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
1186         // Make sure the "brand" on this ACL is consistent
1187         // with the default_entry_acl_type bits provided.
1188         if (acl_get_brand_np(acl, &brand) != 0) {
1189                 archive_set_error(&a->archive, errno,
1190                     "Failed to read ACL brand");
1191                 return (ARCHIVE_WARN);
1192         }
1193         switch (brand) {
1194         case ACL_BRAND_POSIX:
1195                 switch (default_entry_acl_type) {
1196                 case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
1197                 case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
1198                         break;
1199                 default:
1200                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1201                             "Invalid ACL entry type for POSIX.1e ACL");
1202                         return (ARCHIVE_WARN);
1203                 }
1204                 break;
1205         case ACL_BRAND_NFS4:
1206                 if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1207                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1208                             "Invalid ACL entry type for NFSv4 ACL");
1209                         return (ARCHIVE_WARN);
1210                 }
1211                 break;
1212         default:
1213                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1214                     "Unknown ACL brand");
1215                 return (ARCHIVE_WARN);
1216         }
1217 #endif
1218
1219         s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
1220         if (s == -1) {
1221                 archive_set_error(&a->archive, errno,
1222                     "Failed to get first ACL entry");
1223                 return (ARCHIVE_WARN);
1224         }
1225
1226 #if HAVE_DARWIN_ACL
1227         while (s == 0)
1228 #else   /* FreeBSD, Linux */
1229         while (s == 1)
1230 #endif
1231         {
1232                 ae_id = -1;
1233                 ae_name = NULL;
1234                 ae_perm = 0;
1235
1236                 if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
1237                         archive_set_error(&a->archive, errno,
1238                             "Failed to get ACL tag type");
1239                         return (ARCHIVE_WARN);
1240                 }
1241                 switch (acl_tag) {
1242 #if !HAVE_DARWIN_ACL    /* FreeBSD, Linux */
1243                 case ACL_USER:
1244                         q = acl_get_qualifier(acl_entry);
1245                         if (q != NULL) {
1246                                 ae_id = (int)*(uid_t *)q;
1247                                 acl_free(q);
1248                                 ae_name = archive_read_disk_uname(&a->archive,
1249                                     ae_id);
1250                         }
1251                         ae_tag = ARCHIVE_ENTRY_ACL_USER;
1252                         break;
1253                 case ACL_GROUP:
1254                         q = acl_get_qualifier(acl_entry);
1255                         if (q != NULL) {
1256                                 ae_id = (int)*(gid_t *)q;
1257                                 acl_free(q);
1258                                 ae_name = archive_read_disk_gname(&a->archive,
1259                                     ae_id);
1260                         }
1261                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
1262                         break;
1263                 case ACL_MASK:
1264                         ae_tag = ARCHIVE_ENTRY_ACL_MASK;
1265                         break;
1266                 case ACL_USER_OBJ:
1267                         ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
1268                         break;
1269                 case ACL_GROUP_OBJ:
1270                         ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
1271                         break;
1272                 case ACL_OTHER:
1273                         ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
1274                         break;
1275 #if HAVE_ACL_TYPE_NFS4
1276                 case ACL_EVERYONE:
1277                         ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
1278                         break;
1279 #endif
1280 #else   /* HAVE_DARWIN_ACL */
1281                 case ACL_EXTENDED_ALLOW:
1282                         entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1283                         r = translate_guid(&a->archive, acl_entry, &ae_id,
1284                             &ae_tag, &ae_name);
1285                         break;
1286                 case ACL_EXTENDED_DENY:
1287                         entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1288                         r = translate_guid(&a->archive, acl_entry, &ae_id,
1289                             &ae_tag, &ae_name);
1290                         break;
1291 #endif  /* HAVE_DARWIN_ACL */
1292                 default:
1293                         /* Skip types that libarchive can't support. */
1294                         s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1295                         continue;
1296                 }
1297
1298 #if HAVE_DARWIN_ACL
1299                 /* Skip if translate_guid() above failed */
1300                 if (r != 0) {
1301                         s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1302                         continue;
1303                 }
1304 #endif
1305
1306 #if !HAVE_DARWIN_ACL
1307                 // XXX acl_type maps to allow/deny/audit/YYYY bits
1308                 entry_acl_type = default_entry_acl_type;
1309 #endif
1310 #if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
1311                 if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
1312 #if HAVE_ACL_TYPE_NFS4
1313                         /*
1314                          * acl_get_entry_type_np() fails with non-NFSv4 ACLs
1315                          */
1316                         if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
1317                                 archive_set_error(&a->archive, errno, "Failed "
1318                                     "to get ACL type from a NFSv4 ACL entry");
1319                                 return (ARCHIVE_WARN);
1320                         }
1321                         switch (acl_type) {
1322                         case ACL_ENTRY_TYPE_ALLOW:
1323                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
1324                                 break;
1325                         case ACL_ENTRY_TYPE_DENY:
1326                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
1327                                 break;
1328                         case ACL_ENTRY_TYPE_AUDIT:
1329                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
1330                                 break;
1331                         case ACL_ENTRY_TYPE_ALARM:
1332                                 entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
1333                                 break;
1334                         default:
1335                                 archive_set_error(&a->archive, errno,
1336                                     "Invalid NFSv4 ACL entry type");
1337                                 return (ARCHIVE_WARN);
1338                         }
1339 #endif  /* HAVE_ACL_TYPE_NFS4 */
1340
1341                         /*
1342                          * Libarchive stores "flag" (NFSv4 inheritance bits)
1343                          * in the ae_perm bitmap.
1344                          *
1345                          * acl_get_flagset_np() fails with non-NFSv4 ACLs
1346                          */
1347                         if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
1348                                 archive_set_error(&a->archive, errno,
1349                                     "Failed to get flagset from a NFSv4 ACL entry");
1350                                 return (ARCHIVE_WARN);
1351                         }
1352                         for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
1353                                 r = acl_get_flag_np(acl_flagset,
1354                                     acl_inherit_map[i].platform_inherit);
1355                                 if (r == -1) {
1356                                         archive_set_error(&a->archive, errno,
1357                                             "Failed to check flag in a NFSv4 "
1358                                             "ACL flagset");
1359                                         return (ARCHIVE_WARN);
1360                                 } else if (r)
1361                                         ae_perm |= acl_inherit_map[i].archive_inherit;
1362                         }
1363                 }
1364 #endif  /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
1365
1366                 if (acl_get_permset(acl_entry, &acl_permset) != 0) {
1367                         archive_set_error(&a->archive, errno,
1368                             "Failed to get ACL permission set");
1369                         return (ARCHIVE_WARN);
1370                 }
1371                 for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
1372                         /*
1373                          * acl_get_perm() is spelled differently on different
1374                          * platforms; see above.
1375                          */
1376                         r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
1377                         if (r == -1) {
1378                                 archive_set_error(&a->archive, errno,
1379                                     "Failed to check permission in an ACL permission set");
1380                                 return (ARCHIVE_WARN);
1381                         } else if (r)
1382                                 ae_perm |= acl_perm_map[i].archive_perm;
1383                 }
1384
1385                 archive_entry_acl_add_entry(entry, entry_acl_type,
1386                                             ae_perm, ae_tag,
1387                                             ae_id, ae_name);
1388
1389                 s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
1390 #if !HAVE_DARWIN_ACL
1391                 if (s == -1) {
1392                         archive_set_error(&a->archive, errno,
1393                             "Failed to get next ACL entry");
1394                         return (ARCHIVE_WARN);
1395                 }
1396 #endif
1397         }
1398         return (ARCHIVE_OK);
1399 }
1400 #endif  /* !HAVE_SUN_ACL */
1401 #else   /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1402 static int
1403 setup_acls(struct archive_read_disk *a,
1404     struct archive_entry *entry, int *fd)
1405 {
1406         (void)a;      /* UNUSED */
1407         (void)entry;  /* UNUSED */
1408         (void)fd;     /* UNUSED */
1409         return (ARCHIVE_OK);
1410 }
1411 #endif  /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
1412
1413 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
1414     HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
1415     (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
1416
1417 /*
1418  * Linux and AIX extended attribute support.
1419  *
1420  * TODO:  By using a stack-allocated buffer for the first
1421  * call to getxattr(), we might be able to avoid the second
1422  * call entirely.  We only need the second call if the
1423  * stack-allocated buffer is too small.  But a modest buffer
1424  * of 1024 bytes or so will often be big enough.  Same applies
1425  * to listxattr().
1426  */
1427
1428
1429 static int
1430 setup_xattr(struct archive_read_disk *a,
1431     struct archive_entry *entry, const char *name, int fd, const char *accpath)
1432 {
1433         ssize_t size;
1434         void *value = NULL;
1435
1436 #if HAVE_FGETXATTR
1437         if (fd >= 0)
1438                 size = fgetxattr(fd, name, NULL, 0);
1439         else if (!a->follow_symlinks)
1440                 size = lgetxattr(accpath, name, NULL, 0);
1441         else
1442                 size = getxattr(accpath, name, NULL, 0);
1443 #elif HAVE_FGETEA
1444         if (fd >= 0)
1445                 size = fgetea(fd, name, NULL, 0);
1446         else if (!a->follow_symlinks)
1447                 size = lgetea(accpath, name, NULL, 0);
1448         else
1449                 size = getea(accpath, name, NULL, 0);
1450 #endif
1451
1452         if (size == -1) {
1453                 archive_set_error(&a->archive, errno,
1454                     "Couldn't query extended attribute");
1455                 return (ARCHIVE_WARN);
1456         }
1457
1458         if (size > 0 && (value = malloc(size)) == NULL) {
1459                 archive_set_error(&a->archive, errno, "Out of memory");
1460                 return (ARCHIVE_FATAL);
1461         }
1462
1463 #if HAVE_FGETXATTR
1464         if (fd >= 0)
1465                 size = fgetxattr(fd, name, value, size);
1466         else if (!a->follow_symlinks)
1467                 size = lgetxattr(accpath, name, value, size);
1468         else
1469                 size = getxattr(accpath, name, value, size);
1470 #elif HAVE_FGETEA
1471         if (fd >= 0)
1472                 size = fgetea(fd, name, value, size);
1473         else if (!a->follow_symlinks)
1474                 size = lgetea(accpath, name, value, size);
1475         else
1476                 size = getea(accpath, name, value, size);
1477 #endif
1478
1479         if (size == -1) {
1480                 archive_set_error(&a->archive, errno,
1481                     "Couldn't read extended attribute");
1482                 return (ARCHIVE_WARN);
1483         }
1484
1485         archive_entry_xattr_add_entry(entry, name, value, size);
1486
1487         free(value);
1488         return (ARCHIVE_OK);
1489 }
1490
1491 static int
1492 setup_xattrs(struct archive_read_disk *a,
1493     struct archive_entry *entry, int *fd)
1494 {
1495         char *list, *p;
1496         const char *path;
1497         ssize_t list_size;
1498
1499         path = NULL;
1500
1501         if (*fd < 0) {
1502                 path = archive_entry_sourcepath(entry);
1503                 if (path == NULL || (a->tree != NULL &&
1504                     a->tree_enter_working_dir(a->tree) != 0))
1505                         path = archive_entry_pathname(entry);
1506                 if (path == NULL) {
1507                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1508                             "Couldn't determine file path to read "
1509                             "extended attributes");
1510                         return (ARCHIVE_WARN);
1511                 }
1512                 if (a->tree != NULL && (a->follow_symlinks ||
1513                     archive_entry_filetype(entry) != AE_IFLNK)) {
1514                         *fd = a->open_on_current_dir(a->tree,
1515                             path, O_RDONLY | O_NONBLOCK);
1516                 }
1517         }
1518
1519 #if HAVE_FLISTXATTR
1520         if (*fd >= 0)
1521                 list_size = flistxattr(*fd, NULL, 0);
1522         else if (!a->follow_symlinks)
1523                 list_size = llistxattr(path, NULL, 0);
1524         else
1525                 list_size = listxattr(path, NULL, 0);
1526 #elif HAVE_FLISTEA
1527         if (*fd >= 0)
1528                 list_size = flistea(*fd, NULL, 0);
1529         else if (!a->follow_symlinks)
1530                 list_size = llistea(path, NULL, 0);
1531         else
1532                 list_size = listea(path, NULL, 0);
1533 #endif
1534
1535         if (list_size == -1) {
1536                 if (errno == ENOTSUP || errno == ENOSYS)
1537                         return (ARCHIVE_OK);
1538                 archive_set_error(&a->archive, errno,
1539                         "Couldn't list extended attributes");
1540                 return (ARCHIVE_WARN);
1541         }
1542
1543         if (list_size == 0)
1544                 return (ARCHIVE_OK);
1545
1546         if ((list = malloc(list_size)) == NULL) {
1547                 archive_set_error(&a->archive, errno, "Out of memory");
1548                 return (ARCHIVE_FATAL);
1549         }
1550
1551 #if HAVE_FLISTXATTR
1552         if (*fd >= 0)
1553                 list_size = flistxattr(*fd, list, list_size);
1554         else if (!a->follow_symlinks)
1555                 list_size = llistxattr(path, list, list_size);
1556         else
1557                 list_size = listxattr(path, list, list_size);
1558 #elif HAVE_FLISTEA
1559         if (*fd >= 0)
1560                 list_size = flistea(*fd, list, list_size);
1561         else if (!a->follow_symlinks)
1562                 list_size = llistea(path, list, list_size);
1563         else
1564                 list_size = listea(path, list, list_size);
1565 #endif
1566
1567         if (list_size == -1) {
1568                 archive_set_error(&a->archive, errno,
1569                         "Couldn't retrieve extended attributes");
1570                 free(list);
1571                 return (ARCHIVE_WARN);
1572         }
1573
1574         for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
1575                 if (strncmp(p, "system.", 7) == 0 ||
1576                                 strncmp(p, "xfsroot.", 8) == 0)
1577                         continue;
1578                 setup_xattr(a, entry, p, *fd, path);
1579         }
1580
1581         free(list);
1582         return (ARCHIVE_OK);
1583 }
1584
1585 #elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
1586     HAVE_DECL_EXTATTR_NAMESPACE_USER
1587
1588 /*
1589  * FreeBSD extattr interface.
1590  */
1591
1592 /* TODO: Implement this.  Follow the Linux model above, but
1593  * with FreeBSD-specific system calls, of course.  Be careful
1594  * to not include the system extattrs that hold ACLs; we handle
1595  * those separately.
1596  */
1597 static int
1598 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1599     int namespace, const char *name, const char *fullname, int fd,
1600     const char *path);
1601
1602 static int
1603 setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1604     int namespace, const char *name, const char *fullname, int fd,
1605     const char *accpath)
1606 {
1607         ssize_t size;
1608         void *value = NULL;
1609
1610         if (fd >= 0)
1611                 size = extattr_get_fd(fd, namespace, name, NULL, 0);
1612         else if (!a->follow_symlinks)
1613                 size = extattr_get_link(accpath, namespace, name, NULL, 0);
1614         else
1615                 size = extattr_get_file(accpath, namespace, name, NULL, 0);
1616
1617         if (size == -1) {
1618                 archive_set_error(&a->archive, errno,
1619                     "Couldn't query extended attribute");
1620                 return (ARCHIVE_WARN);
1621         }
1622
1623         if (size > 0 && (value = malloc(size)) == NULL) {
1624                 archive_set_error(&a->archive, errno, "Out of memory");
1625                 return (ARCHIVE_FATAL);
1626         }
1627
1628         if (fd >= 0)
1629                 size = extattr_get_fd(fd, namespace, name, value, size);
1630         else if (!a->follow_symlinks)
1631                 size = extattr_get_link(accpath, namespace, name, value, size);
1632         else
1633                 size = extattr_get_file(accpath, namespace, name, value, size);
1634
1635         if (size == -1) {
1636                 free(value);
1637                 archive_set_error(&a->archive, errno,
1638                     "Couldn't read extended attribute");
1639                 return (ARCHIVE_WARN);
1640         }
1641
1642         archive_entry_xattr_add_entry(entry, fullname, value, size);
1643
1644         free(value);
1645         return (ARCHIVE_OK);
1646 }
1647
1648 static int
1649 setup_xattrs(struct archive_read_disk *a,
1650     struct archive_entry *entry, int *fd)
1651 {
1652         char buff[512];
1653         char *list, *p;
1654         ssize_t list_size;
1655         const char *path;
1656         int namespace = EXTATTR_NAMESPACE_USER;
1657
1658         path = NULL;
1659
1660         if (*fd < 0) {
1661                 path = archive_entry_sourcepath(entry);
1662                 if (path == NULL || (a->tree != NULL &&
1663                     a->tree_enter_working_dir(a->tree) != 0))
1664                         path = archive_entry_pathname(entry);
1665                 if (path == NULL) {
1666                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
1667                             "Couldn't determine file path to read "
1668                             "extended attributes");
1669                         return (ARCHIVE_WARN);
1670                 }
1671                 if (a->tree != NULL && (a->follow_symlinks ||
1672                     archive_entry_filetype(entry) != AE_IFLNK)) {
1673                         *fd = a->open_on_current_dir(a->tree,
1674                             path, O_RDONLY | O_NONBLOCK);
1675                 }
1676         }
1677
1678         if (*fd >= 0)
1679                 list_size = extattr_list_fd(*fd, namespace, NULL, 0);
1680         else if (!a->follow_symlinks)
1681                 list_size = extattr_list_link(path, namespace, NULL, 0);
1682         else
1683                 list_size = extattr_list_file(path, namespace, NULL, 0);
1684
1685         if (list_size == -1 && errno == EOPNOTSUPP)
1686                 return (ARCHIVE_OK);
1687         if (list_size == -1) {
1688                 archive_set_error(&a->archive, errno,
1689                         "Couldn't list extended attributes");
1690                 return (ARCHIVE_WARN);
1691         }
1692
1693         if (list_size == 0)
1694                 return (ARCHIVE_OK);
1695
1696         if ((list = malloc(list_size)) == NULL) {
1697                 archive_set_error(&a->archive, errno, "Out of memory");
1698                 return (ARCHIVE_FATAL);
1699         }
1700
1701         if (*fd >= 0)
1702                 list_size = extattr_list_fd(*fd, namespace, list, list_size);
1703         else if (!a->follow_symlinks)
1704                 list_size = extattr_list_link(path, namespace, list, list_size);
1705         else
1706                 list_size = extattr_list_file(path, namespace, list, list_size);
1707
1708         if (list_size == -1) {
1709                 archive_set_error(&a->archive, errno,
1710                         "Couldn't retrieve extended attributes");
1711                 free(list);
1712                 return (ARCHIVE_WARN);
1713         }
1714
1715         p = list;
1716         while ((p - list) < list_size) {
1717                 size_t len = 255 & (int)*p;
1718                 char *name;
1719
1720                 strcpy(buff, "user.");
1721                 name = buff + strlen(buff);
1722                 memcpy(name, p + 1, len);
1723                 name[len] = '\0';
1724                 setup_xattr(a, entry, namespace, name, buff, *fd, path);
1725                 p += 1 + len;
1726         }
1727
1728         free(list);
1729         return (ARCHIVE_OK);
1730 }
1731
1732 #else
1733
1734 /*
1735  * Generic (stub) extended attribute support.
1736  */
1737 static int
1738 setup_xattrs(struct archive_read_disk *a,
1739     struct archive_entry *entry, int *fd)
1740 {
1741         (void)a;     /* UNUSED */
1742         (void)entry; /* UNUSED */
1743         (void)fd;    /* UNUSED */
1744         return (ARCHIVE_OK);
1745 }
1746
1747 #endif
1748
1749 #if defined(HAVE_LINUX_FIEMAP_H)
1750
1751 /*
1752  * Linux FIEMAP sparse interface.
1753  *
1754  * The FIEMAP ioctl returns an "extent" for each physical allocation
1755  * on disk.  We need to process those to generate a more compact list
1756  * of logical file blocks.  We also need to be very careful to use
1757  * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
1758  * does not report allocations for newly-written data that hasn't
1759  * been synced to disk.
1760  *
1761  * It's important to return a minimal sparse file list because we want
1762  * to not trigger sparse file extensions if we don't have to, since
1763  * not all readers support them.
1764  */
1765
1766 static int
1767 setup_sparse_fiemap(struct archive_read_disk *a,
1768     struct archive_entry *entry, int *fd)
1769 {
1770         char buff[4096];
1771         struct fiemap *fm;
1772         struct fiemap_extent *fe;
1773         int64_t size;
1774         int count, do_fiemap, iters;
1775         int exit_sts = ARCHIVE_OK;
1776
1777         if (archive_entry_filetype(entry) != AE_IFREG
1778             || archive_entry_size(entry) <= 0
1779             || archive_entry_hardlink(entry) != NULL)
1780                 return (ARCHIVE_OK);
1781
1782         if (*fd < 0) {
1783                 const char *path;
1784
1785                 path = archive_entry_sourcepath(entry);
1786                 if (path == NULL)
1787                         path = archive_entry_pathname(entry);
1788                 if (a->tree != NULL)
1789                         *fd = a->open_on_current_dir(a->tree, path,
1790                                 O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1791                 else
1792                         *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1793                 if (*fd < 0) {
1794                         archive_set_error(&a->archive, errno,
1795                             "Can't open `%s'", path);
1796                         return (ARCHIVE_FAILED);
1797                 }
1798                 __archive_ensure_cloexec_flag(*fd);
1799         }
1800
1801         /* Initialize buffer to avoid the error valgrind complains about. */
1802         memset(buff, 0, sizeof(buff));
1803         count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
1804         fm = (struct fiemap *)buff;
1805         fm->fm_start = 0;
1806         fm->fm_length = ~0ULL;;
1807         fm->fm_flags = FIEMAP_FLAG_SYNC;
1808         fm->fm_extent_count = count;
1809         do_fiemap = 1;
1810         size = archive_entry_size(entry);
1811         for (iters = 0; ; ++iters) {
1812                 int i, r;
1813
1814                 r = ioctl(*fd, FS_IOC_FIEMAP, fm); 
1815                 if (r < 0) {
1816                         /* When something error happens, it is better we
1817                          * should return ARCHIVE_OK because an earlier
1818                          * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
1819                         goto exit_setup_sparse_fiemap;
1820                 }
1821                 if (fm->fm_mapped_extents == 0) {
1822                         if (iters == 0) {
1823                                 /* Fully sparse file; insert a zero-length "data" entry */
1824                                 archive_entry_sparse_add_entry(entry, 0, 0);
1825                         }
1826                         break;
1827                 }
1828                 fe = fm->fm_extents;
1829                 for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
1830                         if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
1831                                 /* The fe_length of the last block does not
1832                                  * adjust itself to its size files. */
1833                                 int64_t length = fe->fe_length;
1834                                 if (fe->fe_logical + length > (uint64_t)size)
1835                                         length -= fe->fe_logical + length - size;
1836                                 if (fe->fe_logical == 0 && length == size) {
1837                                         /* This is not sparse. */
1838                                         do_fiemap = 0;
1839                                         break;
1840                                 }
1841                                 if (length > 0)
1842                                         archive_entry_sparse_add_entry(entry,
1843                                             fe->fe_logical, length);
1844                         }
1845                         if (fe->fe_flags & FIEMAP_EXTENT_LAST)
1846                                 do_fiemap = 0;
1847                 }
1848                 if (do_fiemap) {
1849                         fe = fm->fm_extents + fm->fm_mapped_extents -1;
1850                         fm->fm_start = fe->fe_logical + fe->fe_length;
1851                 } else
1852                         break;
1853         }
1854 exit_setup_sparse_fiemap:
1855         return (exit_sts);
1856 }
1857
1858 #if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1859 static int
1860 setup_sparse(struct archive_read_disk *a,
1861     struct archive_entry *entry, int *fd)
1862 {
1863         return setup_sparse_fiemap(a, entry, fd);
1864 }
1865 #endif
1866 #endif  /* defined(HAVE_LINUX_FIEMAP_H) */
1867
1868 #if defined(SEEK_HOLE) && defined(SEEK_DATA)
1869
1870 /*
1871  * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
1872  */
1873
1874 static int
1875 setup_sparse(struct archive_read_disk *a,
1876     struct archive_entry *entry, int *fd)
1877 {
1878         int64_t size;
1879         off_t initial_off;
1880         off_t off_s, off_e;
1881         int exit_sts = ARCHIVE_OK;
1882         int check_fully_sparse = 0;
1883
1884         if (archive_entry_filetype(entry) != AE_IFREG
1885             || archive_entry_size(entry) <= 0
1886             || archive_entry_hardlink(entry) != NULL)
1887                 return (ARCHIVE_OK);
1888
1889         /* Does filesystem support the reporting of hole ? */
1890         if (*fd < 0 && a->tree != NULL) {
1891                 const char *path;
1892
1893                 path = archive_entry_sourcepath(entry);
1894                 if (path == NULL)
1895                         path = archive_entry_pathname(entry);
1896                 *fd = a->open_on_current_dir(a->tree, path,
1897                                 O_RDONLY | O_NONBLOCK);
1898                 if (*fd < 0) {
1899                         archive_set_error(&a->archive, errno,
1900                             "Can't open `%s'", path);
1901                         return (ARCHIVE_FAILED);
1902                 }
1903         }
1904
1905         if (*fd >= 0) {
1906 #ifdef _PC_MIN_HOLE_SIZE
1907                 if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
1908                         return (ARCHIVE_OK);
1909 #endif
1910                 initial_off = lseek(*fd, 0, SEEK_CUR);
1911                 if (initial_off != 0)
1912                         lseek(*fd, 0, SEEK_SET);
1913         } else {
1914                 const char *path;
1915
1916                 path = archive_entry_sourcepath(entry);
1917                 if (path == NULL)
1918                         path = archive_entry_pathname(entry);
1919                         
1920 #ifdef _PC_MIN_HOLE_SIZE
1921                 if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
1922                         return (ARCHIVE_OK);
1923 #endif
1924                 *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1925                 if (*fd < 0) {
1926                         archive_set_error(&a->archive, errno,
1927                             "Can't open `%s'", path);
1928                         return (ARCHIVE_FAILED);
1929                 }
1930                 __archive_ensure_cloexec_flag(*fd);
1931                 initial_off = 0;
1932         }
1933
1934 #ifndef _PC_MIN_HOLE_SIZE
1935         /* Check if the underlying filesystem supports seek hole */
1936         off_s = lseek(*fd, 0, SEEK_HOLE);
1937         if (off_s < 0)
1938 #if defined(HAVE_LINUX_FIEMAP_H)
1939                 return setup_sparse_fiemap(a, entry, fd);
1940 #else
1941                 goto exit_setup_sparse;
1942 #endif
1943         else if (off_s > 0)
1944                 lseek(*fd, 0, SEEK_SET);
1945 #endif
1946
1947         off_s = 0;
1948         size = archive_entry_size(entry);
1949         while (off_s < size) {
1950                 off_s = lseek(*fd, off_s, SEEK_DATA);
1951                 if (off_s == (off_t)-1) {
1952                         if (errno == ENXIO) {
1953                                 /* no more hole */
1954                                 if (archive_entry_sparse_count(entry) == 0) {
1955                                         /* Potentially a fully-sparse file. */
1956                                         check_fully_sparse = 1;
1957                                 }
1958                                 break;
1959                         }
1960                         archive_set_error(&a->archive, errno,
1961                             "lseek(SEEK_HOLE) failed");
1962                         exit_sts = ARCHIVE_FAILED;
1963                         goto exit_setup_sparse;
1964                 }
1965                 off_e = lseek(*fd, off_s, SEEK_HOLE);
1966                 if (off_e == (off_t)-1) {
1967                         if (errno == ENXIO) {
1968                                 off_e = lseek(*fd, 0, SEEK_END);
1969                                 if (off_e != (off_t)-1)
1970                                         break;/* no more data */
1971                         }
1972                         archive_set_error(&a->archive, errno,
1973                             "lseek(SEEK_DATA) failed");
1974                         exit_sts = ARCHIVE_FAILED;
1975                         goto exit_setup_sparse;
1976                 }
1977                 if (off_s == 0 && off_e == size)
1978                         break;/* This is not sparse. */
1979                 archive_entry_sparse_add_entry(entry, off_s,
1980                         off_e - off_s);
1981                 off_s = off_e;
1982         }
1983
1984         if (check_fully_sparse) {
1985                 if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
1986                         lseek(*fd, 0, SEEK_END) == size) {
1987                         /* Fully sparse file; insert a zero-length "data" entry */
1988                         archive_entry_sparse_add_entry(entry, 0, 0);
1989                 }
1990         }
1991 exit_setup_sparse:
1992         lseek(*fd, initial_off, SEEK_SET);
1993         return (exit_sts);
1994 }
1995
1996 #elif !defined(HAVE_LINUX_FIEMAP_H)
1997
1998 /*
1999  * Generic (stub) sparse support.
2000  */
2001 static int
2002 setup_sparse(struct archive_read_disk *a,
2003     struct archive_entry *entry, int *fd)
2004 {
2005         (void)a;     /* UNUSED */
2006         (void)entry; /* UNUSED */
2007         (void)fd;    /* UNUSED */
2008         return (ARCHIVE_OK);
2009 }
2010
2011 #endif
2012
2013 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */
2014