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; 168231200Smm#if defined(HAVE_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; 203231200Smm#if defined(HAVE_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; 247231200Smm int allocated_filesytem; 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 *); 359231200Smmstatic int _archive_read_next_header2(struct archive *, 360231200Smm struct archive_entry *); 361231200Smmstatic const char *trivial_lookup_gname(void *, int64_t gid); 362231200Smmstatic const char *trivial_lookup_uname(void *, int64_t uid); 363231200Smmstatic int setup_sparse(struct archive_read_disk *, struct archive_entry *); 364231200Smmstatic int close_and_restore_time(int fd, struct tree *, 365231200Smm struct restore_time *); 366238856Smmstatic int open_on_current_dir(struct tree *, const char *, int); 367248616Smmstatic int tree_dup(int); 368228753Smm 369231200Smm 370228753Smmstatic struct archive_vtable * 371228753Smmarchive_read_disk_vtable(void) 372228753Smm{ 373228753Smm static struct archive_vtable av; 374228753Smm static int inited = 0; 375228753Smm 376228753Smm if (!inited) { 377228905Smm av.archive_free = _archive_read_free; 378228753Smm av.archive_close = _archive_read_close; 379231200Smm av.archive_read_data_block = _archive_read_data_block; 380231200Smm av.archive_read_next_header2 = _archive_read_next_header2; 381231200Smm inited = 1; 382228753Smm } 383228753Smm return (&av); 384228753Smm} 385228753Smm 386228753Smmconst char * 387231200Smmarchive_read_disk_gname(struct archive *_a, int64_t gid) 388228753Smm{ 389228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 390231200Smm if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 391231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_gname")) 392231200Smm return (NULL); 393231200Smm if (a->lookup_gname == NULL) 394231200Smm return (NULL); 395231200Smm return ((*a->lookup_gname)(a->lookup_gname_data, gid)); 396228753Smm} 397228753Smm 398228753Smmconst char * 399231200Smmarchive_read_disk_uname(struct archive *_a, int64_t uid) 400228753Smm{ 401228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 402231200Smm if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 403231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_uname")) 404231200Smm return (NULL); 405231200Smm if (a->lookup_uname == NULL) 406231200Smm return (NULL); 407231200Smm return ((*a->lookup_uname)(a->lookup_uname_data, uid)); 408228753Smm} 409228753Smm 410228753Smmint 411228753Smmarchive_read_disk_set_gname_lookup(struct archive *_a, 412228753Smm void *private_data, 413231200Smm const char * (*lookup_gname)(void *private, int64_t gid), 414228753Smm void (*cleanup_gname)(void *private)) 415228753Smm{ 416228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 417231200Smm archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, 418228753Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup"); 419228753Smm 420228753Smm if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) 421228753Smm (a->cleanup_gname)(a->lookup_gname_data); 422228753Smm 423228753Smm a->lookup_gname = lookup_gname; 424228753Smm a->cleanup_gname = cleanup_gname; 425228753Smm a->lookup_gname_data = private_data; 426228753Smm return (ARCHIVE_OK); 427228753Smm} 428228753Smm 429228753Smmint 430228753Smmarchive_read_disk_set_uname_lookup(struct archive *_a, 431228753Smm void *private_data, 432231200Smm const char * (*lookup_uname)(void *private, int64_t uid), 433228753Smm void (*cleanup_uname)(void *private)) 434228753Smm{ 435228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 436231200Smm archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC, 437228753Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup"); 438228753Smm 439228753Smm if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) 440228753Smm (a->cleanup_uname)(a->lookup_uname_data); 441228753Smm 442228753Smm a->lookup_uname = lookup_uname; 443228753Smm a->cleanup_uname = cleanup_uname; 444228753Smm a->lookup_uname_data = private_data; 445228753Smm return (ARCHIVE_OK); 446228753Smm} 447228753Smm 448228753Smm/* 449228753Smm * Create a new archive_read_disk object and initialize it with global state. 450228753Smm */ 451228753Smmstruct archive * 452228753Smmarchive_read_disk_new(void) 453228753Smm{ 454228753Smm struct archive_read_disk *a; 455228753Smm 456238856Smm a = (struct archive_read_disk *)calloc(1, sizeof(*a)); 457228753Smm if (a == NULL) 458228753Smm return (NULL); 459228753Smm a->archive.magic = ARCHIVE_READ_DISK_MAGIC; 460231200Smm a->archive.state = ARCHIVE_STATE_NEW; 461228753Smm a->archive.vtable = archive_read_disk_vtable(); 462228753Smm a->lookup_uname = trivial_lookup_uname; 463228753Smm a->lookup_gname = trivial_lookup_gname; 464238856Smm a->enable_copyfile = 1; 465238856Smm a->traverse_mount_points = 1; 466238856Smm a->open_on_current_dir = open_on_current_dir; 467238856Smm a->tree_current_dir_fd = tree_current_dir_fd; 468238856Smm a->tree_enter_working_dir = tree_enter_working_dir; 469228753Smm return (&a->archive); 470228753Smm} 471228753Smm 472228753Smmstatic int 473228905Smm_archive_read_free(struct archive *_a) 474228753Smm{ 475228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 476231200Smm int r; 477228753Smm 478231200Smm if (_a == NULL) 479231200Smm return (ARCHIVE_OK); 480231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 481231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); 482231200Smm 483231200Smm if (a->archive.state != ARCHIVE_STATE_CLOSED) 484231200Smm r = _archive_read_close(&a->archive); 485231200Smm else 486231200Smm r = ARCHIVE_OK; 487231200Smm 488231200Smm tree_free(a->tree); 489228753Smm if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL) 490228753Smm (a->cleanup_gname)(a->lookup_gname_data); 491228753Smm if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL) 492228753Smm (a->cleanup_uname)(a->lookup_uname_data); 493228753Smm archive_string_free(&a->archive.error_string); 494231200Smm a->archive.magic = 0; 495231200Smm __archive_clean(&a->archive); 496228753Smm free(a); 497231200Smm return (r); 498228753Smm} 499228753Smm 500228753Smmstatic int 501228753Smm_archive_read_close(struct archive *_a) 502228753Smm{ 503231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 504231200Smm 505231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 506231200Smm ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); 507231200Smm 508231200Smm if (a->archive.state != ARCHIVE_STATE_FATAL) 509231200Smm a->archive.state = ARCHIVE_STATE_CLOSED; 510231200Smm 511231200Smm tree_close(a->tree); 512231200Smm 513228753Smm return (ARCHIVE_OK); 514228753Smm} 515228753Smm 516231200Smmstatic void 517231200Smmsetup_symlink_mode(struct archive_read_disk *a, char symlink_mode, 518231200Smm int follow_symlinks) 519231200Smm{ 520231200Smm a->symlink_mode = symlink_mode; 521231200Smm a->follow_symlinks = follow_symlinks; 522231200Smm if (a->tree != NULL) { 523231200Smm a->tree->initial_symlink_mode = a->symlink_mode; 524231200Smm a->tree->symlink_mode = a->symlink_mode; 525231200Smm } 526231200Smm} 527231200Smm 528228753Smmint 529228753Smmarchive_read_disk_set_symlink_logical(struct archive *_a) 530228753Smm{ 531228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 532231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 533231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_logical"); 534231200Smm setup_symlink_mode(a, 'L', 1); 535228753Smm return (ARCHIVE_OK); 536228753Smm} 537228753Smm 538228753Smmint 539228753Smmarchive_read_disk_set_symlink_physical(struct archive *_a) 540228753Smm{ 541228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 542231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 543231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_physical"); 544231200Smm setup_symlink_mode(a, 'P', 0); 545228753Smm return (ARCHIVE_OK); 546228753Smm} 547228753Smm 548228753Smmint 549228753Smmarchive_read_disk_set_symlink_hybrid(struct archive *_a) 550228753Smm{ 551228753Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 552231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 553231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_symlink_hybrid"); 554231200Smm setup_symlink_mode(a, 'H', 1);/* Follow symlinks initially. */ 555228753Smm return (ARCHIVE_OK); 556228753Smm} 557228753Smm 558231200Smmint 559231200Smmarchive_read_disk_set_atime_restored(struct archive *_a) 560231200Smm{ 561231200Smm#ifndef HAVE_UTIMES 562231200Smm static int warning_done = 0; 563231200Smm#endif 564231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 565231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 566231200Smm ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime"); 567231200Smm#ifdef HAVE_UTIMES 568231200Smm a->restore_time = 1; 569231200Smm if (a->tree != NULL) 570231200Smm a->tree->flags |= needsRestoreTimes; 571231200Smm return (ARCHIVE_OK); 572231200Smm#else 573231200Smm if (warning_done) 574231200Smm /* Warning was already emitted; suppress further warnings. */ 575231200Smm return (ARCHIVE_OK); 576231200Smm 577231200Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 578231200Smm "Cannot restore access time on this system"); 579231200Smm warning_done = 1; 580231200Smm return (ARCHIVE_WARN); 581231200Smm#endif 582231200Smm} 583231200Smm 584238856Smmint 585238856Smmarchive_read_disk_set_behavior(struct archive *_a, int flags) 586238856Smm{ 587238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 588238856Smm int r = ARCHIVE_OK; 589238856Smm 590238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 591238856Smm ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump"); 592238856Smm 593238856Smm if (flags & ARCHIVE_READDISK_RESTORE_ATIME) 594238856Smm r = archive_read_disk_set_atime_restored(_a); 595238856Smm else { 596238856Smm a->restore_time = 0; 597238856Smm if (a->tree != NULL) 598238856Smm a->tree->flags &= ~needsRestoreTimes; 599238856Smm } 600238856Smm if (flags & ARCHIVE_READDISK_HONOR_NODUMP) 601238856Smm a->honor_nodump = 1; 602238856Smm else 603238856Smm a->honor_nodump = 0; 604238856Smm if (flags & ARCHIVE_READDISK_MAC_COPYFILE) 605238856Smm a->enable_copyfile = 1; 606238856Smm else 607238856Smm a->enable_copyfile = 0; 608238856Smm if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) 609238856Smm a->traverse_mount_points = 0; 610238856Smm else 611238856Smm a->traverse_mount_points = 1; 612238856Smm return (r); 613238856Smm} 614238856Smm 615228753Smm/* 616228753Smm * Trivial implementations of gname/uname lookup functions. 617228753Smm * These are normally overridden by the client, but these stub 618228753Smm * versions ensure that we always have something that works. 619228753Smm */ 620228753Smmstatic const char * 621231200Smmtrivial_lookup_gname(void *private_data, int64_t gid) 622228753Smm{ 623228753Smm (void)private_data; /* UNUSED */ 624228753Smm (void)gid; /* UNUSED */ 625228753Smm return (NULL); 626228753Smm} 627228753Smm 628228753Smmstatic const char * 629231200Smmtrivial_lookup_uname(void *private_data, int64_t uid) 630228753Smm{ 631228753Smm (void)private_data; /* UNUSED */ 632228753Smm (void)uid; /* UNUSED */ 633228753Smm return (NULL); 634228753Smm} 635231200Smm 636231200Smm/* 637231200Smm * Allocate memory for the reading buffer adjusted to the filesystem 638231200Smm * alignment. 639231200Smm */ 640231200Smmstatic int 641231200Smmsetup_suitable_read_buffer(struct archive_read_disk *a) 642231200Smm{ 643231200Smm struct tree *t = a->tree; 644231200Smm struct filesystem *cf = t->current_filesystem; 645231200Smm size_t asize; 646231200Smm size_t s; 647231200Smm 648231200Smm if (cf->allocation_ptr == NULL) { 649231200Smm /* If we couldn't get a filesystem alignment, 650231200Smm * we use 4096 as default value but we won't use 651231200Smm * O_DIRECT to open() and openat() operations. */ 652231200Smm long xfer_align = (cf->xfer_align == -1)?4096:cf->xfer_align; 653231200Smm 654231200Smm if (cf->max_xfer_size != -1) 655231200Smm asize = cf->max_xfer_size + xfer_align; 656231200Smm else { 657231200Smm long incr = cf->incr_xfer_size; 658231200Smm /* Some platform does not set a proper value to 659231200Smm * incr_xfer_size.*/ 660231200Smm if (incr < 0) 661231200Smm incr = cf->min_xfer_size; 662231200Smm if (cf->min_xfer_size < 0) { 663231200Smm incr = xfer_align; 664231200Smm asize = xfer_align; 665231200Smm } else 666231200Smm asize = cf->min_xfer_size; 667231200Smm 668231200Smm /* Increase a buffer size up to 64K bytes in 669231200Smm * a proper incremant size. */ 670231200Smm while (asize < 1024*64) 671231200Smm asize += incr; 672231200Smm /* Take a margin to adjust to the filesystem 673231200Smm * alignment. */ 674231200Smm asize += xfer_align; 675231200Smm } 676231200Smm cf->allocation_ptr = malloc(asize); 677231200Smm if (cf->allocation_ptr == NULL) { 678231200Smm archive_set_error(&a->archive, ENOMEM, 679231200Smm "Couldn't allocate memory"); 680231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 681231200Smm return (ARCHIVE_FATAL); 682231200Smm } 683231200Smm 684231200Smm /* 685231200Smm * Calculate proper address for the filesystem. 686231200Smm */ 687231200Smm s = (uintptr_t)cf->allocation_ptr; 688231200Smm s %= xfer_align; 689231200Smm if (s > 0) 690231200Smm s = xfer_align - s; 691231200Smm 692231200Smm /* 693231200Smm * Set a read buffer pointer in the proper alignment of 694231200Smm * the current filesystem. 695231200Smm */ 696231200Smm cf->buff = cf->allocation_ptr + s; 697231200Smm cf->buff_size = asize - xfer_align; 698231200Smm } 699231200Smm return (ARCHIVE_OK); 700231200Smm} 701231200Smm 702231200Smmstatic int 703231200Smm_archive_read_data_block(struct archive *_a, const void **buff, 704231200Smm size_t *size, int64_t *offset) 705231200Smm{ 706231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 707231200Smm struct tree *t = a->tree; 708231200Smm int r; 709231200Smm ssize_t bytes; 710231200Smm size_t buffbytes; 711231200Smm 712231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 713231200Smm "archive_read_data_block"); 714231200Smm 715231200Smm if (t->entry_eof || t->entry_remaining_bytes <= 0) { 716231200Smm r = ARCHIVE_EOF; 717231200Smm goto abort_read_data; 718231200Smm } 719231200Smm 720231200Smm /* 721231200Smm * Open the current file. 722231200Smm */ 723231200Smm if (t->entry_fd < 0) { 724248616Smm int flags = O_RDONLY | O_BINARY | O_CLOEXEC; 725231200Smm 726231200Smm /* 727231200Smm * Eliminate or reduce cache effects if we can. 728231200Smm * 729231200Smm * Carefully consider this to be enabled. 730231200Smm */ 731231200Smm#if defined(O_DIRECT) && 0/* Disabled for now */ 732231200Smm if (t->current_filesystem->xfer_align != -1 && 733231200Smm t->nlink == 1) 734231200Smm flags |= O_DIRECT; 735231200Smm#endif 736231200Smm#if defined(O_NOATIME) 737231200Smm /* 738231200Smm * Linux has O_NOATIME flag; use it if we need. 739231200Smm */ 740231200Smm if ((t->flags & needsRestoreTimes) != 0 && 741231200Smm t->restore_time.noatime == 0) 742231200Smm flags |= O_NOATIME; 743231200Smm do { 744231200Smm#endif 745238856Smm t->entry_fd = open_on_current_dir(t, 746231200Smm tree_current_access_path(t), flags); 747248616Smm __archive_ensure_cloexec_flag(t->entry_fd); 748231200Smm#if defined(O_NOATIME) 749231200Smm /* 750231200Smm * When we did open the file with O_NOATIME flag, 751231200Smm * if successful, set 1 to t->restore_time.noatime 752231200Smm * not to restore an atime of the file later. 753231200Smm * if failed by EPERM, retry it without O_NOATIME flag. 754231200Smm */ 755231200Smm if (flags & O_NOATIME) { 756231200Smm if (t->entry_fd >= 0) 757231200Smm t->restore_time.noatime = 1; 758231200Smm else if (errno == EPERM) { 759231200Smm flags &= ~O_NOATIME; 760231200Smm continue; 761231200Smm } 762231200Smm } 763231200Smm } while (0); 764231200Smm#endif 765231200Smm if (t->entry_fd < 0) { 766231200Smm archive_set_error(&a->archive, errno, 767231200Smm "Couldn't open %s", tree_current_path(t)); 768231200Smm r = ARCHIVE_FAILED; 769231200Smm tree_enter_initial_dir(t); 770231200Smm goto abort_read_data; 771231200Smm } 772231200Smm tree_enter_initial_dir(t); 773231200Smm } 774231200Smm 775231200Smm /* 776231200Smm * Allocate read buffer if not allocated. 777231200Smm */ 778231200Smm if (t->current_filesystem->allocation_ptr == NULL) { 779231200Smm r = setup_suitable_read_buffer(a); 780231200Smm if (r != ARCHIVE_OK) { 781231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 782231200Smm goto abort_read_data; 783231200Smm } 784231200Smm } 785231200Smm t->entry_buff = t->current_filesystem->buff; 786231200Smm t->entry_buff_size = t->current_filesystem->buff_size; 787231200Smm 788231200Smm buffbytes = t->entry_buff_size; 789248616Smm if ((int64_t)buffbytes > t->current_sparse->length) 790248616Smm buffbytes = t->current_sparse->length; 791231200Smm 792231200Smm /* 793231200Smm * Skip hole. 794231200Smm * TODO: Should we consider t->current_filesystem->xfer_align? 795231200Smm */ 796231200Smm if (t->current_sparse->offset > t->entry_total) { 797231200Smm if (lseek(t->entry_fd, 798231200Smm (off_t)t->current_sparse->offset, SEEK_SET) < 0) { 799231200Smm archive_set_error(&a->archive, errno, "Seek error"); 800231200Smm r = ARCHIVE_FATAL; 801231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 802231200Smm goto abort_read_data; 803231200Smm } 804231200Smm bytes = t->current_sparse->offset - t->entry_total; 805231200Smm t->entry_remaining_bytes -= bytes; 806231200Smm t->entry_total += bytes; 807231200Smm } 808231200Smm 809231200Smm /* 810231200Smm * Read file contents. 811231200Smm */ 812231200Smm if (buffbytes > 0) { 813231200Smm bytes = read(t->entry_fd, t->entry_buff, buffbytes); 814231200Smm if (bytes < 0) { 815231200Smm archive_set_error(&a->archive, errno, "Read error"); 816231200Smm r = ARCHIVE_FATAL; 817231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 818231200Smm goto abort_read_data; 819231200Smm } 820231200Smm } else 821231200Smm bytes = 0; 822231200Smm if (bytes == 0) { 823231200Smm /* Get EOF */ 824231200Smm t->entry_eof = 1; 825231200Smm r = ARCHIVE_EOF; 826231200Smm goto abort_read_data; 827231200Smm } 828231200Smm *buff = t->entry_buff; 829231200Smm *size = bytes; 830231200Smm *offset = t->entry_total; 831231200Smm t->entry_total += bytes; 832231200Smm t->entry_remaining_bytes -= bytes; 833231200Smm if (t->entry_remaining_bytes == 0) { 834231200Smm /* Close the current file descriptor */ 835231200Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 836231200Smm t->entry_fd = -1; 837231200Smm t->entry_eof = 1; 838231200Smm } 839231200Smm t->current_sparse->offset += bytes; 840231200Smm t->current_sparse->length -= bytes; 841231200Smm if (t->current_sparse->length == 0 && !t->entry_eof) 842231200Smm t->current_sparse++; 843231200Smm return (ARCHIVE_OK); 844231200Smm 845231200Smmabort_read_data: 846231200Smm *buff = NULL; 847231200Smm *size = 0; 848231200Smm *offset = t->entry_total; 849231200Smm if (t->entry_fd >= 0) { 850231200Smm /* Close the current file descriptor */ 851231200Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 852231200Smm t->entry_fd = -1; 853231200Smm } 854231200Smm return (r); 855231200Smm} 856231200Smm 857231200Smmstatic int 858238856Smmnext_entry(struct archive_read_disk *a, struct tree *t, 859238856Smm struct archive_entry *entry) 860231200Smm{ 861231200Smm const struct stat *st; /* info to use for this entry */ 862231200Smm const struct stat *lst;/* lstat() information */ 863238856Smm const char *name; 864238856Smm int descend, r; 865231200Smm 866231200Smm st = NULL; 867231200Smm lst = NULL; 868238856Smm t->descend = 0; 869231200Smm do { 870231200Smm switch (tree_next(t)) { 871231200Smm case TREE_ERROR_FATAL: 872231200Smm archive_set_error(&a->archive, t->tree_errno, 873231200Smm "%s: Unable to continue traversing directory tree", 874231200Smm tree_current_path(t)); 875231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 876231200Smm tree_enter_initial_dir(t); 877231200Smm return (ARCHIVE_FATAL); 878231200Smm case TREE_ERROR_DIR: 879231200Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 880231200Smm "%s: Couldn't visit directory", 881231200Smm tree_current_path(t)); 882231200Smm tree_enter_initial_dir(t); 883231200Smm return (ARCHIVE_FAILED); 884231200Smm case 0: 885231200Smm tree_enter_initial_dir(t); 886231200Smm return (ARCHIVE_EOF); 887231200Smm case TREE_POSTDESCENT: 888231200Smm case TREE_POSTASCENT: 889231200Smm break; 890231200Smm case TREE_REGULAR: 891231200Smm lst = tree_current_lstat(t); 892231200Smm if (lst == NULL) { 893231200Smm archive_set_error(&a->archive, errno, 894231200Smm "%s: Cannot stat", 895231200Smm tree_current_path(t)); 896231200Smm tree_enter_initial_dir(t); 897231200Smm return (ARCHIVE_FAILED); 898231200Smm } 899231200Smm break; 900231200Smm } 901231200Smm } while (lst == NULL); 902231200Smm 903238856Smm#ifdef __APPLE__ 904238856Smm if (a->enable_copyfile) { 905238856Smm /* If we're using copyfile(), ignore "._XXX" files. */ 906238856Smm const char *bname = strrchr(tree_current_path(t), '/'); 907238856Smm if (bname == NULL) 908238856Smm bname = tree_current_path(t); 909238856Smm else 910238856Smm ++bname; 911238856Smm if (bname[0] == '.' && bname[1] == '_') 912238856Smm return (ARCHIVE_RETRY); 913238856Smm } 914238856Smm#endif 915238856Smm 916238856Smm archive_entry_copy_pathname(entry, tree_current_path(t)); 917231200Smm /* 918238856Smm * Perform path matching. 919238856Smm */ 920238856Smm if (a->matching) { 921238856Smm r = archive_match_path_excluded(a->matching, entry); 922238856Smm if (r < 0) { 923238856Smm archive_set_error(&(a->archive), errno, 924238856Smm "Faild : %s", archive_error_string(a->matching)); 925238856Smm return (r); 926238856Smm } 927238856Smm if (r) { 928238856Smm if (a->excluded_cb_func) 929238856Smm a->excluded_cb_func(&(a->archive), 930238856Smm a->excluded_cb_data, entry); 931238856Smm return (ARCHIVE_RETRY); 932238856Smm } 933238856Smm } 934238856Smm 935238856Smm /* 936231200Smm * Distinguish 'L'/'P'/'H' symlink following. 937231200Smm */ 938231200Smm switch(t->symlink_mode) { 939231200Smm case 'H': 940231200Smm /* 'H': After the first item, rest like 'P'. */ 941231200Smm t->symlink_mode = 'P'; 942231200Smm /* 'H': First item (from command line) like 'L'. */ 943231200Smm /* FALLTHROUGH */ 944231200Smm case 'L': 945231200Smm /* 'L': Do descend through a symlink to dir. */ 946231200Smm descend = tree_current_is_dir(t); 947231200Smm /* 'L': Follow symlinks to files. */ 948231200Smm a->symlink_mode = 'L'; 949231200Smm a->follow_symlinks = 1; 950231200Smm /* 'L': Archive symlinks as targets, if we can. */ 951231200Smm st = tree_current_stat(t); 952231200Smm if (st != NULL && !tree_target_is_same_as_parent(t, st)) 953231200Smm break; 954231200Smm /* If stat fails, we have a broken symlink; 955231200Smm * in that case, don't follow the link. */ 956231200Smm /* FALLTHROUGH */ 957231200Smm default: 958231200Smm /* 'P': Don't descend through a symlink to dir. */ 959231200Smm descend = tree_current_is_physical_dir(t); 960231200Smm /* 'P': Don't follow symlinks to files. */ 961231200Smm a->symlink_mode = 'P'; 962231200Smm a->follow_symlinks = 0; 963231200Smm /* 'P': Archive symlinks as symlinks. */ 964231200Smm st = lst; 965231200Smm break; 966231200Smm } 967231200Smm 968231200Smm if (update_current_filesystem(a, st->st_dev) != ARCHIVE_OK) { 969231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 970231200Smm tree_enter_initial_dir(t); 971231200Smm return (ARCHIVE_FATAL); 972231200Smm } 973238856Smm if (t->initial_filesystem_id == -1) 974238856Smm t->initial_filesystem_id = t->current_filesystem_id; 975238856Smm if (!a->traverse_mount_points) { 976238856Smm if (t->initial_filesystem_id != t->current_filesystem_id) 977238856Smm return (ARCHIVE_RETRY); 978238856Smm } 979231200Smm t->descend = descend; 980231200Smm 981238856Smm /* 982238856Smm * Honor nodump flag. 983238856Smm * If the file is marked with nodump flag, do not return this entry. 984238856Smm */ 985238856Smm if (a->honor_nodump) { 986238856Smm#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) 987238856Smm if (st->st_flags & UF_NODUMP) 988238856Smm return (ARCHIVE_RETRY); 989238856Smm#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\ 990238856Smm defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) 991238856Smm if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) { 992248616Smm int stflags; 993238856Smm 994238856Smm t->entry_fd = open_on_current_dir(t, 995248616Smm tree_current_access_path(t), 996248616Smm O_RDONLY | O_NONBLOCK | O_CLOEXEC); 997248616Smm __archive_ensure_cloexec_flag(t->entry_fd); 998238856Smm if (t->entry_fd >= 0) { 999238856Smm r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS, 1000238856Smm &stflags); 1001238856Smm if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0) 1002238856Smm return (ARCHIVE_RETRY); 1003238856Smm } 1004238856Smm } 1005238856Smm#endif 1006238856Smm } 1007238856Smm 1008231200Smm archive_entry_copy_stat(entry, st); 1009231200Smm 1010238856Smm /* Save the times to be restored. This must be in before 1011238856Smm * calling archive_read_disk_descend() or any chance of it, 1012238856Smm * especially, invokng a callback. */ 1013231200Smm t->restore_time.mtime = archive_entry_mtime(entry); 1014231200Smm t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry); 1015231200Smm t->restore_time.atime = archive_entry_atime(entry); 1016231200Smm t->restore_time.atime_nsec = archive_entry_atime_nsec(entry); 1017231200Smm t->restore_time.filetype = archive_entry_filetype(entry); 1018231200Smm t->restore_time.noatime = t->current_filesystem->noatime; 1019231200Smm 1020231200Smm /* 1021238856Smm * Perform time matching. 1022231200Smm */ 1023238856Smm if (a->matching) { 1024238856Smm r = archive_match_time_excluded(a->matching, entry); 1025238856Smm if (r < 0) { 1026238856Smm archive_set_error(&(a->archive), errno, 1027238856Smm "Faild : %s", archive_error_string(a->matching)); 1028238856Smm return (r); 1029238856Smm } 1030238856Smm if (r) { 1031238856Smm if (a->excluded_cb_func) 1032238856Smm a->excluded_cb_func(&(a->archive), 1033238856Smm a->excluded_cb_data, entry); 1034238856Smm return (ARCHIVE_RETRY); 1035238856Smm } 1036238856Smm } 1037231200Smm 1038238856Smm /* Lookup uname/gname */ 1039238856Smm name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry)); 1040238856Smm if (name != NULL) 1041238856Smm archive_entry_copy_uname(entry, name); 1042238856Smm name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry)); 1043238856Smm if (name != NULL) 1044238856Smm archive_entry_copy_gname(entry, name); 1045231200Smm 1046231200Smm /* 1047238856Smm * Perform owner matching. 1048238856Smm */ 1049238856Smm if (a->matching) { 1050238856Smm r = archive_match_owner_excluded(a->matching, entry); 1051238856Smm if (r < 0) { 1052238856Smm archive_set_error(&(a->archive), errno, 1053238856Smm "Faild : %s", archive_error_string(a->matching)); 1054238856Smm return (r); 1055238856Smm } 1056238856Smm if (r) { 1057238856Smm if (a->excluded_cb_func) 1058238856Smm a->excluded_cb_func(&(a->archive), 1059238856Smm a->excluded_cb_data, entry); 1060238856Smm return (ARCHIVE_RETRY); 1061238856Smm } 1062238856Smm } 1063238856Smm 1064238856Smm /* 1065238856Smm * Invoke a meta data filter callback. 1066238856Smm */ 1067238856Smm if (a->metadata_filter_func) { 1068238856Smm if (!a->metadata_filter_func(&(a->archive), 1069238856Smm a->metadata_filter_data, entry)) 1070238856Smm return (ARCHIVE_RETRY); 1071238856Smm } 1072238856Smm 1073238856Smm /* 1074231200Smm * Populate the archive_entry with metadata from the disk. 1075231200Smm */ 1076238856Smm archive_entry_copy_sourcepath(entry, tree_current_access_path(t)); 1077238856Smm r = archive_read_disk_entry_from_file(&(a->archive), entry, 1078238856Smm t->entry_fd, st); 1079231200Smm 1080238856Smm return (r); 1081238856Smm} 1082231200Smm 1083238856Smmstatic int 1084238856Smm_archive_read_next_header2(struct archive *_a, struct archive_entry *entry) 1085238856Smm{ 1086238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1087238856Smm struct tree *t; 1088238856Smm int r; 1089238856Smm 1090238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1091238856Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1092238856Smm "archive_read_next_header2"); 1093238856Smm 1094238856Smm t = a->tree; 1095238856Smm if (t->entry_fd >= 0) { 1096238856Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 1097238856Smm t->entry_fd = -1; 1098238856Smm } 1099238856Smm 1100238856Smm for (;;) { 1101238856Smm r = next_entry(a, t, entry); 1102238856Smm if (t->entry_fd >= 0) { 1103238856Smm close(t->entry_fd); 1104238856Smm t->entry_fd = -1; 1105238856Smm } 1106238856Smm 1107238856Smm if (r == ARCHIVE_RETRY) { 1108238856Smm archive_entry_clear(entry); 1109238856Smm continue; 1110238856Smm } 1111238856Smm break; 1112238856Smm } 1113238856Smm 1114231200Smm /* Return to the initial directory. */ 1115231200Smm tree_enter_initial_dir(t); 1116231200Smm 1117231200Smm /* 1118231200Smm * EOF and FATAL are persistent at this layer. By 1119231200Smm * modifying the state, we guarantee that future calls to 1120231200Smm * read a header or read data will fail. 1121231200Smm */ 1122231200Smm switch (r) { 1123231200Smm case ARCHIVE_EOF: 1124231200Smm a->archive.state = ARCHIVE_STATE_EOF; 1125231200Smm break; 1126231200Smm case ARCHIVE_OK: 1127231200Smm case ARCHIVE_WARN: 1128238856Smm /* Overwrite the sourcepath based on the initial directory. */ 1129238856Smm archive_entry_copy_sourcepath(entry, tree_current_path(t)); 1130231200Smm t->entry_total = 0; 1131231200Smm if (archive_entry_filetype(entry) == AE_IFREG) { 1132231200Smm t->nlink = archive_entry_nlink(entry); 1133231200Smm t->entry_remaining_bytes = archive_entry_size(entry); 1134231200Smm t->entry_eof = (t->entry_remaining_bytes == 0)? 1: 0; 1135231200Smm if (!t->entry_eof && 1136231200Smm setup_sparse(a, entry) != ARCHIVE_OK) 1137231200Smm return (ARCHIVE_FATAL); 1138231200Smm } else { 1139231200Smm t->entry_remaining_bytes = 0; 1140231200Smm t->entry_eof = 1; 1141231200Smm } 1142231200Smm a->archive.state = ARCHIVE_STATE_DATA; 1143231200Smm break; 1144231200Smm case ARCHIVE_RETRY: 1145231200Smm break; 1146231200Smm case ARCHIVE_FATAL: 1147231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1148231200Smm break; 1149231200Smm } 1150231200Smm 1151231200Smm return (r); 1152231200Smm} 1153231200Smm 1154231200Smmstatic int 1155231200Smmsetup_sparse(struct archive_read_disk *a, struct archive_entry *entry) 1156231200Smm{ 1157231200Smm struct tree *t = a->tree; 1158231200Smm int64_t length, offset; 1159231200Smm int i; 1160231200Smm 1161231200Smm t->sparse_count = archive_entry_sparse_reset(entry); 1162231200Smm if (t->sparse_count+1 > t->sparse_list_size) { 1163231200Smm free(t->sparse_list); 1164231200Smm t->sparse_list_size = t->sparse_count + 1; 1165231200Smm t->sparse_list = malloc(sizeof(t->sparse_list[0]) * 1166231200Smm t->sparse_list_size); 1167231200Smm if (t->sparse_list == NULL) { 1168231200Smm t->sparse_list_size = 0; 1169231200Smm archive_set_error(&a->archive, ENOMEM, 1170231200Smm "Can't allocate data"); 1171231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1172231200Smm return (ARCHIVE_FATAL); 1173231200Smm } 1174231200Smm } 1175231200Smm for (i = 0; i < t->sparse_count; i++) { 1176231200Smm archive_entry_sparse_next(entry, &offset, &length); 1177231200Smm t->sparse_list[i].offset = offset; 1178231200Smm t->sparse_list[i].length = length; 1179231200Smm } 1180231200Smm if (i == 0) { 1181231200Smm t->sparse_list[i].offset = 0; 1182231200Smm t->sparse_list[i].length = archive_entry_size(entry); 1183231200Smm } else { 1184231200Smm t->sparse_list[i].offset = archive_entry_size(entry); 1185231200Smm t->sparse_list[i].length = 0; 1186231200Smm } 1187231200Smm t->current_sparse = t->sparse_list; 1188231200Smm 1189231200Smm return (ARCHIVE_OK); 1190231200Smm} 1191231200Smm 1192238856Smmint 1193238856Smmarchive_read_disk_set_matching(struct archive *_a, struct archive *_ma, 1194238856Smm void (*_excluded_func)(struct archive *, void *, struct archive_entry *), 1195238856Smm void *_client_data) 1196238856Smm{ 1197238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1198238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1199238856Smm ARCHIVE_STATE_ANY, "archive_read_disk_set_matching"); 1200238856Smm a->matching = _ma; 1201238856Smm a->excluded_cb_func = _excluded_func; 1202238856Smm a->excluded_cb_data = _client_data; 1203238856Smm return (ARCHIVE_OK); 1204238856Smm} 1205238856Smm 1206238856Smmint 1207238856Smmarchive_read_disk_set_metadata_filter_callback(struct archive *_a, 1208238856Smm int (*_metadata_filter_func)(struct archive *, void *, 1209238856Smm struct archive_entry *), void *_client_data) 1210238856Smm{ 1211238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1212238856Smm 1213238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY, 1214238856Smm "archive_read_disk_set_metadata_filter_callback"); 1215238856Smm 1216238856Smm a->metadata_filter_func = _metadata_filter_func; 1217238856Smm a->metadata_filter_data = _client_data; 1218238856Smm return (ARCHIVE_OK); 1219238856Smm} 1220238856Smm 1221238856Smmint 1222238856Smmarchive_read_disk_can_descend(struct archive *_a) 1223238856Smm{ 1224238856Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1225238856Smm struct tree *t = a->tree; 1226238856Smm 1227238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1228238856Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1229238856Smm "archive_read_disk_can_descend"); 1230238856Smm 1231238856Smm return (t->visit_type == TREE_REGULAR && t->descend); 1232238856Smm} 1233238856Smm 1234231200Smm/* 1235231200Smm * Called by the client to mark the directory just returned from 1236231200Smm * tree_next() as needing to be visited. 1237231200Smm */ 1238231200Smmint 1239231200Smmarchive_read_disk_descend(struct archive *_a) 1240231200Smm{ 1241231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1242231200Smm struct tree *t = a->tree; 1243231200Smm 1244238856Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1245238856Smm ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, 1246231200Smm "archive_read_disk_descend"); 1247231200Smm 1248238856Smm if (t->visit_type != TREE_REGULAR || !t->descend) 1249238856Smm return (ARCHIVE_OK); 1250231200Smm 1251231200Smm if (tree_current_is_physical_dir(t)) { 1252231200Smm tree_push(t, t->basename, t->current_filesystem_id, 1253231200Smm t->lst.st_dev, t->lst.st_ino, &t->restore_time); 1254231200Smm t->stack->flags |= isDir; 1255231200Smm } else if (tree_current_is_dir(t)) { 1256231200Smm tree_push(t, t->basename, t->current_filesystem_id, 1257231200Smm t->st.st_dev, t->st.st_ino, &t->restore_time); 1258231200Smm t->stack->flags |= isDirLink; 1259231200Smm } 1260231200Smm t->descend = 0; 1261231200Smm return (ARCHIVE_OK); 1262231200Smm} 1263231200Smm 1264231200Smmint 1265231200Smmarchive_read_disk_open(struct archive *_a, const char *pathname) 1266231200Smm{ 1267231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1268231200Smm 1269231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1270231200Smm ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, 1271231200Smm "archive_read_disk_open"); 1272231200Smm archive_clear_error(&a->archive); 1273231200Smm 1274231200Smm return (_archive_read_disk_open(_a, pathname)); 1275231200Smm} 1276231200Smm 1277231200Smmint 1278231200Smmarchive_read_disk_open_w(struct archive *_a, const wchar_t *pathname) 1279231200Smm{ 1280231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1281231200Smm struct archive_string path; 1282231200Smm int ret; 1283231200Smm 1284231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, 1285231200Smm ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED, 1286231200Smm "archive_read_disk_open_w"); 1287231200Smm archive_clear_error(&a->archive); 1288231200Smm 1289231200Smm /* Make a char string from a wchar_t string. */ 1290231200Smm archive_string_init(&path); 1291231200Smm if (archive_string_append_from_wcs(&path, pathname, 1292231200Smm wcslen(pathname)) != 0) { 1293238856Smm if (errno == ENOMEM) 1294238856Smm archive_set_error(&a->archive, ENOMEM, 1295238856Smm "Can't allocate memory"); 1296238856Smm else 1297238856Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 1298238856Smm "Can't convert a path to a char string"); 1299231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1300231200Smm ret = ARCHIVE_FATAL; 1301231200Smm } else 1302231200Smm ret = _archive_read_disk_open(_a, path.s); 1303231200Smm 1304231200Smm archive_string_free(&path); 1305231200Smm return (ret); 1306231200Smm} 1307231200Smm 1308231200Smmstatic int 1309231200Smm_archive_read_disk_open(struct archive *_a, const char *pathname) 1310231200Smm{ 1311231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1312231200Smm 1313231200Smm if (a->tree != NULL) 1314231200Smm a->tree = tree_reopen(a->tree, pathname, a->restore_time); 1315231200Smm else 1316231200Smm a->tree = tree_open(pathname, a->symlink_mode, 1317231200Smm a->restore_time); 1318231200Smm if (a->tree == NULL) { 1319231200Smm archive_set_error(&a->archive, ENOMEM, 1320231200Smm "Can't allocate tar data"); 1321231200Smm a->archive.state = ARCHIVE_STATE_FATAL; 1322231200Smm return (ARCHIVE_FATAL); 1323231200Smm } 1324231200Smm a->archive.state = ARCHIVE_STATE_HEADER; 1325231200Smm 1326231200Smm return (ARCHIVE_OK); 1327231200Smm} 1328231200Smm 1329231200Smm/* 1330231200Smm * Return a current filesystem ID which is index of the filesystem entry 1331231200Smm * you've visited through archive_read_disk. 1332231200Smm */ 1333231200Smmint 1334231200Smmarchive_read_disk_current_filesystem(struct archive *_a) 1335231200Smm{ 1336231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1337231200Smm 1338231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 1339231200Smm "archive_read_disk_current_filesystem"); 1340231200Smm 1341231200Smm return (a->tree->current_filesystem_id); 1342231200Smm} 1343231200Smm 1344231200Smmstatic int 1345231200Smmupdate_current_filesystem(struct archive_read_disk *a, int64_t dev) 1346231200Smm{ 1347231200Smm struct tree *t = a->tree; 1348231200Smm int i, fid; 1349231200Smm 1350231200Smm if (t->current_filesystem != NULL && 1351231200Smm t->current_filesystem->dev == dev) 1352231200Smm return (ARCHIVE_OK); 1353231200Smm 1354231200Smm for (i = 0; i < t->max_filesystem_id; i++) { 1355231200Smm if (t->filesystem_table[i].dev == dev) { 1356231200Smm /* There is the filesytem ID we've already generated. */ 1357231200Smm t->current_filesystem_id = i; 1358231200Smm t->current_filesystem = &(t->filesystem_table[i]); 1359231200Smm return (ARCHIVE_OK); 1360231200Smm } 1361231200Smm } 1362231200Smm 1363231200Smm /* 1364231200Smm * This is the new filesytem which we have to generate a new ID for. 1365231200Smm */ 1366231200Smm fid = t->max_filesystem_id++; 1367231200Smm if (t->max_filesystem_id > t->allocated_filesytem) { 1368231200Smm size_t s; 1369248616Smm void *p; 1370231200Smm 1371231200Smm s = t->max_filesystem_id * 2; 1372248616Smm p = realloc(t->filesystem_table, 1373248616Smm s * sizeof(*t->filesystem_table)); 1374248616Smm if (p == NULL) { 1375231200Smm archive_set_error(&a->archive, ENOMEM, 1376231200Smm "Can't allocate tar data"); 1377231200Smm return (ARCHIVE_FATAL); 1378231200Smm } 1379248616Smm t->filesystem_table = (struct filesystem *)p; 1380231200Smm t->allocated_filesytem = s; 1381231200Smm } 1382231200Smm t->current_filesystem_id = fid; 1383231200Smm t->current_filesystem = &(t->filesystem_table[fid]); 1384231200Smm t->current_filesystem->dev = dev; 1385231200Smm t->current_filesystem->allocation_ptr = NULL; 1386231200Smm t->current_filesystem->buff = NULL; 1387231200Smm 1388231200Smm /* Setup the current filesystem properties which depend on 1389231200Smm * platform specific. */ 1390231200Smm return (setup_current_filesystem(a)); 1391231200Smm} 1392231200Smm 1393231200Smm/* 1394231200Smm * Returns 1 if current filesystem is generated filesystem, 0 if it is not 1395231200Smm * or -1 if it is unknown. 1396231200Smm */ 1397231200Smmint 1398231200Smmarchive_read_disk_current_filesystem_is_synthetic(struct archive *_a) 1399231200Smm{ 1400231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1401231200Smm 1402231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 1403231200Smm "archive_read_disk_current_filesystem"); 1404231200Smm 1405231200Smm return (a->tree->current_filesystem->synthetic); 1406231200Smm} 1407231200Smm 1408231200Smm/* 1409231200Smm * Returns 1 if current filesystem is remote filesystem, 0 if it is not 1410231200Smm * or -1 if it is unknown. 1411231200Smm */ 1412231200Smmint 1413231200Smmarchive_read_disk_current_filesystem_is_remote(struct archive *_a) 1414231200Smm{ 1415231200Smm struct archive_read_disk *a = (struct archive_read_disk *)_a; 1416231200Smm 1417231200Smm archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA, 1418231200Smm "archive_read_disk_current_filesystem"); 1419231200Smm 1420231200Smm return (a->tree->current_filesystem->remote); 1421231200Smm} 1422231200Smm 1423231200Smm#if defined(_PC_REC_INCR_XFER_SIZE) && defined(_PC_REC_MAX_XFER_SIZE) &&\ 1424231200Smm defined(_PC_REC_MIN_XFER_SIZE) && defined(_PC_REC_XFER_ALIGN) 1425231200Smmstatic int 1426231200Smmget_xfer_size(struct tree *t, int fd, const char *path) 1427231200Smm{ 1428231200Smm t->current_filesystem->xfer_align = -1; 1429231200Smm errno = 0; 1430231200Smm if (fd >= 0) { 1431231200Smm t->current_filesystem->incr_xfer_size = 1432231200Smm fpathconf(fd, _PC_REC_INCR_XFER_SIZE); 1433231200Smm t->current_filesystem->max_xfer_size = 1434231200Smm fpathconf(fd, _PC_REC_MAX_XFER_SIZE); 1435231200Smm t->current_filesystem->min_xfer_size = 1436231200Smm fpathconf(fd, _PC_REC_MIN_XFER_SIZE); 1437231200Smm t->current_filesystem->xfer_align = 1438231200Smm fpathconf(fd, _PC_REC_XFER_ALIGN); 1439231200Smm } else if (path != NULL) { 1440231200Smm t->current_filesystem->incr_xfer_size = 1441231200Smm pathconf(path, _PC_REC_INCR_XFER_SIZE); 1442231200Smm t->current_filesystem->max_xfer_size = 1443231200Smm pathconf(path, _PC_REC_MAX_XFER_SIZE); 1444231200Smm t->current_filesystem->min_xfer_size = 1445231200Smm pathconf(path, _PC_REC_MIN_XFER_SIZE); 1446231200Smm t->current_filesystem->xfer_align = 1447231200Smm pathconf(path, _PC_REC_XFER_ALIGN); 1448231200Smm } 1449231200Smm /* At least we need an alignment size. */ 1450231200Smm if (t->current_filesystem->xfer_align == -1) 1451231200Smm return ((errno == EINVAL)?1:-1); 1452231200Smm else 1453231200Smm return (0); 1454231200Smm} 1455231200Smm#else 1456231200Smmstatic int 1457231200Smmget_xfer_size(struct tree *t, int fd, const char *path) 1458231200Smm{ 1459231200Smm (void)t; /* UNUSED */ 1460231200Smm (void)fd; /* UNUSED */ 1461231200Smm (void)path; /* UNUSED */ 1462231200Smm return (1);/* Not supported */ 1463231200Smm} 1464231200Smm#endif 1465231200Smm 1466231200Smm#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \ 1467231200Smm && !defined(ST_LOCAL) 1468231200Smm 1469231200Smm/* 1470231200Smm * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X. 1471231200Smm */ 1472231200Smmstatic int 1473231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1474231200Smm{ 1475231200Smm struct tree *t = a->tree; 1476231200Smm struct statfs sfs; 1477231200Smm#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) 1478231200Smm struct xvfsconf vfc; 1479231200Smm#endif 1480231200Smm int r, xr = 0; 1481231200Smm#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX) 1482231200Smm long nm; 1483231200Smm#endif 1484231200Smm 1485231200Smm t->current_filesystem->synthetic = -1; 1486231200Smm t->current_filesystem->remote = -1; 1487231200Smm if (tree_current_is_symblic_link_target(t)) { 1488238856Smm#if defined(HAVE_OPENAT) 1489231200Smm /* 1490231200Smm * Get file system statistics on any directory 1491231200Smm * where current is. 1492231200Smm */ 1493231200Smm int fd = openat(tree_current_dir_fd(t), 1494248616Smm tree_current_access_path(t), O_RDONLY | O_CLOEXEC); 1495248616Smm __archive_ensure_cloexec_flag(fd); 1496231200Smm if (fd < 0) { 1497231200Smm archive_set_error(&a->archive, errno, 1498231200Smm "openat failed"); 1499231200Smm return (ARCHIVE_FAILED); 1500231200Smm } 1501231200Smm r = fstatfs(fd, &sfs); 1502231200Smm if (r == 0) 1503231200Smm xr = get_xfer_size(t, fd, NULL); 1504231200Smm close(fd); 1505231200Smm#else 1506238856Smm if (tree_enter_working_dir(t) != 0) { 1507238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1508238856Smm return (ARCHIVE_FAILED); 1509238856Smm } 1510231200Smm r = statfs(tree_current_access_path(t), &sfs); 1511231200Smm if (r == 0) 1512231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1513231200Smm#endif 1514231200Smm } else { 1515231200Smm r = fstatfs(tree_current_dir_fd(t), &sfs); 1516231200Smm if (r == 0) 1517231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1518231200Smm } 1519231200Smm if (r == -1 || xr == -1) { 1520231200Smm archive_set_error(&a->archive, errno, "statfs failed"); 1521231200Smm return (ARCHIVE_FAILED); 1522231200Smm } else if (xr == 1) { 1523231200Smm /* pathconf(_PC_REX_*) operations are not supported. */ 1524231200Smm t->current_filesystem->xfer_align = sfs.f_bsize; 1525231200Smm t->current_filesystem->max_xfer_size = -1; 1526231200Smm t->current_filesystem->min_xfer_size = sfs.f_iosize; 1527231200Smm t->current_filesystem->incr_xfer_size = sfs.f_iosize; 1528231200Smm } 1529231200Smm if (sfs.f_flags & MNT_LOCAL) 1530231200Smm t->current_filesystem->remote = 0; 1531231200Smm else 1532231200Smm t->current_filesystem->remote = 1; 1533231200Smm 1534231200Smm#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) 1535231200Smm r = getvfsbyname(sfs.f_fstypename, &vfc); 1536231200Smm if (r == -1) { 1537231200Smm archive_set_error(&a->archive, errno, "getvfsbyname failed"); 1538231200Smm return (ARCHIVE_FAILED); 1539231200Smm } 1540231200Smm if (vfc.vfc_flags & VFCF_SYNTHETIC) 1541231200Smm t->current_filesystem->synthetic = 1; 1542231200Smm else 1543231200Smm t->current_filesystem->synthetic = 0; 1544231200Smm#endif 1545231200Smm 1546231200Smm#if defined(MNT_NOATIME) 1547231200Smm if (sfs.f_flags & MNT_NOATIME) 1548231200Smm t->current_filesystem->noatime = 1; 1549231200Smm else 1550231200Smm#endif 1551231200Smm t->current_filesystem->noatime = 0; 1552231200Smm 1553231200Smm#if defined(HAVE_READDIR_R) 1554231200Smm /* Set maximum filename length. */ 1555231200Smm#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX) 1556231200Smm t->current_filesystem->name_max = sfs.f_namemax; 1557231200Smm#else 1558231200Smm /* Mac OS X does not have f_namemax in struct statfs. */ 1559238856Smm if (tree_current_is_symblic_link_target(t)) { 1560238856Smm if (tree_enter_working_dir(t) != 0) { 1561238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1562238856Smm return (ARCHIVE_FAILED); 1563238856Smm } 1564231200Smm nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); 1565238856Smm } else 1566231200Smm nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); 1567231200Smm if (nm == -1) 1568231200Smm t->current_filesystem->name_max = NAME_MAX; 1569231200Smm else 1570231200Smm t->current_filesystem->name_max = nm; 1571231200Smm#endif 1572231200Smm#endif /* HAVE_READDIR_R */ 1573231200Smm return (ARCHIVE_OK); 1574231200Smm} 1575231200Smm 1576231200Smm#elif (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) && defined(ST_LOCAL) 1577231200Smm 1578231200Smm/* 1579231200Smm * Gather current filesystem properties on NetBSD 1580231200Smm */ 1581231200Smmstatic int 1582231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1583231200Smm{ 1584231200Smm struct tree *t = a->tree; 1585231200Smm struct statvfs sfs; 1586231200Smm int r, xr = 0; 1587231200Smm 1588231200Smm t->current_filesystem->synthetic = -1; 1589238856Smm if (tree_enter_working_dir(t) != 0) { 1590238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1591238856Smm return (ARCHIVE_FAILED); 1592238856Smm } 1593231200Smm if (tree_current_is_symblic_link_target(t)) { 1594231200Smm r = statvfs(tree_current_access_path(t), &sfs); 1595231200Smm if (r == 0) 1596231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1597231200Smm } else { 1598231200Smm#ifdef HAVE_FSTATVFS 1599231200Smm r = fstatvfs(tree_current_dir_fd(t), &sfs); 1600231200Smm if (r == 0) 1601231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1602231200Smm#else 1603231200Smm r = statvfs(".", &sfs); 1604231200Smm if (r == 0) 1605231200Smm xr = get_xfer_size(t, -1, "."); 1606231200Smm#endif 1607231200Smm } 1608231200Smm if (r == -1 || xr == -1) { 1609231200Smm t->current_filesystem->remote = -1; 1610231200Smm archive_set_error(&a->archive, errno, "statvfs failed"); 1611231200Smm return (ARCHIVE_FAILED); 1612231200Smm } else if (xr == 1) { 1613231200Smm /* Usuall come here unless NetBSD supports _PC_REC_XFER_ALIGN 1614231200Smm * for pathconf() function. */ 1615231200Smm t->current_filesystem->xfer_align = sfs.f_frsize; 1616231200Smm t->current_filesystem->max_xfer_size = -1; 1617238856Smm#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) 1618231200Smm t->current_filesystem->min_xfer_size = sfs.f_iosize; 1619231200Smm t->current_filesystem->incr_xfer_size = sfs.f_iosize; 1620238856Smm#else 1621238856Smm t->current_filesystem->min_xfer_size = sfs.f_bsize; 1622238856Smm t->current_filesystem->incr_xfer_size = sfs.f_bsize; 1623238856Smm#endif 1624231200Smm } 1625231200Smm if (sfs.f_flag & ST_LOCAL) 1626231200Smm t->current_filesystem->remote = 0; 1627231200Smm else 1628231200Smm t->current_filesystem->remote = 1; 1629231200Smm 1630238856Smm#if defined(ST_NOATIME) 1631231200Smm if (sfs.f_flag & ST_NOATIME) 1632231200Smm t->current_filesystem->noatime = 1; 1633231200Smm else 1634238856Smm#endif 1635231200Smm t->current_filesystem->noatime = 0; 1636231200Smm 1637231200Smm /* Set maximum filename length. */ 1638231200Smm t->current_filesystem->name_max = sfs.f_namemax; 1639231200Smm return (ARCHIVE_OK); 1640231200Smm} 1641231200Smm 1642231200Smm#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_LINUX_MAGIC_H) &&\ 1643231200Smm defined(HAVE_STATFS) && defined(HAVE_FSTATFS) 1644231200Smm/* 1645231200Smm * Note: statfs is deprecated since LSB 3.2 1646231200Smm */ 1647231200Smm 1648231200Smm#ifndef CIFS_SUPER_MAGIC 1649231200Smm#define CIFS_SUPER_MAGIC 0xFF534D42 1650231200Smm#endif 1651231200Smm#ifndef DEVFS_SUPER_MAGIC 1652231200Smm#define DEVFS_SUPER_MAGIC 0x1373 1653231200Smm#endif 1654231200Smm 1655231200Smm/* 1656231200Smm * Gather current filesystem properties on Linux 1657231200Smm */ 1658231200Smmstatic int 1659231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1660231200Smm{ 1661231200Smm struct tree *t = a->tree; 1662231200Smm struct statfs sfs; 1663231200Smm struct statvfs svfs; 1664231200Smm int r, vr = 0, xr = 0; 1665231200Smm 1666231200Smm if (tree_current_is_symblic_link_target(t)) { 1667238856Smm#if defined(HAVE_OPENAT) 1668231200Smm /* 1669231200Smm * Get file system statistics on any directory 1670231200Smm * where current is. 1671231200Smm */ 1672231200Smm int fd = openat(tree_current_dir_fd(t), 1673248616Smm tree_current_access_path(t), O_RDONLY | O_CLOEXEC); 1674248616Smm __archive_ensure_cloexec_flag(fd); 1675231200Smm if (fd < 0) { 1676231200Smm archive_set_error(&a->archive, errno, 1677231200Smm "openat failed"); 1678231200Smm return (ARCHIVE_FAILED); 1679231200Smm } 1680231200Smm vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */ 1681231200Smm r = fstatfs(fd, &sfs); 1682231200Smm if (r == 0) 1683231200Smm xr = get_xfer_size(t, fd, NULL); 1684231200Smm close(fd); 1685231200Smm#else 1686238856Smm if (tree_enter_working_dir(t) != 0) { 1687238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1688238856Smm return (ARCHIVE_FAILED); 1689238856Smm } 1690231200Smm vr = statvfs(tree_current_access_path(t), &svfs); 1691231200Smm r = statfs(tree_current_access_path(t), &sfs); 1692231200Smm if (r == 0) 1693231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1694231200Smm#endif 1695231200Smm } else { 1696231200Smm#ifdef HAVE_FSTATFS 1697231200Smm vr = fstatvfs(tree_current_dir_fd(t), &svfs); 1698231200Smm r = fstatfs(tree_current_dir_fd(t), &sfs); 1699231200Smm if (r == 0) 1700231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1701231200Smm#else 1702238856Smm if (tree_enter_working_dir(t) != 0) { 1703238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1704238856Smm return (ARCHIVE_FAILED); 1705238856Smm } 1706231200Smm vr = statvfs(".", &svfs); 1707231200Smm r = statfs(".", &sfs); 1708231200Smm if (r == 0) 1709231200Smm xr = get_xfer_size(t, -1, "."); 1710231200Smm#endif 1711231200Smm } 1712231200Smm if (r == -1 || xr == -1 || vr == -1) { 1713231200Smm t->current_filesystem->synthetic = -1; 1714231200Smm t->current_filesystem->remote = -1; 1715231200Smm archive_set_error(&a->archive, errno, "statfs failed"); 1716231200Smm return (ARCHIVE_FAILED); 1717231200Smm } else if (xr == 1) { 1718231200Smm /* pathconf(_PC_REX_*) operations are not supported. */ 1719231200Smm t->current_filesystem->xfer_align = svfs.f_frsize; 1720231200Smm t->current_filesystem->max_xfer_size = -1; 1721231200Smm t->current_filesystem->min_xfer_size = svfs.f_bsize; 1722231200Smm t->current_filesystem->incr_xfer_size = svfs.f_bsize; 1723231200Smm } 1724231200Smm switch (sfs.f_type) { 1725231200Smm case AFS_SUPER_MAGIC: 1726231200Smm case CIFS_SUPER_MAGIC: 1727231200Smm case CODA_SUPER_MAGIC: 1728231200Smm case NCP_SUPER_MAGIC:/* NetWare */ 1729231200Smm case NFS_SUPER_MAGIC: 1730231200Smm case SMB_SUPER_MAGIC: 1731231200Smm t->current_filesystem->remote = 1; 1732231200Smm t->current_filesystem->synthetic = 0; 1733231200Smm break; 1734231200Smm case DEVFS_SUPER_MAGIC: 1735231200Smm case PROC_SUPER_MAGIC: 1736231200Smm case USBDEVICE_SUPER_MAGIC: 1737231200Smm t->current_filesystem->remote = 0; 1738231200Smm t->current_filesystem->synthetic = 1; 1739231200Smm break; 1740231200Smm default: 1741231200Smm t->current_filesystem->remote = 0; 1742231200Smm t->current_filesystem->synthetic = 0; 1743231200Smm break; 1744231200Smm } 1745231200Smm 1746231200Smm#if defined(ST_NOATIME) 1747231200Smm if (svfs.f_flag & ST_NOATIME) 1748231200Smm t->current_filesystem->noatime = 1; 1749231200Smm else 1750231200Smm#endif 1751231200Smm t->current_filesystem->noatime = 0; 1752231200Smm 1753231200Smm#if defined(HAVE_READDIR_R) 1754231200Smm /* Set maximum filename length. */ 1755231200Smm t->current_filesystem->name_max = sfs.f_namelen; 1756231200Smm#endif 1757231200Smm return (ARCHIVE_OK); 1758231200Smm} 1759231200Smm 1760231200Smm#elif defined(HAVE_SYS_STATVFS_H) &&\ 1761231200Smm (defined(HAVE_STATVFS) || defined(HAVE_FSTATVFS)) 1762231200Smm 1763231200Smm/* 1764231200Smm * Gather current filesystem properties on other posix platform. 1765231200Smm */ 1766231200Smmstatic int 1767231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1768231200Smm{ 1769231200Smm struct tree *t = a->tree; 1770231200Smm struct statvfs sfs; 1771231200Smm int r, xr = 0; 1772231200Smm 1773231200Smm t->current_filesystem->synthetic = -1;/* Not supported */ 1774231200Smm t->current_filesystem->remote = -1;/* Not supported */ 1775231200Smm if (tree_current_is_symblic_link_target(t)) { 1776238856Smm#if defined(HAVE_OPENAT) 1777231200Smm /* 1778231200Smm * Get file system statistics on any directory 1779231200Smm * where current is. 1780231200Smm */ 1781231200Smm int fd = openat(tree_current_dir_fd(t), 1782248616Smm tree_current_access_path(t), O_RDONLY | O_CLOEXEC); 1783248616Smm __archive_ensure_cloexec_flag(fd); 1784231200Smm if (fd < 0) { 1785231200Smm archive_set_error(&a->archive, errno, 1786231200Smm "openat failed"); 1787231200Smm return (ARCHIVE_FAILED); 1788231200Smm } 1789231200Smm r = fstatvfs(fd, &sfs); 1790231200Smm if (r == 0) 1791231200Smm xr = get_xfer_size(t, fd, NULL); 1792231200Smm close(fd); 1793231200Smm#else 1794238856Smm if (tree_enter_working_dir(t) != 0) { 1795238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1796238856Smm return (ARCHIVE_FAILED); 1797238856Smm } 1798231200Smm r = statvfs(tree_current_access_path(t), &sfs); 1799231200Smm if (r == 0) 1800231200Smm xr = get_xfer_size(t, -1, tree_current_access_path(t)); 1801231200Smm#endif 1802231200Smm } else { 1803231200Smm#ifdef HAVE_FSTATVFS 1804231200Smm r = fstatvfs(tree_current_dir_fd(t), &sfs); 1805231200Smm if (r == 0) 1806231200Smm xr = get_xfer_size(t, tree_current_dir_fd(t), NULL); 1807231200Smm#else 1808238856Smm if (tree_enter_working_dir(t) != 0) { 1809238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1810238856Smm return (ARCHIVE_FAILED); 1811238856Smm } 1812231200Smm r = statvfs(".", &sfs); 1813231200Smm if (r == 0) 1814231200Smm xr = get_xfer_size(t, -1, "."); 1815231200Smm#endif 1816231200Smm } 1817231200Smm if (r == -1 || xr == -1) { 1818231200Smm t->current_filesystem->synthetic = -1; 1819231200Smm t->current_filesystem->remote = -1; 1820231200Smm archive_set_error(&a->archive, errno, "statvfs failed"); 1821231200Smm return (ARCHIVE_FAILED); 1822231200Smm } else if (xr == 1) { 1823231200Smm /* pathconf(_PC_REX_*) operations are not supported. */ 1824231200Smm t->current_filesystem->xfer_align = sfs.f_frsize; 1825231200Smm t->current_filesystem->max_xfer_size = -1; 1826231200Smm t->current_filesystem->min_xfer_size = sfs.f_bsize; 1827231200Smm t->current_filesystem->incr_xfer_size = sfs.f_bsize; 1828231200Smm } 1829231200Smm 1830231200Smm#if defined(ST_NOATIME) 1831231200Smm if (sfs.f_flag & ST_NOATIME) 1832231200Smm t->current_filesystem->noatime = 1; 1833231200Smm else 1834231200Smm#endif 1835231200Smm t->current_filesystem->noatime = 0; 1836231200Smm 1837231200Smm#if defined(HAVE_READDIR_R) 1838231200Smm /* Set maximum filename length. */ 1839231200Smm t->current_filesystem->name_max = sfs.f_namemax; 1840231200Smm#endif 1841231200Smm return (ARCHIVE_OK); 1842231200Smm} 1843231200Smm 1844231200Smm#else 1845231200Smm 1846231200Smm/* 1847231200Smm * Generic: Gather current filesystem properties. 1848231200Smm * TODO: Is this generic function really needed? 1849231200Smm */ 1850231200Smmstatic int 1851231200Smmsetup_current_filesystem(struct archive_read_disk *a) 1852231200Smm{ 1853231200Smm struct tree *t = a->tree; 1854231200Smm#if defined(_PC_NAME_MAX) && defined(HAVE_READDIR_R) 1855231200Smm long nm; 1856231200Smm#endif 1857231200Smm t->current_filesystem->synthetic = -1;/* Not supported */ 1858231200Smm t->current_filesystem->remote = -1;/* Not supported */ 1859231200Smm t->current_filesystem->noatime = 0; 1860231200Smm (void)get_xfer_size(t, -1, ".");/* Dummy call to avoid build error. */ 1861231200Smm t->current_filesystem->xfer_align = -1;/* Unknown */ 1862231200Smm t->current_filesystem->max_xfer_size = -1; 1863231200Smm t->current_filesystem->min_xfer_size = -1; 1864231200Smm t->current_filesystem->incr_xfer_size = -1; 1865231200Smm 1866231200Smm#if defined(HAVE_READDIR_R) 1867231200Smm /* Set maximum filename length. */ 1868231200Smm# if defined(_PC_NAME_MAX) 1869238856Smm if (tree_current_is_symblic_link_target(t)) { 1870238856Smm if (tree_enter_working_dir(t) != 0) { 1871238856Smm archive_set_error(&a->archive, errno, "fchdir failed"); 1872238856Smm return (ARCHIVE_FAILED); 1873238856Smm } 1874231200Smm nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); 1875238856Smm } else 1876231200Smm nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); 1877231200Smm if (nm == -1) 1878231200Smm# endif /* _PC_NAME_MAX */ 1879231200Smm /* 1880231200Smm * Some sysmtes (HP-UX or others?) incorrectly defined 1881231200Smm * NAME_MAX macro to be a smaller value. 1882231200Smm */ 1883231200Smm# if defined(NAME_MAX) && NAME_MAX >= 255 1884231200Smm t->current_filesystem->name_max = NAME_MAX; 1885231200Smm# else 1886231200Smm /* No way to get a trusted value of maximum filename 1887231200Smm * length. */ 1888231200Smm t->current_filesystem->name_max = PATH_MAX; 1889231200Smm# endif /* NAME_MAX */ 1890231200Smm# if defined(_PC_NAME_MAX) 1891231200Smm else 1892231200Smm t->current_filesystem->name_max = nm; 1893231200Smm# endif /* _PC_NAME_MAX */ 1894231200Smm#endif /* HAVE_READDIR_R */ 1895231200Smm return (ARCHIVE_OK); 1896231200Smm} 1897231200Smm 1898231200Smm#endif 1899231200Smm 1900231200Smmstatic int 1901231200Smmclose_and_restore_time(int fd, struct tree *t, struct restore_time *rt) 1902231200Smm{ 1903231200Smm#ifndef HAVE_UTIMES 1904248616Smm (void)t; /* UNUSED */ 1905248616Smm (void)rt; /* UNUSED */ 1906231200Smm return (close(fd)); 1907231200Smm#else 1908231200Smm#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) 1909231200Smm struct timespec timespecs[2]; 1910231200Smm#endif 1911231200Smm struct timeval times[2]; 1912231200Smm 1913231200Smm if ((t->flags & needsRestoreTimes) == 0 || rt->noatime) { 1914231200Smm if (fd >= 0) 1915231200Smm return (close(fd)); 1916231200Smm else 1917231200Smm return (0); 1918231200Smm } 1919231200Smm 1920231200Smm#if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__) 1921231200Smm timespecs[1].tv_sec = rt->mtime; 1922231200Smm timespecs[1].tv_nsec = rt->mtime_nsec; 1923231200Smm 1924231200Smm timespecs[0].tv_sec = rt->atime; 1925231200Smm timespecs[0].tv_nsec = rt->atime_nsec; 1926231200Smm /* futimens() is defined in POSIX.1-2008. */ 1927231200Smm if (futimens(fd, timespecs) == 0) 1928231200Smm return (close(fd)); 1929231200Smm#endif 1930231200Smm 1931231200Smm times[1].tv_sec = rt->mtime; 1932231200Smm times[1].tv_usec = rt->mtime_nsec / 1000; 1933231200Smm 1934231200Smm times[0].tv_sec = rt->atime; 1935231200Smm times[0].tv_usec = rt->atime_nsec / 1000; 1936231200Smm 1937231200Smm#if !defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES) && !defined(__CYGWIN__) 1938231200Smm if (futimes(fd, times) == 0) 1939231200Smm return (close(fd)); 1940231200Smm#endif 1941231200Smm close(fd); 1942231200Smm#if defined(HAVE_FUTIMESAT) 1943231200Smm if (futimesat(tree_current_dir_fd(t), rt->name, times) == 0) 1944231200Smm return (0); 1945231200Smm#endif 1946231200Smm#ifdef HAVE_LUTIMES 1947231200Smm if (lutimes(rt->name, times) != 0) 1948231200Smm#else 1949231200Smm if (AE_IFLNK != rt->filetype && utimes(rt->name, times) != 0) 1950231200Smm#endif 1951231200Smm return (-1); 1952231200Smm#endif 1953231200Smm return (0); 1954231200Smm} 1955231200Smm 1956238856Smmstatic int 1957238856Smmopen_on_current_dir(struct tree *t, const char *path, int flags) 1958238856Smm{ 1959238856Smm#ifdef HAVE_OPENAT 1960238856Smm return (openat(tree_current_dir_fd(t), path, flags)); 1961238856Smm#else 1962238856Smm if (tree_enter_working_dir(t) != 0) 1963238856Smm return (-1); 1964238856Smm return (open(path, flags)); 1965238856Smm#endif 1966238856Smm} 1967238856Smm 1968248616Smmstatic int 1969248616Smmtree_dup(int fd) 1970248616Smm{ 1971248616Smm int new_fd; 1972248616Smm#ifdef F_DUPFD_CLOEXEC 1973248616Smm static volatile int can_dupfd_cloexec = 1; 1974248616Smm 1975248616Smm if (can_dupfd_cloexec) { 1976248616Smm new_fd = fcntl(fd, F_DUPFD_CLOEXEC); 1977248616Smm if (new_fd != -1) 1978248616Smm return (new_fd); 1979248616Smm /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC, 1980248616Smm * but it cannot be used. So we have to try dup(). */ 1981248616Smm /* We won't try F_DUPFD_CLOEXEC. */ 1982248616Smm can_dupfd_cloexec = 0; 1983248616Smm } 1984248616Smm#endif /* F_DUPFD_CLOEXEC */ 1985248616Smm new_fd = dup(fd); 1986248616Smm __archive_ensure_cloexec_flag(new_fd); 1987248616Smm return (new_fd); 1988248616Smm} 1989248616Smm 1990231200Smm/* 1991231200Smm * Add a directory path to the current stack. 1992231200Smm */ 1993231200Smmstatic void 1994231200Smmtree_push(struct tree *t, const char *path, int filesystem_id, 1995231200Smm int64_t dev, int64_t ino, struct restore_time *rt) 1996231200Smm{ 1997231200Smm struct tree_entry *te; 1998231200Smm 1999231200Smm te = malloc(sizeof(*te)); 2000231200Smm memset(te, 0, sizeof(*te)); 2001231200Smm te->next = t->stack; 2002231200Smm te->parent = t->current; 2003231200Smm if (te->parent) 2004231200Smm te->depth = te->parent->depth + 1; 2005231200Smm t->stack = te; 2006231200Smm archive_string_init(&te->name); 2007231200Smm te->symlink_parent_fd = -1; 2008231200Smm archive_strcpy(&te->name, path); 2009231200Smm te->flags = needsDescent | needsOpen | needsAscent; 2010231200Smm te->filesystem_id = filesystem_id; 2011231200Smm te->dev = dev; 2012231200Smm te->ino = ino; 2013231200Smm te->dirname_length = t->dirname_length; 2014231200Smm te->restore_time.name = te->name.s; 2015231200Smm if (rt != NULL) { 2016231200Smm te->restore_time.mtime = rt->mtime; 2017231200Smm te->restore_time.mtime_nsec = rt->mtime_nsec; 2018231200Smm te->restore_time.atime = rt->atime; 2019231200Smm te->restore_time.atime_nsec = rt->atime_nsec; 2020231200Smm te->restore_time.filetype = rt->filetype; 2021231200Smm te->restore_time.noatime = rt->noatime; 2022231200Smm } 2023231200Smm} 2024231200Smm 2025231200Smm/* 2026231200Smm * Append a name to the current dir path. 2027231200Smm */ 2028231200Smmstatic void 2029231200Smmtree_append(struct tree *t, const char *name, size_t name_length) 2030231200Smm{ 2031231200Smm size_t size_needed; 2032231200Smm 2033231200Smm t->path.s[t->dirname_length] = '\0'; 2034231200Smm t->path.length = t->dirname_length; 2035231200Smm /* Strip trailing '/' from name, unless entire name is "/". */ 2036231200Smm while (name_length > 1 && name[name_length - 1] == '/') 2037231200Smm name_length--; 2038231200Smm 2039231200Smm /* Resize pathname buffer as needed. */ 2040231200Smm size_needed = name_length + t->dirname_length + 2; 2041231200Smm archive_string_ensure(&t->path, size_needed); 2042231200Smm /* Add a separating '/' if it's needed. */ 2043231200Smm if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != '/') 2044231200Smm archive_strappend_char(&t->path, '/'); 2045231200Smm t->basename = t->path.s + archive_strlen(&t->path); 2046231200Smm archive_strncat(&t->path, name, name_length); 2047231200Smm t->restore_time.name = t->basename; 2048231200Smm} 2049231200Smm 2050231200Smm/* 2051231200Smm * Open a directory tree for traversal. 2052231200Smm */ 2053231200Smmstatic struct tree * 2054231200Smmtree_open(const char *path, int symlink_mode, int restore_time) 2055231200Smm{ 2056231200Smm struct tree *t; 2057231200Smm 2058231200Smm if ((t = malloc(sizeof(*t))) == NULL) 2059231200Smm return (NULL); 2060231200Smm memset(t, 0, sizeof(*t)); 2061231200Smm archive_string_init(&t->path); 2062231200Smm archive_string_ensure(&t->path, 31); 2063231200Smm t->initial_symlink_mode = symlink_mode; 2064231200Smm return (tree_reopen(t, path, restore_time)); 2065231200Smm} 2066231200Smm 2067231200Smmstatic struct tree * 2068231200Smmtree_reopen(struct tree *t, const char *path, int restore_time) 2069231200Smm{ 2070231200Smm t->flags = (restore_time)?needsRestoreTimes:0; 2071238856Smm t->flags |= onInitialDir; 2072231200Smm t->visit_type = 0; 2073231200Smm t->tree_errno = 0; 2074231200Smm t->dirname_length = 0; 2075231200Smm t->depth = 0; 2076231200Smm t->descend = 0; 2077231200Smm t->current = NULL; 2078231200Smm t->d = INVALID_DIR_HANDLE; 2079231200Smm t->symlink_mode = t->initial_symlink_mode; 2080231200Smm archive_string_empty(&t->path); 2081231200Smm t->entry_fd = -1; 2082231200Smm t->entry_eof = 0; 2083231200Smm t->entry_remaining_bytes = 0; 2084238856Smm t->initial_filesystem_id = -1; 2085231200Smm 2086231200Smm /* First item is set up a lot like a symlink traversal. */ 2087231200Smm tree_push(t, path, 0, 0, 0, NULL); 2088231200Smm t->stack->flags = needsFirstVisit; 2089231200Smm t->maxOpenCount = t->openCount = 1; 2090248616Smm t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC); 2091248616Smm __archive_ensure_cloexec_flag(t->initial_dir_fd); 2092248616Smm t->working_dir_fd = tree_dup(t->initial_dir_fd); 2093231200Smm return (t); 2094231200Smm} 2095231200Smm 2096231200Smmstatic int 2097231200Smmtree_descent(struct tree *t) 2098231200Smm{ 2099238856Smm int flag, new_fd, r = 0; 2100231200Smm 2101231200Smm t->dirname_length = archive_strlen(&t->path); 2102248616Smm flag = O_RDONLY | O_CLOEXEC; 2103238856Smm#if defined(O_DIRECTORY) 2104238856Smm flag |= O_DIRECTORY; 2105238856Smm#endif 2106238856Smm new_fd = open_on_current_dir(t, t->stack->name.s, flag); 2107248616Smm __archive_ensure_cloexec_flag(new_fd); 2108231200Smm if (new_fd < 0) { 2109231200Smm t->tree_errno = errno; 2110231200Smm r = TREE_ERROR_DIR; 2111231200Smm } else { 2112231200Smm t->depth++; 2113231200Smm /* If it is a link, set up fd for the ascent. */ 2114231200Smm if (t->stack->flags & isDirLink) { 2115231200Smm t->stack->symlink_parent_fd = t->working_dir_fd; 2116231200Smm t->openCount++; 2117231200Smm if (t->openCount > t->maxOpenCount) 2118231200Smm t->maxOpenCount = t->openCount; 2119231200Smm } else 2120231200Smm close(t->working_dir_fd); 2121238856Smm /* Renew the current working directory. */ 2122231200Smm t->working_dir_fd = new_fd; 2123238856Smm t->flags &= ~onWorkingDir; 2124231200Smm } 2125231200Smm return (r); 2126231200Smm} 2127231200Smm 2128231200Smm/* 2129231200Smm * We've finished a directory; ascend back to the parent. 2130231200Smm */ 2131231200Smmstatic int 2132231200Smmtree_ascend(struct tree *t) 2133231200Smm{ 2134231200Smm struct tree_entry *te; 2135238856Smm int new_fd, r = 0, prev_dir_fd; 2136231200Smm 2137231200Smm te = t->stack; 2138231200Smm prev_dir_fd = t->working_dir_fd; 2139231200Smm if (te->flags & isDirLink) 2140238856Smm new_fd = te->symlink_parent_fd; 2141248616Smm else { 2142248616Smm new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC); 2143248616Smm __archive_ensure_cloexec_flag(new_fd); 2144248616Smm } 2145238856Smm if (new_fd < 0) { 2146238856Smm t->tree_errno = errno; 2147238856Smm r = TREE_ERROR_FATAL; 2148231200Smm } else { 2149238856Smm /* Renew the current working directory. */ 2150238856Smm t->working_dir_fd = new_fd; 2151238856Smm t->flags &= ~onWorkingDir; 2152231200Smm /* Current directory has been changed, we should 2153231200Smm * close an fd of previous working directory. */ 2154231200Smm close_and_restore_time(prev_dir_fd, t, &te->restore_time); 2155231200Smm if (te->flags & isDirLink) { 2156231200Smm t->openCount--; 2157231200Smm te->symlink_parent_fd = -1; 2158231200Smm } 2159231200Smm t->depth--; 2160231200Smm } 2161231200Smm return (r); 2162231200Smm} 2163231200Smm 2164231200Smm/* 2165231200Smm * Return to the initial directory where tree_open() was performed. 2166231200Smm */ 2167231200Smmstatic int 2168231200Smmtree_enter_initial_dir(struct tree *t) 2169231200Smm{ 2170231200Smm int r = 0; 2171231200Smm 2172238856Smm if ((t->flags & onInitialDir) == 0) { 2173231200Smm r = fchdir(t->initial_dir_fd); 2174238856Smm if (r == 0) { 2175231200Smm t->flags &= ~onWorkingDir; 2176238856Smm t->flags |= onInitialDir; 2177238856Smm } 2178231200Smm } 2179231200Smm return (r); 2180231200Smm} 2181231200Smm 2182231200Smm/* 2183231200Smm * Restore working directory of directory traversals. 2184231200Smm */ 2185231200Smmstatic int 2186231200Smmtree_enter_working_dir(struct tree *t) 2187231200Smm{ 2188231200Smm int r = 0; 2189231200Smm 2190231200Smm /* 2191231200Smm * Change the current directory if really needed. 2192231200Smm * Sometimes this is unneeded when we did not do 2193231200Smm * descent. 2194231200Smm */ 2195231200Smm if (t->depth > 0 && (t->flags & onWorkingDir) == 0) { 2196231200Smm r = fchdir(t->working_dir_fd); 2197238856Smm if (r == 0) { 2198238856Smm t->flags &= ~onInitialDir; 2199231200Smm t->flags |= onWorkingDir; 2200238856Smm } 2201231200Smm } 2202231200Smm return (r); 2203231200Smm} 2204231200Smm 2205231200Smmstatic int 2206231200Smmtree_current_dir_fd(struct tree *t) 2207231200Smm{ 2208231200Smm return (t->working_dir_fd); 2209231200Smm} 2210231200Smm 2211231200Smm/* 2212231200Smm * Pop the working stack. 2213231200Smm */ 2214231200Smmstatic void 2215231200Smmtree_pop(struct tree *t) 2216231200Smm{ 2217231200Smm struct tree_entry *te; 2218231200Smm 2219231200Smm t->path.s[t->dirname_length] = '\0'; 2220231200Smm t->path.length = t->dirname_length; 2221231200Smm if (t->stack == t->current && t->current != NULL) 2222231200Smm t->current = t->current->parent; 2223231200Smm te = t->stack; 2224231200Smm t->stack = te->next; 2225231200Smm t->dirname_length = te->dirname_length; 2226231200Smm t->basename = t->path.s + t->dirname_length; 2227231200Smm while (t->basename[0] == '/') 2228231200Smm t->basename++; 2229231200Smm archive_string_free(&te->name); 2230231200Smm free(te); 2231231200Smm} 2232231200Smm 2233231200Smm/* 2234231200Smm * Get the next item in the tree traversal. 2235231200Smm */ 2236231200Smmstatic int 2237231200Smmtree_next(struct tree *t) 2238231200Smm{ 2239231200Smm int r; 2240231200Smm 2241231200Smm while (t->stack != NULL) { 2242231200Smm /* If there's an open dir, get the next entry from there. */ 2243231200Smm if (t->d != INVALID_DIR_HANDLE) { 2244231200Smm r = tree_dir_next_posix(t); 2245231200Smm if (r == 0) 2246231200Smm continue; 2247231200Smm return (r); 2248231200Smm } 2249231200Smm 2250231200Smm if (t->stack->flags & needsFirstVisit) { 2251231200Smm /* Top stack item needs a regular visit. */ 2252231200Smm t->current = t->stack; 2253231200Smm tree_append(t, t->stack->name.s, 2254231200Smm archive_strlen(&(t->stack->name))); 2255231200Smm /* t->dirname_length = t->path_length; */ 2256231200Smm /* tree_pop(t); */ 2257231200Smm t->stack->flags &= ~needsFirstVisit; 2258231200Smm return (t->visit_type = TREE_REGULAR); 2259231200Smm } else if (t->stack->flags & needsDescent) { 2260231200Smm /* Top stack item is dir to descend into. */ 2261231200Smm t->current = t->stack; 2262231200Smm tree_append(t, t->stack->name.s, 2263231200Smm archive_strlen(&(t->stack->name))); 2264231200Smm t->stack->flags &= ~needsDescent; 2265231200Smm r = tree_descent(t); 2266231200Smm if (r != 0) { 2267231200Smm tree_pop(t); 2268231200Smm t->visit_type = r; 2269231200Smm } else 2270231200Smm t->visit_type = TREE_POSTDESCENT; 2271231200Smm return (t->visit_type); 2272231200Smm } else if (t->stack->flags & needsOpen) { 2273231200Smm t->stack->flags &= ~needsOpen; 2274231200Smm r = tree_dir_next_posix(t); 2275231200Smm if (r == 0) 2276231200Smm continue; 2277231200Smm return (r); 2278231200Smm } else if (t->stack->flags & needsAscent) { 2279231200Smm /* Top stack item is dir and we're done with it. */ 2280231200Smm r = tree_ascend(t); 2281231200Smm tree_pop(t); 2282231200Smm t->visit_type = r != 0 ? r : TREE_POSTASCENT; 2283231200Smm return (t->visit_type); 2284231200Smm } else { 2285231200Smm /* Top item on stack is dead. */ 2286231200Smm tree_pop(t); 2287231200Smm t->flags &= ~hasLstat; 2288231200Smm t->flags &= ~hasStat; 2289231200Smm } 2290231200Smm } 2291231200Smm return (t->visit_type = 0); 2292231200Smm} 2293231200Smm 2294231200Smmstatic int 2295231200Smmtree_dir_next_posix(struct tree *t) 2296231200Smm{ 2297231200Smm int r; 2298231200Smm const char *name; 2299231200Smm size_t namelen; 2300231200Smm 2301231200Smm if (t->d == NULL) { 2302231200Smm#if defined(HAVE_READDIR_R) 2303231200Smm size_t dirent_size; 2304231200Smm#endif 2305231200Smm 2306231200Smm#if defined(HAVE_FDOPENDIR) 2307248616Smm t->d = fdopendir(tree_dup(t->working_dir_fd)); 2308248616Smm#else /* HAVE_FDOPENDIR */ 2309248616Smm if (tree_enter_working_dir(t) == 0) { 2310248616Smm t->d = opendir("."); 2311248616Smm#if HAVE_DIRFD || defined(dirfd) 2312248616Smm __archive_ensure_cloexec_flag(dirfd(t->d)); 2313231200Smm#endif 2314248616Smm } 2315248616Smm#endif /* HAVE_FDOPENDIR */ 2316248616Smm if (t->d == NULL) { 2317231200Smm r = tree_ascend(t); /* Undo "chdir" */ 2318231200Smm tree_pop(t); 2319231200Smm t->tree_errno = errno; 2320231200Smm t->visit_type = r != 0 ? r : TREE_ERROR_DIR; 2321231200Smm return (t->visit_type); 2322231200Smm } 2323231200Smm#if defined(HAVE_READDIR_R) 2324231200Smm dirent_size = offsetof(struct dirent, d_name) + 2325231200Smm t->filesystem_table[t->current->filesystem_id].name_max + 1; 2326231200Smm if (t->dirent == NULL || t->dirent_allocated < dirent_size) { 2327231200Smm free(t->dirent); 2328231200Smm t->dirent = malloc(dirent_size); 2329231200Smm if (t->dirent == NULL) { 2330231200Smm closedir(t->d); 2331231200Smm t->d = INVALID_DIR_HANDLE; 2332231200Smm (void)tree_ascend(t); 2333231200Smm tree_pop(t); 2334231200Smm t->tree_errno = ENOMEM; 2335231200Smm t->visit_type = TREE_ERROR_DIR; 2336231200Smm return (t->visit_type); 2337231200Smm } 2338231200Smm t->dirent_allocated = dirent_size; 2339231200Smm } 2340231200Smm#endif /* HAVE_READDIR_R */ 2341231200Smm } 2342231200Smm for (;;) { 2343248616Smm errno = 0; 2344231200Smm#if defined(HAVE_READDIR_R) 2345231200Smm r = readdir_r(t->d, t->dirent, &t->de); 2346248616Smm#ifdef _AIX 2347248616Smm /* Note: According to the man page, return value 9 indicates 2348248616Smm * that the readdir_r was not successful and the error code 2349248616Smm * is set to the global errno variable. And then if the end 2350248616Smm * of directory entries was reached, the return value is 9 2351248616Smm * and the third parameter is set to NULL and errno is 2352248616Smm * unchanged. */ 2353248616Smm if (r == 9) 2354248616Smm r = errno; 2355248616Smm#endif /* _AIX */ 2356231200Smm if (r != 0 || t->de == NULL) { 2357231200Smm#else 2358231200Smm t->de = readdir(t->d); 2359231200Smm if (t->de == NULL) { 2360231200Smm r = errno; 2361231200Smm#endif 2362231200Smm closedir(t->d); 2363231200Smm t->d = INVALID_DIR_HANDLE; 2364231200Smm if (r != 0) { 2365231200Smm t->tree_errno = r; 2366231200Smm t->visit_type = TREE_ERROR_DIR; 2367231200Smm return (t->visit_type); 2368231200Smm } else 2369231200Smm return (0); 2370231200Smm } 2371231200Smm name = t->de->d_name; 2372231200Smm namelen = D_NAMELEN(t->de); 2373231200Smm t->flags &= ~hasLstat; 2374231200Smm t->flags &= ~hasStat; 2375231200Smm if (name[0] == '.' && name[1] == '\0') 2376231200Smm continue; 2377231200Smm if (name[0] == '.' && name[1] == '.' && name[2] == '\0') 2378231200Smm continue; 2379231200Smm tree_append(t, name, namelen); 2380231200Smm return (t->visit_type = TREE_REGULAR); 2381231200Smm } 2382231200Smm} 2383231200Smm 2384231200Smm 2385231200Smm/* 2386231200Smm * Get the stat() data for the entry just returned from tree_next(). 2387231200Smm */ 2388231200Smmstatic const struct stat * 2389231200Smmtree_current_stat(struct tree *t) 2390231200Smm{ 2391231200Smm if (!(t->flags & hasStat)) { 2392231200Smm#ifdef HAVE_FSTATAT 2393231200Smm if (fstatat(tree_current_dir_fd(t), 2394231200Smm tree_current_access_path(t), &t->st, 0) != 0) 2395231200Smm#else 2396238856Smm if (tree_enter_working_dir(t) != 0) 2397238856Smm return NULL; 2398231200Smm if (stat(tree_current_access_path(t), &t->st) != 0) 2399231200Smm#endif 2400231200Smm return NULL; 2401231200Smm t->flags |= hasStat; 2402231200Smm } 2403231200Smm return (&t->st); 2404231200Smm} 2405231200Smm 2406231200Smm/* 2407231200Smm * Get the lstat() data for the entry just returned from tree_next(). 2408231200Smm */ 2409231200Smmstatic const struct stat * 2410231200Smmtree_current_lstat(struct tree *t) 2411231200Smm{ 2412231200Smm if (!(t->flags & hasLstat)) { 2413231200Smm#ifdef HAVE_FSTATAT 2414231200Smm if (fstatat(tree_current_dir_fd(t), 2415231200Smm tree_current_access_path(t), &t->lst, 2416231200Smm AT_SYMLINK_NOFOLLOW) != 0) 2417231200Smm#else 2418238856Smm if (tree_enter_working_dir(t) != 0) 2419238856Smm return NULL; 2420231200Smm if (lstat(tree_current_access_path(t), &t->lst) != 0) 2421231200Smm#endif 2422231200Smm return NULL; 2423231200Smm t->flags |= hasLstat; 2424231200Smm } 2425231200Smm return (&t->lst); 2426231200Smm} 2427231200Smm 2428231200Smm/* 2429231200Smm * Test whether current entry is a dir or link to a dir. 2430231200Smm */ 2431231200Smmstatic int 2432231200Smmtree_current_is_dir(struct tree *t) 2433231200Smm{ 2434231200Smm const struct stat *st; 2435231200Smm /* 2436231200Smm * If we already have lstat() info, then try some 2437231200Smm * cheap tests to determine if this is a dir. 2438231200Smm */ 2439231200Smm if (t->flags & hasLstat) { 2440231200Smm /* If lstat() says it's a dir, it must be a dir. */ 2441238856Smm st = tree_current_lstat(t); 2442238856Smm if (st == NULL) 2443238856Smm return 0; 2444238856Smm if (S_ISDIR(st->st_mode)) 2445231200Smm return 1; 2446231200Smm /* Not a dir; might be a link to a dir. */ 2447231200Smm /* If it's not a link, then it's not a link to a dir. */ 2448248616Smm if (!S_ISLNK(st->st_mode)) 2449231200Smm return 0; 2450231200Smm /* 2451231200Smm * It's a link, but we don't know what it's a link to, 2452231200Smm * so we'll have to use stat(). 2453231200Smm */ 2454231200Smm } 2455231200Smm 2456231200Smm st = tree_current_stat(t); 2457231200Smm /* If we can't stat it, it's not a dir. */ 2458231200Smm if (st == NULL) 2459231200Smm return 0; 2460231200Smm /* Use the definitive test. Hopefully this is cached. */ 2461231200Smm return (S_ISDIR(st->st_mode)); 2462231200Smm} 2463231200Smm 2464231200Smm/* 2465231200Smm * Test whether current entry is a physical directory. Usually, we 2466231200Smm * already have at least one of stat() or lstat() in memory, so we 2467231200Smm * use tricks to try to avoid an extra trip to the disk. 2468231200Smm */ 2469231200Smmstatic int 2470231200Smmtree_current_is_physical_dir(struct tree *t) 2471231200Smm{ 2472231200Smm const struct stat *st; 2473231200Smm 2474231200Smm /* 2475231200Smm * If stat() says it isn't a dir, then it's not a dir. 2476231200Smm * If stat() data is cached, this check is free, so do it first. 2477231200Smm */ 2478238856Smm if (t->flags & hasStat) { 2479238856Smm st = tree_current_stat(t); 2480238856Smm if (st == NULL) 2481238856Smm return (0); 2482238856Smm if (!S_ISDIR(st->st_mode)) 2483238856Smm return (0); 2484238856Smm } 2485231200Smm 2486231200Smm /* 2487231200Smm * Either stat() said it was a dir (in which case, we have 2488231200Smm * to determine whether it's really a link to a dir) or 2489231200Smm * stat() info wasn't available. So we use lstat(), which 2490231200Smm * hopefully is already cached. 2491231200Smm */ 2492231200Smm 2493231200Smm st = tree_current_lstat(t); 2494231200Smm /* If we can't stat it, it's not a dir. */ 2495231200Smm if (st == NULL) 2496231200Smm return 0; 2497231200Smm /* Use the definitive test. Hopefully this is cached. */ 2498231200Smm return (S_ISDIR(st->st_mode)); 2499231200Smm} 2500231200Smm 2501231200Smm/* 2502231200Smm * Test whether the same file has been in the tree as its parent. 2503231200Smm */ 2504231200Smmstatic int 2505231200Smmtree_target_is_same_as_parent(struct tree *t, const struct stat *st) 2506231200Smm{ 2507231200Smm struct tree_entry *te; 2508231200Smm 2509231200Smm for (te = t->current->parent; te != NULL; te = te->parent) { 2510232153Smm if (te->dev == (int64_t)st->st_dev && 2511232153Smm te->ino == (int64_t)st->st_ino) 2512231200Smm return (1); 2513231200Smm } 2514231200Smm return (0); 2515231200Smm} 2516231200Smm 2517231200Smm/* 2518231200Smm * Test whether the current file is symbolic link target and 2519231200Smm * on the other filesystem. 2520231200Smm */ 2521231200Smmstatic int 2522231200Smmtree_current_is_symblic_link_target(struct tree *t) 2523231200Smm{ 2524231200Smm static const struct stat *lst, *st; 2525231200Smm 2526231200Smm lst = tree_current_lstat(t); 2527231200Smm st = tree_current_stat(t); 2528238856Smm return (st != NULL && lst != NULL && 2529232153Smm (int64_t)st->st_dev == t->current_filesystem->dev && 2530231200Smm st->st_dev != lst->st_dev); 2531231200Smm} 2532231200Smm 2533231200Smm/* 2534231200Smm * Return the access path for the entry just returned from tree_next(). 2535231200Smm */ 2536231200Smmstatic const char * 2537231200Smmtree_current_access_path(struct tree *t) 2538231200Smm{ 2539231200Smm return (t->basename); 2540231200Smm} 2541231200Smm 2542231200Smm/* 2543231200Smm * Return the full path for the entry just returned from tree_next(). 2544231200Smm */ 2545231200Smmstatic const char * 2546231200Smmtree_current_path(struct tree *t) 2547231200Smm{ 2548231200Smm return (t->path.s); 2549231200Smm} 2550231200Smm 2551231200Smm/* 2552231200Smm * Terminate the traversal. 2553231200Smm */ 2554231200Smmstatic void 2555231200Smmtree_close(struct tree *t) 2556231200Smm{ 2557231200Smm 2558231200Smm if (t == NULL) 2559231200Smm return; 2560231200Smm if (t->entry_fd >= 0) { 2561231200Smm close_and_restore_time(t->entry_fd, t, &t->restore_time); 2562231200Smm t->entry_fd = -1; 2563231200Smm } 2564231200Smm /* Close the handle of readdir(). */ 2565231200Smm if (t->d != INVALID_DIR_HANDLE) { 2566231200Smm closedir(t->d); 2567231200Smm t->d = INVALID_DIR_HANDLE; 2568231200Smm } 2569231200Smm /* Release anything remaining in the stack. */ 2570231200Smm while (t->stack != NULL) { 2571231200Smm if (t->stack->flags & isDirLink) 2572231200Smm close(t->stack->symlink_parent_fd); 2573231200Smm tree_pop(t); 2574231200Smm } 2575231200Smm if (t->working_dir_fd >= 0) { 2576231200Smm close(t->working_dir_fd); 2577231200Smm t->working_dir_fd = -1; 2578231200Smm } 2579231200Smm if (t->initial_dir_fd >= 0) { 2580231200Smm close(t->initial_dir_fd); 2581231200Smm t->initial_dir_fd = -1; 2582231200Smm } 2583231200Smm} 2584231200Smm 2585231200Smm/* 2586231200Smm * Release any resources. 2587231200Smm */ 2588231200Smmstatic void 2589231200Smmtree_free(struct tree *t) 2590231200Smm{ 2591231200Smm int i; 2592231200Smm 2593231200Smm if (t == NULL) 2594231200Smm return; 2595231200Smm archive_string_free(&t->path); 2596231200Smm#if defined(HAVE_READDIR_R) 2597231200Smm free(t->dirent); 2598231200Smm#endif 2599231200Smm free(t->sparse_list); 2600231200Smm for (i = 0; i < t->max_filesystem_id; i++) 2601231200Smm free(t->filesystem_table[i].allocation_ptr); 2602231200Smm free(t->filesystem_table); 2603231200Smm free(t); 2604231200Smm} 2605231200Smm 2606231200Smm#endif 2607