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