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, ©file_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