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