1228753Smm/*- 2228753Smm * Copyright (c) 2003-2009 Tim Kientzle 3238856Smm * Copyright (c) 2010-2012 Michihiro NAKAJIMA 4228753Smm * All rights reserved. 5228753Smm * 6228753Smm * Redistribution and use in source and binary forms, with or without 7228753Smm * modification, are permitted provided that the following conditions 8228753Smm * are met: 9228753Smm * 1. Redistributions of source code must retain the above copyright 10228753Smm * notice, this list of conditions and the following disclaimer 11228753Smm * in this position and unchanged. 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 28231200Smm/* This is the tree-walking code for POSIX systems. */ 29231200Smm#if !defined(_WIN32) || defined(__CYGWIN__) 30231200Smm 31228753Smm#include "archive_platform.h" 32231200Smm__FBSDID("$FreeBSD$"); 33228753Smm 34231200Smm#ifdef HAVE_SYS_PARAM_H 35231200Smm#include <sys/param.h> 36231200Smm#endif 37231200Smm#ifdef HAVE_SYS_MOUNT_H 38231200Smm#include <sys/mount.h> 39231200Smm#endif 40231200Smm#ifdef HAVE_SYS_STAT_H 41231200Smm#include <sys/stat.h> 42231200Smm#endif 43231200Smm#ifdef HAVE_SYS_STATFS_H 44231200Smm#include <sys/statfs.h> 45231200Smm#endif 46231200Smm#ifdef HAVE_SYS_STATVFS_H 47231200Smm#include <sys/statvfs.h> 48231200Smm#endif 49231200Smm#ifdef HAVE_SYS_TIME_H 50231200Smm#include <sys/time.h> 51231200Smm#endif 52231200Smm#ifdef HAVE_LINUX_MAGIC_H 53231200Smm#include <linux/magic.h> 54231200Smm#endif 55238856Smm#ifdef HAVE_LINUX_FS_H 56238856Smm#include <linux/fs.h> 57238856Smm#endif 58238856Smm/* 59238856Smm * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h. 60238856Smm * As the include guards don't agree, the order of include is important. 61238856Smm */ 62238856Smm#ifdef HAVE_LINUX_EXT2_FS_H 63238856Smm#include <linux/ext2_fs.h> /* for Linux file flags */ 64238856Smm#endif 65238856Smm#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__) 66238856Smm#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */ 67238856Smm#endif 68231200Smm#ifdef HAVE_DIRECT_H 69231200Smm#include <direct.h> 70231200Smm#endif 71231200Smm#ifdef HAVE_DIRENT_H 72231200Smm#include <dirent.h> 73231200Smm#endif 74231200Smm#ifdef HAVE_ERRNO_H 75231200Smm#include <errno.h> 76231200Smm#endif 77231200Smm#ifdef HAVE_FCNTL_H 78231200Smm#include <fcntl.h> 79231200Smm#endif 80231200Smm#ifdef HAVE_LIMITS_H 81231200Smm#include <limits.h> 82231200Smm#endif 83231200Smm#ifdef HAVE_STDLIB_H 84231200Smm#include <stdlib.h> 85231200Smm#endif 86231200Smm#ifdef HAVE_STRING_H 87231200Smm#include <string.h> 88231200Smm#endif 89231200Smm#ifdef HAVE_UNISTD_H 90231200Smm#include <unistd.h> 91231200Smm#endif 92238856Smm#ifdef HAVE_SYS_IOCTL_H 93238856Smm#include <sys/ioctl.h> 94238856Smm#endif 95231200Smm 96228753Smm#include "archive.h" 97228753Smm#include "archive_string.h" 98228753Smm#include "archive_entry.h" 99228753Smm#include "archive_private.h" 100228753Smm#include "archive_read_disk_private.h" 101228753Smm 102231200Smm#ifndef HAVE_FCHDIR 103231200Smm#error fchdir function required. 104231200Smm#endif 105231200Smm#ifndef O_BINARY 106231200Smm#define O_BINARY 0 107231200Smm#endif 108248616Smm#ifndef O_CLOEXEC 109248616Smm#define O_CLOEXEC 0 110248616Smm#endif 111231200Smm 112231200Smm/*- 113231200Smm * This is a new directory-walking system that addresses a number 114231200Smm * of problems I've had with fts(3). In particular, it has no 115231200Smm * pathname-length limits (other than the size of 'int'), handles 116231200Smm * deep logical traversals, uses considerably less memory, and has 117231200Smm * an opaque interface (easier to modify in the future). 118231200Smm * 119231200Smm * Internally, it keeps a single list of "tree_entry" items that 120231200Smm * represent filesystem objects that require further attention. 121231200Smm * Non-directories are not kept in memory: they are pulled from 122231200Smm * readdir(), returned to the client, then freed as soon as possible. 123231200Smm * Any directory entry to be traversed gets pushed onto the stack. 124231200Smm * 125231200Smm * There is surprisingly little information that needs to be kept for 126231200Smm * each item on the stack. Just the name, depth (represented here as the 127231200Smm * string length of the parent directory's pathname), and some markers 128231200Smm * indicating how to get back to the parent (via chdir("..") for a 129231200Smm * regular dir or via fchdir(2) for a symlink). 130231200Smm */ 131231200Smm/* 132231200Smm * TODO: 133231200Smm * 1) Loop checking. 134231200Smm * 3) Arbitrary logical traversals by closing/reopening intermediate fds. 135231200Smm */ 136231200Smm 137231200Smmstruct restore_time { 138231200Smm const char *name; 139231200Smm time_t mtime; 140231200Smm long mtime_nsec; 141231200Smm time_t atime; 142231200Smm long atime_nsec; 143231200Smm mode_t filetype; 144231200Smm int noatime; 145231200Smm}; 146231200Smm 147231200Smmstruct tree_entry { 148231200Smm int depth; 149231200Smm struct tree_entry *next; 150231200Smm struct tree_entry *parent; 151231200Smm struct archive_string name; 152231200Smm size_t dirname_length; 153231200Smm int64_t dev; 154231200Smm int64_t ino; 155231200Smm int flags; 156231200Smm int filesystem_id; 157231200Smm /* How to return back to the parent of a symlink. */ 158231200Smm int symlink_parent_fd; 159231200Smm /* How to restore time of a directory. */ 160231200Smm struct restore_time restore_time; 161231200Smm}; 162231200Smm 163231200Smmstruct filesystem { 164231200Smm int64_t dev; 165231200Smm int synthetic; 166231200Smm int remote; 167231200Smm int noatime; 168306322Smm#if defined(USE_READDIR_R) 169231200Smm size_t name_max; 170231200Smm#endif 171231200Smm long incr_xfer_size; 172231200Smm long max_xfer_size; 173231200Smm long min_xfer_size; 174231200Smm long xfer_align; 175231200Smm 176231200Smm /* 177231200Smm * Buffer used for reading file contents. 178231200Smm */ 179231200Smm /* Exactly allocated memory pointer. */ 180231200Smm unsigned char *allocation_ptr; 181231200Smm /* Pointer adjusted to the filesystem alignment . */ 182231200Smm unsigned char *buff; 183231200Smm size_t buff_size; 184231200Smm}; 185231200Smm 186231200Smm/* Definitions for tree_entry.flags bitmap. */ 187231200Smm#define isDir 1 /* This entry is a regular directory. */ 188231200Smm#define isDirLink 2 /* This entry is a symbolic link to a directory. */ 189231200Smm#define needsFirstVisit 4 /* This is an initial entry. */ 190231200Smm#define needsDescent 8 /* This entry needs to be previsited. */ 191231200Smm#define needsOpen 16 /* This is a directory that needs to be opened. */ 192231200Smm#define needsAscent 32 /* This entry needs to be postvisited. */ 193231200Smm 194231200Smm/* 195231200Smm * Local data for this package. 196231200Smm */ 197231200Smmstruct tree { 198231200Smm struct tree_entry *stack; 199231200Smm struct tree_entry *current; 200231200Smm DIR *d; 201231200Smm#define INVALID_DIR_HANDLE NULL 202231200Smm struct dirent *de; 203306322Smm#if defined(USE_READDIR_R) 204231200Smm struct dirent *dirent; 205231200Smm size_t dirent_allocated; 206231200Smm#endif 207231200Smm int flags; 208231200Smm int visit_type; 209231200Smm /* Error code from last failed operation. */ 210231200Smm int tree_errno; 211231200Smm 212231200Smm /* Dynamically-sized buffer for holding path */ 213231200Smm struct archive_string path; 214231200Smm 215231200Smm /* Last path element */ 216231200Smm const char *basename; 217231200Smm /* Leading dir length */ 218231200Smm size_t dirname_length; 219231200Smm 220231200Smm int depth; 221231200Smm int openCount; 222231200Smm int maxOpenCount; 223231200Smm int initial_dir_fd; 224231200Smm int working_dir_fd; 225231200Smm 226231200Smm struct stat lst; 227231200Smm struct stat st; 228231200Smm int descend; 229231200Smm int nlink; 230231200Smm /* How to restore time of a file. */ 231231200Smm struct restore_time restore_time; 232231200Smm 233231200Smm struct entry_sparse { 234231200Smm int64_t length; 235231200Smm int64_t offset; 236231200Smm } *sparse_list, *current_sparse; 237231200Smm int sparse_count; 238231200Smm int sparse_list_size; 239231200Smm 240231200Smm char initial_symlink_mode; 241231200Smm char symlink_mode; 242231200Smm struct filesystem *current_filesystem; 243231200Smm struct filesystem *filesystem_table; 244238856Smm int initial_filesystem_id; 245231200Smm int current_filesystem_id; 246231200Smm int max_filesystem_id; 247311042Smm int allocated_filesystem; 248231200Smm 249231200Smm int entry_fd; 250231200Smm int entry_eof; 251231200Smm int64_t entry_remaining_bytes; 252231200Smm int64_t entry_total; 253231200Smm unsigned char *entry_buff; 254231200Smm size_t entry_buff_size; 255231200Smm}; 256231200Smm 257231200Smm/* Definitions for tree.flags bitmap. */ 258231200Smm#define hasStat 16 /* The st entry is valid. */ 259231200Smm#define hasLstat 32 /* The lst entry is valid. */ 260231200Smm#define onWorkingDir 64 /* We are on the working dir where we are 261231200Smm * reading directory entry at this time. */ 262231200Smm#define needsRestoreTimes 128 263238856Smm#define onInitialDir 256 /* We are on the initial dir. */ 264231200Smm 265231200Smmstatic int 266231200Smmtree_dir_next_posix(struct tree *t); 267231200Smm 268231200Smm#ifdef HAVE_DIRENT_D_NAMLEN 269231200Smm/* BSD extension; avoids need for a strlen() call. */ 270231200Smm#define D_NAMELEN(dp) (dp)->d_namlen 271231200Smm#else 272231200Smm#define D_NAMELEN(dp) (strlen((dp)->d_name)) 273231200Smm#endif 274231200Smm 275231200Smm/* Initiate/terminate a tree traversal. */ 276231200Smmstatic struct tree *tree_open(const char *, int, int); 277231200Smmstatic struct tree *tree_reopen(struct tree *, const char *, int); 278231200Smmstatic void tree_close(struct tree *); 279231200Smmstatic void tree_free(struct tree *); 280231200Smmstatic void tree_push(struct tree *, const char *, int, int64_t, int64_t, 281231200Smm struct restore_time *); 282231200Smmstatic int tree_enter_initial_dir(struct tree *); 283231200Smmstatic int tree_enter_working_dir(struct tree *); 284231200Smmstatic int tree_current_dir_fd(struct tree *); 285231200Smm 286231200Smm/* 287231200Smm * tree_next() returns Zero if there is no next entry, non-zero if 288231200Smm * there is. Note that directories are visited three times. 289231200Smm * Directories are always visited first as part of enumerating their 290231200Smm * parent; that is a "regular" visit. If tree_descend() is invoked at 291231200Smm * that time, the directory is added to a work list and will 292231200Smm * subsequently be visited two more times: once just after descending 293231200Smm * into the directory ("postdescent") and again just after ascending 294231200Smm * back to the parent ("postascent"). 295231200Smm * 296231200Smm * TREE_ERROR_DIR is returned if the descent failed (because the 297231200Smm * directory couldn't be opened, for instance). This is returned 298231200Smm * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a 299231200Smm * fatal error, but it does imply that the relevant subtree won't be 300231200Smm * visited. TREE_ERROR_FATAL is returned for an error that left the 301231200Smm * traversal completely hosed. Right now, this is only returned for 302231200Smm * chdir() failures during ascent. 303231200Smm */ 304231200Smm#define TREE_REGULAR 1 305231200Smm#define TREE_POSTDESCENT 2 306231200Smm#define TREE_POSTASCENT 3 307231200Smm#define TREE_ERROR_DIR -1 308231200Smm#define TREE_ERROR_FATAL -2 309231200Smm 310231200Smmstatic int tree_next(struct tree *); 311231200Smm 312231200Smm/* 313231200Smm * Return information about the current entry. 314231200Smm */ 315231200Smm 316231200Smm/* 317231200Smm * The current full pathname, length of the full pathname, and a name 318231200Smm * that can be used to access the file. Because tree does use chdir 319231200Smm * extensively, the access path is almost never the same as the full 320231200Smm * current path. 321231200Smm * 322231200Smm * TODO: On platforms that support it, use openat()-style operations 323231200Smm * to eliminate the chdir() operations entirely while still supporting 324231200Smm * arbitrarily deep traversals. This makes access_path troublesome to 325231200Smm * support, of course, which means we'll need a rich enough interface 326231200Smm * that clients can function without it. (In particular, we'll need 327231200Smm * tree_current_open() that returns an open file descriptor.) 328231200Smm * 329231200Smm */ 330231200Smmstatic const char *tree_current_path(struct tree *); 331231200Smmstatic const char *tree_current_access_path(struct tree *); 332231200Smm 333231200Smm/* 334231200Smm * Request the lstat() or stat() data for the current path. Since the 335231200Smm * tree package needs to do some of this anyway, and caches the 336231200Smm * results, you should take advantage of it here if you need it rather 337231200Smm * than make a redundant stat() or lstat() call of your own. 338231200Smm */ 339231200Smmstatic const struct stat *tree_current_stat(struct tree *); 340231200Smmstatic const struct stat *tree_current_lstat(struct tree *); 341231200Smmstatic int tree_current_is_symblic_link_target(struct tree *); 342231200Smm 343231200Smm/* The following functions use tricks to avoid a certain number of 344231200Smm * stat()/lstat() calls. */ 345231200Smm/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */ 346231200Smmstatic int tree_current_is_physical_dir(struct tree *); 347231200Smm/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */ 348231200Smmstatic int tree_current_is_dir(struct tree *); 349231200Smmstatic int update_current_filesystem(struct archive_read_disk *a, 350231200Smm int64_t dev); 351231200Smmstatic int setup_current_filesystem(struct archive_read_disk *); 352231200Smmstatic int tree_target_is_same_as_parent(struct tree *, const struct stat *); 353231200Smm 354231200Smmstatic int _archive_read_disk_open(struct archive *, const char *); 355228905Smmstatic int _archive_read_free(struct archive *); 356228753Smmstatic int _archive_read_close(struct archive *); 357231200Smmstatic int _archive_read_data_block(struct archive *, 358231200Smm const void **, size_t *, int64_t *); 359302001Smmstatic int _archive_read_next_header(struct archive *, 360302001Smm struct archive_entry **); 361231200Smmstatic int _archive_read_next_header2(struct archive *, 362231200Smm struct archive_entry *); 363231200Smmstatic const char *trivial_lookup_gname(void *, int64_t gid); 364231200Smmstatic const char *trivial_lookup_uname(void *, int64_t uid); 365231200Smmstatic int setup_sparse(struct archive_read_disk *, struct archive_entry *); 366231200Smmstatic int close_and_restore_time(int fd, struct tree *, 367231200Smm struct restore_time *); 368238856Smmstatic int open_on_current_dir(struct tree *, const char *, int); 369248616Smmstatic int tree_dup(int); 370228753Smm 371231200Smm 372228753Smmstatic struct archive_vtable * 373228753Smmarchive_read_disk_vtable(void) 374228753Smm{ 375228753Smm static struct archive_vtable av; 376228753Smm static int inited = 0; 377228753Smm 378228753Smm if (!inited) { 379228905Smm av.archive_free = _archive_read_free; 380228753Smm av.archive_close = _archive_read_close; 381231200Smm av.archive_read_data_block = _archive_read_data_block; 382302001Smm av.archive_read_next_header = _archive_read_next_header; 383231200Smm av.archive_read_next_header2 = _archive_read_next_header2; 384231200Smm inited = 1; 385228753Smm } 386228753Smm return (&av); 387228753Smm} 388228753Smm 389228753Smmconst char * 390328828Smmarchive_read_disk_gname(struct archive *_a, la_int64_t gid) 391228753Smm{ 392228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 393231200Smm if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 394231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_gname")) 395231200Smm return (NULL); 396231200Smm if (a->lookup_gname == NULL) 397231200Smm return (NULL); 398231200Smm return ((*a->lookup_gname)(a->lookup_gname_data, gid)); 399228753Smm} 400228753Smm 401228753Smmconst char * 402328828Smmarchive_read_disk_uname(struct archive *_a, la_int64_t uid) 403228753Smm{ 404228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 405231200Smm if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 406231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_uname")) 407231200Smm return (NULL); 408231200Smm if (a->lookup_uname == NULL) 409231200Smm return (NULL); 410231200Smm return ((*a->lookup_uname)(a->lookup_uname_data, uid)); 411228753Smm} 412228753Smm 413228753Smmint 414228753Smmarchive_read_disk_set_gname_lookup(struct archive *_a, 415228753Smm void *private_data, 416328828Smm const char * (*lookup_gname)(void *private, la_int64_t gid), 417228753Smm void (*cleanup_gname)(void *private)) 418228753Smm{ 419228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 420231200Smm archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, 421228753Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup"); 422228753Smm 423228753Smm if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) 424228753Smm (a->cleanup_gname)(a->lookup_gname_data); 425228753Smm 426228753Smm a->lookup_gname = lookup_gname; 427228753Smm a->cleanup_gname = cleanup_gname; 428228753Smm a->lookup_gname_data = private_data; 429228753Smm return (ARCHIVE_OK); 430228753Smm} 431228753Smm 432228753Smmint 433228753Smmarchive_read_disk_set_uname_lookup(struct archive *_a, 434228753Smm void *private_data, 435328828Smm const char * (*lookup_uname)(void *private, la_int64_t uid), 436228753Smm void (*cleanup_uname)(void *private)) 437228753Smm{ 438228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 439231200Smm archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, 440228753Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup"); 441228753Smm 442228753Smm if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) 443228753Smm (a->cleanup_uname)(a->lookup_uname_data); 444228753Smm 445228753Smm a->lookup_uname = lookup_uname; 446228753Smm a->cleanup_uname = cleanup_uname; 447228753Smm a->lookup_uname_data = private_data; 448228753Smm return (ARCHIVE_OK); 449228753Smm} 450228753Smm 451228753Smm/* 452228753Smm * Create a new archive_read_disk object and initialize it with global state. 453228753Smm */ 454228753Smmstruct archive * 455228753Smmarchive_read_disk_new(void) 456228753Smm{ 457228753Smm struct archive_read_disk *a; 458228753Smm 459238856Smm a = (struct archive_read_disk *)calloc(1, sizeof(*a)); 460228753Smm if (a == NULL) 461228753Smm return (NULL); 462228753Smm a->archive.magic = ARCHIVE_READ_DISK_MAGIC; 463231200Smm a->archive.state = ARCHIVE_STATE_NEW; 464228753Smm a->archive.vtable = archive_read_disk_vtable(); 465302001Smm a->entry = archive_entry_new2(&a->archive); 466228753Smm a->lookup_uname = trivial_lookup_uname; 467228753Smm a->lookup_gname = trivial_lookup_gname; 468315433Smm a->flags = ARCHIVE_READDISK_MAC_COPYFILE; 469238856Smm a->open_on_current_dir = open_on_current_dir; 470238856Smm a->tree_current_dir_fd = tree_current_dir_fd; 471238856Smm a->tree_enter_working_dir = tree_enter_working_dir; 472228753Smm return (&a->archive); 473228753Smm} 474228753Smm 475228753Smmstatic int 476228905Smm_archive_read_free(struct archive *_a) 477228753Smm{ 478228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 479231200Smm int r; 480228753Smm 481231200Smm if (_a == NULL) 482231200Smm return (ARCHIVE_OK); 483231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 484231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); 485231200Smm 486231200Smm if (a->archive.state != ARCHIVE_STATE_CLOSED) 487231200Smm r = _archive_read_close(&a->archive); 488231200Smm else 489231200Smm r = ARCHIVE_OK; 490231200Smm 491231200Smm tree_free(a->tree); 492228753Smm if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) 493228753Smm (a->cleanup_gname)(a->lookup_gname_data); 494228753Smm if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) 495228753Smm (a->cleanup_uname)(a->lookup_uname_data); 496228753Smm archive_string_free(&a->archive.error_string); 497302001Smm archive_entry_free(a->entry); 498231200Smm a->archive.magic = 0; 499231200Smm __archive_clean(&a->archive); 500228753Smm free(a); 501231200Smm return (r); 502228753Smm} 503228753Smm 504228753Smmstatic int 505228753Smm_archive_read_close(struct archive *_a) 506228753Smm{ 507231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 508231200Smm 509231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 510231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); 511231200Smm 512231200Smm if (a->archive.state != ARCHIVE_STATE_FATAL) 513231200Smm a->archive.state = ARCHIVE_STATE_CLOSED; 514231200Smm 515231200Smm tree_close(a->tree); 516231200Smm 517228753Smm return (ARCHIVE_OK); 518228753Smm} 519228753Smm 520231200Smmstatic void 521231200Smmsetup_symlink_mode(struct archive_read_disk *a, char symlink_mode, 522231200Smm int follow_symlinks) 523231200Smm{ 524231200Smm a->symlink_mode = symlink_mode; 525231200Smm a->follow_symlinks = follow_symlinks; 526231200Smm if (a->tree != NULL) { 527231200Smm a->tree->initial_symlink_mode = a->symlink_mode; 528231200Smm a->tree->symlink_mode = a->symlink_mode; 529231200Smm } 530231200Smm} 531231200Smm 532228753Smmint 533228753Smmarchive_read_disk_set_symlink_logical(struct archive *_a) 534228753Smm{ 535228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 536231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 537231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical"); 538231200Smm setup_symlink_mode(a, 'L', 1); 539228753Smm return (ARCHIVE_OK); 540228753Smm} 541228753Smm 542228753Smmint 543228753Smmarchive_read_disk_set_symlink_physical(struct archive *_a) 544228753Smm{ 545228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 546231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 547231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical"); 548231200Smm setup_symlink_mode(a, 'P', 0); 549228753Smm return (ARCHIVE_OK); 550228753Smm} 551228753Smm 552228753Smmint 553228753Smmarchive_read_disk_set_symlink_hybrid(struct archive *_a) 554228753Smm{ 555228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 556231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 557231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid"); 558231200Smm setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */ 559228753Smm return (ARCHIVE_OK); 560228753Smm} 561228753Smm 562231200Smmint 563231200Smmarchive_read_disk_set_atime_restored(struct archive *_a) 564231200Smm{ 565231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 566231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 567231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime"); 568231200Smm#ifdef HAVE_UTIMES 569315433Smm a->flags |= ARCHIVE_READDISK_RESTORE_ATIME; 570231200Smm if (a->tree != NULL) 571231200Smm a->tree->flags |= needsRestoreTimes; 572231200Smm return (ARCHIVE_OK); 573231200Smm#else 574315433Smm /* Display warning and unset flag */ 575231200Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 576231200Smm "Cannot restore access time on this system"); 577315433Smm a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME; 578231200Smm return (ARCHIVE_WARN); 579231200Smm#endif 580231200Smm} 581231200Smm 582238856Smmint 583238856Smmarchive_read_disk_set_behavior(struct archive *_a, int flags) 584238856Smm{ 585238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 586238856Smm int r = ARCHIVE_OK; 587238856Smm 588238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 589238856Smm ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); 590238856Smm 591315433Smm a->flags = flags; 592315433Smm 593238856Smm if (flags & ARCHIVE_READDISK_RESTORE_ATIME) 594238856Smm r = archive_read_disk_set_atime_restored(_a); 595238856Smm else { 596238856Smm if (a->tree != NULL) 597238856Smm a->tree->flags &= ~needsRestoreTimes; 598238856Smm } 599238856Smm return (r); 600238856Smm} 601238856Smm 602228753Smm/* 603228753Smm * Trivial implementations of gname/uname lookup functions. 604228753Smm * These are normally overridden by the client, but these stub 605228753Smm * versions ensure that we always have something that works. 606228753Smm */ 607228753Smmstatic const char * 608231200Smmtrivial_lookup_gname(void *private_data, int64_t gid) 609228753Smm{ 610228753Smm (void)private_data; /* UNUSED */ 611228753Smm (void)gid; /* UNUSED */ 612228753Smm return (NULL); 613228753Smm} 614228753Smm 615228753Smmstatic const char * 616231200Smmtrivial_lookup_uname(void *private_data, int64_t uid) 617228753Smm{ 618228753Smm (void)private_data; /* UNUSED */ 619228753Smm (void)uid; /* UNUSED */ 620228753Smm return (NULL); 621228753Smm} 622231200Smm 623231200Smm/* 624231200Smm * Allocate memory for the reading buffer adjusted to the filesystem 625231200Smm * alignment. 626231200Smm */ 627231200Smmstatic int 628231200Smmsetup_suitable_read_buffer(struct archive_read_disk *a) 629231200Smm{ 630231200Smm struct tree *t = a->tree; 631231200Smm struct filesystem *cf = t->current_filesystem; 632231200Smm size_t asize; 633231200Smm size_t s; 634231200Smm 635231200Smm if (cf->allocation_ptr == NULL) { 636231200Smm /* If we couldn't get a filesystem alignment, 637231200Smm * we use 4096 as default value but we won't use 638231200Smm * O_DIRECT to open() and openat() operations. */ 639231200Smm long xfer_align = (cf->xfer_align == -1)?4096:cf->xfer_align; 640231200Smm 641231200Smm if (cf->max_xfer_size != -1) 642231200Smm asize = cf->max_xfer_size + xfer_align; 643231200Smm else { 644231200Smm long incr = cf->incr_xfer_size; 645231200Smm /* Some platform does not set a proper value to 646231200Smm * incr_xfer_size.*/ 647231200Smm if (incr < 0) 648231200Smm incr = cf->min_xfer_size; 649231200Smm if (cf->min_xfer_size < 0) { 650231200Smm incr = xfer_align; 651231200Smm asize = xfer_align; 652231200Smm } else 653231200Smm asize = cf->min_xfer_size; 654231200Smm 655231200Smm /* Increase a buffer size up to 64K bytes in 656313571Smm * a proper increment size. */ 657231200Smm while (asize < 1024*64) 658231200Smm asize += incr; 659231200Smm /* Take a margin to adjust to the filesystem 660231200Smm * alignment. */ 661231200Smm asize += xfer_align; 662231200Smm } 663231200Smm cf->allocation_ptr = malloc(asize); 664231200Smm if (cf->allocation_ptr == NULL) { 665231200Smm archive_set_error(&a->archive, ENOMEM, 666231200Smm "Couldn't allocate memory"); 667231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 668231200Smm return (ARCHIVE_FATAL); 669231200Smm } 670231200Smm 671231200Smm /* 672231200Smm * Calculate proper address for the filesystem. 673231200Smm */ 674231200Smm s = (uintptr_t)cf->allocation_ptr; 675231200Smm s %= xfer_align; 676231200Smm if (s > 0) 677231200Smm s = xfer_align - s; 678231200Smm 679231200Smm /* 680231200Smm * Set a read buffer pointer in the proper alignment of 681231200Smm * the current filesystem. 682231200Smm */ 683231200Smm cf->buff = cf->allocation_ptr + s; 684231200Smm cf->buff_size = asize - xfer_align; 685231200Smm } 686231200Smm return (ARCHIVE_OK); 687231200Smm} 688231200Smm 689231200Smmstatic int 690231200Smm_archive_read_data_block(struct archive *_a, const void **buff, 691231200Smm size_t *size, int64_t *offset) 692231200Smm{ 693231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 694231200Smm struct tree *t = a->tree; 695231200Smm int r; 696231200Smm ssize_t bytes; 697358090Smm int64_t sparse_bytes; 698231200Smm size_t buffbytes; 699302001Smm int empty_sparse_region = 0; 700231200Smm 701231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 702231200Smm "archive_read_data_block"); 703231200Smm 704231200Smm if (t->entry_eof || t->entry_remaining_bytes <= 0) { 705231200Smm r = ARCHIVE_EOF; 706231200Smm goto abort_read_data; 707231200Smm } 708231200Smm 709231200Smm /* 710231200Smm * Open the current file. 711231200Smm */ 712231200Smm if (t->entry_fd < 0) { 713248616Smm int flags = O_RDONLY | O_BINARY | O_CLOEXEC; 714231200Smm 715231200Smm /* 716231200Smm * Eliminate or reduce cache effects if we can. 717231200Smm * 718231200Smm * Carefully consider this to be enabled. 719231200Smm */ 720231200Smm#if defined(O_DIRECT) && 0/* Disabled for now */ 721231200Smm if (t->current_filesystem->xfer_align != -1 && 722231200Smm t->nlink == 1) 723231200Smm flags |= O_DIRECT; 724231200Smm#endif 725231200Smm#if defined(O_NOATIME) 726231200Smm /* 727231200Smm * Linux has O_NOATIME flag; use it if we need. 728231200Smm */ 729231200Smm if ((t->flags & needsRestoreTimes) != 0 && 730231200Smm t->restore_time.noatime == 0) 731231200Smm flags |= O_NOATIME; 732231200Smm#endif 733358090Smm t->entry_fd = open_on_current_dir(t, 734358090Smm tree_current_access_path(t), flags); 735358090Smm __archive_ensure_cloexec_flag(t->entry_fd); 736231200Smm#if defined(O_NOATIME) 737358090Smm /* 738358090Smm * When we did open the file with O_NOATIME flag, 739358090Smm * if successful, set 1 to t->restore_time.noatime 740358090Smm * not to restore an atime of the file later. 741358090Smm * if failed by EPERM, retry it without O_NOATIME flag. 742358090Smm */ 743358090Smm if (flags & O_NOATIME) { 744358090Smm if (t->entry_fd >= 0) 745358090Smm t->restore_time.noatime = 1; 746358090Smm else if (errno == EPERM) 747358090Smm flags &= ~O_NOATIME; 748358090Smm } 749231200Smm#endif 750231200Smm if (t->entry_fd < 0) { 751231200Smm archive_set_error(&a->archive, errno, 752231200Smm "Couldn't open %s", tree_current_path(t)); 753231200Smm r = ARCHIVE_FAILED; 754231200Smm tree_enter_initial_dir(t); 755231200Smm goto abort_read_data; 756231200Smm } 757231200Smm tree_enter_initial_dir(t); 758231200Smm } 759231200Smm 760231200Smm /* 761231200Smm * Allocate read buffer if not allocated. 762231200Smm */ 763231200Smm if (t->current_filesystem->allocation_ptr == NULL) { 764231200Smm r = setup_suitable_read_buffer(a); 765231200Smm if (r != ARCHIVE_OK) { 766231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 767231200Smm goto abort_read_data; 768231200Smm } 769231200Smm } 770231200Smm t->entry_buff = t->current_filesystem->buff; 771231200Smm t->entry_buff_size = t->current_filesystem->buff_size; 772231200Smm 773231200Smm buffbytes = t->entry_buff_size; 774248616Smm if ((int64_t)buffbytes > t->current_sparse->length) 775248616Smm buffbytes = t->current_sparse->length; 776231200Smm 777302001Smm if (t->current_sparse->length == 0) 778302001Smm empty_sparse_region = 1; 779302001Smm 780231200Smm /* 781231200Smm * Skip hole. 782231200Smm * TODO: Should we consider t->current_filesystem->xfer_align? 783231200Smm */ 784231200Smm if (t->current_sparse->offset > t->entry_total) { 785231200Smm if (lseek(t->entry_fd, 786231200Smm (off_t)t->current_sparse->offset, SEEK_SET) < 0) { 787231200Smm archive_set_error(&a->archive, errno, "Seek error"); 788231200Smm r = ARCHIVE_FATAL; 789231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 790231200Smm goto abort_read_data; 791231200Smm } 792358090Smm sparse_bytes = t->current_sparse->offset - t->entry_total; 793358090Smm t->entry_remaining_bytes -= sparse_bytes; 794358090Smm t->entry_total += sparse_bytes; 795231200Smm } 796231200Smm 797231200Smm /* 798231200Smm * Read file contents. 799231200Smm */ 800231200Smm if (buffbytes > 0) { 801231200Smm bytes = read(t->entry_fd, t->entry_buff, buffbytes); 802231200Smm if (bytes < 0) { 803231200Smm archive_set_error(&a->archive, errno, "Read error"); 804231200Smm r = ARCHIVE_FATAL; 805231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 806231200Smm goto abort_read_data; 807231200Smm } 808231200Smm } else 809231200Smm bytes = 0; 810302001Smm /* 811302001Smm * Return an EOF unless we've read a leading empty sparse region, which 812302001Smm * is used to represent fully-sparse files. 813302001Smm */ 814302001Smm if (bytes == 0 && !empty_sparse_region) { 815231200Smm /* Get EOF */ 816231200Smm t->entry_eof = 1; 817231200Smm r = ARCHIVE_EOF; 818231200Smm goto abort_read_data; 819231200Smm } 820231200Smm *buff = t->entry_buff; 821231200Smm *size = bytes; 822231200Smm *offset = t->entry_total; 823231200Smm t->entry_total += bytes; 824231200Smm t->entry_remaining_bytes -= bytes; 825231200Smm if (t->entry_remaining_bytes == 0) { 826231200Smm /* Close the current file descriptor */ 827231200Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 828231200Smm t->entry_fd = -1; 829231200Smm t->entry_eof = 1; 830231200Smm } 831231200Smm t->current_sparse->offset += bytes; 832231200Smm t->current_sparse->length -= bytes; 833231200Smm if (t->current_sparse->length == 0 && !t->entry_eof) 834231200Smm t->current_sparse++; 835231200Smm return (ARCHIVE_OK); 836231200Smm 837231200Smmabort_read_data: 838231200Smm *buff = NULL; 839231200Smm *size = 0; 840231200Smm *offset = t->entry_total; 841231200Smm if (t->entry_fd >= 0) { 842231200Smm /* Close the current file descriptor */ 843231200Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 844231200Smm t->entry_fd = -1; 845231200Smm } 846231200Smm return (r); 847231200Smm} 848231200Smm 849231200Smmstatic int 850238856Smmnext_entry(struct archive_read_disk *a, struct tree *t, 851238856Smm struct archive_entry *entry) 852231200Smm{ 853231200Smm const struct stat *st; /* info to use for this entry */ 854231200Smm const struct stat *lst;/* lstat() information */ 855238856Smm const char *name; 856344674Smm int delayed, delayed_errno, descend, r; 857344674Smm struct archive_string delayed_str; 858231200Smm 859344674Smm delayed = ARCHIVE_OK; 860344674Smm delayed_errno = 0; 861344674Smm archive_string_init(&delayed_str); 862344674Smm 863231200Smm st = NULL; 864231200Smm lst = NULL; 865238856Smm t->descend = 0; 866231200Smm do { 867231200Smm switch (tree_next(t)) { 868231200Smm case TREE_ERROR_FATAL: 869231200Smm archive_set_error(&a->archive, t->tree_errno, 870231200Smm "%s: Unable to continue traversing directory tree", 871231200Smm tree_current_path(t)); 872231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 873231200Smm tree_enter_initial_dir(t); 874231200Smm return (ARCHIVE_FATAL); 875231200Smm case TREE_ERROR_DIR: 876231200Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 877231200Smm "%s: Couldn't visit directory", 878231200Smm tree_current_path(t)); 879231200Smm tree_enter_initial_dir(t); 880231200Smm return (ARCHIVE_FAILED); 881231200Smm case 0: 882231200Smm tree_enter_initial_dir(t); 883231200Smm return (ARCHIVE_EOF); 884231200Smm case TREE_POSTDESCENT: 885231200Smm case TREE_POSTASCENT: 886231200Smm break; 887231200Smm case TREE_REGULAR: 888231200Smm lst = tree_current_lstat(t); 889231200Smm if (lst == NULL) { 890344674Smm if (errno == ENOENT && t->depth > 0) { 891344674Smm delayed = ARCHIVE_WARN; 892344674Smm delayed_errno = errno; 893344674Smm if (delayed_str.length == 0) { 894344674Smm archive_string_sprintf(&delayed_str, 895344674Smm "%s", tree_current_path(t)); 896344674Smm } else { 897344674Smm archive_string_sprintf(&delayed_str, 898344674Smm " %s", tree_current_path(t)); 899344674Smm } 900344674Smm } else { 901231200Smm archive_set_error(&a->archive, errno, 902231200Smm "%s: Cannot stat", 903231200Smm tree_current_path(t)); 904231200Smm tree_enter_initial_dir(t); 905231200Smm return (ARCHIVE_FAILED); 906344674Smm } 907231200Smm } 908231200Smm break; 909348608Smm } 910231200Smm } while (lst == NULL); 911231200Smm 912238856Smm#ifdef __APPLE__ 913315433Smm if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) { 914238856Smm /* If we're using copyfile(), ignore "._XXX" files. */ 915238856Smm const char *bname = strrchr(tree_current_path(t), '/'); 916238856Smm if (bname == NULL) 917238856Smm bname = tree_current_path(t); 918238856Smm else 919238856Smm ++bname; 920238856Smm if (bname[0] == '.' && bname[1] == '_') 921238856Smm return (ARCHIVE_RETRY); 922238856Smm } 923238856Smm#endif 924238856Smm 925238856Smm archive_entry_copy_pathname(entry, tree_current_path(t)); 926231200Smm /* 927238856Smm * Perform path matching. 928238856Smm */ 929238856Smm if (a->matching) { 930238856Smm r = archive_match_path_excluded(a->matching, entry); 931238856Smm if (r < 0) { 932238856Smm archive_set_error(&(a->archive), errno, 933305192Smm "Failed : %s", archive_error_string(a->matching)); 934238856Smm return (r); 935238856Smm } 936238856Smm if (r) { 937238856Smm if (a->excluded_cb_func) 938238856Smm a->excluded_cb_func(&(a->archive), 939238856Smm a->excluded_cb_data, entry); 940238856Smm return (ARCHIVE_RETRY); 941238856Smm } 942238856Smm } 943238856Smm 944238856Smm /* 945231200Smm * Distinguish 'L'/'P'/'H' symlink following. 946231200Smm */ 947231200Smm switch(t->symlink_mode) { 948231200Smm case 'H': 949231200Smm /* 'H': After the first item, rest like 'P'. */ 950231200Smm t->symlink_mode = 'P'; 951231200Smm /* 'H': First item (from command line) like 'L'. */ 952231200Smm /* FALLTHROUGH */ 953231200Smm case 'L': 954231200Smm /* 'L': Do descend through a symlink to dir. */ 955231200Smm descend = tree_current_is_dir(t); 956231200Smm /* 'L': Follow symlinks to files. */ 957231200Smm a->symlink_mode = 'L'; 958231200Smm a->follow_symlinks = 1; 959231200Smm /* 'L': Archive symlinks as targets, if we can. */ 960231200Smm st = tree_current_stat(t); 961231200Smm if (st != NULL && !tree_target_is_same_as_parent(t, st)) 962231200Smm break; 963231200Smm /* If stat fails, we have a broken symlink; 964231200Smm * in that case, don't follow the link. */ 965231200Smm /* FALLTHROUGH */ 966231200Smm default: 967231200Smm /* 'P': Don't descend through a symlink to dir. */ 968231200Smm descend = tree_current_is_physical_dir(t); 969231200Smm /* 'P': Don't follow symlinks to files. */ 970231200Smm a->symlink_mode = 'P'; 971231200Smm a->follow_symlinks = 0; 972231200Smm /* 'P': Archive symlinks as symlinks. */ 973231200Smm st = lst; 974231200Smm break; 975231200Smm } 976231200Smm 977231200Smm if (update_current_filesystem(a, st->st_dev) != ARCHIVE_OK) { 978231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 979231200Smm tree_enter_initial_dir(t); 980231200Smm return (ARCHIVE_FATAL); 981231200Smm } 982238856Smm if (t->initial_filesystem_id == -1) 983238856Smm t->initial_filesystem_id = t->current_filesystem_id; 984315433Smm if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) { 985238856Smm if (t->initial_filesystem_id != t->current_filesystem_id) 986281044Sbdrewery descend = 0; 987238856Smm } 988231200Smm t->descend = descend; 989231200Smm 990238856Smm /* 991238856Smm * Honor nodump flag. 992238856Smm * If the file is marked with nodump flag, do not return this entry. 993238856Smm */ 994315433Smm if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) { 995238856Smm#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 996238856Smm if (st->st_flags & UF_NODUMP) 997238856Smm return (ARCHIVE_RETRY); 998315433Smm#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \ 999315433Smm defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \ 1000315433Smm (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \ 1001315433Smm defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)) 1002238856Smm if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) { 1003248616Smm int stflags; 1004238856Smm 1005238856Smm t->entry_fd = open_on_current_dir(t, 1006248616Smm tree_current_access_path(t), 1007248616Smm O_RDONLY | O_NONBLOCK | O_CLOEXEC); 1008248616Smm __archive_ensure_cloexec_flag(t->entry_fd); 1009238856Smm if (t->entry_fd >= 0) { 1010315433Smm r = ioctl(t->entry_fd, 1011315433Smm#ifdef FS_IOC_GETFLAGS 1012315433Smm FS_IOC_GETFLAGS, 1013315433Smm#else 1014315433Smm EXT2_IOC_GETFLAGS, 1015315433Smm#endif 1016238856Smm &stflags); 1017315433Smm#ifdef FS_NODUMP_FL 1018315433Smm if (r == 0 && (stflags & FS_NODUMP_FL) != 0) 1019315433Smm#else 1020238856Smm if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0) 1021315433Smm#endif 1022238856Smm return (ARCHIVE_RETRY); 1023238856Smm } 1024238856Smm } 1025238856Smm#endif 1026238856Smm } 1027238856Smm 1028231200Smm archive_entry_copy_stat(entry, st); 1029231200Smm 1030238856Smm /* Save the times to be restored. This must be in before 1031238856Smm * calling archive_read_disk_descend() or any chance of it, 1032311042Smm * especially, invoking a callback. */ 1033231200Smm t->restore_time.mtime = archive_entry_mtime(entry); 1034231200Smm t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry); 1035231200Smm t->restore_time.atime = archive_entry_atime(entry); 1036231200Smm t->restore_time.atime_nsec = archive_entry_atime_nsec(entry); 1037231200Smm t->restore_time.filetype = archive_entry_filetype(entry); 1038231200Smm t->restore_time.noatime = t->current_filesystem->noatime; 1039231200Smm 1040231200Smm /* 1041238856Smm * Perform time matching. 1042231200Smm */ 1043238856Smm if (a->matching) { 1044238856Smm r = archive_match_time_excluded(a->matching, entry); 1045238856Smm if (r < 0) { 1046238856Smm archive_set_error(&(a->archive), errno, 1047305192Smm "Failed : %s", archive_error_string(a->matching)); 1048238856Smm return (r); 1049238856Smm } 1050238856Smm if (r) { 1051238856Smm if (a->excluded_cb_func) 1052238856Smm a->excluded_cb_func(&(a->archive), 1053238856Smm a->excluded_cb_data, entry); 1054238856Smm return (ARCHIVE_RETRY); 1055238856Smm } 1056238856Smm } 1057231200Smm 1058238856Smm /* Lookup uname/gname */ 1059238856Smm name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); 1060238856Smm if (name != NULL) 1061238856Smm archive_entry_copy_uname(entry, name); 1062238856Smm name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); 1063238856Smm if (name != NULL) 1064238856Smm archive_entry_copy_gname(entry, name); 1065231200Smm 1066231200Smm /* 1067238856Smm * Perform owner matching. 1068238856Smm */ 1069238856Smm if (a->matching) { 1070238856Smm r = archive_match_owner_excluded(a->matching, entry); 1071238856Smm if (r < 0) { 1072238856Smm archive_set_error(&(a->archive), errno, 1073305192Smm "Failed : %s", archive_error_string(a->matching)); 1074238856Smm return (r); 1075238856Smm } 1076238856Smm if (r) { 1077238856Smm if (a->excluded_cb_func) 1078238856Smm a->excluded_cb_func(&(a->archive), 1079238856Smm a->excluded_cb_data, entry); 1080238856Smm return (ARCHIVE_RETRY); 1081238856Smm } 1082238856Smm } 1083238856Smm 1084238856Smm /* 1085238856Smm * Invoke a meta data filter callback. 1086238856Smm */ 1087238856Smm if (a->metadata_filter_func) { 1088238856Smm if (!a->metadata_filter_func(&(a->archive), 1089238856Smm a->metadata_filter_data, entry)) 1090238856Smm return (ARCHIVE_RETRY); 1091238856Smm } 1092238856Smm 1093238856Smm /* 1094231200Smm * Populate the archive_entry with metadata from the disk. 1095231200Smm */ 1096238856Smm archive_entry_copy_sourcepath(entry, tree_current_access_path(t)); 1097238856Smm r = archive_read_disk_entry_from_file(&(a->archive), entry, 1098238856Smm t->entry_fd, st); 1099231200Smm 1100344674Smm if (r == ARCHIVE_OK) { 1101344674Smm r = delayed; 1102344674Smm if (r != ARCHIVE_OK) { 1103344674Smm archive_string_sprintf(&delayed_str, ": %s", 1104344674Smm "File removed before we read it"); 1105344674Smm archive_set_error(&(a->archive), delayed_errno, 1106344674Smm "%s", delayed_str.s); 1107344674Smm } 1108344674Smm } 1109358090Smm archive_string_free(&delayed_str); 1110344674Smm 1111238856Smm return (r); 1112238856Smm} 1113231200Smm 1114238856Smmstatic int 1115302001Smm_archive_read_next_header(struct archive *_a, struct archive_entry **entryp) 1116302001Smm{ 1117302001Smm int ret; 1118302001Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1119302001Smm *entryp = NULL; 1120302001Smm ret = _archive_read_next_header2(_a, a->entry); 1121302001Smm *entryp = a->entry; 1122302001Smm return ret; 1123302001Smm} 1124302001Smm 1125302001Smmstatic int 1126238856Smm_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) 1127238856Smm{ 1128238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1129238856Smm struct tree *t; 1130238856Smm int r; 1131238856Smm 1132238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1133238856Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1134238856Smm "archive_read_next_header2"); 1135238856Smm 1136238856Smm t = a->tree; 1137238856Smm if (t->entry_fd >= 0) { 1138238856Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 1139238856Smm t->entry_fd = -1; 1140238856Smm } 1141238856Smm 1142349901Smm archive_entry_clear(entry); 1143349901Smm 1144238856Smm for (;;) { 1145238856Smm r = next_entry(a, t, entry); 1146238856Smm if (t->entry_fd >= 0) { 1147238856Smm close(t->entry_fd); 1148238856Smm t->entry_fd = -1; 1149238856Smm } 1150238856Smm 1151238856Smm if (r == ARCHIVE_RETRY) { 1152238856Smm archive_entry_clear(entry); 1153238856Smm continue; 1154238856Smm } 1155238856Smm break; 1156238856Smm } 1157238856Smm 1158231200Smm /* Return to the initial directory. */ 1159231200Smm tree_enter_initial_dir(t); 1160231200Smm 1161231200Smm /* 1162231200Smm * EOF and FATAL are persistent at this layer. By 1163231200Smm * modifying the state, we guarantee that future calls to 1164231200Smm * read a header or read data will fail. 1165231200Smm */ 1166231200Smm switch (r) { 1167231200Smm case ARCHIVE_EOF: 1168231200Smm a->archive.state = ARCHIVE_STATE_EOF; 1169231200Smm break; 1170231200Smm case ARCHIVE_OK: 1171231200Smm case ARCHIVE_WARN: 1172238856Smm /* Overwrite the sourcepath based on the initial directory. */ 1173238856Smm archive_entry_copy_sourcepath(entry, tree_current_path(t)); 1174231200Smm t->entry_total = 0; 1175231200Smm if (archive_entry_filetype(entry) == AE_IFREG) { 1176231200Smm t->nlink = archive_entry_nlink(entry); 1177231200Smm t->entry_remaining_bytes = archive_entry_size(entry); 1178231200Smm t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0; 1179231200Smm if (!t->entry_eof && 1180231200Smm setup_sparse(a, entry) != ARCHIVE_OK) 1181231200Smm return (ARCHIVE_FATAL); 1182231200Smm } else { 1183231200Smm t->entry_remaining_bytes = 0; 1184231200Smm t->entry_eof = 1; 1185231200Smm } 1186231200Smm a->archive.state = ARCHIVE_STATE_DATA; 1187231200Smm break; 1188231200Smm case ARCHIVE_RETRY: 1189231200Smm break; 1190231200Smm case ARCHIVE_FATAL: 1191231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1192231200Smm break; 1193231200Smm } 1194231200Smm 1195302001Smm __archive_reset_read_data(&a->archive); 1196231200Smm return (r); 1197231200Smm} 1198231200Smm 1199231200Smmstatic int 1200231200Smmsetup_sparse(struct archive_read_disk *a, struct archive_entry *entry) 1201231200Smm{ 1202231200Smm struct tree *t = a->tree; 1203231200Smm int64_t length, offset; 1204231200Smm int i; 1205231200Smm 1206231200Smm t->sparse_count = archive_entry_sparse_reset(entry); 1207231200Smm if (t->sparse_count+1 > t->sparse_list_size) { 1208231200Smm free(t->sparse_list); 1209231200Smm t->sparse_list_size = t->sparse_count + 1; 1210231200Smm t->sparse_list = malloc(sizeof(t->sparse_list[0]) * 1211231200Smm t->sparse_list_size); 1212231200Smm if (t->sparse_list == NULL) { 1213231200Smm t->sparse_list_size = 0; 1214231200Smm archive_set_error(&a->archive, ENOMEM, 1215231200Smm "Can't allocate data"); 1216231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1217231200Smm return (ARCHIVE_FATAL); 1218231200Smm } 1219231200Smm } 1220231200Smm for (i = 0; i < t->sparse_count; i++) { 1221231200Smm archive_entry_sparse_next(entry, &offset, &length); 1222231200Smm t->sparse_list[i].offset = offset; 1223231200Smm t->sparse_list[i].length = length; 1224231200Smm } 1225231200Smm if (i == 0) { 1226231200Smm t->sparse_list[i].offset = 0; 1227231200Smm t->sparse_list[i].length = archive_entry_size(entry); 1228231200Smm } else { 1229231200Smm t->sparse_list[i].offset = archive_entry_size(entry); 1230231200Smm t->sparse_list[i].length = 0; 1231231200Smm } 1232231200Smm t->current_sparse = t->sparse_list; 1233231200Smm 1234231200Smm return (ARCHIVE_OK); 1235231200Smm} 1236231200Smm 1237238856Smmint 1238238856Smmarchive_read_disk_set_matching(struct archive *_a, struct archive *_ma, 1239238856Smm void (*_excluded_func)(struct archive *, void *, struct archive_entry *), 1240238856Smm void *_client_data) 1241238856Smm{ 1242238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1243238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1244238856Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); 1245238856Smm a->matching = _ma; 1246238856Smm a->excluded_cb_func = _excluded_func; 1247238856Smm a->excluded_cb_data = _client_data; 1248238856Smm return (ARCHIVE_OK); 1249238856Smm} 1250238856Smm 1251238856Smmint 1252238856Smmarchive_read_disk_set_metadata_filter_callback(struct archive *_a, 1253238856Smm int (*_metadata_filter_func)(struct archive *, void *, 1254238856Smm struct archive_entry *), void *_client_data) 1255238856Smm{ 1256238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1257238856Smm 1258238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, 1259238856Smm "archive_read_disk_set_metadata_filter_callback"); 1260238856Smm 1261238856Smm a->metadata_filter_func = _metadata_filter_func; 1262238856Smm a->metadata_filter_data = _client_data; 1263238856Smm return (ARCHIVE_OK); 1264238856Smm} 1265238856Smm 1266238856Smmint 1267238856Smmarchive_read_disk_can_descend(struct archive *_a) 1268238856Smm{ 1269238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1270238856Smm struct tree *t = a->tree; 1271238856Smm 1272238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1273238856Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1274238856Smm "archive_read_disk_can_descend"); 1275238856Smm 1276238856Smm return (t->visit_type == TREE_REGULAR && t->descend); 1277238856Smm} 1278238856Smm 1279231200Smm/* 1280231200Smm * Called by the client to mark the directory just returned from 1281231200Smm * tree_next() as needing to be visited. 1282231200Smm */ 1283231200Smmint 1284231200Smmarchive_read_disk_descend(struct archive *_a) 1285231200Smm{ 1286231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1287231200Smm struct tree *t = a->tree; 1288231200Smm 1289238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1290238856Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1291231200Smm "archive_read_disk_descend"); 1292231200Smm 1293238856Smm if (t->visit_type != TREE_REGULAR || !t->descend) 1294238856Smm return (ARCHIVE_OK); 1295231200Smm 1296348608Smm /* 1297348608Smm * We must not treat the initial specified path as a physical dir, 1298348608Smm * because if we do then we will try and ascend out of it by opening 1299348608Smm * ".." which is (a) wrong and (b) causes spurious permissions errors 1300348608Smm * if ".." is not readable by us. Instead, treat it as if it were a 1301348608Smm * symlink. (This uses an extra fd, but it can only happen once at the 1302348608Smm * top level of a traverse.) But we can't necessarily assume t->st is 1303348608Smm * valid here (though t->lst is), which complicates the logic a 1304348608Smm * little. 1305348608Smm */ 1306231200Smm if (tree_current_is_physical_dir(t)) { 1307231200Smm tree_push(t, t->basename, t->current_filesystem_id, 1308231200Smm t->lst.st_dev, t->lst.st_ino, &t->restore_time); 1309348608Smm if (t->stack->parent->parent != NULL) 1310348608Smm t->stack->flags |= isDir; 1311348608Smm else 1312348608Smm t->stack->flags |= isDirLink; 1313231200Smm } else if (tree_current_is_dir(t)) { 1314231200Smm tree_push(t, t->basename, t->current_filesystem_id, 1315231200Smm t->st.st_dev, t->st.st_ino, &t->restore_time); 1316231200Smm t->stack->flags |= isDirLink; 1317231200Smm } 1318231200Smm t->descend = 0; 1319231200Smm return (ARCHIVE_OK); 1320231200Smm} 1321231200Smm 1322231200Smmint 1323231200Smmarchive_read_disk_open(struct archive *_a, const char *pathname) 1324231200Smm{ 1325231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1326231200Smm 1327231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1328231200Smm ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, 1329231200Smm "archive_read_disk_open"); 1330231200Smm archive_clear_error(&a->archive); 1331231200Smm 1332231200Smm return (_archive_read_disk_open(_a, pathname)); 1333231200Smm} 1334231200Smm 1335231200Smmint 1336231200Smmarchive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) 1337231200Smm{ 1338231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1339231200Smm struct archive_string path; 1340231200Smm int ret; 1341231200Smm 1342231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1343231200Smm ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, 1344231200Smm "archive_read_disk_open_w"); 1345231200Smm archive_clear_error(&a->archive); 1346231200Smm 1347231200Smm /* Make a char string from a wchar_t string. */ 1348231200Smm archive_string_init(&path); 1349231200Smm if (archive_string_append_from_wcs(&path, pathname, 1350231200Smm wcslen(pathname)) != 0) { 1351238856Smm if (errno == ENOMEM) 1352238856Smm archive_set_error(&a->archive, ENOMEM, 1353238856Smm "Can't allocate memory"); 1354238856Smm else 1355238856Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1356238856Smm "Can't convert a path to a char string"); 1357231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1358231200Smm ret = ARCHIVE_FATAL; 1359231200Smm } else 1360231200Smm ret = _archive_read_disk_open(_a, path.s); 1361231200Smm 1362231200Smm archive_string_free(&path); 1363231200Smm return (ret); 1364231200Smm} 1365231200Smm 1366231200Smmstatic int 1367231200Smm_archive_read_disk_open(struct archive *_a, const char *pathname) 1368231200Smm{ 1369231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1370231200Smm 1371231200Smm if (a->tree != NULL) 1372315433Smm a->tree = tree_reopen(a->tree, pathname, 1373315433Smm a->flags & ARCHIVE_READDISK_RESTORE_ATIME); 1374231200Smm else 1375231200Smm a->tree = tree_open(pathname, a->symlink_mode, 1376315433Smm a->flags & ARCHIVE_READDISK_RESTORE_ATIME); 1377231200Smm if (a->tree == NULL) { 1378231200Smm archive_set_error(&a->archive, ENOMEM, 1379231200Smm "Can't allocate tar data"); 1380231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1381231200Smm return (ARCHIVE_FATAL); 1382231200Smm } 1383231200Smm a->archive.state = ARCHIVE_STATE_HEADER; 1384231200Smm 1385231200Smm return (ARCHIVE_OK); 1386231200Smm} 1387231200Smm 1388231200Smm/* 1389231200Smm * Return a current filesystem ID which is index of the filesystem entry 1390231200Smm * you've visited through archive_read_disk. 1391231200Smm */ 1392231200Smmint 1393231200Smmarchive_read_disk_current_filesystem(struct archive *_a) 1394231200Smm{ 1395231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1396231200Smm 1397231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 1398231200Smm "archive_read_disk_current_filesystem"); 1399231200Smm 1400231200Smm return (a->tree->current_filesystem_id); 1401231200Smm} 1402231200Smm 1403231200Smmstatic int 1404231200Smmupdate_current_filesystem(struct archive_read_disk *a, int64_t dev) 1405231200Smm{ 1406231200Smm struct tree *t = a->tree; 1407231200Smm int i, fid; 1408231200Smm 1409231200Smm if (t->current_filesystem != NULL && 1410231200Smm t->current_filesystem->dev == dev) 1411231200Smm return (ARCHIVE_OK); 1412231200Smm 1413231200Smm for (i = 0; i < t->max_filesystem_id; i++) { 1414231200Smm if (t->filesystem_table[i].dev == dev) { 1415311042Smm /* There is the filesystem ID we've already generated. */ 1416231200Smm t->current_filesystem_id = i; 1417231200Smm t->current_filesystem = &(t->filesystem_table[i]); 1418231200Smm return (ARCHIVE_OK); 1419231200Smm } 1420231200Smm } 1421231200Smm 1422231200Smm /* 1423311042Smm * This is the new filesystem which we have to generate a new ID for. 1424231200Smm */ 1425231200Smm fid = t->max_filesystem_id++; 1426311042Smm if (t->max_filesystem_id > t->allocated_filesystem) { 1427231200Smm size_t s; 1428248616Smm void *p; 1429231200Smm 1430231200Smm s = t->max_filesystem_id * 2; 1431248616Smm p = realloc(t->filesystem_table, 1432248616Smm s * sizeof(*t->filesystem_table)); 1433248616Smm if (p == NULL) { 1434231200Smm archive_set_error(&a->archive, ENOMEM, 1435231200Smm "Can't allocate tar data"); 1436231200Smm return (ARCHIVE_FATAL); 1437231200Smm } 1438248616Smm t->filesystem_table = (struct filesystem *)p; 1439311042Smm t->allocated_filesystem = s; 1440231200Smm } 1441231200Smm t->current_filesystem_id = fid; 1442231200Smm t->current_filesystem = &(t->filesystem_table[fid]); 1443231200Smm t->current_filesystem->dev = dev; 1444231200Smm t->current_filesystem->allocation_ptr = NULL; 1445231200Smm t->current_filesystem->buff = NULL; 1446231200Smm 1447231200Smm /* Setup the current filesystem properties which depend on 1448231200Smm * platform specific. */ 1449231200Smm return (setup_current_filesystem(a)); 1450231200Smm} 1451231200Smm 1452231200Smm/* 1453231200Smm * Returns 1 if current filesystem is generated filesystem, 0 if it is not 1454231200Smm * or -1 if it is unknown. 1455231200Smm */ 1456231200Smmint 1457231200Smmarchive_read_disk_current_filesystem_is_synthetic(struct archive *_a) 1458231200Smm{ 1459231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1460231200Smm 1461231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 1462231200Smm "archive_read_disk_current_filesystem"); 1463231200Smm 1464231200Smm return (a->tree->current_filesystem->synthetic); 1465231200Smm} 1466231200Smm 1467231200Smm/* 1468231200Smm * Returns 1 if current filesystem is remote filesystem, 0 if it is not 1469231200Smm * or -1 if it is unknown. 1470231200Smm */ 1471231200Smmint 1472231200Smmarchive_read_disk_current_filesystem_is_remote(struct archive *_a) 1473231200Smm{ 1474231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1475231200Smm 1476231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 1477231200Smm "archive_read_disk_current_filesystem"); 1478231200Smm 1479231200Smm return (a->tree->current_filesystem->remote); 1480231200Smm} 1481231200Smm 1482231200Smm#if defined(_PC_REC_INCR_XFER_SIZE) && defined(_PC_REC_MAX_XFER_SIZE) &&\ 1483231200Smm defined(_PC_REC_MIN_XFER_SIZE) && defined(_PC_REC_XFER_ALIGN) 1484231200Smmstatic int 1485231200Smmget_xfer_size(struct tree *t, int fd, const char *path) 1486231200Smm{ 1487231200Smm t->current_filesystem->xfer_align = -1; 1488231200Smm errno = 0; 1489231200Smm if (fd >= 0) { 1490231200Smm t->current_filesystem->incr_xfer_size = 1491231200Smm fpathconf(fd, _PC_REC_INCR_XFER_SIZE); 1492231200Smm t->current_filesystem->max_xfer_size = 1493231200Smm fpathconf(fd, _PC_REC_MAX_XFER_SIZE); 1494231200Smm t->current_filesystem->min_xfer_size = 1495231200Smm fpathconf(fd, _PC_REC_MIN_XFER_SIZE); 1496231200Smm t->current_filesystem->xfer_align = 1497231200Smm fpathconf(fd, _PC_REC_XFER_ALIGN); 1498231200Smm } else if (path != NULL) { 1499231200Smm t->current_filesystem->incr_xfer_size = 1500231200Smm pathconf(path, _PC_REC_INCR_XFER_SIZE); 1501231200Smm t->current_filesystem->max_xfer_size = 1502231200Smm pathconf(path, _PC_REC_MAX_XFER_SIZE); 1503231200Smm t->current_filesystem->min_xfer_size = 1504231200Smm pathconf(path, _PC_REC_MIN_XFER_SIZE); 1505231200Smm t->current_filesystem->xfer_align = 1506231200Smm pathconf(path, _PC_REC_XFER_ALIGN); 1507231200Smm } 1508231200Smm /* At least we need an alignment size. */ 1509231200Smm if (t->current_filesystem->xfer_align == -1) 1510231200Smm return ((errno == EINVAL)?1:-1); 1511231200Smm else 1512231200Smm return (0); 1513231200Smm} 1514231200Smm#else 1515231200Smmstatic int 1516231200Smmget_xfer_size(struct tree *t, int fd, const char *path) 1517231200Smm{ 1518231200Smm (void)t; /* UNUSED */ 1519231200Smm (void)fd; /* UNUSED */ 1520231200Smm (void)path; /* UNUSED */ 1521231200Smm return (1);/* Not supported */ 1522231200Smm} 1523231200Smm#endif 1524231200Smm 1525231200Smm#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \ 1526231200Smm && !defined(ST_LOCAL) 1527231200Smm 1528231200Smm/* 1529231200Smm * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X. 1530231200Smm */ 1531231200Smmstatic int 1532231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1533231200Smm{ 1534231200Smm struct tree *t = a->tree; 1535231200Smm struct statfs sfs; 1536231200Smm#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) 1537305755Smm/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make 1538305755Smm * this accurate; some platforms have both and we need the one that's 1539305755Smm * used by getvfsbyname() 1540305755Smm * 1541305755Smm * Then the following would become: 1542305755Smm * #if defined(GETVFSBYNAME_ARG_TYPE) 1543305755Smm * GETVFSBYNAME_ARG_TYPE vfc; 1544305755Smm * #endif 1545305755Smm */ 1546305755Smm# if defined(HAVE_STRUCT_XVFSCONF) 1547305755Smm struct xvfsconf vfc; 1548305755Smm# else 1549302425Smm struct vfsconf vfc; 1550302425Smm# endif 1551231200Smm#endif 1552231200Smm int r, xr = 0; 1553231200Smm#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX) 1554231200Smm long nm; 1555231200Smm#endif 1556231200Smm 1557231200Smm t->current_filesystem->synthetic = -1; 1558231200Smm t->current_filesystem->remote = -1; 1559231200Smm if (tree_current_is_symblic_link_target(t)) { 1560238856Smm#if defined(HAVE_OPENAT) 1561231200Smm /* 1562231200Smm * Get file system statistics on any directory 1563231200Smm * where current is. 1564231200Smm */ 1565231200Smm int fd = openat(tree_current_dir_fd(t), 1566248616Smm tree_current_access_path(t), O_RDONLY | O_CLOEXEC); 1567248616Smm __archive_ensure_cloexec_flag(fd); 1568231200Smm if (fd < 0) { 1569231200Smm archive_set_error(&a->archive, errno, 1570231200Smm "openat failed"); 1571231200Smm return (ARCHIVE_FAILED); 1572231200Smm } 1573231200Smm r = fstatfs(fd, &sfs); 1574231200Smm if (r == 0) 1575231200Smm xr = get_xfer_size(t, fd, NULL); 1576231200Smm close(fd); 1577231200Smm#else 1578238856Smm if (tree_enter_working_dir(t) != 0) { 1579238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1580238856Smm return (ARCHIVE_FAILED); 1581238856Smm } 1582231200Smm r = statfs(tree_current_access_path(t), &sfs); 1583231200Smm if (r == 0) 1584231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1585231200Smm#endif 1586231200Smm } else { 1587231200Smm r = fstatfs(tree_current_dir_fd(t), &sfs); 1588231200Smm if (r == 0) 1589231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1590231200Smm } 1591231200Smm if (r == -1 || xr == -1) { 1592231200Smm archive_set_error(&a->archive, errno, "statfs failed"); 1593231200Smm return (ARCHIVE_FAILED); 1594231200Smm } else if (xr == 1) { 1595231200Smm /* pathconf(_PC_REX_*) operations are not supported. */ 1596231200Smm t->current_filesystem->xfer_align = sfs.f_bsize; 1597231200Smm t->current_filesystem->max_xfer_size = -1; 1598231200Smm t->current_filesystem->min_xfer_size = sfs.f_iosize; 1599231200Smm t->current_filesystem->incr_xfer_size = sfs.f_iosize; 1600231200Smm } 1601231200Smm if (sfs.f_flags & MNT_LOCAL) 1602231200Smm t->current_filesystem->remote = 0; 1603231200Smm else 1604231200Smm t->current_filesystem->remote = 1; 1605231200Smm 1606231200Smm#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) 1607231200Smm r = getvfsbyname(sfs.f_fstypename, &vfc); 1608231200Smm if (r == -1) { 1609231200Smm archive_set_error(&a->archive, errno, "getvfsbyname failed"); 1610231200Smm return (ARCHIVE_FAILED); 1611231200Smm } 1612231200Smm if (vfc.vfc_flags & VFCF_SYNTHETIC) 1613231200Smm t->current_filesystem->synthetic = 1; 1614231200Smm else 1615231200Smm t->current_filesystem->synthetic = 0; 1616231200Smm#endif 1617231200Smm 1618231200Smm#if defined(MNT_NOATIME) 1619231200Smm if (sfs.f_flags & MNT_NOATIME) 1620231200Smm t->current_filesystem->noatime = 1; 1621231200Smm else 1622231200Smm#endif 1623231200Smm t->current_filesystem->noatime = 0; 1624231200Smm 1625306322Smm#if defined(USE_READDIR_R) 1626231200Smm /* Set maximum filename length. */ 1627231200Smm#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX) 1628231200Smm t->current_filesystem->name_max = sfs.f_namemax; 1629231200Smm#else 1630302001Smm# if defined(_PC_NAME_MAX) 1631231200Smm /* Mac OS X does not have f_namemax in struct statfs. */ 1632238856Smm if (tree_current_is_symblic_link_target(t)) { 1633238856Smm if (tree_enter_working_dir(t) != 0) { 1634238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1635238856Smm return (ARCHIVE_FAILED); 1636238856Smm } 1637231200Smm nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); 1638238856Smm } else 1639231200Smm nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); 1640302001Smm# else 1641302001Smm nm = -1; 1642302001Smm# endif 1643231200Smm if (nm == -1) 1644231200Smm t->current_filesystem->name_max = NAME_MAX; 1645231200Smm else 1646231200Smm t->current_filesystem->name_max = nm; 1647231200Smm#endif 1648306322Smm#endif /* USE_READDIR_R */ 1649231200Smm return (ARCHIVE_OK); 1650231200Smm} 1651231200Smm 1652231200Smm#elif (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) && defined(ST_LOCAL) 1653231200Smm 1654231200Smm/* 1655231200Smm * Gather current filesystem properties on NetBSD 1656231200Smm */ 1657231200Smmstatic int 1658231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1659231200Smm{ 1660231200Smm struct tree *t = a->tree; 1661362134Smm struct statvfs svfs; 1662231200Smm int r, xr = 0; 1663231200Smm 1664231200Smm t->current_filesystem->synthetic = -1; 1665238856Smm if (tree_enter_working_dir(t) != 0) { 1666238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1667238856Smm return (ARCHIVE_FAILED); 1668238856Smm } 1669231200Smm if (tree_current_is_symblic_link_target(t)) { 1670362134Smm r = statvfs(tree_current_access_path(t), &svfs); 1671231200Smm if (r == 0) 1672231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1673231200Smm } else { 1674231200Smm#ifdef HAVE_FSTATVFS 1675362134Smm r = fstatvfs(tree_current_dir_fd(t), &svfs); 1676231200Smm if (r == 0) 1677231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1678231200Smm#else 1679362134Smm r = statvfs(".", &svfs); 1680231200Smm if (r == 0) 1681231200Smm xr = get_xfer_size(t, -1, "."); 1682231200Smm#endif 1683231200Smm } 1684231200Smm if (r == -1 || xr == -1) { 1685231200Smm t->current_filesystem->remote = -1; 1686231200Smm archive_set_error(&a->archive, errno, "statvfs failed"); 1687231200Smm return (ARCHIVE_FAILED); 1688231200Smm } else if (xr == 1) { 1689313571Smm /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN 1690231200Smm * for pathconf() function. */ 1691362134Smm t->current_filesystem->xfer_align = svfs.f_frsize; 1692231200Smm t->current_filesystem->max_xfer_size = -1; 1693238856Smm#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) 1694362134Smm t->current_filesystem->min_xfer_size = svfs.f_iosize; 1695362134Smm t->current_filesystem->incr_xfer_size = svfs.f_iosize; 1696238856Smm#else 1697362134Smm t->current_filesystem->min_xfer_size = svfs.f_bsize; 1698362134Smm t->current_filesystem->incr_xfer_size = svfs.f_bsize; 1699238856Smm#endif 1700231200Smm } 1701362134Smm if (svfs.f_flag & ST_LOCAL) 1702231200Smm t->current_filesystem->remote = 0; 1703231200Smm else 1704231200Smm t->current_filesystem->remote = 1; 1705231200Smm 1706238856Smm#if defined(ST_NOATIME) 1707362134Smm if (svfs.f_flag & ST_NOATIME) 1708231200Smm t->current_filesystem->noatime = 1; 1709231200Smm else 1710238856Smm#endif 1711231200Smm t->current_filesystem->noatime = 0; 1712231200Smm 1713231200Smm /* Set maximum filename length. */ 1714362134Smm t->current_filesystem->name_max = svfs.f_namemax; 1715231200Smm return (ARCHIVE_OK); 1716231200Smm} 1717231200Smm 1718231200Smm#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_LINUX_MAGIC_H) &&\ 1719231200Smm defined(HAVE_STATFS) && defined(HAVE_FSTATFS) 1720231200Smm/* 1721231200Smm * Note: statfs is deprecated since LSB 3.2 1722231200Smm */ 1723231200Smm 1724231200Smm#ifndef CIFS_SUPER_MAGIC 1725231200Smm#define CIFS_SUPER_MAGIC 0xFF534D42 1726231200Smm#endif 1727231200Smm#ifndef DEVFS_SUPER_MAGIC 1728231200Smm#define DEVFS_SUPER_MAGIC 0x1373 1729231200Smm#endif 1730231200Smm 1731231200Smm/* 1732231200Smm * Gather current filesystem properties on Linux 1733231200Smm */ 1734231200Smmstatic int 1735231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1736231200Smm{ 1737231200Smm struct tree *t = a->tree; 1738231200Smm struct statfs sfs; 1739302001Smm#if defined(HAVE_STATVFS) 1740231200Smm struct statvfs svfs; 1741302001Smm#endif 1742231200Smm int r, vr = 0, xr = 0; 1743231200Smm 1744231200Smm if (tree_current_is_symblic_link_target(t)) { 1745238856Smm#if defined(HAVE_OPENAT) 1746231200Smm /* 1747231200Smm * Get file system statistics on any directory 1748231200Smm * where current is. 1749231200Smm */ 1750231200Smm int fd = openat(tree_current_dir_fd(t), 1751248616Smm tree_current_access_path(t), O_RDONLY | O_CLOEXEC); 1752248616Smm __archive_ensure_cloexec_flag(fd); 1753231200Smm if (fd < 0) { 1754231200Smm archive_set_error(&a->archive, errno, 1755231200Smm "openat failed"); 1756231200Smm return (ARCHIVE_FAILED); 1757231200Smm } 1758302001Smm#if defined(HAVE_FSTATVFS) 1759231200Smm vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */ 1760302001Smm#endif 1761231200Smm r = fstatfs(fd, &sfs); 1762231200Smm if (r == 0) 1763231200Smm xr = get_xfer_size(t, fd, NULL); 1764231200Smm close(fd); 1765231200Smm#else 1766238856Smm if (tree_enter_working_dir(t) != 0) { 1767238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1768238856Smm return (ARCHIVE_FAILED); 1769238856Smm } 1770302001Smm#if defined(HAVE_STATVFS) 1771231200Smm vr = statvfs(tree_current_access_path(t), &svfs); 1772302001Smm#endif 1773231200Smm r = statfs(tree_current_access_path(t), &sfs); 1774231200Smm if (r == 0) 1775231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1776231200Smm#endif 1777231200Smm } else { 1778231200Smm#ifdef HAVE_FSTATFS 1779302001Smm#if defined(HAVE_FSTATVFS) 1780231200Smm vr = fstatvfs(tree_current_dir_fd(t), &svfs); 1781302001Smm#endif 1782231200Smm r = fstatfs(tree_current_dir_fd(t), &sfs); 1783231200Smm if (r == 0) 1784231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1785231200Smm#else 1786238856Smm if (tree_enter_working_dir(t) != 0) { 1787238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1788238856Smm return (ARCHIVE_FAILED); 1789238856Smm } 1790302001Smm#if defined(HAVE_STATVFS) 1791231200Smm vr = statvfs(".", &svfs); 1792302001Smm#endif 1793231200Smm r = statfs(".", &sfs); 1794231200Smm if (r == 0) 1795231200Smm xr = get_xfer_size(t, -1, "."); 1796231200Smm#endif 1797231200Smm } 1798231200Smm if (r == -1 || xr == -1 || vr == -1) { 1799231200Smm t->current_filesystem->synthetic = -1; 1800231200Smm t->current_filesystem->remote = -1; 1801231200Smm archive_set_error(&a->archive, errno, "statfs failed"); 1802231200Smm return (ARCHIVE_FAILED); 1803231200Smm } else if (xr == 1) { 1804231200Smm /* pathconf(_PC_REX_*) operations are not supported. */ 1805302001Smm#if defined(HAVE_STATVFS) 1806231200Smm t->current_filesystem->xfer_align = svfs.f_frsize; 1807231200Smm t->current_filesystem->max_xfer_size = -1; 1808231200Smm t->current_filesystem->min_xfer_size = svfs.f_bsize; 1809231200Smm t->current_filesystem->incr_xfer_size = svfs.f_bsize; 1810302001Smm#else 1811302001Smm t->current_filesystem->xfer_align = sfs.f_frsize; 1812302001Smm t->current_filesystem->max_xfer_size = -1; 1813302001Smm t->current_filesystem->min_xfer_size = sfs.f_bsize; 1814302001Smm t->current_filesystem->incr_xfer_size = sfs.f_bsize; 1815302001Smm#endif 1816231200Smm } 1817231200Smm switch (sfs.f_type) { 1818231200Smm case AFS_SUPER_MAGIC: 1819231200Smm case CIFS_SUPER_MAGIC: 1820231200Smm case CODA_SUPER_MAGIC: 1821231200Smm case NCP_SUPER_MAGIC:/* NetWare */ 1822231200Smm case NFS_SUPER_MAGIC: 1823231200Smm case SMB_SUPER_MAGIC: 1824231200Smm t->current_filesystem->remote = 1; 1825231200Smm t->current_filesystem->synthetic = 0; 1826231200Smm break; 1827231200Smm case DEVFS_SUPER_MAGIC: 1828231200Smm case PROC_SUPER_MAGIC: 1829231200Smm case USBDEVICE_SUPER_MAGIC: 1830231200Smm t->current_filesystem->remote = 0; 1831231200Smm t->current_filesystem->synthetic = 1; 1832231200Smm break; 1833231200Smm default: 1834231200Smm t->current_filesystem->remote = 0; 1835231200Smm t->current_filesystem->synthetic = 0; 1836231200Smm break; 1837231200Smm } 1838231200Smm 1839231200Smm#if defined(ST_NOATIME) 1840302001Smm#if defined(HAVE_STATVFS) 1841231200Smm if (svfs.f_flag & ST_NOATIME) 1842302001Smm#else 1843362134Smm if (sfs.f_flags & ST_NOATIME) 1844302001Smm#endif 1845231200Smm t->current_filesystem->noatime = 1; 1846231200Smm else 1847231200Smm#endif 1848231200Smm t->current_filesystem->noatime = 0; 1849231200Smm 1850306322Smm#if defined(USE_READDIR_R) 1851231200Smm /* Set maximum filename length. */ 1852231200Smm t->current_filesystem->name_max = sfs.f_namelen; 1853231200Smm#endif 1854231200Smm return (ARCHIVE_OK); 1855231200Smm} 1856231200Smm 1857231200Smm#elif defined(HAVE_SYS_STATVFS_H) &&\ 1858231200Smm (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) 1859231200Smm 1860231200Smm/* 1861231200Smm * Gather current filesystem properties on other posix platform. 1862231200Smm */ 1863231200Smmstatic int 1864231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1865231200Smm{ 1866231200Smm struct tree *t = a->tree; 1867362134Smm struct statvfs svfs; 1868231200Smm int r, xr = 0; 1869231200Smm 1870231200Smm t->current_filesystem->synthetic = -1;/* Not supported */ 1871231200Smm t->current_filesystem->remote = -1;/* Not supported */ 1872231200Smm if (tree_current_is_symblic_link_target(t)) { 1873238856Smm#if defined(HAVE_OPENAT) 1874231200Smm /* 1875231200Smm * Get file system statistics on any directory 1876231200Smm * where current is. 1877231200Smm */ 1878231200Smm int fd = openat(tree_current_dir_fd(t), 1879248616Smm tree_current_access_path(t), O_RDONLY | O_CLOEXEC); 1880248616Smm __archive_ensure_cloexec_flag(fd); 1881231200Smm if (fd < 0) { 1882231200Smm archive_set_error(&a->archive, errno, 1883231200Smm "openat failed"); 1884231200Smm return (ARCHIVE_FAILED); 1885231200Smm } 1886362134Smm r = fstatvfs(fd, &svfs); 1887231200Smm if (r == 0) 1888231200Smm xr = get_xfer_size(t, fd, NULL); 1889231200Smm close(fd); 1890231200Smm#else 1891238856Smm if (tree_enter_working_dir(t) != 0) { 1892238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1893238856Smm return (ARCHIVE_FAILED); 1894238856Smm } 1895362134Smm r = statvfs(tree_current_access_path(t), &svfs); 1896231200Smm if (r == 0) 1897231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1898231200Smm#endif 1899231200Smm } else { 1900231200Smm#ifdef HAVE_FSTATVFS 1901362134Smm r = fstatvfs(tree_current_dir_fd(t), &svfs); 1902231200Smm if (r == 0) 1903231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1904231200Smm#else 1905238856Smm if (tree_enter_working_dir(t) != 0) { 1906238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1907238856Smm return (ARCHIVE_FAILED); 1908238856Smm } 1909362134Smm r = statvfs(".", &svfs); 1910231200Smm if (r == 0) 1911231200Smm xr = get_xfer_size(t, -1, "."); 1912231200Smm#endif 1913231200Smm } 1914231200Smm if (r == -1 || xr == -1) { 1915231200Smm t->current_filesystem->synthetic = -1; 1916231200Smm t->current_filesystem->remote = -1; 1917231200Smm archive_set_error(&a->archive, errno, "statvfs failed"); 1918231200Smm return (ARCHIVE_FAILED); 1919231200Smm } else if (xr == 1) { 1920231200Smm /* pathconf(_PC_REX_*) operations are not supported. */ 1921362134Smm t->current_filesystem->xfer_align = svfs.f_frsize; 1922231200Smm t->current_filesystem->max_xfer_size = -1; 1923362134Smm t->current_filesystem->min_xfer_size = svfs.f_bsize; 1924362134Smm t->current_filesystem->incr_xfer_size = svfs.f_bsize; 1925231200Smm } 1926231200Smm 1927231200Smm#if defined(ST_NOATIME) 1928362134Smm if (svfs.f_flag & ST_NOATIME) 1929231200Smm t->current_filesystem->noatime = 1; 1930231200Smm else 1931231200Smm#endif 1932231200Smm t->current_filesystem->noatime = 0; 1933231200Smm 1934306322Smm#if defined(USE_READDIR_R) 1935231200Smm /* Set maximum filename length. */ 1936362134Smm t->current_filesystem->name_max = svfs.f_namemax; 1937231200Smm#endif 1938231200Smm return (ARCHIVE_OK); 1939231200Smm} 1940231200Smm 1941231200Smm#else 1942231200Smm 1943231200Smm/* 1944231200Smm * Generic: Gather current filesystem properties. 1945231200Smm * TODO: Is this generic function really needed? 1946231200Smm */ 1947231200Smmstatic int 1948231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1949231200Smm{ 1950231200Smm struct tree *t = a->tree; 1951306322Smm#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R) 1952231200Smm long nm; 1953231200Smm#endif 1954231200Smm t->current_filesystem->synthetic = -1;/* Not supported */ 1955231200Smm t->current_filesystem->remote = -1;/* Not supported */ 1956231200Smm t->current_filesystem->noatime = 0; 1957231200Smm (void)get_xfer_size(t, -1, ".");/* Dummy call to avoid build error. */ 1958231200Smm t->current_filesystem->xfer_align = -1;/* Unknown */ 1959231200Smm t->current_filesystem->max_xfer_size = -1; 1960231200Smm t->current_filesystem->min_xfer_size = -1; 1961231200Smm t->current_filesystem->incr_xfer_size = -1; 1962231200Smm 1963306322Smm#if defined(USE_READDIR_R) 1964231200Smm /* Set maximum filename length. */ 1965231200Smm# if defined(_PC_NAME_MAX) 1966238856Smm if (tree_current_is_symblic_link_target(t)) { 1967238856Smm if (tree_enter_working_dir(t) != 0) { 1968238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1969238856Smm return (ARCHIVE_FAILED); 1970238856Smm } 1971231200Smm nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); 1972238856Smm } else 1973231200Smm nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); 1974231200Smm if (nm == -1) 1975231200Smm# endif /* _PC_NAME_MAX */ 1976231200Smm /* 1977313571Smm * Some systems (HP-UX or others?) incorrectly defined 1978231200Smm * NAME_MAX macro to be a smaller value. 1979231200Smm */ 1980231200Smm# if defined(NAME_MAX) && NAME_MAX >= 255 1981231200Smm t->current_filesystem->name_max = NAME_MAX; 1982231200Smm# else 1983231200Smm /* No way to get a trusted value of maximum filename 1984231200Smm * length. */ 1985231200Smm t->current_filesystem->name_max = PATH_MAX; 1986231200Smm# endif /* NAME_MAX */ 1987231200Smm# if defined(_PC_NAME_MAX) 1988231200Smm else 1989231200Smm t->current_filesystem->name_max = nm; 1990231200Smm# endif /* _PC_NAME_MAX */ 1991306322Smm#endif /* USE_READDIR_R */ 1992231200Smm return (ARCHIVE_OK); 1993231200Smm} 1994231200Smm 1995231200Smm#endif 1996231200Smm 1997231200Smmstatic int 1998231200Smmclose_and_restore_time(int fd, struct tree *t, struct restore_time *rt) 1999231200Smm{ 2000231200Smm#ifndef HAVE_UTIMES 2001248616Smm (void)t; /* UNUSED */ 2002248616Smm (void)rt; /* UNUSED */ 2003231200Smm return (close(fd)); 2004231200Smm#else 2005231200Smm#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) 2006231200Smm struct timespec timespecs[2]; 2007231200Smm#endif 2008231200Smm struct timeval times[2]; 2009231200Smm 2010231200Smm if ((t->flags & needsRestoreTimes) == 0 || rt->noatime) { 2011231200Smm if (fd >= 0) 2012231200Smm return (close(fd)); 2013231200Smm else 2014231200Smm return (0); 2015231200Smm } 2016231200Smm 2017231200Smm#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) 2018231200Smm timespecs[1].tv_sec = rt->mtime; 2019231200Smm timespecs[1].tv_nsec = rt->mtime_nsec; 2020231200Smm 2021231200Smm timespecs[0].tv_sec = rt->atime; 2022231200Smm timespecs[0].tv_nsec = rt->atime_nsec; 2023231200Smm /* futimens() is defined in POSIX.1-2008. */ 2024231200Smm if (futimens(fd, timespecs) == 0) 2025231200Smm return (close(fd)); 2026231200Smm#endif 2027231200Smm 2028231200Smm times[1].tv_sec = rt->mtime; 2029231200Smm times[1].tv_usec = rt->mtime_nsec / 1000; 2030231200Smm 2031231200Smm times[0].tv_sec = rt->atime; 2032231200Smm times[0].tv_usec = rt->atime_nsec / 1000; 2033231200Smm 2034231200Smm#if !defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES) && !defined(__CYGWIN__) 2035231200Smm if (futimes(fd, times) == 0) 2036231200Smm return (close(fd)); 2037231200Smm#endif 2038231200Smm close(fd); 2039231200Smm#if defined(HAVE_FUTIMESAT) 2040231200Smm if (futimesat(tree_current_dir_fd(t), rt->name, times) == 0) 2041231200Smm return (0); 2042231200Smm#endif 2043231200Smm#ifdef HAVE_LUTIMES 2044231200Smm if (lutimes(rt->name, times) != 0) 2045231200Smm#else 2046231200Smm if (AE_IFLNK != rt->filetype && utimes(rt->name, times) != 0) 2047231200Smm#endif 2048231200Smm return (-1); 2049231200Smm#endif 2050231200Smm return (0); 2051231200Smm} 2052231200Smm 2053238856Smmstatic int 2054238856Smmopen_on_current_dir(struct tree *t, const char *path, int flags) 2055238856Smm{ 2056238856Smm#ifdef HAVE_OPENAT 2057238856Smm return (openat(tree_current_dir_fd(t), path, flags)); 2058238856Smm#else 2059238856Smm if (tree_enter_working_dir(t) != 0) 2060238856Smm return (-1); 2061238856Smm return (open(path, flags)); 2062238856Smm#endif 2063238856Smm} 2064238856Smm 2065248616Smmstatic int 2066248616Smmtree_dup(int fd) 2067248616Smm{ 2068248616Smm int new_fd; 2069248616Smm#ifdef F_DUPFD_CLOEXEC 2070248616Smm static volatile int can_dupfd_cloexec = 1; 2071248616Smm 2072248616Smm if (can_dupfd_cloexec) { 2073302001Smm new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); 2074248616Smm if (new_fd != -1) 2075248616Smm return (new_fd); 2076248616Smm /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC, 2077248616Smm * but it cannot be used. So we have to try dup(). */ 2078248616Smm /* We won't try F_DUPFD_CLOEXEC. */ 2079248616Smm can_dupfd_cloexec = 0; 2080248616Smm } 2081248616Smm#endif /* F_DUPFD_CLOEXEC */ 2082248616Smm new_fd = dup(fd); 2083248616Smm __archive_ensure_cloexec_flag(new_fd); 2084248616Smm return (new_fd); 2085248616Smm} 2086248616Smm 2087231200Smm/* 2088231200Smm * Add a directory path to the current stack. 2089231200Smm */ 2090231200Smmstatic void 2091231200Smmtree_push(struct tree *t, const char *path, int filesystem_id, 2092231200Smm int64_t dev, int64_t ino, struct restore_time *rt) 2093231200Smm{ 2094231200Smm struct tree_entry *te; 2095231200Smm 2096311042Smm te = calloc(1, sizeof(*te)); 2097231200Smm te->next = t->stack; 2098231200Smm te->parent = t->current; 2099231200Smm if (te->parent) 2100231200Smm te->depth = te->parent->depth + 1; 2101231200Smm t->stack = te; 2102231200Smm archive_string_init(&te->name); 2103231200Smm te->symlink_parent_fd = -1; 2104231200Smm archive_strcpy(&te->name, path); 2105231200Smm te->flags = needsDescent | needsOpen | needsAscent; 2106231200Smm te->filesystem_id = filesystem_id; 2107231200Smm te->dev = dev; 2108231200Smm te->ino = ino; 2109231200Smm te->dirname_length = t->dirname_length; 2110231200Smm te->restore_time.name = te->name.s; 2111231200Smm if (rt != NULL) { 2112231200Smm te->restore_time.mtime = rt->mtime; 2113231200Smm te->restore_time.mtime_nsec = rt->mtime_nsec; 2114231200Smm te->restore_time.atime = rt->atime; 2115231200Smm te->restore_time.atime_nsec = rt->atime_nsec; 2116231200Smm te->restore_time.filetype = rt->filetype; 2117231200Smm te->restore_time.noatime = rt->noatime; 2118231200Smm } 2119231200Smm} 2120231200Smm 2121231200Smm/* 2122231200Smm * Append a name to the current dir path. 2123231200Smm */ 2124231200Smmstatic void 2125231200Smmtree_append(struct tree *t, const char *name, size_t name_length) 2126231200Smm{ 2127231200Smm size_t size_needed; 2128231200Smm 2129231200Smm t->path.s[t->dirname_length] = '\0'; 2130231200Smm t->path.length = t->dirname_length; 2131231200Smm /* Strip trailing '/' from name, unless entire name is "/". */ 2132231200Smm while (name_length > 1 && name[name_length - 1] == '/') 2133231200Smm name_length--; 2134231200Smm 2135231200Smm /* Resize pathname buffer as needed. */ 2136231200Smm size_needed = name_length + t->dirname_length + 2; 2137231200Smm archive_string_ensure(&t->path, size_needed); 2138231200Smm /* Add a separating '/' if it's needed. */ 2139231200Smm if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != '/') 2140231200Smm archive_strappend_char(&t->path, '/'); 2141231200Smm t->basename = t->path.s + archive_strlen(&t->path); 2142231200Smm archive_strncat(&t->path, name, name_length); 2143231200Smm t->restore_time.name = t->basename; 2144231200Smm} 2145231200Smm 2146231200Smm/* 2147231200Smm * Open a directory tree for traversal. 2148231200Smm */ 2149231200Smmstatic struct tree * 2150231200Smmtree_open(const char *path, int symlink_mode, int restore_time) 2151231200Smm{ 2152231200Smm struct tree *t; 2153231200Smm 2154311042Smm if ((t = calloc(1, sizeof(*t))) == NULL) 2155231200Smm return (NULL); 2156231200Smm archive_string_init(&t->path); 2157231200Smm archive_string_ensure(&t->path, 31); 2158231200Smm t->initial_symlink_mode = symlink_mode; 2159231200Smm return (tree_reopen(t, path, restore_time)); 2160231200Smm} 2161231200Smm 2162231200Smmstatic struct tree * 2163231200Smmtree_reopen(struct tree *t, const char *path, int restore_time) 2164231200Smm{ 2165348608Smm#if defined(O_PATH) 2166348608Smm /* Linux */ 2167348608Smm const int o_flag = O_PATH; 2168348608Smm#elif defined(O_SEARCH) 2169348608Smm /* SunOS */ 2170348608Smm const int o_flag = O_SEARCH; 2171358090Smm#elif defined(__FreeBSD__) && defined(O_EXEC) 2172348608Smm /* FreeBSD */ 2173348608Smm const int o_flag = O_EXEC; 2174348608Smm#endif 2175348608Smm 2176315433Smm t->flags = (restore_time != 0)?needsRestoreTimes:0; 2177238856Smm t->flags |= onInitialDir; 2178231200Smm t->visit_type = 0; 2179231200Smm t->tree_errno = 0; 2180231200Smm t->dirname_length = 0; 2181231200Smm t->depth = 0; 2182231200Smm t->descend = 0; 2183231200Smm t->current = NULL; 2184231200Smm t->d = INVALID_DIR_HANDLE; 2185231200Smm t->symlink_mode = t->initial_symlink_mode; 2186231200Smm archive_string_empty(&t->path); 2187231200Smm t->entry_fd = -1; 2188231200Smm t->entry_eof = 0; 2189231200Smm t->entry_remaining_bytes = 0; 2190238856Smm t->initial_filesystem_id = -1; 2191231200Smm 2192231200Smm /* First item is set up a lot like a symlink traversal. */ 2193231200Smm tree_push(t, path, 0, 0, 0, NULL); 2194231200Smm t->stack->flags = needsFirstVisit; 2195231200Smm t->maxOpenCount = t->openCount = 1; 2196248616Smm t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC); 2197358090Smm#if defined(O_PATH) || defined(O_SEARCH) || \ 2198358090Smm (defined(__FreeBSD__) && defined(O_EXEC)) 2199348608Smm /* 2200348608Smm * Most likely reason to fail opening "." is that it's not readable, 2201348608Smm * so try again for execute. The consequences of not opening this are 2202348608Smm * unhelpful and unnecessary errors later. 2203348608Smm */ 2204348608Smm if (t->initial_dir_fd < 0) 2205348608Smm t->initial_dir_fd = open(".", o_flag | O_CLOEXEC); 2206348608Smm#endif 2207248616Smm __archive_ensure_cloexec_flag(t->initial_dir_fd); 2208248616Smm t->working_dir_fd = tree_dup(t->initial_dir_fd); 2209231200Smm return (t); 2210231200Smm} 2211231200Smm 2212231200Smmstatic int 2213231200Smmtree_descent(struct tree *t) 2214231200Smm{ 2215238856Smm int flag, new_fd, r = 0; 2216231200Smm 2217231200Smm t->dirname_length = archive_strlen(&t->path); 2218248616Smm flag = O_RDONLY | O_CLOEXEC; 2219238856Smm#if defined(O_DIRECTORY) 2220238856Smm flag |= O_DIRECTORY; 2221238856Smm#endif 2222238856Smm new_fd = open_on_current_dir(t, t->stack->name.s, flag); 2223248616Smm __archive_ensure_cloexec_flag(new_fd); 2224231200Smm if (new_fd < 0) { 2225231200Smm t->tree_errno = errno; 2226231200Smm r = TREE_ERROR_DIR; 2227231200Smm } else { 2228231200Smm t->depth++; 2229231200Smm /* If it is a link, set up fd for the ascent. */ 2230231200Smm if (t->stack->flags & isDirLink) { 2231231200Smm t->stack->symlink_parent_fd = t->working_dir_fd; 2232231200Smm t->openCount++; 2233231200Smm if (t->openCount > t->maxOpenCount) 2234231200Smm t->maxOpenCount = t->openCount; 2235231200Smm } else 2236231200Smm close(t->working_dir_fd); 2237238856Smm /* Renew the current working directory. */ 2238231200Smm t->working_dir_fd = new_fd; 2239238856Smm t->flags &= ~onWorkingDir; 2240231200Smm } 2241231200Smm return (r); 2242231200Smm} 2243231200Smm 2244231200Smm/* 2245231200Smm * We've finished a directory; ascend back to the parent. 2246231200Smm */ 2247231200Smmstatic int 2248231200Smmtree_ascend(struct tree *t) 2249231200Smm{ 2250231200Smm struct tree_entry *te; 2251238856Smm int new_fd, r = 0, prev_dir_fd; 2252231200Smm 2253231200Smm te = t->stack; 2254231200Smm prev_dir_fd = t->working_dir_fd; 2255231200Smm if (te->flags & isDirLink) 2256238856Smm new_fd = te->symlink_parent_fd; 2257248616Smm else { 2258248616Smm new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC); 2259248616Smm __archive_ensure_cloexec_flag(new_fd); 2260248616Smm } 2261238856Smm if (new_fd < 0) { 2262238856Smm t->tree_errno = errno; 2263238856Smm r = TREE_ERROR_FATAL; 2264231200Smm } else { 2265238856Smm /* Renew the current working directory. */ 2266238856Smm t->working_dir_fd = new_fd; 2267238856Smm t->flags &= ~onWorkingDir; 2268231200Smm /* Current directory has been changed, we should 2269231200Smm * close an fd of previous working directory. */ 2270231200Smm close_and_restore_time(prev_dir_fd, t, &te->restore_time); 2271231200Smm if (te->flags & isDirLink) { 2272231200Smm t->openCount--; 2273231200Smm te->symlink_parent_fd = -1; 2274231200Smm } 2275231200Smm t->depth--; 2276231200Smm } 2277231200Smm return (r); 2278231200Smm} 2279231200Smm 2280231200Smm/* 2281231200Smm * Return to the initial directory where tree_open() was performed. 2282231200Smm */ 2283231200Smmstatic int 2284231200Smmtree_enter_initial_dir(struct tree *t) 2285231200Smm{ 2286231200Smm int r = 0; 2287231200Smm 2288238856Smm if ((t->flags & onInitialDir) == 0) { 2289231200Smm r = fchdir(t->initial_dir_fd); 2290238856Smm if (r == 0) { 2291231200Smm t->flags &= ~onWorkingDir; 2292238856Smm t->flags |= onInitialDir; 2293238856Smm } 2294231200Smm } 2295231200Smm return (r); 2296231200Smm} 2297231200Smm 2298231200Smm/* 2299231200Smm * Restore working directory of directory traversals. 2300231200Smm */ 2301231200Smmstatic int 2302231200Smmtree_enter_working_dir(struct tree *t) 2303231200Smm{ 2304231200Smm int r = 0; 2305231200Smm 2306231200Smm /* 2307231200Smm * Change the current directory if really needed. 2308231200Smm * Sometimes this is unneeded when we did not do 2309231200Smm * descent. 2310231200Smm */ 2311231200Smm if (t->depth > 0 && (t->flags & onWorkingDir) == 0) { 2312231200Smm r = fchdir(t->working_dir_fd); 2313238856Smm if (r == 0) { 2314238856Smm t->flags &= ~onInitialDir; 2315231200Smm t->flags |= onWorkingDir; 2316238856Smm } 2317231200Smm } 2318231200Smm return (r); 2319231200Smm} 2320231200Smm 2321231200Smmstatic int 2322231200Smmtree_current_dir_fd(struct tree *t) 2323231200Smm{ 2324231200Smm return (t->working_dir_fd); 2325231200Smm} 2326231200Smm 2327231200Smm/* 2328231200Smm * Pop the working stack. 2329231200Smm */ 2330231200Smmstatic void 2331231200Smmtree_pop(struct tree *t) 2332231200Smm{ 2333231200Smm struct tree_entry *te; 2334231200Smm 2335231200Smm t->path.s[t->dirname_length] = '\0'; 2336231200Smm t->path.length = t->dirname_length; 2337231200Smm if (t->stack == t->current && t->current != NULL) 2338231200Smm t->current = t->current->parent; 2339231200Smm te = t->stack; 2340231200Smm t->stack = te->next; 2341231200Smm t->dirname_length = te->dirname_length; 2342231200Smm t->basename = t->path.s + t->dirname_length; 2343231200Smm while (t->basename[0] == '/') 2344231200Smm t->basename++; 2345231200Smm archive_string_free(&te->name); 2346231200Smm free(te); 2347231200Smm} 2348231200Smm 2349231200Smm/* 2350231200Smm * Get the next item in the tree traversal. 2351231200Smm */ 2352231200Smmstatic int 2353231200Smmtree_next(struct tree *t) 2354231200Smm{ 2355231200Smm int r; 2356231200Smm 2357231200Smm while (t->stack != NULL) { 2358231200Smm /* If there's an open dir, get the next entry from there. */ 2359231200Smm if (t->d != INVALID_DIR_HANDLE) { 2360231200Smm r = tree_dir_next_posix(t); 2361231200Smm if (r == 0) 2362231200Smm continue; 2363231200Smm return (r); 2364231200Smm } 2365231200Smm 2366231200Smm if (t->stack->flags & needsFirstVisit) { 2367231200Smm /* Top stack item needs a regular visit. */ 2368231200Smm t->current = t->stack; 2369231200Smm tree_append(t, t->stack->name.s, 2370231200Smm archive_strlen(&(t->stack->name))); 2371231200Smm /* t->dirname_length = t->path_length; */ 2372231200Smm /* tree_pop(t); */ 2373231200Smm t->stack->flags &= ~needsFirstVisit; 2374231200Smm return (t->visit_type = TREE_REGULAR); 2375231200Smm } else if (t->stack->flags & needsDescent) { 2376231200Smm /* Top stack item is dir to descend into. */ 2377231200Smm t->current = t->stack; 2378231200Smm tree_append(t, t->stack->name.s, 2379231200Smm archive_strlen(&(t->stack->name))); 2380231200Smm t->stack->flags &= ~needsDescent; 2381231200Smm r = tree_descent(t); 2382231200Smm if (r != 0) { 2383231200Smm tree_pop(t); 2384231200Smm t->visit_type = r; 2385231200Smm } else 2386231200Smm t->visit_type = TREE_POSTDESCENT; 2387231200Smm return (t->visit_type); 2388231200Smm } else if (t->stack->flags & needsOpen) { 2389231200Smm t->stack->flags &= ~needsOpen; 2390231200Smm r = tree_dir_next_posix(t); 2391231200Smm if (r == 0) 2392231200Smm continue; 2393231200Smm return (r); 2394231200Smm } else if (t->stack->flags & needsAscent) { 2395231200Smm /* Top stack item is dir and we're done with it. */ 2396231200Smm r = tree_ascend(t); 2397231200Smm tree_pop(t); 2398231200Smm t->visit_type = r != 0 ? r : TREE_POSTASCENT; 2399231200Smm return (t->visit_type); 2400231200Smm } else { 2401231200Smm /* Top item on stack is dead. */ 2402231200Smm tree_pop(t); 2403231200Smm t->flags &= ~hasLstat; 2404231200Smm t->flags &= ~hasStat; 2405231200Smm } 2406231200Smm } 2407231200Smm return (t->visit_type = 0); 2408231200Smm} 2409231200Smm 2410231200Smmstatic int 2411231200Smmtree_dir_next_posix(struct tree *t) 2412231200Smm{ 2413231200Smm int r; 2414231200Smm const char *name; 2415231200Smm size_t namelen; 2416231200Smm 2417231200Smm if (t->d == NULL) { 2418306322Smm#if defined(USE_READDIR_R) 2419231200Smm size_t dirent_size; 2420231200Smm#endif 2421231200Smm 2422231200Smm#if defined(HAVE_FDOPENDIR) 2423248616Smm t->d = fdopendir(tree_dup(t->working_dir_fd)); 2424248616Smm#else /* HAVE_FDOPENDIR */ 2425248616Smm if (tree_enter_working_dir(t) == 0) { 2426248616Smm t->d = opendir("."); 2427248616Smm#if HAVE_DIRFD || defined(dirfd) 2428248616Smm __archive_ensure_cloexec_flag(dirfd(t->d)); 2429231200Smm#endif 2430248616Smm } 2431248616Smm#endif /* HAVE_FDOPENDIR */ 2432248616Smm if (t->d == NULL) { 2433231200Smm r = tree_ascend(t); /* Undo "chdir" */ 2434231200Smm tree_pop(t); 2435231200Smm t->tree_errno = errno; 2436231200Smm t->visit_type = r != 0 ? r : TREE_ERROR_DIR; 2437231200Smm return (t->visit_type); 2438231200Smm } 2439306322Smm#if defined(USE_READDIR_R) 2440231200Smm dirent_size = offsetof(struct dirent, d_name) + 2441231200Smm t->filesystem_table[t->current->filesystem_id].name_max + 1; 2442231200Smm if (t->dirent == NULL || t->dirent_allocated < dirent_size) { 2443231200Smm free(t->dirent); 2444231200Smm t->dirent = malloc(dirent_size); 2445231200Smm if (t->dirent == NULL) { 2446231200Smm closedir(t->d); 2447231200Smm t->d = INVALID_DIR_HANDLE; 2448231200Smm (void)tree_ascend(t); 2449231200Smm tree_pop(t); 2450231200Smm t->tree_errno = ENOMEM; 2451231200Smm t->visit_type = TREE_ERROR_DIR; 2452231200Smm return (t->visit_type); 2453231200Smm } 2454231200Smm t->dirent_allocated = dirent_size; 2455231200Smm } 2456306322Smm#endif /* USE_READDIR_R */ 2457231200Smm } 2458231200Smm for (;;) { 2459248616Smm errno = 0; 2460306322Smm#if defined(USE_READDIR_R) 2461231200Smm r = readdir_r(t->d, t->dirent, &t->de); 2462248616Smm#ifdef _AIX 2463248616Smm /* Note: According to the man page, return value 9 indicates 2464248616Smm * that the readdir_r was not successful and the error code 2465248616Smm * is set to the global errno variable. And then if the end 2466248616Smm * of directory entries was reached, the return value is 9 2467248616Smm * and the third parameter is set to NULL and errno is 2468248616Smm * unchanged. */ 2469248616Smm if (r == 9) 2470248616Smm r = errno; 2471248616Smm#endif /* _AIX */ 2472231200Smm if (r != 0 || t->de == NULL) { 2473231200Smm#else 2474231200Smm t->de = readdir(t->d); 2475231200Smm if (t->de == NULL) { 2476231200Smm r = errno; 2477231200Smm#endif 2478231200Smm closedir(t->d); 2479231200Smm t->d = INVALID_DIR_HANDLE; 2480231200Smm if (r != 0) { 2481231200Smm t->tree_errno = r; 2482231200Smm t->visit_type = TREE_ERROR_DIR; 2483231200Smm return (t->visit_type); 2484231200Smm } else 2485231200Smm return (0); 2486231200Smm } 2487231200Smm name = t->de->d_name; 2488231200Smm namelen = D_NAMELEN(t->de); 2489231200Smm t->flags &= ~hasLstat; 2490231200Smm t->flags &= ~hasStat; 2491231200Smm if (name[0] == '.' && name[1] == '\0') 2492231200Smm continue; 2493231200Smm if (name[0] == '.' && name[1] == '.' && name[2] == '\0') 2494231200Smm continue; 2495231200Smm tree_append(t, name, namelen); 2496231200Smm return (t->visit_type = TREE_REGULAR); 2497231200Smm } 2498231200Smm} 2499231200Smm 2500231200Smm 2501231200Smm/* 2502231200Smm * Get the stat() data for the entry just returned from tree_next(). 2503231200Smm */ 2504231200Smmstatic const struct stat * 2505231200Smmtree_current_stat(struct tree *t) 2506231200Smm{ 2507231200Smm if (!(t->flags & hasStat)) { 2508231200Smm#ifdef HAVE_FSTATAT 2509231200Smm if (fstatat(tree_current_dir_fd(t), 2510231200Smm tree_current_access_path(t), &t->st, 0) != 0) 2511231200Smm#else 2512238856Smm if (tree_enter_working_dir(t) != 0) 2513238856Smm return NULL; 2514348608Smm if (la_stat(tree_current_access_path(t), &t->st) != 0) 2515231200Smm#endif 2516231200Smm return NULL; 2517231200Smm t->flags |= hasStat; 2518231200Smm } 2519231200Smm return (&t->st); 2520231200Smm} 2521231200Smm 2522231200Smm/* 2523231200Smm * Get the lstat() data for the entry just returned from tree_next(). 2524231200Smm */ 2525231200Smmstatic const struct stat * 2526231200Smmtree_current_lstat(struct tree *t) 2527231200Smm{ 2528231200Smm if (!(t->flags & hasLstat)) { 2529231200Smm#ifdef HAVE_FSTATAT 2530231200Smm if (fstatat(tree_current_dir_fd(t), 2531231200Smm tree_current_access_path(t), &t->lst, 2532231200Smm AT_SYMLINK_NOFOLLOW) != 0) 2533231200Smm#else 2534238856Smm if (tree_enter_working_dir(t) != 0) 2535238856Smm return NULL; 2536231200Smm if (lstat(tree_current_access_path(t), &t->lst) != 0) 2537231200Smm#endif 2538231200Smm return NULL; 2539231200Smm t->flags |= hasLstat; 2540231200Smm } 2541231200Smm return (&t->lst); 2542231200Smm} 2543231200Smm 2544231200Smm/* 2545231200Smm * Test whether current entry is a dir or link to a dir. 2546231200Smm */ 2547231200Smmstatic int 2548231200Smmtree_current_is_dir(struct tree *t) 2549231200Smm{ 2550231200Smm const struct stat *st; 2551231200Smm /* 2552231200Smm * If we already have lstat() info, then try some 2553231200Smm * cheap tests to determine if this is a dir. 2554231200Smm */ 2555231200Smm if (t->flags & hasLstat) { 2556231200Smm /* If lstat() says it's a dir, it must be a dir. */ 2557238856Smm st = tree_current_lstat(t); 2558238856Smm if (st == NULL) 2559238856Smm return 0; 2560238856Smm if (S_ISDIR(st->st_mode)) 2561231200Smm return 1; 2562231200Smm /* Not a dir; might be a link to a dir. */ 2563231200Smm /* If it's not a link, then it's not a link to a dir. */ 2564248616Smm if (!S_ISLNK(st->st_mode)) 2565231200Smm return 0; 2566231200Smm /* 2567231200Smm * It's a link, but we don't know what it's a link to, 2568231200Smm * so we'll have to use stat(). 2569231200Smm */ 2570231200Smm } 2571231200Smm 2572231200Smm st = tree_current_stat(t); 2573231200Smm /* If we can't stat it, it's not a dir. */ 2574231200Smm if (st == NULL) 2575231200Smm return 0; 2576231200Smm /* Use the definitive test. Hopefully this is cached. */ 2577231200Smm return (S_ISDIR(st->st_mode)); 2578231200Smm} 2579231200Smm 2580231200Smm/* 2581231200Smm * Test whether current entry is a physical directory. Usually, we 2582231200Smm * already have at least one of stat() or lstat() in memory, so we 2583231200Smm * use tricks to try to avoid an extra trip to the disk. 2584231200Smm */ 2585231200Smmstatic int 2586231200Smmtree_current_is_physical_dir(struct tree *t) 2587231200Smm{ 2588231200Smm const struct stat *st; 2589231200Smm 2590231200Smm /* 2591231200Smm * If stat() says it isn't a dir, then it's not a dir. 2592231200Smm * If stat() data is cached, this check is free, so do it first. 2593231200Smm */ 2594238856Smm if (t->flags & hasStat) { 2595238856Smm st = tree_current_stat(t); 2596238856Smm if (st == NULL) 2597238856Smm return (0); 2598238856Smm if (!S_ISDIR(st->st_mode)) 2599238856Smm return (0); 2600238856Smm } 2601231200Smm 2602231200Smm /* 2603231200Smm * Either stat() said it was a dir (in which case, we have 2604231200Smm * to determine whether it's really a link to a dir) or 2605231200Smm * stat() info wasn't available. So we use lstat(), which 2606231200Smm * hopefully is already cached. 2607231200Smm */ 2608231200Smm 2609231200Smm st = tree_current_lstat(t); 2610231200Smm /* If we can't stat it, it's not a dir. */ 2611231200Smm if (st == NULL) 2612231200Smm return 0; 2613231200Smm /* Use the definitive test. Hopefully this is cached. */ 2614231200Smm return (S_ISDIR(st->st_mode)); 2615231200Smm} 2616231200Smm 2617231200Smm/* 2618231200Smm * Test whether the same file has been in the tree as its parent. 2619231200Smm */ 2620231200Smmstatic int 2621231200Smmtree_target_is_same_as_parent(struct tree *t, const struct stat *st) 2622231200Smm{ 2623231200Smm struct tree_entry *te; 2624231200Smm 2625231200Smm for (te = t->current->parent; te != NULL; te = te->parent) { 2626232153Smm if (te->dev == (int64_t)st->st_dev && 2627232153Smm te->ino == (int64_t)st->st_ino) 2628231200Smm return (1); 2629231200Smm } 2630231200Smm return (0); 2631231200Smm} 2632231200Smm 2633231200Smm/* 2634231200Smm * Test whether the current file is symbolic link target and 2635231200Smm * on the other filesystem. 2636231200Smm */ 2637231200Smmstatic int 2638231200Smmtree_current_is_symblic_link_target(struct tree *t) 2639231200Smm{ 2640231200Smm static const struct stat *lst, *st; 2641231200Smm 2642231200Smm lst = tree_current_lstat(t); 2643231200Smm st = tree_current_stat(t); 2644238856Smm return (st != NULL && lst != NULL && 2645232153Smm (int64_t)st->st_dev == t->current_filesystem->dev && 2646231200Smm st->st_dev != lst->st_dev); 2647231200Smm} 2648231200Smm 2649231200Smm/* 2650231200Smm * Return the access path for the entry just returned from tree_next(). 2651231200Smm */ 2652231200Smmstatic const char * 2653231200Smmtree_current_access_path(struct tree *t) 2654231200Smm{ 2655231200Smm return (t->basename); 2656231200Smm} 2657231200Smm 2658231200Smm/* 2659231200Smm * Return the full path for the entry just returned from tree_next(). 2660231200Smm */ 2661231200Smmstatic const char * 2662231200Smmtree_current_path(struct tree *t) 2663231200Smm{ 2664231200Smm return (t->path.s); 2665231200Smm} 2666231200Smm 2667231200Smm/* 2668231200Smm * Terminate the traversal. 2669231200Smm */ 2670231200Smmstatic void 2671231200Smmtree_close(struct tree *t) 2672231200Smm{ 2673231200Smm 2674231200Smm if (t == NULL) 2675231200Smm return; 2676231200Smm if (t->entry_fd >= 0) { 2677231200Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 2678231200Smm t->entry_fd = -1; 2679231200Smm } 2680231200Smm /* Close the handle of readdir(). */ 2681231200Smm if (t->d != INVALID_DIR_HANDLE) { 2682231200Smm closedir(t->d); 2683231200Smm t->d = INVALID_DIR_HANDLE; 2684231200Smm } 2685231200Smm /* Release anything remaining in the stack. */ 2686231200Smm while (t->stack != NULL) { 2687231200Smm if (t->stack->flags & isDirLink) 2688231200Smm close(t->stack->symlink_parent_fd); 2689231200Smm tree_pop(t); 2690231200Smm } 2691231200Smm if (t->working_dir_fd >= 0) { 2692231200Smm close(t->working_dir_fd); 2693231200Smm t->working_dir_fd = -1; 2694231200Smm } 2695231200Smm if (t->initial_dir_fd >= 0) { 2696231200Smm close(t->initial_dir_fd); 2697231200Smm t->initial_dir_fd = -1; 2698231200Smm } 2699231200Smm} 2700231200Smm 2701231200Smm/* 2702231200Smm * Release any resources. 2703231200Smm */ 2704231200Smmstatic void 2705231200Smmtree_free(struct tree *t) 2706231200Smm{ 2707231200Smm int i; 2708231200Smm 2709231200Smm if (t == NULL) 2710231200Smm return; 2711231200Smm archive_string_free(&t->path); 2712306322Smm#if defined(USE_READDIR_R) 2713231200Smm free(t->dirent); 2714231200Smm#endif 2715231200Smm free(t->sparse_list); 2716231200Smm for (i = 0; i < t->max_filesystem_id; i++) 2717231200Smm free(t->filesystem_table[i].allocation_ptr); 2718231200Smm free(t->filesystem_table); 2719231200Smm free(t); 2720231200Smm} 2721231200Smm 2722231200Smm#endif 2723