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