archive_read_disk_entry_from_file.c revision 313926
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 313926 2017-02-18 21:58:56Z 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_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
135static int setup_acls(struct archive_read_disk *,
136    struct archive_entry *, int *fd);
137static int setup_mac_metadata(struct archive_read_disk *,
138    struct archive_entry *, int *fd);
139static int setup_xattrs(struct archive_read_disk *,
140    struct archive_entry *, int *fd);
141static int setup_sparse(struct archive_read_disk *,
142    struct archive_entry *, int *fd);
143#if defined(HAVE_LINUX_FIEMAP_H)
144static int setup_sparse_fiemap(struct archive_read_disk *,
145    struct archive_entry *, int *fd);
146#endif
147
148int
149archive_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 */
307static int
308setup_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
396cleanup:
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 */
411static int
412setup_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
423static int translate_guid(struct archive *, acl_entry_t,
424    int *, int *, const char **);
425
426static void add_trivial_nfs4_acl(struct archive_entry *);
427#endif
428
429#if HAVE_SUN_ACL
430static int
431sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
432#endif
433
434#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
435static 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
444static int
445setup_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 */
621static const struct {
622	const int archive_perm;
623	const 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 */
690static const struct {
691	const int archive_inherit;
692	const int platform_inherit;
693} acl_inherit_map[] = {
694#if HAVE_SUN_ACL	/* Solaris ACL inheritance flags */
695	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
696	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
697	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
698	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
699	{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
700	{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
701	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
702#elif HAVE_DARWIN_ACL	/* MacOS NFSv4 inheritance flags */
703	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
704	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
705	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
706	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
707	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
708#else	/* FreeBSD NFSv4 ACL inheritance flags */
709	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
710	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
711	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
712	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
713	{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
714	{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
715	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
716#endif	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
717};
718#endif	/* HAVE_NFS4_ACL */
719
720#if HAVE_DARWIN_ACL
721static 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 */
768static void
769add_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 */
858static int
859sun_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	 * including 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 */
1012static int
1013translate_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 */
1146static int
1147translate_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 */
1385static int
1386setup_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
1412static int
1413setup_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
1479static int
1480setup_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 */
1583static int
1584setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
1585    int namespace, const char *name, const char *fullname, int fd);
1586
1587static int
1588setup_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
1637static int
1638setup_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 */
1724static int
1725setup_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
1753static int
1754setup_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	}
1841exit_setup_sparse_fiemap:
1842	return (exit_sts);
1843}
1844
1845#if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
1846static int
1847setup_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
1861static int
1862setup_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	}
1978exit_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 */
1988static int
1989setup_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
2002