1228753Smm/*- 2228753Smm * Copyright (c) 2003-2009 Tim Kientzle 3238856Smm * Copyright (c) 2010-2012 Michihiro NAKAJIMA 4313571Smm * Copyright (c) 2016 Martin Matuska 5228753Smm * All rights reserved. 6228753Smm * 7228753Smm * Redistribution and use in source and binary forms, with or without 8228753Smm * modification, are permitted provided that the following conditions 9228753Smm * are met: 10228753Smm * 1. Redistributions of source code must retain the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer. 12228753Smm * 2. Redistributions in binary form must reproduce the above copyright 13228753Smm * notice, this list of conditions and the following disclaimer in the 14228753Smm * documentation and/or other materials provided with the distribution. 15228753Smm * 16228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26228753Smm */ 27228753Smm 28228753Smm#include "archive_platform.h" 29316338Smm__FBSDID("$FreeBSD"); 30228753Smm 31232153Smm/* This is the tree-walking code for POSIX systems. */ 32232153Smm#if !defined(_WIN32) || defined(__CYGWIN__) 33232153Smm 34228753Smm#ifdef HAVE_SYS_TYPES_H 35228753Smm#include <sys/types.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_SYS_EXTATTR_H 38228753Smm#include <sys/extattr.h> 39228753Smm#endif 40232153Smm#ifdef HAVE_SYS_IOCTL_H 41232153Smm#include <sys/ioctl.h> 42232153Smm#endif 43228753Smm#ifdef HAVE_SYS_PARAM_H 44228753Smm#include <sys/param.h> 45228753Smm#endif 46228753Smm#ifdef HAVE_SYS_STAT_H 47228753Smm#include <sys/stat.h> 48228753Smm#endif 49248616Smm#if defined(HAVE_SYS_XATTR_H) 50228753Smm#include <sys/xattr.h> 51248616Smm#elif defined(HAVE_ATTR_XATTR_H) 52248616Smm#include <attr/xattr.h> 53228753Smm#endif 54232153Smm#ifdef HAVE_SYS_EA_H 55232153Smm#include <sys/ea.h> 56232153Smm#endif 57232153Smm#ifdef HAVE_COPYFILE_H 58232153Smm#include <copyfile.h> 59232153Smm#endif 60228753Smm#ifdef HAVE_ERRNO_H 61228753Smm#include <errno.h> 62228753Smm#endif 63232153Smm#ifdef HAVE_FCNTL_H 64232153Smm#include <fcntl.h> 65232153Smm#endif 66228753Smm#ifdef HAVE_LIMITS_H 67228753Smm#include <limits.h> 68228753Smm#endif 69238856Smm#ifdef HAVE_LINUX_TYPES_H 70238856Smm#include <linux/types.h> 71238856Smm#endif 72232153Smm#ifdef HAVE_LINUX_FIEMAP_H 73232153Smm#include <linux/fiemap.h> 74228753Smm#endif 75232153Smm#ifdef HAVE_LINUX_FS_H 76232153Smm#include <linux/fs.h> 77232153Smm#endif 78232153Smm/* 79232153Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 80232153Smm * As the include guards don't agree, the order of include is important. 81232153Smm */ 82232153Smm#ifdef HAVE_LINUX_EXT2_FS_H 83232153Smm#include <linux/ext2_fs.h> /* for Linux file flags */ 84232153Smm#endif 85232153Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 86232153Smm#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ 87232153Smm#endif 88232153Smm#ifdef HAVE_PATHS_H 89232153Smm#include <paths.h> 90232153Smm#endif 91232153Smm#ifdef HAVE_UNISTD_H 92232153Smm#include <unistd.h> 93232153Smm#endif 94228753Smm 95228753Smm#include "archive.h" 96228753Smm#include "archive_entry.h" 97228753Smm#include "archive_private.h" 98228753Smm#include "archive_read_disk_private.h" 99228753Smm 100248616Smm#ifndef O_CLOEXEC 101248616Smm#define O_CLOEXEC 0 102248616Smm#endif 103248616Smm 104232153Smmstatic int setup_mac_metadata(struct archive_read_disk *, 105238856Smm struct archive_entry *, int *fd); 106368708Smm#ifdef ARCHIVE_XATTR_FREEBSD 107368708Smmstatic int setup_xattrs_namespace(struct archive_read_disk *, 108368708Smm struct archive_entry *, int *, int); 109368708Smm#endif 110228753Smmstatic int setup_xattrs(struct archive_read_disk *, 111238856Smm struct archive_entry *, int *fd); 112232153Smmstatic int setup_sparse(struct archive_read_disk *, 113238856Smm struct archive_entry *, int *fd); 114311042Smm#if defined(HAVE_LINUX_FIEMAP_H) 115311042Smmstatic int setup_sparse_fiemap(struct archive_read_disk *, 116311042Smm struct archive_entry *, int *fd); 117311042Smm#endif 118228753Smm 119316338Smm#if !ARCHIVE_ACL_SUPPORT 120228753Smmint 121316338Smmarchive_read_disk_entry_setup_acls(struct archive_read_disk *a, 122316338Smm struct archive_entry *entry, int *fd) 123316338Smm{ 124316338Smm (void)a; /* UNUSED */ 125316338Smm (void)entry; /* UNUSED */ 126316338Smm (void)fd; /* UNUSED */ 127316338Smm return (ARCHIVE_OK); 128316338Smm} 129316338Smm#endif 130316338Smm 131316338Smm/* 132316338Smm * Enter working directory and return working pathname of archive_entry. 133316338Smm * If a pointer to an integer is provided and its value is below zero 134324418Smm * open a file descriptor on this pathname. 135316338Smm */ 136316338Smmconst char * 137316338Smmarchive_read_disk_entry_setup_path(struct archive_read_disk *a, 138316338Smm struct archive_entry *entry, int *fd) 139316338Smm{ 140316338Smm const char *path; 141316338Smm 142316338Smm path = archive_entry_sourcepath(entry); 143316338Smm 144316338Smm if (path == NULL || (a->tree != NULL && 145316338Smm a->tree_enter_working_dir(a->tree) != 0)) 146316338Smm path = archive_entry_pathname(entry); 147316338Smm if (path == NULL) { 148316338Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 149316338Smm "Couldn't determine path"); 150316338Smm } else if (fd != NULL && *fd < 0 && a->tree != NULL && 151316338Smm (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) { 152316338Smm *fd = a->open_on_current_dir(a->tree, path, 153316338Smm O_RDONLY | O_NONBLOCK); 154316338Smm } 155316338Smm return (path); 156316338Smm} 157316338Smm 158316338Smmint 159228753Smmarchive_read_disk_entry_from_file(struct archive *_a, 160228753Smm struct archive_entry *entry, 161232153Smm int fd, 162232153Smm const struct stat *st) 163228753Smm{ 164228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 165228753Smm const char *path, *name; 166228753Smm struct stat s; 167228753Smm int initial_fd = fd; 168228753Smm int r, r1; 169228753Smm 170346105Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, 171346105Smm "archive_read_disk_entry_from_file"); 172346105Smm 173228753Smm archive_clear_error(_a); 174228753Smm path = archive_entry_sourcepath(entry); 175228753Smm if (path == NULL) 176228753Smm path = archive_entry_pathname(entry); 177228753Smm 178232153Smm if (a->tree == NULL) { 179232153Smm if (st == NULL) { 180228753Smm#if HAVE_FSTAT 181232153Smm if (fd >= 0) { 182232153Smm if (fstat(fd, &s) != 0) { 183232153Smm archive_set_error(&a->archive, errno, 184232153Smm "Can't fstat"); 185232153Smm return (ARCHIVE_FAILED); 186232153Smm } 187232153Smm } else 188228753Smm#endif 189228753Smm#if HAVE_LSTAT 190232153Smm if (!a->follow_symlinks) { 191232153Smm if (lstat(path, &s) != 0) { 192232153Smm archive_set_error(&a->archive, errno, 193232153Smm "Can't lstat %s", path); 194232153Smm return (ARCHIVE_FAILED); 195232153Smm } 196232153Smm } else 197232153Smm#endif 198348608Smm if (la_stat(path, &s) != 0) { 199228753Smm archive_set_error(&a->archive, errno, 200232153Smm "Can't stat %s", path); 201228753Smm return (ARCHIVE_FAILED); 202228753Smm } 203232153Smm st = &s; 204228753Smm } 205232153Smm archive_entry_copy_stat(entry, st); 206228753Smm } 207228753Smm 208238909Smm /* Lookup uname/gname */ 209238909Smm name = archive_read_disk_uname(_a, archive_entry_uid(entry)); 210238909Smm if (name != NULL) 211238909Smm archive_entry_copy_uname(entry, name); 212238909Smm name = archive_read_disk_gname(_a, archive_entry_gid(entry)); 213238909Smm if (name != NULL) 214238909Smm archive_entry_copy_gname(entry, name); 215238909Smm 216228753Smm#ifdef HAVE_STRUCT_STAT_ST_FLAGS 217228753Smm /* On FreeBSD, we get flags for free with the stat. */ 218228753Smm /* TODO: Does this belong in copy_stat()? */ 219315433Smm if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0) 220228753Smm archive_entry_set_fflags(entry, st->st_flags, 0); 221228753Smm#endif 222228753Smm 223315433Smm#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ 224315433Smm (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) 225232153Smm /* Linux requires an extra ioctl to pull the flags. Although 226232153Smm * this is an extra step, it has a nice side-effect: We get an 227232153Smm * open file descriptor which we can use in the subsequent lookups. */ 228315433Smm if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && 229315433Smm (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) { 230238856Smm if (fd < 0) { 231238856Smm if (a->tree != NULL) 232238856Smm fd = a->open_on_current_dir(a->tree, path, 233248616Smm O_RDONLY | O_NONBLOCK | O_CLOEXEC); 234238856Smm else 235248616Smm fd = open(path, O_RDONLY | O_NONBLOCK | 236248616Smm O_CLOEXEC); 237248616Smm __archive_ensure_cloexec_flag(fd); 238238856Smm } 239232153Smm if (fd >= 0) { 240248616Smm int stflags; 241315433Smm r = ioctl(fd, 242315433Smm#if defined(FS_IOC_GETFLAGS) 243315433Smm FS_IOC_GETFLAGS, 244315433Smm#else 245315433Smm EXT2_IOC_GETFLAGS, 246315433Smm#endif 247315433Smm &stflags); 248232153Smm if (r == 0 && stflags != 0) 249232153Smm archive_entry_set_fflags(entry, stflags, 0); 250232153Smm } 251232153Smm } 252232153Smm#endif 253232153Smm 254232153Smm#if defined(HAVE_READLINK) || defined(HAVE_READLINKAT) 255228753Smm if (S_ISLNK(st->st_mode)) { 256358090Smm size_t linkbuffer_len = st->st_size; 257232153Smm char *linkbuffer; 258232153Smm int lnklen; 259232153Smm 260358090Smm linkbuffer = malloc(linkbuffer_len + 1); 261232153Smm if (linkbuffer == NULL) { 262232153Smm archive_set_error(&a->archive, ENOMEM, 263232153Smm "Couldn't read link data"); 264232153Smm return (ARCHIVE_FAILED); 265232153Smm } 266238856Smm if (a->tree != NULL) { 267232153Smm#ifdef HAVE_READLINKAT 268238856Smm lnklen = readlinkat(a->tree_current_dir_fd(a->tree), 269238856Smm path, linkbuffer, linkbuffer_len); 270238856Smm#else 271238856Smm if (a->tree_enter_working_dir(a->tree) != 0) { 272238856Smm archive_set_error(&a->archive, errno, 273238856Smm "Couldn't read link data"); 274238856Smm free(linkbuffer); 275238856Smm return (ARCHIVE_FAILED); 276238856Smm } 277238856Smm lnklen = readlink(path, linkbuffer, linkbuffer_len); 278232153Smm#endif /* HAVE_READLINKAT */ 279238856Smm } else 280238856Smm lnklen = readlink(path, linkbuffer, linkbuffer_len); 281228753Smm if (lnklen < 0) { 282228753Smm archive_set_error(&a->archive, errno, 283228753Smm "Couldn't read link data"); 284232153Smm free(linkbuffer); 285228753Smm return (ARCHIVE_FAILED); 286228753Smm } 287358090Smm linkbuffer[lnklen] = '\0'; 288228753Smm archive_entry_set_symlink(entry, linkbuffer); 289232153Smm free(linkbuffer); 290228753Smm } 291232153Smm#endif /* HAVE_READLINK || HAVE_READLINKAT */ 292228753Smm 293315433Smm r = 0; 294315433Smm if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0) 295316338Smm r = archive_read_disk_entry_setup_acls(a, entry, &fd); 296315433Smm if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) { 297302001Smm r1 = setup_xattrs(a, entry, &fd); 298302001Smm if (r1 < r) 299302001Smm r = r1; 300302001Smm } 301315433Smm if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) { 302238856Smm r1 = setup_mac_metadata(a, entry, &fd); 303238856Smm if (r1 < r) 304238856Smm r = r1; 305238856Smm } 306238856Smm r1 = setup_sparse(a, entry, &fd); 307232153Smm if (r1 < r) 308232153Smm r = r1; 309232153Smm 310228753Smm /* If we opened the file earlier in this function, close it. */ 311228753Smm if (initial_fd != fd) 312228753Smm close(fd); 313228753Smm return (r); 314228753Smm} 315228753Smm 316232153Smm#if defined(__APPLE__) && defined(HAVE_COPYFILE_H) 317232153Smm/* 318232153Smm * The Mac OS "copyfile()" API copies the extended metadata for a 319232153Smm * file into a separate file in AppleDouble format (see RFC 1740). 320232153Smm * 321232153Smm * Mac OS tar and cpio implementations store this extended 322232153Smm * metadata as a separate entry just before the regular entry 323232153Smm * with a "._" prefix added to the filename. 324232153Smm * 325232153Smm * Note that this is currently done unconditionally; the tar program has 326232153Smm * an option to discard this information before the archive is written. 327232153Smm * 328232153Smm * TODO: If there's a failure, report it and return ARCHIVE_WARN. 329232153Smm */ 330232153Smmstatic int 331232153Smmsetup_mac_metadata(struct archive_read_disk *a, 332238856Smm struct archive_entry *entry, int *fd) 333232153Smm{ 334232153Smm int tempfd = -1; 335232153Smm int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR; 336232153Smm struct stat copyfile_stat; 337232153Smm int ret = ARCHIVE_OK; 338248616Smm void *buff = NULL; 339232153Smm int have_attrs; 340248616Smm const char *name, *tempdir; 341248616Smm struct archive_string tempfile; 342232153Smm 343238856Smm (void)fd; /* UNUSED */ 344316338Smm 345316338Smm name = archive_read_disk_entry_setup_path(a, entry, NULL); 346232153Smm if (name == NULL) 347232153Smm return (ARCHIVE_WARN); 348232153Smm 349232153Smm /* Short-circuit if there's nothing to do. */ 350232153Smm have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); 351232153Smm if (have_attrs == -1) { 352232153Smm archive_set_error(&a->archive, errno, 353232153Smm "Could not check extended attributes"); 354232153Smm return (ARCHIVE_WARN); 355232153Smm } 356232153Smm if (have_attrs == 0) 357232153Smm return (ARCHIVE_OK); 358232153Smm 359232153Smm tempdir = NULL; 360232153Smm if (issetugid() == 0) 361232153Smm tempdir = getenv("TMPDIR"); 362232153Smm if (tempdir == NULL) 363232153Smm tempdir = _PATH_TMP; 364248616Smm archive_string_init(&tempfile); 365248616Smm archive_strcpy(&tempfile, tempdir); 366248616Smm archive_strcat(&tempfile, "tar.md.XXXXXX"); 367248616Smm tempfd = mkstemp(tempfile.s); 368248616Smm if (tempfd < 0) { 369248616Smm archive_set_error(&a->archive, errno, 370248616Smm "Could not open extended attribute file"); 371248616Smm ret = ARCHIVE_WARN; 372248616Smm goto cleanup; 373248616Smm } 374248616Smm __archive_ensure_cloexec_flag(tempfd); 375232153Smm 376232153Smm /* XXX I wish copyfile() could pack directly to a memory 377232153Smm * buffer; that would avoid the temp file here. For that 378232153Smm * matter, it would be nice if fcopyfile() actually worked, 379232153Smm * that would reduce the many open/close races here. */ 380248616Smm if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) { 381232153Smm archive_set_error(&a->archive, errno, 382232153Smm "Could not pack extended attributes"); 383232153Smm ret = ARCHIVE_WARN; 384232153Smm goto cleanup; 385232153Smm } 386232153Smm if (fstat(tempfd, ©file_stat)) { 387232153Smm archive_set_error(&a->archive, errno, 388232153Smm "Could not check size of extended attributes"); 389232153Smm ret = ARCHIVE_WARN; 390232153Smm goto cleanup; 391232153Smm } 392232153Smm buff = malloc(copyfile_stat.st_size); 393232153Smm if (buff == NULL) { 394232153Smm archive_set_error(&a->archive, errno, 395232153Smm "Could not allocate memory for extended attributes"); 396232153Smm ret = ARCHIVE_WARN; 397232153Smm goto cleanup; 398232153Smm } 399232153Smm if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) { 400232153Smm archive_set_error(&a->archive, errno, 401232153Smm "Could not read extended attributes into memory"); 402232153Smm ret = ARCHIVE_WARN; 403232153Smm goto cleanup; 404232153Smm } 405232153Smm archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size); 406232153Smm 407232153Smmcleanup: 408248616Smm if (tempfd >= 0) { 409232153Smm close(tempfd); 410248616Smm unlink(tempfile.s); 411248616Smm } 412248616Smm archive_string_free(&tempfile); 413248616Smm free(buff); 414232153Smm return (ret); 415232153Smm} 416232153Smm 417232153Smm#else 418232153Smm 419232153Smm/* 420232153Smm * Stub implementation for non-Mac systems. 421232153Smm */ 422232153Smmstatic int 423232153Smmsetup_mac_metadata(struct archive_read_disk *a, 424238856Smm struct archive_entry *entry, int *fd) 425232153Smm{ 426232153Smm (void)a; /* UNUSED */ 427232153Smm (void)entry; /* UNUSED */ 428232153Smm (void)fd; /* UNUSED */ 429232153Smm return (ARCHIVE_OK); 430232153Smm} 431232153Smm#endif 432232153Smm 433316338Smm#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX 434232153Smm 435228753Smm/* 436316338Smm * Linux, Darwin and AIX extended attribute support. 437228753Smm * 438228753Smm * TODO: By using a stack-allocated buffer for the first 439228753Smm * call to getxattr(), we might be able to avoid the second 440228753Smm * call entirely. We only need the second call if the 441228753Smm * stack-allocated buffer is too small. But a modest buffer 442228753Smm * of 1024 bytes or so will often be big enough. Same applies 443228753Smm * to listxattr(). 444228753Smm */ 445228753Smm 446228753Smm 447228753Smmstatic int 448228753Smmsetup_xattr(struct archive_read_disk *a, 449315433Smm struct archive_entry *entry, const char *name, int fd, const char *accpath) 450228753Smm{ 451228753Smm ssize_t size; 452228753Smm void *value = NULL; 453228753Smm 454316338Smm 455316338Smm if (fd >= 0) { 456316338Smm#if ARCHIVE_XATTR_LINUX 457232153Smm size = fgetxattr(fd, name, NULL, 0); 458316338Smm#elif ARCHIVE_XATTR_DARWIN 459316338Smm size = fgetxattr(fd, name, NULL, 0, 0, 0); 460316338Smm#elif ARCHIVE_XATTR_AIX 461316338Smm size = fgetea(fd, name, NULL, 0); 462316338Smm#endif 463316338Smm } else if (!a->follow_symlinks) { 464316338Smm#if ARCHIVE_XATTR_LINUX 465228753Smm size = lgetxattr(accpath, name, NULL, 0); 466316338Smm#elif ARCHIVE_XATTR_DARWIN 467316338Smm size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW); 468316338Smm#elif ARCHIVE_XATTR_AIX 469316338Smm size = lgetea(accpath, name, NULL, 0); 470316338Smm#endif 471316338Smm } else { 472316338Smm#if ARCHIVE_XATTR_LINUX 473228753Smm size = getxattr(accpath, name, NULL, 0); 474316338Smm#elif ARCHIVE_XATTR_DARWIN 475316338Smm size = getxattr(accpath, name, NULL, 0, 0, 0); 476316338Smm#elif ARCHIVE_XATTR_AIX 477232153Smm size = getea(accpath, name, NULL, 0); 478232153Smm#endif 479316338Smm } 480228753Smm 481228753Smm if (size == -1) { 482228753Smm archive_set_error(&a->archive, errno, 483228753Smm "Couldn't query extended attribute"); 484228753Smm return (ARCHIVE_WARN); 485228753Smm } 486228753Smm 487228753Smm if (size > 0 && (value = malloc(size)) == NULL) { 488228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 489228753Smm return (ARCHIVE_FATAL); 490228753Smm } 491228753Smm 492316338Smm 493316338Smm if (fd >= 0) { 494316338Smm#if ARCHIVE_XATTR_LINUX 495232153Smm size = fgetxattr(fd, name, value, size); 496316338Smm#elif ARCHIVE_XATTR_DARWIN 497316338Smm size = fgetxattr(fd, name, value, size, 0, 0); 498316338Smm#elif ARCHIVE_XATTR_AIX 499316338Smm size = fgetea(fd, name, value, size); 500316338Smm#endif 501316338Smm } else if (!a->follow_symlinks) { 502316338Smm#if ARCHIVE_XATTR_LINUX 503228753Smm size = lgetxattr(accpath, name, value, size); 504316338Smm#elif ARCHIVE_XATTR_DARWIN 505316338Smm size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW); 506316338Smm#elif ARCHIVE_XATTR_AIX 507316338Smm size = lgetea(accpath, name, value, size); 508316338Smm#endif 509316338Smm } else { 510316338Smm#if ARCHIVE_XATTR_LINUX 511228753Smm size = getxattr(accpath, name, value, size); 512316338Smm#elif ARCHIVE_XATTR_DARWIN 513316338Smm size = getxattr(accpath, name, value, size, 0, 0); 514316338Smm#elif ARCHIVE_XATTR_AIX 515232153Smm size = getea(accpath, name, value, size); 516232153Smm#endif 517316338Smm } 518228753Smm 519228753Smm if (size == -1) { 520228753Smm archive_set_error(&a->archive, errno, 521228753Smm "Couldn't read extended attribute"); 522228753Smm return (ARCHIVE_WARN); 523228753Smm } 524228753Smm 525228753Smm archive_entry_xattr_add_entry(entry, name, value, size); 526228753Smm 527228753Smm free(value); 528228753Smm return (ARCHIVE_OK); 529228753Smm} 530228753Smm 531228753Smmstatic int 532228753Smmsetup_xattrs(struct archive_read_disk *a, 533238856Smm struct archive_entry *entry, int *fd) 534228753Smm{ 535228753Smm char *list, *p; 536228753Smm const char *path; 537228753Smm ssize_t list_size; 538228753Smm 539315433Smm path = NULL; 540228753Smm 541315433Smm if (*fd < 0) { 542316338Smm path = archive_read_disk_entry_setup_path(a, entry, fd); 543316338Smm if (path == NULL) 544315433Smm return (ARCHIVE_WARN); 545238856Smm } 546238856Smm 547316338Smm if (*fd >= 0) { 548316338Smm#if ARCHIVE_XATTR_LINUX 549238856Smm list_size = flistxattr(*fd, NULL, 0); 550316338Smm#elif ARCHIVE_XATTR_DARWIN 551316338Smm list_size = flistxattr(*fd, NULL, 0, 0); 552316338Smm#elif ARCHIVE_XATTR_AIX 553316338Smm list_size = flistea(*fd, NULL, 0); 554316338Smm#endif 555316338Smm } else if (!a->follow_symlinks) { 556316338Smm#if ARCHIVE_XATTR_LINUX 557228753Smm list_size = llistxattr(path, NULL, 0); 558316338Smm#elif ARCHIVE_XATTR_DARWIN 559316338Smm list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW); 560316338Smm#elif ARCHIVE_XATTR_AIX 561316338Smm list_size = llistea(path, NULL, 0); 562316338Smm#endif 563316338Smm } else { 564316338Smm#if ARCHIVE_XATTR_LINUX 565228753Smm list_size = listxattr(path, NULL, 0); 566316338Smm#elif ARCHIVE_XATTR_DARWIN 567316338Smm list_size = listxattr(path, NULL, 0, 0); 568316338Smm#elif ARCHIVE_XATTR_AIX 569232153Smm list_size = listea(path, NULL, 0); 570232153Smm#endif 571316338Smm } 572228753Smm 573228753Smm if (list_size == -1) { 574232153Smm if (errno == ENOTSUP || errno == ENOSYS) 575228753Smm return (ARCHIVE_OK); 576228753Smm archive_set_error(&a->archive, errno, 577228753Smm "Couldn't list extended attributes"); 578228753Smm return (ARCHIVE_WARN); 579228753Smm } 580228753Smm 581228753Smm if (list_size == 0) 582228753Smm return (ARCHIVE_OK); 583228753Smm 584228753Smm if ((list = malloc(list_size)) == NULL) { 585228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 586228753Smm return (ARCHIVE_FATAL); 587228753Smm } 588228753Smm 589316338Smm if (*fd >= 0) { 590316338Smm#if ARCHIVE_XATTR_LINUX 591238856Smm list_size = flistxattr(*fd, list, list_size); 592316338Smm#elif ARCHIVE_XATTR_DARWIN 593316338Smm list_size = flistxattr(*fd, list, list_size, 0); 594316338Smm#elif ARCHIVE_XATTR_AIX 595316338Smm list_size = flistea(*fd, list, list_size); 596316338Smm#endif 597316338Smm } else if (!a->follow_symlinks) { 598316338Smm#if ARCHIVE_XATTR_LINUX 599228753Smm list_size = llistxattr(path, list, list_size); 600316338Smm#elif ARCHIVE_XATTR_DARWIN 601316338Smm list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW); 602316338Smm#elif ARCHIVE_XATTR_AIX 603316338Smm list_size = llistea(path, list, list_size); 604316338Smm#endif 605316338Smm } else { 606316338Smm#if ARCHIVE_XATTR_LINUX 607228753Smm list_size = listxattr(path, list, list_size); 608316338Smm#elif ARCHIVE_XATTR_DARWIN 609316338Smm list_size = listxattr(path, list, list_size, 0); 610316338Smm#elif ARCHIVE_XATTR_AIX 611232153Smm list_size = listea(path, list, list_size); 612232153Smm#endif 613316338Smm } 614228753Smm 615228753Smm if (list_size == -1) { 616228753Smm archive_set_error(&a->archive, errno, 617228753Smm "Couldn't retrieve extended attributes"); 618228753Smm free(list); 619228753Smm return (ARCHIVE_WARN); 620228753Smm } 621228753Smm 622228753Smm for (p = list; (p - list) < list_size; p += strlen(p) + 1) { 623353377Smm#if ARCHIVE_XATTR_LINUX 624353377Smm /* Linux: skip POSIX.1e ACL extended attributes */ 625353377Smm if (strncmp(p, "system.", 7) == 0 && 626353377Smm (strcmp(p + 7, "posix_acl_access") == 0 || 627353377Smm strcmp(p + 7, "posix_acl_default") == 0)) 628228753Smm continue; 629353377Smm if (strncmp(p, "trusted.SGI_", 12) == 0 && 630353377Smm (strcmp(p + 12, "ACL_DEFAULT") == 0 || 631353377Smm strcmp(p + 12, "ACL_FILE") == 0)) 632353377Smm continue; 633353377Smm 634353377Smm /* Linux: xfsroot namespace is obsolete and unsupported */ 635353377Smm if (strncmp(p, "xfsroot.", 8) == 0) 636353377Smm continue; 637353377Smm#endif 638315433Smm setup_xattr(a, entry, p, *fd, path); 639228753Smm } 640228753Smm 641228753Smm free(list); 642228753Smm return (ARCHIVE_OK); 643228753Smm} 644228753Smm 645316338Smm#elif ARCHIVE_XATTR_FREEBSD 646228753Smm 647228753Smm/* 648228753Smm * FreeBSD extattr interface. 649228753Smm */ 650228753Smm 651228753Smm/* TODO: Implement this. Follow the Linux model above, but 652228753Smm * with FreeBSD-specific system calls, of course. Be careful 653228753Smm * to not include the system extattrs that hold ACLs; we handle 654228753Smm * those separately. 655228753Smm */ 656228753Smmstatic int 657228753Smmsetup_xattr(struct archive_read_disk *a, struct archive_entry *entry, 658315433Smm int namespace, const char *name, const char *fullname, int fd, 659315433Smm const char *path); 660228753Smm 661228753Smmstatic int 662228753Smmsetup_xattr(struct archive_read_disk *a, struct archive_entry *entry, 663315433Smm int namespace, const char *name, const char *fullname, int fd, 664315433Smm const char *accpath) 665228753Smm{ 666228753Smm ssize_t size; 667228753Smm void *value = NULL; 668228753Smm 669232153Smm if (fd >= 0) 670232153Smm size = extattr_get_fd(fd, namespace, name, NULL, 0); 671232153Smm else if (!a->follow_symlinks) 672228753Smm size = extattr_get_link(accpath, namespace, name, NULL, 0); 673228753Smm else 674228753Smm size = extattr_get_file(accpath, namespace, name, NULL, 0); 675228753Smm 676228753Smm if (size == -1) { 677228753Smm archive_set_error(&a->archive, errno, 678228753Smm "Couldn't query extended attribute"); 679228753Smm return (ARCHIVE_WARN); 680228753Smm } 681228753Smm 682228753Smm if (size > 0 && (value = malloc(size)) == NULL) { 683228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 684228753Smm return (ARCHIVE_FATAL); 685228753Smm } 686228753Smm 687232153Smm if (fd >= 0) 688232153Smm size = extattr_get_fd(fd, namespace, name, value, size); 689232153Smm else if (!a->follow_symlinks) 690228753Smm size = extattr_get_link(accpath, namespace, name, value, size); 691228753Smm else 692228753Smm size = extattr_get_file(accpath, namespace, name, value, size); 693228753Smm 694228753Smm if (size == -1) { 695238856Smm free(value); 696228753Smm archive_set_error(&a->archive, errno, 697228753Smm "Couldn't read extended attribute"); 698228753Smm return (ARCHIVE_WARN); 699228753Smm } 700228753Smm 701228753Smm archive_entry_xattr_add_entry(entry, fullname, value, size); 702228753Smm 703228753Smm free(value); 704228753Smm return (ARCHIVE_OK); 705228753Smm} 706228753Smm 707228753Smmstatic int 708368708Smmsetup_xattrs_namespace(struct archive_read_disk *a, 709368708Smm struct archive_entry *entry, int *fd, int namespace) 710228753Smm{ 711228753Smm char buff[512]; 712228753Smm char *list, *p; 713228753Smm ssize_t list_size; 714228753Smm const char *path; 715228753Smm 716315433Smm path = NULL; 717228753Smm 718315433Smm if (*fd < 0) { 719316338Smm path = archive_read_disk_entry_setup_path(a, entry, fd); 720316338Smm if (path == NULL) 721315433Smm return (ARCHIVE_WARN); 722238856Smm } 723238856Smm 724238856Smm if (*fd >= 0) 725238856Smm list_size = extattr_list_fd(*fd, namespace, NULL, 0); 726232153Smm else if (!a->follow_symlinks) 727228753Smm list_size = extattr_list_link(path, namespace, NULL, 0); 728228753Smm else 729228753Smm list_size = extattr_list_file(path, namespace, NULL, 0); 730228753Smm 731228753Smm if (list_size == -1 && errno == EOPNOTSUPP) 732228753Smm return (ARCHIVE_OK); 733368708Smm if (list_size == -1 && errno == EPERM) 734368708Smm return (ARCHIVE_OK); 735228753Smm if (list_size == -1) { 736228753Smm archive_set_error(&a->archive, errno, 737228753Smm "Couldn't list extended attributes"); 738228753Smm return (ARCHIVE_WARN); 739228753Smm } 740228753Smm 741228753Smm if (list_size == 0) 742228753Smm return (ARCHIVE_OK); 743228753Smm 744228753Smm if ((list = malloc(list_size)) == NULL) { 745228753Smm archive_set_error(&a->archive, errno, "Out of memory"); 746228753Smm return (ARCHIVE_FATAL); 747228753Smm } 748228753Smm 749238856Smm if (*fd >= 0) 750238856Smm list_size = extattr_list_fd(*fd, namespace, list, list_size); 751232153Smm else if (!a->follow_symlinks) 752228753Smm list_size = extattr_list_link(path, namespace, list, list_size); 753228753Smm else 754228753Smm list_size = extattr_list_file(path, namespace, list, list_size); 755228753Smm 756228753Smm if (list_size == -1) { 757228753Smm archive_set_error(&a->archive, errno, 758228753Smm "Couldn't retrieve extended attributes"); 759228753Smm free(list); 760228753Smm return (ARCHIVE_WARN); 761228753Smm } 762228753Smm 763228753Smm p = list; 764228753Smm while ((p - list) < list_size) { 765228753Smm size_t len = 255 & (int)*p; 766228753Smm char *name; 767228753Smm 768368708Smm if (namespace == EXTATTR_NAMESPACE_SYSTEM) { 769368708Smm if (!strcmp(p + 1, "nfs4.acl") || 770368708Smm !strcmp(p + 1, "posix1e.acl_access") || 771368708Smm !strcmp(p + 1, "posix1e.acl_default")) { 772368708Smm p += 1 + len; 773368708Smm continue; 774368708Smm } 775368708Smm strcpy(buff, "system."); 776368708Smm } else { 777368708Smm strcpy(buff, "user."); 778368708Smm } 779228753Smm name = buff + strlen(buff); 780228753Smm memcpy(name, p + 1, len); 781228753Smm name[len] = '\0'; 782315433Smm setup_xattr(a, entry, namespace, name, buff, *fd, path); 783228753Smm p += 1 + len; 784228753Smm } 785228753Smm 786228753Smm free(list); 787228753Smm return (ARCHIVE_OK); 788228753Smm} 789228753Smm 790368708Smmstatic int 791368708Smmsetup_xattrs(struct archive_read_disk *a, 792368708Smm struct archive_entry *entry, int *fd) 793368708Smm{ 794368708Smm int namespaces[2]; 795368708Smm int i, res; 796368708Smm 797368708Smm namespaces[0] = EXTATTR_NAMESPACE_USER; 798368708Smm namespaces[1] = EXTATTR_NAMESPACE_SYSTEM; 799368708Smm 800368708Smm for (i = 0; i < 2; i++) { 801368708Smm res = setup_xattrs_namespace(a, entry, fd, 802368708Smm namespaces[i]); 803368708Smm switch (res) { 804368708Smm case (ARCHIVE_OK): 805368708Smm case (ARCHIVE_WARN): 806368708Smm break; 807368708Smm default: 808368708Smm return (res); 809368708Smm } 810368708Smm } 811368708Smm 812368708Smm return (ARCHIVE_OK); 813368708Smm} 814368708Smm 815228753Smm#else 816228753Smm 817228753Smm/* 818228753Smm * Generic (stub) extended attribute support. 819228753Smm */ 820228753Smmstatic int 821228753Smmsetup_xattrs(struct archive_read_disk *a, 822238856Smm struct archive_entry *entry, int *fd) 823228753Smm{ 824228753Smm (void)a; /* UNUSED */ 825228753Smm (void)entry; /* UNUSED */ 826228753Smm (void)fd; /* UNUSED */ 827228753Smm return (ARCHIVE_OK); 828228753Smm} 829228753Smm 830228753Smm#endif 831232153Smm 832232153Smm#if defined(HAVE_LINUX_FIEMAP_H) 833232153Smm 834232153Smm/* 835311042Smm * Linux FIEMAP sparse interface. 836232153Smm * 837232153Smm * The FIEMAP ioctl returns an "extent" for each physical allocation 838232153Smm * on disk. We need to process those to generate a more compact list 839232153Smm * of logical file blocks. We also need to be very careful to use 840232153Smm * FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes 841232153Smm * does not report allocations for newly-written data that hasn't 842232153Smm * been synced to disk. 843232153Smm * 844232153Smm * It's important to return a minimal sparse file list because we want 845232153Smm * to not trigger sparse file extensions if we don't have to, since 846232153Smm * not all readers support them. 847232153Smm */ 848232153Smm 849232153Smmstatic int 850311042Smmsetup_sparse_fiemap(struct archive_read_disk *a, 851238856Smm struct archive_entry *entry, int *fd) 852232153Smm{ 853232153Smm char buff[4096]; 854232153Smm struct fiemap *fm; 855232153Smm struct fiemap_extent *fe; 856232153Smm int64_t size; 857302001Smm int count, do_fiemap, iters; 858232153Smm int exit_sts = ARCHIVE_OK; 859316338Smm const char *path; 860232153Smm 861232153Smm if (archive_entry_filetype(entry) != AE_IFREG 862232153Smm || archive_entry_size(entry) <= 0 863232153Smm || archive_entry_hardlink(entry) != NULL) 864232153Smm return (ARCHIVE_OK); 865232153Smm 866238856Smm if (*fd < 0) { 867316338Smm path = archive_read_disk_entry_setup_path(a, entry, NULL); 868316338Smm if (path == NULL) 869316338Smm return (ARCHIVE_FAILED); 870232153Smm 871238856Smm if (a->tree != NULL) 872238856Smm *fd = a->open_on_current_dir(a->tree, path, 873248616Smm O_RDONLY | O_NONBLOCK | O_CLOEXEC); 874238856Smm else 875248616Smm *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); 876238856Smm if (*fd < 0) { 877232153Smm archive_set_error(&a->archive, errno, 878232153Smm "Can't open `%s'", path); 879232153Smm return (ARCHIVE_FAILED); 880232153Smm } 881248616Smm __archive_ensure_cloexec_flag(*fd); 882232153Smm } 883232153Smm 884248616Smm /* Initialize buffer to avoid the error valgrind complains about. */ 885248616Smm memset(buff, 0, sizeof(buff)); 886232153Smm count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe); 887232153Smm fm = (struct fiemap *)buff; 888232153Smm fm->fm_start = 0; 889232153Smm fm->fm_length = ~0ULL;; 890232153Smm fm->fm_flags = FIEMAP_FLAG_SYNC; 891232153Smm fm->fm_extent_count = count; 892232153Smm do_fiemap = 1; 893232153Smm size = archive_entry_size(entry); 894302001Smm for (iters = 0; ; ++iters) { 895232153Smm int i, r; 896232153Smm 897238856Smm r = ioctl(*fd, FS_IOC_FIEMAP, fm); 898232153Smm if (r < 0) { 899238856Smm /* When something error happens, it is better we 900238856Smm * should return ARCHIVE_OK because an earlier 901311042Smm * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */ 902311042Smm goto exit_setup_sparse_fiemap; 903232153Smm } 904302001Smm if (fm->fm_mapped_extents == 0) { 905302001Smm if (iters == 0) { 906302001Smm /* Fully sparse file; insert a zero-length "data" entry */ 907302001Smm archive_entry_sparse_add_entry(entry, 0, 0); 908302001Smm } 909232153Smm break; 910302001Smm } 911232153Smm fe = fm->fm_extents; 912232153Smm for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) { 913232153Smm if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) { 914232153Smm /* The fe_length of the last block does not 915232153Smm * adjust itself to its size files. */ 916232153Smm int64_t length = fe->fe_length; 917232153Smm if (fe->fe_logical + length > (uint64_t)size) 918232153Smm length -= fe->fe_logical + length - size; 919232153Smm if (fe->fe_logical == 0 && length == size) { 920232153Smm /* This is not sparse. */ 921232153Smm do_fiemap = 0; 922232153Smm break; 923232153Smm } 924232153Smm if (length > 0) 925232153Smm archive_entry_sparse_add_entry(entry, 926232153Smm fe->fe_logical, length); 927232153Smm } 928232153Smm if (fe->fe_flags & FIEMAP_EXTENT_LAST) 929232153Smm do_fiemap = 0; 930232153Smm } 931232153Smm if (do_fiemap) { 932232153Smm fe = fm->fm_extents + fm->fm_mapped_extents -1; 933232153Smm fm->fm_start = fe->fe_logical + fe->fe_length; 934232153Smm } else 935232153Smm break; 936232153Smm } 937311042Smmexit_setup_sparse_fiemap: 938232153Smm return (exit_sts); 939232153Smm} 940232153Smm 941311042Smm#if !defined(SEEK_HOLE) || !defined(SEEK_DATA) 942311042Smmstatic int 943311042Smmsetup_sparse(struct archive_read_disk *a, 944311042Smm struct archive_entry *entry, int *fd) 945311042Smm{ 946311042Smm return setup_sparse_fiemap(a, entry, fd); 947311042Smm} 948311042Smm#endif 949311042Smm#endif /* defined(HAVE_LINUX_FIEMAP_H) */ 950232153Smm 951311042Smm#if defined(SEEK_HOLE) && defined(SEEK_DATA) 952311042Smm 953232153Smm/* 954311042Smm * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris) 955232153Smm */ 956232153Smm 957232153Smmstatic int 958232153Smmsetup_sparse(struct archive_read_disk *a, 959238856Smm struct archive_entry *entry, int *fd) 960232153Smm{ 961232153Smm int64_t size; 962311042Smm off_t initial_off; 963311042Smm off_t off_s, off_e; 964232153Smm int exit_sts = ARCHIVE_OK; 965302001Smm int check_fully_sparse = 0; 966316338Smm const char *path; 967232153Smm 968232153Smm if (archive_entry_filetype(entry) != AE_IFREG 969232153Smm || archive_entry_size(entry) <= 0 970232153Smm || archive_entry_hardlink(entry) != NULL) 971232153Smm return (ARCHIVE_OK); 972232153Smm 973232153Smm /* Does filesystem support the reporting of hole ? */ 974318483Smm if (*fd < 0) 975316338Smm path = archive_read_disk_entry_setup_path(a, entry, fd); 976318483Smm else 977318483Smm path = NULL; 978238856Smm 979238856Smm if (*fd >= 0) { 980311042Smm#ifdef _PC_MIN_HOLE_SIZE 981238856Smm if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0) 982232153Smm return (ARCHIVE_OK); 983311042Smm#endif 984238856Smm initial_off = lseek(*fd, 0, SEEK_CUR); 985232153Smm if (initial_off != 0) 986238856Smm lseek(*fd, 0, SEEK_SET); 987232153Smm } else { 988318483Smm if (path == NULL) 989318483Smm return (ARCHIVE_FAILED); 990311042Smm#ifdef _PC_MIN_HOLE_SIZE 991232153Smm if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) 992232153Smm return (ARCHIVE_OK); 993311042Smm#endif 994248616Smm *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); 995238856Smm if (*fd < 0) { 996232153Smm archive_set_error(&a->archive, errno, 997232153Smm "Can't open `%s'", path); 998232153Smm return (ARCHIVE_FAILED); 999232153Smm } 1000248616Smm __archive_ensure_cloexec_flag(*fd); 1001232153Smm initial_off = 0; 1002232153Smm } 1003232153Smm 1004311042Smm#ifndef _PC_MIN_HOLE_SIZE 1005311042Smm /* Check if the underlying filesystem supports seek hole */ 1006311042Smm off_s = lseek(*fd, 0, SEEK_HOLE); 1007311042Smm if (off_s < 0) 1008311042Smm#if defined(HAVE_LINUX_FIEMAP_H) 1009311042Smm return setup_sparse_fiemap(a, entry, fd); 1010311042Smm#else 1011311042Smm goto exit_setup_sparse; 1012311042Smm#endif 1013311042Smm else if (off_s > 0) 1014311042Smm lseek(*fd, 0, SEEK_SET); 1015311042Smm#endif 1016311042Smm 1017232153Smm off_s = 0; 1018232153Smm size = archive_entry_size(entry); 1019232153Smm while (off_s < size) { 1020238856Smm off_s = lseek(*fd, off_s, SEEK_DATA); 1021232153Smm if (off_s == (off_t)-1) { 1022302001Smm if (errno == ENXIO) { 1023302001Smm /* no more hole */ 1024302001Smm if (archive_entry_sparse_count(entry) == 0) { 1025302001Smm /* Potentially a fully-sparse file. */ 1026302001Smm check_fully_sparse = 1; 1027302001Smm } 1028302001Smm break; 1029302001Smm } 1030232153Smm archive_set_error(&a->archive, errno, 1031232153Smm "lseek(SEEK_HOLE) failed"); 1032232153Smm exit_sts = ARCHIVE_FAILED; 1033232153Smm goto exit_setup_sparse; 1034232153Smm } 1035238856Smm off_e = lseek(*fd, off_s, SEEK_HOLE); 1036238856Smm if (off_e == (off_t)-1) { 1037232153Smm if (errno == ENXIO) { 1038238856Smm off_e = lseek(*fd, 0, SEEK_END); 1039232153Smm if (off_e != (off_t)-1) 1040232153Smm break;/* no more data */ 1041232153Smm } 1042232153Smm archive_set_error(&a->archive, errno, 1043232153Smm "lseek(SEEK_DATA) failed"); 1044232153Smm exit_sts = ARCHIVE_FAILED; 1045232153Smm goto exit_setup_sparse; 1046232153Smm } 1047232153Smm if (off_s == 0 && off_e == size) 1048311042Smm break;/* This is not sparse. */ 1049232153Smm archive_entry_sparse_add_entry(entry, off_s, 1050232153Smm off_e - off_s); 1051232153Smm off_s = off_e; 1052232153Smm } 1053302001Smm 1054302001Smm if (check_fully_sparse) { 1055302001Smm if (lseek(*fd, 0, SEEK_HOLE) == 0 && 1056302001Smm lseek(*fd, 0, SEEK_END) == size) { 1057302001Smm /* Fully sparse file; insert a zero-length "data" entry */ 1058302001Smm archive_entry_sparse_add_entry(entry, 0, 0); 1059302001Smm } 1060302001Smm } 1061232153Smmexit_setup_sparse: 1062238856Smm lseek(*fd, initial_off, SEEK_SET); 1063232153Smm return (exit_sts); 1064232153Smm} 1065232153Smm 1066311042Smm#elif !defined(HAVE_LINUX_FIEMAP_H) 1067232153Smm 1068232153Smm/* 1069232153Smm * Generic (stub) sparse support. 1070232153Smm */ 1071232153Smmstatic int 1072232153Smmsetup_sparse(struct archive_read_disk *a, 1073238856Smm struct archive_entry *entry, int *fd) 1074232153Smm{ 1075232153Smm (void)a; /* UNUSED */ 1076232153Smm (void)entry; /* UNUSED */ 1077232153Smm (void)fd; /* UNUSED */ 1078232153Smm return (ARCHIVE_OK); 1079232153Smm} 1080232153Smm 1081232153Smm#endif 1082232153Smm 1083232153Smm#endif /* !defined(_WIN32) || defined(__CYGWIN__) */ 1084232153Smm 1085