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