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